| |
| /* ----------------------------------------------------------------------------------------------------------- |
| Software License for The Fraunhofer FDK AAC Codec Library for Android |
| |
| © Copyright 1995 - 2012 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. |
| All rights reserved. |
| |
| 1. INTRODUCTION |
| The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements |
| the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio. |
| This FDK AAC Codec software is intended to be used on a wide variety of Android devices. |
| |
| AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual |
| audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by |
| independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part |
| of the MPEG specifications. |
| |
| Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer) |
| may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners |
| individually for the purpose of encoding or decoding bit streams in products that are compliant with |
| the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license |
| these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec |
| software may already be covered under those patent licenses when it is used for those licensed purposes only. |
| |
| Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality, |
| are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional |
| applications information and documentation. |
| |
| 2. COPYRIGHT LICENSE |
| |
| Redistribution and use in source and binary forms, with or without modification, are permitted without |
| payment of copyright license fees provided that you satisfy the following conditions: |
| |
| You must retain the complete text of this software license in redistributions of the FDK AAC Codec or |
| your modifications thereto in source code form. |
| |
| You must retain the complete text of this software license in the documentation and/or other materials |
| provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form. |
| You must make available free of charge copies of the complete source code of the FDK AAC Codec and your |
| modifications thereto to recipients of copies in binary form. |
| |
| The name of Fraunhofer may not be used to endorse or promote products derived from this library without |
| prior written permission. |
| |
| You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec |
| software or your modifications thereto. |
| |
| Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software |
| and the date of any change. For modified versions of the FDK AAC Codec, the term |
| "Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term |
| "Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android." |
| |
| 3. NO PATENT LICENSE |
| |
| NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer, |
| ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with |
| respect to this software. |
| |
| You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized |
| by appropriate patent licenses. |
| |
| 4. DISCLAIMER |
| |
| This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors |
| "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties |
| of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
| CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages, |
| including but not limited to procurement of substitute goods or services; loss of use, data, or profits, |
| or business interruption, however caused and on any theory of liability, whether in contract, strict |
| liability, or tort (including negligence), arising in any way out of the use of this software, even if |
| advised of the possibility of such damage. |
| |
| 5. CONTACT INFORMATION |
| |
| Fraunhofer Institute for Integrated Circuits IIS |
| Attention: Audio and Multimedia Departments - FDK AAC LL |
| Am Wolfsmantel 33 |
| 91058 Erlangen, Germany |
| |
| www.iis.fraunhofer.de/amm |
| amm-info@iis.fraunhofer.de |
| ----------------------------------------------------------------------------------------------------------- */ |
| |
| /*! |
| \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 |
| |
| The primary source code documentation is based on generated and cross-referenced HTML files using |
| <a HREF="http://www.doxygen.org">doxygen</a>. 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 "sbrdec_drc.h" |
| |
| #include "psbitdec.h" |
| |
| |
| /* Decoder library info */ |
| #define SBRDECODER_LIB_VL0 2 |
| #define SBRDECODER_LIB_VL1 1 |
| #define SBRDECODER_LIB_VL2 2 |
| #define SBRDECODER_LIB_TITLE "SBR Decoder" |
| #define SBRDECODER_LIB_BUILD_DATE __DATE__ |
| #define SBRDECODER_LIB_BUILD_TIME __TIME__ |
| |
| |
| |
| |
| 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; |
| } |
| |
| |
| /*! |
| \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; |
| |
| /* Check in/out samplerates */ |
| if ( sampleRateIn < 6400 |
| || sampleRateIn > 24000 |
| ) |
| { |
| sbrError = SBRDEC_UNSUPPORTED_CONFIG; |
| goto bail; |
| } |
| |
| if ( sampleRateOut > 48000 ) |
| { |
| 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; |
| } else { |
| synDownsampleFac = 1; |
| } |
| |
| self->synDownsampleFac = synDownsampleFac; |
| self->sampleRateOut = sampleRateOut; |
| |
| { |
| int i; |
| |
| for (i = 0; i < (1)+1; i++) |
| { |
| hSbrHeader = &(self->sbrHeader[elementIndex][i]); |
| |
| /* init a default header such that we can at least do upsampling later */ |
| sbrError = initHeaderData( |
| hSbrHeader, |
| sampleRateIn, |
| sampleRateOut, |
| samplesPerFrame, |
| self->flags |
| ); |
| } |
| } |
| |
| if (sbrError != SBRDEC_OK) { |
| goto bail; |
| } |
| |
| /* Init SBR channels going to be assigned to a SBR element */ |
| { |
| int ch; |
| |
| for (ch=0; ch<self->pSbrElement[elementIndex]->nChannels; ch++) |
| { |
| /* and create sbrDec */ |
| sbrError = createSbrDec (self->pSbrElement[elementIndex]->pSbrChannel[ch], |
| hSbrHeader, |
| &self->pSbrElement[elementIndex]->transposerSettings, |
| synDownsampleFac, |
| qmfFlags, |
| self->flags, |
| overlap, |
| ch ); |
| |
| 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; |
| } |
| |
| |
| SBR_ERROR sbrDecoder_Open ( HANDLE_SBRDECODER * pSelf ) |
| { |
| HANDLE_SBRDECODER self = NULL; |
| SBR_ERROR sbrError = SBRDEC_OK; |
| |
| /* Get memory for this instance */ |
| self = GetRam_SbrDecoder(); |
| if (self == NULL) { |
| sbrError = SBRDEC_MEM_ALLOC_FAILED; |
| goto bail; |
| } |
| |
| self->workBuffer1 = GetRam_SbrDecWorkBuffer1(); |
| self->workBuffer2 = GetRam_SbrDecWorkBuffer2(); |
| |
| if ( self->workBuffer1 == NULL |
| || self->workBuffer2 == NULL ) |
| { |
| sbrError = SBRDEC_MEM_ALLOC_FAILED; |
| goto bail; |
| } |
| |
| /* |
| Already zero because of calloc |
| self->numSbrElements = 0; |
| self->numSbrChannels = 0; |
| self->codecFrameSize = 0; |
| */ |
| |
| self->numDelayFrames = (1); /* set to the max value by default */ |
| |
| *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: |
| 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 |
| ) |
| { |
| SBR_ERROR sbrError = SBRDEC_OK; |
| int chCnt=0; |
| int nSbrElementsStart = self->numSbrElements; |
| |
| /* Check core codec AOT */ |
| if (! sbrDecoder_isCoreCodecValid(coreCodec) || elementIndex >= (4)) { |
| 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 |
| ) |
| { |
| /* Nothing to do */ |
| return SBRDEC_OK; |
| } |
| |
| self->sampleRateIn = sampleRateIn; |
| self->codecFrameSize = samplesPerFrame; |
| self->coreCodec = coreCodec; |
| |
| self->flags = 0; |
| self->flags |= (coreCodec == AOT_ER_AAC_ELD) ? SBRDEC_ELD_GRID : 0; |
| |
| /* 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; |
| } |
| } |
| |
| 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 ); |
| |
| /* Add reference pointer to workbuffers. */ |
| self->pSbrElement[elementIndex]->pSbrChannel[ch]->SbrDec.WorkBuffer1 = self->workBuffer1; |
| self->pSbrElement[elementIndex]->pSbrChannel[ch]->SbrDec.WorkBuffer2 = self->workBuffer2; |
| chCnt++; |
| } |
| if (elChannels == 1 && self->pSbrElement[elementIndex]->pSbrChannel[ch] != NULL) { |
| deleteSbrDec( self->pSbrElement[elementIndex]->pSbrChannel[ch] ); |
| FreeRam_SbrDecChannel( &self->pSbrElement[elementIndex]->pSbrChannel[ch] ); |
| } |
| } |
| |
| /* clear error flags for all delay slots */ |
| FDKmemclear(self->pSbrElement[elementIndex]->frameErrorFlag, ((1)+1)*sizeof(UCHAR)); |
| |
| /* Initialize this instance */ |
| sbrError = sbrDecoder_ResetElement( |
| self, |
| sampleRateIn, |
| sampleRateOut, |
| samplesPerFrame, |
| elementID, |
| elementIndex, |
| (coreCodec == AOT_ER_AAC_ELD) ? 0 : (6) |
| ); |
| |
| |
| |
| bail: |
| if (sbrError != SBRDEC_OK) { |
| if (nSbrElementsStart < self->numSbrElements) { |
| /* Free the memory allocated for this element */ |
| sbrDecoder_DestroyElement( self, elementIndex ); |
| } else if (self->pSbrElement[elementIndex] != NULL) { |
| /* Set error flag to trigger concealment */ |
| self->pSbrElement[elementIndex]->frameErrorFlag[self->pSbrElement[elementIndex]->useFrameSlot] = 1;; |
| } |
| } |
| |
| return sbrError; |
| } |
| |
| /** |
| * \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) |
| { |
| /* 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 |
| ) |
| { |
| SBR_HEADER_STATUS headerStatus; |
| HANDLE_SBR_HEADER_DATA hSbrHeader; |
| SBR_ERROR sbrError = SBRDEC_OK; |
| int headerIndex; |
| |
| if ( self == NULL || elementIndex > (4) ) |
| { |
| return SBRDEC_UNSUPPORTED_CONFIG; |
| } |
| |
| if (! sbrDecoder_isCoreCodecValid(coreCodec)) { |
| return SBRDEC_UNSUPPORTED_CONFIG; |
| } |
| |
| sbrError = sbrDecoder_InitElement( |
| self, |
| sampleRateIn, |
| sampleRateOut, |
| samplesPerFrame, |
| coreCodec, |
| elementID, |
| elementIndex |
| ); |
| |
| if (sbrError != SBRDEC_OK) { |
| goto bail; |
| } |
| |
| headerIndex = getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot, |
| self->pSbrElement[elementIndex]->useHeaderSlot); |
| hSbrHeader = &(self->sbrHeader[elementIndex][headerIndex]); |
| |
| headerStatus = sbrGetHeaderData ( hSbrHeader, |
| hBs, |
| self->flags, |
| 0); |
| |
| |
| { |
| 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: |
| 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_BS_INTERRUPTION: |
| { |
| int elementIndex; |
| /* Loop over SBR elements */ |
| for (elementIndex = 0; elementIndex < self->numSbrElements; elementIndex++) |
| { |
| 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; |
| 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 < (4)) && (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 = FDKmin(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; |
| |
| if (self == NULL) { |
| return SBRDEC_NOT_INITIALIZED; |
| } |
| if (ch > (6) || pNextFact_mag == NULL) { |
| return SBRDEC_SET_PARAM_FAIL; |
| } |
| |
| /* Find the right SBR channel */ |
| pSbrDrcChannelData = sbrDecoder_drcGetChannel( self, ch ); |
| |
| if ( pSbrDrcChannelData != NULL ) { |
| 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 > (6)) |
| || (self->numSbrElements == 0) |
| || (self->numSbrChannels == 0) ) { |
| return; |
| } |
| |
| /* Find the right SBR channel */ |
| pSbrDrcChannelData = sbrDecoder_drcGetChannel( self, ch ); |
| |
| if ( pSbrDrcChannelData != NULL ) { |
| pSbrDrcChannelData->enable = 0; |
| } |
| } |
| |
| |
| |
| SBR_ERROR sbrDecoder_Parse( |
| HANDLE_SBRDECODER self, |
| HANDLE_FDK_BITSTREAM hBs, |
| int *count, |
| int bsPayLen, |
| int crcFlag, |
| MP4_ELEMENT_ID prevElement, |
| int elementIndex, |
| int fGlobalIndependencyFlag |
| ) |
| { |
| SBR_DECODER_ELEMENT *hSbrElement; |
| HANDLE_SBR_HEADER_DATA hSbrHeader; |
| HANDLE_SBR_CHANNEL *pSbrChannel; |
| |
| SBR_FRAME_DATA *hFrameDataLeft; |
| SBR_FRAME_DATA *hFrameDataRight; |
| |
| SBR_ERROR errorStatus = SBRDEC_OK; |
| SBR_SYNC_STATE initialSyncState; |
| SBR_HEADER_STATUS headerStatus = HEADER_NOT_PRESENT; |
| |
| INT startPos; |
| INT CRCLen = 0; |
| |
| int stereo; |
| int fDoDecodeSbrData = 1; |
| |
| int lastSlot, lastHdrSlot = 0, thisHdrSlot; |
| |
| /* Remember start position of SBR element */ |
| startPos = FDKgetValidBits(hBs); |
| |
| /* SBR sanity checks */ |
| if ( self == NULL || 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]; |
| hFrameDataRight = &self->pSbrElement[elementIndex]->pSbrChannel[1]->frameData[hSbrElement->useFrameSlot]; |
| |
| initialSyncState = hSbrHeader->syncState; |
| |
| /* 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 == 1) { |
| switch (self->coreCodec) { |
| case AOT_ER_AAC_ELD: |
| FDKpushFor (hBs, 10); |
| /* check sbrcrc later: we don't know the payload length now */ |
| 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; |
| |
| { |
| sbrHeaderPresent = FDKreadBit(hBs); |
| } |
| |
| if ( sbrHeaderPresent ) { |
| headerStatus = sbrGetHeaderData (hSbrHeader, |
| hBs, |
| self->flags, |
| 1); |
| } |
| |
| 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; |
| } |
| } |
| |
| 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) { |
| sbrFrameOk = sbrGetChannelPairElement(hSbrHeader, |
| hFrameDataLeft, |
| hFrameDataRight, |
| hBs, |
| self->flags, |
| self->pSbrElement[elementIndex]->transposerSettings.overlap); |
| } |
| else { |
| if (self->hParametricStereoDec != NULL) { |
| /* update slot index for PS bitstream parsing */ |
| self->hParametricStereoDec->bsLastSlot = self->hParametricStereoDec->bsReadSlot; |
| self->hParametricStereoDec->bsReadSlot = hSbrElement->useFrameSlot; |
| } |
| sbrFrameOk = sbrGetSingleChannelElement(hSbrHeader, |
| hFrameDataLeft, |
| hBs, |
| 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 == 1 ) { |
| 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; |
| 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; |
| } |
| } |
| } |
| } |
| |
| if (!fDoDecodeSbrData) { |
| /* Set error flag for this slot to trigger concealment */ |
| self->pSbrElement[elementIndex]->frameErrorFlag[hSbrElement->useFrameSlot] = 1; |
| errorStatus = SBRDEC_PARSE_ERROR; |
| } else { |
| /* Everything seems to be ok so clear the error flag */ |
| self->pSbrElement[elementIndex]->frameErrorFlag[hSbrElement->useFrameSlot] = 0; |
| } |
| |
| 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 (errorStatus == SBRDEC_OK) { |
| if (headerStatus == HEADER_NOT_PRESENT) { |
| /* 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 - 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 interleaved flag indicating interleaved channel output |
| * \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 (reading stride). |
| * \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, |
| INT_PCM *timeData, |
| const int interleaved, |
| const UCHAR *channelMapping, |
| 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 = &hSbrElement->pSbrChannel[0]->frameData[hSbrElement->useFrameSlot]; |
| SBR_FRAME_DATA *hFrameDataRight = &hSbrElement->pSbrChannel[1]->frameData[hSbrElement->useFrameSlot]; |
| |
| SBR_ERROR errorStatus = SBRDEC_OK; |
| |
| |
| INT strideIn, strideOut, offset0, offset1; |
| INT codecFrameSize = self->codecFrameSize; |
| |
| int stereo = (hSbrElement->elementID == ID_CPE) ? 1 : 0; |
| int numElementChannels = hSbrElement->nChannels; /* Number of channels of the current SBR element */ |
| |
| /* 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, |
| codecFrameSize, |
| self->flags |
| ); |
| |
| 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; |
| for (ch = 0 ; ch < numElementChannels; ch++) { |
| SBR_ERROR errorStatusTmp = SBRDEC_OK; |
| |
| errorStatusTmp = resetSbrDec ( |
| &pSbrChannel[ch]->SbrDec, |
| hSbrHeader, |
| &pSbrChannel[ch]->prevFrameData, |
| self->flags & SBRDEC_LOW_POWER, |
| self->synDownsampleFac |
| ); |
| |
| if (errorStatusTmp != SBRDEC_OK) { |
| errorStatus = errorStatusTmp; |
| } |
| } |
| 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; |
| } |
| |
| /* decode PS data if available */ |
| if (h_ps_d != NULL && psPossible) { |
| int applyPs = 1; |
| |
| /* define which frame delay line slot to process */ |
| h_ps_d->processSlot = hSbrElement->useFrameSlot; |
| |
| applyPs = DecodePs(h_ps_d, hSbrHeader->frameErrorFlag); |
| self->flags |= (applyPs) ? SBRDEC_PS_DECODED : 0; |
| } |
| |
| /* Set strides for reading and writing */ |
| if (interleaved) { |
| strideIn = numInChannels; |
| if ( psPossible ) |
| strideOut = (numInChannels < 2) ? 2 : numInChannels; |
| else |
| strideOut = numInChannels; |
| offset0 = channelMapping[0]; |
| offset1 = channelMapping[1]; |
| } else { |
| strideIn = 1; |
| strideOut = 1; |
| offset0 = channelMapping[0]*2*codecFrameSize; |
| offset1 = channelMapping[1]*2*codecFrameSize; |
| } |
| |
| /* use same buffers for left and right channel and apply PS per timeslot */ |
| /* Process left channel */ |
| //FDKprintf("self->codecFrameSize %d\t%d\n",self->codecFrameSize,self->sampleRateIn); |
| sbr_dec (&pSbrChannel[0]->SbrDec, |
| timeData + offset0, |
| timeData + offset0, |
| &pSbrChannel[1]->SbrDec, |
| timeData + offset1, |
| strideIn, |
| strideOut, |
| hSbrHeader, |
| hFrameDataLeft, |
| &pSbrChannel[0]->prevFrameData, |
| (hSbrHeader->syncState == SBR_ACTIVE), |
| h_ps_d, |
| self->flags |
| ); |
| |
| if (stereo) { |
| /* Process right channel */ |
| sbr_dec (&pSbrChannel[1]->SbrDec, |
| timeData + offset1, |
| timeData + offset1, |
| NULL, |
| NULL, |
| strideIn, |
| strideOut, |
| hSbrHeader, |
| hFrameDataRight, |
| &pSbrChannel[1]->prevFrameData, |
| (hSbrHeader->syncState == SBR_ACTIVE), |
| NULL, |
| self->flags |
| ); |
| } |
| |
| if (h_ps_d != NULL) { |
| /* save PS status for next run */ |
| h_ps_d->psDecodedPrv = (self->flags & SBRDEC_PS_DECODED) ? 1 : 0 ; |
| } |
| |
| if ( psPossible |
| ) |
| { |
| 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 availble. */ |
| /* So copy left channel to right channel. */ |
| if (interleaved) { |
| INT_PCM *ptr; |
| INT i; |
| FDK_ASSERT(strideOut == 2); |
| |
| ptr = timeData; |
| for (i = codecFrameSize; 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; |
| } |
| } else { |
| FDKmemcpy( timeData+2*codecFrameSize, timeData, 2*codecFrameSize*sizeof(INT_PCM) ); |
| } |
| } |
| *numOutChannels = 2; /* Output minimum two channels when PS is enabled. */ |
| } |
| |
| return errorStatus; |
| } |
| |
| |
| SBR_ERROR sbrDecoder_Apply ( HANDLE_SBRDECODER self, |
| INT_PCM *timeData, |
| int *numChannels, |
| int *sampleRate, |
| const UCHAR channelMapping[(6)], |
| const int interleaved, |
| const int coreDecodedOk, |
| UCHAR *psDecoded ) |
| { |
| SBR_ERROR errorStatus = SBRDEC_OK; |
| |
| int psPossible = 0; |
| int sbrElementNum; |
| int numCoreChannels = *numChannels; |
| int numSbrChannels = 0; |
| |
| psPossible = *psDecoded; |
| |
| if (self->numSbrElements < 1) { |
| /* exit immediately to avoid access violations */ |
| return SBRDEC_CREATE_ERROR; |
| } |
| |
| /* Sanity check of allocated SBR elements. */ |
| for (sbrElementNum=0; sbrElementNum<self->numSbrElements; sbrElementNum++) { |
| if (self->pSbrElement[sbrElementNum] == NULL) { |
| return SBRDEC_CREATE_ERROR; |
| } |
| } |
| |
| if (self->numSbrElements != 1 || self->pSbrElement[0]->elementID != ID_SCE) { |
| psPossible = 0; |
| } |
| |
| |
| /* In case of non-interleaved time domain data and upsampling, make room for bigger SBR output. */ |
| if (self->synDownsampleFac == 1 && interleaved == 0) { |
| int c, outputFrameSize; |
| |
| outputFrameSize = |
| self->pSbrElement[0]->pSbrChannel[0]->SbrDec.SynthesisQMF.no_channels |
| * self->pSbrElement[0]->pSbrChannel[0]->SbrDec.SynthesisQMF.no_col; |
| |
| for (c=numCoreChannels-1; c>0; c--) { |
| FDKmemmove(timeData + c*outputFrameSize, timeData + c*self->codecFrameSize , self->codecFrameSize*sizeof(INT_PCM)); |
| } |
| } |
| |
| |
| /* 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; |
| } |
| |
| /* Loop over SBR elements */ |
| for (sbrElementNum = 0; sbrElementNum<self->numSbrElements; sbrElementNum++) |
| { |
| int numElementChan; |
| |
| if (psPossible && self->pSbrElement[sbrElementNum]->pSbrChannel[1] == NULL) { |
| errorStatus = SBRDEC_UNSUPPORTED_CONFIG; |
| goto bail; |
| } |
| |
| numElementChan = (self->pSbrElement[sbrElementNum]->elementID == ID_CPE) ? 2 : 1; |
| |
| /* If core signal is bad then force upsampling */ |
| if ( ! coreDecodedOk ) { |
| self->pSbrElement[sbrElementNum]->frameErrorFlag[self->pSbrElement[sbrElementNum]->useFrameSlot] = 1; |
| } |
| |
| errorStatus = sbrDecoder_DecodeElement ( |
| self, |
| timeData, |
| interleaved, |
| channelMapping, |
| sbrElementNum, |
| numCoreChannels, |
| &numElementChan, |
| psPossible |
| ); |
| |
| if (errorStatus != SBRDEC_OK) { |
| goto bail; |
| } |
| |
| numSbrChannels += numElementChan; |
| channelMapping += numElementChan; |
| |
| if (numSbrChannels >= numCoreChannels) { |
| break; |
| } |
| } |
| |
| /* Update numChannels and samplerate */ |
| *numChannels = numSbrChannels; |
| *sampleRate = self->sampleRateOut; |
| *psDecoded = (self->flags & SBRDEC_PS_DECODED) ? 1 : 0; |
| |
| |
| |
| 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 ); |
| } |
| |
| if (self->workBuffer1 != NULL) { |
| FreeRam_SbrDecWorkBuffer1(&self->workBuffer1); |
| } |
| if (self->workBuffer2 != NULL) { |
| FreeRam_SbrDecWorkBuffer2(&self->workBuffer2); |
| } |
| |
| for (i = 0; i < (4); 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 = (char *)SBRDECODER_LIB_BUILD_DATE; |
| info->build_time = (char *)SBRDECODER_LIB_BUILD_TIME; |
| info->title = (char *)SBRDECODER_LIB_TITLE; |
| |
| /* Set flags */ |
| info->flags = 0 |
| | CAPF_SBR_HQ |
| | CAPF_SBR_LP |
| | CAPF_SBR_PS_MPEG |
| | CAPF_SBR_CONCEALMENT |
| | CAPF_SBR_DRC |
| ; |
| /* End of flags */ |
| |
| return 0; |
| } |
| |