Commit Graph

79 Commits

Author SHA1 Message Date
Isaac Connor
ce1474667a fix: stop montage zms <img> reconnect storm on stale auth hash
A live multipart (mode=jpeg) stream <img> whose baked auth hash expires
past AUTH_HASH_TTL is reconnected by the browser itself, reusing the same
src (same connkey, same dead hash). Every native reconnect returns 403, so
once the capture daemon drops the stream the client storms zms with auth
failures for hours. Observed in production: a single connkey retried 84
times over 2.5h, 880 failures on one monitor whose zmc was timing out,
while monitors with healthy zmc showed only baseline hash-rollover noise.

img_onerror only blanked the <img> src inside its async refresh callback,
which never ran once authRefreshAttempts reached the cap. On give-up the
stale src stayed live and the browser kept native-retrying it, which is the
storm. Blank src synchronously at the top of img_onerror so the browser's
retry loop stops immediately, and reconnect with a fresh connkey (the zms
process behind the old connkey has exited) after fetching a fresh hash.

Extract the src rewrite into a pure rebuildStreamSrc() helper in
auth-helpers.js with unit tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:15:28 -04:00
Steve Gilvarry
dc4cf32a63 fix: guard zms buffer_level against zero buffer count refs #4936
MonitorStream::processCommand computed buffer_level by dividing by
temp_image_buffer_count (and via MOD_ADD modulo) while only guarding on
playback_buffer. processCommand runs on the command_processor thread,
started in runStream before temp_image_buffer_count is assigned from
playback_buffer. In that window temp_image_buffer_count is still 0 while
playback_buffer is already > 0, so a command arriving then divided by
zero and raised SIGFPE, crashing nph-zms.

Extract the percentage math into MonitorStreamBufferLevel which returns 0
when the buffer count is not positive, and add Catch2 coverage for the
zero-count and wrap-around cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 08:21:29 +10:00
Isaac Connor
1e76424db1 Merge branch 'onvif-wsse-created-race' 2026-06-14 09:15:01 -05:00
Isaac Connor
312ce1d676 fix: pin ONVIF WS-Security Timestamp and UsernameToken Created together
ONVIF PullMessages intermittently failed with ter:NotAuthorized (logged as
the misleading clock-drift error) every few thousand requests, then ZM tore
down a healthy subscription and re-subscribed. SOAP logs showed the trigger:
the failing request always had wsu:Timestamp/Created one second behind
UsernameToken/Created, while every successful request had them identical.

The cause is in set_credentials(): soap_wsse_add_Timestamp() and
soap_wsse_add_UsernameTokenDigest() each call time(NULL) on their own, so when
the two calls straddle a one-second boundary the two Created values diverge by
a second and Hikvision rejects the request. This is probabilistic, which is
why it hit roughly hourly per camera and constantly across a fleet.

Capture time(NULL) once, re-stamp the Timestamp Created/Expires from it, and
use soap_wsse_add_UsernameTokenDigest_at() so the token Created and its
password digest are pinned to the same instant. Both Created values are then
always identical.

Add tests/zm_onvif_wsse.cpp asserting the two Created values match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 21:12:49 -05:00
Isaac Connor
5e0a0eeaee Merge pull request #4909 from SteveGilvarry/fix/rotate-plane-segfault
fix: corrupted scaled/converted output for rotated monitors (SWScale buffer alignment)
2026-06-13 10:20:56 -04:00
Isaac Connor
3b633a281b fix: Rotate/Flip honor borrowed source linesize; size Flip dest for 32-aligned planes
get_y_image() wraps the decoder Y plane zero-copy but recorded
FFALIGN(width,32) as the Image stride instead of the frame's real
linesize[0]. For widths that are not a multiple of 32 the decoder packs
the plane tighter than FFALIGN, so:

- Image::Rotate/Flip re-derived the source stride via
  av_image_fill_arrays(...,32) and read past the end of the borrowed
  plane (and skewed Y-channel motion analysis, which reads the same
  buffer).
