[PATCH v4 3/3] mf: Partially implement the topology loader.

Sergio Gómez Del Real sdelreal at codeweavers.com
Fri Apr 3 10:35:53 CDT 2020


Signed-off-by: Sergio Gómez Del Real <sdelreal at codeweavers.com>
---
 dlls/mf/tests/mf.c |  95 +++++++-----
 dlls/mf/topology.c | 378 +++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 421 insertions(+), 52 deletions(-)

diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index 1a762c6874..42db1bc4e2 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -1380,7 +1380,7 @@ static void test_topology_loader(void)
 {
     IMFSampleGrabberSinkCallback test_grabber_callback = { &test_grabber_callback_vtbl };
     IMFMediaSource test_media_source = { &test_media_source_vtbl };
-    IMFTopology *topology, *topology2, *full_topology;
+    IMFTopology *topology, *topology2, *full_topology = NULL;
     IMFTopologyNode *src_node, *sink_node;
     IMFMediaType *media_type, *current_media_type;
     IMFPresentationDescriptor *pd;
@@ -1418,7 +1418,6 @@ static void test_topology_loader(void)
 
     /* Empty topology */
     hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
-todo_wine
     ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
 
     hr = MFCreateSourceResolver(&resolver);
@@ -1463,7 +1462,6 @@ todo_wine
 
     /* Source node only. */
     hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
-todo_wine
     ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
 
     /* Add grabber sink. */
@@ -1489,7 +1487,6 @@ todo_wine
     ok(hr == S_OK, "Failed to add sink node, hr %#x.\n", hr);
 
     hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
-todo_wine
     ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
 
     hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0);
@@ -1513,38 +1510,49 @@ todo_wine
     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");
-
-    IMFTopology_GetNodeCount(full_topology, &node_count);
+    if (full_topology)
+        hr = IMFTopology_GetNodeCount(full_topology, &node_count);
+todo_wine
     ok(node_count == 2, "Topology node count is %#x.\n", node_count);
 
     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 = IMFTopology_GetCount(full_topology, &count);
+    hr = E_FAIL;
+    if (full_topology)
+        hr = IMFTopology_GetCount(full_topology, &count);
+todo_wine {
     ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr);
-todo_wine
     ok(count == 1, "Unexpected count %u.\n", count);
+}
 
-    hr = IMFTopology_GetItemByIndex(full_topology, 0, &guid, NULL);
+    if (full_topology)
+        hr = IMFTopology_GetItemByIndex(full_topology, 0, &guid, NULL);
 todo_wine {
     ok(hr == S_OK, "Failed to get attribute key, hr %#x.\n", hr);
     ok(IsEqualGUID(&guid, &MF_TOPOLOGY_RESOLUTION_STATUS), "Unexpected key %s.\n", wine_dbgstr_guid(&guid));
 }
     value = 0xdeadbeef;
-    hr = IMFTopology_GetUINT32(full_topology, &MF_TOPOLOGY_RESOLUTION_STATUS, &value);
+    if (full_topology)
+        hr = IMFTopology_GetUINT32(full_topology, &MF_TOPOLOGY_RESOLUTION_STATUS, &value);
 todo_wine {
     ok(hr == S_OK, "Failed to get attribute, hr %#x.\n", hr);
     ok(value == MF_TOPOLOGY_RESOLUTION_SUCCEEDED, "Unexpected value %#x.\n", value);
 }
     hr = IMFTopoLoader_Load(loader, full_topology, &topology2, NULL);
+todo_wine
     ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
     ok(full_topology != topology2, "Unexpected instance.\n");
 
-    IMFTopology_Release(topology2);
-    IMFTopology_Release(full_topology);
+    if (full_topology)
+    {
+        IMFTopology_Release(topology2);
+        IMFTopology_Release(full_topology);
+    }
     IMFByteStream_Release(stream);
     IMFStreamDescriptor_Release(sd);
 
