[PATCH 0/12] MR10009: mf/topology_loader: Rewrite the topology loader to match more closely the test results.
The end result is more a rewrite than a modified version of the original. I was able to split the changes into patches, but this is not necessarily easier to understand than doing a mostly complete replacement in one commit and then adding a few things on top of that. With the change to video converter creation, mfmediaengine now depends on ENABLE_XVP being set, as it does in Windows. This change has already been made in mfmediaengine. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/mf/main.c | 183 ++++++++++++++++++++++++++++++++++++++ dlls/mf/mf_private.h | 2 + dlls/mf/topology_loader.c | 31 +++++-- 3 files changed, 209 insertions(+), 7 deletions(-) diff --git a/dlls/mf/main.c b/dlls/mf/main.c index 537db3174cf..931400cd50c 100644 --- a/dlls/mf/main.c +++ b/dlls/mf/main.c @@ -36,6 +36,189 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); extern const GUID CLSID_FileSchemePlugin; +struct guid_def +{ + const GUID *guid; + const char *name; +}; + +static int __cdecl debug_compare_guid(const void *a, const void *b) +{ + const GUID *guid = a; + const struct guid_def *guid_def = b; + return memcmp(guid, guid_def->guid, sizeof(*guid)); +} + +/* copied from mfplat module */ +const char *debugstr_mf_guid(const GUID *guid) +{ + static const struct guid_def guid_defs[] = + { +#define X(g) { &(g), #g } + X(MFAudioFormat_ADTS), + X(MFAudioFormat_PCM), + X(MFAudioFormat_PCM_HDCP), + X(MFAudioFormat_Float), + X(MFAudioFormat_DTS), + X(MFAudioFormat_DRM), + X(MFAudioFormat_MSP1), + X(MFAudioFormat_Vorbis), + X(MFAudioFormat_AAC), + X(MFVideoFormat_RGB24), + X(MFVideoFormat_ARGB32), + X(MFVideoFormat_RGB32), + X(MFVideoFormat_RGB565), + X(MFVideoFormat_RGB555), + X(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID), + X(MFT_CATEGORY_MULTIPLEXER), + X(MFVideoFormat_A2R10G10B10), + X(MFT_CATEGORY_VIDEO_EFFECT), + X(MFMediaType_Script), + X(MFMediaType_Image), + X(MFMediaType_HTML), + X(MFMediaType_Binary), + X(MFVideoFormat_MPEG2), + X(MFMediaType_FileTransfer), + X(MFVideoFormat_RGB8), + X(MFAudioFormat_Dolby_AC3), + X(MFVideoFormat_L8), + X(MFAudioFormat_LPCM), + X(MFVideoFormat_420O), + X(MFVideoFormat_AI44), + X(MFVideoFormat_AV1), + X(MFVideoFormat_AYUV), + X(MFVideoFormat_H263), + X(MFVideoFormat_H264), + X(MFVideoFormat_H265), + X(MFVideoFormat_HEVC), + X(MFVideoFormat_HEVC_ES), + X(MFT_CATEGORY_AUDIO_EFFECT), + X(MFVideoFormat_I420), + X(MFVideoFormat_IYUV), + X(MFT_CATEGORY_VIDEO_DECODER), + X(MFVideoFormat_M4S2), + X(MFVideoFormat_MJPG), + X(MFVideoFormat_MP43), + X(MFVideoFormat_MP4S), + X(MFVideoFormat_MP4V), + X(MFVideoFormat_MPG1), + X(MFVideoFormat_MSS1), + X(MFVideoFormat_MSS2), + X(MFVideoFormat_NV11), + X(MFVideoFormat_NV12), + X(MFVideoFormat_ORAW), + X(MFAudioFormat_Opus), + X(MFAudioFormat_MPEG), + X(MFVideoFormat_D16), + X(MFVideoFormat_P010), + X(MFVideoFormat_P016), + X(MFVideoFormat_P210), + X(MFVideoFormat_P216), + X(MFVideoFormat_L16), + X(MFAudioFormat_MP3), + X(MFVideoFormat_UYVY), + X(MFVideoFormat_VP10), + X(MFVideoFormat_VP80), + X(MFVideoFormat_VP90), + X(MFVideoFormat_WMV1), + X(MFVideoFormat_WMV2), + X(MFVideoFormat_WMV3), + X(MFVideoFormat_WVC1), + X(MFT_CATEGORY_OTHER), + X(MFVideoFormat_Y210), + X(MFVideoFormat_Y216), + X(MFVideoFormat_Y410), + X(MFVideoFormat_Y416), + X(MFVideoFormat_Y41P), + X(MFVideoFormat_Y41T), + X(MFVideoFormat_Y42T), + X(MFVideoFormat_YUY2), + X(MFVideoFormat_YV12), + X(MFVideoFormat_YVU9), + X(MFVideoFormat_YVYU), + X(MFAudioFormat_WMAudioV8), + X(MFAudioFormat_ALAC), + X(MFAudioFormat_AMR_NB), + X(MFMediaType_Audio), + X(MFAudioFormat_WMAudioV9), + X(MFAudioFormat_AMR_WB), + X(MFAudioFormat_WMAudio_Lossless), + X(MFAudioFormat_AMR_WP), + X(MFAudioFormat_WMASPDIF), + X(MFVideoFormat_DV25), + X(MFVideoFormat_DV50), + X(MFVideoFormat_DVC), + X(MFVideoFormat_DVH1), + X(MFVideoFormat_DVHD), + X(MFVideoFormat_DVSD), + X(MFVideoFormat_DVSL), + X(MFVideoFormat_A16B16G16R16F), + X(MFVideoFormat_v210), + X(MFVideoFormat_v216), + X(MFVideoFormat_v410), + X(MFMediaType_Video), + X(MFAudioFormat_AAC_HDCP), + X(MFT_CATEGORY_DEMULTIPLEXER), + X(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID), + X(MFT_CATEGORY_VIDEO_ENCODER), + X(MFAudioFormat_Dolby_AC3_HDCP), + X(MFMediaType_Subtitle), + X(MFMediaType_Stream), + X(MFAudioFormat_Dolby_AC3_SPDIF), + X(MFAudioFormat_Float_SpatialObjects), + X(MFMediaType_SAMI), + X(MFAudioFormat_ADTS_HDCP), + X(MFAudioFormat_FLAC), + X(MFAudioFormat_Dolby_DDPlus), + X(MFMediaType_MultiplexedFrames), + X(MFT_CATEGORY_AUDIO_DECODER), + X(MFAudioFormat_Base_HDCP), + X(MFT_CATEGORY_AUDIO_ENCODER), + X(MFVideoFormat_Base_HDCP), + X(MFVideoFormat_H264_HDCP), + X(MFVideoFormat_HEVC_HDCP), + X(MFMediaType_Default), + X(MFMediaType_Protected), + X(MFVideoFormat_H264_ES), + X(MFMediaType_Perception), + X(MFT_CATEGORY_VIDEO_PROCESSOR), +#undef X + }; + struct guid_def *ret = NULL; + + if (guid) + ret = bsearch(guid, guid_defs, ARRAY_SIZE(guid_defs), sizeof(*guid_defs), debug_compare_guid); + + return ret ? wine_dbg_sprintf("%s", ret->name) : wine_dbgstr_guid(guid); +} + +const char *debugstr_media_subtype(IMFMediaType *media_type) +{ + UINT channels, sps; + GUID subtype = {0}; + UINT64 frame_size; + + if (!media_type) + return "{null}"; + + IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype); + + if (SUCCEEDED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size)) && frame_size) + { + return wine_dbg_sprintf("{%p %s %ux%u}", media_type, debugstr_mf_guid(&subtype), (UINT)(frame_size >> 32), (UINT32)frame_size); + } + else if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, &channels)) && channels) + { + if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &sps))) + return wine_dbg_sprintf("{%p %s %u-ch %u}", media_type, debugstr_mf_guid(&subtype), channels, sps); + return wine_dbg_sprintf("{%p %s %u-ch}", media_type, debugstr_mf_guid(&subtype), channels); + } + else + { + return wine_dbg_sprintf("{%p %s ?}", media_type, debugstr_mf_guid(&subtype)); + } +} + struct activate_object { IMFActivate IMFActivate_iface; diff --git a/dlls/mf/mf_private.h b/dlls/mf/mf_private.h index 1f2ef17a8c9..6b182e04d82 100644 --- a/dlls/mf/mf_private.h +++ b/dlls/mf/mf_private.h @@ -113,6 +113,8 @@ static inline const char *debugstr_propvar(const PROPVARIANT *v) } } +extern const char *debugstr_media_subtype(IMFMediaType *media_type); + extern HRESULT file_scheme_handler_construct(REFIID riid, void **obj); extern HRESULT urlmon_scheme_handler_construct(REFIID riid, void **obj); diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 73f70e62bc6..0c1b48ca1b2 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -147,9 +147,26 @@ struct topology_branch struct list entry; }; +static const char *debugstr_topology_node_type(IMFTopologyNode *node) +{ + MF_TOPOLOGY_TYPE type = MF_TOPOLOGY_MAX; + + IMFTopologyNode_GetNodeType(node, &type); + switch (type) + { + case MF_TOPOLOGY_OUTPUT_NODE: return "sink"; + case MF_TOPOLOGY_SOURCESTREAM_NODE: return "source"; + case MF_TOPOLOGY_TRANSFORM_NODE: return "transform"; + case MF_TOPOLOGY_TEE_NODE: return "tee"; + default: return "unknown"; + } +} + 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); + return wine_dbg_sprintf("%s %p:%lu to %s %p:%lu", debugstr_topology_node_type(branch->up.node), + branch->up.node, branch->up.stream, debugstr_topology_node_type(branch->down.node), + branch->down.node, branch->down.stream); } static HRESULT topology_branch_create(IMFTopologyNode *source, DWORD source_stream, @@ -282,8 +299,8 @@ static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNEC GUID category, guid; HRESULT 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); + TRACE("topology %p, method_mask %#x, branch %s, up_type %s, down_type %s.\n", topology, method_mask, + debugstr_topology_branch(branch), debugstr_media_subtype(up_type), debugstr_media_subtype(down_type)); if (FAILED(hr = IMFMediaType_GetMajorType(up_type, &input_info.guidMajorType))) return hr; @@ -420,8 +437,8 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_ME DWORD flags; HRESULT hr; - TRACE("topology %p, method_mask %#x, branch %s, up_type %p.\n", - topology, method_mask, debugstr_topology_branch(branch), up_type); + TRACE("topology %p, method_mask %#x, branch %s, up_type %s.\n", + topology, method_mask, debugstr_topology_branch(branch), debugstr_media_subtype(up_type)); if (FAILED(IMFTopologyNode_GetUINT32(branch->down.node, &MF_TOPONODE_CONNECT_METHOD, &method))) method = MF_CONNECT_ALLOW_DECODER; @@ -432,14 +449,14 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_ME if (SUCCEEDED(hr = get_first_supported_media_type(down_handler, &down_type)) && IMFMediaType_IsEqual(up_type, down_type, &flags) == S_OK) { - TRACE("Connecting branch %s with current type %p.\n", debugstr_topology_branch(branch), up_type); + TRACE("Connecting branch %s with current type %s.\n", debugstr_topology_branch(branch), debugstr_media_subtype(up_type)); hr = IMFTopologyNode_ConnectOutput(branch->up.node, branch->up.stream, branch->down.node, branch->down.stream); goto done; } if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(down_handler, up_type, NULL))) { - TRACE("Connected branch %s with upstream type %p.\n", debugstr_topology_branch(branch), up_type); + TRACE("Connected branch %s with upstream type %s.\n", debugstr_topology_branch(branch), debugstr_media_subtype(up_type)); if (SUCCEEDED(IMFTopologyNode_GetNodeType(branch->down.node, &type)) && type == MF_TOPOLOGY_TRANSFORM_NODE && FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(down_handler, up_type))) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
From: Conor McCarthy <cmccarthy@codeweavers.com> This is not necessary and results in some branches being connected twice. --- dlls/mf/topology_loader.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 0c1b48ca1b2..5c691003621 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -555,7 +555,6 @@ static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD static HRESULT topology_loader_resolve_branches(struct topoloader_context *context, struct list *branches, BOOL enumerate_source_types) { - struct list new_branches = LIST_INIT(new_branches); struct topology_branch *branch, *next; MF_TOPOLOGY_TYPE node_type; HRESULT hr = S_OK; @@ -564,9 +563,7 @@ static HRESULT topology_loader_resolve_branches(struct topoloader_context *conte { 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))) + 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)); @@ -582,7 +579,6 @@ static HRESULT topology_loader_resolve_branches(struct topoloader_context *conte break; } - list_move_tail(branches, &new_branches); return hr; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/mf/tests/topology.c | 12 +-- dlls/mf/topology_loader.c | 151 +++++++++++++++++++++++++++++--------- 2 files changed, 121 insertions(+), 42 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index d2c1b047c52..52a95e2d973 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -2661,7 +2661,7 @@ static void test_topology_loader(void) .mft_output_types = {&audio_float_minimal, &audio_pcm_minimal, &audio_float_48000, &audio_pcm_48000}, .mft_current_output = &audio_pcm_minimal, .expected_result = MF_E_INVALIDMEDIATYPE, - .flags = LOADER_ADD_TEST_MFT | LOADER_TODO_MFT_IN_TYPE | LOADER_TODO_MFT_OUT_TYPE | LOADER_TODO, + .flags = LOADER_ADD_TEST_MFT | LOADER_TODO_MFT_IN_TYPE, }, { /* PCM -> PCM, different enumerated bps, add test MFT */ @@ -2676,7 +2676,7 @@ static void test_topology_loader(void) .mft_output_types = {&audio_float_minimal, &audio_pcm_minimal, &audio_float_48000, &audio_pcm_48000_resampler}, .mft_current_output = &audio_pcm_48000, .expected_result = S_OK, - .flags = LOADER_ADD_TEST_MFT | LOADER_TODO_MFT_IN_TYPE | LOADER_TODO_MFT_OUT_TYPE, + .flags = LOADER_ADD_TEST_MFT | LOADER_TODO_MFT_IN_TYPE, }, { /* PCM -> PCM, different enumerated bps, add test MFT, configure MFT, no output types */ @@ -2684,7 +2684,7 @@ static void test_topology_loader(void) .mft_output_types = {&audio_float_minimal, &audio_pcm_minimal, &audio_float_48000, &audio_pcm_48000_resampler}, .mft_current_output = &audio_pcm_48000, .expected_result = S_OK, - .flags = LOADER_ADD_TEST_MFT | LOADER_NO_CURRENT_OUTPUT | LOADER_TODO_MFT_IN_TYPE | LOADER_TODO_MFT_OUT_TYPE, + .flags = LOADER_ADD_TEST_MFT | LOADER_NO_CURRENT_OUTPUT | LOADER_TODO_MFT_IN_TYPE, }, { /* MP3 -> PCM, different enumerated bps, add test MFT, configure MFT */ @@ -2692,7 +2692,7 @@ static void test_topology_loader(void) .mft_input_type = &audio_pcm_44100, .mft_output_types = {&audio_pcm_48000}, .decoded_type = &audio_pcm_44100, .expected_result = S_OK, .decoder_class = CLSID_CMP3DecMediaObject, - .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO | LOADER_TODO_MFT_OUT_TYPE, + .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, }, { /* MP3 -> PCM, different enumerated bps, add incompatible test MFT, configure MFT */ @@ -2837,14 +2837,14 @@ static void test_topology_loader(void) .input_types = {&video_h264_1280}, .output_types = {&video_video_processor_1280_rgb32}, .sink_method = -1, .source_method = -1, .mft_input_type = &video_video_processor_1280_rgb32, .mft_output_types = {&video_video_processor_1280_rgb32}, .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, .converter_class = CLSID_CColorConvertDMO, - .flags = LOADER_ADD_TEST_MFT | LOADER_TODO_MFT_OUT_TYPE | LOADER_TEST_MFT_EXPECT_CONVERTER | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, + .flags = LOADER_ADD_TEST_MFT | LOADER_TEST_MFT_EXPECT_CONVERTER | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, }, { /* H264 -> NV12, add test MFT */ .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = -1, .source_method = -1, .mft_input_type = &video_nv12_1280, .mft_output_types = {&video_nv12_1280}, .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, - .flags = LOADER_ADD_TEST_MFT | LOADER_TODO_MFT_OUT_TYPE | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, + .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, }, }; diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 5c691003621..3b20b5b7cb9 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -124,18 +124,6 @@ struct transform_output_type 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; -}; - struct topology_branch { struct @@ -283,6 +271,99 @@ static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMedi return hr; } +struct connection_context_type_enumerator +{ + IMFMediaTypeHandler *handler; + IMFMediaType *current; + IMFMediaType *index0; + BOOL enumerate; + int index; +}; + +static void type_enumerator_reset(struct connection_context_type_enumerator *enumerator) +{ + enumerator->index = 0 - !!enumerator->current; +} + +static HRESULT type_enumerator_get_next_media_type(struct connection_context_type_enumerator *enumerator, + IMFMediaType **type) +{ + int i = enumerator->index++; + + if (i < 0) + { + IMFMediaType_AddRef(*type = enumerator->current); + return S_OK; + } + + /* If we are not enumerating and we have a current type, do not check index 0. */ + if (!i && (!enumerator->current || enumerator->enumerate)) + { + /* Null is returned for sink type enumeration if GetCurrentMediaType() returns E_FAIL. */ + if ((*type = enumerator->index0)) + IMFMediaType_AddRef(*type); + return S_OK; + } + + if (enumerator->enumerate) + return IMFMediaTypeHandler_GetMediaTypeByIndex(enumerator->handler, i, type); + + /* return MF_E_INVALIDMEDIATYPE if not enumerating types */ + return MF_E_INVALIDMEDIATYPE; +} + +static void type_enumerator_release(struct connection_context_type_enumerator *enumerator) +{ + if (enumerator->current) + IMFMediaType_Release(enumerator->current); + if (enumerator->index0) + IMFMediaType_Release(enumerator->index0); + if (enumerator->handler) + IMFMediaTypeHandler_Release(enumerator->handler); +} + +struct connection_context +{ + MF_TOPOLOGY_TYPE up_node_type; + struct connection_context_type_enumerator up_types; +}; + +static void connection_context_destroy(struct connection_context *context) +{ + type_enumerator_release(&context->up_types); +} + +static HRESULT connection_context_init(struct connection_context *context, IMFTopology *topology, + struct topology_branch *branch, MF_CONNECT_METHOD method, BOOL enumerate_source_types) +{ + IMFMediaType *up_type; + HRESULT hr; + + if (FAILED(hr = IMFTopologyNode_GetNodeType(branch->up.node, &context->up_node_type))) + return hr; + + if (FAILED(hr = topology_node_get_type_handler(branch->up.node, branch->up.stream, TRUE, &context->up_types.handler))) + return hr; + + enumerate_source_types = context->up_node_type == MF_TOPOLOGY_SOURCESTREAM_NODE && enumerate_source_types; + if (!(context->up_types.enumerate = enumerate_source_types)) + { + hr = IMFMediaTypeHandler_GetCurrentMediaType(context->up_types.handler, &context->up_types.current); + if (context->up_node_type != MF_TOPOLOGY_SOURCESTREAM_NODE) + context->up_types.enumerate = FAILED(hr); + } + + if (FAILED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(context->up_types.handler, 0, &up_type))) + goto failed; + context->up_types.index0 = up_type; + + return S_OK; + +failed: + connection_context_destroy(context); + return hr; +} + static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD method_mask, struct topology_branch *branch, BOOL enumerate_source_types); static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method_mask, @@ -484,16 +565,13 @@ done: } static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, MF_CONNECT_METHOD method_mask, - struct topology_branch *branch) + struct topology_branch *branch, struct connection_context *context) { - IMFMediaTypeHandler *handler; + IMFMediaTypeHandler *handler = context->up_types.handler; IMFMediaType *type; DWORD index = 0; HRESULT hr; - if (FAILED(hr = topology_node_get_type_handler(branch->up.node, branch->up.stream, TRUE, &handler))) - return hr; - while (SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, index++, &type))) { hr = topology_branch_connect_down(topology, method_mask, branch, type); @@ -504,50 +582,58 @@ static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, MF_CONNEC break; } - IMFMediaTypeHandler_Release(handler); return hr; } static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD method_mask, struct topology_branch *branch, BOOL enumerate_source_types) { + struct connection_context context = {0}; UINT32 method; HRESULT hr; TRACE("topology %p, method_mask %#x, branch %s.\n", topology, method_mask, debugstr_topology_branch(branch)); + if (FAILED(hr = connection_context_init(&context, topology, branch, method_mask, enumerate_source_types))) + return hr; + if (FAILED(IMFTopologyNode_GetUINT32(branch->up.node, &MF_TOPONODE_CONNECT_METHOD, &method))) method = MF_CONNECT_DIRECT; if (enumerate_source_types) { if (method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES) - hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_DECODER, branch); + hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_DECODER, branch, &context); else { - hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_DIRECT, branch); + hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_DIRECT, branch, &context); if (FAILED(hr)) - hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_CONVERTER, branch); + hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_CONVERTER, branch, &context); if (FAILED(hr)) - hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_DECODER, branch); + hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_DECODER, branch, &context); } } else { - 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))) + type_enumerator_reset(&context.up_types); + while (SUCCEEDED(type_enumerator_get_next_media_type(&context.up_types, &up_type))) { hr = topology_branch_connect_down(topology, method_mask, branch, up_type); + /* Upstream type is left unset only for an unenumerated media source. */ + if (SUCCEEDED(hr) && context.up_node_type != MF_TOPOLOGY_SOURCESTREAM_NODE) + hr = IMFMediaTypeHandler_SetCurrentMediaType(context.up_types.handler, up_type); IMFMediaType_Release(up_type); + if (SUCCEEDED(hr)) + break; } - IMFMediaTypeHandler_Release(up_handler); + if (hr == MF_E_INVALIDMEDIATYPE && context.up_types.enumerate) + hr = MF_E_NO_MORE_TYPES; } + connection_context_destroy(&context); + TRACE("returning %#lx\n", hr); return hr; } @@ -556,23 +642,16 @@ static HRESULT topology_loader_resolve_branches(struct topoloader_context *conte BOOL enumerate_source_types) { struct topology_branch *branch, *next; - MF_TOPOLOGY_TYPE node_type; HRESULT hr = S_OK; LIST_FOR_EACH_ENTRY_SAFE(branch, next, branches, struct topology_branch, entry) { list_remove(&branch->entry); - 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))) + if (FAILED(hr = topology_branch_clone_nodes(context, branch))) WARN("Failed to clone nodes for branch %s\n", debugstr_topology_branch(branch)); else - { hr = topology_branch_connect(context->output_topology, MF_CONNECT_ALLOW_DECODER, branch, enumerate_source_types); - if (hr == MF_E_INVALIDMEDIATYPE && !enumerate_source_types && node_type == MF_TOPOLOGY_TRANSFORM_NODE) - hr = topology_branch_connect(context->output_topology, MF_CONNECT_ALLOW_DECODER, branch, TRUE); - } topology_branch_destroy(branch); if (FAILED(hr)) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
From: Conor McCarthy <cmccarthy@codeweavers.com> The todo_wine on test line 2712 is for a sink with zero supported media types, not valid on recent Windows versions. --- dlls/mf/tests/mf.c | 2 +- dlls/mf/tests/topology.c | 14 ++++----- dlls/mf/topology_loader.c | 61 ++++++++++++++++++++++----------------- 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index d3e191d8721..68fe4743efe 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -2635,7 +2635,6 @@ static void test_media_session_events(void) ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); PropVariantClear(&propvar); - todo_wine ok(!handler->enum_count, "got %lu GetMediaTypeByIndex\n", handler->enum_count); ok(handler->set_current_count, "got %lu SetCurrentMediaType\n", handler->set_current_count); handler->enum_count = handler->set_current_count = 0; @@ -2709,6 +2708,7 @@ static void test_media_session_events(void) ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); PropVariantClear(&propvar); + todo_wine ok(!handler->enum_count, "got %lu GetMediaTypeByIndex\n", handler->enum_count); ok(handler->set_current_count, "got %lu SetCurrentMediaType\n", handler->set_current_count); handler->enum_count = handler->set_current_count = 0; diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index 52a95e2d973..a1fcff28e33 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -2486,7 +2486,6 @@ static void test_topology_loader(void) .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_44100}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .current_input = &audio_pcm_44100_incomplete, .expected_result = MF_E_INVALIDMEDIATYPE, - .flags = LOADER_TODO, }, { /* PCM -> PCM, same enumerated bps, different current bps */ @@ -2513,7 +2512,7 @@ static void test_topology_loader(void) .input_types = {&audio_pcm_44100_incomplete}, .output_types = {&audio_pcm_44100}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .current_input = &audio_pcm_44100, .expected_result = MF_E_NO_MORE_TYPES, - .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES | LOADER_TODO, + .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES, }, { @@ -2661,7 +2660,7 @@ static void test_topology_loader(void) .mft_output_types = {&audio_float_minimal, &audio_pcm_minimal, &audio_float_48000, &audio_pcm_48000}, .mft_current_output = &audio_pcm_minimal, .expected_result = MF_E_INVALIDMEDIATYPE, - .flags = LOADER_ADD_TEST_MFT | LOADER_TODO_MFT_IN_TYPE, + .flags = LOADER_ADD_TEST_MFT, }, { /* PCM -> PCM, different enumerated bps, add test MFT */ @@ -2676,7 +2675,7 @@ static void test_topology_loader(void) .mft_output_types = {&audio_float_minimal, &audio_pcm_minimal, &audio_float_48000, &audio_pcm_48000_resampler}, .mft_current_output = &audio_pcm_48000, .expected_result = S_OK, - .flags = LOADER_ADD_TEST_MFT | LOADER_TODO_MFT_IN_TYPE, + .flags = LOADER_ADD_TEST_MFT, }, { /* PCM -> PCM, different enumerated bps, add test MFT, configure MFT, no output types */ @@ -2684,7 +2683,7 @@ static void test_topology_loader(void) .mft_output_types = {&audio_float_minimal, &audio_pcm_minimal, &audio_float_48000, &audio_pcm_48000_resampler}, .mft_current_output = &audio_pcm_48000, .expected_result = S_OK, - .flags = LOADER_ADD_TEST_MFT | LOADER_NO_CURRENT_OUTPUT | LOADER_TODO_MFT_IN_TYPE, + .flags = LOADER_ADD_TEST_MFT | LOADER_NO_CURRENT_OUTPUT, }, { /* MP3 -> PCM, different enumerated bps, add test MFT, configure MFT */ @@ -2699,7 +2698,7 @@ static void test_topology_loader(void) .input_types = {&audio_mp3_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_DIRECT, .source_method = MF_CONNECT_DIRECT, .mft_input_type = &audio_aac_44100, .mft_output_types = {&audio_pcm_48000}, .expected_result = MF_E_TOPO_CODEC_NOT_FOUND, - .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO | LOADER_TODO, + .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, }, { @@ -2830,7 +2829,7 @@ static void test_topology_loader(void) .input_types = {&video_h264_1280}, .output_types = {&video_color_convert_1280_rgb32}, .sink_method = -1, .source_method = -1, .mft_input_type = &video_color_convert_1280_rgb32, .mft_output_types = {&video_color_convert_1280_rgb32}, .expected_result = MF_E_TOPO_CODEC_NOT_FOUND, .decoder_class = CLSID_CMSH264DecoderMFT, - .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO | LOADER_TODO, + .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, }, { /* H264 -> RGB32, Video Processor media type, add test MFT */ @@ -3417,7 +3416,6 @@ todo_wine { ok(ref == 0, "Release returned %ld\n", ref); ref = IMFMediaType_Release(input_types[0]); - todo_wine ok(ref == 0, "Release returned %ld\n", ref); ref = IMFMediaType_Release(input_types[1]); ok(ref == 0, "Release returned %ld\n", ref); diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 3b20b5b7cb9..ce7ef64e228 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -326,11 +326,13 @@ struct connection_context { MF_TOPOLOGY_TYPE up_node_type; struct connection_context_type_enumerator up_types; + struct connection_context_type_enumerator down_types; }; static void connection_context_destroy(struct connection_context *context) { type_enumerator_release(&context->up_types); + type_enumerator_release(&context->down_types); } static HRESULT connection_context_init(struct connection_context *context, IMFTopology *topology, @@ -344,6 +346,8 @@ static HRESULT connection_context_init(struct connection_context *context, IMFTo if (FAILED(hr = topology_node_get_type_handler(branch->up.node, branch->up.stream, TRUE, &context->up_types.handler))) return hr; + if (FAILED(hr = topology_node_get_type_handler(branch->down.node, branch->down.stream, FALSE, &context->down_types.handler))) + goto failed; enumerate_source_types = context->up_node_type == MF_TOPOLOGY_SOURCESTREAM_NODE && enumerate_source_types; if (!(context->up_types.enumerate = enumerate_source_types)) @@ -357,6 +361,9 @@ static HRESULT connection_context_init(struct connection_context *context, IMFTo goto failed; context->up_types.index0 = up_type; + hr = IMFMediaTypeHandler_GetCurrentMediaType(context->down_types.handler, &context->down_types.current); + context->down_types.enumerate = (hr == MF_E_NOT_INITIALIZED || hr == MF_E_TRANSFORM_TYPE_NOT_SET); + return S_OK; failed: @@ -364,12 +371,19 @@ failed: return hr; } +static void connection_context_init_down_type_enumeration(struct connection_context *context) +{ + /* Types are fetched by index only if GetCurrentMediaType() returned MF_E_NOT_INITIALIZED or MF_E_TRANSFORM_TYPE_NOT_SET. */ + if (context->down_types.enumerate && !context->down_types.index0) + IMFMediaTypeHandler_GetMediaTypeByIndex(context->down_types.handler, 0, &context->down_types.index0); +} + static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD method_mask, struct topology_branch *branch, BOOL enumerate_source_types); static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method_mask, - struct topology_branch *branch, IMFMediaType *up_type); + struct topology_branch *branch, IMFMediaType *up_type, struct connection_context *context); static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNECT_METHOD method_mask, - struct topology_branch *branch, IMFMediaType *up_type, IMFMediaType *down_type) + struct topology_branch *branch, BOOL enumerate, 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; @@ -421,6 +435,7 @@ static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNEC { struct topology_branch down_branch = {.up.node = node, .down = branch->down}; struct topology_branch up_branch = {.up = branch->up, .down.node = node}; + struct connection_context up_context = {0}; MF_CONNECT_METHOD method = method_mask; IMFMediaType *media_type; @@ -432,7 +447,14 @@ static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNEC if (SUCCEEDED(IMFActivate_GetGUID(activates[i], &MFT_TRANSFORM_CLSID_Attribute, &guid))) IMFTopologyNode_SetGUID(node, &MF_TOPONODE_TRANSFORM_OBJECTID, &guid); - hr = topology_branch_connect_down(topology, MF_CONNECT_DIRECT, &up_branch, up_type); + if (FAILED(hr = connection_context_init(&up_context, topology, &up_branch, MF_CONNECT_DIRECT, enumerate))) + { + IMFTransform_Release(transform); + continue; + } + + hr = topology_branch_connect_down(topology, MF_CONNECT_DIRECT, &up_branch, up_type, &up_context); + connection_context_destroy(&up_context); if (down_type && SUCCEEDED(MFCreateMediaType(&media_type))) { if (SUCCEEDED(IMFMediaType_CopyAllItems(down_type, (IMFAttributes *)media_type)) @@ -509,13 +531,12 @@ HRESULT topology_node_init_media_type(IMFTopologyNode *node, DWORD stream, BOOL } static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method_mask, - struct topology_branch *branch, IMFMediaType *up_type) + struct topology_branch *branch, IMFMediaType *up_type, struct connection_context *context) { - IMFMediaTypeHandler *down_handler; - IMFMediaType *down_type = NULL; + IMFMediaTypeHandler *down_handler = context->down_types.handler; + IMFMediaType *down_type; MF_TOPOLOGY_TYPE type; UINT32 method; - DWORD flags; HRESULT hr; TRACE("topology %p, method_mask %#x, branch %s, up_type %s.\n", @@ -524,17 +545,6 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_ME if (FAILED(IMFTopologyNode_GetUINT32(branch->down.node, &MF_TOPONODE_CONNECT_METHOD, &method))) method = MF_CONNECT_ALLOW_DECODER; - if (FAILED(hr = topology_node_get_type_handler(branch->down.node, branch->down.stream, FALSE, &down_handler))) - return hr; - - if (SUCCEEDED(hr = get_first_supported_media_type(down_handler, &down_type)) - && IMFMediaType_IsEqual(up_type, down_type, &flags) == S_OK) - { - TRACE("Connecting branch %s with current type %s.\n", debugstr_topology_branch(branch), debugstr_media_subtype(up_type)); - hr = IMFTopologyNode_ConnectOutput(branch->up.node, branch->up.stream, branch->down.node, branch->down.stream); - goto done; - } - if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(down_handler, up_type, NULL))) { TRACE("Connected branch %s with upstream type %s.\n", debugstr_topology_branch(branch), debugstr_media_subtype(up_type)); @@ -548,19 +558,18 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_ME goto done; } + connection_context_init_down_type_enumeration(context); + down_type = context->down_types.current ? context->down_types.current : context->down_types.index0; + 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); + branch, context->up_types.enumerate, 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); + branch, context->up_types.enumerate, up_type, down_type); done: - if (down_type) - IMFMediaType_Release(down_type); - IMFMediaTypeHandler_Release(down_handler); - return hr; } @@ -574,7 +583,7 @@ static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, MF_CONNEC while (SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, index++, &type))) { - hr = topology_branch_connect_down(topology, method_mask, branch, type); + hr = topology_branch_connect_down(topology, method_mask, branch, type, context); if (SUCCEEDED(hr)) hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, type); IMFMediaType_Release(type); @@ -620,7 +629,7 @@ static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD type_enumerator_reset(&context.up_types); while (SUCCEEDED(type_enumerator_get_next_media_type(&context.up_types, &up_type))) { - hr = topology_branch_connect_down(topology, method_mask, branch, up_type); + hr = topology_branch_connect_down(topology, method_mask, branch, up_type, &context); /* Upstream type is left unset only for an unenumerated media source. */ if (SUCCEEDED(hr) && context.up_node_type != MF_TOPOLOGY_SOURCESTREAM_NODE) hr = IMFMediaTypeHandler_SetCurrentMediaType(context.up_types.handler, up_type); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
From: Conor McCarthy <cmccarthy@codeweavers.com> Windows does not call MFTEnumEx to get a resampler. --- dlls/mf/tests/topology.c | 4 +- dlls/mf/topology_loader.c | 211 +++++++++++++++++++++++++++++++++++++- 2 files changed, 211 insertions(+), 4 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index a1fcff28e33..39e8ecdb401 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -2549,7 +2549,7 @@ static void test_topology_loader(void) /* PCM -> PCM, different enumerated bps, no current type, sink allow converter, no output types */ .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = MF_CONNECT_DIRECT, .expected_result = MF_E_INVALIDMEDIATYPE, .converter_class = CLSID_CResamplerMediaObject, - .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_TODO, + .flags = LOADER_NO_CURRENT_OUTPUT, }, { /* PCM -> PCM, different enumerated bps, no current type, sink allow converter, no current output type */ @@ -2698,7 +2698,7 @@ static void test_topology_loader(void) .input_types = {&audio_mp3_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_DIRECT, .source_method = MF_CONNECT_DIRECT, .mft_input_type = &audio_aac_44100, .mft_output_types = {&audio_pcm_48000}, .expected_result = MF_E_TOPO_CODEC_NOT_FOUND, - .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, + .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED, }, { diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index ce7ef64e228..fef4446a298 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -32,6 +32,8 @@ #include "wine/list.h" #include "mf_private.h" +#include "initguid.h" +#include "wmcodecdsp.h" WINE_DEFAULT_DEBUG_CHANNEL(mfplat); @@ -327,6 +329,7 @@ struct connection_context MF_TOPOLOGY_TYPE up_node_type; struct connection_context_type_enumerator up_types; struct connection_context_type_enumerator down_types; + BOOL is_video; }; static void connection_context_destroy(struct connection_context *context) @@ -339,6 +342,7 @@ static HRESULT connection_context_init(struct connection_context *context, IMFTo struct topology_branch *branch, MF_CONNECT_METHOD method, BOOL enumerate_source_types) { IMFMediaType *up_type; + GUID major; HRESULT hr; if (FAILED(hr = IMFTopologyNode_GetNodeType(branch->up.node, &context->up_node_type))) @@ -364,6 +368,10 @@ static HRESULT connection_context_init(struct connection_context *context, IMFTo hr = IMFMediaTypeHandler_GetCurrentMediaType(context->down_types.handler, &context->down_types.current); context->down_types.enumerate = (hr == MF_E_NOT_INITIALIZED || hr == MF_E_TRANSFORM_TYPE_NOT_SET); + if (FAILED(hr = IMFMediaType_GetMajorType(up_type, &major))) + goto failed; + context->is_video = IsEqualGUID(&major, &MFMediaType_Video); + return S_OK; failed: @@ -378,6 +386,39 @@ static void connection_context_init_down_type_enumeration(struct connection_cont IMFMediaTypeHandler_GetMediaTypeByIndex(context->down_types.handler, 0, &context->down_types.index0); } +static HRESULT clone_media_type(IMFMediaType *in_type, IMFMediaType **out_type) +{ + IMFMediaType *media_type; + HRESULT hr; + + if (FAILED(hr = MFCreateMediaType(&media_type))) + return hr; + + if (SUCCEEDED(hr = IMFMediaType_CopyAllItems(in_type, (IMFAttributes *)media_type))) + *out_type = media_type; + else + IMFMediaType_Release(media_type); + + return hr; +} + +static HRESULT clone_media_type_updated_from_upstream(IMFMediaType *in_type, IMFMediaType *up_type, + IMFMediaType **out_type) +{ + IMFMediaType *media_type; + HRESULT hr; + + if (FAILED(hr = clone_media_type(in_type, &media_type))) + return hr; + + if (SUCCEEDED(hr = update_media_type_from_upstream(media_type, up_type))) + *out_type = media_type; + else + IMFMediaType_Release(media_type); + + return hr; +} + static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD method_mask, struct topology_branch *branch, BOOL enumerate_source_types); static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method_mask, @@ -474,7 +515,12 @@ static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNEC } if (SUCCEEDED(hr)) + { hr = topology_branch_connect(topology, method, &down_branch, !down_type); + /* Failure to connect a converter must result in MF_E_TOPO_CODEC_NOT_FOUND */ + if (hr == MF_E_INVALIDMEDIATYPE) + hr = MF_E_TOPO_CODEC_NOT_FOUND; + } if (SUCCEEDED(hr)) hr = IMFTopology_AddNode(topology, node); if (SUCCEEDED(hr)) @@ -530,6 +576,162 @@ HRESULT topology_node_init_media_type(IMFTopologyNode *node, DWORD stream, BOOL return hr; } +static HRESULT create_transform_node(const GUID *class_id, IMFTopologyNode **node_out, + IMFTransform **transform_out) +{ + IMFTopologyNode *node = NULL; + IMFTransform *transform; + HRESULT hr; + + if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform))) + return hr; + + if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node)) + || FAILED(hr = IMFTopologyNode_SetGUID(node, &MF_TOPONODE_TRANSFORM_OBJECTID, class_id)) + || FAILED(hr = IMFTopologyNode_SetObject(node, (IUnknown *)transform))) + goto failed; + + *node_out = node; + *transform_out = transform; + + return S_OK; + +failed: + if (node) + IMFTopologyNode_Release(node); + IMFTransform_Release(transform); + + return hr; +} + +static HRESULT topology_branch_connect_converter_with_types(IMFTopology *topology, struct topology_branch *branch, + IMFMediaType *up_type, IMFMediaType *down_type, struct connection_context *context) +{ + IMFMediaTypeHandler *down_handler = context->down_types.handler, *up_handler = context->up_types.handler; + IMFMediaType *output_type, *media_type; + IMFTransform *transform; + IMFTopologyNode *node; + HRESULT hr, type_hr; + UINT i; + + TRACE("branch %s, up_type %s, down_type %s.\n", debugstr_topology_branch(branch), debugstr_media_subtype(up_type), + debugstr_media_subtype(down_type)); + + /* Changing the resampler GUID in Windows regedit does not prevent a CResamplerMediaObject + * being used, implying that MFTEnumEx() is not called for resamplers. */ + if (FAILED(hr = create_transform_node(&CLSID_CResamplerMediaObject, &node, &transform))) + return hr; + + if (FAILED(hr = IMFTransform_SetInputType(transform, 0, up_type, 0)) + || FAILED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(up_handler, up_type, NULL))) + { + hr = MF_E_TOPO_CODEC_NOT_FOUND; + goto done; + } + + /* MF_E_INVALIDMEDIATYPE is returned if the transform cannot be connected down. */ + hr = MF_E_INVALIDMEDIATYPE; + + for (i = 0; SUCCEEDED(type_hr = IMFTransform_GetOutputAvailableType(transform, 0, i, &output_type)); ++i) + { + DWORD flags; + + /* IsMediaTypeSupported() is not called until the type passes a sanity check of some kind. + * The below condition at least matches the test results. */ + if (down_type && (FAILED(IMFMediaType_IsEqual(output_type, down_type, &flags)) + || !(flags & MF_MEDIATYPE_EQUAL_MAJOR_TYPES) || !(flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES))) + { + IMFMediaType_Release(output_type); + continue; + } + + if (down_type) + { + /* It is not clear exactly how the type should be compiled, but attributes from the down type should + * have priority, and then we should probably add any from upstream which have not been set. */ + if (FAILED(clone_media_type_updated_from_upstream(down_type, output_type, &media_type))) + continue; + update_media_type_from_upstream(media_type, up_type); + } + else + { + if (FAILED(clone_media_type_updated_from_upstream(output_type, up_type, &media_type))) + continue; + } + + IMFMediaType_Release(output_type); + + if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(down_handler, media_type, NULL))) + { + if (context->up_types.enumerate) + hr = IMFMediaTypeHandler_SetCurrentMediaType(up_handler, up_type); + + if (SUCCEEDED(hr) && SUCCEEDED(hr = IMFTransform_SetOutputType(transform, 0, media_type, 0)) + && SUCCEEDED(hr = IMFTopologyNode_ConnectOutput(branch->up.node, branch->up.stream, node, 0)) + && SUCCEEDED(hr = IMFTopologyNode_ConnectOutput(node, 0, branch->down.node, branch->down.stream)) + && SUCCEEDED(hr = IMFTopology_AddNode(topology, node))) + { + TRACE("Connected converter %p, input %s, output %s.\n", transform, debugstr_media_subtype(up_type), + debugstr_media_subtype(media_type)); + } + } + IMFMediaType_Release(media_type); + + if (SUCCEEDED(hr)) + break; + } + + if (FAILED(type_hr) && type_hr != MF_E_NO_MORE_TYPES) + hr = type_hr; + +done: + if (node) + IMFTopologyNode_Release(node); + IMFTransform_Release(transform); + + return hr; +} + +static HRESULT topology_branch_connect_converter(IMFTopology *topology, + struct topology_branch *branch, struct connection_context *context) +{ + IMFMediaType *up_type, *down_type; + HRESULT hr; + GUID subtype; + + if (FAILED(hr = IMFMediaType_GetGUID(context->up_types.index0, &MF_MT_SUBTYPE, &subtype))) + return hr; + + if (!IsEqualGUID(&subtype, &MFAudioFormat_PCM) && !IsEqualGUID(&subtype, &MFAudioFormat_Float)) + return MF_E_TOPO_CODEC_NOT_FOUND; + + connection_context_init_down_type_enumeration(context); + + type_enumerator_reset(&context->up_types); + type_enumerator_reset(&context->down_types); + while (SUCCEEDED(hr = type_enumerator_get_next_media_type(&context->up_types, &up_type))) + { + /* TODO: sink types are tried in reverse order, and float at any index is preferred for audio, + * probably because it has a greater bit depth and dynamic range. All indices are always + * fetched, which is consistent with sorting audio types and starting at the last index + * without fetching the type count. */ + while (SUCCEEDED(hr = type_enumerator_get_next_media_type(&context->down_types, &down_type))) + { + hr = topology_branch_connect_converter_with_types(topology, branch, up_type, down_type, context); + if (down_type) + IMFMediaType_Release(down_type); + if (SUCCEEDED(hr)) + { + IMFMediaType_Release(up_type); + return hr; + } + } + IMFMediaType_Release(up_type); + } + + return hr; +} + static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method_mask, struct topology_branch *branch, IMFMediaType *up_type, struct connection_context *context) { @@ -562,8 +764,13 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_ME down_type = context->down_types.current ? context->down_types.current : context->down_types.index0; 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, context->up_types.enumerate, up_type, down_type); + { + if (context->is_video) + hr = topology_branch_connect_indirect(topology, MF_CONNECT_ALLOW_CONVERTER, + branch, context->up_types.enumerate, up_type, down_type); + else + hr = topology_branch_connect_converter(topology, branch, context); + } if (FAILED(hr) && (method & method_mask & MF_CONNECT_ALLOW_DECODER) == MF_CONNECT_ALLOW_DECODER) hr = topology_branch_connect_indirect(topology, MF_CONNECT_ALLOW_DECODER, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/mf/tests/topology.c | 22 ++++++------ dlls/mf/topology_loader.c | 76 +++++++++++++++++++++------------------ 2 files changed, 52 insertions(+), 46 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index 39e8ecdb401..fc3fc68aa21 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -2761,7 +2761,7 @@ static void test_topology_loader(void) .input_types = {&video_h264_1280}, .output_types = {&video_color_convert_1280_rgb32, &video_video_processor_1280_rgb32}, .sink_method = -1, .source_method = -1, .decoded_type = &video_nv12_1280, .expected_output_index = 1, .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, .converter_class = CLSID_CColorConvertDMO, - .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_EXPECT_SINK_ENUMERATED_TODO | LOADER_TODO, + .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_EXPECT_SINK_ENUMERATED, }, { /* H264 -> {DMO_RGB32, MF_RGB32} */ @@ -2776,28 +2776,28 @@ static void test_topology_loader(void) .decoded_type = &video_generic_yuv_1280, .expected_output_index = 1, .decoded_subtypes = {&MFVideoFormat_NV12, &MFVideoFormat_YUY2}, .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, .converter_class = CLSID_CColorConvertDMO, - .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_TODO_OUT_TYPE | LOADER_EXPECT_SINK_ENUMERATED_TODO, + .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_TODO_OUT_TYPE | LOADER_EXPECT_SINK_ENUMERATED, }, { /* H264 -> {RGB24, RGB32} */ .input_types = {&video_h264_1280}, .output_types = {&video_video_processor_1280_rgb24, &video_video_processor_1280_rgb32}, .sink_method = -1, .source_method = -1, .decoded_type = &video_nv12_1280, .expected_output_index = 1, .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, .converter_class = CLSID_CColorConvertDMO, - .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_TODO_OUT_TYPE | LOADER_EXPECT_SINK_ENUMERATED_TODO, + .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_TODO_OUT_TYPE | LOADER_EXPECT_SINK_ENUMERATED, }, { /* H264 -> {RGB24, RGB555} */ .input_types = {&video_h264_1280}, .output_types = {&video_video_processor_1280_rgb24, &video_video_processor_1280_rgb555}, .sink_method = -1, .source_method = -1, .decoded_type = &video_nv12_1280, .expected_output_index = 1, .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, .converter_class = CLSID_CColorConvertDMO, - .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_TODO_OUT_TYPE | LOADER_EXPECT_SINK_ENUMERATED_TODO, + .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_TODO_OUT_TYPE | LOADER_EXPECT_SINK_ENUMERATED, }, { /* H264 -> {RGB555, RGB24} */ .input_types = {&video_h264_1280}, .output_types = {&video_video_processor_1280_rgb555, &video_video_processor_1280_rgb24}, .sink_method = -1, .source_method = -1, .decoded_type = &video_nv12_1280, .expected_output_index = 1, .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, .converter_class = CLSID_CColorConvertDMO, - .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_TODO_OUT_TYPE | LOADER_EXPECT_SINK_ENUMERATED_TODO, + .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_TODO_OUT_TYPE | LOADER_EXPECT_SINK_ENUMERATED, }, { @@ -2805,7 +2805,7 @@ static void test_topology_loader(void) .input_types = {&video_h264_1280}, .output_types = {&video_color_convert_1280_rgb32}, .sink_method = -1, .source_method = -1, .decoded_type = &video_nv12_1280, .expected_result = MF_E_TOPO_CODEC_NOT_FOUND, .decoder_class = CLSID_CMSH264DecoderMFT, .converter_class = CLSID_CColorConvertDMO, - .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_EXPECT_SINK_ENUMERATED_TODO, + .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_EXPECT_SINK_ENUMERATED, }, { @@ -2814,7 +2814,7 @@ static void test_topology_loader(void) .decoded_type = &video_generic_yuv_1280, .expected_output_index = 1, .decoded_subtypes = {&MFVideoFormat_NV12, &MFVideoFormat_YUY2}, .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, .converter_class = CLSID_VideoProcessorMFT, - .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_SET_XVP_FOR_PLAYBACK | LOADER_EXPECT_SINK_ENUMERATED_TODO | LOADER_TODO, + .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_SET_XVP_FOR_PLAYBACK | LOADER_EXPECT_SINK_ENUMERATED, }, { /* H264 -> RGB32, resize, set XVP */ @@ -2829,21 +2829,21 @@ static void test_topology_loader(void) .input_types = {&video_h264_1280}, .output_types = {&video_color_convert_1280_rgb32}, .sink_method = -1, .source_method = -1, .mft_input_type = &video_color_convert_1280_rgb32, .mft_output_types = {&video_color_convert_1280_rgb32}, .expected_result = MF_E_TOPO_CODEC_NOT_FOUND, .decoder_class = CLSID_CMSH264DecoderMFT, - .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, + .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED, }, { /* H264 -> RGB32, Video Processor media type, add test MFT */ .input_types = {&video_h264_1280}, .output_types = {&video_video_processor_1280_rgb32}, .sink_method = -1, .source_method = -1, .mft_input_type = &video_video_processor_1280_rgb32, .mft_output_types = {&video_video_processor_1280_rgb32}, .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, .converter_class = CLSID_CColorConvertDMO, - .flags = LOADER_ADD_TEST_MFT | LOADER_TEST_MFT_EXPECT_CONVERTER | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, + .flags = LOADER_ADD_TEST_MFT | LOADER_TEST_MFT_EXPECT_CONVERTER | LOADER_EXPECT_MFT_INPUT_ENUMERATED, }, { /* H264 -> NV12, add test MFT */ .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = -1, .source_method = -1, .mft_input_type = &video_nv12_1280, .mft_output_types = {&video_nv12_1280}, .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, - .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, + .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED, }, }; @@ -3287,13 +3287,11 @@ todo_wine { hr = IMFTopologyNode_GetGUID(mft_node, &MF_TOPONODE_TRANSFORM_OBJECTID, &class_id); if (test->flags & LOADER_SET_XVP_FOR_PLAYBACK) { - todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "Got attribute hr %#lx.\n", hr); } else { ok(hr == S_OK, "Failed to get attribute, hr %#lx.\n", hr); - todo_wine_if(IsEqualGUID(&test->converter_class, &CLSID_CColorConvertDMO)) ok(IsEqualGUID(&class_id, &test->converter_class), "got MF_TOPONODE_TRANSFORM_OBJECTID %s.\n", debugstr_guid(&class_id)); } diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index fef4446a298..e499d84d4aa 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -329,6 +329,7 @@ struct connection_context MF_TOPOLOGY_TYPE up_node_type; struct connection_context_type_enumerator up_types; struct connection_context_type_enumerator down_types; + BOOL enable_xvp; BOOL is_video; }; @@ -353,6 +354,8 @@ static HRESULT connection_context_init(struct connection_context *context, IMFTo if (FAILED(hr = topology_node_get_type_handler(branch->down.node, branch->down.stream, FALSE, &context->down_types.handler))) goto failed; + IMFTopology_GetUINT32(topology, &MF_TOPOLOGY_ENABLE_XVP_FOR_PLAYBACK, (UINT32 *)&context->enable_xvp); + enumerate_source_types = context->up_node_type == MF_TOPOLOGY_SOURCESTREAM_NODE && enumerate_source_types; if (!(context->up_types.enumerate = enumerate_source_types)) { @@ -423,10 +426,9 @@ static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD struct topology_branch *branch, BOOL enumerate_source_types); static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method_mask, struct topology_branch *branch, IMFMediaType *up_type, struct connection_context *context); -static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNECT_METHOD method_mask, +static HRESULT topology_branch_connect_indirect(IMFTopology *topology, struct topology_branch *branch, BOOL enumerate, 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; @@ -435,7 +437,7 @@ static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNEC GUID category, guid; HRESULT hr; - TRACE("topology %p, method_mask %#x, branch %s, up_type %s, down_type %s.\n", topology, method_mask, + TRACE("topology %p, branch %s, up_type %s, down_type %s.\n", topology, debugstr_topology_branch(branch), debugstr_media_subtype(up_type), debugstr_media_subtype(down_type)); if (FAILED(hr = IMFMediaType_GetMajorType(up_type, &input_info.guidMajorType))) @@ -453,23 +455,17 @@ static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNEC } if (IsEqualGUID(&input_info.guidMajorType, &MFMediaType_Audio)) - category = decoder ? MFT_CATEGORY_AUDIO_DECODER : MFT_CATEGORY_AUDIO_EFFECT; + category = MFT_CATEGORY_AUDIO_DECODER; else if (IsEqualGUID(&input_info.guidMajorType, &MFMediaType_Video)) - category = decoder ? MFT_CATEGORY_VIDEO_DECODER : MFT_CATEGORY_VIDEO_PROCESSOR; + category = MFT_CATEGORY_VIDEO_DECODER; else return MF_E_INVALIDMEDIATYPE; if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node))) return hr; - if (!decoder) - method_mask = MF_CONNECT_DIRECT; - else - { - IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_DECODER, 1); - method_mask = MF_CONNECT_ALLOW_CONVERTER; - } + IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_DECODER, 1); - if (FAILED(hr = MFTEnumEx(category, MFT_ENUM_FLAG_ALL, &input_info, decoder ? NULL : &output_info, &activates, &count))) + if (FAILED(hr = MFTEnumEx(category, MFT_ENUM_FLAG_ALL, &input_info, NULL, &activates, &count))) return hr; for (i = 0, hr = MF_E_TRANSFORM_NOT_POSSIBLE_FOR_CURRENT_MEDIATYPE_COMBINATION; i < count; ++i) @@ -477,7 +473,7 @@ static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNEC struct topology_branch down_branch = {.up.node = node, .down = branch->down}; struct topology_branch up_branch = {.up = branch->up, .down.node = node}; struct connection_context up_context = {0}; - MF_CONNECT_METHOD method = method_mask; + MF_CONNECT_METHOD method = MF_CONNECT_ALLOW_CONVERTER; IMFMediaType *media_type; if (FAILED(IMFActivate_ActivateObject(activates[i], &IID_IMFTransform, (void **)&transform))) @@ -577,7 +573,7 @@ HRESULT topology_node_init_media_type(IMFTopologyNode *node, DWORD stream, BOOL } static HRESULT create_transform_node(const GUID *class_id, IMFTopologyNode **node_out, - IMFTransform **transform_out) + IMFTransform **transform_out, BOOL set_id) { IMFTopologyNode *node = NULL; IMFTransform *transform; @@ -587,7 +583,7 @@ static HRESULT create_transform_node(const GUID *class_id, IMFTopologyNode **nod return hr; if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node)) - || FAILED(hr = IMFTopologyNode_SetGUID(node, &MF_TOPONODE_TRANSFORM_OBJECTID, class_id)) + || (set_id && FAILED(hr = IMFTopologyNode_SetGUID(node, &MF_TOPONODE_TRANSFORM_OBJECTID, class_id))) || FAILED(hr = IMFTopologyNode_SetObject(node, (IUnknown *)transform))) goto failed; @@ -617,10 +613,25 @@ static HRESULT topology_branch_connect_converter_with_types(IMFTopology *topolog TRACE("branch %s, up_type %s, down_type %s.\n", debugstr_topology_branch(branch), debugstr_media_subtype(up_type), debugstr_media_subtype(down_type)); - /* Changing the resampler GUID in Windows regedit does not prevent a CResamplerMediaObject - * being used, implying that MFTEnumEx() is not called for resamplers. */ - if (FAILED(hr = create_transform_node(&CLSID_CResamplerMediaObject, &node, &transform))) - return hr; + if (!context->is_video) + { + /* Changing the resampler GUID in Windows regedit does not prevent a CResamplerMediaObject + * being used, implying that MFTEnumEx() is not called for resamplers. */ + if (FAILED(hr = create_transform_node(&CLSID_CResamplerMediaObject, &node, &transform, TRUE))) + return hr; + } + else + { + /* Changing the color converter GUID in Windows regedit does not prevent a CColorConvertDMO + * being used, implying that MFTEnumEx() is not called for converters. + * TODO: The same is not true for the VideoProcessorMFT, so MFTEnumEx() should be used when ENABLE_XVP is specified. */ + if (context->enable_xvp) + hr = create_transform_node(&CLSID_VideoProcessorMFT, &node, &transform, FALSE); + else + hr = create_transform_node(&CLSID_CColorConvertDMO, &node, &transform, TRUE); + if (FAILED(hr)) + return hr; + } if (FAILED(hr = IMFTransform_SetInputType(transform, 0, up_type, 0)) || FAILED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(up_handler, up_type, NULL))) @@ -697,13 +708,17 @@ static HRESULT topology_branch_connect_converter(IMFTopology *topology, { IMFMediaType *up_type, *down_type; HRESULT hr; - GUID subtype; - if (FAILED(hr = IMFMediaType_GetGUID(context->up_types.index0, &MF_MT_SUBTYPE, &subtype))) - return hr; + if (!context->is_video) + { + GUID subtype; - if (!IsEqualGUID(&subtype, &MFAudioFormat_PCM) && !IsEqualGUID(&subtype, &MFAudioFormat_Float)) - return MF_E_TOPO_CODEC_NOT_FOUND; + if (FAILED(hr = IMFMediaType_GetGUID(context->up_types.index0, &MF_MT_SUBTYPE, &subtype))) + return hr; + + if (!IsEqualGUID(&subtype, &MFAudioFormat_PCM) && !IsEqualGUID(&subtype, &MFAudioFormat_Float)) + return MF_E_TOPO_CODEC_NOT_FOUND; + } connection_context_init_down_type_enumeration(context); @@ -764,17 +779,10 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_ME down_type = context->down_types.current ? context->down_types.current : context->down_types.index0; if (FAILED(hr) && (method & method_mask & MF_CONNECT_ALLOW_CONVERTER) == MF_CONNECT_ALLOW_CONVERTER) - { - if (context->is_video) - hr = topology_branch_connect_indirect(topology, MF_CONNECT_ALLOW_CONVERTER, - branch, context->up_types.enumerate, up_type, down_type); - else - hr = topology_branch_connect_converter(topology, branch, context); - } + hr = topology_branch_connect_converter(topology, branch, context); 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, context->up_types.enumerate, up_type, down_type); + hr = topology_branch_connect_indirect(topology, branch, context->up_types.enumerate, up_type, down_type); done: return hr; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
From: Conor McCarthy <cmccarthy@codeweavers.com> To avoid test failure, decoder connection must also be switched to always use this pathway. The transform output type must not be set before connecting the down branch because types will not be enumerated if the output type is set, and the correct type should be set in topology_branch_connect_up_types(). --- dlls/mf/topology.c | 4 +- dlls/mf/topology_loader.c | 136 +++++++++++++++++++++++++------------- 2 files changed, 91 insertions(+), 49 deletions(-) diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 572d4d426d3..48ce941f2dd 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -1887,9 +1887,9 @@ static HRESULT WINAPI type_handler_IsMediaTypeSupported(IMFMediaTypeHandler *ifa if (handler->transform) { if (handler->output) - return IMFTransform_SetOutputType(handler->transform, handler->stream, in_type, MFT_SET_TYPE_TEST_ONLY); + return IMFTransform_SetOutputType(handler->transform, handler->stream, in_type, 0); else - return IMFTransform_SetInputType(handler->transform, handler->stream, in_type, MFT_SET_TYPE_TEST_ONLY); + return IMFTransform_SetInputType(handler->transform, handler->stream, in_type, 0); } if (FAILED(hr = IMFMediaTypeHandler_GetCurrentMediaType(iface, &type))) diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index e499d84d4aa..6e92e4675b0 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -389,6 +389,24 @@ static void connection_context_init_down_type_enumeration(struct connection_cont IMFMediaTypeHandler_GetMediaTypeByIndex(context->down_types.handler, 0, &context->down_types.index0); } +static HRESULT topology_branch_complete_connection(struct topology_branch *branch, struct connection_context *context, + IMFMediaType *up_type) +{ + HRESULT hr = S_OK; + + /* Current type is set for sources when enumerating, and always for transforms. */ + if (context->up_types.enumerate || context->up_node_type == MF_TOPOLOGY_TRANSFORM_NODE) + hr = IMFMediaTypeHandler_SetCurrentMediaType(context->up_types.handler, up_type); + + if (SUCCEEDED(hr)) + { + TRACE("Connected branch %s with up type %s.\n", debugstr_topology_branch(branch), debugstr_media_subtype(up_type)); + hr = IMFTopologyNode_ConnectOutput(branch->up.node, branch->up.stream, branch->down.node, branch->down.stream); + } + + return hr; +} + static HRESULT clone_media_type(IMFMediaType *in_type, IMFMediaType **out_type) { IMFMediaType *media_type; @@ -425,7 +443,7 @@ static HRESULT clone_media_type_updated_from_upstream(IMFMediaType *in_type, IMF static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD method_mask, struct topology_branch *branch, BOOL enumerate_source_types); static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method_mask, - struct topology_branch *branch, IMFMediaType *up_type, struct connection_context *context); + struct topology_branch *branch, struct connection_context *context); static HRESULT topology_branch_connect_indirect(IMFTopology *topology, struct topology_branch *branch, BOOL enumerate, IMFMediaType *up_type, IMFMediaType *down_type) { @@ -473,46 +491,24 @@ static HRESULT topology_branch_connect_indirect(IMFTopology *topology, struct topology_branch down_branch = {.up.node = node, .down = branch->down}; struct topology_branch up_branch = {.up = branch->up, .down.node = node}; struct connection_context up_context = {0}; - MF_CONNECT_METHOD method = MF_CONNECT_ALLOW_CONVERTER; - IMFMediaType *media_type; if (FAILED(IMFActivate_ActivateObject(activates[i], &IID_IMFTransform, (void **)&transform))) continue; IMFTopologyNode_SetObject(node, (IUnknown *)transform); + IMFTransform_Release(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); if (FAILED(hr = connection_context_init(&up_context, topology, &up_branch, MF_CONNECT_DIRECT, enumerate))) - { - IMFTransform_Release(transform); continue; - } - - hr = topology_branch_connect_down(topology, MF_CONNECT_DIRECT, &up_branch, up_type, &up_context); + hr = topology_branch_connect_down(topology, MF_CONNECT_DIRECT, &up_branch, &up_context); connection_context_destroy(&up_context); - if (down_type && SUCCEEDED(MFCreateMediaType(&media_type))) - { - if (SUCCEEDED(IMFMediaType_CopyAllItems(down_type, (IMFAttributes *)media_type)) - && SUCCEEDED(update_media_type_from_upstream(media_type, up_type)) - && SUCCEEDED(IMFTransform_SetOutputType(transform, 0, media_type, 0))) - method = MF_CONNECT_DIRECT; - IMFMediaType_Release(media_type); - } - IMFTransform_Release(transform); - - if (SUCCEEDED(hr) && method != MF_CONNECT_DIRECT - && SUCCEEDED(IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type))) - { - if (SUCCEEDED(update_media_type_from_upstream(media_type, up_type))) - IMFTransform_SetOutputType(transform, 0, media_type, 0); - IMFMediaType_Release(media_type); - } if (SUCCEEDED(hr)) { - hr = topology_branch_connect(topology, method, &down_branch, !down_type); + hr = topology_branch_connect(topology, MF_CONNECT_ALLOW_CONVERTER, &down_branch, FALSE); /* Failure to connect a converter must result in MF_E_TOPO_CODEC_NOT_FOUND */ if (hr == MF_E_INVALIDMEDIATYPE) hr = MF_E_TOPO_CODEC_NOT_FOUND; @@ -600,6 +596,30 @@ failed: return hr; } +static HRESULT topology_branch_connect_up_types(struct topology_branch *branch, struct connection_context *context) +{ + IMFMediaTypeHandler *down_handler = context->down_types.handler; + IMFMediaType *up_type; + HRESULT hr; + + /* The downstream current media type is not used here. Setting it in advance has no effect on the type used. + * TODO: unless MF_TOPONODE_LOCKED is set? + * Up and down transform media types are always set, even if they already match. + * If enumeration is disabled and upstream current type is null, the available type at index 0 is used. */ + + type_enumerator_reset(&context->up_types); + while (SUCCEEDED(hr = type_enumerator_get_next_media_type(&context->up_types, &up_type))) + { + if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(down_handler, up_type, NULL))) + hr = topology_branch_complete_connection(branch, context, up_type); + IMFMediaType_Release(up_type); + if (SUCCEEDED(hr)) + break; + } + + return hr; +} + static HRESULT topology_branch_connect_converter_with_types(IMFTopology *topology, struct topology_branch *branch, IMFMediaType *up_type, IMFMediaType *down_type, struct connection_context *context) { @@ -747,7 +767,7 @@ static HRESULT topology_branch_connect_converter(IMFTopology *topology, return hr; } -static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method_mask, +static HRESULT topology_branch_connect_independent_outtypes(IMFTopology *topology, MF_CONNECT_METHOD method_mask, struct topology_branch *branch, IMFMediaType *up_type, struct connection_context *context) { IMFMediaTypeHandler *down_handler = context->down_types.handler; @@ -798,7 +818,7 @@ static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, MF_CONNEC while (SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, index++, &type))) { - hr = topology_branch_connect_down(topology, method_mask, branch, type, context); + hr = topology_branch_connect_independent_outtypes(topology, method_mask, branch, type, context); if (SUCCEEDED(hr)) hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, type); IMFMediaType_Release(type); @@ -809,11 +829,43 @@ static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, MF_CONNEC return hr; } +static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method, + struct topology_branch *branch, struct connection_context *context) +{ + IMFMediaType *up_type; + HRESULT hr; + + TRACE("topology %p, branch %s.\n", topology, debugstr_topology_branch(branch)); + + if (SUCCEEDED(hr = topology_branch_connect_up_types(branch, context))) + return hr; + + if (!(method & MF_CONNECT_ALLOW_DECODER)) + return hr; + + if (SUCCEEDED(hr = topology_branch_connect_converter(topology, branch, context))) + return hr; + + if ((method & MF_CONNECT_ALLOW_DECODER) != MF_CONNECT_ALLOW_DECODER) + return hr; + + type_enumerator_reset(&context->up_types); + while (SUCCEEDED(hr = type_enumerator_get_next_media_type(&context->up_types, &up_type))) + { + hr = topology_branch_connect_indirect(topology, branch, context->up_types.enumerate, up_type, NULL); + IMFMediaType_Release(up_type); + if (SUCCEEDED(hr)) + return hr; + } + + return MF_E_TOPO_CODEC_NOT_FOUND; +} + static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD method_mask, struct topology_branch *branch, BOOL enumerate_source_types) { struct connection_context context = {0}; - UINT32 method; + UINT32 up_method, down_method; HRESULT hr; TRACE("topology %p, method_mask %#x, branch %s.\n", topology, method_mask, debugstr_topology_branch(branch)); @@ -821,12 +873,16 @@ static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD if (FAILED(hr = connection_context_init(&context, topology, branch, method_mask, enumerate_source_types))) return hr; - if (FAILED(IMFTopologyNode_GetUINT32(branch->up.node, &MF_TOPONODE_CONNECT_METHOD, &method))) - method = MF_CONNECT_DIRECT; + if (FAILED(IMFTopologyNode_GetUINT32(branch->up.node, &MF_TOPONODE_CONNECT_METHOD, &up_method))) + up_method = MF_CONNECT_DIRECT; + + if (FAILED(IMFTopologyNode_GetUINT32(branch->down.node, &MF_TOPONODE_CONNECT_METHOD, &down_method))) + down_method = MF_CONNECT_ALLOW_DECODER; + down_method &= method_mask; if (enumerate_source_types) { - if (method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES) + if (up_method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES) hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_DECODER, branch, &context); else { @@ -839,21 +895,7 @@ static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD } else { - IMFMediaType *up_type; - - type_enumerator_reset(&context.up_types); - while (SUCCEEDED(type_enumerator_get_next_media_type(&context.up_types, &up_type))) - { - hr = topology_branch_connect_down(topology, method_mask, branch, up_type, &context); - /* Upstream type is left unset only for an unenumerated media source. */ - if (SUCCEEDED(hr) && context.up_node_type != MF_TOPOLOGY_SOURCESTREAM_NODE) - hr = IMFMediaTypeHandler_SetCurrentMediaType(context.up_types.handler, up_type); - IMFMediaType_Release(up_type); - if (SUCCEEDED(hr)) - break; - } - if (hr == MF_E_INVALIDMEDIATYPE && context.up_types.enumerate) - hr = MF_E_NO_MORE_TYPES; + hr = topology_branch_connect_down(topology, down_method, branch, &context); } connection_context_destroy(&context); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
From: Conor McCarthy <cmccarthy@codeweavers.com> This method is used only for connecting source nodes down, and MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES is the only valid flag. --- dlls/mf/topology_loader.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 6e92e4675b0..6d30f529843 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -873,7 +873,8 @@ static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD if (FAILED(hr = connection_context_init(&context, topology, branch, method_mask, enumerate_source_types))) return hr; - if (FAILED(IMFTopologyNode_GetUINT32(branch->up.node, &MF_TOPONODE_CONNECT_METHOD, &up_method))) + if (context.up_node_type != MF_TOPOLOGY_SOURCESTREAM_NODE || !enumerate_source_types + || FAILED(IMFTopologyNode_GetUINT32(branch->up.node, &MF_TOPONODE_CONNECT_METHOD, &up_method))) up_method = MF_CONNECT_DIRECT; if (FAILED(IMFTopologyNode_GetUINT32(branch->down.node, &MF_TOPONODE_CONNECT_METHOD, &down_method))) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/mf/topology_loader.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 6d30f529843..79b9f3a0184 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -881,23 +881,10 @@ static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD down_method = MF_CONNECT_ALLOW_DECODER; down_method &= method_mask; - if (enumerate_source_types) - { - if (up_method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES) - hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_DECODER, branch, &context); - else - { - hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_DIRECT, branch, &context); - if (FAILED(hr)) - hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_CONVERTER, branch, &context); - if (FAILED(hr)) - hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_DECODER, branch, &context); - } - } + if (up_method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES) + hr = topology_branch_foreach_up_types(topology, down_method, branch, &context); else - { hr = topology_branch_connect_down(topology, down_method, branch, &context); - } connection_context_destroy(&context); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/mf/tests/topology.c | 2 +- dlls/mf/topology_loader.c | 80 +++++++++++++++++---------------------- 2 files changed, 35 insertions(+), 47 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index fc3fc68aa21..6c402e1e338 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -2651,7 +2651,7 @@ static void test_topology_loader(void) .input_types = {&audio_mp3_44100, &audio_pcm_44100}, .output_types = {&audio_pcm_44100}, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES, .expected_result = S_OK, .decoder_class = CLSID_CMP3DecMediaObject, - .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_SET_ENUMERATE_SOURCE_TYPES | LOADER_EXPECT_SINK_ENUMERATED_TODO, + .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_SET_ENUMERATE_SOURCE_TYPES | LOADER_EXPECT_SINK_ENUMERATED, }, { diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 79b9f3a0184..9572a2c5407 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -767,61 +767,49 @@ static HRESULT topology_branch_connect_converter(IMFTopology *topology, return hr; } -static HRESULT topology_branch_connect_independent_outtypes(IMFTopology *topology, MF_CONNECT_METHOD method_mask, - struct topology_branch *branch, IMFMediaType *up_type, struct connection_context *context) +static HRESULT topology_branch_connect_independent_outtypes(IMFTopology *topology, MF_CONNECT_METHOD method, + struct topology_branch *branch, struct connection_context *context) { - IMFMediaTypeHandler *down_handler = context->down_types.handler; - IMFMediaType *down_type; - MF_TOPOLOGY_TYPE type; - UINT32 method; + IMFMediaType *up_type, *down_type; HRESULT hr; - TRACE("topology %p, method_mask %#x, branch %s, up_type %s.\n", - topology, method_mask, debugstr_topology_branch(branch), debugstr_media_subtype(up_type)); - - if (FAILED(IMFTopologyNode_GetUINT32(branch->down.node, &MF_TOPONODE_CONNECT_METHOD, &method))) - method = MF_CONNECT_ALLOW_DECODER; + connection_context_init_down_type_enumeration(context); - if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(down_handler, up_type, NULL))) + type_enumerator_reset(&context->up_types); + type_enumerator_reset(&context->down_types); + while (SUCCEEDED(hr = type_enumerator_get_next_media_type(&context->up_types, &up_type))) { - TRACE("Connected branch %s with upstream type %s.\n", debugstr_topology_branch(branch), debugstr_media_subtype(up_type)); - - if (SUCCEEDED(IMFTopologyNode_GetNodeType(branch->down.node, &type)) && type == MF_TOPOLOGY_TRANSFORM_NODE - && FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(down_handler, up_type))) - WARN("Failed to set transform node media type, hr %#lx\n", hr); - - hr = IMFTopologyNode_ConnectOutput(branch->up.node, branch->up.stream, branch->down.node, branch->down.stream); - - goto done; - } - - connection_context_init_down_type_enumeration(context); - down_type = context->down_types.current ? context->down_types.current : context->down_types.index0; + if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(context->down_types.handler, up_type, NULL))) + { + hr = topology_branch_complete_connection(branch, context, up_type); + IMFMediaType_Release(up_type); + return hr; + } - if (FAILED(hr) && (method & method_mask & MF_CONNECT_ALLOW_CONVERTER) == MF_CONNECT_ALLOW_CONVERTER) - hr = topology_branch_connect_converter(topology, branch, context); + if (!(method & MF_CONNECT_ALLOW_DECODER)) + { + IMFMediaType_Release(up_type); + continue; + } - if (FAILED(hr) && (method & method_mask & MF_CONNECT_ALLOW_DECODER) == MF_CONNECT_ALLOW_DECODER) - hr = topology_branch_connect_indirect(topology, branch, context->up_types.enumerate, up_type, down_type); + while (SUCCEEDED(hr = type_enumerator_get_next_media_type(&context->down_types, &down_type))) + { + hr = topology_branch_connect_converter_with_types(topology, branch, up_type, down_type, context); + if (down_type) + IMFMediaType_Release(down_type); + if (SUCCEEDED(hr)) + break; + } -done: - return hr; -} + if (FAILED(hr) && (method & MF_CONNECT_ALLOW_DECODER) == MF_CONNECT_ALLOW_DECODER) + { + /* TODO: calls to IsMediaTypeSupported() on our test sink show that Windows enumerates down types + * here too, but independent out types is rarely used, and no issues are known to exist here. */ + hr = topology_branch_connect_indirect(topology, branch, context->up_types.enumerate, up_type, NULL); + } -static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, MF_CONNECT_METHOD method_mask, - struct topology_branch *branch, struct connection_context *context) -{ - IMFMediaTypeHandler *handler = context->up_types.handler; - IMFMediaType *type; - DWORD index = 0; - HRESULT hr; + IMFMediaType_Release(up_type); - while (SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, index++, &type))) - { - hr = topology_branch_connect_independent_outtypes(topology, method_mask, branch, type, context); - if (SUCCEEDED(hr)) - hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, type); - IMFMediaType_Release(type); if (SUCCEEDED(hr)) break; } @@ -882,7 +870,7 @@ static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD down_method &= method_mask; if (up_method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES) - hr = topology_branch_foreach_up_types(topology, down_method, branch, &context); + hr = topology_branch_connect_independent_outtypes(topology, down_method, branch, &context); else hr = topology_branch_connect_down(topology, down_method, branch, &context); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/mf/topology_loader.c | 70 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 9572a2c5407..857e395cc05 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -327,6 +327,7 @@ static void type_enumerator_release(struct connection_context_type_enumerator *e struct connection_context { MF_TOPOLOGY_TYPE up_node_type; + MF_TOPOLOGY_TYPE down_node_type; struct connection_context_type_enumerator up_types; struct connection_context_type_enumerator down_types; BOOL enable_xvp; @@ -348,6 +349,8 @@ static HRESULT connection_context_init(struct connection_context *context, IMFTo if (FAILED(hr = IMFTopologyNode_GetNodeType(branch->up.node, &context->up_node_type))) return hr; + if (FAILED(hr = IMFTopologyNode_GetNodeType(branch->down.node, &context->down_node_type))) + return hr; if (FAILED(hr = topology_node_get_type_handler(branch->up.node, branch->up.stream, TRUE, &context->up_types.handler))) return hr; @@ -817,6 +820,70 @@ static HRESULT topology_branch_connect_independent_outtypes(IMFTopology *topolog return hr; } +static HRESULT topology_branch_connect_indirect_video(IMFTopology *topology, struct topology_branch *branch, + struct connection_context *context) +{ + IMFMediaTypeHandler *down_handler = context->down_types.handler, *up_handler = context->up_types.handler; + IMFMediaType *up_type = NULL, *down_type = NULL; + HRESULT hr = MF_E_TOPO_CODEC_NOT_FOUND; + UINT i, j; + + TRACE("topology %p, branch %s.\n", topology, debugstr_topology_branch(branch)); + + if (context->down_node_type == MF_TOPOLOGY_OUTPUT_NODE) + { + /* output node media types are not enumerated */ + connection_context_init_down_type_enumeration(context); + down_type = context->down_types.current ? context->down_types.current : context->down_types.index0; + + if (!down_type) + goto done; + + for (j = 0; SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(up_handler, j, &up_type)); j++) + { + hr = topology_branch_connect_indirect(topology, branch, context->up_types.enumerate, up_type, down_type); + IMFMediaType_Release(up_type); + if (SUCCEEDED(hr)) + break; + } + } + else + { + /* media types are enumerated for transforms */ + for (i = 0; SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(down_handler, i, &down_type)); i++) + { + for (j = 0; SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(up_handler, j, &up_type)); j++) + { + hr = topology_branch_connect_indirect(topology, branch, context->up_types.enumerate, up_type, down_type); + IMFMediaType_Release(up_type); + if (SUCCEEDED(hr)) + break; + } + + IMFMediaType_Release(down_type); + + if (SUCCEEDED(hr)) + break; + } + } + + if (FAILED(hr)) + { + for (i = 0; SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(up_handler, i, &up_type)); i++) + { + hr = topology_branch_connect_indirect(topology, branch, context->up_types.enumerate, up_type, NULL); + IMFMediaType_Release(up_type); + if (SUCCEEDED(hr)) + break; + } + if (hr == MF_E_NO_MORE_TYPES) + hr = MF_E_TOPO_CODEC_NOT_FOUND; + } + +done: + return hr; +} + static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method, struct topology_branch *branch, struct connection_context *context) { @@ -837,6 +904,9 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_ME if ((method & MF_CONNECT_ALLOW_DECODER) != MF_CONNECT_ALLOW_DECODER) return hr; + if (context->is_video) + return topology_branch_connect_indirect_video(topology, branch, context); + type_enumerator_reset(&context->up_types); while (SUCCEEDED(hr = type_enumerator_get_next_media_type(&context->up_types, &up_type))) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/mf/topology_loader.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 857e395cc05..32e06cfbcff 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -513,7 +513,7 @@ static HRESULT topology_branch_connect_indirect(IMFTopology *topology, { hr = topology_branch_connect(topology, MF_CONNECT_ALLOW_CONVERTER, &down_branch, FALSE); /* Failure to connect a converter must result in MF_E_TOPO_CODEC_NOT_FOUND */ - if (hr == MF_E_INVALIDMEDIATYPE) + if (hr == MF_E_INVALIDMEDIATYPE || hr == MF_E_NO_MORE_TYPES) hr = MF_E_TOPO_CODEC_NOT_FOUND; } if (SUCCEEDED(hr)) @@ -605,6 +605,8 @@ static HRESULT topology_branch_connect_up_types(struct topology_branch *branch, IMFMediaType *up_type; HRESULT hr; + TRACE("branch %s.\n", debugstr_topology_branch(branch)); + /* The downstream current media type is not used here. Setting it in advance has no effect on the type used. * TODO: unless MF_TOPONODE_LOCKED is set? * Up and down transform media types are always set, even if they already match. @@ -820,6 +822,19 @@ static HRESULT topology_branch_connect_independent_outtypes(IMFTopology *topolog return hr; } +static HRESULT topology_branch_connect_indirect_audio(IMFTopology *topology, + struct topology_branch *branch, struct connection_context *context) +{ + IMFMediaType *down_type; + + TRACE("topology %p, branch %s.\n", topology, debugstr_topology_branch(branch)); + + connection_context_init_down_type_enumeration(context); + down_type = context->down_types.current ? context->down_types.current : context->down_types.index0; + + return topology_branch_connect_indirect(topology, branch, context->up_types.enumerate, context->up_types.index0, down_type); +} + static HRESULT topology_branch_connect_indirect_video(IMFTopology *topology, struct topology_branch *branch, struct connection_context *context) { @@ -887,11 +902,8 @@ done: static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method, struct topology_branch *branch, struct connection_context *context) { - IMFMediaType *up_type; HRESULT hr; - TRACE("topology %p, branch %s.\n", topology, debugstr_topology_branch(branch)); - if (SUCCEEDED(hr = topology_branch_connect_up_types(branch, context))) return hr; @@ -906,17 +918,8 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_ME if (context->is_video) return topology_branch_connect_indirect_video(topology, branch, context); - - type_enumerator_reset(&context->up_types); - while (SUCCEEDED(hr = type_enumerator_get_next_media_type(&context->up_types, &up_type))) - { - hr = topology_branch_connect_indirect(topology, branch, context->up_types.enumerate, up_type, NULL); - IMFMediaType_Release(up_type); - if (SUCCEEDED(hr)) - return hr; - } - - return MF_E_TOPO_CODEC_NOT_FOUND; + else + return topology_branch_connect_indirect_audio(topology, branch, context); } static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD method_mask, @@ -1212,7 +1215,7 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in TOPOID topoid; HRESULT hr = E_FAIL; - FIXME("iface %p, input_topology %p, ret_topology %p, current_topology %p stub!\n", + TRACE("iface %p, input_topology %p, ret_topology %p, current_topology %p.\n", iface, input_topology, ret_topology, current_topology); if (current_topology) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
participants (2)
-
Conor McCarthy -
Conor McCarthy (@cmccarthy)