Commit e66ede91f1 for ffmpeg

commit e66ede91f175d6cba3ffff076fa705d9febc8bee
Author: Patrick Domack <patrickdk@patrickdk.com>
Date:   Sun Nov 1 04:56:42 2026 -0500

    avcodec/g723_1dec: saturate the formant postfilter like the reference

    The formant postfilter's ARMA filter has the same problem as the
    synthesis filter, and one more (DS2-Anywhere SPEC.md section 4.8.1,
    step 8). The reference saturates its sum after every product, while
    FFmpeg's iir_filter() macro sums in 64 bits and clips once. The
    reference then keeps the saturated 32-bit sum, adds the tilt term to
    it and rounds. FFmpeg adds the rounding constant before the clip and
    the tilt term after it, so near full scale its output can come out 1
    lower. This has been so since the decoder was added in 2011.

    Replace the macro with a filter that saturates after every product
    and stores the unrounded sum. Round the previous output where the
    filter and the tilt term read it, and round the output only after
    adding the tilt term.

    Over the 371 test streams, the frames that differ from the reference
    with the postfilter on drop from 145 to 1, and the streams that differ
    from 32 to 1. With the postfilter off the formant postfilter does not
    run.

    Frame 42 of saturation.tco: with the postfilter on and every G.723.1
    fix but this one, sample 121 is -14369 where the reference gives
    -14366, and the frame differs by up to 13.

    fate-g723_1-dec-1 to -8 pass unchanged.

    Signed-off-by: Patrick Domack <patrickdk@patrickdk.com>

diff --git a/libavcodec/g723_1dec.c b/libavcodec/g723_1dec.c
index b230b6f1c2..5414bf8712 100644
--- a/libavcodec/g723_1dec.c
+++ b/libavcodec/g723_1dec.c
@@ -583,31 +583,20 @@ static void residual_interp(int16_t *buf, int16_t *out, int lag,
     }
 }

-/**
- * Perform IIR filtering.
- *
- * @param fir_coef FIR coefficients
- * @param iir_coef IIR coefficients
- * @param src      source vector
- * @param dest     destination vector
- * @param width    width of the output, 16 bits(0) / 32 bits(1)
- */
-#define iir_filter(fir_coef, iir_coef, src, dest, width)\
-{\
-    int m, n;\
-    int res_shift = 16 & ~-(width);\
-    int in_shift  = 16 - res_shift;\
-\
-    for (m = 0; m < SUBFRAME_LEN; m++) {\
-        int64_t filter = 0;\
-        for (n = 1; n <= LPC_ORDER; n++) {\
-            filter -= (fir_coef)[n - 1] * (src)[m - n] -\
-                      (iir_coef)[n - 1] * ((dest)[m - n] >> in_shift);\
-        }\
-\
-        (dest)[m] = av_clipl_int32(((src)[m] * 65536) + (filter * 8) +\
-                                   (1 << 15)) >> res_shift;\
-    }\
+static void formant_filter(const int16_t *fir_coef, const int16_t *iir_coef,
+                           const int16_t *src, int *dest)
+{
+    for (int m = 0; m < SUBFRAME_LEN; m++) {
+        int sum = src[m] * (1 << 14);
+
+        for (int n = 1; n <= LPC_ORDER; n++)
+            sum = av_sat_dsub32(sum, fir_coef[n - 1] * src[m - n]);
+        for (int n = 1; n <= LPC_ORDER; n++)
+            sum = av_sat_dadd32(sum, iir_coef[n - 1] *
+                                     (av_sat_add32(dest[m - n], 1 << 15) >> 16));
+
+        dest[m] = av_clipl_int32((int64_t)sum * 4);
+    }
 }

 /**
@@ -677,7 +666,7 @@ static void formant_postfilter(G723_1_ChannelContext *p, int16_t *lpc,
             filter_coef[1][k] = (-lpc[k] * postfilter_tbl[1][k] +
                                  (1 << 14)) >> 15;
         }
-        iir_filter(filter_coef[0], filter_coef[1], buf + i, filter_signal + i, 1);
+        formant_filter(filter_coef[0], filter_coef[1], buf + i, filter_signal + i);
         lpc += LPC_ORDER;
     }

@@ -708,8 +697,10 @@ static void formant_postfilter(G723_1_ChannelContext *p, int16_t *lpc,

         /* Compensation filter */
         for (j = 0; j < SUBFRAME_LEN; j++) {
-            dst[j] = av_sat_dadd32(signal_ptr[j],
-                                   (signal_ptr[j - 1] >> 16) * temp) >> 16;
+            int prev = av_sat_add32(signal_ptr[j - 1], 1 << 15) >> 16;
+
+            dst[j] = av_sat_add32(av_sat_dadd32(signal_ptr[j], prev * temp),
+                                  1 << 15) >> 16;
         }

         /* Compute normalized signal energy */