| /* | |
| * Parser (Base for parsers and splitters) | |
| * | |
| * Copyright 2003 Robert Shearman | |
| * Copyright 2004-2005 Christian Costa | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| */ | |
| #include "quartz_private.h" | |
| #include "pin.h" | |
| #include "vfwmsgs.h" | |
| #include "amvideo.h" | |
| #include "wine/unicode.h" | |
| #include "wine/debug.h" | |
| #include <math.h> | |
| #include <assert.h> | |
| #include "parser.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(quartz); | |
| static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0}; | |
| static const IMediaSeekingVtbl Parser_Seeking_Vtbl; | |
| static const IPinVtbl Parser_OutputPin_Vtbl; | |
| static const IPinVtbl Parser_InputPin_Vtbl; | |
| static HRESULT WINAPI Parser_ChangeStart(IMediaSeeking *iface); | |
| static HRESULT WINAPI Parser_ChangeStop(IMediaSeeking *iface); | |
| static HRESULT WINAPI Parser_ChangeRate(IMediaSeeking *iface); | |
| static HRESULT WINAPI Parser_OutputPin_DecideBufferSize(BaseOutputPin *iface, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest); | |
| static HRESULT WINAPI Parser_OutputPin_GetMediaType(BasePin *iface, int iPosition, AM_MEDIA_TYPE *pmt); | |
| static HRESULT WINAPI Parser_OutputPin_DecideAllocator(BaseOutputPin *This, IMemInputPin *pPin, IMemAllocator **pAlloc); | |
| static HRESULT WINAPI Parser_OutputPin_BreakConnect(BaseOutputPin *This); | |
| static inline ParserImpl *impl_from_IMediaSeeking( IMediaSeeking *iface ) | |
| { | |
| return CONTAINING_RECORD(iface, ParserImpl, sourceSeeking.IMediaSeeking_iface); | |
| } | |
| static inline ParserImpl *impl_from_IBaseFilter( IBaseFilter *iface ) | |
| { | |
| return CONTAINING_RECORD(iface, ParserImpl, filter.IBaseFilter_iface); | |
| } | |
| static inline ParserImpl *impl_from_BaseFilter( BaseFilter *iface ) | |
| { | |
| return CONTAINING_RECORD(iface, ParserImpl, filter); | |
| } | |
| /* FIXME: WRONG */ | |
| static IPin* WINAPI Parser_GetPin(BaseFilter *iface, int pos) | |
| { | |
| ParserImpl *This = impl_from_BaseFilter(iface); | |
| TRACE("Asking for pos %x\n", pos); | |
| /* Input pin also has a pin, hence the > and not >= */ | |
| if (pos > This->cStreams || pos < 0) | |
| return NULL; | |
| IPin_AddRef(This->ppPins[pos]); | |
| return This->ppPins[pos]; | |
| } | |
| static LONG WINAPI Parser_GetPinCount(BaseFilter *iface) | |
| { | |
| ParserImpl *This = impl_from_BaseFilter(iface); | |
| return This->cStreams; | |
| } | |
| static const BaseFilterFuncTable BaseFuncTable = { | |
| Parser_GetPin, | |
| Parser_GetPinCount | |
| }; | |
| 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, SourceSeeking_ChangeStop stop, SourceSeeking_ChangeStart start, SourceSeeking_ChangeRate rate) | |
| { | |
| HRESULT hr; | |
| PIN_INFO piInput; | |
| /* pTransformFilter is already allocated */ | |
| BaseFilter_Init(&pParser->filter, Parser_Vtbl, pClsid, (DWORD_PTR)(__FILE__ ": ParserImpl.csFilter"), &BaseFuncTable); | |
| pParser->fnDisconnect = fnDisconnect; | |
| pParser->cStreams = 0; | |
| pParser->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *)); | |
| /* construct input pin */ | |
| piInput.dir = PINDIR_INPUT; | |
| piInput.pFilter = &pParser->filter.IBaseFilter_iface; | |
| lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0])); | |
| if (!start) | |
| start = Parser_ChangeStart; | |
| if (!stop) | |
| stop = Parser_ChangeStop; | |
| if (!rate) | |
| rate = Parser_ChangeRate; | |
| SourceSeeking_Init(&pParser->sourceSeeking, &Parser_Seeking_Vtbl, stop, start, rate, &pParser->filter.csFilter); | |
| hr = PullPin_Construct(&Parser_InputPin_Vtbl, &piInput, fnProcessSample, (LPVOID)pParser, fnQueryAccept, fnCleanup, fnRequest, fnDone, &pParser->filter.csFilter, (IPin **)&pParser->pInputPin); | |
| if (SUCCEEDED(hr)) | |
| { | |
| pParser->ppPins[0] = &pParser->pInputPin->pin.IPin_iface; | |
| pParser->pInputPin->fnPreConnect = fnPreConnect; | |
| } | |
| else | |
| { | |
| CoTaskMemFree(pParser->ppPins); | |
| BaseFilterImpl_Release(&pParser->filter.IBaseFilter_iface); | |
| CoTaskMemFree(pParser); | |
| } | |
| return hr; | |
| } | |
| HRESULT WINAPI Parser_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv) | |
| { | |
| ParserImpl *This = impl_from_IBaseFilter(iface); | |
| TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv); | |
| *ppv = NULL; | |
| if ( IsEqualIID(riid, &IID_IUnknown) | |
| || IsEqualIID(riid, &IID_IPersist) | |
| || IsEqualIID(riid, &IID_IMediaFilter) | |
| || IsEqualIID(riid, &IID_IBaseFilter) ) | |
| *ppv = &This->filter.IBaseFilter_iface; | |
| if (*ppv) | |
| { | |
| IUnknown_AddRef((IUnknown *)*ppv); | |
| return S_OK; | |
| } | |
| if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow)) | |
| FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); | |
| return E_NOINTERFACE; | |
| } | |
| ULONG WINAPI Parser_AddRef(IBaseFilter * iface) | |
| { | |
| return BaseFilterImpl_AddRef(iface); | |
| } | |
| void Parser_Destroy(ParserImpl *This) | |
| { | |
| IPin *connected = NULL; | |
| ULONG pinref; | |
| HRESULT hr; | |
| assert(!This->filter.refCount); | |
| PullPin_WaitForStateChange(This->pInputPin, INFINITE); | |
| /* Don't need to clean up output pins, freeing input pin will do that */ | |
| IPin_ConnectedTo(&This->pInputPin->pin.IPin_iface, &connected); | |
| if (connected) | |
| { | |
| hr = IPin_Disconnect(connected); | |
| assert(hr == S_OK); | |
| IPin_Release(connected); | |
| hr = IPin_Disconnect(&This->pInputPin->pin.IPin_iface); | |
| assert(hr == S_OK); | |
| } | |
| pinref = IPin_Release(&This->pInputPin->pin.IPin_iface); | |
| 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(&This->pInputPin->pin.IPin_iface); | |
| } | |
| CoTaskMemFree(This->ppPins); | |
| BaseFilter_Destroy(&This->filter); | |
| TRACE("Destroying parser\n"); | |
| CoTaskMemFree(This); | |
| } | |
| ULONG WINAPI Parser_Release(IBaseFilter * iface) | |
| { | |
| ParserImpl *This = impl_from_IBaseFilter(iface); | |
| ULONG refCount = InterlockedDecrement(&This->filter.refCount); | |
| TRACE("(%p)->() Release from %d\n", This, refCount + 1); | |
| if (!refCount) | |
| Parser_Destroy(This); | |
| return refCount; | |
| } | |
| /** IPersist methods **/ | |
| HRESULT WINAPI Parser_GetClassID(IBaseFilter * iface, CLSID * pClsid) | |
| { | |
| ParserImpl *This = impl_from_IBaseFilter(iface); | |
| TRACE("(%p)\n", pClsid); | |
| *pClsid = This->filter.clsid; | |
| return S_OK; | |
| } | |
| /** IMediaFilter methods **/ | |
| HRESULT WINAPI Parser_Stop(IBaseFilter * iface) | |
| { | |
| ParserImpl *This = impl_from_IBaseFilter(iface); | |
| PullPin *pin = impl_PullPin_from_IPin(This->ppPins[0]); | |
| ULONG i; | |
| TRACE("()\n"); | |
| EnterCriticalSection(&pin->thread_lock); | |
| IAsyncReader_BeginFlush(This->pInputPin->pReader); | |
| EnterCriticalSection(&This->filter.csFilter); | |
| if (This->filter.state == State_Stopped) | |
| { | |
| LeaveCriticalSection(&This->filter.csFilter); | |
| IAsyncReader_EndFlush(This->pInputPin->pReader); | |
| LeaveCriticalSection(&pin->thread_lock); | |
| return S_OK; | |
| } | |
| This->filter.state = State_Stopped; | |
| for (i = 1; i < (This->cStreams + 1); i++) | |
| { | |
| BaseOutputPinImpl_Inactive((BaseOutputPin *)This->ppPins[i]); | |
| } | |
| LeaveCriticalSection(&This->filter.csFilter); | |
| PullPin_PauseProcessing(This->pInputPin); | |
| PullPin_WaitForStateChange(This->pInputPin, INFINITE); | |
| IAsyncReader_EndFlush(This->pInputPin->pReader); | |
| LeaveCriticalSection(&pin->thread_lock); | |
| return S_OK; | |
| } | |
| HRESULT WINAPI Parser_Pause(IBaseFilter * iface) | |
| { | |
| HRESULT hr = S_OK; | |
| ParserImpl *This = impl_from_IBaseFilter(iface); | |
| PullPin *pin = impl_PullPin_from_IPin(This->ppPins[0]); | |
| TRACE("()\n"); | |
| EnterCriticalSection(&pin->thread_lock); | |
| EnterCriticalSection(&This->filter.csFilter); | |
| if (This->filter.state == State_Paused) | |
| { | |
| LeaveCriticalSection(&This->filter.csFilter); | |
| LeaveCriticalSection(&pin->thread_lock); | |
| return S_OK; | |
| } | |
| if (This->filter.state == State_Stopped) | |
| { | |
| LeaveCriticalSection(&This->filter.csFilter); | |
| hr = IBaseFilter_Run(iface, -1); | |
| EnterCriticalSection(&This->filter.csFilter); | |
| } | |
| if (SUCCEEDED(hr)) | |
| This->filter.state = State_Paused; | |
| LeaveCriticalSection(&This->filter.csFilter); | |
| LeaveCriticalSection(&pin->thread_lock); | |
| return hr; | |
| } | |
| HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart) | |
| { | |
| HRESULT hr = S_OK; | |
| ParserImpl *This = impl_from_IBaseFilter(iface); | |
| PullPin *pin = impl_PullPin_from_IPin(This->ppPins[0]); | |
| ULONG i; | |
| TRACE("(%s)\n", wine_dbgstr_longlong(tStart)); | |
| EnterCriticalSection(&pin->thread_lock); | |
| EnterCriticalSection(&This->filter.csFilter); | |
| { | |
| HRESULT hr_any = VFW_E_NOT_CONNECTED; | |
| This->filter.rtStreamStart = tStart; | |
| if (This->filter.state == State_Running || This->filter.state == State_Paused) | |
| { | |
| This->filter.state = State_Running; | |
| LeaveCriticalSection(&This->filter.csFilter); | |
| LeaveCriticalSection(&pin->thread_lock); | |
| return S_OK; | |
| } | |
| for (i = 1; i < (This->cStreams + 1); i++) | |
| { | |
| hr = BaseOutputPinImpl_Active((BaseOutputPin *)This->ppPins[i]); | |
| if (SUCCEEDED(hr)) | |
| hr_any = hr; | |
| } | |
| hr = hr_any; | |
| if (SUCCEEDED(hr)) | |
| { | |
| LeaveCriticalSection(&This->filter.csFilter); | |
| hr = PullPin_StartProcessing(This->pInputPin); | |
| EnterCriticalSection(&This->filter.csFilter); | |
| } | |
| if (SUCCEEDED(hr)) | |
| This->filter.state = State_Running; | |
| } | |
| LeaveCriticalSection(&This->filter.csFilter); | |
| LeaveCriticalSection(&pin->thread_lock); | |
| return hr; | |
| } | |
| HRESULT WINAPI Parser_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState) | |
| { | |
| ParserImpl *This = impl_from_IBaseFilter(iface); | |
| PullPin *pin = impl_PullPin_from_IPin(This->ppPins[0]); | |
| HRESULT hr = S_OK; | |
| TRACE("(%d, %p)\n", dwMilliSecsTimeout, pState); | |
| EnterCriticalSection(&pin->thread_lock); | |
| EnterCriticalSection(&This->filter.csFilter); | |
| { | |
| *pState = This->filter.state; | |
| } | |
| LeaveCriticalSection(&This->filter.csFilter); | |
| if (This->pInputPin && (PullPin_WaitForStateChange(This->pInputPin, dwMilliSecsTimeout) == S_FALSE)) | |
| hr = VFW_S_STATE_INTERMEDIATE; | |
| LeaveCriticalSection(&pin->thread_lock); | |
| return hr; | |
| } | |
| HRESULT WINAPI Parser_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock) | |
| { | |
| ParserImpl *This = impl_from_IBaseFilter(iface); | |
| PullPin *pin = impl_PullPin_from_IPin(This->ppPins[0]); | |
| TRACE("(%p)\n", pClock); | |
| EnterCriticalSection(&pin->thread_lock); | |
| BaseFilterImpl_SetSyncSource(iface,pClock); | |
| LeaveCriticalSection(&pin->thread_lock); | |
| return S_OK; | |
| } | |
| HRESULT WINAPI Parser_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock) | |
| { | |
| return BaseFilterImpl_GetSyncSource(iface, ppClock); | |
| } | |
| /** IBaseFilter implementation **/ | |
| HRESULT WINAPI Parser_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum) | |
| { | |
| return BaseFilterImpl_EnumPins(iface,ppEnum); | |
| } | |
| HRESULT WINAPI Parser_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin) | |
| { | |
| FIXME("(%p)->(%s,%p)\n", iface, debugstr_w(Id), ppPin); | |
| /* FIXME: critical section */ | |
| return E_NOTIMPL; | |
| } | |
| HRESULT WINAPI Parser_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo) | |
| { | |
| return BaseFilterImpl_QueryFilterInfo(iface, pInfo); | |
| } | |
| HRESULT WINAPI Parser_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName) | |
| { | |
| return BaseFilterImpl_JoinFilterGraph(iface, pGraph, pName); | |
| } | |
| HRESULT WINAPI Parser_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo) | |
| { | |
| return BaseFilterImpl_QueryVendorInfo(iface, pVendorInfo); | |
| } | |
| static const BaseOutputPinFuncTable output_BaseOutputFuncTable = { | |
| { | |
| NULL, | |
| BaseOutputPinImpl_AttemptConnection, | |
| BasePinImpl_GetMediaTypeVersion, | |
| Parser_OutputPin_GetMediaType | |
| }, | |
| Parser_OutputPin_DecideBufferSize, | |
| Parser_OutputPin_DecideAllocator, | |
| Parser_OutputPin_BreakConnect | |
| }; | |
| HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, const AM_MEDIA_TYPE * amt) | |
| { | |
| IPin ** ppOldPins; | |
| HRESULT hr; | |
| ppOldPins = This->ppPins; | |
| This->ppPins = CoTaskMemAlloc((This->cStreams + 2) * sizeof(IPin *)); | |
| memcpy(This->ppPins, ppOldPins, (This->cStreams + 1) * sizeof(IPin *)); | |
| hr = BaseOutputPin_Construct(&Parser_OutputPin_Vtbl, sizeof(Parser_OutputPin), piOutput, &output_BaseOutputFuncTable, &This->filter.csFilter, This->ppPins + (This->cStreams + 1)); | |
| if (SUCCEEDED(hr)) | |
| { | |
| IPin *pPin = This->ppPins[This->cStreams + 1]; | |
| Parser_OutputPin *pin = unsafe_impl_Parser_OutputPin_from_IPin(pPin); | |
| pin->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); | |
| CopyMediaType(pin->pmt, amt); | |
| pin->dwSamplesProcessed = 0; | |
| pin->pin.pin.pinInfo.pFilter = &This->filter.IBaseFilter_iface; | |
| pin->allocProps = *props; | |
| This->cStreams++; | |
| BaseFilterImpl_IncrementPinVersion(&This->filter); | |
| CoTaskMemFree(ppOldPins); | |
| } | |
| else | |
| { | |
| CoTaskMemFree(This->ppPins); | |
| This->ppPins = ppOldPins; | |
| ERR("Failed with error %x\n", hr); | |
| } | |
| return hr; | |
| } | |
| 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++) | |
| { | |
| hr = ((BaseOutputPin *)ppOldPins[i + 1])->pFuncsTable->pfnBreakConnect((BaseOutputPin *)ppOldPins[i + 1]); | |
| TRACE("Disconnect: %08x\n", hr); | |
| IPin_Release(ppOldPins[i + 1]); | |
| } | |
| BaseFilterImpl_IncrementPinVersion(&This->filter); | |
| This->cStreams = 0; | |
| CoTaskMemFree(ppOldPins); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI Parser_ChangeStart(IMediaSeeking *iface) | |
| { | |
| FIXME("(%p) filter hasn't implemented start position change!\n", iface); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI Parser_ChangeStop(IMediaSeeking *iface) | |
| { | |
| FIXME("(%p) filter hasn't implemented stop position change!\n", iface); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI Parser_ChangeRate(IMediaSeeking *iface) | |
| { | |
| FIXME("(%p) filter hasn't implemented rate change!\n", iface); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI Parser_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv) | |
| { | |
| ParserImpl *This = impl_from_IMediaSeeking(iface); | |
| return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv); | |
| } | |
| static ULONG WINAPI Parser_Seeking_AddRef(IMediaSeeking * iface) | |
| { | |
| ParserImpl *This = impl_from_IMediaSeeking(iface); | |
| return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); | |
| } | |
| static ULONG WINAPI Parser_Seeking_Release(IMediaSeeking * iface) | |
| { | |
| ParserImpl *This = impl_from_IMediaSeeking(iface); | |
| return IBaseFilter_Release(&This->filter.IBaseFilter_iface); | |
| } | |
| static const IMediaSeekingVtbl Parser_Seeking_Vtbl = | |
| { | |
| Parser_Seeking_QueryInterface, | |
| Parser_Seeking_AddRef, | |
| Parser_Seeking_Release, | |
| SourceSeekingImpl_GetCapabilities, | |
| SourceSeekingImpl_CheckCapabilities, | |
| SourceSeekingImpl_IsFormatSupported, | |
| SourceSeekingImpl_QueryPreferredFormat, | |
| SourceSeekingImpl_GetTimeFormat, | |
| SourceSeekingImpl_IsUsingTimeFormat, | |
| SourceSeekingImpl_SetTimeFormat, | |
| SourceSeekingImpl_GetDuration, | |
| SourceSeekingImpl_GetStopPosition, | |
| SourceSeekingImpl_GetCurrentPosition, | |
| SourceSeekingImpl_ConvertTimeFormat, | |
| SourceSeekingImpl_SetPositions, | |
| SourceSeekingImpl_GetPositions, | |
| SourceSeekingImpl_GetAvailable, | |
| SourceSeekingImpl_SetRate, | |
| SourceSeekingImpl_GetRate, | |
| SourceSeekingImpl_GetPreroll | |
| }; | |
| static HRESULT WINAPI Parser_OutputPin_DecideBufferSize(BaseOutputPin *iface, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) | |
| { | |
| Parser_OutputPin *This = (Parser_OutputPin*)iface; | |
| ALLOCATOR_PROPERTIES actual; | |
| if (ppropInputRequest->cbAlign && ppropInputRequest->cbAlign != This->allocProps.cbAlign) | |
| FIXME("Requested Buffer cbAlign mismatch %i,%i\n",This->allocProps.cbAlign, ppropInputRequest->cbAlign); | |
| if (ppropInputRequest->cbPrefix) | |
| FIXME("Requested Buffer cbPrefix mismatch %i,%i\n",This->allocProps.cbPrefix, ppropInputRequest->cbPrefix); | |
| if (ppropInputRequest->cbBuffer) | |
| FIXME("Requested Buffer cbBuffer mismatch %i,%i\n",This->allocProps.cbBuffer, ppropInputRequest->cbBuffer); | |
| if (ppropInputRequest->cBuffers) | |
| FIXME("Requested Buffer cBuffers mismatch %i,%i\n",This->allocProps.cBuffers, ppropInputRequest->cBuffers); | |
| return IMemAllocator_SetProperties(pAlloc, &This->allocProps, &actual); | |
| } | |
| static HRESULT WINAPI Parser_OutputPin_GetMediaType(BasePin *iface, int iPosition, AM_MEDIA_TYPE *pmt) | |
| { | |
| Parser_OutputPin *This = (Parser_OutputPin*)iface; | |
| if (iPosition < 0) | |
| return E_INVALIDARG; | |
| if (iPosition > 0) | |
| return VFW_S_NO_MORE_ITEMS; | |
| CopyMediaType(pmt, This->pmt); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI Parser_OutputPin_DecideAllocator(BaseOutputPin *iface, IMemInputPin *pPin, IMemAllocator **pAlloc) | |
| { | |
| Parser_OutputPin *This = (Parser_OutputPin*)iface; | |
| HRESULT hr; | |
| *pAlloc = NULL; | |
| if (This->alloc) | |
| { | |
| hr = IMemInputPin_NotifyAllocator(pPin, This->alloc, This->readonly); | |
| if (SUCCEEDED(hr)) | |
| { | |
| *pAlloc = This->alloc; | |
| IMemAllocator_AddRef(*pAlloc); | |
| } | |
| } | |
| else | |
| hr = VFW_E_NO_ALLOCATOR; | |
| return hr; | |
| } | |
| static HRESULT WINAPI Parser_OutputPin_BreakConnect(BaseOutputPin *This) | |
| { | |
| HRESULT hr; | |
| TRACE("(%p)->()\n", This); | |
| EnterCriticalSection(This->pin.pCritSec); | |
| if (!This->pin.pConnectedTo || !This->pMemInputPin) | |
| hr = VFW_E_NOT_CONNECTED; | |
| else | |
| { | |
| hr = IPin_Disconnect(This->pin.pConnectedTo); | |
| IPin_Disconnect(&This->pin.IPin_iface); | |
| } | |
| LeaveCriticalSection(This->pin.pCritSec); | |
| return hr; | |
| } | |
| static HRESULT WINAPI Parser_OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) | |
| { | |
| Parser_OutputPin *This = unsafe_impl_Parser_OutputPin_from_IPin(iface); | |
| TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv); | |
| *ppv = NULL; | |
| if (IsEqualIID(riid, &IID_IUnknown)) | |
| *ppv = iface; | |
| else if (IsEqualIID(riid, &IID_IPin)) | |
| *ppv = iface; | |
| /* The Parser filter does not support querying IMediaSeeking, return it directly */ | |
| else if (IsEqualIID(riid, &IID_IMediaSeeking)) | |
| *ppv = &impl_from_IBaseFilter(This->pin.pin.pinInfo.pFilter)->sourceSeeking; | |
| if (*ppv) | |
| { | |
| IUnknown_AddRef((IUnknown *)(*ppv)); | |
| return S_OK; | |
| } | |
| FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); | |
| return E_NOINTERFACE; | |
| } | |
| static ULONG WINAPI Parser_OutputPin_Release(IPin * iface) | |
| { | |
| Parser_OutputPin *This = unsafe_impl_Parser_OutputPin_from_IPin(iface); | |
| ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount); | |
| TRACE("(%p)->() Release from %d\n", iface, refCount + 1); | |
| if (!refCount) | |
| { | |
| FreeMediaType(This->pmt); | |
| CoTaskMemFree(This->pmt); | |
| FreeMediaType(&This->pin.pin.mtCurrent); | |
| if (This->pin.pAllocator) | |
| IMemAllocator_Release(This->pin.pAllocator); | |
| CoTaskMemFree(This); | |
| return 0; | |
| } | |
| return refCount; | |
| } | |
| static HRESULT WINAPI Parser_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) | |
| { | |
| Parser_OutputPin *This = unsafe_impl_Parser_OutputPin_from_IPin(iface); | |
| ParserImpl *parser = impl_from_IBaseFilter(This->pin.pin.pinInfo.pFilter); | |
| /* Set the allocator to our input pin's */ | |
| EnterCriticalSection(This->pin.pin.pCritSec); | |
| This->alloc = parser->pInputPin->pAlloc; | |
| LeaveCriticalSection(This->pin.pin.pCritSec); | |
| return BaseOutputPinImpl_Connect(iface, pReceivePin, pmt); | |
| } | |
| static HRESULT WINAPI Parser_OutputPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE * pmt) | |
| { | |
| Parser_OutputPin *This = unsafe_impl_Parser_OutputPin_from_IPin(iface); | |
| TRACE("()\n"); | |
| dump_AM_MEDIA_TYPE(pmt); | |
| return (memcmp(This->pmt, pmt, sizeof(AM_MEDIA_TYPE)) == 0); | |
| } | |
| static const IPinVtbl Parser_OutputPin_Vtbl = | |
| { | |
| Parser_OutputPin_QueryInterface, | |
| BasePinImpl_AddRef, | |
| Parser_OutputPin_Release, | |
| Parser_OutputPin_Connect, | |
| BaseOutputPinImpl_ReceiveConnection, | |
| BaseOutputPinImpl_Disconnect, | |
| BasePinImpl_ConnectedTo, | |
| BasePinImpl_ConnectionMediaType, | |
| BasePinImpl_QueryPinInfo, | |
| BasePinImpl_QueryDirection, | |
| BasePinImpl_QueryId, | |
| Parser_OutputPin_QueryAccept, | |
| BasePinImpl_EnumMediaTypes, | |
| BasePinImpl_QueryInternalConnections, | |
| BaseOutputPinImpl_EndOfStream, | |
| BaseOutputPinImpl_BeginFlush, | |
| BaseOutputPinImpl_EndFlush, | |
| BasePinImpl_NewSegment | |
| }; | |
| static HRESULT WINAPI Parser_PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) | |
| { | |
| PullPin *This = impl_PullPin_from_IPin(iface); | |
| TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv); | |
| *ppv = NULL; | |
| /* | |
| * It is important to capture the request for the IMediaSeeking interface before it is passed | |
| * on to PullPin_QueryInterface, this is necessary since the Parser filter does not support | |
| * querying IMediaSeeking | |
| */ | |
| if (IsEqualIID(riid, &IID_IMediaSeeking)) | |
| *ppv = &impl_from_IBaseFilter(This->pin.pinInfo.pFilter)->sourceSeeking; | |
| if (*ppv) | |
| { | |
| IUnknown_AddRef((IUnknown *)(*ppv)); | |
| return S_OK; | |
| } | |
| return PullPin_QueryInterface(iface, riid, ppv); | |
| } | |
| static HRESULT WINAPI Parser_PullPin_Disconnect(IPin * iface) | |
| { | |
| HRESULT hr; | |
| PullPin *This = impl_PullPin_from_IPin(iface); | |
| TRACE("()\n"); | |
| EnterCriticalSection(&This->thread_lock); | |
| EnterCriticalSection(This->pin.pCritSec); | |
| { | |
| if (This->pin.pConnectedTo) | |
| { | |
| FILTER_STATE state; | |
| ParserImpl *Parser = impl_from_IBaseFilter(This->pin.pinInfo.pFilter); | |
| 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))) | |
| { | |
| LeaveCriticalSection(This->pin.pCritSec); | |
| PullPin_Disconnect(iface); | |
| EnterCriticalSection(This->pin.pCritSec); | |
| hr = Parser_RemoveOutputPins(impl_from_IBaseFilter(This->pin.pinInfo.pFilter)); | |
| } | |
| else | |
| hr = VFW_E_NOT_STOPPED; | |
| } | |
| else | |
| hr = S_FALSE; | |
| } | |
| LeaveCriticalSection(This->pin.pCritSec); | |
| LeaveCriticalSection(&This->thread_lock); | |
| return hr; | |
| } | |
| static HRESULT WINAPI Parser_PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) | |
| { | |
| HRESULT hr; | |
| TRACE("()\n"); | |
| hr = PullPin_ReceiveConnection(iface, pReceivePin, pmt); | |
| if (FAILED(hr)) | |
| { | |
| BasePin *This = (BasePin *)iface; | |
| EnterCriticalSection(This->pCritSec); | |
| Parser_RemoveOutputPins(impl_from_IBaseFilter(This->pinInfo.pFilter)); | |
| LeaveCriticalSection(This->pCritSec); | |
| } | |
| return hr; | |
| } | |
| static HRESULT WINAPI Parser_PullPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum) | |
| { | |
| BasePin *This = (BasePin *)iface; | |
| TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); | |
| return EnumMediaTypes_Construct(This, BasePinImpl_GetMediaType, BasePinImpl_GetMediaTypeVersion, ppEnum); | |
| } | |
| static const IPinVtbl Parser_InputPin_Vtbl = | |
| { | |
| Parser_PullPin_QueryInterface, | |
| BasePinImpl_AddRef, | |
| PullPin_Release, | |
| BaseInputPinImpl_Connect, | |
| Parser_PullPin_ReceiveConnection, | |
| Parser_PullPin_Disconnect, | |
| BasePinImpl_ConnectedTo, | |
| BasePinImpl_ConnectionMediaType, | |
| BasePinImpl_QueryPinInfo, | |
| BasePinImpl_QueryDirection, | |
| BasePinImpl_QueryId, | |
| PullPin_QueryAccept, | |
| Parser_PullPin_EnumMediaTypes, | |
| BasePinImpl_QueryInternalConnections, | |
| PullPin_EndOfStream, | |
| PullPin_BeginFlush, | |
| PullPin_EndFlush, | |
| PullPin_NewSegment | |
| }; |