Browse Source

add capture processes

Blake Blackshear 4 years ago
parent
commit
9778a748fc
2 changed files with 58 additions and 33 deletions
  1. 46 3
      frigate/__main__.py
  2. 12 30
      frigate/video.py

+ 46 - 3
frigate/__main__.py

@@ -13,7 +13,7 @@ from frigate.http import create_app
 from frigate.models import Event
 from frigate.mqtt import create_mqtt_client
 from frigate.object_processing import TrackedObjectProcessor
-from frigate.video import get_frame_shape, track_camera
+from frigate.video import get_frame_shape, track_camera, get_ffmpeg_input, capture_camera
 
 class FrigateApp():
     def __init__(self):
@@ -36,7 +36,7 @@ class FrigateApp():
         
         self.config = FRIGATE_CONFIG_SCHEMA(config)
 
-        for camera_config in self.config['cameras'].values():
+        for camera_name, camera_config in self.config['cameras'].items():
             if 'width' in camera_config and 'height' in camera_config:
                 frame_shape = (camera_config['height'], camera_config['width'], 3)
             else:
@@ -44,6 +44,43 @@ class FrigateApp():
         
             camera_config['frame_shape'] = frame_shape
 
+            ffmpeg = camera_config['ffmpeg']
+            ffmpeg_input = ffmpeg['input']
+            ffmpeg_global_args = ffmpeg.get('global_args', self.config['ffmpeg']['global_args'])
+            ffmpeg_hwaccel_args = ffmpeg.get('hwaccel_args', self.config['ffmpeg']['hwaccel_args'])
+            ffmpeg_input_args = ffmpeg.get('input_args', self.config['ffmpeg']['input_args'])
+            ffmpeg_output_args = ffmpeg.get('output_args', self.config['ffmpeg']['output_args'])
+            if not camera_config.get('fps') is None:
+                ffmpeg_output_args = ["-r", str(camera_config['fps'])] + ffmpeg_output_args
+            if camera_config['save_clips']['enabled']:
+                ffmpeg_output_args = [
+                    "-f",
+                    "segment",
+                    "-segment_time",
+                    "10",
+                    "-segment_format",
+                    "mp4",
+                    "-reset_timestamps",
+                    "1",
+                    "-strftime",
+                    "1",
+                    "-c",
+                    "copy",
+                    "-an",
+                    "-map",
+                    "0",
+                    f"{os.path.join(self.config['save_clips']['cache_dir'], camera_name)}-%Y%m%d%H%M%S.mp4"
+                ] + ffmpeg_output_args
+            ffmpeg_cmd = (['ffmpeg'] +
+                    ffmpeg_global_args +
+                    ffmpeg_hwaccel_args +
+                    ffmpeg_input_args +
+                    ['-i', ffmpeg_input] +
+                    ffmpeg_output_args +
+                    ['pipe:'])
+            
+            camera_config['ffmpeg_cmd'] = ffmpeg_cmd
+
         # TODO: sub in FRIGATE_ENV vars
 
     def init_queues(self):
@@ -115,7 +152,13 @@ class FrigateApp():
             print(f"Camera process started for {name}: {camera_process.pid}")
 
     def start_camera_capture_processes(self):
-        pass
+        for name, config in self.config['cameras'].items():
+            capture_process = mp.Process(target=capture_camera, args=(name, config,
+                self.camera_process_info[name]))
+            capture_process.daemon = True
+            self.camera_process_info[name]['capture_process'] = capture_process
+            capture_process.start()
+            print(f"Camera process started for {name}: {capture_process.pid}")
 
     def start_watchdog(self):
         pass

+ 12 - 30
frigate/video.py

@@ -116,10 +116,8 @@ def start_or_restart_ffmpeg(ffmpeg_cmd, frame_size, ffmpeg_process=None):
     return process
 
 def capture_frames(ffmpeg_process, camera_name, frame_shape, frame_manager: FrameManager, 
-    frame_queue, take_frame: int, fps:mp.Value, skipped_fps: mp.Value, 
-    stop_event: mp.Event, current_frame: mp.Value):
+    frame_queue, fps:mp.Value, skipped_fps: mp.Value, current_frame: mp.Value):
 
-    frame_num = 0
     frame_size = frame_shape[0] * frame_shape[1] * 3 // 2
     frame_rate = EventsPerSecond()
     frame_rate.start()
