When including 'wine/port.h', include it first.
[wine] / dlls / quartz / basepin.c
1 /*
2  * Implements IPin and IMemInputPin. (internal)
3  *
4  * hidenori@a2.ctktv.ne.jp
5  */
6
7 #include "config.h"
8
9 #include "windef.h"
10 #include "winbase.h"
11 #include "wingdi.h"
12 #include "winuser.h"
13 #include "winerror.h"
14 #include "strmif.h"
15 #include "vfwmsgs.h"
16
17 #include "debugtools.h"
18 DEFAULT_DEBUG_CHANNEL(quartz);
19
20 #include "quartz_private.h"
21 #include "basefilt.h"
22 #include "memalloc.h"
23
24
25 /***************************************************************************
26  *
27  *      CPinBaseImpl
28  *
29  */
30
31 static HRESULT WINAPI
32 CPinBaseImpl_fnQueryInterface(IPin* iface,REFIID riid,void** ppobj)
33 {
34         ICOM_THIS(CPinBaseImpl,iface);
35
36         TRACE("(%p)->()\n",This);
37
38         return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
39 }
40
41 static ULONG WINAPI
42 CPinBaseImpl_fnAddRef(IPin* iface)
43 {
44         ICOM_THIS(CPinBaseImpl,iface);
45
46         TRACE("(%p)->()\n",This);
47
48         return IUnknown_AddRef(This->punkControl);
49 }
50
51 static ULONG WINAPI
52 CPinBaseImpl_fnRelease(IPin* iface)
53 {
54         ICOM_THIS(CPinBaseImpl,iface);
55
56         TRACE("(%p)->()\n",This);
57
58         return IUnknown_Release(This->punkControl);
59 }
60
61 static HRESULT WINAPI
62 CPinBaseImpl_fnConnect(IPin* iface,IPin* pPin,const AM_MEDIA_TYPE* pmt)
63 {
64         ICOM_THIS(CPinBaseImpl,iface);
65         HRESULT hr = E_NOTIMPL;
66         ULONG   i;
67
68         FIXME("(%p)->(%p,%p)\n",This,pPin,pmt);
69
70         if ( !This->bOutput )
71                 return E_UNEXPECTED;
72         if ( pPin == NULL )
73                 return E_POINTER;
74
75         TRACE("try to connect to %p\n",pPin);
76
77         EnterCriticalSection( This->pcsPin );
78
79         if ( This->pPinConnectedTo != NULL )
80         {
81                 hr = VFW_E_ALREADY_CONNECTED;
82                 goto err;
83         }
84
85         /* FIXME - return fail if running */
86
87         if ( This->pHandlers->pOnPreConnect != NULL )
88         {
89                 hr = This->pHandlers->pOnPreConnect(This,pPin);
90                 if ( FAILED(hr) )
91                         goto err;
92         }
93
94         if ( pmt != NULL )
95         {
96                 hr = IPin_QueryAccept(iface,pmt);
97                 if ( FAILED(hr) )
98                         goto err;
99                 hr = IPin_ReceiveConnection(pPin,iface,pmt);
100                 if ( FAILED(hr) )
101                         goto err;
102         }
103         else
104         {
105                 for ( i = 0; i < This->cAcceptTypes; i++ )
106                 {
107                         pmt = &This->pmtAcceptTypes[i];
108                         hr = IPin_QueryAccept(iface,pmt);
109                         if ( SUCCEEDED(hr) )
110                         {
111                                 hr = IPin_ReceiveConnection(pPin,iface,pmt);
112                                 if ( SUCCEEDED(hr) )
113                                 {
114                                         goto connected;
115                                 }
116                         }
117                 }
118
119                 hr = VFW_E_TYPE_NOT_ACCEPTED;
120                 goto err;
121         }
122
123 connected:;
124         This->pmtConn = QUARTZ_MediaType_Duplicate( pmt );
125         if ( This->pmtConn == NULL )
126         {
127                 hr = E_OUTOFMEMORY;
128                 IPin_Disconnect(pPin);
129                 goto err;
130         }
131
132         This->pPinConnectedTo = pPin; IPin_AddRef(pPin);
133         hr = IPin_QueryInterface(pPin,&IID_IMemInputPin,(void**)&This->pMemInputPinConnectedTo);
134         if ( FAILED(hr) )
135         {
136                 IPin_Disconnect(pPin);
137                 goto err;
138         }
139
140         if ( This->pHandlers->pOnPostConnect != NULL )
141         {
142                 hr = This->pHandlers->pOnPostConnect(This,pPin);
143                 if ( FAILED(hr) )
144                 {
145                         IPin_Disconnect(pPin);
146                         goto err;
147                 }
148         }
149
150         hr = S_OK;
151
152 err:
153         if ( FAILED(hr) )
154         {
155                 IPin_Disconnect(iface);
156         }
157         LeaveCriticalSection( This->pcsPin );
158
159         return hr;
160 }
161
162 static HRESULT WINAPI
163 CPinBaseImpl_fnReceiveConnection(IPin* iface,IPin* pPin,const AM_MEDIA_TYPE* pmt)
164 {
165         ICOM_THIS(CPinBaseImpl,iface);
166         HRESULT hr = E_NOTIMPL;
167
168         FIXME("(%p)->(%p,%p)\n",This,pPin,pmt);
169
170         if ( This->bOutput )
171                 return E_UNEXPECTED;
172         if ( pPin == NULL || pmt == NULL )
173                 return E_POINTER;
174
175         EnterCriticalSection( This->pcsPin );
176
177         if ( This->pPinConnectedTo != NULL )
178         {
179                 hr = VFW_E_ALREADY_CONNECTED;
180                 goto err;
181         }
182
183         /* FIXME - return fail if running */
184
185         if ( This->pHandlers->pOnPreConnect != NULL )
186         {
187                 hr = This->pHandlers->pOnPreConnect(This,pPin);
188                 if ( FAILED(hr) )
189                         goto err;
190         }
191
192         hr = IPin_QueryAccept(iface,pmt);
193         if ( FAILED(hr) )
194                 goto err;
195
196         This->pmtConn = QUARTZ_MediaType_Duplicate( pmt );
197         if ( This->pmtConn == NULL )
198         {
199                 hr = E_OUTOFMEMORY;
200                 goto err;
201         }
202
203         if ( This->pHandlers->pOnPostConnect != NULL )
204         {
205                 hr = This->pHandlers->pOnPostConnect(This,pPin);
206                 if ( FAILED(hr) )
207                         goto err;
208         }
209
210         hr = S_OK;
211         This->pPinConnectedTo = pPin; IPin_AddRef(pPin);
212
213 err:
214         if ( FAILED(hr) )
215                 IPin_Disconnect(iface);
216         LeaveCriticalSection( This->pcsPin );
217
218         return hr;
219 }
220
221 static HRESULT WINAPI
222 CPinBaseImpl_fnDisconnect(IPin* iface)
223 {
224         ICOM_THIS(CPinBaseImpl,iface);
225         HRESULT hr = NOERROR;
226
227         FIXME("(%p)->() stub!\n",This);
228
229         EnterCriticalSection( This->pcsPin );
230
231         /* FIXME - return fail if running */
232
233         if ( This->pHandlers->pOnDisconnect != NULL )
234                 hr = This->pHandlers->pOnDisconnect(This);
235
236         if ( This->pmtConn != NULL )
237         {
238                 QUARTZ_MediaType_Destroy( This->pmtConn );
239                 This->pmtConn = NULL;
240         }
241         if ( This->pMemInputPinConnectedTo != NULL )
242         {
243                 IMemInputPin_Release(This->pMemInputPinConnectedTo);
244                 This->pMemInputPinConnectedTo = NULL;
245         }
246         if ( This->pPinConnectedTo != NULL )
247         {
248                 /* FIXME - cleanup */
249
250                 IPin_Release(This->pPinConnectedTo);
251                 This->pPinConnectedTo = NULL;
252                 hr = NOERROR;
253         }
254         else
255         {
256                 hr = S_FALSE; /* FIXME - is this correct??? */
257         }
258
259         LeaveCriticalSection( This->pcsPin );
260
261         return hr;
262 }
263
264 static HRESULT WINAPI
265 CPinBaseImpl_fnConnectedTo(IPin* iface,IPin** ppPin)
266 {
267         ICOM_THIS(CPinBaseImpl,iface);
268         HRESULT hr = VFW_E_NOT_CONNECTED;
269
270         TRACE("(%p)->(%p)\n",This,ppPin);
271
272         if ( ppPin == NULL )
273                 return E_POINTER;
274
275         EnterCriticalSection( This->pcsPin );
276
277         *ppPin = This->pPinConnectedTo;
278         if ( This->pPinConnectedTo != NULL )
279         {
280                 IPin_AddRef(This->pPinConnectedTo);
281                 hr = NOERROR;
282         }
283
284         LeaveCriticalSection( This->pcsPin );
285
286         return hr;
287 }
288
289 static HRESULT WINAPI
290 CPinBaseImpl_fnConnectionMediaType(IPin* iface,AM_MEDIA_TYPE* pmt)
291 {
292         ICOM_THIS(CPinBaseImpl,iface);
293         HRESULT hr = E_FAIL;
294
295         TRACE("(%p)->(%p)\n",This,pmt);
296
297         if ( pmt == NULL )
298                 return E_POINTER;
299
300         EnterCriticalSection( This->pcsPin );
301
302         if ( This->pmtConn != NULL )
303         {
304                 hr = QUARTZ_MediaType_Copy( pmt, This->pmtConn );
305         }
306         else
307         {
308                 ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
309                 pmt->bFixedSizeSamples = TRUE;
310                 pmt->lSampleSize = 1;
311                 hr = NOERROR;
312         }
313
314         LeaveCriticalSection( This->pcsPin );
315
316         return hr;
317 }
318
319 static HRESULT WINAPI
320 CPinBaseImpl_fnQueryPinInfo(IPin* iface,PIN_INFO* pinfo)
321 {
322         ICOM_THIS(CPinBaseImpl,iface);
323
324         TRACE("(%p)->(%p)\n",This,pinfo);
325
326         if ( pinfo == NULL )
327                 return E_POINTER;
328
329         EnterCriticalSection( This->pcsPin );
330
331         ZeroMemory( pinfo, sizeof(PIN_INFO) );
332         pinfo->pFilter = (IBaseFilter*)(This->pFilter);
333         if ( pinfo->pFilter != NULL )
334                 IBaseFilter_AddRef( pinfo->pFilter );
335         pinfo->dir = This->bOutput ? PINDIR_OUTPUT : PINDIR_INPUT;
336         if ( This->cbIdLen <= sizeof(pinfo->achName) )
337                 memcpy( pinfo->achName, This->pwszId, This->cbIdLen );
338         else
339         {
340                 memcpy( pinfo->achName, This->pwszId, sizeof(pinfo->achName) );
341                 pinfo->achName[sizeof(pinfo->achName)/sizeof(pinfo->achName[0])-1] = 0;
342         }
343
344         LeaveCriticalSection( This->pcsPin );
345
346         return NOERROR;
347 }
348
349 static HRESULT WINAPI
350 CPinBaseImpl_fnQueryDirection(IPin* iface,PIN_DIRECTION* pdir)
351 {
352         ICOM_THIS(CPinBaseImpl,iface);
353
354         TRACE("(%p)->(%p)\n",This,pdir);
355
356         if ( pdir == NULL )
357                 return E_POINTER;
358
359         *pdir = This->bOutput ? PINDIR_OUTPUT : PINDIR_INPUT;
360
361         return NOERROR;
362 }
363
364 static HRESULT WINAPI
365 CPinBaseImpl_fnQueryId(IPin* iface,LPWSTR* lpwszId)
366 {
367         ICOM_THIS(CPinBaseImpl,iface);
368
369         TRACE("(%p)->(%p)\n",This,lpwszId);
370
371         if ( lpwszId == NULL )
372                 return E_POINTER;
373
374         *lpwszId = (WCHAR*)CoTaskMemAlloc( This->cbIdLen );
375         if ( *lpwszId == NULL )
376                 return E_OUTOFMEMORY;
377         memcpy( *lpwszId, This->pwszId, This->cbIdLen );
378
379         return NOERROR;
380 }
381
382 static HRESULT WINAPI
383 CPinBaseImpl_fnQueryAccept(IPin* iface,const AM_MEDIA_TYPE* pmt)
384 {
385         ICOM_THIS(CPinBaseImpl,iface);
386         HRESULT hr;
387
388         TRACE("(%p)->(%p)\n",This,pmt);
389
390         if ( pmt == NULL )
391                 return E_POINTER;
392
393         hr = NOERROR;
394         EnterCriticalSection( This->pcsPin );
395         if ( This->pHandlers->pCheckMediaType != NULL )
396                 hr = This->pHandlers->pCheckMediaType(This,pmt);
397         LeaveCriticalSection( This->pcsPin );
398
399         return hr;
400 }
401
402 static HRESULT WINAPI
403 CPinBaseImpl_fnEnumMediaTypes(IPin* iface,IEnumMediaTypes** ppenum)
404 {
405         ICOM_THIS(CPinBaseImpl,iface);
406         HRESULT hr;
407
408         TRACE("(%p)->(%p)\n",This,ppenum);
409
410         if ( ppenum == NULL )
411                 return E_POINTER;
412
413         hr = E_NOTIMPL;
414
415         EnterCriticalSection( This->pcsPin );
416         if ( This->cAcceptTypes > 0 )
417                 hr = QUARTZ_CreateEnumMediaTypes(
418                         ppenum, This->pmtAcceptTypes, This->cAcceptTypes );
419         LeaveCriticalSection( This->pcsPin );
420
421         return hr;
422 }
423
424 static HRESULT WINAPI
425 CPinBaseImpl_fnQueryInternalConnections(IPin* iface,IPin** ppPin,ULONG* pul)
426 {
427         ICOM_THIS(CPinBaseImpl,iface);
428
429         TRACE("(%p)->(%p,%p)\n",This,ppPin,pul);
430
431         /* E_NOTIMPL means 'no internal connections'. */
432         return E_NOTIMPL;
433 }
434
435 static HRESULT WINAPI
436 CPinBaseImpl_fnEndOfStream(IPin* iface)
437 {
438         ICOM_THIS(CPinBaseImpl,iface);
439         HRESULT hr = E_NOTIMPL;
440
441         TRACE("(%p)->()\n",This);
442
443         if ( This->bOutput )
444                 return E_UNEXPECTED;
445
446         EnterCriticalSection( This->pcsPin );
447         if ( This->pHandlers->pEndOfStream != NULL )
448                 hr = This->pHandlers->pEndOfStream(This);
449         LeaveCriticalSection( This->pcsPin );
450
451         return hr;
452 }
453
454 static HRESULT WINAPI
455 CPinBaseImpl_fnBeginFlush(IPin* iface)
456 {
457         ICOM_THIS(CPinBaseImpl,iface);
458         HRESULT hr = E_NOTIMPL;
459
460         TRACE("(%p)->()\n",This);
461
462         if ( This->bOutput )
463                 return E_UNEXPECTED;
464
465         EnterCriticalSection( This->pcsPin );
466         if ( This->pHandlers->pBeginFlush != NULL )
467                 hr = This->pHandlers->pBeginFlush(This);
468         LeaveCriticalSection( This->pcsPin );
469
470         return hr;
471 }
472
473 static HRESULT WINAPI
474 CPinBaseImpl_fnEndFlush(IPin* iface)
475 {
476         ICOM_THIS(CPinBaseImpl,iface);
477         HRESULT hr = E_NOTIMPL;
478
479         TRACE("(%p)->()\n",This);
480
481         if ( This->bOutput )
482                 return E_UNEXPECTED;
483
484         EnterCriticalSection( This->pcsPin );
485         if ( This->pHandlers->pEndFlush != NULL )
486                 hr = This->pHandlers->pEndFlush(This);
487         LeaveCriticalSection( This->pcsPin );
488
489         return hr;
490 }
491
492 static HRESULT WINAPI
493 CPinBaseImpl_fnNewSegment(IPin* iface,REFERENCE_TIME rtStart,REFERENCE_TIME rtStop,double rate)
494 {
495         ICOM_THIS(CPinBaseImpl,iface);
496         HRESULT hr = E_NOTIMPL;
497
498         TRACE("(%p)->()\n",This);
499
500         if ( This->bOutput )
501                 return E_UNEXPECTED;
502
503         EnterCriticalSection( This->pcsPin );
504         if ( This->pHandlers->pNewSegment != NULL )
505                 hr = This->pHandlers->pNewSegment(This,rtStart,rtStop,rate);
506         LeaveCriticalSection( This->pcsPin );
507
508         return hr;
509 }
510
511
512
513
514 static ICOM_VTABLE(IPin) ipin =
515 {
516         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
517         /* IUnknown fields */
518         CPinBaseImpl_fnQueryInterface,
519         CPinBaseImpl_fnAddRef,
520         CPinBaseImpl_fnRelease,
521         /* IPin fields */
522         CPinBaseImpl_fnConnect,
523         CPinBaseImpl_fnReceiveConnection,
524         CPinBaseImpl_fnDisconnect,
525         CPinBaseImpl_fnConnectedTo,
526         CPinBaseImpl_fnConnectionMediaType,
527         CPinBaseImpl_fnQueryPinInfo,
528         CPinBaseImpl_fnQueryDirection,
529         CPinBaseImpl_fnQueryId,
530         CPinBaseImpl_fnQueryAccept,
531         CPinBaseImpl_fnEnumMediaTypes,
532         CPinBaseImpl_fnQueryInternalConnections,
533         CPinBaseImpl_fnEndOfStream,
534         CPinBaseImpl_fnBeginFlush,
535         CPinBaseImpl_fnEndFlush,
536         CPinBaseImpl_fnNewSegment,
537 };
538
539
540 HRESULT CPinBaseImpl_InitIPin(
541         CPinBaseImpl* This, IUnknown* punkControl,
542         CRITICAL_SECTION* pcsPin,
543         CBaseFilterImpl* pFilter, LPCWSTR pwszId,
544         BOOL bOutput,
545         const CBasePinHandlers* pHandlers )
546 {
547         HRESULT hr = NOERROR;
548
549         TRACE("(%p,%p,%p)\n",This,punkControl,pFilter);
550
551         if ( punkControl == NULL )
552         {
553                 ERR( "punkControl must not be NULL\n" );
554                 return E_INVALIDARG;
555         }
556
557         ICOM_VTBL(This) = &ipin;
558         This->punkControl = punkControl;
559         This->pHandlers = pHandlers;
560         This->cbIdLen = sizeof(WCHAR)*(lstrlenW(pwszId)+1);
561         This->pwszId = NULL;
562         This->bOutput = bOutput;
563         This->pmtAcceptTypes = NULL;
564         This->cAcceptTypes = 0;
565         This->pcsPin = pcsPin;
566         This->pFilter = pFilter;
567         This->pPinConnectedTo = NULL;
568         This->pMemInputPinConnectedTo = NULL;
569         This->pmtConn = NULL;
570         This->pAsyncOut = NULL;
571
572         This->pwszId = (WCHAR*)QUARTZ_AllocMem( This->cbIdLen );
573         if ( This->pwszId == NULL )
574         {
575                 hr = E_OUTOFMEMORY;
576                 goto err;
577         }
578         memcpy( This->pwszId, pwszId, This->cbIdLen );
579
580         return NOERROR;
581
582 err:;
583         CPinBaseImpl_UninitIPin( This );
584         return hr;
585 }
586
587 void CPinBaseImpl_UninitIPin( CPinBaseImpl* This )
588 {
589         TRACE("(%p)\n",This);
590
591         IPin_Disconnect( (IPin*)(This) );
592
593         if ( This->pwszId != NULL )
594         {
595                 QUARTZ_FreeMem( This->pwszId );
596                 This->pwszId = NULL;
597         }
598 }
599
600
601 /***************************************************************************
602  *
603  *      CMemInputPinBaseImpl
604  *
605  */
606
607
608 static HRESULT WINAPI
609 CMemInputPinBaseImpl_fnQueryInterface(IMemInputPin* iface,REFIID riid,void** ppobj)
610 {
611         ICOM_THIS(CMemInputPinBaseImpl,iface);
612
613         TRACE("(%p)->()\n",This);
614
615         return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
616 }
617
618 static ULONG WINAPI
619 CMemInputPinBaseImpl_fnAddRef(IMemInputPin* iface)
620 {
621         ICOM_THIS(CMemInputPinBaseImpl,iface);
622
623         TRACE("(%p)->()\n",This);
624
625         return IUnknown_AddRef(This->punkControl);
626 }
627
628 static ULONG WINAPI
629 CMemInputPinBaseImpl_fnRelease(IMemInputPin* iface)
630 {
631         ICOM_THIS(CMemInputPinBaseImpl,iface);
632
633         TRACE("(%p)->()\n",This);
634
635         return IUnknown_Release(This->punkControl);
636 }
637
638
639 static HRESULT WINAPI
640 CMemInputPinBaseImpl_fnGetAllocator(IMemInputPin* iface,IMemAllocator** ppAllocator)
641 {
642         ICOM_THIS(CMemInputPinBaseImpl,iface);
643         HRESULT hr = NOERROR;
644         IUnknown* punk;
645
646         TRACE("(%p)->()\n",This);
647
648         if ( ppAllocator == NULL )
649                 return E_POINTER;
650
651         EnterCriticalSection( This->pPin->pcsPin );
652
653         if ( This->pAllocator == NULL )
654         {
655                 hr = QUARTZ_CreateMemoryAllocator(NULL,(void**)&punk);
656                 if ( hr == NOERROR )
657                 {
658                         hr = IUnknown_QueryInterface(punk,
659                                 &IID_IMemAllocator,(void**)&This->pAllocator);
660                         IUnknown_Release(punk);
661                 }
662         }
663
664         if ( hr == NOERROR )
665         {
666                 *ppAllocator = This->pAllocator;
667                 IMemAllocator_AddRef(This->pAllocator);
668         }
669
670         LeaveCriticalSection( This->pPin->pcsPin );
671
672         return hr;
673 }
674
675 static HRESULT WINAPI
676 CMemInputPinBaseImpl_fnNotifyAllocator(IMemInputPin* iface,IMemAllocator* pAllocator,BOOL bReadonly)
677 {
678         ICOM_THIS(CMemInputPinBaseImpl,iface);
679
680         TRACE("(%p)->()\n",This);
681
682         if ( pAllocator == NULL )
683                 return E_POINTER;
684
685         EnterCriticalSection( This->pPin->pcsPin );
686
687         if ( This->pAllocator != NULL )
688         {
689                 IMemAllocator_Release(This->pAllocator);
690                 This->pAllocator = NULL;
691         }
692         This->pAllocator = pAllocator;
693         IMemAllocator_AddRef(This->pAllocator);
694
695         This->bReadonly = bReadonly;
696
697         LeaveCriticalSection( This->pPin->pcsPin );
698
699         return NOERROR;
700 }
701
702 static HRESULT WINAPI
703 CMemInputPinBaseImpl_fnGetAllocatorRequirements(IMemInputPin* iface,ALLOCATOR_PROPERTIES* pProp)
704 {
705         ICOM_THIS(CMemInputPinBaseImpl,iface);
706
707         TRACE("(%p)->(%p)\n",This,pProp);
708
709         if ( pProp == NULL )
710                 return E_POINTER;
711
712         /* E_MOTIMPL means 'no requirements' */
713         return E_NOTIMPL;
714 }
715
716 static HRESULT WINAPI
717 CMemInputPinBaseImpl_fnReceive(IMemInputPin* iface,IMediaSample* pSample)
718 {
719         ICOM_THIS(CMemInputPinBaseImpl,iface);
720         HRESULT hr = E_NOTIMPL;
721
722         TRACE("(%p)->(%p)\n",This,pSample);
723
724         EnterCriticalSection( This->pPin->pcsPin );
725         if ( This->pPin->pHandlers->pReceive != NULL )
726                 hr = This->pPin->pHandlers->pReceive(This->pPin,pSample);
727         LeaveCriticalSection( This->pPin->pcsPin );
728
729         return hr;
730 }
731
732 static HRESULT WINAPI
733 CMemInputPinBaseImpl_fnReceiveMultiple(IMemInputPin* iface,IMediaSample** ppSample,long nSample,long* pnSampleProcessed)
734 {
735         ICOM_THIS(CMemInputPinBaseImpl,iface);
736         long    n;
737         HRESULT hr;
738
739         TRACE("(%p)->()\n",This);
740
741         if ( ppSample == NULL || pnSampleProcessed == NULL )
742                 return E_POINTER;
743
744         EnterCriticalSection( This->pPin->pcsPin );
745
746         hr = NOERROR;
747         for ( n = 0; n < nSample; n++ )
748         {
749                 hr = IMemInputPin_Receive(iface,ppSample[n]);
750                 if ( FAILED(hr) )
751                         break;
752         }
753
754         LeaveCriticalSection( This->pPin->pcsPin );
755
756         *pnSampleProcessed = n;
757         return hr;
758 }
759
760 static HRESULT WINAPI
761 CMemInputPinBaseImpl_fnReceiveCanBlock(IMemInputPin* iface)
762 {
763         ICOM_THIS(CMemInputPinBaseImpl,iface);
764         HRESULT hr = E_NOTIMPL;
765
766         TRACE("(%p)->()\n",This);
767
768         EnterCriticalSection( This->pPin->pcsPin );
769         if ( This->pPin->pHandlers->pReceiveCanBlock != NULL )
770                 hr = This->pPin->pHandlers->pReceiveCanBlock(This->pPin);
771         LeaveCriticalSection( This->pPin->pcsPin );
772
773         return hr;
774 }
775
776
777 static ICOM_VTABLE(IMemInputPin) imeminputpin =
778 {
779         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
780         /* IUnknown fields */
781         CMemInputPinBaseImpl_fnQueryInterface,
782         CMemInputPinBaseImpl_fnAddRef,
783         CMemInputPinBaseImpl_fnRelease,
784         /* IMemInputPin fields */
785         CMemInputPinBaseImpl_fnGetAllocator,
786         CMemInputPinBaseImpl_fnNotifyAllocator,
787         CMemInputPinBaseImpl_fnGetAllocatorRequirements,
788         CMemInputPinBaseImpl_fnReceive,
789         CMemInputPinBaseImpl_fnReceiveMultiple,
790         CMemInputPinBaseImpl_fnReceiveCanBlock,
791 };
792
793 HRESULT CMemInputPinBaseImpl_InitIMemInputPin(
794         CMemInputPinBaseImpl* This, IUnknown* punkControl,
795         CPinBaseImpl* pPin )
796 {
797         TRACE("(%p,%p)\n",This,punkControl);
798
799         if ( punkControl == NULL )
800         {
801                 ERR( "punkControl must not be NULL\n" );
802                 return E_INVALIDARG;
803         }
804
805         ICOM_VTBL(This) = &imeminputpin;
806         This->punkControl = punkControl;
807         This->pPin = pPin;
808         This->pAllocator = NULL;
809         This->bReadonly = FALSE;
810
811         return NOERROR;
812 }
813
814 void CMemInputPinBaseImpl_UninitIMemInputPin(
815         CMemInputPinBaseImpl* This )
816 {
817         TRACE("(%p)\n",This);
818
819         if ( This->pAllocator != NULL )
820         {
821                 IMemAllocator_Release(This->pAllocator);
822                 This->pAllocator = NULL;
823         }
824 }
825
826 /***************************************************************************
827  *
828  *      CQualityControlPassThruImpl
829  *
830  */
831
832 static HRESULT WINAPI
833 CQualityControlPassThruImpl_fnQueryInterface(IQualityControl* iface,REFIID riid,void** ppobj)
834 {
835         ICOM_THIS(CQualityControlPassThruImpl,iface);
836
837         TRACE("(%p)->()\n",This);
838
839         return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
840 }
841
842 static ULONG WINAPI
843 CQualityControlPassThruImpl_fnAddRef(IQualityControl* iface)
844 {
845         ICOM_THIS(CQualityControlPassThruImpl,iface);
846
847         TRACE("(%p)->()\n",This);
848
849         return IUnknown_AddRef(This->punkControl);
850 }
851
852 static ULONG WINAPI
853 CQualityControlPassThruImpl_fnRelease(IQualityControl* iface)
854 {
855         ICOM_THIS(CQualityControlPassThruImpl,iface);
856
857         TRACE("(%p)->()\n",This);
858
859         return IUnknown_Release(This->punkControl);
860 }
861
862
863 static HRESULT WINAPI
864 CQualityControlPassThruImpl_fnNotify(IQualityControl* iface,IBaseFilter* pFilter,Quality q)
865 {
866         ICOM_THIS(CQualityControlPassThruImpl,iface);
867         HRESULT hr = S_FALSE;
868
869         TRACE("(%p)->()\n",This);
870
871         if ( This->pControl != NULL )
872                 return IQualityControl_Notify( This->pControl, pFilter, q );
873
874         EnterCriticalSection( This->pPin->pcsPin );
875         if ( This->pPin->pHandlers->pQualityNotify != NULL )
876                 hr = This->pPin->pHandlers->pQualityNotify(This->pPin,pFilter,q);
877         LeaveCriticalSection( This->pPin->pcsPin );
878
879         return hr;
880 }
881
882 static HRESULT WINAPI
883 CQualityControlPassThruImpl_fnSetSink(IQualityControl* iface,IQualityControl* pControl)
884 {
885         ICOM_THIS(CQualityControlPassThruImpl,iface);
886
887         TRACE("(%p)->()\n",This);
888
889         This->pControl = pControl; /* AddRef() must not be called */
890
891         return NOERROR;
892 }
893
894 static ICOM_VTABLE(IQualityControl) iqualitycontrol =
895 {
896         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
897         /* IUnknown fields */
898         CQualityControlPassThruImpl_fnQueryInterface,
899         CQualityControlPassThruImpl_fnAddRef,
900         CQualityControlPassThruImpl_fnRelease,
901         /* IQualityControl fields */
902         CQualityControlPassThruImpl_fnNotify,
903         CQualityControlPassThruImpl_fnSetSink,
904 };
905
906 HRESULT CQualityControlPassThruImpl_InitIQualityControl(
907         CQualityControlPassThruImpl* This, IUnknown* punkControl,
908         CPinBaseImpl* pPin )
909 {
910         TRACE("(%p,%p)\n",This,punkControl);
911
912         if ( punkControl == NULL )
913         {
914                 ERR( "punkControl must not be NULL\n" );
915                 return E_INVALIDARG;
916         }
917
918         ICOM_VTBL(This) = &iqualitycontrol;
919         This->punkControl = punkControl;
920         This->pPin = pPin;
921
922         return NOERROR;
923 }
924
925 void CQualityControlPassThruImpl_UninitIQualityControl(
926         CQualityControlPassThruImpl* This )
927 {
928 }
929
930 /***************************************************************************
931  *
932  *      helper methods for output pins.
933  *
934  */
935
936 HRESULT CPinBaseImpl_SendSample( CPinBaseImpl* This, IMediaSample* pSample )
937 {
938         if ( This->pHandlers->pReceive == NULL )
939                 return E_NOTIMPL;
940
941         return This->pHandlers->pReceive( This, pSample );
942 }
943
944 HRESULT CPinBaseImpl_SendEndOfStream( CPinBaseImpl* This )
945 {
946         if ( This->pHandlers->pEndOfStream == NULL )
947                 return E_NOTIMPL;
948
949         return This->pHandlers->pEndOfStream( This );
950 }
951
952 HRESULT CPinBaseImpl_SendBeginFlush( CPinBaseImpl* This )
953 {
954         if ( This->pHandlers->pBeginFlush == NULL )
955                 return E_NOTIMPL;
956
957         return This->pHandlers->pBeginFlush( This );
958 }
959
960 HRESULT CPinBaseImpl_SendEndFlush( CPinBaseImpl* This )
961 {
962         if ( This->pHandlers->pEndFlush == NULL )
963                 return E_NOTIMPL;
964
965         return This->pHandlers->pEndFlush( This );
966 }
967
968 HRESULT CPinBaseImpl_SendNewSegment( CPinBaseImpl* This, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
969 {
970         if ( This->pHandlers->pNewSegment == NULL )
971                 return E_NOTIMPL;
972
973         return This->pHandlers->pNewSegment( This, rtStart, rtStop, rate );
974 }
975
976
977
978 /***************************************************************************
979  *
980  *      handlers for output pins.
981  *
982  */
983
984 HRESULT OutputPinSync_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
985 {
986         if ( pImpl->pMemInputPinConnectedTo == NULL )
987                 return NOERROR;
988
989         return IMemInputPin_Receive(pImpl->pMemInputPinConnectedTo,pSample);
990 }
991
992 HRESULT OutputPinSync_ReceiveCanBlock( CPinBaseImpl* pImpl )
993 {
994         if ( pImpl->pMemInputPinConnectedTo == NULL )
995                 return S_FALSE;
996
997         return IMemInputPin_ReceiveCanBlock(pImpl->pMemInputPinConnectedTo);
998 }
999
1000 HRESULT OutputPinSync_EndOfStream( CPinBaseImpl* pImpl )
1001 {
1002         if ( pImpl->pPinConnectedTo == NULL )
1003                 return NOERROR;
1004
1005         return IPin_EndOfStream(pImpl->pPinConnectedTo);
1006 }
1007
1008 HRESULT OutputPinSync_BeginFlush( CPinBaseImpl* pImpl )
1009 {
1010         if ( pImpl->pPinConnectedTo == NULL )
1011                 return NOERROR;
1012
1013         return IPin_BeginFlush(pImpl->pPinConnectedTo);
1014 }
1015
1016 HRESULT OutputPinSync_EndFlush( CPinBaseImpl* pImpl )
1017 {
1018         if ( pImpl->pPinConnectedTo == NULL )
1019                 return NOERROR;
1020
1021         return IPin_EndFlush(pImpl->pPinConnectedTo);
1022 }
1023
1024 HRESULT OutputPinSync_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
1025 {
1026         if ( pImpl->pPinConnectedTo == NULL )
1027                 return NOERROR;
1028
1029         return IPin_NewSegment(pImpl->pPinConnectedTo,rtStart,rtStop,rate);
1030 }
1031
1032 /***************************************************************************
1033  *
1034  *      handlers for output pins (async).
1035  *
1036  */
1037
1038 typedef struct OutputPinTask OutputPinTask;
1039
1040 enum OutputPinTaskType
1041 {
1042         OutTask_ExitThread,
1043         OutTask_Receive,
1044         OutTask_EndOfStream,
1045         OutTask_BeginFlush,
1046         OutTask_EndFlush,
1047         OutTask_NewSegment,
1048 };
1049
1050 struct OutputPinTask
1051 {
1052         OutputPinTask* pNext;
1053         enum OutputPinTaskType tasktype;
1054         IMediaSample* pSample;
1055         REFERENCE_TIME rtStart;
1056         REFERENCE_TIME rtStop;
1057         double rate;
1058 };
1059
1060 struct OutputPinAsyncImpl
1061 {
1062         HANDLE m_hTaskThread;
1063         HANDLE m_hTaskEvent;
1064         IPin* m_pPin; /* connected pin */
1065         IMemInputPin* m_pMemInputPin; /* connected pin */
1066         CRITICAL_SECTION m_csTasks;
1067         OutputPinTask* m_pFirst;
1068         OutputPinTask* m_pLast;
1069         OutputPinTask* m_pTaskExitThread;
1070 };
1071
1072 static OutputPinTask* OutputPinAsync_AllocTask( enum OutputPinTaskType tasktype )
1073 {
1074         OutputPinTask* pTask;
1075
1076         pTask = (OutputPinTask*)QUARTZ_AllocMem( sizeof(OutputPinTask) );
1077         pTask->pNext = NULL;
1078         pTask->tasktype = tasktype;
1079         pTask->pSample = NULL;
1080
1081         return pTask;
1082 }
1083
1084 static void OutputPinAsync_FreeTask( OutputPinTask* pTask )
1085 {
1086         if ( pTask->pSample != NULL )
1087                 IMediaSample_Release( pTask->pSample );
1088         QUARTZ_FreeMem( pTask );
1089 }
1090
1091 static void OutputPinAsync_AddTask( OutputPinAsyncImpl* This, OutputPinTask* pTask, BOOL bFirst )
1092 {
1093         EnterCriticalSection( &This->m_csTasks );
1094
1095         if ( bFirst )
1096         {
1097                 pTask->pNext = This->m_pFirst;
1098                 This->m_pFirst = pTask;
1099                 if ( This->m_pLast == NULL )
1100                         This->m_pLast = pTask;
1101         }
1102         else
1103         {
1104                 if ( This->m_pLast != NULL )
1105                         This->m_pLast->pNext = pTask;
1106                 else
1107                         This->m_pFirst = pTask;
1108                 This->m_pLast = pTask;
1109         }
1110
1111         LeaveCriticalSection( &This->m_csTasks );
1112
1113         SetEvent( This->m_hTaskEvent );
1114 }
1115
1116 static OutputPinTask* OutputPinAsync_GetNextTask( OutputPinAsyncImpl* This )
1117 {
1118         OutputPinTask* pTask;
1119
1120         EnterCriticalSection( &This->m_csTasks );
1121         pTask = This->m_pFirst;
1122         if ( pTask != NULL )
1123         {
1124                 This->m_pFirst = pTask->pNext;
1125                 if ( This->m_pFirst == NULL )
1126                         This->m_pLast = NULL;
1127                 else
1128                         SetEvent( This->m_hTaskEvent );
1129         }
1130
1131         LeaveCriticalSection( &This->m_csTasks );
1132
1133         return pTask;
1134 }
1135
1136 static DWORD WINAPI OutputPinAsync_ThreadEntry( LPVOID pv )
1137 {
1138         OutputPinAsyncImpl* This = ((CPinBaseImpl*)pv)->pAsyncOut;
1139         OutputPinTask* pTask;
1140         BOOL bLoop = TRUE;
1141         BOOL bInFlush = FALSE;
1142         HRESULT hr;
1143
1144         while ( bLoop )
1145         {
1146                 WaitForSingleObject( This->m_hTaskEvent, INFINITE );
1147                 ResetEvent( This->m_hTaskEvent );
1148
1149                 pTask = OutputPinAsync_GetNextTask( This );
1150                 if ( pTask == NULL )
1151                         continue;
1152
1153                 hr = S_OK;
1154                 switch ( pTask->tasktype )
1155                 {
1156                 case OutTask_ExitThread:
1157                         bLoop = FALSE;
1158                         break;
1159                 case OutTask_Receive:
1160                         if ( !bInFlush )
1161                                 hr = IMemInputPin_Receive( This->m_pMemInputPin, pTask->pSample );
1162                         break;
1163                 case OutTask_EndOfStream:
1164                         hr = IPin_EndOfStream( This->m_pPin );
1165                         break;
1166                 case OutTask_BeginFlush:
1167                         bInFlush = TRUE;
1168                         hr = IPin_BeginFlush( This->m_pPin );
1169                         break;
1170                 case OutTask_EndFlush:
1171                         bInFlush = FALSE;
1172                         hr = IPin_EndFlush( This->m_pPin );
1173                         break;
1174                 case OutTask_NewSegment:
1175                         hr = IPin_NewSegment( This->m_pPin, pTask->rtStart, pTask->rtStop, pTask->rate );
1176                         break;
1177                 default:
1178                         ERR( "unexpected task type %d.\n", pTask->tasktype );
1179                         bLoop = FALSE;
1180                         break;
1181                 }
1182
1183                 OutputPinAsync_FreeTask( pTask );
1184
1185                 if ( FAILED(hr) )
1186                 {
1187                         ERR( "hresult %08lx\n", hr );
1188                         bLoop = FALSE;
1189                 }
1190         }
1191
1192         return 0;
1193 }
1194
1195 HRESULT OutputPinAsync_OnActive( CPinBaseImpl* pImpl )
1196 {
1197         HRESULT hr;
1198         DWORD dwThreadId;
1199
1200         FIXME("(%p)\n",pImpl);
1201
1202         if ( pImpl->pMemInputPinConnectedTo == NULL )
1203                 return NOERROR;
1204
1205         pImpl->pAsyncOut = (OutputPinAsyncImpl*)
1206                 QUARTZ_AllocMem( sizeof( OutputPinAsyncImpl ) );
1207         if ( pImpl->pAsyncOut == NULL )
1208                 return E_OUTOFMEMORY;
1209
1210         InitializeCriticalSection( &pImpl->pAsyncOut->m_csTasks );
1211         pImpl->pAsyncOut->m_hTaskThread = (HANDLE)NULL;
1212         pImpl->pAsyncOut->m_hTaskEvent = (HANDLE)NULL;
1213         pImpl->pAsyncOut->m_pFirst = NULL;
1214         pImpl->pAsyncOut->m_pLast = NULL;
1215         pImpl->pAsyncOut->m_pTaskExitThread = NULL;
1216         pImpl->pAsyncOut->m_pPin = pImpl->pPinConnectedTo;
1217         pImpl->pAsyncOut->m_pMemInputPin = pImpl->pMemInputPinConnectedTo;
1218
1219         pImpl->pAsyncOut->m_hTaskEvent =
1220                 CreateEventA( NULL, TRUE, FALSE, NULL );
1221         if ( pImpl->pAsyncOut->m_hTaskEvent == (HANDLE)NULL )
1222         {
1223                 hr = E_FAIL;
1224                 goto err;
1225         }
1226
1227         pImpl->pAsyncOut->m_pTaskExitThread =
1228                 OutputPinAsync_AllocTask( OutTask_ExitThread );
1229         if ( pImpl->pAsyncOut->m_pTaskExitThread == NULL )
1230         {
1231                 hr = E_OUTOFMEMORY;
1232                 goto err;
1233         }
1234
1235         pImpl->pAsyncOut->m_hTaskThread = CreateThread(
1236                 NULL, 0, OutputPinAsync_ThreadEntry, pImpl,
1237                 0, &dwThreadId );
1238         if ( pImpl->pAsyncOut->m_hTaskThread == (HANDLE)NULL )
1239         {
1240                 hr = E_FAIL;
1241                 goto err;
1242         }
1243
1244         return NOERROR;
1245 err:
1246         OutputPinAsync_OnInactive( pImpl );
1247         return hr;
1248 }
1249
1250 HRESULT OutputPinAsync_OnInactive( CPinBaseImpl* pImpl )
1251 {
1252         OutputPinTask* pTask;
1253
1254         FIXME("(%p)\n",pImpl);
1255
1256         if ( pImpl->pAsyncOut == NULL )
1257                 return NOERROR;
1258
1259         if ( pImpl->pAsyncOut->m_pTaskExitThread != NULL )
1260         {
1261                 OutputPinAsync_AddTask( pImpl->pAsyncOut, pImpl->pAsyncOut->m_pTaskExitThread, TRUE );
1262                 pImpl->pAsyncOut->m_pTaskExitThread = NULL;
1263         }
1264
1265         if ( pImpl->pAsyncOut->m_hTaskThread != (HANDLE)NULL )
1266         {
1267                 WaitForSingleObject( pImpl->pAsyncOut->m_hTaskThread, INFINITE );
1268                 CloseHandle( pImpl->pAsyncOut->m_hTaskThread );
1269         }
1270         if ( pImpl->pAsyncOut->m_hTaskEvent != (HANDLE)NULL )
1271                 CloseHandle( pImpl->pAsyncOut->m_hTaskEvent );
1272
1273         /* release all tasks. */
1274         while ( 1 )
1275         {
1276                 pTask = OutputPinAsync_GetNextTask( pImpl->pAsyncOut );
1277                 if ( pTask == NULL )
1278                         break;
1279                 OutputPinAsync_FreeTask( pTask );
1280         }
1281
1282         DeleteCriticalSection( &pImpl->pAsyncOut->m_csTasks );
1283
1284         QUARTZ_FreeMem( pImpl->pAsyncOut );
1285         pImpl->pAsyncOut = NULL;
1286
1287         return NOERROR;
1288 }
1289
1290 HRESULT OutputPinAsync_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
1291 {
1292         OutputPinAsyncImpl* This = pImpl->pAsyncOut;
1293         OutputPinTask* pTask;
1294
1295         TRACE("(%p,%p)\n",pImpl,pSample);
1296
1297         if ( This == NULL )
1298                 return NOERROR;
1299
1300         pTask = OutputPinAsync_AllocTask( OutTask_Receive );
1301         if ( pTask == NULL )
1302                 return E_OUTOFMEMORY;
1303         pTask->pSample = pSample; IMediaSample_AddRef( pSample );
1304         OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE );
1305
1306         return NOERROR;
1307 }
1308
1309 HRESULT OutputPinAsync_ReceiveCanBlock( CPinBaseImpl* pImpl )
1310 {
1311         return S_FALSE;
1312 }
1313
1314 HRESULT OutputPinAsync_EndOfStream( CPinBaseImpl* pImpl )
1315 {
1316         OutputPinAsyncImpl* This = pImpl->pAsyncOut;
1317         OutputPinTask* pTask;
1318
1319         TRACE("(%p)\n",pImpl);
1320
1321         if ( This == NULL )
1322                 return NOERROR;
1323
1324         pTask = OutputPinAsync_AllocTask( OutTask_EndOfStream );
1325         if ( pTask == NULL )
1326                 return E_OUTOFMEMORY;
1327         OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE );
1328
1329         return NOERROR;
1330 }
1331
1332 HRESULT OutputPinAsync_BeginFlush( CPinBaseImpl* pImpl )
1333 {
1334         OutputPinAsyncImpl* This = pImpl->pAsyncOut;
1335         OutputPinTask* pTask;
1336
1337         TRACE("(%p)\n",pImpl);
1338
1339         if ( This == NULL )
1340                 return NOERROR;
1341
1342         pTask = OutputPinAsync_AllocTask( OutTask_BeginFlush );
1343         if ( pTask == NULL )
1344                 return E_OUTOFMEMORY;
1345         OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, TRUE );
1346
1347         return NOERROR;
1348 }
1349
1350 HRESULT OutputPinAsync_EndFlush( CPinBaseImpl* pImpl )
1351 {
1352         OutputPinAsyncImpl* This = pImpl->pAsyncOut;
1353         OutputPinTask* pTask;
1354
1355         TRACE("(%p)\n",pImpl);
1356
1357         if ( This == NULL )
1358                 return NOERROR;
1359
1360         pTask = OutputPinAsync_AllocTask( OutTask_EndFlush );
1361         if ( pTask == NULL )
1362                 return E_OUTOFMEMORY;
1363         OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE );
1364
1365         return NOERROR;
1366 }
1367
1368 HRESULT OutputPinAsync_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
1369 {
1370         OutputPinAsyncImpl* This = pImpl->pAsyncOut;
1371         OutputPinTask* pTask;
1372
1373         TRACE("(%p)\n",pImpl);
1374
1375         if ( This == NULL )
1376                 return NOERROR;
1377
1378         pTask = OutputPinAsync_AllocTask( OutTask_NewSegment );
1379         if ( pTask == NULL )
1380                 return E_OUTOFMEMORY;
1381         pTask->rtStart = rtStart;
1382         pTask->rtStop = rtStop;
1383         pTask->rate = rate;
1384         OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE );
1385
1386         return NOERROR;
1387 }
1388
1389