1
0
mirror of https://github.com/mstorsjo/fdk-aac.git synced 2025-01-31 07:55:22 +01:00

Merge "Fix USAC time domain limiter latency at config change."

This commit is contained in:
TreeHugger Robot 2021-01-15 00:47:10 +00:00 committed by Android (Google) Code Review
commit eb8e26e019
5 changed files with 156 additions and 141 deletions

View File

@ -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))
/* @} */

View File

@ -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)

View File

@ -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);

View File

@ -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 */

View File

@ -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 */