PR #24707 opened by Forgejo_Fairy URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24707 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24707.patch
The libspeex encoder emits empty audio packets since c31a781412a3 (#23692). The status returned by `ff_af_queue_remove()` overwrites the byte count from `speex_bits_write()`, and the successful status of zero becomes the packet size. Store the encoded byte count directly in the packet before updating its timing, preserving queue error handling. Add generated-input FATE tests for mono encoding and stereo encoding with two frames per packet. The tests compare decoded frame counts and stream properties, avoiding dependence on libspeex's precise encoded bytes or additional sample files. Addresses #23926. Validation on Linux AArch64 with GCC 13 and libspeex 1.2.1: - Built and tested c31a781412a3 and its parent 87bcbbff5722. A one-second, 32 kHz mono sine encoded at the requested 30 kbit/s produces zero audio payload bytes at the culprit, versus 3,700 bytes and 50 decoded frames at the parent. - Reproduced the same failure on master 6246f7a4cde6; the patch restores 3,700 payload bytes and 50 decoded frames. - `make fate-libspeex-encode fate-libspeex-encode-stereo` passes with the patch. Both tests fail against the unpatched master executable, reporting no decoded frames instead of 50 and 25 respectively. - Default one-frame-per-packet encoding and decoding succeeds for mono and stereo at 8, 16 and 32 kHz. - `git diff --check` passes. Reproduction: `ffmpeg -v verbose -f lavfi -i sine=frequency=1000:sample_rate=32000:duration=1 -y -vn -c:a libspeex -ab 30k -ar 32000 -frames:v 1000 output_spx.ogg`, followed by `ffmpeg -v verbose -i output_spx.ogg -f null -`. The existing queue-closing warning also occurs on the working parent and remains outside this packet-size fix. Broader checks found decoding errors for some partially filled final packets with nondefault `frames_per_packet=3` or `8`; these also occur with output from the working parent. The FATE tests use complete packets. Source inspection found the faulty assignment absent from the available active release branches 4.4, 5.1, 6.1, 7.1, 8.0, 8.1 and 9.0. >From 4aed8a59fe8d2ae15b3ac549e9fc1b5f4f262c11 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Fri, 25 Sep 2026 16:37:36 +0000 Subject: [PATCH] avcodec/libspeexenc: preserve the encoded packet size ff_af_queue_remove() now returns a status code. Its return value replaced the byte count from speex_bits_write(), so every successful encode emitted an empty packet. Store the encoded byte count in the packet before updating its timing. Add generated-input FATE coverage for mono and stereo encoding, including multiple frames per packet. Check decoded frame counts instead of exact encoded bytes so the tests do not depend on libspeex's implementation. Fixes: c31a781412a3aa801cc0997ba001177f258f4d80 Fixes: #23926 Assisted-by: Fairy --- libavcodec/libspeexenc.c | 3 +-- tests/fate/enc_external.mak | 14 ++++++++++++++ tests/ref/fate/libspeex-encode | 6 ++++++ tests/ref/fate/libspeex-encode-stereo | 6 ++++++ 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 tests/ref/fate/libspeex-encode create mode 100644 tests/ref/fate/libspeex-encode-stereo diff --git a/libavcodec/libspeexenc.c b/libavcodec/libspeexenc.c index 32abadcef1..6e1591b397 100644 --- a/libavcodec/libspeexenc.c +++ b/libavcodec/libspeexenc.c @@ -292,7 +292,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *avpkt, s->pkt_frame_count = 0; if ((ret = ff_alloc_packet(avctx, avpkt, speex_bits_nbytes(&s->bits))) < 0) return ret; - ret = speex_bits_write(&s->bits, avpkt->data, avpkt->size); + avpkt->size = speex_bits_write(&s->bits, avpkt->data, avpkt->size); speex_bits_reset(&s->bits); /* Get the next frame pts/duration */ @@ -301,7 +301,6 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *avpkt, if (ret < 0) return ret; - avpkt->size = ret; *got_packet_ptr = 1; return 0; } diff --git a/tests/fate/enc_external.mak b/tests/fate/enc_external.mak index 705f733db7..aa017dfcaa 100644 --- a/tests/fate/enc_external.mak +++ b/tests/fate/enc_external.mak @@ -14,3 +14,17 @@ fate-libx264-hdr10: CMD = enc_external $(TARGET_SAMPLES)/hevc/hdr10_plus_h265_sa FATE_SAMPLES_FFMPEG_FFPROBE += $(FATE_ENC_EXTERNAL-yes) fate-enc-external: $(FATE_ENC_EXTERNAL-yes) + +# Check decoded frame counts without depending on libspeex's encoded bytes. +FATE_LIBSPEEX-$(call ALLYES, LIBSPEEX_ENCODER SPEEX_DECODER OGG_MUXER OGG_DEMUXER LAVFI_INDEV SINE_FILTER ARESAMPLE_FILTER PCM_S16LE_DECODER FILE_PROTOCOL) += fate-libspeex-encode fate-libspeex-encode-stereo +fate-libspeex-encode: SPEEX_OPTS = -ac 1 +fate-libspeex-encode-stereo: SPEEX_OPTS = -ac 2 -frames_per_packet 2 +$(FATE_LIBSPEEX-yes): CMD = run_with_temp \ + "$(FFMPEG) -nostdin -hide_banner -loglevel error \ + -f lavfi -i sine=frequency=1000:sample_rate=32000:duration=1 \ + -c:a libspeex -b:a 30k $(SPEEX_OPTS) -f ogg -y" \ + "ffprobe$(PROGSSUF)$(EXESUF) -v error -bitexact -count_frames \ + -show_entries stream=codec_name,sample_rate,channels,nb_read_frames" ogg + +FATE_FFMPEG_FFPROBE += $(FATE_LIBSPEEX-yes) +fate-enc-external: $(FATE_LIBSPEEX-yes) diff --git a/tests/ref/fate/libspeex-encode b/tests/ref/fate/libspeex-encode new file mode 100644 index 0000000000..179ea07d71 --- /dev/null +++ b/tests/ref/fate/libspeex-encode @@ -0,0 +1,6 @@ +[STREAM] +codec_name=speex +sample_rate=32000 +channels=1 +nb_read_frames=50 +[/STREAM] diff --git a/tests/ref/fate/libspeex-encode-stereo b/tests/ref/fate/libspeex-encode-stereo new file mode 100644 index 0000000000..ea01697eb4 --- /dev/null +++ b/tests/ref/fate/libspeex-encode-stereo @@ -0,0 +1,6 @@ +[STREAM] +codec_name=speex +sample_rate=32000 +channels=2 +nb_read_frames=25 +[/STREAM] -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
