Added LGPL standard comment, and copyright notices where necessary.
[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->meminput.pAllocator != This->pFilter->m_pOutPinAllocator )
212         {
213                 if ( This->pFilter->m_pSample == NULL )
214                 {
215                         hr = IMemAllocator_GetBuffer( This->pFilter->m_pOutPinAllocator, &This->pFilter->m_pSample, NULL, NULL, 0 );
216                         if ( FAILED(hr) )
217                                 goto end;
218                 }
219                 hr = QUARTZ_IMediaSample_Copy(
220                         This->pFilter->m_pSample, pSample, This->pFilter->m_bPreCopy );
221                 if ( FAILED(hr) )
222                         goto end;
223         }
224
225         if ( This->pFilter->m_bPreCopy )
226                 hr = This->pFilter->m_pHandler->pTransform( This->pFilter, This->pFilter->m_pSample, NULL );
227         else
228                 hr = This->pFilter->m_pHandler->pTransform( This->pFilter, pSample, This->pFilter->m_pSample );
229
230         if ( FAILED(hr) )
231                 goto end;
232
233         if ( hr == NOERROR )
234         {
235                 hr = CPinBaseImpl_SendSample(&This->pFilter->pOutPin->pin,This->pFilter->m_pSample);
236                 if ( FAILED(hr) )
237                         goto end;
238         }
239
240         hr = NOERROR;
241 end:
242         if ( !This->pFilter->m_bReuseSample )
243         {
244                 if ( This->pFilter->m_pSample != NULL )
245                 {
246                         IMediaSample_Release( This->pFilter->m_pSample );
247                         This->pFilter->m_pSample = NULL;
248                 }
249         }
250
251         if ( FAILED(hr) )
252         {
253                 /* Notify(ABORT) */
254         }
255
256         return hr;
257 }
258
259 static HRESULT CTransformBaseInPinImpl_ReceiveCanBlock( CPinBaseImpl* pImpl )
260 {
261         CTransformBaseInPinImpl_THIS(pImpl,pin);
262
263         TRACE( "(%p)\n", This );
264
265         if ( This->pin.pPinConnectedTo == NULL ||
266                  This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
267                 return S_FALSE;
268
269         return CPinBaseImpl_SendReceiveCanBlock( &This->pFilter->pOutPin->pin );
270 }
271
272 static HRESULT CTransformBaseInPinImpl_EndOfStream( CPinBaseImpl* pImpl )
273 {
274         CTransformBaseInPinImpl_THIS(pImpl,pin);
275
276         TRACE( "(%p)\n", This );
277
278         if ( This->pin.pPinConnectedTo == NULL ||
279                  This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
280                 return NOERROR;
281
282         return CPinBaseImpl_SendEndOfStream( &This->pFilter->pOutPin->pin );
283 }
284
285 static HRESULT CTransformBaseInPinImpl_BeginFlush( CPinBaseImpl* pImpl )
286 {
287         CTransformBaseInPinImpl_THIS(pImpl,pin);
288
289         TRACE( "(%p)\n", This );
290
291         if ( This->pin.pPinConnectedTo == NULL ||
292                  This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
293                 return NOERROR;
294
295         This->pFilter->m_bInFlush = TRUE;
296
297         return CPinBaseImpl_SendBeginFlush( &This->pFilter->pOutPin->pin );
298 }
299
300 static HRESULT CTransformBaseInPinImpl_EndFlush( CPinBaseImpl* pImpl )
301 {
302         CTransformBaseInPinImpl_THIS(pImpl,pin);
303
304         TRACE( "(%p)\n", This );
305
306         if ( This->pin.pPinConnectedTo == NULL ||
307                  This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
308                 return NOERROR;
309
310         This->pFilter->m_bInFlush = FALSE;
311
312         return CPinBaseImpl_SendEndFlush( &This->pFilter->pOutPin->pin );
313 }
314
315 static HRESULT CTransformBaseInPinImpl_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
316 {
317         CTransformBaseInPinImpl_THIS(pImpl,pin);
318
319         FIXME( "(%p)\n", This );
320
321         if ( This->pin.pPinConnectedTo == NULL ||
322                  This->pFilter->pOutPin->pin.pPinConnectedTo == NULL )
323                 return NOERROR;
324
325         return CPinBaseImpl_SendNewSegment( &This->pFilter->pOutPin->pin,
326                 rtStart, rtStop, rate );
327 }
328
329 static const CBasePinHandlers inputpinhandlers =
330 {
331         NULL, /* pOnPreConnect */
332         CTransformBaseInPinImpl_OnPostConnect, /* pOnPostConnect */
333         CTransformBaseInPinImpl_OnDisconnect, /* pOnDisconnect */
334         CTransformBaseInPinImpl_CheckMediaType, /* pCheckMediaType */
335         NULL, /* pQualityNotify */
336         CTransformBaseInPinImpl_Receive, /* pReceive */
337         CTransformBaseInPinImpl_ReceiveCanBlock, /* pReceiveCanBlock */
338         CTransformBaseInPinImpl_EndOfStream, /* pEndOfStream */
339         CTransformBaseInPinImpl_BeginFlush, /* pBeginFlush */
340         CTransformBaseInPinImpl_EndFlush, /* pEndFlush */
341         CTransformBaseInPinImpl_NewSegment, /* pNewSegment */
342 };
343
344 /***************************************************************************
345  *
346  *      CTransformBaseOutPinImpl methods
347  *
348  */
349
350 static HRESULT CTransformBaseOutPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
351 {
352         CTransformBaseOutPinImpl_THIS(pImpl,pin);
353         HRESULT hr;
354         ALLOCATOR_PROPERTIES propReqThis;
355         ALLOCATOR_PROPERTIES propReqPeer;
356         ALLOCATOR_PROPERTIES propActual;
357         BOOL bTransInPlace = FALSE;
358         BOOL bTryToReUseSample = FALSE;
359         BOOL bOutReadonly = FALSE;
360         IMemAllocator*  pAllocator;
361
362         FIXME( "(%p,%p)\n", This, pPin );
363
364         if ( This->pFilter->pInPin->pin.pPinConnectedTo == NULL )
365                 return E_FAIL;
366         if ( This->pin.pMemInputPinConnectedTo == NULL )
367                 return E_UNEXPECTED;
368
369         ZeroMemory( &propReqThis, sizeof(ALLOCATOR_PROPERTIES) );
370         ZeroMemory( &propReqPeer, sizeof(ALLOCATOR_PROPERTIES) );
371         ZeroMemory( &propActual, sizeof(ALLOCATOR_PROPERTIES) );
372
373         hr = This->pFilter->m_pHandler->pGetAllocProp( This->pFilter, This->pFilter->pInPin->pin.pmtConn, This->pin.pmtConn, &propReqThis, &bTransInPlace, &bTryToReUseSample );
374         if ( FAILED(hr) )
375                 goto end;
376
377         if ( propReqThis.cbAlign == 0 )
378                 propReqThis.cbAlign = 1;
379
380         if ( bTransInPlace )
381         {
382                 ZeroMemory( &propReqPeer, sizeof(ALLOCATOR_PROPERTIES) );
383                 hr = IMemInputPin_GetAllocatorRequirements(
384                         This->pin.pMemInputPinConnectedTo, &propReqPeer );
385                 if ( propReqPeer.cbAlign != 0 && propReqPeer.cbAlign != 1 )
386                         bTransInPlace = FALSE;
387                 if ( propReqPeer.cbPrefix != 0 )
388                         bTransInPlace = FALSE;
389
390                 bOutReadonly = FALSE;
391                 if ( bTransInPlace && This->pFilter->pInPin->meminput.bReadonly )
392                         bOutReadonly = TRUE;
393
394                 pAllocator = This->pFilter->pInPin->meminput.pAllocator;
395
396                 hr = IMemInputPin_NotifyAllocator(
397                         This->pin.pMemInputPinConnectedTo,
398                         pAllocator, bOutReadonly );
399                 if ( hr == NOERROR )
400                 {
401                         This->pFilter->m_pOutPinAllocator = pAllocator;
402                         IMemAllocator_AddRef(pAllocator);
403                         bTryToReUseSample = FALSE;
404                         goto end;
405                 }
406         }
407
408         hr = IMemInputPin_GetAllocator(
409                         This->pin.pMemInputPinConnectedTo, &pAllocator );
410         if ( FAILED(hr) )
411                 goto end;
412         hr = IMemAllocator_SetProperties( pAllocator, &propReqThis, &propActual );
413         if ( SUCCEEDED(hr) )
414         {
415                 TRACE("cBuffers = %ld / cbBuffer = %ld\n",propActual.cBuffers,propActual.cbBuffer);
416                 hr = IMemInputPin_NotifyAllocator(
417                         This->pin.pMemInputPinConnectedTo, pAllocator,
418                         bTryToReUseSample );
419         }
420         if ( FAILED(hr) )
421         {
422                 IMemAllocator_Release(pAllocator);
423                 goto end;
424         }
425         This->pFilter->m_pOutPinAllocator = pAllocator;
426
427         hr = NOERROR;
428 end:
429         This->pFilter->m_bPreCopy = FALSE;
430         This->pFilter->m_bReuseSample = FALSE;
431         if ( hr == NOERROR )
432         {
433                 This->pFilter->m_bPreCopy = bTransInPlace && (This->pFilter->pInPin->meminput.pAllocator != This->pFilter->m_pOutPinAllocator);
434                 This->pFilter->m_bReuseSample = bTryToReUseSample;
435         }
436
437         return hr;
438 }
439
440 static HRESULT CTransformBaseOutPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
441 {
442         CTransformBaseOutPinImpl_THIS(pImpl,pin);
443
444         FIXME( "(%p)\n", This );
445
446         if ( This->pFilter->m_pOutPinAllocator != NULL )
447         {
448                 IMemAllocator_Decommit(This->pFilter->m_pOutPinAllocator);
449                 IMemAllocator_Release(This->pFilter->m_pOutPinAllocator);
450                 This->pFilter->m_pOutPinAllocator = NULL;
451         }
452
453         return NOERROR;
454 }
455
456 static HRESULT CTransformBaseOutPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
457 {
458         CTransformBaseOutPinImpl_THIS(pImpl,pin);
459         HRESULT hr;
460
461         TRACE( "(%p,%p)\n", This, pmt );
462
463         if ( This->pFilter->pInPin->pin.pPinConnectedTo == NULL )
464                 return E_FAIL;
465
466         EnterCriticalSection( &This->pFilter->basefilter.csFilter );
467         hr = This->pFilter->m_pHandler->pCheckMediaType( This->pFilter, This->pFilter->pInPin->pin.pmtConn, pmt );
468         LeaveCriticalSection( &This->pFilter->basefilter.csFilter );
469
470         return hr;
471 }
472
473 static const CBasePinHandlers outputpinhandlers =
474 {
475         NULL, /* pOnPreConnect */
476         CTransformBaseOutPinImpl_OnPostConnect, /* pOnPostConnect */
477         CTransformBaseOutPinImpl_OnDisconnect, /* pOnDisconnect */
478         CTransformBaseOutPinImpl_CheckMediaType, /* pCheckMediaType */
479         NULL, /* pQualityNotify */
480         OutputPinSync_Receive, /* pReceive */
481         OutputPinSync_ReceiveCanBlock, /* pReceiveCanBlock */
482         OutputPinSync_EndOfStream, /* pEndOfStream */
483         OutputPinSync_BeginFlush, /* pBeginFlush */
484         OutputPinSync_EndFlush, /* pEndFlush */
485         OutputPinSync_NewSegment, /* pNewSegment */
486 };
487
488
489 /***************************************************************************
490  *
491  *      new/delete CTransformBaseImpl
492  *
493  */
494
495 /* can I use offsetof safely? - FIXME? */
496 static QUARTZ_IFEntry FilterIFEntries[] =
497 {
498   { &IID_IPersist, offsetof(CTransformBaseImpl,basefilter)-offsetof(CTransformBaseImpl,unk) },
499   { &IID_IMediaFilter, offsetof(CTransformBaseImpl,basefilter)-offsetof(CTransformBaseImpl,unk) },
500   { &IID_IBaseFilter, offsetof(CTransformBaseImpl,basefilter)-offsetof(CTransformBaseImpl,unk) },
501 };
502
503 static void QUARTZ_DestroyTransformBase(IUnknown* punk)
504 {
505         CTransformBaseImpl_THIS(punk,unk);
506
507         TRACE( "(%p)\n", This );
508
509         This->m_pHandler->pCleanup(This);
510
511         if ( This->pInPin != NULL )
512         {
513                 IUnknown_Release(This->pInPin->unk.punkControl);
514                 This->pInPin = NULL;
515         }
516         if ( This->pOutPin != NULL )
517         {
518                 IUnknown_Release(This->pOutPin->unk.punkControl);
519                 This->pOutPin = NULL;
520         }
521         if ( This->pSeekPass != NULL )
522         {
523                 IUnknown_Release((IUnknown*)&This->pSeekPass->unk);
524                 This->pSeekPass = NULL;
525         }
526
527         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
528
529         DeleteCriticalSection( &This->csReceive );
530 }
531
532 HRESULT QUARTZ_CreateTransformBase(
533         IUnknown* punkOuter,void** ppobj,
534         const CLSID* pclsidTransformBase,
535         LPCWSTR pwszTransformBaseName,
536         LPCWSTR pwszInPinName,
537         LPCWSTR pwszOutPinName,
538         const TransformBaseHandlers* pHandler )
539 {
540         CTransformBaseImpl*     This = NULL;
541         HRESULT hr;
542
543         TRACE("(%p,%p)\n",punkOuter,ppobj);
544
545         if ( pwszInPinName == NULL )
546                 pwszInPinName = XFORM_DefInName;
547         if ( pwszOutPinName == NULL )
548                 pwszOutPinName = XFORM_DefOutName;
549
550         This = (CTransformBaseImpl*)
551                 QUARTZ_AllocObj( sizeof(CTransformBaseImpl) );
552         if ( This == NULL )
553                 return E_OUTOFMEMORY;
554
555         This->pInPin = NULL;
556         This->pOutPin = NULL;
557         This->pSeekPass = NULL;
558         This->m_pOutPinAllocator = NULL;
559         This->m_bPreCopy = FALSE; /* sample must be copied */
560         This->m_bReuseSample = FALSE; /* sample must be reused */
561         This->m_bInFlush = FALSE;
562         This->m_pSample = NULL;
563         This->m_bFiltering = FALSE;
564         This->m_pHandler = pHandler;
565         This->m_pUserData = NULL;
566
567         QUARTZ_IUnkInit( &This->unk, punkOuter );
568
569         hr = CBaseFilterImpl_InitIBaseFilter(
570                 &This->basefilter,
571                 This->unk.punkControl,
572                 pclsidTransformBase,
573                 pwszTransformBaseName,
574                 &filterhandlers );
575         if ( SUCCEEDED(hr) )
576         {
577                 /* construct this class. */
578                 hr = This->m_pHandler->pInit( This );
579                 if ( FAILED(hr) )
580                 {
581                         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
582                 }
583         }
584
585         if ( FAILED(hr) )
586         {
587                 QUARTZ_FreeObj(This);
588                 return hr;
589         }
590
591         This->unk.pEntries = FilterIFEntries;
592         This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
593         This->unk.pOnFinalRelease = QUARTZ_DestroyTransformBase;
594         InitializeCriticalSection( &This->csReceive );
595
596         /* create pins. */
597         hr = QUARTZ_CreateTransformBaseInPin(
598                 This, &This->basefilter.csFilter, &This->csReceive,
599                 &This->pInPin, pwszInPinName );
600         if ( SUCCEEDED(hr) )
601                 hr = QUARTZ_CompList_AddComp(
602                         This->basefilter.pInPins,
603                         (IUnknown*)&(This->pInPin->pin),
604                         NULL, 0 );
605         if ( SUCCEEDED(hr) )
606                 hr = QUARTZ_CreateTransformBaseOutPin(
607                         This, &This->basefilter.csFilter,
608                         &This->pOutPin, pwszOutPinName );
609         if ( SUCCEEDED(hr) )
610                 hr = QUARTZ_CompList_AddComp(
611                         This->basefilter.pOutPins,
612                         (IUnknown*)&(This->pOutPin->pin),
613                         NULL, 0 );
614
615         if ( SUCCEEDED(hr) )
616         {
617                 hr = QUARTZ_CreateSeekingPassThruInternal(
618                         (IUnknown*)&(This->pOutPin->unk), &This->pSeekPass,
619                         FALSE, (IPin*)&(This->pInPin->pin) );
620         }
621
622         if ( FAILED(hr) )
623         {
624                 IUnknown_Release( This->unk.punkControl );
625                 return hr;
626         }
627
628         *ppobj = (void*)&(This->unk);
629
630         return S_OK;
631 }
632
633 /***************************************************************************
634  *
635  *      new/delete CTransformBaseInPinImpl
636  *
637  */
638
639 /* can I use offsetof safely? - FIXME? */
640 static QUARTZ_IFEntry InPinIFEntries[] =
641 {
642   { &IID_IPin, offsetof(CTransformBaseInPinImpl,pin)-offsetof(CTransformBaseInPinImpl,unk) },
643   { &IID_IMemInputPin, offsetof(CTransformBaseInPinImpl,meminput)-offsetof(CTransformBaseInPinImpl,unk) },
644 };
645
646 static void QUARTZ_DestroyTransformBaseInPin(IUnknown* punk)
647 {
648         CTransformBaseInPinImpl_THIS(punk,unk);
649
650         TRACE( "(%p)\n", This );
651
652         CPinBaseImpl_UninitIPin( &This->pin );
653         CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput );
654 }
655
656 HRESULT QUARTZ_CreateTransformBaseInPin(
657         CTransformBaseImpl* pFilter,
658         CRITICAL_SECTION* pcsPin,
659         CRITICAL_SECTION* pcsPinReceive,
660         CTransformBaseInPinImpl** ppPin,
661         LPCWSTR pwszPinName )
662 {
663         CTransformBaseInPinImpl*        This = NULL;
664         HRESULT hr;
665
666         TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
667
668         This = (CTransformBaseInPinImpl*)
669                 QUARTZ_AllocObj( sizeof(CTransformBaseInPinImpl) );
670         if ( This == NULL )
671                 return E_OUTOFMEMORY;
672
673         QUARTZ_IUnkInit( &This->unk, NULL );
674         This->pFilter = pFilter;
675
676         hr = CPinBaseImpl_InitIPin(
677                 &This->pin,
678                 This->unk.punkControl,
679                 pcsPin, pcsPinReceive,
680                 &pFilter->basefilter,
681                 pwszPinName,
682                 FALSE,
683                 &inputpinhandlers );
684
685         if ( SUCCEEDED(hr) )
686         {
687                 hr = CMemInputPinBaseImpl_InitIMemInputPin(
688                         &This->meminput,
689                         This->unk.punkControl,
690                         &This->pin );
691                 if ( FAILED(hr) )
692                 {
693                         CPinBaseImpl_UninitIPin( &This->pin );
694                 }
695         }
696
697         if ( FAILED(hr) )
698         {
699                 QUARTZ_FreeObj(This);
700                 return hr;
701         }
702
703         This->unk.pEntries = InPinIFEntries;
704         This->unk.dwEntries = sizeof(InPinIFEntries)/sizeof(InPinIFEntries[0]);
705         This->unk.pOnFinalRelease = QUARTZ_DestroyTransformBaseInPin;
706
707         *ppPin = This;
708
709         TRACE("returned successfully.\n");
710
711         return S_OK;
712 }
713
714
715 /***************************************************************************
716  *
717  *      new/delete CTransformBaseOutPinImpl
718  *
719  */
720
721 /* can I use offsetof safely? - FIXME? */
722 static QUARTZ_IFEntry OutPinIFEntries[] =
723 {
724   { &IID_IPin, offsetof(CTransformBaseOutPinImpl,pin)-offsetof(CTransformBaseOutPinImpl,unk) },
725   { &IID_IQualityControl, offsetof(CTransformBaseOutPinImpl,qcontrol)-offsetof(CTransformBaseOutPinImpl,unk) },
726 };
727
728 static HRESULT CTransformBaseOutPinImpl_OnQueryInterface(
729         IUnknown* punk, const IID* piid, void** ppobj )
730 {
731         CTransformBaseOutPinImpl_THIS(punk,unk);
732
733         if ( This->pFilter == NULL || This->pFilter->pSeekPass == NULL )
734                 return E_NOINTERFACE;
735
736         if ( IsEqualGUID( &IID_IMediaPosition, piid ) ||
737                  IsEqualGUID( &IID_IMediaSeeking, piid ) )
738         {
739                 TRACE( "IMediaSeeking(or IMediaPosition) is queried\n" );
740                 return IUnknown_QueryInterface( (IUnknown*)(&This->pFilter->pSeekPass->unk), piid, ppobj );
741         }
742
743         return E_NOINTERFACE;
744 }
745
746 static void QUARTZ_DestroyTransformBaseOutPin(IUnknown* punk)
747 {
748         CTransformBaseOutPinImpl_THIS(punk,unk);
749
750         TRACE( "(%p)\n", This );
751
752         CPinBaseImpl_UninitIPin( &This->pin );
753         CQualityControlPassThruImpl_UninitIQualityControl( &This->qcontrol );
754 }
755
756 HRESULT QUARTZ_CreateTransformBaseOutPin(
757         CTransformBaseImpl* pFilter,
758         CRITICAL_SECTION* pcsPin,
759         CTransformBaseOutPinImpl** ppPin,
760         LPCWSTR pwszPinName )
761 {
762         CTransformBaseOutPinImpl*       This = NULL;
763         HRESULT hr;
764
765         TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
766
767         This = (CTransformBaseOutPinImpl*)
768                 QUARTZ_AllocObj( sizeof(CTransformBaseOutPinImpl) );
769         if ( This == NULL )
770                 return E_OUTOFMEMORY;
771
772         QUARTZ_IUnkInit( &This->unk, NULL );
773         This->qiext.pNext = NULL;
774         This->qiext.pOnQueryInterface = &CTransformBaseOutPinImpl_OnQueryInterface;
775         QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
776
777         This->pFilter = pFilter;
778
779         hr = CPinBaseImpl_InitIPin(
780                 &This->pin,
781                 This->unk.punkControl,
782                 pcsPin, NULL,
783                 &pFilter->basefilter,
784                 pwszPinName,
785                 TRUE,
786                 &outputpinhandlers );
787
788         if ( SUCCEEDED(hr) )
789         {
790                 hr = CQualityControlPassThruImpl_InitIQualityControl(
791                         &This->qcontrol,
792                         This->unk.punkControl,
793                         &This->pin );
794                 if ( FAILED(hr) )
795                 {
796                         CPinBaseImpl_UninitIPin( &This->pin );
797                 }
798         }
799
800         if ( FAILED(hr) )
801         {
802                 QUARTZ_FreeObj(This);
803                 return hr;
804         }
805
806         This->unk.pEntries = OutPinIFEntries;
807         This->unk.dwEntries = sizeof(OutPinIFEntries)/sizeof(OutPinIFEntries[0]);
808         This->unk.pOnFinalRelease = QUARTZ_DestroyTransformBaseOutPin;
809
810         *ppPin = This;
811
812         TRACE("returned successfully.\n");
813
814         return S_OK;
815 }
816