mf/topoloader: Implement source node to sink node branch resolver.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com> Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
eb28343c47
commit
d61e9f7535
|
@ -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 },
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue