The app I'm considering opens a video_processor on its own, with a NV12 format on input and a ARGB32 format on output.
Tested on Windows: the samples are flipped vertically. While Wine keeps them untouched.
So added a videoflip in the video processor to be activated when needed. Current activation is based on RGB vs non RGB input/output formats.
Set as draft as if somehow related to MR!2159. Comments welcomed.
Signed-off-by: Eric Pouech epouech@codeweavers.com
-- v4: winegstreamer: In video_processor, activate a videoflip converter. mf/tests: Add tests about (negative) stride handling.
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/mf/tests/transform.c | 746 ++++++++++++++++++++++++++++++++++---- 1 file changed, 681 insertions(+), 65 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index b41f87afabe..4a86e830a40 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -4971,6 +4971,37 @@ static void test_wmv_decoder(void) ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE), {0}, }; + const struct attribute_desc output_type_desc_negative_stride[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, -actual_width), + {0}, + }; + const struct attribute_desc output_type_desc_rgb[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE), + {0}, + }; + const struct attribute_desc output_type_desc_rgb_negative_stride[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, -actual_width * 4), + {0}, + }; + const struct attribute_desc output_type_desc_rgb_positive_stride[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 4), + {0}, + }; const struct attribute_desc expect_input_type_desc[] = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -4992,12 +5023,57 @@ static void test_wmv_decoder(void) ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), {0}, }; + const struct attribute_desc expect_output_type_desc_rgb[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 4), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), + ATTR_UINT32(MF_MT_VIDEO_NOMINAL_RANGE, 2), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + {0}, + }; + const struct attribute_desc expect_output_type_desc_rgb_negative_stride[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, -actual_width * 4), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), + ATTR_UINT32(MF_MT_VIDEO_NOMINAL_RANGE, 2), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + {0}, + }; + const struct attribute_desc expect_output_type_desc_rgb_positive_stride[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 4), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), + ATTR_UINT32(MF_MT_VIDEO_NOMINAL_RANGE, 2), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + {0}, + }; const MFT_OUTPUT_STREAM_INFO expect_output_info = { .dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_DISCARDABLE, .cbSize = 0x3600, .cbAlignment = 1, }; + const MFT_OUTPUT_STREAM_INFO expect_output_info_rgb = + { + .dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_DISCARDABLE, + .cbSize = 0x9000, + .cbAlignment = 1, + }; const MFT_OUTPUT_STREAM_INFO empty_output_info = { .dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_DISCARDABLE, @@ -5007,6 +5083,11 @@ static void test_wmv_decoder(void) .cbSize = 0x3600, .cbAlignment = 1, }; + const MFT_INPUT_STREAM_INFO expect_input_info_rgb = + { + .cbSize = 0x9000, + .cbAlignment = 1, + };
const struct attribute_desc output_sample_attributes[] = { @@ -5018,12 +5099,23 @@ static void test_wmv_decoder(void) .length = actual_width * actual_height * 3 / 2, .compare = compare_nv12, .dump = dump_nv12, .rect = {.right = 82, .bottom = 84}, }; + const struct buffer_desc output_buffer_desc_rgb = + { + .length = actual_width * actual_height * 4, + .compare = compare_rgb32, .dump = dump_rgb32, .rect = {.right = 82, .bottom = 84}, + }; const struct sample_desc output_sample_desc_nv12 = { .attributes = output_sample_attributes, .sample_time = 0, .sample_duration = 333333, .buffer_count = 1, .buffers = &output_buffer_desc_nv12, }; + const struct sample_desc output_sample_desc_rgb = + { + .attributes = output_sample_attributes, + .sample_time = 0, .sample_duration = 333333, + .buffer_count = 1, .buffers = &output_buffer_desc_rgb, + };
MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Video, MFVideoFormat_NV12}; MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Video, MFVideoFormat_WMV1}; @@ -5114,6 +5206,12 @@ static void test_wmv_decoder(void) ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr); ok(i == ARRAY_SIZE(expect_available_outputs), "%lu input media types\n", i);
+ /* WMV1 -> YUV */ + winetest_push_context("WMV1 -> YUV"); + check_mft_set_input_type_required(transform, input_type_desc); + check_mft_set_input_type(transform, input_type_desc); + check_mft_get_input_current_type_(transform, expect_input_type_desc, FALSE, TRUE); + check_mft_set_output_type_required(transform, output_type_desc); check_mft_set_output_type(transform, output_type_desc, S_OK); check_mft_get_output_current_type_(transform, expect_output_type_desc, FALSE, TRUE); @@ -5158,6 +5256,211 @@ static void test_wmv_decoder(void) ret = check_mf_sample_collection(output_samples, &output_sample_desc_nv12, L"nv12frame.bmp"); ok(ret == 0, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples); + winetest_pop_context(); + + winetest_push_context("WMV1 -> YUV (negative strive)"); + check_mft_set_input_type_required(transform, input_type_desc); + check_mft_set_input_type(transform, input_type_desc); + check_mft_get_input_current_type_(transform, expect_input_type_desc, FALSE, TRUE); + + check_mft_set_output_type_required(transform, output_type_desc_negative_stride); + check_mft_set_output_type(transform, output_type_desc_negative_stride, S_OK); + check_mft_get_output_current_type_(transform, expect_output_type_desc, FALSE, TRUE); + + check_mft_get_input_stream_info(transform, S_OK, &expect_input_info); + check_mft_get_output_stream_info(transform, S_OK, &expect_output_info); + + load_resource(L"wmvencdata.bin", &wmvenc_data, &wmvenc_data_len); + + input_sample = create_sample(wmvenc_data + sizeof(DWORD), *(DWORD *)wmvenc_data); + wmvenc_data_len -= *(DWORD *)wmvenc_data + sizeof(DWORD); + wmvenc_data += *(DWORD *)wmvenc_data + sizeof(DWORD); + hr = IMFSample_SetSampleTime(input_sample, 0); + ok(hr == S_OK, "SetSampleTime returned %#lx\n", hr); + hr = IMFSample_SetSampleDuration(input_sample, 333333); + ok(hr == S_OK, "SetSampleDuration returned %#lx\n", hr); + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "ProcessInput returned %#lx\n", hr); + ret = IMFSample_Release(input_sample); + ok(ret <= 1, "Release returned %ld\n", ret); + + hr = MFCreateCollection(&output_samples); + ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr); + + output_sample = create_sample(NULL, expect_output_info.cbSize); + for (i = 0; SUCCEEDED(hr = check_mft_process_output(transform, output_sample, &output_status)); i++) + { + winetest_push_context("%lu", i); + ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr); + hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + ref = IMFSample_Release(output_sample); + ok(ref == 1, "Release returned %ld\n", ref); + output_sample = create_sample(NULL, expect_output_info.cbSize); + winetest_pop_context(); + } + ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + ok(i == 1, "got %lu output samples\n", i); + + ret = check_mf_sample_collection(output_samples, &output_sample_desc_nv12, L"nv12frame.bmp"); + ok(ret == 0, "got %lu%% diff\n", ret); + IMFCollection_Release(output_samples); + winetest_pop_context(); + + winetest_push_context("WMV1 -> RGB"); + check_mft_set_input_type_required(transform, input_type_desc); + check_mft_set_input_type(transform, input_type_desc); + check_mft_get_input_current_type_(transform, expect_input_type_desc, FALSE, TRUE); + + check_mft_set_output_type_required(transform, output_type_desc_rgb); + check_mft_set_output_type(transform, output_type_desc_rgb, S_OK); + check_mft_get_output_current_type_(transform, expect_output_type_desc_rgb, FALSE, TRUE); + + check_mft_get_input_stream_info(transform, S_OK, &expect_input_info_rgb); + check_mft_get_output_stream_info(transform, S_OK, &expect_output_info_rgb); + + load_resource(L"wmvencdata.bin", &wmvenc_data, &wmvenc_data_len); + + input_sample = create_sample(wmvenc_data + sizeof(DWORD), *(DWORD *)wmvenc_data); + wmvenc_data_len -= *(DWORD *)wmvenc_data + sizeof(DWORD); + wmvenc_data += *(DWORD *)wmvenc_data + sizeof(DWORD); + hr = IMFSample_SetSampleTime(input_sample, 0); + ok(hr == S_OK, "SetSampleTime returned %#lx\n", hr); + hr = IMFSample_SetSampleDuration(input_sample, 333333); + ok(hr == S_OK, "SetSampleDuration returned %#lx\n", hr); + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "ProcessInput returned %#lx\n", hr); + ret = IMFSample_Release(input_sample); + ok(ret <= 1, "Release returned %ld\n", ret); + + hr = MFCreateCollection(&output_samples); + ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr); + + output_sample = create_sample(NULL, expect_output_info_rgb.cbSize); + for (i = 0; SUCCEEDED(hr = check_mft_process_output(transform, output_sample, &output_status)); i++) + { + winetest_push_context("%lu", i); + ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr); + hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + ref = IMFSample_Release(output_sample); + ok(ref == 1, "Release returned %ld\n", ref); + output_sample = create_sample(NULL, expect_output_info_rgb.cbSize); + winetest_pop_context(); + } + ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + ok(i == 1, "got %lu output samples\n", i); + + ret = check_mf_sample_collection(output_samples, &output_sample_desc_rgb, L"rgb32frame-vp.bmp"); + ok(ret == 0, "got %lu%% diff\n", ret); + IMFCollection_Release(output_samples); + winetest_pop_context(); + + winetest_push_context("WMV1 -> RGB (negative stride)"); + check_mft_set_input_type_required(transform, input_type_desc); + check_mft_set_input_type(transform, input_type_desc); + check_mft_get_input_current_type_(transform, expect_input_type_desc, FALSE, TRUE); + + check_mft_set_output_type_required(transform, output_type_desc_rgb_negative_stride); + check_mft_set_output_type(transform, output_type_desc_rgb_negative_stride, S_OK); + check_mft_get_output_current_type_(transform, expect_output_type_desc_rgb_negative_stride, FALSE, TRUE); + + check_mft_get_input_stream_info(transform, S_OK, &expect_input_info_rgb); + check_mft_get_output_stream_info(transform, S_OK, &expect_output_info_rgb); + + load_resource(L"wmvencdata.bin", &wmvenc_data, &wmvenc_data_len); + + input_sample = create_sample(wmvenc_data + sizeof(DWORD), *(DWORD *)wmvenc_data); + wmvenc_data_len -= *(DWORD *)wmvenc_data + sizeof(DWORD); + wmvenc_data += *(DWORD *)wmvenc_data + sizeof(DWORD); + hr = IMFSample_SetSampleTime(input_sample, 0); + ok(hr == S_OK, "SetSampleTime returned %#lx\n", hr); + hr = IMFSample_SetSampleDuration(input_sample, 333333); + ok(hr == S_OK, "SetSampleDuration returned %#lx\n", hr); + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "ProcessInput returned %#lx\n", hr); + ret = IMFSample_Release(input_sample); + ok(ret <= 1, "Release returned %ld\n", ret); + + hr = MFCreateCollection(&output_samples); + ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr); + + output_sample = create_sample(NULL, expect_output_info_rgb.cbSize); + for (i = 0; SUCCEEDED(hr = check_mft_process_output(transform, output_sample, &output_status)); i++) + { + winetest_push_context("%lu", i); + ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr); + hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + ref = IMFSample_Release(output_sample); + ok(ref == 1, "Release returned %ld\n", ref); + output_sample = create_sample(NULL, expect_output_info_rgb.cbSize); + winetest_pop_context(); + } + ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + ok(i == 1, "got %lu output samples\n", i); + + ret = check_mf_sample_collection(output_samples, &output_sample_desc_rgb, L"rgb32frame-vp.bmp"); + ok(ret == 0, "got %lu%% diff\n", ret); + IMFCollection_Release(output_samples); + winetest_pop_context(); + + winetest_push_context("WMV1 -> RGB (positive stride)"); + check_mft_set_input_type_required(transform, input_type_desc); + check_mft_set_input_type(transform, input_type_desc); + check_mft_get_input_current_type_(transform, expect_input_type_desc, FALSE, TRUE); + + check_mft_set_output_type_required(transform, output_type_desc_rgb_positive_stride); + check_mft_set_output_type(transform, output_type_desc_rgb_positive_stride, S_OK); + check_mft_get_output_current_type_(transform, expect_output_type_desc_rgb_positive_stride, FALSE, TRUE); + + check_mft_get_input_stream_info(transform, S_OK, &expect_input_info_rgb); + check_mft_get_output_stream_info(transform, S_OK, &expect_output_info_rgb); + + load_resource(L"wmvencdata.bin", &wmvenc_data, &wmvenc_data_len); + + input_sample = create_sample(wmvenc_data + sizeof(DWORD), *(DWORD *)wmvenc_data); + wmvenc_data_len -= *(DWORD *)wmvenc_data + sizeof(DWORD); + wmvenc_data += *(DWORD *)wmvenc_data + sizeof(DWORD); + hr = IMFSample_SetSampleTime(input_sample, 0); + ok(hr == S_OK, "SetSampleTime returned %#lx\n", hr); + hr = IMFSample_SetSampleDuration(input_sample, 333333); + ok(hr == S_OK, "SetSampleDuration returned %#lx\n", hr); + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "ProcessInput returned %#lx\n", hr); + ret = IMFSample_Release(input_sample); + ok(ret <= 1, "Release returned %ld\n", ret); + + hr = MFCreateCollection(&output_samples); + ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr); + + output_sample = create_sample(NULL, expect_output_info_rgb.cbSize); + for (i = 0; SUCCEEDED(hr = check_mft_process_output(transform, output_sample, &output_status)); i++) + { + winetest_push_context("%lu", i); + ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr); + hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + ref = IMFSample_Release(output_sample); + ok(ref == 1, "Release returned %ld\n", ref); + output_sample = create_sample(NULL, expect_output_info_rgb.cbSize); + winetest_pop_context(); + } + ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + ok(i == 1, "got %lu output samples\n", i); + + ret = check_mf_sample_collection(output_samples, &output_sample_desc_rgb, L"rgb32frame-vp.bmp"); + ok(ret == 0, "got %lu%% diff\n", ret); + IMFCollection_Release(output_samples); + winetest_pop_context();
skip_tests: ret = IMFTransform_Release(transform); @@ -5591,6 +5894,22 @@ static void test_color_convert(void) ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE), {0}, }; + const struct attribute_desc output_type_desc_negative_stride[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, -actual_width * 4), + {0}, + }; + const struct attribute_desc output_type_desc_positive_stride[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 4), + {0}, + }; const struct attribute_desc expect_input_type_desc[] = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), @@ -5616,6 +5935,18 @@ static void test_color_convert(void) ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), {0}, }; + const struct attribute_desc expect_output_type_desc_negativestride[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, -actual_width * 4), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), + {0}, + }; const MFT_OUTPUT_STREAM_INFO output_info = { .cbSize = actual_width * actual_height * 4, @@ -5659,61 +5990,183 @@ static void test_color_convert(void) hr = CoInitialize(NULL); ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);
- winetest_push_context("colorconv"); + winetest_push_context("colorconv"); + + if (!check_mft_enum(MFT_CATEGORY_VIDEO_EFFECT, &input_type, &output_type, class_id)) + goto failed; + check_mft_get_info(class_id, &expect_mft_info); + check_dmo_get_info(class_id, &expect_dmo_info); + + if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, + &IID_IMFTransform, (void **)&transform))) + goto failed; + + check_interface(transform, &IID_IMFTransform, TRUE); + check_interface(transform, &IID_IMediaObject, TRUE); + check_interface(transform, &IID_IPropertyStore, TRUE); + todo_wine + check_interface(transform, &IID_IPropertyBag, FALSE); + todo_wine + check_interface(transform, &IID_IMFRealTimeClient, TRUE); + /* check_interface(transform, &IID_IWMColorConvProps, TRUE); */ + + check_mft_optional_methods(transform, 1); + check_mft_get_attributes(transform, NULL, FALSE); + check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL); + check_mft_get_output_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL); + + i = -1; + while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &media_type))) + { + winetest_push_context("out %lu", i); + ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr); + check_media_type(media_type, expect_available_common, -1); + check_media_type(media_type, expect_available_outputs[i], -1); + ret = IMFMediaType_Release(media_type); + ok(ret == 0, "Release returned %lu\n", ret); + winetest_pop_context(); + } + ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr); + ok(i == 16, "%lu output media types\n", i); + + i = -1; + while (SUCCEEDED(hr = IMFTransform_GetInputAvailableType(transform, 0, ++i, &media_type))) + { + winetest_push_context("in %lu", i); + ok(hr == S_OK, "GetInputAvailableType returned %#lx\n", hr); + check_media_type(media_type, expect_available_common, -1); + check_media_type(media_type, expect_available_inputs[i], -1); + ret = IMFMediaType_Release(media_type); + ok(ret == 0, "Release returned %lu\n", ret); + winetest_pop_context(); + } + ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr); + ok(i == 20, "%lu input media types\n", i); + + winetest_push_context("YUV -> RGB"); + check_mft_set_output_type_required(transform, output_type_desc); + check_mft_set_output_type(transform, output_type_desc, S_OK); + check_mft_get_output_current_type_(transform, expect_output_type_desc, FALSE, TRUE); + + check_mft_set_input_type_required(transform, input_type_desc); + check_mft_set_input_type(transform, input_type_desc); + check_mft_get_input_current_type_(transform, expect_input_type_desc, FALSE, TRUE); + + check_mft_get_input_stream_info(transform, S_OK, &input_info); + check_mft_get_output_stream_info(transform, S_OK, &output_info); + + load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len); + /* skip BMP header and RGB data from the dump */ + length = *(DWORD *)(nv12frame_data + 2); + nv12frame_data_len = nv12frame_data_len - length; + nv12frame_data = nv12frame_data + length; + ok(nv12frame_data_len == 13824, "got length %lu\n", nv12frame_data_len); + + input_sample = create_sample(nv12frame_data, nv12frame_data_len); + hr = IMFSample_SetSampleTime(input_sample, 0); + ok(hr == S_OK, "SetSampleTime returned %#lx\n", hr); + hr = IMFSample_SetSampleDuration(input_sample, 10000000); + ok(hr == S_OK, "SetSampleDuration returned %#lx\n", hr); + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "ProcessInput returned %#lx\n", hr); + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr); + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0); + ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr); + ret = IMFSample_Release(input_sample); + ok(ret <= 1, "Release returned %ld\n", ret); + + hr = MFCreateCollection(&output_samples); + ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr); + + output_sample = create_sample(NULL, output_info.cbSize); + hr = check_mft_process_output(transform, output_sample, &output_status); + ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr); + ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status); + hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + ref = IMFSample_Release(output_sample); + ok(ref == 1, "Release returned %ld\n", ref); + + ret = check_mf_sample_collection(output_samples, &output_sample_desc, L"rgb32frame.bmp"); + ok(ret <= 4 /* small and harmless diff in Wine vs Windows */, "got %lu%% diff\n", ret); + IMFCollection_Release(output_samples); + + output_sample = create_sample(NULL, output_info.cbSize); + hr = check_mft_process_output(transform, output_sample, &output_status); + ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); + ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status); + hr = IMFSample_GetTotalLength(output_sample, &length); + ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr); + ok(length == 0, "got length %lu\n", length); + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + winetest_pop_context(); + + winetest_push_context("YUV -> RGB (negative stride)"); + check_mft_set_output_type_required(transform, output_type_desc_negative_stride); + check_mft_set_output_type(transform, output_type_desc_negative_stride, S_OK); + check_mft_get_output_current_type_(transform, expect_output_type_desc_negativestride, FALSE, TRUE); + + check_mft_set_input_type_required(transform, input_type_desc); + check_mft_set_input_type(transform, input_type_desc); + check_mft_get_input_current_type_(transform, expect_input_type_desc, FALSE, TRUE); + + check_mft_get_input_stream_info(transform, S_OK, &input_info); + check_mft_get_output_stream_info(transform, S_OK, &output_info); + + load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len); + /* skip BMP header and RGB data from the dump */ + length = *(DWORD *)(nv12frame_data + 2); + nv12frame_data_len = nv12frame_data_len - length; + nv12frame_data = nv12frame_data + length; + ok(nv12frame_data_len == 13824, "got length %lu\n", nv12frame_data_len); + + input_sample = create_sample(nv12frame_data, nv12frame_data_len); + hr = IMFSample_SetSampleTime(input_sample, 0); + ok(hr == S_OK, "SetSampleTime returned %#lx\n", hr); + hr = IMFSample_SetSampleDuration(input_sample, 10000000); + ok(hr == S_OK, "SetSampleDuration returned %#lx\n", hr); + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "ProcessInput returned %#lx\n", hr); + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr); + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0); + ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr); + ret = IMFSample_Release(input_sample); + ok(ret <= 1, "Release returned %ld\n", ret);
- if (!check_mft_enum(MFT_CATEGORY_VIDEO_EFFECT, &input_type, &output_type, class_id)) - goto failed; - check_mft_get_info(class_id, &expect_mft_info); - check_dmo_get_info(class_id, &expect_dmo_info); + hr = MFCreateCollection(&output_samples); + ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr);
- if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, - &IID_IMFTransform, (void **)&transform))) - goto failed; + output_sample = create_sample(NULL, output_info.cbSize); + hr = check_mft_process_output(transform, output_sample, &output_status); + ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr); + ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status); + hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + ref = IMFSample_Release(output_sample); + ok(ref == 1, "Release returned %ld\n", ref);
- check_interface(transform, &IID_IMFTransform, TRUE); - check_interface(transform, &IID_IMediaObject, TRUE); - check_interface(transform, &IID_IPropertyStore, TRUE); - todo_wine - check_interface(transform, &IID_IPropertyBag, FALSE); + ret = check_mf_sample_collection(output_samples, &output_sample_desc, L"rgb32frame-vp.bmp"); todo_wine - check_interface(transform, &IID_IMFRealTimeClient, TRUE); - /* check_interface(transform, &IID_IWMColorConvProps, TRUE); */ - - check_mft_optional_methods(transform, 1); - check_mft_get_attributes(transform, NULL, FALSE); - check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL); - check_mft_get_output_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL); - - i = -1; - while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &media_type))) - { - winetest_push_context("out %lu", i); - ok(hr == S_OK, "GetOutputAvailableType returned %#lx\n", hr); - check_media_type(media_type, expect_available_common, -1); - check_media_type(media_type, expect_available_outputs[i], -1); - ret = IMFMediaType_Release(media_type); - ok(ret == 0, "Release returned %lu\n", ret); - winetest_pop_context(); - } - ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr); - ok(i == 16, "%lu output media types\n", i); + ok(ret <= 4 /* small and harmless diff in Wine vs Windows */, "got %lu%% diff\n", ret); + IMFCollection_Release(output_samples);
- i = -1; - while (SUCCEEDED(hr = IMFTransform_GetInputAvailableType(transform, 0, ++i, &media_type))) - { - winetest_push_context("in %lu", i); - ok(hr == S_OK, "GetInputAvailableType returned %#lx\n", hr); - check_media_type(media_type, expect_available_common, -1); - check_media_type(media_type, expect_available_inputs[i], -1); - ret = IMFMediaType_Release(media_type); - ok(ret == 0, "Release returned %lu\n", ret); - winetest_pop_context(); - } - ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr); - ok(i == 20, "%lu input media types\n", i); + output_sample = create_sample(NULL, output_info.cbSize); + hr = check_mft_process_output(transform, output_sample, &output_status); + ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); + ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status); + hr = IMFSample_GetTotalLength(output_sample, &length); + ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr); + ok(length == 0, "got length %lu\n", length); + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + winetest_pop_context();
- check_mft_set_output_type_required(transform, output_type_desc); - check_mft_set_output_type(transform, output_type_desc, S_OK); + winetest_push_context("YUV -> RGB (positive stride)"); + check_mft_set_output_type_required(transform, output_type_desc_positive_stride); + check_mft_set_output_type(transform, output_type_desc_positive_stride, S_OK); check_mft_get_output_current_type_(transform, expect_output_type_desc, FALSE, TRUE);
check_mft_set_input_type_required(transform, input_type_desc); @@ -5769,6 +6222,7 @@ static void test_color_convert(void) ok(length == 0, "got length %lu\n", length); ret = IMFSample_Release(output_sample); ok(ret == 0, "Release returned %lu\n", ret); + winetest_pop_context();
ret = IMFTransform_Release(transform); ok(ret == 0, "Release returned %ld\n", ret); @@ -5944,6 +6398,24 @@ static void test_video_processor(void) ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), {0}, }; + const struct attribute_desc output_type_desc_negative_stride[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE), + ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, -actual_width * 4), + {0}, + }; + const struct attribute_desc output_type_desc_positive_stride[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE), + ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 4), + {0}, + }; const MFT_OUTPUT_STREAM_INFO initial_output_info = {0}; const MFT_INPUT_STREAM_INFO initial_input_info = {0}; MFT_OUTPUT_STREAM_INFO output_info = {0}; @@ -6285,6 +6757,7 @@ static void test_video_processor(void) ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr); ok(i == 22 || i == 30 || broken(i == 26) /* w1064v1507 */, "%lu input media types\n", i);
+ winetest_push_context("YUV -> RGB"); check_mft_set_input_type_required(transform, input_type_desc); check_mft_set_input_type(transform, input_type_desc); check_mft_get_input_current_type(transform, input_type_desc); @@ -6328,31 +6801,174 @@ static void test_video_processor(void) if (hr != S_OK) { win_skip("ProcessOutput returned MF_E_SHUTDOWN, skipping tests.\n"); - goto skip_output; } - ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status); + else + { + ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
- hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample); - ok(hr == S_OK, "AddElement returned %#lx\n", hr); - ref = IMFSample_Release(output_sample); - ok(ref == 1, "Release returned %ld\n", ref); + hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + ref = IMFSample_Release(output_sample); + ok(ref == 1, "Release returned %ld\n", ref);
- ret = check_mf_sample_collection(output_samples, &output_sample_desc, L"rgb32frame-vp.bmp"); - todo_wine - ok(ret == 0 || broken(ret == 25) /* w1064v1507 / w1064v1809 incorrectly rescale */, "got %lu%% diff\n", ret); - IMFCollection_Release(output_samples); + ret = check_mf_sample_collection(output_samples, &output_sample_desc, L"rgb32frame-vp.bmp"); + todo_wine + ok(ret == 0 || broken(ret == 25) /* w1064v1507 / w1064v1809 incorrectly rescale */, "got %lu%% diff\n", ret); + IMFCollection_Release(output_samples); + + output_sample = create_sample(NULL, output_info.cbSize); + hr = check_mft_process_output(transform, output_sample, &output_status); + ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); + ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status); + hr = IMFSample_GetTotalLength(output_sample, &length); + ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr); + ok(length == 0, "got length %lu\n", length); + } + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + winetest_pop_context(); + + winetest_push_context("YUV -> RGB (negative stride)"); + check_mft_set_input_type_required(transform, input_type_desc); + check_mft_set_input_type(transform, input_type_desc); + check_mft_get_input_current_type(transform, input_type_desc); + + check_mft_set_output_type_required(transform, output_type_desc_negative_stride); + check_mft_set_output_type(transform, output_type_desc_negative_stride, S_OK); + check_mft_get_output_current_type(transform, output_type_desc_negative_stride); + + input_info.cbSize = actual_width * actual_height * 3 / 2; + output_info.cbSize = actual_width * actual_height * 4; + check_mft_get_input_stream_info(transform, S_OK, &input_info); + check_mft_get_output_stream_info(transform, S_OK, &output_info); + + load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len); + /* skip BMP header and RGB data from the dump */ + length = *(DWORD *)(nv12frame_data + 2); + nv12frame_data_len = nv12frame_data_len - length; + nv12frame_data = nv12frame_data + length; + ok(nv12frame_data_len == 13824, "got length %lu\n", nv12frame_data_len); + + input_sample = create_sample(nv12frame_data, nv12frame_data_len); + hr = IMFSample_SetSampleTime(input_sample, 0); + ok(hr == S_OK, "SetSampleTime returned %#lx\n", hr); + hr = IMFSample_SetSampleDuration(input_sample, 10000000); + ok(hr == S_OK, "SetSampleDuration returned %#lx\n", hr); + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "ProcessInput returned %#lx\n", hr); + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr); + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0); + ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr); + ret = IMFSample_Release(input_sample); + ok(ret <= 1, "Release returned %ld\n", ret); + + hr = MFCreateCollection(&output_samples); + ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr);
output_sample = create_sample(NULL, output_info.cbSize); hr = check_mft_process_output(transform, output_sample, &output_status); - ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); - ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status); - hr = IMFSample_GetTotalLength(output_sample, &length); - ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr); - ok(length == 0, "got length %lu\n", length); + ok(hr == S_OK || broken(hr == MF_E_SHUTDOWN) /* w8 */, "ProcessOutput returned %#lx\n", hr); + if (hr != S_OK) + { + win_skip("ProcessOutput returned MF_E_SHUTDOWN, skipping tests.\n"); + } + else + { + ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status); + + hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + ref = IMFSample_Release(output_sample); + ok(ref == 1, "Release returned %ld\n", ref); + + ret = check_mf_sample_collection(output_samples, &output_sample_desc, L"rgb32frame-vp.bmp"); + todo_wine + ok(ret == 0 || broken(ret == 25) /* w1064v1507 / w1064v1809 incorrectly rescale */, "got %lu%% diff\n", ret); + IMFCollection_Release(output_samples); + + output_sample = create_sample(NULL, output_info.cbSize); + hr = check_mft_process_output(transform, output_sample, &output_status); + ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); + ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status); + hr = IMFSample_GetTotalLength(output_sample, &length); + ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr); + ok(length == 0, "got length %lu\n", length); + } + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + winetest_pop_context(); + + winetest_push_context("YUV -> RGB (positive stride)"); + check_mft_set_input_type_required(transform, input_type_desc); + check_mft_set_input_type(transform, input_type_desc); + check_mft_get_input_current_type(transform, input_type_desc); + + check_mft_set_output_type_required(transform, output_type_desc_positive_stride); + check_mft_set_output_type(transform, output_type_desc_positive_stride, S_OK); + check_mft_get_output_current_type(transform, output_type_desc_positive_stride); + + input_info.cbSize = actual_width * actual_height * 3 / 2; + output_info.cbSize = actual_width * actual_height * 4; + check_mft_get_input_stream_info(transform, S_OK, &input_info); + check_mft_get_output_stream_info(transform, S_OK, &output_info); + + load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len); + /* skip BMP header and RGB data from the dump */ + length = *(DWORD *)(nv12frame_data + 2); + nv12frame_data_len = nv12frame_data_len - length; + nv12frame_data = nv12frame_data + length; + ok(nv12frame_data_len == 13824, "got length %lu\n", nv12frame_data_len); + + input_sample = create_sample(nv12frame_data, nv12frame_data_len); + hr = IMFSample_SetSampleTime(input_sample, 0); + ok(hr == S_OK, "SetSampleTime returned %#lx\n", hr); + hr = IMFSample_SetSampleDuration(input_sample, 10000000); + ok(hr == S_OK, "SetSampleDuration returned %#lx\n", hr); + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "ProcessInput returned %#lx\n", hr); + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr); + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0); + ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr); + ret = IMFSample_Release(input_sample); + ok(ret <= 1, "Release returned %ld\n", ret); + + hr = MFCreateCollection(&output_samples); + ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr); + + output_sample = create_sample(NULL, output_info.cbSize); + hr = check_mft_process_output(transform, output_sample, &output_status); + ok(hr == S_OK || broken(hr == MF_E_SHUTDOWN) /* w8 */, "ProcessOutput returned %#lx\n", hr); + if (hr != S_OK) + { + win_skip("ProcessOutput returned MF_E_SHUTDOWN, skipping tests.\n"); + } + else + { + ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status);
-skip_output: + hr = IMFCollection_AddElement(output_samples, (IUnknown *)output_sample); + ok(hr == S_OK, "AddElement returned %#lx\n", hr); + ref = IMFSample_Release(output_sample); + ok(ref == 1, "Release returned %ld\n", ref); + + ret = check_mf_sample_collection(output_samples, &output_sample_desc, L"rgb32frame.bmp"); + todo_wine + ok(ret == 0 || broken(ret == 25) /* w1064v1507 / w1064v1809 incorrectly rescale */, "got %lu%% diff\n", ret); + IMFCollection_Release(output_samples); + + output_sample = create_sample(NULL, output_info.cbSize); + hr = check_mft_process_output(transform, output_sample, &output_status); + ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); + ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status); + hr = IMFSample_GetTotalLength(output_sample, &length); + ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr); + ok(length == 0, "got length %lu\n", length); + } ret = IMFSample_Release(output_sample); ok(ret == 0, "Release returned %lu\n", ret); + winetest_pop_context();
ret = IMFTransform_Release(transform); ok(ret == 0, "Release returned %ld\n", ret);
From: Eric Pouech eric.pouech@gmail.com
The app I'm considering opens a video_processor on its own, with a NV12 format on input and a ARGB32 format on output.
Tested on Windows: the samples are flipped vertically. While Wine keeps them untouched.
So added a videoflip in the video processor to be activated when needed. This patch depends on MR!2159.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/mf/tests/transform.c | 18 +++++++----------- dlls/winegstreamer/color_convert.c | 4 ++++ dlls/winegstreamer/gst_private.h | 2 ++ dlls/winegstreamer/mfplat.c | 26 +++++++++++++++----------- dlls/winegstreamer/quartz_parser.c | 1 + dlls/winegstreamer/video_decoder.c | 2 -- dlls/winegstreamer/video_processor.c | 6 ++++++ dlls/winegstreamer/wg_transform.c | 25 +++++++++++++++++++++++++ dlls/winegstreamer/wmv_decoder.c | 3 +++ 9 files changed, 63 insertions(+), 24 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 4a86e830a40..f448a2675ca 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -5356,7 +5356,7 @@ static void test_wmv_decoder(void) ok(i == 1, "got %lu output samples\n", i);
ret = check_mf_sample_collection(output_samples, &output_sample_desc_rgb, L"rgb32frame-vp.bmp"); - ok(ret == 0, "got %lu%% diff\n", ret); + ok(ret <= 5, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples); winetest_pop_context();
@@ -5407,7 +5407,7 @@ static void test_wmv_decoder(void) ok(i == 1, "got %lu output samples\n", i);
ret = check_mf_sample_collection(output_samples, &output_sample_desc_rgb, L"rgb32frame-vp.bmp"); - ok(ret == 0, "got %lu%% diff\n", ret); + ok(ret <= 5, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples); winetest_pop_context();
@@ -5458,7 +5458,7 @@ static void test_wmv_decoder(void) ok(i == 1, "got %lu output samples\n", i);
ret = check_mf_sample_collection(output_samples, &output_sample_desc_rgb, L"rgb32frame-vp.bmp"); - ok(ret == 0, "got %lu%% diff\n", ret); + ok(ret <= 5, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples); winetest_pop_context();
@@ -6149,8 +6149,7 @@ static void test_color_convert(void) ok(ref == 1, "Release returned %ld\n", ref);
ret = check_mf_sample_collection(output_samples, &output_sample_desc, L"rgb32frame-vp.bmp"); - todo_wine - ok(ret <= 4 /* small and harmless diff in Wine vs Windows */, "got %lu%% diff\n", ret); + ok(ret <= 6 /* small and harmless diff in Wine vs Windows */, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples);
output_sample = create_sample(NULL, output_info.cbSize); @@ -6812,8 +6811,7 @@ static void test_video_processor(void) ok(ref == 1, "Release returned %ld\n", ref);
ret = check_mf_sample_collection(output_samples, &output_sample_desc, L"rgb32frame-vp.bmp"); - todo_wine - ok(ret == 0 || broken(ret == 25) /* w1064v1507 / w1064v1809 incorrectly rescale */, "got %lu%% diff\n", ret); + ok(ret <= 2 || broken(ret == 25) /* w1064v1507 / w1064v1809 incorrectly rescale */, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples);
output_sample = create_sample(NULL, output_info.cbSize); @@ -6883,8 +6881,7 @@ static void test_video_processor(void) ok(ref == 1, "Release returned %ld\n", ref);
ret = check_mf_sample_collection(output_samples, &output_sample_desc, L"rgb32frame-vp.bmp"); - todo_wine - ok(ret == 0 || broken(ret == 25) /* w1064v1507 / w1064v1809 incorrectly rescale */, "got %lu%% diff\n", ret); + ok(ret <= 2 || broken(ret == 25) /* w1064v1507 / w1064v1809 incorrectly rescale */, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples);
output_sample = create_sample(NULL, output_info.cbSize); @@ -6954,8 +6951,7 @@ static void test_video_processor(void) ok(ref == 1, "Release returned %ld\n", ref);
ret = check_mf_sample_collection(output_samples, &output_sample_desc, L"rgb32frame.bmp"); - todo_wine - ok(ret == 0 || broken(ret == 25) /* w1064v1507 / w1064v1809 incorrectly rescale */, "got %lu%% diff\n", ret); + ok(ret <= 6 || broken(ret == 25) /* w1064v1507 / w1064v1809 incorrectly rescale */, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples);
output_sample = create_sample(NULL, output_info.cbSize); diff --git a/dlls/winegstreamer/color_convert.c b/dlls/winegstreamer/color_convert.c index 0eaddc687ee..0bec0ad4895 100644 --- a/dlls/winegstreamer/color_convert.c +++ b/dlls/winegstreamer/color_convert.c @@ -106,10 +106,14 @@ static HRESULT try_create_wg_transform(struct color_convert *impl) mf_media_type_to_wg_format(impl->input_type, &input_format); if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE; + if (!wg_video_adapt_from_mf_stride(&input_format, impl->input_type)) + input_format.u.video.height = abs(input_format.u.video.height);
mf_media_type_to_wg_format(impl->output_type, &output_format); if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE; + if (!wg_video_adapt_from_mf_stride(&output_format, impl->output_type)) + output_format.u.video.height = abs(output_format.u.video.height);
if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format))) return E_FAIL; diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 04ec84c7936..4393aa162ec 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -152,6 +152,8 @@ unsigned int wg_format_get_stride(const struct wg_format *format);
bool wg_video_format_is_rgb(enum wg_video_format format);
+bool wg_video_adapt_from_mf_stride(struct wg_format *format, IMFMediaType *type); + HRESULT aac_decoder_create(REFIID riid, void **ret); HRESULT h264_decoder_create(REFIID riid, void **ret); HRESULT video_processor_create(REFIID riid, void **ret); diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 9cf98ec9dc4..65ef9b3b46f 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -697,7 +697,7 @@ static void mf_media_type_to_wg_format_video(IMFMediaType *type, const GUID *sub { UINT64 frame_rate, frame_size; MFVideoArea aperture; - UINT32 size, stride; + UINT32 size;
if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) { @@ -727,16 +727,6 @@ static void mf_media_type_to_wg_format_video(IMFMediaType *type, const GUID *sub }
format->u.video.format = mf_video_format_to_wg(subtype); - - if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_DEFAULT_STRIDE, &stride))) - { - if ((int)stride < 0) - format->u.video.height = -format->u.video.height; - } - else if (wg_video_format_is_rgb(format->u.video.format)) - { - format->u.video.height = -format->u.video.height; - } }
static void mf_media_type_to_wg_format_audio_wma(IMFMediaType *type, const GUID *subtype, struct wg_format *format) @@ -901,3 +891,17 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) else FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type)); } + +bool wg_video_adapt_from_mf_stride(struct wg_format *format, IMFMediaType *type) +{ + UINT32 stride; + + if (format->major_type == WG_MAJOR_TYPE_VIDEO) + { + if (!SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_DEFAULT_STRIDE, &stride))) + return false; + if ((int)stride < 0) + format->u.video.height = -format->u.video.height; + } + return true; +} diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index a5eb939fcbb..707bd694392 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -703,6 +703,7 @@ static bool amt_to_wg_format_video(const AM_MEDIA_TYPE *mt, struct wg_format *fo {&MEDIASUBTYPE_RGB565, WG_VIDEO_FORMAT_RGB16}, {&MEDIASUBTYPE_AYUV, WG_VIDEO_FORMAT_AYUV}, {&MEDIASUBTYPE_I420, WG_VIDEO_FORMAT_I420}, + {&MEDIASUBTYPE_IYUV, WG_VIDEO_FORMAT_I420}, {&MEDIASUBTYPE_NV12, WG_VIDEO_FORMAT_NV12}, {&MEDIASUBTYPE_UYVY, WG_VIDEO_FORMAT_UYVY}, {&MEDIASUBTYPE_YUY2, WG_VIDEO_FORMAT_YUY2}, diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 66df8173038..0087e12abe3 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -310,8 +310,6 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF { mf_media_type_to_wg_format(decoder->output_type, &output_format);
- output_format.u.video.width = frame_size >> 32; - output_format.u.video.height = (UINT32)frame_size; output_format.u.video.fps_d = 0; output_format.u.video.fps_n = 0;
diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 21bc46b0bb3..46103b46f14 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -96,10 +96,16 @@ static HRESULT try_create_wg_transform(struct video_processor *impl) mf_media_type_to_wg_format(impl->input_type, &input_format); if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE; + if (!wg_video_adapt_from_mf_stride(&input_format, impl->input_type) + && wg_video_format_is_rgb(input_format.u.video.format)) + input_format.u.video.height = -input_format.u.video.height;
mf_media_type_to_wg_format(impl->output_type, &output_format); if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE; + if (!wg_video_adapt_from_mf_stride(&output_format, impl->output_type) + && wg_video_format_is_rgb(output_format.u.video.format)) + output_format.u.video.height = -output_format.u.video.height;
if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format))) return E_FAIL; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index ccdd90361fc..ff42f7a2b0c 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -56,6 +56,9 @@ struct wg_transform guint input_max_length; GstAtomicQueue *input_queue;
+ bool input_is_flipped; + GstElement *video_flip; + guint output_plane_align; struct wg_sample *output_wg_sample; GstAtomicQueue *output_queue; @@ -347,6 +350,12 @@ static struct wg_sample *transform_request_sample(gsize size, void *context) return InterlockedExchangePointer((void **)&transform->output_wg_sample, NULL); }
+static bool wg_format_need_video_flip(const struct wg_transform *transform, const struct wg_format *format) +{ + return format->major_type == WG_MAJOR_TYPE_VIDEO + && transform->input_is_flipped != (format->u.video.height < 0); +} + NTSTATUS wg_transform_create(void *args) { struct wg_transform_create_params *params = args; @@ -475,6 +484,17 @@ NTSTATUS wg_transform_create(void *args) goto out; /* Let GStreamer choose a default number of threads. */ gst_util_set_object_arg(G_OBJECT(element), "n-threads", "0"); + if (!(transform->video_flip = create_element("videoflip", "base")) + || !transform_append_element(transform, transform->video_flip, &first, &last)) + goto out; + if (input_format.major_type == WG_MAJOR_TYPE_VIDEO) + transform->input_is_flipped = (input_format.u.video.height < 0); + else + transform->input_is_flipped = false; + if (wg_format_need_video_flip(transform, &output_format)) + { + gst_util_set_object_arg(G_OBJECT(transform->video_flip), "method", "vertical-flip"); + } break;
case WG_MAJOR_TYPE_AUDIO_MPEG1: @@ -588,6 +608,11 @@ NTSTATUS wg_transform_set_output_format(void *args) gst_caps_unref(transform->output_caps); transform->output_caps = caps;
+ if (transform->video_flip) + { + gst_util_set_object_arg(G_OBJECT(transform->video_flip), "method", + wg_format_need_video_flip(transform, format) ? "vertical-flip" : "none"); + } if (!gst_pad_push_event(transform->my_sink, gst_event_new_reconfigure())) { GST_ERROR("Failed to reconfigure transform %p.", transform); diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index 82c69776bd6..14867422565 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -584,6 +584,9 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde if (flags & DMO_SET_TYPEF_TEST_ONLY) return S_OK;
+ if (wg_video_format_is_rgb(wg_format.u.video.format)) + wg_format.u.video.height = -wg_format.u.video.height; + decoder->output_subtype = type->subtype; decoder->output_format = wg_format;
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=131855
Your paranoid android.
=== w1064v1507 (32 bit report) ===
mf: transform.c:6954: Test failed: videoproc: YUV -> RGB (positive stride): got 32% diff
=== w1064v1809 (32 bit report) ===
mf: transform.c:6954: Test failed: videoproc: YUV -> RGB (positive stride): got 32% diff
=== w1064v1507 (64 bit report) ===
mf: transform.c:6954: Test failed: videoproc: YUV -> RGB (positive stride): got 32% diff
=== w1064v1809 (64 bit report) ===
mf: transform.c:6954: Test failed: videoproc: YUV -> RGB (positive stride): got 32% diff
=== debian11 (32 bit report) ===
mf: transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005.
=== debian11 (32 bit ar:MA report) ===
mf: transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005.
=== debian11 (32 bit de report) ===
mf: transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005.
=== debian11 (32 bit fr report) ===
mf: transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005.
=== debian11 (32 bit he:IL report) ===
mf: transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005.
=== debian11 (32 bit hi:IN report) ===
mf: transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005.
=== debian11 (32 bit ja:JP report) ===
mf: transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005.
=== debian11 (32 bit zh:CN report) ===
mf: transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005.
=== debian11b (32 bit WoW report) ===
mf: transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005.
=== debian11b (64 bit WoW report) ===
mf: transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test succeeded inside todo block: wmvdec: out 2: SetOutputType returned 0. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005. transform.c:5644: Test failed: wmvdec: out 11: SetOutputType returned 0x80004005.
V3 pushed V2 => V3: - added a bunch of tests about effect of MF_MT_DEFAULT_STRIDE (positive value, negative value, no value) - Note: the tests results on windows are not pixel perfect compared to rgb32 frame (flipped or not) (checked the variations: there are of same nature as the one analyzed in V1 on gstreamer: smoothing on band vertical transition and right hand-side vertical bar...) the net results of the tests is: ``` | | | | MF output format | MF output format w/ | MF output format w/ | | | From | To | w/o stride | positive stride | negative stride | |-----------------+------+-----+------------------+---------------------+---------------------| | decode | WMV | YUV | no flip | no flip | no flip | | decode | WMV | RGB | flip | flip | flip | | color conv | YUV | RGB | no flip | no flip | flip | | video processor | YUV | RGB | flip | no flip | flip | ``` so it looks like it up to the caller of tranform to adapt the flipping (eg. decode seems to use only output type (rgb => flipped) without taking care of sign), while color_conv and video_processor seem to use sign of stride to enable (or not flip), but differ on behavior when stride isn't present Adapted callers to wg_transform to follow this.