forked from Mirrors/wine-wine
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 <baskanov@gmail.com> Signed-off-by: Zebediah Figura <z.figura12@gmail.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>feature/deterministic
parent
2d79e04bfe
commit
ff38669c1a
|
@ -151,7 +151,7 @@ typedef struct _ITF_CACHE_ENTRY {
|
||||||
|
|
||||||
struct filter
|
struct filter
|
||||||
{
|
{
|
||||||
struct list entry, sorted_entry;
|
struct list entry;
|
||||||
IBaseFilter *filter;
|
IBaseFilter *filter;
|
||||||
IMediaSeeking *seeking;
|
IMediaSeeking *seeking;
|
||||||
WCHAR *name;
|
WCHAR *name;
|
||||||
|
@ -187,17 +187,7 @@ typedef struct _IFilterGraphImpl {
|
||||||
LONG ref;
|
LONG ref;
|
||||||
IUnknown *punkFilterMapper2;
|
IUnknown *punkFilterMapper2;
|
||||||
|
|
||||||
/* We keep two lists of filters, one unsorted and one topologically sorted.
|
struct list filters;
|
||||||
* 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;
|
|
||||||
unsigned int name_index;
|
unsigned int name_index;
|
||||||
|
|
||||||
IReferenceClock *refClock;
|
IReferenceClock *refClock;
|
||||||
|
@ -686,7 +676,6 @@ static HRESULT WINAPI FilterGraph2_AddFilter(IFilterGraph2 *iface,
|
||||||
IBaseFilter_AddRef(entry->filter = filter);
|
IBaseFilter_AddRef(entry->filter = filter);
|
||||||
|
|
||||||
list_add_head(&graph->filters, &entry->entry);
|
list_add_head(&graph->filters, &entry->entry);
|
||||||
list_add_head(&graph->sorted_filters, &entry->sorted_entry);
|
|
||||||
entry->sorting = FALSE;
|
entry->sorting = FALSE;
|
||||||
entry->seeking = NULL;
|
entry->seeking = NULL;
|
||||||
++graph->version;
|
++graph->version;
|
||||||
|
@ -768,7 +757,6 @@ static HRESULT WINAPI FilterGraph2_RemoveFilter(IFilterGraph2 *iface, IBaseFilte
|
||||||
if (entry->seeking)
|
if (entry->seeking)
|
||||||
IMediaSeeking_Release(entry->seeking);
|
IMediaSeeking_Release(entry->seeking);
|
||||||
list_remove(&entry->entry);
|
list_remove(&entry->entry);
|
||||||
list_remove(&entry->sorted_entry);
|
|
||||||
CoTaskMemFree(entry->name);
|
CoTaskMemFree(entry->name);
|
||||||
heap_free(entry);
|
heap_free(entry);
|
||||||
This->version++;
|
This->version++;
|
||||||
|
@ -897,7 +885,7 @@ static struct filter *find_sorted_filter(IFilterGraphImpl *graph, IBaseFilter *i
|
||||||
{
|
{
|
||||||
struct filter *filter;
|
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)
|
if (filter->filter == iface)
|
||||||
return filter;
|
return filter;
|
||||||
|
@ -941,21 +929,21 @@ static void sort_filter_recurse(IFilterGraphImpl *graph, struct filter *filter,
|
||||||
|
|
||||||
filter->sorting = FALSE;
|
filter->sorting = FALSE;
|
||||||
|
|
||||||
list_remove(&filter->sorted_entry);
|
list_remove(&filter->entry);
|
||||||
list_add_head(sorted, &filter->sorted_entry);
|
list_add_head(sorted, &filter->entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sort_filters(IFilterGraphImpl *graph)
|
static void sort_filters(IFilterGraphImpl *graph)
|
||||||
{
|
{
|
||||||
struct list sorted = LIST_INIT(sorted), *cursor;
|
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);
|
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
|
/* 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;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5138,9 +5123,11 @@ static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sort_filters(graph);
|
||||||
|
|
||||||
if (graph->state == State_Running)
|
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);
|
filter_hr = IBaseFilter_Pause(filter->filter);
|
||||||
if (hr == S_OK)
|
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);
|
filter_hr = IBaseFilter_Stop(filter->filter);
|
||||||
if (hr == S_OK)
|
if (hr == S_OK)
|
||||||
|
@ -5194,6 +5181,7 @@ static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sort_filters(graph);
|
||||||
update_render_count(graph);
|
update_render_count(graph);
|
||||||
|
|
||||||
if (graph->defaultclock && !graph->refClock)
|
if (graph->defaultclock && !graph->refClock)
|
||||||
|
@ -5207,7 +5195,7 @@ static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
|
||||||
graph->current_pos += graph->stream_elapsed;
|
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);
|
filter_hr = IBaseFilter_Pause(filter->filter);
|
||||||
if (hr == S_OK)
|
if (hr == S_OK)
|
||||||
|
@ -5238,6 +5226,7 @@ static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME start)
|
||||||
}
|
}
|
||||||
graph->EcCompleteCount = 0;
|
graph->EcCompleteCount = 0;
|
||||||
|
|
||||||
|
sort_filters(graph);
|
||||||
update_render_count(graph);
|
update_render_count(graph);
|
||||||
|
|
||||||
if (graph->defaultclock && !graph->refClock)
|
if (graph->defaultclock && !graph->refClock)
|
||||||
|
@ -5251,7 +5240,7 @@ static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME start)
|
||||||
stream_start += 500000;
|
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);
|
filter_hr = IBaseFilter_Run(filter->filter, stream_start);
|
||||||
if (hr == S_OK)
|
if (hr == S_OK)
|
||||||
|
@ -5278,9 +5267,11 @@ static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD timeout, F
|
||||||
|
|
||||||
EnterCriticalSection(&graph->cs);
|
EnterCriticalSection(&graph->cs);
|
||||||
|
|
||||||
|
sort_filters(graph);
|
||||||
|
|
||||||
*state = graph->state;
|
*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;
|
FILTER_STATE filter_state;
|
||||||
int wait;
|
int wait;
|
||||||
|
@ -5753,7 +5744,6 @@ static HRESULT filter_graph_common_create(IUnknown *outer, IUnknown **out, BOOL
|
||||||
fimpl->IVideoFrameStep_iface.lpVtbl = &VideoFrameStep_vtbl;
|
fimpl->IVideoFrameStep_iface.lpVtbl = &VideoFrameStep_vtbl;
|
||||||
fimpl->ref = 1;
|
fimpl->ref = 1;
|
||||||
list_init(&fimpl->filters);
|
list_init(&fimpl->filters);
|
||||||
list_init(&fimpl->sorted_filters);
|
|
||||||
fimpl->name_index = 1;
|
fimpl->name_index = 1;
|
||||||
fimpl->refClock = NULL;
|
fimpl->refClock = NULL;
|
||||||
fimpl->hEventCompletion = CreateEventW(0, TRUE, FALSE, 0);
|
fimpl->hEventCompletion = CreateEventW(0, TRUE, FALSE, 0);
|
||||||
|
|
|
@ -3166,7 +3166,9 @@ static void test_filter_state(void)
|
||||||
IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL);
|
IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL);
|
||||||
IFilterGraph2_AddFilter(graph, &sink.IBaseFilter_iface, NULL);
|
IFilterGraph2_AddFilter(graph, &sink.IBaseFilter_iface, NULL);
|
||||||
IFilterGraph2_AddFilter(graph, &dummy.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);
|
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_IMediaFilter, (void **)&filter);
|
||||||
IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
|
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_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);
|
hr = IMediaFilter_Pause(filter);
|
||||||
ok(hr == S_OK, "Got hr %#x.\n", hr);
|
ok(hr == S_OK, "Got hr %#x.\n", hr);
|
||||||
|
|
Loading…
Reference in New Issue