Commit fb9015d55c for ffmpeg
commit fb9015d55c8c3433fd440d2d573703e90249abbe
Author: Jun Zhao <barryjzhao@tencent.com>
Date: Sun Oct 25 08:27:39 2026 +0800
avcodec/ac3dec: preserve AVOptions across flush
ac3_decode_flush() clears every field from frame_type to the end of
AC3DecodeContext with a single memset. Several fields backing AVOptions
(drc_scale, heavy_compression, target_level and
consistent_noise_generation, plus the exported downmix fields) were
located in that range, so avcodec_flush_buffers() silently zeroed them.
For drc_scale that does not even restore the default of 1.0,
effectively disabling dynamic range compression after any flush, e.g.
on seek.
Move all AVOption fields above the start of the flushable fields, next
to downmix_layout which was already kept there, so that flush only
resets actual decoding state. The exported downmix fields are written
from the frame header for every frame, so preserving them across flush
does not change decoding.
Fixes: https://code.ffmpeg.org/FFmpeg/FFmpeg/issues/25430
Signed-off-by: Jun Zhao <barryjzhao@tencent.com>
diff --git a/libavcodec/ac3dec.h b/libavcodec/ac3dec.h
index 25ce1b1c90..3c98393c6c 100644
--- a/libavcodec/ac3dec.h
+++ b/libavcodec/ac3dec.h
@@ -93,8 +93,26 @@ typedef struct AC3DecodeContext {
AVChannelLayout downmix_layout;
SHORTFLOAT *downmix_coeffs[2]; ///< stereo downmix coefficients
+///@name AVOptions
+/// Fields backing AVOptions. They hold user configuration (or, for the
+/// exported downmix fields, values derived from the last decoded frame) and
+/// must survive avcodec_flush_buffers(), so they must stay above the start
+/// of the flushable fields below.
+///@{
+ int preferred_stereo_downmix;
+ float ltrt_center_mix_level;
+ float ltrt_surround_mix_level;
+ float loro_center_mix_level;
+ float loro_surround_mix_level;
+ int target_level; ///< target level in dBFS
+ INTFLOAT drc_scale; ///< percentage of dynamic range compression to be applied
+ int heavy_compression; ///< apply heavy compression
+ int consistent_noise_generation; ///< seed noise generation with AC-3 frame on decode
+///@}
+
// Start of flushable fields.
-// frame_type must be the flushable field, or the offset changed in ac3_decode_flush().
+// frame_type must be the first flushable field, or the offset changed in
+// ac3_decode_flush(). No AVOption field may be placed at or below this line.
///@name Bit stream information
///@{
@@ -127,12 +145,6 @@ typedef struct AC3DecodeContext {
int dolby_headphone_mode; ///< dolby headphone mode (dheadphonmod)
///@}
- int preferred_stereo_downmix;
- float ltrt_center_mix_level;
- float ltrt_surround_mix_level;
- float loro_center_mix_level;
- float loro_surround_mix_level;
- int target_level; ///< target level in dBFS
float level_gain[2];
///@name Frame syntax parameters
@@ -194,8 +206,6 @@ typedef struct AC3DecodeContext {
///@name Dynamic range
INTFLOAT dynamic_range[2]; ///< dynamic range
- INTFLOAT drc_scale; ///< percentage of dynamic range compression to be applied
- int heavy_compression; ///< apply heavy compression
INTFLOAT heavy_dynamic_range[2]; ///< heavy dynamic range compression
///@}
@@ -204,10 +214,6 @@ typedef struct AC3DecodeContext {
int end_freq[AC3_MAX_CHANNELS]; ///< end frequency bin (endmant)
///@}
-///@name Consistent noise generation
- int consistent_noise_generation; ///< seed noise generation with AC-3 frame on decode
-///@}
-
///@name Rematrixing
int num_rematrixing_bands; ///< number of rematrixing bands (nrematbnd)
int rematrixing_flags[4]; ///< rematrixing flags (rematflg)