diff options
Diffstat (limited to 'fdk-aac/libAACdec/src/aacdecoder_lib.cpp')
-rw-r--r-- | fdk-aac/libAACdec/src/aacdecoder_lib.cpp | 2035 |
1 files changed, 2035 insertions, 0 deletions
diff --git a/fdk-aac/libAACdec/src/aacdecoder_lib.cpp b/fdk-aac/libAACdec/src/aacdecoder_lib.cpp new file mode 100644 index 0000000..7df17b9 --- /dev/null +++ b/fdk-aac/libAACdec/src/aacdecoder_lib.cpp @@ -0,0 +1,2035 @@ +/* ----------------------------------------------------------------------------- +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): Manuel Jander + + Description: + +*******************************************************************************/ + +#include "aacdecoder_lib.h" + +#include "aac_ram.h" +#include "aacdecoder.h" +#include "tpdec_lib.h" +#include "FDK_core.h" /* FDK_tools version info */ + +#include "sbrdecoder.h" + +#include "conceal.h" + +#include "aacdec_drc.h" + +#include "sac_dec_lib.h" + +#include "pcm_utils.h" + +/* Decoder library info */ +#define AACDECODER_LIB_VL0 3 +#define AACDECODER_LIB_VL1 0 +#define AACDECODER_LIB_VL2 0 +#define AACDECODER_LIB_TITLE "AAC Decoder Lib" +#ifdef __ANDROID__ +#define AACDECODER_LIB_BUILD_DATE "" +#define AACDECODER_LIB_BUILD_TIME "" +#else +#define AACDECODER_LIB_BUILD_DATE __DATE__ +#define AACDECODER_LIB_BUILD_TIME __TIME__ +#endif + +static AAC_DECODER_ERROR setConcealMethod(const HANDLE_AACDECODER self, + const INT method); + +static void aacDecoder_setMetadataExpiry(const HANDLE_AACDECODER self, + const INT value) { + /* check decoder handle */ + if (self != NULL) { + INT mdExpFrame = 0; /* default: disable */ + + if ((value > 0) && + (self->streamInfo.aacSamplesPerFrame > + 0)) { /* Determine the corresponding number of frames: */ + FIXP_DBL frameTime = fDivNorm(self->streamInfo.aacSampleRate, + self->streamInfo.aacSamplesPerFrame * 1000); + mdExpFrame = fMultIceil(frameTime, value); + } + + /* Configure DRC module */ + aacDecoder_drcSetParam(self->hDrcInfo, DRC_DATA_EXPIRY_FRAME, mdExpFrame); + + /* Configure PCM downmix module */ + pcmDmx_SetParam(self->hPcmUtils, DMX_BS_DATA_EXPIRY_FRAME, mdExpFrame); + } +} + +LINKSPEC_CPP AAC_DECODER_ERROR +aacDecoder_GetFreeBytes(const HANDLE_AACDECODER self, UINT *pFreeBytes) { + /* reset free bytes */ + *pFreeBytes = 0; + + /* check handle */ + if (!self) return AAC_DEC_INVALID_HANDLE; + + /* return nr of free bytes */ + HANDLE_FDK_BITSTREAM hBs = transportDec_GetBitstream(self->hInput, 0); + *pFreeBytes = FDKgetFreeBits(hBs) >> 3; + + /* success */ + return AAC_DEC_OK; +} + +/** + * Config Decoder using a CSAudioSpecificConfig struct. + */ +static LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_Config( + HANDLE_AACDECODER self, const CSAudioSpecificConfig *pAscStruct, + UCHAR configMode, UCHAR *configChanged) { + AAC_DECODER_ERROR err; + + /* Initialize AAC core decoder, and update self->streaminfo */ + err = CAacDecoder_Init(self, pAscStruct, configMode, configChanged); + + if (!FDK_chMapDescr_isValid(&self->mapDescr)) { + return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; + } + + return err; +} + +LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_ConfigRaw(HANDLE_AACDECODER self, + UCHAR *conf[], + const UINT length[]) { + AAC_DECODER_ERROR err = AAC_DEC_OK; + TRANSPORTDEC_ERROR errTp; + UINT layer, nrOfLayers = self->nrOfLayers; + + for (layer = 0; layer < nrOfLayers; layer++) { + if (length[layer] > 0) { + errTp = transportDec_OutOfBandConfig(self->hInput, conf[layer], + length[layer], layer); + if (errTp != TRANSPORTDEC_OK) { + switch (errTp) { + case TRANSPORTDEC_NEED_TO_RESTART: + err = AAC_DEC_NEED_TO_RESTART; + break; + case TRANSPORTDEC_UNSUPPORTED_FORMAT: + err = AAC_DEC_UNSUPPORTED_FORMAT; + break; + default: + err = AAC_DEC_UNKNOWN; + break; + } + /* if baselayer is OK we continue decoding */ + if (layer >= 1) { + self->nrOfLayers = layer; + err = AAC_DEC_OK; + } + break; + } + } + } + + return err; +} + +LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_RawISOBMFFData(HANDLE_AACDECODER self, + UCHAR *buffer, + UINT length) { + FDK_BITSTREAM bs; + HANDLE_FDK_BITSTREAM hBs = &bs; + AAC_DECODER_ERROR err = AAC_DEC_OK; + + if (length < 8) return AAC_DEC_UNKNOWN; + + while (length >= 8) { + UINT size = + (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; + DRC_DEC_ERROR uniDrcErr = DRC_DEC_OK; + + if (length < size) return AAC_DEC_UNKNOWN; + if (size <= 8) return AAC_DEC_UNKNOWN; + + FDKinitBitStream(hBs, buffer + 8, 0x10000000, (size - 8) * 8); + + if ((buffer[4] == 'l') && (buffer[5] == 'u') && (buffer[6] == 'd') && + (buffer[7] == 't')) { + uniDrcErr = FDK_drcDec_ReadLoudnessBox(self->hUniDrcDecoder, hBs); + } else if ((buffer[4] == 'd') && (buffer[5] == 'm') && (buffer[6] == 'i') && + (buffer[7] == 'x')) { + uniDrcErr = + FDK_drcDec_ReadDownmixInstructions_Box(self->hUniDrcDecoder, hBs); + } else if ((buffer[4] == 'u') && (buffer[5] == 'd') && (buffer[6] == 'i') && + (buffer[7] == '2')) { + uniDrcErr = + FDK_drcDec_ReadUniDrcInstructions_Box(self->hUniDrcDecoder, hBs); + } else if ((buffer[4] == 'u') && (buffer[5] == 'd') && (buffer[6] == 'c') && + (buffer[7] == '2')) { + uniDrcErr = + FDK_drcDec_ReadUniDrcCoefficients_Box(self->hUniDrcDecoder, hBs); + } + + if (uniDrcErr != DRC_DEC_OK) err = AAC_DEC_UNKNOWN; + + buffer += size; + length -= size; + } + + return err; +} + +static INT aacDecoder_ConfigCallback(void *handle, + const CSAudioSpecificConfig *pAscStruct, + UCHAR configMode, UCHAR *configChanged) { + HANDLE_AACDECODER self = (HANDLE_AACDECODER)handle; + AAC_DECODER_ERROR err = AAC_DEC_OK; + TRANSPORTDEC_ERROR errTp; + + FDK_ASSERT(self != NULL); + { + { err = aacDecoder_Config(self, pAscStruct, configMode, configChanged); } + } + if (err == AAC_DEC_OK) { + /* + revert concealment method if either + - Interpolation concealment might not be meaningful + - Interpolation concealment is not implemented + */ + if ((self->flags[0] & (AC_LD | AC_ELD) && + (self->concealMethodUser == ConcealMethodNone) && + CConcealment_GetDelay(&self->concealCommonData) > + 0) /* might not be meaningful but allow if user has set it + expicitly */ + || (self->flags[0] & (AC_USAC | AC_RSVD50 | AC_RSV603DA) && + CConcealment_GetDelay(&self->concealCommonData) > + 0) /* not implemented */ + ) { + /* Revert to error concealment method Noise Substitution. + Because interpolation is not implemented for USAC or + the additional delay is unwanted for low delay codecs. */ + setConcealMethod(self, 1); + } + aacDecoder_setMetadataExpiry(self, self->metadataExpiry); + errTp = TRANSPORTDEC_OK; + } else { + if (err == AAC_DEC_NEED_TO_RESTART) { + errTp = TRANSPORTDEC_NEED_TO_RESTART; + } else if (IS_INIT_ERROR(err)) { + errTp = TRANSPORTDEC_UNSUPPORTED_FORMAT; + } /* Fatal errors */ + else { + errTp = TRANSPORTDEC_UNKOWN_ERROR; + } + } + + return errTp; +} + +static INT aacDecoder_FreeMemCallback(void *handle, + const CSAudioSpecificConfig *pAscStruct) { + TRANSPORTDEC_ERROR errTp = TRANSPORTDEC_OK; + HANDLE_AACDECODER self = (HANDLE_AACDECODER)handle; + + const int subStreamIndex = 0; + + FDK_ASSERT(self != NULL); + + if (CAacDecoder_FreeMem(self, subStreamIndex) != AAC_DEC_OK) { + errTp = TRANSPORTDEC_UNKOWN_ERROR; + } + + /* free Ram_SbrDecoder and Ram_SbrDecChannel */ + if (self->hSbrDecoder != NULL) { + if (sbrDecoder_FreeMem(&self->hSbrDecoder) != SBRDEC_OK) { + errTp = TRANSPORTDEC_UNKOWN_ERROR; + } + } + + /* free pSpatialDec and mpsData */ + if (self->pMpegSurroundDecoder != NULL) { + if (mpegSurroundDecoder_FreeMem( + (CMpegSurroundDecoder *)self->pMpegSurroundDecoder) != MPS_OK) { + errTp = TRANSPORTDEC_UNKOWN_ERROR; + } + } + + /* free persistent qmf domain buffer, QmfWorkBufferCore3, QmfWorkBufferCore4, + * QmfWorkBufferCore5 and configuration variables */ + FDK_QmfDomain_FreeMem(&self->qmfDomain); + + return errTp; +} + +static INT aacDecoder_CtrlCFGChangeCallback( + void *handle, const CCtrlCFGChange *pCtrlCFGChangeStruct) { + TRANSPORTDEC_ERROR errTp = TRANSPORTDEC_OK; + HANDLE_AACDECODER self = (HANDLE_AACDECODER)handle; + + if (self != NULL) { + CAacDecoder_CtrlCFGChange( + self, pCtrlCFGChangeStruct->flushStatus, pCtrlCFGChangeStruct->flushCnt, + pCtrlCFGChangeStruct->buildUpStatus, pCtrlCFGChangeStruct->buildUpCnt); + } else { + errTp = TRANSPORTDEC_UNKOWN_ERROR; + } + + return errTp; +} + +static INT aacDecoder_SbrCallback( + void *handle, HANDLE_FDK_BITSTREAM hBs, const INT sampleRateIn, + const INT sampleRateOut, const INT samplesPerFrame, + const AUDIO_OBJECT_TYPE coreCodec, const MP4_ELEMENT_ID elementID, + const INT elementIndex, const UCHAR harmonicSBR, + const UCHAR stereoConfigIndex, const UCHAR configMode, UCHAR *configChanged, + const INT downscaleFactor) { + HANDLE_SBRDECODER self = (HANDLE_SBRDECODER)handle; + + INT errTp = sbrDecoder_Header(self, hBs, sampleRateIn, sampleRateOut, + samplesPerFrame, coreCodec, elementID, + elementIndex, harmonicSBR, stereoConfigIndex, + configMode, configChanged, downscaleFactor); + + return errTp; +} + +static INT aacDecoder_SscCallback(void *handle, HANDLE_FDK_BITSTREAM hBs, + const AUDIO_OBJECT_TYPE coreCodec, + const INT samplingRate, const INT frameSize, + const INT stereoConfigIndex, + const INT coreSbrFrameLengthIndex, + const INT configBytes, const UCHAR configMode, + UCHAR *configChanged) { + SACDEC_ERROR err; + TRANSPORTDEC_ERROR errTp; + HANDLE_AACDECODER hAacDecoder = (HANDLE_AACDECODER)handle; + + err = mpegSurroundDecoder_Config( + (CMpegSurroundDecoder *)hAacDecoder->pMpegSurroundDecoder, hBs, coreCodec, + samplingRate, frameSize, stereoConfigIndex, coreSbrFrameLengthIndex, + configBytes, configMode, configChanged); + + switch (err) { + case MPS_UNSUPPORTED_CONFIG: + /* MPS found but invalid or not decodable by this instance */ + /* We switch off MPS and keep going */ + hAacDecoder->mpsEnableCurr = 0; + hAacDecoder->mpsApplicable = 0; + errTp = TRANSPORTDEC_OK; + break; + case MPS_PARSE_ERROR: + /* MPS found but invalid or not decodable by this instance */ + hAacDecoder->mpsEnableCurr = 0; + hAacDecoder->mpsApplicable = 0; + if ((coreCodec == AOT_USAC) || (coreCodec == AOT_DRM_USAC) || + IS_LOWDELAY(coreCodec)) { + errTp = TRANSPORTDEC_PARSE_ERROR; + } else { + errTp = TRANSPORTDEC_OK; + } + break; + case MPS_OK: + hAacDecoder->mpsApplicable = 1; + errTp = TRANSPORTDEC_OK; + break; + default: + /* especially Parsing error is critical for transport layer */ + hAacDecoder->mpsApplicable = 0; + errTp = TRANSPORTDEC_UNKOWN_ERROR; + } + + return (INT)errTp; +} + +static INT aacDecoder_UniDrcCallback(void *handle, HANDLE_FDK_BITSTREAM hBs, + const INT fullPayloadLength, + const INT payloadType, + const INT subStreamIndex, + const INT payloadStart, + const AUDIO_OBJECT_TYPE aot) { + DRC_DEC_ERROR err = DRC_DEC_OK; + TRANSPORTDEC_ERROR errTp; + HANDLE_AACDECODER hAacDecoder = (HANDLE_AACDECODER)handle; + DRC_DEC_CODEC_MODE drcDecCodecMode = DRC_DEC_CODEC_MODE_UNDEFINED; + + if (subStreamIndex != 0) { + return TRANSPORTDEC_OK; + } + + else if (aot == AOT_USAC) { + drcDecCodecMode = DRC_DEC_MPEG_D_USAC; + } + + err = FDK_drcDec_SetCodecMode(hAacDecoder->hUniDrcDecoder, drcDecCodecMode); + if (err) return (INT)TRANSPORTDEC_UNKOWN_ERROR; + + if (payloadType == 0) /* uniDrcConfig */ + { + err = FDK_drcDec_ReadUniDrcConfig(hAacDecoder->hUniDrcDecoder, hBs); + } else /* loudnessInfoSet */ + { + err = FDK_drcDec_ReadLoudnessInfoSet(hAacDecoder->hUniDrcDecoder, hBs); + hAacDecoder->loudnessInfoSetPosition[1] = payloadStart; + hAacDecoder->loudnessInfoSetPosition[2] = fullPayloadLength; + } + + if (err == DRC_DEC_OK) + errTp = TRANSPORTDEC_OK; + else + errTp = TRANSPORTDEC_UNKOWN_ERROR; + + return (INT)errTp; +} + +LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_AncDataInit(HANDLE_AACDECODER self, + UCHAR *buffer, int size) { + CAncData *ancData = &self->ancData; + + return CAacDecoder_AncDataInit(ancData, buffer, size); +} + +LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_AncDataGet(HANDLE_AACDECODER self, + int index, UCHAR **ptr, + int *size) { + CAncData *ancData = &self->ancData; + + return CAacDecoder_AncDataGet(ancData, index, ptr, size); +} + +/* If MPS is present in stream, but not supported by this instance, we'll + have to switch off MPS and use QMF synthesis in the SBR module if required */ +static int isSupportedMpsConfig(AUDIO_OBJECT_TYPE aot, + unsigned int numInChannels, + unsigned int fMpsPresent) { + LIB_INFO libInfo[FDK_MODULE_LAST]; + UINT mpsCaps; + int isSupportedCfg = 1; + + FDKinitLibInfo(libInfo); + + mpegSurroundDecoder_GetLibInfo(libInfo); + + mpsCaps = FDKlibInfo_getCapabilities(libInfo, FDK_MPSDEC); + + if (!(mpsCaps & CAPF_MPS_LD) && IS_LOWDELAY(aot)) { + /* We got an LD AOT but MPS decoder does not support LD. */ + isSupportedCfg = 0; + } + if ((mpsCaps & CAPF_MPS_LD) && IS_LOWDELAY(aot) && !fMpsPresent) { + /* We got an LD AOT and the MPS decoder supports it. + * But LD-MPS is not explicitly signaled. */ + isSupportedCfg = 0; + } + if (!(mpsCaps & CAPF_MPS_USAC) && IS_USAC(aot)) { + /* We got an USAC AOT but MPS decoder does not support USAC. */ + isSupportedCfg = 0; + } + if (!(mpsCaps & CAPF_MPS_STD) && !IS_LOWDELAY(aot) && !IS_USAC(aot)) { + /* We got an GA AOT but MPS decoder does not support it. */ + isSupportedCfg = 0; + } + /* Check whether the MPS modul supports the given number of input channels: */ + switch (numInChannels) { + case 1: + if (!(mpsCaps & CAPF_MPS_1CH_IN)) { + /* We got a one channel input to MPS decoder but it does not support it. + */ + isSupportedCfg = 0; + } + break; + case 2: + if (!(mpsCaps & CAPF_MPS_2CH_IN)) { + /* We got a two channel input to MPS decoder but it does not support it. + */ + isSupportedCfg = 0; + } + break; + case 5: + case 6: + if (!(mpsCaps & CAPF_MPS_6CH_IN)) { + /* We got a six channel input to MPS decoder but it does not support it. + */ + isSupportedCfg = 0; + } + break; + default: + isSupportedCfg = 0; + } + + return (isSupportedCfg); +} + +static AAC_DECODER_ERROR setConcealMethod( + const HANDLE_AACDECODER self, /*!< Handle of the decoder instance */ + const INT method) { + AAC_DECODER_ERROR errorStatus = AAC_DEC_OK; + CConcealParams *pConcealData = NULL; + int method_revert = 0; + HANDLE_SBRDECODER hSbrDec = NULL; + HANDLE_AAC_DRC hDrcInfo = NULL; + HANDLE_PCM_DOWNMIX hPcmDmx = NULL; + CConcealmentMethod backupMethod = ConcealMethodNone; + int backupDelay = 0; + int bsDelay = 0; + + /* check decoder handle */ + if (self != NULL) { + pConcealData = &self->concealCommonData; + hSbrDec = self->hSbrDecoder; + hDrcInfo = self->hDrcInfo; + hPcmDmx = self->hPcmUtils; + if (self->flags[0] & (AC_USAC | AC_RSVD50 | AC_RSV603DA) && method >= 2) { + /* Interpolation concealment is not implemented for USAC/RSVD50 */ + /* errorStatus = AAC_DEC_SET_PARAM_FAIL; + goto bail; */ + method_revert = 1; + } + if (self->flags[0] & (AC_USAC | AC_RSVD50 | AC_RSV603DA) && method >= 2) { + /* Interpolation concealment is not implemented for USAC/RSVD50 */ + errorStatus = AAC_DEC_SET_PARAM_FAIL; + goto bail; + } + } + + /* Get current method/delay */ + backupMethod = CConcealment_GetMethod(pConcealData); + backupDelay = CConcealment_GetDelay(pConcealData); + + /* Be sure to set AAC and SBR concealment method simultaneously! */ + errorStatus = CConcealment_SetParams( + pConcealData, + (method_revert == 0) ? (int)method : (int)1, // concealMethod + AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, // concealFadeOutSlope + AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, // concealFadeInSlope + AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, // concealMuteRelease + AACDEC_CONCEAL_PARAM_NOT_SPECIFIED // concealComfNoiseLevel + ); + if ((errorStatus != AAC_DEC_OK) && (errorStatus != AAC_DEC_INVALID_HANDLE)) { + goto bail; + } + + /* Get new delay */ + bsDelay = CConcealment_GetDelay(pConcealData); + + { + SBR_ERROR sbrErr = SBRDEC_OK; + + /* set SBR bitstream delay */ + sbrErr = sbrDecoder_SetParam(hSbrDec, SBR_SYSTEM_BITSTREAM_DELAY, bsDelay); + + switch (sbrErr) { + case SBRDEC_OK: + case SBRDEC_NOT_INITIALIZED: + if (self != NULL) { + /* save the param value and set later + (when SBR has been initialized) */ + self->sbrParams.bsDelay = bsDelay; + } + break; + default: + errorStatus = AAC_DEC_SET_PARAM_FAIL; + goto bail; + } + } + + errorStatus = aacDecoder_drcSetParam(hDrcInfo, DRC_BS_DELAY, bsDelay); + if ((errorStatus != AAC_DEC_OK) && (errorStatus != AAC_DEC_INVALID_HANDLE)) { + goto bail; + } + + if (errorStatus == AAC_DEC_OK) { + PCMDMX_ERROR err = pcmDmx_SetParam(hPcmDmx, DMX_BS_DATA_DELAY, bsDelay); + switch (err) { + case PCMDMX_INVALID_HANDLE: + errorStatus = AAC_DEC_INVALID_HANDLE; + break; + case PCMDMX_OK: + break; + default: + errorStatus = AAC_DEC_SET_PARAM_FAIL; + goto bail; + } + } + +bail: + if ((errorStatus != AAC_DEC_OK) && (errorStatus != AAC_DEC_INVALID_HANDLE)) { + /* Revert to the initial state */ + CConcealment_SetParams( + pConcealData, (int)backupMethod, AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, + AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, + AACDEC_CONCEAL_PARAM_NOT_SPECIFIED); + /* Revert SBR bitstream delay */ + sbrDecoder_SetParam(hSbrDec, SBR_SYSTEM_BITSTREAM_DELAY, backupDelay); + /* Revert DRC bitstream delay */ + aacDecoder_drcSetParam(hDrcInfo, DRC_BS_DELAY, backupDelay); + /* Revert PCM mixdown bitstream delay */ + pcmDmx_SetParam(hPcmDmx, DMX_BS_DATA_DELAY, backupDelay); + } + + return errorStatus; +} + +LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_SetParam( + const HANDLE_AACDECODER self, /*!< Handle of the decoder instance */ + const AACDEC_PARAM param, /*!< Parameter to set */ + const INT value) /*!< Parameter valued */ +{ + AAC_DECODER_ERROR errorStatus = AAC_DEC_OK; + HANDLE_TRANSPORTDEC hTpDec = NULL; + TRANSPORTDEC_ERROR errTp = TRANSPORTDEC_OK; + HANDLE_AAC_DRC hDrcInfo = NULL; + HANDLE_PCM_DOWNMIX hPcmDmx = NULL; + PCMDMX_ERROR dmxErr = PCMDMX_OK; + TDLimiterPtr hPcmTdl = NULL; + DRC_DEC_ERROR uniDrcErr = DRC_DEC_OK; + + /* check decoder handle */ + if (self != NULL) { + hTpDec = self->hInput; + hDrcInfo = self->hDrcInfo; + hPcmDmx = self->hPcmUtils; + hPcmTdl = self->hLimiter; + } else { + errorStatus = AAC_DEC_INVALID_HANDLE; + goto bail; + } + + /* configure the subsystems */ + switch (param) { + case AAC_PCM_MIN_OUTPUT_CHANNELS: + if (value < -1 || value > (8)) { + return AAC_DEC_SET_PARAM_FAIL; + } + dmxErr = pcmDmx_SetParam(hPcmDmx, MIN_NUMBER_OF_OUTPUT_CHANNELS, value); + break; + + case AAC_PCM_MAX_OUTPUT_CHANNELS: + if (value < -1 || value > (8)) { + return AAC_DEC_SET_PARAM_FAIL; + } + dmxErr = pcmDmx_SetParam(hPcmDmx, MAX_NUMBER_OF_OUTPUT_CHANNELS, value); + + if (dmxErr != PCMDMX_OK) { + goto bail; + } + errorStatus = + aacDecoder_drcSetParam(hDrcInfo, MAX_OUTPUT_CHANNELS, value); + if (value > 0) { + uniDrcErr = FDK_drcDec_SetParam(self->hUniDrcDecoder, + DRC_DEC_TARGET_CHANNEL_COUNT_REQUESTED, + (FIXP_DBL)value); + } + break; + + case AAC_PCM_DUAL_CHANNEL_OUTPUT_MODE: + dmxErr = pcmDmx_SetParam(hPcmDmx, DMX_DUAL_CHANNEL_MODE, value); + break; + + case AAC_PCM_LIMITER_ENABLE: + if (value < -2 || value > 1) { + return AAC_DEC_SET_PARAM_FAIL; + } + 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 (pcmLimiter_SetAttack(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 (pcmLimiter_SetRelease(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_METADATA_PROFILE: { + DMX_PROFILE_TYPE dmxProfile; + INT mdExpiry = -1; /* in ms (-1: don't change) */ + + switch ((AAC_MD_PROFILE)value) { + case AAC_MD_PROFILE_MPEG_STANDARD: + dmxProfile = DMX_PRFL_STANDARD; + break; + case AAC_MD_PROFILE_MPEG_LEGACY: + dmxProfile = DMX_PRFL_MATRIX_MIX; + break; + case AAC_MD_PROFILE_MPEG_LEGACY_PRIO: + dmxProfile = DMX_PRFL_FORCE_MATRIX_MIX; + break; + case AAC_MD_PROFILE_ARIB_JAPAN: + dmxProfile = DMX_PRFL_ARIB_JAPAN; + mdExpiry = 550; /* ms */ + break; + default: + return AAC_DEC_SET_PARAM_FAIL; + } + dmxErr = pcmDmx_SetParam(hPcmDmx, DMX_PROFILE_SETTING, (INT)dmxProfile); + if (dmxErr != PCMDMX_OK) { + goto bail; + } + if ((self != NULL) && (mdExpiry >= 0)) { + self->metadataExpiry = mdExpiry; + /* Determine the corresponding number of frames and configure all + * related modules. */ + aacDecoder_setMetadataExpiry(self, mdExpiry); + } + } break; + + case AAC_METADATA_EXPIRY_TIME: + if (value < 0) { + return AAC_DEC_SET_PARAM_FAIL; + } + if (self != NULL) { + self->metadataExpiry = value; + /* Determine the corresponding number of frames and configure all + * related modules. */ + aacDecoder_setMetadataExpiry(self, value); + } + break; + + case AAC_PCM_OUTPUT_CHANNEL_MAPPING: + if (value < 0 || value > 1) { + return AAC_DEC_SET_PARAM_FAIL; + } + /* CAUTION: The given value must be inverted to match the logic! */ + FDK_chMapDescr_setPassThrough(&self->mapDescr, !value); + break; + + case AAC_QMF_LOWPOWER: + if (value < -1 || value > 1) { + return AAC_DEC_SET_PARAM_FAIL; + } + + /** + * Set QMF mode (might be overriden) + * 0:HQ (complex) + * 1:LP (partially complex) + */ + self->qmfModeUser = (QMF_MODE)value; + break; + + case AAC_DRC_ATTENUATION_FACTOR: + /* DRC compression factor (where 0 is no and 127 is max compression) */ + errorStatus = aacDecoder_drcSetParam(hDrcInfo, DRC_CUT_SCALE, value); + break; + + case AAC_DRC_BOOST_FACTOR: + /* DRC boost factor (where 0 is no and 127 is max boost) */ + errorStatus = aacDecoder_drcSetParam(hDrcInfo, DRC_BOOST_SCALE, value); + break; + + case AAC_DRC_REFERENCE_LEVEL: + if ((value >= 0) && + ((value < 40) || (value > 127))) /* allowed range: -10 to -31.75 dB */ + return AAC_DEC_SET_PARAM_FAIL; + /* DRC target reference level quantized in 0.25dB steps using values + [40..127]. Negative values switch off loudness normalisation. Negative + values also switch off MPEG-4 DRC, while MPEG-D DRC can be separately + switched on/off with AAC_UNIDRC_SET_EFFECT */ + errorStatus = aacDecoder_drcSetParam(hDrcInfo, TARGET_REF_LEVEL, value); + uniDrcErr = FDK_drcDec_SetParam(self->hUniDrcDecoder, + DRC_DEC_LOUDNESS_NORMALIZATION_ON, + (FIXP_DBL)(value >= 0)); + /* set target loudness also for MPEG-D DRC */ + self->defaultTargetLoudness = (SCHAR)value; + break; + + case AAC_DRC_HEAVY_COMPRESSION: + /* Don't need to overwrite cut/boost values */ + errorStatus = + aacDecoder_drcSetParam(hDrcInfo, APPLY_HEAVY_COMPRESSION, value); + break; + + case AAC_DRC_DEFAULT_PRESENTATION_MODE: + /* DRC default presentation mode */ + errorStatus = + aacDecoder_drcSetParam(hDrcInfo, DEFAULT_PRESENTATION_MODE, value); + break; + + case AAC_DRC_ENC_TARGET_LEVEL: + /* Encoder target level for light (i.e. not heavy) compression: + Target reference level assumed at encoder for deriving limiting gains + */ + errorStatus = + aacDecoder_drcSetParam(hDrcInfo, ENCODER_TARGET_LEVEL, value); + break; + + case AAC_UNIDRC_SET_EFFECT: + if ((value < -1) || (value > 6)) return AAC_DEC_SET_PARAM_FAIL; + uniDrcErr = FDK_drcDec_SetParam(self->hUniDrcDecoder, DRC_DEC_EFFECT_TYPE, + (FIXP_DBL)value); + break; + case AAC_TPDEC_CLEAR_BUFFER: + errTp = transportDec_SetParam(hTpDec, TPDEC_PARAM_RESET, 1); + self->streamInfo.numLostAccessUnits = 0; + self->streamInfo.numBadBytes = 0; + self->streamInfo.numTotalBytes = 0; + /* aacDecoder_SignalInterruption(self); */ + break; + case AAC_CONCEAL_METHOD: + /* Changing the concealment method can introduce additional bitstream + delay. And that in turn affects sub libraries and modules which makes + the whole thing quite complex. So the complete changing routine is + packed into a helper function which keeps all modules and libs in a + consistent state even in the case an error occures. */ + errorStatus = setConcealMethod(self, value); + if (errorStatus == AAC_DEC_OK) { + self->concealMethodUser = (CConcealmentMethod)value; + } + break; + + default: + return AAC_DEC_SET_PARAM_FAIL; + } /* switch(param) */ + +bail: + + if (errorStatus == AAC_DEC_OK) { + /* Check error code returned by DMX module library: */ + switch (dmxErr) { + case PCMDMX_OK: + break; + case PCMDMX_INVALID_HANDLE: + errorStatus = AAC_DEC_INVALID_HANDLE; + break; + default: + errorStatus = AAC_DEC_SET_PARAM_FAIL; + } + } + + if (errTp != TRANSPORTDEC_OK && errorStatus == AAC_DEC_OK) { + errorStatus = AAC_DEC_SET_PARAM_FAIL; + } + + if (errorStatus == AAC_DEC_OK) { + /* Check error code returned by MPEG-D DRC decoder library: */ + switch (uniDrcErr) { + case 0: + break; + case -9998: + errorStatus = AAC_DEC_INVALID_HANDLE; + break; + default: + errorStatus = AAC_DEC_SET_PARAM_FAIL; + break; + } + } + + return (errorStatus); +} +LINKSPEC_CPP HANDLE_AACDECODER aacDecoder_Open(TRANSPORT_TYPE transportFmt, + UINT nrOfLayers) { + AAC_DECODER_INSTANCE *aacDec = NULL; + HANDLE_TRANSPORTDEC pIn; + int err = 0; + int stereoConfigIndex = -1; + + UINT nrOfLayers_min = fMin(nrOfLayers, (UINT)1); + + /* Allocate transport layer struct. */ + pIn = transportDec_Open(transportFmt, TP_FLAG_MPEG4, nrOfLayers_min); + if (pIn == NULL) { + return NULL; + } + + transportDec_SetParam(pIn, TPDEC_PARAM_IGNORE_BUFFERFULLNESS, 1); + + /* Allocate AAC decoder core struct. */ + aacDec = CAacDecoder_Open(transportFmt); + + if (aacDec == NULL) { + transportDec_Close(&pIn); + goto bail; + } + aacDec->hInput = pIn; + + aacDec->nrOfLayers = nrOfLayers_min; + + /* Setup channel mapping descriptor. */ + FDK_chMapDescr_init(&aacDec->mapDescr, NULL, 0, 0); + + /* Register Config Update callback. */ + transportDec_RegisterAscCallback(pIn, aacDecoder_ConfigCallback, + (void *)aacDec); + + /* Register Free Memory callback. */ + transportDec_RegisterFreeMemCallback(pIn, aacDecoder_FreeMemCallback, + (void *)aacDec); + + /* Register config switch control callback. */ + transportDec_RegisterCtrlCFGChangeCallback( + pIn, aacDecoder_CtrlCFGChangeCallback, (void *)aacDec); + + FDKmemclear(&aacDec->qmfDomain, sizeof(FDK_QMF_DOMAIN)); + /* open SBR decoder */ + if (SBRDEC_OK != sbrDecoder_Open(&aacDec->hSbrDecoder, &aacDec->qmfDomain)) { + err = -1; + goto bail; + } + aacDec->qmfModeUser = NOT_DEFINED; + transportDec_RegisterSbrCallback(aacDec->hInput, aacDecoder_SbrCallback, + (void *)aacDec->hSbrDecoder); + + if (mpegSurroundDecoder_Open( + (CMpegSurroundDecoder **)&aacDec->pMpegSurroundDecoder, + stereoConfigIndex, &aacDec->qmfDomain)) { + err = -1; + goto bail; + } + /* Set MPEG Surround defaults */ + aacDec->mpsEnableUser = 0; + aacDec->mpsEnableCurr = 0; + aacDec->mpsApplicable = 0; + aacDec->mpsOutputMode = (SCHAR)SACDEC_OUT_MODE_NORMAL; + transportDec_RegisterSscCallback(pIn, aacDecoder_SscCallback, (void *)aacDec); + + { + if (FDK_drcDec_Open(&(aacDec->hUniDrcDecoder), DRC_DEC_ALL) != 0) { + err = -1; + goto bail; + } + } + + transportDec_RegisterUniDrcConfigCallback(pIn, aacDecoder_UniDrcCallback, + (void *)aacDec, + aacDec->loudnessInfoSetPosition); + aacDec->defaultTargetLoudness = (SCHAR)96; + + pcmDmx_Open(&aacDec->hPcmUtils); + if (aacDec->hPcmUtils == NULL) { + err = -1; + goto bail; + } + + aacDec->hLimiter = + pcmLimiter_Create(TDL_ATTACK_DEFAULT_MS, TDL_RELEASE_DEFAULT_MS, + (FIXP_DBL)MAXVAL_DBL, (8), 96000); + if (NULL == aacDec->hLimiter) { + err = -1; + goto bail; + } + aacDec->limiterEnableUser = (UCHAR)-1; + aacDec->limiterEnableCurr = 0; + + /* Assure that all modules have same delay */ + if (setConcealMethod(aacDec, + CConcealment_GetMethod(&aacDec->concealCommonData))) { + err = -1; + goto bail; + } + +bail: + if (err == -1) { + aacDecoder_Close(aacDec); + aacDec = NULL; + } + return aacDec; +} + +LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_Fill(HANDLE_AACDECODER self, + UCHAR *pBuffer[], + const UINT bufferSize[], + UINT *pBytesValid) { + TRANSPORTDEC_ERROR tpErr; + /* loop counter for layers; if not TT_MP4_RAWPACKETS used as index for only + available layer */ + INT layer = 0; + INT nrOfLayers = self->nrOfLayers; + + { + for (layer = 0; layer < nrOfLayers; layer++) { + { + tpErr = transportDec_FillData(self->hInput, pBuffer[layer], + bufferSize[layer], &pBytesValid[layer], + layer); + if (tpErr != TRANSPORTDEC_OK) { + return AAC_DEC_UNKNOWN; /* Must be an internal error */ + } + } + } + } + + return AAC_DEC_OK; +} + +static void aacDecoder_SignalInterruption(HANDLE_AACDECODER self) { + CAacDecoder_SignalInterruption(self); + + if (self->hSbrDecoder != NULL) { + sbrDecoder_SetParam(self->hSbrDecoder, SBR_BS_INTERRUPTION, 1); + } + if (self->mpsEnableUser) { + mpegSurroundDecoder_SetParam( + (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, + SACDEC_BS_INTERRUPTION, 1); + } +} + +static void aacDecoder_UpdateBitStreamCounters(CStreamInfo *pSi, + HANDLE_FDK_BITSTREAM hBs, + INT nBits, + AAC_DECODER_ERROR ErrorStatus) { + /* calculate bit difference (amount of bits moved forward) */ + nBits = nBits - (INT)FDKgetValidBits(hBs); + + /* Note: The amount of bits consumed might become negative when parsing a + bit stream with several sub frames, and we find out at the last sub frame + that the total frame length does not match the sum of sub frame length. + If this happens, the transport decoder might want to rewind to the supposed + ending of the transport frame, and this position might be before the last + access unit beginning. */ + + /* Calc bitrate. */ + if (pSi->frameSize > 0) { + /* bitRate = nBits * sampleRate / frameSize */ + int ratio_e = 0; + FIXP_DBL ratio_m = fDivNorm(pSi->sampleRate, pSi->frameSize, &ratio_e); + pSi->bitRate = (INT)fMultNorm(nBits, DFRACT_BITS - 1, ratio_m, ratio_e, + DFRACT_BITS - 1); + } + + /* bit/byte counters */ + { + INT nBytes; + + nBytes = nBits >> 3; + pSi->numTotalBytes += nBytes; + if (IS_OUTPUT_VALID(ErrorStatus)) { + pSi->numTotalAccessUnits++; + } + if (IS_DECODE_ERROR(ErrorStatus)) { + pSi->numBadBytes += nBytes; + pSi->numBadAccessUnits++; + } + } +} + +static INT aacDecoder_EstimateNumberOfLostFrames(HANDLE_AACDECODER self) { + INT n; + + transportDec_GetMissingAccessUnitCount(&n, self->hInput); + + return n; +} + +LINKSPEC_CPP AAC_DECODER_ERROR +aacDecoder_DecodeFrame(HANDLE_AACDECODER self, INT_PCM *pTimeData_extern, + const INT timeDataSize_extern, const UINT flags) { + AAC_DECODER_ERROR ErrorStatus; + INT layer; + INT nBits; + HANDLE_FDK_BITSTREAM hBs; + int fTpInterruption = 0; /* Transport originated interruption detection. */ + int fTpConceal = 0; /* Transport originated concealment. */ + INT_PCM *pTimeData = NULL; + INT timeDataSize = 0; + UINT accessUnit = 0; + UINT numAccessUnits = 1; + UINT numPrerollAU = 0; + int fEndAuNotAdjusted = 0; /* The end of the access unit was not adjusted */ + int applyCrossfade = 1; /* flag indicates if flushing was possible */ + FIXP_PCM *pTimeDataFixpPcm; /* Signal buffer for decoding process before PCM + processing */ + INT timeDataFixpPcmSize; + PCM_DEC *pTimeDataPcmPost; /* Signal buffer for PCM post-processing */ + INT timeDataPcmPostSize; + + if (self == NULL) { + return AAC_DEC_INVALID_HANDLE; + } + + pTimeData = self->pcmOutputBuffer; + timeDataSize = sizeof(self->pcmOutputBuffer) / sizeof(*self->pcmOutputBuffer); + + if (flags & AACDEC_INTR) { + self->streamInfo.numLostAccessUnits = 0; + } + hBs = transportDec_GetBitstream(self->hInput, 0); + + /* Get current bits position for bitrate calculation. */ + nBits = FDKgetValidBits(hBs); + + if (flags & AACDEC_CLRHIST) { + if (self->flags[0] & AC_USAC) { + /* 1) store AudioSpecificConfig always in AudioSpecificConfig_Parse() */ + /* 2) free memory of dynamic allocated data */ + CSAudioSpecificConfig asc; + transportDec_GetAsc(self->hInput, 0, &asc); + aacDecoder_FreeMemCallback(self, &asc); + self->streamInfo.numChannels = 0; + /* 3) restore AudioSpecificConfig */ + transportDec_OutOfBandConfig(self->hInput, asc.config, + (asc.configBits + 7) >> 3, 0); + } + } + + if (!((flags & (AACDEC_CONCEAL | AACDEC_FLUSH)) || + (self->flushStatus == AACDEC_RSV60_DASH_IPF_ATSC_FLUSH_ON) || + (self->flushStatus == AACDEC_USAC_DASH_IPF_FLUSH_ON) || + (self->buildUpStatus == AACDEC_RSV60_BUILD_UP_IDLE_IN_BAND))) { + TRANSPORTDEC_ERROR err; + + for (layer = 0; layer < self->nrOfLayers; layer++) { + err = transportDec_ReadAccessUnit(self->hInput, layer); + if (err != TRANSPORTDEC_OK) { + switch (err) { + case TRANSPORTDEC_NOT_ENOUGH_BITS: + ErrorStatus = AAC_DEC_NOT_ENOUGH_BITS; + goto bail; + case TRANSPORTDEC_SYNC_ERROR: + self->streamInfo.numLostAccessUnits = + aacDecoder_EstimateNumberOfLostFrames(self); + fTpInterruption = 1; + break; + case TRANSPORTDEC_NEED_TO_RESTART: + ErrorStatus = AAC_DEC_NEED_TO_RESTART; + goto bail; + case TRANSPORTDEC_CRC_ERROR: + fTpConceal = 1; + break; + case TRANSPORTDEC_UNSUPPORTED_FORMAT: + ErrorStatus = AAC_DEC_UNSUPPORTED_FORMAT; + goto bail; + default: + ErrorStatus = AAC_DEC_UNKNOWN; + goto bail; + } + } + } + } else { + if (self->streamInfo.numLostAccessUnits > 0) { + self->streamInfo.numLostAccessUnits--; + } + } + + self->frameOK = 1; + + UINT prerollAUOffset[AACDEC_MAX_NUM_PREROLL_AU]; + UINT prerollAULength[AACDEC_MAX_NUM_PREROLL_AU]; + for (int i = 0; i < AACDEC_MAX_NUM_PREROLL_AU + 1; i++) + self->prerollAULength[i] = 0; + + INT auStartAnchor; + HANDLE_FDK_BITSTREAM hBsAu; + + /* Process preroll frames and current frame */ + do { + if (!(flags & (AACDEC_CONCEAL | AACDEC_FLUSH)) && + (self->flushStatus != AACDEC_RSV60_CFG_CHANGE_ATSC_FLUSH_ON) && + (accessUnit == 0) && + (self->hasAudioPreRoll || + (self->buildUpStatus == AACDEC_RSV60_BUILD_UP_IDLE_IN_BAND)) && + !fTpInterruption && + !fTpConceal /* Bit stream pointer needs to be at the beginning of a + (valid) AU. */ + ) { + ErrorStatus = CAacDecoder_PreRollExtensionPayloadParse( + self, &numPrerollAU, prerollAUOffset, prerollAULength); + + if (ErrorStatus != AAC_DEC_OK) { + switch (ErrorStatus) { + case AAC_DEC_NOT_ENOUGH_BITS: + goto bail; + case AAC_DEC_PARSE_ERROR: + self->frameOK = 0; + break; + default: + break; + } + } + + numAccessUnits += numPrerollAU; + } + + hBsAu = transportDec_GetBitstream(self->hInput, 0); + auStartAnchor = (INT)FDKgetValidBits(hBsAu); + + self->accessUnit = accessUnit; + if (accessUnit < numPrerollAU) { + FDKpushFor(hBsAu, prerollAUOffset[accessUnit]); + } + + /* Signal bit stream interruption to other modules if required. */ + if (fTpInterruption || (flags & AACDEC_INTR)) { + aacDecoder_SignalInterruption(self); + if (!(flags & AACDEC_INTR)) { + ErrorStatus = AAC_DEC_TRANSPORT_SYNC_ERROR; + goto bail; + } + } + + /* Clearing core data will be done in CAacDecoder_DecodeFrame() below. + Tell other modules to clear states if required. */ + if (flags & AACDEC_CLRHIST) { + if (!(self->flags[0] & AC_USAC)) { + sbrDecoder_SetParam(self->hSbrDecoder, SBR_CLEAR_HISTORY, 1); + mpegSurroundDecoder_SetParam( + (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, + SACDEC_CLEAR_HISTORY, 1); + if (FDK_QmfDomain_ClearPersistentMemory(&self->qmfDomain) != 0) { + ErrorStatus = AAC_DEC_UNKNOWN; + goto bail; + } + } + } + + /* Empty bit buffer in case of flush request. */ + if (flags & AACDEC_FLUSH && !(flags & AACDEC_CONCEAL)) { + if (!self->flushStatus) { + transportDec_SetParam(self->hInput, TPDEC_PARAM_RESET, 1); + self->streamInfo.numLostAccessUnits = 0; + self->streamInfo.numBadBytes = 0; + self->streamInfo.numTotalBytes = 0; + } + } + /* Reset the output delay field. The modules will add their figures one + * after another. */ + self->streamInfo.outputDelay = 0; + + if (self->limiterEnableUser == (UCHAR)-2) { + /* Enable limiter only for RSVD60. */ + self->limiterEnableCurr = (self->flags[0] & AC_RSV603DA) ? 1 : 0; + } else if (self->limiterEnableUser == (UCHAR)-1) { + /* Enable limiter for all non-lowdelay AOT's. */ + self->limiterEnableCurr = (self->flags[0] & (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)); + + pTimeDataFixpPcm = pTimeData; + timeDataFixpPcmSize = timeDataSize; + + ErrorStatus = CAacDecoder_DecodeFrame( + self, + flags | (fTpConceal ? AACDEC_CONCEAL : 0) | + ((self->flushStatus && !(flags & AACDEC_CONCEAL)) ? AACDEC_FLUSH + : 0), + pTimeDataFixpPcm + 0, timeDataFixpPcmSize, + self->streamInfo.aacSamplesPerFrame + 0); + + /* if flushing for USAC DASH IPF was not possible go on with decoding + * preroll */ + if ((self->flags[0] & AC_USAC) && + (self->flushStatus == AACDEC_USAC_DASH_IPF_FLUSH_ON) && + !(flags & AACDEC_CONCEAL) && (ErrorStatus != AAC_DEC_OK)) { + applyCrossfade = 0; + } else /* USAC DASH IPF flushing possible begin */ + { + if (!((flags & (AACDEC_CONCEAL | AACDEC_FLUSH)) || fTpConceal || + self->flushStatus) && + (!(IS_OUTPUT_VALID(ErrorStatus)) || !(accessUnit < numPrerollAU))) { + TRANSPORTDEC_ERROR tpErr; + tpErr = transportDec_EndAccessUnit(self->hInput); + if (tpErr != TRANSPORTDEC_OK) { + self->frameOK = 0; + } + } else { /* while preroll processing later possibly an error in the + renderer part occurrs */ + if (IS_OUTPUT_VALID(ErrorStatus)) { + fEndAuNotAdjusted = 1; + } + } + + /* If the current pTimeDataFixpPcm does not contain a valid signal, there + * nothing else we can do, so bail. */ + if (!IS_OUTPUT_VALID(ErrorStatus)) { + goto bail; + } + + { + self->streamInfo.sampleRate = self->streamInfo.aacSampleRate; + self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame; + } + + self->streamInfo.numChannels = self->streamInfo.aacNumChannels; + + { + FDK_Delay_Apply(&self->usacResidualDelay, + pTimeDataFixpPcm + + 1 * (self->streamInfo.aacSamplesPerFrame + 0) + 0, + self->streamInfo.frameSize, 0); + } + + /* Setting of internal MPS state; may be reset in CAacDecoder_SyncQmfMode + if decoder is unable to decode with user defined qmfMode */ + if (!(self->flags[0] & (AC_USAC | AC_RSVD50 | AC_RSV603DA | AC_ELD))) { + self->mpsEnableCurr = + (self->mpsEnableUser && + isSupportedMpsConfig(self->streamInfo.aot, + self->streamInfo.numChannels, + (self->flags[0] & AC_MPS_PRESENT) ? 1 : 0)); + } + + if (!self->qmfDomain.globalConf.qmfDomainExplicitConfig && + self->mpsEnableCurr) { + /* if not done yet, allocate full MPEG Surround decoder instance */ + if (mpegSurroundDecoder_IsFullMpegSurroundDecoderInstanceAvailable( + (CMpegSurroundDecoder *)self->pMpegSurroundDecoder) == + SAC_INSTANCE_NOT_FULL_AVAILABLE) { + if (mpegSurroundDecoder_Open( + (CMpegSurroundDecoder **)&self->pMpegSurroundDecoder, -1, + &self->qmfDomain)) { + return AAC_DEC_OUT_OF_MEMORY; + } + } + } + + CAacDecoder_SyncQmfMode(self); + + if (!self->qmfDomain.globalConf.qmfDomainExplicitConfig && + self->mpsEnableCurr) { + SAC_INPUT_CONFIG sac_interface = (self->sbrEnabled && self->hSbrDecoder) + ? SAC_INTERFACE_QMF + : SAC_INTERFACE_TIME; + /* needs to be done before first SBR apply. */ + mpegSurroundDecoder_ConfigureQmfDomain( + (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, sac_interface, + (UINT)self->streamInfo.aacSampleRate, self->streamInfo.aot); + if (self->qmfDomain.globalConf.nBandsAnalysis_requested > 0) { + self->qmfDomain.globalConf.nQmfTimeSlots_requested = + self->streamInfo.aacSamplesPerFrame / + self->qmfDomain.globalConf.nBandsAnalysis_requested; + } else { + self->qmfDomain.globalConf.nQmfTimeSlots_requested = 0; + } + } + + self->qmfDomain.globalConf.TDinput = pTimeData; + + switch (FDK_QmfDomain_Configure(&self->qmfDomain)) { + default: + case QMF_DOMAIN_INIT_ERROR: + ErrorStatus = AAC_DEC_UNKNOWN; + goto bail; + case QMF_DOMAIN_OUT_OF_MEMORY: + ErrorStatus = AAC_DEC_OUT_OF_MEMORY; + goto bail; + case QMF_DOMAIN_OK: + break; + } + + /* sbr decoder */ + + if ((ErrorStatus != AAC_DEC_OK) || (flags & AACDEC_CONCEAL) || + self->pAacDecoderStaticChannelInfo[0]->concealmentInfo.concealState > + ConcealState_FadeIn) { + self->frameOK = 0; /* if an error has occured do concealment in the SBR + decoder too */ + } + + if (self->sbrEnabled && (!(self->flags[0] & AC_USAC_SCFGI3))) { + SBR_ERROR sbrError = SBRDEC_OK; + int chIdx, numCoreChannel = self->streamInfo.numChannels; + + /* set params */ + sbrDecoder_SetParam(self->hSbrDecoder, SBR_SYSTEM_BITSTREAM_DELAY, + self->sbrParams.bsDelay); + sbrDecoder_SetParam( + self->hSbrDecoder, SBR_FLUSH_DATA, + (flags & AACDEC_FLUSH) | + ((self->flushStatus && !(flags & AACDEC_CONCEAL)) ? AACDEC_FLUSH + : 0)); + + if (self->streamInfo.aot == AOT_ER_AAC_ELD) { + /* Configure QMF */ + sbrDecoder_SetParam(self->hSbrDecoder, SBR_LD_QMF_TIME_ALIGN, + (self->flags[0] & AC_MPS_PRESENT) ? 1 : 0); + } + + { + PCMDMX_ERROR dmxErr; + INT maxOutCh = 0; + + dmxErr = pcmDmx_GetParam(self->hPcmUtils, + MAX_NUMBER_OF_OUTPUT_CHANNELS, &maxOutCh); + if ((dmxErr == PCMDMX_OK) && (maxOutCh == 1)) { + /* Disable PS processing if we have to create a mono output signal. + */ + self->psPossible = 0; + } + } + + sbrDecoder_SetParam(self->hSbrDecoder, SBR_SKIP_QMF, + (self->mpsEnableCurr) ? 2 : 0); + + INT_PCM *input; + input = (INT_PCM *)self->workBufferCore2; + FDKmemcpy(input, pTimeData, + sizeof(INT_PCM) * (self->streamInfo.numChannels) * + (self->streamInfo.frameSize)); + + /* apply SBR processing */ + sbrError = sbrDecoder_Apply(self->hSbrDecoder, input, pTimeData, + timeDataSize, &self->streamInfo.numChannels, + &self->streamInfo.sampleRate, + &self->mapDescr, self->chMapIndex, + self->frameOK, &self->psPossible); + + if (sbrError == SBRDEC_OK) { + /* Update data in streaminfo structure. Assume that the SBR upsampling + factor is either 1, 2, 8/3 or 4. Maximum upsampling factor is 4 + (CELP+SBR or USAC 4:1 SBR) */ + self->flags[0] |= AC_SBR_PRESENT; + if (self->streamInfo.aacSampleRate != self->streamInfo.sampleRate) { + if (self->streamInfo.aacSampleRate >> 2 == + self->streamInfo.sampleRate) { + self->streamInfo.frameSize = + self->streamInfo.aacSamplesPerFrame >> 2; + self->streamInfo.outputDelay = self->streamInfo.outputDelay >> 2; + } else if (self->streamInfo.aacSampleRate >> 1 == + self->streamInfo.sampleRate) { + self->streamInfo.frameSize = + self->streamInfo.aacSamplesPerFrame >> 1; + self->streamInfo.outputDelay = self->streamInfo.outputDelay >> 1; + } else if (self->streamInfo.aacSampleRate << 1 == + self->streamInfo.sampleRate) { + self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame + << 1; + self->streamInfo.outputDelay = self->streamInfo.outputDelay << 1; + } else if (self->streamInfo.aacSampleRate << 2 == + self->streamInfo.sampleRate) { + self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame + << 2; + self->streamInfo.outputDelay = self->streamInfo.outputDelay << 2; + } else if (self->streamInfo.frameSize == 768) { + self->streamInfo.frameSize = + (self->streamInfo.aacSamplesPerFrame << 3) / 3; + self->streamInfo.outputDelay = + (self->streamInfo.outputDelay << 3) / 3; + } else { + ErrorStatus = AAC_DEC_SET_PARAM_FAIL; + goto bail; + } + } else { + self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame; + } + self->streamInfo.outputDelay += + sbrDecoder_GetDelay(self->hSbrDecoder); + + if (self->psPossible) { + self->flags[0] |= AC_PS_PRESENT; + } + for (chIdx = numCoreChannel; chIdx < self->streamInfo.numChannels; + chIdx += 1) { + self->channelType[chIdx] = ACT_FRONT; + self->channelIndices[chIdx] = chIdx; + } + } + if (sbrError == SBRDEC_OUTPUT_BUFFER_TOO_SMALL) { + ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL; + goto bail; + } + } + + if (self->mpsEnableCurr) { + int err, sac_interface, nChannels, frameSize; + + nChannels = self->streamInfo.numChannels; + frameSize = self->streamInfo.frameSize; + sac_interface = SAC_INTERFACE_TIME; + + if (self->sbrEnabled && self->hSbrDecoder) + sac_interface = SAC_INTERFACE_QMF; + if (self->streamInfo.aot == AOT_USAC) { + if (self->flags[0] & AC_USAC_SCFGI3) { + sac_interface = SAC_INTERFACE_TIME; + } + } + err = mpegSurroundDecoder_SetParam( + (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, + SACDEC_INTERFACE, sac_interface); + + if (err == 0) { + err = mpegSurroundDecoder_Apply( + (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, + (INT_PCM *)self->workBufferCore2, pTimeData, timeDataSize, + self->streamInfo.aacSamplesPerFrame, &nChannels, &frameSize, + self->streamInfo.sampleRate, self->streamInfo.aot, + self->channelType, self->channelIndices, &self->mapDescr); + } + + if (err == MPS_OUTPUT_BUFFER_TOO_SMALL) { + ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL; + goto bail; + } + if (err == 0) { + /* Update output parameter */ + self->streamInfo.numChannels = nChannels; + self->streamInfo.frameSize = frameSize; + self->streamInfo.outputDelay += mpegSurroundDecoder_GetDelay( + (CMpegSurroundDecoder *)self->pMpegSurroundDecoder); + /* Save current parameter for possible concealment of next frame */ + self->mpsOutChannelsLast = nChannels; + self->mpsFrameSizeLast = frameSize; + } else if ((self->mpsOutChannelsLast > 0) && + (self->mpsFrameSizeLast > 0)) { + /* Restore parameters of last frame ... */ + self->streamInfo.numChannels = self->mpsOutChannelsLast; + self->streamInfo.frameSize = self->mpsFrameSizeLast; + /* ... and clear output buffer so that potentially corrupted data does + * not reach the framework. */ + FDKmemclear(pTimeData, self->mpsOutChannelsLast * + self->mpsFrameSizeLast * sizeof(INT_PCM)); + /* Additionally proclaim that this frame had errors during decoding. + */ + ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; + } else { + ErrorStatus = AAC_DEC_UNKNOWN; /* no output */ + } + } + + /* SBR decoder for Unified Stereo Config (stereoConfigIndex == 3) */ + + if (self->sbrEnabled && (self->flags[0] & AC_USAC_SCFGI3)) { + SBR_ERROR sbrError = SBRDEC_OK; + + /* set params */ + sbrDecoder_SetParam(self->hSbrDecoder, SBR_SYSTEM_BITSTREAM_DELAY, + self->sbrParams.bsDelay); + + sbrDecoder_SetParam(self->hSbrDecoder, SBR_SKIP_QMF, 1); + + /* apply SBR processing */ + sbrError = sbrDecoder_Apply(self->hSbrDecoder, pTimeData, pTimeData, + timeDataSize, &self->streamInfo.numChannels, + &self->streamInfo.sampleRate, + &self->mapDescr, self->chMapIndex, + self->frameOK, &self->psPossible); + + if (sbrError == SBRDEC_OK) { + /* Update data in streaminfo structure. Assume that the SBR upsampling + * factor is either 1,2 or 4 */ + self->flags[0] |= AC_SBR_PRESENT; + if (self->streamInfo.aacSampleRate != self->streamInfo.sampleRate) { + if (self->streamInfo.frameSize == 768) { + self->streamInfo.frameSize = + (self->streamInfo.aacSamplesPerFrame * 8) / 3; + } else if (self->streamInfo.aacSampleRate << 2 == + self->streamInfo.sampleRate) { + self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame + << 2; + } else { + self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame + << 1; + } + } + + self->flags[0] &= ~AC_PS_PRESENT; + } + if (sbrError == SBRDEC_OUTPUT_BUFFER_TOO_SMALL) { + ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL; + goto bail; + } + } + + /* Use dedicated memory for PCM postprocessing */ + pTimeDataPcmPost = self->pTimeData2; + timeDataPcmPostSize = self->timeData2Size; + + { + const int size = + self->streamInfo.frameSize * self->streamInfo.numChannels; + FDK_ASSERT(timeDataPcmPostSize >= size); + for (int i = 0; i < size; i++) { + pTimeDataPcmPost[i] = + (PCM_DEC)FX_PCM2PCM_DEC(pTimeData[i]) >> PCM_OUT_HEADROOM; + } + } + + { + if ((FDK_drcDec_GetParam(self->hUniDrcDecoder, DRC_DEC_IS_ACTIVE)) && + !(self->flags[0] & AC_RSV603DA)) { + /* Apply DRC gains*/ + int ch, drcDelay = 0; + int needsDeinterleaving = 0; + FIXP_DBL *drcWorkBuffer = NULL; + FIXP_DBL channelGain[(8)]; + int reverseInChannelMap[(8)]; + int reverseOutChannelMap[(8)]; + int numDrcOutChannels = FDK_drcDec_GetParam( + self->hUniDrcDecoder, DRC_DEC_TARGET_CHANNEL_COUNT_SELECTED); + FDKmemclear(channelGain, sizeof(channelGain)); + for (ch = 0; ch < (8); ch++) { + reverseInChannelMap[ch] = ch; + reverseOutChannelMap[ch] = ch; + } + + /* If SBR and/or MPS is active, the DRC gains are aligned to the QMF + domain signal before the QMF synthesis. Therefore the DRC gains + need to be delayed by the QMF synthesis delay. */ + if (self->sbrEnabled) drcDelay = 257; + if (self->mpsEnableCurr) drcDelay = 257; + /* Take into account concealment delay */ + drcDelay += CConcealment_GetDelay(&self->concealCommonData) * + self->streamInfo.frameSize; + + for (ch = 0; ch < self->streamInfo.numChannels; ch++) { + UCHAR mapValue = FDK_chMapDescr_getMapValue( + &self->mapDescr, (UCHAR)ch, self->chMapIndex); + if (mapValue < (8)) reverseInChannelMap[mapValue] = ch; + } + for (ch = 0; ch < (int)numDrcOutChannels; ch++) { + UCHAR mapValue = FDK_chMapDescr_getMapValue( + &self->mapDescr, (UCHAR)ch, numDrcOutChannels); + if (mapValue < (8)) reverseOutChannelMap[mapValue] = ch; + } + + /* The output of SBR and MPS is interleaved. Deinterleaving may be + * necessary for FDK_drcDec_ProcessTime, which accepts deinterleaved + * audio only. */ + if ((self->streamInfo.numChannels > 1) && + (0 || (self->sbrEnabled) || (self->mpsEnableCurr))) { + /* interleaving/deinterleaving is performed on upper part of + * pTimeDataPcmPost. Check if this buffer is large enough. */ + if (timeDataPcmPostSize < + (INT)(2 * self->streamInfo.numChannels * + self->streamInfo.frameSize * sizeof(PCM_DEC))) { + ErrorStatus = AAC_DEC_UNKNOWN; + goto bail; + } + needsDeinterleaving = 1; + drcWorkBuffer = + (FIXP_DBL *)pTimeDataPcmPost + + self->streamInfo.numChannels * self->streamInfo.frameSize; + FDK_deinterleave( + pTimeDataPcmPost, drcWorkBuffer, self->streamInfo.numChannels, + self->streamInfo.frameSize, self->streamInfo.frameSize); + } else { + drcWorkBuffer = (FIXP_DBL *)pTimeDataPcmPost; + } + + /* prepare Loudness Normalisation gain */ + FDK_drcDec_SetParam(self->hUniDrcDecoder, DRC_DEC_TARGET_LOUDNESS, + (INT)-self->defaultTargetLoudness * + FL2FXCONST_DBL(1.0f / (float)(1 << 9))); + FDK_drcDec_SetChannelGains(self->hUniDrcDecoder, + self->streamInfo.numChannels, + self->streamInfo.frameSize, channelGain, + drcWorkBuffer, self->streamInfo.frameSize); + FDK_drcDec_Preprocess(self->hUniDrcDecoder); + + /* apply DRC1 gain sequence */ + for (ch = 0; ch < self->streamInfo.numChannels; ch++) { + FDK_drcDec_ProcessTime(self->hUniDrcDecoder, drcDelay, DRC_DEC_DRC1, + ch, reverseInChannelMap[ch] - ch, 1, + drcWorkBuffer, self->streamInfo.frameSize); + } + /* apply downmix */ + FDK_drcDec_ApplyDownmix( + self->hUniDrcDecoder, reverseInChannelMap, reverseOutChannelMap, + drcWorkBuffer, + &self->streamInfo.numChannels); /* self->streamInfo.numChannels + may change here */ + /* apply DRC2/3 gain sequence */ + for (ch = 0; ch < self->streamInfo.numChannels; ch++) { + FDK_drcDec_ProcessTime(self->hUniDrcDecoder, drcDelay, + DRC_DEC_DRC2_DRC3, ch, + reverseOutChannelMap[ch] - ch, 1, + drcWorkBuffer, self->streamInfo.frameSize); + } + + if (needsDeinterleaving) { + FDK_interleave( + drcWorkBuffer, pTimeDataPcmPost, self->streamInfo.numChannels, + self->streamInfo.frameSize, self->streamInfo.frameSize); + } + } + } + + if (self->streamInfo.extAot != AOT_AAC_SLS) { + INT pcmLimiterScale = 0; + PCMDMX_ERROR dmxErr = PCMDMX_OK; + if (flags & (AACDEC_INTR)) { + /* delete data from the past (e.g. mixdown coeficients) */ + pcmDmx_Reset(self->hPcmUtils, PCMDMX_RESET_BS_DATA); + } + if (flags & (AACDEC_CLRHIST)) { + if (!(self->flags[0] & AC_USAC)) { + /* delete data from the past (e.g. mixdown coeficients) */ + pcmDmx_Reset(self->hPcmUtils, PCMDMX_RESET_BS_DATA); + } + } + + INT interleaved = 0; + interleaved |= (self->sbrEnabled) ? 1 : 0; + interleaved |= (self->mpsEnableCurr) ? 1 : 0; + + /* do PCM post processing */ + dmxErr = pcmDmx_ApplyFrame( + self->hPcmUtils, pTimeDataPcmPost, timeDataFixpPcmSize, + self->streamInfo.frameSize, &self->streamInfo.numChannels, + interleaved, self->channelType, self->channelIndices, + &self->mapDescr, + (self->limiterEnableCurr) ? &pcmLimiterScale : NULL); + if (dmxErr == PCMDMX_OUTPUT_BUFFER_TOO_SMALL) { + ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL; + goto bail; + } + if ((ErrorStatus == AAC_DEC_OK) && (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) { + if (!(self->flags[0] & AC_USAC)) { + /* Delete the delayed signal. */ + pcmLimiter_Reset(self->hLimiter); + } + } + + if (self->limiterEnableCurr) { + /* use workBufferCore2 buffer for interleaving */ + PCM_LIM *pInterleaveBuffer; + int blockLength = self->streamInfo.frameSize; + + /* Set actual signal parameters */ + pcmLimiter_SetNChannels(self->hLimiter, self->streamInfo.numChannels); + pcmLimiter_SetSampleRate(self->hLimiter, self->streamInfo.sampleRate); + pcmLimiterScale += PCM_OUT_HEADROOM; + + if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) || + (self->mpsEnableCurr)) { + pInterleaveBuffer = (PCM_LIM *)pTimeDataPcmPost; + } else { + pInterleaveBuffer = (PCM_LIM *)pTimeData; + /* applyLimiter requests for interleaved data */ + /* Interleave ouput buffer */ + FDK_interleave(pTimeDataPcmPost, pInterleaveBuffer, + self->streamInfo.numChannels, blockLength, + self->streamInfo.frameSize); + } + + pcmLimiter_Apply(self->hLimiter, pInterleaveBuffer, pTimeData, + self->extGain, &pcmLimiterScale, 1, + self->extGainDelay, self->streamInfo.frameSize); + + { + /* Announce the additional limiter output delay */ + self->streamInfo.outputDelay += pcmLimiter_GetDelay(self->hLimiter); + } + } else { + /* If numChannels = 1 we do not need interleaving. The same applies if + SBR or MPS are used, since their output is interleaved already + (resampled or not) */ + if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) || + (self->mpsEnableCurr)) { + scaleValuesSaturate( + pTimeData, pTimeDataPcmPost, + self->streamInfo.frameSize * self->streamInfo.numChannels, + PCM_OUT_HEADROOM); + + } else { + scaleValuesSaturate( + (INT_PCM *)self->workBufferCore2, pTimeDataPcmPost, + self->streamInfo.frameSize * self->streamInfo.numChannels, + PCM_OUT_HEADROOM); + /* Interleave ouput buffer */ + FDK_interleave((INT_PCM *)self->workBufferCore2, pTimeData, + self->streamInfo.numChannels, + self->streamInfo.frameSize, + self->streamInfo.frameSize); + } + } + } /* if (self->streamInfo.extAot != AOT_AAC_SLS)*/ + + if (self->flags[0] & AC_USAC) { + if (self->flushStatus == AACDEC_USAC_DASH_IPF_FLUSH_ON && + !(flags & AACDEC_CONCEAL)) { + CAacDecoder_PrepareCrossFade(pTimeData, self->pTimeDataFlush, + self->streamInfo.numChannels, + self->streamInfo.frameSize, 1); + } + + /* prepare crossfade buffer for fade in */ + if (!applyCrossfade && self->applyCrossfade && + !(flags & AACDEC_CONCEAL)) { + for (int ch = 0; ch < self->streamInfo.numChannels; ch++) { + for (int i = 0; i < TIME_DATA_FLUSH_SIZE; i++) { + self->pTimeDataFlush[ch][i] = 0; + } + } + applyCrossfade = 1; + } + + if (applyCrossfade && self->applyCrossfade && + !(accessUnit < numPrerollAU) && + (self->buildUpStatus == AACDEC_USAC_BUILD_UP_ON)) { + CAacDecoder_ApplyCrossFade(pTimeData, self->pTimeDataFlush, + self->streamInfo.numChannels, + self->streamInfo.frameSize, 1); + self->applyCrossfade = 0; + } + } + + /* Signal interruption to take effect in next frame. */ + if ((flags & AACDEC_FLUSH || self->flushStatus) && + !(flags & AACDEC_CONCEAL)) { + aacDecoder_SignalInterruption(self); + } + + /* Update externally visible copy of flags */ + self->streamInfo.flags = self->flags[0]; + + } /* USAC DASH IPF flushing possible end */ + if (accessUnit < numPrerollAU) { + FDKpushBack(hBsAu, auStartAnchor - (INT)FDKgetValidBits(hBsAu)); + } else { + if ((self->buildUpStatus == AACDEC_RSV60_BUILD_UP_ON) || + (self->buildUpStatus == AACDEC_RSV60_BUILD_UP_ON_IN_BAND) || + (self->buildUpStatus == AACDEC_USAC_BUILD_UP_ON)) { + self->buildUpCnt--; + + if (self->buildUpCnt < 0) { + self->buildUpStatus = 0; + } + } + + if (self->flags[0] & AC_USAC) { + if (self->flushStatus == AACDEC_USAC_DASH_IPF_FLUSH_ON && + !(flags & AACDEC_CONCEAL)) { + self->streamInfo.frameSize = 0; + } + } + } + + if (self->flushStatus != AACDEC_USAC_DASH_IPF_FLUSH_ON) { + accessUnit++; + } + } while ((accessUnit < numAccessUnits) || + ((self->flushStatus == AACDEC_USAC_DASH_IPF_FLUSH_ON) && + !(flags & AACDEC_CONCEAL))); + +bail: + + /* error in renderer part occurred, ErrorStatus was set to invalid output */ + if (fEndAuNotAdjusted && !IS_OUTPUT_VALID(ErrorStatus) && + (accessUnit < numPrerollAU)) { + transportDec_EndAccessUnit(self->hInput); + } + + /* Update Statistics */ + aacDecoder_UpdateBitStreamCounters(&self->streamInfo, hBs, nBits, + ErrorStatus); + if (((self->streamInfo.numChannels <= 0) || + (self->streamInfo.frameSize <= 0) || + (self->streamInfo.sampleRate <= 0)) && + IS_OUTPUT_VALID(ErrorStatus)) { + /* Ensure consistency of IS_OUTPUT_VALID() macro. */ + ErrorStatus = AAC_DEC_UNKNOWN; + } + + /* Check whether external output buffer is large enough. */ + if (timeDataSize_extern < + self->streamInfo.numChannels * self->streamInfo.frameSize) { + ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL; + } + + /* Update external output buffer. */ + if (IS_OUTPUT_VALID(ErrorStatus)) { + FDKmemcpy(pTimeData_extern, pTimeData, + self->streamInfo.numChannels * self->streamInfo.frameSize * + sizeof(*pTimeData)); + } else { + FDKmemclear(pTimeData_extern, + timeDataSize_extern * sizeof(*pTimeData_extern)); + } + + return ErrorStatus; +} + +LINKSPEC_CPP void aacDecoder_Close(HANDLE_AACDECODER self) { + if (self == NULL) return; + + if (self->hLimiter != NULL) { + pcmLimiter_Destroy(self->hLimiter); + } + + if (self->hPcmUtils != NULL) { + pcmDmx_Close(&self->hPcmUtils); + } + + FDK_drcDec_Close(&self->hUniDrcDecoder); + + if (self->pMpegSurroundDecoder != NULL) { + mpegSurroundDecoder_Close( + (CMpegSurroundDecoder *)self->pMpegSurroundDecoder); + } + + if (self->hSbrDecoder != NULL) { + sbrDecoder_Close(&self->hSbrDecoder); + } + + if (self->hInput != NULL) { + transportDec_Close(&self->hInput); + } + + CAacDecoder_Close(self); +} + +LINKSPEC_CPP CStreamInfo *aacDecoder_GetStreamInfo(HANDLE_AACDECODER self) { + return CAacDecoder_GetStreamInfo(self); +} + +LINKSPEC_CPP INT aacDecoder_GetLibInfo(LIB_INFO *info) { + int i; + + if (info == NULL) { + return -1; + } + + sbrDecoder_GetLibInfo(info); + mpegSurroundDecoder_GetLibInfo(info); + transportDec_GetLibInfo(info); + FDK_toolsGetLibInfo(info); + pcmDmx_GetLibInfo(info); + pcmLimiter_GetLibInfo(info); + FDK_drcDec_GetLibInfo(info); + + /* search for next free tab */ + for (i = 0; i < FDK_MODULE_LAST; i++) { + if (info[i].module_id == FDK_NONE) break; + } + if (i == FDK_MODULE_LAST) { + return -1; + } + info += i; + + info->module_id = FDK_AACDEC; + /* build own library info */ + info->version = + LIB_VERSION(AACDECODER_LIB_VL0, AACDECODER_LIB_VL1, AACDECODER_LIB_VL2); + LIB_VERSION_STRING(info); + info->build_date = AACDECODER_LIB_BUILD_DATE; + info->build_time = AACDECODER_LIB_BUILD_TIME; + info->title = AACDECODER_LIB_TITLE; + + /* Set flags */ + info->flags = 0 | CAPF_AAC_LC | CAPF_ER_AAC_LC | CAPF_ER_AAC_SCAL | + CAPF_AAC_VCB11 | CAPF_AAC_HCR | CAPF_AAC_RVLC | CAPF_ER_AAC_LD | + CAPF_ER_AAC_ELD | CAPF_AAC_CONCEALMENT | CAPF_AAC_DRC | + CAPF_AAC_MPEG4 | CAPF_AAC_DRM_BSFORMAT | CAPF_AAC_1024 | + CAPF_AAC_960 | CAPF_AAC_512 | CAPF_AAC_480 | + CAPF_AAC_ELD_DOWNSCALE + + | CAPF_AAC_USAC | CAPF_ER_AAC_ELDV2 | CAPF_AAC_UNIDRC; + /* End of flags */ + + return 0; +} |