apply good defauls for the tensorrt and change ffmpeg to decoder

This commit is contained in:
YS 2022-03-30 13:15:15 +03:00
parent 403bee8d3a
commit 846586d959
4 changed files with 73 additions and 56 deletions

View File

@ -89,7 +89,7 @@ class FrigateApp:
"detection_fps": mp.Value("d", 0.0), "detection_fps": mp.Value("d", 0.0),
"detection_frame": mp.Value("d", 0.0), "detection_frame": mp.Value("d", 0.0),
"read_start": 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), "frame_queue": mp.Queue(maxsize=2),
} }

View File

@ -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_TRACKED_OBJECTS = ["person"]
DEFAULT_DETECTORS = {"cpu": {"type": "cpu"}} 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 FrigateBaseModel(BaseModel):
class Config: class Config:
@ -926,7 +928,7 @@ class FrigateConfig(FrigateBaseModel):
if config.mqtt.password: if config.mqtt.password:
config.mqtt.password = config.mqtt.password.format(**FRIGATE_ENV_VARS) 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( global_config = config.dict(
include={ include={
"record": ..., "record": ...,
@ -1047,10 +1049,25 @@ class FrigateConfig(FrigateBaseModel):
logger.warning( 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." 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() camera_config.create_decoder_cmds()
config.cameras[name] = camera_config 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 return config
@validator("cameras") @validator("cameras")

View File

@ -34,7 +34,7 @@ def deep_merge(dct1: dict, dct2: dict, override=False, merge_lists=False) -> dic
for k, v2 in dct2.items(): for k, v2 in dct2.items():
if k in merged: if k in merged:
v1 = merged[k] 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) merged[k] = deep_merge(v1, v2, override)
elif isinstance(v1, list) and isinstance(v2, list): elif isinstance(v1, list) and isinstance(v2, list):
if merge_lists: if merge_lists:

View File

@ -87,24 +87,24 @@ def create_tensor_input(frame, model_shape, region):
return cropped_frame return cropped_frame
def stop_ffmpeg(ffmpeg_process, logger): def stop_decoder(decoder_process, logger):
logger.info("Terminating the existing ffmpeg process...") logger.info("Terminating the existing decoder process...")
ffmpeg_process.terminate() decoder_process.terminate()
try: try:
logger.info("Waiting for ffmpeg to exit gracefully...") logger.info("Waiting for decoder to exit gracefully...")
ffmpeg_process.communicate(timeout=30) decoder_process.communicate(timeout=30)
except sp.TimeoutExpired: except sp.TimeoutExpired:
logger.info("FFmpeg didnt exit. Force killing...") logger.info("decoder didnt exit. Force killing...")
ffmpeg_process.kill() decoder_process.kill()
ffmpeg_process.communicate() decoder_process.communicate()
ffmpeg_process = None decoder_process = None
def start_or_restart_ffmpeg( def start_or_restart_decoder(
decoder_cmd, logger, logpipe: LogPipe, frame_size=None, ffmpeg_process=None decoder_cmd, logger, logpipe: LogPipe, frame_size=None, decoder_process=None
): ):
if ffmpeg_process is not None: if decoder_process is not None:
stop_ffmpeg(ffmpeg_process, logger) stop_decoder(decoder_process, logger)
if frame_size is None: if frame_size is None:
process = sp.Popen( process = sp.Popen(
@ -127,7 +127,7 @@ def start_or_restart_ffmpeg(
def capture_frames( def capture_frames(
ffmpeg_process, decoder_process,
camera_name, camera_name,
frame_shape, frame_shape,
frame_manager: FrameManager, frame_manager: FrameManager,
@ -150,13 +150,13 @@ def capture_frames(
frame_name = f"{camera_name}{current_frame.value}" frame_name = f"{camera_name}{current_frame.value}"
frame_buffer = frame_manager.create(frame_name, frame_size) frame_buffer = frame_manager.create(frame_name, frame_size)
try: try:
frame_buffer[:] = ffmpeg_process.stdout.read(frame_size) frame_buffer[:] = decoder_process.stdout.read(frame_size)
except Exception as e: 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( 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) frame_manager.delete(frame_name)
break break
@ -179,38 +179,38 @@ def capture_frames(
class CameraWatchdog(threading.Thread): class CameraWatchdog(threading.Thread):
def __init__( 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) threading.Thread.__init__(self)
self.logger = logging.getLogger(f"watchdog.{camera_name}") self.logger = logging.getLogger(f"watchdog.{camera_name}")
self.camera_name = camera_name self.camera_name = camera_name
self.config = config self.config = config
self.capture_thread = None self.capture_thread = None
self.ffmpeg_detect_process = None self.decoder_detect_process = None
self.logpipe = LogPipe(f"ffmpeg.{self.camera_name}.detect", logging.ERROR) self.logpipe = LogPipe(f"decoder.{self.camera_name}.detect", logging.ERROR)
self.ffmpeg_other_processes = [] self.decoder_other_processes = []
self.camera_fps = camera_fps self.camera_fps = camera_fps
self.ffmpeg_pid = ffmpeg_pid self.decoder_pid = decoder_pid
self.frame_queue = frame_queue self.frame_queue = frame_queue
self.frame_shape = self.config.frame_shape_yuv self.frame_shape = self.config.frame_shape_yuv
self.frame_size = self.frame_shape[0] * self.frame_shape[1] self.frame_size = self.frame_shape[0] * self.frame_shape[1]
self.stop_event = stop_event self.stop_event = stop_event
def run(self): def run(self):
self.start_ffmpeg_detect() self.start_decoder_detect()
for c in self.config.decoder_cmds: for c in self.config.decoder_cmds:
if "detect" in c["roles"]: if "detect" in c["roles"]:
continue continue
logpipe = LogPipe( logpipe = LogPipe(
f"ffmpeg.{self.camera_name}.{'_'.join(sorted(c['roles']))}", f"decoder.{self.camera_name}.{'_'.join(sorted(c['roles']))}",
logging.ERROR, logging.ERROR,
) )
self.ffmpeg_other_processes.append( self.decoder_other_processes.append(
{ {
"cmd": c["cmd"], "cmd": c["cmd"],
"logpipe": logpipe, "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(): if not self.capture_thread.is_alive():
self.logger.error( self.logger.error(
f"Ffmpeg process crashed unexpectedly for {self.camera_name}." f"decoder process crashed unexpectedly for {self.camera_name}."
) )
self.logger.error( 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.logpipe.dump()
self.start_ffmpeg_detect() self.start_decoder_detect()
elif now - self.capture_thread.current_frame.value > 20: elif now - self.capture_thread.current_frame.value > 20:
self.logger.info( 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: try:
self.logger.info("Waiting for ffmpeg to exit gracefully...") self.logger.info("Waiting for decoder to exit gracefully...")
self.ffmpeg_detect_process.communicate(timeout=30) self.decoder_detect_process.communicate(timeout=30)
except sp.TimeoutExpired: except sp.TimeoutExpired:
self.logger.info("FFmpeg didnt exit. Force killing...") self.logger.info("decoder didnt exit. Force killing...")
self.ffmpeg_detect_process.kill() self.decoder_detect_process.kill()
self.ffmpeg_detect_process.communicate() self.decoder_detect_process.communicate()
for p in self.ffmpeg_other_processes: for p in self.decoder_other_processes:
poll = p["process"].poll() poll = p["process"].poll()
if poll is None: if poll is None:
continue continue
p["logpipe"].dump() p["logpipe"].dump()
p["process"] = start_or_restart_ffmpeg( p["process"] = start_or_restart_decoder(
p["cmd"], self.logger, p["logpipe"], ffmpeg_process=p["process"] p["cmd"], self.logger, p["logpipe"], decoder_process=p["process"]
) )
stop_ffmpeg(self.ffmpeg_detect_process, self.logger) stop_decoder(self.decoder_detect_process, self.logger)
for p in self.ffmpeg_other_processes: for p in self.decoder_other_processes:
stop_ffmpeg(p["process"], self.logger) stop_decoder(p["process"], self.logger)
p["logpipe"].close() p["logpipe"].close()
self.logpipe.close() self.logpipe.close()
def start_ffmpeg_detect(self): def start_decoder_detect(self):
decoder_cmd = [ decoder_cmd = [
c["cmd"] for c in self.config.decoder_cmds if "detect" in c["roles"] c["cmd"] for c in self.config.decoder_cmds if "detect" in c["roles"]
][0] ][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 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.capture_thread = CameraCapture(
self.camera_name, self.camera_name,
self.ffmpeg_detect_process, self.decoder_detect_process,
self.frame_shape, self.frame_shape,
self.frame_queue, self.frame_queue,
self.camera_fps, self.camera_fps,
@ -274,7 +274,7 @@ class CameraWatchdog(threading.Thread):
class CameraCapture(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) threading.Thread.__init__(self)
self.name = f"capture:{camera_name}" self.name = f"capture:{camera_name}"
self.camera_name = camera_name self.camera_name = camera_name
@ -283,14 +283,14 @@ class CameraCapture(threading.Thread):
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.decoder_process = decoder_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
def run(self): def run(self):
self.skipped_fps.start() self.skipped_fps.start()
capture_frames( capture_frames(
self.ffmpeg_process, self.decoder_process,
self.camera_name, self.camera_name,
self.frame_shape, self.frame_shape,
self.frame_manager, self.frame_manager,
@ -316,7 +316,7 @@ def capture_camera(name, config: CameraConfig, process_info):
config, config,
frame_queue, frame_queue,
process_info["camera_fps"], process_info["camera_fps"],
process_info["ffmpeg_pid"], process_info["decoder_pid"],
stop_event, stop_event,
) )
camera_watchdog.start() camera_watchdog.start()