PR #24535 opened by AYOUB NABIL BOUBAGRAT (ayoubnabil)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24535
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24535.patch

with aa=0, rounding can still send samples into the interpolation path, where 
factor() divides by zero and produces NaNs. return zero in this case to keep 
the quantized value.

added a FATE test that fails before the fix and passes after. tested 
configurations with aa>0 stay bit-identical.


>From 31c85ce1749730522c5688845a0de8b597a45773 Mon Sep 17 00:00:00 2001
From: Ayoub Nabil Boubagrat <[email protected]>
Date: Wed, 16 Sep 2026 11:37:59 +0200
Subject: [PATCH] avfilter/af_acrusher: avoid NaNs when anti-aliasing is
 disabled

Signed-off-by: Ayoub Nabil Boubagrat 
<[email protected]>
---
 libavfilter/af_acrusher.c              | 8 ++++++++
 tests/fate/filter-audio.mak            | 3 +++
 tests/ref/fate/filter-acrusher-zero-aa | 8 ++++++++
 3 files changed, 19 insertions(+)
 create mode 100644 tests/ref/fate/filter-acrusher-zero-aa

diff --git a/libavfilter/af_acrusher.c b/libavfilter/af_acrusher.c
index 3ec38269d0..c3374ea46f 100644
--- a/libavfilter/af_acrusher.c
+++ b/libavfilter/af_acrusher.c
@@ -118,6 +118,14 @@ static double remove_dc(double s, double dc, double idc)
 
 static inline double factor(double y, double k, double aa1, double aa)
 {
+    /* aa == 0 sets aa1 to 0.5, so the anti-aliasing region is empty and the
+     * callers should always take their |y - k| <= aa1 branch instead.  They do
+     * not always: k comes from roundf() applied to a double, which rounds at
+     * float precision and can leave |y - k| a hair above 0.5.  Dividing by aa
+     * then gives sin(+-INFINITY), i.e. NaN.  A zero-width transition means no
+     * interpolation, which is what returning 0 expresses. */
+    if (aa <= 0.0)
+        return 0.0;
     return 0.5 * (sin(M_PI * (fabs(y - k) - aa1) / aa - M_PI_2) + 1);
 }
 
diff --git a/tests/fate/filter-audio.mak b/tests/fate/filter-audio.mak
index b5c27daf1c..a1e3b88a8c 100644
--- a/tests/fate/filter-audio.mak
+++ b/tests/fate/filter-audio.mak
@@ -205,6 +205,9 @@ fate-filter-pan-channel-id-limit: REF = Input channel id 768
 FATE_AFILTER-$(call ALLYES, LAVFI_INDEV AEVALSRC_FILTER SILENCEREMOVE_FILTER 
ARESAMPLE_FILTER) += fate-filter-silenceremove
 fate-filter-silenceremove: CMD = framecrc -auto_conversion_filters -f lavfi -i 
"aevalsrc=between(t\,1\,2)+between(t\,4\,5)+between(t\,7\,9):d=10:n=8192,silenceremove=start_periods=0:start_duration=0:start_threshold=0:stop_periods=-1:stop_duration=0:stop_threshold=-90dB:window=0:detection=avg"
 
+FATE_AFILTER-$(call FILTERFRAMECRC, AEVALSRC ACRUSHER ARESAMPLE, 
PCM_F32LE_ENCODER PCM_F64LE_DECODER LAVFI_INDEV) += fate-filter-acrusher-zero-aa
+fate-filter-acrusher-zero-aa: CMD = framecrc -auto_conversion_filters -f lavfi 
-i "aevalsrc=0.9*sin(1000*t):d=0.2:n=4096" -af "acrusher=aa=0:bits=16:mix=1" 
-c:a pcm_f32le
+
 FATE_FILTER_STEREOTOOLS-$(call FRAMECRC) += fate-filter-stereotools
 FATE_AFILTER_SAMPLES-$(call FILTERDEMDECENCMUX, STEREOTOOLS ARESAMPLE, WAV, 
PCM_S16LE, PCM_S16LE, WAV) += $(FATE_FILTER_STEREOTOOLS-yes)
 fate-filter-stereotools: SRC = 
$(TARGET_SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav
diff --git a/tests/ref/fate/filter-acrusher-zero-aa 
b/tests/ref/fate/filter-acrusher-zero-aa
new file mode 100644
index 0000000000..37631acf88
--- /dev/null
+++ b/tests/ref/fate/filter-acrusher-zero-aa
@@ -0,0 +1,8 @@
+#tb 0: 1/44100
+#media_type 0: audio
+#codec_id 0: pcm_f32le
+#sample_rate 0: 44100
+#channel_layout_name 0: mono
+0,          0,          0,     4096,    16384, 0xf8f5ff93
+0,       4096,       4096,     4096,    16384, 0x5136f2c8
+0,       8192,       8192,      628,     2512, 0x95c5a42f
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to