Commit Graph
192 Commits
Author SHA1 Message Date
Isaac Connor bb1b3d8dbe Take Importance into account when logging about timing out waiting for capture in monitorstream 2026-08-18 22:09:14 -04:00
Jash f5cfbcd54c fix: make MonitorStream playback state shared with the command thread atomic fixes #4939 2026-08-16 16:46:47 +05:30
Isaac ConnorandClaude Opus 4.8 7cd4be5cfb feat: add nph-zms memory diagnostics refs #5006
Add instrumentation to trace which stream type and workload precede the
occasional runaway memory growth in nph-zms.

- zm_utils: add zm_get_rss_kb() reading resident set size from
  /proc/self/statm
- zms: log a one-shot Debug summary of the decoded request (source, mode,
  monitor/event, connkey, scale, buffer, ttl, rss) so a runaway process
  can be tied to its stream parameters
- MonitorStream/EventStream: emit a periodic Debug RSS trace every 30s.
  The EventStream trace includes frames-vector size and frame_count,
  which scale with reloaded event length and will show whether the
  in-process event reload path drives the growth

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 09:48:44 -04:00
Isaac Connor 9424399ed0 Improve timed out log message to add ttl 2026-07-11 12:43:37 -07:00
Isaac Connor 356f22c9cc Warning=>Debug 2026-06-25 17:30:35 -04:00
SteveGilvarryandClaude Opus 4.8 629842c938 fix: start zms command processor after buffer state is initialised refs #4936
The command_processor thread was started in runStream() before
temp_image_buffer_count, the read/write indices and temp_image_buffer were
assigned, so a command arriving in that window observed a half-initialised
stream (the root cause behind the divide-by-zero guarded in the previous
commit). Keep the thread object declared up front for the join(), but defer
its launch until after the playback_buffer setup so processCommand can only
run against fully initialised state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 08:56:11 +10:00
Steve GilvarryandClaude Opus 4.8 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 ConnorandClaude Opus 4.8 bc15782474 fix: skip final stream sleep when zm_terminate is already set
Avoid sleeping up to MAX_SLEEP (500ms) at the end of runStream when
termination has been requested, so zms shuts down more promptly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 19:11:51 -04:00
Isaac ConnorandClaude Opus 4.8 a36375585c refactor: make zm_terminate a std::atomic<bool>
zm_terminate is written from signal handlers and read from daemon loops.
A plain bool is undefined to access from a signal handler and may be hoisted
out of a loop by the optimizer. std::atomic<bool> is lock-free on supported
platforms and matches the already-atomic per-object terminate_ flags. Update
the three Debug() vararg sites to call .load() since atomics can't pass
through ...

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 19:11:51 -04:00
Isaac ConnorandClaude Opus 4.7 6765962737 fix: nullptr-safe pixfmt name; route GetImage/getSnapshot through ReadShmFrame (PR #4788)
- Added zm_get_pix_fmt_name() in zm_pixformat.h: av_get_pix_fmt_name()
  returns nullptr for unknown formats (including AV_PIX_FMT_NONE), and
  passing nullptr to %s is undefined and can crash. Wraps with an
  "unknown" fallback. Replaced the five raw uses flagged by review
  (RemoteCameraRtsp/FfmpegCamera/VncCamera/LocalCamera constructors and
  MonitorStream::sendFrame's Debug log) with the wrapper. Each can hit
  AV_PIX_FMT_NONE before the first frame or via an unexpected
  (colours, subpixelorder) pair.
- Monitor::GetImage and Monitor::getSnapshot now route the slot read
  through ReadShmFrame so the per-slot AVPixelFormat zmc recorded is
  adopted on image_buffer[index] before its bytes are interpreted.
  Without this, the JPEG encode in GetImage and the ZMPacket returned
  by getSnapshot would interpret SHM bytes using the placeholder format
  set at attach time and produce garbled output when the slot's actual
  format differs (the contract previously relied on callers calling
  ReadShmFrame themselves). getSnapshot/GetTimestamp drop const since
  ReadShmFrame mutates image_buffer[index]; callers in this codebase
  already use a non-const Monitor pointer.
- Monitor::connect: updated the misleading "+64 bytes reserved" comment
  to match the actual reservation of 63 + (alignof(AVPixelFormat) - 1).

refs #4788

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-31 09:22:09 -04:00
Isaac Connor a7c3fb7ce6 Merge branch 'master' into fix/avpixelformat-respin 2026-05-21 21:11:40 -04:00
copilot-swe-agent[bot]andconnortechnology 03801a9e23 fix: reset step/send_twice in MonitorStream CMD_STOP; reset stopped in EventStream.js lifecycle
Agent-Logs-Url: https://github.com/ZoneMinder/zoneminder/sessions/8c14d453-7815-44fd-956a-0cda13c218f9

Co-authored-by: connortechnology <925519+connortechnology@users.noreply.github.com>
2026-05-17 12:37:39 +00:00
copilot-swe-agent[bot]andconnortechnology 1bce09f4e8 fix: address review feedback - endian decode, send_twice init, setLastViewed, curr_frame_id gating
Agent-Logs-Url: https://github.com/ZoneMinder/zoneminder/sessions/b457dcf6-616f-4df9-bc28-76640bf5dd39

Co-authored-by: connortechnology <925519+connortechnology@users.noreply.github.com>
2026-05-17 03:29:41 +00:00
copilot-swe-agent[bot]andconnortechnology 1be352c790 fix: add stopped state for CMD_STOP, fixing paused=true response bug
When CMD_STOP is sent via AJAX using ZMS MJPEG streaming, the response
was incorrectly returning paused=true instead of indicating a stopped
state (paused=false).

Changes:
- Add `stopped` boolean to StreamBase (zm_stream.h)
- MonitorStream: CMD_STOP now sets stopped=true, paused=false instead
  of paused=true; run loop skips frame sending when stopped
- EventStream: CMD_STOP sets stopped=true (was already setting
  paused=false); run loop skips frame sending when stopped
- All other play/pause commands reset stopped=false
- Both streams include stopped field in the status response struct
- stream.php unpacks the new stopped field from MSG_DATA_WATCH and
  MSG_DATA_EVENT responses
- MonitorStream.js handles stopped status in UI (shows 'Stopped' mode)
- EventStream.js tracks stopped state from server response

Fixes issue: CMD_STOP response paused=true should be paused=false

Agent-Logs-Url: https://github.com/ZoneMinder/zoneminder/sessions/ba9cb47a-a3e8-4e13-aec7-c9cd258e2a3d

Co-authored-by: connortechnology <925519+connortechnology@users.noreply.github.com>
2026-05-06 01:58:48 +00:00
Isaac ConnorandClaude Opus 4.7 c8d8cc384a feat: SHM cross-process format consistency via per-slot AVPixelFormat
The deprecated Monitors.Colours column was driving the on-disk SHM
image_buffer slot format end-to-end: zmc allocated each slot in
camera->Colours()/SubpixelOrder() shape, zms attached and built its
own per-process Image objects assuming the same shape. Anything that
wrote a different format into a slot — i.e. anything that wasn't
already RGB32 on a Colours=4 monitor — left zmc's local Image with
the new format but zms reading the bytes as RGB32. The visible
artefacts varied with the format pair (4 small images per row for
YUV420P-into-RGB32, 3 tiles for the planar-as-RGB24 fallthrough,
fully garbled colours for image_pixelformats overlapping alarm_image,
etc.) but the underlying contract was just broken — the SHM had no
representation of the per-slot format.

Make the SHM transport any format Image supports without an upfront
convert step:

- Place image_pixelformats[] correctly. mem_size already reserved
  image_buffer_count*sizeof(AVPixelFormat) at the end of the SHM
  region, but the pointer was set to shared_images +
  image_buffer_count*image_size — overlapping the alarm_image
  region. zmc's writes scribbled into alarm_image; zms read alarm
  pixel data back as enum values. Move it to
  +2*image_buffer_count*image_size, after both image regions.
- Add Monitor::WriteShmFrame(index, capture_image): no conversion,
  just Assign and record image_pixelformats[index] =
  capture_image->AVPixFormat(). Used by both the normal Decode path
  and the signal-loss path so they share the same cross-process
  format-consistency contract.
- Add Monitor::ReadShmFrame(index): the read-side counterpart. Calls
  image_buffer[index]->AVPixFormat(image_pixelformats[index]) before
  returning so other-process Image objects interpret the SHM bytes
  correctly per-frame. zm_monitorstream's image_buffer[index]
  accesses go through this accessor.
- image_buffer[i] / alarm_image: initial format is now just a
  placeholder (YUV420P), with allocation sized from
  camera->ImageSize() as the upper bound. The actual format carried
  in each slot is the one zmc wrote, recorded in image_pixelformats
  and adopted on read.

This means the typical capture pipelines run with zero sws_scale
calls in the SHM hot path:

- H.264/H.265 sw decode -> YUV420P -> identity copy via
  av_image_copy in Image::Assign(AVFrame*).
- LocalCamera/MJPEG -> RGB32 (DecodeJpeg target) -> SHM holds RGB32;
  zms reads RGB32 directly.
- H.265 hwaccel -> NV12 -> falls through to YUV420P (NV12 isn't in
  zm_pixformat) — one convert at decode time, then passthrough
  through the rest of the pipeline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 13:03:53 -04:00
Isaac Connor 8b4c93ea1f fix: bail from MonitorStream::runStream when monitor failed to load
When setStreamStart()->loadMonitor() failed (e.g. monitor id not found,
shm not yet mapped), zms continued into runStream() for non-SINGLE
stream types and dereferenced a null Monitor shared_ptr at
monitor->GetFPS(), crashing in get_capture_fps with fault address 0x618.

Bail early after the STREAM_SINGLE branch with a "Not connected" text
frame, mirroring the SINGLE-type recovery. For STREAM_JPEG, emit the
multipart Content-Type first so sendTextFrame produces a well-formed
response. Placed before openComms()/command_processor spawn so there
is no resource teardown to do on the bail path.
2026-04-30 18:11:55 -04:00
Isaac ConnorandClaude Opus 4.6 2526b9b85e feat: install SIGPIPE handler in zms for clean browser-disconnect shutdown
When a browser closes a streaming connection, fwrite to stdout raises
SIGPIPE.  Without a handler the default action terminates the process
immediately, skipping exit_zm() and leaving the DB handle and log
unclosed.

Add zm_pipe_handler that sets zm_terminate so zms falls out of its
streaming loop and exits through the normal shutdown path.  Clarify
the sendFrame comment to match.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 09:53:23 -04:00
Isaac ConnorandClaude Opus 4.6 4df2bf4f0b feat: add analysis_image field to stream status for client-side verification
Add a boolean analysis_image field to the CMD_QUERY status response that
reports whether zms is actually sending analysis images (with motion zone
overlays) or regular capture images. This lets MonitorStream.js detect
when the stream state is out of sync with what the client requested and
re-send the CMD_ANALYZE_ON/OFF command to correct it.

The field is true only when frame_type is FRAME_ANALYSIS, shared memory
is valid, and the monitor has analysis enabled — matching the same
condition used to select the image in the streaming loop.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 15:44:49 -04:00
copilot-swe-agent[bot]andconnortechnology 2dfb79975d fix: prevent segfault when MPEG stream codec fails to open
Co-authored-by: connortechnology <925519+connortechnology@users.noreply.github.com>
2026-03-05 02:15:08 +00:00
Isaac ConnorandClaude Opus 4.6 29541c9aa7 fix: prevent segfault in MonitorStream::processCommand from shared memory race
The command processor thread could crash dereferencing monitor->shared_data
or monitor->trigger_data while the main thread was in loadMonitor() calling
disconnect() which munmaps shared memory and nulls those pointers.

Three fixes:
- Guard against null monitor at the top of processCommand
- Add monitor_mutex to StreamBase, held during disconnect/connect in
  loadMonitor and during shared memory reads in processCommand, so the
  command thread cannot access shared memory while it is being remapped
- Initialize status_data.analysing and status_data.score in the
  !ShmValid branch where they were previously sent uninitialized

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 18:19:20 -05:00
Isaac Connor f90c4a4d35 Add timeout when waiting for zmc. Fixes 620 2026-02-11 22:35:00 -05:00
Isaac Connor 0f92ad79b0 Remove debug 2026-02-05 09:07:22 -05:00
Isaac Connor 45fe630677 Spacing and improve debug 2026-02-04 22:55:50 -05:00
Isaac Connor b64520649d Use std::shared_ptr to fix memory leak due to use of GetSnapshot and not freeing the returned packet. 2026-01-20 16:18:43 -05:00
Isaac Connor 47cc713eaa Re-enable analysis image viewing 2026-01-16 16:02:19 -05:00
Isaac ConnorandClaude Opus 4.5 2f73e0591d feat: add last_analysis_viewed_time tracking for analysis image viewers
Add SharedData field and methods to track when analysis images are being
viewed, mirroring the existing last_viewed_time functionality. This allows
the analysis process to know if someone is actively viewing analysis images.

- Add last_analysis_viewed_time to SharedData struct
- Add getLastAnalysisViewed(), setLastAnalysisViewed(), hasAnalysisViewers()
- Update MonitorStream to set flag when streaming FRAME_ANALYSIS

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 10:13:23 -05:00
Isaac Connor adba371cd1 pause when we receive CMD_STOP 2025-08-07 14:39:04 -04:00
Isaac Connor 283b62a3bf Fix format string for size_t 2025-07-19 16:58:29 -04:00
Isaac Connor 4757d711ef Change various cases of int img_buffer_size to size_t 2025-07-19 14:18:32 -04:00
Isaac Connor 14d6234e57 Make frame send time a debug 2024-12-09 12:26:51 -05:00
Isaac Connor 42914b63c0 Remove unneeded initialisations and group command processor code together 2024-10-20 18:04:12 -04:00
Isaac Connor bc1a7af1fc Add analysing to monitor status stream 2024-10-02 09:30:03 -04:00
Isaac Connor 0780032149 Add score to monitorstream status 2024-10-01 16:28:56 -04:00
Isaac Connor e6f9dbae2e move image_count to shared mem. Use it in monitorstream to detect when last_write_time % buffer_count hasn't changed, but there is in fact a new image. 2024-05-21 14:53:52 -04:00
Aaron Kling c4683d90a9 Format code using astyle google format
Commands used:
astyle --style=google --indent=spaces=2 --keep-one-line-blocks src/*.cpp
astyle --style=google --indent=spaces=2 --keep-one-line-blocks src/*.h
2024-03-26 13:43:58 -05:00
Isaac Connor b87c86621a Set zm_terminate on io error 2024-02-08 14:42:08 -05:00
Isaac Connor 79ce5cf80f When monitor is Decoding==None send a more informative text image saying so. Instead of simply returning, set zm_terminate and go through the normal flow so that comms thread and db threads terminate as well. Might fixes zms hangs 2024-02-08 10:58:58 -05:00
Isaac Connor 3fe8f2f4b3 Better debug on waiting for capture to begin. Only send error image once, as we are in single image mode 2024-01-11 10:12:00 -05:00
Isaac Connor 8617c09f16 Implement new zms parameters frames= which is the # of frames to send when in streaming mode. The idea is to replicate single mode, but allowing for other intermediate images, like Waiting for Connection etc. type=single should only ever send 1 single image. 2024-01-04 11:37:49 -05:00
Isaac Connor c598f49b55 Comment out pixformat line to stop warnings 2024-01-02 16:24:44 -05:00
Isaac Connor 7a6c0e2743 Comment out unneeded debug 2023-12-19 10:54:35 -05:00
Isaac Connor c2f05911b1 Put a 1 sec wait limit on zms when in single image mode. 2023-12-03 09:15:28 -05:00
Alejandro Criado-Pérez 543683aa4c Corrections on cpp and h files 2023-08-13 01:27:19 +02:00
Isaac Connor a4c14eb890 Don't crash when not able to connect to monitor 2023-08-02 15:11:13 -04:00
Isaac Connor 01257d2ca1 Output debug the pixformat of the shm image 2023-07-21 15:09:51 -04:00
Isaac Connor 32ffee0a75 When waiting for capture, output text images saying so with a keepalive frequency 2023-06-12 09:22:16 -04:00
Isaac Connor 8676da6ead If monitor has been deleted, we won't be able to connect to it. Show an instructive jpeg and exit. 2023-05-10 13:06:09 -04:00
Isaac Connor 3f3d9cb421 Don't crash when doing single image of a monitor that isn't running 2023-04-25 10:18:37 -04:00
Isaac Connor c61d5ce341 Implement ZOOMSTOP for live monitor view 2023-04-13 12:25:08 -04:00
Isaac Connor 87f4f9afbd Add scale to status for monitorStream 2023-04-06 19:02:50 -04:00