Evidence clip export: concatenates the segments overlapping a time range and trims to
the requested window with -c copy (no re-encode). Keyframe-aligned (Stage 0 precision).
Network discovery: scan an IPv4 range / CIDR for cameras (open RTSP), then identify each by
probing a list of vendor RTSP paths with one or more credential sets (via ffprobe). Vendor-
agnostic: HikVision, Dahua, Axis, and generic/ONVIF paths are all tried. Optionally auto-
registers verified devices (recording disabled by default).
Health monitor: downgrades cameras that claim to be recording but have stopped producing
segments (a stalled-but-connected stream), emitting an event on the transition.
Timeline indexer: periodically scans each camera’s recordings directory, turning closed
segment files into rows in the segments table (the timeline index) and detecting gaps.
Live-view gateway integration: registers a camera’s stream as a MediaMTX path (server-side,
credentials never exposed to the browser) and returns HLS / WebRTC / RTSP playback URLs.
Alert notifier: delivers new warning/critical events to a configured webhook (POST JSON).
The delivery cursor is persisted (survives restarts, so events generated during downtime are
still delivered); retryable failures (5xx / 429 / network) do not advance the cursor.
main only supervises this task when a webhook is configured, so the no-webhook path returns
once without a respawn storm.
Recorder supervisor: one FFmpeg process per camera, recording the configured stream
into time-segmented fragmented-MP4 files with -c copy (no decode). Supervises the
process, reconnects with backoff on stream loss, and maintains live camera status.
Retention sweeper: deletes recordings past each camera’s age policy, and enforces a global
size cap by pruning the oldest unlocked segments. Locked (evidence) segments are never deleted.
AI frame sampler (Stage 2): for each (camera, stream_profile) that has an enabled AI task, decode
that stream at a budgeted frame rate and write the latest frame to frames/<cam>/latest_<profile>.jpg
(atomic rename, so readers never see a torn JPEG). AI workers pull frames on their own cadence.
A global FPS budget is shared across samplers, and the number of concurrent decoders is capped, so
adding AI cameras degrades gracefully instead of overloading the host (backpressure). AI workers
never touch RTSP directly — they consume sampled frames + post detections back.
Storage / disk observability: free space on the recordings filesystem (via statvfs), the
recordings footprint, and a projected retention horizon from the recent write rate.
Zone engine (Stage 3): evaluates tracked detections against per-camera polygon zones and raises
enter / exit / dwell events (with an evidence frame). State is keyed per (camera, zone, track),
held in memory, and driven by SERVER time (never the worker-supplied timestamp), so a skewed
worker clock cannot corrupt or evict state. A small confirm-frame debounce suppresses boundary
jitter, and a track still inside when its state expires gets a synthesized exit. Fed
synchronously from detection ingest.