On 4/1/20 4:11 PM, Sergio Gómez Del Real wrote:
Signed-off-by: Sergio Gómez Del Real sdelreal@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;elsereturn 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?
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?
{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 =