diff options
author | Dave Burke <daveburke@google.com> | 2012-05-12 13:17:25 -0700 |
---|---|---|
committer | Dave Burke <daveburke@google.com> | 2012-05-12 13:47:46 -0700 |
commit | 698b536f3b34a7cfc41a80e1034cc359456bdd66 (patch) | |
tree | fa3dfa75d535b188725f1b84316cb4b06db79771 /libAACenc | |
parent | 9bf37cc9712506b2483650c82d3c41152337ef7e (diff) | |
download | fdk-aac-698b536f3b34a7cfc41a80e1034cc359456bdd66.tar.gz fdk-aac-698b536f3b34a7cfc41a80e1034cc359456bdd66.tar.bz2 fdk-aac-698b536f3b34a7cfc41a80e1034cc359456bdd66.zip |
Update to 2012_05_11 version.
Fixes:
- Don't throw error for invalid bitrate but limit to functional value
- More robust ASC parsing
- More robust handling of corrupt bitstreams
- Handle multiple raw access units
Change-Id: Ib49fe2545ff4185fe924126da702fe84ac5c2d87
Diffstat (limited to 'libAACenc')
-rw-r--r-- | libAACenc/src/aacenc.cpp | 95 | ||||
-rw-r--r-- | libAACenc/src/aacenc.h | 27 | ||||
-rw-r--r-- | libAACenc/src/aacenc_lib.cpp | 164 | ||||
-rw-r--r-- | libAACenc/src/psy_data.h | 2 | ||||
-rw-r--r-- | libAACenc/src/qc_main.cpp | 35 |
5 files changed, 252 insertions, 71 deletions
diff --git a/libAACenc/src/aacenc.cpp b/libAACenc/src/aacenc.cpp index 5ab7192..c2c744f 100644 --- a/libAACenc/src/aacenc.cpp +++ b/libAACenc/src/aacenc.cpp @@ -43,48 +43,61 @@ +#define MIN_BUFSIZE_PER_EFF_CHAN 6144 + static AAC_ENCODER_ERROR FDKaacEnc_InitCheckAncillary(INT bitRate, INT framelength, INT ancillaryRate, INT *ancillaryBitsPerFrame, INT sampleRate); -/** - * For calculating average bitrate of an access unit 32 bit data width is not sufficient - * in worst case. Therefore use scaling of the samplingrate parameter to keep complete information. - */ -typedef struct { - INT samplingRate; - UCHAR scalingFactor; -} SR_SCALING_TAB; - -static const SR_SCALING_TAB samplingRateScalingTable[] = +INT FDKaacEnc_LimitBitrate( + HANDLE_TRANSPORTENC hTpEnc, + INT coreSamplingRate, + INT frameLength, + INT nChannels, + INT nChannelsEff, + INT bitRate, + INT averageBits, + INT *pAverageBitsPerFrame, + INT bitrateMode, + INT nSubFrames + ) { - { 8000, 5 }, { 11025, 0 }, { 12000, 5 }, { 16000, 5 }, - { 22050, 1 }, { 24000, 5 }, { 32000, 5 }, { 44100, 2 }, - { 48000, 5 }, { 64000, 5 }, { 88200, 3 }, { 96000, 5 } -}; + INT transportBits, prevBitRate, averageBitsPerFrame, shift = 0, iter=0; -/** - * Get maximal scaling factor without losing samplingrate accuracy. - * - * \param samplingRate Samplingrate to be used. - * \return scaling value. - */ -static int GetSrSf(const INT samplingRate) -{ - int i, result = 0; + while ( (frameLength & ~((1<<(shift+1))-1)) == frameLength + && (coreSamplingRate & ~((1<<(shift+1))-1)) == coreSamplingRate ) + { + shift ++; + } - for (i=0; i<(int)(sizeof(samplingRateScalingTable)/sizeof(SR_SCALING_TAB)); i++) { - if ( samplingRateScalingTable[i].samplingRate == samplingRate ) { - result = samplingRateScalingTable[i].scalingFactor; - break; + do { + prevBitRate = bitRate; + averageBitsPerFrame = (bitRate*(frameLength>>shift)) / (coreSamplingRate>>shift) / nSubFrames; + + if (pAverageBitsPerFrame != NULL) { + *pAverageBitsPerFrame = averageBitsPerFrame; } - } - return result; + + if (hTpEnc != NULL) { + transportBits = transportEnc_GetStaticBits(hTpEnc, averageBitsPerFrame); + } else { + /* Assume some worst case */ + transportBits = 208; + } + + bitRate = FDKmax(bitRate, ((((40 * nChannels) + transportBits + frameLength) * (coreSamplingRate)) / frameLength) ); + FDK_ASSERT(bitRate >= 0); + + bitRate = FDKmin(bitRate, ((nChannelsEff * MIN_BUFSIZE_PER_EFF_CHAN)*(coreSamplingRate>>shift)) / (frameLength>>shift)) ; + FDK_ASSERT(bitRate >= 0); + + } while (prevBitRate != bitRate && iter++ < 3) ; + + return bitRate; } -#define MIN_BUFSIZE_PER_EFF_CHAN 6144 typedef struct { @@ -349,16 +362,20 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize(HANDLE_AAC_ENC hAacEnc, /* check bit rate */ - /* check if bitRate is not too low or high */ - averageBitsPerFrame = (config->bitRate*(config->framelength>>GetSrSf(config->sampleRate))) / (config->sampleRate>>GetSrSf(config->sampleRate)) / config->nSubFrames; - - /* assume minimum static bits of 40 in each channel. */ - if ( (averageBitsPerFrame <= ((40*config->nChannels) + transportEnc_GetStaticBits(hTpEnc, averageBitsPerFrame))) || - ( ((config->bitRate*(config->framelength>>GetSrSf(config->sampleRate)))) > - ((FDKaacEnc_GetChannelModeConfiguration(config->channelMode)->nChannelsEff * MIN_BUFSIZE_PER_EFF_CHAN))*(config->sampleRate>>GetSrSf(config->sampleRate)) ) - ) + if (FDKaacEnc_LimitBitrate( + hTpEnc, + config->sampleRate, + config->framelength, + config->nChannels, + FDKaacEnc_GetChannelModeConfiguration(config->channelMode)->nChannelsEff, + config->bitRate, + config->averageBits, + &averageBitsPerFrame, + config->bitrateMode, + config->nSubFrames + ) != config->bitRate ) { - return AAC_ENC_UNSUPPORTED_BITRATE; + return AAC_ENC_UNSUPPORTED_BITRATE; } if (config->syntaxFlags & AC_ER_VCB11) { diff --git a/libAACenc/src/aacenc.h b/libAACenc/src/aacenc.h index 66ef2b9..22228f6 100644 --- a/libAACenc/src/aacenc.h +++ b/libAACenc/src/aacenc.h @@ -159,6 +159,33 @@ typedef struct { typedef struct AAC_ENC *HANDLE_AAC_ENC; +/** + * \brief Limit given bit rate to a valid value + * \param hTpEnc transport encoder handle + * \param coreSamplingRate the sample rate to be used for the AAC encoder + * \param frameLength the frameLength to be used for the AAC encoder + * \param nChannels number of total channels + * \param nChannelsEff number of effective channels + * \param bitRate the initial bit rate value for which the closest valid bit rate value is searched for + * \param averageBits average bits per frame for fixed framing. Set to -1 if not available. + * \param optional pointer where the current bits per frame are stored into. + * \param bitrateMode the current bit rate mode + * \param nSubFrames number of sub frames for super framing (not transport frames). + * \return a valid bit rate value as close as possible or identical to bitRate + */ +INT FDKaacEnc_LimitBitrate( + HANDLE_TRANSPORTENC hTpEnc, + INT coreSamplingRate, + INT frameLength, + INT nChannels, + INT nChannelsEff, + INT bitRate, + INT averageBits, + INT *pAverageBitsPerFrame, + INT bitrateMode, + INT nSubFrames + ); + /*----------------------------------------------------------------------------- functionname: FDKaacEnc_GetVBRBitrate diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp index 65a9bfc..7984c13 100644 --- a/libAACenc/src/aacenc_lib.cpp +++ b/libAACenc/src/aacenc_lib.cpp @@ -388,6 +388,138 @@ AAC_ENCODER_ERROR aacEncDefaultConfig(HANDLE_AACENC_CONFIG hAacConfig, return AAC_ENC_OK; } +static +void aacEncDistributeSbrBits(CHANNEL_MAPPING *channelMapping, SBR_ELEMENT_INFO *sbrElInfo, INT bitRate) +{ + INT codebits = bitRate; + int el; + + /* Copy Element info */ + for (el=0; el<channelMapping->nElements; el++) { + sbrElInfo[el].ChannelIndex[0] = channelMapping->elInfo[el].ChannelIndex[0]; + sbrElInfo[el].ChannelIndex[1] = channelMapping->elInfo[el].ChannelIndex[1]; + sbrElInfo[el].elType = channelMapping->elInfo[el].elType; + sbrElInfo[el].bitRate = (INT)(fMultNorm(channelMapping->elInfo[el].relativeBits, (FIXP_DBL)bitRate)); + sbrElInfo[el].instanceTag = channelMapping->elInfo[el].instanceTag; + sbrElInfo[el].nChannelsInEl = channelMapping->elInfo[el].nChannelsInEl; + + codebits -= sbrElInfo[el].bitRate; + } + sbrElInfo[0].bitRate += codebits; +} + + +static +INT aacEncoder_LimitBitrate( + const HANDLE_TRANSPORTENC hTpEnc, + const INT samplingRate, + const INT frameLength, + const INT nChannels, + const CHANNEL_MODE channelMode, + INT bitRate, + const INT nSubFrames, + const INT sbrActive, + const AUDIO_OBJECT_TYPE aot + ) +{ + INT coreSamplingRate; + CHANNEL_MAPPING cm; + + FDKaacEnc_InitChannelMapping(channelMode, CH_ORDER_MPEG, &cm); + + if (sbrActive) { + /* Assume SBR rate ratio of 2:1 */ + coreSamplingRate = samplingRate / 2; + } else { + coreSamplingRate = samplingRate; + } + + /* Consider bandwidth channel bit rate limit (see bandwidth.cpp: GetBandwidthEntry()) */ + if (aot == AOT_ER_AAC_LD || aot == AOT_ER_AAC_ELD) { + bitRate = FDKmin(360000*nChannels, bitRate); + bitRate = FDKmax(8000*nChannels, bitRate); + } + + if (aot == AOT_AAC_LC || aot == AOT_SBR || aot == AOT_PS) { + bitRate = FDKmin(576000*nChannels, bitRate); + /*bitRate = FDKmax(0*nChannels, bitRate);*/ + } + + + /* Limit bit rate in respect to the core coder */ + bitRate = FDKaacEnc_LimitBitrate( + hTpEnc, + coreSamplingRate, + frameLength, + nChannels, + cm.nChannelsEff, + bitRate, + -1, + NULL, + -1, + nSubFrames + ); + + /* Limit bit rate in respect to available SBR modes if active */ + if (sbrActive) + { + SBR_ELEMENT_INFO sbrElInfo[6]; + INT sbrBitRate = 0; + int e, tooBig=-1; + + FDK_ASSERT(cm.nElements <= (6)); + + /* Get bit rate for each SBR element */ + aacEncDistributeSbrBits(&cm, sbrElInfo, bitRate); + + for (e=0; e<cm.nElements; e++) + { + INT sbrElementBitRateIn, sbrBitRateOut; + + if (cm.elInfo[e].elType != ID_SCE && cm.elInfo[e].elType != ID_CPE) { + continue; + } + sbrElementBitRateIn = sbrElInfo[e].bitRate; + sbrBitRateOut = sbrEncoder_LimitBitRate(sbrElementBitRateIn , cm.elInfo[e].nChannelsInEl, coreSamplingRate, aot); + if (sbrBitRateOut == 0) { + return 0; + } + if (sbrElementBitRateIn < sbrBitRateOut) { + FDK_ASSERT(tooBig != 1); + tooBig = 0; + if (e == 0) { + sbrBitRate = 0; + } + } + if (sbrElementBitRateIn > sbrBitRateOut) { + FDK_ASSERT(tooBig != 0); + tooBig = 1; + if (e == 0) { + sbrBitRate = 5000000; + } + } + if (tooBig != -1) + { + INT sbrBitRateLimit = (INT)fDivNorm((FIXP_DBL)sbrBitRateOut, cm.elInfo[e].relativeBits); + if (tooBig) { + sbrBitRate = fMin(sbrBitRate, sbrBitRateLimit-16); + FDK_ASSERT( (INT)fMultNorm(cm.elInfo[e].relativeBits, (FIXP_DBL)sbrBitRate) < sbrBitRateOut); + } else { + sbrBitRate = fMax(sbrBitRate, sbrBitRateLimit+16); + FDK_ASSERT( (INT)fMultNorm(cm.elInfo[e].relativeBits, (FIXP_DBL)sbrBitRate) >= sbrBitRateOut); + } + } + } + if (tooBig != -1) { + bitRate = sbrBitRate; + } + } + + FDK_ASSERT(bitRate > 0); + + return bitRate; +} + /* * \brief Consistency check of given USER_PARAM struct and * copy back configuration from public struct into internal @@ -482,6 +614,19 @@ AACENC_ERROR FDKaacEnc_AdjustEncSettings(HANDLE_AACENCODER hAacEncoder, break; } + /* We need the frame length to call aacEncoder_LimitBitrate() */ + hAacConfig->bitRate = aacEncoder_LimitBitrate( + NULL, + hAacConfig->sampleRate, + hAacConfig->framelength, + hAacConfig->nChannels, + hAacConfig->channelMode, + config->userBitrate, + hAacConfig->nSubFrames, + isSbrActive(hAacConfig), + hAacConfig->audioObjectType + ); + switch ( hAacConfig->audioObjectType ) { case AOT_ER_AAC_LD: case AOT_ER_AAC_ELD: @@ -605,7 +750,6 @@ static AACENC_ERROR aacEncInit(HANDLE_AACENCODER hAacEncoder, INT frameLength = hAacConfig->framelength; - if ( (InitFlags & AACENC_INIT_CONFIG) ) { CHANNEL_MODE prevChMode = hAacConfig->channelMode; @@ -645,9 +789,7 @@ static AACENC_ERROR aacEncInit(HANDLE_AACENCODER hAacEncoder, INT sbrError; SBR_ELEMENT_INFO sbrElInfo[(6)]; CHANNEL_MAPPING channelMapping; - int el; - INT codebits = hAacConfig->bitRate; - INT bitrateSc = CountLeadingBits(codebits); + AUDIO_OBJECT_TYPE aot = hAacConfig->audioObjectType; if ( FDKaacEnc_InitChannelMapping(hAacConfig->channelMode, @@ -662,19 +804,7 @@ static AACENC_ERROR aacEncInit(HANDLE_AACENCODER hAacEncoder, return AACENC_INIT_ERROR; } - /* Copy Element info */ - for (el=0; el<channelMapping.nElements; el++) { - sbrElInfo[el].ChannelIndex[0] = channelMapping.elInfo[el].ChannelIndex[0]; - sbrElInfo[el].ChannelIndex[1] = channelMapping.elInfo[el].ChannelIndex[1]; - sbrElInfo[el].elType = channelMapping.elInfo[el].elType; - sbrElInfo[el].bitRate = (INT)(fMult(channelMapping.elInfo[el].relativeBits, (FIXP_DBL)(hAacConfig->bitRate<<bitrateSc))>>(bitrateSc)); - sbrElInfo[el].instanceTag = channelMapping.elInfo[el].instanceTag; - sbrElInfo[el].nChannelsInEl = channelMapping.elInfo[el].nChannelsInEl; - - sbrElInfo[el].bitRate = fMult(channelMapping.elInfo[el].relativeBits, (FIXP_DBL)hAacConfig->bitRate); - codebits -= sbrElInfo[el].bitRate; - } - sbrElInfo[0].bitRate += codebits; + aacEncDistributeSbrBits(&channelMapping, sbrElInfo, hAacConfig->bitRate); UINT initFlag = 0; initFlag += (InitFlags & AACENC_INIT_STATES) ? 1 : 0; diff --git a/libAACenc/src/psy_data.h b/libAACenc/src/psy_data.h index af3cde8..38faac1 100644 --- a/libAACenc/src/psy_data.h +++ b/libAACenc/src/psy_data.h @@ -60,7 +60,7 @@ typedef shouldBeUnion{ typedef struct{ INT_PCM* psyInputBuffer; - FIXP_DBL RESTRICT overlapAddBuffer[1024]; + FIXP_DBL overlapAddBuffer[1024]; BLOCK_SWITCHING_CONTROL blockSwitchingControl; /* block switching */ FIXP_DBL sfbThresholdnm1[MAX_SFB]; /* FDKaacEnc_PreEchoControl */ diff --git a/libAACenc/src/qc_main.cpp b/libAACenc/src/qc_main.cpp index df9c4c4..3414310 100644 --- a/libAACenc/src/qc_main.cpp +++ b/libAACenc/src/qc_main.cpp @@ -1314,23 +1314,30 @@ AAC_ENCODER_ERROR FDKaacEnc_FinalizeBitConsumption(CHANNEL_MAPPING *cm, /* Now we can get the exact transport bit amount, and hopefully it is equal to the estimated value */ exactTpBits = transportEnc_GetStaticBits(hTpEnc, qcOut->totalBits); - while (exactTpBits != qcKernel->globHdrBits && (max_iter-- > 0)) - { - INT diffBits = qcKernel->globHdrBits-exactTpBits; - if (diffBits >= 0) { - /* move bits from header to payload */ - qcOut->totFillBits += diffBits; - qcOut->totalBits += diffBits; - qcOut->grantedDynBits += diffBits; + if (exactTpBits != qcKernel->globHdrBits) { + INT diffFillBits = 0; + + /* Number of bits which can be moved to bitreservoir. */ + INT bitsToBitres = qcKernel->globHdrBits - exactTpBits; + + if (bitsToBitres>0) { + /* if bitreservoir can not take all bits, move ramaining bits to fillbits */ + diffFillBits = FDKmax(0, bitsToBitres - (qcKernel->bitResTotMax-qcKernel->bitResTot)); } - else { - /* get missing bits from bitreservoir */ - qcKernel->bitResTot += diffBits; + else if (bitsToBitres<0) { + /* if bits mus be taken from bitreservoir, reduce fillbits first. */ + diffFillBits = (FDKmax(FDKmax(bitsToBitres, -qcKernel->bitResTot), -qcOut->totFillBits)); } - qcKernel->globHdrBits = exactTpBits; - exactTpBits = transportEnc_GetStaticBits(hTpEnc, qcOut->totalBits); + + diffFillBits = (diffFillBits+7)&~7; /* assure previous alignment */ + + qcOut->totFillBits += diffFillBits; + qcOut->totalBits += diffFillBits; + qcOut->grantedDynBits += diffFillBits; + + /* new header bits */ + qcKernel->globHdrBits = transportEnc_GetStaticBits(hTpEnc, qcOut->totalBits); } - FDK_ASSERT(exactTpBits == qcKernel->globHdrBits); } /* Save total fill bits and distribut to alignment and fill bits */ |