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

Sergio Gómez Del Real sdelreal at codeweavers.com
Thu Apr 2 12:54:04 CDT 2020


On 2/04/20 11:07 a. m., Derek Lesho wrote:

>
> On 4/1/20 4:11 PM, Sergio Gómez Del Real wrote:
>> Signed-off-by: Sergio Gómez Del Real <sdelreal at codeweavers.com>
>> ---
>>   dlls/mf/tests/mf.c |   3 -
>>   dlls/mf/topology.c | 337 ++++++++++++++++++++++++++++++++++++++++++---
>>   2 files changed, 321 insertions(+), 19 deletions(-)
>>
>> diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
>> index 1a762c6874..4ecd928970 100644
>> --- a/dlls/mf/tests/mf.c
>> +++ b/dlls/mf/tests/mf.c
>> @@ -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);
>> diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c
>> index 0b4d734442..7a4c95bea0 100644
>> --- a/dlls/mf/topology.c
>> +++ b/dlls/mf/topology.c
>> @@ -1913,47 +1913,352 @@ 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);
>> +        in = out;
>> +    }
>> +}
>> +
>> +static HRESULT topology_loader_resolve_branch(IMFTopologyNode *src, 
>> IMFMediaType *mediatype, IMFTopologyNode *sink, MF_CONNECT_METHOD 
>> method)
>> +{
>> +    IMFStreamSink *streamsink;
>> +    IMFMediaTypeHandler *mth;
>> +    HRESULT hr;
>> +
>> +    IMFTopologyNode_GetObject(sink, (IUnknown **)&streamsink);
>> +    IMFStreamSink_GetMediaTypeHandler(streamsink, &mth);
>> +    if (method == MF_CONNECT_DIRECT)
>> +    {
>> +        if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, 
>> mediatype)))
>> +            return hr;
>> +        hr = IMFTopologyNode_ConnectOutput(src, 0, sink, 0);
>> +        return hr;
>> +    }
>> +    else
>> +    {
>> +        IMFTopologyNode *node_dec, *node_conv;
>> +        GUID major_type, subtype, mft_category;
>> +        MFT_REGISTER_TYPE_INFO mft_typeinfo;
>> +        UINT32 flags = MFT_ENUM_FLAG_ALL;
>> +        IMFActivate **activates_decs;
>> +        UINT32 num_activates_decs;
>> +        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
>> +            return MF_E_INVALIDMEDIATYPE;
>> +
>> +        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, 0)))
>> +            {
>> +                UINT32 num_activates_convs;
>> +                IMFActivate **activates_convs;
>> +                IMFMediaType *decoder_mtype;
>> +
>> +                int count = 0;
>> +                while 
>> (SUCCEEDED(IMFTransform_GetOutputAvailableType(decoder, 0, count++, 
>> &decoder_mtype)))
>> +                {
>> +                    IMFTransform *converter;
>> +
>> +                    /* succeeded with source -> decoder -> sink */
>> +                    if 
>> (SUCCEEDED(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_convs[i]);
> Shouldn't this be activates_decs?
Yeah... thanks for catching that one.
>> +                        return S_OK;
>> +                    }
>> +
>> +                    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, 0)))
>> +                        {
>> +                            int count = 0;
>> +                            while 
>> (SUCCEEDED(IMFTransform_GetOutputAvailableType(converter, 0, count++, 
>> &converter_mtype)))
>> +                            {
>> +                                /* succeeded with source -> decoder 
>> -> converter -> sink */
>> +                                if 
>> (SUCCEEDED(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]);
>> +                                    return S_OK;
>> +                                }
>> +                            }
>> +                        }
>> + IMFActivate_ShutdownObject(activates_convs[j]);
>> +                    }
>> +                }
>> +            }
>> +            IMFActivate_ShutdownObject(activates_decs[i]);
>> +        }
>> +    }
>> +    return E_FAIL;
>> +}
>> +
>> +static HRESULT topology_loader_resolve_partial_topology(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;
>> +    }
>> +
>> +    hr = IMFTopology_GetUINT32(&topology->IMFTopology_iface, 
>> &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enum_src_types);
>> +
>> +    mtype_src = NULL;
>> +    if (FAILED(hr) || !enum_src_types)
>> +    {
>> +        num_media_types = 1;
>> +        enum_src_types = 0;
>> +        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 (mtype_src)
>> +        src_mediatypes[0] = mtype_src;
>> +    else
>> +        for (i = 0; i < num_media_types; i++)
>> +            IMFMediaTypeHandler_GetMediaTypeByIndex(mth_src, i, 
>> &src_mediatypes[i]);
>> +
>> +
>> +    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(topology_loader_resolve_branch(clone_src, 
>> src_mediatypes[i], clone_sink, method)))
>> +                    {
>> + topology_loader_add_branch(*full_topology, clone_src, clone_sink);
>> +                        heap_free(src_mediatypes);
>> +                        return S_OK;
>> +                    }
>> +        }
>> +        else
>> +        {
>> +            for (i = 0; i < num_media_types; i++)
>> +                for (method = MF_CONNECT_DIRECT; method < 
>> MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
>> +                    if 
>> (SUCCEEDED(topology_loader_resolve_branch(clone_src, 
>> src_mediatypes[i], clone_sink, method)))
>> +                    {
>> + topology_loader_add_branch(*full_topology, clone_src, clone_sink);
>> +                        heap_free(src_mediatypes);
>> +                        return S_OK;
>> +                    }
>> +        }
>> +    }
>> +    else
>> +    {
>> +        if (SUCCEEDED(topology_loader_resolve_branch(clone_src, 
>> src_mediatypes[0], clone_sink, MF_CONNECT_DIRECT)))
> Are you sure we're not supposed to try the various methods here?
Yeah. I changed this to test something and forgot to change it back. 
Thanks :)
>> +        {
>> +            topology_loader_add_branch(*full_topology, clone_src, 
>> clone_sink);
>> +            heap_free(src_mediatypes);
>> +            return S_OK;
>> +        }
>> +    }
>> +
>> +    heap_free(src_mediatypes);
>> +    return MF_E_TOPO_UNSUPPORTED;
>> +}
>> +
>>   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];
>> +    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++;
>> +            }
>>           }
>>       }
>>   +    /* 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(output_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_topology = 
>> unsafe_impl_from_IMFTopology(*output_topology);
>> +
>> +        if (FAILED(hr = 
>> topology_loader_resolve_partial_topology(src, sink, topology, 
>> &full_topology)))
>> +        {
>> +            heap_free(node_pairs);
>> +            return hr;
>> +        }
>> +    }
>> +
>> +    heap_free(node_pairs);
>> +    return S_OK;
>>   }
>>     static const IMFTopoLoaderVtbl topologyloadervtbl =



More information about the wine-devel mailing list