Implement ResetDC and PHYSICALOFFSET[X|Y] devcaps.
[wine] / dlls / quartz / xform.c
1 /*
2  * Implements IBaseFilter for transform filters. (internal)
3  *
4  * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
5  *
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.
10  *
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.
15  *
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
19  */
20
21
22 #include "config.h"
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winerror.h"
29 #include "strmif.h"
30 #include "control.h"
31 #include "vfwmsgs.h"
32 #include "uuids.h"
33
34 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
36
37 #include "quartz_private.h"
38 #include "xform.h"
39 #include "sample.h"
40
41
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};
46
47 /***************************************************************************
48  *
49  *      CTransformBaseImpl methods
50  *
51  */
52
53 static HRESULT CTransformBaseImpl_OnActive( CBaseFilterImpl* pImpl )
54 {
55         CTransformBaseImpl_THIS(pImpl,basefilter);
56
57         TRACE( "(%p)\n", This );
58
59         return NOERROR;
60 }
61
62 static HRESULT CTransformBaseImpl_OnInactive( CBaseFilterImpl* pImpl )
63 {
64         CTransformBaseImpl_THIS(pImpl,basefilter);
65         HRESULT hr;
66         IMemAllocator* pAllocator;
67
68         TRACE( "(%p)\n", This );
69
70         if ( This->pInPin->pin.pPinConnectedTo == NULL ||
71                  This->pOutPin->pin.pPinConnectedTo == NULL )
72                 return NOERROR;
73
74         EnterCriticalSection( &This->basefilter.csFilter );
75
76         pAllocator = This->m_pOutPinAllocator;
77         if ( pAllocator != NULL &&
78                  This->pInPin->meminput.pAllocator != pAllocator )
79         {
80                 hr = IMemAllocator_Commit( pAllocator );
81                 if ( FAILED(hr) )
82                         goto end;
83         }
84
85         if ( !This->m_bFiltering )
86         {
87                 hr = This->m_pHandler->pBeginTransform( This, This->pInPin->pin.pmtConn, This->pOutPin->pin.pmtConn, This->m_bReuseSample );
88                 if ( FAILED(hr) )
89                         goto end;
90                 This->m_bFiltering = TRUE;
91         }
92
93         hr = NOERROR;
94 end:
95         LeaveCriticalSection( &This->basefilter.csFilter );
96
97         return hr;
98 }
99
100 static HRESULT CTransformBaseImpl_OnStop( CBaseFilterImpl* pImpl )
101 {
102         CTransformBaseImpl_THIS(pImpl,basefilter);
103         IMemAllocator* pAllocator;
104
105         TRACE( "(%p)\n", This );
106
107         EnterCriticalSection( &This->basefilter.csFilter );
108
109         if ( This->m_bFiltering )
110         {
111                 This->m_pHandler->pEndTransform( This );
112                 This->m_bFiltering = FALSE;
113         }
114         if ( This->m_pSample != NULL )
115         {
116                 IMediaSample_Release( This->m_pSample );
117                 This->m_pSample = NULL;
118         }
119
120         pAllocator = This->m_pOutPinAllocator;
121         if ( pAllocator != NULL &&
122                  This->pInPin->meminput.pAllocator != pAllocator )
123         {
124                 IMemAllocator_Decommit( pAllocator );
125         }
126
127         LeaveCriticalSection( &This->basefilter.csFilter );
128
129         return NOERROR;
130 }
131
132 static const CBaseFilterHandlers filterhandlers =
133 {
134         CTransformBaseImpl_OnActive, /* pOnActive */
135         CTransformBaseImpl_OnInactive, /* pOnInactive */
136         CTransformBaseImpl_OnStop, /* pOnStop */
137 };
138
139 /***************************************************************************
140  *
141  *      CTransformBaseInPinImpl methods
142  *
143  */
144
145 static HRESULT CTransformBaseInPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
146 {
147         CTransformBaseInPinImpl_THIS(pImpl,pin);
148         HRESULT hr;
149
150         TRACE( "(%p,%p)\n", This, pPin );
151
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 );
154         if ( FAILED(hr) )
155                 goto end;
156
157         hr = NOERROR;
158 end:
159         LeaveCriticalSection( &This->pFilter->basefilter.csFilter );
160
161         return hr;
162 }
163
164 static HRESULT CTransformBaseInPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
165 {
166         CTransformBaseInPinImpl_THIS(pImpl,pin);
167
168         TRACE( "(%p)\n", This );
169
170         if ( This->meminput.pAllocator != NULL )
171         {
172                 IMemAllocator_Decommit(This->meminput.pAllocator);
173                 IMemAllocator_Release(This->meminput.pAllocator);
174                 This->meminput.pAllocator = NULL;
175         }
176
177         return NOERROR;
178 }
179
180 static HRESULT CTransformBaseInPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
181 {
182         CTransformBaseInPinImpl_THIS(pImpl,pin);
183         HRESULT hr;
184
185         TRACE( "(%p,%p)\n", This, pmt );
186
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 );
190
191         return hr;
192 }
193
194 static HRESULT CTransformBaseInPinImpl_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
195 {
196         CTransformBaseInPinImpl_THIS(pImpl,pin);
197         HRESULT hr;
198
199         TRACE( "(%p,%p)\n", This, pSample );
200
201         if ( This->pin.pPinConnectedTo == NULL ||
202                  This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
203                 return NOERROR;
204
205         if ( !This->pFilter->m_bFiltering )
206                 return E_UNEXPECTED;
207
208         if ( This->pFilter->m_bInFlush )
209                 return S_FALSE;
210
211         if ( This->pFilter->m_pHandler->pProcessReceive != NULL )
212         {
213                 hr = This->pFilter->m_pHandler->pProcessReceive( This->pFilter, pSample );
214         }
215         else
216         {
217                 if ( This->meminput.pAllocator != This->pFilter->m_pOutPinAllocator )
218                 {
219                         if ( This->pFilter->m_pSample == NULL )
220                         {
221                                 hr = IMemAllocator_GetBuffer( This->pFilter->m_pOutPinAllocator, &This->pFilter->m_pSample, NULL, NULL, 0 );
222                                 if ( FAILED(hr) )
223                                         goto end;
224                         }
225                         hr = QUARTZ_IMediaSample_Copy(
226                                 This->pFilter->m_pSample, pSample, This->pFilter->m_bPreCopy );
227                         if ( FAILED(hr) )
228                                 goto end;
229                 }
230
231                 if ( This->pFilter->m_bPreCopy )
232                         hr = This->pFilter->m_pHandler->pTransform( This->pFilter, This->pFilter->m_pSample, NULL );
233                 else
234                         hr = This->pFilter->m_pHandler->pTransform( This->pFilter, pSample, This->pFilter->m_pSample );
235
236                 if ( FAILED(hr) )
237                         goto end;
238
239                 if ( hr == NOERROR )
240                 {
241                         hr = CPinBaseImpl_SendSample(&This->pFilter->pOutPin->pin,This->pFilter->m_pSample);
242                         if ( FAILED(hr) )
243                                 goto end;
244                 }
245
246                 hr = NOERROR;
247         end:
248                 if ( !This->pFilter->m_bReuseSample )
249                 {
250                         if ( This->pFilter->m_pSample != NULL )
251                         {
252                                 IMediaSample_Release( This->pFilter->m_pSample );
253                                 This->pFilter->m_pSample = NULL;
254                         }
255                 }
256
257                 if ( FAILED(hr) )
258                 {
259                         /* Notify(ABORT) */
260                 }
261         }
262
263         return hr;
264 }
265
266 static HRESULT CTransformBaseInPinImpl_ReceiveCanBlock( CPinBaseImpl* pImpl )
267 {
268         CTransformBaseInPinImpl_THIS(pImpl,pin);
269
270         TRACE( "(%p)\n", This );
271
272         if ( This->pin.pPinConnectedTo == NULL ||
273                  This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
274                 return S_FALSE;
275
276         return CPinBaseImpl_SendReceiveCanBlock( &This->pFilter->pOutPin->pin );
277 }
278
279 static HRESULT CTransformBaseInPinImpl_EndOfStream( CPinBaseImpl* pImpl )
280 {
281         CTransformBaseInPinImpl_THIS(pImpl,pin);
282
283         TRACE( "(%p)\n", This );
284
285         if ( This->pin.pPinConnectedTo == NULL ||
286                  This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
287                 return NOERROR;
288
289         return CPinBaseImpl_SendEndOfStream( &This->pFilter->pOutPin->pin );
290 }
291
292 static HRESULT CTransformBaseInPinImpl_BeginFlush( CPinBaseImpl* pImpl )
293 {
294         CTransformBaseInPinImpl_THIS(pImpl,pin);
295
296         TRACE( "(%p)\n", This );
297
298         if ( This->pin.pPinConnectedTo == NULL ||
299                  This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
300                 return NOERROR;
301
302         This->pFilter->m_bInFlush = TRUE;
303
304         return CPinBaseImpl_SendBeginFlush( &This->pFilter->pOutPin->pin );
305 }
306
307 static HRESULT CTransformBaseInPinImpl_EndFlush( CPinBaseImpl* pImpl )
308 {
309         CTransformBaseInPinImpl_THIS(pImpl,pin);
310
311         TRACE( "(%p)\n", This );
312
313         if ( This->pin.pPinConnectedTo == NULL ||
314                  This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
315                 return NOERROR;
316
317         This->pFilter->m_bInFlush = FALSE;
318
319         return CPinBaseImpl_SendEndFlush( &This->pFilter->pOutPin->pin );
320 }
321
322 static HRESULT CTransformBaseInPinImpl_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
323 {
324         CTransformBaseInPinImpl_THIS(pImpl,pin);
325
326         FIXME( "(%p)\n", This );
327
328         if ( This->pin.pPinConnectedTo == NULL ||
329                  This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
330                 return NOERROR;
331
332         return CPinBaseImpl_SendNewSegment( &This->pFilter->pOutPin->pin,
333                 rtStart, rtStop, rate );
334 }
335
336 static const CBasePinHandlers inputpinhandlers =
337 {
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 */
349 };
350
351 /***************************************************************************
352  *
353  *      CTransformBaseOutPinImpl methods
354  *
355  */
356
357 static HRESULT CTransformBaseOutPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
358 {
359         CTransformBaseOutPinImpl_THIS(pImpl,pin);
360         HRESULT hr;
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;
368
369         FIXME( "(%p,%p)\n", This, pPin );
370
371         if ( This->pFilter->pInPin->pin.pPinConnectedTo == NULL )
372                 return E_FAIL;
373         if ( This->pin.pMemInputPinConnectedTo == NULL )
374                 return E_UNEXPECTED;
375
376         ZeroMemory( &propReqThis, sizeof(ALLOCATOR_PROPERTIES) );
377         ZeroMemory( &propReqPeer, sizeof(ALLOCATOR_PROPERTIES) );
378         ZeroMemory( &propActual, sizeof(ALLOCATOR_PROPERTIES) );
379
380         hr = This->pFilter->m_pHandler->pGetAllocProp( This->pFilter, This->pFilter->pInPin->pin.pmtConn, This->pin.pmtConn, &propReqThis, &bTransInPlace, &bTryToReUseSample );
381         if ( FAILED(hr) )
382                 goto end;
383
384         if ( propReqThis.cbAlign == 0 )
385                 propReqThis.cbAlign = 1;
386
387         if ( bTransInPlace )
388         {
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;
396
397                 bOutReadonly = FALSE;
398                 if ( bTransInPlace && This->pFilter->pInPin->meminput.bReadonly )
399                         bOutReadonly = TRUE;
400
401                 pAllocator = This->pFilter->pInPin->meminput.pAllocator;
402
403                 hr = IMemInputPin_NotifyAllocator(
404                         This->pin.pMemInputPinConnectedTo,
405                         pAllocator, bOutReadonly );
406                 if ( hr == NOERROR )
407                 {
408                         This->pFilter->m_pOutPinAllocator = pAllocator;
409                         IMemAllocator_AddRef(pAllocator);
410                         bTryToReUseSample = FALSE;
411                         goto end;
412                 }
413         }
414
415         hr = IMemInputPin_GetAllocator(
416                         This->pin.pMemInputPinConnectedTo, &pAllocator );
417         if ( FAILED(hr) )
418                 goto end;
419         hr = IMemAllocator_SetProperties( pAllocator, &propReqThis, &propActual );
420         if ( SUCCEEDED(hr) )
421         {
422                 TRACE("cBuffers = %ld / cbBuffer = %ld\n",propActual.cBuffers,propActual.cbBuffer);
423                 hr = IMemInputPin_NotifyAllocator(
424                         This->pin.pMemInputPinConnectedTo, pAllocator,
425                         bTryToReUseSample );
426         }
427         if ( FAILED(hr) )
428         {
429                 IMemAllocator_Release(pAllocator);
430                 goto end;
431         }
432         This->pFilter->m_pOutPinAllocator = pAllocator;
433
434         hr = NOERROR;
435 end:
436         This->pFilter->m_bPreCopy = FALSE;
437         This->pFilter->m_bReuseSample = FALSE;
438         if ( hr == NOERROR )
439         {
440                 This->pFilter->m_bPreCopy = bTransInPlace && (This->pFilter->pInPin->meminput.pAllocator != This->pFilter->m_pOutPinAllocator);
441                 This->pFilter->m_bReuseSample = bTryToReUseSample;
442         }
443
444         return hr;
445 }
446
447 static HRESULT CTransformBaseOutPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
448 {
449         CTransformBaseOutPinImpl_THIS(pImpl,pin);
450
451         FIXME( "(%p)\n", This );
452
453         if ( This->pFilter->m_pOutPinAllocator != NULL )
454         {
455                 IMemAllocator_Decommit(This->pFilter->m_pOutPinAllocator);
456                 IMemAllocator_Release(This->pFilter->m_pOutPinAllocator);
457                 This->pFilter->m_pOutPinAllocator = NULL;
458         }
459
460         return NOERROR;
461 }
462
463 static HRESULT CTransformBaseOutPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
464 {
465         CTransformBaseOutPinImpl_THIS(pImpl,pin);
466         HRESULT hr;
467
468         TRACE( "(%p,%p)\n", This, pmt );
469
470         if ( This->pFilter->pInPin->pin.pPinConnectedTo == NULL )
471                 return E_FAIL;
472
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 );
476
477         return hr;
478 }
479
480 static const CBasePinHandlers outputpinhandlers =
481 {
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 */
493 };
494
495
496 /***************************************************************************
497  *
498  *      new/delete CTransformBaseImpl
499  *
500  */
501
502 /* can I use offsetof safely? - FIXME? */
503 static QUARTZ_IFEntry FilterIFEntries[] =
504 {
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) },
508 };
509
510 static void QUARTZ_DestroyTransformBase(IUnknown* punk)
511 {
512         CTransformBaseImpl_THIS(punk,unk);
513
514         TRACE( "(%p)\n", This );
515
516         This->m_pHandler->pCleanup(This);
517
518         if ( This->pInPin != NULL )
519         {
520                 IUnknown_Release(This->pInPin->unk.punkControl);
521                 This->pInPin = NULL;
522         }
523         if ( This->pOutPin != NULL )
524         {
525                 IUnknown_Release(This->pOutPin->unk.punkControl);
526                 This->pOutPin = NULL;
527         }
528         if ( This->pSeekPass != NULL )
529         {
530                 IUnknown_Release((IUnknown*)&This->pSeekPass->unk);
531                 This->pSeekPass = NULL;
532         }
533
534         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
535
536         DeleteCriticalSection( &This->csReceive );
537 }
538
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 )
546 {
547         CTransformBaseImpl*     This = NULL;
548         HRESULT hr;
549
550         TRACE("(%p,%p)\n",punkOuter,ppobj);
551
552         if ( pwszInPinName == NULL )
553                 pwszInPinName = XFORM_DefInName;
554         if ( pwszOutPinName == NULL )
555                 pwszOutPinName = XFORM_DefOutName;
556
557         This = (CTransformBaseImpl*)
558                 QUARTZ_AllocObj( sizeof(CTransformBaseImpl) );
559         if ( This == NULL )
560                 return E_OUTOFMEMORY;
561
562         This->pInPin = NULL;
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;
573
574         QUARTZ_IUnkInit( &This->unk, punkOuter );
575
576         hr = CBaseFilterImpl_InitIBaseFilter(
577                 &This->basefilter,
578                 This->unk.punkControl,
579                 pclsidTransformBase,
580                 pwszTransformBaseName,
581                 &filterhandlers );
582         if ( SUCCEEDED(hr) )
583         {
584                 /* construct this class. */
585                 hr = This->m_pHandler->pInit( This );
586                 if ( FAILED(hr) )
587                 {
588                         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
589                 }
590         }
591
592         if ( FAILED(hr) )
593         {
594                 QUARTZ_FreeObj(This);
595                 return hr;
596         }
597
598         This->unk.pEntries = FilterIFEntries;
599         This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
600         This->unk.pOnFinalRelease = QUARTZ_DestroyTransformBase;
601         InitializeCriticalSection( &This->csReceive );
602
603         /* create pins. */
604         hr = QUARTZ_CreateTransformBaseInPin(
605                 This, &This->basefilter.csFilter, &This->csReceive,
606                 &This->pInPin, pwszInPinName );
607         if ( SUCCEEDED(hr) )
608                 hr = QUARTZ_CompList_AddComp(
609                         This->basefilter.pInPins,
610                         (IUnknown*)&(This->pInPin->pin),
611                         NULL, 0 );
612         if ( SUCCEEDED(hr) )
613                 hr = QUARTZ_CreateTransformBaseOutPin(
614                         This, &This->basefilter.csFilter,
615                         &This->pOutPin, pwszOutPinName );
616         if ( SUCCEEDED(hr) )
617                 hr = QUARTZ_CompList_AddComp(
618                         This->basefilter.pOutPins,
619                         (IUnknown*)&(This->pOutPin->pin),
620                         NULL, 0 );
621
622         if ( SUCCEEDED(hr) )
623         {
624                 hr = QUARTZ_CreateSeekingPassThruInternal(
625                         (IUnknown*)&(This->pOutPin->unk), &This->pSeekPass,
626                         FALSE, (IPin*)&(This->pInPin->pin) );
627         }
628
629         if ( FAILED(hr) )
630         {
631                 IUnknown_Release( This->unk.punkControl );
632                 return hr;
633         }
634
635         *ppobj = (void*)&(This->unk);
636
637         return S_OK;
638 }
639
640 /***************************************************************************
641  *
642  *      new/delete CTransformBaseInPinImpl
643  *
644  */
645
646 /* can I use offsetof safely? - FIXME? */
647 static QUARTZ_IFEntry InPinIFEntries[] =
648 {
649   { &IID_IPin, offsetof(CTransformBaseInPinImpl,pin)-offsetof(CTransformBaseInPinImpl,unk) },
650   { &IID_IMemInputPin, offsetof(CTransformBaseInPinImpl,meminput)-offsetof(CTransformBaseInPinImpl,unk) },
651 };
652
653 static void QUARTZ_DestroyTransformBaseInPin(IUnknown* punk)
654 {
655         CTransformBaseInPinImpl_THIS(punk,unk);
656
657         TRACE( "(%p)\n", This );
658
659         CPinBaseImpl_UninitIPin( &This->pin );
660         CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput );
661 }
662
663 HRESULT QUARTZ_CreateTransformBaseInPin(
664         CTransformBaseImpl* pFilter,
665         CRITICAL_SECTION* pcsPin,
666         CRITICAL_SECTION* pcsPinReceive,
667         CTransformBaseInPinImpl** ppPin,
668         LPCWSTR pwszPinName )
669 {
670         CTransformBaseInPinImpl*        This = NULL;
671         HRESULT hr;
672
673         TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
674
675         This = (CTransformBaseInPinImpl*)
676                 QUARTZ_AllocObj( sizeof(CTransformBaseInPinImpl) );
677         if ( This == NULL )
678                 return E_OUTOFMEMORY;
679
680         QUARTZ_IUnkInit( &This->unk, NULL );
681         This->pFilter = pFilter;
682
683         hr = CPinBaseImpl_InitIPin(
684                 &This->pin,
685                 This->unk.punkControl,
686                 pcsPin, pcsPinReceive,
687                 &pFilter->basefilter,
688                 pwszPinName,
689                 FALSE,
690                 &inputpinhandlers );
691
692         if ( SUCCEEDED(hr) )
693         {
694                 hr = CMemInputPinBaseImpl_InitIMemInputPin(
695                         &This->meminput,
696                         This->unk.punkControl,
697                         &This->pin );
698                 if ( FAILED(hr) )
699                 {
700                         CPinBaseImpl_UninitIPin( &This->pin );
701                 }
702         }
703
704         if ( FAILED(hr) )
705         {
706                 QUARTZ_FreeObj(This);
707                 return hr;
708         }
709
710         This->unk.pEntries = InPinIFEntries;
711         This->unk.dwEntries = sizeof(InPinIFEntries)/sizeof(InPinIFEntries[0]);
712         This->unk.pOnFinalRelease = QUARTZ_DestroyTransformBaseInPin;
713
714         *ppPin = This;
715
716         TRACE("returned successfully.\n");
717
718         return S_OK;
719 }
720
721
722 /***************************************************************************
723  *
724  *      new/delete CTransformBaseOutPinImpl
725  *
726  */
727
728 /* can I use offsetof safely? - FIXME? */
729 static QUARTZ_IFEntry OutPinIFEntries[] =
730 {
731   { &IID_IPin, offsetof(CTransformBaseOutPinImpl,pin)-offsetof(CTransformBaseOutPinImpl,unk) },
732   { &IID_IQualityControl, offsetof(CTransformBaseOutPinImpl,qcontrol)-offsetof(CTransformBaseOutPinImpl,unk) },
733 };
734
735 static HRESULT CTransformBaseOutPinImpl_OnQueryInterface(
736         IUnknown* punk, const IID* piid, void** ppobj )
737 {
738         CTransformBaseOutPinImpl_THIS(punk,unk);
739
740         if ( This->pFilter == NULL || This->pFilter->pSeekPass == NULL )
741                 return E_NOINTERFACE;
742
743         if ( IsEqualGUID( &IID_IMediaPosition, piid ) ||
744                  IsEqualGUID( &IID_IMediaSeeking, piid ) )
745         {
746                 TRACE( "IMediaSeeking(or IMediaPosition) is queried\n" );
747                 return IUnknown_QueryInterface( (IUnknown*)(&This->pFilter->pSeekPass->unk), piid, ppobj );
748         }
749
750         return E_NOINTERFACE;
751 }
752
753 static void QUARTZ_DestroyTransformBaseOutPin(IUnknown* punk)
754 {
755         CTransformBaseOutPinImpl_THIS(punk,unk);
756
757         TRACE( "(%p)\n", This );
758
759         CPinBaseImpl_UninitIPin( &This->pin );
760         CQualityControlPassThruImpl_UninitIQualityControl( &This->qcontrol );
761 }
762
763 HRESULT QUARTZ_CreateTransformBaseOutPin(
764         CTransformBaseImpl* pFilter,
765         CRITICAL_SECTION* pcsPin,
766         CTransformBaseOutPinImpl** ppPin,
767         LPCWSTR pwszPinName )
768 {
769         CTransformBaseOutPinImpl*       This = NULL;
770         HRESULT hr;
771
772         TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
773
774         This = (CTransformBaseOutPinImpl*)
775                 QUARTZ_AllocObj( sizeof(CTransformBaseOutPinImpl) );
776         if ( This == NULL )
777                 return E_OUTOFMEMORY;
778
779         QUARTZ_IUnkInit( &This->unk, NULL );
780         This->qiext.pNext = NULL;
781         This->qiext.pOnQueryInterface = &CTransformBaseOutPinImpl_OnQueryInterface;
782         QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
783
784         This->pFilter = pFilter;
785
786         hr = CPinBaseImpl_InitIPin(
787                 &This->pin,
788                 This->unk.punkControl,
789                 pcsPin, NULL,
790                 &pFilter->basefilter,
791                 pwszPinName,
792                 TRUE,
793                 &outputpinhandlers );
794
795         if ( SUCCEEDED(hr) )
796         {
797                 hr = CQualityControlPassThruImpl_InitIQualityControl(
798                         &This->qcontrol,
799                         This->unk.punkControl,
800                         &This->pin );
801                 if ( FAILED(hr) )
802                 {
803                         CPinBaseImpl_UninitIPin( &This->pin );
804                 }
805         }
806
807         if ( FAILED(hr) )
808         {
809                 QUARTZ_FreeObj(This);
810                 return hr;
811         }
812
813         This->unk.pEntries = OutPinIFEntries;
814         This->unk.dwEntries = sizeof(OutPinIFEntries)/sizeof(OutPinIFEntries[0]);
815         This->unk.pOnFinalRelease = QUARTZ_DestroyTransformBaseOutPin;
816
817         *ppPin = This;
818
819         TRACE("returned successfully.\n");
820
821         return S_OK;
822 }
823