Various cosmetic changes.
[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->pcsPinReceive );
492         if ( This->pHandlers->pEndOfStream != NULL )
493                 hr = This->pHandlers->pEndOfStream(This);
494         LeaveCriticalSection( This->pcsPinReceive );
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         EnterCriticalSection( This->pcsPinReceive );
516         LeaveCriticalSection( This->pcsPinReceive );
517
518         return hr;
519 }
520
521 static HRESULT WINAPI
522 CPinBaseImpl_fnEndFlush(IPin* iface)
523 {
524         ICOM_THIS(CPinBaseImpl,iface);
525         HRESULT hr = E_NOTIMPL;
526
527         TRACE("(%p)->()\n",This);
528
529         if ( This->bOutput )
530                 return E_UNEXPECTED;
531
532         EnterCriticalSection( This->pcsPin );
533         if ( This->pHandlers->pEndFlush != NULL )
534                 hr = This->pHandlers->pEndFlush(This);
535         LeaveCriticalSection( This->pcsPin );
536
537         return hr;
538 }
539
540 static HRESULT WINAPI
541 CPinBaseImpl_fnNewSegment(IPin* iface,REFERENCE_TIME rtStart,REFERENCE_TIME rtStop,double rate)
542 {
543         ICOM_THIS(CPinBaseImpl,iface);
544         HRESULT hr = E_NOTIMPL;
545
546         TRACE("(%p)->()\n",This);
547
548         if ( This->bOutput )
549                 return E_UNEXPECTED;
550
551         EnterCriticalSection( This->pcsPin );
552         if ( This->pHandlers->pNewSegment != NULL )
553                 hr = This->pHandlers->pNewSegment(This,rtStart,rtStop,rate);
554         LeaveCriticalSection( This->pcsPin );
555
556         return hr;
557 }
558
559
560
561
562 static ICOM_VTABLE(IPin) ipin =
563 {
564         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
565         /* IUnknown fields */
566         CPinBaseImpl_fnQueryInterface,
567         CPinBaseImpl_fnAddRef,
568         CPinBaseImpl_fnRelease,
569         /* IPin fields */
570         CPinBaseImpl_fnConnect,
571         CPinBaseImpl_fnReceiveConnection,
572         CPinBaseImpl_fnDisconnect,
573         CPinBaseImpl_fnConnectedTo,
574         CPinBaseImpl_fnConnectionMediaType,
575         CPinBaseImpl_fnQueryPinInfo,
576         CPinBaseImpl_fnQueryDirection,
577         CPinBaseImpl_fnQueryId,
578         CPinBaseImpl_fnQueryAccept,
579         CPinBaseImpl_fnEnumMediaTypes,
580         CPinBaseImpl_fnQueryInternalConnections,
581         CPinBaseImpl_fnEndOfStream,
582         CPinBaseImpl_fnBeginFlush,
583         CPinBaseImpl_fnEndFlush,
584         CPinBaseImpl_fnNewSegment,
585 };
586
587
588 HRESULT CPinBaseImpl_InitIPin(
589         CPinBaseImpl* This, IUnknown* punkControl,
590         CRITICAL_SECTION* pcsPin,
591         CRITICAL_SECTION* pcsPinReceive,
592         CBaseFilterImpl* pFilter, LPCWSTR pwszId,
593         BOOL bOutput,
594         const CBasePinHandlers* pHandlers )
595 {
596         HRESULT hr = NOERROR;
597
598         TRACE("(%p,%p,%p)\n",This,punkControl,pFilter);
599
600         if ( punkControl == NULL )
601         {
602                 ERR( "punkControl must not be NULL\n" );
603                 return E_INVALIDARG;
604         }
605
606         ICOM_VTBL(This) = &ipin;
607         This->punkControl = punkControl;
608         This->pHandlers = pHandlers;
609         This->cbIdLen = sizeof(WCHAR)*(lstrlenW(pwszId)+1);
610         This->pwszId = NULL;
611         This->bOutput = bOutput;
612         This->pmtAcceptTypes = NULL;
613         This->cAcceptTypes = 0;
614         This->pcsPin = pcsPin;
615         This->pcsPinReceive = pcsPinReceive;
616         This->pFilter = pFilter;
617         This->pPinConnectedTo = NULL;
618         This->pMemInputPinConnectedTo = NULL;
619         This->pmtConn = NULL;
620         This->pAsyncOut = NULL;
621
622         This->pwszId = (WCHAR*)QUARTZ_AllocMem( This->cbIdLen );
623         if ( This->pwszId == NULL )
624         {
625                 hr = E_OUTOFMEMORY;
626                 goto err;
627         }
628         memcpy( This->pwszId, pwszId, This->cbIdLen );
629
630         return NOERROR;
631
632 err:;
633         CPinBaseImpl_UninitIPin( This );
634         return hr;
635 }
636
637 void CPinBaseImpl_UninitIPin( CPinBaseImpl* This )
638 {
639         TRACE("(%p)\n",This);
640
641         IPin_Disconnect( (IPin*)(This) );
642
643         if ( This->pwszId != NULL )
644         {
645                 QUARTZ_FreeMem( This->pwszId );
646                 This->pwszId = NULL;
647         }
648 }
649
650
651 /***************************************************************************
652  *
653  *      CMemInputPinBaseImpl
654  *
655  */
656
657
658 static HRESULT WINAPI
659 CMemInputPinBaseImpl_fnQueryInterface(IMemInputPin* iface,REFIID riid,void** ppobj)
660 {
661         ICOM_THIS(CMemInputPinBaseImpl,iface);
662
663         TRACE("(%p)->()\n",This);
664
665         return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
666 }
667
668 static ULONG WINAPI
669 CMemInputPinBaseImpl_fnAddRef(IMemInputPin* iface)
670 {
671         ICOM_THIS(CMemInputPinBaseImpl,iface);
672
673         TRACE("(%p)->()\n",This);
674
675         return IUnknown_AddRef(This->punkControl);
676 }
677
678 static ULONG WINAPI
679 CMemInputPinBaseImpl_fnRelease(IMemInputPin* iface)
680 {
681         ICOM_THIS(CMemInputPinBaseImpl,iface);
682
683         TRACE("(%p)->()\n",This);
684
685         return IUnknown_Release(This->punkControl);
686 }
687
688
689 static HRESULT WINAPI
690 CMemInputPinBaseImpl_fnGetAllocator(IMemInputPin* iface,IMemAllocator** ppAllocator)
691 {
692         ICOM_THIS(CMemInputPinBaseImpl,iface);
693         HRESULT hr = NOERROR;
694         IUnknown* punk;
695
696         TRACE("(%p)->()\n",This);
697
698         if ( ppAllocator == NULL )
699                 return E_POINTER;
700
701         EnterCriticalSection( This->pPin->pcsPin );
702
703         if ( This->pAllocator == NULL )
704         {
705                 hr = QUARTZ_CreateMemoryAllocator(NULL,(void**)&punk);
706                 if ( hr == NOERROR )
707                 {
708                         hr = IUnknown_QueryInterface(punk,
709                                 &IID_IMemAllocator,(void**)&This->pAllocator);
710                         IUnknown_Release(punk);
711                 }
712         }
713
714         if ( hr == NOERROR )
715         {
716                 *ppAllocator = This->pAllocator;
717                 IMemAllocator_AddRef(This->pAllocator);
718         }
719
720         LeaveCriticalSection( This->pPin->pcsPin );
721
722         return hr;
723 }
724
725 static HRESULT WINAPI
726 CMemInputPinBaseImpl_fnNotifyAllocator(IMemInputPin* iface,IMemAllocator* pAllocator,BOOL bReadonly)
727 {
728         ICOM_THIS(CMemInputPinBaseImpl,iface);
729
730         TRACE("(%p)->()\n",This);
731
732         if ( pAllocator == NULL )
733                 return E_POINTER;
734
735         EnterCriticalSection( This->pPin->pcsPin );
736
737         if ( This->pAllocator != NULL )
738         {
739                 IMemAllocator_Release(This->pAllocator);
740                 This->pAllocator = NULL;
741         }
742         This->pAllocator = pAllocator;
743         IMemAllocator_AddRef(This->pAllocator);
744
745         This->bReadonly = bReadonly;
746
747         LeaveCriticalSection( This->pPin->pcsPin );
748
749         return NOERROR;
750 }
751
752 static HRESULT WINAPI
753 CMemInputPinBaseImpl_fnGetAllocatorRequirements(IMemInputPin* iface,ALLOCATOR_PROPERTIES* pProp)
754 {
755         ICOM_THIS(CMemInputPinBaseImpl,iface);
756
757         TRACE("(%p)->(%p)\n",This,pProp);
758
759         if ( pProp == NULL )
760                 return E_POINTER;
761
762         /* E_MOTIMPL means 'no requirements' */
763         return E_NOTIMPL;
764 }
765
766 static HRESULT WINAPI
767 CMemInputPinBaseImpl_fnReceive(IMemInputPin* iface,IMediaSample* pSample)
768 {
769         ICOM_THIS(CMemInputPinBaseImpl,iface);
770         HRESULT hr = E_NOTIMPL;
771
772         TRACE("(%p)->(%p)\n",This,pSample);
773
774         EnterCriticalSection( This->pPin->pcsPinReceive );
775         if ( This->pPin->pHandlers->pReceive != NULL )
776                 hr = This->pPin->pHandlers->pReceive(This->pPin,pSample);
777         LeaveCriticalSection( This->pPin->pcsPinReceive );
778
779         return hr;
780 }
781
782 static HRESULT WINAPI
783 CMemInputPinBaseImpl_fnReceiveMultiple(IMemInputPin* iface,IMediaSample** ppSample,long nSample,long* pnSampleProcessed)
784 {
785         ICOM_THIS(CMemInputPinBaseImpl,iface);
786         long    n;
787         HRESULT hr;
788
789         TRACE("(%p)->()\n",This);
790
791         if ( ppSample == NULL || pnSampleProcessed == NULL )
792                 return E_POINTER;
793
794         hr = NOERROR;
795         for ( n = 0; n < nSample; n++ )
796         {
797                 hr = IMemInputPin_Receive(iface,ppSample[n]);
798                 if ( FAILED(hr) )
799                         break;
800         }
801
802         *pnSampleProcessed = n;
803         return hr;
804 }
805
806 static HRESULT WINAPI
807 CMemInputPinBaseImpl_fnReceiveCanBlock(IMemInputPin* iface)
808 {
809         ICOM_THIS(CMemInputPinBaseImpl,iface);
810         HRESULT hr = E_NOTIMPL;
811
812         TRACE("(%p)->()\n",This);
813
814         EnterCriticalSection( This->pPin->pcsPin );
815         if ( This->pPin->pHandlers->pReceiveCanBlock != NULL )
816                 hr = This->pPin->pHandlers->pReceiveCanBlock(This->pPin);
817         LeaveCriticalSection( This->pPin->pcsPin );
818
819         return hr;
820 }
821
822
823 static ICOM_VTABLE(IMemInputPin) imeminputpin =
824 {
825         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
826         /* IUnknown fields */
827         CMemInputPinBaseImpl_fnQueryInterface,
828         CMemInputPinBaseImpl_fnAddRef,
829         CMemInputPinBaseImpl_fnRelease,
830         /* IMemInputPin fields */
831         CMemInputPinBaseImpl_fnGetAllocator,
832         CMemInputPinBaseImpl_fnNotifyAllocator,
833         CMemInputPinBaseImpl_fnGetAllocatorRequirements,
834         CMemInputPinBaseImpl_fnReceive,
835         CMemInputPinBaseImpl_fnReceiveMultiple,
836         CMemInputPinBaseImpl_fnReceiveCanBlock,
837 };
838
839 HRESULT CMemInputPinBaseImpl_InitIMemInputPin(
840         CMemInputPinBaseImpl* This, IUnknown* punkControl,
841         CPinBaseImpl* pPin )
842 {
843         TRACE("(%p,%p)\n",This,punkControl);
844
845         if ( punkControl == NULL )
846         {
847                 ERR( "punkControl must not be NULL\n" );
848                 return E_INVALIDARG;
849         }
850
851         ICOM_VTBL(This) = &imeminputpin;
852         This->punkControl = punkControl;
853         This->pPin = pPin;
854         This->pAllocator = NULL;
855         This->bReadonly = FALSE;
856
857         return NOERROR;
858 }
859
860 void CMemInputPinBaseImpl_UninitIMemInputPin(
861         CMemInputPinBaseImpl* This )
862 {
863         TRACE("(%p)\n",This);
864
865         if ( This->pAllocator != NULL )
866         {
867                 IMemAllocator_Release(This->pAllocator);
868                 This->pAllocator = NULL;
869         }
870 }
871
872 /***************************************************************************
873  *
874  *      CQualityControlPassThruImpl
875  *
876  */
877
878 static HRESULT WINAPI
879 CQualityControlPassThruImpl_fnQueryInterface(IQualityControl* iface,REFIID riid,void** ppobj)
880 {
881         ICOM_THIS(CQualityControlPassThruImpl,iface);
882
883         TRACE("(%p)->()\n",This);
884
885         return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
886 }
887
888 static ULONG WINAPI
889 CQualityControlPassThruImpl_fnAddRef(IQualityControl* iface)
890 {
891         ICOM_THIS(CQualityControlPassThruImpl,iface);
892
893         TRACE("(%p)->()\n",This);
894
895         return IUnknown_AddRef(This->punkControl);
896 }
897
898 static ULONG WINAPI
899 CQualityControlPassThruImpl_fnRelease(IQualityControl* iface)
900 {
901         ICOM_THIS(CQualityControlPassThruImpl,iface);
902
903         TRACE("(%p)->()\n",This);
904
905         return IUnknown_Release(This->punkControl);
906 }
907
908
909 static HRESULT WINAPI
910 CQualityControlPassThruImpl_fnNotify(IQualityControl* iface,IBaseFilter* pFilter,Quality q)
911 {
912         ICOM_THIS(CQualityControlPassThruImpl,iface);
913         HRESULT hr = S_FALSE;
914
915         TRACE("(%p)->()\n",This);
916
917         if ( This->pControl != NULL )
918                 return IQualityControl_Notify( This->pControl, pFilter, q );
919
920         EnterCriticalSection( This->pPin->pcsPin );
921         if ( This->pPin->pHandlers->pQualityNotify != NULL )
922                 hr = This->pPin->pHandlers->pQualityNotify(This->pPin,pFilter,q);
923         LeaveCriticalSection( This->pPin->pcsPin );
924
925         return hr;
926 }
927
928 static HRESULT WINAPI
929 CQualityControlPassThruImpl_fnSetSink(IQualityControl* iface,IQualityControl* pControl)
930 {
931         ICOM_THIS(CQualityControlPassThruImpl,iface);
932
933         TRACE("(%p)->()\n",This);
934
935         This->pControl = pControl; /* AddRef() must not be called */
936
937         return NOERROR;
938 }
939
940 static ICOM_VTABLE(IQualityControl) iqualitycontrol =
941 {
942         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
943         /* IUnknown fields */
944         CQualityControlPassThruImpl_fnQueryInterface,
945         CQualityControlPassThruImpl_fnAddRef,
946         CQualityControlPassThruImpl_fnRelease,
947         /* IQualityControl fields */
948         CQualityControlPassThruImpl_fnNotify,
949         CQualityControlPassThruImpl_fnSetSink,
950 };
951
952 HRESULT CQualityControlPassThruImpl_InitIQualityControl(
953         CQualityControlPassThruImpl* This, IUnknown* punkControl,
954         CPinBaseImpl* pPin )
955 {
956         TRACE("(%p,%p)\n",This,punkControl);
957
958         if ( punkControl == NULL )
959         {
960                 ERR( "punkControl must not be NULL\n" );
961                 return E_INVALIDARG;
962         }
963
964         ICOM_VTBL(This) = &iqualitycontrol;
965         This->punkControl = punkControl;
966         This->pPin = pPin;
967
968         return NOERROR;
969 }
970
971 void CQualityControlPassThruImpl_UninitIQualityControl(
972         CQualityControlPassThruImpl* This )
973 {
974 }
975
976 /***************************************************************************
977  *
978  *      helper methods for output pins.
979  *
980  */
981
982 HRESULT CPinBaseImpl_SendSample( CPinBaseImpl* This, IMediaSample* pSample )
983 {
984         if ( This->pHandlers->pReceive == NULL )
985                 return E_NOTIMPL;
986
987         return This->pHandlers->pReceive( This, pSample );
988 }
989
990 HRESULT CPinBaseImpl_SendReceiveCanBlock( CPinBaseImpl* This )
991 {
992         if ( This->pHandlers->pReceiveCanBlock == NULL )
993                 return E_NOTIMPL;
994
995         return This->pHandlers->pReceiveCanBlock( This );
996 }
997
998 HRESULT CPinBaseImpl_SendEndOfStream( CPinBaseImpl* This )
999 {
1000         if ( This->pHandlers->pEndOfStream == NULL )
1001                 return E_NOTIMPL;
1002
1003         return This->pHandlers->pEndOfStream( This );
1004 }
1005
1006 HRESULT CPinBaseImpl_SendBeginFlush( CPinBaseImpl* This )
1007 {
1008         if ( This->pHandlers->pBeginFlush == NULL )
1009                 return E_NOTIMPL;
1010
1011         return This->pHandlers->pBeginFlush( This );
1012 }
1013
1014 HRESULT CPinBaseImpl_SendEndFlush( CPinBaseImpl* This )
1015 {
1016         if ( This->pHandlers->pEndFlush == NULL )
1017                 return E_NOTIMPL;
1018
1019         return This->pHandlers->pEndFlush( This );
1020 }
1021
1022 HRESULT CPinBaseImpl_SendNewSegment( CPinBaseImpl* This, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
1023 {
1024         if ( This->pHandlers->pNewSegment == NULL )
1025                 return E_NOTIMPL;
1026
1027         return This->pHandlers->pNewSegment( This, rtStart, rtStop, rate );
1028 }
1029
1030
1031
1032 /***************************************************************************
1033  *
1034  *      handlers for output pins.
1035  *
1036  */
1037
1038 HRESULT OutputPinSync_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
1039 {
1040         if ( pImpl->pMemInputPinConnectedTo == NULL )
1041                 return NOERROR;
1042
1043         return IMemInputPin_Receive(pImpl->pMemInputPinConnectedTo,pSample);
1044 }
1045
1046 HRESULT OutputPinSync_ReceiveCanBlock( CPinBaseImpl* pImpl )
1047 {
1048         if ( pImpl->pMemInputPinConnectedTo == NULL )
1049                 return S_FALSE;
1050
1051         return IMemInputPin_ReceiveCanBlock(pImpl->pMemInputPinConnectedTo);
1052 }
1053
1054 HRESULT OutputPinSync_EndOfStream( CPinBaseImpl* pImpl )
1055 {
1056         if ( pImpl->pPinConnectedTo == NULL )
1057                 return NOERROR;
1058
1059         return IPin_EndOfStream(pImpl->pPinConnectedTo);
1060 }
1061
1062 HRESULT OutputPinSync_BeginFlush( CPinBaseImpl* pImpl )
1063 {
1064         if ( pImpl->pPinConnectedTo == NULL )
1065                 return NOERROR;
1066
1067         return IPin_BeginFlush(pImpl->pPinConnectedTo);
1068 }
1069
1070 HRESULT OutputPinSync_EndFlush( CPinBaseImpl* pImpl )
1071 {
1072         if ( pImpl->pPinConnectedTo == NULL )
1073                 return NOERROR;
1074
1075         return IPin_EndFlush(pImpl->pPinConnectedTo);
1076 }
1077
1078 HRESULT OutputPinSync_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
1079 {
1080         if ( pImpl->pPinConnectedTo == NULL )
1081                 return NOERROR;
1082
1083         return IPin_NewSegment(pImpl->pPinConnectedTo,rtStart,rtStop,rate);
1084 }
1085
1086 /***************************************************************************
1087  *
1088  *      handlers for output pins (async).
1089  *
1090  */
1091
1092 typedef struct OutputPinTask OutputPinTask;
1093
1094 enum OutputPinTaskType
1095 {
1096         OutTask_ExitThread,
1097         OutTask_Receive,
1098         OutTask_EndOfStream,
1099         OutTask_BeginFlush,
1100         OutTask_EndFlush,
1101         OutTask_NewSegment,
1102 };
1103
1104 struct OutputPinTask
1105 {
1106         OutputPinTask* pNext;
1107         enum OutputPinTaskType tasktype;
1108         IMediaSample* pSample;
1109         REFERENCE_TIME rtStart;
1110         REFERENCE_TIME rtStop;
1111         double rate;
1112 };
1113
1114 struct OutputPinAsyncImpl
1115 {
1116         HANDLE m_hTaskThread;
1117         HANDLE m_hTaskEvent;
1118         IPin* m_pPin; /* connected pin */
1119         IMemInputPin* m_pMemInputPin; /* connected pin */
1120         CRITICAL_SECTION m_csTasks;
1121         OutputPinTask* m_pFirst;
1122         OutputPinTask* m_pLast;
1123         OutputPinTask* m_pTaskExitThread;
1124 };
1125
1126 static OutputPinTask* OutputPinAsync_AllocTask( enum OutputPinTaskType tasktype )
1127 {
1128         OutputPinTask* pTask;
1129
1130         pTask = (OutputPinTask*)QUARTZ_AllocMem( sizeof(OutputPinTask) );
1131         pTask->pNext = NULL;
1132         pTask->tasktype = tasktype;
1133         pTask->pSample = NULL;
1134
1135         return pTask;
1136 }
1137
1138 static void OutputPinAsync_FreeTask( OutputPinTask* pTask )
1139 {
1140         if ( pTask->pSample != NULL )
1141                 IMediaSample_Release( pTask->pSample );
1142         QUARTZ_FreeMem( pTask );
1143 }
1144
1145 static void OutputPinAsync_AddTask( OutputPinAsyncImpl* This, OutputPinTask* pTask, BOOL bFirst )
1146 {
1147         EnterCriticalSection( &This->m_csTasks );
1148
1149         if ( bFirst )
1150         {
1151                 pTask->pNext = This->m_pFirst;
1152                 This->m_pFirst = pTask;
1153                 if ( This->m_pLast == NULL )
1154                         This->m_pLast = pTask;
1155         }
1156         else
1157         {
1158                 if ( This->m_pLast != NULL )
1159                         This->m_pLast->pNext = pTask;
1160                 else
1161                         This->m_pFirst = pTask;
1162                 This->m_pLast = pTask;
1163         }
1164
1165         LeaveCriticalSection( &This->m_csTasks );
1166
1167         SetEvent( This->m_hTaskEvent );
1168 }
1169
1170 static OutputPinTask* OutputPinAsync_GetNextTask( OutputPinAsyncImpl* This )
1171 {
1172         OutputPinTask* pTask;
1173
1174         EnterCriticalSection( &This->m_csTasks );
1175         pTask = This->m_pFirst;
1176         if ( pTask != NULL )
1177         {
1178                 This->m_pFirst = pTask->pNext;
1179                 if ( This->m_pFirst == NULL )
1180                         This->m_pLast = NULL;
1181                 else
1182                         SetEvent( This->m_hTaskEvent );
1183         }
1184
1185         LeaveCriticalSection( &This->m_csTasks );
1186
1187         return pTask;
1188 }
1189
1190 static DWORD WINAPI OutputPinAsync_ThreadEntry( LPVOID pv )
1191 {
1192         OutputPinAsyncImpl* This = ((CPinBaseImpl*)pv)->pAsyncOut;
1193         OutputPinTask* pTask;
1194         BOOL bLoop = TRUE;
1195         BOOL bInFlush = FALSE;
1196         HRESULT hr;
1197
1198         while ( bLoop )
1199         {
1200                 WaitForSingleObject( This->m_hTaskEvent, INFINITE );
1201                 ResetEvent( This->m_hTaskEvent );
1202
1203                 pTask = OutputPinAsync_GetNextTask( This );
1204                 if ( pTask == NULL )
1205                         continue;
1206
1207                 hr = S_OK;
1208                 switch ( pTask->tasktype )
1209                 {
1210                 case OutTask_ExitThread:
1211                         bLoop = FALSE;
1212                         break;
1213                 case OutTask_Receive:
1214                         if ( !bInFlush )
1215                                 hr = IMemInputPin_Receive( This->m_pMemInputPin, pTask->pSample );
1216                         break;
1217                 case OutTask_EndOfStream:
1218                         hr = IPin_EndOfStream( This->m_pPin );
1219                         break;
1220                 case OutTask_BeginFlush:
1221                         bInFlush = TRUE;
1222                         hr = IPin_BeginFlush( This->m_pPin );
1223                         break;
1224                 case OutTask_EndFlush:
1225                         bInFlush = FALSE;
1226                         hr = IPin_EndFlush( This->m_pPin );
1227                         break;
1228                 case OutTask_NewSegment:
1229                         hr = IPin_NewSegment( This->m_pPin, pTask->rtStart, pTask->rtStop, pTask->rate );
1230                         break;
1231                 default:
1232                         ERR( "unexpected task type %d.\n", pTask->tasktype );
1233                         bLoop = FALSE;
1234                         break;
1235                 }
1236
1237                 OutputPinAsync_FreeTask( pTask );
1238
1239                 if ( FAILED(hr) )
1240                 {
1241                         ERR( "hresult %08lx\n", hr );
1242                         bLoop = FALSE;
1243                 }
1244         }
1245
1246         return 0;
1247 }
1248
1249 HRESULT OutputPinAsync_OnActive( CPinBaseImpl* pImpl )
1250 {
1251         HRESULT hr;
1252         DWORD dwThreadId;
1253
1254         FIXME("(%p)\n",pImpl);
1255
1256         if ( pImpl->pMemInputPinConnectedTo == NULL )
1257                 return NOERROR;
1258
1259         pImpl->pAsyncOut = (OutputPinAsyncImpl*)
1260                 QUARTZ_AllocMem( sizeof( OutputPinAsyncImpl ) );
1261         if ( pImpl->pAsyncOut == NULL )
1262                 return E_OUTOFMEMORY;
1263
1264         InitializeCriticalSection( &pImpl->pAsyncOut->m_csTasks );
1265         pImpl->pAsyncOut->m_hTaskThread = (HANDLE)NULL;
1266         pImpl->pAsyncOut->m_hTaskEvent = (HANDLE)NULL;
1267         pImpl->pAsyncOut->m_pFirst = NULL;
1268         pImpl->pAsyncOut->m_pLast = NULL;
1269         pImpl->pAsyncOut->m_pTaskExitThread = NULL;
1270         pImpl->pAsyncOut->m_pPin = pImpl->pPinConnectedTo;
1271         pImpl->pAsyncOut->m_pMemInputPin = pImpl->pMemInputPinConnectedTo;
1272
1273         pImpl->pAsyncOut->m_hTaskEvent =
1274                 CreateEventA( NULL, TRUE, FALSE, NULL );
1275         if ( pImpl->pAsyncOut->m_hTaskEvent == (HANDLE)NULL )
1276         {
1277                 hr = E_FAIL;
1278                 goto err;
1279         }
1280
1281         pImpl->pAsyncOut->m_pTaskExitThread =
1282                 OutputPinAsync_AllocTask( OutTask_ExitThread );
1283         if ( pImpl->pAsyncOut->m_pTaskExitThread == NULL )
1284         {
1285                 hr = E_OUTOFMEMORY;
1286                 goto err;
1287         }
1288
1289         pImpl->pAsyncOut->m_hTaskThread = CreateThread(
1290                 NULL, 0, OutputPinAsync_ThreadEntry, pImpl,
1291                 0, &dwThreadId );
1292         if ( pImpl->pAsyncOut->m_hTaskThread == (HANDLE)NULL )
1293         {
1294                 hr = E_FAIL;
1295                 goto err;
1296         }
1297
1298         return NOERROR;
1299 err:
1300         OutputPinAsync_OnInactive( pImpl );
1301         return hr;
1302 }
1303
1304 HRESULT OutputPinAsync_OnInactive( CPinBaseImpl* pImpl )
1305 {
1306         OutputPinTask* pTask;
1307
1308         FIXME("(%p)\n",pImpl);
1309
1310         if ( pImpl->pAsyncOut == NULL )
1311                 return NOERROR;
1312
1313         if ( pImpl->pAsyncOut->m_pTaskExitThread != NULL )
1314         {
1315                 OutputPinAsync_AddTask( pImpl->pAsyncOut, pImpl->pAsyncOut->m_pTaskExitThread, TRUE );
1316                 pImpl->pAsyncOut->m_pTaskExitThread = NULL;
1317         }
1318
1319         if ( pImpl->pAsyncOut->m_hTaskThread != (HANDLE)NULL )
1320         {
1321                 WaitForSingleObject( pImpl->pAsyncOut->m_hTaskThread, INFINITE );
1322                 CloseHandle( pImpl->pAsyncOut->m_hTaskThread );
1323         }
1324         if ( pImpl->pAsyncOut->m_hTaskEvent != (HANDLE)NULL )
1325                 CloseHandle( pImpl->pAsyncOut->m_hTaskEvent );
1326
1327         /* release all tasks. */
1328         while ( 1 )
1329         {
1330                 pTask = OutputPinAsync_GetNextTask( pImpl->pAsyncOut );
1331                 if ( pTask == NULL )
1332                         break;
1333                 OutputPinAsync_FreeTask( pTask );
1334         }
1335
1336         DeleteCriticalSection( &pImpl->pAsyncOut->m_csTasks );
1337
1338         QUARTZ_FreeMem( pImpl->pAsyncOut );
1339         pImpl->pAsyncOut = NULL;
1340
1341         return NOERROR;
1342 }
1343
1344 HRESULT OutputPinAsync_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
1345 {
1346         OutputPinAsyncImpl* This = pImpl->pAsyncOut;
1347         OutputPinTask* pTask;
1348
1349         TRACE("(%p,%p)\n",pImpl,pSample);
1350
1351         if ( This == NULL )
1352                 return NOERROR;
1353
1354         pTask = OutputPinAsync_AllocTask( OutTask_Receive );
1355         if ( pTask == NULL )
1356                 return E_OUTOFMEMORY;
1357         pTask->pSample = pSample; IMediaSample_AddRef( pSample );
1358         OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE );
1359
1360         return NOERROR;
1361 }
1362
1363 HRESULT OutputPinAsync_ReceiveCanBlock( CPinBaseImpl* pImpl )
1364 {
1365         return S_FALSE;
1366 }
1367
1368 HRESULT OutputPinAsync_EndOfStream( CPinBaseImpl* pImpl )
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_EndOfStream );
1379         if ( pTask == NULL )
1380                 return E_OUTOFMEMORY;
1381         OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE );
1382
1383         return NOERROR;
1384 }
1385
1386 HRESULT OutputPinAsync_BeginFlush( CPinBaseImpl* pImpl )
1387 {
1388         OutputPinAsyncImpl* This = pImpl->pAsyncOut;
1389         OutputPinTask* pTask;
1390
1391         TRACE("(%p)\n",pImpl);
1392
1393         if ( This == NULL )
1394                 return NOERROR;
1395
1396         pTask = OutputPinAsync_AllocTask( OutTask_BeginFlush );
1397         if ( pTask == NULL )
1398                 return E_OUTOFMEMORY;
1399         OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, TRUE );
1400
1401         return NOERROR;
1402 }
1403
1404 HRESULT OutputPinAsync_EndFlush( CPinBaseImpl* pImpl )
1405 {
1406         OutputPinAsyncImpl* This = pImpl->pAsyncOut;
1407         OutputPinTask* pTask;
1408
1409         TRACE("(%p)\n",pImpl);
1410
1411         if ( This == NULL )
1412                 return NOERROR;
1413
1414         pTask = OutputPinAsync_AllocTask( OutTask_EndFlush );
1415         if ( pTask == NULL )
1416                 return E_OUTOFMEMORY;
1417         OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE );
1418
1419         return NOERROR;
1420 }
1421
1422 HRESULT OutputPinAsync_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
1423 {
1424         OutputPinAsyncImpl* This = pImpl->pAsyncOut;
1425         OutputPinTask* pTask;
1426
1427         TRACE("(%p)\n",pImpl);
1428
1429         if ( This == NULL )
1430                 return NOERROR;
1431
1432         pTask = OutputPinAsync_AllocTask( OutTask_NewSegment );
1433         if ( pTask == NULL )
1434                 return E_OUTOFMEMORY;
1435         pTask->rtStart = rtStart;
1436         pTask->rtStop = rtStop;
1437         pTask->rate = rate;
1438         OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE );
1439
1440         return NOERROR;
1441 }
1442
1443