diff --git a/frigate/ffmpeg_presets.py b/frigate/ffmpeg_presets.py index a9bd3059e..0f94fb5c1 100644 --- a/frigate/ffmpeg_presets.py +++ b/frigate/ffmpeg_presets.py @@ -1,14 +1,52 @@ """Handles inserting and maintaining ffmpeg presets.""" +import logging import os from typing import Any from frigate.version import VERSION from frigate.const import BTBN_PATH +from frigate.util import vainfo_hwaccel + + +logger = logging.getLogger(__name__) + + +class LibvaGpuSelector: + "Automatically selects the correct libva GPU." + + _selected_gpu = None + + def get_selected_gpu(self) -> str: + """Get selected libva GPU.""" + if not os.path.exists("/dev/dri"): + return "" + + if self._selected_gpu: + return self._selected_gpu + + devices = list(filter(lambda d: d.startswith("render"), os.listdir("/dev/dri"))) + + if len(devices) < 2: + self._selected_gpu = "/dev/dri/renderD128" + return self._selected_gpu + + for device in devices: + check = vainfo_hwaccel(device_name=device) + + logger.debug(f"{device} return vainfo status code: {check.returncode}") + + if check.returncode == 0: + self._selected_gpu = f"/dev/dri/{device}" + return self._selected_gpu + + return "" + TIMEOUT_PARAM = "-timeout" if os.path.exists(BTBN_PATH) else "-stimeout" +_gpu_selector = LibvaGpuSelector() _user_agent_args = [ "-user_agent", f"FFmpeg Frigate/{VERSION}", @@ -23,7 +61,7 @@ PRESETS_HW_ACCEL_DECODE = { "-hwaccel", "vaapi", "-hwaccel_device", - "/dev/dri/renderD128", + _gpu_selector.get_selected_gpu(), "-hwaccel_output_format", "vaapi", ], @@ -31,7 +69,7 @@ PRESETS_HW_ACCEL_DECODE = { "-hwaccel", "qsv", "-qsv_device", - "/dev/dri/renderD128", + _gpu_selector.get_selected_gpu(), "-hwaccel_output_format", "qsv", "-c:v", @@ -43,7 +81,7 @@ PRESETS_HW_ACCEL_DECODE = { "-hwaccel", "qsv", "-qsv_device", - "/dev/dri/renderD128", + _gpu_selector.get_selected_gpu(), "-hwaccel_output_format", "qsv", "-c:v", @@ -95,7 +133,7 @@ PRESETS_HW_ACCEL_SCALE = { PRESETS_HW_ACCEL_ENCODE = { "preset-rpi-32-h264": "ffmpeg -hide_banner {0} -c:v h264_v4l2m2m -g 50 -bf 0 {1}", "preset-rpi-64-h264": "ffmpeg -hide_banner {0} -c:v h264_v4l2m2m -g 50 -bf 0 {1}", - "preset-vaapi": "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi {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-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}", @@ -143,6 +181,7 @@ def parse_preset_hardware_acceleration_encode(arg: Any, input: str, output: str) return PRESETS_HW_ACCEL_ENCODE.get(arg, PRESETS_HW_ACCEL_ENCODE["default"]).format( input, output, + _gpu_selector.get_selected_gpu(), ) diff --git a/frigate/util.py b/frigate/util.py index 02433b358..6a44811ba 100755 --- a/frigate/util.py +++ b/frigate/util.py @@ -14,7 +14,7 @@ from abc import ABC, abstractmethod from collections import Counter from collections.abc import Mapping from multiprocessing import shared_memory -from typing import Any, AnyStr, Tuple +from typing import Any, AnyStr, Optional, Tuple import cv2 import numpy as np @@ -976,9 +976,13 @@ def ffprobe_stream(path: str) -> sp.CompletedProcess: return sp.run(ffprobe_cmd, capture_output=True) -def vainfo_hwaccel() -> sp.CompletedProcess: +def vainfo_hwaccel(device_name: Optional[str] = None) -> sp.CompletedProcess: """Run vainfo.""" - ffprobe_cmd = ["vainfo"] + ffprobe_cmd = ( + ["vainfo"] + if not device_name + else ["vainfo", "--display", "drm", "--device", f"/dev/dri/{device_name}"] + ) return sp.run(ffprobe_cmd, capture_output=True)