[PATCH v3 0/7] MR9979: mf/tests: Test SAR's IMFPresentationTimeSource interface.
This also removes duplicated tests from test_sar. -- v3: mf/tests: Test SAR scrubbing start. mf/tests: Test SAR timer with ENDOFSEGMENT marker. mf/tests: Test SAR timer with pre-roll and duration. mf/tests: Test SAR timer with pre-roll and no duration. mf/tests: Test SAR's SetPresentationClock. mf/tests: Test SAR's IMFPresentationTimeSource interface. mf/tests: Test SAR's IMFRateSupport interface. https://gitlab.winehq.org/wine/wine/-/merge_requests/9979
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/mf/tests/mf.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index d3e191d8721..401ea3edb4a 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6324,6 +6324,100 @@ if (SUCCEEDED(hr)) CoUninitialize(); } +static void test_sar_time_source(void) +{ + static const UINT32 NUM_CHANNELS = 2; + + IMFRateSupport *rate_support1, *rate_support2; + IMFMediaTypeHandler *type_handler; + UINT32 samples_per_second; + IMFMediaType *media_type; + IMFStreamSink *stream; + IMFMediaSink *sink; + HRESULT hr; + float rate; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateAudioRenderer(NULL, &sink); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Test rate support */ + hr = IMFMediaSink_QueryInterface(sink, &IID_IMFRateSupport, (void**)&rate_support1); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFGetService((IUnknown*)sink, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void**)&rate_support2); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(rate_support1 == rate_support2, "rate support interfaces don't match %p vs %p\n", rate_support1, rate_support2); + +if (rate_support1) +{ + hr = IMFRateSupport_GetSlowestRate(rate_support1, MFRATE_FORWARD, FALSE, &rate); + ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#lx.\n", hr); + + hr = IMFRateSupport_GetFastestRate(rate_support1, MFRATE_FORWARD, FALSE, &rate); + ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#lx.\n", hr); + + hr = IMFRateSupport_IsRateSupported(rate_support1, FALSE, 1.0, &rate); + ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#lx.\n", hr); +} + + /* Initialise SAR */ + hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFStreamSink_GetMediaTypeHandler(stream, &type_handler); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* media type here only includes samples per second. SAR will accept it in SetCurrentMediaType, + * and it will subsequently return success on further API calls, but it will never produce audio. + * So we must add the missing attributes to test SAR properly */ + IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &samples_per_second); + IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, NUM_CHANNELS); + IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, sizeof(float) * 8); + IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, sizeof(float) * NUM_CHANNELS); + IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, samples_per_second * NUM_CHANNELS * sizeof(float)); + hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMFMediaType_Release(media_type); + IMFMediaTypeHandler_Release(type_handler); + + /* Test rate support when initialised */ +if (rate_support1) +{ + hr = IMFRateSupport_GetSlowestRate(rate_support1, MFRATE_FORWARD, FALSE, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(rate == 0.125, "Unexpected rate %f\n", rate); + + hr = IMFRateSupport_GetFastestRate(rate_support1, MFRATE_FORWARD, FALSE, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(rate == 8.0, "Unexpected rate %f\n", rate); + + hr = IMFRateSupport_IsRateSupported(rate_support1, FALSE, 1.0, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(rate == 1.0, "Unexpected rate %f\n", rate); + + hr = IMFRateSupport_IsRateSupported(rate_support1, FALSE, 0.1, &rate); + ok(hr == MF_E_UNSUPPORTED_RATE, "Unexpected hr %#lx.\n", hr); + ok(rate == 0.125, "Unexpected rate %f\n", rate); + + IMFRateSupport_Release(rate_support1); + IMFRateSupport_Release(rate_support2); +} + + IMFStreamSink_Release(stream); + IMFMediaSink_Release(sink); + + MFShutdown(); +} + static void test_evr(void) { static const float supported_rates[] = @@ -9498,6 +9592,7 @@ START_TEST(mf) test_sample_grabber_orientation(MFVideoFormat_NV12); test_quality_manager(); test_sar(); + test_sar_time_source(); test_evr(); test_MFCreateSimpleTypeHandler(); test_MFGetSupportedMimeTypes(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9979
From: Brendan McGrath <bmcgrath@codeweavers.com> This also removes duplicated tests from test_sar. --- dlls/mf/tests/mf.c | 121 +++++++++++++++++++++++++++++++-------------- 1 file changed, 83 insertions(+), 38 deletions(-) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 401ea3edb4a..0f7d4ba871d 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -5775,11 +5775,11 @@ static void test_sar(void) IMFPresentationClock *present_clock, *present_clock2; IMFMediaType *mediatype, *mediatype2, *mediatype3; UINT32 channel_count, rate, bytes_per_second; - IMFClockStateSink *state_sink, *state_sink2; IMFMediaTypeHandler *handler, *handler2; IMFPresentationTimeSource *time_source; IMFSimpleAudioVolume *simple_volume; IMFAudioStreamVolume *stream_volume; + IMFClockStateSink *state_sink; IMFAsyncCallback *callback; IMFMediaSink *sink, *sink2; IMFStreamSink *stream_sink; @@ -5788,10 +5788,8 @@ static void test_sar(void) DWORD id, flags, count; IMFActivate *activate; IMFMediaEvent *event; - MFCLOCK_STATE state; PROPVARIANT propvar; IMFSample *sample; - IMFClock *clock; IUnknown *unk; HRESULT hr; BYTE *buff; @@ -5817,41 +5815,6 @@ static void test_sar(void) hr = MFCreatePresentationClock(&present_clock); ok(hr == S_OK, "Failed to create presentation clock, hr %#lx.\n", hr); - hr = IMFMediaSink_QueryInterface(sink, &IID_IMFPresentationTimeSource, (void **)&time_source); - todo_wine - ok(hr == S_OK, "Failed to get time source interface, hr %#lx.\n", hr); - -if (SUCCEEDED(hr)) -{ - hr = IMFPresentationTimeSource_QueryInterface(time_source, &IID_IMFClockStateSink, (void **)&state_sink2); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFPresentationTimeSource_QueryInterface(time_source, &IID_IMFClockStateSink, (void **)&state_sink); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(state_sink == state_sink2, "Unexpected clock sink.\n"); - IMFClockStateSink_Release(state_sink2); - IMFClockStateSink_Release(state_sink); - - hr = IMFPresentationTimeSource_GetUnderlyingClock(time_source, &clock); - ok(hr == MF_E_NO_CLOCK, "Unexpected hr %#lx.\n", hr); - - hr = IMFPresentationTimeSource_GetClockCharacteristics(time_source, &flags); - ok(hr == S_OK, "Failed to get flags, hr %#lx.\n", hr); - ok(flags == MFCLOCK_CHARACTERISTICS_FLAG_FREQUENCY_10MHZ, "Unexpected flags %#lx.\n", flags); - - hr = IMFPresentationTimeSource_GetState(time_source, 0, &state); - ok(hr == S_OK, "Failed to get clock state, hr %#lx.\n", hr); - ok(state == MFCLOCK_STATE_INVALID, "Unexpected state %d.\n", state); - - hr = IMFPresentationTimeSource_QueryInterface(time_source, &IID_IMFClockStateSink, (void **)&state_sink); - ok(hr == S_OK, "Failed to get state sink, hr %#lx.\n", hr); - - hr = IMFClockStateSink_OnClockStart(state_sink, 0, 0); - ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#lx.\n", hr); - - IMFClockStateSink_Release(state_sink); - - IMFPresentationTimeSource_Release(time_source); -} hr = IMFMediaSink_AddStreamSink(sink, 123, NULL, &stream_sink); ok(hr == MF_E_STREAMSINKS_FIXED, "Unexpected hr %#lx.\n", hr); @@ -6329,20 +6292,32 @@ static void test_sar_time_source(void) static const UINT32 NUM_CHANNELS = 2; IMFRateSupport *rate_support1, *rate_support2; + IMFClockStateSink *state_sink1, *state_sink2; + IMFPresentationTimeSource *time_source; + MFCLOCK_PROPERTIES clock_properties; IMFMediaTypeHandler *type_handler; + IMFAsyncCallback *callback; UINT32 samples_per_second; IMFMediaType *media_type; IMFStreamSink *stream; + DWORD characteristics; + MFCLOCK_STATE state; + PROPVARIANT propvar; IMFMediaSink *sink; HRESULT hr; float rate; + /* Initialise required resources */ + PropVariantInit(&propvar); + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = MFCreateAudioRenderer(NULL, &sink); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + callback = create_test_callback(TRUE); + /* Test rate support */ hr = IMFMediaSink_QueryInterface(sink, &IID_IMFRateSupport, (void**)&rate_support1); todo_wine @@ -6365,6 +6340,41 @@ if (rate_support1) ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#lx.\n", hr); } + /* Test IMFPresentationTimeSource interface */ + hr = IMFMediaSink_QueryInterface(sink, &IID_IMFPresentationTimeSource, (void**)&time_source); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaSink_QueryInterface(sink, &IID_IMFClockStateSink, (void **)&state_sink1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFClockStateSink_OnClockStart(state_sink1, 0, 0); + ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#lx.\n", hr); + +if (time_source) +{ + hr = IMFPresentationTimeSource_GetClockCharacteristics(time_source, &characteristics); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(characteristics == MFCLOCK_CHARACTERISTICS_FLAG_FREQUENCY_10MHZ, "Unexpected characteristics %#lx.\n", characteristics); + + hr = IMFPresentationTimeSource_GetProperties(time_source, &clock_properties); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(clock_properties.qwClockFrequency == MFCLOCK_FREQUENCY_HNS, "Unexpected frequency value %I64d.\n", clock_properties.qwClockFrequency); + ok(clock_properties.dwClockTolerance == MFCLOCK_TOLERANCE_UNKNOWN, "Unexpected tolerance value %ld.\n", clock_properties.dwClockTolerance); + ok(clock_properties.dwClockJitter == 1, "Unexpected jitter value %ld.\n", clock_properties.dwClockJitter); + + hr = IMFPresentationTimeSource_GetState(time_source, 0, &state); + ok(hr == S_OK, "Failed to get clock state, hr %#lx.\n", hr); + ok(state == MFCLOCK_STATE_INVALID, "Unexpected state %d.\n", state); + + hr = IMFPresentationTimeSource_QueryInterface(time_source, &IID_IMFClockStateSink, (void **)&state_sink2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(state_sink1 == state_sink2, "clock state sink interfaces don't match %p vs %p.\n", state_sink1, state_sink2); + + IMFClockStateSink_Release(state_sink2); +} + + /* Initialise SAR */ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -6412,6 +6422,41 @@ if (rate_support1) IMFRateSupport_Release(rate_support2); } + /* Test IMFPresentationTimeSource interface when initialised */ +if (time_source) +{ + hr = IMFPresentationTimeSource_GetState(time_source, 0, &state); + ok(hr == S_OK, "Failed to get clock state, hr %#lx.\n", hr); + ok(state == MFCLOCK_STATE_INVALID, "Unexpected state %d.\n", state); + + hr = IMFClockStateSink_OnClockStart(state_sink1, 0, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkStarted, 1000, &propvar); + ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + hr = IMFPresentationTimeSource_GetState(time_source, 0, &state); + ok(hr == S_OK, "Failed to get clock state, hr %#lx.\n", hr); + ok(state == MFCLOCK_STATE_RUNNING, "Unexpected state %d.\n", state); + + hr = IMFClockStateSink_OnClockStop(state_sink1, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkStopped, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + hr = IMFPresentationTimeSource_GetState(time_source, 0, &state); + ok(hr == S_OK, "Failed to get clock state, hr %#lx.\n", hr); + ok(state == MFCLOCK_STATE_STOPPED, "Unexpected state %d.\n", state); + + IMFPresentationTimeSource_Release(time_source); +} + + /* Free allocated resources */ + IMFAsyncCallback_Release(callback); + IMFClockStateSink_Release(state_sink1); IMFStreamSink_Release(stream); IMFMediaSink_Release(sink); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9979
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/mf/tests/mf.c | 99 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 82 insertions(+), 17 deletions(-) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 0f7d4ba871d..2a4803e2a3a 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -4277,10 +4277,11 @@ struct presentation_clock IMFPresentationClock IMFPresentationClock_iface; IMFTimer IMFTimer_iface; LONG refcount; - IMFClockStateSink *sample_grabber_clock_state_sink; + IMFClockStateSink *clock_state_sink; IMFAsyncResult *callback_result; IUnknown *cancel_key; HANDLE set_timer_event; + IMFPresentationTimeSource *time_source; }; static struct presentation_clock* impl_from_IMFTimer(IMFTimer *iface) @@ -4359,6 +4360,11 @@ static IMFTimerVtbl MFTimerVtbl = timer_CancelTimer, }; +DEFINE_EXPECT(presentation_clock_AddClockStateSink); +DEFINE_EXPECT(presentation_clock_RemoveClockStateSink); +DEFINE_EXPECT(presentation_clock_GetTimeSource); +DEFINE_EXPECT(presentation_clock_SetTimeSource); + static struct presentation_clock* impl_from_IMFPresentationClock(IMFPresentationClock *iface) { return CONTAINING_RECORD(iface, struct presentation_clock, IMFPresentationClock_iface); @@ -4401,10 +4407,12 @@ static WINAPI ULONG presentation_clock_Release(IMFPresentationClock *iface) if (!pc->refcount) { - if (pc->sample_grabber_clock_state_sink) - IMFClockStateSink_Release(pc->sample_grabber_clock_state_sink); + if (pc->clock_state_sink) + IMFClockStateSink_Release(pc->clock_state_sink); if (pc->callback_result) IMFAsyncResult_Release(pc->callback_result); + if (pc->time_source) + IMFPresentationTimeSource_Release(pc->time_source); CloseHandle(pc->set_timer_event); free(pc); } @@ -4441,13 +4449,27 @@ static WINAPI HRESULT presentation_clock_GetProperties(IMFPresentationClock *ifa static WINAPI HRESULT presentation_clock_SetTimeSource(IMFPresentationClock *iface, IMFPresentationTimeSource *time_source) { - return E_NOTIMPL; + struct presentation_clock *pc = impl_from_IMFPresentationClock(iface); + + CHECK_EXPECT(presentation_clock_SetTimeSource); + if (pc->time_source) IMFPresentationTimeSource_Release(pc->time_source); + IMFPresentationTimeSource_AddRef(pc->time_source = time_source); + return S_OK; } static WINAPI HRESULT presentation_clock_GetTimeSource(IMFPresentationClock *iface, IMFPresentationTimeSource **time_source) { - return E_NOTIMPL; + struct presentation_clock *pc = impl_from_IMFPresentationClock(iface); + + CHECK_EXPECT(presentation_clock_GetTimeSource); + + if (!pc->time_source) + return MF_E_CLOCK_NO_TIME_SOURCE; + + IMFPresentationTimeSource_AddRef(*time_source = pc->time_source); + + return S_OK; } static WINAPI HRESULT presentation_clock_GetTime(IMFPresentationClock *iface, MFTIME *time) @@ -4459,10 +4481,12 @@ static WINAPI HRESULT presentation_clock_AddClockStateSink(IMFPresentationClock { struct presentation_clock *pc = impl_from_IMFPresentationClock(iface); - if (pc->sample_grabber_clock_state_sink) - IMFClockStateSink_Release(pc->sample_grabber_clock_state_sink); + CHECK_EXPECT(presentation_clock_AddClockStateSink); + + if (pc->clock_state_sink) + IMFClockStateSink_Release(pc->clock_state_sink); - IMFClockStateSink_AddRef(pc->sample_grabber_clock_state_sink = state_sink); + IMFClockStateSink_AddRef(pc->clock_state_sink = state_sink); return S_OK; } @@ -4472,10 +4496,12 @@ static WINAPI HRESULT presentation_clock_RemoveClockStateSink(IMFPresentationClo { struct presentation_clock *pc = impl_from_IMFPresentationClock(iface); - if (pc->sample_grabber_clock_state_sink == state_sink) + CHECK_EXPECT(presentation_clock_RemoveClockStateSink); + + if (pc->clock_state_sink == state_sink) { IMFClockStateSink_Release(state_sink); - pc->sample_grabber_clock_state_sink = NULL; + pc->clock_state_sink = NULL; } return S_OK; @@ -4487,9 +4513,9 @@ static WINAPI HRESULT presentation_clock_Start(IMFPresentationClock *iface, LONG HRESULT hr; if (start_offset == PRESENTATION_CURRENT_POSITION) - hr = IMFClockStateSink_OnClockRestart(pc->sample_grabber_clock_state_sink, 0); + hr = IMFClockStateSink_OnClockRestart(pc->clock_state_sink, 0); else - hr = IMFClockStateSink_OnClockStart(pc->sample_grabber_clock_state_sink, 0, start_offset); + hr = IMFClockStateSink_OnClockStart(pc->clock_state_sink, 0, start_offset); return hr; } @@ -4497,14 +4523,14 @@ static WINAPI HRESULT presentation_clock_Stop(IMFPresentationClock *iface) { struct presentation_clock *pc = impl_from_IMFPresentationClock(iface); - return IMFClockStateSink_OnClockStop(pc->sample_grabber_clock_state_sink, 0); + return IMFClockStateSink_OnClockStop(pc->clock_state_sink, 0); } static WINAPI HRESULT presentation_clock_Pause(IMFPresentationClock *iface) { struct presentation_clock *pc = impl_from_IMFPresentationClock(iface); - return IMFClockStateSink_OnClockPause(pc->sample_grabber_clock_state_sink, 0); + return IMFClockStateSink_OnClockPause(pc->clock_state_sink, 0); } static IMFPresentationClockVtbl MFPresentationClockVtbl = @@ -4726,9 +4752,11 @@ static void test_sample_grabber_seek(void) mock_clock = create_presentation_clock(); clock = &mock_clock->IMFPresentationClock_iface; + SET_EXPECT(presentation_clock_AddClockStateSink); hr = IMFMediaSink_SetPresentationClock(sink, clock); ok(hr == S_OK, "Failed to set presentation clock, hr %#lx.\n", hr); - ok(!!mock_clock->sample_grabber_clock_state_sink, "AddClockStateSink not called\n"); + ok(!!mock_clock->clock_state_sink, "AddClockStateSink not called\n"); + CHECK_CALLED(presentation_clock_AddClockStateSink); /* test number of new sample requests on clock start */ hr = IMFPresentationClock_Start(clock, 0); @@ -4986,8 +5014,10 @@ static void test_sample_grabber_seek(void) ref = IMFPresentationClock_Release(clock); ok(ref == 2, "Release returned %ld\n", ref); + SET_EXPECT(presentation_clock_RemoveClockStateSink); hr = IMFMediaSink_Shutdown(sink); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + CHECK_CALLED(presentation_clock_RemoveClockStateSink); ref = IMFMediaSink_Release(sink); todo_wine @@ -5037,8 +5067,10 @@ static void test_sample_grabber_seek(void) mock_clock = create_presentation_clock(); clock = &mock_clock->IMFPresentationClock_iface; + SET_EXPECT(presentation_clock_AddClockStateSink); hr = IMFMediaSink_SetPresentationClock(sink, clock); ok(hr == S_OK, "Failed to set presentation clock, hr %#lx.\n", hr); + CHECK_CALLED(presentation_clock_AddClockStateSink); /* test number of new sample requests on clock start */ hr = IMFPresentationClock_Start(clock, 0); @@ -5211,8 +5243,10 @@ static void test_sample_grabber_seek(void) ref = IMFPresentationClock_Release(clock); ok(ref == 2, "Release returned %ld\n", ref); + SET_EXPECT(presentation_clock_RemoveClockStateSink); hr = IMFMediaSink_Shutdown(sink); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + CHECK_CALLED(presentation_clock_RemoveClockStateSink); ref = IMFMediaSink_Release(sink); todo_wine @@ -6291,11 +6325,13 @@ static void test_sar_time_source(void) { static const UINT32 NUM_CHANNELS = 2; + struct presentation_clock *presentation_clock; IMFRateSupport *rate_support1, *rate_support2; IMFClockStateSink *state_sink1, *state_sink2; IMFPresentationTimeSource *time_source; MFCLOCK_PROPERTIES clock_properties; IMFMediaTypeHandler *type_handler; + IMFPresentationClock *clock; IMFAsyncCallback *callback; UINT32 samples_per_second; IMFMediaType *media_type; @@ -6306,6 +6342,7 @@ static void test_sar_time_source(void) IMFMediaSink *sink; HRESULT hr; float rate; + ULONG ref; /* Initialise required resources */ PropVariantInit(&propvar); @@ -6318,6 +6355,9 @@ static void test_sar_time_source(void) callback = create_test_callback(TRUE); + presentation_clock = create_presentation_clock(); + clock = &presentation_clock->IMFPresentationClock_iface; + /* Test rate support */ hr = IMFMediaSink_QueryInterface(sink, &IID_IMFRateSupport, (void**)&rate_support1); todo_wine @@ -6374,7 +6414,6 @@ if (time_source) IMFClockStateSink_Release(state_sink2); } - /* Initialise SAR */ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -6451,14 +6490,40 @@ if (time_source) ok(hr == S_OK, "Failed to get clock state, hr %#lx.\n", hr); ok(state == MFCLOCK_STATE_STOPPED, "Unexpected state %d.\n", state); + SET_EXPECT(presentation_clock_GetTimeSource); + hr = IMFMediaSink_SetPresentationClock(sink, clock); + ok(hr == MF_E_CLOCK_NO_TIME_SOURCE, "Unexpected hr %#lx.\n", hr); + CHECK_CALLED(presentation_clock_GetTimeSource); + + IMFPresentationTimeSource_AddRef(presentation_clock->time_source = time_source); + + SET_EXPECT(presentation_clock_GetTimeSource); + SET_EXPECT(presentation_clock_AddClockStateSink); + hr = IMFMediaSink_SetPresentationClock(sink, clock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + CHECK_CALLED(presentation_clock_GetTimeSource); + CHECK_CALLED(presentation_clock_AddClockStateSink); + + ok(presentation_clock->clock_state_sink == state_sink1, + "clock state sink interfaces don't match %p vs %p.\n", presentation_clock->clock_state_sink, state_sink1); + IMFPresentationTimeSource_Release(time_source); } /* Free allocated resources */ + IMFPresentationClock_Release(clock); IMFAsyncCallback_Release(callback); IMFClockStateSink_Release(state_sink1); IMFStreamSink_Release(stream); - IMFMediaSink_Release(sink); + + SET_EXPECT(presentation_clock_RemoveClockStateSink); + hr = IMFMediaSink_Shutdown(sink); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + todo_wine + CHECK_CALLED(presentation_clock_RemoveClockStateSink); + + ref = IMFMediaSink_Release(sink); + ok(ref == 0, "Release returned %ld\n", ref); MFShutdown(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9979
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/mf/tests/mf.c | 147 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 3 deletions(-) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 2a4803e2a3a..d8b22012aab 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -4474,7 +4474,16 @@ static WINAPI HRESULT presentation_clock_GetTimeSource(IMFPresentationClock *ifa static WINAPI HRESULT presentation_clock_GetTime(IMFPresentationClock *iface, MFTIME *time) { - return E_NOTIMPL; + struct presentation_clock *pc = impl_from_IMFPresentationClock(iface); + MFTIME systime; + HRESULT hr; + + if (!pc->time_source) + return MF_E_CLOCK_NO_TIME_SOURCE; + + hr = IMFPresentationTimeSource_GetCorrelatedTime(pc->time_source, 0, time, &systime); + + return hr; } static WINAPI HRESULT presentation_clock_AddClockStateSink(IMFPresentationClock *iface, IMFClockStateSink *state_sink) @@ -6321,16 +6330,52 @@ static void test_sar(void) CoUninitialize(); } -static void test_sar_time_source(void) +static const UINT32 NUM_CHANNELS = 2; + +#define create_audio_sample(samples_per_second, duration) _create_audio_sample(__LINE__, samples_per_second, duration) +static IMFSample *_create_audio_sample(int line, UINT32 samples_per_second, MFTIME duration) { - static const UINT32 NUM_CHANNELS = 2; + IMFMediaBuffer *buffer; + IMFSample *sample; + HRESULT hr; + DWORD size; + BYTE *data; + + size = sizeof(float) * NUM_CHANNELS * samples_per_second * duration / MFCLOCK_FREQUENCY_HNS; + + hr = MFCreateMemoryBuffer(size, &buffer); + ok_(__FILE__, line)(hr == S_OK, "Failed to create memory buffer %#lx.\n", hr); + + hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL); + ok_(__FILE__, line)(hr == S_OK, "Failed to lock memory buffer %#lx.\n", hr); + + memset(data, 0, size); + + hr = IMFMediaBuffer_Unlock(buffer); + ok_(__FILE__, line)(hr == S_OK, "Failed to unlock memory buffer %#lx.\n", hr); + + hr = IMFMediaBuffer_SetCurrentLength(buffer, size); + ok_(__FILE__, line)(hr == S_OK, "Failed to set current length %#lx.\n", hr); + + hr = MFCreateSample(&sample); + ok_(__FILE__, line)(hr == S_OK, "Failed to create sample %#lx.\n", hr); + hr = IMFSample_AddBuffer(sample, buffer); + ok_(__FILE__, line)(hr == S_OK, "Failed to add buffer %#lx.\n", hr); + IMFMediaBuffer_Release(buffer); + + return sample; +} + +static void test_sar_time_source(void) +{ struct presentation_clock *presentation_clock; IMFRateSupport *rate_support1, *rate_support2; IMFClockStateSink *state_sink1, *state_sink2; IMFPresentationTimeSource *time_source; MFCLOCK_PROPERTIES clock_properties; IMFMediaTypeHandler *type_handler; + IMFMediaSinkPreroll *preroll; IMFPresentationClock *clock; IMFAsyncCallback *callback; UINT32 samples_per_second; @@ -6340,9 +6385,12 @@ static void test_sar_time_source(void) MFCLOCK_STATE state; PROPVARIANT propvar; IMFMediaSink *sink; + IMFSample *sample; + MFTIME time; HRESULT hr; float rate; ULONG ref; + INT i; /* Initialise required resources */ PropVariantInit(&propvar); @@ -6507,6 +6555,99 @@ if (time_source) ok(presentation_clock->clock_state_sink == state_sink1, "clock state sink interfaces don't match %p vs %p.\n", presentation_clock->clock_state_sink, state_sink1); + /* Test preroll start when no duration provided */ + hr = IMFMediaSink_QueryInterface(sink, &IID_IMFMediaSinkPreroll, (void**)&preroll); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaSinkPreroll_NotifyPreroll(preroll, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* We should now get two sample requests */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Provide one sample. Note that duration is not set */ + sample = create_audio_sample(samples_per_second, 100000); + hr = IMFSample_SetSampleTime(sample, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFStreamSink_ProcessSample(stream, sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFSample_Release(sample); + + /* But no MEStreamSinkPrerolled will be provided until we provide a second sample */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkPrerolled, 100, &propvar); + ok(hr == WAIT_TIMEOUT, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Provide second sample */ + sample = create_audio_sample(samples_per_second, 100000); + hr = IMFSample_SetSampleTime(sample, 100000); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFStreamSink_ProcessSample(stream, sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFSample_Release(sample); + + /* A third sample is requested only after the first two have been delivered */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Now we get the pre-roll event. The third sample does not need to be provided */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkPrerolled, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Check clock time before start */ + hr = IMFPresentationClock_GetTime(clock, &time); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(time == 0, "Unexpected time %I64d.\n", time); + + /* Start clock */ + hr = IMFPresentationClock_Start(clock, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Two more samples are immediately requested */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Before we get the started event */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkStarted, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Check clock time */ + for (i = 0; i < 100 && time < 200000; i++) + { + IMFPresentationClock_GetTime(clock, &time); + Sleep(50); + } + + /* Clock time will halt at exactly 200000 as this is the total duration of the two samples */ + ok(time == 200000, "Unexpected time %I64d.\n", time); + + /* Stop clock */ + hr = IMFPresentationClock_Stop(clock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Time should now be zero */ + hr = IMFPresentationClock_GetTime(clock, &time); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(time == 0, "Unexpected time %I64d.\n", time); + + IMFMediaSinkPreroll_Release(preroll); + IMFPresentationTimeSource_Release(time_source); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9979
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/mf/tests/mf.c | 136 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index d8b22012aab..03fb9037134 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6646,6 +6646,142 @@ if (time_source) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(time == 0, "Unexpected time %I64d.\n", time); + /* Test preroll start when duration is provided */ + hr = IMFMediaSinkPreroll_NotifyPreroll(preroll, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* We should now get two sample requests */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Provide one sample. Note that duration is set */ + sample = create_audio_sample(samples_per_second, 100000); + hr = IMFSample_SetSampleTime(sample, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFSample_SetSampleDuration(sample, 100000); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFStreamSink_ProcessSample(stream, sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFSample_Release(sample); + + /* But no MEStreamSinkPrerolled will be provided until we provide at least 200ms of data */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkPrerolled, 100, &propvar); + ok(hr == WAIT_TIMEOUT, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Provide second sample */ + sample = create_audio_sample(samples_per_second, 100000); + hr = IMFSample_SetSampleTime(sample, 100000); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFSample_SetSampleDuration(sample, 100000); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFStreamSink_ProcessSample(stream, sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFSample_Release(sample); + + /* A third sample is requested only after the first two have been delivered */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* But we still don't get the pre-roll event. Not until we provide 200ms of data */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkPrerolled, 100, &propvar); + ok(hr == WAIT_TIMEOUT, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Confirm a start prior to pre-roll completion will fail */ + hr = IMFPresentationClock_Start(clock, 0); + ok(hr == MF_E_STATE_TRANSITION_PENDING, "Unexpected hr %#lx.\n", hr); + + /* Complete the pre-roll, we still need 180ms of duration. We'll send an 80ms sample and four 25ms. + * A new sample will be requested after each is provided; but for the last */ + + sample = create_audio_sample(samples_per_second, 800000); + hr = IMFSample_SetSampleTime(sample, 200000); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFSample_SetSampleDuration(sample, 800000); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFStreamSink_ProcessSample(stream, sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFSample_Release(sample); + + time = 1000000; + for (i = 0; i < 4; i++) + { + const LONGLONG duration = 250000; + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + sample = create_audio_sample(samples_per_second, duration); + hr = IMFSample_SetSampleTime(sample, time); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFSample_SetSampleDuration(sample, duration); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFStreamSink_ProcessSample(stream, sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFSample_Release(sample); + + time += duration; + } + + /* A new sample is not requested if duration is provided and the total duration of samples buffered is 200ms or more + * Instead there is a preroll event */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkPrerolled, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Check clock time before start */ + hr = IMFPresentationClock_GetTime(clock, &time); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(time == 0, "Unexpected time %I64d.\n", time); + + /* Start clock */ + hr = IMFPresentationClock_Start(clock, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* On start, the 200ms worth of samples will be consumed. A new sample is requested for each sample consumed. In this case, it is seven. */ + for (i = 0; i < 7; i++) + { + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + } + + /* Check clock time */ + time = 0; + for (i = 0; i < 100 && time < 2000000; i++) + { + IMFPresentationClock_GetTime(clock, &time); + Sleep(50); + } + + /* Clock time will halt at exactly 2000000 as this is the total duration of all the provided samples */ + ok(time == 2000000, "Unexpected time %I64d.\n", time); + + /* Stop clock */ + hr = IMFPresentationClock_Stop(clock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Get stop event */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkStopped, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Time should now be zero */ + hr = IMFPresentationClock_GetTime(clock, &time); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(time == 0, "Unexpected time %I64d.\n", time); + IMFMediaSinkPreroll_Release(preroll); IMFPresentationTimeSource_Release(time_source); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9979
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/mf/tests/mf.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 03fb9037134..fbe4a60a45c 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6637,10 +6637,52 @@ if (time_source) /* Clock time will halt at exactly 200000 as this is the total duration of the two samples */ ok(time == 200000, "Unexpected time %I64d.\n", time); + /* Provide a third sample */ + sample = create_audio_sample(samples_per_second, 100000); + hr = IMFSample_SetSampleTime(sample, 200000); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFStreamSink_ProcessSample(stream, sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFSample_Release(sample); + + /* Providing a sample without duration always triggers a request for another sample */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Place an ENDOFSEGMENT marker after the third sample */ + hr = IMFStreamSink_PlaceMarker(stream, MFSTREAMSINK_MARKER_ENDOFSEGMENT, NULL, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkMarker, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Check clock time */ + for (i = 0; i < 100 && time <= 300000; i++) + { + IMFPresentationClock_GetTime(clock, &time); + Sleep(50); + } + + /* Time is now greater than 300000 as, due to the ENDOFSEGMENT marker, SAR will now insert silence and continue the timer */ + ok(time > 300000, "Unexpected time %I64d.\n", time); + + /* No new samples are requested after the marker */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 100, &propvar); + ok(hr == WAIT_TIMEOUT, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + /* Stop clock */ hr = IMFPresentationClock_Stop(clock); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + /* Get stop event */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkStopped, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + /* Time should now be zero */ hr = IMFPresentationClock_GetTime(clock, &time); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9979
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/mf/tests/mf.c | 120 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index fbe4a60a45c..96605dd1f6c 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6826,6 +6826,126 @@ if (time_source) IMFMediaSinkPreroll_Release(preroll); + /* Test scrubbing. Start by setting clock rate to zero. */ + hr = IMFClockStateSink_OnClockSetRate(state_sink1, 0, 0.0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Wait for the rate changed event */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRateChanged, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Start the clock */ + hr = IMFPresentationClock_Start(clock, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* We immediately get the stream started event */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkStarted, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Then two samples are requested */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* And then the scrub complete event. No samples need to be provided. */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkScrubSampleComplete, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* But when we do provide a requested sample ... */ + sample = create_audio_sample(samples_per_second, 100000); + hr = IMFSample_SetSampleTime(sample, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFStreamSink_ProcessSample(stream, sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFSample_Release(sample); + + /* ... no new sample is requested ... */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 100, &propvar); + ok(hr == WAIT_TIMEOUT, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* ... until we provide the second ... */ + sample = create_audio_sample(samples_per_second, 100000); + hr = IMFSample_SetSampleTime(sample, 100000); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFStreamSink_ProcessSample(stream, sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFSample_Release(sample); + + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* ... but the clock remains at zero */ + hr = IMFPresentationClock_GetTime(clock, &time); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(time == 0, "Unexpected time %I64d.\n", time); + + /* to start the playback, we pause ... */ + hr = IMFPresentationClock_Pause(clock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkPaused, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* ... set rate back to 1 ... */ + hr = IMFClockStateSink_OnClockSetRate(state_sink1, 0, 1.0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRateChanged, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* ... and restart */ + hr = IMFPresentationClock_Start(clock, PRESENTATION_CURRENT_POSITION); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkStarted, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Check clock time */ + for (i = 0; i < 100 && time < 200000; i++) + { + IMFPresentationClock_GetTime(clock, &time); + Sleep(50); + } + + /* Clock time will halt at exactly 200000 as this is the total duration of the two samples */ + ok(time == 200000, "Unexpected time %I64d.\n", time); + + /* Stop clock */ + hr = IMFPresentationClock_Stop(clock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Get stop event */ + hr = gen_wait_media_event_until_blocking((IMFMediaEventGenerator*)stream, callback, MEStreamSinkStopped, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + + /* Time should now be zero */ + hr = IMFPresentationClock_GetTime(clock, &time); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(time == 0, "Unexpected time %I64d.\n", time); + IMFPresentationTimeSource_Release(time_source); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9979
v3: - Remove 'skip' - Ensure `GetTime` test won't loop indefinitely -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9979#note_128180
On Tue Jan 27 19:49:16 2026 +0000, Brendan McGrath wrote:
changed this line in [version 3 of the diff](/wine/wine/-/merge_requests/9979/diffs?diff_id=240537&start_sha=08dda286dd74b6df8c8f2f4cb72c21bab67b28d0#38af2002cdac18e4819839775ba914609caa73df_6433_6430) OK, I've removed both skips.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9979#note_128181
On Tue Jan 27 12:23:49 2026 +0000, Nikolay Sivov wrote:
This does not look very safe to me. If we must to do GetTime(), maybe do it in a separate thread, and have a timeout? I've changed this to a `for` loop; ensuring we won't loop more than 100 times. This is effectively a 5 second timeout.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9979#note_128182
participants (2)
-
Brendan McGrath -
Brendan McGrath (@redmcg)