PR #25172 opened by Marti2203
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25172
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25172.patch
The `SWS_DITHER_ED` branches of `yuv2mono_1_c_template()` and
`yuv2mono_2_c_template()` only store a byte when `(i & 7) == 6`. For widths
whose last pixel pair does not end a byte, the final partial byte of each row
is never written and keeps whatever the destination buffer held.
`yuv2mono_X_c_template()` already writes this tail (`if (i & 6)` after the
loop).
Reproduction (uniformly white input, so every valid bit should be 1):
```
ffmpeg -f lavfi -i color=c=white:s=100x8:d=0.04 -frames:v 1 \
-sws_flags +error_diffusion -vf format=monob -f rawvideo out.raw
```
Last byte of rows 0-3 (pixels 96-99 are the top 4 bits):
| width | master (ED) | patched (ED) | default dither |
|-------|-------------|--------------|----------------|
| 100 | ff 00 00 00 | ff f0 f0 f0 | f0 f0 f0 70 |
| 102 | ff 00 00 00 | ff fc fc fc | fc fc fc 7c |
| 64 | ff ff ff ff | ff ff ff ff | ff ff ff 7f |
The patch writes the pending bits after the loop, shifted into the high bits as
monob expects. The 28 FATE tests matching `monob`/`monow` (`pixfmt-*`,
`filter-pixdesc-*`, `lavf-*`) pass.
This issue was found by an LLM-Enhanced Static Analysis Engine and verified
manually.
>From 926e5ffc1aa465416463270bdbb50202d5093557 Mon Sep 17 00:00:00 2001
From: Martin Mirchev <[email protected]>
Date: Sun, 18 Oct 2026 16:30:57 +0800
Subject: [PATCH] swscale/output: write the last partial byte in the mono
error-diffusion paths
The SWS_DITHER_ED branches of yuv2mono_1_c_template() and
yuv2mono_2_c_template() only store a byte when (i & 7) == 6, so for widths
whose last pixel pair does not end a byte the final partial byte of each
row is never written and keeps whatever the destination held. Converting a
white 100x8 frame with -sws_flags +error_diffusion -pix_fmt monob leaves the
last 4 pixels of rows 1-7 black (0x00 instead of 0xf0).
Write the pending bits after the loop, shifted into the high bits as monob
expects, like the non-ED paths.
Signed-off-by: Martin Mirchev <[email protected]>
---
libswscale/output.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libswscale/output.c b/libswscale/output.c
index 760dca642e..5cc5cf026d 100644
--- a/libswscale/output.c
+++ b/libswscale/output.c
@@ -749,6 +749,8 @@ yuv2mono_2_c_template(SwsInternal *c, const int16_t *buf[2],
output_pixel(*dest++, acc);
}
c->dither_error[0][i] = err;
+ if (i & 6)
+ output_pixel(*dest, acc << (8 - (i & 7)));
} else {
for (i = 0; i < dstW; i += 8) {
int Y;
@@ -807,6 +809,8 @@ yuv2mono_1_c_template(SwsInternal *c, const int16_t *buf0,
output_pixel(*dest++, acc);
}
c->dither_error[0][i] = err;
+ if (i & 6)
+ output_pixel(*dest, acc << (8 - (i & 7)));
} else {
for (i = 0; i < dstW; i += 8) {
unsigned acc = 0;
--
2.54.0
_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]