[PATCH v5 3/4] mf/topoloader: Implement source node to sink node branch resolver.
Derek Lesho
dlesho at codeweavers.com
Mon Nov 30 09:59:40 CST 2020
Signed-off-by: Derek Lesho <dlesho at codeweavers.com>
---
v5: Correct connect method handling. In v4, the MF_CONNECT_ALLOW_DECODER path is only triggered if the conidtion for sink_method & MF_CONNECT_ALLOW_CONVERTER is not satisfied.
This is never true, effectively making MF_CONNECT_ALLOW_DECODER a noop. Instead of using else here, just check for FAILED(hr).
---
dlls/mf/topology.c | 273 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 268 insertions(+), 5 deletions(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c
index a09f6ef0ef4..e3a4dfd5141 100644
--- a/dlls/mf/topology.c
+++ b/dlls/mf/topology.c
@@ -1992,15 +1992,278 @@ static HRESULT topology_loader_clone_node(struct topoloader_context *context, IM
return hr;
}
+struct transform_output_type
+{
+ IMFMediaType *type;
+ IMFTransform *transform;
+};
+
+struct connect_context
+{
+ struct topoloader_context *context;
+ IMFTopologyNode *upstream_node;
+ IMFTopologyNode *sink;
+ IMFMediaTypeHandler *sink_handler;
+ const GUID *converter_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;
+ 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 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 = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node)))
+ return hr;
+
+ IMFTopologyNode_SetObject(node, (IUnknown *)output_type->transform);
+ 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 = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node)))
+ return hr;
+
+ IMFTopologyNode_SetObject(node, (IUnknown *)output_type->transform);
+
+ 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_connect_source_node(struct topoloader_context *context, IMFTopologyNode *upstream_node,
- unsigned int output_index, IMFTopologyNode *downstream_node, unsigned int input_index)
+static HRESULT topology_loader_get_node_type_handler(IMFTopologyNode *node, IMFMediaTypeHandler **handler)
{
- FIXME("Unimplemented.\n");
+ MF_TOPOLOGY_TYPE node_type;
+ IMFStreamSink *stream_sink;
+ IMFStreamDescriptor *sd;
+ IUnknown *object;
+ HRESULT hr;
- return E_NOTIMPL;
+ if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type)))
+ return hr;
+
+ switch (node_type)
+ {
+ case MF_TOPOLOGY_OUTPUT_NODE:
+ if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, (IUnknown **)&object)))
+ {
+ if (SUCCEEDED(hr = IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&stream_sink)))
+ {
+ hr = IMFStreamSink_GetMediaTypeHandler(stream_sink, handler);
+ IMFStreamSink_Release(stream_sink);
+ }
+ IUnknown_Release(object);
+ }
+ break;
+ case MF_TOPOLOGY_SOURCESTREAM_NODE:
+ if (SUCCEEDED(hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR,
+ &IID_IMFStreamDescriptor, (void **)&sd)))
+ {
+ hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, handler);
+ IMFStreamDescriptor_Release(sd);
+ }
+ break;
+ default:
+ WARN("Unexpected node type %u.\n", node_type);
+ return MF_E_UNEXPECTED;
+ }
+
+ return hr;
+}
+
+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_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;
+ GUID decode_cat, convert_cat;
+ 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_loader_get_node_type_handler(source, &source_handler)))
+ goto done;
+
+ if (FAILED(hr = topology_loader_get_node_type_handler(sink, &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;
+
+ if (FAILED(hr = topology_loader_get_mft_categories(source_handler, &decode_cat, &convert_cat)))
+ goto done;
+
+ sink_ctx.context = context;
+ sink_ctx.upstream_node = source;
+ sink_ctx.sink = sink;
+ sink_ctx.sink_handler = sink_handler;
+
+ convert_ctx = sink_ctx;
+ convert_ctx.converter_category = &convert_cat;
+
+ if (SUCCEEDED(hr = IMFMediaTypeHandler_GetCurrentMediaType(source_handler, &media_type)))
+ {
+ /* Direct connection. */
+ if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(sink_handler, media_type, NULL))
+ && SUCCEEDED(hr = IMFMediaTypeHandler_SetCurrentMediaType(sink_handler, media_type)))
+ {
+ hr = IMFTopologyNode_ConnectOutput(source, output_index, sink, input_index);
+ }
+ if (FAILED(hr) && sink_method & MF_CONNECT_ALLOW_CONVERTER)
+ {
+ hr = topology_loader_enumerate_output_types(&convert_cat, media_type, connect_to_sink, &sink_ctx);
+ }
+ if (FAILED(hr) && sink_method & MF_CONNECT_ALLOW_DECODER)
+ {
+ hr = topology_loader_enumerate_output_types(&decode_cat, media_type, connect_to_converter, &convert_ctx);
+ }
+
+ 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,
@@ -2009,7 +2272,7 @@ static HRESULT topology_loader_resolve_branch(struct topoloader_context *context
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_node, NULL, NULL, NULL },
+ /* SOURCESTREAM */ { topology_loader_connect_source_to_sink, NULL, NULL, NULL },
/* TRANSFORM */ { NULL },
/* TEE */ { NULL },
};
--
2.29.2
More information about the wine-devel
mailing list