Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/mf/topology.c | 170 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 166 insertions(+), 4 deletions(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 4298ab1bc5..f1b3c3c9e4 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -31,6 +31,7 @@ #include "mfidl.h"
#include "wine/debug.h" +#include "wine/list.h"
#include "mf_private.h"
@@ -39,6 +40,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); static LONG next_node_id; static TOPOID next_topology_id;
+struct list_topologies +{ + struct list entry; + struct topology *topology; +}; + struct node_stream { IMFMediaType *preferred_type; @@ -1913,6 +1920,161 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface) return refcount; }
+static HRESULT topology_loader_add_branch(struct topology *topology, IMFTopologyNode *first) +{ + IMFTopology *full_topo = &topology->IMFTopology_iface; + IMFTopologyNode *in, *out; + DWORD index; + HRESULT hr; + + if (!topology || !first) + { + hr = MF_E_INVALIDREQUEST; + goto out; + } + + in = first; + if (SUCCEEDED(hr = IMFTopology_AddNode(full_topo, in))) + { + while (SUCCEEDED(hr = IMFTopologyNode_GetOutput(in, 0, &out, &index))) + { + if (FAILED(hr = IMFTopology_AddNode(full_topo, out))) + break; + IMFTopologyNode_Release(out); + in = out; + } + } + +out: + return hr == MF_E_NOT_FOUND ? S_OK : hr; +} + +/* iterate through the branch that starts at source node with id srcid, and try to resolve it */ +static HRESULT topology_loader_resolve_branch_connect_nodes(struct topology *topology, TOPOID srcid, MF_CONNECT_METHOD method) +{ + IMFTopologyNode *up_clone, *down_clone; + IMFTopologyNode *src, *up, *down; + struct list *list_topologies; + IMFTopology *clone_topo; + int num_lists, i; + DWORD index; + HRESULT hr; + + num_lists = topology->nodes.count-1; + list_topologies = heap_alloc_zero(sizeof(struct list) * num_lists); + if (!list_topologies) + return E_OUTOFMEMORY; + + MFCreateTopology(&clone_topo); + IMFTopology_CloneFrom(clone_topo, &topology->IMFTopology_iface); + IMFTopology_GetNodeByID(clone_topo, srcid, &src); + + up = src; + for (i = 0; i < num_lists; i++) + { + MF_TOPOLOGY_TYPE type; + + IMFTopologyNode_GetOutput(up, 0, &down, &index); + + IMFTopologyNode_GetNodeType(down, &type); + MFCreateTopologyNode(type, &down_clone); + IMFTopologyNode_CloneFrom(down_clone, down); + + list_init(&list_topologies[i]); + + if (i == 0) + { + IMFTopologyNode_GetNodeType(up, &type); + MFCreateTopologyNode(type, &up_clone); + IMFTopologyNode_CloneFrom(up_clone, up); + + /* 'method' argument passed to function only applies to source media types */ + if (method == MF_CONNECT_DIRECT) + { + hr = S_OK; + if (list_empty(&list_topologies[i])) + { + IMFTopologyNode_Release(up_clone); + IMFTopologyNode_Release(down_clone); + IMFTopologyNode_Release(up); + IMFTopologyNode_Release(down); + IMFTopology_Release(clone_topo); + goto out; + } + } + else + { + hr = S_OK; + if (list_empty(&list_topologies[i])) + { + IMFTopologyNode_Release(up_clone); + IMFTopologyNode_Release(down_clone); + IMFTopologyNode_Release(up); + IMFTopologyNode_Release(down); + IMFTopology_Release(clone_topo); + goto out; + } + } + } + + else + { + struct list_topologies *prev_topologies, *safety_prev; + + /* + * Iterate through list of resolved topologies for previous nodes in the branch, and use it as base + * to build the list of resolved topologies that include the next node in the branch. + */ + LIST_FOR_EACH_ENTRY_SAFE(prev_topologies, safety_prev, &list_topologies[i-1], struct list_topologies, entry) + { + struct list_topologies *curr_topologies; + struct topology *prev_topology; + IMFTopologyNode *up_clone; + + MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &up_clone); + + prev_topology = prev_topologies->topology; + IMFTopologyNode_CloneFrom(up_clone, &prev_topology->nodes.nodes[prev_topology->nodes.count-1]->IMFTopologyNode_iface); + + if (list_empty(&list_topologies[i])) + { + IMFTopologyNode_Release(up_clone); + IMFTopologyNode_Release(down_clone); + IMFTopologyNode_Release(up); + IMFTopologyNode_Release(down); + IMFTopology_Release(clone_topo); + goto out; + } + + LIST_FOR_EACH_ENTRY(curr_topologies, &list_topologies[i], struct list_topologies, entry) + { + struct topology *curr_topology = curr_topologies->topology; + IMFTopologyNode *last_node_prev_topo; + IMFTopology *new_topology; + + MFCreateTopology(&new_topology); + IMFTopology_CloneFrom(new_topology, &prev_topology->IMFTopology_iface); + IMFTopology_GetNode(new_topology, prev_topology->nodes.count-1, &last_node_prev_topo); + IMFTopologyNode_ConnectOutput(last_node_prev_topo, 0, &curr_topology->nodes.nodes[0]->IMFTopologyNode_iface, 0); + topology_loader_add_branch(impl_from_IMFTopology(new_topology), &curr_topology->nodes.nodes[0]->IMFTopologyNode_iface); + curr_topologies->topology = impl_from_IMFTopology(new_topology); + IMFTopology_Release(&curr_topology->IMFTopology_iface); + } + list_remove(&prev_topologies->entry); + heap_free(prev_topologies); + IMFTopology_Release(&prev_topology->IMFTopology_iface); + } + } + IMFTopologyNode_Release(up_clone); + IMFTopologyNode_Release(down_clone); + IMFTopologyNode_Release(up); + up = down; + } + +out: + heap_free(list_topologies); + return hr; +}
/* Resolves a branch with the supplied source and sink */ static HRESULT topology_loader_resolve_branch(struct topology_node *src, struct topology_node *sink, struct topology *full_topology) @@ -1977,8 +2139,8 @@ static HRESULT topology_loader_resolve_branch(struct topology_node *src, struct for (i = 0; i < num_media_types; i++) { IMFMediaTypeHandler_SetCurrentMediaType(mth_src, src_mediatypes[i]); - hr = S_OK; - goto out; + if (SUCCEEDED(hr = topology_loader_resolve_branch_connect_nodes(full_topology, src->id, method))) + goto out; } } } @@ -1989,8 +2151,8 @@ static HRESULT topology_loader_resolve_branch(struct topology_node *src, struct for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++) { IMFMediaTypeHandler_SetCurrentMediaType(mth_src, src_mediatypes[i]); - hr = S_OK; - goto out; + if (SUCCEEDED(hr = topology_loader_resolve_branch_connect_nodes(full_topology, src->id, method))) + goto out; } } }