@@ -1554,21 +1562,32 @@ todo_wine {
     hr = IMFPresentationDescriptor_DeselectStream(pd, 0);
     ok(hr == S_OK, "Failed to deselect stream, hr %#x.\n", hr);
     hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+todo_wine
     ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
     IMFTopologyNode_Release(src_node);
-    hr = IMFTopology_GetNode(full_topology, 0, &src_node);
+    if (full_topology)
+        hr = IMFTopology_GetNode(full_topology, 0, &src_node);
+todo_wine
     ok(hr == S_OK, "Failed to get full topology source node, hr %#x.\n", hr);
-    IMFPresentationDescriptor_Release(pd);
-    hr = IMFTopologyNode_GetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor, (void **)&pd);
-    ok(hr == S_OK, "Failed to get presentation descriptor, hr %#x.\n", hr);
-    IMFStreamDescriptor_Release(sd);
-    IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 0, &selected, &sd);
-    ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr);
-    ok(!selected, "Stream should not be selected\n.");
+    if (hr == S_OK)
+    {
+        IMFPresentationDescriptor_Release(pd);
+todo_wine
+        hr = IMFTopologyNode_GetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor, (void **)&pd);
+        ok(hr == S_OK, "Failed to get presentation descriptor, hr %#x.\n", hr);
+        IMFStreamDescriptor_Release(sd);
+        IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 0, &selected, &sd);
+todo_wine
+        ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr);
+        ok(!selected, "Stream should not be selected\n.");
+    }
 
-    IMFPresentationDescriptor_Release(pd);
-    IMFTopologyNode_Release(src_node);
-    IMFTopology_Release(full_topology);
+    if (hr == S_OK)
+    {
+        IMFPresentationDescriptor_Release(pd);
+        IMFTopologyNode_Release(src_node);
+        IMFTopology_Release(full_topology);
+    }
     IMFTopology_Release(topology);
     IMFMediaSource_Release(source);
     IMFSourceResolver_Release(resolver);
@@ -1636,7 +1655,6 @@ todo_wine {
     ok(hr == MF_E_ATTRIBUTENOTFOUND, "Attribute should not be set\n.");
     /* if no current media type set, loader uses first index exclusively */
     hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
-todo_wine
     /* when major types differ, error is MF_E_TOPO_CODEC_NOT_FOUND */
     ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#x.\n", hr);
 
@@ -1661,14 +1679,18 @@ todo_wine
     ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr);
 
     hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+todo_wine
     ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
 
-    hr = IMFTopology_GetNodeCount(full_topology, &node_count);
+    if (hr == S_OK)
+        hr = IMFTopology_GetNodeCount(full_topology, &node_count);
+todo_wine {
     ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
-todo_wine
     ok(node_count == 3, "Unexpected node count.\n");
+}
 
-    IMFTopology_Release(full_topology);
+    if (hr == S_OK)
+        IMFTopology_Release(full_topology);
 
     /* now test with MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES set on topology */
     hr = IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, 1);
@@ -1723,7 +1745,7 @@ todo_wine {
     ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr);
     hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &mth);
     ok(hr == S_OK, "Failed to get media type handler, hr %#x.\n", hr);
-    hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 1, &media_type);
+    hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 2, &media_type);
     ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr);
     hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, media_type);
     ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr);
@@ -1793,10 +1815,10 @@ todo_wine {
     /* unconnected nodes in partial topology are discarded */
     hr = IMFTopology_GetNodeCount(full_topology, &node_count);
     ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
-todo_wine
-    ok(node_count == 3, "Unexpected node count %d.\n", node_count);
+    ok(node_count == 2, "Unexpected node count %d.\n", node_count);
 
-    IMFTopology_Release(full_topology);
+    if (hr == S_OK)
+        IMFTopology_Release(full_topology);
 
     /* connect nodes for second branch */
     hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0);
@@ -1804,7 +1826,6 @@ todo_wine
 
     /* all branches must have valid media types */
     hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
-todo_wine
     ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#x.\n", hr);
 
     /* set valid media type for second branch */
@@ -1815,14 +1836,18 @@ todo_wine
     ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr);
 
     hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+todo_wine
     ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
 
-    hr = IMFTopology_GetNodeCount(full_topology, &node_count);
+    if (hr == S_OK)
+        hr = IMFTopology_GetNodeCount(full_topology, &node_count);
+todo_wine {
     ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
-todo_wine
     ok(node_count == 6, "Unexpected node count %d.\n", node_count);
+}
 
-    IMFTopology_Release(full_topology);
+    if (hr == S_OK)
+        IMFTopology_Release(full_topology);
     IMFMediaType_Release(media_type);
     IMFTopologyNode_Release(src_node);
     IMFTopologyNode_Release(sink_node);
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c
index 0b4d734442..aeaa9cb84a 100644
--- a/dlls/mf/topology.c
+++ b/dlls/mf/topology.c
@@ -1913,47 +1913,391 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface)
     return refcount;
 }
 
