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