From bc06b8c753844a92b76a0615d0f4c195d3e6f59b Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Sun, 11 Oct 2026 22:01:58 -0500 Subject: [PATCH] run opencv single threaded in camera tracking processes (#24640) OpenCV's default thread pool is sized to every core, and its idle threads spin while it works on the small motion frames and detection regions in each camera tracking process. On a 16 thread machine replaying 720p clips at 5 fps, tracking CPU dropped from 27-50 ms to 5-8 ms per frame with identical output and no change in wall time. Frames from ffmpeg are now also read directly into shared memory with readinto(), which skips one copy per frame. --- frigate/video/detect.py | 5 +++++ frigate/video/ffmpeg.py | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/frigate/video/detect.py b/frigate/video/detect.py index d1048e4270..f55c1c9635 100644 --- a/frigate/video/detect.py +++ b/frigate/video/detect.py @@ -144,6 +144,11 @@ class CameraTracker(FrigateProcess): def run(self) -> None: self.pre_run_setup(self.log_config) + + # OpenCV only sees small images here, and its default per-core thread + # pool burns ~5x the CPU of running them inline + cv2.setNumThreads(1) + frame_queue = self.camera_metrics.frame_queue frame_shape = self.config.frame_shape diff --git a/frigate/video/ffmpeg.py b/frigate/video/ffmpeg.py index c4364f8d71..16e3afcdb5 100644 --- a/frigate/video/ffmpeg.py +++ b/frigate/video/ffmpeg.py @@ -79,7 +79,8 @@ def capture_frames( frame_name = f"{config.name}_frame{frame_index}" frame_buffer = frame_manager.write(frame_name) try: - frame_buffer[:] = ffmpeg_process.stdout.read(frame_size) + if ffmpeg_process.stdout.readinto(frame_buffer) != frame_size: + raise EOFError("incomplete frame") except Exception: # shutdown has been initiated if stop_event.is_set():