From a50f535238216db487cd2191cd4005a42c82c168 Mon Sep 17 00:00:00 2001 From: patrykorwat Date: Fri, 21 Aug 2026 09:38:17 +0000 Subject: [PATCH] fix(axelera): no keep-alives while a real frame is outstanding Keep-alive zeros injected during a pending request queue in the SDK pipeline ahead of the real frame and delay its result by one slot each: observed 3 s real-frame latency with 1 s keep-alive spacing vs 14 ms for back-to-back real frames (and 10 ms delivered by the FIFO path). The feeder now skips keep-alives whenever a request id is still outstanding, so real frames are processed back-to-back and true-idle behaviour (stream kept alive) is preserved. --- frigate/detectors/plugins/axelera.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/frigate/detectors/plugins/axelera.py b/frigate/detectors/plugins/axelera.py index d83a8629e5..2c6d981ede 100644 --- a/frigate/detectors/plugins/axelera.py +++ b/frigate/detectors/plugins/axelera.py @@ -198,7 +198,8 @@ class _AxeleraInference: self._frame_q: queue.Queue = queue.Queue(maxsize=64) self._cond = threading.Condition() # request ids a caller is still waiting on (guarded by _cond); the pump - # only delivers results whose decoded token is in this set + # only delivers results whose decoded token is in this set. The feeder + # also uses it as the "real frame outstanding" signal. self._waiting: set = set() self._results: dict[int, np.ndarray] = {} self._next_id = 0 @@ -241,9 +242,17 @@ class _AxeleraInference: try: frame_id, frame = self._frame_q.get(timeout=1.0) except queue.Empty: - # keep-alive: no request pending, keep the SDK stream fed so the - # inference timeout never kills it during quiet periods. The - # None id means this frame's result is dropped by the pump. + # A real frame may be outstanding: do NOT inject a keep-alive in + # that window, otherwise the zeros queue in the SDK pipeline + # ahead of the pending frame and delay its result by one slot + # per keep-alive (observed: 3 s real-frame latency under 1 s + # keep-alive spacing vs 14 ms for back-to-back real frames). + with self._cond: + if self._waiting: + continue + # truly idle: keep the SDK stream fed so its inference timeout + # never kills it during quiet periods. The None id means this + # frame's result is dropped by the pump. frame_id, frame = None, np.zeros( (self._height, self._width, 3), np.uint8 )