aboutsummaryrefslogtreecommitdiffstats
path: root/fdk-aac/libAACdec/src/aacdec_drc.cpp
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2019-11-11 11:38:02 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2019-11-11 11:38:02 +0100
commit0e5af65c467b2423a0b857ae3ad98c91acc1e190 (patch)
treed07f69550d8886271e44fe79c4dcfb299cafbd38 /fdk-aac/libAACdec/src/aacdec_drc.cpp
parentefe406d9724f959c8bc2a31802559ca6d41fd897 (diff)
downloadODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.gz
ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.bz2
ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.zip
Include patched FDK-AAC in the repository
The initial idea was to get the DAB+ patch into upstream, but since that follows the android source releases, there is no place for a custom DAB+ patch there. So instead of having to maintain a patched fdk-aac that has to have the same .so version as the distribution package on which it is installed, we prefer having a separate fdk-aac-dab library to avoid collision. At that point, there's no reason to keep fdk-aac in a separate repository, as odr-audioenc is the only tool that needs DAB+ encoding support. Including it here simplifies installation, and makes it consistent with toolame-dab, also shipped in this repository. DAB+ decoding support (needed by ODR-SourceCompanion, dablin, etisnoop, welle.io and others) can be done using upstream FDK-AAC.
Diffstat (limited to 'fdk-aac/libAACdec/src/aacdec_drc.cpp')
-rw-r--r--fdk-aac/libAACdec/src/aacdec_drc.cpp1355
1 files changed, 1355 insertions, 0 deletions
diff --git a/fdk-aac/libAACdec/src/aacdec_drc.cpp b/fdk-aac/libAACdec/src/aacdec_drc.cpp
new file mode 100644
index 0000000..922a09e
--- /dev/null
+++ b/fdk-aac/libAACdec/src/aacdec_drc.cpp
@@ -0,0 +1,1355 @@
+/* -----------------------------------------------------------------------------
+Software License for The Fraunhofer FDK AAC Codec Library for Android
+
+© Copyright 1995 - 2018 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
+----------------------------------------------------------------------------- */
+
+/**************************** AAC decoder library ******************************
+
+ Author(s): Christian Griebel
+
+ Description: Dynamic range control (DRC) decoder tool for AAC
+
+*******************************************************************************/
+
+#include "aacdec_drc.h"
+
+#include "channelinfo.h"
+#include "aac_rom.h"
+
+#include "sbrdecoder.h"
+
+/*
+ * Dynamic Range Control
+ */
+
+/* For parameter conversion */
+#define DRC_PARAMETER_BITS (7)
+#define DRC_MAX_QUANT_STEPS (1 << DRC_PARAMETER_BITS)
+#define DRC_MAX_QUANT_FACTOR (DRC_MAX_QUANT_STEPS - 1)
+#define DRC_PARAM_QUANT_STEP \
+ (FL2FXCONST_DBL(1.0f / (float)DRC_MAX_QUANT_FACTOR))
+#define DRC_PARAM_SCALE (1)
+#define DRC_SCALING_MAX \
+ ((FIXP_DBL)((INT)(DRC_PARAM_QUANT_STEP >> DRC_PARAM_SCALE) * (INT)127))
+
+#define DRC_BLOCK_LEN (1024)
+#define DRC_BAND_MULT (4)
+#define DRC_BLOCK_LEN_DIV_BAND_MULT (DRC_BLOCK_LEN / DRC_BAND_MULT)
+
+#define MAX_REFERENCE_LEVEL (127)
+
+#define DRC_HEAVY_THRESHOLD_DB (10)
+
+#define DVB_ANC_DATA_SYNC_BYTE (0xBC) /* DVB ancillary data sync byte. */
+
+#define OFF 0
+#define ON 1
+
+static INT convert_drcParam(FIXP_DBL param_dbl) {
+ /* converts an internal DRC boost/cut scaling factor in FIXP_DBL
+ (which is downscaled by DRC_PARAM_SCALE)
+ back to an integer value between 0 and 127. */
+ LONG param_long;
+
+ param_long = (LONG)param_dbl >> 7;
+ param_long = param_long * (INT)DRC_MAX_QUANT_FACTOR;
+ param_long >>= 31 - 7 - DRC_PARAM_SCALE - 1;
+ param_long += 1; /* for rounding */
+ param_long >>= 1;
+
+ return (INT)param_long;
+}
+
+/*!
+ \brief Initialize DRC information
+
+ \self Handle of DRC info
+
+ \return none
+*/
+void aacDecoder_drcInit(HANDLE_AAC_DRC self) {
+ CDrcParams *pParams;
+
+ if (self == NULL) {
+ return;
+ }
+
+ /* init control fields */
+ self->enable = OFF;
+ self->numThreads = 0;
+
+ /* init params */
+ pParams = &self->params;
+ pParams->bsDelayEnable = 0;
+ pParams->cut = FL2FXCONST_DBL(0.0f);
+ pParams->usrCut = FL2FXCONST_DBL(0.0f);
+ pParams->boost = FL2FXCONST_DBL(0.0f);
+ pParams->usrBoost = FL2FXCONST_DBL(0.0f);
+ pParams->targetRefLevel = -1;
+ pParams->expiryFrame = AACDEC_DRC_DFLT_EXPIRY_FRAMES;
+ pParams->applyDigitalNorm = OFF;
+ pParams->applyHeavyCompression = OFF;
+ pParams->usrApplyHeavyCompression = OFF;
+
+ pParams->defaultPresentationMode = DISABLED_PARAMETER_HANDLING;
+ pParams->encoderTargetLevel = MAX_REFERENCE_LEVEL; /* worst case assumption */
+
+ self->update = 1;
+ self->numOutChannels = 0;
+ self->prevAacNumChannels = 0;
+
+ /* initial program ref level = target ref level */
+ self->progRefLevel = pParams->targetRefLevel;
+ self->progRefLevelPresent = 0;
+ self->presMode = -1;
+ self->uniDrcPrecedence = 0;
+}
+
+/*!
+ \brief Initialize DRC control data for one channel
+
+ \self Handle of DRC info
+
+ \return none
+*/
+void aacDecoder_drcInitChannelData(CDrcChannelData *pDrcChData) {
+ if (pDrcChData != NULL) {
+ pDrcChData->expiryCount = 0;
+ pDrcChData->numBands = 1;
+ pDrcChData->bandTop[0] = DRC_BLOCK_LEN_DIV_BAND_MULT - 1;
+ pDrcChData->drcValue[0] = 0;
+ pDrcChData->drcInterpolationScheme = 0;
+ pDrcChData->drcDataType = UNKNOWN_PAYLOAD;
+ }
+}
+
+/*!
+ \brief Set one single DRC parameter
+
+ \self Handle of DRC info.
+ \param Parameter to be set.
+ \value Value to be set.
+
+ \return an error code.
+*/
+AAC_DECODER_ERROR aacDecoder_drcSetParam(HANDLE_AAC_DRC self,
+ AACDEC_DRC_PARAM param, INT value) {
+ AAC_DECODER_ERROR ErrorStatus = AAC_DEC_OK;
+
+ switch (param) {
+ case DRC_CUT_SCALE:
+ /* set attenuation scale factor */
+ if ((value < 0) || (value > DRC_MAX_QUANT_FACTOR)) {
+ return AAC_DEC_SET_PARAM_FAIL;
+ }
+ if (self == NULL) {
+ return AAC_DEC_INVALID_HANDLE;
+ }
+ self->params.usrCut = (FIXP_DBL)(
+ (INT)(DRC_PARAM_QUANT_STEP >> DRC_PARAM_SCALE) * (INT)value);
+ self->update = 1;
+ break;
+ case DRC_BOOST_SCALE:
+ /* set boost factor */
+ if ((value < 0) || (value > DRC_MAX_QUANT_FACTOR)) {
+ return AAC_DEC_SET_PARAM_FAIL;
+ }
+ if (self == NULL) {
+ return AAC_DEC_INVALID_HANDLE;
+ }
+ self->params.usrBoost = (FIXP_DBL)(
+ (INT)(DRC_PARAM_QUANT_STEP >> DRC_PARAM_SCALE) * (INT)value);
+ self->update = 1;
+ break;
+ case TARGET_REF_LEVEL:
+ if (value > MAX_REFERENCE_LEVEL || value < -MAX_REFERENCE_LEVEL) {
+ return AAC_DEC_SET_PARAM_FAIL;
+ }
+ if (self == NULL) {
+ return AAC_DEC_INVALID_HANDLE;
+ }
+ if (value < 0) {
+ self->params.applyDigitalNorm = OFF;
+ self->params.targetRefLevel = -1;
+ } else {
+ /* ref_level must be between 0 and MAX_REFERENCE_LEVEL, inclusive */
+ self->params.applyDigitalNorm = ON;
+ if (self->params.targetRefLevel != (SCHAR)value) {
+ self->params.targetRefLevel = (SCHAR)value;
+ self->progRefLevel = (SCHAR)value; /* Always set the program reference
+ level equal to the target level
+ according to 4.5.2.7.3 of
+ ISO/IEC 14496-3. */
+ }
+ self->update = 1;
+ }
+ break;
+ case APPLY_NORMALIZATION:
+ if ((value != OFF) && (value != ON)) {
+ 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 != OFF) && (value != ON)) {
+ return AAC_DEC_SET_PARAM_FAIL;
+ }
+ if (self == NULL) {
+ return AAC_DEC_INVALID_HANDLE;
+ }
+ /* Store new parameter value */
+ self->params.usrApplyHeavyCompression = (UCHAR)value;
+ self->update = 1;
+ break;
+ case DEFAULT_PRESENTATION_MODE:
+ if (value < AAC_DRC_PARAMETER_HANDLING_DISABLED ||
+ value > AAC_DRC_PRESENTATION_MODE_2_DEFAULT) {
+ return AAC_DEC_SET_PARAM_FAIL;
+ }
+ if (self == NULL) {
+ return AAC_DEC_INVALID_HANDLE;
+ }
+ self->params.defaultPresentationMode =
+ (AACDEC_DRC_PARAMETER_HANDLING)value;
+ self->update = 1;
+ break;
+ case ENCODER_TARGET_LEVEL:
+ if (value > MAX_REFERENCE_LEVEL || value < 0) {
+ return AAC_DEC_SET_PARAM_FAIL;
+ }
+ if (self == NULL) {
+ return AAC_DEC_INVALID_HANDLE;
+ }
+ self->params.encoderTargetLevel = (UCHAR)value;
+ self->update = 1;
+ break;
+ case DRC_BS_DELAY:
+ if (value < 0 || value > 1) {
+ return AAC_DEC_SET_PARAM_FAIL;
+ }
+ if (self == NULL) {
+ return AAC_DEC_INVALID_HANDLE;
+ }
+ self->params.bsDelayEnable = value;
+ break;
+ case DRC_DATA_EXPIRY_FRAME:
+ if (self == NULL) {
+ return AAC_DEC_INVALID_HANDLE;
+ }
+ self->params.expiryFrame = (value > 0) ? (UINT)value : 0;
+ break;
+ case MAX_OUTPUT_CHANNELS:
+ if (self == NULL) {
+ return AAC_DEC_INVALID_HANDLE;
+ }
+ self->numOutChannels = (INT)value;
+ self->update = 1;
+ break;
+ case UNIDRC_PRECEDENCE:
+ if (self == NULL) {
+ return AAC_DEC_INVALID_HANDLE;
+ }
+ self->uniDrcPrecedence = (UCHAR)value;
+ break;
+ default:
+ return AAC_DEC_SET_PARAM_FAIL;
+ } /* switch(param) */
+
+ return ErrorStatus;
+}
+
+static int parseExcludedChannels(UINT *excludedChnsMask,
+ HANDLE_FDK_BITSTREAM bs) {
+ UINT excludeMask = 0;
+ UINT i, j;
+ int bitCnt = 9;
+
+ for (i = 0, j = 1; i < 7; i++, j <<= 1) {
+ if (FDKreadBits(bs, 1)) {
+ excludeMask |= j;
+ }
+ }
+
+ /* additional_excluded_chns */
+ while (FDKreadBits(bs, 1)) {
+ for (i = 0; i < 7; i++, j <<= 1) {
+ if (FDKreadBits(bs, 1)) {
+ excludeMask |= j;
+ }
+ }
+ bitCnt += 9;
+ FDK_ASSERT(j < (UINT)-1);
+ }
+
+ *excludedChnsMask = excludeMask;
+
+ return (bitCnt);
+}
+
+/*!
+ \brief Save DRC payload bitstream position
+
+ \self Handle of DRC info
+ \bs Handle of FDK bitstream
+
+ \return The number of DRC payload bits
+*/
+int aacDecoder_drcMarkPayload(HANDLE_AAC_DRC self, HANDLE_FDK_BITSTREAM bs,
+ AACDEC_DRC_PAYLOAD_TYPE type) {
+ UINT bsStartPos;
+ int i, numBands = 1, bitCnt = 0;
+
+ if (self == NULL) {
+ return 0;
+ }
+
+ bsStartPos = FDKgetValidBits(bs);
+
+ switch (type) {
+ case MPEG_DRC_EXT_DATA: {
+ bitCnt = 4;
+
+ if (FDKreadBits(bs, 1)) { /* pce_tag_present */
+ FDKreadBits(bs, 8); /* pce_instance_tag + drc_tag_reserved_bits */
+ bitCnt += 8;
+ }
+
+ if (FDKreadBits(bs, 1)) { /* excluded_chns_present */
+ FDKreadBits(bs, 7); /* exclude mask [0..7] */
+ bitCnt += 8;
+ while (FDKreadBits(bs, 1)) { /* additional_excluded_chns */
+ FDKreadBits(bs, 7); /* exclude mask [x..y] */
+ bitCnt += 8;
+ }
+ }
+
+ if (FDKreadBits(bs, 1)) { /* drc_bands_present */
+ numBands += FDKreadBits(bs, 4); /* drc_band_incr */
+ FDKreadBits(bs, 4); /* reserved */
+ bitCnt += 8;
+ for (i = 0; i < numBands; i++) {
+ FDKreadBits(bs, 8); /* drc_band_top[i] */
+ bitCnt += 8;
+ }
+ }
+
+ if (FDKreadBits(bs, 1)) { /* prog_ref_level_present */
+ FDKreadBits(bs, 8); /* prog_ref_level + prog_ref_level_reserved_bits */
+ bitCnt += 8;
+ }
+
+ for (i = 0; i < numBands; i++) {
+ FDKreadBits(bs, 8); /* dyn_rng_sgn[i] + dyn_rng_ctl[i] */
+ bitCnt += 8;
+ }
+
+ if ((self->numPayloads < MAX_DRC_THREADS) &&
+ ((INT)FDKgetValidBits(bs) >= 0)) {
+ self->drcPayloadPosition[self->numPayloads++] = bsStartPos;
+ }
+ } break;
+
+ case DVB_DRC_ANC_DATA:
+ bitCnt += 8;
+ /* check sync word */
+ if (FDKreadBits(bs, 8) == DVB_ANC_DATA_SYNC_BYTE) {
+ int dmxLevelsPresent, compressionPresent;
+ int coarseGrainTcPresent, fineGrainTcPresent;
+
+ /* bs_info field */
+ FDKreadBits(
+ bs,
+ 8); /* mpeg_audio_type, dolby_surround_mode, presentation_mode */
+ bitCnt += 8;
+
+ /* Evaluate ancillary_data_status */
+ FDKreadBits(bs, 3); /* reserved, set to 0 */
+ dmxLevelsPresent =
+ FDKreadBits(bs, 1); /* downmixing_levels_MPEG4_status */
+ FDKreadBits(bs, 1); /* reserved, set to 0 */
+ compressionPresent =
+ FDKreadBits(bs, 1); /* audio_coding_mode_and_compression status */
+ coarseGrainTcPresent =
+ FDKreadBits(bs, 1); /* coarse_grain_timecode_status */
+ fineGrainTcPresent =
+ FDKreadBits(bs, 1); /* fine_grain_timecode_status */
+ bitCnt += 8;
+
+ /* MPEG4 downmixing levels */
+ if (dmxLevelsPresent) {
+ FDKreadBits(bs, 8); /* downmixing_levels_MPEG4 */
+ bitCnt += 8;
+ }
+ /* audio coding mode and compression status */
+ if (compressionPresent) {
+ FDKreadBits(bs, 16); /* audio_coding_mode, Compression_value */
+ bitCnt += 16;
+ }
+ /* coarse grain timecode */
+ if (coarseGrainTcPresent) {
+ FDKreadBits(bs, 16); /* coarse_grain_timecode */
+ bitCnt += 16;
+ }
+ /* fine grain timecode */
+ if (fineGrainTcPresent) {
+ FDKreadBits(bs, 16); /* fine_grain_timecode */
+ bitCnt += 16;
+ }
+ if (!self->dvbAncDataAvailable && ((INT)FDKgetValidBits(bs) >= 0)) {
+ self->dvbAncDataPosition = bsStartPos;
+ self->dvbAncDataAvailable = 1;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return (bitCnt);
+}
+
+/*!
+ \brief Parse DRC parameters from bitstream
+
+ \bs Handle of FDK bitstream (in)
+ \pDrcBs Pointer to DRC payload data container (out)
+ \payloadPosition Bitstream position of MPEG DRC data chunk (in)
+
+ \return Flag telling whether new DRC data has been found or not.
+*/
+static int aacDecoder_drcParse(HANDLE_FDK_BITSTREAM bs, CDrcPayload *pDrcBs,
+ UINT payloadPosition) {
+ int i, numBands;
+
+ /* Move to the beginning of the DRC payload field */
+ FDKpushBiDirectional(bs, (INT)FDKgetValidBits(bs) - (INT)payloadPosition);
+
+ /* pce_tag_present */
+ if (FDKreadBits(bs, 1)) {
+ pDrcBs->pceInstanceTag = FDKreadBits(bs, 4); /* pce_instance_tag */
+ /* only one program supported */
+ FDKreadBits(bs, 4); /* drc_tag_reserved_bits */
+ } else {
+ pDrcBs->pceInstanceTag = -1; /* not present */
+ }
+
+ if (FDKreadBits(bs, 1)) { /* excluded_chns_present */
+ /* get excluded_chn_mask */
+ parseExcludedChannels(&pDrcBs->excludedChnsMask, bs);
+ } else {
+ pDrcBs->excludedChnsMask = 0;
+ }
+
+ numBands = 1;
+ if (FDKreadBits(bs, 1)) /* drc_bands_present */
+ {
+ /* get band_incr */
+ numBands += FDKreadBits(bs, 4); /* drc_band_incr */
+ pDrcBs->channelData.drcInterpolationScheme =
+ FDKreadBits(bs, 4); /* drc_interpolation_scheme */
+ /* band_top */
+ for (i = 0; i < numBands; i++) {
+ pDrcBs->channelData.bandTop[i] = FDKreadBits(bs, 8); /* drc_band_top[i] */
+ }
+ } else {
+ pDrcBs->channelData.bandTop[0] = DRC_BLOCK_LEN_DIV_BAND_MULT -
+ 1; /* ... comprising the whole spectrum. */
+ ;
+ }
+
+ pDrcBs->channelData.numBands = numBands;
+
+ if (FDKreadBits(bs, 1)) /* prog_ref_level_present */
+ {
+ pDrcBs->progRefLevel = FDKreadBits(bs, 7); /* prog_ref_level */
+ FDKreadBits(bs, 1); /* prog_ref_level_reserved_bits */
+ } else {
+ pDrcBs->progRefLevel = -1;
+ }
+
+ for (i = 0; i < numBands; i++) {
+ pDrcBs->channelData.drcValue[i] = FDKreadBits(bs, 1)
+ << 7; /* dyn_rng_sgn[i] */
+ pDrcBs->channelData.drcValue[i] |=
+ FDKreadBits(bs, 7) & 0x7F; /* dyn_rng_ctl[i] */
+ }
+
+ /* Set DRC payload type */
+ pDrcBs->channelData.drcDataType = MPEG_DRC_EXT_DATA;
+
+ return (1);
+}
+
+/*!
+ \brief Parse heavy compression value transported in DSEs of DVB streams with
+ MPEG-4 content.
+
+ \bs Handle of FDK bitstream (in)
+ \pDrcBs Pointer to DRC payload data container (out)
+ \payloadPosition Bitstream position of DVB ancillary data chunk
+
+ \return Flag telling whether new DRC data has been found or not.
+*/
+#define DVB_COMPRESSION_SCALE (8) /* 48,164 dB */
+
+static int aacDecoder_drcReadCompression(HANDLE_FDK_BITSTREAM bs,
+ CDrcPayload *pDrcBs,
+ UINT payloadPosition) {
+ int foundDrcData = 0;
+ int dmxLevelsPresent, compressionPresent;
+
+ /* Move to the beginning of the DRC payload field */
+ FDKpushBiDirectional(bs, (INT)FDKgetValidBits(bs) - (INT)payloadPosition);
+
+ /* Sanity checks */
+ if (FDKgetValidBits(bs) < 24) {
+ return 0;
+ }
+
+ /* Check sync word */
+ if (FDKreadBits(bs, 8) != DVB_ANC_DATA_SYNC_BYTE) {
+ return 0;
+ }
+
+ /* Evaluate bs_info field */
+ if (FDKreadBits(bs, 2) != 3) { /* mpeg_audio_type */
+ /* No MPEG-4 audio data */
+ return 0;
+ }
+ FDKreadBits(bs, 2); /* dolby_surround_mode */
+ pDrcBs->presMode = FDKreadBits(bs, 2); /* presentation_mode */
+ FDKreadBits(bs, 1); /* stereo_downmix_mode */
+ if (FDKreadBits(bs, 1) != 0) { /* reserved, set to 0 */
+ return 0;
+ }
+
+ /* Evaluate ancillary_data_status */
+ if (FDKreadBits(bs, 3) != 0) { /* reserved, set to 0 */
+ return 0;
+ }
+ dmxLevelsPresent = FDKreadBits(bs, 1); /* downmixing_levels_MPEG4_status */
+ /*extensionPresent =*/FDKreadBits(bs,
+ 1); /* ancillary_data_extension_status; */
+ compressionPresent =
+ FDKreadBits(bs, 1); /* audio_coding_mode_and_compression status */
+ /*coarseGrainTcPresent =*/FDKreadBits(bs,
+ 1); /* coarse_grain_timecode_status */
+ /*fineGrainTcPresent =*/FDKreadBits(bs, 1); /* fine_grain_timecode_status */
+
+ if (dmxLevelsPresent) {
+ FDKreadBits(bs, 8); /* downmixing_levels_MPEG4 */
+ }
+
+ /* audio_coding_mode_and_compression_status */
+ if (compressionPresent) {
+ UCHAR compressionOn, compressionValue;
+
+ /* audio_coding_mode */
+ if (FDKreadBits(bs, 7) != 0) { /* The reserved bits shall be set to "0". */
+ return 0;
+ }
+ compressionOn = (UCHAR)FDKreadBits(bs, 1); /* compression_on */
+ compressionValue = (UCHAR)FDKreadBits(bs, 8); /* Compression_value */
+
+ if (compressionOn) {
+ /* A compression value is available so store the data just like MPEG DRC
+ * data */
+ pDrcBs->channelData.numBands = 1; /* One band ... */
+ pDrcBs->channelData.drcValue[0] =
+ compressionValue; /* ... with one value ... */
+ pDrcBs->channelData.bandTop[0] =
+ DRC_BLOCK_LEN_DIV_BAND_MULT -
+ 1; /* ... comprising the whole spectrum. */
+ ;
+ pDrcBs->pceInstanceTag = -1; /* Not present */
+ pDrcBs->progRefLevel = -1; /* Not present */
+ pDrcBs->channelData.drcDataType =
+ DVB_DRC_ANC_DATA; /* Set DRC payload type to DVB. */
+ foundDrcData = 1;
+ }
+ }
+
+ return (foundDrcData);
+}
+
+/*
+ * Extract DRC payload from bitstream and map it to channels.
+ * Valid return values are:
+ * -1 : An unexpected error occured.
+ * 0 : No error and no valid DRC data available.
+ * 1 : No error and valid DRC data has been mapped.
+ */
+static int aacDecoder_drcExtractAndMap(
+ HANDLE_AAC_DRC self, HANDLE_FDK_BITSTREAM hBs,
+ CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[],
+ UCHAR pceInstanceTag,
+ UCHAR channelMapping[], /* Channel mapping translating drcChannel index to
+ canonical channel index */
+ int validChannels) {
+ CDrcPayload threadBs[MAX_DRC_THREADS];
+ CDrcPayload *validThreadBs[MAX_DRC_THREADS];
+ CDrcParams *pParams;
+ UINT backupBsPosition;
+ int result = 0;
+ int i, thread, validThreads = 0;
+
+ FDK_ASSERT(self != NULL);
+ FDK_ASSERT(hBs != NULL);
+ FDK_ASSERT(pAacDecoderStaticChannelInfo != NULL);
+
+ pParams = &self->params;
+
+ self->numThreads = 0;
+ backupBsPosition = FDKgetValidBits(hBs);
+
+ for (i = 0; i < self->numPayloads && self->numThreads < MAX_DRC_THREADS;
+ i++) {
+ /* Init payload data chunk. The memclear is very important because it
+ initializes the most values. Without it the module wouldn't work properly
+ or crash. */
+ FDKmemclear(&threadBs[self->numThreads], sizeof(CDrcPayload));
+ threadBs[self->numThreads].channelData.bandTop[0] =
+ DRC_BLOCK_LEN_DIV_BAND_MULT - 1;
+
+ /* Extract payload */
+ self->numThreads += aacDecoder_drcParse(hBs, &threadBs[self->numThreads],
+ self->drcPayloadPosition[i]);
+ }
+ self->numPayloads = 0;
+
+ if (self->dvbAncDataAvailable &&
+ self->numThreads < MAX_DRC_THREADS) { /* Append a DVB heavy compression
+ payload thread if available. */
+
+ /* Init payload data chunk. The memclear is very important because it
+ initializes the most values. Without it the module wouldn't work properly
+ or crash. */
+ FDKmemclear(&threadBs[self->numThreads], sizeof(CDrcPayload));
+ threadBs[self->numThreads].channelData.bandTop[0] =
+ DRC_BLOCK_LEN_DIV_BAND_MULT - 1;
+
+ /* Extract payload */
+ self->numThreads += aacDecoder_drcReadCompression(
+ hBs, &threadBs[self->numThreads], self->dvbAncDataPosition);
+ }
+ self->dvbAncDataAvailable = 0;
+
+ /* Reset the bitbufffer */
+ FDKpushBiDirectional(hBs, (INT)FDKgetValidBits(hBs) - (INT)backupBsPosition);
+
+ /* calculate number of valid bits in excl_chn_mask */
+
+ /* coupling channels not supported */
+
+ /* check for valid threads */
+ for (thread = 0; thread < self->numThreads; thread++) {
+ CDrcPayload *pThreadBs = &threadBs[thread];
+ int numExclChns = 0;
+
+ switch ((AACDEC_DRC_PAYLOAD_TYPE)pThreadBs->channelData.drcDataType) {
+ default:
+ continue;
+ case MPEG_DRC_EXT_DATA:
+ case DVB_DRC_ANC_DATA:
+ break;
+ }
+
+ if (pThreadBs->pceInstanceTag >= 0) { /* if PCE tag present */
+ if (pThreadBs->pceInstanceTag != pceInstanceTag) {
+ continue; /* don't accept */
+ }
+ }
+
+ /* calculate number of excluded channels */
+ if (pThreadBs->excludedChnsMask > 0) {
+ INT exclMask = pThreadBs->excludedChnsMask;
+ int ch;
+ for (ch = 0; ch < validChannels; ch++) {
+ numExclChns += exclMask & 0x1;
+ exclMask >>= 1;
+ }
+ }
+ if (numExclChns < validChannels) {
+ validThreadBs[validThreads] = pThreadBs;
+ validThreads++;
+ }
+ }
+
+ /* map DRC bitstream information onto DRC channel information */
+ for (thread = 0; thread < validThreads; thread++) {
+ CDrcPayload *pThreadBs = validThreadBs[thread];
+ INT exclMask = pThreadBs->excludedChnsMask;
+ AACDEC_DRC_PAYLOAD_TYPE drcPayloadType =
+ (AACDEC_DRC_PAYLOAD_TYPE)pThreadBs->channelData.drcDataType;
+ int ch;
+
+ /* last progRefLevel transmitted is the one that is used
+ * (but it should really only be transmitted once per block!)
+ */
+ if (pThreadBs->progRefLevel >= 0) {
+ self->progRefLevel = pThreadBs->progRefLevel;
+ self->progRefLevelPresent = 1;
+ self->prlExpiryCount = 0; /* Got a new value -> Reset counter */
+ }
+
+ if (drcPayloadType == DVB_DRC_ANC_DATA) {
+ /* Announce the presentation mode of this valid thread. */
+ self->presMode = pThreadBs->presMode;
+ }
+
+ /* SCE, CPE and LFE */
+ for (ch = 0; ch < validChannels; ch++) {
+ AACDEC_DRC_PAYLOAD_TYPE prvPayloadType = UNKNOWN_PAYLOAD;
+ int mapedChannel = channelMapping[ch];
+
+ if ((mapedChannel >= validChannels) ||
+ ((exclMask & (1 << mapedChannel)) != 0))
+ continue;
+
+ if ((pParams->expiryFrame <= 0) ||
+ (pAacDecoderStaticChannelInfo[ch]->drcData.expiryCount <
+ pParams->expiryFrame)) {
+ prvPayloadType =
+ (AACDEC_DRC_PAYLOAD_TYPE)pAacDecoderStaticChannelInfo[ch]
+ ->drcData.drcDataType;
+ }
+ if (((drcPayloadType == MPEG_DRC_EXT_DATA) &&
+ (prvPayloadType != DVB_DRC_ANC_DATA)) ||
+ ((drcPayloadType == DVB_DRC_ANC_DATA) &&
+ (pParams->applyHeavyCompression ==
+ ON))) { /* copy thread to channel */
+ pAacDecoderStaticChannelInfo[ch]->drcData = pThreadBs->channelData;
+ result = 1;
+ }
+ }
+ /* CCEs not supported by now */
+ }
+
+ /* Increment and check expiry counter for the program reference level: */
+ if ((pParams->expiryFrame > 0) &&
+ (self->prlExpiryCount++ >
+ pParams->expiryFrame)) { /* The program reference level is too old, so
+ set it back to the target level. */
+ self->progRefLevelPresent = 0;
+ self->progRefLevel = pParams->targetRefLevel;
+ self->prlExpiryCount = 0;
+ }
+
+ return result;
+}
+
+void aacDecoder_drcApply(HANDLE_AAC_DRC self, void *pSbrDec,
+ CAacDecoderChannelInfo *pAacDecoderChannelInfo,
+ CDrcChannelData *pDrcChData, FIXP_DBL *extGain,
+ int ch, /* needed only for SBR */
+ int aacFrameSize, int bSbrPresent) {
+ int band, bin, numBands;
+ int bottom = 0;
+ int modifyBins = 0;
+
+ FIXP_DBL max_mantissa;
+ INT max_exponent;
+
+ 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];
+
+ CDrcParams *pParams = &self->params;
+
+ FIXP_DBL *pSpectralCoefficient =
+ SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient);
+ CIcsInfo *pIcsInfo = &pAacDecoderChannelInfo->icsInfo;
+ SHORT *pSpecScale = pAacDecoderChannelInfo->specScale;
+
+ int winSeq = pIcsInfo->WindowSequence;
+
+ /* Increment and check expiry counter */
+ if ((pParams->expiryFrame > 0) &&
+ (++pDrcChData->expiryCount >
+ pParams->expiryFrame)) { /* The DRC data is too old, so delete it. */
+ aacDecoder_drcInitChannelData(pDrcChData);
+ }
+
+ if (self->enable != ON) {
+ 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;
+ }
+
+ numBands = pDrcChData->numBands;
+
+ /* If program reference normalization is done in the digital domain,
+ modify factor to perform normalization. prog_ref_level can
+ alternatively be passed to the system for modification of the level in
+ the analog domain. Analog level modification avoids problems with
+ reduced DAC SNR (if signal is attenuated) or clipping (if signal is
+ boosted) */
+
+ if (pParams->targetRefLevel >= 0) {
+ /* 0.5^((targetRefLevel - progRefLevel)/24) */
+ norm_mantissa =
+ fLdPow(FL2FXCONST_DBL(-1.0), /* log2(0.5) */
+ 0,
+ (FIXP_DBL)((INT)(FL2FXCONST_DBL(1.0f / 24.0) >> 3) *
+ (INT)(pParams->targetRefLevel - self->progRefLevel)),
+ 3, &norm_exponent);
+ }
+ /* 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 == OFF) {
+ /* Reset normalization gain since this module must not apply it */
+ norm_mantissa = FL2FXCONST_DBL(0.5f);
+ norm_exponent = 1;
+ }
+
+ /* calc scale factors */
+ for (band = 0; band < numBands; band++) {
+ UCHAR drcVal = pDrcChData->drcValue[band];
+
+ fact_mantissa[band] = FL2FXCONST_DBL(0.5f);
+ fact_exponent[band] = 1;
+
+ if ((pParams->applyHeavyCompression == ON) &&
+ ((AACDEC_DRC_PAYLOAD_TYPE)pDrcChData->drcDataType ==
+ DVB_DRC_ANC_DATA)) {
+ INT compressionFactorVal_e;
+ int valX, valY;
+
+ valX = drcVal >> 4;
+ valY = drcVal & 0x0F;
+
+ /* calculate the unscaled heavy compression factor.
+ compressionFactor = 48.164 - 6.0206*valX - 0.4014*valY dB
+ range: -48.166 dB to 48.164 dB */
+ if (drcVal != 0x7F) {
+ fact_mantissa[band] = fPowInt(
+ FL2FXCONST_DBL(0.95483867181), /* -0.4014dB = 0.95483867181 */
+ 0, valY, &compressionFactorVal_e);
+
+ /* -0.0008dB (48.164 - 6.0206*8 = -0.0008) */
+ fact_mantissa[band] =
+ fMult(FL2FXCONST_DBL(0.99990790084), fact_mantissa[band]);
+
+ fact_exponent[band] =
+ DVB_COMPRESSION_SCALE - valX + compressionFactorVal_e;
+ }
+ } else if ((AACDEC_DRC_PAYLOAD_TYPE)pDrcChData->drcDataType ==
+ MPEG_DRC_EXT_DATA) {
+ /* apply the scaled dynamic range control words to factor.
+ * if scaling drc_cut (or drc_boost), or control word drc_mantissa is 0
+ * then there is no dynamic range compression
+ *
+ * if pDrcChData->drcSgn[band] is
+ * 1 then gain is < 1 : factor = 2^(-self->cut *
+ * pDrcChData->drcMag[band] / 24) 0 then gain is > 1 : factor = 2^(
+ * self->boost * pDrcChData->drcMag[band] / 24)
+ */
+
+ if ((drcVal & 0x7F) > 0) {
+ FIXP_DBL tParamVal = (drcVal & 0x80) ? -pParams->cut : pParams->boost;
+
+ fact_mantissa[band] = f2Pow(
+ (FIXP_DBL)((INT)fMult(FL2FXCONST_DBL(1.0f / 192.0f), tParamVal) *
+ (drcVal & 0x7F)),
+ 3 + DRC_PARAM_SCALE, &fact_exponent[band]);
+ }
+ }
+
+ fact_mantissa[band] = fMult(fact_mantissa[band], norm_mantissa);
+ fact_exponent[band] += norm_exponent;
+
+ } /* end loop over bands */
+
+ /* normalizations */
+ {
+ int res;
+
+ max_mantissa = FL2FXCONST_DBL(0.0f);
+ max_exponent = 0;
+ for (band = 0; band < numBands; band++) {
+ max_mantissa = fixMax(max_mantissa, fact_mantissa[band]);
+ max_exponent = fixMax(max_exponent, fact_exponent[band]);
+ }
+
+ /* left shift factors to gain accurancy */
+ res = CntLeadingZeros(max_mantissa) - 1;
+
+ /* above topmost DRC band gain factor is 1 */
+ if (((pDrcChData->bandTop[fMax(0, numBands - 1)] + 1) << 2) < aacFrameSize)
+ res = 0;
+
+ if (res > 0) {
+ res = fixMin(res, max_exponent);
+ max_exponent -= res;
+
+ for (band = 0; band < numBands; band++) {
+ fact_mantissa[band] <<= res;
+ fact_exponent[band] -= res;
+ }
+ }
+
+ /* normalize magnitudes to one scale factor */
+ for (band = 0; band < numBands; band++) {
+ if (fact_exponent[band] < max_exponent) {
+ fact_mantissa[band] >>= max_exponent - fact_exponent[band];
+ }
+ if (fact_mantissa[band] != FL2FXCONST_DBL(0.5f)) {
+ modifyBins = 1;
+ }
+ }
+ if (max_exponent != 1) {
+ modifyBins = 1;
+ }
+ }
+
+ /* apply factor to spectral lines
+ * short blocks must take care that bands fall on
+ * block boundaries!
+ */
+ if (!bSbrPresent) {
+ bottom = 0;
+
+ if (!modifyBins) {
+ /* We don't have to modify the spectral bins because the fractional part
+ of all factors is 0.5. In order to keep accurancy we don't apply the
+ factor but decrease the exponent instead. */
+ max_exponent -= 1;
+ } else {
+ for (band = 0; band < numBands; band++) {
+ int top = fixMin((int)((pDrcChData->bandTop[band] + 1) << 2),
+ aacFrameSize); /* ... * DRC_BAND_MULT; */
+
+ for (bin = bottom; bin < top; bin++) {
+ pSpectralCoefficient[bin] =
+ fMult(pSpectralCoefficient[bin], fact_mantissa[band]);
+ }
+
+ bottom = top;
+ }
+ }
+
+ /* above topmost DRC band gain factor is 1 */
+ if (max_exponent > 0) {
+ for (bin = bottom; bin < aacFrameSize; bin += 1) {
+ pSpectralCoefficient[bin] >>= max_exponent;
+ }
+ }
+
+ /* adjust scaling */
+ pSpecScale[0] += max_exponent;
+
+ if (winSeq == BLOCK_SHORT) {
+ int win;
+ for (win = 1; win < 8; win++) {
+ pSpecScale[win] += max_exponent;
+ }
+ }
+ } else {
+ HANDLE_SBRDECODER hSbrDecoder = (HANDLE_SBRDECODER)pSbrDec;
+ numBands = pDrcChData->numBands;
+
+ /* feed factors into SBR decoder for application in QMF domain. */
+ sbrDecoder_drcFeedChannel(hSbrDecoder, ch, numBands, fact_mantissa,
+ max_exponent, pDrcChData->drcInterpolationScheme,
+ winSeq, pDrcChData->bandTop);
+ }
+
+ return;
+}
+
+/*
+ * DRC parameter and presentation mode handling
+ */
+static void aacDecoder_drcParameterHandling(HANDLE_AAC_DRC self,
+ INT aacNumChannels,
+ SCHAR prevDrcProgRefLevel,
+ SCHAR prevDrcPresMode) {
+ int isDownmix, isMonoDownmix, isStereoDownmix;
+ int dDmx, dHr;
+ AACDEC_DRC_PARAMETER_HANDLING drcParameterHandling;
+ CDrcParams *p;
+
+ FDK_ASSERT(self != NULL);
+
+ p = &self->params;
+
+ if (self->progRefLevel != prevDrcProgRefLevel) self->update = 1;
+
+ if (self->presMode != prevDrcPresMode) self->update = 1;
+
+ if (self->prevAacNumChannels != aacNumChannels) self->update = 1;
+
+ /* return if no relevant parameter has changed */
+ if (!self->update) {
+ return;
+ }
+
+ /* derive downmix property. aacNumChannels: number of channels in aac stream,
+ * numOutChannels: number of output channels */
+ isDownmix = (aacNumChannels > self->numOutChannels);
+ isDownmix = (isDownmix && (self->numOutChannels > 0));
+ isMonoDownmix = (isDownmix && (self->numOutChannels == 1));
+ isStereoDownmix = (isDownmix && (self->numOutChannels == 2));
+
+ if ((self->presMode == 1) || (self->presMode == 2)) {
+ drcParameterHandling = (AACDEC_DRC_PARAMETER_HANDLING)self->presMode;
+ } else { /* no presentation mode -> use parameter handling specified by
+ AAC_DRC_DEFAULT_PRESENTATION_MODE */
+ drcParameterHandling = p->defaultPresentationMode;
+ }
+
+ /* by default, do as desired */
+ p->cut = p->usrCut;
+ p->boost = p->usrBoost;
+ p->applyHeavyCompression = p->usrApplyHeavyCompression;
+
+ switch (drcParameterHandling) {
+ case DISABLED_PARAMETER_HANDLING:
+ default:
+ /* use drc parameters as requested */
+ break;
+
+ case ENABLED_PARAMETER_HANDLING:
+ /* dDmx: estimated headroom reduction due to downmix, format: -1/4*dB
+ dDmx = floor(-4*20*log10(aacNumChannels/numOutChannels)) */
+ if (isDownmix) {
+ FIXP_DBL dmxTmp;
+ int e_log, e_mult;
+ dmxTmp = fDivNorm(self->numOutChannels,
+ aacNumChannels); /* inverse division ->
+ negative sign after
+ logarithm */
+ dmxTmp = fLog2(dmxTmp, 0, &e_log);
+ dmxTmp = fMultNorm(
+ dmxTmp, FL2FXCONST_DBL(4.0f * 20.0f * 0.30103f / (float)(1 << 5)),
+ &e_mult); /* e = e_log + e_mult + 5 */
+ dDmx = (int)scaleValue(dmxTmp, e_log + e_mult + 5 - (DFRACT_BITS - 1));
+ } else {
+ dDmx = 0;
+ }
+
+ /* dHr: Full estimated (decoder) headroom reduction due to loudness
+ * normalisation (DTL - PRL) and downmix. Format: -1/4*dB */
+ if (p->targetRefLevel >= 0) { /* if target level is provided */
+ dHr = p->targetRefLevel + dDmx - self->progRefLevel;
+ } else {
+ dHr = dDmx;
+ }
+
+ if (dHr < 0) { /* if headroom is reduced */
+ /* Use compression, but as little as possible. */
+ /* eHr: Headroom provided by encoder, format: -1/4 dB */
+ int eHr = fixMin(p->encoderTargetLevel - self->progRefLevel, 0);
+ if (eHr <
+ dHr) { /* if encoder provides more headroom than decoder needs */
+ /* derive scaling of light DRC */
+ FIXP_DBL calcFactor_norm;
+ INT calcFactor; /* fraction of DRC gains that is minimally needed for
+ clipping prevention */
+ calcFactor_norm =
+ fDivNorm(-dHr, -eHr); /* 0.0 < calcFactor_norm < 1.0 */
+ calcFactor_norm = calcFactor_norm >> DRC_PARAM_SCALE;
+ /* quantize to 128 steps */
+ calcFactor = convert_drcParam(
+ calcFactor_norm); /* convert to integer value between 0 and 127 */
+ calcFactor_norm = (FIXP_DBL)(
+ (INT)(DRC_PARAM_QUANT_STEP >> DRC_PARAM_SCALE) * calcFactor);
+ p->cut = (calcFactor_norm > p->cut)
+ ? calcFactor_norm
+ : p->cut; /* use calcFactor_norm as lower limit */
+ } else {
+ /* encoder provides equal or less headroom than decoder needs */
+ /* the time domain limiter must always be active in this case. It is
+ * assumed that the framework activates it by default */
+ p->cut = DRC_SCALING_MAX;
+ if ((dHr - eHr) <=
+ -4 * DRC_HEAVY_THRESHOLD_DB) { /* use heavy compression if
+ headroom deficit is equal or
+ higher than
+ DRC_HEAVY_THRESHOLD_DB */
+ p->applyHeavyCompression = ON;
+ }
+ }
+ } else { /* dHr >= 0 */
+ /* no restrictions required, as headroom is not reduced. */
+ /* p->cut = p->usrCut; */
+ }
+ break;
+
+ /* presentation mode 1 and 2 according to ETSI TS 101 154:
+ Digital Video Broadcasting (DVB); Specification for the use of Video
+ and Audio Coding in Broadcasting Applications based on the MPEG-2
+ Transport Stream, section C.5.4., "Decoding", and Table C.33. Also
+ according to amendment 4 to ISO/IEC 14496-3, section 4.5.2.14.2.4, and
+ Table AMD4.11. ISO DRC -> applyHeavyCompression = OFF (Use
+ light compression, MPEG-style) Compression_value ->
+ applyHeavyCompression = ON (Use heavy compression, DVB-style) scaling
+ restricted -> p->cut = DRC_SCALING_MAX */
+
+ case DRC_PRESENTATION_MODE_1: /* presentation mode 1, Light:-31/Heavy:-23 */
+ if ((p->targetRefLevel >= 0) &&
+ (p->targetRefLevel <
+ 124)) { /* if target level is provided and > -31 dB */
+ /* playback up to -23 dB */
+ p->applyHeavyCompression = ON;
+ } else { /* target level <= -31 dB or not provided */
+ /* playback -31 dB */
+ if (isMonoDownmix || isStereoDownmix) { /* stereo or mono downmixing */
+ p->cut = DRC_SCALING_MAX;
+ }
+ }
+ break;
+
+ case DRC_PRESENTATION_MODE_2: /* presentation mode 2, Light:-23/Heavy:-23 */
+ if ((p->targetRefLevel >= 0) &&
+ (p->targetRefLevel <
+ 124)) { /* if target level is provided and > -31 dB */
+ /* playback up to -23 dB */
+ if (isMonoDownmix) { /* if mono downmix */
+ p->applyHeavyCompression = ON;
+ } else {
+ p->applyHeavyCompression = OFF;
+ p->cut = DRC_SCALING_MAX;
+ }
+ } else { /* target level <= -31 dB or not provided */
+ /* playback -31 dB */
+ p->applyHeavyCompression = OFF;
+ if (isMonoDownmix || isStereoDownmix) { /* stereo or mono downmixing */
+ p->cut = DRC_SCALING_MAX;
+ }
+ }
+ break;
+ } /* switch (drcParameterHandling) */
+
+ /* With heavy compression, there is no scaling.
+ Scaling factors are set for notification only. */
+ if (p->applyHeavyCompression == ON) {
+ p->boost = DRC_SCALING_MAX;
+ p->cut = DRC_SCALING_MAX;
+ }
+
+ /* switch on/off processing */
+ self->enable = ((p->boost > (FIXP_DBL)0) || (p->cut > (FIXP_DBL)0) ||
+ (p->applyHeavyCompression == ON) || (p->targetRefLevel >= 0));
+ self->enable = (self->enable && !self->uniDrcPrecedence);
+
+ self->prevAacNumChannels = aacNumChannels;
+ self->update = 0;
+}
+
+/*
+ * Prepare DRC processing
+ * Valid return values are:
+ * -1 : An unexpected error occured.
+ * 0 : No error and no valid DRC data available.
+ * 1 : No error and valid DRC data has been mapped.
+ */
+int aacDecoder_drcProlog(
+ HANDLE_AAC_DRC self, HANDLE_FDK_BITSTREAM hBs,
+ CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[],
+ UCHAR pceInstanceTag,
+ UCHAR channelMapping[], /* Channel mapping translating drcChannel index to
+ canonical channel index */
+ int validChannels) {
+ int result = 0;
+
+ if (self == NULL) {
+ return -1;
+ }
+
+ if (!self->params.bsDelayEnable) {
+ /* keep previous progRefLevel and presMode for update flag in
+ * drcParameterHandling */
+ INT prevPRL, prevPM = 0;
+ prevPRL = self->progRefLevel;
+ prevPM = self->presMode;
+
+ result = aacDecoder_drcExtractAndMap(
+ self, hBs, pAacDecoderStaticChannelInfo, pceInstanceTag, channelMapping,
+ validChannels);
+
+ if (result < 0) {
+ return result;
+ }
+
+ /* Drc parameter handling */
+ aacDecoder_drcParameterHandling(self, validChannels, prevPRL, prevPM);
+ }
+
+ return result;
+}
+
+/*
+ * Finalize DRC processing
+ * Valid return values are:
+ * -1 : An unexpected error occured.
+ * 0 : No error and no valid DRC data available.
+ * 1 : No error and valid DRC data has been mapped.
+ */
+int aacDecoder_drcEpilog(
+ HANDLE_AAC_DRC self, HANDLE_FDK_BITSTREAM hBs,
+ CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[],
+ UCHAR pceInstanceTag,
+ UCHAR channelMapping[], /* Channel mapping translating drcChannel index to
+ canonical channel index */
+ int validChannels) {
+ int result = 0;
+
+ if (self == NULL) {
+ return -1;
+ }
+
+ if (self->params.bsDelayEnable) {
+ /* keep previous progRefLevel and presMode for update flag in
+ * drcParameterHandling */
+ INT prevPRL, prevPM = 0;
+ prevPRL = self->progRefLevel;
+ prevPM = self->presMode;
+
+ result = aacDecoder_drcExtractAndMap(
+ self, hBs, pAacDecoderStaticChannelInfo, pceInstanceTag, channelMapping,
+ validChannels);
+
+ if (result < 0) {
+ return result;
+ }
+
+ /* Drc parameter handling */
+ aacDecoder_drcParameterHandling(self, validChannels, prevPRL, prevPM);
+ }
+
+ return result;
+}
+
+/*
+ * Export relevant metadata info from bitstream payload.
+ */
+void aacDecoder_drcGetInfo(HANDLE_AAC_DRC self, SCHAR *pPresMode,
+ SCHAR *pProgRefLevel) {
+ if (self != NULL) {
+ if (pPresMode != NULL) {
+ *pPresMode = self->presMode;
+ }
+ if (pProgRefLevel != NULL) {
+ if (self->progRefLevelPresent) {
+ *pProgRefLevel = self->progRefLevel;
+ } else {
+ *pProgRefLevel = -1;
+ }
+ }
+ }
+}