[PATCH 3/4] mfmediaengine/renderer: Add clock state sink.

Nikolay Sivov nsivov at codeweavers.com
Mon Nov 2 06:41:17 CST 2020


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mfmediaengine/renderer.c | 207 +++++++++++++++++++++++++++++++++-
 1 file changed, 203 insertions(+), 4 deletions(-)

diff --git a/dlls/mfmediaengine/renderer.c b/dlls/mfmediaengine/renderer.c
index 98807f23d0f..d747f42774a 100644
--- a/dlls/mfmediaengine/renderer.c
+++ b/dlls/mfmediaengine/renderer.c
@@ -29,6 +29,34 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
 
+static const char *debugstr_time(LONGLONG time)
+{
+    ULONGLONG abstime = time >= 0 ? time : -time;
+    unsigned int i = 0, j = 0;
+    char buffer[23], rev[23];
+
+    while (abstime || i <= 8)
+    {
+        buffer[i++] = '0' + (abstime % 10);
+        abstime /= 10;
+        if (i == 7) buffer[i++] = '.';
+    }
+    if (time < 0) buffer[i++] = '-';
+
+    while (i--) rev[j++] = buffer[i];
+    while (rev[j-1] == '0' && rev[j-2] != '.') --j;
+    rev[j] = 0;
+
+    return wine_dbg_sprintf("%s", rev);
+}
+
+enum stream_state
+{
+    STREAM_STATE_STOPPED = 0,
+    STREAM_STATE_RUNNING,
+    STREAM_STATE_PAUSED,
+};
+
 enum video_renderer_flags
 {
     FLAG_SHUT_DOWN = 0x1,
@@ -39,11 +67,14 @@ struct video_renderer
     IMFMediaSink IMFMediaSink_iface;
     IMFStreamSink IMFStreamSink_iface;
     IMFMediaTypeHandler IMFMediaTypeHandler_iface;
+    IMFClockStateSink IMFClockStateSink_iface;
     IMFMediaEventGenerator IMFMediaEventGenerator_iface;
     LONG refcount;
     IMFMediaEventQueue *event_queue;
     IMFMediaEventQueue *stream_event_queue;
+    IMFPresentationClock *clock;
     unsigned int flags;
+    unsigned int state;
     CRITICAL_SECTION cs;
 };
 
@@ -52,6 +83,11 @@ static struct video_renderer *impl_from_IMFMediaSink(IMFMediaSink *iface)
     return CONTAINING_RECORD(iface, struct video_renderer, IMFMediaSink_iface);
 }
 
