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