Nikolay Sivov : mfplat: Implement time source state changes.
Alexandre Julliard
julliard at winehq.org
Wed Mar 6 15:29:40 CST 2019
Module: wine
Branch: master
Commit: 3865a8c9d5633b9f9c71ed39ab74aba6308f31cd
URL: https://source.winehq.org/git/wine.git/?a=commit;h=3865a8c9d5633b9f9c71ed39ab74aba6308f31cd
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Wed Mar 6 12:42:14 2019 +0300
mfplat: Implement time source state changes.
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/mfplat/main.c | 112 +++++++++++++++++++++++++++++++++++++++------
dlls/mfplat/tests/mfplat.c | 65 +++++++++++++++++++++++++-
2 files changed, 162 insertions(+), 15 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c
index 4ce97b1..6bec418 100644
--- a/dlls/mfplat/main.c
+++ b/dlls/mfplat/main.c
@@ -1,5 +1,4 @@
/*
- *
* Copyright 2014 Austin English
*
* This library is free software; you can redistribute it and/or
@@ -44,6 +43,8 @@ struct system_time_source
IMFPresentationTimeSource IMFPresentationTimeSource_iface;
IMFClockStateSink IMFClockStateSink_iface;
LONG refcount;
+ MFCLOCK_STATE state;
+ CRITICAL_SECTION cs;
};
static struct system_time_source *impl_from_IMFPresentationTimeSource(IMFPresentationTimeSource *iface)
@@ -3085,7 +3086,10 @@ static ULONG WINAPI system_time_source_Release(IMFPresentationTimeSource *iface)
TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount)
+ {
+ DeleteCriticalSection(&source->cs);
heap_free(source);
+ }
return refcount;
}
@@ -3120,9 +3124,15 @@ static HRESULT WINAPI system_time_source_GetContinuityKey(IMFPresentationTimeSou
static HRESULT WINAPI system_time_source_GetState(IMFPresentationTimeSource *iface, DWORD reserved,
MFCLOCK_STATE *state)
{
- FIXME("%p, %#x, %p.\n", iface, reserved, state);
+ struct system_time_source *source = impl_from_IMFPresentationTimeSource(iface);
- return E_NOTIMPL;
+ TRACE("%p, %#x, %p.\n", iface, reserved, state);
+
+ EnterCriticalSection(&source->cs);
+ *state = source->state;
+ LeaveCriticalSection(&source->cs);
+
+ return S_OK;
}
static HRESULT WINAPI system_time_source_GetProperties(IMFPresentationTimeSource *iface, MFCLOCK_PROPERTIES *props)
@@ -3170,32 +3180,107 @@ static ULONG WINAPI system_time_source_sink_Release(IMFClockStateSink *iface)
return IMFPresentationTimeSource_Release(&source->IMFPresentationTimeSource_iface);
}
-static HRESULT WINAPI system_time_source_sink_OnClockStart(IMFClockStateSink *iface, MFTIME system_time, LONGLONG start_offset)
+enum clock_command
{
- FIXME("%p, %s, %s.\n", iface, wine_dbgstr_longlong(system_time), wine_dbgstr_longlong(start_offset));
+ CLOCK_CMD_START = 0,
+ CLOCK_CMD_STOP,
+ CLOCK_CMD_PAUSE,
+ CLOCK_CMD_RESTART,
+ CLOCK_CMD_MAX,
+};
- return E_NOTIMPL;
+static HRESULT system_time_source_change_state(struct system_time_source *source, enum clock_command command)
+{
+ static const BYTE state_change_is_allowed[MFCLOCK_STATE_PAUSED+1][CLOCK_CMD_MAX] =
+ { /* S S* P R */
+ /* INVALID */ { 1, 0, 1, 0 },
+ /* RUNNING */ { 1, 1, 1, 0 },
+ /* STOPPED */ { 1, 1, 0, 0 },
+ /* PAUSED */ { 1, 1, 0, 1 },
+ };
+ static const MFCLOCK_STATE states[CLOCK_CMD_MAX] =
+ {
+ /* CLOCK_CMD_START */ MFCLOCK_STATE_RUNNING,
+ /* CLOCK_CMD_STOP */ MFCLOCK_STATE_STOPPED,
+ /* CLOCK_CMD_PAUSE */ MFCLOCK_STATE_PAUSED,
+ /* CLOCK_CMD_RESTART */ MFCLOCK_STATE_RUNNING,
+ };
+
+ /* Special case that go against usual state change vs return value behavior. */
+ if (source->state == MFCLOCK_STATE_INVALID && command == CLOCK_CMD_STOP)
+ return S_OK;
+
+ if (!state_change_is_allowed[source->state][command])
+ return MF_E_INVALIDREQUEST;
+
+ source->state = states[command];
+
+ return S_OK;
+}
+
+static HRESULT WINAPI system_time_source_sink_OnClockStart(IMFClockStateSink *iface, MFTIME system_time,
+ LONGLONG start_offset)
+{
+ struct system_time_source *source = impl_from_IMFClockStateSink(iface);
+ HRESULT hr;
+
+ 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);
+ LeaveCriticalSection(&source->cs);
+
+ /* FIXME: update timestamps */
+
+ return hr;
}
static HRESULT WINAPI system_time_source_sink_OnClockStop(IMFClockStateSink *iface, MFTIME system_time)
{
- FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
+ struct system_time_source *source = impl_from_IMFClockStateSink(iface);
+ HRESULT hr;
- return E_NOTIMPL;
+ TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
+
+ EnterCriticalSection(&source->cs);
+ hr = system_time_source_change_state(source, CLOCK_CMD_STOP);
+ LeaveCriticalSection(&source->cs);
+
+ /* FIXME: update timestamps */
+
+ return hr;
}
static HRESULT WINAPI system_time_source_sink_OnClockPause(IMFClockStateSink *iface, MFTIME system_time)
{
- FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
+ struct system_time_source *source = impl_from_IMFClockStateSink(iface);
+ HRESULT hr;
- return E_NOTIMPL;
+ TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
+
+ EnterCriticalSection(&source->cs);
+ hr = system_time_source_change_state(source, CLOCK_CMD_PAUSE);
+ LeaveCriticalSection(&source->cs);
+
+ /* FIXME: update timestamps */
+
+ return hr;
}
static HRESULT WINAPI system_time_source_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME system_time)
{
- FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
+ struct system_time_source *source = impl_from_IMFClockStateSink(iface);
+ HRESULT hr;
- return E_NOTIMPL;
+ TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
+
+ EnterCriticalSection(&source->cs);
+ hr = system_time_source_change_state(source, CLOCK_CMD_RESTART);
+ LeaveCriticalSection(&source->cs);
+
+ /* FIXME: update timestamps */
+
+ return hr;
}
static HRESULT WINAPI system_time_source_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME system_time, float rate)
@@ -3226,13 +3311,14 @@ HRESULT WINAPI MFCreateSystemTimeSource(IMFPresentationTimeSource **time_source)
TRACE("%p.\n", time_source);
- object = heap_alloc(sizeof(*object));
+ object = heap_alloc_zero(sizeof(*object));
if (!object)
return E_OUTOFMEMORY;
object->IMFPresentationTimeSource_iface.lpVtbl = &systemtimesourcevtbl;
object->IMFClockStateSink_iface.lpVtbl = &systemtimesourcesinkvtbl;
object->refcount = 1;
+ InitializeCriticalSection(&object->cs);
*time_source = &object->IMFPresentationTimeSource_iface;
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index cb3f2a9..c4685a3 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -1598,11 +1598,46 @@ static void test_presentation_descriptor(void)
IMFMediaType_Release(media_type);
}
+enum clock_action
+{
+ CLOCK_START,
+ CLOCK_STOP,
+ CLOCK_PAUSE,
+ CLOCK_RESTART,
+};
+
static void test_system_time_source(void)
{
+ static const struct clock_state_test
+ {
+ enum clock_action action;
+ MFCLOCK_STATE state;
+ BOOL is_invalid;
+ }
+ clock_state_change[] =
+ {
+ { CLOCK_STOP, MFCLOCK_STATE_INVALID },
+ { CLOCK_RESTART, MFCLOCK_STATE_INVALID, TRUE },
+ { CLOCK_PAUSE, MFCLOCK_STATE_PAUSED },
+ { CLOCK_PAUSE, MFCLOCK_STATE_PAUSED, TRUE },
+ { CLOCK_STOP, MFCLOCK_STATE_STOPPED },
+ { CLOCK_STOP, MFCLOCK_STATE_STOPPED },
+ { CLOCK_RESTART, MFCLOCK_STATE_STOPPED, TRUE },
+ { CLOCK_START, MFCLOCK_STATE_RUNNING },
+ { CLOCK_START, MFCLOCK_STATE_RUNNING },
+ { CLOCK_RESTART, MFCLOCK_STATE_RUNNING, TRUE },
+ { CLOCK_PAUSE, MFCLOCK_STATE_PAUSED },
+ { CLOCK_START, MFCLOCK_STATE_RUNNING },
+ { CLOCK_PAUSE, MFCLOCK_STATE_PAUSED },
+ { CLOCK_RESTART, MFCLOCK_STATE_RUNNING },
+ { CLOCK_RESTART, MFCLOCK_STATE_RUNNING, TRUE },
+ { CLOCK_STOP, MFCLOCK_STATE_STOPPED },
+ { CLOCK_PAUSE, MFCLOCK_STATE_STOPPED, TRUE },
+ };
IMFPresentationTimeSource *time_source;
IMFClockStateSink *statesink;
MFCLOCK_STATE state;
+ unsigned int i;
DWORD value;
HRESULT hr;
@@ -1620,12 +1655,38 @@ static void test_system_time_source(void)
ok(value == 0, "Unexpected value %u.\n", value);
hr = IMFPresentationTimeSource_GetState(time_source, 0, &state);
-todo_wine {
ok(hr == S_OK, "Failed to get state, hr %#x.\n", hr);
ok(state == MFCLOCK_STATE_INVALID, "Unexpected state %d.\n", state);
-}
+
hr = IMFPresentationTimeSource_QueryInterface(time_source, &IID_IMFClockStateSink, (void **)&statesink);
ok(hr == S_OK, "Failed to get state sink, hr %#x.\n", hr);
+
+ /* State changes. */
+ for (i = 0; i < ARRAY_SIZE(clock_state_change); ++i)
+ {
+ switch (clock_state_change[i].action)
+ {
+ case CLOCK_STOP:
+ hr = IMFClockStateSink_OnClockStop(statesink, 0);
+ break;
+ case CLOCK_RESTART:
+ hr = IMFClockStateSink_OnClockRestart(statesink, 0);
+ break;
+ case CLOCK_PAUSE:
+ hr = IMFClockStateSink_OnClockPause(statesink, 0);
+ break;
+ case CLOCK_START:
+ hr = IMFClockStateSink_OnClockStart(statesink, 0, 0);
+ break;
+ default:
+ ;
+ }
+ ok(hr == (clock_state_change[i].is_invalid ? MF_E_INVALIDREQUEST : S_OK), "%u: unexpected hr %#x.\n", i, hr);
+ hr = IMFPresentationTimeSource_GetState(time_source, 0, &state);
+ ok(hr == S_OK, "%u: failed to get state, hr %#x.\n", i, hr);
+ ok(state == clock_state_change[i].state, "%u: unexpected state %d.\n", i, state);
+ }
+
IMFClockStateSink_Release(statesink);
IMFPresentationTimeSource_Release(time_source);
More information about the wine-cvs
mailing list