| /* ----------------------------------------------------------------------------- |
| 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 |
| ----------------------------------------------------------------------------- */ |
| |
| /**************************** 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 "sbr_crc.h" |
| #include "sbr_ram.h" |
| #include "sbr_rom.h" |
| #include "lpp_tran.h" |
| #include "transcendent.h" |
| |
| #include "FDK_crc.h" |
| |
| #include "sbrdec_drc.h" |
| |
| #include "psbitdec.h" |
| |
| /* Decoder library info */ |
| #define SBRDECODER_LIB_VL0 3 |
| #define SBRDECODER_LIB_VL1 0 |
| #define SBRDECODER_LIB_VL2 0 |
| #define SBRDECODER_LIB_TITLE "SBR Decoder" |
| #ifdef __ANDROID__ |
| #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; |
| } |
| |
| /* Save element ID for sanity checks and to have a fallback for concealment. |
| */ |
| self->pSbrElement[elementIndex]->elementID = elementID; |
| |
| /* 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 += self->pSbrElement[elementIndex]->nChannels; |
| sbrError = SBRDEC_PARSE_ERROR; |
| goto bail; |
| } |
| |
| 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 { |
| Since we already have overwritten the old SBR header the only way out |
| is UPSAMPLING! This will be prepared in the next step. |
| } */ |
| } |
| } |
| } |
| 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); |
| INT CRCLen = 0; |
| HANDLE_FDK_BITSTREAM hBsOriginal = hBs; |
| FDK_BITSTREAM bsBwd; |
| |
| FDK_CRCINFO crcInfo; |
| INT crcReg = 0; |
| USHORT drmSbrCrc = 0; |
| 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 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_ER_AAC_ELD: |
| FDKpushFor(hBs, 10); |
| /* check sbrcrc later: we don't know the payload length now */ |
| break; |
| case AOT_DRM_AAC: |
| case AOT_DRM_SURROUND: |
| drmSbrCrc = (USHORT)FDKreadBits(hBs, 8); |
| /* Setup CRC decoder */ |
| FDKcrcInit(&crcInfo, 0x001d, 0xFFFF, 8); |
| /* Start CRC region */ |
| crcReg = FDKcrcStartReg(&crcInfo, hBs, 0); |
| break; |
| default: |
| CRCLen = bsPayLen - 10; /* change: 0 => i */ |
| if (CRCLen < 0) { |
| fDoDecodeSbrData = 0; |
| } else { |
| fDoDecodeSbrData = SbrCrcCheck(hBs, CRCLen); |
| } |
| break; |
| } |
| } |
| } /* 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); |
| } |
| |
| if (crcFlag) { |
| switch (self->coreCodec) { |
| case AOT_ER_AAC_ELD: { |
| /* late crc check for eld */ |
| INT payloadbits = |
| (INT)startPos - (INT)FDKgetValidBits(hBs) - startPos; |
| INT crcLen = payloadbits - 10; |
| FDKpushBack(hBs, payloadbits); |
| fDoDecodeSbrData = SbrCrcCheck(hBs, crcLen); |
| FDKpushFor(hBs, crcLen); |
| } break; |
| case AOT_DRM_AAC: |
| case AOT_DRM_SURROUND: |
| /* End CRC region */ |
| FDKcrcEndReg(&crcInfo, hBs, crcReg); |
| /* Check CRC */ |
| if ((FDKcrcGetCRC(&crcInfo) ^ 0xFF) != drmSbrCrc) { |
| fDoDecodeSbrData = 0; |
| if (headerStatus != HEADER_NOT_PRESENT) { |
| headerStatus = HEADER_ERROR; |
| hSbrHeader->syncState = SBR_NOT_INITIALIZED; |
| } |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| |
| /* 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 */ |
| int 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 (!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, QDOM_PCM *input, INT_PCM *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); |
| |
| 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); |
| } |
| |
| 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; |
| INT_PCM *ptr; |
| INT i; |
| FDK_ASSERT(strideOut == 2); |
| |
| ptr = timeData; |
| for (i = copyFrameSize >> 1; i--;) { |
| INT_PCM 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, INT_PCM *input, |
| INT_PCM *timeData, const int timeDataSize, |
| int *numChannels, int *sampleRate, |
| const FDK_channelMapDescr *const mapDescr, |
| const int mapIdx, const int coreDecodedOk, |
| UCHAR *psDecoded) { |
| 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; |
| } |
| |
| /* 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); |
| } |