Commit Graph

27125 Commits

Author SHA1 Message Date
Isaac Connor
ca22ae3737 Remove fatal version check. Just error. 2026-02-12 16:53:29 -05:00
Isaac Connor
8b3ed97fa4 perf: auto-vectorize alarmedpixels loop for SIMD on all platforms
Restructure std_alarmedpixels inner loop so GCC/Clang can auto-vectorize
it at -O2/-O3. The compiler now emits 16-byte SIMD (SSE2/NEON) processing
16 pixels per iteration instead of 1.

Three changes enable this:
- Extract inner loop into static alarmedpixels_row() with __restrict__
  on function parameters, giving the compiler a strong no-alias guarantee
- Use branchless bitwise AND instead of short-circuit && to avoid
  branches that block vectorization
- Remove per-row Debug(7) call that clobbered memory from the compiler's
  perspective, invalidating pointer analysis

The original hand-written SSE2 ASM (removed in 2011, commit 8e9ccfe1e)
had alignment restrictions and didn't use per-row polygon ranges. This
approach is portable, maintainable, and achieves equivalent throughput.

GCC confirms: "loop vectorized using 16 byte vectors"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 14:36:13 -05:00
Isaac Connor
bf185cf4b4 fix: replace global include_directories with target_include_directories
Replace 13 global include_directories() calls with list(APPEND
ZM_INCLUDE_DIRS ...) in root CMakeLists.txt, then apply them scoped
to the zm static library target via target_include_directories() in
src/CMakeLists.txt.

Previously all library include paths (MySQL, OpenSSL, curl, zlib, JPEG,
pthread, PCRE, VLC, VNC, libunwind, GnuTLS, Mosquitto) leaked into
vendored deps (RtspServer, CxxUrl, bcrypt). Now only the zm target and
its dependents see them.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 13:32:23 -05:00
Isaac Connor
7df902abdc fix: resolve "no url in button" when adding detected cameras
- Provide default rtsp://<ip>/ monitor entry for cameras discovered
  via ARP that lack a vendor-specific probe function, so they always
  have a URL for the Add button
- Only render the Add button and populate ProbeResults when url is
  non-empty, preventing the "No url in button" alert
- Fix curl_getinfo() called after curl_close() which broke HTTP
  response body parsing in probe functions
- Add missing break in import switch case to prevent fall-through
  to default warning

maybe fixes #4613

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 12:55:32 -05:00
Isaac Connor
56a9c53948 fix: scope add_definitions to zm target with target_compile_definitions
Replace global add_definitions(-DWITH_GSOAP) and add_definitions(-DZM_STRIP_NEON=1)
with target_compile_definitions on the zm static library target. These defines are
only consumed by src/ files but were leaking into all vendored deps (RtspServer,
CxxUrl, bcrypt, etc).

WITH_GSOAP is PUBLIC on zm since the executables linking zm include headers
that check it. ZM_STRIP_NEON is PRIVATE since it's only used in zm_image.cpp.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 12:52:10 -05:00
Isaac Connor
c250eadcea fix: use ${PERL_EXECUTABLE} instead of hardcoded perl in CMake builds
Replace 4 hardcoded `perl` invocations with `${PERL_EXECUTABLE}` from
find_package(Perl) so builds work when perl isn't in PATH or the wrong
perl would be found (NixOS, custom installs, Homebrew vs system).

Also: fix ZMCONFGEN_RESULT variable case mismatch in error message,
remove deprecated IMMEDIATE keyword from configure_file(), bump
cmake_minimum_required from 3.5 to 3.12 (C++17 requires 3.9+), and
remove dead C++11 fallback for CMake < 3.8 in ConfigureBaseTargets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 12:25:37 -05:00
Isaac Connor
215d566658 refactor: condense AGENTS.md from 1733 to 335 lines (74% smaller)
Remove redundant sections (Quick Command Reference, duplicate workflow
examples, triplicate pre-commit checklists), discoverable reference
material (full directory tree, dependency install commands, platform
notes), and human-only content (learning resources, identified gaps).

Add "why" comments explaining rationale for key rules (out-of-source
builds, conventional commits, no superlatives, prepared statements,
.in templates, shared memory architecture). Add condensed directory
structure and contributing links for human readers.

