PR #25209 opened by Peter Krefting (nafmo) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25209 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25209.patch
We are decoding several HE-AAC audio streams in parallel, and calling avcodec_flush_buffers() between each call. We are seeing that the full state is not reset between calls, similar to what we previously experienced with the [E-AC3 decoder](https://trac.ffmpeg.org/ticket/10732) (fixed in 045a8b15b19ec7f872fb01cfb986faeaa26cb8bb). The problem occurs in the SBR handling for HE-AAC. After throwing the problem on opencode.ai and the free OpenCode Zen Big Pickle model, it came up with the attached patch, which does fix the issue on our side. The LLM output referenced [this message](https://ffmpeg.org/pipermail/ffmpeg-devel/2020-January/255176.html) as information about why the SBR data had not been flushed, so it deserves credit. Originally filed as a bug report as https://code.ffmpeg.org/FFmpeg/FFmpeg/issues/25066 >From 8a56c1b58525909fb8f61aa3ee78f3cc64391545 Mon Sep 17 00:00:00 2001 From: Peter Krefting <[email protected]> Date: Mon, 19 Oct 2026 09:07:17 +0100 Subject: [PATCH] avcodec/aac: Reset SBR context (HE-AAC) when flushing AAC decoder When calling avcodec_flush_buffers() on the AAC decoder, decoding an HE-AAC stream, the SBR state would not be cleared properly. See: https://ffmpeg.org/pipermail/ffmpeg-devel/2020-January/255176.html Assisted-by: OpenZen Big Pickle --- libavcodec/aac/aacdec.c | 1 + libavcodec/aac/aacdec.h | 1 + libavcodec/aac/aacdec_proc_template.c | 1 + libavcodec/aacsbr.h | 5 ++++ libavcodec/aacsbr_template.c | 35 +++++++++++++++++++++++++++ 5 files changed, 43 insertions(+) diff --git a/libavcodec/aac/aacdec.c b/libavcodec/aac/aacdec.c index 66ab648016..5bdabe388c 100644 --- a/libavcodec/aac/aacdec.c +++ b/libavcodec/aac/aacdec.c @@ -564,6 +564,7 @@ static av_cold void flush(AVCodecContext *avctx) for (j = 0; j <= 1; j++) { memset(che->ch[j].saved, 0, sizeof(che->ch[j].saved)); } + ac->proc.sbr_ctx_reset(ac, che); } } } diff --git a/libavcodec/aac/aacdec.h b/libavcodec/aac/aacdec.h index 18412fb97a..1fb89ace61 100644 --- a/libavcodec/aac/aacdec.h +++ b/libavcodec/aac/aacdec.h @@ -458,6 +458,7 @@ typedef struct AACDecProc { void (*sbr_apply)(AACDecContext *ac, ChannelElement *che, int id_aac, int fl960, void /* INTFLOAT */ *L, void /* INTFLOAT */ *R); void (*sbr_ctx_close)(ChannelElement *che); + void (*sbr_ctx_reset)(AACDecContext *ac, ChannelElement *che); } AACDecProc; /** diff --git a/libavcodec/aac/aacdec_proc_template.c b/libavcodec/aac/aacdec_proc_template.c index 327f3117b5..b56302a93f 100644 --- a/libavcodec/aac/aacdec_proc_template.c +++ b/libavcodec/aac/aacdec_proc_template.c @@ -444,5 +444,6 @@ static av_cold void AAC_RENAME(aac_proc_init)(AACDecProc *aac_proc) SET(sbr_decode_extension); SET(sbr_apply); SET(sbr_ctx_close); + SET(sbr_ctx_reset); #undef SET } diff --git a/libavcodec/aacsbr.h b/libavcodec/aacsbr.h index afc8ad188a..c330a13183 100644 --- a/libavcodec/aacsbr.h +++ b/libavcodec/aacsbr.h @@ -82,6 +82,11 @@ int ff_aac_sbr_ctx_alloc_init_fixed(AACDecContext *ac, ChannelElement **che, int void ff_aac_sbr_ctx_close(ChannelElement *che); void ff_aac_sbr_ctx_close_fixed(ChannelElement *che); +/** Reset the SBR context contained in a ChannelElement, discarding all + * inter-frame state while keeping the allocated transform contexts. */ +void ff_aac_sbr_ctx_reset(AACDecContext *ac, ChannelElement *che); +void ff_aac_sbr_ctx_reset_fixed(AACDecContext *ac, ChannelElement *che); + /** Decode one SBR element. */ int ff_aac_sbr_decode_extension(AACDecContext *ac, ChannelElement *che, GetBitContext *gb, int crc, int cnt, int id_aac, diff --git a/libavcodec/aacsbr_template.c b/libavcodec/aacsbr_template.c index cc22b64416..ed07ea6108 100644 --- a/libavcodec/aacsbr_template.c +++ b/libavcodec/aacsbr_template.c @@ -123,6 +123,41 @@ av_cold void AAC_RENAME(ff_aac_sbr_ctx_close)(ChannelElement *che) av_tx_uninit(&sbr->mdct_ana); } +av_cold void AAC_RENAME(ff_aac_sbr_ctx_reset)(AACDecContext *ac, ChannelElement *che) +{ + SpectralBandReplication *sbr = get_sbr(che); + + /* Keep the members set up by ff_aac_sbr_ctx_alloc_init() that must survive + * a reset (the allocated transform contexts and the function pointer + * tables); everything else is inter-frame state that has to be discarded. */ + AVTXContext *mdct = sbr->mdct; + av_tx_fn mdct_fn = sbr->mdct_fn; + AVTXContext *mdct_ana = sbr->mdct_ana; + av_tx_fn mdct_ana_fn = sbr->mdct_ana_fn; + SBRDSPContext dsp; + AACSBRContext c; + int id_aac = sbr->id_aac; + + memcpy(&dsp, &sbr->dsp, sizeof(dsp)); + memcpy(&c, &sbr->c, sizeof(c)); + + memset(sbr, 0, sizeof(*sbr)); + + sbr->mdct = mdct; + sbr->mdct_fn = mdct_fn; + sbr->mdct_ana = mdct_ana; + sbr->mdct_ana_fn = mdct_ana_fn; + sbr->dsp = dsp; + sbr->c = c; + + sbr->id_aac = id_aac; + sbr->kx[0] = sbr->kx[1]; + sbr_turnoff(sbr); + sbr->data[0].synthesis_filterbank_samples_offset = SBR_SYNTHESIS_BUF_SIZE - (1280 - 128); + sbr->data[1].synthesis_filterbank_samples_offset = SBR_SYNTHESIS_BUF_SIZE - (1280 - 128); + AAC_RENAME(ff_ps_ctx_init)(&sbr->ps); +} + static int qsort_comparison_function_int16(const void *a, const void *b) { return *(const int16_t *)a - *(const int16_t *)b; -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
