obs-ffmpeg: Implement NVENC video card blacklist
This implements a blacklist of devices that ship with NVENC libraries, but do not support NVENC, which would cause the plugin to mistakenly think that NVENC was available when it was not. If these devices are the only NVIDIA devices on the system, consider NVENC unavailable. This is much more efficient than spawning an encoder on startup to see if NVENC is available, which would incur a ~500 millisecond hit on startup. Additionally, also much less crash-prone.
This commit is contained in:
@@ -7,6 +7,12 @@
|
||||
#include <libavformat/avformat.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <dxgi.h>
|
||||
#include <util/dstr.h>
|
||||
#include <util/windows/win-version.h>
|
||||
#endif
|
||||
|
||||
OBS_DECLARE_MODULE()
|
||||
OBS_MODULE_USE_DEFAULT_LOCALE("obs-ffmpeg", "en-US")
|
||||
MODULE_EXPORT const char *obs_module_description(void)
|
||||
@@ -134,6 +140,89 @@ cleanup:
|
||||
|
||||
static const char *nvenc_check_name = "nvenc_check";
|
||||
|
||||
#ifdef _WIN32
|
||||
static const wchar_t *blacklisted_adapters[] = {
|
||||
L"920M",
|
||||
L"940M",
|
||||
L"820M",
|
||||
L"840M",
|
||||
L"1030",
|
||||
L"MX130"
|
||||
};
|
||||
|
||||
static const size_t num_blacklisted =
|
||||
sizeof(blacklisted_adapters) / sizeof(blacklisted_adapters[0]);
|
||||
|
||||
static bool is_blacklisted(const wchar_t *name)
|
||||
{
|
||||
for (size_t i = 0; i < num_blacklisted; i++) {
|
||||
const wchar_t *blacklisted_adapter = blacklisted_adapters[i];
|
||||
if (wstrstri(blacklisted_adapter, name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef HRESULT (*create_dxgi_proc)(const IID *, IDXGIFactory1 **);
|
||||
|
||||
static bool nvenc_device_available(void)
|
||||
{
|
||||
static HMODULE dxgi = NULL;
|
||||
static create_dxgi_proc create = NULL;
|
||||
IDXGIFactory1 *factory;
|
||||
IDXGIAdapter1 *adapter;
|
||||
bool available = false;
|
||||
HRESULT hr;
|
||||
UINT i = 0;
|
||||
|
||||
if (!dxgi) {
|
||||
dxgi = GetModuleHandleW(L"dxgi");
|
||||
if (!dxgi) {
|
||||
dxgi = LoadLibraryW(L"dxgi");
|
||||
if (!dxgi) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!create) {
|
||||
create = (create_dxgi_proc)GetProcAddress(dxgi,
|
||||
"CreateDXGIFactory1");
|
||||
if (!create) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
hr = create(&IID_IDXGIFactory1, &factory);
|
||||
if (FAILED(hr)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
while (factory->lpVtbl->EnumAdapters1(factory, i++, &adapter) == S_OK) {
|
||||
DXGI_ADAPTER_DESC desc;
|
||||
|
||||
hr = adapter->lpVtbl->GetDesc(adapter, &desc);
|
||||
adapter->lpVtbl->Release(adapter);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wstrstri(desc.Description, L"nvidia") &&
|
||||
!is_blacklisted(desc.Description)) {
|
||||
available = true;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
factory->lpVtbl->Release(factory);
|
||||
return available;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool nvenc_supported(void)
|
||||
{
|
||||
av_register_all();
|
||||
@@ -149,6 +238,10 @@ static bool nvenc_supported(void)
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (!nvenc_device_available()) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (sizeof(void*) == 8) {
|
||||
lib = os_dlopen("nvEncodeAPI64.dll");
|
||||
} else {
|
||||
|
Reference in New Issue
Block a user