/********************** Fraunhofer IIS FDK AAC Encoder lib ****************** (C) Copyright Fraunhofer IIS (2011) All Rights Reserved Please be advised that this software and/or program delivery is Confidential Information of Fraunhofer and subject to and covered by the Fraunhofer IIS Software Evaluation Agreement between Google Inc. and Fraunhofer effective and in full force since March 1, 2012. You may use this software and/or program only under the terms and conditions described in the above mentioned Fraunhofer IIS Software Evaluation Agreement. Any other and/or further use requires a separate agreement. $Id$ Author(s): V. Bacigalupo Description: Metadata Encoder library interface functions This software and/or program is protected by copyright law and international treaties. Any reproduction or distribution of this software and/or program, or any portion of it, may result in severe civil and criminal penalties, and will be prosecuted to the maximum extent possible under law. ******************************************************************************/ #include "metadata_main.h" #include "metadata_compressor.h" #include "FDK_bitstream.h" #include "FDK_audio.h" #include "genericStds.h" /*----------------- defines ----------------------*/ #define MAX_DRC_BANDS (1<<4) #define MAX_DRC_CHANNELS (8) #define MAX_DRC_FRAMELEN (2*1024) /*--------------- structure definitions --------------------*/ typedef struct AAC_METADATA { /* MPEG: Dynamic Range Control */ struct { UCHAR prog_ref_level_present; SCHAR prog_ref_level; UCHAR dyn_rng_sgn[MAX_DRC_BANDS]; UCHAR dyn_rng_ctl[MAX_DRC_BANDS]; UCHAR drc_bands_present; UCHAR drc_band_incr; UCHAR drc_band_top[MAX_DRC_BANDS]; UCHAR drc_interpolation_scheme; AACENC_METADATA_DRC_PROFILE drc_profile; INT drc_TargetRefLevel; /* used for Limiter */ /* excluded channels */ UCHAR excluded_chns_present; UCHAR exclude_mask[2]; /* MAX_NUMBER_CHANNELS/8 */ } mpegDrc; /* ETSI: addtl ancillary data */ struct { /* Heavy Compression */ UCHAR compression_on; /* flag, if compression value should be written */ UCHAR compression_value; /* compression value */ AACENC_METADATA_DRC_PROFILE comp_profile; INT comp_TargetRefLevel; /* used for Limiter */ INT timecode_coarse_status; INT timecode_fine_status; } etsiAncData; SCHAR centerMixLevel; /* center downmix level (0...7, according to table) */ SCHAR surroundMixLevel; /* surround downmix level (0...7, according to table) */ UCHAR WritePCEMixDwnIdx; /* flag */ UCHAR DmxLvl_On; /* flag */ UCHAR dolbySurroundMode; UCHAR metadataMode; /* indicate meta data mode in current frame (delay line) */ } AAC_METADATA; struct FDK_METADATA_ENCODER { INT metadataMode; HDRC_COMP hDrcComp; AACENC_MetaData submittedMetaData; INT nAudioDataDelay; INT nMetaDataDelay; INT nChannels; INT_PCM audioDelayBuffer[MAX_DRC_CHANNELS*MAX_DRC_FRAMELEN]; int audioDelayIdx; AAC_METADATA metaDataBuffer[3]; int metaDataDelayIdx; UCHAR drcInfoPayload[12]; UCHAR drcDsePayload[8]; INT matrix_mixdown_idx; AACENC_EXT_PAYLOAD exPayload[2]; INT nExtensions; INT finalizeMetaData; /* Delay switch off by one frame and write default configuration to finalize the metadata setup. */ }; /*---------------- constants -----------------------*/ static const AACENC_MetaData defaultMetaDataSetup = { AACENC_METADATA_DRC_NONE, AACENC_METADATA_DRC_NONE, -(31<<16), -(31<<16), 0, -(31<<16), 0, 0, 0, 0, 0 }; static const FIXP_DBL dmxTable[8] = { ((FIXP_DBL)MAXVAL_DBL), FL2FXCONST_DBL(0.841f), FL2FXCONST_DBL(0.707f), FL2FXCONST_DBL(0.596f), FL2FXCONST_DBL(0.500f), FL2FXCONST_DBL(0.422f), FL2FXCONST_DBL(0.355f), FL2FXCONST_DBL(0.000f) }; static const UCHAR surmix2matrix_mixdown_idx[8] = { 0, 0, 0, 1, 1, 2, 2, 3 }; /*--------------- function declarations --------------------*/ static FDK_METADATA_ERROR WriteMetadataPayload( const HANDLE_FDK_METADATA_ENCODER hMetaData, const AAC_METADATA * const pMetadata ); static INT WriteDynamicRangeInfoPayload( const AAC_METADATA* const pMetadata, UCHAR* const pExtensionPayload ); static INT WriteEtsiAncillaryDataPayload( const AAC_METADATA* const pMetadata, UCHAR* const pExtensionPayload ); static FDK_METADATA_ERROR CompensateAudioDelay( HANDLE_FDK_METADATA_ENCODER hMetaDataEnc, INT_PCM * const pAudioSamples, const INT nAudioSamples ); static FDK_METADATA_ERROR LoadSubmittedMetadata( const AACENC_MetaData * const hMetadata, const INT nChannels, const INT metadataMode, AAC_METADATA * const pAacMetaData ); static FDK_METADATA_ERROR ProcessCompressor( AAC_METADATA *pMetadata, HDRC_COMP hDrcComp, const INT_PCM * const pSamples, const INT nSamples ); /*------------- function definitions ----------------*/ static DRC_PROFILE convertProfile(AACENC_METADATA_DRC_PROFILE aacProfile) { DRC_PROFILE drcProfile = DRC_NONE; switch(aacProfile) { case AACENC_METADATA_DRC_NONE: drcProfile = DRC_NONE; break; case AACENC_METADATA_DRC_FILMSTANDARD: drcProfile = DRC_FILMSTANDARD; break; case AACENC_METADATA_DRC_FILMLIGHT: drcProfile = DRC_FILMLIGHT; break; case AACENC_METADATA_DRC_MUSICSTANDARD: drcProfile = DRC_MUSICSTANDARD; break; case AACENC_METADATA_DRC_MUSICLIGHT: drcProfile = DRC_MUSICLIGHT; break; case AACENC_METADATA_DRC_SPEECH: drcProfile = DRC_SPEECH; break; default: drcProfile = DRC_NONE; break; } return drcProfile; } /* convert dialog normalization to program reference level */ /* NOTE: this only is correct, if the decoder target level is set to -31dB for line mode / -20dB for RF mode */ static UCHAR dialnorm2progreflvl(const INT d) { return ((UCHAR)FDKmax(0, FDKmin((-d + (1<<13)) >> 14, 127))); } /* convert program reference level to dialog normalization */ static INT progreflvl2dialnorm(const UCHAR p) { return -((INT)(p<<(16-2))); } /* encode downmix levels to Downmixing_levels_MPEG4 */ static SCHAR encodeDmxLvls(const SCHAR cmixlev, const SCHAR surmixlev) { SCHAR dmxLvls = 0; dmxLvls |= 0x80 | (cmixlev << 4); /* center_mix_level_on */ dmxLvls |= 0x08 | surmixlev; /* surround_mix_level_on */ return dmxLvls; } /* encode AAC DRC gain (ISO/IEC 14496-3:2005 4.5.2.7) */ static void encodeDynrng(INT gain, UCHAR* const dyn_rng_ctl, UCHAR* const dyn_rng_sgn ) { if(gain < 0) { *dyn_rng_sgn = 1; gain = -gain; } else { *dyn_rng_sgn = 0; } gain = FDKmin(gain,(127<<14)); *dyn_rng_ctl = (UCHAR)((gain + (1<<13)) >> 14); } /* decode AAC DRC gain (ISO/IEC 14496-3:2005 4.5.2.7) */ static INT decodeDynrng(const UCHAR dyn_rng_ctl, const UCHAR dyn_rng_sgn) { INT tmp = ((INT)dyn_rng_ctl << (16-2)); if (dyn_rng_sgn) tmp = -tmp; return tmp; } /* encode AAC compression value (ETSI TS 101 154 page 99) */ static UCHAR encodeCompr(INT gain) { UCHAR x, y; INT tmp; /* tmp = (int)((48.164f - gain) / 6.0206f * 15 + 0.5f); */ tmp = ((3156476 - gain) * 15 + 197283) / 394566; if (tmp >= 240) { return 0xFF; } else if (tmp < 0) { return 0; } else { x = tmp / 15; y = tmp % 15; } return (x << 4) | y; } /* decode AAC compression value (ETSI TS 101 154 page 99) */ static INT decodeCompr(const UCHAR compr) { INT gain; SCHAR x = compr >> 4; /* 4 MSB of compr */ UCHAR y = (compr & 0x0F); /* 4 LSB of compr */ /* gain = (INT)((48.164f - 6.0206f * x - 0.4014f * y) ); */ gain = (INT)( scaleValue(((LONG)FL2FXCONST_DBL(6.0206f/128.f)*(8-x) - (LONG)FL2FXCONST_DBL(0.4014f/128.f)*y), -(DFRACT_BITS-1-7-16)) ); return gain; } FDK_METADATA_ERROR FDK_MetadataEnc_Open( HANDLE_FDK_METADATA_ENCODER *phMetaData ) { FDK_METADATA_ERROR err = METADATA_OK; HANDLE_FDK_METADATA_ENCODER hMetaData = NULL; if (phMetaData == NULL) { err = METADATA_INVALID_HANDLE; goto bail; } /* allocate memory */ hMetaData = (HANDLE_FDK_METADATA_ENCODER) FDKcalloc(1, sizeof(FDK_METADATA_ENCODER) ); if (hMetaData == NULL) { err = METADATA_MEMORY_ERROR; goto bail; } FDKmemclear(hMetaData, sizeof(FDK_METADATA_ENCODER)); /* Allocate DRC Compressor. */ if (FDK_DRC_Generator_Open(&hMetaData->hDrcComp)!=0) { err = METADATA_MEMORY_ERROR; goto bail; } /* Return metadata instance */ *phMetaData = hMetaData; return err; bail: FDK_MetadataEnc_Close(&hMetaData); return err; } FDK_METADATA_ERROR FDK_MetadataEnc_Close( HANDLE_FDK_METADATA_ENCODER *phMetaData ) { FDK_METADATA_ERROR err = METADATA_OK; if (phMetaData == NULL) { err = METADATA_INVALID_HANDLE; goto bail; } if (*phMetaData != NULL) { FDK_DRC_Generator_Close(&(*phMetaData)->hDrcComp); FDKfree(*phMetaData); *phMetaData = NULL; } bail: return err; } FDK_METADATA_ERROR FDK_MetadataEnc_Init( HANDLE_FDK_METADATA_ENCODER hMetaData, const INT resetStates, const INT metadataMode, const INT audioDelay, const UINT frameLength, const UINT sampleRate, const UINT nChannels, const CHANNEL_MODE channelMode, const CHANNEL_ORDER channelOrder ) { FDK_METADATA_ERROR err = METADATA_OK; int i, nFrames, delay; if (hMetaData==NULL) { err = METADATA_INVALID_HANDLE; goto bail; } /* Determine values for delay compensation. */ for (nFrames=0, delay=audioDelay-frameLength; delay>0; delay-=frameLength, nFrames++); if ( (hMetaData->nChannels>MAX_DRC_CHANNELS) || ((-delay)>MAX_DRC_FRAMELEN) ) { err = METADATA_INIT_ERROR; goto bail; } /* Initialize with default setup. */ FDKmemcpy(&hMetaData->submittedMetaData, &defaultMetaDataSetup, sizeof(AACENC_MetaData)); hMetaData->finalizeMetaData = 0; /* finalize meta data only while on/off switching, else disabled */ /* Reset delay lines. */ if ( resetStates || (hMetaData->nAudioDataDelay!=-delay) || (hMetaData->nChannels!=(INT)nChannels) ) { FDKmemclear(hMetaData->audioDelayBuffer, sizeof(hMetaData->audioDelayBuffer)); FDKmemclear(hMetaData->metaDataBuffer, sizeof(hMetaData->metaDataBuffer)); hMetaData->audioDelayIdx = 0; hMetaData->metaDataDelayIdx = 0; } else { /* Enable meta data. */ if ( (hMetaData->metadataMode==0) && (metadataMode!=0) ) { /* disable meta data in all delay lines */ for (i=0; i<(int)(sizeof(hMetaData->metaDataBuffer)/sizeof(AAC_METADATA)); i++) { LoadSubmittedMetadata(&hMetaData->submittedMetaData, nChannels, 0, &hMetaData->metaDataBuffer[i]); } } /* Disable meta data.*/ if ( (hMetaData->metadataMode!=0) && (metadataMode==0) ) { hMetaData->finalizeMetaData = hMetaData->metadataMode; } } /* Initialize delay. */ hMetaData->nAudioDataDelay = -delay; hMetaData->nMetaDataDelay = nFrames; hMetaData->nChannels = nChannels; hMetaData->metadataMode = metadataMode; /* Initialize compressor. */ if (metadataMode != 0) { if ( FDK_DRC_Generator_Initialize( hMetaData->hDrcComp, DRC_NONE, DRC_NONE, frameLength, sampleRate, channelMode, channelOrder, 1) != 0) { err = METADATA_INIT_ERROR; } } bail: return err; } static FDK_METADATA_ERROR ProcessCompressor( AAC_METADATA *pMetadata, HDRC_COMP hDrcComp, const INT_PCM * const pSamples, const INT nSamples ) { FDK_METADATA_ERROR err = METADATA_OK; INT dynrng, compr; DRC_PROFILE profileDrc = convertProfile(pMetadata->mpegDrc.drc_profile); DRC_PROFILE profileComp = convertProfile(pMetadata->etsiAncData.comp_profile); if ( (pMetadata==NULL) || (hDrcComp==NULL) ) { err = METADATA_INVALID_HANDLE; return err; } /* first, check if profile is same as last frame * otherwise, update setup */ if ( (profileDrc != FDK_DRC_Generator_getDrcProfile(hDrcComp)) || (profileComp != FDK_DRC_Generator_getCompProfile(hDrcComp)) ) { FDK_DRC_Generator_setDrcProfile(hDrcComp, profileDrc, profileComp); } /* Sanity check */ if (profileComp == DRC_NONE) { pMetadata->etsiAncData.compression_value = 0x80; /* to ensure no external values will be written if not configured */ } /* in case of embedding external values, copy this now (limiter may overwrite them) */ dynrng = decodeDynrng(pMetadata->mpegDrc.dyn_rng_ctl[0], pMetadata->mpegDrc.dyn_rng_sgn[0]); compr = decodeCompr(pMetadata->etsiAncData.compression_value); /* Call compressor */ if (FDK_DRC_Generator_Calc(hDrcComp, pSamples, progreflvl2dialnorm(pMetadata->mpegDrc.prog_ref_level), pMetadata->mpegDrc.drc_TargetRefLevel, pMetadata->etsiAncData.comp_TargetRefLevel, dmxTable[pMetadata->centerMixLevel], dmxTable[pMetadata->surroundMixLevel], &dynrng, &compr) != 0) { err = METADATA_ENCODE_ERROR; goto bail; } /* Write DRC values */ pMetadata->mpegDrc.drc_band_incr = 0; encodeDynrng(dynrng, pMetadata->mpegDrc.dyn_rng_ctl, pMetadata->mpegDrc.dyn_rng_sgn); pMetadata->etsiAncData.compression_value = encodeCompr(compr); bail: return err; } FDK_METADATA_ERROR FDK_MetadataEnc_Process( HANDLE_FDK_METADATA_ENCODER hMetaDataEnc, INT_PCM * const pAudioSamples, const INT nAudioSamples, const AACENC_MetaData * const pMetadata, AACENC_EXT_PAYLOAD ** ppMetaDataExtPayload, UINT * nMetaDataExtensions, INT * matrix_mixdown_idx ) { FDK_METADATA_ERROR err = METADATA_OK; int metaDataDelayWriteIdx, metaDataDelayReadIdx, metadataMode; /* Where to write new meta data info */ metaDataDelayWriteIdx = hMetaDataEnc->metaDataDelayIdx; /* How to write the data */ metadataMode = hMetaDataEnc->metadataMode; /* Compensate meta data delay. */ hMetaDataEnc->metaDataDelayIdx++; if (hMetaDataEnc->metaDataDelayIdx > hMetaDataEnc->nMetaDataDelay) hMetaDataEnc->metaDataDelayIdx = 0; /* Where to read pending meta data info from. */ metaDataDelayReadIdx = hMetaDataEnc->metaDataDelayIdx; /* Submit new data if available. */ if (pMetadata!=NULL) { FDKmemcpy(&hMetaDataEnc->submittedMetaData, pMetadata, sizeof(AACENC_MetaData)); } /* Write one additional frame with default configuration of meta data. Ensure defined behaviour on decoder side. */ if ( (hMetaDataEnc->finalizeMetaData!=0) && (hMetaDataEnc->metadataMode==0)) { FDKmemcpy(&hMetaDataEnc->submittedMetaData, &defaultMetaDataSetup, sizeof(AACENC_MetaData)); metadataMode = hMetaDataEnc->finalizeMetaData; hMetaDataEnc->finalizeMetaData = 0; } /* Get last submitted data. */ if ( (err = LoadSubmittedMetadata( &hMetaDataEnc->submittedMetaData, hMetaDataEnc->nChannels, metadataMode, &hMetaDataEnc->metaDataBuffer[metaDataDelayWriteIdx])) != METADATA_OK ) { goto bail; } /* Calculate compressor if necessary and updata meta data info */ if (hMetaDataEnc->metaDataBuffer[metaDataDelayWriteIdx].metadataMode != 0) { if ( (err = ProcessCompressor( &hMetaDataEnc->metaDataBuffer[metaDataDelayWriteIdx], hMetaDataEnc->hDrcComp, pAudioSamples, nAudioSamples)) != METADATA_OK) { /* Get last submitted data again. */ LoadSubmittedMetadata( &hMetaDataEnc->submittedMetaData, hMetaDataEnc->nChannels, metadataMode, &hMetaDataEnc->metaDataBuffer[metaDataDelayWriteIdx]); } } /* Convert Meta Data side info to bitstream data. */ if ( (err = WriteMetadataPayload(hMetaDataEnc, &hMetaDataEnc->metaDataBuffer[metaDataDelayReadIdx])) != METADATA_OK ) { goto bail; } /* Assign meta data to output */ *ppMetaDataExtPayload = hMetaDataEnc->exPayload; *nMetaDataExtensions = hMetaDataEnc->nExtensions; *matrix_mixdown_idx = hMetaDataEnc->matrix_mixdown_idx; bail: /* Compensate audio delay, reset err status. */ err = CompensateAudioDelay(hMetaDataEnc, pAudioSamples, nAudioSamples); return err; } static FDK_METADATA_ERROR CompensateAudioDelay( HANDLE_FDK_METADATA_ENCODER hMetaDataEnc, INT_PCM * const pAudioSamples, const INT nAudioSamples ) { FDK_METADATA_ERROR err = METADATA_OK; if (hMetaDataEnc->nAudioDataDelay) { int i, delaySamples = hMetaDataEnc->nAudioDataDelay*hMetaDataEnc->nChannels; for (i = 0; i < nAudioSamples; i++) { INT_PCM tmp = pAudioSamples[i]; pAudioSamples[i] = hMetaDataEnc->audioDelayBuffer[hMetaDataEnc->audioDelayIdx]; hMetaDataEnc->audioDelayBuffer[hMetaDataEnc->audioDelayIdx] = tmp; hMetaDataEnc->audioDelayIdx++; if (hMetaDataEnc->audioDelayIdx >= delaySamples) hMetaDataEnc->audioDelayIdx = 0; } } return err; } /*----------------------------------------------------------------------------- functionname: WriteMetadataPayload description: fills anc data and extension payload returns: Error status ------------------------------------------------------------------------------*/ static FDK_METADATA_ERROR WriteMetadataPayload( const HANDLE_FDK_METADATA_ENCODER hMetaData, const AAC_METADATA * const pMetadata ) { FDK_METADATA_ERROR err = METADATA_OK; if ( (hMetaData==NULL) || (pMetadata==NULL) ) { err = METADATA_INVALID_HANDLE; goto bail; } hMetaData->nExtensions = 0; hMetaData->matrix_mixdown_idx = -1; /* AAC-DRC */ if (pMetadata->metadataMode != 0) { hMetaData->exPayload[hMetaData->nExtensions].pData = hMetaData->drcInfoPayload; hMetaData->exPayload[hMetaData->nExtensions].dataType = EXT_DYNAMIC_RANGE; hMetaData->exPayload[hMetaData->nExtensions].associatedChElement = -1; hMetaData->exPayload[hMetaData->nExtensions].dataSize = WriteDynamicRangeInfoPayload(pMetadata, hMetaData->exPayload[hMetaData->nExtensions].pData); hMetaData->nExtensions++; /* Matrix Mixdown Coefficient in PCE */ if (pMetadata->WritePCEMixDwnIdx) { hMetaData->matrix_mixdown_idx = surmix2matrix_mixdown_idx[pMetadata->surroundMixLevel]; } /* ETSI TS 101 154 (DVB) - MPEG4 ancillary_data() */ if (pMetadata->metadataMode == 2) /* MP4_METADATA_MPEG_ETSI */ { hMetaData->exPayload[hMetaData->nExtensions].pData = hMetaData->drcDsePayload; hMetaData->exPayload[hMetaData->nExtensions].dataType = EXT_DATA_ELEMENT; hMetaData->exPayload[hMetaData->nExtensions].associatedChElement = -1; hMetaData->exPayload[hMetaData->nExtensions].dataSize = WriteEtsiAncillaryDataPayload(pMetadata,hMetaData->exPayload[hMetaData->nExtensions].pData); hMetaData->nExtensions++; } /* metadataMode == 2 */ } /* metadataMode != 0 */ bail: return err; } static INT WriteDynamicRangeInfoPayload( const AAC_METADATA* const pMetadata, UCHAR* const pExtensionPayload ) { const INT pce_tag_present = 0; /* yet fixed setting! */ const INT prog_ref_lev_res_bits = 0; INT i, drc_num_bands = 1; FDK_BITSTREAM bsWriter; FDKinitBitStream(&bsWriter, pExtensionPayload, 16, 0, BS_WRITER); /* dynamic_range_info() */ FDKwriteBits(&bsWriter, pce_tag_present, 1); /* pce_tag_present */ if (pce_tag_present) { FDKwriteBits(&bsWriter, 0x0, 4); /* pce_instance_tag */ FDKwriteBits(&bsWriter, 0x0, 4); /* drc_tag_reserved_bits */ } /* Exclude channels */ FDKwriteBits(&bsWriter, (pMetadata->mpegDrc.excluded_chns_present) ? 1 : 0, 1); /* excluded_chns_present*/ /* Multiband DRC */ FDKwriteBits(&bsWriter, (pMetadata->mpegDrc.drc_bands_present) ? 1 : 0, 1); /* drc_bands_present */ if (pMetadata->mpegDrc.drc_bands_present) { FDKwriteBits(&bsWriter, pMetadata->mpegDrc.drc_band_incr, 4); /* drc_band_incr */ FDKwriteBits(&bsWriter, pMetadata->mpegDrc.drc_interpolation_scheme, 4); /* drc_interpolation_scheme */ drc_num_bands += pMetadata->mpegDrc.drc_band_incr; for (i=0; impegDrc.drc_band_top[i], 8); /* drc_band_top */ } } /* Program Reference Level */ FDKwriteBits(&bsWriter, pMetadata->mpegDrc.prog_ref_level_present, 1); /* prog_ref_level_present */ if (pMetadata->mpegDrc.prog_ref_level_present) { FDKwriteBits(&bsWriter, pMetadata->mpegDrc.prog_ref_level, 7); /* prog_ref_level */ FDKwriteBits(&bsWriter, prog_ref_lev_res_bits, 1); /* prog_ref_level_reserved_bits */ } /* DRC Values */ for (i=0; impegDrc.dyn_rng_sgn[i]) ? 1 : 0, 1); /* dyn_rng_sgn[ */ FDKwriteBits(&bsWriter, pMetadata->mpegDrc.dyn_rng_ctl[i], 7); /* dyn_rng_ctl */ } /* return number of valid bits in extension payload. */ return FDKgetValidBits(&bsWriter); } static INT WriteEtsiAncillaryDataPayload( const AAC_METADATA* const pMetadata, UCHAR* const pExtensionPayload ) { FDK_BITSTREAM bsWriter; FDKinitBitStream(&bsWriter, pExtensionPayload, 16, 0, BS_WRITER); /* ancillary_data_sync */ FDKwriteBits(&bsWriter, 0xBC, 8); /* bs_info */ FDKwriteBits(&bsWriter, 0x3, 2); /* mpeg_audio_type */ FDKwriteBits(&bsWriter, pMetadata->dolbySurroundMode, 2); /* dolby_surround_mode */ FDKwriteBits(&bsWriter, 0x0, 4); /* reserved */ /* ancillary_data_status */ FDKwriteBits(&bsWriter, 0, 3); /* 3 bit Reserved, set to "0" */ FDKwriteBits(&bsWriter, (pMetadata->DmxLvl_On) ? 1 : 0, 1); /* downmixing_levels_MPEG4_status */ FDKwriteBits(&bsWriter, 0, 1); /* Reserved, set to "0" */ FDKwriteBits(&bsWriter, (pMetadata->etsiAncData.compression_on) ? 1 : 0, 1); /* audio_coding_mode_and_compression status */ FDKwriteBits(&bsWriter, (pMetadata->etsiAncData.timecode_coarse_status) ? 1 : 0, 1); /* coarse_grain_timecode_status */ FDKwriteBits(&bsWriter, (pMetadata->etsiAncData.timecode_fine_status) ? 1 : 0, 1); /* fine_grain_timecode_status */ /* downmixing_levels_MPEG4_status */ if (pMetadata->DmxLvl_On) { FDKwriteBits(&bsWriter, encodeDmxLvls(pMetadata->centerMixLevel, pMetadata->surroundMixLevel), 8); } /* audio_coding_mode_and_compression_status */ if (pMetadata->etsiAncData.compression_on) { FDKwriteBits(&bsWriter, 0x01, 8); /* audio coding mode */ FDKwriteBits(&bsWriter, pMetadata->etsiAncData.compression_value, 8); /* compression value */ } /* grain-timecode coarse/fine */ if (pMetadata->etsiAncData.timecode_coarse_status) { FDKwriteBits(&bsWriter, 0x0, 16); /* not yet supported */ } if (pMetadata->etsiAncData.timecode_fine_status) { FDKwriteBits(&bsWriter, 0x0, 16); /* not yet supported */ } return FDKgetValidBits(&bsWriter); } static FDK_METADATA_ERROR LoadSubmittedMetadata( const AACENC_MetaData * const hMetadata, const INT nChannels, const INT metadataMode, AAC_METADATA * const pAacMetaData ) { FDK_METADATA_ERROR err = METADATA_OK; if (pAacMetaData==NULL) { err = METADATA_INVALID_HANDLE; } else { /* init struct */ FDKmemclear(pAacMetaData, sizeof(AAC_METADATA)); if (hMetadata!=NULL) { /* convert data */ pAacMetaData->mpegDrc.drc_profile = hMetadata->drc_profile; pAacMetaData->etsiAncData.comp_profile = hMetadata->comp_profile; pAacMetaData->mpegDrc.drc_TargetRefLevel = hMetadata->drc_TargetRefLevel; pAacMetaData->etsiAncData.comp_TargetRefLevel= hMetadata->comp_TargetRefLevel; pAacMetaData->mpegDrc.prog_ref_level_present = hMetadata->prog_ref_level_present; pAacMetaData->mpegDrc.prog_ref_level = dialnorm2progreflvl(hMetadata->prog_ref_level); pAacMetaData->centerMixLevel = hMetadata->centerMixLevel; pAacMetaData->surroundMixLevel = hMetadata->surroundMixLevel; pAacMetaData->WritePCEMixDwnIdx = hMetadata->PCE_mixdown_idx_present; pAacMetaData->DmxLvl_On = hMetadata->ETSI_DmxLvl_present; pAacMetaData->etsiAncData.compression_on = 1; if (nChannels == 2) { pAacMetaData->dolbySurroundMode = hMetadata->dolbySurroundMode; /* dolby_surround_mode */ } else { pAacMetaData->dolbySurroundMode = 0; } pAacMetaData->etsiAncData.timecode_coarse_status = 0; /* not yet supported - attention: Update GetEstMetadataBytesPerFrame() if enable this! */ pAacMetaData->etsiAncData.timecode_fine_status = 0; /* not yet supported - attention: Update GetEstMetadataBytesPerFrame() if enable this! */ pAacMetaData->metadataMode = metadataMode; } else { pAacMetaData->metadataMode = 0; /* there is no configuration available */ } } return err; } INT FDK_MetadataEnc_GetDelay( HANDLE_FDK_METADATA_ENCODER hMetadataEnc ) { INT delay = 0; if (hMetadataEnc!=NULL) { delay = hMetadataEnc->nAudioDataDelay; } return delay; }