quartz: Add tests for avi splitter.
[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     hr = This->fnSampleProc(This->pin.pUserData, pSample);
807     return hr;
808 }
809
810 HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, long nSamples, long *nSamplesProcessed)
811 {
812     HRESULT hr = S_OK;
813     InputPin *This = impl_from_IMemInputPin(iface);
814
815     TRACE("(%p/%p)->(%p, %ld, %p)\n", This, iface, pSamples, nSamples, nSamplesProcessed);
816
817     for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; (*nSamplesProcessed)++)
818     {
819         hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
820         if (hr != S_OK)
821             break;
822     }
823
824     return hr;
825 }
826
827 HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface)
828 {
829     InputPin *This = impl_from_IMemInputPin(iface);
830
831     TRACE("(%p/%p)->()\n", This, iface);
832
833     return S_OK;
834 }
835
836 static const IMemInputPinVtbl MemInputPin_Vtbl = 
837 {
838     MemInputPin_QueryInterface,
839     MemInputPin_AddRef,
840     MemInputPin_Release,
841     MemInputPin_GetAllocator,
842     MemInputPin_NotifyAllocator,
843     MemInputPin_GetAllocatorRequirements,
844     MemInputPin_Receive,
845     MemInputPin_ReceiveMultiple,
846     MemInputPin_ReceiveCanBlock
847 };
848
849 HRESULT WINAPI OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
850 {
851     OutputPin *This = (OutputPin *)iface;
852
853     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
854
855     *ppv = NULL;
856
857     if (IsEqualIID(riid, &IID_IUnknown))
858         *ppv = (LPVOID)iface;
859     else if (IsEqualIID(riid, &IID_IPin))
860         *ppv = (LPVOID)iface;
861     else if (IsEqualIID(riid, &IID_IMediaSeeking))
862     {
863         return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
864     }
865
866     if (*ppv)
867     {
868         IUnknown_AddRef((IUnknown *)(*ppv));
869         return S_OK;
870     }
871
872     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
873
874     return E_NOINTERFACE;
875 }
876
877 ULONG WINAPI OutputPin_Release(IPin * iface)
878 {
879     OutputPin *This = (OutputPin *)iface;
880     ULONG refCount = InterlockedDecrement(&This->pin.refCount);
881
882     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
883
884     if (!refCount)
885     {
886         FreeMediaType(&This->pin.mtCurrent);
887         CoTaskMemFree(This);
888         return 0;
889     }
890     return refCount;
891 }
892
893 HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
894 {
895     HRESULT hr;
896     OutputPin *This = (OutputPin *)iface;
897
898     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
899     dump_AM_MEDIA_TYPE(pmt);
900
901     /* If we try to connect to ourself, we will definitely deadlock.
902      * There are other cases where we could deadlock too, but this
903      * catches the obvious case */
904     assert(pReceivePin != iface);
905
906     EnterCriticalSection(This->pin.pCritSec);
907     {
908         /* if we have been a specific type to connect with, then we can either connect
909          * with that or fail. We cannot choose different AM_MEDIA_TYPE */
910         if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
911             hr = This->pConnectSpecific(iface, pReceivePin, pmt);
912         else
913         {
914             /* negotiate media type */
915
916             IEnumMediaTypes * pEnumCandidates;
917             AM_MEDIA_TYPE * pmtCandidate; /* Candidate media type */
918
919             if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates)))
920             {
921                 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
922
923                 /* try this filter's media types first */
924                 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
925                 {
926                     if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && 
927                         (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
928                     {
929                         hr = S_OK;
930                         CoTaskMemFree(pmtCandidate);
931                         break;
932                     }
933                     CoTaskMemFree(pmtCandidate);
934                 }
935                 IEnumMediaTypes_Release(pEnumCandidates);
936             }
937
938             /* then try receiver filter's media types */
939             if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */
940             {
941                 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
942
943                 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
944                 {
945                     if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && 
946                         (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
947                     {
948                         hr = S_OK;
949                         CoTaskMemFree(pmtCandidate);
950                         break;
951                     }
952                     CoTaskMemFree(pmtCandidate);
953                 } /* while */
954                 IEnumMediaTypes_Release(pEnumCandidates);
955             } /* if not found */
956         } /* if negotiate media type */
957     } /* if succeeded */
958     LeaveCriticalSection(This->pin.pCritSec);
959
960     TRACE(" -- %x\n", hr);
961     return hr;
962 }
963
964 HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
965 {
966     ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin, pmt);
967
968     return E_UNEXPECTED;
969 }
970
971 HRESULT WINAPI OutputPin_Disconnect(IPin * iface)
972 {
973     HRESULT hr;
974     OutputPin *This = (OutputPin *)iface;
975
976     TRACE("()\n");
977
978     EnterCriticalSection(This->pin.pCritSec);
979     {
980         if (This->pMemInputPin)
981         {
982             IMemInputPin_Release(This->pMemInputPin);
983             This->pMemInputPin = NULL;
984         }
985         if (This->pin.pConnectedTo)
986         {
987             IPin_Release(This->pin.pConnectedTo);
988             This->pin.pConnectedTo = NULL;
989             hr = S_OK;
990         }
991         else
992             hr = S_FALSE;
993     }
994     LeaveCriticalSection(This->pin.pCritSec);
995
996     return hr;
997 }
998
999 HRESULT WINAPI OutputPin_EndOfStream(IPin * iface)
1000 {
1001     TRACE("()\n");
1002
1003     /* not supposed to do anything in an output pin */
1004
1005     return E_UNEXPECTED;
1006 }
1007
1008 HRESULT WINAPI OutputPin_BeginFlush(IPin * iface)
1009 {
1010     TRACE("(%p)->()\n", iface);
1011
1012     /* not supposed to do anything in an output pin */
1013
1014     return E_UNEXPECTED;
1015 }
1016
1017 HRESULT WINAPI OutputPin_EndFlush(IPin * iface)
1018 {
1019     TRACE("(%p)->()\n", iface);
1020
1021     /* not supposed to do anything in an output pin */
1022
1023     return E_UNEXPECTED;
1024 }
1025
1026 HRESULT WINAPI OutputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1027 {
1028     TRACE("(%p)->(%x%08x, %x%08x, %e)\n", iface, (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate);
1029
1030     /* not supposed to do anything in an output pin */
1031
1032     return E_UNEXPECTED;
1033 }
1034
1035 static const IPinVtbl OutputPin_Vtbl = 
1036 {
1037     OutputPin_QueryInterface,
1038     IPinImpl_AddRef,
1039     OutputPin_Release,
1040     OutputPin_Connect,
1041     OutputPin_ReceiveConnection,
1042     OutputPin_Disconnect,
1043     IPinImpl_ConnectedTo,
1044     IPinImpl_ConnectionMediaType,
1045     IPinImpl_QueryPinInfo,
1046     IPinImpl_QueryDirection,
1047     IPinImpl_QueryId,
1048     IPinImpl_QueryAccept,
1049     IPinImpl_EnumMediaTypes,
1050     IPinImpl_QueryInternalConnections,
1051     OutputPin_EndOfStream,
1052     OutputPin_BeginFlush,
1053     OutputPin_EndFlush,
1054     OutputPin_NewSegment
1055 };
1056
1057 HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags)
1058 {
1059     HRESULT hr;
1060
1061     TRACE("(%p, %p, %p, %x)\n", ppSample, tStart, tStop, dwFlags);
1062
1063     EnterCriticalSection(This->pin.pCritSec);
1064     {
1065         if (!This->pin.pConnectedTo)
1066             hr = VFW_E_NOT_CONNECTED;
1067         else
1068         {
1069             IMemAllocator * pAlloc = NULL;
1070             
1071             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
1072
1073             if (SUCCEEDED(hr))
1074                 hr = IMemAllocator_GetBuffer(pAlloc, ppSample, tStart, tStop, dwFlags);
1075
1076             if (SUCCEEDED(hr))
1077                 hr = IMediaSample_SetTime(*ppSample, tStart, tStop);
1078
1079             if (pAlloc)
1080                 IMemAllocator_Release(pAlloc);
1081         }
1082     }
1083     LeaveCriticalSection(This->pin.pCritSec);
1084     
1085     return hr;
1086 }
1087
1088 HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample)
1089 {
1090     HRESULT hr = S_OK;
1091     IMemInputPin * pMemConnected = NULL;
1092     PIN_INFO pinInfo;
1093
1094     EnterCriticalSection(This->pin.pCritSec);
1095     {
1096         if (!This->pin.pConnectedTo || !This->pMemInputPin)
1097             hr = VFW_E_NOT_CONNECTED;
1098         else
1099         {
1100             /* we don't have the lock held when using This->pMemInputPin,
1101              * so we need to AddRef it to stop it being deleted while we are
1102              * using it. Same with its filter. */
1103             pMemConnected = This->pMemInputPin;
1104             IMemInputPin_AddRef(pMemConnected);
1105             hr = IPin_QueryPinInfo(This->pin.pConnectedTo, &pinInfo);
1106         }
1107     }
1108     LeaveCriticalSection(This->pin.pCritSec);
1109
1110     if (SUCCEEDED(hr))
1111     {
1112         /* NOTE: if we are in a critical section when Receive is called
1113          * then it causes some problems (most notably with the native Video
1114          * Renderer) if we are re-entered for whatever reason */
1115         hr = IMemInputPin_Receive(pMemConnected, pSample);
1116
1117         /* If the filter's destroyed, tell upstream to stop sending data */
1118         if(IBaseFilter_Release(pinInfo.pFilter) == 0 && SUCCEEDED(hr))
1119             hr = S_FALSE;
1120     }
1121     if (pMemConnected)
1122         IMemInputPin_Release(pMemConnected);
1123
1124     return hr;
1125 }
1126
1127 HRESULT OutputPin_DeliverNewSegment(OutputPin * This, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1128 {
1129     HRESULT hr;
1130
1131     EnterCriticalSection(This->pin.pCritSec);
1132     {
1133         if (!This->pin.pConnectedTo)
1134             hr = VFW_E_NOT_CONNECTED;
1135         else
1136             hr = IPin_NewSegment(This->pin.pConnectedTo, tStart, tStop, dRate);
1137     }
1138     LeaveCriticalSection(This->pin.pCritSec);
1139     
1140     return hr;
1141 }
1142
1143 HRESULT OutputPin_CommitAllocator(OutputPin * This)
1144 {
1145     HRESULT hr = S_OK;
1146
1147     TRACE("(%p)->()\n", This);
1148
1149     EnterCriticalSection(This->pin.pCritSec);
1150     {
1151         if (!This->pin.pConnectedTo || !This->pMemInputPin)
1152             hr = VFW_E_NOT_CONNECTED;
1153         else
1154         {
1155             IMemAllocator * pAlloc = NULL;
1156
1157             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
1158
1159             if (SUCCEEDED(hr))
1160                 hr = IMemAllocator_Commit(pAlloc);
1161
1162             if (pAlloc)
1163                 IMemAllocator_Release(pAlloc);
1164         }
1165     }
1166     LeaveCriticalSection(This->pin.pCritSec);
1167
1168     TRACE("--> %08x\n", hr);
1169     return hr;
1170 }
1171
1172 HRESULT OutputPin_DecommitAllocator(OutputPin * This)
1173 {
1174     HRESULT hr = S_OK;
1175
1176     TRACE("(%p)->()\n", This);
1177
1178     EnterCriticalSection(This->pin.pCritSec);
1179     {
1180         if (!This->pin.pConnectedTo || !This->pMemInputPin)
1181             hr = VFW_E_NOT_CONNECTED;
1182         else
1183         {
1184             IMemAllocator * pAlloc = NULL;
1185
1186             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
1187
1188             if (SUCCEEDED(hr))
1189                 hr = IMemAllocator_Decommit(pAlloc);
1190
1191             if (pAlloc)
1192                 IMemAllocator_Release(pAlloc);
1193         }
1194     }
1195     LeaveCriticalSection(This->pin.pCritSec);
1196
1197     TRACE("--> %08x\n", hr);
1198     return hr;
1199 }
1200
1201 HRESULT OutputPin_DeliverDisconnect(OutputPin * This)
1202 {
1203     HRESULT hr;
1204
1205     TRACE("(%p)->()\n", This);
1206
1207     EnterCriticalSection(This->pin.pCritSec);
1208     {
1209         if (!This->pin.pConnectedTo || !This->pMemInputPin)
1210             hr = VFW_E_NOT_CONNECTED;
1211         else if (!This->custom_allocator)
1212         {
1213             IMemAllocator * pAlloc = NULL;
1214
1215             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
1216
1217             if (SUCCEEDED(hr))
1218                 hr = IMemAllocator_Decommit(pAlloc);
1219
1220             if (pAlloc)
1221                 IMemAllocator_Release(pAlloc);
1222
1223             if (SUCCEEDED(hr))
1224                 hr = IPin_Disconnect(This->pin.pConnectedTo);
1225         }
1226         else /* Kill the allocator! */
1227         {
1228             hr = IPin_Disconnect(This->pin.pConnectedTo);
1229         }
1230         IPin_Disconnect((IPin *)This);
1231     }
1232     LeaveCriticalSection(This->pin.pCritSec);
1233
1234     return hr;
1235 }
1236
1237
1238 static HRESULT PullPin_Init(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData,
1239                             QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, STOPPROCESSPROC pDone, LPCRITICAL_SECTION pCritSec, PullPin * pPinImpl)
1240 {
1241     /* Common attributes */
1242     pPinImpl->pin.lpVtbl = PullPin_Vtbl;
1243     pPinImpl->pin.refCount = 1;
1244     pPinImpl->pin.pConnectedTo = NULL;
1245     pPinImpl->pin.fnQueryAccept = pQueryAccept;
1246     pPinImpl->pin.pUserData = pUserData;
1247     pPinImpl->pin.pCritSec = pCritSec;
1248     Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
1249     ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
1250
1251     /* Input pin attributes */
1252     pPinImpl->fnSampleProc = pSampleProc;
1253     pPinImpl->fnCleanProc = pCleanUp;
1254     pPinImpl->fnDone = pDone;
1255     pPinImpl->fnPreConnect = NULL;
1256     pPinImpl->pAlloc = NULL;
1257     pPinImpl->pReader = NULL;
1258     pPinImpl->hThread = NULL;
1259     pPinImpl->hEventStateChanged = CreateEventW(NULL, TRUE, TRUE, NULL);
1260     pPinImpl->thread_sleepy = CreateEventW(NULL, FALSE, FALSE, NULL);
1261
1262     pPinImpl->rtStart = 0;
1263     pPinImpl->rtCurrent = 0;
1264     pPinImpl->rtStop = ((LONGLONG)0x7fffffff << 32) | 0xffffffff;
1265     pPinImpl->dRate = 1.0;
1266     pPinImpl->state = Req_Die;
1267     pPinImpl->fnCustomRequest = pCustomRequest;
1268     pPinImpl->stop_playback = 1;
1269
1270     InitializeCriticalSection(&pPinImpl->thread_lock);
1271     pPinImpl->thread_lock.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": PullPin.thread_lock");
1272
1273     return S_OK;
1274 }
1275
1276 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)
1277 {
1278     PullPin * pPinImpl;
1279
1280     *ppPin = NULL;
1281
1282     if (pPinInfo->dir != PINDIR_INPUT)
1283     {
1284         ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
1285         return E_INVALIDARG;
1286     }
1287
1288     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
1289
1290     if (!pPinImpl)
1291         return E_OUTOFMEMORY;
1292
1293     if (SUCCEEDED(PullPin_Init(PullPin_Vtbl, pPinInfo, pSampleProc, pUserData, pQueryAccept, pCleanUp, pCustomRequest, pDone, pCritSec, pPinImpl)))
1294     {
1295         *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
1296         return S_OK;
1297     }
1298
1299     CoTaskMemFree(pPinImpl);
1300     return E_FAIL;
1301 }
1302
1303 static HRESULT PullPin_InitProcessing(PullPin * This);
1304
1305 HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
1306 {
1307     PIN_DIRECTION pindirReceive;
1308     HRESULT hr = S_OK;
1309     PullPin *This = (PullPin *)iface;
1310
1311     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
1312     dump_AM_MEDIA_TYPE(pmt);
1313
1314     EnterCriticalSection(This->pin.pCritSec);
1315     if (!This->pin.pConnectedTo)
1316     {
1317         ALLOCATOR_PROPERTIES props;
1318
1319         props.cBuffers = 3;
1320         props.cbBuffer = 64 * 1024; /* 64k bytes */
1321         props.cbAlign = 1;
1322         props.cbPrefix = 0;
1323
1324         if (SUCCEEDED(hr) && (This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK))
1325             hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto 
1326                                            * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
1327
1328         if (SUCCEEDED(hr))
1329         {
1330             IPin_QueryDirection(pReceivePin, &pindirReceive);
1331
1332             if (pindirReceive != PINDIR_OUTPUT)
1333             {
1334                 ERR("Can't connect from non-output pin\n");
1335                 hr = VFW_E_INVALID_DIRECTION;
1336             }
1337         }
1338
1339         This->pReader = NULL;
1340         This->pAlloc = NULL;
1341         if (SUCCEEDED(hr))
1342         {
1343             hr = IPin_QueryInterface(pReceivePin, &IID_IAsyncReader, (LPVOID *)&This->pReader);
1344         }
1345
1346         if (SUCCEEDED(hr) && This->fnPreConnect)
1347         {
1348             hr = This->fnPreConnect(iface, pReceivePin, &props);
1349         }
1350
1351         if (SUCCEEDED(hr))
1352         {
1353             hr = IAsyncReader_RequestAllocator(This->pReader, NULL, &props, &This->pAlloc);
1354         }
1355
1356         if (SUCCEEDED(hr))
1357         {
1358             CopyMediaType(&This->pin.mtCurrent, pmt);
1359             This->pin.pConnectedTo = pReceivePin;
1360             IPin_AddRef(pReceivePin);
1361             hr = IMemAllocator_Commit(This->pAlloc);
1362         }
1363
1364         if (SUCCEEDED(hr))
1365             hr = PullPin_InitProcessing(This);
1366
1367         if (FAILED(hr))
1368         {
1369              if (This->pReader)
1370                  IAsyncReader_Release(This->pReader);
1371              This->pReader = NULL;
1372              if (This->pAlloc)
1373                  IMemAllocator_Release(This->pAlloc);
1374              This->pAlloc = NULL;
1375         }
1376     }
1377     else
1378         hr = VFW_E_ALREADY_CONNECTED;
1379     LeaveCriticalSection(This->pin.pCritSec);
1380     return hr;
1381 }
1382
1383 HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
1384 {
1385     PullPin *This = (PullPin *)iface;
1386
1387     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
1388
1389     *ppv = NULL;
1390
1391     if (IsEqualIID(riid, &IID_IUnknown))
1392         *ppv = (LPVOID)iface;
1393     else if (IsEqualIID(riid, &IID_IPin))
1394         *ppv = (LPVOID)iface;
1395     else if (IsEqualIID(riid, &IID_IMediaSeeking))
1396     {
1397         return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
1398     }
1399
1400     if (*ppv)
1401     {
1402         IUnknown_AddRef((IUnknown *)(*ppv));
1403         return S_OK;
1404     }
1405
1406     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
1407
1408     return E_NOINTERFACE;
1409 }
1410
1411 ULONG WINAPI PullPin_Release(IPin *iface)
1412 {
1413     PullPin *This = (PullPin *)iface;
1414     ULONG refCount = InterlockedDecrement(&This->pin.refCount);
1415
1416     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
1417
1418     if (!refCount)
1419     {
1420         WaitForSingleObject(This->hEventStateChanged, INFINITE);
1421         assert(!This->hThread);
1422
1423         if(This->pAlloc)
1424             IMemAllocator_Release(This->pAlloc);
1425         if(This->pReader)
1426             IAsyncReader_Release(This->pReader);
1427         CloseHandle(This->thread_sleepy);
1428         CloseHandle(This->hEventStateChanged);
1429         This->thread_lock.DebugInfo->Spare[0] = 0;
1430         DeleteCriticalSection(&This->thread_lock);
1431         CoTaskMemFree(This);
1432         return 0;
1433     }
1434     return refCount;
1435 }
1436
1437 static void CALLBACK PullPin_Flush(PullPin *This)
1438 {
1439     IMediaSample *pSample;
1440     TRACE("Flushing!\n");
1441
1442     if (This->pReader)
1443     {
1444         /* Flush outstanding samples */
1445         IAsyncReader_BeginFlush(This->pReader);
1446
1447         for (;;)
1448         {
1449             DWORD_PTR dwUser;
1450
1451             IAsyncReader_WaitForNext(This->pReader, 0, &pSample, &dwUser);
1452
1453             if (!pSample)
1454                 break;
1455
1456             assert(!IMediaSample_GetActualDataLength(pSample));
1457
1458             IMediaSample_Release(pSample);
1459         }
1460
1461         IAsyncReader_EndFlush(This->pReader);
1462     }
1463 }
1464
1465 static void CALLBACK PullPin_Thread_Process(PullPin *This)
1466 {
1467     HRESULT hr;
1468     IMediaSample * pSample = NULL;
1469     ALLOCATOR_PROPERTIES allocProps;
1470
1471     hr = IMemAllocator_GetProperties(This->pAlloc, &allocProps);
1472
1473     This->cbAlign = allocProps.cbAlign;
1474
1475     if (This->rtCurrent < This->rtStart)
1476         This->rtCurrent = MEDIATIME_FROM_BYTES(ALIGNDOWN(BYTES_FROM_MEDIATIME(This->rtStart), This->cbAlign));
1477
1478     TRACE("Start\n");
1479
1480     if (This->rtCurrent >= This->rtStop)
1481     {
1482         IPin_EndOfStream((IPin *)This);
1483         return;
1484     }
1485
1486     /* There is no sample in our buffer */
1487     hr = This->fnCustomRequest(This->pin.pUserData);
1488
1489     if (FAILED(hr))
1490         ERR("Request error: %x\n", hr);
1491
1492     EnterCriticalSection(This->pin.pCritSec);
1493     SetEvent(This->hEventStateChanged);
1494     LeaveCriticalSection(This->pin.pCritSec);
1495
1496     if (SUCCEEDED(hr))
1497     do
1498     {
1499         DWORD_PTR dwUser;
1500
1501         TRACE("Process sample\n");
1502
1503         hr = IAsyncReader_WaitForNext(This->pReader, 10000, &pSample, &dwUser);
1504
1505         /* Return an empty sample on error to the implementation in case it does custom parsing, so it knows it's gone */
1506         if (SUCCEEDED(hr))
1507         {
1508             hr = This->fnSampleProc(This->pin.pUserData, pSample, dwUser);
1509         }
1510         else
1511         {
1512             /* FIXME: This is not well handled yet! */
1513             ERR("Processing error: %x\n", hr);
1514         }
1515
1516         if (pSample)
1517         {
1518             IMediaSample_Release(pSample);
1519             pSample = NULL;
1520         }
1521     } while (This->rtCurrent < This->rtStop && hr == S_OK && !This->stop_playback);
1522
1523     /* Sample was rejected, and we are asked to terminate */
1524     if (pSample)
1525     {
1526         IMediaSample_Release(pSample);
1527     }
1528
1529     /* Can't reset state to Sleepy here because that might race, instead PauseProcessing will do that for us
1530      * Flush remaining samples
1531      */
1532     if (This->fnDone)
1533         This->fnDone(This->pin.pUserData);
1534
1535     TRACE("End: %08x, %d\n", hr, This->stop_playback);
1536 }
1537
1538 static void CALLBACK PullPin_Thread_Pause(PullPin *This)
1539 {
1540     EnterCriticalSection(This->pin.pCritSec);
1541     This->state = Req_Sleepy;
1542     SetEvent(This->hEventStateChanged);
1543     LeaveCriticalSection(This->pin.pCritSec);
1544 }
1545
1546 static void CALLBACK PullPin_Thread_Stop(PullPin *This)
1547 {
1548     TRACE("(%p)->()\n", This);
1549
1550     EnterCriticalSection(This->pin.pCritSec);
1551     {
1552         CloseHandle(This->hThread);
1553         This->hThread = NULL;
1554         SetEvent(This->hEventStateChanged);
1555     }
1556     LeaveCriticalSection(This->pin.pCritSec);
1557
1558     IBaseFilter_Release(This->pin.pinInfo.pFilter);
1559
1560     CoUninitialize();
1561     ExitThread(0);
1562 }
1563
1564 static void CALLBACK PullPin_Thread_Flush(PullPin *This)
1565 {
1566     PullPin_Flush(This);
1567
1568     EnterCriticalSection(This->pin.pCritSec);
1569     This->state = Req_Sleepy;
1570     SetEvent(This->hEventStateChanged);
1571     LeaveCriticalSection(This->pin.pCritSec);
1572 }
1573
1574 static DWORD WINAPI PullPin_Thread_Main(LPVOID pv)
1575 {
1576     PullPin *This = pv;
1577     CoInitializeEx(NULL, COINIT_MULTITHREADED);
1578
1579     PullPin_Flush(This);
1580
1581     for (;;)
1582     {
1583         WaitForSingleObject(This->thread_sleepy, INFINITE);
1584
1585         TRACE("State: %d\n", This->state);
1586
1587         switch (This->state)
1588         {
1589         case Req_Die: PullPin_Thread_Stop(This); break;
1590         case Req_Run: PullPin_Thread_Process(This); break;
1591         case Req_Pause: PullPin_Thread_Pause(This); break;
1592         case Req_Flush: PullPin_Thread_Flush(This); break;
1593         case Req_Sleepy: ERR("Should not be signalled with SLEEPY!\n"); break;
1594         default: ERR("Unknown state request: %d\n", This->state); break;
1595         }
1596     }
1597 }
1598
1599 static HRESULT PullPin_InitProcessing(PullPin * This)
1600 {
1601     HRESULT hr = S_OK;
1602
1603     TRACE("(%p)->()\n", This);
1604
1605     /* if we are connected */
1606     if (This->pAlloc)
1607     {
1608         DWORD dwThreadId;
1609
1610         WaitForSingleObject(This->hEventStateChanged, INFINITE);
1611         EnterCriticalSection(This->pin.pCritSec);
1612
1613         assert(!This->hThread);
1614         assert(This->state == Req_Die);
1615         assert(This->stop_playback);
1616         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1617         This->state = Req_Sleepy;
1618
1619         /* AddRef the filter to make sure it and it's pins will be around
1620          * as long as the thread */
1621         IBaseFilter_AddRef(This->pin.pinInfo.pFilter);
1622
1623
1624         This->hThread = CreateThread(NULL, 0, PullPin_Thread_Main, This, 0, &dwThreadId);
1625         if (!This->hThread)
1626         {
1627             hr = HRESULT_FROM_WIN32(GetLastError());
1628             IBaseFilter_Release(This->pin.pinInfo.pFilter);
1629         }
1630
1631         if (SUCCEEDED(hr))
1632         {
1633             SetEvent(This->hEventStateChanged);
1634             /* If assert fails, that means a command was not processed before the thread previously terminated */
1635         }
1636         LeaveCriticalSection(This->pin.pCritSec);
1637     }
1638
1639     TRACE(" -- %x\n", hr);
1640
1641     return hr;
1642 }
1643
1644 HRESULT PullPin_StartProcessing(PullPin * This)
1645 {
1646     /* if we are connected */
1647     TRACE("(%p)->()\n", This);
1648     if(This->pAlloc)
1649     {
1650         assert(This->hThread);
1651
1652         PullPin_WaitForStateChange(This, INFINITE);
1653
1654         assert(This->state == Req_Sleepy);
1655
1656         /* Wake up! */
1657         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1658         This->state = Req_Run;
1659         This->stop_playback = 0;
1660         ResetEvent(This->hEventStateChanged);
1661         SetEvent(This->thread_sleepy);
1662     }
1663
1664     return S_OK;
1665 }
1666
1667 HRESULT PullPin_PauseProcessing(PullPin * This)
1668 {
1669     /* if we are connected */
1670     TRACE("(%p)->()\n", This);
1671     if(This->pAlloc)
1672     {
1673         assert(This->hThread);
1674
1675         PullPin_WaitForStateChange(This, INFINITE);
1676
1677         EnterCriticalSection(This->pin.pCritSec);
1678
1679         assert(!This->stop_playback);
1680         assert(This->state == Req_Run|| This->state == Req_Sleepy);
1681
1682         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1683         This->state = Req_Pause;
1684         This->stop_playback = 1;
1685         ResetEvent(This->hEventStateChanged);
1686         SetEvent(This->thread_sleepy);
1687
1688         LeaveCriticalSection(This->pin.pCritSec);
1689     }
1690
1691     return S_OK;
1692 }
1693
1694 static HRESULT PullPin_StopProcessing(PullPin * This)
1695 {
1696     TRACE("(%p)->()\n", This);
1697
1698     /* if we are alive */
1699     assert(This->hThread);
1700
1701     PullPin_WaitForStateChange(This, INFINITE);
1702
1703     assert(This->state == Req_Pause || This->state == Req_Sleepy);
1704
1705     This->stop_playback = 1;
1706     This->state = Req_Die;
1707     assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1708     ResetEvent(This->hEventStateChanged);
1709     SetEvent(This->thread_sleepy);
1710     return S_OK;
1711 }
1712
1713 HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds)
1714 {
1715     if (WaitForSingleObject(This->hEventStateChanged, dwMilliseconds) == WAIT_TIMEOUT)
1716         return S_FALSE;
1717     return S_OK;
1718 }
1719
1720 HRESULT WINAPI PullPin_EndOfStream(IPin * iface)
1721 {
1722     FIXME("(%p)->() stub\n", iface);
1723
1724     return SendFurther( iface, deliver_endofstream, NULL, NULL );
1725 }
1726
1727 HRESULT WINAPI PullPin_BeginFlush(IPin * iface)
1728 {
1729     PullPin *This = (PullPin *)iface;
1730     TRACE("(%p)->()\n", This);
1731
1732     EnterCriticalSection(This->pin.pCritSec);
1733     {
1734         SendFurther( iface, deliver_beginflush, NULL, NULL );
1735     }
1736     LeaveCriticalSection(This->pin.pCritSec);
1737
1738     EnterCriticalSection(&This->thread_lock);
1739     {
1740         if (This->pReader)
1741             IAsyncReader_BeginFlush(This->pReader);
1742         PullPin_WaitForStateChange(This, INFINITE);
1743
1744         if (This->hThread && This->state == Req_Run)
1745         {
1746             PullPin_PauseProcessing(This);
1747             PullPin_WaitForStateChange(This, INFINITE);
1748         }
1749
1750         This->state = Req_Flush;
1751         ResetEvent(This->hEventStateChanged);
1752         SetEvent(This->thread_sleepy);
1753         PullPin_WaitForStateChange(This, INFINITE);
1754     }
1755     LeaveCriticalSection(&This->thread_lock);
1756
1757     EnterCriticalSection(This->pin.pCritSec);
1758     {
1759         This->fnCleanProc(This->pin.pUserData);
1760     }
1761     LeaveCriticalSection(This->pin.pCritSec);
1762
1763     return S_OK;
1764 }
1765
1766 HRESULT WINAPI PullPin_EndFlush(IPin * iface)
1767 {
1768     PullPin *This = (PullPin *)iface;
1769
1770     TRACE("(%p)->()\n", iface);
1771
1772     EnterCriticalSection(&This->thread_lock);
1773     {
1774         FILTER_STATE state;
1775         IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state);
1776
1777         if (This->stop_playback && state != State_Stopped)
1778             PullPin_StartProcessing(This);
1779
1780         PullPin_WaitForStateChange(This, INFINITE);
1781     }
1782     LeaveCriticalSection(&This->thread_lock);
1783
1784     EnterCriticalSection(This->pin.pCritSec);
1785     SendFurther( iface, deliver_endflush, NULL, NULL );
1786     LeaveCriticalSection(This->pin.pCritSec);
1787
1788     return S_OK;
1789 }
1790
1791 HRESULT WINAPI PullPin_Disconnect(IPin *iface)
1792 {
1793     HRESULT hr;
1794     PullPin *This = (PullPin *)iface;
1795
1796     TRACE("()\n");
1797
1798     EnterCriticalSection(This->pin.pCritSec);
1799     {
1800         if (FAILED(hr = IMemAllocator_Decommit(This->pAlloc)))
1801             ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr);
1802
1803         if (This->pin.pConnectedTo)
1804         {
1805             IPin_Release(This->pin.pConnectedTo);
1806             This->pin.pConnectedTo = NULL;
1807             PullPin_StopProcessing(This);
1808             hr = S_OK;
1809         }
1810         else
1811             hr = S_FALSE;
1812     }
1813     LeaveCriticalSection(This->pin.pCritSec);
1814
1815     return hr;
1816 }
1817
1818 HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1819 {
1820     newsegmentargs args;
1821     FIXME("(%p)->(%s, %s, %g) stub\n", iface, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate);
1822
1823     args.tStart = tStart;
1824     args.tStop = tStop;
1825     args.rate = dRate;
1826
1827     return SendFurther( iface, deliver_newsegment, &args, NULL );
1828 }
1829
1830 static const IPinVtbl PullPin_Vtbl = 
1831 {
1832     PullPin_QueryInterface,
1833     IPinImpl_AddRef,
1834     PullPin_Release,
1835     InputPin_Connect,
1836     PullPin_ReceiveConnection,
1837     PullPin_Disconnect,
1838     IPinImpl_ConnectedTo,
1839     IPinImpl_ConnectionMediaType,
1840     IPinImpl_QueryPinInfo,
1841     IPinImpl_QueryDirection,
1842     IPinImpl_QueryId,
1843     IPinImpl_QueryAccept,
1844     IPinImpl_EnumMediaTypes,
1845     IPinImpl_QueryInternalConnections,
1846     PullPin_EndOfStream,
1847     PullPin_BeginFlush,
1848     PullPin_EndFlush,
1849     PullPin_NewSegment
1850 };