[PATCH 1/4] mf: Implement node connections.

Nikolay Sivov nsivov at codeweavers.com
Wed May 8 06:46:40 CDT 2019


Signed-off-by: Nikolay Sivov <nsivov at 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;
-- 
2.20.1




More information about the wine-devel mailing list