[PATCH v3 3/3] mf: Partially implement the topology loader.
Nikolay Sivov
nsivov at codeweavers.com
Thu Apr 2 14:05:17 CDT 2020
On 4/2/20 12:11 AM, Sergio Gómez Del Real wrote:
> +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;
> + }
> +}
Second node argument is not used, is that intentional? It also leaks on
every iteration. I'm surprised it works, that you can connect nodes
before adding them,
and then have a situation when one is added and has a connection to
another that isn't yet.
It also assumes that all nodes are 1-1 for i/o count, which is
reasonable, but we'll need a fixme for unsupported cases. Obviously not
in this helper.
> +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
Is it checked anywhere that types are actually compatible? Also, this
function only checks for DIRECT mode, what's a point of iterating over
all methods when it's called?
> + /* 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;
You have similar condition right above that one. I think you can ignore
that for now and assume we only need decoders.
> + for (i = 0; i < num_activates_decs; i++)
> + {
> + IMFTransform *decoder;
> +
> + IMFActivate_ActivateObject(activates_decs[i], &IID_IMFTransform, (void **)&decoder);
This definitely needs some error handling.
> + /* 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]);
> + return S_OK;
> + }
You need to set decoder output type as well, and shutting it down looks,
even if it works. Is it possible loader stashes activator in some attribute?
Or maybe it sets IMFActivate as object itself, and pre-activates it. Or
maybe loader does not use it at all and keeps using CLSIDs.
Conceptually after loader did its job it should still be possible to
shut down.
topology_loader_resolve_branch() has a lot of leaks, for example you
should free returned IMFActivate arrays.
> + 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);
I would prefer to clone whole topology first, and do all necessary fixups.
> + 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)))
> + {
> + topology_loader_add_branch(*full_topology, clone_src, clone_sink);
> + heap_free(src_mediatypes);
> + return S_OK;
> + }
> + }
'enum_src_types' should only control if all supported output types are
considered, and not just current, so why false branch is using DIRECT?
I'd expect you still might want a decoder.
I would suggest to split this patch as much as possible. It's hard to
see the whole picture, but so far I have a feeling that assuming that you
need to resolve from source to sink all the time is not sustainable. For
example if partial topology already has decoders for some branches that
won't apply.
More general approach of resolving from input to output might be better,
for example taking sink media type, comparing to upstream peer,
regardless of node types.
More information about the wine-devel
mailing list