From 2638ef5d199f3a9828f4a7946327c91e74a784ed Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Fri, 4 Apr 2008 16:27:29 -0700 Subject: [PATCH] quartz: Handle flushing and end of stream notifications for input pins --- dlls/quartz/dsoundrender.c | 96 +++++++++++++++++++++++++++---------------- dlls/quartz/nullrenderer.c | 3 + dlls/quartz/pin.c | 48 ++++++++++++++++----- dlls/quartz/pin.h | 1 + dlls/quartz/transform.c | 6 +++ dlls/quartz/videorenderer.c | 6 +++ 6 files changed, 112 insertions(+), 48 deletions(-) diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index 7a2d461..0cfd163 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -96,14 +96,39 @@ static HRESULT sound_mod_rate(IBaseFilter *iface) return S_OK; } -static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, DWORD *pWritePos, REFERENCE_TIME *pRefTime) +static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, REFERENCE_TIME *pRefTime) { HRESULT hr; EnterCriticalSection(&This->csFilter); { - hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, pWritePos); - if (hr == DS_OK) + DWORD state; + + hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state); + if (SUCCEEDED(hr) && !(state & DSBSTATUS_PLAYING) && This->state == State_Running) + { + LPBYTE buf; + DWORD size; + TRACE("Not playing, kickstarting the engine\n"); + This->write_pos = 0; + IDirectSoundBuffer_SetCurrentPosition(This->dsbuffer, 0); + + hr = IDirectSoundBuffer_Lock(This->dsbuffer, 0, 0, (void**)&buf, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER); + if (hr != DS_OK) + ERR("Unable to lock sound buffer! (%x)\n", hr); + else + memset(buf, 0, size); + hr = IDirectSoundBuffer_Unlock(This->dsbuffer, buf, size, NULL, 0); + + hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING); + if (FAILED(hr)) + ERR("Can't play sound buffer (%x)\n", hr); + hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, &This->last_play_pos, &This->write_pos); + *pPlayPos = This->last_play_pos; + } + else if (SUCCEEDED(hr)) + hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, NULL); + if (hr == S_OK) { DWORD play_pos = *pPlayPos; @@ -139,7 +164,7 @@ static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPo static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *data, DWORD size) { - HRESULT hr; + HRESULT hr = S_OK; LPBYTE lpbuf1 = NULL; LPBYTE lpbuf2 = NULL; DWORD dwsize1 = 0; @@ -147,8 +172,9 @@ static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *d DWORD size2; DWORD play_pos,buf_free; - do { - hr = DSoundRender_GetPos(This, &play_pos, NULL, NULL); + while (size && This->state == State_Running && !This->pInputPin->flushing) { + + hr = DSoundRender_GetPos(This, &play_pos, NULL); if (hr != DS_OK) { ERR("GetPos returned error: %x\n", hr); @@ -190,7 +216,7 @@ static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *d This->write_pos -= This->buf_size; This->write_loops++; } - } while (size && This->state == State_Running); + } return hr; } @@ -205,9 +231,9 @@ static HRESULT DSoundRender_Sample(LPVOID iface, IMediaSample * pSample) TRACE("%p %p\n", iface, pSample); - if (This->state != State_Running) + if (This->state == State_Stopped) return VFW_E_WRONG_STATE; - + hr = IMediaSample_GetPointer(pSample, &pbSrcStream); if (FAILED(hr)) { @@ -463,6 +489,9 @@ static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface) EnterCriticalSection(&This->csFilter); { DWORD state = 0; + if (This->state == State_Stopped) + This->pInputPin->end_of_stream = 0; + if (This->dsbuffer) { hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state); @@ -489,27 +518,9 @@ static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStar EnterCriticalSection(&This->csFilter); { - /* It's okay if there's no buffer yet. It'll start when it's created */ - if (This->dsbuffer) - { - if (This->state == State_Stopped) - { - char *buf1; - DWORD size1; - - IDirectSoundBuffer_Lock(This->dsbuffer, 0, 0, (void**)&buf1, &size1, NULL, NULL, DSBLOCK_ENTIREBUFFER); - memset(buf1, 0, size1); - IDirectSoundBuffer_Unlock(This->dsbuffer, buf1, size1, NULL, 0); - } - hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING); - if (FAILED(hr)) - ERR("Can't start playing! (%x)\n", hr); - } - if (SUCCEEDED(hr)) - { - This->rtStreamStart = tStart; - This->state = State_Running; - } + This->rtStreamStart = tStart; + This->state = State_Running; + This->pInputPin->end_of_stream = 0; } LeaveCriticalSection(&This->csFilter); @@ -722,10 +733,6 @@ static HRESULT WINAPI DSoundRender_InputPin_ReceiveConnection(IPin * iface, IPin DSImpl->write_pos = 0; hr = S_OK; - if (DSImpl->state == State_Running) - hr = IDirectSoundBuffer_Play(DSImpl->dsbuffer, 0, 0, DSBPLAY_LOOPING); - if (FAILED(hr)) - ERR("Can't play sound buffer (%x)\n", hr); } if (SUCCEEDED(hr)) @@ -791,6 +798,23 @@ static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface) return hr; } +static HRESULT WINAPI DSoundRender_InputPin_BeginFlush(IPin * iface) +{ + InputPin *This = (InputPin *)iface; + DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter; + HRESULT hr; + + hr = InputPin_BeginFlush(iface); + + FIXME("Requested flush\n"); + EnterCriticalSection(This->pin.pCritSec); + if (pFilter->dsbuffer) + IDirectSoundBuffer_Stop(pFilter->dsbuffer); + LeaveCriticalSection(This->pin.pCritSec); + + return hr; +} + static const IPinVtbl DSoundRender_InputPin_Vtbl = { InputPin_QueryInterface, @@ -808,7 +832,7 @@ static const IPinVtbl DSoundRender_InputPin_Vtbl = IPinImpl_EnumMediaTypes, IPinImpl_QueryInternalConnections, DSoundRender_InputPin_EndOfStream, - InputPin_BeginFlush, + DSoundRender_InputPin_BeginFlush, InputPin_EndFlush, InputPin_NewSegment }; @@ -1023,7 +1047,7 @@ static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface, TRACE("(%p/%p)->(%p)\n", This, iface, pTime); if (This->dsbuffer) - hr = DSoundRender_GetPos(This, &play_pos, NULL, pTime); + hr = DSoundRender_GetPos(This, &play_pos, pTime); if (FAILED(hr)) ERR("Could not get reference time (%x)!\n", hr); diff --git a/dlls/quartz/nullrenderer.c b/dlls/quartz/nullrenderer.c index 131ea7e..191771b 100644 --- a/dlls/quartz/nullrenderer.c +++ b/dlls/quartz/nullrenderer.c @@ -394,6 +394,8 @@ static HRESULT WINAPI NullRenderer_Pause(IBaseFilter * iface) EnterCriticalSection(&This->csFilter); { + if (This->state == State_Stopped) + This->pInputPin->end_of_stream = 0; This->state = State_Paused; } LeaveCriticalSection(&This->csFilter); @@ -411,6 +413,7 @@ static HRESULT WINAPI NullRenderer_Run(IBaseFilter * iface, REFERENCE_TIME tStar { This->rtStreamStart = tStart; This->state = State_Running; + This->pInputPin->end_of_stream = 0; } LeaveCriticalSection(&This->csFilter); diff --git a/dlls/quartz/pin.c b/dlls/quartz/pin.c index d88b762..f762eb8 100644 --- a/dlls/quartz/pin.c +++ b/dlls/quartz/pin.c @@ -248,6 +248,7 @@ static HRESULT InputPin_Init(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPi pPinImpl->dRate = 0; pPinImpl->pin.lpVtbl = InputPin_Vtbl; pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl; + pPinImpl->flushing = pPinImpl->end_of_stream = 0; return S_OK; } @@ -598,12 +599,10 @@ static HRESULT deliver_endofstream(IPin* pin, LPVOID unused) HRESULT WINAPI InputPin_EndOfStream(IPin * iface) { - FIXME("() stub\n"); + InputPin *This = (InputPin *)iface; + TRACE("(%p)\n", This); - /* Should do an end of stream notification? - * Also, don't accept any more samples from now! - * TODO: Don't accept any more packets - */ + This->end_of_stream = 1; return SendFurther( iface, deliver_endofstream, NULL, NULL ); } @@ -615,10 +614,21 @@ static HRESULT deliver_beginflush(IPin* pin, LPVOID unused) HRESULT WINAPI InputPin_BeginFlush(IPin * iface) { - FIXME("() stub\n"); + InputPin *This = (InputPin *)iface; + HRESULT hr; + TRACE("() semi-stub\n"); + + /* Assign this outside the critical section so that _Receive loops can be broken */ + This->flushing = 1; + + EnterCriticalSection(This->pin.pCritSec); - /* TODO: Drop all cached packets, and don't accept any more samples! */ - return SendFurther( iface, deliver_beginflush, NULL, NULL ); + if (This->fnCleanProc) + This->fnCleanProc(This->pin.pUserData); + + hr = SendFurther( iface, deliver_beginflush, NULL, NULL ); + LeaveCriticalSection(This->pin.pCritSec); + return hr; } static HRESULT deliver_endflush(IPin* pin, LPVOID unused) @@ -628,10 +638,17 @@ static HRESULT deliver_endflush(IPin* pin, LPVOID unused) HRESULT WINAPI InputPin_EndFlush(IPin * iface) { - FIXME("() stub\n"); + InputPin *This = (InputPin *)iface; + HRESULT hr; + TRACE("(%p)\n", This); - /* TODO: Accept any samples again */ - return SendFurther( iface, deliver_endflush, NULL, NULL ); + EnterCriticalSection(This->pin.pCritSec); + This->flushing = 0; + + hr = SendFurther( iface, deliver_endflush, NULL, NULL ); + LeaveCriticalSection(This->pin.pCritSec); + + return hr; } typedef struct newsegmentargs @@ -747,11 +764,18 @@ HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin * iface, ALLOCA HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample) { InputPin *This = impl_from_IMemInputPin(iface); + HRESULT hr; /* this trace commented out for performance reasons */ /*TRACE("(%p/%p)->(%p)\n", This, iface, pSample);*/ - return This->fnSampleProc(This->pin.pUserData, pSample); + EnterCriticalSection(This->pin.pCritSec); + if (!This->end_of_stream && !This->flushing && !This->end_of_stream) + hr = This->fnSampleProc(This->pin.pUserData, pSample); + else + hr = S_FALSE; + LeaveCriticalSection(This->pin.pCritSec); + return hr; } HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, long nSamples, long *nSamplesProcessed) diff --git a/dlls/quartz/pin.h b/dlls/quartz/pin.h index 0991963..f97a33d 100644 --- a/dlls/quartz/pin.h +++ b/dlls/quartz/pin.h @@ -67,6 +67,7 @@ typedef struct InputPin REFERENCE_TIME tStart; REFERENCE_TIME tStop; double dRate; + BOOL flushing, end_of_stream; } InputPin; typedef struct OutputPin diff --git a/dlls/quartz/transform.c b/dlls/quartz/transform.c index 5928ba3..85962d1 100644 --- a/dlls/quartz/transform.c +++ b/dlls/quartz/transform.c @@ -341,6 +341,9 @@ static HRESULT WINAPI TransformFilter_Pause(IBaseFilter * iface) EnterCriticalSection(&This->csFilter); { + if (This->state == State_Stopped) + ((InputPin *)This->ppPins[0])->end_of_stream = 0; + This->state = State_Paused; } LeaveCriticalSection(&This->csFilter); @@ -357,6 +360,9 @@ static HRESULT WINAPI TransformFilter_Run(IBaseFilter * iface, REFERENCE_TIME tS EnterCriticalSection(&This->csFilter); { + if (This->state == State_Stopped) + ((InputPin *)This->ppPins[0])->end_of_stream = 0; + This->rtStreamStart = tStart; This->state = State_Running; OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]); diff --git a/dlls/quartz/videorenderer.c b/dlls/quartz/videorenderer.c index b331211..f363b82 100644 --- a/dlls/quartz/videorenderer.c +++ b/dlls/quartz/videorenderer.c @@ -645,6 +645,9 @@ static HRESULT WINAPI VideoRenderer_Pause(IBaseFilter * iface) EnterCriticalSection(&This->csFilter); { + if (This->state == State_Stopped) + This->pInputPin->end_of_stream = 0; + This->state = State_Paused; } LeaveCriticalSection(&This->csFilter); @@ -660,6 +663,9 @@ static HRESULT WINAPI VideoRenderer_Run(IBaseFilter * iface, REFERENCE_TIME tSta EnterCriticalSection(&This->csFilter); { + if (This->state == State_Stopped) + This->pInputPin->end_of_stream = 0; + This->rtStreamStart = tStart; This->state = State_Running; } -- 1.5.4.1