quartz: Clear pin value if not connected.
[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 HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
1281 {
1282     PIN_DIRECTION pindirReceive;
1283     HRESULT hr = S_OK;
1284     PullPin *This = (PullPin *)iface;
1285
1286     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
1287     dump_AM_MEDIA_TYPE(pmt);
1288
1289     EnterCriticalSection(This->pin.pCritSec);
1290     {
1291         ALLOCATOR_PROPERTIES props;
1292
1293         props.cBuffers = 3;
1294         props.cbBuffer = 64 * 1024; /* 64k bytes */
1295         props.cbAlign = 1;
1296         props.cbPrefix = 0;
1297
1298         if (This->pin.pConnectedTo)
1299             hr = VFW_E_ALREADY_CONNECTED;
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
1342         if (FAILED(hr))
1343         {
1344              if (This->pReader)
1345                  IAsyncReader_Release(This->pReader);
1346              This->pReader = NULL;
1347              if (This->pAlloc)
1348                  IMemAllocator_Release(This->pAlloc);
1349              This->pAlloc = NULL;
1350         }
1351     }
1352     LeaveCriticalSection(This->pin.pCritSec);
1353     return hr;
1354 }
1355
1356 HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
1357 {
1358     PullPin *This = (PullPin *)iface;
1359
1360     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
1361
1362     *ppv = NULL;
1363
1364     if (IsEqualIID(riid, &IID_IUnknown))
1365         *ppv = (LPVOID)iface;
1366     else if (IsEqualIID(riid, &IID_IPin))
1367         *ppv = (LPVOID)iface;
1368     else if (IsEqualIID(riid, &IID_IMediaSeeking))
1369     {
1370         return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
1371     }
1372
1373     if (*ppv)
1374     {
1375         IUnknown_AddRef((IUnknown *)(*ppv));
1376         return S_OK;
1377     }
1378
1379     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
1380
1381     return E_NOINTERFACE;
1382 }
1383
1384 ULONG WINAPI PullPin_Release(IPin *iface)
1385 {
1386     PullPin *This = (PullPin *)iface;
1387     ULONG refCount = InterlockedDecrement(&This->pin.refCount);
1388
1389     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
1390
1391     if (!refCount)
1392     {
1393         WaitForSingleObject(This->hEventStateChanged, INFINITE);
1394         assert(!This->hThread);
1395
1396         if(This->pAlloc)
1397             IMemAllocator_Release(This->pAlloc);
1398         if(This->pReader)
1399             IAsyncReader_Release(This->pReader);
1400         CloseHandle(This->thread_sleepy);
1401         CloseHandle(This->hEventStateChanged);
1402         This->thread_lock.DebugInfo->Spare[0] = 0;
1403         DeleteCriticalSection(&This->thread_lock);
1404         CoTaskMemFree(This);
1405         return 0;
1406     }
1407     return refCount;
1408 }
1409
1410 static HRESULT PullPin_Standard_Request(PullPin *This, BOOL start)
1411 {
1412     REFERENCE_TIME rtSampleStart;
1413     REFERENCE_TIME rtSampleStop;
1414     IMediaSample *sample = NULL;
1415     HRESULT hr;
1416
1417     TRACE("Requesting sample!\n");
1418
1419     if (start)
1420         This->rtNext = This->rtCurrent;
1421
1422     if (This->rtNext >= This->rtStop)
1423         /* Last sample has already been queued, request nothing more */
1424         return S_OK;
1425
1426     hr = IMemAllocator_GetBuffer(This->pAlloc, &sample, NULL, NULL, 0);
1427
1428     if (SUCCEEDED(hr))
1429     {
1430         rtSampleStart = This->rtNext;
1431         rtSampleStop = rtSampleStart + MEDIATIME_FROM_BYTES(IMediaSample_GetSize(sample));
1432         if (rtSampleStop > This->rtStop)
1433             rtSampleStop = MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(This->rtStop), This->cbAlign));
1434         hr = IMediaSample_SetTime(sample, &rtSampleStart, &rtSampleStop);
1435
1436         This->rtCurrent = This->rtNext;
1437         This->rtNext = rtSampleStop;
1438
1439         if (SUCCEEDED(hr))
1440             hr = IAsyncReader_Request(This->pReader, sample, 0);
1441     }
1442     if (FAILED(hr))
1443         FIXME("Failed to queue sample : %08x\n", hr);
1444
1445     return hr;
1446 }
1447
1448 static void CALLBACK PullPin_Flush(PullPin *This)
1449 {
1450     IMediaSample *pSample;
1451     TRACE("Flushing!\n");
1452
1453     EnterCriticalSection(This->pin.pCritSec);
1454     if (This->pReader)
1455     {
1456         /* Flush outstanding samples */
1457         IAsyncReader_BeginFlush(This->pReader);
1458         for (;;)
1459         {
1460             DWORD_PTR dwUser;
1461
1462             IAsyncReader_WaitForNext(This->pReader, 0, &pSample, &dwUser);
1463
1464             if (!pSample)
1465                 break;
1466
1467             assert(!IMediaSample_GetActualDataLength(pSample));
1468             if (This->fnCustomRequest)
1469                 This->fnSampleProc(This->pin.pUserData, pSample, dwUser);
1470
1471             IMediaSample_Release(pSample);
1472         }
1473
1474         IAsyncReader_EndFlush(This->pReader);
1475     }
1476     LeaveCriticalSection(This->pin.pCritSec);
1477 }
1478
1479 static void CALLBACK PullPin_Thread_Process(PullPin *This)
1480 {
1481     HRESULT hr;
1482     IMediaSample * pSample = NULL;
1483     ALLOCATOR_PROPERTIES allocProps;
1484
1485     hr = IMemAllocator_GetProperties(This->pAlloc, &allocProps);
1486
1487     This->cbAlign = allocProps.cbAlign;
1488
1489     if (This->rtCurrent < This->rtStart)
1490         This->rtCurrent = MEDIATIME_FROM_BYTES(ALIGNDOWN(BYTES_FROM_MEDIATIME(This->rtStart), This->cbAlign));
1491
1492     TRACE("Start\n");
1493
1494     if (This->rtCurrent >= This->rtStop)
1495     {
1496         IPin_EndOfStream((IPin *)This);
1497         return;
1498     }
1499
1500     /* There is no sample in our buffer */
1501     if (!This->fnCustomRequest)
1502         hr = PullPin_Standard_Request(This, TRUE);
1503     else
1504         hr = This->fnCustomRequest(This->pin.pUserData);
1505
1506     if (FAILED(hr))
1507         ERR("Request error: %x\n", hr);
1508
1509     EnterCriticalSection(This->pin.pCritSec);
1510     SetEvent(This->hEventStateChanged);
1511     LeaveCriticalSection(This->pin.pCritSec);
1512
1513     do
1514     {
1515         DWORD_PTR dwUser;
1516
1517         TRACE("Process sample\n");
1518
1519         hr = IAsyncReader_WaitForNext(This->pReader, 10000, &pSample, &dwUser);
1520
1521         /* Calling fnCustomRequest is not specifically useful here: It can be handled inside fnSampleProc */
1522         if (pSample && !This->fnCustomRequest)
1523             hr = PullPin_Standard_Request(This, FALSE);
1524
1525         /* Return an empty sample on error to the implementation in case it does custom parsing, so it knows it's gone */
1526         if (SUCCEEDED(hr) || (This->fnCustomRequest && pSample))
1527         {
1528             REFERENCE_TIME rtStart, rtStop;
1529             BOOL rejected;
1530
1531             IMediaSample_GetTime(pSample, &rtStart, &rtStop);
1532
1533             do
1534             {
1535                 hr = This->fnSampleProc(This->pin.pUserData, pSample, dwUser);
1536
1537                 if (This->fnCustomRequest)
1538                     break;
1539
1540                 rejected = FALSE;
1541                 if (This->rtCurrent == rtStart)
1542                 {
1543                     rejected = TRUE;
1544                     TRACE("DENIED!\n");
1545                     Sleep(10);
1546                     /* Maybe it's transient? */
1547                 }
1548                 /* rtNext = rtCurrent, because the next sample is already queued */
1549                 else if (rtStop != This->rtCurrent && rtStop < This->rtStop)
1550                 {
1551                     WARN("Position changed! rtStop: %u, rtCurrent: %u\n", (DWORD)BYTES_FROM_MEDIATIME(rtStop), (DWORD)BYTES_FROM_MEDIATIME(This->rtCurrent));
1552                     PullPin_Flush(This);
1553                     hr = PullPin_Standard_Request(This, TRUE);
1554                 }
1555             } while (rejected && (This->rtCurrent < This->rtStop && hr == S_OK && !This->stop_playback));
1556         }
1557         else
1558         {
1559             /* FIXME: This is not well handled yet! */
1560             ERR("Processing error: %x\n", hr);
1561         }
1562
1563         if (pSample)
1564         {
1565             IMediaSample_Release(pSample);
1566             pSample = NULL;
1567         }
1568     } while (This->rtCurrent < This->rtStop && hr == S_OK && !This->stop_playback);
1569
1570     /* Sample was rejected, and we are asked to terminate */
1571     if (pSample)
1572     {
1573         IMediaSample_Release(pSample);
1574     }
1575
1576     /* Can't reset state to Sleepy here because that might race, instead PauseProcessing will do that for us
1577      * Flush remaining samples
1578      */
1579     TRACE("Almost done..\n");
1580
1581     if (This->fnDone)
1582         This->fnDone(This->pin.pUserData);
1583     PullPin_Flush(This);
1584
1585     TRACE("End: %08x, %d\n", hr, This->stop_playback);
1586 }
1587
1588 static void CALLBACK PullPin_Thread_Pause(PullPin *This)
1589 {
1590     TRACE("(%p)->()\n", This);
1591
1592     EnterCriticalSection(This->pin.pCritSec);
1593     {
1594         This->state = Req_Sleepy;
1595         SetEvent(This->hEventStateChanged);
1596     }
1597     LeaveCriticalSection(This->pin.pCritSec);
1598 }
1599
1600 static void CALLBACK PullPin_Thread_Stop(PullPin *This)
1601 {
1602     TRACE("(%p)->()\n", This);
1603
1604     EnterCriticalSection(This->pin.pCritSec);
1605     {
1606         CloseHandle(This->hThread);
1607         This->hThread = NULL;
1608         SetEvent(This->hEventStateChanged);
1609     }
1610     LeaveCriticalSection(This->pin.pCritSec);
1611
1612     IBaseFilter_Release(This->pin.pinInfo.pFilter);
1613
1614     CoUninitialize();
1615     ExitThread(0);
1616 }
1617
1618 static DWORD WINAPI PullPin_Thread_Main(LPVOID pv)
1619 {
1620     PullPin *This = pv;
1621     CoInitializeEx(NULL, COINIT_MULTITHREADED);
1622
1623     for (;;)
1624     {
1625         WaitForSingleObject(This->thread_sleepy, INFINITE);
1626
1627         TRACE("State: %d\n", This->state);
1628
1629         switch (This->state)
1630         {
1631         case Req_Die: PullPin_Thread_Stop(This); break;
1632         case Req_Run: PullPin_Thread_Process(This); break;
1633         case Req_Pause: PullPin_Thread_Pause(This); break;
1634         case Req_Sleepy: ERR("Should not be signalled with SLEEPY!\n"); break;
1635         default: ERR("Unknown state request: %d\n", This->state); break;
1636         }
1637     }
1638 }
1639
1640 HRESULT PullPin_InitProcessing(PullPin * This)
1641 {
1642     HRESULT hr = S_OK;
1643
1644     TRACE("(%p)->()\n", This);
1645
1646     /* if we are connected */
1647     if (This->pAlloc)
1648     {
1649         DWORD dwThreadId;
1650
1651         WaitForSingleObject(This->hEventStateChanged, INFINITE);
1652         EnterCriticalSection(This->pin.pCritSec);
1653
1654         assert(!This->hThread);
1655         assert(This->state == Req_Die);
1656         assert(This->stop_playback);
1657         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1658         This->state = Req_Sleepy;
1659
1660         /* AddRef the filter to make sure it and it's pins will be around
1661          * as long as the thread */
1662         IBaseFilter_AddRef(This->pin.pinInfo.pFilter);
1663
1664
1665         This->hThread = CreateThread(NULL, 0, PullPin_Thread_Main, This, 0, &dwThreadId);
1666         if (!This->hThread)
1667         {
1668             hr = HRESULT_FROM_WIN32(GetLastError());
1669             IBaseFilter_Release(This->pin.pinInfo.pFilter);
1670         }
1671
1672         if (SUCCEEDED(hr))
1673         {
1674             SetEvent(This->hEventStateChanged);
1675             /* If assert fails, that means a command was not processed before the thread previously terminated */
1676         }
1677         LeaveCriticalSection(This->pin.pCritSec);
1678     }
1679
1680     TRACE(" -- %x\n", hr);
1681
1682     return hr;
1683 }
1684
1685 HRESULT PullPin_StartProcessing(PullPin * This)
1686 {
1687     /* if we are connected */
1688     TRACE("(%p)->()\n", This);
1689     if(This->pAlloc)
1690     {
1691         assert(This->hThread);
1692
1693         PullPin_WaitForStateChange(This, INFINITE);
1694
1695         assert(This->state == Req_Sleepy);
1696
1697         /* Wake up! */
1698         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1699         This->state = Req_Run;
1700         This->stop_playback = 0;
1701         ResetEvent(This->hEventStateChanged);
1702         SetEvent(This->thread_sleepy);
1703     }
1704
1705     return S_OK;
1706 }
1707
1708 HRESULT PullPin_PauseProcessing(PullPin * This)
1709 {
1710     /* if we are connected */
1711     TRACE("(%p)->()\n", This);
1712     if(This->pAlloc)
1713     {
1714         assert(This->hThread);
1715
1716         PullPin_WaitForStateChange(This, INFINITE);
1717
1718         EnterCriticalSection(This->pin.pCritSec);
1719         /* Faster! */
1720         IAsyncReader_BeginFlush(This->pReader);
1721
1722         assert(!This->stop_playback);
1723         assert(This->state == Req_Run|| This->state == Req_Sleepy);
1724
1725         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1726         This->state = Req_Pause;
1727         This->stop_playback = 1;
1728         ResetEvent(This->hEventStateChanged);
1729         SetEvent(This->thread_sleepy);
1730
1731         LeaveCriticalSection(This->pin.pCritSec);
1732     }
1733
1734     return S_OK;
1735 }
1736
1737 HRESULT PullPin_StopProcessing(PullPin * This)
1738 {
1739     TRACE("(%p)->()\n", This);
1740
1741     /* if we are alive */
1742     assert(This->hThread);
1743
1744     PullPin_WaitForStateChange(This, INFINITE);
1745
1746     assert(This->state == Req_Pause || This->state == Req_Sleepy);
1747
1748     This->stop_playback = 1;
1749     This->state = Req_Die;
1750     assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1751     ResetEvent(This->hEventStateChanged);
1752     SetEvent(This->thread_sleepy);
1753     return S_OK;
1754 }
1755
1756 HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds)
1757 {
1758     if (WaitForSingleObject(This->hEventStateChanged, dwMilliseconds) == WAIT_TIMEOUT)
1759         return S_FALSE;
1760     return S_OK;
1761 }
1762
1763 HRESULT WINAPI PullPin_EndOfStream(IPin * iface)
1764 {
1765     FIXME("(%p)->() stub\n", iface);
1766
1767     return SendFurther( iface, deliver_endofstream, NULL, NULL );
1768 }
1769
1770 HRESULT WINAPI PullPin_BeginFlush(IPin * iface)
1771 {
1772     PullPin *This = (PullPin *)iface;
1773     TRACE("(%p)->()\n", This);
1774
1775     EnterCriticalSection(This->pin.pCritSec);
1776     {
1777         SendFurther( iface, deliver_beginflush, NULL, NULL );
1778     }
1779     LeaveCriticalSection(This->pin.pCritSec);
1780
1781     EnterCriticalSection(&This->thread_lock);
1782     {
1783         PullPin_WaitForStateChange(This, INFINITE);
1784
1785         if (This->hThread && !This->stop_playback)
1786         {
1787             PullPin_PauseProcessing(This);
1788             PullPin_WaitForStateChange(This, INFINITE);
1789         }
1790     }
1791     LeaveCriticalSection(&This->thread_lock);
1792
1793     EnterCriticalSection(This->pin.pCritSec);
1794     {
1795         This->fnCleanProc(This->pin.pUserData);
1796     }
1797     LeaveCriticalSection(This->pin.pCritSec);
1798
1799     return S_OK;
1800 }
1801
1802 HRESULT WINAPI PullPin_EndFlush(IPin * iface)
1803 {
1804     PullPin *This = (PullPin *)iface;
1805
1806     TRACE("(%p)->()\n", iface);
1807
1808     EnterCriticalSection(&This->thread_lock);
1809     {
1810         FILTER_STATE state;
1811         IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state);
1812
1813         if (This->stop_playback && state == State_Running)
1814             PullPin_StartProcessing(This);
1815
1816         PullPin_WaitForStateChange(This, INFINITE);
1817     }
1818     LeaveCriticalSection(&This->thread_lock);
1819
1820     EnterCriticalSection(This->pin.pCritSec);
1821     SendFurther( iface, deliver_endflush, NULL, NULL );
1822     LeaveCriticalSection(This->pin.pCritSec);
1823
1824     return S_OK;
1825 }
1826
1827 HRESULT WINAPI PullPin_Disconnect(IPin *iface)
1828 {
1829     HRESULT hr;
1830     PullPin *This = (PullPin *)iface;
1831
1832     TRACE("()\n");
1833
1834     EnterCriticalSection(This->pin.pCritSec);
1835     {
1836         if (FAILED(hr = IMemAllocator_Decommit(This->pAlloc)))
1837             ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr);
1838
1839         if (This->pin.pConnectedTo)
1840         {
1841             IPin_Release(This->pin.pConnectedTo);
1842             This->pin.pConnectedTo = NULL;
1843             hr = S_OK;
1844         }
1845         else
1846             hr = S_FALSE;
1847     }
1848     LeaveCriticalSection(This->pin.pCritSec);
1849
1850     return hr;
1851 }
1852
1853 HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1854 {
1855     newsegmentargs args;
1856     FIXME("(%p)->(%s, %s, %g) stub\n", iface, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate);
1857
1858     args.tStart = tStart;
1859     args.tStop = tStop;
1860     args.rate = dRate;
1861
1862     return SendFurther( iface, deliver_newsegment, &args, NULL );
1863 }
1864
1865 static const IPinVtbl PullPin_Vtbl = 
1866 {
1867     PullPin_QueryInterface,
1868     IPinImpl_AddRef,
1869     PullPin_Release,
1870     InputPin_Connect,
1871     PullPin_ReceiveConnection,
1872     PullPin_Disconnect,
1873     IPinImpl_ConnectedTo,
1874     IPinImpl_ConnectionMediaType,
1875     IPinImpl_QueryPinInfo,
1876     IPinImpl_QueryDirection,
1877     IPinImpl_QueryId,
1878     IPinImpl_QueryAccept,
1879     IPinImpl_EnumMediaTypes,
1880     IPinImpl_QueryInternalConnections,
1881     PullPin_EndOfStream,
1882     PullPin_BeginFlush,
1883     PullPin_EndFlush,
1884     PullPin_NewSegment
1885 };