[PATCH 1/2] mf: Add rate support for presentation clock.

Nikolay Sivov nsivov at codeweavers.com
Mon Jun 3 05:11:33 CDT 2019


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mf/session.c  | 107 +++++++++++++++++++++++++++++++++------------
 dlls/mf/tests/mf.c |  52 ++++++++++++++++++++++
 2 files changed, 131 insertions(+), 28 deletions(-)

diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 8e41942448..3a33a88a4b 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -85,6 +85,7 @@ enum clock_command
     CLOCK_CMD_START = 0,
     CLOCK_CMD_STOP,
     CLOCK_CMD_PAUSE,
+    CLOCK_CMD_SET_RATE,
     CLOCK_CMD_MAX,
 };
 
@@ -94,6 +95,16 @@ enum clock_notification
     CLOCK_NOTIFY_STOP,
     CLOCK_NOTIFY_PAUSE,
     CLOCK_NOTIFY_RESTART,
+    CLOCK_NOTIFY_SET_RATE,
+};
+
+struct clock_state_change_param
+{
+    union
+    {
+        LONGLONG offset;
+        float rate;
+    } u;
 };
 
 struct sink_notification
@@ -101,7 +112,7 @@ struct sink_notification
     IUnknown IUnknown_iface;
     LONG refcount;
     MFTIME system_time;
-    LONGLONG offset;
+    struct clock_state_change_param param;
     enum clock_notification notification;
     IMFClockStateSink *sink;
 };
@@ -118,6 +129,7 @@ struct presentation_clock
     IMFClockStateSink *time_source_sink;
     MFCLOCK_STATE state;
     struct list sinks;
+    float rate;
     CRITICAL_SECTION cs;
 };
 
@@ -1092,8 +1104,8 @@ static const IUnknownVtbl sinknotificationvtbl =
     sink_notification_Release,
 };
 
