| /* |
| * Implements IPin and IMemInputPin. (internal) |
| * |
| * hidenori@a2.ctktv.ne.jp |
| */ |
| |
| #include "config.h" |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wingdi.h" |
| #include "winuser.h" |
| #include "winerror.h" |
| #include "wine/obj_base.h" |
| #include "strmif.h" |
| #include "vfwmsgs.h" |
| #include "wine/unicode.h" |
| |
| #include "debugtools.h" |
| DEFAULT_DEBUG_CHANNEL(quartz); |
| |
| #include "quartz_private.h" |
| #include "basefilt.h" |
| #include "memalloc.h" |
| |
| |
| /*************************************************************************** |
| * |
| * CPinBaseImpl |
| * |
| */ |
| |
| static HRESULT WINAPI |
| CPinBaseImpl_fnQueryInterface(IPin* iface,REFIID riid,void** ppobj) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| |
| TRACE("(%p)->()\n",This); |
| |
| return IUnknown_QueryInterface(This->punkControl,riid,ppobj); |
| } |
| |
| static ULONG WINAPI |
| CPinBaseImpl_fnAddRef(IPin* iface) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| |
| TRACE("(%p)->()\n",This); |
| |
| return IUnknown_AddRef(This->punkControl); |
| } |
| |
| static ULONG WINAPI |
| CPinBaseImpl_fnRelease(IPin* iface) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| |
| TRACE("(%p)->()\n",This); |
| |
| return IUnknown_Release(This->punkControl); |
| } |
| |
| static HRESULT WINAPI |
| CPinBaseImpl_fnConnect(IPin* iface,IPin* pPin,const AM_MEDIA_TYPE* pmt) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| HRESULT hr = E_NOTIMPL; |
| ULONG i; |
| |
| FIXME("(%p)->(%p,%p) stub!\n",This,pPin,pmt); |
| |
| if ( !This->bOutput ) |
| return E_UNEXPECTED; |
| if ( pPin == NULL ) |
| return E_POINTER; |
| |
| TRACE("try to connect to %p\n",pPin); |
| |
| EnterCriticalSection( This->pcsPin ); |
| |
| if ( This->pPinConnectedTo != NULL ) |
| { |
| hr = VFW_E_ALREADY_CONNECTED; |
| goto err; |
| } |
| |
| /* FIXME - return fail if running */ |
| |
| if ( This->pHandlers->pOnPreConnect != NULL ) |
| { |
| hr = This->pHandlers->pOnPreConnect(This,pPin); |
| if ( FAILED(hr) ) |
| goto err; |
| } |
| |
| if ( pmt != NULL ) |
| { |
| hr = IPin_QueryAccept(iface,pmt); |
| if ( FAILED(hr) ) |
| goto err; |
| hr = IPin_ReceiveConnection(pPin,iface,pmt); |
| if ( FAILED(hr) ) |
| goto err; |
| } |
| else |
| { |
| for ( i = 0; i < This->cAcceptTypes; i++ ) |
| { |
| pmt = &This->pmtAcceptTypes[i]; |
| hr = IPin_QueryAccept(iface,pmt); |
| if ( SUCCEEDED(hr) ) |
| { |
| hr = IPin_ReceiveConnection(pPin,iface,pmt); |
| if ( SUCCEEDED(hr) ) |
| { |
| goto connected; |
| } |
| } |
| } |
| |
| hr = VFW_E_TYPE_NOT_ACCEPTED; |
| goto err; |
| } |
| |
| connected:; |
| This->pmtConn = QUARTZ_MediaType_Duplicate( pmt ); |
| if ( This->pmtConn == NULL ) |
| { |
| hr = E_OUTOFMEMORY; |
| IPin_Disconnect(pPin); |
| goto err; |
| } |
| |
| This->pPinConnectedTo = pPin; IPin_AddRef(pPin); |
| hr = IPin_QueryInterface(pPin,&IID_IMemInputPin,(void**)&This->pMemInputPinConnectedTo); |
| if ( FAILED(hr) ) |
| { |
| IPin_Disconnect(pPin); |
| goto err; |
| } |
| |
| if ( This->pHandlers->pOnPostConnect != NULL ) |
| { |
| hr = This->pHandlers->pOnPostConnect(This,pPin); |
| if ( FAILED(hr) ) |
| { |
| IPin_Disconnect(pPin); |
| goto err; |
| } |
| } |
| |
| hr = S_OK; |
| |
| err: |
| if ( FAILED(hr) ) |
| { |
| IPin_Disconnect(iface); |
| } |
| LeaveCriticalSection( This->pcsPin ); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| CPinBaseImpl_fnReceiveConnection(IPin* iface,IPin* pPin,const AM_MEDIA_TYPE* pmt) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| HRESULT hr = E_NOTIMPL; |
| |
| FIXME("(%p)->(%p,%p) stub!\n",This,pPin,pmt); |
| |
| if ( This->bOutput ) |
| return E_UNEXPECTED; |
| if ( pPin == NULL || pmt == NULL ) |
| return E_POINTER; |
| |
| EnterCriticalSection( This->pcsPin ); |
| |
| if ( This->pPinConnectedTo != NULL ) |
| { |
| hr = VFW_E_ALREADY_CONNECTED; |
| goto err; |
| } |
| |
| /* FIXME - return fail if running */ |
| |
| if ( This->pHandlers->pOnPreConnect != NULL ) |
| { |
| hr = This->pHandlers->pOnPreConnect(This,pPin); |
| if ( FAILED(hr) ) |
| goto err; |
| } |
| |
| hr = IPin_QueryAccept(iface,pmt); |
| if ( FAILED(hr) ) |
| goto err; |
| |
| This->pmtConn = QUARTZ_MediaType_Duplicate( pmt ); |
| if ( This->pmtConn == NULL ) |
| { |
| hr = E_OUTOFMEMORY; |
| goto err; |
| } |
| |
| if ( This->pHandlers->pOnPostConnect != NULL ) |
| { |
| hr = This->pHandlers->pOnPostConnect(This,pPin); |
| if ( FAILED(hr) ) |
| goto err; |
| } |
| |
| hr = S_OK; |
| This->pPinConnectedTo = pPin; IPin_AddRef(pPin); |
| |
| err: |
| if ( FAILED(hr) ) |
| IPin_Disconnect(iface); |
| LeaveCriticalSection( This->pcsPin ); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| CPinBaseImpl_fnDisconnect(IPin* iface) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| HRESULT hr = NOERROR; |
| |
| FIXME("(%p)->() stub!\n",This); |
| |
| EnterCriticalSection( This->pcsPin ); |
| |
| /* FIXME - return fail if running */ |
| |
| if ( This->pHandlers->pOnDisconnect != NULL ) |
| hr = This->pHandlers->pOnDisconnect(This); |
| |
| if ( This->pmtConn != NULL ) |
| { |
| QUARTZ_MediaType_Destroy( This->pmtConn ); |
| This->pmtConn = NULL; |
| } |
| if ( This->pMemInputPinConnectedTo != NULL ) |
| { |
| IMemInputPin_Release(This->pMemInputPinConnectedTo); |
| This->pMemInputPinConnectedTo = NULL; |
| } |
| if ( This->pPinConnectedTo != NULL ) |
| { |
| /* FIXME - cleanup */ |
| |
| IPin_Release(This->pPinConnectedTo); |
| This->pPinConnectedTo = NULL; |
| hr = NOERROR; |
| } |
| else |
| { |
| hr = S_FALSE; /* FIXME - is this correct??? */ |
| } |
| |
| LeaveCriticalSection( This->pcsPin ); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| CPinBaseImpl_fnConnectedTo(IPin* iface,IPin** ppPin) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| HRESULT hr = VFW_E_NOT_CONNECTED; |
| |
| TRACE("(%p)->(%p)\n",This,ppPin); |
| |
| if ( ppPin == NULL ) |
| return E_POINTER; |
| |
| EnterCriticalSection( This->pcsPin ); |
| |
| *ppPin = This->pPinConnectedTo; |
| if ( This->pPinConnectedTo != NULL ) |
| { |
| IPin_AddRef(This->pPinConnectedTo); |
| hr = NOERROR; |
| } |
| |
| LeaveCriticalSection( This->pcsPin ); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| CPinBaseImpl_fnConnectionMediaType(IPin* iface,AM_MEDIA_TYPE* pmt) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| HRESULT hr = E_FAIL; |
| |
| TRACE("(%p)->(%p)\n",This,pmt); |
| |
| if ( pmt == NULL ) |
| return E_POINTER; |
| |
| EnterCriticalSection( This->pcsPin ); |
| |
| if ( This->pmtConn != NULL ) |
| { |
| hr = QUARTZ_MediaType_Copy( pmt, This->pmtConn ); |
| } |
| else |
| { |
| ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) ); |
| pmt->bFixedSizeSamples = TRUE; |
| pmt->lSampleSize = 1; |
| hr = NOERROR; |
| } |
| |
| LeaveCriticalSection( This->pcsPin ); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| CPinBaseImpl_fnQueryPinInfo(IPin* iface,PIN_INFO* pinfo) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| |
| TRACE("(%p)->(%p)\n",This,pinfo); |
| |
| if ( pinfo == NULL ) |
| return E_POINTER; |
| |
| EnterCriticalSection( This->pcsPin ); |
| |
| ZeroMemory( pinfo, sizeof(PIN_INFO) ); |
| pinfo->pFilter = (IBaseFilter*)(This->pFilter); |
| if ( pinfo->pFilter != NULL ) |
| IBaseFilter_AddRef( pinfo->pFilter ); |
| pinfo->dir = This->bOutput ? PINDIR_OUTPUT : PINDIR_INPUT; |
| if ( This->cbIdLen <= sizeof(pinfo->achName) ) |
| memcpy( pinfo->achName, This->pwszId, This->cbIdLen ); |
| else |
| { |
| memcpy( pinfo->achName, This->pwszId, sizeof(pinfo->achName) ); |
| pinfo->achName[sizeof(pinfo->achName)/sizeof(pinfo->achName[0])-1] = 0; |
| } |
| |
| LeaveCriticalSection( This->pcsPin ); |
| |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI |
| CPinBaseImpl_fnQueryDirection(IPin* iface,PIN_DIRECTION* pdir) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| |
| TRACE("(%p)->(%p)\n",This,pdir); |
| |
| if ( pdir == NULL ) |
| return E_POINTER; |
| |
| *pdir = This->bOutput ? PINDIR_OUTPUT : PINDIR_INPUT; |
| |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI |
| CPinBaseImpl_fnQueryId(IPin* iface,LPWSTR* lpwszId) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| |
| TRACE("(%p)->(%p)\n",This,lpwszId); |
| |
| if ( lpwszId == NULL ) |
| return E_POINTER; |
| |
| *lpwszId = (WCHAR*)CoTaskMemAlloc( This->cbIdLen ); |
| if ( *lpwszId == NULL ) |
| return E_OUTOFMEMORY; |
| memcpy( *lpwszId, This->pwszId, This->cbIdLen ); |
| |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI |
| CPinBaseImpl_fnQueryAccept(IPin* iface,const AM_MEDIA_TYPE* pmt) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| HRESULT hr; |
| |
| TRACE("(%p)->(%p)\n",This,pmt); |
| |
| if ( pmt == NULL ) |
| return E_POINTER; |
| |
| hr = NOERROR; |
| EnterCriticalSection( This->pcsPin ); |
| if ( This->pHandlers->pCheckMediaType != NULL ) |
| hr = This->pHandlers->pCheckMediaType(This,pmt); |
| LeaveCriticalSection( This->pcsPin ); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| CPinBaseImpl_fnEnumMediaTypes(IPin* iface,IEnumMediaTypes** ppenum) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| HRESULT hr; |
| |
| TRACE("(%p)->(%p)\n",This,ppenum); |
| |
| if ( ppenum == NULL ) |
| return E_POINTER; |
| |
| hr = E_NOTIMPL; |
| |
| EnterCriticalSection( This->pcsPin ); |
| if ( This->cAcceptTypes > 0 ) |
| hr = QUARTZ_CreateEnumMediaTypes( |
| ppenum, This->pmtAcceptTypes, This->cAcceptTypes ); |
| LeaveCriticalSection( This->pcsPin ); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| CPinBaseImpl_fnQueryInternalConnections(IPin* iface,IPin** ppPin,ULONG* pul) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| |
| TRACE("(%p)->(%p,%p)\n",This,ppPin,pul); |
| |
| /* E_NOTIMPL means 'no internal connections'. */ |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI |
| CPinBaseImpl_fnEndOfStream(IPin* iface) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| HRESULT hr = E_NOTIMPL; |
| |
| TRACE("(%p)->()\n",This); |
| |
| if ( This->bOutput ) |
| return E_UNEXPECTED; |
| |
| EnterCriticalSection( This->pcsPin ); |
| if ( This->pHandlers->pEndOfStream != NULL ) |
| hr = This->pHandlers->pEndOfStream(This); |
| LeaveCriticalSection( This->pcsPin ); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| CPinBaseImpl_fnBeginFlush(IPin* iface) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| HRESULT hr = E_NOTIMPL; |
| |
| TRACE("(%p)->()\n",This); |
| |
| if ( This->bOutput ) |
| return E_UNEXPECTED; |
| |
| EnterCriticalSection( This->pcsPin ); |
| if ( This->pHandlers->pBeginFlush != NULL ) |
| hr = This->pHandlers->pBeginFlush(This); |
| LeaveCriticalSection( This->pcsPin ); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| CPinBaseImpl_fnEndFlush(IPin* iface) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| HRESULT hr = E_NOTIMPL; |
| |
| TRACE("(%p)->()\n",This); |
| |
| if ( This->bOutput ) |
| return E_UNEXPECTED; |
| |
| EnterCriticalSection( This->pcsPin ); |
| if ( This->pHandlers->pEndFlush != NULL ) |
| hr = This->pHandlers->pEndFlush(This); |
| LeaveCriticalSection( This->pcsPin ); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| CPinBaseImpl_fnNewSegment(IPin* iface,REFERENCE_TIME rtStart,REFERENCE_TIME rtStop,double rate) |
| { |
| ICOM_THIS(CPinBaseImpl,iface); |
| HRESULT hr = E_NOTIMPL; |
| |
| TRACE("(%p)->()\n",This); |
| |
| if ( This->bOutput ) |
| return E_UNEXPECTED; |
| |
| EnterCriticalSection( This->pcsPin ); |
| if ( This->pHandlers->pNewSegment != NULL ) |
| hr = This->pHandlers->pNewSegment(This,rtStart,rtStop,rate); |
| LeaveCriticalSection( This->pcsPin ); |
| |
| return hr; |
| } |
| |
| |
| |
| |
| static ICOM_VTABLE(IPin) ipin = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| /* IUnknown fields */ |
| CPinBaseImpl_fnQueryInterface, |
| CPinBaseImpl_fnAddRef, |
| CPinBaseImpl_fnRelease, |
| /* IPin fields */ |
| CPinBaseImpl_fnConnect, |
| CPinBaseImpl_fnReceiveConnection, |
| CPinBaseImpl_fnDisconnect, |
| CPinBaseImpl_fnConnectedTo, |
| CPinBaseImpl_fnConnectionMediaType, |
| CPinBaseImpl_fnQueryPinInfo, |
| CPinBaseImpl_fnQueryDirection, |
| CPinBaseImpl_fnQueryId, |
| CPinBaseImpl_fnQueryAccept, |
| CPinBaseImpl_fnEnumMediaTypes, |
| CPinBaseImpl_fnQueryInternalConnections, |
| CPinBaseImpl_fnEndOfStream, |
| CPinBaseImpl_fnBeginFlush, |
| CPinBaseImpl_fnEndFlush, |
| CPinBaseImpl_fnNewSegment, |
| }; |
| |
| |
| HRESULT CPinBaseImpl_InitIPin( |
| CPinBaseImpl* This, IUnknown* punkControl, |
| CRITICAL_SECTION* pcsPin, |
| CBaseFilterImpl* pFilter, LPCWSTR pwszId, |
| BOOL bOutput, |
| const CBasePinHandlers* pHandlers ) |
| { |
| HRESULT hr = NOERROR; |
| |
| TRACE("(%p,%p,%p)\n",This,punkControl,pFilter); |
| |
| if ( punkControl == NULL ) |
| { |
| ERR( "punkControl must not be NULL\n" ); |
| return E_INVALIDARG; |
| } |
| |
| ICOM_VTBL(This) = &ipin; |
| This->punkControl = punkControl; |
| This->pHandlers = pHandlers; |
| This->cbIdLen = sizeof(WCHAR)*(strlenW(pwszId)+1); |
| This->pwszId = NULL; |
| This->bOutput = bOutput; |
| This->pmtAcceptTypes = NULL; |
| This->cAcceptTypes = 0; |
| This->pcsPin = pcsPin; |
| This->pFilter = pFilter; |
| This->pPinConnectedTo = NULL; |
| This->pMemInputPinConnectedTo = NULL; |
| This->pmtConn = NULL; |
| This->pAsyncOut = NULL; |
| |
| This->pwszId = (WCHAR*)QUARTZ_AllocMem( This->cbIdLen ); |
| if ( This->pwszId == NULL ) |
| { |
| hr = E_OUTOFMEMORY; |
| goto err; |
| } |
| memcpy( This->pwszId, pwszId, This->cbIdLen ); |
| |
| return NOERROR; |
| |
| err:; |
| CPinBaseImpl_UninitIPin( This ); |
| return hr; |
| } |
| |
| void CPinBaseImpl_UninitIPin( CPinBaseImpl* This ) |
| { |
| TRACE("(%p)\n",This); |
| |
| IPin_Disconnect( (IPin*)(This) ); |
| |
| if ( This->pwszId != NULL ) |
| { |
| QUARTZ_FreeMem( This->pwszId ); |
| This->pwszId = NULL; |
| } |
| } |
| |
| |
| /*************************************************************************** |
| * |
| * CMemInputPinBaseImpl |
| * |
| */ |
| |
| |
| static HRESULT WINAPI |
| CMemInputPinBaseImpl_fnQueryInterface(IMemInputPin* iface,REFIID riid,void** ppobj) |
| { |
| ICOM_THIS(CMemInputPinBaseImpl,iface); |
| |
| TRACE("(%p)->()\n",This); |
| |
| return IUnknown_QueryInterface(This->punkControl,riid,ppobj); |
| } |
| |
| static ULONG WINAPI |
| CMemInputPinBaseImpl_fnAddRef(IMemInputPin* iface) |
| { |
| ICOM_THIS(CMemInputPinBaseImpl,iface); |
| |
| TRACE("(%p)->()\n",This); |
| |
| return IUnknown_AddRef(This->punkControl); |
| } |
| |
| static ULONG WINAPI |
| CMemInputPinBaseImpl_fnRelease(IMemInputPin* iface) |
| { |
| ICOM_THIS(CMemInputPinBaseImpl,iface); |
| |
| TRACE("(%p)->()\n",This); |
| |
| return IUnknown_Release(This->punkControl); |
| } |
| |
| |
| static HRESULT WINAPI |
| CMemInputPinBaseImpl_fnGetAllocator(IMemInputPin* iface,IMemAllocator** ppAllocator) |
| { |
| ICOM_THIS(CMemInputPinBaseImpl,iface); |
| HRESULT hr = NOERROR; |
| IUnknown* punk; |
| |
| TRACE("(%p)->()\n",This); |
| |
| if ( ppAllocator == NULL ) |
| return E_POINTER; |
| |
| EnterCriticalSection( This->pPin->pcsPin ); |
| |
| if ( This->pAllocator == NULL ) |
| { |
| hr = QUARTZ_CreateMemoryAllocator(NULL,(void**)&punk); |
| if ( hr == NOERROR ) |
| { |
| hr = IUnknown_QueryInterface(punk, |
| &IID_IMemAllocator,(void**)&This->pAllocator); |
| IUnknown_Release(punk); |
| } |
| } |
| |
| if ( hr == NOERROR ) |
| { |
| *ppAllocator = This->pAllocator; |
| IMemAllocator_AddRef(This->pAllocator); |
| } |
| |
| LeaveCriticalSection( This->pPin->pcsPin ); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| CMemInputPinBaseImpl_fnNotifyAllocator(IMemInputPin* iface,IMemAllocator* pAllocator,BOOL bReadonly) |
| { |
| ICOM_THIS(CMemInputPinBaseImpl,iface); |
| |
| TRACE("(%p)->()\n",This); |
| |
| if ( pAllocator == NULL ) |
| return E_POINTER; |
| |
| EnterCriticalSection( This->pPin->pcsPin ); |
| |
| if ( This->pAllocator != NULL ) |
| { |
| IMemAllocator_Release(This->pAllocator); |
| This->pAllocator = NULL; |
| } |
| This->pAllocator = pAllocator; |
| IMemAllocator_AddRef(This->pAllocator); |
| |
| This->bReadonly = bReadonly; |
| |
| LeaveCriticalSection( This->pPin->pcsPin ); |
| |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI |
| CMemInputPinBaseImpl_fnGetAllocatorRequirements(IMemInputPin* iface,ALLOCATOR_PROPERTIES* pProp) |
| { |
| ICOM_THIS(CMemInputPinBaseImpl,iface); |
| |
| TRACE("(%p)->(%p)\n",This,pProp); |
| |
| if ( pProp == NULL ) |
| return E_POINTER; |
| |
| /* E_MOTIMPL means 'no requirements' */ |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI |
| CMemInputPinBaseImpl_fnReceive(IMemInputPin* iface,IMediaSample* pSample) |
| { |
| ICOM_THIS(CMemInputPinBaseImpl,iface); |
| HRESULT hr = E_NOTIMPL; |
| |
| TRACE("(%p)->(%p)\n",This,pSample); |
| |
| EnterCriticalSection( This->pPin->pcsPin ); |
| if ( This->pPin->pHandlers->pReceive != NULL ) |
| hr = This->pPin->pHandlers->pReceive(This->pPin,pSample); |
| LeaveCriticalSection( This->pPin->pcsPin ); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| CMemInputPinBaseImpl_fnReceiveMultiple(IMemInputPin* iface,IMediaSample** ppSample,long nSample,long* pnSampleProcessed) |
| { |
| ICOM_THIS(CMemInputPinBaseImpl,iface); |
| long n; |
| HRESULT hr; |
| |
| TRACE("(%p)->()\n",This); |
| |
| if ( ppSample == NULL || pnSampleProcessed == NULL ) |
| return E_POINTER; |
| |
| EnterCriticalSection( This->pPin->pcsPin ); |
| |
| hr = NOERROR; |
| for ( n = 0; n < nSample; n++ ) |
| { |
| hr = IMemInputPin_Receive(iface,ppSample[n]); |
| if ( FAILED(hr) ) |
| break; |
| } |
| |
| LeaveCriticalSection( This->pPin->pcsPin ); |
| |
| *pnSampleProcessed = n; |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| CMemInputPinBaseImpl_fnReceiveCanBlock(IMemInputPin* iface) |
| { |
| ICOM_THIS(CMemInputPinBaseImpl,iface); |
| HRESULT hr = E_NOTIMPL; |
| |
| TRACE("(%p)->()\n",This); |
| |
| EnterCriticalSection( This->pPin->pcsPin ); |
| if ( This->pPin->pHandlers->pReceiveCanBlock != NULL ) |
| hr = This->pPin->pHandlers->pReceiveCanBlock(This->pPin); |
| LeaveCriticalSection( This->pPin->pcsPin ); |
| |
| return hr; |
| } |
| |
| |
| static ICOM_VTABLE(IMemInputPin) imeminputpin = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| /* IUnknown fields */ |
| CMemInputPinBaseImpl_fnQueryInterface, |
| CMemInputPinBaseImpl_fnAddRef, |
| CMemInputPinBaseImpl_fnRelease, |
| /* IMemInputPin fields */ |
| CMemInputPinBaseImpl_fnGetAllocator, |
| CMemInputPinBaseImpl_fnNotifyAllocator, |
| CMemInputPinBaseImpl_fnGetAllocatorRequirements, |
| CMemInputPinBaseImpl_fnReceive, |
| CMemInputPinBaseImpl_fnReceiveMultiple, |
| CMemInputPinBaseImpl_fnReceiveCanBlock, |
| }; |
| |
| HRESULT CMemInputPinBaseImpl_InitIMemInputPin( |
| CMemInputPinBaseImpl* This, IUnknown* punkControl, |
| CPinBaseImpl* pPin ) |
| { |
| TRACE("(%p,%p)\n",This,punkControl); |
| |
| if ( punkControl == NULL ) |
| { |
| ERR( "punkControl must not be NULL\n" ); |
| return E_INVALIDARG; |
| } |
| |
| ICOM_VTBL(This) = &imeminputpin; |
| This->punkControl = punkControl; |
| This->pPin = pPin; |
| This->pAllocator = NULL; |
| This->bReadonly = FALSE; |
| |
| return NOERROR; |
| } |
| |
| void CMemInputPinBaseImpl_UninitIMemInputPin( |
| CMemInputPinBaseImpl* This ) |
| { |
| TRACE("(%p)\n",This); |
| |
| if ( This->pAllocator != NULL ) |
| { |
| IMemAllocator_Release(This->pAllocator); |
| This->pAllocator = NULL; |
| } |
| } |
| |
| /*************************************************************************** |
| * |
| * CQualityControlPassThruImpl |
| * |
| */ |
| |
| static HRESULT WINAPI |
| CQualityControlPassThruImpl_fnQueryInterface(IQualityControl* iface,REFIID riid,void** ppobj) |
| { |
| ICOM_THIS(CQualityControlPassThruImpl,iface); |
| |
| TRACE("(%p)->()\n",This); |
| |
| return IUnknown_QueryInterface(This->punkControl,riid,ppobj); |
| } |
| |
| static ULONG WINAPI |
| CQualityControlPassThruImpl_fnAddRef(IQualityControl* iface) |
| { |
| ICOM_THIS(CQualityControlPassThruImpl,iface); |
| |
| TRACE("(%p)->()\n",This); |
| |
| return IUnknown_AddRef(This->punkControl); |
| } |
| |
| static ULONG WINAPI |
| CQualityControlPassThruImpl_fnRelease(IQualityControl* iface) |
| { |
| ICOM_THIS(CQualityControlPassThruImpl,iface); |
| |
| TRACE("(%p)->()\n",This); |
| |
| return IUnknown_Release(This->punkControl); |
| } |
| |
| |
| static HRESULT WINAPI |
| CQualityControlPassThruImpl_fnNotify(IQualityControl* iface,IBaseFilter* pFilter,Quality q) |
| { |
| ICOM_THIS(CQualityControlPassThruImpl,iface); |
| HRESULT hr = S_FALSE; |
| |
| TRACE("(%p)->()\n",This); |
| |
| if ( This->pControl != NULL ) |
| return IQualityControl_Notify( This->pControl, pFilter, q ); |
| |
| EnterCriticalSection( This->pPin->pcsPin ); |
| if ( This->pPin->pHandlers->pQualityNotify != NULL ) |
| hr = This->pPin->pHandlers->pQualityNotify(This->pPin,pFilter,q); |
| LeaveCriticalSection( This->pPin->pcsPin ); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| CQualityControlPassThruImpl_fnSetSink(IQualityControl* iface,IQualityControl* pControl) |
| { |
| ICOM_THIS(CQualityControlPassThruImpl,iface); |
| |
| TRACE("(%p)->()\n",This); |
| |
| This->pControl = pControl; /* AddRef() must not be called */ |
| |
| return NOERROR; |
| } |
| |
| static ICOM_VTABLE(IQualityControl) iqualitycontrol = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| /* IUnknown fields */ |
| CQualityControlPassThruImpl_fnQueryInterface, |
| CQualityControlPassThruImpl_fnAddRef, |
| CQualityControlPassThruImpl_fnRelease, |
| /* IQualityControl fields */ |
| CQualityControlPassThruImpl_fnNotify, |
| CQualityControlPassThruImpl_fnSetSink, |
| }; |
| |
| HRESULT CQualityControlPassThruImpl_InitIQualityControl( |
| CQualityControlPassThruImpl* This, IUnknown* punkControl, |
| CPinBaseImpl* pPin ) |
| { |
| TRACE("(%p,%p)\n",This,punkControl); |
| |
| if ( punkControl == NULL ) |
| { |
| ERR( "punkControl must not be NULL\n" ); |
| return E_INVALIDARG; |
| } |
| |
| ICOM_VTBL(This) = &iqualitycontrol; |
| This->punkControl = punkControl; |
| This->pPin = pPin; |
| |
| return NOERROR; |
| } |
| |
| void CQualityControlPassThruImpl_UninitIQualityControl( |
| CQualityControlPassThruImpl* This ) |
| { |
| } |
| |
| /*************************************************************************** |
| * |
| * helper methods for output pins. |
| * |
| */ |
| |
| HRESULT CPinBaseImpl_SendSample( CPinBaseImpl* This, IMediaSample* pSample ) |
| { |
| if ( This->pHandlers->pReceive == NULL ) |
| return E_NOTIMPL; |
| |
| return This->pHandlers->pReceive( This, pSample ); |
| } |
| |
| HRESULT CPinBaseImpl_SendEndOfStream( CPinBaseImpl* This ) |
| { |
| if ( This->pHandlers->pEndOfStream == NULL ) |
| return E_NOTIMPL; |
| |
| return This->pHandlers->pEndOfStream( This ); |
| } |
| |
| HRESULT CPinBaseImpl_SendBeginFlush( CPinBaseImpl* This ) |
| { |
| if ( This->pHandlers->pBeginFlush == NULL ) |
| return E_NOTIMPL; |
| |
| return This->pHandlers->pBeginFlush( This ); |
| } |
| |
| HRESULT CPinBaseImpl_SendEndFlush( CPinBaseImpl* This ) |
| { |
| if ( This->pHandlers->pEndFlush == NULL ) |
| return E_NOTIMPL; |
| |
| return This->pHandlers->pEndFlush( This ); |
| } |
| |
| HRESULT CPinBaseImpl_SendNewSegment( CPinBaseImpl* This, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate ) |
| { |
| if ( This->pHandlers->pNewSegment == NULL ) |
| return E_NOTIMPL; |
| |
| return This->pHandlers->pNewSegment( This, rtStart, rtStop, rate ); |
| } |
| |
| |
| |
| /*************************************************************************** |
| * |
| * handlers for output pins. |
| * |
| */ |
| |
| HRESULT OutputPinSync_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample ) |
| { |
| if ( pImpl->pMemInputPinConnectedTo == NULL ) |
| return E_UNEXPECTED; |
| |
| return IMemInputPin_Receive(pImpl->pMemInputPinConnectedTo,pSample); |
| } |
| |
| HRESULT OutputPinSync_ReceiveCanBlock( CPinBaseImpl* pImpl ) |
| { |
| if ( pImpl->pMemInputPinConnectedTo == NULL ) |
| return S_FALSE; |
| |
| return IMemInputPin_ReceiveCanBlock(pImpl->pMemInputPinConnectedTo); |
| } |
| |
| HRESULT OutputPinSync_EndOfStream( CPinBaseImpl* pImpl ) |
| { |
| if ( pImpl->pPinConnectedTo == NULL ) |
| return NOERROR; |
| |
| return IPin_EndOfStream(pImpl->pPinConnectedTo); |
| } |
| |
| HRESULT OutputPinSync_BeginFlush( CPinBaseImpl* pImpl ) |
| { |
| if ( pImpl->pPinConnectedTo == NULL ) |
| return NOERROR; |
| |
| return IPin_BeginFlush(pImpl->pPinConnectedTo); |
| } |
| |
| HRESULT OutputPinSync_EndFlush( CPinBaseImpl* pImpl ) |
| { |
| if ( pImpl->pPinConnectedTo == NULL ) |
| return NOERROR; |
| |
| return IPin_EndFlush(pImpl->pPinConnectedTo); |
| } |
| |
| HRESULT OutputPinSync_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate ) |
| { |
| if ( pImpl->pPinConnectedTo == NULL ) |
| return NOERROR; |
| |
| return IPin_NewSegment(pImpl->pPinConnectedTo,rtStart,rtStop,rate); |
| } |
| |
| /*************************************************************************** |
| * |
| * handlers for output pins (async). |
| * |
| */ |
| |
| typedef struct OutputPinTask OutputPinTask; |
| |
| enum OutputPinTaskType |
| { |
| OutTask_ExitThread, |
| OutTask_Receive, |
| OutTask_EndOfStream, |
| OutTask_BeginFlush, |
| OutTask_EndFlush, |
| OutTask_NewSegment, |
| }; |
| |
| struct OutputPinTask |
| { |
| OutputPinTask* pNext; |
| enum OutputPinTaskType tasktype; |
| IMediaSample* pSample; |
| REFERENCE_TIME rtStart; |
| REFERENCE_TIME rtStop; |
| double rate; |
| }; |
| |
| struct OutputPinAsyncImpl |
| { |
| HANDLE m_hTaskThread; |
| HANDLE m_hTaskEvent; |
| IPin* m_pPin; /* connected pin */ |
| IMemInputPin* m_pMemInputPin; /* connected pin */ |
| CRITICAL_SECTION m_csTasks; |
| OutputPinTask* m_pFirst; |
| OutputPinTask* m_pLast; |
| OutputPinTask* m_pTaskExitThread; |
| }; |
| |
| static OutputPinTask* OutputPinAsync_AllocTask( enum OutputPinTaskType tasktype ) |
| { |
| OutputPinTask* pTask; |
| |
| pTask = (OutputPinTask*)QUARTZ_AllocMem( sizeof(OutputPinTask) ); |
| pTask->pNext = NULL; |
| pTask->tasktype = tasktype; |
| pTask->pSample = NULL; |
| |
| return pTask; |
| } |
| |
| static void OutputPinAsync_FreeTask( OutputPinTask* pTask ) |
| { |
| if ( pTask->pSample != NULL ) |
| IMediaSample_Release( pTask->pSample ); |
| QUARTZ_FreeMem( pTask ); |
| } |
| |
| static void OutputPinAsync_AddTask( OutputPinAsyncImpl* This, OutputPinTask* pTask, BOOL bFirst ) |
| { |
| EnterCriticalSection( &This->m_csTasks ); |
| |
| if ( bFirst ) |
| { |
| pTask->pNext = This->m_pFirst; |
| This->m_pFirst = pTask; |
| if ( This->m_pLast == NULL ) |
| This->m_pLast = pTask; |
| } |
| else |
| { |
| if ( This->m_pLast != NULL ) |
| This->m_pLast->pNext = pTask; |
| else |
| This->m_pFirst = pTask; |
| This->m_pLast = pTask; |
| } |
| |
| LeaveCriticalSection( &This->m_csTasks ); |
| |
| SetEvent( This->m_hTaskEvent ); |
| } |
| |
| static OutputPinTask* OutputPinAsync_GetNextTask( OutputPinAsyncImpl* This ) |
| { |
| OutputPinTask* pTask; |
| |
| EnterCriticalSection( &This->m_csTasks ); |
| pTask = This->m_pFirst; |
| if ( pTask != NULL ) |
| { |
| This->m_pFirst = pTask->pNext; |
| if ( This->m_pFirst == NULL ) |
| This->m_pLast = NULL; |
| else |
| SetEvent( This->m_hTaskEvent ); |
| } |
| |
| LeaveCriticalSection( &This->m_csTasks ); |
| |
| return pTask; |
| } |
| |
| static DWORD WINAPI OutputPinAsync_ThreadEntry( LPVOID pv ) |
| { |
| OutputPinAsyncImpl* This = ((CPinBaseImpl*)pv)->pAsyncOut; |
| OutputPinTask* pTask; |
| BOOL bLoop = TRUE; |
| BOOL bInFlush = FALSE; |
| HRESULT hr; |
| |
| while ( bLoop ) |
| { |
| WaitForSingleObject( This->m_hTaskEvent, INFINITE ); |
| ResetEvent( This->m_hTaskEvent ); |
| |
| pTask = OutputPinAsync_GetNextTask( This ); |
| if ( pTask == NULL ) |
| continue; |
| |
| hr = S_OK; |
| switch ( pTask->tasktype ) |
| { |
| case OutTask_ExitThread: |
| bLoop = FALSE; |
| break; |
| case OutTask_Receive: |
| if ( !bInFlush ) |
| hr = IMemInputPin_Receive( This->m_pMemInputPin, pTask->pSample ); |
| break; |
| case OutTask_EndOfStream: |
| hr = IPin_EndOfStream( This->m_pPin ); |
| break; |
| case OutTask_BeginFlush: |
| bInFlush = TRUE; |
| hr = IPin_BeginFlush( This->m_pPin ); |
| break; |
| case OutTask_EndFlush: |
| bInFlush = FALSE; |
| hr = IPin_EndFlush( This->m_pPin ); |
| break; |
| case OutTask_NewSegment: |
| hr = IPin_NewSegment( This->m_pPin, pTask->rtStart, pTask->rtStop, pTask->rate ); |
| break; |
| default: |
| ERR( "unexpected task type %d.\n", pTask->tasktype ); |
| bLoop = FALSE; |
| break; |
| } |
| |
| OutputPinAsync_FreeTask( pTask ); |
| |
| if ( FAILED(hr) ) |
| { |
| ERR( "hresult %08lx\n", hr ); |
| bLoop = FALSE; |
| } |
| } |
| |
| return 0; |
| } |
| |
| HRESULT OutputPinAsync_OnActive( CPinBaseImpl* pImpl ) |
| { |
| HRESULT hr; |
| DWORD dwThreadId; |
| |
| FIXME("(%p)\n",pImpl); |
| |
| if ( pImpl->pMemInputPinConnectedTo == NULL ) |
| return NOERROR; |
| |
| pImpl->pAsyncOut = (OutputPinAsyncImpl*) |
| QUARTZ_AllocMem( sizeof( OutputPinAsyncImpl ) ); |
| if ( pImpl->pAsyncOut == NULL ) |
| return E_OUTOFMEMORY; |
| |
| InitializeCriticalSection( &pImpl->pAsyncOut->m_csTasks ); |
| pImpl->pAsyncOut->m_hTaskThread = (HANDLE)NULL; |
| pImpl->pAsyncOut->m_hTaskEvent = (HANDLE)NULL; |
| pImpl->pAsyncOut->m_pFirst = NULL; |
| pImpl->pAsyncOut->m_pLast = NULL; |
| pImpl->pAsyncOut->m_pTaskExitThread = NULL; |
| pImpl->pAsyncOut->m_pPin = pImpl->pPinConnectedTo; |
| pImpl->pAsyncOut->m_pMemInputPin = pImpl->pMemInputPinConnectedTo; |
| |
| pImpl->pAsyncOut->m_hTaskEvent = |
| CreateEventA( NULL, TRUE, FALSE, NULL ); |
| if ( pImpl->pAsyncOut->m_hTaskEvent == (HANDLE)NULL ) |
| { |
| hr = E_FAIL; |
| goto err; |
| } |
| |
| pImpl->pAsyncOut->m_pTaskExitThread = |
| OutputPinAsync_AllocTask( OutTask_ExitThread ); |
| if ( pImpl->pAsyncOut->m_pTaskExitThread == NULL ) |
| { |
| hr = E_OUTOFMEMORY; |
| goto err; |
| } |
| |
| pImpl->pAsyncOut->m_hTaskThread = CreateThread( |
| NULL, 0, OutputPinAsync_ThreadEntry, pImpl, |
| 0, &dwThreadId ); |
| if ( pImpl->pAsyncOut->m_hTaskThread == (HANDLE)NULL ) |
| { |
| hr = E_FAIL; |
| goto err; |
| } |
| |
| return NOERROR; |
| err: |
| OutputPinAsync_OnInactive( pImpl ); |
| return hr; |
| } |
| |
| HRESULT OutputPinAsync_OnInactive( CPinBaseImpl* pImpl ) |
| { |
| OutputPinTask* pTask; |
| |
| FIXME("(%p)\n",pImpl); |
| |
| if ( pImpl->pAsyncOut == NULL ) |
| return NOERROR; |
| |
| if ( pImpl->pAsyncOut->m_pTaskExitThread != NULL ) |
| { |
| OutputPinAsync_AddTask( pImpl->pAsyncOut, pImpl->pAsyncOut->m_pTaskExitThread, TRUE ); |
| pImpl->pAsyncOut->m_pTaskExitThread = NULL; |
| } |
| |
| if ( pImpl->pAsyncOut->m_hTaskThread != (HANDLE)NULL ) |
| { |
| WaitForSingleObject( pImpl->pAsyncOut->m_hTaskThread, INFINITE ); |
| CloseHandle( pImpl->pAsyncOut->m_hTaskThread ); |
| } |
| if ( pImpl->pAsyncOut->m_hTaskEvent != (HANDLE)NULL ) |
| CloseHandle( pImpl->pAsyncOut->m_hTaskEvent ); |
| |
| /* release all tasks. */ |
| while ( 1 ) |
| { |
| pTask = OutputPinAsync_GetNextTask( pImpl->pAsyncOut ); |
| if ( pTask == NULL ) |
| break; |
| OutputPinAsync_FreeTask( pTask ); |
| } |
| |
| DeleteCriticalSection( &pImpl->pAsyncOut->m_csTasks ); |
| |
| QUARTZ_FreeMem( pImpl->pAsyncOut ); |
| pImpl->pAsyncOut = NULL; |
| |
| return NOERROR; |
| } |
| |
| HRESULT OutputPinAsync_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample ) |
| { |
| OutputPinAsyncImpl* This = pImpl->pAsyncOut; |
| OutputPinTask* pTask; |
| |
| TRACE("(%p,%p)\n",pImpl,pSample); |
| |
| if ( This == NULL ) |
| return NOERROR; |
| |
| pTask = OutputPinAsync_AllocTask( OutTask_Receive ); |
| if ( pTask == NULL ) |
| return E_OUTOFMEMORY; |
| pTask->pSample = pSample; IMediaSample_AddRef( pSample ); |
| OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE ); |
| |
| return NOERROR; |
| } |
| |
| HRESULT OutputPinAsync_ReceiveCanBlock( CPinBaseImpl* pImpl ) |
| { |
| return S_FALSE; |
| } |
| |
| HRESULT OutputPinAsync_EndOfStream( CPinBaseImpl* pImpl ) |
| { |
| OutputPinAsyncImpl* This = pImpl->pAsyncOut; |
| OutputPinTask* pTask; |
| |
| TRACE("(%p)\n",pImpl); |
| |
| if ( This == NULL ) |
| return NOERROR; |
| |
| pTask = OutputPinAsync_AllocTask( OutTask_EndOfStream ); |
| if ( pTask == NULL ) |
| return E_OUTOFMEMORY; |
| OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE ); |
| |
| return NOERROR; |
| } |
| |
| HRESULT OutputPinAsync_BeginFlush( CPinBaseImpl* pImpl ) |
| { |
| OutputPinAsyncImpl* This = pImpl->pAsyncOut; |
| OutputPinTask* pTask; |
| |
| TRACE("(%p)\n",pImpl); |
| |
| if ( This == NULL ) |
| return NOERROR; |
| |
| pTask = OutputPinAsync_AllocTask( OutTask_BeginFlush ); |
| if ( pTask == NULL ) |
| return E_OUTOFMEMORY; |
| OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, TRUE ); |
| |
| return NOERROR; |
| } |
| |
| HRESULT OutputPinAsync_EndFlush( CPinBaseImpl* pImpl ) |
| { |
| OutputPinAsyncImpl* This = pImpl->pAsyncOut; |
| OutputPinTask* pTask; |
| |
| TRACE("(%p)\n",pImpl); |
| |
| if ( This == NULL ) |
| return NOERROR; |
| |
| pTask = OutputPinAsync_AllocTask( OutTask_EndFlush ); |
| if ( pTask == NULL ) |
| return E_OUTOFMEMORY; |
| OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE ); |
| |
| return NOERROR; |
| } |
| |
| HRESULT OutputPinAsync_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate ) |
| { |
| OutputPinAsyncImpl* This = pImpl->pAsyncOut; |
| OutputPinTask* pTask; |
| |
| TRACE("(%p)\n",pImpl); |
| |
| if ( This == NULL ) |
| return NOERROR; |
| |
| pTask = OutputPinAsync_AllocTask( OutTask_NewSegment ); |
| if ( pTask == NULL ) |
| return E_OUTOFMEMORY; |
| pTask->rtStart = rtStart; |
| pTask->rtStop = rtStop; |
| pTask->rate = rate; |
| OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE ); |
| |
| return NOERROR; |
| } |
| |
| |