All behavioral rules and mandatory instructions preserved.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 09:39:49 -05:00
Isaac Connor
c12e5ec607 Fix missing br after recording function. Move onvif out of recording function block. 2026-02-12 09:16:39 -05:00
Isaac Connor
8b46844838 Handle no canvas more gracefully. THere is no graph canvas when in live mode 2026-02-11 22:36:12 -05:00
Isaac Connor
56588939e7 Make clearPackets return false if it can't remove any packets. So that we try again even if we aren't looking at a keyframe. 2026-02-11 22:35:50 -05:00
Isaac Connor
f90c4a4d35 Add timeout when waiting for zmc. Fixes 620 2026-02-11 22:35:00 -05:00
Isaac Connor
4a730d6934 fix: remove vulnerable phpunit dev dependency (CVE-2026-24765)
Remove phpunit/phpunit from require-dev in web/api/composer.json.
The pinned ^3.7 version is vulnerable to unsafe deserialization in
PHPT code coverage handling. Since ZoneMinder does not run CakePHP
unit tests in CI, the dependency is unused.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 21:59:03 -05:00
Isaac Connor
874f43b198 feat: add --local-source option to do_debian_package.sh
Allow specifying a local git directory to clone from without pulling it
first. Accepts -l=DIR / --local-source=DIR flag or a trailing positional
argument that is an existing directory. Skips all git pull operations on
the source, using the directory contents as-is.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 20:12:25 -05:00
Isaac Connor
2b88db632f Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-02-11 17:43:13 -05:00
Isaac Connor
d5b4709584 fix: reduce packet queue backpressure from event thread blocking
Three changes to prevent the analysis thread from stalling and the
packet queue from filling up:

1. Replace blind sleep_for/usleep in Event::Run() with
   packetqueue->wait_for() condition variable waits. The event thread
   now wakes immediately when decoder/analysis completes or new packets
   are queued, instead of always sleeping the full 33ms/10ms.

2. Add missing packetqueue.notify_all() calls after setting
   packet->analyzed (Monitor::Analyse) and packet->decoded
   (DECODING_NONE path in Monitor::Capture) so the event thread's
   condition waits actually get signaled.

3. Replace synchronous zmDbDoUpdate() calls in Event::~Event() with
   async dbQueue.push(). The two Events UPDATE queries (with Name
   fallback logic) are combined into a single query using MySQL IF().
   This eliminates blocking DB I/O from the close_event_thread, which
   the analysis thread joins on the next closeEvent() call.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 17:17:45 -05:00
Isaac Connor
6db96f2f14 Merge pull request #4615 from nabbi/revert-4611-perf-skip-ffmpeg-open-savejpegs
Revert "perf: skip FFmpeg video probe for JPEG-based event streams"
2026-02-10 21:11:19 -05:00
nic
d91556e1ff Revert "perf: skip FFmpeg video probe for JPEG-based event streams" 2026-02-10 20:08:48 -06:00
Isaac Connor
9175f49208 Merge pull request #4614 from IgorA100/patch-304697
Moved the "replaceDOMElement" function from "MonitorStream.js" to "skin.js"
2026-02-10 14:28:10 -05:00
IgorA100
d15febf205 Moved the "replaceDOMElement" function to "skin.js" (MonitorStream.js) 2026-02-10 22:15:48 +03:00
IgorA100
5845f15b1f Moved the "replaceDOMElement" function from "MonitorStream.js" (skin.js) 2026-02-10 22:08:04 +03:00
Isaac Connor
347d160836 Merge pull request #4593 from IgorA100/patch-317546
Fix: Run ".setPlayer" (set the default monitor player) when starting monitor on the Montage page
2026-02-10 13:41:12 -05:00
Isaac Connor
368affc08e Merge pull request #4591 from IgorA100/patch-955784
Fix: More correct logic for #volumeSlider processing & Improved functionality for RTSP2web, Janus, and ZMS
2026-02-10 12:55:09 -05:00
Isaac Connor
a888a09121 Merge pull request #4612 from IgorA100/patch-615390
Fix: Bootstrap-table info class ".fixed-table-loading" creates a scrollbar (skin.css)
2026-02-10 12:47:24 -05:00
IgorA100
6ff3e2b3cc Fix: Bootstrap-table info class ".fixed-table-loading" creates a scrollbar (skin.css) 2026-02-10 19:29:43 +03:00
Isaac Connor
c9196e8fd5 Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-02-10 09:38:03 -05:00
Isaac Connor
9a2e9a8600 fix: fall back to CameraDirectPrimary when RTSPServer is disabled
When StreamChannel is set to Restream, the JS maps it to the
_ZoneMinderPrimary go2rtc stream. However, that stream is only
registered when RTSPServer is enabled on the monitor. Fall back
to _CameraDirectPrimary when RTSPServer is not enabled.

