2 * Implements IBaseFilter for transform filters. (internal)
4 * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
37 #include "quartz_private.h"
42 static const WCHAR XFORM_DefInName[] =
43 {'X','F','o','r','m',' ','I','n',0};
44 static const WCHAR XFORM_DefOutName[] =
45 {'X','F','o','r','m',' ','O','u','t',0};
47 /***************************************************************************
49 * CTransformBaseImpl methods
53 static HRESULT CTransformBaseImpl_OnActive( CBaseFilterImpl* pImpl )
55 CTransformBaseImpl_THIS(pImpl,basefilter);
57 TRACE( "(%p)\n", This );
62 static HRESULT CTransformBaseImpl_OnInactive( CBaseFilterImpl* pImpl )
64 CTransformBaseImpl_THIS(pImpl,basefilter);
66 IMemAllocator* pAllocator;
68 TRACE( "(%p)\n", This );
70 if ( This->pInPin->pin.pPinConnectedTo == NULL ||
71 This->pOutPin->pin.pPinConnectedTo == NULL )
74 EnterCriticalSection( &This->basefilter.csFilter );
76 pAllocator = This->m_pOutPinAllocator;
77 if ( pAllocator != NULL &&
78 This->pInPin->meminput.pAllocator != pAllocator )
80 hr = IMemAllocator_Commit( pAllocator );
85 if ( !This->m_bFiltering )
87 hr = This->m_pHandler->pBeginTransform( This, This->pInPin->pin.pmtConn, This->pOutPin->pin.pmtConn, This->m_bReuseSample );
90 This->m_bFiltering = TRUE;
95 LeaveCriticalSection( &This->basefilter.csFilter );
100 static HRESULT CTransformBaseImpl_OnStop( CBaseFilterImpl* pImpl )
102 CTransformBaseImpl_THIS(pImpl,basefilter);
103 IMemAllocator* pAllocator;
105 TRACE( "(%p)\n", This );
107 EnterCriticalSection( &This->basefilter.csFilter );
109 if ( This->m_bFiltering )
111 This->m_pHandler->pEndTransform( This );
112 This->m_bFiltering = FALSE;
114 if ( This->m_pSample != NULL )
116 IMediaSample_Release( This->m_pSample );
117 This->m_pSample = NULL;
120 pAllocator = This->m_pOutPinAllocator;
121 if ( pAllocator != NULL &&
122 This->pInPin->meminput.pAllocator != pAllocator )
124 IMemAllocator_Decommit( pAllocator );
127 LeaveCriticalSection( &This->basefilter.csFilter );
132 static const CBaseFilterHandlers filterhandlers =
134 CTransformBaseImpl_OnActive, /* pOnActive */
135 CTransformBaseImpl_OnInactive, /* pOnInactive */
136 CTransformBaseImpl_OnStop, /* pOnStop */
139 /***************************************************************************
141 * CTransformBaseInPinImpl methods
145 static HRESULT CTransformBaseInPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
147 CTransformBaseInPinImpl_THIS(pImpl,pin);
150 TRACE( "(%p,%p)\n", This, pPin );
152 EnterCriticalSection( &This->pFilter->basefilter.csFilter );
153 hr = This->pFilter->m_pHandler->pGetOutputTypes( This->pFilter, This->pFilter->pInPin->pin.pmtConn, &This->pFilter->pOutPin->pin.pmtAcceptTypes, &This->pFilter->pOutPin->pin.cAcceptTypes );
159 LeaveCriticalSection( &This->pFilter->basefilter.csFilter );
164 static HRESULT CTransformBaseInPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
166 CTransformBaseInPinImpl_THIS(pImpl,pin);
168 TRACE( "(%p)\n", This );
170 if ( This->meminput.pAllocator != NULL )
172 IMemAllocator_Decommit(This->meminput.pAllocator);
173 IMemAllocator_Release(This->meminput.pAllocator);
174 This->meminput.pAllocator = NULL;
180 static HRESULT CTransformBaseInPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
182 CTransformBaseInPinImpl_THIS(pImpl,pin);
185 TRACE( "(%p,%p)\n", This, pmt );
187 EnterCriticalSection( &This->pFilter->basefilter.csFilter );
188 hr = This->pFilter->m_pHandler->pCheckMediaType( This->pFilter, pmt, (This->pFilter->pOutPin->pin.pPinConnectedTo != NULL) ? This->pFilter->pOutPin->pin.pmtConn : NULL );
189 LeaveCriticalSection( &This->pFilter->basefilter.csFilter );
194 static HRESULT CTransformBaseInPinImpl_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
196 CTransformBaseInPinImpl_THIS(pImpl,pin);
199 TRACE( "(%p,%p)\n", This, pSample );
201 if ( This->pin.pPinConnectedTo == NULL ||
202 This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
205 if ( !This->pFilter->m_bFiltering )
208 if ( This->pFilter->m_bInFlush )
211 if ( This->pFilter->m_pHandler->pProcessReceive != NULL )
213 hr = This->pFilter->m_pHandler->pProcessReceive( This->pFilter, pSample );
217 if ( This->meminput.pAllocator != This->pFilter->m_pOutPinAllocator )
219 if ( This->pFilter->m_pSample == NULL )
221 hr = IMemAllocator_GetBuffer( This->pFilter->m_pOutPinAllocator, &This->pFilter->m_pSample, NULL, NULL, 0 );
225 hr = QUARTZ_IMediaSample_Copy(
226 This->pFilter->m_pSample, pSample, This->pFilter->m_bPreCopy );
231 if ( This->pFilter->m_bPreCopy )
232 hr = This->pFilter->m_pHandler->pTransform( This->pFilter, This->pFilter->m_pSample, NULL );
234 hr = This->pFilter->m_pHandler->pTransform( This->pFilter, pSample, This->pFilter->m_pSample );
241 hr = CPinBaseImpl_SendSample(&This->pFilter->pOutPin->pin,This->pFilter->m_pSample);
248 if ( !This->pFilter->m_bReuseSample )
250 if ( This->pFilter->m_pSample != NULL )
252 IMediaSample_Release( This->pFilter->m_pSample );
253 This->pFilter->m_pSample = NULL;
266 static HRESULT CTransformBaseInPinImpl_ReceiveCanBlock( CPinBaseImpl* pImpl )
268 CTransformBaseInPinImpl_THIS(pImpl,pin);
270 TRACE( "(%p)\n", This );
272 if ( This->pin.pPinConnectedTo == NULL ||
273 This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
276 return CPinBaseImpl_SendReceiveCanBlock( &This->pFilter->pOutPin->pin );
279 static HRESULT CTransformBaseInPinImpl_EndOfStream( CPinBaseImpl* pImpl )
281 CTransformBaseInPinImpl_THIS(pImpl,pin);
283 TRACE( "(%p)\n", This );
285 if ( This->pin.pPinConnectedTo == NULL ||
286 This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
289 return CPinBaseImpl_SendEndOfStream( &This->pFilter->pOutPin->pin );
292 static HRESULT CTransformBaseInPinImpl_BeginFlush( CPinBaseImpl* pImpl )
294 CTransformBaseInPinImpl_THIS(pImpl,pin);
296 TRACE( "(%p)\n", This );
298 if ( This->pin.pPinConnectedTo == NULL ||
299 This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
302 This->pFilter->m_bInFlush = TRUE;
304 return CPinBaseImpl_SendBeginFlush( &This->pFilter->pOutPin->pin );
307 static HRESULT CTransformBaseInPinImpl_EndFlush( CPinBaseImpl* pImpl )
309 CTransformBaseInPinImpl_THIS(pImpl,pin);
311 TRACE( "(%p)\n", This );
313 if ( This->pin.pPinConnectedTo == NULL ||
314 This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
317 This->pFilter->m_bInFlush = FALSE;
319 return CPinBaseImpl_SendEndFlush( &This->pFilter->pOutPin->pin );
322 static HRESULT CTransformBaseInPinImpl_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
324 CTransformBaseInPinImpl_THIS(pImpl,pin);
326 FIXME( "(%p)\n", This );
328 if ( This->pin.pPinConnectedTo == NULL ||
329 This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
332 return CPinBaseImpl_SendNewSegment( &This->pFilter->pOutPin->pin,
333 rtStart, rtStop, rate );
336 static const CBasePinHandlers inputpinhandlers =
338 NULL, /* pOnPreConnect */
339 CTransformBaseInPinImpl_OnPostConnect, /* pOnPostConnect */
340 CTransformBaseInPinImpl_OnDisconnect, /* pOnDisconnect */
341 CTransformBaseInPinImpl_CheckMediaType, /* pCheckMediaType */
342 NULL, /* pQualityNotify */
343 CTransformBaseInPinImpl_Receive, /* pReceive */
344 CTransformBaseInPinImpl_ReceiveCanBlock, /* pReceiveCanBlock */
345 CTransformBaseInPinImpl_EndOfStream, /* pEndOfStream */
346 CTransformBaseInPinImpl_BeginFlush, /* pBeginFlush */
347 CTransformBaseInPinImpl_EndFlush, /* pEndFlush */
348 CTransformBaseInPinImpl_NewSegment, /* pNewSegment */
351 /***************************************************************************
353 * CTransformBaseOutPinImpl methods
357 static HRESULT CTransformBaseOutPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
359 CTransformBaseOutPinImpl_THIS(pImpl,pin);
361 ALLOCATOR_PROPERTIES propReqThis;
362 ALLOCATOR_PROPERTIES propReqPeer;
363 ALLOCATOR_PROPERTIES propActual;
364 BOOL bTransInPlace = FALSE;
365 BOOL bTryToReUseSample = FALSE;
366 BOOL bOutReadonly = FALSE;
367 IMemAllocator* pAllocator;
369 FIXME( "(%p,%p)\n", This, pPin );
371 if ( This->pFilter->pInPin->pin.pPinConnectedTo == NULL )
373 if ( This->pin.pMemInputPinConnectedTo == NULL )
376 ZeroMemory( &propReqThis, sizeof(ALLOCATOR_PROPERTIES) );
377 ZeroMemory( &propReqPeer, sizeof(ALLOCATOR_PROPERTIES) );
378 ZeroMemory( &propActual, sizeof(ALLOCATOR_PROPERTIES) );
380 hr = This->pFilter->m_pHandler->pGetAllocProp( This->pFilter, This->pFilter->pInPin->pin.pmtConn, This->pin.pmtConn, &propReqThis, &bTransInPlace, &bTryToReUseSample );
384 if ( propReqThis.cbAlign == 0 )
385 propReqThis.cbAlign = 1;
389 ZeroMemory( &propReqPeer, sizeof(ALLOCATOR_PROPERTIES) );
390 hr = IMemInputPin_GetAllocatorRequirements(
391 This->pin.pMemInputPinConnectedTo, &propReqPeer );
392 if ( propReqPeer.cbAlign != 0 && propReqPeer.cbAlign != 1 )
393 bTransInPlace = FALSE;
394 if ( propReqPeer.cbPrefix != 0 )
395 bTransInPlace = FALSE;
397 bOutReadonly = FALSE;
398 if ( bTransInPlace && This->pFilter->pInPin->meminput.bReadonly )
401 pAllocator = This->pFilter->pInPin->meminput.pAllocator;
403 hr = IMemInputPin_NotifyAllocator(
404 This->pin.pMemInputPinConnectedTo,
405 pAllocator, bOutReadonly );
408 This->pFilter->m_pOutPinAllocator = pAllocator;
409 IMemAllocator_AddRef(pAllocator);
410 bTryToReUseSample = FALSE;
415 hr = IMemInputPin_GetAllocator(
416 This->pin.pMemInputPinConnectedTo, &pAllocator );
419 hr = IMemAllocator_SetProperties( pAllocator, &propReqThis, &propActual );
422 TRACE("cBuffers = %ld / cbBuffer = %ld\n",propActual.cBuffers,propActual.cbBuffer);
423 hr = IMemInputPin_NotifyAllocator(
424 This->pin.pMemInputPinConnectedTo, pAllocator,
429 IMemAllocator_Release(pAllocator);
432 This->pFilter->m_pOutPinAllocator = pAllocator;
436 This->pFilter->m_bPreCopy = FALSE;
437 This->pFilter->m_bReuseSample = FALSE;
440 This->pFilter->m_bPreCopy = bTransInPlace && (This->pFilter->pInPin->meminput.pAllocator != This->pFilter->m_pOutPinAllocator);
441 This->pFilter->m_bReuseSample = bTryToReUseSample;
447 static HRESULT CTransformBaseOutPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
449 CTransformBaseOutPinImpl_THIS(pImpl,pin);
451 FIXME( "(%p)\n", This );
453 if ( This->pFilter->m_pOutPinAllocator != NULL )
455 IMemAllocator_Decommit(This->pFilter->m_pOutPinAllocator);
456 IMemAllocator_Release(This->pFilter->m_pOutPinAllocator);
457 This->pFilter->m_pOutPinAllocator = NULL;
463 static HRESULT CTransformBaseOutPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
465 CTransformBaseOutPinImpl_THIS(pImpl,pin);
468 TRACE( "(%p,%p)\n", This, pmt );
470 if ( This->pFilter->pInPin->pin.pPinConnectedTo == NULL )
473 EnterCriticalSection( &This->pFilter->basefilter.csFilter );
474 hr = This->pFilter->m_pHandler->pCheckMediaType( This->pFilter, This->pFilter->pInPin->pin.pmtConn, pmt );
475 LeaveCriticalSection( &This->pFilter->basefilter.csFilter );
480 static const CBasePinHandlers outputpinhandlers =
482 NULL, /* pOnPreConnect */
483 CTransformBaseOutPinImpl_OnPostConnect, /* pOnPostConnect */
484 CTransformBaseOutPinImpl_OnDisconnect, /* pOnDisconnect */
485 CTransformBaseOutPinImpl_CheckMediaType, /* pCheckMediaType */
486 NULL, /* pQualityNotify */
487 OutputPinSync_Receive, /* pReceive */
488 OutputPinSync_ReceiveCanBlock, /* pReceiveCanBlock */
489 OutputPinSync_EndOfStream, /* pEndOfStream */
490 OutputPinSync_BeginFlush, /* pBeginFlush */
491 OutputPinSync_EndFlush, /* pEndFlush */
492 OutputPinSync_NewSegment, /* pNewSegment */
496 /***************************************************************************
498 * new/delete CTransformBaseImpl
502 /* can I use offsetof safely? - FIXME? */
503 static QUARTZ_IFEntry FilterIFEntries[] =
505 { &IID_IPersist, offsetof(CTransformBaseImpl,basefilter)-offsetof(CTransformBaseImpl,unk) },
506 { &IID_IMediaFilter, offsetof(CTransformBaseImpl,basefilter)-offsetof(CTransformBaseImpl,unk) },
507 { &IID_IBaseFilter, offsetof(CTransformBaseImpl,basefilter)-offsetof(CTransformBaseImpl,unk) },
510 static void QUARTZ_DestroyTransformBase(IUnknown* punk)
512 CTransformBaseImpl_THIS(punk,unk);
514 TRACE( "(%p)\n", This );
516 This->m_pHandler->pCleanup(This);
518 if ( This->pInPin != NULL )
520 IUnknown_Release(This->pInPin->unk.punkControl);
523 if ( This->pOutPin != NULL )
525 IUnknown_Release(This->pOutPin->unk.punkControl);
526 This->pOutPin = NULL;
528 if ( This->pSeekPass != NULL )
530 IUnknown_Release((IUnknown*)&This->pSeekPass->unk);
531 This->pSeekPass = NULL;
534 CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
536 DeleteCriticalSection( &This->csReceive );
539 HRESULT QUARTZ_CreateTransformBase(
540 IUnknown* punkOuter,void** ppobj,
541 const CLSID* pclsidTransformBase,
542 LPCWSTR pwszTransformBaseName,
543 LPCWSTR pwszInPinName,
544 LPCWSTR pwszOutPinName,
545 const TransformBaseHandlers* pHandler )
547 CTransformBaseImpl* This = NULL;
550 TRACE("(%p,%p)\n",punkOuter,ppobj);
552 if ( pwszInPinName == NULL )
553 pwszInPinName = XFORM_DefInName;
554 if ( pwszOutPinName == NULL )
555 pwszOutPinName = XFORM_DefOutName;
557 This = (CTransformBaseImpl*)
558 QUARTZ_AllocObj( sizeof(CTransformBaseImpl) );
560 return E_OUTOFMEMORY;
563 This->pOutPin = NULL;
564 This->pSeekPass = NULL;
565 This->m_pOutPinAllocator = NULL;
566 This->m_bPreCopy = FALSE; /* sample must be copied */
567 This->m_bReuseSample = FALSE; /* sample must be reused */
568 This->m_bInFlush = FALSE;
569 This->m_pSample = NULL;
570 This->m_bFiltering = FALSE;
571 This->m_pHandler = pHandler;
572 This->m_pUserData = NULL;
574 QUARTZ_IUnkInit( &This->unk, punkOuter );
576 hr = CBaseFilterImpl_InitIBaseFilter(
578 This->unk.punkControl,
580 pwszTransformBaseName,
584 /* construct this class. */
585 hr = This->m_pHandler->pInit( This );
588 CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
594 QUARTZ_FreeObj(This);
598 This->unk.pEntries = FilterIFEntries;
599 This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
600 This->unk.pOnFinalRelease = QUARTZ_DestroyTransformBase;
601 InitializeCriticalSection( &This->csReceive );
604 hr = QUARTZ_CreateTransformBaseInPin(
605 This, &This->basefilter.csFilter, &This->csReceive,
606 &This->pInPin, pwszInPinName );
608 hr = QUARTZ_CompList_AddComp(
609 This->basefilter.pInPins,
610 (IUnknown*)&(This->pInPin->pin),
613 hr = QUARTZ_CreateTransformBaseOutPin(
614 This, &This->basefilter.csFilter,
615 &This->pOutPin, pwszOutPinName );
617 hr = QUARTZ_CompList_AddComp(
618 This->basefilter.pOutPins,
619 (IUnknown*)&(This->pOutPin->pin),
624 hr = QUARTZ_CreateSeekingPassThruInternal(
625 (IUnknown*)&(This->pOutPin->unk), &This->pSeekPass,
626 FALSE, (IPin*)&(This->pInPin->pin) );
631 IUnknown_Release( This->unk.punkControl );
635 *ppobj = (void*)&(This->unk);
640 /***************************************************************************
642 * new/delete CTransformBaseInPinImpl
646 /* can I use offsetof safely? - FIXME? */
647 static QUARTZ_IFEntry InPinIFEntries[] =
649 { &IID_IPin, offsetof(CTransformBaseInPinImpl,pin)-offsetof(CTransformBaseInPinImpl,unk) },
650 { &IID_IMemInputPin, offsetof(CTransformBaseInPinImpl,meminput)-offsetof(CTransformBaseInPinImpl,unk) },
653 static void QUARTZ_DestroyTransformBaseInPin(IUnknown* punk)
655 CTransformBaseInPinImpl_THIS(punk,unk);
657 TRACE( "(%p)\n", This );
659 CPinBaseImpl_UninitIPin( &This->pin );
660 CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput );
663 HRESULT QUARTZ_CreateTransformBaseInPin(
664 CTransformBaseImpl* pFilter,
665 CRITICAL_SECTION* pcsPin,
666 CRITICAL_SECTION* pcsPinReceive,
667 CTransformBaseInPinImpl** ppPin,
668 LPCWSTR pwszPinName )
670 CTransformBaseInPinImpl* This = NULL;
673 TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
675 This = (CTransformBaseInPinImpl*)
676 QUARTZ_AllocObj( sizeof(CTransformBaseInPinImpl) );
678 return E_OUTOFMEMORY;
680 QUARTZ_IUnkInit( &This->unk, NULL );
681 This->pFilter = pFilter;
683 hr = CPinBaseImpl_InitIPin(
685 This->unk.punkControl,
686 pcsPin, pcsPinReceive,
687 &pFilter->basefilter,
694 hr = CMemInputPinBaseImpl_InitIMemInputPin(
696 This->unk.punkControl,
700 CPinBaseImpl_UninitIPin( &This->pin );
706 QUARTZ_FreeObj(This);
710 This->unk.pEntries = InPinIFEntries;
711 This->unk.dwEntries = sizeof(InPinIFEntries)/sizeof(InPinIFEntries[0]);
712 This->unk.pOnFinalRelease = QUARTZ_DestroyTransformBaseInPin;
716 TRACE("returned successfully.\n");
722 /***************************************************************************
724 * new/delete CTransformBaseOutPinImpl
728 /* can I use offsetof safely? - FIXME? */
729 static QUARTZ_IFEntry OutPinIFEntries[] =
731 { &IID_IPin, offsetof(CTransformBaseOutPinImpl,pin)-offsetof(CTransformBaseOutPinImpl,unk) },
732 { &IID_IQualityControl, offsetof(CTransformBaseOutPinImpl,qcontrol)-offsetof(CTransformBaseOutPinImpl,unk) },
735 static HRESULT CTransformBaseOutPinImpl_OnQueryInterface(
736 IUnknown* punk, const IID* piid, void** ppobj )
738 CTransformBaseOutPinImpl_THIS(punk,unk);
740 if ( This->pFilter == NULL || This->pFilter->pSeekPass == NULL )
741 return E_NOINTERFACE;
743 if ( IsEqualGUID( &IID_IMediaPosition, piid ) ||
744 IsEqualGUID( &IID_IMediaSeeking, piid ) )
746 TRACE( "IMediaSeeking(or IMediaPosition) is queried\n" );
747 return IUnknown_QueryInterface( (IUnknown*)(&This->pFilter->pSeekPass->unk), piid, ppobj );
750 return E_NOINTERFACE;
753 static void QUARTZ_DestroyTransformBaseOutPin(IUnknown* punk)
755 CTransformBaseOutPinImpl_THIS(punk,unk);
757 TRACE( "(%p)\n", This );
759 CPinBaseImpl_UninitIPin( &This->pin );
760 CQualityControlPassThruImpl_UninitIQualityControl( &This->qcontrol );
763 HRESULT QUARTZ_CreateTransformBaseOutPin(
764 CTransformBaseImpl* pFilter,
765 CRITICAL_SECTION* pcsPin,
766 CTransformBaseOutPinImpl** ppPin,
767 LPCWSTR pwszPinName )
769 CTransformBaseOutPinImpl* This = NULL;
772 TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
774 This = (CTransformBaseOutPinImpl*)
775 QUARTZ_AllocObj( sizeof(CTransformBaseOutPinImpl) );
777 return E_OUTOFMEMORY;
779 QUARTZ_IUnkInit( &This->unk, NULL );
780 This->qiext.pNext = NULL;
781 This->qiext.pOnQueryInterface = &CTransformBaseOutPinImpl_OnQueryInterface;
782 QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
784 This->pFilter = pFilter;
786 hr = CPinBaseImpl_InitIPin(
788 This->unk.punkControl,
790 &pFilter->basefilter,
793 &outputpinhandlers );
797 hr = CQualityControlPassThruImpl_InitIQualityControl(
799 This->unk.punkControl,
803 CPinBaseImpl_UninitIPin( &This->pin );
809 QUARTZ_FreeObj(This);
813 This->unk.pEntries = OutPinIFEntries;
814 This->unk.dwEntries = sizeof(OutPinIFEntries)/sizeof(OutPinIFEntries[0]);
815 This->unk.pOnFinalRelease = QUARTZ_DestroyTransformBaseOutPin;
819 TRACE("returned successfully.\n");