quartz: Add a function that can be called when stopping processing data.

This commit is contained in:
Maarten Lankhorst 2008-04-25 14:59:05 -07:00 committed by Alexandre Julliard
parent ec87de35af
commit 512ee927cb
7 changed files with 64 additions and 29 deletions

View File

@ -1080,7 +1080,7 @@ HRESULT AVISplitter_create(IUnknown * pUnkOuter, LPVOID * ppv)
This->streams = NULL; This->streams = NULL;
This->oldindex = NULL; This->oldindex = NULL;
hr = Parser_Create(&(This->Parser), &AVISplitter_Vtbl, &CLSID_AviSplitter, AVISplitter_Sample, AVISplitter_QueryAccept, AVISplitter_InputPin_PreConnect, AVISplitter_Cleanup, AVISplitter_Disconnect, NULL, NULL, NULL, NULL); hr = Parser_Create(&(This->Parser), &AVISplitter_Vtbl, &CLSID_AviSplitter, AVISplitter_Sample, AVISplitter_QueryAccept, AVISplitter_InputPin_PreConnect, AVISplitter_Cleanup, AVISplitter_Disconnect, NULL, NULL, NULL, NULL, NULL);
if (FAILED(hr)) if (FAILED(hr))
return hr; return hr;

View File

@ -830,7 +830,7 @@ HRESULT MPEGSplitter_create(IUnknown * pUnkOuter, LPVOID * ppv)
} }
This->seek_entries = 64; This->seek_entries = 64;
hr = Parser_Create(&(This->Parser), &MPEGSplitter_Vtbl, &CLSID_MPEG1Splitter, MPEGSplitter_process_sample, MPEGSplitter_query_accept, MPEGSplitter_pre_connect, MPEGSplitter_cleanup, MPEGSplitter_disconnect, MPEGSplitter_first_request, NULL, MPEGSplitter_seek, NULL); hr = Parser_Create(&(This->Parser), &MPEGSplitter_Vtbl, &CLSID_MPEG1Splitter, MPEGSplitter_process_sample, MPEGSplitter_query_accept, MPEGSplitter_pre_connect, MPEGSplitter_cleanup, MPEGSplitter_disconnect, MPEGSplitter_first_request, NULL, NULL, MPEGSplitter_seek, NULL);
if (FAILED(hr)) if (FAILED(hr))
{ {
CoTaskMemFree(This); CoTaskMemFree(This);

View File

@ -52,7 +52,7 @@ static inline ParserImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
} }
HRESULT Parser_Create(ParserImpl* pParser, const IBaseFilterVtbl *Parser_Vtbl, const CLSID* pClsid, PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect, PFN_CLEANUP fnCleanup, PFN_DISCONNECT fnDisconnect, REQUESTPROC fnRequest, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate) HRESULT Parser_Create(ParserImpl* pParser, const IBaseFilterVtbl *Parser_Vtbl, const CLSID* pClsid, PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect, PFN_CLEANUP fnCleanup, PFN_DISCONNECT fnDisconnect, REQUESTPROC fnRequest, STOPPROCESSPROC fnDone, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate)
{ {
HRESULT hr; HRESULT hr;
PIN_INFO piInput; PIN_INFO piInput;
@ -67,8 +67,8 @@ HRESULT Parser_Create(ParserImpl* pParser, const IBaseFilterVtbl *Parser_Vtbl, c
pParser->pClock = NULL; pParser->pClock = NULL;
pParser->fnDisconnect = fnDisconnect; pParser->fnDisconnect = fnDisconnect;
ZeroMemory(&pParser->filterInfo, sizeof(FILTER_INFO)); ZeroMemory(&pParser->filterInfo, sizeof(FILTER_INFO));
pParser->lastpinchange = GetTickCount(); pParser->lastpinchange = GetTickCount();
pParser->cStreams = 0; pParser->cStreams = 0;
pParser->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *)); pParser->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *));
@ -89,7 +89,7 @@ HRESULT Parser_Create(ParserImpl* pParser, const IBaseFilterVtbl *Parser_Vtbl, c
MediaSeekingImpl_Init((IBaseFilter*)pParser, stop, current, rate, &pParser->mediaSeeking, &pParser->csFilter); MediaSeekingImpl_Init((IBaseFilter*)pParser, stop, current, rate, &pParser->mediaSeeking, &pParser->csFilter);
pParser->mediaSeeking.lpVtbl = &Parser_Seeking_Vtbl; pParser->mediaSeeking.lpVtbl = &Parser_Seeking_Vtbl;
hr = PullPin_Construct(&Parser_InputPin_Vtbl, &piInput, fnProcessSample, (LPVOID)pParser, fnQueryAccept, fnCleanup, fnRequest, &pParser->csFilter, (IPin **)&pParser->pInputPin); hr = PullPin_Construct(&Parser_InputPin_Vtbl, &piInput, fnProcessSample, (LPVOID)pParser, fnQueryAccept, fnCleanup, fnRequest, fnDone, &pParser->csFilter, (IPin **)&pParser->pInputPin);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
@ -150,6 +150,10 @@ ULONG WINAPI Parser_AddRef(IBaseFilter * iface)
void Parser_Destroy(ParserImpl *This) void Parser_Destroy(ParserImpl *This)
{ {
IPin *connected = NULL; IPin *connected = NULL;
ULONG pinref;
assert(!This->refCount);
PullPin_WaitForStateChange(This->pInputPin, INFINITE);
if (This->pClock) if (This->pClock)
IReferenceClock_Release(This->pClock); IReferenceClock_Release(This->pClock);
@ -158,11 +162,21 @@ void Parser_Destroy(ParserImpl *This)
IPin_ConnectedTo((IPin *)This->pInputPin, &connected); IPin_ConnectedTo((IPin *)This->pInputPin, &connected);
if (connected) if (connected)
{ {
IPin_Disconnect(connected); assert(IPin_Disconnect(connected) == S_OK);
IPin_Release(connected); IPin_Release(connected);
IPin_Disconnect((IPin *)This->pInputPin); assert(IPin_Disconnect((IPin *)This->pInputPin) == S_OK);
} }
IPin_Release((IPin *)This->pInputPin); pinref = IPin_Release((IPin *)This->pInputPin);
if (pinref)
{
/* Valgrind could find this, if I kill it here */
ERR("pinref should be null, is %u, destroying anyway\n", pinref);
assert((LONG)pinref > 0);
while (pinref)
pinref = IPin_Release((IPin *)This->pInputPin);
}
CoTaskMemFree(This->ppPins); CoTaskMemFree(This->ppPins);
This->lpVtbl = NULL; This->lpVtbl = NULL;
@ -378,6 +392,7 @@ HRESULT WINAPI Parser_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClo
/** IBaseFilter implementation **/ /** IBaseFilter implementation **/
/* FIXME: WRONG */
static HRESULT Parser_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick) static HRESULT Parser_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
{ {
ParserImpl *This = (ParserImpl *)iface; ParserImpl *This = (ParserImpl *)iface;
@ -464,7 +479,7 @@ HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PR
This->ppPins = CoTaskMemAlloc((This->cStreams + 2) * sizeof(IPin *)); This->ppPins = CoTaskMemAlloc((This->cStreams + 2) * sizeof(IPin *));
memcpy(This->ppPins, ppOldPins, (This->cStreams + 1) * sizeof(IPin *)); memcpy(This->ppPins, ppOldPins, (This->cStreams + 1) * sizeof(IPin *));
hr = OutputPin_Construct(&Parser_OutputPin_Vtbl, sizeof(Parser_OutputPin), piOutput, props, NULL, Parser_OutputPin_QueryAccept, &This->csFilter, This->ppPins + This->cStreams + 1); hr = OutputPin_Construct(&Parser_OutputPin_Vtbl, sizeof(Parser_OutputPin), piOutput, props, NULL, Parser_OutputPin_QueryAccept, &This->csFilter, This->ppPins + (This->cStreams + 1));
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
@ -494,22 +509,25 @@ HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PR
static HRESULT Parser_RemoveOutputPins(ParserImpl * This) static HRESULT Parser_RemoveOutputPins(ParserImpl * This)
{ {
/* NOTE: should be in critical section when calling this function */ /* NOTE: should be in critical section when calling this function */
HRESULT hr;
ULONG i; ULONG i;
IPin ** ppOldPins = This->ppPins; IPin ** ppOldPins = This->ppPins;
TRACE("(%p)\n", This);
/* reduce the pin array down to 1 (just our input pin) */ /* reduce the pin array down to 1 (just our input pin) */
This->ppPins = CoTaskMemAlloc(sizeof(IPin *) * 1); This->ppPins = CoTaskMemAlloc(sizeof(IPin *) * 1);
memcpy(This->ppPins, ppOldPins, sizeof(IPin *) * 1); memcpy(This->ppPins, ppOldPins, sizeof(IPin *) * 1);
for (i = 0; i < This->cStreams; i++) for (i = 0; i < This->cStreams; i++)
{ {
OutputPin_DeliverDisconnect((OutputPin *)ppOldPins[i + 1]); hr = OutputPin_DeliverDisconnect((OutputPin *)ppOldPins[i + 1]);
FIXME("Other side: %08x\n", hr);
IPin_Release(ppOldPins[i + 1]); IPin_Release(ppOldPins[i + 1]);
} }
This->cStreams = 0;
This->lastpinchange = GetTickCount(); This->lastpinchange = GetTickCount();
This->cStreams = 0;
CoTaskMemFree(ppOldPins); CoTaskMemFree(ppOldPins);
return S_OK; return S_OK;
@ -687,27 +705,31 @@ static const IPinVtbl Parser_OutputPin_Vtbl =
static HRESULT WINAPI Parser_PullPin_Disconnect(IPin * iface) static HRESULT WINAPI Parser_PullPin_Disconnect(IPin * iface)
{ {
HRESULT hr; HRESULT hr;
IPinImpl *This = (IPinImpl *)iface; PullPin *This = (PullPin *)iface;
TRACE("()\n"); TRACE("()\n");
EnterCriticalSection(This->pCritSec); EnterCriticalSection(&This->thread_lock);
EnterCriticalSection(This->pin.pCritSec);
{ {
if (This->pConnectedTo) if (This->pin.pConnectedTo)
{ {
PullPin *ppin = (PullPin *)This; PullPin *ppin = (PullPin *)This;
FILTER_STATE state; FILTER_STATE state;
ParserImpl *Parser = (ParserImpl *)This->pinInfo.pFilter; ParserImpl *Parser = (ParserImpl *)This->pin.pinInfo.pFilter;
hr = IBaseFilter_GetState(This->pinInfo.pFilter, 0, &state); LeaveCriticalSection(This->pin.pCritSec);
hr = IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state);
EnterCriticalSection(This->pin.pCritSec);
if (SUCCEEDED(hr) && (state == State_Stopped) && SUCCEEDED(Parser->fnDisconnect(Parser))) if (SUCCEEDED(hr) && (state == State_Stopped) && SUCCEEDED(Parser->fnDisconnect(Parser)))
{ {
IPin_Release(This->pConnectedTo); IPin_Release(This->pin.pConnectedTo);
This->pConnectedTo = NULL; This->pin.pConnectedTo = NULL;
if (FAILED(hr = IMemAllocator_Decommit(ppin->pAlloc))) if (FAILED(hr = IMemAllocator_Decommit(ppin->pAlloc)))
ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr); ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr);
hr = Parser_RemoveOutputPins((ParserImpl *)This->pinInfo.pFilter); hr = Parser_RemoveOutputPins((ParserImpl *)This->pin.pinInfo.pFilter);
} }
else else
hr = VFW_E_NOT_STOPPED; hr = VFW_E_NOT_STOPPED;
@ -715,7 +737,8 @@ static HRESULT WINAPI Parser_PullPin_Disconnect(IPin * iface)
else else
hr = S_FALSE; hr = S_FALSE;
} }
LeaveCriticalSection(This->pCritSec); LeaveCriticalSection(This->pin.pCritSec);
LeaveCriticalSection(&This->thread_lock);
return hr; return hr;
} }

View File

@ -58,7 +58,7 @@ typedef struct Parser_OutputPin
extern HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, const AM_MEDIA_TYPE * amt); extern HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, const AM_MEDIA_TYPE * amt);
extern HRESULT Parser_Create(ParserImpl*, const IBaseFilterVtbl *, const CLSID*, PFN_PROCESS_SAMPLE, PFN_QUERY_ACCEPT, PFN_PRE_CONNECT, extern HRESULT Parser_Create(ParserImpl*, const IBaseFilterVtbl *, const CLSID*, PFN_PROCESS_SAMPLE, PFN_QUERY_ACCEPT, PFN_PRE_CONNECT,
PFN_CLEANUP, PFN_DISCONNECT, REQUESTPROC, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate); PFN_CLEANUP, PFN_DISCONNECT, REQUESTPROC, STOPPROCESSPROC, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate);
/* Override the _Release function and call this when releasing */ /* Override the _Release function and call this when releasing */
extern void Parser_Destroy(ParserImpl *This); extern void Parser_Destroy(ParserImpl *This);

View File

@ -1205,7 +1205,7 @@ HRESULT OutputPin_DeliverDisconnect(OutputPin * This)
static HRESULT PullPin_Init(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, static HRESULT PullPin_Init(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData,
QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, LPCRITICAL_SECTION pCritSec, PullPin * pPinImpl) QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, STOPPROCESSPROC pDone, LPCRITICAL_SECTION pCritSec, PullPin * pPinImpl)
{ {
/* Common attributes */ /* Common attributes */
pPinImpl->pin.lpVtbl = PullPin_Vtbl; pPinImpl->pin.lpVtbl = PullPin_Vtbl;
@ -1220,6 +1220,7 @@ static HRESULT PullPin_Init(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinI
/* Input pin attributes */ /* Input pin attributes */
pPinImpl->fnSampleProc = pSampleProc; pPinImpl->fnSampleProc = pSampleProc;
pPinImpl->fnCleanProc = pCleanUp; pPinImpl->fnCleanProc = pCleanUp;
pPinImpl->fnDone = pDone;
pPinImpl->fnPreConnect = NULL; pPinImpl->fnPreConnect = NULL;
pPinImpl->pAlloc = NULL; pPinImpl->pAlloc = NULL;
pPinImpl->pReader = NULL; pPinImpl->pReader = NULL;
@ -1241,7 +1242,7 @@ static HRESULT PullPin_Init(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinI
return S_OK; return S_OK;
} }
HRESULT PullPin_Construct(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, LPCRITICAL_SECTION pCritSec, IPin ** ppPin) HRESULT PullPin_Construct(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, STOPPROCESSPROC pDone, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
{ {
PullPin * pPinImpl; PullPin * pPinImpl;
@ -1258,7 +1259,7 @@ HRESULT PullPin_Construct(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInf
if (!pPinImpl) if (!pPinImpl)
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
if (SUCCEEDED(PullPin_Init(PullPin_Vtbl, pPinInfo, pSampleProc, pUserData, pQueryAccept, pCleanUp, pCustomRequest, pCritSec, pPinImpl))) if (SUCCEEDED(PullPin_Init(PullPin_Vtbl, pPinInfo, pSampleProc, pUserData, pQueryAccept, pCleanUp, pCustomRequest, pDone, pCritSec, pPinImpl)))
{ {
*ppPin = (IPin *)(&pPinImpl->pin.lpVtbl); *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
return S_OK; return S_OK;
@ -1381,6 +1382,9 @@ ULONG WINAPI PullPin_Release(IPin *iface)
if (!refCount) if (!refCount)
{ {
WaitForSingleObject(This->hEventStateChanged, INFINITE);
assert(!This->hThread);
if(This->pAlloc) if(This->pAlloc)
IMemAllocator_Release(This->pAlloc); IMemAllocator_Release(This->pAlloc);
if(This->pReader) if(This->pReader)
@ -1565,6 +1569,8 @@ static void CALLBACK PullPin_Thread_Process(PullPin *This)
* Flush remaining samples * Flush remaining samples
*/ */
PullPin_Flush(This); PullPin_Flush(This);
if (This->fnDone)
This->fnDone(This->pin.pUserData);
TRACE("End: %08x, %d\n", hr, This->stop_playback); TRACE("End: %08x, %d\n", hr, This->stop_playback);
} }

View File

@ -59,6 +59,11 @@ typedef HRESULT (* CLEANUPPROC) (LPVOID userdata);
*/ */
typedef HRESULT (* REQUESTPROC) (LPVOID userdata); typedef HRESULT (* REQUESTPROC) (LPVOID userdata);
/* This function is called after processing is done (for whatever reason that is caused)
* This is useful if you create processing threads that need to die
*/
typedef HRESULT (* STOPPROCESSPROC) (LPVOID userdata);
#define ALIGNDOWN(value,boundary) ((value)/(boundary)*(boundary)) #define ALIGNDOWN(value,boundary) ((value)/(boundary)*(boundary))
#define ALIGNUP(value,boundary) (ALIGNDOWN((value)+(boundary)-1, (boundary))) #define ALIGNUP(value,boundary) (ALIGNDOWN((value)+(boundary)-1, (boundary)))
@ -115,6 +120,7 @@ typedef struct PullPin
PRECONNECTPROC fnPreConnect; PRECONNECTPROC fnPreConnect;
REQUESTPROC fnCustomRequest; REQUESTPROC fnCustomRequest;
CLEANUPPROC fnCleanProc; CLEANUPPROC fnCleanProc;
STOPPROCESSPROC fnDone;
double dRate; double dRate;
BOOL stop_playback; BOOL stop_playback;
DWORD cbAlign; DWORD cbAlign;
@ -138,7 +144,7 @@ typedef struct PullPin
/*** Constructors ***/ /*** Constructors ***/
HRESULT InputPin_Construct(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IPin ** ppPin); HRESULT InputPin_Construct(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
HRESULT OutputPin_Construct(const IPinVtbl *OutputPin_Vtbl, long outputpin_size, const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin); HRESULT OutputPin_Construct(const IPinVtbl *OutputPin_Vtbl, long outputpin_size, const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
HRESULT PullPin_Construct(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, LPCRITICAL_SECTION pCritSec, IPin ** ppPin); HRESULT PullPin_Construct(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, STOPPROCESSPROC, REQUESTPROC pCustomRequest, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
/**************************/ /**************************/
/*** Pin Implementation ***/ /*** Pin Implementation ***/

View File

@ -459,7 +459,7 @@ HRESULT WAVEParser_create(IUnknown * pUnkOuter, LPVOID * ppv)
This->pCurrentSample = NULL; This->pCurrentSample = NULL;
hr = Parser_Create(&(This->Parser), &WAVEParser_Vtbl, &CLSID_WAVEParser, WAVEParser_Sample, WAVEParser_QueryAccept, WAVEParser_InputPin_PreConnect, WAVEParser_Cleanup, WAVEParser_disconnect, WAVEParser_first_request, NULL, WAVEParserImpl_seek, NULL); hr = Parser_Create(&(This->Parser), &WAVEParser_Vtbl, &CLSID_WAVEParser, WAVEParser_Sample, WAVEParser_QueryAccept, WAVEParser_InputPin_PreConnect, WAVEParser_Cleanup, WAVEParser_disconnect, WAVEParser_first_request, NULL, NULL, WAVEParserImpl_seek, NULL);
if (FAILED(hr)) if (FAILED(hr))
return hr; return hr;