mirror of https://github.com/mstorsjo/fdk-aac.git
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
This commit is contained in:
parent
b831187d3a
commit
e499f9485e
|
@ -1,7 +1,7 @@
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
Software License for The Fraunhofer FDK AAC Codec Library for Android
|
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.
|
Forschung e.V. All rights reserved.
|
||||||
|
|
||||||
1. INTRODUCTION
|
1. INTRODUCTION
|
||||||
|
@ -245,6 +245,46 @@ INT FDKaacEnc_GetVBRBitrate(AACENC_BITRATE_MODE bitrateMode,
|
||||||
return bitrate;
|
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.
|
* \brief Convert encoder bitreservoir value for transport library.
|
||||||
*
|
*
|
||||||
|
@ -397,7 +437,6 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize(
|
||||||
FIXP_DBL mbfac, bw_ratio;
|
FIXP_DBL mbfac, bw_ratio;
|
||||||
QC_INIT qcInit;
|
QC_INIT qcInit;
|
||||||
INT averageBitsPerFrame = 0;
|
INT averageBitsPerFrame = 0;
|
||||||
int bitresMin = 0; /* the bitreservoir is always big for AAC-LC */
|
|
||||||
const CHANNEL_MODE prevChannelMode = hAacEnc->encoderMode;
|
const CHANNEL_MODE prevChannelMode = hAacEnc->encoderMode;
|
||||||
|
|
||||||
if (config == NULL) return AAC_ENC_INVALID_HANDLE;
|
if (config == NULL) return AAC_ENC_INVALID_HANDLE;
|
||||||
|
@ -553,7 +592,6 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize(
|
||||||
qcInit.minBits = fixMin(qcInit.minBits, averageBitsPerFrame & ~7);
|
qcInit.minBits = fixMin(qcInit.minBits, averageBitsPerFrame & ~7);
|
||||||
} else {
|
} else {
|
||||||
INT bitreservoir = -1; /* default bitreservoir size*/
|
INT bitreservoir = -1; /* default bitreservoir size*/
|
||||||
bitresMin = BITRES_MIN;
|
|
||||||
if (isLowDelay(config->audioObjectType)) {
|
if (isLowDelay(config->audioObjectType)) {
|
||||||
INT brPerChannel = config->bitRate / config->nChannels;
|
INT brPerChannel = config->bitRate / config->nChannels;
|
||||||
brPerChannel = fMin(BITRATE_MAX_LD, fMax(BITRATE_MIN_LD, brPerChannel));
|
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)) +
|
bitreservoir = fMultI(slope, (INT)(BITRES_MAX_LD - BITRES_MIN_LD)) +
|
||||||
BITRES_MIN_LD; /* interpolate */
|
BITRES_MIN_LD; /* interpolate */
|
||||||
bitreservoir = bitreservoir & ~7; /* align to bytes */
|
bitreservoir = bitreservoir & ~7; /* align to bytes */
|
||||||
bitresMin = BITRES_MIN_LD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int maxBitres;
|
int maxBitres;
|
||||||
|
@ -604,7 +641,8 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize(
|
||||||
qcInit.nSubFrames = config->nSubFrames;
|
qcInit.nSubFrames = config->nSubFrames;
|
||||||
qcInit.padding.paddingRest = config->sampleRate;
|
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 */
|
qcInit.bitResMode = AACENC_BR_MODE_FULL; /* full bitreservoir */
|
||||||
} else if (qcInit.maxBits > qcInit.averageBits) {
|
} else if (qcInit.maxBits > qcInit.averageBits) {
|
||||||
qcInit.bitResMode = AACENC_BR_MODE_REDUCED; /* reduced bitreservoir */
|
qcInit.bitResMode = AACENC_BR_MODE_REDUCED; /* reduced bitreservoir */
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
Software License for The Fraunhofer FDK AAC Codec Library for Android
|
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.
|
Forschung e.V. All rights reserved.
|
||||||
|
|
||||||
1. INTRODUCTION
|
1. INTRODUCTION
|
||||||
|
@ -333,6 +333,19 @@ INT FDKaacEnc_GetBitReservoirState(const HANDLE_AAC_ENC hAacEncoder);
|
||||||
INT FDKaacEnc_GetVBRBitrate(AACENC_BITRATE_MODE bitrateMode,
|
INT FDKaacEnc_GetVBRBitrate(AACENC_BITRATE_MODE bitrateMode,
|
||||||
CHANNEL_MODE channelMode);
|
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
|
functionname: FDKaacEnc_AacInitDefaultConfig
|
||||||
|
|
|
@ -1028,6 +1028,13 @@ static AACENC_ERROR FDKaacEnc_AdjustEncSettings(HANDLE_AACENCODER hAacEncoder,
|
||||||
case AACENC_BR_MODE_VBR_3:
|
case AACENC_BR_MODE_VBR_3:
|
||||||
case AACENC_BR_MODE_VBR_4:
|
case AACENC_BR_MODE_VBR_4:
|
||||||
case AACENC_BR_MODE_VBR_5:
|
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 */
|
/* Get bitrate in VBR configuration */
|
||||||
/* In VBR mode; SBR-modul depends on bitrate, core encoder on bitrateMode.
|
/* In VBR mode; SBR-modul depends on bitrate, core encoder on bitrateMode.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
Software License for The Fraunhofer FDK AAC Codec Library for Android
|
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.
|
Forschung e.V. All rights reserved.
|
||||||
|
|
||||||
1. INTRODUCTION
|
1. INTRODUCTION
|
||||||
|
@ -373,13 +373,8 @@ AAC_ENCODER_ERROR FDKaacEnc_QCInit(QC_STATE* hQC, struct QC_INIT* init,
|
||||||
hQC->invQuant = init->invQuant;
|
hQC->invQuant = init->invQuant;
|
||||||
hQC->maxIterations = init->maxIterations;
|
hQC->maxIterations = init->maxIterations;
|
||||||
|
|
||||||
if (isConstantBitrateMode(hQC->bitrateMode)) {
|
/* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir */
|
||||||
/* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir
|
hQC->bitResMode = init->bitResMode;
|
||||||
*/
|
|
||||||
hQC->bitResMode = init->bitResMode;
|
|
||||||
} else {
|
|
||||||
hQC->bitResMode = AACENC_BR_MODE_FULL; /* full bitreservoir */
|
|
||||||
}
|
|
||||||
|
|
||||||
hQC->padding.paddingRest = init->padding.paddingRest;
|
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 avgTotalDynBits = 0; /* maximal allowed dynamic bits for all frames */
|
||||||
INT totalAvailableBits = 0;
|
INT totalAvailableBits = 0;
|
||||||
INT nSubFrames = 1;
|
INT nSubFrames = 1;
|
||||||
|
const INT isCBRAdjustment = (isConstantBitrateMode(hQC->bitrateMode) ||
|
||||||
|
(hQC->bitResMode != AACENC_BR_MODE_FULL))
|
||||||
|
? 1
|
||||||
|
: 0;
|
||||||
|
|
||||||
/*-------------------------------------------- */
|
/*-------------------------------------------- */
|
||||||
/* redistribute total bitreservoir to elements */
|
/* 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) {
|
if (ErrorStatus != AAC_ENC_OK) {
|
||||||
return ErrorStatus;
|
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
|
||||||
/* calc granted dynamic bits for sub frame and
|
distribute it to each element */
|
||||||
distribute it to each element */
|
ErrorStatus = FDKaacEnc_prepareBitDistribution(
|
||||||
ErrorStatus = FDKaacEnc_prepareBitDistribution(
|
hQC, psyOut, qcOut, cm, qcElement,
|
||||||
hQC, psyOut, qcOut, cm, qcElement, avgTotalBits, &totalAvailableBits,
|
(isCBRAdjustment == 0) ? hQC->maxBitsPerFrame : avgTotalBits,
|
||||||
&avgTotalDynBits);
|
&totalAvailableBits, &avgTotalDynBits);
|
||||||
|
|
||||||
if (ErrorStatus != AAC_ENC_OK) {
|
if (ErrorStatus != AAC_ENC_OK) {
|
||||||
return ErrorStatus;
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* for ( all sub frames ) ... */
|
/* for ( all sub frames ) ... */
|
||||||
for (c = 0; c < nSubFrames; c++) {
|
for (c = 0; c < nSubFrames; c++) {
|
||||||
/* for CBR and VBR mode */
|
/* for CBR and VBR mode */
|
||||||
FDKaacEnc_AdjustThresholds(hQC->hAdjThr, qcElement[c], qcOut[c],
|
FDKaacEnc_AdjustThresholds(hQC->hAdjThr, qcElement[c], qcOut[c],
|
||||||
psyOut[c]->psyOutElement,
|
psyOut[c]->psyOutElement, isCBRAdjustment, cm);
|
||||||
isConstantBitrateMode(hQC->bitrateMode), cm);
|
|
||||||
|
|
||||||
} /* -end- sub frame counter */
|
} /* -end- sub frame counter */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue