Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/tests/mf.c | 115 +++++++++++++++++++++- dlls/mf/topology.c | 235 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 308 insertions(+), 42 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 4974e043af..8b3b8b4373 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -39,7 +39,15 @@ DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
#include "wine/test.h"
-DEFINE_GUID(GUID_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); +#define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__) +static void _expect_ref(IUnknown* obj, ULONG expected_refcount, int line) +{ + ULONG refcount; + IUnknown_AddRef(obj); + refcount = IUnknown_Release(obj); + ok_(__FILE__, line)(refcount == expected_refcount, "Unexpected refcount %d, expected %d.\n", refcount, + expected_refcount); +}
static HRESULT WINAPI test_unk_QueryInterface(IUnknown *iface, REFIID riid, void **obj) { @@ -79,9 +87,10 @@ static void test_topology(void) IMFTopologyNode *node, *node2, *node3; IMFMediaType *mediatype, *mediatype2; IMFTopology *topology, *topology2; + MF_TOPOLOGY_TYPE node_type; + UINT32 count, index; IUnknown *object; WORD node_count; - UINT32 count; DWORD size; HRESULT hr; TOPOID id; @@ -520,6 +529,108 @@ static void test_topology(void) }
IMFTopology_Release(topology); + + /* Connect nodes. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); + ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node2); + ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr); + + EXPECT_REF(node, 1); + EXPECT_REF(node2, 1); + + hr = IMFTopologyNode_ConnectOutput(node, 0, node2, 1); + ok(hr == S_OK, "Failed to connect nodes, hr %#x.\n", hr); + + EXPECT_REF(node, 2); + EXPECT_REF(node2, 2); + + IMFTopologyNode_Release(node); + + EXPECT_REF(node, 1); + EXPECT_REF(node2, 2); + + IMFTopologyNode_Release(node2); + + EXPECT_REF(node, 1); + EXPECT_REF(node2, 1); + + hr = IMFTopologyNode_GetNodeType(node2, &node_type); + ok(hr == S_OK, "Failed to get node type, hr %#x.\n", hr); + + IMFTopologyNode_Release(node); + + /* Connect within topology. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); + ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node2); + ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr); + + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "Failed to create topology, hr %#x.\n", hr); + + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); + + hr = IMFTopology_AddNode(topology, node2); + ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); + + EXPECT_REF(node, 2); + EXPECT_REF(node2, 2); + + hr = IMFTopologyNode_ConnectOutput(node, 0, node2, 1); + ok(hr == S_OK, "Failed to connect nodes, hr %#x.\n", hr); + + EXPECT_REF(node, 3); + EXPECT_REF(node2, 3); + + hr = IMFTopology_Clear(topology); + ok(hr == S_OK, "Failed to clear topology, hr %#x.\n", hr); + +todo_wine { + EXPECT_REF(node, 1); + EXPECT_REF(node2, 1); +} + /* Removing connected node breaks connection. */ + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); + + hr = IMFTopology_AddNode(topology, node2); + ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); + + hr = IMFTopologyNode_ConnectOutput(node, 0, node2, 1); + ok(hr == S_OK, "Failed to connect nodes, hr %#x.\n", hr); + + hr = IMFTopology_RemoveNode(topology, node); + ok(hr == S_OK, "Failed to remove a node, hr %#x.\n", hr); + +todo_wine { + EXPECT_REF(node, 1); + EXPECT_REF(node2, 2); +} + hr = IMFTopologyNode_GetOutput(node, 0, &node3, &index); +todo_wine + ok(hr == MF_E_NOT_FOUND, "Unexpected hr %#x.\n", hr); + + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); + + hr = IMFTopologyNode_ConnectOutput(node, 0, node2, 1); + ok(hr == S_OK, "Failed to connect nodes, hr %#x.\n", hr); + + hr = IMFTopology_RemoveNode(topology, node2); + ok(hr == S_OK, "Failed to remove a node, hr %#x.\n", hr); + +todo_wine { + EXPECT_REF(node, 2); + EXPECT_REF(node2, 1); +} + IMFTopologyNode_Release(node); + IMFTopologyNode_Release(node2); + + IMFTopology_Release(topology); }
static HRESULT WINAPI test_getservice_QI(IMFGetService *iface, REFIID riid, void **obj) diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 298200c40d..eaae7c910c 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -57,6 +57,15 @@ struct topology struct node_stream { IMFMediaType *preferred_type; + struct topology_node *connection; + DWORD connection_stream; +}; + +struct node_streams +{ + struct node_stream *streams; + size_t size; + size_t count; };
struct topology_node @@ -67,18 +76,8 @@ 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; + struct node_streams inputs; + struct node_streams outputs; CRITICAL_SECTION cs; };
@@ -104,6 +103,15 @@ static struct topology_node *impl_from_IMFTopologyNode(IMFTopologyNode *iface) return CONTAINING_RECORD(iface, struct topology_node, IMFTopologyNode_iface); }
+static const IMFTopologyNodeVtbl topologynodevtbl; + +static struct topology_node *unsafe_impl_from_IMFTopologyNode(IMFTopologyNode *iface) +{ + if (!iface || iface->lpVtbl != &topologynodevtbl) + return NULL; + return impl_from_IMFTopologyNode(iface); +} + static struct topology_loader *impl_from_IMFTopoLoader(IMFTopoLoader *iface) { return CONTAINING_RECORD(iface, struct topology_loader, IMFTopoLoader_iface); @@ -114,6 +122,20 @@ static struct seq_source *impl_from_IMFSequencerSource(IMFSequencerSource *iface return CONTAINING_RECORD(iface, struct seq_source, IMFSequencerSource_iface); }
+static HRESULT topology_node_reserve_streams(struct node_streams *streams, DWORD index) +{ + if (!mf_array_reserve((void **)&streams->streams, &streams->size, index + 1, sizeof(*streams->streams))) + return E_OUTOFMEMORY; + + if (index >= streams->count) + { + memset(&streams->streams[streams->count], 0, (index - streams->count + 1) * sizeof(*streams->streams)); + streams->count = index + 1; + } + + return S_OK; +} + static HRESULT WINAPI topology_QueryInterface(IMFTopology *iface, REFIID riid, void **out) { struct topology *topology = impl_from_IMFTopology(iface); @@ -459,14 +481,17 @@ static HRESULT topology_get_node_by_id(const struct topology *topology, TOPOID i IMFTopologyNode *iter; unsigned int i = 0;
- while (IMFCollection_GetElement(topology->nodes, i, (IUnknown **)&iter) == S_OK) + while (IMFCollection_GetElement(topology->nodes, i++, (IUnknown **)&iter) == S_OK) { TOPOID node_id; HRESULT hr;
hr = IMFTopologyNode_GetTopoNodeID(iter, &node_id); if (FAILED(hr)) + { + IMFTopologyNode_Release(iter); return hr; + }
if (node_id == id) { @@ -474,7 +499,7 @@ static HRESULT topology_get_node_by_id(const struct topology *topology, TOPOID i return S_OK; }
- ++i; + IMFTopologyNode_Release(iter); }
return MF_E_NOT_FOUND; @@ -1218,35 +1243,177 @@ static HRESULT WINAPI topology_node_GetOutputCount(IMFTopologyNode *iface, DWORD return S_OK; }
+static HRESULT topology_node_disconnect_output(struct topology_node *node, DWORD output_index) +{ + struct topology_node *connection = NULL; + struct node_stream *stream; + DWORD connection_stream; + HRESULT hr = S_OK; + + EnterCriticalSection(&node->cs); + + if (output_index < node->outputs.count) + { + stream = &node->outputs.streams[output_index]; + + if (stream->connection) + { + connection = stream->connection; + connection_stream = stream->connection_stream; + stream->connection = NULL; + stream->connection_stream = 0; + } + else + hr = MF_E_NOT_FOUND; + } + else + hr = E_INVALIDARG; + + LeaveCriticalSection(&node->cs); + + if (connection) + { + EnterCriticalSection(&connection->cs); + + if (connection_stream < connection->inputs.count) + { + stream = &connection->inputs.streams[connection_stream]; + + if (stream->connection) + { + stream->connection = NULL; + stream->connection_stream = 0; + } + } + + LeaveCriticalSection(&connection->cs); + + IMFTopologyNode_Release(&connection->IMFTopologyNode_iface); + IMFTopologyNode_Release(&node->IMFTopologyNode_iface); + } + + return hr; +} + static HRESULT WINAPI topology_node_ConnectOutput(IMFTopologyNode *iface, DWORD output_index, - IMFTopologyNode *node, DWORD input_index) + IMFTopologyNode *peer, DWORD input_index) { - FIXME("(%p)->(%u, %p, %u)\n", iface, output_index, node, input_index); + struct topology_node *node = impl_from_IMFTopologyNode(iface); + struct topology_node *connection = unsafe_impl_from_IMFTopologyNode(peer); + struct node_stream *stream; + HRESULT hr;
- return E_NOTIMPL; + TRACE("%p, %u, %p, %u.\n", iface, output_index, peer, input_index); + + if (!connection) + { + WARN("External node implementations are not supported.\n"); + return E_UNEXPECTED; + } + + if (node->node_type == MF_TOPOLOGY_OUTPUT_NODE || connection->node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) + return E_FAIL; + + EnterCriticalSection(&node->cs); + EnterCriticalSection(&connection->cs); + + topology_node_disconnect_output(node, output_index); + if (input_index < connection->inputs.count) + { + stream = &connection->inputs.streams[input_index]; + if (stream->connection) + topology_node_disconnect_output(stream->connection, stream->connection_stream); + } + + hr = topology_node_reserve_streams(&node->outputs, output_index); + if (SUCCEEDED(hr)) + hr = topology_node_reserve_streams(&connection->inputs, input_index); + + if (SUCCEEDED(hr)) + { + node->outputs.streams[output_index].connection = connection; + IMFTopologyNode_AddRef(&node->outputs.streams[output_index].connection->IMFTopologyNode_iface); + node->outputs.streams[output_index].connection_stream = input_index; + connection->inputs.streams[input_index].connection = node; + IMFTopologyNode_AddRef(&connection->inputs.streams[input_index].connection->IMFTopologyNode_iface); + connection->inputs.streams[input_index].connection_stream = output_index; + } + + LeaveCriticalSection(&connection->cs); + LeaveCriticalSection(&node->cs); + + return hr; }
-static HRESULT WINAPI topology_node_DisconnectOutput(IMFTopologyNode *iface, DWORD index) +static HRESULT WINAPI topology_node_DisconnectOutput(IMFTopologyNode *iface, DWORD output_index) { - FIXME("(%p)->(%u)\n", iface, index); + struct topology_node *node = impl_from_IMFTopologyNode(iface);
- return E_NOTIMPL; + TRACE("%p, %u.\n", iface, output_index); + + return topology_node_disconnect_output(node, output_index); }
-static HRESULT WINAPI topology_node_GetInput(IMFTopologyNode *iface, DWORD input_index, IMFTopologyNode **node, +static HRESULT WINAPI topology_node_GetInput(IMFTopologyNode *iface, DWORD input_index, IMFTopologyNode **ret, DWORD *output_index) { - FIXME("(%p)->(%u, %p, %p)\n", iface, input_index, node, output_index); + struct topology_node *node = impl_from_IMFTopologyNode(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %u, %p, %p.\n", iface, input_index, ret, output_index); + + EnterCriticalSection(&node->cs); + + if (input_index < node->inputs.count) + { + const struct node_stream *stream = &node->inputs.streams[input_index]; + + if (stream->connection) + { + *ret = &stream->connection->IMFTopologyNode_iface; + IMFTopologyNode_AddRef(*ret); + *output_index = stream->connection_stream; + } + else + hr = MF_E_NOT_FOUND; + } + else + hr = E_INVALIDARG; + + LeaveCriticalSection(&node->cs); + + return hr; }
-static HRESULT WINAPI topology_node_GetOutput(IMFTopologyNode *iface, DWORD output_index, IMFTopologyNode **node, +static HRESULT WINAPI topology_node_GetOutput(IMFTopologyNode *iface, DWORD output_index, IMFTopologyNode **ret, DWORD *input_index) { - FIXME("(%p)->(%u, %p, %p)\n", iface, output_index, node, input_index); + struct topology_node *node = impl_from_IMFTopologyNode(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %u, %p, %p.\n", iface, output_index, ret, input_index); + + EnterCriticalSection(&node->cs); + + if (output_index < node->outputs.count) + { + const struct node_stream *stream = &node->outputs.streams[output_index]; + + if (stream->connection) + { + *ret = &stream->connection->IMFTopologyNode_iface; + IMFTopologyNode_AddRef(*ret); + *input_index = stream->connection_stream; + } + else + hr = MF_E_NOT_FOUND; + } + else + hr = E_INVALIDARG; + + LeaveCriticalSection(&node->cs); + + return hr; }
static HRESULT WINAPI topology_node_SetOutputPrefType(IMFTopologyNode *iface, DWORD index, IMFMediaType *mediatype) @@ -1260,23 +1427,14 @@ static HRESULT WINAPI topology_node_SetOutputPrefType(IMFTopologyNode *iface, DW
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 (SUCCEEDED(hr = topology_node_reserve_streams(&node->outputs, index))) { - 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; @@ -1322,8 +1480,7 @@ static HRESULT WINAPI topology_node_SetInputPrefType(IMFTopologyNode *iface, DWO
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 (SUCCEEDED(hr = topology_node_reserve_streams(&node->inputs, index))) { if (index >= node->inputs.count) { @@ -1337,8 +1494,6 @@ static HRESULT WINAPI topology_node_SetInputPrefType(IMFTopologyNode *iface, DWO 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;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/topology.c | 193 +++++++++++++++++++++++---------------------- 1 file changed, 99 insertions(+), 94 deletions(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index eaae7c910c..c10bc6ad02 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -45,15 +45,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); static LONG next_node_id; static TOPOID next_topology_id;
-struct topology -{ - IMFTopology IMFTopology_iface; - LONG refcount; - IMFAttributes *attributes; - IMFCollection *nodes; - TOPOID id; -}; - struct node_stream { IMFMediaType *preferred_type; @@ -81,6 +72,20 @@ struct topology_node CRITICAL_SECTION cs; };
+struct topology +{ + IMFTopology IMFTopology_iface; + LONG refcount; + IMFAttributes *attributes; + struct + { + struct topology_node **nodes; + size_t size; + size_t count; + } nodes; + TOPOID id; +}; + struct topology_loader { IMFTopoLoader IMFTopoLoader_iface; @@ -169,19 +174,32 @@ static ULONG WINAPI topology_AddRef(IMFTopology *iface) return refcount; }
+static void topology_clear(struct topology *topology) +{ + size_t i; + + for (i = 0; i < topology->nodes.count; ++i) + { + IMFTopologyNode_Release(&topology->nodes.nodes[i]->IMFTopologyNode_iface); + } + heap_free(topology->nodes.nodes); + topology->nodes.nodes = NULL; + topology->nodes.count = 0; + topology->nodes.size = 0; +} + static ULONG WINAPI topology_Release(IMFTopology *iface) { struct topology *topology = impl_from_IMFTopology(iface); ULONG refcount = InterlockedDecrement(&topology->refcount);
- TRACE("(%p) refcount=%u\n", iface, refcount); + TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount) { if (topology->attributes) IMFAttributes_Release(topology->attributes); - if (topology->nodes) - IMFCollection_Release(topology->nodes); + topology_clear(topology); heap_free(topology); }
@@ -476,80 +494,72 @@ static HRESULT WINAPI topology_GetTopologyID(IMFTopology *iface, TOPOID *id) return S_OK; }
-static HRESULT topology_get_node_by_id(const struct topology *topology, TOPOID id, IMFTopologyNode **node) +static HRESULT topology_get_node_by_id(const struct topology *topology, TOPOID id, struct topology_node **node) { - IMFTopologyNode *iter; - unsigned int i = 0; + size_t i = 0;
- while (IMFCollection_GetElement(topology->nodes, i++, (IUnknown **)&iter) == S_OK) + for (i = 0; i < topology->nodes.count; ++i) { - TOPOID node_id; - HRESULT hr; - - hr = IMFTopologyNode_GetTopoNodeID(iter, &node_id); - if (FAILED(hr)) - { - IMFTopologyNode_Release(iter); - return hr; - } - - if (node_id == id) + if (topology->nodes.nodes[i]->id == id) { - *node = iter; + *node = topology->nodes.nodes[i]; + IMFTopologyNode_AddRef(&(*node)->IMFTopologyNode_iface); return S_OK; } - - IMFTopologyNode_Release(iter); }
return MF_E_NOT_FOUND; }
-static HRESULT WINAPI topology_AddNode(IMFTopology *iface, IMFTopologyNode *node) +static HRESULT WINAPI topology_AddNode(IMFTopology *iface, IMFTopologyNode *node_iface) { struct topology *topology = impl_from_IMFTopology(iface); - IMFTopologyNode *match; - HRESULT hr; - TOPOID id; + struct topology_node *node = unsafe_impl_from_IMFTopologyNode(node_iface); + struct topology_node *match;
- TRACE("(%p)->(%p)\n", iface, node); + TRACE("%p, %p.\n", iface, node_iface);
if (!node) return E_POINTER;
- if (FAILED(hr = IMFTopologyNode_GetTopoNodeID(node, &id))) - return hr; + if (SUCCEEDED(topology_get_node_by_id(topology, node->id, &match))) + { + IMFTopologyNode_Release(&match->IMFTopologyNode_iface); + return E_INVALIDARG; + }
- if (FAILED(topology_get_node_by_id(topology, id, &match))) - return IMFCollection_AddElement(topology->nodes, (IUnknown *)node); + if (!mf_array_reserve((void **)&topology->nodes.nodes, &topology->nodes.size, topology->nodes.count + 1, + sizeof(*topology->nodes.nodes))) + { + return E_OUTOFMEMORY; + }
- IMFTopologyNode_Release(match); + topology->nodes.nodes[topology->nodes.count++] = node; + IMFTopologyNode_AddRef(&node->IMFTopologyNode_iface);
- return E_INVALIDARG; + return S_OK; }
static HRESULT WINAPI topology_RemoveNode(IMFTopology *iface, IMFTopologyNode *node) { struct topology *topology = impl_from_IMFTopology(iface); - unsigned int i = 0; - IUnknown *element; + size_t i, count;
- TRACE("(%p)->(%p)\n", iface, node); + TRACE("%p, %p.\n", iface, node);
- while (IMFCollection_GetElement(topology->nodes, i, &element) == S_OK) + for (i = 0; i < topology->nodes.count; ++i) { - BOOL match = element == (IUnknown *)node; - - IUnknown_Release(element); - - if (match) + if (&topology->nodes.nodes[i]->IMFTopologyNode_iface == node) { - IMFCollection_RemoveElement(topology->nodes, i, &element); - IUnknown_Release(element); + count = topology->nodes.count - i - 1; + if (count) + { + memmove(&topology->nodes.nodes[i], &topology->nodes.nodes[i + 1], + count * sizeof(*topology->nodes.nodes)); + } + topology->nodes.count--; return S_OK; } - - ++i; }
return E_INVALIDARG; @@ -558,38 +568,43 @@ static HRESULT WINAPI topology_RemoveNode(IMFTopology *iface, IMFTopologyNode *n static HRESULT WINAPI topology_GetNodeCount(IMFTopology *iface, WORD *count) { struct topology *topology = impl_from_IMFTopology(iface); - DWORD nodecount; - HRESULT hr;
- TRACE("(%p)->(%p)\n", iface, count); + TRACE("%p, %p.\n", iface, count);
- hr = IMFCollection_GetElementCount(topology->nodes, count ? &nodecount : NULL); - if (count) - *count = nodecount; + if (!count) + return E_POINTER;
- return hr; + *count = topology->nodes.count; + + return S_OK; }
static HRESULT WINAPI topology_GetNode(IMFTopology *iface, WORD index, IMFTopologyNode **node) { struct topology *topology = impl_from_IMFTopology(iface);
- TRACE("(%p)->(%u, %p)\n", iface, index, node); + 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; + if (index >= topology->nodes.count) + return MF_E_INVALIDINDEX; + + *node = &topology->nodes.nodes[index]->IMFTopologyNode_iface; + IMFTopologyNode_AddRef(*node); + + return S_OK; }
static HRESULT WINAPI topology_Clear(IMFTopology *iface) { struct topology *topology = impl_from_IMFTopology(iface);
- TRACE("(%p)\n", iface); + TRACE("%p.\n", iface);
- return IMFCollection_RemoveAllElements(topology->nodes); + topology_clear(topology); + return S_OK; }
static HRESULT WINAPI topology_CloneFrom(IMFTopology *iface, IMFTopology *src_topology) @@ -599,36 +614,27 @@ static HRESULT WINAPI topology_CloneFrom(IMFTopology *iface, IMFTopology *src_to return E_NOTIMPL; }
-static HRESULT WINAPI topology_GetNodeByID(IMFTopology *iface, TOPOID id, IMFTopologyNode **node) +static HRESULT WINAPI topology_GetNodeByID(IMFTopology *iface, TOPOID id, IMFTopologyNode **ret) { struct topology *topology = impl_from_IMFTopology(iface); - - TRACE("(%p)->(%p)\n", iface, node); - - return topology_get_node_by_id(topology, id, node); -} - -static HRESULT topology_add_node_of_type(const struct topology *topology, IMFTopologyNode *node, - MF_TOPOLOGY_TYPE filter, IMFCollection *collection) -{ - MF_TOPOLOGY_TYPE node_type; + struct topology_node *node; HRESULT hr;
- if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type))) - return hr; + TRACE("%p, %p.\n", iface, ret);
- if (node_type != filter) - return S_OK; + if (SUCCEEDED(hr = topology_get_node_by_id(topology, id, &node))) + *ret = &node->IMFTopologyNode_iface; + else + *ret = NULL;
- return IMFCollection_AddElement(collection, (IUnknown *)node); + return hr; }
static HRESULT topology_get_node_collection(const struct topology *topology, MF_TOPOLOGY_TYPE node_type, IMFCollection **collection) { - IMFTopologyNode *node; - unsigned int i = 0; HRESULT hr; + size_t i;
if (!collection) return E_POINTER; @@ -636,15 +642,17 @@ static HRESULT topology_get_node_collection(const struct topology *topology, MF_ if (FAILED(hr = MFCreateCollection(collection))) return hr;
- while (IMFCollection_GetElement(topology->nodes, i++, (IUnknown **)&node) == S_OK) + for (i = 0; i < topology->nodes.count; ++i) { - hr = topology_add_node_of_type(topology, node, node_type, *collection); - IMFTopologyNode_Release(node); - if (FAILED(hr)) + if (topology->nodes.nodes[i]->node_type == node_type) { - IMFCollection_Release(*collection); - *collection = NULL; - break; + if (FAILED(hr = IMFCollection_AddElement(*collection, + (IUnknown *)&topology->nodes.nodes[i]->IMFTopologyNode_iface))) + { + IMFCollection_Release(*collection); + *collection = NULL; + break; + } } }
@@ -750,9 +758,6 @@ HRESULT WINAPI MFCreateTopology(IMFTopology **topology) object->refcount = 1;
hr = MFCreateAttributes(&object->attributes, 0); - if (SUCCEEDED(hr)) - hr = MFCreateCollection(&object->nodes); - if (FAILED(hr)) { IMFTopology_Release(&object->IMFTopology_iface);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=52000
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/mf/tests/mf.c:79 error: patch failed: dlls/mf/topology.c:57 error: patch failed: dlls/mf/topology.c:45 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/mf/tests/mf.c:79 error: patch failed: dlls/mf/topology.c:57 error: patch failed: dlls/mf/topology.c:45 Task: Patch failed to apply
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/tests/mf.c | 10 ++-- dlls/mf/topology.c | 123 ++++++++++++++++++++++++++------------------- 2 files changed, 74 insertions(+), 59 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 8b3b8b4373..ff3290a158 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -589,10 +589,9 @@ static void test_topology(void) hr = IMFTopology_Clear(topology); ok(hr == S_OK, "Failed to clear topology, hr %#x.\n", hr);
-todo_wine { EXPECT_REF(node, 1); EXPECT_REF(node2, 1); -} + /* Removing connected node breaks connection. */ hr = IMFTopology_AddNode(topology, node); ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); @@ -606,12 +605,10 @@ todo_wine { hr = IMFTopology_RemoveNode(topology, node); ok(hr == S_OK, "Failed to remove a node, hr %#x.\n", hr);
-todo_wine { EXPECT_REF(node, 1); EXPECT_REF(node2, 2); -} + hr = IMFTopologyNode_GetOutput(node, 0, &node3, &index); -todo_wine ok(hr == MF_E_NOT_FOUND, "Unexpected hr %#x.\n", hr);
hr = IMFTopology_AddNode(topology, node); @@ -623,10 +620,9 @@ todo_wine hr = IMFTopology_RemoveNode(topology, node2); ok(hr == S_OK, "Failed to remove a node, hr %#x.\n", hr);
-todo_wine { EXPECT_REF(node, 2); EXPECT_REF(node2, 1); -} + IMFTopologyNode_Release(node); IMFTopologyNode_Release(node2);
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index c10bc6ad02..e10bc8b07d 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -174,12 +174,81 @@ static ULONG WINAPI topology_AddRef(IMFTopology *iface) return refcount; }
+static HRESULT topology_node_disconnect_output(struct topology_node *node, DWORD output_index) +{ + struct topology_node *connection = NULL; + struct node_stream *stream; + DWORD connection_stream; + HRESULT hr = S_OK; + + EnterCriticalSection(&node->cs); + + if (output_index < node->outputs.count) + { + stream = &node->outputs.streams[output_index]; + + if (stream->connection) + { + connection = stream->connection; + connection_stream = stream->connection_stream; + stream->connection = NULL; + stream->connection_stream = 0; + } + else + hr = MF_E_NOT_FOUND; + } + else + hr = E_INVALIDARG; + + LeaveCriticalSection(&node->cs); + + if (connection) + { + EnterCriticalSection(&connection->cs); + + if (connection_stream < connection->inputs.count) + { + stream = &connection->inputs.streams[connection_stream]; + + if (stream->connection) + { + stream->connection = NULL; + stream->connection_stream = 0; + } + } + + LeaveCriticalSection(&connection->cs); + + IMFTopologyNode_Release(&connection->IMFTopologyNode_iface); + IMFTopologyNode_Release(&node->IMFTopologyNode_iface); + } + + return hr; +} + +static void topology_node_disconnect(struct topology_node *node) +{ + struct node_stream *stream; + size_t i; + + for (i = 0; i < node->outputs.count; ++i) + topology_node_disconnect_output(node, i); + + for (i = 0; i < node->inputs.count; ++i) + { + stream = &node->inputs.streams[i]; + if (stream->connection) + topology_node_disconnect_output(stream->connection, stream->connection_stream); + } +} + static void topology_clear(struct topology *topology) { size_t i;
for (i = 0; i < topology->nodes.count; ++i) { + topology_node_disconnect(topology->nodes.nodes[i]); IMFTopologyNode_Release(&topology->nodes.nodes[i]->IMFTopologyNode_iface); } heap_free(topology->nodes.nodes); @@ -551,6 +620,8 @@ static HRESULT WINAPI topology_RemoveNode(IMFTopology *iface, IMFTopologyNode *n { if (&topology->nodes.nodes[i]->IMFTopologyNode_iface == node) { + topology_node_disconnect(topology->nodes.nodes[i]); + IMFTopologyNode_Release(&topology->nodes.nodes[i]->IMFTopologyNode_iface); count = topology->nodes.count - i - 1; if (count) { @@ -1248,58 +1319,6 @@ static HRESULT WINAPI topology_node_GetOutputCount(IMFTopologyNode *iface, DWORD return S_OK; }
-static HRESULT topology_node_disconnect_output(struct topology_node *node, DWORD output_index) -{ - struct topology_node *connection = NULL; - struct node_stream *stream; - DWORD connection_stream; - HRESULT hr = S_OK; - - EnterCriticalSection(&node->cs); - - if (output_index < node->outputs.count) - { - stream = &node->outputs.streams[output_index]; - - if (stream->connection) - { - connection = stream->connection; - connection_stream = stream->connection_stream; - stream->connection = NULL; - stream->connection_stream = 0; - } - else - hr = MF_E_NOT_FOUND; - } - else - hr = E_INVALIDARG; - - LeaveCriticalSection(&node->cs); - - if (connection) - { - EnterCriticalSection(&connection->cs); - - if (connection_stream < connection->inputs.count) - { - stream = &connection->inputs.streams[connection_stream]; - - if (stream->connection) - { - stream->connection = NULL; - stream->connection_stream = 0; - } - } - - LeaveCriticalSection(&connection->cs); - - IMFTopologyNode_Release(&connection->IMFTopologyNode_iface); - IMFTopologyNode_Release(&node->IMFTopologyNode_iface); - } - - return hr; -} - static HRESULT WINAPI topology_node_ConnectOutput(IMFTopologyNode *iface, DWORD output_index, IMFTopologyNode *peer, DWORD input_index) {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=52001
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/mf/tests/mf.c:79 error: patch failed: dlls/mf/topology.c:57 error: patch failed: dlls/mf/topology.c:45 error: patch failed: dlls/mf/tests/mf.c:589 error: patch failed: dlls/mf/topology.c:174 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/mf/tests/mf.c:79 error: patch failed: dlls/mf/topology.c:57 error: patch failed: dlls/mf/topology.c:45 error: patch failed: dlls/mf/tests/mf.c:589 error: patch failed: dlls/mf/topology.c:174 Task: Patch failed to apply
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/session.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ dlls/mf/tests/mf.c | 5 +++++ 2 files changed, 51 insertions(+)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 7f8a283e76..a433a300ee 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -36,6 +36,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); struct media_session { IMFMediaSession IMFMediaSession_iface; + IMFGetService IMFGetService_iface; LONG refcount; IMFMediaEventQueue *event_queue; }; @@ -92,6 +93,11 @@ static inline struct media_session *impl_from_IMFMediaSession(IMFMediaSession *i return CONTAINING_RECORD(iface, struct media_session, IMFMediaSession_iface); }
+static struct media_session *impl_from_IMFGetService(IMFGetService *iface) +{ + return CONTAINING_RECORD(iface, struct media_session, IMFGetService_iface); +} + static struct presentation_clock *impl_from_IMFPresentationClock(IMFPresentationClock *iface) { return CONTAINING_RECORD(iface, struct presentation_clock, IMFPresentationClock_iface); @@ -136,6 +142,12 @@ static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID ri IMFMediaSession_AddRef(iface); return S_OK; } + else if (IsEqualIID(riid, &IID_IMFGetService)) + { + *out = &session->IMFGetService_iface; + IMFMediaSession_AddRef(iface); + return S_OK; + }
WARN("Unsupported %s.\n", debugstr_guid(riid)); *out = NULL; @@ -301,6 +313,39 @@ static const IMFMediaSessionVtbl mfmediasessionvtbl = mfsession_GetFullTopology, };
+static HRESULT WINAPI session_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj) +{ + struct media_session *session = impl_from_IMFGetService(iface); + return IMFMediaSession_QueryInterface(&session->IMFMediaSession_iface, riid, obj); +} + +static ULONG WINAPI session_get_service_AddRef(IMFGetService *iface) +{ + struct media_session *session = impl_from_IMFGetService(iface); + return IMFMediaSession_AddRef(&session->IMFMediaSession_iface); +} + +static ULONG WINAPI session_get_service_Release(IMFGetService *iface) +{ + struct media_session *session = impl_from_IMFGetService(iface); + return IMFMediaSession_Release(&session->IMFMediaSession_iface); +} + +static HRESULT WINAPI session_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj) +{ + FIXME("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj); + + return E_NOTIMPL; +} + +static const IMFGetServiceVtbl session_get_service_vtbl = +{ + session_get_service_QueryInterface, + session_get_service_AddRef, + session_get_service_Release, + session_get_service_GetService, +}; + /*********************************************************************** * MFCreateMediaSession (mf.@) */ @@ -319,6 +364,7 @@ HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **ses return E_OUTOFMEMORY;
object->IMFMediaSession_iface.lpVtbl = &mfmediasessionvtbl; + object->IMFGetService_iface.lpVtbl = &session_get_service_vtbl; object->refcount = 1; if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) { diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index ff3290a158..fc068a93cc 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -944,6 +944,7 @@ todo_wine static void test_media_session(void) { IMFMediaSession *session; + IMFGetService *gs; IUnknown *unk; HRESULT hr;
@@ -956,6 +957,10 @@ static void test_media_session(void) hr = IMFMediaSession_QueryInterface(session, &IID_IMFAttributes, (void **)&unk); ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr);
+ hr = IMFMediaSession_QueryInterface(session, &IID_IMFGetService, (void **)&gs); + ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr); + IMFGetService_Release(gs); + test_session_events(session);
IMFMediaSession_Release(session);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=52002
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/mf/tests/mf.c:79 error: patch failed: dlls/mf/topology.c:57 error: patch failed: dlls/mf/topology.c:45 error: patch failed: dlls/mf/tests/mf.c:589 error: patch failed: dlls/mf/topology.c:174 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/mf/tests/mf.c:79 error: patch failed: dlls/mf/topology.c:57 error: patch failed: dlls/mf/topology.c:45 error: patch failed: dlls/mf/tests/mf.c:589 error: patch failed: dlls/mf/topology.c:174 Task: Patch failed to apply
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=51999
Your paranoid android.
=== debian9 (build log) ===
error: patch failed: dlls/mf/tests/mf.c:79 error: patch failed: dlls/mf/topology.c:57 Task: Patch failed to apply
=== debian9 (build log) ===
error: patch failed: dlls/mf/tests/mf.c:79 error: patch failed: dlls/mf/topology.c:57 Task: Patch failed to apply