From df8eabc00a0807cf89f528bb6bce10427c300407 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Tue, 14 Jul 2020 19:56:22 -0500 Subject: [PATCH] quartz: Poll in IMediaFilter::GetState(). Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard --- dlls/quartz/filtergraph.c | 55 +++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index 5a10df9db2b..17963c2b757 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -4923,40 +4923,57 @@ static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD timeout, F { struct filter_graph *graph = impl_from_IMediaFilter(iface); DWORD end = GetTickCount() + timeout; - HRESULT hr = S_OK, filter_hr; - struct filter *filter; + HRESULT hr; TRACE("graph %p, timeout %u, state %p.\n", graph, timeout, state); if (!state) return E_POINTER; - EnterCriticalSection(&graph->cs); + /* Thread safety is a little tricky here. GetState() shouldn't block other + * functions from being called on the filter graph. However, we can't just + * call IBaseFilter::GetState() in one loop and drop the lock on every + * iteration, since the filter list might change beneath us. So instead we + * do what native does, and poll for it every 10 ms. */ + EnterCriticalSection(&graph->cs); *state = graph->state; - LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry) + for (;;) { + IBaseFilter *async_filter = NULL; FILTER_STATE filter_state; - int wait; + struct filter *filter; - if (timeout == INFINITE) - wait = INFINITE; - else if (!timeout) - wait = 0; - else - wait = max(end - GetTickCount(), 0); + hr = S_OK; - filter_hr = IBaseFilter_GetState(filter->filter, wait, &filter_state); - if (hr == S_OK && filter_hr == VFW_S_STATE_INTERMEDIATE) - hr = VFW_S_STATE_INTERMEDIATE; - else if (filter_hr != S_OK && filter_hr != VFW_S_STATE_INTERMEDIATE) - hr = filter_hr; - if (filter_state != graph->state) - ERR("Filter %p reported incorrect state %u.\n", filter->filter, filter_state); + LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry) + { + HRESULT filter_hr = IBaseFilter_GetState(filter->filter, 0, &filter_state); + + TRACE("Filter %p returned hr %#x, state %u.\n", filter->filter, filter_hr, filter_state); + + if (filter_hr == VFW_S_STATE_INTERMEDIATE) + async_filter = filter->filter; + + if (hr == S_OK && filter_hr == VFW_S_STATE_INTERMEDIATE) + hr = VFW_S_STATE_INTERMEDIATE; + else if (filter_hr != S_OK && filter_hr != VFW_S_STATE_INTERMEDIATE) + hr = filter_hr; + if (filter_state != graph->state) + ERR("Filter %p reported incorrect state %u.\n", filter->filter, filter_state); + } + + LeaveCriticalSection(&graph->cs); + + if (hr != VFW_S_STATE_INTERMEDIATE || (timeout != INFINITE && GetTickCount() >= end)) + break; + + IBaseFilter_GetState(async_filter, 10, &filter_state); + + EnterCriticalSection(&graph->cs); } - LeaveCriticalSection(&graph->cs); TRACE("Returning %#x, state %u.\n", hr, *state); return hr; }