[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