[PATCH 1/3] mf: Control time source state from presentation clock.

Nikolay Sivov nsivov at codeweavers.com
Thu Mar 7 01:07:52 CST 2019


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 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 2961abe879..27b2c4cce6 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 9fa0bda839..bae674d7fa 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 be35e6e20f..f7f0934d6c 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 */
-- 
2.20.1




More information about the wine-devel mailing list