From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/mf/tests/mf.c | 230 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index df1362381b2..ef4a71f8055 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -3876,6 +3876,192 @@ static const IMFClockStateSinkVtbl test_clock_sink_vtbl = test_clock_sink_OnClockSetRate, }; +struct test_time_source +{ + IMFPresentationTimeSource IMFPresentationTimeSource_iface; + IMFClockStateSink IMFClockStateSink_iface; + LONG refcount; + LONGLONG time; +}; + +static struct test_time_source *test_time_source_from_IMFPresentationTimeSource(IMFPresentationTimeSource *iface) +{ + return CONTAINING_RECORD(iface, struct test_time_source, IMFPresentationTimeSource_iface); +} + +static HRESULT WINAPI test_time_source_QueryInterface(IMFPresentationTimeSource *iface, REFIID riid, void **obj) +{ + struct test_time_source *test_time_source = test_time_source_from_IMFPresentationTimeSource(iface); + + if (IsEqualGUID(riid, &IID_IMFPresentationTimeSource) || + IsEqualGUID(riid, &IID_IMFClock) || + IsEqualGUID(riid, &IID_IUnknown)) + { + *obj = iface; + } + else if (IsEqualGUID(riid, &IID_IMFClockStateSink)) + { + *obj = &test_time_source->IMFClockStateSink_iface; + } + else + { + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*obj); + return S_OK; +} + +static ULONG WINAPI test_time_source_AddRef(IMFPresentationTimeSource *iface) +{ + struct test_time_source *test_time_source = test_time_source_from_IMFPresentationTimeSource(iface); + ULONG refcount = InterlockedIncrement(&test_time_source->refcount); + return refcount; +} + +static ULONG WINAPI test_time_source_Release(IMFPresentationTimeSource *iface) +{ + struct test_time_source *test_time_source = test_time_source_from_IMFPresentationTimeSource(iface); + ULONG refcount = InterlockedDecrement(&test_time_source->refcount); + + if (!refcount) + free(test_time_source); + + return refcount; +} + +static HRESULT WINAPI test_time_source_GetClockCharacteristics(IMFPresentationTimeSource *iface, DWORD *flags) +{ + *flags = MFCLOCK_CHARACTERISTICS_FLAG_FREQUENCY_10MHZ; + + return S_OK; +} + +static HRESULT WINAPI test_time_source_GetCorrelatedTime(IMFPresentationTimeSource *iface, DWORD reserved, + LONGLONG *clock_time, MFTIME *system_time) +{ + struct test_time_source *test_time_source = test_time_source_from_IMFPresentationTimeSource(iface); + + *clock_time = test_time_source->time; + *system_time = MFGetSystemTime(); + + return S_OK; +} + +static HRESULT WINAPI test_time_source_GetContinuityKey(IMFPresentationTimeSource *iface, DWORD *key) +{ + return E_NOTIMPL; +} + + +static HRESULT WINAPI test_time_source_GetState(IMFPresentationTimeSource *iface, DWORD reserved, + MFCLOCK_STATE *state) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_time_source_GetProperties(IMFPresentationTimeSource *iface, MFCLOCK_PROPERTIES *props) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_time_source_GetUnderlyingClock(IMFPresentationTimeSource *iface, IMFClock **clock) +{ + return MF_E_NO_CLOCK; +} + +DEFINE_EXPECT(test_time_source_sink_OnClockStart); + +static IMFPresentationTimeSourceVtbl test_time_source_vtbl = +{ + test_time_source_QueryInterface, + test_time_source_AddRef, + test_time_source_Release, + test_time_source_GetClockCharacteristics, + test_time_source_GetCorrelatedTime, + test_time_source_GetContinuityKey, + test_time_source_GetState, + test_time_source_GetProperties, + test_time_source_GetUnderlyingClock, +}; + +static struct test_time_source *test_time_source_from_IMFClockStateSink(IMFClockStateSink *iface) +{ + return CONTAINING_RECORD(iface, struct test_time_source, IMFClockStateSink_iface); +} + +static HRESULT WINAPI test_time_source_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj) +{ + struct test_time_source *test_time_source = test_time_source_from_IMFClockStateSink(iface); + return IMFPresentationTimeSource_QueryInterface(&test_time_source->IMFPresentationTimeSource_iface, riid, obj); +} + +static ULONG WINAPI test_time_source_sink_AddRef(IMFClockStateSink *iface) +{ + struct test_time_source *test_time_source = test_time_source_from_IMFClockStateSink(iface); + return IMFPresentationTimeSource_AddRef(&test_time_source->IMFPresentationTimeSource_iface); +} + +static ULONG WINAPI test_time_source_sink_Release(IMFClockStateSink *iface) +{ + struct test_time_source *test_time_source = test_time_source_from_IMFClockStateSink(iface); + return IMFPresentationTimeSource_Release(&test_time_source->IMFPresentationTimeSource_iface); +} + +static HRESULT WINAPI test_time_source_sink_OnClockStart(IMFClockStateSink *iface, MFTIME system_time, LONGLONG offset) +{ + HRESULT hr; + + hr = (expect_test_time_source_sink_OnClockStart) ? S_OK : E_NOTIMPL; + todo_wine_if(!expect_test_time_source_sink_OnClockStart) + CHECK_EXPECT(test_time_source_sink_OnClockStart); + return hr; +} + +static HRESULT WINAPI test_time_source_sink_OnClockStop(IMFClockStateSink *iface, MFTIME system_time) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_time_source_sink_OnClockPause(IMFClockStateSink *iface, MFTIME system_time) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_time_source_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME system_time) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_time_source_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME system_time, float rate) +{ + return E_NOTIMPL; +} + +static IMFClockStateSinkVtbl test_time_source_sink_vtbl = +{ + test_time_source_sink_QueryInterface, + test_time_source_sink_AddRef, + test_time_source_sink_Release, + test_time_source_sink_OnClockStart, + test_time_source_sink_OnClockStop, + test_time_source_sink_OnClockPause, + test_time_source_sink_OnClockRestart, + test_time_source_sink_OnClockSetRate, +}; + +struct test_time_source *create_test_time_source(void) +{ + struct test_time_source *test_time_source; + test_time_source = calloc(1, sizeof(*test_time_source)); + test_time_source->IMFPresentationTimeSource_iface.lpVtbl = &test_time_source_vtbl; + test_time_source->IMFClockStateSink_iface.lpVtbl = &test_time_source_sink_vtbl; + test_time_source->refcount = 1; + + return test_time_source; +} + static void test_presentation_clock(void) { static const struct clock_state_test @@ -3904,6 +4090,7 @@ static void test_presentation_clock(void) { CLOCK_START, MFCLOCK_STATE_RUNNING, MFCLOCK_STATE_RUNNING }, }; IMFClockStateSink test_sink = { &test_clock_sink_vtbl }; + struct test_time_source *test_time_source; IMFPresentationTimeSource *time_source; struct test_callback *timer_callback; MFCLOCK_PROPERTIES props, props2; @@ -4207,6 +4394,49 @@ static void test_presentation_clock(void) IMFPresentationClock_Release(clock); + /* Test with a custom presentation time source */ + hr = MFCreatePresentationClock(&clock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + test_time_source = create_test_time_source(); + time_source = &test_time_source->IMFPresentationTimeSource_iface; + + hr = IMFPresentationClock_SetTimeSource(clock, time_source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFPresentationClock_AddClockStateSink(clock, &test_time_source->IMFClockStateSink_iface); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + SET_EXPECT(test_time_source_sink_OnClockStart); + hr = IMFPresentationClock_Start(clock, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + CHECK_CALLED(test_time_source_sink_OnClockStart); + + hr = IMFPresentationClock_QueryInterface(clock, &IID_IMFTimer, (void **)&timer); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + callback = create_test_callback(FALSE); + timer_callback = impl_from_IMFAsyncCallback(callback); + hr = IMFTimer_SetTimer(timer, 0, 1000000, callback, NULL, &timer_cancel_key); + ok(hr == S_OK, "got hr %#lx.\n", hr); + todo_wine + ok(WaitForSingleObject(timer_callback->event, 4000) == WAIT_TIMEOUT, "WaitForSingleObject should timeout.\n"); + + /* the timer will only trigger when the time of the time source is within 5ms of the target time */ + test_time_source->time = 1000000-50001; + ok(WaitForSingleObject(timer_callback->event, 4000) == WAIT_TIMEOUT, "WaitForSingleObject should timeout.\n"); + + test_time_source->time = 1000000-50000; + todo_wine + ok(WaitForSingleObject(timer_callback->event, 4000) == WAIT_OBJECT_0, "WaitForSingleObject failed.\n"); + + IUnknown_Release(timer_cancel_key); + IMFTimer_Release(timer); + IMFAsyncCallback_Release(callback); + + IMFPresentationTimeSource_Release(time_source); + IMFPresentationClock_Release(clock); + hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10095