From ef540d88cb59198076a7e176c65b42600609f894 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Mon, 12 Oct 2026 06:15:26 -0500 Subject: [PATCH] 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. --- frigate/util/image.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/frigate/util/image.py b/frigate/util/image.py index 1d99ea7cd5..35d516ed4e 100644 --- a/frigate/util/image.py +++ b/frigate/util/image.py @@ -990,7 +990,13 @@ class FrameManager(ABC): pass @abstractmethod - def get(self, name: str, timeout_ms: int = 0): + def get( + self, name: str, shape: tuple[int, ...], frame_time: float | None = None + ) -> np.ndarray | None: + pass + + @abstractmethod + def frame_times(self, camera: str) -> np.ndarray | None: pass @abstractmethod @@ -1099,8 +1105,22 @@ class SharedMemoryFrameManager(FrameManager): ) def get( - self, name: str, shape, frame_time: float | None = None + self, name: str, shape: tuple[int, ...], frame_time: float | None = None ) -> np.ndarray | None: + """Map a frame slot as an array without copying it. + + The array points into shared memory, so it is only valid until the next + close(), delete(), or get() of the same name. Copy it to keep it longer. + + Args: + name: Slot name, such as front_door_frame3 + shape: Array shape, which must match the slot's size + frame_time: Time of the frame the caller was told is in the slot + + Returns: + The frame, or None when the slot is missing, the wrong size, or holds + a different frame than frame_time + """ if frame_time is not None and not self._holds(name, frame_time): # a mapping left over from a same-size recreate of the camera # looks the same as a lapped slot, so reopen by name once