quartz: Handle flushing and end of stream notifications for input pins.
This commit is contained in:
parent
ee792916e0
commit
01c6e64da6
|
@ -96,14 +96,39 @@ static HRESULT sound_mod_rate(IBaseFilter *iface)
|
||||||
return S_OK;
|
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;
|
HRESULT hr;
|
||||||
|
|
||||||
EnterCriticalSection(&This->csFilter);
|
EnterCriticalSection(&This->csFilter);
|
||||||
{
|
{
|
||||||
hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, pWritePos);
|
DWORD state;
|
||||||
if (hr == DS_OK)
|
|
||||||
|
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;
|
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)
|
static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *data, DWORD size)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr = S_OK;
|
||||||
LPBYTE lpbuf1 = NULL;
|
LPBYTE lpbuf1 = NULL;
|
||||||
LPBYTE lpbuf2 = NULL;
|
LPBYTE lpbuf2 = NULL;
|
||||||
DWORD dwsize1 = 0;
|
DWORD dwsize1 = 0;
|
||||||
|
@ -147,8 +172,9 @@ static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *d
|
||||||
DWORD size2;
|
DWORD size2;
|
||||||
DWORD play_pos,buf_free;
|
DWORD play_pos,buf_free;
|
||||||
|
|
||||||
do {
|
while (size && This->state == State_Running && !This->pInputPin->flushing) {
|
||||||
hr = DSoundRender_GetPos(This, &play_pos, NULL, NULL);
|
|
||||||
|
hr = DSoundRender_GetPos(This, &play_pos, NULL);
|
||||||
if (hr != DS_OK)
|
if (hr != DS_OK)
|
||||||
{
|
{
|
||||||
ERR("GetPos returned error: %x\n", hr);
|
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_pos -= This->buf_size;
|
||||||
This->write_loops++;
|
This->write_loops++;
|
||||||
}
|
}
|
||||||
} while (size && This->state == State_Running);
|
}
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
@ -205,9 +231,9 @@ static HRESULT DSoundRender_Sample(LPVOID iface, IMediaSample * pSample)
|
||||||
|
|
||||||
TRACE("%p %p\n", iface, pSample);
|
TRACE("%p %p\n", iface, pSample);
|
||||||
|
|
||||||
if (This->state != State_Running)
|
if (This->state == State_Stopped)
|
||||||
return VFW_E_WRONG_STATE;
|
return VFW_E_WRONG_STATE;
|
||||||
|
|
||||||
hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
|
hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
|
@ -463,6 +489,9 @@ static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface)
|
||||||
EnterCriticalSection(&This->csFilter);
|
EnterCriticalSection(&This->csFilter);
|
||||||
{
|
{
|
||||||
DWORD state = 0;
|
DWORD state = 0;
|
||||||
|
if (This->state == State_Stopped)
|
||||||
|
This->pInputPin->end_of_stream = 0;
|
||||||
|
|
||||||
if (This->dsbuffer)
|
if (This->dsbuffer)
|
||||||
{
|
{
|
||||||
hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
|
hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
|
||||||
|
@ -489,27 +518,9 @@ static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStar
|
||||||
|
|
||||||
EnterCriticalSection(&This->csFilter);
|
EnterCriticalSection(&This->csFilter);
|
||||||
{
|
{
|
||||||
/* It's okay if there's no buffer yet. It'll start when it's created */
|
This->rtStreamStart = tStart;
|
||||||
if (This->dsbuffer)
|
This->state = State_Running;
|
||||||
{
|
This->pInputPin->end_of_stream = 0;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
LeaveCriticalSection(&This->csFilter);
|
LeaveCriticalSection(&This->csFilter);
|
||||||
|
|
||||||
|
@ -722,10 +733,6 @@ static HRESULT WINAPI DSoundRender_InputPin_ReceiveConnection(IPin * iface, IPin
|
||||||
|
|
||||||
DSImpl->write_pos = 0;
|
DSImpl->write_pos = 0;
|
||||||
hr = S_OK;
|
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))
|
if (SUCCEEDED(hr))
|
||||||
|
@ -791,6 +798,23 @@ static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface)
|
||||||
return hr;
|
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 =
|
static const IPinVtbl DSoundRender_InputPin_Vtbl =
|
||||||
{
|
{
|
||||||
InputPin_QueryInterface,
|
InputPin_QueryInterface,
|
||||||
|
@ -808,7 +832,7 @@ static const IPinVtbl DSoundRender_InputPin_Vtbl =
|
||||||
IPinImpl_EnumMediaTypes,
|
IPinImpl_EnumMediaTypes,
|
||||||
IPinImpl_QueryInternalConnections,
|
IPinImpl_QueryInternalConnections,
|
||||||
DSoundRender_InputPin_EndOfStream,
|
DSoundRender_InputPin_EndOfStream,
|
||||||
InputPin_BeginFlush,
|
DSoundRender_InputPin_BeginFlush,
|
||||||
InputPin_EndFlush,
|
InputPin_EndFlush,
|
||||||
InputPin_NewSegment
|
InputPin_NewSegment
|
||||||
};
|
};
|
||||||
|
@ -1023,7 +1047,7 @@ static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface,
|
||||||
TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
|
TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
|
||||||
|
|
||||||
if (This->dsbuffer)
|
if (This->dsbuffer)
|
||||||
hr = DSoundRender_GetPos(This, &play_pos, NULL, pTime);
|
hr = DSoundRender_GetPos(This, &play_pos, pTime);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
ERR("Could not get reference time (%x)!\n", hr);
|
ERR("Could not get reference time (%x)!\n", hr);
|
||||||
|
|
||||||
|
|
|
@ -394,6 +394,8 @@ static HRESULT WINAPI NullRenderer_Pause(IBaseFilter * iface)
|
||||||
|
|
||||||
EnterCriticalSection(&This->csFilter);
|
EnterCriticalSection(&This->csFilter);
|
||||||
{
|
{
|
||||||
|
if (This->state == State_Stopped)
|
||||||
|
This->pInputPin->end_of_stream = 0;
|
||||||
This->state = State_Paused;
|
This->state = State_Paused;
|
||||||
}
|
}
|
||||||
LeaveCriticalSection(&This->csFilter);
|
LeaveCriticalSection(&This->csFilter);
|
||||||
|
@ -411,6 +413,7 @@ static HRESULT WINAPI NullRenderer_Run(IBaseFilter * iface, REFERENCE_TIME tStar
|
||||||
{
|
{
|
||||||
This->rtStreamStart = tStart;
|
This->rtStreamStart = tStart;
|
||||||
This->state = State_Running;
|
This->state = State_Running;
|
||||||
|
This->pInputPin->end_of_stream = 0;
|
||||||
}
|
}
|
||||||
LeaveCriticalSection(&This->csFilter);
|
LeaveCriticalSection(&This->csFilter);
|
||||||
|
|
||||||
|
|
|
@ -248,6 +248,7 @@ static HRESULT InputPin_Init(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPi
|
||||||
pPinImpl->dRate = 0;
|
pPinImpl->dRate = 0;
|
||||||
pPinImpl->pin.lpVtbl = InputPin_Vtbl;
|
pPinImpl->pin.lpVtbl = InputPin_Vtbl;
|
||||||
pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl;
|
pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl;
|
||||||
|
pPinImpl->flushing = pPinImpl->end_of_stream = 0;
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
@ -598,12 +599,10 @@ static HRESULT deliver_endofstream(IPin* pin, LPVOID unused)
|
||||||
|
|
||||||
HRESULT WINAPI InputPin_EndOfStream(IPin * iface)
|
HRESULT WINAPI InputPin_EndOfStream(IPin * iface)
|
||||||
{
|
{
|
||||||
FIXME("() stub\n");
|
InputPin *This = (InputPin *)iface;
|
||||||
|
TRACE("(%p)\n", This);
|
||||||
|
|
||||||
/* Should do an end of stream notification?
|
This->end_of_stream = 1;
|
||||||
* Also, don't accept any more samples from now!
|
|
||||||
* TODO: Don't accept any more packets
|
|
||||||
*/
|
|
||||||
|
|
||||||
return SendFurther( iface, deliver_endofstream, NULL, NULL );
|
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)
|
HRESULT WINAPI InputPin_BeginFlush(IPin * iface)
|
||||||
{
|
{
|
||||||
FIXME("() stub\n");
|
InputPin *This = (InputPin *)iface;
|
||||||
|
HRESULT hr;
|
||||||
|
TRACE("() semi-stub\n");
|
||||||
|
|
||||||
/* TODO: Drop all cached packets, and don't accept any more samples! */
|
/* Assign this outside the critical section so that _Receive loops can be broken */
|
||||||
return SendFurther( iface, deliver_beginflush, NULL, NULL );
|
This->flushing = 1;
|
||||||
|
|
||||||
|
EnterCriticalSection(This->pin.pCritSec);
|
||||||
|
|
||||||
|
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)
|
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)
|
HRESULT WINAPI InputPin_EndFlush(IPin * iface)
|
||||||
{
|
{
|
||||||
FIXME("() stub\n");
|
InputPin *This = (InputPin *)iface;
|
||||||
|
HRESULT hr;
|
||||||
|
TRACE("(%p)\n", This);
|
||||||
|
|
||||||
/* TODO: Accept any samples again */
|
EnterCriticalSection(This->pin.pCritSec);
|
||||||
return SendFurther( iface, deliver_endflush, NULL, NULL );
|
This->flushing = 0;
|
||||||
|
|
||||||
|
hr = SendFurther( iface, deliver_endflush, NULL, NULL );
|
||||||
|
LeaveCriticalSection(This->pin.pCritSec);
|
||||||
|
|
||||||
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct newsegmentargs
|
typedef struct newsegmentargs
|
||||||
|
@ -747,11 +764,18 @@ HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin * iface, ALLOCA
|
||||||
HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample)
|
HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample)
|
||||||
{
|
{
|
||||||
InputPin *This = impl_from_IMemInputPin(iface);
|
InputPin *This = impl_from_IMemInputPin(iface);
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
/* this trace commented out for performance reasons */
|
/* this trace commented out for performance reasons */
|
||||||
/*TRACE("(%p/%p)->(%p)\n", This, iface, pSample);*/
|
/*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)
|
HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, long nSamples, long *nSamplesProcessed)
|
||||||
|
|
|
@ -67,6 +67,7 @@ typedef struct InputPin
|
||||||
REFERENCE_TIME tStart;
|
REFERENCE_TIME tStart;
|
||||||
REFERENCE_TIME tStop;
|
REFERENCE_TIME tStop;
|
||||||
double dRate;
|
double dRate;
|
||||||
|
BOOL flushing, end_of_stream;
|
||||||
} InputPin;
|
} InputPin;
|
||||||
|
|
||||||
typedef struct OutputPin
|
typedef struct OutputPin
|
||||||
|
|
|
@ -341,6 +341,9 @@ static HRESULT WINAPI TransformFilter_Pause(IBaseFilter * iface)
|
||||||
|
|
||||||
EnterCriticalSection(&This->csFilter);
|
EnterCriticalSection(&This->csFilter);
|
||||||
{
|
{
|
||||||
|
if (This->state == State_Stopped)
|
||||||
|
((InputPin *)This->ppPins[0])->end_of_stream = 0;
|
||||||
|
|
||||||
This->state = State_Paused;
|
This->state = State_Paused;
|
||||||
}
|
}
|
||||||
LeaveCriticalSection(&This->csFilter);
|
LeaveCriticalSection(&This->csFilter);
|
||||||
|
@ -357,6 +360,9 @@ static HRESULT WINAPI TransformFilter_Run(IBaseFilter * iface, REFERENCE_TIME tS
|
||||||
|
|
||||||
EnterCriticalSection(&This->csFilter);
|
EnterCriticalSection(&This->csFilter);
|
||||||
{
|
{
|
||||||
|
if (This->state == State_Stopped)
|
||||||
|
((InputPin *)This->ppPins[0])->end_of_stream = 0;
|
||||||
|
|
||||||
This->rtStreamStart = tStart;
|
This->rtStreamStart = tStart;
|
||||||
This->state = State_Running;
|
This->state = State_Running;
|
||||||
OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]);
|
OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]);
|
||||||
|
|
|
@ -645,6 +645,9 @@ static HRESULT WINAPI VideoRenderer_Pause(IBaseFilter * iface)
|
||||||
|
|
||||||
EnterCriticalSection(&This->csFilter);
|
EnterCriticalSection(&This->csFilter);
|
||||||
{
|
{
|
||||||
|
if (This->state == State_Stopped)
|
||||||
|
This->pInputPin->end_of_stream = 0;
|
||||||
|
|
||||||
This->state = State_Paused;
|
This->state = State_Paused;
|
||||||
}
|
}
|
||||||
LeaveCriticalSection(&This->csFilter);
|
LeaveCriticalSection(&This->csFilter);
|
||||||
|
@ -660,6 +663,9 @@ static HRESULT WINAPI VideoRenderer_Run(IBaseFilter * iface, REFERENCE_TIME tSta
|
||||||
|
|
||||||
EnterCriticalSection(&This->csFilter);
|
EnterCriticalSection(&This->csFilter);
|
||||||
{
|
{
|
||||||
|
if (This->state == State_Stopped)
|
||||||
|
This->pInputPin->end_of_stream = 0;
|
||||||
|
|
||||||
This->rtStreamStart = tStart;
|
This->rtStreamStart = tStart;
|
||||||
This->state = State_Running;
|
This->state = State_Running;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue