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)