From 0e5af65c467b2423a0b857ae3ad98c91acc1e190 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Mon, 11 Nov 2019 11:38:02 +0100 Subject: Include patched FDK-AAC in the repository The initial idea was to get the DAB+ patch into upstream, but since that follows the android source releases, there is no place for a custom DAB+ patch there. So instead of having to maintain a patched fdk-aac that has to have the same .so version as the distribution package on which it is installed, we prefer having a separate fdk-aac-dab library to avoid collision. At that point, there's no reason to keep fdk-aac in a separate repository, as odr-audioenc is the only tool that needs DAB+ encoding support. Including it here simplifies installation, and makes it consistent with toolame-dab, also shipped in this repository. DAB+ decoding support (needed by ODR-SourceCompanion, dablin, etisnoop, welle.io and others) can be done using upstream FDK-AAC. --- fdk-aac/libAACdec/src/aacdecoder.cpp | 3464 ++++++++++++++++++++++++++++++++++ 1 file changed, 3464 insertions(+) create mode 100644 fdk-aac/libAACdec/src/aacdecoder.cpp (limited to 'fdk-aac/libAACdec/src/aacdecoder.cpp') diff --git a/fdk-aac/libAACdec/src/aacdecoder.cpp b/fdk-aac/libAACdec/src/aacdecoder.cpp new file mode 100644 index 0000000..8f03328 --- /dev/null +++ b/fdk-aac/libAACdec/src/aacdecoder.cpp @@ -0,0 +1,3464 @@ +/* ----------------------------------------------------------------------------- +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): Josef Hoepfl + + Description: + +*******************************************************************************/ + +/*! + \page default General Overview of the AAC Decoder Implementation + + The main entry point to decode a AAC frame is CAacDecoder_DecodeFrame(). It + handles the different transport multiplexes and bitstream formats supported by + this implementation. It extracts the AAC_raw_data_blocks from these bitstreams + to further process then in the actual decoding stages. + + Note: Click on a function of file in the above image to see details about the + function. Also note, that this is just an overview of the most important + functions and not a complete call graph. + +

1 Bitstream deformatter

+ The basic bit stream parser function CChannelElement_Read() is called. It uses + other subcalls in order to parse and unpack the bitstreams. Note, that this + includes huffmann decoding of the coded spectral data. This operation can be + computational significant specifically at higher bitrates. Optimization is + likely in CBlock_ReadSpectralData(). + + The bitstream deformatter also includes many bitfield operations. Profiling on + the target will determine required optimizations. + +

2 Actual decoding to retain the time domain output

+ The basic bitstream deformatter function CChannelElement_Decode() for CPE + elements and SCE elements are called. Except for the stereo processing (2.1) + which is only used for CPE elements, the function calls for CPE or SCE are + similar, except that CPE always processes to independent channels while SCE + only processes one channel. + + Often there is the distinction between long blocks and short blocks. However, + computational expensive functions that ususally require optimization are being + shared by these two groups, + +

2.1 Stereo processing for CPE elements

+ CChannelPairElement_Decode() first calles the joint stereo tools in + stereo.cpp when required. + +

2.2 Scaling of spectral data

+ CBlock_ScaleSpectralData(). + +

2.3 Apply additional coding tools

+ ApplyTools() calles the PNS tools in case of MPEG-4 bitstreams, and TNS + filtering CTns_Apply() for MPEG-2 and MPEG-4 bitstreams. The function + TnsFilterIIR() which is called by CTns_Apply() (2.3.1) might require some + optimization. + +

3 Frequency-To-Time conversion

