This fixes failure to play the prologue video in Planet of the Apes: Last Frontier, which unpauses by calling Start() with a location. The exact state leading to this issue does not occur in the Start() tests, and it's not clear how to reproduce it reliably.
-- v2: mf: Reset transform nodes when seeking. mf: Initialise the grabber sample count when setting state after a seek. mf: Reset transform node outputs when seeking. mf: Drop transform node input events when unpausing at a specific position.
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mf/session.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 483ea6f904f..e595cadd185 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -1061,13 +1061,29 @@ static void session_handle_start_error(struct media_session *session, HRESULT hr session_command_complete_with_event(session, MESessionStarted, hr, NULL); }
+static void session_reset_transforms(struct media_session *session) +{ + struct topo_node *topo_node; + UINT i; + + LIST_FOR_EACH_ENTRY(topo_node, &session->presentation.nodes, struct topo_node, entry) + { + if (topo_node->type != MF_TOPOLOGY_TRANSFORM_NODE) + continue; + + for (i = 0; i < topo_node->u.transform.input_count; i++) + { + struct transform_stream *stream = &topo_node->u.transform.inputs[i]; + stream->draining = FALSE; + } + } +} + static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position) { struct media_source *source; - struct topo_node *topo_node; MFTIME duration; HRESULT hr; - UINT i;
switch (session->state) { @@ -1103,17 +1119,7 @@ static void session_start(struct media_session *session, const GUID *time_format } }
- LIST_FOR_EACH_ENTRY(topo_node, &session->presentation.nodes, struct topo_node, entry) - { - if (topo_node->type == MF_TOPOLOGY_TRANSFORM_NODE) - { - for (i = 0; i < topo_node->u.transform.input_count; i++) - { - struct transform_stream *stream = &topo_node->u.transform.inputs[i]; - stream->draining = FALSE; - } - } - } + session_reset_transforms(session);
session->state = SESSION_STATE_STARTING_SOURCES; break;
From: Conor McCarthy cmccarthy@codeweavers.com
The start position is empty when starting at the current position from the paused state, but if it is not empty, this is a seek operation. --- dlls/mf/session.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index e595cadd185..876dd6eb95c 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -1061,7 +1061,7 @@ static void session_handle_start_error(struct media_session *session, HRESULT hr session_command_complete_with_event(session, MESessionStarted, hr, NULL); }
-static void session_reset_transforms(struct media_session *session) +static void session_reset_transforms(struct media_session *session, BOOL drop) { struct topo_node *topo_node; UINT i; @@ -1071,10 +1071,15 @@ static void session_reset_transforms(struct media_session *session) if (topo_node->type != MF_TOPOLOGY_TRANSFORM_NODE) continue;
+ if (drop) + IMFTransform_ProcessMessage(topo_node->object.transform, MFT_MESSAGE_COMMAND_FLUSH, 0); + for (i = 0; i < topo_node->u.transform.input_count; i++) { struct transform_stream *stream = &topo_node->u.transform.inputs[i]; stream->draining = FALSE; + if (drop) + transform_stream_drop_events(stream); } } } @@ -1119,7 +1124,7 @@ static void session_start(struct media_session *session, const GUID *time_format } }
- session_reset_transforms(session); + session_reset_transforms(session, start_position->vt == VT_I8);
session->state = SESSION_STATE_STARTING_SOURCES; break;
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mf/session.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 876dd6eb95c..7e68c89212e 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -1081,6 +1081,16 @@ static void session_reset_transforms(struct media_session *session, BOOL drop) if (drop) transform_stream_drop_events(stream); } + + if (!drop) + continue; + + for (i = 0; i < topo_node->u.transform.output_count; ++i) + { + struct transform_stream *stream = &topo_node->u.transform.outputs[i]; + transform_stream_drop_events(stream); + stream->requests = 0; + } } }
From: Conor McCarthy cmccarthy@codeweavers.com
If sample_count is zero in this case, we end up with no samples being requested. --- dlls/mf/samplegrabber.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index de599139736..4d54afc1d31 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -1195,6 +1195,10 @@ static HRESULT sample_grabber_set_state(struct sample_grabber *grabber, enum sin
if (state == SINK_STATE_RUNNING && grabber->state != SINK_STATE_RUNNING) { + /* Unpause at a position is a seek operation which drops everything pending. */ + if (grabber->state == SINK_STATE_PAUSED && offset != PRESENTATION_CURRENT_POSITION) + grabber->sample_count = MAX_SAMPLE_QUEUE_LENGTH; + /* Every transition to running state sends a bunch requests to build up initial queue. */ for (i = 0; i < grabber->sample_count; ++i) {
From: Conor McCarthy cmccarthy@codeweavers.com
--- dlls/mf/session.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 7e68c89212e..8a55a97b13a 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -1163,6 +1163,8 @@ static void session_start(struct media_session *session, const GUID *time_format } }
+ session_reset_transforms(session, TRUE); + session->presentation.time_format = *time_format; session->presentation.start_position.vt = VT_EMPTY; PropVariantCopy(&session->presentation.start_position, start_position);
Added a call to IMFTransform_ProcessMessage() with MFT_MESSAGE_COMMAND_FLUSH. Not 100% sure the location is correct.
We have session_flush_nodes() that flushes transforms and sinks, and it's called on SESSION_STATE_RESTARTING_SOURCES. These changes look to scattered to me to make sense, but it should also be possible to test manually in which order things happen, e.g. when, or if, we should flush relative to source restart for example.