Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfreadwrite/main.c | 98 +++++++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 19 deletions(-)
diff --git a/dlls/mfreadwrite/main.c b/dlls/mfreadwrite/main.c index 77dbd7b052..dcacd9a751 100644 --- a/dlls/mfreadwrite/main.c +++ b/dlls/mfreadwrite/main.c @@ -28,10 +28,14 @@ #include "ole2.h" #include "rpcproxy.h" #include "mfreadwrite.h" +#include "mfidl.h"
#include "wine/debug.h" +#include "wine/heap.h"
DEFINE_GUID(CLSID_MFReadWriteClassFactory, 0x48e2ed0f, 0x98c2, 0x4a37, 0xbe, 0xd5, 0x16, 0x63, 0x12, 0xdd, 0xd8, 0x3f); +DEFINE_GUID(CLSID_MFSourceReader, 0x1777133c, 0x0881, 0x411b, 0xa5, 0x77, 0xad, 0x54, 0x5f, 0x07, 0x14, 0xc4); +DEFINE_GUID(CLSID_MFSinkWriter, 0xa3bbfb17, 0x8273, 0x4e52, 0x9e, 0x0e, 0x97, 0x39, 0xdc, 0x88, 0x79, 0x90);
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
@@ -52,15 +56,6 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) return TRUE; }
- -HRESULT WINAPI MFCreateSourceReaderFromMediaSource(IMFMediaSource *source, IMFAttributes *attributes, - IMFSourceReader **reader) -{ - FIXME("%p %p %p stub.\n", source, attributes, reader); - - return E_NOTIMPL; -} - HRESULT WINAPI DllCanUnloadNow(void) { return S_FALSE; @@ -228,21 +223,52 @@ struct IMFSourceReaderVtbl srcreader_vtbl = src_reader_GetPresentationAttribute };
-HRESULT WINAPI MFCreateSourceReaderFromByteStream(IMFByteStream *stream, IMFAttributes *attributes, IMFSourceReader **reader) +static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttributes *attributes, + REFIID riid, void **out) { srcreader *object; + HRESULT hr;
- TRACE("%p, %p, %p\n", stream, attributes, reader); - - object = HeapAlloc( GetProcessHeap(), 0, sizeof(*object) ); - if(!object) + object = heap_alloc(sizeof(*object)); + if (!object) return E_OUTOFMEMORY;
- object->ref = 1; object->IMFSourceReader_iface.lpVtbl = &srcreader_vtbl; + object->ref = 1;
- *reader = &object->IMFSourceReader_iface; - return S_OK; + hr = IMFSourceReader_QueryInterface(&object->IMFSourceReader_iface, riid, out); + IMFSourceReader_Release(&object->IMFSourceReader_iface); + return hr; +} + +static HRESULT create_source_reader_from_stream(IMFByteStream *stream, IMFAttributes *attributes, + REFIID riid, void **out) +{ + /* FIXME: resolve bytestream to media source */ + + return create_source_reader_from_source(NULL, attributes, riid, out); +} + +/*********************************************************************** + * MFCreateSourceReaderFromByteStream (mfreadwrite.@) + */ +HRESULT WINAPI MFCreateSourceReaderFromByteStream(IMFByteStream *stream, IMFAttributes *attributes, + IMFSourceReader **reader) +{ + TRACE("%p, %p, %p.\n", stream, attributes, reader); + + return create_source_reader_from_stream(stream, attributes, &IID_IMFSourceReader, (void **)reader); +} + +/*********************************************************************** + * MFCreateSourceReaderFromMediaSource (mfreadwrite.@) + */ +HRESULT WINAPI MFCreateSourceReaderFromMediaSource(IMFMediaSource *source, IMFAttributes *attributes, + IMFSourceReader **reader) +{ + TRACE("%p, %p, %p.\n", source, attributes, reader); + + return create_source_reader_from_source(source, attributes, &IID_IMFSourceReader, (void **)reader); }
static HRESULT WINAPI readwrite_factory_QueryInterface(IMFReadWriteClassFactory *iface, REFIID riid, void **out) @@ -281,9 +307,43 @@ static HRESULT WINAPI readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassF static HRESULT WINAPI readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory *iface, REFCLSID clsid, IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out) { - FIXME("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid), unk, attributes, debugstr_guid(riid), out); + HRESULT hr;
- return E_NOTIMPL; + TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid), unk, attributes, debugstr_guid(riid), out); + + if (IsEqualGUID(clsid, &CLSID_MFSourceReader)) + { + IMFMediaSource *source = NULL; + IMFByteStream *stream = NULL; + + hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream); + if (FAILED(hr)) + hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSource, (void **)&source); + + if (stream) + hr = create_source_reader_from_stream(stream, attributes, riid, out); + else if (source) + hr = create_source_reader_from_source(source, attributes, riid, out); + + if (source) + IMFMediaSource_Release(source); + if (stream) + IMFByteStream_Release(stream); + + return hr; + } + else if (IsEqualGUID(clsid, &CLSID_MFSinkWriter)) + { + FIXME("MFSinkWriter is not supported.\n"); + *out = NULL; + return E_NOTIMPL; + } + else + { + WARN("Unsupported class %s.\n", debugstr_guid(clsid)); + *out = NULL; + return E_FAIL; + } }
static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl =
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/tests/mf.c | 8 ++++---- dlls/mf/topology.c | 20 ++++++++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index d6091cb629..38bf48ebf9 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -57,11 +57,10 @@ static void test_topology(void) ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr);
hr = IMFTopologyNode_GetTopoNodeID(node, &id); -todo_wine ok(hr == S_OK, "Failed to get node id, hr %#x.\n", hr); + ok(((id >> 32) == GetCurrentProcessId()) && !!(id & 0xffff), "Unexpected node id %s.\n", wine_dbgstr_longlong(id));
hr = IMFTopologyNode_SetTopoNodeID(node2, id); -todo_wine ok(hr == S_OK, "Failed to set node id, hr %#x.\n", hr);
count = 1; @@ -96,7 +95,6 @@ todo_wine {
/* Change node id, add it again. */ hr = IMFTopologyNode_SetTopoNodeID(node, ++id); -todo_wine ok(hr == S_OK, "Failed to set node id, hr %#x.\n", hr);
hr = IMFTopology_GetNodeByID(topology, id, &node2); @@ -148,7 +146,6 @@ todo_wine { hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node2); ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr); hr = IMFTopologyNode_SetTopoNodeID(node2, id); -todo_wine ok(hr == S_OK, "Failed to set node id, hr %#x.\n", hr); hr = IMFTopology_RemoveNode(topology, node2); todo_wine @@ -179,6 +176,9 @@ todo_wine { todo_wine ok(hr == S_OK, "Failed to clear topology, hr %#x.\n", hr);
+ hr = IMFTopologyNode_SetTopoNodeID(node, 123); + ok(hr == S_OK, "Failed to set node id, hr %#x.\n", hr); + IMFTopologyNode_Release(node); IMFTopology_Release(topology); } diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 308a1e3ce9..54e9faf94a 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -32,6 +32,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+static LONG next_node_id; + struct topology { IMFTopology IMFTopology_iface; @@ -45,6 +47,7 @@ struct topology_node LONG refcount; IMFAttributes *attributes; MF_TOPOLOGY_TYPE node_type; + TOPOID id; };
struct seq_source @@ -887,16 +890,24 @@ static HRESULT WINAPI topology_node_GetNodeType(IMFTopologyNode *iface, MF_TOPOL
static HRESULT WINAPI topology_node_GetTopoNodeID(IMFTopologyNode *iface, TOPOID *id) { - FIXME("(%p)->(%p)\n", iface, id); + struct topology_node *node = impl_from_IMFTopologyNode(iface);
- return E_NOTIMPL; + TRACE("(%p)->(%p)\n", iface, id); + + *id = node->id; + + return S_OK; }
static HRESULT WINAPI topology_node_SetTopoNodeID(IMFTopologyNode *iface, TOPOID id) { - FIXME("(%p)->(%s)\n", iface, wine_dbgstr_longlong(id)); + struct topology_node *node = impl_from_IMFTopologyNode(iface);
- return E_NOTIMPL; + TRACE("(%p)->(%s)\n", iface, wine_dbgstr_longlong(id)); + + node->id = id; + + return S_OK; }
static HRESULT WINAPI topology_node_GetInputCount(IMFTopologyNode *iface, DWORD *count) @@ -1058,6 +1069,7 @@ HRESULT WINAPI MFCreateTopologyNode(MF_TOPOLOGY_TYPE node_type, IMFTopologyNode heap_free(object); return hr; } + object->id = ((TOPOID)GetCurrentProcessId() << 32) | InterlockedIncrement(&next_node_id);
*node = &object->IMFTopologyNode_iface;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/tests/mf.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 38bf48ebf9..e8051eb3ba 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -35,7 +35,7 @@
static void test_topology(void) { - IMFTopologyNode *node, *node2; + IMFTopologyNode *node, *node2, *node3; IMFTopology *topology; WORD count; HRESULT hr; @@ -180,6 +180,39 @@ todo_wine ok(hr == S_OK, "Failed to set node id, hr %#x.\n", hr);
IMFTopologyNode_Release(node); + + /* Change id for attached node. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node); + ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node2); + ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr); + + hr = IMFTopology_AddNode(topology, node); +todo_wine + ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); + + hr = IMFTopology_AddNode(topology, node2); +todo_wine + ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); + + hr = IMFTopologyNode_GetTopoNodeID(node, &id); + ok(hr == S_OK, "Failed to get node id, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetTopoNodeID(node2, id); + ok(hr == S_OK, "Failed to get node id, hr %#x.\n", hr); + + hr = IMFTopology_GetNodeByID(topology, id, &node3); +todo_wine { + ok(hr == S_OK, "Failed to get a node, hr %#x.\n", hr); + ok(node3 == node, "Unexpected node.\n"); +} + if (SUCCEEDED(hr)) + IMFTopologyNode_Release(node3); + + IMFTopologyNode_Release(node); + IMFTopologyNode_Release(node2); + IMFTopology_Release(topology); }
Signed-off-by: Nikolay Sivov nsivov@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);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/tests/mf.c | 57 +++++++--------------- dlls/mf/topology.c | 117 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 121 insertions(+), 53 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index e8051eb3ba..2b3fdcd798 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -63,117 +63,101 @@ static void test_topology(void) hr = IMFTopologyNode_SetTopoNodeID(node2, id); ok(hr == S_OK, "Failed to set node id, hr %#x.\n", hr);
+ hr = IMFTopology_GetNodeCount(topology, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = IMFTopology_AddNode(topology, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + count = 1; hr = IMFTopology_GetNodeCount(topology, &count); -todo_wine { ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr); ok(count == 0, "Unexpected node count %u.\n", count); -} + /* Same id, different nodes. */ hr = IMFTopology_AddNode(topology, node); -todo_wine ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr);
count = 0; hr = IMFTopology_GetNodeCount(topology, &count); -todo_wine { ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr); ok(count == 1, "Unexpected node count %u.\n", count); -} + hr = IMFTopology_AddNode(topology, node2); -todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); IMFTopologyNode_Release(node2);
hr = IMFTopology_GetNodeByID(topology, id, &node2); -todo_wine { ok(hr == S_OK, "Failed to get a node, hr %#x.\n", hr); ok(node2 == node, "Unexpected node.\n"); -} - if (SUCCEEDED(hr)) - IMFTopologyNode_Release(node2); + IMFTopologyNode_Release(node2);
/* Change node id, add it again. */ hr = IMFTopologyNode_SetTopoNodeID(node, ++id); ok(hr == S_OK, "Failed to set node id, hr %#x.\n", hr);
hr = IMFTopology_GetNodeByID(topology, id, &node2); -todo_wine { ok(hr == S_OK, "Failed to get a node, hr %#x.\n", hr); ok(node2 == node, "Unexpected node.\n"); -} - if (SUCCEEDED(hr)) - IMFTopologyNode_Release(node2); + IMFTopologyNode_Release(node2);
hr = IMFTopology_GetNodeByID(topology, id + 1, &node2); -todo_wine ok(hr == MF_E_NOT_FOUND, "Unexpected hr %#x.\n", hr);
hr = IMFTopology_AddNode(topology, node); -todo_wine ok(hr == E_INVALIDARG, "Failed to add a node, hr %#x.\n", hr);
hr = IMFTopology_GetNode(topology, 0, &node2); -todo_wine { ok(hr == S_OK, "Failed to get a node, hr %#x.\n", hr); ok(node2 == node, "Unexpected node.\n"); -} - if (SUCCEEDED(hr)) - IMFTopologyNode_Release(node2); + IMFTopologyNode_Release(node2); + + hr = IMFTopology_GetNode(topology, 1, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
hr = IMFTopology_GetNode(topology, 1, &node2); -todo_wine ok(hr == MF_E_INVALIDINDEX, "Failed to get a node, hr %#x.\n", hr);
hr = IMFTopology_GetNode(topology, -2, &node2); -todo_wine ok(hr == MF_E_INVALIDINDEX, "Failed to get a node, hr %#x.\n", hr);
hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node2); ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr); hr = IMFTopology_AddNode(topology, node2); -todo_wine ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); IMFTopologyNode_Release(node2);
count = 0; hr = IMFTopology_GetNodeCount(topology, &count); -todo_wine { ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr); ok(count == 2, "Unexpected node count %u.\n", count); -} + /* Remove with detached node, existing id. */ hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node2); ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr); hr = IMFTopologyNode_SetTopoNodeID(node2, id); ok(hr == S_OK, "Failed to set node id, hr %#x.\n", hr); hr = IMFTopology_RemoveNode(topology, node2); -todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); IMFTopologyNode_Release(node2);
hr = IMFTopology_RemoveNode(topology, node); -todo_wine ok(hr == S_OK, "Failed to remove a node, hr %#x.\n", hr);
count = 0; hr = IMFTopology_GetNodeCount(topology, &count); -todo_wine { ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr); ok(count == 1, "Unexpected node count %u.\n", count); -} + hr = IMFTopology_Clear(topology); -todo_wine ok(hr == S_OK, "Failed to clear topology, hr %#x.\n", hr);
count = 1; hr = IMFTopology_GetNodeCount(topology, &count); -todo_wine { ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr); ok(count == 0, "Unexpected node count %u.\n", count); -} + hr = IMFTopology_Clear(topology); -todo_wine ok(hr == S_OK, "Failed to clear topology, hr %#x.\n", hr);
hr = IMFTopologyNode_SetTopoNodeID(node, 123); @@ -189,11 +173,9 @@ todo_wine ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr);
hr = IMFTopology_AddNode(topology, node); -todo_wine ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr);
hr = IMFTopology_AddNode(topology, node2); -todo_wine ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr);
hr = IMFTopologyNode_GetTopoNodeID(node, &id); @@ -203,12 +185,9 @@ todo_wine ok(hr == S_OK, "Failed to get node id, hr %#x.\n", hr);
hr = IMFTopology_GetNodeByID(topology, id, &node3); -todo_wine { ok(hr == S_OK, "Failed to get a node, hr %#x.\n", hr); ok(node3 == node, "Unexpected node.\n"); -} - if (SUCCEEDED(hr)) - IMFTopologyNode_Release(node3); + IMFTopologyNode_Release(node3);
IMFTopologyNode_Release(node); IMFTopologyNode_Release(node2); diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 54e9faf94a..d8012226f4 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -25,6 +25,7 @@ #include "winbase.h" #include "initguid.h" #include "mfapi.h" +#include "mferror.h" #include "mfidl.h"
#include "wine/debug.h" @@ -39,6 +40,7 @@ struct topology IMFTopology IMFTopology_iface; LONG refcount; IMFAttributes *attributes; + IMFCollection *nodes; };
struct topology_node @@ -113,7 +115,10 @@ static ULONG WINAPI topology_Release(IMFTopology *iface)
if (!refcount) { - IMFAttributes_Release(topology->attributes); + if (topology->attributes) + IMFAttributes_Release(topology->attributes); + if (topology->nodes) + IMFCollection_Release(topology->nodes); heap_free(topology); }
@@ -401,39 +406,117 @@ static HRESULT WINAPI topology_GetTopologyID(IMFTopology *iface, TOPOID *id) return E_NOTIMPL; }
+static HRESULT topology_get_node_by_id(const struct topology *topology, TOPOID id, IMFTopologyNode **node) +{ + IMFTopologyNode *iter; + unsigned int i = 0; + + while (IMFCollection_GetElement(topology->nodes, i, (IUnknown **)&iter) == S_OK) + { + TOPOID node_id; + HRESULT hr; + + hr = IMFTopologyNode_GetTopoNodeID(iter, &node_id); + if (FAILED(hr)) + return hr; + + if (node_id == id) + { + *node = iter; + return S_OK; + } + + ++i; + } + + return MF_E_NOT_FOUND; +} + static HRESULT WINAPI topology_AddNode(IMFTopology *iface, IMFTopologyNode *node) { - FIXME("(%p)->(%p)\n", iface, node); + struct topology *topology = impl_from_IMFTopology(iface); + IMFTopologyNode *match; + HRESULT hr; + TOPOID id;
- return E_NOTIMPL; + TRACE("(%p)->(%p)\n", iface, node); + + if (!node) + return E_POINTER; + + if (FAILED(hr = IMFTopologyNode_GetTopoNodeID(node, &id))) + return hr; + + if (FAILED(topology_get_node_by_id(topology, id, &match))) + return IMFCollection_AddElement(topology->nodes, (IUnknown *)node); + + IMFTopologyNode_Release(match); + + return E_INVALIDARG; }
static HRESULT WINAPI topology_RemoveNode(IMFTopology *iface, IMFTopologyNode *node) { - FIXME("(%p)->(%p)\n", iface, node); + struct topology *topology = impl_from_IMFTopology(iface); + unsigned int i = 0; + IUnknown *element;
- return E_NOTIMPL; + TRACE("(%p)->(%p)\n", iface, node); + + while (IMFCollection_GetElement(topology->nodes, i, &element) == S_OK) + { + BOOL match = element == (IUnknown *)node; + + IUnknown_Release(element); + + if (match) + { + IMFCollection_RemoveElement(topology->nodes, i, &element); + IUnknown_Release(element); + return S_OK; + } + + ++i; + } + + return E_INVALIDARG; }
static HRESULT WINAPI topology_GetNodeCount(IMFTopology *iface, WORD *count) { - FIXME("(%p)->(%p)\n", iface, count); + struct topology *topology = impl_from_IMFTopology(iface); + DWORD nodecount; + HRESULT hr;
- return E_NOTIMPL; + TRACE("(%p)->(%p)\n", iface, count); + + hr = IMFCollection_GetElementCount(topology->nodes, count ? &nodecount : NULL); + if (count) + *count = nodecount; + + return hr; }
static HRESULT WINAPI topology_GetNode(IMFTopology *iface, WORD index, IMFTopologyNode **node) { - FIXME("(%p)->(%u, %p)\n", iface, index, node); + struct topology *topology = impl_from_IMFTopology(iface);
- return E_NOTIMPL; + TRACE("(%p)->(%u, %p)\n", iface, index, node); + + if (!node) + return E_POINTER; + + return SUCCEEDED(IMFCollection_GetElement(topology->nodes, index, (IUnknown **)node)) ? + S_OK : MF_E_INVALIDINDEX; }
static HRESULT WINAPI topology_Clear(IMFTopology *iface) { - FIXME("(%p)\n", iface); + struct topology *topology = impl_from_IMFTopology(iface);
- return E_NOTIMPL; + TRACE("(%p)\n", iface); + + return IMFCollection_RemoveAllElements(topology->nodes); }
static HRESULT WINAPI topology_CloneFrom(IMFTopology *iface, IMFTopology *src_topology) @@ -445,9 +528,11 @@ static HRESULT WINAPI topology_CloneFrom(IMFTopology *iface, IMFTopology *src_to
static HRESULT WINAPI topology_GetNodeByID(IMFTopology *iface, TOPOID id, IMFTopologyNode **node) { - FIXME("(%p)->(%p)\n", iface, node); + struct topology *topology = impl_from_IMFTopology(iface);
- return E_NOTIMPL; + TRACE("(%p)->(%p)\n", iface, node); + + return topology_get_node_by_id(topology, id, node); }
static HRESULT WINAPI topology_GetSourceNodeCollection(IMFTopology *iface, IMFCollection **collection) @@ -530,10 +615,14 @@ HRESULT WINAPI MFCreateTopology(IMFTopology **topology)
object->IMFTopology_iface.lpVtbl = &topologyvtbl; object->refcount = 1; + hr = MFCreateAttributes(&object->attributes, 0); + if (SUCCEEDED(hr)) + hr = MFCreateCollection(&object->nodes); + if (FAILED(hr)) { - heap_free(object); + IMFTopology_Release(&object->IMFTopology_iface); return hr; }
From: Gijs Vermeulen gijsvrm@gmail.com
Signed-off-by: Gijs Vermeulen gijsvrm@gmail.com Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 18 ++++++++++++++++++ dlls/mfplat/mfplat.spec | 4 ++-- dlls/mfplat/tests/mfplat.c | 21 +++++++++++++++++++++ include/mfapi.h | 10 ++++++++++ 4 files changed, 51 insertions(+), 2 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index e9b0abb041..a38c03b4d1 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -4124,3 +4124,21 @@ HRESULT WINAPI MFCreateCollection(IMFCollection **collection)
return S_OK; } + +/*********************************************************************** + * MFHeapAlloc (mfplat.@) + */ +void *WINAPI MFHeapAlloc(SIZE_T size, ULONG flags, char *file, int line, EAllocationType type) +{ + TRACE("%lu, %#x, %s, %d, %#x.\n", size, flags, debugstr_a(file), line, type); + return HeapAlloc(GetProcessHeap(), flags, size); +} + +/*********************************************************************** + * MFHeapFree (mfplat.@) + */ +void WINAPI MFHeapFree(void *p) +{ + TRACE("%p\n", p); + HeapFree(GetProcessHeap(), 0, p); +} diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index b35b33558f..c4e0b2abfa 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -103,8 +103,8 @@ @ stub MFGetUncompressedVideoFormat @ stub MFGetWorkQueueMMCSSClass @ stub MFGetWorkQueueMMCSSTaskId -@ stub MFHeapAlloc -@ stub MFHeapFree +@ stdcall MFHeapAlloc(long long str long long) +@ stdcall MFHeapFree(ptr) @ stub MFInitAMMediaTypeFromMFMediaType @ stub MFInitAttributesFromBlob @ stub MFInitMediaTypeFromAMMediaType diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index d0ae80a1e3..609faa5d00 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -41,6 +41,8 @@ static HRESULT (WINAPI *pMFCopyImage)(BYTE *dest, LONG deststride, const BYTE *s static HRESULT (WINAPI *pMFCreateSourceResolver)(IMFSourceResolver **resolver); static HRESULT (WINAPI *pMFCreateMFByteStreamOnStream)(IStream *stream, IMFByteStream **bytestream); static HRESULT (WINAPI *pMFCreateMemoryBuffer)(DWORD max_length, IMFMediaBuffer **buffer); +static void* (WINAPI *pMFHeapAlloc)(SIZE_T size, ULONG flags, char *file, int line, EAllocationType type); +static void (WINAPI *pMFHeapFree)(void *p);
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
@@ -314,6 +316,8 @@ static void init_functions(void) X(MFCreateSourceResolver); X(MFCreateMFByteStreamOnStream); X(MFCreateMemoryBuffer); + X(MFHeapAlloc); + X(MFHeapFree); #undef X }
@@ -1015,6 +1019,22 @@ static void test_MFCreateCollection(void) IMFCollection_Release(collection); }
+static void test_MFHeapAlloc(void) +{ + void *res; + + if (!pMFHeapAlloc) + { + win_skip("MFHeapAlloc() is not available.\n"); + return; + } + + res = pMFHeapAlloc(16, 0, NULL, 0, eAllocationTypeIgnore); + ok(res != NULL, "MFHeapAlloc failed.\n"); + + pMFHeapFree(res); +} + START_TEST(mfplat) { CoInitialize(NULL); @@ -1035,6 +1055,7 @@ START_TEST(mfplat) test_allocate_queue(); test_MFCopyImage(); test_MFCreateCollection(); + test_MFHeapAlloc();
CoUninitialize(); } diff --git a/include/mfapi.h b/include/mfapi.h index 5797db1152..7c47213d85 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -68,6 +68,14 @@ typedef struct tagMFASYNCRESULT HANDLE hEvent; } MFASYNCRESULT;
+typedef enum _EAllocationType +{ + eAllocationTypeDynamic, + eAllocationTypeRT, + eAllocationTypePageable, + eAllocationTypeIgnore +} EAllocationType; + 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); DEFINE_GUID(MF_MT_FRAME_SIZE, 0x1652c33d, 0xd6b2, 0x4012, 0xb8, 0x34, 0x72, 0x03, 0x08, 0x49, 0xa3, 0x7d); @@ -94,6 +102,8 @@ HRESULT WINAPI MFCreateMediaEvent(MediaEventType type, REFGUID extended_type, HR HRESULT WINAPI MFCreateMediaType(IMFMediaType **type); HRESULT WINAPI MFCreateSample(IMFSample **sample); HRESULT WINAPI MFCreateMemoryBuffer(DWORD max_length, IMFMediaBuffer **buffer); +void * WINAPI MFHeapAlloc(SIZE_T size, ULONG flags, char *file, int line, EAllocationType type); +void WINAPI MFHeapFree(void *ptr); HRESULT WINAPI MFGetTimerPeriodicity(DWORD *periodicity); HRESULT WINAPI MFTEnum(GUID category, UINT32 flags, MFT_REGISTER_TYPE_INFO *input_type, MFT_REGISTER_TYPE_INFO *output_type, IMFAttributes *attributes,