[PATCH v2 0/8] MR10791: mf/topology_loader: Implement optional nodes basic support.
Supersedes https://gitlab.winehq.org/wine/wine/-/merge_requests/10645 -- v2: mf/topology_loader: Force enumerate types when optional node method is set. mf/topology_loader: Try to insert optional nodes after resolving the surrounding branch. https://gitlab.winehq.org/wine/wine/-/merge_requests/10791
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/mf/tests/topology.c | 324 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 309 insertions(+), 15 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index 2270d7d6b0e..6c86d23fbe1 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -247,6 +247,8 @@ static void init_sink_node(IMFStreamSink *stream_sink, MF_CONNECT_METHOD method, } } +static LONG sequence_count; + struct test_transform { IMFTransform IMFTransform_iface; @@ -258,6 +260,8 @@ struct test_transform UINT input_count; IMFMediaType **input_types; IMFMediaType *input_type; + LONG set_input_sequence_id; + LONG set_output_sequence_id; UINT output_count; IMFMediaType **output_types; @@ -267,6 +271,7 @@ struct test_transform BOOL input_type_set; BOOL output_type_set; BOOL set_input_nulls_output; + BOOL validate_output_type; IDirect3DDeviceManager9 *expect_d3d9_device_manager; BOOL got_d3d9_device_manager; @@ -437,6 +442,9 @@ static HRESULT WINAPI test_transform_SetInputType(IMFTransform *iface, DWORD id, if (type) { + if (!transform->set_input_sequence_id) + transform->set_input_sequence_id = InterlockedIncrement(&sequence_count); + for (i = 0; i < transform->input_count; ++i) { if (IMFMediaType_Compare(transform->input_types[i], (IMFAttributes *)type, @@ -473,10 +481,25 @@ static HRESULT WINAPI test_transform_SetOutputType(IMFTransform *iface, DWORD id struct test_transform *transform = test_transform_from_IMFTransform(iface); if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; + if (type && transform->validate_output_type) + { + BOOL result; + UINT i; + for (i = 0; i < transform->output_count; ++i) + { + if (IMFMediaType_Compare(transform->output_types[i], (IMFAttributes *)type, + MF_ATTRIBUTES_MATCH_OUR_ITEMS, &result) == S_OK && result) + break; + } + if (i == transform->output_count) + return MF_E_INVALIDMEDIATYPE; + } if (transform->output_type) IMFMediaType_Release(transform->output_type); if ((transform->output_type = type)) { + if (!transform->set_output_sequence_id) + transform->set_output_sequence_id = InterlockedIncrement(&sequence_count); transform->output_type_set = TRUE; IMFMediaType_AddRef(transform->output_type); } @@ -1739,7 +1762,7 @@ struct test_handler ULONG media_types_count; IMFMediaType **media_types; BOOL enum_complete; - BOOL is_supported_called; + LONG is_supported_sequence_id; }; static struct test_handler *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler *iface) @@ -1777,7 +1800,8 @@ static HRESULT WINAPI test_handler_IsMediaTypeSupported(IMFMediaTypeHandler *ifa BOOL result; ULONG i; - impl->is_supported_called = TRUE; + if (!impl->is_supported_sequence_id) + impl->is_supported_sequence_id = InterlockedIncrement(&sequence_count); if (out_type) *out_type = NULL; @@ -2265,6 +2289,9 @@ enum loader_test_flags LOADER_TEST_MFT_EXPECT_CONVERTER = 0x2000, LOADER_EXPECT_MFT_OUTPUT_ENUMERATED = 0x4000, LOADER_EXPECT_MFT_INPUT_ENUMERATED = 0x8000, + LOADER_ADD_OPTIONAL_TEST_MFT_DOWNSTREAM = 0x10000, + LOADER_EXPECT_MFT_OUTPUT_ENUMERATED_TODO = 0x20000, + LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO = 0x40000, }; static void test_topology_loader(void) @@ -2473,6 +2500,8 @@ static void test_topology_loader(void) const media_type_desc *output_types[2]; const media_type_desc *mft_input_types[3]; const media_type_desc *mft_output_types[5]; + const media_type_desc *optional_mft_input_types[2]; /* one per node */ + const media_type_desc *optional_mft_output_type; const media_type_desc *current_input; const media_type_desc *mft_current_output; const media_type_desc *decoded_type; @@ -2482,6 +2511,8 @@ static void test_topology_loader(void) HRESULT expected_result; unsigned int mft_current_input_1based_index; unsigned int expected_output_index; + unsigned int optional_mft_count; + BOOL expect_optional_mft_rejected[2]; unsigned int flags; GUID decoder_class; GUID converter_class; @@ -2865,10 +2896,138 @@ static void test_topology_loader(void) .expected_result = S_OK, .flags = LOADER_ADD_TEST_MFT, }, + + { + /* H264 -> NV12, add optional test MFT and test MFT */ + .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = -1, .source_method = -1, + .mft_input_types = {&video_nv12_1280}, .mft_output_types = {&video_nv12_1280}, + .optional_mft_count = 1, + .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, + .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, + }, + { + /* H264 -> NV12, add two optional test MFTs and test MFT */ + .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = -1, .source_method = -1, + .mft_input_types = {&video_nv12_1280}, .mft_output_types = {&video_nv12_1280}, + .optional_mft_count = 2, + .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, + .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, + }, + { + /* H264 -> NV12, add unconnectable optional test MFT and test MFT */ + .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = -1, .source_method = -1, + .mft_input_types = {&video_nv12_1280}, .mft_output_types = {&video_nv12_1280}, + .optional_mft_input_types = {&video_yuy2_1280}, + .optional_mft_count = 1, .expect_optional_mft_rejected = {TRUE}, + .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, + .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, + }, + { + /* H264 -> NV12, add unconnectable optional test MFT, connectable optional test MFT and test MFT */ + .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = -1, .source_method = -1, + .mft_input_types = {&video_nv12_1280}, .mft_output_types = {&video_nv12_1280}, + .optional_mft_input_types = {&video_yuy2_1280, &video_nv12_1280}, + .optional_mft_count = 2, .expect_optional_mft_rejected = {TRUE, FALSE}, + .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, + .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, + }, + { + /* #60 H264 -> NV12, add connectable optional test MFT, unconnectable optional test MFT and test MFT */ + .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = -1, .source_method = -1, + .mft_input_types = {&video_nv12_1280}, .mft_output_types = {&video_nv12_1280}, + .optional_mft_input_types = {&video_nv12_1280, &video_yuy2_1280}, + .optional_mft_count = 2, .expect_optional_mft_rejected = {FALSE, TRUE}, + .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, + .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, + }, + { + /* H264 -> NV12, add two unconnectable optional test MFTs and test MFT */ + .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = -1, .source_method = -1, + .mft_input_types = {&video_nv12_1280}, .mft_output_types = {&video_nv12_1280}, + .optional_mft_input_types = {&video_yuy2_1280, &video_yuy2_1280}, + .optional_mft_count = 2, .expect_optional_mft_rejected = {TRUE, TRUE}, + .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, + .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, + }, + { + /* H264 -> NV12, add optional test MFT and test MFT, require test MFT input change for optional */ + .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = -1, .source_method = -1, + .mft_input_types = {&video_nv12_1280, &video_yuy2_1280}, .mft_output_types = {&video_nv12_1280}, + .optional_mft_output_type = &video_yuy2_1280, + .optional_mft_count = 1, + .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, + .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO, + }, + { + /* H264 -> NV12, add test MFT and optional test MFT */ + .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .mft_input_types = {&video_nv12_1280}, .mft_output_types = {&video_nv12_1280}, + .optional_mft_count = 1, + .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, + .flags = LOADER_ADD_TEST_MFT | LOADER_ADD_OPTIONAL_TEST_MFT_DOWNSTREAM | LOADER_EXPECT_MFT_INPUT_ENUMERATED, + }, + { + /* H264 -> NV12, add test MFT and optional test MFT, require sink input change for optional */ + .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280, &video_yuy2_1280}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .mft_input_types = {&video_nv12_1280}, .mft_output_types = {&video_nv12_1280}, + .optional_mft_output_type = &video_yuy2_1280, + .optional_mft_count = 1, + .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, + .flags = LOADER_ADD_TEST_MFT | LOADER_NO_CURRENT_OUTPUT | LOADER_ADD_OPTIONAL_TEST_MFT_DOWNSTREAM | LOADER_EXPECT_MFT_INPUT_ENUMERATED, + }, + { + /* H264 -> NV12, add test MFT and optional test MFT, require test MFT output change for optional */ + .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .mft_input_types = {&video_nv12_1280}, .mft_output_types = {&video_nv12_1280, &video_yuy2_1280}, + .optional_mft_input_types = {&video_yuy2_1280}, + .optional_mft_count = 1, + .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, + .flags = LOADER_ADD_TEST_MFT | LOADER_NO_CURRENT_OUTPUT | LOADER_ADD_OPTIONAL_TEST_MFT_DOWNSTREAM | LOADER_EXPECT_MFT_INPUT_ENUMERATED | LOADER_EXPECT_MFT_OUTPUT_ENUMERATED_TODO, + }, + { + /* H264 -> NV12, add test MFT and unconnectable optional test MFT, converter is not added for optional connection */ + .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = -1, .source_method = -1, + .mft_input_types = {&video_nv12_1280}, .mft_output_types = {&video_nv12_1280}, + .optional_mft_output_type = &video_yuy2_1280, + .optional_mft_count = 1, .expect_optional_mft_rejected = {TRUE}, + .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, + .flags = LOADER_ADD_TEST_MFT | LOADER_ADD_OPTIONAL_TEST_MFT_DOWNSTREAM | LOADER_EXPECT_MFT_INPUT_ENUMERATED, + }, + + { + /* PCM -> PCM, optional sink */ + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_44100}, .sink_method = MF_CONNECT_AS_OPTIONAL, .source_method = -1, + .expected_result = MF_E_TOPO_UNSUPPORTED, + .flags = LOADER_TODO, + }, + { + /* PCM -> PCM, optional source is ignored */ + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_44100}, .sink_method = -1, .source_method = MF_CONNECT_AS_OPTIONAL, + .expected_result = S_OK, + }, + { + /* H264 -> NV12, optional sink */ + .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = MF_CONNECT_AS_OPTIONAL | MF_CONNECT_ALLOW_DECODER, .source_method = -1, + .expected_result = MF_E_TOPO_UNSUPPORTED, .decoder_class = CLSID_CMSH264DecoderMFT, + .flags = LOADER_TODO, + }, + { + /* #70 H264 -> NV12, optional source is ignored */ + .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = -1, .source_method = MF_CONNECT_AS_OPTIONAL, + .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, + }, + { + /* H264 -> NV12, add test MFT, optional source is ignored */ + .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = -1, .source_method = MF_CONNECT_AS_OPTIONAL, + .mft_input_types = {&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, + }, }; IMFTopologyNode *src_node, *sink_node, *src_node2, *sink_node2, *mft_node; IMFSampleGrabberSinkCallback *grabber_callback = create_test_grabber_callback(); + TOPOID node_id, oldtopoid, newtopoid, optional_mft_node_id[2]; IMFMediaType *media_type, *input_types[2], *output_types[2]; struct test_stream_sink stream_sink = test_stream_sink; IMFTopology *topology, *topology2, *full_topology; @@ -2883,7 +3042,6 @@ static void test_topology_loader(void) IMFTopoLoader *loader; IUnknown *node_object; WORD node_count; - TOPOID node_id, oldtopoid, newtopoid; DWORD index; HRESULT hr; BOOL ret; @@ -3009,8 +3167,10 @@ static void test_topology_loader(void) for (i = 0; i < ARRAY_SIZE(loader_tests); ++i) { + struct test_transform *test_transform = NULL, *optional_transforms[2] = {0}; const struct loader_test *test = &loader_tests[i]; - struct test_transform *test_transform = NULL; + IMFTopologyNode *optional_mft_nodes[2] = {0}; + IMFMediaType *optional_mft_types[2] = {0}; IMFMediaType *mft_output_types[4] = {0}; IMFMediaType *mft_input_types[2] = {0}; @@ -3088,6 +3248,40 @@ static void test_topology_loader(void) test_transform_create(input_count, mft_input_types, output_count, mft_output_types, FALSE, &transform); test_transform = test_transform_from_IMFTransform(transform); IMFTransform_AddRef(transform); + + if (test->optional_mft_count) + { + const media_type_desc *optional_desc; + IMFTransform *optional_mft; + + for (j = 0; j < test->optional_mft_count; j++) + { + IMFMediaType **optional_input_types = &mft_input_types[0], **optional_output_types = &mft_input_types[0]; + + optional_desc = test->optional_mft_input_types[j] ? test->optional_mft_input_types[j] : test->optional_mft_output_type; + if (optional_desc) + { + hr = MFCreateMediaType(&optional_mft_types[j]); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + init_media_type(optional_mft_types[j], *optional_desc, -1); + if (test->optional_mft_input_types[j]) + optional_input_types = &optional_mft_types[j]; + else + optional_output_types = &optional_mft_types[j]; + } + + hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &optional_mft_nodes[j]); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_SetUINT32(optional_mft_nodes[j], &MF_TOPONODE_CONNECT_METHOD, MF_CONNECT_ALLOW_DECODER | MF_CONNECT_AS_OPTIONAL); + ok(hr == S_OK, "Failed to set connect method, hr %#lx.\n", hr); + + test_transform_create(1, optional_input_types, 1, optional_output_types, FALSE, &optional_mft); + hr = IMFTopologyNode_SetObject(optional_mft_nodes[j], (IUnknown *)optional_mft); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + optional_transforms[j] = test_transform_from_IMFTransform(optional_mft); + optional_transforms[j]->validate_output_type = !!test->optional_mft_output_type; + } + } } else { @@ -3126,14 +3320,56 @@ static void test_topology_loader(void) { test_transform->input_type_set = FALSE; test_transform->output_type_set = FALSE; + test_transform->set_input_sequence_id = 0; + test_transform->set_output_sequence_id = 0; } hr = IMFTopology_AddNode(topology, mft_node); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopologyNode_ConnectOutput(src_node, 0, mft_node, 0); - ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); - hr = IMFTopologyNode_ConnectOutput(mft_node, 0, sink_node, 0); - ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + if (test->optional_mft_count) + { + for (j = 0; j < test->optional_mft_count; j++) + { + hr = IMFTopology_AddNode(topology, optional_mft_nodes[j]); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + if (test->flags & LOADER_ADD_OPTIONAL_TEST_MFT_DOWNSTREAM) + { + hr = IMFTopologyNode_ConnectOutput(src_node, 0, mft_node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + hr = IMFTopologyNode_ConnectOutput(mft_node, 0, optional_mft_nodes[0], 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + hr = IMFTopologyNode_ConnectOutput(optional_mft_nodes[test->optional_mft_count - 1], 0, sink_node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + } + else + { + hr = IMFTopologyNode_ConnectOutput(src_node, 0, optional_mft_nodes[0], 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + hr = IMFTopologyNode_ConnectOutput(optional_mft_nodes[test->optional_mft_count - 1], 0, mft_node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + hr = IMFTopologyNode_ConnectOutput(mft_node, 0, sink_node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + } + if (optional_mft_nodes[1]) + { + hr = IMFTopologyNode_ConnectOutput(optional_mft_nodes[0], 0, optional_mft_nodes[1], 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + } + for (j = 0; j < test->optional_mft_count; j++) + { + hr = IMFTopologyNode_GetTopoNodeID(optional_mft_nodes[j], &optional_mft_node_id[j]); + ok(hr == S_OK, "Failed to get source node id, hr %#lx.\n", hr); + IMFTopologyNode_Release(optional_mft_nodes[j]); + } + } + else + { + hr = IMFTopologyNode_ConnectOutput(src_node, 0, mft_node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + hr = IMFTopologyNode_ConnectOutput(mft_node, 0, sink_node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + } IMFTopologyNode_Release(mft_node); } else @@ -3159,7 +3395,7 @@ static void test_topology_loader(void) ok(hr == S_OK, "Failed to get attribute count, hr %#lx.\n", hr); ok(!count, "Unexpected count %u.\n", count); - handler.is_supported_called = FALSE; + handler.is_supported_sequence_id = 0; if (test->flags & LOADER_SET_ENUMERATE_SOURCE_TYPES) IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, 1); @@ -3187,11 +3423,30 @@ static void test_topology_loader(void) } else if (test->expected_result == S_OK) { + BOOL expect_optional_rejected = FALSE; + IMFTopology_GetTopologyID(topology, &oldtopoid); IMFTopology_GetTopologyID(full_topology, &newtopoid); ok(oldtopoid == newtopoid, "Expected the same topology id. %I64u == %I64u\n", oldtopoid, newtopoid); ok(topology != full_topology, "Expected a different object for the resolved topology.\n"); + for (j = 0; j < test->optional_mft_count; ++j) + { + hr = IMFTopology_GetNodeByID(full_topology, optional_mft_node_id[j], &mft_node); + todo_wine_if(test->expect_optional_mft_rejected[j]) + ok(hr == (test->expect_optional_mft_rejected[j] ? MF_E_NOT_FOUND : S_OK), "Unexpected hr %#lx.\n", hr); + expect_optional_rejected |= test->expect_optional_mft_rejected[j]; + + if (hr == S_OK) + { + UINT32 method; + hr = IMFTopologyNode_GetUINT32(mft_node, &MF_TOPONODE_CONNECT_METHOD, &method); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(method == (MF_CONNECT_ALLOW_DECODER | MF_CONNECT_AS_OPTIONAL), "Unexpected method %#x\n", method); + IMFTopologyNode_Release(mft_node); + } + } + expected_count = 1 + !!(test->flags & LOADER_SET_ENUMERATE_SOURCE_TYPES) + !!(test->flags & LOADER_SET_XVP_FOR_PLAYBACK); hr = IMFTopology_GetCount(full_topology, &count); @@ -3203,9 +3458,10 @@ static void test_topology_loader(void) hr = IMFTopology_GetUINT32(full_topology, &MF_TOPOLOGY_RESOLUTION_STATUS, &value); todo_wine { ok(hr == S_OK, "Failed to get attribute, hr %#lx.\n", hr); - ok(value == MF_TOPOLOGY_RESOLUTION_SUCCEEDED, "Unexpected value %#x.\n", value); + ok(value == (expect_optional_rejected ? MF_OPTIONAL_NODE_REJECTED_MEDIA_TYPE : MF_TOPOLOGY_RESOLUTION_SUCCEEDED), + "Unexpected value %#x.\n", value); } - count = 2 + !!test_transform; + count = 2 + !!test_transform + test->optional_mft_count - test->expect_optional_mft_rejected[0] - test->expect_optional_mft_rejected[1]; if (!IsEqualGUID(&test->decoder_class, &GUID_NULL)) count++; if (!IsEqualGUID(&test->converter_class, &GUID_NULL)) @@ -3213,6 +3469,7 @@ todo_wine { hr = IMFTopology_GetNodeCount(full_topology, &node_count); ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); + todo_wine_if(expect_optional_rejected) ok(node_count == count, "Unexpected node count %u.\n", node_count); hr = IMFTopologyNode_GetTopoNodeID(src_node, &node_id); @@ -3238,7 +3495,37 @@ todo_wine { if (hr == S_OK) IMFMediaType_Release(media_type); - ok(handler.is_supported_called, "Sink input support not checked.\n"); + ok(!!handler.is_supported_sequence_id, "Sink input sequence id not set.\n"); + + if (optional_transforms[0]) + { + ok(!!optional_transforms[0]->set_input_sequence_id, "Optional transform input sequence id not set.\n"); + ok(!!test_transform->set_input_sequence_id, "Test transform input sequence id not set.\n"); + ok(!!test_transform->set_output_sequence_id, "Test transform output sequence id not set.\n"); + if (test->flags & LOADER_ADD_OPTIONAL_TEST_MFT_DOWNSTREAM) + { + todo_wine + ok(optional_transforms[0]->set_input_sequence_id > handler.is_supported_sequence_id, + "Optional transform input was not configured after the sink input.\n"); + } + else + { + todo_wine + ok(optional_transforms[0]->set_input_sequence_id > test_transform->set_input_sequence_id, + "Optional transform input was not configured after the non-optional one.\n"); + if (optional_transforms[0]->set_output_sequence_id) + { + /* Non-optional transform is connected to its downstream node after the optional + * node is inserted upstream, i.e. after each branch is connected, its optional + * nodes are inserted before the next branch is connected. */ + todo_wine + ok(optional_transforms[0]->set_output_sequence_id < test_transform->set_output_sequence_id, + "Optional transform output was not configured before the non-optional one.\n"); + } + } + for (j = 0; j < test->optional_mft_count; j++) + IMFTransform_Release(&optional_transforms[j]->IMFTransform_iface); + } if (!IsEqualGUID(&test->decoder_class, &GUID_NULL)) { @@ -3386,6 +3673,10 @@ todo_wine { ok(oldtopoid == newtopoid, "Expected the same topology id. %I64u == %I64u\n", oldtopoid, newtopoid); hr = IMFTopology_GetUINT32(topology2, &IID_IMFTopology, &value); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopology_GetNodeCount(topology2, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); + todo_wine_if(expect_optional_rejected) + ok(node_count == count, "Unexpected node count %u.\n", node_count); ref = IMFTopology_Release(topology2); ok(ref == 0, "Release returned %ld\n", ref); @@ -3407,10 +3698,11 @@ todo_wine { if (test_transform) { - ok(test_transform->input_enum_complete == !!(test->flags & LOADER_EXPECT_MFT_INPUT_ENUMERATED), + 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)), "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), + todo_wine_if((test->flags & LOADER_EXPECT_MFT_OUTPUT_ENUMERATED_TODO) || (test_transform->output_enum_complete && (test->flags & LOADER_TODO))) + ok(test_transform->output_enum_complete == !!(test->flags & (LOADER_EXPECT_MFT_OUTPUT_ENUMERATED | LOADER_EXPECT_MFT_OUTPUT_ENUMERATED_TODO)), "got transform output_enum_complete %u\n", test_transform->output_enum_complete); ok(test_transform->input_type_set == (test->expected_result != MF_E_TOPO_CODEC_NOT_FOUND), "Got transform input_type_set %u.\n", test_transform->input_type_set); @@ -3437,6 +3729,8 @@ todo_wine { ok(ref == 0, "Release returned %ld\n", ref); for (j = 0; j < ARRAY_SIZE(mft_input_types) && mft_input_types[j]; ++j) IMFMediaType_Release(mft_input_types[j]); + for (j = 0; j < ARRAY_SIZE(optional_mft_types) && optional_mft_types[j]; ++j) + IMFMediaType_Release(optional_mft_types[j]); for (j = 0; j < ARRAY_SIZE(mft_output_types) && mft_output_types[j]; ++j) IMFMediaType_Release(mft_output_types[j]); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10791
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/mf/topology_loader.c | 50 ++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 08557d354a8..3519f94bd30 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -101,27 +101,21 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface) return refcount; } -struct topoloader_context -{ - IMFTopology *input_topology; - IMFTopology *output_topology; -}; - -static HRESULT topology_loader_clone_node(struct topoloader_context *context, IMFTopologyNode *node, IMFTopologyNode **clone) +static HRESULT topology_clone_node(IMFTopology *topology, IMFTopologyNode *node, IMFTopologyNode **clone) { HRESULT hr; TOPOID id; if (FAILED(hr = IMFTopologyNode_GetTopoNodeID(node, &id))) return hr; - if (SUCCEEDED(hr = IMFTopology_GetNodeByID(context->output_topology, id, clone))) + if (SUCCEEDED(hr = IMFTopology_GetNodeByID(topology, id, clone))) return hr; if (FAILED(hr = MFCreateTopologyNode(topology_node_get_type(node), clone))) return hr; hr = IMFTopologyNode_CloneFrom(*clone, node); if (SUCCEEDED(hr)) - hr = IMFTopology_AddNode(context->output_topology, *clone); + hr = IMFTopology_AddNode(topology, *clone); if (FAILED(hr)) { @@ -224,14 +218,14 @@ static HRESULT topology_branch_create_indirect(struct topology_branch *branch, return hr; } -static HRESULT topology_branch_clone_nodes(struct topoloader_context *context, struct topology_branch *branch) +static HRESULT topology_branch_clone_nodes(IMFTopology *topology, struct topology_branch *branch) { IMFTopologyNode *up, *down; HRESULT hr; - if (FAILED(hr = topology_loader_clone_node(context, branch->up.node, &up))) + if (FAILED(hr = topology_clone_node(topology, branch->up.node, &up))) return hr; - if (FAILED(hr = topology_loader_clone_node(context, branch->down.node, &down))) + if (FAILED(hr = topology_clone_node(topology, branch->down.node, &down))) { IMFTopologyNode_Release(up); return hr; @@ -752,7 +746,7 @@ static HRESULT topology_branch_connect(IMFTopology *topology, enum connect_metho return hr; } -static HRESULT topology_loader_resolve_branches(struct topoloader_context *context, struct list *branches) +static HRESULT topology_loader_resolve_branches(IMFTopology *topology, struct list *branches) { enum connect_method method_mask = connect_method_from_mf(MF_CONNECT_ALLOW_DECODER); struct topology_branch *branch, *next; @@ -762,10 +756,10 @@ static HRESULT topology_loader_resolve_branches(struct topoloader_context *conte { list_remove(&branch->entry); - if (FAILED(hr = topology_branch_clone_nodes(context, branch))) + if (FAILED(hr = topology_branch_clone_nodes(topology, branch))) WARN("Failed to clone nodes for branch %s\n", debugstr_topology_branch(branch)); else - hr = topology_branch_connect(context->output_topology, method_mask, branch, NULL); + hr = topology_branch_connect(topology, method_mask, branch, NULL); topology_branch_destroy(branch); if (FAILED(hr)) @@ -840,7 +834,7 @@ static HRESULT topology_loader_create_copier(IMFTopologyNode *upstream_node, DWO return hr; } -static HRESULT topology_loader_connect_copier(struct topoloader_context *context, IMFTopologyNode *upstream_node, +static HRESULT topology_loader_connect_copier(IMFTopology *topology, IMFTopologyNode *upstream_node, DWORD upstream_output, IMFTopologyNode *downstream_node, DWORD downstream_input, IMFTransform *copier) { IMFTopologyNode *copier_node; @@ -850,7 +844,7 @@ static HRESULT topology_loader_connect_copier(struct topoloader_context *context return hr; IMFTopologyNode_SetObject(copier_node, (IUnknown *)copier); - IMFTopology_AddNode(context->output_topology, copier_node); + IMFTopology_AddNode(topology, copier_node); IMFTopologyNode_ConnectOutput(upstream_node, upstream_output, copier_node, 0); IMFTopologyNode_ConnectOutput(copier_node, 0, downstream_node, downstream_input); @@ -907,7 +901,7 @@ HRESULT stream_sink_get_device_manager(IMFStreamSink *stream_sink, IUnknown **de } /* Right now this should be used for output nodes only. */ -static HRESULT topology_loader_connect_d3d_aware_sink(struct topoloader_context *context, +static HRESULT topology_loader_connect_d3d_aware_sink(IMFTopology *topology, IMFTopologyNode *node, MFTOPOLOGY_DXVA_MODE dxva_mode) { IMFTopologyNode *upstream_node; @@ -940,7 +934,7 @@ static HRESULT topology_loader_connect_d3d_aware_sink(struct topoloader_context if (needs_copier && SUCCEEDED(hr = topology_loader_create_copier(upstream_node, upstream_output, node, 0, &copier))) { - hr = topology_loader_connect_copier(context, upstream_node, upstream_output, node, 0, copier); + hr = topology_loader_connect_copier(topology, upstream_node, upstream_output, node, 0, copier); IMFTransform_Release(copier); } @@ -958,21 +952,21 @@ static HRESULT topology_loader_connect_d3d_aware_sink(struct topoloader_context return hr; } -static void topology_loader_resolve_complete(struct topoloader_context *context) +static void topology_loader_resolve_complete(IMFTopology *topology) { MFTOPOLOGY_DXVA_MODE dxva_mode; IMFTopologyNode *node; WORD i, node_count; HRESULT hr; - IMFTopology_GetNodeCount(context->output_topology, &node_count); + IMFTopology_GetNodeCount(topology, &node_count); - if (FAILED(IMFTopology_GetUINT32(context->input_topology, &MF_TOPOLOGY_DXVA_MODE, (UINT32 *)&dxva_mode))) + if (FAILED(IMFTopology_GetUINT32(topology, &MF_TOPOLOGY_DXVA_MODE, (UINT32 *)&dxva_mode))) dxva_mode = 0; for (i = 0; i < node_count; ++i) { - if (SUCCEEDED(IMFTopology_GetNode(context->output_topology, i, &node))) + if (SUCCEEDED(IMFTopology_GetNode(topology, i, &node))) { switch (topology_node_get_type(node)) { @@ -981,7 +975,7 @@ static void topology_loader_resolve_complete(struct topoloader_context *context) if (FAILED(IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAMID, NULL))) IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_STREAMID, 0); - if (FAILED(hr = topology_loader_connect_d3d_aware_sink(context, node, dxva_mode))) + if (FAILED(hr = topology_loader_connect_d3d_aware_sink(topology, node, dxva_mode))) WARN("Failed to connect D3D-aware input, hr %#lx.\n", hr); break; case MF_TOPOLOGY_SOURCESTREAM_NODE: @@ -1002,7 +996,6 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in IMFTopology **ret_topology, IMFTopology *current_topology) { struct list branches = LIST_INIT(branches); - struct topoloader_context context = { 0 }; struct topology_branch *branch, *next; IMFTopology *output_topology; IMFTopologyNode *node; @@ -1056,9 +1049,6 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in IMFTopology_CopyAllItems(input_topology, (IMFAttributes *)output_topology); - context.input_topology = input_topology; - context.output_topology = output_topology; - for (i = 0; SUCCEEDED(IMFTopology_GetNode(input_topology, i, &node)); i++) { hr = topology_node_list_branches(node, &branches); @@ -1070,7 +1060,7 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in hr = MF_E_TOPO_UNSUPPORTED; while (SUCCEEDED(hr) && !list_empty(&branches)) - hr = topology_loader_resolve_branches(&context, &branches); + hr = topology_loader_resolve_branches(output_topology, &branches); LIST_FOR_EACH_ENTRY_SAFE(branch, next, &branches, struct topology_branch, entry) { @@ -1083,7 +1073,7 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in IMFTopology_Release(output_topology); else { - topology_loader_resolve_complete(&context); + topology_loader_resolve_complete(output_topology); *ret_topology = output_topology; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10791
From: Rémi Bernon <rbernon@codeweavers.com> Enumerating source nodes while at it. --- dlls/mf/topology_loader.c | 84 +++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 3519f94bd30..2cd798f9d16 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -992,62 +992,76 @@ static void topology_loader_resolve_complete(IMFTopology *topology) } } -static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, - IMFTopology **ret_topology, IMFTopology *current_topology) +static HRESULT clone_topology(IMFTopology *input_topology, IMFCollection *sources, + IMFTopology **output_topology) { - struct list branches = LIST_INIT(branches); - struct topology_branch *branch, *next; - IMFTopology *output_topology; + BOOL has_source = FALSE; IMFTopologyNode *node; - unsigned short i = 0; IMFStreamSink *sink; + HRESULT hr = S_OK; IUnknown *object; TOPOID topoid; - HRESULT hr = E_FAIL; - - FIXME("iface %p, input_topology %p, ret_topology %p, current_topology %p stub!\n", - iface, input_topology, ret_topology, current_topology); - if (current_topology) - FIXME("Current topology instance is ignored.\n"); - - /* Basic sanity checks for input topology: + IMFTopology_GetTopologyID(input_topology, &topoid); + if (FAILED(hr = create_topology(topoid, output_topology))) + return hr; + hr = IMFTopology_CopyAllItems(input_topology, (IMFAttributes *)*output_topology); - - source nodes must have stream descriptor set; - - sink nodes must be resolved to stream sink objects; - */ - while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node))) + for (UINT i = 0; SUCCEEDED(hr) && SUCCEEDED(IMFTopology_GetNode(input_topology, i, &node)); i++) { switch (topology_node_get_type(node)) { case MF_TOPOLOGY_OUTPUT_NODE: - if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object))) - { - /* Sinks must be bound beforehand. */ - if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&sink))) - hr = MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; - else if (sink) - IMFStreamSink_Release(sink); - IUnknown_Release(object); - } + if (FAILED(hr = IMFTopologyNode_GetObject(node, &object))) + break; + if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&sink))) + hr = MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; + else + IMFStreamSink_Release(sink); + IUnknown_Release(object); break; case MF_TOPOLOGY_SOURCESTREAM_NODE: - hr = IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL); + if (SUCCEEDED(hr = IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL))) + hr = IMFCollection_AddElement(sources, (IUnknown *)node); + has_source = TRUE; break; default: - ; + break; } IMFTopologyNode_Release(node); - if (FAILED(hr)) - return hr; } - IMFTopology_GetTopologyID(input_topology, &topoid); - if (FAILED(hr = create_topology(topoid, &output_topology))) + if (SUCCEEDED(hr) && !has_source) + hr = MF_E_TOPO_UNSUPPORTED; + if (SUCCEEDED(hr)) return hr; - IMFTopology_CopyAllItems(input_topology, (IMFAttributes *)output_topology); + IMFTopology_Release(*output_topology); + return hr; +} + +static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, + IMFTopology **ret_topology, IMFTopology *current_topology) +{ + struct list branches = LIST_INIT(branches); + struct topology_branch *branch, *next; + IMFTopology *output_topology; + IMFTopologyNode *node; + IMFCollection *nodes; + unsigned short i = 0; + HRESULT hr = E_FAIL; + + TRACE("iface %p, input_topology %p, ret_topology %p, current_topology %p.\n", + iface, input_topology, ret_topology, current_topology); + + if (current_topology) + FIXME("Current topology instance is ignored.\n"); + + if (FAILED(hr = MFCreateCollection(&nodes))) + return hr; + if (FAILED(hr = clone_topology(input_topology, nodes, &output_topology))) + goto done; for (i = 0; SUCCEEDED(IMFTopology_GetNode(input_topology, i, &node)); i++) { @@ -1077,6 +1091,8 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in *ret_topology = output_topology; } +done: + IMFCollection_Release(nodes); return hr; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10791
From: Rémi Bernon <rbernon@codeweavers.com> Leaving the original branch untouched, so we can still use its nodes to further iterate over desired and optional connections. --- dlls/mf/topology_loader.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 2cd798f9d16..17b1a6ebe93 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -218,23 +218,23 @@ static HRESULT topology_branch_create_indirect(struct topology_branch *branch, return hr; } -static HRESULT topology_branch_clone_nodes(IMFTopology *topology, struct topology_branch *branch) +static HRESULT topology_branch_create_cloned(IMFTopology *topology, IMFTopologyNode *up_node, DWORD up_stream, + IMFTopologyNode *down_node, DWORD down_stream, struct topology_branch **out) { IMFTopologyNode *up, *down; HRESULT hr; - if (FAILED(hr = topology_clone_node(topology, branch->up.node, &up))) + if (FAILED(hr = topology_clone_node(topology, up_node, &up))) return hr; - if (FAILED(hr = topology_clone_node(topology, branch->down.node, &down))) + if (FAILED(hr = topology_clone_node(topology, down_node, &down))) { IMFTopologyNode_Release(up); return hr; } - IMFTopologyNode_Release(branch->up.node); - IMFTopologyNode_Release(branch->down.node); - branch->up.node = up; - branch->down.node = down; + hr = topology_branch_create(up, up_stream, down, down_stream, out); + IMFTopologyNode_Release(up); + IMFTopologyNode_Release(down); return hr; } @@ -749,17 +749,19 @@ static HRESULT topology_branch_connect(IMFTopology *topology, enum connect_metho static HRESULT topology_loader_resolve_branches(IMFTopology *topology, struct list *branches) { enum connect_method method_mask = connect_method_from_mf(MF_CONNECT_ALLOW_DECODER); - struct topology_branch *branch, *next; + struct topology_branch *branch, *cloned, *next; HRESULT hr = S_OK; LIST_FOR_EACH_ENTRY_SAFE(branch, next, branches, struct topology_branch, entry) { list_remove(&branch->entry); - if (FAILED(hr = topology_branch_clone_nodes(topology, branch))) - WARN("Failed to clone nodes for branch %s\n", debugstr_topology_branch(branch)); - else - hr = topology_branch_connect(topology, method_mask, branch, NULL); + if (SUCCEEDED(hr = topology_branch_create_cloned(topology, branch->up.node, branch->up.stream, + branch->down.node, branch->down.stream, &cloned))) + { + hr = topology_branch_connect(topology, method_mask, cloned, NULL); + topology_branch_destroy(cloned); + } topology_branch_destroy(branch); if (FAILED(hr)) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10791
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/mf/tests/topology.c | 1 - dlls/mf/topology_loader.c | 84 +++++++++++++++------------------------ 2 files changed, 31 insertions(+), 54 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index 6c86d23fbe1..0a268054a46 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -3518,7 +3518,6 @@ todo_wine { /* Non-optional transform is connected to its downstream node after the optional * node is inserted upstream, i.e. after each branch is connected, its optional * nodes are inserted before the next branch is connected. */ - todo_wine ok(optional_transforms[0]->set_output_sequence_id < test_transform->set_output_sequence_id, "Optional transform output was not configured before the non-optional one.\n"); } diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 17b1a6ebe93..1dd050685a4 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -140,8 +140,6 @@ struct topology_branch DWORD stream; IMFMediaTypeHandler *handler; } up, down; - - struct list entry; }; static const char *debugstr_topology_type(MF_TOPOLOGY_TYPE type) @@ -218,6 +216,21 @@ static HRESULT topology_branch_create_indirect(struct topology_branch *branch, return hr; } +/* create a branch for a given node output stream, skipping any optional nodes */ +static HRESULT topology_branch_create_for_output(IMFTopologyNode *node, DWORD stream, struct topology_branch **out) +{ + IMFTopologyNode *down_node; + DWORD down_stream; + HRESULT hr; + + if (FAILED(hr = IMFTopologyNode_GetOutput(node, stream, &down_node, &down_stream))) + return hr; + hr = topology_branch_create(node, stream, down_node, down_stream, out); + IMFTopologyNode_Release(down_node); + + return hr; +} + static HRESULT topology_branch_create_cloned(IMFTopology *topology, IMFTopologyNode *up_node, DWORD up_stream, IMFTopologyNode *down_node, DWORD down_stream, struct topology_branch **out) { @@ -238,28 +251,6 @@ static HRESULT topology_branch_create_cloned(IMFTopology *topology, IMFTopologyN return hr; } -static HRESULT topology_node_list_branches(IMFTopologyNode *node, struct list *branches) -{ - struct topology_branch *branch; - DWORD i, count, down_stream; - IMFTopologyNode *down_node; - HRESULT hr; - - hr = IMFTopologyNode_GetOutputCount(node, &count); - for (i = 0; SUCCEEDED(hr) && i < count; ++i) - { - if (FAILED(IMFTopologyNode_GetOutput(node, i, &down_node, &down_stream))) - continue; - - if (SUCCEEDED(hr = topology_branch_create(node, i, down_node, down_stream, &branch))) - list_add_tail(branches, &branch->entry); - - IMFTopologyNode_Release(down_node); - } - - return hr; -} - static void media_type_try_copy_attr(IMFMediaType *dst, IMFMediaType *src, const GUID *attr, HRESULT *hr) { PROPVARIANT value; @@ -746,28 +737,32 @@ static HRESULT topology_branch_connect(IMFTopology *topology, enum connect_metho return hr; } -static HRESULT topology_loader_resolve_branches(IMFTopology *topology, struct list *branches) +static HRESULT topology_loader_resolve_node(IMFTopology *topology, IMFTopologyNode *node) { enum connect_method method_mask = connect_method_from_mf(MF_CONNECT_ALLOW_DECODER); - struct topology_branch *branch, *cloned, *next; - HRESULT hr = S_OK; + struct topology_branch *branch, *cloned; + DWORD output_count; + HRESULT hr; - LIST_FOR_EACH_ENTRY_SAFE(branch, next, branches, struct topology_branch, entry) - { - list_remove(&branch->entry); + TRACE("topology %p, node %p\n", topology, node); + + if (SUCCEEDED(hr = IMFTopologyNode_GetOutputCount(node, &output_count)) && !output_count) + return topology_node_get_type(node) == MF_TOPOLOGY_OUTPUT_NODE ? S_OK : MF_E_TOPO_UNSUPPORTED; + for (UINT i = 0; SUCCEEDED(hr) && SUCCEEDED(topology_branch_create_for_output(node, i, &branch)); ++i) + { if (SUCCEEDED(hr = topology_branch_create_cloned(topology, branch->up.node, branch->up.stream, branch->down.node, branch->down.stream, &cloned))) { hr = topology_branch_connect(topology, method_mask, cloned, NULL); topology_branch_destroy(cloned); } - + if (SUCCEEDED(hr)) + hr = topology_loader_resolve_node(topology, branch->down.node); topology_branch_destroy(branch); - if (FAILED(hr)) - break; } + TRACE("returning %#lx\n", hr); return hr; } @@ -1046,13 +1041,10 @@ static HRESULT clone_topology(IMFTopology *input_topology, IMFCollection *source static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, IMFTopology **ret_topology, IMFTopology *current_topology) { - struct list branches = LIST_INIT(branches); - struct topology_branch *branch, *next; IMFTopology *output_topology; IMFTopologyNode *node; IMFCollection *nodes; - unsigned short i = 0; - HRESULT hr = E_FAIL; + HRESULT hr; TRACE("iface %p, input_topology %p, ret_topology %p, current_topology %p.\n", iface, input_topology, ret_topology, current_topology); @@ -1065,24 +1057,10 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in if (FAILED(hr = clone_topology(input_topology, nodes, &output_topology))) goto done; - for (i = 0; SUCCEEDED(IMFTopology_GetNode(input_topology, i, &node)); i++) + while (SUCCEEDED(hr) && SUCCEEDED(IMFCollection_RemoveElement(nodes, 0, (IUnknown **)&node))) { - hr = topology_node_list_branches(node, &branches); + hr = topology_loader_resolve_node(output_topology, node); IMFTopologyNode_Release(node); - if (FAILED(hr)) - break; - } - if (SUCCEEDED(hr) && list_empty(&branches)) - hr = MF_E_TOPO_UNSUPPORTED; - - while (SUCCEEDED(hr) && !list_empty(&branches)) - hr = topology_loader_resolve_branches(output_topology, &branches); - - LIST_FOR_EACH_ENTRY_SAFE(branch, next, &branches, struct topology_branch, entry) - { - WARN("Failed to resolve branch %s\n", debugstr_topology_branch(branch)); - list_remove(&branch->entry); - topology_branch_destroy(branch); } if (FAILED(hr)) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10791
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/mf/tests/topology.c | 2 -- dlls/mf/topology_loader.c | 19 ++++++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index 0a268054a46..4d96fcb5e87 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -2998,7 +2998,6 @@ static void test_topology_loader(void) /* PCM -> PCM, optional sink */ .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_44100}, .sink_method = MF_CONNECT_AS_OPTIONAL, .source_method = -1, .expected_result = MF_E_TOPO_UNSUPPORTED, - .flags = LOADER_TODO, }, { /* PCM -> PCM, optional source is ignored */ @@ -3009,7 +3008,6 @@ static void test_topology_loader(void) /* H264 -> NV12, optional sink */ .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = MF_CONNECT_AS_OPTIONAL | MF_CONNECT_ALLOW_DECODER, .source_method = -1, .expected_result = MF_E_TOPO_UNSUPPORTED, .decoder_class = CLSID_CMSH264DecoderMFT, - .flags = LOADER_TODO, }, { /* #70 H264 -> NV12, optional source is ignored */ diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 1dd050685a4..187789bad57 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -998,6 +998,7 @@ static HRESULT clone_topology(IMFTopology *input_topology, IMFCollection *source HRESULT hr = S_OK; IUnknown *object; TOPOID topoid; + UINT32 method; IMFTopology_GetTopologyID(input_topology, &topoid); if (FAILED(hr = create_topology(topoid, output_topology))) @@ -1009,13 +1010,17 @@ static HRESULT clone_topology(IMFTopology *input_topology, IMFCollection *source switch (topology_node_get_type(node)) { case MF_TOPOLOGY_OUTPUT_NODE: - if (FAILED(hr = IMFTopologyNode_GetObject(node, &object))) - break; - if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&sink))) - hr = MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; - else - IMFStreamSink_Release(sink); - IUnknown_Release(object); + if (SUCCEEDED(IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_CONNECT_METHOD, &method)) + && (method & MF_CONNECT_AS_OPTIONAL)) + hr = MF_E_TOPO_UNSUPPORTED; + else if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object))) + { + if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&sink))) + hr = MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; + else + IMFStreamSink_Release(sink); + IUnknown_Release(object); + } break; case MF_TOPOLOGY_SOURCESTREAM_NODE: if (SUCCEEDED(hr = IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL))) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10791
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/mf/tests/topology.c | 29 ++++++------- dlls/mf/topology_loader.c | 90 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 17 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index 4d96fcb5e87..6df7da89635 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -2291,7 +2291,6 @@ enum loader_test_flags LOADER_EXPECT_MFT_INPUT_ENUMERATED = 0x8000, LOADER_ADD_OPTIONAL_TEST_MFT_DOWNSTREAM = 0x10000, LOADER_EXPECT_MFT_OUTPUT_ENUMERATED_TODO = 0x20000, - LOADER_EXPECT_MFT_INPUT_ENUMERATED_TODO = 0x40000, }; static void test_topology_loader(void) @@ -2513,6 +2512,7 @@ static void test_topology_loader(void) unsigned int expected_output_index; unsigned int optional_mft_count; BOOL expect_optional_mft_rejected[2]; + BOOL expect_optional_mft_accepted_todo; unsigned int flags; GUID decoder_class; GUID converter_class; @@ -2903,7 +2903,7 @@ static void test_topology_loader(void) .mft_input_types = {&video_nv12_1280}, .mft_output_types = {&video_nv12_1280}, .optional_mft_count = 1, .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, }, { /* H264 -> NV12, add two optional test MFTs and test MFT */ @@ -2911,7 +2911,7 @@ static void test_topology_loader(void) .mft_input_types = {&video_nv12_1280}, .mft_output_types = {&video_nv12_1280}, .optional_mft_count = 2, .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, }, { /* H264 -> NV12, add unconnectable optional test MFT and test MFT */ @@ -2920,7 +2920,7 @@ static void test_topology_loader(void) .optional_mft_input_types = {&video_yuy2_1280}, .optional_mft_count = 1, .expect_optional_mft_rejected = {TRUE}, .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, }, { /* H264 -> NV12, add unconnectable optional test MFT, connectable optional test MFT and test MFT */ @@ -2929,7 +2929,7 @@ static void test_topology_loader(void) .optional_mft_input_types = {&video_yuy2_1280, &video_nv12_1280}, .optional_mft_count = 2, .expect_optional_mft_rejected = {TRUE, FALSE}, .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, }, { /* #60 H264 -> NV12, add connectable optional test MFT, unconnectable optional test MFT and test MFT */ @@ -2938,7 +2938,7 @@ static void test_topology_loader(void) .optional_mft_input_types = {&video_nv12_1280, &video_yuy2_1280}, .optional_mft_count = 2, .expect_optional_mft_rejected = {FALSE, TRUE}, .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, }, { /* H264 -> NV12, add two unconnectable optional test MFTs and test MFT */ @@ -2947,7 +2947,7 @@ static void test_topology_loader(void) .optional_mft_input_types = {&video_yuy2_1280, &video_yuy2_1280}, .optional_mft_count = 2, .expect_optional_mft_rejected = {TRUE, TRUE}, .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, }, { /* H264 -> NV12, add optional test MFT and test MFT, require test MFT input change for optional */ @@ -2956,7 +2956,7 @@ static void test_topology_loader(void) .optional_mft_output_type = &video_yuy2_1280, .optional_mft_count = 1, .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, }, { /* H264 -> NV12, add test MFT and optional test MFT */ @@ -2980,7 +2980,7 @@ static void test_topology_loader(void) .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .mft_input_types = {&video_nv12_1280}, .mft_output_types = {&video_nv12_1280, &video_yuy2_1280}, .optional_mft_input_types = {&video_yuy2_1280}, - .optional_mft_count = 1, + .optional_mft_count = 1, .expect_optional_mft_accepted_todo = TRUE, .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, .flags = LOADER_ADD_TEST_MFT | LOADER_NO_CURRENT_OUTPUT | LOADER_ADD_OPTIONAL_TEST_MFT_DOWNSTREAM | LOADER_EXPECT_MFT_INPUT_ENUMERATED | LOADER_EXPECT_MFT_OUTPUT_ENUMERATED_TODO, }, @@ -3431,7 +3431,7 @@ static void test_topology_loader(void) for (j = 0; j < test->optional_mft_count; ++j) { hr = IMFTopology_GetNodeByID(full_topology, optional_mft_node_id[j], &mft_node); - todo_wine_if(test->expect_optional_mft_rejected[j]) + todo_wine_if(test->expect_optional_mft_accepted_todo) ok(hr == (test->expect_optional_mft_rejected[j] ? MF_E_NOT_FOUND : S_OK), "Unexpected hr %#lx.\n", hr); expect_optional_rejected |= test->expect_optional_mft_rejected[j]; @@ -3467,7 +3467,7 @@ todo_wine { hr = IMFTopology_GetNodeCount(full_topology, &node_count); ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - todo_wine_if(expect_optional_rejected) + todo_wine_if(test->expect_optional_mft_accepted_todo) ok(node_count == count, "Unexpected node count %u.\n", node_count); hr = IMFTopologyNode_GetTopoNodeID(src_node, &node_id); @@ -3502,13 +3502,11 @@ todo_wine { ok(!!test_transform->set_output_sequence_id, "Test transform output sequence id not set.\n"); if (test->flags & LOADER_ADD_OPTIONAL_TEST_MFT_DOWNSTREAM) { - todo_wine ok(optional_transforms[0]->set_input_sequence_id > handler.is_supported_sequence_id, "Optional transform input was not configured after the sink input.\n"); } else { - todo_wine ok(optional_transforms[0]->set_input_sequence_id > test_transform->set_input_sequence_id, "Optional transform input was not configured after the non-optional one.\n"); if (optional_transforms[0]->set_output_sequence_id) @@ -3672,7 +3670,7 @@ todo_wine { ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFTopology_GetNodeCount(topology2, &node_count); ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - todo_wine_if(expect_optional_rejected) + todo_wine_if(test->expect_optional_mft_accepted_todo) ok(node_count == count, "Unexpected node count %u.\n", node_count); ref = IMFTopology_Release(topology2); @@ -3695,8 +3693,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->flags & LOADER_EXPECT_MFT_OUTPUT_ENUMERATED_TODO) || (test_transform->output_enum_complete && (test->flags & LOADER_TODO))) ok(test_transform->output_enum_complete == !!(test->flags & (LOADER_EXPECT_MFT_OUTPUT_ENUMERATED | LOADER_EXPECT_MFT_OUTPUT_ENUMERATED_TODO)), diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 187789bad57..a44289c5f86 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -221,16 +221,40 @@ static HRESULT topology_branch_create_for_output(IMFTopologyNode *node, DWORD st { IMFTopologyNode *down_node; DWORD down_stream; + UINT32 method; HRESULT hr; if (FAILED(hr = IMFTopologyNode_GetOutput(node, stream, &down_node, &down_stream))) return hr; + while (SUCCEEDED(IMFTopologyNode_GetUINT32(down_node, &MF_TOPONODE_CONNECT_METHOD, &method)) + && (method & MF_CONNECT_AS_OPTIONAL)) + { + IMFTopologyNode *tmp = down_node; + hr = IMFTopologyNode_GetOutput(tmp, 0, &down_node, &down_stream); + IMFTopologyNode_Release(tmp); + if (FAILED(hr)) + return hr; + } hr = topology_branch_create(node, stream, down_node, down_stream, out); IMFTopologyNode_Release(down_node); return hr; } +/* create a branch for a given node input stream */ +static HRESULT topology_branch_create_for_input(IMFTopologyNode *node, DWORD stream, struct topology_branch **out) +{ + IMFTopologyNode *up_node; + DWORD up_stream; + HRESULT hr; + + if (FAILED(hr = IMFTopologyNode_GetInput(node, stream, &up_node, &up_stream))) + return hr; + hr = topology_branch_create(up_node, up_stream, node, stream, out); + IMFTopologyNode_Release(up_node); + return hr; +} + static HRESULT topology_branch_create_cloned(IMFTopology *topology, IMFTopologyNode *up_node, DWORD up_stream, IMFTopologyNode *down_node, DWORD down_stream, struct topology_branch **out) { @@ -251,6 +275,18 @@ static HRESULT topology_branch_create_cloned(IMFTopology *topology, IMFTopologyN return hr; } +static HRESULT topology_branch_create_optional(IMFTopology *topology, struct topology_branch *branch, + IMFTopologyNode *optional, DWORD stream, struct topology_branch **up, struct topology_branch **down) +{ + HRESULT hr; + + if (SUCCEEDED(hr = topology_branch_create_cloned(topology, branch->up.node, branch->up.stream, optional, stream, up)) + && FAILED(hr = topology_branch_create_cloned(topology, optional, 0, branch->down.node, branch->down.stream, down))) + topology_branch_destroy(*up); + + return hr; +} + static void media_type_try_copy_attr(IMFMediaType *dst, IMFMediaType *src, const GUID *attr, HRESULT *hr) { PROPVARIANT value; @@ -737,11 +773,58 @@ static HRESULT topology_branch_connect(IMFTopology *topology, enum connect_metho return hr; } +static HRESULT topology_branch_connect_optional_chain(IMFTopology *topology, struct topology_branch *branch, + IMFTopologyNode *down_node, DWORD down_stream) +{ + struct topology_branch *current, *up_branch, *down_branch; + IMFTopologyNode *node; + DWORD stream; + HRESULT hr; + + TRACE("topology %p, branch %s, down_node %p, down_stream %lu\n", topology, debugstr_topology_branch(branch), + down_node, down_stream); + + if (FAILED(hr = IMFTopologyNode_GetOutput(branch->up.node, branch->up.stream, &node, &stream))) + return hr; + while (SUCCEEDED(hr) && node != branch->down.node) + { + IMFTopologyNode *tmp = node; + + /* The loader may have inserted one or more transforms upstream. Only try inserting the optional node + * downstream of them. Support for upstream insertion is untested in native, but seems unlikely to work. */ + if (FAILED(hr = topology_branch_create_for_input(down_node, down_stream, ¤t))) + break; + if (SUCCEEDED(hr = topology_branch_create_optional(topology, current, node, stream, &up_branch, &down_branch))) + { + if (FAILED(hr = topology_branch_connect(topology, CONNECT_DIRECT, up_branch, NULL)) + || FAILED(hr = topology_branch_connect(topology, CONNECT_DIRECT, down_branch, NULL))) + { + if (FAILED(hr = topology_branch_connect(topology, CONNECT_DIRECT, current, NULL))) + WARN("Failed to restore previous branch %s\n", debugstr_topology_branch(current)); + IMFTopology_RemoveNode(topology, down_branch->up.node); + } + topology_branch_destroy(down_branch); + topology_branch_destroy(up_branch); + } + topology_branch_destroy(current); + + hr = IMFTopologyNode_GetOutput(tmp, 0, &node, &stream); + IMFTopologyNode_Release(tmp); + if (FAILED(hr)) + return hr; + } + IMFTopologyNode_Release(node); + + TRACE("returning %#lx\n", hr); + return hr; +} + static HRESULT topology_loader_resolve_node(IMFTopology *topology, IMFTopologyNode *node) { enum connect_method method_mask = connect_method_from_mf(MF_CONNECT_ALLOW_DECODER); struct topology_branch *branch, *cloned; DWORD output_count; + UINT32 method; HRESULT hr; TRACE("topology %p, node %p\n", topology, node); @@ -749,12 +832,17 @@ static HRESULT topology_loader_resolve_node(IMFTopology *topology, IMFTopologyNo if (SUCCEEDED(hr = IMFTopologyNode_GetOutputCount(node, &output_count)) && !output_count) return topology_node_get_type(node) == MF_TOPOLOGY_OUTPUT_NODE ? S_OK : MF_E_TOPO_UNSUPPORTED; + if (SUCCEEDED(IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_CONNECT_METHOD, &method)) + && (method & MF_CONNECT_AS_OPTIONAL_BRANCH)) + FIXME("MF_CONNECT_AS_OPTIONAL_BRANCH not implemented\n"); + for (UINT i = 0; SUCCEEDED(hr) && SUCCEEDED(topology_branch_create_for_output(node, i, &branch)); ++i) { if (SUCCEEDED(hr = topology_branch_create_cloned(topology, branch->up.node, branch->up.stream, branch->down.node, branch->down.stream, &cloned))) { - hr = topology_branch_connect(topology, method_mask, cloned, NULL); + if (SUCCEEDED(hr = topology_branch_connect(topology, method_mask, cloned, NULL))) + topology_branch_connect_optional_chain(topology, branch, cloned->down.node, cloned->down.stream); topology_branch_destroy(cloned); } if (SUCCEEDED(hr)) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10791
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/mf/tests/topology.c | 6 +----- dlls/mf/topology_loader.c | 30 +++++++++++++++++------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index 6df7da89635..eeb9169c668 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -2512,7 +2512,6 @@ static void test_topology_loader(void) unsigned int expected_output_index; unsigned int optional_mft_count; BOOL expect_optional_mft_rejected[2]; - BOOL expect_optional_mft_accepted_todo; unsigned int flags; GUID decoder_class; GUID converter_class; @@ -2980,7 +2979,7 @@ static void test_topology_loader(void) .input_types = {&video_h264_1280}, .output_types = {&video_nv12_1280}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .mft_input_types = {&video_nv12_1280}, .mft_output_types = {&video_nv12_1280, &video_yuy2_1280}, .optional_mft_input_types = {&video_yuy2_1280}, - .optional_mft_count = 1, .expect_optional_mft_accepted_todo = TRUE, + .optional_mft_count = 1, .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, .flags = LOADER_ADD_TEST_MFT | LOADER_NO_CURRENT_OUTPUT | LOADER_ADD_OPTIONAL_TEST_MFT_DOWNSTREAM | LOADER_EXPECT_MFT_INPUT_ENUMERATED | LOADER_EXPECT_MFT_OUTPUT_ENUMERATED_TODO, }, @@ -3431,7 +3430,6 @@ static void test_topology_loader(void) for (j = 0; j < test->optional_mft_count; ++j) { hr = IMFTopology_GetNodeByID(full_topology, optional_mft_node_id[j], &mft_node); - todo_wine_if(test->expect_optional_mft_accepted_todo) ok(hr == (test->expect_optional_mft_rejected[j] ? MF_E_NOT_FOUND : S_OK), "Unexpected hr %#lx.\n", hr); expect_optional_rejected |= test->expect_optional_mft_rejected[j]; @@ -3467,7 +3465,6 @@ todo_wine { hr = IMFTopology_GetNodeCount(full_topology, &node_count); ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - todo_wine_if(test->expect_optional_mft_accepted_todo) ok(node_count == count, "Unexpected node count %u.\n", node_count); hr = IMFTopologyNode_GetTopoNodeID(src_node, &node_id); @@ -3670,7 +3667,6 @@ todo_wine { ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFTopology_GetNodeCount(topology2, &node_count); ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - todo_wine_if(test->expect_optional_mft_accepted_todo) ok(node_count == count, "Unexpected node count %u.\n", node_count); ref = IMFTopology_Release(topology2); diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index a44289c5f86..0d3e2a88669 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -475,7 +475,7 @@ static HRESULT topology_branch_connect_with_type(IMFTopology *topology, struct t } static HRESULT topology_branch_connect(IMFTopology *topology, enum connect_method method_mask, - struct topology_branch *branch, IMFMediaType *upstream); + struct topology_branch *branch, IMFMediaType *upstream, BOOL force_enumerate); static HRESULT topology_branch_connect_indirect(IMFTopology *topology, BOOL decoder, struct topology_branch *branch, IMFMediaType *upstream) { @@ -541,7 +541,7 @@ static HRESULT topology_branch_connect_indirect(IMFTopology *topology, BOOL deco if (SUCCEEDED(hr = topology_branch_connect_with_type(topology, up_branch, upstream))) { if (FAILED(hr = topology_branch_find_best_type(down_branch, upstream, &media_type))) - hr = topology_branch_connect(topology, method_mask, down_branch, upstream); + hr = topology_branch_connect(topology, method_mask, down_branch, upstream, FALSE); else { hr = topology_branch_connect_with_type(topology, down_branch, media_type); @@ -688,7 +688,7 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, enum connect_ } static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, enum connect_method method_mask, - struct topology_branch *branch, IMFMediaType *upstream) + struct topology_branch *branch, IMFMediaType *upstream, BOOL force_enumerate) { HRESULT hr = MF_E_INVALIDMEDIATYPE; UINT32 enumerate = TRUE; @@ -712,7 +712,7 @@ static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, enum conn break; } - if (enumerate) + if (enumerate || force_enumerate) { for (UINT i = 0; SUCCEEDED(hr = media_type_handler_get_type(branch->up.handler, i, &up_type)); i++) { @@ -741,7 +741,7 @@ static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, enum conn } static HRESULT topology_branch_connect(IMFTopology *topology, enum connect_method method_mask, - struct topology_branch *branch, IMFMediaType *upstream) + struct topology_branch *branch, IMFMediaType *upstream, BOOL force_enumerate) { HRESULT hr = MF_E_INVALIDMEDIATYPE; UINT32 up_method, down_method; @@ -758,15 +758,15 @@ static HRESULT topology_branch_connect(IMFTopology *topology, enum connect_metho up_method = MF_CONNECT_DIRECT; if (up_method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES) - hr = topology_branch_foreach_up_types(topology, down_method, branch, upstream); + hr = topology_branch_foreach_up_types(topology, down_method, branch, upstream, force_enumerate); else { if (FAILED(hr) && (down_method & CONNECT_DIRECT)) - hr = topology_branch_foreach_up_types(topology, CONNECT_DIRECT, branch, upstream); + hr = topology_branch_foreach_up_types(topology, CONNECT_DIRECT, branch, upstream, force_enumerate); if (FAILED(hr) && (down_method & CONNECT_CONVERTER)) - hr = topology_branch_foreach_up_types(topology, CONNECT_CONVERTER, branch, upstream); + hr = topology_branch_foreach_up_types(topology, CONNECT_CONVERTER, branch, upstream, force_enumerate); if (FAILED(hr) && (down_method & CONNECT_DECODER)) - hr = topology_branch_foreach_up_types(topology, CONNECT_DECODER, branch, upstream); + hr = topology_branch_foreach_up_types(topology, CONNECT_DECODER, branch, upstream, force_enumerate); } TRACE("returning %#lx\n", hr); @@ -789,6 +789,10 @@ static HRESULT topology_branch_connect_optional_chain(IMFTopology *topology, str while (SUCCEEDED(hr) && node != branch->down.node) { IMFTopologyNode *tmp = node; + UINT32 method; + + if (FAILED(IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_CONNECT_METHOD, &method))) + method = MF_CONNECT_DIRECT; /* The loader may have inserted one or more transforms upstream. Only try inserting the optional node * downstream of them. Support for upstream insertion is untested in native, but seems unlikely to work. */ @@ -796,10 +800,10 @@ static HRESULT topology_branch_connect_optional_chain(IMFTopology *topology, str break; if (SUCCEEDED(hr = topology_branch_create_optional(topology, current, node, stream, &up_branch, &down_branch))) { - if (FAILED(hr = topology_branch_connect(topology, CONNECT_DIRECT, up_branch, NULL)) - || FAILED(hr = topology_branch_connect(topology, CONNECT_DIRECT, down_branch, NULL))) + if (FAILED(hr = topology_branch_connect(topology, CONNECT_DIRECT, up_branch, NULL, !!method)) + || FAILED(hr = topology_branch_connect(topology, CONNECT_DIRECT, down_branch, NULL, FALSE))) { - if (FAILED(hr = topology_branch_connect(topology, CONNECT_DIRECT, current, NULL))) + if (FAILED(hr = topology_branch_connect(topology, CONNECT_DIRECT, current, NULL, FALSE))) WARN("Failed to restore previous branch %s\n", debugstr_topology_branch(current)); IMFTopology_RemoveNode(topology, down_branch->up.node); } @@ -841,7 +845,7 @@ static HRESULT topology_loader_resolve_node(IMFTopology *topology, IMFTopologyNo if (SUCCEEDED(hr = topology_branch_create_cloned(topology, branch->up.node, branch->up.stream, branch->down.node, branch->down.stream, &cloned))) { - if (SUCCEEDED(hr = topology_branch_connect(topology, method_mask, cloned, NULL))) + if (SUCCEEDED(hr = topology_branch_connect(topology, method_mask, cloned, NULL, FALSE))) topology_branch_connect_optional_chain(topology, branch, cloned->down.node, cloned->down.stream); topology_branch_destroy(cloned); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10791
Conor McCarthy (@cmccarthy) commented about dlls/mf/topology_loader.c:
break; if (SUCCEEDED(hr = topology_branch_create_optional(topology, current, node, stream, &up_branch, &down_branch))) { - if (FAILED(hr = topology_branch_connect(topology, CONNECT_DIRECT, up_branch, NULL)) - || FAILED(hr = topology_branch_connect(topology, CONNECT_DIRECT, down_branch, NULL))) + if (FAILED(hr = topology_branch_connect(topology, CONNECT_DIRECT, up_branch, NULL, !!method))
Does native force enumeration for any method flag, even irrelevant/invalid ones? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10791#note_138490
participants (4)
-
Conor McCarthy -
Conor McCarthy (@cmccarthy) -
Rémi Bernon -
Rémi Bernon (@rbernon)