[PATCH 8/9] mf: Add support for requesting sample from transform nodes.

Nikolay Sivov nsivov at codeweavers.com
Fri Mar 13 07:34:37 CDT 2020


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mf/session.c | 225 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 180 insertions(+), 45 deletions(-)

diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 62b2b4f0ec..503948000e 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -110,6 +110,17 @@ struct media_sink
     BOOL finalized;
 };
 
+struct sample
+{
+    struct list entry;
+    IMFSample *sample;
+};
+
+struct transform_stream
+{
+    struct list samples;
+};
+
 struct topo_node
 {
     struct list entry;
@@ -141,6 +152,7 @@ struct topo_node
             unsigned int *input_map;
             unsigned int input_count;
 
+            struct transform_stream *outputs;
             unsigned int *output_map;
             unsigned int output_count;
         } transform;
@@ -623,8 +635,23 @@ static void session_set_caps(struct media_session *session, DWORD caps)
     IMFMediaEvent_Release(event);
 }
 
+static void transform_stream_drop_samples(struct transform_stream *stream)
+{
+    struct sample *sample, *sample2;
+
+    LIST_FOR_EACH_ENTRY_SAFE(sample, sample2, &stream->samples, struct sample, entry)
+    {
+        list_remove(&sample->entry);
+        if (sample->sample)
+            IMFSample_Release(sample->sample);
+        heap_free(sample);
+    }
+}
+
 static void release_topo_node(struct topo_node *node)
 {
+    unsigned int i;
+
     switch (node->type)
     {
         case MF_TOPOLOGY_SOURCESTREAM_NODE:
@@ -632,6 +659,9 @@ static void release_topo_node(struct topo_node *node)
                 IMFMediaSource_Release(node->u.source.source);
             break;
         case MF_TOPOLOGY_TRANSFORM_NODE:
+            for (i = 0; i < node->u.transform.output_count; ++i)
+                transform_stream_drop_samples(&node->u.transform.outputs[i]);
+            heap_free(node->u.transform.outputs);
             heap_free(node->u.transform.input_map);
             heap_free(node->u.transform.output_map);
             break;
@@ -960,14 +990,13 @@ static HRESULT session_add_media_sink(struct media_session *session, IMFTopology
 static HRESULT session_set_transform_stream_info(struct topo_node *node)
 {
     unsigned int *input_map = NULL, *output_map = NULL;
-    unsigned int input_count, output_count;
+    unsigned int i, input_count, output_count;
+    struct transform_stream *streams;
     HRESULT hr;
 
     hr = IMFTransform_GetStreamCount(node->object.transform, &input_count, &output_count);
     if (SUCCEEDED(hr) && (input_count > 1 || output_count > 1))
     {
-        unsigned int *input_map, *output_map;
-
         input_map = heap_calloc(input_count, sizeof(*input_map));
         output_map = heap_calloc(output_count, sizeof(*output_map));
         if (FAILED(IMFTransform_GetStreamIDs(node->object.transform, input_count, input_map,
@@ -982,6 +1011,11 @@ static HRESULT session_set_transform_stream_info(struct topo_node *node)
 
     if (SUCCEEDED(hr))
     {
+        streams = heap_calloc(output_count, sizeof(*streams));
+        for (i = 0; i < output_count; ++i)
+            list_init(&streams[i].samples);
+        node->u.transform.outputs = streams;
+
         node->u.transform.input_count = input_count;
         node->u.transform.output_count = output_count;
         node->u.transform.input_map = input_map;
@@ -2167,63 +2201,81 @@ static struct topo_node *session_get_node_by_id(struct media_session *session, T
     return NULL;
 }
 
-static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *upstream_node,
-        DWORD upsteam_output)
+static DWORD transform_node_get_stream_id(struct topo_node *node, BOOL output, DWORD index)
 {
-    MF_TOPOLOGY_TYPE upstream_type;
-    struct topo_node *node;
-    TOPOID upstream_id;
-    HRESULT hr;
+    unsigned int *map = output ? node->u.transform.output_map : node->u.transform.input_map;
+    return map ? map[index] : index;
+}
 
-    IMFTopologyNode_GetNodeType(upstream_node, &upstream_type);
-    IMFTopologyNode_GetTopoNodeID(upstream_node, &upstream_id);
+static HRESULT transform_node_get_sample(struct topo_node *node, DWORD output, IMFSample **sample)
+{
+    struct list *list = &node->u.transform.outputs[output].samples;
+    MFT_OUTPUT_STREAM_INFO stream_info;
+    MFT_OUTPUT_DATA_BUFFER *buffers;
+    struct sample *queued_sample;
+    DWORD status = 0;
+    unsigned int i;
+    HRESULT hr;
 
-    node = session_get_node_by_id(session, upstream_id);
+    *sample = NULL;
 
-    switch (upstream_type)
+    if (!list_empty(list))
     {
-        case MF_TOPOLOGY_SOURCESTREAM_NODE:
-            if (FAILED(hr = IMFMediaStream_RequestSample(node->object.source_stream, NULL)))
-                WARN("Sample request failed, hr %#x.\n", hr);
-            break;
-        case MF_TOPOLOGY_TRANSFORM_NODE:
-        case MF_TOPOLOGY_TEE_NODE:
-            FIXME("Unhandled upstream node type %d.\n", upstream_type);
-        default:
-            hr = E_UNEXPECTED;
+        queued_sample = LIST_ENTRY(list_head(list), struct sample, entry);
+        list_remove(&queued_sample->entry);
+        *sample = queued_sample->sample;
+        heap_free(queued_sample);
+        return S_OK;
     }
 
-    return hr;
-}
+    if (!(buffers = heap_calloc(node->u.transform.output_count, sizeof(*buffers))))
+        return E_OUTOFMEMORY;
 
-static void session_request_sample(struct media_session *session, IMFStreamSink *sink_stream)
-{
-    struct topo_node *sink_node = NULL, *node;
-    IMFTopologyNode *upstream_node;
-    DWORD upstream_output;
-    HRESULT hr;
+    for (i = 0; i < node->u.transform.output_count; ++i)
+    {
+        buffers[i].dwStreamID = transform_node_get_stream_id(node, TRUE, i);
+        buffers[i].pSample = NULL;
+        buffers[i].dwStatus = 0;
+        buffers[i].pEvents = NULL;
 
-    LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
+        /* Buffer requirements. */
+        memset(&stream_info, 0, sizeof(stream_info));
+        if (FAILED(hr = IMFTransform_GetOutputStreamInfo(node->object.transform, buffers[i].dwStreamID, &stream_info)))
+            goto exit;
+
+        if (!(stream_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES))
+            FIXME("Allocate client sample for stream %u.\n", buffers[i].dwStreamID);
+    }
+
+    hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status);
+    if (hr == S_OK)
     {
-        if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink_stream)
+        /* Collect returned samples for all streams. */
+        for (i = 0; i < node->u.transform.output_count; ++i)
         {
-            sink_node = node;
-            break;
-        }
-    }
+            if (buffers[i].pEvents)
+                IMFCollection_Release(buffers[i].pEvents);
 
-    if (!sink_node)
-        return;
+            if (!buffers[i].pSample)
+                continue;
 
-    if (FAILED(hr = IMFTopologyNode_GetInput(sink_node->node, 0, &upstream_node, &upstream_output)))
-    {
-        WARN("Failed to get upstream node connection, hr %#x.\n", hr);
-        return;
+            if (i == output)
+            {
+                *sample = buffers[i].pSample;
+            }
+            else
+            {
+                queued_sample = heap_alloc(sizeof(*queued_sample));
+                queued_sample->sample = buffers[i].pSample;
+                list_add_tail(&node->u.transform.outputs[i].samples, &queued_sample->entry);
+            }
+        }
     }
 
-    if (SUCCEEDED(session_request_sample_from_node(session, upstream_node, upstream_output)))
-        sink_node->u.sink.requests++;
-    IMFTopologyNode_Release(upstream_node);
+exit:
+    heap_free(buffers);
+
+    return hr;
 }
 
 static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *downstream_node,
@@ -2258,6 +2310,89 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop
     }
 }
 
+static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output)
+{
+    IMFTopologyNode *downstream_node, *upstream_node;
+    MF_TOPOLOGY_TYPE node_type;
+    IMFSample *sample = NULL;
+    struct topo_node *topo_node;
+    DWORD downstream_input, upstream_output;
+    TOPOID node_id;
+    HRESULT hr;
+
+    IMFTopologyNode_GetNodeType(node, &node_type);
+    IMFTopologyNode_GetTopoNodeID(node, &node_id);
+
+    topo_node = session_get_node_by_id(session, node_id);
+
+    switch (node_type)
+    {
+        case MF_TOPOLOGY_SOURCESTREAM_NODE:
+            if (FAILED(hr = IMFMediaStream_RequestSample(topo_node->object.source_stream, NULL)))
+                WARN("Sample request failed, hr %#x.\n", hr);
+            break;
+        case MF_TOPOLOGY_TRANSFORM_NODE:
+
+            hr = transform_node_get_sample(topo_node, output, &sample);
+            if (sample)
+            {
+                if (SUCCEEDED(hr = IMFTopologyNode_GetOutput(node, output, &downstream_node, &downstream_input)))
+                {
+                    session_deliver_sample_to_node(session, downstream_node, downstream_input, sample);
+                    IMFTopologyNode_Release(downstream_node);
+                }
+                IMFSample_Release(sample);
+            }
+
+            /* Forward request to upstream node. */
+            if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT || (hr == S_OK && !sample))
+            {
+                if (SUCCEEDED(hr = IMFTopologyNode_GetInput(node, 0 /* FIXME */, &upstream_node, &upstream_output)))
+                {
+                    hr = session_request_sample_from_node(session, upstream_node, upstream_output);
+                    IMFTopologyNode_Release(upstream_node);
+                }
+            }
+            break;
+        case MF_TOPOLOGY_TEE_NODE:
+            FIXME("Unhandled upstream node type %d.\n", node_type);
+        default:
+            hr = E_UNEXPECTED;
+    }
+
+    return hr;
+}
+
+static void session_request_sample(struct media_session *session, IMFStreamSink *sink_stream)
+{
+    struct topo_node *sink_node = NULL, *node;
+    IMFTopologyNode *upstream_node;
+    DWORD upstream_output;
+    HRESULT hr;
+
+    LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
+    {
+        if (node->type == MF_TOPOLOGY_OUTPUT_NODE && node->object.sink_stream == sink_stream)
+        {
+            sink_node = node;
+            break;
+        }
+    }
+
+    if (!sink_node)
+        return;
+
+    if (FAILED(hr = IMFTopologyNode_GetInput(sink_node->node, 0, &upstream_node, &upstream_output)))
+    {
+        WARN("Failed to get upstream node connection, hr %#x.\n", hr);
+        return;
+    }
+
+    if (SUCCEEDED(session_request_sample_from_node(session, upstream_node, upstream_output)))
+        sink_node->u.sink.requests++;
+    IMFTopologyNode_Release(upstream_node);
+}
+
 static void session_deliver_sample(struct media_session *session, IMFMediaStream *stream, const PROPVARIANT *value)
 {
     struct topo_node *source_node = NULL, *node;
-- 
2.25.1




More information about the wine-devel mailing list