Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/mf/topology.c | 268 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 266 insertions(+), 2 deletions(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index a09f6ef0ef4..4756a30895b 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -1992,15 +1992,279 @@ static HRESULT topology_loader_clone_node(struct topoloader_context *context, IM return hr; }
+struct available_output_type +{ + IMFMediaType *type; + IMFTransform *transform; +}; + +static HRESULT topology_loader_enumerate_output_types(GUID *category, IMFMediaType *input_type, HRESULT (*new_type)(struct available_output_type *, void *), void *context) +{ + MFT_REGISTER_TYPE_INFO mft_typeinfo; + GUID major_type, subtype; + IMFActivate **activates; + UINT32 num_activates; + HRESULT hr; + + if (FAILED(hr = IMFMediaType_GetMajorType(input_type, &major_type))) + return hr; + + if (FAILED(hr = IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &subtype))) + return hr; + + mft_typeinfo.guidMajorType = major_type; + mft_typeinfo.guidSubtype = subtype; + + if (FAILED(hr = MFTEnumEx(*category, MFT_ENUM_FLAG_ALL, &mft_typeinfo, NULL, &activates, &num_activates))) + return hr; + + hr = E_FAIL; + + for (unsigned int i = 0; i < num_activates; i++) + { + IMFTransform *mft; + + if (FAILED(IMFActivate_ActivateObject(activates[i], &IID_IMFTransform, (void**) &mft))) + { + IMFActivate_Release(activates[i]); + continue; + } + + if (SUCCEEDED(hr = IMFTransform_SetInputType(mft, 0, input_type, 0))) + { + struct available_output_type avail = {.transform = mft}; + unsigned int output_count = 0; + + while (SUCCEEDED(IMFTransform_GetOutputAvailableType(mft, 0, output_count++, &avail.type))) + { + if (SUCCEEDED(hr = new_type(&avail, context))) + { + IMFActivate_Release(activates[i]); + return hr; + } + } + } + + IMFActivate_ShutdownObject(activates[i]); + IMFActivate_Release(activates[i]); + } + + return hr; +} + +struct connect_to_sink_context +{ + struct topoloader_context *context; + IMFTopologyNode *src, *sink; + IMFMediaTypeHandler *sink_mth; +}; + +HRESULT connect_to_sink(struct available_output_type *type, void *context) +{ + IMFTopologyNode *node; + struct connect_to_sink_context *ctx = context; + + if (SUCCEEDED(IMFMediaTypeHandler_IsMediaTypeSupported(ctx->sink_mth, type->type, NULL))) + { + MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node); + IMFTopologyNode_SetObject(node, (IUnknown *) type->transform); + IMFTopologyNode_ConnectOutput(ctx->src, 0, node, 0); + IMFTopologyNode_ConnectOutput(node, 0, ctx->sink, 0); + + IMFTopology_AddNode(ctx->context->output_topology, node); + IMFTopologyNode_Release(node); + + IMFMediaTypeHandler_SetCurrentMediaType(ctx->sink_mth, type->type); + IMFTransform_SetOutputType(type->transform, 0, type->type, 0); + + return S_OK; + } + return MF_E_TRANSFORM_NOT_POSSIBLE_FOR_CURRENT_MEDIATYPE_COMBINATION; +} + +struct connect_to_converter_context +{ + struct connect_to_sink_context sink_ctx; + GUID *converter_category; +}; + +HRESULT connect_to_converter(struct available_output_type *type, void *context) +{ + struct connect_to_converter_context *ctx = context; + struct connect_to_sink_context sink_ctx; + IMFTopologyNode *node; + HRESULT hr; + + if (SUCCEEDED(connect_to_sink(type, &ctx->sink_ctx))) + return S_OK; + + MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node); + IMFTopologyNode_SetObject(node, (IUnknown *) type->transform); + + sink_ctx = ctx->sink_ctx; + sink_ctx.src = node; + if (SUCCEEDED(hr = topology_loader_enumerate_output_types(ctx->converter_category, type->type, connect_to_sink, &sink_ctx))) + { + IMFTopologyNode_ConnectOutput(ctx->sink_ctx.src, 0, node, 0); + + IMFTopology_AddNode(ctx->sink_ctx.context->output_topology, node); + + IMFTransform_SetOutputType(type->transform, 0, type->type, 0); + + return S_OK; + } + IMFTopologyNode_Release(node); + return hr; +} + typedef HRESULT (*p_topology_loader_connect_func)(struct topoloader_context *context, IMFTopologyNode *upstream_node, unsigned int output_index, IMFTopologyNode *downstream_node, unsigned int input_index);
static HRESULT topology_loader_connect_source_node(struct topoloader_context *context, IMFTopologyNode *upstream_node, unsigned int output_index, IMFTopologyNode *downstream_node, unsigned int input_index) { - FIXME("Unimplemented.\n"); + UINT32 enum_src_types, src_method = 0, sink_method = MF_CONNECT_ALLOW_DECODER; + IMFMediaTypeHandler *src_mth = NULL, *sink_mth = NULL; + struct connect_to_converter_context convert_ctx; + unsigned int i, k, i_, k_, src_type_count; + GUID major_type, decode_cat, convert_cat; + struct connect_to_sink_context sink_ctx; + IMFStreamDescriptor *desc = NULL; + IMFStreamSink *stream_sink; + IMFMediaType *media_type; + HRESULT hr;
- return E_NOTIMPL; + TRACE("attempting to connect %p:%u to %p:%u\n", upstream_node, output_index, downstream_node, input_index); + + IMFTopologyNode_GetUnknown(upstream_node, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor, (void **)&desc); + + if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(desc, &src_mth))) + goto done; + + if (FAILED(hr = IMFMediaTypeHandler_GetMediaTypeCount(src_mth, &src_type_count))) + goto done; + + IMFTopologyNode_GetObject(downstream_node, (IUnknown **)&stream_sink); + + if (FAILED(hr = IMFStreamSink_GetMediaTypeHandler(stream_sink, &sink_mth))) + { + IMFStreamSink_Release(stream_sink); + goto done; + } + IMFStreamSink_Release(stream_sink); + + IMFTopologyNode_GetUINT32(upstream_node, &MF_TOPONODE_CONNECT_METHOD, &src_method); + IMFTopologyNode_GetUINT32(downstream_node, &MF_TOPONODE_CONNECT_METHOD, &sink_method); + IMFTopology_GetUINT32(context->input_topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enum_src_types); + + if (FAILED(hr = IMFMediaTypeHandler_GetMajorType(src_mth, &major_type))) + goto done; + + if (IsEqualGUID(&major_type, &MFMediaType_Audio)) + { + decode_cat = MFT_CATEGORY_AUDIO_DECODER; + convert_cat = MFT_CATEGORY_AUDIO_EFFECT; + } + else if (IsEqualGUID(&major_type, &MFMediaType_Video)) + { + decode_cat = MFT_CATEGORY_VIDEO_DECODER; + convert_cat = MFT_CATEGORY_VIDEO_EFFECT; + } + else + { + hr = MF_E_INVALIDTYPE; + goto done; + } + + sink_ctx.context = context; + sink_ctx.src = upstream_node; + sink_ctx.sink = downstream_node; + sink_ctx.sink_mth = sink_mth; + + convert_ctx.sink_ctx = sink_ctx; + convert_ctx.converter_category = &convert_cat; + + i_ = (enum_src_types && src_method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES) ? src_type_count : 1; + k_ = (enum_src_types && !(src_method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES)) ? src_type_count : 1; + for(i = 0; i < i_; i++) + { + /* MF_CONNECT_DIRECT */ + for (k = 0; k < k_; k++) + { + if (enum_src_types) + { + if (FAILED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(src_mth, i * k, &media_type))) goto done; + } + else + if (FAILED(hr = IMFMediaTypeHandler_GetCurrentMediaType(src_mth, &media_type))) goto done; + + if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(sink_mth, media_type, NULL))) + { + IMFMediaTypeHandler_SetCurrentMediaType(src_mth, media_type); + IMFMediaTypeHandler_SetCurrentMediaType(sink_mth, media_type); + IMFTopologyNode_ConnectOutput(upstream_node, output_index, downstream_node, input_index); + IMFMediaType_Release(media_type); + goto done; + } + + IMFMediaType_Release(media_type); + } + + for (k = 0; k < k_; k++) + { + if (enum_src_types) + { + if (FAILED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(src_mth, i * k, &media_type))) goto done; + } + else + if (FAILED(hr = IMFMediaTypeHandler_GetCurrentMediaType(src_mth, &media_type))) goto done; + + if (sink_method & MF_CONNECT_ALLOW_CONVERTER) + { + if (SUCCEEDED(hr = topology_loader_enumerate_output_types(&convert_cat, media_type, connect_to_sink, &sink_ctx))) + { + IMFMediaTypeHandler_SetCurrentMediaType(src_mth, media_type); + IMFMediaType_Release(media_type); + goto done; + } + } + + IMFMediaType_Release(media_type); + } + + for (k = 0; k < k_; k++) + { + if (enum_src_types) + { + if (FAILED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(src_mth, i * k, &media_type))) goto done; + } + else + if (FAILED(hr = IMFMediaTypeHandler_GetCurrentMediaType(src_mth, &media_type))) goto done; + + if (sink_method & MF_CONNECT_ALLOW_DECODER) + { + if (SUCCEEDED(hr = topology_loader_enumerate_output_types(&decode_cat, media_type, connect_to_converter, &convert_ctx))) + { + IMFMediaTypeHandler_SetCurrentMediaType(src_mth, media_type); + IMFMediaType_Release(media_type); + goto done; + } + } + + IMFMediaType_Release(media_type); + } + } + hr = MF_E_INVALIDMEDIATYPE; + + done: + if (desc) + IMFStreamDescriptor_Release(desc); + if (src_mth) + IMFMediaTypeHandler_Release(src_mth); + if (sink_mth) + IMFMediaTypeHandler_Release(sink_mth); + + return hr; }
static HRESULT topology_loader_resolve_branch(struct topoloader_context *context, IMFTopologyNode *upstream_node,