winhttp: Reimplement WinHttpCrackUrl.
[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                 /* Input pin provides no allocator, use standard memory allocator */
196                 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)&pMemAlloc);
197
198             if (SUCCEEDED(hr))
199                 hr = IMemAllocator_SetProperties(pMemAlloc, &This->allocProps, &actual);
200
201             if (SUCCEEDED(hr))
202                 hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, pMemAlloc, This->readonly);
203
204             if (pMemAlloc)
205                 IMemAllocator_Release(pMemAlloc);
206         }
207         else if (SUCCEEDED(hr))
208         {
209             if (This->alloc)
210             {
211                 hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, This->alloc, This->readonly);
212             }
213             else
214                 hr = VFW_E_NO_ALLOCATOR;
215         }
216
217         /* break connection if we couldn't get the allocator */
218         if (FAILED(hr))
219         {
220             if (This->pMemInputPin)
221                 IMemInputPin_Release(This->pMemInputPin);
222             This->pMemInputPin = NULL;
223
224             IPin_Disconnect(pReceivePin);
225         }
226     }
227
228     if (FAILED(hr))
229     {
230         IPin_Release(This->pin.pConnectedTo);
231         This->pin.pConnectedTo = NULL;
232         FreeMediaType(&This->pin.mtCurrent);
233     }
234
235     TRACE(" -- %x\n", hr);
236     return hr;
237 }
238
239 static HRESULT InputPin_Init(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData,
240                              QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, InputPin * pPinImpl)
241 {
242     TRACE("\n");
243
244     /* Common attributes */
245     pPinImpl->pin.refCount = 1;
246     pPinImpl->pin.pConnectedTo = NULL;
247     pPinImpl->pin.fnQueryAccept = pQueryAccept;
248     pPinImpl->pin.pUserData = pUserData;
249     pPinImpl->pin.pCritSec = pCritSec;
250     Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
251     ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
252
253     /* Input pin attributes */
254     pPinImpl->fnSampleProc = pSampleProc;
255     pPinImpl->fnCleanProc = pCleanUp;
256     pPinImpl->pAllocator = pPinImpl->preferred_allocator = allocator;
257     if (pPinImpl->preferred_allocator)
258         IMemAllocator_AddRef(pPinImpl->preferred_allocator);
259     pPinImpl->tStart = 0;
260     pPinImpl->tStop = 0;
261     pPinImpl->dRate = 1.0;
262     pPinImpl->pin.lpVtbl = InputPin_Vtbl;
263     pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl;
264     pPinImpl->flushing = pPinImpl->end_of_stream = 0;
265
266     return S_OK;
267 }
268
269 static HRESULT OutputPin_Init(const IPinVtbl *OutputPin_Vtbl, const PIN_INFO * pPinInfo, const ALLOCATOR_PROPERTIES * props, LPVOID pUserData,
270                               QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl)
271 {
272     TRACE("\n");
273
274     /* Common attributes */
275     pPinImpl->pin.lpVtbl = OutputPin_Vtbl;
276     pPinImpl->pin.refCount = 1;
277     pPinImpl->pin.pConnectedTo = NULL;
278     pPinImpl->pin.fnQueryAccept = pQueryAccept;
279     pPinImpl->pin.pUserData = pUserData;
280     pPinImpl->pin.pCritSec = pCritSec;
281     Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
282     ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
283
284     /* Output pin attributes */
285     pPinImpl->pMemInputPin = NULL;
286     pPinImpl->pConnectSpecific = OutputPin_ConnectSpecific;
287     /* If custom_allocator is set, you will need to specify an allocator
288      * in the alloc member of the struct before an output pin can connect
289      */
290     pPinImpl->custom_allocator = 0;
291     pPinImpl->alloc = NULL;
292     pPinImpl->readonly = FALSE;
293     if (props)
294     {
295         pPinImpl->allocProps = *props;
296         if (pPinImpl->allocProps.cbAlign == 0)
297             pPinImpl->allocProps.cbAlign = 1;
298     }
299     else
300         ZeroMemory(&pPinImpl->allocProps, sizeof(pPinImpl->allocProps));
301
302     return S_OK;
303 }
304
305 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)
306 {
307     InputPin * pPinImpl;
308
309     *ppPin = NULL;
310
311     if (pPinInfo->dir != PINDIR_INPUT)
312     {
313         ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
314         return E_INVALIDARG;
315     }
316
317     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
318
319     if (!pPinImpl)
320         return E_OUTOFMEMORY;
321
322     if (SUCCEEDED(InputPin_Init(InputPin_Vtbl, pPinInfo, pSampleProc, pUserData, pQueryAccept, pCleanUp, pCritSec, allocator, pPinImpl)))
323     {
324         *ppPin = (IPin *)pPinImpl;
325         return S_OK;
326     }
327
328     CoTaskMemFree(pPinImpl);
329     return E_FAIL;
330 }
331
332 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)
333 {
334     OutputPin * pPinImpl;
335
336     *ppPin = NULL;
337
338     if (pPinInfo->dir != PINDIR_OUTPUT)
339     {
340         ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo->dir);
341         return E_INVALIDARG;
342     }
343
344     assert(outputpin_size >= sizeof(OutputPin));
345
346     pPinImpl = CoTaskMemAlloc(outputpin_size);
347
348     if (!pPinImpl)
349         return E_OUTOFMEMORY;
350
351     if (SUCCEEDED(OutputPin_Init(OutputPin_Vtbl, pPinInfo, props, pUserData, pQueryAccept, pCritSec, pPinImpl)))
352     {
353         *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
354         return S_OK;
355     }
356
357     CoTaskMemFree(pPinImpl);
358     return E_FAIL;
359 }
360
361 /*** Common pin functions ***/
362
363 ULONG WINAPI IPinImpl_AddRef(IPin * iface)
364 {
365     IPinImpl *This = (IPinImpl *)iface;
366     ULONG refCount = InterlockedIncrement(&This->refCount);
367     
368     TRACE("(%p)->() AddRef from %d\n", iface, refCount - 1);
369     
370     return refCount;
371 }
372
373 HRESULT WINAPI IPinImpl_Disconnect(IPin * iface)
374 {
375     HRESULT hr;
376     IPinImpl *This = (IPinImpl *)iface;
377
378     TRACE("()\n");
379
380     EnterCriticalSection(This->pCritSec);
381     {
382         if (This->pConnectedTo)
383         {
384             IPin_Release(This->pConnectedTo);
385             This->pConnectedTo = NULL;
386             FreeMediaType(&This->mtCurrent);
387             ZeroMemory(&This->mtCurrent, sizeof(This->mtCurrent));
388             hr = S_OK;
389         }
390         else
391             hr = S_FALSE;
392     }
393     LeaveCriticalSection(This->pCritSec);
394     
395     return hr;
396 }
397
398 HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin)
399 {
400     HRESULT hr;
401     IPinImpl *This = (IPinImpl *)iface;
402
403     TRACE("(%p)\n", ppPin);
404
405     EnterCriticalSection(This->pCritSec);
406     {
407         if (This->pConnectedTo)
408         {
409             *ppPin = This->pConnectedTo;
410             IPin_AddRef(*ppPin);
411             hr = S_OK;
412         }
413         else
414         {
415             hr = VFW_E_NOT_CONNECTED;
416             *ppPin = NULL;
417         }
418     }
419     LeaveCriticalSection(This->pCritSec);
420
421     return hr;
422 }
423
424 HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
425 {
426     HRESULT hr;
427     IPinImpl *This = (IPinImpl *)iface;
428
429     TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
430
431     EnterCriticalSection(This->pCritSec);
432     {
433         if (This->pConnectedTo)
434         {
435             CopyMediaType(pmt, &This->mtCurrent);
436             hr = S_OK;
437         }
438         else
439         {
440             ZeroMemory(pmt, sizeof(*pmt));
441             hr = VFW_E_NOT_CONNECTED;
442         }
443     }
444     LeaveCriticalSection(This->pCritSec);
445
446     return hr;
447 }
448
449 HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
450 {
451     IPinImpl *This = (IPinImpl *)iface;
452
453     TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
454
455     Copy_PinInfo(pInfo, &This->pinInfo);
456     IBaseFilter_AddRef(pInfo->pFilter);
457
458     return S_OK;
459 }
460
461 HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
462 {
463     IPinImpl *This = (IPinImpl *)iface;
464
465     TRACE("(%p/%p)->(%p)\n", This, iface, pPinDir);
466
467     *pPinDir = This->pinInfo.dir;
468
469     return S_OK;
470 }
471
472 HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id)
473 {
474     IPinImpl *This = (IPinImpl *)iface;
475
476     TRACE("(%p/%p)->(%p)\n", This, iface, Id);
477
478     *Id = CoTaskMemAlloc((strlenW(This->pinInfo.achName) + 1) * sizeof(WCHAR));
479     if (!*Id)
480         return E_OUTOFMEMORY;
481
482     strcpyW(*Id, This->pinInfo.achName);
483
484     return S_OK;
485 }
486
487 HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
488 {
489     IPinImpl *This = (IPinImpl *)iface;
490
491     TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
492
493     return (This->fnQueryAccept(This->pUserData, pmt) == S_OK ? S_OK : S_FALSE);
494 }
495
496 HRESULT WINAPI IPinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
497 {
498     IPinImpl *This = (IPinImpl *)iface;
499     ENUMMEDIADETAILS emd;
500
501     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
502
503     /* override this method to allow enumeration of your types */
504     emd.cMediaTypes = 0;
505     emd.pMediaTypes = NULL;
506
507     return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
508 }
509
510 HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
511 {
512     IPinImpl *This = (IPinImpl *)iface;
513
514     TRACE("(%p/%p)->(%p, %p)\n", This, iface, apPin, cPin);
515
516     return E_NOTIMPL; /* to tell caller that all input pins connected to all output pins */
517 }
518
519 /*** IPin implementation for an input pin ***/
520
521 HRESULT WINAPI InputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
522 {
523     InputPin *This = (InputPin *)iface;
524
525     TRACE("(%p)->(%s, %p)\n", iface, qzdebugstr_guid(riid), ppv);
526
527     *ppv = NULL;
528
529     if (IsEqualIID(riid, &IID_IUnknown))
530         *ppv = (LPVOID)iface;
531     else if (IsEqualIID(riid, &IID_IPin))
532         *ppv = (LPVOID)iface;
533     else if (IsEqualIID(riid, &IID_IMemInputPin))
534         *ppv = (LPVOID)&This->lpVtblMemInput;
535     else if (IsEqualIID(riid, &IID_IMediaSeeking))
536     {
537         return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
538     }
539
540     if (*ppv)
541     {
542         IUnknown_AddRef((IUnknown *)(*ppv));
543         return S_OK;
544     }
545
546     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
547
548     return E_NOINTERFACE;
549 }
550
551 ULONG WINAPI InputPin_Release(IPin * iface)
552 {
553     InputPin *This = (InputPin *)iface;
554     ULONG refCount = InterlockedDecrement(&This->pin.refCount);
555     
556     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
557     
558     if (!refCount)
559     {
560         FreeMediaType(&This->pin.mtCurrent);
561         if (This->pAllocator)
562             IMemAllocator_Release(This->pAllocator);
563         This->pAllocator = NULL;
564         This->pin.lpVtbl = NULL;
565         CoTaskMemFree(This);
566         return 0;
567     }
568     else
569         return refCount;
570 }
571
572 HRESULT WINAPI InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
573 {
574     ERR("Outgoing connection on an input pin! (%p, %p)\n", pConnector, pmt);
575
576     return E_UNEXPECTED;
577 }
578
579
580 HRESULT WINAPI InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
581 {
582     InputPin *This = (InputPin *)iface;
583     PIN_DIRECTION pindirReceive;
584     HRESULT hr = S_OK;
585
586     TRACE("(%p, %p)\n", pReceivePin, pmt);
587     dump_AM_MEDIA_TYPE(pmt);
588
589     EnterCriticalSection(This->pin.pCritSec);
590     {
591         if (This->pin.pConnectedTo)
592             hr = VFW_E_ALREADY_CONNECTED;
593
594         if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)
595             hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto
596                                            * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
597
598         if (SUCCEEDED(hr))
599         {
600             IPin_QueryDirection(pReceivePin, &pindirReceive);
601
602             if (pindirReceive != PINDIR_OUTPUT)
603             {
604                 ERR("Can't connect from non-output pin\n");
605                 hr = VFW_E_INVALID_DIRECTION;
606             }
607         }
608
609         if (SUCCEEDED(hr))
610         {
611             CopyMediaType(&This->pin.mtCurrent, pmt);
612             This->pin.pConnectedTo = pReceivePin;
613             IPin_AddRef(pReceivePin);
614         }
615     }
616     LeaveCriticalSection(This->pin.pCritSec);
617
618     return hr;
619 }
620
621 static HRESULT deliver_endofstream(IPin* pin, LPVOID unused)
622 {
623     return IPin_EndOfStream( pin );
624 }
625
626 HRESULT WINAPI InputPin_EndOfStream(IPin * iface)
627 {
628     HRESULT hr = S_OK;
629     InputPin *This = (InputPin *)iface;
630
631     TRACE("(%p)\n", This);
632
633     EnterCriticalSection(This->pin.pCritSec);
634     if (This->flushing)
635         hr = S_FALSE;
636     else
637         This->end_of_stream = 1;
638     LeaveCriticalSection(This->pin.pCritSec);
639
640     if (hr == S_OK)
641         hr = SendFurther( iface, deliver_endofstream, NULL, NULL );
642     return hr;
643 }
644
645 static HRESULT deliver_beginflush(IPin* pin, LPVOID unused)
646 {
647     return IPin_BeginFlush( pin );
648 }
649
650 HRESULT WINAPI InputPin_BeginFlush(IPin * iface)
651 {
652     InputPin *This = (InputPin *)iface;
653     HRESULT hr;
654     TRACE("() semi-stub\n");
655
656     EnterCriticalSection(This->pin.pCritSec);
657     This->flushing = 1;
658
659     if (This->fnCleanProc)
660         This->fnCleanProc(This->pin.pUserData);
661
662     hr = SendFurther( iface, deliver_beginflush, NULL, NULL );
663     LeaveCriticalSection(This->pin.pCritSec);
664
665     return hr;
666 }
667
668 static HRESULT deliver_endflush(IPin* pin, LPVOID unused)
669 {
670     return IPin_EndFlush( pin );
671 }
672
673 HRESULT WINAPI InputPin_EndFlush(IPin * iface)
674 {
675     InputPin *This = (InputPin *)iface;
676     HRESULT hr;
677     TRACE("(%p)\n", This);
678
679     EnterCriticalSection(This->pin.pCritSec);
680     This->flushing = This->end_of_stream = 0;
681
682     hr = SendFurther( iface, deliver_endflush, NULL, NULL );
683     LeaveCriticalSection(This->pin.pCritSec);
684
685     return hr;
686 }
687
688 typedef struct newsegmentargs
689 {
690     REFERENCE_TIME tStart, tStop;
691     double rate;
692 } newsegmentargs;
693
694 static HRESULT deliver_newsegment(IPin *pin, LPVOID data)
695 {
696     newsegmentargs *args = data;
697     return IPin_NewSegment(pin, args->tStart, args->tStop, args->rate);
698 }
699
700 HRESULT WINAPI InputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
701 {
702     InputPin *This = (InputPin *)iface;
703     newsegmentargs args;
704
705     TRACE("(%x%08x, %x%08x, %e)\n", (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate);
706
707     args.tStart = This->tStart = tStart;
708     args.tStop = This->tStop = tStop;
709     args.rate = This->dRate = dRate;
710
711     return SendFurther( iface, deliver_newsegment, &args, NULL );
712 }
713
714 static const IPinVtbl InputPin_Vtbl = 
715 {
716     InputPin_QueryInterface,
717     IPinImpl_AddRef,
718     InputPin_Release,
719     InputPin_Connect,
720     InputPin_ReceiveConnection,
721     IPinImpl_Disconnect,
722     IPinImpl_ConnectedTo,
723     IPinImpl_ConnectionMediaType,
724     IPinImpl_QueryPinInfo,
725     IPinImpl_QueryDirection,
726     IPinImpl_QueryId,
727     IPinImpl_QueryAccept,
728     IPinImpl_EnumMediaTypes,
729     IPinImpl_QueryInternalConnections,
730     InputPin_EndOfStream,
731     InputPin_BeginFlush,
732     InputPin_EndFlush,
733     InputPin_NewSegment
734 };
735
736 /*** IMemInputPin implementation ***/
737
738 HRESULT WINAPI MemInputPin_QueryInterface(IMemInputPin * iface, REFIID riid, LPVOID * ppv)
739 {
740     InputPin *This = impl_from_IMemInputPin(iface);
741
742     return IPin_QueryInterface((IPin *)&This->pin, riid, ppv);
743 }
744
745 ULONG WINAPI MemInputPin_AddRef(IMemInputPin * iface)
746 {
747     InputPin *This = impl_from_IMemInputPin(iface);
748
749     return IPin_AddRef((IPin *)&This->pin);
750 }
751
752 ULONG WINAPI MemInputPin_Release(IMemInputPin * iface)
753 {
754     InputPin *This = impl_from_IMemInputPin(iface);
755
756     return IPin_Release((IPin *)&This->pin);
757 }
758
759 HRESULT WINAPI MemInputPin_GetAllocator(IMemInputPin * iface, IMemAllocator ** ppAllocator)
760 {
761     InputPin *This = impl_from_IMemInputPin(iface);
762
763     TRACE("(%p/%p)->(%p)\n", This, iface, ppAllocator);
764
765     *ppAllocator = This->pAllocator;
766     if (*ppAllocator)
767         IMemAllocator_AddRef(*ppAllocator);
768     
769     return *ppAllocator ? S_OK : VFW_E_NO_ALLOCATOR;
770 }
771
772 HRESULT WINAPI MemInputPin_NotifyAllocator(IMemInputPin * iface, IMemAllocator * pAllocator, BOOL bReadOnly)
773 {
774     InputPin *This = impl_from_IMemInputPin(iface);
775
776     TRACE("(%p/%p)->(%p, %d)\n", This, iface, pAllocator, bReadOnly);
777
778     if (bReadOnly)
779         FIXME("Read only flag not handled yet!\n");
780
781     /* FIXME: Should we release the allocator on disconnection? */
782     if (!pAllocator)
783     {
784         WARN("Null allocator\n");
785         return E_POINTER;
786     }
787
788     if (This->preferred_allocator && pAllocator != This->preferred_allocator)
789         return E_FAIL;
790
791     if (This->pAllocator)
792         IMemAllocator_Release(This->pAllocator);
793     This->pAllocator = pAllocator;
794     if (This->pAllocator)
795         IMemAllocator_AddRef(This->pAllocator);
796
797     return S_OK;
798 }
799
800 HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin * iface, ALLOCATOR_PROPERTIES * pProps)
801 {
802     InputPin *This = impl_from_IMemInputPin(iface);
803
804     TRACE("(%p/%p)->(%p)\n", This, iface, pProps);
805
806     /* override this method if you have any specific requirements */
807
808     return E_NOTIMPL;
809 }
810
811 HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample)
812 {
813     InputPin *This = impl_from_IMemInputPin(iface);
814     HRESULT hr;
815
816     /* this trace commented out for performance reasons */
817     /*TRACE("(%p/%p)->(%p)\n", This, iface, pSample);*/
818     hr = This->fnSampleProc(This->pin.pUserData, pSample);
819     return hr;
820 }
821
822 HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, long nSamples, long *nSamplesProcessed)
823 {
824     HRESULT hr = S_OK;
825     InputPin *This = impl_from_IMemInputPin(iface);
826
827     TRACE("(%p/%p)->(%p, %ld, %p)\n", This, iface, pSamples, nSamples, nSamplesProcessed);
828
829     for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; (*nSamplesProcessed)++)
830     {
831         hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
832         if (hr != S_OK)
833             break;
834     }
835
836     return hr;
837 }
838
839 HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface)
840 {
841     InputPin *This = impl_from_IMemInputPin(iface);
842
843     TRACE("(%p/%p)->()\n", This, iface);
844
845     return S_OK;
846 }
847
848 static const IMemInputPinVtbl MemInputPin_Vtbl = 
849 {
850     MemInputPin_QueryInterface,
851     MemInputPin_AddRef,
852     MemInputPin_Release,
853     MemInputPin_GetAllocator,
854     MemInputPin_NotifyAllocator,
855     MemInputPin_GetAllocatorRequirements,
856     MemInputPin_Receive,
857     MemInputPin_ReceiveMultiple,
858     MemInputPin_ReceiveCanBlock
859 };
860
861 HRESULT WINAPI OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
862 {
863     OutputPin *This = (OutputPin *)iface;
864
865     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
866
867     *ppv = NULL;
868
869     if (IsEqualIID(riid, &IID_IUnknown))
870         *ppv = (LPVOID)iface;
871     else if (IsEqualIID(riid, &IID_IPin))
872         *ppv = (LPVOID)iface;
873     else if (IsEqualIID(riid, &IID_IMediaSeeking))
874     {
875         return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
876     }
877
878     if (*ppv)
879     {
880         IUnknown_AddRef((IUnknown *)(*ppv));
881         return S_OK;
882     }
883
884     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
885
886     return E_NOINTERFACE;
887 }
888
889 ULONG WINAPI OutputPin_Release(IPin * iface)
890 {
891     OutputPin *This = (OutputPin *)iface;
892     ULONG refCount = InterlockedDecrement(&This->pin.refCount);
893
894     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
895
896     if (!refCount)
897     {
898         FreeMediaType(&This->pin.mtCurrent);
899         CoTaskMemFree(This);
900         return 0;
901     }
902     return refCount;
903 }
904
905 HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
906 {
907     HRESULT hr;
908     OutputPin *This = (OutputPin *)iface;
909
910     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
911     dump_AM_MEDIA_TYPE(pmt);
912
913     /* If we try to connect to ourself, we will definitely deadlock.
914      * There are other cases where we could deadlock too, but this
915      * catches the obvious case */
916     assert(pReceivePin != iface);
917
918     EnterCriticalSection(This->pin.pCritSec);
919     {
920         /* if we have been a specific type to connect with, then we can either connect
921          * with that or fail. We cannot choose different AM_MEDIA_TYPE */
922         if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
923             hr = This->pConnectSpecific(iface, pReceivePin, pmt);
924         else
925         {
926             /* negotiate media type */
927
928             IEnumMediaTypes * pEnumCandidates;
929             AM_MEDIA_TYPE * pmtCandidate = NULL; /* Candidate media type */
930
931             if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates)))
932             {
933                 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
934
935                 /* try this filter's media types first */
936                 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
937                 {
938                     assert(pmtCandidate);
939                     dump_AM_MEDIA_TYPE(pmtCandidate);
940                     if (!IsEqualGUID(&FORMAT_None, &pmtCandidate->formattype)
941                         && !IsEqualGUID(&GUID_NULL, &pmtCandidate->formattype))
942                         assert(pmtCandidate->pbFormat);
943                     if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && 
944                         (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
945                     {
946                         hr = S_OK;
947                         DeleteMediaType(pmtCandidate);
948                         break;
949                     }
950                     DeleteMediaType(pmtCandidate);
951                     pmtCandidate = NULL;
952                 }
953                 IEnumMediaTypes_Release(pEnumCandidates);
954             }
955
956             /* then try receiver filter's media types */
957             if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */
958             {
959                 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
960
961                 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
962                 {
963                     assert(pmtCandidate);
964                     dump_AM_MEDIA_TYPE(pmtCandidate);
965                     if (!IsEqualGUID(&FORMAT_None, &pmtCandidate->formattype)
966                         && !IsEqualGUID(&GUID_NULL, &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         pSample = NULL;
1530         hr = IAsyncReader_WaitForNext(This->pReader, 10000, &pSample, &dwUser);
1531
1532         /* Return an empty sample on error to the implementation in case it does custom parsing, so it knows it's gone */
1533         if (SUCCEEDED(hr))
1534         {
1535             hr = This->fnSampleProc(This->pin.pUserData, pSample, dwUser);
1536         }
1537         else
1538         {
1539             /* FIXME: This is not well handled yet! */
1540             ERR("Processing error: %x\n", hr);
1541             if (hr == VFW_E_TIMEOUT)
1542             {
1543                 assert(!pSample);
1544                 hr = S_OK;
1545                 continue;
1546             }
1547         }
1548
1549         if (pSample)
1550         {
1551             IMediaSample_Release(pSample);
1552             pSample = NULL;
1553         }
1554     } while (This->rtCurrent < This->rtStop && hr == S_OK && !This->stop_playback);
1555
1556     /* Sample was rejected, and we are asked to terminate */
1557     if (pSample)
1558     {
1559         IMediaSample_Release(pSample);
1560     }
1561
1562     /* Can't reset state to Sleepy here because that might race, instead PauseProcessing will do that for us
1563      * Flush remaining samples
1564      */
1565     if (This->fnDone)
1566         This->fnDone(This->pin.pUserData);
1567
1568     TRACE("End: %08x, %d\n", hr, This->stop_playback);
1569 }
1570
1571 static void CALLBACK PullPin_Thread_Pause(PullPin *This)
1572 {
1573     PullPin_Flush(This);
1574
1575     EnterCriticalSection(This->pin.pCritSec);
1576     This->state = Req_Sleepy;
1577     SetEvent(This->hEventStateChanged);
1578     LeaveCriticalSection(This->pin.pCritSec);
1579 }
1580
1581 static void CALLBACK PullPin_Thread_Stop(PullPin *This)
1582 {
1583     TRACE("(%p)->()\n", This);
1584
1585     EnterCriticalSection(This->pin.pCritSec);
1586     {
1587         CloseHandle(This->hThread);
1588         This->hThread = NULL;
1589         SetEvent(This->hEventStateChanged);
1590     }
1591     LeaveCriticalSection(This->pin.pCritSec);
1592
1593     IBaseFilter_Release(This->pin.pinInfo.pFilter);
1594
1595     CoUninitialize();
1596     ExitThread(0);
1597 }
1598
1599 static DWORD WINAPI PullPin_Thread_Main(LPVOID pv)
1600 {
1601     PullPin *This = pv;
1602     CoInitializeEx(NULL, COINIT_MULTITHREADED);
1603
1604     PullPin_Flush(This);
1605
1606     for (;;)
1607     {
1608         WaitForSingleObject(This->thread_sleepy, INFINITE);
1609
1610         TRACE("State: %d\n", This->state);
1611
1612         switch (This->state)
1613         {
1614         case Req_Die: PullPin_Thread_Stop(This); break;
1615         case Req_Run: PullPin_Thread_Process(This); break;
1616         case Req_Pause: PullPin_Thread_Pause(This); break;
1617         case Req_Sleepy: ERR("Should not be signalled with SLEEPY!\n"); break;
1618         default: ERR("Unknown state request: %d\n", This->state); break;
1619         }
1620     }
1621     return 0;
1622 }
1623
1624 static HRESULT PullPin_InitProcessing(PullPin * This)
1625 {
1626     HRESULT hr = S_OK;
1627
1628     TRACE("(%p)->()\n", This);
1629
1630     /* if we are connected */
1631     if (This->pAlloc)
1632     {
1633         DWORD dwThreadId;
1634
1635         WaitForSingleObject(This->hEventStateChanged, INFINITE);
1636         EnterCriticalSection(This->pin.pCritSec);
1637
1638         assert(!This->hThread);
1639         assert(This->state == Req_Die);
1640         assert(This->stop_playback);
1641         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1642         This->state = Req_Sleepy;
1643
1644         /* AddRef the filter to make sure it and it's pins will be around
1645          * as long as the thread */
1646         IBaseFilter_AddRef(This->pin.pinInfo.pFilter);
1647
1648
1649         This->hThread = CreateThread(NULL, 0, PullPin_Thread_Main, This, 0, &dwThreadId);
1650         if (!This->hThread)
1651         {
1652             hr = HRESULT_FROM_WIN32(GetLastError());
1653             IBaseFilter_Release(This->pin.pinInfo.pFilter);
1654         }
1655
1656         if (SUCCEEDED(hr))
1657         {
1658             SetEvent(This->hEventStateChanged);
1659             /* If assert fails, that means a command was not processed before the thread previously terminated */
1660         }
1661         LeaveCriticalSection(This->pin.pCritSec);
1662     }
1663
1664     TRACE(" -- %x\n", hr);
1665
1666     return hr;
1667 }
1668
1669 HRESULT PullPin_StartProcessing(PullPin * This)
1670 {
1671     /* if we are connected */
1672     TRACE("(%p)->()\n", This);
1673     if(This->pAlloc)
1674     {
1675         assert(This->hThread);
1676
1677         PullPin_WaitForStateChange(This, INFINITE);
1678
1679         assert(This->state == Req_Sleepy);
1680
1681         /* Wake up! */
1682         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1683         This->state = Req_Run;
1684         This->stop_playback = 0;
1685         ResetEvent(This->hEventStateChanged);
1686         SetEvent(This->thread_sleepy);
1687     }
1688
1689     return S_OK;
1690 }
1691
1692 HRESULT PullPin_PauseProcessing(PullPin * This)
1693 {
1694     /* if we are connected */
1695     TRACE("(%p)->()\n", This);
1696     if(This->pAlloc)
1697     {
1698         assert(This->hThread);
1699
1700         PullPin_WaitForStateChange(This, INFINITE);
1701
1702         EnterCriticalSection(This->pin.pCritSec);
1703
1704         assert(!This->stop_playback);
1705         assert(This->state == Req_Run|| This->state == Req_Sleepy);
1706
1707         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1708         This->state = Req_Pause;
1709         This->stop_playback = 1;
1710         ResetEvent(This->hEventStateChanged);
1711         SetEvent(This->thread_sleepy);
1712
1713         LeaveCriticalSection(This->pin.pCritSec);
1714     }
1715
1716     return S_OK;
1717 }
1718
1719 static HRESULT PullPin_StopProcessing(PullPin * This)
1720 {
1721     TRACE("(%p)->()\n", This);
1722
1723     /* if we are alive */
1724     assert(This->hThread);
1725
1726     PullPin_WaitForStateChange(This, INFINITE);
1727
1728     assert(This->state == Req_Pause || This->state == Req_Sleepy);
1729
1730     This->stop_playback = 1;
1731     This->state = Req_Die;
1732     assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1733     ResetEvent(This->hEventStateChanged);
1734     SetEvent(This->thread_sleepy);
1735     return S_OK;
1736 }
1737
1738 HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds)
1739 {
1740     if (WaitForSingleObject(This->hEventStateChanged, dwMilliseconds) == WAIT_TIMEOUT)
1741         return S_FALSE;
1742     return S_OK;
1743 }
1744
1745 HRESULT WINAPI PullPin_EndOfStream(IPin * iface)
1746 {
1747     FIXME("(%p)->() stub\n", iface);
1748
1749     return SendFurther( iface, deliver_endofstream, NULL, NULL );
1750 }
1751
1752 HRESULT WINAPI PullPin_BeginFlush(IPin * iface)
1753 {
1754     PullPin *This = (PullPin *)iface;
1755     TRACE("(%p)->()\n", This);
1756
1757     EnterCriticalSection(This->pin.pCritSec);
1758     {
1759         SendFurther( iface, deliver_beginflush, NULL, NULL );
1760     }
1761     LeaveCriticalSection(This->pin.pCritSec);
1762
1763     EnterCriticalSection(&This->thread_lock);
1764     {
1765         if (This->pReader)
1766             IAsyncReader_BeginFlush(This->pReader);
1767         PullPin_WaitForStateChange(This, INFINITE);
1768
1769         if (This->hThread && This->state == Req_Run)
1770         {
1771             PullPin_PauseProcessing(This);
1772             PullPin_WaitForStateChange(This, INFINITE);
1773         }
1774     }
1775     LeaveCriticalSection(&This->thread_lock);
1776
1777     EnterCriticalSection(This->pin.pCritSec);
1778     {
1779         This->fnCleanProc(This->pin.pUserData);
1780     }
1781     LeaveCriticalSection(This->pin.pCritSec);
1782
1783     return S_OK;
1784 }
1785
1786 HRESULT WINAPI PullPin_EndFlush(IPin * iface)
1787 {
1788     PullPin *This = (PullPin *)iface;
1789
1790     TRACE("(%p)->()\n", iface);
1791
1792     /* Send further first: Else a race condition might terminate processing early */
1793     EnterCriticalSection(This->pin.pCritSec);
1794     SendFurther( iface, deliver_endflush, NULL, NULL );
1795     LeaveCriticalSection(This->pin.pCritSec);
1796
1797     EnterCriticalSection(&This->thread_lock);
1798     {
1799         FILTER_STATE state;
1800
1801         if (This->pReader)
1802             IAsyncReader_EndFlush(This->pReader);
1803
1804         IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state);
1805
1806         if (state != State_Stopped)
1807             PullPin_StartProcessing(This);
1808
1809         PullPin_WaitForStateChange(This, INFINITE);
1810     }
1811     LeaveCriticalSection(&This->thread_lock);
1812
1813     return S_OK;
1814 }
1815
1816 HRESULT WINAPI PullPin_Disconnect(IPin *iface)
1817 {
1818     HRESULT hr;
1819     PullPin *This = (PullPin *)iface;
1820
1821     TRACE("()\n");
1822
1823     EnterCriticalSection(This->pin.pCritSec);
1824     {
1825         if (FAILED(hr = IMemAllocator_Decommit(This->pAlloc)))
1826             ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr);
1827
1828         if (This->pin.pConnectedTo)
1829         {
1830             IPin_Release(This->pin.pConnectedTo);
1831             This->pin.pConnectedTo = NULL;
1832             PullPin_StopProcessing(This);
1833
1834             FreeMediaType(&This->pin.mtCurrent);
1835             ZeroMemory(&This->pin.mtCurrent, sizeof(This->pin.mtCurrent));
1836             hr = S_OK;
1837         }
1838         else
1839             hr = S_FALSE;
1840     }
1841     LeaveCriticalSection(This->pin.pCritSec);
1842
1843     return hr;
1844 }
1845
1846 HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1847 {
1848     newsegmentargs args;
1849     FIXME("(%p)->(%s, %s, %g) stub\n", iface, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate);
1850
1851     args.tStart = tStart;
1852     args.tStop = tStop;
1853     args.rate = dRate;
1854
1855     return SendFurther( iface, deliver_newsegment, &args, NULL );
1856 }
1857
1858 static const IPinVtbl PullPin_Vtbl = 
1859 {
1860     PullPin_QueryInterface,
1861     IPinImpl_AddRef,
1862     PullPin_Release,
1863     InputPin_Connect,
1864     PullPin_ReceiveConnection,
1865     PullPin_Disconnect,
1866     IPinImpl_ConnectedTo,
1867     IPinImpl_ConnectionMediaType,
1868     IPinImpl_QueryPinInfo,
1869     IPinImpl_QueryDirection,
1870     IPinImpl_QueryId,
1871     IPinImpl_QueryAccept,
1872     IPinImpl_EnumMediaTypes,
1873     IPinImpl_QueryInternalConnections,
1874     PullPin_EndOfStream,
1875     PullPin_BeginFlush,
1876     PullPin_EndFlush,
1877     PullPin_NewSegment
1878 };