[PATCH 4/6] mfplat: Implement MFCreateCollection().
Nikolay Sivov
nsivov at codeweavers.com
Fri Feb 22 01:36:52 CST 2019
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
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 21240dfbeb..e9b0abb041 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 e55cfb9a5a..b35b33558f 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 a7b5620d32..d0ae80a1e3 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 d85f7408b0..5797db1152 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);
--
2.20.1
More information about the wine-devel
mailing list