| /* ----------------------------------------------------------------------------- |
| 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 */ |
| if (channelConfig == 0) { |
| FDKmemcpy(pce, tmpPce, |
| sizeof(CProgramConfig)); /* Store the complete PCE */ |
| pceStatus = 2; /* Decoder needs re-configuration */ |
| } |
| break; |
| 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))) { |
| |