Auto select gpu for hwaccel presets (#5406)

* Add ability to GPU device to be automatically detected when multiple exist

* Add logging info

* Fix access

* Fix

* Formatting

* Fix path of device

* Use log error instead of raise

* Remove log which could apply to other caess

* Set default value

* rework logic and support auto gpu selection for encoding gpu as well
This commit is contained in:
Nicolas Mowen 2023-02-11 07:00:58 -07:00 committed by GitHub
parent babd976533
commit 562e2627c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 50 additions and 7 deletions

View File

@ -1,14 +1,52 @@
"""Handles inserting and maintaining ffmpeg presets.""" """Handles inserting and maintaining ffmpeg presets."""
import logging
import os import os
from typing import Any from typing import Any
from frigate.version import VERSION from frigate.version import VERSION
from frigate.const import BTBN_PATH 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" TIMEOUT_PARAM = "-timeout" if os.path.exists(BTBN_PATH) else "-stimeout"
_gpu_selector = LibvaGpuSelector()
_user_agent_args = [ _user_agent_args = [
"-user_agent", "-user_agent",
f"FFmpeg Frigate/{VERSION}", f"FFmpeg Frigate/{VERSION}",
@ -23,7 +61,7 @@ PRESETS_HW_ACCEL_DECODE = {
"-hwaccel", "-hwaccel",
"vaapi", "vaapi",
"-hwaccel_device", "-hwaccel_device",
"/dev/dri/renderD128", _gpu_selector.get_selected_gpu(),
"-hwaccel_output_format", "-hwaccel_output_format",
"vaapi", "vaapi",
], ],
@ -31,7 +69,7 @@ PRESETS_HW_ACCEL_DECODE = {
"-hwaccel", "-hwaccel",
"qsv", "qsv",
"-qsv_device", "-qsv_device",
"/dev/dri/renderD128", _gpu_selector.get_selected_gpu(),
"-hwaccel_output_format", "-hwaccel_output_format",
"qsv", "qsv",
"-c:v", "-c:v",
@ -43,7 +81,7 @@ PRESETS_HW_ACCEL_DECODE = {
"-hwaccel", "-hwaccel",
"qsv", "qsv",
"-qsv_device", "-qsv_device",
"/dev/dri/renderD128", _gpu_selector.get_selected_gpu(),
"-hwaccel_output_format", "-hwaccel_output_format",
"qsv", "qsv",
"-c:v", "-c:v",
@ -95,7 +133,7 @@ PRESETS_HW_ACCEL_SCALE = {
PRESETS_HW_ACCEL_ENCODE = { PRESETS_HW_ACCEL_ENCODE = {
"preset-rpi-32-h264": "ffmpeg -hide_banner {0} -c:v h264_v4l2m2m -g 50 -bf 0 {1}", "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-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-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-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-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( return PRESETS_HW_ACCEL_ENCODE.get(arg, PRESETS_HW_ACCEL_ENCODE["default"]).format(
input, input,
output, output,
_gpu_selector.get_selected_gpu(),
) )

View File

@ -14,7 +14,7 @@ from abc import ABC, abstractmethod
from collections import Counter from collections import Counter
from collections.abc import Mapping from collections.abc import Mapping
from multiprocessing import shared_memory from multiprocessing import shared_memory
from typing import Any, AnyStr, Tuple from typing import Any, AnyStr, Optional, Tuple
import cv2 import cv2
import numpy as np import numpy as np
@ -976,9 +976,13 @@ def ffprobe_stream(path: str) -> sp.CompletedProcess:
return sp.run(ffprobe_cmd, capture_output=True) 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.""" """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) return sp.run(ffprobe_cmd, capture_output=True)