From ff38669c1adb127aebfe2dea640d720790cd2436 Mon Sep 17 00:00:00 2001 From: Anton Baskanov Date: Fri, 12 Jun 2020 14:57:09 +0700 Subject: [PATCH] quartz/filtergraph: Always sort filter list before use. Some applications (e.g. Earth 2150) call IPin::Connect directly instead of IFilterGraph::ConnectDirect. Signed-off-by: Anton Baskanov Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard --- 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 0d0ccc2b624..fa20d98981b 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; @@ -686,7 +676,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; @@ -768,7 +757,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++; @@ -897,7 +885,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; @@ -941,21 +929,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 @@ -1008,9 +996,6 @@ static HRESULT WINAPI FilterGraph2_ConnectDirect(IFilterGraph2 *iface, IPin *ppi } } - if (SUCCEEDED(hr)) - sort_filters(This); - return hr; } @@ -5138,9 +5123,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) @@ -5148,7 +5135,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) @@ -5194,6 +5181,7 @@ static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface) return S_OK; } + sort_filters(graph); update_render_count(graph); if (graph->defaultclock && !graph->refClock) @@ -5207,7 +5195,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) @@ -5238,6 +5226,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) @@ -5251,7 +5240,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) @@ -5278,9 +5267,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; @@ -5753,7 +5744,6 @@ static HRESULT filter_graph_common_create(IUnknown *outer, IUnknown **out, BOOL fimpl->IVideoFrameStep_iface.lpVtbl = &VideoFrameStep_vtbl; 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 50c2402c326..4f4abeac9b9 100644 --- a/dlls/quartz/tests/filtergraph.c +++ b/dlls/quartz/tests/filtergraph.c @@ -3166,7 +3166,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); @@ -3241,9 +3243,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);