mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-11-01 19:30:33 +03:00
c172db9fa4a196c88d25c68cacdbf1dcef0f8cf9
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ff9eb8f184 |
Keep frame shared memory mapped (#24644)
* keep frame shm open and skip overwritten frames
Every reader closed and reopened a frame's shared memory segment on each frame, so each process paid a page fault on every page of a fresh mapping (about 760 for a 1080p frame) per frame. Readers now keep segments mapped. Capture stamps each slot's frame time in a per-camera `{camera}_frame_times` segment, and `get()` returns None when the slot no longer holds the requested frame, reopening once by name so a mapping left over from a same-size camera recreate heals itself. Capture also reuses a slot when the frame queue is full, since no reader was told about it.
* verify the frame for embeddings object updates
Tracked object events only carried the object's own frame_time, which stays at its last detection when the object isn't detected in a frame, so embeddings couldn't check the slot it read and could crop face or plate data from a frame that had already been overwritten. Events now carry the time of the frame they name, and embeddings passes it to `get()`.
* log when a frame slot was overwritten before it was read
A lapped read and a missing segment ended up as the same debug line at every caller, so there was no way to tell a slow reader from a missing frame.
* bring the FrameManager interface in line with its implementation
The abstract get() still had a timeout_ms signature from an older implementation and frame_times() wasn't declared, though capture and detect are typed against the interface. get() also didn't say how long the array it returns stays valid.
* drop a camera's cached frame mappings when it is removed or recreated
A reader that kept its mappings open stayed on a removed camera's segments, which pinned their shared memory until restart, and after a same-size recreate the ledger reopen only refreshed the slot being read while the other cached slots still returned the old camera's pixels. Readers now drop every cached slot for a camera on its remove update, and get() does the same when a ledger mismatch turns out to be a replaced ledger rather than a lapped slot.
* match a camera's frame names exactly in close_camera
The prefix match on `{camera}_frame` also caught another camera whose name starts with it, so removing `cam` dropped the cached ring of a camera named `cam_frame`.
|
||
|
|
3a09d01bbe |
Debug replay resolution (#23287)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* unlink shm frames when camera is removed * drop stale shm cache refs when cached segment is too small for requested shape * skip new-object frame cache write when current_frame is unavailable * add tests * use setdefault when adding a new camera Multiple subscribers in the same process each unpickle the ZMQ payload independently and would otherwise write divergent Python objects to the shared cameras dict — leaving long-lived references (e.g. CameraState.camera_config) pointing at a copy that subsequent in-place mutations like apply_section_update can never reach. setdefault collapses everyone onto the first writer's object so attribute mutations propagate to every consumer in this process. * rebuild ffmpeg commands on detect update Rebuild the cached ffmpeg cmd so the next process spawn picks up new resolution/fps. Running cameras keep their existing cmd (ffmpeg_cmds is only read at process startup); replay cameras are recycled by CameraMaintainer to pick up the rebuilt cmd * drop stale shm cache refs when cached segment size doesn't match requested shape The cached SharedMemoryFrameManager reference can point at a segment whose size no longer matches the requested shape — the segment was unlinked and recreated at a different size in a camera add/remove cycle. This catches both a resolution increase (cached too small) and a decrease (cached too large, pointing at an orphaned inode whose stale bytes would otherwise be misinterpreted at the new shape, producing distorted/miscolored YUV frames). After reopening, if the OS-level segment still doesn't match the requested shape we're in a transient mid-recreate state — either the maintainer hasn't allocated the new segment yet (size too small) or we opened a pre-recycle segment (size too big). Either way, skip the frame and don't cache the mismatched ref. * recycle replay camera on detect update * discard tracked-object state when detect resolution changes mid-session When detect resolution changes mid-session every tracked object we hold was localized against the old pixel grid. Their boxes no longer correspond to anything in the new frame, and the `end` callback that fires when their IDs disappear from the new detect process's detections publishes those stale boxes to consumers (LPR, snapshot crop) that slice the new frame and crash on empty arrays. Drop the tracked-object state on a shape change so no stale boxes ever cross the CameraState boundary. Belt-and-suspenders: also drop any incoming batch whose boxes exceed the current detect resolution. These are in-flight queue entries from the pre-recycle detect process that beat the new detect process to the queue; processing them would re-introduce stale-resolution tracked objects we just dropped above. The per-camera detect process clamps legitimate boxes to detect.width-1 / detect.height-1, so any coord beyond that is unambiguously stale. * rebuild motion and object filter masks on detect resolution change Apply the detect update first so frame_shape reflects the new resolution before we rebuild dependents. Motion's rasterized_mask is sized to frame_shape at construction. When detect resolution changes we must rebuild RuntimeMotionConfig so the mask matches the new frame size; otherwise consumers like the LPR processor and motion detector hit a shape mismatch when they index frames with the stale mask. Same story for per-object filter masks — rebuild RuntimeFilterConfig at the new frame_shape so the merged global+per-object masks they hold match what they'll be indexed against. * republish motion and objects on in-memory detect resize A detect resolution change also invalidates the rasterized masks on motion and per-object filters. apply_section_update has rebuilt them at the new frame_shape; publish them too so other processes replace their old values. * add test * frontend * add refresh topic for camera maintainer recycle action The maintainer's recycle branch is doing an action (recycle the camera) in response to a section-level signal. Introduce a CameraConfigUpdateEnum.refresh case as an explicit action signal — the maintainer subscribes to refresh instead of detect, parallel with add and remove. Publishers fire refresh alongside detect when a recycle is needed; section-level subscribers keep their existing topic. Since no main-process subscriber listens for detect anymore, the refresh handler calls recreate_ffmpeg_cmds() explicitly so the shared CameraConfig's ffmpeg_cmds is rebuilt before the new subprocesses spawn. * factor stale-resolution state drop into a CameraState method |