aboutsummaryrefslogtreecommitdiffstats
path: root/fdk-aac/libAACdec/src/aacdecoder.cpp
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2019-11-11 11:38:02 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2019-11-11 11:38:02 +0100
commit0e5af65c467b2423a0b857ae3ad98c91acc1e190 (patch)
treed07f69550d8886271e44fe79c4dcfb299cafbd38 /fdk-aac/libAACdec/src/aacdecoder.cpp
parentefe406d9724f959c8bc2a31802559ca6d41fd897 (diff)
downloadODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.gz
ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.bz2
ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.zip
Include patched FDK-AAC in the repository
The initial idea was to get the DAB+ patch into upstream, but since that follows the android source releases, there is no place for a custom DAB+ patch there. So instead of having to maintain a patched fdk-aac that has to have the same .so version as the distribution package on which it is installed, we prefer having a separate fdk-aac-dab library to avoid collision. At that point, there's no reason to keep fdk-aac in a separate repository, as odr-audioenc is the only tool that needs DAB+ encoding support. Including it here simplifies installation, and makes it consistent with toolame-dab, also shipped in this repository. DAB+ decoding support (needed by ODR-SourceCompanion, dablin, etisnoop, welle.io and others) can be done using upstream FDK-AAC.
Diffstat (limited to 'fdk-aac/libAACdec/src/aacdecoder.cpp')
-rw-r--r--fdk-aac/libAACdec/src/aacdecoder.cpp3464
1 files changed, 3464 insertions, 0 deletions
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.
+
+ <h2>1 Bitstream deformatter</h2>
+ 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.
+
+ <h2>2 Actual decoding to retain the time domain output</h2>
+ 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,
+
+ <h3>2.1 Stereo processing for CPE elements</h3>
+ CChannelPairElement_Decode() first calles the joint stereo tools in
+ stereo.cpp when required.
+
+ <h3>2.2 Scaling of spectral data</h3>
+ CBlock_ScaleSpectralData().
+
+ <h3>2.3 Apply additional coding tools</h3>
+ 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.
+
+ <h2>3 Frequency-To-Time conversion</h3>
+ 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;
+}