Pass RTSPServer property through monitorData in all views so the
JS can check it at stream selection time.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 09:32:24 -05:00
Isaac Connor
30e1795dc2 Merge pull request #4610 from nabbi/perf-zone-checkalarms-image-reuse
perf: reuse diff image buffer in Zone::CheckAlarms
2026-02-10 09:28:29 -05:00
Isaac Connor
e38e78d1f3 fix: always render monitorStatus HTML in montage view
The monitorStatus HTML was conditionally omitted based on
ZM_WEB_COMPACT_MONTAGE, leaving the status position dropdown
with no elements to operate on. Always render the HTML and
use the dropdown's hidden option to handle compact montage
instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 09:26:34 -05:00
Isaac Connor
c10ce94ec1 Merge pull request #4611 from nabbi/perf-skip-ffmpeg-open-savejpegs
perf: skip FFmpeg video probe for JPEG-based event streams
2026-02-10 09:15:21 -05:00
Isaac Connor
6c949d79ba Merge pull request #4608 from nabbi/fix-montage-rate-on-load
fix: preserve maxfps when MonitorStream.start() rebuilds stream URL
2026-02-10 09:14:11 -05:00
Nic Boet
f77ca859ed perf: skip FFmpeg video probe for JPEG-based event streams
When SaveJPEGs is enabled, sendFrame() reads JPEG files directly from
disk and never touches the FFmpeg input. However, loadEventData()
unconditionally called FFmpeg_Input::Open() on the event video file,
which runs avformat_find_stream_info() — a 2-5 second probe that was
pure overhead for JPEG-based streaming.

Gate the Open() call on !(SaveJPEGs & 1) so the expensive probe is
only performed when frame extraction from the video container is
actually needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 23:14:55 -06:00
Nic Boet
5fde4e5deb perf: reuse diff image buffer in Zone::CheckAlarms
Replace delete/new Image cycle with lazy-alloc + Assign(). When the
buffer already exists (every frame after the first), Assign() detects
matching dimensions and does a plain memcpy into the existing
allocation, eliminating an aligned malloc+free of ~2 MB per zone per
analyzed frame.

With 4 zones at 15 fps this removes 60 alloc/free cycles per second
from the analysis hot path. The HighlightEdges code path (analysis
images) still allocates a new Image and deletes the old diff buffer,
which is correct — the next Assign() will reallocate once to restore
the single-channel format, then resume reuse.

Behaviorally equivalent: Zone dimensions are constant during zone
lifetime, the destructor already handles cleanup via delete image,
and the only external consumer (Monitor::Analyse → AlarmImage →
Overlay) reads the image without storing pointers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 19:25:58 -06:00
Nic Boet
5393c626c5 fix: preserve maxfps when MonitorStream.start() rebuilds stream URL
start() reconstructs the zms URL from url_to_zms, which only contains
the monitor id. Parameters like auth, connkey, scale, and mode are
carried over, but maxfps was dropped. This causes streams to start at
the camera's native capture rate even when PHP rendered the initial
<img src> with a maxfps value (e.g. from the montage Rate cookie).

Carry over maxfps from the existing src the same way the other
parameters are preserved.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 18:42:44 -06:00
Isaac Connor
df88c7317e Fix eslint 2026-02-09 17:54:37 -05:00
Isaac Connor
f7ececbf83 Merge pull request #4607 from nabbi/event-playback-fixes-master
Fix event playback stability and optimize seek performance
2026-02-09 17:44:05 -05:00
Isaac Connor
f6c59d3759 Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-02-09 17:41:59 -05:00
Isaac Connor
02ed1b15d7 fix: correct seek threshold in FFmpeg_Input::get_frame to avoid sequential scan
The jump-ahead heuristic used 10*time_base.den*frame->duration which for
a typical stream (time_base=1/90000, 30fps duration=3000) produced a
threshold of ~30000 seconds, effectively never triggering. This caused
large seek jumps to decode every intermediate packet sequentially.

