[PATCH 3/3] mf: Add support for clock sink notifications.

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


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mf/session.c  | 237 +++++++++++++++++++++++++++++++++++++++++----
 dlls/mf/tests/mf.c |   3 +
 include/mfidl.idl  |   2 +
 3 files changed, 224 insertions(+), 18 deletions(-)

diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index d2d1d495a0..7f8a283e76 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -46,12 +46,39 @@ struct clock_sink
     IMFClockStateSink *state_sink;
 };
 
+enum clock_command
+{
+    CLOCK_CMD_START = 0,
+    CLOCK_CMD_STOP,
+    CLOCK_CMD_PAUSE,
+    CLOCK_CMD_MAX,
+};
+
+enum clock_notification
+{
+    CLOCK_NOTIFY_START,
+    CLOCK_NOTIFY_STOP,
+    CLOCK_NOTIFY_PAUSE,
+    CLOCK_NOTIFY_RESTART,
+};
+
+struct sink_notification
+{
+    IUnknown IUnknown_iface;
+    LONG refcount;
+    MFTIME system_time;
+    LONGLONG offset;
+    enum clock_notification notification;
+    IMFClockStateSink *sink;
+};
+
 struct presentation_clock
 {
     IMFPresentationClock IMFPresentationClock_iface;
     IMFRateControl IMFRateControl_iface;
     IMFTimer IMFTimer_iface;
     IMFShutdown IMFShutdown_iface;
+    IMFAsyncCallback IMFAsyncCallback_iface;
     LONG refcount;
     IMFPresentationTimeSource *time_source;
     IMFClockStateSink *time_source_sink;
@@ -85,6 +112,16 @@ static struct presentation_clock *impl_from_IMFShutdown(IMFShutdown *iface)
     return CONTAINING_RECORD(iface, struct presentation_clock, IMFShutdown_iface);
 }
 
