From b37a28ad9f177dda03408ba47156cdb584b5d2fc Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Fri, 4 Jul 2008 18:43:05 -0700 Subject: [PATCH] quartz: Fix parser/pullpin to only have a state transition between stopped and started --- dlls/quartz/parser.c | 36 +++++++++++++++----- dlls/quartz/pin.c | 88 ++++++++++++++++++++++++++++++++++++------------- dlls/quartz/pin.h | 3 +- 3 files changed, 93 insertions(+), 34 deletions(-) diff --git a/dlls/quartz/parser.c b/dlls/quartz/parser.c index 97be991..0848e84 100644 --- a/dlls/quartz/parser.c +++ b/dlls/quartz/parser.c @@ -219,15 +219,35 @@ HRESULT WINAPI Parser_Stop(IBaseFilter * iface) { ParserImpl *This = (ParserImpl *)iface; PullPin *pin = (PullPin *)This->ppPins[0]; + int i; TRACE("()\n"); EnterCriticalSection(&pin->thread_lock); + + IAsyncReader_BeginFlush(This->pInputPin->pReader); EnterCriticalSection(&This->csFilter); + + if (This->state == State_Stopped) { - This->state = State_Stopped; + LeaveCriticalSection(&This->csFilter); + LeaveCriticalSection(&pin->thread_lock); + return S_OK; } + + This->state = State_Stopped; + + for (i = 1; i < (This->cStreams + 1); i++) + { + OutputPin_DecommitAllocator((OutputPin *)This->ppPins[i]); + } + LeaveCriticalSection(&This->csFilter); + + PullPin_PauseProcessing(This->pInputPin); + PullPin_WaitForStateChange(This->pInputPin, INFINITE); + IAsyncReader_EndFlush(This->pInputPin->pReader); + LeaveCriticalSection(&pin->thread_lock); return S_OK; } @@ -260,8 +280,6 @@ HRESULT WINAPI Parser_Pause(IBaseFilter * iface) This->state = State_Paused; LeaveCriticalSection(&This->csFilter); - if (SUCCEEDED(hr)) - hr = PullPin_PauseProcessing(This->pInputPin); LeaveCriticalSection(&pin->thread_lock); return hr; @@ -280,8 +298,9 @@ HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart) EnterCriticalSection(&pin->thread_lock); EnterCriticalSection(&This->csFilter); { - if (This->state == State_Running) + if (This->state == State_Running || This->state == State_Paused) { + This->state = State_Running; LeaveCriticalSection(&This->csFilter); LeaveCriticalSection(&pin->thread_lock); return S_OK; @@ -289,12 +308,11 @@ HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart) This->rtStreamStart = tStart; - if (SUCCEEDED(hr) && (This->state == State_Stopped)) + for (i = 1; i < (This->cStreams + 1); i++) { - for (i = 1; i < (This->cStreams + 1); i++) - { - OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]); - } + hr = OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]); + if (FAILED(hr)) + break; } if (SUCCEEDED(hr)) diff --git a/dlls/quartz/pin.c b/dlls/quartz/pin.c index 5bce9bb..0ecf055 100644 --- a/dlls/quartz/pin.c +++ b/dlls/quartz/pin.c @@ -1175,6 +1175,35 @@ HRESULT OutputPin_CommitAllocator(OutputPin * This) return hr; } +HRESULT OutputPin_DecommitAllocator(OutputPin * This) +{ + HRESULT hr = S_OK; + + TRACE("(%p)->()\n", This); + + EnterCriticalSection(This->pin.pCritSec); + { + if (!This->pin.pConnectedTo || !This->pMemInputPin) + hr = VFW_E_NOT_CONNECTED; + else + { + IMemAllocator * pAlloc = NULL; + + hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); + + if (SUCCEEDED(hr)) + hr = IMemAllocator_Decommit(pAlloc); + + if (pAlloc) + IMemAllocator_Release(pAlloc); + } + } + LeaveCriticalSection(This->pin.pCritSec); + + TRACE("--> %08x\n", hr); + return hr; +} + HRESULT OutputPin_DeliverDisconnect(OutputPin * This) { HRESULT hr; @@ -1416,11 +1445,11 @@ static void CALLBACK PullPin_Flush(PullPin *This) IMediaSample *pSample; TRACE("Flushing!\n"); - EnterCriticalSection(This->pin.pCritSec); if (This->pReader) { /* Flush outstanding samples */ IAsyncReader_BeginFlush(This->pReader); + for (;;) { DWORD_PTR dwUser; @@ -1437,10 +1466,9 @@ static void CALLBACK PullPin_Flush(PullPin *This) IAsyncReader_EndFlush(This->pReader); } - LeaveCriticalSection(This->pin.pCritSec); } -static void CALLBACK PullPin_Thread_Process(PullPin *This, BOOL pause) +static void CALLBACK PullPin_Thread_Process(PullPin *This) { HRESULT hr; IMediaSample * pSample = NULL; @@ -1467,12 +1495,9 @@ static void CALLBACK PullPin_Thread_Process(PullPin *This, BOOL pause) if (FAILED(hr)) ERR("Request error: %x\n", hr); - if (!pause) - { - EnterCriticalSection(This->pin.pCritSec); - SetEvent(This->hEventStateChanged); - LeaveCriticalSection(This->pin.pCritSec); - } + EnterCriticalSection(This->pin.pCritSec); + SetEvent(This->hEventStateChanged); + LeaveCriticalSection(This->pin.pCritSec); if (SUCCEEDED(hr)) do @@ -1510,23 +1535,20 @@ static void CALLBACK PullPin_Thread_Process(PullPin *This, BOOL pause) /* Can't reset state to Sleepy here because that might race, instead PauseProcessing will do that for us * Flush remaining samples */ - TRACE("Almost done..\n"); - if (This->fnDone) This->fnDone(This->pin.pUserData); - if (pause) - { - EnterCriticalSection(This->pin.pCritSec); - This->state = Req_Sleepy; - SetEvent(This->hEventStateChanged); - LeaveCriticalSection(This->pin.pCritSec); - } - - TRACE("End: %08x, %d\n", hr, This->stop_playback); } +static void CALLBACK PullPin_Thread_Pause(PullPin *This) +{ + EnterCriticalSection(This->pin.pCritSec); + This->state = Req_Sleepy; + SetEvent(This->hEventStateChanged); + LeaveCriticalSection(This->pin.pCritSec); +} + static void CALLBACK PullPin_Thread_Stop(PullPin *This) { TRACE("(%p)->()\n", This); @@ -1545,6 +1567,16 @@ static void CALLBACK PullPin_Thread_Stop(PullPin *This) ExitThread(0); } +static void CALLBACK PullPin_Thread_Flush(PullPin *This) +{ + PullPin_Flush(This); + + EnterCriticalSection(This->pin.pCritSec); + This->state = Req_Sleepy; + SetEvent(This->hEventStateChanged); + LeaveCriticalSection(This->pin.pCritSec); +} + static DWORD WINAPI PullPin_Thread_Main(LPVOID pv) { PullPin *This = pv; @@ -1561,8 +1593,9 @@ static DWORD WINAPI PullPin_Thread_Main(LPVOID pv) switch (This->state) { case Req_Die: PullPin_Thread_Stop(This); break; - case Req_Run: PullPin_Thread_Process(This, FALSE); break; - case Req_Pause: PullPin_Thread_Process(This, TRUE); break; + case Req_Run: PullPin_Thread_Process(This); break; + case Req_Pause: PullPin_Thread_Pause(This); break; + case Req_Flush: PullPin_Thread_Flush(This); break; case Req_Sleepy: ERR("Should not be signalled with SLEEPY!\n"); break; default: ERR("Unknown state request: %d\n", This->state); break; } @@ -1710,13 +1743,20 @@ HRESULT WINAPI PullPin_BeginFlush(IPin * iface) EnterCriticalSection(&This->thread_lock); { + if (This->pReader) + IAsyncReader_BeginFlush(This->pReader); PullPin_WaitForStateChange(This, INFINITE); - if (This->hThread && !This->stop_playback) + if (This->hThread && This->state == Req_Run) { PullPin_PauseProcessing(This); PullPin_WaitForStateChange(This, INFINITE); } + + This->state = Req_Flush; + ResetEvent(This->hEventStateChanged); + SetEvent(This->thread_sleepy); + PullPin_WaitForStateChange(This, INFINITE); } LeaveCriticalSection(&This->thread_lock); @@ -1740,7 +1780,7 @@ HRESULT WINAPI PullPin_EndFlush(IPin * iface) FILTER_STATE state; IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state); - if (This->stop_playback && state == State_Running) + if (This->stop_playback && state != State_Stopped) PullPin_StartProcessing(This); PullPin_WaitForStateChange(This, INFINITE); diff --git a/dlls/quartz/pin.h b/dlls/quartz/pin.h index b67ff1b..4170ca5 100644 --- a/dlls/quartz/pin.h +++ b/dlls/quartz/pin.h @@ -52,7 +52,6 @@ typedef HRESULT (* CLEANUPPROC) (LPVOID userdata); * If you implement it (it can be NULL for default behavior), you have to * call IMemAllocator_GetBuffer and IMemAllocator_RequestBuffer * This is useful if you want to request more than 1 buffer at simultaneously - * If PullPin->flushed is set, it means that all buffers queued previously are gone * * This will also cause the Sample Proc to be called with empty buffers to indicate * failure in retrieving the sample. @@ -141,6 +140,7 @@ typedef struct PullPin #define Req_Die 1 #define Req_Run 2 #define Req_Pause 3 +#define Req_Flush 4 /*** Constructors ***/ HRESULT InputPin_Construct(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *, IPin ** ppPin); @@ -184,6 +184,7 @@ HRESULT WINAPI OutputPin_EndFlush(IPin * iface); HRESULT WINAPI OutputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); HRESULT OutputPin_CommitAllocator(OutputPin * This); +HRESULT OutputPin_DecommitAllocator(OutputPin * This); HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags); HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample); HRESULT OutputPin_DeliverDisconnect(OutputPin * This); -- 1.5.4.1