From a606abf245e22936eb771dcfc8f4e7d7eb78de41 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Fri, 22 Feb 2019 10:36:52 +0300 Subject: [PATCH] mfplat: Implement MFCreateCollection(). Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/mfplat/main.c | 253 +++++++++++++++++++++++++++++++++++++ dlls/mfplat/mfplat.spec | 2 +- dlls/mfplat/tests/mfplat.c | 103 +++++++++++++++ include/mfapi.h | 1 + 4 files changed, 358 insertions(+), 1 deletion(-) diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 21240dfbeb9..e9b0abb0416 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -129,6 +129,33 @@ static BOOL GUIDFromString(LPCWSTR s, GUID *id) return FALSE; } +static BOOL mf_array_reserve(void **elements, size_t *capacity, size_t count, size_t size) +{ + size_t new_capacity, max_capacity; + void *new_elements; + + if (count <= *capacity) + return TRUE; + + max_capacity = ~(SIZE_T)0 / size; + if (count > max_capacity) + return FALSE; + + new_capacity = max(4, *capacity); + while (new_capacity < count && new_capacity <= max_capacity / 2) + new_capacity *= 2; + if (new_capacity < count) + new_capacity = max_capacity; + + if (!(new_elements = heap_realloc(*elements, new_capacity * size))) + return FALSE; + + *elements = new_elements; + *capacity = new_capacity; + + return TRUE; +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { switch (reason) @@ -3871,3 +3898,229 @@ HRESULT WINAPI MFCreateSample(IMFSample **sample) return S_OK; } + +struct collection +{ + IMFCollection IMFCollection_iface; + LONG refcount; + IUnknown **elements; + size_t capacity; + size_t count; +}; + +static struct collection *impl_from_IMFCollection(IMFCollection *iface) +{ + return CONTAINING_RECORD(iface, struct collection, IMFCollection_iface); +} + +static void collection_clear(struct collection *collection) +{ + size_t i; + + for (i = 0; i < collection->count; ++i) + { + if (collection->elements[i]) + IUnknown_Release(collection->elements[i]); + } + + heap_free(collection->elements); + collection->elements = NULL; + collection->count = 0; + collection->capacity = 0; +} + +static HRESULT WINAPI collection_QueryInterface(IMFCollection *iface, REFIID riid, void **out) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IMFCollection) || + IsEqualIID(riid, &IID_IUnknown)) + { + *out = iface; + IMFCollection_AddRef(iface); + return S_OK; + } + + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI collection_AddRef(IMFCollection *iface) +{ + struct collection *collection = impl_from_IMFCollection(iface); + ULONG refcount = InterlockedIncrement(&collection->refcount); + + TRACE("%p, %d.\n", collection, refcount); + + return refcount; +} + +static ULONG WINAPI collection_Release(IMFCollection *iface) +{ + struct collection *collection = impl_from_IMFCollection(iface); + ULONG refcount = InterlockedDecrement(&collection->refcount); + + TRACE("%p, %d.\n", collection, refcount); + + if (!refcount) + { + collection_clear(collection); + heap_free(collection->elements); + heap_free(collection); + } + + return refcount; +} + +static HRESULT WINAPI collection_GetElementCount(IMFCollection *iface, DWORD *count) +{ + struct collection *collection = impl_from_IMFCollection(iface); + + TRACE("%p, %p.\n", iface, count); + + if (!count) + return E_POINTER; + + *count = collection->count; + + return S_OK; +} + +static HRESULT WINAPI collection_GetElement(IMFCollection *iface, DWORD idx, IUnknown **element) +{ + struct collection *collection = impl_from_IMFCollection(iface); + + TRACE("%p, %u, %p.\n", iface, idx, element); + + if (!element) + return E_POINTER; + + if (idx >= collection->count) + return E_INVALIDARG; + + *element = collection->elements[idx]; + if (*element) + IUnknown_AddRef(*element); + + return *element ? S_OK : E_UNEXPECTED; +} + +static HRESULT WINAPI collection_AddElement(IMFCollection *iface, IUnknown *element) +{ + struct collection *collection = impl_from_IMFCollection(iface); + + TRACE("%p, %p.\n", iface, element); + + if (!mf_array_reserve((void **)&collection->elements, &collection->capacity, collection->count + 1, + sizeof(*collection->elements))) + return E_OUTOFMEMORY; + + collection->elements[collection->count++] = element; + if (element) + IUnknown_AddRef(element); + + return S_OK; +} + +static HRESULT WINAPI collection_RemoveElement(IMFCollection *iface, DWORD idx, IUnknown **element) +{ + struct collection *collection = impl_from_IMFCollection(iface); + size_t count; + + TRACE("%p, %u, %p.\n", iface, idx, element); + + if (!element) + return E_POINTER; + + if (idx >= collection->count) + return E_INVALIDARG; + + *element = collection->elements[idx]; + + count = collection->count - idx - 1; + if (count) + memmove(&collection->elements[idx], &collection->elements[idx + 1], count * sizeof(*collection->elements)); + collection->count--; + + return S_OK; +} + +static HRESULT WINAPI collection_InsertElementAt(IMFCollection *iface, DWORD idx, IUnknown *element) +{ + struct collection *collection = impl_from_IMFCollection(iface); + size_t i; + + TRACE("%p, %u, %p.\n", iface, idx, element); + + if (!mf_array_reserve((void **)&collection->elements, &collection->capacity, idx + 1, + sizeof(*collection->elements))) + return E_OUTOFMEMORY; + + if (idx < collection->count) + { + memmove(&collection->elements[idx + 1], &collection->elements[idx], + (collection->count - idx) * sizeof(*collection->elements)); + collection->count++; + } + else + { + for (i = collection->count; i < idx; ++i) + collection->elements[i] = NULL; + collection->count = idx + 1; + } + + collection->elements[idx] = element; + if (collection->elements[idx]) + IUnknown_AddRef(collection->elements[idx]); + + return S_OK; +} + +static HRESULT WINAPI collection_RemoveAllElements(IMFCollection *iface) +{ + struct collection *collection = impl_from_IMFCollection(iface); + + TRACE("%p.\n", iface); + + collection_clear(collection); + + return S_OK; +} + +static const IMFCollectionVtbl mfcollectionvtbl = +{ + collection_QueryInterface, + collection_AddRef, + collection_Release, + collection_GetElementCount, + collection_GetElement, + collection_AddElement, + collection_RemoveElement, + collection_InsertElementAt, + collection_RemoveAllElements, +}; + +/*********************************************************************** + * MFCreateCollection (mfplat.@) + */ +HRESULT WINAPI MFCreateCollection(IMFCollection **collection) +{ + struct collection *object; + + TRACE("%p\n", collection); + + if (!collection) + return E_POINTER; + + object = heap_alloc_zero(sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + object->IMFCollection_iface.lpVtbl = &mfcollectionvtbl; + object->refcount = 1; + + *collection = &object->IMFCollection_iface; + + return S_OK; +} diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index e55cfb9a5ac..b35b33558fa 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -41,7 +41,7 @@ @ stdcall MFCreateAsyncResult(ptr ptr ptr ptr) @ stdcall MFCreateAttributes(ptr long) @ stub MFCreateAudioMediaType -@ stub MFCreateCollection +@ stdcall MFCreateCollection(ptr) @ stdcall MFCreateEventQueue(ptr) @ stdcall MFCreateFile(long long long wstr ptr) @ stub MFCreateLegacyMediaBufferOnMFMediaBuffer diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index a7b5620d32a..d0ae80a1e38 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -913,6 +913,108 @@ static void test_MFCopyImage(void) ok(!memcmp(dest, src, 16), "Unexpected buffer contents.\n"); } +static void test_MFCreateCollection(void) +{ + IMFCollection *collection; + IUnknown *element; + DWORD count; + HRESULT hr; + + hr = MFCreateCollection(NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = MFCreateCollection(&collection); + ok(hr == S_OK, "Failed to create collection, hr %#x.\n", hr); + + hr = IMFCollection_GetElementCount(collection, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + count = 1; + hr = IMFCollection_GetElementCount(collection, &count); + ok(hr == S_OK, "Failed to get element count, hr %#x.\n", hr); + ok(count == 0, "Unexpected count %u.\n", count); + + hr = IMFCollection_GetElement(collection, 0, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + element = (void *)0xdeadbeef; + hr = IMFCollection_GetElement(collection, 0, &element); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + ok(element == (void *)0xdeadbeef, "Unexpected pointer.\n"); + + hr = IMFCollection_RemoveElement(collection, 0, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + element = (void *)0xdeadbeef; + hr = IMFCollection_RemoveElement(collection, 0, &element); + ok(hr == E_INVALIDARG, "Failed to remove element, hr %#x.\n", hr); + ok(element == (void *)0xdeadbeef, "Unexpected pointer.\n"); + + hr = IMFCollection_RemoveAllElements(collection); + ok(hr == S_OK, "Failed to clear, hr %#x.\n", hr); + + hr = IMFCollection_AddElement(collection, (IUnknown *)collection); + ok(hr == S_OK, "Failed to add element, hr %#x.\n", hr); + + count = 0; + hr = IMFCollection_GetElementCount(collection, &count); + ok(hr == S_OK, "Failed to get element count, hr %#x.\n", hr); + ok(count == 1, "Unexpected count %u.\n", count); + + hr = IMFCollection_AddElement(collection, NULL); + ok(hr == S_OK, "Failed to add element, hr %#x.\n", hr); + + count = 0; + hr = IMFCollection_GetElementCount(collection, &count); + ok(hr == S_OK, "Failed to get element count, hr %#x.\n", hr); + ok(count == 2, "Unexpected count %u.\n", count); + + hr = IMFCollection_InsertElementAt(collection, 10, (IUnknown *)collection); + ok(hr == S_OK, "Failed to insert element, hr %#x.\n", hr); + + count = 0; + hr = IMFCollection_GetElementCount(collection, &count); + ok(hr == S_OK, "Failed to get element count, hr %#x.\n", hr); + ok(count == 11, "Unexpected count %u.\n", count); + + hr = IMFCollection_GetElement(collection, 0, &element); + ok(hr == S_OK, "Failed to get element, hr %#x.\n", hr); + ok(element == (IUnknown *)collection, "Unexpected element.\n"); + IUnknown_Release(element); + + hr = IMFCollection_GetElement(collection, 1, &element); + ok(hr == E_UNEXPECTED, "Unexpected hr %#x.\n", hr); + ok(!element, "Unexpected element.\n"); + + hr = IMFCollection_GetElement(collection, 2, &element); + ok(hr == E_UNEXPECTED, "Unexpected hr %#x.\n", hr); + ok(!element, "Unexpected element.\n"); + + hr = IMFCollection_GetElement(collection, 10, &element); + ok(hr == S_OK, "Failed to get element, hr %#x.\n", hr); + ok(element == (IUnknown *)collection, "Unexpected element.\n"); + IUnknown_Release(element); + + hr = IMFCollection_InsertElementAt(collection, 0, NULL); + ok(hr == S_OK, "Failed to insert element, hr %#x.\n", hr); + + hr = IMFCollection_GetElement(collection, 0, &element); + ok(hr == E_UNEXPECTED, "Unexpected hr %#x.\n", hr); + + hr = IMFCollection_RemoveAllElements(collection); + ok(hr == S_OK, "Failed to clear, hr %#x.\n", hr); + + count = 1; + hr = IMFCollection_GetElementCount(collection, &count); + ok(hr == S_OK, "Failed to get element count, hr %#x.\n", hr); + ok(count == 0, "Unexpected count %u.\n", count); + + hr = IMFCollection_InsertElementAt(collection, 0, NULL); + ok(hr == S_OK, "Failed to insert element, hr %#x.\n", hr); + + IMFCollection_Release(collection); +} + START_TEST(mfplat) { CoInitialize(NULL); @@ -932,6 +1034,7 @@ START_TEST(mfplat) test_MFCreateAsyncResult(); test_allocate_queue(); test_MFCopyImage(); + test_MFCreateCollection(); CoUninitialize(); } diff --git a/include/mfapi.h b/include/mfapi.h index d85f7408b08..5797db11528 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -85,6 +85,7 @@ 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 MFCreateCollection(IMFCollection **collection); HRESULT WINAPI MFCreateEventQueue(IMFMediaEventQueue **queue); HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE openmode, MF_FILE_FLAGS flags, LPCWSTR url, IMFByteStream **bytestream);