+ The filterbank is called using CBlock_FrequencyToTime() using the MDCT module + from the FDK Tools + +*/ + +#include "aacdecoder.h" + +#include "aac_rom.h" +#include "aac_ram.h" +#include "channel.h" +#include "FDK_audio.h" + +#include "aacdec_pns.h" + +#include "sbrdecoder.h" + +#include "sac_dec_lib.h" + +#include "aacdec_hcr.h" +#include "rvlc.h" + +#include "usacdec_lpd.h" + +#include "ac_arith_coder.h" + +#include "tpdec_lib.h" + +#include "conceal.h" + +#include "FDK_crc.h" +#define PS_IS_EXPLICITLY_DISABLED(aot, flags) \ + (((aot) == AOT_DRM_AAC) && !(flags & AC_PS_PRESENT)) + +#define IS_STEREO_SBR(el_id, stereoConfigIndex) \ + (((el_id) == ID_USAC_CPE && (stereoConfigIndex) == 0) || \ + ((el_id) == ID_USAC_CPE && (stereoConfigIndex) == 3)) + +void CAacDecoder_SyncQmfMode(HANDLE_AACDECODER self) { + FDK_ASSERT( + !((self->flags[0] & AC_MPS_PRESENT) && (self->flags[0] & AC_PS_PRESENT))); + + /* Assign user requested mode */ + self->qmfModeCurr = self->qmfModeUser; + + if (IS_USAC(self->streamInfo.aot)) { + self->qmfModeCurr = MODE_HQ; + } + + if (self->qmfModeCurr == NOT_DEFINED) { + if ((IS_LOWDELAY(self->streamInfo.aot) && + (self->flags[0] & AC_MPS_PRESENT)) || + ((self->streamInfo.aacNumChannels == 1) && + ((CAN_DO_PS(self->streamInfo.aot) && + !(self->flags[0] & AC_MPS_PRESENT)) || + (IS_USAC(self->streamInfo.aot))))) { + self->qmfModeCurr = MODE_HQ; + } else { + self->qmfModeCurr = MODE_LP; + } + } + + if (self->mpsEnableCurr) { + if (IS_LOWDELAY(self->streamInfo.aot) && + (self->qmfModeCurr == MODE_LP)) { /* Overrule user requested QMF mode */ + self->qmfModeCurr = MODE_HQ; + } + /* Set and check if MPS decoder allows the current mode */ + switch (mpegSurroundDecoder_SetParam( + (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, + SACDEC_PARTIALLY_COMPLEX, self->qmfModeCurr == MODE_LP)) { + case MPS_OK: + break; + case MPS_INVALID_PARAMETER: { /* Only one mode supported. Find out which + one: */ + LIB_INFO libInfo[FDK_MODULE_LAST]; + UINT mpsCaps; + + FDKinitLibInfo(libInfo); + mpegSurroundDecoder_GetLibInfo(libInfo); + mpsCaps = FDKlibInfo_getCapabilities(libInfo, FDK_MPSDEC); + + if (((mpsCaps & CAPF_MPS_LP) && (self->qmfModeCurr == MODE_LP)) || + ((mpsCaps & CAPF_MPS_HQ) && + (self->qmfModeCurr == + MODE_HQ))) { /* MPS decoder does support the requested mode. */ + break; + } + } + FDK_FALLTHROUGH; + default: + if (self->qmfModeUser == NOT_DEFINED) { + /* Revert in case mpegSurroundDecoder_SetParam() fails. */ + self->qmfModeCurr = + (self->qmfModeCurr == MODE_LP) ? MODE_HQ : MODE_LP; + } else { + /* in case specific mode was requested we disable MPS and playout the + * downmix */ + self->mpsEnableCurr = 0; + } + } + } + + /* Set SBR to current QMF mode. Error does not matter. */ + sbrDecoder_SetParam(self->hSbrDecoder, SBR_QMF_MODE, + (self->qmfModeCurr == MODE_LP)); + self->psPossible = + ((CAN_DO_PS(self->streamInfo.aot) && + !PS_IS_EXPLICITLY_DISABLED(self->streamInfo.aot, self->flags[0]) && + self->streamInfo.aacNumChannels == 1 && + !(self->flags[0] & AC_MPS_PRESENT))) && + self->qmfModeCurr == MODE_HQ; + FDK_ASSERT(!((self->flags[0] & AC_MPS_PRESENT) && self->psPossible)); +} + +void CAacDecoder_SignalInterruption(HANDLE_AACDECODER self) { + if (self->flags[0] & (AC_USAC | AC_RSVD50 | AC_RSV603DA)) { + int i; + + for (i = 0; i < fMin(self->aacChannels, (8)); i++) { + if (self->pAacDecoderStaticChannelInfo + [i]) { /* number of active channels can be smaller */ + self->pAacDecoderStaticChannelInfo[i]->hArCo->m_numberLinesPrev = 0; + } + } + } +} + +/*! + \brief Calculates the number of element channels + + \type channel type + \usacStereoConfigIndex usac stereo config index + + \return element channels +*/ +static int CAacDecoder_GetELChannels(MP4_ELEMENT_ID type, + UCHAR usacStereoConfigIndex) { + int el_channels = 0; + + switch (type) { + case ID_USAC_CPE: + if (usacStereoConfigIndex == 1) { + el_channels = 1; + } else { + el_channels = 2; + } + break; + case ID_CPE: + el_channels = 2; + break; + case ID_USAC_SCE: + case ID_USAC_LFE: + case ID_SCE: + case ID_LFE: + el_channels = 1; + break; + default: + el_channels = 0; + break; + } + + return el_channels; +} + +/*! + \brief Reset ancillary data struct. Call before parsing a new frame. + + \ancData Pointer to ancillary data structure + + \return Error code +*/ +static AAC_DECODER_ERROR CAacDecoder_AncDataReset(CAncData *ancData) { + int i; + for (i = 0; i < 8; i++) { + ancData->offset[i] = 0; + } + ancData->nrElements = 0; + + return AAC_DEC_OK; +} + +/*! + \brief Initialize ancillary buffer + + \ancData Pointer to ancillary data structure + \buffer Pointer to (external) anc data buffer + \size Size of the buffer pointed on by buffer in bytes + + \return Error code +*/ +AAC_DECODER_ERROR CAacDecoder_AncDataInit(CAncData *ancData, + unsigned char *buffer, int size) { + if (size >= 0) { + ancData->buffer = buffer; + ancData->bufferSize = size; + + CAacDecoder_AncDataReset(ancData); + + return AAC_DEC_OK; + } + + return AAC_DEC_ANC_DATA_ERROR; +} + +/*! + \brief Get one ancillary data element + + \ancData Pointer to ancillary data structure + \index Index of the anc data element to get + \ptr Pointer to a buffer receiving a pointer to the requested anc data element + \size Pointer to a buffer receiving the length of the requested anc data + element in bytes + + \return Error code +*/ +AAC_DECODER_ERROR CAacDecoder_AncDataGet(CAncData *ancData, int index, + unsigned char **ptr, int *size) { + AAC_DECODER_ERROR error = AAC_DEC_OK; + + *ptr = NULL; + *size = 0; + + if (index >= 0 && index < 8 - 1 && index < ancData->nrElements) { + *ptr = &ancData->buffer[ancData->offset[index]]; + *size = ancData->offset[index + 1] - ancData->offset[index]; + } + + return error; +} + +/*! + \brief Parse ancillary data + + \ancData Pointer to ancillary data structure + \hBs Handle to FDK bitstream + \ancBytes Length of ancillary data to read from the bitstream + + \return Error code +*/ +static AAC_DECODER_ERROR CAacDecoder_AncDataParse(CAncData *ancData, + HANDLE_FDK_BITSTREAM hBs, + const int ancBytes) { + AAC_DECODER_ERROR error = AAC_DEC_OK; + int readBytes = 0; + + if (ancData->buffer != NULL) { + if (ancBytes > 0) { + /* write ancillary data to external buffer */ + int offset = ancData->offset[ancData->nrElements]; + + if ((offset + ancBytes) > ancData->bufferSize) { + error = AAC_DEC_TOO_SMALL_ANC_BUFFER; + } else if (ancData->nrElements >= 8 - 1) { + error = AAC_DEC_TOO_MANY_ANC_ELEMENTS; + } else { + int i; + + for (i = 0; i < ancBytes; i++) { + ancData->buffer[i + offset] = FDKreadBits(hBs, 8); + readBytes++; + } + + ancData->nrElements++; + ancData->offset[ancData->nrElements] = + ancBytes + ancData->offset[ancData->nrElements - 1]; + } + } + } + + readBytes = ancBytes - readBytes; + + if (readBytes > 0) { + /* skip data */ + FDKpushFor(hBs, readBytes << 3); + } + + return error; +} + +/*! + \brief Read Stream Data Element + + \bs Bitstream Handle + + \return Error code +*/ +static AAC_DECODER_ERROR CDataStreamElement_Read(HANDLE_AACDECODER self, + HANDLE_FDK_BITSTREAM bs, + UCHAR *elementInstanceTag, + UINT alignmentAnchor) { + AAC_DECODER_ERROR error = AAC_DEC_OK; + UINT dseBits; + INT dataStart; + int dataByteAlignFlag, count; + + FDK_ASSERT(self != NULL); + + int crcReg = transportDec_CrcStartReg(self->hInput, 0); + + /* Element Instance Tag */ + *elementInstanceTag = FDKreadBits(bs, 4); + /* Data Byte Align Flag */ + dataByteAlignFlag = FDKreadBits(bs, 1); + + count = FDKreadBits(bs, 8); + + if (count == 255) { + count += FDKreadBits(bs, 8); /* EscCount */ + } + dseBits = count * 8; + + if (dataByteAlignFlag) { + FDKbyteAlign(bs, alignmentAnchor); + } + + dataStart = (INT)FDKgetValidBits(bs); + + error = CAacDecoder_AncDataParse(&self->ancData, bs, count); + transportDec_CrcEndReg(self->hInput, crcReg); + + { + /* Move to the beginning of the data chunk */ + FDKpushBack(bs, dataStart - (INT)FDKgetValidBits(bs)); + + /* Read Anc data if available */ + aacDecoder_drcMarkPayload(self->hDrcInfo, bs, DVB_DRC_ANC_DATA); + } + + { + PCMDMX_ERROR dmxErr = PCMDMX_OK; + + /* Move to the beginning of the data chunk */ + FDKpushBack(bs, dataStart - (INT)FDKgetValidBits(bs)); + + /* Read DMX meta-data */ + dmxErr = pcmDmx_Parse(self->hPcmUtils, bs, dseBits, 0 /* not mpeg2 */); + if (error == AAC_DEC_OK && dmxErr != PCMDMX_OK) { + error = AAC_DEC_UNKNOWN; + } + } + + /* Move to the very end of the element. */ + FDKpushBiDirectional(bs, (INT)FDKgetValidBits(bs) - dataStart + (INT)dseBits); + + return error; +} + +/*! + \brief Read Program Config Element + + \bs Bitstream Handle + \pTp Transport decoder handle for CRC handling + \pce Pointer to PCE buffer + \channelConfig Current channel configuration + \alignAnchor Anchor for byte alignment + + \return PCE status (-1: fail, 0: no new PCE, 1: PCE updated, 2: PCE updated + need re-config). +*/ +static int CProgramConfigElement_Read(HANDLE_FDK_BITSTREAM bs, + HANDLE_TRANSPORTDEC pTp, + CProgramConfig *pce, + const UINT channelConfig, + const UINT alignAnchor) { + int pceStatus = 0; + int crcReg; + + /* read PCE to temporal buffer first */ + C_ALLOC_SCRATCH_START(tmpPce, CProgramConfig, 1); + + CProgramConfig_Init(tmpPce); + + crcReg = transportDec_CrcStartReg(pTp, 0); + + CProgramConfig_Read(tmpPce, bs, alignAnchor); + + transportDec_CrcEndReg(pTp, crcReg); + + if (CProgramConfig_IsValid(tmpPce) && (tmpPce->Profile == 1)) { + if (!CProgramConfig_IsValid(pce) && (channelConfig > 0)) { + /* Create a standard channel config PCE to compare with */ + CProgramConfig_GetDefault(pce, channelConfig); + } + + if (CProgramConfig_IsValid(pce)) { + /* Compare the new and the old PCE (tags ignored) */ + switch (CProgramConfig_Compare(pce, tmpPce)) { + case 1: /* Channel configuration not changed. Just new metadata. */ + FDKmemcpy(pce, tmpPce, + sizeof(CProgramConfig)); /* Store the complete PCE */ + pceStatus = 1; /* New PCE but no change of config */ + break; + case 2: /* The number of channels are identical but not the config */ + case -1: /* The channel configuration is completely different */ + pceStatus = -1; /* Not supported! */ + break; + case 0: /* Nothing to do because PCE matches the old one exactly. */ + default: + /* pceStatus = 0; */ + break; + } + } + } + + C_ALLOC_SCRATCH_END(tmpPce, CProgramConfig, 1); + + return pceStatus; +} + +/*! + \brief Prepares crossfade for USAC DASH IPF config change + + \pTimeData Pointer to time data + \pTimeDataFlush Pointer to flushed time data + \numChannels Number of channels + \frameSize Size of frame + \interleaved Indicates if time data is interleaved + + \return Error code +*/ +LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_PrepareCrossFade( + const INT_PCM *pTimeData, INT_PCM **pTimeDataFlush, const INT numChannels, + const INT frameSize, const INT interleaved) { + int i, ch, s1, s2; + AAC_DECODER_ERROR ErrorStatus; + + ErrorStatus = AAC_DEC_OK; + + if (interleaved) { + s1 = 1; + s2 = numChannels; + } else { + s1 = frameSize; + s2 = 1; + } + + for (ch = 0; ch < numChannels; ch++) { + const INT_PCM *pIn = &pTimeData[ch * s1]; + for (i = 0; i < TIME_DATA_FLUSH_SIZE; i++) { + pTimeDataFlush[ch][i] = *pIn; + pIn += s2; + } + } + + return ErrorStatus; +} + +/*! + \brief Applies crossfade for USAC DASH IPF config change + + \pTimeData Pointer to time data + \pTimeDataFlush Pointer to flushed time data + \numChannels Number of channels + \frameSize Size of frame + \interleaved Indicates if time data is interleaved + + \return Error code +*/ +LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_ApplyCrossFade( + INT_PCM *pTimeData, INT_PCM **pTimeDataFlush, const INT numChannels, + const INT frameSize, const INT interleaved) { + int i, ch, s1, s2; + AAC_DECODER_ERROR ErrorStatus; + + ErrorStatus = AAC_DEC_OK; + + if (interleaved) { + s1 = 1; + s2 = numChannels; + } else { + s1 = frameSize; + s2 = 1; + } + + for (ch = 0; ch < numChannels; ch++) { + INT_PCM *pIn = &pTimeData[ch * s1]; + for (i = 0; i < TIME_DATA_FLUSH_SIZE; i++) { + FIXP_SGL alpha = (FIXP_SGL)i + << (FRACT_BITS - 1 - TIME_DATA_FLUSH_SIZE_SF); + FIXP_DBL time = FX_PCM2FX_DBL(*pIn); + FIXP_DBL timeFlush = FX_PCM2FX_DBL(pTimeDataFlush[ch][i]); + + *pIn = (INT_PCM)(FIXP_PCM)FX_DBL2FX_PCM( + timeFlush - fMult(timeFlush, alpha) + fMult(time, alpha)); + pIn += s2; + } + } + + return ErrorStatus; +} + +/*! + \brief Parse PreRoll Extension Payload + + \self Handle of AAC decoder + \numPrerollAU Number of preRoll AUs + \prerollAUOffset Offset to each preRoll AU + \prerollAULength Length of each preRoll AU + + \return Error code +*/ +LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_PreRollExtensionPayloadParse( + HANDLE_AACDECODER self, UINT *numPrerollAU, UINT *prerollAUOffset, + UINT *prerollAULength) { + FDK_BITSTREAM bs; + HANDLE_FDK_BITSTREAM hBs; + AAC_DECODER_ERROR ErrorStatus; + + INT auStartAnchor; + UINT independencyFlag; + UINT extPayloadPresentFlag; + UINT useDefaultLengthFlag; + UINT configLength = 0; + UINT preRollPossible = 1; + UINT i; + UCHAR configChanged = 0; + UCHAR config[TP_USAC_MAX_CONFIG_LEN] = {0}; + UCHAR + implicitExplicitCfgDiff = 0; /* in case implicit and explicit config is + equal preroll AU's should be processed + after decoder reset */ + + ErrorStatus = AAC_DEC_OK; + + hBs = transportDec_GetBitstream(self->hInput, 0); + bs = *hBs; + + auStartAnchor = (INT)FDKgetValidBits(hBs); + if (auStartAnchor <= 0) { + ErrorStatus = AAC_DEC_NOT_ENOUGH_BITS; + goto bail; + } + + /* Independency flag */ + FDKreadBit(hBs); + + /* Payload present flag of extension ID_EXT_ELE_AUDIOPREROLL must be one */ + extPayloadPresentFlag = FDKreadBits(hBs, 1); + if (!extPayloadPresentFlag) { + preRollPossible = 0; + } + + /* Default length flag of extension ID_EXT_ELE_AUDIOPREROLL must be zero */ + useDefaultLengthFlag = FDKreadBits(hBs, 1); + if (useDefaultLengthFlag) { + preRollPossible = 0; + } + + if (preRollPossible) { /* extPayloadPresentFlag && !useDefaultLengthFlag */ + /* Read overall ext payload length, useDefaultLengthFlag must be zero. */ + escapedValue(hBs, 8, 16, 0); + + /* Read RSVD60 Config size */ + configLength = escapedValue(hBs, 4, 4, 8); + + /* Avoid decoding pre roll frames if there was no config change and no + * config is included in the pre roll ext payload. */ + } + + /* If pre roll not possible then exit. */ + if (preRollPossible == 0) { + /* Sanity check: if flushing is switched on, preRollPossible must be 1 */ + if (self->flushStatus != AACDEC_FLUSH_OFF) { + /* Mismatch of current payload and flushing status */ + self->flushStatus = AACDEC_FLUSH_OFF; + ErrorStatus = AAC_DEC_PARSE_ERROR; + } + goto bail; + } + + if (self->flags[0] & AC_USAC) { + if (configLength > 0) { + /* DASH IPF USAC Config Change: Read new config and compare with current + * config. Apply reconfiguration if config's are different. */ + for (i = 0; i < configLength; i++) { + config[i] = FDKreadBits(hBs, 8); + } + TRANSPORTDEC_ERROR terr; + terr = transportDec_InBandConfig(self->hInput, config, configLength, + self->buildUpStatus, &configChanged, 0, + &implicitExplicitCfgDiff); + if (terr != TRANSPORTDEC_OK) { + ErrorStatus = AAC_DEC_PARSE_ERROR; + goto bail; + } + } + } + + /* For the first frame buildUpStatus is not set and no flushing is performed + * but preroll AU's should processed. */ + /* For USAC there is no idle state. */ + if ((self->streamInfo.numChannels == 0) && !implicitExplicitCfgDiff && + (self->flags[0] & AC_USAC)) { + self->buildUpStatus = AACDEC_USAC_BUILD_UP_ON; + /* sanity check: if buildUp status on -> flushing must be off */ + if (self->flushStatus != AACDEC_FLUSH_OFF) { + self->flushStatus = AACDEC_FLUSH_OFF; + ErrorStatus = AAC_DEC_PARSE_ERROR; + goto bail; + } + } + + if (self->flags[0] & AC_USAC) { + /* We are interested in preroll AUs if an explicit or an implicit config + * change is signalized in other words if the build up status is set. */ + if (self->buildUpStatus == AACDEC_USAC_BUILD_UP_ON) { + self->applyCrossfade |= FDKreadBit(hBs); + FDKreadBit(hBs); /* reserved */ + /* Read num preroll AU's */ + *numPrerollAU = escapedValue(hBs, 2, 4, 0); + /* check limits for USAC */ + if (*numPrerollAU > AACDEC_MAX_NUM_PREROLL_AU_USAC) { + *numPrerollAU = 0; + ErrorStatus = AAC_DEC_PARSE_ERROR; + goto bail; + } + } + } + + for (i = 0; i < *numPrerollAU; i++) { + /* For every AU get length and offset in the bitstream */ + prerollAULength[i] = escapedValue(hBs, 16, 16, 0); + if (prerollAULength[i] > 0) { + prerollAUOffset[i] = auStartAnchor - (INT)FDKgetValidBits(hBs); + independencyFlag = FDKreadBit(hBs); + if (i == 0 && !independencyFlag) { + *numPrerollAU = 0; + ErrorStatus = AAC_DEC_PARSE_ERROR; + goto bail; + } + FDKpushFor(hBs, prerollAULength[i] * 8 - 1); + self->prerollAULength[i] = (prerollAULength[i] * 8) + prerollAUOffset[i]; + } else { + *numPrerollAU = 0; + ErrorStatus = AAC_DEC_PARSE_ERROR; /* Something is wrong */ + goto bail; + } + } + +bail: + + *hBs = bs; + + return ErrorStatus; +} + +/*! + \brief Parse Extension Payload + + \self Handle of AAC decoder + \count Pointer to bit counter. + \previous_element ID of previous element (required by some extension payloads) + + \return Error code +*/ +static AAC_DECODER_ERROR CAacDecoder_ExtPayloadParse( + HANDLE_AACDECODER self, HANDLE_FDK_BITSTREAM hBs, int *count, + MP4_ELEMENT_ID previous_element, int elIndex, int fIsFillElement) { + AAC_DECODER_ERROR error = AAC_DEC_OK; + EXT_PAYLOAD_TYPE extension_type; + int bytes = (*count) >> 3; + int crcFlag = 0; + + if (*count < 4) { + return AAC_DEC_PARSE_ERROR; + } else if ((INT)FDKgetValidBits(hBs) < *count) { + return AAC_DEC_DECODE_FRAME_ERROR; + } + + extension_type = + (EXT_PAYLOAD_TYPE)FDKreadBits(hBs, 4); /* bs_extension_type */ + *count -= 4; + + /* For ELD, the SBR signaling is explicit and parsed in + aacDecoder_ParseExplicitMpsAndSbr(), therefore skip SBR if implicit + present. */ + if ((self->flags[0] & AC_ELD) && ((extension_type == EXT_SBR_DATA_CRC) || + (extension_type == EXT_SBR_DATA))) { + extension_type = EXT_FIL; /* skip sbr data */ + } + + switch (extension_type) { + case EXT_DYNAMIC_RANGE: { + INT readBits = + aacDecoder_drcMarkPayload(self->hDrcInfo, hBs, MPEG_DRC_EXT_DATA); + + if (readBits > *count) { /* Read too much. Something went wrong! */ + error = AAC_DEC_PARSE_ERROR; + } + *count -= readBits; + } break; + case EXT_UNI_DRC: { + DRC_DEC_ERROR drcErr = DRC_DEC_OK; + DRC_DEC_CODEC_MODE drcDecCodecMode = DRC_DEC_CODEC_MODE_UNDEFINED; + INT nBitsRemaining = FDKgetValidBits(hBs); + INT readBits; + + switch (self->streamInfo.aot) { + case AOT_AAC_LC: + case AOT_SBR: + case AOT_PS: + drcDecCodecMode = DRC_DEC_MPEG_4_AAC; + break; + default: + error = AAC_DEC_PARSE_ERROR; + goto bail; + } + + drcErr = FDK_drcDec_SetCodecMode(self->hUniDrcDecoder, drcDecCodecMode); + if (drcErr) { + error = AAC_DEC_PARSE_ERROR; + goto bail; + } + + drcErr = FDK_drcDec_ReadUniDrc(self->hUniDrcDecoder, hBs); + if (drcErr) { + error = AAC_DEC_PARSE_ERROR; + goto bail; + } + readBits = (INT)nBitsRemaining - (INT)FDKgetValidBits(hBs); + if (readBits > *count) { /* Read too much. Something went wrong! */ + error = AAC_DEC_PARSE_ERROR; + } + *count -= readBits; + /* Skip any trailing bits */ + FDKpushFor(hBs, *count); + *count = 0; + } break; + case EXT_LDSAC_DATA: + case EXT_SAC_DATA: + /* Read MPEG Surround Extension payload */ + { + int err, mpsSampleRate, mpsFrameSize; + + if (self->flags[0] & AC_PS_PRESENT) { + error = AAC_DEC_PARSE_ERROR; + goto bail; + } + + /* Handle SBR dual rate case */ + if (self->streamInfo.extSamplingRate != 0) { + mpsSampleRate = self->streamInfo.extSamplingRate; + mpsFrameSize = self->streamInfo.aacSamplesPerFrame * + (self->streamInfo.extSamplingRate / + self->streamInfo.aacSampleRate); + } else { + mpsSampleRate = self->streamInfo.aacSampleRate; + mpsFrameSize = self->streamInfo.aacSamplesPerFrame; + } + /* 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_ELD))) { + self->mpsEnableCurr = self->mpsEnableUser; + } + if (self->mpsEnableCurr) { + if (!self->qmfDomain.globalConf.qmfDomainExplicitConfig) { + /* 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; + } + } + } + err = mpegSurroundDecoder_Parse( + (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, hBs, count, + self->streamInfo.aot, mpsSampleRate, mpsFrameSize, + self->flags[0] & AC_INDEP); + if (err == MPS_OK) { + self->flags[0] |= AC_MPS_PRESENT; + } else { + error = AAC_DEC_PARSE_ERROR; + } + } + /* Skip any trailing bytes */ + FDKpushFor(hBs, *count); + *count = 0; + } + break; + + case EXT_SBR_DATA_CRC: + crcFlag = 1; + FDK_FALLTHROUGH; + case EXT_SBR_DATA: + if (IS_CHANNEL_ELEMENT(previous_element)) { + SBR_ERROR sbrError; + UCHAR configMode = 0; + UCHAR configChanged = 0; + + CAacDecoder_SyncQmfMode(self); + + configMode |= AC_CM_ALLOC_MEM; + + sbrError = sbrDecoder_InitElement( + self->hSbrDecoder, self->streamInfo.aacSampleRate, + self->streamInfo.extSamplingRate, + self->streamInfo.aacSamplesPerFrame, self->streamInfo.aot, + previous_element, elIndex, + 2, /* Signalize that harmonicSBR shall be ignored in the config + change detection */ + 0, configMode, &configChanged, self->downscaleFactor); + + if (sbrError == SBRDEC_OK) { + sbrError = sbrDecoder_Parse(self->hSbrDecoder, hBs, + self->pDrmBsBuffer, self->drmBsBufferSize, + count, *count, crcFlag, previous_element, + elIndex, self->flags[0], self->elFlags); + /* Enable SBR for implicit SBR signalling but only if no severe error + * happend. */ + if ((sbrError == SBRDEC_OK) || (sbrError == SBRDEC_PARSE_ERROR)) { + self->sbrEnabled = 1; + } + } else { + /* Do not try to apply SBR because initializing the element failed. */ + self->sbrEnabled = 0; + } + /* Citation from ISO/IEC 14496-3 chapter 4.5.2.1.5.2 + Fill elements containing an extension_payload() with an extension_type + of EXT_SBR_DATA or EXT_SBR_DATA_CRC shall not contain any other + extension_payload of any other extension_type. + */ + if (fIsFillElement) { + FDKpushBiDirectional(hBs, *count); + *count = 0; + } else { + /* If this is not a fill element with a known length, we are screwed + * and further parsing makes no sense. */ + if (sbrError != SBRDEC_OK) { + self->frameOK = 0; + } + } + } else { + error = AAC_DEC_PARSE_ERROR; + } + break; + + case EXT_FILL_DATA: { + int temp; + + temp = FDKreadBits(hBs, 4); + bytes--; + if (temp != 0) { + error = AAC_DEC_PARSE_ERROR; + break; + } + while (bytes > 0) { + temp = FDKreadBits(hBs, 8); + bytes--; + if (temp != 0xa5) { + error = AAC_DEC_PARSE_ERROR; + break; + } + } + *count = bytes << 3; + } break; + + case EXT_DATA_ELEMENT: { + int dataElementVersion; + + dataElementVersion = FDKreadBits(hBs, 4); + *count -= 4; + if (dataElementVersion == 0) /* ANC_DATA */ + { + int temp, dataElementLength = 0; + do { + temp = FDKreadBits(hBs, 8); + *count -= 8; + dataElementLength += temp; + } while (temp == 255); + + CAacDecoder_AncDataParse(&self->ancData, hBs, dataElementLength); + *count -= (dataElementLength << 3); + } else { + /* align = 0 */ + error = AAC_DEC_PARSE_ERROR; + goto bail; + } + } break; + + case EXT_DATA_LENGTH: + if (!fIsFillElement /* Makes no sens to have an additional length in a + fill ... */ + && + (self->flags[0] & + AC_ER)) /* ... element because this extension payload type was ... */ + { /* ... created to circumvent the missing length in ER-Syntax. */ + int bitCnt, len = FDKreadBits(hBs, 4); + *count -= 4; + + if (len == 15) { + int add_len = FDKreadBits(hBs, 8); + *count -= 8; + len += add_len; + + if (add_len == 255) { + len += FDKreadBits(hBs, 16); + *count -= 16; + } + } + len <<= 3; + bitCnt = len; + + if ((EXT_PAYLOAD_TYPE)FDKreadBits(hBs, 4) == EXT_DATA_LENGTH) { + /* Check NOTE 2: The extension_payload() included here must + not have extension_type == EXT_DATA_LENGTH. */ + error = AAC_DEC_PARSE_ERROR; + goto bail; + } else { + /* rewind and call myself again. */ + FDKpushBack(hBs, 4); + + error = CAacDecoder_ExtPayloadParse( + self, hBs, &bitCnt, previous_element, elIndex, + 1); /* Treat same as fill element */ + + *count -= len - bitCnt; + } + /* Note: the fall through in case the if statement above is not taken is + * intentional. */ + break; + } + FDK_FALLTHROUGH; + + case EXT_FIL: + + default: + /* align = 4 */ + FDKpushFor(hBs, *count); + *count = 0; + break; + } + +bail: + if ((error != AAC_DEC_OK) && + fIsFillElement) { /* Skip the remaining extension bytes */ + FDKpushBiDirectional(hBs, *count); + *count = 0; + /* Patch error code because decoding can go on. */ + error = AAC_DEC_OK; + /* Be sure that parsing errors have been stored. */ + } + return error; +} + +static AAC_DECODER_ERROR aacDecoder_ParseExplicitMpsAndSbr( + HANDLE_AACDECODER self, HANDLE_FDK_BITSTREAM bs, + const MP4_ELEMENT_ID previous_element, const int previous_element_index, + const int element_index, const int el_cnt[]) { + AAC_DECODER_ERROR ErrorStatus = AAC_DEC_OK; + INT bitCnt = 0; + + /* get the remaining bits of this frame */ + bitCnt = transportDec_GetAuBitsRemaining(self->hInput, 0); + + if ((self->flags[0] & AC_SBR_PRESENT) && + (self->flags[0] & (AC_USAC | AC_RSVD50 | AC_ELD | AC_DRM))) { + SBR_ERROR err = SBRDEC_OK; + int chElIdx, numChElements = el_cnt[ID_SCE] + el_cnt[ID_CPE] + + el_cnt[ID_LFE] + el_cnt[ID_USAC_SCE] + + el_cnt[ID_USAC_CPE] + el_cnt[ID_USAC_LFE]; + INT bitCntTmp = bitCnt; + + if (self->flags[0] & AC_USAC) { + chElIdx = numChElements - 1; + } else { + chElIdx = 0; /* ELD case */ + } + + for (; chElIdx < numChElements; chElIdx += 1) { + MP4_ELEMENT_ID sbrType; + SBR_ERROR errTmp; + if (self->flags[0] & (AC_USAC)) { + FDK_ASSERT((self->elements[element_index] == ID_USAC_SCE) || + (self->elements[element_index] == ID_USAC_CPE)); + sbrType = IS_STEREO_SBR(self->elements[element_index], + self->usacStereoConfigIndex[element_index]) + ? ID_CPE + : ID_SCE; + } else + sbrType = self->elements[chElIdx]; + errTmp = sbrDecoder_Parse(self->hSbrDecoder, bs, self->pDrmBsBuffer, + self->drmBsBufferSize, &bitCnt, -1, + self->flags[0] & AC_SBRCRC, sbrType, chElIdx, + self->flags[0], self->elFlags); + if (errTmp != SBRDEC_OK) { + err = errTmp; + bitCntTmp = bitCnt; + bitCnt = 0; + } + } + switch (err) { + case SBRDEC_PARSE_ERROR: + /* Can not go on parsing because we do not + know the length of the SBR extension data. */ + FDKpushFor(bs, bitCntTmp); + bitCnt = 0; + break; + case SBRDEC_OK: + self->sbrEnabled = 1; + break; + default: + self->frameOK = 0; + break; + } + } + + if ((bitCnt > 0) && (self->flags[0] & (AC_USAC | AC_RSVD50))) { + if ((self->flags[0] & AC_MPS_PRESENT) || + (self->elFlags[element_index] & AC_EL_USAC_MPS212)) { + int err; + + err = mpegSurroundDecoder_ParseNoHeader( + (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, bs, &bitCnt, + self->flags[0] & AC_INDEP); + if (err != MPS_OK) { + self->frameOK = 0; + ErrorStatus = AAC_DEC_PARSE_ERROR; + } + } + } + + if (self->flags[0] & AC_DRM) { + if ((bitCnt = (INT)FDKgetValidBits(bs)) != 0) { + FDKpushBiDirectional(bs, bitCnt); + } + } + + if (!(self->flags[0] & (AC_USAC | AC_RSVD50 | AC_DRM))) { + while (bitCnt > 7) { + ErrorStatus = CAacDecoder_ExtPayloadParse( + self, bs, &bitCnt, previous_element, previous_element_index, 0); + if (ErrorStatus != AAC_DEC_OK) { + self->frameOK = 0; + ErrorStatus = AAC_DEC_PARSE_ERROR; + break; + } + } + } + return ErrorStatus; +} + +/* Stream Configuration and Information. + + This class holds configuration and information data for a stream to be + decoded. It provides the calling application as well as the decoder with + substantial information, e.g. profile, sampling rate, number of channels + found in the bitstream etc. +*/ +static void CStreamInfoInit(CStreamInfo *pStreamInfo) { + pStreamInfo->aacSampleRate = 0; + pStreamInfo->profile = -1; + pStreamInfo->aot = AOT_NONE; + + pStreamInfo->channelConfig = -1; + pStreamInfo->bitRate = 0; + pStreamInfo->aacSamplesPerFrame = 0; + + pStreamInfo->extAot = AOT_NONE; + pStreamInfo->extSamplingRate = 0; + + pStreamInfo->flags = 0; + + pStreamInfo->epConfig = -1; /* default: no ER */ + + pStreamInfo->numChannels = 0; + pStreamInfo->sampleRate = 0; + pStreamInfo->frameSize = 0; + + pStreamInfo->outputDelay = 0; + + /* DRC */ + pStreamInfo->drcProgRefLev = + -1; /* set program reference level to not indicated */ + pStreamInfo->drcPresMode = -1; /* default: presentation mode not indicated */ +} + +/*! + \brief Initialization of AacDecoderChannelInfo + + The function initializes the pointers to AacDecoderChannelInfo for each + channel, set the start values for window shape and window sequence of + overlap&add to zero, set the overlap buffer to zero and initializes the + pointers to the window coefficients. \param bsFormat is the format of the AAC + bitstream + + \return AACDECODER instance +*/ +LINKSPEC_CPP HANDLE_AACDECODER CAacDecoder_Open( + TRANSPORT_TYPE bsFormat) /*!< bitstream format (adif,adts,loas,...). */ +{ + HANDLE_AACDECODER self; + + self = GetAacDecoder(); + if (self == NULL) { + goto bail; + } + + FDK_QmfDomain_ClearRequested(&self->qmfDomain.globalConf); + + /* Assign channel mapping info arrays (doing so removes dependency of settings + * header in API header). */ + self->streamInfo.pChannelIndices = self->channelIndices; + self->streamInfo.pChannelType = self->channelType; + self->downscaleFactor = 1; + self->downscaleFactorInBS = 1; + + /* initialize anc data */ + CAacDecoder_AncDataInit(&self->ancData, NULL, 0); + + /* initialize stream info */ + CStreamInfoInit(&self->streamInfo); + + /* initialize progam config */ + CProgramConfig_Init(&self->pce); + + /* initialize error concealment common data */ + CConcealment_InitCommonData(&self->concealCommonData); + self->concealMethodUser = ConcealMethodNone; /* undefined -> auto mode */ + + self->hDrcInfo = GetDrcInfo(); + if (self->hDrcInfo == NULL) { + goto bail; + } + /* Init common DRC structure */ + aacDecoder_drcInit(self->hDrcInfo); + /* Set default frame delay */ + aacDecoder_drcSetParam(self->hDrcInfo, DRC_BS_DELAY, + CConcealment_GetDelay(&self->concealCommonData)); + + self->workBufferCore2 = GetWorkBufferCore2(); + if (self->workBufferCore2 == NULL) goto bail; + + /* When RSVD60 is active use dedicated memory for core decoding */ + self->pTimeData2 = GetWorkBufferCore5(); + self->timeData2Size = GetRequiredMemWorkBufferCore5(); + if (self->pTimeData2 == NULL) { + goto bail; + } + + return self; + +bail: + CAacDecoder_Close(self); + + return NULL; +} + +/* Revert CAacDecoder_Init() */ +static void CAacDecoder_DeInit(HANDLE_AACDECODER self, + const int subStreamIndex) { + int ch; + int aacChannelOffset = 0, aacChannels = (8); + int numElements = (((8)) + (8)), elementOffset = 0; + + if (self == NULL) return; + + { + self->ascChannels[0] = 0; + self->elements[0] = ID_END; + } + + for (ch = aacChannelOffset; ch < aacChannelOffset + aacChannels; ch++) { + if (self->pAacDecoderChannelInfo[ch] != NULL) { + if (self->pAacDecoderChannelInfo[ch]->pComStaticData != NULL) { + if (self->pAacDecoderChannelInfo[ch] + ->pComStaticData->pWorkBufferCore1 != NULL) { + if (ch == aacChannelOffset) { + FreeWorkBufferCore1(&self->pAacDecoderChannelInfo[ch] + ->pComStaticData->pWorkBufferCore1); + } + } + if (self->pAacDecoderChannelInfo[ch] + ->pComStaticData->cplxPredictionData != NULL) { + FreeCplxPredictionData(&self->pAacDecoderChannelInfo[ch] + ->pComStaticData->cplxPredictionData); + } + /* Avoid double free of linked pComStaticData in case of CPE by settings + * pointer to NULL. */ + if (ch < (8) - 1) { + if ((self->pAacDecoderChannelInfo[ch + 1] != NULL) && + (self->pAacDecoderChannelInfo[ch + 1]->pComStaticData == + self->pAacDecoderChannelInfo[ch]->pComStaticData)) { + self->pAacDecoderChannelInfo[ch + 1]->pComStaticData = NULL; + } + } + FDKfree(self->pAacDecoderChannelInfo[ch]->pComStaticData); + self->pAacDecoderChannelInfo[ch]->pComStaticData = NULL; + } + if (self->pAacDecoderChannelInfo[ch]->pComData != NULL) { + /* Avoid double free of linked pComData in case of CPE by settings + * pointer to NULL. */ + if (ch < (8) - 1) { + if ((self->pAacDecoderChannelInfo[ch + 1] != NULL) && + (self->pAacDecoderChannelInfo[ch + 1]->pComData == + self->pAacDecoderChannelInfo[ch]->pComData)) { + self->pAacDecoderChannelInfo[ch + 1]->pComData = NULL; + } + } + if (ch == aacChannelOffset) { + FreeWorkBufferCore6( + (SCHAR **)&self->pAacDecoderChannelInfo[ch]->pComData); + } else { + FDKafree(self->pAacDecoderChannelInfo[ch]->pComData); + } + self->pAacDecoderChannelInfo[ch]->pComData = NULL; + } + } + if (self->pAacDecoderStaticChannelInfo[ch] != NULL) { + if (self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer != NULL) { + FreeOverlapBuffer( + &self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer); + } + if (self->pAacDecoderStaticChannelInfo[ch]->hArCo != NULL) { + CArco_Destroy(self->pAacDecoderStaticChannelInfo[ch]->hArCo); + } + FreeAacDecoderStaticChannelInfo(&self->pAacDecoderStaticChannelInfo[ch]); + } + if (self->pAacDecoderChannelInfo[ch] != NULL) { + FreeAacDecoderChannelInfo(&self->pAacDecoderChannelInfo[ch]); + } + } + + { + int el; + for (el = elementOffset; el < elementOffset + numElements; el++) { + if (self->cpeStaticData[el] != NULL) { + FreeCpePersistentData(&self->cpeStaticData[el]); + } + } + } + + FDK_Delay_Destroy(&self->usacResidualDelay); + + self->aacChannels = 0; + self->streamInfo.aacSampleRate = 0; + self->streamInfo.sampleRate = 0; + /* This samplerate value is checked for configuration change, not the others + * above. */ + self->samplingRateInfo[subStreamIndex].samplingRate = 0; +} + +/*! + * \brief CAacDecoder_CtrlCFGChange Set config change parameters. + * + * \param self [i] handle to AACDECODER structure + * \param flushStatus [i] flush status: on|off + * \param flushCnt [i] flush frame counter + * \param buildUpStatus [i] build up status: on|off + * \param buildUpCnt [i] build up frame counter + * + * \return error + */ +LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_CtrlCFGChange(HANDLE_AACDECODER self, + UCHAR flushStatus, + SCHAR flushCnt, + UCHAR buildUpStatus, + SCHAR buildUpCnt) { + AAC_DECODER_ERROR err = AAC_DEC_OK; + + self->flushStatus = flushStatus; + self->flushCnt = flushCnt; + self->buildUpStatus = buildUpStatus; + self->buildUpCnt = buildUpCnt; + + return (err); +} + +/*! + * \brief CAacDecoder_FreeMem Free config dependent AAC memory. + * + * \param self [i] handle to AACDECODER structure + * + * \return error + */ +LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_FreeMem(HANDLE_AACDECODER self, + const int subStreamIndex) { + AAC_DECODER_ERROR err = AAC_DEC_OK; + + CAacDecoder_DeInit(self, subStreamIndex); + + return (err); +} + +/* Destroy aac decoder */ +LINKSPEC_CPP void CAacDecoder_Close(HANDLE_AACDECODER self) { + if (self == NULL) return; + + CAacDecoder_DeInit(self, 0); + + { + int ch; + for (ch = 0; ch < (8); ch++) { + if (self->pTimeDataFlush[ch] != NULL) { + FreeTimeDataFlush(&self->pTimeDataFlush[ch]); + } + } + } + + if (self->hDrcInfo) { + FreeDrcInfo(&self->hDrcInfo); + } + + /* Free WorkBufferCore2 */ + if (self->workBufferCore2 != NULL) { + FreeWorkBufferCore2(&self->workBufferCore2); + } + if (self->pTimeData2 != NULL) { + FreeWorkBufferCore5(&self->pTimeData2); + } + + FDK_QmfDomain_Close(&self->qmfDomain); + + FreeAacDecoder(&self); +} + +/*! + \brief Initialization of decoder instance + + The function initializes the decoder. + + \return error status: 0 for success, <>0 for unsupported configurations +*/ +LINKSPEC_CPP AAC_DECODER_ERROR +CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, + UCHAR configMode, UCHAR *configChanged) { + AAC_DECODER_ERROR err = AAC_DEC_OK; + INT ascChannels, ascChanged = 0; + AACDEC_RENDER_MODE initRenderMode = AACDEC_RENDER_INVALID; + SCHAR usacStereoConfigIndex = -1; + int usacResidualDelayCompSamples = 0; + int elementOffset, aacChannelsOffset, aacChannelsOffsetIdx; + const int streamIndex = 0; + INT flushChannels = 0; + + if (!self) return AAC_DEC_INVALID_HANDLE; + + UCHAR downscaleFactor = self->downscaleFactor; + UCHAR downscaleFactorInBS = self->downscaleFactorInBS; + + // set profile and check for supported aot + // leave profile on default (=-1) for all other supported MPEG-4 aot's except + // aot=2 (=AAC-LC) + switch (asc->m_aot) { + case AOT_AAC_LC: + self->streamInfo.profile = 1; + FDK_FALLTHROUGH; + case AOT_ER_AAC_SCAL: + if (asc->m_sc.m_gaSpecificConfig.m_layer > 0) { + /* aac_scalable_extension_element() currently not supported. */ + return AAC_DEC_UNSUPPORTED_FORMAT; + } + FDK_FALLTHROUGH; + case AOT_SBR: + case AOT_PS: + case AOT_ER_AAC_LC: + case AOT_ER_AAC_LD: + case AOT_DRM_AAC: + case AOT_DRM_SURROUND: + initRenderMode = AACDEC_RENDER_IMDCT; + break; + case AOT_ER_AAC_ELD: + initRenderMode = AACDEC_RENDER_ELDFB; + break; + case AOT_USAC: + initRenderMode = AACDEC_RENDER_IMDCT; + break; + default: + return AAC_DEC_UNSUPPORTED_AOT; + } + + if (CProgramConfig_IsValid(&self->pce) && (asc->m_channelConfiguration > 0)) { + /* Compare the stored (old) PCE with a default PCE created from the (new) + channel_config (on a temporal buffer) to find out wheter we can keep it + (and its metadata) or not. */ + int pceCmpResult; + C_ALLOC_SCRATCH_START(tmpPce, CProgramConfig, 1); + + CProgramConfig_GetDefault(tmpPce, asc->m_channelConfiguration); + pceCmpResult = CProgramConfig_Compare(&self->pce, tmpPce); + if ((pceCmpResult < 0) /* Reset if PCEs are completely different ... */ + || + (pceCmpResult > 1)) { /* ... or have a different layout. */ + CProgramConfig_Init(&self->pce); + } /* Otherwise keep the PCE (and its metadata). */ + C_ALLOC_SCRATCH_END(tmpPce, CProgramConfig, 1); + } else { + CProgramConfig_Init(&self->pce); + } + + /* set channels */ + switch (asc->m_channelConfiguration) { + case 0: + switch (asc->m_aot) { + case AOT_USAC: + self->chMapIndex = 0; + ascChannels = asc->m_sc.m_usacConfig.m_nUsacChannels; + break; + default: + /* get channels from program config (ASC) */ + if (CProgramConfig_IsValid(&asc->m_progrConfigElement)) { + ascChannels = asc->m_progrConfigElement.NumChannels; + if (ascChannels > 0) { + int el_tmp; + /* valid number of channels -> copy program config element (PCE) + * from ASC */ + FDKmemcpy(&self->pce, &asc->m_progrConfigElement, + sizeof(CProgramConfig)); + /* Built element table */ + el_tmp = CProgramConfig_GetElementTable( + &asc->m_progrConfigElement, self->elements, (((8)) + (8)), + &self->chMapIndex); + for (; el_tmp < (3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1); + el_tmp++) { + self->elements[el_tmp] = ID_NONE; + } + } else { + return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; + } + } else { + self->chMapIndex = 0; + return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; + } + break; + } + break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + ascChannels = asc->m_channelConfiguration; + break; + case 11: + ascChannels = 7; + break; + case 7: + case 12: + case 14: + ascChannels = 8; + break; + default: + return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; + } + + if (asc->m_aot == AOT_USAC) { + flushChannels = fMin(ascChannels, (8)); + INT numChannel; + pcmDmx_GetParam(self->hPcmUtils, MIN_NUMBER_OF_OUTPUT_CHANNELS, + &numChannel); + flushChannels = fMin(fMax(numChannel, flushChannels), (8)); + } + + if (IS_USAC(asc->m_aot)) { + for (int el = 0; el < (INT)asc->m_sc.m_usacConfig.m_usacNumElements; el++) { + /* fix number of core channels aka ascChannels for stereoConfigIndex = 1 + * cases */ + if (asc->m_sc.m_usacConfig.element[el].m_stereoConfigIndex == 1) { + ascChannels--; /* stereoConfigIndex == 1 stereo cases do actually + contain only a mono core channel. */ + } else if (asc->m_sc.m_usacConfig.element[el].m_stereoConfigIndex == 2) { + /* In this case it is necessary to follow up the DMX signal delay caused + by HBE also with the residual signal (2nd core channel). The SBR + overlap delay is not regarded here, this is handled by the MPS212 + implementation. + */ + if (asc->m_sc.m_usacConfig.element[el].m_harmonicSBR) { + usacResidualDelayCompSamples += asc->m_samplesPerFrame; + } + if (asc->m_sc.m_usacConfig.m_coreSbrFrameLengthIndex == 4) { + usacResidualDelayCompSamples += + 6 * 16; /* difference between 12 SBR + overlap slots from SBR and 6 + slots delayed in MPS212 */ + } + } + } + } + + aacChannelsOffset = 0; + aacChannelsOffsetIdx = 0; + elementOffset = 0; + if ((ascChannels <= 0) || (ascChannels > (8)) || + (asc->m_channelConfiguration > AACDEC_MAX_CH_CONF)) { + return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; + } + + /* Set syntax flags */ + self->flags[streamIndex] = 0; + { FDKmemclear(self->elFlags, sizeof(self->elFlags)); } + + if ((asc->m_channelConfiguration > 0) || IS_USAC(asc->m_aot)) { + if (IS_USAC(asc->m_aot)) { + /* copy pointer to usac config + (this is preliminary since there's an ongoing discussion about storing + the config-part of the bitstream rather than the complete decoded + configuration) */ + self->pUsacConfig[streamIndex] = &asc->m_sc.m_usacConfig; + + /* copy list of elements */ + if (self->pUsacConfig[streamIndex]->m_usacNumElements > + (3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1)) { + goto bail; + } + + if (self->numUsacElements[streamIndex] != + asc->m_sc.m_usacConfig.m_usacNumElements) { + ascChanged = 1; + } + + if (configMode & AC_CM_ALLOC_MEM) { + self->numUsacElements[streamIndex] = + asc->m_sc.m_usacConfig.m_usacNumElements; + } + + self->mpsEnableCurr = 0; + for (int _el = 0; + _el < (int)self->pUsacConfig[streamIndex]->m_usacNumElements; + _el++) { + int el = _el + elementOffset; + if (self->elements[el] != + self->pUsacConfig[streamIndex]->element[_el].usacElementType) { + ascChanged = 1; + } + if (self->usacStereoConfigIndex[el] != + asc->m_sc.m_usacConfig.element[_el].m_stereoConfigIndex) { + ascChanged = 1; + } + if (configMode & AC_CM_ALLOC_MEM) { + self->elements[el] = + self->pUsacConfig[streamIndex]->element[_el].usacElementType; + /* for Unified Stereo Coding */ + self->usacStereoConfigIndex[el] = + asc->m_sc.m_usacConfig.element[_el].m_stereoConfigIndex; + if (self->elements[el] == ID_USAC_CPE) { + self->mpsEnableCurr |= self->usacStereoConfigIndex[el] ? 1 : 0; + } + } + + self->elFlags[el] |= + (asc->m_sc.m_usacConfig.element[_el].m_noiseFilling) + ? AC_EL_USAC_NOISE + : 0; + self->elFlags[el] |= + (asc->m_sc.m_usacConfig.element[_el].m_stereoConfigIndex > 0) + ? AC_EL_USAC_MPS212 + : 0; + self->elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].m_interTes) + ? AC_EL_USAC_ITES + : 0; + self->elFlags[el] |= + (asc->m_sc.m_usacConfig.element[_el].m_pvc) ? AC_EL_USAC_PVC : 0; + self->elFlags[el] |= + (asc->m_sc.m_usacConfig.element[_el].usacElementType == ID_USAC_LFE) + ? AC_EL_USAC_LFE + : 0; + self->elFlags[el] |= + (asc->m_sc.m_usacConfig.element[_el].usacElementType == ID_USAC_LFE) + ? AC_EL_LFE + : 0; + if ((asc->m_sc.m_usacConfig.element[_el].usacElementType == + ID_USAC_CPE) && + ((self->usacStereoConfigIndex[el] == 0))) { + self->elFlags[el] |= AC_EL_USAC_CP_POSSIBLE; + } + } + + self->hasAudioPreRoll = 0; + if (self->pUsacConfig[streamIndex]->m_usacNumElements) { + self->hasAudioPreRoll = asc->m_sc.m_usacConfig.element[0] + .extElement.usacExtElementHasAudioPreRoll; + } + if (configMode & AC_CM_ALLOC_MEM) { + self->elements[elementOffset + + self->pUsacConfig[streamIndex]->m_usacNumElements] = + ID_END; + } + } else { + /* Initialize constant mappings for channel config 1-7 */ + int i; + for (i = 0; i < AACDEC_CH_ELEMENTS_TAB_SIZE; i++) { + self->elements[i] = elementsTab[asc->m_channelConfiguration - 1][i]; + } + for (; i < (3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1); i++) { + self->elements[i] = ID_NONE; + } + } + + { + int ch; + + for (ch = 0; ch < ascChannels; ch++) { + self->chMapping[ch] = ch; + } + for (; ch < (8); ch++) { + self->chMapping[ch] = 255; + } + } + + self->chMapIndex = asc->m_channelConfiguration; + } else { + if (CProgramConfig_IsValid(&asc->m_progrConfigElement)) { + /* Set matrix mixdown infos if available from PCE. */ + pcmDmx_SetMatrixMixdownFromPce( + self->hPcmUtils, asc->m_progrConfigElement.MatrixMixdownIndexPresent, + asc->m_progrConfigElement.MatrixMixdownIndex, + asc->m_progrConfigElement.PseudoSurroundEnable); + } + } + + self->streamInfo.channelConfig = asc->m_channelConfiguration; + + if (self->streamInfo.aot != asc->m_aot) { + if (configMode & AC_CM_ALLOC_MEM) { + self->streamInfo.aot = asc->m_aot; + } + ascChanged = 1; + } + + if (asc->m_aot == AOT_ER_AAC_ELD && + asc->m_sc.m_eldSpecificConfig.m_downscaledSamplingFrequency != 0) { + if (self->samplingRateInfo[0].samplingRate != + asc->m_sc.m_eldSpecificConfig.m_downscaledSamplingFrequency || + self->samplingRateInfo[0].samplingRate * self->downscaleFactor != + asc->m_samplingFrequency) { + /* get downscaledSamplingFrequency from ESC and compute the downscale + * factor */ + downscaleFactorInBS = + asc->m_samplingFrequency / + asc->m_sc.m_eldSpecificConfig.m_downscaledSamplingFrequency; + if (downscaleFactorInBS == 1 || downscaleFactorInBS == 2 || + downscaleFactorInBS == 3 || downscaleFactorInBS == 4) { + downscaleFactor = downscaleFactorInBS; + } + } + } else { + downscaleFactorInBS = 1; + downscaleFactor = 1; + } + + if (self->downscaleFactorInBS != downscaleFactorInBS) { + if (configMode & AC_CM_ALLOC_MEM) { + self->downscaleFactorInBS = downscaleFactorInBS; + self->downscaleFactor = downscaleFactor; + } + ascChanged = 1; + } + + if ((INT)asc->m_samplesPerFrame % downscaleFactor != 0) { + return AAC_DEC_UNSUPPORTED_SAMPLINGRATE; /* frameSize/dsf must be an integer + number */ + } + + self->streamInfo.bitRate = 0; + + if (asc->m_aot == AOT_ER_AAC_ELD) { + if (self->useLdQmfTimeAlign != + asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign) { + ascChanged = 1; + } + if (configMode & AC_CM_ALLOC_MEM) { + self->useLdQmfTimeAlign = + asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign; + } + } + + self->streamInfo.extAot = asc->m_extensionAudioObjectType; + if (self->streamInfo.extSamplingRate != + (INT)asc->m_extensionSamplingFrequency) { + ascChanged = 1; + } + if (configMode & AC_CM_ALLOC_MEM) { + self->streamInfo.extSamplingRate = asc->m_extensionSamplingFrequency; + } + self->flags[streamIndex] |= (asc->m_sbrPresentFlag) ? AC_SBR_PRESENT : 0; + self->flags[streamIndex] |= (asc->m_psPresentFlag) ? AC_PS_PRESENT : 0; + if (asc->m_sbrPresentFlag) { + self->sbrEnabled = 1; + self->sbrEnabledPrev = 1; + } else { + self->sbrEnabled = 0; + self->sbrEnabledPrev = 0; + } + if (self->sbrEnabled && asc->m_extensionSamplingFrequency) { + if (downscaleFactor != 1 && (downscaleFactor)&1) { + return AAC_DEC_UNSUPPORTED_SAMPLINGRATE; /* SBR needs an even downscale + factor */ + } + if (configMode & AC_CM_ALLOC_MEM) { + self->streamInfo.extSamplingRate = + self->streamInfo.extSamplingRate / self->downscaleFactor; + } + } + + /* --------- vcb11 ------------ */ + self->flags[streamIndex] |= (asc->m_vcb11Flag) ? AC_ER_VCB11 : 0; + + /* ---------- rvlc ------------ */ + self->flags[streamIndex] |= (asc->m_rvlcFlag) ? AC_ER_RVLC : 0; + + /* ----------- hcr ------------ */ + self->flags[streamIndex] |= (asc->m_hcrFlag) ? AC_ER_HCR : 0; + + if (asc->m_aot == AOT_ER_AAC_ELD) { + self->mpsEnableCurr = 0; + self->flags[streamIndex] |= AC_ELD; + self->flags[streamIndex] |= + (asc->m_sbrPresentFlag) + ? AC_SBR_PRESENT + : 0; /* Need to set the SBR flag for backward-compatibility + reasons. Even if SBR is not supported. */ + self->flags[streamIndex] |= + (asc->m_sc.m_eldSpecificConfig.m_sbrCrcFlag) ? AC_SBRCRC : 0; + self->flags[streamIndex] |= + (asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign) ? AC_MPS_PRESENT + : 0; + if (self->mpsApplicable) { + self->mpsEnableCurr = asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign; + } + } + self->flags[streamIndex] |= (asc->m_aot == AOT_ER_AAC_LD) ? AC_LD : 0; + self->flags[streamIndex] |= (asc->m_epConfig >= 0) ? AC_ER : 0; + + if (asc->m_aot == AOT_USAC) { + self->flags[streamIndex] |= AC_USAC; + self->flags[streamIndex] |= + (asc->m_sc.m_usacConfig.element[0].m_stereoConfigIndex > 0) + ? AC_MPS_PRESENT + : 0; + } + if (asc->m_aot == AOT_DRM_AAC) { + self->flags[streamIndex] |= AC_DRM | AC_SBRCRC | AC_SCALABLE; + } + if (asc->m_aot == AOT_DRM_SURROUND) { + self->flags[streamIndex] |= + AC_DRM | AC_SBRCRC | AC_SCALABLE | AC_MPS_PRESENT; + FDK_ASSERT(!asc->m_psPresentFlag); + } + if ((asc->m_aot == AOT_AAC_SCAL) || (asc->m_aot == AOT_ER_AAC_SCAL)) { + self->flags[streamIndex] |= AC_SCALABLE; + } + + if ((asc->m_epConfig >= 0) && (asc->m_channelConfiguration <= 0)) { + /* we have to know the number of channels otherwise no decoding is possible + */ + return AAC_DEC_UNSUPPORTED_ER_FORMAT; + } + + self->streamInfo.epConfig = asc->m_epConfig; + /* self->hInput->asc.m_epConfig = asc->m_epConfig; */ + + if (asc->m_epConfig > 1) return AAC_DEC_UNSUPPORTED_ER_FORMAT; + + /* Check if samplerate changed. */ + if ((self->samplingRateInfo[streamIndex].samplingRate != + asc->m_samplingFrequency) || + (self->streamInfo.aacSamplesPerFrame != + (INT)asc->m_samplesPerFrame / downscaleFactor)) { + AAC_DECODER_ERROR error; + + ascChanged = 1; + + if (configMode & AC_CM_ALLOC_MEM) { + /* Update samplerate info. */ + error = getSamplingRateInfo( + &self->samplingRateInfo[streamIndex], asc->m_samplesPerFrame, + asc->m_samplingFrequencyIndex, asc->m_samplingFrequency); + if (error != AAC_DEC_OK) { + return error; + } + self->streamInfo.aacSampleRate = + self->samplingRateInfo[0].samplingRate / self->downscaleFactor; + self->streamInfo.aacSamplesPerFrame = + asc->m_samplesPerFrame / self->downscaleFactor; + } + } + + /* Check if amount of channels has changed. */ + if (self->ascChannels[streamIndex] != ascChannels) { + ascChanged = 1; + } + + /* detect config change */ + if (configMode & AC_CM_DET_CFG_CHANGE) { + if (ascChanged != 0) { + *configChanged = 1; + } + return err; + } + + /* set AC_USAC_SCFGI3 globally if any usac element uses */ + switch (asc->m_aot) { + case AOT_USAC: + if (self->sbrEnabled) { + for (int _el = 0; + _el < (int)self->pUsacConfig[streamIndex]->m_usacNumElements; + _el++) { + int el = elementOffset + _el; + if (IS_USAC_CHANNEL_ELEMENT(self->elements[el])) { + if (usacStereoConfigIndex < 0) { + usacStereoConfigIndex = self->usacStereoConfigIndex[el]; + } else { + if ((usacStereoConfigIndex != self->usacStereoConfigIndex[el]) || + (self->usacStereoConfigIndex[el] > 0)) { + goto bail; + } + } + } + } + + if (usacStereoConfigIndex < 0) { + goto bail; + } + + if (usacStereoConfigIndex == 3) { + self->flags[streamIndex] |= AC_USAC_SCFGI3; + } + } + break; + default: + break; + } + + if (*configChanged) { + /* Set up QMF domain for AOTs with explicit signalling of SBR and or MPS. + This is to be able to play out the first frame alway with the correct + frame size and sampling rate even in case of concealment. + */ + switch (asc->m_aot) { + case AOT_USAC: + if (self->sbrEnabled) { + const UCHAR map_sbrRatio_2_nAnaBands[] = {16, 24, 32}; + + FDK_ASSERT(asc->m_sc.m_usacConfig.m_sbrRatioIndex > 0); + FDK_ASSERT(streamIndex == 0); + + self->qmfDomain.globalConf.nInputChannels_requested = ascChannels; + self->qmfDomain.globalConf.nOutputChannels_requested = + (usacStereoConfigIndex == 1) ? 2 : ascChannels; + self->qmfDomain.globalConf.flags_requested = 0; + self->qmfDomain.globalConf.nBandsAnalysis_requested = + map_sbrRatio_2_nAnaBands[asc->m_sc.m_usacConfig.m_sbrRatioIndex - + 1]; + self->qmfDomain.globalConf.nBandsSynthesis_requested = 64; + self->qmfDomain.globalConf.nQmfTimeSlots_requested = + (asc->m_sc.m_usacConfig.m_sbrRatioIndex == 1) ? 64 : 32; + self->qmfDomain.globalConf.nQmfOvTimeSlots_requested = + (asc->m_sc.m_usacConfig.m_sbrRatioIndex == 1) ? 12 : 6; + self->qmfDomain.globalConf.nQmfProcBands_requested = 64; + self->qmfDomain.globalConf.nQmfProcChannels_requested = 1; + self->qmfDomain.globalConf.parkChannel = + (usacStereoConfigIndex == 3) ? 1 : 0; + self->qmfDomain.globalConf.parkChannel_requested = + (usacStereoConfigIndex == 3) ? 1 : 0; + self->qmfDomain.globalConf.qmfDomainExplicitConfig = 1; + } + break; + case AOT_ER_AAC_ELD: + if (self->mpsEnableCurr && + asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign) { + SAC_INPUT_CONFIG sac_interface = + (self->sbrEnabled && self->hSbrDecoder) ? SAC_INTERFACE_QMF + : SAC_INTERFACE_TIME; + mpegSurroundDecoder_ConfigureQmfDomain( + (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, sac_interface, + (UINT)self->streamInfo.aacSampleRate, asc->m_aot); + self->qmfDomain.globalConf.qmfDomainExplicitConfig = 1; + } + break; + default: + self->qmfDomain.globalConf.qmfDomainExplicitConfig = + 0; /* qmfDomain is initialized by SBR and MPS init functions if + required */ + break; + } + + /* Allocate all memory structures for each channel */ + { + int ch = aacChannelsOffset; + for (int _ch = 0; _ch < ascChannels; _ch++) { + if (ch >= (8)) { + goto bail; + } + self->pAacDecoderChannelInfo[ch] = GetAacDecoderChannelInfo(ch); + /* This is temporary until the DynamicData is split into two or more + regions! The memory could be reused after completed core decoding. */ + if (self->pAacDecoderChannelInfo[ch] == NULL) { + goto bail; + } + ch++; + } + + int chIdx = aacChannelsOffsetIdx; + ch = aacChannelsOffset; + int _numElements; + _numElements = (((8)) + (8)); + if (self->flags[streamIndex] & (AC_RSV603DA | AC_USAC)) { + _numElements = (int)asc->m_sc.m_usacConfig.m_usacNumElements; + } + for (int _el = 0; _el < _numElements; _el++) { + int el_channels = 0; + int el = elementOffset + _el; + + if (self->flags[streamIndex] & + (AC_ER | AC_LD | AC_ELD | AC_RSV603DA | AC_USAC | AC_RSVD50)) { + if (ch >= ascChannels) { + break; + } + } + + switch (self->elements[el]) { + case ID_SCE: + case ID_CPE: + case ID_LFE: + case ID_USAC_SCE: + case ID_USAC_CPE: + case ID_USAC_LFE: + + el_channels = CAacDecoder_GetELChannels( + self->elements[el], self->usacStereoConfigIndex[el]); + + { + self->pAacDecoderChannelInfo[ch]->pComStaticData = + (CAacDecoderCommonStaticData *)FDKcalloc( + 1, sizeof(CAacDecoderCommonStaticData)); + if (self->pAacDecoderChannelInfo[ch]->pComStaticData == NULL) { + goto bail; + } + if (ch == aacChannelsOffset) { + self->pAacDecoderChannelInfo[ch]->pComData = + (CAacDecoderCommonData *)GetWorkBufferCore6(); + self->pAacDecoderChannelInfo[ch] + ->pComStaticData->pWorkBufferCore1 = GetWorkBufferCore1(); + } else { + self->pAacDecoderChannelInfo[ch]->pComData = + (CAacDecoderCommonData *)FDKaalloc( + sizeof(CAacDecoderCommonData), ALIGNMENT_DEFAULT); + self->pAacDecoderChannelInfo[ch] + ->pComStaticData->pWorkBufferCore1 = + self->pAacDecoderChannelInfo[aacChannelsOffset] + ->pComStaticData->pWorkBufferCore1; + } + if ((self->pAacDecoderChannelInfo[ch]->pComData == NULL) || + (self->pAacDecoderChannelInfo[ch] + ->pComStaticData->pWorkBufferCore1 == NULL)) { + goto bail; + } + self->pAacDecoderChannelInfo[ch]->pDynData = + &(self->pAacDecoderChannelInfo[ch] + ->pComData->pAacDecoderDynamicData[0]); + self->pAacDecoderChannelInfo[ch]->pSpectralCoefficient = + (SPECTRAL_PTR)&self->workBufferCore2[ch * 1024]; + + if (el_channels == 2) { + if (ch >= (8) - 1) { + return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; + } + self->pAacDecoderChannelInfo[ch + 1]->pComData = + self->pAacDecoderChannelInfo[ch]->pComData; + self->pAacDecoderChannelInfo[ch + 1]->pComStaticData = + self->pAacDecoderChannelInfo[ch]->pComStaticData; + self->pAacDecoderChannelInfo[ch + 1] + ->pComStaticData->pWorkBufferCore1 = + self->pAacDecoderChannelInfo[ch] + ->pComStaticData->pWorkBufferCore1; + self->pAacDecoderChannelInfo[ch + 1]->pDynData = + &(self->pAacDecoderChannelInfo[ch] + ->pComData->pAacDecoderDynamicData[1]); + self->pAacDecoderChannelInfo[ch + 1]->pSpectralCoefficient = + (SPECTRAL_PTR)&self->workBufferCore2[(ch + 1) * 1024]; + } + + ch += el_channels; + } + chIdx += el_channels; + break; + + default: + break; + } + + if (self->elements[el] == ID_END) { + break; + } + + el++; + } + + chIdx = aacChannelsOffsetIdx; + ch = aacChannelsOffset; + for (int _ch = 0; _ch < ascChannels; _ch++) { + /* Allocate persistent channel memory */ + { + self->pAacDecoderStaticChannelInfo[ch] = + GetAacDecoderStaticChannelInfo(ch); + if (self->pAacDecoderStaticChannelInfo[ch] == NULL) { + goto bail; + } + self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer = + GetOverlapBuffer(ch); /* This area size depends on the AOT */ + if (self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer == NULL) { + goto bail; + } + if (self->flags[streamIndex] & + (AC_USAC | AC_RSVD50 | AC_RSV603DA /*|AC_BSAC*/)) { + self->pAacDecoderStaticChannelInfo[ch]->hArCo = CArco_Create(); + if (self->pAacDecoderStaticChannelInfo[ch]->hArCo == NULL) { + goto bail; + } + } + + if (!(self->flags[streamIndex] & (AC_USAC | AC_RSV603DA))) { + CPns_UpdateNoiseState( + &self->pAacDecoderChannelInfo[ch]->data.aac.PnsData, + &self->pAacDecoderStaticChannelInfo[ch]->pnsCurrentSeed, + self->pAacDecoderChannelInfo[ch]->pComData->pnsRandomSeed); + } + ch++; + } + chIdx++; + } + + if (self->flags[streamIndex] & AC_USAC) { + for (int _ch = 0; _ch < flushChannels; _ch++) { + ch = aacChannelsOffset + _ch; + if (self->pTimeDataFlush[ch] == NULL) { + self->pTimeDataFlush[ch] = GetTimeDataFlush(ch); + if (self->pTimeDataFlush[ch] == NULL) { + goto bail; + } + } + } + } + + if (self->flags[streamIndex] & (AC_USAC | AC_RSV603DA)) { + int complexStereoPredPossible = 0; + ch = aacChannelsOffset; + chIdx = aacChannelsOffsetIdx; + for (int _el2 = 0; _el2 < (int)asc->m_sc.m_usacConfig.m_usacNumElements; + _el2++) { + int el2 = elementOffset + _el2; + int elCh = 0, ch2; + + if ((self->elements[el2] == ID_USAC_CPE) && + !(self->usacStereoConfigIndex[el2] == 1)) { + elCh = 2; + } else if (IS_CHANNEL_ELEMENT(self->elements[el2])) { + elCh = 1; + } + + if (self->elFlags[el2] & AC_EL_USAC_CP_POSSIBLE) { + complexStereoPredPossible = 1; + if (self->cpeStaticData[el2] == NULL) { + self->cpeStaticData[el2] = GetCpePersistentData(); + if (self->cpeStaticData[el2] == NULL) { + goto bail; + } + } + } + + for (ch2 = 0; ch2 < elCh; ch2++) { + /* Hook element specific cpeStaticData into channel specific + * aacDecoderStaticChannelInfo */ + self->pAacDecoderStaticChannelInfo[ch]->pCpeStaticData = + self->cpeStaticData[el2]; + if (self->pAacDecoderStaticChannelInfo[ch]->pCpeStaticData != + NULL) { + self->pAacDecoderStaticChannelInfo[ch] + ->pCpeStaticData->jointStereoPersistentData + .spectralCoeffs[ch2] = + self->pAacDecoderStaticChannelInfo[ch] + ->concealmentInfo.spectralCoefficient; + self->pAacDecoderStaticChannelInfo[ch] + ->pCpeStaticData->jointStereoPersistentData.specScale[ch2] = + self->pAacDecoderStaticChannelInfo[ch] + ->concealmentInfo.specScale; + self->pAacDecoderStaticChannelInfo[ch] + ->pCpeStaticData->jointStereoPersistentData.scratchBuffer = + (FIXP_DBL *)self->pTimeData2; + } + chIdx++; + ch++; + } /* for each channel in current element */ + if (complexStereoPredPossible && (elCh == 2)) { + /* needed once for all channels */ + if (self->pAacDecoderChannelInfo[ch - 1] + ->pComStaticData->cplxPredictionData == NULL) { + self->pAacDecoderChannelInfo[ch - 1] + ->pComStaticData->cplxPredictionData = + GetCplxPredictionData(); + } + if (self->pAacDecoderChannelInfo[ch - 1] + ->pComStaticData->cplxPredictionData == NULL) { + goto bail; + } + } + if (elCh > 0) { + self->pAacDecoderStaticChannelInfo[ch - elCh]->nfRandomSeed = + (ULONG)0x3039; + if (self->elements[el2] == ID_USAC_CPE) { + if (asc->m_sc.m_usacConfig.element[el2].m_stereoConfigIndex != + 1) { + self->pAacDecoderStaticChannelInfo[ch - elCh + 1] + ->nfRandomSeed = (ULONG)0x10932; + } + } + } + } /* for each element */ + } + + if (ascChannels != self->aacChannels) { + /* Make allocated channel count persistent in decoder context. */ + self->aacChannels = aacChannelsOffset + ch; + } + } + + if (usacResidualDelayCompSamples) { + INT delayErr = FDK_Delay_Create(&self->usacResidualDelay, + (USHORT)usacResidualDelayCompSamples, 1); + if (delayErr) { + goto bail; + } + } + + /* Make amount of signalled channels persistent in decoder context. */ + self->ascChannels[streamIndex] = ascChannels; + /* Init the previous channel count values. This is required to avoid a + mismatch of memory accesses in the error concealment module and the + allocated channel structures in this function. */ + self->aacChannelsPrev = 0; + } + + if (self->pAacDecoderChannelInfo[0] != NULL) { + self->pDrmBsBuffer = self->pAacDecoderChannelInfo[0] + ->pComStaticData->pWorkBufferCore1->DrmBsBuffer; + self->drmBsBufferSize = DRM_BS_BUFFER_SIZE; + } + + /* Update structures */ + if (*configChanged) { + /* Things to be done for each channel, which do not involve allocating + memory. Doing these things only on the channels needed for the current + configuration (ascChannels) could lead to memory access violation later + (error concealment). */ + int ch = 0; + int chIdx = 0; + for (int _ch = 0; _ch < self->ascChannels[streamIndex]; _ch++) { + switch (self->streamInfo.aot) { + case AOT_ER_AAC_ELD: + case AOT_ER_AAC_LD: + self->pAacDecoderChannelInfo[ch]->granuleLength = + self->streamInfo.aacSamplesPerFrame; + break; + default: + self->pAacDecoderChannelInfo[ch]->granuleLength = + self->streamInfo.aacSamplesPerFrame / 8; + break; + } + self->pAacDecoderChannelInfo[ch]->renderMode = initRenderMode; + + mdct_init(&self->pAacDecoderStaticChannelInfo[ch]->IMdct, + self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer, + OverlapBufferSize); + + self->pAacDecoderStaticChannelInfo[ch]->last_core_mode = FD_LONG; + self->pAacDecoderStaticChannelInfo[ch]->last_lpd_mode = 255; + + self->pAacDecoderStaticChannelInfo[ch]->last_tcx_pitch = L_DIV; + + /* Reset DRC control data for this channel */ + aacDecoder_drcInitChannelData( + &self->pAacDecoderStaticChannelInfo[ch]->drcData); + + /* Delete mixdown metadata from the past */ + pcmDmx_Reset(self->hPcmUtils, PCMDMX_RESET_BS_DATA); + + /* Reset concealment only if ASC changed. Otherwise it will be done with + any config callback. E.g. every time the LATM SMC is present. */ + CConcealment_InitChannelData( + &self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo, + &self->concealCommonData, initRenderMode, + self->streamInfo.aacSamplesPerFrame); + ch++; + chIdx++; + } + } + + /* Update externally visible copy of flags */ + self->streamInfo.flags = self->flags[0]; + + if (*configChanged) { + int drcDecSampleRate, drcDecFrameSize; + + if (self->streamInfo.extSamplingRate != 0) { + drcDecSampleRate = self->streamInfo.extSamplingRate; + drcDecFrameSize = (self->streamInfo.aacSamplesPerFrame * + self->streamInfo.extSamplingRate) / + self->streamInfo.aacSampleRate; + } else { + drcDecSampleRate = self->streamInfo.aacSampleRate; + drcDecFrameSize = self->streamInfo.aacSamplesPerFrame; + } + + if (FDK_drcDec_Init(self->hUniDrcDecoder, drcDecFrameSize, drcDecSampleRate, + self->aacChannels) != 0) + goto bail; + } + + if (asc->m_aot == AOT_USAC) { + pcmLimiter_SetAttack(self->hLimiter, (5)); + pcmLimiter_SetThreshold(self->hLimiter, FL2FXCONST_DBL(0.89125094f)); + } + + return err; + +bail: + CAacDecoder_DeInit(self, 0); + return AAC_DEC_OUT_OF_MEMORY; +} + +LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( + HANDLE_AACDECODER self, const UINT flags, FIXP_PCM *pTimeData, + const INT timeDataSize, const int timeDataChannelOffset) { + AAC_DECODER_ERROR ErrorStatus = AAC_DEC_OK; + + CProgramConfig *pce; + HANDLE_FDK_BITSTREAM bs = transportDec_GetBitstream(self->hInput, 0); + + MP4_ELEMENT_ID type = ID_NONE; /* Current element type */ + INT aacChannels = 0; /* Channel counter for channels found in the bitstream */ + const int streamIndex = 0; /* index of the current substream */ + + INT auStartAnchor = (INT)FDKgetValidBits( + bs); /* AU start bit buffer position for AU byte alignment */ + + INT checkSampleRate = self->streamInfo.aacSampleRate; + + INT CConceal_TDFading_Applied[(8)] = { + 0}; /* Initialize status of Time Domain fading */ + + if (self->aacChannels <= 0) { + return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; + } + + /* Any supported base layer valid AU will require more than 16 bits. */ + if ((transportDec_GetAuBitsRemaining(self->hInput, 0) < 15) && + (flags & (AACDEC_CONCEAL | AACDEC_FLUSH)) == 0) { + self->frameOK = 0; + ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; + } + + /* Reset Program Config structure */ + pce = &self->pce; + CProgramConfig_Reset(pce); + + CAacDecoder_AncDataReset(&self->ancData); + if (!(flags & (AACDEC_CONCEAL | AACDEC_FLUSH)) && + !(self->flags[0] & (AC_USAC | AC_RSV603DA))) { + int ch; + if (self->streamInfo.channelConfig == 0) { + /* Init Channel/Element mapping table */ + for (ch = 0; ch < (8); ch++) { + self->chMapping[ch] = 255; + } + if (!CProgramConfig_IsValid(pce)) { + int el; + for (el = 0; el < (3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1); + el++) { + self->elements[el] = ID_NONE; + } + } + } + } + + if (self->downscaleFactor > 1 && (self->flags[0] & AC_ELD)) { + self->flags[0] |= AC_ELD_DOWNSCALE; + } else { + self->flags[0] &= ~AC_ELD_DOWNSCALE; + } + /* unsupported dsf (aacSampleRate has not yet been divided by dsf) -> divide + */ + if (self->downscaleFactorInBS > 1 && + (self->flags[0] & AC_ELD_DOWNSCALE) == 0) { + checkSampleRate = + self->streamInfo.aacSampleRate / self->downscaleFactorInBS; + } + + /* Check sampling frequency */ + if (self->streamInfo.aacSampleRate <= 0) { + /* Instance maybe uninitialized! */ + return AAC_DEC_UNSUPPORTED_SAMPLINGRATE; + } + switch (checkSampleRate) { + case 96000: + case 88200: + case 64000: + case 16000: + case 12000: + case 11025: + case 8000: + case 7350: + case 48000: + case 44100: + case 32000: + case 24000: + case 22050: + break; + default: + if (!(self->flags[0] & (AC_USAC | AC_RSVD50 | AC_RSV603DA))) { + return AAC_DEC_UNSUPPORTED_SAMPLINGRATE; + } + break; + } + + if (flags & AACDEC_CLRHIST) { + if (!(self->flags[0] & AC_USAC)) { + int ch; + /* Clear history */ + for (ch = 0; ch < self->aacChannels; ch++) { + /* Reset concealment */ + CConcealment_InitChannelData( + &self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo, + &self->concealCommonData, + self->pAacDecoderChannelInfo[0]->renderMode, + self->streamInfo.aacSamplesPerFrame); + /* Clear overlap-add buffers to avoid clicks. */ + FDKmemclear(self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer, + OverlapBufferSize * sizeof(FIXP_DBL)); + } + if (self->streamInfo.channelConfig > 0) { + /* Declare the possibly adopted old PCE (with outdated metadata) + * invalid. */ + CProgramConfig_Init(pce); + } + } + } + + int pceRead = 0; /* Flag indicating a PCE in the current raw_data_block() */ + + INT hdaacDecoded = 0; + MP4_ELEMENT_ID previous_element = + ID_END; /* Last element ID (required for extension payload mapping */ + UCHAR previous_element_index = 0; /* Canonical index of last element */ + int element_count = + 0; /* Element counter for elements found in the bitstream */ + int channel_element_count = 0; /* Channel element counter */ + MP4_ELEMENT_ID + channel_elements[(3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + + 1)]; /* Channel elements in bit stream order. */ + int el_cnt[ID_LAST] = {0}; /* element counter ( robustness ) */ + int element_count_prev_streams = + 0; /* Element count of all previous sub streams. */ + + while ((type != ID_END) && (!(flags & (AACDEC_CONCEAL | AACDEC_FLUSH))) && + self->frameOK) { + int el_channels; + + if (!(self->flags[0] & + (AC_USAC | AC_RSVD50 | AC_RSV603DA | AC_ELD | AC_SCALABLE | AC_ER))) + type = (MP4_ELEMENT_ID)FDKreadBits(bs, 3); + else { + if (element_count >= (3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1)) { + self->frameOK = 0; + ErrorStatus = AAC_DEC_PARSE_ERROR; + break; + } + type = self->elements[element_count]; + } + + if ((self->flags[streamIndex] & (AC_USAC | AC_RSVD50) && + element_count == 0) || + (self->flags[streamIndex] & AC_RSV603DA)) { + self->flags[streamIndex] &= ~AC_INDEP; + + if (FDKreadBit(bs)) { + self->flags[streamIndex] |= AC_INDEP; + } + + int ch = aacChannels; + for (int chIdx = aacChannels; chIdx < self->ascChannels[streamIndex]; + chIdx++) { + { + /* Robustness check */ + if (ch >= self->aacChannels) { + return AAC_DEC_UNKNOWN; + } + + /* if last frame was broken and this frame is no independent frame, + * correct decoding is impossible we need to trigger concealment */ + if ((CConcealment_GetLastFrameOk( + &self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo, + 1) == 0) && + !(self->flags[streamIndex] & AC_INDEP)) { + self->frameOK = 0; + } + ch++; + } + } + } + + if ((INT)FDKgetValidBits(bs) < 0) { + self->frameOK = 0; + } + + switch (type) { + case ID_SCE: + case ID_CPE: + case ID_LFE: + case ID_USAC_SCE: + case ID_USAC_CPE: + case ID_USAC_LFE: + if (element_count >= (3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1)) { + self->frameOK = 0; + ErrorStatus = AAC_DEC_PARSE_ERROR; + break; + } + + el_channels = CAacDecoder_GetELChannels( + type, self->usacStereoConfigIndex[element_count]); + + /* + Consistency check + */ + { + int totalAscChannels = 0; + + for (int i = 0; i < (1 * 1); i++) { + totalAscChannels += self->ascChannels[i]; + } + if ((el_cnt[type] >= (totalAscChannels >> (el_channels - 1))) || + (aacChannels > (totalAscChannels - el_channels))) { + ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; + self->frameOK = 0; + break; + } + } + + if (!(self->flags[streamIndex] & (AC_USAC | AC_RSVD50 | AC_RSV603DA))) { + int ch; + for (ch = 0; ch < el_channels; ch += 1) { + CPns_ResetData(&self->pAacDecoderChannelInfo[aacChannels + ch] + ->data.aac.PnsData, + &self->pAacDecoderChannelInfo[aacChannels + ch] + ->pComData->pnsInterChannelData); + } + } + + if (self->frameOK) { + ErrorStatus = CChannelElement_Read( + bs, &self->pAacDecoderChannelInfo[aacChannels], + &self->pAacDecoderStaticChannelInfo[aacChannels], + self->streamInfo.aot, &self->samplingRateInfo[streamIndex], + self->flags[streamIndex], self->elFlags[element_count], + self->streamInfo.aacSamplesPerFrame, el_channels, + self->streamInfo.epConfig, self->hInput); + if (ErrorStatus != AAC_DEC_OK) { + self->frameOK = 0; + } + } + + if (self->frameOK) { + /* Lookup the element and decode it only if it belongs to the current + * program */ + if (CProgramConfig_LookupElement( + pce, self->streamInfo.channelConfig, + self->pAacDecoderChannelInfo[aacChannels]->ElementInstanceTag, + aacChannels, self->chMapping, self->channelType, + self->channelIndices, (8), &previous_element_index, + self->elements, type)) { + channel_elements[channel_element_count++] = type; + aacChannels += el_channels; + } else { + self->frameOK = 0; + } + /* Create SBR element for SBR for upsampling for LFE elements, + and if SBR was implicitly signaled, because the first frame(s) + may not contain SBR payload (broken encoder, bit errors). */ + if (self->frameOK && + ((self->flags[streamIndex] & AC_SBR_PRESENT) || + (self->sbrEnabled == 1)) && + !(self->flags[streamIndex] & + AC_USAC) /* Is done during explicit config set up */ + ) { + SBR_ERROR sbrError; + UCHAR configMode = 0; + UCHAR configChanged = 0; + configMode |= AC_CM_ALLOC_MEM; + + sbrError = sbrDecoder_InitElement( + self->hSbrDecoder, self->streamInfo.aacSampleRate, + self->streamInfo.extSamplingRate, + self->streamInfo.aacSamplesPerFrame, self->streamInfo.aot, type, + previous_element_index, 2, /* Signalize that harmonicSBR shall + be ignored in the config change + detection */ + 0, configMode, &configChanged, self->downscaleFactor); + if (sbrError != SBRDEC_OK) { + /* Do not try to apply SBR because initializing the element + * failed. */ + self->sbrEnabled = 0; + } + } + } + + el_cnt[type]++; + if (self->frameOK && (self->flags[streamIndex] & AC_USAC) && + (type == ID_USAC_CPE || type == ID_USAC_SCE)) { + ErrorStatus = aacDecoder_ParseExplicitMpsAndSbr( + self, bs, previous_element, previous_element_index, element_count, + el_cnt); + if (ErrorStatus != AAC_DEC_OK) { + self->frameOK = 0; + } + } + break; + + case ID_CCE: + /* + Consistency check + */ + if (el_cnt[type] > self->ascChannels[streamIndex]) { + ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; + self->frameOK = 0; + break; + } + + if (self->frameOK) { + CAacDecoderCommonData commonData; + CAacDecoderCommonStaticData commonStaticData; + CWorkBufferCore1 workBufferCore1; + commonStaticData.pWorkBufferCore1 = &workBufferCore1; + /* memory for spectral lines temporal on scratch */ + C_AALLOC_SCRATCH_START(mdctSpec, FIXP_DBL, 1024); + + /* create dummy channel for CCE parsing on stack */ + CAacDecoderChannelInfo tmpAacDecoderChannelInfo, + *pTmpAacDecoderChannelInfo; + + FDKmemclear(mdctSpec, 1024 * sizeof(FIXP_DBL)); + + tmpAacDecoderChannelInfo.pDynData = commonData.pAacDecoderDynamicData; + tmpAacDecoderChannelInfo.pComData = &commonData; + tmpAacDecoderChannelInfo.pComStaticData = &commonStaticData; + tmpAacDecoderChannelInfo.pSpectralCoefficient = + (SPECTRAL_PTR)mdctSpec; + /* Assume AAC-LC */ + tmpAacDecoderChannelInfo.granuleLength = + self->streamInfo.aacSamplesPerFrame / 8; + /* Reset PNS data. */ + CPns_ResetData( + &tmpAacDecoderChannelInfo.data.aac.PnsData, + &tmpAacDecoderChannelInfo.pComData->pnsInterChannelData); + pTmpAacDecoderChannelInfo = &tmpAacDecoderChannelInfo; + /* do CCE parsing */ + ErrorStatus = CChannelElement_Read( + bs, &pTmpAacDecoderChannelInfo, NULL, self->streamInfo.aot, + &self->samplingRateInfo[streamIndex], self->flags[streamIndex], + AC_EL_GA_CCE, self->streamInfo.aacSamplesPerFrame, 1, + self->streamInfo.epConfig, self->hInput); + + C_AALLOC_SCRATCH_END(mdctSpec, FIXP_DBL, 1024); + + if (ErrorStatus) { + self->frameOK = 0; + } + + if (self->frameOK) { + /* Lookup the element and decode it only if it belongs to the + * current program */ + if (CProgramConfig_LookupElement( + pce, self->streamInfo.channelConfig, + pTmpAacDecoderChannelInfo->ElementInstanceTag, 0, + self->chMapping, self->channelType, self->channelIndices, + (8), &previous_element_index, self->elements, type)) { + /* decoding of CCE not supported */ + } else { + self->frameOK = 0; + } + } + } + el_cnt[type]++; + break; + + case ID_DSE: { + UCHAR element_instance_tag; + + CDataStreamElement_Read(self, bs, &element_instance_tag, auStartAnchor); + + if (!CProgramConfig_LookupElement( + pce, self->streamInfo.channelConfig, element_instance_tag, 0, + self->chMapping, self->channelType, self->channelIndices, (8), + &previous_element_index, self->elements, type)) { + /* most likely an error in bitstream occured */ + // self->frameOK = 0; + } + } break; + + case ID_PCE: { + int result = CProgramConfigElement_Read(bs, self->hInput, pce, + self->streamInfo.channelConfig, + auStartAnchor); + if (result < 0) { + /* Something went wrong */ + ErrorStatus = AAC_DEC_PARSE_ERROR; + self->frameOK = 0; + } else if (result > 1) { + /* Built element table */ + int elIdx = CProgramConfig_GetElementTable( + pce, self->elements, (((8)) + (8)), &self->chMapIndex); + /* Reset the remaining tabs */ + for (; elIdx < (3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1); + elIdx++) { + self->elements[elIdx] = ID_NONE; + } + /* Make new number of channel persistent */ + self->ascChannels[streamIndex] = pce->NumChannels; + /* If PCE is not first element conceal this frame to avoid + * inconsistencies */ + if (element_count != 0) { + self->frameOK = 0; + } + } + pceRead = (result >= 0) ? 1 : 0; + } break; + + case ID_FIL: { + int bitCnt = FDKreadBits(bs, 4); /* bs_count */ + + if (bitCnt == 15) { + int esc_count = FDKreadBits(bs, 8); /* bs_esc_count */ + bitCnt = esc_count + 14; + } + + /* Convert to bits */ + bitCnt <<= 3; + + while (bitCnt > 0) { + ErrorStatus = CAacDecoder_ExtPayloadParse( + self, bs, &bitCnt, previous_element, previous_element_index, 1); + if (ErrorStatus != AAC_DEC_OK) { + self->frameOK = 0; + break; + } + } + } break; + + case ID_EXT: + if (element_count >= (3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1)) { + self->frameOK = 0; + ErrorStatus = AAC_DEC_PARSE_ERROR; + break; + } + + ErrorStatus = aacDecoder_ParseExplicitMpsAndSbr( + self, bs, previous_element, previous_element_index, element_count, + el_cnt); + break; + + case ID_USAC_EXT: { + if ((element_count - element_count_prev_streams) >= + TP_USAC_MAX_ELEMENTS) { + self->frameOK = 0; + ErrorStatus = AAC_DEC_PARSE_ERROR; + break; + } + /* parse extension element payload + q.v. rsv603daExtElement() ISO/IEC DIS 23008-3 Table 30 + or UsacExElement() ISO/IEC FDIS 23003-3:2011(E) Table 21 + */ + int usacExtElementPayloadLength; + /* int usacExtElementStart, usacExtElementStop; */ + + if (FDKreadBit(bs)) { /* usacExtElementPresent */ + if (FDKreadBit(bs)) { /* usacExtElementUseDefaultLength */ + usacExtElementPayloadLength = + self->pUsacConfig[streamIndex] + ->element[element_count - element_count_prev_streams] + .extElement.usacExtElementDefaultLength; + } else { + usacExtElementPayloadLength = FDKreadBits(bs, 8); + if (usacExtElementPayloadLength == (UINT)(1 << 8) - 1) { + UINT valueAdd = FDKreadBits(bs, 16); + usacExtElementPayloadLength += (INT)valueAdd - 2; + } + } + if (usacExtElementPayloadLength > 0) { + int usacExtBitPos; + + if (self->pUsacConfig[streamIndex] + ->element[element_count - element_count_prev_streams] + .extElement.usacExtElementPayloadFrag) { + /* usacExtElementStart = */ FDKreadBit(bs); + /* usacExtElementStop = */ FDKreadBit(bs); + } else { + /* usacExtElementStart = 1; */ + /* usacExtElementStop = 1; */ + } + + usacExtBitPos = (INT)FDKgetValidBits(bs); + + USAC_EXT_ELEMENT_TYPE usacExtElementType = + self->pUsacConfig[streamIndex] + ->element[element_count - element_count_prev_streams] + .extElement.usacExtElementType; + + switch (usacExtElementType) { + case ID_EXT_ELE_UNI_DRC: /* uniDrcGain() */ + if (streamIndex == 0) { + int drcErr; + + drcErr = FDK_drcDec_ReadUniDrcGain(self->hUniDrcDecoder, bs); + if (drcErr != 0) { + ErrorStatus = AAC_DEC_PARSE_ERROR; + } + } + break; + + default: + break; + } + + /* Skip any remaining bits of extension payload */ + usacExtBitPos = (usacExtElementPayloadLength * 8) - + (usacExtBitPos - (INT)FDKgetValidBits(bs)); + if (usacExtBitPos < 0) { + self->frameOK = 0; + ErrorStatus = AAC_DEC_PARSE_ERROR; + } + FDKpushBiDirectional(bs, usacExtBitPos); + } + } + } break; + case ID_END: + case ID_USAC_END: + break; + + default: + ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; + self->frameOK = 0; + break; + } + + previous_element = type; + element_count++; + + } /* while ( (type != ID_END) ... ) */ + + if (!(flags & (AACDEC_CONCEAL | AACDEC_FLUSH))) { + /* float decoder checks if bitsLeft is in range 0-7; only prerollAUs are + * byteAligned with respect to the first bit */ + /* Byte alignment with respect to the first bit of the raw_data_block(). */ + if (!(self->flags[streamIndex] & (AC_RSVD50 | AC_USAC)) || + (self->prerollAULength[self->accessUnit]) /* indicates preroll */ + ) { + FDKbyteAlign(bs, auStartAnchor); + } + + /* Check if all bits of the raw_data_block() have been read. */ + if (transportDec_GetAuBitsTotal(self->hInput, 0) > 0) { + INT unreadBits = transportDec_GetAuBitsRemaining(self->hInput, 0); + /* for pre-roll frames pre-roll length has to be used instead of total AU + * lenght */ + /* unreadBits regarding preroll bounds */ + if (self->prerollAULength[self->accessUnit]) { + unreadBits = unreadBits - transportDec_GetAuBitsTotal(self->hInput, 0) + + (INT)self->prerollAULength[self->accessUnit]; + } + if (((self->flags[streamIndex] & (AC_RSVD50 | AC_USAC)) && + ((unreadBits < 0) || (unreadBits > 7)) && + !(self->prerollAULength[self->accessUnit])) || + ((!(self->flags[streamIndex] & (AC_RSVD50 | AC_USAC)) || + (self->prerollAULength[self->accessUnit])) && + (unreadBits != 0))) { + if ((((unreadBits < 0) || (unreadBits > 7)) && self->frameOK) && + ((transportDec_GetFormat(self->hInput) == TT_DRM) && + (self->flags[streamIndex] & AC_USAC))) { + /* Set frame OK because of fill bits. */ + self->frameOK = 1; + } else { + self->frameOK = 0; + } + + /* Do not overwrite current error */ + if (ErrorStatus == AAC_DEC_OK && self->frameOK == 0) { + ErrorStatus = AAC_DEC_PARSE_ERROR; + } + /* Always put the bitbuffer at the right position after the current + * Access Unit. */ + FDKpushBiDirectional(bs, unreadBits); + } + } + + /* Check the last element. The terminator (ID_END) has to be the last one + * (even if ER syntax is used). */ + if (self->frameOK && type != ID_END) { + /* Do not overwrite current error */ + if (ErrorStatus == AAC_DEC_OK) { + ErrorStatus = AAC_DEC_PARSE_ERROR; + } + self->frameOK = 0; + } + } + + if (!(flags & (AACDEC_CONCEAL | AACDEC_FLUSH)) && self->frameOK) { + channel_elements[channel_element_count++] = ID_END; + } + element_count = 0; + aacChannels = 0; + type = ID_NONE; + previous_element_index = 0; + + while (type != ID_END && + element_count < (3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1)) { + int el_channels; + + if ((flags & (AACDEC_CONCEAL | AACDEC_FLUSH)) || !self->frameOK) { + channel_elements[element_count] = self->elements[element_count]; + if (channel_elements[element_count] == ID_NONE) { + channel_elements[element_count] = ID_END; + } + } + + if (self->flags[streamIndex] & (AC_USAC | AC_RSV603DA | AC_BSAC)) { + type = self->elements[element_count]; + } else { + type = channel_elements[element_count]; + } + + if (!(flags & (AACDEC_CONCEAL | AACDEC_FLUSH)) && self->frameOK) { + switch (type) { + case ID_SCE: + case ID_CPE: + case ID_LFE: + case ID_USAC_SCE: + case ID_USAC_CPE: + case ID_USAC_LFE: + + el_channels = CAacDecoder_GetELChannels( + type, self->usacStereoConfigIndex[element_count]); + + if (!hdaacDecoded) { + if (self->pAacDecoderStaticChannelInfo[aacChannels] + ->pCpeStaticData != NULL) { + self->pAacDecoderStaticChannelInfo[aacChannels] + ->pCpeStaticData->jointStereoPersistentData.scratchBuffer = + (FIXP_DBL *)pTimeData; + } + CChannelElement_Decode( + &self->pAacDecoderChannelInfo[aacChannels], + &self->pAacDecoderStaticChannelInfo[aacChannels], + &self->samplingRateInfo[streamIndex], self->flags[streamIndex], + self->elFlags[element_count], el_channels); + } + aacChannels += el_channels; + break; + case ID_NONE: + type = ID_END; + break; + default: + break; + } + } + element_count++; + } + + /* More AAC channels than specified by the ASC not allowed. */ + if ((aacChannels == 0 || aacChannels > self->aacChannels) && + !(flags & (AACDEC_CONCEAL | AACDEC_FLUSH))) { + /* Do not overwrite current error */ + if (ErrorStatus == AAC_DEC_OK) { + ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; + } + self->frameOK = 0; + aacChannels = 0; + } + + if (!(flags & (AACDEC_CONCEAL | AACDEC_FLUSH))) { + if (TRANSPORTDEC_OK != transportDec_CrcCheck(self->hInput)) { + ErrorStatus = AAC_DEC_CRC_ERROR; + self->frameOK = 0; + } + } + + /* Ensure that in case of concealment a proper error status is set. */ + if ((self->frameOK == 0) && (ErrorStatus == AAC_DEC_OK)) { + ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; + } + + if (self->frameOK && (flags & AACDEC_FLUSH)) { + aacChannels = self->aacChannelsPrev; + /* Because the downmix could be active, its necessary to restore the channel + * type and indices. */ + FDKmemcpy(self->channelType, self->channelTypePrev, + (8) * sizeof(AUDIO_CHANNEL_TYPE)); /* restore */ + FDKmemcpy(self->channelIndices, self->channelIndicesPrev, + (8) * sizeof(UCHAR)); /* restore */ + self->sbrEnabled = self->sbrEnabledPrev; + } else { + /* store or restore the number of channels and the corresponding info */ + if (self->frameOK && !(flags & AACDEC_CONCEAL)) { + self->aacChannelsPrev = aacChannels; /* store */ + FDKmemcpy(self->channelTypePrev, self->channelType, + (8) * sizeof(AUDIO_CHANNEL_TYPE)); /* store */ + FDKmemcpy(self->channelIndicesPrev, self->channelIndices, + (8) * sizeof(UCHAR)); /* store */ + self->sbrEnabledPrev = self->sbrEnabled; + } else { + if (self->aacChannels > 0) { + if ((self->buildUpStatus == AACDEC_RSV60_BUILD_UP_ON) || + (self->buildUpStatus == AACDEC_RSV60_BUILD_UP_ON_IN_BAND) || + (self->buildUpStatus == AACDEC_USAC_BUILD_UP_ON)) { + aacChannels = self->aacChannels; + self->aacChannelsPrev = aacChannels; /* store */ + } else { + aacChannels = self->aacChannelsPrev; /* restore */ + } + FDKmemcpy(self->channelType, self->channelTypePrev, + (8) * sizeof(AUDIO_CHANNEL_TYPE)); /* restore */ + FDKmemcpy(self->channelIndices, self->channelIndicesPrev, + (8) * sizeof(UCHAR)); /* restore */ + self->sbrEnabled = self->sbrEnabledPrev; + } + } + } + + /* Update number of output channels */ + self->streamInfo.aacNumChannels = aacChannels; + + /* Ensure consistency of IS_OUTPUT_VALID() macro. */ + if (aacChannels == 0) { + ErrorStatus = AAC_DEC_UNKNOWN; + } + + if (pceRead == 1 && CProgramConfig_IsValid(pce)) { + /* Set matrix mixdown infos if available from PCE. */ + pcmDmx_SetMatrixMixdownFromPce( + self->hPcmUtils, pce->MatrixMixdownIndexPresent, + pce->MatrixMixdownIndex, pce->PseudoSurroundEnable); + ; + } + + /* If there is no valid data to transfrom into time domain, return. */ + if (!IS_OUTPUT_VALID(ErrorStatus)) { + return ErrorStatus; + } + + /* Setup the output channel mapping. The table below shows the three + * possibilities: # | chCfg | PCE | chMapIndex + * ---+-------+-----+------------------ + * 1 | > 0 | no | chCfg + * 2 | 0 | yes | cChCfg + * 3 | 0 | no | aacChannels || 0 + * ---+-------+-----+--------+------------------ + * Where chCfg is the channel configuration index from ASC and cChCfg is a + * corresponding chCfg derived from a given PCE. The variable aacChannels + * represents the number of channel found during bitstream decoding. Due to + * the structure of the mapping table it can only be used for mapping if its + * value is smaller than 7. Otherwise we use the fallback (0) which is a + * simple pass-through. The possibility #3 should appear only with MPEG-2 + * (ADTS) streams. This is mode is called "implicit channel mapping". + */ + if ((self->streamInfo.channelConfig == 0) && !pce->isValid) { + self->chMapIndex = (aacChannels < 7) ? aacChannels : 0; + } + + /* + Inverse transform + */ + { + int c, cIdx; + int mapped, fCopyChMap = 1; + UCHAR drcChMap[(8)]; + + if ((self->streamInfo.channelConfig == 0) && CProgramConfig_IsValid(pce)) { + /* ISO/IEC 14496-3 says: + If a PCE is present, the exclude_mask bits correspond to the audio + channels in the SCE, CPE, CCE and LFE syntax elements in the order of + their appearance in the PCE. In the case of a CPE, the first + transmitted mask bit corresponds to the first channel in the CPE, the + second transmitted mask bit to the second channel. In the case of a + CCE, a mask bit is transmitted only if the coupling channel is + specified to be an independently switched coupling channel. Thus we + have to convert the internal channel mapping from "canonical" MPEG to + PCE order: */ + UCHAR tmpChMap[(8)]; + if (CProgramConfig_GetPceChMap(pce, tmpChMap, (8)) == 0) { + for (c = 0; c < aacChannels; c += 1) { + drcChMap[c] = + (self->chMapping[c] == 255) ? 255 : tmpChMap[self->chMapping[c]]; + } + fCopyChMap = 0; + } + } + if (fCopyChMap != 0) { + FDKmemcpy(drcChMap, self->chMapping, (8) * sizeof(UCHAR)); + } + + /* Turn on/off DRC modules level normalization in digital domain depending + * on the limiter status. */ + aacDecoder_drcSetParam(self->hDrcInfo, APPLY_NORMALIZATION, + (self->limiterEnableCurr) ? 0 : 1); + + /* deactivate legacy DRC in case uniDrc is active, i.e. uniDrc payload is + * present and one of DRC or Loudness Normalization is switched on */ + aacDecoder_drcSetParam( + self->hDrcInfo, UNIDRC_PRECEDENCE, + FDK_drcDec_GetParam(self->hUniDrcDecoder, DRC_DEC_IS_ACTIVE)); + + /* Extract DRC control data and map it to channels (without bitstream delay) + */ + mapped = aacDecoder_drcProlog( + self->hDrcInfo, bs, self->pAacDecoderStaticChannelInfo, + pce->ElementInstanceTag, drcChMap, aacChannels); + if (mapped > 0) { + /* If at least one DRC thread has been mapped to a channel threre was DRC + * data in the bitstream. */ + self->flags[streamIndex] |= AC_DRC_PRESENT; + } + + /* Create a reverse mapping table */ + UCHAR Reverse_chMapping[((8) * 2)]; + for (c = 0; c < aacChannels; c++) { + int d; + for (d = 0; d < aacChannels - 1; d++) { + if (self->chMapping[d] == c) { + break; + } + } + Reverse_chMapping[c] = d; + } + + int el; + int el_channels; + c = 0; + cIdx = 0; + el_channels = 0; + for (el = 0; el < element_count; el++) { + int frameOk_butConceal = + 0; /* Force frame concealment during mute release active state. */ + int concealApplyReturnCode; + + if (self->flags[streamIndex] & (AC_USAC | AC_RSV603DA | AC_BSAC)) { + type = self->elements[el]; + } else { + type = channel_elements[el]; + } + + { + int nElementChannels; + + nElementChannels = + CAacDecoder_GetELChannels(type, self->usacStereoConfigIndex[el]); + + el_channels += nElementChannels; + + if (nElementChannels == 0) { + continue; + } + } + + int offset; + int elCh = 0; + /* "c" iterates in canonical MPEG channel order */ + for (; cIdx < el_channels; c++, cIdx++, elCh++) { + /* Robustness check */ + if (c >= aacChannels) { + return AAC_DEC_UNKNOWN; + } + + CAacDecoderChannelInfo *pAacDecoderChannelInfo = + self->pAacDecoderChannelInfo[c]; + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo = + self->pAacDecoderStaticChannelInfo[c]; + + /* Setup offset for time buffer traversal. */ + { + pAacDecoderStaticChannelInfo = + self->pAacDecoderStaticChannelInfo[Reverse_chMapping[c]]; + offset = + FDK_chMapDescr_getMapValue( + &self->mapDescr, Reverse_chMapping[cIdx], self->chMapIndex) * + timeDataChannelOffset; + } + + if (flags & AACDEC_FLUSH) { + /* Clear pAacDecoderChannelInfo->pSpectralCoefficient because with + * AACDEC_FLUSH set it contains undefined data. */ + FDKmemclear(pAacDecoderChannelInfo->pSpectralCoefficient, + sizeof(FIXP_DBL) * self->streamInfo.aacSamplesPerFrame); + } + + /* if The ics info is not valid and it will be stored and used in the + * following concealment method, mark the frame as erroneous */ + { + CIcsInfo *pIcsInfo = &pAacDecoderChannelInfo->icsInfo; + CConcealmentInfo *hConcealmentInfo = + &pAacDecoderStaticChannelInfo->concealmentInfo; + const int mute_release_active = + (self->frameOK && !(flags & AACDEC_CONCEAL)) && + ((hConcealmentInfo->concealState >= ConcealState_Mute) && + (hConcealmentInfo->cntValidFrames + 1 <= + hConcealmentInfo->pConcealParams->numMuteReleaseFrames)); + const int icsIsInvalid = (GetScaleFactorBandsTransmitted(pIcsInfo) > + GetScaleFactorBandsTotal(pIcsInfo)); + const int icsInfoUsedinFadeOut = + !(pAacDecoderChannelInfo->renderMode == AACDEC_RENDER_LPD && + pAacDecoderStaticChannelInfo->last_lpd_mode == 0); + if (icsInfoUsedinFadeOut && icsIsInvalid && !mute_release_active) { + self->frameOK = 0; + } + } + + /* + Conceal defective spectral data + */ + { + CAacDecoderChannelInfo **ppAacDecoderChannelInfo = + &pAacDecoderChannelInfo; + CAacDecoderStaticChannelInfo **ppAacDecoderStaticChannelInfo = + &pAacDecoderStaticChannelInfo; + { + concealApplyReturnCode = CConcealment_Apply( + &(*ppAacDecoderStaticChannelInfo)->concealmentInfo, + *ppAacDecoderChannelInfo, *ppAacDecoderStaticChannelInfo, + &self->samplingRateInfo[streamIndex], + self->streamInfo.aacSamplesPerFrame, + pAacDecoderStaticChannelInfo->last_lpd_mode, + (self->frameOK && !(flags & AACDEC_CONCEAL)), + self->flags[streamIndex]); + } + } + if (concealApplyReturnCode == -1) { + frameOk_butConceal = 1; + } + + if (flags & (AACDEC_INTR)) { + /* Reset DRC control data for this channel */ + aacDecoder_drcInitChannelData(&pAacDecoderStaticChannelInfo->drcData); + } + if (flags & (AACDEC_CLRHIST)) { + if (!(self->flags[0] & AC_USAC)) { + /* Reset DRC control data for this channel */ + aacDecoder_drcInitChannelData( + &pAacDecoderStaticChannelInfo->drcData); + } + } + /* The DRC module demands to be called with the gain field holding the + * gain scale. */ + self->extGain[0] = (FIXP_DBL)TDL_GAIN_SCALING; + /* DRC processing */ + aacDecoder_drcApply( + self->hDrcInfo, self->hSbrDecoder, pAacDecoderChannelInfo, + &pAacDecoderStaticChannelInfo->drcData, self->extGain, c, + self->streamInfo.aacSamplesPerFrame, self->sbrEnabled + + ); + + if (timeDataSize < timeDataChannelOffset * self->aacChannels) { + ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL; + break; + } + if (self->flushStatus && (self->flushCnt > 0) && + !(flags & AACDEC_CONCEAL)) { + FDKmemclear(pTimeData + offset, + sizeof(FIXP_PCM) * self->streamInfo.aacSamplesPerFrame); + } else + switch (pAacDecoderChannelInfo->renderMode) { + case AACDEC_RENDER_IMDCT: + + CBlock_FrequencyToTime( + pAacDecoderStaticChannelInfo, pAacDecoderChannelInfo, + pTimeData + offset, self->streamInfo.aacSamplesPerFrame, + (self->frameOK && !(flags & AACDEC_CONCEAL) && + !frameOk_butConceal), + pAacDecoderChannelInfo->pComStaticData->pWorkBufferCore1 + ->mdctOutTemp, + self->elFlags[el], elCh); + + self->extGainDelay = self->streamInfo.aacSamplesPerFrame; + break; + case AACDEC_RENDER_ELDFB: { + CBlock_FrequencyToTimeLowDelay( + pAacDecoderStaticChannelInfo, pAacDecoderChannelInfo, + pTimeData + offset, self->streamInfo.aacSamplesPerFrame); + self->extGainDelay = + (self->streamInfo.aacSamplesPerFrame * 2 - + self->streamInfo.aacSamplesPerFrame / 2 - 1) / + 2; + } break; + case AACDEC_RENDER_LPD: + + CLpd_RenderTimeSignal( + pAacDecoderStaticChannelInfo, pAacDecoderChannelInfo, + pTimeData + offset, self->streamInfo.aacSamplesPerFrame, + &self->samplingRateInfo[streamIndex], + (self->frameOK && !(flags & AACDEC_CONCEAL) && + !frameOk_butConceal), + flags, self->flags[streamIndex]); + + self->extGainDelay = self->streamInfo.aacSamplesPerFrame; + break; + default: + ErrorStatus = AAC_DEC_UNKNOWN; + break; + } + /* TimeDomainFading */ + if (!CConceal_TDFading_Applied[c]) { + CConceal_TDFading_Applied[c] = CConcealment_TDFading( + self->streamInfo.aacSamplesPerFrame, + &self->pAacDecoderStaticChannelInfo[c], pTimeData + offset, 0); + if (c + 1 < (8) && c < aacChannels - 1) { + /* update next TDNoise Seed to avoid muting in case of Parametric + * Stereo */ + self->pAacDecoderStaticChannelInfo[c + 1] + ->concealmentInfo.TDNoiseSeed = + self->pAacDecoderStaticChannelInfo[c] + ->concealmentInfo.TDNoiseSeed; + } + } + } + } + + if (self->flags[streamIndex] & AC_USAC) { + int bsPseudoLr = 0; + mpegSurroundDecoder_IsPseudoLR( + (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, &bsPseudoLr); + /* ISO/IEC 23003-3, 7.11.2.6 Modification of core decoder output (pseudo + * LR) */ + if ((aacChannels == 2) && bsPseudoLr) { + int i, offset2; + const FIXP_SGL invSqrt2 = FL2FXCONST_SGL(0.707106781186547f); + FIXP_PCM *pTD = pTimeData; + + offset2 = timeDataChannelOffset; + + for (i = 0; i < self->streamInfo.aacSamplesPerFrame; i++) { + FIXP_DBL L = FX_PCM2FX_DBL(pTD[0]); + FIXP_DBL R = FX_PCM2FX_DBL(pTD[offset2]); + L = fMult(L, invSqrt2); + R = fMult(R, invSqrt2); +#if (SAMPLE_BITS == 16) + pTD[0] = FX_DBL2FX_PCM(fAddSaturate(L + R, (FIXP_DBL)0x8000)); + pTD[offset2] = FX_DBL2FX_PCM(fAddSaturate(L - R, (FIXP_DBL)0x8000)); +#else + pTD[0] = FX_DBL2FX_PCM(L + R); + pTD[offset2] = FX_DBL2FX_PCM(L - R); +#endif + pTD++; + } + } + } + + /* Extract DRC control data and map it to channels (with bitstream delay) */ + mapped = aacDecoder_drcEpilog( + self->hDrcInfo, bs, self->pAacDecoderStaticChannelInfo, + pce->ElementInstanceTag, drcChMap, aacChannels); + if (mapped > 0) { + /* If at least one DRC thread has been mapped to a channel threre was DRC + * data in the bitstream. */ + self->flags[streamIndex] |= AC_DRC_PRESENT; + } + } + + /* Add additional concealment delay */ + self->streamInfo.outputDelay += + CConcealment_GetDelay(&self->concealCommonData) * + self->streamInfo.aacSamplesPerFrame; + + /* Map DRC data to StreamInfo structure */ + aacDecoder_drcGetInfo(self->hDrcInfo, &self->streamInfo.drcPresMode, + &self->streamInfo.drcProgRefLev); + + /* Reorder channel type information tables. */ + if (!(self->flags[0] & AC_RSV603DA)) { + AUDIO_CHANNEL_TYPE types[(8)]; + UCHAR idx[(8)]; + int c; + int mapValue; + + FDK_ASSERT(sizeof(self->channelType) == sizeof(types)); + FDK_ASSERT(sizeof(self->channelIndices) == sizeof(idx)); + + FDKmemcpy(types, self->channelType, sizeof(types)); + FDKmemcpy(idx, self->channelIndices, sizeof(idx)); + + for (c = 0; c < aacChannels; c++) { + mapValue = + FDK_chMapDescr_getMapValue(&self->mapDescr, c, self->chMapIndex); + self->channelType[mapValue] = types[c]; + self->channelIndices[mapValue] = idx[c]; + } + } + + self->blockNumber++; + + return ErrorStatus; +} + +/*! + \brief returns the streaminfo pointer + + The function hands back a pointer to the streaminfo structure + + \return pointer to the struct +*/ +LINKSPEC_CPP CStreamInfo *CAacDecoder_GetStreamInfo(HANDLE_AACDECODER self) { + if (!self) { + return NULL; + } + return &self->streamInfo; +} -- cgit v1.2.3