The same behaviour occurs when duration is not provided.
This fixes video playback in Mortal Kombat 11.
From: Brendan McGrath bmcgrath@codeweavers.com
--- dlls/mf/tests/transform.c | 66 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 28b746f1622..820bb331dcc 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -5155,6 +5155,19 @@ static void test_h264_decoder_timestamps(void) { 3333336, 416667 }, { 3750003, 416667 }, }; + static const struct timestamps exp_zero_ts[] = + { + { 0, 416667 }, + { 0, 416667 }, + { 0, 416667 }, + { 0, 416667 }, + { 0, 416667 }, + { 0, 416667 }, + { 0, 416667 }, + { 0, 416667 }, + { 0, 416667 }, + { 0, 416667 }, + }; static const struct timestamps input_sample_ts[] = { { 1334666, 333667, 667333 }, @@ -5370,6 +5383,59 @@ static void test_h264_decoder_timestamps(void) ret = IMFTransform_Release(transform); ok(ret == 0, "Release returned %lu\n", ret);
+ /* Test when 24fps framerate is provided and samples contain zero timestamp and duration */ + hr = CoCreateInstance(&CLSID_MSH264DecoderMFT, 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_zero_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); + ok(time == exp_zero_ts[i].time, "got time %I64d, expected %I64d\n", time, exp_zero_ts[i].time); + hr = IMFSample_GetSampleDuration(output_sample, &duration); + ok(hr == S_OK, "Got %#lx\n", hr); + todo_wine + ok(duration == exp_zero_ts[i].duration, "got duration %I64d, expected %I64d\n", duration, exp_zero_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) + { + input_sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len); + hr = IMFSample_SetSampleTime(input_sample, 0); + ok(hr == S_OK, "Got %#lx\n", hr); + hr = IMFSample_SetSampleDuration(input_sample, 0); + ok(hr == S_OK, "Got %#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 %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(&CLSID_MSH264DecoderMFT, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform);
From: Brendan McGrath bmcgrath@codeweavers.com
--- dlls/mf/tests/transform.c | 67 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 820bb331dcc..47be57d02fb 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -7285,6 +7285,13 @@ static void test_wmv_decoder_timestamps(void) { 0, 0 }, { 0, 0 }, }; + static const struct timestamps exp_zero_ts[] = + { + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + }; static const struct timestamps input_sample_ts[] = { { 666666, 166667 }, @@ -7449,6 +7456,66 @@ static void test_wmv_decoder_timestamps(void) ret = IMFTransform_Release(transform); ok(ret == 0, "Release returned %lu\n", ret);
+ /* Test when 24fps framerate is provided and samples contain zero timestamp and duration */ + hr = CoCreateInstance(&CLSID_CWMVDecMediaObject, 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_zero_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); + ok(time == exp_zero_ts[i].time, "got time %I64d, expected %I64d\n", time, exp_zero_ts[i].time); + hr = IMFSample_GetSampleDuration(output_sample, &duration); + ok(hr == S_OK, "Got %#lx\n", hr); + ok(duration == exp_zero_ts[i].duration, "got duration %I64d, expected %I64d\n", duration, exp_zero_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 && 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, "Got %#lx\n", hr); + hr = IMFSample_SetSampleDuration(input_sample, 0); + ok(hr == S_OK, "Got %#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 %lu\n", ret); + } + else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT && !wmvenc_data_len) + { + i = ARRAYSIZE(exp_zero_ts) + 1; + } + winetest_pop_context(); + } + + ok(i == ARRAYSIZE(exp_zero_ts), "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(&CLSID_CWMVDecMediaObject, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform);
From: Brendan McGrath bmcgrath@codeweavers.com
The same behaviour occurs when duration is not provided. --- dlls/mf/tests/transform.c | 1 - dlls/winegstreamer/video_decoder.c | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 47be57d02fb..4153da28f37 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -5409,7 +5409,6 @@ static void test_h264_decoder_timestamps(void) ok(time == exp_zero_ts[i].time, "got time %I64d, expected %I64d\n", time, exp_zero_ts[i].time); hr = IMFSample_GetSampleDuration(output_sample, &duration); ok(hr == S_OK, "Got %#lx\n", hr); - todo_wine ok(duration == exp_zero_ts[i].duration, "got duration %I64d, expected %I64d\n", duration, exp_zero_ts[i].duration); ret = IMFSample_Release(output_sample); ok(ret == 0, "Release returned %lu\n", ret); diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index ba8b2d545f7..e56f7b9baf7 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -946,7 +946,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, { struct video_decoder *decoder = impl_from_IMFTransform(iface); UINT32 sample_size; - LONGLONG duration; + LONGLONG duration, sample_duration; IMFSample *sample; UINT64 frame_size, frame_rate; bool preserve_timestamps; @@ -1016,6 +1016,11 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, WARN("Failed to set sample duration\n"); decoder->sample_time += duration; } + else if (FAILED(IMFSample_GetSampleDuration(sample, &sample_duration)) || !sample_duration) + { + if (FAILED(IMFSample_SetSampleDuration(sample, duration))) + WARN("Failed to set sample duration\n"); + } }
if (hr == MF_E_TRANSFORM_STREAM_CHANGE)
@rbernon I've added you as reviewer as this is an extension of MR !7623 (which you also reviewed). It turns out Windows will add/fix-up duration if Sample Time is set and duration is either: - omitted; or - given the value of zero
This merge request was approved by Rémi Bernon.