From: R��mi Bernon rbernon@codeweavers.com
--- dlls/mf/Makefile.in | 3 +- dlls/mf/mf_private.h | 1 + dlls/mf/topology.c | 797 +----------------------------------- dlls/mf/topology_loader.c | 826 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 830 insertions(+), 797 deletions(-) create mode 100644 dlls/mf/topology_loader.c
diff --git a/dlls/mf/Makefile.in b/dlls/mf/Makefile.in index 36727d4d4e3..d5478cf4853 100644 --- a/dlls/mf/Makefile.in +++ b/dlls/mf/Makefile.in @@ -14,7 +14,8 @@ C_SRCS = \ samplegrabber.c \ sar.c \ session.c \ - topology.c + topology.c \ + topology_loader.c
IDL_SRCS = mf.idl
diff --git a/dlls/mf/mf_private.h b/dlls/mf/mf_private.h index 6f28c93aea3..bd1d6c7537b 100644 --- a/dlls/mf/mf_private.h +++ b/dlls/mf/mf_private.h @@ -116,3 +116,4 @@ static inline const char *debugstr_propvar(const PROPVARIANT *v) extern BOOL mf_is_sample_copier_transform(IMFTransform *transform) DECLSPEC_HIDDEN; extern BOOL mf_is_sar_sink(IMFMediaSink *sink) DECLSPEC_HIDDEN; extern HRESULT topology_node_get_object(IMFTopologyNode *node, REFIID riid, void **obj) DECLSPEC_HIDDEN; +extern HRESULT topology_node_get_type_handler(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaTypeHandler **handler) DECLSPEC_HIDDEN; diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index e158ba1fc82..d9d1bc1c57e 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -79,12 +79,6 @@ struct topology TOPOID id; };
-struct topology_loader -{ - IMFTopoLoader IMFTopoLoader_iface; - LONG refcount; -}; - struct seq_source { IMFSequencerSource IMFSequencerSource_iface; @@ -117,11 +111,6 @@ static HRESULT topology_node_connect_output(struct topology_node *node, DWORD ou
static struct topology *unsafe_impl_from_IMFTopology(IMFTopology *iface);
-static struct topology_loader *impl_from_IMFTopoLoader(IMFTopoLoader *iface) -{ - return CONTAINING_RECORD(iface, struct topology_loader, IMFTopoLoader_iface); -} - static struct seq_source *impl_from_IMFSequencerSource(IMFSequencerSource *iface) { return CONTAINING_RECORD(iface, struct seq_source, IMFSequencerSource_iface); @@ -1820,7 +1809,7 @@ HRESULT WINAPI MFCreateTopologyNode(MF_TOPOLOGY_TYPE node_type, IMFTopologyNode return hr; }
-static HRESULT topology_node_get_type_handler(IMFTopologyNode *node, DWORD stream, +HRESULT topology_node_get_type_handler(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaTypeHandler **handler) { MF_TOPOLOGY_TYPE node_type; @@ -1913,790 +1902,6 @@ HRESULT WINAPI MFGetTopoNodeCurrentType(IMFTopologyNode *node, DWORD stream, BOO return hr; }
-static HRESULT WINAPI topology_loader_QueryInterface(IMFTopoLoader *iface, REFIID riid, void **out) -{ - TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); - - if (IsEqualIID(riid, &IID_IMFTopoLoader) || - IsEqualIID(riid, &IID_IUnknown)) - { - *out = iface; - IMFTopoLoader_AddRef(iface); - return S_OK; - } - - WARN("Unsupported %s.\n", debugstr_guid(riid)); - *out = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI topology_loader_AddRef(IMFTopoLoader *iface) -{ - struct topology_loader *loader = impl_from_IMFTopoLoader(iface); - ULONG refcount = InterlockedIncrement(&loader->refcount); - - TRACE("%p, refcount %lu.\n", iface, refcount); - - return refcount; -} - -static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface) -{ - struct topology_loader *loader = impl_from_IMFTopoLoader(iface); - ULONG refcount = InterlockedDecrement(&loader->refcount); - - TRACE("%p, refcount %lu.\n", iface, refcount); - - if (!refcount) - free(loader); - - return refcount; -} - -struct topoloader_context -{ - IMFTopology *input_topology; - IMFTopology *output_topology; - unsigned int marker; - GUID key; -}; - -static IMFTopologyNode *topology_loader_get_node_for_marker(struct topoloader_context *context, TOPOID *id) -{ - IMFTopologyNode *node; - unsigned short i = 0; - unsigned int value; - - while (SUCCEEDED(IMFTopology_GetNode(context->output_topology, i++, &node))) - { - if (SUCCEEDED(IMFTopologyNode_GetUINT32(node, &context->key, &value)) && value == context->marker) - { - IMFTopologyNode_GetTopoNodeID(node, id); - return node; - } - IMFTopologyNode_Release(node); - } - - *id = 0; - return NULL; -} - -static HRESULT topology_loader_clone_node(struct topoloader_context *context, IMFTopologyNode *node, - IMFTopologyNode **ret, unsigned int marker) -{ - IMFTopologyNode *cloned_node; - MF_TOPOLOGY_TYPE node_type; - HRESULT hr; - - if (ret) *ret = NULL; - - IMFTopologyNode_GetNodeType(node, &node_type); - - if (FAILED(hr = MFCreateTopologyNode(node_type, &cloned_node))) - return hr; - - if (SUCCEEDED(hr = IMFTopologyNode_CloneFrom(cloned_node, node))) - hr = IMFTopologyNode_SetUINT32(cloned_node, &context->key, marker); - - if (SUCCEEDED(hr)) - hr = IMFTopology_AddNode(context->output_topology, cloned_node); - - if (SUCCEEDED(hr) && ret) - { - *ret = cloned_node; - IMFTopologyNode_AddRef(*ret); - } - - IMFTopologyNode_Release(cloned_node); - - return hr; -} - -struct transform_output_type -{ - IMFMediaType *type; - IMFTransform *transform; - IMFActivate *activate; -}; - -struct connect_context -{ - struct topoloader_context *context; - IMFTopologyNode *upstream_node; - IMFTopologyNode *sink; - IMFMediaTypeHandler *sink_handler; - unsigned int output_index; - unsigned int input_index; - GUID converter_category; - GUID decoder_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; - output_type.activate = activates[i]; - 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 topology_loader_create_transform(const struct transform_output_type *output_type, - IMFTopologyNode **node) -{ - HRESULT hr; - GUID guid; - - if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, node))) - return hr; - - IMFTopologyNode_SetObject(*node, (IUnknown *)output_type->transform); - - if (SUCCEEDED(IMFActivate_GetGUID(output_type->activate, &MF_TRANSFORM_CATEGORY_Attribute, &guid)) && - (IsEqualGUID(&guid, &MFT_CATEGORY_AUDIO_DECODER) || IsEqualGUID(&guid, &MFT_CATEGORY_VIDEO_DECODER))) - { - IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_DECODER, 1); - } - - if (SUCCEEDED(IMFActivate_GetGUID(output_type->activate, &MFT_TRANSFORM_CLSID_Attribute, &guid))) - IMFTopologyNode_SetGUID(*node, &MF_TOPONODE_TRANSFORM_OBJECTID, &guid); - - 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 = topology_loader_create_transform(output_type, &node))) - return hr; - - 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 = topology_loader_create_transform(output_type, &node))) - return hr; - - 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_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(IMFMediaTypeHandler *sink_handler, unsigned int sink_method, - struct connect_context *sink_ctx, struct connect_context *convert_ctx, IMFMediaType *media_type) -{ - HRESULT hr; - - if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(sink_handler, media_type, NULL)) - && SUCCEEDED(hr = IMFMediaTypeHandler_SetCurrentMediaType(sink_handler, media_type))) - { - hr = IMFTopologyNode_ConnectOutput(sink_ctx->upstream_node, sink_ctx->output_index, sink_ctx->sink, sink_ctx->input_index); - } - - if (FAILED(hr) && sink_method & MF_CONNECT_ALLOW_CONVERTER) - { - hr = topology_loader_enumerate_output_types(&convert_ctx->converter_category, media_type, connect_to_sink, sink_ctx); - } - - if (FAILED(hr) && sink_method & MF_CONNECT_ALLOW_DECODER) - { - hr = topology_loader_enumerate_output_types(&convert_ctx->decoder_category, media_type, - connect_to_converter, convert_ctx); - } - - return hr; -} - -static HRESULT topology_loader_foreach_source_type(IMFMediaTypeHandler *sink_handler, IMFMediaTypeHandler *source_handler, - unsigned int sink_method, struct connect_context *sink_ctx, struct connect_context *convert_ctx) -{ - unsigned int index = 0; - IMFMediaType *media_type; - HRESULT hr; - - while (SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(source_handler, index++, &media_type))) - { - hr = topology_loader_connect(sink_handler, sink_method, sink_ctx, convert_ctx, media_type); - if (SUCCEEDED(hr)) break; - IMFMediaType_Release(media_type); - media_type = NULL; - } - - if (media_type) - { - hr = IMFMediaTypeHandler_SetCurrentMediaType(source_handler, media_type); - IMFMediaType_Release(media_type); - } - - return hr; -} - -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; - unsigned int enumerate_source_types = 0; - 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_node_get_type_handler(source, output_index, TRUE, &source_handler))) - goto done; - if (FAILED(hr = topology_node_get_type_handler(sink, input_index, FALSE, &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; - - sink_ctx.context = context; - sink_ctx.upstream_node = source; - sink_ctx.sink = sink; - sink_ctx.sink_handler = sink_handler; - sink_ctx.output_index = output_index; - sink_ctx.input_index = input_index; - - convert_ctx = sink_ctx; - if (FAILED(hr = topology_loader_get_mft_categories(source_handler, &convert_ctx.decoder_category, - &convert_ctx.converter_category))) - goto done; - - IMFTopology_GetUINT32(context->output_topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enumerate_source_types); - - if (enumerate_source_types) - { - if (source_method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES) - { - hr = topology_loader_foreach_source_type(sink_handler, source_handler, MF_CONNECT_ALLOW_DECODER, - &sink_ctx, &convert_ctx); - } - else - { - hr = topology_loader_foreach_source_type(sink_handler, source_handler, MF_CONNECT_DIRECT, - &sink_ctx, &convert_ctx); - if (FAILED(hr)) - hr = topology_loader_foreach_source_type(sink_handler, source_handler, MF_CONNECT_ALLOW_CONVERTER, - &sink_ctx, &convert_ctx); - if (FAILED(hr)) - hr = topology_loader_foreach_source_type(sink_handler, source_handler, MF_CONNECT_ALLOW_DECODER, - &sink_ctx, &convert_ctx); - } - } - else - { - if (SUCCEEDED(hr = IMFMediaTypeHandler_GetCurrentMediaType(source_handler, &media_type))) - { - hr = topology_loader_connect(sink_handler, sink_method, &sink_ctx, &convert_ctx, media_type); - 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, - unsigned int output_index, IMFTopologyNode *downstream_node, unsigned input_index) -{ - 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_to_sink, NULL, NULL, NULL }, - /* TRANSFORM */ { NULL }, - /* TEE */ { NULL }, - }; - MF_TOPOLOGY_TYPE u_type, d_type; - IMFTopologyNode *node; - HRESULT hr; - TOPOID id; - - /* Downstream node might have already been cloned. */ - IMFTopologyNode_GetTopoNodeID(downstream_node, &id); - if (FAILED(IMFTopology_GetNodeByID(context->output_topology, id, &node))) - topology_loader_clone_node(context, downstream_node, &node, context->marker + 1); - - IMFTopologyNode_GetNodeType(upstream_node, &u_type); - IMFTopologyNode_GetNodeType(downstream_node, &d_type); - - if (!connectors[u_type][d_type]) - { - WARN("Unsupported branch kind %d -> %d.\n", u_type, d_type); - IMFTopologyNode_Release(node); - return E_FAIL; - } - - hr = connectors[u_type][d_type](context, upstream_node, output_index, node, input_index); - IMFTopologyNode_Release(node); - return hr; -} - -static HRESULT topology_loader_resolve_nodes(struct topoloader_context *context, unsigned int *layer_size) -{ - IMFTopologyNode *downstream_node, *node, *orig_node; - MF_TOPOLOGY_TYPE node_type; - unsigned int size = 0; - DWORD input_index; - HRESULT hr = S_OK; - TOPOID id; - - while ((node = topology_loader_get_node_for_marker(context, &id))) - { - ++size; - - IMFTopologyNode_GetNodeType(node, &node_type); - switch (node_type) - { - case MF_TOPOLOGY_SOURCESTREAM_NODE: - if (SUCCEEDED(hr = IMFTopology_GetNodeByID(context->input_topology, id, &orig_node))) - { - hr = IMFTopologyNode_GetOutput(orig_node, 0, &downstream_node, &input_index); - IMFTopologyNode_Release(orig_node); - } - - if (FAILED(hr)) - { - IMFTopology_RemoveNode(context->output_topology, node); - IMFTopologyNode_Release(node); - continue; - } - - hr = topology_loader_resolve_branch(context, node, 0, downstream_node, input_index); - IMFTopologyNode_Release(downstream_node); - break; - case MF_TOPOLOGY_TRANSFORM_NODE: - case MF_TOPOLOGY_TEE_NODE: - FIXME("Unsupported node type %d.\n", node_type); - break; - default: - WARN("Unexpected node type %d.\n", node_type); - } - - IMFTopologyNode_DeleteItem(node, &context->key); - IMFTopologyNode_Release(node); - - if (FAILED(hr)) - break; - } - - *layer_size = size; - - return hr; -} - -static BOOL topology_loader_is_node_d3d_aware(IMFTopologyNode *node) -{ - IMFAttributes *attributes; - unsigned int d3d_aware = 0; - IMFTransform *transform; - - if (FAILED(topology_node_get_object(node, &IID_IMFAttributes, (void **)&attributes))) - return FALSE; - - IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &d3d_aware); - IMFAttributes_Release(attributes); - - if (!d3d_aware && SUCCEEDED(topology_node_get_object(node, &IID_IMFTransform, (void **)&transform))) - { - d3d_aware = mf_is_sample_copier_transform(transform); - IMFTransform_Release(transform); - } - - return !!d3d_aware; -} - -static HRESULT topology_loader_create_copier(IMFTopologyNode *upstream_node, DWORD upstream_output, - IMFTopologyNode *downstream_node, unsigned int downstream_input, IMFTransform **copier) -{ - IMFMediaType *input_type = NULL, *output_type = NULL; - IMFTransform *transform; - HRESULT hr; - - if (FAILED(hr = MFCreateSampleCopierMFT(&transform))) - return hr; - - if (FAILED(hr = MFGetTopoNodeCurrentType(upstream_node, upstream_output, TRUE, &input_type))) - WARN("Failed to get upstream media type hr %#lx.\n", hr); - - if (SUCCEEDED(hr) && FAILED(hr = MFGetTopoNodeCurrentType(downstream_node, downstream_input, FALSE, &output_type))) - WARN("Failed to get downstream media type hr %#lx.\n", hr); - - if (SUCCEEDED(hr) && FAILED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0))) - WARN("Input type wasn't accepted, hr %#lx.\n", hr); - - if (SUCCEEDED(hr) && FAILED(hr = IMFTransform_SetOutputType(transform, 0, output_type, 0))) - WARN("Output type wasn't accepted, hr %#lx.\n", hr); - - if (SUCCEEDED(hr)) - { - *copier = transform; - IMFTransform_AddRef(*copier); - } - - if (input_type) - IMFMediaType_Release(input_type); - if (output_type) - IMFMediaType_Release(output_type); - - IMFTransform_Release(transform); - - return hr; -} - -static HRESULT topology_loader_connect_copier(struct topoloader_context *context, IMFTopologyNode *upstream_node, - DWORD upstream_output, IMFTopologyNode *downstream_node, DWORD downstream_input, IMFTransform *copier) -{ - IMFTopologyNode *copier_node; - HRESULT hr; - - if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &copier_node))) - return hr; - - IMFTopologyNode_SetObject(copier_node, (IUnknown *)copier); - IMFTopology_AddNode(context->output_topology, copier_node); - IMFTopologyNode_ConnectOutput(upstream_node, upstream_output, copier_node, 0); - IMFTopologyNode_ConnectOutput(copier_node, 0, downstream_node, downstream_input); - - IMFTopologyNode_Release(copier_node); - - return S_OK; -} - -/* Right now this should be used for output nodes only. */ -static HRESULT topology_loader_connect_d3d_aware_input(struct topoloader_context *context, - IMFTopologyNode *node) -{ - IMFTopologyNode *upstream_node; - IMFTransform *copier = NULL; - IMFStreamSink *stream_sink; - DWORD upstream_output; - HRESULT hr; - - if (FAILED(hr = topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink))) - return hr; - - if (topology_loader_is_node_d3d_aware(node)) - { - if (SUCCEEDED(IMFTopologyNode_GetInput(node, 0, &upstream_node, &upstream_output))) - { - if (!topology_loader_is_node_d3d_aware(upstream_node)) - { - if (SUCCEEDED(hr = topology_loader_create_copier(upstream_node, upstream_output, node, 0, &copier))) - { - hr = topology_loader_connect_copier(context, upstream_node, upstream_output, node, 0, copier); - IMFTransform_Release(copier); - } - } - IMFTopologyNode_Release(upstream_node); - } - } - - IMFStreamSink_Release(stream_sink); - - return hr; -} - -static void topology_loader_resolve_complete(struct topoloader_context *context) -{ - MF_TOPOLOGY_TYPE node_type; - IMFTopologyNode *node; - WORD i, node_count; - HRESULT hr; - - IMFTopology_GetNodeCount(context->output_topology, &node_count); - - for (i = 0; i < node_count; ++i) - { - if (SUCCEEDED(IMFTopology_GetNode(context->output_topology, i, &node))) - { - IMFTopologyNode_GetNodeType(node, &node_type); - - if (node_type == MF_TOPOLOGY_OUTPUT_NODE) - { - /* Set MF_TOPONODE_STREAMID for all outputs. */ - if (FAILED(IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAMID, NULL))) - IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_STREAMID, 0); - - if (FAILED(hr = topology_loader_connect_d3d_aware_input(context, node))) - WARN("Failed to connect D3D-aware input, hr %#lx.\n", hr); - } - else if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) - { - /* Set MF_TOPONODE_MEDIASTART for all sources. */ - if (FAILED(IMFTopologyNode_GetItem(node, &MF_TOPONODE_MEDIASTART, NULL))) - IMFTopologyNode_SetUINT64(node, &MF_TOPONODE_MEDIASTART, 0); - } - - IMFTopologyNode_Release(node); - } - } -} - -static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, - IMFTopology **ret_topology, IMFTopology *current_topology) -{ - struct topoloader_context context = { 0 }; - IMFTopology *output_topology; - MF_TOPOLOGY_TYPE node_type; - unsigned int layer_size; - IMFTopologyNode *node; - unsigned short i = 0; - IMFStreamSink *sink; - IUnknown *object; - HRESULT hr = E_FAIL; - - FIXME("%p, %p, %p, %p.\n", iface, input_topology, ret_topology, current_topology); - - if (current_topology) - FIXME("Current topology instance is ignored.\n"); - - /* Basic sanity checks for input topology: - - - source nodes must have stream descriptor set; - - sink nodes must be resolved to stream sink objects; - */ - while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node))) - { - IMFTopologyNode_GetNodeType(node, &node_type); - - switch (node_type) - { - case MF_TOPOLOGY_OUTPUT_NODE: - if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object))) - { - /* Sinks must be bound beforehand. */ - if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&sink))) - hr = MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; - else if (sink) - IMFStreamSink_Release(sink); - IUnknown_Release(object); - } - break; - case MF_TOPOLOGY_SOURCESTREAM_NODE: - hr = IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL); - break; - default: - ; - } - - IMFTopologyNode_Release(node); - if (FAILED(hr)) - return hr; - } - - if (FAILED(hr = MFCreateTopology(&output_topology))) - return hr; - - IMFTopology_CopyAllItems(input_topology, (IMFAttributes *)output_topology); - - context.input_topology = input_topology; - context.output_topology = output_topology; - memset(&context.key, 0xff, sizeof(context.key)); - - /* Clone source nodes, use initial marker value. */ - i = 0; - while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node))) - { - IMFTopologyNode_GetNodeType(node, &node_type); - - if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) - { - if (FAILED(hr = topology_loader_clone_node(&context, node, NULL, 0))) - WARN("Failed to clone source node, hr %#lx.\n", hr); - } - - IMFTopologyNode_Release(node); - } - - for (context.marker = 0;; ++context.marker) - { - if (FAILED(hr = topology_loader_resolve_nodes(&context, &layer_size))) - { - WARN("Failed to resolve for marker %u, hr %#lx.\n", context.marker, hr); - break; - } - - /* Reached last marker value. */ - if (!layer_size) - break; - } - - if (FAILED(hr)) - IMFTopology_Release(output_topology); - else - { - topology_loader_resolve_complete(&context); - *ret_topology = output_topology; - } - - return hr; -} - -static const IMFTopoLoaderVtbl topologyloadervtbl = -{ - topology_loader_QueryInterface, - topology_loader_AddRef, - topology_loader_Release, - topology_loader_Load, -}; - -/*********************************************************************** - * MFCreateTopoLoader (mf.@) - */ -HRESULT WINAPI MFCreateTopoLoader(IMFTopoLoader **loader) -{ - struct topology_loader *object; - - TRACE("%p.\n", loader); - - if (!loader) - return E_POINTER; - - if (!(object = calloc(1, sizeof(*object)))) - return E_OUTOFMEMORY; - - object->IMFTopoLoader_iface.lpVtbl = &topologyloadervtbl; - object->refcount = 1; - - *loader = &object->IMFTopoLoader_iface; - - return S_OK; -} - static HRESULT WINAPI seq_source_QueryInterface(IMFSequencerSource *iface, REFIID riid, void **out) { struct seq_source *seq_source = impl_from_IMFSequencerSource(iface); diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c new file mode 100644 index 00000000000..2ab92393c3e --- /dev/null +++ b/dlls/mf/topology_loader.c @@ -0,0 +1,826 @@ +/* + * Copyright 2017 Nikolay Sivov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> +#include <stddef.h> + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" + +#include "mfidl.h" + +#include "wine/debug.h" + +#include "mf_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +struct topology_loader +{ + IMFTopoLoader IMFTopoLoader_iface; + LONG refcount; +}; + +static inline struct topology_loader *impl_from_IMFTopoLoader(IMFTopoLoader *iface) +{ + return CONTAINING_RECORD(iface, struct topology_loader, IMFTopoLoader_iface); +} + +static HRESULT WINAPI topology_loader_QueryInterface(IMFTopoLoader *iface, REFIID riid, void **out) +{ + TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IMFTopoLoader) + || IsEqualIID(riid, &IID_IUnknown)) + { + *out = iface; + IMFTopoLoader_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI topology_loader_AddRef(IMFTopoLoader *iface) +{ + struct topology_loader *loader = impl_from_IMFTopoLoader(iface); + ULONG refcount = InterlockedIncrement(&loader->refcount); + TRACE("iface %p, refcount %lu.\n", iface, refcount); + return refcount; +} + +static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface) +{ + struct topology_loader *loader = impl_from_IMFTopoLoader(iface); + ULONG refcount = InterlockedDecrement(&loader->refcount); + + TRACE("iface %p, refcount %lu.\n", iface, refcount); + + if (!refcount) + free(loader); + + return refcount; +} + +struct topoloader_context +{ + IMFTopology *input_topology; + IMFTopology *output_topology; + unsigned int marker; + GUID key; +}; + +static IMFTopologyNode *topology_loader_get_node_for_marker(struct topoloader_context *context, TOPOID *id) +{ + IMFTopologyNode *node; + unsigned short i = 0; + unsigned int value; + + while (SUCCEEDED(IMFTopology_GetNode(context->output_topology, i++, &node))) + { + if (SUCCEEDED(IMFTopologyNode_GetUINT32(node, &context->key, &value)) && value == context->marker) + { + IMFTopologyNode_GetTopoNodeID(node, id); + return node; + } + IMFTopologyNode_Release(node); + } + + *id = 0; + return NULL; +} + +static HRESULT topology_loader_clone_node(struct topoloader_context *context, IMFTopologyNode *node, + IMFTopologyNode **ret, unsigned int marker) +{ + IMFTopologyNode *cloned_node; + MF_TOPOLOGY_TYPE node_type; + HRESULT hr; + + if (ret) *ret = NULL; + + IMFTopologyNode_GetNodeType(node, &node_type); + + if (FAILED(hr = MFCreateTopologyNode(node_type, &cloned_node))) + return hr; + + if (SUCCEEDED(hr = IMFTopologyNode_CloneFrom(cloned_node, node))) + hr = IMFTopologyNode_SetUINT32(cloned_node, &context->key, marker); + + if (SUCCEEDED(hr)) + hr = IMFTopology_AddNode(context->output_topology, cloned_node); + + if (SUCCEEDED(hr) && ret) + { + *ret = cloned_node; + IMFTopologyNode_AddRef(*ret); + } + + IMFTopologyNode_Release(cloned_node); + + return hr; +} + +struct transform_output_type +{ + IMFMediaType *type; + IMFTransform *transform; + IMFActivate *activate; +}; + +struct connect_context +{ + struct topoloader_context *context; + IMFTopologyNode *upstream_node; + IMFTopologyNode *sink; + IMFMediaTypeHandler *sink_handler; + unsigned int output_index; + unsigned int input_index; + GUID converter_category; + GUID decoder_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; + output_type.activate = activates[i]; + 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 topology_loader_create_transform(const struct transform_output_type *output_type, + IMFTopologyNode **node) +{ + HRESULT hr; + GUID guid; + + if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, node))) + return hr; + + IMFTopologyNode_SetObject(*node, (IUnknown *)output_type->transform); + + if (SUCCEEDED(IMFActivate_GetGUID(output_type->activate, &MF_TRANSFORM_CATEGORY_Attribute, &guid)) && + (IsEqualGUID(&guid, &MFT_CATEGORY_AUDIO_DECODER) || IsEqualGUID(&guid, &MFT_CATEGORY_VIDEO_DECODER))) + { + IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_DECODER, 1); + } + + if (SUCCEEDED(IMFActivate_GetGUID(output_type->activate, &MFT_TRANSFORM_CLSID_Attribute, &guid))) + IMFTopologyNode_SetGUID(*node, &MF_TOPONODE_TRANSFORM_OBJECTID, &guid); + + 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 = topology_loader_create_transform(output_type, &node))) + return hr; + + 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 = topology_loader_create_transform(output_type, &node))) + return hr; + + 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_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(IMFMediaTypeHandler *sink_handler, unsigned int sink_method, + struct connect_context *sink_ctx, struct connect_context *convert_ctx, IMFMediaType *media_type) +{ + HRESULT hr; + + if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(sink_handler, media_type, NULL)) + && SUCCEEDED(hr = IMFMediaTypeHandler_SetCurrentMediaType(sink_handler, media_type))) + { + hr = IMFTopologyNode_ConnectOutput(sink_ctx->upstream_node, sink_ctx->output_index, sink_ctx->sink, sink_ctx->input_index); + } + + if (FAILED(hr) && sink_method & MF_CONNECT_ALLOW_CONVERTER) + { + hr = topology_loader_enumerate_output_types(&convert_ctx->converter_category, media_type, connect_to_sink, sink_ctx); + } + + if (FAILED(hr) && sink_method & MF_CONNECT_ALLOW_DECODER) + { + hr = topology_loader_enumerate_output_types(&convert_ctx->decoder_category, media_type, + connect_to_converter, convert_ctx); + } + + return hr; +} + +static HRESULT topology_loader_foreach_source_type(IMFMediaTypeHandler *sink_handler, IMFMediaTypeHandler *source_handler, + unsigned int sink_method, struct connect_context *sink_ctx, struct connect_context *convert_ctx) +{ + unsigned int index = 0; + IMFMediaType *media_type; + HRESULT hr; + + while (SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(source_handler, index++, &media_type))) + { + hr = topology_loader_connect(sink_handler, sink_method, sink_ctx, convert_ctx, media_type); + if (SUCCEEDED(hr)) break; + IMFMediaType_Release(media_type); + media_type = NULL; + } + + if (media_type) + { + hr = IMFMediaTypeHandler_SetCurrentMediaType(source_handler, media_type); + IMFMediaType_Release(media_type); + } + + return hr; +} + +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; + unsigned int enumerate_source_types = 0; + 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_node_get_type_handler(source, output_index, TRUE, &source_handler))) + goto done; + if (FAILED(hr = topology_node_get_type_handler(sink, input_index, FALSE, &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; + + sink_ctx.context = context; + sink_ctx.upstream_node = source; + sink_ctx.sink = sink; + sink_ctx.sink_handler = sink_handler; + sink_ctx.output_index = output_index; + sink_ctx.input_index = input_index; + + convert_ctx = sink_ctx; + if (FAILED(hr = topology_loader_get_mft_categories(source_handler, &convert_ctx.decoder_category, + &convert_ctx.converter_category))) + goto done; + + IMFTopology_GetUINT32(context->output_topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enumerate_source_types); + + if (enumerate_source_types) + { + if (source_method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES) + { + hr = topology_loader_foreach_source_type(sink_handler, source_handler, MF_CONNECT_ALLOW_DECODER, + &sink_ctx, &convert_ctx); + } + else + { + hr = topology_loader_foreach_source_type(sink_handler, source_handler, MF_CONNECT_DIRECT, + &sink_ctx, &convert_ctx); + if (FAILED(hr)) + hr = topology_loader_foreach_source_type(sink_handler, source_handler, MF_CONNECT_ALLOW_CONVERTER, + &sink_ctx, &convert_ctx); + if (FAILED(hr)) + hr = topology_loader_foreach_source_type(sink_handler, source_handler, MF_CONNECT_ALLOW_DECODER, + &sink_ctx, &convert_ctx); + } + } + else + { + if (SUCCEEDED(hr = IMFMediaTypeHandler_GetCurrentMediaType(source_handler, &media_type))) + { + hr = topology_loader_connect(sink_handler, sink_method, &sink_ctx, &convert_ctx, media_type); + 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, + unsigned int output_index, IMFTopologyNode *downstream_node, unsigned input_index) +{ + 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_to_sink, NULL, NULL, NULL }, + /* TRANSFORM */ { NULL }, + /* TEE */ { NULL }, + }; + MF_TOPOLOGY_TYPE u_type, d_type; + IMFTopologyNode *node; + HRESULT hr; + TOPOID id; + + /* Downstream node might have already been cloned. */ + IMFTopologyNode_GetTopoNodeID(downstream_node, &id); + if (FAILED(IMFTopology_GetNodeByID(context->output_topology, id, &node))) + topology_loader_clone_node(context, downstream_node, &node, context->marker + 1); + + IMFTopologyNode_GetNodeType(upstream_node, &u_type); + IMFTopologyNode_GetNodeType(downstream_node, &d_type); + + if (!connectors[u_type][d_type]) + { + WARN("Unsupported branch kind %d -> %d.\n", u_type, d_type); + IMFTopologyNode_Release(node); + return E_FAIL; + } + + hr = connectors[u_type][d_type](context, upstream_node, output_index, node, input_index); + IMFTopologyNode_Release(node); + return hr; +} + +static HRESULT topology_loader_resolve_nodes(struct topoloader_context *context, unsigned int *layer_size) +{ + IMFTopologyNode *downstream_node, *node, *orig_node; + MF_TOPOLOGY_TYPE node_type; + unsigned int size = 0; + DWORD input_index; + HRESULT hr = S_OK; + TOPOID id; + + while ((node = topology_loader_get_node_for_marker(context, &id))) + { + ++size; + + IMFTopologyNode_GetNodeType(node, &node_type); + switch (node_type) + { + case MF_TOPOLOGY_SOURCESTREAM_NODE: + if (SUCCEEDED(hr = IMFTopology_GetNodeByID(context->input_topology, id, &orig_node))) + { + hr = IMFTopologyNode_GetOutput(orig_node, 0, &downstream_node, &input_index); + IMFTopologyNode_Release(orig_node); + } + + if (FAILED(hr)) + { + IMFTopology_RemoveNode(context->output_topology, node); + IMFTopologyNode_Release(node); + continue; + } + + hr = topology_loader_resolve_branch(context, node, 0, downstream_node, input_index); + IMFTopologyNode_Release(downstream_node); + break; + case MF_TOPOLOGY_TRANSFORM_NODE: + case MF_TOPOLOGY_TEE_NODE: + FIXME("Unsupported node type %d.\n", node_type); + break; + default: + WARN("Unexpected node type %d.\n", node_type); + } + + IMFTopologyNode_DeleteItem(node, &context->key); + IMFTopologyNode_Release(node); + + if (FAILED(hr)) + break; + } + + *layer_size = size; + + return hr; +} + +static BOOL topology_loader_is_node_d3d_aware(IMFTopologyNode *node) +{ + IMFAttributes *attributes; + unsigned int d3d_aware = 0; + IMFTransform *transform; + + if (FAILED(topology_node_get_object(node, &IID_IMFAttributes, (void **)&attributes))) + return FALSE; + + IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &d3d_aware); + IMFAttributes_Release(attributes); + + if (!d3d_aware && SUCCEEDED(topology_node_get_object(node, &IID_IMFTransform, (void **)&transform))) + { + d3d_aware = mf_is_sample_copier_transform(transform); + IMFTransform_Release(transform); + } + + return !!d3d_aware; +} + +static HRESULT topology_loader_create_copier(IMFTopologyNode *upstream_node, DWORD upstream_output, + IMFTopologyNode *downstream_node, unsigned int downstream_input, IMFTransform **copier) +{ + IMFMediaType *input_type = NULL, *output_type = NULL; + IMFTransform *transform; + HRESULT hr; + + if (FAILED(hr = MFCreateSampleCopierMFT(&transform))) + return hr; + + if (FAILED(hr = MFGetTopoNodeCurrentType(upstream_node, upstream_output, TRUE, &input_type))) + WARN("Failed to get upstream media type hr %#lx.\n", hr); + + if (SUCCEEDED(hr) && FAILED(hr = MFGetTopoNodeCurrentType(downstream_node, downstream_input, FALSE, &output_type))) + WARN("Failed to get downstream media type hr %#lx.\n", hr); + + if (SUCCEEDED(hr) && FAILED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0))) + WARN("Input type wasn't accepted, hr %#lx.\n", hr); + + if (SUCCEEDED(hr) && FAILED(hr = IMFTransform_SetOutputType(transform, 0, output_type, 0))) + WARN("Output type wasn't accepted, hr %#lx.\n", hr); + + if (SUCCEEDED(hr)) + { + *copier = transform; + IMFTransform_AddRef(*copier); + } + + if (input_type) + IMFMediaType_Release(input_type); + if (output_type) + IMFMediaType_Release(output_type); + + IMFTransform_Release(transform); + + return hr; +} + +static HRESULT topology_loader_connect_copier(struct topoloader_context *context, IMFTopologyNode *upstream_node, + DWORD upstream_output, IMFTopologyNode *downstream_node, DWORD downstream_input, IMFTransform *copier) +{ + IMFTopologyNode *copier_node; + HRESULT hr; + + if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &copier_node))) + return hr; + + IMFTopologyNode_SetObject(copier_node, (IUnknown *)copier); + IMFTopology_AddNode(context->output_topology, copier_node); + IMFTopologyNode_ConnectOutput(upstream_node, upstream_output, copier_node, 0); + IMFTopologyNode_ConnectOutput(copier_node, 0, downstream_node, downstream_input); + + IMFTopologyNode_Release(copier_node); + + return S_OK; +} + +/* Right now this should be used for output nodes only. */ +static HRESULT topology_loader_connect_d3d_aware_input(struct topoloader_context *context, + IMFTopologyNode *node) +{ + IMFTopologyNode *upstream_node; + IMFTransform *copier = NULL; + IMFStreamSink *stream_sink; + DWORD upstream_output; + HRESULT hr; + + if (FAILED(hr = topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink))) + return hr; + + if (topology_loader_is_node_d3d_aware(node)) + { + if (SUCCEEDED(IMFTopologyNode_GetInput(node, 0, &upstream_node, &upstream_output))) + { + if (!topology_loader_is_node_d3d_aware(upstream_node)) + { + if (SUCCEEDED(hr = topology_loader_create_copier(upstream_node, upstream_output, node, 0, &copier))) + { + hr = topology_loader_connect_copier(context, upstream_node, upstream_output, node, 0, copier); + IMFTransform_Release(copier); + } + } + IMFTopologyNode_Release(upstream_node); + } + } + + IMFStreamSink_Release(stream_sink); + + return hr; +} + +static void topology_loader_resolve_complete(struct topoloader_context *context) +{ + MF_TOPOLOGY_TYPE node_type; + IMFTopologyNode *node; + WORD i, node_count; + HRESULT hr; + + IMFTopology_GetNodeCount(context->output_topology, &node_count); + + for (i = 0; i < node_count; ++i) + { + if (SUCCEEDED(IMFTopology_GetNode(context->output_topology, i, &node))) + { + IMFTopologyNode_GetNodeType(node, &node_type); + + if (node_type == MF_TOPOLOGY_OUTPUT_NODE) + { + /* Set MF_TOPONODE_STREAMID for all outputs. */ + if (FAILED(IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAMID, NULL))) + IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_STREAMID, 0); + + if (FAILED(hr = topology_loader_connect_d3d_aware_input(context, node))) + WARN("Failed to connect D3D-aware input, hr %#lx.\n", hr); + } + else if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) + { + /* Set MF_TOPONODE_MEDIASTART for all sources. */ + if (FAILED(IMFTopologyNode_GetItem(node, &MF_TOPONODE_MEDIASTART, NULL))) + IMFTopologyNode_SetUINT64(node, &MF_TOPONODE_MEDIASTART, 0); + } + + IMFTopologyNode_Release(node); + } + } +} + +static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, + IMFTopology **ret_topology, IMFTopology *current_topology) +{ + struct topoloader_context context = { 0 }; + IMFTopology *output_topology; + MF_TOPOLOGY_TYPE node_type; + unsigned int layer_size; + IMFTopologyNode *node; + unsigned short i = 0; + IMFStreamSink *sink; + IUnknown *object; + HRESULT hr = E_FAIL; + + FIXME("iface %p, input_topology %p, ret_topology %p, current_topology %p stub!\n", + iface, input_topology, ret_topology, current_topology); + + if (current_topology) + FIXME("Current topology instance is ignored.\n"); + + /* Basic sanity checks for input topology: + + - source nodes must have stream descriptor set; + - sink nodes must be resolved to stream sink objects; + */ + while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node))) + { + IMFTopologyNode_GetNodeType(node, &node_type); + + switch (node_type) + { + case MF_TOPOLOGY_OUTPUT_NODE: + if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object))) + { + /* Sinks must be bound beforehand. */ + if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&sink))) + hr = MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; + else if (sink) + IMFStreamSink_Release(sink); + IUnknown_Release(object); + } + break; + case MF_TOPOLOGY_SOURCESTREAM_NODE: + hr = IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL); + break; + default: + ; + } + + IMFTopologyNode_Release(node); + if (FAILED(hr)) + return hr; + } + + if (FAILED(hr = MFCreateTopology(&output_topology))) + return hr; + + IMFTopology_CopyAllItems(input_topology, (IMFAttributes *)output_topology); + + context.input_topology = input_topology; + context.output_topology = output_topology; + memset(&context.key, 0xff, sizeof(context.key)); + + /* Clone source nodes, use initial marker value. */ + i = 0; + while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node))) + { + IMFTopologyNode_GetNodeType(node, &node_type); + + if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) + { + if (FAILED(hr = topology_loader_clone_node(&context, node, NULL, 0))) + WARN("Failed to clone source node, hr %#lx.\n", hr); + } + + IMFTopologyNode_Release(node); + } + + for (context.marker = 0;; ++context.marker) + { + if (FAILED(hr = topology_loader_resolve_nodes(&context, &layer_size))) + { + WARN("Failed to resolve for marker %u, hr %#lx.\n", context.marker, hr); + break; + } + + /* Reached last marker value. */ + if (!layer_size) + break; + } + + if (FAILED(hr)) + IMFTopology_Release(output_topology); + else + { + topology_loader_resolve_complete(&context); + *ret_topology = output_topology; + } + + return hr; +} + +static const IMFTopoLoaderVtbl topology_loader_vtbl = +{ + topology_loader_QueryInterface, + topology_loader_AddRef, + topology_loader_Release, + topology_loader_Load, +}; + +/*********************************************************************** + * MFCreateTopoLoader (mf.@) + */ +HRESULT WINAPI MFCreateTopoLoader(IMFTopoLoader **loader) +{ + struct topology_loader *object; + + TRACE("loader %p.\n", loader); + + if (!loader) + return E_POINTER; + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + object->IMFTopoLoader_iface.lpVtbl = &topology_loader_vtbl; + object->refcount = 1; + + *loader = &object->IMFTopoLoader_iface; + + return S_OK; +}
From: R��mi Bernon rbernon@codeweavers.com
--- dlls/mf/topology_loader.c | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 2ab92393c3e..997afd5ae0a 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -109,33 +109,32 @@ static IMFTopologyNode *topology_loader_get_node_for_marker(struct topoloader_co }
static HRESULT topology_loader_clone_node(struct topoloader_context *context, IMFTopologyNode *node, - IMFTopologyNode **ret, unsigned int marker) + IMFTopologyNode **clone, unsigned int marker) { - IMFTopologyNode *cloned_node; MF_TOPOLOGY_TYPE node_type; HRESULT hr; + TOPOID id;
- if (ret) *ret = NULL; + if (FAILED(hr = IMFTopologyNode_GetTopoNodeID(node, &id))) + return hr; + if (SUCCEEDED(hr = IMFTopology_GetNodeByID(context->output_topology, id, clone))) + return hr;
IMFTopologyNode_GetNodeType(node, &node_type); - - if (FAILED(hr = MFCreateTopologyNode(node_type, &cloned_node))) + if (FAILED(hr = MFCreateTopologyNode(node_type, clone))) return hr;
- if (SUCCEEDED(hr = IMFTopologyNode_CloneFrom(cloned_node, node))) - hr = IMFTopologyNode_SetUINT32(cloned_node, &context->key, marker); + if (SUCCEEDED(hr = IMFTopologyNode_CloneFrom(*clone, node))) + hr = IMFTopologyNode_SetUINT32(*clone, &context->key, marker);
if (SUCCEEDED(hr)) - hr = IMFTopology_AddNode(context->output_topology, cloned_node); + hr = IMFTopology_AddNode(context->output_topology, *clone);
- if (SUCCEEDED(hr) && ret) + if (FAILED(hr)) { - *ret = cloned_node; - IMFTopologyNode_AddRef(*ret); + IMFTopologyNode_Release(*clone); + *clone = NULL; } - - IMFTopologyNode_Release(cloned_node); - return hr; }
@@ -470,12 +469,9 @@ static HRESULT topology_loader_resolve_branch(struct topoloader_context *context MF_TOPOLOGY_TYPE u_type, d_type; IMFTopologyNode *node; HRESULT hr; - TOPOID id;
- /* Downstream node might have already been cloned. */ - IMFTopologyNode_GetTopoNodeID(downstream_node, &id); - if (FAILED(IMFTopology_GetNodeByID(context->output_topology, id, &node))) - topology_loader_clone_node(context, downstream_node, &node, context->marker + 1); + if (FAILED(hr = topology_loader_clone_node(context, downstream_node, &node, context->marker + 1))) + return hr;
IMFTopologyNode_GetNodeType(upstream_node, &u_type); IMFTopologyNode_GetNodeType(downstream_node, &d_type); @@ -763,8 +759,12 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in
if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) { - if (FAILED(hr = topology_loader_clone_node(&context, node, NULL, 0))) + IMFTopologyNode *clone; + + if (FAILED(hr = topology_loader_clone_node(&context, node, &clone, 0))) WARN("Failed to clone source node, hr %#lx.\n", hr); + else + IMFTopologyNode_Release(clone); }
IMFTopologyNode_Release(node);
From: R��mi Bernon rbernon@codeweavers.com
--- dlls/mf/tests/mf.c | 1 - dlls/mf/topology_loader.c | 236 +++++++++++++++++++++----------------- 2 files changed, 131 insertions(+), 106 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 33f7c119386..90007bf2fb1 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -2324,7 +2324,6 @@ static void test_topology_loader(void)
/* Source node only. */ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); - todo_wine_if(hr == E_INVALIDARG) ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#lx.\n", hr);
hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &sink_node); diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 997afd5ae0a..6d5a99b547b 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -26,6 +26,7 @@ #include "mfidl.h"
#include "wine/debug.h" +#include "wine/list.h"
#include "mf_private.h"
@@ -84,32 +85,9 @@ struct topoloader_context { IMFTopology *input_topology; IMFTopology *output_topology; - unsigned int marker; - GUID key; };
-static IMFTopologyNode *topology_loader_get_node_for_marker(struct topoloader_context *context, TOPOID *id) -{ - IMFTopologyNode *node; - unsigned short i = 0; - unsigned int value; - - while (SUCCEEDED(IMFTopology_GetNode(context->output_topology, i++, &node))) - { - if (SUCCEEDED(IMFTopologyNode_GetUINT32(node, &context->key, &value)) && value == context->marker) - { - IMFTopologyNode_GetTopoNodeID(node, id); - return node; - } - IMFTopologyNode_Release(node); - } - - *id = 0; - return NULL; -} - -static HRESULT topology_loader_clone_node(struct topoloader_context *context, IMFTopologyNode *node, - IMFTopologyNode **clone, unsigned int marker) +static HRESULT topology_loader_clone_node(struct topoloader_context *context, IMFTopologyNode *node, IMFTopologyNode **clone) { MF_TOPOLOGY_TYPE node_type; HRESULT hr; @@ -124,9 +102,7 @@ static HRESULT topology_loader_clone_node(struct topoloader_context *context, IM if (FAILED(hr = MFCreateTopologyNode(node_type, clone))) return hr;
- if (SUCCEEDED(hr = IMFTopologyNode_CloneFrom(*clone, node))) - hr = IMFTopologyNode_SetUINT32(*clone, &context->key, marker); - + hr = IMFTopologyNode_CloneFrom(*clone, node); if (SUCCEEDED(hr)) hr = IMFTopology_AddNode(context->output_topology, *clone);
@@ -157,6 +133,88 @@ struct connect_context GUID decoder_category; };
+struct topology_branch +{ + struct + { + IMFTopologyNode *node; + DWORD stream; + } up, down; + + struct list entry; +}; + +static const char *debugstr_topology_branch(struct topology_branch *branch) +{ + return wine_dbg_sprintf("%p:%lu to %p:%lu", branch->up.node, branch->up.stream, branch->down.node, branch->down.stream); +} + +static HRESULT topology_branch_create(IMFTopologyNode *source, DWORD source_stream, + IMFTopologyNode *sink, DWORD sink_stream, struct topology_branch **out) +{ + struct topology_branch *branch; + + if (!(branch = calloc(1, sizeof(*branch)))) + return E_OUTOFMEMORY; + + IMFTopologyNode_AddRef((branch->up.node = source)); + branch->up.stream = source_stream; + IMFTopologyNode_AddRef((branch->down.node = sink)); + branch->down.stream = sink_stream; + + *out = branch; + return S_OK; +} + +static void topology_branch_destroy(struct topology_branch *branch) +{ + IMFTopologyNode_Release(branch->up.node); + IMFTopologyNode_Release(branch->down.node); + free(branch); +} + +static HRESULT topology_branch_clone_nodes(struct topoloader_context *context, struct topology_branch *branch) +{ + IMFTopologyNode *up, *down; + HRESULT hr; + + if (FAILED(hr = topology_loader_clone_node(context, branch->up.node, &up))) + return hr; + if (FAILED(hr = topology_loader_clone_node(context, branch->down.node, &down))) + { + IMFTopologyNode_Release(up); + return hr; + } + + IMFTopologyNode_Release(branch->up.node); + IMFTopologyNode_Release(branch->down.node); + branch->up.node = up; + branch->down.node = down; + return hr; +} + +static HRESULT topology_node_list_branches(IMFTopologyNode *node, struct list *branches) +{ + struct topology_branch *branch; + DWORD i, count, down_stream; + IMFTopologyNode *down_node; + HRESULT hr; + + hr = IMFTopologyNode_GetOutputCount(node, &count); + for (i = 0; SUCCEEDED(hr) && i < count; ++i) + { + if (FAILED(IMFTopologyNode_GetOutput(node, i, &down_node, &down_stream))) + continue; + + if (SUCCEEDED(hr = topology_branch_create(node, i, down_node, down_stream, &branch))) + list_add_tail(branches, &branch->entry); + + IMFTopologyNode_Release(down_node); + } + + return hr; +} + 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) @@ -456,8 +514,7 @@ done: return hr; }
-static HRESULT topology_loader_resolve_branch(struct topoloader_context *context, IMFTopologyNode *upstream_node, - unsigned int output_index, IMFTopologyNode *downstream_node, unsigned input_index) +static HRESULT topology_loader_resolve_branch(struct topoloader_context *context, struct topology_branch *branch) { static const p_topology_loader_connect_func connectors[MF_TOPOLOGY_TEE_NODE+1][MF_TOPOLOGY_TEE_NODE+1] = { @@ -467,77 +524,58 @@ static HRESULT topology_loader_resolve_branch(struct topoloader_context *context /* TEE */ { NULL }, }; MF_TOPOLOGY_TYPE u_type, d_type; - IMFTopologyNode *node; - HRESULT hr; - - if (FAILED(hr = topology_loader_clone_node(context, downstream_node, &node, context->marker + 1))) - return hr;
- IMFTopologyNode_GetNodeType(upstream_node, &u_type); - IMFTopologyNode_GetNodeType(downstream_node, &d_type); + IMFTopologyNode_GetNodeType(branch->up.node, &u_type); + IMFTopologyNode_GetNodeType(branch->down.node, &d_type);
if (!connectors[u_type][d_type]) { WARN("Unsupported branch kind %d -> %d.\n", u_type, d_type); - IMFTopologyNode_Release(node); return E_FAIL; }
- hr = connectors[u_type][d_type](context, upstream_node, output_index, node, input_index); - IMFTopologyNode_Release(node); - return hr; + return connectors[u_type][d_type](context, branch->up.node, branch->up.stream, branch->down.node, branch->down.stream); }
-static HRESULT topology_loader_resolve_nodes(struct topoloader_context *context, unsigned int *layer_size) +static HRESULT topology_loader_resolve_branches(struct topoloader_context *context, struct list *branches) { - IMFTopologyNode *downstream_node, *node, *orig_node; + struct list new_branches = LIST_INIT(new_branches); + struct topology_branch *branch, *next; MF_TOPOLOGY_TYPE node_type; - unsigned int size = 0; - DWORD input_index; HRESULT hr = S_OK; - TOPOID id;
- while ((node = topology_loader_get_node_for_marker(context, &id))) + LIST_FOR_EACH_ENTRY_SAFE(branch, next, branches, struct topology_branch, entry) { - ++size; - - IMFTopologyNode_GetNodeType(node, &node_type); - switch (node_type) + list_remove(&branch->entry); + + if (FAILED(hr = topology_node_list_branches(branch->down.node, &new_branches))) + WARN("Failed to list branches from branch %s\n", debugstr_topology_branch(branch)); + else if (FAILED(hr = IMFTopologyNode_GetNodeType(branch->up.node, &node_type))) + WARN("Failed to get source node type for branch %s\n", debugstr_topology_branch(branch)); + else if (FAILED(hr = topology_branch_clone_nodes(context, branch))) + WARN("Failed to clone nodes for branch %s\n", debugstr_topology_branch(branch)); + else { - case MF_TOPOLOGY_SOURCESTREAM_NODE: - if (SUCCEEDED(hr = IMFTopology_GetNodeByID(context->input_topology, id, &orig_node))) - { - hr = IMFTopologyNode_GetOutput(orig_node, 0, &downstream_node, &input_index); - IMFTopologyNode_Release(orig_node); - } - - if (FAILED(hr)) - { - IMFTopology_RemoveNode(context->output_topology, node); - IMFTopologyNode_Release(node); - continue; - } - - hr = topology_loader_resolve_branch(context, node, 0, downstream_node, input_index); - IMFTopologyNode_Release(downstream_node); - break; - case MF_TOPOLOGY_TRANSFORM_NODE: - case MF_TOPOLOGY_TEE_NODE: - FIXME("Unsupported node type %d.\n", node_type); - break; - default: - WARN("Unexpected node type %d.\n", node_type); + switch (node_type) + { + case MF_TOPOLOGY_SOURCESTREAM_NODE: + hr = topology_loader_resolve_branch(context, branch); + break; + case MF_TOPOLOGY_TRANSFORM_NODE: + case MF_TOPOLOGY_TEE_NODE: + FIXME("Unsupported node type %d.\n", node_type); + break; + default: + WARN("Unexpected node type %d.\n", node_type); + } }
- IMFTopologyNode_DeleteItem(node, &context->key); - IMFTopologyNode_Release(node); - + topology_branch_destroy(branch); if (FAILED(hr)) break; }
- *layer_size = size; - + list_move_tail(branches, &new_branches); return hr; }
@@ -692,10 +730,11 @@ static void topology_loader_resolve_complete(struct topoloader_context *context) static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, IMFTopology **ret_topology, IMFTopology *current_topology) { + struct list branches = LIST_INIT(branches); struct topoloader_context context = { 0 }; + struct topology_branch *branch, *next; IMFTopology *output_topology; MF_TOPOLOGY_TYPE node_type; - unsigned int layer_size; IMFTopologyNode *node; unsigned short i = 0; IMFStreamSink *sink; @@ -749,38 +788,25 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in
context.input_topology = input_topology; context.output_topology = output_topology; - memset(&context.key, 0xff, sizeof(context.key));
- /* Clone source nodes, use initial marker value. */ - i = 0; - while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node))) + for (i = 0; SUCCEEDED(IMFTopology_GetNode(input_topology, i, &node)); i++) { - IMFTopologyNode_GetNodeType(node, &node_type); - - if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE) - { - IMFTopologyNode *clone; - - if (FAILED(hr = topology_loader_clone_node(&context, node, &clone, 0))) - WARN("Failed to clone source node, hr %#lx.\n", hr); - else - IMFTopologyNode_Release(clone); - } - + hr = topology_node_list_branches(node, &branches); IMFTopologyNode_Release(node); + if (FAILED(hr)) + break; } + if (SUCCEEDED(hr) && list_empty(&branches)) + hr = MF_E_TOPO_UNSUPPORTED;
- for (context.marker = 0;; ++context.marker) - { - if (FAILED(hr = topology_loader_resolve_nodes(&context, &layer_size))) - { - WARN("Failed to resolve for marker %u, hr %#lx.\n", context.marker, hr); - break; - } + while (SUCCEEDED(hr) && !list_empty(&branches)) + hr = topology_loader_resolve_branches(&context, &branches);
- /* Reached last marker value. */ - if (!layer_size) - break; + LIST_FOR_EACH_ENTRY_SAFE(branch, next, &branches, struct topology_branch, entry) + { + WARN("Failed to resolve branch %s\n", debugstr_topology_branch(branch)); + list_remove(&branch->entry); + topology_branch_destroy(branch); }
if (FAILED(hr))
From: R��mi Bernon rbernon@codeweavers.com
Supporting more branch node types and fixing the decoder and converter resolution. --- dlls/mf/tests/mf.c | 9 +- dlls/mf/topology_loader.c | 392 +++++++++++++------------------------- 2 files changed, 135 insertions(+), 266 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 90007bf2fb1..db062c3c3e0 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -2139,7 +2139,6 @@ static void test_topology_loader(void) /* PCM -> PCM, same enumerated type, no current type */ .input_type = &audio_pcm_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .expected_result = S_OK, - .flags = LOADER_TODO, }, { /* PCM -> PCM, same enumerated type, incomplete current type */ @@ -2180,7 +2179,6 @@ static void test_topology_loader(void) /* PCM -> PCM, different enumerated bps, no current type */ .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .expected_result = MF_E_INVALIDMEDIATYPE, - .flags = LOADER_TODO, }, { /* PCM -> PCM, different enumerated bps, same current bps */ @@ -2217,7 +2215,6 @@ static void test_topology_loader(void) /* PCM -> PCM, different enumerated bps, no current type, source allow converter */ .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = MF_CONNECT_ALLOW_CONVERTER, .expected_result = MF_E_INVALIDMEDIATYPE, - .flags = LOADER_TODO, },
{ @@ -2238,7 +2235,7 @@ static void test_topology_loader(void) .input_type = &audio_mp3_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = -1, .current_input = &audio_mp3_44100, .expected_result = MF_E_TRANSFORM_NOT_POSSIBLE_FOR_CURRENT_MEDIATYPE_COMBINATION, - .flags = LOADER_NEEDS_VIDEO_PROCESSOR | LOADER_TODO, + .flags = LOADER_NEEDS_VIDEO_PROCESSOR, }, { /* MP3 -> PCM */ @@ -2427,7 +2424,7 @@ todo_wine {
hr = IMFTopology_GetNodeCount(full_topology, &node_count); ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - todo_wine_if(test->flags & (LOADER_EXPECTED_CONVERTER | LOADER_EXPECTED_DECODER)) + todo_wine_if(test->flags & LOADER_EXPECTED_DECODER) ok(node_count == count, "Unexpected node count %u.\n", node_count);
hr = IMFTopologyNode_GetTopoNodeID(src_node, &node_id); @@ -2442,7 +2439,7 @@ todo_wine { hr = IMFTopology_GetNodeByID(full_topology, node_id, &sink_node2); ok(hr == S_OK, "Failed to get sink in resolved topology, hr %#lx.\n", hr);
- if (test->flags & (LOADER_EXPECTED_DECODER | LOADER_EXPECTED_CONVERTER) && strcmp(winetest_platform, "wine")) + if (test->flags & (LOADER_EXPECTED_DECODER | LOADER_EXPECTED_CONVERTER)) { hr = IMFTopologyNode_GetOutput(src_node2, 0, &mft_node, &index); ok(hr == S_OK, "Failed to get transform node in resolved topology, hr %#lx.\n", hr); diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 6d5a99b547b..68ac7121a97 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -215,328 +215,213 @@ static HRESULT topology_node_list_branches(IMFTopologyNode *node, struct list *b return hr; }
-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; +static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD method_mask, + struct topology_branch *branch); +static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method_mask, + struct topology_branch *branch, IMFMediaType *up_type); +static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNECT_METHOD method_mask, + struct topology_branch *branch, IMFMediaType *up_type, IMFMediaType *down_type) +{ + BOOL decoder = (method_mask & MF_CONNECT_ALLOW_DECODER) == MF_CONNECT_ALLOW_DECODER; + MFT_REGISTER_TYPE_INFO input_info, output_info; + IMFTransform *transform; IMFActivate **activates; + IMFTopologyNode *node; unsigned int i, count; + GUID category, guid; + DWORD flags; HRESULT hr;
- if (FAILED(hr = IMFMediaType_GetMajorType(input_type, &mft_typeinfo.guidMajorType))) - return hr; + TRACE("topology %p, method_mask %#x, branch %s, up_type %p, down_type %p.\n", + topology, method_mask, debugstr_topology_branch(branch), up_type, down_type);
- if (FAILED(hr = IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &mft_typeinfo.guidSubtype))) + if (FAILED(hr = IMFMediaType_GetMajorType(up_type, &input_info.guidMajorType))) + return hr; + if (FAILED(hr = IMFMediaType_GetGUID(up_type, &MF_MT_SUBTYPE, &input_info.guidSubtype))) + return hr; + if (FAILED(hr = IMFMediaType_GetMajorType(down_type, &output_info.guidMajorType))) + return hr; + if (FAILED(hr = IMFMediaType_GetGUID(down_type, &MF_MT_SUBTYPE, &output_info.guidSubtype))) return hr; + if (FAILED(hr = IMFMediaType_IsEqual(up_type, down_type, &flags)) + || !(flags & MF_MEDIATYPE_EQUAL_MAJOR_TYPES)) + return MF_E_INVALIDMEDIATYPE; + + if (IsEqualGUID(&input_info.guidMajorType, &MFMediaType_Audio)) + category = decoder ? MFT_CATEGORY_AUDIO_DECODER : MFT_CATEGORY_AUDIO_EFFECT; + else if (IsEqualGUID(&input_info.guidMajorType, &MFMediaType_Video)) + category = decoder ? MFT_CATEGORY_VIDEO_DECODER : MFT_CATEGORY_VIDEO_EFFECT; + else + return MF_E_INVALIDMEDIATYPE;
- if (FAILED(hr = MFTEnumEx(*category, MFT_ENUM_FLAG_ALL, &mft_typeinfo, NULL, &activates, &count))) + if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node))) return hr; + if (decoder) + IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_DECODER, 1);
- hr = E_FAIL; + if (FAILED(hr = MFTEnumEx(category, MFT_ENUM_FLAG_ALL, &input_info, decoder ? NULL : &output_info, &activates, &count))) + return hr;
- for (i = 0; i < count; ++i) + for (i = 0, hr = MF_E_TRANSFORM_NOT_POSSIBLE_FOR_CURRENT_MEDIATYPE_COMBINATION; i < count; ++i) { - IMFTransform *transform; + struct topology_branch down_branch = {.up.node = node, .down = branch->down}; + struct topology_branch up_branch = {.up = branch->up, .down.node = node};
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; + IMFTopologyNode_SetObject(node, (IUnknown *)transform); + IMFTopologyNode_DeleteItem(node, &MF_TOPONODE_TRANSFORM_OBJECTID); + if (SUCCEEDED(IMFActivate_GetGUID(activates[i], &MFT_TRANSFORM_CLSID_Attribute, &guid))) + IMFTopologyNode_SetGUID(node, &MF_TOPONODE_TRANSFORM_OBJECTID, &guid);
- output_type.transform = transform; - output_type.activate = activates[i]; - 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; - } - } - } + hr = topology_branch_connect_down(topology, MF_CONNECT_DIRECT, &up_branch, up_type); + if (SUCCEEDED(hr)) + hr = IMFTransform_SetOutputType(transform, 0, down_type, 0); + IMFTransform_Release(transform);
- IMFActivate_ShutdownObject(activates[i]); + if (SUCCEEDED(hr)) + hr = topology_branch_connect(topology, decoder ? MF_CONNECT_ALLOW_CONVERTER : MF_CONNECT_DIRECT, &down_branch); + if (SUCCEEDED(hr)) + hr = IMFTopology_AddNode(topology, node); + if (SUCCEEDED(hr)) + break; }
- topology_loader_release_transforms(activates, count); + IMFTopologyNode_Release(node); + for (i = 0; i < count; ++i) + IMFActivate_Release(activates[i]); + CoTaskMemFree(activates);
return hr; }
-static HRESULT topology_loader_create_transform(const struct transform_output_type *output_type, - IMFTopologyNode **node) +static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method_mask, + struct topology_branch *branch, IMFMediaType *up_type) { + IMFMediaTypeHandler *down_handler; + MF_CONNECT_METHOD method; + IMFMediaType *down_type; + DWORD flags; HRESULT hr; - GUID guid; - - if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, node))) - return hr; - - IMFTopologyNode_SetObject(*node, (IUnknown *)output_type->transform); - - if (SUCCEEDED(IMFActivate_GetGUID(output_type->activate, &MF_TRANSFORM_CATEGORY_Attribute, &guid)) && - (IsEqualGUID(&guid, &MFT_CATEGORY_AUDIO_DECODER) || IsEqualGUID(&guid, &MFT_CATEGORY_VIDEO_DECODER))) - { - IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_DECODER, 1); - }
- if (SUCCEEDED(IMFActivate_GetGUID(output_type->activate, &MFT_TRANSFORM_CLSID_Attribute, &guid))) - IMFTopologyNode_SetGUID(*node, &MF_TOPONODE_TRANSFORM_OBJECTID, &guid); - - return hr; -} - -static HRESULT connect_to_sink(struct transform_output_type *output_type, struct connect_context *context) -{ - IMFTopologyNode *node; - HRESULT hr; + TRACE("topology %p, method_mask %#x, branch %s, up_type %p.\n", + topology, method_mask, debugstr_topology_branch(branch), up_type);
- if (FAILED(IMFMediaTypeHandler_IsMediaTypeSupported(context->sink_handler, output_type->type, NULL))) - return MF_E_TRANSFORM_NOT_POSSIBLE_FOR_CURRENT_MEDIATYPE_COMBINATION; + if (FAILED(IMFTopologyNode_GetUINT32(branch->down.node, &MF_TOPONODE_CONNECT_METHOD, &method))) + method = MF_CONNECT_ALLOW_DECODER;
- if (FAILED(hr = topology_loader_create_transform(output_type, &node))) + if (FAILED(hr = topology_node_get_type_handler(branch->down.node, branch->down.stream, FALSE, &down_handler))) return hr;
- 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 = topology_loader_create_transform(output_type, &node))) - return hr; - - 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)) + if (SUCCEEDED(hr = IMFMediaTypeHandler_GetCurrentMediaType(down_handler, &down_type)) + && IMFMediaType_IsEqual(up_type, down_type, &flags) == S_OK) { - IMFTopology_AddNode(context->context->output_topology, node); - IMFTopologyNode_ConnectOutput(context->upstream_node, 0, node, 0); + TRACE("Connecting branch %s with current type %p.\n", debugstr_topology_branch(branch), up_type); + IMFMediaTypeHandler_Release(down_handler); + IMFMediaType_Release(down_type);
- hr = IMFTransform_SetOutputType(output_type->transform, 0, output_type->type, 0); + return IMFTopologyNode_ConnectOutput(branch->up.node, branch->up.stream, branch->down.node, branch->down.stream); }
- 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_get_mft_categories(IMFMediaTypeHandler *handler, GUID *decode_cat, GUID *convert_cat) -{ - GUID major; - HRESULT hr; - - if (FAILED(hr = IMFMediaTypeHandler_GetMajorType(handler, &major))) + if (FAILED(hr) && FAILED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(down_handler, 0, &down_type))) 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 + if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(down_handler, up_type, NULL)) + && SUCCEEDED(hr = IMFMediaTypeHandler_SetCurrentMediaType(down_handler, up_type))) { - WARN("Unexpected major type %s.\n", debugstr_guid(&major)); - return MF_E_INVALIDTYPE; - } - - return S_OK; -} + TRACE("Connected branch %s with upstream type %p.\n", debugstr_topology_branch(branch), up_type); + IMFMediaTypeHandler_Release(down_handler); + IMFMediaType_Release(down_type);
-static HRESULT topology_loader_connect(IMFMediaTypeHandler *sink_handler, unsigned int sink_method, - struct connect_context *sink_ctx, struct connect_context *convert_ctx, IMFMediaType *media_type) -{ - HRESULT hr; - - if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(sink_handler, media_type, NULL)) - && SUCCEEDED(hr = IMFMediaTypeHandler_SetCurrentMediaType(sink_handler, media_type))) - { - hr = IMFTopologyNode_ConnectOutput(sink_ctx->upstream_node, sink_ctx->output_index, sink_ctx->sink, sink_ctx->input_index); + return IMFTopologyNode_ConnectOutput(branch->up.node, branch->up.stream, branch->down.node, branch->down.stream); }
- if (FAILED(hr) && sink_method & MF_CONNECT_ALLOW_CONVERTER) - { - hr = topology_loader_enumerate_output_types(&convert_ctx->converter_category, media_type, connect_to_sink, sink_ctx); - } + IMFMediaTypeHandler_Release(down_handler);
- if (FAILED(hr) && sink_method & MF_CONNECT_ALLOW_DECODER) - { - hr = topology_loader_enumerate_output_types(&convert_ctx->decoder_category, media_type, - connect_to_converter, convert_ctx); - } + if (FAILED(hr) && (method & method_mask & MF_CONNECT_ALLOW_CONVERTER) == MF_CONNECT_ALLOW_CONVERTER) + hr = topology_branch_connect_indirect(topology, MF_CONNECT_ALLOW_CONVERTER, + branch, up_type, down_type); + + if (FAILED(hr) && (method & method_mask & MF_CONNECT_ALLOW_DECODER) == MF_CONNECT_ALLOW_DECODER) + hr = topology_branch_connect_indirect(topology, MF_CONNECT_ALLOW_DECODER, + branch, up_type, down_type);
+ IMFMediaType_Release(down_type); return hr; }
-static HRESULT topology_loader_foreach_source_type(IMFMediaTypeHandler *sink_handler, IMFMediaTypeHandler *source_handler, - unsigned int sink_method, struct connect_context *sink_ctx, struct connect_context *convert_ctx) +static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, MF_CONNECT_METHOD method_mask, + struct topology_branch *branch) { - unsigned int index = 0; - IMFMediaType *media_type; + IMFMediaTypeHandler *handler; + IMFMediaType *type; + DWORD index = 0; HRESULT hr;
- while (SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(source_handler, index++, &media_type))) - { - hr = topology_loader_connect(sink_handler, sink_method, sink_ctx, convert_ctx, media_type); - if (SUCCEEDED(hr)) break; - IMFMediaType_Release(media_type); - media_type = NULL; - } + if (FAILED(hr = topology_node_get_type_handler(branch->up.node, branch->up.stream, TRUE, &handler))) + return hr;
- if (media_type) + while (SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, index++, &type))) { - hr = IMFMediaTypeHandler_SetCurrentMediaType(source_handler, media_type); - IMFMediaType_Release(media_type); + hr = topology_branch_connect_down(topology, method_mask, branch, type); + if (SUCCEEDED(hr)) + hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, type); + IMFMediaType_Release(type); + if (SUCCEEDED(hr)) + break; }
+ IMFMediaTypeHandler_Release(handler); return hr; }
-static HRESULT topology_loader_connect_source_to_sink(struct topoloader_context *context, IMFTopologyNode *source, - unsigned int output_index, IMFTopologyNode *sink, unsigned int input_index) +static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD method_mask, + struct topology_branch *branch) { - IMFMediaTypeHandler *source_handler = NULL, *sink_handler = NULL; - struct connect_context convert_ctx, sink_ctx; - MF_CONNECT_METHOD source_method, sink_method; - unsigned int enumerate_source_types = 0; - IMFMediaType *media_type; + UINT32 enumerate_source_types; + MF_CONNECT_METHOD method; HRESULT hr;
- TRACE("attempting to connect %p:%u to %p:%u\n", source, output_index, sink, input_index); - - if (FAILED(hr = topology_node_get_type_handler(source, output_index, TRUE, &source_handler))) - goto done; - if (FAILED(hr = topology_node_get_type_handler(sink, input_index, FALSE, &sink_handler))) - goto done; + TRACE("topology %p, method_mask %#x, branch %s.\n", topology, method_mask, debugstr_topology_branch(branch));
- 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(IMFTopologyNode_GetUINT32(branch->up.node, &MF_TOPONODE_CONNECT_METHOD, &method))) + method = MF_CONNECT_DIRECT;
- sink_ctx.context = context; - sink_ctx.upstream_node = source; - sink_ctx.sink = sink; - sink_ctx.sink_handler = sink_handler; - sink_ctx.output_index = output_index; - sink_ctx.input_index = input_index; - - convert_ctx = sink_ctx; - if (FAILED(hr = topology_loader_get_mft_categories(source_handler, &convert_ctx.decoder_category, - &convert_ctx.converter_category))) - goto done; - - IMFTopology_GetUINT32(context->output_topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enumerate_source_types); - - if (enumerate_source_types) + if (SUCCEEDED(IMFTopology_GetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enumerate_source_types)) + && enumerate_source_types) { - if (source_method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES) - { - hr = topology_loader_foreach_source_type(sink_handler, source_handler, MF_CONNECT_ALLOW_DECODER, - &sink_ctx, &convert_ctx); - } + if (method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES) + hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_DECODER, branch); else { - hr = topology_loader_foreach_source_type(sink_handler, source_handler, MF_CONNECT_DIRECT, - &sink_ctx, &convert_ctx); + hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_DIRECT, branch); if (FAILED(hr)) - hr = topology_loader_foreach_source_type(sink_handler, source_handler, MF_CONNECT_ALLOW_CONVERTER, - &sink_ctx, &convert_ctx); + hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_CONVERTER, branch); if (FAILED(hr)) - hr = topology_loader_foreach_source_type(sink_handler, source_handler, MF_CONNECT_ALLOW_DECODER, - &sink_ctx, &convert_ctx); + hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_DECODER, branch); } } else { - if (SUCCEEDED(hr = IMFMediaTypeHandler_GetCurrentMediaType(source_handler, &media_type))) + IMFMediaTypeHandler *up_handler; + IMFMediaType *up_type; + + if (FAILED(hr = topology_node_get_type_handler(branch->up.node, branch->up.stream, TRUE, &up_handler))) + return hr; + if (SUCCEEDED(hr = IMFMediaTypeHandler_GetCurrentMediaType(up_handler, &up_type)) + || SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(up_handler, 0, &up_type))) { - hr = topology_loader_connect(sink_handler, sink_method, &sink_ctx, &convert_ctx, media_type); - IMFMediaType_Release(media_type); + hr = topology_branch_connect_down(topology, method_mask, branch, up_type); + IMFMediaType_Release(up_type); } + IMFMediaTypeHandler_Release(up_handler); }
-done: - if (source_handler) - IMFMediaTypeHandler_Release(source_handler); - if (sink_handler) - IMFMediaTypeHandler_Release(sink_handler); - + TRACE("returning %#lx\n", hr); return hr; }
-static HRESULT topology_loader_resolve_branch(struct topoloader_context *context, struct topology_branch *branch) -{ - 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_to_sink, NULL, NULL, NULL }, - /* TRANSFORM */ { NULL }, - /* TEE */ { NULL }, - }; - MF_TOPOLOGY_TYPE u_type, d_type; - - IMFTopologyNode_GetNodeType(branch->up.node, &u_type); - IMFTopologyNode_GetNodeType(branch->down.node, &d_type); - - if (!connectors[u_type][d_type]) - { - WARN("Unsupported branch kind %d -> %d.\n", u_type, d_type); - return E_FAIL; - } - - return connectors[u_type][d_type](context, branch->up.node, branch->up.stream, branch->down.node, branch->down.stream); -} - static HRESULT topology_loader_resolve_branches(struct topoloader_context *context, struct list *branches) { struct list new_branches = LIST_INIT(new_branches); @@ -555,20 +440,7 @@ static HRESULT topology_loader_resolve_branches(struct topoloader_context *conte else if (FAILED(hr = topology_branch_clone_nodes(context, branch))) WARN("Failed to clone nodes for branch %s\n", debugstr_topology_branch(branch)); else - { - switch (node_type) - { - case MF_TOPOLOGY_SOURCESTREAM_NODE: - hr = topology_loader_resolve_branch(context, branch); - break; - case MF_TOPOLOGY_TRANSFORM_NODE: - case MF_TOPOLOGY_TEE_NODE: - FIXME("Unsupported node type %d.\n", node_type); - break; - default: - WARN("Unexpected node type %d.\n", node_type); - } - } + hr = topology_branch_connect(context->output_topology, MF_CONNECT_ALLOW_DECODER, branch);
topology_branch_destroy(branch); if (FAILED(hr))
From: R��mi Bernon rbernon@codeweavers.com
With a helper type handler for transform and tee nodes. --- dlls/mf/tests/mf.c | 6 +- dlls/mf/topology.c | 235 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 202 insertions(+), 39 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index db062c3c3e0..996829c5e9a 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -2197,19 +2197,19 @@ static void test_topology_loader(void) /* PCM -> PCM, different enumerated bps, no current type, sink allow converter */ .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = MF_CONNECT_DIRECT, .expected_result = S_OK, - .flags = LOADER_NEEDS_VIDEO_PROCESSOR | LOADER_EXPECTED_CONVERTER | LOADER_TODO, + .flags = LOADER_NEEDS_VIDEO_PROCESSOR | LOADER_EXPECTED_CONVERTER, }, { /* PCM -> PCM, different enumerated bps, no current type, sink allow decoder */ .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = MF_CONNECT_DIRECT, .expected_result = S_OK, - .flags = LOADER_NEEDS_VIDEO_PROCESSOR | LOADER_EXPECTED_CONVERTER | LOADER_TODO, + .flags = LOADER_NEEDS_VIDEO_PROCESSOR | LOADER_EXPECTED_CONVERTER, }, { /* PCM -> PCM, different enumerated bps, no current type, default methods */ .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = -1, .source_method = -1, .expected_result = S_OK, - .flags = LOADER_NEEDS_VIDEO_PROCESSOR | LOADER_EXPECTED_CONVERTER | LOADER_TODO, + .flags = LOADER_NEEDS_VIDEO_PROCESSOR | LOADER_EXPECTED_CONVERTER, }, { /* PCM -> PCM, different enumerated bps, no current type, source allow converter */ diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index d9d1bc1c57e..25a00708100 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -1809,12 +1809,198 @@ HRESULT WINAPI MFCreateTopologyNode(MF_TOPOLOGY_TYPE node_type, IMFTopologyNode return hr; }
+/* private helper for node types without an actual IMFMediaTypeHandler */ +struct type_handler +{ + IMFMediaTypeHandler IMFMediaTypeHandler_iface; + LONG refcount; + + IMFTopologyNode *node; + DWORD stream; + BOOL output; + + IMFTransform *transform; +}; + +static struct type_handler *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler *iface) +{ + return CONTAINING_RECORD(iface, struct type_handler, IMFMediaTypeHandler_iface); +} + +static HRESULT WINAPI type_handler_QueryInterface(IMFMediaTypeHandler *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFMediaTypeHandler) + || IsEqualIID(riid, &IID_IUnknown)) + { + IMFMediaTypeHandler_AddRef((*obj = iface)); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI type_handler_AddRef(IMFMediaTypeHandler *iface) +{ + struct type_handler *handler = impl_from_IMFMediaTypeHandler(iface); + ULONG refcount = InterlockedIncrement(&handler->refcount); + return refcount; +} + +static ULONG WINAPI type_handler_Release(IMFMediaTypeHandler *iface) +{ + struct type_handler *handler = impl_from_IMFMediaTypeHandler(iface); + ULONG refcount = InterlockedDecrement(&handler->refcount); + + if (!refcount) + { + if (handler->transform) + IMFTransform_Release(handler->transform); + IMFTopologyNode_Release(handler->node); + free(handler); + } + + return refcount; +} + +static HRESULT WINAPI type_handler_IsMediaTypeSupported(IMFMediaTypeHandler *iface, IMFMediaType *in_type, + IMFMediaType **out_type) +{ + struct type_handler *handler = impl_from_IMFMediaTypeHandler(iface); + IMFMediaType *type; + DWORD flags; + HRESULT hr; + + if (out_type) + *out_type = NULL; + + if (handler->transform) + { + if (handler->output) + return IMFTransform_SetOutputType(handler->transform, handler->stream, in_type, MFT_SET_TYPE_TEST_ONLY); + else + return IMFTransform_SetInputType(handler->transform, handler->stream, in_type, MFT_SET_TYPE_TEST_ONLY); + } + + if (FAILED(hr = IMFMediaTypeHandler_GetCurrentMediaType(iface, &type))) + return hr; + + hr = IMFMediaType_IsEqual(type, in_type, &flags); + IMFMediaType_Release(type); + return hr; +} + +static HRESULT WINAPI type_handler_GetMediaTypeCount(IMFMediaTypeHandler *iface, DWORD *count) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *iface, DWORD index, + IMFMediaType **type) +{ + struct type_handler *handler = impl_from_IMFMediaTypeHandler(iface); + + if (handler->transform) + { + if (handler->output) + return IMFTransform_GetOutputAvailableType(handler->transform, handler->stream, index, type); + else + return IMFTransform_GetInputAvailableType(handler->transform, handler->stream, index, type); + } + + if (index) + return MF_E_NO_MORE_TYPES; + + return IMFMediaTypeHandler_GetCurrentMediaType(iface, type); +} + +static HRESULT WINAPI type_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface, IMFMediaType *type) +{ + struct type_handler *handler = impl_from_IMFMediaTypeHandler(iface); + + if (handler->transform) + { + if (handler->output) + return IMFTransform_SetOutputType(handler->transform, handler->stream, type, 0); + else + return IMFTransform_SetInputType(handler->transform, handler->stream, type, 0); + } + + return IMFTopologyNode_SetInputPrefType(handler->node, handler->stream, type); +} + +static HRESULT WINAPI type_handler_GetCurrentMediaType(IMFMediaTypeHandler *iface, IMFMediaType **type) +{ + struct type_handler *handler = impl_from_IMFMediaTypeHandler(iface); + UINT32 output; + + if (handler->transform) + { + if (handler->output) + return IMFTransform_GetOutputCurrentType(handler->transform, handler->stream, type); + else + return IMFTransform_GetInputCurrentType(handler->transform, handler->stream, type); + } + + if (SUCCEEDED(IMFTopologyNode_GetInputPrefType(handler->node, 0, type))) + return S_OK; + + if (FAILED(IMFTopologyNode_GetUINT32(handler->node, &MF_TOPONODE_PRIMARYOUTPUT, &output))) + output = 0; + + return IMFTopologyNode_GetOutputPrefType(handler->node, output, type); +} + +static HRESULT WINAPI type_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type) +{ + IMFMediaType *media_type; + HRESULT hr; + + if (FAILED(hr = IMFMediaTypeHandler_GetCurrentMediaType(iface, &media_type))) + return hr; + + hr = IMFMediaType_GetMajorType(media_type, type); + IMFMediaType_Release(media_type); + return hr; +} + +static const IMFMediaTypeHandlerVtbl type_handler_vtbl = +{ + type_handler_QueryInterface, + type_handler_AddRef, + type_handler_Release, + type_handler_IsMediaTypeSupported, + type_handler_GetMediaTypeCount, + type_handler_GetMediaTypeByIndex, + type_handler_SetCurrentMediaType, + type_handler_GetCurrentMediaType, + type_handler_GetMajorType, +}; + +static HRESULT type_handler_create(IMFTopologyNode *node, DWORD stream, BOOL output, IMFTransform *transform, IMFMediaTypeHandler **out) +{ + struct type_handler *handler; + + if (!(handler = calloc(1, sizeof(*handler)))) return E_OUTOFMEMORY; + handler->IMFMediaTypeHandler_iface.lpVtbl = &type_handler_vtbl; + handler->refcount = 1; + handler->stream = stream; + handler->output = output; + IMFTopologyNode_AddRef((handler->node = node)); + if (transform) + IMFTransform_AddRef((handler->transform = transform)); + + *out = &handler->IMFMediaTypeHandler_iface; + return S_OK; +} + HRESULT topology_node_get_type_handler(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaTypeHandler **handler) { MF_TOPOLOGY_TYPE node_type; IMFStreamSink *stream_sink; IMFStreamDescriptor *sd; + IMFTransform *transform; HRESULT hr;
if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type))) @@ -1843,6 +2029,16 @@ HRESULT topology_node_get_type_handler(IMFTopologyNode *node, DWORD stream, IMFStreamDescriptor_Release(sd); } break; + case MF_TOPOLOGY_TRANSFORM_NODE: + if (SUCCEEDED(hr = topology_node_get_object(node, &IID_IMFTransform, (void **)&transform))) + { + hr = type_handler_create(node, stream, output, transform, handler); + IMFTransform_Release(transform); + } + break; + case MF_TOPOLOGY_TEE_NODE: + hr = type_handler_create(node, stream, output, NULL, handler); + break; default: WARN("Unexpected node type %u.\n", node_type); return MF_E_UNEXPECTED; @@ -1857,48 +2053,15 @@ HRESULT topology_node_get_type_handler(IMFTopologyNode *node, DWORD stream, HRESULT WINAPI MFGetTopoNodeCurrentType(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaType **type) { IMFMediaTypeHandler *handler; - MF_TOPOLOGY_TYPE node_type; - IMFTransform *transform; - UINT32 primary_output; HRESULT hr;
TRACE("%p, %lu, %d, %p.\n", node, stream, output, type);
- if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type))) - return hr; - - if (SUCCEEDED(hr = topology_node_get_type_handler(node, stream, output, &handler))) - { - hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, type); - IMFMediaTypeHandler_Release(handler); + if (FAILED(hr = topology_node_get_type_handler(node, stream, output, &handler))) return hr; - } - - switch (node_type) - { - case MF_TOPOLOGY_TRANSFORM_NODE: - if (SUCCEEDED(hr = topology_node_get_object(node, &IID_IMFTransform, (void **)&transform))) - { - if (output) - hr = IMFTransform_GetOutputCurrentType(transform, stream, type); - else - hr = IMFTransform_GetInputCurrentType(transform, stream, type); - IMFTransform_Release(transform); - } - break; - case MF_TOPOLOGY_TEE_NODE: - if (SUCCEEDED(hr = IMFTopologyNode_GetInputPrefType(node, 0, type))) - break; - - if (FAILED(IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_PRIMARYOUTPUT, &primary_output))) - primary_output = 0; - - hr = IMFTopologyNode_GetOutputPrefType(node, primary_output, type); - break; - default: - ; - }
+ hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, type); + IMFMediaTypeHandler_Release(handler); return hr; }
This merge request was approved by Nikolay Sivov.