/**************************************************************************** (C) Copyright Fraunhofer IIS (2005) All Rights Reserved Please be advised that this software and/or program delivery is Confidential Information of Fraunhofer and subject to and covered by the Fraunhofer IIS Software Evaluation Agreement between Google Inc. and Fraunhofer effective and in full force since March 1, 2012. You may use this software and/or program only under the terms and conditions described in the above mentioned Fraunhofer IIS Software Evaluation Agreement. Any other and/or further use requires a separate agreement. This software and/or program is protected by copyright law and international treaties. Any reproduction or distribution of this software and/or program, or any portion of it, may result in severe civil and criminal penalties, and will be prosecuted to the maximum extent possible under law. $Id$ *******************************************************************************/ /*! \file \brief SBR decoder frontend $Revision: 38029 $ 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 doxygen. As part of this documentation you can find more extensive descriptions about key concepts and algorithms at the following locations:

Programming

\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()

Algorithmic details

\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 1 #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; chpSbrElement[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; chpSbrElement[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; chpSbrElement[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; sbrElementNumnumSbrElements; 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; sbrElementNumnumSbrElements; 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; }