| /* ----------------------------------------------------------------------------- |
| 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; |
| } |
| } |
| } |
| } |