/* ----------------------------------------------------------------------------------------------------------- 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.

1 Bitstream deformatter

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

2 Actual decoding to retain the time domain output

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

2.1 Stereo processing for CPE elements

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

2.2 Scaling of spectral data

CBlock_ScaleSpectralData().

2.3 Apply additional coding tools

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

3 Frequency-To-Time conversion

The filterbank is called using CBlock_FrequencyToTime() using the MDCT module from the FDK Tools */ #include "aacdecoder.h" #include "aac_rom.h" #include "aac_ram.h" #include "channel.h" #include "FDK_audio.h" #include "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; chchMapping[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 ); if ( flags&AACDEC_FLUSH ) { FDKmemclear(pAacDecoderChannelInfo->pSpectralCoefficient, sizeof(FIXP_DBL)*self->streamInfo.aacSamplesPerFrame); } 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(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; cchannelType[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; }