Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/Makefile.in | 3 +- dlls/mfplat/mfplat.spec | 2 +- dlls/mfplat/queue.c | 190 +++++++++++++++++++++++++++++++++++++ dlls/mfplat/tests/mfplat.c | 140 +++++++++++++++++++++++++++ include/mfapi.h | 14 +++ 5 files changed, 347 insertions(+), 2 deletions(-) create mode 100644 dlls/mfplat/queue.c
diff --git a/dlls/mfplat/Makefile.in b/dlls/mfplat/Makefile.in index 76843f5f25..17cda8856c 100644 --- a/dlls/mfplat/Makefile.in +++ b/dlls/mfplat/Makefile.in @@ -3,4 +3,5 @@ IMPORTLIB = mfplat IMPORTS = advapi32 ole32
C_SRCS = \ - main.c + main.c \ + queue.c diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 349b9265d5..b4e6c77aae 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -38,7 +38,7 @@ @ stdcall MFCopyImage(ptr long ptr long long long) @ stub MFCreateAMMediaTypeFromMFMediaType @ stub MFCreateAlignedMemoryBuffer -@ stub MFCreateAsyncResult +@ stdcall MFCreateAsyncResult(ptr ptr ptr ptr) @ stdcall MFCreateAttributes(ptr long) @ stub MFCreateAudioMediaType @ stub MFCreateCollection diff --git a/dlls/mfplat/queue.c b/dlls/mfplat/queue.c new file mode 100644 index 0000000000..762af248f0 --- /dev/null +++ b/dlls/mfplat/queue.c @@ -0,0 +1,190 @@ +/* + * Copyright 2019 Nikolay Sivov for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> + +#define COBJMACROS + +#include "mfapi.h" + +#include "wine/debug.h" +#include "wine/heap.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +struct async_result +{ + MFASYNCRESULT result; + LONG refcount; + IUnknown *object; + IUnknown *state; +}; + +static struct async_result *impl_from_IMFAsyncResult(IMFAsyncResult *iface) +{ + return CONTAINING_RECORD(iface, struct async_result, result.AsyncResult); +} + +static HRESULT WINAPI async_result_QueryInterface(IMFAsyncResult *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFAsyncResult) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFAsyncResult_AddRef(iface); + return S_OK; + } + + *obj = NULL; + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI async_result_AddRef(IMFAsyncResult *iface) +{ + struct async_result *result = impl_from_IMFAsyncResult(iface); + ULONG refcount = InterlockedIncrement(&result->refcount); + + TRACE("%p, %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI async_result_Release(IMFAsyncResult *iface) +{ + struct async_result *result = impl_from_IMFAsyncResult(iface); + ULONG refcount = InterlockedDecrement(&result->refcount); + + TRACE("%p, %u.\n", iface, refcount); + + if (!refcount) + { + if (result->result.pCallback) + IMFAsyncCallback_Release(result->result.pCallback); + if (result->object) + IUnknown_Release(result->object); + if (result->state) + IUnknown_Release(result->state); + heap_free(result); + } + + return refcount; +} + +static HRESULT WINAPI async_result_GetState(IMFAsyncResult *iface, IUnknown **state) +{ + struct async_result *result = impl_from_IMFAsyncResult(iface); + + TRACE("%p, %p.\n", iface, state); + + if (!result->state) + return E_POINTER; + + *state = result->state; + IUnknown_AddRef(*state); + + return S_OK; +} + +static HRESULT WINAPI async_result_GetStatus(IMFAsyncResult *iface) +{ + struct async_result *result = impl_from_IMFAsyncResult(iface); + + TRACE("%p.\n", iface); + + return result->result.hrStatusResult; +} + +static HRESULT WINAPI async_result_SetStatus(IMFAsyncResult *iface, HRESULT status) +{ + struct async_result *result = impl_from_IMFAsyncResult(iface); + + TRACE("%p, %#x.\n", iface, status); + + result->result.hrStatusResult = status; + + return S_OK; +} + +static HRESULT WINAPI async_result_GetObject(IMFAsyncResult *iface, IUnknown **object) +{ + struct async_result *result = impl_from_IMFAsyncResult(iface); + + TRACE("%p, %p.\n", iface, object); + + if (!result->object) + return E_POINTER; + + *object = result->object; + IUnknown_AddRef(*object); + + return S_OK; +} + +static IUnknown * WINAPI async_result_GetStateNoAddRef(IMFAsyncResult *iface) +{ + struct async_result *result = impl_from_IMFAsyncResult(iface); + + TRACE("%p.\n", iface); + + return result->state; +} + +static const IMFAsyncResultVtbl async_result_vtbl = +{ + async_result_QueryInterface, + async_result_AddRef, + async_result_Release, + async_result_GetState, + async_result_GetStatus, + async_result_SetStatus, + async_result_GetObject, + async_result_GetStateNoAddRef, +}; + +HRESULT WINAPI MFCreateAsyncResult(IUnknown *object, IMFAsyncCallback *callback, IUnknown *state, IMFAsyncResult **out) +{ + struct async_result *result; + + TRACE("%p, %p, %p, %p.\n", object, callback, state, out); + + if (!out) + return E_INVALIDARG; + + result = heap_alloc_zero(sizeof(*result)); + if (!result) + return E_OUTOFMEMORY; + + result->result.AsyncResult.lpVtbl = &async_result_vtbl; + result->refcount = 1; + result->object = object; + if (result->object) + IUnknown_AddRef(result->object); + result->result.pCallback = callback; + if (result->result.pCallback) + IMFAsyncCallback_AddRef(result->result.pCallback); + result->state = state; + if (result->state) + IUnknown_AddRef(result->state); + + *out = &result->result.AsyncResult; + + return S_OK; +} diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 3fa59f4816..395fde421d 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -693,6 +693,145 @@ static void test_MFSample(void) IMFSample_Release(sample); }
+static HRESULT WINAPI testcallback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFAsyncCallback) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFAsyncCallback_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI testcallback_AddRef(IMFAsyncCallback *iface) +{ + return 2; +} + +static ULONG WINAPI testcallback_Release(IMFAsyncCallback *iface) +{ + return 1; +} + +static HRESULT WINAPI testcallback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI testcallback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IMFAsyncCallbackVtbl testcallbackvtbl = +{ + testcallback_QueryInterface, + testcallback_AddRef, + testcallback_Release, + testcallback_GetParameters, + testcallback_Invoke, +}; + +static void test_MFCreateAsyncResult(void) +{ + IMFAsyncCallback callback = { &testcallbackvtbl }; + IMFAsyncResult *result, *result2; + IUnknown *state, *object; + MFASYNCRESULT *data; + ULONG refcount; + HRESULT hr; + + hr = MFCreateAsyncResult(NULL, NULL, NULL, NULL); + ok(FAILED(hr), "Unexpected hr %#x.\n", hr); + + hr = MFCreateAsyncResult(NULL, NULL, NULL, &result); + ok(hr == S_OK, "Failed to create object, hr %#x.\n", hr); + + data = (MFASYNCRESULT *)result; + ok(data->pCallback == NULL, "Unexpected callback value.\n"); + ok(data->hrStatusResult == S_OK, "Unexpected status %#x.\n", data->hrStatusResult); + ok(data->dwBytesTransferred == 0, "Unexpected byte length %u.\n", data->dwBytesTransferred); + ok(data->hEvent == NULL, "Unexpected event.\n"); + + hr = IMFAsyncResult_GetState(result, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + state = (void *)0xdeadbeef; + hr = IMFAsyncResult_GetState(result, &state); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + ok(state == (void *)0xdeadbeef, "Unexpected state.\n"); + + hr = IMFAsyncResult_GetStatus(result); + ok(hr == S_OK, "Unexpected status %#x.\n", hr); + + data->hrStatusResult = 123; + hr = IMFAsyncResult_GetStatus(result); + ok(hr == 123, "Unexpected status %#x.\n", hr); + + hr = IMFAsyncResult_SetStatus(result, E_FAIL); + ok(hr == S_OK, "Failed to set status, hr %#x.\n", hr); + ok(data->hrStatusResult == E_FAIL, "Unexpected status %#x.\n", hr); + + hr = IMFAsyncResult_GetObject(result, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + object = (void *)0xdeadbeef; + hr = IMFAsyncResult_GetObject(result, &object); + ok(hr == E_POINTER, "Failed to get object, hr %#x.\n", hr); + ok(object == (void *)0xdeadbeef, "Unexpected object.\n"); + + state = IMFAsyncResult_GetStateNoAddRef(result); + ok(state == NULL, "Unexpected state.\n"); + + /* Object. */ + hr = MFCreateAsyncResult((IUnknown *)result, &callback, NULL, &result2); + ok(hr == S_OK, "Failed to create object, hr %#x.\n", hr); + + data = (MFASYNCRESULT *)result2; + ok(data->pCallback == &callback, "Unexpected callback value.\n"); + ok(data->hrStatusResult == S_OK, "Unexpected status %#x.\n", data->hrStatusResult); + ok(data->dwBytesTransferred == 0, "Unexpected byte length %u.\n", data->dwBytesTransferred); + ok(data->hEvent == NULL, "Unexpected event.\n"); + + object = NULL; + hr = IMFAsyncResult_GetObject(result2, &object); + ok(hr == S_OK, "Failed to get object, hr %#x.\n", hr); + ok(object == (IUnknown *)result, "Unexpected object.\n"); + IUnknown_Release(object); + + IMFAsyncResult_Release(result2); + + /* State object. */ + hr = MFCreateAsyncResult(NULL, &callback, (IUnknown *)result, &result2); + ok(hr == S_OK, "Failed to create object, hr %#x.\n", hr); + + data = (MFASYNCRESULT *)result2; + ok(data->pCallback == &callback, "Unexpected callback value.\n"); + ok(data->hrStatusResult == S_OK, "Unexpected status %#x.\n", data->hrStatusResult); + ok(data->dwBytesTransferred == 0, "Unexpected byte length %u.\n", data->dwBytesTransferred); + ok(data->hEvent == NULL, "Unexpected event.\n"); + + state = NULL; + hr = IMFAsyncResult_GetState(result2, &state); + ok(hr == S_OK, "Failed to get state object, hr %#x.\n", hr); + ok(state == (IUnknown *)result, "Unexpected state.\n"); + IUnknown_Release(state); + + state = IMFAsyncResult_GetStateNoAddRef(result2); + ok(state == (IUnknown *)result, "Unexpected state.\n"); + + refcount = IMFAsyncResult_Release(result2); + ok(!refcount, "Unexpected refcount %u\n.", refcount); + refcount = IMFAsyncResult_Release(result); + ok(!refcount, "Unexpected refcount %u\n.", refcount); +} + START_TEST(mfplat) { CoInitialize(NULL); @@ -708,6 +847,7 @@ START_TEST(mfplat) test_MFCreateMFByteStreamOnStream(); test_MFCreateMemoryBuffer(); test_source_resolver(); + test_MFCreateAsyncResult();
CoUninitialize(); } diff --git a/include/mfapi.h b/include/mfapi.h index b0d8e43125..1575cc3d97 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -54,6 +54,19 @@ extern "C" { DEFINE_MEDIATYPE_GUID(MFVideoFormat_WMV3, MAKEFOURCC('W','M','V','3')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_RGB32, D3DFMT_X8R8G8B8);
+#if defined(__cplusplus) && !defined(CINTERFACE) +typedef struct tagMFASYNCRESULT : public IMFAsyncResult { +#else +typedef struct tagMFASYNCRESULT +{ + IMFAsyncResult AsyncResult; +#endif + OVERLAPPED overlapped; + IMFAsyncCallback *pCallback; + HRESULT hrStatusResult; + DWORD dwBytesTransferred; + HANDLE hEvent; +} MFASYNCRESULT;
DEFINE_GUID(MF_MT_AVG_BITRATE, 0x20332624, 0xfb0d, 0x4d9e, 0xbd, 0x0d, 0xcb, 0xf6, 0x78, 0x6c, 0x10, 0x2e); DEFINE_GUID(MF_MT_FRAME_RATE, 0xc459a2e8, 0x3d2c, 0x4e44, 0xb1, 0x32, 0xfe, 0xe5, 0x15, 0x6c, 0x7b, 0xb0); @@ -70,6 +83,7 @@ typedef unsigned __int64 MFWORKITEM_KEY; HRESULT WINAPI MFCancelWorkItem(MFWORKITEM_KEY key); HRESULT WINAPI MFCopyImage(BYTE *dest, LONG deststride, const BYTE *src, LONG srcstride, DWORD width, DWORD lines); HRESULT WINAPI MFCreateAttributes(IMFAttributes **attributes, UINT32 size); +HRESULT WINAPI MFCreateAsyncResult(IUnknown *object, IMFAsyncCallback *callback, IUnknown *state, IMFAsyncResult **result); HRESULT WINAPI MFCreateEventQueue(IMFMediaEventQueue **queue); HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE openmode, MF_FILE_FLAGS flags, LPCWSTR url, IMFByteStream **bytestream);