When an upstream node has not given enough samples to the transform, we need to request more samples from it to avoid stalling the pipeline.
This fixes an issue where the intro audio of the game Airborne Kingdom stops playing after a few seconds.
-- v2: mf: Request more samples for transforms when needed.
From: Shaun Ren sren@codeweavers.com
If there are multiple upstream nodes, request samples in a round-robin fashion. --- dlls/mf/session.c | 55 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 11 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index b2371763150..05481598265 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -198,6 +198,8 @@ struct topo_node { struct transform_stream *inputs; DWORD *input_map; + BOOL *input_full; + unsigned int input_next; unsigned int input_count;
struct transform_stream *outputs; @@ -707,6 +709,7 @@ static void release_topo_node(struct topo_node *node) free(node->u.transform.outputs); free(node->u.transform.input_map); free(node->u.transform.output_map); + free(node->u.transform.input_full); break; case MF_TOPOLOGY_OUTPUT_NODE: if (node->u.sink.allocator) @@ -1504,6 +1507,8 @@ static HRESULT session_set_transform_stream_info(struct topo_node *node) { node->u.transform.input_map = input_map; node->u.transform.output_map = output_map; + node->u.transform.input_full = calloc(input_count, sizeof(BOOL)); + node->u.transform.input_next = 0;
streams = calloc(input_count, sizeof(*streams)); for (i = 0; i < input_count; ++i) @@ -3138,6 +3143,30 @@ static HRESULT transform_node_pull_samples(const struct media_session *session, return hr; }
+static HRESULT transform_node_request_sample(struct media_session *session, struct topo_node *node) +{ + unsigned int count = node->u.transform.input_count; + IMFTopologyNode *upstream_node; + DWORD upstream_output; + unsigned int i, cur; + HRESULT hr; + + /* In case of multiple inputs, request samples from upstream in a round-robin fashion. */ + for (i = 0; i < count && node->u.transform.input_full[(node->u.transform.input_next + i) % count]; ++i) ; + if (i == count) + return MF_E_NOTACCEPTING; + + cur = (node->u.transform.input_next + i) % count; + if (SUCCEEDED(hr = IMFTopologyNode_GetInput(node->node, cur, &upstream_node, &upstream_output))) + { + if (SUCCEEDED(hr = session_request_sample_from_node(session, upstream_node, upstream_output))) + node->u.transform.input_next = (cur + 1) % count; + IMFTopologyNode_Release(upstream_node); + } + + return hr; +} + static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input, IMFSample *sample) { @@ -3194,7 +3223,10 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop { if ((hr = IMFTransform_ProcessInput(topo_node->object.transform, stream_id, sample_entry->sample, 0)) == MF_E_NOTACCEPTING) + { + topo_node->u.transform.input_full[i] = TRUE; break; + } if (FAILED(hr)) WARN("Failed to process input for stream %u/%lu, hr %#lx.\n", i, stream_id, hr); transform_release_sample(sample_entry); @@ -3213,17 +3245,22 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop WARN("Drain command failed for transform, hr %#lx.\n", hr); }
- transform_node_pull_samples(session, topo_node); + hr = transform_node_pull_samples(session, topo_node); + + if (SUCCEEDED(hr)) + memset(topo_node->u.transform.input_full, 0, sizeof(BOOL) * topo_node->u.transform.input_count);
- /* Remaining unprocessed input has been discarded, now queue markers for every output. */ if (drain) { + /* Remaining unprocessed input has been discarded, now queue markers for every output. */ for (i = 0; i < topo_node->u.transform.output_count; ++i) { if ((sample_entry = transform_create_sample(NULL))) list_add_tail(&topo_node->u.transform.outputs[i].samples, &sample_entry->entry); } } + else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) + transform_node_request_sample(session, topo_node);
/* Push down all available output. */ for (i = 0; i < topo_node->u.transform.output_count; ++i) @@ -3311,8 +3348,8 @@ static void session_deliver_pending_samples(struct media_session *session, IMFTo
static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output) { - IMFTopologyNode *downstream_node, *upstream_node; - DWORD downstream_input, upstream_output; + IMFTopologyNode *downstream_node; + DWORD downstream_input; struct topo_node *topo_node; MF_TOPOLOGY_TYPE node_type; struct sample *sample; @@ -3334,13 +3371,9 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I
if (list_empty(&topo_node->u.transform.outputs[output].samples)) { - /* Forward request to upstream node. */ - if (SUCCEEDED(hr = IMFTopologyNode_GetInput(node, 0 /* FIXME */, &upstream_node, &upstream_output))) - { - if (SUCCEEDED(hr = session_request_sample_from_node(session, upstream_node, upstream_output))) - topo_node->u.transform.outputs[output].requests++; - IMFTopologyNode_Release(upstream_node); - } + /* Forward request to upstream nodes. */ + if (SUCCEEDED(hr = transform_node_request_sample(session, topo_node))) + topo_node->u.transform.outputs[output].requests++; } else {