From 2a6f0a4093a5465f87615bdbf313e9d82c627d53 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Mon, 26 Apr 2021 11:23:33 +0300 Subject: [PATCH] mf/evr: Handle mixer sample requests during sink state transitions. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/mf/evr.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/dlls/mf/evr.c b/dlls/mf/evr.c index 8b4a9c03b5f..baa6665853e 100644 --- a/dlls/mf/evr.c +++ b/dlls/mf/evr.c @@ -47,6 +47,7 @@ enum video_stream_flags { EVR_STREAM_PREROLLING = 0x1, EVR_STREAM_PREROLLED = 0x2, + EVR_STREAM_SAMPLE_NEEDED = 0x4, }; struct video_renderer; @@ -1825,13 +1826,19 @@ static ULONG WINAPI video_renderer_clock_sink_Release(IMFClockStateSink *iface) static HRESULT WINAPI video_renderer_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset) { struct video_renderer *renderer = impl_from_IMFClockStateSink(iface); + unsigned int state, request_sample; size_t i; TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), debugstr_time(offset)); EnterCriticalSection(&renderer->cs); - if (renderer->state == EVR_STATE_STOPPED) + state = renderer->state; + + /* Update sink state before sending sample requests, to avoid potentially receiving new sample in stopped state */ + renderer->state = EVR_STATE_RUNNING; + + if (state == EVR_STATE_STOPPED) { IMFTransform_ProcessMessage(renderer->mixer, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0); IMFVideoPresenter_ProcessMessage(renderer->presenter, MFVP_MESSAGE_BEGINSTREAMING, 0); @@ -1840,19 +1847,19 @@ static HRESULT WINAPI video_renderer_clock_sink_OnClockStart(IMFClockStateSink * { struct video_stream *stream = renderer->streams[i]; - IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL); - EnterCriticalSection(&stream->cs); - if (!(stream->flags & EVR_STREAM_PREROLLED)) + request_sample = !(stream->flags & EVR_STREAM_PREROLLED) || (stream->flags & EVR_STREAM_SAMPLE_NEEDED); + stream->flags |= EVR_STREAM_PREROLLED; + stream->flags &= ~EVR_STREAM_SAMPLE_NEEDED; + LeaveCriticalSection(&stream->cs); + + IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamSinkStarted, &GUID_NULL, S_OK, NULL); + if (request_sample) IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL); - stream->flags |= EVR_STREAM_PREROLLED; - LeaveCriticalSection(&stream->cs); } } - renderer->state = EVR_STATE_RUNNING; - IMFVideoPresenter_OnClockStart(renderer->presenter, systime, offset); LeaveCriticalSection(&renderer->cs); @@ -1886,7 +1893,7 @@ static HRESULT WINAPI video_renderer_clock_sink_OnClockStop(IMFClockStateSink *i IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamSinkStopped, &GUID_NULL, S_OK, NULL); EnterCriticalSection(&stream->cs); - stream->flags &= ~EVR_STREAM_PREROLLED; + stream->flags &= ~(EVR_STREAM_PREROLLED | EVR_STREAM_SAMPLE_NEEDED); LeaveCriticalSection(&stream->cs); } renderer->state = EVR_STATE_STOPPED; @@ -2184,11 +2191,17 @@ static HRESULT WINAPI video_renderer_event_sink_Notify(IMediaEventSink *iface, L idx = param1; if (idx >= renderer->stream_count) hr = MF_E_INVALIDSTREAMNUMBER; - else + else if (renderer->state == EVR_STATE_RUNNING) { hr = IMFMediaEventQueue_QueueEventParamVar(renderer->streams[idx]->event_queue, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL); } + else + { + /* Mixer asks for more input right after preroll too, before renderer finished running state transition. + Mark such streams here, and issue requests later in OnClockStart(). */ + renderer->streams[idx]->flags |= EVR_STREAM_SAMPLE_NEEDED; + } } else if (event == EC_DISPLAY_CHANGED) {