[PATCH v2 0/7] MR9947: mf/tests: Add more topology loader tests.
The first three commits are from !9935 which this goes atop, otherwise it will crash. -- v2: mf/tests: Test topology loader transform enumeration. mf/tests: Add more topology loader tests. mf/tests: Do not expect stereo audio when a decoder and resampler are used. https://gitlab.winehq.org/wine/wine/-/merge_requests/9947
From: Conor McCarthy <cmccarthy@codeweavers.com> The audio resampler does not implement this behaviour. --- dlls/winegstreamer/resampler.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index 910d109c2c6..2b79a613baa 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -374,12 +374,6 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM if (!impl->input_type && FAILED(hr = MFCreateMediaType(&impl->input_type))) return hr; - if (impl->output_type) - { - IMFMediaType_Release(impl->output_type); - impl->output_type = NULL; - } - if (SUCCEEDED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)impl->input_type))) impl->input_info.cbSize = block_alignment; else -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9947
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/winegstreamer/resampler.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index 2b79a613baa..e861c86f737 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -327,6 +327,9 @@ static HRESULT check_media_type(IMFMediaType *type) HRESULT hr; ULONG i; + if (!type) + return S_OK; + if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) return MF_E_ATTRIBUTENOTFOUND; @@ -366,11 +369,21 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM if (FAILED(hr = check_media_type(type))) return hr; - if (FAILED(hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment))) + if (type && FAILED(hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment))) return MF_E_INVALIDMEDIATYPE; if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; + if (!type) + { + if (impl->input_type) + { + IMFMediaType_Release(impl->input_type); + impl->input_type = NULL; + } + return S_OK; + } + if (!impl->input_type && FAILED(hr = MFCreateMediaType(&impl->input_type))) return hr; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9947
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/winegstreamer/resampler.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index e861c86f737..fcaadac17e0 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -412,11 +412,21 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF if (FAILED(hr = check_media_type(type))) return hr; - if (FAILED(hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment))) + if (type && FAILED(hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment))) return MF_E_INVALIDMEDIATYPE; if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; + if (!type) + { + if (impl->output_type) + { + IMFMediaType_Release(impl->output_type); + impl->output_type = NULL; + } + return S_OK; + } + if (!impl->output_type && FAILED(hr = MFCreateMediaType(&impl->output_type))) return hr; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9947
From: Conor McCarthy <cmccarthy@codeweavers.com> Before the addition of more complex tests, we need the sink to behave more like a real sink. --- dlls/mf/tests/topology.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index 9070098a60a..ad89dd3269e 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -1674,6 +1674,8 @@ struct test_handler ULONG set_current_count; IMFMediaType *current_type; IMFMediaType *invalid_type; + BOOL support_any; + BOOL return_media_types; ULONG enum_count; ULONG media_types_count; @@ -1713,6 +1715,7 @@ static HRESULT WINAPI test_handler_IsMediaTypeSupported(IMFMediaTypeHandler *ifa { struct test_handler *impl = impl_from_IMFMediaTypeHandler(iface); BOOL result; + ULONG i; if (out_type) *out_type = NULL; @@ -1721,13 +1724,18 @@ static HRESULT WINAPI test_handler_IsMediaTypeSupported(IMFMediaTypeHandler *ifa MF_ATTRIBUTES_MATCH_OUR_ITEMS, &result) == S_OK && result) return MF_E_INVALIDMEDIATYPE; - if (!impl->current_type) + if (impl->support_any) return S_OK; - if (IMFMediaType_Compare(impl->current_type, (IMFAttributes *)in_type, + if (impl->current_type && IMFMediaType_Compare(impl->current_type, (IMFAttributes *)in_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &result) == S_OK && result) return S_OK; + for (i = 0; i < impl->media_types_count; ++i) + if (IMFMediaType_Compare(impl->media_types[i], (IMFAttributes *)in_type, + MF_ATTRIBUTES_MATCH_OUR_ITEMS, &result) == S_OK && result) + return S_OK; + return MF_E_INVALIDMEDIATYPE; } @@ -1742,7 +1750,7 @@ static HRESULT WINAPI test_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *ifac { struct test_handler *impl = impl_from_IMFMediaTypeHandler(iface); - if (impl->media_types) + if (impl->return_media_types && impl->media_types) { impl->enum_count++; @@ -1776,7 +1784,7 @@ static HRESULT WINAPI test_handler_GetCurrentMediaType(IMFMediaTypeHandler *ifac if (!impl->current_type) { - if (!impl->media_types) + if (!impl->return_media_types) return E_FAIL; if (!impl->media_types_count) return MF_E_TRANSFORM_TYPE_NOT_SET; @@ -2185,6 +2193,7 @@ enum loader_test_flags LOADER_SET_INVALID_INPUT = 0x40, LOADER_SET_MEDIA_TYPES = 0x80, LOADER_ADD_RESAMPLER_MFT = 0x100, + LOADER_SUPPORT_ANY = 0x200, }; static void test_topology_loader(void) @@ -2491,13 +2500,13 @@ static void test_topology_loader(void) /* RGB32 -> Any Video, no current output type */ .input_type = &video_i420_1280, .output_type = &video_dummy, .sink_method = -1, .source_method = -1, .expected_result = S_OK, - .flags = LOADER_NO_CURRENT_OUTPUT, + .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SUPPORT_ANY, }, { /* RGB32 -> Any Video, no current output type, refuse input type */ .input_type = &video_i420_1280, .output_type = &video_dummy, .sink_method = -1, .source_method = -1, .expected_result = S_OK, .converter_class = CLSID_CColorConvertDMO, - .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_INVALID_INPUT, + .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_INVALID_INPUT | LOADER_SUPPORT_ANY, }, { /* RGB32 -> Any Video, no current output type, refuse input type */ @@ -2662,6 +2671,14 @@ static void test_topology_loader(void) handler.invalid_type = input_type; else handler.invalid_type = NULL; + if (test->flags & LOADER_SUPPORT_ANY) + handler.support_any = TRUE; + else + handler.support_any = FALSE; + if (test->flags & LOADER_SET_MEDIA_TYPES) + handler.return_media_types = TRUE; + else + handler.return_media_types = FALSE; handler.enum_count = 0; if (test->flags & LOADER_SET_MEDIA_TYPES) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9947
From: Conor McCarthy <cmccarthy@codeweavers.com> The decoded type is inconsistent across Windows versions. --- dlls/mf/tests/topology.c | 11 +++-------- dlls/mf/tests/transform.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index ad89dd3269e..521f49671cf 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -2268,16 +2268,11 @@ static void test_topology_loader(void) ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 1), ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 8), }; - static const media_type_desc audio_float_44100_stereo = + static const media_type_desc audio_float_44100_no_ch = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float), - ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2), - ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 2 * 4), - ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), - ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 2 * 4 * 44100), ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 4 * 8), - ATTR_UINT32(MF_MT_AUDIO_CHANNEL_MASK, 3, .todo = TRUE), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), }; static const media_type_desc video_i420_1280 = @@ -2468,9 +2463,9 @@ static void test_topology_loader(void) .expected_result = S_OK, .decoder_class = CLSID_CMP3DecMediaObject, }, { - /* MP3 -> PCM, need both decoder and converter */ + /* MP3 -> float, need both decoder and converter */ .input_type = &audio_mp3_44100, .output_type = &audio_float_48000, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = -1, - .current_input = &audio_mp3_44100, .decoded_type = &audio_float_44100_stereo, + .current_input = &audio_mp3_44100, .decoded_type = &audio_float_44100_no_ch, .expected_result = S_OK, .decoder_class = CLSID_CMP3DecMediaObject, .converter_class = CLSID_CResamplerMediaObject, }, diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 4dd9ff7a93e..de085d9926e 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -317,6 +317,9 @@ const char *debugstr_propvariant(const PROPVARIANT *propvar, BOOL ratio) void check_attributes_(const char *file, int line, IMFAttributes *attributes, const struct attribute_desc *desc, ULONG limit) { + UINT32 ch, sample_size, alignment, samples_per_sec, bytes_per_sec; + IMFMediaType *media_type; + GUID major, subtype; PROPVARIANT value; int i, ret; HRESULT hr; @@ -334,6 +337,32 @@ void check_attributes_(const char *file, int line, IMFAttributes *attributes, debugstr_a(desc[i].name), value.vt, debugstr_propvariant(&value, desc[i].ratio)); PropVariantClear(&value); } + + if (FAILED(IMFAttributes_QueryInterface(attributes, &IID_IMFMediaType, (void **)&media_type))) + return; + + /* Check consistency of some float/PCM media type attributes */ + + hr = IMFMediaType_GetMajorType(media_type, &major); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + if (IsEqualGUID(&major, &MFMediaType_Audio) + && (IsEqualGUID(&subtype, &MFAudioFormat_Float) || IsEqualGUID(&subtype, &MFAudioFormat_PCM)) + && SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, &ch)) + && SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &sample_size))) + { + UINT bytes_per_sample = ch * sample_size / CHAR_BIT; + + if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &alignment))) + ok_(__FILE__, line)(alignment == bytes_per_sample, "Unexpected alignment %u\n", alignment); + if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &samples_per_sec)) + && SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bytes_per_sec))) + ok_(__FILE__, line)(bytes_per_sec == bytes_per_sample * samples_per_sec, "Unexpected bytes_per_sec %u\n", bytes_per_sec); + } + + IMFMediaType_Release(media_type); } struct transform_info -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9947
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/mf/tests/topology.c | 370 ++++++++++++++++++++++++++++++++------- 1 file changed, 311 insertions(+), 59 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index 521f49671cf..f4428043048 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -96,6 +96,23 @@ static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOO IUnknown_Release(unk); } +#define check_subtype(a, b) check_subtype_(__LINE__, a, b) +void check_subtype_(unsigned int line, IMFMediaType *media_type, const GUID * const *expected) +{ + GUID subtype = {0}; + HRESULT hr; + UINT i; + + hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + for (i = 0; expected[i]; ++i) + if (IsEqualGUID(&subtype, expected[i])) + return; + + ok(0, "Unexpected subtype %s.\n", debugstr_guid(&subtype)); +} + static HWND create_window(void) { RECT r = {0, 0, 640, 480}; @@ -1680,6 +1697,7 @@ struct test_handler ULONG enum_count; ULONG media_types_count; IMFMediaType **media_types; + BOOL enum_complete; }; static struct test_handler *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler *iface) @@ -1755,7 +1773,10 @@ static HRESULT WINAPI test_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *ifac impl->enum_count++; if (index >= impl->media_types_count) + { + impl->enum_complete = TRUE; return MF_E_NO_MORE_TYPES; + } IMFMediaType_AddRef((*type = impl->media_types[index])); return S_OK; @@ -2186,7 +2207,9 @@ static IMFSampleGrabberSinkCallback *create_test_grabber_callback(void) enum loader_test_flags { - LOADER_TODO = 0x4, + LOADER_TODO = 0x1, + LOADER_TODO_OUT_TYPE = 0x2, + LOADER_SET_XVP_FOR_PLAYBACK = 0x4, LOADER_NEEDS_VIDEO_PROCESSOR = 0x8, LOADER_SET_ENUMERATE_SOURCE_TYPES = 0x10, LOADER_NO_CURRENT_OUTPUT = 0x20, @@ -2194,6 +2217,9 @@ enum loader_test_flags LOADER_SET_MEDIA_TYPES = 0x80, LOADER_ADD_RESAMPLER_MFT = 0x100, LOADER_SUPPORT_ANY = 0x200, + LOADER_EXPECT_SINK_ENUMERATED = 0x400, + LOADER_EXPECT_SINK_ENUMERATED_TODO = 0x800, + LOADER_EXPECT_MFT_ENUMERATED = 0x1000, }; static void test_topology_loader(void) @@ -2268,6 +2294,18 @@ static void test_topology_loader(void) ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 1), ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 8), }; + static const media_type_desc audio_float_44100_stereo = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2), + ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 2 * 4), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), + ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 2 * 4 * 44100), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 4 * 8), + ATTR_UINT32(MF_MT_AUDIO_CHANNEL_MASK, 3, .todo = TRUE), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + }; static const media_type_desc audio_float_44100_no_ch = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), @@ -2293,6 +2331,24 @@ static void test_topology_loader(void) ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), }; + static const media_type_desc video_video_processor_1280_rgb24 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB24), + ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), + }; + static const media_type_desc video_video_processor_1280_rgb555 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB555), + ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), + }; + static const media_type_desc video_video_processor_1024_rgb32 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 1024, 576), + }; static const media_type_desc video_video_processor_rgb32 = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -2317,6 +2373,16 @@ static void test_topology_loader(void) ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), ATTR_UINT32(MF_MT_INTERLACE_MODE, 7), }; + static const media_type_desc video_generic_yuv_1280 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001), + ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), + ATTR_UINT32(MF_MT_INTERLACE_MODE, 7), + }; static const media_type_desc video_dummy = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -2324,13 +2390,16 @@ static void test_topology_loader(void) const struct loader_test { - const media_type_desc *input_type; - const media_type_desc *output_type; + const media_type_desc *input_types[2]; + const media_type_desc *output_types[2]; const media_type_desc *current_input; + const media_type_desc *mft_current_output; const media_type_desc *decoded_type; + const GUID *decoded_subtypes[3]; MF_CONNECT_METHOD source_method; MF_CONNECT_METHOD sink_method; HRESULT expected_result; + unsigned int expected_output_index; unsigned int flags; GUID decoder_class; GUID converter_class; @@ -2339,25 +2408,25 @@ static void test_topology_loader(void) { { /* PCM -> PCM, same enumerated type, no current type */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_44100}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .expected_result = S_OK, }, { /* PCM -> PCM, same enumerated type, incomplete current type */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_44100}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .current_input = &audio_pcm_44100_incomplete, .expected_result = MF_E_INVALIDMEDIATYPE, .flags = LOADER_TODO, }, { /* PCM -> PCM, same enumerated bps, different current bps */ - .input_type = &audio_pcm_48000, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .input_types = {&audio_pcm_48000}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .current_input = &audio_pcm_44100, .expected_result = MF_E_INVALIDMEDIATYPE, }, { /* PCM -> PCM, same enumerated bps, different current bps, force enumerate */ - .input_type = &audio_pcm_48000, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .input_types = {&audio_pcm_48000}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .current_input = &audio_pcm_44100, .expected_result = S_OK, .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES, @@ -2365,13 +2434,13 @@ static void test_topology_loader(void) { /* PCM -> PCM, incomplete enumerated type, same current type */ - .input_type = &audio_pcm_44100_incomplete, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .input_types = {&audio_pcm_44100_incomplete}, .output_types = {&audio_pcm_44100}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .current_input = &audio_pcm_44100, .expected_result = S_OK, }, { /* PCM -> PCM, incomplete enumerated type, same current type, force enumerate */ - .input_type = &audio_pcm_44100_incomplete, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .input_types = {&audio_pcm_44100_incomplete}, .output_types = {&audio_pcm_44100}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .current_input = &audio_pcm_44100, .expected_result = MF_E_NO_MORE_TYPES, .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES | LOADER_TODO, @@ -2379,146 +2448,275 @@ static void test_topology_loader(void) { /* PCM -> PCM, different enumerated bps, no current type */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .expected_result = MF_E_INVALIDMEDIATYPE, }, { /* PCM -> PCM, different enumerated bps, same current bps */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .current_input = &audio_pcm_48000, .expected_result = S_OK, }, { /* PCM -> PCM, different enumerated bps, same current bps, force enumerate */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .current_input = &audio_pcm_48000, .expected_result = MF_E_NO_MORE_TYPES, .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES, }, { /* PCM -> PCM, different enumerated bps, no current type, sink allow converter */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = MF_CONNECT_DIRECT, + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = MF_CONNECT_DIRECT, .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, }, { /* PCM -> PCM, different enumerated bps, same current type, sink allow converter, force enumerate */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = -1, + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = -1, .current_input = &audio_pcm_48000, .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES, }, + { + /* 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, + }, + { + /* PCM -> PCM, different enumerated bps, no current type, sink allow converter, no current output type */ + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = MF_CONNECT_DIRECT, + .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, + .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_EXPECT_SINK_ENUMERATED_TODO, + }, { /* PCM -> PCM, different enumerated bps, no current type, sink allow decoder */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = MF_CONNECT_DIRECT, + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = MF_CONNECT_DIRECT, .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, }, { /* PCM -> PCM, different enumerated bps, no current type, default methods */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = -1, .source_method = -1, + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = -1, .source_method = -1, .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, }, { /* PCM -> PCM, different enumerated bps, no current type, source allow converter */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = MF_CONNECT_ALLOW_CONVERTER, + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_DIRECT, .source_method = MF_CONNECT_ALLOW_CONVERTER, .expected_result = MF_E_INVALIDMEDIATYPE, }, { /* Float -> PCM, refuse input type, add converter */ - .input_type = &audio_float_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .input_types = {&audio_float_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .expected_result = MF_E_NO_MORE_TYPES, .converter_class = CLSID_CResamplerMediaObject, .flags = LOADER_SET_INVALID_INPUT | LOADER_ADD_RESAMPLER_MFT, }, { /* Float -> PCM, refuse input type, add converter, allow resampler output type */ - .input_type = &audio_float_44100, .output_type = &audio_pcm_48000_resampler, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .input_types = {&audio_float_44100}, .output_types = {&audio_pcm_48000_resampler}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, .flags = LOADER_SET_INVALID_INPUT | LOADER_ADD_RESAMPLER_MFT, }, { /* MP3 -> PCM */ - .input_type = &audio_mp3_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .input_types = {&audio_mp3_44100}, .output_types = {&audio_pcm_44100}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .current_input = &audio_mp3_44100, .expected_result = MF_E_INVALIDMEDIATYPE, }, { /* MP3 -> PCM, force enumerate */ - .input_type = &audio_mp3_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .input_types = {&audio_mp3_44100}, .output_types = {&audio_pcm_44100}, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, .current_input = &audio_mp3_44100, .expected_result = MF_E_NO_MORE_TYPES, .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES, }, { /* MP3 -> PCM */ - .input_type = &audio_mp3_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = -1, + .input_types = {&audio_mp3_44100}, .output_types = {&audio_pcm_44100}, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = -1, .current_input = &audio_mp3_44100, .expected_result = MF_E_TRANSFORM_NOT_POSSIBLE_FOR_CURRENT_MEDIATYPE_COMBINATION, .flags = LOADER_TODO, }, { /* MP3 -> PCM */ - .input_type = &audio_mp3_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = -1, + .input_types = {&audio_mp3_44100}, .output_types = {&audio_pcm_44100}, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = -1, .current_input = &audio_mp3_44100, .expected_result = S_OK, .decoder_class = CLSID_CMP3DecMediaObject, }, { /* MP3 -> float, need both decoder and converter */ - .input_type = &audio_mp3_44100, .output_type = &audio_float_48000, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = -1, + .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, }, + { + /* MP3 -> float, need both decoder and converter, no current output type */ + .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, + }, + { + /* 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, + }, + { + /* 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, + }, + + { + /* {MP3, PCM} -> PCM, force enumerate, sink allow decoder, no output types */ + .input_types = {&audio_mp3_44100, &audio_pcm_44100}, .output_types = {&audio_pcm_44100}, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = -1, + .expected_result = S_OK, + .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_ENUMERATE_SOURCE_TYPES, + }, + { + /* {MP3, PCM} -> PCM, force enumerate, independent outtypes, sink allow decoder, no current output type */ + .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, + }, + + { + /* PCM -> PCM, different enumerated bps, add converter, no output types */ + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_DIRECT, .source_method = MF_CONNECT_DIRECT, + .expected_result = MF_E_NO_MORE_TYPES, .converter_class = CLSID_CResamplerMediaObject, + .flags = LOADER_ADD_RESAMPLER_MFT | LOADER_NO_CURRENT_OUTPUT, + }, + { + /* PCM -> PCM, different enumerated bps, add converter, configure converter, no output types */ + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_DIRECT, .source_method = MF_CONNECT_DIRECT, + .mft_current_output = &audio_pcm_48000, + .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, + .flags = LOADER_ADD_RESAMPLER_MFT | LOADER_NO_CURRENT_OUTPUT, + }, { /* I420 -> RGB32, Color Convert media type */ - .input_type = &video_i420_1280, .output_type = &video_color_convert_1280_rgb32, .sink_method = -1, .source_method = -1, + .input_types = {&video_i420_1280}, .output_types = {&video_color_convert_1280_rgb32}, .sink_method = -1, .source_method = -1, .expected_result = MF_E_TOPO_CODEC_NOT_FOUND, .converter_class = CLSID_CColorConvertDMO, .flags = LOADER_NEEDS_VIDEO_PROCESSOR, }, { /* I420 -> RGB32, Video Processor media type */ - .input_type = &video_i420_1280, .output_type = &video_video_processor_1280_rgb32, .sink_method = -1, .source_method = -1, + .input_types = {&video_i420_1280}, .output_types = {&video_video_processor_1280_rgb32}, .sink_method = -1, .source_method = -1, .expected_result = S_OK, .converter_class = CLSID_CColorConvertDMO, }, { /* I420 -> RGB32, Video Processor media type without frame size */ - .input_type = &video_i420_1280, .output_type = &video_video_processor_rgb32, .sink_method = -1, .source_method = -1, + .input_types = {&video_i420_1280}, .output_types = {&video_video_processor_rgb32}, .sink_method = -1, .source_method = -1, .expected_result = S_OK, .converter_class = CLSID_CColorConvertDMO, }, { /* H264 -> RGB32, Video Processor media type */ - .input_type = &video_h264_1280, .output_type = &video_video_processor_1280_rgb32, .sink_method = -1, .source_method = -1, + .input_types = {&video_h264_1280}, .output_types = {&video_video_processor_1280_rgb32}, .sink_method = -1, .source_method = -1, .decoded_type = &video_nv12_1280, .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, .converter_class = CLSID_CColorConvertDMO, }, { /* RGB32 -> Any Video, no current output type */ - .input_type = &video_i420_1280, .output_type = &video_dummy, .sink_method = -1, .source_method = -1, + .input_types = {&video_i420_1280}, .output_types = {&video_dummy}, .sink_method = -1, .source_method = -1, .expected_result = S_OK, .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SUPPORT_ANY, }, { /* RGB32 -> Any Video, no current output type, refuse input type */ - .input_type = &video_i420_1280, .output_type = &video_dummy, .sink_method = -1, .source_method = -1, + .input_types = {&video_i420_1280}, .output_types = {&video_dummy}, .sink_method = -1, .source_method = -1, .expected_result = S_OK, .converter_class = CLSID_CColorConvertDMO, .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_INVALID_INPUT | LOADER_SUPPORT_ANY, }, { /* RGB32 -> Any Video, no current output type, refuse input type */ - .input_type = &video_i420_1280, .output_type = &video_video_processor_rgb32, .sink_method = -1, .source_method = -1, + .input_types = {&video_i420_1280}, .output_types = {&video_video_processor_rgb32}, .sink_method = -1, .source_method = -1, .expected_result = S_OK, .converter_class = CLSID_CColorConvertDMO, - .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_INVALID_INPUT | LOADER_SET_MEDIA_TYPES, + .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_INVALID_INPUT | LOADER_SET_MEDIA_TYPES | LOADER_EXPECT_SINK_ENUMERATED_TODO, + }, + + { + /* H264 -> {DMO_RGB32, MF_RGB32}, no current output type */ + .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, + }, + { + /* H264 -> {DMO_RGB32, MF_RGB32} */ + .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 = MF_E_TOPO_CODEC_NOT_FOUND, .decoder_class = CLSID_CMSH264DecoderMFT, .converter_class = CLSID_CColorConvertDMO, + }, + + { + /* H264 -> {RGB32, RGB24} */ + .input_types = {&video_h264_1280}, .output_types = {&video_video_processor_1280_rgb32, &video_video_processor_1280_rgb24}, .sink_method = -1, .source_method = -1, + .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, + }, + { + /* 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, + }, + { + /* 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, + }, + { + /* 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, + }, + + { + /* H264 -> RGB32, Color Convert media type, no current output type */ + .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, + }, + + { + /* H264 -> {DMO_RGB32, MF_RGB32}, no current output type, set XVP */ + .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_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, + }, + { + /* H264 -> RGB32, resize, set XVP */ + .input_types = {&video_h264_1280}, .output_types = {&video_video_processor_1024_rgb32}, .sink_method = -1, .source_method = -1, + .decoded_type = &video_nv12_1280, + .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, .converter_class = CLSID_VideoProcessorMFT, + .flags = LOADER_SET_XVP_FOR_PLAYBACK, }, }; IMFTopologyNode *src_node, *sink_node, *src_node2, *sink_node2, *mft_node; IMFSampleGrabberSinkCallback *grabber_callback = create_test_grabber_callback(); + IMFMediaType *media_type, *input_types[2], *output_types[2]; struct test_stream_sink stream_sink = test_stream_sink; - IMFMediaType *media_type, *input_type, *output_type; IMFTopology *topology, *topology2, *full_topology; + unsigned int i, count, expected_count, value; struct test_handler handler = test_handler; IMFPresentationDescriptor *pd; - unsigned int i, count, value; IMFActivate *sink_activate; MF_TOPOLOGY_TYPE node_type; IMFStreamDescriptor *sd; @@ -2641,10 +2839,14 @@ static void test_topology_loader(void) ok(ref == 0, "Release returned %ld\n", ref); - hr = MFCreateMediaType(&input_type); + hr = MFCreateMediaType(&input_types[0]); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + hr = MFCreateMediaType(&input_types[1]); ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); - hr = MFCreateMediaType(&output_type); + hr = MFCreateMediaType(&output_types[0]); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + hr = MFCreateMediaType(&output_types[1]); ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); for (i = 0; i < ARRAY_SIZE(loader_tests); ++i) @@ -2653,17 +2855,17 @@ static void test_topology_loader(void) winetest_push_context("%u", i); - init_media_type(input_type, *test->input_type, -1); - init_media_type(output_type, *test->output_type, -1); + init_media_type(input_types[0], *test->input_types[0], -1); + init_media_type(output_types[0], *test->output_types[0], -1); handler.set_current_count = 0; if (test->flags & LOADER_NO_CURRENT_OUTPUT) handler.current_type = NULL; else - IMFMediaType_AddRef((handler.current_type = output_type)); + IMFMediaType_AddRef((handler.current_type = output_types[0])); if (test->flags & LOADER_SET_INVALID_INPUT) - handler.invalid_type = input_type; + handler.invalid_type = input_types[0]; else handler.invalid_type = NULL; if (test->flags & LOADER_SUPPORT_ANY) @@ -2676,15 +2878,19 @@ static void test_topology_loader(void) handler.return_media_types = FALSE; handler.enum_count = 0; - if (test->flags & LOADER_SET_MEDIA_TYPES) + handler.media_types_count = 1; + handler.media_types = output_types; + handler.enum_complete = FALSE; + + if (test->input_types[1]) { - handler.media_types_count = 1; - handler.media_types = &output_type; + init_media_type(input_types[1], *test->input_types[1], -1); } - else + + if (test->output_types[1]) { - handler.media_types_count = 0; - handler.media_types = NULL; + init_media_type(output_types[1], *test->output_types[1], -1); + handler.media_types_count = 2; } if (test->flags & LOADER_ADD_RESAMPLER_MFT) @@ -2705,6 +2911,17 @@ static void test_topology_loader(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFTopologyNode_SetObject(mft_node, (IUnknown *)transform); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (test->mft_current_output) + { + hr = IMFTransform_SetInputType(transform, 0, input_types[0], 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + init_media_type(media_type, *test->mft_current_output, -1); + hr = IMFTransform_SetOutputType(transform, 0, media_type, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(media_type); + } IMFTransform_Release(transform); hr = IMFTopology_AddNode(topology, mft_node); @@ -2727,7 +2944,7 @@ static void test_topology_loader(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); } - create_descriptors(1, &input_type, test->current_input, &pd, &sd); + create_descriptors(1 + !!test->input_types[1], input_types, test->current_input, &pd, &sd); source = create_test_source(pd); @@ -2740,8 +2957,11 @@ static void test_topology_loader(void) if (test->flags & LOADER_SET_ENUMERATE_SOURCE_TYPES) IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, 1); + if (test->flags & LOADER_SET_XVP_FOR_PLAYBACK) + IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENABLE_XVP_FOR_PLAYBACK, 1); hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); IMFTopology_DeleteItem(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES); + IMFTopology_DeleteItem(topology, &MF_TOPOLOGY_ENABLE_XVP_FOR_PLAYBACK); if (test->flags & LOADER_NEEDS_VIDEO_PROCESSOR && !has_video_processor) ok(hr == MF_E_INVALIDMEDIATYPE || hr == MF_E_TOPO_CODEC_NOT_FOUND, @@ -2766,11 +2986,12 @@ static void test_topology_loader(void) 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"); + expected_count = 1 + !!(test->flags & LOADER_SET_ENUMERATE_SOURCE_TYPES) + + !!(test->flags & LOADER_SET_XVP_FOR_PLAYBACK); hr = IMFTopology_GetCount(full_topology, &count); ok(hr == S_OK, "Failed to get attribute count, hr %#lx.\n", hr); todo_wine - ok(count == (test->flags & LOADER_SET_ENUMERATE_SOURCE_TYPES ? 2 : 1), - "Unexpected count %u.\n", count); + ok(count == expected_count, "Unexpected count %u.\n", count); value = 0xdeadbeef; hr = IMFTopology_GetUINT32(full_topology, &MF_TOPOLOGY_RESOLUTION_STATUS, &value); @@ -2794,12 +3015,23 @@ todo_wine { hr = IMFTopology_GetNodeByID(full_topology, node_id, &src_node2); ok(hr == S_OK, "Failed to get source in resolved topology, hr %#lx.\n", hr); + hr = IMFTopologyNode_GetOutputPrefType(src_node2, 0, &media_type); + ok(hr == E_FAIL, "Got src pref type hr %#lx.\n", hr); + hr = IMFTopologyNode_GetTopoNodeID(sink_node, &node_id); ok(hr == S_OK, "Failed to get sink node id, hr %#lx.\n", hr); hr = IMFTopology_GetNodeByID(full_topology, node_id, &sink_node2); ok(hr == S_OK, "Failed to get sink in resolved topology, hr %#lx.\n", hr); + hr = IMFTopologyNode_GetInputPrefType(sink_node, 0, &media_type); + ok(hr == E_FAIL, "Got sink pref type hr %#lx.\n", hr); + hr = IMFTopologyNode_GetInputPrefType(sink_node2, 0, &media_type); + todo_wine + ok(hr == S_OK, "Failed to get sink pref type, hr %#lx.\n", hr); + if (hr == S_OK) + IMFMediaType_Release(media_type); + if (!IsEqualGUID(&test->decoder_class, &GUID_NULL)) { GUID class_id; @@ -2832,7 +3064,7 @@ todo_wine { hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); ok(hr == S_OK, "Failed to get transform input type, hr %#lx.\n", hr); - hr = IMFMediaType_Compare(input_type, (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); + hr = IMFMediaType_Compare(input_types[0], (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); ok(hr == S_OK, "Failed to compare media types, hr %#lx.\n", hr); ok(ret, "Input type of first transform doesn't match source node type.\n"); IMFMediaType_Release(media_type); @@ -2841,13 +3073,15 @@ todo_wine { ok(hr == S_OK, "Failed to get transform input type, hr %#lx.\n", hr); if (IsEqualGUID(&test->converter_class, &GUID_NULL)) { - hr = IMFMediaType_Compare(output_type, (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); + hr = IMFMediaType_Compare(output_types[test->expected_output_index], (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); ok(hr == S_OK, "Failed to compare media types, hr %#lx.\n", hr); ok(ret, "Output type of first transform doesn't match sink node type.\n"); } else if (test->decoded_type) { check_media_type(media_type, *test->decoded_type, -1); + if (test->decoded_subtypes[0]) + check_subtype(media_type, test->decoded_subtypes); } IMFMediaType_Release(media_type); @@ -2868,9 +3102,17 @@ todo_wine { class_id = GUID_NULL; hr = IMFTopologyNode_GetGUID(mft_node, &MF_TOPONODE_TRANSFORM_OBJECTID, &class_id); - 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)); + 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)); + } hr = IMFTopologyNode_GetObject(mft_node, &node_object); ok(hr == S_OK, "Failed to get object of transform node, hr %#lx.\n", hr); @@ -2884,20 +3126,23 @@ todo_wine { ok(hr == S_OK, "Failed to get transform input type, hr %#lx.\n", hr); if (IsEqualGUID(&test->decoder_class, &GUID_NULL)) { - hr = IMFMediaType_Compare(input_type, (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); + hr = IMFMediaType_Compare(input_types[0], (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); ok(hr == S_OK, "Failed to compare media types, hr %#lx.\n", hr); ok(ret, "Input type of last transform doesn't match source node type.\n"); } else if (test->decoded_type) { check_media_type(media_type, *test->decoded_type, -1); + if (test->decoded_subtypes[0]) + check_subtype(media_type, test->decoded_subtypes); } IMFMediaType_Release(media_type); hr = IMFTransform_GetOutputCurrentType(transform, 0, &media_type); - ok(hr == S_OK, "Failed to get transform input type, hr %#lx.\n", hr); - hr = IMFMediaType_Compare(output_type, (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); + ok(hr == S_OK, "Failed to get transform output type, hr %#lx.\n", hr); + hr = IMFMediaType_Compare(output_types[test->expected_output_index], (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); ok(hr == S_OK, "Failed to compare media types, hr %#lx.\n", hr); + todo_wine_if(test->flags & LOADER_TODO_OUT_TYPE) ok(ret, "Output type of last transform doesn't match sink node type.\n"); IMFMediaType_Release(media_type); @@ -2933,6 +3178,9 @@ todo_wine { else ok(!handler.enum_count, "got %lu GetMediaTypeByIndex\n", handler.enum_count); ok(!handler.set_current_count, "got %lu SetCurrentMediaType\n", handler.set_current_count); + todo_wine_if(test->flags & LOADER_EXPECT_SINK_ENUMERATED_TODO) + ok(handler.enum_complete == !!(test->flags & (LOADER_EXPECT_SINK_ENUMERATED | LOADER_EXPECT_SINK_ENUMERATED_TODO)), + "Got enum_complete %u.\n", handler.enum_complete); if (handler.current_type) IMFMediaType_Release(handler.current_type); @@ -2963,9 +3211,13 @@ todo_wine { ref = IMFTopologyNode_Release(sink_node); ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFMediaType_Release(input_type); + ref = IMFMediaType_Release(input_types[0]); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFMediaType_Release(input_types[1]); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFMediaType_Release(output_types[0]); ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFMediaType_Release(output_type); + ref = IMFMediaType_Release(output_types[1]); ok(ref == 0, "Release returned %ld\n", ref); hr = MFShutdown(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9947
From: Conor McCarthy <cmccarthy@codeweavers.com> --- dlls/mf/tests/topology.c | 234 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 220 insertions(+), 14 deletions(-) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index f4428043048..d2c1b047c52 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -262,6 +262,11 @@ struct test_transform UINT output_count; IMFMediaType **output_types; IMFMediaType *output_type; + BOOL input_enum_complete; + BOOL output_enum_complete; + BOOL input_type_set; + BOOL output_type_set; + BOOL set_input_nulls_output; IDirect3DDeviceManager9 *expect_d3d9_device_manager; BOOL got_d3d9_device_manager; @@ -398,6 +403,7 @@ static HRESULT WINAPI test_transform_GetInputAvailableType(IMFTransform *iface, if (index >= transform->input_count) { *type = NULL; + transform->input_enum_complete = TRUE; return MF_E_NO_MORE_TYPES; } @@ -414,6 +420,7 @@ static HRESULT WINAPI test_transform_GetOutputAvailableType(IMFTransform *iface, if (index >= transform->output_count) { *type = NULL; + transform->output_enum_complete = TRUE; return MF_E_NO_MORE_TYPES; } @@ -425,12 +432,39 @@ static HRESULT WINAPI test_transform_GetOutputAvailableType(IMFTransform *iface, static HRESULT WINAPI test_transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { struct test_transform *transform = test_transform_from_IMFTransform(iface); + BOOL result; + UINT i; + + if (type) + { + for (i = 0; i < transform->input_count; ++i) + { + if (IMFMediaType_Compare(transform->input_types[i], (IMFAttributes *)type, + MF_ATTRIBUTES_MATCH_OUR_ITEMS, &result) == S_OK && result) + break; + } + if (i == transform->input_count) + return MF_E_INVALIDMEDIATYPE; + } + if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; + if (transform->input_type) IMFMediaType_Release(transform->input_type); + if ((transform->input_type = type)) + { + transform->input_type_set = TRUE; IMFMediaType_AddRef(transform->input_type); + } + + if (transform->output_type && (!type || transform->set_input_nulls_output)) + { + IMFMediaType_Release(transform->output_type); + transform->output_type = NULL; + } + return S_OK; } @@ -442,7 +476,10 @@ static HRESULT WINAPI test_transform_SetOutputType(IMFTransform *iface, DWORD id if (transform->output_type) IMFMediaType_Release(transform->output_type); if ((transform->output_type = type)) + { + transform->output_type_set = TRUE; IMFMediaType_AddRef(transform->output_type); + } return S_OK; } @@ -607,6 +644,7 @@ static HRESULT WINAPI test_transform_create(UINT input_count, IMFMediaType **inp { struct test_transform *transform; HRESULT hr; + GUID type; if (!(transform = calloc(1, sizeof(*transform)))) return E_OUTOFMEMORY; @@ -622,6 +660,9 @@ static HRESULT WINAPI test_transform_create(UINT input_count, IMFMediaType **inp transform->output_type = output_types[0]; IMFMediaType_AddRef(transform->output_type); + transform->set_input_nulls_output = SUCCEEDED(IMFMediaType_GetGUID(output_types[0], &MF_MT_MAJOR_TYPE, &type)) + && !IsEqualGUID(&type, &MFMediaType_Audio); + hr = MFCreateAttributes(&transform->attributes, 1); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFAttributes_SetUINT32(transform->attributes, &MF_SA_D3D_AWARE, d3d_aware); @@ -2219,7 +2260,13 @@ enum loader_test_flags LOADER_SUPPORT_ANY = 0x200, LOADER_EXPECT_SINK_ENUMERATED = 0x400, LOADER_EXPECT_SINK_ENUMERATED_TODO = 0x800, - LOADER_EXPECT_MFT_ENUMERATED = 0x1000, + LOADER_ADD_TEST_MFT = 0x1000, + 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, }; static void test_topology_loader(void) @@ -2294,6 +2341,18 @@ static void test_topology_loader(void) ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 1), ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 8), }; + static const media_type_desc audio_float_minimal = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + }; + static const media_type_desc audio_pcm_minimal = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + }; static const media_type_desc audio_float_44100_stereo = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), @@ -2313,6 +2372,15 @@ static void test_topology_loader(void) ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 4 * 8), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), }; + static const media_type_desc audio_aac_44100 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_AAC), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), + ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 16000), + ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 1), + }; static const media_type_desc video_i420_1280 = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -2392,6 +2460,8 @@ static void test_topology_loader(void) { const media_type_desc *input_types[2]; const media_type_desc *output_types[2]; + const media_type_desc *mft_input_type; + const media_type_desc *mft_output_types[5]; const media_type_desc *current_input; const media_type_desc *mft_current_output; const media_type_desc *decoded_type; @@ -2470,7 +2540,7 @@ static void test_topology_loader(void) .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, }, { - /* PCM -> PCM, different enumerated bps, same current type, sink allow converter, force enumerate */ + /* #10 PCM -> PCM, different enumerated bps, same current type, sink allow converter, force enumerate */ .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = -1, .current_input = &audio_pcm_48000, .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, @@ -2531,7 +2601,7 @@ static void test_topology_loader(void) .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES, }, { - /* MP3 -> PCM */ + /* #20 MP3 -> PCM */ .input_types = {&audio_mp3_44100}, .output_types = {&audio_pcm_44100}, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = -1, .current_input = &audio_mp3_44100, .expected_result = MF_E_TRANSFORM_NOT_POSSIBLE_FOR_CURRENT_MEDIATYPE_COMBINATION, @@ -2585,6 +2655,53 @@ static void test_topology_loader(void) .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_MEDIA_TYPES | LOADER_SET_ENUMERATE_SOURCE_TYPES | LOADER_EXPECT_SINK_ENUMERATED_TODO, }, + { + /* PCM -> PCM, different enumerated bps, add test MFT, configure MFT incomplete type */ + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_DIRECT, .source_method = MF_CONNECT_DIRECT, + .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, + }, + { + /* PCM -> PCM, different enumerated bps, add test MFT */ + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_DIRECT, .source_method = MF_CONNECT_DIRECT, + .mft_output_types = {&audio_float_minimal, &audio_pcm_minimal, &audio_float_48000, &audio_pcm_48000_resampler}, + .expected_result = MF_E_NO_MORE_TYPES, + .flags = LOADER_ADD_TEST_MFT | LOADER_EXPECT_MFT_OUTPUT_ENUMERATED, + }, + { + /* #30 PCM -> PCM, different enumerated bps, add test MFT, configure MFT */ + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_DIRECT, .source_method = MF_CONNECT_DIRECT, + .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, + }, + { + /* PCM -> PCM, different enumerated bps, add test MFT, configure MFT, no output types */ + .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_DIRECT, .source_method = MF_CONNECT_DIRECT, + .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, + }, + { + /* MP3 -> PCM, different enumerated bps, add 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_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, + }, + { + /* 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 | LOADER_TODO, + }, + { /* PCM -> PCM, different enumerated bps, add converter, no output types */ .input_types = {&audio_pcm_44100}, .output_types = {&audio_pcm_48000}, .sink_method = MF_CONNECT_DIRECT, .source_method = MF_CONNECT_DIRECT, @@ -2622,7 +2739,7 @@ static void test_topology_loader(void) .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, .converter_class = CLSID_CColorConvertDMO, }, { - /* RGB32 -> Any Video, no current output type */ + /* #40 RGB32 -> Any Video, no current output type */ .input_types = {&video_i420_1280}, .output_types = {&video_dummy}, .sink_method = -1, .source_method = -1, .expected_result = S_OK, .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SUPPORT_ANY, @@ -2693,7 +2810,7 @@ static void test_topology_loader(void) }, { - /* H264 -> {DMO_RGB32, MF_RGB32}, no current output type, set XVP */ + /* #50 H264 -> {DMO_RGB32, MF_RGB32}, no current output type, set XVP */ .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_generic_yuv_1280, .expected_output_index = 1, .decoded_subtypes = {&MFVideoFormat_NV12, &MFVideoFormat_YUY2}, @@ -2707,6 +2824,28 @@ static void test_topology_loader(void) .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, .converter_class = CLSID_VideoProcessorMFT, .flags = LOADER_SET_XVP_FOR_PLAYBACK, }, + + { + /* H264 -> RGB32, Color Convert media type, add test MFT */ + .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, + }, + { + /* 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, + }, + { + /* 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, + }, }; IMFTopologyNode *src_node, *sink_node, *src_node2, *sink_node2, *mft_node; @@ -2714,7 +2853,7 @@ static void test_topology_loader(void) IMFMediaType *media_type, *input_types[2], *output_types[2]; struct test_stream_sink stream_sink = test_stream_sink; IMFTopology *topology, *topology2, *full_topology; - unsigned int i, count, expected_count, value; + unsigned int i, j, count, expected_count, value; struct test_handler handler = test_handler; IMFPresentationDescriptor *pd; IMFActivate *sink_activate; @@ -2852,6 +2991,9 @@ static void test_topology_loader(void) for (i = 0; i < ARRAY_SIZE(loader_tests); ++i) { const struct loader_test *test = &loader_tests[i]; + struct test_transform *test_transform = NULL; + IMFMediaType *mft_output_types[4] = {0}; + IMFMediaType *mft_input_type = NULL; winetest_push_context("%u", i); @@ -2893,7 +3035,7 @@ static void test_topology_loader(void) handler.media_types_count = 2; } - if (test->flags & LOADER_ADD_RESAMPLER_MFT) + if (test->flags & (LOADER_ADD_RESAMPLER_MFT | LOADER_ADD_TEST_MFT)) { hr = IMFTopology_Clear(topology); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -2904,11 +3046,33 @@ static void test_topology_loader(void) hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &mft_node); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (test->flags & LOADER_ADD_TEST_MFT) + { + mft_input_type = input_types[0]; - hr = CoCreateInstance(&CLSID_CResamplerMediaObject, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopologyNode_SetGUID(mft_node, &MF_TOPONODE_TRANSFORM_OBJECTID, &CLSID_CResamplerMediaObject); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (test->mft_input_type) + { + hr = MFCreateMediaType(&mft_input_type); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + init_media_type(mft_input_type, *test->mft_input_type, -1); + } + for (j = 0; test->mft_output_types[j]; ++j) + { + hr = MFCreateMediaType(&mft_output_types[j]); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + init_media_type(mft_output_types[j], *test->mft_output_types[j], -1); + } + test_transform_create(1, &mft_input_type, j, mft_output_types, FALSE, &transform); + test_transform = test_transform_from_IMFTransform(transform); + IMFTransform_AddRef(transform); + } + else + { + hr = CoCreateInstance(&CLSID_CResamplerMediaObject, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_SetGUID(mft_node, &MF_TOPONODE_TRANSFORM_OBJECTID, &CLSID_CResamplerMediaObject); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } hr = IMFTopologyNode_SetObject(mft_node, (IUnknown *)transform); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (test->mft_current_output) @@ -2922,8 +3086,19 @@ static void test_topology_loader(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); IMFMediaType_Release(media_type); } + else + { + IMFTransform_SetInputType(transform, 0, NULL, 0); + IMFTransform_SetOutputType(transform, 0, NULL, 0); + } IMFTransform_Release(transform); + if (test_transform) + { + test_transform->input_type_set = FALSE; + test_transform->output_type_set = FALSE; + } + hr = IMFTopology_AddNode(topology, mft_node); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFTopologyNode_ConnectOutput(src_node, 0, mft_node, 0); @@ -2999,7 +3174,7 @@ 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); } - count = 2; + count = 2 + !!test_transform; if (!IsEqualGUID(&test->decoder_class, &GUID_NULL)) count++; if (!IsEqualGUID(&test->converter_class, &GUID_NULL)) @@ -3071,7 +3246,7 @@ todo_wine { hr = IMFTransform_GetOutputCurrentType(transform, 0, &media_type); ok(hr == S_OK, "Failed to get transform input type, hr %#lx.\n", hr); - if (IsEqualGUID(&test->converter_class, &GUID_NULL)) + if (IsEqualGUID(&test->converter_class, &GUID_NULL) && !test_transform) { hr = IMFMediaType_Compare(output_types[test->expected_output_index], (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); ok(hr == S_OK, "Failed to compare media types, hr %#lx.\n", hr); @@ -3093,9 +3268,18 @@ todo_wine { GUID class_id; hr = IMFTopologyNode_GetInput(sink_node2, 0, &mft_node, &index); - ok(hr == S_OK, "Failed to get decoder in resolved topology, hr %#lx.\n", hr); + ok(hr == S_OK, "Failed to get converter in resolved topology, hr %#lx.\n", hr); ok(!index, "Unexpected stream index %lu.\n", index); + if (test->flags & LOADER_TEST_MFT_EXPECT_CONVERTER) + { + IMFTopologyNode *test_mft_node = mft_node; + hr = IMFTopologyNode_GetInput(test_mft_node, 0, &mft_node, &index); + ok(hr == S_OK, "Failed to get converter in resolved topology, hr %#lx.\n", hr); + ok(!index, "Unexpected stream index %lu.\n", index); + IMFTopologyNode_Release(test_mft_node); + } + hr = IMFTopologyNode_GetNodeType(mft_node, &node_type); ok(hr == S_OK, "Failed to get transform node type in resolved topology, hr %#lx.\n", hr); ok(node_type == MF_TOPOLOGY_TRANSFORM_NODE, "Unexpected node type %u.\n", node_type); @@ -3182,6 +3366,23 @@ todo_wine { ok(handler.enum_complete == !!(test->flags & (LOADER_EXPECT_SINK_ENUMERATED | LOADER_EXPECT_SINK_ENUMERATED_TODO)), "Got enum_complete %u.\n", handler.enum_complete); + 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)), + "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), + "got transform output_enum_complete %u\n", test_transform->output_enum_complete); + todo_wine_if(test->flags & LOADER_TODO_MFT_IN_TYPE) + 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); + todo_wine_if(test->flags & LOADER_TODO_MFT_OUT_TYPE) + ok(test_transform->output_type_set == SUCCEEDED(test->expected_result), + "Got transform output_type_set %u.\n", test_transform->output_type_set); + IMFTransform_Release(&test_transform->IMFTransform_iface); + } + if (handler.current_type) IMFMediaType_Release(handler.current_type); handler.current_type = NULL; @@ -3198,6 +3399,10 @@ todo_wine { ok(ref == 0, "Release returned %ld\n", ref); ref = IMFStreamDescriptor_Release(sd); ok(ref == 0, "Release returned %ld\n", ref); + if (mft_input_type && test->mft_input_type) + IMFMediaType_Release(mft_input_type); + for (j = 0; j < ARRAY_SIZE(mft_output_types) && mft_output_types[j]; ++j) + IMFMediaType_Release(mft_output_types[j]); winetest_pop_context(); } @@ -3212,6 +3417,7 @@ 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); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9947
On Tue Jan 27 14:21:45 2026 +0000, Conor McCarthy wrote:
These decoded type mismatches only occur where the type is not sent to the sink, but is instead converted to RGB, so it's invisible to the app unless it goes poking around in the topology. @nsivov The tests are fixed, and I removed an unnecessary check for `!test_transform`. Do you see any local failures?
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9947#note_128264
On Wed Jan 28 13:29:19 2026 +0000, Conor McCarthy wrote:
@nsivov The tests are fixed, and I removed an unnecessary check for `!test_transform`. Do you see any local failures? I do get some failures in a VM, but Wine runs clean.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9947#note_128330
This merge request was approved by Nikolay Sivov. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9947
I just realised this doesn't have the resampler output type tests which go with the winegstreamer changes from !9935. Shall I add that commit? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9947#note_128335
On Thu Jan 29 05:53:23 2026 +0000, Conor McCarthy wrote:
I just realised this doesn't have the resampler output type tests which go with the winegstreamer changes from !9935. Shall I add that commit? Sure.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9947#note_128342
participants (3)
-
Conor McCarthy -
Conor McCarthy (@cmccarthy) -
Nikolay Sivov (@nsivov)