824 lines
21 KiB
C
824 lines
21 KiB
C
/*
|
|
* 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;
|
|
}
|
|
|