| |
| /* ----------------------------------------------------------------------------------------------------------- |
| Software License for The Fraunhofer FDK AAC Codec Library for Android |
| |
| © Copyright 1995 - 2012 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 |
| ----------------------------------------------------------------------------------------------------------- */ |
| |
| /***************************** MPEG-4 AAC Decoder ************************** |
| |
| 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 "FDK_tools_rom.h" |
| |
| #include "aacdec_pns.h" |
| |
| #include "sbrdecoder.h" |
| |
| |
| |
| |
| #include "aacdec_hcr.h" |
| #include "rvlc.h" |
| |
| |
| #include "tpdec_lib.h" |
| |
| #include "conceal.h" |
| |
| |
| |
| #define CAN_DO_PS(aot) \ |
| ((aot) == AOT_AAC_LC \ |
| || (aot) == AOT_SBR \ |
| || (aot) == AOT_PS \ |
| || (aot) == AOT_ER_BSAC \ |
| || (aot) == AOT_DRM_AAC) |
| |
| #define IS_USAC(aot) \ |
| ((aot) == AOT_USAC \ |
| || (aot) == AOT_RSVD50) |
| |
| #define IS_LOWDELAY(aot) \ |
| ((aot) == AOT_ER_AAC_LD \ |
| || (aot) == AOT_ER_AAC_ELD) |
| |
| void CAacDecoder_SyncQmfMode(HANDLE_AACDECODER self) |
| { |
| |
| /* Assign user requested mode */ |
| self->qmfModeCurr = self->qmfModeUser; |
| |
| if ( self->qmfModeCurr == NOT_DEFINED ) |
| { |
| if ( (IS_LOWDELAY(self->streamInfo.aot) && (self->flags & AC_MPS_PRESENT)) |
| || ( (self->ascChannels == 1) |
| && ( (CAN_DO_PS(self->streamInfo.aot) && !(self->flags & AC_MPS_PRESENT)) |
| || ( IS_USAC(self->streamInfo.aot) && (self->flags & AC_MPS_PRESENT)) ) ) ) |
| { |
| self->qmfModeCurr = MODE_HQ; |
| } else { |
| self->qmfModeCurr = MODE_LP; |
| } |
| } |
| |
| |
| /* 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) && self->aacChannels == 1 && ! (self->flags & AC_MPS_PRESENT))) && self->qmfModeCurr == MODE_HQ ; |
| FDK_ASSERT( ! ( (self->flags & AC_MPS_PRESENT) && self->psPossible ) ); |
| } |
| |
| void CAacDecoder_SignalInterruption(HANDLE_AACDECODER self) |
| { |
| } |
| |
| /*! |
| \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 && 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_FDK_BITSTREAM bs, |
| CAncData *ancData, |
| HANDLE_AAC_DRC hDrcInfo, |
| HANDLE_TRANSPORTDEC pTp, |
| UCHAR *elementInstanceTag, |
| UINT alignmentAnchor ) |
| { |
| AAC_DECODER_ERROR error = AAC_DEC_OK; |
| UINT dataStart; |
| int dataByteAlignFlag, count; |
| |
| int crcReg = transportDec_CrcStartReg(pTp, 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 */ |
| } |
| |
| if (dataByteAlignFlag) { |
| FDKbyteAlign(bs, alignmentAnchor); |
| } |
| |
| dataStart = FDKgetValidBits(bs); |
| |
| error = CAacDecoder_AncDataParse(ancData, bs, count); |
| transportDec_CrcEndReg(pTp, crcReg); |
| |
| { |
| INT readBits, dataBits = count<<3; |
| |
| /* Move to the beginning of the data junk */ |
| FDKpushBack(bs, dataStart-FDKgetValidBits(bs)); |
| |
| /* Read Anc data if available */ |
| readBits = aacDecoder_drcMarkPayload( hDrcInfo, bs, DVB_DRC_ANC_DATA ); |
| |
| if (readBits != dataBits) { |
| /* Move to the end again. */ |
| FDKpushBiDirectional(bs, FDKgetValidBits(bs)-dataStart+dataBits); |
| } |
| } |
| |
| return error; |
| } |
| |
| #ifdef TP_PCE_ENABLE |
| /*! |
| \brief Read Program Config Element |
| |
| \bs Bitstream Handle |
| \count Pointer to program config element. |
| |
| \return Error code |
| */ |
| static AAC_DECODER_ERROR CProgramConfigElement_Read ( |
| HANDLE_FDK_BITSTREAM bs, |
| HANDLE_TRANSPORTDEC pTp, |
| CProgramConfig *pce, |
| UINT channelConfig, |
| UINT alignAnchor ) |
| { |
| AAC_DECODER_ERROR error = AAC_DEC_OK; |
| int crcReg; |
| |
| /* read PCE to temporal buffer first */ |
| C_ALLOC_SCRATCH_START(tmpPce, CProgramConfig, 1); |
| |
| CProgramConfig_Init(tmpPce); |
| CProgramConfig_Reset(tmpPce); |
| |
| crcReg = transportDec_CrcStartReg(pTp, 0); |
| |
| CProgramConfig_Read(tmpPce, bs, alignAnchor); |
| |
| transportDec_CrcEndReg(pTp, crcReg); |
| |
| if ( CProgramConfig_IsValid(tmpPce) |
| && ( (channelConfig == 6 && (tmpPce->NumChannels == 6)) |
| || (channelConfig == 5 && (tmpPce->NumChannels == 5)) |
| || (channelConfig == 0 && (tmpPce->NumChannels == pce->NumChannels)) ) |
| && (tmpPce->NumFrontChannelElements == 2) |
| && (tmpPce->NumSideChannelElements == 0) |
| && (tmpPce->NumBackChannelElements == 1) |
| && (tmpPce->Profile == 1) ) |
| { /* Copy the complete PCE including metadata. */ |
| FDKmemcpy(pce, tmpPce, sizeof(CProgramConfig)); |
| } |
| |
| C_ALLOC_SCRATCH_END(tmpPce, CProgramConfig, 1); |
| |
| return error; |
| } |
| #endif |
| |
| /*! |
| \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; |
| |
| 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_SBR_DATA_CRC: |
| crcFlag = 1; |
| case EXT_SBR_DATA: |
| if (IS_CHANNEL_ELEMENT(previous_element)) { |
| SBR_ERROR sbrError; |
| |
| CAacDecoder_SyncQmfMode(self); |
| |
| sbrError = sbrDecoder_InitElement( |
| self->hSbrDecoder, |
| self->streamInfo.aacSampleRate, |
| self->streamInfo.extSamplingRate, |
| self->streamInfo.aacSamplesPerFrame, |
| self->streamInfo.aot, |
| previous_element, |
| elIndex |
| ); |
| |
| if (sbrError == SBRDEC_OK) { |
| sbrError = sbrDecoder_Parse ( |
| self->hSbrDecoder, |
| hBs, |
| count, |
| *count, |
| crcFlag, |
| previous_element, |
| elIndex, |
| self->flags & AC_INDEP ); |
| /* Enable SBR for implicit SBR signalling. */ |
| if (sbrError == SBRDEC_OK) { |
| 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 an no further parsing makes 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 & 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; |
| } |
| |
| 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; |
| } |
| |
| /* 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 is no ER */ |
| |
| pStreamInfo->numChannels = 0; |
| pStreamInfo->sampleRate = 0; |
| pStreamInfo->frameSize = 0; |
| } |
| |
| /*! |
| \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; |
| } |
| |
| /* 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; |
| |
| /* set default output mode */ |
| self->outputInterleaved = 1; /* interleaved */ |
| |
| /* initialize anc data */ |
| CAacDecoder_AncDataInit(&self->ancData, NULL, 0); |
| |
| /* initialize stream info */ |
| CStreamInfoInit(&self->streamInfo); |
| |
| /* initialize error concealment common data */ |
| CConcealment_InitCommonData(&self->concealCommonData); |
| |
| 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->aacCommonData.workBufferCore1 = GetWorkBufferCore1(); |
| self->aacCommonData.workBufferCore2 = GetWorkBufferCore2(); |
| if (self->aacCommonData.workBufferCore1 == NULL |
| ||self->aacCommonData.workBufferCore2 == NULL ) |
| goto bail; |
| |
| return self; |
| |
| bail: |
| CAacDecoder_Close( self ); |
| |
| return NULL; |
| } |
| |
| /* Destroy aac decoder */ |
| LINKSPEC_CPP void CAacDecoder_Close(HANDLE_AACDECODER self) |
| { |
| int ch; |
| |
| if (self == NULL) |
| return; |
| |
| for (ch=0; ch<(6); ch++) { |
| if (self->pAacDecoderStaticChannelInfo[ch] != NULL) { |
| FreeOverlapBuffer (&self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer); |
| FreeAacDecoderStaticChannelInfo (&self->pAacDecoderStaticChannelInfo[ch]); |
| } |
| if (self->pAacDecoderChannelInfo[ch] != NULL) { |
| FreeAacDecoderChannelInfo (&self->pAacDecoderChannelInfo[ch]); |
| } |
| } |
| |
| self->aacChannels = 0; |
| |
| if (self->hDrcInfo) { |
| FreeDrcInfo(&self->hDrcInfo); |
| } |
| |
| FreeWorkBufferCore1 (&self->aacCommonData.workBufferCore1); |
| FreeWorkBufferCore2 (&self->aacCommonData.workBufferCore2); |
| |
| 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) |
| { |
| AAC_DECODER_ERROR err = AAC_DEC_OK; |
| INT ascChannels, ch, ascChanged = 0; |
| |
| if (!self) |
| return AAC_DEC_INVALID_HANDLE; |
| |
| // 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; |
| break; |
| |
| case AOT_SBR: |
| case AOT_PS: |
| case AOT_ER_AAC_LD: |
| case AOT_ER_AAC_ELD: |
| break; |
| |
| default: |
| return AAC_DEC_UNSUPPORTED_AOT; |
| } |
| |
| CProgramConfig_Init(&self->pce); |
| |
| /* set channels */ |
| switch (asc->m_channelConfiguration) { |
| case 0: |
| #ifdef TP_PCE_ENABLE |
| /* get channels from program config (ASC) */ |
| if (CProgramConfig_IsValid(&asc->m_progrConfigElement)) { |
| ascChannels = asc->m_progrConfigElement.NumChannels; |
| if (ascChannels > 0) { |
| int el; |
| /* valid number of channels -> copy program config element (PCE) from ASC */ |
| FDKmemcpy(&self->pce, &asc->m_progrConfigElement, sizeof(CProgramConfig)); |
| /* Built element table */ |
| el = CProgramConfig_GetElementTable(&asc->m_progrConfigElement, self->elements, 7); |
| for (; el<7; el++) { |
| self->elements[el] = ID_NONE; |
| } |
| } else { |
| return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; |
| } |
| } else { |
| if (transportDec_GetFormat(self->hInput) == TT_MP4_ADTS) { |
| /* set default max_channels for memory allocation because in implicit channel mapping mode |
| we don't know the actual number of channels until we processed at least one raw_data_block(). */ |
| ascChannels = (6); |
| } else { |
| return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; |
| } |
| } |
| #else /* TP_PCE_ENABLE */ |
| return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; |
| #endif /* TP_PCE_ENABLE */ |
| break; |
| case 1: case 2: case 3: case 4: case 5: case 6: |
| ascChannels = asc->m_channelConfiguration; |
| break; |
| case 7: |
| ascChannels = 8; |
| break; |
| default: |
| return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; |
| } |
| |
| /* Initialize constant mappings for channel config 1-7 */ |
| if (asc->m_channelConfiguration > 0) { |
| int el; |
| FDKmemcpy(self->elements, elementsTab[asc->m_channelConfiguration-1], sizeof(MP4_ELEMENT_ID)*FDKmin(7,7)); |
| for (el=7; el<7; el++) { |
| self->elements[el] = ID_NONE; |
| } |
| for (ch=0; ch<ascChannels; ch++) { |
| self->chMapping[ch] = ch; |
| } |
| for (; ch<(6); ch++) { |
| self->chMapping[ch] = 255; |
| } |
| } |
| |
| self->streamInfo.channelConfig = asc->m_channelConfiguration; |
| |
| if (ascChannels > (6)) { |
| return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; |
| } |
| if (self->streamInfo.aot != asc->m_aot) { |
| self->streamInfo.aot = asc->m_aot; |
| ascChanged = 1; |
| } |
| |
| if (self->streamInfo.aacSamplesPerFrame != (INT)asc->m_samplesPerFrame) { |
| self->streamInfo.aacSamplesPerFrame = asc->m_samplesPerFrame; |
| ascChanged = 1; |
| } |
| |
| self->streamInfo.bitRate = 0; |
| |
| /* Set syntax flags */ |
| self->flags = 0; |
| |
| self->streamInfo.extAot = asc->m_extensionAudioObjectType; |
| self->streamInfo.extSamplingRate = asc->m_extensionSamplingFrequency; |
| self->flags |= (asc->m_sbrPresentFlag) ? AC_SBR_PRESENT : 0; |
| self->flags |= (asc->m_psPresentFlag) ? AC_PS_PRESENT : 0; |
| self->sbrEnabled = 0; |
| |
| /* --------- vcb11 ------------ */ |
| self->flags |= (asc->m_vcb11Flag) ? AC_ER_VCB11 : 0; |
| |
| /* ---------- rvlc ------------ */ |
| self->flags |= (asc->m_rvlcFlag) ? AC_ER_RVLC : 0; |
| |
| /* ----------- hcr ------------ */ |
| self->flags |= (asc->m_hcrFlag) ? AC_ER_HCR : 0; |
| |
| if (asc->m_aot == AOT_ER_AAC_ELD) { |
| self->flags |= AC_ELD; |
| self->flags |= (asc->m_sc.m_eldSpecificConfig.m_sbrCrcFlag) ? AC_SBRCRC : 0; |
| self->flags |= (asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign) ? AC_LD_MPS : 0; |
| } |
| self->flags |= (asc->m_aot == AOT_ER_AAC_LD) ? AC_LD : 0; |
| self->flags |= (asc->m_epConfig >= 0) ? AC_ER : 0; |
| |
| |
| if (asc->m_sbrPresentFlag) { |
| self->sbrEnabled = 1; |
| self->sbrEnabledPrev = 1; |
| } |
| if (asc->m_psPresentFlag) { |
| self->flags |= AC_PS_PRESENT; |
| } |
| |
| 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->streamInfo.aacSampleRate != (INT)asc->m_samplingFrequency) { |
| AAC_DECODER_ERROR error; |
| |
| ascChanged = 1; |
| |
| /* Update samplerate info. */ |
| error = getSamplingRateInfo(&self->samplingRateInfo, asc->m_samplesPerFrame, asc->m_samplingFrequencyIndex, asc->m_samplingFrequency); |
| if (error != AAC_DEC_OK) { |
| return error; |
| } |
| self->streamInfo.aacSampleRate = self->samplingRateInfo.samplingRate; |
| } |
| |
| /* Check if amount of channels has changed. */ |
| if (self->ascChannels != ascChannels) |
| { |
| ascChanged = 1; |
| |
| /* Allocate all memory structures for each channel */ |
| { |
| for (ch = 0; ch < ascChannels; ch++) { |
| CAacDecoderDynamicData *aacDecoderDynamicData = &self->aacCommonData.workBufferCore1->pAacDecoderDynamicData[ch%2]; |
| |
| /* initialize pointer to CAacDecoderChannelInfo */ |
| if (self->pAacDecoderChannelInfo[ch] == NULL) { |
| 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; |
| } |
| /* Hook shared work memory into channel data structure */ |
| self->pAacDecoderChannelInfo[ch]->pDynData = aacDecoderDynamicData; |
| self->pAacDecoderChannelInfo[ch]->pComData = &self->aacCommonData; |
| } |
| |
| /* Allocate persistent channel memory */ |
| if (self->pAacDecoderStaticChannelInfo[ch] == NULL) { |
| 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; |
| } |
| self->pAacDecoderChannelInfo[ch]->pSpectralCoefficient = (SPECTRAL_PTR) &self->aacCommonData.workBufferCore2[ch*1024]; |
| |
| } |
| CPns_InitPns(&self->pAacDecoderChannelInfo[ch]->data.aac.PnsData, &self->aacCommonData.pnsInterChannelData, &self->aacCommonData.pnsCurrentSeed, self->aacCommonData.pnsRandomSeed); |
| } |
| |
| |
| HcrInitRom(&self->aacCommonData.overlay.aac.erHcrInfo); |
| setHcrType(&self->aacCommonData.overlay.aac.erHcrInfo, ID_SCE); |
| |
| /* Make allocated channel count persistent in decoder context. */ |
| self->aacChannels = ascChannels; |
| } |
| |
| /* Make amount of signalled channels persistent in decoder context. */ |
| self->ascChannels = ascChannels; |
| } |
| |
| /* Update structures */ |
| if (ascChanged) { |
| |
| /* Things to be done for each channel, which do not involved allocating memory. */ |
| for (ch = 0; ch < ascChannels; 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; |
| } |
| mdct_init( &self->pAacDecoderStaticChannelInfo[ch]->IMdct, |
| self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer, |
| OverlapBufferSize ); |
| |
| |
| /* Reset DRC control data for this channel */ |
| aacDecoder_drcInitChannelData ( &self->pAacDecoderStaticChannelInfo[ch]->drcData ); |
| |
| /* 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, |
| self->streamInfo.aacSamplesPerFrame ); |
| } |
| } |
| |
| /* Update externally visible copy of flags */ |
| self->streamInfo.flags = self->flags; |
| |
| return err; |
| |
| bail: |
| aacDecoder_Close( self ); |
| return AAC_DEC_OUT_OF_MEMORY; |
| } |
| |
| |
| LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( |
| HANDLE_AACDECODER self, |
| const UINT flags, |
| INT_PCM *pTimeData, |
| const INT timeDataSize, |
| const INT interleaved |
| ) |
| { |
| 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 */ |
| |
| INT auStartAnchor = (INT)FDKgetValidBits(bs); /* AU start bit buffer position for AU byte alignment */ |
| |
| self->frameOK = 1; |
| |
| /* 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); |
| |
| { |
| int ch; |
| |
| if (self->streamInfo.channelConfig == 0) { |
| /* Init Channel/Element mapping table */ |
| for (ch=0; ch<(6); ch++) { |
| self->chMapping[ch] = 255; |
| } |
| if (!CProgramConfig_IsValid(pce)) { |
| int el; |
| for (el=0; el<7; el++) { |
| self->elements[el] = ID_NONE; |
| } |
| } |
| } |
| } |
| |
| /* Check sampling frequency */ |
| switch ( self->streamInfo.aacSampleRate ) { |
| 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 & (AC_USAC|AC_RSVD50)) ) { |
| return AAC_DEC_UNSUPPORTED_SAMPLINGRATE; |
| } |
| break; |
| } |
| |
| |
| if ( flags & AACDEC_CLRHIST ) |
| { |
| int ch; |
| /* Clear history */ |
| for (ch = 0; ch < self->aacChannels; ch++) { |
| /* Reset concealment */ |
| CConcealment_InitChannelData(&self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo, |
| &self->concealCommonData, |
| self->streamInfo.aacSamplesPerFrame ); |
| /* Clear concealment buffers to get rid of the complete history */ |
| FDKmemclear(self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo.spectralCoefficient, 1024 * sizeof(FIXP_CNCL)); |
| FDKmemclear(self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo.specScale, 8 * sizeof(SHORT)); |
| /* Clear overlap-add buffers to avoid clicks. */ |
| FDKmemclear(self->pAacDecoderStaticChannelInfo[ch]->IMdct.overlap.freq, OverlapBufferSize*sizeof(FIXP_DBL)); |
| } |
| } |
| |
| |
| |
| #ifdef TP_PCE_ENABLE |
| int pceRead = 0; /* Flag indicating a PCE in the current raw_data_block() */ |
| #endif |
| |
| |
| 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 el_cnt[ID_LAST] = { 0 }; /* element counter ( robustness ) */ |
| |
| while ( (type != ID_END) && (! (flags & (AACDEC_CONCEAL | AACDEC_FLUSH))) && self->frameOK ) |
| { |
| int el_channels; |
| |
| if (! (self->flags & (AC_USAC|AC_RSVD50|AC_ELD|AC_SCALABLE|AC_ER))) |
| type = (MP4_ELEMENT_ID) FDKreadBits(bs,3); |
| else |
| type = self->elements[element_count]; |
| |
| setHcrType(&self->aacCommonData.overlay.aac.erHcrInfo, type); |
| |
| |
| if ((INT)FDKgetValidBits(bs) < 0) |
| self->frameOK = 0; |
| |
| switch (type) |
| { |
| case ID_SCE: |
| case ID_CPE: |
| case ID_LFE: |
| /* |
| Consistency check |
| */ |
| |
| if (type == ID_CPE) { |
| el_channels = 2; |
| } else { |
| el_channels = 1; |
| } |
| |
| if ( (el_cnt[type] >= (self->ascChannels>>(el_channels-1))) || (aacChannels > (self->ascChannels-el_channels)) ) { |
| ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; |
| self->frameOK = 0; |
| break; |
| } |
| |
| if ( !(self->flags & (AC_USAC|AC_RSVD50)) ) { |
| 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, |
| self->flags, |
| self->streamInfo.aacSamplesPerFrame, |
| el_channels, |
| self->streamInfo.epConfig, |
| self->hInput |
| ); |
| 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, |
| self->pAacDecoderChannelInfo[aacChannels]->ElementInstanceTag, |
| aacChannels, |
| self->chMapping, |
| self->channelType, |
| self->channelIndices, |
| &previous_element_index, |
| self->elements, |
| type) ) |
| { |
| if ( !hdaacDecoded ) { |
| CChannelElement_Decode( |
| &self->pAacDecoderChannelInfo[aacChannels], |
| &self->pAacDecoderStaticChannelInfo[aacChannels], |
| &self->samplingRateInfo, |
| self->flags, |
| el_channels |
| ); |
| } |
| aacChannels += 1; |
| if (type == ID_CPE) { |
| aacChannels += 1; |
| } |
| } |
| else { |
| self->frameOK = 0; |
| } |
| /* Create SBR element for SBR for upsampling. */ |
| if ( (type == ID_LFE) |
| && ( (self->flags & AC_SBR_PRESENT) |
| || (self->sbrEnabled == 1) ) ) |
| { |
| SBR_ERROR sbrError; |
| |
| sbrError = sbrDecoder_InitElement( |
| self->hSbrDecoder, |
| self->streamInfo.aacSampleRate, |
| self->streamInfo.extSamplingRate, |
| self->streamInfo.aacSamplesPerFrame, |
| self->streamInfo.aot, |
| ID_LFE, |
| previous_element_index |
| ); |
| if (sbrError != SBRDEC_OK) { |
| /* Do not try to apply SBR because initializing the element failed. */ |
| self->sbrEnabled = 0; |
| } |
| } |
| } |
| |
| el_cnt[type]++; |
| break; |
| |
| case ID_CCE: |
| /* |
| Consistency check |
| */ |
| if ( el_cnt[type] > self->ascChannels ) { |
| ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; |
| self->frameOK = 0; |
| break; |
| } |
| |
| if (self->frameOK) |
| { |
| /* memory for spectral lines temporal on scratch */ |
| C_ALLOC_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 = self->aacCommonData.workBufferCore1->pAacDecoderDynamicData; |
| tmpAacDecoderChannelInfo.pComData = &self->aacCommonData; |
| 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, |
| self->flags, |
| self->streamInfo.aacSamplesPerFrame, |
| 1, |
| self->streamInfo.epConfig, |
| self->hInput |
| ); |
| |
| C_ALLOC_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, |
| &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( bs, |
| &self->ancData, |
| self->hDrcInfo, |
| self->hInput, |
| &element_instance_tag, |
| auStartAnchor ); |
| |
| if (!CProgramConfig_LookupElement( |
| pce, |
| self->streamInfo.channelConfig, |
| element_instance_tag, |
| 0, |
| self->chMapping, |
| self->channelType, |
| self->channelIndices, |
| &previous_element_index, |
| self->elements, |
| type) ) |
| { |
| /* most likely an error in bitstream occured */ |
| //self->frameOK = 0; |
| } |
| } |
| |
| { |
| UCHAR *pDvbAncData = NULL; |
| AAC_DECODER_ERROR ancErr; |
| int ancIndex; |
| int dvbAncDataSize = 0; |
| |
| /* Ask how many anc data elements are in buffer */ |
| ancIndex = self->ancData.nrElements - 1; |
| /* Get the last one (if available) */ |
| ancErr = CAacDecoder_AncDataGet( &self->ancData, |
| ancIndex, |
| &pDvbAncData, |
| &dvbAncDataSize ); |
| |
| if (ancErr == AAC_DEC_OK) { |
| pcmDmx_ReadDvbAncData ( |
| self->hPcmUtils, |
| pDvbAncData, |
| dvbAncDataSize, |
| 0 /* not mpeg2 */ ); |
| } |
| } |
| break; |
| |
| #ifdef TP_PCE_ENABLE |
| case ID_PCE: |
| |
| if ( CProgramConfigElement_Read( bs, |
| self->hInput, |
| pce, |
| self->streamInfo.channelConfig, |
| auStartAnchor ) ) |
| { /* Built element table */ |
| int elIdx = CProgramConfig_GetElementTable(pce, self->elements, 7); |
| /* Reset the remaining tabs */ |
| for ( ; elIdx<7; elIdx++) { |
| self->elements[elIdx] = ID_NONE; |
| } |
| /* Make new number of channel persistant */ |
| self->ascChannels = pce->NumChannels; |
| /* If PCE is not first element conceal this frame to avoid inconsistencies */ |
| if ( element_count != 0 ) { |
| self->frameOK = 0; |
| } |
| } |
| pceRead = 1; |
| break; |
| #endif /* TP_PCE_ENABLE */ |
| |
| 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: |
| { |
| INT bitCnt = 0; |
| |
| /* get the remaining bits of this frame */ |
| bitCnt = transportDec_GetAuBitsRemaining(self->hInput, 0); |
| |
| if ( (bitCnt > 0) && (self->flags & AC_SBR_PRESENT) && (self->flags & (AC_USAC|AC_RSVD50|AC_ELD)) ) |
| { |
| SBR_ERROR err = SBRDEC_OK; |
| int elIdx, numChElements = el_cnt[ID_SCE] + el_cnt[ID_CPE]; |
| |
| for (elIdx = 0; elIdx < numChElements; elIdx += 1) |
| { |
| err = sbrDecoder_Parse ( |
| self->hSbrDecoder, |
| bs, |
| &bitCnt, |
| -1, |
| self->flags & AC_SBRCRC, |
| self->elements[elIdx], |
| elIdx, |
| self->flags & AC_INDEP ); |
| |
| if (err != SBRDEC_OK) { |
| break; |
| } |
| } |
| if (err == SBRDEC_OK) { |
| self->sbrEnabled = 1; |
| } else { |
| self->frameOK = 0; |
| } |
| } |
| |
| |
| if ( ! (self->flags & (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; |
| } |
| } |
| } |
| } |
| break; |
| |
| case ID_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)) ) |
| { |
| /* Byte alignment with respect to the first bit of the raw_data_block(). */ |
| { |
| 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); |
| if ( unreadBits != 0 ) { |
| |
| 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; |
| } |
| } |
| |
| /* 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; |
| } |
| else if ( aacChannels > self->ascChannels ) { |
| /* Do not overwrite current error */ |
| if (ErrorStatus == AAC_DEC_OK) { |
| ErrorStatus = AAC_DEC_UNSUPPORTED_FORMAT; |
| } |
| self->frameOK = 0; |
| aacChannels = 0; |
| } |
| |
| if ( TRANSPORTDEC_OK != transportDec_CrcCheck(self->hInput) ) |
| { |
| self->frameOK=0; |
| } |
| |
| /* store or restore the number of channels */ |
| if ( self->frameOK && !(flags &(AACDEC_CONCEAL|AACDEC_FLUSH)) ) { |
| self->concealChannels = aacChannels; /* store */ |
| self->sbrEnabledPrev = self->sbrEnabled; |
| } else { |
| if (self->aacChannels > 0) { |
| aacChannels = self->concealChannels; /* restore */ |
| self->sbrEnabled = self->sbrEnabledPrev; |
| } |
| } |
| |
| /* Update number of output channels */ |
| self->streamInfo.numChannels = aacChannels; |
| |
| #ifdef TP_PCE_ENABLE |
| if (pceRead == 1 || CProgramConfig_IsValid(pce)) { |
| /* Set matrix mixdown infos if available from PCE. */ |
| pcmDmx_SetMatrixMixdownFromPce ( self->hPcmUtils, |
| pce->MatrixMixdownIndexPresent, |
| pce->MatrixMixdownIndex, |
| pce->PseudoSurroundEnable ); |
| } |
| #endif |
| |
| /* If there is no valid data to transfrom into time domain, return. */ |
| if ( ! IS_OUTPUT_VALID(ErrorStatus) ) { |
| return ErrorStatus; |
| } |
| |
| /* |
| Inverse transform |
| */ |
| { |
| int stride, offset, c; |
| |
| /* Extract DRC control data and map it to channels (without bitstream delay) */ |
| aacDecoder_drcProlog ( |
| self->hDrcInfo, |
| bs, |
| self->pAacDecoderStaticChannelInfo, |
| self->pce.ElementInstanceTag, |
| self->chMapping, |
| aacChannels |
| ); |
| |
| /* "c" iterates in canonical MPEG channel order */ |
| for (c=0; c < aacChannels; c++) |
| { |
| CAacDecoderChannelInfo *pAacDecoderChannelInfo; |
| |
| /* Select correct pAacDecoderChannelInfo for current channel */ |
| if (self->chMapping[c] >= aacChannels) { |
| pAacDecoderChannelInfo = self->pAacDecoderChannelInfo[c]; |
| } else { |
| pAacDecoderChannelInfo = self->pAacDecoderChannelInfo[self->chMapping[c]]; |
| } |
| |
| /* Setup offset and stride for time buffer traversal. */ |
| if (interleaved) { |
| stride = aacChannels; |
| offset = self->channelOutputMapping[aacChannels-1][c]; |
| } else { |
| stride = 1; |
| offset = self->channelOutputMapping[aacChannels-1][c] * self->streamInfo.aacSamplesPerFrame; |
| } |
| |
| |
| /* |
| Conceal defective spectral data |
| */ |
| CConcealment_Apply(&self->pAacDecoderStaticChannelInfo[c]->concealmentInfo, |
| pAacDecoderChannelInfo, |
| self->pAacDecoderStaticChannelInfo[c], |
| &self->samplingRateInfo, |
| self->streamInfo.aacSamplesPerFrame, |
| 0, |
| (self->frameOK && !(flags&AACDEC_CONCEAL)), |
| self->flags |
| ); |
| |
| |
| if (flags & (AACDEC_INTR|AACDEC_CLRHIST)) { |
| /* Reset DRC control data for this channel */ |
| aacDecoder_drcInitChannelData ( &self->pAacDecoderStaticChannelInfo[c]->drcData ); |
| } |
| /* DRC processing */ |
| aacDecoder_drcApply ( |
| self->hDrcInfo, |
| self->hSbrDecoder, |
| pAacDecoderChannelInfo, |
| &self->pAacDecoderStaticChannelInfo[c]->drcData, |
| c, |
| self->streamInfo.aacSamplesPerFrame, |
| self->sbrEnabled |
| ); |
| |
| switch (pAacDecoderChannelInfo->renderMode) |
| { |
| case AACDEC_RENDER_IMDCT: |
| CBlock_FrequencyToTime( |
| self->pAacDecoderStaticChannelInfo[c], |
| pAacDecoderChannelInfo, |
| pTimeData + offset, |
| self->streamInfo.aacSamplesPerFrame, |
| stride, |
| (self->frameOK && !(flags&AACDEC_CONCEAL)), |
| self->aacCommonData.workBufferCore1->mdctOutTemp |
| ); |
| break; |
| case AACDEC_RENDER_ELDFB: |
| CBlock_FrequencyToTimeLowDelay( |
| self->pAacDecoderStaticChannelInfo[c], |
| pAacDecoderChannelInfo, |
| pTimeData + offset, |
| self->streamInfo.aacSamplesPerFrame, |
| stride |
| ); |
| break; |
| default: |
| ErrorStatus = AAC_DEC_UNKNOWN; |
| break; |
| } |
| if ( flags&AACDEC_FLUSH ) { |
| FDKmemclear(pAacDecoderChannelInfo->pSpectralCoefficient, sizeof(FIXP_DBL)*self->streamInfo.aacSamplesPerFrame); |
| FDKmemclear(self->pAacDecoderStaticChannelInfo[c]->pOverlapBuffer, OverlapBufferSize*sizeof(FIXP_DBL)); |
| } |
| } |
| |
| |
| /* Extract DRC control data and map it to channels (with bitstream delay) */ |
| aacDecoder_drcEpilog ( |
| self->hDrcInfo, |
| bs, |
| self->pAacDecoderStaticChannelInfo, |
| self->pce.ElementInstanceTag, |
| self->chMapping, |
| aacChannels |
| ); |
| } |
| |
| |
| /* Reorder channel type information tables. */ |
| { |
| AUDIO_CHANNEL_TYPE types[(6)]; |
| UCHAR idx[(6)]; |
| int c; |
| |
| 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++) { |
| self->channelType[self->channelOutputMapping[aacChannels-1][c]] = types[c]; |
| self->channelIndices[self->channelOutputMapping[aacChannels-1][c]] = 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; |
| } |
| |
| |
| |
| |