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:
jp9000
2019-02-05 00:33:48 -08:00
parent 8134b8afda
commit 0be02564cb

View File

@@ -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 {