+static struct presentation_clock *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
+{
+    return CONTAINING_RECORD(iface, struct presentation_clock, IMFAsyncCallback_iface);
+}
+
+static struct sink_notification *impl_from_IUnknown(IUnknown *iface)
+{
+    return CONTAINING_RECORD(iface, struct sink_notification, IUnknown_iface);
+}
+
 static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID riid, void **out)
 {
     struct media_session *session = impl_from_IMFMediaSession(iface);
@@ -533,15 +570,102 @@ static HRESULT WINAPI present_clock_RemoveClockStateSink(IMFPresentationClock *i
     return S_OK;
 }
 
-enum clock_command
+static HRESULT WINAPI sink_notification_QueryInterface(IUnknown *iface, REFIID riid, void **out)
 {
-    CLOCK_CMD_START = 0,
-    CLOCK_CMD_STOP,
-    CLOCK_CMD_PAUSE,
-    CLOCK_CMD_MAX,
+    if (IsEqualIID(riid, &IID_IUnknown))
+    {
+        *out = iface;
+        IUnknown_AddRef(iface);
+        return S_OK;
+    }
+
+    WARN("Unsupported %s.\n", debugstr_guid(riid));
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI sink_notification_AddRef(IUnknown *iface)
+{
+    struct sink_notification *notification = impl_from_IUnknown(iface);
+    ULONG refcount = InterlockedIncrement(&notification->refcount);
+
+    TRACE("%p, refcount %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI sink_notification_Release(IUnknown *iface)
+{
+    struct sink_notification *notification = impl_from_IUnknown(iface);
+    ULONG refcount = InterlockedDecrement(&notification->refcount);
+
+    TRACE("%p, refcount %u.\n", iface, refcount);
+
+    if (!refcount)
+    {
+        IMFClockStateSink_Release(notification->sink);
+        heap_free(notification);
+    }
+
+    return refcount;
+}
+
+static const IUnknownVtbl sinknotificationvtbl =
+{
+    sink_notification_QueryInterface,
+    sink_notification_AddRef,
+    sink_notification_Release,
 };
 
-static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_command command)
+static HRESULT create_sink_notification(MFTIME system_time, LONGLONG offset, enum clock_notification notification,
+        IMFClockStateSink *sink, IUnknown **out)
+{
+    struct sink_notification *object;
+
+    object = heap_alloc(sizeof(*object));
+    if (!object)
+        return E_OUTOFMEMORY;
+
+    object->IUnknown_iface.lpVtbl = &sinknotificationvtbl;
+    object->refcount = 1;
+    object->system_time = system_time;
+    object->offset = offset;
+    object->notification = notification;
+    object->sink = sink;
+    IMFClockStateSink_AddRef(object->sink);
+
+    *out = &object->IUnknown_iface;
+
+    return S_OK;
+}
+
+static HRESULT clock_call_state_change(MFTIME system_time, LONGLONG offset, enum clock_notification notification,
+        IMFClockStateSink *sink)
+{
+    HRESULT hr = S_OK;
+
+    switch (notification)
+    {
+        case CLOCK_NOTIFY_START:
+            hr = IMFClockStateSink_OnClockStart(sink, system_time, offset);
+            break;
+        case CLOCK_NOTIFY_STOP:
+            hr = IMFClockStateSink_OnClockStop(sink, system_time);
+            break;
+        case CLOCK_NOTIFY_PAUSE:
+            hr = IMFClockStateSink_OnClockPause(sink, system_time);
+            break;
+        case CLOCK_NOTIFY_RESTART:
+            hr = IMFClockStateSink_OnClockRestart(sink, system_time);
+            break;
+        default:
+            ;
+    }
+
+    return hr;
+}
+
+static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_command command, LONGLONG offset)
 {
     static const BYTE state_change_is_allowed[MFCLOCK_STATE_PAUSED+1][CLOCK_CMD_MAX] =
     {   /*              S  S* P  */
@@ -556,40 +680,57 @@ static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_c
         /* CLOCK_CMD_STOP  */ MFCLOCK_STATE_STOPPED,
         /* CLOCK_CMD_PAUSE */ MFCLOCK_STATE_PAUSED,
     };
+    enum clock_notification notification;
+    struct clock_sink *sink;
+    IUnknown *notify_object;
+    IMFAsyncResult *result;
+    MFTIME system_time;
     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;
 
+    system_time = MFGetSystemTime();
+
     switch (command)
     {
         case CLOCK_CMD_START:
-            if (clock->state == MFCLOCK_STATE_PAUSED)
-                hr = IMFClockStateSink_OnClockRestart(clock->time_source_sink, 0);
+            if (clock->state == MFCLOCK_STATE_PAUSED && offset == PRESENTATION_CURRENT_POSITION)
+                notification = CLOCK_NOTIFY_RESTART;
             else
-                hr = IMFClockStateSink_OnClockStart(clock->time_source_sink, 0, 0);
+                notification = CLOCK_NOTIFY_START;
             break;
         case CLOCK_CMD_STOP:
-            hr = IMFClockStateSink_OnClockStop(clock->time_source_sink, 0);
+            notification = CLOCK_NOTIFY_STOP;
             break;
         case CLOCK_CMD_PAUSE:
-            hr = IMFClockStateSink_OnClockPause(clock->time_source_sink, 0);
+            notification = CLOCK_NOTIFY_PAUSE;
             break;
         default:
             ;
     }
 
-    if (FAILED(hr))
+    if (FAILED(hr = clock_call_state_change(system_time, offset, notification, clock->time_source_sink)))
         return hr;
 
     clock->state = states[command];
 
-    /* FIXME: notify registered sinks. */
+    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)))
+        {
+            hr = MFCreateAsyncResult(notify_object, &clock->IMFAsyncCallback_iface, NULL, &result);
+            IUnknown_Release(notify_object);
+            if (SUCCEEDED(hr))
+            {
+                MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD, result);
+                IMFAsyncResult_Release(result);
+            }
+        }
+    }
 
     return S_OK;
 }
@@ -602,7 +743,7 @@ static HRESULT WINAPI present_clock_Start(IMFPresentationClock *iface, LONGLONG
     TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(start_offset));
 
     EnterCriticalSection(&clock->cs);
-    hr = clock_change_state(clock, CLOCK_CMD_START);
+    hr = clock_change_state(clock, CLOCK_CMD_START, start_offset);
     LeaveCriticalSection(&clock->cs);
 
     return hr;
@@ -616,7 +757,7 @@ static HRESULT WINAPI present_clock_Stop(IMFPresentationClock *iface)
     TRACE("%p.\n", iface);
 
     EnterCriticalSection(&clock->cs);
-    hr = clock_change_state(clock, CLOCK_CMD_STOP);
+    hr = clock_change_state(clock, CLOCK_CMD_STOP, 0);
     LeaveCriticalSection(&clock->cs);
 
     return hr;