Replace with av_rescale_q-based 5-second threshold that correctly
converts to stream time_base units regardless of the time_base format.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 17:38:14 -05:00
Isaac Connor
f170826a68 Merge pull request #4605 from nabbi/perf-conditional-framesduration-subquery
perf: skip Frames table scan during event playback unless debugging
2026-02-09 17:03:05 -05:00
Isaac Connor
b62285b90b fix: null-check mAudioStream before dereferencing in FfmpegCamera::Capture
When mSecondFormatContext is set but no audio stream was found during
PrimeCapture, mAudioStream is null. Dereferencing mAudioStream->time_base
causes a segfault (SIGSEGV at fault address 0x20). Add mAudioStream to
the condition check, consistent with the existing null guard on line 172.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 15:57:22 -05:00
Isaac Connor
fd7df97469 Merge branch 'master' of github.com:connortechnology/ZoneMinder 2026-02-09 15:24:14 -05:00
Nic Boet
4b098fb760 perf: replace O(n) linear frame seeks with O(log n) binary search
Replace two linear scans in event playback seeking:

- seek(): O(n) walk from frame 0 replaced with std::lower_bound on
  timestamp. Falls back to last frame if target is past end.

- processCommand(CMD_SEEK): O(n) estimate-then-walk replaced with
  std::upper_bound on offset, then step back one. Handles edge cases
  where offset lands before first frame or past last frame.

For a 10-minute event at 30fps (~18,000 frames), worst case drops
from 18,000 comparisons to ~14 (log2).
2026-02-09 12:44:59 -06:00
Nic Boet
8b9d523ffa fix: recover from zms crash by restarting stream on seek or play
When zms dies (any cause), the UI sets zmsBroke=true and subsequent
seeks/plays silently fail. Instead, restart the stream by resetting
the img src, which triggers the browser to make a new CGI request to
zms with the same connkey, spawning a fresh process.

Uses img.onload as the readiness signal rather than polling: when the
new zms delivers its first MJPEG frame, onload fires, confirming the
command socket is ready. This eliminates the race window where
CMD_SEEK could be sent before the socket exists, and removes
dependency on the poll interval (streamTimeout) for seek delivery.

Implementation:
- restartZmsStream(onReady): shared helper that clears img.src to
  kill the old connection, sets a one-shot onload handler, then sets
  the new src. onload clears zmsBroke and invokes the callback.
- streamSeek(): when zmsBroke, calls restartZmsStream with a callback
  that re-invokes streamSeek(offset) once zms is alive.
- playClicked(): when zmsBroke, calls restartZmsStream with no
  callback since zms starts in play mode by default.

Consolidates duplicate restart logic that was previously inlined in
both playClicked() and streamSeek().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 12:44:56 -06:00
Nic Boet
0ca3ed3155 fix: reset keepalive timer on event-end pause to prevent connection drop
When checkEventLoaded pauses at the end of an event in MODE_SINGLE/
MODE_NONE, the main loop relies on last_frame_sent to decide when to
send keepalive frames. If last_frame_sent is stale, the loop waits up
to 5 seconds (MAX_STREAM_DELAY) before sending anything. During that
gap the HTTP connection can time out, causing SIGPIPE on the next write.

Reset last_frame_sent to epoch so the next iteration sends a keepalive
immediately.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 12:29:12 -06:00
IgorA100
09156ccf11 Change IDs for volumeControls, volumeSlider, and controlMute when looping (watch.js) 2026-02-09 20:27:46 +03:00
Isaac Connor
f407ad1321 fix: correct WSA Action for PullMessages and throttle auth error logging
WaitForMessage used WSA Action "PullMessageRequest" while Subscribe's
initial PullMessages used "PullPointSubscription/PullMessagesRequest".
The wrong action caused some cameras to return a generic "not authorized"
fault instead of a proper ActionNotSupported error. Also throttle the
auth error to log once as Error then demote to Debug on repeats.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 11:34:44 -05:00
Isaac Connor
5518f41b05 fix: cache SSL verification failure to avoid repeated warning logs
When SSL certificate verification fails for Go2RTC, RTSP2Web, or Janus
curl requests, the warning was logged on every single call. Since these
methods are called periodically, this flooded the logs. Now a
ssl_verification_failed flag is set on first failure so subsequent calls
skip verification silently. Also adds SSL verification to Janus which
previously had none.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 10:05:02 -05:00
Isaac Connor
fcfc7db0c7 Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-02-09 09:29:41 -05:00
Isaac Connor
f7858f3770 feat: add events command to zmonvif-probe.pl
Add 'events' command to check if an ONVIF camera supports the events
service. Returns "Events: yes" or "Events: no" for easy parsing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 09:29:36 -05:00
Isaac Connor
bd0482db56 Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-02-09 09:18:03 -05:00
nic
59bb0171c7 Merge branch 'ZoneMinder:master' into perf-conditional-framesduration-subquery 2026-02-09 00:23:27 -06:00