diff --git a/docs/docs/configuration/ffmpeg_presets.md b/docs/docs/configuration/ffmpeg_presets.md index e39d1f164..def84c7c0 100644 --- a/docs/docs/configuration/ffmpeg_presets.md +++ b/docs/docs/configuration/ffmpeg_presets.md @@ -18,9 +18,7 @@ See [the hwaccel docs](/configuration/hardware_acceleration.md) for more info on | preset-vaapi | Intel & AMD VAAPI | Check hwaccel docs to ensure correct driver is chosen | | preset-intel-qsv-h264 | Intel QSV with h264 stream | If issues occur recommend using vaapi preset instead | | preset-intel-qsv-h265 | Intel QSV with h265 stream | If issues occur recommend using vaapi preset instead | -| preset-nvidia-h264 | Nvidia GPU with h264 stream | | -| preset-nvidia-h265 | Nvidia GPU with h265 stream | | -| preset-nvidia-mjpeg | Nvidia GPU with mjpeg stream | Recommend restreaming mjpeg and using nvidia-h264 | +| preset-nvidia | Nvidia GPU | | | preset-jetson-h264 | Nvidia Jetson with h264 stream | | | preset-jetson-h265 | Nvidia Jetson with h265 stream | | | preset-rk-h264 | Rockchip MPP with h264 stream | Use image with *-rk suffix and privileged mode | diff --git a/docs/docs/configuration/hardware_acceleration.md b/docs/docs/configuration/hardware_acceleration.md index ad9d27211..4b3444d30 100644 --- a/docs/docs/configuration/hardware_acceleration.md +++ b/docs/docs/configuration/hardware_acceleration.md @@ -5,7 +5,9 @@ title: Hardware Acceleration # Hardware Acceleration -It is recommended to update your configuration to enable hardware accelerated decoding in ffmpeg. Depending on your system, these parameters may not be compatible. More information on hardware accelerated decoding for ffmpeg can be found here: https://trac.ffmpeg.org/wiki/HWAccelIntro +It is highly recommended to use a GPU for hardware acceleration in Frigate. Some types of hardware acceleration are detected and used automatically, but you may need to update your configuration to enable hardware accelerated decoding in ffmpeg. + +Depending on your system, these parameters may not be compatible. More information on hardware accelerated decoding for ffmpeg can be found here: https://trac.ffmpeg.org/wiki/HWAccelIntro # Officially Supported diff --git a/docs/docs/configuration/reference.md b/docs/docs/configuration/reference.md index 584560ea5..1565258d0 100644 --- a/docs/docs/configuration/reference.md +++ b/docs/docs/configuration/reference.md @@ -151,9 +151,9 @@ birdseye: ffmpeg: # Optional: global ffmpeg args (default: shown below) global_args: -hide_banner -loglevel warning -threads 2 - # Optional: global hwaccel args (default: shown below) + # Optional: global hwaccel args (default: auto detect) # NOTE: See hardware acceleration docs for your specific device - hwaccel_args: [] + hwaccel_args: "auto" # Optional: global input args (default: shown below) input_args: preset-rtsp-generic # Optional: global output args diff --git a/frigate/config.py b/frigate/config.py index 3f68f302a..4ee51a1f9 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -39,7 +39,7 @@ from frigate.util.builtin import ( load_config_with_no_duplicates, ) from frigate.util.image import create_mask -from frigate.util.services import get_video_properties +from frigate.util.services import auto_detect_hwaccel, get_video_properties logger = logging.getLogger(__name__) @@ -600,7 +600,7 @@ class FfmpegConfig(FrigateBaseModel): default=FFMPEG_GLOBAL_ARGS_DEFAULT, title="Global FFmpeg arguments." ) hwaccel_args: Union[str, List[str]] = Field( - default_factory=list, title="FFmpeg hardware acceleration arguments." + default="auto", title="FFmpeg hardware acceleration arguments." ) input_args: Union[str, List[str]] = Field( default=FFMPEG_INPUT_ARGS_DEFAULT, title="FFmpeg input arguments." @@ -1097,6 +1097,10 @@ class FrigateConfig(FrigateBaseModel): elif config.objects.filters[attribute].min_score == 0.5: config.objects.filters[attribute].min_score = 0.7 + # auto detect hwaccel args + if config.ffmpeg.hwaccel_args == "auto": + config.ffmpeg.hwaccel_args = auto_detect_hwaccel() + # Global config to propagate down to camera level global_config = config.dict( include={ diff --git a/frigate/const.py b/frigate/const.py index d00221341..97e33b689 100644 --- a/frigate/const.py +++ b/frigate/const.py @@ -35,6 +35,11 @@ AUDIO_MAX_BIT_RANGE = 32768.0 AUDIO_SAMPLE_RATE = 16000 AUDIO_MIN_CONFIDENCE = 0.5 +# Ffmpeg Presets + +FFMPEG_HWACCEL_NVIDIA = "preset-nvidia" +FFMPEG_HWACCEL_VAAPI = "preset-vaapi" + # Regex Consts REGEX_CAMERA_NAME = r"^[a-zA-Z0-9_-]+$" diff --git a/frigate/ffmpeg_presets.py b/frigate/ffmpeg_presets.py index 82ca92dda..96314e6a5 100644 --- a/frigate/ffmpeg_presets.py +++ b/frigate/ffmpeg_presets.py @@ -5,6 +5,7 @@ import os from enum import Enum from typing import Any +from frigate.const import FFMPEG_HWACCEL_NVIDIA, FFMPEG_HWACCEL_VAAPI from frigate.util.services import vainfo_hwaccel from frigate.version import VERSION @@ -62,55 +63,72 @@ _user_agent_args = [ PRESETS_HW_ACCEL_DECODE = { "preset-rpi-64-h264": "-c:v:1 h264_v4l2m2m", "preset-rpi-64-h265": "-c:v:1 hevc_v4l2m2m", - "preset-vaapi": f"-hwaccel_flags allow_profile_mismatch -hwaccel vaapi -hwaccel_device {_gpu_selector.get_selected_gpu()} -hwaccel_output_format vaapi", + FFMPEG_HWACCEL_VAAPI: f"-hwaccel_flags allow_profile_mismatch -hwaccel vaapi -hwaccel_device {_gpu_selector.get_selected_gpu()} -hwaccel_output_format vaapi", "preset-intel-qsv-h264": f"-hwaccel qsv -qsv_device {_gpu_selector.get_selected_gpu()} -hwaccel_output_format qsv -c:v h264_qsv", "preset-intel-qsv-h265": f"-load_plugin hevc_hw -hwaccel qsv -qsv_device {_gpu_selector.get_selected_gpu()} -hwaccel_output_format qsv -c:v hevc_qsv", - "preset-nvidia-h264": "-hwaccel cuda -hwaccel_output_format cuda", - "preset-nvidia-h265": "-hwaccel cuda -hwaccel_output_format cuda", - "preset-nvidia-mjpeg": "-hwaccel cuda -hwaccel_output_format cuda", + FFMPEG_HWACCEL_NVIDIA: "-hwaccel cuda -hwaccel_output_format cuda", "preset-jetson-h264": "-c:v h264_nvmpi -resize {1}x{2}", "preset-jetson-h265": "-c:v hevc_nvmpi -resize {1}x{2}", "preset-rk-h264": "-c:v h264_rkmpp_decoder", "preset-rk-h265": "-c:v hevc_rkmpp_decoder", } +PRESETS_HW_ACCEL_DECODE["preset-nvidia-h264"] = PRESETS_HW_ACCEL_DECODE[ + FFMPEG_HWACCEL_NVIDIA +] +PRESETS_HW_ACCEL_DECODE["preset-nvidia-h265"] = PRESETS_HW_ACCEL_DECODE[ + FFMPEG_HWACCEL_NVIDIA +] +PRESETS_HW_ACCEL_DECODE["preset-nvidia-mjpeg"] = PRESETS_HW_ACCEL_DECODE[ + FFMPEG_HWACCEL_NVIDIA +] PRESETS_HW_ACCEL_SCALE = { "preset-rpi-64-h264": "-r {0} -vf fps={0},scale={1}:{2}", "preset-rpi-64-h265": "-r {0} -vf fps={0},scale={1}:{2}", - "preset-vaapi": "-r {0} -vf fps={0},scale_vaapi=w={1}:h={2}:format=nv12,hwdownload,format=nv12,format=yuv420p", + FFMPEG_HWACCEL_VAAPI: "-r {0} -vf fps={0},scale_vaapi=w={1}:h={2}:format=nv12,hwdownload,format=nv12,format=yuv420p", "preset-intel-qsv-h264": "-r {0} -vf vpp_qsv=framerate={0}:w={1}:h={2}:format=nv12,hwdownload,format=nv12,format=yuv420p", "preset-intel-qsv-h265": "-r {0} -vf vpp_qsv=framerate={0}:w={1}:h={2}:format=nv12,hwdownload,format=nv12,format=yuv420p", - "preset-nvidia-h264": "-r {0} -vf fps={0},scale_cuda=w={1}:h={2}:format=nv12,hwdownload,format=nv12,format=yuv420p", - "preset-nvidia-h265": "-r {0} -vf fps={0},scale_cuda=w={1}:h={2}:format=nv12,hwdownload,format=nv12,format=yuv420p", + FFMPEG_HWACCEL_NVIDIA: "-r {0} -vf fps={0},scale_cuda=w={1}:h={2}:format=nv12,hwdownload,format=nv12,format=yuv420p", "preset-jetson-h264": "-r {0}", # scaled in decoder "preset-jetson-h265": "-r {0}", # scaled in decoder "preset-rk-h264": "-r {0} -vf fps={0},scale={1}:{2}", "preset-rk-h265": "-r {0} -vf fps={0},scale={1}:{2}", "default": "-r {0} -vf fps={0},scale={1}:{2}", } +PRESETS_HW_ACCEL_SCALE["preset-nvidia-h264"] = PRESETS_HW_ACCEL_SCALE[ + FFMPEG_HWACCEL_NVIDIA +] +PRESETS_HW_ACCEL_SCALE["preset-nvidia-h265"] = PRESETS_HW_ACCEL_SCALE[ + FFMPEG_HWACCEL_NVIDIA +] PRESETS_HW_ACCEL_ENCODE_BIRDSEYE = { "preset-rpi-64-h264": "ffmpeg -hide_banner {0} -c:v h264_v4l2m2m {1}", "preset-rpi-64-h265": "ffmpeg -hide_banner {0} -c:v hevc_v4l2m2m {1}", - "preset-vaapi": "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -hwaccel_device {2} {0} -c:v h264_vaapi -g 50 -bf 0 -profile:v high -level:v 4.1 -sei:v 0 -an -vf format=vaapi|nv12,hwupload {1}", + FFMPEG_HWACCEL_VAAPI: "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -hwaccel_device {2} {0} -c:v h264_vaapi -g 50 -bf 0 -profile:v high -level:v 4.1 -sei:v 0 -an -vf format=vaapi|nv12,hwupload {1}", "preset-intel-qsv-h264": "ffmpeg -hide_banner {0} -c:v h264_qsv -g 50 -bf 0 -profile:v high -level:v 4.1 -async_depth:v 1 {1}", "preset-intel-qsv-h265": "ffmpeg -hide_banner {0} -c:v h264_qsv -g 50 -bf 0 -profile:v high -level:v 4.1 -async_depth:v 1 {1}", - "preset-nvidia-h264": "ffmpeg -hide_banner {0} -c:v h264_nvenc -g 50 -profile:v high -level:v auto -preset:v p2 -tune:v ll {1}", - "preset-nvidia-h265": "ffmpeg -hide_banner {0} -c:v h264_nvenc -g 50 -profile:v high -level:v auto -preset:v p2 -tune:v ll {1}", + FFMPEG_HWACCEL_NVIDIA: "ffmpeg -hide_banner {0} -c:v h264_nvenc -g 50 -profile:v high -level:v auto -preset:v p2 -tune:v ll {1}", "preset-jetson-h264": "ffmpeg -hide_banner {0} -c:v h264_nvmpi -profile high {1}", "preset-jetson-h265": "ffmpeg -hide_banner {0} -c:v h264_nvmpi -profile high {1}", "preset-rk-h264": "ffmpeg -hide_banner {0} -c:v h264_rkmpp_encoder -profile high {1}", "preset-rk-h265": "ffmpeg -hide_banner {0} -c:v hevc_rkmpp_encoder -profile high {1}", "default": "ffmpeg -hide_banner {0} -c:v libx264 -g 50 -profile:v high -level:v 4.1 -preset:v superfast -tune:v zerolatency {1}", } +PRESETS_HW_ACCEL_ENCODE_BIRDSEYE[ + "preset-nvidia-h264" +] = PRESETS_HW_ACCEL_ENCODE_BIRDSEYE[FFMPEG_HWACCEL_NVIDIA] +PRESETS_HW_ACCEL_ENCODE_BIRDSEYE[ + "preset-nvidia-h265" +] = PRESETS_HW_ACCEL_ENCODE_BIRDSEYE[FFMPEG_HWACCEL_NVIDIA] PRESETS_HW_ACCEL_ENCODE_TIMELAPSE = { "preset-rpi-64-h264": "ffmpeg -hide_banner {0} -c:v h264_v4l2m2m -pix_fmt yuv420p {1}", "preset-rpi-64-h265": "ffmpeg -hide_banner {0} -c:v hevc_v4l2m2m -pix_fmt yuv420p {1}", - "preset-vaapi": "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -hwaccel_device {2} {0} -c:v h264_vaapi {1}", + FFMPEG_HWACCEL_VAAPI: "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -hwaccel_device {2} {0} -c:v h264_vaapi {1}", "preset-intel-qsv-h264": "ffmpeg -hide_banner {0} -c:v h264_qsv -profile:v high -level:v 4.1 -async_depth:v 1 {1}", "preset-intel-qsv-h265": "ffmpeg -hide_banner {0} -c:v hevc_qsv -profile:v high -level:v 4.1 -async_depth:v 1 {1}", - "preset-nvidia-h264": "ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 8 {0} -c:v h264_nvenc {1}", + FFMPEG_HWACCEL_NVIDIA: "ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 8 {0} -c:v h264_nvenc {1}", "preset-nvidia-h265": "ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 8 {0} -c:v hevc_nvenc {1}", "preset-jetson-h264": "ffmpeg -hide_banner {0} -c:v h264_nvmpi -profile high {1}", "preset-jetson-h265": "ffmpeg -hide_banner {0} -c:v hevc_nvmpi -profile high {1}", @@ -118,6 +136,9 @@ PRESETS_HW_ACCEL_ENCODE_TIMELAPSE = { "preset-rk-h265": "ffmpeg -hide_banner {0} -c:v hevc_rkmpp_encoder -profile high {1}", "default": "ffmpeg -hide_banner {0} -c:v libx264 -preset:v ultrafast -tune:v zerolatency {1}", } +PRESETS_HW_ACCEL_ENCODE_TIMELAPSE[ + "preset-nvidia-h264" +] = PRESETS_HW_ACCEL_ENCODE_TIMELAPSE[FFMPEG_HWACCEL_NVIDIA] # encoding of previews is only done on CPU due to comparable encode times and better quality from libx264 PRESETS_HW_ACCEL_ENCODE_PREVIEW = { diff --git a/frigate/util/services.py b/frigate/util/services.py index ef92b3153..1c3adbde0 100644 --- a/frigate/util/services.py +++ b/frigate/util/services.py @@ -13,7 +13,9 @@ from typing import Optional import cv2 import psutil import py3nvml.py3nvml as nvml +import requests +from frigate.const import FFMPEG_HWACCEL_NVIDIA, FFMPEG_HWACCEL_VAAPI from frigate.util.builtin import clean_camera_user_pass, escape_special_characters logger = logging.getLogger(__name__) @@ -371,6 +373,38 @@ def vainfo_hwaccel(device_name: Optional[str] = None) -> sp.CompletedProcess: return sp.run(ffprobe_cmd, capture_output=True) +def auto_detect_hwaccel() -> str: + """Detect hwaccel args by default.""" + try: + cuda = False + vaapi = False + resp = requests.get("http://192.168.50.106:1984/api/ffmpeg/hardware", timeout=3) + + if resp.status_code == 200: + data: dict[str, list[dict[str, str]]] = resp.json() + for source in data.get("sources", []): + if "cuda" in source.get("url", "") and source.get("name") == "OK": + cuda = True + + if "vaapi" in source.get("url", "") and source.get("name") == "OK": + vaapi = True + except requests.RequestException: + pass + + if cuda: + logger.info("Automatically detected nvidia hwaccel for video decoding") + return FFMPEG_HWACCEL_NVIDIA + + if vaapi: + logger.info("Automatically detected vaapi hwaccel for video decoding") + return FFMPEG_HWACCEL_VAAPI + + logger.warning( + "Did not detect hwaccel, using a GPU for accelerated video decoding is highly recommended" + ) + return "" + + async def get_video_properties(url, get_duration=False) -> dict[str, any]: async def calculate_duration(video: Optional[any]) -> float: duration = None