mf: Implement node connections.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2019-05-08 14:46:40 +03:00 committed by Alexandre Julliard
parent 34ab198faf
commit 6b1a33ce93
2 changed files with 308 additions and 42 deletions

View File

@ -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)

View File

@ -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;