gdiplus: Implement GdipGetEmHeight.
[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_DecommitAllocator(OutputPin * This)
1179 {
1180     HRESULT hr = S_OK;
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
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     }
1201     LeaveCriticalSection(This->pin.pCritSec);
1202
1203     TRACE("--> %08x\n", hr);
1204     return hr;
1205 }
1206
1207 HRESULT OutputPin_DeliverDisconnect(OutputPin * This)
1208 {
1209     HRESULT hr;
1210
1211     TRACE("(%p)->()\n", This);
1212
1213     EnterCriticalSection(This->pin.pCritSec);
1214     {
1215         if (!This->pin.pConnectedTo || !This->pMemInputPin)
1216             hr = VFW_E_NOT_CONNECTED;
1217         else if (!This->custom_allocator)
1218         {
1219             IMemAllocator * pAlloc = NULL;
1220
1221             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
1222
1223             if (SUCCEEDED(hr))
1224                 hr = IMemAllocator_Decommit(pAlloc);
1225
1226             if (pAlloc)
1227                 IMemAllocator_Release(pAlloc);
1228
1229             if (SUCCEEDED(hr))
1230                 hr = IPin_Disconnect(This->pin.pConnectedTo);
1231         }
1232         else /* Kill the allocator! */
1233         {
1234             hr = IPin_Disconnect(This->pin.pConnectedTo);
1235         }
1236         IPin_Disconnect((IPin *)This);
1237     }
1238     LeaveCriticalSection(This->pin.pCritSec);
1239
1240     return hr;
1241 }
1242
1243
1244 static HRESULT PullPin_Init(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData,
1245                             QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, STOPPROCESSPROC pDone, LPCRITICAL_SECTION pCritSec, PullPin * pPinImpl)
1246 {
1247     /* Common attributes */
1248     pPinImpl->pin.lpVtbl = PullPin_Vtbl;
1249     pPinImpl->pin.refCount = 1;
1250     pPinImpl->pin.pConnectedTo = NULL;
1251     pPinImpl->pin.fnQueryAccept = pQueryAccept;
1252     pPinImpl->pin.pUserData = pUserData;
1253     pPinImpl->pin.pCritSec = pCritSec;
1254     Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
1255     ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
1256
1257     /* Input pin attributes */
1258     pPinImpl->fnSampleProc = pSampleProc;
1259     pPinImpl->fnCleanProc = pCleanUp;
1260     pPinImpl->fnDone = pDone;
1261     pPinImpl->fnPreConnect = NULL;
1262     pPinImpl->pAlloc = NULL;
1263     pPinImpl->pReader = NULL;
1264     pPinImpl->hThread = NULL;
1265     pPinImpl->hEventStateChanged = CreateEventW(NULL, TRUE, TRUE, NULL);
1266     pPinImpl->thread_sleepy = CreateEventW(NULL, FALSE, FALSE, NULL);
1267
1268     pPinImpl->rtStart = 0;
1269     pPinImpl->rtCurrent = 0;
1270     pPinImpl->rtStop = ((LONGLONG)0x7fffffff << 32) | 0xffffffff;
1271     pPinImpl->dRate = 1.0;
1272     pPinImpl->state = Req_Die;
1273     pPinImpl->fnCustomRequest = pCustomRequest;
1274     pPinImpl->stop_playback = 1;
1275
1276     InitializeCriticalSection(&pPinImpl->thread_lock);
1277     pPinImpl->thread_lock.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": PullPin.thread_lock");
1278
1279     return S_OK;
1280 }
1281
1282 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)
1283 {
1284     PullPin * pPinImpl;
1285
1286     *ppPin = NULL;
1287
1288     if (pPinInfo->dir != PINDIR_INPUT)
1289     {
1290         ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
1291         return E_INVALIDARG;
1292     }
1293
1294     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
1295
1296     if (!pPinImpl)
1297         return E_OUTOFMEMORY;
1298
1299     if (SUCCEEDED(PullPin_Init(PullPin_Vtbl, pPinInfo, pSampleProc, pUserData, pQueryAccept, pCleanUp, pCustomRequest, pDone, pCritSec, pPinImpl)))
1300     {
1301         *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
1302         return S_OK;
1303     }
1304
1305     CoTaskMemFree(pPinImpl);
1306     return E_FAIL;
1307 }
1308
1309 static HRESULT PullPin_InitProcessing(PullPin * This);
1310
1311 HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
1312 {
1313     PIN_DIRECTION pindirReceive;
1314     HRESULT hr = S_OK;
1315     PullPin *This = (PullPin *)iface;
1316
1317     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
1318     dump_AM_MEDIA_TYPE(pmt);
1319
1320     EnterCriticalSection(This->pin.pCritSec);
1321     if (!This->pin.pConnectedTo)
1322     {
1323         ALLOCATOR_PROPERTIES props;
1324
1325         props.cBuffers = 3;
1326         props.cbBuffer = 64 * 1024; /* 64k bytes */
1327         props.cbAlign = 1;
1328         props.cbPrefix = 0;
1329
1330         if (SUCCEEDED(hr) && (This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK))
1331             hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto 
1332                                            * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
1333
1334         if (SUCCEEDED(hr))
1335         {
1336             IPin_QueryDirection(pReceivePin, &pindirReceive);
1337
1338             if (pindirReceive != PINDIR_OUTPUT)
1339             {
1340                 ERR("Can't connect from non-output pin\n");
1341                 hr = VFW_E_INVALID_DIRECTION;
1342             }
1343         }
1344
1345         This->pReader = NULL;
1346         This->pAlloc = NULL;
1347         if (SUCCEEDED(hr))
1348         {
1349             hr = IPin_QueryInterface(pReceivePin, &IID_IAsyncReader, (LPVOID *)&This->pReader);
1350         }
1351
1352         if (SUCCEEDED(hr) && This->fnPreConnect)
1353         {
1354             hr = This->fnPreConnect(iface, pReceivePin, &props);
1355         }
1356
1357         if (SUCCEEDED(hr))
1358         {
1359             hr = IAsyncReader_RequestAllocator(This->pReader, NULL, &props, &This->pAlloc);
1360         }
1361
1362         if (SUCCEEDED(hr))
1363         {
1364             CopyMediaType(&This->pin.mtCurrent, pmt);
1365             This->pin.pConnectedTo = pReceivePin;
1366             IPin_AddRef(pReceivePin);
1367             hr = IMemAllocator_Commit(This->pAlloc);
1368         }
1369
1370         if (SUCCEEDED(hr))
1371             hr = PullPin_InitProcessing(This);
1372
1373         if (FAILED(hr))
1374         {
1375              if (This->pReader)
1376                  IAsyncReader_Release(This->pReader);
1377              This->pReader = NULL;
1378              if (This->pAlloc)
1379                  IMemAllocator_Release(This->pAlloc);
1380              This->pAlloc = NULL;
1381         }
1382     }
1383     else
1384         hr = VFW_E_ALREADY_CONNECTED;
1385     LeaveCriticalSection(This->pin.pCritSec);
1386     return hr;
1387 }
1388
1389 HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
1390 {
1391     PullPin *This = (PullPin *)iface;
1392
1393     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
1394
1395     *ppv = NULL;
1396
1397     if (IsEqualIID(riid, &IID_IUnknown))
1398         *ppv = (LPVOID)iface;
1399     else if (IsEqualIID(riid, &IID_IPin))
1400         *ppv = (LPVOID)iface;
1401     else if (IsEqualIID(riid, &IID_IMediaSeeking))
1402     {
1403         return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
1404     }
1405
1406     if (*ppv)
1407     {
1408         IUnknown_AddRef((IUnknown *)(*ppv));
1409         return S_OK;
1410     }
1411
1412     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
1413
1414     return E_NOINTERFACE;
1415 }
1416
1417 ULONG WINAPI PullPin_Release(IPin *iface)
1418 {
1419     PullPin *This = (PullPin *)iface;
1420     ULONG refCount = InterlockedDecrement(&This->pin.refCount);
1421
1422     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
1423
1424     if (!refCount)
1425     {
1426         WaitForSingleObject(This->hEventStateChanged, INFINITE);
1427         assert(!This->hThread);
1428
1429         if(This->pAlloc)
1430             IMemAllocator_Release(This->pAlloc);
1431         if(This->pReader)
1432             IAsyncReader_Release(This->pReader);
1433         CloseHandle(This->thread_sleepy);
1434         CloseHandle(This->hEventStateChanged);
1435         This->thread_lock.DebugInfo->Spare[0] = 0;
1436         DeleteCriticalSection(&This->thread_lock);
1437         CoTaskMemFree(This);
1438         return 0;
1439     }
1440     return refCount;
1441 }
1442
1443 static void CALLBACK PullPin_Flush(PullPin *This)
1444 {
1445     IMediaSample *pSample;
1446     TRACE("Flushing!\n");
1447
1448     if (This->pReader)
1449     {
1450         /* Flush outstanding samples */
1451         IAsyncReader_BeginFlush(This->pReader);
1452
1453         for (;;)
1454         {
1455             DWORD_PTR dwUser;
1456
1457             IAsyncReader_WaitForNext(This->pReader, 0, &pSample, &dwUser);
1458
1459             if (!pSample)
1460                 break;
1461
1462             assert(!IMediaSample_GetActualDataLength(pSample));
1463
1464             IMediaSample_Release(pSample);
1465         }
1466
1467         IAsyncReader_EndFlush(This->pReader);
1468     }
1469 }
1470
1471 static void CALLBACK PullPin_Thread_Process(PullPin *This)
1472 {
1473     HRESULT hr;
1474     IMediaSample * pSample = NULL;
1475     ALLOCATOR_PROPERTIES allocProps;
1476
1477     hr = IMemAllocator_GetProperties(This->pAlloc, &allocProps);
1478
1479     This->cbAlign = allocProps.cbAlign;
1480
1481     if (This->rtCurrent < This->rtStart)
1482         This->rtCurrent = MEDIATIME_FROM_BYTES(ALIGNDOWN(BYTES_FROM_MEDIATIME(This->rtStart), This->cbAlign));
1483
1484     TRACE("Start\n");
1485
1486     if (This->rtCurrent >= This->rtStop)
1487     {
1488         IPin_EndOfStream((IPin *)This);
1489         return;
1490     }
1491
1492     /* There is no sample in our buffer */
1493     hr = This->fnCustomRequest(This->pin.pUserData);
1494
1495     if (FAILED(hr))
1496         ERR("Request error: %x\n", hr);
1497
1498     EnterCriticalSection(This->pin.pCritSec);
1499     SetEvent(This->hEventStateChanged);
1500     LeaveCriticalSection(This->pin.pCritSec);
1501
1502     if (SUCCEEDED(hr))
1503     do
1504     {
1505         DWORD_PTR dwUser;
1506
1507         TRACE("Process sample\n");
1508
1509         hr = IAsyncReader_WaitForNext(This->pReader, 10000, &pSample, &dwUser);
1510
1511         /* Return an empty sample on error to the implementation in case it does custom parsing, so it knows it's gone */
1512         if (SUCCEEDED(hr))
1513         {
1514             hr = This->fnSampleProc(This->pin.pUserData, pSample, dwUser);
1515         }
1516         else
1517         {
1518             /* FIXME: This is not well handled yet! */
1519             ERR("Processing error: %x\n", hr);
1520         }
1521
1522         if (pSample)
1523         {
1524             IMediaSample_Release(pSample);
1525             pSample = NULL;
1526         }
1527     } while (This->rtCurrent < This->rtStop && hr == S_OK && !This->stop_playback);
1528
1529     /* Sample was rejected, and we are asked to terminate */
1530     if (pSample)
1531     {
1532         IMediaSample_Release(pSample);
1533     }
1534
1535     /* Can't reset state to Sleepy here because that might race, instead PauseProcessing will do that for us
1536      * Flush remaining samples
1537      */
1538     if (This->fnDone)
1539         This->fnDone(This->pin.pUserData);
1540
1541     TRACE("End: %08x, %d\n", hr, This->stop_playback);
1542 }
1543
1544 static void CALLBACK PullPin_Thread_Pause(PullPin *This)
1545 {
1546     EnterCriticalSection(This->pin.pCritSec);
1547     This->state = Req_Sleepy;
1548     SetEvent(This->hEventStateChanged);
1549     LeaveCriticalSection(This->pin.pCritSec);
1550 }
1551
1552 static void CALLBACK PullPin_Thread_Stop(PullPin *This)
1553 {
1554     TRACE("(%p)->()\n", This);
1555
1556     EnterCriticalSection(This->pin.pCritSec);
1557     {
1558         CloseHandle(This->hThread);
1559         This->hThread = NULL;
1560         SetEvent(This->hEventStateChanged);
1561     }
1562     LeaveCriticalSection(This->pin.pCritSec);
1563
1564     IBaseFilter_Release(This->pin.pinInfo.pFilter);
1565
1566     CoUninitialize();
1567     ExitThread(0);
1568 }
1569
1570 static void CALLBACK PullPin_Thread_Flush(PullPin *This)
1571 {
1572     PullPin_Flush(This);
1573
1574     EnterCriticalSection(This->pin.pCritSec);
1575     This->state = Req_Sleepy;
1576     SetEvent(This->hEventStateChanged);
1577     LeaveCriticalSection(This->pin.pCritSec);
1578 }
1579
1580 static DWORD WINAPI PullPin_Thread_Main(LPVOID pv)
1581 {
1582     PullPin *This = pv;
1583     CoInitializeEx(NULL, COINIT_MULTITHREADED);
1584
1585     PullPin_Flush(This);
1586
1587     for (;;)
1588     {
1589         WaitForSingleObject(This->thread_sleepy, INFINITE);
1590
1591         TRACE("State: %d\n", This->state);
1592
1593         switch (This->state)
1594         {
1595         case Req_Die: PullPin_Thread_Stop(This); break;
1596         case Req_Run: PullPin_Thread_Process(This); break;
1597         case Req_Pause: PullPin_Thread_Pause(This); break;
1598         case Req_Flush: PullPin_Thread_Flush(This); break;
1599         case Req_Sleepy: ERR("Should not be signalled with SLEEPY!\n"); break;
1600         default: ERR("Unknown state request: %d\n", This->state); break;
1601         }
1602     }
1603 }
1604
1605 static HRESULT PullPin_InitProcessing(PullPin * This)
1606 {
1607     HRESULT hr = S_OK;
1608
1609     TRACE("(%p)->()\n", This);
1610
1611     /* if we are connected */
1612     if (This->pAlloc)
1613     {
1614         DWORD dwThreadId;
1615
1616         WaitForSingleObject(This->hEventStateChanged, INFINITE);
1617         EnterCriticalSection(This->pin.pCritSec);
1618
1619         assert(!This->hThread);
1620         assert(This->state == Req_Die);
1621         assert(This->stop_playback);
1622         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1623         This->state = Req_Sleepy;
1624
1625         /* AddRef the filter to make sure it and it's pins will be around
1626          * as long as the thread */
1627         IBaseFilter_AddRef(This->pin.pinInfo.pFilter);
1628
1629
1630         This->hThread = CreateThread(NULL, 0, PullPin_Thread_Main, This, 0, &dwThreadId);
1631         if (!This->hThread)
1632         {
1633             hr = HRESULT_FROM_WIN32(GetLastError());
1634             IBaseFilter_Release(This->pin.pinInfo.pFilter);
1635         }
1636
1637         if (SUCCEEDED(hr))
1638         {
1639             SetEvent(This->hEventStateChanged);
1640             /* If assert fails, that means a command was not processed before the thread previously terminated */
1641         }
1642         LeaveCriticalSection(This->pin.pCritSec);
1643     }
1644
1645     TRACE(" -- %x\n", hr);
1646
1647     return hr;
1648 }
1649
1650 HRESULT PullPin_StartProcessing(PullPin * This)
1651 {
1652     /* if we are connected */
1653     TRACE("(%p)->()\n", This);
1654     if(This->pAlloc)
1655     {
1656         assert(This->hThread);
1657
1658         PullPin_WaitForStateChange(This, INFINITE);
1659
1660         assert(This->state == Req_Sleepy);
1661
1662         /* Wake up! */
1663         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1664         This->state = Req_Run;
1665         This->stop_playback = 0;
1666         ResetEvent(This->hEventStateChanged);
1667         SetEvent(This->thread_sleepy);
1668     }
1669
1670     return S_OK;
1671 }
1672
1673 HRESULT PullPin_PauseProcessing(PullPin * This)
1674 {
1675     /* if we are connected */
1676     TRACE("(%p)->()\n", This);
1677     if(This->pAlloc)
1678     {
1679         assert(This->hThread);
1680
1681         PullPin_WaitForStateChange(This, INFINITE);
1682
1683         EnterCriticalSection(This->pin.pCritSec);
1684
1685         assert(!This->stop_playback);
1686         assert(This->state == Req_Run|| This->state == Req_Sleepy);
1687
1688         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1689         This->state = Req_Pause;
1690         This->stop_playback = 1;
1691         ResetEvent(This->hEventStateChanged);
1692         SetEvent(This->thread_sleepy);
1693
1694         LeaveCriticalSection(This->pin.pCritSec);
1695     }
1696
1697     return S_OK;
1698 }
1699
1700 static HRESULT PullPin_StopProcessing(PullPin * This)
1701 {
1702     TRACE("(%p)->()\n", This);
1703
1704     /* if we are alive */
1705     assert(This->hThread);
1706
1707     PullPin_WaitForStateChange(This, INFINITE);
1708
1709     assert(This->state == Req_Pause || This->state == Req_Sleepy);
1710
1711     This->stop_playback = 1;
1712     This->state = Req_Die;
1713     assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1714     ResetEvent(This->hEventStateChanged);
1715     SetEvent(This->thread_sleepy);
1716     return S_OK;
1717 }
1718
1719 HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds)
1720 {
1721     if (WaitForSingleObject(This->hEventStateChanged, dwMilliseconds) == WAIT_TIMEOUT)
1722         return S_FALSE;
1723     return S_OK;
1724 }
1725
1726 HRESULT WINAPI PullPin_EndOfStream(IPin * iface)
1727 {
1728     FIXME("(%p)->() stub\n", iface);
1729
1730     return SendFurther( iface, deliver_endofstream, NULL, NULL );
1731 }
1732
1733 HRESULT WINAPI PullPin_BeginFlush(IPin * iface)
1734 {
1735     PullPin *This = (PullPin *)iface;
1736     TRACE("(%p)->()\n", This);
1737
1738     EnterCriticalSection(This->pin.pCritSec);
1739     {
1740         SendFurther( iface, deliver_beginflush, NULL, NULL );
1741     }
1742     LeaveCriticalSection(This->pin.pCritSec);
1743
1744     EnterCriticalSection(&This->thread_lock);
1745     {
1746         if (This->pReader)
1747             IAsyncReader_BeginFlush(This->pReader);
1748         PullPin_WaitForStateChange(This, INFINITE);
1749
1750         if (This->hThread && This->state == Req_Run)
1751         {
1752             PullPin_PauseProcessing(This);
1753             PullPin_WaitForStateChange(This, INFINITE);
1754         }
1755
1756         This->state = Req_Flush;
1757         ResetEvent(This->hEventStateChanged);
1758         SetEvent(This->thread_sleepy);
1759         PullPin_WaitForStateChange(This, INFINITE);
1760     }
1761     LeaveCriticalSection(&This->thread_lock);
1762
1763     EnterCriticalSection(This->pin.pCritSec);
1764     {
1765         This->fnCleanProc(This->pin.pUserData);
1766     }
1767     LeaveCriticalSection(This->pin.pCritSec);
1768
1769     return S_OK;
1770 }
1771
1772 HRESULT WINAPI PullPin_EndFlush(IPin * iface)
1773 {
1774     PullPin *This = (PullPin *)iface;
1775
1776     TRACE("(%p)->()\n", iface);
1777
1778     EnterCriticalSection(&This->thread_lock);
1779     {
1780         FILTER_STATE state;
1781         IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state);
1782
1783         if (This->stop_playback && state != State_Stopped)
1784             PullPin_StartProcessing(This);
1785
1786         PullPin_WaitForStateChange(This, INFINITE);
1787     }
1788     LeaveCriticalSection(&This->thread_lock);
1789
1790     EnterCriticalSection(This->pin.pCritSec);
1791     SendFurther( iface, deliver_endflush, NULL, NULL );
1792     LeaveCriticalSection(This->pin.pCritSec);
1793
1794     return S_OK;
1795 }
1796
1797 HRESULT WINAPI PullPin_Disconnect(IPin *iface)
1798 {
1799     HRESULT hr;
1800     PullPin *This = (PullPin *)iface;
1801
1802     TRACE("()\n");
1803
1804     EnterCriticalSection(This->pin.pCritSec);
1805     {
1806         if (FAILED(hr = IMemAllocator_Decommit(This->pAlloc)))
1807             ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr);
1808
1809         if (This->pin.pConnectedTo)
1810         {
1811             IPin_Release(This->pin.pConnectedTo);
1812             This->pin.pConnectedTo = NULL;
1813             PullPin_StopProcessing(This);
1814             hr = S_OK;
1815         }
1816         else
1817             hr = S_FALSE;
1818     }
1819     LeaveCriticalSection(This->pin.pCritSec);
1820
1821     return hr;
1822 }
1823
1824 HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1825 {
1826     newsegmentargs args;
1827     FIXME("(%p)->(%s, %s, %g) stub\n", iface, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate);
1828
1829     args.tStart = tStart;
1830     args.tStop = tStop;
1831     args.rate = dRate;
1832
1833     return SendFurther( iface, deliver_newsegment, &args, NULL );
1834 }
1835
1836 static const IPinVtbl PullPin_Vtbl = 
1837 {
1838     PullPin_QueryInterface,
1839     IPinImpl_AddRef,
1840     PullPin_Release,
1841     InputPin_Connect,
1842     PullPin_ReceiveConnection,
1843     PullPin_Disconnect,
1844     IPinImpl_ConnectedTo,
1845     IPinImpl_ConnectionMediaType,
1846     IPinImpl_QueryPinInfo,
1847     IPinImpl_QueryDirection,
1848     IPinImpl_QueryId,
1849     IPinImpl_QueryAccept,
1850     IPinImpl_EnumMediaTypes,
1851     IPinImpl_QueryInternalConnections,
1852     PullPin_EndOfStream,
1853     PullPin_BeginFlush,
1854     PullPin_EndFlush,
1855     PullPin_NewSegment
1856 };