mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-27 10:52:11 +01:00 
			
		
		
		
	add capture processes
This commit is contained in:
		
							parent
							
								
									e0da462223
								
							
						
					
					
						commit
						40f57a8754
					
				@ -13,7 +13,7 @@ from frigate.http import create_app
 | 
				
			|||||||
from frigate.models import Event
 | 
					from frigate.models import Event
 | 
				
			||||||
from frigate.mqtt import create_mqtt_client
 | 
					from frigate.mqtt import create_mqtt_client
 | 
				
			||||||
from frigate.object_processing import TrackedObjectProcessor
 | 
					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():
 | 
					class FrigateApp():
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
@ -36,7 +36,7 @@ class FrigateApp():
 | 
				
			|||||||
        
 | 
					        
 | 
				
			||||||
        self.config = FRIGATE_CONFIG_SCHEMA(config)
 | 
					        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:
 | 
					            if 'width' in camera_config and 'height' in camera_config:
 | 
				
			||||||
                frame_shape = (camera_config['height'], camera_config['width'], 3)
 | 
					                frame_shape = (camera_config['height'], camera_config['width'], 3)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
@ -44,6 +44,43 @@ class FrigateApp():
 | 
				
			|||||||
        
 | 
					        
 | 
				
			||||||
            camera_config['frame_shape'] = frame_shape
 | 
					            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
 | 
					        # TODO: sub in FRIGATE_ENV vars
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def init_queues(self):
 | 
					    def init_queues(self):
 | 
				
			||||||
@ -115,7 +152,13 @@ class FrigateApp():
 | 
				
			|||||||
            print(f"Camera process started for {name}: {camera_process.pid}")
 | 
					            print(f"Camera process started for {name}: {camera_process.pid}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def start_camera_capture_processes(self):
 | 
					    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):
 | 
					    def start_watchdog(self):
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
				
			|||||||
@ -116,10 +116,8 @@ def start_or_restart_ffmpeg(ffmpeg_cmd, frame_size, ffmpeg_process=None):
 | 
				
			|||||||
    return process
 | 
					    return process
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def capture_frames(ffmpeg_process, camera_name, frame_shape, frame_manager: FrameManager, 
 | 
					def capture_frames(ffmpeg_process, camera_name, frame_shape, frame_manager: FrameManager, 
 | 
				
			||||||
    frame_queue, take_frame: int, fps:mp.Value, skipped_fps: mp.Value, 
 | 
					    frame_queue, fps:mp.Value, skipped_fps: mp.Value, current_frame: mp.Value):
 | 
				
			||||||
    stop_event: mp.Event, current_frame: mp.Value):
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    frame_num = 0
 | 
					 | 
				
			||||||
    frame_size = frame_shape[0] * frame_shape[1] * 3 // 2
 | 
					    frame_size = frame_shape[0] * frame_shape[1] * 3 // 2
 | 
				
			||||||
    frame_rate = EventsPerSecond()
 | 
					    frame_rate = EventsPerSecond()
 | 
				
			||||||
    frame_rate.start()
 | 
					    frame_rate.start()
 | 
				
			||||||
@ -128,9 +126,6 @@ def capture_frames(ffmpeg_process, camera_name, frame_shape, frame_manager: Fram
 | 
				
			|||||||
    while True:
 | 
					    while True:
 | 
				
			||||||
        fps.value = frame_rate.eps()
 | 
					        fps.value = frame_rate.eps()
 | 
				
			||||||
        skipped_fps = skipped_eps.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()
 | 
					        current_frame.value = datetime.datetime.now().timestamp()
 | 
				
			||||||
        frame_name = f"{camera_name}{current_frame.value}"
 | 
					        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_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 the queue is full, skip this frame
 | 
				
			||||||
        if frame_queue.full():
 | 
					        if frame_queue.full():
 | 
				
			||||||
            skipped_eps.update()
 | 
					            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)
 | 
					        frame_queue.put(current_frame.value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CameraWatchdog(threading.Thread):
 | 
					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)
 | 
					        threading.Thread.__init__(self)
 | 
				
			||||||
        self.name = name
 | 
					        self.name = name
 | 
				
			||||||
        self.config = config
 | 
					        self.config = config
 | 
				
			||||||
        self.capture_thread = None
 | 
					        self.capture_thread = None
 | 
				
			||||||
        self.ffmpeg_process = None
 | 
					        self.ffmpeg_process = None
 | 
				
			||||||
        self.stop_event = stop_event
 | 
					 | 
				
			||||||
        self.camera_fps = camera_fps
 | 
					        self.camera_fps = camera_fps
 | 
				
			||||||
        self.ffmpeg_pid = ffmpeg_pid
 | 
					        self.ffmpeg_pid = ffmpeg_pid
 | 
				
			||||||
        self.frame_queue = frame_queue
 | 
					        self.frame_queue = frame_queue
 | 
				
			||||||
