aboutsummaryrefslogtreecommitdiffstats
path: root/libAACenc
diff options
context:
space:
mode:
authorDave Burke <daveburke@google.com>2012-05-12 13:17:25 -0700
committerDave Burke <daveburke@google.com>2012-05-12 13:47:46 -0700
commit698b536f3b34a7cfc41a80e1034cc359456bdd66 (patch)
treefa3dfa75d535b188725f1b84316cb4b06db79771 /libAACenc
parent9bf37cc9712506b2483650c82d3c41152337ef7e (diff)
downloadODR-AudioEnc-698b536f3b34a7cfc41a80e1034cc359456bdd66.tar.gz
ODR-AudioEnc-698b536f3b34a7cfc41a80e1034cc359456bdd66.tar.bz2
ODR-AudioEnc-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.cpp95
-rw-r--r--libAACenc/src/aacenc.h27
-rw-r--r--libAACenc/src/aacenc_lib.cpp164
-rw-r--r--libAACenc/src/psy_data.h2
-rw-r--r--libAACenc/src/qc_main.cpp35
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 */