Browse Source

obs-qsv11: Add a Linux implementation

This adds a CMake module for finding the QSV SDK (libmfx/onevpl) and an
the required platform components to initialize QSV with the VA-API
platform.
Kurt Kartaltepe 2 years ago
parent
commit
c6b470de9a

+ 3 - 2
CI/linux/01_install_dependencies.sh

@@ -93,13 +93,14 @@ install_dependencies() {
          libswscale-dev libx264-dev libcurl4-openssl-dev libmbedtls-dev libgl1-mesa-dev libjansson-dev \
          libluajit-5.1-dev python3-dev libx11-dev libxcb-randr0-dev libxcb-shm0-dev libxcb-xinerama0-dev \
          libxcb-composite0-dev libxinerama-dev libxcb1-dev libx11-xcb-dev libxcb-xfixes0-dev swig libcmocka-dev \
-         libpci-dev libxss-dev libglvnd-dev libgles2-mesa libgles2-mesa-dev libwayland-dev libxkbcommon-dev"
+         libpci-dev libxss-dev libglvnd-dev libgles2-mesa libgles2-mesa-dev libwayland-dev \
+         libxkbcommon-dev"
         "qt5-deps qtbase5-dev qtbase5-private-dev libqt5svg5-dev qtwayland5"
         "qt6-deps qt6-base-dev qt6-base-private-dev libqt6svg6-dev qt6-wayland"
         "cef ${LINUX_CEF_BUILD_VERSION:-${CI_LINUX_CEF_VERSION}}"
         "plugin-deps libasound2-dev libfdk-aac-dev libfontconfig-dev libfreetype6-dev libjack-jackd2-dev \
          libpulse-dev libsndio-dev libspeexdsp-dev libudev-dev libv4l-dev libva-dev libvlc-dev libdrm-dev \
-         nlohmann-json3-dev libwebsocketpp-dev libasio-dev"
+         nlohmann-json3-dev libwebsocketpp-dev libasio-dev libvpl-dev"
     )
 
     sudo apt-get -qq update

+ 6 - 0
CI/linux/02_build_obs.sh

@@ -53,6 +53,10 @@ _configure_obs() {
         PIPEWIRE_OPTION="-DENABLE_PIPEWIRE=OFF"
     fi
 
+    if [ "${DISABLE_QSV}" ]; then
+        QSV_OPTION="-DENABLE_QSV11=OFF"
+    fi
+
     cmake -S . -B ${BUILD_DIR} -G Ninja \
         -DCEF_ROOT_DIR="${DEPS_BUILD_DIR}/cef_binary_${LINUX_CEF_BUILD_VERSION:-${CI_LINUX_CEF_VERSION}}_linux64" \
         -DCMAKE_BUILD_TYPE=${BUILD_CONFIG} \
@@ -61,6 +65,7 @@ _configure_obs() {
         -DENABLE_NEW_MPEGTS_OUTPUT=OFF \
         -DENABLE_WEBRTC=OFF \
         ${PIPEWIRE_OPTION} \
+        ${QSV_OPTION} \
         ${YOUTUBE_OPTIONS} \
         ${TWITCH_OPTIONS} \
         ${RESTREAM_OPTIONS} \
@@ -116,6 +121,7 @@ build-obs-main() {
                 -v | --verbose ) export VERBOSE=TRUE; shift ;;
                 -p | --portable ) export PORTABLE=TRUE; shift ;;
                 --disable-pipewire ) DISABLE_PIPEWIRE=TRUE; shift ;;
+                --disable-qsv ) DISABLE_QSV=TRUE; shift ;;
                 --build-dir ) BUILD_DIR="${2}"; shift 2 ;;
                 -- ) shift; break ;;
                 * ) break ;;

+ 2 - 1
build-aux/com.obsproject.Studio.json

@@ -81,7 +81,8 @@
                 "-DENABLE_RTMPS=ON",
                 "-DENABLE_VLC=OFF",
                 "-DENABLE_AJA=ON",