- Image::Flip sized its destination from this->size, which is tight for a
  borrowed plane and smaller than the 32-aligned layout the planes are
  written at, overrunning the destination.

Record the frame's real linesize in get_y_image(); use the Image's own
linesize for the source plane-0 stride in Rotate/Flip; size Flip's
destination from av_image_get_buffer_size(...,32). All are no-ops for
self-consistent ZM-allocated (32-aligned) images.

tests/zm_image_linesize.cpp: Rotate 90/180/270 and Flip H/V over a tight,
non-32-aligned GRAY8 source verifying correct output.

refs #4788

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 09:35:40 -04:00
Isaac Connor
0db0db300d feat: add Filter::buildSortSql for directional event sort specs with integration test 2026-06-13 09:35:40 -04:00
SteveGilvarry
7e15324385 fix: corrupted scaled/converted output for rotated monitors — SWScale guessed buffer alignment from width
SWScale::Convert chose av_image_fill_arrays alignment by heuristic
(width % 32 ? 1 : 32) for both buffers. Image buffers are always laid
out align-32, so any width not divisible by 32 made Convert read luma
rows 16 bytes short and chroma planes from packed offsets: diagonal
shear plus garbage chroma. Rotating a monitor is what produces such
widths (1280x720 ROTATE_270 -> 720 wide, 3840x2160 ROTATE_90 -> 2160
wide, both % 32 == 16), so every scaled view and every re-encode of a
rotated monitor was corrupted while unrotated monitors (1280/2688/3840
all % 32 == 0) were untouched. The rotate/flip segfault fix exposed
this: before it, rotated planar frames crashed zmc before reaching
Scale.

Alignment is a fact about how a buffer was laid out, not something
derivable from dimensions. Convert now takes explicit in/out alignment:
Image::Scale passes 32/32, the videostore encode path mirrors
get_out_frame's allocation choice, libvnc passes 1 (packed VNC
framebuffer) and 32 (Image WriteBuffer). Remove the unused
SetDefaults/ConvertDefaults API rather than threading alignments
through dead code.

Tests: new Scale regression case on a 720x1280 YUV420P image
(column-banded luma, uniform chroma) fails before the fix exactly as
observed live (sheared rows, V plane reading 0) and passes after.
Full suite 84/84.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 10:19:09 +10:00
SteveGilvarry
ee366cdf78 fix: rotate/flip segfault from AV_CEIL_RSHIFT on unsigned dimensions
Image::Rotate and Image::Flip computed chroma plane dimensions with
AV_CEIL_RSHIFT(width, log2_chroma_w). The macro's runtime form is
-((-(a)) >> (b)), which relies on arithmetic right shift of a negative
value and is only valid for signed operands - FFmpeg always passes int.
Image::width/height are unsigned, so the negation wraps, the shift is
logical, and the result is 2^31 + ceil(w/2^b) instead of ceil(w/2^b):
for 1280x720 the chroma rotate received src_w=2147484288 and
src_h=2147484008 (captured in gdb), writing gigabytes out of bounds.

Effect: zmc's decoder thread segfaulted on the first decoded frame of
any monitor with a rotated or flipped orientation and a planar pixel
format - a monitor with decoding Always crash-loops.

Replace the macro at both sites with an explicit unsigned ceiling
shift helper and a comment documenting the trap.

Tests: new tests/zm_image.cpp covers Rotate 90/180/270 and Flip on
YUV420P with per-plane marker pixels, plus odd dimensions exercising
the chroma ceiling. The Rotate cases segfault before this fix (verified,
exit 139) and pass after. Full suite 85/85 via ctest. Live-verified on
a 1280x720 ROTATE_270 monitor with decoding Always: pre-fix crash
within seconds, post-fix 90s clean run under gdb.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 19:42:52 +10:00
Isaac Connor
37cfb64922 Merge pull request #4788 from ZoneMinder/fix/avpixelformat-respin
fix: deprecate ZM_COLOUR for AVPixelFormat (resubmit with planar/SHM fixes)
2026-06-06 12:45:03 -04:00
Isaac Connor
a55d167b91 feat: refresh auth hash on tab resume, redirect to login on dead session refs #4748
When a console or stream tab is backgrounded or the machine sleeps past the
auth hash TTL, the baked-in auth= on nph-zms <img> URLs expires. The browser
keeps reconnecting with the stale hash, producing a burst of 403s from zms
while the session-backed page still renders.

