diff options
Diffstat (limited to 'libAACdec/src/block.cpp')
-rw-r--r-- | libAACdec/src/block.cpp | 1372 |
1 files changed, 936 insertions, 436 deletions
diff --git a/libAACdec/src/block.cpp b/libAACdec/src/block.cpp index a19284e..7d2a4b9 100644 --- a/libAACdec/src/block.cpp +++ b/libAACdec/src/block.cpp @@ -1,74 +1,85 @@ - -/* ----------------------------------------------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2015 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. - All rights reserved. +© 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. +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: +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 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 +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. +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. +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." +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. +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. +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. +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 @@ -79,28 +90,33 @@ Am Wolfsmantel 33 www.iis.fraunhofer.de/amm amm-info@iis.fraunhofer.de ------------------------------------------------------------------------------------------------------------ */ +----------------------------------------------------------------------------- */ -/***************************** MPEG-4 AAC Decoder ************************** +/**************************** AAC decoder library ****************************** Author(s): Josef Hoepfl + Description: long/short-block decoding -******************************************************************************/ +*******************************************************************************/ #include "block.h" #include "aac_rom.h" #include "FDK_bitstream.h" +#include "scale.h" #include "FDK_tools_rom.h" +#include "usacdec_fac.h" +#include "usacdec_lpd.h" +#include "usacdec_lpc.h" +#include "FDK_trigFcts.h" - +#include "ac_arith_coder.h" #include "aacdec_hcr.h" #include "rvlc.h" - #if defined(__arm__) #include "arm/block_arm.cpp" #endif @@ -111,135 +127,169 @@ amm-info@iis.fraunhofer.de The function reads the escape sequence from the bitstream, if the absolute value of the quantized coefficient has the value 16. + A limitation is implemented to maximal 31 bits to prevent endless loops. + If it strikes, MAX_QUANTIZED_VALUE + 1 is returned, independent of the sign of + parameter q. \return quantized coefficient */ LONG CBlock_GetEscape(HANDLE_FDK_BITSTREAM bs, /*!< pointer to bitstream */ - const LONG q) /*!< quantized coefficient */ + const LONG q) /*!< quantized coefficient */ { - LONG i, off, neg ; + if (fAbs(q) != 16) return (q); - if (q < 0) - { - if (q != -16) return q; - neg = 1; - } - else - { - if (q != +16) return q; - neg = 0; + LONG i, off; + for (i = 4; i < 32; i++) { + if (FDKreadBit(bs) == 0) break; } - for (i=4; ; i++) - { - if (FDKreadBits(bs,1) == 0) - break; - } - - if (i > 16) - { - if (i - 16 > CACHE_BITS) { /* cannot read more than "CACHE_BITS" bits at once in the function FDKreadBits() */ - return (MAX_QUANTIZED_VALUE + 1); /* returning invalid value that will be captured later */ - } - - off = FDKreadBits(bs,i-16) << 16; - off |= FDKreadBits(bs,16); - } - else - { - off = FDKreadBits(bs,i); - } + if (i == 32) return (MAX_QUANTIZED_VALUE + 1); + off = FDKreadBits(bs, i); i = off + (1 << i); - if (neg) i = -i; + if (q < 0) i = -i; return i; } AAC_DECODER_ERROR CBlock_ReadScaleFactorData( - CAacDecoderChannelInfo *pAacDecoderChannelInfo, - HANDLE_FDK_BITSTREAM bs, - UINT flags - ) -{ + CAacDecoderChannelInfo *pAacDecoderChannelInfo, HANDLE_FDK_BITSTREAM bs, + UINT flags) { int temp; int band; int group; int position = 0; /* accu for intensity delta coding */ - int factor = pAacDecoderChannelInfo->pDynData->RawDataInfo.GlobalGain; /* accu for scale factor delta coding */ + int factor = pAacDecoderChannelInfo->pDynData->RawDataInfo + .GlobalGain; /* accu for scale factor delta coding */ UCHAR *pCodeBook = pAacDecoderChannelInfo->pDynData->aCodeBook; SHORT *pScaleFactor = pAacDecoderChannelInfo->pDynData->aScaleFactor; - const CodeBookDescription *hcb =&AACcodeBookDescriptionTable[BOOKSCL]; - - int ScaleFactorBandsTransmitted = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); - for (group=0; group < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++) - { - for (band=0; band < ScaleFactorBandsTransmitted; band++) - { - switch (pCodeBook[group*16+band]) { - - case ZERO_HCB: /* zero book */ - pScaleFactor[group*16+band] = 0; - break; - - default: /* decode scale factor */ - { - temp = CBlock_DecodeHuffmanWord(bs,hcb); - factor += temp - 60; /* MIDFAC 1.5 dB */ - } - pScaleFactor[group*16+band] = factor - 100; - break; - - case INTENSITY_HCB: /* intensity steering */ - case INTENSITY_HCB2: - temp = CBlock_DecodeHuffmanWord(bs,hcb); - position += temp - 60; - pScaleFactor[group*16+band] = position - 100; - break; - - case NOISE_HCB: /* PNS */ - if (flags & (AC_MPS_RES|AC_USAC|AC_RSVD50)) { - return AAC_DEC_PARSE_ERROR; - } - CPns_Read( &pAacDecoderChannelInfo->data.aac.PnsData, bs, hcb, pAacDecoderChannelInfo->pDynData->aScaleFactor, pAacDecoderChannelInfo->pDynData->RawDataInfo.GlobalGain, band, group); - break; + const CodeBookDescription *hcb = &AACcodeBookDescriptionTable[BOOKSCL]; + + const USHORT(*CodeBook)[HuffmanEntries] = hcb->CodeBook; + + int ScaleFactorBandsTransmitted = + GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); + for (group = 0; group < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); + group++) { + for (band = 0; band < ScaleFactorBandsTransmitted; band++) { + switch (pCodeBook[band]) { + case ZERO_HCB: /* zero book */ + pScaleFactor[band] = 0; + break; + + default: /* decode scale factor */ + if (!((flags & (AC_USAC | AC_RSVD50 | AC_RSV603DA)) && band == 0 && + group == 0)) { + temp = CBlock_DecodeHuffmanWordCB(bs, CodeBook); + factor += temp - 60; /* MIDFAC 1.5 dB */ + } + pScaleFactor[band] = factor - 100; + break; + + case INTENSITY_HCB: /* intensity steering */ + case INTENSITY_HCB2: + temp = CBlock_DecodeHuffmanWordCB(bs, CodeBook); + position += temp - 60; + pScaleFactor[band] = position - 100; + break; + + case NOISE_HCB: /* PNS */ + if (flags & (AC_MPEGD_RES | AC_USAC | AC_RSVD50 | AC_RSV603DA)) { + return AAC_DEC_PARSE_ERROR; + } + CPns_Read(&pAacDecoderChannelInfo->data.aac.PnsData, bs, hcb, + pAacDecoderChannelInfo->pDynData->aScaleFactor, + pAacDecoderChannelInfo->pDynData->RawDataInfo.GlobalGain, + band, group); + break; } } + pCodeBook += 16; + pScaleFactor += 16; } return AAC_DEC_OK; } -void CBlock_ScaleSpectralData(CAacDecoderChannelInfo *pAacDecoderChannelInfo, SamplingRateInfo *pSamplingRateInfo) -{ +void CBlock_ScaleSpectralData(CAacDecoderChannelInfo *pAacDecoderChannelInfo, + UCHAR maxSfbs, + SamplingRateInfo *pSamplingRateInfo) { int band; int window; - const SHORT * RESTRICT pSfbScale = pAacDecoderChannelInfo->pDynData->aSfbScale; - SHORT * RESTRICT pSpecScale = pAacDecoderChannelInfo->specScale; - int groupwin,group; - const SHORT * RESTRICT BandOffsets = GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo); - SPECTRAL_PTR RESTRICT pSpectralCoefficient = pAacDecoderChannelInfo->pSpectralCoefficient; - - - FDKmemclear(pSpecScale, 8*sizeof(SHORT)); - - int max_band = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); - for (window=0, group=0; group < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++) - { - for (groupwin=0; groupwin < GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo,group); groupwin++, window++) - { + const SHORT *RESTRICT pSfbScale = pAacDecoderChannelInfo->pDynData->aSfbScale; + SHORT *RESTRICT pSpecScale = pAacDecoderChannelInfo->specScale; + int groupwin, group; + const SHORT *RESTRICT BandOffsets = GetScaleFactorBandOffsets( + &pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo); + SPECTRAL_PTR RESTRICT pSpectralCoefficient = + pAacDecoderChannelInfo->pSpectralCoefficient; + + FDKmemclear(pSpecScale, 8 * sizeof(SHORT)); + + for (window = 0, group = 0; + group < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++) { + for (groupwin = 0; groupwin < GetWindowGroupLength( + &pAacDecoderChannelInfo->icsInfo, group); + groupwin++, window++) { int SpecScale_window = pSpecScale[window]; - FIXP_DBL *pSpectrum = SPEC(pSpectralCoefficient, window, pAacDecoderChannelInfo->granuleLength); + FIXP_DBL *pSpectrum = SPEC(pSpectralCoefficient, window, + pAacDecoderChannelInfo->granuleLength); /* find scaling for current window */ - for (band=0; band < max_band; band++) - { - SpecScale_window = fMax(SpecScale_window, (int)pSfbScale[window*16+band]); + for (band = 0; band < maxSfbs; band++) { + SpecScale_window = + fMax(SpecScale_window, (int)pSfbScale[window * 16 + band]); } - if (pAacDecoderChannelInfo->pDynData->TnsData.Active) { - SpecScale_window += TNS_SCALE; + if (pAacDecoderChannelInfo->pDynData->TnsData.Active && + pAacDecoderChannelInfo->pDynData->TnsData.NumberOfFilters[window] > + 0) { + int filter_index, SpecScale_window_tns; + int tns_start, tns_stop; + + /* Find max scale of TNS bands */ + SpecScale_window_tns = 0; + tns_start = GetMaximumTnsBands(&pAacDecoderChannelInfo->icsInfo, + pSamplingRateInfo->samplingRateIndex); + tns_stop = 0; + for (filter_index = 0; + filter_index < (int)pAacDecoderChannelInfo->pDynData->TnsData + .NumberOfFilters[window]; + filter_index++) { + for (band = pAacDecoderChannelInfo->pDynData->TnsData + .Filter[window][filter_index] + .StartBand; + band < pAacDecoderChannelInfo->pDynData->TnsData + .Filter[window][filter_index] + .StopBand; + band++) { + SpecScale_window_tns = + fMax(SpecScale_window_tns, (int)pSfbScale[window * 16 + band]); + } + /* Find TNS line boundaries for all TNS filters */ + tns_start = + fMin(tns_start, (int)pAacDecoderChannelInfo->pDynData->TnsData + .Filter[window][filter_index] + .StartBand); + tns_stop = + fMax(tns_stop, (int)pAacDecoderChannelInfo->pDynData->TnsData + .Filter[window][filter_index] + .StopBand); + } + SpecScale_window_tns = SpecScale_window_tns + + pAacDecoderChannelInfo->pDynData->TnsData.GainLd; + FDK_ASSERT(tns_stop >= tns_start); + /* Consider existing headroom of all MDCT lines inside the TNS bands. */ + SpecScale_window_tns -= + getScalefactor(pSpectrum + BandOffsets[tns_start], + BandOffsets[tns_stop] - BandOffsets[tns_start]); + if (SpecScale_window <= 17) { + SpecScale_window_tns++; + } + /* Add enough mantissa head room such that the spectrum is still + representable after applying TNS. */ + SpecScale_window = fMax(SpecScale_window, SpecScale_window_tns); } /* store scaling of current window */ @@ -247,79 +297,80 @@ void CBlock_ScaleSpectralData(CAacDecoderChannelInfo *pAacDecoderChannelInfo, Sa #ifdef FUNCTION_CBlock_ScaleSpectralData_func1 - CBlock_ScaleSpectralData_func1(pSpectrum, max_band, BandOffsets, SpecScale_window, pSfbScale, window); - -#else /* FUNCTION_CBlock_ScaleSpectralData_func1 */ - for (band=0; band < max_band; band++) - { - int scale = SpecScale_window - pSfbScale[window*16+band]; - if (scale) - { - /* following relation can be used for optimizations: (BandOffsets[i]%4) == 0 for all i */ - int max_index = BandOffsets[band+1]; - for (int index = BandOffsets[band]; index < max_index; index++) - { + CBlock_ScaleSpectralData_func1(pSpectrum, maxSfbs, BandOffsets, + SpecScale_window, pSfbScale, window); + +#else /* FUNCTION_CBlock_ScaleSpectralData_func1 */ + for (band = 0; band < maxSfbs; band++) { + int scale = fMin(DFRACT_BITS - 1, + SpecScale_window - pSfbScale[window * 16 + band]); + if (scale) { + FDK_ASSERT(scale > 0); + + /* following relation can be used for optimizations: + * (BandOffsets[i]%4) == 0 for all i */ + int max_index = BandOffsets[band + 1]; + DWORD_ALIGNED(pSpectrum); + for (int index = BandOffsets[band]; index < max_index; index++) { pSpectrum[index] >>= scale; } } } -#endif /* FUNCTION_CBlock_ScaleSpectralData_func1 */ +#endif /* FUNCTION_CBlock_ScaleSpectralData_func1 */ } } - } -AAC_DECODER_ERROR CBlock_ReadSectionData(HANDLE_FDK_BITSTREAM bs, - CAacDecoderChannelInfo *pAacDecoderChannelInfo, - const SamplingRateInfo *pSamplingRateInfo, - const UINT flags) -{ +AAC_DECODER_ERROR CBlock_ReadSectionData( + HANDLE_FDK_BITSTREAM bs, CAacDecoderChannelInfo *pAacDecoderChannelInfo, + const SamplingRateInfo *pSamplingRateInfo, const UINT flags) { int top, band; int sect_len, sect_len_incr; int group; UCHAR sect_cb; UCHAR *pCodeBook = pAacDecoderChannelInfo->pDynData->aCodeBook; /* HCR input (long) */ - SHORT *pNumLinesInSec = pAacDecoderChannelInfo->pDynData->specificTo.aac.aNumLineInSec4Hcr; - int numLinesInSecIdx = 0; - UCHAR *pHcrCodeBook = pAacDecoderChannelInfo->pDynData->specificTo.aac.aCodeBooks4Hcr; - const SHORT *BandOffsets = GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo); + SHORT *pNumLinesInSec = + pAacDecoderChannelInfo->pDynData->specificTo.aac.aNumLineInSec4Hcr; + int numLinesInSecIdx = 0; + UCHAR *pHcrCodeBook = + pAacDecoderChannelInfo->pDynData->specificTo.aac.aCodeBooks4Hcr; + const SHORT *BandOffsets = GetScaleFactorBandOffsets( + &pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo); pAacDecoderChannelInfo->pDynData->specificTo.aac.numberSection = 0; AAC_DECODER_ERROR ErrorStatus = AAC_DEC_OK; - FDKmemclear(pCodeBook, sizeof(UCHAR)*(8*16)); + FDKmemclear(pCodeBook, sizeof(UCHAR) * (8 * 16)); - const int nbits = (IsLongBlock(&pAacDecoderChannelInfo->icsInfo) == 1) ? 5 : 3; + const int nbits = + (IsLongBlock(&pAacDecoderChannelInfo->icsInfo) == 1) ? 5 : 3; - int sect_esc_val = (1 << nbits) - 1 ; + int sect_esc_val = (1 << nbits) - 1; - UCHAR ScaleFactorBandsTransmitted = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); - for (group=0; group<GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++) - { - for (band=0; band < ScaleFactorBandsTransmitted; ) - { + UCHAR ScaleFactorBandsTransmitted = + GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); + for (group = 0; group < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); + group++) { + for (band = 0; band < ScaleFactorBandsTransmitted;) { sect_len = 0; - if ( flags & AC_ER_VCB11 ) { - sect_cb = (UCHAR) FDKreadBits(bs,5); - } - else - sect_cb = (UCHAR) FDKreadBits(bs,4); + if (flags & AC_ER_VCB11) { + sect_cb = (UCHAR)FDKreadBits(bs, 5); + } else + sect_cb = (UCHAR)FDKreadBits(bs, 4); - if ( ((flags & AC_ER_VCB11) == 0) || ( sect_cb < 11 ) || ((sect_cb > 11) && (sect_cb < 16)) ) { + if (((flags & AC_ER_VCB11) == 0) || (sect_cb < 11) || + ((sect_cb > 11) && (sect_cb < 16))) { sect_len_incr = FDKreadBits(bs, nbits); - while (sect_len_incr == sect_esc_val) - { + while (sect_len_incr == sect_esc_val) { sect_len += sect_esc_val; sect_len_incr = FDKreadBits(bs, nbits); } - } - else { + } else { sect_len_incr = 1; } sect_len += sect_len_incr; - top = band + sect_len; if (flags & AC_ER_HCR) { @@ -327,10 +378,13 @@ AAC_DECODER_ERROR CBlock_ReadSectionData(HANDLE_FDK_BITSTREAM bs, if (numLinesInSecIdx >= MAX_SFB_HCR) { return AAC_DEC_PARSE_ERROR; } + if (top > (int)GetNumberOfScaleFactorBands( + &pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo)) { + return AAC_DEC_PARSE_ERROR; + } pNumLinesInSec[numLinesInSecIdx] = BandOffsets[top] - BandOffsets[band]; numLinesInSecIdx++; - if (sect_cb == BOOKSCL) - { + if (sect_cb == BOOKSCL) { return AAC_DEC_INVALID_CODE_BOOK; } else { *pHcrCodeBook++ = sect_cb; @@ -339,259 +393,340 @@ AAC_DECODER_ERROR CBlock_ReadSectionData(HANDLE_FDK_BITSTREAM bs, } /* Check spectral line limits */ - if (IsLongBlock( &(pAacDecoderChannelInfo->icsInfo) )) - { + if (IsLongBlock(&(pAacDecoderChannelInfo->icsInfo))) { if (top > 64) { return AAC_DEC_DECODE_FRAME_ERROR; } } else { /* short block */ - if (top + group*16 > (8 * 16)) { + if (top + group * 16 > (8 * 16)) { return AAC_DEC_DECODE_FRAME_ERROR; } } /* Check if decoded codebook index is feasible */ - if ( (sect_cb == BOOKSCL) - || ( (sect_cb == INTENSITY_HCB || sect_cb == INTENSITY_HCB2) && pAacDecoderChannelInfo->pDynData->RawDataInfo.CommonWindow == 0) - ) - { + if ((sect_cb == BOOKSCL) || + ((sect_cb == INTENSITY_HCB || sect_cb == INTENSITY_HCB2) && + pAacDecoderChannelInfo->pDynData->RawDataInfo.CommonWindow == 0)) { return AAC_DEC_INVALID_CODE_BOOK; } /* Store codebook index */ - for (; band < top; band++) - { - pCodeBook[group*16+band] = sect_cb; + for (; band < top; band++) { + pCodeBook[group * 16 + band] = sect_cb; } } } - return ErrorStatus; } /* mso: provides a faster way to i-quantize a whole band in one go */ /** - * \brief inverse quantize one sfb. Each value of the sfb is processed according to the - * formula: spectrum[i] = Sign(spectrum[i]) * Matissa(spectrum[i])^(4/3) * 2^(lsb/4). + * \brief inverse quantize one sfb. Each value of the sfb is processed according + * to the formula: spectrum[i] = Sign(spectrum[i]) * Matissa(spectrum[i])^(4/3) + * * 2^(lsb/4). * \param spectrum pointer to first line of the sfb to be inverse quantized. * \param noLines number of lines belonging to the sfb. * \param lsb last 2 bits of the scale factor of the sfb. * \param scale max allowed shift scale for the sfb. */ -static -void InverseQuantizeBand( FIXP_DBL * RESTRICT spectrum, - INT noLines, - INT lsb, - INT scale ) -{ - const FIXP_DBL * RESTRICT InverseQuantTabler=(FIXP_DBL *)InverseQuantTable; - const FIXP_DBL * RESTRICT MantissaTabler=(FIXP_DBL *)MantissaTable[lsb]; - const SCHAR* RESTRICT ExponentTabler=(SCHAR*)ExponentTable[lsb]; +static inline void InverseQuantizeBand( + FIXP_DBL *RESTRICT spectrum, const FIXP_DBL *RESTRICT InverseQuantTabler, + const FIXP_DBL *RESTRICT MantissaTabler, + const SCHAR *RESTRICT ExponentTabler, INT noLines, INT scale) { + scale = scale + 1; /* +1 to compensate fMultDiv2 shift-right in loop */ - FIXP_DBL *ptr = spectrum; - FIXP_DBL signedValue; + FIXP_DBL *RESTRICT ptr = spectrum; + FIXP_DBL signedValue; - FDK_ASSERT(noLines>2); - for (INT i=noLines; i--; ) - { - if ((signedValue = *ptr++) != FL2FXCONST_DBL(0)) - { - FIXP_DBL value = fAbs(signedValue); - UINT freeBits = CntLeadingZeros(value); - UINT exponent = 32 - freeBits; + for (INT i = noLines; i--;) { + if ((signedValue = *ptr++) != FL2FXCONST_DBL(0)) { + FIXP_DBL value = fAbs(signedValue); + UINT freeBits = CntLeadingZeros(value); + UINT exponent = 32 - freeBits; - UINT x = (UINT) (LONG)value << (INT) freeBits; - x <<= 1; /* shift out sign bit to avoid masking later on */ - UINT tableIndex = x >> 24; - x = (x >> 20) & 0x0F; + UINT x = (UINT)(LONG)value << (INT)freeBits; + x <<= 1; /* shift out sign bit to avoid masking later on */ + UINT tableIndex = x >> 24; + x = (x >> 20) & 0x0F; - UINT r0=(UINT)(LONG)InverseQuantTabler[tableIndex+0]; - UINT r1=(UINT)(LONG)InverseQuantTabler[tableIndex+1]; - UINT temp= (r1 - r0)*x + (r0 << 4); + UINT r0 = (UINT)(LONG)InverseQuantTabler[tableIndex + 0]; + UINT r1 = (UINT)(LONG)InverseQuantTabler[tableIndex + 1]; + UINT temp = (r1 - r0) * x + (r0 << 4); - value = fMultDiv2((FIXP_DBL)temp, MantissaTabler[exponent]); + value = fMultDiv2((FIXP_DBL)temp, MantissaTabler[exponent]); - /* + 1 compensates fMultDiv2() */ - scaleValueInPlace(&value, scale + ExponentTabler[exponent] + 1); + /* + 1 compensates fMultDiv2() */ + scaleValueInPlace(&value, scale + ExponentTabler[exponent]); - signedValue = (signedValue < (FIXP_DBL)0) ? -value : value; - ptr[-1] = signedValue; - } + signedValue = (signedValue < (FIXP_DBL)0) ? -value : value; + ptr[-1] = signedValue; } + } } -AAC_DECODER_ERROR CBlock_InverseQuantizeSpectralData(CAacDecoderChannelInfo *pAacDecoderChannelInfo, SamplingRateInfo *pSamplingRateInfo) -{ +static inline FIXP_DBL maxabs_D(const FIXP_DBL *pSpectralCoefficient, + const int noLines) { + /* Find max spectral line value of the current sfb */ + FIXP_DBL locMax = (FIXP_DBL)0; + int i; + + DWORD_ALIGNED(pSpectralCoefficient); + + for (i = noLines; i-- > 0;) { + /* Expensive memory access */ + locMax = fMax(fixp_abs(pSpectralCoefficient[i]), locMax); + } + + return locMax; +} + +AAC_DECODER_ERROR CBlock_InverseQuantizeSpectralData( + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + SamplingRateInfo *pSamplingRateInfo, UCHAR *band_is_noise, + UCHAR active_band_search) { int window, group, groupwin, band; - int ScaleFactorBandsTransmitted = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); + int ScaleFactorBandsTransmitted = + GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); UCHAR *RESTRICT pCodeBook = pAacDecoderChannelInfo->pDynData->aCodeBook; SHORT *RESTRICT pSfbScale = pAacDecoderChannelInfo->pDynData->aSfbScale; SHORT *RESTRICT pScaleFactor = pAacDecoderChannelInfo->pDynData->aScaleFactor; - const SHORT *RESTRICT BandOffsets = GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo); - - FDKmemclear(pAacDecoderChannelInfo->pDynData->aSfbScale, (8*16)*sizeof(SHORT)); - - for (window=0, group=0; group < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++) - { - for (groupwin=0; groupwin < GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo,group); groupwin++, window++) - { + const SHORT *RESTRICT BandOffsets = GetScaleFactorBandOffsets( + &pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo); + const SHORT total_bands = + GetScaleFactorBandsTotal(&pAacDecoderChannelInfo->icsInfo); + + FDKmemclear(pAacDecoderChannelInfo->pDynData->aSfbScale, + (8 * 16) * sizeof(SHORT)); + + for (window = 0, group = 0; + group < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++) { + for (groupwin = 0; groupwin < GetWindowGroupLength( + &pAacDecoderChannelInfo->icsInfo, group); + groupwin++, window++) { /* inverse quantization */ - for (band=0; band < ScaleFactorBandsTransmitted; band++) - { - FIXP_DBL *pSpectralCoefficient = SPEC(pAacDecoderChannelInfo->pSpectralCoefficient, window, pAacDecoderChannelInfo->granuleLength) + BandOffsets[band]; - - int noLines = BandOffsets[band+1] - BandOffsets[band]; - int bnds = group*16+band; - int i; - - if ((pCodeBook[bnds] == ZERO_HCB) - || (pCodeBook[bnds] == INTENSITY_HCB) - || (pCodeBook[bnds] == INTENSITY_HCB2) - ) + for (band = 0; band < ScaleFactorBandsTransmitted; band++) { + FIXP_DBL *pSpectralCoefficient = + SPEC(pAacDecoderChannelInfo->pSpectralCoefficient, window, + pAacDecoderChannelInfo->granuleLength) + + BandOffsets[band]; + FIXP_DBL locMax; + + const int noLines = BandOffsets[band + 1] - BandOffsets[band]; + const int bnds = group * 16 + band; + + if ((pCodeBook[bnds] == ZERO_HCB) || + (pCodeBook[bnds] == INTENSITY_HCB) || + (pCodeBook[bnds] == INTENSITY_HCB2)) continue; - if (pCodeBook[bnds] == NOISE_HCB) - { - /* Leave headroom for PNS values. + 1 because ceil(log2(2^(0.25*3))) = 1, - worst case of additional headroom required because of the scalefactor. */ - pSfbScale[window*16+band] = (pScaleFactor [bnds] >> 2) + 1 ; + if (pCodeBook[bnds] == NOISE_HCB) { + /* Leave headroom for PNS values. + 1 because ceil(log2(2^(0.25*3))) = + 1, worst case of additional headroom required because of the + scalefactor. */ + pSfbScale[window * 16 + band] = (pScaleFactor[bnds] >> 2) + 1; continue; } - /* Find max spectral line value of the current sfb */ - FIXP_DBL locMax = (FIXP_DBL)0; + locMax = maxabs_D(pSpectralCoefficient, noLines); - for (i = noLines; i-- ; ) { - /* Expensive memory access */ - locMax = fMax(fixp_abs(pSpectralCoefficient[i]), locMax); + if (active_band_search) { + if (locMax != FIXP_DBL(0)) { + band_is_noise[group * 16 + band] = 0; + } } /* Cheap robustness improvement - Do not remove!!! */ if (fixp_abs(locMax) > (FIXP_DBL)MAX_QUANTIZED_VALUE) { - return AAC_DEC_DECODE_FRAME_ERROR; + return AAC_DEC_PARSE_ERROR; } - /* - The inverse quantized spectral lines are defined by: - pSpectralCoefficient[i] = Sign(pSpectralCoefficient[i]) * 2^(0.25*pScaleFactor[bnds]) * pSpectralCoefficient[i]^(4/3) - This is equivalent to: - pSpectralCoefficient[i] = Sign(pSpectralCoefficient[i]) * (2^(pScaleFactor[bnds] % 4) * pSpectralCoefficient[i]^(4/3)) - pSpectralCoefficient_e[i] += pScaleFactor[bnds]/4 + /* Added by Youliy Ninov: + The inverse quantization operation is given by (ISO/IEC 14496-3:2009(E)) + by: + + x_invquant=Sign(x_quant). abs(x_quant)^(4/3) + + We apply a gain, derived from the scale factor for the particular sfb, + according to the following function: + + gain=2^(0.25*ScaleFactor) + + So, after scaling we have: + + x_rescale=gain*x_invquant=Sign(x_quant)*2^(0.25*ScaleFactor)*abs(s_quant)^(4/3) + + We could represent the ScaleFactor as: + + ScaleFactor= (ScaleFactor >> 2)*4 + ScaleFactor %4 + + When we substitute it we get: + + x_rescale=Sign(x_quant)*2^(ScaleFactor>>2)* ( + 2^(0.25*(ScaleFactor%4))*abs(s_quant)^(4/3)) + + When we set: msb=(ScaleFactor>>2) and lsb=(ScaleFactor%4), we obtain: + + x_rescale=Sign(x_quant)*(2^msb)* ( 2^(lsb/4)*abs(s_quant)^(4/3)) + + The rescaled output can be represented by: + mantissa : Sign(x_quant)*( 2^(lsb/4)*abs(s_quant)^(4/3)) + exponent :(2^msb) + */ - { - int msb = pScaleFactor [bnds] >> 2 ; - int lsb = pScaleFactor [bnds] & 0x03 ; - int scale = GetScaleFromValue(locMax, lsb); + int msb = pScaleFactor[bnds] >> 2; - pSfbScale[window*16+band] = msb - scale; - InverseQuantizeBand(pSpectralCoefficient, noLines, lsb, scale); + /* Inverse quantize band only if it is not empty */ + if (locMax != FIXP_DBL(0)) { + int lsb = pScaleFactor[bnds] & 0x03; + + int scale = EvaluatePower43(&locMax, lsb); + + scale = CntLeadingZeros(locMax) - scale - 2; + + pSfbScale[window * 16 + band] = msb - scale; + InverseQuantizeBand(pSpectralCoefficient, InverseQuantTable, + MantissaTable[lsb], ExponentTable[lsb], noLines, + scale); + } else { + pSfbScale[window * 16 + band] = msb; } - } - } - } + } /* for (band=0; band < ScaleFactorBandsTransmitted; band++) */ - return AAC_DEC_OK; -} + /* Make sure the array is cleared to the end */ + SHORT start_clear = BandOffsets[ScaleFactorBandsTransmitted]; + SHORT end_clear = BandOffsets[total_bands]; + int diff_clear = (int)(end_clear - start_clear); + FIXP_DBL *pSpectralCoefficient = + SPEC(pAacDecoderChannelInfo->pSpectralCoefficient, window, + pAacDecoderChannelInfo->granuleLength) + + start_clear; + FDKmemclear(pSpectralCoefficient, diff_clear * sizeof(FIXP_DBL)); + } /* for (groupwin=0; groupwin < + GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo,group); + groupwin++, window++) */ + } /* for (window=0, group=0; group < + GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++)*/ -AAC_DECODER_ERROR CBlock_ReadSpectralData(HANDLE_FDK_BITSTREAM bs, - CAacDecoderChannelInfo *pAacDecoderChannelInfo, - const SamplingRateInfo *pSamplingRateInfo, - const UINT flags) -{ - int i,index; - int window,group,groupwin,groupoffset,band; - UCHAR *RESTRICT pCodeBook = pAacDecoderChannelInfo->pDynData->aCodeBook; - const SHORT *RESTRICT BandOffsets = GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo); + return AAC_DEC_OK; +} - SPECTRAL_PTR pSpectralCoefficient = pAacDecoderChannelInfo->pSpectralCoefficient; - FIXP_DBL locMax; +AAC_DECODER_ERROR CBlock_ReadSpectralData( + HANDLE_FDK_BITSTREAM bs, CAacDecoderChannelInfo *pAacDecoderChannelInfo, + const SamplingRateInfo *pSamplingRateInfo, const UINT flags) { + int index, i; + const SHORT *RESTRICT BandOffsets = GetScaleFactorBandOffsets( + &pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo); - int ScaleFactorBandsTransmitted = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); + SPECTRAL_PTR pSpectralCoefficient = + pAacDecoderChannelInfo->pSpectralCoefficient; FDK_ASSERT(BandOffsets != NULL); FDKmemclear(pSpectralCoefficient, sizeof(SPECTRUM)); - if ( (flags & AC_ER_HCR) == 0 ) - { + if ((flags & AC_ER_HCR) == 0) { + int group; + int groupoffset; + UCHAR *pCodeBook = pAacDecoderChannelInfo->pDynData->aCodeBook; + int ScaleFactorBandsTransmitted = + GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); + int granuleLength = pAacDecoderChannelInfo->granuleLength; + groupoffset = 0; /* plain huffman decoder short */ - for (group=0; group < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++) - { - for (band=0; band < ScaleFactorBandsTransmitted; band++) - { - int bnds = group*16+band; + int max_group = GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); + + for (group = 0; group < max_group; group++) { + int max_groupwin = + GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo, group); + int band; + + int bnds = group * 16; + + int bandOffset1 = BandOffsets[0]; + for (band = 0; band < ScaleFactorBandsTransmitted; band++, bnds++) { UCHAR currentCB = pCodeBook[bnds]; + int bandOffset0 = bandOffset1; + bandOffset1 = BandOffsets[band + 1]; - /* patch to run plain-huffman-decoder with vcb11 input codebooks (LAV-checking might be possible below using the virtual cb and a LAV-table) */ + /* patch to run plain-huffman-decoder with vcb11 input codebooks + * (LAV-checking might be possible below using the virtual cb and a + * LAV-table) */ if ((currentCB >= 16) && (currentCB <= 31)) { pCodeBook[bnds] = currentCB = 11; } - if ( !((currentCB == ZERO_HCB) - || (currentCB == NOISE_HCB) - || (currentCB == INTENSITY_HCB) - || (currentCB == INTENSITY_HCB2)) ) - { - const CodeBookDescription *hcb = &AACcodeBookDescriptionTable[currentCB]; + if (((currentCB != ZERO_HCB) && (currentCB != NOISE_HCB) && + (currentCB != INTENSITY_HCB) && (currentCB != INTENSITY_HCB2))) { + const CodeBookDescription *hcb = + &AACcodeBookDescriptionTable[currentCB]; int step = hcb->Dimension; int offset = hcb->Offset; int bits = hcb->numBits; - int mask = (1<<bits)-1; - - for (groupwin=0; groupwin < GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo,group); groupwin++) - { - window = groupoffset + groupwin; - - FIXP_DBL *mdctSpectrum = SPEC(pSpectralCoefficient, window, pAacDecoderChannelInfo->granuleLength); - - locMax = (FIXP_DBL)0 ; - - for (index=BandOffsets[band]; index < BandOffsets[band+1]; index+=step) - { - int idx = CBlock_DecodeHuffmanWord(bs,hcb); - - for (i=0; i<step; i++) { - FIXP_DBL tmp; - - tmp = (FIXP_DBL)((idx & mask)-offset); - idx >>= bits; + int mask = (1 << bits) - 1; + const USHORT(*CodeBook)[HuffmanEntries] = hcb->CodeBook; + int groupwin; + + FIXP_DBL *mdctSpectrum = + &pSpectralCoefficient[groupoffset * granuleLength]; + + if (offset == 0) { + for (groupwin = 0; groupwin < max_groupwin; groupwin++) { + for (index = bandOffset0; index < bandOffset1; index += step) { + int idx = CBlock_DecodeHuffmanWordCB(bs, CodeBook); + for (i = 0; i < step; i++, idx >>= bits) { + FIXP_DBL tmp = (FIXP_DBL)((idx & mask) - offset); + if (tmp != FIXP_DBL(0)) tmp = (FDKreadBit(bs)) ? -tmp : tmp; + mdctSpectrum[index + i] = tmp; + } - if (offset == 0) { - if (tmp != FIXP_DBL(0)) - tmp = (FDKreadBits(bs,1))? -tmp : tmp; + if (currentCB == ESCBOOK) { + for (int j = 0; j < 2; j++) + mdctSpectrum[index + j] = (FIXP_DBL)CBlock_GetEscape( + bs, (LONG)mdctSpectrum[index + j]); } - mdctSpectrum[index+i] = tmp; } - - if (currentCB == ESCBOOK) - { - mdctSpectrum[index+0] = (FIXP_DBL)CBlock_GetEscape(bs, (LONG)mdctSpectrum[index+0]); - mdctSpectrum[index+1] = (FIXP_DBL)CBlock_GetEscape(bs, (LONG)mdctSpectrum[index+1]); - + mdctSpectrum += granuleLength; + } + } else { + for (groupwin = 0; groupwin < max_groupwin; groupwin++) { + for (index = bandOffset0; index < bandOffset1; index += step) { + int idx = CBlock_DecodeHuffmanWordCB(bs, CodeBook); + for (i = 0; i < step; i++, idx >>= bits) { + mdctSpectrum[index + i] = (FIXP_DBL)((idx & mask) - offset); + } + if (currentCB == ESCBOOK) { + for (int j = 0; j < 2; j++) + mdctSpectrum[index + j] = (FIXP_DBL)CBlock_GetEscape( + bs, (LONG)mdctSpectrum[index + j]); + } } + mdctSpectrum += granuleLength; } } } } - groupoffset += GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo,group); + groupoffset += max_groupwin; } /* plain huffman decoding (short) finished */ } + /* HCR - Huffman Codeword Reordering short */ - else /* if ( flags & AC_ER_HCR ) */ + else /* if ( flags & AC_ER_HCR ) */ + { H_HCR_INFO hHcr = &pAacDecoderChannelInfo->pComData->overlay.aac.erHcrInfo; + int hcrStatus = 0; /* advanced Huffman decoding starts here (HCR decoding :) */ - if ( pAacDecoderChannelInfo->pDynData->specificTo.aac.lenOfReorderedSpectralData != 0 ) { - + if (pAacDecoderChannelInfo->pDynData->specificTo.aac + .lenOfReorderedSpectralData != 0) { /* HCR initialization short */ hcrStatus = HcrInit(hHcr, pAacDecoderChannelInfo, pSamplingRateInfo, bs); @@ -600,7 +735,8 @@ AAC_DECODER_ERROR CBlock_ReadSpectralData(HANDLE_FDK_BITSTREAM bs, } /* HCR decoding short */ - hcrStatus = HcrDecoder(hHcr, pAacDecoderChannelInfo, pSamplingRateInfo, bs); + hcrStatus = + HcrDecoder(hHcr, pAacDecoderChannelInfo, pSamplingRateInfo, bs); if (hcrStatus != 0) { #if HCR_ERROR_CONCEALMENT @@ -610,100 +746,314 @@ AAC_DECODER_ERROR CBlock_ReadSpectralData(HANDLE_FDK_BITSTREAM bs, #endif /* HCR_ERROR_CONCEALMENT */ } - FDKpushFor (bs, pAacDecoderChannelInfo->pDynData->specificTo.aac.lenOfReorderedSpectralData); + FDKpushFor(bs, pAacDecoderChannelInfo->pDynData->specificTo.aac + .lenOfReorderedSpectralData); } } /* HCR - Huffman Codeword Reordering short finished */ + if (IsLongBlock(&pAacDecoderChannelInfo->icsInfo) && + !(flags & (AC_ELD | AC_SCALABLE))) { + /* apply pulse data */ + CPulseData_Apply( + &pAacDecoderChannelInfo->pDynData->specificTo.aac.PulseData, + GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, + pSamplingRateInfo), + SPEC_LONG(pSpectralCoefficient)); + } + return AAC_DEC_OK; +} - if ( IsLongBlock(&pAacDecoderChannelInfo->icsInfo) && !(flags & (AC_ELD|AC_SCALABLE)) ) - { - /* apply pulse data */ - CPulseData_Apply(&pAacDecoderChannelInfo->pDynData->specificTo.aac.PulseData, - GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo), - SPEC_LONG(pSpectralCoefficient)); +static const FIXP_SGL noise_level_tab[8] = { + /* FDKpow(2, (float)(noise_level-14)/3.0f) * 2; (*2 to compensate for + fMultDiv2) noise_level_tab(noise_level==0) == 0 by definition + */ + FX_DBL2FXCONST_SGL(0x00000000 /*0x0a145173*/), + FX_DBL2FXCONST_SGL(0x0cb2ff5e), + FX_DBL2FXCONST_SGL(0x10000000), + FX_DBL2FXCONST_SGL(0x1428a2e7), + FX_DBL2FXCONST_SGL(0x1965febd), + FX_DBL2FXCONST_SGL(0x20000000), + FX_DBL2FXCONST_SGL(0x28514606), + FX_DBL2FXCONST_SGL(0x32cbfd33)}; + +void CBlock_ApplyNoise(CAacDecoderChannelInfo *pAacDecoderChannelInfo, + SamplingRateInfo *pSamplingRateInfo, ULONG *nfRandomSeed, + UCHAR *band_is_noise) { + const SHORT *swb_offset = GetScaleFactorBandOffsets( + &pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo); + int g, win, gwin, sfb, noiseFillingStartOffset, nfStartOffset_sfb; + + /* Obtain noise level and scale factor offset. */ + int noise_level = pAacDecoderChannelInfo->pDynData->specificTo.usac + .fd_noise_level_and_offset >> + 5; + const FIXP_SGL noiseVal_pos = noise_level_tab[noise_level]; + + /* noise_offset can change even when noise_level=0. Neccesary for IGF stereo + * filling */ + const int noise_offset = (pAacDecoderChannelInfo->pDynData->specificTo.usac + .fd_noise_level_and_offset & + 0x1f) - + 16; + + int max_sfb = + GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); + + noiseFillingStartOffset = + (GetWindowSequence(&pAacDecoderChannelInfo->icsInfo) == BLOCK_SHORT) + ? 20 + : 160; + if (pAacDecoderChannelInfo->granuleLength == 96) { + noiseFillingStartOffset = + (3 * noiseFillingStartOffset) / + 4; /* scale offset with 3/4 for coreCoderFrameLength == 768 */ } + /* determine sfb from where on noise filling is applied */ + for (sfb = 0; swb_offset[sfb] < noiseFillingStartOffset; sfb++) + ; + nfStartOffset_sfb = sfb; - return AAC_DEC_OK; + /* if (noise_level!=0) */ + { + for (g = 0, win = 0; g < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); + g++) { + int windowGroupLength = + GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo, g); + for (sfb = nfStartOffset_sfb; sfb < max_sfb; sfb++) { + int bin_start = swb_offset[sfb]; + int bin_stop = swb_offset[sfb + 1]; + + int flagN = band_is_noise[g * 16 + sfb]; + + /* if all bins of one sfb in one window group are zero modify the scale + * factor by noise_offset */ + if (flagN) { + /* Change scaling factors for empty signal bands */ + pAacDecoderChannelInfo->pDynData->aScaleFactor[g * 16 + sfb] += + noise_offset; + /* scale factor "sf" implied gain "g" is g = 2^(sf/4) */ + for (gwin = 0; gwin < windowGroupLength; gwin++) { + pAacDecoderChannelInfo->pDynData + ->aSfbScale[(win + gwin) * 16 + sfb] += (noise_offset >> 2); + } + } + + ULONG seed = *nfRandomSeed; + /* + 1 because exponent of MantissaTable[lsb][0] is always 1. */ + int scale = + (pAacDecoderChannelInfo->pDynData->aScaleFactor[g * 16 + sfb] >> + 2) + + 1; + int lsb = + pAacDecoderChannelInfo->pDynData->aScaleFactor[g * 16 + sfb] & 3; + FIXP_DBL mantissa = MantissaTable[lsb][0]; + + for (gwin = 0; gwin < windowGroupLength; gwin++) { + FIXP_DBL *pSpec = + SPEC(pAacDecoderChannelInfo->pSpectralCoefficient, win + gwin, + pAacDecoderChannelInfo->granuleLength); + + int scale1 = scale - pAacDecoderChannelInfo->pDynData + ->aSfbScale[(win + gwin) * 16 + sfb]; + FIXP_DBL scaled_noiseVal_pos = + scaleValue(fMultDiv2(noiseVal_pos, mantissa), scale1); + FIXP_DBL scaled_noiseVal_neg = -scaled_noiseVal_pos; + + /* If the whole band is zero, just fill without checking */ + if (flagN) { + for (int bin = bin_start; bin < bin_stop; bin++) { + seed = (ULONG)( + (UINT64)seed * 69069 + + 5); /* Inlined: UsacRandomSign - origin in usacdec_lpd.h */ + pSpec[bin] = + (seed & 0x10000) ? scaled_noiseVal_neg : scaled_noiseVal_pos; + } /* for (bin...) */ + } + /*If band is sparsely filled, check for 0 and fill */ + else { + for (int bin = bin_start; bin < bin_stop; bin++) { + if (pSpec[bin] == (FIXP_DBL)0) { + seed = (ULONG)( + (UINT64)seed * 69069 + + 5); /* Inlined: UsacRandomSign - origin in usacdec_lpd.h */ + pSpec[bin] = (seed & 0x10000) ? scaled_noiseVal_neg + : scaled_noiseVal_pos; + } + } /* for (bin...) */ + } + + } /* for (gwin...) */ + *nfRandomSeed = seed; + } /* for (sfb...) */ + win += windowGroupLength; + } /* for (g...) */ + + } /* ... */ } +AAC_DECODER_ERROR CBlock_ReadAcSpectralData( + HANDLE_FDK_BITSTREAM hBs, CAacDecoderChannelInfo *pAacDecoderChannelInfo, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, + const SamplingRateInfo *pSamplingRateInfo, const UINT frame_length, + const UINT flags) { + AAC_DECODER_ERROR errorAAC = AAC_DEC_OK; + ARITH_CODING_ERROR error = ARITH_CODER_OK; + int arith_reset_flag, lg, numWin, win, winLen; + const SHORT *RESTRICT BandOffsets; + + /* number of transmitted spectral coefficients */ + BandOffsets = GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, + pSamplingRateInfo); + lg = BandOffsets[GetScaleFactorBandsTransmitted( + &pAacDecoderChannelInfo->icsInfo)]; + + numWin = GetWindowsPerFrame(&pAacDecoderChannelInfo->icsInfo); + winLen = (IsLongBlock(&pAacDecoderChannelInfo->icsInfo)) + ? (int)frame_length + : (int)frame_length / numWin; + + if (flags & AC_INDEP) { + arith_reset_flag = 1; + } else { + arith_reset_flag = (USHORT)FDKreadBits(hBs, 1); + } + + for (win = 0; win < numWin; win++) { + error = + CArco_DecodeArithData(pAacDecoderStaticChannelInfo->hArCo, hBs, + SPEC(pAacDecoderChannelInfo->pSpectralCoefficient, + win, pAacDecoderChannelInfo->granuleLength), + lg, winLen, arith_reset_flag && (win == 0)); + if (error != ARITH_CODER_OK) { + goto bail; + } + } +bail: + if (error == ARITH_CODER_ERROR) { + errorAAC = AAC_DEC_PARSE_ERROR; + } -void ApplyTools ( CAacDecoderChannelInfo *pAacDecoderChannelInfo[], - const SamplingRateInfo *pSamplingRateInfo, - const UINT flags, - const int channel ) -{ + return errorAAC; +} - if ( !(flags & (AC_USAC|AC_RSVD50|AC_MPS_RES)) ) { - CPns_Apply( - &pAacDecoderChannelInfo[channel]->data.aac.PnsData, - &pAacDecoderChannelInfo[channel]->icsInfo, - pAacDecoderChannelInfo[channel]->pSpectralCoefficient, - pAacDecoderChannelInfo[channel]->specScale, - pAacDecoderChannelInfo[channel]->pDynData->aScaleFactor, - pSamplingRateInfo, - pAacDecoderChannelInfo[channel]->granuleLength, - channel - ); +void ApplyTools(CAacDecoderChannelInfo *pAacDecoderChannelInfo[], + const SamplingRateInfo *pSamplingRateInfo, const UINT flags, + const UINT elFlags, const int channel, + const int common_window) { + if (!(flags & (AC_USAC | AC_RSVD50 | AC_MPEGD_RES | AC_RSV603DA))) { + CPns_Apply(&pAacDecoderChannelInfo[channel]->data.aac.PnsData, + &pAacDecoderChannelInfo[channel]->icsInfo, + pAacDecoderChannelInfo[channel]->pSpectralCoefficient, + pAacDecoderChannelInfo[channel]->specScale, + pAacDecoderChannelInfo[channel]->pDynData->aScaleFactor, + pSamplingRateInfo, + pAacDecoderChannelInfo[channel]->granuleLength, channel); } - CTns_Apply ( - &pAacDecoderChannelInfo[channel]->pDynData->TnsData, - &pAacDecoderChannelInfo[channel]->icsInfo, - pAacDecoderChannelInfo[channel]->pSpectralCoefficient, - pSamplingRateInfo, - pAacDecoderChannelInfo[channel]->granuleLength - ); + UCHAR nbands = + GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo[channel]->icsInfo); + + CTns_Apply(&pAacDecoderChannelInfo[channel]->pDynData->TnsData, + &pAacDecoderChannelInfo[channel]->icsInfo, + pAacDecoderChannelInfo[channel]->pSpectralCoefficient, + pSamplingRateInfo, pAacDecoderChannelInfo[channel]->granuleLength, + nbands, (elFlags & AC_EL_ENHANCED_NOISE) ? 1 : 0, flags); } -static -int getWindow2Nr(int length, int shape) -{ +static int getWindow2Nr(int length, int shape) { int nr = 0; if (shape == 2) { /* Low Overlap, 3/4 zeroed */ - nr = (length * 3)>>2; + nr = (length * 3) >> 2; } return nr; } -void CBlock_FrequencyToTime(CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, - CAacDecoderChannelInfo *pAacDecoderChannelInfo, - INT_PCM outSamples[], - const SHORT frameLen, - const int stride, - const int frameOk, - FIXP_DBL *pWorkBuffer1 ) -{ - int fr, fl, tl, nSamples, nSpec; +FIXP_DBL get_gain(const FIXP_DBL *x, const FIXP_DBL *y, int n) { + FIXP_DBL corr = (FIXP_DBL)0; + FIXP_DBL ener = (FIXP_DBL)1; + + int headroom_x = getScalefactor(x, n); + int headroom_y = getScalefactor(y, n); + + /*Calculate the normalization necessary due to addition*/ + /* Check for power of two /special case */ + INT width_shift = (INT)(fNormz((FIXP_DBL)n)); + /* Get the number of bits necessary minus one, because we need one sign bit + * only */ + width_shift = 31 - width_shift; + + for (int i = 0; i < n; i++) { + corr += + fMultDiv2((x[i] << headroom_x), (y[i] << headroom_y)) >> width_shift; + ener += fPow2Div2((y[i] << headroom_y)) >> width_shift; + } + + int exp_corr = (17 - headroom_x) + (17 - headroom_y) + width_shift + 1; + int exp_ener = ((17 - headroom_y) << 1) + width_shift + 1; + + int temp_exp = 0; + FIXP_DBL output = fDivNormSigned(corr, ener, &temp_exp); + + int output_exp = (exp_corr - exp_ener) + temp_exp; + + INT output_shift = 17 - output_exp; + output_shift = fMin(output_shift, 31); + + output = scaleValue(output, -output_shift); + + return output; +} + +void CBlock_FrequencyToTime( + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, FIXP_PCM outSamples[], + const SHORT frameLen, const int frameOk, FIXP_DBL *pWorkBuffer1, + UINT elFlags, INT elCh) { + int fr, fl, tl, nSpec; - /* Determine left slope length (fl), right slope length (fr) and transform length (tl). - USAC: The slope length may mismatch with the previous frame in case of LPD / FD - transitions. The adjustment is handled by the imdct implementation. +#if defined(FDK_ASSERT_ENABLE) + LONG nSamples; +#endif + + /* Determine left slope length (fl), right slope length (fr) and transform + length (tl). USAC: The slope length may mismatch with the previous frame in + case of LPD / FD transitions. The adjustment is handled by the imdct + implementation. */ tl = frameLen; nSpec = 1; - switch( pAacDecoderChannelInfo->icsInfo.WindowSequence ) { + switch (pAacDecoderChannelInfo->icsInfo.WindowSequence) { default: - case OnlyLongSequence: + case BLOCK_LONG: fl = frameLen; - fr = frameLen - getWindow2Nr(frameLen, GetWindowShape(&pAacDecoderChannelInfo->icsInfo)); + fr = frameLen - + getWindow2Nr(frameLen, + GetWindowShape(&pAacDecoderChannelInfo->icsInfo)); + /* New startup needs differentiation between sine shape and low overlap + shape. This is a special case for the LD-AAC transformation windows, + because the slope length can be different while using the same window + sequence. */ + if (pAacDecoderStaticChannelInfo->IMdct.prev_tl == 0) { + fl = fr; + } break; - case LongStopSequence: + case BLOCK_STOP: fl = frameLen >> 3; fr = frameLen; break; - case LongStartSequence: /* or StopStartSequence */ + case BLOCK_START: /* or StopStartSequence */ fl = frameLen; fr = frameLen >> 3; break; - case EightShortSequence: + case BLOCK_SHORT: fl = fr = frameLen >> 3; tl >>= 3; nSpec = 8; @@ -711,48 +1061,198 @@ void CBlock_FrequencyToTime(CAacDecoderStaticChannelInfo *pAacDecoderStaticChann } { - int i; + int last_frame_lost = pAacDecoderStaticChannelInfo->last_lpc_lost; - { - FIXP_DBL *tmp = pAacDecoderChannelInfo->pComData->workBufferCore1->mdctOutTemp; - - nSamples = imdct_block( - &pAacDecoderStaticChannelInfo->IMdct, - tmp, - SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient), - pAacDecoderChannelInfo->specScale, - nSpec, - frameLen, - tl, - FDKgetWindowSlope(fl, GetWindowShape(&pAacDecoderChannelInfo->icsInfo)), - fl, - FDKgetWindowSlope(fr, GetWindowShape(&pAacDecoderChannelInfo->icsInfo)), - fr, - (FIXP_DBL)0 ); - - for (i=0; i<frameLen; i++) { - outSamples[i*stride] = IMDCT_SCALE(tmp[i]); + if (pAacDecoderStaticChannelInfo->last_core_mode == LPD) { + INT fac_FB = 1; + if (elFlags & AC_EL_FULLBANDLPD) { + fac_FB = 2; + } + + FIXP_DBL *synth; + + /* Keep some free space at the beginning of the buffer. To be used for + * past data */ + if (!(elFlags & AC_EL_LPDSTEREOIDX)) { + synth = pWorkBuffer1 + ((PIT_MAX_MAX - (1 * L_SUBFR)) * fac_FB); + } else { + synth = pWorkBuffer1 + PIT_MAX_MAX * fac_FB; } + + int fac_length = + (pAacDecoderChannelInfo->icsInfo.WindowSequence == BLOCK_SHORT) + ? (frameLen >> 4) + : (frameLen >> 3); + + INT pitch[NB_SUBFR_SUPERFR + SYN_SFD]; + FIXP_DBL pit_gain[NB_SUBFR_SUPERFR + SYN_SFD]; + + int nbDiv = (elFlags & AC_EL_FULLBANDLPD) ? 2 : 4; + int lFrame = (elFlags & AC_EL_FULLBANDLPD) ? frameLen / 2 : frameLen; + int nbSubfr = + lFrame / (nbDiv * L_SUBFR); /* number of subframes per division */ + int LpdSfd = (nbDiv * nbSubfr) >> 1; + int SynSfd = LpdSfd - BPF_SFD; + + FDKmemclear( + pitch, + sizeof( + pitch)); // added to prevent ferret errors in bass_pf_1sf_delay + FDKmemclear(pit_gain, sizeof(pit_gain)); + + /* FAC case */ + if (pAacDecoderStaticChannelInfo->last_lpd_mode == 0 || + pAacDecoderStaticChannelInfo->last_lpd_mode == 4) { + FIXP_DBL fac_buf[LFAC]; + FIXP_LPC *A = pAacDecoderChannelInfo->data.usac.lp_coeff[0]; + + if (!frameOk || last_frame_lost || + (pAacDecoderChannelInfo->data.usac.fac_data[0] == NULL)) { + FDKmemclear(fac_buf, + pAacDecoderChannelInfo->granuleLength * sizeof(FIXP_DBL)); + pAacDecoderChannelInfo->data.usac.fac_data[0] = fac_buf; + pAacDecoderChannelInfo->data.usac.fac_data_e[0] = 0; + } + + INT A_exp; /* linear prediction coefficients exponent */ + { + for (int i = 0; i < M_LP_FILTER_ORDER; i++) { + A[i] = FX_DBL2FX_LPC(fixp_cos( + fMult(pAacDecoderStaticChannelInfo->lpc4_lsf[i], + FL2FXCONST_SGL((1 << LSPARG_SCALE) * M_PI / 6400.0)), + LSF_SCALE - LSPARG_SCALE)); + } + + E_LPC_f_lsp_a_conversion(A, A, &A_exp); + } + +#if defined(FDK_ASSERT_ENABLE) + nSamples = +#endif + CLpd_FAC_Acelp2Mdct( + &pAacDecoderStaticChannelInfo->IMdct, synth, + SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient), + pAacDecoderChannelInfo->specScale, nSpec, + pAacDecoderChannelInfo->data.usac.fac_data[0], + pAacDecoderChannelInfo->data.usac.fac_data_e[0], fac_length, + frameLen, tl, + FDKgetWindowSlope( + fr, GetWindowShape(&pAacDecoderChannelInfo->icsInfo)), + fr, A, A_exp, &pAacDecoderStaticChannelInfo->acelp, + (FIXP_DBL)0, /* FAC gain has already been applied. */ + (last_frame_lost || !frameOk), 1, + pAacDecoderStaticChannelInfo->last_lpd_mode, 0, + pAacDecoderChannelInfo->currAliasingSymmetry); + + } else { +#if defined(FDK_ASSERT_ENABLE) + nSamples = +#endif + imlt_block( + &pAacDecoderStaticChannelInfo->IMdct, synth, + SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient), + pAacDecoderChannelInfo->specScale, nSpec, frameLen, tl, + FDKgetWindowSlope( + fl, GetWindowShape(&pAacDecoderChannelInfo->icsInfo)), + fl, + FDKgetWindowSlope( + fr, GetWindowShape(&pAacDecoderChannelInfo->icsInfo)), + fr, (FIXP_DBL)0, + pAacDecoderChannelInfo->currAliasingSymmetry + ? MLT_FLAG_CURR_ALIAS_SYMMETRY + : 0); + } + FDK_ASSERT(nSamples == frameLen); + + /* The "if" clause is entered both for fullbandLpd mono and + * non-fullbandLpd*. The "else"-> just for fullbandLpd stereo*/ + if (!(elFlags & AC_EL_LPDSTEREOIDX)) { + FDKmemcpy(pitch, pAacDecoderStaticChannelInfo->old_T_pf, + SynSfd * sizeof(INT)); + FDKmemcpy(pit_gain, pAacDecoderStaticChannelInfo->old_gain_pf, + SynSfd * sizeof(FIXP_DBL)); + + for (int i = SynSfd; i < LpdSfd + 3; i++) { + pitch[i] = L_SUBFR; + pit_gain[i] = (FIXP_DBL)0; + } + + if (pAacDecoderStaticChannelInfo->last_lpd_mode == 0) { + pitch[SynSfd] = pitch[SynSfd - 1]; + pit_gain[SynSfd] = pit_gain[SynSfd - 1]; + if (IsLongBlock(&pAacDecoderChannelInfo->icsInfo)) { + pitch[SynSfd + 1] = pitch[SynSfd]; + pit_gain[SynSfd + 1] = pit_gain[SynSfd]; + } + } + + /* Copy old data to the beginning of the buffer */ + { + FDKmemcpy( + pWorkBuffer1, pAacDecoderStaticChannelInfo->old_synth, + ((PIT_MAX_MAX - (1 * L_SUBFR)) * fac_FB) * sizeof(FIXP_DBL)); + } + + FIXP_DBL *p2_synth = pWorkBuffer1 + (PIT_MAX_MAX * fac_FB); + + /* recalculate pitch gain to allow postfilering on FAC area */ + for (int i = 0; i < SynSfd + 2; i++) { + int T = pitch[i]; + FIXP_DBL gain = pit_gain[i]; + + if (gain > (FIXP_DBL)0) { + gain = get_gain(&p2_synth[i * L_SUBFR * fac_FB], + &p2_synth[(i * L_SUBFR * fac_FB) - fac_FB * T], + L_SUBFR * fac_FB); + pit_gain[i] = gain; + } + } + + bass_pf_1sf_delay(p2_synth, pitch, pit_gain, frameLen, + (LpdSfd + 2) * L_SUBFR + BPF_SFD * L_SUBFR, + frameLen - (LpdSfd + 4) * L_SUBFR, outSamples, + pAacDecoderStaticChannelInfo->mem_bpf); + } + + } else /* last_core_mode was not LPD */ + { + FIXP_DBL *tmp = + pAacDecoderChannelInfo->pComStaticData->pWorkBufferCore1->mdctOutTemp; +#if defined(FDK_ASSERT_ENABLE) + nSamples = +#endif + imlt_block(&pAacDecoderStaticChannelInfo->IMdct, tmp, + SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient), + pAacDecoderChannelInfo->specScale, nSpec, frameLen, tl, + FDKgetWindowSlope( + fl, GetWindowShape(&pAacDecoderChannelInfo->icsInfo)), + fl, + FDKgetWindowSlope( + fr, GetWindowShape(&pAacDecoderChannelInfo->icsInfo)), + fr, (FIXP_DBL)0, + pAacDecoderChannelInfo->currAliasingSymmetry + ? MLT_FLAG_CURR_ALIAS_SYMMETRY + : 0); + + scaleValuesSaturate(outSamples, tmp, frameLen, MDCT_OUT_HEADROOM); } } FDK_ASSERT(nSamples == frameLen); + pAacDecoderStaticChannelInfo->last_core_mode = + (pAacDecoderChannelInfo->icsInfo.WindowSequence == BLOCK_SHORT) ? FD_SHORT + : FD_LONG; + pAacDecoderStaticChannelInfo->last_lpd_mode = 255; } #include "ldfiltbank.h" -void CBlock_FrequencyToTimeLowDelay( CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, - CAacDecoderChannelInfo *pAacDecoderChannelInfo, - INT_PCM outSamples[], - const short frameLen, - const char stride ) -{ - InvMdctTransformLowDelay_fdk ( - SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient), - pAacDecoderChannelInfo->specScale[0], - outSamples, - pAacDecoderStaticChannelInfo->pOverlapBuffer, - stride, - frameLen - ); +void CBlock_FrequencyToTimeLowDelay( + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, FIXP_PCM outSamples[], + const short frameLen) { + InvMdctTransformLowDelay_fdk( + SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient), + pAacDecoderChannelInfo->specScale[0], outSamples, + pAacDecoderStaticChannelInfo->pOverlapBuffer, frameLen); } |