Commit 6681908349 for ffmpeg
commit 66819083494e2dbe84d413dc7c5bc252768ba0b0
Author: Patrick Domack <patrickdk@patrickdk.com>
Date: Sun Nov 1 04:56:40 2026 -0500
avcodec/g723_1: saturate the negated LPC coefficients like the reference
The ITU reference computes each LPC coefficient as neg16(round16(x)),
and neg16(-32768) saturates to 32767 (DS2-Anywhere SPEC.md section
4.3.2, step 4). FFmpeg stores the coefficients negated, as round16(x),
and its synthesis filter subtracts them. When round16(x) is -32768,
FFmpeg's filter uses +32768 where the reference uses 32767. This has
been so since the decoder was added in 2011.
Clamp the stored value at -INT16_MAX. The encoder shares this code
through ff_g723_1_lsp_interpolate(), and fate-acodec-g723_1 passes
unchanged.
The cosine step at the top of lsp2lpc() negates too. It could only
give -32768 for an LSP of 32736 or more. The largest LSP in any of the
test streams is 31159, at frame 690 of g723-mix.g723pk.
Over the 35 random streams, the last 5 frames that differed from the
reference now match, with the postfilter on and with it off. These
streams draw their gains at random and never get loud enough to
saturate the synthesis filter or the formant postfilter. The next
three commits handle that.
Frame 91 of cng-erasures.tco is a 6.3 kbit/s frame after an
untransmitted frame. Its last subframe saturates coefficient 4. With
the postfilter on and every G.723.1 fix but this one, the frame parts
from the reference at sample 193 by up to 46, and 4 frames differ.
cng-erasures.tco holds 97 frames in 1377 bytes: 35 at 6.3 kbit/s, 22
at 5.3 kbit/s, 19 SID frames and 21 untransmitted ones. 9 active
frames fail the validity checks. 7 of them follow an active frame and
are concealed, and the other 2 count as untransmitted. 14
untransmitted frames follow an active frame, so their SID frame was
lost. The stream starts with a SID frame, loses three active frames in
a row at frames 69 to 71, and saturates an LPC coefficient at frame
91. Before the G.723.1 fixes, all 97 frames differ from the reference.
fate-g723_1-dec-9 decodes cng-erasures.tco with the postfilter on, and
fate-g723_1-dec-10 with it off. Their refs match the DS2-Anywhere
G.723.1 decoder frame for frame. Both tests fail with this fix or any
of the four G.723.1 fixes before it left out. fate-g723_1-dec-1 to -8
pass unchanged.
Upload the sample to fate-suite as g723_1/cng-erasures.tco.
Signed-off-by: Patrick Domack <patrickdk@patrickdk.com>
diff --git a/libavcodec/g723_1.c b/libavcodec/g723_1.c
index d19d09dd89..1bd8f99770 100644
--- a/libavcodec/g723_1.c
+++ b/libavcodec/g723_1.c
@@ -1243,9 +1243,11 @@ static void lsp2lpc(int16_t *lpc)
int64_t ff1 = f1[i + 1] + f1[i];
int64_t ff2 = f2[i + 1] - f2[i];
- lpc[i] = av_clipl_int32(((ff1 + ff2) * 8) + (1 << 15)) >> 16;
- lpc[LPC_ORDER - i - 1] = av_clipl_int32(((ff1 - ff2) * 8) +
- (1 << 15)) >> 16;
+ lpc[i] = FFMAX(av_clipl_int32(((ff1 + ff2) * 8) + (1 << 15)) >> 16,
+ -INT16_MAX);
+ lpc[LPC_ORDER - i - 1] = FFMAX(av_clipl_int32(((ff1 - ff2) * 8) +
+ (1 << 15)) >> 16,
+ -INT16_MAX);
}
}
diff --git a/tests/fate/voice.mak b/tests/fate/voice.mak
index 5acd56d178..d5c09c2daf 100644
--- a/tests/fate/voice.mak
+++ b/tests/fate/voice.mak
@@ -47,6 +47,12 @@ fate-g723_1-dec-7: CMD = framecrc -postfilter 1 -i $(TARGET_SAMPLES)/g723_1/dtx6
FATE_G723_1 += fate-g723_1-dec-8
fate-g723_1-dec-8: CMD = framecrc -postfilter 1 -i $(TARGET_SAMPLES)/g723_1/dtx63e.tco -af aresample
+FATE_G723_1 += fate-g723_1-dec-9
+fate-g723_1-dec-9: CMD = framecrc -postfilter 1 -i $(TARGET_SAMPLES)/g723_1/cng-erasures.tco -af aresample
+
+FATE_G723_1 += fate-g723_1-dec-10
+fate-g723_1-dec-10: CMD = framecrc -postfilter 0 -i $(TARGET_SAMPLES)/g723_1/cng-erasures.tco -af aresample
+
FATE_G723_1 += fate-g723_1-dec-13
fate-g723_1-dec-13: CMD = framecrc -postfilter 1 -i $(TARGET_SAMPLES)/g723_1/lost-start.tco -af aresample
diff --git a/tests/ref/fate/g723_1-dec-10 b/tests/ref/fate/g723_1-dec-10
new file mode 100644
index 0000000000..6379f07528
--- /dev/null
+++ b/tests/ref/fate/g723_1-dec-10
@@ -0,0 +1,102 @@
+#tb 0: 1/8000
+#media_type 0: audio
+#codec_id 0: pcm_s16le
+#sample_rate 0: 8000
+#channel_layout_name 0: mono
+0, 0, 0, 240, 480, 0x87aeebcc
+0, 240, 240, 240, 480, 0xbffe0499
+0, 480, 480, 240, 480, 0xe835ed9f
+0, 720, 720, 240, 480, 0x7265eb0a
+0, 960, 960, 240, 480, 0x651ce43c
+0, 1200, 1200, 240, 480, 0x1f0ae5f9
+0, 1440, 1440, 240, 480, 0x661cf0d2
+0, 1680, 1680, 240, 480, 0xfbddda7c
+0, 1920, 1920, 240, 480, 0xf852034c
+0, 2160, 2160, 240, 480, 0xa2beed3a
+0, 2400, 2400, 240, 480, 0x1d86e61a
+0, 2640, 2640, 240, 480, 0xf1a4eedd
+0, 2880, 2880, 240, 480, 0xaa8ff792
+0, 3120, 3120, 240, 480, 0xcad5f1e9
+0, 3360, 3360, 240, 480, 0xb868ee27
+0, 3600, 3600, 240, 480, 0x85f3f875
+0, 3840, 3840, 240, 480, 0x379ce9ab
+0, 4080, 4080, 240, 480, 0xea74f333
+0, 4320, 4320, 240, 480, 0xb0eceead
+0, 4560, 4560, 240, 480, 0x52c8d2fe
+0, 4800, 4800, 240, 480, 0x85a3c73e
+0, 5040, 5040, 240, 480, 0x9b96e38d
+0, 5280, 5280, 240, 480, 0x0856f042
+0, 5520, 5520, 240, 480, 0x5a02e9c7
+0, 5760, 5760, 240, 480, 0x9d10ea4c
+0, 6000, 6000, 240, 480, 0x3bcae0cb
+0, 6240, 6240, 240, 480, 0xef47e838
+0, 6480, 6480, 240, 480, 0x293cecb0
+0, 6720, 6720, 240, 480, 0x6409f2fb
+0, 6960, 6960, 240, 480, 0x9b83f342
+0, 7200, 7200, 240, 480, 0xa29ef241
+0, 7440, 7440, 240, 480, 0xdeaff0a8
+0, 7680, 7680, 240, 480, 0x5481ee53
+0, 7920, 7920, 240, 480, 0xf323eb4c
+0, 8160, 8160, 240, 480, 0x8613e597
+0, 8400, 8400, 240, 480, 0x1f8ce94b
+0, 8640, 8640, 240, 480, 0x29fddd40
+0, 8880, 8880, 240, 480, 0xeebde954
+0, 9120, 9120, 240, 480, 0xdd1de35c
+0, 9360, 9360, 240, 480, 0x1e78d8e4
+0, 9600, 9600, 240, 480, 0x7e76ee55
+0, 9840, 9840, 240, 480, 0x3d18de27
+0, 10080, 10080, 240, 480, 0x9364ca4e
+0, 10320, 10320, 240, 480, 0xcc9af167
+0, 10560, 10560, 240, 480, 0x65cfff58
+0, 10800, 10800, 240, 480, 0x051bee3a
+0, 11040, 11040, 240, 480, 0x218bdf5c
+0, 11280, 11280, 240, 480, 0x824befad
+0, 11520, 11520, 240, 480, 0x7edaf36e
+0, 11760, 11760, 240, 480, 0xa2ffe096
+0, 12000, 12000, 240, 480, 0xa0a4e1c1
+0, 12240, 12240, 240, 480, 0x391ef22f
+0, 12480, 12480, 240, 480, 0xeab5f8a2
+0, 12720, 12720, 240, 480, 0x5654378c
+0, 12960, 12960, 240, 480, 0xbd1be151
+0, 13200, 13200, 240, 480, 0xf34ddabd
+0, 13440, 13440, 240, 480, 0x8c8fee74
+0, 13680, 13680, 240, 480, 0xedca1919
+0, 13920, 13920, 240, 480, 0x86df3022
+0, 14160, 14160, 240, 480, 0xdadc0390
+0, 14400, 14400, 240, 480, 0x185df533
+0, 14640, 14640, 240, 480, 0xa92bf03d
+0, 14880, 14880, 240, 480, 0x5301f6a0
+0, 15120, 15120, 240, 480, 0x635df4d6
+0, 15360, 15360, 240, 480, 0xbc6ff11e
+0, 15600, 15600, 240, 480, 0xb4aef63a
+0, 15840, 15840, 240, 480, 0xbfdcf57e
+0, 16080, 16080, 240, 480, 0x2e0cdf25
+0, 16320, 16320, 240, 480, 0xf7f9ee90
+0, 16560, 16560, 240, 480, 0x62c6ee26
+0, 16800, 16800, 240, 480, 0x355ef5b5
+0, 17040, 17040, 240, 480, 0x9853367a
+0, 17280, 17280, 240, 480, 0xab5bd578
+0, 17520, 17520, 240, 480, 0xcd15f21b
+0, 17760, 17760, 240, 480, 0x7bf3ee2b
+0, 18000, 18000, 240, 480, 0x5ec2f0e3
+0, 18240, 18240, 240, 480, 0xfe0ff109
+0, 18480, 18480, 240, 480, 0xc701d5c4
+0, 18720, 18720, 240, 480, 0xbb3df7de
+0, 18960, 18960, 240, 480, 0x9715f71f
+0, 19200, 19200, 240, 480, 0x5bfef181
+0, 19440, 19440, 240, 480, 0xa3813b28
+0, 19680, 19680, 240, 480, 0x6b3745bc
+0, 19920, 19920, 240, 480, 0x8b44e88c
+0, 20160, 20160, 240, 480, 0xab94f540
+0, 20400, 20400, 240, 480, 0x773e0057
+0, 20640, 20640, 240, 480, 0x99b3f729
+0, 20880, 20880, 240, 480, 0x8fea1bb0
+0, 21120, 21120, 240, 480, 0x9d30f101
+0, 21360, 21360, 240, 480, 0x18e1fd48
+0, 21600, 21600, 240, 480, 0x46ecf14b
+0, 21840, 21840, 240, 480, 0xecd4f472
+0, 22080, 22080, 240, 480, 0x75bee0cc
+0, 22320, 22320, 240, 480, 0x99c5f819
+0, 22560, 22560, 240, 480, 0x929aec97
+0, 22800, 22800, 240, 480, 0x438be410
+0, 23040, 23040, 240, 480, 0x46e0ea5d
diff --git a/tests/ref/fate/g723_1-dec-9 b/tests/ref/fate/g723_1-dec-9
new file mode 100644
index 0000000000..5fd55ca8f8
--- /dev/null
+++ b/tests/ref/fate/g723_1-dec-9
@@ -0,0 +1,102 @@
+#tb 0: 1/8000
+#media_type 0: audio
+#codec_id 0: pcm_s16le
+#sample_rate 0: 8000
+#channel_layout_name 0: mono
+0, 0, 0, 240, 480, 0x9960eb28
+0, 240, 240, 240, 480, 0x829b03b8
+0, 480, 480, 240, 480, 0x2ebce6c8
+0, 720, 720, 240, 480, 0xec07f417
+0, 960, 960, 240, 480, 0xebdddefa
+0, 1200, 1200, 240, 480, 0xa6d6ed37
+0, 1440, 1440, 240, 480, 0x18e0e491
+0, 1680, 1680, 240, 480, 0x91b2e0ed
+0, 1920, 1920, 240, 480, 0x5af805dc
+0, 2160, 2160, 240, 480, 0x821aefb4
+0, 2400, 2400, 240, 480, 0x646be254
+0, 2640, 2640, 240, 480, 0xec8ff4d3
+0, 2880, 2880, 240, 480, 0x1e75f923
+0, 3120, 3120, 240, 480, 0x3f58eb3d
+0, 3360, 3360, 240, 480, 0xa87af21b
+0, 3600, 3600, 240, 480, 0x3ee1ea42
+0, 3840, 3840, 240, 480, 0x6122ed84
+0, 4080, 4080, 240, 480, 0xda0aef9c
+0, 4320, 4320, 240, 480, 0x9c7ff1c6
+0, 4560, 4560, 240, 480, 0x3dcfdcae
+0, 4800, 4800, 240, 480, 0x54a7d65a
+0, 5040, 5040, 240, 480, 0xf6b8e44c
+0, 5280, 5280, 240, 480, 0x5b7cf4ad
+0, 5520, 5520, 240, 480, 0x6642e64e
+0, 5760, 5760, 240, 480, 0x473ee490
+0, 6000, 6000, 240, 480, 0xe867f091
+0, 6240, 6240, 240, 480, 0xd7dbea63
+0, 6480, 6480, 240, 480, 0x6792f0b1
+0, 6720, 6720, 240, 480, 0xb67aef82
+0, 6960, 6960, 240, 480, 0x3688fb2a
+0, 7200, 7200, 240, 480, 0x5c12e8be
+0, 7440, 7440, 240, 480, 0xe293ed4c
+0, 7680, 7680, 240, 480, 0x5108f3b7
+0, 7920, 7920, 240, 480, 0x469bd9fd
+0, 8160, 8160, 240, 480, 0xbc60e7f1
+0, 8400, 8400, 240, 480, 0x0b9de2cc
+0, 8640, 8640, 240, 480, 0xb073ec19
+0, 8880, 8880, 240, 480, 0x33f3ee20
+0, 9120, 9120, 240, 480, 0x1546e0a4
+0, 9360, 9360, 240, 480, 0xa7bdebc6
+0, 9600, 9600, 240, 480, 0xf096f4c4
+0, 9840, 9840, 240, 480, 0xf55de7b7
+0, 10080, 10080, 240, 480, 0x510bd374
+0, 10320, 10320, 240, 480, 0x159ee967
+0, 10560, 10560, 240, 480, 0x661b040d
+0, 10800, 10800, 240, 480, 0x523fe64c
+0, 11040, 11040, 240, 480, 0x10b5e79e
+0, 11280, 11280, 240, 480, 0x982eed92
+0, 11520, 11520, 240, 480, 0x5d52ef3f
+0, 11760, 11760, 240, 480, 0xe398d7a7
+0, 12000, 12000, 240, 480, 0xe759e4fc
+0, 12240, 12240, 240, 480, 0xa4a3f5b1
+0, 12480, 12480, 240, 480, 0x8702f703
+0, 12720, 12720, 240, 480, 0x991731f2
+0, 12960, 12960, 240, 480, 0x47e3e201
+0, 13200, 13200, 240, 480, 0x6dc3db07
+0, 13440, 13440, 240, 480, 0x86f6ef1c
+0, 13680, 13680, 240, 480, 0x869814c0
+0, 13920, 13920, 240, 480, 0x893721b5
+0, 14160, 14160, 240, 480, 0xa9b7039c
+0, 14400, 14400, 240, 480, 0x1b27f7c5
+0, 14640, 14640, 240, 480, 0x4f8deff4
+0, 14880, 14880, 240, 480, 0xced6f164
+0, 15120, 15120, 240, 480, 0x571af02e
+0, 15360, 15360, 240, 480, 0x7d93eebb
+0, 15600, 15600, 240, 480, 0x4659f6ac
+0, 15840, 15840, 240, 480, 0x51fbeaa6
+0, 16080, 16080, 240, 480, 0xd2a8e0f7
+0, 16320, 16320, 240, 480, 0xcfbae2e3
+0, 16560, 16560, 240, 480, 0xf908e9e0
+0, 16800, 16800, 240, 480, 0x06f2ed1b
+0, 17040, 17040, 240, 480, 0x402534b0
+0, 17280, 17280, 240, 480, 0x86c9d532
+0, 17520, 17520, 240, 480, 0xab65f21f
+0, 17760, 17760, 240, 480, 0xb543f0f5
+0, 18000, 18000, 240, 480, 0x4e44efbc
+0, 18240, 18240, 240, 480, 0xfe7aea43
+0, 18480, 18480, 240, 480, 0x675cdc8b
+0, 18720, 18720, 240, 480, 0x2536f58a
+0, 18960, 18960, 240, 480, 0x1064f6c6
+0, 19200, 19200, 240, 480, 0xd712ede5
+0, 19440, 19440, 240, 480, 0x6ba13597
+0, 19680, 19680, 240, 480, 0x29e143cf
+0, 19920, 19920, 240, 480, 0x3630da3f
+0, 20160, 20160, 240, 480, 0xbce7f531
+0, 20400, 20400, 240, 480, 0xdab9ee8e
+0, 20640, 20640, 240, 480, 0x534df31e
+0, 20880, 20880, 240, 480, 0x3153ff06
+0, 21120, 21120, 240, 480, 0x6dacf172
+0, 21360, 21360, 240, 480, 0x833405ee
+0, 21600, 21600, 240, 480, 0x92ffef77
+0, 21840, 21840, 240, 480, 0x307de935
+0, 22080, 22080, 240, 480, 0x4880e8cc
+0, 22320, 22320, 240, 480, 0x4aa0f6e9
+0, 22560, 22560, 240, 480, 0x76f2f2de
+0, 22800, 22800, 240, 480, 0xcdbdf36b
+0, 23040, 23040, 240, 480, 0x2a29eed8