Signed-off-by: Nikolay Sivov nsivov@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);