PR #25183 opened by Marti2203
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25183
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25183.patch

Follow-up to #25172, from its review.

In `yuv2mono_X_c_template()` (the multi-tap path, e.g. when scaling vertically) 
the final partial byte of each row was stored as `acc`, without moving its bits 
to the most significant positions. For widths that are not a multiple of 8 the 
last pixels of every row were therefore wrong: their bits went into the 
padding, and the visible positions showed the preceding pixels.

Example, 100x16 picture scaled to 100x4 (bicubic), last byte of each row:

| input | format | before | after |
|---|---|---|---|
| white at x=96..97, rest black | monob | `0c` | `c0` |
| white at x=96..99, rest black | monob | `0f` | `f0` |
| white at x=0..95, tail black | monob | `f0` | `00` |
| white at x=0..95, tail black | monow | `0f` | `f0` |

The same with error diffusion and ordered dithering.

The fix shifts the accumulator into place before the store, as suggested in the 
review. The `vsynth3-bpp1` (34x34, monow) reference changes with it: only the 
last byte of each row differs (1624 of 8500 bytes), PSNR against the source 
goes from 9.57 to 9.66, and in those last two columns the output now agrees 
with the thresholded source as often as in the rest of the row (0.71/0.67, 
before 0.55/0.52). All other sample-free FATE tests pass.

The second commit adds `sws-monob-x-tail` and `sws-monow-x-tail`, which differ 
before the fix and match after.

🤖 Generated with [Claude Code](https://claude.com/claude-code)



From 0305574fc074594d4352641200ac1665404d13c9 Mon Sep 17 00:00:00 2001
From: Martin Mirchev <[email protected]>
Date: Sun, 18 Oct 2026 19:04:03 +0800
Subject: [PATCH 1/2] swscale/output: align the last partial byte in the mono
 _X path

yuv2mono_X_c_template() stored the bits of a final partial byte without
moving them to the most significant positions, so for widths that are not
a multiple of 8 the last pixels of every row were wrong: their bits ended
up in the padding, and the visible positions showed earlier pixels. Shift
the accumulator into place before storing it.

The vsynth3 (34x34) monow reference changes accordingly: only the last
byte of each row differs, and its pixels now agree with the source as
often as the rest of the row.

Signed-off-by: Martin Mirchev <[email protected]>
---
 libswscale/output.c           | 2 +-
 tests/ref/vsynth/vsynth3-bpp1 | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/libswscale/output.c b/libswscale/output.c
index 760dca642e..592867b268 100644
--- a/libswscale/output.c
+++ b/libswscale/output.c
@@ -710,7 +710,7 @@ yuv2mono_X_c_template(SwsInternal *c, const int16_t 
*lumFilter,
     c->dither_error[0][i] = err;
 
     if (i & 6) {
-        output_pixel(*dest, acc);
+        output_pixel(*dest, acc << (8 - (i & 7)));
     }
 }
 
diff --git a/tests/ref/vsynth/vsynth3-bpp1 b/tests/ref/vsynth/vsynth3-bpp1
index 639a2b15de..a79905a1e4 100644
--- a/tests/ref/vsynth/vsynth3-bpp1
+++ b/tests/ref/vsynth/vsynth3-bpp1
@@ -1,4 +1,4 @@
-7eafab02a501b3b0ac9f854cd334f47a *tests/data/fate/vsynth3-bpp1.avi
+b6e3c1ebbe2c7c00d79d76608f394026 *tests/data/fate/vsynth3-bpp1.avi
 20460 tests/data/fate/vsynth3-bpp1.avi
-52ae74ef7910e5b603c12288d425b9ae *tests/data/fate/vsynth3-bpp1.out.rawvideo
-stddev:   84.76 PSNR:  9.57 MAXDIFF:  232 bytes:    86700/    86700
+5a0e703a6b60942d57409654c76d2aea *tests/data/fate/vsynth3-bpp1.out.rawvideo
+stddev:   83.82 PSNR:  9.66 MAXDIFF:  217 bytes:    86700/    86700
-- 
2.54.0


From 8cb3855d99a7084efcc0e7f9d3854e57ded078f9 Mon Sep 17 00:00:00 2001
From: Martin Mirchev <[email protected]>
Date: Sun, 18 Oct 2026 19:04:04 +0800
Subject: [PATCH 2/2] tests/swscale: cover the last partial byte of the mono _X
 path

Scale a 100-pixel-wide picture vertically so that the multi-tap output
path is used, with distinct patterns in the last partial byte for both
monochrome polarities.

Signed-off-by: Martin Mirchev <[email protected]>
---
 tests/fate/libswscale.mak       | 6 ++++++
 tests/ref/fate/sws-monob-x-tail | 6 ++++++
 tests/ref/fate/sws-monow-x-tail | 6 ++++++
 3 files changed, 18 insertions(+)
 create mode 100644 tests/ref/fate/sws-monob-x-tail
 create mode 100644 tests/ref/fate/sws-monow-x-tail

diff --git a/tests/fate/libswscale.mak b/tests/fate/libswscale.mak
index 673c28eae9..eb3730140c 100644
--- a/tests/fate/libswscale.mak
+++ b/tests/fate/libswscale.mak
@@ -22,6 +22,12 @@ $(SWS_SLICE_TEST-yes): tools/scale_slice_test$(EXESUF)
 $(SWS_SLICE_TEST-yes): REF = /dev/null
 FATE_LIBSWSCALE_SAMPLES += $(SWS_SLICE_TEST-yes)
 
+# Last partial byte of each row in the multi-tap monochrome output path.
+FATE_LIBSWSCALE_FFMPEG-$(call FILTERFRAMECRC, COLOR DRAWBOX SCALE FORMAT) += 
fate-sws-monob-x-tail \
+                                                                        
fate-sws-monow-x-tail
+fate-sws-monob-x-tail: CMD = framecrc -lavfi 
color=black:s=100x16:r=1,format=yuv420p,drawbox=x=96:y=0:w=2:h=16:color=white:t=fill,scale=100:4:flags=bicubic+bitexact,format=monob
 -frames:v 1
+fate-sws-monow-x-tail: CMD = framecrc -lavfi 
color=black:s=100x16:r=1,format=yuv420p,drawbox=x=0:y=0:w=96:h=16:color=white:t=fill,scale=100:4:flags=bicubic+bitexact,format=monow
 -frames:v 1
+
 FATE_LIBSWSCALE_FFMPEG-$(call FRAMECRC, RAWVIDEO, RAWVIDEO, SCALE_FILTER) += 
fate-sws-yuv-colorspace \
                                                                              
fate-sws-yuv-range
 fate-sws-yuv-colorspace: tests/data/vsynth1.yuv
diff --git a/tests/ref/fate/sws-monob-x-tail b/tests/ref/fate/sws-monob-x-tail
new file mode 100644
index 0000000000..da9763835b
--- /dev/null
+++ b/tests/ref/fate/sws-monob-x-tail
@@ -0,0 +1,6 @@
+#tb 0: 1/1
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 100x4
+#sar 0: 1/4
+0,          0,          0,        1,       52, 0x3d800300
diff --git a/tests/ref/fate/sws-monow-x-tail b/tests/ref/fate/sws-monow-x-tail
new file mode 100644
index 0000000000..5823283bd2
--- /dev/null
+++ b/tests/ref/fate/sws-monow-x-tail
@@ -0,0 +1,6 @@
+#tb 0: 1/1
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 100x4
+#sar 0: 1/4
+0,          0,          0,        1,       52, 0x4ce003c0
-- 
2.54.0

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

Reply via email to