diff --git a/frigate/app.py b/frigate/app.py index d48e30fea..254def07c 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -89,7 +89,7 @@ class FrigateApp: "detection_fps": mp.Value("d", 0.0), "detection_frame": mp.Value("d", 0.0), "read_start": mp.Value("d", 0.0), - "ffmpeg_pid": mp.Value("i", 0), + "decoder_pid": mp.Value("i", 0), "frame_queue": mp.Queue(maxsize=2), } diff --git a/frigate/config.py b/frigate/config.py index 3f8af47cf..40c895317 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -33,7 +33,9 @@ FRIGATE_ENV_VARS = {k: v for k, v in os.environ.items() if k.startswith("FRIGATE DEFAULT_TRACKED_OBJECTS = ["person"] DEFAULT_DETECTORS = {"cpu": {"type": "cpu"}} - +# TensorRT defaults +DEFAULT_TRT_MODEL_PATH="/yolo4/yolov4-tiny-416.trt" +DEFAULT_TRT_MODEL_SIZE=416 class FrigateBaseModel(BaseModel): class Config: @@ -926,7 +928,7 @@ class FrigateConfig(FrigateBaseModel): if config.mqtt.password: config.mqtt.password = config.mqtt.password.format(**FRIGATE_ENV_VARS) - # Global config to propegate down to camera level + # Global config to propagate down to camera level global_config = config.dict( include={ "record": ..., @@ -1047,10 +1049,25 @@ class FrigateConfig(FrigateBaseModel): logger.warning( f"{name}: Recording retention is configured for {camera_config.record.retain.mode} and event retention is configured for {camera_config.record.events.retain.mode}. The more restrictive retention policy will be applied." ) - # generage the ffmpeg commands + # generage the decoder commands camera_config.create_decoder_cmds() config.cameras[name] = camera_config + for name, detector_config in config.detectors.items(): + if ( + detector_config.type == DetectorTypeEnum.tensorrt + ): + if config.model.path is None: + logger.info( + "Setting default model to the yolov4-tiny-416 for the %s detector.", + name, + ) + config.model.path = DEFAULT_TRT_MODEL_PATH + config.model.height = DEFAULT_TRT_MODEL_SIZE + config.model.width = DEFAULT_TRT_MODEL_SIZE + elif "tflite" in config.model.path: + raise ValueError(f"The {name} detector is of type tensorrt, however, tflite model is used.") + return config @validator("cameras") diff --git a/frigate/util.py b/frigate/util.py index cc73ca7e3..2dd1b5569 100755 --- a/frigate/util.py +++ b/frigate/util.py @@ -34,7 +34,7 @@ def deep_merge(dct1: dict, dct2: dict, override=False, merge_lists=False) -> dic for k, v2 in dct2.items(): if k in merged: v1 = merged[k] - if isinstance(v1, dict) and isinstance(v2, collections.Mapping): + if isinstance(v1, dict) and isinstance(v2, collections.abc.Mapping): merged[k] = deep_merge(v1, v2, override) elif isinstance(v1, list) and isinstance(v2, list): if merge_lists: diff --git a/frigate/video.py b/frigate/video.py index ea624c90d..024a0b789 100755 --- a/frigate/video.py +++ b/frigate/video.py @@ -87,24 +87,24 @@ def create_tensor_input(frame, model_shape, region): return cropped_frame -def stop_ffmpeg(ffmpeg_process, logger): - logger.info("Terminating the existing ffmpeg process...") - ffmpeg_process.terminate() +def stop_decoder(decoder_process, logger): + logger.info("Terminating the existing decoder process...") + decoder_process.terminate() try: - logger.info("Waiting for ffmpeg to exit gracefully...") - ffmpeg_process.communicate(timeout=30) + logger.info("Waiting for decoder to exit gracefully...") + decoder_process.communicate(timeout=30) except sp.TimeoutExpired: - logger.info("FFmpeg didnt exit. Force killing...") - ffmpeg_process.kill() - ffmpeg_process.communicate() - ffmpeg_process = None + logger.info("decoder didnt exit. Force killing...") + decoder_process.kill() + decoder_process.communicate() + decoder_process = None -def start_or_restart_ffmpeg( - decoder_cmd, logger, logpipe: LogPipe, frame_size=None, ffmpeg_process=None +def start_or_restart_decoder( + decoder_cmd, logger, logpipe: LogPipe, frame_size=None, decoder_process=None ): - if ffmpeg_process is not None: - stop_ffmpeg(ffmpeg_process, logger) + if decoder_process is not None: + stop_decoder(decoder_process, logger) if frame_size is None: process = sp.Popen( @@ -127,7 +127,7 @@ def start_or_restart_ffmpeg( def capture_frames( - ffmpeg_process, + decoder_process, camera_name, frame_shape, frame_manager: FrameManager, @@ -150,13 +150,13 @@ def capture_frames( frame_name = f"{camera_name}{current_frame.value}" frame_buffer = frame_manager.create(frame_name, frame_size) try: - frame_buffer[:] = ffmpeg_process.stdout.read(frame_size) + frame_buffer[:] = decoder_process.stdout.read(frame_size) except Exception as e: - logger.error(f"{camera_name}: Unable to read frames from ffmpeg process.") + logger.error(f"{camera_name}: Unable to read frames from decoder process.") - if ffmpeg_process.poll() != None: + if decoder_process.poll() != None: logger.error( - f"{camera_name}: ffmpeg process is not running. exiting capture thread..." + f"{camera_name}: decoder process is not running. exiting capture thread..." ) frame_manager.delete(frame_name) break @@ -179,38 +179,38 @@ def capture_frames( class CameraWatchdog(threading.Thread): def __init__( - self, camera_name, config, frame_queue, camera_fps, ffmpeg_pid, stop_event + self, camera_name, config, frame_queue, camera_fps, decoder_pid, stop_event ): threading.Thread.__init__(self) self.logger = logging.getLogger(f"watchdog.{camera_name}") self.camera_name = camera_name self.config = config self.capture_thread = None - self.ffmpeg_detect_process = None - self.logpipe = LogPipe(f"ffmpeg.{self.camera_name}.detect", logging.ERROR) - self.ffmpeg_other_processes = [] + self.decoder_detect_process = None + self.logpipe = LogPipe(f"decoder.{self.camera_name}.detect", logging.ERROR) + self.decoder_other_processes = [] self.camera_fps = camera_fps - self.ffmpeg_pid = ffmpeg_pid + self.decoder_pid = decoder_pid self.frame_queue = frame_queue self.frame_shape = self.config.frame_shape_yuv self.frame_size = self.frame_shape[0] * self.frame_shape[1] self.stop_event = stop_event def run(self): - self.start_ffmpeg_detect() + self.start_decoder_detect() for c in self.config.decoder_cmds: if "detect" in c["roles"]: continue logpipe = LogPipe( - f"ffmpeg.{self.camera_name}.{'_'.join(sorted(c['roles']))}", + f"decoder.{self.camera_name}.{'_'.join(sorted(c['roles']))}", logging.ERROR, ) - self.ffmpeg_other_processes.append( + self.decoder_other_processes.append( { "cmd": c["cmd"], "logpipe": logpipe, - "process": start_or_restart_ffmpeg(c["cmd"], self.logger, logpipe), + "process": start_or_restart_decoder(c["cmd"], self.logger, logpipe), } ) @@ -220,52 +220,52 @@ class CameraWatchdog(threading.Thread): if not self.capture_thread.is_alive(): self.logger.error( - f"Ffmpeg process crashed unexpectedly for {self.camera_name}." + f"decoder process crashed unexpectedly for {self.camera_name}." ) self.logger.error( - "The following ffmpeg logs include the last 100 lines prior to exit." + "The following decoder logs include the last 100 lines prior to exit." ) self.logpipe.dump() - self.start_ffmpeg_detect() + self.start_decoder_detect() elif now - self.capture_thread.current_frame.value > 20: self.logger.info( - f"No frames received from {self.camera_name} in 20 seconds. Exiting ffmpeg..." + f"No frames received from {self.camera_name} in 20 seconds. Exiting decoder..." ) - self.ffmpeg_detect_process.terminate() + self.decoder_detect_process.terminate() try: - self.logger.info("Waiting for ffmpeg to exit gracefully...") - self.ffmpeg_detect_process.communicate(timeout=30) + self.logger.info("Waiting for decoder to exit gracefully...") + self.decoder_detect_process.communicate(timeout=30) except sp.TimeoutExpired: - self.logger.info("FFmpeg didnt exit. Force killing...") - self.ffmpeg_detect_process.kill() - self.ffmpeg_detect_process.communicate() + self.logger.info("decoder didnt exit. Force killing...") + self.decoder_detect_process.kill() + self.decoder_detect_process.communicate() - for p in self.ffmpeg_other_processes: + for p in self.decoder_other_processes: poll = p["process"].poll() if poll is None: continue p["logpipe"].dump() - p["process"] = start_or_restart_ffmpeg( - p["cmd"], self.logger, p["logpipe"], ffmpeg_process=p["process"] + p["process"] = start_or_restart_decoder( + p["cmd"], self.logger, p["logpipe"], decoder_process=p["process"] ) - stop_ffmpeg(self.ffmpeg_detect_process, self.logger) - for p in self.ffmpeg_other_processes: - stop_ffmpeg(p["process"], self.logger) + stop_decoder(self.decoder_detect_process, self.logger) + for p in self.decoder_other_processes: + stop_decoder(p["process"], self.logger) p["logpipe"].close() self.logpipe.close() - def start_ffmpeg_detect(self): + def start_decoder_detect(self): decoder_cmd = [ c["cmd"] for c in self.config.decoder_cmds if "detect" in c["roles"] ][0] - self.ffmpeg_detect_process = start_or_restart_ffmpeg( + self.decoder_detect_process = start_or_restart_decoder( decoder_cmd, self.logger, self.logpipe, self.frame_size ) - self.ffmpeg_pid.value = self.ffmpeg_detect_process.pid + self.decoder_pid.value = self.decoder_detect_process.pid self.capture_thread = CameraCapture( self.camera_name, - self.ffmpeg_detect_process, + self.decoder_detect_process, self.frame_shape, self.frame_queue, self.camera_fps, @@ -274,7 +274,7 @@ class CameraWatchdog(threading.Thread): class CameraCapture(threading.Thread): - def __init__(self, camera_name, ffmpeg_process, frame_shape, frame_queue, fps): + def __init__(self, camera_name, decoder_process, frame_shape, frame_queue, fps): threading.Thread.__init__(self) self.name = f"capture:{camera_name}" self.camera_name = camera_name @@ -283,14 +283,14 @@ class CameraCapture(threading.Thread): self.fps = fps self.skipped_fps = EventsPerSecond() self.frame_manager = SharedMemoryFrameManager() - self.ffmpeg_process = ffmpeg_process + self.decoder_process = decoder_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.decoder_process, self.camera_name, self.frame_shape, self.frame_manager, @@ -316,7 +316,7 @@ def capture_camera(name, config: CameraConfig, process_info): config, frame_queue, process_info["camera_fps"], - process_info["ffmpeg_pid"], + process_info["decoder_pid"], stop_event, ) camera_watchdog.start()