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.
From: Brendan McGrath bmcgrath@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();
From: Brendan McGrath bmcgrath@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();
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.