Revert "winex11.drv: Optimise getting the bits of a DIB after calling SetDIBits."
[wine] / dlls / quartz / pin.c
1 /*
2  * Generic Implementation of IPin Interface
3  *
4  * Copyright 2003 Robert Shearman
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "quartz_private.h"
22 #include "pin.h"
23
24 #include "wine/debug.h"
25 #include "wine/unicode.h"
26 #include "uuids.h"
27 #include "vfwmsgs.h"
28 #include <assert.h>
29
30 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
31
32 static const IPinVtbl InputPin_Vtbl;
33 static const IPinVtbl OutputPin_Vtbl;
34 static const IMemInputPinVtbl MemInputPin_Vtbl;
35 static const IPinVtbl PullPin_Vtbl;
36
37 #define ALIGNDOWN(value,boundary) ((value)/(boundary)*(boundary))
38 #define ALIGNUP(value,boundary) (ALIGNDOWN((value)+(boundary)-1, (boundary)))
39
40 typedef HRESULT (*SendPinFunc)( IPin *to, LPVOID arg );
41
42 /** Helper function, there are a lot of places where the error code is inherited
43  * The following rules apply:
44  *
45  * Return the first received error code (E_NOTIMPL is ignored)
46  * If no errors occur: return the first received non-error-code that isn't S_OK
47  */
48 HRESULT updatehres( HRESULT original, HRESULT new )
49 {
50     if (FAILED( original ) || new == E_NOTIMPL)
51         return original;
52
53     if (FAILED( new ) || original == S_OK)
54         return new;
55
56     return original;
57 }
58
59 /** Sends a message from a pin further to other, similar pins
60  * fnMiddle is called on each pin found further on the stream.
61  * fnEnd (can be NULL) is called when the message can't be sent any further (this is a renderer or source)
62  *
63  * If the pin given is an input pin, the message will be sent downstream to other input pins
64  * If the pin given is an output pin, the message will be sent upstream to other output pins
65  */
66 static HRESULT SendFurther( IPin *from, SendPinFunc fnMiddle, LPVOID arg, SendPinFunc fnEnd )
67 {
68     PIN_INFO pin_info;
69     ULONG amount = 0;
70     HRESULT hr = S_OK;
71     HRESULT hr_return = S_OK;
72     IEnumPins *enumpins = NULL;
73     BOOL foundend = TRUE;
74     PIN_DIRECTION from_dir;
75
76     IPin_QueryDirection( from, &from_dir );
77
78     hr = IPin_QueryInternalConnections( from, NULL, &amount );
79     if (hr != E_NOTIMPL && amount)
80         FIXME("Use QueryInternalConnections!\n");
81      hr = S_OK;
82
83     pin_info.pFilter = NULL;
84     hr = IPin_QueryPinInfo( from, &pin_info );
85     if (FAILED(hr))
86         goto out;
87
88     hr = IBaseFilter_EnumPins( pin_info.pFilter, &enumpins );
89     if (FAILED(hr))
90         goto out;
91
92     hr = IEnumPins_Reset( enumpins );
93     while (hr == S_OK) {
94         IPin *pin = NULL;
95         hr = IEnumPins_Next( enumpins, 1, &pin, NULL );
96         if (hr == VFW_E_ENUM_OUT_OF_SYNC)
97         {
98             hr = IEnumPins_Reset( enumpins );
99             continue;
100         }
101         if (pin)
102         {
103             PIN_DIRECTION dir;
104
105             IPin_QueryDirection( pin, &dir );
106             if (dir != from_dir)
107             {
108                 IPin *connected = NULL;
109
110                 foundend = FALSE;
111                 IPin_ConnectedTo( pin, &connected );
112                 if (connected)
113                 {
114                     HRESULT hr_local;
115
116                     hr_local = fnMiddle( connected, arg );
117                     hr_return = updatehres( hr_return, hr_local );
118                     IPin_Release(connected);
119                 }
120             }
121             IPin_Release( pin );
122         }
123         else
124         {
125             hr = S_OK;
126             break;
127         }
128     }
129
130     if (!foundend)
131         hr = hr_return;
132     else if (fnEnd) {
133         HRESULT hr_local;
134
135         hr_local = fnEnd( from, arg );
136         hr_return = updatehres( hr_return, hr_local );
137     }
138
139 out:
140     if (pin_info.pFilter)
141         IBaseFilter_Release( pin_info.pFilter );
142     return hr;
143 }
144
145 static inline InputPin *impl_from_IMemInputPin( IMemInputPin *iface )
146 {
147     return (InputPin *)((char*)iface - FIELD_OFFSET(InputPin, lpVtblMemInput));
148 }
149
150
151 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
152 {
153     /* Tempting to just do a memcpy, but the name field is
154        128 characters long! We will probably never exceed 10
155        most of the time, so we are better off copying 
156        each field manually */
157     strcpyW(pDest->achName, pSrc->achName);
158     pDest->dir = pSrc->dir;
159     pDest->pFilter = pSrc->pFilter;
160 }
161
162 /* Function called as a helper to IPin_Connect */
163 /* specific AM_MEDIA_TYPE - it cannot be NULL */
164 /* NOTE: not part of standard interface */
165 static HRESULT OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
166 {
167     OutputPin *This = (OutputPin *)iface;
168     HRESULT hr;
169     IMemAllocator * pMemAlloc = NULL;
170     ALLOCATOR_PROPERTIES actual; /* FIXME: should we put the actual props back in to This? */
171
172     TRACE("(%p, %p)\n", pReceivePin, pmt);
173     dump_AM_MEDIA_TYPE(pmt);
174
175     /* FIXME: call queryacceptproc */
176
177     This->pin.pConnectedTo = pReceivePin;
178     IPin_AddRef(pReceivePin);
179     CopyMediaType(&This->pin.mtCurrent, pmt);
180
181     hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
182
183     /* get the IMemInputPin interface we will use to deliver samples to the
184      * connected pin */
185     if (SUCCEEDED(hr))
186     {
187         This->pMemInputPin = NULL;
188         hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin);
189
190         if (SUCCEEDED(hr) && !This->custom_allocator)
191         {
192             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pMemAlloc);
193
194             if (hr == VFW_E_NO_ALLOCATOR)
195             {
196                 /* Input pin provides no allocator, use standard memory allocator */
197                 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)&pMemAlloc);
198
199                 if (SUCCEEDED(hr))
200                 {
201                     hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, pMemAlloc, This->readonly);
202                 }
203             }
204
205             if (SUCCEEDED(hr))
206                 hr = IMemAllocator_SetProperties(pMemAlloc, &This->allocProps, &actual);
207
208             if (pMemAlloc)
209                 IMemAllocator_Release(pMemAlloc);
210         }
211         else if (SUCCEEDED(hr))
212         {
213             if (This->alloc)
214             {
215                 hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, This->alloc, This->readonly);
216             }
217             else
218                 hr = VFW_E_NO_ALLOCATOR;
219         }
220
221         /* break connection if we couldn't get the allocator */
222         if (FAILED(hr))
223         {
224             if (This->pMemInputPin)
225                 IMemInputPin_Release(This->pMemInputPin);
226             This->pMemInputPin = NULL;
227
228             IPin_Disconnect(pReceivePin);
229         }
230     }
231
232     if (FAILED(hr))
233     {
234         IPin_Release(This->pin.pConnectedTo);
235         This->pin.pConnectedTo = NULL;
236         FreeMediaType(&This->pin.mtCurrent);
237     }
238
239     TRACE(" -- %x\n", hr);
240     return hr;
241 }
242
243 static HRESULT InputPin_Init(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData,
244                              QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, InputPin * pPinImpl)
245 {
246     TRACE("\n");
247
248     /* Common attributes */
249     pPinImpl->pin.refCount = 1;
250     pPinImpl->pin.pConnectedTo = NULL;
251     pPinImpl->pin.fnQueryAccept = pQueryAccept;
252     pPinImpl->pin.pUserData = pUserData;
253     pPinImpl->pin.pCritSec = pCritSec;
254     Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
255     ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
256
257     /* Input pin attributes */
258     pPinImpl->fnSampleProc = pSampleProc;
259     pPinImpl->fnCleanProc = pCleanUp;
260     pPinImpl->pAllocator = pPinImpl->preferred_allocator = allocator;
261     if (pPinImpl->preferred_allocator)
262         IMemAllocator_AddRef(pPinImpl->preferred_allocator);
263     pPinImpl->tStart = 0;
264     pPinImpl->tStop = 0;
265     pPinImpl->dRate = 1.0;
266     pPinImpl->pin.lpVtbl = InputPin_Vtbl;
267     pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl;
268     pPinImpl->flushing = pPinImpl->end_of_stream = 0;
269
270     return S_OK;
271 }
272
273 static HRESULT OutputPin_Init(const IPinVtbl *OutputPin_Vtbl, const PIN_INFO * pPinInfo, const ALLOCATOR_PROPERTIES * props, LPVOID pUserData,
274                               QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl)
275 {
276     TRACE("\n");
277
278     /* Common attributes */
279     pPinImpl->pin.lpVtbl = OutputPin_Vtbl;
280     pPinImpl->pin.refCount = 1;
281     pPinImpl->pin.pConnectedTo = NULL;
282     pPinImpl->pin.fnQueryAccept = pQueryAccept;
283     pPinImpl->pin.pUserData = pUserData;
284     pPinImpl->pin.pCritSec = pCritSec;
285     Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
286     ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
287
288     /* Output pin attributes */
289     pPinImpl->pMemInputPin = NULL;
290     pPinImpl->pConnectSpecific = OutputPin_ConnectSpecific;
291     /* If custom_allocator is set, you will need to specify an allocator
292      * in the alloc member of the struct before an output pin can connect
293      */
294     pPinImpl->custom_allocator = 0;
295     pPinImpl->alloc = NULL;
296     pPinImpl->readonly = FALSE;
297     if (props)
298     {
299         pPinImpl->allocProps = *props;
300         if (pPinImpl->allocProps.cbAlign == 0)
301             pPinImpl->allocProps.cbAlign = 1;
302     }
303     else
304         ZeroMemory(&pPinImpl->allocProps, sizeof(pPinImpl->allocProps));
305
306     return S_OK;
307 }
308
309 HRESULT InputPin_Construct(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, IPin ** ppPin)
310 {
311     InputPin * pPinImpl;
312
313     *ppPin = NULL;
314
315     if (pPinInfo->dir != PINDIR_INPUT)
316     {
317         ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
318         return E_INVALIDARG;
319     }
320
321     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
322
323     if (!pPinImpl)
324         return E_OUTOFMEMORY;
325
326     if (SUCCEEDED(InputPin_Init(InputPin_Vtbl, pPinInfo, pSampleProc, pUserData, pQueryAccept, pCleanUp, pCritSec, allocator, pPinImpl)))
327     {
328         *ppPin = (IPin *)pPinImpl;
329         return S_OK;
330     }
331
332     CoTaskMemFree(pPinImpl);
333     return E_FAIL;
334 }
335
336 HRESULT OutputPin_Construct(const IPinVtbl *OutputPin_Vtbl, long outputpin_size, const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
337 {
338     OutputPin * pPinImpl;
339
340     *ppPin = NULL;
341
342     if (pPinInfo->dir != PINDIR_OUTPUT)
343     {
344         ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo->dir);
345         return E_INVALIDARG;
346     }
347
348     assert(outputpin_size >= sizeof(OutputPin));
349
350     pPinImpl = CoTaskMemAlloc(outputpin_size);
351
352     if (!pPinImpl)
353         return E_OUTOFMEMORY;
354
355     if (SUCCEEDED(OutputPin_Init(OutputPin_Vtbl, pPinInfo, props, pUserData, pQueryAccept, pCritSec, pPinImpl)))
356     {
357         *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
358         return S_OK;
359     }
360
361     CoTaskMemFree(pPinImpl);
362     return E_FAIL;
363 }
364
365 /*** Common pin functions ***/
366
367 ULONG WINAPI IPinImpl_AddRef(IPin * iface)
368 {
369     IPinImpl *This = (IPinImpl *)iface;
370     ULONG refCount = InterlockedIncrement(&This->refCount);
371     
372     TRACE("(%p)->() AddRef from %d\n", iface, refCount - 1);
373     
374     return refCount;
375 }
376
377 HRESULT WINAPI IPinImpl_Disconnect(IPin * iface)
378 {
379     HRESULT hr;
380     IPinImpl *This = (IPinImpl *)iface;
381
382     TRACE("()\n");
383
384     EnterCriticalSection(This->pCritSec);
385     {
386         if (This->pConnectedTo)
387         {
388             IPin_Release(This->pConnectedTo);
389             This->pConnectedTo = NULL;
390             FreeMediaType(&This->mtCurrent);
391             ZeroMemory(&This->mtCurrent, sizeof(This->mtCurrent));
392             hr = S_OK;
393         }
394         else
395             hr = S_FALSE;
396     }
397     LeaveCriticalSection(This->pCritSec);
398     
399     return hr;
400 }
401
402 HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin)
403 {
404     HRESULT hr;
405     IPinImpl *This = (IPinImpl *)iface;
406
407     TRACE("(%p)\n", ppPin);
408
409     EnterCriticalSection(This->pCritSec);
410     {
411         if (This->pConnectedTo)
412         {
413             *ppPin = This->pConnectedTo;
414             IPin_AddRef(*ppPin);
415             hr = S_OK;
416         }
417         else
418         {
419             hr = VFW_E_NOT_CONNECTED;
420             *ppPin = NULL;
421         }
422     }
423     LeaveCriticalSection(This->pCritSec);
424
425     return hr;
426 }
427
428 HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
429 {
430     HRESULT hr;
431     IPinImpl *This = (IPinImpl *)iface;
432
433     TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
434
435     EnterCriticalSection(This->pCritSec);
436     {
437         if (This->pConnectedTo)
438         {
439             CopyMediaType(pmt, &This->mtCurrent);
440             hr = S_OK;
441         }
442         else
443         {
444             ZeroMemory(pmt, sizeof(*pmt));
445             hr = VFW_E_NOT_CONNECTED;
446         }
447     }
448     LeaveCriticalSection(This->pCritSec);
449
450     return hr;
451 }
452
453 HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
454 {
455     IPinImpl *This = (IPinImpl *)iface;
456
457     TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
458
459     Copy_PinInfo(pInfo, &This->pinInfo);
460     IBaseFilter_AddRef(pInfo->pFilter);
461
462     return S_OK;
463 }
464
465 HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
466 {
467     IPinImpl *This = (IPinImpl *)iface;
468
469     TRACE("(%p/%p)->(%p)\n", This, iface, pPinDir);
470
471     *pPinDir = This->pinInfo.dir;
472
473     return S_OK;
474 }
475
476 HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id)
477 {
478     IPinImpl *This = (IPinImpl *)iface;
479
480     TRACE("(%p/%p)->(%p)\n", This, iface, Id);
481
482     *Id = CoTaskMemAlloc((strlenW(This->pinInfo.achName) + 1) * sizeof(WCHAR));
483     if (!*Id)
484         return E_OUTOFMEMORY;
485
486     strcpyW(*Id, This->pinInfo.achName);
487
488     return S_OK;
489 }
490
491 HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
492 {
493     IPinImpl *This = (IPinImpl *)iface;
494
495     TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
496
497     return (This->fnQueryAccept(This->pUserData, pmt) == S_OK ? S_OK : S_FALSE);
498 }
499
500 HRESULT WINAPI IPinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
501 {
502     IPinImpl *This = (IPinImpl *)iface;
503     ENUMMEDIADETAILS emd;
504
505     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
506
507     /* override this method to allow enumeration of your types */
508     emd.cMediaTypes = 0;
509     emd.pMediaTypes = NULL;
510
511     return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
512 }
513
514 HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
515 {
516     IPinImpl *This = (IPinImpl *)iface;
517
518     TRACE("(%p/%p)->(%p, %p)\n", This, iface, apPin, cPin);
519
520     return E_NOTIMPL; /* to tell caller that all input pins connected to all output pins */
521 }
522
523 /*** IPin implementation for an input pin ***/
524
525 HRESULT WINAPI InputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
526 {
527     InputPin *This = (InputPin *)iface;
528
529     TRACE("(%p)->(%s, %p)\n", iface, qzdebugstr_guid(riid), ppv);
530
531     *ppv = NULL;
532
533     if (IsEqualIID(riid, &IID_IUnknown))
534         *ppv = (LPVOID)iface;
535     else if (IsEqualIID(riid, &IID_IPin))
536         *ppv = (LPVOID)iface;
537     else if (IsEqualIID(riid, &IID_IMemInputPin))
538         *ppv = (LPVOID)&This->lpVtblMemInput;
539     else if (IsEqualIID(riid, &IID_IMediaSeeking))
540     {
541         return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
542     }
543
544     if (*ppv)
545     {
546         IUnknown_AddRef((IUnknown *)(*ppv));
547         return S_OK;
548     }
549
550     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
551
552     return E_NOINTERFACE;
553 }
554
555 ULONG WINAPI InputPin_Release(IPin * iface)
556 {
557     InputPin *This = (InputPin *)iface;
558     ULONG refCount = InterlockedDecrement(&This->pin.refCount);
559     
560     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
561     
562     if (!refCount)
563     {
564         FreeMediaType(&This->pin.mtCurrent);
565         if (This->pAllocator)
566             IMemAllocator_Release(This->pAllocator);
567         This->pAllocator = NULL;
568         This->pin.lpVtbl = NULL;
569         CoTaskMemFree(This);
570         return 0;
571     }
572     else
573         return refCount;
574 }
575
576 HRESULT WINAPI InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
577 {
578     ERR("Outgoing connection on an input pin! (%p, %p)\n", pConnector, pmt);
579
580     return E_UNEXPECTED;
581 }
582
583
584 HRESULT WINAPI InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
585 {
586     InputPin *This = (InputPin *)iface;
587     PIN_DIRECTION pindirReceive;
588     HRESULT hr = S_OK;
589
590     TRACE("(%p, %p)\n", pReceivePin, pmt);
591     dump_AM_MEDIA_TYPE(pmt);
592
593     EnterCriticalSection(This->pin.pCritSec);
594     {
595         if (This->pin.pConnectedTo)
596             hr = VFW_E_ALREADY_CONNECTED;
597
598         if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)
599             hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto
600                                            * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
601
602         if (SUCCEEDED(hr))
603         {
604             IPin_QueryDirection(pReceivePin, &pindirReceive);
605
606             if (pindirReceive != PINDIR_OUTPUT)
607             {
608                 ERR("Can't connect from non-output pin\n");
609                 hr = VFW_E_INVALID_DIRECTION;
610             }
611         }
612
613         if (SUCCEEDED(hr))
614         {
615             CopyMediaType(&This->pin.mtCurrent, pmt);
616             This->pin.pConnectedTo = pReceivePin;
617             IPin_AddRef(pReceivePin);
618         }
619     }
620     LeaveCriticalSection(This->pin.pCritSec);
621
622     return hr;
623 }
624
625 static HRESULT deliver_endofstream(IPin* pin, LPVOID unused)
626 {
627     return IPin_EndOfStream( pin );
628 }
629
630 HRESULT WINAPI InputPin_EndOfStream(IPin * iface)
631 {
632     HRESULT hr = S_OK;
633     InputPin *This = (InputPin *)iface;
634
635     TRACE("(%p)\n", This);
636
637     EnterCriticalSection(This->pin.pCritSec);
638     if (This->flushing)
639         hr = S_FALSE;
640     else
641         This->end_of_stream = 1;
642     LeaveCriticalSection(This->pin.pCritSec);
643
644     if (hr == S_OK)
645         hr = SendFurther( iface, deliver_endofstream, NULL, NULL );
646     return hr;
647 }
648
649 static HRESULT deliver_beginflush(IPin* pin, LPVOID unused)
650 {
651     return IPin_BeginFlush( pin );
652 }
653
654 HRESULT WINAPI InputPin_BeginFlush(IPin * iface)
655 {
656     InputPin *This = (InputPin *)iface;
657     HRESULT hr;
658     TRACE("() semi-stub\n");
659
660     EnterCriticalSection(This->pin.pCritSec);
661     This->flushing = 1;
662
663     if (This->fnCleanProc)
664         This->fnCleanProc(This->pin.pUserData);
665
666     hr = SendFurther( iface, deliver_beginflush, NULL, NULL );
667     LeaveCriticalSection(This->pin.pCritSec);
668
669     return hr;
670 }
671
672 static HRESULT deliver_endflush(IPin* pin, LPVOID unused)
673 {
674     return IPin_EndFlush( pin );
675 }
676
677 HRESULT WINAPI InputPin_EndFlush(IPin * iface)
678 {
679     InputPin *This = (InputPin *)iface;
680     HRESULT hr;
681     TRACE("(%p)\n", This);
682
683     EnterCriticalSection(This->pin.pCritSec);
684     This->flushing = This->end_of_stream = 0;
685
686     hr = SendFurther( iface, deliver_endflush, NULL, NULL );
687     LeaveCriticalSection(This->pin.pCritSec);
688
689     return hr;
690 }
691
692 typedef struct newsegmentargs
693 {
694     REFERENCE_TIME tStart, tStop;
695     double rate;
696 } newsegmentargs;
697
698 static HRESULT deliver_newsegment(IPin *pin, LPVOID data)
699 {
700     newsegmentargs *args = data;
701     return IPin_NewSegment(pin, args->tStart, args->tStop, args->rate);
702 }
703
704 HRESULT WINAPI InputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
705 {
706     InputPin *This = (InputPin *)iface;
707     newsegmentargs args;
708
709     TRACE("(%x%08x, %x%08x, %e)\n", (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate);
710
711     args.tStart = This->tStart = tStart;
712     args.tStop = This->tStop = tStop;
713     args.rate = This->dRate = dRate;
714
715     return SendFurther( iface, deliver_newsegment, &args, NULL );
716 }
717
718 static const IPinVtbl InputPin_Vtbl = 
719 {
720     InputPin_QueryInterface,
721     IPinImpl_AddRef,
722     InputPin_Release,
723     InputPin_Connect,
724     InputPin_ReceiveConnection,
725     IPinImpl_Disconnect,
726     IPinImpl_ConnectedTo,
727     IPinImpl_ConnectionMediaType,
728     IPinImpl_QueryPinInfo,
729     IPinImpl_QueryDirection,
730     IPinImpl_QueryId,
731     IPinImpl_QueryAccept,
732     IPinImpl_EnumMediaTypes,
733     IPinImpl_QueryInternalConnections,
734     InputPin_EndOfStream,
735     InputPin_BeginFlush,
736     InputPin_EndFlush,
737     InputPin_NewSegment
738 };
739
740 /*** IMemInputPin implementation ***/
741
742 HRESULT WINAPI MemInputPin_QueryInterface(IMemInputPin * iface, REFIID riid, LPVOID * ppv)
743 {
744     InputPin *This = impl_from_IMemInputPin(iface);
745
746     return IPin_QueryInterface((IPin *)&This->pin, riid, ppv);
747 }
748
749 ULONG WINAPI MemInputPin_AddRef(IMemInputPin * iface)
750 {
751     InputPin *This = impl_from_IMemInputPin(iface);
752
753     return IPin_AddRef((IPin *)&This->pin);
754 }
755
756 ULONG WINAPI MemInputPin_Release(IMemInputPin * iface)
757 {
758     InputPin *This = impl_from_IMemInputPin(iface);
759
760     return IPin_Release((IPin *)&This->pin);
761 }
762
763 HRESULT WINAPI MemInputPin_GetAllocator(IMemInputPin * iface, IMemAllocator ** ppAllocator)
764 {
765     InputPin *This = impl_from_IMemInputPin(iface);
766
767     TRACE("(%p/%p)->(%p)\n", This, iface, ppAllocator);
768
769     *ppAllocator = This->pAllocator;
770     if (*ppAllocator)
771         IMemAllocator_AddRef(*ppAllocator);
772     
773     return *ppAllocator ? S_OK : VFW_E_NO_ALLOCATOR;
774 }
775
776 HRESULT WINAPI MemInputPin_NotifyAllocator(IMemInputPin * iface, IMemAllocator * pAllocator, BOOL bReadOnly)
777 {
778     InputPin *This = impl_from_IMemInputPin(iface);
779
780     TRACE("(%p/%p)->(%p, %d)\n", This, iface, pAllocator, bReadOnly);
781
782     if (bReadOnly)
783         FIXME("Read only flag not handled yet!\n");
784
785     /* FIXME: Should we release the allocator on disconnection? */
786     if (!pAllocator)
787     {
788         WARN("Null allocator\n");
789         return E_POINTER;
790     }
791
792     if (This->preferred_allocator && pAllocator != This->preferred_allocator)
793         return E_FAIL;
794
795     if (This->pAllocator)
796         IMemAllocator_Release(This->pAllocator);
797     This->pAllocator = pAllocator;
798     if (This->pAllocator)
799         IMemAllocator_AddRef(This->pAllocator);
800
801     return S_OK;
802 }
803
804 HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin * iface, ALLOCATOR_PROPERTIES * pProps)
805 {
806     InputPin *This = impl_from_IMemInputPin(iface);
807
808     TRACE("(%p/%p)->(%p)\n", This, iface, pProps);
809
810     /* override this method if you have any specific requirements */
811
812     return E_NOTIMPL;
813 }
814
815 HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample)
816 {
817     InputPin *This = impl_from_IMemInputPin(iface);
818     HRESULT hr;
819
820     /* this trace commented out for performance reasons */
821     /*TRACE("(%p/%p)->(%p)\n", This, iface, pSample);*/
822     hr = This->fnSampleProc(This->pin.pUserData, pSample);
823     return hr;
824 }
825
826 HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, long nSamples, long *nSamplesProcessed)
827 {
828     HRESULT hr = S_OK;
829     InputPin *This = impl_from_IMemInputPin(iface);
830
831     TRACE("(%p/%p)->(%p, %ld, %p)\n", This, iface, pSamples, nSamples, nSamplesProcessed);
832
833     for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; (*nSamplesProcessed)++)
834     {
835         hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
836         if (hr != S_OK)
837             break;
838     }
839
840     return hr;
841 }
842
843 HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface)
844 {
845     InputPin *This = impl_from_IMemInputPin(iface);
846
847     TRACE("(%p/%p)->()\n", This, iface);
848
849     return S_OK;
850 }
851
852 static const IMemInputPinVtbl MemInputPin_Vtbl = 
853 {
854     MemInputPin_QueryInterface,
855     MemInputPin_AddRef,
856     MemInputPin_Release,
857     MemInputPin_GetAllocator,
858     MemInputPin_NotifyAllocator,
859     MemInputPin_GetAllocatorRequirements,
860     MemInputPin_Receive,
861     MemInputPin_ReceiveMultiple,
862     MemInputPin_ReceiveCanBlock
863 };
864
865 HRESULT WINAPI OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
866 {
867     OutputPin *This = (OutputPin *)iface;
868
869     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
870
871     *ppv = NULL;
872
873     if (IsEqualIID(riid, &IID_IUnknown))
874         *ppv = (LPVOID)iface;
875     else if (IsEqualIID(riid, &IID_IPin))
876         *ppv = (LPVOID)iface;
877     else if (IsEqualIID(riid, &IID_IMediaSeeking))
878     {
879         return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
880     }
881
882     if (*ppv)
883     {
884         IUnknown_AddRef((IUnknown *)(*ppv));
885         return S_OK;
886     }
887
888     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
889
890     return E_NOINTERFACE;
891 }
892
893 ULONG WINAPI OutputPin_Release(IPin * iface)
894 {
895     OutputPin *This = (OutputPin *)iface;
896     ULONG refCount = InterlockedDecrement(&This->pin.refCount);
897
898     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
899
900     if (!refCount)
901     {
902         FreeMediaType(&This->pin.mtCurrent);
903         CoTaskMemFree(This);
904         return 0;
905     }
906     return refCount;
907 }
908
909 HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
910 {
911     HRESULT hr;
912     OutputPin *This = (OutputPin *)iface;
913
914     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
915     dump_AM_MEDIA_TYPE(pmt);
916
917     /* If we try to connect to ourself, we will definitely deadlock.
918      * There are other cases where we could deadlock too, but this
919      * catches the obvious case */
920     assert(pReceivePin != iface);
921
922     EnterCriticalSection(This->pin.pCritSec);
923     {
924         /* if we have been a specific type to connect with, then we can either connect
925          * with that or fail. We cannot choose different AM_MEDIA_TYPE */
926         if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
927             hr = This->pConnectSpecific(iface, pReceivePin, pmt);
928         else
929         {
930             /* negotiate media type */
931
932             IEnumMediaTypes * pEnumCandidates;
933             AM_MEDIA_TYPE * pmtCandidate = NULL; /* Candidate media type */
934
935             if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates)))
936             {
937                 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
938
939                 /* try this filter's media types first */
940                 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
941                 {
942                     assert(pmtCandidate);
943                     if (!IsEqualGUID(&FORMAT_None, &pmtCandidate->formattype))
944                         assert(pmtCandidate->pbFormat);
945                     if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && 
946                         (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
947                     {
948                         hr = S_OK;
949                         DeleteMediaType(pmtCandidate);
950                         break;
951                     }
952                     DeleteMediaType(pmtCandidate);
953                     pmtCandidate = NULL;
954                 }
955                 IEnumMediaTypes_Release(pEnumCandidates);
956             }
957
958             /* then try receiver filter's media types */
959             if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */
960             {
961                 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
962
963                 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
964                 {
965                     assert(pmtCandidate);
966                     if (!IsEqualGUID(&FORMAT_None, &pmtCandidate->formattype))
967                         assert(pmtCandidate->pbFormat);
968                     if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && 
969                         (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
970                     {
971                         hr = S_OK;
972                         DeleteMediaType(pmtCandidate);
973                         break;
974                     }
975                     DeleteMediaType(pmtCandidate);
976                     pmtCandidate = NULL;
977                 } /* while */
978                 IEnumMediaTypes_Release(pEnumCandidates);
979             } /* if not found */
980         } /* if negotiate media type */
981     } /* if succeeded */
982     LeaveCriticalSection(This->pin.pCritSec);
983
984     TRACE(" -- %x\n", hr);
985     return hr;
986 }
987
988 HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
989 {
990     ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin, pmt);
991
992     return E_UNEXPECTED;
993 }
994
995 HRESULT WINAPI OutputPin_Disconnect(IPin * iface)
996 {
997     HRESULT hr;
998     OutputPin *This = (OutputPin *)iface;
999
1000     TRACE("()\n");
1001
1002     EnterCriticalSection(This->pin.pCritSec);
1003     {
1004         if (This->pMemInputPin)
1005         {
1006             IMemInputPin_Release(This->pMemInputPin);
1007             This->pMemInputPin = NULL;
1008         }
1009         if (This->pin.pConnectedTo)
1010         {
1011             IPin_Release(This->pin.pConnectedTo);
1012             This->pin.pConnectedTo = NULL;
1013             FreeMediaType(&This->pin.mtCurrent);
1014             ZeroMemory(&This->pin.mtCurrent, sizeof(This->pin.mtCurrent));
1015             hr = S_OK;
1016         }
1017         else
1018             hr = S_FALSE;
1019     }
1020     LeaveCriticalSection(This->pin.pCritSec);
1021
1022     return hr;
1023 }
1024
1025 HRESULT WINAPI OutputPin_EndOfStream(IPin * iface)
1026 {
1027     TRACE("()\n");
1028
1029     /* not supposed to do anything in an output pin */
1030
1031     return E_UNEXPECTED;
1032 }
1033
1034 HRESULT WINAPI OutputPin_BeginFlush(IPin * iface)
1035 {
1036     TRACE("(%p)->()\n", iface);
1037
1038     /* not supposed to do anything in an output pin */
1039
1040     return E_UNEXPECTED;
1041 }
1042
1043 HRESULT WINAPI OutputPin_EndFlush(IPin * iface)
1044 {
1045     TRACE("(%p)->()\n", iface);
1046
1047     /* not supposed to do anything in an output pin */
1048
1049     return E_UNEXPECTED;
1050 }
1051
1052 HRESULT WINAPI OutputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1053 {
1054     TRACE("(%p)->(%x%08x, %x%08x, %e)\n", iface, (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate);
1055
1056     /* not supposed to do anything in an output pin */
1057
1058     return E_UNEXPECTED;
1059 }
1060
1061 static const IPinVtbl OutputPin_Vtbl = 
1062 {
1063     OutputPin_QueryInterface,
1064     IPinImpl_AddRef,
1065     OutputPin_Release,
1066     OutputPin_Connect,
1067     OutputPin_ReceiveConnection,
1068     OutputPin_Disconnect,
1069     IPinImpl_ConnectedTo,
1070     IPinImpl_ConnectionMediaType,
1071     IPinImpl_QueryPinInfo,
1072     IPinImpl_QueryDirection,
1073     IPinImpl_QueryId,
1074     IPinImpl_QueryAccept,
1075     IPinImpl_EnumMediaTypes,
1076     IPinImpl_QueryInternalConnections,
1077     OutputPin_EndOfStream,
1078     OutputPin_BeginFlush,
1079     OutputPin_EndFlush,
1080     OutputPin_NewSegment
1081 };
1082
1083 HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags)
1084 {
1085     HRESULT hr;
1086
1087     TRACE("(%p, %p, %p, %x)\n", ppSample, tStart, tStop, dwFlags);
1088
1089     EnterCriticalSection(This->pin.pCritSec);
1090     {
1091         if (!This->pin.pConnectedTo)
1092             hr = VFW_E_NOT_CONNECTED;
1093         else
1094         {
1095             IMemAllocator * pAlloc = NULL;
1096             
1097             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
1098
1099             if (SUCCEEDED(hr))
1100                 hr = IMemAllocator_GetBuffer(pAlloc, ppSample, tStart, tStop, dwFlags);
1101
1102             if (SUCCEEDED(hr))
1103                 hr = IMediaSample_SetTime(*ppSample, tStart, tStop);
1104
1105             if (pAlloc)
1106                 IMemAllocator_Release(pAlloc);
1107         }
1108     }
1109     LeaveCriticalSection(This->pin.pCritSec);
1110     
1111     return hr;
1112 }
1113
1114 HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample)
1115 {
1116     HRESULT hr = S_OK;
1117     IMemInputPin * pMemConnected = NULL;
1118     PIN_INFO pinInfo;
1119
1120     EnterCriticalSection(This->pin.pCritSec);
1121     {
1122         if (!This->pin.pConnectedTo || !This->pMemInputPin)
1123             hr = VFW_E_NOT_CONNECTED;
1124         else
1125         {
1126             /* we don't have the lock held when using This->pMemInputPin,
1127              * so we need to AddRef it to stop it being deleted while we are
1128              * using it. Same with its filter. */
1129             pMemConnected = This->pMemInputPin;
1130             IMemInputPin_AddRef(pMemConnected);
1131             hr = IPin_QueryPinInfo(This->pin.pConnectedTo, &pinInfo);
1132         }
1133     }
1134     LeaveCriticalSection(This->pin.pCritSec);
1135
1136     if (SUCCEEDED(hr))
1137     {
1138         /* NOTE: if we are in a critical section when Receive is called
1139          * then it causes some problems (most notably with the native Video
1140          * Renderer) if we are re-entered for whatever reason */
1141         hr = IMemInputPin_Receive(pMemConnected, pSample);
1142
1143         /* If the filter's destroyed, tell upstream to stop sending data */
1144         if(IBaseFilter_Release(pinInfo.pFilter) == 0 && SUCCEEDED(hr))
1145             hr = S_FALSE;
1146     }
1147     if (pMemConnected)
1148         IMemInputPin_Release(pMemConnected);
1149
1150     return hr;
1151 }
1152
1153 HRESULT OutputPin_DeliverNewSegment(OutputPin * This, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1154 {
1155     HRESULT hr;
1156
1157     EnterCriticalSection(This->pin.pCritSec);
1158     {
1159         if (!This->pin.pConnectedTo)
1160             hr = VFW_E_NOT_CONNECTED;
1161         else
1162             hr = IPin_NewSegment(This->pin.pConnectedTo, tStart, tStop, dRate);
1163     }
1164     LeaveCriticalSection(This->pin.pCritSec);
1165     
1166     return hr;
1167 }
1168
1169 HRESULT OutputPin_CommitAllocator(OutputPin * This)
1170 {
1171     HRESULT hr = S_OK;
1172
1173     TRACE("(%p)->()\n", This);
1174
1175     EnterCriticalSection(This->pin.pCritSec);
1176     {
1177         if (!This->pin.pConnectedTo || !This->pMemInputPin)
1178             hr = VFW_E_NOT_CONNECTED;
1179         else
1180         {
1181             IMemAllocator * pAlloc = NULL;
1182
1183             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
1184
1185             if (SUCCEEDED(hr))
1186                 hr = IMemAllocator_Commit(pAlloc);
1187
1188             if (pAlloc)
1189                 IMemAllocator_Release(pAlloc);
1190         }
1191     }
1192     LeaveCriticalSection(This->pin.pCritSec);
1193
1194     TRACE("--> %08x\n", hr);
1195     return hr;
1196 }
1197
1198 HRESULT OutputPin_DecommitAllocator(OutputPin * This)
1199 {
1200     HRESULT hr = S_OK;
1201
1202     TRACE("(%p)->()\n", This);
1203
1204     EnterCriticalSection(This->pin.pCritSec);
1205     {
1206         if (!This->pin.pConnectedTo || !This->pMemInputPin)
1207             hr = VFW_E_NOT_CONNECTED;
1208         else
1209         {
1210             IMemAllocator * pAlloc = NULL;
1211
1212             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
1213
1214             if (SUCCEEDED(hr))
1215                 hr = IMemAllocator_Decommit(pAlloc);
1216
1217             if (pAlloc)
1218                 IMemAllocator_Release(pAlloc);
1219         }
1220     }
1221     LeaveCriticalSection(This->pin.pCritSec);
1222
1223     TRACE("--> %08x\n", hr);
1224     return hr;
1225 }
1226
1227 HRESULT OutputPin_DeliverDisconnect(OutputPin * This)
1228 {
1229     HRESULT hr;
1230
1231     TRACE("(%p)->()\n", This);
1232
1233     EnterCriticalSection(This->pin.pCritSec);
1234     {
1235         if (!This->pin.pConnectedTo || !This->pMemInputPin)
1236             hr = VFW_E_NOT_CONNECTED;
1237         else if (!This->custom_allocator)
1238         {
1239             IMemAllocator * pAlloc = NULL;
1240
1241             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
1242
1243             if (SUCCEEDED(hr))
1244                 hr = IMemAllocator_Decommit(pAlloc);
1245
1246             if (pAlloc)
1247                 IMemAllocator_Release(pAlloc);
1248
1249             if (SUCCEEDED(hr))
1250                 hr = IPin_Disconnect(This->pin.pConnectedTo);
1251         }
1252         else /* Kill the allocator! */
1253         {
1254             hr = IPin_Disconnect(This->pin.pConnectedTo);
1255         }
1256         IPin_Disconnect((IPin *)This);
1257     }
1258     LeaveCriticalSection(This->pin.pCritSec);
1259
1260     return hr;
1261 }
1262
1263
1264 static HRESULT PullPin_Init(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData,
1265                             QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, STOPPROCESSPROC pDone, LPCRITICAL_SECTION pCritSec, PullPin * pPinImpl)
1266 {
1267     /* Common attributes */
1268     pPinImpl->pin.lpVtbl = PullPin_Vtbl;
1269     pPinImpl->pin.refCount = 1;
1270     pPinImpl->pin.pConnectedTo = NULL;
1271     pPinImpl->pin.fnQueryAccept = pQueryAccept;
1272     pPinImpl->pin.pUserData = pUserData;
1273     pPinImpl->pin.pCritSec = pCritSec;
1274     Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
1275     ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
1276
1277     /* Input pin attributes */
1278     pPinImpl->fnSampleProc = pSampleProc;
1279     pPinImpl->fnCleanProc = pCleanUp;
1280     pPinImpl->fnDone = pDone;
1281     pPinImpl->fnPreConnect = NULL;
1282     pPinImpl->pAlloc = NULL;
1283     pPinImpl->pReader = NULL;
1284     pPinImpl->hThread = NULL;
1285     pPinImpl->hEventStateChanged = CreateEventW(NULL, TRUE, TRUE, NULL);
1286     pPinImpl->thread_sleepy = CreateEventW(NULL, FALSE, FALSE, NULL);
1287
1288     pPinImpl->rtStart = 0;
1289     pPinImpl->rtCurrent = 0;
1290     pPinImpl->rtStop = ((LONGLONG)0x7fffffff << 32) | 0xffffffff;
1291     pPinImpl->dRate = 1.0;
1292     pPinImpl->state = Req_Die;
1293     pPinImpl->fnCustomRequest = pCustomRequest;
1294     pPinImpl->stop_playback = 1;
1295
1296     InitializeCriticalSection(&pPinImpl->thread_lock);
1297     pPinImpl->thread_lock.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": PullPin.thread_lock");
1298
1299     return S_OK;
1300 }
1301
1302 HRESULT PullPin_Construct(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, STOPPROCESSPROC pDone, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
1303 {
1304     PullPin * pPinImpl;
1305
1306     *ppPin = NULL;
1307
1308     if (pPinInfo->dir != PINDIR_INPUT)
1309     {
1310         ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
1311         return E_INVALIDARG;
1312     }
1313
1314     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
1315
1316     if (!pPinImpl)
1317         return E_OUTOFMEMORY;
1318
1319     if (SUCCEEDED(PullPin_Init(PullPin_Vtbl, pPinInfo, pSampleProc, pUserData, pQueryAccept, pCleanUp, pCustomRequest, pDone, pCritSec, pPinImpl)))
1320     {
1321         *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
1322         return S_OK;
1323     }
1324
1325     CoTaskMemFree(pPinImpl);
1326     return E_FAIL;
1327 }
1328
1329 static HRESULT PullPin_InitProcessing(PullPin * This);
1330
1331 HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
1332 {
1333     PIN_DIRECTION pindirReceive;
1334     HRESULT hr = S_OK;
1335     PullPin *This = (PullPin *)iface;
1336
1337     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
1338     dump_AM_MEDIA_TYPE(pmt);
1339
1340     EnterCriticalSection(This->pin.pCritSec);
1341     if (!This->pin.pConnectedTo)
1342     {
1343         ALLOCATOR_PROPERTIES props;
1344
1345         props.cBuffers = 3;
1346         props.cbBuffer = 64 * 1024; /* 64k bytes */
1347         props.cbAlign = 1;
1348         props.cbPrefix = 0;
1349
1350         if (SUCCEEDED(hr) && (This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK))
1351             hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto 
1352                                            * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
1353
1354         if (SUCCEEDED(hr))
1355         {
1356             IPin_QueryDirection(pReceivePin, &pindirReceive);
1357
1358             if (pindirReceive != PINDIR_OUTPUT)
1359             {
1360                 ERR("Can't connect from non-output pin\n");
1361                 hr = VFW_E_INVALID_DIRECTION;
1362             }
1363         }
1364
1365         This->pReader = NULL;
1366         This->pAlloc = NULL;
1367         if (SUCCEEDED(hr))
1368         {
1369             hr = IPin_QueryInterface(pReceivePin, &IID_IAsyncReader, (LPVOID *)&This->pReader);
1370         }
1371
1372         if (SUCCEEDED(hr) && This->fnPreConnect)
1373         {
1374             hr = This->fnPreConnect(iface, pReceivePin, &props);
1375         }
1376
1377         if (SUCCEEDED(hr))
1378         {
1379             hr = IAsyncReader_RequestAllocator(This->pReader, NULL, &props, &This->pAlloc);
1380         }
1381
1382         if (SUCCEEDED(hr))
1383         {
1384             CopyMediaType(&This->pin.mtCurrent, pmt);
1385             This->pin.pConnectedTo = pReceivePin;
1386             IPin_AddRef(pReceivePin);
1387             hr = IMemAllocator_Commit(This->pAlloc);
1388         }
1389
1390         if (SUCCEEDED(hr))
1391             hr = PullPin_InitProcessing(This);
1392
1393         if (FAILED(hr))
1394         {
1395              if (This->pReader)
1396                  IAsyncReader_Release(This->pReader);
1397              This->pReader = NULL;
1398              if (This->pAlloc)
1399                  IMemAllocator_Release(This->pAlloc);
1400              This->pAlloc = NULL;
1401         }
1402     }
1403     else
1404         hr = VFW_E_ALREADY_CONNECTED;
1405     LeaveCriticalSection(This->pin.pCritSec);
1406     return hr;
1407 }
1408
1409 HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
1410 {
1411     PullPin *This = (PullPin *)iface;
1412
1413     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
1414
1415     *ppv = NULL;
1416
1417     if (IsEqualIID(riid, &IID_IUnknown))
1418         *ppv = (LPVOID)iface;
1419     else if (IsEqualIID(riid, &IID_IPin))
1420         *ppv = (LPVOID)iface;
1421     else if (IsEqualIID(riid, &IID_IMediaSeeking))
1422     {
1423         return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
1424     }
1425
1426     if (*ppv)
1427     {
1428         IUnknown_AddRef((IUnknown *)(*ppv));
1429         return S_OK;
1430     }
1431
1432     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
1433
1434     return E_NOINTERFACE;
1435 }
1436
1437 ULONG WINAPI PullPin_Release(IPin *iface)
1438 {
1439     PullPin *This = (PullPin *)iface;
1440     ULONG refCount = InterlockedDecrement(&This->pin.refCount);
1441
1442     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
1443
1444     if (!refCount)
1445     {
1446         WaitForSingleObject(This->hEventStateChanged, INFINITE);
1447         assert(!This->hThread);
1448
1449         if(This->pAlloc)
1450             IMemAllocator_Release(This->pAlloc);
1451         if(This->pReader)
1452             IAsyncReader_Release(This->pReader);
1453         CloseHandle(This->thread_sleepy);
1454         CloseHandle(This->hEventStateChanged);
1455         This->thread_lock.DebugInfo->Spare[0] = 0;
1456         DeleteCriticalSection(&This->thread_lock);
1457         CoTaskMemFree(This);
1458         return 0;
1459     }
1460     return refCount;
1461 }
1462
1463 static void CALLBACK PullPin_Flush(PullPin *This)
1464 {
1465     IMediaSample *pSample;
1466     TRACE("Flushing!\n");
1467
1468     if (This->pReader)
1469     {
1470         /* Flush outstanding samples */
1471         IAsyncReader_BeginFlush(This->pReader);
1472
1473         for (;;)
1474         {
1475             DWORD_PTR dwUser;
1476
1477             IAsyncReader_WaitForNext(This->pReader, 0, &pSample, &dwUser);
1478
1479             if (!pSample)
1480                 break;
1481
1482             assert(!IMediaSample_GetActualDataLength(pSample));
1483
1484             IMediaSample_Release(pSample);
1485         }
1486
1487         IAsyncReader_EndFlush(This->pReader);
1488     }
1489 }
1490
1491 static void CALLBACK PullPin_Thread_Process(PullPin *This)
1492 {
1493     HRESULT hr;
1494     IMediaSample * pSample = NULL;
1495     ALLOCATOR_PROPERTIES allocProps;
1496
1497     hr = IMemAllocator_GetProperties(This->pAlloc, &allocProps);
1498
1499     This->cbAlign = allocProps.cbAlign;
1500
1501     if (This->rtCurrent < This->rtStart)
1502         This->rtCurrent = MEDIATIME_FROM_BYTES(ALIGNDOWN(BYTES_FROM_MEDIATIME(This->rtStart), This->cbAlign));
1503
1504     TRACE("Start\n");
1505
1506     if (This->rtCurrent >= This->rtStop)
1507     {
1508         IPin_EndOfStream((IPin *)This);
1509         return;
1510     }
1511
1512     /* There is no sample in our buffer */
1513     hr = This->fnCustomRequest(This->pin.pUserData);
1514
1515     if (FAILED(hr))
1516         ERR("Request error: %x\n", hr);
1517
1518     EnterCriticalSection(This->pin.pCritSec);
1519     SetEvent(This->hEventStateChanged);
1520     LeaveCriticalSection(This->pin.pCritSec);
1521
1522     if (SUCCEEDED(hr))
1523     do
1524     {
1525         DWORD_PTR dwUser;
1526
1527         TRACE("Process sample\n");
1528
1529         hr = IAsyncReader_WaitForNext(This->pReader, 10000, &pSample, &dwUser);
1530
1531         /* Return an empty sample on error to the implementation in case it does custom parsing, so it knows it's gone */
1532         if (SUCCEEDED(hr))
1533         {
1534             hr = This->fnSampleProc(This->pin.pUserData, pSample, dwUser);
1535         }
1536         else
1537         {
1538             /* FIXME: This is not well handled yet! */
1539             ERR("Processing error: %x\n", hr);
1540         }
1541
1542         if (pSample)
1543         {
1544             IMediaSample_Release(pSample);
1545             pSample = NULL;
1546         }
1547     } while (This->rtCurrent < This->rtStop && hr == S_OK && !This->stop_playback);
1548
1549     /* Sample was rejected, and we are asked to terminate */
1550     if (pSample)
1551     {
1552         IMediaSample_Release(pSample);
1553     }
1554
1555     /* Can't reset state to Sleepy here because that might race, instead PauseProcessing will do that for us
1556      * Flush remaining samples
1557      */
1558     if (This->fnDone)
1559         This->fnDone(This->pin.pUserData);
1560
1561     TRACE("End: %08x, %d\n", hr, This->stop_playback);
1562 }
1563
1564 static void CALLBACK PullPin_Thread_Pause(PullPin *This)
1565 {
1566     PullPin_Flush(This);
1567
1568     EnterCriticalSection(This->pin.pCritSec);
1569     This->state = Req_Sleepy;
1570     SetEvent(This->hEventStateChanged);
1571     LeaveCriticalSection(This->pin.pCritSec);
1572 }
1573
1574 static void CALLBACK PullPin_Thread_Stop(PullPin *This)
1575 {
1576     TRACE("(%p)->()\n", This);
1577
1578     EnterCriticalSection(This->pin.pCritSec);
1579     {
1580         CloseHandle(This->hThread);
1581         This->hThread = NULL;
1582         SetEvent(This->hEventStateChanged);
1583     }
1584     LeaveCriticalSection(This->pin.pCritSec);
1585
1586     IBaseFilter_Release(This->pin.pinInfo.pFilter);
1587
1588     CoUninitialize();
1589     ExitThread(0);
1590 }
1591
1592 static DWORD WINAPI PullPin_Thread_Main(LPVOID pv)
1593 {
1594     PullPin *This = pv;
1595     CoInitializeEx(NULL, COINIT_MULTITHREADED);
1596
1597     PullPin_Flush(This);
1598
1599     for (;;)
1600     {
1601         WaitForSingleObject(This->thread_sleepy, INFINITE);
1602
1603         TRACE("State: %d\n", This->state);
1604
1605         switch (This->state)
1606         {
1607         case Req_Die: PullPin_Thread_Stop(This); break;
1608         case Req_Run: PullPin_Thread_Process(This); break;
1609         case Req_Pause: PullPin_Thread_Pause(This); break;
1610         case Req_Sleepy: ERR("Should not be signalled with SLEEPY!\n"); break;
1611         default: ERR("Unknown state request: %d\n", This->state); break;
1612         }
1613     }
1614 }
1615
1616 static HRESULT PullPin_InitProcessing(PullPin * This)
1617 {
1618     HRESULT hr = S_OK;
1619
1620     TRACE("(%p)->()\n", This);
1621
1622     /* if we are connected */
1623     if (This->pAlloc)
1624     {
1625         DWORD dwThreadId;
1626
1627         WaitForSingleObject(This->hEventStateChanged, INFINITE);
1628         EnterCriticalSection(This->pin.pCritSec);
1629
1630         assert(!This->hThread);
1631         assert(This->state == Req_Die);
1632         assert(This->stop_playback);
1633         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1634         This->state = Req_Sleepy;
1635
1636         /* AddRef the filter to make sure it and it's pins will be around
1637          * as long as the thread */
1638         IBaseFilter_AddRef(This->pin.pinInfo.pFilter);
1639
1640
1641         This->hThread = CreateThread(NULL, 0, PullPin_Thread_Main, This, 0, &dwThreadId);
1642         if (!This->hThread)
1643         {
1644             hr = HRESULT_FROM_WIN32(GetLastError());
1645             IBaseFilter_Release(This->pin.pinInfo.pFilter);
1646         }
1647
1648         if (SUCCEEDED(hr))
1649         {
1650             SetEvent(This->hEventStateChanged);
1651             /* If assert fails, that means a command was not processed before the thread previously terminated */
1652         }
1653         LeaveCriticalSection(This->pin.pCritSec);
1654     }
1655
1656     TRACE(" -- %x\n", hr);
1657
1658     return hr;
1659 }
1660
1661 HRESULT PullPin_StartProcessing(PullPin * This)
1662 {
1663     /* if we are connected */
1664     TRACE("(%p)->()\n", This);
1665     if(This->pAlloc)
1666     {
1667         assert(This->hThread);
1668
1669         PullPin_WaitForStateChange(This, INFINITE);
1670
1671         assert(This->state == Req_Sleepy);
1672
1673         /* Wake up! */
1674         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1675         This->state = Req_Run;
1676         This->stop_playback = 0;
1677         ResetEvent(This->hEventStateChanged);
1678         SetEvent(This->thread_sleepy);
1679     }
1680
1681     return S_OK;
1682 }
1683
1684 HRESULT PullPin_PauseProcessing(PullPin * This)
1685 {
1686     /* if we are connected */
1687     TRACE("(%p)->()\n", This);
1688     if(This->pAlloc)
1689     {
1690         assert(This->hThread);
1691
1692         PullPin_WaitForStateChange(This, INFINITE);
1693
1694         EnterCriticalSection(This->pin.pCritSec);
1695
1696         assert(!This->stop_playback);
1697         assert(This->state == Req_Run|| This->state == Req_Sleepy);
1698
1699         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1700         This->state = Req_Pause;
1701         This->stop_playback = 1;
1702         ResetEvent(This->hEventStateChanged);
1703         SetEvent(This->thread_sleepy);
1704
1705         LeaveCriticalSection(This->pin.pCritSec);
1706     }
1707
1708     return S_OK;
1709 }
1710
1711 static HRESULT PullPin_StopProcessing(PullPin * This)
1712 {
1713     TRACE("(%p)->()\n", This);
1714
1715     /* if we are alive */
1716     assert(This->hThread);
1717
1718     PullPin_WaitForStateChange(This, INFINITE);
1719
1720     assert(This->state == Req_Pause || This->state == Req_Sleepy);
1721
1722     This->stop_playback = 1;
1723     This->state = Req_Die;
1724     assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1725     ResetEvent(This->hEventStateChanged);
1726     SetEvent(This->thread_sleepy);
1727     return S_OK;
1728 }
1729
1730 HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds)
1731 {
1732     if (WaitForSingleObject(This->hEventStateChanged, dwMilliseconds) == WAIT_TIMEOUT)
1733         return S_FALSE;
1734     return S_OK;
1735 }
1736
1737 HRESULT WINAPI PullPin_EndOfStream(IPin * iface)
1738 {
1739     FIXME("(%p)->() stub\n", iface);
1740
1741     return SendFurther( iface, deliver_endofstream, NULL, NULL );
1742 }
1743
1744 HRESULT WINAPI PullPin_BeginFlush(IPin * iface)
1745 {
1746     PullPin *This = (PullPin *)iface;
1747     TRACE("(%p)->()\n", This);
1748
1749     EnterCriticalSection(This->pin.pCritSec);
1750     {
1751         SendFurther( iface, deliver_beginflush, NULL, NULL );
1752     }
1753     LeaveCriticalSection(This->pin.pCritSec);
1754
1755     EnterCriticalSection(&This->thread_lock);
1756     {
1757         if (This->pReader)
1758             IAsyncReader_BeginFlush(This->pReader);
1759         PullPin_WaitForStateChange(This, INFINITE);
1760
1761         if (This->hThread && This->state == Req_Run)
1762         {
1763             PullPin_PauseProcessing(This);
1764             PullPin_WaitForStateChange(This, INFINITE);
1765         }
1766     }
1767     LeaveCriticalSection(&This->thread_lock);
1768
1769     EnterCriticalSection(This->pin.pCritSec);
1770     {
1771         This->fnCleanProc(This->pin.pUserData);
1772     }
1773     LeaveCriticalSection(This->pin.pCritSec);
1774
1775     return S_OK;
1776 }
1777
1778 HRESULT WINAPI PullPin_EndFlush(IPin * iface)
1779 {
1780     PullPin *This = (PullPin *)iface;
1781
1782     TRACE("(%p)->()\n", iface);
1783
1784     /* Send further first: Else a race condition might terminate processing early */
1785     EnterCriticalSection(This->pin.pCritSec);
1786     SendFurther( iface, deliver_endflush, NULL, NULL );
1787     LeaveCriticalSection(This->pin.pCritSec);
1788
1789     EnterCriticalSection(&This->thread_lock);
1790     {
1791         FILTER_STATE state;
1792         IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state);
1793
1794         if (state != State_Stopped)
1795             PullPin_StartProcessing(This);
1796
1797         PullPin_WaitForStateChange(This, INFINITE);
1798     }
1799     LeaveCriticalSection(&This->thread_lock);
1800
1801     return S_OK;
1802 }
1803
1804 HRESULT WINAPI PullPin_Disconnect(IPin *iface)
1805 {
1806     HRESULT hr;
1807     PullPin *This = (PullPin *)iface;
1808
1809     TRACE("()\n");
1810
1811     EnterCriticalSection(This->pin.pCritSec);
1812     {
1813         if (FAILED(hr = IMemAllocator_Decommit(This->pAlloc)))
1814             ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr);
1815
1816         if (This->pin.pConnectedTo)
1817         {
1818             IPin_Release(This->pin.pConnectedTo);
1819             This->pin.pConnectedTo = NULL;
1820             PullPin_StopProcessing(This);
1821
1822             FreeMediaType(&This->pin.mtCurrent);
1823             ZeroMemory(&This->pin.mtCurrent, sizeof(This->pin.mtCurrent));
1824             hr = S_OK;
1825         }
1826         else
1827             hr = S_FALSE;
1828     }
1829     LeaveCriticalSection(This->pin.pCritSec);
1830
1831     return hr;
1832 }
1833
1834 HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1835 {
1836     newsegmentargs args;
1837     FIXME("(%p)->(%s, %s, %g) stub\n", iface, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate);
1838
1839     args.tStart = tStart;
1840     args.tStop = tStop;
1841     args.rate = dRate;
1842
1843     return SendFurther( iface, deliver_newsegment, &args, NULL );
1844 }
1845
1846 static const IPinVtbl PullPin_Vtbl = 
1847 {
1848     PullPin_QueryInterface,
1849     IPinImpl_AddRef,
1850     PullPin_Release,
1851     InputPin_Connect,
1852     PullPin_ReceiveConnection,
1853     PullPin_Disconnect,
1854     IPinImpl_ConnectedTo,
1855     IPinImpl_ConnectionMediaType,
1856     IPinImpl_QueryPinInfo,
1857     IPinImpl_QueryDirection,
1858     IPinImpl_QueryId,
1859     IPinImpl_QueryAccept,
1860     IPinImpl_EnumMediaTypes,
1861     IPinImpl_QueryInternalConnections,
1862     PullPin_EndOfStream,
1863     PullPin_BeginFlush,
1864     PullPin_EndFlush,
1865     PullPin_NewSegment
1866 };