From 512ee927cb56a6b3355550c2f929d34f080247ea Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Fri, 25 Apr 2008 14:59:05 -0700 Subject: [PATCH] quartz: Add a function that can be called when stopping processing data. --- dlls/quartz/avisplit.c | 2 +- dlls/quartz/mpegsplit.c | 2 +- dlls/quartz/parser.c | 65 +++++++++++++++++++++++++++------------- dlls/quartz/parser.h | 2 +- dlls/quartz/pin.c | 12 ++++++-- dlls/quartz/pin.h | 8 ++++- dlls/quartz/waveparser.c | 2 +- 7 files changed, 64 insertions(+), 29 deletions(-) diff --git a/dlls/quartz/avisplit.c b/dlls/quartz/avisplit.c index 77ebc9a5958..e09adb7db71 100644 --- a/dlls/quartz/avisplit.c +++ b/dlls/quartz/avisplit.c @@ -1080,7 +1080,7 @@ HRESULT AVISplitter_create(IUnknown * pUnkOuter, LPVOID * ppv) This->streams = 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)) return hr; diff --git a/dlls/quartz/mpegsplit.c b/dlls/quartz/mpegsplit.c index 1b88739c89d..71027e93eb0 100644 --- a/dlls/quartz/mpegsplit.c +++ b/dlls/quartz/mpegsplit.c @@ -830,7 +830,7 @@ HRESULT MPEGSplitter_create(IUnknown * pUnkOuter, LPVOID * ppv) } 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)) { CoTaskMemFree(This); diff --git a/dlls/quartz/parser.c b/dlls/quartz/parser.c index 7a7f9ba5646..f9140ae7e8f 100644 --- a/dlls/quartz/parser.c +++ b/dlls/quartz/parser.c @@ -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; PIN_INFO piInput; @@ -67,8 +67,8 @@ HRESULT Parser_Create(ParserImpl* pParser, const IBaseFilterVtbl *Parser_Vtbl, c pParser->pClock = NULL; pParser->fnDisconnect = fnDisconnect; ZeroMemory(&pParser->filterInfo, sizeof(FILTER_INFO)); - pParser->lastpinchange = GetTickCount(); + pParser->cStreams = 0; 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); 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)) { @@ -150,6 +150,10 @@ ULONG WINAPI Parser_AddRef(IBaseFilter * iface) void Parser_Destroy(ParserImpl *This) { IPin *connected = NULL; + ULONG pinref; + + assert(!This->refCount); + PullPin_WaitForStateChange(This->pInputPin, INFINITE); if (This->pClock) IReferenceClock_Release(This->pClock); @@ -158,11 +162,21 @@ void Parser_Destroy(ParserImpl *This) IPin_ConnectedTo((IPin *)This->pInputPin, &connected); if (connected) { - IPin_Disconnect(connected); + assert(IPin_Disconnect(connected) == S_OK); 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); This->lpVtbl = NULL; @@ -378,6 +392,7 @@ HRESULT WINAPI Parser_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClo /** IBaseFilter implementation **/ +/* FIXME: WRONG */ static HRESULT Parser_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick) { 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 *)); 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)) { @@ -494,22 +509,25 @@ HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PR static HRESULT Parser_RemoveOutputPins(ParserImpl * This) { /* NOTE: should be in critical section when calling this function */ - + HRESULT hr; ULONG i; IPin ** ppOldPins = This->ppPins; + TRACE("(%p)\n", This); + /* reduce the pin array down to 1 (just our input pin) */ This->ppPins = CoTaskMemAlloc(sizeof(IPin *) * 1); memcpy(This->ppPins, ppOldPins, sizeof(IPin *) * 1); 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]); } - This->cStreams = 0; This->lastpinchange = GetTickCount(); + This->cStreams = 0; CoTaskMemFree(ppOldPins); return S_OK; @@ -613,7 +631,7 @@ static ULONG WINAPI Parser_OutputPin_Release(IPin * iface) ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount); TRACE("(%p)->() Release from %d\n", iface, refCount + 1); - + if (!refCount) { FreeMediaType(This->pmt); @@ -687,27 +705,31 @@ static const IPinVtbl Parser_OutputPin_Vtbl = static HRESULT WINAPI Parser_PullPin_Disconnect(IPin * iface) { HRESULT hr; - IPinImpl *This = (IPinImpl *)iface; + PullPin *This = (PullPin *)iface; TRACE("()\n"); - EnterCriticalSection(This->pCritSec); + EnterCriticalSection(&This->thread_lock); + EnterCriticalSection(This->pin.pCritSec); { - if (This->pConnectedTo) + if (This->pin.pConnectedTo) { PullPin *ppin = (PullPin *)This; 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))) { - IPin_Release(This->pConnectedTo); - This->pConnectedTo = NULL; + IPin_Release(This->pin.pConnectedTo); + This->pin.pConnectedTo = NULL; + if (FAILED(hr = IMemAllocator_Decommit(ppin->pAlloc))) 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 hr = VFW_E_NOT_STOPPED; @@ -715,8 +737,9 @@ static HRESULT WINAPI Parser_PullPin_Disconnect(IPin * iface) else hr = S_FALSE; } - LeaveCriticalSection(This->pCritSec); - + LeaveCriticalSection(This->pin.pCritSec); + LeaveCriticalSection(&This->thread_lock); + return hr; } diff --git a/dlls/quartz/parser.h b/dlls/quartz/parser.h index f30a8fdfdeb..b5423885400 100644 --- a/dlls/quartz/parser.h +++ b/dlls/quartz/parser.h @@ -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_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 */ extern void Parser_Destroy(ParserImpl *This); diff --git a/dlls/quartz/pin.c b/dlls/quartz/pin.c index 6bbcf9a4f20..803a751ec85 100644 --- a/dlls/quartz/pin.c +++ b/dlls/quartz/pin.c @@ -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, - 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 */ pPinImpl->pin.lpVtbl = PullPin_Vtbl; @@ -1220,6 +1220,7 @@ static HRESULT PullPin_Init(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinI /* Input pin attributes */ pPinImpl->fnSampleProc = pSampleProc; pPinImpl->fnCleanProc = pCleanUp; + pPinImpl->fnDone = pDone; pPinImpl->fnPreConnect = NULL; pPinImpl->pAlloc = NULL; pPinImpl->pReader = NULL; @@ -1241,7 +1242,7 @@ static HRESULT PullPin_Init(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinI 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; @@ -1258,7 +1259,7 @@ HRESULT PullPin_Construct(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInf if (!pPinImpl) 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); return S_OK; @@ -1381,6 +1382,9 @@ ULONG WINAPI PullPin_Release(IPin *iface) if (!refCount) { + WaitForSingleObject(This->hEventStateChanged, INFINITE); + assert(!This->hThread); + if(This->pAlloc) IMemAllocator_Release(This->pAlloc); if(This->pReader) @@ -1565,6 +1569,8 @@ static void CALLBACK PullPin_Thread_Process(PullPin *This) * Flush remaining samples */ PullPin_Flush(This); + if (This->fnDone) + This->fnDone(This->pin.pUserData); TRACE("End: %08x, %d\n", hr, This->stop_playback); } diff --git a/dlls/quartz/pin.h b/dlls/quartz/pin.h index 147a64ceddf..80b439d52b1 100644 --- a/dlls/quartz/pin.h +++ b/dlls/quartz/pin.h @@ -59,6 +59,11 @@ typedef HRESULT (* CLEANUPPROC) (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 ALIGNUP(value,boundary) (ALIGNDOWN((value)+(boundary)-1, (boundary))) @@ -115,6 +120,7 @@ typedef struct PullPin PRECONNECTPROC fnPreConnect; REQUESTPROC fnCustomRequest; CLEANUPPROC fnCleanProc; + STOPPROCESSPROC fnDone; double dRate; BOOL stop_playback; DWORD cbAlign; @@ -138,7 +144,7 @@ typedef struct PullPin /*** 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 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 ***/ diff --git a/dlls/quartz/waveparser.c b/dlls/quartz/waveparser.c index 8e3767e7f98..38182141e47 100644 --- a/dlls/quartz/waveparser.c +++ b/dlls/quartz/waveparser.c @@ -459,7 +459,7 @@ HRESULT WAVEParser_create(IUnknown * pUnkOuter, LPVOID * ppv) 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)) return hr;