From: Giovanni Mascellani <gmascellani(a)codeweavers.com> The following behaviors from Windows are implemented: * Transitions from STOPPED to PAUSED are forbidden; * Sample requests are only emitted for transitions from STOPPED to RUNNING (i.e., not when transitioning from PAUSED); * Transition events are emitted again when transitioning from a state to the same state, except when such state is PAUSED. Signed-off-by: Giovanni Mascellani <gmascellani(a)codeweavers.com> Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com> --- No substantial changes, tweaked subject as this patch grew up to be more than sending a missing event. dlls/mf/samplegrabber.c | 64 +++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index f60ce2a8433..4a0be291015 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -32,6 +32,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); enum sink_state { SINK_STATE_STOPPED = 0, + SINK_STATE_PAUSED, SINK_STATE_RUNNING, }; @@ -1101,46 +1102,59 @@ static ULONG WINAPI sample_grabber_clock_sink_Release(IMFClockStateSink *iface) return IMFMediaSink_Release(&grabber->IMFMediaSink_iface); } -static void sample_grabber_set_state(struct sample_grabber *grabber, enum sink_state state) +static HRESULT sample_grabber_set_state(struct sample_grabber *grabber, enum sink_state state, + MFTIME systime, LONGLONG offset) { static const DWORD events[] = { MEStreamSinkStopped, /* SINK_STATE_STOPPED */ + MEStreamSinkPaused, /* SINK_STATE_PAUSED */ MEStreamSinkStarted, /* SINK_STATE_RUNNING */ }; - BOOL set_state = FALSE; + BOOL do_callback = FALSE; + HRESULT hr = S_OK; unsigned int i; EnterCriticalSection(&grabber->cs); if (!grabber->is_shut_down) { - switch (grabber->state) - { - case SINK_STATE_STOPPED: - set_state = state == SINK_STATE_RUNNING; - break; - case SINK_STATE_RUNNING: - set_state = state == SINK_STATE_STOPPED; - break; - default: - ; - } - - if (set_state) + if (state == SINK_STATE_PAUSED && grabber->state == SINK_STATE_STOPPED) + hr = MF_E_INVALID_STATE_TRANSITION; + else { - grabber->state = state; - if (state == SINK_STATE_RUNNING) + if (state == SINK_STATE_RUNNING && grabber->state == SINK_STATE_STOPPED) { /* Every transition to running state sends a bunch requests to build up initial queue. */ for (i = 0; i < 4; ++i) sample_grabber_stream_request_sample(grabber); } - IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, events[state], &GUID_NULL, S_OK, NULL); + do_callback = state != grabber->state || state != SINK_STATE_PAUSED; + if (do_callback) + IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, events[state], &GUID_NULL, S_OK, NULL); + grabber->state = state; } } LeaveCriticalSection(&grabber->cs); + + if (do_callback) + { + switch (state) + { + case SINK_STATE_STOPPED: + hr = IMFSampleGrabberSinkCallback_OnClockStop(sample_grabber_get_callback(grabber), systime); + break; + case SINK_STATE_PAUSED: + hr = IMFSampleGrabberSinkCallback_OnClockPause(sample_grabber_get_callback(grabber), systime); + break; + case SINK_STATE_RUNNING: + hr = IMFSampleGrabberSinkCallback_OnClockStart(sample_grabber_get_callback(grabber), systime, offset); + break; + } + } + + return hr; } static HRESULT WINAPI sample_grabber_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset) @@ -1149,9 +1163,7 @@ static HRESULT WINAPI sample_grabber_clock_sink_OnClockStart(IMFClockStateSink * TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), debugstr_time(offset)); - sample_grabber_set_state(grabber, SINK_STATE_RUNNING); - - return IMFSampleGrabberSinkCallback_OnClockStart(sample_grabber_get_callback(grabber), systime, offset); + return sample_grabber_set_state(grabber, SINK_STATE_RUNNING, systime, offset); } static HRESULT WINAPI sample_grabber_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime) @@ -1160,9 +1172,7 @@ static HRESULT WINAPI sample_grabber_clock_sink_OnClockStop(IMFClockStateSink *i TRACE("%p, %s.\n", iface, debugstr_time(systime)); - sample_grabber_set_state(grabber, SINK_STATE_STOPPED); - - return IMFSampleGrabberSinkCallback_OnClockStop(sample_grabber_get_callback(grabber), systime); + return sample_grabber_set_state(grabber, SINK_STATE_STOPPED, systime, 0); } static HRESULT WINAPI sample_grabber_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime) @@ -1171,7 +1181,7 @@ static HRESULT WINAPI sample_grabber_clock_sink_OnClockPause(IMFClockStateSink * TRACE("%p, %s.\n", iface, debugstr_time(systime)); - return IMFSampleGrabberSinkCallback_OnClockPause(sample_grabber_get_callback(grabber), systime); + return sample_grabber_set_state(grabber, SINK_STATE_PAUSED, systime, 0); } static HRESULT WINAPI sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime) @@ -1180,9 +1190,7 @@ static HRESULT WINAPI sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink TRACE("%p, %s.\n", iface, debugstr_time(systime)); - sample_grabber_set_state(grabber, SINK_STATE_RUNNING); - - return IMFSampleGrabberSinkCallback_OnClockRestart(sample_grabber_get_callback(grabber), systime); + return sample_grabber_set_state(grabber, SINK_STATE_RUNNING, systime, PRESENTATION_CURRENT_POSITION); } static HRESULT WINAPI sample_grabber_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate) -- 2.30.2