@@ -630,7 +771,7 @@ static HRESULT WINAPI present_clock_Pause(IMFPresentationClock *iface)
     TRACE("%p.\n", iface);
 
     EnterCriticalSection(&clock->cs);
-    hr = clock_change_state(clock, CLOCK_CMD_PAUSE);
+    hr = clock_change_state(clock, CLOCK_CMD_PAUSE, 0);
     LeaveCriticalSection(&clock->cs);
 
     return hr;
@@ -780,6 +921,65 @@ static const IMFShutdownVtbl presentclockshutdownvtbl =
     present_clock_shutdown_GetShutdownStatus,
 };
 
+static HRESULT WINAPI present_clock_sink_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **out)
+{
+    if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
+            IsEqualIID(riid, &IID_IUnknown))
+    {
+        *out = iface;
+        IMFAsyncCallback_AddRef(iface);
+        return S_OK;
+    }
+
+    WARN("Unsupported %s.\n", wine_dbgstr_guid(riid));
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI present_clock_sink_callback_AddRef(IMFAsyncCallback *iface)
+{
+    struct presentation_clock *clock = impl_from_IMFAsyncCallback(iface);
+    return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
+}
+
+static ULONG WINAPI present_clock_sink_callback_Release(IMFAsyncCallback *iface)
+{
+    struct presentation_clock *clock = impl_from_IMFAsyncCallback(iface);
+    return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
+}
+
+static HRESULT WINAPI present_clock_sink_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
+{
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI present_clock_sink_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
+{
+    struct sink_notification *data;
+    IUnknown *object;
+    HRESULT hr;
+
+    if (FAILED(hr = IMFAsyncResult_GetObject(result, &object)))
+        return hr;
+
+    data = impl_from_IUnknown(object);
+
+    clock_call_state_change(data->system_time, data->offset, data->notification, data->sink);
+
+    IUnknown_Release(object);
+
+    return S_OK;
+}
+
+static const IMFAsyncCallbackVtbl presentclocksinkcallbackvtbl =
+{
+    present_clock_sink_callback_QueryInterface,
+    present_clock_sink_callback_AddRef,
+    present_clock_sink_callback_Release,
+    present_clock_sink_callback_GetParameters,
+    present_clock_sink_callback_Invoke,
+};
+
 /***********************************************************************
  *      MFCreatePresentationClock (mf.@)
  */
@@ -797,6 +997,7 @@ HRESULT WINAPI MFCreatePresentationClock(IMFPresentationClock **clock)
     object->IMFRateControl_iface.lpVtbl = &presentclockratecontrolvtbl;
     object->IMFTimer_iface.lpVtbl = &presentclocktimervtbl;
     object->IMFShutdown_iface.lpVtbl = &presentclockshutdownvtbl;
+    object->IMFAsyncCallback_iface.lpVtbl = &presentclocksinkcallbackvtbl;
     object->refcount = 1;
     list_init(&object->sinks);
     InitializeCriticalSection(&object->cs);
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index 42b23d6c3e..4dfefdd459 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -826,6 +826,9 @@ static void test_presentation_clock(void)
         { 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 },
+        { CLOCK_START, MFCLOCK_STATE_RUNNING, MFCLOCK_STATE_RUNNING },
+        { CLOCK_PAUSE, MFCLOCK_STATE_PAUSED, MFCLOCK_STATE_PAUSED },
+        { CLOCK_START, MFCLOCK_STATE_RUNNING, MFCLOCK_STATE_RUNNING },
     };
     IMFClockStateSink test_sink = { &test_clock_sink_vtbl };
     IMFPresentationTimeSource *time_source;
diff --git a/include/mfidl.idl b/include/mfidl.idl
index 252099e145..04a6d71bf9 100644
--- a/include/mfidl.idl
+++ b/include/mfidl.idl
@@ -412,6 +412,8 @@ interface IMFPresentationTimeSource : IMFClock
     HRESULT GetUnderlyingClock([out] IMFClock **clock);
 }
 
+cpp_quote("#define PRESENTATION_CURRENT_POSITION 0x7fffffffffffffff")
+
 [
     object,
     uuid(868ce85c-8ea9-4f55-ab82-b009a910a805)
-- 
2.20.1




More information about the wine-devel mailing list