- QML owns presentation and user intent. It does not persist secrets.
SystemControllercoordinates camera models, state, discovery and device services.GstPlayerowns one playback pipeline per visible camera. Analytics consumes the same decoded frames instead of opening a second RTSP session.- Each camera has at most one dedicated recorder. It remuxes the compressed camera stream to MP4 and finalizes it with EOS.
AnalyticsEngineschedules inference, evidence capture and the SQLite analytics event store.
GstPlayer exposes idle, connecting, streaming, reconnecting and authentication-error states. Network failures use a 1, 2, 4, 8, 16, 30 second bounded backoff. Thirty stable frames reset the attempt counter. A frame watchdog detects pipelines that remain alive but stop producing video. HTTP/RTSP authentication errors do not create an infinite retry loop.
The grid prefers SD for normal multi-camera viewing, switches to HD for fullscreen or analytics, and falls back to SD when HD fails. Credentials are injected into an in-memory URL immediately before pipeline creation.
Manual and analytics-triggered recording share a single recorder state machine, so they cannot open two competing HD recording sessions. If an event owns the recorder, a manual request is queued until the event MP4 is finalized. If a manual recording is already active, analytics writes the event from its decoded pre/post-event frame buffer to the event's original path. Direct stream recordings retain camera audio; the buffered fallback is video-only.
Application state is stored in state.sqlite3 using WAL-capable SQLite and explicit schema_migrations. Updates use a database transaction and a singleton app_state record. On first run after an upgrade, valid legacy state.json data is imported, credential fields are removed, and the plaintext legacy files are deleted after the database commit succeeds.
Analytics events use a separate indexed SQLite store so high-volume event history does not rewrite application state.
MajesticClientis a schema-driven OpenIPC device service. It discovers the live Majestic configuration/schema, flattens supported fields for QML, creates minimal nested patches, validates them against the camera schema, redacts sensitive diffs, and owns runtime commands, metrics and backup I/O. Older firmware withoutconfig.schema.jsonis exposed read-only rather than guessed.NetworkDiscoveryServicecombines official OpenIPC mDNS markers, ONVIF WS-Discovery and bounded Majestic/WebUI/RTSP probing. Candidates carry confidence and evidence and are merged with Dahua SDK results by IP.CameraOnboardingParseracceptsopenipc://and RTSP QR payloads without embedding credentials in persisted URLs.ModelArtifactVerifieris the trust boundary for downloaded inference artifacts.ReconnectPolicyis independent of GStreamer and unit tested.