| /* |
| * 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; |
| |
| 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; |
| |
| 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) |
| { |
| assert(IPin_Disconnect(connected) == S_OK); |
| IPin_Release(connected); |
| assert(IPin_Disconnect(&This->pInputPin->pin.IPin_iface) == 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); |
| |
| TRACE("Destroying parser\n"); |
| CoTaskMemFree(This); |
| } |
| |
| ULONG WINAPI Parser_Release(IBaseFilter * iface) |
| { |
| ParserImpl *This = impl_from_IBaseFilter(iface); |
| ULONG refCount = BaseFilterImpl_Release(iface); |
| |
| 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 BasePinFuncTable output_BaseFuncTable = { |
| NULL, |
| BaseOutputPinImpl_AttemptConnection, |
| BasePinImpl_GetMediaTypeVersion, |
| Parser_OutputPin_GetMediaType |
| }; |
| |
| static const BaseOutputPinFuncTable output_BaseOutputFuncTable = { |
| 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_BaseFuncTable, &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 = (LPVOID)This; |
| 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 IUnknown_QueryInterface((IUnknown *)This, riid, ppv); |
| } |
| |
| static ULONG WINAPI Parser_Seeking_AddRef(IMediaSeeking * iface) |
| { |
| ParserImpl *This = impl_from_IMediaSeeking(iface); |
| |
| return IUnknown_AddRef((IUnknown *)This); |
| } |
| |
| static ULONG WINAPI Parser_Seeking_Release(IMediaSeeking * iface) |
| { |
| ParserImpl *This = impl_from_IMediaSeeking(iface); |
| |
| return IUnknown_Release((IUnknown *)This); |
| } |
| |
| 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); |
| 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); |
| 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 |
| }; |