Commit 6a99de49ec for ffmpeg

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

    avcodec/g723_1dec: clear excitation history after unvoiced concealment

    When an active frame is lost and the last good frame was unvoiced, the
    decoder fills the frame with scaled noise. The ITU reference then
    clears its whole excitation buffer, so the next frame's adaptive
    codebook starts from silence (DS2-Anywhere SPEC.md section 4.9).

    residual_interp() still clears p->excitation, but since 4b728b4712
    (2012) the caller copies prev_excitation from the output buffer, which
    holds the noise. Before that commit it copied from p->excitation. So
    every later frame that reads the adaptive codebook, active or comfort
    noise, starts from that noise.

    Clear prev_excitation after unvoiced concealment, and keep the copy
    for voiced concealment.

    Over the 35 random streams, the frames that differ from the reference
    drop from 10169 to 471 with the postfilter on and from 9656 to 214
    with it off. The streams that differ drop from 35 to 14.

    Frame 55 of cng-erasures.tco, a stream that a later commit adds to FATE,
    is a SID frame after a lost 5.3 kbit/s frame that was concealed as
    unvoiced. With the postfilter on and every G.723.1 fix but this one, its
    second sample is 8 where the reference gives 20, the frame differs by up
    to 345, and 16 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 2b433e4552..eaf31939ea 100644
--- a/libavcodec/g723_1dec.c
+++ b/libavcodec/g723_1dec.c
@@ -1056,8 +1056,12 @@ static int g723_1_decode_frame(AVCodecContext *avctx, AVFrame *frame,
                                     p->interp_gain, &p->random_seed);

                     /* Save the excitation for the next frame */
-                    memcpy(p->prev_excitation, buf + (FRAME_LEN - PITCH_MAX),
-                           PITCH_MAX * sizeof(*p->excitation));
+                    if (p->interp_index)
+                        memcpy(p->prev_excitation, buf + (FRAME_LEN - PITCH_MAX),
+                               PITCH_MAX * sizeof(*p->excitation));
+                    else
+                        memset(p->prev_excitation, 0,
+                               PITCH_MAX * sizeof(*p->excitation));
                 }
             }
             p->cng_random_seed = CNG_RANDOM_SEED;