| /* |
| * Implements IBaseFilter for transform filters. (internal) |
| * |
| * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp> |
| * |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| |
| #include "config.h" |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wingdi.h" |
| #include "winuser.h" |
| #include "winerror.h" |
| #include "strmif.h" |
| #include "control.h" |
| #include "vfwmsgs.h" |
| #include "uuids.h" |
| |
| #include "wine/debug.h" |
| WINE_DEFAULT_DEBUG_CHANNEL(quartz); |
| |
| #include "quartz_private.h" |
| #include "xform.h" |
| #include "sample.h" |
| |
| |
| static const WCHAR XFORM_DefInName[] = |
| {'X','F','o','r','m',' ','I','n',0}; |
| static const WCHAR XFORM_DefOutName[] = |
| {'X','F','o','r','m',' ','O','u','t',0}; |
| |
| /*************************************************************************** |
| * |
| * CTransformBaseImpl methods |
| * |
| */ |
| |
| static HRESULT CTransformBaseImpl_OnActive( CBaseFilterImpl* pImpl ) |
| { |
| CTransformBaseImpl_THIS(pImpl,basefilter); |
| |
| TRACE( "(%p)\n", This ); |
| |
| return NOERROR; |
| } |
| |
| static HRESULT CTransformBaseImpl_OnInactive( CBaseFilterImpl* pImpl ) |
| { |
| CTransformBaseImpl_THIS(pImpl,basefilter); |
| HRESULT hr; |
| IMemAllocator* pAllocator; |
| |
| TRACE( "(%p)\n", This ); |
| |
| if ( This->pInPin->pin.pPinConnectedTo == NULL || |
| This->pOutPin->pin.pPinConnectedTo == NULL ) |
| return NOERROR; |
| |
| EnterCriticalSection( &This->basefilter.csFilter ); |
| |
| pAllocator = This->m_pOutPinAllocator; |
| if ( pAllocator != NULL && |
| This->pInPin->meminput.pAllocator != pAllocator ) |
| { |
| hr = IMemAllocator_Commit( pAllocator ); |
| if ( FAILED(hr) ) |
| goto end; |
| } |
| |
| if ( !This->m_bFiltering ) |
| { |
| hr = This->m_pHandler->pBeginTransform( This, This->pInPin->pin.pmtConn, This->pOutPin->pin.pmtConn, This->m_bReuseSample ); |
| if ( FAILED(hr) ) |
| goto end; |
| This->m_bFiltering = TRUE; |
| } |
| |
| hr = NOERROR; |
| end: |
| LeaveCriticalSection( &This->basefilter.csFilter ); |
| |
| return hr; |
| } |
| |
| static HRESULT CTransformBaseImpl_OnStop( CBaseFilterImpl* pImpl ) |
| { |
| CTransformBaseImpl_THIS(pImpl,basefilter); |
| IMemAllocator* pAllocator; |
| |
| TRACE( "(%p)\n", This ); |
| |
| EnterCriticalSection( &This->basefilter.csFilter ); |
| |
| if ( This->m_bFiltering ) |
| { |
| This->m_pHandler->pEndTransform( This ); |
| This->m_bFiltering = FALSE; |
| } |
| if ( This->m_pSample != NULL ) |
| { |
| IMediaSample_Release( This->m_pSample ); |
| This->m_pSample = NULL; |
| } |
| |
| pAllocator = This->m_pOutPinAllocator; |
| if ( pAllocator != NULL && |
| This->pInPin->meminput.pAllocator != pAllocator ) |
| { |
| IMemAllocator_Decommit( pAllocator ); |
| } |
| |
| LeaveCriticalSection( &This->basefilter.csFilter ); |
| |
| return NOERROR; |
| } |
| |
| static const CBaseFilterHandlers filterhandlers = |
| { |
| CTransformBaseImpl_OnActive, /* pOnActive */ |
| CTransformBaseImpl_OnInactive, /* pOnInactive */ |
| CTransformBaseImpl_OnStop, /* pOnStop */ |
| }; |
| |
| /*************************************************************************** |
| * |
| * CTransformBaseInPinImpl methods |
| * |
| */ |
| |
| static HRESULT CTransformBaseInPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin ) |
| { |
| CTransformBaseInPinImpl_THIS(pImpl,pin); |
| HRESULT hr; |
| |
| TRACE( "(%p,%p)\n", This, pPin ); |
| |
| EnterCriticalSection( &This->pFilter->basefilter.csFilter ); |
| hr = This->pFilter->m_pHandler->pGetOutputTypes( This->pFilter, This->pFilter->pInPin->pin.pmtConn, &This->pFilter->pOutPin->pin.pmtAcceptTypes, &This->pFilter->pOutPin->pin.cAcceptTypes ); |
| if ( FAILED(hr) ) |
| goto end; |
| |
| hr = NOERROR; |
| end: |
| LeaveCriticalSection( &This->pFilter->basefilter.csFilter ); |
| |
| return hr; |
| } |
| |
| static HRESULT CTransformBaseInPinImpl_OnDisconnect( CPinBaseImpl* pImpl ) |
| { |
| CTransformBaseInPinImpl_THIS(pImpl,pin); |
| |
| TRACE( "(%p)\n", This ); |
| |
| if ( This->meminput.pAllocator != NULL ) |
| { |
| IMemAllocator_Decommit(This->meminput.pAllocator); |
| IMemAllocator_Release(This->meminput.pAllocator); |
| This->meminput.pAllocator = NULL; |
| } |
| |
| return NOERROR; |
| } |
| |
| static HRESULT CTransformBaseInPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt ) |
| { |
| CTransformBaseInPinImpl_THIS(pImpl,pin); |
| HRESULT hr; |
| |
| TRACE( "(%p,%p)\n", This, pmt ); |
| |
| EnterCriticalSection( &This->pFilter->basefilter.csFilter ); |
| hr = This->pFilter->m_pHandler->pCheckMediaType( This->pFilter, pmt, (This->pFilter->pOutPin->pin.pPinConnectedTo != NULL) ? This->pFilter->pOutPin->pin.pmtConn : NULL ); |
| LeaveCriticalSection( &This->pFilter->basefilter.csFilter ); |
| |
| return hr; |
| } |
| |
| static HRESULT CTransformBaseInPinImpl_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample ) |
| { |
| CTransformBaseInPinImpl_THIS(pImpl,pin); |
| HRESULT hr; |
| |
| TRACE( "(%p,%p)\n", This, pSample ); |
| |
| if ( This->pin.pPinConnectedTo == NULL || |
| This->pFilter->pOutPin->pin.pPinConnectedTo == NULL ) |
| return NOERROR; |
| |
| if ( !This->pFilter->m_bFiltering ) |
| return E_UNEXPECTED; |
| |
| if ( This->pFilter->m_bInFlush ) |
| return S_FALSE; |
| |
| if ( This->pFilter->m_pHandler->pProcessReceive != NULL ) |
| { |
| hr = This->pFilter->m_pHandler->pProcessReceive( This->pFilter, pSample ); |
| } |
| else |
| { |
| if ( This->meminput.pAllocator != This->pFilter->m_pOutPinAllocator ) |
| { |
| if ( This->pFilter->m_pSample == NULL ) |
| { |
| hr = IMemAllocator_GetBuffer( This->pFilter->m_pOutPinAllocator, &This->pFilter->m_pSample, NULL, NULL, 0 ); |
| if ( FAILED(hr) ) |
| goto end; |
| } |
| hr = QUARTZ_IMediaSample_Copy( |
| This->pFilter->m_pSample, pSample, This->pFilter->m_bPreCopy ); |
| if ( FAILED(hr) ) |
| goto end; |
| } |
| |
| if ( This->pFilter->m_bPreCopy ) |
| hr = This->pFilter->m_pHandler->pTransform( This->pFilter, This->pFilter->m_pSample, NULL ); |
| else |
| hr = This->pFilter->m_pHandler->pTransform( This->pFilter, pSample, This->pFilter->m_pSample ); |
| |
| if ( FAILED(hr) ) |
| goto end; |
| |
| if ( hr == NOERROR ) |
| { |
| hr = CPinBaseImpl_SendSample(&This->pFilter->pOutPin->pin,This->pFilter->m_pSample); |
| if ( FAILED(hr) ) |
| goto end; |
| } |
| |
| hr = NOERROR; |
| end: |
| if ( !This->pFilter->m_bReuseSample ) |
| { |
| if ( This->pFilter->m_pSample != NULL ) |
| { |
| IMediaSample_Release( This->pFilter->m_pSample ); |
| This->pFilter->m_pSample = NULL; |
| } |
| } |
| |
| if ( FAILED(hr) ) |
| { |
| /* Notify(ABORT) */ |
| } |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT CTransformBaseInPinImpl_ReceiveCanBlock( CPinBaseImpl* pImpl ) |
| { |
| CTransformBaseInPinImpl_THIS(pImpl,pin); |
| |
| TRACE( "(%p)\n", This ); |
| |
| if ( This->pin.pPinConnectedTo == NULL || |
| This->pFilter->pOutPin->pin.pPinConnectedTo == NULL ) |
| return S_FALSE; |
| |
| return CPinBaseImpl_SendReceiveCanBlock( &This->pFilter->pOutPin->pin ); |
| } |
| |
| static HRESULT CTransformBaseInPinImpl_EndOfStream( CPinBaseImpl* pImpl ) |
| { |
| CTransformBaseInPinImpl_THIS(pImpl,pin); |
| |
| TRACE( "(%p)\n", This ); |
| |
| if ( This->pin.pPinConnectedTo == NULL || |
| This->pFilter->pOutPin->pin.pPinConnectedTo == NULL ) |
| return NOERROR; |
| |
| return CPinBaseImpl_SendEndOfStream( &This->pFilter->pOutPin->pin ); |
| } |
| |
| static HRESULT CTransformBaseInPinImpl_BeginFlush( CPinBaseImpl* pImpl ) |
| { |
| CTransformBaseInPinImpl_THIS(pImpl,pin); |
| |
| TRACE( "(%p)\n", This ); |
| |
| if ( This->pin.pPinConnectedTo == NULL || |
| This->pFilter->pOutPin->pin.pPinConnectedTo == NULL ) |
| return NOERROR; |
| |
| This->pFilter->m_bInFlush = TRUE; |
| |
| return CPinBaseImpl_SendBeginFlush( &This->pFilter->pOutPin->pin ); |
| } |
| |
| static HRESULT CTransformBaseInPinImpl_EndFlush( CPinBaseImpl* pImpl ) |
| { |
| CTransformBaseInPinImpl_THIS(pImpl,pin); |
| |
| TRACE( "(%p)\n", This ); |
| |
| if ( This->pin.pPinConnectedTo == NULL || |
| This->pFilter->pOutPin->pin.pPinConnectedTo == NULL ) |
| return NOERROR; |
| |
| This->pFilter->m_bInFlush = FALSE; |
| |
| return CPinBaseImpl_SendEndFlush( &This->pFilter->pOutPin->pin ); |
| } |
| |
| static HRESULT CTransformBaseInPinImpl_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate ) |
| { |
| CTransformBaseInPinImpl_THIS(pImpl,pin); |
| |
| FIXME( "(%p)\n", This ); |
| |
| if ( This->pin.pPinConnectedTo == NULL || |
| This->pFilter->pOutPin->pin.pPinConnectedTo == NULL ) |
| return NOERROR; |
| |
| return CPinBaseImpl_SendNewSegment( &This->pFilter->pOutPin->pin, |
| rtStart, rtStop, rate ); |
| } |
| |
| static const CBasePinHandlers inputpinhandlers = |
| { |
| NULL, /* pOnPreConnect */ |
| CTransformBaseInPinImpl_OnPostConnect, /* pOnPostConnect */ |
| CTransformBaseInPinImpl_OnDisconnect, /* pOnDisconnect */ |
| CTransformBaseInPinImpl_CheckMediaType, /* pCheckMediaType */ |
| NULL, /* pQualityNotify */ |
| CTransformBaseInPinImpl_Receive, /* pReceive */ |
| CTransformBaseInPinImpl_ReceiveCanBlock, /* pReceiveCanBlock */ |
| CTransformBaseInPinImpl_EndOfStream, /* pEndOfStream */ |
| CTransformBaseInPinImpl_BeginFlush, /* pBeginFlush */ |
| CTransformBaseInPinImpl_EndFlush, /* pEndFlush */ |
| CTransformBaseInPinImpl_NewSegment, /* pNewSegment */ |
| }; |
| |
| /*************************************************************************** |
| * |
| * CTransformBaseOutPinImpl methods |
| * |
| */ |
| |
| static HRESULT CTransformBaseOutPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin ) |
| { |
| CTransformBaseOutPinImpl_THIS(pImpl,pin); |
| HRESULT hr; |
| ALLOCATOR_PROPERTIES propReqThis; |
| ALLOCATOR_PROPERTIES propReqPeer; |
| ALLOCATOR_PROPERTIES propActual; |
| BOOL bTransInPlace = FALSE; |
| BOOL bTryToReUseSample = FALSE; |
| BOOL bOutReadonly = FALSE; |
| IMemAllocator* pAllocator; |
| |
| FIXME( "(%p,%p)\n", This, pPin ); |
| |
| if ( This->pFilter->pInPin->pin.pPinConnectedTo == NULL ) |
| return E_FAIL; |
| if ( This->pin.pMemInputPinConnectedTo == NULL ) |
| return E_UNEXPECTED; |
| |
| ZeroMemory( &propReqThis, sizeof(ALLOCATOR_PROPERTIES) ); |
| ZeroMemory( &propReqPeer, sizeof(ALLOCATOR_PROPERTIES) ); |
| ZeroMemory( &propActual, sizeof(ALLOCATOR_PROPERTIES) ); |
| |
| hr = This->pFilter->m_pHandler->pGetAllocProp( This->pFilter, This->pFilter->pInPin->pin.pmtConn, This->pin.pmtConn, &propReqThis, &bTransInPlace, &bTryToReUseSample ); |
| if ( FAILED(hr) ) |
| goto end; |
| |
| if ( propReqThis.cbAlign == 0 ) |
| propReqThis.cbAlign = 1; |
| |
| if ( bTransInPlace ) |
| { |
| ZeroMemory( &propReqPeer, sizeof(ALLOCATOR_PROPERTIES) ); |
| hr = IMemInputPin_GetAllocatorRequirements( |
| This->pin.pMemInputPinConnectedTo, &propReqPeer ); |
| if ( propReqPeer.cbAlign != 0 && propReqPeer.cbAlign != 1 ) |
| bTransInPlace = FALSE; |
| if ( propReqPeer.cbPrefix != 0 ) |
| bTransInPlace = FALSE; |
| |
| bOutReadonly = FALSE; |
| if ( bTransInPlace && This->pFilter->pInPin->meminput.bReadonly ) |
| bOutReadonly = TRUE; |
| |
| pAllocator = This->pFilter->pInPin->meminput.pAllocator; |
| |
| hr = IMemInputPin_NotifyAllocator( |
| This->pin.pMemInputPinConnectedTo, |
| pAllocator, bOutReadonly ); |
| if ( hr == NOERROR ) |
| { |
| This->pFilter->m_pOutPinAllocator = pAllocator; |
| IMemAllocator_AddRef(pAllocator); |
| bTryToReUseSample = FALSE; |
| goto end; |
| } |
| } |
| |
| hr = IMemInputPin_GetAllocator( |
| This->pin.pMemInputPinConnectedTo, &pAllocator ); |
| if ( FAILED(hr) ) |
| goto end; |
| hr = IMemAllocator_SetProperties( pAllocator, &propReqThis, &propActual ); |
| if ( SUCCEEDED(hr) ) |
| { |
| TRACE("cBuffers = %ld / cbBuffer = %ld\n",propActual.cBuffers,propActual.cbBuffer); |
| hr = IMemInputPin_NotifyAllocator( |
| This->pin.pMemInputPinConnectedTo, pAllocator, |
| bTryToReUseSample ); |
| } |
| if ( FAILED(hr) ) |
| { |
| IMemAllocator_Release(pAllocator); |
| goto end; |
| } |
| This->pFilter->m_pOutPinAllocator = pAllocator; |
| |
| hr = NOERROR; |
| end: |
| This->pFilter->m_bPreCopy = FALSE; |
| This->pFilter->m_bReuseSample = FALSE; |
| if ( hr == NOERROR ) |
| { |
| This->pFilter->m_bPreCopy = bTransInPlace && (This->pFilter->pInPin->meminput.pAllocator != This->pFilter->m_pOutPinAllocator); |
| This->pFilter->m_bReuseSample = bTryToReUseSample; |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT CTransformBaseOutPinImpl_OnDisconnect( CPinBaseImpl* pImpl ) |
| { |
| CTransformBaseOutPinImpl_THIS(pImpl,pin); |
| |
| TRACE( "(%p)\n", This ); |
| |
| if ( This->pFilter->m_pOutPinAllocator != NULL ) |
| { |
| IMemAllocator_Decommit(This->pFilter->m_pOutPinAllocator); |
| IMemAllocator_Release(This->pFilter->m_pOutPinAllocator); |
| This->pFilter->m_pOutPinAllocator = NULL; |
| } |
| |
| return NOERROR; |
| } |
| |
| static HRESULT CTransformBaseOutPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt ) |
| { |
| CTransformBaseOutPinImpl_THIS(pImpl,pin); |
| HRESULT hr; |
| |
| TRACE( "(%p,%p)\n", This, pmt ); |
| |
| if ( This->pFilter->pInPin->pin.pPinConnectedTo == NULL ) |
| return E_FAIL; |
| |
| EnterCriticalSection( &This->pFilter->basefilter.csFilter ); |
| hr = This->pFilter->m_pHandler->pCheckMediaType( This->pFilter, This->pFilter->pInPin->pin.pmtConn, pmt ); |
| LeaveCriticalSection( &This->pFilter->basefilter.csFilter ); |
| |
| return hr; |
| } |
| |
| static const CBasePinHandlers outputpinhandlers = |
| { |
| NULL, /* pOnPreConnect */ |
| CTransformBaseOutPinImpl_OnPostConnect, /* pOnPostConnect */ |
| CTransformBaseOutPinImpl_OnDisconnect, /* pOnDisconnect */ |
| CTransformBaseOutPinImpl_CheckMediaType, /* pCheckMediaType */ |
| NULL, /* pQualityNotify */ |
| OutputPinSync_Receive, /* pReceive */ |
| OutputPinSync_ReceiveCanBlock, /* pReceiveCanBlock */ |
| OutputPinSync_EndOfStream, /* pEndOfStream */ |
| OutputPinSync_BeginFlush, /* pBeginFlush */ |
| OutputPinSync_EndFlush, /* pEndFlush */ |
| OutputPinSync_NewSegment, /* pNewSegment */ |
| }; |
| |
| |
| /*************************************************************************** |
| * |
| * new/delete CTransformBaseImpl |
| * |
| */ |
| |
| /* can I use offsetof safely? - FIXME? */ |
| static QUARTZ_IFEntry FilterIFEntries[] = |
| { |
| { &IID_IPersist, offsetof(CTransformBaseImpl,basefilter)-offsetof(CTransformBaseImpl,unk) }, |
| { &IID_IMediaFilter, offsetof(CTransformBaseImpl,basefilter)-offsetof(CTransformBaseImpl,unk) }, |
| { &IID_IBaseFilter, offsetof(CTransformBaseImpl,basefilter)-offsetof(CTransformBaseImpl,unk) }, |
| }; |
| |
| static void QUARTZ_DestroyTransformBase(IUnknown* punk) |
| { |
| CTransformBaseImpl_THIS(punk,unk); |
| |
| TRACE( "(%p)\n", This ); |
| |
| This->m_pHandler->pCleanup(This); |
| |
| if ( This->pInPin != NULL ) |
| { |
| IUnknown_Release(This->pInPin->unk.punkControl); |
| This->pInPin = NULL; |
| } |
| if ( This->pOutPin != NULL ) |
| { |
| IUnknown_Release(This->pOutPin->unk.punkControl); |
| This->pOutPin = NULL; |
| } |
| if ( This->pSeekPass != NULL ) |
| { |
| IUnknown_Release((IUnknown*)&This->pSeekPass->unk); |
| This->pSeekPass = NULL; |
| } |
| |
| CBaseFilterImpl_UninitIBaseFilter(&This->basefilter); |
| |
| DeleteCriticalSection( &This->csReceive ); |
| } |
| |
| HRESULT QUARTZ_CreateTransformBase( |
| IUnknown* punkOuter,void** ppobj, |
| const CLSID* pclsidTransformBase, |
| LPCWSTR pwszTransformBaseName, |
| LPCWSTR pwszInPinName, |
| LPCWSTR pwszOutPinName, |
| const TransformBaseHandlers* pHandler ) |
| { |
| CTransformBaseImpl* This = NULL; |
| HRESULT hr; |
| |
| TRACE("(%p,%p)\n",punkOuter,ppobj); |
| |
| if ( pwszInPinName == NULL ) |
| pwszInPinName = XFORM_DefInName; |
| if ( pwszOutPinName == NULL ) |
| pwszOutPinName = XFORM_DefOutName; |
| |
| This = (CTransformBaseImpl*) |
| QUARTZ_AllocObj( sizeof(CTransformBaseImpl) ); |
| if ( This == NULL ) |
| return E_OUTOFMEMORY; |
| |
| This->pInPin = NULL; |
| This->pOutPin = NULL; |
| This->pSeekPass = NULL; |
| This->m_pOutPinAllocator = NULL; |
| This->m_bPreCopy = FALSE; /* sample must be copied */ |
| This->m_bReuseSample = FALSE; /* sample must be reused */ |
| This->m_bInFlush = FALSE; |
| This->m_pSample = NULL; |
| This->m_bFiltering = FALSE; |
| This->m_pHandler = pHandler; |
| This->m_pUserData = NULL; |
| |
| QUARTZ_IUnkInit( &This->unk, punkOuter ); |
| |
| hr = CBaseFilterImpl_InitIBaseFilter( |
| &This->basefilter, |
| This->unk.punkControl, |
| pclsidTransformBase, |
| pwszTransformBaseName, |
| &filterhandlers ); |
| if ( SUCCEEDED(hr) ) |
| { |
| /* construct this class. */ |
| hr = This->m_pHandler->pInit( This ); |
| if ( FAILED(hr) ) |
| { |
| CBaseFilterImpl_UninitIBaseFilter(&This->basefilter); |
| } |
| } |
| |
| if ( FAILED(hr) ) |
| { |
| QUARTZ_FreeObj(This); |
| return hr; |
| } |
| |
| This->unk.pEntries = FilterIFEntries; |
| This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]); |
| This->unk.pOnFinalRelease = QUARTZ_DestroyTransformBase; |
| InitializeCriticalSection( &This->csReceive ); |
| |
| /* create pins. */ |
| hr = QUARTZ_CreateTransformBaseInPin( |
| This, &This->basefilter.csFilter, &This->csReceive, |
| &This->pInPin, pwszInPinName ); |
| if ( SUCCEEDED(hr) ) |
| hr = QUARTZ_CompList_AddComp( |
| This->basefilter.pInPins, |
| (IUnknown*)&(This->pInPin->pin), |
| NULL, 0 ); |
| if ( SUCCEEDED(hr) ) |
| hr = QUARTZ_CreateTransformBaseOutPin( |
| This, &This->basefilter.csFilter, |
| &This->pOutPin, pwszOutPinName ); |
| if ( SUCCEEDED(hr) ) |
| hr = QUARTZ_CompList_AddComp( |
| This->basefilter.pOutPins, |
| (IUnknown*)&(This->pOutPin->pin), |
| NULL, 0 ); |
| |
| if ( SUCCEEDED(hr) ) |
| { |
| hr = QUARTZ_CreateSeekingPassThruInternal( |
| (IUnknown*)&(This->pOutPin->unk), &This->pSeekPass, |
| FALSE, (IPin*)&(This->pInPin->pin) ); |
| } |
| |
| if ( FAILED(hr) ) |
| { |
| IUnknown_Release( This->unk.punkControl ); |
| return hr; |
| } |
| |
| *ppobj = (void*)&(This->unk); |
| |
| return S_OK; |
| } |
| |
| /*************************************************************************** |
| * |
| * new/delete CTransformBaseInPinImpl |
| * |
| */ |
| |
| /* can I use offsetof safely? - FIXME? */ |
| static QUARTZ_IFEntry InPinIFEntries[] = |
| { |
| { &IID_IPin, offsetof(CTransformBaseInPinImpl,pin)-offsetof(CTransformBaseInPinImpl,unk) }, |
| { &IID_IMemInputPin, offsetof(CTransformBaseInPinImpl,meminput)-offsetof(CTransformBaseInPinImpl,unk) }, |
| }; |
| |
| static void QUARTZ_DestroyTransformBaseInPin(IUnknown* punk) |
| { |
| CTransformBaseInPinImpl_THIS(punk,unk); |
| |
| TRACE( "(%p)\n", This ); |
| |
| CPinBaseImpl_UninitIPin( &This->pin ); |
| CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput ); |
| } |
| |
| HRESULT QUARTZ_CreateTransformBaseInPin( |
| CTransformBaseImpl* pFilter, |
| CRITICAL_SECTION* pcsPin, |
| CRITICAL_SECTION* pcsPinReceive, |
| CTransformBaseInPinImpl** ppPin, |
| LPCWSTR pwszPinName ) |
| { |
| CTransformBaseInPinImpl* This = NULL; |
| HRESULT hr; |
| |
| TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin); |
| |
| This = (CTransformBaseInPinImpl*) |
| QUARTZ_AllocObj( sizeof(CTransformBaseInPinImpl) ); |
| if ( This == NULL ) |
| return E_OUTOFMEMORY; |
| |
| QUARTZ_IUnkInit( &This->unk, NULL ); |
| This->pFilter = pFilter; |
| |
| hr = CPinBaseImpl_InitIPin( |
| &This->pin, |
| This->unk.punkControl, |
| pcsPin, pcsPinReceive, |
| &pFilter->basefilter, |
| pwszPinName, |
| FALSE, |
| &inputpinhandlers ); |
| |
| if ( SUCCEEDED(hr) ) |
| { |
| hr = CMemInputPinBaseImpl_InitIMemInputPin( |
| &This->meminput, |
| This->unk.punkControl, |
| &This->pin ); |
| if ( FAILED(hr) ) |
| { |
| CPinBaseImpl_UninitIPin( &This->pin ); |
| } |
| } |
| |
| if ( FAILED(hr) ) |
| { |
| QUARTZ_FreeObj(This); |
| return hr; |
| } |
| |
| This->unk.pEntries = InPinIFEntries; |
| This->unk.dwEntries = sizeof(InPinIFEntries)/sizeof(InPinIFEntries[0]); |
| This->unk.pOnFinalRelease = QUARTZ_DestroyTransformBaseInPin; |
| |
| *ppPin = This; |
| |
| TRACE("returned successfully.\n"); |
| |
| return S_OK; |
| } |
| |
| |
| /*************************************************************************** |
| * |
| * new/delete CTransformBaseOutPinImpl |
| * |
| */ |
| |
| /* can I use offsetof safely? - FIXME? */ |
| static QUARTZ_IFEntry OutPinIFEntries[] = |
| { |
| { &IID_IPin, offsetof(CTransformBaseOutPinImpl,pin)-offsetof(CTransformBaseOutPinImpl,unk) }, |
| { &IID_IQualityControl, offsetof(CTransformBaseOutPinImpl,qcontrol)-offsetof(CTransformBaseOutPinImpl,unk) }, |
| }; |
| |
| static HRESULT CTransformBaseOutPinImpl_OnQueryInterface( |
| IUnknown* punk, const IID* piid, void** ppobj ) |
| { |
| CTransformBaseOutPinImpl_THIS(punk,unk); |
| |
| if ( This->pFilter == NULL || This->pFilter->pSeekPass == NULL ) |
| return E_NOINTERFACE; |
| |
| if ( IsEqualGUID( &IID_IMediaPosition, piid ) || |
| IsEqualGUID( &IID_IMediaSeeking, piid ) ) |
| { |
| TRACE( "IMediaSeeking(or IMediaPosition) is queried\n" ); |
| return IUnknown_QueryInterface( (IUnknown*)(&This->pFilter->pSeekPass->unk), piid, ppobj ); |
| } |
| |
| return E_NOINTERFACE; |
| } |
| |
| static void QUARTZ_DestroyTransformBaseOutPin(IUnknown* punk) |
| { |
| CTransformBaseOutPinImpl_THIS(punk,unk); |
| |
| TRACE( "(%p)\n", This ); |
| |
| CPinBaseImpl_UninitIPin( &This->pin ); |
| CQualityControlPassThruImpl_UninitIQualityControl( &This->qcontrol ); |
| } |
| |
| HRESULT QUARTZ_CreateTransformBaseOutPin( |
| CTransformBaseImpl* pFilter, |
| CRITICAL_SECTION* pcsPin, |
| CTransformBaseOutPinImpl** ppPin, |
| LPCWSTR pwszPinName ) |
| { |
| CTransformBaseOutPinImpl* This = NULL; |
| HRESULT hr; |
| |
| TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin); |
| |
| This = (CTransformBaseOutPinImpl*) |
| QUARTZ_AllocObj( sizeof(CTransformBaseOutPinImpl) ); |
| if ( This == NULL ) |
| return E_OUTOFMEMORY; |
| |
| QUARTZ_IUnkInit( &This->unk, NULL ); |
| This->qiext.pNext = NULL; |
| This->qiext.pOnQueryInterface = &CTransformBaseOutPinImpl_OnQueryInterface; |
| QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext ); |
| |
| This->pFilter = pFilter; |
| |
| hr = CPinBaseImpl_InitIPin( |
| &This->pin, |
| This->unk.punkControl, |
| pcsPin, NULL, |
| &pFilter->basefilter, |
| pwszPinName, |
| TRUE, |
| &outputpinhandlers ); |
| |
| if ( SUCCEEDED(hr) ) |
| { |
| hr = CQualityControlPassThruImpl_InitIQualityControl( |
| &This->qcontrol, |
| This->unk.punkControl, |
| &This->pin ); |
| if ( FAILED(hr) ) |
| { |
| CPinBaseImpl_UninitIPin( &This->pin ); |
| } |
| } |
| |
| if ( FAILED(hr) ) |
| { |
| QUARTZ_FreeObj(This); |
| return hr; |
| } |
| |
| This->unk.pEntries = OutPinIFEntries; |
| This->unk.dwEntries = sizeof(OutPinIFEntries)/sizeof(OutPinIFEntries[0]); |
| This->unk.pOnFinalRelease = QUARTZ_DestroyTransformBaseOutPin; |
| |
| *ppPin = This; |
| |
| TRACE("returned successfully.\n"); |
| |
| return S_OK; |
| } |
| |