Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mfplat/main.c | 248 +++++++++++++++++++++++++++++++++----
dlls/mfplat/tests/mfplat.c | 162 +++++++++++++++++++++++-
include/mfapi.h | 4 +
3 files changed, 386 insertions(+), 28 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c
index 452426d055f..68aa2cdaa2d 100644
--- a/dlls/mfplat/main.c
+++ b/dlls/mfplat/main.c
@@ -8556,12 +8556,29 @@ HRESULT WINAPI CreatePropertyStore(IPropertyStore **store)
return S_OK;
}
+enum dxgi_device_handle_flags
+{
+ DXGI_DEVICE_HANDLE_FLAG_OPEN = 0x1,
+ DXGI_DEVICE_HANDLE_FLAG_INVALID = 0x2,
+ DXGI_DEVICE_HANDLE_FLAG_LOCKED = 0x4,
+};
+
struct dxgi_device_manager
{
IMFDXGIDeviceManager IMFDXGIDeviceManager_iface;
LONG refcount;
UINT token;
IDXGIDevice *device;
+
+ unsigned int *handles;
+ size_t count;
+ size_t capacity;
+
+ unsigned int locks;
+ unsigned int locking_tid;
+
+ CRITICAL_SECTION cs;
+ CONDITION_VARIABLE lock;
};
static struct dxgi_device_manager *impl_from_IMFDXGIDeviceManager(IMFDXGIDeviceManager *iface)
@@ -8569,6 +8586,14 @@ static struct dxgi_device_manager *impl_from_IMFDXGIDeviceManager(IMFDXGIDeviceM
return CONTAINING_RECORD(iface, struct dxgi_device_manager, IMFDXGIDeviceManager_iface);
}
+static HRESULT dxgi_device_manager_get_handle_index(struct dxgi_device_manager *manager, HANDLE hdevice, size_t *idx)
+{
+ if (!hdevice || hdevice > ULongToHandle(manager->count))
+ return E_HANDLE;
+ *idx = (ULONG_PTR)hdevice - 1;
+ return S_OK;
+}
+
static HRESULT WINAPI dxgi_device_manager_QueryInterface(IMFDXGIDeviceManager *iface, REFIID riid, void **obj)
{
TRACE("(%p, %s, %p).\n", iface, debugstr_guid(riid), obj);
@@ -8607,17 +8632,61 @@ static ULONG WINAPI dxgi_device_manager_Release(IMFDXGIDeviceManager *iface)
{
if (manager->device)
IDXGIDevice_Release(manager->device);
+ DeleteCriticalSection(&manager->cs);
+ heap_free(manager->handles);
heap_free(manager);
}
return refcount;
}
-static HRESULT WINAPI dxgi_device_manager_CloseDeviceHandle(IMFDXGIDeviceManager *iface, HANDLE device)
+static void dxgi_device_manager_lock_handle(struct dxgi_device_manager *manager, size_t idx)
{
- FIXME("(%p, %p): stub.\n", iface, device);
+ if (manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_LOCKED)
+ return;
- return E_NOTIMPL;
+ manager->handles[idx] |= DXGI_DEVICE_HANDLE_FLAG_LOCKED;
+ manager->locks++;
+}
+
+static void dxgi_device_manager_unlock_handle(struct dxgi_device_manager *manager, size_t idx)
+{
+ if (!(manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_LOCKED))
+ return;
+
+ manager->handles[idx] &= ~DXGI_DEVICE_HANDLE_FLAG_LOCKED;
+ if (!--manager->locks)
+ manager->locking_tid = 0;
+}
+
+static HRESULT WINAPI dxgi_device_manager_CloseDeviceHandle(IMFDXGIDeviceManager *iface, HANDLE hdevice)
+{
+ struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
+ HRESULT hr;
+ size_t idx;
+
+ TRACE("%p, %p.\n", iface, hdevice);
+
+ EnterCriticalSection(&manager->cs);
+
+ if (SUCCEEDED(hr = dxgi_device_manager_get_handle_index(manager, hdevice, &idx)))
+ {
+ if (manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_OPEN)
+ {
+ dxgi_device_manager_unlock_handle(manager, idx);
+ manager->handles[idx] = 0;
+ if (idx == manager->count - 1)
+ manager->count--;
+ }
+ else
+ hr = E_HANDLE;
+ }
+
+ LeaveCriticalSection(&manager->cs);
+
+ WakeAllConditionVariable(&manager->lock);
+
+ return hr;
}
static HRESULT WINAPI dxgi_device_manager_GetVideoService(IMFDXGIDeviceManager *iface, HANDLE device,
@@ -8628,57 +8697,180 @@ static HRESULT WINAPI dxgi_device_manager_GetVideoService(IMFDXGIDeviceManager *
return E_NOTIMPL;
}
-static HRESULT WINAPI dxgi_device_manager_LockDevice(IMFDXGIDeviceManager *iface, HANDLE device,
- REFIID riid, void **ppv, BOOL block)
+static HRESULT WINAPI dxgi_device_manager_LockDevice(IMFDXGIDeviceManager *iface, HANDLE hdevice,
+ REFIID riid, void **obj, BOOL block)
{
- FIXME("(%p, %p, %s, %p, %d): stub.\n", iface, device, wine_dbgstr_guid(riid), ppv, block);
+ struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
+ HRESULT hr;
+ size_t idx;
- return E_NOTIMPL;
+ TRACE("%p, %p, %s, %p, %d.\n", iface, hdevice, wine_dbgstr_guid(riid), obj, block);
+
+ EnterCriticalSection(&manager->cs);
+
+ if (SUCCEEDED(hr = dxgi_device_manager_get_handle_index(manager, hdevice, &idx)))
+ {
+ if (!manager->device)
+ {
+ hr = MF_E_DXGI_DEVICE_NOT_INITIALIZED;
+ }
+ else if (manager->locking_tid == GetCurrentThreadId())
+ {
+ if (SUCCEEDED(hr = IDXGIDevice_QueryInterface(manager->device, riid, obj)))
+ dxgi_device_manager_lock_handle(manager, idx);
+ }
+ else if (manager->locking_tid && !block)
+ {
+ hr = MF_E_DXGI_VIDEO_DEVICE_LOCKED;
+ }
+ else
+ {
+ while (manager->locking_tid)
+ {
+ SleepConditionVariableCS(&manager->lock, &manager->cs, INFINITE);
+ }
+
+ if (SUCCEEDED(hr = dxgi_device_manager_get_handle_index(manager, hdevice, &idx)))
+ {
+ if (manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_INVALID)
+ hr = MF_E_DXGI_NEW_VIDEO_DEVICE;
+ else if (SUCCEEDED(hr = IDXGIDevice_QueryInterface(manager->device, riid, obj)))
+ {
+ manager->locking_tid = GetCurrentThreadId();
+ dxgi_device_manager_lock_handle(manager, idx);
+ }
+ }
+ }
+ }
+
+ LeaveCriticalSection(&manager->cs);
+
+ return hr;
}
-static HRESULT WINAPI dxgi_device_manager_OpenDeviceHandle(IMFDXGIDeviceManager *iface, HANDLE *device)
+static HRESULT WINAPI dxgi_device_manager_OpenDeviceHandle(IMFDXGIDeviceManager *iface, HANDLE *hdevice)
{
- FIXME("(%p, %p): stub.\n", iface, device);
+ struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
+ HRESULT hr = S_OK;
+ size_t i;
- return E_NOTIMPL;
+ TRACE("%p, %p.\n", iface, hdevice);
+
+ *hdevice = NULL;
+
+ EnterCriticalSection(&manager->cs);
+
+ if (!manager->device)
+ hr = MF_E_DXGI_DEVICE_NOT_INITIALIZED;
+ else
+ {
+ for (i = 0; i < manager->count; ++i)
+ {
+ if (!(manager->handles[i] & DXGI_DEVICE_HANDLE_FLAG_OPEN))
+ {
+ manager->handles[i] |= DXGI_DEVICE_HANDLE_FLAG_OPEN;
+ *hdevice = ULongToHandle(i + 1);
+ break;
+ }
+ }
+
+ if (mf_array_reserve((void **)&manager->handles, &manager->capacity, manager->count + 1,
+ sizeof(*manager->handles)))
+ {
+ *hdevice = ULongToHandle(manager->count + 1);
+ manager->handles[manager->count++] = DXGI_DEVICE_HANDLE_FLAG_OPEN;
+ }
+ else
+ hr = E_OUTOFMEMORY;
+ }
+
+ LeaveCriticalSection(&manager->cs);
+
+ return hr;
}
static HRESULT WINAPI dxgi_device_manager_ResetDevice(IMFDXGIDeviceManager *iface, IUnknown *device, UINT token)
{
struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
IDXGIDevice *dxgi_device;
- HRESULT hr;
+ size_t i;
- TRACE("(%p, %p, %u).\n", iface, device, token);
+ TRACE("%p, %p, %u.\n", iface, device, token);
if (!device || token != manager->token)
return E_INVALIDARG;
- hr = IUnknown_QueryInterface(device, &IID_IDXGIDevice, (void **)&dxgi_device);
- if (SUCCEEDED(hr))
+ if (FAILED(IUnknown_QueryInterface(device, &IID_IDXGIDevice, (void **)&dxgi_device)))
+ return E_INVALIDARG;
+
+ EnterCriticalSection(&manager->cs);
+
+ if (manager->device)
{
- if (manager->device)
- IDXGIDevice_Release(manager->device);
- manager->device = dxgi_device;
+ for (i = 0; i < manager->count; ++i)
+ {
+ manager->handles[i] |= DXGI_DEVICE_HANDLE_FLAG_INVALID;
+ manager->handles[i] &= ~DXGI_DEVICE_HANDLE_FLAG_LOCKED;
+ }
+ manager->locking_tid = 0;
+ manager->locks = 0;
+ IDXGIDevice_Release(manager->device);
}
- else
- hr = E_INVALIDARG;
+ manager->device = dxgi_device;
- return hr;
+ LeaveCriticalSection(&manager->cs);
+
+ WakeAllConditionVariable(&manager->lock);
+
+ return S_OK;
}
-static HRESULT WINAPI dxgi_device_manager_TestDevice(IMFDXGIDeviceManager *iface, HANDLE device)
+static HRESULT WINAPI dxgi_device_manager_TestDevice(IMFDXGIDeviceManager *iface, HANDLE hdevice)
{
- FIXME("(%p, %p): stub.\n", iface, device);
+ struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
+ HRESULT hr;
+ size_t idx;
- return E_NOTIMPL;
+ TRACE("%p, %p.\n", iface, hdevice);
+
+ EnterCriticalSection(&manager->cs);
+
+ if (SUCCEEDED(hr = dxgi_device_manager_get_handle_index(manager, hdevice, &idx)))
+ {
+ if (manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_INVALID)
+ hr = MF_E_DXGI_NEW_VIDEO_DEVICE;
+ else if (!(manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_OPEN))
+ hr = E_HANDLE;
+ }
+
+ LeaveCriticalSection(&manager->cs);
+
+ return hr;
}
-static HRESULT WINAPI dxgi_device_manager_UnlockDevice(IMFDXGIDeviceManager *iface, HANDLE device, BOOL state)
+static HRESULT WINAPI dxgi_device_manager_UnlockDevice(IMFDXGIDeviceManager *iface, HANDLE hdevice,
+ BOOL savestate)
{
- FIXME("(%p, %p, %d): stub.\n", iface, device, state);
+ struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface);
+ HRESULT hr = E_FAIL;
+ size_t idx;
- return E_NOTIMPL;
+ TRACE("%p, %p, %d.\n", iface, hdevice, savestate);
+
+ EnterCriticalSection(&manager->cs);
+
+ if (SUCCEEDED(dxgi_device_manager_get_handle_index(manager, hdevice, &idx)))
+ {
+ hr = manager->handles[idx] & DXGI_DEVICE_HANDLE_FLAG_LOCKED ? S_OK : E_INVALIDARG;
+ if (SUCCEEDED(hr))
+ dxgi_device_manager_unlock_handle(manager, idx);
+ }
+
+ LeaveCriticalSection(&manager->cs);
+
+ WakeAllConditionVariable(&manager->lock);
+
+ return hr;
}
static const IMFDXGIDeviceManagerVtbl dxgi_device_manager_vtbl =
@@ -8699,7 +8891,7 @@ HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **man
{
struct dxgi_device_manager *object;
- TRACE("(%p, %p).\n", token, manager);
+ TRACE("%p, %p.\n", token, manager);
if (!token || !manager)
return E_POINTER;
@@ -8712,6 +8904,8 @@ HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **man
object->refcount = 1;
object->token = GetTickCount();
object->device = NULL;
+ InitializeCriticalSection(&object->cs);
+ InitializeConditionVariable(&object->lock);
TRACE("Created device manager: %p, token: %u.\n", object, object->token);
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index a5388840bc5..c318c4364fb 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -4497,10 +4497,38 @@ if (0)
ok(!refcount, "Unexpected refcount %u.\n", refcount);
}
+struct test_thread_param
+{
+ IMFDXGIDeviceManager *manager;
+ HANDLE handle;
+ BOOL lock;
+};
+
+static DWORD WINAPI test_device_manager_thread(void *arg)
+{
+ struct test_thread_param *param = arg;
+ ID3D11Device *device;
+ HRESULT hr;
+
+ if (param->lock)
+ {
+ hr = IMFDXGIDeviceManager_LockDevice(param->manager, param->handle, &IID_ID3D11Device,
+ (void **)&device, FALSE);
+ if (SUCCEEDED(hr))
+ ID3D11Device_Release(device);
+ }
+ else
+ hr = IMFDXGIDeviceManager_UnlockDevice(param->manager, param->handle, FALSE);
+
+ return hr;
+}
+
static void test_dxgi_device_manager(void)
{
IMFDXGIDeviceManager *manager, *manager2;
- ID3D11Device *d3d11_dev, *d3d11_dev2;
+ ID3D11Device *device, *d3d11_dev, *d3d11_dev2;
+ struct test_thread_param param;
+ HANDLE handle1, handle, thread;
UINT token, token2;
HRESULT hr;
@@ -4532,6 +4560,18 @@ static void test_dxgi_device_manager(void)
ok(manager != manager2, "got wrong pointer: %p.\n", manager2);
EXPECT_REF(manager, 1);
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle);
+ ok(hr == MF_E_DXGI_DEVICE_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, 0);
+ ok(hr == E_HANDLE, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, 0, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == E_HANDLE, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, UlongToHandle(100), &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == E_HANDLE, "Unexpected hr %#x.\n", hr);
+
hr = pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT,
NULL, 0, D3D11_SDK_VERSION, &d3d11_dev, NULL, NULL);
ok(hr == S_OK, "D3D11CreateDevice failed: %#x.\n", hr);
@@ -4569,6 +4609,126 @@ static void test_dxgi_device_manager(void)
EXPECT_REF(d3d11_dev2, 2);
EXPECT_REF(d3d11_dev, 1);
+ handle = NULL;
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(!!handle, "Unexpected handle value %p.\n", handle);
+
+ handle1 = NULL;
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(handle != handle1, "Unexpected handle.\n");
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ /* Already closed. */
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle);
+ ok(hr == E_HANDLE, "Unexpected hr %#x.\n", hr);
+
+ handle = NULL;
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_TestDevice(manager, handle1);
+ ok(hr == E_HANDLE, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(device == d3d11_dev2, "Unexpected device pointer.\n");
+ ID3D11Device_Release(device);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle, FALSE);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, UlongToHandle(100), FALSE);
+ ok(hr == E_FAIL, "Unexpected hr %#x.\n", hr);
+
+ /* Locked with one handle, unlock with another. */
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle1, FALSE);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+ ID3D11Device_Release(device);
+
+ /* Closing unlocks the device. */
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle1, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ID3D11Device_Release(device);
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ /* Open two handles. */
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ID3D11Device_Release(device);
+
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle1, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ID3D11Device_Release(device);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle, FALSE);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+ param.manager = manager;
+ param.handle = handle;
+ param.lock = TRUE;
+ thread = CreateThread(NULL, 0, test_device_manager_thread, ¶m, 0, NULL);
+ ok(!WaitForSingleObject(thread, 1000), "Wait for a test thread failed.\n");
+ GetExitCodeThread(thread, (DWORD *)&hr);
+ ok(hr == MF_E_DXGI_VIDEO_DEVICE_LOCKED, "Unexpected hr %#x.\n", hr);
+ CloseHandle(thread);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle1, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_UnlockDevice(manager, handle1, FALSE);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+ /* Lock on main thread, unlock on another. */
+ hr = IMFDXGIDeviceManager_LockDevice(manager, handle, &IID_ID3D11Device, (void **)&device, FALSE);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ID3D11Device_Release(device);
+
+ param.manager = manager;
+ param.handle = handle;
+ param.lock = FALSE;
+ thread = CreateThread(NULL, 0, test_device_manager_thread, ¶m, 0, NULL);
+ ok(!WaitForSingleObject(thread, 1000), "Wait for a test thread failed.\n");
+ GetExitCodeThread(thread, (DWORD *)&hr);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ CloseHandle(thread);
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle1);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
IMFDXGIDeviceManager_Release(manager);
EXPECT_REF(d3d11_dev2, 1);
ID3D11Device_Release(d3d11_dev);
diff --git a/include/mfapi.h b/include/mfapi.h
index 499c77ab337..25fced1c7d6 100644
--- a/include/mfapi.h
+++ b/include/mfapi.h
@@ -482,6 +482,10 @@ typedef enum
#define MFSESSIONCAP_RATE_REVERSE 0x00000020
#define MFSESSIONCAP_DOES_NOT_USE_NETWORK 0x00000040
+#define MF_E_DXGI_DEVICE_NOT_INITIALIZED ((HRESULT)0x80041000)
+#define MF_E_DXGI_NEW_VIDEO_DEVICE ((HRESULT)0x80041001)
+#define MF_E_DXGI_VIDEO_DEVICE_LOCKED ((HRESULT)0x80041002)
+
HRESULT WINAPI MFAddPeriodicCallback(MFPERIODICCALLBACK callback, IUnknown *context, DWORD *key);
HRESULT WINAPI MFAllocateSerialWorkQueue(DWORD target_queue, DWORD *queue);
HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue);
--
2.28.0