Signed-off-by: Nikolay Sivov nsivov@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);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 28 ++++++++++++++++++++++++---- dlls/mfplat/tests/mfplat.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 4 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 68aa2cdaa2d..1c51fafff1e 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -8689,12 +8689,32 @@ static HRESULT WINAPI dxgi_device_manager_CloseDeviceHandle(IMFDXGIDeviceManager return hr; }
-static HRESULT WINAPI dxgi_device_manager_GetVideoService(IMFDXGIDeviceManager *iface, HANDLE device, - REFIID riid, void **service) +static HRESULT WINAPI dxgi_device_manager_GetVideoService(IMFDXGIDeviceManager *iface, HANDLE hdevice, + REFIID riid, void **service) { - FIXME("(%p, %p, %s, %p): stub.\n", iface, device, debugstr_guid(riid), service); + struct dxgi_device_manager *manager = impl_from_IMFDXGIDeviceManager(iface); + HRESULT hr; + size_t idx;
- return E_NOTIMPL; + TRACE("%p, %p, %s, %p.\n", iface, hdevice, debugstr_guid(riid), service); + + EnterCriticalSection(&manager->cs); + + if (!manager->device) + hr = MF_E_DXGI_DEVICE_NOT_INITIALIZED; + else 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 = IDXGIDevice_QueryInterface(manager->device, riid, service); + else + hr = E_HANDLE; + } + + LeaveCriticalSection(&manager->cs); + + return hr; }
static HRESULT WINAPI dxgi_device_manager_LockDevice(IMFDXGIDeviceManager *iface, HANDLE hdevice, diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index c318c4364fb..5b09d36f616 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -4530,6 +4530,7 @@ static void test_dxgi_device_manager(void) struct test_thread_param param; HANDLE handle1, handle, thread; UINT token, token2; + IUnknown *unk; HRESULT hr;
if (!pMFCreateDXGIDeviceManager) @@ -4560,6 +4561,9 @@ static void test_dxgi_device_manager(void) ok(manager != manager2, "got wrong pointer: %p.\n", manager2); EXPECT_REF(manager, 1);
+ hr = IMFDXGIDeviceManager_GetVideoService(manager, NULL, &IID_ID3D11Device, (void **)&unk); + ok(hr == MF_E_DXGI_DEVICE_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr); + hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle); ok(hr == MF_E_DXGI_DEVICE_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr);
@@ -4599,6 +4603,12 @@ static void test_dxgi_device_manager(void) EXPECT_REF(manager, 1); EXPECT_REF(d3d11_dev, 2);
+ /* GetVideoService() on device change. */ + handle = NULL; + hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!!handle, "Unexpected handle value %p.\n", handle); + hr = pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &d3d11_dev2, NULL, NULL); ok(hr == S_OK, "D3D11CreateDevice failed: %#x.\n", hr); @@ -4609,11 +4619,32 @@ static void test_dxgi_device_manager(void) EXPECT_REF(d3d11_dev2, 2); EXPECT_REF(d3d11_dev, 1);
+ hr = IMFDXGIDeviceManager_GetVideoService(manager, handle, &IID_ID3D11Device, (void **)&unk); + ok(hr == MF_E_DXGI_NEW_VIDEO_DEVICE, "Unexpected hr %#x.\n", hr); + + hr = IMFDXGIDeviceManager_CloseDeviceHandle(manager, handle); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + handle = NULL; hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle); ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(!!handle, "Unexpected handle value %p.\n", handle);
+ hr = IMFDXGIDeviceManager_GetVideoService(manager, NULL, &IID_ID3D11Device, (void **)&unk); + ok(hr == E_HANDLE, "Unexpected hr %#x.\n", hr); + + hr = IMFDXGIDeviceManager_GetVideoService(manager, handle, &IID_ID3D11Device, (void **)&unk); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + IUnknown_Release(unk); + + hr = IMFDXGIDeviceManager_GetVideoService(manager, handle, &IID_IUnknown, (void **)&unk); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + IUnknown_Release(unk); + + hr = IMFDXGIDeviceManager_GetVideoService(manager, handle, &IID_IDXGIDevice, (void **)&unk); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + IUnknown_Release(unk); + handle1 = NULL; hr = IMFDXGIDeviceManager_OpenDeviceHandle(manager, &handle1); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=80910
Your paranoid android.
=== w8 (32 bit report) ===
mfplat: mfplat.c:4574: Test failed: Unexpected hr 0x80041000. mfplat.c:4577: Test failed: Unexpected hr 0x80041000.
=== w8adm (32 bit report) ===
mfplat: mfplat.c:4574: Test failed: Unexpected hr 0x80041000. mfplat.c:4577: Test failed: Unexpected hr 0x80041000.
=== w1064v1507 (32 bit report) ===
mfplat: mfplat.c:4574: Test failed: Unexpected hr 0x80041000. mfplat.c:4577: Test failed: Unexpected hr 0x80041000.
=== w864 (64 bit report) ===
mfplat: mfplat.c:4574: Test failed: Unexpected hr 0x80041000. mfplat.c:4577: Test failed: Unexpected hr 0x80041000.
=== w1064v1507 (64 bit report) ===
mfplat: mfplat.c:4574: Test failed: Unexpected hr 0x80041000. mfplat.c:4577: Test failed: Unexpected hr 0x80041000.
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/main.c | 16 ++++++++++++++-- dlls/mf/tests/mf.c | 15 +++++++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/dlls/mf/main.c b/dlls/mf/main.c index 53264258137..c48fc81a1d2 100644 --- a/dlls/mf/main.c +++ b/dlls/mf/main.c @@ -1523,7 +1523,8 @@ static ULONG WINAPI sample_copier_transform_Release(IMFTransform *iface)
if (!refcount) { - IMFAttributes_Release(transform->attributes); + if (transform->attributes) + IMFAttributes_Release(transform->attributes); if (transform->buffer_type) IMFMediaType_Release(transform->buffer_type); DeleteCriticalSection(&transform->cs); @@ -1999,6 +2000,7 @@ static const IMFTransformVtbl sample_copier_transform_vtbl = HRESULT WINAPI MFCreateSampleCopierMFT(IMFTransform **transform) { struct sample_copier *object; + HRESULT hr;
TRACE("%p.\n", transform);
@@ -2008,10 +2010,20 @@ HRESULT WINAPI MFCreateSampleCopierMFT(IMFTransform **transform)
object->IMFTransform_iface.lpVtbl = &sample_copier_transform_vtbl; object->refcount = 1; - MFCreateAttributes(&object->attributes, 0); InitializeCriticalSection(&object->cs);
+ if (FAILED(hr = MFCreateAttributes(&object->attributes, 0))) + goto failed; + + IMFAttributes_SetUINT32(object->attributes, &MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, 1); + *transform = &object->IMFTransform_iface;
return S_OK; + +failed: + + IMFTransform_Release(&object->IMFTransform_iface); + + return hr; } diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 6699c1ca9d1..b110c0ec9ef 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -3660,6 +3660,7 @@ static BOOL is_sample_copier_available_type(IMFMediaType *type)
static void test_sample_copier(void) { + IMFAttributes *attributes, *attributes2; DWORD in_min, in_max, out_min, out_max; IMFMediaType *mediatype, *mediatype2; MFT_OUTPUT_STREAM_INFO output_info; @@ -3668,9 +3669,9 @@ static void test_sample_copier(void) DWORD input_count, output_count; MFT_OUTPUT_DATA_BUFFER buffer; IMFMediaBuffer *media_buffer; - IMFAttributes *attributes; + DWORD count, flags, status; IMFTransform *copier; - DWORD flags, status; + UINT32 value; HRESULT hr;
hr = MFCreateSampleCopierMFT(&copier); @@ -3678,6 +3679,16 @@ static void test_sample_copier(void)
hr = IMFTransform_GetAttributes(copier, &attributes); ok(hr == S_OK, "Failed to get transform attributes, hr %#x.\n", hr); + hr = IMFTransform_GetAttributes(copier, &attributes2); + ok(hr == S_OK, "Failed to get transform attributes, hr %#x.\n", hr); + ok(attributes == attributes2, "Unexpected instance.\n"); + IMFAttributes_Release(attributes2); + hr = IMFAttributes_GetCount(attributes, &count); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(count == 1, "Unexpected attribute count %u.\n", count); + hr = IMFAttributes_GetUINT32(attributes, &MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, &value); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!!value, "Unexpected value %u.\n", value); IMFAttributes_Release(attributes);
hr = IMFTransform_GetInputStreamAttributes(copier, 0, &attributes);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/mixer.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
diff --git a/dlls/evr/mixer.c b/dlls/evr/mixer.c index 48875a200fd..c0d46ce5331 100644 --- a/dlls/evr/mixer.c +++ b/dlls/evr/mixer.c @@ -28,6 +28,7 @@
#include "initguid.h" #include "evr9.h" +#include "evcode.h"
#include "wine/debug.h" #include "wine/heap.h" @@ -44,6 +45,7 @@ struct input_stream MFVideoNormalizedRect rect; unsigned int zorder; IMFSample *sample; + unsigned int sample_requested : 1; };
struct rt_format @@ -995,6 +997,15 @@ static HRESULT WINAPI video_mixer_transform_ProcessEvent(IMFTransform *iface, DW return E_NOTIMPL; }
+static void video_mixer_request_sample(struct video_mixer *mixer, unsigned int idx) +{ + if (!mixer->event_sink || mixer->inputs[idx].sample_requested) + return; + + IMediaEventSink_Notify(mixer->event_sink, EC_SAMPLE_NEEDED, idx, 0); + mixer->inputs[idx].sample_requested = 1; +} + static HRESULT WINAPI video_mixer_transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { struct video_mixer *mixer = impl_from_IMFTransform(iface); @@ -1039,6 +1050,12 @@ static HRESULT WINAPI video_mixer_transform_ProcessMessage(IMFTransform *iface,
EnterCriticalSection(&mixer->cs);
+ if (!mixer->is_streaming) + { + for (i = 0; i < mixer->input_count; ++i) + video_mixer_request_sample(mixer, i); + } + mixer->is_streaming = message == MFT_MESSAGE_NOTIFY_BEGIN_STREAMING;
LeaveCriticalSection(&mixer->cs); @@ -1078,6 +1095,7 @@ static HRESULT WINAPI video_mixer_transform_ProcessInput(IMFTransform *iface, DW else { mixer->is_streaming = 1; + input->sample_requested = 0; input->sample = sample; IMFSample_AddRef(input->sample); }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/mixer.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/dlls/evr/mixer.c b/dlls/evr/mixer.c index c0d46ce5331..59d75c0476b 100644 --- a/dlls/evr/mixer.c +++ b/dlls/evr/mixer.c @@ -1038,6 +1038,7 @@ static HRESULT WINAPI video_mixer_transform_ProcessMessage(IMFTransform *iface, { IMFSample_Release(mixer->inputs[i].sample); mixer->inputs[i].sample = NULL; + mixer->inputs[i].sample_requested = 0; } }
@@ -1150,6 +1151,7 @@ static HRESULT WINAPI video_mixer_transform_ProcessOutput(IMFTransform *iface, D struct video_mixer *mixer = impl_from_IMFTransform(iface); IDirect3DSurface9 *surface; IDirect3DDevice9 *device; + unsigned int i; HRESULT hr;
TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, buffers, status); @@ -1168,8 +1170,26 @@ static HRESULT WINAPI video_mixer_transform_ProcessOutput(IMFTransform *iface, D { if (mixer->is_streaming) { - FIXME("Streaming state is not handled.\n"); - hr = E_NOTIMPL; + for (i = 0; i < mixer->input_count; ++i) + { + if (!mixer->inputs[i].sample) + { + hr = MF_E_TRANSFORM_NEED_MORE_INPUT; + break; + } + } + + /* FIXME: for now discard input */ + + if (SUCCEEDED(hr)) + { + for (i = 0; i < mixer->input_count; ++i) + { + IMFSample_Release(mixer->inputs[i].sample); + mixer->inputs[i].sample = NULL; + video_mixer_request_sample(mixer, i); + } + } } else {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=80909
Your paranoid android.
=== w8 (32 bit report) ===
mfplat: mfplat.c:4570: Test failed: Unexpected hr 0x80041000. mfplat.c:4573: Test failed: Unexpected hr 0x80041000.
=== w8adm (32 bit report) ===
mfplat: mfplat.c:4570: Test failed: Unexpected hr 0x80041000. mfplat.c:4573: Test failed: Unexpected hr 0x80041000.
=== w1064v1507 (32 bit report) ===
mfplat: mfplat.c:4570: Test failed: Unexpected hr 0x80041000. mfplat.c:4573: Test failed: Unexpected hr 0x80041000.
=== w864 (64 bit report) ===
mfplat: mfplat.c:4570: Test failed: Unexpected hr 0x80041000. mfplat.c:4573: Test failed: Unexpected hr 0x80041000.
=== w1064v1507 (64 bit report) ===
mfplat: mfplat.c:4570: Test failed: Unexpected hr 0x80041000. mfplat.c:4573: Test failed: Unexpected hr 0x80041000.
=== debiant (32 bit French report) ===
mfplat: mfplat.c:2795: Test failed: Unexpected counter value 0. mfplat.c:2872: Test failed: Unexpected return value 0x102. Unhandled exception: page fault on execute access to 0x0a2e7823 in 32-bit code (0x0a2e7823).
Report validation errors: mfplat:mfplat crashed (c0000005)