+static void topology_loader_add_branch(struct topology *topology, IMFTopologyNode *first, IMFTopologyNode *last)
+{
+    IMFTopology *full_topo = &topology->IMFTopology_iface;
+    IMFTopologyNode *in, *out;
+    DWORD index;
+
+    in = first;
+    IMFTopology_AddNode(full_topo, in);
+    while (SUCCEEDED(IMFTopologyNode_GetOutput(in, 0, &out, &index)))
+    {
+        IMFTopology_AddNode(full_topo, out);
+        IMFTopologyNode_Release(out);
+        in = out;
+    }
+}
+
+static HRESULT topology_loader_resolve_branch_connect_nodes(IMFTopologyNode *src, IMFMediaType *mediatype, IMFTopologyNode *sink, MF_CONNECT_METHOD method)
+{
+    HRESULT hr;
+    IMFMediaTypeHandler *mth;
+    IMFStreamSink *streamsink;
+    IMFActivate **activates_decs;
+    IMFActivate **activates_convs;
+    UINT32 num_activates_decs = 0;
+    UINT32 num_activates_convs = 0;
+
+    IMFTopologyNode_GetObject(sink, (IUnknown **)&streamsink);
+    IMFStreamSink_GetMediaTypeHandler(streamsink, &mth);
+    if (method == MF_CONNECT_DIRECT)
+    {
+        if (FAILED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(mth, mediatype, NULL)))
+            goto out;
+        IMFMediaTypeHandler_SetCurrentMediaType(mth, mediatype);
+        IMFTopologyNode_ConnectOutput(src, 0, sink, 0);
+        goto out;
+    }
+    else
+    {
+        IMFTopologyNode *node_dec, *node_conv;
+        GUID major_type, subtype, mft_category;
+        MFT_REGISTER_TYPE_INFO mft_typeinfo;
+        UINT32 flags = MFT_ENUM_FLAG_ALL;
+        int i, j;
+
+        IMFMediaType_GetGUID(mediatype, &MF_MT_MAJOR_TYPE, &major_type);
+        if (IsEqualGUID(&major_type, &MFMediaType_Audio))
+            mft_category = MFT_CATEGORY_AUDIO_DECODER;
+        else if (IsEqualGUID(&major_type, &MFMediaType_Video))
+            mft_category = MFT_CATEGORY_VIDEO_DECODER;
+        else
+        {
+            hr = MF_E_TOPO_CODEC_NOT_FOUND;
+            goto out;
+        }
+
+        IMFMediaType_GetGUID(mediatype, &MF_MT_SUBTYPE, &subtype);
+        mft_typeinfo.guidMajorType = major_type;
+        mft_typeinfo.guidSubtype = subtype;
+        MFTEnumEx(mft_category, flags, &mft_typeinfo, NULL, &activates_decs, &num_activates_decs);
+
+        /* for getting converters later on */
+        if (IsEqualGUID(&major_type, &MFMediaType_Audio))
+            mft_category = MFT_CATEGORY_AUDIO_EFFECT;
+        else if (IsEqualGUID(&major_type, &MFMediaType_Video))
+            mft_category = MFT_CATEGORY_VIDEO_EFFECT;
+
+        /*
+         * Iterate over number of decoders.
+         * Try to set input type on decoder with source's output media type.
+         * If succeeds, iterate over decoder's output media types.
+         * Try to set input type on sink with decoder's output media type.
+         * If fails, iterate over number of converters.
+         * Try to set input type on converter with decoder's output media type.
+         * If succeeds, iterate over converters output media types.
+         * Try to set input type on sink with converter's output media type.
+         */
+        for (i = 0; i < num_activates_decs; i++)
+        {
+            IMFTransform *decoder;
+
+            IMFActivate_ActivateObject(activates_decs[i], &IID_IMFTransform, (void **)&decoder);
+            if (SUCCEEDED(hr = IMFTransform_SetInputType(decoder, 0, mediatype, MFT_SET_TYPE_TEST_ONLY)))
+            {
+                IMFMediaType *decoder_mtype;
+
+                int count = 0;
+                IMFTransform_SetInputType(decoder, 0, mediatype, 0);
+                while (SUCCEEDED(IMFTransform_GetOutputAvailableType(decoder, 0, count++, &decoder_mtype)))
+                {
+                    IMFTransform *converter;
+
+                    /* succeeded with source -> decoder -> sink */
+                    if (SUCCEEDED(IMFMediaTypeHandler_IsMediaTypeSupported(mth, decoder_mtype, NULL)))
+                    {
+                        IMFMediaTypeHandler_SetCurrentMediaType(mth, decoder_mtype);
+                        MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_dec);
+                        IMFTopologyNode_SetObject(node_dec, (IUnknown *)decoder);
+                        IMFTopologyNode_ConnectOutput(src, 0, node_dec, 0);
+                        IMFTopologyNode_ConnectOutput(node_dec, 0, sink, 0);
+
+                        IMFActivate_ShutdownObject(activates_decs[i]);
+                        hr = S_OK;
+                        goto out;
+                    }
+
+                    IMFMediaType_GetGUID(decoder_mtype, &MF_MT_SUBTYPE, &subtype);
+                    mft_typeinfo.guidSubtype = subtype;
+                    MFTEnumEx(mft_category, flags, &mft_typeinfo, NULL, &activates_convs, &num_activates_convs);
+                    for (j = 0; j < num_activates_convs; j++)
+                    {
+                        IMFMediaType *converter_mtype;
+
+                        IMFActivate_ActivateObject(activates_convs[j], &IID_IMFTransform, (void **)&converter);
+                        if (SUCCEEDED(IMFTransform_SetInputType(converter, 0, decoder_mtype, MFT_SET_TYPE_TEST_ONLY)))
+                        {
+                            int count = 0;
+                            IMFTransform_SetInputType(converter, 0, decoder_mtype, 0);
+                            while (SUCCEEDED(IMFTransform_GetOutputAvailableType(converter, 0, count++, &converter_mtype)))
+                            {
+                                /* succeeded with source -> decoder -> converter -> sink */
+                                if (SUCCEEDED(IMFMediaTypeHandler_IsMediaTypeSupported(mth, converter_mtype, NULL)))
+                                {
+                                    IMFMediaTypeHandler_SetCurrentMediaType(mth, converter_mtype);
+                                    MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_dec);
+                                    IMFTopologyNode_SetObject(node_dec, (IUnknown *)decoder);
+                                    MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_conv);
+                                    IMFTopologyNode_SetObject(node_conv, (IUnknown *)converter);
+                                    IMFTopologyNode_ConnectOutput(src, 0, node_dec, 0);
+                                    IMFTopologyNode_ConnectOutput(node_dec, 0, node_conv, 0);
+                                    IMFTopologyNode_ConnectOutput(node_conv, 0, sink, 0);
+
+                                    IMFActivate_ShutdownObject(activates_convs[j]);
+                                    IMFActivate_ShutdownObject(activates_decs[i]);
+                                    hr = S_OK;
+                                    goto out;
+                                }
+                            }
+                        }
+                        IMFActivate_ShutdownObject(activates_convs[j]);
+                    }
+                }
+            }
+            IMFActivate_ShutdownObject(activates_decs[i]);
+        }
+    }
+    hr = MF_E_TOPO_CODEC_NOT_FOUND;
+out:
+    while (num_activates_convs--)
+        IMFActivate_Release(activates_convs[num_activates_convs]);
+    while (num_activates_decs--)
+        IMFActivate_Release(activates_decs[num_activates_decs]);
+    CoTaskMemFree(activates_decs);
+    CoTaskMemFree(activates_convs);
+    IMFMediaTypeHandler_Release(mth);
+    IMFStreamSink_Release(streamsink);
+
+    return hr;
+}
+
+static HRESULT topology_loader_resolve_branch(struct topology_node *src, struct topology_node *sink, struct topology *topology, struct topology *full_topology)
+{
+    IMFMediaTypeHandler *mth_src, *mth_sink;
+    IMFTopologyNode *clone_src, *clone_sink;
+    UINT32 method, enum_src_types, streamid;
+    IMFMediaType **src_mediatypes;
+    IMFStreamDescriptor *desc;
+    IMFAttributes *attrs_src;
+    IMFStreamSink *strm_sink;
+    IMFMediaType *mtype_src;
+    DWORD num_media_types;
+    HRESULT hr;
+    int i;
+
+    attrs_src = src->attributes;
+    if (FAILED(hr = IMFAttributes_GetUnknown(attrs_src, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor, (void **)&desc)))
+        return hr;
+    strm_sink = (IMFStreamSink *)sink->object;
+
+    if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(desc, &mth_src)))
+    {
+        IMFStreamDescriptor_Release(desc);
+        return hr;
+    }
+    if (FAILED(hr = IMFStreamSink_GetMediaTypeHandler(strm_sink, &mth_sink)))
+    {
+        IMFStreamDescriptor_Release(desc);
+        IMFMediaTypeHandler_Release(mth_src);
+        return hr;
+    }
+
+    enum_src_types = 0;
+    hr = IMFTopology_GetUINT32(&topology->IMFTopology_iface, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enum_src_types);
+
+    if (FAILED(hr) || !enum_src_types)
+    {
+        num_media_types = 1;
+        if (FAILED(hr = IMFMediaTypeHandler_GetCurrentMediaType(mth_src, &mtype_src)))
+            if (FAILED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth_src, 0, &mtype_src)))
+            {
+                IMFMediaTypeHandler_Release(mth_src);
+                IMFMediaTypeHandler_Release(mth_sink);
+                IMFStreamDescriptor_Release(desc);
+                return hr;
+            }
+    }
+    else
+        IMFMediaTypeHandler_GetMediaTypeCount(mth_src, &num_media_types);
+
+    src_mediatypes = heap_alloc(sizeof(IMFMediaType *) * num_media_types);
+
+    if (enum_src_types)
+        for (i = 0; i < num_media_types; i++)
+            IMFMediaTypeHandler_GetMediaTypeByIndex(mth_src, i, &src_mediatypes[i]);
+    else
+        src_mediatypes[0] = mtype_src;
+
+
+    MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &clone_src);
+    MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &clone_sink);
+    IMFTopologyNode_CloneFrom(clone_src, &src->IMFTopologyNode_iface);
+    IMFTopologyNode_CloneFrom(clone_sink, &sink->IMFTopologyNode_iface);
+
+    if (FAILED(IMFTopologyNode_GetUINT32(clone_sink, &MF_TOPONODE_STREAMID, &streamid)))
+        IMFTopologyNode_SetUINT32(clone_sink, &MF_TOPONODE_STREAMID, 0);
+
+    if (enum_src_types)
+    {
+        hr = IMFAttributes_GetUINT32(attrs_src, &MF_TOPONODE_CONNECT_METHOD, &method);
+        if (hr == S_OK && method != MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES)
+        {
+            for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
+                for (i = 0; i < num_media_types; i++)
+                    if (SUCCEEDED(hr = topology_loader_resolve_branch_connect_nodes(clone_src, src_mediatypes[i], clone_sink, method)))
+                    {
+                        topology_loader_add_branch(full_topology, clone_src, clone_sink);
+                        goto out;
+                    }
+        }
+        else
+        {
+            for (i = 0; i < num_media_types; i++)
+                for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
+                    if (SUCCEEDED(hr = topology_loader_resolve_branch_connect_nodes(clone_src, src_mediatypes[i], clone_sink, method)))
+                    {
+                        topology_loader_add_branch(full_topology, clone_src, clone_sink);
+                        goto out;
+                    }
+        }
+    }
+    else
+    {
+        for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
+            if (SUCCEEDED(hr = topology_loader_resolve_branch_connect_nodes(clone_src, src_mediatypes[0], clone_sink, method)))
+            {
+                topology_loader_add_branch(full_topology, clone_src, clone_sink);
+                goto out;
+            }
+    }
+
+    IMFTopologyNode_Release(clone_src);
+    IMFTopologyNode_Release(clone_sink);
+out:
+    if (!enum_src_types)
+        IMFMediaType_Release(mtype_src);
+    IMFMediaTypeHandler_Release(mth_src);
+    IMFMediaTypeHandler_Release(mth_sink);
+    IMFStreamDescriptor_Release(desc);
+    heap_free(src_mediatypes);
+    return hr;
+}
+
 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);
