Commit 6764a34
fix: planar YUV correctness + alignment in Image methods
Several Image methods were silently producing wrong output for planar
YUV formats and for any format-width pair where the natural linesize
isn't a multiple of 32. Each surfaced as a different visual artefact
once the SHM started carrying YUV420P/RGB32/etc. through to the
JPEG encoders without an upfront convert-to-RGB32 step:
- Image::Assign(const Image &): sized new_size from
image.height * image.linesize, which counts only the Y plane for
planar layouts. Use image.size, which is populated from
av_image_get_buffer_size and includes chroma. Without this an
Assign'd YUV420P image left Cb/Cr at zero — solid green output via
YCbCr-to-RGB later.
- Image::AssignDirect(width,height,colours,...): computed
new_buffer_size as W*H*p_colours and linesize as W*p_colours, both
wrong for planar (1.5x undersize) and for non-32-aligned RGB widths
(the actual buffer stride after sws_scale + av_image_fill_arrays
with align=32 is FFALIGN(W*bpp, 32), not W*bpp). Use
av_image_get_buffer_size and FFALIGN(av_image_get_linesize(...), 32)
so the recorded size/linesize match the real buffer layout.
Mismatched linesize produced the diagonal-shift artefact in
RGB32 streams at scaled widths like 1094.
- Image::WriteBuffer: same FFALIGN linesize fix; it was using the
unaligned natural linesize too.
- Image::Scale(new_width, new_height): scale_buffer was sized
(new_W+1)*(new_H+1)*colours which undercounts planar formats.
SWScale::Convert correctly checks the buffer against
av_image_get_buffer_size and returns an error, but the caller
ignored the return value and AssignDirect'd the empty/uninit
buffer anyway. Size with av_image_get_buffer_size, check the
Convert return, free and bail on failure.
- Image::Scale(factor): the hand-rolled pixel-doubling/decimation
loop treated the buffer as packed `colours`-bytes-per-pixel —
scaled only the Y plane and dropped chroma. Drop the loop and
delegate to Scale(new_width, new_height), which now uses sws_scale
for all formats.
- Image::EncodeJpeg + Image::WriteJpeg: format dispatch and
scanline writer had no planar-YUV support. WriteJpeg's existing
branch unpacked the buffer as packed YUYV 4:2:2 with offset
scanline*W*2, which read W*H/2 bytes past the end of any YUV420P
buffer — a latent crash that became reachable once image_buffer
could carry YUV420P data, segfaulting from the Event thread on
every event-frame write. Add a planar branch that uses
av_image_fill_arrays for plane pointers and per-plane linesizes
and feeds JCS_YCbCr scanlines built from the Y/U/V planes —
works for both 4:2:0 (YUV420P/YUVJ420P) and 4:2:2 (YUV422P/YUVJ422P).
- Image::Overlay: the warning fired on a benign GRAY8-on-YUV420P
case (both report colours=1 due to the GRAY8/YUV420P alias
collision in zm_rgb.h, but their imagePixFormat differs). Reframe
the check so it only warns when imagePixFormat actually matches
but the ZM (colours, subpixelorder) metadata diverges — i.e. a
real format-tracking bug.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 7b21371 commit 6764a34
1 file changed
Lines changed: 163 additions & 129 deletions
0 commit comments