From 40f57a875445b62cd9455956791f14edf08ebd04 Mon Sep 17 00:00:00 2001 From: Blake Blackshear Date: Sun, 1 Nov 2020 10:55:11 -0600 Subject: [PATCH] add capture processes --- frigate/__main__.py | 49 ++++++++++++++++++++++++++++++++++++++++++--- frigate/video.py | 42 +++++++++++--------------------------- 2 files changed, 58 insertions(+), 33 deletions(-) diff --git a/frigate/__main__.py b/frigate/__main__.py index ddbe6893c..79ac19eda 100644 --- a/frigate/__main__.py +++ b/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 diff --git a/frigate/video.py b/frigate/video.py index 82d2fe916..a147724bd 100755 --- a/frigate/video.py +++ b/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()