@ -185,10 +173,6 @@ class CameraWatchdog(threading.Thread):
 | 
				
			|||||||
        self.start_ffmpeg()
 | 
					        self.start_ffmpeg()
 | 
				
			||||||
        time.sleep(10)
 | 
					        time.sleep(10)
 | 
				
			||||||
        while True:
 | 
					        while True:
 | 
				
			||||||
            if self.stop_event.is_set():
 | 
					 | 
				
			||||||
                print(f"Exiting watchdog...")
 | 
					 | 
				
			||||||
                break
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            now = datetime.datetime.now().timestamp()
 | 
					            now = datetime.datetime.now().timestamp()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if not self.capture_thread.is_alive():
 | 
					            if not self.capture_thread.is_alive():
 | 
				
			||||||
@ -211,33 +195,31 @@ class CameraWatchdog(threading.Thread):
 | 
				
			|||||||
        self.ffmpeg_process = start_or_restart_ffmpeg(self.config['ffmpeg_cmd'], self.frame_size)
 | 
					        self.ffmpeg_process = start_or_restart_ffmpeg(self.config['ffmpeg_cmd'], self.frame_size)
 | 
				
			||||||
        self.ffmpeg_pid.value = self.ffmpeg_process.pid
 | 
					        self.ffmpeg_pid.value = self.ffmpeg_process.pid
 | 
				
			||||||
        self.capture_thread = CameraCapture(self.name, self.ffmpeg_process, self.frame_shape, self.frame_queue, 
 | 
					        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.camera_fps)
 | 
				
			||||||
        self.capture_thread.start()
 | 
					        self.capture_thread.start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CameraCapture(threading.Thread):
 | 
					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)
 | 
					        threading.Thread.__init__(self)
 | 
				
			||||||
        self.name = name
 | 
					        self.name = name
 | 
				
			||||||
        self.frame_shape = frame_shape
 | 
					        self.frame_shape = frame_shape
 | 
				
			||||||
        self.frame_size = frame_shape[0] * frame_shape[1] * frame_shape[2]
 | 
					        self.frame_size = frame_shape[0] * frame_shape[1] * frame_shape[2]
 | 
				
			||||||
        self.frame_queue = frame_queue
 | 
					        self.frame_queue = frame_queue
 | 
				
			||||||
        self.take_frame = take_frame
 | 
					 | 
				
			||||||
        self.fps = fps
 | 
					        self.fps = fps
 | 
				
			||||||
        self.skipped_fps = EventsPerSecond()
 | 
					        self.skipped_fps = EventsPerSecond()
 | 
				
			||||||
        self.frame_manager = SharedMemoryFrameManager()
 | 
					        self.frame_manager = SharedMemoryFrameManager()
 | 
				
			||||||
        self.ffmpeg_process = ffmpeg_process
 | 
					        self.ffmpeg_process = ffmpeg_process
 | 
				
			||||||
        self.current_frame = mp.Value('d', 0.0)
 | 
					        self.current_frame = mp.Value('d', 0.0)
 | 
				
			||||||
        self.last_frame = 0
 | 
					        self.last_frame = 0
 | 
				
			||||||
        self.stop_event = stop_event
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def run(self):
 | 
					    def run(self):
 | 
				
			||||||
        self.skipped_fps.start()
 | 
					        self.skipped_fps.start()
 | 
				
			||||||
        capture_frames(self.ffmpeg_process, self.name, self.frame_shape, self.frame_manager, self.frame_queue, self.take_frame,
 | 
					        capture_frames(self.ffmpeg_process, self.name, self.frame_shape, self.frame_manager, self.frame_queue,
 | 
				
			||||||
            self.fps, self.skipped_fps, self.stop_event, self.current_frame)
 | 
					            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']
 | 
					    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.start()
 | 
				
			||||||
    camera_watchdog.join()
 | 
					    camera_watchdog.join()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user