[PATCH 3/4] quartz/filtergraph: Always sort filter list before use.
Anton Baskanov
baskanov at gmail.com
Mon Jun 8 13:00:54 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 | 68 +++++++++++++++++----------------
dlls/quartz/tests/filtergraph.c | 11 ++++--
2 files changed, 44 insertions(+), 35 deletions(-)
diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c
index 76d64e4ca4..bfb6ea78d3 100644
--- a/dlls/quartz/filtergraph.c
+++ b/dlls/quartz/filtergraph.c
@@ -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;
@@ -680,7 +670,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;
@@ -762,7 +751,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++;
@@ -887,11 +875,11 @@ out:
#endif
}
-static struct filter *find_sorted_filter(IFilterGraphImpl *graph, IBaseFilter *iface)
+static struct filter *find_sorted_filter(struct list *sorted_filters, IBaseFilter *iface)
{
struct filter *filter;
- LIST_FOR_EACH_ENTRY(filter, &graph->sorted_filters, struct filter, sorted_entry)
+ LIST_FOR_EACH_ENTRY(filter, sorted_filters, struct filter, sorted_entry)
{
if (filter->filter == iface)
return filter;
@@ -900,7 +888,7 @@ static struct filter *find_sorted_filter(IFilterGraphImpl *graph, IBaseFilter *i
return NULL;
}
-static void sort_filter_recurse(IFilterGraphImpl *graph, struct filter *filter, struct list *sorted)
+static void sort_filter_recurse(struct list *sorted_filters, struct filter *filter, struct list *sorted)
{
struct filter *peer_filter;
IEnumPins *enumpins;
@@ -924,8 +912,8 @@ static void sort_filter_recurse(IFilterGraphImpl *graph, struct filter *filter,
{
IPin_QueryPinInfo(peer, &info);
/* Note that the filter may have already been sorted. */
- if ((peer_filter = find_sorted_filter(graph, info.pFilter)))
- sort_filter_recurse(graph, peer_filter, sorted);
+ if ((peer_filter = find_sorted_filter(sorted_filters, info.pFilter)))
+ sort_filter_recurse(sorted_filters, peer_filter, sorted);
IBaseFilter_Release(info.pFilter);
IPin_Release(peer);
}
@@ -939,17 +927,25 @@ static void sort_filter_recurse(IFilterGraphImpl *graph, struct filter *filter,
list_add_head(sorted, &filter->sorted_entry);
}
-static void sort_filters(IFilterGraphImpl *graph)
+static void sort_filters(IFilterGraphImpl *graph, struct list *sorted_filters)
{
struct list sorted = LIST_INIT(sorted), *cursor;
+ struct filter *filter;
+
+ list_init(sorted_filters);
+
+ LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry)
+ {
+ list_add_tail(sorted_filters, &filter->sorted_entry);
+ }
- while ((cursor = list_head(&graph->sorted_filters)))
+ while ((cursor = list_head(sorted_filters)))
{
- struct filter *filter = LIST_ENTRY(cursor, struct filter, sorted_entry);
- sort_filter_recurse(graph, filter, &sorted);
+ filter = LIST_ENTRY(cursor, struct filter, sorted_entry);
+ sort_filter_recurse(sorted_filters, filter, &sorted);
}
- list_move_tail(&graph->sorted_filters, &sorted);
+ list_move_tail(sorted_filters, &sorted);
}
/* NOTE: despite the implication, it doesn't matter which
@@ -1002,9 +998,6 @@ static HRESULT WINAPI FilterGraph2_ConnectDirect(IFilterGraph2 *iface, IPin *ppi
}
}
- if (SUCCEEDED(hr))
- sort_filters(This);
-
return hr;
}
@@ -5120,6 +5113,7 @@ static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
{
IFilterGraphImpl *graph = impl_from_IMediaFilter(iface);
HRESULT hr = S_OK, filter_hr;
+ struct list sorted_filters;
struct filter *filter;
TRACE("graph %p.\n", graph);
@@ -5132,9 +5126,11 @@ static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
return S_OK;
}
+ sort_filters(graph, &sorted_filters);
+
if (graph->state == State_Running)
{
- LIST_FOR_EACH_ENTRY(filter, &graph->sorted_filters, struct filter, sorted_entry)
+ LIST_FOR_EACH_ENTRY(filter, &sorted_filters, struct filter, sorted_entry)
{
filter_hr = IBaseFilter_Pause(filter->filter);
if (hr == S_OK)
@@ -5142,7 +5138,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, &sorted_filters, struct filter, sorted_entry)
{
filter_hr = IBaseFilter_Stop(filter->filter);
if (hr == S_OK)
@@ -5163,6 +5159,7 @@ static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
{
IFilterGraphImpl *graph = impl_from_IMediaFilter(iface);
HRESULT hr = S_OK, filter_hr;
+ struct list sorted_filters;
struct filter *filter;
TRACE("graph %p.\n", graph);
@@ -5175,6 +5172,8 @@ static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
return S_OK;
}
+ sort_filters(graph, &sorted_filters);
+
if (graph->defaultclock && !graph->refClock)
IFilterGraph2_SetDefaultSyncSource(&graph->IFilterGraph2_iface);
@@ -5186,7 +5185,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, &sorted_filters, struct filter, sorted_entry)
{
filter_hr = IBaseFilter_Pause(filter->filter);
if (hr == S_OK)
@@ -5204,6 +5203,7 @@ static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME start)
IFilterGraphImpl *graph = impl_from_IMediaFilter(iface);
REFERENCE_TIME stream_start = start;
HRESULT hr = S_OK, filter_hr;
+ struct list sorted_filters;
struct filter *filter;
TRACE("graph %p, start %s.\n", graph, debugstr_time(start));
@@ -5218,6 +5218,8 @@ static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME start)
graph->EcCompleteCount = 0;
graph->nRenderers = 0;
+ sort_filters(graph, &sorted_filters);
+
if (graph->defaultclock && !graph->refClock)
IFilterGraph2_SetDefaultSyncSource(&graph->IFilterGraph2_iface);
@@ -5229,7 +5231,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, &sorted_filters, struct filter, sorted_entry)
{
filter_hr = IBaseFilter_Run(filter->filter, stream_start);
if (hr == S_OK)
@@ -5249,6 +5251,7 @@ static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD timeout, F
IFilterGraphImpl *graph = impl_from_IMediaFilter(iface);
DWORD end = GetTickCount() + timeout;
HRESULT hr = S_OK, filter_hr;
+ struct list sorted_filters;
struct filter *filter;
TRACE("graph %p, timeout %u, state %p.\n", graph, timeout, state);
@@ -5258,9 +5261,11 @@ static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD timeout, F
EnterCriticalSection(&graph->cs);
+ sort_filters(graph, &sorted_filters);
+
*state = graph->state;
- LIST_FOR_EACH_ENTRY(filter, &graph->sorted_filters, struct filter, sorted_entry)
+ LIST_FOR_EACH_ENTRY(filter, &sorted_filters, struct filter, sorted_entry)
{
FILTER_STATE filter_state;
int wait;
@@ -5681,7 +5686,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 e0883ed258..3a14a1a6e9 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