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