@@ -128,9 +126,6 @@ def capture_frames(ffmpeg_process, camera_name, frame_shape, frame_manager: Fram
     while True:
         fps.value = frame_rate.eps()
         skipped_fps = skipped_eps.eps()
-        if stop_event.is_set():
-            print(f"{camera_name}: stop event set. exiting capture thread...")
-            break
 
         current_frame.value = datetime.datetime.now().timestamp()
         frame_name = f"{camera_name}{current_frame.value}"
@@ -149,12 +144,6 @@ def capture_frames(ffmpeg_process, camera_name, frame_shape, frame_manager: Fram
 
         frame_rate.update()
 
-        frame_num += 1
-        if (frame_num % take_frame) != 0:
-            skipped_eps.update()
-            frame_manager.delete(frame_name)
-            continue
-
         # if the queue is full, skip this frame
         if frame_queue.full():
             skipped_eps.update()
@@ -168,13 +157,12 @@ def capture_frames(ffmpeg_process, camera_name, frame_shape, frame_manager: Fram
         frame_queue.put(current_frame.value)
 
 class CameraWatchdog(threading.Thread):
-    def __init__(self, name, config, frame_queue, camera_fps, ffmpeg_pid, stop_event):
+    def __init__(self, name, config, frame_queue, camera_fps, ffmpeg_pid):
         threading.Thread.__init__(self)
         self.name = name
         self.config = config
         self.capture_thread = None
         self.ffmpeg_process = None
-        self.stop_event = stop_event
         self.camera_fps = camera_fps
         self.ffmpeg_pid = ffmpeg_pid
         self.frame_queue = frame_queue
@@ -185,10 +173,6 @@ class CameraWatchdog(threading.Thread):
         self.start_ffmpeg()
         time.sleep(10)
         while True:
-            if self.stop_event.is_set():
-                print(f"Exiting watchdog...")
-                break
-
             now = datetime.datetime.now().timestamp()
 
             if not self.capture_thread.is_alive():
@@ -208,36 +192,34 @@ class CameraWatchdog(threading.Thread):
             time.sleep(10)
     
     def start_ffmpeg(self):
-      self.ffmpeg_process = start_or_restart_ffmpeg(self.config['ffmpeg_cmd'], self.frame_size)
-      self.ffmpeg_pid.value = self.ffmpeg_process.pid
-      self.capture_thread = CameraCapture(self.name, self.ffmpeg_process, self.frame_shape, self.frame_queue, 
-          self.config['take_frame'], self.camera_fps, self.stop_event)
-      self.capture_thread.start()
+        self.ffmpeg_process = start_or_restart_ffmpeg(self.config['ffmpeg_cmd'], self.frame_size)
+        self.ffmpeg_pid.value = self.ffmpeg_process.pid
+        self.capture_thread = CameraCapture(self.name, self.ffmpeg_process, self.frame_shape, self.frame_queue, 
+            self.camera_fps)
+        self.capture_thread.start()
 
 class CameraCapture(threading.Thread):
-    def __init__(self, name, ffmpeg_process, frame_shape, frame_queue, take_frame, fps, stop_event):
+    def __init__(self, name, ffmpeg_process, frame_shape, frame_queue, fps):
         threading.Thread.__init__(self)
         self.name = name
         self.frame_shape = frame_shape
         self.frame_size = frame_shape[0] * frame_shape[1] * frame_shape[2]
         self.frame_queue = frame_queue
-        self.take_frame = take_frame
         self.fps = fps
         self.skipped_fps = EventsPerSecond()
         self.frame_manager = SharedMemoryFrameManager()
         self.ffmpeg_process = ffmpeg_process
         self.current_frame = mp.Value('d', 0.0)
         self.last_frame = 0
-        self.stop_event = stop_event
 
     def run(self):
         self.skipped_fps.start()
-        capture_frames(self.ffmpeg_process, self.name, self.frame_shape, self.frame_manager, self.frame_queue, self.take_frame,
-            self.fps, self.skipped_fps, self.stop_event, self.current_frame)
+        capture_frames(self.ffmpeg_process, self.name, self.frame_shape, self.frame_manager, self.frame_queue,
+            self.fps, self.skipped_fps, self.current_frame)
 
-def capture_camera(name, config, process_info, stop_event):
+def capture_camera(name, config, process_info):
     frame_queue = process_info['frame_queue']
-    camera_watchdog = CameraWatchdog(name, config, frame_queue, process_info['camera_fps'], process_info['ffmpeg_pid'], stop_event)
+    camera_watchdog = CameraWatchdog(name, config, frame_queue, process_info['camera_fps'], process_info['ffmpeg_pid'])
     camera_watchdog.start()
     camera_watchdog.join()