fix: build zone alarm highlights in YUV420P to stop spurious Colourise warning

The "Target image is already colourised, colours: 1" warning fired from
Image::Colourise() during zone alarm overlay on YUV420P monitors, even with
ZM_COLOUR_JPEG_FILES off.

monitor->Colours() returns 1 for both GRAY8 and planar YUV420P (the GRAY8
alias), so zm_zone.cpp misclassified YUV420P monitors as grayscale and built
an RGB24 alarm highlight. Overlaying that RGB24 highlight onto the YUV420P
analysis_image hit the RGB-on-mono branch, which calls Colourise() - valid
only for GRAY8. Colourise() warned and bailed, after which the per-pixel loop
walked the 1.5x planar buffer as 3x packed RGB (out-of-bounds write).

Resolve the real capture format via zm_pixformat_from_colours() so true GRAY8
still upgrades to an RGB24 highlight while YUV420P keeps its format. Add a
YUV420P output branch to HighlightEdges (single alarm colour written to luma
and the shared chroma sample, transparent elsewhere) and a YUV420P-on-YUV420P
branch to Overlay (copies luma where non-zero, copies each chroma sample when
any covered luma pixel is marked). Colourise() is now only reached for GRAY8.

Add Catch2 coverage for the YUV420P Overlay masking and HighlightEdges output.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Isaac ConnorandClaude Opus 4.8 committed 2026-06-26 16:10:07 -04:00
1 parent d4020e6394
commit cf92249820
3 files changed
+155 -3

No files matched your search

+7 -1
View File
@@ -790,7 +790,13 @@ bool Zone::CheckAlarms(const Image *delta_image) {
}
} // end for y
if (monitor->Colours() == ZM_COLOUR_GRAY8) {
// Build the alarm highlight in the capture's own pixel format so Overlay()
// onto the analysis image is a same-format copy. monitor->Colours()==1
// aliases both GRAY8 and planar YUV420P, so resolve the real format first:
// a true GRAY8 monitor has no colour to carry, so upgrade its highlight to
// RGB24; YUV420P keeps its format and carries the alarm colour in chroma.
AVPixelFormat capture_fmt = zm_pixformat_from_colours(monitor->Colours(), monitor->SubpixelOrder());
if (capture_fmt == AV_PIX_FMT_GRAY8) {
image = diff_image->HighlightEdges(alarm_rgb, ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB, &polygon.Extent());
} else {
image = diff_image->HighlightEdges(alarm_rgb, monitor->Colours(), monitor->SubpixelOrder(), &polygon.Extent());