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