diff --git a/frigate/ffmpeg_presets.py b/frigate/ffmpeg_presets.py index 12edfdb74..cd725961b 100644 --- a/frigate/ffmpeg_presets.py +++ b/frigate/ffmpeg_presets.py @@ -4,18 +4,32 @@ from typing import Any PRESETS_HW_ACCEL = { - "preset-rpi-32-h264": "-c:v h264_v4l2m2m", - "preset-rpi-64-h264": "-c:v h264_v4l2m2m", - "preset-intel-vaapi": "-hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format yuv420p", - "preset-intel-qsv-h264": "-c:v h264_qsv", - "preset-intel-qsv-h265": "-c:v hevc_qsv", - "preset-amd-vaapi": "-hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format yuv420p", - "preset-nvidia-h264": "-c:v h264_cuvid", - "preset-nvidia-h265": "-c:v hevc_cuvid", + "preset-rpi-32-h264": ["-c:v", "h264_v4l2m2m"], + "preset-rpi-64-h264": ["-c:v", "h264_v4l2m2m"], + "preset-intel-vaapi": [ + "-hwaccel", + "vaapi", + "-hwaccel_device", + "/dev/dri/renderD128", + "-hwaccel_output_format", + "yuv420p", + ], + "preset-intel-qsv-h264": ["-c:v", "h264_qsv"], + "preset-intel-qsv-h265": ["-c:v", "hevc_qsv"], + "preset-amd-vaapi": [ + "-hwaccel", + "vaapi", + "-hwaccel_device", + "/dev/dri/renderD128", + "-hwaccel_output_format", + "yuv420p", + ], + "preset-nvidia-h264": ["-c:v", "h264_cuvid"], + "preset-nvidia-h265": ["-c:v", "hevc_cuvid"], } -def parse_preset_hardware_acceleration(arg: Any) -> str: +def parse_preset_hardware_acceleration(arg: Any) -> list[str]: """Return the correct preset if in preset format otherwise return raw input.""" if not isinstance(arg, str): return None @@ -24,17 +38,118 @@ def parse_preset_hardware_acceleration(arg: Any) -> str: PRESETS_INPUT = { - "preset-http-jpeg-generic": "-r {} -stream_loop -1 -f image2 -avoid_negative_ts make_zero -fflags nobuffer -flags low_delay -strict experimental -fflags +genpts+discardcorrupt -use_wallclock_as_timestamps 1", - "preset-http-mjpeg-generic": "-avoid_negative_ts make_zero -fflags nobuffer -flags low_delay -strict experimental -fflags +genpts+discardcorrupt -use_wallclock_as_timestamps 1", - "preset-http-reolink": "-avoid_negative_ts make_zero -fflags +genpts+discardcorrupt -flags low_delay -strict experimental -analyzeduration 1000M -probesize 1000M -rw_timeout 5000000", - "preset-rtmp-generic": "-avoid_negative_ts make_zero -fflags nobuffer -flags low_delay -strict experimental -fflags +genpts+discardcorrupt -rw_timeout 5000000 -use_wallclock_as_timestamps 1 -f live_flv", - "preset-rtsp-generic": "-avoid_negative_ts make_zero -fflags +genpts+discardcorrupt -rtsp_transport tcp -timeout 5000000 -use_wallclock_as_timestamps 1", - "preset-rtsp-udp": "-avoid_negative_ts make_zero -fflags +genpts+discardcorrupt -rtsp_transport udp -timeout 5000000 -use_wallclock_as_timestamps 1", - "preset-rtsp-blue-iris": "-avoid_negative_ts make_zero -flags low_delay -strict experimental -fflags +genpts+discardcorrupt -rtsp_transport tcp -timeout 5000000 -use_wallclock_as_timestamps 1", + "preset-http-jpeg-generic": [ + "-r", + "{}", + "-stream_loop", + "-1", + "-f", + "image2", + "-avoid_negative_ts", + "make_zero", + "-fflags", + "nobuffer", + "-flags", + "low_delay", + "-strict", + "experimental", + "-fflags", + "+genpts+discardcorrupt", + "-use_wallclock_as_timestamps", + "1", + ], + "preset-http-mjpeg-generic": [ + "-avoid_negative_ts", + "make_zero", + "-fflags", + "nobuffer", + "-flags", + "low_delay", + "-strict", + "experimental", + "-fflags", + "+genpts+discardcorrupt", + "-use_wallclock_as_timestamps", + "1", + ], + "preset-http-reolink": [ + "-avoid_negative_ts", + "make_zero", + "-fflags", + "+genpts+discardcorrupt", + "-flags", + "low_delay", + "-strict", + "experimental", + "-analyzeduration", + "1000M", + "-probesize", + "1000M", + "-rw_timeout", + "5000000", + ], + "preset-rtmp-generic": [ + "-avoid_negative_ts", + "make_zero", + "-fflags", + "nobuffer", + "-flags", + "low_delay", + "-strict", + "experimental", + "-fflags", + "+genpts+discardcorrupt", + "-rw_timeout", + "5000000", + "-use_wallclock_as_timestamps", + "1", + "-f", + "live_flv", + ], + "preset-rtsp-generic": [ + "-avoid_negative_ts", + "make_zero", + "-fflags", + "+genpts+discardcorrupt", + "-rtsp_transport", + "tcp", + "-timeout", + "5000000", + "-use_wallclock_as_timestamps", + "1", + ], + "preset-rtsp-udp": [ + "-avoid_negative_ts", + "make_zero", + "-fflags", + "+genpts+discardcorrupt", + "-rtsp_transport", + "udp", + "-timeout", + "5000000", + "-use_wallclock_as_timestamps", + "1", + ], + "preset-rtsp-blue-iris": [ + "-avoid_negative_ts", + "make_zero", + "-flags", + "low_delay", + "-strict", + "experimental", + "-fflags", + "+genpts+discardcorrupt", + "-rtsp_transport", + "tcp", + "-timeout", + "5000000", + "-use_wallclock_as_timestamps", + "1", + ], } -def parse_preset_input(arg: Any, detect_fps: int) -> str: +def parse_preset_input(arg: Any, detect_fps: int) -> list[str]: """Return the correct preset if in preset format otherwise return raw input.""" if not isinstance(arg, str): return None @@ -46,15 +161,89 @@ def parse_preset_input(arg: Any, detect_fps: int) -> str: PRESETS_RECORD_OUTPUT = { - "preset-record-generic": "-f segment -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c copy -an", - "preset-record-generic-audio": "-f segment -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c:v copy -c:a aac", - "preset-record-mjpeg": "-f segment -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c:v libx264 -an", - "preset-record-jpeg": "-f segment -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c:v libx264 -an", - "preset-record-ubiquiti": "-f segment -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c:v copy -ar 44100 -c:a aac", + "preset-record-generic": [ + "-f", + "segment", + "-segment_time", + "10", + "-segment_format", + "mp4", + "-reset_timestamps", + "1", + "-strftime", + "1", + "-c", + "copy", + "-an", + ], + "preset-record-generic-audio": [ + "-f", + "segment", + "-segment_time", + "10", + "-segment_format", + "mp4", + "-reset_timestamps", + "1", + "-strftime", + "1", + "-c:v", + "copy", + "-c:a", + "aac", + ], + "preset-record-mjpeg": [ + "-f", + "segment", + "-segment_time", + "10", + "-segment_format", + "mp4", + "-reset_timestamps", + "1", + "-strftime", + "1", + "-c:v", + "libx264", + "-an", + ], + "preset-record-jpeg": [ + "-f", + "segment", + "-segment_time", + "10", + "-segment_format", + "mp4", + "-reset_timestamps", + "1", + "-strftime", + "1", + "-c:v", + "libx264", + "-an", + ], + "preset-record-ubiquiti": [ + "-f", + "segment", + "-segment_time", + "10", + "-segment_format", + "mp4", + "-reset_timestamps", + "1", + "-strftime", + "1", + "-c:v", + "copy", + "-ar", + "44100", + "-c:a", + "aac", + ], } -def parse_preset_output_record(arg: Any) -> str: +def parse_preset_output_record(arg: Any) -> list[str]: """Return the correct preset if in preset format otherwise return raw input.""" if not isinstance(arg, str): return None @@ -63,14 +252,23 @@ def parse_preset_output_record(arg: Any) -> str: PRESETS_RTMP_OUTPUT = { - "preset-rtmp-generic": "-c copy -f flv", - "preset-rtmp-mjpeg": "-c:v libx264 -an -f flv", - "preset-rtmp-jpeg": "-c:v libx264 -an -f flv", - "preset-rtmp-ubiquiti": "-c:v copy -f flv -ar 44100 -c:a aac", + "preset-rtmp-generic": ["-c", "copy", "-f", "flv"], + "preset-rtmp-mjpeg": ["-c:v", "libx264", "-an", "-f", "flv"], + "preset-rtmp-jpeg": ["-c:v", "libx264", "-an", "-f", "flv"], + "preset-rtmp-ubiquiti": [ + "-c:v", + "copy", + "-f", + "flv", + "-ar", + "44100", + "-c:a", + "aac", + ], } -def parse_preset_output_rtmp(arg: Any) -> str: +def parse_preset_output_rtmp(arg: Any) -> list[str]: """Return the correct preset if in preset format otherwise return raw input.""" if not isinstance(arg, str): return None diff --git a/frigate/test/test_ffmpeg_presets.py b/frigate/test/test_ffmpeg_presets.py index d3b47b052..531d98e4b 100644 --- a/frigate/test/test_ffmpeg_presets.py +++ b/frigate/test/test_ffmpeg_presets.py @@ -89,7 +89,7 @@ class TestFfmpegPresets(unittest.TestCase): assert "preset-rtmp-generic" not in ( " ".join(frigate_config.cameras["back"].ffmpeg_cmds[0]["cmd"]) ) - assert parse_preset_input("preset-rtmp-generic", 5) in ( + assert (" ".join(parse_preset_input("preset-rtmp-generic", 5))) in ( " ".join(frigate_config.cameras["back"].ffmpeg_cmds[0]["cmd"]) )