summaryrefslogtreecommitdiffstats
path: root/libAACenc/src/metadata_main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libAACenc/src/metadata_main.cpp')
-rw-r--r--libAACenc/src/metadata_main.cpp809
1 files changed, 809 insertions, 0 deletions
diff --git a/libAACenc/src/metadata_main.cpp b/libAACenc/src/metadata_main.cpp
new file mode 100644
index 0000000..f02ba3b
--- /dev/null
+++ b/libAACenc/src/metadata_main.cpp
@@ -0,0 +1,809 @@
+/********************** 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; 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;
+}
+
+