+    struct topology_node *(*node_pairs)[2];
+    IMFTopology *full_topology;
+    int num_connections;
     IMFStreamSink *sink;
     HRESULT hr;
-    size_t i;
+    int i, idx;
 
     FIXME("%p, %p, %p, %p.\n", iface, input_topology, output_topology, current_topology);
 
     if (current_topology)
         FIXME("Current topology instance is ignored.\n");
 
+    if (!topology || topology->nodes.count < 2)
+        return MF_E_TOPO_UNSUPPORTED;
+
+    num_connections = 0;
+    for (i = 0; i < topology->nodes.count; i++)
+    {
+        struct topology_node *node = topology->nodes.nodes[i];
+
+        if (node->node_type == MF_TOPOLOGY_SOURCESTREAM_NODE)
+        {
+            if (node->outputs.count && node->outputs.streams->connection)
+                num_connections++;
+        }
+    }
+
+    if (!num_connections)
+        return MF_E_TOPO_UNSUPPORTED;
+
+    node_pairs = heap_alloc_zero(sizeof(struct topology_node *[2]) * num_connections);
+
+    idx = 0;
     for (i = 0; i < topology->nodes.count; ++i)
     {
         struct topology_node *node = topology->nodes.nodes[i];
 
-        switch (node->node_type)
+        if (node->node_type == MF_TOPOLOGY_SOURCESTREAM_NODE)
         {
-            case MF_TOPOLOGY_OUTPUT_NODE:
-                if (node->object)
+            if (node->outputs.count && node->outputs.streams->connection)
+            {
+                node_pairs[idx][0] = node;
+                if (node->outputs.streams->connection->node_type == MF_TOPOLOGY_TRANSFORM_NODE)
                 {
-                    /* 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);
+                    struct topology_node *sink = node->outputs.streams->connection;
+
+                    while (sink && sink->node_type != MF_TOPOLOGY_OUTPUT_NODE && sink->outputs.count)
+                           sink = sink->outputs.streams->connection;
+                    if (!sink || !sink->outputs.count)
+                    {
+                        FIXME("Check for MF_CONNECT_AS_OPTIONAL and MF_CONNECT_AS_OPTIONAL_BRANCH flags.\n");
+                        heap_free(node_pairs);
+                        return MF_E_TOPO_UNSUPPORTED;
+                    }
+                    node_pairs[idx][1] = sink;
                 }
-                break;
-            case MF_TOPOLOGY_SOURCESTREAM_NODE:
-                if (FAILED(hr = IMFAttributes_GetItem(node->attributes, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL)))
-                    return hr;
-                break;
-            default:
-                ;
+                else if (node->outputs.streams->connection->node_type == MF_TOPOLOGY_OUTPUT_NODE)
+                    node_pairs[idx][1] = node->outputs.streams->connection;
+                else {
+                    FIXME("Tee nodes currently unhandled.\n");
+                    heap_free(node_pairs);
+                    return MF_E_TOPO_UNSUPPORTED;
+                }
+                idx++;
+            }
         }
     }
 
-    if (FAILED(hr = MFCreateTopology(output_topology)))
+    /* all sinks must be activated */
+    for (i = 0; i < num_connections; i++)
+    {
+        if (FAILED(IUnknown_QueryInterface(node_pairs[i][1]->object, &IID_IMFStreamSink, (void **)&sink)))
+        {
+            FIXME("Check for MF_CONNECT_AS_OPTIONAL and MF_CONNECT_AS_OPTIONAL_BRANCH flags.\n");
+            heap_free(node_pairs);
+            return MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED;
+        }
+        IMFStreamSink_Release(sink);
+    }
+
+    if (FAILED(hr = MFCreateTopology(&full_topology)))
         return hr;
 
-    return IMFTopology_CloneFrom(*output_topology, input_topology);
+    /* resolve each branch */
+    for (i = 0; i < num_connections; i++)
+    {
+        struct topology_node *src = node_pairs[i][0];
+        struct topology_node *sink = node_pairs[i][1];
+        struct topology *full_topo;
+
+        if (FAILED(hr = topology_loader_resolve_branch(src, sink, topology, full_topo = impl_from_IMFTopology(full_topology))))
+        {
+            if (full_topo->nodes.count)
+            {
+                int count = 0;
+                while (count < full_topo->nodes.count)
+                {
+                    IMFTopologyNode_Release(&full_topo->nodes.nodes[count]->IMFTopologyNode_iface);
+                    count++;
+                }
+            }
+            heap_free(node_pairs);
+            IMFTopology_Release(full_topology);
+            return hr;
+        }
+    }
+
+    *output_topology = full_topology;
+    heap_free(node_pairs);
+    return S_OK;
 }
 
 static const IMFTopoLoaderVtbl topologyloadervtbl =
-- 
2.17.1




More information about the wine-devel mailing list