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@codeweavers.com --- dlls/mf/samplegrabber.c | 51 ++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 21 deletions(-)
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index f60ce2a8433..5961cac7e0f 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,55 +1102,52 @@ 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) { static const DWORD events[] = { MEStreamSinkStopped, /* SINK_STATE_STOPPED */ + MEStreamSinkPaused, /* SINK_STATE_PAUSED */ MEStreamSinkStarted, /* SINK_STATE_RUNNING */ }; - BOOL set_state = 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); + if (state != grabber->state || state != SINK_STATE_PAUSED) + IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, events[state], &GUID_NULL, S_OK, NULL); + grabber->state = state; } }
LeaveCriticalSection(&grabber->cs); + + return hr; }
static HRESULT WINAPI sample_grabber_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset) { struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface); + HRESULT hr;
TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), debugstr_time(offset));
- sample_grabber_set_state(grabber, SINK_STATE_RUNNING); + hr = sample_grabber_set_state(grabber, SINK_STATE_RUNNING); + if (FAILED(hr)) + return hr;
return IMFSampleGrabberSinkCallback_OnClockStart(sample_grabber_get_callback(grabber), systime, offset); } @@ -1157,10 +1155,13 @@ static HRESULT WINAPI sample_grabber_clock_sink_OnClockStart(IMFClockStateSink * static HRESULT WINAPI sample_grabber_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime) { struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface); + HRESULT hr;
TRACE("%p, %s.\n", iface, debugstr_time(systime));
- sample_grabber_set_state(grabber, SINK_STATE_STOPPED); + hr = sample_grabber_set_state(grabber, SINK_STATE_STOPPED); + if (FAILED(hr)) + return hr;
return IMFSampleGrabberSinkCallback_OnClockStop(sample_grabber_get_callback(grabber), systime); } @@ -1168,19 +1169,27 @@ static HRESULT WINAPI sample_grabber_clock_sink_OnClockStop(IMFClockStateSink *i static HRESULT WINAPI sample_grabber_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime) { struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface); + HRESULT hr;
TRACE("%p, %s.\n", iface, debugstr_time(systime));
+ hr = sample_grabber_set_state(grabber, SINK_STATE_PAUSED); + if (FAILED(hr)) + return hr; + return IMFSampleGrabberSinkCallback_OnClockPause(sample_grabber_get_callback(grabber), systime); }
static HRESULT WINAPI sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime) { struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface); + HRESULT hr;
TRACE("%p, %s.\n", iface, debugstr_time(systime));
- sample_grabber_set_state(grabber, SINK_STATE_RUNNING); + hr = sample_grabber_set_state(grabber, SINK_STATE_RUNNING); + if (FAILED(hr)) + return hr;
return IMFSampleGrabberSinkCallback_OnClockRestart(sample_grabber_get_callback(grabber), systime); }