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

obs-ffmpeg: Make AMF encoder work on Linux #7206

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion plugins/obs-ffmpeg/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,12 @@ if(OS_WINDOWS)
jim-nvenc-ver.h
obs-ffmpeg.rc)
elseif(OS_LINUX OR OS_FREEBSD)
add_subdirectory(obs-amf-test)

find_package(Libva REQUIRED)
find_package(Libpci REQUIRED)

target_sources(obs-ffmpeg PRIVATE obs-ffmpeg-vaapi.c vaapi-utils.c vaapi-utils.h)
target_sources(obs-ffmpeg PRIVATE obs-ffmpeg-vaapi.c vaapi-utils.c vaapi-utils.h texture-amf.cpp)
target_link_libraries(obs-ffmpeg PRIVATE Libva::va Libva::drm Libpci::pci)
endif()

Expand Down
3 changes: 2 additions & 1 deletion plugins/obs-ffmpeg/cmake/legacy.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,10 @@ if(OS_WINDOWS)
obs-ffmpeg.rc)

elseif(OS_POSIX AND NOT OS_MACOS)
add_subdirectory(obs-amf-test)
find_package(Libva REQUIRED)
find_package(Libpci REQUIRED)
target_sources(obs-ffmpeg PRIVATE obs-ffmpeg-vaapi.c vaapi-utils.c vaapi-utils.h)
target_sources(obs-ffmpeg PRIVATE obs-ffmpeg-vaapi.c vaapi-utils.c vaapi-utils.h texture-amf.cpp)
target_link_libraries(obs-ffmpeg PRIVATE Libva::va Libva::drm LIBPCI::LIBPCI)
endif()

Expand Down
10 changes: 8 additions & 2 deletions plugins/obs-ffmpeg/obs-amf-test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ find_package(AMF 1.4.29 REQUIRED)

target_include_directories(obs-amf-test PRIVATE ${CMAKE_SOURCE_DIR}/libobs)

target_sources(obs-amf-test PRIVATE obs-amf-test.cpp)
target_link_libraries(obs-amf-test d3d11 dxgi dxguid AMF::AMF)
if(OS_WINDOWS)
target_sources(obs-amf-test PRIVATE obs-amf-test.cpp)
target_link_libraries(obs-amf-test d3d11 dxgi dxguid AMF::AMF)
elseif(OS_POSIX AND NOT OS_MACOS)
find_package(Vulkan REQUIRED)
target_sources(obs-amf-test PRIVATE obs-amf-test-linux.cpp)
target_link_libraries(obs-amf-test dl Vulkan::Vulkan AMF::AMF)
endif()

set_target_properties(obs-amf-test PROPERTIES FOLDER "plugins/obs-ffmpeg")

Expand Down
140 changes: 140 additions & 0 deletions plugins/obs-ffmpeg/obs-amf-test/obs-amf-test-linux.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#include <AMF/core/Factory.h>
#include <AMF/core/Trace.h>
#include <AMF/components/VideoEncoderVCE.h>
#include <AMF/components/VideoEncoderHEVC.h>
#include <AMF/components/VideoEncoderAV1.h>

#include <dlfcn.h>
#include <vulkan/vulkan.hpp>

#include <string>
#include <map>

using namespace amf;

struct adapter_caps {
bool is_amd = false;
bool supports_avc = false;
bool supports_hevc = false;
bool supports_av1 = false;
};

static AMFFactory *amf_factory = nullptr;
static std::map<uint32_t, adapter_caps> adapter_info;

static bool has_encoder(AMFContextPtr &amf_context, const wchar_t *encoder_name)
{
AMFComponentPtr encoder;
AMF_RESULT res = amf_factory->CreateComponent(amf_context, encoder_name,
&encoder);
return res == AMF_OK;
}

static bool get_adapter_caps(uint32_t adapter_idx)
{
if (adapter_idx)
return false;

adapter_caps &caps = adapter_info[adapter_idx];

AMF_RESULT res;
AMFContextPtr amf_context;
res = amf_factory->CreateContext(&amf_context);
if (res != AMF_OK)
return true;

AMFContext1 *context1 = NULL;
res = amf_context->QueryInterface(AMFContext1::IID(),
(void **)&context1);
if (res != AMF_OK)
return false;
res = context1->InitVulkan(nullptr);
context1->Release();
if (res != AMF_OK)
return false;

caps.is_amd = true;
caps.supports_avc = has_encoder(amf_context, AMFVideoEncoderVCE_AVC);
caps.supports_hevc = has_encoder(amf_context, AMFVideoEncoder_HEVC);
caps.supports_av1 = has_encoder(amf_context, AMFVideoEncoder_AV1);

return true;
}

