[PATCH 05/14] mf: Use separate list for source streams.

Nikolay Sivov nsivov at codeweavers.com
Fri Feb 28 06:00:55 CST 2020


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

diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 0963bcb06e..17bb44eaa7 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -79,12 +79,6 @@ enum session_state
     SESSION_STATE_SHUT_DOWN,
 };
 
-struct media_stream
-{
-    struct list entry;
-    IMFMediaStream *stream;
-};
-
 enum source_state
 {
     SOURCE_STATE_STOPPED = 0,
@@ -96,8 +90,16 @@ struct media_source
 {
     struct list entry;
     IMFMediaSource *source;
+    IMFPresentationDescriptor *pd;
     enum source_state state;
-    struct list streams;
+};
+
+struct source_node
+{
+    struct list entry;
+    IMFMediaStream *stream;
+    IMFMediaSource *source;
+    DWORD stream_id;
 };
 
 struct media_sink
@@ -125,6 +127,7 @@ struct media_session
         IMFTopology *current_topology;
         MF_TOPOSTATUS topo_status;
         struct list sources;
+        struct list source_nodes;
         struct list sinks;
     } presentation;
     struct list topologies;
@@ -536,8 +539,8 @@ static HRESULT session_bind_output_nodes(IMFTopology *topology)
 
 static void session_clear_presentation(struct media_session *session)
 {
+    struct source_node *src_node, *src_node2;
     struct media_source *source, *source2;
-    struct media_stream *stream, *stream2;
     struct media_sink *sink, *sink2;
 
     IMFTopology_Clear(session->presentation.current_topology);
@@ -546,20 +549,22 @@ static void session_clear_presentation(struct media_session *session)
     LIST_FOR_EACH_ENTRY_SAFE(source, source2, &session->presentation.sources, struct media_source, entry)
     {
         list_remove(&source->entry);
-
-        LIST_FOR_EACH_ENTRY_SAFE(stream, stream2, &source->streams, struct media_stream, entry)
-        {
-            list_remove(&stream->entry);
-            if (stream->stream)
-                IMFMediaStream_Release(stream->stream);
-            heap_free(stream);
-        }
-
         if (source->source)
             IMFMediaSource_Release(source->source);
+        if (source->pd)
+            IMFPresentationDescriptor_Release(source->pd);
         heap_free(source);
     }
 
+    LIST_FOR_EACH_ENTRY_SAFE(src_node, src_node2, &session->presentation.source_nodes, struct source_node, entry)
+    {
+        list_remove(&src_node->entry);
+        if (src_node->stream)
+            IMFMediaStream_Release(src_node->stream);
+        heap_free(src_node);
+    }
+
+
     LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &session->presentation.sinks, struct media_sink, entry)
     {
         list_remove(&sink->entry);
@@ -648,6 +653,130 @@ static void session_start(struct media_session *session, const GUID *time_format
     LeaveCriticalSection(&session->cs);
 }
 
+static struct media_source *session_get_media_source(struct media_session *session, IMFMediaSource *source)
+{
+    struct media_source *cur;
+
+    LIST_FOR_EACH_ENTRY(cur, &session->presentation.sources, struct media_source, entry)
+    {
+        if (source == cur->source)
+            return cur;
+    }
+
+    return NULL;
+}
+
+static void session_release_media_source(struct media_source *source)
+{
+    IMFMediaSource_Release(source->source);
+    if (source->pd)
+        IMFPresentationDescriptor_Release(source->pd);
+    heap_free(source);
+}
+
+static HRESULT session_add_media_source(struct media_session *session, IMFTopologyNode *node, IMFMediaSource *source)
+{
+    struct media_source *media_source;
+    HRESULT hr;
+
+    if (session_get_media_source(session, source))
+        return S_FALSE;
+
+    if (!(media_source = heap_alloc_zero(sizeof(*media_source))))
+        return E_OUTOFMEMORY;
+
+    media_source->source = source;
+    IMFMediaSource_AddRef(media_source->source);
+
+    hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor,
+            (void **)&media_source->pd);
+
+    if (SUCCEEDED(hr))
+        list_add_tail(&session->presentation.sources, &media_source->entry);
+    else
+        session_release_media_source(media_source);
+
+    return hr;
+}
+
+static HRESULT session_add_source_node(struct media_session *session, IMFTopologyNode *node, IMFMediaSource *source)
+{
+    struct source_node *source_node;
+    IMFStreamDescriptor *sd;
+    DWORD stream_id;
+    HRESULT hr;
+
+    if (FAILED(hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor,
+            (void **)&sd)))
+    {
+        WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#x.\n", hr);
+        return hr;
+    }
+
+    hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &stream_id);
+    IMFStreamDescriptor_Release(sd);
+    if (FAILED(hr))
+        return hr;
+
+    if (!(source_node = heap_alloc_zero(sizeof(*source_node))))
+        return E_OUTOFMEMORY;
+
+    source_node->source = source;
+    IMFMediaSource_AddRef(source_node->source);
+
+    list_add_tail(&session->presentation.source_nodes, &source_node->entry);
+
+    return hr;
+}
+
+static void session_collect_source_nodes(struct media_session *session)
+{
+    IMFTopology *topology;
+    IMFTopologyNode *node;
+    IMFCollection *nodes;
+    DWORD count, i;
+    HRESULT hr;
+
+    if (!list_empty(&session->presentation.source_nodes))
+        return;
+
+    topology = session->presentation.current_topology;
+
+    if (!topology || FAILED(IMFTopology_GetSourceNodeCollection(topology, &nodes)))
+        return;
+
+    if (FAILED(IMFCollection_GetElementCount(nodes, &count)))
+        return;
+
+    /* Create list of distinct sources, and whole list of source nodes. */
+    for (i = 0; i < count; ++i)
+    {
+        if (SUCCEEDED(hr = IMFCollection_GetElement(nodes, i, (IUnknown **)&node)))
+        {
+            IMFMediaSource *source;
+
+            if (FAILED(IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_SOURCE, &IID_IMFMediaSource, (void **)&source)))
+            {
+                WARN("Missing MF_TOPONODE_SOURCE, hr %#x.\n", hr);
+                IMFTopologyNode_Release(node);
+                continue;
+            }
+
+            hr = session_add_media_source(session, node, source);
+            IMFMediaSource_Release(source);
+
+            if (SUCCEEDED(hr))
+            {
+                if (FAILED(hr = session_add_source_node(session, node, source)))
+                    WARN("Failed to add source node, hr %#x.\n", hr);
+            }
+
+            IMFMediaSource_Release(source);
+            IMFTopologyNode_Release(node);
+        }
+    }
+}
+
 static void session_raise_topology_set(struct media_session *session, IMFTopology *topology, HRESULT status)
 {
     PROPVARIANT param;
@@ -669,6 +798,8 @@ static void session_set_current_topology(struct media_session *session, IMFTopol
         return;
     }
 
+    session_collect_source_nodes(session);
+
     /* FIXME: attributes are all zero for now */
     if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime, &GUID_NULL, S_OK, NULL, &event)))
     {
@@ -1220,17 +1351,36 @@ static HRESULT WINAPI session_events_callback_GetParameters(IMFAsyncCallback *if
     return E_NOTIMPL;
 }
 
-static HRESULT session_add_media_stream(struct media_source *source, IMFMediaStream *stream)
+static HRESULT session_add_media_stream(struct media_session *session, IMFMediaSource *source, IMFMediaStream *stream)
 {
-    struct media_stream *media_stream;
+    struct source_node *node;
+    IMFStreamDescriptor *sd;
+    DWORD stream_id = 0;
+    HRESULT hr;
 
-    if (!(media_stream = heap_alloc_zero(sizeof(*media_stream))))
-        return E_OUTOFMEMORY;
+    if (FAILED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
+        return hr;
 
-    media_stream->stream = stream;
-    IMFMediaStream_AddRef(media_stream->stream);
+    hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &stream_id);
+    IMFStreamDescriptor_Release(sd);
+    if (FAILED(hr))
+        return hr;
 
-    list_add_tail(&source->streams, &media_stream->entry);
+    LIST_FOR_EACH_ENTRY(node, &session->presentation.source_nodes, struct source_node, entry)
+    {
+        if (node->source == source && node->stream_id == stream_id)
+        {
+            if (node->stream)
+            {
+                WARN("Source node already has stream set.\n");
+                return S_FALSE;
+            }
+
+            node->stream = stream;
+            IMFMediaStream_AddRef(node->stream);
+            break;
+        }
+    }
 
     return S_OK;
 }
@@ -1322,7 +1472,6 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM
     enum source_state source_state;
     IMFMediaEvent *event = NULL;
     MediaEventType event_type;
-    struct media_source *cur;
     IMFMediaSource *source;
     IMFMediaStream *stream;
     PROPVARIANT value;
@@ -1394,22 +1543,12 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM
                 break;
 
             EnterCriticalSection(&session->cs);
-
-            LIST_FOR_EACH_ENTRY(cur, &session->presentation.sources, struct media_source, entry)
-            {
-                if (source == cur->source)
-                {
-                    hr = session_add_media_stream(cur, stream);
-
-                    if (SUCCEEDED(hr))
-                        hr = IMFMediaStream_BeginGetEvent(stream, &session->events_callback, (IUnknown *)stream);
-
-                    break;
-                }
-            }
-
+            if (SUCCEEDED(hr = session_add_media_stream(session, source, stream)))
+                hr = IMFMediaStream_BeginGetEvent(stream, &session->events_callback, (IUnknown *)stream);
             LeaveCriticalSection(&session->cs);
 
+            IMFMediaSource_Release(source);
+
             break;
         default:
             ;
@@ -1610,6 +1749,7 @@ HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **ses
     object->refcount = 1;
     list_init(&object->topologies);
     list_init(&object->presentation.sources);
+    list_init(&object->presentation.source_nodes);
     list_init(&object->presentation.sinks);
     InitializeCriticalSection(&object->cs);
 
-- 
2.25.0




More information about the wine-devel mailing list