Detect the tab becoming visible again (visibilitychange/pageshow) and probe
auth once against the navBar status endpoint before letting streams reconnect:
on success refresh the global auth_hash and repaint; on a dead session (401)
go straight to login instead of retrying. Route the navBar poll, console table
query, and per-stream error paths through a shared decision so 401/403 ends in
a single login redirect rather than a retry storm.

Put the auth functions (goToLogin, revalidateAuth, onAuthVisible) and the pure
authFailureAction/loginRedirectUrl helpers in web/js/auth-helpers.js as named
globals; skin.js only wires the visibility listeners. Node unit tests cover the
pure helpers (tests/js/auth-helpers.test.js).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 10:26:15 -04:00
Isaac Connor
20f95ccde9 Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-06-04 09:46:11 -04:00
Isaac Connor
dd1976bdea Merge pull request #4871 from connortechnology/4870-midnight-event-folder-mismatch
fix: store event StartDateTime with second precision to match disk path (refs #4870)
2026-06-03 22:09:57 -04:00
Isaac Connor
614690925f docs: correct epoch-to-UTC time in test comment refs #4870
1764623999 is 2025-12-01 21:19:59 UTC, not 19:59:59. Pointed out by
Copilot review on PR #4871.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 22:05:26 -04:00
Isaac Connor
62ff384855 fix: store event StartDateTime with second precision to match disk path refs #4870
SystemTimePointToMysqlString appended ".%06d" microseconds to the string it
hands MySQL for the Events.StartDateTime datetime column. That column has no
fractional precision, and MySQL 8 ROUNDS a fractional value when storing it, so
a start_time of 23:59:59.5xx-.999999 local was promoted to 00:00:00 of the next
day. Event::SetPath() derives the on-disk day folder from to_time_t(start_time),
which truncates, so it landed on the previous day.

For continuous recording the event start is backdated to the preceding keyframe,
which for a section forced closed at local midnight falls just before midnight.
On MySQL 8 the DB row then recorded the next day while the files were written
under the previous day's folder, producing a permanent zmaudit path mismatch and
orphaned files when the event aged out (the purge path is built from
StartDateTime).

Format the value to whole seconds only so it matches to_time_t() used by
SetPath(), keeping the DB row and the disk folder on the same second regardless
of whether the DB engine rounds or truncates.

Add tests/zm_time.cpp covering the floor-not-round behaviour and consistency
with the to_time_t-derived path second.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 08:42:10 -04:00
Isaac Connor
2bfab23096 Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-06-01 17:05:03 -04:00
Isaac Connor
f7a3263c52 perf: emit sargable range queries for Date/StartDate/EndDate filter terms
zmfilter and the web filter UI generated SQL like
  to_days(E.StartDateTime) = to_days('2026-05-06 09:42:56')
which prevents MySQL from using the StartDateTime index, forcing a
full table scan. With many filter daemons against a large Events
table this saturates mysqld and makes the system unresponsive.

Rewrite the SQL generation in ZoneMinder::Filter (Perl) and
ZM\FilterTerm (PHP) so Date/StartDate/EndDate attrs emit range
expressions against the underlying datetime column:
  E.StartDateTime >= '2026-05-06 00:00:00'
    AND E.StartDateTime < '2026-05-07 00:00:00'
Covers =, !=, >, >=, <, <=, IS, IS NOT, IN, NOT IN, and the
CURDATE()/NOW() values (which use INTERVAL 1 DAY for the upper
bound). EXPLAIN now reports type=range on Events_StartDateTime_idx
where it previously reported type=ALL.

CurrentDate (the constant left-hand expression to_days(NOW()))
keeps its existing form since it does not touch the indexed column.

Add Perl and PHP unit tests under tests/perl/ and tests/php/
exercising the generated SQL across operators.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 22:13:22 -04:00
Jash
1ba3169de7 Merge branch 'master' of https://github.com/AJ0070/zoneminder into fix/4750 2026-05-29 09:45:51 +05:30
Jash
202753e99c fix: widen DefaultScale columns to preserve fit_to_width 2026-05-29 09:41:46 +05:30
Isaac Connor
a7c3fb7ce6 Merge branch 'master' into fix/avpixelformat-respin 2026-05-21 21:11:40 -04:00
Isaac Connor
e1eb7876c6 fix: clamp percentage polygon to width-1/height-1
ParsePercentagePolygon clamped to [0, width] / [0, height], so a new
zone created at 100% produced pixel coords equal to the monitor
dimensions. The rasterizer requires hi_x < width and hi_y < height,
so the runtime then logged warnings like
  "polygon hi_x (1920) >= image width (1920), clamping".

Clamp to width-1 / height-1 instead. Updates existing tests that
encoded the previous behavior.
2026-05-13 11:38:42 -04:00
Isaac Connor
c4073c964c feat: encoder parameter templates with editor + REST API closes #4778 closes #4802
Adds a curated, per-encoder parameter-template library to ZoneMinder:

- Monitor edit page: a new Template row above the EncoderParameters
  textarea offers per-encoder templates (Balanced / Archival / Low
  Power / Low CPU). Apply merges the template's params into the
  textarea, preserving user-only keys. Advisory lint flags option
  keys that aren't recognised for the selected encoder. Switching
  encoders offers a same-name template on the new encoder via a
  native confirm.

- Options page: a new Encoder Templates tab with full CRUD —
  list / edit / copy / delete — backed by a new CakePHP REST API
  at /api/encoder_templates.

- Storage: a new EncoderTemplates DB table seeded with 14 shipped
  defaults across libx264 / libx265 / h264_nvenc / hevc_nvenc /
  h264_vaapi / hevc_vaapi. The table is mutable; ZM upgrades do not
  re-seed user-edited rows.

- valid_keys (the lint allow-list) stays in PHP code as ffmpeg
  vocabulary, not user data.

- Default params explicitly include pix_fmt to avoid the yuvj420p
  HEVC HW-decode rejection issue we hit earlier.

No C++ change. The textarea content is parsed by the existing
av_dict_parse_string call in src/zm_videostore.cpp.

version.txt -> 1.39.6.

Specs: docs/superpowers/specs/2026-05-0{1,2}-*.md
Plans: docs/superpowers/plans/2026-05-0{1,2}-*.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 17:24:17 -04:00
Isaac Connor
7b21371083 Reapply "fix: replace ZM_COLOUR system with AVPixelFormat for format dispatch"
This reverts commit 60b6b37c60.
2026-05-03 12:24:43 -04:00
Isaac Connor
60b6b37c60 Revert "fix: replace ZM_COLOUR system with AVPixelFormat for format dispatch" 2026-05-02 18:26:48 -04:00
Isaac Connor
11544d86e3 fix: PR #4742 round 2 review feedback
Eight Copilot comments from the second review pass:

1. monitor.php (#3): "Deprecated - will be auto-detected..." note next
   to TargetColorspace bypassed translate(). Added DeprecatedColoursSetting
   key to en_gb and routed the deprecation note through translate() so it
   localises with the rest of the form.

2. tests/zm_pixformat.cpp (#4): zm_colours_from_pixformat / round-trip
   tests didn't cover the new YUV422P/YUVJ422P entries (added by
   02e6be6b4). Added explicit assertions in both test cases — bumps
   pixformat coverage from 105 to 115 assertions.

3. zm_image.cpp WriteBuffer (#5): linesize and size were derived from
   p_width * p_colours, which undercounts planar YUV* (where p_colours=1
   via the GRAY8 alias collision but actual buffer needs ~1.5x/2x for
   chroma). Use av_image_get_buffer_size and av_image_get_linesize for
   the AVPixelFormat instead, with bail-out on either failing.

4. zm_image.cpp AssignDirect (#6, #7): av_image_get_buffer_size returns
   int and can be negative; assigning that into unsigned size/allocation
   wrapped to a huge value. Check the return first, treat negative as the
   same "unsupported format" failure as zm_colours_from_pixformat
   returning false, and reset size/allocation/linesize/pixels to 0
   (alongside imagePixFormat=NONE/colours=0/subpixelorder=0) so the
   Image is left in a single coherent invalid state instead of partially
   stale.

5. zm_image.cpp Assign (#8): av_get_pix_fmt_name(format) can return
   nullptr (e.g. AV_PIX_FMT_NONE / unknown); passing that into
   Debug(..., "%s", ...) would segfault. Capture once with a fallback
   string before logging.

6. zm_monitor.cpp Capture path (#9): same nullptr issue with two Debug
   calls — capture native_fmt_name once with fallback.

7. zm_monitor.cpp can_passthrough comment (#10): comment claimed
   YUVJ422P would be converted to YUV420P because Image drops chroma,
   but can_passthrough now allows YUV422P/YUVJ422P passthrough since
   02e6be6b4 added 4:2:2 support. Updated the comment to describe the
   current behavior (full 4:2:0 + 4:2:2 planar passthrough plus GRAY8
   and RGB24/32) so the code and the rationale agree.

Tests: 76 cases, 788 assertions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 17:59:51 -04:00
Isaac Connor
b416aa5293 fix: replace ZM_COLOUR_*/ZM_SUBPIX_ORDER_* with AVPixelFormat for format dispatch
ZM_COLOUR_GRAY8, ZM_COLOUR_YUV420P, and ZM_COLOUR_YUVJ420P were all
defined to 1, making format identification via colours ambiguous.
LocalCamera misidentified YUV420P as GRAY8, causing V4L2 MJPEG cameras
to decode to grayscale via expensive sws_scale conversion.

Replace the legacy ZM_COLOUR_*/ZM_SUBPIX_ORDER_* integer pair with
AVPixelFormat as the single source of truth for pixel format dispatch:

- Add src/zm_pixformat.h with central format helpers:
  zm_pixformat_from_colours, zm_colours_from_pixformat,
  zm_bytes_per_pixel, zm_db_colours_to_pixformat, zm_is_rgb32,
  zm_is_rgb24, zm_is_yuv420
- Add AVPixelFormat pixelFormat member + PixelFormat() accessor to Camera
- Add PixFormat() accessor to Image, delegate AVPixFormat methods
  to shared helpers
- Migrate all ~100 format dispatch comparisons in zm_image.cpp,
  zm_local_camera.cpp, zm_ffmpeg_camera.cpp, zm_remote_camera_rtsp.cpp,
  zm_libvlc_camera.cpp, zm_libvnc_camera.cpp, zm_monitor.cpp,
  zm_mpeg.cpp from colours/subpixelorder checks to imagePixFormat/
  AVPixelFormat checks
- Deprecate GetFFMPEGPixelFormat, delegate to zm_pixformat_from_colours
- Fix DeColourise bug: imagePixFormat was not updated to GRAY8
- Deprecate ZM_COLOUR_* and ZM_SUBPIX_ORDER_* constants in zm_rgb.h
- Add deprecation notice on Monitor.Colours web UI dropdown
- Add 13 Catch2 test cases (105 assertions) for format mapping helpers

refs #4735

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 11:42:06 -04:00
Isaac Connor
7d78b722d0 fix: auto-detect zone coordinate format instead of trusting Units field
The zone loader now ignores the Units DB field and detects the coordinate
format by checking for decimal points: decimal values are percentages,
integer-only values are legacy pixels. This fixes motion detection being
broken when zones had Units=Pixels but percentage coordinates (or vice
versa), which resulted in a ~99x99 pixel zone on a 2560x1440 monitor.

The PHP zone view now always forces Units=Percent when saving, since it
always works in percentage space. convertPixelPointsToPercent() now
returns bool to indicate whether conversion occurred.

Tests added for: truncation bug via atoi, correct percentage-to-pixel
conversion, auto-detect heuristic, and resolution independence.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 15:26:36 -04:00
Isaac Connor
c0016fa00b feat: store zone coordinates as percentages for resolution independence
Convert zone coordinates from absolute pixel values to percentages
(0.00-100.00) so zones automatically adapt when monitor resolution
changes. This eliminates the need to manually reconfigure zones after
resolution adjustments.

Changes:
- Add DB migration (zm_update-1.37.81.sql) to convert existing pixel
  coords to percentages, recalculate area, and update Units default
- Add Zone::ParsePercentagePolygon() in C++ to parse percentage coords
  and convert to pixels at runtime using monitor dimensions
- Backwards compat: C++ Zone::Load() checks Units column and uses old
  pixel parser for legacy 'Pixels' zones
- Update PHP coordsToPoints/mapCoords/getPolyArea for float coords,
  replace scanline area algorithm with shoelace formula
- Update JS zone editor to work in percentage coordinate space with
  SVG viewBox "0 0 100 100" and non-scaling-stroke for consistent
  line thickness
- Position zone SVG overlay inside imageFeed container via JS to align
  with image only (not status bar)
- Support array of zone IDs in Monitor::getStreamHTML zones option
- Update monitor resize handler: percentage coords don't need rescaling,
  only threshold pixel counts are adjusted
- Add 8 Catch2 unit tests for ParsePercentagePolygon

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 18:19:20 -05:00
Isaac Connor
47edcca6ab fix: fall back to pixel parsing when zone Units=Percent but coords exceed 100
When zones have Units='Percent' in the database but their Coords contain
pixel values (>100), ParsePercentagePolygon treats them as percentages,
causing wild scaling (e.g., 639% * 1920 / 100 = 12269) followed by
clamping to monitor bounds, producing degenerate full-frame zones.

Add a pre-check in Zone::Load that scans coordinate values before calling
ParsePercentagePolygon. If any value exceeds 100, log a warning and use
ParsePolygonString (pixel path) instead. Also add unit tests for both
ParsePolygonString and ParsePercentagePolygon.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 18:16:55 -05:00
Isaac Connor
2e2e9576ac refactor: move format_absolute_time_iso8601 from zm_monitor_onvif to zm_time
Move the ISO 8601 time formatting function to zm_time.cpp/h so it is
reusable and not duplicated. Remove the local copies from
zm_monitor_onvif.cpp (was static) and tests/zm_onvif_renewal.cpp
(was a copy for testing). Both now use the shared declaration from
zm_time.h.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 16:53:39 -05:00
Isaac Connor
334994bd3f Fix appending %% instead of % when uri decoding. Add test for URIEncode 2026-02-04 20:45:46 -05:00
Ben Dailey
2dc48e4335 feat: add per-topic alarm expiry using PullMessagesResponse TerminationTime
Cameras like Reolink send alarm=true but never send the corresponding
false, causing alarms to stick indefinitely. Use the TerminationTime
from PullMessagesResponse to auto-expire stale per-topic alarms.

- Add AlarmEntry struct with value and termination_time fields
- Extract TerminationTime from each PullMessagesResponse and attach
  it to alarm entries; refresh on re-trigger so active alarms persist
- Sweep expired alarms after processing messages and on poll timeout
- Add expire_alarms option (default: true) to disable via onvif_options
- Fix TOCTOU race: remove unsynchronized alarms.empty() check before
  acquiring mutex in the timeout sweep path
- Simplify SetNoteSet with C++17 structured bindings
- Add Catch2 tests for alarm expiry logic (mirrored struct to avoid
  gSOAP header dependency)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 05:52:31 -05:00
copilot-swe-agent[bot]
d905753b5e test: add ISO 8601 formatting tests for ONVIF absolute time renewal
Co-authored-by: connortechnology <925519+connortechnology@users.noreply.github.com>
2026-01-13 04:02:21 +00:00
copilot-swe-agent[bot]
e62f0c0e4e feat: add ONVIF subscription cleanup to prevent leaks
Add cleanup_subscription() helper method that properly unsubscribes
from ONVIF cameras with error handling. This prevents subscription
leaks when renewals fail or when restarting subscriptions.

Changes:
- Add cleanup_subscription() method to header and implementation
- Call cleanup on renewal failures in Renew()
- Call cleanup when start() detects existing soap context
- Improve destructor logging for unsubscribe failures
- Add test documentation for cleanup behavior

Refs: ONVIF subscription leak issue

Co-authored-by: connortechnology <925519+connortechnology@users.noreply.github.com>
2026-01-11 14:30:50 +00:00
copilot-swe-agent[bot]
8f2799f0de Implement ONVIF subscription renewal optimization with time tracking
- Add subscription_termination_time and next_renewal_time tracking to ONVIF class
- Add update_renewal_times() helper method to parse and store termination times
- Initialize renewal tracking in constructor
- Capture TerminationTime from CreatePullPointSubscriptionResponse
- Update times after successful Renew operations
- Implement conditional renewal logic in WaitForMessage() to only renew 10 seconds before expiration
- Add unit tests for renewal timing logic

This reduces unnecessary ONVIF traffic by only renewing subscriptions when needed,
following ONVIF specification best practices.

Co-authored-by: connortechnology <925519+connortechnology@users.noreply.github.com>
2026-01-09 19:36:34 +00:00
Isaac Connor
44e47c975f Update to Catch2 v3 2024-05-08 14:16:05 -04:00
Isaac Connor
365830a9ae Rough in remove_password function + tests 2022-07-04 09:53:50 -04:00
Isaac Connor
c3d7c306fc Add tests for mask_authentication 2022-04-18 13:33:22 -04:00
Peter Keresztes Schmidt
46155942c1 Misc: Rename namespace ZM to zm
We had a mixture of both spellings. Unify it according to our code-style.
2021-06-06 19:11:11 +02:00
Peter Keresztes Schmidt
9a983bb321 Crypto: Implement SHA1 hashing 2021-05-30 22:56:21 +02:00
Peter Keresztes Schmidt
d2932b5d68 Utils: Add a ByteArrayToHexString helper 2021-05-30 22:53:05 +02:00
Peter Keresztes Schmidt
2bda413698 Crypto: Implement a generic hashing API
Currently MD5 is implemented
2021-05-30 22:53:05 +02:00
Peter Keresztes Schmidt
9900fc1273 tests/Font: Avoid lambda capture initialization
Remove the use of this language feature until we raise the requirements to C++14.
2021-05-24 00:55:46 +02:00
Peter Keresztes Schmidt
298415fff3 Remove remaining usages of VLAs 2021-05-17 22:12:04 +02:00
Peter Keresztes Schmidt
b1de220958 Polygon: Perform clip operation on existing object instead of returning a new clipped one 2021-05-16 19:42:41 +02:00
Peter Keresztes Schmidt
29488900a1 Box: Make range calculations mathematically correct 2021-05-16 19:41:45 +02:00
Peter Keresztes Schmidt
3c85d63655 Polygon: Implement clipping to a boundary box
Using the Sutherland-Hodgman algorithms convex and concave subject polygons can be clipped
by convex clip polygons.
For now we only need clipping to rectangles (Box), so limit our implementation to that. If needed this can be
trivially extended to convex clip polygons (a check whether the clip polygon is actually convex has to be added).
If convex clip polygons are needed we have to switch to e.g the Vatti algorithm.
2021-05-16 19:41:45 +02:00
Peter Keresztes Schmidt
c2a7f7b593 tests/Box: Add unit tests 2021-05-16 16:42:58 +02:00
Peter Keresztes Schmidt
e6c159fb70 Vector2: Make coordinate components public
The components were already unconditionally/without side-effects writable. Let's make them public so we don't need the setters.
2021-05-16 16:42:58 +02:00
Peter Keresztes Schmidt
707700e24e Vector2: Add unit tests 2021-05-14 20:14:50 +02:00