diff options
author | Jean-Michel Trivi <jmtrivi@google.com> | 2013-12-30 16:01:08 -0800 |
---|---|---|
committer | Jean-Michel Trivi <jmtrivi@google.com> | 2014-03-31 23:41:44 +0000 |
commit | 603f48ab99ce76f552f4f6f85d06b8c5b94c698e (patch) | |
tree | 303937f6779cdb798e3cec67ebe32abb39eab15b /libAACdec | |
parent | 629f60c0e71f4a5ad273d5ab3fc6964e5eb1f9f4 (diff) | |
download | fdk-aac-603f48ab99ce76f552f4f6f85d06b8c5b94c698e.tar.gz fdk-aac-603f48ab99ce76f552f4f6f85d06b8c5b94c698e.tar.bz2 fdk-aac-603f48ab99ce76f552f4f6f85d06b8c5b94c698e.zip |
AAC Decoder: introduce time domain limiter
Introduce time domain limiter. The module is per default enabled for all
AAC-LC and HE-AAC v1/2 streams. For all ER-AAC-LD and ER-AAC-ELD streams
the limiter is disabled per default. The feature can be en- or disabled
via dynamic API parameter. Note that the limiter introduces an additional
output delay which depends on the module parameters and the streams
sampling rate.
Bug 9428126
Change-Id: I299a072340b33e2c324facbd347a72c8de3d380e
Diffstat (limited to 'libAACdec')
-rw-r--r-- | libAACdec/include/aacdecoder_lib.h | 10 | ||||
-rw-r--r-- | libAACdec/src/aacdec_drc.cpp | 50 | ||||
-rw-r--r-- | libAACdec/src/aacdec_drc.h | 5 | ||||
-rw-r--r-- | libAACdec/src/aacdec_drc_types.h | 1 | ||||
-rw-r--r-- | libAACdec/src/aacdecoder.cpp | 7 | ||||
-rw-r--r-- | libAACdec/src/aacdecoder.h | 7 | ||||
-rw-r--r-- | libAACdec/src/aacdecoder_lib.cpp | 91 |
7 files changed, 159 insertions, 12 deletions
diff --git a/libAACdec/include/aacdecoder_lib.h b/libAACdec/include/aacdecoder_lib.h index 0253c5c..a281ab9 100644 --- a/libAACdec/include/aacdecoder_lib.h +++ b/libAACdec/include/aacdecoder_lib.h @@ -436,6 +436,16 @@ typedef enum 2: Create a dual mono output signal from channel 2. \n 3: Create a dual mono output signal by mixing both channels (L' = R' = 0.5*Ch1 + 0.5*Ch2). */ AAC_PCM_OUTPUT_CHANNEL_MAPPING = 0x0003, /*!< Output buffer channel ordering. 0: MPEG PCE style order, 1: WAV file channel order (default). */ + AAC_PCM_LIMITER_ENABLE = 0x0004, /*!< Enable signal level limiting. \n + -1: Auto-config. Enable limiter for all non-lowdelay configurations by default. \n + 0: Disable limiter in general. \n + 1: Enable limiter always. + It is recommended to call the decoder with a AACDEC_CLRHIST flag to reset all states when + the limiter switch is changed explicitly. */ + AAC_PCM_LIMITER_ATTACK_TIME = 0x0005, /*!< Signal level limiting attack time in ms. + Default confguration is 15 ms. Adjustable range from 1 ms to 15 ms. */ + AAC_PCM_LIMITER_RELEAS_TIME = 0x0006, /*!< Signal level limiting release time in ms. + Default configuration is 50 ms. Adjustable time must be larger than 0 ms. */ AAC_PCM_MIN_OUTPUT_CHANNELS = 0x0011, /*!< Minimum number of PCM output channels. If higher than the number of encoded audio channels, a simple channel extension is applied. \n -1, 0: Disable channel extenstion feature. The decoder output contains the same number of diff --git a/libAACdec/src/aacdec_drc.cpp b/libAACdec/src/aacdec_drc.cpp index bc74ddf..ba7419d 100644 --- a/libAACdec/src/aacdec_drc.cpp +++ b/libAACdec/src/aacdec_drc.cpp @@ -130,7 +130,6 @@ void aacDecoder_drcInit ( /* init control fields */ self->enable = 0; self->numThreads = 0; - self->digitalNorm = 0; /* init params */ pParams = &self->params; @@ -139,8 +138,9 @@ void aacDecoder_drcInit ( pParams->usrCut = FL2FXCONST_DBL(0.0f); pParams->boost = FL2FXCONST_DBL(0.0f); pParams->usrBoost = FL2FXCONST_DBL(0.0f); - pParams->targetRefLevel = AACDEC_DRC_DEFAULT_REF_LEVEL; + pParams->targetRefLevel = -1; pParams->expiryFrame = AACDEC_DRC_DFLT_EXPIRY_FRAMES; + pParams->applyDigitalNorm = 0; pParams->applyHeavyCompression = 0; /* initial program ref level = target ref level */ @@ -222,11 +222,12 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam ( return AAC_DEC_INVALID_HANDLE; } if (value < 0) { - self->digitalNorm = 0; + self->params.applyDigitalNorm = 0; + self->params.targetRefLevel = -1; } else { /* ref_level must be between 0 and MAX_REFERENCE_LEVEL, inclusive */ - self->digitalNorm = 1; + self->params.applyDigitalNorm = 1; if (self->params.targetRefLevel != (SCHAR)value) { self->params.targetRefLevel = (SCHAR)value; self->progRefLevel = (SCHAR)value; /* Always set the program reference level equal to the @@ -234,6 +235,16 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam ( } } break; + case APPLY_NORMALIZATION: + if (value < 0 || value > 1) { + return AAC_DEC_SET_PARAM_FAIL; + } + if (self == NULL) { + return AAC_DEC_INVALID_HANDLE; + } + /* Store new parameter value */ + self->params.applyDigitalNorm = (UCHAR)value; + break; case APPLY_HEAVY_COMPRESSION: if (value < 0 || value > 1) { return AAC_DEC_SET_PARAM_FAIL; @@ -278,7 +289,7 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam ( self->enable = ( (self->params.boost > (FIXP_DBL)0) || (self->params.cut > (FIXP_DBL)0) || (self->params.applyHeavyCompression != 0) - || (self->digitalNorm == 1) ); + || (self->params.targetRefLevel >= 0) ); return ErrorStatus; @@ -827,6 +838,7 @@ void aacDecoder_drcApply ( void *pSbrDec, CAacDecoderChannelInfo *pAacDecoderChannelInfo, CDrcChannelData *pDrcChData, + FIXP_DBL *extGain, int ch, /* needed only for SBR */ int aacFrameSize, int bSbrPresent ) @@ -838,8 +850,8 @@ void aacDecoder_drcApply ( FIXP_DBL max_mantissa; INT max_exponent; - FIXP_DBL norm_mantissa = FL2FXCONST_DBL(0.0f); - INT norm_exponent = 0; + FIXP_DBL norm_mantissa = FL2FXCONST_DBL(0.5f); + INT norm_exponent = 1; FIXP_DBL fact_mantissa[MAX_DRC_BANDS]; INT fact_exponent[MAX_DRC_BANDS]; @@ -861,6 +873,15 @@ void aacDecoder_drcApply ( if (!self->enable) { sbrDecoder_drcDisable( (HANDLE_SBRDECODER)pSbrDec, ch ); + if (extGain != NULL) { + INT gainScale = (INT)*extGain; + /* The gain scaling must be passed to the function in the buffer pointed on by extGain. */ + if (gainScale >= 0 && gainScale <= DFRACT_BITS) { + *extGain = scaleValue(norm_mantissa, norm_exponent-gainScale); + } else { + FDK_ASSERT(0); + } + } return; } @@ -876,7 +897,7 @@ void aacDecoder_drcApply ( reduced DAC SNR (if signal is attenuated) or clipping (if signal is boosted) */ - if (self->digitalNorm == 1) + if (pParams->targetRefLevel >= 0) { /* 0.5^((targetRefLevel - progRefLevel)/24) */ norm_mantissa = fLdPow( @@ -886,7 +907,18 @@ void aacDecoder_drcApply ( 3, &norm_exponent ); } - else { + /* Always export the normalization gain (if possible). */ + if (extGain != NULL) { + INT gainScale = (INT)*extGain; + /* The gain scaling must be passed to the function in the buffer pointed on by extGain. */ + if (gainScale >= 0 && gainScale <= DFRACT_BITS) { + *extGain = scaleValue(norm_mantissa, norm_exponent-gainScale); + } else { + FDK_ASSERT(0); + } + } + if (self->params.applyDigitalNorm == 0) { + /* Reset normalization gain since this module must not apply it */ norm_mantissa = FL2FXCONST_DBL(0.5f); norm_exponent = 1; } diff --git a/libAACdec/src/aacdec_drc.h b/libAACdec/src/aacdec_drc.h index 2ebae2c..41aac69 100644 --- a/libAACdec/src/aacdec_drc.h +++ b/libAACdec/src/aacdec_drc.h @@ -98,7 +98,6 @@ amm-info@iis.fraunhofer.de #include "channel.h" #include "FDK_bitstream.h" -#define AACDEC_DRC_DEFAULT_REF_LEVEL ( 108 ) /* -27 dB below full scale (typical for movies) */ #define AACDEC_DRC_DFLT_EXPIRY_FRAMES ( 50 ) /* Default DRC data expiry time in AAC frames */ /** @@ -111,6 +110,7 @@ typedef enum TARGET_REF_LEVEL, DRC_BS_DELAY, DRC_DATA_EXPIRY_FRAME, + APPLY_NORMALIZATION, APPLY_HEAVY_COMPRESSION } AACDEC_DRC_PARAM; @@ -149,6 +149,8 @@ int aacDecoder_drcProlog ( * \param pSbrDec pointer to SBR decoder instance * \param pAacDecoderChannelInfo AAC decoder channel instance to be processed * \param pDrcDat DRC channel data + * \param extGain Pointer to a FIXP_DBL where a externally applyable gain will be stored into (independently on whether it will be apply internally or not). + * At function call the buffer must hold the scale (0 >= scale < DFRACT_BITS) to be applied on the gain value. * \param ch channel index * \param aacFrameSize AAC frame size * \param bSbrPresent flag indicating that SBR is present, in which case DRC is handed over to the SBR instance pSbrDec @@ -158,6 +160,7 @@ void aacDecoder_drcApply ( void *pSbrDec, CAacDecoderChannelInfo *pAacDecoderChannelInfo, CDrcChannelData *pDrcDat, + FIXP_DBL *extGain, int ch, int aacFrameSize, int bSbrPresent ); diff --git a/libAACdec/src/aacdec_drc_types.h b/libAACdec/src/aacdec_drc_types.h index 1b5cd76..1f595b9 100644 --- a/libAACdec/src/aacdec_drc_types.h +++ b/libAACdec/src/aacdec_drc_types.h @@ -140,6 +140,7 @@ typedef struct UINT expiryFrame; SCHAR targetRefLevel; UCHAR bsDelayEnable; + UCHAR applyDigitalNorm; UCHAR applyHeavyCompression; } CDrcParams; diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp index 7903f76..18c9afa 100644 --- a/libAACdec/src/aacdecoder.cpp +++ b/libAACdec/src/aacdecoder.cpp @@ -1653,6 +1653,8 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( { int stride, offset, c; + /* Turn on/off DRC modules level normalization in digital domain depending on the limiter status. */ + aacDecoder_drcSetParam( self->hDrcInfo, APPLY_NORMALIZATION, (self->limiterEnableCurr) ? 0 : 1 ); /* Extract DRC control data and map it to channels (without bitstream delay) */ aacDecoder_drcProlog ( self->hDrcInfo, @@ -1703,12 +1705,15 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( /* Reset DRC control data for this channel */ aacDecoder_drcInitChannelData ( &self->pAacDecoderStaticChannelInfo[c]->drcData ); } + /* The DRC module demands to be called with the gain field holding the gain scale. */ + self->extGain[0] = (FIXP_DBL)TDL_GAIN_SCALING; /* DRC processing */ aacDecoder_drcApply ( self->hDrcInfo, self->hSbrDecoder, pAacDecoderChannelInfo, &self->pAacDecoderStaticChannelInfo[c]->drcData, + self->extGain, c, self->streamInfo.aacSamplesPerFrame, self->sbrEnabled @@ -1726,6 +1731,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( (self->frameOK && !(flags&AACDEC_CONCEAL)), self->aacCommonData.workBufferCore1->mdctOutTemp ); + self->extGainDelay = self->streamInfo.aacSamplesPerFrame; break; case AACDEC_RENDER_ELDFB: CBlock_FrequencyToTimeLowDelay( @@ -1735,6 +1741,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( self->streamInfo.aacSamplesPerFrame, stride ); + self->extGainDelay = (self->streamInfo.aacSamplesPerFrame*2 - self->streamInfo.aacSamplesPerFrame/2 - 1)/2; break; default: ErrorStatus = AAC_DEC_UNKNOWN; diff --git a/libAACdec/src/aacdecoder.h b/libAACdec/src/aacdecoder.h index f581054..bcbc040 100644 --- a/libAACdec/src/aacdecoder.h +++ b/libAACdec/src/aacdecoder.h @@ -111,6 +111,7 @@ amm-info@iis.fraunhofer.de #include "aacdec_drc.h" #include "pcmutils_lib.h" + #include "limiter.h" /* Capabilities flags */ @@ -215,6 +216,12 @@ struct AAC_DECODER_INSTANCE { CAncData ancData; /*!< structure to handle ancillary data */ HANDLE_PCM_DOWNMIX hPcmUtils; /*!< privat data for the PCM utils. */ + TDLimiterPtr hLimiter; /*!< Handle of time domain limiter. */ + UCHAR limiterEnableUser; /*!< The limiter configuration requested by the library user */ + UCHAR limiterEnableCurr; /*!< The current limiter configuration. */ + + FIXP_DBL extGain[1]; /*!< Gain that must be applied to the output signal. */ + UINT extGainDelay; /*!< Delay that must be accounted for extGain. */ }; diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index d1b895d..98ef0de 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -110,7 +110,7 @@ amm-info@iis.fraunhofer.de /* Decoder library info */ #define AACDECODER_LIB_VL0 2 #define AACDECODER_LIB_VL1 5 -#define AACDECODER_LIB_VL2 6 +#define AACDECODER_LIB_VL2 7 #define AACDECODER_LIB_TITLE "AAC Decoder Lib" #define AACDECODER_LIB_BUILD_DATE __DATE__ #define AACDECODER_LIB_BUILD_TIME __TIME__ @@ -397,12 +397,14 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode CConcealParams *pConcealData = NULL; HANDLE_AAC_DRC hDrcInfo = NULL; HANDLE_PCM_DOWNMIX hPcmDmx = NULL; + TDLimiterPtr hPcmTdl = NULL; /* check decoder handle */ if (self != NULL) { pConcealData = &self->concealCommonData; hDrcInfo = self->hDrcInfo; hPcmDmx = self->hPcmUtils; + hPcmTdl = self->hLimiter; } else { errorStatus = AAC_DEC_INVALID_HANDLE; } @@ -486,6 +488,47 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode } break; + + case AAC_PCM_LIMITER_ENABLE: + if (value < -1 || value > 1) { + return AAC_DEC_SET_PARAM_FAIL; + } + if (self == NULL) { + return AAC_DEC_INVALID_HANDLE; + } + self->limiterEnableUser = value; + break; + + case AAC_PCM_LIMITER_ATTACK_TIME: + if (value <= 0) { /* module function converts value to unsigned */ + return AAC_DEC_SET_PARAM_FAIL; + } + switch (setLimiterAttack(hPcmTdl, value)) { + case TDLIMIT_OK: + break; + case TDLIMIT_INVALID_HANDLE: + return AAC_DEC_INVALID_HANDLE; + case TDLIMIT_INVALID_PARAMETER: + default: + return AAC_DEC_SET_PARAM_FAIL; + } + break; + + case AAC_PCM_LIMITER_RELEAS_TIME: + if (value <= 0) { /* module function converts value to unsigned */ + return AAC_DEC_SET_PARAM_FAIL; + } + switch (setLimiterRelease(hPcmTdl, value)) { + case TDLIMIT_OK: + break; + case TDLIMIT_INVALID_HANDLE: + return AAC_DEC_INVALID_HANDLE; + case TDLIMIT_INVALID_PARAMETER: + default: + return AAC_DEC_SET_PARAM_FAIL; + } + break; + case AAC_PCM_OUTPUT_CHANNEL_MAPPING: switch (value) { case 0: @@ -632,6 +675,14 @@ LINKSPEC_CPP HANDLE_AACDECODER aacDecoder_Open(TRANSPORT_TYPE transportFmt, UINT goto bail; } + aacDec->hLimiter = createLimiter(TDL_ATTACK_DEFAULT_MS, TDL_RELEASE_DEFAULT_MS, SAMPLE_MAX, (8), 96000); + if (NULL == aacDec->hLimiter) { + err = -1; + goto bail; + } + aacDec->limiterEnableUser = (UCHAR)-1; + aacDec->limiterEnableCurr = 0; + /* Assure that all modules have same delay */ @@ -807,6 +858,17 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( self->streamInfo.numTotalBytes = 0; } + if (self->limiterEnableUser==(UCHAR)-1) { + /* Enbale limiter for all non-lowdelay AOT's. */ + self->limiterEnableCurr = ( self->flags & (AC_LD|AC_ELD) ) ? 0 : 1; + } + else { + /* Use limiter configuration as requested. */ + self->limiterEnableCurr = self->limiterEnableUser; + } + /* reset limiter gain on a per frame basis */ + self->extGain[0] = FL2FXCONST_DBL(1.0f/(float)(1<<TDL_GAIN_SCALING)); + ErrorStatus = CAacDecoder_DecodeFrame(self, flags | (fTpConceal ? AACDEC_CONCEAL : 0), @@ -909,6 +971,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( { + INT pcmLimiterScale = 0; PCMDMX_ERROR dmxErr = PCMDMX_OK; if ( flags & (AACDEC_INTR | AACDEC_CLRHIST) ) { /* delete data from the past (e.g. mixdown coeficients) */ @@ -924,13 +987,34 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( self->channelType, self->channelIndices, self->channelOutputMapping, - NULL + (self->limiterEnableCurr) ? &pcmLimiterScale : NULL ); if (dmxErr == PCMDMX_INVALID_MODE) { /* Announce the framework that the current combination of channel configuration and downmix * settings are not know to produce a predictable behavior and thus maybe produce strange output. */ ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; } + + if ( flags & AACDEC_CLRHIST ) { + /* Delete the delayed signal. */ + resetLimiter(self->hLimiter); + } + if (self->limiterEnableCurr) + { + /* Set actual signal parameters */ + setLimiterNChannels(self->hLimiter, self->streamInfo.numChannels); + setLimiterSampleRate(self->hLimiter, self->streamInfo.sampleRate); + + applyLimiter( + self->hLimiter, + pTimeData, + self->extGain, + &pcmLimiterScale, + 1, + self->extGainDelay, + self->streamInfo.frameSize + ); + } } @@ -956,6 +1040,9 @@ LINKSPEC_CPP void aacDecoder_Close ( HANDLE_AACDECODER self ) return; + if (self->hLimiter != NULL) { + destroyLimiter(self->hLimiter); + } if (self->hPcmUtils != NULL) { pcmDmx_Close( &self->hPcmUtils ); |