From 4623a6b4bc4c89ceb5db684e2e7fbd57d01129aa Mon Sep 17 00:00:00 2001 From: Carlo Castoldi Date: Mon, 27 Sep 2021 20:37:52 +0200 Subject: [PATCH] obs-ffmpeg: Set DRI devices and their name persistently retrieving the DRI devices from /dev/dri/by-path/ instead of /dev/dri/renderDXXX. This enable us to use lspci to get the device name as well. --- .github/workflows/main.yml | 3 +- cmake/Modules/FindLibpci.cmake | 49 +++++++++++++++ plugins/obs-ffmpeg/CMakeLists.txt | 8 ++- plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c | 89 ++++++++++++++++++++++++--- 4 files changed, 138 insertions(+), 11 deletions(-) create mode 100644 cmake/Modules/FindLibpci.cmake diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5885a2ccf..acc747c2d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -441,7 +441,8 @@ jobs: qtbase5-private-dev \ libqt5svg5-dev \ swig \ - libcmocka-dev + libcmocka-dev \ + libpci-dev - name: 'Restore Chromium Embedded Framework from cache' id: cef-cache uses: actions/cache@v2.1.2 diff --git a/cmake/Modules/FindLibpci.cmake b/cmake/Modules/FindLibpci.cmake new file mode 100644 index 000000000..63fd5873b --- /dev/null +++ b/cmake/Modules/FindLibpci.cmake @@ -0,0 +1,49 @@ +# * Try to find Libpci +# Once done this will define +# +# LIBPCI_FOUND - system has Libpci +# LIBPCI_INCLUDE_DIRS - the Libpci include directory +# LIBPCI_LIBRARIES - the libraries needed to use Libpci +# LIBPCI_DEFINITIONS - Compiler switches required for using Libpci + +# Use pkg-config to get the directories and then use these values in the +# find_path() and find_library() calls + +find_package(PkgConfig QUIET) +if(PKG_CONFIG_FOUND) + pkg_check_modules(_LIBPCI libpci) +endif() + +find_path( + LIBPCI_INCLUDE_DIR + NAMES pci.h + HINTS ${_LIBPCI_INCLUDE_DIRS} + PATHS /usr/include /usr/local/include /opt/local/include + PATH_SUFFIXES pci/) + +find_library( + LIBPCI_LIB + NAMES ${_LIBPCI_LIBRARIES} libpci + HINTS ${_LIBPCI_LIBRARY_DIRS} + PATHS /usr/lib /usr/local/lib /opt/local/lib) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Libpci REQUIRED_VARS LIBPCI_LIB LIBPCI_INCLUDE_DIR) +mark_as_advanced(LIBPCI_INCLUDE_DIR LIBPCI_LIB) + +if(LIBPCI_FOUND) + set(LIBPCI_INCLUDE_DIRS ${LIBPCI_INCLUDE_DIR}) + set(LIBPCI_LIBRARIES ${LIBPCI_LIB}) + + if(NOT TARGET LIBPCI::LIBPCI) + if(IS_ABSOLUTE "${LIBPCI_LIBRARIES}") + add_library(LIBPCI::LIBPCI UNKNOWN IMPORTED) + set_target_properties(LIBPCI::LIBPCI PROPERTIES IMPORTED_LOCATION + "${LIBPCI_LIBRARIES}") + else() + add_library(LIBPCI::LIBPCI INTERFACE IMPORTED) + set_target_properties(LIBPCI::LIBPCI PROPERTIES IMPORTED_LIBNAME + "${LIBPCI_LIBRARIES}") + endif() + endif() +endif() diff --git a/plugins/obs-ffmpeg/CMakeLists.txt b/plugins/obs-ffmpeg/CMakeLists.txt index 31d12dcbf..b257d6df6 100644 --- a/plugins/obs-ffmpeg/CMakeLists.txt +++ b/plugins/obs-ffmpeg/CMakeLists.txt @@ -11,6 +11,11 @@ find_package(FFmpeg REQUIRED COMPONENTS avcodec avfilter avdevice avutil swscale avformat swresample) include_directories(${FFMPEG_INCLUDE_DIRS}) +if(UNIX AND NOT APPLE) + find_package(Libpci REQUIRED) + include_directories(${LIBPCI_INCLUDE_DIRS}) +endif() + configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/obs-ffmpeg-config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/obs-ffmpeg-config.h") @@ -38,7 +43,8 @@ if(UNIX AND NOT APPLE) list(APPEND obs-ffmpeg_SOURCES obs-ffmpeg-vaapi.c) LIST(APPEND obs-ffmpeg_PLATFORM_DEPS - ${LIBVA_LBRARIES}) + ${LIBVA_LBRARIES} + ${LIBPCI_LIBRARIES}) endif() if(ENABLE_FFMPEG_LOGGING) diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c b/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c index 445c5a792..1598d39db 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,8 @@ #include #include +#include + #include "obs-ffmpeg-formats.h" #define do_log(level, format, ...) \ @@ -538,6 +541,31 @@ static bool rate_control_modified(obs_properties_t *ppts, obs_property_t *p, return true; } +static bool get_device_name_from_pci(struct pci_access *pacc, char *pci_slot, + char *buf, int size) +{ + struct pci_filter filter; + struct pci_dev *dev; + char *name; + + pci_filter_init(pacc, &filter); + if (pci_filter_parse_slot(&filter, pci_slot)) + return false; + + pci_scan_bus(pacc); + for (dev = pacc->devices; dev; dev = dev->next) { + if (pci_filter_match(&filter, dev)) { + pci_fill_info(dev, PCI_FILL_IDENT); + name = pci_lookup_name(pacc, buf, size, + PCI_LOOKUP_DEVICE, + dev->vendor_id, dev->device_id); + strcpy(buf, name); + return true; + } + } + return false; +} + static obs_properties_t *vaapi_properties(void *unused) { UNUSED_PARAMETER(unused); @@ -549,15 +577,58 @@ static obs_properties_t *vaapi_properties(void *unused) obs_module_text("VAAPI.Device"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); - char path[32] = "/dev/dri/renderD1"; - for (int i = 28;; i++) { - sprintf(path, "/dev/dri/renderD1%d", i); - if (access(path, F_OK) == 0) { - char card[128] = "Card: "; - sprintf(card, "Card%d: %s", i - 28, path); - obs_property_list_add_string(list, card, path); - } else { - break; + if (os_file_exists("/dev/dri/by-path")) { + os_dir_t *by_path_dir = os_opendir("/dev/dri/by-path"); + struct pci_access *pacc = pci_alloc(); + struct os_dirent *file; + char namebuf[1024]; + char pci_slot[13]; + char *type; + + pci_init(pacc); + while ((file = os_readdir(by_path_dir)) != NULL) { + // file_name pattern: pci-- + char *file_name = file->d_name; + if (strcmp(file_name, ".") == 0 || + strcmp(file_name, "..") == 0) + continue; + + char path[64] = "\0"; + sprintf(path, "/dev/dri/by-path/%s", file_name); + type = strrchr(file_name, '-'); + if (type == NULL) + continue; + else + type++; + + if (strcmp(type, "render") == 0) { + strncpy(pci_slot, file_name + 4, 12); + pci_slot[12] = 0; + bool name_found = get_device_name_from_pci( + pacc, pci_slot, namebuf, + sizeof(namebuf)); + if (!name_found) + obs_property_list_add_string(list, path, + path); + else + obs_property_list_add_string( + list, namebuf, path); + } + } + pci_cleanup(pacc); + os_closedir(by_path_dir); + } + if (obs_property_list_item_count(list) == 0) { + char path[32] = "/dev/dri/renderD1"; + for (int i = 28;; i++) { + sprintf(path, "/dev/dri/renderD1%d", i); + if (access(path, F_OK) == 0) { + char card[128] = "Card: "; + sprintf(card, "Card%d: %s", i - 28, path); + obs_property_list_add_string(list, card, path); + } else { + break; + } } }