[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