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