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