[PATCH v5 3/4] mf/topoloader: Implement source node to sink node branch resolver.

Derek Lesho dlesho at codeweavers.com
Mon Nov 30 09:59:40 CST 2020


Signed-off-by: Derek Lesho <dlesho at codeweavers.com>
---
v5: Correct connect method handling.  In v4, the MF_CONNECT_ALLOW_DECODER path is only triggered if the conidtion for sink_method & MF_CONNECT_ALLOW_CONVERTER is not satisfied.
This is never true, effectively making MF_CONNECT_ALLOW_DECODER a noop.  Instead of using else here, just check for FAILED(hr).
---
 dlls/mf/topology.c | 273 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 268 insertions(+), 5 deletions(-)

diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c
index a09f6ef0ef4..e3a4dfd5141 100644
--- a/dlls/mf/topology.c
+++ b/dlls/mf/topology.c
@@ -1992,15 +1992,278 @@ static HRESULT topology_loader_clone_node(struct topoloader_context *context, IM
     return hr;
 }
 
+struct transform_output_type
+{
+    IMFMediaType *type;
+    IMFTransform *transform;
+};
+
+struct connect_context
+{
+    struct topoloader_context *context;
+    IMFTopologyNode *upstream_node;
+    IMFTopologyNode *sink;
+    IMFMediaTypeHandler *sink_handler;
+    const GUID *converter_category;
+};
+
+typedef HRESULT (*p_connect_func)(struct transform_output_type *output_type, struct connect_context *context);
+
+static void topology_loader_release_transforms(IMFActivate **activates, unsigned int count)
+{
+    unsigned int i;
+
+    for (i = 0; i < count; ++i)
+        IMFActivate_Release(activates[i]);
+    CoTaskMemFree(activates);
+}
+
+static HRESULT topology_loader_enumerate_output_types(const GUID *category, IMFMediaType *input_type,
+        p_connect_func connect_func, struct connect_context *context)
+{
+    MFT_REGISTER_TYPE_INFO mft_typeinfo;
+    IMFActivate **activates;
+    unsigned int i, count;
+    HRESULT hr;
+
+    if (FAILED(hr = IMFMediaType_GetMajorType(input_type, &mft_typeinfo.guidMajorType)))
+        return hr;
+
+    if (FAILED(hr = IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &mft_typeinfo.guidSubtype)))
+        return hr;
+
+    if (FAILED(hr = MFTEnumEx(*category, MFT_ENUM_FLAG_ALL, &mft_typeinfo, NULL, &activates, &count)))
+        return hr;
+
+    hr = E_FAIL;
+
+    for (i = 0; i < count; ++i)
+    {
+        IMFTransform *transform;
+
+        if (FAILED(IMFActivate_ActivateObject(activates[i], &IID_IMFTransform, (void **)&transform)))
+        {
+            WARN("Failed to create a transform.\n");
+            continue;
+        }
+
+        if (SUCCEEDED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0)))
+        {
+            struct transform_output_type output_type;
+            unsigned int output_count = 0;
+
+            output_type.transform = transform;
+            while (SUCCEEDED(IMFTransform_GetOutputAvailableType(transform, 0, output_count++, &output_type.type)))
+            {
+                hr = connect_func(&output_type, context);
+                IMFMediaType_Release(output_type.type);
+                if (SUCCEEDED(hr))
+                {
+                    topology_loader_release_transforms(activates, count);
+                    return hr;
+                }
+            }
+        }
+
+        IMFActivate_ShutdownObject(activates[i]);
+    }
+
+    topology_loader_release_transforms(activates, count);
+
+    return hr;
+}
+
+static HRESULT connect_to_sink(struct transform_output_type *output_type, struct connect_context *context)
+{
+    IMFTopologyNode *node;
+    HRESULT hr;
+
+    if (FAILED(IMFMediaTypeHandler_IsMediaTypeSupported(context->sink_handler, output_type->type, NULL)))
+        return MF_E_TRANSFORM_NOT_POSSIBLE_FOR_CURRENT_MEDIATYPE_COMBINATION;
+
+    if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node)))
+        return hr;
+
+    IMFTopologyNode_SetObject(node, (IUnknown *)output_type->transform);
+    IMFTopology_AddNode(context->context->output_topology, node);
+    IMFTopologyNode_ConnectOutput(context->upstream_node, 0, node, 0);
+    IMFTopologyNode_ConnectOutput(node, 0, context->sink, 0);
+
+    IMFTopologyNode_Release(node);
+
+    hr = IMFMediaTypeHandler_SetCurrentMediaType(context->sink_handler, output_type->type);
+    if (SUCCEEDED(hr))
+        hr = IMFTransform_SetOutputType(output_type->transform, 0, output_type->type, 0);
+
+    return S_OK;
+}
+
+static HRESULT connect_to_converter(struct transform_output_type *output_type, struct connect_context *context)
+{
+    struct connect_context sink_ctx;
+    IMFTopologyNode *node;
+    HRESULT hr;
+
+    if (SUCCEEDED(connect_to_sink(output_type, context)))
+        return S_OK;
+
+    if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node)))
+        return hr;
+
+    IMFTopologyNode_SetObject(node, (IUnknown *)output_type->transform);
+
+    sink_ctx = *context;
+    sink_ctx.upstream_node = node;
+
+    if (SUCCEEDED(hr = topology_loader_enumerate_output_types(context->converter_category, output_type->type,
+            connect_to_sink, &sink_ctx)))
+    {
+        hr = IMFTopology_AddNode(context->context->output_topology, node);
+    }
+    IMFTopologyNode_Release(node);
+
+    if (SUCCEEDED(hr))
+    {
+        IMFTopology_AddNode(context->context->output_topology, node);
+        IMFTopologyNode_ConnectOutput(context->upstream_node, 0, node, 0);
+
+        hr = IMFTransform_SetOutputType(output_type->transform, 0, output_type->type, 0);
+    }
+
+    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)
+static HRESULT topology_loader_get_node_type_handler(IMFTopologyNode *node, IMFMediaTypeHandler **handler)
 {
-    FIXME("Unimplemented.\n");
+    MF_TOPOLOGY_TYPE node_type;
+    IMFStreamSink *stream_sink;
+    IMFStreamDescriptor *sd;
+    IUnknown *object;
+    HRESULT hr;
 
-    return E_NOTIMPL;
+    if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type)))
+         return hr;
+
+    switch (node_type)
+    {
+        case MF_TOPOLOGY_OUTPUT_NODE:
+            if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, (IUnknown **)&object)))
+            {
+                if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&stream_sink)))
+                {
+                    hr = IMFStreamSink_GetMediaTypeHandler(stream_sink, handler);
+                    IMFStreamSink_Release(stream_sink);
+                }
+                IUnknown_Release(object);
+            }
+            break;
+        case MF_TOPOLOGY_SOURCESTREAM_NODE:
+            if (SUCCEEDED(hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
+                    &IID_IMFStreamDescriptor, (void **)&sd)))
+            {
+                hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, handler);
+                IMFStreamDescriptor_Release(sd);
+            }
+            break;
+        default:
+            WARN("Unexpected node type %u.\n", node_type);
+            return MF_E_UNEXPECTED;
+    }
+
+    return hr;
+}
+
+static HRESULT topology_loader_get_mft_categories(IMFMediaTypeHandler *handler, GUID *decode_cat, GUID *convert_cat)
+{
+    GUID major;
+    HRESULT hr;
+
+    if (FAILED(hr = IMFMediaTypeHandler_GetMajorType(handler, &major)))
+        return hr;
+
+    if (IsEqualGUID(&major, &MFMediaType_Audio))
+    {
+        *decode_cat = MFT_CATEGORY_AUDIO_DECODER;
+        *convert_cat = MFT_CATEGORY_AUDIO_EFFECT;
+    }
+    else if (IsEqualGUID(&major, &MFMediaType_Video))
+    {
+        *decode_cat = MFT_CATEGORY_VIDEO_DECODER;
+        *convert_cat = MFT_CATEGORY_VIDEO_EFFECT;
+    }
+    else
+    {
+        WARN("Unexpected major type %s.\n", debugstr_guid(&major));
+        return MF_E_INVALIDTYPE;
+    }
+
+    return S_OK;
+}
+
+static HRESULT topology_loader_connect_source_to_sink(struct topoloader_context *context, IMFTopologyNode *source,
+        unsigned int output_index, IMFTopologyNode *sink, unsigned int input_index)
+{
+    IMFMediaTypeHandler *source_handler = NULL, *sink_handler = NULL;
+    struct connect_context convert_ctx, sink_ctx;
+    MF_CONNECT_METHOD source_method, sink_method;
+    GUID decode_cat, convert_cat;
+    IMFMediaType *media_type;
+    HRESULT hr;
+
+    TRACE("attempting to connect %p:%u to %p:%u\n", source, output_index, sink, input_index);
+
+    if (FAILED(hr = topology_loader_get_node_type_handler(source, &source_handler)))
+        goto done;
+
+    if (FAILED(hr = topology_loader_get_node_type_handler(sink, &sink_handler)))
+        goto done;
+
+    if (FAILED(IMFTopologyNode_GetUINT32(source, &MF_TOPONODE_CONNECT_METHOD, &source_method)))
+        source_method = MF_CONNECT_DIRECT;
+    if (FAILED(IMFTopologyNode_GetUINT32(sink, &MF_TOPONODE_CONNECT_METHOD, &sink_method)))
+        sink_method = MF_CONNECT_ALLOW_DECODER;
+
+    if (FAILED(hr = topology_loader_get_mft_categories(source_handler, &decode_cat, &convert_cat)))
+        goto done;
+
+    sink_ctx.context = context;
+    sink_ctx.upstream_node = source;
+    sink_ctx.sink = sink;
+    sink_ctx.sink_handler = sink_handler;
+
+    convert_ctx = sink_ctx;
+    convert_ctx.converter_category = &convert_cat;
+
+    if (SUCCEEDED(hr = IMFMediaTypeHandler_GetCurrentMediaType(source_handler, &media_type)))
+    {
+        /* Direct connection. */
+        if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(sink_handler, media_type, NULL))
+                && SUCCEEDED(hr = IMFMediaTypeHandler_SetCurrentMediaType(sink_handler, media_type)))
+        {
+            hr = IMFTopologyNode_ConnectOutput(source, output_index, sink, input_index);
+        }
+        if (FAILED(hr) && sink_method & MF_CONNECT_ALLOW_CONVERTER)
+        {
+            hr = topology_loader_enumerate_output_types(&convert_cat, media_type, connect_to_sink, &sink_ctx);
+        }
+        if (FAILED(hr) && sink_method & MF_CONNECT_ALLOW_DECODER)
+        {
+            hr = topology_loader_enumerate_output_types(&decode_cat, media_type, connect_to_converter, &convert_ctx);
+        }
+
+        IMFMediaType_Release(media_type);
+    }
+
+done:
+    if (source_handler)
+        IMFMediaTypeHandler_Release(source_handler);
+    if (sink_handler)
+        IMFMediaTypeHandler_Release(sink_handler);
+
+    return hr;
 }
 
 static HRESULT topology_loader_resolve_branch(struct topoloader_context *context, IMFTopologyNode *upstream_node,
@@ -2009,7 +2272,7 @@ static HRESULT topology_loader_resolve_branch(struct topoloader_context *context
     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 },
+    /* SOURCESTREAM */ { topology_loader_connect_source_to_sink, NULL, NULL, NULL },
        /* TRANSFORM */ { NULL },
              /* TEE */ { NULL },
     };
-- 
2.29.2




More information about the wine-devel mailing list