session_request_sample() calls session_request_sample_from_node() and increments sink.requests only if that succeeds. But session_request_sample_from_node() calls session_deliver_sample_to_node() synchronously for MF_TOPOLOGY_TRANSFORM_NODE if there are output samples available. Then, if sink.requests is zero before this session_request_sample() call that sample is silently dropped.
It might not be easily noticeable currently, but I have a patchset which implements _ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN) needed for some games (and also improving end of playback by fully delivering output including few last frames). And currently if session_deliver_sample_to_node() performs drain and that drain produces any samples we get a data sample processed but end marker silently dropped resulting in hanging session. That market gets to session_request_sample / session_request_sample_from_node but gets dropped in session_deliver_sample_to_node due to the reason first patch is fixing.
Thus also the second patch. I am not sure it is strictly needed, but the current handling of that seems fragile to me, I suppose we shouldn't ever drop markers.
From: Paul Gofman pgofman@codeweavers.com
--- dlls/mf/session.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 85baf07d05a..adda37e8df7 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -3162,6 +3162,10 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop switch (node_type) { case MF_TOPOLOGY_OUTPUT_NODE: + if (!sample && FAILED(hr = IMFStreamSink_PlaceMarker(topo_node->object.sink_stream, MFSTREAMSINK_MARKER_ENDOFSEGMENT, + NULL, NULL))) + WARN("Failed to place sink marker, hr %#lx.\n", hr); + if (topo_node->u.sink.requests) { if (sample) @@ -3169,11 +3173,6 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop if (FAILED(hr = IMFStreamSink_ProcessSample(topo_node->object.sink_stream, sample))) WARN("Stream sink failed to process sample, hr %#lx.\n", hr); } - else if (FAILED(hr = IMFStreamSink_PlaceMarker(topo_node->object.sink_stream, MFSTREAMSINK_MARKER_ENDOFSEGMENT, - NULL, NULL))) - { - WARN("Failed to place sink marker, hr %#lx.\n", hr); - } topo_node->u.sink.requests--; } break;
From: Paul Gofman pgofman@codeweavers.com
--- dlls/mf/session.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index b2371763150..85baf07d05a 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -3388,8 +3388,9 @@ static void session_request_sample(struct media_session *session, IMFStreamSink return; }
- if (SUCCEEDED(session_request_sample_from_node(session, upstream_node, upstream_output))) - sink_node->u.sink.requests++; + sink_node->u.sink.requests++; + if (FAILED(session_request_sample_from_node(session, upstream_node, upstream_output))) + sink_node->u.sink.requests--; IMFTopologyNode_Release(upstream_node); }