[PATCH v7 0/6] MR10009: mf/topology_loader: Fix some topology loader test failures.
A followup MR will move converter connection behaviour closer to native, and maybe revise decoder connection a bit. -- v7: mf/topology_loader: Always enable enumeration when connecting a decoder down. mf/topology_loader: Enumerate up and down types if applicable when inserting a converter. mf/topology_loader: Create video converters via CoCreateInstance(). mf/topology_loader: Create audio resamplers via CoCreateInstance(). mf/topology_loader: Load the down connection method in topology_branch_connect(). mf/topology_loader: Introduce a helper to clone a media type and update it from upstream. https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/mf/topology_loader.c | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 05f999fcaec..8f7b108d693 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -265,6 +265,39 @@ static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMedi return hr; } +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_and_update_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, @@ -336,11 +369,9 @@ static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNEC IMFTopologyNode_SetGUID(node, &MF_TOPONODE_TRANSFORM_OBJECTID, &guid); hr = topology_branch_connect_down(topology, MF_CONNECT_DIRECT, &up_branch, up_type); - if (down_type && SUCCEEDED(MFCreateMediaType(&media_type))) + if (down_type && SUCCEEDED(clone_media_type_and_update_from_upstream(down_type, up_type, &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))) + if (SUCCEEDED(IMFTransform_SetOutputType(transform, 0, media_type, 0))) method = MF_CONNECT_DIRECT; IMFMediaType_Release(media_type); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/mf/topology_loader.c | 43 ++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 8f7b108d693..f68e17134ee 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -300,7 +300,7 @@ static HRESULT clone_media_type_and_update_from_upstream(IMFMediaType *in_type, 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, +static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method, struct topology_branch *branch, IMFMediaType *up_type); static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNECT_METHOD method_mask, struct topology_branch *branch, IMFMediaType *up_type, IMFMediaType *down_type) @@ -442,20 +442,16 @@ HRESULT topology_node_init_media_type(IMFTopologyNode *node, DWORD stream, BOOL return hr; } -static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method_mask, +static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method, struct topology_branch *branch, IMFMediaType *up_type) { IMFMediaTypeHandler *down_handler; IMFMediaType *down_type = NULL; - UINT32 method; DWORD flags; HRESULT hr; - TRACE("topology %p, method_mask %#x, branch %s, up_type %s.\n", - topology, method_mask, debugstr_topology_branch(branch), debugstr_media_type(up_type)); - - if (FAILED(IMFTopologyNode_GetUINT32(branch->down.node, &MF_TOPONODE_CONNECT_METHOD, &method))) - method = MF_CONNECT_ALLOW_DECODER; + TRACE("topology %p, method %#x, branch %s, up_type %s.\n", + topology, method, debugstr_topology_branch(branch), debugstr_media_type(up_type)); if (FAILED(hr = topology_node_get_type_handler(branch->down.node, branch->down.stream, FALSE, &down_handler))) return hr; @@ -481,11 +477,11 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_ME goto done; } - if (FAILED(hr) && (method & method_mask & MF_CONNECT_ALLOW_CONVERTER) == MF_CONNECT_ALLOW_CONVERTER) + if (FAILED(hr) && (method & MF_CONNECT_ALLOW_CONVERTER) == MF_CONNECT_ALLOW_CONVERTER) hr = topology_branch_connect_indirect(topology, MF_CONNECT_ALLOW_CONVERTER, branch, up_type, down_type); - if (FAILED(hr) && (method & method_mask & MF_CONNECT_ALLOW_DECODER) == MF_CONNECT_ALLOW_DECODER) + if (FAILED(hr) && (method & MF_CONNECT_ALLOW_DECODER) == MF_CONNECT_ALLOW_DECODER) hr = topology_branch_connect_indirect(topology, MF_CONNECT_ALLOW_DECODER, branch, up_type, down_type); @@ -497,7 +493,7 @@ done: return hr; } -static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, MF_CONNECT_METHOD method_mask, +static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, MF_CONNECT_METHOD method, struct topology_branch *branch) { IMFMediaTypeHandler *handler; @@ -510,7 +506,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, branch, type); if (SUCCEEDED(hr)) hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, type); IMFMediaType_Release(type); @@ -525,27 +521,32 @@ static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, MF_CONNEC static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD method_mask, struct topology_branch *branch, BOOL enumerate_source_types) { + UINT32 down_method; HRESULT hr; TRACE("topology %p, method_mask %#x, branch %s.\n", topology, method_mask, debugstr_topology_branch(branch)); + 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) { - UINT32 method; + UINT32 up_method; if (topology_node_get_type(branch->up.node) != MF_TOPOLOGY_SOURCESTREAM_NODE - || FAILED(IMFTopologyNode_GetUINT32(branch->up.node, &MF_TOPONODE_CONNECT_METHOD, &method))) - method = MF_CONNECT_DIRECT; + || FAILED(IMFTopologyNode_GetUINT32(branch->up.node, &MF_TOPONODE_CONNECT_METHOD, &up_method))) + up_method = MF_CONNECT_DIRECT; - if (method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES) - hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_DECODER, branch); + if (up_method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES) + hr = topology_branch_foreach_up_types(topology, down_method & MF_CONNECT_ALLOW_DECODER, branch); else { - hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_DIRECT, branch); + hr = topology_branch_foreach_up_types(topology, down_method & MF_CONNECT_DIRECT, branch); if (FAILED(hr)) - hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_CONVERTER, branch); + hr = topology_branch_foreach_up_types(topology, down_method & MF_CONNECT_ALLOW_CONVERTER, branch); if (FAILED(hr)) - hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_DECODER, branch); + hr = topology_branch_foreach_up_types(topology, down_method & MF_CONNECT_ALLOW_DECODER, branch); } } else @@ -558,7 +559,7 @@ static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD if (SUCCEEDED(hr = IMFMediaTypeHandler_GetCurrentMediaType(up_handler, &up_type)) || SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(up_handler, 0, &up_type))) { - hr = topology_branch_connect_down(topology, method_mask, branch, up_type); + hr = topology_branch_connect_down(topology, down_method, branch, up_type); IMFMediaType_Release(up_type); } IMFMediaTypeHandler_Release(up_handler); -- 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 | 2 +- dlls/mf/topology_loader.c | 144 +++++++++++++++++++++++++++++++++++++- 2 files changed, 143 insertions(+), 3 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index 63a8192aca3..46bc9d52d7a 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -2550,7 +2550,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 */ diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index f68e17134ee..4a73c8441d7 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); @@ -442,6 +444,145 @@ 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, BOOL set_id) +{ + 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)) + || (set_id && 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) +{ + IMFMediaTypeHandler *up_handler = NULL, *down_handler = NULL; + HRESULT hr, ret_hr = MF_E_TOPO_CODEC_NOT_FOUND; + IMFMediaType *output_type, *media_type; + IMFTransform *transform; + IMFTopologyNode *node; + GUID major; + UINT i; + + TRACE("branch %s, up_type %s, down_type %s.\n", debugstr_topology_branch(branch), debugstr_media_type(up_type), + debugstr_media_type(down_type)); + + if (FAILED(hr = IMFMediaType_GetMajorType(up_type, &major))) + return hr; + + if (IsEqualGUID(&major, &MFMediaType_Audio)) + { + /* 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 if (IsEqualGUID(&major, &MFMediaType_Video)) + { + return topology_branch_connect_indirect(topology, MF_CONNECT_ALLOW_CONVERTER, branch, up_type, down_type); + } + else + { + return MF_E_INVALIDMEDIATYPE; + } + + if (FAILED(hr = topology_node_get_type_handler(branch->up.node, branch->up.stream, TRUE, &up_handler))) + goto done; + if (FAILED(hr = topology_node_get_type_handler(branch->down.node, branch->down.stream, FALSE, &down_handler))) + goto done; + + if (FAILED(hr = IMFTransform_SetInputType(transform, 0, up_type, 0)) + || FAILED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(up_handler, up_type, NULL))) + { + goto done; + } + + for (i = 0; SUCCEEDED(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 probably attributes from the down + * type should have priority, and then we should add any from upstream which have not been set. */ + if (FAILED(clone_media_type_and_update_from_upstream(down_type, output_type, &media_type))) + continue; + update_media_type_from_upstream(media_type, up_type); + } + else + { + if (FAILED(clone_media_type_and_update_from_upstream(output_type, up_type, &media_type))) + continue; + } + + IMFMediaType_Release(output_type); + + /* Error code from this call seems to be the required return if we never get past here. */ + if (SUCCEEDED(ret_hr = IMFMediaTypeHandler_IsMediaTypeSupported(down_handler, media_type, NULL))) + { + hr = IMFMediaTypeHandler_SetCurrentMediaType(up_handler, up_type); + + ret_hr = MF_E_TOPO_CODEC_NOT_FOUND; + + if (SUCCEEDED(hr) && SUCCEEDED(hr = IMFTransform_SetOutputType(transform, 0, media_type, 0)) + && SUCCEEDED(ret_hr = IMFTopologyNode_ConnectOutput(branch->up.node, branch->up.stream, node, 0)) + && SUCCEEDED(ret_hr = IMFTopologyNode_ConnectOutput(node, 0, branch->down.node, branch->down.stream)) + && SUCCEEDED(ret_hr = IMFTopology_AddNode(topology, node))) + { + TRACE("Connected converter %p, input %s, output %s.\n", transform, debugstr_media_type(up_type), + debugstr_media_type(media_type)); + } + } + IMFMediaType_Release(media_type); + + if (SUCCEEDED(ret_hr)) + break; + } + + /* Return unexpected errors such as allocation failure. */ + if (FAILED(hr) && hr != MF_E_INVALIDMEDIATYPE && hr != MF_E_NO_MORE_TYPES) + ret_hr = hr; + +done: + if (down_handler) + IMFMediaTypeHandler_Release(down_handler); + if (up_handler) + IMFMediaTypeHandler_Release(up_handler); + if (node) + IMFTopologyNode_Release(node); + IMFTransform_Release(transform); + + return ret_hr; +} + static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method, struct topology_branch *branch, IMFMediaType *up_type) { @@ -478,8 +619,7 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_ME } if (FAILED(hr) && (method & MF_CONNECT_ALLOW_CONVERTER) == MF_CONNECT_ALLOW_CONVERTER) - hr = topology_branch_connect_indirect(topology, MF_CONNECT_ALLOW_CONVERTER, - branch, up_type, down_type); + hr = topology_branch_connect_converter_with_types(topology, branch, up_type, down_type); if (FAILED(hr) && (method & 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> Windows does not call MFTEnumEx to get a color converter. --- dlls/mf/tests/topology.c | 7 ++---- dlls/mf/topology_loader.c | 47 +++++++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index 46bc9d52d7a..f80bff61154 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -2699,7 +2699,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 +2830,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 */ @@ -3298,13 +3298,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)); } @@ -3427,7 +3425,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 4a73c8441d7..a78ee5ad8f9 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -304,10 +304,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, struct topology_branch *branch, IMFMediaType *up_type); -static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNECT_METHOD method_mask, +static HRESULT topology_branch_connect_decoder(IMFTopology *topology, struct topology_branch *branch, 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; @@ -316,7 +315,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_type(up_type), debugstr_media_type(down_type)); if (FAILED(hr = IMFMediaType_GetMajorType(up_type, &input_info.guidMajorType))) @@ -334,32 +333,26 @@ 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); - IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_MARKIN_HERE, 1); - IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_MARKOUT_HERE, 1); - method_mask = MF_CONNECT_ALLOW_CONVERTER; - } + IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_DECODER, 1); + IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_MARKIN_HERE, 1); + IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_MARKOUT_HERE, 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) { struct topology_branch down_branch = {.up.node = node, .down = branch->down}; struct topology_branch up_branch = {.up = branch->up, .down.node = node}; - 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))) @@ -388,7 +381,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_NO_MORE_TYPES) + hr = MF_E_TOPO_CODEC_NOT_FOUND; + } if (SUCCEEDED(hr)) hr = IMFTopology_AddNode(topology, node); if (SUCCEEDED(hr)) @@ -498,7 +496,19 @@ static HRESULT topology_branch_connect_converter_with_types(IMFTopology *topolog } else if (IsEqualGUID(&major, &MFMediaType_Video)) { - return topology_branch_connect_indirect(topology, MF_CONNECT_ALLOW_CONVERTER, branch, up_type, down_type); + UINT32 enable_xvp = 0; + + IMFTopology_GetUINT32(topology, &MF_TOPOLOGY_ENABLE_XVP_FOR_PLAYBACK, &enable_xvp); + + /* 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 (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; } else { @@ -622,8 +632,7 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_ME hr = topology_branch_connect_converter_with_types(topology, branch, up_type, down_type); if (FAILED(hr) && (method & MF_CONNECT_ALLOW_DECODER) == MF_CONNECT_ALLOW_DECODER) - hr = topology_branch_connect_indirect(topology, MF_CONNECT_ALLOW_DECODER, - branch, up_type, down_type); + hr = topology_branch_connect_decoder(topology, branch, up_type, down_type); done: if (down_type) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/mf/tests/topology.c | 36 ++++----- dlls/mf/topology_loader.c | 162 +++++++++++++++++++++++++++++++++----- 2 files changed, 159 insertions(+), 39 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index f80bff61154..17ad76ad559 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -2264,7 +2264,6 @@ enum loader_test_flags LOADER_TEST_MFT_EXPECT_CONVERTER = 0x2000, LOADER_EXPECT_MFT_OUTPUT_ENUMERATED = 0x4000, LOADER_EXPECT_MFT_INPUT_ENUMERATED = 0x8000, - LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO = 0x10000, LOADER_TODO_MFT_IN_TYPE = 0x20000, LOADER_TODO_MFT_OUT_TYPE = 0x40000, }; @@ -2624,21 +2623,21 @@ static void test_topology_loader(void) .input_types = {&audio_mp3_44100}, .output_types = {&audio_float_48000}, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = -1, .current_input = &audio_mp3_44100, .decoded_type = &audio_float_44100_no_ch, .expected_result = S_OK, .decoder_class = CLSID_CMP3DecMediaObject, .converter_class = CLSID_CResamplerMediaObject, - .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, }, { /* MP3 -> {float, PCM}, need both decoder and converter, no current output type */ .input_types = {&audio_mp3_44100}, .output_types = {&audio_float_48000, &audio_pcm_48000}, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = -1, .current_input = &audio_mp3_44100, .decoded_type = &audio_float_44100_stereo, .expected_result = S_OK, .decoder_class = CLSID_CMP3DecMediaObject, .converter_class = CLSID_CResamplerMediaObject, - .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, }, { /* MP3 -> {PCM, float}, need both decoder and converter, no current output type */ .input_types = {&audio_mp3_44100}, .output_types = {&audio_pcm_48000, &audio_float_48000}, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = -1, .current_input = &audio_mp3_44100, .decoded_type = &audio_float_44100_stereo, .expected_output_index = 1, .expected_result = S_OK, .decoder_class = CLSID_CMP3DecMediaObject, .converter_class = CLSID_CResamplerMediaObject, - .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, }, { @@ -2652,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, }, { @@ -2692,14 +2691,14 @@ 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 | LOADER_TODO_MFT_OUT_TYPE, }, { /* MP3 -> PCM, different enumerated bps, add incompatible test MFT, configure MFT */ .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, }, { @@ -2762,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} */ @@ -2777,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, }, { @@ -2806,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, }, { @@ -2815,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 */ @@ -2830,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_TODO_MFT_OUT_TYPE | LOADER_TEST_MFT_EXPECT_CONVERTER | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, + .flags = LOADER_ADD_TEST_MFT | LOADER_TODO_MFT_OUT_TYPE | 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_TODO_MFT_OUT_TYPE | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, + .flags = LOADER_ADD_TEST_MFT | LOADER_TODO_MFT_OUT_TYPE | LOADER_EXPECT_MFT_INPUT_ENUMERATED, }, }; @@ -3376,8 +3375,7 @@ todo_wine { if (test_transform) { - todo_wine_if(test->flags & LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO) - ok(test_transform->input_enum_complete == !!(test->flags & (LOADER_EXPECT_MFT_INPUT_ENUMERATED | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO)), + ok(test_transform->input_enum_complete == !!(test->flags & LOADER_EXPECT_MFT_INPUT_ENUMERATED), "got transform input_enum_complete %u\n", test_transform->input_enum_complete); todo_wine_if(test_transform->output_enum_complete && (test->flags & LOADER_TODO)) ok(test_transform->output_enum_complete == !!(test->flags & LOADER_EXPECT_MFT_OUTPUT_ENUMERATED), diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index a78ee5ad8f9..e343ba2083a 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -129,6 +129,8 @@ struct topology_branch { IMFTopologyNode *node; DWORD stream; + BOOL enumerate; + BOOL enum_initialised; } up, down; struct list entry; @@ -267,6 +269,87 @@ static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMedi return hr; } +struct type_enumerator +{ + IMFMediaTypeHandler *handler; + BOOL enumerate; + BOOL down; + BOOL have_current; + int i; +}; + +static void type_enumerator_init(struct type_enumerator *enumerator, IMFMediaTypeHandler *handler, BOOL enumerate, BOOL down) +{ + enumerator->handler = handler; + enumerator->enumerate = enumerate; + enumerator->down = down; + enumerator->have_current = FALSE; + enumerator->i = enumerate - 1; +} + +static void topology_branch_init_up_type_enumeration(struct topology_branch *branch, IMFMediaTypeHandler *up_handler) +{ + IMFMediaType *current; + HRESULT hr; + + if (branch->up.enum_initialised || branch->up.enumerate) + return; + + if (topology_node_get_type(branch->up.node) != MF_TOPOLOGY_SOURCESTREAM_NODE) + { + if (SUCCEEDED(hr = IMFMediaTypeHandler_GetCurrentMediaType(up_handler, ¤t))) + IMFMediaType_Release(current); + branch->up.enumerate = FAILED(hr); + } + branch->up.enum_initialised = TRUE; +} + +static void topology_branch_init_down_type_enumeration(struct topology_branch *branch, IMFMediaTypeHandler *down_handler) +{ + IMFMediaType *current; + HRESULT hr; + + if (branch->down.enum_initialised) + return; + + if (SUCCEEDED(hr = IMFMediaTypeHandler_GetCurrentMediaType(down_handler, ¤t))) + IMFMediaType_Release(current); + + branch->down.enumerate = hr == MF_E_NOT_INITIALIZED + /* One of the mf tests returns MF_E_TRANSFORM_TYPE_NOT_SET from a sink. */ + || (hr == MF_E_TRANSFORM_TYPE_NOT_SET && topology_node_get_type(branch->down.node) == MF_TOPOLOGY_TRANSFORM_NODE); + branch->down.enum_initialised = TRUE; +} + +static HRESULT type_enumerator_get_next_media_type(struct type_enumerator *enumerator, IMFMediaType **type) +{ + int i = enumerator->i++; + + if (i < 0) + { + if (SUCCEEDED(IMFMediaTypeHandler_GetCurrentMediaType(enumerator->handler, type))) + { + enumerator->have_current = TRUE; + return S_OK; + } + i = enumerator->i++; + } + + if (!i && enumerator->down && !enumerator->have_current && !enumerator->enumerate) + { + /* No current type and not enumerating. This occus if a sink returns E_FAIL when getting the current type. */ + *type = NULL; + return S_OK; + } + + /* If we are not enumerating and we have a current type, do not check index 0. */ + if ((!i && !enumerator->have_current) || enumerator->enumerate) + return IMFMediaTypeHandler_GetMediaTypeByIndex(enumerator->handler, i, type); + + /* return MF_E_INVALIDMEDIATYPE if not enumerating types */ + return MF_E_INVALIDMEDIATYPE; +} + static HRESULT clone_media_type(IMFMediaType *in_type, IMFMediaType **out_type) { IMFMediaType *media_type; @@ -381,12 +464,7 @@ static HRESULT topology_branch_connect_decoder(IMFTopology *topology, } 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_NO_MORE_TYPES) - hr = MF_E_TOPO_CODEC_NOT_FOUND; - } if (SUCCEEDED(hr)) hr = IMFTopology_AddNode(topology, node); if (SUCCEEDED(hr)) @@ -471,9 +549,8 @@ failed: } static HRESULT topology_branch_connect_converter_with_types(IMFTopology *topology, struct topology_branch *branch, - IMFMediaType *up_type, IMFMediaType *down_type) + IMFMediaType *up_type, IMFMediaType *down_type, IMFMediaTypeHandler *up_handler, IMFMediaTypeHandler *down_handler) { - IMFMediaTypeHandler *up_handler = NULL, *down_handler = NULL; HRESULT hr, ret_hr = MF_E_TOPO_CODEC_NOT_FOUND; IMFMediaType *output_type, *media_type; IMFTransform *transform; @@ -515,11 +592,6 @@ static HRESULT topology_branch_connect_converter_with_types(IMFTopology *topolog return MF_E_INVALIDMEDIATYPE; } - if (FAILED(hr = topology_node_get_type_handler(branch->up.node, branch->up.stream, TRUE, &up_handler))) - goto done; - if (FAILED(hr = topology_node_get_type_handler(branch->down.node, branch->down.stream, FALSE, &down_handler))) - goto done; - if (FAILED(hr = IMFTransform_SetInputType(transform, 0, up_type, 0)) || FAILED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(up_handler, up_type, NULL))) { @@ -582,10 +654,6 @@ static HRESULT topology_branch_connect_converter_with_types(IMFTopology *topolog ret_hr = hr; done: - if (down_handler) - IMFMediaTypeHandler_Release(down_handler); - if (up_handler) - IMFMediaTypeHandler_Release(up_handler); if (node) IMFTopologyNode_Release(node); IMFTransform_Release(transform); @@ -593,6 +661,58 @@ done: return ret_hr; } +static HRESULT topology_branch_connect_converter(IMFTopology *topology, struct topology_branch *branch) +{ + struct type_enumerator up_enumerator, down_enumerator; + IMFMediaTypeHandler *up_handler, *down_handler = NULL; + HRESULT hr, ret_hr = MF_E_TOPO_CODEC_NOT_FOUND; + IMFMediaType *up_type, *down_type; + + if (FAILED(hr = topology_node_get_type_handler(branch->up.node, branch->up.stream, TRUE, &up_handler))) + return hr; + if (FAILED(hr = topology_node_get_type_handler(branch->down.node, branch->down.stream, FALSE, &down_handler))) + goto done; + + topology_branch_init_up_type_enumeration(branch, up_handler); + topology_branch_init_down_type_enumeration(branch, down_handler); + + type_enumerator_init(&up_enumerator, up_handler, branch->up.enumerate, FALSE); + type_enumerator_init(&down_enumerator, down_handler, branch->down.enumerate, TRUE); + + while (SUCCEEDED(hr = type_enumerator_get_next_media_type(&up_enumerator, &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(&down_enumerator, &down_type))) + { + ret_hr = topology_branch_connect_converter_with_types(topology, branch, up_type, down_type, up_handler, down_handler); + + if (down_type) + IMFMediaType_Release(down_type); + + if (SUCCEEDED(ret_hr)) + { + IMFMediaType_Release(up_type); + goto done; + } + } + + IMFMediaType_Release(up_type); + } + + /* Return unexpected errors such as allocation failure. */ + if (FAILED(hr) && hr != MF_E_INVALIDMEDIATYPE && hr != MF_E_NO_MORE_TYPES) + ret_hr = hr; + +done: + if (down_handler) + IMFMediaTypeHandler_Release(down_handler); + IMFMediaTypeHandler_Release(up_handler); + return ret_hr; +} + static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_METHOD method, struct topology_branch *branch, IMFMediaType *up_type) { @@ -629,7 +749,7 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_ME } if (FAILED(hr) && (method & MF_CONNECT_ALLOW_CONVERTER) == MF_CONNECT_ALLOW_CONVERTER) - hr = topology_branch_connect_converter_with_types(topology, branch, up_type, down_type); + hr = topology_branch_connect_converter(topology, branch); if (FAILED(hr) && (method & MF_CONNECT_ALLOW_DECODER) == MF_CONNECT_ALLOW_DECODER) hr = topology_branch_connect_decoder(topology, branch, up_type, down_type); @@ -679,6 +799,8 @@ static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD down_method = MF_CONNECT_ALLOW_DECODER; down_method &= method_mask; + branch->up.enumerate = enumerate_source_types && topology_node_get_type(branch->up.node) == MF_TOPOLOGY_SOURCESTREAM_NODE; + if (enumerate_source_types) { UINT32 up_method; @@ -692,9 +814,9 @@ static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD else { hr = topology_branch_foreach_up_types(topology, down_method & MF_CONNECT_DIRECT, branch); - if (FAILED(hr)) - hr = topology_branch_foreach_up_types(topology, down_method & MF_CONNECT_ALLOW_CONVERTER, branch); - if (FAILED(hr)) + if (FAILED(hr) && (down_method & MF_CONNECT_ALLOW_CONVERTER)) + hr = topology_branch_connect_converter(topology, branch); + if (FAILED(hr) && (down_method & MF_CONNECT_ALLOW_DECODER) == MF_CONNECT_ALLOW_DECODER) hr = topology_branch_foreach_up_types(topology, down_method & MF_CONNECT_ALLOW_DECODER, branch); } } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
From: Conor McCarthy <cmccarthy@codeweavers.com> Enumeration should be enabled for transforms when they have no current type, but since that is not implemented, we can instead pass TRUE to topology_branch_connect(). --- dlls/mf/topology_loader.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index e343ba2083a..5c846bc0c18 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -436,35 +436,20 @@ static HRESULT topology_branch_connect_decoder(IMFTopology *topology, struct topology_branch down_branch = {.up.node = node, .down = branch->down}; struct topology_branch up_branch = {.up = branch->up, .down.node = node}; 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); hr = topology_branch_connect_down(topology, MF_CONNECT_DIRECT, &up_branch, up_type); - if (down_type && SUCCEEDED(clone_media_type_and_update_from_upstream(down_type, up_type, &media_type))) - { - if (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, method, &down_branch, TRUE); if (SUCCEEDED(hr)) hr = IMFTopology_AddNode(topology, node); if (SUCCEEDED(hr)) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
On Thu Apr 2 06:47:37 2026 +0000, Conor McCarthy wrote:
changed this line in [version 7 of the diff](/wine/wine/-/merge_requests/10009/diffs?diff_id=257049&start_sha=10241f5b6764224ddc7f03bc5939e0e62547a724#5f2d54b92889d121dabbd2b285d0737d1d1cd987_344_360) `topology_branch_is_input_type_supported` sets the down node type. The up node type is set here.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10009#note_134770
On Mon Mar 30 09:38:57 2026 +0000, Rémi Bernon wrote:
Aren't we basically reimplementing the `if (enumerate_source_types)` case here, when enumerate == TRUE? This should probably be using the existing code, fixing it if necessary, rather than adding another type enumeration logic. With everything being interdependent, it's difficult to make gradual changes without breaking tests or adding code which is similar to existing code. However, I found it goes much more smoothly if I start with indirect connections, which is basically the reverse of what I had before. I pushed a new set of commits.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10009#note_134771
On Thu Apr 2 06:57:06 2026 +0000, Conor McCarthy wrote:
With everything being interdependent, it's difficult to make gradual changes without breaking tests or adding code which is similar to existing code. However, I found it goes much more smoothly if I start with indirect connections, which is basically the reverse of what I had before. I pushed a new set of commits. Well I think we can fix things without duplicating the indirect connection logic. The code here even has a TODO indicating that the video processor is supposed to go through MFTEnumEx, while removing the logic that was doing exactly that. I understand that we might want to change some cases to use color converter instead, but that doesn't require duplicating the entire indirect connection logic.
The fact that native doesn't use MFTEnumEx for color converter / resampler could be interesting to note but IMO there's not much justification doing the same unless some application really depends on that. MFTEnumEx can already be instructed to select the color converter when needed through the enumerated category (it is under VIDEO_EFFECT while the video processor is under VIDEO_PROCESSOR). What the tests really indicate is that there actually is a deeper media type enumeration going on, probably to try harder to match types between upstream and downstream nodes, when we only currently try our luck optimistically. This can be added while keeping the rest of the logic mostly unchanged. The type_enumerator is also very difficult to understand, as it squeezes together all possible cases (when there's a current type and where there is not) when they should be made more obvious by keeping the cases clearly separate in the code. It is already done in `topology_branch_connect`, and could be done the same for downstream type enumeration. I've implemented this here: https://gitlab.winehq.org/rbernon/wine/-/commits/wip/topology-loader, fixing most of the tests. There's only a handful and harmless todo_wine remaining after these changes, a couple of successful connections when we should fail, and one failure that returns a different error. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10009#note_135274
This has been merged with !10585 and !10596 -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10009#note_136677
This merge request was closed by Rémi Bernon. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10009
participants (3)
-
Conor McCarthy -
Conor McCarthy (@cmccarthy) -
Rémi Bernon (@rbernon)