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