quartz: Fix parser/pullpin to only care about the state transition stopped<->playing.

This commit is contained in:
Maarten Lankhorst 2008-07-04 18:43:05 -07:00 committed by Alexandre Julliard
parent e58855e0e9
commit 53782ca47a
3 changed files with 93 additions and 34 deletions

View File

@ -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))

View File

@ -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);

View File

@ -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);