From 854aa51470f2f76dc3fbd846ade97f3498db821f Mon Sep 17 00:00:00 2001 From: Ward from fusion-voyager-3 Date: Sun, 25 Feb 2024 22:22:58 +0300 Subject: [PATCH] update to 30.0.2 --- debian/changelog | 4 +- debian/rules | 2 +- main.sh | 2 +- ...rt-Disable-browser-panels-on-Wayland.patch | 43 + ...registering-CEF-OAuth-integrations-o.patch | 47 + ...reference-the-software-H264-encoder-.patch | 104 + patches/0002-7206.patch | 2678 ----------------- ...nitial-support-for-the-OpenH264-H.26.patch | 346 +++ patches/0003-8788.patch | 63 - ...or-OpenH264-as-the-worst-case-fallba.patch | 545 ++++ ...a179ed2768304a98d48f4074e54fe7cbf5b3.patch | 27 - patches/{0001-6207.patch => 6207.patch} | 0 patches/8051.patch | 283 ++ patches/{0005-8794.patch => 8794.patch} | 59 +- patches/{0006-8832.patch => 8832.patch} | 358 +-- patches/{0004-9475.patch => 9475.patch} | 0 patches/add-plugins.patch | 14 + ...oder-rename.patch => encoder-rename.patch} | 54 - patches/obs-studio-30-cmake-3.20.patch | 423 +++ ...obs-studio-UI-use-fdk-aac-by-default.patch | 36 + ...o-deps-Add-license-declaration-files.patch | 218 ++ 21 files changed, 2183 insertions(+), 3123 deletions(-) create mode 100644 patches/0001-Revert-Disable-browser-panels-on-Wayland.patch create mode 100644 patches/0001-Revert-UI-Avoid-registering-CEF-OAuth-integrations-o.patch create mode 100644 patches/0001-UI-Consistently-reference-the-software-H264-encoder-.patch delete mode 100644 patches/0002-7206.patch create mode 100644 patches/0002-obs-ffmpeg-Add-initial-support-for-the-OpenH264-H.26.patch delete mode 100644 patches/0003-8788.patch create mode 100644 patches/0003-UI-Add-support-for-OpenH264-as-the-worst-case-fallba.patch delete mode 100644 patches/0007-5fdda179ed2768304a98d48f4074e54fe7cbf5b3.patch rename patches/{0001-6207.patch => 6207.patch} (100%) create mode 100644 patches/8051.patch rename patches/{0005-8794.patch => 8794.patch} (86%) rename patches/{0006-8832.patch => 8832.patch} (78%) rename patches/{0004-9475.patch => 9475.patch} (100%) create mode 100644 patches/add-plugins.patch rename patches/{0006-encoder-rename.patch => encoder-rename.patch} (63%) create mode 100644 patches/obs-studio-30-cmake-3.20.patch create mode 100644 patches/obs-studio-UI-use-fdk-aac-by-default.patch create mode 100644 patches/obs-studio-deps-Add-license-declaration-files.patch diff --git a/debian/changelog b/debian/changelog index d6fd5ea..c03b838 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,6 @@ -obs-studio (29.1.3-100pika3) pikauwu; urgency=low +obs-studio (30.0.2-100pika1) pikauwu; urgency=low - Update to 29.1.3 + Update to 30.0.2 -- Kevin Henkel Sat, 04 Feb 2023 12:48:06 +0100 diff --git a/debian/rules b/debian/rules index 2cede6c..33eda19 100755 --- a/debian/rules +++ b/debian/rules @@ -8,4 +8,4 @@ AJA_DIR := $(BASE_DIR)/ntv2 dh $@ override_dh_auto_configure: #dh_auto_configure -- -DOBS_VERSION_OVERRIDE="29.1.3" -DBUILD_FOR_PPA=ON -DTWITCH_CLIENTID='unla3~mb`xq9`1dhr?1lhhg`65mah0' -DTWITCH_HASH='2D4A98C454B4B0B6' -DRESTREAM_CLIENTID='ml6b16ec(n9?1#9g?m#>9f0,gnkojhhd;oh6' -DRESTREAM_HASH='2DE8E8C514397EE9' -DYOUTUBE_CLIENTID='153066229607$$;a7mw2ig756r?vc +Date: Fri, 22 Dec 2023 18:25:09 -0500 +Subject: [PATCH] Revert "Disable browser panels on Wayland" + +This reverts commit 7402271392a6a74fb49f16d84fb3c04c1b603d9a. +--- + panel/browser-panel.hpp | 12 ------------ + 1 file changed, 12 deletions(-) + +diff --git a/panel/browser-panel.hpp b/panel/browser-panel.hpp +index dd61f38..5fb9d35 100644 +--- a/panel/browser-panel.hpp ++++ b/panel/browser-panel.hpp +@@ -12,10 +12,6 @@ + #include + #endif + +-#ifdef ENABLE_WAYLAND +-#include +-#endif +- + struct QCefCookieManager { + virtual ~QCefCookieManager() {} + +@@ -81,14 +77,6 @@ struct QCef { + + static inline void *get_browser_lib() + { +- // Disable panels on Wayland for now +- bool isWayland = false; +-#ifdef ENABLE_WAYLAND +- isWayland = obs_get_nix_platform() == OBS_NIX_PLATFORM_WAYLAND; +-#endif +- if (isWayland) +- return nullptr; +- + obs_module_t *browserModule = obs_get_module("obs-browser"); + + if (!browserModule) +-- +2.43.0 + diff --git a/patches/0001-Revert-UI-Avoid-registering-CEF-OAuth-integrations-o.patch b/patches/0001-Revert-UI-Avoid-registering-CEF-OAuth-integrations-o.patch new file mode 100644 index 0000000..af949c5 --- /dev/null +++ b/patches/0001-Revert-UI-Avoid-registering-CEF-OAuth-integrations-o.patch @@ -0,0 +1,47 @@ +From fcd09096796a259c8c438627528c92829be39c01 Mon Sep 17 00:00:00 2001 +From: Thomas Crider +Date: Fri, 22 Dec 2023 19:10:34 -0500 +Subject: [PATCH] Revert "UI: Avoid registering CEF OAuth integrations on + Wayland" + +This reverts commit 169cd07c42ddf1d0693094badb75f6255c052fac. +--- + UI/auth-restream.cpp | 5 ----- + UI/auth-twitch.cpp | 5 ----- + 2 files changed, 10 deletions(-) + +diff --git a/UI/auth-restream.cpp b/UI/auth-restream.cpp +index bedc10c70..cf8a3e098 100644 +--- a/UI/auth-restream.cpp ++++ b/UI/auth-restream.cpp +@@ -282,11 +282,6 @@ static void DeleteCookies() + + void RegisterRestreamAuth() + { +-#if !defined(__APPLE__) && !defined(_WIN32) +- if (QApplication::platformName().contains("wayland")) +- return; +-#endif +- + OAuth::RegisterOAuth(restreamDef, CreateRestreamAuth, + RestreamAuth::Login, DeleteCookies); + } +diff --git a/UI/auth-twitch.cpp b/UI/auth-twitch.cpp +index 88e14e0be..abc9cae66 100644 +--- a/UI/auth-twitch.cpp ++++ b/UI/auth-twitch.cpp +@@ -512,11 +512,6 @@ static void DeleteCookies() + + void RegisterTwitchAuth() + { +-#if !defined(__APPLE__) && !defined(_WIN32) +- if (QApplication::platformName().contains("wayland")) +- return; +-#endif +- + OAuth::RegisterOAuth(twitchDef, CreateTwitchAuth, TwitchAuth::Login, + DeleteCookies); + } +-- +2.43.0 + diff --git a/patches/0001-UI-Consistently-reference-the-software-H264-encoder-.patch b/patches/0001-UI-Consistently-reference-the-software-H264-encoder-.patch new file mode 100644 index 0000000..e976f5c --- /dev/null +++ b/patches/0001-UI-Consistently-reference-the-software-H264-encoder-.patch @@ -0,0 +1,104 @@ +From 04d3a21c6e72cd5574f7333adf548012d912c1ee Mon Sep 17 00:00:00 2001 +From: Neal Gompa +Date: Sat, 7 Jan 2023 23:15:13 -0500 +Subject: [PATCH 1/3] UI: Consistently reference the software H264 encoder + properly + +The code here assumes that the only software encoder is the x264-based +H.264 encoder. That may not always remain true. This change adjusts +the encoder string to indicate that it's an H.264 encoder from x264. +--- + UI/data/locale/en-US.ini | 4 ++-- + UI/window-basic-auto-config-test.cpp | 6 +++--- + UI/window-basic-settings-stream.cpp | 2 +- + UI/window-basic-settings.cpp | 7 ++++--- + 4 files changed, 10 insertions(+), 9 deletions(-) + +diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini +index 4c03aa7db..e44d99660 100644 +--- a/UI/data/locale/en-US.ini ++++ b/UI/data/locale/en-US.ini +@@ -980,7 +980,7 @@ Basic.Settings.Output.Simple.Warn.Encoder="Warning: Recording with a software en + Basic.Settings.Output.Simple.Warn.Lossless="Warning: Lossless quality generates tremendously large file sizes! Lossless quality can use upward of 7 gigabytes of disk space per minute at high resolutions and framerates. Lossless is not recommended for long recordings unless you have a very large amount of disk space available." + Basic.Settings.Output.Simple.Warn.Lossless.Msg="Are you sure you want to use lossless quality?" + Basic.Settings.Output.Simple.Warn.Lossless.Title="Lossless quality warning!" +-Basic.Settings.Output.Simple.Encoder.Software="Software (x264)" ++Basic.Settings.Output.Simple.Encoder.Software.X264.H264="Software (x264)" + Basic.Settings.Output.Simple.Encoder.Hardware.QSV.H264="Hardware (QSV, H.264)" + Basic.Settings.Output.Simple.Encoder.Hardware.QSV.AV1="Hardware (QSV, AV1)" + Basic.Settings.Output.Simple.Encoder.Hardware.AMD.H264="Hardware (AMD, H.264)" +@@ -991,7 +991,7 @@ Basic.Settings.Output.Simple.Encoder.Hardware.NVENC.AV1="Hardware (NVENC, AV1)" + Basic.Settings.Output.Simple.Encoder.Hardware.NVENC.HEVC="Hardware (NVENC, HEVC)" + Basic.Settings.Output.Simple.Encoder.Hardware.Apple.H264="Hardware (Apple, H.264)" + Basic.Settings.Output.Simple.Encoder.Hardware.Apple.HEVC="Hardware (Apple, HEVC)" +-Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Software (x264 low CPU usage preset, increases file size)" ++Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU.X264.H264="Software (x264 low CPU usage preset, increases file size)" + Basic.Settings.Output.Simple.Codec.AAC="AAC" + Basic.Settings.Output.Simple.Codec.AAC.Default="AAC (Default)" + Basic.Settings.Output.Simple.Codec.Opus="Opus" +diff --git a/UI/window-basic-auto-config-test.cpp b/UI/window-basic-auto-config-test.cpp +index 2d89d7347..09979c031 100644 +--- a/UI/window-basic-auto-config-test.cpp ++++ b/UI/window-basic-auto-config-test.cpp +@@ -993,7 +993,7 @@ void AutoConfigTestPage::TestRecordingEncoderThread() + } + + #define ENCODER_TEXT(x) "Basic.Settings.Output.Simple.Encoder." x +-#define ENCODER_SOFTWARE ENCODER_TEXT("Software") ++#define ENCODER_X264 ENCODER_TEXT("Software.X264.H264") + #define ENCODER_NVENC ENCODER_TEXT("Hardware.NVENC.H264") + #define ENCODER_QSV ENCODER_TEXT("Hardware.QSV.H264") + #define ENCODER_AMD ENCODER_TEXT("Hardware.AMD.H264") +@@ -1033,7 +1033,7 @@ void AutoConfigTestPage::FinalizeResults() + auto encName = [](AutoConfig::Encoder enc) -> QString { + switch (enc) { + case AutoConfig::Encoder::x264: +- return QTStr(ENCODER_SOFTWARE); ++ return QTStr(ENCODER_X264); + case AutoConfig::Encoder::NVENC: + return QTStr(ENCODER_NVENC); + case AutoConfig::Encoder::QSV: +@@ -1046,7 +1046,7 @@ void AutoConfigTestPage::FinalizeResults() + return QTStr(QUALITY_SAME); + } + +- return QTStr(ENCODER_SOFTWARE); ++ return QTStr(ENCODER_X264); + }; + + auto newLabel = [this](const char *str) -> QLabel * { +diff --git a/UI/window-basic-settings-stream.cpp b/UI/window-basic-settings-stream.cpp +index f6e0817a0..b056938e7 100644 +--- a/UI/window-basic-settings-stream.cpp ++++ b/UI/window-basic-settings-stream.cpp +@@ -1585,7 +1585,7 @@ void OBSBasicSettings::ResetEncoders(bool streamOnly) + + #define ENCODER_STR(str) QTStr("Basic.Settings.Output.Simple.Encoder." str) + +- ui->simpleOutStrEncoder->addItem(ENCODER_STR("Software"), ++ ui->simpleOutStrEncoder->addItem(ENCODER_STR("Software.X264.H264"), + QString(SIMPLE_ENCODER_X264)); + if (service_supports_encoder(vcodecs, "obs_qsv11")) + ui->simpleOutStrEncoder->addItem( +diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp +index fb170bfc1..48bb4bac6 100644 +--- a/UI/window-basic-settings.cpp ++++ b/UI/window-basic-settings.cpp +@@ -5286,10 +5286,11 @@ void OBSBasicSettings::FillSimpleRecordingValues() + ADD_QUALITY("HQ"); + ADD_QUALITY("Lossless"); + +- ui->simpleOutRecEncoder->addItem(ENCODER_STR("Software"), ++ ui->simpleOutRecEncoder->addItem(ENCODER_STR("Software.X264.H264"), + QString(SIMPLE_ENCODER_X264)); +- ui->simpleOutRecEncoder->addItem(ENCODER_STR("SoftwareLowCPU"), +- QString(SIMPLE_ENCODER_X264_LOWCPU)); ++ ui->simpleOutRecEncoder->addItem( ++ ENCODER_STR("SoftwareLowCPU.X264.H264"), ++ QString(SIMPLE_ENCODER_X264_LOWCPU)); + if (EncoderAvailable("obs_qsv11")) + ui->simpleOutRecEncoder->addItem( + ENCODER_STR("Hardware.QSV.H264"), +-- +2.39.2 + diff --git a/patches/0002-7206.patch b/patches/0002-7206.patch deleted file mode 100644 index 0a33fca..0000000 --- a/patches/0002-7206.patch +++ /dev/null @@ -1,2678 +0,0 @@ -From 11b4addd007f4d057c6cbc48f225f9de8a9652da Mon Sep 17 00:00:00 2001 -From: David Rosca -Date: Sun, 28 Aug 2022 10:15:16 +0200 -Subject: [PATCH 1/5] obs-ffmpeg: Make AMF encoder work on Linux - -Only the fallback encoders are available (no texture support). - -Requires AMD proprietary Vulkan driver, using different driver -will be detected on startup and the encoders disabled. ---- - plugins/obs-ffmpeg/CMakeLists.txt | 4 +- - plugins/obs-ffmpeg/cmake/legacy.cmake | 3 +- - .../obs-ffmpeg/obs-amf-test/CMakeLists.txt | 10 +- - .../obs-amf-test/obs-amf-test-linux.cpp | 140 ++++++++++++++++++ - plugins/obs-ffmpeg/obs-ffmpeg.c | 10 +- - plugins/obs-ffmpeg/texture-amf-opts.hpp | 2 +- - plugins/obs-ffmpeg/texture-amf.cpp | 114 +++++++++++--- - 7 files changed, 259 insertions(+), 24 deletions(-) - create mode 100644 plugins/obs-ffmpeg/obs-amf-test/obs-amf-test-linux.cpp - -diff --git a/plugins/obs-ffmpeg/CMakeLists.txt b/plugins/obs-ffmpeg/CMakeLists.txt -index 3eba00932..778d93ffb 100644 ---- a/plugins/obs-ffmpeg/CMakeLists.txt -+++ b/plugins/obs-ffmpeg/CMakeLists.txt -@@ -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() - -diff --git a/plugins/obs-ffmpeg/cmake/legacy.cmake b/plugins/obs-ffmpeg/cmake/legacy.cmake -index 5540676ea..78b8c30a1 100644 ---- a/plugins/obs-ffmpeg/cmake/legacy.cmake -+++ b/plugins/obs-ffmpeg/cmake/legacy.cmake -@@ -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() - -diff --git a/plugins/obs-ffmpeg/obs-amf-test/CMakeLists.txt b/plugins/obs-ffmpeg/obs-amf-test/CMakeLists.txt -index e00cef1cf..07cf1e0fc 100644 ---- a/plugins/obs-ffmpeg/obs-amf-test/CMakeLists.txt -+++ b/plugins/obs-ffmpeg/obs-amf-test/CMakeLists.txt -@@ -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") - -diff --git a/plugins/obs-ffmpeg/obs-amf-test/obs-amf-test-linux.cpp b/plugins/obs-ffmpeg/obs-amf-test/obs-amf-test-linux.cpp -new file mode 100644 -index 000000000..db437d851 ---- /dev/null -+++ b/plugins/obs-ffmpeg/obs-amf-test/obs-amf-test-linux.cpp -@@ -0,0 +1,140 @@ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+ -+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 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; -+} -diff --git a/plugins/obs-ffmpeg/obs-ffmpeg.c b/plugins/obs-ffmpeg/obs-ffmpeg.c -index da0b2c2b4..92421c6f3 100644 ---- a/plugins/obs-ffmpeg/obs-ffmpeg.c -+++ b/plugins/obs-ffmpeg/obs-ffmpeg.c -@@ -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 -@@ -434,7 +437,7 @@ bool obs_module_load(void) - #endif - } - --#ifdef _WIN32 -+#if defined(_WIN32) || defined(__linux__) - amf_load(); - #endif - -@@ -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 - } -diff --git a/plugins/obs-ffmpeg/texture-amf-opts.hpp b/plugins/obs-ffmpeg/texture-amf-opts.hpp -index b1c37d200..d28e3f77e 100644 ---- a/plugins/obs-ffmpeg/texture-amf-opts.hpp -+++ b/plugins/obs-ffmpeg/texture-amf-opts.hpp -@@ -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); -diff --git a/plugins/obs-ffmpeg/texture-amf.cpp b/plugins/obs-ffmpeg/texture-amf.cpp -index 88914a027..fe651f0e1 100644 ---- a/plugins/obs-ffmpeg/texture-amf.cpp -+++ b/plugins/obs-ffmpeg/texture-amf.cpp -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -18,6 +19,7 @@ - #include - #include - -+#ifdef _WIN32 - #include - #include - #include -@@ -25,6 +27,8 @@ - #include - #include - #include -+#endif -+ - #include - #include - #include -@@ -55,8 +59,10 @@ struct amf_error { - - struct handle_tex { - uint32_t handle; -+#ifdef _WIN32 - ComPtr tex; - ComPtr km; -+#endif - }; - - struct adapter_caps { -@@ -72,7 +78,7 @@ static std::map caps; - static bool h264_supported = false; - static AMFFactory *amf_factory = nullptr; - static AMFTrace *amf_trace = nullptr; --static HMODULE amf_module = nullptr; -+static void *amf_module = nullptr; - static uint64_t amf_version = 0; - - /* ========================================================================= */ -@@ -120,9 +126,11 @@ struct amf_base { - virtual void init() = 0; - }; - --using d3dtex_t = ComPtr; - using buf_t = std::vector; - -+#ifdef _WIN32 -+using d3dtex_t = ComPtr; -+ - struct amf_texencode : amf_base, public AMFSurfaceObserver { - volatile bool destroying = false; - -@@ -159,6 +167,7 @@ struct amf_texencode : amf_base, public AMFSurfaceObserver { - throw amf_error("InitDX11 failed", res); - } - }; -+#endif - - struct amf_fallback : amf_base, public AMFSurfaceObserver { - volatile bool destroying = false; -@@ -186,9 +195,21 @@ struct amf_fallback : amf_base, public AMFSurfaceObserver { - - void init() override - { -+#if defined(_WIN32) - AMF_RESULT res = amf_context->InitDX11(nullptr, AMF_DX11_1); - if (res != AMF_OK) - throw amf_error("InitDX11 failed", res); -+#elif defined(__linux__) -+ AMFContext1 *context1 = NULL; -+ AMF_RESULT res = amf_context->QueryInterface( -+ AMFContext1::IID(), (void **)&context1); -+ if (res != AMF_OK) -+ throw amf_error("CreateContext1 failed", res); -+ res = context1->InitVulkan(nullptr); -+ context1->Release(); -+ if (res != AMF_OK) -+ throw amf_error("InitVulkan failed", res); -+#endif - } - }; - -@@ -230,13 +251,18 @@ static void set_amf_property(amf_base *enc, const wchar_t *name, const T &value) - : (enc->codec == amf_codec_type::HEVC) \ - ? AMF_VIDEO_ENCODER_HEVC_##name \ - : AMF_VIDEO_ENCODER_AV1_##name) -+#define get_opt_name_enum(name) \ -+ ((enc->codec == amf_codec_type::AVC) ? (int)AMF_VIDEO_ENCODER_##name \ -+ : (enc->codec == amf_codec_type::HEVC) \ -+ ? (int)AMF_VIDEO_ENCODER_HEVC_##name \ -+ : (int)AMF_VIDEO_ENCODER_AV1_##name) - #define set_opt(name, value) set_amf_property(enc, get_opt_name(name), value) - #define get_opt(name, value) get_amf_property(enc, get_opt_name(name), value) - #define set_avc_opt(name, value) set_avc_property(enc, name, value) - #define set_hevc_opt(name, value) set_hevc_property(enc, name, value) - #define set_av1_opt(name, value) set_av1_property(enc, name, value) - #define set_enum_opt(name, value) \ -- set_amf_property(enc, get_opt_name(name), get_opt_name(name##_##value)) -+ set_amf_property(enc, get_opt_name(name), get_opt_name_enum(name##_##value)) - #define set_avc_enum(name, value) \ - set_avc_property(enc, name, AMF_VIDEO_ENCODER_##name##_##value) - #define set_hevc_enum(name, value) \ -@@ -247,6 +273,7 @@ static void set_amf_property(amf_base *enc, const wchar_t *name, const T &value) - /* ------------------------------------------------------------------------- */ - /* Implementation */ - -+#ifdef _WIN32 - static HMODULE get_lib(const char *lib) - { - HMODULE mod = GetModuleHandleA(lib); -@@ -393,6 +420,7 @@ static void get_tex_from_handle(amf_texencode *enc, uint32_t handle, - *km_out = km.Detach(); - *tex_out = tex.Detach(); - } -+#endif - - static constexpr amf_int64 macroblock_size = 16; - -@@ -504,7 +532,7 @@ static void convert_to_encoder_packet(amf_base *enc, AMFDataPtr &data, - enc->packet_data = AMFBufferPtr(data); - data->GetProperty(L"PTS", &packet->pts); - -- const wchar_t *get_output_type; -+ const wchar_t *get_output_type = NULL; - switch (enc->codec) { - case amf_codec_type::AVC: - get_output_type = AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE; -@@ -638,6 +666,7 @@ static void amf_encode_base(amf_base *enc, AMFSurface *amf_surf, - static bool amf_encode_tex(void *data, uint32_t handle, int64_t pts, - uint64_t lock_key, uint64_t *next_key, - encoder_packet *packet, bool *received_packet) -+#ifdef _WIN32 - try { - amf_texencode *enc = (amf_texencode *)data; - ID3D11DeviceContext *context = enc->context; -@@ -714,6 +743,18 @@ try { - *received_packet = false; - return false; - } -+#else -+{ -+ UNUSED_PARAMETER(data); -+ UNUSED_PARAMETER(handle); -+ UNUSED_PARAMETER(pts); -+ UNUSED_PARAMETER(lock_key); -+ UNUSED_PARAMETER(next_key); -+ UNUSED_PARAMETER(packet); -+ UNUSED_PARAMETER(received_packet); -+ return false; -+} -+#endif - - static buf_t alloc_buf(amf_fallback *enc) - { -@@ -1177,6 +1218,7 @@ static const char *amf_avc_get_name(void *) - - static inline int get_avc_preset(amf_base *enc, const char *preset) - { -+ UNUSED_PARAMETER(enc); - if (astrcmpi(preset, "quality") == 0) - return AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY; - else if (astrcmpi(preset, "speed") == 0) -@@ -1287,7 +1329,7 @@ static bool amf_avc_init(void *data, obs_data_t *settings) - set_avc_property(enc, B_PIC_PATTERN, bf); - - } else if (bf != 0) { -- warn("B-Frames set to %lld but b-frames are not " -+ warn("B-Frames set to %" PRId64 " but b-frames are not " - "supported by this device", - bf); - bf = 0; -@@ -1332,12 +1374,12 @@ static bool amf_avc_init(void *data, obs_data_t *settings) - - info("settings:\n" - "\trate_control: %s\n" -- "\tbitrate: %d\n" -- "\tcqp: %d\n" -+ "\tbitrate: %" PRId64 "\n" -+ "\tcqp: %" PRId64 "\n" - "\tkeyint: %d\n" - "\tpreset: %s\n" - "\tprofile: %s\n" -- "\tb-frames: %d\n" -+ "\tb-frames: %" PRId64 "\n" - "\twidth: %d\n" - "\theight: %d\n" - "\tparams: %s", -@@ -1407,6 +1449,7 @@ static void amf_avc_create_internal(amf_base *enc, obs_data_t *settings) - - static void *amf_avc_create_texencode(obs_data_t *settings, - obs_encoder_t *encoder) -+#ifdef _WIN32 - try { - check_texture_encode_capability(encoder, amf_codec_type::AVC); - -@@ -1429,6 +1472,12 @@ try { - blog(LOG_ERROR, "[texture-amf-h264] %s: %s", __FUNCTION__, err); - return obs_encoder_create_rerouted(encoder, "h264_fallback_amf"); - } -+#else -+{ -+ UNUSED_PARAMETER(settings); -+ return obs_encoder_create_rerouted(encoder, "h264_fallback_amf"); -+} -+#endif - - static void *amf_avc_create_fallback(obs_data_t *settings, - obs_encoder_t *encoder) -@@ -1514,6 +1563,7 @@ static const char *amf_hevc_get_name(void *) - - static inline int get_hevc_preset(amf_base *enc, const char *preset) - { -+ UNUSED_PARAMETER(enc); - if (astrcmpi(preset, "balanced") == 0) - return AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_BALANCED; - else if (astrcmpi(preset, "speed") == 0) -@@ -1633,8 +1683,8 @@ static bool amf_hevc_init(void *data, obs_data_t *settings) - - info("settings:\n" - "\trate_control: %s\n" -- "\tbitrate: %d\n" -- "\tcqp: %d\n" -+ "\tbitrate: %" PRId64 "\n" -+ "\tcqp: %" PRId64 "\n" - "\tkeyint: %d\n" - "\tpreset: %s\n" - "\tprofile: %s\n" -@@ -1751,6 +1801,7 @@ static void amf_hevc_create_internal(amf_base *enc, obs_data_t *settings) - - static void *amf_hevc_create_texencode(obs_data_t *settings, - obs_encoder_t *encoder) -+#ifdef _WIN32 - try { - check_texture_encode_capability(encoder, amf_codec_type::HEVC); - -@@ -1773,6 +1824,12 @@ try { - blog(LOG_ERROR, "[texture-amf-h265] %s: %s", __FUNCTION__, err); - return obs_encoder_create_rerouted(encoder, "h265_fallback_amf"); - } -+#else -+{ -+ UNUSED_PARAMETER(settings); -+ return obs_encoder_create_rerouted(encoder, "h265_fallback_amf"); -+} -+#endif - - static void *amf_hevc_create_fallback(obs_data_t *settings, - obs_encoder_t *encoder) -@@ -1854,6 +1911,7 @@ static const char *amf_av1_get_name(void *) - - static inline int get_av1_preset(amf_base *enc, const char *preset) - { -+ UNUSED_PARAMETER(enc); - if (astrcmpi(preset, "highquality") == 0) - return AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_HIGH_QUALITY; - else if (astrcmpi(preset, "quality") == 0) -@@ -1987,8 +2045,8 @@ static bool amf_av1_init(void *data, obs_data_t *settings) - - info("settings:\n" - "\trate_control: %s\n" -- "\tbitrate: %d\n" -- "\tcqp: %d\n" -+ "\tbitrate: %" PRId64 "\n" -+ "\tcqp: %" PRId64 "\n" - "\tkeyint: %d\n" - "\tpreset: %s\n" - "\tprofile: %s\n" -@@ -2052,6 +2110,7 @@ static void amf_av1_create_internal(amf_base *enc, obs_data_t *settings) - - static void *amf_av1_create_texencode(obs_data_t *settings, - obs_encoder_t *encoder) -+#ifdef _WIN32 - try { - check_texture_encode_capability(encoder, amf_codec_type::AV1); - -@@ -2074,6 +2133,12 @@ try { - blog(LOG_ERROR, "[texture-amf-av1] %s: %s", __FUNCTION__, err); - return obs_encoder_create_rerouted(encoder, "av1_fallback_amf"); - } -+#else -+{ -+ UNUSED_PARAMETER(settings); -+ return obs_encoder_create_rerouted(encoder, "av1_fallback_amf"); -+} -+#endif - - static void *amf_av1_create_fallback(obs_data_t *settings, - obs_encoder_t *encoder) -@@ -2164,9 +2229,16 @@ static bool enum_luids(void *param, uint32_t idx, uint64_t luid) - return true; - } - -+#ifdef _WIN32 -+#define OBS_AMF_TEST "obs-amf-test.exe" -+#else -+#define OBS_AMF_TEST "obs-amf-test" -+#endif -+ - extern "C" void amf_load(void) - try { - AMF_RESULT res; -+#ifdef _WIN32 - HMODULE amf_module_test; - - /* Check if the DLL is present before running the more expensive */ -@@ -2176,16 +2248,24 @@ try { - if (!amf_module_test) - throw "No AMF library"; - FreeLibrary(amf_module_test); -+#else -+ void *amf_module_test = os_dlopen(AMF_DLL_NAMEA); -+ if (!amf_module_test) -+ throw "No AMF library"; -+ os_dlclose(amf_module_test); -+#endif - - /* ----------------------------------- */ - /* Check for supported codecs */ - -- BPtr test_exe = os_get_executable_path_ptr("obs-amf-test.exe"); -+ BPtr test_exe = os_get_executable_path_ptr(OBS_AMF_TEST); - std::stringstream cmd; - std::string caps_str; - - cmd << test_exe; -+#ifdef _WIN32 - enum_graphics_device_luids(enum_luids, &cmd); -+#endif - - os_process_pipe_t *pp = os_process_pipe_create(cmd.str().c_str(), "r"); - if (!pp) -@@ -2245,12 +2325,12 @@ try { - /* ----------------------------------- */ - /* Init AMF */ - -- amf_module = LoadLibraryW(AMF_DLL_NAME); -+ amf_module = os_dlopen(AMF_DLL_NAMEA); - if (!amf_module) - throw "AMF library failed to load"; - - AMFInit_Fn init = -- (AMFInit_Fn)GetProcAddress(amf_module, AMF_INIT_FUNCTION_NAME); -+ (AMFInit_Fn)os_dlsym(amf_module, AMF_INIT_FUNCTION_NAME); - if (!init) - throw "Failed to get AMFInit address"; - -@@ -2262,7 +2342,7 @@ try { - if (res != AMF_OK) - throw amf_error("GetTrace failed", res); - -- AMFQueryVersion_Fn get_ver = (AMFQueryVersion_Fn)GetProcAddress( -+ AMFQueryVersion_Fn get_ver = (AMFQueryVersion_Fn)os_dlsym( - amf_module, AMF_QUERY_VERSION_FUNCTION_NAME); - if (!get_ver) - throw "Failed to get AMFQueryVersion address"; -@@ -2301,7 +2381,7 @@ try { - } catch (const amf_error &err) { - /* doing an error here because it means at least the library has loaded - * successfully, so they probably have AMD at this point */ -- blog(LOG_ERROR, "%s: %s: 0x%lX", __FUNCTION__, err.str, -+ blog(LOG_ERROR, "%s: %s: 0x%uX", __FUNCTION__, err.str, - (uint32_t)err.res); - } - --- -2.40.0 - -From 33d3c849e8e68f0d479548640202d2e8e7041396 Mon Sep 17 00:00:00 2001 -From: Kurt Kartaltepe -Date: Mon, 6 Feb 2023 21:13:59 -0800 -Subject: [PATCH 2/5] libobs-opengl: Enable imported dmabufs for rendering - -For now just tag all imported images with GS_RENDER, this may not work -for some images that were produced by some hardware other than the gpu -render engines. But since we dont import vaapi decoded frames we -probably wont run into this. And we need this to render into vaapi -frames destined for encoding. ---- - libobs-opengl/gl-egl-common.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/libobs-opengl/gl-egl-common.c b/libobs-opengl/gl-egl-common.c -index f06cd1901..e53f5a275 100644 ---- a/libobs-opengl/gl-egl-common.c -+++ b/libobs-opengl/gl-egl-common.c -@@ -186,7 +186,7 @@ struct gs_texture *gl_egl_create_texture_from_eglimage( - - struct gs_texture *texture = NULL; - texture = gs_texture_create(width, height, color_format, 1, NULL, -- GS_GL_DUMMYTEX); -+ GS_GL_DUMMYTEX | GS_RENDER_TARGET); - const GLuint gltex = *(GLuint *)gs_texture_get_obj(texture); - - gl_bind_texture(GL_TEXTURE_2D, gltex); --- -2.40.0 - -From de0dd29322328c003944905c89b7da6401159fb5 Mon Sep 17 00:00:00 2001 -From: Kurt Kartaltepe -Date: Wed, 29 Mar 2023 10:20:22 +0200 -Subject: [PATCH 3/5] libobs,libobs-opengl: enable gpu encoding for opengl - -Enable all of the previously windows only paths for opengl backends that -support encode_texture2 ---- - libobs-opengl/gl-subsystem.c | 12 +++ - libobs/graphics/graphics-imports.c | 4 +- - libobs/graphics/graphics-internal.h | 20 ++-- - libobs/graphics/graphics.c | 156 ++++++++++++++-------------- - libobs/graphics/graphics.h | 13 ++- - libobs/obs-encoder.h | 3 + - libobs/obs-internal.h | 2 +- - libobs/obs-video-gpu-encode.c | 23 ++-- - libobs/obs-video.c | 22 ++-- - libobs/obs.c | 6 -- - 10 files changed, 135 insertions(+), 126 deletions(-) - -diff --git a/libobs-opengl/gl-subsystem.c b/libobs-opengl/gl-subsystem.c -index 0cdd46d08..8499af20e 100644 ---- a/libobs-opengl/gl-subsystem.c -+++ b/libobs-opengl/gl-subsystem.c -@@ -1519,6 +1519,18 @@ void gs_swapchain_destroy(gs_swapchain_t *swapchain) - bfree(swapchain); - } - -+bool device_nv12_available(gs_device_t *device) -+{ -+ UNUSED_PARAMETER(device); -+ return true; // always a split R8,R8G8 texture. -+} -+ -+bool device_p010_available(gs_device_t *device) -+{ -+ UNUSED_PARAMETER(device); -+ return true; // always a split R16,R16G16 texture. -+} -+ - uint32_t gs_voltexture_get_width(const gs_texture_t *voltex) - { - /* TODO */ -diff --git a/libobs/graphics/graphics-imports.c b/libobs/graphics/graphics-imports.c -index d6eaccccc..8de5bebb6 100644 ---- a/libobs/graphics/graphics-imports.c -+++ b/libobs/graphics/graphics-imports.c -@@ -195,6 +195,8 @@ bool load_graphics_imports(struct gs_exports *exports, void *module, - - GRAPHICS_IMPORT_OPTIONAL(device_nv12_available); - GRAPHICS_IMPORT_OPTIONAL(device_p010_available); -+ GRAPHICS_IMPORT_OPTIONAL(device_texture_create_nv12); -+ GRAPHICS_IMPORT_OPTIONAL(device_texture_create_p010); - - GRAPHICS_IMPORT(device_is_monitor_hdr); - -@@ -230,8 +232,6 @@ bool load_graphics_imports(struct gs_exports *exports, void *module, - GRAPHICS_IMPORT_OPTIONAL(device_texture_wrap_obj); - GRAPHICS_IMPORT_OPTIONAL(device_texture_acquire_sync); - GRAPHICS_IMPORT_OPTIONAL(device_texture_release_sync); -- GRAPHICS_IMPORT_OPTIONAL(device_texture_create_nv12); -- GRAPHICS_IMPORT_OPTIONAL(device_texture_create_p010); - GRAPHICS_IMPORT_OPTIONAL(device_stagesurface_create_nv12); - GRAPHICS_IMPORT_OPTIONAL(device_stagesurface_create_p010); - GRAPHICS_IMPORT_OPTIONAL(device_register_loss_callbacks); -diff --git a/libobs/graphics/graphics-internal.h b/libobs/graphics/graphics-internal.h -index d0ae5b895..268ad36da 100644 ---- a/libobs/graphics/graphics-internal.h -+++ b/libobs/graphics/graphics-internal.h -@@ -273,6 +273,16 @@ struct gs_exports { - - bool (*device_nv12_available)(gs_device_t *device); - bool (*device_p010_available)(gs_device_t *device); -+ bool (*device_texture_create_nv12)(gs_device_t *device, -+ gs_texture_t **tex_y, -+ gs_texture_t **tex_uv, -+ uint32_t width, uint32_t height, -+ uint32_t flags); -+ bool (*device_texture_create_p010)(gs_device_t *device, -+ gs_texture_t **tex_y, -+ gs_texture_t **tex_uv, -+ uint32_t width, uint32_t height, -+ uint32_t flags); - - bool (*device_is_monitor_hdr)(gs_device_t *device, void *monitor); - -@@ -330,16 +340,6 @@ struct gs_exports { - int (*device_texture_acquire_sync)(gs_texture_t *tex, uint64_t key, - uint32_t ms); - int (*device_texture_release_sync)(gs_texture_t *tex, uint64_t key); -- bool (*device_texture_create_nv12)(gs_device_t *device, -- gs_texture_t **tex_y, -- gs_texture_t **tex_uv, -- uint32_t width, uint32_t height, -- uint32_t flags); -- bool (*device_texture_create_p010)(gs_device_t *device, -- gs_texture_t **tex_y, -- gs_texture_t **tex_uv, -- uint32_t width, uint32_t height, -- uint32_t flags); - - gs_stagesurf_t *(*device_stagesurface_create_nv12)(gs_device_t *device, - uint32_t width, -diff --git a/libobs/graphics/graphics.c b/libobs/graphics/graphics.c -index 288fb1db6..78a7fc27b 100644 ---- a/libobs/graphics/graphics.c -+++ b/libobs/graphics/graphics.c -@@ -2908,6 +2908,84 @@ void gs_debug_marker_end(void) - thread_graphics->device); - } - -+bool gs_texture_create_nv12(gs_texture_t **tex_y, gs_texture_t **tex_uv, -+ uint32_t width, uint32_t height, uint32_t flags) -+{ -+ graphics_t *graphics = thread_graphics; -+ bool success = false; -+ -+ if (!gs_valid("gs_texture_create_nv12")) -+ return false; -+ -+ if ((width & 1) == 1 || (height & 1) == 1) { -+ blog(LOG_ERROR, "NV12 textures must have dimensions " -+ "divisible by 2."); -+ return false; -+ } -+ -+ if (graphics->exports.device_texture_create_nv12) { -+ success = graphics->exports.device_texture_create_nv12( -+ graphics->device, tex_y, tex_uv, width, height, flags); -+ if (success) -+ return true; -+ } -+ -+ *tex_y = gs_texture_create(width, height, GS_R8, 1, NULL, flags); -+ *tex_uv = gs_texture_create(width / 2, height / 2, GS_R8G8, 1, NULL, -+ flags); -+ -+ if (!*tex_y || !*tex_uv) { -+ if (*tex_y) -+ gs_texture_destroy(*tex_y); -+ if (*tex_uv) -+ gs_texture_destroy(*tex_uv); -+ *tex_y = NULL; -+ *tex_uv = NULL; -+ return false; -+ } -+ -+ return true; -+} -+ -+bool gs_texture_create_p010(gs_texture_t **tex_y, gs_texture_t **tex_uv, -+ uint32_t width, uint32_t height, uint32_t flags) -+{ -+ graphics_t *graphics = thread_graphics; -+ bool success = false; -+ -+ if (!gs_valid("gs_texture_create_p010")) -+ return false; -+ -+ if ((width & 1) == 1 || (height & 1) == 1) { -+ blog(LOG_ERROR, "P010 textures must have dimensions " -+ "divisible by 2."); -+ return false; -+ } -+ -+ if (graphics->exports.device_texture_create_p010) { -+ success = graphics->exports.device_texture_create_p010( -+ graphics->device, tex_y, tex_uv, width, height, flags); -+ if (success) -+ return true; -+ } -+ -+ *tex_y = gs_texture_create(width, height, GS_R16, 1, NULL, flags); -+ *tex_uv = gs_texture_create(width / 2, height / 2, GS_RG16, 1, NULL, -+ flags); -+ -+ if (!*tex_y || !*tex_uv) { -+ if (*tex_y) -+ gs_texture_destroy(*tex_y); -+ if (*tex_uv) -+ gs_texture_destroy(*tex_uv); -+ *tex_y = NULL; -+ *tex_uv = NULL; -+ return false; -+ } -+ -+ return true; -+} -+ - #ifdef __APPLE__ - - /** Platform specific functions */ -@@ -3175,84 +3253,6 @@ int gs_texture_release_sync(gs_texture_t *tex, uint64_t key) - return -1; - } - --bool gs_texture_create_nv12(gs_texture_t **tex_y, gs_texture_t **tex_uv, -- uint32_t width, uint32_t height, uint32_t flags) --{ -- graphics_t *graphics = thread_graphics; -- bool success = false; -- -- if (!gs_valid("gs_texture_create_nv12")) -- return false; -- -- if ((width & 1) == 1 || (height & 1) == 1) { -- blog(LOG_ERROR, "NV12 textures must have dimensions " -- "divisible by 2."); -- return false; -- } -- -- if (graphics->exports.device_texture_create_nv12) { -- success = graphics->exports.device_texture_create_nv12( -- graphics->device, tex_y, tex_uv, width, height, flags); -- if (success) -- return true; -- } -- -- *tex_y = gs_texture_create(width, height, GS_R8, 1, NULL, flags); -- *tex_uv = gs_texture_create(width / 2, height / 2, GS_R8G8, 1, NULL, -- flags); -- -- if (!*tex_y || !*tex_uv) { -- if (*tex_y) -- gs_texture_destroy(*tex_y); -- if (*tex_uv) -- gs_texture_destroy(*tex_uv); -- *tex_y = NULL; -- *tex_uv = NULL; -- return false; -- } -- -- return true; --} -- --bool gs_texture_create_p010(gs_texture_t **tex_y, gs_texture_t **tex_uv, -- uint32_t width, uint32_t height, uint32_t flags) --{ -- graphics_t *graphics = thread_graphics; -- bool success = false; -- -- if (!gs_valid("gs_texture_create_p010")) -- return false; -- -- if ((width & 1) == 1 || (height & 1) == 1) { -- blog(LOG_ERROR, "P010 textures must have dimensions " -- "divisible by 2."); -- return false; -- } -- -- if (graphics->exports.device_texture_create_p010) { -- success = graphics->exports.device_texture_create_p010( -- graphics->device, tex_y, tex_uv, width, height, flags); -- if (success) -- return true; -- } -- -- *tex_y = gs_texture_create(width, height, GS_R16, 1, NULL, flags); -- *tex_uv = gs_texture_create(width / 2, height / 2, GS_RG16, 1, NULL, -- flags); -- -- if (!*tex_y || !*tex_uv) { -- if (*tex_y) -- gs_texture_destroy(*tex_y); -- if (*tex_uv) -- gs_texture_destroy(*tex_uv); -- *tex_y = NULL; -- *tex_uv = NULL; -- return false; -- } -- -- return true; --} -- - gs_stagesurf_t *gs_stagesurface_create_nv12(uint32_t width, uint32_t height) - { - graphics_t *graphics = thread_graphics; -diff --git a/libobs/graphics/graphics.h b/libobs/graphics/graphics.h -index 0f62d5b95..ee17a65fa 100644 ---- a/libobs/graphics/graphics.h -+++ b/libobs/graphics/graphics.h -@@ -857,6 +857,12 @@ EXPORT bool gs_timer_range_get_data(gs_timer_range_t *range, bool *disjoint, - - EXPORT bool gs_nv12_available(void); - EXPORT bool gs_p010_available(void); -+EXPORT bool gs_texture_create_nv12(gs_texture_t **tex_y, gs_texture_t **tex_uv, -+ uint32_t width, uint32_t height, -+ uint32_t flags); -+EXPORT bool gs_texture_create_p010(gs_texture_t **tex_y, gs_texture_t **tex_uv, -+ uint32_t width, uint32_t height, -+ uint32_t flags); - - EXPORT bool gs_is_monitor_hdr(void *monitor); - -@@ -955,13 +961,6 @@ EXPORT int gs_texture_acquire_sync(gs_texture_t *tex, uint64_t key, - */ - EXPORT int gs_texture_release_sync(gs_texture_t *tex, uint64_t key); - --EXPORT bool gs_texture_create_nv12(gs_texture_t **tex_y, gs_texture_t **tex_uv, -- uint32_t width, uint32_t height, -- uint32_t flags); --EXPORT bool gs_texture_create_p010(gs_texture_t **tex_y, gs_texture_t **tex_uv, -- uint32_t width, uint32_t height, -- uint32_t flags); -- - EXPORT gs_stagesurf_t *gs_stagesurface_create_nv12(uint32_t width, - uint32_t height); - EXPORT gs_stagesurf_t *gs_stagesurface_create_p010(uint32_t width, -diff --git a/libobs/obs-encoder.h b/libobs/obs-encoder.h -index 6e831af5c..c6184bfb5 100644 ---- a/libobs/obs-encoder.h -+++ b/libobs/obs-encoder.h -@@ -29,6 +29,9 @@ - extern "C" { - #endif - -+struct obs_encoder; -+typedef struct obs_encoder obs_encoder_t; -+ - #define OBS_ENCODER_CAP_DEPRECATED (1 << 0) - #define OBS_ENCODER_CAP_PASS_TEXTURE (1 << 1) - #define OBS_ENCODER_CAP_DYN_BITRATE (1 << 2) -diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h -index 1ea555c3a..6e975d065 100644 ---- a/libobs/obs-internal.h -+++ b/libobs/obs-internal.h -@@ -268,9 +268,9 @@ struct obs_core_video_mix { - gs_stagesurf_t *active_copy_surfaces[NUM_TEXTURES][NUM_CHANNELS]; - gs_stagesurf_t *copy_surfaces[NUM_TEXTURES][NUM_CHANNELS]; - gs_texture_t *convert_textures[NUM_CHANNELS]; -+ gs_texture_t *convert_textures_encode[NUM_CHANNELS]; - #ifdef _WIN32 - gs_stagesurf_t *copy_surfaces_encode[NUM_TEXTURES]; -- gs_texture_t *convert_textures_encode[NUM_CHANNELS]; - #endif - gs_texture_t *render_texture; - gs_texture_t *output_texture; -diff --git a/libobs/obs-video-gpu-encode.c b/libobs/obs-video-gpu-encode.c -index 0dfb11df0..0d65a6d17 100644 ---- a/libobs/obs-video-gpu-encode.c -+++ b/libobs/obs-video-gpu-encode.c -@@ -17,8 +17,11 @@ - - #include "obs-internal.h" - --static void *gpu_encode_thread(struct obs_core_video_mix *video) -+#define NBSP "\xC2\xA0" -+static const char *gpu_encode_frame_name = "gpu_encode_frame"; -+static void *gpu_encode_thread(void *data) - { -+ struct obs_core_video_mix *video = data; - uint64_t interval = video_output_get_frame_time(video->video); - DARRAY(obs_encoder_t *) encoders; - int wait_frames = NUM_ENCODE_TEXTURE_FRAMES_TO_WAIT; -@@ -26,6 +29,10 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video) - da_init(encoders); - - os_set_thread_name("obs gpu encode thread"); -+ const char *gpu_encode_thread_name = profile_store_name( -+ obs_get_profiler_name_store(), -+ "obs_gpu_encode_thread(%g" NBSP "ms)", interval / 1000000.); -+ profile_register_root(gpu_encode_thread_name, interval); - - while (os_sem_wait(video->gpu_encode_semaphore) == 0) { - struct obs_tex_frame tf; -@@ -42,6 +49,8 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video) - continue; - } - -+ profile_start(gpu_encode_thread_name); -+ - os_event_reset(video->gpu_encode_inactive); - - /* -------------- */ -@@ -141,6 +150,9 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video) - obs_encoder_release(encoders.array[i]); - - da_resize(encoders, 0); -+ -+ profile_end(gpu_encode_thread_name); -+ profile_reenable_thread(); - } - - da_free(encoders); -@@ -149,7 +161,6 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video) - - bool init_gpu_encoding(struct obs_core_video_mix *video) - { --#ifdef _WIN32 - const struct video_output_info *info = - video_output_get_info(video->video); - -@@ -173,7 +184,11 @@ bool init_gpu_encoding(struct obs_core_video_mix *video) - return false; - } - -+#ifdef _WIN32 - uint32_t handle = gs_texture_get_shared_handle(tex); -+#else -+ uint32_t handle = (uint32_t)-1; -+#endif - - struct obs_tex_frame frame = { - .tex = tex, .tex_uv = tex_uv, .handle = handle}; -@@ -195,10 +210,6 @@ bool init_gpu_encoding(struct obs_core_video_mix *video) - - video->gpu_encode_thread_initialized = true; - return true; --#else -- UNUSED_PARAMETER(video); -- return false; --#endif - } - - void stop_gpu_encoding_thread(struct obs_core_video_mix *video) -diff --git a/libobs/obs-video.c b/libobs/obs-video.c -index 60acaaf6f..8918b869d 100644 ---- a/libobs/obs-video.c -+++ b/libobs/obs-video.c -@@ -427,7 +427,6 @@ stage_output_texture(struct obs_core_video_mix *video, int cur_texture, - profile_end(stage_output_texture_name); - } - --#ifdef _WIN32 - static inline bool queue_frame(struct obs_core_video_mix *video, - bool raw_active, - struct obs_vframe_info *vframe_info) -@@ -455,7 +454,9 @@ static inline bool queue_frame(struct obs_core_video_mix *video, - circlebuf_pop_front(&video->gpu_encoder_avail_queue, &tf, sizeof(tf)); - - if (tf.released) { -+#ifdef _WIN32 - gs_texture_acquire_sync(tf.tex, tf.lock_key, GS_WAIT_INFINITE); -+#endif - tf.released = false; - } - -@@ -479,8 +480,10 @@ static inline bool queue_frame(struct obs_core_video_mix *video, - tf.count = 1; - tf.timestamp = vframe_info->timestamp; - tf.released = true; -+#ifdef _WIN32 - tf.handle = gs_texture_get_shared_handle(tf.tex); - gs_texture_release_sync(tf.tex, ++tf.lock_key); -+#endif - circlebuf_push_back(&video->gpu_encoder_queue, &tf, sizeof(tf)); - - os_sem_post(video->gpu_encode_semaphore); -@@ -520,7 +523,6 @@ static void output_gpu_encoders(struct obs_core_video_mix *video, - end: - profile_end(output_gpu_encoders_name); - } --#endif - - static inline void render_video(struct obs_core_video_mix *video, - bool raw_active, const bool gpu_active, -@@ -540,26 +542,24 @@ static inline void render_video(struct obs_core_video_mix *video, - size_t channel_count = NUM_CHANNELS; - gs_texture_t *output_texture = render_output_texture(video); - --#ifdef _WIN32 - if (gpu_active) { - convert_textures = video->convert_textures_encode; -+#ifdef _WIN32 - copy_surfaces = video->copy_surfaces_encode; - channel_count = 1; -+#endif - gs_flush(); - } --#endif - - if (video->gpu_conversion) { - render_convert_texture(video, convert_textures, - output_texture); - } - --#ifdef _WIN32 - if (gpu_active) { - gs_flush(); - output_gpu_encoders(video, raw_active); - } --#endif - - if (raw_active) { - stage_output_texture(video, cur_texture, -@@ -963,12 +963,10 @@ static void clear_raw_frame_data(struct obs_core_video_mix *video) - circlebuf_free(&video->vframe_info_buffer); - } - --#ifdef _WIN32 - static void clear_gpu_frame_data(struct obs_core_video_mix *video) - { - circlebuf_free(&video->vframe_info_buffer_gpu); - } --#endif - - extern THREAD_LOCAL bool is_graphics_thread; - -@@ -1076,30 +1074,22 @@ static const char *output_frame_name = "output_frame"; - static inline void update_active_state(struct obs_core_video_mix *video) - { - const bool raw_was_active = video->raw_was_active; --#ifdef _WIN32 - const bool gpu_was_active = video->gpu_was_active; --#endif - const bool was_active = video->was_active; - - bool raw_active = os_atomic_load_long(&video->raw_active) > 0; --#ifdef _WIN32 - const bool gpu_active = - os_atomic_load_long(&video->gpu_encoder_active) > 0; - const bool active = raw_active || gpu_active; --#else -- const bool active = raw_active; --#endif - - if (!was_active && active) - clear_base_frame_data(video); - if (!raw_was_active && raw_active) - clear_raw_frame_data(video); --#ifdef _WIN32 - if (!gpu_was_active && gpu_active) - clear_gpu_frame_data(video); - - video->gpu_was_active = gpu_active; --#endif - video->raw_was_active = raw_active; - video->was_active = active; - } -diff --git a/libobs/obs.c b/libobs/obs.c -index 1850ecc75..1e57f2517 100644 ---- a/libobs/obs.c -+++ b/libobs/obs.c -@@ -179,7 +179,6 @@ static bool obs_init_gpu_conversion(struct obs_core_video_mix *video) - video->convert_textures[0] = NULL; - video->convert_textures[1] = NULL; - video->convert_textures[2] = NULL; --#ifdef _WIN32 - video->convert_textures_encode[0] = NULL; - video->convert_textures_encode[1] = NULL; - video->convert_textures_encode[2] = NULL; -@@ -200,7 +199,6 @@ static bool obs_init_gpu_conversion(struct obs_core_video_mix *video) - return false; - } - } --#endif - - bool success = true; - -@@ -297,13 +295,11 @@ static bool obs_init_gpu_conversion(struct obs_core_video_mix *video) - gs_texture_destroy(video->convert_textures[c]); - video->convert_textures[c] = NULL; - } --#ifdef _WIN32 - if (video->convert_textures_encode[c]) { - gs_texture_destroy( - video->convert_textures_encode[c]); - video->convert_textures_encode[c] = NULL; - } --#endif - } - } - -@@ -817,12 +813,10 @@ static void obs_free_render_textures(struct obs_core_video_mix *video) - gs_texture_destroy(video->convert_textures[c]); - video->convert_textures[c] = NULL; - } --#ifdef _WIN32 - if (video->convert_textures_encode[c]) { - gs_texture_destroy(video->convert_textures_encode[c]); - video->convert_textures_encode[c] = NULL; - } --#endif - } - - gs_texture_destroy(video->output_texture); --- -2.40.0 - -From d9c1a0ce4ae3b7a2465b0f77dd1bc8e8ff74dd21 Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Sun, 11 Jul 2021 21:23:07 +0200 -Subject: [PATCH 4/5] libobs: Add encode_texture2 function to struct - obs_encoder_info - -And use it if non-NULL instead of encode_texture. ---- - libobs/obs-encoder.c | 21 ++++++++++++++++++- - libobs/obs-encoder.h | 33 ++++++++++++++++++++++++++++++ - libobs/obs-internal.h | 3 +++ - libobs/obs-module.c | 38 +++++++++++++++++++++++++---------- - libobs/obs-video-gpu-encode.c | 33 +++++++++++++++++++++++++----- - 5 files changed, 111 insertions(+), 17 deletions(-) - -diff --git a/libobs/obs-encoder.c b/libobs/obs-encoder.c -index 677b92f7d..83bf911c9 100644 ---- a/libobs/obs-encoder.c -+++ b/libobs/obs-encoder.c -@@ -194,7 +194,7 @@ static void add_connection(struct obs_encoder *encoder) - &audio_info, receive_audio, encoder); - } else { - struct video_scale_info info = {0}; -- get_video_info(encoder, &info); -+ obs_encoder_get_video_info(encoder, &info); - - if (gpu_encode_available(encoder)) { - start_gpu_encode(encoder); -@@ -528,6 +528,25 @@ void obs_encoder_shutdown(obs_encoder_t *encoder) - pthread_mutex_unlock(&encoder->init_mutex); - } - -+void obs_encoder_get_video_info(struct obs_encoder *encoder, -+ struct video_scale_info *info) -+{ -+ const struct video_output_info *voi; -+ voi = video_output_get_info(encoder->media); -+ -+ info->format = voi->format; -+ info->colorspace = voi->colorspace; -+ info->range = voi->range; -+ info->width = obs_encoder_get_width(encoder); -+ info->height = obs_encoder_get_height(encoder); -+ -+ if (encoder->info.get_video_info) -+ encoder->info.get_video_info(encoder->context.data, info); -+ -+ if (info->width != voi->width || info->height != voi->height) -+ obs_encoder_set_scaled_size(encoder, info->width, info->height); -+} -+ - static inline size_t - get_callback_idx(const struct obs_encoder *encoder, - void (*new_packet)(void *param, struct encoder_packet *packet), -diff --git a/libobs/obs-encoder.h b/libobs/obs-encoder.h -index c6184bfb5..f33e668bf 100644 ---- a/libobs/obs-encoder.h -+++ b/libobs/obs-encoder.h -@@ -105,6 +105,18 @@ struct encoder_frame { - int64_t pts; - }; - -+struct gs_texture; -+ -+/** Encoder input texture */ -+struct encoder_texture { -+ /** Texture format and size */ -+ struct video_scale_info info; -+ /** Shared texture handle, only set on Windows */ -+ uint32_t handle; -+ /** Textures, NULL-terminated */ -+ struct gs_texture *tex[5]; -+}; -+ - /** - * Encoder interface - * -@@ -265,6 +277,27 @@ struct obs_encoder_info { - uint64_t lock_key, uint64_t *next_key, - struct encoder_packet *packet, - bool *received_packet); -+ -+ /** -+ * Returns whether texture encoding is available for this video format -+ * -+ * Has no effect if caps does not contain OBS_ENCODER_CAP_PASS_TEXTURE. -+ * If this function is not defined, it is assumed that only textures in -+ * NV12 format are supported. -+ * -+ * @param data Data associated with this encoder context -+ * @param[in] info Video format information -+ * @return Whether the encoder supports texture encoding -+ * with this video format -+ */ -+ bool (*encode_texture_available)(void *data, -+ const struct video_scale_info *info); -+ -+ bool (*encode_texture2)(void *data, struct encoder_texture *texture, -+ int64_t pts, uint64_t lock_key, -+ uint64_t *next_key, -+ struct encoder_packet *packet, -+ bool *received_packet); - }; - - EXPORT void obs_register_encoder_s(const struct obs_encoder_info *info, -diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h -index 6e975d065..2abfbddee 100644 ---- a/libobs/obs-internal.h -+++ b/libobs/obs-internal.h -@@ -1259,6 +1259,9 @@ extern struct obs_encoder_info *find_encoder(const char *id); - extern bool obs_encoder_initialize(obs_encoder_t *encoder); - extern void obs_encoder_shutdown(obs_encoder_t *encoder); - -+extern void obs_encoder_get_video_info(struct obs_encoder *encoder, -+ struct video_scale_info *info); -+ - extern void obs_encoder_start(obs_encoder_t *encoder, - void (*new_packet)(void *param, - struct encoder_packet *packet), -diff --git a/libobs/obs-module.c b/libobs/obs-module.c -index cd7841b6c..443c97b23 100644 ---- a/libobs/obs-module.c -+++ b/libobs/obs-module.c -@@ -679,16 +679,30 @@ cleanup: - da_push_back(dest, &data); \ - } while (false) - --#define CHECK_REQUIRED_VAL(type, info, val, func) \ -- do { \ -- if ((offsetof(type, val) + sizeof(info->val) > size) || \ -- !info->val) { \ -- blog(LOG_ERROR, \ -- "Required value '" #val "' for " \ -- "'%s' not found. " #func " failed.", \ -- info->id); \ -- goto error; \ -- } \ -+#define HAS_VAL(type, info, val) \ -+ ((offsetof(type, val) + sizeof(info->val) <= size) && info->val) -+ -+#define CHECK_REQUIRED_VAL(type, info, val, func) \ -+ do { \ -+ if (!HAS_VAL(type, info, val)) { \ -+ blog(LOG_ERROR, \ -+ "Required value '" #val "' for " \ -+ "'%s' not found. " #func " failed.", \ -+ info->id); \ -+ goto error; \ -+ } \ -+ } while (false) -+ -+#define CHECK_REQUIRED_VAL_EITHER(type, info, val1, val2, func) \ -+ do { \ -+ if (!HAS_VAL(type, info, val1) && \ -+ !HAS_VAL(type, info, val2)) { \ -+ blog(LOG_ERROR, \ -+ "Neither '" #val1 "' nor '" #val2 "' " \ -+ "for '%s' found. " #func " failed.", \ -+ info->id); \ -+ goto error; \ -+ } \ - } while (false) - - #define HANDLE_ERROR(size_var, structure, info) \ -@@ -899,7 +913,9 @@ void obs_register_encoder_s(const struct obs_encoder_info *info, size_t size) - CHECK_REQUIRED_VAL_(info, destroy, obs_register_encoder); - - if ((info->caps & OBS_ENCODER_CAP_PASS_TEXTURE) != 0) -- CHECK_REQUIRED_VAL_(info, encode_texture, obs_register_encoder); -+ CHECK_REQUIRED_VAL_EITHER(struct obs_encoder_info, info, -+ encode_texture, encode_texture2, -+ obs_register_encoder); - else - CHECK_REQUIRED_VAL_(info, encode, obs_register_encoder); - -diff --git a/libobs/obs-video-gpu-encode.c b/libobs/obs-video-gpu-encode.c -index 0d65a6d17..394ded9b6 100644 ---- a/libobs/obs-video-gpu-encode.c -+++ b/libobs/obs-video-gpu-encode.c -@@ -78,7 +78,7 @@ static void *gpu_encode_thread(void *data) - for (size_t i = 0; i < encoders.num; i++) { - struct encoder_packet pkt = {0}; - bool received = false; -- bool success; -+ bool success = false; - - obs_encoder_t *encoder = encoders.array[i]; - struct obs_encoder *pair = encoder->paired_encoder; -@@ -111,10 +111,33 @@ static void *gpu_encode_thread(void *data) - else - next_key++; - -- success = encoder->info.encode_texture( -- encoder->context.data, tf.handle, -- encoder->cur_pts, lock_key, &next_key, &pkt, -- &received); -+ if (encoder->info.encode_texture2) { -+ union { -+ struct encoder_texture tex; -+ /* MSVC complains about -+ offsetof(..., tex[3]) */ -+ char dummy[offsetof(struct encoder_texture, -+ tex) + -+ sizeof(struct gs_texture *) * -+ 3]; -+ } u = {0}; -+ -+ obs_encoder_get_video_info(encoder, -+ &u.tex.info); -+ u.tex.handle = tf.handle; -+ u.tex.tex[0] = tf.tex; -+ u.tex.tex[1] = tf.tex_uv; -+ u.tex.tex[2] = NULL; -+ success = encoder->info.encode_texture2( -+ encoder->context.data, &u.tex, -+ encoder->cur_pts, lock_key, &next_key, -+ &pkt, &received); -+ } else { -+ success = encoder->info.encode_texture( -+ encoder->context.data, tf.handle, -+ encoder->cur_pts, lock_key, &next_key, -+ &pkt, &received); -+ } - send_off_encoder_packet(encoder, success, received, - &pkt); - --- -2.40.0 - -From 0475795cdbf7c7bcb90bb373a10bbd5a7ce17a07 Mon Sep 17 00:00:00 2001 -From: David Rosca -Date: Thu, 30 Mar 2023 16:48:02 +0200 -Subject: [PATCH 5/5] obs-ffmpeg: Implement Linux AMF texture encoding - -v2: don't require vk_enum_string_helper.h -v3: only use one set of GL interop textures -v4: wait on Vulkan copy fence -v5: wait on GL copy sem + Vulkan external queue transfer -v6: use optimal tiling -v7: fix some validation errors -v8: init AMF context with our Vulkan device ---- - plugins/obs-ffmpeg/CMakeLists.txt | 3 +- - plugins/obs-ffmpeg/cmake/legacy.cmake | 3 +- - plugins/obs-ffmpeg/texture-amf.cpp | 939 +++++++++++++++++++++++++- - 3 files changed, 913 insertions(+), 32 deletions(-) - -diff --git a/plugins/obs-ffmpeg/CMakeLists.txt b/plugins/obs-ffmpeg/CMakeLists.txt -index 778d93ffb..97376182f 100644 ---- a/plugins/obs-ffmpeg/CMakeLists.txt -+++ b/plugins/obs-ffmpeg/CMakeLists.txt -@@ -112,9 +112,10 @@ elseif(OS_LINUX OR OS_FREEBSD) - - find_package(Libva REQUIRED) - find_package(Libpci REQUIRED) -+ find_package(Vulkan REQUIRED) - - 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) -+ target_link_libraries(obs-ffmpeg PRIVATE Libva::va Libva::drm Libpci::pci Vulkan::Vulkan) - endif() - - set_target_properties_obs(obs-ffmpeg PROPERTIES FOLDER plugins/obs-ffmpeg PREFIX "") -diff --git a/plugins/obs-ffmpeg/cmake/legacy.cmake b/plugins/obs-ffmpeg/cmake/legacy.cmake -index 78b8c30a1..b29eef673 100644 ---- a/plugins/obs-ffmpeg/cmake/legacy.cmake -+++ b/plugins/obs-ffmpeg/cmake/legacy.cmake -@@ -109,8 +109,9 @@ elseif(OS_POSIX AND NOT OS_MACOS) - add_subdirectory(obs-amf-test) - find_package(Libva REQUIRED) - find_package(Libpci REQUIRED) -+ find_package(Vulkan REQUIRED) - 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) -+ target_link_libraries(obs-ffmpeg PRIVATE Libva::va Libva::drm LIBPCI::LIBPCI Vulkan::Vulkan) - endif() - - setup_plugin_target(obs-ffmpeg) -diff --git a/plugins/obs-ffmpeg/texture-amf.cpp b/plugins/obs-ffmpeg/texture-amf.cpp -index fe651f0e1..0f5ee7b91 100644 ---- a/plugins/obs-ffmpeg/texture-amf.cpp -+++ b/plugins/obs-ffmpeg/texture-amf.cpp -@@ -29,6 +29,15 @@ - #include - #endif - -+#ifdef __linux -+#include -+#include -+#include -+#include -+#include -+#include -+#endif -+ - #include - #include - #include -@@ -57,14 +66,89 @@ struct amf_error { - } - }; - -+#define VK_CHECK(f) \ -+ { \ -+ VkResult res = (f); \ -+ if (res != VK_SUCCESS) { \ -+ blog(LOG_ERROR, "Vulkan error: " __FILE__ ":%d", \ -+ __LINE__); \ -+ throw "Vulkan error"; \ -+ } \ -+ } -+ -+static VkFormat to_vk_format(AMF_SURFACE_FORMAT fmt) -+{ -+ switch (fmt) { -+ case AMF_SURFACE_NV12: -+ return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; -+ case AMF_SURFACE_P010: -+ return VK_FORMAT_G16_B16R16_2PLANE_420_UNORM; -+ default: -+ throw "Unsupported AMF_SURFACE_FORMAT"; -+ } -+} -+ -+static VkFormat to_vk_format(enum gs_color_format fmt) -+{ -+ switch (fmt) { -+ case GS_R8: -+ return VK_FORMAT_R8_UNORM; -+ case GS_R16: -+ return VK_FORMAT_R16_UNORM; -+ case GS_R8G8: -+ return VK_FORMAT_R8G8_UNORM; -+ case GS_RG16: -+ return VK_FORMAT_R16G16_UNORM; -+ default: -+ throw "Unsupported gs_color_format"; -+ } -+} -+ -+static GLenum to_gl_format(enum gs_color_format fmt) -+{ -+ switch (fmt) { -+ case GS_R8: -+ return GL_R8; -+ case GS_R16: -+ return GL_R16; -+ case GS_R8G8: -+ return GL_RG8; -+ case GS_RG16: -+ return GL_RG16; -+ default: -+ throw "Unsupported gs_color_format"; -+ } -+} -+ - struct handle_tex { - uint32_t handle; - #ifdef _WIN32 - ComPtr tex; - ComPtr km; -+#else -+ AMFVulkanSurface *surfaceVk = nullptr; - #endif - }; - -+#ifdef __linux -+struct gl_tex { -+ GLuint glsem = 0; -+ VkSemaphore sem = VK_NULL_HANDLE; -+ GLuint glCopySem = 0; -+ VkSemaphore copySem = VK_NULL_HANDLE; -+ VkFence copyFence = VK_NULL_HANDLE; -+ struct { -+ uint32_t width = 0; -+ uint32_t height = 0; -+ VkImage image = VK_NULL_HANDLE; -+ VkDeviceMemory memory = VK_NULL_HANDLE; -+ GLuint glmem = 0; -+ GLuint gltex = 0; -+ GLuint fbo = 0; -+ } planes[2]; -+}; -+#endif -+ - struct adapter_caps { - bool is_amd = false; - bool supports_avc = false; -@@ -97,6 +181,7 @@ struct amf_base { - bool fallback; - - AMFContextPtr amf_context; -+ AMFContext1Ptr amf_context1; - AMFComponentPtr amf_encoder; - AMFBufferPtr packet_data; - AMFRate amf_frame_rate; -@@ -130,6 +215,9 @@ using buf_t = std::vector; - - #ifdef _WIN32 - using d3dtex_t = ComPtr; -+#else -+using d3dtex_t = handle_tex; -+#endif - - struct amf_texencode : amf_base, public AMFSurfaceObserver { - volatile bool destroying = false; -@@ -140,11 +228,92 @@ struct amf_texencode : amf_base, public AMFSurfaceObserver { - std::vector available_textures; - std::unordered_map active_textures; - -+#ifdef _WIN32 - ComPtr device; - ComPtr context; -+#else -+ std::unique_ptr vk; -+ VkQueue queue = VK_NULL_HANDLE; -+ VkCommandPool cmdpool = VK_NULL_HANDLE; -+ VkCommandBuffer cmdbuf = VK_NULL_HANDLE; -+ struct gl_tex gltex = {}; -+ std::unordered_map read_fbos; -+ -+ PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR; -+ PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR; -+ PFNGLGETERRORPROC glGetError; -+ PFNGLCREATEMEMORYOBJECTSEXTPROC glCreateMemoryObjectsEXT; -+ PFNGLDELETEMEMORYOBJECTSEXTPROC glDeleteMemoryObjectsEXT; -+ PFNGLIMPORTMEMORYFDEXTPROC glImportMemoryFdEXT; -+ PFNGLISMEMORYOBJECTEXTPROC glIsMemoryObjectEXT; -+ PFNGLMEMORYOBJECTPARAMETERIVEXTPROC glMemoryObjectParameterivEXT; -+ PFNGLGENTEXTURESPROC glGenTextures; -+ PFNGLDELETETEXTURESPROC glDeleteTextures; -+ PFNGLBINDTEXTUREPROC glBindTexture; -+ PFNGLTEXPARAMETERIPROC glTexParameteri; -+ PFNGLTEXSTORAGEMEM2DEXTPROC glTexStorageMem2DEXT; -+ PFNGLGENSEMAPHORESEXTPROC glGenSemaphoresEXT; -+ PFNGLDELETESEMAPHORESEXTPROC glDeleteSemaphoresEXT; -+ PFNGLIMPORTSEMAPHOREFDEXTPROC glImportSemaphoreFdEXT; -+ PFNGLISSEMAPHOREEXTPROC glIsSemaphoreEXT; -+ PFNGLWAITSEMAPHOREEXTPROC glWaitSemaphoreEXT; -+ PFNGLSIGNALSEMAPHOREEXTPROC glSignalSemaphoreEXT; -+ PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; -+ PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; -+ PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; -+ PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; -+ PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer; -+#endif - - inline amf_texencode() : amf_base(false) {} -- ~amf_texencode() { os_atomic_set_bool(&destroying, true); } -+ ~amf_texencode() -+ { -+ os_atomic_set_bool(&destroying, true); -+#ifdef __linux -+ if (!vk) -+ return; -+ -+ vkDeviceWaitIdle(vk->hDevice); -+ vkFreeCommandBuffers(vk->hDevice, cmdpool, 1, &cmdbuf); -+ vkDestroyCommandPool(vk->hDevice, cmdpool, nullptr); -+ -+ for (auto t : input_textures) { -+ vkFreeMemory(vk->hDevice, t.surfaceVk->hMemory, -+ nullptr); -+ vkDestroyImage(vk->hDevice, t.surfaceVk->hImage, -+ nullptr); -+ delete t.surfaceVk; -+ } -+ -+ obs_enter_graphics(); -+ -+ for (int i = 0; i < 2; ++i) { -+ auto p = gltex.planes[i]; -+ vkFreeMemory(vk->hDevice, p.memory, nullptr); -+ vkDestroyImage(vk->hDevice, p.image, nullptr); -+ this->glDeleteMemoryObjectsEXT(1, &p.glmem); -+ this->glDeleteTextures(1, &p.gltex); -+ this->glDeleteFramebuffers(1, &p.fbo); -+ } -+ vkDestroySemaphore(vk->hDevice, gltex.sem, nullptr); -+ vkDestroySemaphore(vk->hDevice, gltex.copySem, nullptr); -+ vkDestroyFence(vk->hDevice, gltex.copyFence, nullptr); -+ this->glDeleteSemaphoresEXT(1, &gltex.glsem); -+ this->glDeleteSemaphoresEXT(1, &gltex.glCopySem); -+ -+ for (auto f : read_fbos) -+ this->glDeleteFramebuffers(1, &f.second); -+ -+ obs_leave_graphics(); -+ -+ amf_encoder->Terminate(); -+ amf_context1->Terminate(); -+ amf_context->Terminate(); -+ -+ vkDestroyDevice(vk->hDevice, nullptr); -+ vkDestroyInstance(vk->hInstance, nullptr); -+#endif -+ } - - void AMF_STD_CALL OnSurfaceDataRelease(amf::AMFSurface *surf) override - { -@@ -162,12 +331,189 @@ struct amf_texencode : amf_base, public AMFSurfaceObserver { - - void init() override - { -+#if defined(_WIN32) - AMF_RESULT res = amf_context->InitDX11(device, AMF_DX11_1); - if (res != AMF_OK) - throw amf_error("InitDX11 failed", res); -+#elif defined(__linux__) -+ vk = std::make_unique(); -+ vk->cbSizeof = sizeof(AMFVulkanDevice); -+ -+ std::vector instance_extensions = { -+ VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, -+ VK_KHR_SURFACE_EXTENSION_NAME, -+ }; -+ -+ std::vector device_extensions = { -+ VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, -+ VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, -+ VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, -+ VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, -+ }; -+ -+ amf_size count = 0; -+ amf_context1->GetVulkanDeviceExtensions(&count, nullptr); -+ device_extensions.resize(device_extensions.size() + count); -+ amf_context1->GetVulkanDeviceExtensions( -+ &count, -+ &device_extensions[device_extensions.size() - count]); -+ -+ VkApplicationInfo appInfo = {}; -+ appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; -+ appInfo.pApplicationName = "OBS"; -+ appInfo.apiVersion = VK_API_VERSION_1_2; -+ -+ VkInstanceCreateInfo instanceInfo = {}; -+ instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; -+ instanceInfo.pApplicationInfo = &appInfo; -+ instanceInfo.enabledExtensionCount = instance_extensions.size(); -+ instanceInfo.ppEnabledExtensionNames = -+ instance_extensions.data(); -+ VK_CHECK(vkCreateInstance(&instanceInfo, nullptr, -+ &vk->hInstance)); -+ -+ uint32_t deviceCount = 0; -+ VK_CHECK(vkEnumeratePhysicalDevices(vk->hInstance, &deviceCount, -+ nullptr)); -+ std::vector physicalDevices(deviceCount); -+ VK_CHECK(vkEnumeratePhysicalDevices(vk->hInstance, &deviceCount, -+ physicalDevices.data())); -+ for (VkPhysicalDevice dev : physicalDevices) { -+ VkPhysicalDeviceDriverProperties driverProps = {}; -+ driverProps.sType = -+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; -+ -+ VkPhysicalDeviceProperties2 props = {}; -+ props.sType = -+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; -+ props.pNext = &driverProps; -+ vkGetPhysicalDeviceProperties2(dev, &props); -+ if (driverProps.driverID == -+ VK_DRIVER_ID_AMD_PROPRIETARY) { -+ vk->hPhysicalDevice = dev; -+ break; -+ } -+ } -+ if (!vk->hPhysicalDevice) { -+ throw "Failed to find Vulkan device VK_DRIVER_ID_AMD_PROPRIETARY"; -+ } -+ -+ uint32_t deviceExtensionCount = 0; -+ VK_CHECK(vkEnumerateDeviceExtensionProperties( -+ vk->hPhysicalDevice, nullptr, &deviceExtensionCount, -+ nullptr)); -+ std::vector deviceExts( -+ deviceExtensionCount); -+ VK_CHECK(vkEnumerateDeviceExtensionProperties( -+ vk->hPhysicalDevice, nullptr, &deviceExtensionCount, -+ deviceExts.data())); -+ std::vector deviceExtensions; -+ for (const char *name : device_extensions) { -+ auto it = std::find_if( -+ deviceExts.begin(), deviceExts.end(), -+ [name](VkExtensionProperties e) { -+ return strcmp(e.extensionName, name) == -+ 0; -+ }); -+ if (it != deviceExts.end()) { -+ deviceExtensions.push_back(name); -+ } -+ } -+ -+ float queuePriority = 1.0; -+ std::vector queueInfos; -+ uint32_t queueFamilyCount; -+ vkGetPhysicalDeviceQueueFamilyProperties( -+ vk->hPhysicalDevice, &queueFamilyCount, nullptr); -+ std::vector queueFamilyProperties( -+ queueFamilyCount); -+ vkGetPhysicalDeviceQueueFamilyProperties( -+ vk->hPhysicalDevice, &queueFamilyCount, -+ queueFamilyProperties.data()); -+ for (uint32_t i = 0; i < queueFamilyProperties.size(); ++i) { -+ VkDeviceQueueCreateInfo queueInfo = {}; -+ queueInfo.sType = -+ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; -+ queueInfo.queueFamilyIndex = i; -+ queueInfo.queueCount = 1; -+ queueInfo.pQueuePriorities = &queuePriority; -+ queueInfos.push_back(queueInfo); -+ } -+ -+ VkDeviceCreateInfo deviceInfo = {}; -+ deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; -+ deviceInfo.queueCreateInfoCount = queueInfos.size(); -+ deviceInfo.pQueueCreateInfos = queueInfos.data(); -+ deviceInfo.enabledExtensionCount = deviceExtensions.size(); -+ deviceInfo.ppEnabledExtensionNames = deviceExtensions.data(); -+ VK_CHECK(vkCreateDevice(vk->hPhysicalDevice, &deviceInfo, -+ nullptr, &vk->hDevice)); -+ -+ AMF_RESULT res = amf_context1->InitVulkan(vk.get()); -+ if (res != AMF_OK) -+ throw amf_error("InitVulkan failed", res); -+ -+ vkGetDeviceQueue(vk->hDevice, 0, 0, &queue); -+ -+ VkCommandPoolCreateInfo cmdPoolInfo = {}; -+ cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; -+ cmdPoolInfo.queueFamilyIndex = 0; -+ cmdPoolInfo.flags = -+ VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; -+ VK_CHECK(vkCreateCommandPool(vk->hDevice, &cmdPoolInfo, nullptr, -+ &cmdpool)); -+ -+ VkCommandBufferAllocateInfo commandBufferInfo = {}; -+ commandBufferInfo.sType = -+ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; -+ commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; -+ commandBufferInfo.commandPool = cmdpool; -+ commandBufferInfo.commandBufferCount = 1; -+ VK_CHECK(vkAllocateCommandBuffers(vk->hDevice, -+ &commandBufferInfo, &cmdbuf)); -+ -+#define GET_PROC_VK(x) \ -+ x = reinterpret_cast( \ -+ vkGetDeviceProcAddr(vk->hDevice, #x)); \ -+ if (!x) \ -+ throw "Failed to resolve " #x; -+ -+#define GET_PROC_GL(x) \ -+ x = reinterpret_cast(eglGetProcAddress(#x)); \ -+ if (!x) \ -+ throw "Failed to resolve " #x; -+ -+ GET_PROC_VK(vkGetMemoryFdKHR); -+ GET_PROC_VK(vkGetSemaphoreFdKHR); -+ GET_PROC_GL(glGetError); -+ GET_PROC_GL(glCreateMemoryObjectsEXT); -+ GET_PROC_GL(glDeleteMemoryObjectsEXT); -+ GET_PROC_GL(glImportMemoryFdEXT); -+ GET_PROC_GL(glIsMemoryObjectEXT); -+ GET_PROC_GL(glMemoryObjectParameterivEXT); -+ GET_PROC_GL(glGenTextures); -+ GET_PROC_GL(glDeleteTextures); -+ GET_PROC_GL(glBindTexture); -+ GET_PROC_GL(glTexParameteri); -+ GET_PROC_GL(glTexStorageMem2DEXT); -+ GET_PROC_GL(glGenSemaphoresEXT); -+ GET_PROC_GL(glDeleteSemaphoresEXT); -+ GET_PROC_GL(glImportSemaphoreFdEXT); -+ GET_PROC_GL(glIsSemaphoreEXT); -+ GET_PROC_GL(glWaitSemaphoreEXT); -+ GET_PROC_GL(glSignalSemaphoreEXT); -+ GET_PROC_GL(glGenFramebuffers); -+ GET_PROC_GL(glDeleteFramebuffers); -+ GET_PROC_GL(glBindFramebuffer); -+ GET_PROC_GL(glFramebufferTexture2D); -+ GET_PROC_GL(glBlitFramebuffer); -+ -+#undef GET_PROC_VK -+#undef GET_PROC_GL -+ -+#endif - } - }; --#endif - - struct amf_fallback : amf_base, public AMFSurfaceObserver { - volatile bool destroying = false; -@@ -200,13 +546,7 @@ struct amf_fallback : amf_base, public AMFSurfaceObserver { - if (res != AMF_OK) - throw amf_error("InitDX11 failed", res); - #elif defined(__linux__) -- AMFContext1 *context1 = NULL; -- AMF_RESULT res = amf_context->QueryInterface( -- AMFContext1::IID(), (void **)&context1); -- if (res != AMF_OK) -- throw amf_error("CreateContext1 failed", res); -- res = context1->InitVulkan(nullptr); -- context1->Release(); -+ AMF_RESULT res = amf_context1->InitVulkan(nullptr); - if (res != AMF_OK) - throw amf_error("InitVulkan failed", res); - #endif -@@ -420,6 +760,361 @@ static void get_tex_from_handle(amf_texencode *enc, uint32_t handle, - *km_out = km.Detach(); - *tex_out = tex.Detach(); - } -+#else -+static uint32_t memoryTypeIndex(amf_texencode *enc, -+ VkMemoryPropertyFlags properties, -+ uint32_t typeBits) -+{ -+ VkPhysicalDeviceMemoryProperties prop; -+ vkGetPhysicalDeviceMemoryProperties(enc->vk->hPhysicalDevice, &prop); -+ for (uint32_t i = 0; i < prop.memoryTypeCount; i++) { -+ if ((prop.memoryTypes[i].propertyFlags & properties) == -+ properties && -+ typeBits & (1 << i)) { -+ return i; -+ } -+ } -+ return 0xFFFFFFFF; -+} -+ -+static void cmd_buf_begin(amf_texencode *enc) -+{ -+ VkCommandBufferBeginInfo commandBufferBegin = {}; -+ commandBufferBegin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; -+ VK_CHECK(vkBeginCommandBuffer(enc->cmdbuf, &commandBufferBegin)); -+} -+ -+static void cmd_buf_submit(amf_texencode *enc, VkSemaphore *semaphore = nullptr, -+ VkFence *fence = nullptr) -+{ -+ VK_CHECK(vkEndCommandBuffer(enc->cmdbuf)); -+ VkSubmitInfo submitInfo = {}; -+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; -+ submitInfo.commandBufferCount = 1; -+ submitInfo.pCommandBuffers = &enc->cmdbuf; -+ submitInfo.signalSemaphoreCount = semaphore ? 1 : 0; -+ submitInfo.pSignalSemaphores = semaphore; -+ if (fence) { -+ VK_CHECK(vkQueueSubmit(enc->queue, 1, &submitInfo, *fence)); -+ return; -+ } -+ VkFenceCreateInfo fenceInfo = {}; -+ fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; -+ VkFence f; -+ VK_CHECK(vkCreateFence(enc->vk->hDevice, &fenceInfo, nullptr, &f)); -+ VK_CHECK(vkQueueSubmit(enc->queue, 1, &submitInfo, f)); -+ VK_CHECK(vkWaitForFences(enc->vk->hDevice, 1, &f, VK_TRUE, UINT64_MAX)); -+ vkDestroyFence(enc->vk->hDevice, f, nullptr); -+} -+ -+static void add_output_tex(amf_texencode *enc, handle_tex &output_tex, -+ encoder_texture *from) -+{ -+ output_tex.surfaceVk = new AMFVulkanSurface; -+ output_tex.surfaceVk->cbSizeof = sizeof(AMFVulkanSurface); -+ output_tex.surfaceVk->pNext = nullptr; -+ -+ VkImageCreateInfo imageInfo = {}; -+ imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; -+ imageInfo.imageType = VK_IMAGE_TYPE_2D; -+ imageInfo.format = to_vk_format(enc->amf_format); -+ imageInfo.extent.width = from->info.width; -+ imageInfo.extent.height = from->info.height; -+ imageInfo.extent.depth = 1; -+ imageInfo.arrayLayers = 1; -+ imageInfo.mipLevels = 1; -+ imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; -+ imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; -+ imageInfo.tiling = VK_IMAGE_TILING_LINEAR; -+ imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | -+ VK_IMAGE_USAGE_TRANSFER_DST_BIT; -+ imageInfo.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; -+ imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; -+ VK_CHECK(vkCreateImage(enc->vk->hDevice, &imageInfo, nullptr, -+ &output_tex.surfaceVk->hImage)); -+ -+ VkMemoryRequirements memoryReqs; -+ vkGetImageMemoryRequirements(enc->vk->hDevice, -+ output_tex.surfaceVk->hImage, &memoryReqs); -+ VkMemoryAllocateInfo memoryAllocInfo = {}; -+ memoryAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; -+ memoryAllocInfo.allocationSize = memoryReqs.size; -+ memoryAllocInfo.memoryTypeIndex = -+ memoryTypeIndex(enc, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, -+ memoryReqs.memoryTypeBits); -+ VK_CHECK(vkAllocateMemory(enc->vk->hDevice, &memoryAllocInfo, nullptr, -+ &output_tex.surfaceVk->hMemory)); -+ VK_CHECK(vkBindImageMemory(enc->vk->hDevice, -+ output_tex.surfaceVk->hImage, -+ output_tex.surfaceVk->hMemory, 0)); -+ -+ cmd_buf_begin(enc); -+ VkImageMemoryBarrier imageBarrier = {}; -+ imageBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; -+ imageBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; -+ imageBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; -+ imageBarrier.image = output_tex.surfaceVk->hImage; -+ imageBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ imageBarrier.subresourceRange.layerCount = 1; -+ imageBarrier.subresourceRange.levelCount = 1; -+ imageBarrier.srcAccessMask = 0; -+ imageBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | -+ VK_ACCESS_MEMORY_WRITE_BIT; -+ vkCmdPipelineBarrier(enc->cmdbuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, -+ VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, -+ nullptr, 1, &imageBarrier); -+ cmd_buf_submit(enc); -+ -+ output_tex.surfaceVk->iSize = memoryAllocInfo.allocationSize; -+ output_tex.surfaceVk->eFormat = imageInfo.format; -+ output_tex.surfaceVk->iWidth = imageInfo.extent.width; -+ output_tex.surfaceVk->iHeight = imageInfo.extent.height; -+ output_tex.surfaceVk->eCurrentLayout = imageInfo.initialLayout; -+ output_tex.surfaceVk->eUsage = AMF_SURFACE_USAGE_DEFAULT; -+ output_tex.surfaceVk->eAccess = AMF_MEMORY_CPU_LOCAL; -+ output_tex.surfaceVk->Sync.cbSizeof = sizeof(AMFVulkanSync); -+ output_tex.surfaceVk->Sync.pNext = nullptr; -+ output_tex.surfaceVk->Sync.hSemaphore = nullptr; -+ output_tex.surfaceVk->Sync.bSubmitted = true; -+ output_tex.surfaceVk->Sync.hFence = nullptr; -+ -+ enc->input_textures.push_back(output_tex); -+} -+ -+static inline void create_gl_tex(amf_texencode *enc, gl_tex &output_tex, -+ encoder_texture *from) -+{ -+ if (output_tex.glsem) -+ return; -+ -+ cmd_buf_begin(enc); -+ for (int i = 0; i < 2; ++i) { -+ obs_enter_graphics(); -+ auto gs_format = gs_texture_get_color_format(from->tex[i]); -+ output_tex.planes[i].width = gs_texture_get_width(from->tex[i]); -+ output_tex.planes[i].height = -+ gs_texture_get_height(from->tex[i]); -+ obs_leave_graphics(); -+ -+ VkExternalMemoryImageCreateInfo extImageInfo = {}; -+ extImageInfo.sType = -+ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; -+ extImageInfo.handleTypes = -+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; -+ -+ VkImageCreateInfo imageInfo = {}; -+ imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; -+ imageInfo.pNext = &extImageInfo; -+ imageInfo.imageType = VK_IMAGE_TYPE_2D; -+ imageInfo.format = to_vk_format(gs_format); -+ imageInfo.extent.width = output_tex.planes[i].width; -+ imageInfo.extent.height = output_tex.planes[i].height; -+ imageInfo.extent.depth = 1; -+ imageInfo.arrayLayers = 1; -+ imageInfo.mipLevels = 1; -+ imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; -+ imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; -+ imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; -+ imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | -+ VK_IMAGE_USAGE_TRANSFER_SRC_BIT; -+ imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; -+ VK_CHECK(vkCreateImage(enc->vk->hDevice, &imageInfo, nullptr, -+ &output_tex.planes[i].image)); -+ -+ VkMemoryRequirements memoryReqs; -+ vkGetImageMemoryRequirements(enc->vk->hDevice, -+ output_tex.planes[i].image, -+ &memoryReqs); -+ -+ VkExportMemoryAllocateInfo expMemoryAllocInfo = {}; -+ expMemoryAllocInfo.sType = -+ VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO; -+ expMemoryAllocInfo.handleTypes = -+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; -+ -+ VkMemoryDedicatedAllocateInfo dedMemoryAllocInfo = {}; -+ dedMemoryAllocInfo.sType = -+ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO; -+ dedMemoryAllocInfo.image = output_tex.planes[i].image; -+ dedMemoryAllocInfo.pNext = &expMemoryAllocInfo; -+ -+ VkMemoryAllocateInfo memoryAllocInfo = {}; -+ memoryAllocInfo.pNext = &dedMemoryAllocInfo; -+ memoryAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; -+ memoryAllocInfo.allocationSize = memoryReqs.size; -+ memoryAllocInfo.memoryTypeIndex = memoryTypeIndex( -+ enc, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, -+ memoryReqs.memoryTypeBits); -+ VK_CHECK(vkAllocateMemory(enc->vk->hDevice, &memoryAllocInfo, -+ nullptr, -+ &output_tex.planes[i].memory)); -+ VK_CHECK(vkBindImageMemory(enc->vk->hDevice, -+ output_tex.planes[i].image, -+ output_tex.planes[i].memory, 0)); -+ -+ VkImageMemoryBarrier imageBarrier = {}; -+ imageBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; -+ imageBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; -+ imageBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; -+ imageBarrier.image = output_tex.planes[i].image; -+ imageBarrier.subresourceRange.aspectMask = -+ VK_IMAGE_ASPECT_COLOR_BIT; -+ imageBarrier.subresourceRange.layerCount = 1; -+ imageBarrier.subresourceRange.levelCount = 1; -+ imageBarrier.srcAccessMask = 0; -+ imageBarrier.dstAccessMask = 0; -+ vkCmdPipelineBarrier(enc->cmdbuf, -+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, -+ VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, -+ nullptr, 0, nullptr, 1, &imageBarrier); -+ -+ imageBarrier.oldLayout = imageBarrier.newLayout; -+ imageBarrier.srcQueueFamilyIndex = 0; -+ imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL; -+ vkCmdPipelineBarrier(enc->cmdbuf, -+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, -+ VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, -+ nullptr, 0, nullptr, 1, &imageBarrier); -+ -+ // Import memory -+ VkMemoryGetFdInfoKHR memFdInfo = {}; -+ memFdInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; -+ memFdInfo.memory = output_tex.planes[i].memory; -+ memFdInfo.handleType = -+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; -+ int fd = -1; -+ VK_CHECK(enc->vkGetMemoryFdKHR(enc->vk->hDevice, &memFdInfo, -+ &fd)); -+ -+ obs_enter_graphics(); -+ -+ enc->glCreateMemoryObjectsEXT(1, &output_tex.planes[i].glmem); -+ GLint dedicated = GL_TRUE; -+ enc->glMemoryObjectParameterivEXT( -+ output_tex.planes[i].glmem, -+ GL_DEDICATED_MEMORY_OBJECT_EXT, &dedicated); -+ enc->glImportMemoryFdEXT(output_tex.planes[i].glmem, -+ memoryAllocInfo.allocationSize, -+ GL_HANDLE_TYPE_OPAQUE_FD_EXT, fd); -+ -+ enc->glGenTextures(1, &output_tex.planes[i].gltex); -+ enc->glBindTexture(GL_TEXTURE_2D, output_tex.planes[i].gltex); -+ enc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_TILING_EXT, -+ GL_OPTIMAL_TILING_EXT); -+ enc->glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, -+ to_gl_format(gs_format), -+ imageInfo.extent.width, -+ imageInfo.extent.height, -+ output_tex.planes[i].glmem, 0); -+ -+ enc->glGenFramebuffers(1, &output_tex.planes[i].fbo); -+ enc->glBindFramebuffer(GL_FRAMEBUFFER, -+ output_tex.planes[i].fbo); -+ enc->glFramebufferTexture2D(GL_FRAMEBUFFER, -+ GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, -+ output_tex.planes[i].gltex, 0); -+ enc->glBindFramebuffer(GL_FRAMEBUFFER, 0); -+ -+ bool import_ok = -+ enc->glIsMemoryObjectEXT(output_tex.planes[i].glmem) && -+ enc->glGetError() == GL_NO_ERROR; -+ -+ obs_leave_graphics(); -+ -+ if (!import_ok) -+ throw "OpenGL texture import failed"; -+ } -+ -+ VkExportSemaphoreCreateInfo expSemInfo = {}; -+ expSemInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO; -+ expSemInfo.handleTypes = -+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; -+ -+ VkSemaphoreCreateInfo semInfo = {}; -+ semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; -+ semInfo.pNext = &expSemInfo; -+ VK_CHECK(vkCreateSemaphore(enc->vk->hDevice, &semInfo, nullptr, -+ &output_tex.sem)); -+ -+ VK_CHECK(vkCreateSemaphore(enc->vk->hDevice, &semInfo, nullptr, -+ &output_tex.copySem)); -+ -+ VkFenceCreateInfo fenceInfo = {}; -+ fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; -+ VK_CHECK(vkCreateFence(enc->vk->hDevice, &fenceInfo, nullptr, -+ &output_tex.copyFence)); -+ -+ cmd_buf_submit(enc, &output_tex.copySem, &output_tex.copyFence); -+ -+ // Import semaphores -+ VkSemaphoreGetFdInfoKHR semFdInfo = {}; -+ semFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR; -+ semFdInfo.semaphore = output_tex.sem; -+ semFdInfo.handleType = -+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; -+ int fd = -1; -+ VK_CHECK(enc->vkGetSemaphoreFdKHR(enc->vk->hDevice, &semFdInfo, &fd)); -+ -+ semFdInfo.semaphore = output_tex.copySem; -+ int fdCopy = -1; -+ VK_CHECK(enc->vkGetSemaphoreFdKHR(enc->vk->hDevice, &semFdInfo, -+ &fdCopy)); -+ -+ obs_enter_graphics(); -+ -+ enc->glGenSemaphoresEXT(1, &output_tex.glsem); -+ enc->glGenSemaphoresEXT(1, &output_tex.glCopySem); -+ enc->glImportSemaphoreFdEXT(output_tex.glsem, -+ GL_HANDLE_TYPE_OPAQUE_FD_EXT, fd); -+ enc->glImportSemaphoreFdEXT(output_tex.glCopySem, -+ GL_HANDLE_TYPE_OPAQUE_FD_EXT, fdCopy); -+ -+ bool import_ok = enc->glIsSemaphoreEXT(output_tex.glsem) && -+ enc->glIsSemaphoreEXT(output_tex.glCopySem) && -+ enc->glGetError() == GL_NO_ERROR; -+ -+ obs_leave_graphics(); -+ -+ if (!import_ok) -+ throw "OpenGL semaphore import failed"; -+} -+ -+static inline bool get_available_tex(amf_texencode *enc, handle_tex &output_tex) -+{ -+ std::scoped_lock lock(enc->textures_mutex); -+ if (enc->available_textures.size()) { -+ output_tex = enc->available_textures.back(); -+ enc->available_textures.pop_back(); -+ return true; -+ } -+ -+ return false; -+} -+ -+static inline void get_output_tex(amf_texencode *enc, handle_tex &output_tex, -+ encoder_texture *from) -+{ -+ if (!get_available_tex(enc, output_tex)) -+ add_output_tex(enc, output_tex, from); -+ -+ create_gl_tex(enc, enc->gltex, from); -+} -+ -+static inline GLuint get_read_fbo(amf_texencode *enc, gs_texture *tex) -+{ -+ auto it = enc->read_fbos.find(tex); -+ if (it != enc->read_fbos.end()) { -+ return it->second; -+ } -+ GLuint *tex_obj = static_cast(gs_texture_get_obj(tex)); -+ GLuint fbo; -+ enc->glGenFramebuffers(1, &fbo); -+ enc->glBindFramebuffer(GL_FRAMEBUFFER, fbo); -+ enc->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, -+ GL_TEXTURE_2D, *tex_obj, 0); -+ enc->read_fbos.insert({tex, fbo}); -+ return fbo; -+} - #endif - - static constexpr amf_int64 macroblock_size = 16; -@@ -756,6 +1451,197 @@ try { - } - #endif - -+static bool amf_encode_tex2(void *data, encoder_texture *texture, int64_t pts, -+ uint64_t lock_key, uint64_t *next_key, -+ encoder_packet *packet, bool *received_packet) -+try { -+ UNUSED_PARAMETER(lock_key); -+ UNUSED_PARAMETER(next_key); -+ -+ amf_texencode *enc = (amf_texencode *)data; -+ handle_tex output_tex; -+ AMFSurfacePtr amf_surf; -+ AMF_RESULT res; -+ -+ if (!texture) { -+ throw "Encode failed: bad texture handle"; -+ } -+ -+ /* ------------------------------------ */ -+ /* get an output tex */ -+ -+ get_output_tex(enc, output_tex, texture); -+ -+ /* ------------------------------------ */ -+ /* copy to output tex */ -+ -+ VK_CHECK(vkWaitForFences(enc->vk->hDevice, 1, &enc->gltex.copyFence, -+ VK_TRUE, UINT64_MAX)); -+ VK_CHECK(vkResetFences(enc->vk->hDevice, 1, &enc->gltex.copyFence)); -+ -+ obs_enter_graphics(); -+ -+ GLuint sem_tex[2]; -+ GLenum sem_layout[2]; -+ for (int i = 0; i < 2; ++i) { -+ sem_tex[i] = enc->gltex.planes[i].gltex; -+ sem_layout[i] = GL_LAYOUT_TRANSFER_SRC_EXT; -+ } -+ enc->glWaitSemaphoreEXT(enc->gltex.glCopySem, 0, 0, 2, sem_tex, -+ sem_layout); -+ for (int i = 0; i < 2; ++i) { -+ GLuint read_fbo = get_read_fbo(enc, texture->tex[i]); -+ enc->glBindFramebuffer(GL_READ_FRAMEBUFFER, read_fbo); -+ enc->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, -+ enc->gltex.planes[i].fbo); -+ enc->glBlitFramebuffer(0, 0, enc->gltex.planes[i].width, -+ enc->gltex.planes[i].height, 0, 0, -+ enc->gltex.planes[i].width, -+ enc->gltex.planes[i].height, -+ GL_COLOR_BUFFER_BIT, GL_NEAREST); -+ enc->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); -+ enc->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -+ } -+ enc->glSignalSemaphoreEXT(enc->gltex.glsem, 0, 0, 2, sem_tex, -+ sem_layout); -+ -+ obs_leave_graphics(); -+ -+ res = enc->amf_context1->CreateSurfaceFromVulkanNative( -+ output_tex.surfaceVk, &amf_surf, enc); -+ if (res != AMF_OK) -+ throw amf_error("CreateSurfaceFromVulkanNative failed", res); -+ -+ /* ------------------------------------ */ -+ /* copy to submit tex */ -+ -+ VkCommandBufferBeginInfo commandBufferBegin = {}; -+ commandBufferBegin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; -+ VK_CHECK(vkBeginCommandBuffer(enc->cmdbuf, &commandBufferBegin)); -+ -+ VkImageMemoryBarrier imageBarriers[2]; -+ imageBarriers[0] = {}; -+ imageBarriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; -+ imageBarriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; -+ imageBarriers[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; -+ imageBarriers[0].image = enc->gltex.planes[0].image; -+ imageBarriers[0].subresourceRange.aspectMask = -+ VK_IMAGE_ASPECT_COLOR_BIT; -+ imageBarriers[0].subresourceRange.layerCount = 1; -+ imageBarriers[0].subresourceRange.levelCount = 1; -+ imageBarriers[0].srcAccessMask = 0; -+ imageBarriers[0].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; -+ imageBarriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL; -+ imageBarriers[0].dstQueueFamilyIndex = 0; -+ imageBarriers[1] = {}; -+ imageBarriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; -+ imageBarriers[1].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; -+ imageBarriers[1].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; -+ imageBarriers[1].image = enc->gltex.planes[1].image; -+ imageBarriers[1].subresourceRange.aspectMask = -+ VK_IMAGE_ASPECT_COLOR_BIT; -+ imageBarriers[1].subresourceRange.layerCount = 1; -+ imageBarriers[1].subresourceRange.levelCount = 1; -+ imageBarriers[1].srcAccessMask = 0; -+ imageBarriers[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; -+ imageBarriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL; -+ imageBarriers[1].dstQueueFamilyIndex = 0; -+ vkCmdPipelineBarrier(enc->cmdbuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, -+ VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, -+ nullptr, 2, imageBarriers); -+ -+ VkImageCopy imageCopy = {}; -+ imageCopy.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ imageCopy.srcSubresource.mipLevel = 0; -+ imageCopy.srcSubresource.baseArrayLayer = 0; -+ imageCopy.srcSubresource.layerCount = 1; -+ imageCopy.srcOffset.x = 0; -+ imageCopy.srcOffset.y = 0; -+ imageCopy.srcOffset.z = 0; -+ imageCopy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT; -+ imageCopy.dstSubresource.mipLevel = 0; -+ imageCopy.dstSubresource.baseArrayLayer = 0; -+ imageCopy.dstSubresource.layerCount = 1; -+ imageCopy.dstOffset.x = 0; -+ imageCopy.dstOffset.y = 0; -+ imageCopy.dstOffset.z = 0; -+ imageCopy.extent.width = enc->gltex.planes[0].width; -+ imageCopy.extent.height = enc->gltex.planes[0].height; -+ imageCopy.extent.depth = 1; -+ vkCmdCopyImage(enc->cmdbuf, enc->gltex.planes[0].image, -+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, -+ output_tex.surfaceVk->hImage, VK_IMAGE_LAYOUT_GENERAL, 1, -+ &imageCopy); -+ -+ imageCopy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT; -+ imageCopy.extent.width = enc->gltex.planes[1].width; -+ imageCopy.extent.height = enc->gltex.planes[1].height; -+ vkCmdCopyImage(enc->cmdbuf, enc->gltex.planes[1].image, -+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, -+ output_tex.surfaceVk->hImage, VK_IMAGE_LAYOUT_GENERAL, 1, -+ &imageCopy); -+ -+ imageBarriers[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; -+ imageBarriers[0].dstAccessMask = 0; -+ imageBarriers[0].srcQueueFamilyIndex = 0; -+ imageBarriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL; -+ imageBarriers[1].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; -+ imageBarriers[1].dstAccessMask = 0; -+ imageBarriers[1].srcQueueFamilyIndex = 0; -+ imageBarriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL; -+ vkCmdPipelineBarrier(enc->cmdbuf, VK_PIPELINE_STAGE_TRANSFER_BIT, -+ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, -+ nullptr, 0, nullptr, 2, imageBarriers); -+ -+ VK_CHECK(vkEndCommandBuffer(enc->cmdbuf)); -+ -+ VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; -+ VkSubmitInfo submitInfo = {}; -+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; -+ submitInfo.commandBufferCount = 1; -+ submitInfo.pCommandBuffers = &enc->cmdbuf; -+ submitInfo.waitSemaphoreCount = 1; -+ submitInfo.pWaitSemaphores = &enc->gltex.sem; -+ submitInfo.pWaitDstStageMask = &waitStage; -+ submitInfo.signalSemaphoreCount = 1; -+ submitInfo.pSignalSemaphores = &enc->gltex.copySem; -+ VK_CHECK(vkQueueSubmit(enc->queue, 1, &submitInfo, -+ enc->gltex.copyFence)); -+ -+ output_tex.surfaceVk->Sync.hSemaphore = enc->gltex.copySem; -+ output_tex.surfaceVk->Sync.bSubmitted = true; -+ -+ int64_t last_ts = convert_to_amf_ts(enc, pts - 1); -+ int64_t cur_ts = convert_to_amf_ts(enc, pts); -+ -+ amf_surf->SetPts(cur_ts); -+ amf_surf->SetProperty(L"PTS", pts); -+ -+ { -+ std::scoped_lock lock(enc->textures_mutex); -+ enc->active_textures[amf_surf.GetPtr()] = output_tex; -+ } -+ -+ /* ------------------------------------ */ -+ /* do actual encode */ -+ -+ amf_encode_base(enc, amf_surf, packet, received_packet); -+ return true; -+ -+} catch (const char *err) { -+ amf_texencode *enc = (amf_texencode *)data; -+ error("%s: %s", __FUNCTION__, err); -+ *received_packet = false; -+ return false; -+ -+} catch (const amf_error &err) { -+ amf_texencode *enc = (amf_texencode *)data; -+ error("%s: %s: %ls", __FUNCTION__, err.str, -+ amf_trace->GetResultText(err.res)); -+ *received_packet = false; -+ return false; -+} -+ - static buf_t alloc_buf(amf_fallback *enc) - { - buf_t buf; -@@ -1016,6 +1902,8 @@ try { - if (res != AMF_OK) - throw amf_error("CreateContext failed", res); - -+ enc->amf_context1 = AMFContext1Ptr(enc->amf_context); -+ - enc->init(); - - const wchar_t *codec = nullptr; -@@ -1449,7 +2337,6 @@ static void amf_avc_create_internal(amf_base *enc, obs_data_t *settings) - - static void *amf_avc_create_texencode(obs_data_t *settings, - obs_encoder_t *encoder) --#ifdef _WIN32 - try { - check_texture_encode_capability(encoder, amf_codec_type::AVC); - -@@ -1457,8 +2344,10 @@ try { - enc->encoder = encoder; - enc->encoder_str = "texture-amf-h264"; - -+#ifdef _WIN32 - if (!amf_init_d3d11(enc.get())) - throw "Failed to create D3D11"; -+#endif - - amf_avc_create_internal(enc.get(), settings); - return enc.release(); -@@ -1472,12 +2361,6 @@ try { - blog(LOG_ERROR, "[texture-amf-h264] %s: %s", __FUNCTION__, err); - return obs_encoder_create_rerouted(encoder, "h264_fallback_amf"); - } --#else --{ -- UNUSED_PARAMETER(settings); -- return obs_encoder_create_rerouted(encoder, "h264_fallback_amf"); --} --#endif - - static void *amf_avc_create_fallback(obs_data_t *settings, - obs_encoder_t *encoder) -@@ -1533,6 +2416,7 @@ static void register_avc() - /* FIXME: Figure out why encoder does not survive reconfiguration - amf_encoder_info.update = amf_avc_update; */ - amf_encoder_info.encode_texture = amf_encode_tex; -+ amf_encoder_info.encode_texture2 = amf_encode_tex2; - amf_encoder_info.get_defaults = amf_defaults; - amf_encoder_info.get_properties = amf_avc_properties; - amf_encoder_info.get_extra_data = amf_extra_data; -@@ -1544,6 +2428,7 @@ static void register_avc() - amf_encoder_info.caps = OBS_ENCODER_CAP_INTERNAL | - OBS_ENCODER_CAP_DYN_BITRATE; - amf_encoder_info.encode_texture = nullptr; -+ amf_encoder_info.encode_texture2 = nullptr; - amf_encoder_info.create = amf_avc_create_fallback; - amf_encoder_info.encode = amf_encode_fallback; - amf_encoder_info.get_video_info = h264_video_info_fallback; -@@ -1801,7 +2686,6 @@ static void amf_hevc_create_internal(amf_base *enc, obs_data_t *settings) - - static void *amf_hevc_create_texencode(obs_data_t *settings, - obs_encoder_t *encoder) --#ifdef _WIN32 - try { - check_texture_encode_capability(encoder, amf_codec_type::HEVC); - -@@ -1809,8 +2693,10 @@ try { - enc->encoder = encoder; - enc->encoder_str = "texture-amf-h265"; - -+#ifdef _WIN32 - if (!amf_init_d3d11(enc.get())) - throw "Failed to create D3D11"; -+#endif - - amf_hevc_create_internal(enc.get(), settings); - return enc.release(); -@@ -1824,12 +2710,6 @@ try { - blog(LOG_ERROR, "[texture-amf-h265] %s: %s", __FUNCTION__, err); - return obs_encoder_create_rerouted(encoder, "h265_fallback_amf"); - } --#else --{ -- UNUSED_PARAMETER(settings); -- return obs_encoder_create_rerouted(encoder, "h265_fallback_amf"); --} --#endif - - static void *amf_hevc_create_fallback(obs_data_t *settings, - obs_encoder_t *encoder) -@@ -1881,6 +2761,7 @@ static void register_hevc() - /* FIXME: Figure out why encoder does not survive reconfiguration - amf_encoder_info.update = amf_hevc_update; */ - amf_encoder_info.encode_texture = amf_encode_tex; -+ amf_encoder_info.encode_texture2 = amf_encode_tex2; - amf_encoder_info.get_defaults = amf_defaults; - amf_encoder_info.get_properties = amf_hevc_properties; - amf_encoder_info.get_extra_data = amf_extra_data; -@@ -1892,6 +2773,7 @@ static void register_hevc() - amf_encoder_info.caps = OBS_ENCODER_CAP_INTERNAL | - OBS_ENCODER_CAP_DYN_BITRATE; - amf_encoder_info.encode_texture = nullptr; -+ amf_encoder_info.encode_texture2 = nullptr; - amf_encoder_info.create = amf_hevc_create_fallback; - amf_encoder_info.encode = amf_encode_fallback; - amf_encoder_info.get_video_info = h265_video_info_fallback; -@@ -2110,7 +2992,6 @@ static void amf_av1_create_internal(amf_base *enc, obs_data_t *settings) - - static void *amf_av1_create_texencode(obs_data_t *settings, - obs_encoder_t *encoder) --#ifdef _WIN32 - try { - check_texture_encode_capability(encoder, amf_codec_type::AV1); - -@@ -2118,8 +2999,10 @@ try { - enc->encoder = encoder; - enc->encoder_str = "texture-amf-av1"; - -+#ifdef _WIN32 - if (!amf_init_d3d11(enc.get())) - throw "Failed to create D3D11"; -+#endif - - amf_av1_create_internal(enc.get(), settings); - return enc.release(); -@@ -2133,12 +3016,6 @@ try { - blog(LOG_ERROR, "[texture-amf-av1] %s: %s", __FUNCTION__, err); - return obs_encoder_create_rerouted(encoder, "av1_fallback_amf"); - } --#else --{ -- UNUSED_PARAMETER(settings); -- return obs_encoder_create_rerouted(encoder, "av1_fallback_amf"); --} --#endif - - static void *amf_av1_create_fallback(obs_data_t *settings, - obs_encoder_t *encoder) -@@ -2200,6 +3077,7 @@ static void register_av1() - /* FIXME: Figure out why encoder does not survive reconfiguration - amf_encoder_info.update = amf_av1_update; */ - amf_encoder_info.encode_texture = amf_encode_tex; -+ amf_encoder_info.encode_texture2 = amf_encode_tex2; - amf_encoder_info.get_defaults = amf_av1_defaults; - amf_encoder_info.get_properties = amf_av1_properties; - amf_encoder_info.get_extra_data = amf_extra_data; -@@ -2211,6 +3089,7 @@ static void register_av1() - amf_encoder_info.caps = OBS_ENCODER_CAP_INTERNAL | - OBS_ENCODER_CAP_DYN_BITRATE; - amf_encoder_info.encode_texture = nullptr; -+ amf_encoder_info.encode_texture2 = nullptr; - amf_encoder_info.create = amf_av1_create_fallback; - amf_encoder_info.encode = amf_encode_fallback; - amf_encoder_info.get_video_info = av1_video_info_fallback; --- -2.40.0 - diff --git a/patches/0002-obs-ffmpeg-Add-initial-support-for-the-OpenH264-H.26.patch b/patches/0002-obs-ffmpeg-Add-initial-support-for-the-OpenH264-H.26.patch new file mode 100644 index 0000000..412e883 --- /dev/null +++ b/patches/0002-obs-ffmpeg-Add-initial-support-for-the-OpenH264-H.26.patch @@ -0,0 +1,346 @@ +From 4517d8d8bb4c43af1f5b757773a5f9550bd23d37 Mon Sep 17 00:00:00 2001 +From: Neal Gompa +Date: Sun, 26 Mar 2023 06:06:31 -0400 +Subject: [PATCH 2/3] obs-ffmpeg: Add initial support for the OpenH264 H.264 + software codec + +This allows users to leverage the OpenH264 codec from Cisco to encode +H.264 video content. It is significantly reduced in capability from +alternatives, but it does the job. + +This also provides a framework for adding support for other H.264 +software codecs provided through FFmpeg. +--- + plugins/obs-ffmpeg/CMakeLists.txt | 1 + + plugins/obs-ffmpeg/cmake/legacy.cmake | 1 + + plugins/obs-ffmpeg/data/locale/en-US.ini | 3 + + plugins/obs-ffmpeg/obs-ffmpeg-h264.c | 260 +++++++++++++++++++++++ + plugins/obs-ffmpeg/obs-ffmpeg.c | 2 + + 5 files changed, 267 insertions(+) + create mode 100644 plugins/obs-ffmpeg/obs-ffmpeg-h264.c + +diff --git a/plugins/obs-ffmpeg/CMakeLists.txt b/plugins/obs-ffmpeg/CMakeLists.txt +index 3eba00932..f97622c22 100644 +--- a/plugins/obs-ffmpeg/CMakeLists.txt ++++ b/plugins/obs-ffmpeg/CMakeLists.txt +@@ -34,6 +34,7 @@ target_sources( + $<$:obs-ffmpeg-logging.c> + obs-ffmpeg-audio-encoders.c + obs-ffmpeg-av1.c ++ obs-ffmpeg-h264.c + obs-ffmpeg-compat.h + obs-ffmpeg-formats.h + obs-ffmpeg-hls-mux.c +diff --git a/plugins/obs-ffmpeg/cmake/legacy.cmake b/plugins/obs-ffmpeg/cmake/legacy.cmake +index 5540676ea..62f2cc7a1 100644 +--- a/plugins/obs-ffmpeg/cmake/legacy.cmake ++++ b/plugins/obs-ffmpeg/cmake/legacy.cmake +@@ -40,6 +40,7 @@ target_sources( + obs-ffmpeg-video-encoders.c + obs-ffmpeg-audio-encoders.c + obs-ffmpeg-av1.c ++ obs-ffmpeg-h264.c + obs-ffmpeg-nvenc.c + obs-ffmpeg-output.c + obs-ffmpeg-mux.c +diff --git a/plugins/obs-ffmpeg/data/locale/en-US.ini b/plugins/obs-ffmpeg/data/locale/en-US.ini +index 55bbe919d..0363ed82b 100644 +--- a/plugins/obs-ffmpeg/data/locale/en-US.ini ++++ b/plugins/obs-ffmpeg/data/locale/en-US.ini +@@ -109,4 +109,7 @@ NVENC.CheckDrivers="Try installing the latest ++ Partly derived from obs-ffmpeg-av1.c by Hugh Bailey ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++******************************************************************************/ ++ ++#include "obs-ffmpeg-video-encoders.h" ++ ++#define do_log(level, format, ...) \ ++ blog(level, "[H.264 encoder: '%s'] " format, \ ++ obs_encoder_get_name(enc->ffve.encoder), ##__VA_ARGS__) ++ ++#define error(format, ...) do_log(LOG_ERROR, format, ##__VA_ARGS__) ++#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__) ++#define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__) ++#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__) ++ ++enum h264_encoder_type { ++ H264_ENCODER_TYPE_OH264, ++}; ++ ++struct h264_encoder { ++ struct ffmpeg_video_encoder ffve; ++ enum h264_encoder_type type; ++ ++ DARRAY(uint8_t) header; ++}; ++ ++static const char *oh264_getname(void *unused) ++{ ++ UNUSED_PARAMETER(unused); ++ return "CPU: OpenH264"; ++} ++ ++static void h264_video_info(void *data, struct video_scale_info *info) ++{ ++ UNUSED_PARAMETER(data); ++ ++ // OpenH264 only supports I420 ++ info->format = VIDEO_FORMAT_I420; ++} ++ ++static bool h264_update(struct h264_encoder *enc, obs_data_t *settings) ++{ ++ const char *profile = obs_data_get_string(settings, "profile"); ++ int bitrate = (int)obs_data_get_int(settings, "bitrate"); ++ int keyint_sec = 0; // This is not supported by OpenH264 ++ const char *rc_mode = "quality"; // We only want to use quality mode ++ int allow_skip_frames = 1; // This is required for quality mode ++ ++ video_t *video = obs_encoder_video(enc->ffve.encoder); ++ const struct video_output_info *voi = video_output_get_info(video); ++ struct video_scale_info info; ++ ++ info.format = voi->format; ++ info.colorspace = voi->colorspace; ++ info.range = voi->range; ++ ++ enc->ffve.context->thread_count = 0; ++ ++ h264_video_info(enc, &info); ++ ++ av_opt_set(enc->ffve.context->priv_data, "rc_mode", rc_mode, 0); ++ av_opt_set(enc->ffve.context->priv_data, "profile", profile, 0); ++ av_opt_set_int(enc->ffve.context->priv_data, "allow_skip_frames", ++ allow_skip_frames, 0); ++ ++ const char *ffmpeg_opts = obs_data_get_string(settings, "ffmpeg_opts"); ++ ffmpeg_video_encoder_update(&enc->ffve, bitrate, keyint_sec, voi, &info, ++ ffmpeg_opts); ++ info("settings:\n" ++ "\tencoder: %s\n" ++ "\trc_mode: %s\n" ++ "\tbitrate: %d\n" ++ "\tprofile: %s\n" ++ "\twidth: %d\n" ++ "\theight: %d\n" ++ "\tffmpeg opts: %s\n", ++ enc->ffve.enc_name, rc_mode, bitrate, profile, ++ enc->ffve.context->width, enc->ffve.height, ffmpeg_opts); ++ ++ enc->ffve.context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; ++ return ffmpeg_video_encoder_init_codec(&enc->ffve); ++} ++ ++static void h264_destroy(void *data) ++{ ++ struct h264_encoder *enc = data; ++ ++ ffmpeg_video_encoder_free(&enc->ffve); ++ da_free(enc->header); ++ bfree(enc); ++} ++ ++static void on_first_packet(void *data, AVPacket *pkt, struct darray *da) ++{ ++ struct h264_encoder *enc = data; ++ ++ da_copy_array(enc->header, enc->ffve.context->extradata, ++ enc->ffve.context->extradata_size); ++ ++ darray_copy_array(1, da, pkt->data, pkt->size); ++} ++ ++static void *h264_create_internal(obs_data_t *settings, obs_encoder_t *encoder, ++ const char *enc_lib, const char *enc_name) ++{ ++ video_t *video = obs_encoder_video(encoder); ++ const struct video_output_info *voi = video_output_get_info(video); ++ ++ switch (voi->format) { ++ // planar 4:2:0 formats ++ case VIDEO_FORMAT_I420: // three-plane ++ case VIDEO_FORMAT_NV12: // two-plane, luma and packed chroma ++ // packed 4:2:2 formats ++ case VIDEO_FORMAT_YVYU: ++ case VIDEO_FORMAT_YUY2: // YUYV ++ case VIDEO_FORMAT_UYVY: ++ // packed uncompressed formats ++ case VIDEO_FORMAT_RGBA: ++ case VIDEO_FORMAT_BGRA: ++ case VIDEO_FORMAT_BGRX: ++ case VIDEO_FORMAT_BGR3: ++ case VIDEO_FORMAT_Y800: // grayscale ++ // planar 4:4:4 ++ case VIDEO_FORMAT_I444: ++ // planar 4:2:2 ++ case VIDEO_FORMAT_I422: ++ // planar 4:2:0 with alpha ++ case VIDEO_FORMAT_I40A: ++ // planar 4:2:2 with alpha ++ case VIDEO_FORMAT_I42A: ++ // planar 4:4:4 with alpha ++ case VIDEO_FORMAT_YUVA: ++ // packed 4:4:4 with alpha ++ case VIDEO_FORMAT_AYUV: ++ break; ++ default:; // Make the compiler do the right thing ++ const char *const text = ++ obs_module_text("H264.UnsupportedVideoFormat"); ++ obs_encoder_set_last_error(encoder, text); ++ blog(LOG_ERROR, "[H.264 encoder] %s", text); ++ return NULL; ++ } ++ ++ switch (voi->colorspace) { ++ case VIDEO_CS_DEFAULT: ++ case VIDEO_CS_709: ++ break; ++ default:; // Make the compiler do the right thing ++ const char *const text = ++ obs_module_text("H264.UnsupportedColorSpace"); ++ obs_encoder_set_last_error(encoder, text); ++ blog(LOG_ERROR, "[H.264 encoder] %s", text); ++ return NULL; ++ } ++ ++ struct h264_encoder *enc = bzalloc(sizeof(*enc)); ++ ++ if (strcmp(enc_lib, "libopenh264") == 0) ++ enc->type = H264_ENCODER_TYPE_OH264; ++ ++ if (!ffmpeg_video_encoder_init(&enc->ffve, enc, encoder, enc_lib, NULL, ++ enc_name, NULL, on_first_packet)) ++ goto fail; ++ if (!h264_update(enc, settings)) ++ goto fail; ++ ++ return enc; ++ ++fail: ++ h264_destroy(enc); ++ return NULL; ++} ++ ++static void *oh264_create(obs_data_t *settings, obs_encoder_t *encoder) ++{ ++ return h264_create_internal(settings, encoder, "libopenh264", ++ "CPU: OpenH264"); ++} ++ ++static bool h264_encode(void *data, struct encoder_frame *frame, ++ struct encoder_packet *packet, bool *received_packet) ++{ ++ struct h264_encoder *enc = data; ++ return ffmpeg_video_encode(&enc->ffve, frame, packet, received_packet); ++} ++ ++void h264_defaults(obs_data_t *settings) ++{ ++ obs_data_set_default_int(settings, "bitrate", 2500); ++ obs_data_set_default_string(settings, "profile", "main"); ++} ++ ++obs_properties_t *h264_properties(enum h264_encoder_type type) ++{ ++ UNUSED_PARAMETER(type); // Only one encoder right now... ++ obs_properties_t *props = obs_properties_create(); ++ obs_property_t *p; ++ ++ p = obs_properties_add_list(props, "profile", ++ obs_module_text("Profile"), ++ OBS_COMBO_TYPE_LIST, ++ OBS_COMBO_FORMAT_STRING); ++ obs_property_list_add_string(p, "constrained_baseline", ++ "constrained_baseline"); ++ obs_property_list_add_string(p, "main", "main"); ++ obs_property_list_add_string(p, "high", "high"); ++ ++ p = obs_properties_add_int(props, "bitrate", obs_module_text("Bitrate"), ++ 50, 300000, 50); ++ obs_property_int_set_suffix(p, " Kbps"); ++ ++ obs_properties_add_text(props, "ffmpeg_opts", ++ obs_module_text("FFmpegOpts"), ++ OBS_TEXT_DEFAULT); ++ ++ return props; ++} ++ ++obs_properties_t *oh264_properties(void *unused) ++{ ++ UNUSED_PARAMETER(unused); ++ return h264_properties(H264_ENCODER_TYPE_OH264); ++} ++ ++static bool h264_extra_data(void *data, uint8_t **extra_data, size_t *size) ++{ ++ struct h264_encoder *enc = data; ++ ++ *extra_data = enc->header.array; ++ *size = enc->header.num; ++ return true; ++} ++ ++struct obs_encoder_info oh264_encoder_info = { ++ .id = "ffmpeg_openh264", ++ .type = OBS_ENCODER_VIDEO, ++ .codec = "h264", ++ .get_name = oh264_getname, ++ .create = oh264_create, ++ .destroy = h264_destroy, ++ .encode = h264_encode, ++ .get_defaults = h264_defaults, ++ .get_properties = oh264_properties, ++ .get_extra_data = h264_extra_data, ++ .get_video_info = h264_video_info, ++}; +diff --git a/plugins/obs-ffmpeg/obs-ffmpeg.c b/plugins/obs-ffmpeg/obs-ffmpeg.c +index da0b2c2b4..a01a729c8 100644 +--- a/plugins/obs-ffmpeg/obs-ffmpeg.c ++++ b/plugins/obs-ffmpeg/obs-ffmpeg.c +@@ -39,6 +39,7 @@ extern struct obs_encoder_info pcm24_encoder_info; + extern struct obs_encoder_info pcm32_encoder_info; + extern struct obs_encoder_info alac_encoder_info; + extern struct obs_encoder_info flac_encoder_info; ++extern struct obs_encoder_info oh264_encoder_info; + extern struct obs_encoder_info h264_nvenc_encoder_info; + #ifdef ENABLE_HEVC + extern struct obs_encoder_info hevc_nvenc_encoder_info; +@@ -387,6 +388,7 @@ bool obs_module_load(void) + obs_register_output(&ffmpeg_hls_muxer); + obs_register_output(&replay_buffer); + obs_register_encoder(&aac_encoder_info); ++ register_encoder_if_available(&oh264_encoder_info, "libopenh264"); + register_encoder_if_available(&svt_av1_encoder_info, "libsvtav1"); + register_encoder_if_available(&aom_av1_encoder_info, "libaom-av1"); + obs_register_encoder(&opus_encoder_info); +-- +2.39.2 + diff --git a/patches/0003-8788.patch b/patches/0003-8788.patch deleted file mode 100644 index 270eab8..0000000 --- a/patches/0003-8788.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 8e5fec4c7765b1c43d40f652b46d034340877a31 Mon Sep 17 00:00:00 2001 -From: Ryan Foster -Date: Fri, 14 Apr 2023 12:05:59 -0400 -Subject: [PATCH 1/2] obs-ffmpeg: Use 2x2 tiles in NVENC AV1 for 4K+ - -When resolution is 4K or higher, use 2x2 uniform tiles for NVENC AV1. ---- - plugins/obs-ffmpeg/jim-nvenc.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/plugins/obs-ffmpeg/jim-nvenc.c b/plugins/obs-ffmpeg/jim-nvenc.c -index 10a7dd18549b9..c1e8bee154770 100644 ---- a/plugins/obs-ffmpeg/jim-nvenc.c -+++ b/plugins/obs-ffmpeg/jim-nvenc.c -@@ -922,6 +922,17 @@ static bool init_encoder_av1(struct nvenc_data *enc, obs_data_t *settings, - if (config->rcParams.rateControlMode == NV_ENC_PARAMS_RC_CBR) - av1_config->enableBitstreamPadding = 1; - -+#define FOUR_K_CX 3840 -+#define FOUR_K_CY 2160 -+#define PIXELCOUNT_4K (FOUR_K_CX * FOUR_K_CY) -+ -+ /* If 4K+, set tiles to 2x2 uniform tiles. */ -+ if ((voi->width * voi->height) >= PIXELCOUNT_4K) { -+ av1_config->enableCustomTileConfig = 0; -+ av1_config->numTileColumns = 2; -+ av1_config->numTileRows = 2; -+ } -+ - switch (voi->colorspace) { - case VIDEO_CS_601: - av1_config->colorPrimaries = 6; - -From 872f0353e68191d69bcc4678a2d195144fdcabeb Mon Sep 17 00:00:00 2001 -From: Ryan Foster -Date: Fri, 14 Apr 2023 12:07:50 -0400 -Subject: [PATCH 2/2] obs-ffmpeg: Use 2 tiles per frame in AMF AV1 for 4K+ - -When resolution is 4K or higher, use 2 tiles per frame in AMF AV1. ---- - plugins/obs-ffmpeg/texture-amf.cpp | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/plugins/obs-ffmpeg/texture-amf.cpp b/plugins/obs-ffmpeg/texture-amf.cpp -index 88914a027f699..5979b903385ad 100644 ---- a/plugins/obs-ffmpeg/texture-amf.cpp -+++ b/plugins/obs-ffmpeg/texture-amf.cpp -@@ -2018,6 +2018,15 @@ static void amf_av1_create_internal(amf_base *enc, obs_data_t *settings) - const bool is10bit = enc->amf_format == AMF_SURFACE_P010; - const char *preset = obs_data_get_string(settings, "preset"); - -+ constexpr uint32_t four_k_cx = 3840; -+ constexpr uint32_t four_k_cy = 2160; -+ constexpr uint32_t pixelcount_4k = four_k_cx * four_k_cy; -+ -+ /* If 4K+, set tiles per frame to 2. */ -+ if ((enc->cx * enc->cy) >= pixelcount_4k) { -+ set_av1_property(enc, TILES_PER_FRAME, 2); -+ } -+ - set_av1_property(enc, FRAMESIZE, AMFConstructSize(enc->cx, enc->cy)); - set_av1_property(enc, USAGE, AMF_VIDEO_ENCODER_USAGE_TRANSCODING); - set_av1_property(enc, ALIGNMENT_MODE, diff --git a/patches/0003-UI-Add-support-for-OpenH264-as-the-worst-case-fallba.patch b/patches/0003-UI-Add-support-for-OpenH264-as-the-worst-case-fallba.patch new file mode 100644 index 0000000..a2bae3a --- /dev/null +++ b/patches/0003-UI-Add-support-for-OpenH264-as-the-worst-case-fallba.patch @@ -0,0 +1,545 @@ +From 30f84455969071ff9aa826a44438a0402dd15123 Mon Sep 17 00:00:00 2001 +From: Neal Gompa +Date: Tue, 28 Mar 2023 05:08:49 -0400 +Subject: [PATCH 3/3] UI: Add support for OpenH264 as the worst-case fallback + +OpenH264 exists as the codec of last resort, so it is implemented +such that it is only used as the software codec if x264 is not +available. +--- + UI/data/locale/en-US.ini | 1 + + UI/window-basic-auto-config-test.cpp | 50 +++++++++++++++++++--------- + UI/window-basic-auto-config.cpp | 15 ++++++++- + UI/window-basic-auto-config.hpp | 3 ++ + UI/window-basic-main-outputs.cpp | 6 ++-- + UI/window-basic-main-profiles.cpp | 34 +++++++++++-------- + UI/window-basic-main.cpp | 20 +++++++---- + UI/window-basic-main.hpp | 3 +- + UI/window-basic-settings-stream.cpp | 16 ++++++--- + UI/window-basic-settings.cpp | 23 ++++++++++--- + 10 files changed, 123 insertions(+), 48 deletions(-) + +diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini +index e44d99660..a5ba5d661 100644 +--- a/UI/data/locale/en-US.ini ++++ b/UI/data/locale/en-US.ini +@@ -980,6 +980,7 @@ Basic.Settings.Output.Simple.Warn.Encoder="Warning: Recording with a software en + Basic.Settings.Output.Simple.Warn.Lossless="Warning: Lossless quality generates tremendously large file sizes! Lossless quality can use upward of 7 gigabytes of disk space per minute at high resolutions and framerates. Lossless is not recommended for long recordings unless you have a very large amount of disk space available." + Basic.Settings.Output.Simple.Warn.Lossless.Msg="Are you sure you want to use lossless quality?" + Basic.Settings.Output.Simple.Warn.Lossless.Title="Lossless quality warning!" ++Basic.Settings.Output.Simple.Encoder.Software.OpenH264.H264="Software (OpenH264)" + Basic.Settings.Output.Simple.Encoder.Software.X264.H264="Software (x264)" + Basic.Settings.Output.Simple.Encoder.Hardware.QSV.H264="Hardware (QSV, H.264)" + Basic.Settings.Output.Simple.Encoder.Hardware.QSV.AV1="Hardware (QSV, AV1)" +diff --git a/UI/window-basic-auto-config-test.cpp b/UI/window-basic-auto-config-test.cpp +index 09979c031..c791c8b8b 100644 +--- a/UI/window-basic-auto-config-test.cpp ++++ b/UI/window-basic-auto-config-test.cpp +@@ -199,7 +199,8 @@ void AutoConfigTestPage::TestBandwidthThread() + : "rtmp_common"; + + OBSEncoderAutoRelease vencoder = obs_video_encoder_create( +- "obs_x264", "test_x264", nullptr, nullptr); ++ (wiz->x264Available ? "obs_x264" : "ffmpeg_openh264"), ++ "test_h264", nullptr, nullptr); + OBSEncoderAutoRelease aencoder = obs_audio_encoder_create( + "ffmpeg_aac", "test_aac", nullptr, 0, nullptr); + OBSServiceAutoRelease service = obs_service_create( +@@ -238,10 +239,11 @@ void AutoConfigTestPage::TestBandwidthThread() + obs_data_set_string(service_settings, "key", key.c_str()); + + obs_data_set_int(vencoder_settings, "bitrate", wiz->startingBitrate); +- obs_data_set_string(vencoder_settings, "rate_control", "CBR"); +- obs_data_set_string(vencoder_settings, "preset", "veryfast"); +- obs_data_set_int(vencoder_settings, "keyint_sec", 2); +- ++ if (wiz->x264Available) { ++ obs_data_set_string(vencoder_settings, "rate_control", "CBR"); ++ obs_data_set_string(vencoder_settings, "preset", "veryfast"); ++ obs_data_set_int(vencoder_settings, "keyint_sec", 2); ++ } + obs_data_set_int(aencoder_settings, "bitrate", 32); + + OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); +@@ -567,7 +569,8 @@ bool AutoConfigTestPage::TestSoftwareEncoding() + /* create obs objects */ + + OBSEncoderAutoRelease vencoder = obs_video_encoder_create( +- "obs_x264", "test_x264", nullptr, nullptr); ++ (wiz->x264Available ? "obs_x264" : "ffmpeg_openh264"), ++ "test_h264", nullptr, nullptr); + OBSEncoderAutoRelease aencoder = obs_audio_encoder_create( + "ffmpeg_aac", "test_aac", nullptr, 0, nullptr); + OBSOutputAutoRelease output = +@@ -581,17 +584,25 @@ bool AutoConfigTestPage::TestSoftwareEncoding() + obs_data_set_int(aencoder_settings, "bitrate", 32); + + if (wiz->type != AutoConfig::Type::Recording) { +- obs_data_set_int(vencoder_settings, "keyint_sec", 2); ++ if (wiz->x264Available) { ++ obs_data_set_int(vencoder_settings, "keyint_sec", 2); ++ obs_data_set_string(vencoder_settings, "rate_control", ++ "CBR"); ++ obs_data_set_string(vencoder_settings, "preset", ++ "veryfast"); ++ } + obs_data_set_int(vencoder_settings, "bitrate", + wiz->idealBitrate); +- obs_data_set_string(vencoder_settings, "rate_control", "CBR"); + obs_data_set_string(vencoder_settings, "profile", "main"); +- obs_data_set_string(vencoder_settings, "preset", "veryfast"); + } else { +- obs_data_set_int(vencoder_settings, "crf", 20); +- obs_data_set_string(vencoder_settings, "rate_control", "CRF"); ++ if (wiz->x264Available) { ++ obs_data_set_int(vencoder_settings, "crf", 20); ++ obs_data_set_string(vencoder_settings, "rate_control", ++ "CRF"); ++ obs_data_set_string(vencoder_settings, "preset", ++ "veryfast"); ++ } + obs_data_set_string(vencoder_settings, "profile", "high"); +- obs_data_set_string(vencoder_settings, "preset", "veryfast"); + } + + /* -----------------------------------*/ +@@ -944,7 +955,10 @@ void AutoConfigTestPage::TestStreamEncoderThread() + else + wiz->streamingEncoder = AutoConfig::Encoder::AMD; + } else { +- wiz->streamingEncoder = AutoConfig::Encoder::x264; ++ if (wiz->x264Available) ++ wiz->streamingEncoder = AutoConfig::Encoder::x264; ++ else ++ wiz->streamingEncoder = AutoConfig::Encoder::OpenH264; + } + + if (preferHardware && !softwareTested && wiz->hardwareEncodingAvailable) +@@ -979,7 +993,10 @@ void AutoConfigTestPage::TestRecordingEncoderThread() + else + wiz->recordingEncoder = AutoConfig::Encoder::AMD; + } else { +- wiz->recordingEncoder = AutoConfig::Encoder::x264; ++ if (wiz->x264Available) ++ wiz->streamingEncoder = AutoConfig::Encoder::x264; ++ else ++ wiz->streamingEncoder = AutoConfig::Encoder::OpenH264; + } + + if (wiz->recordingEncoder != AutoConfig::Encoder::NVENC) { +@@ -993,6 +1010,7 @@ void AutoConfigTestPage::TestRecordingEncoderThread() + } + + #define ENCODER_TEXT(x) "Basic.Settings.Output.Simple.Encoder." x ++#define ENCODER_OPENH264 ENCODER_TEXT("Software.OpenH264.H264") + #define ENCODER_X264 ENCODER_TEXT("Software.X264.H264") + #define ENCODER_NVENC ENCODER_TEXT("Hardware.NVENC.H264") + #define ENCODER_QSV ENCODER_TEXT("Hardware.QSV.H264") +@@ -1032,6 +1050,8 @@ void AutoConfigTestPage::FinalizeResults() + + auto encName = [](AutoConfig::Encoder enc) -> QString { + switch (enc) { ++ case AutoConfig::Encoder::OpenH264: ++ return QTStr(ENCODER_OPENH264); + case AutoConfig::Encoder::x264: + return QTStr(ENCODER_X264); + case AutoConfig::Encoder::NVENC: +@@ -1046,7 +1066,7 @@ void AutoConfigTestPage::FinalizeResults() + return QTStr(QUALITY_SAME); + } + +- return QTStr(ENCODER_X264); ++ return QTStr(ENCODER_OPENH264); + }; + + auto newLabel = [this](const char *str) -> QLabel * { +diff --git a/UI/window-basic-auto-config.cpp b/UI/window-basic-auto-config.cpp +index 3e9c36685..eace18067 100644 +--- a/UI/window-basic-auto-config.cpp ++++ b/UI/window-basic-auto-config.cpp +@@ -961,6 +961,7 @@ AutoConfig::AutoConfig(QWidget *parent) : QWizard(parent) + streamPage->ui->bitrate->setValue(bitrate); + streamPage->ServiceChanged(); + ++ TestSoftwareEncoding(); + TestHardwareEncoding(); + if (!hardwareEncodingAvailable) { + delete streamPage->ui->preferHardware; +@@ -989,6 +990,16 @@ AutoConfig::~AutoConfig() + EnableThreadedMessageBoxes(false); + } + ++void AutoConfig::TestSoftwareEncoding() ++{ ++ size_t idx = 0; ++ const char *id; ++ while (obs_enum_encoder_types(idx++, &id)) { ++ if (strcmp(id, "obs_x264") == 0) ++ x264Available = true; ++ } ++} ++ + void AutoConfig::TestHardwareEncoding() + { + size_t idx = 0; +@@ -1061,8 +1072,10 @@ inline const char *AutoConfig::GetEncoderId(Encoder enc) + return SIMPLE_ENCODER_AMD; + case Encoder::Apple: + return SIMPLE_ENCODER_APPLE_H264; +- default: ++ case Encoder::x264: + return SIMPLE_ENCODER_X264; ++ default: ++ return SIMPLE_ENCODER_OPENH264; + } + }; + +diff --git a/UI/window-basic-auto-config.hpp b/UI/window-basic-auto-config.hpp +index eb50701ff..e581791dd 100644 +--- a/UI/window-basic-auto-config.hpp ++++ b/UI/window-basic-auto-config.hpp +@@ -43,6 +43,7 @@ class AutoConfig : public QWizard { + }; + + enum class Encoder { ++ OpenH264, + x264, + NVENC, + QSV, +@@ -91,6 +92,7 @@ class AutoConfig : public QWizard { + bool qsvAvailable = false; + bool vceAvailable = false; + bool appleAvailable = false; ++ bool x264Available = false; + + int startingBitrate = 2500; + bool customServer = false; +@@ -106,6 +108,7 @@ class AutoConfig : public QWizard { + int specificFPSNum = 0; + int specificFPSDen = 0; + ++ void TestSoftwareEncoding(); + void TestHardwareEncoding(); + bool CanTestServer(const char *server); + +diff --git a/UI/window-basic-main-outputs.cpp b/UI/window-basic-main-outputs.cpp +index 737ab966d..a4df630c4 100644 +--- a/UI/window-basic-main-outputs.cpp ++++ b/UI/window-basic-main-outputs.cpp +@@ -515,7 +515,9 @@ void SimpleOutput::LoadStreamingPreset_Lossy(const char *encoderId) + /* mistakes have been made to lead us to this. */ + const char *get_simple_output_encoder(const char *encoder) + { +- if (strcmp(encoder, SIMPLE_ENCODER_X264) == 0) { ++ if (strcmp(encoder, SIMPLE_ENCODER_OPENH264) == 0) { ++ return "ffmpeg_openh264"; ++ } else if (strcmp(encoder, SIMPLE_ENCODER_X264) == 0) { + return "obs_x264"; + } else if (strcmp(encoder, SIMPLE_ENCODER_X264_LOWCPU) == 0) { + return "obs_x264"; +@@ -549,7 +551,7 @@ const char *get_simple_output_encoder(const char *encoder) + #endif + } + +- return "obs_x264"; ++ return "ffmpeg_openh264"; + } + + void SimpleOutput::LoadRecordingPreset() +diff --git a/UI/window-basic-main-profiles.cpp b/UI/window-basic-main-profiles.cpp +index 4941359ea..1f3ffdc1d 100644 +--- a/UI/window-basic-main-profiles.cpp ++++ b/UI/window-basic-main-profiles.cpp +@@ -794,7 +794,7 @@ void OBSBasic::ChangeProfile() + + Auth::Load(); + +- CheckForSimpleModeX264Fallback(); ++ CheckForSimpleModeH264Fallback(); + + blog(LOG_INFO, "Switched to profile '%s' (%s)", newName, newDir); + blog(LOG_INFO, "------------------------------------------------"); +@@ -815,12 +815,13 @@ void OBSBasic::ChangeProfile() + } + } + +-void OBSBasic::CheckForSimpleModeX264Fallback() ++void OBSBasic::CheckForSimpleModeH264Fallback() + { + const char *curStreamEncoder = + config_get_string(basicConfig, "SimpleOutput", "StreamEncoder"); + const char *curRecEncoder = + config_get_string(basicConfig, "SimpleOutput", "RecEncoder"); ++ bool x264_supported = false; + bool qsv_supported = false; + bool qsv_av1_supported = false; + bool amd_supported = false; +@@ -849,7 +850,9 @@ void OBSBasic::CheckForSimpleModeX264Fallback() + const char *id; + + while (obs_enum_encoder_types(idx++, &id)) { +- if (strcmp(id, "h264_texture_amf") == 0) ++ if (strcmp(id, "obs_x264") == 0) ++ x264_supported = true; ++ else if (strcmp(id, "h264_texture_amf") == 0) + amd_supported = true; + else if (strcmp(id, "obs_qsv11") == 0) + qsv_supported = true; +@@ -865,68 +868,73 @@ void OBSBasic::CheckForSimpleModeX264Fallback() + #endif + } + ++ // Check to see whether x264 is available ++ const char *fallback_encoder_name = (x264_supported ++ ? SIMPLE_ENCODER_X264 ++ : SIMPLE_ENCODER_OPENH264); ++ + auto CheckEncoder = [&](const char *&name) { + if (strcmp(name, SIMPLE_ENCODER_QSV) == 0) { + if (!qsv_supported) { + changed = true; +- name = SIMPLE_ENCODER_X264; ++ name = fallback_encoder_name; + return false; + } + } else if (strcmp(name, SIMPLE_ENCODER_QSV_AV1) == 0) { + if (!qsv_av1_supported) { + changed = true; +- name = SIMPLE_ENCODER_X264; ++ name = fallback_encoder_name; + return false; + } + } else if (strcmp(name, SIMPLE_ENCODER_NVENC) == 0) { + if (!nve_supported) { + changed = true; +- name = SIMPLE_ENCODER_X264; ++ name = fallback_encoder_name; + return false; + } + } else if (strcmp(name, SIMPLE_ENCODER_NVENC_AV1) == 0) { + if (!nve_supported) { + changed = true; +- name = SIMPLE_ENCODER_X264; ++ name = fallback_encoder_name; + return false; + } + #ifdef ENABLE_HEVC + } else if (strcmp(name, SIMPLE_ENCODER_AMD_HEVC) == 0) { + if (!amd_hevc_supported) { + changed = true; +- name = SIMPLE_ENCODER_X264; ++ name = fallback_encoder_name; + return false; + } + } else if (strcmp(name, SIMPLE_ENCODER_NVENC_HEVC) == 0) { + if (!nve_hevc_supported) { + changed = true; +- name = SIMPLE_ENCODER_X264; ++ name = fallback_encoder_name; + return false; + } + #endif + } else if (strcmp(name, SIMPLE_ENCODER_AMD) == 0) { + if (!amd_supported) { + changed = true; +- name = SIMPLE_ENCODER_X264; ++ name = fallback_encoder_name; + return false; + } + } else if (strcmp(name, SIMPLE_ENCODER_AMD_AV1) == 0) { + if (!amd_av1_supported) { + changed = true; +- name = SIMPLE_ENCODER_X264; ++ name = fallback_encoder_name; + return false; + } + } else if (strcmp(name, SIMPLE_ENCODER_APPLE_H264) == 0) { + if (!apple_supported) { + changed = true; +- name = SIMPLE_ENCODER_X264; ++ name = fallback_encoder_name; + return false; + } + #ifdef ENABLE_HEVC + } else if (strcmp(name, SIMPLE_ENCODER_APPLE_HEVC) == 0) { + if (!apple_hevc_supported) { + changed = true; +- name = SIMPLE_ENCODER_X264; ++ name = fallback_encoder_name; + return false; + } + #endif +diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp +index 6d9375eb4..c6aae8c7b 100644 +--- a/UI/window-basic-main.cpp ++++ b/UI/window-basic-main.cpp +@@ -1379,6 +1379,8 @@ extern void CheckExistingCookieId(); + #define DEFAULT_CONTAINER "fragmented_mp4" + #endif + ++extern bool EncoderAvailable(const char *encoder); ++ + bool OBSBasic::InitBasicConfigDefaults() + { + QList screens = QGuiApplication::screens(); +@@ -1549,7 +1551,10 @@ bool OBSBasic::InitBasicConfigDefaults() + config_set_default_bool(basicConfig, "AdvOut", "UseRescale", false); + config_set_default_uint(basicConfig, "AdvOut", "TrackIndex", 1); + config_set_default_uint(basicConfig, "AdvOut", "VodTrackIndex", 2); +- config_set_default_string(basicConfig, "AdvOut", "Encoder", "obs_x264"); ++ ++ bool useX264 = EncoderAvailable("obs_x264"); ++ config_set_default_string(basicConfig, "AdvOut", "Encoder", ++ (useX264 ? "obs_x264" : "ffmpeg_openh264")); + + config_set_default_string(basicConfig, "AdvOut", "RecType", "Standard"); + +@@ -1672,7 +1677,6 @@ bool OBSBasic::InitBasicConfigDefaults() + return true; + } + +-extern bool EncoderAvailable(const char *encoder); + extern bool update_nvenc_presets(ConfigFile &config); + + void OBSBasic::InitBasicConfigDefaults2() +@@ -1681,12 +1685,14 @@ void OBSBasic::InitBasicConfigDefaults2() + "Pre23Defaults"); + bool useNV = EncoderAvailable("ffmpeg_nvenc") && !oldEncDefaults; + ++ bool useX264 = EncoderAvailable("obs_x264"); ++ const char *h264_fallback = ++ (useX264 ? SIMPLE_ENCODER_X264 : SIMPLE_ENCODER_OPENH264); ++ + config_set_default_string(basicConfig, "SimpleOutput", "StreamEncoder", +- useNV ? SIMPLE_ENCODER_NVENC +- : SIMPLE_ENCODER_X264); ++ useNV ? SIMPLE_ENCODER_NVENC : h264_fallback); + config_set_default_string(basicConfig, "SimpleOutput", "RecEncoder", +- useNV ? SIMPLE_ENCODER_NVENC +- : SIMPLE_ENCODER_X264); ++ useNV ? SIMPLE_ENCODER_NVENC : h264_fallback); + + const char *aac_default = "ffmpeg_aac"; + if (EncoderAvailable("CoreAudio_AAC")) +@@ -1967,7 +1973,7 @@ void OBSBasic::OBSInit() + + InitBasicConfigDefaults2(); + +- CheckForSimpleModeX264Fallback(); ++ CheckForSimpleModeH264Fallback(); + + blog(LOG_INFO, STARTUP_SEPARATOR); + +diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp +index cbce69832..74c6eb144 100644 +--- a/UI/window-basic-main.hpp ++++ b/UI/window-basic-main.hpp +@@ -66,6 +66,7 @@ class OBSBasicVCamConfig; + + #define SIMPLE_ENCODER_X264 "x264" + #define SIMPLE_ENCODER_X264_LOWCPU "x264_lowcpu" ++#define SIMPLE_ENCODER_OPENH264 "ffmpeg_openh264" + #define SIMPLE_ENCODER_QSV "qsv" + #define SIMPLE_ENCODER_QSV_AV1 "qsv_av1" + #define SIMPLE_ENCODER_NVENC "nvenc" +@@ -434,7 +435,7 @@ private: + void DeleteProfile(const char *profile_name, const char *profile_dir); + void RefreshProfiles(); + void ChangeProfile(); +- void CheckForSimpleModeX264Fallback(); ++ void CheckForSimpleModeH264Fallback(); + + void SaveProjectNow(); + +diff --git a/UI/window-basic-settings-stream.cpp b/UI/window-basic-settings-stream.cpp +index b056938e7..548e5f45f 100644 +--- a/UI/window-basic-settings-stream.cpp ++++ b/UI/window-basic-settings-stream.cpp +@@ -1362,7 +1362,9 @@ static QString get_adv_fallback(const QString &enc) + return "com.apple.videotoolbox.videoencoder.ave.avc"; + if (enc == "obs_qsv11_av1") + return "obs_qsv11"; +- return "obs_x264"; ++ if (EncoderAvailable("obs_x264")) ++ return "obs_x264"; ++ return "ffmpeg_openh264"; + } + + static QString get_adv_audio_fallback(const QString &enc) +@@ -1391,7 +1393,9 @@ static QString get_simple_fallback(const QString &enc) + return SIMPLE_ENCODER_APPLE_H264; + if (enc == SIMPLE_ENCODER_QSV_AV1) + return SIMPLE_ENCODER_QSV; +- return SIMPLE_ENCODER_X264; ++ if (EncoderAvailable("obs_x264")) ++ return SIMPLE_ENCODER_X264; ++ return SIMPLE_ENCODER_OPENH264; + } + + bool OBSBasicSettings::ServiceSupportsCodecCheck() +@@ -1670,8 +1674,12 @@ void OBSBasicSettings::ResetEncoders(bool streamOnly) + + #define ENCODER_STR(str) QTStr("Basic.Settings.Output.Simple.Encoder." str) + +- ui->simpleOutStrEncoder->addItem(ENCODER_STR("Software.X264.H264"), +- QString(SIMPLE_ENCODER_X264)); ++ ui->simpleOutStrEncoder->addItem(ENCODER_STR("Software.OpenH264.H264"), ++ QString(SIMPLE_ENCODER_OPENH264)); ++ if (service_supports_encoder(vcodecs, "obs_x264")) ++ ui->simpleOutStrEncoder->addItem( ++ ENCODER_STR("Software.X264.H264"), ++ QString(SIMPLE_ENCODER_X264)); + #ifdef _WIN32 + if (service_supports_encoder(vcodecs, "obs_qsv11")) + ui->simpleOutStrEncoder->addItem( +diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp +index 48bb4bac6..51fe280db 100644 +--- a/UI/window-basic-settings.cpp ++++ b/UI/window-basic-settings.cpp +@@ -3831,6 +3831,11 @@ void OBSBasicSettings::SaveOutputSettings() + do. This only exists to make sure that the x264 preset doesn't + get overwritten with empty data. */ + presetType = "ApplePreset"; ++ else if (encoder == SIMPLE_ENCODER_OPENH264) ++ /* The OpenH264 encoder does not have presets like the other encoders ++ do. This only exists to make sure that the x264 preset doesn't ++ get overwritten with empty data. */ ++ presetType = "OpenH264Preset"; + else + presetType = "Preset"; + +@@ -5286,11 +5291,16 @@ void OBSBasicSettings::FillSimpleRecordingValues() + ADD_QUALITY("HQ"); + ADD_QUALITY("Lossless"); + +- ui->simpleOutRecEncoder->addItem(ENCODER_STR("Software.X264.H264"), +- QString(SIMPLE_ENCODER_X264)); +- ui->simpleOutRecEncoder->addItem( +- ENCODER_STR("SoftwareLowCPU.X264.H264"), +- QString(SIMPLE_ENCODER_X264_LOWCPU)); ++ ui->simpleOutRecEncoder->addItem(ENCODER_STR("Software.OpenH264.H264"), ++ QString(SIMPLE_ENCODER_OPENH264)); ++ if (EncoderAvailable("obs_x264")) { ++ ui->simpleOutRecEncoder->addItem( ++ ENCODER_STR("Software.X264.H264"), ++ QString(SIMPLE_ENCODER_X264)); ++ ui->simpleOutRecEncoder->addItem( ++ ENCODER_STR("SoftwareLowCPU.X264.H264"), ++ QString(SIMPLE_ENCODER_X264_LOWCPU)); ++ } + if (EncoderAvailable("obs_qsv11")) + ui->simpleOutRecEncoder->addItem( + ENCODER_STR("Hardware.QSV.H264"), +@@ -5463,6 +5473,9 @@ void OBSBasicSettings::SimpleStreamingEncoderChanged() + + defaultPreset = "balanced"; + preset = curAMDAV1Preset; ++ } else if (encoder == SIMPLE_ENCODER_OPENH264) { ++ ui->simpleOutPreset->setVisible(false); ++ ui->simpleOutPresetLabel->setVisible(false); + } else { + + #define PRESET_STR(val) \ +-- +2.39.2 + diff --git a/patches/0007-5fdda179ed2768304a98d48f4074e54fe7cbf5b3.patch b/patches/0007-5fdda179ed2768304a98d48f4074e54fe7cbf5b3.patch deleted file mode 100644 index 6f93acf..0000000 --- a/patches/0007-5fdda179ed2768304a98d48f4074e54fe7cbf5b3.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 5fdda179ed2768304a98d48f4074e54fe7cbf5b3 Mon Sep 17 00:00:00 2001 -From: David Rosca -Date: Fri, 30 Jun 2023 07:23:41 +0200 -Subject: [PATCH] obs-ffmpeg: Increase initial buffer fullness for VAAPI - -Default ffmpeg initial buffer fullness (75%) is too low -and results in significantly lower video quality on AMD cards. - -Changing it to 100% fixes the quality and also matches what -AMF encoder is doing. ---- - plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c b/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c -index c5aa0128a54b9..1a6ecd63ae4d4 100644 ---- a/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c -+++ b/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c -@@ -300,6 +300,8 @@ static bool vaapi_update(void *data, obs_data_t *settings, bool hevc) - enc->context->level = level; - enc->context->bit_rate = bitrate * 1000; - enc->context->rc_max_rate = maxrate * 1000; -+ enc->context->rc_initial_buffer_occupancy = -+ (maxrate ? maxrate : bitrate) * 1000; - - enc->context->width = obs_encoder_get_width(enc->encoder); - enc->context->height = obs_encoder_get_height(enc->encoder); diff --git a/patches/0001-6207.patch b/patches/6207.patch similarity index 100% rename from patches/0001-6207.patch rename to patches/6207.patch diff --git a/patches/8051.patch b/patches/8051.patch new file mode 100644 index 0000000..4977c00 --- /dev/null +++ b/patches/8051.patch @@ -0,0 +1,283 @@ +From 01f0cab97d222f5cd4d7468f730370e76f08b42a Mon Sep 17 00:00:00 2001 +From: CodeYan01 <65320293+CodeYan01@users.noreply.github.com> +Date: Thu, 12 Jan 2023 01:01:14 +0800 +Subject: [PATCH] UI: Refactor editable list modification + +Previously would unnecessarily recreating the data array for every +modification (adding/removing/reordering/editing). This clears the +fields in the associated data array that other code/scripts would add, +such as an ID field for each item that could be used to distinguish +each item from their duplicates in the list. + +I initially wanted to remove EditableListChanged, but it no longer saved +the item selection whenever the list is modified, so I kept the function +and just changed it to update the selected state in the data array. +--- + UI/properties-view.cpp | 97 +++++++++++++++++++++++++++++++++++++----- + UI/properties-view.hpp | 6 +++ + 2 files changed, 93 insertions(+), 10 deletions(-) + +diff --git a/UI/properties-view.cpp b/UI/properties-view.cpp +index 7d8838b3603a2..025b104d0db27 100644 +--- a/UI/properties-view.cpp ++++ b/UI/properties-view.cpp +@@ -709,6 +709,11 @@ void OBSPropertiesView::AddEditableList(obs_property_t *prop, + { + const char *name = obs_property_name(prop); + OBSDataArrayAutoRelease array = obs_data_get_array(settings, name); ++ if (array == NULL) { ++ array = obs_data_array_create(); ++ obs_data_set_array(settings, name, array); ++ } ++ + QListWidget *list = new QListWidget(); + size_t count = obs_data_array_count(array); + +@@ -731,8 +736,8 @@ void OBSPropertiesView::AddEditableList(obs_property_t *prop, + WidgetInfo *info = new WidgetInfo(this, prop, list); + + list->setDragDropMode(QAbstractItemView::InternalMove); +- connect(list->model(), &QAbstractItemModel::rowsMoved, +- [info]() { info->EditableListChanged(); }); ++ connect(list->model(), &QAbstractItemModel::rowsMoved, info, ++ &WidgetInfo::EditListReordered); + + QVBoxLayout *sideLayout = new QVBoxLayout(); + NewButton(sideLayout, info, "addIconSmall", &WidgetInfo::EditListAdd); +@@ -1992,24 +1997,52 @@ void WidgetInfo::GroupChanged(const char *setting) + : true); + } + ++void WidgetInfo::EditListReordered(const QModelIndex &sourceParent, ++ int sourceStart, int sourceEnd, ++ const QModelIndex &destinationParent, ++ int destinationRow) ++{ ++ UNUSED_PARAMETER(sourceParent); ++ UNUSED_PARAMETER(destinationParent); ++ ++ const char *setting = obs_property_name(property); ++ OBSDataArrayAutoRelease array = ++ obs_data_get_array(view->settings, setting); ++ ++ for (int i = sourceStart; i <= sourceEnd; i++) { ++ OBSDataAutoRelease arrayItem = obs_data_array_item(array, i); ++ obs_data_array_insert(array, destinationRow, arrayItem); ++ // if moved to top, destination row increases ++ obs_data_array_erase(array, (i > destinationRow) ? i + 1 : i); ++ ++destinationRow; ++ } ++ EditableListChanged(); ++} ++ ++void WidgetInfo::EditableListArrayPushBack(obs_data_array_t *array, ++ const char *text) ++{ ++ OBSDataAutoRelease arrayItem = obs_data_create(); ++ obs_data_set_string(arrayItem, "value", text); ++ obs_data_set_bool(arrayItem, "selected", false); ++ obs_data_set_bool(arrayItem, "hidden", false); ++ obs_data_array_push_back(array, arrayItem); ++} ++ + void WidgetInfo::EditableListChanged() + { + const char *setting = obs_property_name(property); + QListWidget *list = reinterpret_cast(widget); +- OBSDataArrayAutoRelease array = obs_data_array_create(); ++ OBSDataArrayAutoRelease array = ++ obs_data_get_array(view->settings, setting); + + for (int i = 0; i < list->count(); i++) { + QListWidgetItem *item = list->item(i); +- OBSDataAutoRelease arrayItem = obs_data_create(); +- obs_data_set_string(arrayItem, "value", +- QT_TO_UTF8(item->text())); ++ OBSDataAutoRelease arrayItem = obs_data_array_item(array, i); + obs_data_set_bool(arrayItem, "selected", item->isSelected()); + obs_data_set_bool(arrayItem, "hidden", item->isHidden()); +- obs_data_array_push_back(array, arrayItem); + } + +- obs_data_set_array(view->settings, setting, array); +- + ControlChanged(); + } + +@@ -2263,6 +2296,9 @@ void WidgetInfo::EditListAddText() + { + QListWidget *list = reinterpret_cast(widget); + const char *desc = obs_property_description(property); ++ const char *setting = obs_property_name(property); ++ OBSDataArrayAutoRelease array = ++ obs_data_get_array(view->settings, setting); + + EditableItemDialog dialog(widget->window(), QString(), false); + auto title = QTStr("Basic.PropertiesWindow.AddEditableListEntry") +@@ -2276,6 +2312,7 @@ void WidgetInfo::EditListAddText() + return; + + list->addItem(text); ++ EditableListArrayPushBack(array, QT_TO_UTF8(text)); + EditableListChanged(); + } + +@@ -2286,6 +2323,9 @@ void WidgetInfo::EditListAddFiles() + const char *filter = obs_property_editable_list_filter(property); + const char *default_path = + obs_property_editable_list_default_path(property); ++ const char *setting = obs_property_name(property); ++ OBSDataArrayAutoRelease array = ++ obs_data_get_array(view->settings, setting); + + QString title = QTStr("Basic.PropertiesWindow.AddEditableListFiles") + .arg(QT_UTF8(desc)); +@@ -2301,6 +2341,9 @@ void WidgetInfo::EditListAddFiles() + return; + + list->addItems(files); ++ for (QString &file : files) { ++ EditableListArrayPushBack(array, QT_TO_UTF8(file)); ++ } + EditableListChanged(); + } + +@@ -2310,6 +2353,9 @@ void WidgetInfo::EditListAddDir() + const char *desc = obs_property_description(property); + const char *default_path = + obs_property_editable_list_default_path(property); ++ const char *setting = obs_property_name(property); ++ OBSDataArrayAutoRelease array = ++ obs_data_get_array(view->settings, setting); + + QString title = QTStr("Basic.PropertiesWindow.AddEditableListDir") + .arg(QT_UTF8(desc)); +@@ -2325,6 +2371,7 @@ void WidgetInfo::EditListAddDir() + return; + + list->addItem(dir); ++ EditableListArrayPushBack(array, QT_TO_UTF8(dir)); + EditableListChanged(); + } + +@@ -2332,9 +2379,15 @@ void WidgetInfo::EditListRemove() + { + QListWidget *list = reinterpret_cast(widget); + QList items = list->selectedItems(); ++ const char *setting = obs_property_name(property); ++ OBSDataArrayAutoRelease array = ++ obs_data_get_array(view->settings, setting); + +- for (QListWidgetItem *item : items) ++ for (qsizetype i = items.size() - 1; i >= 0; i--) { ++ QListWidgetItem *item = items.at(i); ++ obs_data_array_erase(array, list->row(item)); + delete item; ++ } + EditableListChanged(); + } + +@@ -2343,6 +2396,7 @@ void WidgetInfo::EditListEdit() + QListWidget *list = reinterpret_cast(widget); + enum obs_editable_list_type type = + obs_property_editable_list_type(property); ++ const char *setting = obs_property_name(property); + const char *desc = obs_property_description(property); + const char *filter = obs_property_editable_list_filter(property); + QList selectedItems = list->selectedItems(); +@@ -2351,6 +2405,10 @@ void WidgetInfo::EditListEdit() + return; + + QListWidgetItem *item = selectedItems[0]; ++ int row = list->row(item); ++ OBSDataArrayAutoRelease array = ++ obs_data_get_array(view->settings, setting); ++ OBSDataAutoRelease arrayItem = obs_data_array_item(array, row); + + if (type == OBS_EDITABLE_LIST_TYPE_FILES) { + QDir pathDir(item->text()); +@@ -2367,6 +2425,7 @@ void WidgetInfo::EditListEdit() + return; + + item->setText(path); ++ obs_data_set_string(arrayItem, "value", QT_TO_UTF8(path)); + EditableListChanged(); + return; + } +@@ -2385,6 +2444,7 @@ void WidgetInfo::EditListEdit() + return; + + item->setText(text); ++ obs_data_set_string(arrayItem, "value", QT_TO_UTF8(text)); + EditableListChanged(); + } + +@@ -2392,6 +2452,9 @@ void WidgetInfo::EditListUp() + { + QListWidget *list = reinterpret_cast(widget); + int lastItemRow = -1; ++ const char *setting = obs_property_name(property); ++ OBSDataArrayAutoRelease array = ++ obs_data_get_array(view->settings, setting); + + for (int i = 0; i < list->count(); i++) { + QListWidgetItem *item = list->item(i); +@@ -2405,6 +2468,11 @@ void WidgetInfo::EditListUp() + list->takeItem(row); + list->insertItem(lastItemRow, item); + item->setSelected(true); ++ ++ OBSDataAutoRelease arrayItem = ++ obs_data_array_item(array, row); ++ obs_data_array_insert(array, lastItemRow, arrayItem); ++ obs_data_array_erase(array, row + 1); + } else { + lastItemRow = row; + } +@@ -2417,6 +2485,9 @@ void WidgetInfo::EditListDown() + { + QListWidget *list = reinterpret_cast(widget); + int lastItemRow = list->count(); ++ const char *setting = obs_property_name(property); ++ OBSDataArrayAutoRelease array = ++ obs_data_get_array(view->settings, setting); + + for (int i = list->count() - 1; i >= 0; i--) { + QListWidgetItem *item = list->item(i); +@@ -2430,6 +2501,12 @@ void WidgetInfo::EditListDown() + list->takeItem(row); + list->insertItem(lastItemRow, item); + item->setSelected(true); ++ ++ OBSDataAutoRelease arrayItem = ++ obs_data_array_item(array, row); ++ obs_data_array_insert(array, lastItemRow + 1, ++ arrayItem); ++ obs_data_array_erase(array, row); + } else { + lastItemRow = row; + } +diff --git a/UI/properties-view.hpp b/UI/properties-view.hpp +index e520dcdde2c90..89546b1317fba 100644 +--- a/UI/properties-view.hpp ++++ b/UI/properties-view.hpp +@@ -47,6 +47,8 @@ class WidgetInfo : public QObject { + void ButtonClicked(); + + void TogglePasswordText(bool checked); ++ void EditableListArrayPushBack(obs_data_array_t *array, ++ const char *text); + + public: + inline WidgetInfo(OBSPropertiesView *view_, obs_property_t *prop, +@@ -79,6 +81,10 @@ public slots: + void EditListEdit(); + void EditListUp(); + void EditListDown(); ++ void EditListReordered(const QModelIndex &sourceParent, int sourceStart, ++ int sourceEnd, ++ const QModelIndex &destinationParent, ++ int destinationRow); + }; + + /* ------------------------------------------------------------------------- */ diff --git a/patches/0005-8794.patch b/patches/8794.patch similarity index 86% rename from patches/0005-8794.patch rename to patches/8794.patch index 81169d2..aeb89da 100644 --- a/patches/0005-8794.patch +++ b/patches/8794.patch @@ -1,7 +1,7 @@ From 38031cd5d1e9486f06c782fbc0162e9f95e3d116 Mon Sep 17 00:00:00 2001 From: Bleuzen <12885163+Bleuzen@users.noreply.github.com> Date: Sat, 19 Aug 2023 02:50:09 +0200 -Subject: [PATCH] obs-ffmpeg: Add NVENC AV1 FFmpeg encoder, part 1 +Subject: [PATCH 1/2] obs-ffmpeg: Add NVENC AV1 FFmpeg encoder, part 1 --- plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c | 109 ++++++++++++++++++++++++-- @@ -23,7 +23,7 @@ index cfd4ea91916a2..80db3ba85ef39 100644 @@ -61,6 +62,13 @@ static const char *hevc_nvenc_getname(void *unused) } #endif - + +#define ENCODER_NAME_AV1 "GPU: NVIDIA NVENC AV1 (FFmpeg)" +static const char *av1_nvenc_getname(void *unused) +{ @@ -47,13 +47,13 @@ index cfd4ea91916a2..80db3ba85ef39 100644 &enc->header.array, &enc->header.num, @@ -300,10 +310,11 @@ static void on_first_packet(void *data, AVPacket *pkt, struct darray *da) } - + static void *nvenc_create_internal(obs_data_t *settings, obs_encoder_t *encoder, - bool psycho_aq, bool hevc) + bool psycho_aq, bool hevc, bool av1) { struct nvenc_encoder *enc = bzalloc(sizeof(*enc)); - + + enc->av1 = av1; #ifdef ENABLE_HEVC enc->hevc = hevc; @@ -74,7 +74,7 @@ index cfd4ea91916a2..80db3ba85ef39 100644 ENCODER_NAME_H264, on_init_error, @@ -368,12 +384,14 @@ static void *h264_nvenc_create(obs_data_t *settings, obs_encoder_t *encoder) } - + bool psycho_aq = obs_data_get_bool(settings, "psycho_aq"); - void *enc = nvenc_create_internal(settings, encoder, psycho_aq, false); + void *enc = nvenc_create_internal(settings, encoder, psycho_aq, false, @@ -87,11 +87,11 @@ index cfd4ea91916a2..80db3ba85ef39 100644 + enc = nvenc_create_internal(settings, encoder, false, false, + false); } - + return enc; @@ -415,18 +433,68 @@ static void *hevc_nvenc_create(obs_data_t *settings, obs_encoder_t *encoder) } - + bool psycho_aq = obs_data_get_bool(settings, "psycho_aq"); - void *enc = nvenc_create_internal(settings, encoder, psycho_aq, true); + void *enc = nvenc_create_internal(settings, encoder, psycho_aq, true, @@ -104,11 +104,11 @@ index cfd4ea91916a2..80db3ba85ef39 100644 + enc = nvenc_create_internal(settings, encoder, false, true, + false); } - + return enc; } #endif - + +static void *av1_nvenc_create(obs_data_t *settings, obs_encoder_t *encoder) +{ + video_t *video = obs_encoder_video(encoder); @@ -163,7 +163,7 @@ index cfd4ea91916a2..80db3ba85ef39 100644 @@ -669,6 +737,12 @@ obs_properties_t *hevc_nvenc_properties_ffmpeg(void *unused) } #endif - + +obs_properties_t *av1_nvenc_properties_ffmpeg(void *unused) +{ + UNUSED_PARAMETER(unused); @@ -209,7 +209,7 @@ index 7eb9a876d82ff..07973ffc73b40 100644 +extern struct obs_encoder_info av1_nvenc_encoder_info; extern struct obs_encoder_info svt_av1_encoder_info; extern struct obs_encoder_info aom_av1_encoder_info; - + @@ -272,7 +273,7 @@ static void do_nvenc_check_for_ubuntu_20_04(void) static bool nvenc_codec_exists(const char *name, const char *fallback) { @@ -217,7 +217,7 @@ index 7eb9a876d82ff..07973ffc73b40 100644 - if (!nvenc) + if (!nvenc && fallback) nvenc = avcodec_find_encoder_by_name(fallback); - + return nvenc != NULL; @@ -302,8 +303,10 @@ static bool nvenc_supported(bool *out_h264, bool *out_hevc, bool *out_av1) if (success) { @@ -238,5 +238,38 @@ index 7eb9a876d82ff..07973ffc73b40 100644 + if (av1) + obs_register_encoder(&av1_nvenc_encoder_info); } - + #ifdef _WIN32 + +From c973af782104d8ac471e08da6b243ceac102f6f2 Mon Sep 17 00:00:00 2001 +From: Bleuzen <12885163+Bleuzen@users.noreply.github.com> +Date: Mon, 13 Nov 2023 00:02:14 +0100 +Subject: [PATCH 2/2] obs-ffmpeg: Add NVENC AV1 FFmpeg encoder, part 2 + +--- + plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c b/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c +index 80db3ba85ef39..72455e23b744f 100644 +--- a/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c ++++ b/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c +@@ -19,6 +19,7 @@ + #ifdef ENABLE_HEVC + #include + #endif ++#include + + #include "obs-ffmpeg-video-encoders.h" + +@@ -290,7 +291,9 @@ static void on_first_packet(void *data, AVPacket *pkt, struct darray *da) + } else + #endif + if (enc->av1) { +- // TODO: add obs_extract_av1_headers ++ obs_extract_av1_headers(pkt->data, pkt->size, ++ (uint8_t **)&da->array, &da->num, ++ &enc->header.array, &enc->header.num); + } else { + obs_extract_avc_headers(pkt->data, pkt->size, + (uint8_t **)&da->array, &da->num, diff --git a/patches/0006-8832.patch b/patches/8832.patch similarity index 78% rename from patches/0006-8832.patch rename to patches/8832.patch index 18975a1..f58224f 100644 --- a/patches/0006-8832.patch +++ b/patches/8832.patch @@ -1,218 +1,7 @@ -From a8d13ad4d98e70da648819afc219c65d256cf95d Mon Sep 17 00:00:00 2001 -From: David Rosca -Date: Tue, 2 May 2023 13:14:18 +0200 -Subject: [PATCH 1/3] libobs: Add AV1 parsing functions - ---- - libobs/CMakeLists.txt | 2 + - libobs/cmake/legacy.cmake | 2 + - libobs/obs-av1.c | 123 ++++++++++++++++++++++++++++++++++++++ - libobs/obs-av1.h | 35 +++++++++++ - 4 files changed, 162 insertions(+) - create mode 100644 libobs/obs-av1.c - create mode 100644 libobs/obs-av1.h - -diff --git a/libobs/CMakeLists.txt b/libobs/CMakeLists.txt -index 46112abe71f9d..36a75713c001f 100644 ---- a/libobs/CMakeLists.txt -+++ b/libobs/CMakeLists.txt -@@ -33,6 +33,8 @@ target_sources( - obs-audio-controls.c - obs-audio-controls.h - obs-audio.c -+ obs-av1.c -+ obs-av1.h - obs-avc.c - obs-avc.h - obs-data.c -diff --git a/libobs/cmake/legacy.cmake b/libobs/cmake/legacy.cmake -index 5f13c4c0f04ab..dd77cdfb94229 100644 ---- a/libobs/cmake/legacy.cmake -+++ b/libobs/cmake/legacy.cmake -@@ -32,6 +32,8 @@ target_sources( - obs-audio.c - obs-audio-controls.c - obs-audio-controls.h -+ obs-av1.c -+ obs-av1.h - obs-avc.c - obs-avc.h - obs-data.c -diff --git a/libobs/obs-av1.c b/libobs/obs-av1.c -new file mode 100644 -index 0000000000000..a015130537cf2 ---- /dev/null -+++ b/libobs/obs-av1.c -@@ -0,0 +1,123 @@ -+// SPDX-FileCopyrightText: 2023 David Rosca -+// -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+#include "obs-av1.h" -+ -+#include "obs.h" -+ -+static inline uint64_t leb128(const uint8_t *buf, size_t size, size_t *len) -+{ -+ uint64_t value = 0; -+ uint8_t leb128_byte; -+ -+ *len = 0; -+ -+ for (int i = 0; i < 8; i++) { -+ if (size-- < 1) -+ break; -+ (*len)++; -+ leb128_byte = buf[i]; -+ value |= (leb128_byte & 0x7f) << (i * 7); -+ if (!(leb128_byte & 0x80)) -+ break; -+ } -+ -+ return value; -+} -+ -+static inline unsigned int get_bits(uint8_t val, unsigned int n, -+ unsigned int count) -+{ -+ return (val >> (8 - n - count)) & ((1 << (count - 1)) * 2 - 1); -+} -+ -+static void parse_obu_header(const uint8_t *buf, size_t size, size_t *obu_start, -+ size_t *obu_size, int *obu_type) -+{ -+ int extension_flag, has_size_field; -+ size_t size_len = 0; -+ -+ *obu_start = 0; -+ *obu_size = 0; -+ *obu_type = 0; -+ -+ if (size < 1) -+ return; -+ -+ *obu_type = get_bits(*buf, 1, 4); -+ extension_flag = get_bits(*buf, 5, 1); -+ has_size_field = get_bits(*buf, 6, 1); -+ -+ if (extension_flag) -+ (*obu_start)++; -+ -+ (*obu_start)++; -+ -+ if (has_size_field) -+ *obu_size = (size_t)leb128(buf + *obu_start, size - *obu_start, -+ &size_len); -+ else -+ *obu_size = size - 1; -+ -+ *obu_start += size_len; -+} -+ -+bool obs_av1_keyframe(const uint8_t *data, size_t size) -+{ -+ const uint8_t *start = data, *end = data + size; -+ -+ while (start < end) { -+ size_t obu_start, obu_size; -+ int obu_type; -+ parse_obu_header(start, end - start, &obu_start, &obu_size, -+ &obu_type); -+ -+ if (obu_size) { -+ if (obu_type == OBS_OBU_FRAME || -+ obu_type == OBS_OBU_FRAME_HEADER) { -+ uint8_t val = *(start + obu_start); -+ if (!get_bits(val, 0, 1)) // show_existing_frame -+ return get_bits(val, 1, 2) == -+ 0; // frame_type -+ return false; -+ } -+ } -+ -+ start += obu_start + obu_size; -+ } -+ -+ return false; -+} -+ -+void obs_extract_av1_headers(const uint8_t *packet, size_t size, -+ uint8_t **new_packet_data, size_t *new_packet_size, -+ uint8_t **header_data, size_t *header_size) -+{ -+ DARRAY(uint8_t) new_packet; -+ DARRAY(uint8_t) header; -+ const uint8_t *start = packet, *end = packet + size; -+ -+ da_init(new_packet); -+ da_init(header); -+ -+ while (start < end) { -+ size_t obu_start, obu_size; -+ int obu_type; -+ parse_obu_header(start, end - start, &obu_start, &obu_size, -+ &obu_type); -+ -+ if (obu_type == OBS_OBU_METADATA || -+ obu_type == OBS_OBU_SEQUENCE_HEADER) { -+ da_push_back_array(header, start, obu_start + obu_size); -+ } -+ da_push_back_array(new_packet, start, obu_start + obu_size); -+ -+ start += obu_start + obu_size; -+ } -+ -+ *new_packet_data = new_packet.array; -+ *new_packet_size = new_packet.num; -+ *header_data = header.array; -+ *header_size = header.num; -+} -diff --git a/libobs/obs-av1.h b/libobs/obs-av1.h -new file mode 100644 -index 0000000000000..031299da0a415 ---- /dev/null -+++ b/libobs/obs-av1.h -@@ -0,0 +1,35 @@ -+// SPDX-FileCopyrightText: 2023 David Rosca -+// -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+#pragma once -+ -+#include "util/c99defs.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+enum { -+ OBS_OBU_SEQUENCE_HEADER = 1, -+ OBS_OBU_TEMPORAL_DELIMITER = 2, -+ OBS_OBU_FRAME_HEADER = 3, -+ OBS_OBU_TILE_GROUP = 4, -+ OBS_OBU_METADATA = 5, -+ OBS_OBU_FRAME = 6, -+ OBS_OBU_REDUNDANT_FRAME_HEADER = 7, -+ OBS_OBU_TILE_LIST = 8, -+ OBS_OBU_PADDING = 15, -+}; -+ -+/* Helpers for parsing AV1 OB units. */ -+ -+EXPORT bool obs_av1_keyframe(const uint8_t *data, size_t size); -+EXPORT void obs_extract_av1_headers(const uint8_t *packet, size_t size, -+ uint8_t **new_packet_data, -+ size_t *new_packet_size, -+ uint8_t **header_data, size_t *header_size); -+ -+#ifdef __cplusplus -+} -+#endif - -From 5d0940dd512515d7885aafdd01cff6a875431418 Mon Sep 17 00:00:00 2001 +From 27565d8ffc8fa7407381595f56c2f1aebb03d3ec Mon Sep 17 00:00:00 2001 From: David Rosca Date: Tue, 2 May 2023 13:39:13 +0200 -Subject: [PATCH 2/3] obs-ffmpeg: Add AV1 support for VA-API +Subject: [PATCH 1/2] obs-ffmpeg: Add AV1 support for VA-API --- plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c | 284 ++++++++++++++++---------- @@ -222,7 +11,7 @@ Subject: [PATCH 2/3] obs-ffmpeg: Add AV1 support for VA-API 4 files changed, 254 insertions(+), 108 deletions(-) diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c b/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c -index 25c5f79007a31..7543d68b6f750 100644 +index ec2a8651a850b..88c906e5dc98d 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c @@ -24,6 +24,7 @@ @@ -236,7 +25,7 @@ index 25c5f79007a31..7543d68b6f750 100644 @@ -51,8 +52,15 @@ #define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__) #define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__) - + +enum codec_type { + CODEC_H264, + CODEC_HEVC, @@ -246,13 +35,13 @@ index 25c5f79007a31..7543d68b6f750 100644 struct vaapi_encoder { obs_encoder_t *encoder; + enum codec_type codec; - + AVBufferRef *vadevice_ref; AVBufferRef *vaframes_ref; @@ -83,59 +91,48 @@ static const char *h264_vaapi_getname(void *unused) return "FFmpeg VAAPI H.264"; } - + -#ifdef ENABLE_HEVC -static const char *hevc_vaapi_getname(void *unused) +static const char *av1_vaapi_getname(void *unused) @@ -267,7 +56,7 @@ index 25c5f79007a31..7543d68b6f750 100644 - return format == VIDEO_FORMAT_NV12; + return "FFmpeg VAAPI AV1"; } - + #ifdef ENABLE_HEVC -static inline bool hevc_valid_format(enum video_format format) +static const char *hevc_vaapi_getname(void *unused) @@ -277,7 +66,7 @@ index 25c5f79007a31..7543d68b6f750 100644 + return "FFmpeg VAAPI HEVC"; } #endif - + -static void h264_vaapi_video_info(void *data, struct video_scale_info *info) +static inline bool vaapi_valid_format(struct vaapi_encoder *enc, + enum video_format format) @@ -302,16 +91,16 @@ index 25c5f79007a31..7543d68b6f750 100644 - - info->format = pref_format; } - + -#ifdef ENABLE_HEVC -static void hevc_vaapi_video_info(void *data, struct video_scale_info *info) +static void vaapi_video_info(void *data, struct video_scale_info *info) { struct vaapi_encoder *enc = data; enum video_format pref_format; - + pref_format = obs_encoder_get_preferred_video_format(enc->encoder); - + - if (!hevc_valid_format(pref_format)) { - pref_format = hevc_valid_format(info->format) + if (!vaapi_valid_format(enc, pref_format)) { @@ -319,34 +108,34 @@ index 25c5f79007a31..7543d68b6f750 100644 ? info->format : VIDEO_FORMAT_NV12; } - + info->format = pref_format; } -#endif - + static bool vaapi_init_codec(struct vaapi_encoder *enc, const char *path) { @@ -232,7 +229,7 @@ static const rc_mode_t *get_rc_mode(const char *name) return rc_mode ? rc_mode : RC_MODES; } - + -static bool vaapi_update(void *data, obs_data_t *settings, bool hevc) +static bool vaapi_update(void *data, obs_data_t *settings) { struct vaapi_encoder *enc = data; - + @@ -247,7 +244,7 @@ static bool vaapi_update(void *data, obs_data_t *settings, bool hevc) int bf = (int)obs_data_get_int(settings, "bf"); int qp = rc_mode->qp ? (int)obs_data_get_int(settings, "qp") : 0; - + - av_opt_set_int(enc->context->priv_data, "qp", qp, 0); + enc->context->global_quality = enc->codec == CODEC_AV1 ? qp * 5 : qp; - + int level = (int)obs_data_get_int(settings, "level"); int bitrate = rc_mode->bitrate @@ -277,21 +274,15 @@ static bool vaapi_update(void *data, obs_data_t *settings, bool hevc) info.range = voi->range; - + #ifdef ENABLE_HEVC - if (hevc) { + if (enc->codec == CODEC_HEVC) { @@ -366,13 +155,13 @@ index 25c5f79007a31..7543d68b6f750 100644 } +#endif + vaapi_video_info(enc, &info); - + enc->context->profile = profile; enc->context->max_b_frames = bf; -@@ -418,16 +409,28 @@ static void vaapi_destroy(void *data) +@@ -414,8 +405,20 @@ static void vaapi_destroy(void *data) bfree(enc); } - + +static inline const char *vaapi_encoder_name(enum codec_type codec) +{ + if (codec == CODEC_H264) { @@ -390,28 +179,29 @@ index 25c5f79007a31..7543d68b6f750 100644 + enum codec_type codec) { struct vaapi_encoder *enc; - + #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100) +@@ -425,8 +428,8 @@ static void *vaapi_create_internal(obs_data_t *settings, obs_encoder_t *encoder, enc = bzalloc(sizeof(*enc)); enc->encoder = encoder; - + - const char *const name = hevc ? "hevc_vaapi" : "h264_vaapi"; - enc->vaapi = avcodec_find_encoder_by_name(name); + enc->codec = codec; + enc->vaapi = avcodec_find_encoder_by_name(vaapi_encoder_name(codec)); - + enc->first_packet = true; - + @@ -444,7 +447,7 @@ static void *vaapi_create_internal(obs_data_t *settings, obs_encoder_t *encoder, goto fail; } - + - if (!vaapi_update(enc, settings, hevc)) + if (!vaapi_update(enc, settings)) goto fail; - + return enc; @@ -456,13 +459,18 @@ static void *vaapi_create_internal(obs_data_t *settings, obs_encoder_t *encoder, - + static void *h264_vaapi_create(obs_data_t *settings, obs_encoder_t *encoder) { - return vaapi_create_internal(settings, encoder, false); @@ -422,7 +212,7 @@ index 25c5f79007a31..7543d68b6f750 100644 +{ + return vaapi_create_internal(settings, encoder, CODEC_AV1); } - + #ifdef ENABLE_HEVC static void *hevc_vaapi_create(obs_data_t *settings, obs_encoder_t *encoder) { @@ -430,11 +220,11 @@ index 25c5f79007a31..7543d68b6f750 100644 + return vaapi_create_internal(settings, encoder, CODEC_HEVC); } #endif - + @@ -492,9 +500,8 @@ static inline void copy_data(AVFrame *pic, const struct encoder_frame *frame, } } - + -static bool vaapi_encode_internal(void *data, struct encoder_frame *frame, - struct encoder_packet *packet, - bool *received_packet, bool hevc) @@ -444,7 +234,7 @@ index 25c5f79007a31..7543d68b6f750 100644 struct vaapi_encoder *enc = data; AVFrame *hwframe = NULL; @@ -556,22 +563,26 @@ static bool vaapi_encode_internal(void *data, struct encoder_frame *frame, - + enc->first_packet = false; #ifdef ENABLE_HEVC - if (hevc) { @@ -472,7 +262,7 @@ index 25c5f79007a31..7543d68b6f750 100644 + &enc->header, + &enc->header_size); } - + da_copy_array(enc->buffer, new_packet, size); @@ -587,14 +598,17 @@ static bool vaapi_encode_internal(void *data, struct encoder_frame *frame, packet->size = enc->buffer.num; @@ -497,7 +287,7 @@ index 25c5f79007a31..7543d68b6f750 100644 @@ -610,54 +624,61 @@ static bool vaapi_encode_internal(void *data, struct encoder_frame *frame, return false; } - + -static bool h264_vaapi_encode(void *data, struct encoder_frame *frame, - struct encoder_packet *packet, - bool *received_packet) @@ -508,7 +298,7 @@ index 25c5f79007a31..7543d68b6f750 100644 + obs_property_t *p = obs_properties_get(ppts, name); + obs_property_set_visible(p, visible); } - + -#ifdef ENABLE_HEVC -static bool hevc_vaapi_encode(void *data, struct encoder_frame *frame, - struct encoder_packet *packet, @@ -534,7 +324,7 @@ index 25c5f79007a31..7543d68b6f750 100644 + } + return VAProfileNone; } - + -static void vaapi_defaults_internal(obs_data_t *settings, bool hevc) +static inline const char *vaapi_default_device(enum codec_type codec) { @@ -554,7 +344,7 @@ index 25c5f79007a31..7543d68b6f750 100644 + } + return NULL; +} - + +static void vaapi_defaults_internal(obs_data_t *settings, enum codec_type codec) +{ + const char *const device = vaapi_default_device(codec); @@ -565,7 +355,7 @@ index 25c5f79007a31..7543d68b6f750 100644 obs_data_set_default_int(settings, "profile", FF_PROFILE_HEVC_MAIN); + obs_data_set_default_int(settings, "level", 120); - + } else -#else - UNUSED_PARAMETER(hevc); @@ -587,7 +377,7 @@ index 25c5f79007a31..7543d68b6f750 100644 @@ -670,12 +691,7 @@ static void vaapi_defaults_internal(obs_data_t *settings, bool hevc) if (!va_dpy) return; - + -#ifdef ENABLE_HEVC - const VAProfile profile = hevc ? VAProfileHEVCMain - : VAProfileH264ConstrainedBaseline; @@ -599,7 +389,7 @@ index 25c5f79007a31..7543d68b6f750 100644 obs_data_set_default_string(settings, "rate_control", "CBR"); else if (vaapi_device_rc_supported(profile, va_dpy, VA_RC_VBR, device)) @@ -688,12 +704,17 @@ static void vaapi_defaults_internal(obs_data_t *settings, bool hevc) - + static void h264_vaapi_defaults(obs_data_t *settings) { - vaapi_defaults_internal(settings, false); @@ -610,13 +400,13 @@ index 25c5f79007a31..7543d68b6f750 100644 +{ + vaapi_defaults_internal(settings, CODEC_AV1); } - + static void hevc_vaapi_defaults(obs_data_t *settings) { - vaapi_defaults_internal(settings, true); + vaapi_defaults_internal(settings, CODEC_HEVC); } - + static bool vaapi_device_modified(obs_properties_t *ppts, obs_property_t *p, @@ -729,6 +750,11 @@ static bool vaapi_device_modified(obs_properties_t *ppts, obs_property_t *p, goto fail; @@ -630,16 +420,16 @@ index 25c5f79007a31..7543d68b6f750 100644 #ifdef ENABLE_HEVC case FF_PROFILE_HEVC_MAIN: if (!vaapi_display_hevc_supported(va_dpy, device)) -@@ -800,7 +826,7 @@ static bool get_device_name_from_pci(struct pci_access *pacc, char *pci_slot, +@@ -802,7 +828,7 @@ static bool get_device_name_from_pci(struct pci_access *pacc, char *pci_slot, return false; } - + -static obs_properties_t *vaapi_properties_internal(bool hevc) +static obs_properties_t *vaapi_properties_internal(enum codec_type codec) { obs_properties_t *props = obs_properties_create(); obs_property_t *list; -@@ -891,16 +917,18 @@ static obs_properties_t *vaapi_properties_internal(bool hevc) +@@ -893,16 +919,18 @@ static obs_properties_t *vaapi_properties_internal(bool hevc) obs_module_text("Profile"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); @@ -658,9 +448,9 @@ index 25c5f79007a31..7543d68b6f750 100644 + } else if (codec == CODEC_AV1) { + obs_property_list_add_int(list, "Main", FF_PROFILE_AV1_MAIN); } - + obs_property_set_modified_callback(list, vaapi_device_modified); -@@ -909,15 +937,34 @@ static obs_properties_t *vaapi_properties_internal(bool hevc) +@@ -911,15 +939,34 @@ static obs_properties_t *vaapi_properties_internal(bool hevc) OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_list_add_int(list, "Auto", FF_LEVEL_UNKNOWN); @@ -701,10 +491,10 @@ index 25c5f79007a31..7543d68b6f750 100644 + obs_property_list_add_int(list, "5.2", 14); + obs_property_list_add_int(list, "5.3", 15); + } - + list = obs_properties_add_list(props, "rate_control", obs_module_text("RateControl"), -@@ -952,14 +999,20 @@ static obs_properties_t *vaapi_properties_internal(bool hevc) +@@ -957,14 +1004,20 @@ static obs_properties_t *vaapi_properties_internal(bool hevc) static obs_properties_t *h264_vaapi_properties(void *unused) { UNUSED_PARAMETER(unused); @@ -717,7 +507,7 @@ index 25c5f79007a31..7543d68b6f750 100644 + UNUSED_PARAMETER(unused); + return vaapi_properties_internal(CODEC_AV1); } - + #ifdef ENABLE_HEVC static obs_properties_t *hevc_vaapi_properties(void *unused) { @@ -726,8 +516,8 @@ index 25c5f79007a31..7543d68b6f750 100644 + return vaapi_properties_internal(CODEC_HEVC); } #endif - -@@ -988,12 +1041,27 @@ struct obs_encoder_info h264_vaapi_encoder_info = { + +@@ -993,12 +1046,27 @@ struct obs_encoder_info h264_vaapi_encoder_info = { .get_name = h264_vaapi_getname, .create = h264_vaapi_create, .destroy = vaapi_destroy, @@ -755,9 +545,9 @@ index 25c5f79007a31..7543d68b6f750 100644 + .get_sei_data = vaapi_sei_data, + .get_video_info = vaapi_video_info, }; - + #ifdef ENABLE_HEVC -@@ -1004,11 +1072,11 @@ struct obs_encoder_info hevc_vaapi_encoder_info = { +@@ -1009,11 +1077,11 @@ struct obs_encoder_info hevc_vaapi_encoder_info = { .get_name = hevc_vaapi_getname, .create = hevc_vaapi_create, .destroy = vaapi_destroy, @@ -776,7 +566,7 @@ index 7eb9a876d82ff..981bb9c6550ff 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg.c @@ -47,6 +47,7 @@ extern struct obs_encoder_info aom_av1_encoder_info; - + #ifdef LIBAVUTIL_VAAPI_AVAILABLE extern struct obs_encoder_info h264_vaapi_encoder_info; +extern struct obs_encoder_info av1_vaapi_encoder_info; @@ -804,7 +594,7 @@ index 7eb9a876d82ff..981bb9c6550ff 100644 @@ -447,6 +459,13 @@ bool obs_module_load(void) blog(LOG_INFO, "FFmpeg VAAPI H264 encoding not supported"); } - + + if (av1_vaapi_supported()) { + blog(LOG_INFO, "FFmpeg VAAPI AV1 encoding supported"); + obs_register_encoder(&av1_vaapi_encoder_info); @@ -816,13 +606,13 @@ index 7eb9a876d82ff..981bb9c6550ff 100644 if (hevc_vaapi_supported()) { blog(LOG_INFO, "FFmpeg VAAPI HEVC encoding supported"); diff --git a/plugins/obs-ffmpeg/vaapi-utils.c b/plugins/obs-ffmpeg/vaapi-utils.c -index 4198ee59c6ab4..2c8eddd3676fa 100644 +index d020e2a1d8704..2ca7e468cc485 100644 --- a/plugins/obs-ffmpeg/vaapi-utils.c +++ b/plugins/obs-ffmpeg/vaapi-utils.c -@@ -261,6 +261,61 @@ const char *vaapi_get_h264_default_device() +@@ -293,6 +293,61 @@ const char *vaapi_get_h264_default_device() return default_h264_device; } - + +bool vaapi_display_av1_supported(VADisplay dpy, const char *device_path) +{ + bool ret = false; @@ -879,16 +669,16 @@ index 4198ee59c6ab4..2c8eddd3676fa 100644 +} + #ifdef ENABLE_HEVC - + bool vaapi_display_hevc_supported(VADisplay dpy, const char *device_path) diff --git a/plugins/obs-ffmpeg/vaapi-utils.h b/plugins/obs-ffmpeg/vaapi-utils.h -index b90b2394710b3..2d7ee29dc9ab9 100644 +index b8a8800331266..d458bad2c5d82 100644 --- a/plugins/obs-ffmpeg/vaapi-utils.h +++ b/plugins/obs-ffmpeg/vaapi-utils.h -@@ -19,6 +19,10 @@ bool vaapi_display_h264_supported(VADisplay dpy, const char *device_path); +@@ -20,6 +20,10 @@ bool vaapi_display_h264_supported(VADisplay dpy, const char *device_path); bool vaapi_device_h264_supported(const char *device_path); const char *vaapi_get_h264_default_device(void); - + +bool vaapi_display_av1_supported(VADisplay dpy, const char *device_path); +bool vaapi_device_av1_supported(const char *device_path); +const char *vaapi_get_av1_default_device(void); @@ -897,10 +687,10 @@ index b90b2394710b3..2d7ee29dc9ab9 100644 bool vaapi_display_hevc_supported(VADisplay dpy, const char *device_path); bool vaapi_device_hevc_supported(const char *device_path); -From 1b2b4da94760c829366e129cddda7cfe886f7b48 Mon Sep 17 00:00:00 2001 +From 871212adda660968cff324e1ab1053e19b342c11 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Fri, 22 Sep 2023 08:11:46 +0200 -Subject: [PATCH 3/3] obs-ffmpeg: Set better VA-API defaults +Subject: [PATCH 2/2] obs-ffmpeg: Set better VA-API defaults Use High profile for H264 and auto level with all codecs. Remove setting default value for unused "rendermode" option. @@ -909,7 +699,7 @@ Remove setting default value for unused "rendermode" option. 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c b/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c -index 7543d68b6f750..0ec7fa2ec43d0 100644 +index 88c906e5dc98d..b7e5d5eddb4a0 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c @@ -663,26 +663,21 @@ static void vaapi_defaults_internal(obs_data_t *settings, enum codec_type codec) @@ -944,17 +734,17 @@ index 7543d68b6f750..0ec7fa2ec43d0 100644 - obs_data_set_default_int(settings, "rendermode", 0); obs_data_set_default_int(settings, "qp", 20); obs_data_set_default_int(settings, "maxrate", 0); - + @@ -770,7 +765,7 @@ static bool vaapi_device_modified(obs_properties_t *ppts, obs_property_t *p, } - + if (vaapi_device_rc_supported(profile, va_dpy, VA_RC_CBR, device)) - obs_property_list_add_string(rc_p, "CBR (default)", "CBR"); + obs_property_list_add_string(rc_p, "CBR", "CBR"); - + if (vaapi_device_rc_supported(profile, va_dpy, VA_RC_VBR, device)) obs_property_list_add_string(rc_p, "VBR", "VBR"); -@@ -922,8 +917,7 @@ static obs_properties_t *vaapi_properties_internal(enum codec_type codec) +@@ -924,8 +919,7 @@ static obs_properties_t *vaapi_properties_internal(enum codec_type codec) obs_property_list_add_int(list, "Main10", FF_PROFILE_HEVC_MAIN_10); } else if (codec == CODEC_H264) { @@ -964,7 +754,7 @@ index 7543d68b6f750..0ec7fa2ec43d0 100644 FF_PROFILE_H264_CONSTRAINED_BASELINE); obs_property_list_add_int(list, "Main", FF_PROFILE_H264_MAIN); obs_property_list_add_int(list, "High", FF_PROFILE_H264_HIGH); -@@ -940,8 +934,7 @@ static obs_properties_t *vaapi_properties_internal(enum codec_type codec) +@@ -942,8 +936,7 @@ static obs_properties_t *vaapi_properties_internal(enum codec_type codec) if (codec == CODEC_H264) { obs_property_list_add_int(list, "3.0", 30); obs_property_list_add_int(list, "3.1", 31); @@ -974,7 +764,7 @@ index 7543d68b6f750..0ec7fa2ec43d0 100644 obs_property_list_add_int(list, "4.1", 41); obs_property_list_add_int(list, "4.2", 42); obs_property_list_add_int(list, "5.0", 50); -@@ -950,7 +943,7 @@ static obs_properties_t *vaapi_properties_internal(enum codec_type codec) +@@ -952,7 +945,7 @@ static obs_properties_t *vaapi_properties_internal(enum codec_type codec) } else if (codec == CODEC_HEVC) { obs_property_list_add_int(list, "3.0", 90); obs_property_list_add_int(list, "3.1", 93); @@ -983,7 +773,7 @@ index 7543d68b6f750..0ec7fa2ec43d0 100644 obs_property_list_add_int(list, "4.1", 123); obs_property_list_add_int(list, "5.0", 150); obs_property_list_add_int(list, "5.1", 153); -@@ -958,7 +951,7 @@ static obs_properties_t *vaapi_properties_internal(enum codec_type codec) +@@ -960,7 +953,7 @@ static obs_properties_t *vaapi_properties_internal(enum codec_type codec) } else if (codec == CODEC_AV1) { obs_property_list_add_int(list, "3.0", 4); obs_property_list_add_int(list, "3.1", 5); diff --git a/patches/0004-9475.patch b/patches/9475.patch similarity index 100% rename from patches/0004-9475.patch rename to patches/9475.patch diff --git a/patches/add-plugins.patch b/patches/add-plugins.patch new file mode 100644 index 0000000..f673dca --- /dev/null +++ b/patches/add-plugins.patch @@ -0,0 +1,14 @@ +diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt +index d20bce142..febeff6b7 100644 +--- a/plugins/CMakeLists.txt ++++ b/plugins/CMakeLists.txt +@@ -60,6 +60,9 @@ elseif(OS_LINUX) + add_subdirectory(vlc-video) + add_subdirectory(sndio) + add_subdirectory(obs-vst) ++ add_subdirectory(obs-source-record) ++ ++ + + check_obs_browser() + elseif(OS_FREEBSD) diff --git a/patches/0006-encoder-rename.patch b/patches/encoder-rename.patch similarity index 63% rename from patches/0006-encoder-rename.patch rename to patches/encoder-rename.patch index e9f5059..a356e3f 100644 --- a/patches/0006-encoder-rename.patch +++ b/patches/encoder-rename.patch @@ -4,34 +4,11 @@ Date: Sat, 29 Apr 2023 14:46:16 -0600 Subject: [PATCH] encoder rename --- - plugins/obs-ffmpeg/jim-nvenc.c | 4 ++-- plugins/obs-ffmpeg/obs-ffmpeg-av1.c | 4 ++-- plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c | 4 ++-- - plugins/obs-ffmpeg/texture-amf.cpp | 6 +++--- plugins/obs-x264/obs-x264.c | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) -diff --git a/plugins/obs-ffmpeg/jim-nvenc.c b/plugins/obs-ffmpeg/jim-nvenc.c -index 10a7dd1..c912205 100644 ---- a/plugins/obs-ffmpeg/jim-nvenc.c -+++ b/plugins/obs-ffmpeg/jim-nvenc.c -@@ -227,14 +227,14 @@ static void nv_texture_free(struct nvenc_data *enc, struct nv_texture *nvtex) - static const char *h264_nvenc_get_name(void *type_data) - { - UNUSED_PARAMETER(type_data); -- return "NVIDIA NVENC H.264"; -+ return "GPU: NVIDIA NVENC H.264 (FFmpeg)"; - } - - #ifdef ENABLE_HEVC - static const char *hevc_nvenc_get_name(void *type_data) - { - UNUSED_PARAMETER(type_data); -- return "NVIDIA NVENC HEVC"; -+ return "GPU: NVIDIA NVENC H.265/HEVC (FFmpeg)"; - } - #endif - diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-av1.c b/plugins/obs-ffmpeg/obs-ffmpeg-av1.c index 0b671ae..681f728 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-av1.c @@ -74,37 +51,6 @@ index 8cd8138..add8e02 100644 static const char *hevc_nvenc_getname(void *unused) { UNUSED_PARAMETER(unused); -diff --git a/plugins/obs-ffmpeg/texture-amf.cpp b/plugins/obs-ffmpeg/texture-amf.cpp -index 0f5ee7b..e350257 100644 ---- a/plugins/obs-ffmpeg/texture-amf.cpp -+++ b/plugins/obs-ffmpeg/texture-amf.cpp -@@ -2101,7 +2101,7 @@ static obs_properties_t *amf_av1_properties(void *unused) - - static const char *amf_avc_get_name(void *) - { -- return "AMD HW H.264 (AVC)"; -+ return "GPU: AMD AMF H.264 (FFmpeg)"; - } - - static inline int get_avc_preset(amf_base *enc, const char *preset) -@@ -2443,7 +2443,7 @@ static void register_avc() - - static const char *amf_hevc_get_name(void *) - { -- return "AMD HW H.265 (HEVC)"; -+ return "GPU: AMD AMF H.265/HEVC (FFmpeg)"; - } - - static inline int get_hevc_preset(amf_base *enc, const char *preset) -@@ -2788,7 +2788,7 @@ static void register_hevc() - - static const char *amf_av1_get_name(void *) - { -- return "AMD HW AV1"; -+ return "GPU: AMD AMF AV1 (FFmpeg)"; - } - - static inline int get_av1_preset(amf_base *enc, const char *preset) diff --git a/plugins/obs-x264/obs-x264.c b/plugins/obs-x264/obs-x264.c index 1de88d3..d4c377d 100644 --- a/plugins/obs-x264/obs-x264.c diff --git a/patches/obs-studio-30-cmake-3.20.patch b/patches/obs-studio-30-cmake-3.20.patch new file mode 100644 index 0000000..bac02da --- /dev/null +++ b/patches/obs-studio-30-cmake-3.20.patch @@ -0,0 +1,423 @@ +From 09fbac02fa36e945480edb1cf8547ba8ce4d08ff Mon Sep 17 00:00:00 2001 +From: Neal Gompa +Date: Mon, 11 Sep 2023 15:50:55 -0400 +Subject: [PATCH] cmake: Allow CMake 3.20 and 3.21 to be used to build OBS + +CentOS Stream 9 (and thus Red Hat Enterprise Linux 9) have CMake 3.20. + +There does not appear to be anything preventing it from building +on CMake 3.20, so let's permit it so that it can still be built +for Fedora Extra Packages for Enterprise Linux 9. +--- + CMakeLists.txt | 2 +- + UI/CMakeLists.txt | 2 +- + UI/frontend-plugins/aja-output-ui/CMakeLists.txt | 2 +- + UI/frontend-plugins/decklink-captions/CMakeLists.txt | 2 +- + UI/frontend-plugins/decklink-output-ui/CMakeLists.txt | 2 +- + UI/frontend-plugins/frontend-tools/CMakeLists.txt | 2 +- + UI/obs-frontend-api/CMakeLists.txt | 2 +- + deps/blake2/CMakeLists.txt | 2 +- + deps/file-updater/CMakeLists.txt | 2 +- + deps/glad/CMakeLists.txt | 2 +- + deps/happy-eyeballs/CMakeLists.txt | 2 +- + deps/json11/CMakeLists.txt | 2 +- + deps/libcaption/CMakeLists.txt | 2 +- + deps/media-playback/CMakeLists.txt | 2 +- + deps/obs-scripting/CMakeLists.txt | 2 +- + deps/obs-scripting/obslua/CMakeLists.txt | 2 +- + deps/obs-scripting/obspython/CMakeLists.txt | 2 +- + deps/opts-parser/CMakeLists.txt | 2 +- + deps/uthash/CMakeLists.txt | 2 +- + libobs-opengl/CMakeLists.txt | 2 +- + libobs/CMakeLists.txt | 2 +- + plugins/CMakeLists.txt | 2 +- + plugins/aja/CMakeLists.txt | 2 +- + plugins/decklink/CMakeLists.txt | 2 +- + plugins/image-source/CMakeLists.txt | 2 +- + plugins/obs-ffmpeg/CMakeLists.txt | 2 +- + plugins/obs-ffmpeg/ffmpeg-mux/CMakeLists.txt | 2 +- + plugins/obs-filters/CMakeLists.txt | 2 +- + plugins/obs-outputs/CMakeLists.txt | 2 +- + plugins/obs-qsv11/CMakeLists.txt | 2 +- + plugins/obs-transitions/CMakeLists.txt | 2 +- + plugins/obs-vst/CMakeLists.txt | 2 +- + plugins/obs-webrtc/CMakeLists.txt | 2 +- + plugins/obs-x264/CMakeLists.txt | 2 +- + plugins/rtmp-services/CMakeLists.txt | 2 +- + plugins/text-freetype2/CMakeLists.txt | 2 +- + plugins/vlc-video/CMakeLists.txt | 2 +- + 37 files changed, 37 insertions(+), 37 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index b6f157fbe..3e628c792 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + if(CMAKE_HOST_SYSTEM_NAME MATCHES "(Darwin)" OR OBS_CMAKE_VERSION VERSION_GREATER_EQUAL 3.0.0) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/bootstrap.cmake" NO_POLICY_SCOPE) +diff --git a/UI/CMakeLists.txt b/UI/CMakeLists.txt +index cbebcd84d..b5660e662 100644 +--- a/UI/CMakeLists.txt ++++ b/UI/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/UI/frontend-plugins/aja-output-ui/CMakeLists.txt b/UI/frontend-plugins/aja-output-ui/CMakeLists.txt +index 3555192e6..e9b9ed0ba 100644 +--- a/UI/frontend-plugins/aja-output-ui/CMakeLists.txt ++++ b/UI/frontend-plugins/aja-output-ui/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/UI/frontend-plugins/decklink-captions/CMakeLists.txt b/UI/frontend-plugins/decklink-captions/CMakeLists.txt +index 3fc910b6c..0969dd7b0 100644 +--- a/UI/frontend-plugins/decklink-captions/CMakeLists.txt ++++ b/UI/frontend-plugins/decklink-captions/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/UI/frontend-plugins/decklink-output-ui/CMakeLists.txt b/UI/frontend-plugins/decklink-output-ui/CMakeLists.txt +index a5e697e88..1fc0af541 100644 +--- a/UI/frontend-plugins/decklink-output-ui/CMakeLists.txt ++++ b/UI/frontend-plugins/decklink-output-ui/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/UI/frontend-plugins/frontend-tools/CMakeLists.txt b/UI/frontend-plugins/frontend-tools/CMakeLists.txt +index 5a0eeba45..b29d335a3 100644 +--- a/UI/frontend-plugins/frontend-tools/CMakeLists.txt ++++ b/UI/frontend-plugins/frontend-tools/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/UI/obs-frontend-api/CMakeLists.txt b/UI/obs-frontend-api/CMakeLists.txt +index ca4eae513..fd7c9433b 100644 +--- a/UI/obs-frontend-api/CMakeLists.txt ++++ b/UI/obs-frontend-api/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/deps/blake2/CMakeLists.txt b/deps/blake2/CMakeLists.txt +index b9fb338a8..6e31ec857 100644 +--- a/deps/blake2/CMakeLists.txt ++++ b/deps/blake2/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + add_library(blake2 STATIC EXCLUDE_FROM_ALL ) + add_library(OBS::blake2 ALIAS blake2) +diff --git a/deps/file-updater/CMakeLists.txt b/deps/file-updater/CMakeLists.txt +index e07cd2f0f..fbb358110 100644 +--- a/deps/file-updater/CMakeLists.txt ++++ b/deps/file-updater/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + find_package(CURL REQUIRED) + +diff --git a/deps/glad/CMakeLists.txt b/deps/glad/CMakeLists.txt +index 64b05a2cc..c6d7ea19c 100644 +--- a/deps/glad/CMakeLists.txt ++++ b/deps/glad/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + find_package(OpenGL REQUIRED) + +diff --git a/deps/happy-eyeballs/CMakeLists.txt b/deps/happy-eyeballs/CMakeLists.txt +index b3a5692cd..ff3be48ff 100644 +--- a/deps/happy-eyeballs/CMakeLists.txt ++++ b/deps/happy-eyeballs/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + add_library(happy-eyeballs INTERFACE) + add_library(OBS::happy-eyeballs ALIAS happy-eyeballs) +diff --git a/deps/json11/CMakeLists.txt b/deps/json11/CMakeLists.txt +index 78cb7c94a..82d0a063b 100644 +--- a/deps/json11/CMakeLists.txt ++++ b/deps/json11/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + add_library(json11 INTERFACE) + add_library(OBS::json11 ALIAS json11) +diff --git a/deps/libcaption/CMakeLists.txt b/deps/libcaption/CMakeLists.txt +index 53cd79196..2770b6746 100644 +--- a/deps/libcaption/CMakeLists.txt ++++ b/deps/libcaption/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + add_library(caption STATIC EXCLUDE_FROM_ALL ) + add_library(OBS::caption ALIAS caption) +diff --git a/deps/media-playback/CMakeLists.txt b/deps/media-playback/CMakeLists.txt +index a84900e47..351f4bb42 100644 +--- a/deps/media-playback/CMakeLists.txt ++++ b/deps/media-playback/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + find_package(FFmpeg REQUIRED COMPONENTS avcodec avdevice avutil avformat) + +diff --git a/deps/obs-scripting/CMakeLists.txt b/deps/obs-scripting/CMakeLists.txt +index 9096e4b27..988d2235c 100644 +--- a/deps/obs-scripting/CMakeLists.txt ++++ b/deps/obs-scripting/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/deps/obs-scripting/obslua/CMakeLists.txt b/deps/obs-scripting/obslua/CMakeLists.txt +index 98517ee7d..22edd1e1c 100644 +--- a/deps/obs-scripting/obslua/CMakeLists.txt ++++ b/deps/obs-scripting/obslua/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/deps/obs-scripting/obspython/CMakeLists.txt b/deps/obs-scripting/obspython/CMakeLists.txt +index f0db72f75..f0a07f66c 100644 +--- a/deps/obs-scripting/obspython/CMakeLists.txt ++++ b/deps/obs-scripting/obspython/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/deps/opts-parser/CMakeLists.txt b/deps/opts-parser/CMakeLists.txt +index a87ee641e..72d61be53 100644 +--- a/deps/opts-parser/CMakeLists.txt ++++ b/deps/opts-parser/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + add_library(opts-parser INTERFACE) + add_library(OBS::opts-parser ALIAS opts-parser) +diff --git a/deps/uthash/CMakeLists.txt b/deps/uthash/CMakeLists.txt +index aecb0d74e..7ebb524f0 100644 +--- a/deps/uthash/CMakeLists.txt ++++ b/deps/uthash/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + add_library(uthash INTERFACE) + add_library(OBS::uthash ALIAS uthash) +diff --git a/libobs-opengl/CMakeLists.txt b/libobs-opengl/CMakeLists.txt +index 7ee9478ea..51751719d 100644 +--- a/libobs-opengl/CMakeLists.txt ++++ b/libobs-opengl/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/libobs/CMakeLists.txt b/libobs/CMakeLists.txt +index 46112abe7..28551f61d 100644 +--- a/libobs/CMakeLists.txt ++++ b/libobs/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt +index 90bea35be..26e6b57ec 100644 +--- a/plugins/CMakeLists.txt ++++ b/plugins/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + option(ENABLE_PLUGINS "Enable building OBS plugins" ON) + +diff --git a/plugins/aja/CMakeLists.txt b/plugins/aja/CMakeLists.txt +index 423d9d099..daaa57f51 100644 +--- a/plugins/aja/CMakeLists.txt ++++ b/plugins/aja/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/plugins/decklink/CMakeLists.txt b/plugins/decklink/CMakeLists.txt +index e93c7c772..8423fe52a 100644 +--- a/plugins/decklink/CMakeLists.txt ++++ b/plugins/decklink/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/plugins/image-source/CMakeLists.txt b/plugins/image-source/CMakeLists.txt +index a7682454e..2f5fd3790 100644 +--- a/plugins/image-source/CMakeLists.txt ++++ b/plugins/image-source/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/plugins/obs-ffmpeg/CMakeLists.txt b/plugins/obs-ffmpeg/CMakeLists.txt +index 04530ef39..16c4d1e1a 100644 +--- a/plugins/obs-ffmpeg/CMakeLists.txt ++++ b/plugins/obs-ffmpeg/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/plugins/obs-ffmpeg/ffmpeg-mux/CMakeLists.txt b/plugins/obs-ffmpeg/ffmpeg-mux/CMakeLists.txt +index afa22b7a5..5644f8213 100644 +--- a/plugins/obs-ffmpeg/ffmpeg-mux/CMakeLists.txt ++++ b/plugins/obs-ffmpeg/ffmpeg-mux/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/plugins/obs-filters/CMakeLists.txt b/plugins/obs-filters/CMakeLists.txt +index 22d79388c..84b337c40 100644 +--- a/plugins/obs-filters/CMakeLists.txt ++++ b/plugins/obs-filters/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/plugins/obs-outputs/CMakeLists.txt b/plugins/obs-outputs/CMakeLists.txt +index cedc77da0..f131ca671 100644 +--- a/plugins/obs-outputs/CMakeLists.txt ++++ b/plugins/obs-outputs/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/plugins/obs-qsv11/CMakeLists.txt b/plugins/obs-qsv11/CMakeLists.txt +index cae152765..f1c39cc6a 100644 +--- a/plugins/obs-qsv11/CMakeLists.txt ++++ b/plugins/obs-qsv11/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/plugins/obs-transitions/CMakeLists.txt b/plugins/obs-transitions/CMakeLists.txt +index 65e3b13ac..c18ac96ed 100644 +--- a/plugins/obs-transitions/CMakeLists.txt ++++ b/plugins/obs-transitions/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/plugins/obs-vst/CMakeLists.txt b/plugins/obs-vst/CMakeLists.txt +index bb5c32a00..78530783b 100644 +--- a/plugins/obs-vst/CMakeLists.txt ++++ b/plugins/obs-vst/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/plugins/obs-webrtc/CMakeLists.txt b/plugins/obs-webrtc/CMakeLists.txt +index de943062f..84b0f1aa5 100644 +--- a/plugins/obs-webrtc/CMakeLists.txt ++++ b/plugins/obs-webrtc/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/plugins/obs-x264/CMakeLists.txt b/plugins/obs-x264/CMakeLists.txt +index 4c293fb33..c75491a51 100644 +--- a/plugins/obs-x264/CMakeLists.txt ++++ b/plugins/obs-x264/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/plugins/rtmp-services/CMakeLists.txt b/plugins/rtmp-services/CMakeLists.txt +index e8d304ae0..9dc0b2396 100644 +--- a/plugins/rtmp-services/CMakeLists.txt ++++ b/plugins/rtmp-services/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/plugins/text-freetype2/CMakeLists.txt b/plugins/text-freetype2/CMakeLists.txt +index bb30f99a7..b19b0cd57 100644 +--- a/plugins/text-freetype2/CMakeLists.txt ++++ b/plugins/text-freetype2/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +diff --git a/plugins/vlc-video/CMakeLists.txt b/plugins/vlc-video/CMakeLists.txt +index 0a35ae284..40a62b076 100644 +--- a/plugins/vlc-video/CMakeLists.txt ++++ b/plugins/vlc-video/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.22...3.25) ++cmake_minimum_required(VERSION 3.20...3.25) + + legacy_check() + +-- +2.41.0 + diff --git a/patches/obs-studio-UI-use-fdk-aac-by-default.patch b/patches/obs-studio-UI-use-fdk-aac-by-default.patch new file mode 100644 index 0000000..5f9d1e1 --- /dev/null +++ b/patches/obs-studio-UI-use-fdk-aac-by-default.patch @@ -0,0 +1,36 @@ +From 841fd01b7a529b7c1d0e0a509190a26eb1220d5a Mon Sep 17 00:00:00 2001 +From: Neal Gompa +Date: Thu, 4 May 2023 13:52:01 -0400 +Subject: [PATCH] UI: Default to fdk-aac for AAC when auto-configuring settings + +We always have the FDK-AAC codec available, and it's a better +codec anyway. +--- + UI/window-basic-auto-config-test.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/UI/window-basic-auto-config-test.cpp b/UI/window-basic-auto-config-test.cpp +index c791c8b8b..7dabfd93f 100644 +--- a/UI/window-basic-auto-config-test.cpp ++++ b/UI/window-basic-auto-config-test.cpp +@@ -202,7 +202,7 @@ void AutoConfigTestPage::TestBandwidthThread() + (wiz->x264Available ? "obs_x264" : "ffmpeg_openh264"), + "test_h264", nullptr, nullptr); + OBSEncoderAutoRelease aencoder = obs_audio_encoder_create( +- "ffmpeg_aac", "test_aac", nullptr, 0, nullptr); ++ "libfdk_aac", "test_aac", nullptr, 0, nullptr); + OBSServiceAutoRelease service = obs_service_create( + serverType, "test_service", nullptr, nullptr); + +@@ -572,7 +572,7 @@ bool AutoConfigTestPage::TestSoftwareEncoding() + (wiz->x264Available ? "obs_x264" : "ffmpeg_openh264"), + "test_h264", nullptr, nullptr); + OBSEncoderAutoRelease aencoder = obs_audio_encoder_create( +- "ffmpeg_aac", "test_aac", nullptr, 0, nullptr); ++ "libfdk_aac", "test_aac", nullptr, 0, nullptr); + OBSOutputAutoRelease output = + obs_output_create("null_output", "null", nullptr, nullptr); + +-- +2.40.0 + diff --git a/patches/obs-studio-deps-Add-license-declaration-files.patch b/patches/obs-studio-deps-Add-license-declaration-files.patch new file mode 100644 index 0000000..d1e460c --- /dev/null +++ b/patches/obs-studio-deps-Add-license-declaration-files.patch @@ -0,0 +1,218 @@ +From b6be0b4bf5b0b2f26c8143641881cde23ac8ba9c Mon Sep 17 00:00:00 2001 +From: Neal Gompa +Date: Wed, 26 Apr 2023 07:56:35 -0400 +Subject: [PATCH 1/2] deps: Add license declaration files + +--- + deps/blake2/LICENSE.blake2 | 19 ++++++++++ + deps/libff/LICENSE.libff | 18 ++++++++++ + deps/media-playback/LICENSE.media-playback | 19 ++++++++++ + libobs/graphics/libnsgif/LICENSE.libnsgif | 33 ++++++++++++++++++ + libobs/util/simde/LICENSE.simde | 40 ++++++++++++++++++++++ + plugins/decklink/LICENSE.decklink-sdk | 30 ++++++++++++++++ + 6 files changed, 159 insertions(+) + create mode 100644 deps/blake2/LICENSE.blake2 + create mode 100644 deps/libff/LICENSE.libff + create mode 100644 deps/media-playback/LICENSE.media-playback + create mode 100644 libobs/graphics/libnsgif/LICENSE.libnsgif + create mode 100644 libobs/util/simde/LICENSE.simde + create mode 100644 plugins/decklink/LICENSE.decklink-sdk + +diff --git a/deps/blake2/LICENSE.blake2 b/deps/blake2/LICENSE.blake2 +new file mode 100644 +index 000000000..3a8abc787 +--- /dev/null ++++ b/deps/blake2/LICENSE.blake2 +@@ -0,0 +1,19 @@ ++BLAKE2 is licensed to permit usage under the terms of the CC0, the OpenSSL License, ++ or the Apache Public License 2.0 at the user's option. ++ ++The license grant is reproduced in full below. ++ ++/* ++ BLAKE2 reference source code package - reference C implementations ++ ++ Copyright 2012, Samuel Neves . You may use this under the ++ terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at ++ your option. The terms of these licenses can be found at: ++ ++ - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 ++ - OpenSSL license : https://www.openssl.org/source/license.html ++ - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 ++ ++ More information about the BLAKE2 hash function can be found at ++ https://blake2.net. ++*/ +diff --git a/deps/libff/LICENSE.libff b/deps/libff/LICENSE.libff +new file mode 100644 +index 000000000..b6f51157a +--- /dev/null ++++ b/deps/libff/LICENSE.libff +@@ -0,0 +1,18 @@ ++libff is licensed under the ISC license. The license terms are fully ++reproduced below: ++ ++/* ++ * Copyright (c) 2015 John R. Bradley ++ * ++ * Permission to use, copy, modify, and distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ +diff --git a/deps/media-playback/LICENSE.media-playback b/deps/media-playback/LICENSE.media-playback +new file mode 100644 +index 000000000..17d74f4b3 +--- /dev/null ++++ b/deps/media-playback/LICENSE.media-playback +@@ -0,0 +1,19 @@ ++media-playback is licensed under the ISC license. The license terms are fully ++reproduced below: ++ ++ ++/* ++ * Copyright (c) 2023 Hugh Bailey ++ * ++ * Permission to use, copy, modify, and distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ +diff --git a/libobs/graphics/libnsgif/LICENSE.libnsgif b/libobs/graphics/libnsgif/LICENSE.libnsgif +new file mode 100644 +index 000000000..9b28c0b45 +--- /dev/null ++++ b/libobs/graphics/libnsgif/LICENSE.libnsgif +@@ -0,0 +1,33 @@ ++libnsgif is licensed under the MIT license. The licensing statement ++and the full license are reproduced below. ++ ++/* ++ * Copyright 2003 James Bursa ++ * Copyright 2004 John Tytgat ++ * Copyright 2004 Richard Wilson ++ * Copyright 2008 Sean Fox ++ * ++ * This file is part of NetSurf's libnsgif, http://www.netsurf-browser.org/ ++ * Licenced under the MIT License, ++ * http://www.opensource.org/licenses/mit-license.php ++ */ ++ ++The MIT License ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in ++all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++THE SOFTWARE. +diff --git a/libobs/util/simde/LICENSE.simde b/libobs/util/simde/LICENSE.simde +new file mode 100644 +index 000000000..78d482e75 +--- /dev/null ++++ b/libobs/util/simde/LICENSE.simde +@@ -0,0 +1,40 @@ ++simde is licensed as a combination of MIT and CC0 code. ++ ++License notices for both are reproduced below: ++ ++/* SPDX-License-Identifier: MIT ++ * ++ * Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, ++ * modify, merge, publish, distribute, sublicense, and/or sell copies ++ * of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ * ++ * Copyright: ++ * 2017-2020 Evan Nemerson ++ */ ++ ++/* Portable Snippets - https://gitub.com/nemequ/portable-snippets ++ * Created by Evan Nemerson ++ * ++ * To the extent possible under law, the authors have waived all ++ * copyright and related or neighboring rights to this code. For ++ * details, see the Creative Commons Zero 1.0 Universal license at ++ * https://creativecommons.org/publicdomain/zero/1.0/ ++ * ++ * SPDX-License-Identifier: CC0-1.0 ++ */ +diff --git a/plugins/decklink/LICENSE.decklink-sdk b/plugins/decklink/LICENSE.decklink-sdk +new file mode 100644 +index 000000000..d320d805b +--- /dev/null ++++ b/plugins/decklink/LICENSE.decklink-sdk +@@ -0,0 +1,30 @@ ++decklink-sdk is licensed under to Boost Software License 1.0 (BSL-1.0). ++ ++The license text is reproduced in full below: ++ ++/* -LICENSE-START- ++** Copyright (c) 2020 Blackmagic Design ++** ++** Permission is hereby granted, free of charge, to any person or organization ++** obtaining a copy of the software and accompanying documentation covered by ++** this license (the "Software") to use, reproduce, display, distribute, ++** execute, and transmit the Software, and to prepare derivative works of the ++** Software, and to permit third-parties to whom the Software is furnished to ++** do so, all subject to the following: ++** ++** The copyright notices in the Software and this entire statement, including ++** the above license grant, this restriction and the following disclaimer, ++** must be included in all copies of the Software, in whole or in part, and ++** all derivative works of the Software, unless such copies or derivative ++** works are solely in the form of machine-executable object code generated by ++** a source language processor. ++** ++** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT ++** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE ++** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ++** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++** DEALINGS IN THE SOFTWARE. ++** -LICENSE-END- ++*/ +-- +2.40.0 +