[PATCH v3 3/4] mf/topoloader: Implement source node to sink node branch resolver.
Derek Lesho
dlesho at codeweavers.com
Fri Nov 27 16:36:08 CST 2020
Signed-off-by: Derek Lesho <dlesho at 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,
--
2.29.2
More information about the wine-devel
mailing list