+static struct video_renderer *impl_from_IMFClockStateSink(IMFClockStateSink *iface)
+{
+    return CONTAINING_RECORD(iface, struct video_renderer, IMFClockStateSink_iface);
+}
+
 static struct video_renderer *impl_from_IMFStreamSink(IMFStreamSink *iface)
 {
     return CONTAINING_RECORD(iface, struct video_renderer, IMFStreamSink_iface);
@@ -78,6 +114,10 @@ static HRESULT WINAPI video_renderer_sink_QueryInterface(IMFMediaSink *iface, RE
     {
         *obj = iface;
     }
+    else if (IsEqualIID(riid, &IID_IMFClockStateSink))
+    {
+        *obj = &renderer->IMFClockStateSink_iface;
+    }
     else if (IsEqualIID(riid, &IID_IMFMediaEventGenerator))
     {
         *obj = &renderer->IMFMediaEventGenerator_iface;
@@ -115,6 +155,8 @@ static ULONG WINAPI video_renderer_sink_Release(IMFMediaSink *iface)
             IMFMediaEventQueue_Release(renderer->event_queue);
         if (renderer->stream_event_queue)
             IMFMediaEventQueue_Release(renderer->stream_event_queue);
+        if (renderer->clock)
+            IMFPresentationClock_Release(renderer->clock);
         DeleteCriticalSection(&renderer->cs);
         heap_free(renderer);
     }
@@ -222,19 +264,66 @@ static HRESULT WINAPI video_renderer_sink_GetStreamSinkById(IMFMediaSink *iface,
     return hr;
 }
 
+static void video_renderer_set_presentation_clock(struct video_renderer *renderer, IMFPresentationClock *clock)
+{
+    if (renderer->clock)
+    {
+        IMFPresentationClock_RemoveClockStateSink(renderer->clock, &renderer->IMFClockStateSink_iface);
+        IMFPresentationClock_Release(renderer->clock);
+    }
+    renderer->clock = clock;
+    if (renderer->clock)
+    {
+        IMFPresentationClock_AddRef(renderer->clock);
+        IMFPresentationClock_AddClockStateSink(renderer->clock, &renderer->IMFClockStateSink_iface);
+    }
+}
+
 static HRESULT WINAPI video_renderer_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock)
 {
-    FIXME("%p, %p.\n", iface, clock);
+    struct video_renderer *renderer = impl_from_IMFMediaSink(iface);
+    HRESULT hr = S_OK;
 
-    return E_NOTIMPL;
+    TRACE("%p, %p.\n", iface, clock);
+
+    EnterCriticalSection(&renderer->cs);
+
+    if (renderer->flags & FLAG_SHUT_DOWN)
+        hr = MF_E_SHUTDOWN;
+    else
+        video_renderer_set_presentation_clock(renderer, clock);
+
+    LeaveCriticalSection(&renderer->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI video_renderer_sink_GetPresentationClock(IMFMediaSink *iface,
         IMFPresentationClock **clock)
 {
-    FIXME("%p, %p.\n", iface, clock);
+    struct video_renderer *renderer = impl_from_IMFMediaSink(iface);
+    HRESULT hr = S_OK;
 
-    return E_NOTIMPL;
+    TRACE("%p, %p.\n", iface, clock);
+
+    if (!clock)
+        return E_POINTER;
+
+    EnterCriticalSection(&renderer->cs);
+
+    if (renderer->flags & FLAG_SHUT_DOWN)
+        hr = MF_E_SHUTDOWN;
+    else if (renderer->clock)
+    {
+        *clock = renderer->clock;
+        IMFPresentationClock_AddRef(*clock);
+    }
+    else
+        hr = MF_E_NO_CLOCK;
+
+    LeaveCriticalSection(&renderer->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI video_renderer_sink_Shutdown(IMFMediaSink *iface)
@@ -250,6 +339,7 @@ static HRESULT WINAPI video_renderer_sink_Shutdown(IMFMediaSink *iface)
     renderer->flags |= FLAG_SHUT_DOWN;
     IMFMediaEventQueue_Shutdown(renderer->event_queue);
     IMFMediaEventQueue_Shutdown(renderer->stream_event_queue);
+    video_renderer_set_presentation_clock(renderer, NULL);
     LeaveCriticalSection(&renderer->cs);
 
     return S_OK;
@@ -624,6 +714,114 @@ static const IMFMediaEventGeneratorVtbl video_renderer_events_vtbl =
     video_renderer_events_QueueEvent,
 };
 
+static HRESULT WINAPI video_renderer_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj)
+{
+    struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+    return IMFMediaSink_QueryInterface(&renderer->IMFMediaSink_iface, riid, obj);
+}
+
+static ULONG WINAPI video_renderer_clock_sink_AddRef(IMFClockStateSink *iface)
+{
+    struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+    return IMFMediaSink_AddRef(&renderer->IMFMediaSink_iface);
+}
+
+static ULONG WINAPI video_renderer_clock_sink_Release(IMFClockStateSink *iface)
+{
+    struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+    return IMFMediaSink_Release(&renderer->IMFMediaSink_iface);
+}
+
+static HRESULT WINAPI video_renderer_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset)
+{
+    struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+
+    TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), debugstr_time(offset));
+
+    EnterCriticalSection(&renderer->cs);
+
+    if (renderer->state == STREAM_STATE_STOPPED)
+        renderer->state = STREAM_STATE_RUNNING;
+
+    IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL);
+
+    LeaveCriticalSection(&renderer->cs);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI video_renderer_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime)
+{
+    struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+
+    TRACE("%p, %s.\n", iface, debugstr_time(systime));
+
+    EnterCriticalSection(&renderer->cs);
+
+    renderer->state = STREAM_STATE_STOPPED;
+    IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStopped, &GUID_NULL, S_OK, NULL);
+
+    LeaveCriticalSection(&renderer->cs);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI video_renderer_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime)
+{
+    struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("%p, %s.\n", iface, debugstr_time(systime));
+
+    EnterCriticalSection(&renderer->cs);
+
+    if (renderer->state == STREAM_STATE_RUNNING)
+    {
+        renderer->state = STREAM_STATE_PAUSED;
+        IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkPaused, &GUID_NULL, S_OK, NULL);
+    }
+    else
+        hr = MF_E_INVALID_STATE_TRANSITION;
+
+    LeaveCriticalSection(&renderer->cs);
+
+    return hr;
+}
+
+static HRESULT WINAPI video_renderer_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime)
+{
+    struct video_renderer *renderer = impl_from_IMFClockStateSink(iface);
+
+    TRACE("%p, %s.\n", iface, debugstr_time(systime));
+
+    EnterCriticalSection(&renderer->cs);
+
+    IMFMediaEventQueue_QueueEventParamVar(renderer->stream_event_queue, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL);
+
+    LeaveCriticalSection(&renderer->cs);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI video_renderer_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate)
+{
+    FIXME("%p, %s, %f.\n", iface, debugstr_time(systime), rate);
+
+    return E_NOTIMPL;
+}
+
+static const IMFClockStateSinkVtbl video_renderer_clock_sink_vtbl =
+{
+    video_renderer_clock_sink_QueryInterface,
+    video_renderer_clock_sink_AddRef,
+    video_renderer_clock_sink_Release,
+    video_renderer_clock_sink_OnClockStart,
+    video_renderer_clock_sink_OnClockStop,
+    video_renderer_clock_sink_OnClockPause,
+    video_renderer_clock_sink_OnClockRestart,
+    video_renderer_clock_sink_OnClockSetRate,
+};
+
 HRESULT media_engine_create_video_renderer(IMFTopologyNode **node)
 {
     struct video_renderer *renderer;
@@ -638,6 +836,7 @@ HRESULT media_engine_create_video_renderer(IMFTopologyNode **node)
     renderer->IMFStreamSink_iface.lpVtbl = &video_renderer_stream_vtbl;
     renderer->IMFMediaTypeHandler_iface.lpVtbl = &video_renderer_stream_type_handler_vtbl;
     renderer->IMFMediaEventGenerator_iface.lpVtbl = &video_renderer_events_vtbl;
+    renderer->IMFClockStateSink_iface.lpVtbl = &video_renderer_clock_sink_vtbl;
     renderer->refcount = 1;
     InitializeCriticalSection(&renderer->cs);
 
-- 
2.28.0




More information about the wine-devel mailing list