quartz: Fix parser and pins logic to no longer deadlock.
authorMaarten Lankhorst <m.b.lankhorst@gmail.com>
Tue, 1 Apr 2008 21:35:14 +0000 (14:35 -0700)
committerAlexandre Julliard <julliard@winehq.org>
Wed, 2 Apr 2008 09:16:09 +0000 (11:16 +0200)
dlls/quartz/parser.c
dlls/quartz/pin.c
dlls/quartz/pin.h
dlls/quartz/tests/filtergraph.c

index b7bb270620e5476926eab47d18c4674f46f61b71..b09b397be794b1a341ce1584b743125a7cbd13e9 100644 (file)
@@ -259,11 +259,11 @@ static HRESULT WINAPI Parser_Stop(IBaseFilter * iface)
             LeaveCriticalSection(&This->csFilter);
             return S_OK;
         }
-        hr = PullPin_StopProcessing(This->pInputPin);
         This->state = State_Stopped;
     }
     LeaveCriticalSection(&This->csFilter);
-    
+
+    hr = PullPin_StopProcessing(This->pInputPin);
     return hr;
 }
 
@@ -291,8 +291,6 @@ static HRESULT WINAPI Parser_Pause(IBaseFilter * iface)
     {
         unsigned int i;
 
-        hr = PullPin_Seek(This->pInputPin, 0, ((LONGLONG)0x7fffffff << 32) | 0xffffffff);
-
         if (SUCCEEDED(hr))
             hr = PullPin_InitProcessing(This->pInputPin);
 
@@ -342,11 +340,11 @@ static HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
 
         This->rtStreamStart = tStart;
 
-        hr = PullPin_Seek(This->pInputPin, 0, ((LONGLONG)0x7fffffff << 32) | 0xffffffff);
-
         if (SUCCEEDED(hr) && (This->state == State_Stopped))
         {
+            LeaveCriticalSection(&This->csFilter);
             hr = PullPin_InitProcessing(This->pInputPin);
+            EnterCriticalSection(&This->csFilter);
 
             if (SUCCEEDED(hr))
             { 
@@ -358,7 +356,11 @@ static HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
         }
 
         if (SUCCEEDED(hr))
+        {
+            LeaveCriticalSection(&This->csFilter);
             hr = PullPin_StartProcessing(This->pInputPin);
+            EnterCriticalSection(&This->csFilter);
+        }
 
         if (SUCCEEDED(hr))
             This->state = State_Running;
index e8d0f441dd11c6d2fe29f4836c5fa554d4802cdf..686669e08549a41292241faf87287afccc6ba647 100644 (file)
@@ -1195,11 +1195,12 @@ HRESULT PullPin_Init(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID p
     pPinImpl->pAlloc = NULL;
     pPinImpl->pReader = NULL;
     pPinImpl->hThread = NULL;
-    pPinImpl->hEventStateChanged = CreateEventW(NULL, FALSE, TRUE, NULL);
+    pPinImpl->hEventStateChanged = CreateEventW(NULL, TRUE, TRUE, NULL);
 
     pPinImpl->rtStart = 0;
     pPinImpl->rtCurrent = 0;
     pPinImpl->rtStop = ((LONGLONG)0x7fffffff << 32) | 0xffffffff;
+    pPinImpl->state = State_Stopped;
 
     return S_OK;
 }
@@ -1337,8 +1338,11 @@ static void CALLBACK PullPin_Thread_Process(ULONG_PTR iface)
     ALLOCATOR_PROPERTIES allocProps;
 
     CoInitializeEx(NULL, COINIT_MULTITHREADED);
-    
+
+    EnterCriticalSection(This->pin.pCritSec);
     SetEvent(This->hEventStateChanged);
+    This->state = State_Running;
+    LeaveCriticalSection(This->pin.pCritSec);
 
     hr = IMemAllocator_GetProperties(This->pAlloc, &allocProps);
 
@@ -1347,7 +1351,7 @@ static void CALLBACK PullPin_Thread_Process(ULONG_PTR iface)
 
     TRACE("Start\n");
 
-    while (This->rtCurrent < This->rtStop && hr == S_OK)
+    while (This->rtCurrent < This->rtStop && hr == S_OK && !This->stop_playback)
     {
         /* FIXME: to improve performance by quite a bit this should be changed
          * so that one sample is processed while one sample is fetched. However,
@@ -1375,7 +1379,7 @@ static void CALLBACK PullPin_Thread_Process(ULONG_PTR iface)
             hr = IAsyncReader_Request(This->pReader, pSample, (ULONG_PTR)0);
 
         if (SUCCEEDED(hr))
-            hr = IAsyncReader_WaitForNext(This->pReader, 10000, &pSample, &dwUser);
+            hr = IAsyncReader_WaitForNext(This->pReader, 1000, &pSample, &dwUser);
 
         if (SUCCEEDED(hr))
         {
@@ -1395,10 +1399,27 @@ static void CALLBACK PullPin_Thread_Process(ULONG_PTR iface)
     }
 
     CoUninitialize();
-
+    EnterCriticalSection(This->pin.pCritSec);
+    This->state = State_Paused;
+    LeaveCriticalSection(This->pin.pCritSec);
     TRACE("End\n");
 }
 
+static void CALLBACK PullPin_Thread_Pause(ULONG_PTR iface)
+{
+    PullPin *This = (PullPin *)iface;
+
+    TRACE("(%p/%p)->()\n", This, (LPVOID)iface);
+
+    EnterCriticalSection(This->pin.pCritSec);
+    {
+        This->state = State_Paused;
+        SetEvent(This->hEventStateChanged);
+    }
+    LeaveCriticalSection(This->pin.pCritSec);
+}
+
+
 static void CALLBACK PullPin_Thread_Stop(ULONG_PTR iface)
 {
     PullPin *This = (PullPin *)iface;
@@ -1413,11 +1434,12 @@ static void CALLBACK PullPin_Thread_Stop(ULONG_PTR iface)
         This->hThread = NULL;
         if (FAILED(hr = IMemAllocator_Decommit(This->pAlloc)))
             ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr);
+
+        SetEvent(This->hEventStateChanged);
+        This->state = State_Stopped;
     }
     LeaveCriticalSection(This->pin.pCritSec);
 
-    SetEvent(This->hEventStateChanged);
-
     IBaseFilter_Release(This->pin.pinInfo.pFilter);
 
     ExitThread(0);
@@ -1429,16 +1451,16 @@ HRESULT PullPin_InitProcessing(PullPin * This)
 
     TRACE("(%p)->()\n", This);
 
-    assert(!This->hThread);
-
     /* if we are connected */
     if (This->pAlloc)
     {
+        WaitForSingleObject(This->hEventStateChanged, INFINITE);
         EnterCriticalSection(This->pin.pCritSec);
+        if (This->state == State_Stopped)
         {
             DWORD dwThreadId;
             assert(!This->hThread);
-        
+
             /* AddRef the filter to make sure it and it's pins will be around
              * as long as the thread */
             IBaseFilter_AddRef(This->pin.pinInfo.pFilter);
@@ -1451,8 +1473,13 @@ HRESULT PullPin_InitProcessing(PullPin * This)
             }
 
             if (SUCCEEDED(hr))
+            {
                 hr = IMemAllocator_Commit(This->pAlloc);
+                This->state = State_Paused;
+                SetEvent(This->hEventStateChanged);
+            }
         }
+        else assert(This->hThread);
         LeaveCriticalSection(This->pin.pCritSec);
     }
 
@@ -1468,8 +1495,10 @@ HRESULT PullPin_StartProcessing(PullPin * This)
     if(This->pAlloc)
     {
         assert(This->hThread);
-        
+
+        PullPin_WaitForStateChange(This, INFINITE);
         ResetEvent(This->hEventStateChanged);
+        This->stop_playback = 0;
 
         if (!QueueUserAPC(PullPin_Thread_Process, This->hThread, (ULONG_PTR)This))
             return HRESULT_FROM_WIN32(GetLastError());
@@ -1480,8 +1509,21 @@ HRESULT PullPin_StartProcessing(PullPin * This)
 
 HRESULT PullPin_PauseProcessing(PullPin * This)
 {
-    /* make the processing function exit its loop */
-    This->rtStop = 0;
+    /* if we are connected */
+    TRACE("(%p)->()\n", This);
+    if(This->pAlloc)
+    {
+        assert(This->hThread);
+
+        PullPin_WaitForStateChange(This, INFINITE);
+        EnterCriticalSection(This->pin.pCritSec);
+        This->stop_playback = 0;
+        LeaveCriticalSection(This->pin.pCritSec);
+        ResetEvent(This->hEventStateChanged);
+
+        if (!QueueUserAPC(PullPin_Thread_Pause, This->hThread, (ULONG_PTR)This))
+            return HRESULT_FROM_WIN32(GetLastError());
+    }
 
     return S_OK;
 }
@@ -1489,14 +1531,13 @@ HRESULT PullPin_PauseProcessing(PullPin * This)
 HRESULT PullPin_StopProcessing(PullPin * This)
 {
     /* if we are connected */
-    if (This->pAlloc)
+    if (This->pAlloc && This->hThread)
     {
-        assert(This->hThread);
+        PullPin_WaitForStateChange(This, INFINITE);
 
+        This->stop_playback = 0;
         ResetEvent(This->hEventStateChanged);
 
-        PullPin_PauseProcessing(This);
-
         if (!QueueUserAPC(PullPin_Thread_Stop, This->hThread, (ULONG_PTR)This))
             return HRESULT_FROM_WIN32(GetLastError());
     }
@@ -1511,19 +1552,6 @@ HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds)
     return S_OK;
 }
 
-HRESULT PullPin_Seek(PullPin * This, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop)
-{
-    FIXME("(%p)->(%x%08x, %x%08x)\n", This, (LONG)(rtStart >> 32), (LONG)rtStart, (LONG)(rtStop >> 32), (LONG)rtStop);
-
-    PullPin_BeginFlush((IPin *)This);
-    /* FIXME: need critical section? */
-    This->rtStart = rtStart;
-    This->rtStop = rtStop;
-    PullPin_EndFlush((IPin *)This);
-
-    return S_OK;
-}
-
 HRESULT WINAPI PullPin_EndOfStream(IPin * iface)
 {
     FIXME("(%p)->() stub\n", iface);
@@ -1533,23 +1561,37 @@ HRESULT WINAPI PullPin_EndOfStream(IPin * iface)
 
 HRESULT WINAPI PullPin_BeginFlush(IPin * iface)
 {
+    PullPin *This = (PullPin *)iface;
     FIXME("(%p)->() stub\n", iface);
 
-    return SendFurther( iface, deliver_beginflush, NULL, NULL );
+    SendFurther( iface, deliver_beginflush, NULL, NULL );
+
+    if (This->state == State_Running)
+        return PullPin_PauseProcessing(This);
+    return S_OK;
 }
 
 HRESULT WINAPI PullPin_EndFlush(IPin * iface)
 {
+    FILTER_STATE state;
+    PullPin *This = (PullPin *)iface;
+
     FIXME("(%p)->() stub\n", iface);
+    SendFurther( iface, deliver_endflush, NULL, NULL );
 
-    return SendFurther( iface, deliver_endflush, NULL, NULL );
+    return IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state);
 }
 
 HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
 {
+    newsegmentargs args;
     FIXME("(%p)->(%s, %s, %g) stub\n", iface, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate);
 
-    return SendFurther( iface, deliver_newsegment, NULL, NULL );
+    args.tStart = tStart;
+    args.tStop = tStop;
+    args.rate = dRate;
+
+    return SendFurther( iface, deliver_newsegment, &args, NULL );
 }
 
 static const IPinVtbl PullPin_Vtbl = 
index 29b5a327a55016159d256a2ae8dcf3acd8c84a60..44400e63cc0cff71220409fbaebdcd4e4984341c 100644 (file)
@@ -85,6 +85,9 @@ typedef struct PullPin
        REFERENCE_TIME rtStart;
        REFERENCE_TIME rtStop;
        REFERENCE_TIME rtCurrent;
+       FILTER_STATE state;
+       BOOL stop_playback;
+       double dRate;
 } PullPin;
 
 /*** Initializers ***/
@@ -161,7 +164,6 @@ HRESULT PullPin_InitProcessing(PullPin * This);
 HRESULT PullPin_StartProcessing(PullPin * This);
 HRESULT PullPin_StopProcessing(PullPin * This);
 HRESULT PullPin_PauseProcessing(PullPin * This);
-HRESULT PullPin_Seek(PullPin * This, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop);
 HRESULT WINAPI PullPin_EndOfStream(IPin * iface);
 HRESULT WINAPI PullPin_BeginFlush(IPin * iface);
 HRESULT WINAPI PullPin_EndFlush(IPin * iface);
index efe12fce41c495e6f02c1900a66461f32774497d..e1a6ef2201013d26b9a1fe1707ac0d92c25e0ee2 100644 (file)
@@ -58,6 +58,17 @@ static void rungraph(void)
     hr = IMediaControl_Run(pmc);
     ok(hr==S_FALSE, "Cannot run the graph returned: %x\n", hr);
 
+    Sleep(100);
+    /* Crash fun */
+    hr = IMediaControl_Stop(pmc);
+    ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
+    hr = IMediaControl_Run(pmc);
+    ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
+    hr = IMediaControl_Pause(pmc);
+    ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
+    hr = IMediaControl_Run(pmc);
+    ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
+
     hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaEvent, (LPVOID*)&pme);
     ok(hr==S_OK, "Cannot get IMediaEvent interface returned: %x\n", hr);