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