Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/mf_private.h | 29 +++++++ dlls/mf/tests/mf.c | 163 +++++++++++++++++++++++++++++++++------ dlls/mf/topology.c | 176 ++++++++++++++++++++++++++++++++++++++----- 3 files changed, 330 insertions(+), 38 deletions(-)
diff --git a/dlls/mf/mf_private.h b/dlls/mf/mf_private.h index b5b4e84bba..45a3834eec 100644 --- a/dlls/mf/mf_private.h +++ b/dlls/mf/mf_private.h @@ -18,6 +18,35 @@
#include "mfidl.h"
+#include "wine/heap.h" + +static inline 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; +} + struct activate_funcs { HRESULT (*create_object)(void *context, IUnknown **object); diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index cea5f98f6e..4974e043af 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -77,11 +77,12 @@ static void test_topology(void) IUnknown test_unk2 = { &test_unk_vtbl }; IUnknown test_unk = { &test_unk_vtbl }; IMFTopologyNode *node, *node2, *node3; + IMFMediaType *mediatype, *mediatype2; IMFTopology *topology, *topology2; - UINT32 attr_count; IUnknown *object; + WORD node_count; + UINT32 count; DWORD size; - WORD count; HRESULT hr; TOPOID id;
@@ -132,19 +133,19 @@ static void test_topology(void) hr = IMFTopology_AddNode(topology, NULL); ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
- count = 1; - hr = IMFTopology_GetNodeCount(topology, &count); + node_count = 1; + hr = IMFTopology_GetNodeCount(topology, &node_count); ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr); - ok(count == 0, "Unexpected node count %u.\n", count); + ok(node_count == 0, "Unexpected node count %u.\n", node_count);
/* Same id, different nodes. */ hr = IMFTopology_AddNode(topology, node); ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr);
- count = 0; - hr = IMFTopology_GetNodeCount(topology, &count); + node_count = 0; + hr = IMFTopology_GetNodeCount(topology, &node_count); ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr); - ok(count == 1, "Unexpected node count %u.\n", count); + ok(node_count == 1, "Unexpected node count %u.\n", node_count);
hr = IMFTopology_AddNode(topology, node2); ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); @@ -190,10 +191,10 @@ static void test_topology(void) ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); IMFTopologyNode_Release(node2);
- count = 0; - hr = IMFTopology_GetNodeCount(topology, &count); + node_count = 0; + hr = IMFTopology_GetNodeCount(topology, &node_count); ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr); - ok(count == 2, "Unexpected node count %u.\n", count); + ok(node_count == 2, "Unexpected node count %u.\n", node_count);
/* Remove with detached node, existing id. */ hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node2); @@ -207,18 +208,18 @@ static void test_topology(void) hr = IMFTopology_RemoveNode(topology, node); ok(hr == S_OK, "Failed to remove a node, hr %#x.\n", hr);
- count = 0; - hr = IMFTopology_GetNodeCount(topology, &count); + node_count = 0; + hr = IMFTopology_GetNodeCount(topology, &node_count); ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr); - ok(count == 1, "Unexpected node count %u.\n", count); + ok(node_count == 1, "Unexpected node count %u.\n", node_count);
hr = IMFTopology_Clear(topology); ok(hr == S_OK, "Failed to clear topology, hr %#x.\n", hr);
- count = 1; - hr = IMFTopology_GetNodeCount(topology, &count); + node_count = 1; + hr = IMFTopology_GetNodeCount(topology, &node_count); ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr); - ok(count == 0, "Unexpected node count %u.\n", count); + ok(node_count == 0, "Unexpected node count %u.\n", node_count);
hr = IMFTopology_Clear(topology); ok(hr == S_OK, "Failed to clear topology, hr %#x.\n", hr); @@ -366,9 +367,9 @@ static void test_topology(void) hr = IMFTopologyNode_SetObject(node, &test_unk2); ok(hr == S_OK, "Failed to set object, hr %#x.\n", hr);
- hr = IMFTopologyNode_GetCount(node, &attr_count); + hr = IMFTopologyNode_GetCount(node, &count); ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr); - ok(attr_count == 0, "Unexpected attribute count %u.\n", attr_count); + ok(count == 0, "Unexpected attribute count %u.\n", count);
hr = IMFTopologyNode_SetGUID(node, &MF_TOPONODE_TRANSFORM_OBJECTID, &MF_TOPONODE_TRANSFORM_OBJECTID); ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); @@ -381,12 +382,132 @@ static void test_topology(void) ok(hr == E_FAIL, "Unexpected hr %#x.\n", hr); ok(!object, "Unexpected object %p.\n", object);
- hr = IMFTopologyNode_GetCount(node, &attr_count); + hr = IMFTopologyNode_GetCount(node, &count); ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr); - ok(attr_count == 1, "Unexpected attribute count %u.\n", attr_count); + ok(count == 1, "Unexpected attribute count %u.\n", count); + + /* Preferred stream types. */ + hr = IMFTopologyNode_GetInputCount(node, &count); + ok(hr == S_OK, "Failed to get input count, hr %#x.\n", hr); + ok(count == 0, "Unexpected count %u.\n", count); + + hr = IMFTopologyNode_GetInputPrefType(node, 0, &mediatype); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = MFCreateMediaType(&mediatype); + ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetInputPrefType(node, 0, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#x.\n", hr); + + hr = IMFTopologyNode_GetInputPrefType(node, 0, &mediatype2); + ok(hr == S_OK, "Failed to get preferred type, hr %#x.\n", hr); + ok(mediatype2 == mediatype, "Unexpected mediatype instance.\n"); + IMFMediaType_Release(mediatype2); + + hr = IMFTopologyNode_SetInputPrefType(node, 0, NULL); + ok(hr == S_OK, "Failed to set preferred type, hr %#x.\n", hr); + + hr = IMFTopologyNode_GetInputPrefType(node, 0, &mediatype2); + ok(hr == E_FAIL, "Unexpected hr %#x.\n", hr); + ok(!mediatype2, "Unexpected mediatype instance.\n"); + + hr = IMFTopologyNode_SetInputPrefType(node, 1, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetInputPrefType(node, 1, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#x.\n", hr); + + hr = IMFTopologyNode_GetInputCount(node, &count); + ok(hr == S_OK, "Failed to get input count, hr %#x.\n", hr); + ok(count == 2, "Unexpected count %u.\n", count); + + hr = IMFTopologyNode_GetOutputCount(node, &count); + ok(hr == S_OK, "Failed to get input count, hr %#x.\n", hr); + ok(count == 0, "Unexpected count %u.\n", count); + + hr = IMFTopologyNode_SetOutputPrefType(node, 0, mediatype); + ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); + + IMFTopologyNode_Release(node); + + /* Source node. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); + ok(hr == S_OK, "Failed to create a node, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetInputPrefType(node, 0, mediatype); + ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); + + hr = IMFTopologyNode_SetOutputPrefType(node, 2, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#x.\n", hr); + + hr = IMFTopologyNode_GetOutputPrefType(node, 0, &mediatype2); + ok(hr == E_FAIL, "Failed to get preferred type, hr %#x.\n", hr); + ok(!mediatype2, "Unexpected mediatype instance.\n"); + + hr = IMFTopologyNode_GetOutputCount(node, &count); + ok(hr == S_OK, "Failed to get output count, hr %#x.\n", hr); + ok(count == 3, "Unexpected count %u.\n", count);
IMFTopologyNode_Release(node);
+ /* Tee node. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node); + ok(hr == S_OK, "Failed to create a node, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetInputPrefType(node, 0, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#x.\n", hr); + + hr = IMFTopologyNode_GetInputPrefType(node, 0, &mediatype2); + ok(hr == S_OK, "Failed to get preferred type, hr %#x.\n", hr); + ok(mediatype2 == mediatype, "Unexpected mediatype instance.\n"); + IMFMediaType_Release(mediatype2); + + hr = IMFTopologyNode_GetInputCount(node, &count); + ok(hr == S_OK, "Failed to get output count, hr %#x.\n", hr); + ok(count == 0, "Unexpected count %u.\n", count); + + hr = IMFTopologyNode_SetInputPrefType(node, 1, mediatype); + ok(hr == MF_E_INVALIDTYPE, "Unexpected hr %#x.\n", hr); + + hr = IMFTopologyNode_SetInputPrefType(node, 3, mediatype); + ok(hr == MF_E_INVALIDTYPE, "Unexpected hr %#x.\n", hr); + + hr = IMFTopologyNode_SetOutputPrefType(node, 4, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#x.\n", hr); + + hr = IMFTopologyNode_GetInputCount(node, &count); + ok(hr == S_OK, "Failed to get output count, hr %#x.\n", hr); + ok(count == 0, "Unexpected count %u.\n", count); + + hr = IMFTopologyNode_GetOutputCount(node, &count); + ok(hr == S_OK, "Failed to get output count, hr %#x.\n", hr); + ok(count == 5, "Unexpected count %u.\n", count); + + IMFTopologyNode_Release(node); + + /* Transform node. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node); + ok(hr == S_OK, "Failed to create a node, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetInputPrefType(node, 3, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetOutputPrefType(node, 4, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#x.\n", hr); + + hr = IMFTopologyNode_GetInputCount(node, &count); + ok(hr == S_OK, "Failed to get output count, hr %#x.\n", hr); + ok(count == 4, "Unexpected count %u.\n", count); + + hr = IMFTopologyNode_GetOutputCount(node, &count); + ok(hr == S_OK, "Failed to get output count, hr %#x.\n", hr); + ok(count == 5, "Unexpected count %u.\n", count); + + IMFTopologyNode_Release(node); + + IMFMediaType_Release(mediatype); + hr = IMFTopology_GetOutputNodeCollection(topology, &collection); ok(hr == S_OK || broken(hr == E_FAIL) /* before Win8 */, "Failed to get output node collection, hr %#x.\n", hr); if (SUCCEEDED(hr)) diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index e01444b8ce..f40fe00c17 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -37,7 +37,8 @@ #include "mfidl.h"
#include "wine/debug.h" -#include "wine/heap.h" + +#include "mf_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
@@ -53,6 +54,11 @@ struct topology TOPOID id; };
+struct node_stream +{ + IMFMediaType *preferred_type; +}; + struct topology_node { IMFTopologyNode IMFTopologyNode_iface; @@ -61,6 +67,18 @@ struct topology_node MF_TOPOLOGY_TYPE node_type; TOPOID id; IUnknown *object; + struct + { + struct node_stream *streams; + size_t size; + size_t count; + } inputs; + struct + { + struct node_stream *streams; + size_t size; + size_t count; + } outputs; CRITICAL_SECTION cs; };
@@ -758,6 +776,7 @@ static ULONG WINAPI topology_node_Release(IMFTopologyNode *iface) { struct topology_node *node = impl_from_IMFTopologyNode(iface); ULONG refcount = InterlockedDecrement(&node->refcount); + unsigned int i;
TRACE("(%p) refcount=%u\n", iface, refcount);
@@ -765,6 +784,18 @@ static ULONG WINAPI topology_node_Release(IMFTopologyNode *iface) { if (node->object) IUnknown_Release(node->object); + for (i = 0; i < node->inputs.count; ++i) + { + if (node->inputs.streams[i].preferred_type) + IMFMediaType_Release(node->inputs.streams[i].preferred_type); + } + for (i = 0; i < node->outputs.count; ++i) + { + if (node->outputs.streams[i].preferred_type) + IMFMediaType_Release(node->outputs.streams[i].preferred_type); + } + heap_free(node->inputs.streams); + heap_free(node->outputs.streams); IMFAttributes_Release(node->attributes); DeleteCriticalSection(&node->cs); heap_free(node); @@ -1154,16 +1185,31 @@ static HRESULT WINAPI topology_node_SetTopoNodeID(IMFTopologyNode *iface, TOPOID
static HRESULT WINAPI topology_node_GetInputCount(IMFTopologyNode *iface, DWORD *count) { - FIXME("(%p)->(%p)\n", iface, count); + struct topology_node *node = impl_from_IMFTopologyNode(iface);
- return E_NOTIMPL; + TRACE("%p, %p.\n", iface, count); + + switch (node->node_type) + { + case MF_TOPOLOGY_TEE_NODE: + *count = 0; + break; + default: + *count = node->inputs.count; + } + + return S_OK; }
static HRESULT WINAPI topology_node_GetOutputCount(IMFTopologyNode *iface, DWORD *count) { - FIXME("(%p)->(%p)\n", iface, count); + struct topology_node *node = impl_from_IMFTopologyNode(iface);
- return E_NOTIMPL; + TRACE("%p, %p.\n", iface, count); + + *count = node->outputs.count; + + return S_OK; }
static HRESULT WINAPI topology_node_ConnectOutput(IMFTopologyNode *iface, DWORD output_index, @@ -1197,32 +1243,128 @@ static HRESULT WINAPI topology_node_GetOutput(IMFTopologyNode *iface, DWORD outp return E_NOTIMPL; }
-static HRESULT WINAPI topology_node_SetOutputPrefType(IMFTopologyNode *iface, DWORD index, IMFMediaType *type) +static HRESULT WINAPI topology_node_SetOutputPrefType(IMFTopologyNode *iface, DWORD index, IMFMediaType *mediatype) { - FIXME("(%p)->(%u, %p)\n", iface, index, type); + struct topology_node *node = impl_from_IMFTopologyNode(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %u, %p.\n", iface, index, mediatype); + + EnterCriticalSection(&node->cs); + + if (node->node_type != MF_TOPOLOGY_OUTPUT_NODE) + { + if (mf_array_reserve((void **)&node->outputs.streams, &node->outputs.size, index + 1, + sizeof(*node->outputs.streams))) + { + if (index >= node->outputs.count) + { + memset(&node->outputs.streams[node->outputs.count], 0, + (index - node->outputs.count + 1) * sizeof(*node->outputs.streams)); + node->outputs.count = index + 1; + } + if (node->outputs.streams[index].preferred_type) + IMFMediaType_Release(node->outputs.streams[index].preferred_type); + node->outputs.streams[index].preferred_type = mediatype; + if (node->outputs.streams[index].preferred_type) + IMFMediaType_AddRef(node->outputs.streams[index].preferred_type); + } + else + hr = E_OUTOFMEMORY; + } + else + hr = E_NOTIMPL; + + LeaveCriticalSection(&node->cs); + + return hr; }
-static HRESULT WINAPI topology_node_GetOutputPrefType(IMFTopologyNode *iface, DWORD output_index, IMFMediaType **type) +static HRESULT WINAPI topology_node_GetOutputPrefType(IMFTopologyNode *iface, DWORD index, IMFMediaType **mediatype) { - FIXME("(%p)->(%u, %p)\n", iface, output_index, type); + struct topology_node *node = impl_from_IMFTopologyNode(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %u, %p.\n", iface, index, mediatype); + + EnterCriticalSection(&node->cs); + + if (index < node->outputs.count) + { + *mediatype = node->outputs.streams[index].preferred_type; + if (*mediatype) + IMFMediaType_AddRef(*mediatype); + else + hr = E_FAIL; + } + else + hr = E_INVALIDARG; + + LeaveCriticalSection(&node->cs); + + return hr; }
-static HRESULT WINAPI topology_node_SetInputPrefType(IMFTopologyNode *iface, DWORD index, IMFMediaType *type) +static HRESULT WINAPI topology_node_SetInputPrefType(IMFTopologyNode *iface, DWORD index, IMFMediaType *mediatype) { - FIXME("(%p)->(%u, %p)\n", iface, index, type); + struct topology_node *node = impl_from_IMFTopologyNode(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %u, %p.\n", iface, index, mediatype); + + EnterCriticalSection(&node->cs); + + if (node->node_type != MF_TOPOLOGY_SOURCESTREAM_NODE && !(index > 0 && node->node_type == MF_TOPOLOGY_TEE_NODE)) + { + if (mf_array_reserve((void **)&node->inputs.streams, &node->inputs.size, index + 1, + sizeof(*node->inputs.streams))) + { + if (index >= node->inputs.count) + { + memset(&node->inputs.streams[node->inputs.count], 0, + (index - node->inputs.count + 1) * sizeof(*node->inputs.streams)); + node->inputs.count = index + 1; + } + if (node->inputs.streams[index].preferred_type) + IMFMediaType_Release(node->inputs.streams[index].preferred_type); + node->inputs.streams[index].preferred_type = mediatype; + if (node->inputs.streams[index].preferred_type) + IMFMediaType_AddRef(node->inputs.streams[index].preferred_type); + } + else + hr = E_OUTOFMEMORY; + } + else + hr = node->node_type == MF_TOPOLOGY_TEE_NODE ? MF_E_INVALIDTYPE : E_NOTIMPL; + + LeaveCriticalSection(&node->cs); + + return hr; }
-static HRESULT WINAPI topology_node_GetInputPrefType(IMFTopologyNode *iface, DWORD index, IMFMediaType **type) +static HRESULT WINAPI topology_node_GetInputPrefType(IMFTopologyNode *iface, DWORD index, IMFMediaType **mediatype) { - FIXME("(%p)->(%u, %p)\n", iface, index, type); + struct topology_node *node = impl_from_IMFTopologyNode(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %u, %p.\n", iface, index, mediatype); + + EnterCriticalSection(&node->cs); + + if (index < node->inputs.count) + { + *mediatype = node->inputs.streams[index].preferred_type; + if (*mediatype) + IMFMediaType_AddRef(*mediatype); + else + hr = E_FAIL; + } + else + hr = E_INVALIDARG; + + LeaveCriticalSection(&node->cs); + + return hr; }
static HRESULT WINAPI topology_node_CloneFrom(IMFTopologyNode *iface, IMFTopologyNode *node)