Zebediah Figura : quartz: Poll in IMediaFilter::GetState().

Alexandre Julliard julliard at winehq.org
Wed Jul 15 16:44:44 CDT 2020


Module: wine
Branch: master
Commit: df8eabc00a0807cf89f528bb6bce10427c300407
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=df8eabc00a0807cf89f528bb6bce10427c300407

Author: Zebediah Figura <z.figura12 at gmail.com>
Date:   Tue Jul 14 19:56:22 2020 -0500

quartz: Poll in IMediaFilter::GetState().

Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 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 5a10df9db2..17963c2b75 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;
 }




More information about the wine-cvs mailing list