-                "-DENABLE_LIBFDK=ON"
+                "-DENABLE_LIBFDK=ON",
+                "-DENABLE_QSV11=OFF"
             ],
             "secret-opts": [
                 "-DRESTREAM_CLIENTID=$RESTREAM_CLIENTID",

+ 47 - 0
cmake/Modules/FindVPL.cmake

@@ -0,0 +1,47 @@
+# * Try to find libvpl
+#
+# Once done this will define
+#
+# VPL_FOUND - system has intel media sdk VPL_INCLUDE_DIRS - the intel media sdk include directory VPL_LIBRARIES - the
+# libraries needed to use intel media sdk VPL_DEFINITIONS - Compiler switches required for using intel media sdk
+
+# 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(_VPL vpl)
+endif()
+
+find_path(
+  VPL_INCLUDE_DIR
+  NAMES mfxstructures.h
+  HINTS ${_VPL_INCLUDE_DIRS} ${_VPL_INCLUDE_DIRS}
+  PATHS /usr/include /usr/local/include /opt/local/include /sw/include
+  PATH_SUFFIXES vpl/)
+
+find_library(
+  VPL_LIB
+  NAMES ${_VPL_LIBRARIES} ${_VPL_LIBRARIES} vpl
+  HINTS ${_VPL_LIBRARY_DIRS} ${_VPL_LIBRARY_DIRS}
+  PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(VPL REQUIRED_VARS VPL_LIB VPL_INCLUDE_DIR)
+mark_as_advanced(VPL_INCLUDE_DIR VPL_LIB)
+
+if(VPL_FOUND)
+  set(VPL_INCLUDE_DIRS ${VPL_INCLUDE_DIR})
+  set(VPL_LIBRARIES ${VPL_LIB})
+
+  if(NOT TARGET VPL::VPL)
+    if(IS_ABSOLUTE "${VPL_LIBRARIES}")
+      add_library(VPL::VPL UNKNOWN IMPORTED)
+      set_target_properties(VPL::VPL PROPERTIES IMPORTED_LOCATION "${VPL_LIBRARIES}")
+    else()
+      add_library(VPL::VPL INTERFACE IMPORTED)
+      set_target_properties(VPL::VPL PROPERTIES IMPORTED_LIBNAME "${VPL_LIBRARIES}")
+    endif()
+
+    set_target_properties(VPL::VPL PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${VPL_INCLUDE_DIRS}")
+  endif()
+endif()

+ 1 - 0
plugins/CMakeLists.txt

@@ -153,6 +153,7 @@ elseif(OS_LINUX)
   add_subdirectory(vlc-video)
   add_subdirectory(sndio)
   add_subdirectory(obs-vst)
+  add_subdirectory(obs-qsv11)
 
   check_obs_browser()
 elseif(OS_FREEBSD)

+ 88 - 79
plugins/obs-qsv11/CMakeLists.txt

@@ -9,74 +9,14 @@ if(NOT ENABLE_QSV11)
   return()
 endif()
 
-add_library(libmfx INTERFACE)
-add_library(OBS::libmfx ALIAS libmfx)
-
-target_sources(
-  libmfx
-  INTERFACE # cmake-format: sortable
-            libmfx/include/mfx_critical_section.h
-            libmfx/include/mfx_dispatcher.h
-            libmfx/include/mfx_dispatcher_defs.h
-            libmfx/include/mfx_dispatcher_log.h
-            libmfx/include/mfx_driver_store_loader.h
-            libmfx/include/mfx_dxva2_device.h
-            libmfx/include/mfx_exposed_functions_list.h
-            libmfx/include/mfx_library_iterator.h
-            libmfx/include/mfx_load_dll.h
-            libmfx/include/mfx_load_plugin.h
-            libmfx/include/mfx_plugin_hive.h
-            libmfx/include/mfx_vector.h
-            libmfx/include/mfx_win_reg_key.h
-            libmfx/include/mfxaudio_exposed_functions_list.h
-            libmfx/include/msdk/include/mfxadapter.h
-            libmfx/include/msdk/include/mfxastructures.h
-            libmfx/include/msdk/include/mfxaudio++.h
-            libmfx/include/msdk/include/mfxaudio.h
-            libmfx/include/msdk/include/mfxcommon.h
-            libmfx/include/msdk/include/mfxdefs.h
-            libmfx/include/msdk/include/mfxjpeg.h
-            libmfx/include/msdk/include/mfxmvc.h
-            libmfx/include/msdk/include/mfxplugin++.h
-            libmfx/include/msdk/include/mfxplugin.h
-            libmfx/include/msdk/include/mfxsession.h
-            libmfx/include/msdk/include/mfxstructures.h
-            libmfx/include/msdk/include/mfxvideo++.h
-            libmfx/include/msdk/include/mfxvideo.h
-            libmfx/include/msdk/include/mfxvstructures.h
-            libmfx/src/main.cpp
-            libmfx/src/mfx_critical_section.cpp
-            libmfx/src/mfx_dispatcher.cpp
-            libmfx/src/mfx_dispatcher_log.cpp
-            libmfx/src/mfx_driver_store_loader.cpp
-            libmfx/src/mfx_dxva2_device.cpp
-            libmfx/src/mfx_function_table.cpp
-            libmfx/src/mfx_library_iterator.cpp
-            libmfx/src/mfx_load_dll.cpp
-            libmfx/src/mfx_load_plugin.cpp
-            libmfx/src/mfx_plugin_hive.cpp
-            libmfx/src/mfx_win_reg_key.cpp)
-
-target_include_directories(libmfx INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/libmfx/include/msdk/include"
-                                            "${CMAKE_CURRENT_SOURCE_DIR}/libmfx/include")
-
 add_library(obs-qsv11 MODULE)
 add_library(OBS::qsv11 ALIAS obs-qsv11)
 
 target_sources(
   obs-qsv11
   PRIVATE # cmake-format: sortable
-          bits/linux_defs.h
-          bits/windows_defs.h
-          common_directx11.cpp
-          common_directx11.h
-          common_directx9.cpp
-          common_directx9.h
           common_utils.cpp
           common_utils.h
-          common_utils_windows.cpp
-          device_directx9.cpp
-          device_directx9.h
           obs-qsv11-plugin-main.c
           obs-qsv11.c
           QSV_Encoder.cpp
@@ -84,29 +24,98 @@ target_sources(
           QSV_Encoder_Internal.cpp
           QSV_Encoder_Internal.h)
 
-configure_file(cmake/windows/obs-module.rc.in obs-qsv11.rc)
-target_sources(obs-qsv11 PRIVATE obs-qsv11.rc)
-
-target_compile_definitions(obs-qsv11 PRIVATE DX11_D3D)
-
-target_link_libraries(
-  obs-qsv11
-  PRIVATE OBS::libobs
-          OBS::libmfx
-          d3d9
-          d3d11
-          dxva2
-          dxgi
-          dxguid)
-
-add_subdirectory(obs-qsv-test)
+target_link_libraries(obs-qsv11 PRIVATE OBS::libobs)
 
 # cmake-format: off
 set_target_properties_obs(obs-qsv11 PROPERTIES FOLDER plugins/obs-qsv11 PREFIX "")
 # cmake-format: on
 
-get_target_property(target_sources libmfx SOURCES)
+if(OS_WINDOWS)
+  add_subdirectory(obs-qsv-test)
+
+  add_library(libmfx INTERFACE)
+  add_library(OBS::libmfx ALIAS libmfx)
+
+  target_sources(
+    libmfx
+    INTERFACE # cmake-format: sortable
+              libmfx/include/mfx_critical_section.h
+              libmfx/include/mfx_dispatcher.h
+              libmfx/include/mfx_dispatcher_defs.h
+              libmfx/include/mfx_dispatcher_log.h
+              libmfx/include/mfx_driver_store_loader.h
+              libmfx/include/mfx_dxva2_device.h
+              libmfx/include/mfx_exposed_functions_list.h
+              libmfx/include/mfx_library_iterator.h
+              libmfx/include/mfx_load_dll.h
+              libmfx/include/mfx_load_plugin.h
+              libmfx/include/mfx_plugin_hive.h
+              libmfx/include/mfx_vector.h
+              libmfx/include/mfx_win_reg_key.h
+              libmfx/include/mfxaudio_exposed_functions_list.h
+              libmfx/include/msdk/include/mfxadapter.h
+              libmfx/include/msdk/include/mfxastructures.h
+              libmfx/include/msdk/include/mfxaudio++.h
+              libmfx/include/msdk/include/mfxaudio.h
+              libmfx/include/msdk/include/mfxcommon.h
+              libmfx/include/msdk/include/mfxdefs.h
+              libmfx/include/msdk/include/mfxjpeg.h
+              libmfx/include/msdk/include/mfxmvc.h
+              libmfx/include/msdk/include/mfxplugin++.h
+              libmfx/include/msdk/include/mfxplugin.h
+              libmfx/include/msdk/include/mfxsession.h
+              libmfx/include/msdk/include/mfxstructures.h
+              libmfx/include/msdk/include/mfxvideo++.h
+              libmfx/include/msdk/include/mfxvideo.h
+              libmfx/include/msdk/include/mfxvstructures.h
+              libmfx/src/main.cpp
+              libmfx/src/mfx_critical_section.cpp
+              libmfx/src/mfx_dispatcher.cpp
+              libmfx/src/mfx_dispatcher_log.cpp
+              libmfx/src/mfx_driver_store_loader.cpp
+              libmfx/src/mfx_dxva2_device.cpp
+              libmfx/src/mfx_function_table.cpp
+              libmfx/src/mfx_library_iterator.cpp
+              libmfx/src/mfx_load_dll.cpp
+              libmfx/src/mfx_load_plugin.cpp
+              libmfx/src/mfx_plugin_hive.cpp
+              libmfx/src/mfx_win_reg_key.cpp)
+
+  target_include_directories(libmfx INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/libmfx/include/msdk/include"
+                                              "${CMAKE_CURRENT_SOURCE_DIR}/libmfx/include")
+  get_target_property(mfx_sources libmfx SOURCES)
+  list(FILTER mfx_sources INCLUDE REGEX ".*\\.(m|c[cp]?p?|swift)")
+  list(FILTER mfx_headers INCLUDE REGEX ".*\\.h(pp)?")
+  source_group("libmfx\\Source Files" FILES ${mfx_sources})
+  source_group("libmfx\\Header Files" FILES ${mfx_headers})
+
+  configure_file(cmake/windows/obs-module.rc.in obs-qsv11.rc)
+  target_sources(obs-qsv11 PRIVATE obs-qsv11.rc)
+
+  target_compile_definitions(obs-qsv11 PRIVATE DX11_D3D)
+
+  target_sources(
+    obs-qsv11
+    PRIVATE # cmake-format: sortable
+            common_directx11.cpp
+            common_directx11.h
+            common_directx9.cpp
+            common_directx9.h
+            common_utils_windows.cpp
+            device_directx9.cpp
+            device_directx9.h)
+
+  target_link_libraries(obs-qsv11 PRIVATE OBS::libmfx d3d9 d3d11 dxva2 dxgi dxguid)
+elseif(OS_LINUX)
+  find_package(VPL REQUIRED)
+
+  target_sources(obs-qsv11 PRIVATE common_utils_linux.cpp)
+
+  target_link_libraries(obs-qsv11 PRIVATE VPL::VPL)
+endif()
+
+get_target_property(target_sources obs-qsv11 SOURCES)
 list(FILTER target_sources INCLUDE REGEX ".*\\.(m|c[cp]?p?|swift)")
 list(FILTER target_headers INCLUDE REGEX ".*\\.h(pp)?")
-source_group("libmfx\\Source Files" FILES ${target_sources})
-source_group("libmfx\\Header Files" FILES ${target_headers})
+source_group("obs-qsv11\\Source Files" FILES ${target_sources})
+source_group("obs-qsv11\\Header Files" FILES ${target_headers})

+ 2 - 2
plugins/obs-qsv11/QSV_Encoder.h

@@ -56,10 +56,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #pragma once
 
-#include "mfxstructures.h"
-#include "mfxadapter.h"
+#include <mfxadapter.h>
 #include <stdint.h>
 #include <stdbool.h>
+#include <stddef.h>
 
 #ifdef __cplusplus
 extern "C" {

+ 27 - 5
plugins/obs-qsv11/QSV_Encoder_Internal.cpp

@@ -56,8 +56,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "QSV_Encoder_Internal.h"
 #include "QSV_Encoder.h"
-#include "mfxastructures.h"
-#include "mfxvideo++.h"
+#include <mfxvideo++.h>
 #include <obs-module.h>
 
 #define do_log(level, format, ...) \
@@ -86,25 +85,36 @@ QSV_Encoder_Internal::QSV_Encoder_Internal(mfxIMPL &impl, mfxVersion &version,
 	mfxIMPL tempImpl;
 	mfxStatus sts;
 
+#if defined(_WIN32)
 	m_bUseD3D11 = true;
 	m_bD3D9HACK = true;
 	m_bUseTexAlloc = true;
 
 	tempImpl = impl | MFX_IMPL_VIA_D3D11;
+	const char *sImpl = "D3D11";
+#else
+	m_bUseTexAlloc = false;
+	tempImpl = impl | MFX_IMPL_VIA_VAAPI;
+	const char *sImpl = "VAAPI";
+#endif
 	sts = m_session.Init(tempImpl, &version);
 	if (sts == MFX_ERR_NONE) {
 		m_session.QueryVersion(&version);
 		m_session.Close();
 
-		blog(LOG_INFO, "\timpl:           D3D11\n"
-			       "\tsurf:           D3D11");
+		blog(LOG_INFO,
+		     "\timpl:           %s\n"
+		     "\tsurf:           %s",
+		     sImpl, m_bUseTexAlloc ? "Texture" : "SysMem");
 
 		m_impl = tempImpl;
 		m_ver = version;
 		return;
 	}
 
+#if defined(_WIN32)
 	// D3D11 failed at this point.
+	m_bUseD3D11 = false;
 	tempImpl = impl | MFX_IMPL_VIA_D3D9;
 	sts = m_session.Init(tempImpl, &version);
 	if (sts == MFX_ERR_NONE) {
@@ -118,6 +128,7 @@ QSV_Encoder_Internal::QSV_Encoder_Internal(mfxIMPL &impl, mfxVersion &version,
 		m_ver = version;
 		m_bUseD3D11 = false;
 	}
+#endif
 }
 
 QSV_Encoder_Internal::~QSV_Encoder_Internal()
@@ -130,6 +141,7 @@ mfxStatus QSV_Encoder_Internal::Open(qsv_param_t *pParams, enum qsv_codec codec)
 {
 	mfxStatus sts = MFX_ERR_NONE;
 
+#if defined(_WIN32)
 	if (m_bUseD3D11)
 		// Use D3D11 surface
 		sts = Initialize(m_impl, m_ver, &m_session, &m_mfxAllocator,
@@ -140,6 +152,9 @@ mfxStatus QSV_Encoder_Internal::Open(qsv_param_t *pParams, enum qsv_codec codec)
 				 &g_DX_Handle, false, true);
 	else
 		sts = Initialize(m_impl, m_ver, &m_session, NULL);
+#else
+	sts = Initialize(m_impl, m_ver, &m_session, NULL, NULL, false, false);
+#endif
 
 	MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
 
@@ -215,6 +230,8 @@ mfxStatus QSV_Encoder_Internal::InitParams(qsv_param_t *pParams,
 	if (codec == QSV_CODEC_HEVC)
 		m_mfxEncParams.mfx.LowPower = MFX_CODINGOPTION_OFF;
 
+#if defined(_WIN32)
+	// TODO: Why isn't LowPower coding supported on VAAPI backend.
 	enum qsv_cpu_platform qsv_platform = qsv_get_cpu_platform();
 	if ((m_isDGPU || qsv_platform >= QSV_CPU_PLATFORM_ICL ||
 	     qsv_platform == QSV_CPU_PLATFORM_UNKNOWN) &&
@@ -226,6 +243,7 @@ mfxStatus QSV_Encoder_Internal::InitParams(qsv_param_t *pParams,
 		    pParams->nRateControl == MFX_RATECONTROL_LA)
 			pParams->nRateControl = MFX_RATECONTROL_VBR;
 	}
+#endif
 
 	m_mfxEncParams.mfx.RateControlMethod = pParams->nRateControl;
 
@@ -322,6 +340,8 @@ mfxStatus QSV_Encoder_Internal::InitParams(qsv_param_t *pParams,
 		}
 	}
 
+#if defined(_WIN32)
+	// TODO: Ask about this one on VAAPI too.
 	memset(&m_ExtVideoSignalInfo, 0, sizeof(m_ExtVideoSignalInfo));
 	m_ExtVideoSignalInfo.Header.BufferId = MFX_EXTBUFF_VIDEO_SIGNAL_INFO;
 	m_ExtVideoSignalInfo.Header.BufferSz = sizeof(m_ExtVideoSignalInfo);
@@ -333,6 +353,7 @@ mfxStatus QSV_Encoder_Internal::InitParams(qsv_param_t *pParams,
 		pParams->TransferCharacteristics;
 	m_ExtVideoSignalInfo.MatrixCoefficients = pParams->MatrixCoefficients;
 	extendedBuffers.push_back((mfxExtBuffer *)&m_ExtVideoSignalInfo);
+#endif
 
 /* TODO: Ask Intel why this is MFX_ERR_UNSUPPORTED */
 #if 0
@@ -813,8 +834,9 @@ mfxStatus QSV_Encoder_Internal::Encode_tex(uint64_t ts, uint32_t tex_handle,
 	//copy to default surface directly
 	pSurface->Data.TimeStamp = ts;
 	if (m_bUseTexAlloc) {
+		// mfxU64 isn't consistent with stdint, requiring a cast to be multi-platform.
 		sts = simple_copytex(m_mfxAllocator.pthis, pSurface->Data.MemId,
-				     tex_handle, lock_key, next_key);
+				     tex_handle, lock_key, (mfxU64 *)next_key);
 		MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
 	}
 

+ 1 - 2
plugins/obs-qsv11/QSV_Encoder_Internal.h

@@ -54,8 +54,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 #pragma once
-#include "mfxastructures.h"
-#include "mfxvideo++.h"
+#include <mfxvideo++.h>
 #include "QSV_Encoder.h"
 #include "common_utils.h"
 

+ 1 - 1
plugins/obs-qsv11/bits/linux_defs.h

@@ -6,4 +6,4 @@
 #define MSDK_FOPEN(FH, FN, M)           { FH=fopen(FN,M); }
 #define MSDK_SLEEP(X)                   { usleep(1000*(X)); }
 
-typedef timespec mfxTime;
+typedef struct timespec mfxTime;

+ 21 - 19
plugins/obs-qsv11/cmake/legacy.cmake

@@ -64,15 +64,8 @@ target_sources(
   obs-qsv11
   PRIVATE obs-qsv11.c
           obs-qsv11-plugin-main.c
-          common_directx9.cpp
-          common_directx9.h
-          common_directx11.cpp
-          common_directx11.h
           common_utils.cpp
           common_utils.h
-          common_utils_windows.cpp
-          device_directx9.cpp
-          device_directx9.h
           QSV_Encoder.cpp
           QSV_Encoder.h
           QSV_Encoder_Internal.cpp
@@ -80,27 +73,36 @@ target_sources(
           bits/linux_defs.h
           bits/windows_defs.h)
 
-target_link_libraries(
-  obs-qsv11
-  PRIVATE OBS::libobs
-          OBS::libmfx
-          d3d9
-          d3d11
-          dxva2
-          dxgi
-          dxguid)
-
-target_compile_definitions(obs-qsv11 PRIVATE DX11_D3D)
+target_link_libraries(obs-qsv11 PRIVATE OBS::libobs)
 
 if(OS_WINDOWS)
   add_subdirectory(obs-qsv-test)
 
+  target_compile_definitions(obs-qsv11 PRIVATE DX11_D3D)
+
   set(MODULE_DESCRIPTION "OBS QSV encoder")
   configure_file(${CMAKE_SOURCE_DIR}/cmake/bundle/windows/obs-module.rc.in obs-qsv11.rc)
 
-  target_sources(obs-qsv11 PRIVATE obs-qsv11.rc)
+  target_sources(
+    obs-qsv11
+    PRIVATE obs-qsv11.rc
+            common_directx9.cpp
+            common_directx9.h
+            common_directx11.cpp
+            common_directx11.h
+            common_utils_windows.cpp
+            device_directx9.cpp
+            device_directx9.h)
+
+  target_link_libraries(obs-qsv11 PRIVATE OBS::libmfx d3d9 d3d11 dxva2 dxgi dxguid)
 
   target_compile_definitions(obs-qsv11 PRIVATE UNICODE _UNICODE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_WARNINGS)
+elseif(OS_LINUX)
+  find_package(VPL REQUIRED)
+
+  target_sources(obs-qsv11 PRIVATE common_utils_linux.cpp)
+
+  target_link_libraries(obs-qsv11 PRIVATE VPL::VPL)
 endif()
 
 set_target_properties(obs-qsv11 PROPERTIES FOLDER "plugins/obs-qsv11")

+ 1 - 1
plugins/obs-qsv11/common_utils.h

@@ -2,7 +2,7 @@
 
 #include <stdio.h>
 
-#include "mfxvideo++.h"
+#include <mfxvideo++.h>
 
 // =================================================================
 // OS-specific definitions of types, macro, etc...

+ 100 - 0
plugins/obs-qsv11/common_utils_linux.cpp

@@ -0,0 +1,100 @@
+#include "common_utils.h"
+#include <time.h>
+#include <cpuid.h>
+#include <util/c99defs.h>
+
+mfxStatus simple_alloc(mfxHDL pthis, mfxFrameAllocRequest *request,
+		       mfxFrameAllocResponse *response)
+{
+	UNUSED_PARAMETER(pthis);
+	UNUSED_PARAMETER(request);
+	UNUSED_PARAMETER(response);
+	return MFX_ERR_UNSUPPORTED;
+}
+
+mfxStatus simple_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
+{
+	UNUSED_PARAMETER(pthis);
+	UNUSED_PARAMETER(mid);
+	UNUSED_PARAMETER(ptr);
+	return MFX_ERR_UNSUPPORTED;
+}
+
+mfxStatus simple_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
+{
+	UNUSED_PARAMETER(pthis);
+	UNUSED_PARAMETER(mid);
+	UNUSED_PARAMETER(ptr);
+	return MFX_ERR_UNSUPPORTED;
+}
+
+mfxStatus simple_gethdl(mfxHDL pthis, mfxMemId mid, mfxHDL *handle)
+{
+	UNUSED_PARAMETER(pthis);
+	UNUSED_PARAMETER(mid);
+	UNUSED_PARAMETER(handle);
+	return MFX_ERR_UNSUPPORTED;
+}
+
+mfxStatus simple_free(mfxHDL pthis, mfxFrameAllocResponse *response)
+{
+	UNUSED_PARAMETER(pthis);
+	UNUSED_PARAMETER(response);
+	return MFX_ERR_UNSUPPORTED;
+}
+
+mfxStatus simple_copytex(mfxHDL pthis, mfxMemId mid, mfxU32 tex_handle,
+			 mfxU64 lock_key, mfxU64 *next_key)
+{
+	UNUSED_PARAMETER(pthis);
+	UNUSED_PARAMETER(mid);
+	UNUSED_PARAMETER(tex_handle);
+	UNUSED_PARAMETER(lock_key);
+	UNUSED_PARAMETER(next_key);
+	return MFX_ERR_UNSUPPORTED;
+}
+
+#if 0
+void ClearYUVSurfaceVMem(mfxMemId memId);
+void ClearRGBSurfaceVMem(mfxMemId memId);
+#endif
+
+// Initialize Intel Media SDK Session, device/display and memory manager
+mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession *pSession,
+		     mfxFrameAllocator *pmfxAllocator, mfxHDL *deviceHandle,
+		     bool bCreateSharedHandles, bool dx9hack)
+{
+	UNUSED_PARAMETER(pmfxAllocator);
+	UNUSED_PARAMETER(deviceHandle);
+	UNUSED_PARAMETER(bCreateSharedHandles);
+	UNUSED_PARAMETER(dx9hack);
+	mfxStatus sts = MFX_ERR_NONE;
+
+	// Initialize Intel Media SDK Session
+	sts = pSession->Init(impl, &ver);
+	MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
+	return sts;
+}
+
+// Release resources (device/display)
+void Release(){};
+
+void mfxGetTime(mfxTime *timestamp)
+{
+	clock_gettime(CLOCK_MONOTONIC, timestamp);
+}
+
+double TimeDiffMsec(mfxTime tfinish, mfxTime tstart)
+{
+	UNUSED_PARAMETER(tfinish);
+	UNUSED_PARAMETER(tstart);
+	//TODO, unused so far it seems
+	return 0.0;
+}
+
+extern "C" void util_cpuid(int cpuinfo[4], int level)
+{
+	__get_cpuid(level, (unsigned int *)&cpuinfo[0],
+		    (unsigned int *)&cpuinfo[1], (unsigned int *)&cpuinfo[2],
+		    (unsigned int *)&cpuinfo[3]);
+}

+ 15 - 0
plugins/obs-qsv11/obs-qsv11-plugin-main.c

@@ -93,6 +93,7 @@ static bool enum_luids(void *param, uint32_t idx, uint64_t luid)
 
 bool obs_module_load(void)
 {
+#if defined(_WIN32)
 	char *test_exe = os_get_executable_path_ptr("obs-qsv-test.exe");
 	struct dstr cmd = {0};
 	struct dstr caps_str = {0};
@@ -161,6 +162,18 @@ bool obs_module_load(void)
 		av1_supported |= adapter->supports_av1;
 		hevc_supported |= adapter->supports_hevc;
 	}
+#else
+	// We could lift the VA-API query from obs-ffmpeg here.
+	adapter_count = 1;
+	struct adapter_info *adapter = &adapters[0];
+	adapter->is_intel = true;
+	adapter->is_dgpu = true;
+	adapter->supports_av1 = true;
+	adapter->supports_hevc = true;
+	bool avc_supported = true;
+	bool hevc_supported = true;
+	bool av1_supported = true;
+#endif
 
 	if (avc_supported) {
 		obs_register_encoder(&obs_qsv_encoder_tex_v2);
@@ -180,11 +193,13 @@ bool obs_module_load(void)
 #endif
 
 fail:
+#if defined(_WIN32)
 	config_close(config);
 	dstr_free(&caps_str);
 	dstr_free(&cmd);
 	os_process_pipe_destroy(pp);
 	bfree(test_exe);
+#endif
 
 	return true;
 }

+ 4 - 0
plugins/obs-qsv11/obs-qsv11.c

@@ -75,6 +75,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
 #define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
 
+#ifndef GS_INVALID_HANDLE
+#define GS_INVALID_HANDLE (uint32_t) - 1
+#endif
+
 /* ------------------------------------------------------------------------- */
 
 struct obs_qsv {