Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/topology.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index abe66c45fd4..fdb2944676a 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -1936,38 +1936,50 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface) static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, IMFTopology **output_topology, IMFTopology *current_topology) { - struct topology *topology = unsafe_impl_from_IMFTopology(input_topology); + MF_TOPOLOGY_TYPE node_type; + IMFTopologyNode *node; + unsigned short i = 0; IMFStreamSink *sink; + IUnknown *object; HRESULT hr; - size_t i;
FIXME("%p, %p, %p, %p.\n", iface, input_topology, output_topology, current_topology);
if (current_topology) FIXME("Current topology instance is ignored.\n");
- for (i = 0; i < topology->nodes.count; ++i) + /* Basic sanity checks for input topology: + + - source nodes must have stream descriptor set; + - sink nodes must be resolved to stream sink objects; + */ + while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node))) { - struct topology_node *node = topology->nodes.nodes[i]; + IMFTopologyNode_GetNodeType(node, &node_type);
- switch (node->node_type) + switch (node_type) { case MF_TOPOLOGY_OUTPUT_NODE: - if (node->object) + if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object))) { /* Sinks must be bound beforehand. */ - if (FAILED(IUnknown_QueryInterface(node->object, &IID_IMFStreamSink, (void **)&sink))) - return MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; - IMFStreamSink_Release(sink); + if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&sink))) + hr = MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; + else if (sink) + IMFStreamSink_Release(sink); + IUnknown_Release(object); } break; case MF_TOPOLOGY_SOURCESTREAM_NODE: - if (FAILED(hr = IMFAttributes_GetItem(node->attributes, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL))) - return hr; + hr = IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL); break; default: ; } + + IMFTopologyNode_Release(node); + if (FAILED(hr)) + return hr; }
if (FAILED(hr = MFCreateTopology(output_topology)))
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/topology.c | 61 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 4 deletions(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index fdb2944676a..038d6214d4a 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -1933,9 +1933,40 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface) return refcount; }
+struct topoloader_context +{ + IMFTopology *output_topology; + GUID key; +}; + +static HRESULT topology_loader_clone_node(struct topoloader_context *context, IMFTopologyNode *node, + unsigned int marker) +{ + IMFTopologyNode *cloned_node; + MF_TOPOLOGY_TYPE node_type; + HRESULT hr; + + IMFTopologyNode_GetNodeType(node, &node_type); + + if (FAILED(hr = MFCreateTopologyNode(node_type, &cloned_node))) + return hr; + + if (SUCCEEDED(hr = IMFTopologyNode_CloneFrom(cloned_node, node))) + hr = IMFTopologyNode_SetUINT32(cloned_node, &context->key, marker); + + if (SUCCEEDED(hr)) + hr = IMFTopology_AddNode(context->output_topology, cloned_node); + + IMFTopologyNode_Release(cloned_node); + + return hr; +} + static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, - IMFTopology **output_topology, IMFTopology *current_topology) + IMFTopology **ret_topology, IMFTopology *current_topology) { + struct topoloader_context context = { 0 }; + IMFTopology *output_topology; MF_TOPOLOGY_TYPE node_type; IMFTopologyNode *node; unsigned short i = 0; @@ -1943,7 +1974,7 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in IUnknown *object; HRESULT hr;
- FIXME("%p, %p, %p, %p.\n", iface, input_topology, output_topology, current_topology); + FIXME("%p, %p, %p, %p.\n", iface, input_topology, ret_topology, current_topology);
if (current_topology) FIXME("Current topology instance is ignored.\n"); @@ -1982,10 +2013,32 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in return hr; }
- if (FAILED(hr = MFCreateTopology(output_topology))) + if (FAILED(hr = MFCreateTopology(&output_topology))) return hr;
- return IMFTopology_CloneFrom(*output_topology, input_topology); + context.output_topology = output_topology; + memset(&context.key, 0xff, sizeof(context.key)); + + /* Clone source nodes, use initial marker value. */ + i = 0; + while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node))) + { + IMFTopologyNode_GetNodeType(node, &node_type); + + if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) + { + if (FAILED(hr = topology_loader_clone_node(&context, node, 0))) + WARN("Failed to clone source node, hr %#x.\n", hr); + } + + IMFTopologyNode_Release(node); + } + + /* For now return original topology. */ + + *ret_topology = output_topology; + + return IMFTopology_CloneFrom(output_topology, input_topology); }
static const IMFTopoLoaderVtbl topologyloadervtbl =
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/tests/mf.c | 9 ++- dlls/mf/topology.c | 138 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 143 insertions(+), 4 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index aa2c5199b95..f01385cc46c 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -1400,6 +1400,7 @@ static void test_topology_loader(void) IMFPresentationDescriptor *pd; IMFSourceResolver *resolver; IMFActivate *sink_activate; + IMFStreamSink *stream_sink; unsigned int count, value; IMFMediaType *media_type; IMFStreamDescriptor *sd; @@ -1512,15 +1513,19 @@ todo_wine hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink); ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr);
- hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)sink); + hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream_sink); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)stream_sink); ok(hr == S_OK, "Failed to set object, hr %#x.\n", hr);
+ IMFStreamSink_Release(stream_sink); + hr = IMFTopology_GetCount(topology, &count); ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr); ok(count == 0, "Unexpected count %u.\n", count);
hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); -todo_wine ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr); ok(full_topology != topology, "Unexpected instance.\n");
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 038d6214d4a..d21c84ac8f7 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -1935,17 +1935,41 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface)
struct topoloader_context { + IMFTopology *input_topology; IMFTopology *output_topology; + unsigned int marker; GUID key; };
+static IMFTopologyNode *topology_loader_get_node_for_marker(struct topoloader_context *context, TOPOID *id) +{ + IMFTopologyNode *node; + unsigned short i = 0; + unsigned int value; + + while (SUCCEEDED(IMFTopology_GetNode(context->output_topology, i++, &node))) + { + if (SUCCEEDED(IMFTopologyNode_GetUINT32(node, &context->key, &value)) && value == context->marker) + { + IMFTopologyNode_GetTopoNodeID(node, id); + return node; + } + IMFTopologyNode_Release(node); + } + + *id = 0; + return NULL; +} + static HRESULT topology_loader_clone_node(struct topoloader_context *context, IMFTopologyNode *node, - unsigned int marker) + IMFTopologyNode **ret, unsigned int marker) { IMFTopologyNode *cloned_node; MF_TOPOLOGY_TYPE node_type; HRESULT hr;
+ if (ret) *ret = NULL; + IMFTopologyNode_GetNodeType(node, &node_type);
if (FAILED(hr = MFCreateTopologyNode(node_type, &cloned_node))) @@ -1957,17 +1981,113 @@ static HRESULT topology_loader_clone_node(struct topoloader_context *context, IM if (SUCCEEDED(hr)) hr = IMFTopology_AddNode(context->output_topology, cloned_node);
+ if (SUCCEEDED(hr) && ret) + { + *ret = cloned_node; + IMFTopologyNode_AddRef(*ret); + } + IMFTopologyNode_Release(cloned_node);
return hr; }
+typedef HRESULT (*p_topology_loader_connect_func)(struct topoloader_context *context, IMFTopologyNode *upstream_node, + unsigned int output_index, IMFTopologyNode *downstream_node, unsigned int input_index); + +static HRESULT topology_loader_connect_source_node(struct topoloader_context *context, IMFTopologyNode *upstream_node, + unsigned int output_index, IMFTopologyNode *downstream_node, unsigned int input_index) +{ + FIXME("Unimplemented.\n"); + + return E_NOTIMPL; +} + +static HRESULT topology_loader_resolve_branch(struct topoloader_context *context, IMFTopologyNode *upstream_node, + unsigned int output_index, IMFTopologyNode *downstream_node, unsigned input_index) +{ + static const p_topology_loader_connect_func connectors[MF_TOPOLOGY_TEE_NODE+1][MF_TOPOLOGY_TEE_NODE+1] = + { + /* OUTPUT */ { NULL }, + /* SOURCESTREAM */ { topology_loader_connect_source_node, NULL, NULL, NULL }, + /* TRANSFORM */ { NULL }, + /* TEE */ { NULL }, + }; + MF_TOPOLOGY_TYPE u_type, d_type; + IMFTopologyNode *node; + TOPOID id; + + /* Downstream node might have already been cloned. */ + IMFTopologyNode_GetTopoNodeID(downstream_node, &id); + if (FAILED(IMFTopology_GetNodeByID(context->output_topology, id, &node))) + topology_loader_clone_node(context, downstream_node, &node, context->marker + 1); + + IMFTopologyNode_ConnectOutput(upstream_node, output_index, node, input_index); + + IMFTopologyNode_GetNodeType(upstream_node, &u_type); + IMFTopologyNode_GetNodeType(downstream_node, &d_type); + + if (!connectors[u_type][d_type]) + { + WARN("Unsupported branch kind %d -> %d.\n", u_type, d_type); + return E_FAIL; + } + + return connectors[u_type][d_type](context, upstream_node, output_index, downstream_node, input_index); +} + +static HRESULT topology_loader_resolve_nodes(struct topoloader_context *context, unsigned int *layer_size) +{ + IMFTopologyNode *downstream_node, *node, *orig_node; + unsigned int input_index, size = 0; + MF_TOPOLOGY_TYPE node_type; + HRESULT hr = S_OK; + TOPOID id; + + while ((node = topology_loader_get_node_for_marker(context, &id))) + { + ++size; + + IMFTopology_GetNodeByID(context->input_topology, id, &orig_node); + + IMFTopologyNode_GetNodeType(node, &node_type); + switch (node_type) + { + case MF_TOPOLOGY_SOURCESTREAM_NODE: + if (FAILED(IMFTopologyNode_GetOutput(orig_node, 0, &downstream_node, &input_index))) + { + IMFTopology_RemoveNode(context->output_topology, node); + continue; + } + + hr = topology_loader_resolve_branch(context, node, 0, downstream_node, input_index); + break; + case MF_TOPOLOGY_TRANSFORM_NODE: + case MF_TOPOLOGY_TEE_NODE: + FIXME("Unsupported node type %d.\n", node_type); + break; + default: + WARN("Unexpected node type %d.\n", node_type); + } + + IMFTopologyNode_DeleteItem(node, &context->key); + + if (FAILED(hr)) + break; + } + + *layer_size = size; + + return hr; +} + static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, IMFTopology **ret_topology, IMFTopology *current_topology) { struct topoloader_context context = { 0 }; IMFTopology *output_topology; MF_TOPOLOGY_TYPE node_type; + unsigned int layer_size; IMFTopologyNode *node; unsigned short i = 0; IMFStreamSink *sink; @@ -2016,6 +2136,7 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in if (FAILED(hr = MFCreateTopology(&output_topology))) return hr;
+ context.input_topology = input_topology; context.output_topology = output_topology; memset(&context.key, 0xff, sizeof(context.key));
@@ -2027,13 +2148,26 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in
if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) { - if (FAILED(hr = topology_loader_clone_node(&context, node, 0))) + if (FAILED(hr = topology_loader_clone_node(&context, node, NULL, 0))) WARN("Failed to clone source node, hr %#x.\n", hr); }
IMFTopologyNode_Release(node); }
+ for (context.marker = 0;; ++context.marker) + { + if (FAILED(hr = topology_loader_resolve_nodes(&context, &layer_size))) + { + WARN("Failed to resolve for marker %u, hr %#x.\n", context.marker, hr); + break; + } + + /* Reached last marker value. */ + if (!layer_size) + break; + } + /* For now return original topology. */
*ret_topology = output_topology;