PR #25515 opened by Forgejo_Fairy URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25515 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25515.patch
Negative-zero samples can replace a zero period peak in speechnorm's nonnegative analysis branch. Dividing the target peak by that value produces negative infinite gain, corrupting silence and subsequent nonzero audio; linked processing can spread the corruption to other channels. Take the absolute value when accumulating the nonnegative half-period's peak. This treats both signs of zero identically without changing finite nonzero peak values. Add four synthetic FATE tests covering float and double processing, linked and independent channels, signed silence, and transitions to and from nonzero input. Expected sample counts and NaN/infinity statistics reside in tests/ref/fate/filter-speechnorm; no external sample is needed. Validation on Linux AArch64 with GCC 13.3.0: all four tests fail with the unpatched binary and pass with this change. The synthetic cases and attached WAV from #25434 produce finite output after the fix, and AAC encoding succeeds with linking enabled and disabled. Ordinary sine output remains byte-identical in both formats and linking modes. Fixes #25434. >From dfde5f140545a93529ac297b10c7b83d138ed32f Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Tue, 27 Oct 2026 03:55:37 +0000 Subject: [PATCH] avfilter/af_speechnorm: keep peak magnitudes nonnegative Negative zero enters the nonnegative analysis branch and can replace a zero peak through FFMAX. Dividing the target peak by that negative zero then produces a negative infinite gain, corrupting both silence and later nonzero input. Take the absolute value when accumulating the nonnegative half-period's peak. This preserves finite nonzero peaks while treating both signs of zero identically. Add synthetic FATE coverage for both sample formats, linked and unlinked channels, and transitions between signed silence and nonzero samples. The tests compare the sample count and NaN/Inf statistics with a reference. Fixes #25434. Assisted-by: Fairy --- libavfilter/af_speechnorm.c | 2 +- tests/fate/filter-audio.mak | 12 ++++++++++++ tests/ref/fate/filter-speechnorm | 4 ++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/ref/fate/filter-speechnorm diff --git a/libavfilter/af_speechnorm.c b/libavfilter/af_speechnorm.c index 9e2ba6381c5..729c4d2dc04 100644 --- a/libavfilter/af_speechnorm.c +++ b/libavfilter/af_speechnorm.c @@ -283,7 +283,7 @@ static void analyze_channel_## name (AVFilterContext *ctx, ChannelContext *cc, new_size = pi[pi_end].size; \ if (cc->state) { \ while (src[n] >= zero) { \ - new_max_peak = FFMAX(new_max_peak, src[n]); \ + new_max_peak = FFMAX(new_max_peak, fabs(src[n])); \ new_rms_sum += src[n] * src[n]; \ new_size++; \ n++; \ diff --git a/tests/fate/filter-audio.mak b/tests/fate/filter-audio.mak index f1035bba24a..00376350edb 100644 --- a/tests/fate/filter-audio.mak +++ b/tests/fate/filter-audio.mak @@ -458,6 +458,18 @@ fate-filter-crazychannels: tests/data/filtergraphs/crazychannels fate-filter-crazychannels: CMD = framecrc -auto_conversion_filters -/filter_complex $(TARGET_PATH)/tests/data/filtergraphs/crazychannels FATE_AFILTER-$(call FILTERFRAMECRC, ARESAMPLE SINE JOIN ATRIM CHANNELMAP CHANNELSPLIT, FILE_PROTOCOL) += fate-filter-crazychannels +# Exercise signed silence and transitions to/from nonzero input across frames. +FATE_SPEECHNORM = fate-filter-speechnorm-fltp fate-filter-speechnorm-dblp \ + fate-filter-speechnorm-fltp-linked fate-filter-speechnorm-dblp-linked + +fate-filter-speechnorm-fltp fate-filter-speechnorm-fltp-linked: SPEECHNORM_FMT = fltp +fate-filter-speechnorm-dblp fate-filter-speechnorm-dblp-linked: SPEECHNORM_FMT = dblp +$(FATE_SPEECHNORM): SPEECHNORM_LINK = 0 +fate-filter-speechnorm-fltp-linked fate-filter-speechnorm-dblp-linked: SPEECHNORM_LINK = 1 +$(FATE_SPEECHNORM): CMD = ffmpeg -auto_conversion_filters -f lavfi -i "aevalsrc=0|-0|if(lt(t\,0.5)\,-0\,0.1)|if(lt(t\,0.5)\,-0.1\,-0):s=48000:d=1" -af "aformat=sample_fmts=$(SPEECHNORM_FMT),speechnorm=link=$(SPEECHNORM_LINK),asetnsamples=n=48000:p=0,astats=metadata=1:measure_perchannel=none:measure_overall=Number_of_samples+Number_of_NaNs+Number_of_Infs,ametadata=mode=print:file=-" -c:a pcm_f64le -f null - +$(FATE_SPEECHNORM): REF = $(SRC_PATH)/tests/ref/fate/filter-speechnorm +FATE_AFILTER-$(call ALLYES, LAVFI_INDEV AEVALSRC_FILTER AFORMAT_FILTER ARESAMPLE_FILTER SPEECHNORM_FILTER ASETNSAMPLES_FILTER ASTATS_FILTER AMETADATA_FILTER PCM_F64$(if $(filter yes,$(HAVE_BIGENDIAN)),BE,LE)_DECODER PCM_F64LE_ENCODER NULL_MUXER PIPE_PROTOCOL) += $(FATE_SPEECHNORM) + FATE_AFILTER-yes += fate-filter-formats fate-filter-formats: libavfilter/tests/formats$(EXESUF) fate-filter-formats: CMD = run libavfilter/tests/formats$(EXESUF) diff --git a/tests/ref/fate/filter-speechnorm b/tests/ref/fate/filter-speechnorm new file mode 100644 index 00000000000..91a775f1e34 --- /dev/null +++ b/tests/ref/fate/filter-speechnorm @@ -0,0 +1,4 @@ +frame:0 pts:0 pts_time:0 +lavfi.astats.Overall.Number_of_samples=48000.000000 +lavfi.astats.Number of NaNs=0.000000 +lavfi.astats.Number of Infs=0.000000 -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
