Let winegstreamer's media source emit the same rate limits that Windows exposes for media sources generated with the standard source resolver.
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com --- dlls/winegstreamer/media_source.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index e153c8e9161..d013a60e150 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -933,7 +933,7 @@ static HRESULT WINAPI media_source_rate_support_GetSlowestRate(IMFRateSupport *i { TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
- *rate = direction == MFRATE_FORWARD ? 1.0f : -1.0f; + *rate = 0.0f;
return S_OK; } @@ -942,14 +942,14 @@ static HRESULT WINAPI media_source_rate_support_GetFastestRate(IMFRateSupport *i { TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
- *rate = direction == MFRATE_FORWARD ? 1.0f : -1.0f; + *rate = direction == MFRATE_FORWARD ? 1e6f : -1e6f;
return S_OK; }
static HRESULT WINAPI media_source_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate, float *nearest_support_rate) { - const float supported_rate = rate >= 0.0f ? 1.0f : -1.0f; + const float supported_rate = max(min(rate, 1e6f), -1e6f);
TRACE("%p, %d, %f, %p.\n", iface, thin, rate, nearest_support_rate);
The current algorithm correctly only considers the absolute value of nodes' rates when computing maximum and minimum, but omits negating the result when in reverse direction.
Also, when computing the minimum intializing with zero is wrong, as it would always give final result zero. We have to initialize with a number that is bigger than at least one operand, e.g. FLT_MAX.
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com --- dlls/mf/session.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 925a8c93d20..275b1e3dd98 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -18,6 +18,7 @@
#include <stdarg.h> #include <math.h> +#include <float.h>
#define COBJMACROS
@@ -3532,7 +3533,7 @@ static HRESULT session_get_presentation_rate(struct media_session *session, MFRA struct media_sink *sink; HRESULT hr = E_POINTER;
- *result = 0.0f; + *result = fastest ? FLT_MAX : 0.0f;
EnterCriticalSection(&session->cs);
@@ -3556,6 +3557,9 @@ static HRESULT session_get_presentation_rate(struct media_session *session, MFRA
LeaveCriticalSection(&session->cs);
+ if (direction == MFRATE_REVERSE) + *result = -*result; + return hr; }
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 | 64 +++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 28 deletions(-)
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index f60ce2a8433..329f76218d2 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; + HRESULT hr = S_OK; + BOOL do_callback = FALSE; 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) + { + do_callback = TRUE; + 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)