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