Commit cdd9cc0c53 for ffmpeg
commit cdd9cc0c530529149a6aa86e5b13536745cd21d3
Author: Patrick Domack <patrickdk@patrickdk.com>
Date: Sun Nov 1 04:56:39 2026 -0500
avcodec/g723_1dec: zero the synthesis input on the third lost frame
On the third lost active frame in a row the ITU reference sets the
excitation to zero, so the synthesis filter only rings out its memory
(DS2-Anywhere SPEC.md section 4.9). FFmpeg clears frame->data[0]
instead. That is the output buffer, which the postfilter or the
scaling for the unfiltered output overwrites later anyway. The
synthesis filter reads p->audio, which still holds the previous frame.
The memset also writes FRAME_LEN + LPC_ORDER samples into a plane of
FRAME_LEN. That stays in bounds only because the default allocator
pads each plane, and a get_buffer2() callback that allocates exactly
nb_samples gets 20 bytes written past its plane. It only clears
channel 0 too.
FFmpeg's first version of the decoder cleared the buffer it
synthesized from. 70bcdfb39f (2012), which took Libav's version of
this code, moved the memset to the output frame.
Clear p->audio + LPC_ORDER, the synthesis input, instead.
Over the 35 random streams, the frames that differ from the reference
drop from 471 to 378 with the postfilter on and from 214 to 190 with
it off. The streams that differ drop from 14 to 7.
Frame 71 of cng-erasures.tco, a stream that a later commit adds to FATE,
is the third lost active frame in a row. With the postfilter on and
every G.723.1 fix but this one, its first sample is -1812 where the
reference gives -447, and the frame differs by up to 4436.
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 eaf31939ea..ad335dc8db 100644
--- a/libavcodec/g723_1dec.c
+++ b/libavcodec/g723_1dec.c
@@ -1046,8 +1046,8 @@ static int g723_1_decode_frame(AVCodecContext *avctx, AVFrame *frame,
(FRAME_LEN + PITCH_MAX) * sizeof(*p->excitation));
memset(p->prev_excitation, 0,
PITCH_MAX * sizeof(*p->excitation));
- memset(frame->data[0], 0,
- (FRAME_LEN + LPC_ORDER) * sizeof(int16_t));
+ memset(p->audio + LPC_ORDER, 0,
+ FRAME_LEN * sizeof(*p->audio));
} else {
int16_t *buf = p->audio + LPC_ORDER;