From b5dfe8f92dd94e91f8391a9dc3d1fa7b0415ece2 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Mon, 6 Jul 2020 16:37:38 +0200 Subject: [PATCH 01/78] Fix heap buffer overflow in sbrDecoder_AssignQmfChannels2SbrChannels(). In the bug the SBR decoder has already set up 9 channels and tries to allocate one more channel. The assignment of the QMF channels to SBR channels fails since the QMF domain manages only 8+1 channels instead of 10 channels as reqeusted by SBR. Here we have added a check in sbrDecoder_InitElement() which will return with a parse error in case additional SBR channels would exceed the maximum number of SBR channels. This solves the potential heap buffer overflow. Bug: 158762825 Test: atest DecoderTestAacDrc DecoderTestAacFormat DecoderTestXheAac Change-Id: I0150ac6d5a47ffce883010f531928656eebc619e --- libSBRdec/src/sbrdecoder.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libSBRdec/src/sbrdecoder.cpp b/libSBRdec/src/sbrdecoder.cpp index b51461d..b101a4a 100644 --- a/libSBRdec/src/sbrdecoder.cpp +++ b/libSBRdec/src/sbrdecoder.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -617,10 +617,6 @@ SBR_ERROR sbrDecoder_InitElement( 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: @@ -653,12 +649,16 @@ SBR_ERROR sbrDecoder_InitElement( } /* Sanity check to avoid memory leaks */ - if (elChannels < self->pSbrElement[elementIndex]->nChannels) { + if (elChannels < self->pSbrElement[elementIndex]->nChannels || + (self->numSbrChannels + elChannels) > (8) + (1)) { self->numSbrChannels += self->pSbrElement[elementIndex]->nChannels; sbrError = SBRDEC_PARSE_ERROR; goto bail; } + /* Save element ID for sanity checks and to have a fallback for concealment. + */ + self->pSbrElement[elementIndex]->elementID = elementID; self->pSbrElement[elementIndex]->nChannels = elChannels; for (ch = 0; ch < elChannels; ch++) { From f451278f0e57a7355783d644f7083b28b41e4b4e Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Mon, 5 Oct 2020 16:27:56 -0700 Subject: [PATCH 02/78] Fix fuzzer's use of aacDecoder_DecodeFrame The aacDecoder_DecodeFrame function takes a size in numbers of samples (INT_PCM), not a number of bytes. Using a number of bytes caused the FDK to believe the array was larger than it really was. Therefore on invalid frames, it would try to clear a size larger than was really available, causing an OOB crash. Bug: 161014225 Test: check clusterfuzz results for case 6217304556437504 Change-Id: I9278898a17c1c961c568e841c6037d0c14bcc8b4 --- fuzzer/aac_dec_fuzzer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fuzzer/aac_dec_fuzzer.cpp b/fuzzer/aac_dec_fuzzer.cpp index b5545fc..c970197 100644 --- a/fuzzer/aac_dec_fuzzer.cpp +++ b/fuzzer/aac_dec_fuzzer.cpp @@ -118,7 +118,8 @@ void Codec::decodeFrames(UCHAR *data, UINT size) { INT_PCM outputBuf[kMaxOutBufferSize]; do { mErrorCode = - aacDecoder_DecodeFrame(mAacDecoderHandle, outputBuf, sizeof(outputBuf), 0); + aacDecoder_DecodeFrame(mAacDecoderHandle, outputBuf, + kMaxOutBufferSize /*size in number of INT_PCM, not bytes*/, 0); } while (mErrorCode == AAC_DEC_OK); UINT offset = inputSize - valid; data += offset; From 9f9bffb7633f69d4578167d40ff310c62897d51c Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:50:10 +0200 Subject: [PATCH 03/78] Prevent integer overflows in dualChannelFiltering() and eightChannelFiltering(). Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: Ic9217bbb3980807036ae6ae121e6ddb7cc1bce35 --- libFDK/src/FDK_hybrid.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/libFDK/src/FDK_hybrid.cpp b/libFDK/src/FDK_hybrid.cpp index 08d32a8..d208abd 100644 --- a/libFDK/src/FDK_hybrid.cpp +++ b/libFDK/src/FDK_hybrid.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -539,11 +539,11 @@ static void dualChannelFiltering(const FIXP_DBL *const pQmfReal, i6 = pQmfImag[pReadIdx[6]] >> 2; FDK_ASSERT((invert == 0) || (invert == 1)); - mHybridReal[0 + invert] = (r6 + r1) << 1; - mHybridImag[0 + invert] = (i6 + i1) << 1; + mHybridReal[0 + invert] = SATURATE_LEFT_SHIFT((r6 + r1), 1, DFRACT_BITS); + mHybridImag[0 + invert] = SATURATE_LEFT_SHIFT((i6 + i1), 1, DFRACT_BITS); - mHybridReal[1 - invert] = (r6 - r1) << 1; - mHybridImag[1 - invert] = (i6 - i1) << 1; + mHybridReal[1 - invert] = SATURATE_LEFT_SHIFT((r6 - r1), 1, DFRACT_BITS); + mHybridImag[1 - invert] = SATURATE_LEFT_SHIFT((i6 - i1), 1, DFRACT_BITS); } static void fourChannelFiltering(const FIXP_DBL *const pQmfReal, @@ -766,15 +766,15 @@ static void eightChannelFiltering(const FIXP_DBL *const pQmfReal, mHybridReal[3] = pfft[FFT_IDX_R(1)] << sc; mHybridImag[3] = pfft[FFT_IDX_I(1)] << sc; - mHybridReal[4] = pfft[FFT_IDX_R(2)] << sc; - mHybridReal[4] += pfft[FFT_IDX_R(5)] << sc; - mHybridImag[4] = pfft[FFT_IDX_I(2)] << sc; - mHybridImag[4] += pfft[FFT_IDX_I(5)] << sc; + mHybridReal[4] = SATURATE_LEFT_SHIFT( + (pfft[FFT_IDX_R(2)] + pfft[FFT_IDX_R(5)]), sc, DFRACT_BITS); + mHybridImag[4] = SATURATE_LEFT_SHIFT( + (pfft[FFT_IDX_I(2)] + pfft[FFT_IDX_I(5)]), sc, DFRACT_BITS); - mHybridReal[5] = pfft[FFT_IDX_R(3)] << sc; - mHybridReal[5] += pfft[FFT_IDX_R(4)] << sc; - mHybridImag[5] = pfft[FFT_IDX_I(3)] << sc; - mHybridImag[5] += pfft[FFT_IDX_I(4)] << sc; + mHybridReal[5] = SATURATE_LEFT_SHIFT( + (pfft[FFT_IDX_R(3)] + pfft[FFT_IDX_R(4)]), sc, DFRACT_BITS); + mHybridImag[5] = SATURATE_LEFT_SHIFT( + (pfft[FFT_IDX_I(3)] + pfft[FFT_IDX_I(4)]), sc, DFRACT_BITS); } else { for (k = 0; k < 8; k++) { mHybridReal[k] = pfft[FFT_IDX_R(k)] << sc; From 2b281bb5a38685988e145b5b2fcbbcb6fb547bdc Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:52:56 +0200 Subject: [PATCH 04/78] Avoid integer overflow in dct_II(). Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I6c30c4dec3f85410c2748eb42d38f5eb72521ec5 --- libFDK/src/dct.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/libFDK/src/dct.cpp b/libFDK/src/dct.cpp index bd26736..35507b5 100644 --- a/libFDK/src/dct.cpp +++ b/libFDK/src/dct.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -305,9 +305,8 @@ void dct_II( { for (i = 0; i < M; i++) { - tmp[i] = pDat[2 * i] >> 1; /* dit_fft expects 1 bit scaled input values */ - tmp[L - 1 - i] = - pDat[2 * i + 1] >> 1; /* dit_fft expects 1 bit scaled input values */ + tmp[i] = pDat[2 * i] >> 2; + tmp[L - 1 - i] = pDat[2 * i + 1] >> 2; } } @@ -337,15 +336,14 @@ void dct_II( a1 = ((pTmp_0[0] >> 1) + (pTmp_1[0] >> 1)); a2 = ((pTmp_0[1] >> 1) - (pTmp_1[1] >> 1)); - cplxMultDiv2(&accu3, &accu4, (a1 + accu2), -(accu1 + a2), - sin_twiddle[i * inc]); - pDat[L - i] = accu4; - pDat[i] = accu3; + cplxMult(&accu3, &accu4, (accu1 + a2), (a1 + accu2), sin_twiddle[i * inc]); + pDat[L - i] = -accu3; + pDat[i] = accu4; - cplxMultDiv2(&accu3, &accu4, (a1 - accu2), -(accu1 - a2), - sin_twiddle[(M - i) * inc]); - pDat[M + i] = accu4; - pDat[M - i] = accu3; + cplxMult(&accu3, &accu4, (accu1 - a2), (a1 - accu2), + sin_twiddle[(M - i) * inc]); + pDat[M + i] = -accu3; + pDat[M - i] = accu4; /* Create index helper variables for (4*i)*inc indexed equivalent values of * short tables. */ @@ -356,12 +354,12 @@ void dct_II( } } - cplxMultDiv2(&accu1, &accu2, tmp[M], tmp[M + 1], sin_twiddle[(M / 2) * inc]); + cplxMult(&accu1, &accu2, tmp[M], tmp[M + 1], sin_twiddle[(M / 2) * inc]); pDat[L - (M / 2)] = accu2; pDat[M / 2] = accu1; - pDat[0] = (tmp[0] >> 1) + (tmp[1] >> 1); - pDat[M] = fMult(((tmp[0] >> 1) - (tmp[1] >> 1)), + pDat[0] = tmp[0] + tmp[1]; + pDat[M] = fMult(tmp[0] - tmp[1], sin_twiddle[M * inc].v.re); /* cos((PI/(2*L))*M); */ *pDat_e += 2; From 4305167cebc29610cbfeb0295c06f0e94cfbf6a6 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:53:51 +0200 Subject: [PATCH 05/78] Limit smoothedNoise values to avoid integer overflows in adjustTimeSlotHQ() and adjustTimeSlotHQ_GainAndNoise(). Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: Ib630d56a626ddd59a9155df38cda2011c3165346 --- libSBRdec/src/env_calc.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/libSBRdec/src/env_calc.cpp b/libSBRdec/src/env_calc.cpp index 0b2f651..ad5edfe 100644 --- a/libSBRdec/src/env_calc.cpp +++ b/libSBRdec/src/env_calc.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -1398,6 +1398,17 @@ void calculateSbrEnvelope( */ noise_e = (start_pos < no_cols) ? adj_e : final_e; + if (start_pos >= no_cols) { + int diff = h_sbr_cal_env->filtBufferNoise_e - noise_e; + if (diff > 0) { + int s = getScalefactor(h_sbr_cal_env->filtBufferNoise, noSubbands); + if (diff > s) { + final_e += diff - s; + noise_e = final_e; + } + } + } + /* Convert energies to amplitude levels */ @@ -2741,6 +2752,9 @@ static void adjustTimeSlotHQ_GainAndNoise( fMult(direct_ratio, noiseLevel[k]); } + smoothedNoise = fMax(fMin(smoothedNoise, (FIXP_DBL)(MAXVAL_DBL / 2)), + (FIXP_DBL)(MINVAL_DBL / 2)); + /* The next 2 multiplications constitute the actual envelope adjustment of the signal and should be carried out with full accuracy @@ -2930,6 +2944,9 @@ static void adjustTimeSlotHQ( fMult(direct_ratio, noiseLevel[k]); } + smoothedNoise = fMax(fMin(smoothedNoise, (FIXP_DBL)(MAXVAL_DBL / 2)), + (FIXP_DBL)(MINVAL_DBL / 2)); + /* The next 2 multiplications constitute the actual envelope adjustment of the signal and should be carried out with full accuracy From aad908c262eaffec9728851ff410c7991893111a Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:54:10 +0200 Subject: [PATCH 06/78] Prevent integer overflow in subbandTPApply() energy update. Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I9ed8b33414907706808956cffad252052928c799 --- libSACdec/src/sac_stp.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libSACdec/src/sac_stp.cpp b/libSACdec/src/sac_stp.cpp index bb66277..b328c82 100644 --- a/libSACdec/src/sac_stp.cpp +++ b/libSACdec/src/sac_stp.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -369,15 +369,15 @@ SACDEC_ERROR subbandTPApply(spatialDec *self, const SPATIAL_BS_FRAME *frame) { hStpDec->update_old_ener = 1; for (ch = 0; ch < self->numInputChannels; ch++) { hStpDec->oldDryEnerLD64[ch] = - CalcLdData(hStpDec->runDryEner[ch] + ABS_THR__FDK); + CalcLdData(fAddSaturate(hStpDec->runDryEner[ch], ABS_THR__FDK)); } for (ch = 0; ch < self->numOutputChannels; ch++) { if (self->treeConfig == TREE_212) hStpDec->oldWetEnerLD64[ch] = - CalcLdData(hStpDec->runWetEner[ch] + ABS_THR__FDK); + CalcLdData(fAddSaturate(hStpDec->runWetEner[ch], ABS_THR__FDK)); else hStpDec->oldWetEnerLD64[ch] = - CalcLdData(hStpDec->runWetEner[ch] + ABS_THR2__FDK); + CalcLdData(fAddSaturate(hStpDec->runWetEner[ch], ABS_THR2__FDK)); } } else { hStpDec->update_old_ener++; From 883c1143990c6d41abdadcb18cf8d084aeb8630d Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:54:33 +0200 Subject: [PATCH 07/78] Validate DRC compression factor and DRC boost factor value range in aacDecoder_SetParam(). Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I1d8534145bcf400c5da58d64d3b7e73a87cb43be --- libAACdec/src/aacdecoder_lib.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index 0f281eb..4c0d347 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -822,6 +822,9 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_SetParam( case AAC_DRC_ATTENUATION_FACTOR: /* DRC compression factor (where 0 is no and 127 is max compression) */ + if ((value < 0) || (value > 127)) { + return AAC_DEC_SET_PARAM_FAIL; + } errorStatus = aacDecoder_drcSetParam(hDrcInfo, DRC_CUT_SCALE, value); uniDrcErr = FDK_drcDec_SetParam(self->hUniDrcDecoder, DRC_DEC_COMPRESS, value * (FL2FXCONST_DBL(0.5f / 127.0f))); @@ -829,6 +832,9 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_SetParam( case AAC_DRC_BOOST_FACTOR: /* DRC boost factor (where 0 is no and 127 is max boost) */ + if ((value < 0) || (value > 127)) { + return AAC_DEC_SET_PARAM_FAIL; + } errorStatus = aacDecoder_drcSetParam(hDrcInfo, DRC_BOOST_SCALE, value); uniDrcErr = FDK_drcDec_SetParam(self->hUniDrcDecoder, DRC_DEC_BOOST, value * (FL2FXCONST_DBL(0.5f / 127.0f))); From c8a38ef6474f174f4b09ff69f5a8d746019307c0 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 10 Dec 2020 18:32:03 +0100 Subject: [PATCH 08/78] Adjust VBR mode depending on given peak bitrate and fix crash recovery usage. Operating the FDK encoder in A2DP with variable bitrate mode configuration resulted in unexpected encoder return value AACENC_ENCODE_ERROR. Due to peak bitrate restriction the encoder quite often runs into requantization. In case the bitrate constraint is not fulfilled, the so-called crash recovery is used as final emergency step. The crash recovery reduces the overall bit consumption considering the given number of bits to be saved. The bit difference is extracted from audio element structures. In VBR mode the element wise bit consumption state was not updated since there is typically no bitrate limitation required. The patch solves the choppy audio problems and increases audio quality for AAC VBR encoding. The changes in FDKaacEnc_QCMain() ensure that audio element bit info is always updated. This is achieved by always calling FDKaacEnc_BitResRedistribution() and FDKaacEnc_prepareBitDistribution() with maxBitsPerFrame variable as total bits parameter. Furthermore, VBR assumes a certain target bitrate which is used for internal configuration and limitations. In case the peak bitrate parameter is less than the VBR mode target bitrate the maximum of both bitrate configurations was used. The function FDKaacEnc_AdjustVBRBitrateMode() is added to adjust the encoder internal VBR mode to a desired target bitrate less than given peak bitrate. It is possible that the peak bitrate is very close to the desired target bitrate. The virtual available bitreservoir is quite low and the encoder would run quite often into requantization with needless audio quality reduction. In such a configuration, it is a better choice to use the CBR targeted threshold adaption to avoid audio quality reduction. In FDKaacEnc_Initialize(), there was already a bitResMode selection depending on available bitreservoir for CBR. This selection will now also be used for VBR. In case the bitResMode is AACENC_BR_MODE_FULL and VBR mode is selected, the VBR threshold adaption is used. Otherwise, CBR threshold adaption strategy is used and therefore, no unnecessary fill bits are written. Bug: 161400526 Test: see bug Change-Id: I1865f817180150da6add2623a64f1a102622784a --- libAACenc/src/aacenc.cpp | 48 ++++++++++++++++++++++++++++++++---- libAACenc/src/aacenc.h | 15 ++++++++++- libAACenc/src/aacenc_lib.cpp | 7 ++++++ libAACenc/src/qc_main.cpp | 47 ++++++++++++++--------------------- 4 files changed, 82 insertions(+), 35 deletions(-) diff --git a/libAACenc/src/aacenc.cpp b/libAACenc/src/aacenc.cpp index b6f733d..1af8a2e 100644 --- a/libAACenc/src/aacenc.cpp +++ b/libAACenc/src/aacenc.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -245,6 +245,46 @@ INT FDKaacEnc_GetVBRBitrate(AACENC_BITRATE_MODE bitrateMode, return bitrate; } +/*----------------------------------------------------------------------------- + + functionname: FDKaacEnc_AdjustVBRBitrateMode + description: Adjust bitrate mode to given bitrate parameter + input params: int vbrQuality (VBR0, VBR1, VBR2) + bitrate + channelMode + returns: vbr bitrate mode + + ------------------------------------------------------------------------------*/ +AACENC_BITRATE_MODE FDKaacEnc_AdjustVBRBitrateMode( + AACENC_BITRATE_MODE bitrateMode, INT bitrate, CHANNEL_MODE channelMode) { + AACENC_BITRATE_MODE newBitrateMode = bitrateMode; + + if (bitrate != -1) { + const INT monoStereoMode = + (FDKaacEnc_GetMonoStereoMode(channelMode) == EL_MODE_STEREO) ? 1 : 0; + const INT nChannelsEff = + FDKaacEnc_GetChannelModeConfiguration(channelMode)->nChannelsEff; + newBitrateMode = AACENC_BR_MODE_INVALID; + + for (int idx = (int)(sizeof(configTabVBR) / sizeof(*configTabVBR)) - 1; + idx >= 0; idx--) { + if (bitrate >= + configTabVBR[idx].chanBitrate[monoStereoMode] * nChannelsEff) { + if (configTabVBR[idx].chanBitrate[monoStereoMode] * nChannelsEff < + FDKaacEnc_GetVBRBitrate(bitrateMode, channelMode)) { + newBitrateMode = configTabVBR[idx].bitrateMode; + } else { + newBitrateMode = bitrateMode; + } + break; + } + } + } + + return AACENC_BR_MODE_IS_VBR(newBitrateMode) ? newBitrateMode + : AACENC_BR_MODE_INVALID; +} + /** * \brief Convert encoder bitreservoir value for transport library. * @@ -397,7 +437,6 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize( FIXP_DBL mbfac, bw_ratio; QC_INIT qcInit; INT averageBitsPerFrame = 0; - int bitresMin = 0; /* the bitreservoir is always big for AAC-LC */ const CHANNEL_MODE prevChannelMode = hAacEnc->encoderMode; if (config == NULL) return AAC_ENC_INVALID_HANDLE; @@ -553,7 +592,6 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize( qcInit.minBits = fixMin(qcInit.minBits, averageBitsPerFrame & ~7); } else { INT bitreservoir = -1; /* default bitreservoir size*/ - bitresMin = BITRES_MIN; if (isLowDelay(config->audioObjectType)) { INT brPerChannel = config->bitRate / config->nChannels; brPerChannel = fMin(BITRATE_MAX_LD, fMax(BITRATE_MIN_LD, brPerChannel)); @@ -567,7 +605,6 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize( bitreservoir = fMultI(slope, (INT)(BITRES_MAX_LD - BITRES_MIN_LD)) + BITRES_MIN_LD; /* interpolate */ bitreservoir = bitreservoir & ~7; /* align to bytes */ - bitresMin = BITRES_MIN_LD; } int maxBitres; @@ -604,7 +641,8 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize( qcInit.nSubFrames = config->nSubFrames; qcInit.padding.paddingRest = config->sampleRate; - if (qcInit.maxBits - qcInit.averageBits >= bitresMin * config->nChannels) { + if (qcInit.maxBits - qcInit.averageBits >= + ((qcInit.isLowDelay) ? BITRES_MIN_LD : BITRES_MIN) * config->nChannels) { qcInit.bitResMode = AACENC_BR_MODE_FULL; /* full bitreservoir */ } else if (qcInit.maxBits > qcInit.averageBits) { qcInit.bitResMode = AACENC_BR_MODE_REDUCED; /* reduced bitreservoir */ diff --git a/libAACenc/src/aacenc.h b/libAACenc/src/aacenc.h index 0e0d8c1..b7e0ef2 100644 --- a/libAACenc/src/aacenc.h +++ b/libAACenc/src/aacenc.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -333,6 +333,19 @@ INT FDKaacEnc_GetBitReservoirState(const HANDLE_AAC_ENC hAacEncoder); INT FDKaacEnc_GetVBRBitrate(AACENC_BITRATE_MODE bitrateMode, CHANNEL_MODE channelMode); +/*----------------------------------------------------------------------------- + + functionname: FDKaacEnc_AdjustVBRBitrateMode + description: Adjust bitrate mode to given bitrate parameter + input params: int vbrQuality (VBR0, VBR1, VBR2) + bitrate + channelMode + returns: vbr bitrate mode + + ------------------------------------------------------------------------------*/ +AACENC_BITRATE_MODE FDKaacEnc_AdjustVBRBitrateMode( + AACENC_BITRATE_MODE bitrateMode, INT bitrate, CHANNEL_MODE channelMode); + /*----------------------------------------------------------------------------- functionname: FDKaacEnc_AacInitDefaultConfig diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp index c3977f3..0ae329b 100644 --- a/libAACenc/src/aacenc_lib.cpp +++ b/libAACenc/src/aacenc_lib.cpp @@ -1028,6 +1028,13 @@ static AACENC_ERROR FDKaacEnc_AdjustEncSettings(HANDLE_AACENCODER hAacEncoder, case AACENC_BR_MODE_VBR_3: case AACENC_BR_MODE_VBR_4: case AACENC_BR_MODE_VBR_5: + /* Adjust bitrate mode in case given peak bitrate is lower than expected + * VBR bitrate. */ + if ((INT)config->userPeakBitrate != -1) { + hAacConfig->bitrateMode = FDKaacEnc_AdjustVBRBitrateMode( + hAacConfig->bitrateMode, config->userPeakBitrate, + hAacConfig->channelMode); + } /* Get bitrate in VBR configuration */ /* In VBR mode; SBR-modul depends on bitrate, core encoder on bitrateMode. */ diff --git a/libAACenc/src/qc_main.cpp b/libAACenc/src/qc_main.cpp index bcfaa23..9a42550 100644 --- a/libAACenc/src/qc_main.cpp +++ b/libAACenc/src/qc_main.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -373,13 +373,8 @@ AAC_ENCODER_ERROR FDKaacEnc_QCInit(QC_STATE* hQC, struct QC_INIT* init, hQC->invQuant = init->invQuant; hQC->maxIterations = init->maxIterations; - if (isConstantBitrateMode(hQC->bitrateMode)) { - /* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir - */ - hQC->bitResMode = init->bitResMode; - } else { - hQC->bitResMode = AACENC_BR_MODE_FULL; /* full bitreservoir */ - } + /* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir */ + hQC->bitResMode = init->bitResMode; hQC->padding.paddingRest = init->padding.paddingRest; @@ -800,10 +795,15 @@ AAC_ENCODER_ERROR FDKaacEnc_QCMain(QC_STATE* RESTRICT hQC, PSY_OUT** psyOut, INT avgTotalDynBits = 0; /* maximal allowed dynamic bits for all frames */ INT totalAvailableBits = 0; INT nSubFrames = 1; + const INT isCBRAdjustment = (isConstantBitrateMode(hQC->bitrateMode) || + (hQC->bitResMode != AACENC_BR_MODE_FULL)) + ? 1 + : 0; /*-------------------------------------------- */ /* redistribute total bitreservoir to elements */ - ErrorStatus = FDKaacEnc_BitResRedistribution(hQC, cm, avgTotalBits); + ErrorStatus = FDKaacEnc_BitResRedistribution( + hQC, cm, (isCBRAdjustment == 0) ? hQC->maxBitsPerFrame : avgTotalBits); if (ErrorStatus != AAC_ENC_OK) { return ErrorStatus; } @@ -831,33 +831,22 @@ AAC_ENCODER_ERROR FDKaacEnc_QCMain(QC_STATE* RESTRICT hQC, PSY_OUT** psyOut, /*-------------------------------------------- */ /*-------------------------------------------- */ - if (isConstantBitrateMode(hQC->bitrateMode)) { - /* calc granted dynamic bits for sub frame and - distribute it to each element */ - ErrorStatus = FDKaacEnc_prepareBitDistribution( - hQC, psyOut, qcOut, cm, qcElement, avgTotalBits, &totalAvailableBits, - &avgTotalDynBits); + /* calc granted dynamic bits for sub frame and + distribute it to each element */ + ErrorStatus = FDKaacEnc_prepareBitDistribution( + hQC, psyOut, qcOut, cm, qcElement, + (isCBRAdjustment == 0) ? hQC->maxBitsPerFrame : avgTotalBits, + &totalAvailableBits, &avgTotalDynBits); - if (ErrorStatus != AAC_ENC_OK) { - return ErrorStatus; - } - } else { - qcOut[0]->grantedDynBits = - ((hQC->maxBitsPerFrame - (hQC->globHdrBits)) & ~7) - - (qcOut[0]->globalExtBits + qcOut[0]->staticBits + - qcOut[0]->elementExtBits); - qcOut[0]->maxDynBits = qcOut[0]->grantedDynBits; - - totalAvailableBits = hQC->maxBitsPerFrame; - avgTotalDynBits = 0; + if (ErrorStatus != AAC_ENC_OK) { + return ErrorStatus; } /* for ( all sub frames ) ... */ for (c = 0; c < nSubFrames; c++) { /* for CBR and VBR mode */ FDKaacEnc_AdjustThresholds(hQC->hAdjThr, qcElement[c], qcOut[c], - psyOut[c]->psyOutElement, - isConstantBitrateMode(hQC->bitrateMode), cm); + psyOut[c]->psyOutElement, isCBRAdjustment, cm); } /* -end- sub frame counter */ From 8f2e68d5c4d2a1d67952c8af68005aa22de179ce Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:55:38 +0200 Subject: [PATCH 09/78] Introduce aacDecoder_drcDisable() and always disable legacy DRC for USAC. Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I75edf24b18e1f5392b6eb179d5574cb93fcbc7c2 --- libAACdec/src/aacdec_drc.cpp | 15 ++++++++++++++- libAACdec/src/aacdec_drc.h | 4 +++- libAACdec/src/aacdecoder.cpp | 13 +++++++------ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/libAACdec/src/aacdec_drc.cpp b/libAACdec/src/aacdec_drc.cpp index b6f5b49..760a9ba 100644 --- a/libAACdec/src/aacdec_drc.cpp +++ b/libAACdec/src/aacdec_drc.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -149,6 +149,19 @@ static INT convert_drcParam(FIXP_DBL param_dbl) { return (INT)param_long; } +/*! +\brief Disable DRC + +\self Handle of DRC info + +\return none +*/ +void aacDecoder_drcDisable(HANDLE_AAC_DRC self) { + self->enable = 0; + self->applyExtGain = 0; + self->progRefLevelPresent = 0; +} + /*! \brief Reset DRC information diff --git a/libAACdec/src/aacdec_drc.h b/libAACdec/src/aacdec_drc.h index 76a44d6..2bb945d 100644 --- a/libAACdec/src/aacdec_drc.h +++ b/libAACdec/src/aacdec_drc.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -140,6 +140,8 @@ typedef enum { /** * \brief DRC module interface functions */ +void aacDecoder_drcDisable(HANDLE_AAC_DRC self); + void aacDecoder_drcReset(HANDLE_AAC_DRC self); void aacDecoder_drcInit(HANDLE_AAC_DRC self); diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp index 965631b..414c3e2 100644 --- a/libAACdec/src/aacdecoder.cpp +++ b/libAACdec/src/aacdecoder.cpp @@ -2383,8 +2383,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, if (*configChanged) { if (asc->m_aot == AOT_USAC) { - self->hDrcInfo->enable = 0; - self->hDrcInfo->progRefLevelPresent = 0; + aacDecoder_drcDisable(self->hDrcInfo); } } @@ -3194,11 +3193,12 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( * data in the bitstream. */ self->flags[streamIndex] |= AC_DRC_PRESENT; } else { - self->hDrcInfo->enable = 0; - self->hDrcInfo->progRefLevelPresent = 0; ErrorStatus = AAC_DEC_UNSUPPORTED_FORMAT; } } + if (self->flags[streamIndex] & (AC_USAC | AC_RSV603DA)) { + aacDecoder_drcDisable(self->hDrcInfo); + } /* Create a reverse mapping table */ UCHAR Reverse_chMapping[((8) * 2)]; @@ -3441,11 +3441,12 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( * data in the bitstream. */ self->flags[streamIndex] |= AC_DRC_PRESENT; } else { - self->hDrcInfo->enable = 0; - self->hDrcInfo->progRefLevelPresent = 0; ErrorStatus = AAC_DEC_UNSUPPORTED_FORMAT; } } + if (self->flags[streamIndex] & (AC_USAC | AC_RSV603DA)) { + aacDecoder_drcDisable(self->hDrcInfo); + } } /* Add additional concealment delay */ From fcc3c65ec545ebaf4cbb78d529b47e6d6b5d4ce9 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:55:59 +0200 Subject: [PATCH 10/78] Evaluate and return StoreConfigAsBitstream() error state. Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I025e943e91f9be1a5259a761a8ff88defd8babea --- libMpegTPDec/src/tpdec_asc.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp index 82f840e..ffe85c1 100644 --- a/libMpegTPDec/src/tpdec_asc.cpp +++ b/libMpegTPDec/src/tpdec_asc.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -1996,9 +1996,11 @@ static TRANSPORTDEC_ERROR UsacConfig_Parse(CSAudioSpecificConfig *asc, /* Copy UsacConfig() to asc->m_sc.m_usacConfig.UsacConfig[] buffer. */ INT configSize_bits = (INT)FDKgetValidBits(hBs) - nbits; - StoreConfigAsBitstream(hBs, configSize_bits, - asc->m_sc.m_usacConfig.UsacConfig, - TP_USAC_MAX_CONFIG_LEN); + if (StoreConfigAsBitstream(hBs, configSize_bits, + asc->m_sc.m_usacConfig.UsacConfig, + TP_USAC_MAX_CONFIG_LEN)) { + return TRANSPORTDEC_PARSE_ERROR; + } asc->m_sc.m_usacConfig.UsacConfigBits = fAbs(configSize_bits); return err; @@ -2300,8 +2302,10 @@ TRANSPORTDEC_ERROR AudioSpecificConfig_Parse( /* Copy config() to asc->config[] buffer. */ if ((ErrorStatus == TRANSPORTDEC_OK) && (self->m_aot == AOT_USAC)) { INT configSize_bits = (INT)FDKgetValidBits(bs) - (INT)ascStartAnchor; - StoreConfigAsBitstream(bs, configSize_bits, self->config, - TP_USAC_MAX_CONFIG_LEN); + if (StoreConfigAsBitstream(bs, configSize_bits, self->config, + TP_USAC_MAX_CONFIG_LEN)) { + return TRANSPORTDEC_PARSE_ERROR; + } self->configBits = fAbs(configSize_bits); } From b1136d1c348261adc1801c8db04d25033a0bdb9f Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:56:25 +0200 Subject: [PATCH 11/78] Check transportDec_OutOfBandConfig() input buffer size parameter. Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I60ac86f09a5652c820d60dfdc12212637f888164 --- libAACdec/src/aacdecoder_lib.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index 4c0d347..0c13304 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -1179,8 +1179,10 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(HANDLE_AACDECODER self, aacDecoder_FreeMemCallback(self, &asc); self->streamInfo.numChannels = 0; /* 3) restore AudioSpecificConfig */ - transportDec_OutOfBandConfig(self->hInput, asc.config, - (asc.configBits + 7) >> 3, 0); + if (asc.configBits <= (TP_USAC_MAX_CONFIG_LEN << 3)) { + transportDec_OutOfBandConfig(self->hInput, asc.config, + (asc.configBits + 7) >> 3, 0); + } } } From 9f2d1a18d451a3a9c5f0cd05120ddb0eea731d47 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:57:27 +0200 Subject: [PATCH 12/78] ELD downscale factor 3 is only allowed for framesize 480. Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I9681942ba39761e4f1d66236ad80c2420ca5abe9 --- libAACdec/src/aacdecoder.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp index 414c3e2..08128c0 100644 --- a/libAACdec/src/aacdecoder.cpp +++ b/libAACdec/src/aacdecoder.cpp @@ -1791,9 +1791,17 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, downscaleFactorInBS = asc->m_samplingFrequency / asc->m_sc.m_eldSpecificConfig.m_downscaledSamplingFrequency; - if (downscaleFactorInBS == 1 || downscaleFactorInBS == 2 || - downscaleFactorInBS == 3 || downscaleFactorInBS == 4) { + if ((downscaleFactorInBS == 1 || downscaleFactorInBS == 2 || + (downscaleFactorInBS == 3 && + asc->m_sc.m_eldSpecificConfig.m_frameLengthFlag) || + downscaleFactorInBS == 4) && + ((asc->m_samplingFrequency % + asc->m_sc.m_eldSpecificConfig.m_downscaledSamplingFrequency) == + 0)) { downscaleFactor = downscaleFactorInBS; + } else { + downscaleFactorInBS = 1; + downscaleFactor = 1; } } } else { From d6a7375bfa25ebcdd47900e5f32958c6c8deb57f Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:58:01 +0200 Subject: [PATCH 13/78] Revise bypass mode in SpatialDecApplyParameterSets() to prevent an assert in fDivNorm(). Bug: 176246647 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I198747688f1677b82f27a17a2fcf40229c92b1da --- libSACdec/src/sac_dec.cpp | 61 ++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/libSACdec/src/sac_dec.cpp b/libSACdec/src/sac_dec.cpp index a7b50df..f0d24fb 100644 --- a/libSACdec/src/sac_dec.cpp +++ b/libSACdec/src/sac_dec.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -1098,6 +1098,28 @@ static void SpatialDecApplyBypass(spatialDec *self, FIXP_DBL **hybInputReal, } } +/** + * \brief Set internal error and reset error status + * + * \param self spatialDec handle. + * \param bypassMode pointer to bypassMode. + * \param err error status. + * + * \return error status. + */ +static SACDEC_ERROR SpatialDecSetInternalError(spatialDec *self, + int *bypassMode, + SACDEC_ERROR err) { + *bypassMode = 1; + + if (self->errInt == MPS_OK) { + /* store internal error before it gets overwritten */ + self->errInt = err; + } + + return MPS_OK; +} + /******************************************************************************* Functionname: SpatialDecApplyParameterSets ******************************************************************************* @@ -1118,7 +1140,7 @@ static SACDEC_ERROR SpatialDecApplyParameterSets( const FDK_channelMapDescr *const mapDescr) { SACDEC_ERROR err = MPS_OK; - FIXP_SGL alpha; + FIXP_SGL alpha = FL2FXCONST_SGL(0.0); int ts; int ch; @@ -1141,20 +1163,22 @@ static SACDEC_ERROR SpatialDecApplyParameterSets( ts++, ts_io++) { int currSlot = frame->paramSlot[ps]; + err = (currSlot < ts) ? MPS_WRONG_PARAMETERSETS : MPS_OK; + if (err != MPS_OK) { + err = SpatialDecSetInternalError(self, &bypassMode, err); + } + /* * Get new parameter set */ if (ts == prevSlot + 1) { - err = SpatialDecCalculateM1andM2(self, ps, - frame); /* input: ottCLD, ottICC, ... */ - /* output: M1param(Real/Imag), M2(Real/Imag) */ - if (err != MPS_OK) { - bypassMode = 1; - if (self->errInt == MPS_OK) { - /* store internal error befor it gets overwritten */ - self->errInt = err; + if (bypassMode == 0) { + err = SpatialDecCalculateM1andM2( + self, ps, frame); /* input: ottCLD, ottICC, ... */ + /* output: M1param(Real/Imag), M2(Real/Imag) */ + if (err != MPS_OK) { + err = SpatialDecSetInternalError(self, &bypassMode, err); } - err = MPS_OK; } if ((ps == 0) && (self->bOverwriteM1M2prev != 0)) { @@ -1168,13 +1192,16 @@ static SACDEC_ERROR SpatialDecApplyParameterSets( self->bOverwriteM1M2prev = 0; } - SpatialDecSmoothM1andM2( - self, frame, - ps); /* input: M1param(Real/Imag)(Prev), M2(Real/Imag)(Prev) */ - /* output: M1param(Real/Imag), M2(Real/Imag) */ + if (bypassMode == 0) { + SpatialDecSmoothM1andM2( + self, frame, + ps); /* input: M1param(Real/Imag)(Prev), M2(Real/Imag)(Prev) */ + } /* output: M1param(Real/Imag), M2(Real/Imag) */ } - alpha = FX_DBL2FX_SGL(fDivNorm(ts - prevSlot, currSlot - prevSlot)); + if (bypassMode == 0) { + alpha = FX_DBL2FX_SGL(fDivNorm(ts - prevSlot, currSlot - prevSlot)); + } switch (mode) { case INPUTMODE_QMF_SBR: @@ -1360,7 +1387,7 @@ static SACDEC_ERROR SpatialDecApplyParameterSets( } /* !self->tempShapeConfig == 1 */ } /* !bypassMode */ - if (self->phaseCoding == 1) { + if ((self->phaseCoding == 1) && (bypassMode == 0)) { /* only if bsPhaseCoding == 1 and bsResidualCoding == 0 */ SpatialDecApplyPhase( From 293ccc7fbc509cc0ba4d944bd1bb9ad6f79c037d Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:54:50 +0200 Subject: [PATCH 14/78] Fix unsigned integer overflow in Hcr_State_BODY_SIGN_ESC__ESC_WORD(). Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I5eb0f88a55e856c427f9e4647332070f66e673c5 --- libAACdec/src/aacdec_hcrs.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libAACdec/src/aacdec_hcrs.cpp b/libAACdec/src/aacdec_hcrs.cpp index 44b32a5..5e3f9ac 100644 --- a/libAACdec/src/aacdec_hcrs.cpp +++ b/libAACdec/src/aacdec_hcrs.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -173,7 +173,9 @@ void DecodeNonPCWs(HANDLE_FDK_BITSTREAM bs, H_HCR_INFO pHcr) { pHcr->segmentInfo.readDirection = FROM_RIGHT_TO_LEFT; /* Process sets subsequently */ + numSet = fMin(numSet, (UCHAR)MAX_HCR_SETS); for (currentSet = 1; currentSet < numSet; currentSet++) { + /* step 1 */ numCodeword -= *pNumSegment; /* number of remaining non PCWs [for all sets] */ From 9256cfbb73ead016322637f84254856bbe918493 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:55:17 +0200 Subject: [PATCH 15/78] Make sure that alphaValue is correctly initialized in sbrDecoder_drcApplySlot(). Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I5bded2e3d29278bb5df561eaa2a46d963ee21df8 --- libSBRdec/src/sbrdec_drc.cpp | 53 +++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/libSBRdec/src/sbrdec_drc.cpp b/libSBRdec/src/sbrdec_drc.cpp index 2d73f32..089d046 100644 --- a/libSBRdec/src/sbrdec_drc.cpp +++ b/libSBRdec/src/sbrdec_drc.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -233,14 +233,19 @@ void sbrDecoder_drcApplySlot(HANDLE_SBR_DRC_CHANNEL hDrcData, if (hDrcData->winSequenceCurr != 2) { /* long window */ int j = col + (numQmfSubSamples >> 1); - if (hDrcData->drcInterpolationSchemeCurr == 0) { - INT k = (frameLenFlag) ? 0x4444445 : 0x4000000; + if (j < winBorderToColMap[15]) { + if (hDrcData->drcInterpolationSchemeCurr == 0) { + INT k = (frameLenFlag) ? 0x4444445 : 0x4000000; - alphaValue = (FIXP_DBL)(j * k); - } else { - if (j >= (int)winBorderToColMap[hDrcData->drcInterpolationSchemeCurr]) { - alphaValue = (FIXP_DBL)MAXVAL_DBL; + alphaValue = (FIXP_DBL)(j * k); + } else { + if (j >= + (int)winBorderToColMap[hDrcData->drcInterpolationSchemeCurr]) { + alphaValue = (FIXP_DBL)MAXVAL_DBL; + } } + } else { + alphaValue = (FIXP_DBL)MAXVAL_DBL; } } else { /* short windows */ shortDrc = 1; @@ -254,14 +259,19 @@ void sbrDecoder_drcApplySlot(HANDLE_SBR_DRC_CHANNEL hDrcData, if (hDrcData->winSequenceNext != 2) { /* next: long window */ int j = col - (numQmfSubSamples >> 1); - if (hDrcData->drcInterpolationSchemeNext == 0) { - INT k = (frameLenFlag) ? 0x4444445 : 0x4000000; + if (j < winBorderToColMap[15]) { + if (hDrcData->drcInterpolationSchemeNext == 0) { + INT k = (frameLenFlag) ? 0x4444445 : 0x4000000; - alphaValue = (FIXP_DBL)(j * k); - } else { - if (j >= (int)winBorderToColMap[hDrcData->drcInterpolationSchemeNext]) { - alphaValue = (FIXP_DBL)MAXVAL_DBL; + alphaValue = (FIXP_DBL)(j * k); + } else { + if (j >= + (int)winBorderToColMap[hDrcData->drcInterpolationSchemeNext]) { + alphaValue = (FIXP_DBL)MAXVAL_DBL; + } } + } else { + alphaValue = (FIXP_DBL)MAXVAL_DBL; } fact_mag = hDrcData->nextFact_mag; @@ -289,14 +299,19 @@ void sbrDecoder_drcApplySlot(HANDLE_SBR_DRC_CHANNEL hDrcData, if (hDrcData->winSequenceNext != 2) { /* long window */ int j = col - (numQmfSubSamples >> 1); - if (hDrcData->drcInterpolationSchemeNext == 0) { - INT k = (frameLenFlag) ? 0x4444445 : 0x4000000; + if (j < winBorderToColMap[15]) { + if (hDrcData->drcInterpolationSchemeNext == 0) { + INT k = (frameLenFlag) ? 0x4444445 : 0x4000000; - alphaValue = (FIXP_DBL)(j * k); - } else { - if (j >= (int)winBorderToColMap[hDrcData->drcInterpolationSchemeNext]) { - alphaValue = (FIXP_DBL)MAXVAL_DBL; + alphaValue = (FIXP_DBL)(j * k); + } else { + if (j >= + (int)winBorderToColMap[hDrcData->drcInterpolationSchemeNext]) { + alphaValue = (FIXP_DBL)MAXVAL_DBL; + } } + } else { + alphaValue = (FIXP_DBL)MAXVAL_DBL; } } else { /* short windows */ shortDrc = 1; From bfd912da32b1253c9020a82d5520f1754dadcfc5 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:57:46 +0200 Subject: [PATCH 16/78] Improve decoder robustness by storing flags and elFlags temporarily. Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I6aaeef87e1f2ce5d5031f088b8c57e6f5806929d --- libAACdec/src/aacdecoder.cpp | 135 +++++++++++++++++++++-------------- 1 file changed, 82 insertions(+), 53 deletions(-) diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp index 08128c0..c6d1832 100644 --- a/libAACdec/src/aacdecoder.cpp +++ b/libAACdec/src/aacdecoder.cpp @@ -1396,6 +1396,31 @@ static void CAacDecoder_DeInit(HANDLE_AACDECODER self, self->samplingRateInfo[subStreamIndex].samplingRate = 0; } +/*! + * \brief CAacDecoder_AcceptFlags Accept flags and element flags + * + * \param self [o] handle to AACDECODER structure + * \param asc [i] handle to ASC structure + * \param flags [i] flags + * \param elFlags [i] pointer to element flags + * \param streamIndex [i] stream index + * \param elementOffset [i] element offset + * + * \return void + */ +static void CAacDecoder_AcceptFlags(HANDLE_AACDECODER self, + const CSAudioSpecificConfig *asc, + UINT flags, UINT *elFlags, int streamIndex, + int elementOffset) { + { + FDKmemcpy( + self->elFlags, elFlags, + sizeof(*elFlags) * (3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1)); + } + + self->flags[streamIndex] = flags; +} + /*! * \brief CAacDecoder_CtrlCFGChange Set config change parameters. * @@ -1493,6 +1518,9 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, const int streamIndex = 0; INT flushChannels = 0; + UINT flags; + UINT elFlags[(3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1)]; + if (!self) return AAC_DEC_INVALID_HANDLE; UCHAR downscaleFactor = self->downscaleFactor; @@ -1649,8 +1677,8 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, } /* Set syntax flags */ - self->flags[streamIndex] = 0; - { FDKmemclear(self->elFlags, sizeof(self->elFlags)); } + flags = 0; + { FDKmemclear(elFlags, sizeof(elFlags)); } if ((asc->m_channelConfiguration > 0) || IS_USAC(asc->m_aot)) { if (IS_USAC(asc->m_aot)) { @@ -1700,31 +1728,30 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, } } - self->elFlags[el] |= - (asc->m_sc.m_usacConfig.element[_el].m_noiseFilling) - ? AC_EL_USAC_NOISE - : 0; - self->elFlags[el] |= + elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].m_noiseFilling) + ? AC_EL_USAC_NOISE + : 0; + elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].m_stereoConfigIndex > 0) ? AC_EL_USAC_MPS212 : 0; - self->elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].m_interTes) - ? AC_EL_USAC_ITES - : 0; - self->elFlags[el] |= + elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].m_interTes) + ? AC_EL_USAC_ITES + : 0; + elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].m_pvc) ? AC_EL_USAC_PVC : 0; - self->elFlags[el] |= + elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].usacElementType == ID_USAC_LFE) ? AC_EL_USAC_LFE : 0; - self->elFlags[el] |= + elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].usacElementType == ID_USAC_LFE) ? AC_EL_LFE : 0; if ((asc->m_sc.m_usacConfig.element[_el].usacElementType == ID_USAC_CPE) && ((self->usacStereoConfigIndex[el] == 0))) { - self->elFlags[el] |= AC_EL_USAC_CP_POSSIBLE; + elFlags[el] |= AC_EL_USAC_CP_POSSIBLE; } } @@ -1846,8 +1873,8 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, if (configMode & AC_CM_ALLOC_MEM) { self->streamInfo.extSamplingRate = asc->m_extensionSamplingFrequency; } - self->flags[streamIndex] |= (asc->m_sbrPresentFlag) ? AC_SBR_PRESENT : 0; - self->flags[streamIndex] |= (asc->m_psPresentFlag) ? AC_PS_PRESENT : 0; + flags |= (asc->m_sbrPresentFlag) ? AC_SBR_PRESENT : 0; + flags |= (asc->m_psPresentFlag) ? AC_PS_PRESENT : 0; if (asc->m_sbrPresentFlag) { self->sbrEnabled = 1; self->sbrEnabledPrev = 1; @@ -1873,51 +1900,47 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, } /* --------- vcb11 ------------ */ - self->flags[streamIndex] |= (asc->m_vcb11Flag) ? AC_ER_VCB11 : 0; + flags |= (asc->m_vcb11Flag) ? AC_ER_VCB11 : 0; /* ---------- rvlc ------------ */ - self->flags[streamIndex] |= (asc->m_rvlcFlag) ? AC_ER_RVLC : 0; + flags |= (asc->m_rvlcFlag) ? AC_ER_RVLC : 0; /* ----------- hcr ------------ */ - self->flags[streamIndex] |= (asc->m_hcrFlag) ? AC_ER_HCR : 0; + flags |= (asc->m_hcrFlag) ? AC_ER_HCR : 0; if (asc->m_aot == AOT_ER_AAC_ELD) { self->mpsEnableCurr = 0; - self->flags[streamIndex] |= AC_ELD; - self->flags[streamIndex] |= - (asc->m_sbrPresentFlag) - ? AC_SBR_PRESENT - : 0; /* Need to set the SBR flag for backward-compatibility - reasons. Even if SBR is not supported. */ - self->flags[streamIndex] |= - (asc->m_sc.m_eldSpecificConfig.m_sbrCrcFlag) ? AC_SBRCRC : 0; - self->flags[streamIndex] |= - (asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign) ? AC_MPS_PRESENT - : 0; + flags |= AC_ELD; + flags |= (asc->m_sbrPresentFlag) + ? AC_SBR_PRESENT + : 0; /* Need to set the SBR flag for backward-compatibility + reasons. Even if SBR is not supported. */ + flags |= (asc->m_sc.m_eldSpecificConfig.m_sbrCrcFlag) ? AC_SBRCRC : 0; + flags |= (asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign) + ? AC_MPS_PRESENT + : 0; if (self->mpsApplicable) { self->mpsEnableCurr = asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign; } } - self->flags[streamIndex] |= (asc->m_aot == AOT_ER_AAC_LD) ? AC_LD : 0; - self->flags[streamIndex] |= (asc->m_epConfig >= 0) ? AC_ER : 0; + flags |= (asc->m_aot == AOT_ER_AAC_LD) ? AC_LD : 0; + flags |= (asc->m_epConfig >= 0) ? AC_ER : 0; if (asc->m_aot == AOT_USAC) { - self->flags[streamIndex] |= AC_USAC; - self->flags[streamIndex] |= - (asc->m_sc.m_usacConfig.element[0].m_stereoConfigIndex > 0) - ? AC_MPS_PRESENT - : 0; + flags |= AC_USAC; + flags |= (asc->m_sc.m_usacConfig.element[0].m_stereoConfigIndex > 0) + ? AC_MPS_PRESENT + : 0; } if (asc->m_aot == AOT_DRM_AAC) { - self->flags[streamIndex] |= AC_DRM | AC_SBRCRC | AC_SCALABLE; + flags |= AC_DRM | AC_SBRCRC | AC_SCALABLE; } if (asc->m_aot == AOT_DRM_SURROUND) { - self->flags[streamIndex] |= - AC_DRM | AC_SBRCRC | AC_SCALABLE | AC_MPS_PRESENT; + flags |= AC_DRM | AC_SBRCRC | AC_SCALABLE | AC_MPS_PRESENT; FDK_ASSERT(!asc->m_psPresentFlag); } if ((asc->m_aot == AOT_AAC_SCAL) || (asc->m_aot == AOT_ER_AAC_SCAL)) { - self->flags[streamIndex] |= AC_SCALABLE; + flags |= AC_SCALABLE; } if ((asc->m_epConfig >= 0) && (asc->m_channelConfiguration <= 0)) { @@ -1968,6 +1991,10 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, if (ascChanged != 0) { *configChanged = 1; } + + CAacDecoder_AcceptFlags(self, asc, flags, elFlags, streamIndex, + elementOffset); + return err; } @@ -1996,7 +2023,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, } if (usacStereoConfigIndex == 3) { - self->flags[streamIndex] |= AC_USAC_SCFGI3; + flags |= AC_USAC_SCFGI3; } } break; @@ -2077,14 +2104,14 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, ch = aacChannelsOffset; int _numElements; _numElements = (((8)) + (8)); - if (self->flags[streamIndex] & (AC_RSV603DA | AC_USAC)) { + if (flags & (AC_RSV603DA | AC_USAC)) { _numElements = (int)asc->m_sc.m_usacConfig.m_usacNumElements; } for (int _el = 0; _el < _numElements; _el++) { int el_channels = 0; int el = elementOffset + _el; - if (self->flags[streamIndex] & + if (flags & (AC_ER | AC_LD | AC_ELD | AC_RSV603DA | AC_USAC | AC_RSVD50)) { if (ch >= ascChannels) { break; @@ -2184,15 +2211,14 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, if (self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer == NULL) { goto bail; } - if (self->flags[streamIndex] & - (AC_USAC | AC_RSVD50 | AC_RSV603DA /*|AC_BSAC*/)) { + if (flags & (AC_USAC | AC_RSVD50 | AC_RSV603DA /*|AC_BSAC*/)) { self->pAacDecoderStaticChannelInfo[ch]->hArCo = CArco_Create(); if (self->pAacDecoderStaticChannelInfo[ch]->hArCo == NULL) { goto bail; } } - if (!(self->flags[streamIndex] & (AC_USAC | AC_RSV603DA))) { + if (!(flags & (AC_USAC | AC_RSV603DA))) { CPns_UpdateNoiseState( &self->pAacDecoderChannelInfo[ch]->data.aac.PnsData, &self->pAacDecoderStaticChannelInfo[ch]->pnsCurrentSeed, @@ -2203,7 +2229,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, chIdx++; } - if (self->flags[streamIndex] & AC_USAC) { + if (flags & AC_USAC) { for (int _ch = 0; _ch < flushChannels; _ch++) { ch = aacChannelsOffset + _ch; if (self->pTimeDataFlush[ch] == NULL) { @@ -2215,7 +2241,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, } } - if (self->flags[streamIndex] & (AC_USAC | AC_RSV603DA)) { + if (flags & (AC_USAC | AC_RSV603DA)) { int complexStereoPredPossible = 0; ch = aacChannelsOffset; chIdx = aacChannelsOffsetIdx; @@ -2231,7 +2257,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, elCh = 1; } - if (self->elFlags[el2] & AC_EL_USAC_CP_POSSIBLE) { + if (elFlags[el2] & AC_EL_USAC_CP_POSSIBLE) { complexStereoPredPossible = 1; if (self->cpeStaticData[el2] == NULL) { self->cpeStaticData[el2] = GetCpePersistentData(); @@ -2368,9 +2394,6 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, } } - /* Update externally visible copy of flags */ - self->streamInfo.flags = self->flags[0]; - if (*configChanged) { int drcDecSampleRate, drcDecFrameSize; @@ -2400,6 +2423,12 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, pcmLimiter_SetThreshold(self->hLimiter, FL2FXCONST_DBL(0.89125094f)); } + CAacDecoder_AcceptFlags(self, asc, flags, elFlags, streamIndex, + elementOffset); + + /* Update externally visible copy of flags */ + self->streamInfo.flags = self->flags[0]; + return err; bail: From 5eb9ed1b1fe94e8bf94bba4aa305b61db19b48c5 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:58:17 +0200 Subject: [PATCH 17/78] Check number of core channels and SAC decoder input channels to avoid a channel mismatch. Bug: 176246647 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: Ib8b6973e9c29e13b8ef33d7736be2b977928face --- libAACdec/src/aacdecoder_lib.cpp | 16 +++++++--------- libAACenc/src/aacenc_lib.cpp | 4 ++-- libMpegTPDec/include/tp_data.h | 4 ++-- libMpegTPDec/src/tpdec_asc.cpp | 8 ++++++-- libMpegTPEnc/include/tp_data.h | 4 ++-- libMpegTPEnc/src/tpenc_asc.cpp | 6 +++--- libSACdec/include/sac_dec_lib.h | 6 +++--- libSACdec/src/sac_dec.cpp | 14 ++++++++------ libSACdec/src/sac_dec_lib.cpp | 21 ++++++++++++++++++--- 9 files changed, 51 insertions(+), 32 deletions(-) diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index 0c13304..6fb7bf1 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -385,21 +385,19 @@ static INT aacDecoder_SbrCallback( return errTp; } -static INT aacDecoder_SscCallback(void *handle, HANDLE_FDK_BITSTREAM hBs, - const AUDIO_OBJECT_TYPE coreCodec, - const INT samplingRate, const INT frameSize, - const INT stereoConfigIndex, - const INT coreSbrFrameLengthIndex, - const INT configBytes, const UCHAR configMode, - UCHAR *configChanged) { +static INT aacDecoder_SscCallback( + void *handle, HANDLE_FDK_BITSTREAM hBs, const AUDIO_OBJECT_TYPE coreCodec, + const INT samplingRate, const INT frameSize, const INT numChannels, + const INT stereoConfigIndex, const INT coreSbrFrameLengthIndex, + const INT configBytes, const UCHAR configMode, UCHAR *configChanged) { SACDEC_ERROR err; TRANSPORTDEC_ERROR errTp; HANDLE_AACDECODER hAacDecoder = (HANDLE_AACDECODER)handle; err = mpegSurroundDecoder_Config( (CMpegSurroundDecoder *)hAacDecoder->pMpegSurroundDecoder, hBs, coreCodec, - samplingRate, frameSize, stereoConfigIndex, coreSbrFrameLengthIndex, - configBytes, configMode, configChanged); + samplingRate, frameSize, numChannels, stereoConfigIndex, + coreSbrFrameLengthIndex, configBytes, configMode, configChanged); switch (err) { case MPS_UNSUPPORTED_CONFIG: diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp index c3977f3..e39e62e 100644 --- a/libAACenc/src/aacenc_lib.cpp +++ b/libAACenc/src/aacenc_lib.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -1235,7 +1235,7 @@ static INT aacenc_SbrCallback(void *self, HANDLE_FDK_BITSTREAM hBs, INT aacenc_SscCallback(void *self, HANDLE_FDK_BITSTREAM hBs, const AUDIO_OBJECT_TYPE coreCodec, const INT samplingRate, const INT frameSize, - const INT stereoConfigIndex, + const INT numChannels, const INT stereoConfigIndex, const INT coreSbrFrameLengthIndex, const INT configBytes, const UCHAR configMode, UCHAR *configChanged) { HANDLE_AACENCODER hAacEncoder = (HANDLE_AACENCODER)self; diff --git a/libMpegTPDec/include/tp_data.h b/libMpegTPDec/include/tp_data.h index b015332..b63087a 100644 --- a/libMpegTPDec/include/tp_data.h +++ b/libMpegTPDec/include/tp_data.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -368,7 +368,7 @@ typedef INT (*cbCtrlCFGChange_t)(void *, const CCtrlCFGChange *); typedef INT (*cbSsc_t)(void *, HANDLE_FDK_BITSTREAM, const AUDIO_OBJECT_TYPE coreCodec, const INT samplingRate, const INT frameSize, - const INT stereoConfigIndex, + const INT numChannels, const INT stereoConfigIndex, const INT coreSbrFrameLengthIndex, const INT configBytes, const UCHAR configMode, UCHAR *configChanged); diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp index ffe85c1..5a89a4d 100644 --- a/libMpegTPDec/src/tpdec_asc.cpp +++ b/libMpegTPDec/src/tpdec_asc.cpp @@ -1415,7 +1415,7 @@ static TRANSPORTDEC_ERROR EldSpecificConfig_Parse(CSAudioSpecificConfig *asc, cb->cbSscData, hBs, asc->m_aot, asc->m_samplingFrequency << esc->m_sbrSamplingRate, asc->m_samplesPerFrame << esc->m_sbrSamplingRate, - 1, /* stereoConfigIndex */ + asc->m_channelConfiguration, 1, /* stereoConfigIndex */ -1, /* nTimeSlots: read from bitstream */ eldExtLen, asc->configMode, &asc->SacConfigChanged); if (ErrorStatus != TRANSPORTDEC_OK) { @@ -1827,6 +1827,8 @@ static TRANSPORTDEC_ERROR UsacRsv60DecoderConfig_Parse( /* Mps212Config() ISO/IEC FDIS 23003-3 */ if (cb->cbSsc(cb->cbSscData, hBs, asc->m_aot, asc->m_extensionSamplingFrequency, samplesPerFrame, + 1, /* only downmix channels (residual channels are + not counted) */ usc->element[i].m_stereoConfigIndex, usc->m_coreSbrFrameLengthIndex, 0, /* don't know the length */ @@ -2221,7 +2223,7 @@ TRANSPORTDEC_ERROR AudioSpecificConfig_Parse( case AOT_MPEGS: if (cb->cbSsc != NULL) { if (cb->cbSsc(cb->cbSscData, bs, self->m_aot, self->m_samplingFrequency, - self->m_samplesPerFrame, 1, + self->m_samplesPerFrame, self->m_channelConfiguration, 1, -1, /* nTimeSlots: read from bitstream */ 0, /* don't know the length */ self->configMode, &self->SacConfigChanged)) { @@ -2419,6 +2421,8 @@ static TRANSPORTDEC_ERROR Drm_xHEAACDecoderConfig( cb->cbSscData, hBs, AOT_DRM_USAC, /* syntax differs from MPEG Mps212Config() */ asc->m_extensionSamplingFrequency, samplesPerFrame, + 1, /* only downmix channels (residual channels are not + counted) */ usc->element[elemIdx].m_stereoConfigIndex, usc->m_coreSbrFrameLengthIndex, 0, /* don't know the length */ asc->configMode, &asc->SacConfigChanged); diff --git a/libMpegTPEnc/include/tp_data.h b/libMpegTPEnc/include/tp_data.h index 00de356..464c485 100644 --- a/libMpegTPEnc/include/tp_data.h +++ b/libMpegTPEnc/include/tp_data.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -368,7 +368,7 @@ typedef INT (*cbCtrlCFGChange_t)(void *, const CCtrlCFGChange *); typedef INT (*cbSsc_t)(void *, HANDLE_FDK_BITSTREAM, const AUDIO_OBJECT_TYPE coreCodec, const INT samplingRate, const INT frameSize, - const INT stereoConfigIndex, + const INT numChannels, const INT stereoConfigIndex, const INT coreSbrFrameLengthIndex, const INT configBytes, const UCHAR configMode, UCHAR *configChanged); diff --git a/libMpegTPEnc/src/tpenc_asc.cpp b/libMpegTPEnc/src/tpenc_asc.cpp index 0b484a0..9591ba8 100644 --- a/libMpegTPEnc/src/tpenc_asc.cpp +++ b/libMpegTPEnc/src/tpenc_asc.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -795,7 +795,7 @@ static int transportEnc_writeELDSpecificConfig(HANDLE_FDK_BITSTREAM hBs, const INT eldExtLen = (cb->cbSsc(cb->cbSscData, NULL, config->aot, config->extSamplingRate, 0, - 0, 0, 0, 0, NULL) + + 0, 0, 0, 0, 0, NULL) + 7) >> 3; INT cnt = eldExtLen; @@ -818,7 +818,7 @@ static int transportEnc_writeELDSpecificConfig(HANDLE_FDK_BITSTREAM hBs, } cb->cbSsc(cb->cbSscData, hBs, config->aot, config->extSamplingRate, 0, 0, 0, - 0, 0, NULL); + 0, 0, 0, NULL); } if (config->downscaleSamplingRate != 0 && diff --git a/libSACdec/include/sac_dec_lib.h b/libSACdec/include/sac_dec_lib.h index 1827504..5aad4e0 100644 --- a/libSACdec/include/sac_dec_lib.h +++ b/libSACdec/include/sac_dec_lib.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -316,8 +316,8 @@ SACDEC_ERROR mpegSurroundDecoder_Init( SACDEC_ERROR mpegSurroundDecoder_Config( CMpegSurroundDecoder *pMpegSurroundDecoder, HANDLE_FDK_BITSTREAM hBs, AUDIO_OBJECT_TYPE coreCodec, INT samplingRate, INT frameSize, - INT stereoConfigIndex, INT coreSbrFrameLengthIndex, INT configBytes, - const UCHAR configMode, UCHAR *configChanged); + INT numChannels, INT stereoConfigIndex, INT coreSbrFrameLengthIndex, + INT configBytes, const UCHAR configMode, UCHAR *configChanged); SACDEC_ERROR mpegSurroundDecoder_ConfigureQmfDomain( diff --git a/libSACdec/src/sac_dec.cpp b/libSACdec/src/sac_dec.cpp index f0d24fb..a26e251 100644 --- a/libSACdec/src/sac_dec.cpp +++ b/libSACdec/src/sac_dec.cpp @@ -1209,15 +1209,17 @@ static SACDEC_ERROR SpatialDecApplyParameterSets( self->bShareDelayWithSBR = 0; /* We got no hybrid delay */ else self->bShareDelayWithSBR = 1; - SpatialDecFeedQMF(self, qmfInDataReal, qmfInDataImag, ts_io, bypassMode, - self->qmfInputReal__FDK, self->qmfInputImag__FDK, - self->numInputChannels); + SpatialDecFeedQMF( + self, qmfInDataReal, qmfInDataImag, ts_io, bypassMode, + self->qmfInputReal__FDK, self->qmfInputImag__FDK, + (bypassMode) ? numInputChannels : self->numInputChannels); break; case INPUTMODE_TIME: self->bShareDelayWithSBR = 0; - SpatialDecQMFAnalysis(self, inData, ts_io, bypassMode, - self->qmfInputReal__FDK, self->qmfInputImag__FDK, - self->numInputChannels); + SpatialDecQMFAnalysis( + self, inData, ts_io, bypassMode, self->qmfInputReal__FDK, + self->qmfInputImag__FDK, + (bypassMode) ? numInputChannels : self->numInputChannels); break; default: break; diff --git a/libSACdec/src/sac_dec_lib.cpp b/libSACdec/src/sac_dec_lib.cpp index 57446f8..d30131f 100644 --- a/libSACdec/src/sac_dec_lib.cpp +++ b/libSACdec/src/sac_dec_lib.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -700,9 +700,10 @@ bail: SACDEC_ERROR mpegSurroundDecoder_Config( CMpegSurroundDecoder *pMpegSurroundDecoder, HANDLE_FDK_BITSTREAM hBs, AUDIO_OBJECT_TYPE coreCodec, INT samplingRate, INT frameSize, - INT stereoConfigIndex, INT coreSbrFrameLengthIndex, INT configBytes, - const UCHAR configMode, UCHAR *configChanged) { + INT numChannels, INT stereoConfigIndex, INT coreSbrFrameLengthIndex, + INT configBytes, const UCHAR configMode, UCHAR *configChanged) { SACDEC_ERROR err = MPS_OK; + INT nInputChannels; SPATIAL_SPECIFIC_CONFIG spatialSpecificConfig; SPATIAL_SPECIFIC_CONFIG *pSsc = &pMpegSurroundDecoder->spatialSpecificConfigBackup; @@ -716,12 +717,18 @@ SACDEC_ERROR mpegSurroundDecoder_Config( err = SpatialDecParseMps212Config( hBs, &spatialSpecificConfig, samplingRate, coreCodec, stereoConfigIndex, coreSbrFrameLengthIndex); + nInputChannels = spatialSpecificConfig.nInputChannels; pSsc = &spatialSpecificConfig; } else { err = SpatialDecParseMps212Config( hBs, &pMpegSurroundDecoder->spatialSpecificConfigBackup, samplingRate, coreCodec, stereoConfigIndex, coreSbrFrameLengthIndex); + nInputChannels = + pMpegSurroundDecoder->spatialSpecificConfigBackup.nInputChannels; + } + if ((err == MPS_OK) && (numChannels != nInputChannels)) { + err = MPS_PARSE_ERROR; } break; case AOT_ER_AAC_ELD: @@ -731,11 +738,19 @@ SACDEC_ERROR mpegSurroundDecoder_Config( * into temporarily allocated structure */ err = SpatialDecParseSpecificConfig(hBs, &spatialSpecificConfig, configBytes, coreCodec); + nInputChannels = spatialSpecificConfig.nInputChannels; pSsc = &spatialSpecificConfig; } else { err = SpatialDecParseSpecificConfig( hBs, &pMpegSurroundDecoder->spatialSpecificConfigBackup, configBytes, coreCodec); + nInputChannels = + pMpegSurroundDecoder->spatialSpecificConfigBackup.nInputChannels; + } + /* check number of channels for channel_configuration > 0 */ + if ((err == MPS_OK) && (numChannels > 0) && + (numChannels != nInputChannels)) { + err = MPS_PARSE_ERROR; } break; default: From 36dd057c406534e077c37d5121633dd9ef6ded68 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:58:42 +0200 Subject: [PATCH 18/78] Introduce additional sanity checks to validate program config element. Bug: 176246647 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I3e04480ab5a74da1a9d09af5da95afb2000b3117 --- libMpegTPDec/src/tpdec_asc.cpp | 167 ++++++++++++++++++++++++++++++--- 1 file changed, 156 insertions(+), 11 deletions(-) diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp index 5a89a4d..a2baaaf 100644 --- a/libMpegTPDec/src/tpdec_asc.cpp +++ b/libMpegTPDec/src/tpdec_asc.cpp @@ -266,11 +266,118 @@ static int CProgramConfig_ReadHeightExt(CProgramConfig *pPce, return (err); } +/** + * \brief Sanity checks for program config element. + * Check order of elements according to ISO/IEC 13818-7:2003(E), + * chapter 8.5.1 + * + * \param pPce pointer to program config element. + * + * \return 0 if successful, otherwise 1. + */ +static int CProgramConfig_Check(CProgramConfig *pPce) { + INT i; + INT err = 0; + INT numBackChannels[3] = {0}; + INT numSideChannels[3] = {0}; + INT numFrontChannels[3] = {0}; + UCHAR *pCpeFront = pPce->FrontElementIsCpe; + UCHAR *pCpeSide = pPce->SideElementIsCpe; + UCHAR *pCpeBack = pPce->BackElementIsCpe; + UCHAR *pHeight; + + pHeight = pPce->BackElementHeightInfo; + for (i = 0; i < pPce->NumBackChannelElements; i++) { + numBackChannels[*pHeight] += pPce->BackElementIsCpe[i] ? 2 : 1; + pHeight++; + } + pHeight = pPce->SideElementHeightInfo; + for (i = 0; i < pPce->NumSideChannelElements; i++) { + numSideChannels[*pHeight] += pPce->SideElementIsCpe[i] ? 2 : 1; + pHeight++; + } + pHeight = pPce->FrontElementHeightInfo; + for (i = 0; i < pPce->NumFrontChannelElements; i++) { + numFrontChannels[*pHeight] += pPce->FrontElementIsCpe[i] ? 2 : 1; + pHeight++; + } + + /* 0 = normal height channels, 1 = top height channels, 2 = bottom height + * channels */ + for (i = 0; i < 3; i++) { + /* if number of channels is odd => first element must be a SCE (front center + * channel) */ + if (numFrontChannels[i] & 1) { + if (*pCpeFront++ == ID_CPE) { + err = 1; + goto bail; + } + numFrontChannels[i]--; + } + while (numFrontChannels[i] > 0) { + /* must be CPE or paired SCE */ + if (*pCpeFront++ == ID_SCE) { + if (*pCpeFront++ == ID_CPE) { + err = 1; + goto bail; + } + } + numFrontChannels[i] -= 2; + }; + + /* in case that a top center surround channel (Ts) is transmitted the number + * of channels can be odd */ + if (i != 1) { + /* number of channels must be even */ + if (numSideChannels[i] & 1) { + err = 1; + goto bail; + } + while (numSideChannels[i] > 0) { + /* must be CPE or paired SCE */ + if (*pCpeSide++ == ID_SCE) { + if (*pCpeSide++ == ID_CPE) { + err = 1; + goto bail; + } + } + numSideChannels[i] -= 2; + }; + } + + while (numBackChannels[i] > 1) { + /* must be CPE or paired SCE */ + if (*pCpeBack++ == ID_SCE) { + if (*pCpeBack++ == ID_CPE) { + err = 1; + goto bail; + } + } + numBackChannels[i] -= 2; + }; + /* if number of channels is odd => last element must be a SCE (back center + * channel) */ + if (numBackChannels[i]) { + if (*pCpeBack++ == ID_CPE) { + err = 1; + goto bail; + } + } + } + +bail: + + return err; +} + void CProgramConfig_Read(CProgramConfig *pPce, HANDLE_FDK_BITSTREAM bs, UINT alignmentAnchor) { - int i, err = 0; + int i; int commentBytes; + UCHAR tag, isCpe; + UCHAR checkElementTagSelect[3][PC_FSB_CHANNELS_MAX] = {{0}}; + pPce->isValid = 1; pPce->NumEffectiveChannels = 0; pPce->NumChannels = 0; pPce->ElementInstanceTag = (UCHAR)FDKreadBits(bs, 4); @@ -297,28 +404,60 @@ void CProgramConfig_Read(CProgramConfig *pPce, HANDLE_FDK_BITSTREAM bs, } for (i = 0; i < pPce->NumFrontChannelElements; i++) { - pPce->FrontElementIsCpe[i] = (UCHAR)FDKreadBits(bs, 1); - pPce->FrontElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); + pPce->FrontElementIsCpe[i] = isCpe = (UCHAR)FDKreadBits(bs, 1); + pPce->FrontElementTagSelect[i] = tag = (UCHAR)FDKreadBits(bs, 4); pPce->NumChannels += pPce->FrontElementIsCpe[i] ? 2 : 1; + + /* Check element instance tag according to ISO/IEC 13818-7:2003(E), + * chapter 8.2.1.1 */ + if (checkElementTagSelect[isCpe][tag] == 0) { + checkElementTagSelect[isCpe][tag] = 1; + } else { + pPce->isValid = 0; + } } for (i = 0; i < pPce->NumSideChannelElements; i++) { - pPce->SideElementIsCpe[i] = (UCHAR)FDKreadBits(bs, 1); - pPce->SideElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); + pPce->SideElementIsCpe[i] = isCpe = (UCHAR)FDKreadBits(bs, 1); + pPce->SideElementTagSelect[i] = tag = (UCHAR)FDKreadBits(bs, 4); pPce->NumChannels += pPce->SideElementIsCpe[i] ? 2 : 1; + + /* Check element instance tag according to ISO/IEC 13818-7:2003(E), + * chapter 8.2.1.1 */ + if (checkElementTagSelect[isCpe][tag] == 0) { + checkElementTagSelect[isCpe][tag] = 1; + } else { + pPce->isValid = 0; + } } for (i = 0; i < pPce->NumBackChannelElements; i++) { - pPce->BackElementIsCpe[i] = (UCHAR)FDKreadBits(bs, 1); - pPce->BackElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); + pPce->BackElementIsCpe[i] = isCpe = (UCHAR)FDKreadBits(bs, 1); + pPce->BackElementTagSelect[i] = tag = (UCHAR)FDKreadBits(bs, 4); pPce->NumChannels += pPce->BackElementIsCpe[i] ? 2 : 1; + + /* Check element instance tag according to ISO/IEC 13818-7:2003(E), + * chapter 8.2.1.1 */ + if (checkElementTagSelect[isCpe][tag] == 0) { + checkElementTagSelect[isCpe][tag] = 1; + } else { + pPce->isValid = 0; + } } pPce->NumEffectiveChannels = pPce->NumChannels; for (i = 0; i < pPce->NumLfeChannelElements; i++) { - pPce->LfeElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); + pPce->LfeElementTagSelect[i] = tag = (UCHAR)FDKreadBits(bs, 4); pPce->NumChannels += 1; + + /* Check element instance tag according to ISO/IEC 13818-7:2003(E), + * chapter 8.2.1.1 */ + if (checkElementTagSelect[2][tag] == 0) { + checkElementTagSelect[2][tag] = 1; + } else { + pPce->isValid = 0; + } } for (i = 0; i < pPce->NumAssocDataElements; i++) { @@ -336,7 +475,15 @@ void CProgramConfig_Read(CProgramConfig *pPce, HANDLE_FDK_BITSTREAM bs, commentBytes = pPce->CommentFieldBytes; /* Search for height info extension and read it if available */ - err = CProgramConfig_ReadHeightExt(pPce, bs, &commentBytes, alignmentAnchor); + if (CProgramConfig_ReadHeightExt(pPce, bs, &commentBytes, alignmentAnchor)) { + pPce->isValid = 0; + } + + /* Check order of elements according to ISO / IEC 13818 - 7:2003(E), + * chapter 8.5.1 */ + if (CProgramConfig_Check(pPce)) { + pPce->isValid = 0; + } for (i = 0; i < commentBytes; i++) { UCHAR text; @@ -347,8 +494,6 @@ void CProgramConfig_Read(CProgramConfig *pPce, HANDLE_FDK_BITSTREAM bs, pPce->Comment[i] = text; } } - - pPce->isValid = (err) ? 0 : 1; } /* From 9a48d4799826e54915f06ca25bfd4e9d81dcf8c7 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:05:08 +0200 Subject: [PATCH 19/78] Consider TNS headroom for complex prediction. Bug: 176246647 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I8261106b98d7e7c5a8a2af38585c726285ea8623 --- libAACdec/src/channel.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libAACdec/src/channel.cpp b/libAACdec/src/channel.cpp index a020034..7e62bfb 100644 --- a/libAACdec/src/channel.cpp +++ b/libAACdec/src/channel.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -265,7 +265,9 @@ void CChannelElement_Decode( stereo prediction since scaling has already been carried out. */ int max_sfb_ste = (INT)(pAacDecoderChannelInfo[L]->icsInfo.max_sfb_ste); - if ((!CP_active) || (CP_active && (max_sfb_ste < noSfbs)) || + if (!(CP_active && (max_sfb_ste == noSfbs)) || + !(CP_active && + !(pAacDecoderChannelInfo[ch]->pDynData->TnsData.Active)) || ((flags & (AC_USAC | AC_RSVD50 | AC_RSV603DA)) && (pAacDecoderChannelInfo[L]->pDynData->specificTo.usac.tns_on_lr == 0))) { From 3495808c8348ca8df31b0fdb051c135656931cb4 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:07:13 +0200 Subject: [PATCH 20/78] Fix USAC time domain limiter latency at config change. We have observed quality problems regarding config switching for USAC streams. Crossfading did not consider the USAC time domain limiter latency correctly. The limiter memory still contained the last part of the frame before the config change. With this patch we were able to improve the quality by moving the limiter processing to the end of the processing chain (crossfade -> DRC -> limiter). By that we don't have to consider the limiter latency at the crossfader anymore and can resolve the quality issue. Bug: 176246647 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I0dfd3b76ff2b0daf495ad406283f56a39982ad8f Change-Id: I26f5da65ef8344602007e180e837820c6a25f173 --- libAACdec/src/aac_ram.cpp | 4 +- libAACdec/src/aac_ram.h | 4 +- libAACdec/src/aacdecoder.cpp | 23 +-- libAACdec/src/aacdecoder.h | 18 ++- libAACdec/src/aacdecoder_lib.cpp | 248 ++++++++++++++++--------------- 5 files changed, 156 insertions(+), 141 deletions(-) diff --git a/libAACdec/src/aac_ram.cpp b/libAACdec/src/aac_ram.cpp index aa8f6a6..fac1540 100644 --- a/libAACdec/src/aac_ram.cpp +++ b/libAACdec/src/aac_ram.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -148,7 +148,7 @@ C_ALLOC_MEM(CplxPredictionData, CCplxPredictionData, 1) /*! The buffer holds time samples for the crossfade in case of an USAC DASH IPF config change Dimension: (8) */ -C_ALLOC_MEM2(TimeDataFlush, INT_PCM, TIME_DATA_FLUSH_SIZE, (8)) +C_ALLOC_MEM2(TimeDataFlush, PCM_DEC, TIME_DATA_FLUSH_SIZE, (8)) /* @} */ diff --git a/libAACdec/src/aac_ram.h b/libAACdec/src/aac_ram.h index b9b95b7..395b2b2 100644 --- a/libAACdec/src/aac_ram.h +++ b/libAACdec/src/aac_ram.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -132,7 +132,7 @@ H_ALLOC_MEM(CplxPredictionData, CCplxPredictionData) H_ALLOC_MEM(SpectralCoeffs, FIXP_DBL) H_ALLOC_MEM(SpecScale, SHORT) -H_ALLOC_MEM(TimeDataFlush, INT_PCM) +H_ALLOC_MEM(TimeDataFlush, PCM_DEC) H_ALLOC_MEM_OVERLAY(WorkBufferCore1, CWorkBufferCore1) H_ALLOC_MEM_OVERLAY(WorkBufferCore2, FIXP_DBL) diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp index c6d1832..c18e5e9 100644 --- a/libAACdec/src/aacdecoder.cpp +++ b/libAACdec/src/aacdecoder.cpp @@ -568,7 +568,7 @@ static int CProgramConfigElement_Read(HANDLE_FDK_BITSTREAM bs, \return Error code */ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_PrepareCrossFade( - const INT_PCM *pTimeData, INT_PCM **pTimeDataFlush, const INT numChannels, + const PCM_DEC *pTimeData, PCM_DEC **pTimeDataFlush, const INT numChannels, const INT frameSize, const INT interleaved) { int i, ch, s1, s2; AAC_DECODER_ERROR ErrorStatus; @@ -584,7 +584,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_PrepareCrossFade( } for (ch = 0; ch < numChannels; ch++) { - const INT_PCM *pIn = &pTimeData[ch * s1]; + const PCM_DEC *pIn = &pTimeData[ch * s1]; for (i = 0; i < TIME_DATA_FLUSH_SIZE; i++) { pTimeDataFlush[ch][i] = *pIn; pIn += s2; @@ -606,7 +606,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_PrepareCrossFade( \return Error code */ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_ApplyCrossFade( - INT_PCM *pTimeData, INT_PCM **pTimeDataFlush, const INT numChannels, + PCM_DEC *pTimeData, PCM_DEC **pTimeDataFlush, const INT numChannels, const INT frameSize, const INT interleaved) { int i, ch, s1, s2; AAC_DECODER_ERROR ErrorStatus; @@ -622,15 +622,15 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_ApplyCrossFade( } for (ch = 0; ch < numChannels; ch++) { - INT_PCM *pIn = &pTimeData[ch * s1]; + PCM_DEC *pIn = &pTimeData[ch * s1]; for (i = 0; i < TIME_DATA_FLUSH_SIZE; i++) { FIXP_SGL alpha = (FIXP_SGL)i << (FRACT_BITS - 1 - TIME_DATA_FLUSH_SIZE_SF); - FIXP_DBL time = FX_PCM2FX_DBL(*pIn); - FIXP_DBL timeFlush = FX_PCM2FX_DBL(pTimeDataFlush[ch][i]); + FIXP_DBL time = PCM_DEC2FIXP_DBL(*pIn); + FIXP_DBL timeFlush = PCM_DEC2FIXP_DBL(pTimeDataFlush[ch][i]); - *pIn = (INT_PCM)(FIXP_PCM)FX_DBL2FX_PCM( - timeFlush - fMult(timeFlush, alpha) + fMult(time, alpha)); + *pIn = FIXP_DBL2PCM_DEC(timeFlush - fMult(timeFlush, alpha) + + fMult(time, alpha)); pIn += s2; } } @@ -753,7 +753,12 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_PreRollExtensionPayloadParse( /* We are interested in preroll AUs if an explicit or an implicit config * change is signalized in other words if the build up status is set. */ if (self->buildUpStatus == AACDEC_USAC_BUILD_UP_ON) { - self->applyCrossfade |= FDKreadBit(hBs); + UCHAR applyCrossfade = FDKreadBit(hBs); + if (applyCrossfade) { + self->applyCrossfade |= AACDEC_CROSSFADE_BITMASK_PREROLL; + } else { + self->applyCrossfade &= ~AACDEC_CROSSFADE_BITMASK_PREROLL; + } FDKreadBit(hBs); /* reserved */ /* Read num preroll AU's */ *numPrerollAU = escapedValue(hBs, 2, 4, 0); diff --git a/libAACdec/src/aacdecoder.h b/libAACdec/src/aacdecoder.h index bd1f38f..002807f 100644 --- a/libAACdec/src/aacdecoder.h +++ b/libAACdec/src/aacdecoder.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -172,6 +172,12 @@ enum { AACDEC_RSV60_BUILD_UP_IDLE_IN_BAND = 5 }; +#define AACDEC_CROSSFADE_BITMASK_OFF \ + ((UCHAR)0) /*!< No cross-fade between frames shall be applied at next \ + config change. */ +#define AACDEC_CROSSFADE_BITMASK_PREROLL \ + ((UCHAR)1 << 1) /*!< applyCrossfade is signaled in AudioPreRoll */ + typedef struct { /* Usac Extension Elements */ USAC_EXT_ELEMENT_TYPE usacExtElementType[(3)]; @@ -325,7 +331,7 @@ This structure is allocated once for each CPE. */ UINT loudnessInfoSetPosition[3]; SCHAR defaultTargetLoudness; - INT_PCM + PCM_DEC *pTimeDataFlush[((8) * 2)]; /*!< Pointer to the flushed time data which will be used for the crossfade in case of an USAC DASH IPF config change */ @@ -341,8 +347,8 @@ This structure is allocated once for each CPE. */ start position in the bitstream */ INT accessUnit; /*!< Number of the actual processed preroll accessUnit */ - UCHAR applyCrossfade; /*!< if set crossfade for seamless stream switching is - applied */ + UCHAR applyCrossfade; /*!< If any bit is set, cross-fade for seamless stream + switching is applied */ FDK_SignalDelay usacResidualDelay; /*!< Delay residual signal to compensate for eSBR delay of DMX signal in case of @@ -439,12 +445,12 @@ LINKSPEC_H AAC_DECODER_ERROR CAacDecoder_FreeMem(HANDLE_AACDECODER self, /* Prepare crossfade for USAC DASH IPF config change */ LINKSPEC_H AAC_DECODER_ERROR CAacDecoder_PrepareCrossFade( - const INT_PCM *pTimeData, INT_PCM **pTimeDataFlush, const INT numChannels, + const PCM_DEC *pTimeData, PCM_DEC **pTimeDataFlush, const INT numChannels, const INT frameSize, const INT interleaved); /* Apply crossfade for USAC DASH IPF config change */ LINKSPEC_H AAC_DECODER_ERROR CAacDecoder_ApplyCrossFade( - INT_PCM *pTimeData, INT_PCM **pTimeDataFlush, const INT numChannels, + PCM_DEC *pTimeData, PCM_DEC **pTimeDataFlush, const INT numChannels, const INT frameSize, const INT interleaved); /* Set flush and build up mode */ diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index 6fb7bf1..5efa369 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -1155,6 +1155,8 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(HANDLE_AACDECODER self, int applyCrossfade = 1; /* flag indicates if flushing was possible */ PCM_DEC *pTimeData2; PCM_AAC *pTimeData3; + INT pcmLimiterScale = 0; + INT interleaved = 0; if (self == NULL) { return AAC_DEC_INVALID_HANDLE; @@ -1800,8 +1802,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(HANDLE_AACDECODER self, } if (self->streamInfo.extAot != AOT_AAC_SLS) { - INT pcmLimiterScale = 0; - INT interleaved = 0; + interleaved = 0; interleaved |= (self->sbrEnabled) ? 1 : 0; interleaved |= (self->mpsEnableCurr) ? 1 : 0; PCMDMX_ERROR dmxErr = PCMDMX_OK; @@ -1832,145 +1833,38 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(HANDLE_AACDECODER self, * predictable behavior and thus maybe produce strange output. */ ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; } - - pcmLimiterScale += PCM_OUT_HEADROOM; - - if (flags & AACDEC_CLRHIST) { - if (!(self->flags[0] & AC_USAC)) { - /* Reset DRC data */ - aacDecoder_drcReset(self->hDrcInfo); - /* Delete the delayed signal. */ - pcmLimiter_Reset(self->hLimiter); - } - } - - /* Set applyExtGain if DRC processing is enabled and if - progRefLevelPresent is present for the first time. Consequences: The - headroom of the output signal can be set to AACDEC_DRC_GAIN_SCALING - only for audio formats which support legacy DRC Level Normalization. - For all other audio formats the headroom of the output - signal is set to PCM_OUT_HEADROOM. */ - if (self->hDrcInfo->enable && - (self->hDrcInfo->progRefLevelPresent == 1)) { - self->hDrcInfo->applyExtGain |= 1; - } - - /* Check whether time data buffer is large enough. */ - if (timeDataSize < - (self->streamInfo.numChannels * self->streamInfo.frameSize)) { - ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL; - goto bail; - } - - if (self->limiterEnableCurr) { - /* use workBufferCore2 buffer for interleaving */ - PCM_LIM *pInterleaveBuffer; - int blockLength = self->streamInfo.frameSize; - - /* Set actual signal parameters */ - pcmLimiter_SetNChannels(self->hLimiter, self->streamInfo.numChannels); - pcmLimiter_SetSampleRate(self->hLimiter, self->streamInfo.sampleRate); - - if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) || - (self->mpsEnableCurr)) { - pInterleaveBuffer = (PCM_LIM *)pTimeData2; - } else { - pInterleaveBuffer = (PCM_LIM *)self->workBufferCore2; - - /* applyLimiter requests for interleaved data */ - /* Interleave ouput buffer */ - FDK_interleave(pTimeData2, pInterleaveBuffer, - self->streamInfo.numChannels, blockLength, - self->streamInfo.frameSize); - } - - FIXP_DBL *pGainPerSample = NULL; - - if (self->hDrcInfo->enable && self->hDrcInfo->applyExtGain) { - pGainPerSample = self->workBufferCore1; - - if ((INT)GetRequiredMemWorkBufferCore1() < - (INT)(self->streamInfo.frameSize * sizeof(FIXP_DBL))) { - ErrorStatus = AAC_DEC_UNKNOWN; - goto bail; - } - - pcmLimiterScale = applyDrcLevelNormalization( - self->hDrcInfo, (PCM_DEC *)pInterleaveBuffer, self->extGain, - pGainPerSample, pcmLimiterScale, self->extGainDelay, - self->streamInfo.frameSize, self->streamInfo.numChannels, 1, 1); - } - - pcmLimiter_Apply(self->hLimiter, pInterleaveBuffer, pTimeData, - pGainPerSample, pcmLimiterScale, - self->streamInfo.frameSize); - - { - /* Announce the additional limiter output delay */ - self->streamInfo.outputDelay += pcmLimiter_GetDelay(self->hLimiter); - } - } else { - if (self->hDrcInfo->enable && self->hDrcInfo->applyExtGain) { - pcmLimiterScale = applyDrcLevelNormalization( - self->hDrcInfo, pTimeData2, self->extGain, NULL, - pcmLimiterScale, self->extGainDelay, self->streamInfo.frameSize, - self->streamInfo.numChannels, - (interleaved || (self->streamInfo.numChannels == 1)) - ? 1 - : self->streamInfo.frameSize, - 0); - } - - /* If numChannels = 1 we do not need interleaving. The same applies if - SBR or MPS are used, since their output is interleaved already - (resampled or not) */ - if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) || - (self->mpsEnableCurr)) { - scaleValuesSaturate( - pTimeData, pTimeData2, - self->streamInfo.frameSize * self->streamInfo.numChannels, - pcmLimiterScale); - - } else { - scaleValuesSaturate( - (INT_PCM *)self->workBufferCore2, pTimeData2, - self->streamInfo.frameSize * self->streamInfo.numChannels, - pcmLimiterScale); - /* Interleave ouput buffer */ - FDK_interleave((INT_PCM *)self->workBufferCore2, pTimeData, - self->streamInfo.numChannels, - self->streamInfo.frameSize, - self->streamInfo.frameSize); - } - } - } /* if (self->streamInfo.extAot != AOT_AAC_SLS)*/ + } if (self->flags[0] & AC_USAC) { if (self->flushStatus == AACDEC_USAC_DASH_IPF_FLUSH_ON && !(flags & AACDEC_CONCEAL)) { - CAacDecoder_PrepareCrossFade(pTimeData, self->pTimeDataFlush, + CAacDecoder_PrepareCrossFade(pTimeData2, self->pTimeDataFlush, self->streamInfo.numChannels, - self->streamInfo.frameSize, 1); + self->streamInfo.frameSize, interleaved); } /* prepare crossfade buffer for fade in */ - if (!applyCrossfade && self->applyCrossfade && + if (!applyCrossfade && + (self->applyCrossfade != AACDEC_CROSSFADE_BITMASK_OFF) && !(flags & AACDEC_CONCEAL)) { for (int ch = 0; ch < self->streamInfo.numChannels; ch++) { for (int i = 0; i < TIME_DATA_FLUSH_SIZE; i++) { - self->pTimeDataFlush[ch][i] = 0; + self->pTimeDataFlush[ch][i] = (PCM_DEC)0; } } applyCrossfade = 1; } - if (applyCrossfade && self->applyCrossfade && + if (applyCrossfade && + (self->applyCrossfade != AACDEC_CROSSFADE_BITMASK_OFF) && !(accessUnit < numPrerollAU) && (self->buildUpStatus == AACDEC_USAC_BUILD_UP_ON)) { - CAacDecoder_ApplyCrossFade(pTimeData, self->pTimeDataFlush, + CAacDecoder_ApplyCrossFade(pTimeData2, self->pTimeDataFlush, self->streamInfo.numChannels, - self->streamInfo.frameSize, 1); - self->applyCrossfade = 0; + self->streamInfo.frameSize, interleaved); + self->applyCrossfade = + AACDEC_CROSSFADE_BITMASK_OFF; /* disable cross-fade between frames + at nect config change */ } } @@ -2012,6 +1906,116 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(HANDLE_AACDECODER self, ((self->flushStatus == AACDEC_USAC_DASH_IPF_FLUSH_ON) && !(flags & AACDEC_CONCEAL))); + if (self->streamInfo.extAot != AOT_AAC_SLS) { + pcmLimiterScale += PCM_OUT_HEADROOM; + + if (flags & AACDEC_CLRHIST) { + if (!(self->flags[0] & AC_USAC)) { + /* Reset DRC data */ + aacDecoder_drcReset(self->hDrcInfo); + /* Delete the delayed signal. */ + pcmLimiter_Reset(self->hLimiter); + } + } + + /* Set applyExtGain if DRC processing is enabled and if progRefLevelPresent + is present for the first time. Consequences: The headroom of the output + signal can be set to AACDEC_DRC_GAIN_SCALING only for audio formats which + support legacy DRC Level Normalization. For all other audio formats the + headroom of the output signal is set to PCM_OUT_HEADROOM. */ + if (self->hDrcInfo->enable && (self->hDrcInfo->progRefLevelPresent == 1)) { + self->hDrcInfo->applyExtGain |= 1; + } + + /* Check whether time data buffer is large enough. */ + if (timeDataSize < + (self->streamInfo.numChannels * self->streamInfo.frameSize)) { + ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL; + goto bail; + } + + if (self->limiterEnableCurr) { + /* use workBufferCore2 buffer for interleaving */ + PCM_LIM *pInterleaveBuffer; + int blockLength = self->streamInfo.frameSize; + + /* Set actual signal parameters */ + pcmLimiter_SetNChannels(self->hLimiter, self->streamInfo.numChannels); + pcmLimiter_SetSampleRate(self->hLimiter, self->streamInfo.sampleRate); + + if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) || + (self->mpsEnableCurr)) { + pInterleaveBuffer = (PCM_LIM *)pTimeData2; + } else { + pInterleaveBuffer = (PCM_LIM *)self->workBufferCore2; + + /* applyLimiter requests for interleaved data */ + /* Interleave ouput buffer */ + FDK_interleave(pTimeData2, pInterleaveBuffer, + self->streamInfo.numChannels, blockLength, + self->streamInfo.frameSize); + } + + FIXP_DBL *pGainPerSample = NULL; + + if (self->hDrcInfo->enable && self->hDrcInfo->applyExtGain) { + pGainPerSample = self->workBufferCore1; + + if ((INT)GetRequiredMemWorkBufferCore1() < + (INT)(self->streamInfo.frameSize * sizeof(FIXP_DBL))) { + ErrorStatus = AAC_DEC_UNKNOWN; + goto bail; + } + + pcmLimiterScale = applyDrcLevelNormalization( + self->hDrcInfo, (PCM_DEC *)pInterleaveBuffer, self->extGain, + pGainPerSample, pcmLimiterScale, self->extGainDelay, + self->streamInfo.frameSize, self->streamInfo.numChannels, 1, 1); + } + + pcmLimiter_Apply(self->hLimiter, pInterleaveBuffer, pTimeData, + pGainPerSample, pcmLimiterScale, + self->streamInfo.frameSize); + + { + /* Announce the additional limiter output delay */ + self->streamInfo.outputDelay += pcmLimiter_GetDelay(self->hLimiter); + } + } else { + if (self->hDrcInfo->enable && self->hDrcInfo->applyExtGain) { + pcmLimiterScale = applyDrcLevelNormalization( + self->hDrcInfo, pTimeData2, self->extGain, NULL, pcmLimiterScale, + self->extGainDelay, self->streamInfo.frameSize, + self->streamInfo.numChannels, + (interleaved || (self->streamInfo.numChannels == 1)) + ? 1 + : self->streamInfo.frameSize, + 0); + } + + /* If numChannels = 1 we do not need interleaving. The same applies if SBR + or MPS are used, since their output is interleaved already (resampled or + not) */ + if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) || + (self->mpsEnableCurr)) { + scaleValuesSaturate( + pTimeData, pTimeData2, + self->streamInfo.frameSize * self->streamInfo.numChannels, + pcmLimiterScale); + + } else { + scaleValuesSaturate( + (INT_PCM *)self->workBufferCore2, pTimeData2, + self->streamInfo.frameSize * self->streamInfo.numChannels, + pcmLimiterScale); + /* Interleave ouput buffer */ + FDK_interleave((INT_PCM *)self->workBufferCore2, pTimeData, + self->streamInfo.numChannels, self->streamInfo.frameSize, + self->streamInfo.frameSize); + } + } + } /* if (self->streamInfo.extAot != AOT_AAC_SLS)*/ + bail: /* error in renderer part occurred, ErrorStatus was set to invalid output */ From 67cae74f74bce961e0812c1743c64df96a3396b7 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:08:00 +0200 Subject: [PATCH 21/78] Read uniDrcGainExtension element only if all DRC gain sequences are parsed correctly. Prevent error return during parsing of incomplete uniDrcGain() element. This fixes unnecessary concealment of frames for AAC in case a uniDrcGain() is provided, but the uniDrcConfig() element is not available. Bug: 176246647 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I5ae343eaea481774c53240dbce4da0f4ff06cd1d --- libDRCdec/src/drcDec_reader.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/libDRCdec/src/drcDec_reader.cpp b/libDRCdec/src/drcDec_reader.cpp index 367a352..b3ec187 100644 --- a/libDRCdec/src/drcDec_reader.cpp +++ b/libDRCdec/src/drcDec_reader.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -512,10 +512,13 @@ drcDec_readUniDrcGain(HANDLE_FDK_BITSTREAM hBs, fMin(tmpNNodes, (UCHAR)16) * sizeof(GAIN_NODE)); } - hUniDrcGain->uniDrcGainExtPresent = FDKreadBits(hBs, 1); - if (hUniDrcGain->uniDrcGainExtPresent == 1) { - err = _readUniDrcGainExtension(hBs, &(hUniDrcGain->uniDrcGainExtension)); - if (err) return err; + if (pCoef && (gainSequenceCount == + pCoef->gainSequenceCount)) { /* all sequences have been read */ + hUniDrcGain->uniDrcGainExtPresent = FDKreadBits(hBs, 1); + if (hUniDrcGain->uniDrcGainExtPresent == 1) { + err = _readUniDrcGainExtension(hBs, &(hUniDrcGain->uniDrcGainExtension)); + if (err) return err; + } } if (err == DE_OK && gainSequenceCount > 0) { From af0c91e7b88ebe1a2b9a2dc272a7ba4faa92f478 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:08:34 +0200 Subject: [PATCH 22/78] Solve issue regarding config changes between Loudness-only vs. Loudness+DRC. Fix config changes from Loudness+DRC to Loudness-only configurations by clearing the DRC configuration Bug: 176246647 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I7afef848308478c29a82b13f24ba8c2a9760fd45 --- libAACdec/src/aacdecoder_lib.cpp | 17 +++++++++--- libMpegTPDec/src/tpdec_asc.cpp | 45 +++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index 6fb7bf1..47d204b 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -441,12 +441,23 @@ static INT aacDecoder_UniDrcCallback(void *handle, HANDLE_FDK_BITSTREAM hBs, TRANSPORTDEC_ERROR errTp; HANDLE_AACDECODER hAacDecoder = (HANDLE_AACDECODER)handle; DRC_DEC_CODEC_MODE drcDecCodecMode = DRC_DEC_CODEC_MODE_UNDEFINED; + UCHAR dummyBuffer[4] = {0}; + FDK_BITSTREAM dummyBs; + HANDLE_FDK_BITSTREAM hReadBs; if (subStreamIndex != 0) { return TRANSPORTDEC_OK; } - else if (aot == AOT_USAC) { + if (hBs == NULL) { + /* use dummy zero payload to clear memory */ + hReadBs = &dummyBs; + FDKinitBitStream(hReadBs, dummyBuffer, 4, 24); + } else { + hReadBs = hBs; + } + + if (aot == AOT_USAC) { drcDecCodecMode = DRC_DEC_MPEG_D_USAC; } @@ -455,10 +466,10 @@ static INT aacDecoder_UniDrcCallback(void *handle, HANDLE_FDK_BITSTREAM hBs, if (payloadType == 0) /* uniDrcConfig */ { - err = FDK_drcDec_ReadUniDrcConfig(hAacDecoder->hUniDrcDecoder, hBs); + err = FDK_drcDec_ReadUniDrcConfig(hAacDecoder->hUniDrcDecoder, hReadBs); } else /* loudnessInfoSet */ { - err = FDK_drcDec_ReadLoudnessInfoSet(hAacDecoder->hUniDrcDecoder, hBs); + err = FDK_drcDec_ReadLoudnessInfoSet(hAacDecoder->hUniDrcDecoder, hReadBs); hAacDecoder->loudnessInfoSetPosition[1] = payloadStart; hAacDecoder->loudnessInfoSetPosition[2] = fullPayloadLength; } diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp index a2baaaf..e46cb32 100644 --- a/libMpegTPDec/src/tpdec_asc.cpp +++ b/libMpegTPDec/src/tpdec_asc.cpp @@ -1778,6 +1778,10 @@ static TRANSPORTDEC_ERROR configExtension(CSUsacConfig *usc, int numConfigExtensions; CONFIG_EXT_ID usacConfigExtType; int usacConfigExtLength; + int loudnessInfoSetIndex = + -1; /* index of loudnessInfoSet config extension. -1 if not contained. */ + int tmp_subStreamIndex = 0; + AUDIO_OBJECT_TYPE tmp_aot = AOT_USAC; numConfigExtensions = (int)escapedValue(hBs, 2, 4, 8) + 1; for (int confExtIdx = 0; confExtIdx < numConfigExtensions; confExtIdx++) { @@ -1807,10 +1811,12 @@ static TRANSPORTDEC_ERROR configExtension(CSUsacConfig *usc, ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc( cb->cbUniDrcData, hBs, usacConfigExtLength, 1, /* loudnessInfoSet */ - 0, loudnessInfoSetConfigExtensionPosition, AOT_USAC); + tmp_subStreamIndex, loudnessInfoSetConfigExtensionPosition, + tmp_aot); if (ErrorStatus != TRANSPORTDEC_OK) { return ErrorStatus; } + loudnessInfoSetIndex = confExtIdx; } } break; default: @@ -1826,6 +1832,17 @@ static TRANSPORTDEC_ERROR configExtension(CSUsacConfig *usc, FDKpushFor(hBs, usacConfigExtLength); } + if (loudnessInfoSetIndex == -1 && cb->cbUniDrc != NULL) { + /* no loudnessInfoSet contained. Clear the loudnessInfoSet struct by feeding + * an empty config extension */ + ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc( + cb->cbUniDrcData, NULL, 0, 1 /* loudnessInfoSet */, tmp_subStreamIndex, + 0, tmp_aot); + if (ErrorStatus != TRANSPORTDEC_OK) { + return ErrorStatus; + } + } + return ErrorStatus; } @@ -1842,6 +1859,8 @@ static TRANSPORTDEC_ERROR UsacRsv60DecoderConfig_Parse( int channelElementIdx = 0; /* index for elements which contain audio channels (sce, cpe, lfe) */ SC_CHANNEL_CONFIG sc_chan_config = {0, 0, 0, 0}; + int uniDrcElement = + -1; /* index of uniDrc extension element. -1 if not contained. */ numberOfElements = (int)escapedValue(hBs, 4, 8, 16) + 1; usc->m_usacNumElements = numberOfElements; @@ -2017,6 +2036,10 @@ static TRANSPORTDEC_ERROR UsacRsv60DecoderConfig_Parse( case ID_USAC_EXT: ErrorStatus = extElementConfig(&usc->element[i].extElement, hBs, cb, 0, asc->m_samplesPerFrame, 0, asc->m_aot); + if (usc->element[i].extElement.usacExtElementType == + ID_EXT_ELE_UNI_DRC) { + uniDrcElement = i; + } if (ErrorStatus) { return ErrorStatus; @@ -2045,6 +2068,18 @@ static TRANSPORTDEC_ERROR UsacRsv60DecoderConfig_Parse( } } + if (uniDrcElement == -1 && cb->cbUniDrc != NULL) { + /* no uniDrcConfig contained. Clear the uniDrcConfig struct by feeding an + * empty extension element */ + int subStreamIndex = 0; + ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc( + cb->cbUniDrcData, NULL, 0, 0 /* uniDrcConfig */, subStreamIndex, 0, + asc->m_aot); + if (ErrorStatus != TRANSPORTDEC_OK) { + return ErrorStatus; + } + } + return ErrorStatus; } @@ -2131,6 +2166,14 @@ static TRANSPORTDEC_ERROR UsacConfig_Parse(CSAudioSpecificConfig *asc, if (err != TRANSPORTDEC_OK) { return err; } + } else if (cb->cbUniDrc != NULL) { + /* no loudnessInfoSet contained. Clear the loudnessInfoSet struct by feeding + * an empty config extension */ + err = (TRANSPORTDEC_ERROR)cb->cbUniDrc( + cb->cbUniDrcData, NULL, 0, 1 /* loudnessInfoSet */, 0, 0, asc->m_aot); + if (err != TRANSPORTDEC_OK) { + return err; + } } /* sanity check whether number of channels signaled in UsacDecoderConfig() From a7c36cc207495967b4b31fbb86162860146281c6 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:09:22 +0200 Subject: [PATCH 23/78] Fix wrong input buffer feed for PS encoder at less input samples than framesize. Bug 177604812 Test: see PS/SBR encoder Change-Id: I08a20209bcb83784fda5c14584b6e99c65672545 --- libAACenc/src/aacenc_lib.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp index 8a0819e..19546fc 100644 --- a/libAACenc/src/aacenc_lib.cpp +++ b/libAACenc/src/aacenc_lib.cpp @@ -1784,8 +1784,8 @@ AACENC_ERROR aacEncEncode(const HANDLE_AACENCODER hAacEncoder, hAacEncoder->nSamplesRead)); INT_PCM *pIn = hAacEncoder->inputBuffer + - (hAacEncoder->inputBufferOffset + hAacEncoder->nSamplesRead) / - hAacEncoder->aacConfig.nChannels; + hAacEncoder->inputBufferOffset / hAacEncoder->aacConfig.nChannels + + hAacEncoder->nSamplesRead / hAacEncoder->extParam.nChannels; newSamples -= (newSamples % hAacEncoder->extParam From 91ec65f7c82b202df559384e0844780bb9d80318 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:10:17 +0200 Subject: [PATCH 24/78] Fix input buffer flushing for PS encoder. Bug 177604812 Test: see PS/SBR encoder Change-Id: I3152bd7db5e039ecc54885e5b58c1cf6cb598b28 --- libAACenc/src/aacenc_lib.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp index 19546fc..caa62c5 100644 --- a/libAACenc/src/aacenc_lib.cpp +++ b/libAACenc/src/aacenc_lib.cpp @@ -1827,12 +1827,13 @@ AACENC_ERROR aacEncEncode(const HANDLE_AACENCODER hAacEncoder, /* clear out until end-of-buffer */ if (nZeros) { + INT_PCM *pIn = + hAacEncoder->inputBuffer + + hAacEncoder->inputBufferOffset / + hAacEncoder->aacConfig.nChannels + + hAacEncoder->nSamplesRead / hAacEncoder->extParam.nChannels; for (i = 0; i < (int)hAacEncoder->extParam.nChannels; i++) { - FDKmemclear(hAacEncoder->inputBuffer + - i * hAacEncoder->inputBufferSizePerChannel + - (hAacEncoder->inputBufferOffset + - hAacEncoder->nSamplesRead) / - hAacEncoder->extParam.nChannels, + FDKmemclear(pIn + i * hAacEncoder->inputBufferSizePerChannel, sizeof(INT_PCM) * nZeros); } hAacEncoder->nZerosAppended += nZeros; From 4204c466656c770c09716f89355fe485c1418c4e Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:11:03 +0200 Subject: [PATCH 25/78] Overcome SBR encoder coupling quality issue in ELD. Bug 177604812 Test: see SBR/PS encoder Change-Id: Ie7b9f8d1dec3708557d1e1189d45bc0e3bf5444c --- libSBRenc/src/env_est.cpp | 22 +++++++++++++++------- libSBRenc/src/sbr_encoder.cpp | 5 ++--- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/libSBRenc/src/env_est.cpp b/libSBRenc/src/env_est.cpp index 0eb8425..cc8780a 100644 --- a/libSBRenc/src/env_est.cpp +++ b/libSBRenc/src/env_est.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -1267,6 +1267,7 @@ void FDKsbrEnc_extractSbrEnvelope2( sbrExtrEnv->pre_transient_info[1] = ed->transient_info[1]; /* tran_flag */ hEnvChan->encEnvData.noOfEnvelopes = ed->nEnvelopes = ed->frame_info->nEnvelopes; /* number of envelopes of current frame */ + hEnvChan->encEnvData.currentAmpResFF = (AMP_RES)h_con->initAmpResFF; /* Check if the current frame is divided into one envelope only. If so, set @@ -1274,8 +1275,9 @@ void FDKsbrEnc_extractSbrEnvelope2( */ if ((hEnvChan->encEnvData.hSbrBSGrid->frameClass == FIXFIX) && (ed->nEnvelopes == 1)) { + AMP_RES currentAmpResFF = SBR_AMP_RES_1_5; if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { - /* Note: global_tonaliy_float_value == + /* Note: global_tonality_float_value == ((float)hEnvChan->encEnvData.global_tonality/((INT64)(1)<<(31-(19+2)))/0.524288*(2.0/3.0))); threshold_float_value == ((float)h_con->thresholdAmpResFF_m/((INT64)(1)<<(31-(h_con->thresholdAmpResFF_e)))/0.524288*(2.0/3.0))); @@ -1289,14 +1291,13 @@ void FDKsbrEnc_extractSbrEnvelope2( } else { hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_3_0; } - } else - hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_1_5; + currentAmpResFF = hEnvChan->encEnvData.currentAmpResFF; + } - if (hEnvChan->encEnvData.currentAmpResFF != - hEnvChan->encEnvData.init_sbr_amp_res) { + if (currentAmpResFF != hEnvChan->encEnvData.init_sbr_amp_res) { FDKsbrEnc_InitSbrHuffmanTables( &hEnvChan->encEnvData, &hEnvChan->sbrCodeEnvelope, - &hEnvChan->sbrCodeNoiseFloor, hEnvChan->encEnvData.currentAmpResFF); + &hEnvChan->sbrCodeNoiseFloor, currentAmpResFF); } } else { if (sbrHeaderData->sbr_amp_res != hEnvChan->encEnvData.init_sbr_amp_res) { @@ -1355,6 +1356,13 @@ void FDKsbrEnc_extractSbrEnvelope2( } } + if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY && + stereoMode == SBR_SWITCH_LRC && + h_envChan[0]->encEnvData.currentAmpResFF != + h_envChan[1]->encEnvData.currentAmpResFF) { + stereoMode = SBR_LEFT_RIGHT; + } + /* Extract envelope of current frame. */ diff --git a/libSBRenc/src/sbr_encoder.cpp b/libSBRenc/src/sbr_encoder.cpp index c1e083f..c3da072 100644 --- a/libSBRenc/src/sbr_encoder.cpp +++ b/libSBRenc/src/sbr_encoder.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -1450,8 +1450,6 @@ static INT initEnvChannel(HANDLE_SBR_CONFIG_DATA sbrConfigData, params->deltaTAcrossFrames, 0, 0)) return (1); - sbrConfigData->initAmpResFF = params->init_amp_res_FF; - if (FDKsbrEnc_InitSbrHuffmanTables(&hEnv->encEnvData, &hEnv->sbrCodeEnvelope, &hEnv->sbrCodeNoiseFloor, sbrHeaderData->sbr_amp_res)) @@ -1749,6 +1747,7 @@ static INT FDKsbrEnc_EnvInit(HANDLE_SBR_ELEMENT hSbrElement, hSbrElement->sbrHeaderData.sbr_data_extra = 1; hSbrElement->sbrHeaderData.sbr_amp_res = (AMP_RES)params->amp_res; + hSbrElement->sbrConfigData.initAmpResFF = params->init_amp_res_FF; /* header_extra_1 */ hSbrElement->sbrHeaderData.freqScale = params->freqScale; From f89d1d0a4e3dc2cf291f31e2420d3cb1625f1857 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 10 Dec 2020 18:32:03 +0100 Subject: [PATCH 26/78] Adjust VBR mode depending on given peak bitrate and fix crash recovery usage. Operating the FDK encoder in A2DP with variable bitrate mode configuration resulted in unexpected encoder return value AACENC_ENCODE_ERROR. Due to peak bitrate restriction the encoder quite often runs into requantization. In case the bitrate constraint is not fulfilled, the so-called crash recovery is used as final emergency step. The crash recovery reduces the overall bit consumption considering the given number of bits to be saved. The bit difference is extracted from audio element structures. In VBR mode the element wise bit consumption state was not updated since there is typically no bitrate limitation required. The patch solves the choppy audio problems and increases audio quality for AAC VBR encoding. The changes in FDKaacEnc_QCMain() ensure that audio element bit info is always updated. This is achieved by always calling FDKaacEnc_BitResRedistribution() and FDKaacEnc_prepareBitDistribution() with maxBitsPerFrame variable as total bits parameter. Furthermore, VBR assumes a certain target bitrate which is used for internal configuration and limitations. In case the peak bitrate parameter is less than the VBR mode target bitrate the maximum of both bitrate configurations was used. The function FDKaacEnc_AdjustVBRBitrateMode() is added to adjust the encoder internal VBR mode to a desired target bitrate less than given peak bitrate. It is possible that the peak bitrate is very close to the desired target bitrate. The virtual available bitreservoir is quite low and the encoder would run quite often into requantization with needless audio quality reduction. In such a configuration, it is a better choice to use the CBR targeted threshold adaption to avoid audio quality reduction. In FDKaacEnc_Initialize(), there was already a bitResMode selection depending on available bitreservoir for CBR. This selection will now also be used for VBR. In case the bitResMode is AACENC_BR_MODE_FULL and VBR mode is selected, the VBR threshold adaption is used. Otherwise, CBR threshold adaption strategy is used and therefore, no unnecessary fill bits are written. Bug: 161400526 Test: see bug Change-Id: I1865f817180150da6add2623a64f1a102622784a --- libAACenc/src/aacenc.cpp | 48 ++++++++++++++++++++++++++++++++---- libAACenc/src/aacenc.h | 15 ++++++++++- libAACenc/src/aacenc_lib.cpp | 7 ++++++ libAACenc/src/qc_main.cpp | 47 ++++++++++++++--------------------- 4 files changed, 82 insertions(+), 35 deletions(-) diff --git a/libAACenc/src/aacenc.cpp b/libAACenc/src/aacenc.cpp index b6f733d..1af8a2e 100644 --- a/libAACenc/src/aacenc.cpp +++ b/libAACenc/src/aacenc.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -245,6 +245,46 @@ INT FDKaacEnc_GetVBRBitrate(AACENC_BITRATE_MODE bitrateMode, return bitrate; } +/*----------------------------------------------------------------------------- + + functionname: FDKaacEnc_AdjustVBRBitrateMode + description: Adjust bitrate mode to given bitrate parameter + input params: int vbrQuality (VBR0, VBR1, VBR2) + bitrate + channelMode + returns: vbr bitrate mode + + ------------------------------------------------------------------------------*/ +AACENC_BITRATE_MODE FDKaacEnc_AdjustVBRBitrateMode( + AACENC_BITRATE_MODE bitrateMode, INT bitrate, CHANNEL_MODE channelMode) { + AACENC_BITRATE_MODE newBitrateMode = bitrateMode; + + if (bitrate != -1) { + const INT monoStereoMode = + (FDKaacEnc_GetMonoStereoMode(channelMode) == EL_MODE_STEREO) ? 1 : 0; + const INT nChannelsEff = + FDKaacEnc_GetChannelModeConfiguration(channelMode)->nChannelsEff; + newBitrateMode = AACENC_BR_MODE_INVALID; + + for (int idx = (int)(sizeof(configTabVBR) / sizeof(*configTabVBR)) - 1; + idx >= 0; idx--) { + if (bitrate >= + configTabVBR[idx].chanBitrate[monoStereoMode] * nChannelsEff) { + if (configTabVBR[idx].chanBitrate[monoStereoMode] * nChannelsEff < + FDKaacEnc_GetVBRBitrate(bitrateMode, channelMode)) { + newBitrateMode = configTabVBR[idx].bitrateMode; + } else { + newBitrateMode = bitrateMode; + } + break; + } + } + } + + return AACENC_BR_MODE_IS_VBR(newBitrateMode) ? newBitrateMode + : AACENC_BR_MODE_INVALID; +} + /** * \brief Convert encoder bitreservoir value for transport library. * @@ -397,7 +437,6 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize( FIXP_DBL mbfac, bw_ratio; QC_INIT qcInit; INT averageBitsPerFrame = 0; - int bitresMin = 0; /* the bitreservoir is always big for AAC-LC */ const CHANNEL_MODE prevChannelMode = hAacEnc->encoderMode; if (config == NULL) return AAC_ENC_INVALID_HANDLE; @@ -553,7 +592,6 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize( qcInit.minBits = fixMin(qcInit.minBits, averageBitsPerFrame & ~7); } else { INT bitreservoir = -1; /* default bitreservoir size*/ - bitresMin = BITRES_MIN; if (isLowDelay(config->audioObjectType)) { INT brPerChannel = config->bitRate / config->nChannels; brPerChannel = fMin(BITRATE_MAX_LD, fMax(BITRATE_MIN_LD, brPerChannel)); @@ -567,7 +605,6 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize( bitreservoir = fMultI(slope, (INT)(BITRES_MAX_LD - BITRES_MIN_LD)) + BITRES_MIN_LD; /* interpolate */ bitreservoir = bitreservoir & ~7; /* align to bytes */ - bitresMin = BITRES_MIN_LD; } int maxBitres; @@ -604,7 +641,8 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize( qcInit.nSubFrames = config->nSubFrames; qcInit.padding.paddingRest = config->sampleRate; - if (qcInit.maxBits - qcInit.averageBits >= bitresMin * config->nChannels) { + if (qcInit.maxBits - qcInit.averageBits >= + ((qcInit.isLowDelay) ? BITRES_MIN_LD : BITRES_MIN) * config->nChannels) { qcInit.bitResMode = AACENC_BR_MODE_FULL; /* full bitreservoir */ } else if (qcInit.maxBits > qcInit.averageBits) { qcInit.bitResMode = AACENC_BR_MODE_REDUCED; /* reduced bitreservoir */ diff --git a/libAACenc/src/aacenc.h b/libAACenc/src/aacenc.h index 0e0d8c1..b7e0ef2 100644 --- a/libAACenc/src/aacenc.h +++ b/libAACenc/src/aacenc.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -333,6 +333,19 @@ INT FDKaacEnc_GetBitReservoirState(const HANDLE_AAC_ENC hAacEncoder); INT FDKaacEnc_GetVBRBitrate(AACENC_BITRATE_MODE bitrateMode, CHANNEL_MODE channelMode); +/*----------------------------------------------------------------------------- + + functionname: FDKaacEnc_AdjustVBRBitrateMode + description: Adjust bitrate mode to given bitrate parameter + input params: int vbrQuality (VBR0, VBR1, VBR2) + bitrate + channelMode + returns: vbr bitrate mode + + ------------------------------------------------------------------------------*/ +AACENC_BITRATE_MODE FDKaacEnc_AdjustVBRBitrateMode( + AACENC_BITRATE_MODE bitrateMode, INT bitrate, CHANNEL_MODE channelMode); + /*----------------------------------------------------------------------------- functionname: FDKaacEnc_AacInitDefaultConfig diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp index 2c2010f..d840ff0 100644 --- a/libAACenc/src/aacenc_lib.cpp +++ b/libAACenc/src/aacenc_lib.cpp @@ -1028,6 +1028,13 @@ static AACENC_ERROR FDKaacEnc_AdjustEncSettings(HANDLE_AACENCODER hAacEncoder, case AACENC_BR_MODE_VBR_3: case AACENC_BR_MODE_VBR_4: case AACENC_BR_MODE_VBR_5: + /* Adjust bitrate mode in case given peak bitrate is lower than expected + * VBR bitrate. */ + if ((INT)config->userPeakBitrate != -1) { + hAacConfig->bitrateMode = FDKaacEnc_AdjustVBRBitrateMode( + hAacConfig->bitrateMode, config->userPeakBitrate, + hAacConfig->channelMode); + } /* Get bitrate in VBR configuration */ /* In VBR mode; SBR-modul depends on bitrate, core encoder on bitrateMode. */ diff --git a/libAACenc/src/qc_main.cpp b/libAACenc/src/qc_main.cpp index bcfaa23..9a42550 100644 --- a/libAACenc/src/qc_main.cpp +++ b/libAACenc/src/qc_main.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -373,13 +373,8 @@ AAC_ENCODER_ERROR FDKaacEnc_QCInit(QC_STATE* hQC, struct QC_INIT* init, hQC->invQuant = init->invQuant; hQC->maxIterations = init->maxIterations; - if (isConstantBitrateMode(hQC->bitrateMode)) { - /* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir - */ - hQC->bitResMode = init->bitResMode; - } else { - hQC->bitResMode = AACENC_BR_MODE_FULL; /* full bitreservoir */ - } + /* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir */ + hQC->bitResMode = init->bitResMode; hQC->padding.paddingRest = init->padding.paddingRest; @@ -800,10 +795,15 @@ AAC_ENCODER_ERROR FDKaacEnc_QCMain(QC_STATE* RESTRICT hQC, PSY_OUT** psyOut, INT avgTotalDynBits = 0; /* maximal allowed dynamic bits for all frames */ INT totalAvailableBits = 0; INT nSubFrames = 1; + const INT isCBRAdjustment = (isConstantBitrateMode(hQC->bitrateMode) || + (hQC->bitResMode != AACENC_BR_MODE_FULL)) + ? 1 + : 0; /*-------------------------------------------- */ /* redistribute total bitreservoir to elements */ - ErrorStatus = FDKaacEnc_BitResRedistribution(hQC, cm, avgTotalBits); + ErrorStatus = FDKaacEnc_BitResRedistribution( + hQC, cm, (isCBRAdjustment == 0) ? hQC->maxBitsPerFrame : avgTotalBits); if (ErrorStatus != AAC_ENC_OK) { return ErrorStatus; } @@ -831,33 +831,22 @@ AAC_ENCODER_ERROR FDKaacEnc_QCMain(QC_STATE* RESTRICT hQC, PSY_OUT** psyOut, /*-------------------------------------------- */ /*-------------------------------------------- */ - if (isConstantBitrateMode(hQC->bitrateMode)) { - /* calc granted dynamic bits for sub frame and - distribute it to each element */ - ErrorStatus = FDKaacEnc_prepareBitDistribution( - hQC, psyOut, qcOut, cm, qcElement, avgTotalBits, &totalAvailableBits, - &avgTotalDynBits); + /* calc granted dynamic bits for sub frame and + distribute it to each element */ + ErrorStatus = FDKaacEnc_prepareBitDistribution( + hQC, psyOut, qcOut, cm, qcElement, + (isCBRAdjustment == 0) ? hQC->maxBitsPerFrame : avgTotalBits, + &totalAvailableBits, &avgTotalDynBits); - if (ErrorStatus != AAC_ENC_OK) { - return ErrorStatus; - } - } else { - qcOut[0]->grantedDynBits = - ((hQC->maxBitsPerFrame - (hQC->globHdrBits)) & ~7) - - (qcOut[0]->globalExtBits + qcOut[0]->staticBits + - qcOut[0]->elementExtBits); - qcOut[0]->maxDynBits = qcOut[0]->grantedDynBits; - - totalAvailableBits = hQC->maxBitsPerFrame; - avgTotalDynBits = 0; + if (ErrorStatus != AAC_ENC_OK) { + return ErrorStatus; } /* for ( all sub frames ) ... */ for (c = 0; c < nSubFrames; c++) { /* for CBR and VBR mode */ FDKaacEnc_AdjustThresholds(hQC->hAdjThr, qcElement[c], qcOut[c], - psyOut[c]->psyOutElement, - isConstantBitrateMode(hQC->bitrateMode), cm); + psyOut[c]->psyOutElement, isCBRAdjustment, cm); } /* -end- sub frame counter */ From 614b9f005a6b25834833a89ee20e05bc3886bea9 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:50:10 +0200 Subject: [PATCH 27/78] Prevent integer overflows in dualChannelFiltering() and eightChannelFiltering(). Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: Ic9217bbb3980807036ae6ae121e6ddb7cc1bce35 --- libFDK/src/FDK_hybrid.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/libFDK/src/FDK_hybrid.cpp b/libFDK/src/FDK_hybrid.cpp index 08d32a8..d208abd 100644 --- a/libFDK/src/FDK_hybrid.cpp +++ b/libFDK/src/FDK_hybrid.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -539,11 +539,11 @@ static void dualChannelFiltering(const FIXP_DBL *const pQmfReal, i6 = pQmfImag[pReadIdx[6]] >> 2; FDK_ASSERT((invert == 0) || (invert == 1)); - mHybridReal[0 + invert] = (r6 + r1) << 1; - mHybridImag[0 + invert] = (i6 + i1) << 1; + mHybridReal[0 + invert] = SATURATE_LEFT_SHIFT((r6 + r1), 1, DFRACT_BITS); + mHybridImag[0 + invert] = SATURATE_LEFT_SHIFT((i6 + i1), 1, DFRACT_BITS); - mHybridReal[1 - invert] = (r6 - r1) << 1; - mHybridImag[1 - invert] = (i6 - i1) << 1; + mHybridReal[1 - invert] = SATURATE_LEFT_SHIFT((r6 - r1), 1, DFRACT_BITS); + mHybridImag[1 - invert] = SATURATE_LEFT_SHIFT((i6 - i1), 1, DFRACT_BITS); } static void fourChannelFiltering(const FIXP_DBL *const pQmfReal, @@ -766,15 +766,15 @@ static void eightChannelFiltering(const FIXP_DBL *const pQmfReal, mHybridReal[3] = pfft[FFT_IDX_R(1)] << sc; mHybridImag[3] = pfft[FFT_IDX_I(1)] << sc; - mHybridReal[4] = pfft[FFT_IDX_R(2)] << sc; - mHybridReal[4] += pfft[FFT_IDX_R(5)] << sc; - mHybridImag[4] = pfft[FFT_IDX_I(2)] << sc; - mHybridImag[4] += pfft[FFT_IDX_I(5)] << sc; + mHybridReal[4] = SATURATE_LEFT_SHIFT( + (pfft[FFT_IDX_R(2)] + pfft[FFT_IDX_R(5)]), sc, DFRACT_BITS); + mHybridImag[4] = SATURATE_LEFT_SHIFT( + (pfft[FFT_IDX_I(2)] + pfft[FFT_IDX_I(5)]), sc, DFRACT_BITS); - mHybridReal[5] = pfft[FFT_IDX_R(3)] << sc; - mHybridReal[5] += pfft[FFT_IDX_R(4)] << sc; - mHybridImag[5] = pfft[FFT_IDX_I(3)] << sc; - mHybridImag[5] += pfft[FFT_IDX_I(4)] << sc; + mHybridReal[5] = SATURATE_LEFT_SHIFT( + (pfft[FFT_IDX_R(3)] + pfft[FFT_IDX_R(4)]), sc, DFRACT_BITS); + mHybridImag[5] = SATURATE_LEFT_SHIFT( + (pfft[FFT_IDX_I(3)] + pfft[FFT_IDX_I(4)]), sc, DFRACT_BITS); } else { for (k = 0; k < 8; k++) { mHybridReal[k] = pfft[FFT_IDX_R(k)] << sc; From 19c8cc495e97354dce2e8858f8830fca79318c80 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:52:56 +0200 Subject: [PATCH 28/78] Avoid integer overflow in dct_II(). Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I6c30c4dec3f85410c2748eb42d38f5eb72521ec5 --- libFDK/src/dct.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/libFDK/src/dct.cpp b/libFDK/src/dct.cpp index bd26736..35507b5 100644 --- a/libFDK/src/dct.cpp +++ b/libFDK/src/dct.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -305,9 +305,8 @@ void dct_II( { for (i = 0; i < M; i++) { - tmp[i] = pDat[2 * i] >> 1; /* dit_fft expects 1 bit scaled input values */ - tmp[L - 1 - i] = - pDat[2 * i + 1] >> 1; /* dit_fft expects 1 bit scaled input values */ + tmp[i] = pDat[2 * i] >> 2; + tmp[L - 1 - i] = pDat[2 * i + 1] >> 2; } } @@ -337,15 +336,14 @@ void dct_II( a1 = ((pTmp_0[0] >> 1) + (pTmp_1[0] >> 1)); a2 = ((pTmp_0[1] >> 1) - (pTmp_1[1] >> 1)); - cplxMultDiv2(&accu3, &accu4, (a1 + accu2), -(accu1 + a2), - sin_twiddle[i * inc]); - pDat[L - i] = accu4; - pDat[i] = accu3; + cplxMult(&accu3, &accu4, (accu1 + a2), (a1 + accu2), sin_twiddle[i * inc]); + pDat[L - i] = -accu3; + pDat[i] = accu4; - cplxMultDiv2(&accu3, &accu4, (a1 - accu2), -(accu1 - a2), - sin_twiddle[(M - i) * inc]); - pDat[M + i] = accu4; - pDat[M - i] = accu3; + cplxMult(&accu3, &accu4, (accu1 - a2), (a1 - accu2), + sin_twiddle[(M - i) * inc]); + pDat[M + i] = -accu3; + pDat[M - i] = accu4; /* Create index helper variables for (4*i)*inc indexed equivalent values of * short tables. */ @@ -356,12 +354,12 @@ void dct_II( } } - cplxMultDiv2(&accu1, &accu2, tmp[M], tmp[M + 1], sin_twiddle[(M / 2) * inc]); + cplxMult(&accu1, &accu2, tmp[M], tmp[M + 1], sin_twiddle[(M / 2) * inc]); pDat[L - (M / 2)] = accu2; pDat[M / 2] = accu1; - pDat[0] = (tmp[0] >> 1) + (tmp[1] >> 1); - pDat[M] = fMult(((tmp[0] >> 1) - (tmp[1] >> 1)), + pDat[0] = tmp[0] + tmp[1]; + pDat[M] = fMult(tmp[0] - tmp[1], sin_twiddle[M * inc].v.re); /* cos((PI/(2*L))*M); */ *pDat_e += 2; From ba54a5c0401141cea1a4570590432ff922ccf643 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:53:51 +0200 Subject: [PATCH 29/78] Limit smoothedNoise values to avoid integer overflows in adjustTimeSlotHQ() and adjustTimeSlotHQ_GainAndNoise(). Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: Ib630d56a626ddd59a9155df38cda2011c3165346 --- libSBRdec/src/env_calc.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/libSBRdec/src/env_calc.cpp b/libSBRdec/src/env_calc.cpp index 0b2f651..ad5edfe 100644 --- a/libSBRdec/src/env_calc.cpp +++ b/libSBRdec/src/env_calc.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -1398,6 +1398,17 @@ void calculateSbrEnvelope( */ noise_e = (start_pos < no_cols) ? adj_e : final_e; + if (start_pos >= no_cols) { + int diff = h_sbr_cal_env->filtBufferNoise_e - noise_e; + if (diff > 0) { + int s = getScalefactor(h_sbr_cal_env->filtBufferNoise, noSubbands); + if (diff > s) { + final_e += diff - s; + noise_e = final_e; + } + } + } + /* Convert energies to amplitude levels */ @@ -2741,6 +2752,9 @@ static void adjustTimeSlotHQ_GainAndNoise( fMult(direct_ratio, noiseLevel[k]); } + smoothedNoise = fMax(fMin(smoothedNoise, (FIXP_DBL)(MAXVAL_DBL / 2)), + (FIXP_DBL)(MINVAL_DBL / 2)); + /* The next 2 multiplications constitute the actual envelope adjustment of the signal and should be carried out with full accuracy @@ -2930,6 +2944,9 @@ static void adjustTimeSlotHQ( fMult(direct_ratio, noiseLevel[k]); } + smoothedNoise = fMax(fMin(smoothedNoise, (FIXP_DBL)(MAXVAL_DBL / 2)), + (FIXP_DBL)(MINVAL_DBL / 2)); + /* The next 2 multiplications constitute the actual envelope adjustment of the signal and should be carried out with full accuracy From e916be37f24a118eb0663b53794389dc83af8e8d Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:54:10 +0200 Subject: [PATCH 30/78] Prevent integer overflow in subbandTPApply() energy update. Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I9ed8b33414907706808956cffad252052928c799 --- libSACdec/src/sac_stp.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libSACdec/src/sac_stp.cpp b/libSACdec/src/sac_stp.cpp index bb66277..b328c82 100644 --- a/libSACdec/src/sac_stp.cpp +++ b/libSACdec/src/sac_stp.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -369,15 +369,15 @@ SACDEC_ERROR subbandTPApply(spatialDec *self, const SPATIAL_BS_FRAME *frame) { hStpDec->update_old_ener = 1; for (ch = 0; ch < self->numInputChannels; ch++) { hStpDec->oldDryEnerLD64[ch] = - CalcLdData(hStpDec->runDryEner[ch] + ABS_THR__FDK); + CalcLdData(fAddSaturate(hStpDec->runDryEner[ch], ABS_THR__FDK)); } for (ch = 0; ch < self->numOutputChannels; ch++) { if (self->treeConfig == TREE_212) hStpDec->oldWetEnerLD64[ch] = - CalcLdData(hStpDec->runWetEner[ch] + ABS_THR__FDK); + CalcLdData(fAddSaturate(hStpDec->runWetEner[ch], ABS_THR__FDK)); else hStpDec->oldWetEnerLD64[ch] = - CalcLdData(hStpDec->runWetEner[ch] + ABS_THR2__FDK); + CalcLdData(fAddSaturate(hStpDec->runWetEner[ch], ABS_THR2__FDK)); } } else { hStpDec->update_old_ener++; From 87e01ef1e77105adda58a2a89e2179d43327266c Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:58:17 +0200 Subject: [PATCH 31/78] Check number of core channels and SAC decoder input channels to avoid a channel mismatch. Bug: 176246647 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: Ib8b6973e9c29e13b8ef33d7736be2b977928face --- libAACdec/src/aacdecoder_lib.cpp | 16 +++++++--------- libAACenc/src/aacenc_lib.cpp | 4 ++-- libMpegTPDec/include/tp_data.h | 4 ++-- libMpegTPDec/src/tpdec_asc.cpp | 8 ++++++-- libMpegTPEnc/include/tp_data.h | 4 ++-- libMpegTPEnc/src/tpenc_asc.cpp | 6 +++--- libSACdec/include/sac_dec_lib.h | 6 +++--- libSACdec/src/sac_dec.cpp | 14 ++++++++------ libSACdec/src/sac_dec_lib.cpp | 21 ++++++++++++++++++--- 9 files changed, 51 insertions(+), 32 deletions(-) diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index f5ce7e0..47e7496 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -385,21 +385,19 @@ static INT aacDecoder_SbrCallback( return errTp; } -static INT aacDecoder_SscCallback(void *handle, HANDLE_FDK_BITSTREAM hBs, - const AUDIO_OBJECT_TYPE coreCodec, - const INT samplingRate, const INT frameSize, - const INT stereoConfigIndex, - const INT coreSbrFrameLengthIndex, - const INT configBytes, const UCHAR configMode, - UCHAR *configChanged) { +static INT aacDecoder_SscCallback( + void *handle, HANDLE_FDK_BITSTREAM hBs, const AUDIO_OBJECT_TYPE coreCodec, + const INT samplingRate, const INT frameSize, const INT numChannels, + const INT stereoConfigIndex, const INT coreSbrFrameLengthIndex, + const INT configBytes, const UCHAR configMode, UCHAR *configChanged) { SACDEC_ERROR err; TRANSPORTDEC_ERROR errTp; HANDLE_AACDECODER hAacDecoder = (HANDLE_AACDECODER)handle; err = mpegSurroundDecoder_Config( (CMpegSurroundDecoder *)hAacDecoder->pMpegSurroundDecoder, hBs, coreCodec, - samplingRate, frameSize, stereoConfigIndex, coreSbrFrameLengthIndex, - configBytes, configMode, configChanged); + samplingRate, frameSize, numChannels, stereoConfigIndex, + coreSbrFrameLengthIndex, configBytes, configMode, configChanged); switch (err) { case MPS_UNSUPPORTED_CONFIG: diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp index d840ff0..b0d0454 100644 --- a/libAACenc/src/aacenc_lib.cpp +++ b/libAACenc/src/aacenc_lib.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -1242,7 +1242,7 @@ static INT aacenc_SbrCallback(void *self, HANDLE_FDK_BITSTREAM hBs, INT aacenc_SscCallback(void *self, HANDLE_FDK_BITSTREAM hBs, const AUDIO_OBJECT_TYPE coreCodec, const INT samplingRate, const INT frameSize, - const INT stereoConfigIndex, + const INT numChannels, const INT stereoConfigIndex, const INT coreSbrFrameLengthIndex, const INT configBytes, const UCHAR configMode, UCHAR *configChanged) { HANDLE_AACENCODER hAacEncoder = (HANDLE_AACENCODER)self; diff --git a/libMpegTPDec/include/tp_data.h b/libMpegTPDec/include/tp_data.h index b015332..b63087a 100644 --- a/libMpegTPDec/include/tp_data.h +++ b/libMpegTPDec/include/tp_data.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -368,7 +368,7 @@ typedef INT (*cbCtrlCFGChange_t)(void *, const CCtrlCFGChange *); typedef INT (*cbSsc_t)(void *, HANDLE_FDK_BITSTREAM, const AUDIO_OBJECT_TYPE coreCodec, const INT samplingRate, const INT frameSize, - const INT stereoConfigIndex, + const INT numChannels, const INT stereoConfigIndex, const INT coreSbrFrameLengthIndex, const INT configBytes, const UCHAR configMode, UCHAR *configChanged); diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp index 82f840e..4960d3f 100644 --- a/libMpegTPDec/src/tpdec_asc.cpp +++ b/libMpegTPDec/src/tpdec_asc.cpp @@ -1415,7 +1415,7 @@ static TRANSPORTDEC_ERROR EldSpecificConfig_Parse(CSAudioSpecificConfig *asc, cb->cbSscData, hBs, asc->m_aot, asc->m_samplingFrequency << esc->m_sbrSamplingRate, asc->m_samplesPerFrame << esc->m_sbrSamplingRate, - 1, /* stereoConfigIndex */ + asc->m_channelConfiguration, 1, /* stereoConfigIndex */ -1, /* nTimeSlots: read from bitstream */ eldExtLen, asc->configMode, &asc->SacConfigChanged); if (ErrorStatus != TRANSPORTDEC_OK) { @@ -1827,6 +1827,8 @@ static TRANSPORTDEC_ERROR UsacRsv60DecoderConfig_Parse( /* Mps212Config() ISO/IEC FDIS 23003-3 */ if (cb->cbSsc(cb->cbSscData, hBs, asc->m_aot, asc->m_extensionSamplingFrequency, samplesPerFrame, + 1, /* only downmix channels (residual channels are + not counted) */ usc->element[i].m_stereoConfigIndex, usc->m_coreSbrFrameLengthIndex, 0, /* don't know the length */ @@ -2219,7 +2221,7 @@ TRANSPORTDEC_ERROR AudioSpecificConfig_Parse( case AOT_MPEGS: if (cb->cbSsc != NULL) { if (cb->cbSsc(cb->cbSscData, bs, self->m_aot, self->m_samplingFrequency, - self->m_samplesPerFrame, 1, + self->m_samplesPerFrame, self->m_channelConfiguration, 1, -1, /* nTimeSlots: read from bitstream */ 0, /* don't know the length */ self->configMode, &self->SacConfigChanged)) { @@ -2415,6 +2417,8 @@ static TRANSPORTDEC_ERROR Drm_xHEAACDecoderConfig( cb->cbSscData, hBs, AOT_DRM_USAC, /* syntax differs from MPEG Mps212Config() */ asc->m_extensionSamplingFrequency, samplesPerFrame, + 1, /* only downmix channels (residual channels are not + counted) */ usc->element[elemIdx].m_stereoConfigIndex, usc->m_coreSbrFrameLengthIndex, 0, /* don't know the length */ asc->configMode, &asc->SacConfigChanged); diff --git a/libMpegTPEnc/include/tp_data.h b/libMpegTPEnc/include/tp_data.h index 00de356..464c485 100644 --- a/libMpegTPEnc/include/tp_data.h +++ b/libMpegTPEnc/include/tp_data.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -368,7 +368,7 @@ typedef INT (*cbCtrlCFGChange_t)(void *, const CCtrlCFGChange *); typedef INT (*cbSsc_t)(void *, HANDLE_FDK_BITSTREAM, const AUDIO_OBJECT_TYPE coreCodec, const INT samplingRate, const INT frameSize, - const INT stereoConfigIndex, + const INT numChannels, const INT stereoConfigIndex, const INT coreSbrFrameLengthIndex, const INT configBytes, const UCHAR configMode, UCHAR *configChanged); diff --git a/libMpegTPEnc/src/tpenc_asc.cpp b/libMpegTPEnc/src/tpenc_asc.cpp index 0b484a0..9591ba8 100644 --- a/libMpegTPEnc/src/tpenc_asc.cpp +++ b/libMpegTPEnc/src/tpenc_asc.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -795,7 +795,7 @@ static int transportEnc_writeELDSpecificConfig(HANDLE_FDK_BITSTREAM hBs, const INT eldExtLen = (cb->cbSsc(cb->cbSscData, NULL, config->aot, config->extSamplingRate, 0, - 0, 0, 0, 0, NULL) + + 0, 0, 0, 0, 0, NULL) + 7) >> 3; INT cnt = eldExtLen; @@ -818,7 +818,7 @@ static int transportEnc_writeELDSpecificConfig(HANDLE_FDK_BITSTREAM hBs, } cb->cbSsc(cb->cbSscData, hBs, config->aot, config->extSamplingRate, 0, 0, 0, - 0, 0, NULL); + 0, 0, 0, NULL); } if (config->downscaleSamplingRate != 0 && diff --git a/libSACdec/include/sac_dec_lib.h b/libSACdec/include/sac_dec_lib.h index 1827504..5aad4e0 100644 --- a/libSACdec/include/sac_dec_lib.h +++ b/libSACdec/include/sac_dec_lib.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -316,8 +316,8 @@ SACDEC_ERROR mpegSurroundDecoder_Init( SACDEC_ERROR mpegSurroundDecoder_Config( CMpegSurroundDecoder *pMpegSurroundDecoder, HANDLE_FDK_BITSTREAM hBs, AUDIO_OBJECT_TYPE coreCodec, INT samplingRate, INT frameSize, - INT stereoConfigIndex, INT coreSbrFrameLengthIndex, INT configBytes, - const UCHAR configMode, UCHAR *configChanged); + INT numChannels, INT stereoConfigIndex, INT coreSbrFrameLengthIndex, + INT configBytes, const UCHAR configMode, UCHAR *configChanged); SACDEC_ERROR mpegSurroundDecoder_ConfigureQmfDomain( diff --git a/libSACdec/src/sac_dec.cpp b/libSACdec/src/sac_dec.cpp index a7b50df..649c18d 100644 --- a/libSACdec/src/sac_dec.cpp +++ b/libSACdec/src/sac_dec.cpp @@ -1182,15 +1182,17 @@ static SACDEC_ERROR SpatialDecApplyParameterSets( self->bShareDelayWithSBR = 0; /* We got no hybrid delay */ else self->bShareDelayWithSBR = 1; - SpatialDecFeedQMF(self, qmfInDataReal, qmfInDataImag, ts_io, bypassMode, - self->qmfInputReal__FDK, self->qmfInputImag__FDK, - self->numInputChannels); + SpatialDecFeedQMF( + self, qmfInDataReal, qmfInDataImag, ts_io, bypassMode, + self->qmfInputReal__FDK, self->qmfInputImag__FDK, + (bypassMode) ? numInputChannels : self->numInputChannels); break; case INPUTMODE_TIME: self->bShareDelayWithSBR = 0; - SpatialDecQMFAnalysis(self, inData, ts_io, bypassMode, - self->qmfInputReal__FDK, self->qmfInputImag__FDK, - self->numInputChannels); + SpatialDecQMFAnalysis( + self, inData, ts_io, bypassMode, self->qmfInputReal__FDK, + self->qmfInputImag__FDK, + (bypassMode) ? numInputChannels : self->numInputChannels); break; default: break; diff --git a/libSACdec/src/sac_dec_lib.cpp b/libSACdec/src/sac_dec_lib.cpp index 856a923..da19bb8 100644 --- a/libSACdec/src/sac_dec_lib.cpp +++ b/libSACdec/src/sac_dec_lib.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -700,9 +700,10 @@ bail: SACDEC_ERROR mpegSurroundDecoder_Config( CMpegSurroundDecoder *pMpegSurroundDecoder, HANDLE_FDK_BITSTREAM hBs, AUDIO_OBJECT_TYPE coreCodec, INT samplingRate, INT frameSize, - INT stereoConfigIndex, INT coreSbrFrameLengthIndex, INT configBytes, - const UCHAR configMode, UCHAR *configChanged) { + INT numChannels, INT stereoConfigIndex, INT coreSbrFrameLengthIndex, + INT configBytes, const UCHAR configMode, UCHAR *configChanged) { SACDEC_ERROR err = MPS_OK; + INT nInputChannels; SPATIAL_SPECIFIC_CONFIG spatialSpecificConfig; SPATIAL_SPECIFIC_CONFIG *pSsc = &pMpegSurroundDecoder->spatialSpecificConfigBackup; @@ -716,12 +717,18 @@ SACDEC_ERROR mpegSurroundDecoder_Config( err = SpatialDecParseMps212Config( hBs, &spatialSpecificConfig, samplingRate, coreCodec, stereoConfigIndex, coreSbrFrameLengthIndex); + nInputChannels = spatialSpecificConfig.nInputChannels; pSsc = &spatialSpecificConfig; } else { err = SpatialDecParseMps212Config( hBs, &pMpegSurroundDecoder->spatialSpecificConfigBackup, samplingRate, coreCodec, stereoConfigIndex, coreSbrFrameLengthIndex); + nInputChannels = + pMpegSurroundDecoder->spatialSpecificConfigBackup.nInputChannels; + } + if ((err == MPS_OK) && (numChannels != nInputChannels)) { + err = MPS_PARSE_ERROR; } break; case AOT_ER_AAC_ELD: @@ -731,11 +738,19 @@ SACDEC_ERROR mpegSurroundDecoder_Config( * into temporarily allocated structure */ err = SpatialDecParseSpecificConfig(hBs, &spatialSpecificConfig, configBytes, coreCodec); + nInputChannels = spatialSpecificConfig.nInputChannels; pSsc = &spatialSpecificConfig; } else { err = SpatialDecParseSpecificConfig( hBs, &pMpegSurroundDecoder->spatialSpecificConfigBackup, configBytes, coreCodec); + nInputChannels = + pMpegSurroundDecoder->spatialSpecificConfigBackup.nInputChannels; + } + /* check number of channels for channel_configuration > 0 */ + if ((err == MPS_OK) && (numChannels > 0) && + (numChannels != nInputChannels)) { + err = MPS_PARSE_ERROR; } break; default: From a1a8f69b14d6754aab8302fdad28976f17e0ac9e Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:58:01 +0200 Subject: [PATCH 32/78] Revise bypass mode in SpatialDecApplyParameterSets() to prevent an assert in fDivNorm(). Bug: 176246647 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I198747688f1677b82f27a17a2fcf40229c92b1da --- libSACdec/src/sac_dec.cpp | 61 ++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/libSACdec/src/sac_dec.cpp b/libSACdec/src/sac_dec.cpp index 649c18d..a26e251 100644 --- a/libSACdec/src/sac_dec.cpp +++ b/libSACdec/src/sac_dec.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -1098,6 +1098,28 @@ static void SpatialDecApplyBypass(spatialDec *self, FIXP_DBL **hybInputReal, } } +/** + * \brief Set internal error and reset error status + * + * \param self spatialDec handle. + * \param bypassMode pointer to bypassMode. + * \param err error status. + * + * \return error status. + */ +static SACDEC_ERROR SpatialDecSetInternalError(spatialDec *self, + int *bypassMode, + SACDEC_ERROR err) { + *bypassMode = 1; + + if (self->errInt == MPS_OK) { + /* store internal error before it gets overwritten */ + self->errInt = err; + } + + return MPS_OK; +} + /******************************************************************************* Functionname: SpatialDecApplyParameterSets ******************************************************************************* @@ -1118,7 +1140,7 @@ static SACDEC_ERROR SpatialDecApplyParameterSets( const FDK_channelMapDescr *const mapDescr) { SACDEC_ERROR err = MPS_OK; - FIXP_SGL alpha; + FIXP_SGL alpha = FL2FXCONST_SGL(0.0); int ts; int ch; @@ -1141,20 +1163,22 @@ static SACDEC_ERROR SpatialDecApplyParameterSets( ts++, ts_io++) { int currSlot = frame->paramSlot[ps]; + err = (currSlot < ts) ? MPS_WRONG_PARAMETERSETS : MPS_OK; + if (err != MPS_OK) { + err = SpatialDecSetInternalError(self, &bypassMode, err); + } + /* * Get new parameter set */ if (ts == prevSlot + 1) { - err = SpatialDecCalculateM1andM2(self, ps, - frame); /* input: ottCLD, ottICC, ... */ - /* output: M1param(Real/Imag), M2(Real/Imag) */ - if (err != MPS_OK) { - bypassMode = 1; - if (self->errInt == MPS_OK) { - /* store internal error befor it gets overwritten */ - self->errInt = err; + if (bypassMode == 0) { + err = SpatialDecCalculateM1andM2( + self, ps, frame); /* input: ottCLD, ottICC, ... */ + /* output: M1param(Real/Imag), M2(Real/Imag) */ + if (err != MPS_OK) { + err = SpatialDecSetInternalError(self, &bypassMode, err); } - err = MPS_OK; } if ((ps == 0) && (self->bOverwriteM1M2prev != 0)) { @@ -1168,13 +1192,16 @@ static SACDEC_ERROR SpatialDecApplyParameterSets( self->bOverwriteM1M2prev = 0; } - SpatialDecSmoothM1andM2( - self, frame, - ps); /* input: M1param(Real/Imag)(Prev), M2(Real/Imag)(Prev) */ - /* output: M1param(Real/Imag), M2(Real/Imag) */ + if (bypassMode == 0) { + SpatialDecSmoothM1andM2( + self, frame, + ps); /* input: M1param(Real/Imag)(Prev), M2(Real/Imag)(Prev) */ + } /* output: M1param(Real/Imag), M2(Real/Imag) */ } - alpha = FX_DBL2FX_SGL(fDivNorm(ts - prevSlot, currSlot - prevSlot)); + if (bypassMode == 0) { + alpha = FX_DBL2FX_SGL(fDivNorm(ts - prevSlot, currSlot - prevSlot)); + } switch (mode) { case INPUTMODE_QMF_SBR: @@ -1362,7 +1389,7 @@ static SACDEC_ERROR SpatialDecApplyParameterSets( } /* !self->tempShapeConfig == 1 */ } /* !bypassMode */ - if (self->phaseCoding == 1) { + if ((self->phaseCoding == 1) && (bypassMode == 0)) { /* only if bsPhaseCoding == 1 and bsResidualCoding == 0 */ SpatialDecApplyPhase( From b93f896f37d9fe0a09c8233459b3403c699eff2e Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:57:46 +0200 Subject: [PATCH 33/78] Improve decoder robustness by storing flags and elFlags temporarily. Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I6aaeef87e1f2ce5d5031f088b8c57e6f5806929d --- libAACdec/src/aacdecoder.cpp | 135 +++++++++++++++++++++-------------- 1 file changed, 82 insertions(+), 53 deletions(-) diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp index 965631b..6b5f873 100644 --- a/libAACdec/src/aacdecoder.cpp +++ b/libAACdec/src/aacdecoder.cpp @@ -1396,6 +1396,31 @@ static void CAacDecoder_DeInit(HANDLE_AACDECODER self, self->samplingRateInfo[subStreamIndex].samplingRate = 0; } +/*! + * \brief CAacDecoder_AcceptFlags Accept flags and element flags + * + * \param self [o] handle to AACDECODER structure + * \param asc [i] handle to ASC structure + * \param flags [i] flags + * \param elFlags [i] pointer to element flags + * \param streamIndex [i] stream index + * \param elementOffset [i] element offset + * + * \return void + */ +static void CAacDecoder_AcceptFlags(HANDLE_AACDECODER self, + const CSAudioSpecificConfig *asc, + UINT flags, UINT *elFlags, int streamIndex, + int elementOffset) { + { + FDKmemcpy( + self->elFlags, elFlags, + sizeof(*elFlags) * (3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1)); + } + + self->flags[streamIndex] = flags; +} + /*! * \brief CAacDecoder_CtrlCFGChange Set config change parameters. * @@ -1493,6 +1518,9 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, const int streamIndex = 0; INT flushChannels = 0; + UINT flags; + UINT elFlags[(3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1)]; + if (!self) return AAC_DEC_INVALID_HANDLE; UCHAR downscaleFactor = self->downscaleFactor; @@ -1649,8 +1677,8 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, } /* Set syntax flags */ - self->flags[streamIndex] = 0; - { FDKmemclear(self->elFlags, sizeof(self->elFlags)); } + flags = 0; + { FDKmemclear(elFlags, sizeof(elFlags)); } if ((asc->m_channelConfiguration > 0) || IS_USAC(asc->m_aot)) { if (IS_USAC(asc->m_aot)) { @@ -1700,31 +1728,30 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, } } - self->elFlags[el] |= - (asc->m_sc.m_usacConfig.element[_el].m_noiseFilling) - ? AC_EL_USAC_NOISE - : 0; - self->elFlags[el] |= + elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].m_noiseFilling) + ? AC_EL_USAC_NOISE + : 0; + elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].m_stereoConfigIndex > 0) ? AC_EL_USAC_MPS212 : 0; - self->elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].m_interTes) - ? AC_EL_USAC_ITES - : 0; - self->elFlags[el] |= + elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].m_interTes) + ? AC_EL_USAC_ITES + : 0; + elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].m_pvc) ? AC_EL_USAC_PVC : 0; - self->elFlags[el] |= + elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].usacElementType == ID_USAC_LFE) ? AC_EL_USAC_LFE : 0; - self->elFlags[el] |= + elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].usacElementType == ID_USAC_LFE) ? AC_EL_LFE : 0; if ((asc->m_sc.m_usacConfig.element[_el].usacElementType == ID_USAC_CPE) && ((self->usacStereoConfigIndex[el] == 0))) { - self->elFlags[el] |= AC_EL_USAC_CP_POSSIBLE; + elFlags[el] |= AC_EL_USAC_CP_POSSIBLE; } } @@ -1838,8 +1865,8 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, if (configMode & AC_CM_ALLOC_MEM) { self->streamInfo.extSamplingRate = asc->m_extensionSamplingFrequency; } - self->flags[streamIndex] |= (asc->m_sbrPresentFlag) ? AC_SBR_PRESENT : 0; - self->flags[streamIndex] |= (asc->m_psPresentFlag) ? AC_PS_PRESENT : 0; + flags |= (asc->m_sbrPresentFlag) ? AC_SBR_PRESENT : 0; + flags |= (asc->m_psPresentFlag) ? AC_PS_PRESENT : 0; if (asc->m_sbrPresentFlag) { self->sbrEnabled = 1; self->sbrEnabledPrev = 1; @@ -1865,51 +1892,47 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, } /* --------- vcb11 ------------ */ - self->flags[streamIndex] |= (asc->m_vcb11Flag) ? AC_ER_VCB11 : 0; + flags |= (asc->m_vcb11Flag) ? AC_ER_VCB11 : 0; /* ---------- rvlc ------------ */ - self->flags[streamIndex] |= (asc->m_rvlcFlag) ? AC_ER_RVLC : 0; + flags |= (asc->m_rvlcFlag) ? AC_ER_RVLC : 0; /* ----------- hcr ------------ */ - self->flags[streamIndex] |= (asc->m_hcrFlag) ? AC_ER_HCR : 0; + flags |= (asc->m_hcrFlag) ? AC_ER_HCR : 0; if (asc->m_aot == AOT_ER_AAC_ELD) { self->mpsEnableCurr = 0; - self->flags[streamIndex] |= AC_ELD; - self->flags[streamIndex] |= - (asc->m_sbrPresentFlag) - ? AC_SBR_PRESENT - : 0; /* Need to set the SBR flag for backward-compatibility - reasons. Even if SBR is not supported. */ - self->flags[streamIndex] |= - (asc->m_sc.m_eldSpecificConfig.m_sbrCrcFlag) ? AC_SBRCRC : 0; - self->flags[streamIndex] |= - (asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign) ? AC_MPS_PRESENT - : 0; + flags |= AC_ELD; + flags |= (asc->m_sbrPresentFlag) + ? AC_SBR_PRESENT + : 0; /* Need to set the SBR flag for backward-compatibility + reasons. Even if SBR is not supported. */ + flags |= (asc->m_sc.m_eldSpecificConfig.m_sbrCrcFlag) ? AC_SBRCRC : 0; + flags |= (asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign) + ? AC_MPS_PRESENT + : 0; if (self->mpsApplicable) { self->mpsEnableCurr = asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign; } } - self->flags[streamIndex] |= (asc->m_aot == AOT_ER_AAC_LD) ? AC_LD : 0; - self->flags[streamIndex] |= (asc->m_epConfig >= 0) ? AC_ER : 0; + flags |= (asc->m_aot == AOT_ER_AAC_LD) ? AC_LD : 0; + flags |= (asc->m_epConfig >= 0) ? AC_ER : 0; if (asc->m_aot == AOT_USAC) { - self->flags[streamIndex] |= AC_USAC; - self->flags[streamIndex] |= - (asc->m_sc.m_usacConfig.element[0].m_stereoConfigIndex > 0) - ? AC_MPS_PRESENT - : 0; + flags |= AC_USAC; + flags |= (asc->m_sc.m_usacConfig.element[0].m_stereoConfigIndex > 0) + ? AC_MPS_PRESENT + : 0; } if (asc->m_aot == AOT_DRM_AAC) { - self->flags[streamIndex] |= AC_DRM | AC_SBRCRC | AC_SCALABLE; + flags |= AC_DRM | AC_SBRCRC | AC_SCALABLE; } if (asc->m_aot == AOT_DRM_SURROUND) { - self->flags[streamIndex] |= - AC_DRM | AC_SBRCRC | AC_SCALABLE | AC_MPS_PRESENT; + flags |= AC_DRM | AC_SBRCRC | AC_SCALABLE | AC_MPS_PRESENT; FDK_ASSERT(!asc->m_psPresentFlag); } if ((asc->m_aot == AOT_AAC_SCAL) || (asc->m_aot == AOT_ER_AAC_SCAL)) { - self->flags[streamIndex] |= AC_SCALABLE; + flags |= AC_SCALABLE; } if ((asc->m_epConfig >= 0) && (asc->m_channelConfiguration <= 0)) { @@ -1960,6 +1983,10 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, if (ascChanged != 0) { *configChanged = 1; } + + CAacDecoder_AcceptFlags(self, asc, flags, elFlags, streamIndex, + elementOffset); + return err; } @@ -1988,7 +2015,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, } if (usacStereoConfigIndex == 3) { - self->flags[streamIndex] |= AC_USAC_SCFGI3; + flags |= AC_USAC_SCFGI3; } } break; @@ -2069,14 +2096,14 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, ch = aacChannelsOffset; int _numElements; _numElements = (((8)) + (8)); - if (self->flags[streamIndex] & (AC_RSV603DA | AC_USAC)) { + if (flags & (AC_RSV603DA | AC_USAC)) { _numElements = (int)asc->m_sc.m_usacConfig.m_usacNumElements; } for (int _el = 0; _el < _numElements; _el++) { int el_channels = 0; int el = elementOffset + _el; - if (self->flags[streamIndex] & + if (flags & (AC_ER | AC_LD | AC_ELD | AC_RSV603DA | AC_USAC | AC_RSVD50)) { if (ch >= ascChannels) { break; @@ -2176,15 +2203,14 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, if (self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer == NULL) { goto bail; } - if (self->flags[streamIndex] & - (AC_USAC | AC_RSVD50 | AC_RSV603DA /*|AC_BSAC*/)) { + if (flags & (AC_USAC | AC_RSVD50 | AC_RSV603DA /*|AC_BSAC*/)) { self->pAacDecoderStaticChannelInfo[ch]->hArCo = CArco_Create(); if (self->pAacDecoderStaticChannelInfo[ch]->hArCo == NULL) { goto bail; } } - if (!(self->flags[streamIndex] & (AC_USAC | AC_RSV603DA))) { + if (!(flags & (AC_USAC | AC_RSV603DA))) { CPns_UpdateNoiseState( &self->pAacDecoderChannelInfo[ch]->data.aac.PnsData, &self->pAacDecoderStaticChannelInfo[ch]->pnsCurrentSeed, @@ -2195,7 +2221,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, chIdx++; } - if (self->flags[streamIndex] & AC_USAC) { + if (flags & AC_USAC) { for (int _ch = 0; _ch < flushChannels; _ch++) { ch = aacChannelsOffset + _ch; if (self->pTimeDataFlush[ch] == NULL) { @@ -2207,7 +2233,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, } } - if (self->flags[streamIndex] & (AC_USAC | AC_RSV603DA)) { + if (flags & (AC_USAC | AC_RSV603DA)) { int complexStereoPredPossible = 0; ch = aacChannelsOffset; chIdx = aacChannelsOffsetIdx; @@ -2223,7 +2249,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, elCh = 1; } - if (self->elFlags[el2] & AC_EL_USAC_CP_POSSIBLE) { + if (elFlags[el2] & AC_EL_USAC_CP_POSSIBLE) { complexStereoPredPossible = 1; if (self->cpeStaticData[el2] == NULL) { self->cpeStaticData[el2] = GetCpePersistentData(); @@ -2360,9 +2386,6 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, } } - /* Update externally visible copy of flags */ - self->streamInfo.flags = self->flags[0]; - if (*configChanged) { int drcDecSampleRate, drcDecFrameSize; @@ -2393,6 +2416,12 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, pcmLimiter_SetThreshold(self->hLimiter, FL2FXCONST_DBL(0.89125094f)); } + CAacDecoder_AcceptFlags(self, asc, flags, elFlags, streamIndex, + elementOffset); + + /* Update externally visible copy of flags */ + self->streamInfo.flags = self->flags[0]; + return err; bail: From 18758b9fe1a3ea4034792158009996d350f93bb1 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:57:27 +0200 Subject: [PATCH 34/78] ELD downscale factor 3 is only allowed for framesize 480. Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I9681942ba39761e4f1d66236ad80c2420ca5abe9 --- libAACdec/src/aacdecoder.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp index 6b5f873..b87c388 100644 --- a/libAACdec/src/aacdecoder.cpp +++ b/libAACdec/src/aacdecoder.cpp @@ -1818,9 +1818,17 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, downscaleFactorInBS = asc->m_samplingFrequency / asc->m_sc.m_eldSpecificConfig.m_downscaledSamplingFrequency; - if (downscaleFactorInBS == 1 || downscaleFactorInBS == 2 || - downscaleFactorInBS == 3 || downscaleFactorInBS == 4) { + if ((downscaleFactorInBS == 1 || downscaleFactorInBS == 2 || + (downscaleFactorInBS == 3 && + asc->m_sc.m_eldSpecificConfig.m_frameLengthFlag) || + downscaleFactorInBS == 4) && + ((asc->m_samplingFrequency % + asc->m_sc.m_eldSpecificConfig.m_downscaledSamplingFrequency) == + 0)) { downscaleFactor = downscaleFactorInBS; + } else { + downscaleFactorInBS = 1; + downscaleFactor = 1; } } } else { From ef5f44c760e01aa86e107a5f304bd477c684c509 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:56:25 +0200 Subject: [PATCH 35/78] Check transportDec_OutOfBandConfig() input buffer size parameter. Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I60ac86f09a5652c820d60dfdc12212637f888164 --- libAACdec/src/aacdecoder_lib.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index 47e7496..2b5cd8b 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -1171,8 +1171,10 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(HANDLE_AACDECODER self, aacDecoder_FreeMemCallback(self, &asc); self->streamInfo.numChannels = 0; /* 3) restore AudioSpecificConfig */ - transportDec_OutOfBandConfig(self->hInput, asc.config, - (asc.configBits + 7) >> 3, 0); + if (asc.configBits <= (TP_USAC_MAX_CONFIG_LEN << 3)) { + transportDec_OutOfBandConfig(self->hInput, asc.config, + (asc.configBits + 7) >> 3, 0); + } } } From 702d914e1a43433c90bf15d066585dd85f44572a Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:55:59 +0200 Subject: [PATCH 36/78] Evaluate and return StoreConfigAsBitstream() error state. Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I025e943e91f9be1a5259a761a8ff88defd8babea --- libMpegTPDec/src/tpdec_asc.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp index 4960d3f..5a89a4d 100644 --- a/libMpegTPDec/src/tpdec_asc.cpp +++ b/libMpegTPDec/src/tpdec_asc.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -1998,9 +1998,11 @@ static TRANSPORTDEC_ERROR UsacConfig_Parse(CSAudioSpecificConfig *asc, /* Copy UsacConfig() to asc->m_sc.m_usacConfig.UsacConfig[] buffer. */ INT configSize_bits = (INT)FDKgetValidBits(hBs) - nbits; - StoreConfigAsBitstream(hBs, configSize_bits, - asc->m_sc.m_usacConfig.UsacConfig, - TP_USAC_MAX_CONFIG_LEN); + if (StoreConfigAsBitstream(hBs, configSize_bits, + asc->m_sc.m_usacConfig.UsacConfig, + TP_USAC_MAX_CONFIG_LEN)) { + return TRANSPORTDEC_PARSE_ERROR; + } asc->m_sc.m_usacConfig.UsacConfigBits = fAbs(configSize_bits); return err; @@ -2302,8 +2304,10 @@ TRANSPORTDEC_ERROR AudioSpecificConfig_Parse( /* Copy config() to asc->config[] buffer. */ if ((ErrorStatus == TRANSPORTDEC_OK) && (self->m_aot == AOT_USAC)) { INT configSize_bits = (INT)FDKgetValidBits(bs) - (INT)ascStartAnchor; - StoreConfigAsBitstream(bs, configSize_bits, self->config, - TP_USAC_MAX_CONFIG_LEN); + if (StoreConfigAsBitstream(bs, configSize_bits, self->config, + TP_USAC_MAX_CONFIG_LEN)) { + return TRANSPORTDEC_PARSE_ERROR; + } self->configBits = fAbs(configSize_bits); } From 3ebe6ffe9531825f67f2ff340a489092e445e675 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:55:38 +0200 Subject: [PATCH 37/78] Introduce aacDecoder_drcDisable() and always disable legacy DRC for USAC. Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I75edf24b18e1f5392b6eb179d5574cb93fcbc7c2 --- libAACdec/src/aacdec_drc.cpp | 15 ++++++++++++++- libAACdec/src/aacdec_drc.h | 4 +++- libAACdec/src/aacdecoder.cpp | 13 +++++++------ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/libAACdec/src/aacdec_drc.cpp b/libAACdec/src/aacdec_drc.cpp index b6f5b49..760a9ba 100644 --- a/libAACdec/src/aacdec_drc.cpp +++ b/libAACdec/src/aacdec_drc.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -149,6 +149,19 @@ static INT convert_drcParam(FIXP_DBL param_dbl) { return (INT)param_long; } +/*! +\brief Disable DRC + +\self Handle of DRC info + +\return none +*/ +void aacDecoder_drcDisable(HANDLE_AAC_DRC self) { + self->enable = 0; + self->applyExtGain = 0; + self->progRefLevelPresent = 0; +} + /*! \brief Reset DRC information diff --git a/libAACdec/src/aacdec_drc.h b/libAACdec/src/aacdec_drc.h index 76a44d6..2bb945d 100644 --- a/libAACdec/src/aacdec_drc.h +++ b/libAACdec/src/aacdec_drc.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -140,6 +140,8 @@ typedef enum { /** * \brief DRC module interface functions */ +void aacDecoder_drcDisable(HANDLE_AAC_DRC self); + void aacDecoder_drcReset(HANDLE_AAC_DRC self); void aacDecoder_drcInit(HANDLE_AAC_DRC self); diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp index b87c388..c6d1832 100644 --- a/libAACdec/src/aacdecoder.cpp +++ b/libAACdec/src/aacdecoder.cpp @@ -2414,8 +2414,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, if (*configChanged) { if (asc->m_aot == AOT_USAC) { - self->hDrcInfo->enable = 0; - self->hDrcInfo->progRefLevelPresent = 0; + aacDecoder_drcDisable(self->hDrcInfo); } } @@ -3231,11 +3230,12 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( * data in the bitstream. */ self->flags[streamIndex] |= AC_DRC_PRESENT; } else { - self->hDrcInfo->enable = 0; - self->hDrcInfo->progRefLevelPresent = 0; ErrorStatus = AAC_DEC_UNSUPPORTED_FORMAT; } } + if (self->flags[streamIndex] & (AC_USAC | AC_RSV603DA)) { + aacDecoder_drcDisable(self->hDrcInfo); + } /* Create a reverse mapping table */ UCHAR Reverse_chMapping[((8) * 2)]; @@ -3478,11 +3478,12 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( * data in the bitstream. */ self->flags[streamIndex] |= AC_DRC_PRESENT; } else { - self->hDrcInfo->enable = 0; - self->hDrcInfo->progRefLevelPresent = 0; ErrorStatus = AAC_DEC_UNSUPPORTED_FORMAT; } } + if (self->flags[streamIndex] & (AC_USAC | AC_RSV603DA)) { + aacDecoder_drcDisable(self->hDrcInfo); + } } /* Add additional concealment delay */ From 150febcc65fd7864846cbb03f511fafbaa276f86 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:55:17 +0200 Subject: [PATCH 38/78] Make sure that alphaValue is correctly initialized in sbrDecoder_drcApplySlot(). Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I5bded2e3d29278bb5df561eaa2a46d963ee21df8 --- libSBRdec/src/sbrdec_drc.cpp | 53 +++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/libSBRdec/src/sbrdec_drc.cpp b/libSBRdec/src/sbrdec_drc.cpp index 2d73f32..089d046 100644 --- a/libSBRdec/src/sbrdec_drc.cpp +++ b/libSBRdec/src/sbrdec_drc.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -233,14 +233,19 @@ void sbrDecoder_drcApplySlot(HANDLE_SBR_DRC_CHANNEL hDrcData, if (hDrcData->winSequenceCurr != 2) { /* long window */ int j = col + (numQmfSubSamples >> 1); - if (hDrcData->drcInterpolationSchemeCurr == 0) { - INT k = (frameLenFlag) ? 0x4444445 : 0x4000000; + if (j < winBorderToColMap[15]) { + if (hDrcData->drcInterpolationSchemeCurr == 0) { + INT k = (frameLenFlag) ? 0x4444445 : 0x4000000; - alphaValue = (FIXP_DBL)(j * k); - } else { - if (j >= (int)winBorderToColMap[hDrcData->drcInterpolationSchemeCurr]) { - alphaValue = (FIXP_DBL)MAXVAL_DBL; + alphaValue = (FIXP_DBL)(j * k); + } else { + if (j >= + (int)winBorderToColMap[hDrcData->drcInterpolationSchemeCurr]) { + alphaValue = (FIXP_DBL)MAXVAL_DBL; + } } + } else { + alphaValue = (FIXP_DBL)MAXVAL_DBL; } } else { /* short windows */ shortDrc = 1; @@ -254,14 +259,19 @@ void sbrDecoder_drcApplySlot(HANDLE_SBR_DRC_CHANNEL hDrcData, if (hDrcData->winSequenceNext != 2) { /* next: long window */ int j = col - (numQmfSubSamples >> 1); - if (hDrcData->drcInterpolationSchemeNext == 0) { - INT k = (frameLenFlag) ? 0x4444445 : 0x4000000; + if (j < winBorderToColMap[15]) { + if (hDrcData->drcInterpolationSchemeNext == 0) { + INT k = (frameLenFlag) ? 0x4444445 : 0x4000000; - alphaValue = (FIXP_DBL)(j * k); - } else { - if (j >= (int)winBorderToColMap[hDrcData->drcInterpolationSchemeNext]) { - alphaValue = (FIXP_DBL)MAXVAL_DBL; + alphaValue = (FIXP_DBL)(j * k); + } else { + if (j >= + (int)winBorderToColMap[hDrcData->drcInterpolationSchemeNext]) { + alphaValue = (FIXP_DBL)MAXVAL_DBL; + } } + } else { + alphaValue = (FIXP_DBL)MAXVAL_DBL; } fact_mag = hDrcData->nextFact_mag; @@ -289,14 +299,19 @@ void sbrDecoder_drcApplySlot(HANDLE_SBR_DRC_CHANNEL hDrcData, if (hDrcData->winSequenceNext != 2) { /* long window */ int j = col - (numQmfSubSamples >> 1); - if (hDrcData->drcInterpolationSchemeNext == 0) { - INT k = (frameLenFlag) ? 0x4444445 : 0x4000000; + if (j < winBorderToColMap[15]) { + if (hDrcData->drcInterpolationSchemeNext == 0) { + INT k = (frameLenFlag) ? 0x4444445 : 0x4000000; - alphaValue = (FIXP_DBL)(j * k); - } else { - if (j >= (int)winBorderToColMap[hDrcData->drcInterpolationSchemeNext]) { - alphaValue = (FIXP_DBL)MAXVAL_DBL; + alphaValue = (FIXP_DBL)(j * k); + } else { + if (j >= + (int)winBorderToColMap[hDrcData->drcInterpolationSchemeNext]) { + alphaValue = (FIXP_DBL)MAXVAL_DBL; + } } + } else { + alphaValue = (FIXP_DBL)MAXVAL_DBL; } } else { /* short windows */ shortDrc = 1; From a7c64ff42f1c67960acb9686555ecbc683e3762c Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:54:50 +0200 Subject: [PATCH 39/78] Fix unsigned integer overflow in Hcr_State_BODY_SIGN_ESC__ESC_WORD(). Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I5eb0f88a55e856c427f9e4647332070f66e673c5 --- libAACdec/src/aacdec_hcrs.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libAACdec/src/aacdec_hcrs.cpp b/libAACdec/src/aacdec_hcrs.cpp index 44b32a5..5e3f9ac 100644 --- a/libAACdec/src/aacdec_hcrs.cpp +++ b/libAACdec/src/aacdec_hcrs.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -173,7 +173,9 @@ void DecodeNonPCWs(HANDLE_FDK_BITSTREAM bs, H_HCR_INFO pHcr) { pHcr->segmentInfo.readDirection = FROM_RIGHT_TO_LEFT; /* Process sets subsequently */ + numSet = fMin(numSet, (UCHAR)MAX_HCR_SETS); for (currentSet = 1; currentSet < numSet; currentSet++) { + /* step 1 */ numCodeword -= *pNumSegment; /* number of remaining non PCWs [for all sets] */ From baa32039711dd15772f65eb61e2ce131dbaefc49 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:54:33 +0200 Subject: [PATCH 40/78] Validate DRC compression factor and DRC boost factor value range in aacDecoder_SetParam(). Bug: 176246647 Test: atest DecoderTestXheAac DecoderTestAacDrc Change-Id: I1d8534145bcf400c5da58d64d3b7e73a87cb43be --- libAACdec/src/aacdecoder_lib.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index 2b5cd8b..3ef7140 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -820,6 +820,9 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_SetParam( case AAC_DRC_ATTENUATION_FACTOR: /* DRC compression factor (where 0 is no and 127 is max compression) */ + if ((value < 0) || (value > 127)) { + return AAC_DEC_SET_PARAM_FAIL; + } errorStatus = aacDecoder_drcSetParam(hDrcInfo, DRC_CUT_SCALE, value); uniDrcErr = FDK_drcDec_SetParam(self->hUniDrcDecoder, DRC_DEC_COMPRESS, value * (FL2FXCONST_DBL(0.5f / 127.0f))); @@ -827,6 +830,9 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_SetParam( case AAC_DRC_BOOST_FACTOR: /* DRC boost factor (where 0 is no and 127 is max boost) */ + if ((value < 0) || (value > 127)) { + return AAC_DEC_SET_PARAM_FAIL; + } errorStatus = aacDecoder_drcSetParam(hDrcInfo, DRC_BOOST_SCALE, value); uniDrcErr = FDK_drcDec_SetParam(self->hUniDrcDecoder, DRC_DEC_BOOST, value * (FL2FXCONST_DBL(0.5f / 127.0f))); From 82f6f3dac64d2b0f124f5c993c365855ab6716a5 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Thu, 9 Apr 2020 17:58:42 +0200 Subject: [PATCH 41/78] Introduce additional sanity checks to validate program config element. Bug: 176246647 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I3e04480ab5a74da1a9d09af5da95afb2000b3117 --- libMpegTPDec/src/tpdec_asc.cpp | 167 ++++++++++++++++++++++++++++++--- 1 file changed, 156 insertions(+), 11 deletions(-) diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp index 5a89a4d..a2baaaf 100644 --- a/libMpegTPDec/src/tpdec_asc.cpp +++ b/libMpegTPDec/src/tpdec_asc.cpp @@ -266,11 +266,118 @@ static int CProgramConfig_ReadHeightExt(CProgramConfig *pPce, return (err); } +/** + * \brief Sanity checks for program config element. + * Check order of elements according to ISO/IEC 13818-7:2003(E), + * chapter 8.5.1 + * + * \param pPce pointer to program config element. + * + * \return 0 if successful, otherwise 1. + */ +static int CProgramConfig_Check(CProgramConfig *pPce) { + INT i; + INT err = 0; + INT numBackChannels[3] = {0}; + INT numSideChannels[3] = {0}; + INT numFrontChannels[3] = {0}; + UCHAR *pCpeFront = pPce->FrontElementIsCpe; + UCHAR *pCpeSide = pPce->SideElementIsCpe; + UCHAR *pCpeBack = pPce->BackElementIsCpe; + UCHAR *pHeight; + + pHeight = pPce->BackElementHeightInfo; + for (i = 0; i < pPce->NumBackChannelElements; i++) { + numBackChannels[*pHeight] += pPce->BackElementIsCpe[i] ? 2 : 1; + pHeight++; + } + pHeight = pPce->SideElementHeightInfo; + for (i = 0; i < pPce->NumSideChannelElements; i++) { + numSideChannels[*pHeight] += pPce->SideElementIsCpe[i] ? 2 : 1; + pHeight++; + } + pHeight = pPce->FrontElementHeightInfo; + for (i = 0; i < pPce->NumFrontChannelElements; i++) { + numFrontChannels[*pHeight] += pPce->FrontElementIsCpe[i] ? 2 : 1; + pHeight++; + } + + /* 0 = normal height channels, 1 = top height channels, 2 = bottom height + * channels */ + for (i = 0; i < 3; i++) { + /* if number of channels is odd => first element must be a SCE (front center + * channel) */ + if (numFrontChannels[i] & 1) { + if (*pCpeFront++ == ID_CPE) { + err = 1; + goto bail; + } + numFrontChannels[i]--; + } + while (numFrontChannels[i] > 0) { + /* must be CPE or paired SCE */ + if (*pCpeFront++ == ID_SCE) { + if (*pCpeFront++ == ID_CPE) { + err = 1; + goto bail; + } + } + numFrontChannels[i] -= 2; + }; + + /* in case that a top center surround channel (Ts) is transmitted the number + * of channels can be odd */ + if (i != 1) { + /* number of channels must be even */ + if (numSideChannels[i] & 1) { + err = 1; + goto bail; + } + while (numSideChannels[i] > 0) { + /* must be CPE or paired SCE */ + if (*pCpeSide++ == ID_SCE) { + if (*pCpeSide++ == ID_CPE) { + err = 1; + goto bail; + } + } + numSideChannels[i] -= 2; + }; + } + + while (numBackChannels[i] > 1) { + /* must be CPE or paired SCE */ + if (*pCpeBack++ == ID_SCE) { + if (*pCpeBack++ == ID_CPE) { + err = 1; + goto bail; + } + } + numBackChannels[i] -= 2; + }; + /* if number of channels is odd => last element must be a SCE (back center + * channel) */ + if (numBackChannels[i]) { + if (*pCpeBack++ == ID_CPE) { + err = 1; + goto bail; + } + } + } + +bail: + + return err; +} + void CProgramConfig_Read(CProgramConfig *pPce, HANDLE_FDK_BITSTREAM bs, UINT alignmentAnchor) { - int i, err = 0; + int i; int commentBytes; + UCHAR tag, isCpe; + UCHAR checkElementTagSelect[3][PC_FSB_CHANNELS_MAX] = {{0}}; + pPce->isValid = 1; pPce->NumEffectiveChannels = 0; pPce->NumChannels = 0; pPce->ElementInstanceTag = (UCHAR)FDKreadBits(bs, 4); @@ -297,28 +404,60 @@ void CProgramConfig_Read(CProgramConfig *pPce, HANDLE_FDK_BITSTREAM bs, } for (i = 0; i < pPce->NumFrontChannelElements; i++) { - pPce->FrontElementIsCpe[i] = (UCHAR)FDKreadBits(bs, 1); - pPce->FrontElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); + pPce->FrontElementIsCpe[i] = isCpe = (UCHAR)FDKreadBits(bs, 1); + pPce->FrontElementTagSelect[i] = tag = (UCHAR)FDKreadBits(bs, 4); pPce->NumChannels += pPce->FrontElementIsCpe[i] ? 2 : 1; + + /* Check element instance tag according to ISO/IEC 13818-7:2003(E), + * chapter 8.2.1.1 */ + if (checkElementTagSelect[isCpe][tag] == 0) { + checkElementTagSelect[isCpe][tag] = 1; + } else { + pPce->isValid = 0; + } } for (i = 0; i < pPce->NumSideChannelElements; i++) { - pPce->SideElementIsCpe[i] = (UCHAR)FDKreadBits(bs, 1); - pPce->SideElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); + pPce->SideElementIsCpe[i] = isCpe = (UCHAR)FDKreadBits(bs, 1); + pPce->SideElementTagSelect[i] = tag = (UCHAR)FDKreadBits(bs, 4); pPce->NumChannels += pPce->SideElementIsCpe[i] ? 2 : 1; + + /* Check element instance tag according to ISO/IEC 13818-7:2003(E), + * chapter 8.2.1.1 */ + if (checkElementTagSelect[isCpe][tag] == 0) { + checkElementTagSelect[isCpe][tag] = 1; + } else { + pPce->isValid = 0; + } } for (i = 0; i < pPce->NumBackChannelElements; i++) { - pPce->BackElementIsCpe[i] = (UCHAR)FDKreadBits(bs, 1); - pPce->BackElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); + pPce->BackElementIsCpe[i] = isCpe = (UCHAR)FDKreadBits(bs, 1); + pPce->BackElementTagSelect[i] = tag = (UCHAR)FDKreadBits(bs, 4); pPce->NumChannels += pPce->BackElementIsCpe[i] ? 2 : 1; + + /* Check element instance tag according to ISO/IEC 13818-7:2003(E), + * chapter 8.2.1.1 */ + if (checkElementTagSelect[isCpe][tag] == 0) { + checkElementTagSelect[isCpe][tag] = 1; + } else { + pPce->isValid = 0; + } } pPce->NumEffectiveChannels = pPce->NumChannels; for (i = 0; i < pPce->NumLfeChannelElements; i++) { - pPce->LfeElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); + pPce->LfeElementTagSelect[i] = tag = (UCHAR)FDKreadBits(bs, 4); pPce->NumChannels += 1; + + /* Check element instance tag according to ISO/IEC 13818-7:2003(E), + * chapter 8.2.1.1 */ + if (checkElementTagSelect[2][tag] == 0) { + checkElementTagSelect[2][tag] = 1; + } else { + pPce->isValid = 0; + } } for (i = 0; i < pPce->NumAssocDataElements; i++) { @@ -336,7 +475,15 @@ void CProgramConfig_Read(CProgramConfig *pPce, HANDLE_FDK_BITSTREAM bs, commentBytes = pPce->CommentFieldBytes; /* Search for height info extension and read it if available */ - err = CProgramConfig_ReadHeightExt(pPce, bs, &commentBytes, alignmentAnchor); + if (CProgramConfig_ReadHeightExt(pPce, bs, &commentBytes, alignmentAnchor)) { + pPce->isValid = 0; + } + + /* Check order of elements according to ISO / IEC 13818 - 7:2003(E), + * chapter 8.5.1 */ + if (CProgramConfig_Check(pPce)) { + pPce->isValid = 0; + } for (i = 0; i < commentBytes; i++) { UCHAR text; @@ -347,8 +494,6 @@ void CProgramConfig_Read(CProgramConfig *pPce, HANDLE_FDK_BITSTREAM bs, pPce->Comment[i] = text; } } - - pPce->isValid = (err) ? 0 : 1; } /* From 09e7c40a3aa31a47edd272269325e72b40668e90 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:07:13 +0200 Subject: [PATCH 42/78] Fix USAC time domain limiter latency at config change. We have observed quality problems regarding config switching for USAC streams. Crossfading did not consider the USAC time domain limiter latency correctly. The limiter memory still contained the last part of the frame before the config change. With this patch we were able to improve the quality by moving the limiter processing to the end of the processing chain (crossfade -> DRC -> limiter). By that we don't have to consider the limiter latency at the crossfader anymore and can resolve the quality issue. Bug: 176246647 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I0dfd3b76ff2b0daf495ad406283f56a39982ad8f Change-Id: I26f5da65ef8344602007e180e837820c6a25f173 --- libAACdec/src/aac_ram.cpp | 4 +- libAACdec/src/aac_ram.h | 4 +- libAACdec/src/aacdecoder.cpp | 23 +-- libAACdec/src/aacdecoder.h | 18 ++- libAACdec/src/aacdecoder_lib.cpp | 248 ++++++++++++++++--------------- 5 files changed, 156 insertions(+), 141 deletions(-) diff --git a/libAACdec/src/aac_ram.cpp b/libAACdec/src/aac_ram.cpp index aa8f6a6..fac1540 100644 --- a/libAACdec/src/aac_ram.cpp +++ b/libAACdec/src/aac_ram.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -148,7 +148,7 @@ C_ALLOC_MEM(CplxPredictionData, CCplxPredictionData, 1) /*! The buffer holds time samples for the crossfade in case of an USAC DASH IPF config change Dimension: (8) */ -C_ALLOC_MEM2(TimeDataFlush, INT_PCM, TIME_DATA_FLUSH_SIZE, (8)) +C_ALLOC_MEM2(TimeDataFlush, PCM_DEC, TIME_DATA_FLUSH_SIZE, (8)) /* @} */ diff --git a/libAACdec/src/aac_ram.h b/libAACdec/src/aac_ram.h index b9b95b7..395b2b2 100644 --- a/libAACdec/src/aac_ram.h +++ b/libAACdec/src/aac_ram.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -132,7 +132,7 @@ H_ALLOC_MEM(CplxPredictionData, CCplxPredictionData) H_ALLOC_MEM(SpectralCoeffs, FIXP_DBL) H_ALLOC_MEM(SpecScale, SHORT) -H_ALLOC_MEM(TimeDataFlush, INT_PCM) +H_ALLOC_MEM(TimeDataFlush, PCM_DEC) H_ALLOC_MEM_OVERLAY(WorkBufferCore1, CWorkBufferCore1) H_ALLOC_MEM_OVERLAY(WorkBufferCore2, FIXP_DBL) diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp index c6d1832..c18e5e9 100644 --- a/libAACdec/src/aacdecoder.cpp +++ b/libAACdec/src/aacdecoder.cpp @@ -568,7 +568,7 @@ static int CProgramConfigElement_Read(HANDLE_FDK_BITSTREAM bs, \return Error code */ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_PrepareCrossFade( - const INT_PCM *pTimeData, INT_PCM **pTimeDataFlush, const INT numChannels, + const PCM_DEC *pTimeData, PCM_DEC **pTimeDataFlush, const INT numChannels, const INT frameSize, const INT interleaved) { int i, ch, s1, s2; AAC_DECODER_ERROR ErrorStatus; @@ -584,7 +584,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_PrepareCrossFade( } for (ch = 0; ch < numChannels; ch++) { - const INT_PCM *pIn = &pTimeData[ch * s1]; + const PCM_DEC *pIn = &pTimeData[ch * s1]; for (i = 0; i < TIME_DATA_FLUSH_SIZE; i++) { pTimeDataFlush[ch][i] = *pIn; pIn += s2; @@ -606,7 +606,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_PrepareCrossFade( \return Error code */ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_ApplyCrossFade( - INT_PCM *pTimeData, INT_PCM **pTimeDataFlush, const INT numChannels, + PCM_DEC *pTimeData, PCM_DEC **pTimeDataFlush, const INT numChannels, const INT frameSize, const INT interleaved) { int i, ch, s1, s2; AAC_DECODER_ERROR ErrorStatus; @@ -622,15 +622,15 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_ApplyCrossFade( } for (ch = 0; ch < numChannels; ch++) { - INT_PCM *pIn = &pTimeData[ch * s1]; + PCM_DEC *pIn = &pTimeData[ch * s1]; for (i = 0; i < TIME_DATA_FLUSH_SIZE; i++) { FIXP_SGL alpha = (FIXP_SGL)i << (FRACT_BITS - 1 - TIME_DATA_FLUSH_SIZE_SF); - FIXP_DBL time = FX_PCM2FX_DBL(*pIn); - FIXP_DBL timeFlush = FX_PCM2FX_DBL(pTimeDataFlush[ch][i]); + FIXP_DBL time = PCM_DEC2FIXP_DBL(*pIn); + FIXP_DBL timeFlush = PCM_DEC2FIXP_DBL(pTimeDataFlush[ch][i]); - *pIn = (INT_PCM)(FIXP_PCM)FX_DBL2FX_PCM( - timeFlush - fMult(timeFlush, alpha) + fMult(time, alpha)); + *pIn = FIXP_DBL2PCM_DEC(timeFlush - fMult(timeFlush, alpha) + + fMult(time, alpha)); pIn += s2; } } @@ -753,7 +753,12 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_PreRollExtensionPayloadParse( /* We are interested in preroll AUs if an explicit or an implicit config * change is signalized in other words if the build up status is set. */ if (self->buildUpStatus == AACDEC_USAC_BUILD_UP_ON) { - self->applyCrossfade |= FDKreadBit(hBs); + UCHAR applyCrossfade = FDKreadBit(hBs); + if (applyCrossfade) { + self->applyCrossfade |= AACDEC_CROSSFADE_BITMASK_PREROLL; + } else { + self->applyCrossfade &= ~AACDEC_CROSSFADE_BITMASK_PREROLL; + } FDKreadBit(hBs); /* reserved */ /* Read num preroll AU's */ *numPrerollAU = escapedValue(hBs, 2, 4, 0); diff --git a/libAACdec/src/aacdecoder.h b/libAACdec/src/aacdecoder.h index bd1f38f..002807f 100644 --- a/libAACdec/src/aacdecoder.h +++ b/libAACdec/src/aacdecoder.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -172,6 +172,12 @@ enum { AACDEC_RSV60_BUILD_UP_IDLE_IN_BAND = 5 }; +#define AACDEC_CROSSFADE_BITMASK_OFF \ + ((UCHAR)0) /*!< No cross-fade between frames shall be applied at next \ + config change. */ +#define AACDEC_CROSSFADE_BITMASK_PREROLL \ + ((UCHAR)1 << 1) /*!< applyCrossfade is signaled in AudioPreRoll */ + typedef struct { /* Usac Extension Elements */ USAC_EXT_ELEMENT_TYPE usacExtElementType[(3)]; @@ -325,7 +331,7 @@ This structure is allocated once for each CPE. */ UINT loudnessInfoSetPosition[3]; SCHAR defaultTargetLoudness; - INT_PCM + PCM_DEC *pTimeDataFlush[((8) * 2)]; /*!< Pointer to the flushed time data which will be used for the crossfade in case of an USAC DASH IPF config change */ @@ -341,8 +347,8 @@ This structure is allocated once for each CPE. */ start position in the bitstream */ INT accessUnit; /*!< Number of the actual processed preroll accessUnit */ - UCHAR applyCrossfade; /*!< if set crossfade for seamless stream switching is - applied */ + UCHAR applyCrossfade; /*!< If any bit is set, cross-fade for seamless stream + switching is applied */ FDK_SignalDelay usacResidualDelay; /*!< Delay residual signal to compensate for eSBR delay of DMX signal in case of @@ -439,12 +445,12 @@ LINKSPEC_H AAC_DECODER_ERROR CAacDecoder_FreeMem(HANDLE_AACDECODER self, /* Prepare crossfade for USAC DASH IPF config change */ LINKSPEC_H AAC_DECODER_ERROR CAacDecoder_PrepareCrossFade( - const INT_PCM *pTimeData, INT_PCM **pTimeDataFlush, const INT numChannels, + const PCM_DEC *pTimeData, PCM_DEC **pTimeDataFlush, const INT numChannels, const INT frameSize, const INT interleaved); /* Apply crossfade for USAC DASH IPF config change */ LINKSPEC_H AAC_DECODER_ERROR CAacDecoder_ApplyCrossFade( - INT_PCM *pTimeData, INT_PCM **pTimeDataFlush, const INT numChannels, + PCM_DEC *pTimeData, PCM_DEC **pTimeDataFlush, const INT numChannels, const INT frameSize, const INT interleaved); /* Set flush and build up mode */ diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index 3ef7140..90563ea 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -1155,6 +1155,8 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(HANDLE_AACDECODER self, int applyCrossfade = 1; /* flag indicates if flushing was possible */ PCM_DEC *pTimeData2; PCM_AAC *pTimeData3; + INT pcmLimiterScale = 0; + INT interleaved = 0; if (self == NULL) { return AAC_DEC_INVALID_HANDLE; @@ -1800,8 +1802,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(HANDLE_AACDECODER self, } if (self->streamInfo.extAot != AOT_AAC_SLS) { - INT pcmLimiterScale = 0; - INT interleaved = 0; + interleaved = 0; interleaved |= (self->sbrEnabled) ? 1 : 0; interleaved |= (self->mpsEnableCurr) ? 1 : 0; PCMDMX_ERROR dmxErr = PCMDMX_OK; @@ -1832,145 +1833,38 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(HANDLE_AACDECODER self, * predictable behavior and thus maybe produce strange output. */ ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; } - - pcmLimiterScale += PCM_OUT_HEADROOM; - - if (flags & AACDEC_CLRHIST) { - if (!(self->flags[0] & AC_USAC)) { - /* Reset DRC data */ - aacDecoder_drcReset(self->hDrcInfo); - /* Delete the delayed signal. */ - pcmLimiter_Reset(self->hLimiter); - } - } - - /* Set applyExtGain if DRC processing is enabled and if - progRefLevelPresent is present for the first time. Consequences: The - headroom of the output signal can be set to AACDEC_DRC_GAIN_SCALING - only for audio formats which support legacy DRC Level Normalization. - For all other audio formats the headroom of the output - signal is set to PCM_OUT_HEADROOM. */ - if (self->hDrcInfo->enable && - (self->hDrcInfo->progRefLevelPresent == 1)) { - self->hDrcInfo->applyExtGain |= 1; - } - - /* Check whether time data buffer is large enough. */ - if (timeDataSize < - (self->streamInfo.numChannels * self->streamInfo.frameSize)) { - ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL; - goto bail; - } - - if (self->limiterEnableCurr) { - /* use workBufferCore2 buffer for interleaving */ - PCM_LIM *pInterleaveBuffer; - int blockLength = self->streamInfo.frameSize; - - /* Set actual signal parameters */ - pcmLimiter_SetNChannels(self->hLimiter, self->streamInfo.numChannels); - pcmLimiter_SetSampleRate(self->hLimiter, self->streamInfo.sampleRate); - - if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) || - (self->mpsEnableCurr)) { - pInterleaveBuffer = (PCM_LIM *)pTimeData2; - } else { - pInterleaveBuffer = (PCM_LIM *)self->workBufferCore2; - - /* applyLimiter requests for interleaved data */ - /* Interleave ouput buffer */ - FDK_interleave(pTimeData2, pInterleaveBuffer, - self->streamInfo.numChannels, blockLength, - self->streamInfo.frameSize); - } - - FIXP_DBL *pGainPerSample = NULL; - - if (self->hDrcInfo->enable && self->hDrcInfo->applyExtGain) { - pGainPerSample = self->workBufferCore1; - - if ((INT)GetRequiredMemWorkBufferCore1() < - (INT)(self->streamInfo.frameSize * sizeof(FIXP_DBL))) { - ErrorStatus = AAC_DEC_UNKNOWN; - goto bail; - } - - pcmLimiterScale = applyDrcLevelNormalization( - self->hDrcInfo, (PCM_DEC *)pInterleaveBuffer, self->extGain, - pGainPerSample, pcmLimiterScale, self->extGainDelay, - self->streamInfo.frameSize, self->streamInfo.numChannels, 1, 1); - } - - pcmLimiter_Apply(self->hLimiter, pInterleaveBuffer, pTimeData, - pGainPerSample, pcmLimiterScale, - self->streamInfo.frameSize); - - { - /* Announce the additional limiter output delay */ - self->streamInfo.outputDelay += pcmLimiter_GetDelay(self->hLimiter); - } - } else { - if (self->hDrcInfo->enable && self->hDrcInfo->applyExtGain) { - pcmLimiterScale = applyDrcLevelNormalization( - self->hDrcInfo, pTimeData2, self->extGain, NULL, - pcmLimiterScale, self->extGainDelay, self->streamInfo.frameSize, - self->streamInfo.numChannels, - (interleaved || (self->streamInfo.numChannels == 1)) - ? 1 - : self->streamInfo.frameSize, - 0); - } - - /* If numChannels = 1 we do not need interleaving. The same applies if - SBR or MPS are used, since their output is interleaved already - (resampled or not) */ - if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) || - (self->mpsEnableCurr)) { - scaleValuesSaturate( - pTimeData, pTimeData2, - self->streamInfo.frameSize * self->streamInfo.numChannels, - pcmLimiterScale); - - } else { - scaleValuesSaturate( - (INT_PCM *)self->workBufferCore2, pTimeData2, - self->streamInfo.frameSize * self->streamInfo.numChannels, - pcmLimiterScale); - /* Interleave ouput buffer */ - FDK_interleave((INT_PCM *)self->workBufferCore2, pTimeData, - self->streamInfo.numChannels, - self->streamInfo.frameSize, - self->streamInfo.frameSize); - } - } - } /* if (self->streamInfo.extAot != AOT_AAC_SLS)*/ + } if (self->flags[0] & AC_USAC) { if (self->flushStatus == AACDEC_USAC_DASH_IPF_FLUSH_ON && !(flags & AACDEC_CONCEAL)) { - CAacDecoder_PrepareCrossFade(pTimeData, self->pTimeDataFlush, + CAacDecoder_PrepareCrossFade(pTimeData2, self->pTimeDataFlush, self->streamInfo.numChannels, - self->streamInfo.frameSize, 1); + self->streamInfo.frameSize, interleaved); } /* prepare crossfade buffer for fade in */ - if (!applyCrossfade && self->applyCrossfade && + if (!applyCrossfade && + (self->applyCrossfade != AACDEC_CROSSFADE_BITMASK_OFF) && !(flags & AACDEC_CONCEAL)) { for (int ch = 0; ch < self->streamInfo.numChannels; ch++) { for (int i = 0; i < TIME_DATA_FLUSH_SIZE; i++) { - self->pTimeDataFlush[ch][i] = 0; + self->pTimeDataFlush[ch][i] = (PCM_DEC)0; } } applyCrossfade = 1; } - if (applyCrossfade && self->applyCrossfade && + if (applyCrossfade && + (self->applyCrossfade != AACDEC_CROSSFADE_BITMASK_OFF) && !(accessUnit < numPrerollAU) && (self->buildUpStatus == AACDEC_USAC_BUILD_UP_ON)) { - CAacDecoder_ApplyCrossFade(pTimeData, self->pTimeDataFlush, + CAacDecoder_ApplyCrossFade(pTimeData2, self->pTimeDataFlush, self->streamInfo.numChannels, - self->streamInfo.frameSize, 1); - self->applyCrossfade = 0; + self->streamInfo.frameSize, interleaved); + self->applyCrossfade = + AACDEC_CROSSFADE_BITMASK_OFF; /* disable cross-fade between frames + at nect config change */ } } @@ -2012,6 +1906,116 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(HANDLE_AACDECODER self, ((self->flushStatus == AACDEC_USAC_DASH_IPF_FLUSH_ON) && !(flags & AACDEC_CONCEAL))); + if (self->streamInfo.extAot != AOT_AAC_SLS) { + pcmLimiterScale += PCM_OUT_HEADROOM; + + if (flags & AACDEC_CLRHIST) { + if (!(self->flags[0] & AC_USAC)) { + /* Reset DRC data */ + aacDecoder_drcReset(self->hDrcInfo); + /* Delete the delayed signal. */ + pcmLimiter_Reset(self->hLimiter); + } + } + + /* Set applyExtGain if DRC processing is enabled and if progRefLevelPresent + is present for the first time. Consequences: The headroom of the output + signal can be set to AACDEC_DRC_GAIN_SCALING only for audio formats which + support legacy DRC Level Normalization. For all other audio formats the + headroom of the output signal is set to PCM_OUT_HEADROOM. */ + if (self->hDrcInfo->enable && (self->hDrcInfo->progRefLevelPresent == 1)) { + self->hDrcInfo->applyExtGain |= 1; + } + + /* Check whether time data buffer is large enough. */ + if (timeDataSize < + (self->streamInfo.numChannels * self->streamInfo.frameSize)) { + ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL; + goto bail; + } + + if (self->limiterEnableCurr) { + /* use workBufferCore2 buffer for interleaving */ + PCM_LIM *pInterleaveBuffer; + int blockLength = self->streamInfo.frameSize; + + /* Set actual signal parameters */ + pcmLimiter_SetNChannels(self->hLimiter, self->streamInfo.numChannels); + pcmLimiter_SetSampleRate(self->hLimiter, self->streamInfo.sampleRate); + + if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) || + (self->mpsEnableCurr)) { + pInterleaveBuffer = (PCM_LIM *)pTimeData2; + } else { + pInterleaveBuffer = (PCM_LIM *)self->workBufferCore2; + + /* applyLimiter requests for interleaved data */ + /* Interleave ouput buffer */ + FDK_interleave(pTimeData2, pInterleaveBuffer, + self->streamInfo.numChannels, blockLength, + self->streamInfo.frameSize); + } + + FIXP_DBL *pGainPerSample = NULL; + + if (self->hDrcInfo->enable && self->hDrcInfo->applyExtGain) { + pGainPerSample = self->workBufferCore1; + + if ((INT)GetRequiredMemWorkBufferCore1() < + (INT)(self->streamInfo.frameSize * sizeof(FIXP_DBL))) { + ErrorStatus = AAC_DEC_UNKNOWN; + goto bail; + } + + pcmLimiterScale = applyDrcLevelNormalization( + self->hDrcInfo, (PCM_DEC *)pInterleaveBuffer, self->extGain, + pGainPerSample, pcmLimiterScale, self->extGainDelay, + self->streamInfo.frameSize, self->streamInfo.numChannels, 1, 1); + } + + pcmLimiter_Apply(self->hLimiter, pInterleaveBuffer, pTimeData, + pGainPerSample, pcmLimiterScale, + self->streamInfo.frameSize); + + { + /* Announce the additional limiter output delay */ + self->streamInfo.outputDelay += pcmLimiter_GetDelay(self->hLimiter); + } + } else { + if (self->hDrcInfo->enable && self->hDrcInfo->applyExtGain) { + pcmLimiterScale = applyDrcLevelNormalization( + self->hDrcInfo, pTimeData2, self->extGain, NULL, pcmLimiterScale, + self->extGainDelay, self->streamInfo.frameSize, + self->streamInfo.numChannels, + (interleaved || (self->streamInfo.numChannels == 1)) + ? 1 + : self->streamInfo.frameSize, + 0); + } + + /* If numChannels = 1 we do not need interleaving. The same applies if SBR + or MPS are used, since their output is interleaved already (resampled or + not) */ + if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) || + (self->mpsEnableCurr)) { + scaleValuesSaturate( + pTimeData, pTimeData2, + self->streamInfo.frameSize * self->streamInfo.numChannels, + pcmLimiterScale); + + } else { + scaleValuesSaturate( + (INT_PCM *)self->workBufferCore2, pTimeData2, + self->streamInfo.frameSize * self->streamInfo.numChannels, + pcmLimiterScale); + /* Interleave ouput buffer */ + FDK_interleave((INT_PCM *)self->workBufferCore2, pTimeData, + self->streamInfo.numChannels, self->streamInfo.frameSize, + self->streamInfo.frameSize); + } + } + } /* if (self->streamInfo.extAot != AOT_AAC_SLS)*/ + bail: /* error in renderer part occurred, ErrorStatus was set to invalid output */ From 5e031b67ba74f2713af8f4237f43825742c0a28a Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:05:08 +0200 Subject: [PATCH 43/78] Consider TNS headroom for complex prediction. Bug: 176246647 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I8261106b98d7e7c5a8a2af38585c726285ea8623 --- libAACdec/src/channel.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libAACdec/src/channel.cpp b/libAACdec/src/channel.cpp index a020034..7e62bfb 100644 --- a/libAACdec/src/channel.cpp +++ b/libAACdec/src/channel.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -265,7 +265,9 @@ void CChannelElement_Decode( stereo prediction since scaling has already been carried out. */ int max_sfb_ste = (INT)(pAacDecoderChannelInfo[L]->icsInfo.max_sfb_ste); - if ((!CP_active) || (CP_active && (max_sfb_ste < noSfbs)) || + if (!(CP_active && (max_sfb_ste == noSfbs)) || + !(CP_active && + !(pAacDecoderChannelInfo[ch]->pDynData->TnsData.Active)) || ((flags & (AC_USAC | AC_RSVD50 | AC_RSV603DA)) && (pAacDecoderChannelInfo[L]->pDynData->specificTo.usac.tns_on_lr == 0))) { From 0c2c08aef6849fdec71cae4d769c6cd3dd86303d Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:08:00 +0200 Subject: [PATCH 44/78] Read uniDrcGainExtension element only if all DRC gain sequences are parsed correctly. Prevent error return during parsing of incomplete uniDrcGain() element. This fixes unnecessary concealment of frames for AAC in case a uniDrcGain() is provided, but the uniDrcConfig() element is not available. Bug: 176246647 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I5ae343eaea481774c53240dbce4da0f4ff06cd1d --- libDRCdec/src/drcDec_reader.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/libDRCdec/src/drcDec_reader.cpp b/libDRCdec/src/drcDec_reader.cpp index 367a352..b3ec187 100644 --- a/libDRCdec/src/drcDec_reader.cpp +++ b/libDRCdec/src/drcDec_reader.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -512,10 +512,13 @@ drcDec_readUniDrcGain(HANDLE_FDK_BITSTREAM hBs, fMin(tmpNNodes, (UCHAR)16) * sizeof(GAIN_NODE)); } - hUniDrcGain->uniDrcGainExtPresent = FDKreadBits(hBs, 1); - if (hUniDrcGain->uniDrcGainExtPresent == 1) { - err = _readUniDrcGainExtension(hBs, &(hUniDrcGain->uniDrcGainExtension)); - if (err) return err; + if (pCoef && (gainSequenceCount == + pCoef->gainSequenceCount)) { /* all sequences have been read */ + hUniDrcGain->uniDrcGainExtPresent = FDKreadBits(hBs, 1); + if (hUniDrcGain->uniDrcGainExtPresent == 1) { + err = _readUniDrcGainExtension(hBs, &(hUniDrcGain->uniDrcGainExtension)); + if (err) return err; + } } if (err == DE_OK && gainSequenceCount > 0) { From bd021e7fb414744d47d48af1996b08ee2dc24a9c Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:09:22 +0200 Subject: [PATCH 45/78] Fix wrong input buffer feed for PS encoder at less input samples than framesize. Bug 177604812 Test: see PS/SBR encoder Change-Id: I08a20209bcb83784fda5c14584b6e99c65672545 --- libAACenc/src/aacenc_lib.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp index b0d0454..3bfdfe8 100644 --- a/libAACenc/src/aacenc_lib.cpp +++ b/libAACenc/src/aacenc_lib.cpp @@ -1784,8 +1784,8 @@ AACENC_ERROR aacEncEncode(const HANDLE_AACENCODER hAacEncoder, hAacEncoder->nSamplesRead)); INT_PCM *pIn = hAacEncoder->inputBuffer + - (hAacEncoder->inputBufferOffset + hAacEncoder->nSamplesRead) / - hAacEncoder->aacConfig.nChannels; + hAacEncoder->inputBufferOffset / hAacEncoder->aacConfig.nChannels + + hAacEncoder->nSamplesRead / hAacEncoder->extParam.nChannels; newSamples -= (newSamples % hAacEncoder->extParam From 4fbc97cc479704a5e12d2d3c0d2b782cf21595a3 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:10:17 +0200 Subject: [PATCH 46/78] Fix input buffer flushing for PS encoder. Bug 177604812 Test: see PS/SBR encoder Change-Id: I3152bd7db5e039ecc54885e5b58c1cf6cb598b28 --- libAACenc/src/aacenc_lib.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp index 3bfdfe8..0217641 100644 --- a/libAACenc/src/aacenc_lib.cpp +++ b/libAACenc/src/aacenc_lib.cpp @@ -1827,12 +1827,13 @@ AACENC_ERROR aacEncEncode(const HANDLE_AACENCODER hAacEncoder, /* clear out until end-of-buffer */ if (nZeros) { + INT_PCM *pIn = + hAacEncoder->inputBuffer + + hAacEncoder->inputBufferOffset / + hAacEncoder->aacConfig.nChannels + + hAacEncoder->nSamplesRead / hAacEncoder->extParam.nChannels; for (i = 0; i < (int)hAacEncoder->extParam.nChannels; i++) { - FDKmemclear(hAacEncoder->inputBuffer + - i * hAacEncoder->inputBufferSizePerChannel + - (hAacEncoder->inputBufferOffset + - hAacEncoder->nSamplesRead) / - hAacEncoder->extParam.nChannels, + FDKmemclear(pIn + i * hAacEncoder->inputBufferSizePerChannel, sizeof(INT_PCM) * nZeros); } hAacEncoder->nZerosAppended += nZeros; From edab3e30d68dc47ad8e4fabcca78b62dbd930d4c Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:11:03 +0200 Subject: [PATCH 47/78] Overcome SBR encoder coupling quality issue in ELD. Bug 177604812 Test: see SBR/PS encoder Change-Id: Ie7b9f8d1dec3708557d1e1189d45bc0e3bf5444c --- libSBRenc/src/env_est.cpp | 22 +++++++++++++++------- libSBRenc/src/sbr_encoder.cpp | 5 ++--- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/libSBRenc/src/env_est.cpp b/libSBRenc/src/env_est.cpp index 0eb8425..cc8780a 100644 --- a/libSBRenc/src/env_est.cpp +++ b/libSBRenc/src/env_est.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -1267,6 +1267,7 @@ void FDKsbrEnc_extractSbrEnvelope2( sbrExtrEnv->pre_transient_info[1] = ed->transient_info[1]; /* tran_flag */ hEnvChan->encEnvData.noOfEnvelopes = ed->nEnvelopes = ed->frame_info->nEnvelopes; /* number of envelopes of current frame */ + hEnvChan->encEnvData.currentAmpResFF = (AMP_RES)h_con->initAmpResFF; /* Check if the current frame is divided into one envelope only. If so, set @@ -1274,8 +1275,9 @@ void FDKsbrEnc_extractSbrEnvelope2( */ if ((hEnvChan->encEnvData.hSbrBSGrid->frameClass == FIXFIX) && (ed->nEnvelopes == 1)) { + AMP_RES currentAmpResFF = SBR_AMP_RES_1_5; if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { - /* Note: global_tonaliy_float_value == + /* Note: global_tonality_float_value == ((float)hEnvChan->encEnvData.global_tonality/((INT64)(1)<<(31-(19+2)))/0.524288*(2.0/3.0))); threshold_float_value == ((float)h_con->thresholdAmpResFF_m/((INT64)(1)<<(31-(h_con->thresholdAmpResFF_e)))/0.524288*(2.0/3.0))); @@ -1289,14 +1291,13 @@ void FDKsbrEnc_extractSbrEnvelope2( } else { hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_3_0; } - } else - hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_1_5; + currentAmpResFF = hEnvChan->encEnvData.currentAmpResFF; + } - if (hEnvChan->encEnvData.currentAmpResFF != - hEnvChan->encEnvData.init_sbr_amp_res) { + if (currentAmpResFF != hEnvChan->encEnvData.init_sbr_amp_res) { FDKsbrEnc_InitSbrHuffmanTables( &hEnvChan->encEnvData, &hEnvChan->sbrCodeEnvelope, - &hEnvChan->sbrCodeNoiseFloor, hEnvChan->encEnvData.currentAmpResFF); + &hEnvChan->sbrCodeNoiseFloor, currentAmpResFF); } } else { if (sbrHeaderData->sbr_amp_res != hEnvChan->encEnvData.init_sbr_amp_res) { @@ -1355,6 +1356,13 @@ void FDKsbrEnc_extractSbrEnvelope2( } } + if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY && + stereoMode == SBR_SWITCH_LRC && + h_envChan[0]->encEnvData.currentAmpResFF != + h_envChan[1]->encEnvData.currentAmpResFF) { + stereoMode = SBR_LEFT_RIGHT; + } + /* Extract envelope of current frame. */ diff --git a/libSBRenc/src/sbr_encoder.cpp b/libSBRenc/src/sbr_encoder.cpp index df9e996..9f1ede2 100644 --- a/libSBRenc/src/sbr_encoder.cpp +++ b/libSBRenc/src/sbr_encoder.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -1450,8 +1450,6 @@ static INT initEnvChannel(HANDLE_SBR_CONFIG_DATA sbrConfigData, params->deltaTAcrossFrames, 0, 0)) return (1); - sbrConfigData->initAmpResFF = params->init_amp_res_FF; - if (FDKsbrEnc_InitSbrHuffmanTables(&hEnv->encEnvData, &hEnv->sbrCodeEnvelope, &hEnv->sbrCodeNoiseFloor, sbrHeaderData->sbr_amp_res)) @@ -1749,6 +1747,7 @@ static INT FDKsbrEnc_EnvInit(HANDLE_SBR_ELEMENT hSbrElement, hSbrElement->sbrHeaderData.sbr_data_extra = 1; hSbrElement->sbrHeaderData.sbr_amp_res = (AMP_RES)params->amp_res; + hSbrElement->sbrConfigData.initAmpResFF = params->init_amp_res_FF; /* header_extra_1 */ hSbrElement->sbrHeaderData.freqScale = params->freqScale; From a4695298d6142f1dfe9cabb74432c40b635d36a6 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:08:34 +0200 Subject: [PATCH 48/78] Solve issue regarding config changes between Loudness-only vs. Loudness+DRC. Fix config changes from Loudness+DRC to Loudness-only configurations by clearing the DRC configuration Bug: 176246647 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I7afef848308478c29a82b13f24ba8c2a9760fd45 --- libAACdec/src/aacdecoder_lib.cpp | 17 +++++++++--- libMpegTPDec/src/tpdec_asc.cpp | 45 +++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index 90563ea..239896d 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -441,12 +441,23 @@ static INT aacDecoder_UniDrcCallback(void *handle, HANDLE_FDK_BITSTREAM hBs, TRANSPORTDEC_ERROR errTp; HANDLE_AACDECODER hAacDecoder = (HANDLE_AACDECODER)handle; DRC_DEC_CODEC_MODE drcDecCodecMode = DRC_DEC_CODEC_MODE_UNDEFINED; + UCHAR dummyBuffer[4] = {0}; + FDK_BITSTREAM dummyBs; + HANDLE_FDK_BITSTREAM hReadBs; if (subStreamIndex != 0) { return TRANSPORTDEC_OK; } - else if (aot == AOT_USAC) { + if (hBs == NULL) { + /* use dummy zero payload to clear memory */ + hReadBs = &dummyBs; + FDKinitBitStream(hReadBs, dummyBuffer, 4, 24); + } else { + hReadBs = hBs; + } + + if (aot == AOT_USAC) { drcDecCodecMode = DRC_DEC_MPEG_D_USAC; } @@ -455,10 +466,10 @@ static INT aacDecoder_UniDrcCallback(void *handle, HANDLE_FDK_BITSTREAM hBs, if (payloadType == 0) /* uniDrcConfig */ { - err = FDK_drcDec_ReadUniDrcConfig(hAacDecoder->hUniDrcDecoder, hBs); + err = FDK_drcDec_ReadUniDrcConfig(hAacDecoder->hUniDrcDecoder, hReadBs); } else /* loudnessInfoSet */ { - err = FDK_drcDec_ReadLoudnessInfoSet(hAacDecoder->hUniDrcDecoder, hBs); + err = FDK_drcDec_ReadLoudnessInfoSet(hAacDecoder->hUniDrcDecoder, hReadBs); hAacDecoder->loudnessInfoSetPosition[1] = payloadStart; hAacDecoder->loudnessInfoSetPosition[2] = fullPayloadLength; } diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp index a2baaaf..e46cb32 100644 --- a/libMpegTPDec/src/tpdec_asc.cpp +++ b/libMpegTPDec/src/tpdec_asc.cpp @@ -1778,6 +1778,10 @@ static TRANSPORTDEC_ERROR configExtension(CSUsacConfig *usc, int numConfigExtensions; CONFIG_EXT_ID usacConfigExtType; int usacConfigExtLength; + int loudnessInfoSetIndex = + -1; /* index of loudnessInfoSet config extension. -1 if not contained. */ + int tmp_subStreamIndex = 0; + AUDIO_OBJECT_TYPE tmp_aot = AOT_USAC; numConfigExtensions = (int)escapedValue(hBs, 2, 4, 8) + 1; for (int confExtIdx = 0; confExtIdx < numConfigExtensions; confExtIdx++) { @@ -1807,10 +1811,12 @@ static TRANSPORTDEC_ERROR configExtension(CSUsacConfig *usc, ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc( cb->cbUniDrcData, hBs, usacConfigExtLength, 1, /* loudnessInfoSet */ - 0, loudnessInfoSetConfigExtensionPosition, AOT_USAC); + tmp_subStreamIndex, loudnessInfoSetConfigExtensionPosition, + tmp_aot); if (ErrorStatus != TRANSPORTDEC_OK) { return ErrorStatus; } + loudnessInfoSetIndex = confExtIdx; } } break; default: @@ -1826,6 +1832,17 @@ static TRANSPORTDEC_ERROR configExtension(CSUsacConfig *usc, FDKpushFor(hBs, usacConfigExtLength); } + if (loudnessInfoSetIndex == -1 && cb->cbUniDrc != NULL) { + /* no loudnessInfoSet contained. Clear the loudnessInfoSet struct by feeding + * an empty config extension */ + ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc( + cb->cbUniDrcData, NULL, 0, 1 /* loudnessInfoSet */, tmp_subStreamIndex, + 0, tmp_aot); + if (ErrorStatus != TRANSPORTDEC_OK) { + return ErrorStatus; + } + } + return ErrorStatus; } @@ -1842,6 +1859,8 @@ static TRANSPORTDEC_ERROR UsacRsv60DecoderConfig_Parse( int channelElementIdx = 0; /* index for elements which contain audio channels (sce, cpe, lfe) */ SC_CHANNEL_CONFIG sc_chan_config = {0, 0, 0, 0}; + int uniDrcElement = + -1; /* index of uniDrc extension element. -1 if not contained. */ numberOfElements = (int)escapedValue(hBs, 4, 8, 16) + 1; usc->m_usacNumElements = numberOfElements; @@ -2017,6 +2036,10 @@ static TRANSPORTDEC_ERROR UsacRsv60DecoderConfig_Parse( case ID_USAC_EXT: ErrorStatus = extElementConfig(&usc->element[i].extElement, hBs, cb, 0, asc->m_samplesPerFrame, 0, asc->m_aot); + if (usc->element[i].extElement.usacExtElementType == + ID_EXT_ELE_UNI_DRC) { + uniDrcElement = i; + } if (ErrorStatus) { return ErrorStatus; @@ -2045,6 +2068,18 @@ static TRANSPORTDEC_ERROR UsacRsv60DecoderConfig_Parse( } } + if (uniDrcElement == -1 && cb->cbUniDrc != NULL) { + /* no uniDrcConfig contained. Clear the uniDrcConfig struct by feeding an + * empty extension element */ + int subStreamIndex = 0; + ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc( + cb->cbUniDrcData, NULL, 0, 0 /* uniDrcConfig */, subStreamIndex, 0, + asc->m_aot); + if (ErrorStatus != TRANSPORTDEC_OK) { + return ErrorStatus; + } + } + return ErrorStatus; } @@ -2131,6 +2166,14 @@ static TRANSPORTDEC_ERROR UsacConfig_Parse(CSAudioSpecificConfig *asc, if (err != TRANSPORTDEC_OK) { return err; } + } else if (cb->cbUniDrc != NULL) { + /* no loudnessInfoSet contained. Clear the loudnessInfoSet struct by feeding + * an empty config extension */ + err = (TRANSPORTDEC_ERROR)cb->cbUniDrc( + cb->cbUniDrcData, NULL, 0, 1 /* loudnessInfoSet */, 0, 0, asc->m_aot); + if (err != TRANSPORTDEC_OK) { + return err; + } } /* sanity check whether number of channels signaled in UsacDecoderConfig() From edbf93589b1786557383451f2d6d34fd85d8e73d Mon Sep 17 00:00:00 2001 From: Anuj Joshi Date: Fri, 27 Mar 2020 10:43:08 +0530 Subject: [PATCH 49/78] Stop using __DATE__/__TIME__ on all builds Test: mmma external/libaac Bug: 151595970 Change-Id: Icd937cad3e4e2f70a5486cca424544eb410be26f --- Android.bp | 1 + libAACdec/src/aacdecoder_lib.cpp | 2 +- libAACenc/src/aacenc_lib.cpp | 2 +- libDRCdec/src/FDK_drcDecLib.cpp | 2 +- libFDK/src/FDK_core.cpp | 2 +- libMpegTPDec/src/tpdec_lib.cpp | 2 +- libMpegTPEnc/src/tpenc_lib.cpp | 2 +- libPCMutils/src/version.h | 2 +- libSACdec/src/sac_dec_lib.cpp | 2 +- libSACenc/src/sacenc_lib.cpp | 2 +- libSBRdec/src/sbrdecoder.cpp | 2 +- libSBRenc/src/sbr_encoder.cpp | 2 +- 12 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Android.bp b/Android.bp index 1cf54fd..3f42c19 100644 --- a/Android.bp +++ b/Android.bp @@ -23,6 +23,7 @@ cc_library_static { "-Wuninitialized", "-Wno-self-assign", "-Wno-implicit-fallthrough", + "-DSUPPRESS_BUILD_DATE_INFO", ], sanitize: { misc_undefined:[ diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index 239896d..9d36d10 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -122,7 +122,7 @@ amm-info@iis.fraunhofer.de #define AACDECODER_LIB_VL1 2 #define AACDECODER_LIB_VL2 0 #define AACDECODER_LIB_TITLE "AAC Decoder Lib" -#ifdef __ANDROID__ +#ifdef SUPPRESS_BUILD_DATE_INFO #define AACDECODER_LIB_BUILD_DATE "" #define AACDECODER_LIB_BUILD_TIME "" #else diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp index 0217641..caa62c5 100644 --- a/libAACenc/src/aacenc_lib.cpp +++ b/libAACenc/src/aacenc_lib.cpp @@ -112,7 +112,7 @@ amm-info@iis.fraunhofer.de #define AACENCODER_LIB_VL1 0 #define AACENCODER_LIB_VL2 1 #define AACENCODER_LIB_TITLE "AAC Encoder" -#ifdef __ANDROID__ +#ifdef SUPPRESS_BUILD_DATE_INFO #define AACENCODER_LIB_BUILD_DATE "" #define AACENCODER_LIB_BUILD_TIME "" #else diff --git a/libDRCdec/src/FDK_drcDecLib.cpp b/libDRCdec/src/FDK_drcDecLib.cpp index 83b5773..26e5b78 100644 --- a/libDRCdec/src/FDK_drcDecLib.cpp +++ b/libDRCdec/src/FDK_drcDecLib.cpp @@ -112,7 +112,7 @@ amm-info@iis.fraunhofer.de #define DRCDEC_LIB_VL1 1 #define DRCDEC_LIB_VL2 0 #define DRCDEC_LIB_TITLE "MPEG-D DRC Decoder Lib" -#ifdef __ANDROID__ +#ifdef SUPPRESS_BUILD_DATE_INFO #define DRCDEC_LIB_BUILD_DATE "" #define DRCDEC_LIB_BUILD_TIME "" #else diff --git a/libFDK/src/FDK_core.cpp b/libFDK/src/FDK_core.cpp index 2f77179..48db17e 100644 --- a/libFDK/src/FDK_core.cpp +++ b/libFDK/src/FDK_core.cpp @@ -107,7 +107,7 @@ amm-info@iis.fraunhofer.de #define FDK_TOOLS_LIB_VL1 1 #define FDK_TOOLS_LIB_VL2 0 #define FDK_TOOLS_LIB_TITLE "FDK Tools" -#ifdef __ANDROID__ +#ifdef SUPPRESS_BUILD_DATE_INFO #define FDK_TOOLS_LIB_BUILD_DATE "" #define FDK_TOOLS_LIB_BUILD_TIME "" #else diff --git a/libMpegTPDec/src/tpdec_lib.cpp b/libMpegTPDec/src/tpdec_lib.cpp index ca35184..091d011 100644 --- a/libMpegTPDec/src/tpdec_lib.cpp +++ b/libMpegTPDec/src/tpdec_lib.cpp @@ -1769,7 +1769,7 @@ TRANSPORTDEC_ERROR transportDec_GetLibInfo(LIB_INFO *info) { info += i; info->module_id = FDK_TPDEC; -#ifdef __ANDROID__ +#ifdef SUPPRESS_BUILD_DATE_INFO info->build_date = ""; info->build_time = ""; #else diff --git a/libMpegTPEnc/src/tpenc_lib.cpp b/libMpegTPEnc/src/tpenc_lib.cpp index 14ea5fe..77c19b5 100644 --- a/libMpegTPEnc/src/tpenc_lib.cpp +++ b/libMpegTPEnc/src/tpenc_lib.cpp @@ -647,7 +647,7 @@ TRANSPORTENC_ERROR transportEnc_GetLibInfo(LIB_INFO *info) { info->module_id = FDK_TPENC; info->version = LIB_VERSION(TP_LIB_VL0, TP_LIB_VL1, TP_LIB_VL2); LIB_VERSION_STRING(info); -#ifdef __ANDROID__ +#ifdef SUPPRESS_BUILD_DATE_INFO info->build_date = ""; info->build_time = ""; #else diff --git a/libPCMutils/src/version.h b/libPCMutils/src/version.h index 05371f8..871aa90 100644 --- a/libPCMutils/src/version.h +++ b/libPCMutils/src/version.h @@ -108,7 +108,7 @@ amm-info@iis.fraunhofer.de #define PCMUTIL_LIB_VL1 1 #define PCMUTIL_LIB_VL2 0 #define PCMUTIL_LIB_TITLE "PCM Utility Lib" -#ifdef __ANDROID__ +#ifdef SUPPRESS_BUILD_DATE_INFO #define PCMUTIL_LIB_BUILD_DATE "" #define PCMUTIL_LIB_BUILD_TIME "" #else diff --git a/libSACdec/src/sac_dec_lib.cpp b/libSACdec/src/sac_dec_lib.cpp index da19bb8..d30131f 100644 --- a/libSACdec/src/sac_dec_lib.cpp +++ b/libSACdec/src/sac_dec_lib.cpp @@ -1819,7 +1819,7 @@ int mpegSurroundDecoder_GetLibInfo(LIB_INFO *info) { info += i; info->module_id = FDK_MPSDEC; -#ifdef __ANDROID__ +#ifdef SUPPRESS_BUILD_DATE_INFO info->build_date = ""; info->build_time = ""; #else diff --git a/libSACenc/src/sacenc_lib.cpp b/libSACenc/src/sacenc_lib.cpp index d6a1658..fcfe39b 100644 --- a/libSACenc/src/sacenc_lib.cpp +++ b/libSACenc/src/sacenc_lib.cpp @@ -130,7 +130,7 @@ Description of file contents #define SACENC_LIB_VL1 0 #define SACENC_LIB_VL2 0 #define SACENC_LIB_TITLE "MPEG Surround Encoder" -#ifdef __ANDROID__ +#ifdef SUPPRESS_BUILD_DATE_INFO #define SACENC_LIB_BUILD_DATE "" #define SACENC_LIB_BUILD_TIME "" #else diff --git a/libSBRdec/src/sbrdecoder.cpp b/libSBRdec/src/sbrdecoder.cpp index 55f929f..b101a4a 100644 --- a/libSBRdec/src/sbrdecoder.cpp +++ b/libSBRdec/src/sbrdecoder.cpp @@ -158,7 +158,7 @@ amm-info@iis.fraunhofer.de #define SBRDECODER_LIB_VL1 1 #define SBRDECODER_LIB_VL2 0 #define SBRDECODER_LIB_TITLE "SBR Decoder" -#ifdef __ANDROID__ +#ifdef SUPPRESS_BUILD_DATE_INFO #define SBRDECODER_LIB_BUILD_DATE "" #define SBRDECODER_LIB_BUILD_TIME "" #else diff --git a/libSBRenc/src/sbr_encoder.cpp b/libSBRenc/src/sbr_encoder.cpp index 9f1ede2..c3da072 100644 --- a/libSBRenc/src/sbr_encoder.cpp +++ b/libSBRenc/src/sbr_encoder.cpp @@ -2559,7 +2559,7 @@ INT sbrEncoder_GetLibInfo(LIB_INFO *info) { info->version = LIB_VERSION(SBRENCODER_LIB_VL0, SBRENCODER_LIB_VL1, SBRENCODER_LIB_VL2); LIB_VERSION_STRING(info); -#ifdef __ANDROID__ +#ifdef SUPPRESS_BUILD_DATE_INFO info->build_date = ""; info->build_time = ""; #else From 5a83a8e5e1cafceba6bef7ac61e68a57cc93d786 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 8 May 2020 16:40:06 +0200 Subject: [PATCH 50/78] Avoid signed integer overflow in pcmLimiter_Apply(). Bug: 186706541 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I89f5206053926cb2f8726e4bc1ffb9fc88371edb --- libPCMutils/src/limiter.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libPCMutils/src/limiter.cpp b/libPCMutils/src/limiter.cpp index 598dc0c..c6b8687 100644 --- a/libPCMutils/src/limiter.cpp +++ b/libPCMutils/src/limiter.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -322,7 +322,8 @@ TDLIMITER_ERROR pcmLimiter_Apply(TDLimiterPtr limiter, PCM_LIM* samplesIn, (FIXP_DBL)SATURATE_LEFT_SHIFT(tmp, scaling, DFRACT_BITS)); #else samplesOut[j] = (INT_PCM)FX_DBL2FX_PCM((FIXP_DBL)SATURATE_LEFT_SHIFT( - tmp + ((FIXP_DBL)0x8000 >> scaling), scaling, DFRACT_BITS)); + (tmp >> 1) + ((FIXP_DBL)0x8000 >> (scaling + 1)), scaling + 1, + DFRACT_BITS)); #endif } } From d8515f231fea359c20514dd3e36d104f1341b04d Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 8 May 2020 16:39:30 +0200 Subject: [PATCH 51/78] Use dynamic scaling depending on autocorr length to avoid signed integer overflow. Bug: 186706541 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: Ibc035ce2eafe4b0d98377d090adad77bbf5cbb5c --- libFDK/src/autocorr2nd.cpp | 43 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/libFDK/src/autocorr2nd.cpp b/libFDK/src/autocorr2nd.cpp index 718a555..8c5673c 100644 --- a/libFDK/src/autocorr2nd.cpp +++ b/libFDK/src/autocorr2nd.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -102,11 +102,6 @@ amm-info@iis.fraunhofer.de #include "autocorr2nd.h" -/* If the accumulator does not provide enough overflow bits, - products have to be shifted down in the autocorrelation below. */ -#define SHIFT_FACTOR (5) -#define SHIFT >> (SHIFT_FACTOR) - /*! * * \brief Calculate second order autocorrelation using 2 accumulators @@ -126,45 +121,49 @@ INT autoCorr2nd_real( const FIXP_DBL *realBuf = reBuffer; + const int len_scale = fMax(DFRACT_BITS - fNormz((FIXP_DBL)(len / 2)), 1); /* r11r,r22r r01r,r12r r02r */ pReBuf = realBuf - 2; - accu5 = ((fMultDiv2(pReBuf[0], pReBuf[2]) + fMultDiv2(pReBuf[1], pReBuf[3])) - SHIFT); + accu5 = + ((fMultDiv2(pReBuf[0], pReBuf[2]) + fMultDiv2(pReBuf[1], pReBuf[3])) >> + len_scale); pReBuf++; /* len must be even */ - accu1 = fPow2Div2(pReBuf[0]) SHIFT; - accu3 = fMultDiv2(pReBuf[0], pReBuf[1]) SHIFT; + accu1 = fPow2Div2(pReBuf[0]) >> len_scale; + accu3 = fMultDiv2(pReBuf[0], pReBuf[1]) >> len_scale; pReBuf++; for (j = (len - 2) >> 1; j != 0; j--, pReBuf += 2) { - accu1 += ((fPow2Div2(pReBuf[0]) + fPow2Div2(pReBuf[1])) SHIFT); + accu1 += ((fPow2Div2(pReBuf[0]) + fPow2Div2(pReBuf[1])) >> len_scale); - accu3 += ((fMultDiv2(pReBuf[0], pReBuf[1]) + - fMultDiv2(pReBuf[1], pReBuf[2])) SHIFT); + accu3 += + ((fMultDiv2(pReBuf[0], pReBuf[1]) + fMultDiv2(pReBuf[1], pReBuf[2])) >> + len_scale); - accu5 += ((fMultDiv2(pReBuf[0], pReBuf[2]) + - fMultDiv2(pReBuf[1], pReBuf[3])) SHIFT); + accu5 += + ((fMultDiv2(pReBuf[0], pReBuf[2]) + fMultDiv2(pReBuf[1], pReBuf[3])) >> + len_scale); } - accu2 = (fPow2Div2(realBuf[-2]) SHIFT); + accu2 = (fPow2Div2(realBuf[-2]) >> len_scale); accu2 += accu1; - accu1 += (fPow2Div2(realBuf[len - 2]) SHIFT); + accu1 += (fPow2Div2(realBuf[len - 2]) >> len_scale); - accu4 = (fMultDiv2(realBuf[-1], realBuf[-2]) SHIFT); + accu4 = (fMultDiv2(realBuf[-1], realBuf[-2]) >> len_scale); accu4 += accu3; - accu3 += (fMultDiv2(realBuf[len - 1], realBuf[len - 2]) SHIFT); + accu3 += (fMultDiv2(realBuf[len - 1], realBuf[len - 2]) >> len_scale); mScale = CntLeadingZeros( (accu1 | accu2 | fAbs(accu3) | fAbs(accu4) | fAbs(accu5))) - 1; - autoCorrScaling = mScale - 1 - SHIFT_FACTOR; /* -1 because of fMultDiv2*/ + autoCorrScaling = mScale - 1 - len_scale; /* -1 because of fMultDiv2*/ /* Scale to common scale factor */ ac->r11r = accu1 << mScale; @@ -190,7 +189,7 @@ INT autoCorr2nd_cplx( const FIXP_DBL *imBuffer, /*!< Pointer to imag part of input samples */ const int len /*!< Number of input samples (should be smaller than 128) */ ) { - int j, autoCorrScaling, mScale, len_scale; + int j, autoCorrScaling, mScale; FIXP_DBL accu0, accu1, accu2, accu3, accu4, accu5, accu6, accu7, accu8; @@ -199,7 +198,7 @@ INT autoCorr2nd_cplx( const FIXP_DBL *realBuf = reBuffer; const FIXP_DBL *imagBuf = imBuffer; - (len > 64) ? (len_scale = 6) : (len_scale = 5); + const int len_scale = fMax(DFRACT_BITS - fNormz((FIXP_DBL)len), 1); /* r00r, r11r,r22r From 0527875be6340013e933a26e296211999f5377cb Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:42:02 +0100 Subject: [PATCH 52/78] Follow-up on: Improve decoder robustness by storing flags and elFlags temporarily. Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I2aef40ef1868832cd00e4d761b060aa41b1b7efa --- libAACdec/src/aacdecoder.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp index c18e5e9..7c16d2a 100644 --- a/libAACdec/src/aacdecoder.cpp +++ b/libAACdec/src/aacdecoder.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -1417,11 +1417,7 @@ static void CAacDecoder_AcceptFlags(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, UINT flags, UINT *elFlags, int streamIndex, int elementOffset) { - { - FDKmemcpy( - self->elFlags, elFlags, - sizeof(*elFlags) * (3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1)); - } + FDKmemcpy(self->elFlags, elFlags, sizeof(self->elFlags)); self->flags[streamIndex] = flags; } @@ -1524,6 +1520,8 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, INT flushChannels = 0; UINT flags; + /* elFlags[(3*MAX_CHANNELS + (MAX_CHANNELS)/2 + 4 * (MAX_TRACKS) + 1] + where MAX_CHANNELS is (8*2) and MAX_TRACKS is 1 */ UINT elFlags[(3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1)]; if (!self) return AAC_DEC_INVALID_HANDLE; From e15d049ded8996e1b789b26d3d3c2a8fcc0128e5 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:42:35 +0100 Subject: [PATCH 53/78] Use local variables for sbr and mps state in CAacDecoder_Init() to avoid inconsistencies in case of failing initialization. Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: Ic767aeb63cdc7d4556bc68cee0c4f7aeba05d12f --- libAACdec/src/aacdecoder.cpp | 39 +++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp index 7c16d2a..fcf51b5 100644 --- a/libAACdec/src/aacdecoder.cpp +++ b/libAACdec/src/aacdecoder.cpp @@ -1524,6 +1524,10 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, where MAX_CHANNELS is (8*2) and MAX_TRACKS is 1 */ UINT elFlags[(3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1)]; + UCHAR sbrEnabled = self->sbrEnabled; + UCHAR sbrEnabledPrev = self->sbrEnabledPrev; + UCHAR mpsEnableCurr = self->mpsEnableCurr; + if (!self) return AAC_DEC_INVALID_HANDLE; UCHAR downscaleFactor = self->downscaleFactor; @@ -1707,7 +1711,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, asc->m_sc.m_usacConfig.m_usacNumElements; } - self->mpsEnableCurr = 0; + mpsEnableCurr = 0; for (int _el = 0; _el < (int)self->pUsacConfig[streamIndex]->m_usacNumElements; _el++) { @@ -1727,7 +1731,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, self->usacStereoConfigIndex[el] = asc->m_sc.m_usacConfig.element[_el].m_stereoConfigIndex; if (self->elements[el] == ID_USAC_CPE) { - self->mpsEnableCurr |= self->usacStereoConfigIndex[el] ? 1 : 0; + mpsEnableCurr |= self->usacStereoConfigIndex[el] ? 1 : 0; } } @@ -1863,7 +1867,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, self->useLdQmfTimeAlign = asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign; } - if (self->sbrEnabled != asc->m_sbrPresentFlag) { + if (sbrEnabled != asc->m_sbrPresentFlag) { ascChanged = 1; } } @@ -1879,13 +1883,13 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, flags |= (asc->m_sbrPresentFlag) ? AC_SBR_PRESENT : 0; flags |= (asc->m_psPresentFlag) ? AC_PS_PRESENT : 0; if (asc->m_sbrPresentFlag) { - self->sbrEnabled = 1; - self->sbrEnabledPrev = 1; + sbrEnabled = 1; + sbrEnabledPrev = 1; } else { - self->sbrEnabled = 0; - self->sbrEnabledPrev = 0; + sbrEnabled = 0; + sbrEnabledPrev = 0; } - if (self->sbrEnabled && asc->m_extensionSamplingFrequency) { + if (sbrEnabled && asc->m_extensionSamplingFrequency) { if (downscaleFactor != 1 && (downscaleFactor)&1) { return AAC_DEC_UNSUPPORTED_SAMPLINGRATE; /* SBR needs an even downscale factor */ @@ -1912,7 +1916,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, flags |= (asc->m_hcrFlag) ? AC_ER_HCR : 0; if (asc->m_aot == AOT_ER_AAC_ELD) { - self->mpsEnableCurr = 0; + mpsEnableCurr = 0; flags |= AC_ELD; flags |= (asc->m_sbrPresentFlag) ? AC_SBR_PRESENT @@ -1923,7 +1927,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, ? AC_MPS_PRESENT : 0; if (self->mpsApplicable) { - self->mpsEnableCurr = asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign; + mpsEnableCurr = asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign; } } flags |= (asc->m_aot == AOT_ER_AAC_LD) ? AC_LD : 0; @@ -2004,7 +2008,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, /* set AC_USAC_SCFGI3 globally if any usac element uses */ switch (asc->m_aot) { case AOT_USAC: - if (self->sbrEnabled) { + if (sbrEnabled) { for (int _el = 0; _el < (int)self->pUsacConfig[streamIndex]->m_usacNumElements; _el++) { @@ -2041,7 +2045,7 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, */ switch (asc->m_aot) { case AOT_USAC: - if (self->sbrEnabled) { + if (sbrEnabled) { const UCHAR map_sbrRatio_2_nAnaBands[] = {16, 24, 32}; FDK_ASSERT(asc->m_sc.m_usacConfig.m_sbrRatioIndex > 0); @@ -2069,11 +2073,11 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, } break; case AOT_ER_AAC_ELD: - if (self->mpsEnableCurr && + if (mpsEnableCurr && asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign) { - SAC_INPUT_CONFIG sac_interface = - (self->sbrEnabled && self->hSbrDecoder) ? SAC_INTERFACE_QMF - : SAC_INTERFACE_TIME; + SAC_INPUT_CONFIG sac_interface = (sbrEnabled && self->hSbrDecoder) + ? SAC_INTERFACE_QMF + : SAC_INTERFACE_TIME; mpegSurroundDecoder_ConfigureQmfDomain( (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, sac_interface, (UINT)self->streamInfo.aacSampleRate, asc->m_aot); @@ -2428,6 +2432,9 @@ CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc, CAacDecoder_AcceptFlags(self, asc, flags, elFlags, streamIndex, elementOffset); + self->sbrEnabled = sbrEnabled; + self->sbrEnabledPrev = sbrEnabledPrev; + self->mpsEnableCurr = mpsEnableCurr; /* Update externally visible copy of flags */ self->streamInfo.flags = self->flags[0]; From cab99f4b6a45de02a3b6d010cef4443a4a249f88 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:43:10 +0100 Subject: [PATCH 54/78] Perform parameter check before parameter assignment to avoid incorrect initialization in resetFreqBandTables(). Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I5af625905b1e4365fa84423d186c227a49707f72 --- libSBRdec/src/sbrdec_freq_sca.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libSBRdec/src/sbrdec_freq_sca.cpp b/libSBRdec/src/sbrdec_freq_sca.cpp index e187656..daa3554 100644 --- a/libSBRdec/src/sbrdec_freq_sca.cpp +++ b/libSBRdec/src/sbrdec_freq_sca.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -765,9 +765,6 @@ resetFreqBandTables(HANDLE_SBR_HEADER_DATA hHeaderData, const UINT flags) { sbrdecUpdateLoRes(hFreq->freqBandTable[0], &nBandsLo, hFreq->freqBandTable[1], nBandsHi); - hFreq->nSfb[0] = nBandsLo; - hFreq->nSfb[1] = nBandsHi; - /* Check index to freqBandTable[0] */ if (!(nBandsLo > 0) || (nBandsLo > (((hHeaderData->numberOfAnalysisBands == 16) @@ -777,6 +774,9 @@ resetFreqBandTables(HANDLE_SBR_HEADER_DATA hHeaderData, const UINT flags) { return SBRDEC_UNSUPPORTED_CONFIG; } + hFreq->nSfb[0] = nBandsLo; + hFreq->nSfb[1] = nBandsHi; + lsb = hFreq->freqBandTable[0][0]; usb = hFreq->freqBandTable[0][nBandsLo]; @@ -814,15 +814,15 @@ resetFreqBandTables(HANDLE_SBR_HEADER_DATA hHeaderData, const UINT flags) { if (intTemp == 0) intTemp = 1; + if (intTemp > MAX_NOISE_COEFFS) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + hFreq->nNfb = intTemp; } hFreq->nInvfBands = hFreq->nNfb; - if (hFreq->nNfb > MAX_NOISE_COEFFS) { - return SBRDEC_UNSUPPORTED_CONFIG; - } - /* Get noise bands */ sbrdecDownSampleLoRes(hFreq->freqBandTableNoise, hFreq->nNfb, hFreq->freqBandTable[0], nBandsLo); From a1edc32174933c375f84f202dddadd5dfb862060 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:43:32 +0100 Subject: [PATCH 55/78] Sbr syncstate may only be set to upsampling if the sbr decoder was sucessfully initialized. Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I92f7c559af961ec063bfea74353f11092dcda653 --- libSBRdec/src/sbrdecoder.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/libSBRdec/src/sbrdecoder.cpp b/libSBRdec/src/sbrdecoder.cpp index b101a4a..7718695 100644 --- a/libSBRdec/src/sbrdecoder.cpp +++ b/libSBRdec/src/sbrdecoder.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -961,8 +961,10 @@ SBR_ERROR sbrDecoder_SetParam(HANDLE_SBRDECODER self, const SBRDEC_PARAM param, /* 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; + if (hSbrHeader->syncState != SBR_NOT_INITIALIZED) { + hSbrHeader->syncState = UPSAMPLING; + hSbrHeader->status |= SBRDEC_HDR_STAT_UPDATE; + } } } } break; @@ -1371,7 +1373,9 @@ SBR_ERROR sbrDecoder_Parse(HANDLE_SBRDECODER self, HANDLE_FDK_BITSTREAM hBs, } if (headerStatus == HEADER_ERROR) { /* Corrupt SBR info data, do not decode and switch to UPSAMPLING */ - hSbrHeader->syncState = UPSAMPLING; + hSbrHeader->syncState = hSbrHeader->syncState > UPSAMPLING + ? UPSAMPLING + : hSbrHeader->syncState; fDoDecodeSbrData = 0; sbrHeaderPresent = 0; } @@ -1610,7 +1614,9 @@ static SBR_ERROR sbrDecoder_DecodeElement( /* No valid SBR payload available, hence switch to upsampling (in all * headers) */ for (hdrIdx = 0; hdrIdx < ((1) + 1); hdrIdx += 1) { - self->sbrHeader[elementIndex][hdrIdx].syncState = UPSAMPLING; + if (self->sbrHeader[elementIndex][hdrIdx].syncState > UPSAMPLING) { + self->sbrHeader[elementIndex][hdrIdx].syncState = UPSAMPLING; + } } } else { /* Move frame pointer to the next slot which is up to be decoded/applied From 27c3a2bd1cc08b0096813474410c667468077d6e Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:47:41 +0100 Subject: [PATCH 56/78] Check the number of available escapes in rvlcDecodeBackward() to avoid out-of-bounds access. Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I42956a9fd7a8e78c3c0f4f553370ac5a9f1ac2ca --- libAACdec/src/rvlc.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/libAACdec/src/rvlc.cpp b/libAACdec/src/rvlc.cpp index b7a9be1..0b80364 100644 --- a/libAACdec/src/rvlc.cpp +++ b/libAACdec/src/rvlc.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -628,7 +628,7 @@ static void rvlcDecodeBackward(CErRvlcInfo *pRvlc, SHORT *pScfBwd = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd; SHORT *pScfEsc = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfEsc; - UCHAR *pEscEscCnt = &(pRvlc->numDecodedEscapeWordsEsc); + UCHAR escEscCnt = pRvlc->numDecodedEscapeWordsEsc; UCHAR *pEscBwdCnt = &(pRvlc->numDecodedEscapeWordsBwd); pRvlc->pRvlBitCnt_RVL = &(pRvlc->length_of_rvlc_sf_bwd); @@ -636,7 +636,7 @@ static void rvlcDecodeBackward(CErRvlcInfo *pRvlc, *pEscBwdCnt = 0; pRvlc->direction = BWD; - pScfEsc += *pEscEscCnt - 1; /* set pScfEsc to last entry */ + pScfEsc += escEscCnt - 1; /* set pScfEsc to last entry */ pRvlc->firstScf = 0; pRvlc->firstNrg = 0; pRvlc->firstIs = 0; @@ -651,7 +651,7 @@ static void rvlcDecodeBackward(CErRvlcInfo *pRvlc, } dpcm -= TABLE_OFFSET; if ((dpcm == MIN_RVL) || (dpcm == MAX_RVL)) { - if (pRvlc->length_of_rvlc_escapes) { + if ((pRvlc->length_of_rvlc_escapes) || (*pEscBwdCnt >= escEscCnt)) { pRvlc->conceal_min = bnds; return; } else { @@ -694,7 +694,7 @@ static void rvlcDecodeBackward(CErRvlcInfo *pRvlc, } dpcm -= TABLE_OFFSET; if ((dpcm == MIN_RVL) || (dpcm == MAX_RVL)) { - if (pRvlc->length_of_rvlc_escapes) { + if ((pRvlc->length_of_rvlc_escapes) || (*pEscBwdCnt >= escEscCnt)) { pScfBwd[bnds] = position; pRvlc->conceal_min = fMax(0, bnds - offset); return; @@ -731,7 +731,8 @@ static void rvlcDecodeBackward(CErRvlcInfo *pRvlc, } dpcm -= TABLE_OFFSET; if ((dpcm == MIN_RVL) || (dpcm == MAX_RVL)) { - if (pRvlc->length_of_rvlc_escapes) { + if ((pRvlc->length_of_rvlc_escapes) || + (*pEscBwdCnt >= escEscCnt)) { pScfBwd[bnds] = noisenrg; pRvlc->conceal_min = fMax(0, bnds - offset); return; @@ -762,7 +763,7 @@ static void rvlcDecodeBackward(CErRvlcInfo *pRvlc, } dpcm -= TABLE_OFFSET; if ((dpcm == MIN_RVL) || (dpcm == MAX_RVL)) { - if (pRvlc->length_of_rvlc_escapes) { + if ((pRvlc->length_of_rvlc_escapes) || (*pEscBwdCnt >= escEscCnt)) { pScfBwd[bnds] = factor; pRvlc->conceal_min = fMax(0, bnds - offset); return; From 14db264786fdd4fa837662c07f6a63458ce3de48 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:47:58 +0100 Subject: [PATCH 57/78] Avoid integer overflows in CLatmDemux_ReadAuChunkLengthInfo() and FDK_get32() to prevent endless loop. Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: Icaedd341f4602882f72ff5e7be71d99ce08f3bec --- libMpegTPDec/src/tpdec_latm.cpp | 41 +++++++++++++++++---------------- libMpegTPDec/src/tpdec_latm.h | 4 +--- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/libMpegTPDec/src/tpdec_latm.cpp b/libMpegTPDec/src/tpdec_latm.cpp index 3b71db8..c32be54 100644 --- a/libMpegTPDec/src/tpdec_latm.cpp +++ b/libMpegTPDec/src/tpdec_latm.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -591,6 +591,18 @@ bail: return (ErrorStatus); } +static int CLatmDemux_ReadAuChunkLengthInfo(HANDLE_FDK_BITSTREAM bs) { + int len = 0, tmp = 255; + int validBytes = (int)FDKgetValidBits(bs) >> 3; + + while (tmp == 255 && validBytes-- > 0) { + tmp = (int)FDKreadBits(bs, 8); + len += tmp; + } + + return ((tmp == 255) ? -1 : (len << 3)); +} + TRANSPORTDEC_ERROR CLatmDemux_ReadPayloadLengthInfo(HANDLE_FDK_BITSTREAM bs, CLatmDemux *pLatmDemux) { TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; @@ -602,11 +614,17 @@ TRANSPORTDEC_ERROR CLatmDemux_ReadPayloadLengthInfo(HANDLE_FDK_BITSTREAM bs, FDK_ASSERT(pLatmDemux->m_numLayer[prog] <= LATM_MAX_LAYER); for (UINT lay = 0; lay < pLatmDemux->m_numLayer[prog]; lay++) { LATM_LAYER_INFO *p_linfo = &pLatmDemux->m_linfo[prog][lay]; + int auChunkLengthInfo = 0; switch (p_linfo->m_frameLengthType) { case 0: - p_linfo->m_frameLengthInBits = CLatmDemux_ReadAuChunkLengthInfo(bs); - totalPayloadBits += p_linfo->m_frameLengthInBits; + auChunkLengthInfo = CLatmDemux_ReadAuChunkLengthInfo(bs); + if (auChunkLengthInfo >= 0) { + p_linfo->m_frameLengthInBits = (UINT)auChunkLengthInfo; + totalPayloadBits += p_linfo->m_frameLengthInBits; + } else { + return TRANSPORTDEC_PARSE_ERROR; + } break; case 3: case 5: @@ -627,23 +645,6 @@ TRANSPORTDEC_ERROR CLatmDemux_ReadPayloadLengthInfo(HANDLE_FDK_BITSTREAM bs, return (ErrorStatus); } -int CLatmDemux_ReadAuChunkLengthInfo(HANDLE_FDK_BITSTREAM bs) { - UCHAR endFlag; - int len = 0; - - do { - UCHAR tmp = (UCHAR)FDKreadBits(bs, 8); - endFlag = (tmp < 255); - - len += tmp; - - } while (endFlag == 0); - - len <<= 3; /* convert from bytes to bits */ - - return len; -} - UINT CLatmDemux_GetFrameLengthInBits(CLatmDemux *pLatmDemux, const UINT prog, const UINT layer) { UINT nFrameLenBits = 0; diff --git a/libMpegTPDec/src/tpdec_latm.h b/libMpegTPDec/src/tpdec_latm.h index 6af553d..8b8c971 100644 --- a/libMpegTPDec/src/tpdec_latm.h +++ b/libMpegTPDec/src/tpdec_latm.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -151,8 +151,6 @@ typedef struct { AudioPreRoll */ } CLatmDemux; -int CLatmDemux_ReadAuChunkLengthInfo(HANDLE_FDK_BITSTREAM bs); - TRANSPORTDEC_ERROR CLatmDemux_Read(HANDLE_FDK_BITSTREAM bs, CLatmDemux *pLatmDemux, TRANSPORT_TYPE tt, CSTpCallBacks *pTpDecCallbacks, From 9a9d260375879ec8b9bb36c6967bcdac626e7054 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:48:20 +0100 Subject: [PATCH 58/78] Validate whether all PCE listed element instance tags are present in raw_data_block. Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I299d3c11ffa65a7c09c437cd114d62b8d3013e2f --- libAACdec/src/aacdecoder.cpp | 87 ++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp index fcf51b5..d5f0cea 100644 --- a/libAACdec/src/aacdecoder.cpp +++ b/libAACdec/src/aacdecoder.cpp @@ -494,6 +494,75 @@ static AAC_DECODER_ERROR CDataStreamElement_Read(HANDLE_AACDECODER self, return error; } +static INT findElementInstanceTag( + INT elementTag, MP4_ELEMENT_ID elementId, + CAacDecoderChannelInfo **pAacDecoderChannelInfo, INT nChannels, + MP4_ELEMENT_ID *pElementIdTab, INT nElements) { + int el, chCnt = 0; + + for (el = 0; el < nElements; el++) { + switch (pElementIdTab[el]) { + case ID_CPE: + case ID_SCE: + case ID_LFE: + if ((elementTag == pAacDecoderChannelInfo[chCnt]->ElementInstanceTag) && + (elementId == pElementIdTab[el])) { + return 1; /* element instance tag found */ + } + chCnt += (pElementIdTab[el] == ID_CPE) ? 2 : 1; + break; + default: + break; + } + if (chCnt >= nChannels) break; + if (pElementIdTab[el] == ID_END) break; + } + + return 0; /* element instance tag not found */ +} + +static INT validateElementInstanceTags( + CProgramConfig *pce, CAacDecoderChannelInfo **pAacDecoderChannelInfo, + INT nChannels, MP4_ELEMENT_ID *pElementIdTab, INT nElements) { + if (nChannels >= pce->NumChannels) { + for (int el = 0; el < pce->NumFrontChannelElements; el++) { + if (!findElementInstanceTag(pce->FrontElementTagSelect[el], + pce->FrontElementIsCpe[el] ? ID_CPE : ID_SCE, + pAacDecoderChannelInfo, nChannels, + pElementIdTab, nElements)) { + return 0; /* element instance tag not in raw_data_block() */ + } + } + for (int el = 0; el < pce->NumSideChannelElements; el++) { + if (!findElementInstanceTag(pce->SideElementTagSelect[el], + pce->SideElementIsCpe[el] ? ID_CPE : ID_SCE, + pAacDecoderChannelInfo, nChannels, + pElementIdTab, nElements)) { + return 0; /* element instance tag not in raw_data_block() */ + } + } + for (int el = 0; el < pce->NumBackChannelElements; el++) { + if (!findElementInstanceTag(pce->BackElementTagSelect[el], + pce->BackElementIsCpe[el] ? ID_CPE : ID_SCE, + pAacDecoderChannelInfo, nChannels, + pElementIdTab, nElements)) { + return 0; /* element instance tag not in raw_data_block() */ + } + } + for (int el = 0; el < pce->NumLfeChannelElements; el++) { + if (!findElementInstanceTag(pce->LfeElementTagSelect[el], ID_LFE, + pAacDecoderChannelInfo, nChannels, + pElementIdTab, nElements)) { + return 0; /* element instance tag not in raw_data_block() */ + } + } + } else { + return 0; /* too less decoded audio channels */ + } + + return 1; /* all element instance tags found in raw_data_block() */ +} + /*! \brief Read Program Config Element @@ -2973,6 +3042,24 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( } /* while ( (type != ID_END) ... ) */ + if (!(self->flags[streamIndex] & + (AC_USAC | AC_RSVD50 | AC_RSV603DA | AC_BSAC | AC_LD | AC_ELD | AC_ER | + AC_SCALABLE)) && + (self->streamInfo.channelConfig == 0) && pce->isValid && + (ErrorStatus == AAC_DEC_OK) && self->frameOK && + !(flags & (AACDEC_CONCEAL | AACDEC_FLUSH))) { + /* Check whether all PCE listed element instance tags are present in + * raw_data_block() */ + if (!validateElementInstanceTags( + &self->pce, self->pAacDecoderChannelInfo, aacChannels, + channel_elements, + fMin(channel_element_count, (int)(sizeof(channel_elements) / + sizeof(*channel_elements))))) { + ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; + self->frameOK = 0; + } + } + if (!(flags & (AACDEC_CONCEAL | AACDEC_FLUSH))) { /* float decoder checks if bitsLeft is in range 0-7; only prerollAUs are * byteAligned with respect to the first bit */ From 76104a5431c7753df108e410c805aefefac16cf1 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 8 May 2020 16:40:06 +0200 Subject: [PATCH 59/78] Avoid signed integer overflow in pcmLimiter_Apply(). Bug: 186706541 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I89f5206053926cb2f8726e4bc1ffb9fc88371edb (cherry picked from commit 5a83a8e5e1cafceba6bef7ac61e68a57cc93d786) --- libPCMutils/src/limiter.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libPCMutils/src/limiter.cpp b/libPCMutils/src/limiter.cpp index 598dc0c..c6b8687 100644 --- a/libPCMutils/src/limiter.cpp +++ b/libPCMutils/src/limiter.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -322,7 +322,8 @@ TDLIMITER_ERROR pcmLimiter_Apply(TDLimiterPtr limiter, PCM_LIM* samplesIn, (FIXP_DBL)SATURATE_LEFT_SHIFT(tmp, scaling, DFRACT_BITS)); #else samplesOut[j] = (INT_PCM)FX_DBL2FX_PCM((FIXP_DBL)SATURATE_LEFT_SHIFT( - tmp + ((FIXP_DBL)0x8000 >> scaling), scaling, DFRACT_BITS)); + (tmp >> 1) + ((FIXP_DBL)0x8000 >> (scaling + 1)), scaling + 1, + DFRACT_BITS)); #endif } } From 1f5fac767af24805fbd9e25bd5d6a719e8a1e3cc Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:13:35 +0200 Subject: [PATCH 60/78] Adjust data types to prevent load of invalid value Adjust usacExtElementType data type to prevent load of invalid value in extElementConfig(). Adjust usacConfigExtType data type to prevent load of invalid value in configExtension(). Bug: 186706541 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: Ide15daa73c084c4a2cfc9d0f36bd7666fa6bac7a --- libMpegTPDec/src/tpdec_asc.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp index e46cb32..8f77017 100644 --- a/libMpegTPDec/src/tpdec_asc.cpp +++ b/libMpegTPDec/src/tpdec_asc.cpp @@ -1694,8 +1694,7 @@ static TRANSPORTDEC_ERROR extElementConfig(CSUsacExtElementConfig *extElement, const AUDIO_OBJECT_TYPE aot) { TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; - USAC_EXT_ELEMENT_TYPE usacExtElementType = - (USAC_EXT_ELEMENT_TYPE)escapedValue(hBs, 4, 8, 16); + UINT usacExtElementType = escapedValue(hBs, 4, 8, 16); /* recurve extension elements which are invalid for USAC */ if (aot == AOT_USAC) { @@ -1712,7 +1711,6 @@ static TRANSPORTDEC_ERROR extElementConfig(CSUsacExtElementConfig *extElement, } } - extElement->usacExtElementType = usacExtElementType; int usacExtElementConfigLength = escapedValue(hBs, 4, 8, 16); extElement->usacExtElementConfigLength = (USHORT)usacExtElementConfigLength; INT bsAnchor; @@ -1746,8 +1744,10 @@ static TRANSPORTDEC_ERROR extElementConfig(CSUsacExtElementConfig *extElement, } } break; default: + usacExtElementType = ID_EXT_ELE_UNKNOWN; break; } + extElement->usacExtElementType = (USAC_EXT_ELEMENT_TYPE)usacExtElementType; /* Adjust bit stream position. This is required because of byte alignment and * unhandled extensions. */ @@ -1776,7 +1776,7 @@ static TRANSPORTDEC_ERROR configExtension(CSUsacConfig *usc, TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; int numConfigExtensions; - CONFIG_EXT_ID usacConfigExtType; + UINT usacConfigExtType; int usacConfigExtLength; int loudnessInfoSetIndex = -1; /* index of loudnessInfoSet config extension. -1 if not contained. */ @@ -1787,7 +1787,7 @@ static TRANSPORTDEC_ERROR configExtension(CSUsacConfig *usc, for (int confExtIdx = 0; confExtIdx < numConfigExtensions; confExtIdx++) { INT nbits; int loudnessInfoSetConfigExtensionPosition = FDKgetValidBits(hBs); - usacConfigExtType = (CONFIG_EXT_ID)escapedValue(hBs, 4, 8, 16); + usacConfigExtType = escapedValue(hBs, 4, 8, 16); usacConfigExtLength = (int)escapedValue(hBs, 4, 8, 16); /* Start bit position of config extension */ From de5b6b5defb0e95d98de0e6895a3807e1ae5a4cf Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:14:36 +0200 Subject: [PATCH 61/78] Avoid load of undefined SPATIALDEC_TREE_CONFIG enum value. Bug: 186706541 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: Ibf8dbc1e61ff0453ac905efc88892d39c84fece6 --- libSACdec/src/sac_bitdec.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/libSACdec/src/sac_bitdec.cpp b/libSACdec/src/sac_bitdec.cpp index 4485ccf..25b3d9e 100644 --- a/libSACdec/src/sac_bitdec.cpp +++ b/libSACdec/src/sac_bitdec.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -488,12 +488,17 @@ SACDEC_ERROR SpatialDecParseSpecificConfig( pSpatialSpecificConfig->freqRes = (SPATIALDEC_FREQ_RES)freqResTable_LD[bsFreqRes]; - pSpatialSpecificConfig->treeConfig = - (SPATIALDEC_TREE_CONFIG)FDKreadBits(bitstream, 4); + { + UINT treeConfig = FDKreadBits(bitstream, 4); - if (pSpatialSpecificConfig->treeConfig != SPATIALDEC_MODE_RSVD7) { - err = MPS_UNSUPPORTED_CONFIG; - goto bail; + switch (treeConfig) { + case SPATIALDEC_MODE_RSVD7: + pSpatialSpecificConfig->treeConfig = (SPATIALDEC_TREE_CONFIG)treeConfig; + break; + default: + err = MPS_UNSUPPORTED_CONFIG; + goto bail; + } } { From a43c9f8822c3066efc91de366bb1b3c3bf88387a Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:15:06 +0200 Subject: [PATCH 62/78] Prevent undefined values for CODING_SCHEME type in huff_decode(). Bug: 186706541 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I82da4a5660289d1c96888d48c315f96a4a5c1c2a --- libFDK/include/nlc_dec.h | 5 +---- libFDK/src/nlc_dec.cpp | 28 +++++++++++++--------------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/libFDK/include/nlc_dec.h b/libFDK/include/nlc_dec.h index cca97f1..aded569 100644 --- a/libFDK/include/nlc_dec.h +++ b/libFDK/include/nlc_dec.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -159,9 +159,6 @@ typedef enum { #ifndef HUFFDEC_PARAMS #define HUFFDEC_PARMS -#define PAIR_SHIFT 4 -#define PAIR_MASK 0xf - #define MAX_ENTRIES 168 #define HANDLE_HUFF_NODE const SHORT(*)[MAX_ENTRIES][2] diff --git a/libFDK/src/nlc_dec.cpp b/libFDK/src/nlc_dec.cpp index 6e98ce0..3733d98 100644 --- a/libFDK/src/nlc_dec.cpp +++ b/libFDK/src/nlc_dec.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -568,12 +568,12 @@ bail: static ERROR_t huff_decode(HANDLE_FDK_BITSTREAM strm, SCHAR* out_data_1, SCHAR* out_data_2, DATA_TYPE data_type, DIFF_TYPE diff_type_1, DIFF_TYPE diff_type_2, - int num_val, CODING_SCHEME* cdg_scheme, int ldMode) { + int num_val, PAIRING* pairing_scheme, int ldMode) { ERROR_t err = HUFFDEC_OK; + CODING_SCHEME coding_scheme = HUFF_1D; DIFF_TYPE diff_type; int i = 0; - ULONG data = 0; SCHAR pair_vec[28][2]; @@ -596,15 +596,13 @@ static ERROR_t huff_decode(HANDLE_FDK_BITSTREAM strm, SCHAR* out_data_1, int hufYY; /* Coding scheme */ - data = FDKreadBits(strm, 1); - *cdg_scheme = (CODING_SCHEME)(data << PAIR_SHIFT); + coding_scheme = (CODING_SCHEME)FDKreadBits(strm, 1); - if (*cdg_scheme >> PAIR_SHIFT == HUFF_2D) { + if (coding_scheme == HUFF_2D) { if ((out_data_1 != NULL) && (out_data_2 != NULL) && (ldMode == 0)) { - data = FDKreadBits(strm, 1); - *cdg_scheme = (CODING_SCHEME)(*cdg_scheme | data); + *pairing_scheme = (PAIRING)FDKreadBits(strm, 1); } else { - *cdg_scheme = (CODING_SCHEME)(*cdg_scheme | FREQ_PAIR); + *pairing_scheme = FREQ_PAIR; } } @@ -613,7 +611,7 @@ static ERROR_t huff_decode(HANDLE_FDK_BITSTREAM strm, SCHAR* out_data_1, hufYY2 = diff_type_2; } - switch (*cdg_scheme >> PAIR_SHIFT) { + switch (coding_scheme) { case HUFF_1D: p0_flag[0] = (diff_type_1 == DIFF_FREQ); p0_flag[1] = (diff_type_2 == DIFF_FREQ); @@ -634,7 +632,7 @@ static ERROR_t huff_decode(HANDLE_FDK_BITSTREAM strm, SCHAR* out_data_1, case HUFF_2D: - switch (*cdg_scheme & PAIR_MASK) { + switch (*pairing_scheme) { case FREQ_PAIR: if (out_data_1 != NULL) { @@ -843,7 +841,7 @@ ERROR_t EcDataPairDec(DECODER_TYPE DECODER, HANDLE_FDK_BITSTREAM strm, SCHAR* pDataVec[2] = {NULL, NULL}; DIFF_TYPE diff_type[2] = {DIFF_FREQ, DIFF_FREQ}; - CODING_SCHEME cdg_scheme = HUFF_1D; + PAIRING pairing = FREQ_PAIR; DIRECTION direction = BACKWARDS; switch (data_type) { @@ -959,7 +957,7 @@ ERROR_t EcDataPairDec(DECODER_TYPE DECODER, HANDLE_FDK_BITSTREAM strm, } /* Huffman decoding */ err = huff_decode(strm, pDataVec[0], pDataVec[1], data_type, diff_type[0], - diff_type[1], dataBands, &cdg_scheme, + diff_type[1], dataBands, &pairing, (DECODER == SAOC_DECODER)); if (err != HUFFDEC_OK) { return HUFFDEC_NOTOK; @@ -986,8 +984,8 @@ ERROR_t EcDataPairDec(DECODER_TYPE DECODER, HANDLE_FDK_BITSTREAM strm, } } - mixed_time_pair = (diff_type[0] != diff_type[1]) && - ((cdg_scheme & PAIR_MASK) == TIME_PAIR); + mixed_time_pair = + (diff_type[0] != diff_type[1]) && (pairing == TIME_PAIR); if (direction == BACKWARDS) { if (diff_type[0] == DIFF_FREQ) { From ecc0e332069862da177c745137493545dd0cd63b Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 8 May 2020 16:40:31 +0200 Subject: [PATCH 63/78] Avoid signed integer overflow in combineSignalCplxScale2(). Bug: 186706541 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: Ie35e34d982c99f0e328f8f9251bba32c7da8518c --- libSACdec/src/sac_stp.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libSACdec/src/sac_stp.cpp b/libSACdec/src/sac_stp.cpp index b328c82..be332c7 100644 --- a/libSACdec/src/sac_stp.cpp +++ b/libSACdec/src/sac_stp.cpp @@ -252,12 +252,15 @@ inline void combineSignalCplxScale2(FIXP_DBL *hybOutputRealDry, int n; for (n = bands - 1; n >= 0; n--) { - *hybOutputRealDry = - *hybOutputRealDry + - (fMultDiv2(*hybOutputRealWet, scaleX) << (SF_SCALE + 1)); - *hybOutputImagDry = - *hybOutputImagDry + - (fMultDiv2(*hybOutputImagWet, scaleX) << (SF_SCALE + 1)); + *hybOutputRealDry = SATURATE_LEFT_SHIFT( + (*hybOutputRealDry >> 1) + + (fMultDiv2(*hybOutputRealWet, scaleX) << SF_SCALE), + 1, DFRACT_BITS); + *hybOutputImagDry = SATURATE_LEFT_SHIFT( + (*hybOutputImagDry >> 1) + + (fMultDiv2(*hybOutputImagWet, scaleX) << SF_SCALE), + 1, DFRACT_BITS); + ; hybOutputRealDry++, hybOutputRealWet++; hybOutputImagDry++, hybOutputImagWet++; } From 0e0a2f66d6dfa8bdb351c335c09b014f9e7014ed Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 8 May 2020 16:41:03 +0200 Subject: [PATCH 64/78] Revise synthesis QMF scaling for PS to avoid integer overflow in qmfSynPrototypeFirSlot(). Bug: 186706541 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I23ff345a1b1d0a8d125d49164fbd020387a37901 --- libSBRdec/src/sbr_dec.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/libSBRdec/src/sbr_dec.cpp b/libSBRdec/src/sbr_dec.cpp index b1fb0da..919e9bb 100644 --- a/libSBRdec/src/sbr_dec.cpp +++ b/libSBRdec/src/sbr_dec.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -713,7 +713,8 @@ void sbr_dec( } else { /* (flags & SBRDEC_PS_DECODED) */ INT sdiff; - INT scaleFactorHighBand, scaleFactorLowBand_ov, scaleFactorLowBand_no_ov; + INT scaleFactorHighBand, scaleFactorLowBand_ov, scaleFactorLowBand_no_ov, + outScalefactor, outScalefactorR, outScalefactorL; HANDLE_QMF_FILTER_BANK synQmf = &hSbrDec->qmfDomainOutCh->fb; HANDLE_QMF_FILTER_BANK synQmfRight = &hSbrDecRight->qmfDomainOutCh->fb; @@ -744,7 +745,7 @@ void sbr_dec( */ FDK_ASSERT(hSbrDec->qmfDomainInCh->pGlobalConf->nBandsSynthesis <= QMF_MAX_SYNTHESIS_BANDS); - qmfChangeOutScalefactor(synQmfRight, -(8)); + synQmfRight->outScalefactor = synQmf->outScalefactor; FDKmemcpy(synQmfRight->FilterStates, synQmf->FilterStates, 9 * hSbrDec->qmfDomainInCh->pGlobalConf->nBandsSynthesis * sizeof(FIXP_QSS)); @@ -788,9 +789,11 @@ void sbr_dec( FDKmemcpy(&hSbrDecRight->sbrDrcChannel, &hSbrDec->sbrDrcChannel, sizeof(SBRDEC_DRC_CHANNEL)); - for (i = 0; i < synQmf->no_col; i++) { /* ----- no_col loop ----- */ + outScalefactor = maxShift - (8); + outScalefactorL = outScalefactorR = + sbrInDataHeadroom + 1; /* +1: psDiffScale! (MPEG-PS) */ - INT outScalefactorR, outScalefactorL; + for (i = 0; i < synQmf->no_col; i++) { /* ----- no_col loop ----- */ /* qmf timeslot of right channel */ FIXP_DBL *rQmfReal = pWorkBuffer; @@ -815,27 +818,20 @@ void sbr_dec( ? scaleFactorLowBand_ov : scaleFactorLowBand_no_ov, scaleFactorHighBand, synQmf->lsb, synQmf->usb); - - outScalefactorL = outScalefactorR = - 1 + sbrInDataHeadroom; /* psDiffScale! (MPEG-PS) */ } sbrDecoder_drcApplySlot(/* right channel */ &hSbrDecRight->sbrDrcChannel, rQmfReal, rQmfImag, i, synQmfRight->no_col, maxShift); - outScalefactorR += maxShift; - sbrDecoder_drcApplySlot(/* left channel */ &hSbrDec->sbrDrcChannel, *(pLowBandReal + i), *(pLowBandImag + i), i, synQmf->no_col, maxShift); - outScalefactorL += maxShift; - if (!(flags & SBRDEC_SKIP_QMF_SYN)) { - qmfChangeOutScalefactor(synQmf, -(8)); - qmfChangeOutScalefactor(synQmfRight, -(8)); + qmfChangeOutScalefactor(synQmf, outScalefactor); + qmfChangeOutScalefactor(synQmfRight, outScalefactor); qmfSynthesisFilteringSlot( synQmfRight, rQmfReal, /* QMF real buffer */ From 5522e52e5a6efc569cb5607f38132b0619f5d655 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 8 May 2020 16:41:29 +0200 Subject: [PATCH 65/78] Prevent signed integer overflow in calc_qmfBufferReal(). Bug: 186706541 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I6d12fba9d958280ead368fcc4c6c5c79dc0111e2 --- libSBRdec/src/lpp_tran.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/libSBRdec/src/lpp_tran.cpp b/libSBRdec/src/lpp_tran.cpp index 93e1158..ed1a764 100644 --- a/libSBRdec/src/lpp_tran.cpp +++ b/libSBRdec/src/lpp_tran.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -220,19 +220,21 @@ static inline void calc_qmfBufferReal(FIXP_DBL **qmfBufferReal, const FIXP_DBL *const lowBandReal, const int startSample, const int stopSample, const UCHAR hiBand, - const int dynamicScale, const int descale, + const int dynamicScale, const FIXP_SGL a0r, const FIXP_SGL a1r) { - FIXP_DBL accu1, accu2; - int i; + const int dynscale = fixMax(0, dynamicScale - 1) + 1; + const int rescale = -fixMin(0, dynamicScale - 1) + 1; + const int descale = + fixMin(DFRACT_BITS - 1, LPC_SCALE_FACTOR + dynamicScale + rescale); - for (i = 0; i < stopSample - startSample; i++) { - accu1 = fMultDiv2(a1r, lowBandReal[i]); - accu1 = (fMultDiv2(a0r, lowBandReal[i + 1]) + accu1); - accu1 = accu1 >> dynamicScale; + for (int i = 0; i < stopSample - startSample; i++) { + FIXP_DBL accu; - accu1 <<= 1; - accu2 = (lowBandReal[i + 2] >> descale); - qmfBufferReal[i + startSample][hiBand] = accu1 + accu2; + accu = fMultDiv2(a1r, lowBandReal[i]) + fMultDiv2(a0r, lowBandReal[i + 1]); + accu = (lowBandReal[i + 2] >> descale) + (accu >> dynscale); + + qmfBufferReal[i + startSample][hiBand] = + SATURATE_LEFT_SHIFT(accu, rescale, DFRACT_BITS); } } @@ -814,9 +816,7 @@ void lppTransposer( FDK_ASSERT(dynamicScale >= 0); calc_qmfBufferReal( qmfBufferReal, &(lowBandReal[LPC_ORDER + startSample - 2]), - startSample, stopSample, hiBand, dynamicScale, - fMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale)), a0r, - a1r); + startSample, stopSample, hiBand, dynamicScale, a0r, a1r); } } /* bw <= 0 */ From ef864daeea2b2fd8cb3eda0f53a701df912690da Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 8 May 2020 16:41:54 +0200 Subject: [PATCH 66/78] Prevent signed integer overflow in complex path of calc_qmfBuffer(). Bug: 186706541 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: Iae0581ea983912bcf1bc6b3bdc2c0d8ee2f6248e --- libSBRdec/src/arm/lpp_tran_arm.cpp | 159 ----------------------------- libSBRdec/src/lpp_tran.cpp | 64 ++++++------ 2 files changed, 30 insertions(+), 193 deletions(-) delete mode 100644 libSBRdec/src/arm/lpp_tran_arm.cpp diff --git a/libSBRdec/src/arm/lpp_tran_arm.cpp b/libSBRdec/src/arm/lpp_tran_arm.cpp deleted file mode 100644 index db1948f..0000000 --- a/libSBRdec/src/arm/lpp_tran_arm.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* ----------------------------------------------------------------------------- -Software License for The Fraunhofer FDK AAC Codec Library for Android - -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten -Forschung e.V. All rights reserved. - - 1. INTRODUCTION -The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software -that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding -scheme for digital audio. This FDK AAC Codec software is intended to be used on -a wide variety of Android devices. - -AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient -general perceptual audio codecs. AAC-ELD is considered the best-performing -full-bandwidth communications codec by independent studies and is widely -deployed. AAC has been standardized by ISO and IEC as part of the MPEG -specifications. - -Patent licenses for necessary patent claims for the FDK AAC Codec (including -those of Fraunhofer) may be obtained through Via Licensing -(www.vialicensing.com) or through the respective patent owners individually for -the purpose of encoding or decoding bit streams in products that are compliant -with the ISO/IEC MPEG audio standards. Please note that most manufacturers of -Android devices already license these patent claims through Via Licensing or -directly from the patent owners, and therefore FDK AAC Codec software may -already be covered under those patent licenses when it is used for those -licensed purposes only. - -Commercially-licensed AAC software libraries, including floating-point versions -with enhanced sound quality, are also available from Fraunhofer. Users are -encouraged to check the Fraunhofer website for additional applications -information and documentation. - -2. COPYRIGHT LICENSE - -Redistribution and use in source and binary forms, with or without modification, -are permitted without payment of copyright license fees provided that you -satisfy the following conditions: - -You must retain the complete text of this software license in redistributions of -the FDK AAC Codec or your modifications thereto in source code form. - -You must retain the complete text of this software license in the documentation -and/or other materials provided with redistributions of the FDK AAC Codec or -your modifications thereto in binary form. You must make available free of -charge copies of the complete source code of the FDK AAC Codec and your -modifications thereto to recipients of copies in binary form. - -The name of Fraunhofer may not be used to endorse or promote products derived -from this library without prior written permission. - -You may not charge copyright license fees for anyone to use, copy or distribute -the FDK AAC Codec software or your modifications thereto. - -Your modified versions of the FDK AAC Codec must carry prominent notices stating -that you changed the software and the date of any change. For modified versions -of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" -must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK -AAC Codec Library for Android." - -3. NO PATENT LICENSE - -NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without -limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. -Fraunhofer provides no warranty of patent non-infringement with respect to this -software. - -You may use this FDK AAC Codec software or modifications thereto only for -purposes that are authorized by appropriate patent licenses. - -4. DISCLAIMER - -This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright -holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, -including but not limited to the implied warranties of merchantability and -fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, -or consequential damages, including but not limited to procurement of substitute -goods or services; loss of use, data, or profits, or business interruption, -however caused and on any theory of liability, whether in contract, strict -liability, or tort (including negligence), arising in any way out of the use of -this software, even if advised of the possibility of such damage. - -5. CONTACT INFORMATION - -Fraunhofer Institute for Integrated Circuits IIS -Attention: Audio and Multimedia Departments - FDK AAC LL -Am Wolfsmantel 33 -91058 Erlangen, Germany - -www.iis.fraunhofer.de/amm -amm-info@iis.fraunhofer.de ------------------------------------------------------------------------------ */ - -/**************************** SBR decoder library ****************************** - - Author(s): Arthur Tritthart - - Description: (ARM optimised) LPP transposer subroutines - -*******************************************************************************/ - -#if defined(__arm__) - -#define FUNCTION_LPPTRANSPOSER_func1 - -#ifdef FUNCTION_LPPTRANSPOSER_func1 - -/* Note: This code requires only 43 cycles per iteration instead of 61 on - * ARM926EJ-S */ -static void lppTransposer_func1(FIXP_DBL *lowBandReal, FIXP_DBL *lowBandImag, - FIXP_DBL **qmfBufferReal, - FIXP_DBL **qmfBufferImag, int loops, int hiBand, - int dynamicScale, int descale, FIXP_SGL a0r, - FIXP_SGL a0i, FIXP_SGL a1r, FIXP_SGL a1i, - const int fPreWhitening, - FIXP_DBL preWhiteningGain, - int preWhiteningGains_sf) { - FIXP_DBL real1, real2, imag1, imag2, accu1, accu2; - - real2 = lowBandReal[-2]; - real1 = lowBandReal[-1]; - imag2 = lowBandImag[-2]; - imag1 = lowBandImag[-1]; - for (int i = 0; i < loops; i++) { - accu1 = fMultDiv2(a0r, real1); - accu2 = fMultDiv2(a0i, imag1); - accu1 = fMultAddDiv2(accu1, a1r, real2); - accu2 = fMultAddDiv2(accu2, a1i, imag2); - real2 = fMultDiv2(a1i, real2); - accu1 = accu1 - accu2; - accu1 = accu1 >> dynamicScale; - - accu2 = fMultAddDiv2(real2, a1r, imag2); - real2 = real1; - imag2 = imag1; - accu2 = fMultAddDiv2(accu2, a0i, real1); - real1 = lowBandReal[i]; - accu2 = fMultAddDiv2(accu2, a0r, imag1); - imag1 = lowBandImag[i]; - accu2 = accu2 >> dynamicScale; - - accu1 <<= 1; - accu2 <<= 1; - accu1 += (real1 >> descale); - accu2 += (imag1 >> descale); - if (fPreWhitening) { - accu1 = scaleValueSaturate(fMultDiv2(accu1, preWhiteningGain), - preWhiteningGains_sf); - accu2 = scaleValueSaturate(fMultDiv2(accu2, preWhiteningGain), - preWhiteningGains_sf); - } - qmfBufferReal[i][hiBand] = accu1; - qmfBufferImag[i][hiBand] = accu2; - } -} -#endif /* #ifdef FUNCTION_LPPTRANSPOSER_func1 */ - -#endif /* __arm__ */ diff --git a/libSBRdec/src/lpp_tran.cpp b/libSBRdec/src/lpp_tran.cpp index 93e1158..bdbafa6 100644 --- a/libSBRdec/src/lpp_tran.cpp +++ b/libSBRdec/src/lpp_tran.cpp @@ -132,10 +132,6 @@ amm-info@iis.fraunhofer.de #include "HFgen_preFlat.h" -#if defined(__arm__) -#include "arm/lpp_tran_arm.cpp" -#endif - #define LPC_SCALE_FACTOR 2 /*! @@ -771,45 +767,45 @@ void lppTransposer( } else { /* bw <= 0 */ if (!useLP) { - int descale = - fixMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale)); -#ifdef FUNCTION_LPPTRANSPOSER_func1 - lppTransposer_func1( - lowBandReal + LPC_ORDER + startSample, - lowBandImag + LPC_ORDER + startSample, - qmfBufferReal + startSample, qmfBufferImag + startSample, - stopSample - startSample, (int)hiBand, dynamicScale, descale, a0r, - a0i, a1r, a1i, fPreWhitening, preWhiteningGains[loBand], - preWhiteningGains_exp[loBand] + 1); -#else + const int dynscale = fixMax(0, dynamicScale - 2) + 1; + const int rescale = -fixMin(0, dynamicScale - 2) + 1; + const int descale = fixMin(DFRACT_BITS - 1, + LPC_SCALE_FACTOR + dynamicScale + rescale); + for (i = startSample; i < stopSample; i++) { FIXP_DBL accu1, accu2; - accu1 = (fMultDiv2(a0r, lowBandReal[LPC_ORDER + i - 1]) - - fMultDiv2(a0i, lowBandImag[LPC_ORDER + i - 1]) + - fMultDiv2(a1r, lowBandReal[LPC_ORDER + i - 2]) - - fMultDiv2(a1i, lowBandImag[LPC_ORDER + i - 2])) >> - dynamicScale; - accu2 = (fMultDiv2(a0i, lowBandReal[LPC_ORDER + i - 1]) + - fMultDiv2(a0r, lowBandImag[LPC_ORDER + i - 1]) + - fMultDiv2(a1i, lowBandReal[LPC_ORDER + i - 2]) + - fMultDiv2(a1r, lowBandImag[LPC_ORDER + i - 2])) >> - dynamicScale; + accu1 = ((fMultDiv2(a0r, lowBandReal[LPC_ORDER + i - 1]) - + fMultDiv2(a0i, lowBandImag[LPC_ORDER + i - 1])) >> + 1) + + ((fMultDiv2(a1r, lowBandReal[LPC_ORDER + i - 2]) - + fMultDiv2(a1i, lowBandImag[LPC_ORDER + i - 2])) >> + 1); + accu2 = ((fMultDiv2(a0i, lowBandReal[LPC_ORDER + i - 1]) + + fMultDiv2(a0r, lowBandImag[LPC_ORDER + i - 1])) >> + 1) + + ((fMultDiv2(a1i, lowBandReal[LPC_ORDER + i - 2]) + + fMultDiv2(a1r, lowBandImag[LPC_ORDER + i - 2])) >> + 1); - accu1 = (lowBandReal[LPC_ORDER + i] >> descale) + (accu1 << 1); - accu2 = (lowBandImag[LPC_ORDER + i] >> descale) + (accu2 << 1); + accu1 = + (lowBandReal[LPC_ORDER + i] >> descale) + (accu1 >> dynscale); + accu2 = + (lowBandImag[LPC_ORDER + i] >> descale) + (accu2 >> dynscale); if (fPreWhitening) { - accu1 = scaleValueSaturate( + qmfBufferReal[i][hiBand] = scaleValueSaturate( fMultDiv2(accu1, preWhiteningGains[loBand]), - preWhiteningGains_exp[loBand] + 1); - accu2 = scaleValueSaturate( + preWhiteningGains_exp[loBand] + 1 + rescale); + qmfBufferImag[i][hiBand] = scaleValueSaturate( fMultDiv2(accu2, preWhiteningGains[loBand]), - preWhiteningGains_exp[loBand] + 1); + preWhiteningGains_exp[loBand] + 1 + rescale); + } else { + qmfBufferReal[i][hiBand] = + SATURATE_LEFT_SHIFT(accu1, rescale, DFRACT_BITS); + qmfBufferImag[i][hiBand] = + SATURATE_LEFT_SHIFT(accu2, rescale, DFRACT_BITS); } - qmfBufferReal[i][hiBand] = accu1; - qmfBufferImag[i][hiBand] = accu2; } -#endif } else { FDK_ASSERT(dynamicScale >= 0); calc_qmfBufferReal( From 22e70729b4bf541ea507dda074e368dd00e29d0c Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Mon, 6 Jul 2020 16:39:15 +0200 Subject: [PATCH 67/78] Fix stack buffer overflow in Pred_lt4(). Bug: 186706541 Bug: 160187491 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I3b8d9326319cca21145cc246588b01c5bf29a9a0 --- libAACdec/src/usacdec_acelp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libAACdec/src/usacdec_acelp.cpp b/libAACdec/src/usacdec_acelp.cpp index a8dadc0..ca1a6a2 100644 --- a/libAACdec/src/usacdec_acelp.cpp +++ b/libAACdec/src/usacdec_acelp.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -719,7 +719,7 @@ static void ConcealPitchLag(CAcelpStaticMem *acelp_mem, const int PIT_MAX, UCHAR *pold_T0_frac = &acelp_mem->old_T0_frac; if ((int)*pold_T0 >= PIT_MAX) { - *pold_T0 = (UCHAR)(PIT_MAX - 5); + *pold_T0 = (USHORT)(PIT_MAX - 5); } *pT0 = (int)*pold_T0; *pT0_frac = (int)*pold_T0_frac; From 9ed084750d72346b1533119410be9329ae138dcc Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:48:46 +0100 Subject: [PATCH 68/78] Improve validation of channel indices in pcmDmx. Bug: 186777497 Bug: 170374298 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: If4d6f5fec266244b496c6ea08cd411badd9a31cf --- libPCMutils/src/pcmdmx_lib.cpp | 56 +++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/libPCMutils/src/pcmdmx_lib.cpp b/libPCMutils/src/pcmdmx_lib.cpp index 2070dbc..fca12ce 100644 --- a/libPCMutils/src/pcmdmx_lib.cpp +++ b/libPCMutils/src/pcmdmx_lib.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -494,13 +494,40 @@ static PCM_DMX_CHANNEL_MODE getChMode4Plain( return plainChMode; } -static inline UINT getIdxSum(UCHAR numCh) { - UINT result = 0; - int i; - for (i = 1; i < numCh; i += 1) { - result += i; +/** Validates the channel indices of all channels present in the bitstream. + * The channel indices have to be consecutive and unique for each audio channel + *type. + * @param [in] The total number of channels of the given configuration. + * @param [in] The total number of channels of the current audio channel type of + *the given configuration. + * @param [in] Audio channel type to be examined. + * @param [in] Array holding the corresponding channel types for each channel. + * @param [in] Array holding the corresponding channel type indices for each + *channel. + * @returns Returns 1 on success, returns 0 on error. + **/ +static UINT validateIndices(UINT numChannels, UINT numChannelsPlaneAndGrp, + AUDIO_CHANNEL_TYPE aChType, + const AUDIO_CHANNEL_TYPE channelType[], + const UCHAR channelIndices[]) { + for (UINT reqValue = 0; reqValue < numChannelsPlaneAndGrp; reqValue++) { + int found = FALSE; + for (UINT i = 0; i < numChannels; i++) { + if (channelType[i] == aChType) { + if (channelIndices[i] == reqValue) { + if (found == TRUE) { + return 0; /* Found channel index a second time */ + } else { + found = TRUE; /* Found channel index */ + } + } + } + } + if (found == FALSE) { + return 0; /* Did not find channel index */ + } } - return result; + return 1; /* Successfully validated channel indices */ } /** Evaluate a given channel configuration and extract a packed channel mode. In @@ -523,7 +550,6 @@ static PCMDMX_ERROR getChannelMode( UCHAR offsetTable[(8)], /* out */ PCM_DMX_CHANNEL_MODE *chMode /* out */ ) { - UINT idxSum[(3)][(4)]; UCHAR numCh[(3)][(4)]; UCHAR mapped[(8)]; PCM_DMX_SPEAKER_POSITION spkrPos[(8)]; @@ -538,7 +564,6 @@ static PCMDMX_ERROR getChannelMode( FDK_ASSERT(chMode != NULL); /* For details see ISO/IEC 13818-7:2005(E), 8.5.3 Channel configuration */ - FDKmemclear(idxSum, (3) * (4) * sizeof(UINT)); FDKmemclear(numCh, (3) * (4) * sizeof(UCHAR)); FDKmemclear(mapped, (8) * sizeof(UCHAR)); FDKmemclear(spkrPos, (8) * sizeof(PCM_DMX_SPEAKER_POSITION)); @@ -552,19 +577,22 @@ static PCMDMX_ERROR getChannelMode( (channelType[ch] & 0x0F) - 1, 0); /* Assign all undefined channels (ACT_NONE) to front channels. */ numCh[channelType[ch] >> 4][chGrp] += 1; - idxSum[channelType[ch] >> 4][chGrp] += channelIndices[ch]; } - if (numChannels > TWO_CHANNEL) { + + { int chGrp; /* Sanity check on the indices */ for (chGrp = 0; chGrp < (4); chGrp += 1) { int plane; for (plane = 0; plane < (3); plane += 1) { - if (idxSum[plane][chGrp] != getIdxSum(numCh[plane][chGrp])) { + if (numCh[plane][chGrp] == 0) continue; + AUDIO_CHANNEL_TYPE aChType = + (AUDIO_CHANNEL_TYPE)((plane << 4) | ((chGrp + 1) & 0xF)); + if (!validateIndices(numChannels, numCh[plane][chGrp], aChType, + channelType, channelIndices)) { unsigned idxCnt = 0; for (ch = 0; ch < numChannels; ch += 1) { - if (channelType[ch] == - (AUDIO_CHANNEL_TYPE)((plane << 4) | ((chGrp + 1) & 0xF))) { + if (channelType[ch] == aChType) { channelIndices[ch] = idxCnt++; } } From 48e0fa028d4c6f70f46ef5608b2108c89453a487 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:49:07 +0100 Subject: [PATCH 69/78] Avoid unintentional sign conversions in lppTransposer() and lppTransposerHBE(). Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: Ifc4618b8de4e377df28e387fb976ab5acb5883d7 --- libSBRdec/src/lpp_tran.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libSBRdec/src/lpp_tran.cpp b/libSBRdec/src/lpp_tran.cpp index 113b1de..68a25bf 100644 --- a/libSBRdec/src/lpp_tran.cpp +++ b/libSBRdec/src/lpp_tran.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -527,7 +527,7 @@ void lppTransposer( if ((scale > 0) && (result >= (FIXP_DBL)MAXVAL_DBL >> scale)) { resetLPCCoeffs = 1; } else { - alphar[1] = FX_DBL2FX_SGL(scaleValue(result, scale)); + alphar[1] = FX_DBL2FX_SGL(scaleValueSaturate(result, scale)); if ((tmp < FL2FX_DBL(0.0f)) ^ (ac.det < FL2FX_DBL(0.0f))) { alphar[1] = -alphar[1]; } @@ -555,7 +555,7 @@ void lppTransposer( scale)) { resetLPCCoeffs = 1; } else { - alphai[1] = FX_DBL2FX_SGL(scaleValue(result, scale)); + alphai[1] = FX_DBL2FX_SGL(scaleValueSaturate(result, scale)); if ((tmp < FL2FX_DBL(0.0f)) ^ (ac.det < FL2FX_DBL(0.0f))) { alphai[1] = -alphai[1]; } @@ -594,7 +594,7 @@ void lppTransposer( } else { INT scale; FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale); - alphar[0] = FX_DBL2FX_SGL(scaleValue(result, scale + 1)); + alphar[0] = FX_DBL2FX_SGL(scaleValueSaturate(result, scale + 1)); if ((tmp > FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f))) alphar[0] = -alphar[0]; @@ -614,7 +614,7 @@ void lppTransposer( } else { INT scale; FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale); - alphai[0] = FX_DBL2FX_SGL(scaleValue(result, scale + 1)); + alphai[0] = FX_DBL2FX_SGL(scaleValueSaturate(result, scale + 1)); if ((tmp > FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f))) alphai[0] = -alphai[0]; } @@ -657,7 +657,7 @@ void lppTransposer( INT scale; FIXP_DBL result = fDivNorm(fixp_abs(ac.r01r), fixp_abs(ac.r11r), &scale); - k1 = scaleValue(result, scale); + k1 = scaleValueSaturate(result, scale); if (!((ac.r01r < FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f)))) { k1 = -k1; @@ -1062,7 +1062,7 @@ void lppTransposerHBE( if ((scale > 0) && (result >= (FIXP_DBL)MAXVAL_DBL >> scale)) { resetLPCCoeffs = 1; } else { - alphar[1] = FX_DBL2FX_SGL(scaleValue(result, scale)); + alphar[1] = FX_DBL2FX_SGL(scaleValueSaturate(result, scale)); if ((tmp < FL2FX_DBL(0.0f)) ^ (ac.det < FL2FX_DBL(0.0f))) { alphar[1] = -alphar[1]; } @@ -1088,7 +1088,7 @@ void lppTransposerHBE( (result >= /*FL2FXCONST_DBL(1.f)*/ (FIXP_DBL)MAXVAL_DBL >> scale)) { resetLPCCoeffs = 1; } else { - alphai[1] = FX_DBL2FX_SGL(scaleValue(result, scale)); + alphai[1] = FX_DBL2FX_SGL(scaleValueSaturate(result, scale)); if ((tmp < FL2FX_DBL(0.0f)) ^ (ac.det < FL2FX_DBL(0.0f))) { alphai[1] = -alphai[1]; } @@ -1117,7 +1117,7 @@ void lppTransposerHBE( } else { INT scale; FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale); - alphar[0] = FX_DBL2FX_SGL(scaleValue(result, scale + 1)); + alphar[0] = FX_DBL2FX_SGL(scaleValueSaturate(result, scale + 1)); if ((tmp > FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f))) alphar[0] = -alphar[0]; @@ -1136,7 +1136,7 @@ void lppTransposerHBE( } else { INT scale; FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale); - alphai[0] = FX_DBL2FX_SGL(scaleValue(result, scale + 1)); + alphai[0] = FX_DBL2FX_SGL(scaleValueSaturate(result, scale + 1)); if ((tmp > FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f))) { alphai[0] = -alphai[0]; } From 85a3977fdfd1c73c2d0cc6b26f8dfa29a7cfd780 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:49:49 +0100 Subject: [PATCH 70/78] Fix fixmadddiv2_DD() integer overflow in SpatialDecApplyM2_Mode212_ResidualsPlusPhaseCoding(). Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I6237be90ed15e107cc4468770da7c330cdeef16f --- libSACdec/src/sac_process.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/libSACdec/src/sac_process.cpp b/libSACdec/src/sac_process.cpp index 22091a9..33a1647 100644 --- a/libSACdec/src/sac_process.cpp +++ b/libSACdec/src/sac_process.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -517,12 +517,11 @@ SACDEC_ERROR SpatialDecApplyM2_Mode212_ResidualsPlusPhaseCoding( maxVal = fAbs(iReal0) | fAbs(iImag0); maxVal |= fAbs(iReal1); - s = fMax(CntLeadingZeros(maxVal) - 1, 0); - s = fMin(s, scale_param_m2); + s = fMin(CntLeadingZeros(maxVal) - 2, scale_param_m2); - mReal0 = iReal0 << s; - mImag0 = iImag0 << s; - mReal1 = iReal1 << s; + mReal0 = scaleValue(iReal0, s); + mImag0 = scaleValue(iImag0, s); + mReal1 = scaleValue(iReal1, s); s = scale_param_m2 - s; @@ -562,12 +561,11 @@ SACDEC_ERROR SpatialDecApplyM2_Mode212_ResidualsPlusPhaseCoding( maxVal = fAbs(iReal0) | fAbs(iImag0); maxVal |= fAbs(iReal1); - s = fMax(CntLeadingZeros(maxVal) - 1, 0); - s = fMin(s, scale_param_m2); + s = fMin(CntLeadingZeros(maxVal) - 2, scale_param_m2); - mReal0 = FX_DBL2FX_SGL(iReal0 << s); - mImag0 = FX_DBL2FX_SGL(iImag0 << s); - mReal1 = FX_DBL2FX_SGL(iReal1 << s); + mReal0 = FX_DBL2FX_SGL(scaleValue(iReal0, s)); + mImag0 = FX_DBL2FX_SGL(scaleValue(iImag0, s)); + mReal1 = FX_DBL2FX_SGL(scaleValue(iReal1, s)); s = scale_param_m2 - s; From 773ff1d3e8921ed2c9d2def344cf4b6b47f861c8 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:50:04 +0100 Subject: [PATCH 71/78] Adapt scaling in combineSignalCplxScale*() to prevent signed integer overflows. Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: If773c90ccd256fd03641446c7f8bd82d04a100e4 --- libSACdec/src/sac_stp.cpp | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/libSACdec/src/sac_stp.cpp b/libSACdec/src/sac_stp.cpp index be332c7..0e6affa 100644 --- a/libSACdec/src/sac_stp.cpp +++ b/libSACdec/src/sac_stp.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -229,15 +229,13 @@ inline void combineSignalCplxScale1(FIXP_DBL *hybOutputRealDry, int n; FIXP_DBL scaleY; for (n = bands - 1; n >= 0; n--) { - scaleY = fMultDiv2(scaleX, *pBP); + scaleY = fMult(scaleX, *pBP); *hybOutputRealDry = SATURATE_LEFT_SHIFT( - (*hybOutputRealDry >> 1) + - (fMultDiv2(*hybOutputRealWet, scaleY) << (SF_SCALE + 1)), - 1, DFRACT_BITS); + (*hybOutputRealDry >> SF_SCALE) + fMult(*hybOutputRealWet, scaleY), + SF_SCALE, DFRACT_BITS); *hybOutputImagDry = SATURATE_LEFT_SHIFT( - (*hybOutputImagDry >> 1) + - (fMultDiv2(*hybOutputImagWet, scaleY) << (SF_SCALE + 1)), - 1, DFRACT_BITS); + (*hybOutputImagDry >> SF_SCALE) + fMult(*hybOutputImagWet, scaleY), + SF_SCALE, DFRACT_BITS); hybOutputRealDry++, hybOutputRealWet++; hybOutputImagDry++, hybOutputImagWet++; pBP++; @@ -253,14 +251,11 @@ inline void combineSignalCplxScale2(FIXP_DBL *hybOutputRealDry, for (n = bands - 1; n >= 0; n--) { *hybOutputRealDry = SATURATE_LEFT_SHIFT( - (*hybOutputRealDry >> 1) + - (fMultDiv2(*hybOutputRealWet, scaleX) << SF_SCALE), - 1, DFRACT_BITS); + (*hybOutputRealDry >> SF_SCALE) + fMult(*hybOutputRealWet, scaleX), + SF_SCALE, DFRACT_BITS); *hybOutputImagDry = SATURATE_LEFT_SHIFT( - (*hybOutputImagDry >> 1) + - (fMultDiv2(*hybOutputImagWet, scaleX) << SF_SCALE), - 1, DFRACT_BITS); - ; + (*hybOutputImagDry >> SF_SCALE) + fMult(*hybOutputImagWet, scaleX), + SF_SCALE, DFRACT_BITS); hybOutputRealDry++, hybOutputRealWet++; hybOutputImagDry++, hybOutputImagWet++; } From 56de8e29ce7b5c86b1ba7cac9b3286b4a900642f Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:50:24 +0100 Subject: [PATCH 72/78] Utilize dynamic scaling in slotAmp() to avoid signed integer overflows. Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: Ia66fbbd16dec4f9e04d67463cca91d75f3741131 --- libSACdec/src/sac_reshapeBBEnv.cpp | 77 +++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/libSACdec/src/sac_reshapeBBEnv.cpp b/libSACdec/src/sac_reshapeBBEnv.cpp index 272d009..72f4e58 100644 --- a/libSACdec/src/sac_reshapeBBEnv.cpp +++ b/libSACdec/src/sac_reshapeBBEnv.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -241,29 +241,56 @@ static inline void combineDryWet(FIXP_DBL *RESTRICT pReal, } } -static inline void slotAmp(FIXP_DBL *RESTRICT slotAmp_dry, - FIXP_DBL *RESTRICT slotAmp_wet, - FIXP_DBL *RESTRICT pHybOutputRealDry, - FIXP_DBL *RESTRICT pHybOutputImagDry, - FIXP_DBL *RESTRICT pHybOutputRealWet, - FIXP_DBL *RESTRICT pHybOutputImagWet, INT cplxBands, - INT hybBands) { - INT qs; +static inline void slotAmp( + FIXP_DBL *RESTRICT slotAmp_dry, INT *RESTRICT slotAmp_dry_e, + FIXP_DBL *RESTRICT slotAmp_wet, INT *RESTRICT slotAmp_wet_e, + FIXP_DBL *RESTRICT pHybOutputRealDry, FIXP_DBL *RESTRICT pHybOutputImagDry, + FIXP_DBL *RESTRICT pHybOutputRealWet, FIXP_DBL *RESTRICT pHybOutputImagWet, + INT cplxBands, INT hybBands) { + INT qs, s1, s2, headroom_dry, headroom_wet; FIXP_DBL dry, wet; + /* headroom can be reduced by 1 bit due to use of fPow2Div2 */ + s1 = DFRACT_BITS - 1 - CntLeadingZeros(hybBands + cplxBands); + headroom_dry = fMin(getScalefactor(pHybOutputRealDry, hybBands), + getScalefactor(pHybOutputImagDry, cplxBands)); + headroom_wet = fMin(getScalefactor(pHybOutputRealWet, hybBands), + getScalefactor(pHybOutputImagWet, cplxBands)); + dry = wet = FL2FXCONST_DBL(0.0f); for (qs = 0; qs < cplxBands; qs++) { - dry = fAddSaturate(dry, fPow2Div2(pHybOutputRealDry[qs] << (1)) + - fPow2Div2(pHybOutputImagDry[qs] << (1))); - wet = fAddSaturate(wet, fPow2Div2(pHybOutputRealWet[qs] << (1)) + - fPow2Div2(pHybOutputImagWet[qs] << (1))); + /* sum up dry part */ + dry += (fPow2Div2(pHybOutputRealDry[qs] << headroom_dry) >> s1); + dry += (fPow2Div2(pHybOutputImagDry[qs] << headroom_dry) >> s1); + /* sum up wet part */ + wet += (fPow2Div2(pHybOutputRealWet[qs] << headroom_wet) >> s1); + wet += (fPow2Div2(pHybOutputImagWet[qs] << headroom_wet) >> s1); } for (; qs < hybBands; qs++) { - dry = fAddSaturate(dry, fPow2Div2(pHybOutputRealDry[qs] << (1))); - wet = fAddSaturate(wet, fPow2Div2(pHybOutputRealWet[qs] << (1))); + dry += (fPow2Div2(pHybOutputRealDry[qs] << headroom_dry) >> s1); + wet += (fPow2Div2(pHybOutputRealWet[qs] << headroom_wet) >> s1); + } + + /* consider fPow2Div2() */ + s1 += 1; + + /* normalize dry part, ensure that exponent is even */ + s2 = fixMax(0, CntLeadingZeros(dry) - 1); + *slotAmp_dry = dry << s2; + *slotAmp_dry_e = s1 - s2 - 2 * headroom_dry; + if (*slotAmp_dry_e & 1) { + *slotAmp_dry = *slotAmp_dry >> 1; + *slotAmp_dry_e += 1; + } + + /* normalize wet part, ensure that exponent is even */ + s2 = fixMax(0, CntLeadingZeros(wet) - 1); + *slotAmp_wet = wet << s2; + *slotAmp_wet_e = s1 - s2 - 2 * headroom_wet; + if (*slotAmp_wet_e & 1) { + *slotAmp_wet = *slotAmp_wet >> 1; + *slotAmp_wet_e += 1; } - *slotAmp_dry = dry >> (2 * (1)); - *slotAmp_wet = wet >> (2 * (1)); } #if defined(__aarch64__) @@ -533,6 +560,7 @@ void SpatialDecReshapeBBEnv(spatialDec *self, const SPATIAL_BS_FRAME *frame, INT ts) { INT ch, scale; INT dryFacSF, slotAmpSF; + INT slotAmp_dry_e, slotAmp_wet_e; FIXP_DBL tmp, dryFac, envShape; FIXP_DBL slotAmp_dry, slotAmp_wet, slotAmp_ratio; FIXP_DBL envDry[MAX_OUTPUT_CHANNELS], envDmx[2]; @@ -594,22 +622,25 @@ void SpatialDecReshapeBBEnv(spatialDec *self, const SPATIAL_BS_FRAME *frame, dryFacSF = SF_SHAPE + 2 * dryFacSF; } + slotAmp_dry_e = slotAmp_wet_e = 0; + /* calculate slotAmp_dry and slotAmp_wet */ - slotAmp(&slotAmp_dry, &slotAmp_wet, &self->hybOutputRealDry__FDK[ch][6], + slotAmp(&slotAmp_dry, &slotAmp_dry_e, &slotAmp_wet, &slotAmp_wet_e, + &self->hybOutputRealDry__FDK[ch][6], &self->hybOutputImagDry__FDK[ch][6], &self->hybOutputRealWet__FDK[ch][6], &self->hybOutputImagWet__FDK[ch][6], cplxBands, hybBands); + /* exponents must be even due to subsequent square root calculation */ + FDK_ASSERT(((slotAmp_dry_e & 1) == 0) && ((slotAmp_wet_e & 1) == 0)); + /* slotAmp_ratio will be scaled by slotAmpSF bits */ if (slotAmp_dry != FL2FXCONST_DBL(0.0f)) { - sc = fixMax(0, CntLeadingZeros(slotAmp_wet) - 1); - sc = sc - (sc & 1); - - slotAmp_wet = sqrtFixp(slotAmp_wet << sc); + slotAmp_wet = sqrtFixp(slotAmp_wet); slotAmp_dry = invSqrtNorm2(slotAmp_dry, &slotAmpSF); slotAmp_ratio = fMult(slotAmp_wet, slotAmp_dry); - slotAmpSF = slotAmpSF - (sc >> 1); + slotAmpSF = slotAmpSF + (slotAmp_wet_e >> 1) - (slotAmp_dry_e >> 1); } /* calculate common scale factor */ From 92dd536642e0cc64ef0112e255dbfba14da461c1 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:50:43 +0100 Subject: [PATCH 73/78] Pass flushing flag to SBR module for stereo config index 3 as for stereo config index 1 and 2. Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: Ifed0885abdbbfb2e2d4d94bc482e5e1e30794049 --- libAACdec/src/aacdecoder_lib.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index 9d36d10..0c83191 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -1626,6 +1626,11 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(HANDLE_AACDECODER self, /* set params */ sbrDecoder_SetParam(self->hSbrDecoder, SBR_SYSTEM_BITSTREAM_DELAY, self->sbrParams.bsDelay); + sbrDecoder_SetParam( + self->hSbrDecoder, SBR_FLUSH_DATA, + (flags & AACDEC_FLUSH) | + ((self->flushStatus && !(flags & AACDEC_CONCEAL)) ? AACDEC_FLUSH + : 0)); sbrDecoder_SetParam(self->hSbrDecoder, SBR_SKIP_QMF, 1); From e5a14d0a3329f45cbff44a08d5b423ff3cf38b1c Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:51:09 +0100 Subject: [PATCH 74/78] Use scaleValuesSaturate() to avoid integer overflows in QmfTransposerApply(). Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: Ib83bd37861e1e24ff18ea276244a370962808fcf --- libSBRdec/src/hbe.cpp | 55 ++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/libSBRdec/src/hbe.cpp b/libSBRdec/src/hbe.cpp index d210bb6..f2452ea 100644 --- a/libSBRdec/src/hbe.cpp +++ b/libSBRdec/src/hbe.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -1400,42 +1400,27 @@ void QmfTransposerApply(HANDLE_HBE_TRANSPOSER hQmfTransposer, if (shift_ov != 0) { for (i = 0; i < HBE_MAX_OUT_SLOTS; i++) { - for (band = 0; band < QMF_SYNTH_CHANNELS; band++) { - if (shift_ov >= 0) { - hQmfTransposer->qmfHBEBufReal_F[i][band] <<= shift_ov; - hQmfTransposer->qmfHBEBufImag_F[i][band] <<= shift_ov; - } else { - hQmfTransposer->qmfHBEBufReal_F[i][band] >>= (-shift_ov); - hQmfTransposer->qmfHBEBufImag_F[i][band] >>= (-shift_ov); - } - } - } - } - - if ((keepStatesSyncedMode == KEEP_STATES_SYNCED_OFF) && shift_ov != 0) { - for (i = timeStep * firstSlotOffsset; i < ov_len; i++) { - for (band = hQmfTransposer->startBand; band < hQmfTransposer->stopBand; - band++) { - if (shift_ov >= 0) { - ppQmfBufferOutReal_F[i][band] <<= shift_ov; - ppQmfBufferOutImag_F[i][band] <<= shift_ov; - } else { - ppQmfBufferOutReal_F[i][band] >>= (-shift_ov); - ppQmfBufferOutImag_F[i][band] >>= (-shift_ov); - } - } + scaleValuesSaturate(&hQmfTransposer->qmfHBEBufReal_F[i][0], + QMF_SYNTH_CHANNELS, shift_ov); + scaleValuesSaturate(&hQmfTransposer->qmfHBEBufImag_F[i][0], + QMF_SYNTH_CHANNELS, shift_ov); } - /* shift lpc filterstates */ - for (i = 0; i < timeStep * firstSlotOffsset + LPC_ORDER; i++) { - for (band = 0; band < (64); band++) { - if (shift_ov >= 0) { - lpcFilterStatesReal[i][band] <<= shift_ov; - lpcFilterStatesImag[i][band] <<= shift_ov; - } else { - lpcFilterStatesReal[i][band] >>= (-shift_ov); - lpcFilterStatesImag[i][band] >>= (-shift_ov); - } + if (keepStatesSyncedMode == KEEP_STATES_SYNCED_OFF) { + int nBands = + fMax(0, hQmfTransposer->stopBand - hQmfTransposer->startBand); + + for (i = timeStep * firstSlotOffsset; i < ov_len; i++) { + scaleValuesSaturate(&ppQmfBufferOutReal_F[i][hQmfTransposer->startBand], + nBands, shift_ov); + scaleValuesSaturate(&ppQmfBufferOutImag_F[i][hQmfTransposer->startBand], + nBands, shift_ov); + } + + /* shift lpc filterstates */ + for (i = 0; i < timeStep * firstSlotOffsset + LPC_ORDER; i++) { + scaleValuesSaturate(&lpcFilterStatesReal[i][0], (64), shift_ov); + scaleValuesSaturate(&lpcFilterStatesImag[i][0], (64), shift_ov); } } } From 2a40fde39dfcc264e1cda3c429b482246621e60c Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:51:20 +0100 Subject: [PATCH 75/78] Prevent too large shift exponent in apply_inter_tes() and merge two loops. Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I9ecb7fbae0a2c2c24af9067846afcf499b021608 --- libSBRdec/src/env_calc.cpp | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/libSBRdec/src/env_calc.cpp b/libSBRdec/src/env_calc.cpp index ad5edfe..cefa612 100644 --- a/libSBRdec/src/env_calc.cpp +++ b/libSBRdec/src/env_calc.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -664,7 +664,7 @@ static void apply_inter_tes(FIXP_DBL **qmfReal, FIXP_DBL **qmfImag, gain_sf[i] = mult_sf - total_power_low_sf + sf2; gain[i] = sqrtFixp_lookup(gain[i], &gain_sf[i]); if (gain_sf[i] < 0) { - gain[i] >>= -gain_sf[i]; + gain[i] >>= fMin(DFRACT_BITS - 1, -gain_sf[i]); gain_sf[i] = 0; } } else { @@ -683,11 +683,6 @@ static void apply_inter_tes(FIXP_DBL **qmfReal, FIXP_DBL **qmfImag, /* gain[i] = g_inter[i] */ for (i = 0; i < nbSubsample; ++i) { - if (gain_sf[i] < 0) { - gain[i] >>= -gain_sf[i]; - gain_sf[i] = 0; - } - /* calculate: gain[i] = 1.0f + gamma * (gain[i] - 1.0f); */ FIXP_DBL one = (FIXP_DBL)MAXVAL_DBL >> gain_sf[i]; /* to substract this from gain[i] */ @@ -755,23 +750,15 @@ static void apply_inter_tes(FIXP_DBL **qmfReal, FIXP_DBL **qmfImag, int gain_adj_sf = gain_adj_2_sf; for (i = 0; i < nbSubsample; ++i) { - gain[i] = fMult(gain[i], gain_adj); - gain_sf[i] += gain_adj_sf; - - /* limit gain */ - if (gain_sf[i] > INTER_TES_SF_CHANGE) { - gain[i] = (FIXP_DBL)MAXVAL_DBL; - gain_sf[i] = INTER_TES_SF_CHANGE; - } - } - - for (i = 0; i < nbSubsample; ++i) { - /* equalize gain[]'s scale factors */ - gain[i] >>= INTER_TES_SF_CHANGE - gain_sf[i]; + int gain_e = fMax( + fMin(gain_sf[i] + gain_adj_sf - INTER_TES_SF_CHANGE, DFRACT_BITS - 1), + -(DFRACT_BITS - 1)); + FIXP_DBL gain_final = fMult(gain[i], gain_adj); + gain_final = scaleValueSaturate(gain_final, gain_e); for (j = lowSubband; j < highSubband; j++) { - qmfReal[startPos + i][j] = fMult(qmfReal[startPos + i][j], gain[i]); - qmfImag[startPos + i][j] = fMult(qmfImag[startPos + i][j], gain[i]); + qmfReal[startPos + i][j] = fMult(qmfReal[startPos + i][j], gain_final); + qmfImag[startPos + i][j] = fMult(qmfImag[startPos + i][j], gain_final); } } } else { /* gamma_idx == 0 */ From c2416f5e9360db0a6a3578fff087392fc7656f38 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:51:32 +0100 Subject: [PATCH 76/78] Add parameter pointer check to aacEncInfo() encoder API function. Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I5d758d2708a613382d9ad6d02a9dbe46ae2ef0cf --- documentation/aacEncoder.pdf | Bin 443728 -> 443831 bytes libAACenc/include/aacenc_lib.h | 4 ++-- libAACenc/src/aacenc_lib.cpp | 7 ++++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/documentation/aacEncoder.pdf b/documentation/aacEncoder.pdf index 77b8f4cc2210d75dc2e0588f940a07ab370b7dd7..a47708a940e5b2218c0a2eebcb2ea2f4334943e3 100644 GIT binary patch delta 8063 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 delta 7974 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 diff --git a/libAACenc/include/aacenc_lib.h b/libAACenc/include/aacenc_lib.h index 71f7556..f0f23b4 100644 --- a/libAACenc/include/aacenc_lib.h +++ b/libAACenc/include/aacenc_lib.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -1643,7 +1643,7 @@ AACENC_ERROR aacEncEncode(const HANDLE_AACENCODER hAacEncoder, * * \return * - AACENC_OK, on succes. - * - AACENC_INIT_ERROR, on failure. + * - AACENC_INVALID_HANDLE, AACENC_INIT_ERROR, on failure. */ AACENC_ERROR aacEncInfo(const HANDLE_AACENCODER hAacEncoder, AACENC_InfoStruct *pInfo); diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp index caa62c5..c11db27 100644 --- a/libAACenc/src/aacenc_lib.cpp +++ b/libAACenc/src/aacenc_lib.cpp @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- Software License for The Fraunhofer FDK AAC Codec Library for Android -© Copyright 1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten +© Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. All rights reserved. 1. INTRODUCTION @@ -2521,6 +2521,11 @@ AACENC_ERROR aacEncInfo(const HANDLE_AACENCODER hAacEncoder, AACENC_InfoStruct *pInfo) { AACENC_ERROR err = AACENC_OK; + if ((hAacEncoder == NULL) || (pInfo == NULL)) { + err = AACENC_INVALID_HANDLE; + goto bail; + } + FDKmemclear(pInfo, sizeof(AACENC_InfoStruct)); pInfo->confSize = 64; /* pre-initialize */ From 09cf32a6c7f5f0a3d9be6b8b0018211a86d9a57a Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Tue, 16 Mar 2021 14:52:07 +0100 Subject: [PATCH 77/78] Refine aacDecoder_DecodeFrame() output buffer parameter type description. Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: I83a460d03c7cde3e4f74011a7c3556c4cfd08cdd --- documentation/aacDecoder.pdf | Bin 490978 -> 492288 bytes libAACdec/include/aacdecoder_lib.h | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/aacDecoder.pdf b/documentation/aacDecoder.pdf index cc7cf41607d1246b5081bb82d61f87cd816bc804..3d4699e62c19282a31696c58f067bb129a502f23 100644 GIT binary patch delta 90881 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

JnKG9sHd=XX><{{5eCisf8`;J4y5 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 delta 89611 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 xXT1K?WD6|AWGERu`9%zp)Jg%U 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%0D$KsQJh&ZId&a3D3Qoee7tyy zdt5e*fGmmaxrb`_cx~sp#9ug{PI#^1zUKE|NlSI#sVR+=?64i2Zzv)i=^%XX?bCoIO-$tT)2SztI9SP3 z$aif$1t2lJ2X^!9ewc3zm9Er4)g<4ruq!ca4u`Kw``r-PLq;gfmcs_U*RxzaFhaX^ zTP#t-hJwUdpRX%kKgrU=9v6N43y8CUe_&YHJp*9ZupmGQA=E^?SOsyu*a6>hW5lfE`>Rfj#c|aNN zB04pXX=8M&%TnNTi`-T#>%7buV_i9NCR_A~xo>A90n?aPf^Y zqcrorggF;-5JP4S4Q=EZbw8qDk)iU5SHCO-0a#KX0*{0V96G6IY{TP#%~|A#{t1&> zO858tOP}h#tGhHP?oqmb-F$V*qlD;U9dM;my0gcz*#a)}s}5%=-rbYQowzURmeq$z zGdTtrZwU&B^)G2i?U6v5Jl)HqjuceB-Rv5FRH~rD2t0OObfO`fI04b9d&B&t?4yPx z)-};g!xm^MtPBZqh{jf>D02=LTOzYY3C~aHwih}uX3ir*qRDs)v_jx-yZw@KHo&|0 z5v)!TA`J9y2%F2*gJg*0j3oM01L1fTC^Ht;Ljth^HcX?8@0|;?nhB8h;o?F@Tu6pE z3adI#x`k?8L)FX2hw)F2_f#PM5g$n*TRCWDDoo#N!Fk(BBPHHTj1N0EA8lsTS$S40 zS1(V|v(M`yE}uZXCxQiN*{}o>ctGCBF>99UvpOk%fKNEz<)nxIHD^F!|DG4{>Y%r^O+0Z!N$%KXSJ|ES<5mV0W;TymGLSNq>y|8leh9G`U zzkWB|9TvQ)lQnUb1{Vq1gh+7N#^UR8a=Gbd1?>*5(C`m{nsdcW=TlC**vg= zTAyp+I)2t@DhV=?3>L*cM~`;=w6RqJ@ES3_1bx+^5>wH&2HYcm5u(6V(2Xr z>&-2QP>FMrnruEN?=TSHcOb~i3lFb-239l=@3Yv+S-hSU)2`h3pY)wP`hRFGLgyQ(OO>0^YC>T5lD-+j0dt==?{js=hNZr3R zuG4inP1PDCfdhfo0~3Eh5o&UiBDpFa2pJBou&LAZy}Whpxjsx0U*GpHpu)DB4|)00 zHjaB&|IPM>raD-38JjX!BvfPJbaXJ6q|BbC6jGa-ReZBl5h=3|Wm9E_A#h;`%SLg` zn5Ct7*Oq33k(0JDF90-2uhI&(5}T*Q`{4A>3i>luffov!w+L>CcjA{HMDjZWuLs6n zQz+WmqKnTq6_~;jMHHAqWoH!}Ag4DKVaR_TJIu`6otWJ+}6&t}8~A>%5=u$)A? zfkp+!V?u*d>H>wB6Bp?iYnuG3fuK@7??mrgIq5eDNov_gjRZJKU^qHZ{qfHbt~kQU zikV;Wn@snw75_ot=E>3oPR0(b8`P-numS9AG`JI+(RezQ7^tpxPsC-3(?o(g8v>`y zxmdjfF`_(fj)a0%x#DZl&x(OZ$)=%D`TITRa;DeKmf?_X-0T6O=+=O*s4u#EBWBmswuMK7e^{9On}VK zY-Ek`&q`y#6z!7TI4!DUxJLxgCHOqJ*04KMYxZw~=mDW7QL(d|{hx5;wr}X&NKI@k z-lRo7IM5Y*B&*2tGsg_i*#v<~sGy=sSstxcc4PxZ7V(X)2t4 zZ`aq)zMMU8uXV>aFLeTZ@5hesmp7-Q3kwkI*z=?Nd2s+Pzb~RVgs^>tvfsaVLF$bm z6pqkg`T$gi>5MerM5!y5Pj;RU)VSLr`+4}=0-^h7*I@?yA8)8yUzj~FNB&=zlEg6F zR~X2o4d(4ag z>jC`VwXYbh)Myfdq6s`oj8`Wvi=rq_Tan3<6;`oLLnC67xK5u6V9U(bl#+~zxPwFP z0Ex&p`Tbo0HA+4gZe*1R5lbG}nALbR`wU7wvQ$z7ImK>0Th=(DK?7Nb>5+b+VQ7UW zq6X6kLBTV+J8>nv!DF|6Xl2HTWn?P^FobMUN7`!qjcZHG^eAmiGE(XcfX6qf!~IU< z!`)?SOG zF3@gxKA)~1j`IXQ%{y}gnT%q0%kM&01#~aZGJvKKaT;* zft!mnj@{?a`!kp4=XoZF{zu1me9yA5V+QwqmOk5e1N>h8pZq_$3_hZ-KHXn$$`rQw zKCwe5>uuo8<(S2R4Z1$=LF1j4-RuRrKEXcXCZ&tmE~$Ty40vy-(u246+lS)}!?_i8 z?2es}?foYJ{zv%N?{GpC35EoHtS)Xlr?b<+KM7SN|No#NQ5&m^*Us(icJO!XPeK*R zzY;cZ+qs-w4vxmA6S7F!SZ+t(^dS~?jRT54xbydR@_DH$oslDxL=Gc^b8xNLp|WvP z7?xE5+6@4C>V z@9-hVb1hXtpeoPKJdBev2Y&ed=lKf_y0O)`>3%}Iiab6wbY^%TT4W@ps_aoGPCuO}lARtG5>NGX{k0fRLx0g?n_SJ!` zq2!AbaFu{7@GouOC4#=yvf*`Be7(YxqJOj{t}Ft4;x+HLrHxg-E`*Hd05lPDAInc; zv3U>MWIR0uUyqvU-_JnSd5v4ZU%hGi>@*#1yZ@#Hc3J|^gwcJBHcB}Ap7gSzbd-F# z?>a64(l(w$KRYebyPf~7Rpx6m2>{A5w6JlW0|x5+sJm4D*aJ-R>z7yT_T5W!_>6P{ z1`_pSb|pNL^v03tiPjF#Qaq14b-1E9BGIEhMC{_a^LuW8a0=xL4mFxhe<0M~gn}p} zv+cxuk7;Qg=?#4{P1kxxcWbUQ!|^0?k?^8!e8qYWdNuP+ea_jNu_@}+dH~q0IvqWz z#7ZY3x>hl_mD*$I!k%urqJ(US=ej-`5@f7!6YrdXF67F2@xZ=tzHC$lsC^rUuA{7` zu15a&x~CKPD1{t1J7TYz77ROdOuG4<{2p0|Quy4fdH+ZWya=+c{%0>d$X6g|;JpW$ z*(}%LXCYdE;3kwS&BcX$_H8d~pf1QrFIN1ILT|fmG z*3wJLltle`tZ`4GT9fl>@9DZYp6P5s{pfT?d3b)@$mZ;`BLk#!eNnpbAjbh>G1_pV5-V;IM$_BurEg0Qf&kGaBW;QQ z+oJ+zPQgu^&@Ld*(zka}(0~4KA?1cf#BnK4&ClVG)q^kl)l|;fZ9TnHH>ZBbYH%fP~>2nbB$D0-aM$>teEZvF`JcqUVmpNS|idoZ?#6!J1HZ0zT(xN^R zy{i0Tdc)17*C4%P4eSi8ssRB@1I9LidgEbqAwfgw7*12U<4J7T!n6T)X>z`rSk|** zlkKrf6HQyV>zMNPoW%nutQ^bMxjcy_zQgju1dE_Ci?_Wp#h2r_hU*U?rI9}2c4@+X zpb{Q?yXDkFCTHz{?kt<-PltBZ)c(E2UBTwrfd$9}6}c#pHIL>XtD~u);Yvf!Hi@tw zYks!LXaZAm@SE|Lxl4|4)ut6+E6)e#J~&GH$%gpP^Ozki1N7i>!?8JRrJ4ph%@V|v zA>|58X{cPs-=%e_gyf$9r@|RpmM&IT;8u;}%X~s0Va5Vjr3%I{sw!#V;2>Sr&_YM@ zBiTruJ{nYWL`}S|fqq!g_5F+cH+0QylW(+T8C&;&T4BT5b8S~J%F1jOH#7*>O}T^e z+H51CvpKYUOtdVg9v)glGaL3!banCu&8m*cOr?|ovR*Yci}DEoBzhyh8c?Lv+fpSm zj?93y5?Vf|R9e>P@$Q04LhWoPGH_Lph9zyt%JGNs>X7YY$Hl!>2pZy2Xj7iL1W!hAMkdz(c6??I*8i^1CS!HmkT!p7IA++cR6`i}8}_y4lL`VurlL!M(xG}GVltUW z&p|qV@*k^4u{<6TN6`QWW^NAB=jv3CRuJo$T2o7zY9p(_^IBEmE}FVH&MLF*=9euQ z&q(6kF{WEtD-?n;OVi*E%XaolQZ?SPKt6GE4z&FZNBW#q;{;esiMz!TTF1t7B<=xX z&6R5qOOzAWc6bwt)v%Wk!L;+|2uO`Kq=g zS~JZAsaM?xvH|j6tyR-AOa6+h9#t%%-&t4YP^%B>!`g=m3+BX}tx48QrE{q43m0m3 zVLeIfA)~4`fbST;Jtx~&JYe7PwlGm4M4pII{nq)bOodQ+#@$|PGOG82tLP3v8*MFx zXK*BmtXiiDg7e3M?A6*TdBw{1Vs^#q-AJ*YvzAkvXOD(u&o}rEQS1wv3CUDD|5^RmxHPmXm6a&C8e<;`Se)@Uwv!hEE@O(Jf>(JC9 zQ0mar-rtMDm~KH5ZmfxVdBw+K?AEYx#`$CJHwe)n3tanjBE$euplPYkJ+WsCA0Z+? zbCK*B2?i(urwhKu@(lmS4^cj(;QMn(xf(WF=p@Q^;=-1#rWp{(eObQdXwQvG3vYO1 zG+01zxOHgKMZdpmMu@fJcr0T8Xle$u&L7@T+qI}QW)Xvh3aWEv9gb9We0${N5UUcQ(!jB?6-p9pk|X`BU*2uje3Of z6`-^w+=owYe8}9Z4`8zN>zYWLRiP#yVU=fG432x*;#_$x?Dj=6`-VM*#luzBTtaS z?8`>1z=MKu1A#feMwCDl1L~y_^%Mt?jZg42b^1pl9YJa+nKlx4q5`4A$S}^nMQ8>D zGBnBG1@dyQlOr0s0W*WB3>BhR)4yU}CvdwFgj>&wwoS>y3;BP$*Z~t@`3OQrL7O_+ zII618l=r}DZFHEcnr2zzO~A0*!`4Ns$~6_hvWeENa)3cCer9yDi0n=)OY{L8D5MEl zt~c%6BOt*jB*`hAipBOY;oKvJpbNX9Kv@I!2B0faz~{o;exOV+&gm6EpPL!p06h+% zllz9m;OA5Wd6+2*9hs)gA$7ua0wq%U;z^pjY1|5r5Y~`4nc>J9#mSznB}`RbL8}p} zP;xdypQB(KSrAtmEgHC}ylMmRD=CNbK2+>X6ZD4c{kdh`7m-jg>rY5%Ly=eoc{u{| z$y6Uj`tZgac~;$sC#gCn*%bXHe&eb+78hj zn^+OEh_8YK#_z|DZy>&7a&b>lfVRB7XhBBXk6wRUa0~6bXPFa>i9$L zHRYd~R;Cu(;UX?Uu+w!xhFl&HLIEd(1Xf*ZcMB_GWiql*h7LzuMY6}CfEH=D*T%of zT;o(}NVtwxY(A2Z9^|{+ooPwQlDSMFS6=|wpyrw5$|m&@6%gnkA&d1~`F&-lVsj*g zP!3e`E{-sE&dq)mlFA7%_a5jArgy6&7SwUR`h*4k5p>4W{t7WBrqC@r2Li>hIsCbaPZRmJ_Vw1%LDSi8r&86#g(hLz4 zq?RPg^_Q;Eh9EpIDgEG=jGJ}2a1T4GPv|gM#y+-yR||~LAUhRsgmFEVNJ#!?C0HG; z=q`2ls(uusV^|=-+EXidPOak#sGq`Od&O4#Dfw7e-71$g!Ok7ZS-=Pxdf|k3r{WsQ zurLG{FJK}AtN90rd%z#Zs5j?uv>{QHRZ!!MVEI=2hgH(ZdL`F-oI6puXg|9IH+(Yx zF+y$5I+lR5WvVQ}J}AM)A~E$a($HG`7$AR~PC?mR(Ys&(#A&CDA`ey9E)>pcGmb9G zpS+F%S}#77l5%9^%D&c7YO5b}B%%QUQ)&tQ>1=!D?{=kX z9JS|#9p$pR)h{bmMNYV63IYpso@P=>u({-(xFH<+McJ%zc7(j&hS#BiP23EqqXCr3 zg9{;Ys5t0=S+BWF3G7QDO0R?#H{UKOkW=6*GMqYv0>nHNrYJcc5EE|7j^dnHqucy4 z0TF+t)}nj5-YS2C#_iA{oq2@Q+b6&~OH2m0%vi=H|JVE78{5^Nk4=*?pF^;z7X999 z=^Txf-md$?wO5RkhUmc26w!+ry= zPRAMbdn0#g0W|@2LV7`E<3Hg>u%{S;w3Y;y45e~qZgmrn6M54P+DU(tdHE&SmQ)8+ z2h;`t{>k17{;%w`e+up?@1Mm>%;mYPGC3TYo`7zm z_^dK}TRdDxmrjg!N2GuKk$Aszaz=qb>V zymeLl-?zZs({k2*+JVt))RhdMv|)0z_Hv5Xa@r?`osbqW7#N-#gMnRbzl5$NFlV|L zf3v^`Pnsu&2!Ixr!3!#H(X0grpg|}CB*<8V(X3)1$Q>_>?q*fsfECWWni1x|J=^MG zj&ptjL2QNwkfpz}{nm(Ccny?YLu8Ox1sgz2&i}yn5c0z0+Cl0A#pnHGfc*lYHJwNJ z_pCQfRssS(t;-q=x{ZwqY#IlcjWMmk8Vs!sOAag*515U)?K}2{`!8VsZvnM!APfxp zJI4M`Y_AAxOca4-g+wQ)=7s%79!@$tfzRSb4osvVC5(2ZZ{rimMdn(Sz{NJfK3l}HrKZhk3x;8Eg z;uxQ~1`P!3r}^F6=IJw}g8t~1nTnK*zK+NVzc}5kdFU?c0C`QFiHA1(@vnnCc*Is@ z7rA%YXSpe+#gU;<HwOm zqloFXV&-=9RQX(|Cz%PBFRpS-$9ORzn)H%;MzD9xh`^KsS-#Uu1c~g?7X8pL_=?8i z<9_JoNdbyN7ju+_5O<;$P~8u-p~W=J<%H16DDbOJ zlD7%-$@8rG`<0Ee)hdAT_P&*l1BUu?soWyNb#BV=?Cjc6%`SlJ?|CIoK=>JA(> zEEJCx<`Ee zjs3c>j#{j30(gl9K0jv{ZnxJKm6{)|!MJIq7MENOjwGhi$yF5PMv1h1#1&KO|XaVzW-6#6L(j5+~Puo|!S7%I= zyVQv@+(1W2QpD=0KNNirIRYV{Ab=x^=NbLkdKwkGU>k@%TG&;EM)d;f)%?G-;bIhf zAPwa!u=9hVJDJ1kSOZ6>lcoxj{mK2uRh>w{0eP6lA+&&rYE`sDuM$$WmyL87oWXI#^~# zphRO0Z9zg#36}a=;6ha>sWn2$v5L+Jm{Sq4!}x|q=yYF2M70Av|6nR#3C!qf#qwDS*4`~ zCa5)Jrw#1PH|!uRbcqY+ya54g2)=#5)WjDRuY?P{6(2d909VX72|qNMqY3 ztJf9XH%KB^ouLvq)8ok#iA##+4CL4a>wM3TWZia_jJp;kz3zDTTs7YK~qEa8^*nVcClQ#kzh|e`8g{+EZyBbY>-fo;@TB@(6G=8R%kQw zCKGt|)9H;-l#tDoR+}IF111UrA06s>`VGKfyW4_Nnl};!Hf_`@&Gw27hYuip z75(<>sUNEUbN#Ye$Vc5oXa-msX0YR8{k%kwywz-_HON7%19xfr^ftGbg~RnTQ>1ap ztk)k6HBiPjS%5$|LQn22;t)Q%uG_OTs z1>3czsp=(ik_9jK%i?O&)w=V_lU2>X5hcGE-hKc^qs;Q& zC)XxYeqJVssudqMUinXL)cX@(1)7~6=8|mRBxVbix%<3ba~XG2?}06Bysp z6P3ek%*^X(Ad@3U6QU@3Lj;H>?qE5SEe=5ezi7f{q{!>1ZAfIOkF~tTPQY4bqP>Z~ zaaT}YsqKs3qoyBr2h?%+)R+K#_^xEimEU@;OqUnrDMH!pCc>JvEY{%o`w9ym>I++p z)|7P$MFp({?eg?j=5_8@wqQ!+bQa=9l(Q~5o`}2k=%Iz8{+~Zuk zgSts7K+9Y?&^W;GT4g7}Uy+HW6w6U08jc7y)0A4*3Z9PHyFpx~q!R&^lR?dbxY$(M zHK|Nr%`G3NCCW{6G|mBsmdl_uQj$6R#doZXX1}Wc=DS_WIP_TQo-W7I*fEQUWYuyI zTFRJHM%o4>7V`M7vm536nIhwgFbR9uOfAJuzOoojl(dC9c$=W4=5JHQ!s2xbv64A#&ED zJvVzidNH5K(L0b-tclMjag4_4zh{!d+4!o*7pL}26`27fyAY%{Yvei!vsT4hM-_7U zyzT})>RvUsD-;~P=ZC)`7tmpnpP{q!a0A}M)@sh825 z@(8Xa-kAUc2rmownzs<2B!GT{Ta9-LzoBpZAiy+W*Wp>`Gq(4bZ>zJTb~I`0Iy@J;4)Lw33SZ!uO##yL<4w+?PvAzOD2u7r5@nF=>P|=+;XM-J z<@)F^s_!d?2>)J@(RAI5n}aR_O5Wmx?vGLd?&IFOZHK?(%?N(I+tH;DFQ@)-FTo0b ztNcQlP64|r{2wku4$lPd3ZEfg!(T^$<^8!ptxW*C`A=`h=aY|pv8GQ~?vpz9nxxg{ z`}{i^Sr`nfn5t#$ryrqw!At;YabJ-A9D8;RlX8W6nO2Bzug=XR`Z6gODF+zpb?TsA z&dV32nw{26wXKim^J9Ws zdhOjg%U?6d+~zW%+RHO?l^(31B|B`Pp1>hb`HSa2ho8`k?JUs!p3g59K0azGsam$g zVQfNcZ^S^nguN$1BUu3A@xwz>8epfcrGWs$<#K=f4SuvQ-n3|d7`MLU$Qkk5y*Xn! z#@)^8$!neOTXx>lnG@fs0=ly6$D!?Pr}qA88bHrrK;rG4?*tI zuG^LUG^w!_DhzFW!;Vej>Z=iO|86;lGv<26OC0Y7_Yq4t3iemDkBi?@p6JV+WHmyxdXbyT_`Vgb;4nGr&`l+=V8AT}l4Sr|BGl-^zPEXw2#&k3Ac zOib0tE44-H6*)<2r!Ju^RMEcnm*$TfR}Cwefl7TpqQ}_JtIn5LF}}20MxhkQ6Lpqe zw~hCXspf^+EMp+E^3oE51=`}`Y!R$3n^d}W)K{m~G@h%kQ)1qWe2$6*nI}L=%S-lI z(>(}JgE9;YW`;X_#^k8ZJ&t!z9QKA{O#F1;6_X&XN zR<>U;FqvfjGP%}AK<;{KVLkw$U+ypUkTZ1c4cbxD&p!RF4dwa+Z3oBnGwtnH)K`8# zYHK`>`{%9*IZk8!XIzgj!PZ9hY@|HwVb<4t`r9htwE{6x_lT!T5Z8w->_e`~J(Ls_ zeWUHmlUD~{(xKDtd1hEYM?bkHKwmQ$e%6<`eHP2SnM%KAIBSkW{+DM{L|W^UZ* zqp?Q>MWLzAHouAuj4>iUm6(#5ChCn()kRz>6j;Z&vM?H{XkE>uqvSVpvYQUUB^0dgIcr za=o(Xc*1eJdcdWtQR{eO*?eQ`_+9itZTFVZx*6CSazdP;BR=DQ*sK^>UJT~_2}=J3 zg2zRi@XtO&9vnD)S_~;L4k8y5%YT>jtepP?+0~+J6NNk8@KI|pM?e?UjfM0AYI4mF z3o~LvyRCpha@)?6pYj+hjw!yir{OIqkzW;bS9AwY`ZoFGC@%sU+W$mK>g;*@!ivyxh{Jb-H*%im0#8c%YkMvg4ftN_h;ag>xdFtjB^k1#=(r zs&=c#J2J}C;EZvzcA2^p3gBDq^X3i*eoseF%4W0?RteNvXx$-v1QPQ17Iu? zh3oI4slv>hVrCC;=7cqQWx3MMQ^}I|X~`1}S;@*P%^!F@CZh^>IhUdSRv_B)6o}}@ z1+H8X`x!*+Ix6#w+G+K3{;86xqAih3;#C=s`gHC`ws#_T9x2aD;)L2XaD{_(CN7Qa zBq5V#03F3BB)wcwIvQg&ebA=xA^>eEo|{5(L`E{$_;07Uo;sqTXT)Y<(J9#{Mt3E2 zXGNL@`xWP3=xYx^4)gTFr7awgG2uEo;2h ztw!Bz=_TZ;>X{odpJ&q-qn%pQy@zpk3B50ugA`*gLEUTfGv@Wn<}2L!IRRT`WMGr}y7_n?o*f0{$sr!BKKEg5N=85*3f zteYc4eVX)j>2&R^%!@F$wr;y3R+)neCatBNTC`#OOO(wIztWz&H706?m7$w7JJD$Z zFa(E6A_r`6>0k5Oy1LfkxulsLtkiW%4@0$wc>@ECy)|(^wv0O!(*T!wdJ)b|lv^k* zye}x)(<4w$5~|lUO70@6>2S#Bxs>`5%sPeU`Gfeg{Pbd*XTQ)7Eml78&;7uBRsuJF z*T3h;^V83Ni^&Kn^*s}0+9>L+14&->|VRxZ%bnFr~8>hGZ4R|9h_R=g10 z_50~{>hEBAuKH(aR=i-`bB)UQR;<8y9Qx&1&YK~4Y7CF*R;)sE9t}BYR;*y$SqAO@ z577YWN^F!y38B6WZ*c+IwF&5Ts@V$X_N@efL-;$|ODr8Dm50Su*ZEegAR>_g)U&{} zhZ@9Oy_@(CT8w?eiEN<;uD8*26FbHxxm|5ad*ZYI6IzNs8mSGi?y?|8OW6gzL+fNh zhC|(ndsLUXcsKDP&89l*FL7ep3umvUnl;%DjqJ{0LzWu-hQBG+RmHwu&g#<)F|Jc1~-u%^JL&`t7Wj=#w*~KEn+(>YK`jM~gJl-GnSujz)_t%ouJn zW7U&7?Z{t-VKkX~Q3gjjbcs1!kCDb2kL!Dj8OmmD`37^r26)T#lU_Jau{=$eXs3w= zn^d;0tX4fm?HxEP9o^|TYdLmHd=r%bF|AkjtJlXsi~S@0rG z7`Bk7cmu>MHBeeEqaa!Q+o7dOpVDo}UtycMoU1>@x}*nXpuLGtzxck^1ad#$zOhit z0iG`3N8kGU8%eQc+aJ$QfRDSfWeT4jop!+2Ba*UllF>pLd%8g|BBJ zi5I{7+OJoMfxeg53uZ(8JmpOBPdG3KzwY)<Pm#KZWk&~xK(wN1yGjlrHYsrAeV`dApNmHAwkr4Rpw?@c66*r7wg*?^KQB?wa$ z60Z+N3!Q>{>~}YW&uzc=$KEYKxfd=2#FpQiRkYvR(HFmQzfG}DllQBh-_zyM$8U%2 z`>&V9?d96D3+oYtwl)I$ZNDcVgu70I-SnvTnV~-$1l!vW>j^erJ%H*q4v*eVU(Y(^ zwm66j4-9_pJB7SUzc<&XWrVg~^Ir)~PZC=2y&t;*FU#9o4{?C@ZmM(uil@a4j_sO2 zIcX=y84BX_eNRPm4PKf<&l_3qmsUW-`_z=rDfa^s_n8Yng9%3YpUAuky&f-wptGJQ z`wSPm<6nTc$4xme9Dou?pLS)>$ck^e3+D(XmJGv{A$_fM;TDr2B%R29BQHjtPMHK)AVED@_iSjc zymdz^>AO(Gx*Oa*1*`)q-d@`_iPAS@Dy|k`xVUUjlrV-lnT9>OqjYOF<)UMTQBsZ- zTUZ;pg1!9S^{2)Nb(i=q!@BDW+6t^SaH zi7Ig+Tq+FbIyEy8DGs@*4l#Dq$*McWa^4eUp3Bnm4X&r%m4lNr&R0L%Y$2NK`|mM1 zoiVp$q{mvd_}KM2H#Ba87*wvCx>VWf_v)=AV?>ZqjENR(@aLm#u$MorlDh(G+R?3Q z#7%ZVTYRjUKxx?l#Z%2`YVkgilh-5Y+BT}Vo!LCY2Z?F5PC4K9{z)uF@YX==@M_93 zGa8ti>>SzN`CRq966OGIy#L`E6r*>ZS1P z5n05<7;+i>a_<_BYo1e3-+2jq?6b^qoG5#u`(lR82=o{L*T?el>@Q4;1aMUjk=tv^ z2>>%#qxEciPqCFJT^+n=R{A9nHXDO8V`5!}9v^*3Zs=fVhPx-ni40*ku%kuk#@H_C zJhmuuNJc3ED(-Yw`Oi#7Yo5)Z{Zix18sImjE#jg6cv zM+y4mK#v|IA(&8u4;=rxxr@C`LG?xAn5ixFWzW%WY99%XVXh1hr8O{dQoHz-7L}W} z4aXUy(#H2>Z8&>Qhm6Q|iKnG`_}#Fea7-Uloe{uH(7HXQD*aG-UUrdQ@a0$Vq`S3$ zvV-#i!mXFJH7p6gj-~hslH#KOWL3f2$>0=uL-qfOTmmnNdNpE|IN*t87sW|9%+QhS zPgh?pQfbr+R5prFyT1E6kRnz-dIif5 zK%Q@Ko$;S+MwmiQ;JX!*#6r`f8X-wgK|KBhU3{Y}1^sJWsZz+9c&#&2)SfFhw=oEMtBVZi4a~CEdZLccR2zx zG2Db>vq{ZNp%cevC8#0nZj?Sur@3p^6_rXj&xI)$Th_dP-gc%a0C#!s2)3)q3>nrU z;b`W+^jrQM$n`E6(XY%e6^ly)pEoMU^#)65v&FS?>mDpiQ34j9&Myu5ap;19Z>1Tw z!9CEt(H)+~?{M_5ewtk`4#1c`ftT}=^l~kq6=nkK$!6l;L_Q}S)b7t{jYTzFf$UU` z^Z$XBPs@6_@q{wFDlWFr;oMFtv`fXPkrd&}E^+c!z{jtAg zP0#p1WC`acN0z7g;y02O92&QTDt*b#wW$cljMdj+_NtD)NZc^|Er8UnSyQHPZ;tmV zF%zBl@_laA1^>1SuE+N4x3m9ou_+1tB7Q~5(HwPwOpQ?Qx82uN zFz(%NL^)^asD87U!j!~A+^ZUFhfmaOD#6}xUuep*$H*E8e!C?$)O5@D7j!{xkbMRg zVQP4lvr%k8gdYQr)h|KNb1SK59!j4au`8;aF?%KPo&`Z3ek&-nsff0AP9coS`Bsl_a1R6?J zRW|}RVK)1tE+e!DrCA+~z(>>%qCu4gjgKRf1$!&SUKG|^I>LJn?eXtli$jTHp$slF zO<+A*>xv(*1#3!0g{F6v0N?*l{br3C{Q&gh@e$$#(Qy+T#_Y~j9=s{&61Y^U0iNQc zi4ej%+(mIxskqpcN7zCQS$oKxV|R5=T4~^C$5F;iNS(jIRx;5OW6t#J|p9bH(T5AOS*C zC%3DL(S~gWdC1^-`lN`tPyhL(D2G#eQK)*?1{9$@t`^K&4ntNIEF?thMQGtp~Uz#qgLldy*o~F4gZV?*d-&zD|Fak$5gBxrz%bOT}SaMPp^~S;bkfG=b z`SW}@HBJCB@OQlwUZp8KGXyOi37Uh$_2Nm71%tI%1gq zl#&jHY?$DB=afb7oP6&RRzFE|;n15!7p6^{o7Vi@#B_U&AHzLG>Hv5~C=bj^?Fl`0 zdnOJ4z;Sg*BEd7tzQl30qm2503j4~asKRJ%MH-Qm8l*uQM!JR+l%cyzx;qDs(ny!& z&>l1q_1(3;KYQ)-?0xn*>s|Xj=l$`#?}I(2V{KUq zeeL`@sQO!#iug2dfG1SNsQ8zw>txJOYyy}reuBZa2;HH^Bz^eOatB+00zXg-pFL#r z!(D%PGKNS(A6f)aLLgqKJOsaQS8^oiMSlOd17ylHMHc9GoFPi) zok-P>C4>zkDyfol-6~ktMHG%j)X5O(Xp?S{@shMSrYNn7uaTaSUV6NdGuzu4k1ruQ z3X0(=v9?CXUCVp(mM0zoH|H0Z-@OO~bSI=eZhti;n;qOPmQAU?yy+FMJ)5ty`#MKj z(r3vx8}iJAL|wT90vy=v4fH=1>3_NHT?2LxyY*eV8=lEJ5?DDFd~fNedF-rp`c~46 z*aRujxp3Be?Nhh`2Yf%5SA_@3{!Y!^@qO+M=rtp9OW&5y z(HHG9T6)XwUkdIK3|QSiwB-`qeqoZNbfbebPugDC7ci`z0b&(+tR<{`-!9F6?J96^ z+bf4hSU!OpKd=`mVeD#Ur@7SMQQ|?~(_AY*2yRVb$UCuKh%wgWtgz&2fOgXyu{EP8 zkIGsiJul(?IsrLh6rX3IT^vfAU_TkmbKOkAt4=r5L$;Ud!@sUPwu*Pem^pn!F9(tep)KW_-|^D*XJxOb7Uq_D+LQIE(l3j0c?-N)LL`p@y0#JQ8oc zC`m@HU>4Wf7_mRfkgnfrejrpUT!YaqyfhIJ<~40kut=%!C-1zr+*cvJxiG z8l*7Xbvu=hIiDx3y>*3^ttrJN>&*%mFg(%G{mV`!lkm0zu?PO0DuXElAPEX&s&4Kq zqro}5#!V7;0mH+MpdTUb+%r4{6Ow8^HvV99Kl=5+CAn<_sDH%Cn&xcz zF_USuFl6IL%)a*6xUVKOJnbw00Dl^z?0f{hsYBqibU%aJzOr!mWCNifSuvqF4n|If ztGC05Dp$Pb+Lk#mb3;=y@F#(qup!F;0cW+w=pL}euxl}%zp6q>p`m1$z-2S)(!wE+YEIlFw1v9sQ2HP^d`Yqd95Im3bb%{c* zQn}YaLP?IFJlj0YaJpC$JFaqScx&+8t@DM?xP%ZuHs%~a$96(RhChamTv@;kaR@`Q? z#!-oS?0!F~hFHU*ktbGx@1tnT!e}3dJC09VAgC#@**gaw;-EjRK&v0rnfzlhAoxR; zSPq&Ui@oK(en;}qI%eDVj}cV^_GRr`9%V>JX^|)dtjMw+SB=c;gHXYvKl-T(+i8&%--aBdA zC1Eg^&0=wbgI&VlJlxOzOTo*66XgmK-)OlHIxd}}1{()C-}v5HvGL2VN76*r)6@s0 zWtBEA28T$A$CS&BN%Y=iSk&t8$>pS%+OWi=~V8ZMoqd3%*-fysp zFneqR@KG~dr9oZpY&^Y2#Nf133p%dKSCcqBUzFE8b{~#sM+9F@GtEh0^>NJqK zO;UQM-#b9I<-R(5M<=o9oe1S&O`-tA8Cv+6#E zBEa(#7gd&XB^_P6nX1)y(MJ~A=&VIR_jG}>(AHFMgnJxiMQ-GH5($p0}1YdJ#c*7 zF3j9lNhy*-ul_!T7w5O4U*d5EEUH#=-JLoWo|sGdhLAZH3!zYq7BPus1xN5);KQ^; zSVKd5J$?ya8}0h4c6@_>>wML`K;xhNM%8V>te@o9T)8s?dG(DOrKV3L<*A3lKy5)y zqFZgWi!@}>-nh6#$<_soPDH=ChO9w66BblvgE{Bw3$W0()9p)-W_<%=Sg^HH5i^=O z5+lB1;IA%tf$I50rBsx@P)M+9p~wq`rx47$xPC8a`8y2uzuXfH7T;G_2r?B9V|}YWUBuJ zpAh-3HXYVVH}WJQv$^}VQC&lF>9m)gWRmL8Cz*9C&glOvn_t^FU0a+fQHq^HO9*3$ z<2_5mg?_$!7v>U74AdScp`?kY=V^torLbvwcRxy^&seeQuv#iDgZ_Keq~A;yCJ5lf zns#j@GWp9jKByjGPC)zjH{V7TuH0r#UB^0Z*eACVhg*|Ad?3<&=g`z~I!G)hi2p_& zf3n7+Ah2iQJyQa&wJiZFl-{@`^k6Ww>4SK6+ym*hEx_gCp(Fj7${l?X5d#FFVk~-> zBoM85Rd)w-nK>9jXa-z#ng70J2Ayd$W=njp`7ZF|BB0rlgj@XmBahYVx_f_qIG+Sa z?6m{3O`l)}w;A5;A+Wo!i$50v$z610kORo_ayPH^@^VY@Up6EEE|`lYko_|INXsq? zZJADee4qRO{Mx};KYa060O4omgaW!w!FEhwVPOo-)sV>)%p}AF#-KVL9=;elLjU>M0FcjCLwQ1d$$1WKHHq@;h?X#z1Tbv>cjoBMV(s64W^Q&lW0Fiiy-z81bvP5N&e~nvz{`pMc*r*fS2*}9FN^&h{gJ- zP(CQ;zS?>q@jTpr(o<^Ru^Dw(TlPe7nV{XV#_5VUppOA%f`arR>yw*Osrt|-_fhsJ zhCXz$BBB=2qA$HchVn=8_XYM4pfpURmDR@C+{D~stkw3tP!=W~3fRBc_|`s+31S83 zQXR)GkO<|Mt4}u3M5m6=^a5Z%>)v?8Izl}<3;6l$HydBY4WU^%yuwYe19!p6!HMiM z$TQu)plSSwYPrI^?0L&!w>ioVMb{VNSx5!JuaSNogE+e3?&AtnYKIc#$wWJupzWeo zDFRhPUJ%7YBDN4J2)k&3pX|R0`1ZfY7$OW2?9oC;!S6FuRZ{6Ze)72yxTUVPGglip z10G+aM^;8iT9}%-M=Tnh$ll{bry+NzS-dvv*cWTaOxVVy6-O+_ip`5gc2qwbt|Oob zuf7(+WdA5C%eXxLBJbS7~F{mv}j|9C#t&$k|dc{e;qn+&9I z#{L|0?sLiYVhp0bQHwX(sTNh}j>u6vkiw$K@ z{QJ&^hyjBfCeh(X{Y~G12r&MV1zqP<*4kIrs?e<=DOcAwK0SkCQjD$v4MaU0V(m1p zZVk|$Xwi0h*H;ZZJ)0u!bgsq?E_>&xGd}8;7srlS#ix&ws6uuvk!wjg_(%BDap;8D@LF8b*m}|f8od(Y>8Q%We#7xz zoEH47pU=$R)OZqqRJ@(8p$uEnN@!%x<~=C#}jF@L4PbBV&KMLw_VtY)F(ePY+W-I zu6`FkO1TaLmBl`cBh_K>$7Ia@j7_cka`x};VZTSc1u*6(vM~41@L!=nW?1 zWc_Xd$iA+S;TS~ZYWDEjoroM!{J?y>2S1^go+iR8o9K@fg!gq+Jw8<*xe?)4D~U*2 zi^}nUqDdE=l4{5c+^8$N567Hz8Yzc>2r13seYFsGO22}(l^s`$kMJ`-1dc5t3-nGF9&0+ee(~ z@eG_v@!DGC)Xq!2ZKm%XiQ1vXNqq0ZcN>i!InUd$zt@YOBR$(OiLLgPQQ~W(&`TI_ zkJTE^d6v)Wr5cl|bDojJSx(9QL{0Ub0K4vAY+F4p5ml9Bor(;Y<#`VnD9xa=qvv0d zqvujnVgS8~8}5taU`hTH9yh$6Va0MH4oZ;E$KO=Qf3T^jclSx?`Itxa$@|kWErzpD zw(;6o^NV%lP~kRZ{h%6VKCo1$KRFzYcir&4u=$J2McS(Lrt><9U?3Xm2?P4pDPw!;^=ZQ{?X z2Lg9*XWycQR{2F+Lr0NW{2$B)-p$_pwM?qZj!;C1JdR zwPbv0)fF@X2*gR{>VIFqNx7wS@#>DAI*BB&DO7o(d+{So1jhY`E@xr5LzxB?G<&LZL3BrLnHrl2 zbFnpM&7rH&e0Anz)N1`JIurE9`Ca8fmMkOib&*&W5cB%^>l;T>9sN>&@fqj-i|=(e zX4g0m#Js#Si`DZL)paSJs#mzL!MN^?DeZTr<(5x{&o*!P0>HH>9iYmN3!lER=G0Wm8iL7jkh0ZUJp9&w)lp3wR(>} zQqhwpsarey^(#RFTKX6YQu7F1PrC7LV{yE#RRGH@66#6&v0J|dcVQKGInvYZCj2y zSP-jJ5O2_mezRA4Qcaaej)==?qkNz!Bm*;B1^Mvw1E&QvYUHxSt1ygWPZPX7d9Qo~ z(30jS<|N4eB(IDl|MXqjfd}fohOra%_9;j0d0AK9XHX0o*>NEfm()#lCghZ48rDIOjYQ1;ijSQ4U4c zg}&P}(Cr9&m)tk_7ob3*PiSRr{>z+ghmyj$FpmGnp{iAynkae0`7bafMR~(Jj$2YV zK&y5tG&P|l8$Xl%UpG>zuue_bEF_-WobD;f0`cQE*kO`q^8nbwI)n}>Oj}r@Nweji zG%U`t9-F}WENQr8JJy0t#g;zxi3akf)GLCuD&QvOc*k)!bYuP4iRCQpxOr{n)9lqO z<51{Zr}1WjW)+N(^ouXLi?tvgIIRrvrY&Q!kL$^%Qom78G@$R|xIINWHowCWEa zo~Qx$Y-Id>?I@!{Axk$dJ)11*bB(7doK>1Ps(7=_tTH2Raxul76dih diff --git a/libAACdec/include/aacdecoder_lib.h b/libAACdec/include/aacdecoder_lib.h index 56f4ec1..d7928c0 100644 --- a/libAACdec/include/aacdecoder_lib.h +++ b/libAACdec/include/aacdecoder_lib.h @@ -1032,7 +1032,7 @@ LINKSPEC_H AAC_DECODER_ERROR aacDecoder_Fill(HANDLE_AACDECODER self, * \param self AAC decoder handle. * \param pTimeData Pointer to external output buffer where the decoded PCM * samples will be stored into. - * \param timeDataSize Size of external output buffer. + * \param timeDataSize Size of external output buffer in PCM samples. * \param flags Bit field with flags for the decoder: \n * (flags & AACDEC_CONCEAL) == 1: Do concealment. \n * (flags & AACDEC_FLUSH) == 2: Discard input data. Flush From f724d3361fc367db0fe82a06a4d43f2eba0f95d6 Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Fri, 17 Apr 2020 15:11:43 +0200 Subject: [PATCH 78/78] Adjust eqSubbandGainFormat data type to prevent load of invalid value in _skipEqCoefficients(). Bug: 186777497 Test: atest android.media.cts.DecoderTestAacFormat android.media.cts.DecoderTestXheAac android.media.cts.DecoderTestAacDrc Change-Id: Ibd70f0c3e591d5581e5fe2a7469181bc0ba95a3c --- libDRCdec/src/drcDec_reader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libDRCdec/src/drcDec_reader.cpp b/libDRCdec/src/drcDec_reader.cpp index b3ec187..b080f50 100644 --- a/libDRCdec/src/drcDec_reader.cpp +++ b/libDRCdec/src/drcDec_reader.cpp @@ -917,7 +917,7 @@ static void _skipEqCoefficients(HANDLE_FDK_BITSTREAM hBs) { firFilterOrder; int uniqueEqSubbandGainsCount, eqSubbandGainRepresentation, eqSubbandGainCount; - EQ_SUBBAND_GAIN_FORMAT eqSubbandGainFormat; + int eqSubbandGainFormat; eqDelayMaxPresent = FDKreadBits(hBs, 1); if (eqDelayMaxPresent) { @@ -958,7 +958,7 @@ static void _skipEqCoefficients(HANDLE_FDK_BITSTREAM hBs) { uniqueEqSubbandGainsCount = FDKreadBits(hBs, 6); if (uniqueEqSubbandGainsCount > 0) { eqSubbandGainRepresentation = FDKreadBits(hBs, 1); - eqSubbandGainFormat = (EQ_SUBBAND_GAIN_FORMAT)FDKreadBits(hBs, 4); + eqSubbandGainFormat = FDKreadBits(hBs, 4); switch (eqSubbandGainFormat) { case GF_QMF32: eqSubbandGainCount = 32;