| /* ----------------------------------------------------------------------------- | |
| Software License for The Fraunhofer FDK AAC Codec Library for Android | |
| © Copyright 1995 - 2020 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 | |
| ----------------------------------------------------------------------------- */ | |
| /**************************** SBR decoder library ****************************** | |
| Author(s): | |
| Description: | |
| *******************************************************************************/ | |
| /*! | |
| \file | |
| \brief SBR decoder frontend | |
| This module provides a frontend to the SBR decoder. The function openSBR() is | |
| called for initialization. The function sbrDecoder_Apply() is called for each | |
| frame. sbr_Apply() will call the required functions to decode the raw SBR data | |
| (provided by env_extr.cpp), to decode the envelope data and noise floor levels | |
| [decodeSbrData()], and to finally apply SBR to the current frame [sbr_dec()]. | |
| \sa sbrDecoder_Apply(), \ref documentationOverview | |
| */ | |
| /*! | |
| \page documentationOverview Overview of important information resources and | |
| source code documentation | |
| As part of this documentation you can find more extensive descriptions about | |
| key concepts and algorithms at the following locations: | |
| <h2>Programming</h2> | |
| \li Buffer management: sbrDecoder_Apply() and sbr_dec() | |
| \li Internal scale factors to maximize SNR on fixed point processors: | |
| #QMF_SCALE_FACTOR \li Special mantissa-exponent format: Created in | |
| requantizeEnvelopeData() and used in calculateSbrEnvelope() | |
| <h2>Algorithmic details</h2> | |
| \li About the SBR data format: \ref SBR_HEADER_ELEMENT and \ref | |
| SBR_STANDARD_ELEMENT \li Details about the bitstream decoder: env_extr.cpp \li | |
| Details about the QMF filterbank and the provided polyphase implementation: | |
| qmf_dec.cpp \li Details about the transposer: lpp_tran.cpp \li Details about | |
| the envelope adjuster: env_calc.cpp | |
| */ | |
| #include "sbrdecoder.h" | |
| #include "FDK_bitstream.h" | |
| #include "sbrdec_freq_sca.h" | |
| #include "env_extr.h" | |
| #include "sbr_dec.h" | |
| #include "env_dec.h" | |
| #include "FDK_crc.h" | |
| #include "sbr_ram.h" | |
| #include "sbr_rom.h" | |
| #include "lpp_tran.h" | |
| #include "transcendent.h" | |
| #include "sbrdec_drc.h" | |
| #include "psbitdec.h" | |
| /* Decoder library info */ | |
| #define SBRDECODER_LIB_VL0 3 | |
| #define SBRDECODER_LIB_VL1 1 | |
| #define SBRDECODER_LIB_VL2 0 | |
| #define SBRDECODER_LIB_TITLE "SBR Decoder" | |
| #ifdef SUPPRESS_BUILD_DATE_INFO | |
| #define SBRDECODER_LIB_BUILD_DATE "" | |
| #define SBRDECODER_LIB_BUILD_TIME "" | |
| #else | |
| #define SBRDECODER_LIB_BUILD_DATE __DATE__ | |
| #define SBRDECODER_LIB_BUILD_TIME __TIME__ | |
| #endif | |
| static void setFrameErrorFlag(SBR_DECODER_ELEMENT *pSbrElement, UCHAR value) { | |
| if (pSbrElement != NULL) { | |
| switch (value) { | |
| case FRAME_ERROR_ALLSLOTS: | |
| FDKmemset(pSbrElement->frameErrorFlag, FRAME_ERROR, | |
| sizeof(pSbrElement->frameErrorFlag)); | |
| break; | |
| default: | |
| pSbrElement->frameErrorFlag[pSbrElement->useFrameSlot] = value; | |
| } | |
| } | |
| } | |
| static UCHAR getHeaderSlot(UCHAR currentSlot, UCHAR hdrSlotUsage[(1) + 1]) { | |
| UINT occupied = 0; | |
| int s; | |
| UCHAR slot = hdrSlotUsage[currentSlot]; | |
| FDK_ASSERT((1) + 1 < 32); | |
| for (s = 0; s < (1) + 1; s++) { | |
| if ((hdrSlotUsage[s] == slot) && (s != slot)) { | |
| occupied = 1; | |
| break; | |
| } | |
| } | |
| if (occupied) { | |
| occupied = 0; | |
| for (s = 0; s < (1) + 1; s++) { | |
| occupied |= 1 << hdrSlotUsage[s]; | |
| } | |
| for (s = 0; s < (1) + 1; s++) { | |
| if (!(occupied & 0x1)) { | |
| slot = s; | |
| break; | |
| } | |
| occupied >>= 1; | |
| } | |
| } | |
| return slot; | |
| } | |
| static void copySbrHeader(HANDLE_SBR_HEADER_DATA hDst, | |
| const HANDLE_SBR_HEADER_DATA hSrc) { | |
| /* copy the whole header memory (including pointers) */ | |
| FDKmemcpy(hDst, hSrc, sizeof(SBR_HEADER_DATA)); | |
| /* update pointers */ | |
| hDst->freqBandData.freqBandTable[0] = hDst->freqBandData.freqBandTableLo; | |
| hDst->freqBandData.freqBandTable[1] = hDst->freqBandData.freqBandTableHi; | |
| } | |
| static int compareSbrHeader(const HANDLE_SBR_HEADER_DATA hHdr1, | |
| const HANDLE_SBR_HEADER_DATA hHdr2) { | |
| int result = 0; | |
| /* compare basic data */ | |
| result |= (hHdr1->syncState != hHdr2->syncState) ? 1 : 0; | |
| result |= (hHdr1->status != hHdr2->status) ? 1 : 0; | |
| result |= (hHdr1->frameErrorFlag != hHdr2->frameErrorFlag) ? 1 : 0; | |
| result |= (hHdr1->numberTimeSlots != hHdr2->numberTimeSlots) ? 1 : 0; | |
| result |= | |
| (hHdr1->numberOfAnalysisBands != hHdr2->numberOfAnalysisBands) ? 1 : 0; | |
| result |= (hHdr1->timeStep != hHdr2->timeStep) ? 1 : 0; | |
| result |= (hHdr1->sbrProcSmplRate != hHdr2->sbrProcSmplRate) ? 1 : 0; | |
| /* compare bitstream data */ | |
| result |= | |
| FDKmemcmp(&hHdr1->bs_data, &hHdr2->bs_data, sizeof(SBR_HEADER_DATA_BS)); | |
| result |= | |
| FDKmemcmp(&hHdr1->bs_dflt, &hHdr2->bs_dflt, sizeof(SBR_HEADER_DATA_BS)); | |
| result |= FDKmemcmp(&hHdr1->bs_info, &hHdr2->bs_info, | |
| sizeof(SBR_HEADER_DATA_BS_INFO)); | |
| /* compare frequency band data */ | |
| result |= FDKmemcmp(&hHdr1->freqBandData, &hHdr2->freqBandData, | |
| (8 + MAX_NUM_LIMITERS + 1) * sizeof(UCHAR)); | |
| result |= FDKmemcmp(hHdr1->freqBandData.freqBandTableLo, | |
| hHdr2->freqBandData.freqBandTableLo, | |
| (MAX_FREQ_COEFFS / 2 + 1) * sizeof(UCHAR)); | |
| result |= FDKmemcmp(hHdr1->freqBandData.freqBandTableHi, | |
| hHdr2->freqBandData.freqBandTableHi, | |
| (MAX_FREQ_COEFFS + 1) * sizeof(UCHAR)); | |
| result |= FDKmemcmp(hHdr1->freqBandData.freqBandTableNoise, | |
| hHdr2->freqBandData.freqBandTableNoise, | |
| (MAX_NOISE_COEFFS + 1) * sizeof(UCHAR)); | |
| result |= | |
| FDKmemcmp(hHdr1->freqBandData.v_k_master, hHdr2->freqBandData.v_k_master, | |
| (MAX_FREQ_COEFFS + 1) * sizeof(UCHAR)); | |
| return result; | |
| } | |
| /*! | |
| \brief Reset SBR decoder. | |
| Reset should only be called if SBR has been sucessfully detected by | |
| an appropriate checkForPayload() function. | |
| \return Error code. | |
| */ | |
| static SBR_ERROR sbrDecoder_ResetElement(HANDLE_SBRDECODER self, | |
| int sampleRateIn, int sampleRateOut, | |
| int samplesPerFrame, | |
| const MP4_ELEMENT_ID elementID, | |
| const int elementIndex, | |
| const int overlap) { | |
| SBR_ERROR sbrError = SBRDEC_OK; | |
| HANDLE_SBR_HEADER_DATA hSbrHeader; | |
| UINT qmfFlags = 0; | |
| int i, synDownsampleFac; | |
| /* USAC: assuming theoretical case 8 kHz output sample rate with 4:1 SBR */ | |
| const int sbr_min_sample_rate_in = IS_USAC(self->coreCodec) ? 2000 : 6400; | |
| /* Check in/out samplerates */ | |
| if (sampleRateIn < sbr_min_sample_rate_in || sampleRateIn > (96000)) { | |
| sbrError = SBRDEC_UNSUPPORTED_CONFIG; | |
| goto bail; | |
| } | |
| if (sampleRateOut > (96000)) { | |
| sbrError = SBRDEC_UNSUPPORTED_CONFIG; | |
| goto bail; | |
| } | |
| /* Set QMF mode flags */ | |
| if (self->flags & SBRDEC_LOW_POWER) qmfFlags |= QMF_FLAG_LP; | |
| if (self->coreCodec == AOT_ER_AAC_ELD) { | |
| if (self->flags & SBRDEC_LD_MPS_QMF) { | |
| qmfFlags |= QMF_FLAG_MPSLDFB; | |
| } else { | |
| qmfFlags |= QMF_FLAG_CLDFB; | |
| } | |
| } | |
| /* Set downsampling factor for synthesis filter bank */ | |
| if (sampleRateOut == 0) { | |
| /* no single rate mode */ | |
| sampleRateOut = | |
| sampleRateIn | |
| << 1; /* In case of implicit signalling, assume dual rate SBR */ | |
| } | |
| if (sampleRateIn == sampleRateOut) { | |
| synDownsampleFac = 2; | |
| self->flags |= SBRDEC_DOWNSAMPLE; | |
| } else { | |
| synDownsampleFac = 1; | |
| self->flags &= ~SBRDEC_DOWNSAMPLE; | |
| } | |
| self->synDownsampleFac = synDownsampleFac; | |
| self->sampleRateOut = sampleRateOut; | |
| { | |
| for (i = 0; i < (1) + 1; i++) { | |
| int setDflt; | |
| hSbrHeader = &(self->sbrHeader[elementIndex][i]); | |
| setDflt = ((hSbrHeader->syncState == SBR_NOT_INITIALIZED) || | |
| (self->flags & SBRDEC_FORCE_RESET)) | |
| ? 1 | |
| : 0; | |
| /* init a default header such that we can at least do upsampling later */ | |
| sbrError = initHeaderData(hSbrHeader, sampleRateIn, sampleRateOut, | |
| self->downscaleFactor, samplesPerFrame, | |
| self->flags, setDflt); | |
| /* Set synchState to UPSAMPLING in case it already is initialized */ | |
| hSbrHeader->syncState = hSbrHeader->syncState > UPSAMPLING | |
| ? UPSAMPLING | |
| : hSbrHeader->syncState; | |
| } | |
| } | |
| if (sbrError != SBRDEC_OK) { | |
| goto bail; | |
| } | |
| if (!self->pQmfDomain->globalConf.qmfDomainExplicitConfig) { | |
| self->pQmfDomain->globalConf.flags_requested |= qmfFlags; | |
| self->pQmfDomain->globalConf.nBandsAnalysis_requested = | |
| self->sbrHeader[elementIndex][0].numberOfAnalysisBands; | |
| self->pQmfDomain->globalConf.nBandsSynthesis_requested = | |
| (synDownsampleFac == 1) ? 64 : 32; /* may be overwritten by MPS */ | |
| self->pQmfDomain->globalConf.nBandsSynthesis_requested /= | |
| self->downscaleFactor; | |
| self->pQmfDomain->globalConf.nQmfTimeSlots_requested = | |
| self->sbrHeader[elementIndex][0].numberTimeSlots * | |
| self->sbrHeader[elementIndex][0].timeStep; | |
| self->pQmfDomain->globalConf.nQmfOvTimeSlots_requested = overlap; | |
| self->pQmfDomain->globalConf.nQmfProcBands_requested = 64; /* always 64 */ | |
| self->pQmfDomain->globalConf.nQmfProcChannels_requested = | |
| 1; /* may be overwritten by MPS */ | |
| } | |
| /* Init SBR channels going to be assigned to a SBR element */ | |
| { | |
| int ch; | |
| for (ch = 0; ch < self->pSbrElement[elementIndex]->nChannels; ch++) { | |
| int headerIndex = | |
| getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot, | |
| self->pSbrElement[elementIndex]->useHeaderSlot); | |
| /* and create sbrDec */ | |
| sbrError = | |
| createSbrDec(self->pSbrElement[elementIndex]->pSbrChannel[ch], | |
| &self->sbrHeader[elementIndex][headerIndex], | |
| &self->pSbrElement[elementIndex]->transposerSettings, | |
| synDownsampleFac, qmfFlags, self->flags, overlap, ch, | |
| self->codecFrameSize); | |
| if (sbrError != SBRDEC_OK) { | |
| goto bail; | |
| } | |
| } | |
| } | |
| // FDKmemclear(sbr_OverlapBuffer, sizeof(sbr_OverlapBuffer)); | |
| if (self->numSbrElements == 1) { | |
| switch (self->coreCodec) { | |
| case AOT_AAC_LC: | |
| case AOT_SBR: | |
| case AOT_PS: | |
| case AOT_ER_AAC_SCAL: | |
| case AOT_DRM_AAC: | |
| case AOT_DRM_SURROUND: | |
| if (CreatePsDec(&self->hParametricStereoDec, samplesPerFrame)) { | |
| sbrError = SBRDEC_CREATE_ERROR; | |
| goto bail; | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| /* Init frame delay slot handling */ | |
| self->pSbrElement[elementIndex]->useFrameSlot = 0; | |
| for (i = 0; i < ((1) + 1); i++) { | |
| self->pSbrElement[elementIndex]->useHeaderSlot[i] = i; | |
| } | |
| bail: | |
| return sbrError; | |
| } | |
| /*! | |
| \brief Assign QMF domain provided QMF channels to SBR channels. | |
| \return void | |
| */ | |
| static void sbrDecoder_AssignQmfChannels2SbrChannels(HANDLE_SBRDECODER self) { | |
| int ch, el, absCh_offset = 0; | |
| for (el = 0; el < self->numSbrElements; el++) { | |
| if (self->pSbrElement[el] != NULL) { | |
| for (ch = 0; ch < self->pSbrElement[el]->nChannels; ch++) { | |
| FDK_ASSERT(((absCh_offset + ch) < ((8) + (1))) && | |
| ((absCh_offset + ch) < ((8) + (1)))); | |
| self->pSbrElement[el]->pSbrChannel[ch]->SbrDec.qmfDomainInCh = | |
| &self->pQmfDomain->QmfDomainIn[absCh_offset + ch]; | |
| self->pSbrElement[el]->pSbrChannel[ch]->SbrDec.qmfDomainOutCh = | |
| &self->pQmfDomain->QmfDomainOut[absCh_offset + ch]; | |
| } | |
| absCh_offset += self->pSbrElement[el]->nChannels; | |
| } | |
| } | |
| } | |
| SBR_ERROR sbrDecoder_Open(HANDLE_SBRDECODER *pSelf, | |
| HANDLE_FDK_QMF_DOMAIN pQmfDomain) { | |
| HANDLE_SBRDECODER self = NULL; | |
| SBR_ERROR sbrError = SBRDEC_OK; | |
| int elIdx; | |
| if ((pSelf == NULL) || (pQmfDomain == NULL)) { | |
| return SBRDEC_INVALID_ARGUMENT; | |
| } | |
| /* Get memory for this instance */ | |
| self = GetRam_SbrDecoder(); | |
| if (self == NULL) { | |
| sbrError = SBRDEC_MEM_ALLOC_FAILED; | |
| goto bail; | |
| } | |
| self->pQmfDomain = pQmfDomain; | |
| /* | |
| Already zero because of calloc | |
| self->numSbrElements = 0; | |
| self->numSbrChannels = 0; | |
| self->codecFrameSize = 0; | |
| */ | |
| self->numDelayFrames = (1); /* set to the max value by default */ | |
| /* Initialize header sync state */ | |
| for (elIdx = 0; elIdx < (8); elIdx += 1) { | |
| int i; | |
| for (i = 0; i < (1) + 1; i += 1) { | |
| self->sbrHeader[elIdx][i].syncState = SBR_NOT_INITIALIZED; | |
| } | |
| } | |
| *pSelf = self; | |
| bail: | |
| return sbrError; | |
| } | |
| /** | |
| * \brief determine if the given core codec AOT can be processed or not. | |
| * \param coreCodec core codec audio object type. | |
| * \return 1 if SBR can be processed, 0 if SBR cannot be processed/applied. | |
| */ | |
| static int sbrDecoder_isCoreCodecValid(AUDIO_OBJECT_TYPE coreCodec) { | |
| switch (coreCodec) { | |
| case AOT_AAC_LC: | |
| case AOT_SBR: | |
| case AOT_PS: | |
| case AOT_ER_AAC_SCAL: | |
| case AOT_ER_AAC_ELD: | |
| case AOT_DRM_AAC: | |
| case AOT_DRM_SURROUND: | |
| case AOT_USAC: | |
| return 1; | |
| default: | |
| return 0; | |
| } | |
| } | |
| static void sbrDecoder_DestroyElement(HANDLE_SBRDECODER self, | |
| const int elementIndex) { | |
| if (self->pSbrElement[elementIndex] != NULL) { | |
| int ch; | |
| for (ch = 0; ch < SBRDEC_MAX_CH_PER_ELEMENT; ch++) { | |
| if (self->pSbrElement[elementIndex]->pSbrChannel[ch] != NULL) { | |
| deleteSbrDec(self->pSbrElement[elementIndex]->pSbrChannel[ch]); | |
| FreeRam_SbrDecChannel( | |
| &self->pSbrElement[elementIndex]->pSbrChannel[ch]); | |
| self->numSbrChannels -= 1; | |
| } | |
| } | |
| FreeRam_SbrDecElement(&self->pSbrElement[elementIndex]); | |
| self->numSbrElements -= 1; | |
| } | |
| } | |
| SBR_ERROR sbrDecoder_InitElement( | |
| HANDLE_SBRDECODER self, 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) { | |
| SBR_ERROR sbrError = SBRDEC_OK; | |
| int chCnt = 0; | |
| int nSbrElementsStart; | |
| int nSbrChannelsStart; | |
| if (self == NULL) { | |
| return SBRDEC_INVALID_ARGUMENT; | |
| } | |
| nSbrElementsStart = self->numSbrElements; | |
| nSbrChannelsStart = self->numSbrChannels; | |
| /* Check core codec AOT */ | |
| if (!sbrDecoder_isCoreCodecValid(coreCodec) || elementIndex >= (8)) { | |
| sbrError = SBRDEC_UNSUPPORTED_CONFIG; | |
| goto bail; | |
| } | |
| if (elementID != ID_SCE && elementID != ID_CPE && elementID != ID_LFE) { | |
| sbrError = SBRDEC_UNSUPPORTED_CONFIG; | |
| goto bail; | |
| } | |
| if (self->sampleRateIn == sampleRateIn && | |
| self->codecFrameSize == samplesPerFrame && self->coreCodec == coreCodec && | |
| self->pSbrElement[elementIndex] != NULL && | |
| self->pSbrElement[elementIndex]->elementID == elementID && | |
| !(self->flags & SBRDEC_FORCE_RESET) && | |
| ((sampleRateOut == 0) ? 1 : (self->sampleRateOut == sampleRateOut)) && | |
| ((harmonicSBR == 2) ? 1 | |
| : (self->harmonicSBR == | |
| harmonicSBR)) /* The value 2 signalizes that | |
| harmonicSBR shall be ignored in | |
| the config change detection */ | |
| ) { | |
| /* Nothing to do */ | |
| return SBRDEC_OK; | |
| } else { | |
| if (configMode & AC_CM_DET_CFG_CHANGE) { | |
| *configChanged = 1; | |
| } | |
| } | |
| /* reaching this point the SBR-decoder gets (re-)configured */ | |
| /* The flags field is used for all elements! */ | |
| self->flags &= | |
| (SBRDEC_FORCE_RESET | SBRDEC_FLUSH); /* Keep the global flags. They will | |
| be reset after decoding. */ | |
| self->flags |= (downscaleFactor > 1) ? SBRDEC_ELD_DOWNSCALE : 0; | |
| self->flags |= (coreCodec == AOT_ER_AAC_ELD) ? SBRDEC_ELD_GRID : 0; | |
| self->flags |= (coreCodec == AOT_ER_AAC_SCAL) ? SBRDEC_SYNTAX_SCAL : 0; | |
| self->flags |= | |
| (coreCodec == AOT_DRM_AAC) ? SBRDEC_SYNTAX_SCAL | SBRDEC_SYNTAX_DRM : 0; | |
| self->flags |= (coreCodec == AOT_DRM_SURROUND) | |
| ? SBRDEC_SYNTAX_SCAL | SBRDEC_SYNTAX_DRM | |
| : 0; | |
| self->flags |= (coreCodec == AOT_USAC) ? SBRDEC_SYNTAX_USAC : 0; | |
| /* Robustness: Take integer division rounding into consideration. E.g. 22050 | |
| * Hz with 4:1 SBR => 5512 Hz core sampling rate. */ | |
| self->flags |= (sampleRateIn == sampleRateOut / 4) ? SBRDEC_QUAD_RATE : 0; | |
| self->flags |= (harmonicSBR == 1) ? SBRDEC_USAC_HARMONICSBR : 0; | |
| if (configMode & AC_CM_DET_CFG_CHANGE) { | |
| return SBRDEC_OK; | |
| } | |
| self->sampleRateIn = sampleRateIn; | |
| self->codecFrameSize = samplesPerFrame; | |
| self->coreCodec = coreCodec; | |
| self->harmonicSBR = harmonicSBR; | |
| self->downscaleFactor = downscaleFactor; | |
| /* Init SBR elements */ | |
| { | |
| int elChannels, ch; | |
| if (self->pSbrElement[elementIndex] == NULL) { | |
| self->pSbrElement[elementIndex] = GetRam_SbrDecElement(elementIndex); | |
| if (self->pSbrElement[elementIndex] == NULL) { | |
| sbrError = SBRDEC_MEM_ALLOC_FAILED; | |
| goto bail; | |
| } | |
| self->numSbrElements++; | |
| } else { | |
| self->numSbrChannels -= self->pSbrElement[elementIndex]->nChannels; | |
| } | |
| /* Determine amount of channels for this element */ | |
| switch (elementID) { | |
| case ID_NONE: | |
| case ID_CPE: | |
| elChannels = 2; | |
| break; | |
| case ID_LFE: | |
| case ID_SCE: | |
| elChannels = 1; | |
| break; | |
| default: | |
| elChannels = 0; | |
| break; | |
| } | |
| /* Handle case of Parametric Stereo */ | |
| if (elementIndex == 0 && elementID == ID_SCE) { | |
| switch (coreCodec) { | |
| case AOT_AAC_LC: | |
| case AOT_SBR: | |
| case AOT_PS: | |
| case AOT_ER_AAC_SCAL: | |
| case AOT_DRM_AAC: | |
| case AOT_DRM_SURROUND: | |
| elChannels = 2; | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| /* Sanity check to avoid memory leaks */ | |
| if (elChannels < self->pSbrElement[elementIndex]->nChannels || | |
| (self->numSbrChannels + elChannels) > (8) + (1)) { | |
| self->numSbrChannels += self->pSbrElement[elementIndex]->nChannels; | |
| sbrError = SBRDEC_PARSE_ERROR; | |
| goto bail; | |
| } | |
| /* Save element ID for sanity checks and to have a fallback for concealment. | |
| */ | |
| self->pSbrElement[elementIndex]->elementID = elementID; | |
| self->pSbrElement[elementIndex]->nChannels = elChannels; | |
| for (ch = 0; ch < elChannels; ch++) { | |
| if (self->pSbrElement[elementIndex]->pSbrChannel[ch] == NULL) { | |
| self->pSbrElement[elementIndex]->pSbrChannel[ch] = | |
| GetRam_SbrDecChannel(chCnt); | |
| if (self->pSbrElement[elementIndex]->pSbrChannel[ch] == NULL) { | |
| sbrError = SBRDEC_MEM_ALLOC_FAILED; | |
| goto bail; | |
| } | |
| } | |
| self->numSbrChannels++; | |
| sbrDecoder_drcInitChannel(&self->pSbrElement[elementIndex] | |
| ->pSbrChannel[ch] | |
| ->SbrDec.sbrDrcChannel); | |
| chCnt++; | |
| } | |
| } | |
| if (!self->pQmfDomain->globalConf.qmfDomainExplicitConfig) { | |
| self->pQmfDomain->globalConf.nInputChannels_requested = | |
| self->numSbrChannels; | |
| self->pQmfDomain->globalConf.nOutputChannels_requested = | |
| fMax((INT)self->numSbrChannels, | |
| (INT)self->pQmfDomain->globalConf.nOutputChannels_requested); | |
| } | |
| /* Make sure each SBR channel has one QMF channel assigned even if | |
| * numSbrChannels or element set-up has changed. */ | |
| sbrDecoder_AssignQmfChannels2SbrChannels(self); | |
| /* clear error flags for all delay slots */ | |
| FDKmemclear(self->pSbrElement[elementIndex]->frameErrorFlag, | |
| ((1) + 1) * sizeof(UCHAR)); | |
| { | |
| int overlap; | |
| if (coreCodec == AOT_ER_AAC_ELD) { | |
| overlap = 0; | |
| } else if (self->flags & SBRDEC_QUAD_RATE) { | |
| overlap = (3 * 4); | |
| } else { | |
| overlap = (3 * 2); | |
| } | |
| /* Initialize this instance */ | |
| sbrError = sbrDecoder_ResetElement(self, sampleRateIn, sampleRateOut, | |
| samplesPerFrame, elementID, elementIndex, | |
| overlap); | |
| } | |
| bail: | |
| if (sbrError != SBRDEC_OK) { | |
| if ((nSbrElementsStart < self->numSbrElements) || | |
| (nSbrChannelsStart < self->numSbrChannels)) { | |
| /* Free the memory allocated for this element */ | |
| sbrDecoder_DestroyElement(self, elementIndex); | |
| } else if ((elementIndex < (8)) && | |
| (self->pSbrElement[elementIndex] != | |
| NULL)) { /* Set error flag to trigger concealment */ | |
| setFrameErrorFlag(self->pSbrElement[elementIndex], FRAME_ERROR); | |
| } | |
| } | |
| return sbrError; | |
| } | |
| /** | |
| * \brief Free config dependent SBR memory. | |
| * \param self SBR decoder instance handle | |
| */ | |
| SBR_ERROR sbrDecoder_FreeMem(HANDLE_SBRDECODER *self) { | |
| int i; | |
| int elIdx; | |
| if (self != NULL && *self != NULL) { | |
| for (i = 0; i < (8); i++) { | |
| sbrDecoder_DestroyElement(*self, i); | |
| } | |
| for (elIdx = 0; elIdx < (8); elIdx += 1) { | |
| for (i = 0; i < (1) + 1; i += 1) { | |
| (*self)->sbrHeader[elIdx][i].syncState = SBR_NOT_INITIALIZED; | |
| } | |
| } | |
| } | |
| return SBRDEC_OK; | |
| } | |
| /** | |
| * \brief Apply decoded SBR header for one element. | |
| * \param self SBR decoder instance handle | |
| * \param hSbrHeader SBR header handle to be processed. | |
| * \param hSbrChannel pointer array to the SBR element channels corresponding to | |
| * the SBR header. | |
| * \param headerStatus header status value returned from SBR header parser. | |
| * \param numElementChannels amount of channels for the SBR element whos header | |
| * is to be processed. | |
| */ | |
| static SBR_ERROR sbrDecoder_HeaderUpdate(HANDLE_SBRDECODER self, | |
| HANDLE_SBR_HEADER_DATA hSbrHeader, | |
| SBR_HEADER_STATUS headerStatus, | |
| HANDLE_SBR_CHANNEL hSbrChannel[], | |
| const int numElementChannels) { | |
| SBR_ERROR errorStatus = SBRDEC_OK; | |
| /* | |
| change of control data, reset decoder | |
| */ | |
| errorStatus = resetFreqBandTables(hSbrHeader, self->flags); | |
| if (errorStatus == SBRDEC_OK) { | |
| if (hSbrHeader->syncState == UPSAMPLING && headerStatus != HEADER_RESET) { | |
| #if (SBRDEC_MAX_HB_FADE_FRAMES > 0) | |
| int ch; | |
| for (ch = 0; ch < numElementChannels; ch += 1) { | |
| hSbrChannel[ch]->SbrDec.highBandFadeCnt = SBRDEC_MAX_HB_FADE_FRAMES; | |
| } | |
| #endif | |
| /* As the default header would limit the frequency range, | |
| lowSubband and highSubband must be patched. */ | |
| hSbrHeader->freqBandData.lowSubband = hSbrHeader->numberOfAnalysisBands; | |
| hSbrHeader->freqBandData.highSubband = hSbrHeader->numberOfAnalysisBands; | |
| } | |
| /* Trigger a reset before processing this slot */ | |
| hSbrHeader->status |= SBRDEC_HDR_STAT_RESET; | |
| } | |
| return errorStatus; | |
| } | |
| INT sbrDecoder_Header(HANDLE_SBRDECODER self, 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) { | |
| SBR_HEADER_STATUS headerStatus; | |
| HANDLE_SBR_HEADER_DATA hSbrHeader; | |
| SBR_ERROR sbrError = SBRDEC_OK; | |
| int headerIndex; | |
| UINT flagsSaved = | |
| 0; /* flags should not be changed in AC_CM_DET_CFG_CHANGE - mode after | |
| parsing */ | |
| if (self == NULL || elementIndex >= (8)) { | |
| return SBRDEC_UNSUPPORTED_CONFIG; | |
| } | |
| if (!sbrDecoder_isCoreCodecValid(coreCodec)) { | |
| return SBRDEC_UNSUPPORTED_CONFIG; | |
| } | |
| if (configMode & AC_CM_DET_CFG_CHANGE) { | |
| flagsSaved = self->flags; /* store */ | |
| } | |
| sbrError = sbrDecoder_InitElement( | |
| self, sampleRateIn, sampleRateOut, samplesPerFrame, coreCodec, elementID, | |
| elementIndex, harmonicSBR, stereoConfigIndex, configMode, configChanged, | |
| downscaleFactor); | |
| if ((sbrError != SBRDEC_OK) || (elementID == ID_LFE)) { | |
| goto bail; | |
| } | |
| if (configMode & AC_CM_DET_CFG_CHANGE) { | |
| hSbrHeader = NULL; | |
| } else { | |
| headerIndex = getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot, | |
| self->pSbrElement[elementIndex]->useHeaderSlot); | |
| hSbrHeader = &(self->sbrHeader[elementIndex][headerIndex]); | |
| } | |
| headerStatus = sbrGetHeaderData(hSbrHeader, hBs, self->flags, 0, configMode); | |
| if (coreCodec == AOT_USAC) { | |
| if (configMode & AC_CM_DET_CFG_CHANGE) { | |
| self->flags = flagsSaved; /* restore */ | |
| } | |
| return sbrError; | |
| } | |
| if (configMode & AC_CM_ALLOC_MEM) { | |
| SBR_DECODER_ELEMENT *pSbrElement; | |
| pSbrElement = self->pSbrElement[elementIndex]; | |
| /* Sanity check */ | |
| if (pSbrElement != NULL) { | |
| if ((elementID == ID_CPE && pSbrElement->nChannels != 2) || | |
| (elementID != ID_CPE && pSbrElement->nChannels != 1)) { | |
| return SBRDEC_UNSUPPORTED_CONFIG; | |
| } | |
| if (headerStatus == HEADER_RESET) { | |
| sbrError = sbrDecoder_HeaderUpdate(self, hSbrHeader, headerStatus, | |
| pSbrElement->pSbrChannel, | |
| pSbrElement->nChannels); | |
| if (sbrError == SBRDEC_OK) { | |
| hSbrHeader->syncState = SBR_HEADER; | |
| hSbrHeader->status |= SBRDEC_HDR_STAT_UPDATE; | |
| } else { | |
| hSbrHeader->syncState = SBR_NOT_INITIALIZED; | |
| hSbrHeader->status = HEADER_ERROR; | |
| } | |
| } | |
| } | |
| } | |
| bail: | |
| if (configMode & AC_CM_DET_CFG_CHANGE) { | |
| self->flags = flagsSaved; /* restore */ | |
| } | |
| return sbrError; | |
| } | |
| SBR_ERROR sbrDecoder_SetParam(HANDLE_SBRDECODER self, const SBRDEC_PARAM param, | |
| const INT value) { | |
| SBR_ERROR errorStatus = SBRDEC_OK; | |
| /* configure the subsystems */ | |
| switch (param) { | |
| case SBR_SYSTEM_BITSTREAM_DELAY: | |
| if (value < 0 || value > (1)) { | |
| errorStatus = SBRDEC_SET_PARAM_FAIL; | |
| break; | |
| } | |
| if (self == NULL) { | |
| errorStatus = SBRDEC_NOT_INITIALIZED; | |
| } else { | |
| self->numDelayFrames = (UCHAR)value; | |
| } | |
| break; | |
| case SBR_QMF_MODE: | |
| if (self == NULL) { | |
| errorStatus = SBRDEC_NOT_INITIALIZED; | |
| } else { | |
| if (value == 1) { | |
| self->flags |= SBRDEC_LOW_POWER; | |
| } else { | |
| self->flags &= ~SBRDEC_LOW_POWER; | |
| } | |
| } | |
| break; | |
| case SBR_LD_QMF_TIME_ALIGN: | |
| if (self == NULL) { | |
| errorStatus = SBRDEC_NOT_INITIALIZED; | |
| } else { | |
| if (value == 1) { | |
| self->flags |= SBRDEC_LD_MPS_QMF; | |
| } else { | |
| self->flags &= ~SBRDEC_LD_MPS_QMF; | |
| } | |
| } | |
| break; | |
| case SBR_FLUSH_DATA: | |
| if (value != 0) { | |
| if (self == NULL) { | |
| errorStatus = SBRDEC_NOT_INITIALIZED; | |
| } else { | |
| self->flags |= SBRDEC_FLUSH; | |
| } | |
| } | |
| break; | |
| case SBR_CLEAR_HISTORY: | |
| if (value != 0) { | |
| if (self == NULL) { | |
| errorStatus = SBRDEC_NOT_INITIALIZED; | |
| } else { | |
| self->flags |= SBRDEC_FORCE_RESET; | |
| } | |
| } | |
| break; | |
| case SBR_BS_INTERRUPTION: { | |
| int elementIndex; | |
| if (self == NULL) { | |
| errorStatus = SBRDEC_NOT_INITIALIZED; | |
| break; | |
| } | |
| /* Loop over SBR elements */ | |
| for (elementIndex = 0; elementIndex < self->numSbrElements; | |
| elementIndex++) { | |
| if (self->pSbrElement[elementIndex] != NULL) { | |
| HANDLE_SBR_HEADER_DATA hSbrHeader; | |
| int headerIndex = | |
| getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot, | |
| self->pSbrElement[elementIndex]->useHeaderSlot); | |
| hSbrHeader = &(self->sbrHeader[elementIndex][headerIndex]); | |
| /* Set sync state UPSAMPLING for the corresponding slot. | |
| This switches off bitstream parsing until a new header arrives. */ | |
| hSbrHeader->syncState = UPSAMPLING; | |
| hSbrHeader->status |= SBRDEC_HDR_STAT_UPDATE; | |
| } | |
| } | |
| } break; | |
| case SBR_SKIP_QMF: | |
| if (self == NULL) { | |
| errorStatus = SBRDEC_NOT_INITIALIZED; | |
| } else { | |
| if (value == 1) { | |
| self->flags |= SBRDEC_SKIP_QMF_ANA; | |
| } else { | |
| self->flags &= ~SBRDEC_SKIP_QMF_ANA; | |
| } | |
| if (value == 2) { | |
| self->flags |= SBRDEC_SKIP_QMF_SYN; | |
| } else { | |
| self->flags &= ~SBRDEC_SKIP_QMF_SYN; | |
| } | |
| } | |
| break; | |
| default: | |
| errorStatus = SBRDEC_SET_PARAM_FAIL; | |
| break; | |
| } /* switch(param) */ | |
| return (errorStatus); | |
| } | |
| static SBRDEC_DRC_CHANNEL *sbrDecoder_drcGetChannel( | |
| const HANDLE_SBRDECODER self, const INT channel) { | |
| SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL; | |
| int elementIndex, elChanIdx = 0, numCh = 0; | |
| for (elementIndex = 0; (elementIndex < (8)) && (numCh <= channel); | |
| elementIndex++) { | |
| SBR_DECODER_ELEMENT *pSbrElement = self->pSbrElement[elementIndex]; | |
| int c, elChannels; | |
| elChanIdx = 0; | |
| if (pSbrElement == NULL) break; | |
| /* Determine amount of channels for this element */ | |
| switch (pSbrElement->elementID) { | |
| case ID_CPE: | |
| elChannels = 2; | |
| break; | |
| case ID_LFE: | |
| case ID_SCE: | |
| elChannels = 1; | |
| break; | |
| case ID_NONE: | |
| default: | |
| elChannels = 0; | |
| break; | |
| } | |
| /* Limit with actual allocated element channels */ | |
| elChannels = fMin(elChannels, pSbrElement->nChannels); | |
| for (c = 0; (c < elChannels) && (numCh <= channel); c++) { | |
| if (pSbrElement->pSbrChannel[elChanIdx] != NULL) { | |
| numCh++; | |
| elChanIdx++; | |
| } | |
| } | |
| } | |
| elementIndex -= 1; | |
| elChanIdx -= 1; | |
| if (elChanIdx < 0 || elementIndex < 0) { | |
| return NULL; | |
| } | |
| if (self->pSbrElement[elementIndex] != NULL) { | |
| if (self->pSbrElement[elementIndex]->pSbrChannel[elChanIdx] != NULL) { | |
| pSbrDrcChannelData = &self->pSbrElement[elementIndex] | |
| ->pSbrChannel[elChanIdx] | |
| ->SbrDec.sbrDrcChannel; | |
| } | |
| } | |
| return (pSbrDrcChannelData); | |
| } | |
| SBR_ERROR sbrDecoder_drcFeedChannel(HANDLE_SBRDECODER self, INT ch, | |
| UINT numBands, FIXP_DBL *pNextFact_mag, | |
| INT nextFact_exp, | |
| SHORT drcInterpolationScheme, | |
| UCHAR winSequence, USHORT *pBandTop) { | |
| SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL; | |
| int band, isValidData = 0; | |
| if (self == NULL) { | |
| return SBRDEC_NOT_INITIALIZED; | |
| } | |
| if (ch > (8) || pNextFact_mag == NULL) { | |
| return SBRDEC_SET_PARAM_FAIL; | |
| } | |
| /* Search for gain values different to 1.0f */ | |
| for (band = 0; band < (int)numBands; band += 1) { | |
| if (!((pNextFact_mag[band] == FL2FXCONST_DBL(0.5)) && | |
| (nextFact_exp == 1)) && | |
| !((pNextFact_mag[band] == (FIXP_DBL)MAXVAL_DBL) && | |
| (nextFact_exp == 0))) { | |
| isValidData = 1; | |
| break; | |
| } | |
| } | |
| /* Find the right SBR channel */ | |
| pSbrDrcChannelData = sbrDecoder_drcGetChannel(self, ch); | |
| if (pSbrDrcChannelData != NULL) { | |
| if (pSbrDrcChannelData->enable || | |
| isValidData) { /* Activate processing only with real and valid data */ | |
| int i; | |
| pSbrDrcChannelData->enable = 1; | |
| pSbrDrcChannelData->numBandsNext = numBands; | |
| pSbrDrcChannelData->winSequenceNext = winSequence; | |
| pSbrDrcChannelData->drcInterpolationSchemeNext = drcInterpolationScheme; | |
| pSbrDrcChannelData->nextFact_exp = nextFact_exp; | |
| for (i = 0; i < (int)numBands; i++) { | |
| pSbrDrcChannelData->bandTopNext[i] = pBandTop[i]; | |
| pSbrDrcChannelData->nextFact_mag[i] = pNextFact_mag[i]; | |
| } | |
| } | |
| } | |
| return SBRDEC_OK; | |
| } | |
| void sbrDecoder_drcDisable(HANDLE_SBRDECODER self, INT ch) { | |
| SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL; | |
| if ((self == NULL) || (ch > (8)) || (self->numSbrElements == 0) || | |
| (self->numSbrChannels == 0)) { | |
| return; | |
| } | |
| /* Find the right SBR channel */ | |
| pSbrDrcChannelData = sbrDecoder_drcGetChannel(self, ch); | |
| if (pSbrDrcChannelData != NULL) { | |
| sbrDecoder_drcInitChannel(pSbrDrcChannelData); | |
| } | |
| } | |
| SBR_ERROR sbrDecoder_Parse(HANDLE_SBRDECODER self, HANDLE_FDK_BITSTREAM hBs, | |
| UCHAR *pDrmBsBuffer, USHORT drmBsBufferSize, | |
| int *count, int bsPayLen, int crcFlag, | |
| MP4_ELEMENT_ID prevElement, int elementIndex, | |
| UINT acFlags, UINT acElFlags[]) { | |
| SBR_DECODER_ELEMENT *hSbrElement = NULL; | |
| HANDLE_SBR_HEADER_DATA hSbrHeader = NULL; | |
| HANDLE_SBR_CHANNEL *pSbrChannel; | |
| SBR_FRAME_DATA *hFrameDataLeft = NULL; | |
| SBR_FRAME_DATA *hFrameDataRight = NULL; | |
| SBR_FRAME_DATA frameDataLeftCopy; | |
| SBR_FRAME_DATA frameDataRightCopy; | |
| SBR_ERROR errorStatus = SBRDEC_OK; | |
| SBR_HEADER_STATUS headerStatus = HEADER_NOT_PRESENT; | |
| INT startPos = FDKgetValidBits(hBs); | |
| FDK_CRCINFO crcInfo; | |
| INT crcReg = 0; | |
| USHORT sbrCrc = 0; | |
| UINT crcPoly; | |
| UINT crcStartValue = 0; | |
| UINT crcLen; | |
| HANDLE_FDK_BITSTREAM hBsOriginal = hBs; | |
| FDK_BITSTREAM bsBwd; | |
| const int fGlobalIndependencyFlag = acFlags & AC_INDEP; | |
| const int bs_pvc = acElFlags[elementIndex] & AC_EL_USAC_PVC; | |
| const int bs_interTes = acElFlags[elementIndex] & AC_EL_USAC_ITES; | |
| int stereo; | |
| int fDoDecodeSbrData = 1; | |
| int alignBits = 0; | |
| int lastSlot, lastHdrSlot = 0, thisHdrSlot = 0; | |
| if (*count <= 0) { | |
| setFrameErrorFlag(self->pSbrElement[elementIndex], FRAME_ERROR); | |
| return SBRDEC_OK; | |
| } | |
| /* SBR sanity checks */ | |
| if (self == NULL) { | |
| errorStatus = SBRDEC_NOT_INITIALIZED; | |
| goto bail; | |
| } | |
| /* Reverse bits of DRM SBR payload */ | |
| if ((self->flags & SBRDEC_SYNTAX_DRM) && *count > 0) { | |
| int dataBytes, dataBits; | |
| FDK_ASSERT(drmBsBufferSize >= (512)); | |
| dataBits = *count; | |
| if (dataBits > ((512) * 8)) { | |
| /* do not flip more data than needed */ | |
| dataBits = (512) * 8; | |
| } | |
| dataBytes = (dataBits + 7) >> 3; | |
| int j; | |
| if ((j = (int)FDKgetValidBits(hBs)) != 8) { | |
| FDKpushBiDirectional(hBs, (j - 8)); | |
| } | |
| j = 0; | |
| for (; dataBytes > 0; dataBytes--) { | |
| int i; | |
| UCHAR tmpByte; | |
| UCHAR buffer = 0x00; | |
| tmpByte = (UCHAR)FDKreadBits(hBs, 8); | |
| for (i = 0; i < 4; i++) { | |
| int shift = 2 * i + 1; | |
| buffer |= (tmpByte & (0x08 >> i)) << shift; | |
| buffer |= (tmpByte & (0x10 << i)) >> shift; | |
| } | |
| pDrmBsBuffer[j++] = buffer; | |
| FDKpushBack(hBs, 16); | |
| } | |
| FDKinitBitStream(&bsBwd, pDrmBsBuffer, (512), dataBits, BS_READER); | |
| /* Use reversed data */ | |
| hBs = &bsBwd; | |
| bsPayLen = *count; | |
| } | |
| /* Remember start position of SBR element */ | |
| startPos = FDKgetValidBits(hBs); | |
| /* SBR sanity checks */ | |
| if (self->pSbrElement[elementIndex] == NULL) { | |
| errorStatus = SBRDEC_NOT_INITIALIZED; | |
| goto bail; | |
| } | |
| hSbrElement = self->pSbrElement[elementIndex]; | |
| lastSlot = (hSbrElement->useFrameSlot > 0) ? hSbrElement->useFrameSlot - 1 | |
| : self->numDelayFrames; | |
| lastHdrSlot = hSbrElement->useHeaderSlot[lastSlot]; | |
| thisHdrSlot = getHeaderSlot( | |
| hSbrElement->useFrameSlot, | |
| hSbrElement->useHeaderSlot); /* Get a free header slot not used by | |
| frames not processed yet. */ | |
| /* Assign the free slot to store a new header if there is one. */ | |
| hSbrHeader = &self->sbrHeader[elementIndex][thisHdrSlot]; | |
| pSbrChannel = hSbrElement->pSbrChannel; | |
| stereo = (hSbrElement->elementID == ID_CPE) ? 1 : 0; | |
| hFrameDataLeft = &self->pSbrElement[elementIndex] | |
| ->pSbrChannel[0] | |
| ->frameData[hSbrElement->useFrameSlot]; | |
| if (stereo) { | |
| hFrameDataRight = &self->pSbrElement[elementIndex] | |
| ->pSbrChannel[1] | |
| ->frameData[hSbrElement->useFrameSlot]; | |
| } | |
| /* store frameData; new parsed frameData possibly corrupted */ | |
| FDKmemcpy(&frameDataLeftCopy, hFrameDataLeft, sizeof(SBR_FRAME_DATA)); | |
| if (stereo) { | |
| FDKmemcpy(&frameDataRightCopy, hFrameDataRight, sizeof(SBR_FRAME_DATA)); | |
| } | |
| /* reset PS flag; will be set after PS was found */ | |
| self->flags &= ~SBRDEC_PS_DECODED; | |
| if (hSbrHeader->status & SBRDEC_HDR_STAT_UPDATE) { | |
| /* Got a new header from extern (e.g. from an ASC) */ | |
| headerStatus = HEADER_OK; | |
| hSbrHeader->status &= ~SBRDEC_HDR_STAT_UPDATE; | |
| } else if (thisHdrSlot != lastHdrSlot) { | |
| /* Copy the last header into this slot otherwise the | |
| header compare will trigger more HEADER_RESETs than needed. */ | |
| copySbrHeader(hSbrHeader, &self->sbrHeader[elementIndex][lastHdrSlot]); | |
| } | |
| /* | |
| Check if bit stream data is valid and matches the element context | |
| */ | |
| if (((prevElement != ID_SCE) && (prevElement != ID_CPE)) || | |
| prevElement != hSbrElement->elementID) { | |
| /* In case of LFE we also land here, since there is no LFE SBR element (do | |
| * upsampling only) */ | |
| fDoDecodeSbrData = 0; | |
| } | |
| if (fDoDecodeSbrData) { | |
| if ((INT)FDKgetValidBits(hBs) <= 0) { | |
| fDoDecodeSbrData = 0; | |
| } | |
| } | |
| /* | |
| SBR CRC-check | |
| */ | |
| if (fDoDecodeSbrData) { | |
| if (crcFlag) { | |
| switch (self->coreCodec) { | |
| case AOT_DRM_AAC: | |
| case AOT_DRM_SURROUND: | |
| crcPoly = 0x001d; | |
| crcLen = 8; | |
| crcStartValue = 0x000000ff; | |
| break; | |
| default: | |
| crcPoly = 0x0633; | |
| crcLen = 10; | |
| crcStartValue = 0x00000000; | |
| break; | |
| } | |
| sbrCrc = (USHORT)FDKreadBits(hBs, crcLen); | |
| /* Setup CRC decoder */ | |
| FDKcrcInit(&crcInfo, crcPoly, crcStartValue, crcLen); | |
| /* Start CRC region */ | |
| crcReg = FDKcrcStartReg(&crcInfo, hBs, 0); | |
| } | |
| } /* if (fDoDecodeSbrData) */ | |
| /* | |
| Read in the header data and issue a reset if change occured | |
| */ | |
| if (fDoDecodeSbrData) { | |
| int sbrHeaderPresent; | |
| if (self->flags & (SBRDEC_SYNTAX_RSVD50 | SBRDEC_SYNTAX_USAC)) { | |
| SBR_HEADER_DATA_BS_INFO newSbrInfo; | |
| int sbrInfoPresent; | |
| if (bs_interTes) { | |
| self->flags |= SBRDEC_USAC_ITES; | |
| } else { | |
| self->flags &= ~SBRDEC_USAC_ITES; | |
| } | |
| if (fGlobalIndependencyFlag) { | |
| self->flags |= SBRDEC_USAC_INDEP; | |
| sbrInfoPresent = 1; | |
| sbrHeaderPresent = 1; | |
| } else { | |
| self->flags &= ~SBRDEC_USAC_INDEP; | |
| sbrInfoPresent = FDKreadBit(hBs); | |
| if (sbrInfoPresent) { | |
| sbrHeaderPresent = FDKreadBit(hBs); | |
| } else { | |
| sbrHeaderPresent = 0; | |
| } | |
| } | |
| if (sbrInfoPresent) { | |
| newSbrInfo.ampResolution = FDKreadBit(hBs); | |
| newSbrInfo.xover_band = FDKreadBits(hBs, 4); | |
| newSbrInfo.sbr_preprocessing = FDKreadBit(hBs); | |
| if (bs_pvc) { | |
| newSbrInfo.pvc_mode = FDKreadBits(hBs, 2); | |
| /* bs_pvc_mode: 0 -> no PVC, 1 -> PVC mode 1, 2 -> PVC mode 2, 3 -> | |
| * reserved */ | |
| if (newSbrInfo.pvc_mode > 2) { | |
| headerStatus = HEADER_ERROR; | |
| } | |
| if (stereo && newSbrInfo.pvc_mode > 0) { | |
| /* bs_pvc is always transmitted but pvc_mode is set to zero in case | |
| * of stereo SBR. The config might be wrong but we cannot tell for | |
| * sure. */ | |
| newSbrInfo.pvc_mode = 0; | |
| } | |
| } else { | |
| newSbrInfo.pvc_mode = 0; | |
| } | |
| if (headerStatus != HEADER_ERROR) { | |
| if (FDKmemcmp(&hSbrHeader->bs_info, &newSbrInfo, | |
| sizeof(SBR_HEADER_DATA_BS_INFO))) { | |
| /* in case of ampResolution and preprocessing change no full reset | |
| * required */ | |
| /* HEADER reset would trigger HBE transposer reset which breaks | |
| * eSbr_3_Eaa.mp4 */ | |
| if ((hSbrHeader->bs_info.pvc_mode != newSbrInfo.pvc_mode) || | |
| (hSbrHeader->bs_info.xover_band != newSbrInfo.xover_band)) { | |
| headerStatus = HEADER_RESET; | |
| } else { | |
| headerStatus = HEADER_OK; | |
| } | |
| hSbrHeader->bs_info = newSbrInfo; | |
| } else { | |
| headerStatus = HEADER_OK; | |
| } | |
| } | |
| } | |
| if (headerStatus == HEADER_ERROR) { | |
| /* Corrupt SBR info data, do not decode and switch to UPSAMPLING */ | |
| hSbrHeader->syncState = UPSAMPLING; | |
| fDoDecodeSbrData = 0; | |
| sbrHeaderPresent = 0; | |
| } | |
| if (sbrHeaderPresent && fDoDecodeSbrData) { | |
| int useDfltHeader; | |
| useDfltHeader = FDKreadBit(hBs); | |
| if (useDfltHeader) { | |
| sbrHeaderPresent = 0; | |
| if (FDKmemcmp(&hSbrHeader->bs_data, &hSbrHeader->bs_dflt, | |
| sizeof(SBR_HEADER_DATA_BS)) || | |
| hSbrHeader->syncState != SBR_ACTIVE) { | |
| hSbrHeader->bs_data = hSbrHeader->bs_dflt; | |
| headerStatus = HEADER_RESET; | |
| } | |
| } | |
| } | |
| } else { | |
| sbrHeaderPresent = FDKreadBit(hBs); | |
| } | |
| if (sbrHeaderPresent) { | |
| headerStatus = sbrGetHeaderData(hSbrHeader, hBs, self->flags, 1, 0); | |
| } | |
| if (headerStatus == HEADER_RESET) { | |
| errorStatus = sbrDecoder_HeaderUpdate( | |
| self, hSbrHeader, headerStatus, pSbrChannel, hSbrElement->nChannels); | |
| if (errorStatus == SBRDEC_OK) { | |
| hSbrHeader->syncState = SBR_HEADER; | |
| } else { | |
| hSbrHeader->syncState = SBR_NOT_INITIALIZED; | |
| headerStatus = HEADER_ERROR; | |
| } | |
| } | |
| if (errorStatus != SBRDEC_OK) { | |
| fDoDecodeSbrData = 0; | |
| } | |
| } /* if (fDoDecodeSbrData) */ | |
| /* | |
| Print debugging output only if state has changed | |
| */ | |
| /* read frame data */ | |
| if ((hSbrHeader->syncState >= SBR_HEADER) && fDoDecodeSbrData) { | |
| int sbrFrameOk; | |
| /* read the SBR element data */ | |
| if (!stereo && (self->hParametricStereoDec != NULL)) { | |
| /* update slot index for PS bitstream parsing */ | |
| self->hParametricStereoDec->bsLastSlot = | |
| self->hParametricStereoDec->bsReadSlot; | |
| self->hParametricStereoDec->bsReadSlot = hSbrElement->useFrameSlot; | |
| } | |
| sbrFrameOk = sbrGetChannelElement( | |
| hSbrHeader, hFrameDataLeft, (stereo) ? hFrameDataRight : NULL, | |
| &pSbrChannel[0]->prevFrameData, | |
| pSbrChannel[0]->SbrDec.PvcStaticData.pvc_mode_last, hBs, | |
| (stereo) ? NULL : self->hParametricStereoDec, self->flags, | |
| self->pSbrElement[elementIndex]->transposerSettings.overlap); | |
| if (!sbrFrameOk) { | |
| fDoDecodeSbrData = 0; | |
| } else { | |
| INT valBits; | |
| if (bsPayLen > 0) { | |
| valBits = bsPayLen - ((INT)startPos - (INT)FDKgetValidBits(hBs)); | |
| } else { | |
| valBits = (INT)FDKgetValidBits(hBs); | |
| } | |
| /* sanity check of remaining bits */ | |
| if (valBits < 0) { | |
| fDoDecodeSbrData = 0; | |
| } else { | |
| switch (self->coreCodec) { | |
| case AOT_SBR: | |
| case AOT_PS: | |
| case AOT_AAC_LC: { | |
| /* This sanity check is only meaningful with General Audio | |
| * bitstreams */ | |
| alignBits = valBits & 0x7; | |
| if (valBits > alignBits) { | |
| fDoDecodeSbrData = 0; | |
| } | |
| } break; | |
| default: | |
| /* No sanity check available */ | |
| break; | |
| } | |
| } | |
| } | |
| } else { | |
| /* The returned bit count will not be the actual payload size since we did | |
| not parse the frame data. Return an error so that the caller can react | |
| respectively. */ | |
| errorStatus = SBRDEC_PARSE_ERROR; | |
| } | |
| if (crcFlag && (hSbrHeader->syncState >= SBR_HEADER) && fDoDecodeSbrData) { | |
| FDKpushFor(hBs, alignBits); | |
| FDKcrcEndReg(&crcInfo, hBs, crcReg); /* End CRC region */ | |
| FDKpushBack(hBs, alignBits); | |
| /* Check CRC */ | |
| if ((FDKcrcGetCRC(&crcInfo) ^ crcStartValue) != sbrCrc) { | |
| fDoDecodeSbrData = 0; | |
| if (headerStatus != HEADER_NOT_PRESENT) { | |
| headerStatus = HEADER_ERROR; | |
| hSbrHeader->syncState = SBR_NOT_INITIALIZED; | |
| } | |
| } | |
| } | |
| if (!fDoDecodeSbrData) { | |
| /* Set error flag for this slot to trigger concealment */ | |
| setFrameErrorFlag(self->pSbrElement[elementIndex], FRAME_ERROR); | |
| /* restore old frameData for concealment */ | |
| FDKmemcpy(hFrameDataLeft, &frameDataLeftCopy, sizeof(SBR_FRAME_DATA)); | |
| if (stereo) { | |
| FDKmemcpy(hFrameDataRight, &frameDataRightCopy, sizeof(SBR_FRAME_DATA)); | |
| } | |
| errorStatus = SBRDEC_PARSE_ERROR; | |
| } else { | |
| /* Everything seems to be ok so clear the error flag */ | |
| setFrameErrorFlag(self->pSbrElement[elementIndex], FRAME_OK); | |
| } | |
| if (!stereo) { | |
| /* Turn coupling off explicitely to avoid access to absent right frame data | |
| that might occur with corrupt bitstreams. */ | |
| hFrameDataLeft->coupling = COUPLING_OFF; | |
| } | |
| bail: | |
| if (self != NULL) { | |
| if (self->flags & SBRDEC_SYNTAX_DRM) { | |
| hBs = hBsOriginal; | |
| } | |
| if (errorStatus != SBRDEC_NOT_INITIALIZED) { | |
| int useOldHdr = | |
| ((headerStatus == HEADER_NOT_PRESENT) || | |
| (headerStatus == HEADER_ERROR) || | |
| (headerStatus == HEADER_RESET && errorStatus == SBRDEC_PARSE_ERROR)) | |
| ? 1 | |
| : 0; | |
| if (!useOldHdr && (thisHdrSlot != lastHdrSlot) && (hSbrHeader != NULL)) { | |
| useOldHdr |= | |
| (compareSbrHeader(hSbrHeader, | |
| &self->sbrHeader[elementIndex][lastHdrSlot]) == 0) | |
| ? 1 | |
| : 0; | |
| } | |
| if (hSbrElement != NULL) { | |
| if (useOldHdr != 0) { | |
| /* Use the old header for this frame */ | |
| hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot] = lastHdrSlot; | |
| } else { | |
| /* Use the new header for this frame */ | |
| hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot] = thisHdrSlot; | |
| } | |
| /* Move frame pointer to the next slot which is up to be decoded/applied | |
| * next */ | |
| hSbrElement->useFrameSlot = | |
| (hSbrElement->useFrameSlot + 1) % (self->numDelayFrames + 1); | |
| } | |
| } | |
| } | |
| *count -= startPos - (INT)FDKgetValidBits(hBs); | |
| return errorStatus; | |
| } | |
| /** | |
| * \brief Render one SBR element into time domain signal. | |
| * \param self SBR decoder handle | |
| * \param timeData pointer to output buffer | |
| * \param channelMapping pointer to UCHAR array where next 2 channel offsets are | |
| * stored. | |
| * \param elementIndex enumerating index of the SBR element to render. | |
| * \param numInChannels number of channels from core coder. | |
| * \param numOutChannels pointer to a location to return number of output | |
| * channels. | |
| * \param psPossible flag indicating if PS is possible or not. | |
| * \return SBRDEC_OK if successfull, else error code | |
| */ | |
| static SBR_ERROR sbrDecoder_DecodeElement( | |
| HANDLE_SBRDECODER self, LONG *input, LONG *timeData, const int timeDataSize, | |
| const FDK_channelMapDescr *const mapDescr, const int mapIdx, | |
| int channelIndex, const int elementIndex, const int numInChannels, | |
| int *numOutChannels, const int psPossible) { | |
| SBR_DECODER_ELEMENT *hSbrElement = self->pSbrElement[elementIndex]; | |
| HANDLE_SBR_CHANNEL *pSbrChannel = | |
| self->pSbrElement[elementIndex]->pSbrChannel; | |
| HANDLE_SBR_HEADER_DATA hSbrHeader = | |
| &self->sbrHeader[elementIndex] | |
| [hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot]]; | |
| HANDLE_PS_DEC h_ps_d = self->hParametricStereoDec; | |
| /* get memory for frame data from scratch */ | |
| SBR_FRAME_DATA *hFrameDataLeft = NULL; | |
| SBR_FRAME_DATA *hFrameDataRight = NULL; | |
| SBR_ERROR errorStatus = SBRDEC_OK; | |
| INT strideOut, offset0 = 255, offset0_block = 0, offset1 = 255, | |
| offset1_block = 0; | |
| INT codecFrameSize = self->codecFrameSize; | |
| int stereo = (hSbrElement->elementID == ID_CPE) ? 1 : 0; | |
| int numElementChannels = | |
| hSbrElement | |
| ->nChannels; /* Number of channels of the current SBR element */ | |
| hFrameDataLeft = | |
| &hSbrElement->pSbrChannel[0]->frameData[hSbrElement->useFrameSlot]; | |
| if (stereo) { | |
| hFrameDataRight = | |
| &hSbrElement->pSbrChannel[1]->frameData[hSbrElement->useFrameSlot]; | |
| } | |
| if (self->flags & SBRDEC_FLUSH) { | |
| if (self->numFlushedFrames > self->numDelayFrames) { | |
| int hdrIdx; | |
| /* No valid SBR payload available, hence switch to upsampling (in all | |
| * headers) */ | |
| for (hdrIdx = 0; hdrIdx < ((1) + 1); hdrIdx += 1) { | |
| self->sbrHeader[elementIndex][hdrIdx].syncState = UPSAMPLING; | |
| } | |
| } else { | |
| /* Move frame pointer to the next slot which is up to be decoded/applied | |
| * next */ | |
| hSbrElement->useFrameSlot = | |
| (hSbrElement->useFrameSlot + 1) % (self->numDelayFrames + 1); | |
| /* Update header and frame data pointer because they have already been set | |
| */ | |
| hSbrHeader = | |
| &self->sbrHeader[elementIndex] | |
| [hSbrElement | |
| ->useHeaderSlot[hSbrElement->useFrameSlot]]; | |
| hFrameDataLeft = | |
| &hSbrElement->pSbrChannel[0]->frameData[hSbrElement->useFrameSlot]; | |
| if (stereo) { | |
| hFrameDataRight = | |
| &hSbrElement->pSbrChannel[1]->frameData[hSbrElement->useFrameSlot]; | |
| } | |
| } | |
| } | |
| /* Update the header error flag */ | |
| hSbrHeader->frameErrorFlag = | |
| hSbrElement->frameErrorFlag[hSbrElement->useFrameSlot]; | |
| /* | |
| Prepare filterbank for upsampling if no valid bit stream data is available. | |
| */ | |
| if (hSbrHeader->syncState == SBR_NOT_INITIALIZED) { | |
| errorStatus = | |
| initHeaderData(hSbrHeader, self->sampleRateIn, self->sampleRateOut, | |
| self->downscaleFactor, codecFrameSize, self->flags, | |
| 1 /* SET_DEFAULT_HDR */ | |
| ); | |
| if (errorStatus != SBRDEC_OK) { | |
| return errorStatus; | |
| } | |
| hSbrHeader->syncState = UPSAMPLING; | |
| errorStatus = sbrDecoder_HeaderUpdate(self, hSbrHeader, HEADER_NOT_PRESENT, | |
| pSbrChannel, hSbrElement->nChannels); | |
| if (errorStatus != SBRDEC_OK) { | |
| hSbrHeader->syncState = SBR_NOT_INITIALIZED; | |
| return errorStatus; | |
| } | |
| } | |
| /* reset */ | |
| if (hSbrHeader->status & SBRDEC_HDR_STAT_RESET) { | |
| int ch; | |
| int applySbrProc = (hSbrHeader->syncState == SBR_ACTIVE || | |
| (hSbrHeader->frameErrorFlag == 0 && | |
| hSbrHeader->syncState == SBR_HEADER)); | |
| for (ch = 0; ch < numElementChannels; ch++) { | |
| SBR_ERROR errorStatusTmp = SBRDEC_OK; | |
| errorStatusTmp = resetSbrDec( | |
| &pSbrChannel[ch]->SbrDec, hSbrHeader, &pSbrChannel[ch]->prevFrameData, | |
| self->synDownsampleFac, self->flags, pSbrChannel[ch]->frameData); | |
| if (errorStatusTmp != SBRDEC_OK) { | |
| hSbrHeader->syncState = UPSAMPLING; | |
| } | |
| } | |
| if (applySbrProc) { | |
| hSbrHeader->status &= ~SBRDEC_HDR_STAT_RESET; | |
| } | |
| } | |
| /* decoding */ | |
| if ((hSbrHeader->syncState == SBR_ACTIVE) || | |
| ((hSbrHeader->syncState == SBR_HEADER) && | |
| (hSbrHeader->frameErrorFlag == 0))) { | |
| errorStatus = SBRDEC_OK; | |
| decodeSbrData(hSbrHeader, hFrameDataLeft, &pSbrChannel[0]->prevFrameData, | |
| (stereo) ? hFrameDataRight : NULL, | |
| (stereo) ? &pSbrChannel[1]->prevFrameData : NULL); | |
| /* Now we have a full parameter set and can do parameter | |
| based concealment instead of plain upsampling. */ | |
| hSbrHeader->syncState = SBR_ACTIVE; | |
| } | |
| if (timeDataSize < | |
| hSbrHeader->numberTimeSlots * hSbrHeader->timeStep * | |
| self->pQmfDomain->globalConf.nBandsSynthesis * | |
| (psPossible ? fMax(2, numInChannels) : numInChannels)) { | |
| return SBRDEC_OUTPUT_BUFFER_TOO_SMALL; | |
| } | |
| { | |
| self->flags &= ~SBRDEC_PS_DECODED; | |
| C_ALLOC_SCRATCH_START(pPsScratch, struct PS_DEC_COEFFICIENTS, 1) | |
| /* decode PS data if available */ | |
| if (h_ps_d != NULL && psPossible && (hSbrHeader->syncState == SBR_ACTIVE)) { | |
| int applyPs = 1; | |
| /* define which frame delay line slot to process */ | |
| h_ps_d->processSlot = hSbrElement->useFrameSlot; | |
| applyPs = DecodePs(h_ps_d, hSbrHeader->frameErrorFlag, pPsScratch); | |
| self->flags |= (applyPs) ? SBRDEC_PS_DECODED : 0; | |
| } | |
| offset0 = FDK_chMapDescr_getMapValue(mapDescr, channelIndex, mapIdx); | |
| offset0_block = offset0 * codecFrameSize; | |
| if (stereo || psPossible) { | |
| /* the value of offset1 only matters if the condition is true, however if | |
| it is not true channelIndex+1 may exceed the channel map resutling in an | |
| error, though the value of offset1 is actually meaningless. This is | |
| prevented here. */ | |
| offset1 = FDK_chMapDescr_getMapValue(mapDescr, channelIndex + 1, mapIdx); | |
| offset1_block = offset1 * codecFrameSize; | |
| } | |
| /* Set strides for reading and writing */ | |
| if (psPossible) | |
| strideOut = (numInChannels < 2) ? 2 : numInChannels; | |
| else | |
| strideOut = numInChannels; | |
| /* use same buffers for left and right channel and apply PS per timeslot */ | |
| /* Process left channel */ | |
| sbr_dec(&pSbrChannel[0]->SbrDec, input + offset0_block, timeData + offset0, | |
| (self->flags & SBRDEC_PS_DECODED) ? &pSbrChannel[1]->SbrDec : NULL, | |
| timeData + offset1, strideOut, hSbrHeader, hFrameDataLeft, | |
| &pSbrChannel[0]->prevFrameData, | |
| (hSbrHeader->syncState == SBR_ACTIVE), h_ps_d, self->flags, | |
| codecFrameSize, self->sbrInDataHeadroom); | |
| if (stereo) { | |
| /* Process right channel */ | |
| sbr_dec(&pSbrChannel[1]->SbrDec, input + offset1_block, | |
| timeData + offset1, NULL, NULL, strideOut, hSbrHeader, | |
| hFrameDataRight, &pSbrChannel[1]->prevFrameData, | |
| (hSbrHeader->syncState == SBR_ACTIVE), NULL, self->flags, | |
| codecFrameSize, self->sbrInDataHeadroom); | |
| } | |
| C_ALLOC_SCRATCH_END(pPsScratch, struct PS_DEC_COEFFICIENTS, 1) | |
| } | |
| if (h_ps_d != NULL) { | |
| /* save PS status for next run */ | |
| h_ps_d->psDecodedPrv = (self->flags & SBRDEC_PS_DECODED) ? 1 : 0; | |
| } | |
| if (psPossible && !(self->flags & SBRDEC_SKIP_QMF_SYN)) { | |
| FDK_ASSERT(strideOut > 1); | |
| if (!(self->flags & SBRDEC_PS_DECODED)) { | |
| /* A decoder which is able to decode PS has to produce a stereo output | |
| * even if no PS data is available. */ | |
| /* So copy left channel to right channel. */ | |
| int copyFrameSize = | |
| codecFrameSize * self->pQmfDomain->QmfDomainOut->fb.no_channels; | |
| copyFrameSize /= self->pQmfDomain->QmfDomainIn->fb.no_channels; | |
| LONG *ptr; | |
| INT i; | |
| FDK_ASSERT(strideOut == 2); | |
| ptr = timeData; | |
| for (i = copyFrameSize >> 1; i--;) { | |
| LONG tmp; /* This temporal variable is required because some compilers | |
| can't do *ptr++ = *ptr++ correctly. */ | |
| tmp = *ptr++; | |
| *ptr++ = tmp; | |
| tmp = *ptr++; | |
| *ptr++ = tmp; | |
| } | |
| } | |
| *numOutChannels = 2; /* Output minimum two channels when PS is enabled. */ | |
| } | |
| return errorStatus; | |
| } | |
| SBR_ERROR sbrDecoder_Apply(HANDLE_SBRDECODER self, LONG *input, LONG *timeData, | |
| const int timeDataSize, int *numChannels, | |
| int *sampleRate, | |
| const FDK_channelMapDescr *const mapDescr, | |
| const int mapIdx, const int coreDecodedOk, | |
| UCHAR *psDecoded, const INT inDataHeadroom, | |
| INT *outDataHeadroom) { | |
| SBR_ERROR errorStatus = SBRDEC_OK; | |
| int psPossible; | |
| int sbrElementNum; | |
| int numCoreChannels; | |
| int numSbrChannels = 0; | |
| if ((self == NULL) || (timeData == NULL) || (numChannels == NULL) || | |
| (sampleRate == NULL) || (psDecoded == NULL) || | |
| !FDK_chMapDescr_isValid(mapDescr)) { | |
| return SBRDEC_INVALID_ARGUMENT; | |
| } | |
| psPossible = *psDecoded; | |
| numCoreChannels = *numChannels; | |
| if (numCoreChannels <= 0) { | |
| return SBRDEC_INVALID_ARGUMENT; | |
| } | |
| if (self->numSbrElements < 1) { | |
| /* exit immediately to avoid access violations */ | |
| return SBRDEC_NOT_INITIALIZED; | |
| } | |
| /* Sanity check of allocated SBR elements. */ | |
| for (sbrElementNum = 0; sbrElementNum < self->numSbrElements; | |
| sbrElementNum++) { | |
| if (self->pSbrElement[sbrElementNum] == NULL) { | |
| return SBRDEC_NOT_INITIALIZED; | |
| } | |
| } | |
| if (self->numSbrElements != 1 || self->pSbrElement[0]->elementID != ID_SCE) { | |
| psPossible = 0; | |
| } | |
| self->sbrInDataHeadroom = inDataHeadroom; | |
| *outDataHeadroom = (INT)(8); | |
| /* Make sure that even if no SBR data was found/parsed *psDecoded is returned | |
| * 1 if psPossible was 0. */ | |
| if (psPossible == 0) { | |
| self->flags &= ~SBRDEC_PS_DECODED; | |
| } | |
| /* replaces channel based reset inside sbr_dec() */ | |
| if (((self->flags & SBRDEC_LOW_POWER) ? 1 : 0) != | |
| ((self->pQmfDomain->globalConf.flags & QMF_FLAG_LP) ? 1 : 0)) { | |
| if (self->flags & SBRDEC_LOW_POWER) { | |
| self->pQmfDomain->globalConf.flags |= QMF_FLAG_LP; | |
| self->pQmfDomain->globalConf.flags_requested |= QMF_FLAG_LP; | |
| } else { | |
| self->pQmfDomain->globalConf.flags &= ~QMF_FLAG_LP; | |
| self->pQmfDomain->globalConf.flags_requested &= ~QMF_FLAG_LP; | |
| } | |
| if (FDK_QmfDomain_InitFilterBank(self->pQmfDomain, QMF_FLAG_KEEP_STATES)) { | |
| return SBRDEC_UNSUPPORTED_CONFIG; | |
| } | |
| } | |
| if (self->numSbrChannels > self->pQmfDomain->globalConf.nInputChannels) { | |
| return SBRDEC_UNSUPPORTED_CONFIG; | |
| } | |
| if (self->flags & SBRDEC_FLUSH) { | |
| /* flushing is signalized, hence increment the flush frame counter */ | |
| self->numFlushedFrames++; | |
| } else { | |
| /* no flushing is signalized, hence reset the flush frame counter */ | |
| self->numFlushedFrames = 0; | |
| } | |
| /* Loop over SBR elements */ | |
| for (sbrElementNum = 0; sbrElementNum < self->numSbrElements; | |
| sbrElementNum++) { | |
| int numElementChan; | |
| if (psPossible && | |
| self->pSbrElement[sbrElementNum]->pSbrChannel[1] == NULL) { | |
| /* Disable PS and try decoding SBR mono. */ | |
| psPossible = 0; | |
| } | |
| numElementChan = | |
| (self->pSbrElement[sbrElementNum]->elementID == ID_CPE) ? 2 : 1; | |
| /* If core signal is bad then force upsampling */ | |
| if (!coreDecodedOk) { | |
| setFrameErrorFlag(self->pSbrElement[sbrElementNum], FRAME_ERROR_ALLSLOTS); | |
| } | |
| errorStatus = sbrDecoder_DecodeElement( | |
| self, input, timeData, timeDataSize, mapDescr, mapIdx, numSbrChannels, | |
| sbrElementNum, | |
| numCoreChannels, /* is correct even for USC SCI==2 case */ | |
| &numElementChan, psPossible); | |
| if (errorStatus != SBRDEC_OK) { | |
| goto bail; | |
| } | |
| numSbrChannels += numElementChan; | |
| if (numSbrChannels >= numCoreChannels) { | |
| break; | |
| } | |
| } | |
| /* Update numChannels and samplerate */ | |
| /* Do not mess with output channels in case of USAC. numSbrChannels != | |
| * numChannels for stereoConfigIndex == 2 */ | |
| if (!(self->flags & SBRDEC_SYNTAX_USAC)) { | |
| *numChannels = numSbrChannels; | |
| } | |
| *sampleRate = self->sampleRateOut; | |
| *psDecoded = (self->flags & SBRDEC_PS_DECODED) ? 1 : 0; | |
| /* Clear reset and flush flag because everything seems to be done | |
| * successfully. */ | |
| self->flags &= ~SBRDEC_FORCE_RESET; | |
| self->flags &= ~SBRDEC_FLUSH; | |
| bail: | |
| return errorStatus; | |
| } | |
| SBR_ERROR sbrDecoder_Close(HANDLE_SBRDECODER *pSelf) { | |
| HANDLE_SBRDECODER self = *pSelf; | |
| int i; | |
| if (self != NULL) { | |
| if (self->hParametricStereoDec != NULL) { | |
| DeletePsDec(&self->hParametricStereoDec); | |
| } | |
| for (i = 0; i < (8); i++) { | |
| sbrDecoder_DestroyElement(self, i); | |
| } | |
| FreeRam_SbrDecoder(pSelf); | |
| } | |
| return SBRDEC_OK; | |
| } | |
| INT sbrDecoder_GetLibInfo(LIB_INFO *info) { | |
| int i; | |
| if (info == NULL) { | |
| return -1; | |
| } | |
| /* 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_SBRDEC; | |
| info->version = | |
| LIB_VERSION(SBRDECODER_LIB_VL0, SBRDECODER_LIB_VL1, SBRDECODER_LIB_VL2); | |
| LIB_VERSION_STRING(info); | |
| info->build_date = SBRDECODER_LIB_BUILD_DATE; | |
| info->build_time = SBRDECODER_LIB_BUILD_TIME; | |
| info->title = SBRDECODER_LIB_TITLE; | |
| /* Set flags */ | |
| info->flags = 0 | CAPF_SBR_HQ | CAPF_SBR_LP | CAPF_SBR_PS_MPEG | | |
| CAPF_SBR_DRM_BS | CAPF_SBR_CONCEALMENT | CAPF_SBR_DRC | | |
| CAPF_SBR_ELD_DOWNSCALE | CAPF_SBR_HBEHQ; | |
| /* End of flags */ | |
| return 0; | |
| } | |
| UINT sbrDecoder_GetDelay(const HANDLE_SBRDECODER self) { | |
| UINT outputDelay = 0; | |
| if (self != NULL) { | |
| UINT flags = self->flags; | |
| /* See chapter 1.6.7.2 of ISO/IEC 14496-3 for the GA-SBR figures below. */ | |
| /* Are we initialized? */ | |
| if ((self->numSbrChannels > 0) && (self->numSbrElements > 0)) { | |
| /* Add QMF synthesis delay */ | |
| if ((flags & SBRDEC_ELD_GRID) && IS_LOWDELAY(self->coreCodec)) { | |
| /* Low delay SBR: */ | |
| if (!(flags & SBRDEC_SKIP_QMF_SYN)) { | |
| outputDelay += | |
| (flags & SBRDEC_DOWNSAMPLE) ? 32 : 64; /* QMF synthesis */ | |
| if (flags & SBRDEC_LD_MPS_QMF) { | |
| outputDelay += 32; | |
| } | |
| } | |
| } else if (!IS_USAC(self->coreCodec)) { | |
| /* By the method of elimination this is the GA (AAC-LC, HE-AAC, ...) | |
| * branch: */ | |
| outputDelay += (flags & SBRDEC_DOWNSAMPLE) ? 481 : 962; | |
| if (flags & SBRDEC_SKIP_QMF_SYN) { | |
| outputDelay -= 257; /* QMF synthesis */ | |
| } | |
| } | |
| } | |
| } | |
| return (outputDelay); | |
| } |