diff options
Diffstat (limited to 'libAACenc/src/metadata_main.cpp')
-rw-r--r-- | libAACenc/src/metadata_main.cpp | 871 |
1 files changed, 871 insertions, 0 deletions
diff --git a/libAACenc/src/metadata_main.cpp b/libAACenc/src/metadata_main.cpp new file mode 100644 index 0000000..45763a1 --- /dev/null +++ b/libAACenc/src/metadata_main.cpp @@ -0,0 +1,871 @@ + +/* ----------------------------------------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2012 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. + All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements +the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio. +This FDK AAC Codec software is intended to be used on a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual +audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by +independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part +of the MPEG specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer) +may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners +individually for the purpose of encoding or decoding bit streams in products that are compliant with +the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license +these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec +software may already be covered under those patent licenses when it is used for those licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality, +are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional +applications information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, are permitted without +payment of copyright license fees provided that you satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of the FDK AAC Codec or +your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation and/or other materials +provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form. +You must make available free of charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived from this library without +prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec +software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software +and the date of any change. For modified versions of the FDK AAC Codec, the term +"Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term +"Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer, +ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with +respect to this software. + +You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized +by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors +"AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties +of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages, +including but not limited to procurement of substitute goods or services; loss of use, data, or profits, +or business interruption, however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of this software, even if +advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------------------------------------- */ + +/********************** Fraunhofer IIS FDK AAC Encoder lib ****************** + + Author(s): V. Bacigalupo + Description: Metadata Encoder library interface functions + +******************************************************************************/ + + +#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; i<drc_num_bands; i++) { + FDKwriteBits(&bsWriter, pMetadata->mpegDrc.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; i<drc_num_bands; i++) { + FDKwriteBits(&bsWriter, (pMetadata->mpegDrc.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; +} + + |