[PATCH v2 3/3] quartz/filtergraph: Always sort filter list before use.

Anton Baskanov baskanov at gmail.com
Wed Jun 10 11:09:08 CDT 2020


Some applications (e.g. Earth 2150) call IPin::Connect directly instead of IFilterGraph::ConnectDirect.

Signed-off-by: Anton Baskanov <baskanov at gmail.com>
---
 dlls/quartz/filtergraph.c       | 48 +++++++++++++--------------------
 dlls/quartz/tests/filtergraph.c | 11 +++++---
 2 files changed, 27 insertions(+), 32 deletions(-)

diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c
index c0014010d8..3b4f148c0c 100644
--- a/dlls/quartz/filtergraph.c
+++ b/dlls/quartz/filtergraph.c
@@ -151,7 +151,7 @@ typedef struct _ITF_CACHE_ENTRY {
 
 struct filter
 {
-    struct list entry, sorted_entry;
+    struct list entry;
     IBaseFilter *filter;
     IMediaSeeking *seeking;
     WCHAR *name;
@@ -187,17 +187,7 @@ typedef struct _IFilterGraphImpl {
     LONG ref;
     IUnknown *punkFilterMapper2;
 
-    /* We keep two lists of filters, one unsorted and one topologically sorted.
-     * The former is necessary for functions like IGraphBuilder::Connect() and
-     * IGraphBuilder::Render() that iterate through the filter list but may
-     * add to it while doing so; the latter is for functions like
-     * IMediaControl::Run() that should propagate messages to all filters
-     * (including unconnected ones) but must do so in topological order from
-     * sinks to sources. We can easily guarantee that the loop in Connect() will
-     * touch each filter exactly once so long as we aren't reordering it, but
-     * using the sorted filters list there would be hard. This seems to be the
-     * easiest and clearest solution. */
-    struct list filters, sorted_filters;
+    struct list filters;
     unsigned int name_index;
 
     IReferenceClock *refClock;
@@ -683,7 +673,6 @@ static HRESULT WINAPI FilterGraph2_AddFilter(IFilterGraph2 *iface,
     IBaseFilter_AddRef(entry->filter = filter);
 
     list_add_head(&graph->filters, &entry->entry);
-    list_add_head(&graph->sorted_filters, &entry->sorted_entry);
     entry->sorting = FALSE;
     entry->seeking = NULL;
     ++graph->version;
@@ -765,7 +754,6 @@ static HRESULT WINAPI FilterGraph2_RemoveFilter(IFilterGraph2 *iface, IBaseFilte
                 if (entry->seeking)
                     IMediaSeeking_Release(entry->seeking);
                 list_remove(&entry->entry);
-                list_remove(&entry->sorted_entry);
                 CoTaskMemFree(entry->name);
                 heap_free(entry);
                 This->version++;
@@ -894,7 +882,7 @@ static struct filter *find_sorted_filter(IFilterGraphImpl *graph, IBaseFilter *i
 {
     struct filter *filter;
 
-    LIST_FOR_EACH_ENTRY(filter, &graph->sorted_filters, struct filter, sorted_entry)
+    LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
     {
         if (filter->filter == iface)
             return filter;
@@ -938,21 +926,21 @@ static void sort_filter_recurse(IFilterGraphImpl *graph, struct filter *filter,
 
     filter->sorting = FALSE;
 
-    list_remove(&filter->sorted_entry);
-    list_add_head(sorted, &filter->sorted_entry);
+    list_remove(&filter->entry);
+    list_add_head(sorted, &filter->entry);
 }
 
 static void sort_filters(IFilterGraphImpl *graph)
 {
     struct list sorted = LIST_INIT(sorted), *cursor;
 
-    while ((cursor = list_head(&graph->sorted_filters)))
+    while ((cursor = list_head(&graph->filters)))
     {
-        struct filter *filter = LIST_ENTRY(cursor, struct filter, sorted_entry);
+        struct filter *filter = LIST_ENTRY(cursor, struct filter, entry);
         sort_filter_recurse(graph, filter, &sorted);
     }
 
-    list_move_tail(&graph->sorted_filters, &sorted);
+    list_move_tail(&graph->filters, &sorted);
 }
 
 /* NOTE: despite the implication, it doesn't matter which
@@ -1005,9 +993,6 @@ static HRESULT WINAPI FilterGraph2_ConnectDirect(IFilterGraph2 *iface, IPin *ppi
         }
     }
 
-    if (SUCCEEDED(hr))
-        sort_filters(This);
-
     return hr;
 }
 
@@ -5135,9 +5120,11 @@ static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
         return S_OK;
     }
 
+    sort_filters(graph);
+
     if (graph->state == State_Running)
     {
-        LIST_FOR_EACH_ENTRY(filter, &graph->sorted_filters, struct filter, sorted_entry)
+        LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
         {
             filter_hr = IBaseFilter_Pause(filter->filter);
             if (hr == S_OK)
@@ -5145,7 +5132,7 @@ static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
         }
     }
 
-    LIST_FOR_EACH_ENTRY(filter, &graph->sorted_filters, struct filter, sorted_entry)
+    LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
     {
         filter_hr = IBaseFilter_Stop(filter->filter);
         if (hr == S_OK)
@@ -5191,6 +5178,7 @@ static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
         return S_OK;
     }
 
+    sort_filters(graph);
     update_render_count(graph);
 
     if (graph->defaultclock && !graph->refClock)
@@ -5204,7 +5192,7 @@ static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
         graph->current_pos += graph->stream_elapsed;
     }
 
-    LIST_FOR_EACH_ENTRY(filter, &graph->sorted_filters, struct filter, sorted_entry)
+    LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
     {
         filter_hr = IBaseFilter_Pause(filter->filter);
         if (hr == S_OK)
@@ -5235,6 +5223,7 @@ static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME start)
     }
     graph->EcCompleteCount = 0;
 
+    sort_filters(graph);
     update_render_count(graph);
 
     if (graph->defaultclock && !graph->refClock)
@@ -5248,7 +5237,7 @@ static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME start)
             stream_start += 500000;
     }
 
-    LIST_FOR_EACH_ENTRY(filter, &graph->sorted_filters, struct filter, sorted_entry)
+    LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
     {
         filter_hr = IBaseFilter_Run(filter->filter, stream_start);
         if (hr == S_OK)
@@ -5275,9 +5264,11 @@ static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD timeout, F
 
     EnterCriticalSection(&graph->cs);
 
+    sort_filters(graph);
+
     *state = graph->state;
 
-    LIST_FOR_EACH_ENTRY(filter, &graph->sorted_filters, struct filter, sorted_entry)
+    LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
     {
         FILTER_STATE filter_state;
         int wait;
@@ -5698,7 +5689,6 @@ static HRESULT filter_graph_common_create(IUnknown *outer, IUnknown **out, BOOL
     fimpl->IGraphVersion_iface.lpVtbl = &IGraphVersion_VTable;
     fimpl->ref = 1;
     list_init(&fimpl->filters);
-    list_init(&fimpl->sorted_filters);
     fimpl->name_index = 1;
     fimpl->refClock = NULL;
     fimpl->hEventCompletion = CreateEventW(0, TRUE, FALSE, 0);
diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c
index 34d2722213..5441fcb24e 100644
--- a/dlls/quartz/tests/filtergraph.c
+++ b/dlls/quartz/tests/filtergraph.c
@@ -3165,7 +3165,9 @@ static void test_filter_state(void)
     IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL);
     IFilterGraph2_AddFilter(graph, &sink.IBaseFilter_iface, NULL);
     IFilterGraph2_AddFilter(graph, &dummy.IBaseFilter_iface, NULL);
-    IFilterGraph2_ConnectDirect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface, NULL);
+    /* Using IPin::Connect instead of IFilterGraph2::ConnectDirect to show that */
+    /* FilterGraph does not rely on ::ConnectDirect to track filter connections. */
+    IPin_Connect(&source_pin.IPin_iface, &sink_pin.IPin_iface, NULL);
 
     check_filter_state(graph, State_Stopped);
 
@@ -3240,9 +3242,12 @@ static void test_filter_state(void)
     IFilterGraph2_QueryInterface(graph, &IID_IMediaFilter, (void **)&filter);
     IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
 
-    IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL);
+    /* Add the filters in reverse order this time. */
     IFilterGraph2_AddFilter(graph, &sink.IBaseFilter_iface, NULL);
-    IFilterGraph2_ConnectDirect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface, NULL);
+    IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL);
+    /* Using IPin::Connect instead of IFilterGraph2::ConnectDirect to show that */
+    /* FilterGraph does not rely on ::ConnectDirect to track filter connections. */
+    IPin_Connect(&source_pin.IPin_iface, &sink_pin.IPin_iface, NULL);
 
     hr = IMediaFilter_Pause(filter);
     ok(hr == S_OK, "Got hr %#x.\n", hr);
-- 
2.17.1




More information about the wine-devel mailing list