[PATCH v3 0/2] MR7563: mf/tests: Tests timestamp values on output samples from the H.264 and WMV MFT decoders.
These tests serve to illustrate the output sample time and duration values from their respective native MFT video decoders with respect to the following circumstances: 1. When no frame rate nor input sample timestamps are provided; 2. When a frame rate is provided but there are no sample timestamps; and 3. When a frame rate is provided, but the input sample timestamps disagree with this value It also highlights the gap in our implementation. However, I don't believe this can be fixed without first confirming the correct output from our IMFMediaStream implementations. -- v3: mf/tests: Test timestamps in WMV decoder. mf/tests: Test timestamps in H264 decoder. https://gitlab.winehq.org/wine/wine/-/merge_requests/7563
From: Brendan McGrath <bmcgrath(a)codeweavers.com> --- dlls/mf/tests/transform.c | 308 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 439d8ee9d54..1d3625fa5e5 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -5075,6 +5075,313 @@ failed: CoUninitialize(); } +static void test_h264_decoder_timestamps(void) +{ + struct timestamps + { + LONGLONG time; + LONGLONG duration; + LONGLONG dts; + }; + + static const DWORD actual_width = 96, actual_height = 96; + + const GUID *const class_id = &CLSID_MSH264DecoderMFT; + const struct attribute_desc input_type_nofps_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_H264, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height), + {0}, + }; + const struct attribute_desc output_type_nofps_desc[] = + { + 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), + {0}, + }; + + const struct attribute_desc input_type_24fps_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_H264, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height), + ATTR_RATIO(MF_MT_FRAME_RATE, 24, 1), + {0}, + }; + const struct attribute_desc output_type_24fps_desc[] = + { + 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_RATIO(MF_MT_FRAME_RATE, 24, 1), + {0}, + }; + static const struct timestamps exp_nofps[] = + { + { 0 , 333667 }, + { 333667, 333667 }, + { 667334, 333667 }, + { 1001001, 333667 }, + { 1334668, 333667 }, + { 1668335, 333667 }, + { 2002002, 333667 }, + { 2335669, 333667 }, + { 2669336, 333667 }, + { 3003003, 333667 }, + }; + static const struct timestamps exp_24fps[] = + { + { 0, 416667 }, + { 416667, 416667 }, + { 833334, 416667 }, + { 1250001, 416667 }, + { 1666668, 416667 }, + { 2083335, 416667 }, + { 2500002, 416667 }, + { 2916669, 416667 }, + { 3333336, 416667 }, + { 3750003, 416667 }, + }; + static const struct timestamps input_sample_ts[] = + { + { 1334666, 333667, 667333 }, + { 1334666, 333667, 667333 }, + { 1334666, 333667, 667333 }, + { 2669332, 333667, 1000999 }, + { 2001999, 333666, 1334666 }, + { 1668333, 333666 }, + { 2335665, 333667, 2001999 }, + { 4003999, 333667, 2335666 }, + { 3336666, 333666, 2669333 }, + { 3002999, 333667 }, + { 3670332, 333667, 3336666 }, + { 5338666, 333667, 3670333 }, + { 4671332, 333667, 4003999 }, + { 4337666, 333666 }, + { 5004999, 333667, 4671333 }, + { 6673332, 333667, 5004999 }, + { 6005999, 333666, 5338666 }, + { 5672333, 333666 }, + { 6339665, 333667, 6005999 }, + { 8007999, 333667, 6339666 }, + { 7340666, 333666, 6673333 }, + { 7006999, 333667 }, + { 7674332, 333667, 7340666 }, + { 9342666, 333667, 7674333 }, + { 8675332, 333667, 8007999 }, + { 8341666, 333666 }, + { 9008999, 333667, 8675333 }, + { 10677332, 333667, 9008999 }, + { 10009999, 333666, 9342666 }, + { 9676333, 333666 }, + { 10343665, 333667, 10009999 }, + { 12011999, 333667, 10343666 }, + { 11344666, 333666, 10677333 }, + { 11010999, 333667 }, + { 11678332, 333667, 11344666 }, + { 13346666, 333667, 11678333 }, + }; + static const struct timestamps exp_sample_ts[] = + { + { 1334666, 333667 }, + { 1668333, 333666 }, + { 2001999, 333666 }, + { 2335665, 333667 }, + { 2669332, 333667 }, + { 3002999, 333667 }, + { 3336666, 333666 }, + { 3670332, 333667 }, + { 4003999, 333667 }, + { 4337666, 333666 }, + }; + + IMFSample *input_sample, *output_sample; + const BYTE *h264_encoded_data; + ULONG h264_encoded_data_len; + IMFTransform *transform; + LONGLONG duration, time; + DWORD output_status; + ULONG i, j, ret; + HRESULT hr; + + hr = CoInitialize(NULL); + ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr); + + winetest_push_context("h264dec timestamps"); + + /* Test when no framerate is provided and samples contain no timestamps */ + if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, + &IID_IMFTransform, (void **)&transform))) + goto failed; + + load_resource(L"h264data.bin", &h264_encoded_data, &h264_encoded_data_len); + + check_mft_set_input_type(transform, input_type_nofps_desc, S_OK); + check_mft_set_output_type(transform, output_type_nofps_desc, S_OK); + + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0); + ok(hr == S_OK, "Got %#lx\n", hr); + + output_sample = create_sample(NULL, actual_width * actual_height * 2); + for (i = 0; i < ARRAYSIZE(exp_nofps);) + { + winetest_push_context("output %ld", i); + hr = check_mft_process_output(transform, output_sample, &output_status); + ok(hr == S_OK || hr == MF_E_TRANSFORM_STREAM_CHANGE || hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); + if (hr == S_OK) + { + hr = IMFSample_GetSampleTime(output_sample, &time); + ok(hr == S_OK, "Got %#lx\n", hr); + todo_wine_if(i) + ok(time == exp_nofps[i].time, "got time %I64d, expected %I64d\n", time, exp_nofps[i].time); + hr = IMFSample_GetSampleDuration(output_sample, &duration); + ok(hr == S_OK, "Got %#lx\n", hr); + todo_wine + ok(duration == exp_nofps[i].duration, "got duration %I64d, expected %I64d\n", duration, exp_nofps[i].duration); + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + output_sample = create_sample(NULL, actual_width * actual_height * 2); + i++; + } + else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) + { + input_sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len); + 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 %lu\n", ret); + } + winetest_pop_context(); + } + + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + ret = IMFTransform_Release(transform); + ok(ret == 0, "Release returned %lu\n", ret); + + /* Test when 24fps framerate is provided and samples contain no timestamps */ + hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, + &IID_IMFTransform, (void **)&transform); + ok(hr == S_OK, "Got %#lx\n", hr); + + load_resource(L"h264data.bin", &h264_encoded_data, &h264_encoded_data_len); + + check_mft_set_input_type(transform, input_type_24fps_desc, S_OK); + check_mft_set_output_type(transform, output_type_24fps_desc, S_OK); + + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0); + ok(hr == S_OK, "Got %#lx\n", hr); + + output_sample = create_sample(NULL, actual_width * actual_height * 2); + for (i = 0; i < ARRAYSIZE(exp_24fps);) + { + winetest_push_context("output %ld", i); + hr = check_mft_process_output(transform, output_sample, &output_status); + ok(hr == S_OK || hr == MF_E_TRANSFORM_STREAM_CHANGE || hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); + if (hr == S_OK) + { + hr = IMFSample_GetSampleTime(output_sample, &time); + ok(hr == S_OK, "Got %#lx\n", hr); + todo_wine_if(i) + ok(time == exp_24fps[i].time, "got time %I64d, expected %I64d\n", time, exp_24fps[i].time); + hr = IMFSample_GetSampleDuration(output_sample, &duration); + ok(hr == S_OK, "Got %#lx\n", hr); + todo_wine + ok(duration == exp_24fps[i].duration, "got duration %I64d, expected %I64d\n", duration, exp_24fps[i].duration); + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + output_sample = create_sample(NULL, actual_width * actual_height * 2); + i++; + } + else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) + { + input_sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len); + 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 %lu\n", ret); + } + winetest_pop_context(); + } + + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + ret = IMFTransform_Release(transform); + ok(ret == 0, "Release returned %lu\n", ret); + + /* Test when supplied sample timestamps disagree with MT_MF_FRAME_RATE */ + hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, + &IID_IMFTransform, (void **)&transform); + ok(hr == S_OK, "Got %#lx\n", hr); + + load_resource(L"h264data.bin", &h264_encoded_data, &h264_encoded_data_len); + + check_mft_set_input_type(transform, input_type_24fps_desc, S_OK); + check_mft_set_output_type(transform, output_type_24fps_desc, S_OK); + + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0); + ok(hr == S_OK, "Got %#lx\n", hr); + + j = 0; + output_sample = create_sample(NULL, actual_width * actual_height * 2); + for (i = 0; i < ARRAYSIZE(exp_sample_ts);) + { + winetest_push_context("output %ld", i); + hr = check_mft_process_output(transform, output_sample, &output_status); + ok(hr == S_OK || hr == MF_E_TRANSFORM_STREAM_CHANGE || hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); + if (hr == S_OK) + { + hr = IMFSample_GetSampleTime(output_sample, &time); + ok(hr == S_OK, "Got %#lx\n", hr); + todo_wine_if(i) + ok(time == exp_sample_ts[i].time, "got time %I64d, expected %I64d\n", time, exp_sample_ts[i].time); + hr = IMFSample_GetSampleDuration(output_sample, &duration); + ok(hr == S_OK, "Got %#lx\n", hr); + todo_wine + ok(duration == exp_sample_ts[i].duration, "got duration %I64d, expected %I64d\n", duration, exp_sample_ts[i].duration); + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + output_sample = create_sample(NULL, actual_width * actual_height * 2); + i++; + } + else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT && j < ARRAYSIZE(input_sample_ts)) + { + input_sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len); + hr = IMFSample_SetSampleTime(input_sample, input_sample_ts[j].time); + ok(hr == S_OK, "Got %#lx\n", hr); + hr = IMFSample_SetSampleDuration(input_sample, input_sample_ts[j].duration); + ok(hr == S_OK, "Got %#lx\n", hr); + if (input_sample_ts[j].dts) + { + hr = IMFSample_SetUINT64(input_sample, &MFSampleExtension_DecodeTimestamp, input_sample_ts[j].dts); + ok(hr == S_OK, "Got %#lx\n", hr); + } + j++; + 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 %lu\n", ret); + } + else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT && j == ARRAYSIZE(input_sample_ts)) + { + ok(0, "no more input to provide\n"); + i = ARRAYSIZE(exp_sample_ts); + } + winetest_pop_context(); + } + + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + ret = IMFTransform_Release(transform); + ok(ret == 0, "Release returned %lu\n", ret); + +failed: + winetest_pop_context(); + CoUninitialize(); +} + static void test_h264_decoder_concat_streams(void) { const struct buffer_desc output_buffer_desc[] = @@ -10444,6 +10751,7 @@ START_TEST(transform) test_wma_decoder_dmo_output_type(); test_h264_encoder(); test_h264_decoder(); + test_h264_decoder_timestamps(); test_wmv_encoder(); test_wmv_decoder(); test_wmv_decoder_dmo_input_type(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/7563
From: Brendan McGrath <bmcgrath(a)codeweavers.com> --- dlls/mf/tests/transform.c | 294 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 1d3625fa5e5..0c1ca0a22b6 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -7059,6 +7059,299 @@ failed: CoUninitialize(); } +static void test_wmv_decoder_timestamps(void) +{ + struct timestamps + { + LONGLONG time; + LONGLONG duration; + }; + + static const DWORD actual_width = 96, actual_height = 96; + + const GUID *const class_id = &CLSID_CWMVDecMediaObject; + const struct attribute_desc input_type_nofps_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV1, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE, .todo = TRUE), + {0}, + }; + const struct attribute_desc output_type_nofps_desc[] = + { + 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), + {0}, + }; + + const struct attribute_desc input_type_24fps_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV1, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE, .todo = TRUE), + ATTR_RATIO(MF_MT_FRAME_RATE, 24, 1,), + {0}, + }; + const struct attribute_desc output_type_24fps_desc[] = + { + 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_RATIO(MF_MT_FRAME_RATE, 24, 1,), + {0}, + }; + static const struct timestamps exp_nofps[] = + { + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + }; + static const struct timestamps exp_24fps[] = + { + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + }; + static const struct timestamps input_sample_ts[] = + { + { 666666, 166667 }, + { 833333, 166666 }, + { 999999, 166666 }, + { 1166665, 166667 }, + { 1333332, 166667 }, + { 1499999, 166667 }, + { 1666666, 166666 }, + { 1833332, 166667 }, + { 1999999, 166667 }, + { 2166666, 166666 }, + { 2333332, 166667 }, + { 2499999, 166667 }, + { 2666666, 166667 }, + { 2833333, 166666 }, + { 2999999, 166666 }, + { 3166665, 166667 }, + { 3333332, 166667 }, + { 3499999, 166667 }, + { 3666666, 166666 }, + { 3833332, 166667 }, + { 3999999, 166667 }, + }; + static const struct timestamps exp_sample_ts[] = + { + { 666666, 166667 }, + { 833333, 166666 }, + { 999999, 166666 }, + { 1166665, 166667 }, + { 1333332, 166667 }, + { 1499999, 166667 }, + { 1666666, 166666 }, + { 1833332, 166667 }, + { 1999999, 166667 }, + { 2166666, 166666 }, + }; + + IMFSample *input_sample, *output_sample; + IMFTransform *transform; + LONGLONG duration, time; + const BYTE *wmvenc_data; + ULONG wmvenc_data_len; + DWORD output_status; + ULONG i, j, ret; + HRESULT hr; + + hr = CoInitialize(NULL); + ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr); + + winetest_push_context("wmvdec timestamps"); + + /* Test when no framerate is provided and samples contain no timestamps */ + if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, + &IID_IMFTransform, (void **)&transform))) + goto failed; + + load_resource(L"wmvencdata.bin", &wmvenc_data, &wmvenc_data_len); + + check_mft_set_input_type(transform, input_type_nofps_desc, S_OK); + check_mft_set_output_type(transform, output_type_nofps_desc, S_OK); + + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0); + ok(hr == S_OK, "Got %#lx\n", hr); + + output_sample = create_sample(NULL, actual_width * actual_height * 2); + for (i = 0; i < ARRAYSIZE(exp_nofps);) + { + winetest_push_context("output %ld", i); + hr = check_mft_process_output(transform, output_sample, &output_status); + ok(hr == S_OK || hr == MF_E_TRANSFORM_STREAM_CHANGE || hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); + if (hr == S_OK) + { + hr = IMFSample_GetSampleTime(output_sample, &time); + ok(hr == S_OK, "Got %#lx\n", hr); + todo_wine_if(i) + ok(time == exp_nofps[i].time, "got time %I64d, expected %I64d\n", time, exp_nofps[i].time); + hr = IMFSample_GetSampleDuration(output_sample, &duration); + ok(hr == S_OK, "Got %#lx\n", hr); + todo_wine + ok(duration == exp_nofps[i].duration, "got duration %I64d, expected %I64d\n", duration, exp_nofps[i].duration); + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + output_sample = create_sample(NULL, actual_width * actual_height * 2); + i++; + } + else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT && 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 = 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 %lu\n", ret); + } + else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT && !wmvenc_data_len) + { + i = ARRAYSIZE(exp_nofps) + 1; + } + winetest_pop_context(); + } + + ok(i == ARRAYSIZE(exp_nofps), "transform requires more input than available\n"); + + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + ret = IMFTransform_Release(transform); + ok(ret == 0, "Release returned %lu\n", ret); + + /* Test when 24fps framerate is provided and samples contain no timestamps */ + hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, + &IID_IMFTransform, (void **)&transform); + ok(hr == S_OK, "Got %#lx\n", hr); + + load_resource(L"wmvencdata.bin", &wmvenc_data, &wmvenc_data_len); + + check_mft_set_input_type(transform, input_type_24fps_desc, S_OK); + check_mft_set_output_type(transform, output_type_24fps_desc, S_OK); + + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0); + ok(hr == S_OK, "Got %#lx\n", hr); + + output_sample = create_sample(NULL, actual_width * actual_height * 2); + for (i = 0; i < ARRAYSIZE(exp_24fps);) + { + winetest_push_context("output %ld", i); + hr = check_mft_process_output(transform, output_sample, &output_status); + ok(hr == S_OK || hr == MF_E_TRANSFORM_STREAM_CHANGE || hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); + if (hr == S_OK) + { + hr = IMFSample_GetSampleTime(output_sample, &time); + ok(hr == S_OK, "Got %#lx\n", hr); + todo_wine_if(i) + ok(time == exp_24fps[i].time, "got time %I64d, expected %I64d\n", time, exp_24fps[i].time); + hr = IMFSample_GetSampleDuration(output_sample, &duration); + ok(hr == S_OK, "Got %#lx\n", hr); + todo_wine + ok(duration == exp_24fps[i].duration, "got duration %I64d, expected %I64d\n", duration, exp_24fps[i].duration); + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + output_sample = create_sample(NULL, actual_width * actual_height * 2); + i++; + } + else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT && 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 = 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 %lu\n", ret); + } + else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT && !wmvenc_data_len) + { + i = ARRAYSIZE(exp_24fps) + 1; + } + winetest_pop_context(); + } + + ok(i == ARRAYSIZE(exp_24fps), "transform requires more input than available\n"); + + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + ret = IMFTransform_Release(transform); + ok(ret == 0, "Release returned %lu\n", ret); + + /* Test when provided sample timestamps disagree with MT_MF_FRAME_RATE */ + hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, + &IID_IMFTransform, (void **)&transform); + ok(hr == S_OK, "Got %#lx\n", hr); + + load_resource(L"wmvencdata.bin", &wmvenc_data, &wmvenc_data_len); + + check_mft_set_input_type(transform, input_type_24fps_desc, S_OK); + check_mft_set_output_type(transform, output_type_24fps_desc, S_OK); + + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0); + ok(hr == S_OK, "Got %#lx\n", hr); + + j = 0; + output_sample = create_sample(NULL, actual_width * actual_height * 2); + for (i = 0; i < ARRAYSIZE(exp_sample_ts);) + { + winetest_push_context("output %ld", i); + hr = check_mft_process_output(transform, output_sample, &output_status); + ok(hr == S_OK || hr == MF_E_TRANSFORM_STREAM_CHANGE || hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); + if (hr == S_OK) + { + hr = IMFSample_GetSampleTime(output_sample, &time); + ok(hr == S_OK, "Got %#lx\n", hr); + todo_wine_if(i) + ok(time == exp_sample_ts[i].time, "got time %I64d, expected %I64d\n", time, exp_sample_ts[i].time); + hr = IMFSample_GetSampleDuration(output_sample, &duration); + ok(hr == S_OK, "Got %#lx\n", hr); + todo_wine + ok(duration == exp_sample_ts[i].duration, "got duration %I64d, expected %I64d\n", duration, exp_sample_ts[i].duration); + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + output_sample = create_sample(NULL, actual_width * actual_height * 2); + i++; + } + else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT && j < ARRAYSIZE(input_sample_ts)) + { + 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, input_sample_ts[j].time); + ok(hr == S_OK, "Got %#lx\n", hr); + hr = IMFSample_SetSampleDuration(input_sample, input_sample_ts[j].duration); + ok(hr == S_OK, "Got %#lx\n", hr); + j++; + 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 %lu\n", ret); + } + else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT && j == ARRAYSIZE(input_sample_ts)) + { + todo_wine + ok(0, "no more input to provide\n"); + i = ARRAYSIZE(exp_sample_ts); + } + winetest_pop_context(); + } + + ret = IMFSample_Release(output_sample); + ok(ret == 0, "Release returned %lu\n", ret); + ret = IMFTransform_Release(transform); + ok(ret == 0, "Release returned %lu\n", ret); + +failed: + winetest_pop_context(); + CoUninitialize(); +} + static void test_wmv_decoder_dmo_input_type(void) { const GUID *input_subtypes[] = @@ -10754,6 +11047,7 @@ START_TEST(transform) test_h264_decoder_timestamps(); test_wmv_encoder(); test_wmv_decoder(); + test_wmv_decoder_timestamps(); test_wmv_decoder_dmo_input_type(); test_wmv_decoder_dmo_output_type(); test_wmv_decoder_dmo_get_size_info(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/7563
Nikolay Sivov (@nsivov) commented about dlls/mf/tests/transform.c:
+ ULONG h264_encoded_data_len; + IMFTransform *transform; + LONGLONG duration, time; + DWORD output_status; + ULONG i, j, ret; + HRESULT hr; + + hr = CoInitialize(NULL); + ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr); + + winetest_push_context("h264dec timestamps"); + + /* Test when no framerate is provided and samples contain no timestamps */ + if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, + &IID_IMFTransform, (void **)&transform))) + goto failed; I think you can use CLSID_ symbol directly here, if you don't plan to reuse testing function for other decoders.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/7563#note_98519
participants (3)
-
Brendan McGrath -
Brendan McGrath (@redmcg) -
Nikolay Sivov (@nsivov)