From fbbc339cc1ade7505295da0a1bfb3eddb875dc63 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 1 Apr 2008 14:35:14 -0700 Subject: [PATCH] quartz: Fix parser and pins logic to no longer deadlock --- dlls/quartz/parser.c | 14 +++-- dlls/quartz/pin.c | 108 +++++++++++++++++++++++++++------------ dlls/quartz/pin.h | 4 +- dlls/quartz/tests/filtergraph.c | 11 ++++ 4 files changed, 97 insertions(+), 40 deletions(-) diff --git a/dlls/quartz/parser.c b/dlls/quartz/parser.c index b7bb270..b09b397 100644 --- a/dlls/quartz/parser.c +++ b/dlls/quartz/parser.c @@ -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; diff --git a/dlls/quartz/pin.c b/dlls/quartz/pin.c index e8d0f44..686669e 100644 --- a/dlls/quartz/pin.c +++ b/dlls/quartz/pin.c @@ -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 = diff --git a/dlls/quartz/pin.h b/dlls/quartz/pin.h index 29b5a32..44400e6 100644 --- a/dlls/quartz/pin.h +++ b/dlls/quartz/pin.h @@ -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); diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c index efe12fc..e1a6ef2 100644 --- a/dlls/quartz/tests/filtergraph.c +++ b/dlls/quartz/tests/filtergraph.c @@ -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); -- 1.5.4.1