Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 81 +++++++++++++++----- dlls/mfplat/tests/mfplat.c | 152 +++++++++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+), 17 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 23f13afa3a..1009f4083b 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -18,6 +18,7 @@
#include <stdarg.h> #include <string.h> +#include <math.h>
#define COBJMACROS #define NONAMELESSUNION @@ -57,9 +58,20 @@ struct system_time_source LONG refcount; MFCLOCK_STATE state; IMFClock *clock; + LONGLONG start_offset; + float rate; + int i_rate; CRITICAL_SECTION cs; };
+static void system_time_source_apply_rate(const struct system_time_source *source, LONGLONG *value) +{ + if (source->i_rate) + *value *= source->i_rate; + else + *value *= source->rate; +} + static struct system_time_source *impl_from_IMFPresentationTimeSource(IMFPresentationTimeSource *iface) { return CONTAINING_RECORD(iface, struct system_time_source, IMFPresentationTimeSource_iface); @@ -6736,11 +6748,26 @@ static HRESULT WINAPI system_time_source_GetClockCharacteristics(IMFPresentation static HRESULT WINAPI system_time_source_GetCorrelatedTime(IMFPresentationTimeSource *iface, DWORD reserved, LONGLONG *clock_time, MFTIME *system_time) { - FIXME("%p, %#x, %p, %p.\n", iface, reserved, clock_time, system_time); + struct system_time_source *source = impl_from_IMFPresentationTimeSource(iface); + HRESULT hr;
- return E_NOTIMPL; -} + TRACE("%p, %#x, %p, %p.\n", iface, reserved, clock_time, system_time);
+ EnterCriticalSection(&source->cs); + if (SUCCEEDED(hr = IMFClock_GetCorrelatedTime(source->clock, 0, clock_time, system_time))) + { + if (source->state == MFCLOCK_STATE_RUNNING) + { + system_time_source_apply_rate(source, clock_time); + *clock_time += source->start_offset; + } + else + *clock_time = source->start_offset; + } + LeaveCriticalSection(&source->cs); + + return hr; +}
static HRESULT WINAPI system_time_source_GetContinuityKey(IMFPresentationTimeSource *iface, DWORD *key) { @@ -6870,11 +6897,13 @@ static HRESULT WINAPI system_time_source_sink_OnClockStart(IMFClockStateSink *if TRACE("%p, %s, %s.\n", iface, wine_dbgstr_longlong(system_time), wine_dbgstr_longlong(start_offset));
EnterCriticalSection(&source->cs); - hr = system_time_source_change_state(source, CLOCK_CMD_START); + if (SUCCEEDED(hr = system_time_source_change_state(source, CLOCK_CMD_START))) + { + system_time_source_apply_rate(source, &system_time); + source->start_offset = -system_time + start_offset; + } LeaveCriticalSection(&source->cs);
- /* FIXME: update timestamps */ - return hr; }
@@ -6886,11 +6915,10 @@ static HRESULT WINAPI system_time_source_sink_OnClockStop(IMFClockStateSink *ifa TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
EnterCriticalSection(&source->cs); - hr = system_time_source_change_state(source, CLOCK_CMD_STOP); + if (SUCCEEDED(hr = system_time_source_change_state(source, CLOCK_CMD_STOP))) + source->start_offset = 0; LeaveCriticalSection(&source->cs);
- /* FIXME: update timestamps */ - return hr; }
@@ -6902,11 +6930,13 @@ static HRESULT WINAPI system_time_source_sink_OnClockPause(IMFClockStateSink *if TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
EnterCriticalSection(&source->cs); - hr = system_time_source_change_state(source, CLOCK_CMD_PAUSE); + if (SUCCEEDED(hr = system_time_source_change_state(source, CLOCK_CMD_PAUSE))) + { + system_time_source_apply_rate(source, &system_time); + source->start_offset += system_time; + } LeaveCriticalSection(&source->cs);
- /* FIXME: update timestamps */ - return hr; }
@@ -6918,19 +6948,34 @@ static HRESULT WINAPI system_time_source_sink_OnClockRestart(IMFClockStateSink * TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
EnterCriticalSection(&source->cs); - hr = system_time_source_change_state(source, CLOCK_CMD_RESTART); + if (SUCCEEDED(hr = system_time_source_change_state(source, CLOCK_CMD_RESTART))) + { + system_time_source_apply_rate(source, &system_time); + source->start_offset -= system_time; + } LeaveCriticalSection(&source->cs);
- /* FIXME: update timestamps */ - return hr; }
static HRESULT WINAPI system_time_source_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME system_time, float rate) { - FIXME("%p, %s, %f.\n", iface, wine_dbgstr_longlong(system_time), rate); + struct system_time_source *source = impl_from_IMFClockStateSink(iface); + double intpart;
- return E_NOTIMPL; + TRACE("%p, %s, %f.\n", iface, wine_dbgstr_longlong(system_time), rate); + + if (rate == 0.0f) + return MF_E_UNSUPPORTED_RATE; + + modf(rate, &intpart); + + EnterCriticalSection(&source->cs); + source->rate = rate; + source->i_rate = rate == intpart ? rate : 0; + LeaveCriticalSection(&source->cs); + + return S_OK; }
static const IMFClockStateSinkVtbl systemtimesourcesinkvtbl = @@ -6962,6 +7007,8 @@ HRESULT WINAPI MFCreateSystemTimeSource(IMFPresentationTimeSource **time_source) object->IMFPresentationTimeSource_iface.lpVtbl = &systemtimesourcevtbl; object->IMFClockStateSink_iface.lpVtbl = &systemtimesourcesinkvtbl; object->refcount = 1; + object->rate = 1.0f; + object->i_rate = 1; InitializeCriticalSection(&object->cs);
if (FAILED(hr = create_system_clock(&object->clock))) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index e385987f33..295863716b 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -2675,6 +2675,158 @@ static void test_system_time_source(void)
IMFClock_Release(clock);
+ /* Test returned time regarding specified rate and offset. */ + hr = IMFPresentationTimeSource_QueryInterface(time_source, &IID_IMFClockStateSink, (void **)&statesink); + ok(hr == S_OK, "Failed to get sink interface, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetState(time_source, 0, &state); + ok(hr == S_OK, "Failed to get state %#x.\n", hr); + ok(state == MFCLOCK_STATE_STOPPED, "Unexpected state %d.\n", state); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == 0, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), wine_dbgstr_longlong(systime)); + + hr = IMFClockStateSink_OnClockStart(statesink, 0, 0); + ok(hr == S_OK, "Failed to start source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == systime, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), wine_dbgstr_longlong(systime)); + + hr = IMFClockStateSink_OnClockStart(statesink, 0, 1); + ok(hr == S_OK, "Failed to start source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == systime + 1, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), + wine_dbgstr_longlong(systime)); + + hr = IMFClockStateSink_OnClockPause(statesink, 2); + ok(hr == S_OK, "Failed to pause source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == 3, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), wine_dbgstr_longlong(systime)); + + hr = IMFClockStateSink_OnClockRestart(statesink, 5); + ok(hr == S_OK, "Failed to restart source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == systime - 2, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), + wine_dbgstr_longlong(systime)); + + hr = IMFClockStateSink_OnClockPause(statesink, 0); + ok(hr == S_OK, "Failed to pause source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == -2, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), + wine_dbgstr_longlong(systime)); + + hr = IMFClockStateSink_OnClockStop(statesink, 123); + ok(hr == S_OK, "Failed to stop source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == 0, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), wine_dbgstr_longlong(systime)); + + /* Increased rate. */ + hr = IMFClockStateSink_OnClockSetRate(statesink, 0, 2.0f); + ok(hr == S_OK, "Failed to set rate, hr %#x.\n", hr); + + hr = IMFClockStateSink_OnClockStart(statesink, 0, 0); + ok(hr == S_OK, "Failed to start source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == 2 * systime, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), + wine_dbgstr_longlong(2 * systime)); + + hr = IMFClockStateSink_OnClockStart(statesink, 0, 10); + ok(hr == S_OK, "Failed to start source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == 2 * systime + 10, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), + wine_dbgstr_longlong(2 * systime)); + + hr = IMFClockStateSink_OnClockPause(statesink, 2); + ok(hr == S_OK, "Failed to pause source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == 10 + 2 * 2, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), + wine_dbgstr_longlong(systime)); + + hr = IMFClockStateSink_OnClockRestart(statesink, 5); + ok(hr == S_OK, "Failed to restart source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == 2 * systime + 14 - 5 * 2, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), + wine_dbgstr_longlong(systime)); + + hr = IMFClockStateSink_OnClockPause(statesink, 0); + ok(hr == S_OK, "Failed to pause source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == 4, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), + wine_dbgstr_longlong(systime)); + + hr = IMFClockStateSink_OnClockStop(statesink, 123); + ok(hr == S_OK, "Failed to stop source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == 0, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), wine_dbgstr_longlong(systime)); + IMFClockStateSink_Release(statesink); + + hr = IMFClockStateSink_OnClockStart(statesink, 10, 0); + ok(hr == S_OK, "Failed to start source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == 2 * systime - 2 * 10, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), + wine_dbgstr_longlong(2 * systime)); + + hr = IMFClockStateSink_OnClockStop(statesink, 123); + ok(hr == S_OK, "Failed to stop source, hr %#x.\n", hr); + + hr = IMFClockStateSink_OnClockStart(statesink, 10, 20); + ok(hr == S_OK, "Failed to start source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == 2 * systime, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), + wine_dbgstr_longlong(2 * systime)); + + hr = IMFClockStateSink_OnClockPause(statesink, 2); + ok(hr == S_OK, "Failed to pause source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == 2 * 2, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), + wine_dbgstr_longlong(systime)); + + hr = IMFClockStateSink_OnClockRestart(statesink, 5); + ok(hr == S_OK, "Failed to restart source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == 2 * systime + 4 - 5 * 2, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), + wine_dbgstr_longlong(systime)); + + hr = IMFClockStateSink_OnClockPause(statesink, 0); + ok(hr == S_OK, "Failed to pause source, hr %#x.\n", hr); + + hr = IMFPresentationTimeSource_GetCorrelatedTime(time_source, 0, &time, &systime); + ok(hr == S_OK, "Failed to get time %#x.\n", hr); + ok(time == -6, "Unexpected time stamp %s, %s.\n", wine_dbgstr_longlong(time), + wine_dbgstr_longlong(systime)); + IMFPresentationTimeSource_Release(time_source); }