| /* ----------------------------------------------------------------------------- |
| Software License for The Fraunhofer FDK AAC Codec Library for Android |
| |
| © Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten |
| Forschung e.V. All rights reserved. |
| |
| 1. INTRODUCTION |
| The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software |
| that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding |
| scheme for digital audio. This FDK AAC Codec software is intended to be used on |
| a wide variety of Android devices. |
| |
| AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient |
| general perceptual audio codecs. AAC-ELD is considered the best-performing |
| full-bandwidth communications codec by independent studies and is widely |
| deployed. AAC has been standardized by ISO and IEC as part of the MPEG |
| specifications. |
| |
| Patent licenses for necessary patent claims for the FDK AAC Codec (including |
| those of Fraunhofer) may be obtained through Via Licensing |
| (www.vialicensing.com) or through the respective patent owners individually for |
| the purpose of encoding or decoding bit streams in products that are compliant |
| with the ISO/IEC MPEG audio standards. Please note that most manufacturers of |
| Android devices already license these patent claims through Via Licensing or |
| directly from the patent owners, and therefore FDK AAC Codec software may |
| already be covered under those patent licenses when it is used for those |
| licensed purposes only. |
| |
| Commercially-licensed AAC software libraries, including floating-point versions |
| with enhanced sound quality, are also available from Fraunhofer. Users are |
| encouraged to check the Fraunhofer website for additional applications |
| information and documentation. |
| |
| 2. COPYRIGHT LICENSE |
| |
| Redistribution and use in source and binary forms, with or without modification, |
| are permitted without payment of copyright license fees provided that you |
| satisfy the following conditions: |
| |
| You must retain the complete text of this software license in redistributions of |
| the FDK AAC Codec or your modifications thereto in source code form. |
| |
| You must retain the complete text of this software license in the documentation |
| and/or other materials provided with redistributions of the FDK AAC Codec or |
| your modifications thereto in binary form. You must make available free of |
| charge copies of the complete source code of the FDK AAC Codec and your |
| modifications thereto to recipients of copies in binary form. |
| |
| The name of Fraunhofer may not be used to endorse or promote products derived |
| from this library without prior written permission. |
| |
| You may not charge copyright license fees for anyone to use, copy or distribute |
| the FDK AAC Codec software or your modifications thereto. |
| |
| Your modified versions of the FDK AAC Codec must carry prominent notices stating |
| that you changed the software and the date of any change. For modified versions |
| of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" |
| must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK |
| AAC Codec Library for Android." |
| |
| 3. NO PATENT LICENSE |
| |
| NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without |
| limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. |
| Fraunhofer provides no warranty of patent non-infringement with respect to this |
| software. |
| |
| You may use this FDK AAC Codec software or modifications thereto only for |
| purposes that are authorized by appropriate patent licenses. |
| |
| 4. DISCLAIMER |
| |
| This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright |
| holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, |
| including but not limited to the implied warranties of merchantability and |
| fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
| CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, |
| or consequential damages, including but not limited to procurement of substitute |
| goods or services; loss of use, data, or profits, or business interruption, |
| however caused and on any theory of liability, whether in contract, strict |
| liability, or tort (including negligence), arising in any way out of the use of |
| this software, even if advised of the possibility of such damage. |
| |
| 5. CONTACT INFORMATION |
| |
| Fraunhofer Institute for Integrated Circuits IIS |
| Attention: Audio and Multimedia Departments - FDK AAC LL |
| Am Wolfsmantel 33 |
| 91058 Erlangen, Germany |
| |
| www.iis.fraunhofer.de/amm |
| amm-info@iis.fraunhofer.de |
| ----------------------------------------------------------------------------- */ |
| |
| /**************************** AAC decoder library ****************************** |
| |
| Author(s): Manuel Jander |
| |
| Description: |
| |
| *******************************************************************************/ |
| |
| #include "aacdecoder_lib.h" |
| |
| #include "aac_ram.h" |
| #include "aacdecoder.h" |
| #include "tpdec_lib.h" |
| #include "FDK_core.h" /* FDK_tools version info */ |
| |
| #include "sbrdecoder.h" |
| |
| #include "conceal.h" |
| |
| #include "aacdec_drc.h" |
| |
| #include "sac_dec_lib.h" |
| |
| #include "pcm_utils.h" |
| |
| /* Decoder library info */ |
| #define AACDECODER_LIB_VL0 3 |
| #define AACDECODER_LIB_VL1 0 |
| #define AACDECODER_LIB_VL2 0 |
| #define AACDECODER_LIB_TITLE "AAC Decoder Lib" |
| #ifdef __ANDROID__ |
| #define AACDECODER_LIB_BUILD_DATE "" |
| #define AACDECODER_LIB_BUILD_TIME "" |
| #else |
| #define AACDECODER_LIB_BUILD_DATE __DATE__ |
| #define AACDECODER_LIB_BUILD_TIME __TIME__ |
| #endif |
| |
| static AAC_DECODER_ERROR setConcealMethod(const HANDLE_AACDECODER self, |
| const INT method); |
| |
| static void aacDecoder_setMetadataExpiry(const HANDLE_AACDECODER self, |
| const INT value) { |
| /* check decoder handle */ |
| if (self != NULL) { |
| INT mdExpFrame = 0; /* default: disable */ |
| |
| if ((value > 0) && |
| (self->streamInfo.aacSamplesPerFrame > |
| 0)) { /* Determine the corresponding number of frames: */ |
| FIXP_DBL frameTime = fDivNorm(self->streamInfo.aacSampleRate, |
| self->streamInfo.aacSamplesPerFrame * 1000); |
| mdExpFrame = fMultIceil(frameTime, value); |
| } |
| |
| /* Configure DRC module */ |
| aacDecoder_drcSetParam(self->hDrcInfo, DRC_DATA_EXPIRY_FRAME, mdExpFrame); |
| |
| /* Configure PCM downmix module */ |
| pcmDmx_SetParam(self->hPcmUtils, DMX_BS_DATA_EXPIRY_FRAME, mdExpFrame); |
| } |
| } |
| |
| LINKSPEC_CPP AAC_DECODER_ERROR |
| aacDecoder_GetFreeBytes(const HANDLE_AACDECODER self, UINT *pFreeBytes) { |
| /* reset free bytes */ |
| *pFreeBytes = 0; |
| |
| /* check handle */ |
| if (!self) return AAC_DEC_INVALID_HANDLE; |
| |
| /* return nr of free bytes */ |
| HANDLE_FDK_BITSTREAM hBs = transportDec_GetBitstream(self->hInput, 0); |
| *pFreeBytes = FDKgetFreeBits(hBs) >> 3; |
| |
| /* success */ |
| return AAC_DEC_OK; |
| } |
| |
| /** |
| * Config Decoder using a CSAudioSpecificConfig struct. |
| */ |
| static LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_Config( |
| HANDLE_AACDECODER self, const CSAudioSpecificConfig *pAscStruct, |
| UCHAR configMode, UCHAR *configChanged) { |
| AAC_DECODER_ERROR err; |
| |
| /* Initialize AAC core decoder, and update self->streaminfo */ |
| err = CAacDecoder_Init(self, pAscStruct, configMode, configChanged); |
| |
| if (!FDK_chMapDescr_isValid(&self->mapDescr)) { |
| return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; |
| } |
| |
| return err; |
| } |
| |
| LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_ConfigRaw(HANDLE_AACDECODER self, |
| UCHAR *conf[], |
| const UINT length[]) { |
| AAC_DECODER_ERROR err = AAC_DEC_OK; |
| TRANSPORTDEC_ERROR errTp; |
| UINT layer, nrOfLayers = self->nrOfLayers; |
| |
| for (layer = 0; layer < nrOfLayers; layer++) { |
| if (length[layer] > 0) { |
| errTp = transportDec_OutOfBandConfig(self->hInput, conf[layer], |
| length[layer], layer); |
| if (errTp != TRANSPORTDEC_OK) { |
| switch (errTp) { |
| case TRANSPORTDEC_NEED_TO_RESTART: |
| err = AAC_DEC_NEED_TO_RESTART; |
| break; |
| case TRANSPORTDEC_UNSUPPORTED_FORMAT: |
| err = AAC_DEC_UNSUPPORTED_FORMAT; |
| break; |
| default: |
| err = AAC_DEC_UNKNOWN; |
| break; |
| } |
| /* if baselayer is OK we continue decoding */ |
| if (layer >= 1) { |
| self->nrOfLayers = layer; |
| err = AAC_DEC_OK; |
| } |
| break; |
| } |
| } |
| } |
| |
| return err; |
| } |
| |
| LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_RawISOBMFFData(HANDLE_AACDECODER self, |
| UCHAR *buffer, |
| UINT length) { |
| FDK_BITSTREAM bs; |
| HANDLE_FDK_BITSTREAM hBs = &bs; |
| AAC_DECODER_ERROR err = AAC_DEC_OK; |
| |
| if (length < 8) return AAC_DEC_UNKNOWN; |
| |
| while (length >= 8) { |
| UINT size = |
| (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; |
| DRC_DEC_ERROR uniDrcErr = DRC_DEC_OK; |
| |
| if (length < size) return AAC_DEC_UNKNOWN; |
| if (size <= 8) return AAC_DEC_UNKNOWN; |
| |
| FDKinitBitStream(hBs, buffer + 8, 0x10000000, (size - 8) * 8); |
| |
| if ((buffer[4] == 'l') && (buffer[5] == 'u') && (buffer[6] == 'd') && |
| (buffer[7] == 't')) { |
| uniDrcErr = FDK_drcDec_ReadLoudnessBox(self->hUniDrcDecoder, hBs); |
| } else if ((buffer[4] == 'd') && (buffer[5] == 'm') && (buffer[6] == 'i') && |
| (buffer[7] == 'x')) { |
| uniDrcErr = |
| FDK_drcDec_ReadDownmixInstructions_Box(self->hUniDrcDecoder, hBs); |
| } else if ((buffer[4] == 'u') && (buffer[5] == 'd') && (buffer[6] == 'i') && |
| (buffer[7] == '2')) { |
| uniDrcErr = |
| FDK_drcDec_ReadUniDrcInstructions_Box(self->hUniDrcDecoder, hBs); |
| } else if ((buffer[4] == 'u') && (buffer[5] == 'd') && (buffer[6] == 'c') && |
| (buffer[7] == '2')) { |
| uniDrcErr = |
| FDK_drcDec_ReadUniDrcCoefficients_Box(self->hUniDrcDecoder, hBs); |
| } |
| |
| if (uniDrcErr != DRC_DEC_OK) err = AAC_DEC_UNKNOWN; |
| |
| buffer += size; |
| length -= size; |
| } |
| |
| return err; |
| } |
| |
| static INT aacDecoder_ConfigCallback(void *handle, |
| const CSAudioSpecificConfig *pAscStruct, |
| UCHAR configMode, UCHAR *configChanged) { |
| HANDLE_AACDECODER self = (HANDLE_AACDECODER)handle; |
| AAC_DECODER_ERROR err = AAC_DEC_OK; |
| TRANSPORTDEC_ERROR errTp; |
| |
| FDK_ASSERT(self != NULL); |
| { |
| { err = aacDecoder_Config(self, pAscStruct, configMode, configChanged); } |
| } |
| if (err == AAC_DEC_OK) { |
| /* |
| revert concealment method if either |
| - Interpolation concealment might not be meaningful |
| - Interpolation concealment is not implemented |
| */ |
| if ((self->flags[0] & (AC_LD | AC_ELD) && |
| (self->concealMethodUser == ConcealMethodNone) && |
| CConcealment_GetDelay(&self->concealCommonData) > |
| 0) /* might not be meaningful but allow if user has set it |
| expicitly */ |
| || (self->flags[0] & (AC_USAC | AC_RSVD50 | AC_RSV603DA) && |
| CConcealment_GetDelay(&self->concealCommonData) > |
| 0) /* not implemented */ |
| ) { |
| /* Revert to error concealment method Noise Substitution. |
| Because interpolation is not implemented for USAC or |
| the additional delay is unwanted for low delay codecs. */ |
| setConcealMethod(self, 1); |
| } |
| aacDecoder_setMetadataExpiry(self, self->metadataExpiry); |
| errTp = TRANSPORTDEC_OK; |
| } else { |
| if (err == AAC_DEC_NEED_TO_RESTART) { |
| errTp = TRANSPORTDEC_NEED_TO_RESTART; |
| } else if (IS_INIT_ERROR(err)) { |
| errTp = TRANSPORTDEC_UNSUPPORTED_FORMAT; |
| } /* Fatal errors */ |
| else { |
| errTp = TRANSPORTDEC_UNKOWN_ERROR; |
| } |
| } |
| |
| return errTp; |
| } |
| |
| static INT aacDecoder_FreeMemCallback(void *handle, |
| const CSAudioSpecificConfig *pAscStruct) { |
| TRANSPORTDEC_ERROR errTp = TRANSPORTDEC_OK; |
| HANDLE_AACDECODER self = (HANDLE_AACDECODER)handle; |
| |
| const int subStreamIndex = 0; |
| |
| FDK_ASSERT(self != NULL); |
| |
| if (CAacDecoder_FreeMem(self, subStreamIndex) != AAC_DEC_OK) { |
| errTp = TRANSPORTDEC_UNKOWN_ERROR; |
| } |
| |
| /* free Ram_SbrDecoder and Ram_SbrDecChannel */ |
| if (self->hSbrDecoder != NULL) { |
| if (sbrDecoder_FreeMem(&self->hSbrDecoder) != SBRDEC_OK) { |
| errTp = TRANSPORTDEC_UNKOWN_ERROR; |
| } |
| } |
| |
| /* free pSpatialDec and mpsData */ |
| if (self->pMpegSurroundDecoder != NULL) { |
| if (mpegSurroundDecoder_FreeMem( |
| (CMpegSurroundDecoder *)self->pMpegSurroundDecoder) != MPS_OK) { |
| errTp = TRANSPORTDEC_UNKOWN_ERROR; |
| } |
| } |
| |
| /* free persistent qmf domain buffer, QmfWorkBufferCore3, QmfWorkBufferCore4, |
| * QmfWorkBufferCore5 and configuration variables */ |
| FDK_QmfDomain_FreeMem(&self->qmfDomain); |
| |
| return errTp; |
| } |
| |
| static INT aacDecoder_CtrlCFGChangeCallback( |
| void *handle, const CCtrlCFGChange *pCtrlCFGChangeStruct) { |
| TRANSPORTDEC_ERROR errTp = TRANSPORTDEC_OK; |
| HANDLE_AACDECODER self = (HANDLE_AACDECODER)handle; |
| |
| if (self != NULL) { |
| CAacDecoder_CtrlCFGChange( |
| self, pCtrlCFGChangeStruct->flushStatus, pCtrlCFGChangeStruct->flushCnt, |
| pCtrlCFGChangeStruct->buildUpStatus, pCtrlCFGChangeStruct->buildUpCnt); |
| } else { |
| errTp = TRANSPORTDEC_UNKOWN_ERROR; |
| } |
| |
| return errTp; |
| } |
| |
| static INT aacDecoder_SbrCallback( |
| void *handle, HANDLE_FDK_BITSTREAM hBs, const INT sampleRateIn, |
| const INT sampleRateOut, const INT samplesPerFrame, |
| const AUDIO_OBJECT_TYPE coreCodec, const MP4_ELEMENT_ID elementID, |
| const INT elementIndex, const UCHAR harmonicSBR, |
| const UCHAR stereoConfigIndex, const UCHAR configMode, UCHAR *configChanged, |
| const INT downscaleFactor) { |
| HANDLE_SBRDECODER self = (HANDLE_SBRDECODER)handle; |
| |
| INT errTp = sbrDecoder_Header(self, hBs, sampleRateIn, sampleRateOut, |
| samplesPerFrame, coreCodec, elementID, |
| elementIndex, harmonicSBR, stereoConfigIndex, |
| configMode, configChanged, downscaleFactor); |
| |
| return errTp; |
| } |
| |
| static INT aacDecoder_SscCallback(void *handle, HANDLE_FDK_BITSTREAM hBs, |
| const AUDIO_OBJECT_TYPE coreCodec, |
| const INT samplingRate, |
| const INT stereoConfigIndex, |
| const INT coreSbrFrameLengthIndex, |
| const INT configBytes, const UCHAR configMode, |
| UCHAR *configChanged) { |
| SACDEC_ERROR err; |
| TRANSPORTDEC_ERROR errTp; |
| HANDLE_AACDECODER hAacDecoder = (HANDLE_AACDECODER)handle; |
| |
| err = mpegSurroundDecoder_Config( |
| (CMpegSurroundDecoder *)hAacDecoder->pMpegSurroundDecoder, hBs, coreCodec, |
| samplingRate, stereoConfigIndex, coreSbrFrameLengthIndex, configBytes, |
| configMode, configChanged); |
| |
| switch (err) { |
| case MPS_UNSUPPORTED_CONFIG: |
| /* MPS found but invalid or not decodable by this instance */ |
| /* We switch off MPS and keep going */ |
| hAacDecoder->mpsEnableCurr = 0; |
| hAacDecoder->mpsApplicable = 0; |
| errTp = TRANSPORTDEC_OK; |
| break; |
| case MPS_PARSE_ERROR: |
| /* MPS found but invalid or not decodable by this instance */ |
| hAacDecoder->mpsEnableCurr = 0; |
| hAacDecoder->mpsApplicable = 0; |
| if ((coreCodec == AOT_USAC) || (coreCodec == AOT_DRM_USAC) || |
| IS_LOWDELAY(coreCodec)) { |
| errTp = TRANSPORTDEC_PARSE_ERROR; |
| } else { |
| errTp = TRANSPORTDEC_OK; |
| } |
| break; |
| case MPS_OK: |
| hAacDecoder->mpsApplicable = 1; |
| errTp = TRANSPORTDEC_OK; |
| break; |
| default: |
| /* especially Parsing error is critical for transport layer */ |
| hAacDecoder->mpsApplicable = 0; |
| errTp = TRANSPORTDEC_UNKOWN_ERROR; |
| } |
| |
| return (INT)errTp; |
| } |
| |
| static INT aacDecoder_UniDrcCallback(void *handle, HANDLE_FDK_BITSTREAM hBs, |
| const INT fullPayloadLength, |
| const INT payloadType, |
| const INT subStreamIndex, |
| const INT payloadStart, |
| const AUDIO_OBJECT_TYPE aot) { |
| DRC_DEC_ERROR err = DRC_DEC_OK; |
| TRANSPORTDEC_ERROR errTp; |
| HANDLE_AACDECODER hAacDecoder = (HANDLE_AACDECODER)handle; |
| DRC_DEC_CODEC_MODE drcDecCodecMode = DRC_DEC_CODEC_MODE_UNDEFINED; |
| |
| if (subStreamIndex != 0) { |
| return TRANSPORTDEC_OK; |
| } |
| |
| else if (aot == AOT_USAC) { |
| drcDecCodecMode = DRC_DEC_MPEG_D_USAC; |
| } |
| |
| err = FDK_drcDec_SetCodecMode(hAacDecoder->hUniDrcDecoder, drcDecCodecMode); |
| if (err) return (INT)TRANSPORTDEC_UNKOWN_ERROR; |
| |
| if (payloadType == 0) /* uniDrcConfig */ |
| { |
| err = FDK_drcDec_ReadUniDrcConfig(hAacDecoder->hUniDrcDecoder, hBs); |
| } else /* loudnessInfoSet */ |
| { |
| err = FDK_drcDec_ReadLoudnessInfoSet(hAacDecoder->hUniDrcDecoder, hBs); |
| hAacDecoder->loudnessInfoSetPosition[1] = payloadStart; |
| hAacDecoder->loudnessInfoSetPosition[2] = fullPayloadLength; |
| } |
| |
| if (err == DRC_DEC_OK) |
| errTp = TRANSPORTDEC_OK; |
| else |
| errTp = TRANSPORTDEC_UNKOWN_ERROR; |
| |
| return (INT)errTp; |
| } |
| |
| LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_AncDataInit(HANDLE_AACDECODER self, |
| UCHAR *buffer, int size) { |
| CAncData *ancData = &self->ancData; |
| |
| return CAacDecoder_AncDataInit(ancData, buffer, size); |
| } |
| |
| LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_AncDataGet(HANDLE_AACDECODER self, |
| int index, UCHAR **ptr, |
| int *size) { |
| CAncData *ancData = &self->ancData; |
| |
| return CAacDecoder_AncDataGet(ancData, index, ptr, size); |
| } |
| |
| /* If MPS is present in stream, but not supported by this instance, we'll |
| have to switch off MPS and use QMF synthesis in the SBR module if required */ |
| static int isSupportedMpsConfig(AUDIO_OBJECT_TYPE aot, |
| unsigned int numInChannels, |
| unsigned int fMpsPresent) { |
| LIB_INFO libInfo[FDK_MODULE_LAST]; |
| UINT mpsCaps; |
| int isSupportedCfg = 1; |
| |
| FDKinitLibInfo(libInfo); |
| |
| mpegSurroundDecoder_GetLibInfo(libInfo); |
| |
| mpsCaps = FDKlibInfo_getCapabilities(libInfo, FDK_MPSDEC); |
| |
| if (!(mpsCaps & CAPF_MPS_LD) && IS_LOWDELAY(aot)) { |
| /* We got an LD AOT but MPS decoder does not support LD. */ |
| isSupportedCfg = 0; |
| } |
| if ((mpsCaps & CAPF_MPS_LD) && IS_LOWDELAY(aot) && !fMpsPresent) { |
| /* We got an LD AOT and the MPS decoder supports it. |
| * But LD-MPS is not explicitly signaled. */ |
| isSupportedCfg = 0; |
| } |
| if (!(mpsCaps & CAPF_MPS_USAC) && IS_USAC(aot)) { |
| /* We got an USAC AOT but MPS decoder does not support USAC. */ |
| isSupportedCfg = 0; |
| } |
| if (!(mpsCaps & CAPF_MPS_STD) && !IS_LOWDELAY(aot) && !IS_USAC(aot)) { |
| /* We got an GA AOT but MPS decoder does not support it. */ |
| isSupportedCfg = 0; |
| } |
| /* Check whether the MPS modul supports the given number of input channels: */ |
| switch (numInChannels) { |
| case 1: |
| if (!(mpsCaps & CAPF_MPS_1CH_IN)) { |
| /* We got a one channel input to MPS decoder but it does not support it. |
| */ |
| isSupportedCfg = 0; |
| } |
| break; |
| case 2: |
| if (!(mpsCaps & CAPF_MPS_2CH_IN)) { |
| /* We got a two channel input to MPS decoder but it does not support it. |
| */ |
| isSupportedCfg = 0; |
| } |
| break; |
| case 5: |
| case 6: |
| if (!(mpsCaps & CAPF_MPS_6CH_IN)) { |
| /* We got a six channel input to MPS decoder but it does not support it. |
| */ |
| isSupportedCfg = 0; |
| } |
| break; |
| default: |
| isSupportedCfg = 0; |
| } |
| |
| return (isSupportedCfg); |
| } |
| |
| static AAC_DECODER_ERROR setConcealMethod( |
| const HANDLE_AACDECODER self, /*!< Handle of the decoder instance */ |
| const INT method) { |
| AAC_DECODER_ERROR errorStatus = AAC_DEC_OK; |
| CConcealParams *pConcealData = NULL; |
| int method_revert = 0; |
| HANDLE_SBRDECODER hSbrDec = NULL; |
| HANDLE_AAC_DRC hDrcInfo = NULL; |
| HANDLE_PCM_DOWNMIX hPcmDmx = NULL; |
| CConcealmentMethod backupMethod = ConcealMethodNone; |
| int backupDelay = 0; |
| int bsDelay = 0; |
| |
| /* check decoder handle */ |
| if (self != NULL) { |
| pConcealData = &self->concealCommonData; |
| hSbrDec = self->hSbrDecoder; |
| hDrcInfo = self->hDrcInfo; |
| hPcmDmx = self->hPcmUtils; |
| if (self->flags[0] & (AC_USAC | AC_RSVD50 | AC_RSV603DA) && method >= 2) { |
| /* Interpolation concealment is not implemented for USAC/RSVD50 */ |
| /* errorStatus = AAC_DEC_SET_PARAM_FAIL; |
| goto bail; */ |
| method_revert = 1; |
| } |
| if (self->flags[0] & (AC_USAC | AC_RSVD50 | AC_RSV603DA) && method >= 2) { |
| /* Interpolation concealment is not implemented for USAC/RSVD50 */ |
| errorStatus = AAC_DEC_SET_PARAM_FAIL; |
| goto bail; |
| } |
| } |
| |
| /* Get current method/delay */ |
| backupMethod = CConcealment_GetMethod(pConcealData); |
| backupDelay = CConcealment_GetDelay(pConcealData); |
| |
| /* Be sure to set AAC and SBR concealment method simultaneously! */ |
| errorStatus = CConcealment_SetParams( |
| pConcealData, |
| (method_revert == 0) ? (int)method : (int)1, // concealMethod |
| AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, // concealFadeOutSlope |
| AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, // concealFadeInSlope |
| AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, // concealMuteRelease |
| AACDEC_CONCEAL_PARAM_NOT_SPECIFIED // concealComfNoiseLevel |
| ); |
| if ((errorStatus != AAC_DEC_OK) && (errorStatus != AAC_DEC_INVALID_HANDLE)) { |
| goto bail; |
| } |
| |
| /* Get new delay */ |
| bsDelay = CConcealment_GetDelay(pConcealData); |
| |
| { |
| SBR_ERROR sbrErr = SBRDEC_OK; |
| |
| /* set SBR bitstream delay */ |
| sbrErr = sbrDecoder_SetParam(hSbrDec, SBR_SYSTEM_BITSTREAM_DELAY, bsDelay); |
| |
| switch (sbrErr) { |
| case SBRDEC_OK: |
| case SBRDEC_NOT_INITIALIZED: |
| if (self != NULL) { |
| /* save the param value and set later |
| (when SBR has been initialized) */ |
| self->sbrParams.bsDelay = bsDelay; |
| } |
| break; |
| default: |
| errorStatus = AAC_DEC_SET_PARAM_FAIL; |
| goto bail; |
| } |
| } |
| |
| errorStatus = aacDecoder_drcSetParam(hDrcInfo, DRC_BS_DELAY, bsDelay); |
| if ((errorStatus != AAC_DEC_OK) && (errorStatus != AAC_DEC_INVALID_HANDLE)) { |
| goto bail; |
| } |
| |
| if (errorStatus == AAC_DEC_OK) { |
| PCMDMX_ERROR err = pcmDmx_SetParam(hPcmDmx, DMX_BS_DATA_DELAY, bsDelay); |
| switch (err) { |
| case PCMDMX_INVALID_HANDLE: |
| errorStatus = AAC_DEC_INVALID_HANDLE; |
| case PCMDMX_OK: |
| break; |
| default: |
| errorStatus = AAC_DEC_SET_PARAM_FAIL; |
| goto bail; |
| } |
| } |
| |
| bail: |
| if ((errorStatus != AAC_DEC_OK) && (errorStatus != AAC_DEC_INVALID_HANDLE)) { |
| /* Revert to the initial state */ |
| CConcealment_SetParams( |
| pConcealData, (int)backupMethod, AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, |
| AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, |
| AACDEC_CONCEAL_PARAM_NOT_SPECIFIED); |
| /* Revert SBR bitstream delay */ |
| sbrDecoder_SetParam(hSbrDec, SBR_SYSTEM_BITSTREAM_DELAY, backupDelay); |
| /* Revert DRC bitstream delay */ |
| aacDecoder_drcSetParam(hDrcInfo, DRC_BS_DELAY, backupDelay); |
| /* Revert PCM mixdown bitstream delay */ |
| pcmDmx_SetParam(hPcmDmx, DMX_BS_DATA_DELAY, backupDelay); |
| } |
| |
| return errorStatus; |
| } |
| |
| LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_SetParam( |
| const HANDLE_AACDECODER self, /*!< Handle of the decoder instance */ |
| const AACDEC_PARAM param, /*!< Parameter to set */ |
| const INT value) /*!< Parameter valued */ |
| { |
| AAC_DECODER_ERROR errorStatus = AAC_DEC_OK; |
| HANDLE_TRANSPORTDEC hTpDec = NULL; |
| TRANSPORTDEC_ERROR errTp = TRANSPORTDEC_OK; |
| HANDLE_AAC_DRC hDrcInfo = NULL; |
| HANDLE_PCM_DOWNMIX hPcmDmx = NULL; |
| PCMDMX_ERROR dmxErr = PCMDMX_OK; |
| TDLimiterPtr hPcmTdl = NULL; |
| DRC_DEC_ERROR uniDrcErr = DRC_DEC_OK; |
| |
| /* check decoder handle */ |
| if (self != NULL) { |
| hTpDec = self->hInput; |
| hDrcInfo = self->hDrcInfo; |
| hPcmDmx = self->hPcmUtils; |
| hPcmTdl = self->hLimiter; |
| } else { |
| errorStatus = AAC_DEC_INVALID_HANDLE; |
| goto bail; |
| } |
| |
| /* configure the subsystems */ |
| switch (param) { |
| case AAC_PCM_MIN_OUTPUT_CHANNELS: |
| if (value < -1 || value > (8)) { |
| return AAC_DEC_SET_PARAM_FAIL; |
| } |
| dmxErr = pcmDmx_SetParam(hPcmDmx, MIN_NUMBER_OF_OUTPUT_CHANNELS, value); |
| break; |
| |
| case AAC_PCM_MAX_OUTPUT_CHANNELS: |
| if (value < -1 || value > (8)) { |
| return AAC_DEC_SET_PARAM_FAIL; |
| } |
| dmxErr = pcmDmx_SetParam(hPcmDmx, MAX_NUMBER_OF_OUTPUT_CHANNELS, value); |
| |
| if (dmxErr != PCMDMX_OK) { |
| goto bail; |
| } |
| errorStatus = |
| aacDecoder_drcSetParam(hDrcInfo, MAX_OUTPUT_CHANNELS, value); |
| if (value > 0) { |
| uniDrcErr = FDK_drcDec_SetParam(self->hUniDrcDecoder, |
| DRC_DEC_TARGET_CHANNEL_COUNT_REQUESTED, |
| (FIXP_DBL)value); |
| } |
| break; |
| |
| case AAC_PCM_DUAL_CHANNEL_OUTPUT_MODE: |
| dmxErr = pcmDmx_SetParam(hPcmDmx, DMX_DUAL_CHANNEL_MODE, value); |
| break; |
| |
| case AAC_PCM_LIMITER_ENABLE: |
| if (value < -2 || value > 1) { |
| return AAC_DEC_SET_PARAM_FAIL; |
| } |
| self->limiterEnableUser = value; |
| break; |
| |
| case AAC_PCM_LIMITER_ATTACK_TIME: |
| if (value <= 0) { /* module function converts value to unsigned */ |
| return AAC_DEC_SET_PARAM_FAIL; |
| } |
| switch (pcmLimiter_SetAttack(hPcmTdl, value)) { |
| case TDLIMIT_OK: |
| break; |
| case TDLIMIT_INVALID_HANDLE: |
| return AAC_DEC_INVALID_HANDLE; |
| case TDLIMIT_INVALID_PARAMETER: |
| default: |
| return AAC_DEC_SET_PARAM_FAIL; |
| } |
| break; |
| |
| case AAC_PCM_LIMITER_RELEAS_TIME: |
| if (value <= 0) { /* module function converts value to unsigned */ |
| return AAC_DEC_SET_PARAM_FAIL; |
| } |
| switch (pcmLimiter_SetRelease(hPcmTdl, value)) { |
| case TDLIMIT_OK: |
| break; |
| case TDLIMIT_INVALID_HANDLE: |
| return AAC_DEC_INVALID_HANDLE; |
| case TDLIMIT_INVALID_PARAMETER: |
| default: |
| return AAC_DEC_SET_PARAM_FAIL; |
| } |
| break; |
| |
| case AAC_METADATA_PROFILE: { |
| DMX_PROFILE_TYPE dmxProfile; |
| INT mdExpiry = -1; /* in ms (-1: don't change) */ |
| |
| switch ((AAC_MD_PROFILE)value) { |
| case AAC_MD_PROFILE_MPEG_STANDARD: |
| dmxProfile = DMX_PRFL_STANDARD; |
| break; |
| case AAC_MD_PROFILE_MPEG_LEGACY: |
| dmxProfile = DMX_PRFL_MATRIX_MIX; |
| break; |
| case AAC_MD_PROFILE_MPEG_LEGACY_PRIO: |
| dmxProfile = DMX_PRFL_FORCE_MATRIX_MIX; |
| break; |
| case AAC_MD_PROFILE_ARIB_JAPAN: |
| dmxProfile = DMX_PRFL_ARIB_JAPAN; |
| mdExpiry = 550; /* ms */ |
| break; |
| default: |
| return AAC_DEC_SET_PARAM_FAIL; |
| } |
| dmxErr = pcmDmx_SetParam(hPcmDmx, DMX_PROFILE_SETTING, (INT)dmxProfile); |
| if (dmxErr != PCMDMX_OK) { |
| goto bail; |
| } |
| if ((self != NULL) && (mdExpiry >= 0)) { |
| self->metadataExpiry = mdExpiry; |
| /* Determine the corresponding number of frames and configure all |
| * related modules. */ |
| aacDecoder_setMetadataExpiry(self, mdExpiry); |
| } |
| } break; |
| |
| case AAC_METADATA_EXPIRY_TIME: |
| if (value < 0) { |
| return AAC_DEC_SET_PARAM_FAIL; |
| } |
| if (self != NULL) { |
| self->metadataExpiry = value; |
| /* Determine the corresponding number of frames and configure all |
| * related modules. */ |
| aacDecoder_setMetadataExpiry(self, value); |
| } |
| break; |
| |
| case AAC_PCM_OUTPUT_CHANNEL_MAPPING: |
| if (value < 0 || value > 1) { |
| return AAC_DEC_SET_PARAM_FAIL; |
| } |
| /* CAUTION: The given value must be inverted to match the logic! */ |
| FDK_chMapDescr_setPassThrough(&self->mapDescr, !value); |
| break; |
| |
| case AAC_QMF_LOWPOWER: |
| if (value < -1 || value > 1) { |
| return AAC_DEC_SET_PARAM_FAIL; |
| } |
| |
| /** |
| * Set QMF mode (might be overriden) |
| * 0:HQ (complex) |
| * 1:LP (partially complex) |
| */ |
| self->qmfModeUser = (QMF_MODE)value; |
| break; |
| |
| case AAC_DRC_ATTENUATION_FACTOR: |
| /* DRC compression factor (where 0 is no and 127 is max compression) */ |
| errorStatus = aacDecoder_drcSetParam(hDrcInfo, DRC_CUT_SCALE, value); |
| break; |
| |
| case AAC_DRC_BOOST_FACTOR: |
| /* DRC boost factor (where 0 is no and 127 is max boost) */ |
| errorStatus = aacDecoder_drcSetParam(hDrcInfo, DRC_BOOST_SCALE, value); |
| break; |
| |
| case AAC_DRC_REFERENCE_LEVEL: |
| if ((value >= 0) && |
| ((value < 40) || (value > 127))) /* allowed range: -10 to -31.75 dB */ |
| return AAC_DEC_SET_PARAM_FAIL; |
| /* DRC target reference level quantized in 0.25dB steps using values |
| [40..127]. Negative values switch off loudness normalisation. Negative |
| values also switch off MPEG-4 DRC, while MPEG-D DRC can be separately |
| switched on/off with AAC_UNIDRC_SET_EFFECT */ |
| errorStatus = aacDecoder_drcSetParam(hDrcInfo, TARGET_REF_LEVEL, value); |
| uniDrcErr = FDK_drcDec_SetParam(self->hUniDrcDecoder, |
| DRC_DEC_LOUDNESS_NORMALIZATION_ON, |
| (FIXP_DBL)(value >= 0)); |
| /* set target loudness also for MPEG-D DRC */ |
| self->defaultTargetLoudness = (SCHAR)value; |
| break; |
| |
| case AAC_DRC_HEAVY_COMPRESSION: |
| /* Don't need to overwrite cut/boost values */ |
| errorStatus = |
| aacDecoder_drcSetParam(hDrcInfo, APPLY_HEAVY_COMPRESSION, value); |
| break; |
| |
| case AAC_DRC_DEFAULT_PRESENTATION_MODE: |
| /* DRC default presentation mode */ |
| errorStatus = |
| aacDecoder_drcSetParam(hDrcInfo, DEFAULT_PRESENTATION_MODE, value); |
| break; |
| |
| case AAC_DRC_ENC_TARGET_LEVEL: |
| /* Encoder target level for light (i.e. not heavy) compression: |
| Target reference level assumed at encoder for deriving limiting gains |
| */ |
| errorStatus = |
| aacDecoder_drcSetParam(hDrcInfo, ENCODER_TARGET_LEVEL, value); |
| break; |
| |
| case AAC_UNIDRC_SET_EFFECT: |
| if ((value < -1) || (value > 6)) return AAC_DEC_SET_PARAM_FAIL; |
| uniDrcErr = FDK_drcDec_SetParam(self->hUniDrcDecoder, DRC_DEC_EFFECT_TYPE, |
| (FIXP_DBL)value); |
| break; |
| case AAC_TPDEC_CLEAR_BUFFER: |
| errTp = transportDec_SetParam(hTpDec, TPDEC_PARAM_RESET, 1); |
| self->streamInfo.numLostAccessUnits = 0; |
| self->streamInfo.numBadBytes = 0; |
| self->streamInfo.numTotalBytes = 0; |
| /* aacDecoder_SignalInterruption(self); */ |
| break; |
| case AAC_CONCEAL_METHOD: |
| /* Changing the concealment method can introduce additional bitstream |
| delay. And that in turn affects sub libraries and modules which makes |
| the whole thing quite complex. So the complete changing routine is |
| packed into a helper function which keeps all modules and libs in a |
| consistent state even in the case an error occures. */ |
| errorStatus = setConcealMethod(self, value); |
| if (errorStatus == AAC_DEC_OK) { |
| self->concealMethodUser = (CConcealmentMethod)value; |
| } |
| break; |
| |
| default: |
| return AAC_DEC_SET_PARAM_FAIL; |
| } /* switch(param) */ |
| |
| bail: |
| |
| if (errorStatus == AAC_DEC_OK) { |
| /* Check error code returned by DMX module library: */ |
| switch (dmxErr) { |
| case PCMDMX_OK: |
| break; |
| case PCMDMX_INVALID_HANDLE: |
| errorStatus = AAC_DEC_INVALID_HANDLE; |
| break; |
| default: |
| errorStatus = AAC_DEC_SET_PARAM_FAIL; |
| } |
| } |
| |
| if (errTp != TRANSPORTDEC_OK && errorStatus == AAC_DEC_OK) { |
| errorStatus = AAC_DEC_SET_PARAM_FAIL; |
| } |
| |
| if (errorStatus == AAC_DEC_OK) { |
| /* Check error code returned by MPEG-D DRC decoder library: */ |
| switch (uniDrcErr) { |
| case 0: |
| break; |
| case -9998: |
| errorStatus = AAC_DEC_INVALID_HANDLE; |
| break; |
| default: |
| errorStatus = AAC_DEC_SET_PARAM_FAIL; |
| break; |
| } |
| } |
| |
| return (errorStatus); |
| } |
| LINKSPEC_CPP HANDLE_AACDECODER aacDecoder_Open(TRANSPORT_TYPE transportFmt, |
| UINT nrOfLayers) { |
| AAC_DECODER_INSTANCE *aacDec = NULL; |
| HANDLE_TRANSPORTDEC pIn; |
| int err = 0; |
| int stereoConfigIndex = -1; |
| |
| UINT nrOfLayers_min = fMin(nrOfLayers, (UINT)1); |
| |
| /* Allocate transport layer struct. */ |
| pIn = transportDec_Open(transportFmt, TP_FLAG_MPEG4, nrOfLayers_min); |
| if (pIn == NULL) { |
| return NULL; |
| } |
| |
| /* Allocate AAC decoder core struct. */ |
| aacDec = CAacDecoder_Open(transportFmt); |
| |
| if (aacDec == NULL) { |
| transportDec_Close(&pIn); |
| goto bail; |
| } |
| aacDec->hInput = pIn; |
| |
| aacDec->nrOfLayers = nrOfLayers_min; |
| |
| /* Setup channel mapping descriptor. */ |
| FDK_chMapDescr_init(&aacDec->mapDescr, NULL, 0, 0); |
| |
| /* Register Config Update callback. */ |
| transportDec_RegisterAscCallback(pIn, aacDecoder_ConfigCallback, |
| (void *)aacDec); |
| |
| /* Register Free Memory callback. */ |
| transportDec_RegisterFreeMemCallback(pIn, aacDecoder_FreeMemCallback, |
| (void *)aacDec); |
| |
| /* Register config switch control callback. */ |
| transportDec_RegisterCtrlCFGChangeCallback( |
| pIn, aacDecoder_CtrlCFGChangeCallback, (void *)aacDec); |
| |
| FDKmemclear(&aacDec->qmfDomain, sizeof(FDK_QMF_DOMAIN)); |
| /* open SBR decoder */ |
| if (SBRDEC_OK != sbrDecoder_Open(&aacDec->hSbrDecoder, &aacDec->qmfDomain)) { |
| err = -1; |
| goto bail; |
| } |
| aacDec->qmfModeUser = NOT_DEFINED; |
| transportDec_RegisterSbrCallback(aacDec->hInput, aacDecoder_SbrCallback, |
| (void *)aacDec->hSbrDecoder); |
| |
| if (mpegSurroundDecoder_Open( |
| (CMpegSurroundDecoder **)&aacDec->pMpegSurroundDecoder, |
| stereoConfigIndex, &aacDec->qmfDomain)) { |
| err = -1; |
| goto bail; |
| } |
| /* Set MPEG Surround defaults */ |
| aacDec->mpsEnableUser = 0; |
| aacDec->mpsEnableCurr = 0; |
| aacDec->mpsApplicable = 0; |
| aacDec->mpsOutputMode = (SCHAR)SACDEC_OUT_MODE_NORMAL; |
| transportDec_RegisterSscCallback(pIn, aacDecoder_SscCallback, (void *)aacDec); |
| |
| { |
| if (FDK_drcDec_Open(&(aacDec->hUniDrcDecoder), DRC_DEC_ALL) != 0) { |
| err = -1; |
| goto bail; |
| } |
| } |
| |
| transportDec_RegisterUniDrcConfigCallback(pIn, aacDecoder_UniDrcCallback, |
| (void *)aacDec, |
| aacDec->loudnessInfoSetPosition); |
| aacDec->defaultTargetLoudness = (SCHAR)96; |
| |
| pcmDmx_Open(&aacDec->hPcmUtils); |
| if (aacDec->hPcmUtils == NULL) { |
| err = -1; |
| goto bail; |
| } |
| |
| aacDec->hLimiter = |
| pcmLimiter_Create(TDL_ATTACK_DEFAULT_MS, TDL_RELEASE_DEFAULT_MS, |
| (FIXP_DBL)MAXVAL_DBL, (8), 96000); |
| if (NULL == aacDec->hLimiter) { |
| err = -1; |
| goto bail; |
| } |
| aacDec->limiterEnableUser = (UCHAR)-1; |
| aacDec->limiterEnableCurr = 0; |
| |
| /* Assure that all modules have same delay */ |
| if (setConcealMethod(aacDec, |
| CConcealment_GetMethod(&aacDec->concealCommonData))) { |
| err = -1; |
| goto bail; |
| } |
| |
| bail: |
| if (err == -1) { |
| aacDecoder_Close(aacDec); |
| aacDec = NULL; |
| } |
| return aacDec; |
| } |
| |
| LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_Fill(HANDLE_AACDECODER self, |
| UCHAR *pBuffer[], |
| const UINT bufferSize[], |
| UINT *pBytesValid) { |
| TRANSPORTDEC_ERROR tpErr; |
| /* loop counter for layers; if not TT_MP4_RAWPACKETS used as index for only |
| available layer */ |
| INT layer = 0; |
| INT nrOfLayers = self->nrOfLayers; |
| |
| { |
| for (layer = 0; layer < nrOfLayers; layer++) { |
| { |
| tpErr = transportDec_FillData(self->hInput, pBuffer[layer], |
| bufferSize[layer], &pBytesValid[layer], |
| layer); |
| if (tpErr != TRANSPORTDEC_OK) { |
| return AAC_DEC_UNKNOWN; /* Must be an internal error */ |
| } |
| } |
| } |
| } |
| |
| return AAC_DEC_OK; |
| } |
| |
| static void aacDecoder_SignalInterruption(HANDLE_AACDECODER self) { |
| CAacDecoder_SignalInterruption(self); |
| |
| if (self->hSbrDecoder != NULL) { |
| sbrDecoder_SetParam(self->hSbrDecoder, SBR_BS_INTERRUPTION, 1); |
| } |
| if (self->mpsEnableUser) { |
| mpegSurroundDecoder_SetParam( |
| (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, |
| SACDEC_BS_INTERRUPTION, 1); |
| } |
| } |
| |
| static void aacDecoder_UpdateBitStreamCounters(CStreamInfo *pSi, |
| HANDLE_FDK_BITSTREAM hBs, |
| INT nBits, |
| AAC_DECODER_ERROR ErrorStatus) { |
| /* calculate bit difference (amount of bits moved forward) */ |
| nBits = nBits - (INT)FDKgetValidBits(hBs); |
| |
| /* Note: The amount of bits consumed might become negative when parsing a |
| bit stream with several sub frames, and we find out at the last sub frame |
| that the total frame length does not match the sum of sub frame length. |
| If this happens, the transport decoder might want to rewind to the supposed |
| ending of the transport frame, and this position might be before the last |
| access unit beginning. */ |
| |
| /* Calc bitrate. */ |
| if (pSi->frameSize > 0) { |
| /* bitRate = nBits * sampleRate / frameSize */ |
| int ratio_e = 0; |
| FIXP_DBL ratio_m = fDivNorm(pSi->sampleRate, pSi->frameSize, &ratio_e); |
| pSi->bitRate = (INT)fMultNorm(nBits, DFRACT_BITS - 1, ratio_m, ratio_e, |
| DFRACT_BITS - 1); |
| } |
| |
| /* bit/byte counters */ |
| { |
| INT nBytes; |
| |
| nBytes = nBits >> 3; |
| pSi->numTotalBytes += nBytes; |
| if (IS_OUTPUT_VALID(ErrorStatus)) { |
| pSi->numTotalAccessUnits++; |
| } |
| if (IS_DECODE_ERROR(ErrorStatus)) { |
| pSi->numBadBytes += nBytes; |
| pSi->numBadAccessUnits++; |
| } |
| } |
| } |
| |
| static INT aacDecoder_EstimateNumberOfLostFrames(HANDLE_AACDECODER self) { |
| INT n; |
| |
| transportDec_GetMissingAccessUnitCount(&n, self->hInput); |
| |
| return n; |
| } |
| |
| LINKSPEC_CPP AAC_DECODER_ERROR |
| aacDecoder_DecodeFrame(HANDLE_AACDECODER self, INT_PCM *pTimeData_extern, |
| const INT timeDataSize_extern, const UINT flags) { |
| AAC_DECODER_ERROR ErrorStatus; |
| INT layer; |
| INT nBits; |
| HANDLE_FDK_BITSTREAM hBs; |
| int fTpInterruption = 0; /* Transport originated interruption detection. */ |
| int fTpConceal = 0; /* Transport originated concealment. */ |
| INT_PCM *pTimeData = NULL; |
| INT timeDataSize = 0; |
| UINT accessUnit = 0; |
| UINT numAccessUnits = 1; |
| UINT numPrerollAU = 0; |
| int fEndAuNotAdjusted = 0; /* The end of the access unit was not adjusted */ |
| int applyCrossfade = 1; /* flag indicates if flushing was possible */ |
| FIXP_PCM *pTimeDataFixpPcm; /* Signal buffer for decoding process before PCM |
| processing */ |
| INT timeDataFixpPcmSize; |
| PCM_DEC *pTimeDataPcmPost; /* Signal buffer for PCM post-processing */ |
| INT timeDataPcmPostSize; |
| |
| if (self == NULL) { |
| return AAC_DEC_INVALID_HANDLE; |
| } |
| |
| pTimeData = self->pcmOutputBuffer; |
| timeDataSize = sizeof(self->pcmOutputBuffer) / sizeof(*self->pcmOutputBuffer); |
| |
| if (flags & AACDEC_INTR) { |
| self->streamInfo.numLostAccessUnits = 0; |
| } |
| hBs = transportDec_GetBitstream(self->hInput, 0); |
| |
| /* Get current bits position for bitrate calculation. */ |
| nBits = FDKgetValidBits(hBs); |
| |
| if (flags & AACDEC_CLRHIST) { |
| if (self->flags[0] & AC_USAC) { |
| /* 1) store AudioSpecificConfig always in AudioSpecificConfig_Parse() */ |
| /* 2) free memory of dynamic allocated data */ |
| CSAudioSpecificConfig asc; |
| transportDec_GetAsc(self->hInput, 0, &asc); |
| aacDecoder_FreeMemCallback(self, &asc); |
| self->streamInfo.numChannels = 0; |
| /* 3) restore AudioSpecificConfig */ |
| transportDec_OutOfBandConfig(self->hInput, asc.config, |
| (asc.configBits + 7) >> 3, 0); |
| } |
| } |
| |
| if (!((flags & (AACDEC_CONCEAL | AACDEC_FLUSH)) || |
| (self->flushStatus == AACDEC_RSV60_DASH_IPF_ATSC_FLUSH_ON) || |
| (self->flushStatus == AACDEC_USAC_DASH_IPF_FLUSH_ON) || |
| (self->buildUpStatus == AACDEC_RSV60_BUILD_UP_IDLE_IN_BAND))) { |
| TRANSPORTDEC_ERROR err; |
| |
| for (layer = 0; layer < self->nrOfLayers; layer++) { |
| err = transportDec_ReadAccessUnit(self->hInput, layer); |
| if (err != TRANSPORTDEC_OK) { |
| switch (err) { |
| case TRANSPORTDEC_NOT_ENOUGH_BITS: |
| ErrorStatus = AAC_DEC_NOT_ENOUGH_BITS; |
| goto bail; |
| case TRANSPORTDEC_SYNC_ERROR: |
| self->streamInfo.numLostAccessUnits = |
| aacDecoder_EstimateNumberOfLostFrames(self); |
| fTpInterruption = 1; |
| break; |
| case TRANSPORTDEC_NEED_TO_RESTART: |
| ErrorStatus = AAC_DEC_NEED_TO_RESTART; |
| goto bail; |
| case TRANSPORTDEC_CRC_ERROR: |
| fTpConceal = 1; |
| break; |
| case TRANSPORTDEC_UNSUPPORTED_FORMAT: |
| ErrorStatus = AAC_DEC_UNSUPPORTED_FORMAT; |
| goto bail; |
| default: |
| ErrorStatus = AAC_DEC_UNKNOWN; |
| goto bail; |
| } |
| } |
| } |
| } else { |
| if (self->streamInfo.numLostAccessUnits > 0) { |
| self->streamInfo.numLostAccessUnits--; |
| } |
| } |
| |
| self->frameOK = 1; |
| |
| UINT prerollAUOffset[AACDEC_MAX_NUM_PREROLL_AU]; |
| UINT prerollAULength[AACDEC_MAX_NUM_PREROLL_AU]; |
| for (int i = 0; i < AACDEC_MAX_NUM_PREROLL_AU + 1; i++) |
| self->prerollAULength[i] = 0; |
| |
| INT auStartAnchor; |
| HANDLE_FDK_BITSTREAM hBsAu; |
| |
| /* Process preroll frames and current frame */ |
| do { |
| if (!(flags & (AACDEC_CONCEAL | AACDEC_FLUSH)) && |
| (self->flushStatus != AACDEC_RSV60_CFG_CHANGE_ATSC_FLUSH_ON) && |
| (accessUnit == 0) && |
| (self->hasAudioPreRoll || |
| (self->buildUpStatus == AACDEC_RSV60_BUILD_UP_IDLE_IN_BAND)) && |
| !fTpInterruption && |
| !fTpConceal /* Bit stream pointer needs to be at the beginning of a |
| (valid) AU. */ |
| ) { |
| ErrorStatus = CAacDecoder_PreRollExtensionPayloadParse( |
| self, &numPrerollAU, prerollAUOffset, prerollAULength); |
| |
| if (ErrorStatus != AAC_DEC_OK) { |
| switch (ErrorStatus) { |
| case AAC_DEC_NOT_ENOUGH_BITS: |
| goto bail; |
| case AAC_DEC_PARSE_ERROR: |
| self->frameOK = 0; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| numAccessUnits += numPrerollAU; |
| } |
| |
| hBsAu = transportDec_GetBitstream(self->hInput, 0); |
| auStartAnchor = (INT)FDKgetValidBits(hBsAu); |
| |
| self->accessUnit = accessUnit; |
| if (accessUnit < numPrerollAU) { |
| FDKpushFor(hBsAu, prerollAUOffset[accessUnit]); |
| } |
| |
| /* Signal bit stream interruption to other modules if required. */ |
| if (fTpInterruption || (flags & AACDEC_INTR)) { |
| aacDecoder_SignalInterruption(self); |
| if (!(flags & AACDEC_INTR)) { |
| ErrorStatus = AAC_DEC_TRANSPORT_SYNC_ERROR; |
| goto bail; |
| } |
| } |
| |
| /* Clearing core data will be done in CAacDecoder_DecodeFrame() below. |
| Tell other modules to clear states if required. */ |
| if (flags & AACDEC_CLRHIST) { |
| if (!(self->flags[0] & AC_USAC)) { |
| sbrDecoder_SetParam(self->hSbrDecoder, SBR_CLEAR_HISTORY, 1); |
| mpegSurroundDecoder_SetParam( |
| (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, |
| SACDEC_CLEAR_HISTORY, 1); |
| if (FDK_QmfDomain_ClearPersistentMemory(&self->qmfDomain) != 0) { |
| ErrorStatus = AAC_DEC_UNKNOWN; |
| goto bail; |
| } |
| } |
| } |
| |
| /* Empty bit buffer in case of flush request. */ |
| if (flags & AACDEC_FLUSH && !(flags & AACDEC_CONCEAL)) { |
| if (!self->flushStatus) { |
| transportDec_SetParam(self->hInput, TPDEC_PARAM_RESET, 1); |
| self->streamInfo.numLostAccessUnits = 0; |
| self->streamInfo.numBadBytes = 0; |
| self->streamInfo.numTotalBytes = 0; |
| } |
| } |
| /* Reset the output delay field. The modules will add their figures one |
| * after another. */ |
| self->streamInfo.outputDelay = 0; |
| |
| if (self->limiterEnableUser == (UCHAR)-2) { |
| /* Enable limiter only for RSVD60. */ |
| self->limiterEnableCurr = (self->flags[0] & AC_RSV603DA) ? 1 : 0; |
| } else if (self->limiterEnableUser == (UCHAR)-1) { |
| /* Enable limiter for all non-lowdelay AOT's. */ |
| self->limiterEnableCurr = (self->flags[0] & (AC_LD | AC_ELD)) ? 0 : 1; |
| } else { |
| /* Use limiter configuration as requested. */ |
| self->limiterEnableCurr = self->limiterEnableUser; |
| } |
| /* reset limiter gain on a per frame basis */ |
| self->extGain[0] = FL2FXCONST_DBL(1.0f / (float)(1 << TDL_GAIN_SCALING)); |
| |
| pTimeDataFixpPcm = pTimeData; |
| timeDataFixpPcmSize = timeDataSize; |
| |
| ErrorStatus = CAacDecoder_DecodeFrame( |
| self, |
| flags | (fTpConceal ? AACDEC_CONCEAL : 0) | |
| ((self->flushStatus && !(flags & AACDEC_CONCEAL)) ? AACDEC_FLUSH |
| : 0), |
| pTimeDataFixpPcm + 0, timeDataFixpPcmSize, |
| self->streamInfo.aacSamplesPerFrame + 0); |
| |
| /* if flushing for USAC DASH IPF was not possible go on with decoding |
| * preroll */ |
| if ((self->flags[0] & AC_USAC) && |
| (self->flushStatus == AACDEC_USAC_DASH_IPF_FLUSH_ON) && |
| !(flags & AACDEC_CONCEAL) && (ErrorStatus != AAC_DEC_OK)) { |
| applyCrossfade = 0; |
| } else /* USAC DASH IPF flushing possible begin */ |
| { |
| if (!((flags & (AACDEC_CONCEAL | AACDEC_FLUSH)) || fTpConceal || |
| self->flushStatus) && |
| (!(IS_OUTPUT_VALID(ErrorStatus)) || !(accessUnit < numPrerollAU))) { |
| TRANSPORTDEC_ERROR tpErr; |
| tpErr = transportDec_EndAccessUnit(self->hInput); |
| if (tpErr != TRANSPORTDEC_OK) { |
| self->frameOK = 0; |
| } |
| } else { /* while preroll processing later possibly an error in the |
| renderer part occurrs */ |
| if (IS_OUTPUT_VALID(ErrorStatus)) { |
| fEndAuNotAdjusted = 1; |
| } |
| } |
| |
| /* If the current pTimeDataFixpPcm does not contain a valid signal, there |
| * nothing else we can do, so bail. */ |
| if (!IS_OUTPUT_VALID(ErrorStatus)) { |
| goto bail; |
| } |
| |
| { |
| self->streamInfo.sampleRate = self->streamInfo.aacSampleRate; |
| self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame; |
| } |
| |
| self->streamInfo.numChannels = self->streamInfo.aacNumChannels; |
| |
| { |
| FDK_Delay_Apply(&self->usacResidualDelay, |
| pTimeDataFixpPcm + |
| 1 * (self->streamInfo.aacSamplesPerFrame + 0) + 0, |
| self->streamInfo.frameSize, 0); |
| } |
| |
| /* Setting of internal MPS state; may be reset in CAacDecoder_SyncQmfMode |
| if decoder is unable to decode with user defined qmfMode */ |
| if (!(self->flags[0] & (AC_USAC | AC_RSVD50 | AC_RSV603DA | AC_ELD))) { |
| self->mpsEnableCurr = |
| (self->mpsEnableUser && |
| isSupportedMpsConfig(self->streamInfo.aot, |
| self->streamInfo.numChannels, |
| (self->flags[0] & AC_MPS_PRESENT) ? 1 : 0)); |
| } |
| |
| if (!self->qmfDomain.globalConf.qmfDomainExplicitConfig && |
| self->mpsEnableCurr) { |
| /* if not done yet, allocate full MPEG Surround decoder instance */ |
| if (mpegSurroundDecoder_IsFullMpegSurroundDecoderInstanceAvailable( |
| (CMpegSurroundDecoder *)self->pMpegSurroundDecoder) == |
| SAC_INSTANCE_NOT_FULL_AVAILABLE) { |
| if (mpegSurroundDecoder_Open( |
| (CMpegSurroundDecoder **)&self->pMpegSurroundDecoder, -1, |
| &self->qmfDomain)) { |
| return AAC_DEC_OUT_OF_MEMORY; |
| } |
| } |
| } |
| |
| CAacDecoder_SyncQmfMode(self); |
| |
| if (!self->qmfDomain.globalConf.qmfDomainExplicitConfig && |
| self->mpsEnableCurr) { |
| SAC_INPUT_CONFIG sac_interface = (self->sbrEnabled && self->hSbrDecoder) |
| ? SAC_INTERFACE_QMF |
| : SAC_INTERFACE_TIME; |
| /* needs to be done before first SBR apply. */ |
| mpegSurroundDecoder_ConfigureQmfDomain( |
| (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, sac_interface, |
| (UINT)self->streamInfo.aacSampleRate, self->streamInfo.aot); |
| self->qmfDomain.globalConf.nQmfTimeSlots_requested = |
| self->streamInfo.aacSamplesPerFrame / |
| self->qmfDomain.globalConf.nBandsAnalysis_requested; |
| } |
| |
| self->qmfDomain.globalConf.TDinput = pTimeData; |
| |
| switch (FDK_QmfDomain_Configure(&self->qmfDomain)) { |
| default: |
| case QMF_DOMAIN_INIT_ERROR: |
| ErrorStatus = AAC_DEC_UNKNOWN; |
| goto bail; |
| case QMF_DOMAIN_OUT_OF_MEMORY: |
| ErrorStatus = AAC_DEC_OUT_OF_MEMORY; |
| goto bail; |
| case QMF_DOMAIN_OK: |
| break; |
| } |
| |
| /* sbr decoder */ |
| |
| if ((ErrorStatus != AAC_DEC_OK) || (flags & AACDEC_CONCEAL) || |
| self->pAacDecoderStaticChannelInfo[0]->concealmentInfo.concealState > |
| ConcealState_FadeIn) { |
| self->frameOK = 0; /* if an error has occured do concealment in the SBR |
| decoder too */ |
| } |
| |
| if (self->sbrEnabled && (!(self->flags[0] & AC_USAC_SCFGI3))) { |
| SBR_ERROR sbrError = SBRDEC_OK; |
| int chIdx, numCoreChannel = self->streamInfo.numChannels; |
| |
| /* set params */ |
| sbrDecoder_SetParam(self->hSbrDecoder, SBR_SYSTEM_BITSTREAM_DELAY, |
| self->sbrParams.bsDelay); |
| sbrDecoder_SetParam( |
| self->hSbrDecoder, SBR_FLUSH_DATA, |
| (flags & AACDEC_FLUSH) | |
| ((self->flushStatus && !(flags & AACDEC_CONCEAL)) ? AACDEC_FLUSH |
| : 0)); |
| |
| if (self->streamInfo.aot == AOT_ER_AAC_ELD) { |
| /* Configure QMF */ |
| sbrDecoder_SetParam(self->hSbrDecoder, SBR_LD_QMF_TIME_ALIGN, |
| (self->flags[0] & AC_MPS_PRESENT) ? 1 : 0); |
| } |
| |
| { |
| PCMDMX_ERROR dmxErr; |
| INT maxOutCh = 0; |
| |
| dmxErr = pcmDmx_GetParam(self->hPcmUtils, |
| MAX_NUMBER_OF_OUTPUT_CHANNELS, &maxOutCh); |
| if ((dmxErr == PCMDMX_OK) && (maxOutCh == 1)) { |
| /* Disable PS processing if we have to create a mono output signal. |
| */ |
| self->psPossible = 0; |
| } |
| } |
| |
| sbrDecoder_SetParam(self->hSbrDecoder, SBR_SKIP_QMF, |
| (self->mpsEnableCurr) ? 2 : 0); |
| |
| INT_PCM *input; |
| input = (INT_PCM *)self->workBufferCore2; |
| FDKmemcpy(input, pTimeData, |
| sizeof(INT_PCM) * (self->streamInfo.numChannels) * |
| (self->streamInfo.frameSize)); |
| |
| /* apply SBR processing */ |
| sbrError = sbrDecoder_Apply(self->hSbrDecoder, input, pTimeData, |
| timeDataSize, &self->streamInfo.numChannels, |
| &self->streamInfo.sampleRate, |
| &self->mapDescr, self->chMapIndex, |
| self->frameOK, &self->psPossible); |
| |
| if (sbrError == SBRDEC_OK) { |
| /* Update data in streaminfo structure. Assume that the SBR upsampling |
| factor is either 1, 2, 8/3 or 4. Maximum upsampling factor is 4 |
| (CELP+SBR or USAC 4:1 SBR) */ |
| self->flags[0] |= AC_SBR_PRESENT; |
| if (self->streamInfo.aacSampleRate != self->streamInfo.sampleRate) { |
| if (self->streamInfo.aacSampleRate >> 2 == |
| self->streamInfo.sampleRate) { |
| self->streamInfo.frameSize = |
| self->streamInfo.aacSamplesPerFrame >> 2; |
| self->streamInfo.outputDelay = self->streamInfo.outputDelay >> 2; |
| } else if (self->streamInfo.aacSampleRate >> 1 == |
| self->streamInfo.sampleRate) { |
| self->streamInfo.frameSize = |
| self->streamInfo.aacSamplesPerFrame >> 1; |
| self->streamInfo.outputDelay = self->streamInfo.outputDelay >> 1; |
| } else if (self->streamInfo.aacSampleRate << 1 == |
| self->streamInfo.sampleRate) { |
| self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame |
| << 1; |
| self->streamInfo.outputDelay = self->streamInfo.outputDelay << 1; |
| } else if (self->streamInfo.aacSampleRate << 2 == |
| self->streamInfo.sampleRate) { |
| self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame |
| << 2; |
| self->streamInfo.outputDelay = self->streamInfo.outputDelay << 2; |
| } else if (self->streamInfo.frameSize == 768) { |
| self->streamInfo.frameSize = |
| (self->streamInfo.aacSamplesPerFrame << 3) / 3; |
| self->streamInfo.outputDelay = |
| (self->streamInfo.outputDelay << 3) / 3; |
| } else { |
| ErrorStatus = AAC_DEC_SET_PARAM_FAIL; |
| goto bail; |
| } |
| } else { |
| self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame; |
| } |
| self->streamInfo.outputDelay += |
| sbrDecoder_GetDelay(self->hSbrDecoder); |
| |
| if (self->psPossible) { |
| self->flags[0] |= AC_PS_PRESENT; |
| } |
| for (chIdx = numCoreChannel; chIdx < self->streamInfo.numChannels; |
| chIdx += 1) { |
| self->channelType[chIdx] = ACT_FRONT; |
| self->channelIndices[chIdx] = chIdx; |
| } |
| } |
| if (sbrError == SBRDEC_OUTPUT_BUFFER_TOO_SMALL) { |
| ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL; |
| goto bail; |
| } |
| } |
| |
| if (self->mpsEnableCurr) { |
| int err, sac_interface, nChannels, frameSize; |
| |
| nChannels = self->streamInfo.numChannels; |
| frameSize = self->streamInfo.frameSize; |
| sac_interface = SAC_INTERFACE_TIME; |
| |
| if (self->sbrEnabled && self->hSbrDecoder) |
| sac_interface = SAC_INTERFACE_QMF; |
| if (self->streamInfo.aot == AOT_USAC) { |
| if (self->flags[0] & AC_USAC_SCFGI3) { |
| sac_interface = SAC_INTERFACE_TIME; |
| } |
| } |
| err = mpegSurroundDecoder_SetParam( |
| (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, |
| SACDEC_INTERFACE, sac_interface); |
| |
| if (err == 0) { |
| err = mpegSurroundDecoder_Apply( |
| (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, |
| (INT_PCM *)self->workBufferCore2, pTimeData, timeDataSize, |
| self->streamInfo.aacSamplesPerFrame, &nChannels, &frameSize, |
| self->streamInfo.sampleRate, self->streamInfo.aot, |
| self->channelType, self->channelIndices, &self->mapDescr); |
| } |
| |
| if (err == MPS_OUTPUT_BUFFER_TOO_SMALL) { |
| ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL; |
| goto bail; |
| } |
| if (err == 0) { |
| /* Update output parameter */ |
| self->streamInfo.numChannels = nChannels; |
| self->streamInfo.frameSize = frameSize; |
| self->streamInfo.outputDelay += mpegSurroundDecoder_GetDelay( |
| (CMpegSurroundDecoder *)self->pMpegSurroundDecoder); |
| /* Save current parameter for possible concealment of next frame */ |
| self->mpsOutChannelsLast = nChannels; |
| self->mpsFrameSizeLast = frameSize; |
| } else if ((self->mpsOutChannelsLast > 0) && |
| (self->mpsFrameSizeLast > 0)) { |
| /* Restore parameters of last frame ... */ |
| self->streamInfo.numChannels = self->mpsOutChannelsLast; |
| self->streamInfo.frameSize = self->mpsFrameSizeLast; |
| /* ... and clear output buffer so that potentially corrupted data does |
| * not reach the framework. */ |
| FDKmemclear(pTimeData, self->mpsOutChannelsLast * |
| self->mpsFrameSizeLast * sizeof(INT_PCM)); |
| /* Additionally proclaim that this frame had errors during decoding. |
| */ |
| ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; |
| } else { |
| ErrorStatus = AAC_DEC_UNKNOWN; /* no output */ |
| } |
| } |
| |
| /* SBR decoder for Unified Stereo Config (stereoConfigIndex == 3) */ |
| |
| if (self->sbrEnabled && (self->flags[0] & AC_USAC_SCFGI3)) { |
| SBR_ERROR sbrError = SBRDEC_OK; |
| |
| /* set params */ |
| sbrDecoder_SetParam(self->hSbrDecoder, SBR_SYSTEM_BITSTREAM_DELAY, |
| self->sbrParams.bsDelay); |
| |
| sbrDecoder_SetParam(self->hSbrDecoder, SBR_SKIP_QMF, 1); |
| |
| /* apply SBR processing */ |
| sbrError = sbrDecoder_Apply(self->hSbrDecoder, pTimeData, pTimeData, |
| timeDataSize, &self->streamInfo.numChannels, |
| &self->streamInfo.sampleRate, |
| &self->mapDescr, self->chMapIndex, |
| self->frameOK, &self->psPossible); |
| |
| if (sbrError == SBRDEC_OK) { |
| /* Update data in streaminfo structure. Assume that the SBR upsampling |
| * factor is either 1,2 or 4 */ |
| self->flags[0] |= AC_SBR_PRESENT; |
| if (self->streamInfo.aacSampleRate != self->streamInfo.sampleRate) { |
| if (self->streamInfo.frameSize == 768) { |
| self->streamInfo.frameSize = |
| (self->streamInfo.aacSamplesPerFrame * 8) / 3; |
| } else if (self->streamInfo.aacSampleRate << 2 == |
| self->streamInfo.sampleRate) { |
| self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame |
| << 2; |
| } else { |
| self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame |
| << 1; |
| } |
| } |
| |
| self->flags[0] &= ~AC_PS_PRESENT; |
| } |
| if (sbrError == SBRDEC_OUTPUT_BUFFER_TOO_SMALL) { |
| ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL; |
| goto bail; |
| } |
| } |
| |
| /* Use dedicated memory for PCM postprocessing */ |
| pTimeDataPcmPost = self->pTimeData2; |
| timeDataPcmPostSize = self->timeData2Size; |
| |
| { |
| const int size = |
| self->streamInfo.frameSize * self->streamInfo.numChannels; |
| FDK_ASSERT(timeDataPcmPostSize >= size); |
| for (int i = 0; i < size; i++) { |
| pTimeDataPcmPost[i] = |
| (PCM_DEC)FX_PCM2PCM_DEC(pTimeData[i]) >> PCM_OUT_HEADROOM; |
| } |
| } |
| |
| { |
| if ((FDK_drcDec_GetParam(self->hUniDrcDecoder, DRC_DEC_IS_ACTIVE)) && |
| !(self->flags[0] & AC_RSV603DA)) { |
| /* Apply DRC gains*/ |
| int ch, drcDelay = 0; |
| int needsDeinterleaving = 0; |
| FIXP_DBL *drcWorkBuffer = NULL; |
| FIXP_DBL channelGain[(8)]; |
| int reverseInChannelMap[(8)]; |
| int reverseOutChannelMap[(8)]; |
| int numDrcOutChannels = FDK_drcDec_GetParam( |
| self->hUniDrcDecoder, DRC_DEC_TARGET_CHANNEL_COUNT_SELECTED); |
| FDKmemclear(channelGain, sizeof(channelGain)); |
| for (ch = 0; ch < (8); ch++) { |
| reverseInChannelMap[ch] = ch; |
| reverseOutChannelMap[ch] = ch; |
| } |
| |
| /* If SBR and/or MPS is active, the DRC gains are aligned to the QMF |
| domain signal before the QMF synthesis. Therefore the DRC gains |
| need to be delayed by the QMF synthesis delay. */ |
| if (self->sbrEnabled) drcDelay = 257; |
| if (self->mpsEnableCurr) drcDelay = 257; |
| /* Take into account concealment delay */ |
| drcDelay += CConcealment_GetDelay(&self->concealCommonData) * |
| self->streamInfo.frameSize; |
| |
| for (ch = 0; ch < self->streamInfo.numChannels; ch++) { |
| UCHAR mapValue = FDK_chMapDescr_getMapValue( |
| &self->mapDescr, (UCHAR)ch, self->chMapIndex); |
| if (mapValue < (8)) reverseInChannelMap[mapValue] = ch; |
| } |
| for (ch = 0; ch < (int)numDrcOutChannels; ch++) { |
| UCHAR mapValue = FDK_chMapDescr_getMapValue( |
| &self->mapDescr, (UCHAR)ch, numDrcOutChannels); |
| if (mapValue < (8)) reverseOutChannelMap[mapValue] = ch; |
| } |
| |
| /* The output of SBR and MPS is interleaved. Deinterleaving may be |
| * necessary for FDK_drcDec_ProcessTime, which accepts deinterleaved |
| * audio only. */ |
| if ((self->streamInfo.numChannels > 1) && |
| (0 || (self->sbrEnabled) || (self->mpsEnableCurr))) { |
| /* interleaving/deinterleaving is performed on upper part of |
| * pTimeDataPcmPost. Check if this buffer is large enough. */ |
| if (timeDataPcmPostSize < |
| (INT)(2 * self->streamInfo.numChannels * |
| self->streamInfo.frameSize * sizeof(PCM_DEC))) { |
| ErrorStatus = AAC_DEC_UNKNOWN; |
| goto bail; |
| } |
| needsDeinterleaving = 1; |
| drcWorkBuffer = |
| (FIXP_DBL *)pTimeDataPcmPost + |
| self->streamInfo.numChannels * self->streamInfo.frameSize; |
| FDK_deinterleave( |
| pTimeDataPcmPost, drcWorkBuffer, self->streamInfo.numChannels, |
| self->streamInfo.frameSize, self->streamInfo.frameSize); |
| } else { |
| drcWorkBuffer = (FIXP_DBL *)pTimeDataPcmPost; |
| } |
| |
| /* prepare Loudness Normalisation gain */ |
| FDK_drcDec_SetParam(self->hUniDrcDecoder, DRC_DEC_TARGET_LOUDNESS, |
| (INT)-self->defaultTargetLoudness * |
| FL2FXCONST_DBL(1.0f / (float)(1 << 9))); |
| FDK_drcDec_SetChannelGains(self->hUniDrcDecoder, |
| self->streamInfo.numChannels, |
| self->streamInfo.frameSize, channelGain, |
| drcWorkBuffer, self->streamInfo.frameSize); |
| FDK_drcDec_Preprocess(self->hUniDrcDecoder); |
| |
| /* apply DRC1 gain sequence */ |
| for (ch = 0; ch < self->streamInfo.numChannels; ch++) { |
| FDK_drcDec_ProcessTime(self->hUniDrcDecoder, drcDelay, DRC_DEC_DRC1, |
| ch, reverseInChannelMap[ch] - ch, 1, |
| drcWorkBuffer, self->streamInfo.frameSize); |
| } |
| /* apply downmix */ |
| FDK_drcDec_ApplyDownmix( |
| self->hUniDrcDecoder, reverseInChannelMap, reverseOutChannelMap, |
| drcWorkBuffer, |
| &self->streamInfo.numChannels); /* self->streamInfo.numChannels |
| may change here */ |
| /* apply DRC2/3 gain sequence */ |
| for (ch = 0; ch < self->streamInfo.numChannels; ch++) { |
| FDK_drcDec_ProcessTime(self->hUniDrcDecoder, drcDelay, |
| DRC_DEC_DRC2_DRC3, ch, |
| reverseOutChannelMap[ch] - ch, 1, |
| drcWorkBuffer, self->streamInfo.frameSize); |
| } |
| |
| if (needsDeinterleaving) { |
| FDK_interleave( |
| drcWorkBuffer, pTimeDataPcmPost, self->streamInfo.numChannels, |
| self->streamInfo.frameSize, self->streamInfo.frameSize); |
| } |
| } |
| } |
| |
| if (self->streamInfo.extAot != AOT_AAC_SLS) { |
| INT pcmLimiterScale = 0; |
| PCMDMX_ERROR dmxErr = PCMDMX_OK; |
| if (flags & (AACDEC_INTR)) { |
| /* delete data from the past (e.g. mixdown coeficients) */ |
| pcmDmx_Reset(self->hPcmUtils, PCMDMX_RESET_BS_DATA); |
| } |
| if (flags & (AACDEC_CLRHIST)) { |
| if (!(self->flags[0] & AC_USAC)) { |
| /* delete data from the past (e.g. mixdown coeficients) */ |
| pcmDmx_Reset(self->hPcmUtils, PCMDMX_RESET_BS_DATA); |
| } |
| } |
| |
| INT interleaved = 0; |
| interleaved |= (self->sbrEnabled) ? 1 : 0; |
| interleaved |= (self->mpsEnableCurr) ? 1 : 0; |
| |
| /* do PCM post processing */ |
| dmxErr = pcmDmx_ApplyFrame( |
| self->hPcmUtils, pTimeDataPcmPost, timeDataFixpPcmSize, |
| self->streamInfo.frameSize, &self->streamInfo.numChannels, |
| interleaved, self->channelType, self->channelIndices, |
| &self->mapDescr, |
| (self->limiterEnableCurr) ? &pcmLimiterScale : NULL); |
| if (dmxErr == PCMDMX_OUTPUT_BUFFER_TOO_SMALL) { |
| ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL; |
| goto bail; |
| } |
| if ((ErrorStatus == AAC_DEC_OK) && (dmxErr == PCMDMX_INVALID_MODE)) { |
| /* Announce the framework that the current combination of channel |
| * configuration and downmix settings are not know to produce a |
| * predictable behavior and thus maybe produce strange output. */ |
| ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; |
| } |
| |
| if (flags & AACDEC_CLRHIST) { |
| if (!(self->flags[0] & AC_USAC)) { |
| /* Delete the delayed signal. */ |
| pcmLimiter_Reset(self->hLimiter); |
| } |
| } |
| |
| if (self->limiterEnableCurr) { |
| /* use workBufferCore2 buffer for interleaving */ |
| PCM_LIM *pInterleaveBuffer; |
| int blockLength = self->streamInfo.frameSize; |
| |
| /* Set actual signal parameters */ |
| pcmLimiter_SetNChannels(self->hLimiter, self->streamInfo.numChannels); |
| pcmLimiter_SetSampleRate(self->hLimiter, self->streamInfo.sampleRate); |
| pcmLimiterScale += PCM_OUT_HEADROOM; |
| |
| if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) || |
| (self->mpsEnableCurr)) { |
| pInterleaveBuffer = (PCM_LIM *)pTimeDataPcmPost; |
| } else { |
| pInterleaveBuffer = (PCM_LIM *)pTimeData; |
| /* applyLimiter requests for interleaved data */ |
| /* Interleave ouput buffer */ |
| FDK_interleave(pTimeDataPcmPost, pInterleaveBuffer, |
| self->streamInfo.numChannels, blockLength, |
| self->streamInfo.frameSize); |
| } |
| |
| pcmLimiter_Apply(self->hLimiter, pInterleaveBuffer, pTimeData, |
| self->extGain, &pcmLimiterScale, 1, |
| self->extGainDelay, self->streamInfo.frameSize); |
| |
| { |
| /* Announce the additional limiter output delay */ |
| self->streamInfo.outputDelay += pcmLimiter_GetDelay(self->hLimiter); |
| } |
| } else { |
| /* If numChannels = 1 we do not need interleaving. The same applies if |
| SBR or MPS are used, since their output is interleaved already |
| (resampled or not) */ |
| if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) || |
| (self->mpsEnableCurr)) { |
| scaleValuesSaturate( |
| pTimeData, pTimeDataPcmPost, |
| self->streamInfo.frameSize * self->streamInfo.numChannels, |
| PCM_OUT_HEADROOM); |
| |
| } else { |
| scaleValuesSaturate( |
| (INT_PCM *)self->workBufferCore2, pTimeDataPcmPost, |
| self->streamInfo.frameSize * self->streamInfo.numChannels, |
| PCM_OUT_HEADROOM); |
| /* Interleave ouput buffer */ |
| FDK_interleave((INT_PCM *)self->workBufferCore2, pTimeData, |
| self->streamInfo.numChannels, |
| self->streamInfo.frameSize, |
| self->streamInfo.frameSize); |
| } |
| } |
| } /* if (self->streamInfo.extAot != AOT_AAC_SLS)*/ |
| |
| if (self->flags[0] & AC_USAC) { |
| if (self->flushStatus == AACDEC_USAC_DASH_IPF_FLUSH_ON && |
| !(flags & AACDEC_CONCEAL)) { |
| CAacDecoder_PrepareCrossFade(pTimeData, self->pTimeDataFlush, |
| self->streamInfo.numChannels, |
| self->streamInfo.frameSize, 1); |
| } |
| |
| /* prepare crossfade buffer for fade in */ |
| if (!applyCrossfade && self->applyCrossfade && |
| !(flags & AACDEC_CONCEAL)) { |
| for (int ch = 0; ch < self->streamInfo.numChannels; ch++) { |
| for (int i = 0; i < TIME_DATA_FLUSH_SIZE; i++) { |
| self->pTimeDataFlush[ch][i] = 0; |
| } |
| } |
| applyCrossfade = 1; |
| } |
| |
| if (applyCrossfade && self->applyCrossfade && |
| !(accessUnit < numPrerollAU) && |
| (self->buildUpStatus == AACDEC_USAC_BUILD_UP_ON)) { |
| CAacDecoder_ApplyCrossFade(pTimeData, self->pTimeDataFlush, |
| self->streamInfo.numChannels, |
| self->streamInfo.frameSize, 1); |
| self->applyCrossfade = 0; |
| } |
| } |
| |
| /* Signal interruption to take effect in next frame. */ |
| if ((flags & AACDEC_FLUSH || self->flushStatus) && |
| !(flags & AACDEC_CONCEAL)) { |
| aacDecoder_SignalInterruption(self); |
| } |
| |
| /* Update externally visible copy of flags */ |
| self->streamInfo.flags = self->flags[0]; |
| |
| } /* USAC DASH IPF flushing possible end */ |
| if (accessUnit < numPrerollAU) { |
| FDKpushBack(hBsAu, auStartAnchor - (INT)FDKgetValidBits(hBsAu)); |
| } else { |
| if ((self->buildUpStatus == AACDEC_RSV60_BUILD_UP_ON) || |
| (self->buildUpStatus == AACDEC_RSV60_BUILD_UP_ON_IN_BAND) || |
| (self->buildUpStatus == AACDEC_USAC_BUILD_UP_ON)) { |
| self->buildUpCnt--; |
| |
| if (self->buildUpCnt < 0) { |
| self->buildUpStatus = 0; |
| } |
| } |
| |
| if (self->flags[0] & AC_USAC) { |
| if (self->flushStatus == AACDEC_USAC_DASH_IPF_FLUSH_ON && |
| !(flags & AACDEC_CONCEAL)) { |
| self->streamInfo.frameSize = 0; |
| } |
| } |
| } |
| |
| if (self->flushStatus != AACDEC_USAC_DASH_IPF_FLUSH_ON) { |
| accessUnit++; |
| } |
| } while ((accessUnit < numAccessUnits) || |
| ((self->flushStatus == AACDEC_USAC_DASH_IPF_FLUSH_ON) && |
| !(flags & AACDEC_CONCEAL))); |
| |
| bail: |
| |
| /* error in renderer part occurred, ErrorStatus was set to invalid output */ |
| if (fEndAuNotAdjusted && !IS_OUTPUT_VALID(ErrorStatus) && |
| (accessUnit < numPrerollAU)) { |
| transportDec_EndAccessUnit(self->hInput); |
| } |
| |
| /* Update Statistics */ |
| aacDecoder_UpdateBitStreamCounters(&self->streamInfo, hBs, nBits, |
| ErrorStatus); |
| if (((self->streamInfo.numChannels <= 0) || |
| (self->streamInfo.frameSize <= 0) || |
| (self->streamInfo.sampleRate <= 0)) && |
| IS_OUTPUT_VALID(ErrorStatus)) { |
| /* Ensure consistency of IS_OUTPUT_VALID() macro. */ |
| ErrorStatus = AAC_DEC_UNKNOWN; |
| } |
| |
| /* Check whether external output buffer is large enough. */ |
| if (timeDataSize_extern < |
| self->streamInfo.numChannels * self->streamInfo.frameSize) { |
| ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL; |
| } |
| |
| /* Update external output buffer. */ |
| if (IS_OUTPUT_VALID(ErrorStatus)) { |
| FDKmemcpy(pTimeData_extern, pTimeData, |
| self->streamInfo.numChannels * self->streamInfo.frameSize * |
| sizeof(*pTimeData)); |
| } else { |
| FDKmemclear(pTimeData_extern, |
| timeDataSize_extern * sizeof(*pTimeData_extern)); |
| } |
| |
| return ErrorStatus; |
| } |
| |
| LINKSPEC_CPP void aacDecoder_Close(HANDLE_AACDECODER self) { |
| if (self == NULL) return; |
| |
| if (self->hLimiter != NULL) { |
| pcmLimiter_Destroy(self->hLimiter); |
| } |
| |
| if (self->hPcmUtils != NULL) { |
| pcmDmx_Close(&self->hPcmUtils); |
| } |
| |
| FDK_drcDec_Close(&self->hUniDrcDecoder); |
| |
| if (self->pMpegSurroundDecoder != NULL) { |
| mpegSurroundDecoder_Close( |
| (CMpegSurroundDecoder *)self->pMpegSurroundDecoder); |
| } |
| |
| if (self->hSbrDecoder != NULL) { |
| sbrDecoder_Close(&self->hSbrDecoder); |
| } |
| |
| if (self->hInput != NULL) { |
| transportDec_Close(&self->hInput); |
| } |
| |
| CAacDecoder_Close(self); |
| } |
| |
| LINKSPEC_CPP CStreamInfo *aacDecoder_GetStreamInfo(HANDLE_AACDECODER self) { |
| return CAacDecoder_GetStreamInfo(self); |
| } |
| |
| LINKSPEC_CPP INT aacDecoder_GetLibInfo(LIB_INFO *info) { |
| int i; |
| |
| if (info == NULL) { |
| return -1; |
| } |
| |
| sbrDecoder_GetLibInfo(info); |
| mpegSurroundDecoder_GetLibInfo(info); |
| transportDec_GetLibInfo(info); |
| FDK_toolsGetLibInfo(info); |
| pcmDmx_GetLibInfo(info); |
| pcmLimiter_GetLibInfo(info); |
| FDK_drcDec_GetLibInfo(info); |
| |
| /* search for next free tab */ |
| for (i = 0; i < FDK_MODULE_LAST; i++) { |
| if (info[i].module_id == FDK_NONE) break; |
| } |
| if (i == FDK_MODULE_LAST) { |
| return -1; |
| } |
| info += i; |
| |
| info->module_id = FDK_AACDEC; |
| /* build own library info */ |
| info->version = |
| LIB_VERSION(AACDECODER_LIB_VL0, AACDECODER_LIB_VL1, AACDECODER_LIB_VL2); |
| LIB_VERSION_STRING(info); |
| info->build_date = AACDECODER_LIB_BUILD_DATE; |
| info->build_time = AACDECODER_LIB_BUILD_TIME; |
| info->title = AACDECODER_LIB_TITLE; |
| |
| /* Set flags */ |
| info->flags = 0 | CAPF_AAC_LC | CAPF_ER_AAC_LC | CAPF_ER_AAC_SCAL | |
| CAPF_AAC_VCB11 | CAPF_AAC_HCR | CAPF_AAC_RVLC | CAPF_ER_AAC_LD | |
| CAPF_ER_AAC_ELD | CAPF_AAC_CONCEALMENT | CAPF_AAC_DRC | |
| CAPF_AAC_MPEG4 | CAPF_AAC_DRM_BSFORMAT | CAPF_AAC_1024 | |
| CAPF_AAC_960 | CAPF_AAC_512 | CAPF_AAC_480 | |
| CAPF_AAC_ELD_DOWNSCALE |
| |
| | CAPF_AAC_USAC | CAPF_ER_AAC_ELDV2 | CAPF_AAC_UNIDRC; |
| /* End of flags */ |
| |
| return 0; |
| } |