Image::Fill(Polygon) implements scan-line polygon fill but iterated
through active edges one at a time instead of in pairs. For convex
polygons (always exactly 2 active edges per scan line) this happened
to work, but for non-convex polygons it would fill the gaps between
concave sections.
A banana-shaped zone, for example, would have its inner concave area
incorrectly marked as inside the zone, causing motion detection to
trigger on the area the user explicitly drew the zone to avoid.
Fix by stepping the iterator by 2 to fill between pairs of edges
following the standard parity rule for scan-line polygon fill.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add www-data to video and dialout groups in Debian/Ubuntu postinst
scripts so zmc can access /dev/video* devices on fresh installs.
RedHat packaging already handled this via gpasswd in %post.
Add compile-time ZM_FONTDIR to zm_config_data.h.in and use it as a
fallback in zm_image.cpp when the configured font_file_location is not
found, fixing font loading failures caused by stale DB config values.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
colours and subpixelorder were set to GRAY8/NONE before the
format detection logic, so RGB32 SSSE3/fast paths were never
reached and subpixel order switches always hit the default case.
Save originals before overwriting and set output values after
conversion.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace per-frame AllocBuffer/free cycle with a persistent
blend_buffer_ member that is allocated once and reused across
calls. For non-holdbuffer images, swap buffer pointers instead
of freeing and reallocating. Eliminates ~8MB alloc+free per
frame for 1080p RGBA.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge() reset pdest and psrc to buffer base on every pixel iteration,
so only buffer[0] was ever written. Move pdest outside the loop and
use direct array indexing for source buffers.
Highlight() had the same pointer reset bug plus iterated over size
(total bytes) instead of pixels, and the unsigned diff calculation
wrapped around instead of computing absolute difference. Fix pointer
management, loop bound, and diff comparison.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously, when av_buffer_create() failed and returned nullptr, the code
only issued a Warning and continued, assigning the null pointer to the
frame buffer and returning success. Now properly returns -1 on failure.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Switch all owning AVFrame* variables to av_frame_ptr for
automatic cleanup.
Use AVBufferRef to store frame data in AVFrame where appropriate
so that it can be freed automatically with it's AVFrame.
Handle allocation errors.