Nikolay Sivov : mf: Control time source state from presentation clock.
Alexandre Julliard
julliard at winehq.org
Thu Mar 7 16:27:58 CST 2019
Module: wine
Branch: master
Commit: c815f908f97c9f90ee08a82a1a5b2d7c052a5fc2
URL: https://source.winehq.org/git/wine.git/?a=commit;h=c815f908f97c9f90ee08a82a1a5b2d7c052a5fc2
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Thu Mar 7 10:07:52 2019 +0300
mf: Control time source state from presentation clock.
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/mf/session.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++----
dlls/mf/tests/mf.c | 67 +++++++++++++++++++++++++++++
include/mferror.h | 3 +-
3 files changed, 182 insertions(+), 9 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 2961abe..27b2c4c 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -47,6 +47,7 @@ struct presentation_clock
IMFShutdown IMFShutdown_iface;
LONG refcount;
IMFPresentationTimeSource *time_source;
+ IMFClockStateSink *time_source_sink;
MFCLOCK_STATE state;
CRITICAL_SECTION cs;
};
@@ -341,6 +342,8 @@ static ULONG WINAPI present_clock_Release(IMFPresentationClock *iface)
{
if (clock->time_source)
IMFPresentationTimeSource_Release(clock->time_source);
+ if (clock->time_source_sink)
+ IMFClockStateSink_Release(clock->time_source_sink);
DeleteCriticalSection(&clock->cs);
heap_free(clock);
}
@@ -395,9 +398,29 @@ static HRESULT WINAPI present_clock_GetProperties(IMFPresentationClock *iface, M
static HRESULT WINAPI present_clock_SetTimeSource(IMFPresentationClock *iface,
IMFPresentationTimeSource *time_source)
{
- FIXME("%p, %p.\n", iface, time_source);
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ HRESULT hr;
- return E_NOTIMPL;
+ TRACE("%p, %p.\n", iface, time_source);
+
+ EnterCriticalSection(&clock->cs);
+ if (clock->time_source)
+ IMFPresentationTimeSource_Release(clock->time_source);
+ if (clock->time_source_sink)
+ IMFClockStateSink_Release(clock->time_source_sink);
+ clock->time_source = NULL;
+ clock->time_source_sink = NULL;
+
+ hr = IMFPresentationTimeSource_QueryInterface(time_source, &IID_IMFClockStateSink, (void **)&clock->time_source_sink);
+ if (SUCCEEDED(hr))
+ {
+ clock->time_source = time_source;
+ IMFPresentationTimeSource_AddRef(clock->time_source);
+ }
+
+ LeaveCriticalSection(&clock->cs);
+
+ return hr;
}
static HRESULT WINAPI present_clock_GetTimeSource(IMFPresentationClock *iface,
@@ -443,25 +466,107 @@ static HRESULT WINAPI present_clock_RemoveClockStateSink(IMFPresentationClock *i
return E_NOTIMPL;
}
+enum clock_command
+{
+ CLOCK_CMD_START = 0,
+ CLOCK_CMD_STOP,
+ CLOCK_CMD_PAUSE,
+ CLOCK_CMD_MAX,
+};
+
+static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_command command)
+{
+ static const BYTE state_change_is_allowed[MFCLOCK_STATE_PAUSED+1][CLOCK_CMD_MAX] =
+ { /* S S* P */
+ /* INVALID */ { 1, 1, 1 },
+ /* RUNNING */ { 1, 1, 1 },
+ /* STOPPED */ { 1, 1, 0 },
+ /* PAUSED */ { 1, 1, 0 },
+ };
+ 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,
+ };
+ HRESULT hr;
+
+ /* FIXME: use correct timestamps. */
+
+ if (clock->state == states[command] && clock->state != MFCLOCK_STATE_RUNNING)
+ return MF_E_CLOCK_STATE_ALREADY_SET;
+
+ if (!state_change_is_allowed[clock->state][command])
+ return MF_E_INVALIDREQUEST;
+
+ switch (command)
+ {
+ case CLOCK_CMD_START:
+ if (clock->state == MFCLOCK_STATE_PAUSED)
+ hr = IMFClockStateSink_OnClockRestart(clock->time_source_sink, 0);
+ else
+ hr = IMFClockStateSink_OnClockStart(clock->time_source_sink, 0, 0);
+ break;
+ case CLOCK_CMD_STOP:
+ hr = IMFClockStateSink_OnClockStop(clock->time_source_sink, 0);
+ break;
+ case CLOCK_CMD_PAUSE:
+ hr = IMFClockStateSink_OnClockPause(clock->time_source_sink, 0);
+ break;
+ default:
+ ;
+ }
+
+ if (FAILED(hr))
+ return hr;
+
+ clock->state = states[command];
+
+ /* FIXME: notify registered sinks. */
+
+ return S_OK;
+}
+
static HRESULT WINAPI present_clock_Start(IMFPresentationClock *iface, LONGLONG start_offset)
{
- FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(start_offset));
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ HRESULT hr;
- return E_NOTIMPL;
+ TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(start_offset));
+
+ EnterCriticalSection(&clock->cs);
+ hr = clock_change_state(clock, CLOCK_CMD_START);
+ LeaveCriticalSection(&clock->cs);
+
+ return hr;
}
static HRESULT WINAPI present_clock_Stop(IMFPresentationClock *iface)
{
- FIXME("%p.\n", iface);
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ HRESULT hr;
- return E_NOTIMPL;
+ TRACE("%p.\n", iface);
+
+ EnterCriticalSection(&clock->cs);
+ hr = clock_change_state(clock, CLOCK_CMD_STOP);
+ LeaveCriticalSection(&clock->cs);
+
+ return hr;
}
static HRESULT WINAPI present_clock_Pause(IMFPresentationClock *iface)
{
- FIXME("%p.\n", iface);
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ HRESULT hr;
- return E_NOTIMPL;
+ TRACE("%p.\n", iface);
+
+ EnterCriticalSection(&clock->cs);
+ hr = clock_change_state(clock, CLOCK_CMD_PAUSE);
+ LeaveCriticalSection(&clock->cs);
+
+ return hr;
}
static const IMFPresentationClockVtbl presentationclockvtbl =
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index 9fa0bda..bae674d 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -735,8 +735,37 @@ static void test_MFShutdownObject(void)
ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
}
+enum clock_action
+{
+ CLOCK_START,
+ CLOCK_STOP,
+ CLOCK_PAUSE,
+};
+
static void test_presentation_clock(void)
{
+ static const struct clock_state_test
+ {
+ enum clock_action action;
+ MFCLOCK_STATE clock_state;
+ MFCLOCK_STATE source_state;
+ HRESULT hr;
+ }
+ clock_state_change[] =
+ {
+ { CLOCK_STOP, MFCLOCK_STATE_STOPPED, MFCLOCK_STATE_INVALID },
+ { CLOCK_PAUSE, MFCLOCK_STATE_STOPPED, MFCLOCK_STATE_INVALID, MF_E_INVALIDREQUEST },
+ { CLOCK_STOP, MFCLOCK_STATE_STOPPED, MFCLOCK_STATE_INVALID, MF_E_CLOCK_STATE_ALREADY_SET },
+ { CLOCK_START, MFCLOCK_STATE_RUNNING, MFCLOCK_STATE_RUNNING },
+ { CLOCK_START, MFCLOCK_STATE_RUNNING, MFCLOCK_STATE_RUNNING },
+ { CLOCK_PAUSE, MFCLOCK_STATE_PAUSED, MFCLOCK_STATE_PAUSED },
+ { CLOCK_PAUSE, MFCLOCK_STATE_PAUSED, MFCLOCK_STATE_PAUSED, MF_E_CLOCK_STATE_ALREADY_SET },
+ { CLOCK_STOP, MFCLOCK_STATE_STOPPED, MFCLOCK_STATE_STOPPED },
+ { CLOCK_START, MFCLOCK_STATE_RUNNING, MFCLOCK_STATE_RUNNING },
+ { CLOCK_STOP, MFCLOCK_STATE_STOPPED, MFCLOCK_STATE_STOPPED },
+ { CLOCK_STOP, MFCLOCK_STATE_STOPPED, MFCLOCK_STATE_STOPPED, MF_E_CLOCK_STATE_ALREADY_SET },
+ { CLOCK_PAUSE, MFCLOCK_STATE_STOPPED, MFCLOCK_STATE_STOPPED, MF_E_INVALIDREQUEST },
+ };
IMFPresentationTimeSource *time_source;
IMFRateControl *rate_control;
IMFPresentationClock *clock;
@@ -746,6 +775,7 @@ static void test_presentation_clock(void)
MFCLOCK_STATE state;
IMFTimer *timer;
MFTIME systime;
+ unsigned int i;
DWORD value;
HRESULT hr;
@@ -779,6 +809,43 @@ todo_wine
todo_wine
ok(hr == MF_E_CLOCK_NO_TIME_SOURCE, "Unexpected hr %#x.\n", hr);
+ /* Set default time source. */
+ hr = MFCreateSystemTimeSource(&time_source);
+ ok(hr == S_OK, "Failed to create time source, hr %#x.\n", hr);
+
+ hr = IMFPresentationClock_SetTimeSource(clock, time_source);
+ ok(hr == S_OK, "Failed to set time source, 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 = IMFPresentationClock_Stop(clock);
+ break;
+ case CLOCK_PAUSE:
+ hr = IMFPresentationClock_Pause(clock);
+ break;
+ case CLOCK_START:
+ hr = IMFPresentationClock_Start(clock, 0);
+ break;
+ default:
+ ;
+ }
+ ok(hr == clock_state_change[i].hr, "%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].source_state, "%u: unexpected state %d.\n", i, state);
+
+ hr = IMFPresentationClock_GetState(clock, 0, &state);
+ ok(hr == S_OK, "%u: failed to get state, hr %#x.\n", i, hr);
+ ok(state == clock_state_change[i].clock_state, "%u: unexpected state %d.\n", i, state);
+ }
+
+ IMFPresentationTimeSource_Release(time_source);
+
hr = IMFPresentationClock_QueryInterface(clock, &IID_IMFRateControl, (void **)&rate_control);
ok(hr == S_OK, "Failed to get rate control interface, hr %#x.\n", hr);
IMFRateControl_Release(rate_control);
diff --git a/include/mferror.h b/include/mferror.h
index be35e6e..f7f0934 100644
--- a/include/mferror.h
+++ b/include/mferror.h
@@ -82,6 +82,7 @@
#define MF_E_TOPO_MISSING_SOURCE _HRESULT_TYPEDEF_(0xc00d521a)
#define MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED _HRESULT_TYPEDEF_(0xc00d521b)
-#define MF_E_CLOCK_NO_TIME_SOURCE _HRESULT_TYPEDEF_(0xc00d9c41)
+#define MF_E_CLOCK_NO_TIME_SOURCE _HRESULT_TYPEDEF_(0xc00d9c41)
+#define MF_E_CLOCK_STATE_ALREADY_SET _HRESULT_TYPEDEF_(0xc00d9c42)
#endif /* __WINE_MFERROR_H */
More information about the wine-cvs
mailing list