-static HRESULT create_sink_notification(MFTIME system_time, LONGLONG offset, enum clock_notification notification,
-        IMFClockStateSink *sink, IUnknown **out)
+static HRESULT create_sink_notification(MFTIME system_time, struct clock_state_change_param param,
+        enum clock_notification notification, IMFClockStateSink *sink, IUnknown **out)
 {
     struct sink_notification *object;
 
@@ -1104,7 +1116,7 @@ static HRESULT create_sink_notification(MFTIME system_time, LONGLONG offset, enu
     object->IUnknown_iface.lpVtbl = &sinknotificationvtbl;
     object->refcount = 1;
     object->system_time = system_time;
-    object->offset = offset;
+    object->param = param;
     object->notification = notification;
     object->sink = sink;
     IMFClockStateSink_AddRef(object->sink);
@@ -1114,15 +1126,15 @@ static HRESULT create_sink_notification(MFTIME system_time, LONGLONG offset, enu
     return S_OK;
 }
 
-static HRESULT clock_call_state_change(MFTIME system_time, LONGLONG offset, enum clock_notification notification,
-        IMFClockStateSink *sink)
+static HRESULT clock_call_state_change(MFTIME system_time, struct clock_state_change_param param,
+        enum clock_notification notification, IMFClockStateSink *sink)
 {
     HRESULT hr = S_OK;
 
     switch (notification)
     {
         case CLOCK_NOTIFY_START:
-            hr = IMFClockStateSink_OnClockStart(sink, system_time, offset);
+            hr = IMFClockStateSink_OnClockStart(sink, system_time, param.u.offset);
             break;
         case CLOCK_NOTIFY_STOP:
             hr = IMFClockStateSink_OnClockStop(sink, system_time);
@@ -1133,6 +1145,10 @@ static HRESULT clock_call_state_change(MFTIME system_time, LONGLONG offset, enum
         case CLOCK_NOTIFY_RESTART:
             hr = IMFClockStateSink_OnClockRestart(sink, system_time);
             break;
+        case CLOCK_NOTIFY_SET_RATE:
+            /* System time source does not allow 0.0 rate, presentation clock allows it without raising errors. */
+            IMFClockStateSink_OnClockSetRate(sink, system_time, param.u.rate);
+            break;
         default:
             ;
     }
@@ -1140,20 +1156,22 @@ static HRESULT clock_call_state_change(MFTIME system_time, LONGLONG offset, enum
     return hr;
 }
 
-static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_command command, LONGLONG offset)
+static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_command command,
+        struct clock_state_change_param param)
 {
     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 },
+    {   /*              S  S* P, R  */
+        /* INVALID */ { 1, 1, 1, 1 },
+        /* RUNNING */ { 1, 1, 1, 1 },
+        /* STOPPED */ { 1, 1, 0, 1 },
+        /* 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_START    */ MFCLOCK_STATE_RUNNING,
+        /* CLOCK_CMD_STOP     */ MFCLOCK_STATE_STOPPED,
+        /* CLOCK_CMD_PAUSE    */ MFCLOCK_STATE_PAUSED,
+        /* CLOCK_CMD_SET_RATE */ 0, /* Unused */
     };
     enum clock_notification notification;
     struct clock_sink *sink;
@@ -1162,7 +1180,7 @@ static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_c
     MFTIME system_time;
     HRESULT hr;
 
-    if (clock->state == states[command] && clock->state != MFCLOCK_STATE_RUNNING)
+    if (command != CLOCK_CMD_SET_RATE && clock->state == states[command] && clock->state != MFCLOCK_STATE_RUNNING)
         return MF_E_CLOCK_STATE_ALREADY_SET;
 
     if (!state_change_is_allowed[clock->state][command])
@@ -1173,7 +1191,7 @@ static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_c
     switch (command)
     {
         case CLOCK_CMD_START:
-            if (clock->state == MFCLOCK_STATE_PAUSED && offset == PRESENTATION_CURRENT_POSITION)
+            if (clock->state == MFCLOCK_STATE_PAUSED && param.u.offset == PRESENTATION_CURRENT_POSITION)
                 notification = CLOCK_NOTIFY_RESTART;
             else
                 notification = CLOCK_NOTIFY_START;
@@ -1184,18 +1202,21 @@ static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_c
         case CLOCK_CMD_PAUSE:
             notification = CLOCK_NOTIFY_PAUSE;
             break;
+        case CLOCK_CMD_SET_RATE:
+            notification = CLOCK_NOTIFY_SET_RATE;
+            break;
         default:
             ;
     }
 
-    if (FAILED(hr = clock_call_state_change(system_time, offset, notification, clock->time_source_sink)))
+    if (FAILED(hr = clock_call_state_change(system_time, param, notification, clock->time_source_sink)))
         return hr;
 
     clock->state = states[command];
 
     LIST_FOR_EACH_ENTRY(sink, &clock->sinks, struct clock_sink, entry)
     {
-        if (SUCCEEDED(create_sink_notification(system_time, offset, notification, sink->state_sink, &notify_object)))
+        if (SUCCEEDED(create_sink_notification(system_time, param, notification, sink->state_sink, &notify_object)))
         {
             hr = MFCreateAsyncResult(notify_object, &clock->IMFAsyncCallback_iface, NULL, &result);
             IUnknown_Release(notify_object);
@@ -1213,12 +1234,14 @@ static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_c
 static HRESULT WINAPI present_clock_Start(IMFPresentationClock *iface, LONGLONG start_offset)
 {
     struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+    struct clock_state_change_param param = { 0 };
     HRESULT hr;
 
     TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(start_offset));
 
     EnterCriticalSection(&clock->cs);
-    hr = clock_change_state(clock, CLOCK_CMD_START, start_offset);
+    param.u.offset = start_offset;
+    hr = clock_change_state(clock, CLOCK_CMD_START, param);
     LeaveCriticalSection(&clock->cs);
 
     return hr;
@@ -1227,12 +1250,13 @@ static HRESULT WINAPI present_clock_Start(IMFPresentationClock *iface, LONGLONG
 static HRESULT WINAPI present_clock_Stop(IMFPresentationClock *iface)
 {
     struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+    struct clock_state_change_param param = { 0 };
     HRESULT hr;
 
     TRACE("%p.\n", iface);
 
     EnterCriticalSection(&clock->cs);
-    hr = clock_change_state(clock, CLOCK_CMD_STOP, 0);
+    hr = clock_change_state(clock, CLOCK_CMD_STOP, param);
     LeaveCriticalSection(&clock->cs);
 
     return hr;
@@ -1241,12 +1265,13 @@ static HRESULT WINAPI present_clock_Stop(IMFPresentationClock *iface)
 static HRESULT WINAPI present_clock_Pause(IMFPresentationClock *iface)
 {
     struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+    struct clock_state_change_param param = { 0 };
     HRESULT hr;
 
     TRACE("%p.\n", iface);
 
     EnterCriticalSection(&clock->cs);
-    hr = clock_change_state(clock, CLOCK_CMD_PAUSE, 0);
+    hr = clock_change_state(clock, CLOCK_CMD_PAUSE, param);
     LeaveCriticalSection(&clock->cs);
 
     return hr;
@@ -1292,16 +1317,41 @@ static ULONG WINAPI present_clock_rate_control_Release(IMFRateControl *iface)
 
 static HRESULT WINAPI present_clock_rate_SetRate(IMFRateControl *iface, BOOL thin, float rate)
 {
-    FIXME("%p, %d, %f.\n", iface, thin, rate);
+    struct presentation_clock *clock = impl_from_IMFRateControl(iface);
+    struct clock_state_change_param param;
+    HRESULT hr;
 
-    return E_NOTIMPL;
+    TRACE("%p, %d, %f.\n", iface, thin, rate);
+
+    if (thin)
+        return MF_E_THINNING_UNSUPPORTED;
+
+    EnterCriticalSection(&clock->cs);
+    param.u.rate = rate;
+    if (SUCCEEDED(hr = clock_change_state(clock, CLOCK_CMD_SET_RATE, param)))
+        clock->rate = rate;
+    LeaveCriticalSection(&clock->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI present_clock_rate_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
 {
-    FIXME("%p, %p, %p.\n", iface, thin, rate);
+    struct presentation_clock *clock = impl_from_IMFRateControl(iface);
 
-    return E_NOTIMPL;
+    TRACE("%p, %p, %p.\n", iface, thin, rate);
+
+    if (!rate)
+        return E_INVALIDARG;
+
+    if (thin)
+        *thin = FALSE;
+
+    EnterCriticalSection(&clock->cs);
+    *rate = clock->rate;
+    LeaveCriticalSection(&clock->cs);
+
+    return S_OK;
 }
 
 static const IMFRateControlVtbl presentclockratecontrolvtbl =
@@ -1439,7 +1489,7 @@ static HRESULT WINAPI present_clock_sink_callback_Invoke(IMFAsyncCallback *iface
 
     data = impl_from_IUnknown(object);
 
-    clock_call_state_change(data->system_time, data->offset, data->notification, data->sink);
+    clock_call_state_change(data->system_time, data->param, data->notification, data->sink);
 
     IUnknown_Release(object);
 
@@ -1475,6 +1525,7 @@ HRESULT WINAPI MFCreatePresentationClock(IMFPresentationClock **clock)
     object->IMFAsyncCallback_iface.lpVtbl = &presentclocksinkcallbackvtbl;
     object->refcount = 1;
     list_init(&object->sinks);
+    object->rate = 1.0f;
     InitializeCriticalSection(&object->cs);
 
     *clock = &object->IMFPresentationClock_iface;
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index 8f9a97d497..cb2db22d93 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -1430,6 +1430,7 @@ static void test_presentation_clock(void)
     MFCLOCK_PROPERTIES props, props2;
     IMFRateControl *rate_control;
     IMFPresentationClock *clock;
+    MFSHUTDOWN_STATUS status;
     IMFShutdown *shutdown;
     MFTIME systime, time;
     LONGLONG clock_time;
@@ -1437,7 +1438,9 @@ static void test_presentation_clock(void)
     IMFTimer *timer;
     unsigned int i;
     DWORD value;
+    float rate;
     HRESULT hr;
+    BOOL thin;
 
     hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
     ok(hr == S_OK, "Failed to start up, hr %#x.\n", hr);
@@ -1577,6 +1580,40 @@ static void test_presentation_clock(void)
 
     hr = IMFPresentationClock_QueryInterface(clock, &IID_IMFRateControl, (void **)&rate_control);
     ok(hr == S_OK, "Failed to get rate control interface, hr %#x.\n", hr);
+
+    hr = IMFRateControl_GetRate(rate_control, NULL, &rate);
+    ok(hr == S_OK, "Failed to get clock rate, hr %#x.\n", hr);
+
+    hr = IMFRateControl_GetRate(rate_control, &thin, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+    hr = IMFRateControl_GetRate(rate_control, &thin, &rate);
+    ok(hr == S_OK, "Failed to get clock rate, hr %#x.\n", hr);
+    ok(rate == 1.0f, "Unexpected rate.\n");
+    ok(!thin, "Unexpected thinning.\n");
+
+    hr = IMFPresentationClock_Start(clock, 0);
+    ok(hr == S_OK, "Failed to stop, hr %#x.\n", hr);
+
+    hr = IMFRateControl_SetRate(rate_control, FALSE, 0.0f);
+    ok(hr == S_OK, "Failed to set clock rate, hr %#x.\n", hr);
+    hr = IMFRateControl_GetRate(rate_control, &thin, &rate);
+    ok(hr == S_OK, "Failed to get clock rate, hr %#x.\n", hr);
+    ok(rate == 0.0f, "Unexpected rate.\n");
+    hr = IMFRateControl_SetRate(rate_control, FALSE, 1.0f);
+    ok(hr == S_OK, "Failed to set clock rate, hr %#x.\n", hr);
+    hr = IMFRateControl_SetRate(rate_control, FALSE, 0.0f);
+    ok(hr == S_OK, "Failed to set clock rate, hr %#x.\n", hr);
+    hr = IMFRateControl_SetRate(rate_control, FALSE, 0.5f);
+    ok(hr == S_OK, "Failed to set clock rate, hr %#x.\n", hr);
+    hr = IMFRateControl_SetRate(rate_control, TRUE, -1.0f);
+    ok(hr == MF_E_THINNING_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
+
+    hr = IMFRateControl_GetRate(rate_control, &thin, &rate);
+    ok(hr == S_OK, "Failed to get clock rate, hr %#x.\n", hr);
+    ok(rate == 0.5f, "Unexpected rate.\n");
+    ok(!thin, "Unexpected thinning.\n");
+
     IMFRateControl_Release(rate_control);
 
     hr = IMFPresentationClock_QueryInterface(clock, &IID_IMFTimer, (void **)&timer);
@@ -1585,6 +1622,21 @@ static void test_presentation_clock(void)
 
     hr = IMFPresentationClock_QueryInterface(clock, &IID_IMFShutdown, (void **)&shutdown);
     ok(hr == S_OK, "Failed to get shutdown interface, hr %#x.\n", hr);
+
+    /* Shutdown behavior. */
+    hr = IMFShutdown_GetShutdownStatus(shutdown, NULL);
+todo_wine
+    ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+    hr = IMFShutdown_Shutdown(shutdown);
+todo_wine
+    ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
+
+    hr = IMFShutdown_GetShutdownStatus(shutdown, &status);
+todo_wine {
+    ok(hr == S_OK, "Failed to get status, hr %#x.\n", hr);
+    ok(status == MFSHUTDOWN_COMPLETED, "Unexpected status.\n");
+}
     IMFShutdown_Release(shutdown);
 
     IMFPresentationClock_Release(clock);
-- 
2.20.1




More information about the wine-devel mailing list