Repository: blakeblackshear/frigate

Issue:
[Bug] skipped_fps is always 0
AFAICT, the skipped_fps is always zero. https://github.com/blakeblackshear/frigate/blob/7c1568fcb941ad17256ab73438cb997b23fb7f33/frigate/video.py#L175 is where I would expect it to get updated (next to the fps, which ends up corresponding to the camera_fps), but that line doesn't actually assign to anything, and I can't find anywhere that the skipped_fps field of camera stats structures is passed anywhere.

Additionally, showing skipped_fps in the UI on the Detect line is slightly misleading if it is intended to be the location I linked above - that would mean that _all_ processing is getting behind, not just object detection.


Discussion:
I don't think this is valid and the linked issue should not be related. There is a stark difference between what you are seeing there (high levels of motion detection causing the frame buffer to have issues) vs a detector which is slow. 

If you run on an rpi on the CPU there is absolutely skipped fps being set as expected, and it also does not affect the live view from being up to date. 
Looking through the code more, the skipped fps does not seem to be set on the system page, not sure if it was a change recently but I had done testing with skipped fps on my Pi in the past. The value would just need to be passed in to capture_camera and that would link it up I believe.

> Additionally, showing skipped_fps in the UI on the Detect line is slightly misleading if it is intended to be the location I linked above - that would mean that all processing is getting behind, not just object detection.

It might be slightly off in that the detection fps is technically object detections per second and the skipped fps would be total skipped frames, but I don't think it is misleading in the naming because it just says detection after all. 
The issue mentioned (#6861) being only tangentially related is exactly why I opened a new issue. In my case it's perfectly likely that I'm not _actually_ dropping any frames, they just keep getting queued up forever or something.

What I'm saying is I've never seen skipped_fps being non-zero, and can't find an instance of that searching through the issue tracker of other peoples stats that have been posted (granted, GitHub's searching for such a specific thing is poor at best; I just had to search for "skipped_fps" and look at issues that look like they could be load related). I'm positing that assuming frame-skipping is working, it's not actually being reported properly in the stats. I'm not a python expert, but I am an experienced developer of many other languages, so can usually follow along in code even in languages I don't know.

I even tried setting my instance to use a single, single-threaded CPU detector, with the Corals disabled. There's no way it could possibly keep up. As expected, the detector process is using 95% CPU, detect FPS has dropped to 0 or close to it on most cameras (at a total of 9.3fps across all cameras). And yet skipped fps is still 0 for everything.
Yeah, not 100% sure what happened as it has been quite a while since I did that testing but I can see now it is not linked to the stats, should be easy to fix though.

Resolving patch:
diff --git a/frigate/video.py b/frigate/video.py
--- a/frigate/video.py
+++ b/frigate/video.py
@@ -172,7 +172,7 @@ def capture_frames(
     skipped_eps.start()
     while True:
         fps.value = frame_rate.eps()
-        skipped_eps.eps()
+        skipped_fps.value = skipped_eps.eps()
 
         current_frame.value = datetime.datetime.now().timestamp()
         frame_name = f"{camera_name}{current_frame.value}"
@@ -215,6 +215,7 @@ def __init__(
         config: CameraConfig,
         frame_queue,
         camera_fps,
+        skipped_fps,
         ffmpeg_pid,
         stop_event,
     ):
@@ -227,6 +228,7 @@ def __init__(
         self.logpipe = LogPipe(f"ffmpeg.{self.camera_name}.detect")
         self.ffmpeg_other_processes: list[dict[str, any]] = []
         self.camera_fps = camera_fps
+        self.skipped_fps = skipped_fps
         self.ffmpeg_pid = ffmpeg_pid
         self.frame_queue = frame_queue
         self.frame_shape = self.config.frame_shape_yuv
@@ -346,6 +348,7 @@ def start_ffmpeg_detect(self):
             self.frame_shape,
             self.frame_queue,
             self.camera_fps,
+            self.skipped_fps,
             self.stop_event,
         )
         self.capture_thread.start()
@@ -376,7 +379,14 @@ def get_latest_segment_timestamp(self, latest_timestamp) -> int:
 
 class CameraCapture(threading.Thread):
     def __init__(
-        self, camera_name, ffmpeg_process, frame_shape, frame_queue, fps, stop_event
+        self,
+        camera_name,
+        ffmpeg_process,
+        frame_shape,
+        frame_queue,
+        fps,
+        skipped_fps,
+        stop_event,
     ):
         threading.Thread.__init__(self)
         self.name = f"capture:{camera_name}"
@@ -385,14 +395,13 @@ def __init__(
         self.frame_queue = frame_queue
         self.fps = fps
         self.stop_event = stop_event
-        self.skipped_fps = EventsPerSecond()
+        self.skipped_fps = skipped_fps
         self.frame_manager = SharedMemoryFrameManager()
         self.ffmpeg_process = ffmpeg_process
         self.current_frame = mp.Value("d", 0.0)
         self.last_frame = 0
 
     def run(self):
-        self.skipped_fps.start()
         capture_frames(
             self.ffmpeg_process,
             self.camera_name,
@@ -424,6 +433,7 @@ def receiveSignal(signalNumber, frame):
         config,
         frame_queue,
         process_info["camera_fps"],
+        process_info["skipped_fps"],
         process_info["ffmpeg_pid"],
         stop_event,
     )


Test patch: