Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto select gpu for hwaccel presets #5406

Merged
merged 10 commits into from
Feb 11, 2023
Merged
47 changes: 43 additions & 4 deletions frigate/ffmpeg_presets.py
Original file line number Diff line number Diff line change
@@ -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}",
Expand All @@ -23,15 +61,15 @@
"-hwaccel",
"vaapi",
"-hwaccel_device",
"/dev/dri/renderD128",
_gpu_selector.get_selected_gpu(),
"-hwaccel_output_format",
"vaapi",
],
"preset-intel-qsv-h264": [
"-hwaccel",
"qsv",
"-qsv_device",
"/dev/dri/renderD128",
_gpu_selector.get_selected_gpu(),
"-hwaccel_output_format",
"qsv",
"-c:v",
Expand All @@ -43,7 +81,7 @@
"-hwaccel",
"qsv",
"-qsv_device",
"/dev/dri/renderD128",
_gpu_selector.get_selected_gpu(),
"-hwaccel_output_format",
"qsv",
"-c:v",
Expand Down Expand Up @@ -95,7 +133,7 @@
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}",
Expand Down Expand Up @@ -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(),
)


Expand Down
10 changes: 7 additions & 3 deletions frigate/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
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
Expand Down Expand Up @@ -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)


Expand Down