Commit 73d3b57be5 for ffmpeg

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

    avcodec/g723_1dec: follow Annex A when the first SID frame is lost

    An untransmitted frame right after an active frame means the SID frame
    that should have started the silence was lost. G.723.1 Annex A then
    rebuilds the comfort noise level from the energy of the last good
    active frame. FFmpeg's decoder has handled this case differently from
    the ITU reference decoder since comfort noise was added in 04fc5c6bde
    (2012), and n9.0.2 and master 81cf906e75 still do.

    estimate_sid_gain() quantizes that energy to a 6-bit SID gain index.
    It departs from the reference in three places:

    - It multiplies by 273 and shifts by 16. The reference uses mul32x16
      with 273, a shift by 15, so FFmpeg compares half the energy with the
      segment bounds.
    - In segments 0 and 1 it steps by 1 and 2 instead of 2 and 4, and its
      index comes out 16 too low.
    - Its final rounding compares the wrong distances, so it always rounds
      up when the energy lies above the candidate.

    The caller then stores the index as the gain. The reference decodes
    it, as the SID frame path already does with sid_gain_to_lsp_index().
    The reference also takes the comfort noise LSPs from the last good
    active frame. FFmpeg keeps sid_lsp from the last SID frame, or the
    initial DC vector when there was none.

    Quantize with MULL2(), which gives the reference's mul32x16 result
    here because nothing in this calculation saturates. Step through the
    three segments by 2, 4 and 8 with their index offsets 0, 16 and 32,
    round to the nearer index and decode it. Copy prev_lsp into sid_lsp at
    the end of every good active frame.

    The reference used here is the G.723.1 decoder of DS2-Anywhere,
    vendor/dss-codec/src/codec/g723_1.rs in
    https://github.com/Guillain-RDCDE/DS2-Anywhere. It matches the ITU
    reference decoder on the 11 ITU test vectors and on 17 more cases
    decoded with the ITU reference. One of those, a stream of random bits,
    has 283 first-SID-lost frames. Sections 4.4.4, 4.10.2, 4.10.4 and
    4.10.5 of its docs/g723-1/SPEC.md describe each step.

    Its g723-mix.g723pk fixture holds 900 packets of every frame type.
    Before this change, 520 of its frames differed from the reference with
    the postfilter on and 529 with it off. Now none do. Over 35 random
    streams of 3000 frames each, the frames that differ drop from 100308
    to 10169 with the postfilter on and from 99885 to 9656 with it off.
    The following commits fix the rest.

    Frame 16 of cng-erasures.tco, a stream that a later commit adds to FATE,
    is an untransmitted frame after a 6.3 kbit/s frame. With the postfilter
    on and every G.723.1 fix but this one, its first sample is -3881 where
    the reference gives -3458, the frame differs by up to 7448, and 79 of
    the 97 frames differ.

    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 8406655e44..2b433e4552 100644
--- a/libavcodec/g723_1dec.c
+++ b/libavcodec/g723_1dec.c
@@ -761,7 +761,7 @@ static int estimate_sid_gain(G723_1_ChannelContext *p)
         t = (p->sid_gain < 0) ? -1 : 0;
     }else
         t = p->sid_gain >> -shift;
-    x = av_clipl_int32(t * (int64_t)cng_filt[0] >> 16);
+    x = MULL2(t, cng_filt[0]);

     if (x >= cng_bseg[2])
         return 0x3F;
@@ -773,14 +773,14 @@ static int estimate_sid_gain(G723_1_ChannelContext *p)
         shift = 3;
         seg   = (x >= cng_bseg[0]);
     }
-    seg2 = FFMIN(seg, 3);
+    seg2 = FFMIN(seg + 1, 3);

     val     = 1 << shift;
     val_add = val >> 1;
     for (i = 0; i < shift; i++) {
         t = seg * 32 + (val << seg2);
         t *= t;
-        if (x >= t)
+        if (x >= 2 * t)
             val += val_add;
         else
             val -= val_add;
@@ -788,18 +788,18 @@ static int estimate_sid_gain(G723_1_ChannelContext *p)
     }

     t = seg * 32 + (val << seg2);
-    y = t * t - x;
+    y = 2 * t * t - x;
     if (y <= 0) {
         t = seg * 32 + (val + 1 << seg2);
-        t = t * t - x;
+        t = x - 2 * t * t;
         val = (seg2 - 1) * 16 + val;
-        if (t >= y)
+        if (y <= t)
             val++;
     } else {
         t = seg * 32 + (val - 1 << seg2);
-        t = t * t - x;
+        t = x - 2 * t * t;
         val = (seg2 - 1) * 16 + val;
-        if (t >= y)
+        if (y >= t)
             val--;
     }

@@ -1037,6 +1037,7 @@ static int g723_1_decode_frame(AVCodecContext *avctx, AVFrame *frame,
                 /* Save the excitation for the next frame */
                 memcpy(p->prev_excitation, p->excitation + FRAME_LEN,
                        PITCH_MAX * sizeof(*p->excitation));
+                memcpy(p->sid_lsp, p->prev_lsp, LPC_ORDER * sizeof(*p->sid_lsp));
             } else {
                 p->interp_gain = (p->interp_gain * 3 + 2) >> 2;
                 if (p->erased_frames == 3) {
@@ -1065,7 +1066,7 @@ static int g723_1_decode_frame(AVCodecContext *avctx, AVFrame *frame,
                 p->sid_gain = sid_gain_to_lsp_index(p->subframe[0].amp_index);
                 ff_g723_1_inverse_quant(p->sid_lsp, p->prev_lsp, p->lsp_index, 0);
             } else if (p->past_frame_type == ACTIVE_FRAME) {
-                p->sid_gain = estimate_sid_gain(p);
+                p->sid_gain = sid_gain_to_lsp_index(estimate_sid_gain(p));
             }

             if (p->past_frame_type == ACTIVE_FRAME)