int main(void)
try {
AMF_RESULT res;
VkResult vkres;

VkApplicationInfo app_info = {};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
app_info.pApplicationName = "obs-amf-test";
app_info.apiVersion = VK_API_VERSION_1_2;

VkInstanceCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
info.pApplicationInfo = &app_info;

VkInstance instance;
vkres = vkCreateInstance(&info, nullptr, &instance);
if (vkres != VK_SUCCESS)
throw "Failed to initialize Vulkan";

uint32_t device_count;
vkres = vkEnumeratePhysicalDevices(instance, &device_count, nullptr);
if (vkres != VK_SUCCESS || !device_count)
throw "Failed to enumerate Vulkan devices";

VkPhysicalDevice *devices = new VkPhysicalDevice[device_count];
vkres = vkEnumeratePhysicalDevices(instance, &device_count, devices);
if (vkres != VK_SUCCESS)
throw "Failed to enumerate Vulkan devices";

VkPhysicalDeviceDriverProperties driver_props = {};
driver_props.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
VkPhysicalDeviceProperties2 device_props = {};
device_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
device_props.pNext = &driver_props;
vkGetPhysicalDeviceProperties2(devices[0], &device_props);

if (strcmp(driver_props.driverName, "AMD proprietary driver"))
throw "Not running AMD proprietary driver";

vkDestroyInstance(instance, nullptr);

/* --------------------------------------------------------- */
/* try initializing amf, I guess */

void *amf_module = dlopen(AMF_DLL_NAMEA, RTLD_LAZY);
if (!amf_module)
throw "Failed to load AMF lib";

auto init = (AMFInit_Fn)dlsym(amf_module, AMF_INIT_FUNCTION_NAME);
if (!init)
throw "Failed to get init func";

res = init(AMF_FULL_VERSION, &amf_factory);
if (res != AMF_OK)
throw "AMFInit failed";

uint32_t idx = 0;
while (get_adapter_caps(idx++))
;

for (auto &[idx, caps] : adapter_info) {
printf("[%u]\n", idx);
printf("is_amd=%s\n", caps.is_amd ? "true" : "false");
printf("supports_avc=%s\n",
caps.supports_avc ? "true" : "false");
printf("supports_hevc=%s\n",
caps.supports_hevc ? "true" : "false");
printf("supports_av1=%s\n",
caps.supports_av1 ? "true" : "false");
}

return 0;
} catch (const char *text) {
printf("[error]\nstring=%s\n", text);
return 0;
}
10 changes: 8 additions & 2 deletions plugins/obs-ffmpeg/obs-ffmpeg.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,9 @@ static bool hevc_vaapi_supported(void)
#ifdef _WIN32
extern void jim_nvenc_load(bool h264, bool hevc, bool av1);
extern void jim_nvenc_unload(void);
#endif

#if defined(_WIN32) || defined(__linux__)
extern void amf_load(void);
extern void amf_unload(void);
#endif
Expand Down Expand Up @@ -434,7 +437,7 @@ bool obs_module_load(void)
#endif
}

#ifdef _WIN32
#if defined(_WIN32) || defined(__linux__)
amf_load();
#endif

Expand Down Expand Up @@ -475,8 +478,11 @@ void obs_module_unload(void)
obs_ffmpeg_unload_logging();
#endif

#ifdef _WIN32
#if defined(_WIN32) || defined(__linux__)
amf_unload();
#endif

#ifdef _WIN32
jim_nvenc_unload();
#endif
}
2 changes: 1 addition & 1 deletion plugins/obs-ffmpeg/texture-amf-opts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ static void amf_apply_opt(amf_base *enc, obs_option *opt)
val = atoi(opt->value);
}

os_utf8_to_wcs(opt->name, 0, wname, _countof(wname));
os_utf8_to_wcs(opt->name, 0, wname, amf_countof(wname));
if (is_bool) {
bool bool_val = (bool)val;
set_amf_property(enc, wname, bool_val);
Expand Down
Loading