quartz: Release objects when pins fail to connect.
[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-1))
38 #define ALIGNUP(value,boundary) (ALIGNDOWN(value - 1, boundary) + 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         IBaseFilter_Release(pinInfo.pFilter);
917     }
918     if (pMemConnected)
919         IMemInputPin_Release(pMemConnected);
920
921     return hr;
922 }
923
924 HRESULT OutputPin_DeliverNewSegment(OutputPin * This, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
925 {
926     HRESULT hr;
927
928     EnterCriticalSection(This->pin.pCritSec);
929     {
930         if (!This->pin.pConnectedTo)
931             hr = VFW_E_NOT_CONNECTED;
932         else
933             hr = IPin_NewSegment(This->pin.pConnectedTo, tStart, tStop, dRate);
934     }
935     LeaveCriticalSection(This->pin.pCritSec);
936     
937     return hr;
938 }
939
940 HRESULT OutputPin_CommitAllocator(OutputPin * This)
941 {
942     HRESULT hr;
943
944     TRACE("(%p)->()\n", This);
945
946     EnterCriticalSection(This->pin.pCritSec);
947     {
948         if (!This->pin.pConnectedTo || !This->pMemInputPin)
949             hr = VFW_E_NOT_CONNECTED;
950         else
951         {
952             IMemAllocator * pAlloc = NULL;
953
954             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
955
956             if (SUCCEEDED(hr))
957                 hr = IMemAllocator_Commit(pAlloc);
958
959             if (pAlloc)
960                 IMemAllocator_Release(pAlloc);
961         }
962     }
963     LeaveCriticalSection(This->pin.pCritSec);
964     
965     return hr;
966 }
967
968 HRESULT OutputPin_DeliverDisconnect(OutputPin * This)
969 {
970     HRESULT hr;
971
972     TRACE("(%p)->()\n", This);
973
974     EnterCriticalSection(This->pin.pCritSec);
975     {
976         if (!This->pin.pConnectedTo || !This->pMemInputPin)
977             hr = VFW_E_NOT_CONNECTED;
978         else
979         {
980             IMemAllocator * pAlloc = NULL;
981
982             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
983
984             if (SUCCEEDED(hr))
985                 hr = IMemAllocator_Decommit(pAlloc);
986
987             if (pAlloc)
988                 IMemAllocator_Release(pAlloc);
989
990             if (SUCCEEDED(hr))
991                 hr = IPin_Disconnect(This->pin.pConnectedTo);
992         }
993     }
994     LeaveCriticalSection(This->pin.pCritSec);
995
996     return hr;
997 }
998
999
1000 HRESULT PullPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
1001 {
1002     PullPin * pPinImpl;
1003
1004     *ppPin = NULL;
1005
1006     if (pPinInfo->dir != PINDIR_INPUT)
1007     {
1008         ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
1009         return E_INVALIDARG;
1010     }
1011
1012     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
1013
1014     if (!pPinImpl)
1015         return E_OUTOFMEMORY;
1016
1017     if (SUCCEEDED(PullPin_Init(pPinInfo, pSampleProc, pUserData, pQueryAccept, pCritSec, pPinImpl)))
1018     {
1019         pPinImpl->pin.lpVtbl = &PullPin_Vtbl;
1020         
1021         *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
1022         return S_OK;
1023     }
1024     return E_FAIL;
1025 }
1026
1027 HRESULT PullPin_Init(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, PullPin * pPinImpl)
1028 {
1029     /* Common attributes */
1030     pPinImpl->pin.refCount = 1;
1031     pPinImpl->pin.pConnectedTo = NULL;
1032     pPinImpl->pin.fnQueryAccept = pQueryAccept;
1033     pPinImpl->pin.pUserData = pUserData;
1034     pPinImpl->pin.pCritSec = pCritSec;
1035     Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
1036     ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
1037
1038     /* Input pin attributes */
1039     pPinImpl->fnSampleProc = pSampleProc;
1040     pPinImpl->fnPreConnect = NULL;
1041     pPinImpl->pAlloc = NULL;
1042     pPinImpl->pReader = NULL;
1043     pPinImpl->hThread = NULL;
1044     pPinImpl->hEventStateChanged = CreateEventW(NULL, FALSE, TRUE, NULL);
1045
1046     pPinImpl->rtStart = 0;
1047     pPinImpl->rtStop = ((LONGLONG)0x7fffffff << 32) | 0xffffffff;
1048
1049     return S_OK;
1050 }
1051
1052 HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
1053 {
1054     PIN_DIRECTION pindirReceive;
1055     HRESULT hr = S_OK;
1056     PullPin *This = (PullPin *)iface;
1057
1058     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
1059     dump_AM_MEDIA_TYPE(pmt);
1060
1061     EnterCriticalSection(This->pin.pCritSec);
1062     {
1063         if (This->pin.pConnectedTo)
1064             hr = VFW_E_ALREADY_CONNECTED;
1065
1066         if (SUCCEEDED(hr) && (This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK))
1067             hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto 
1068                                            * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
1069
1070         if (SUCCEEDED(hr))
1071         {
1072             IPin_QueryDirection(pReceivePin, &pindirReceive);
1073
1074             if (pindirReceive != PINDIR_OUTPUT)
1075             {
1076                 ERR("Can't connect from non-output pin\n");
1077                 hr = VFW_E_INVALID_DIRECTION;
1078             }
1079         }
1080
1081         This->pReader = NULL;
1082         This->pAlloc = NULL;
1083         if (SUCCEEDED(hr))
1084         {
1085             hr = IPin_QueryInterface(pReceivePin, &IID_IAsyncReader, (LPVOID *)&This->pReader);
1086         }
1087
1088         if (SUCCEEDED(hr))
1089         {
1090             ALLOCATOR_PROPERTIES props;
1091             props.cBuffers = 3;
1092             props.cbBuffer = 64 * 1024; /* 64k bytes */
1093             props.cbAlign = 1;
1094             props.cbPrefix = 0;
1095             hr = IAsyncReader_RequestAllocator(This->pReader, NULL, &props, &This->pAlloc);
1096         }
1097
1098         if (SUCCEEDED(hr) && This->fnPreConnect)
1099         {
1100             hr = This->fnPreConnect(iface, pReceivePin);
1101         }
1102
1103         if (SUCCEEDED(hr))
1104         {
1105             CopyMediaType(&This->pin.mtCurrent, pmt);
1106             This->pin.pConnectedTo = pReceivePin;
1107             IPin_AddRef(pReceivePin);
1108         }
1109         else
1110         {
1111              if (This->pReader)
1112                  IAsyncReader_Release(This->pReader);
1113              This->pReader = NULL;
1114              if (This->pAlloc)
1115                  IMemAllocator_Release(This->pAlloc);
1116              This->pAlloc = NULL;
1117         }
1118     }
1119     LeaveCriticalSection(This->pin.pCritSec);
1120     return hr;
1121 }
1122
1123 HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
1124 {
1125     PullPin *This = (PullPin *)iface;
1126
1127     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
1128
1129     *ppv = NULL;
1130
1131     if (IsEqualIID(riid, &IID_IUnknown))
1132         *ppv = (LPVOID)iface;
1133     else if (IsEqualIID(riid, &IID_IPin))
1134         *ppv = (LPVOID)iface;
1135
1136     if (*ppv)
1137     {
1138         IUnknown_AddRef((IUnknown *)(*ppv));
1139         return S_OK;
1140     }
1141
1142     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
1143
1144     return E_NOINTERFACE;
1145 }
1146
1147 ULONG WINAPI PullPin_Release(IPin * iface)
1148 {
1149     PullPin *This = (PullPin *)iface;
1150     ULONG refCount = InterlockedDecrement(&This->pin.refCount);
1151
1152     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
1153
1154     if (!refCount)
1155     {
1156         if (This->hThread)
1157             PullPin_StopProcessing(This);
1158         if(This->pAlloc)
1159             IMemAllocator_Release(This->pAlloc);
1160         if(This->pReader)
1161             IAsyncReader_Release(This->pReader);
1162         CloseHandle(This->hEventStateChanged);
1163         CoTaskMemFree(This);
1164         return 0;
1165     }
1166     return refCount;
1167 }
1168
1169 static DWORD WINAPI PullPin_Thread_Main(LPVOID pv)
1170 {
1171     for (;;)
1172         SleepEx(INFINITE, TRUE);
1173 }
1174
1175 static void CALLBACK PullPin_Thread_Process(ULONG_PTR iface)
1176 {
1177     PullPin *This = (PullPin *)iface;
1178     HRESULT hr;
1179
1180     REFERENCE_TIME rtCurrent;
1181     ALLOCATOR_PROPERTIES allocProps;
1182     PIN_INFO pinInfo;
1183
1184     CoInitializeEx(NULL, COINIT_MULTITHREADED);
1185     
1186     SetEvent(This->hEventStateChanged);
1187
1188     hr = IMemAllocator_GetProperties(This->pAlloc, &allocProps);
1189
1190     rtCurrent = MEDIATIME_FROM_BYTES(ALIGNDOWN(BYTES_FROM_MEDIATIME(This->rtStart), allocProps.cbAlign));
1191
1192     TRACE("Start\n");
1193
1194     while (rtCurrent < This->rtStop && hr == S_OK)
1195     {
1196         /* FIXME: to improve performance by quite a bit this should be changed
1197          * so that one sample is processed while one sample is fetched. However,
1198          * it is harder to debug so for the moment it will stay as it is */
1199         IMediaSample * pSample = NULL;
1200         REFERENCE_TIME rtSampleStop;
1201         DWORD_PTR dwUser;
1202
1203         pinInfo.pFilter = NULL;
1204
1205         TRACE("Process sample\n");
1206
1207         hr = IMemAllocator_GetBuffer(This->pAlloc, &pSample, NULL, NULL, 0);
1208
1209         if (SUCCEEDED(hr))
1210         {
1211             rtSampleStop = rtCurrent + MEDIATIME_FROM_BYTES(IMediaSample_GetSize(pSample));
1212             if (rtSampleStop > This->rtStop)
1213                 rtSampleStop = MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(This->rtStop), allocProps.cbAlign));
1214             hr = IMediaSample_SetTime(pSample, &rtCurrent, &rtSampleStop);
1215             rtCurrent = rtSampleStop;
1216         }
1217
1218         if (SUCCEEDED(hr))
1219             hr = IAsyncReader_Request(This->pReader, pSample, (ULONG_PTR)0);
1220
1221         if (SUCCEEDED(hr))
1222             hr = IAsyncReader_WaitForNext(This->pReader, 10000, &pSample, &dwUser);
1223
1224         if (SUCCEEDED(hr))
1225             hr = IPin_QueryPinInfo((IPin*)&This->pin, &pinInfo);
1226
1227         if (SUCCEEDED(hr))
1228             hr = This->fnSampleProc(This->pin.pUserData, pSample);
1229         else
1230             ERR("Processing error: %x\n", hr);
1231
1232         if (pinInfo.pFilter)
1233             IBaseFilter_Release(pinInfo.pFilter);
1234         if (pSample)
1235             IMediaSample_Release(pSample);
1236     }
1237
1238     CoUninitialize();
1239
1240     TRACE("End\n");
1241 }
1242
1243 static void CALLBACK PullPin_Thread_Stop(ULONG_PTR iface)
1244 {
1245     PullPin *This = (PullPin *)iface;
1246
1247     TRACE("(%p/%p)->()\n", This, (LPVOID)iface);
1248
1249     EnterCriticalSection(This->pin.pCritSec);
1250     {
1251         HRESULT hr;
1252
1253         CloseHandle(This->hThread);
1254         This->hThread = NULL;
1255         if (FAILED(hr = IMemAllocator_Decommit(This->pAlloc)))
1256             ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr);
1257     }
1258     LeaveCriticalSection(This->pin.pCritSec);
1259
1260     SetEvent(This->hEventStateChanged);
1261
1262     ExitThread(0);
1263 }
1264
1265 HRESULT PullPin_InitProcessing(PullPin * This)
1266 {
1267     HRESULT hr = S_OK;
1268
1269     TRACE("(%p)->()\n", This);
1270
1271     assert(!This->hThread);
1272
1273     /* if we are connected */
1274     if (This->pAlloc)
1275     {
1276         EnterCriticalSection(This->pin.pCritSec);
1277         {
1278             DWORD dwThreadId;
1279             assert(!This->hThread);
1280         
1281             This->hThread = CreateThread(NULL, 0, PullPin_Thread_Main, NULL, 0, &dwThreadId);
1282             if (!This->hThread)
1283                 hr = HRESULT_FROM_WIN32(GetLastError());
1284
1285             if (SUCCEEDED(hr))
1286                 hr = IMemAllocator_Commit(This->pAlloc);
1287         }
1288         LeaveCriticalSection(This->pin.pCritSec);
1289     }
1290
1291     TRACE(" -- %x\n", hr);
1292
1293     return hr;
1294 }
1295
1296 HRESULT PullPin_StartProcessing(PullPin * This)
1297 {
1298     /* if we are connected */
1299     TRACE("(%p)->()\n", This);
1300     if(This->pAlloc)
1301     {
1302         assert(This->hThread);
1303         
1304         ResetEvent(This->hEventStateChanged);
1305         
1306         if (!QueueUserAPC(PullPin_Thread_Process, This->hThread, (ULONG_PTR)This))
1307             return HRESULT_FROM_WIN32(GetLastError());
1308     }
1309
1310     return S_OK;
1311 }
1312
1313 HRESULT PullPin_PauseProcessing(PullPin * This)
1314 {
1315     /* make the processing function exit its loop */
1316     This->rtStop = 0;
1317
1318     return S_OK;
1319 }
1320
1321 HRESULT PullPin_StopProcessing(PullPin * This)
1322 {
1323     /* if we are connected */
1324     if (This->pAlloc)
1325     {
1326         assert(This->hThread);
1327
1328         ResetEvent(This->hEventStateChanged);
1329
1330         PullPin_PauseProcessing(This);
1331
1332         if (!QueueUserAPC(PullPin_Thread_Stop, This->hThread, (ULONG_PTR)This))
1333             return HRESULT_FROM_WIN32(GetLastError());
1334     }
1335
1336     return S_OK;
1337 }
1338
1339 HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds)
1340 {
1341     if (WaitForSingleObject(This->hEventStateChanged, dwMilliseconds) == WAIT_TIMEOUT)
1342         return S_FALSE;
1343     return S_OK;
1344 }
1345
1346 HRESULT PullPin_Seek(PullPin * This, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop)
1347 {
1348     FIXME("(%p)->(%x%08x, %x%08x)\n", This, (LONG)(rtStart >> 32), (LONG)rtStart, (LONG)(rtStop >> 32), (LONG)rtStop);
1349
1350     PullPin_BeginFlush((IPin *)This);
1351     /* FIXME: need critical section? */
1352     This->rtStart = rtStart;
1353     This->rtStop = rtStop;
1354     PullPin_EndFlush((IPin *)This);
1355
1356     return S_OK;
1357 }
1358
1359 HRESULT WINAPI PullPin_EndOfStream(IPin * iface)
1360 {
1361     FIXME("(%p)->()\n", iface);
1362     return E_NOTIMPL;
1363 }
1364
1365 HRESULT WINAPI PullPin_BeginFlush(IPin * iface)
1366 {
1367     FIXME("(%p)->()\n", iface);
1368     return E_NOTIMPL;
1369 }
1370
1371 HRESULT WINAPI PullPin_EndFlush(IPin * iface)
1372 {
1373     FIXME("(%p)->()\n", iface);
1374     return E_NOTIMPL;
1375 }
1376
1377 HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1378 {
1379     FIXME("(%p)->(%s, %s, %g)\n", iface, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate);
1380     return E_NOTIMPL;
1381 }
1382
1383 static const IPinVtbl PullPin_Vtbl = 
1384 {
1385     PullPin_QueryInterface,
1386     IPinImpl_AddRef,
1387     PullPin_Release,
1388     OutputPin_Connect,
1389     PullPin_ReceiveConnection,
1390     IPinImpl_Disconnect,
1391     IPinImpl_ConnectedTo,
1392     IPinImpl_ConnectionMediaType,
1393     IPinImpl_QueryPinInfo,
1394     IPinImpl_QueryDirection,
1395     IPinImpl_QueryId,
1396     IPinImpl_QueryAccept,
1397     IPinImpl_EnumMediaTypes,
1398     IPinImpl_QueryInternalConnections,
1399     PullPin_EndOfStream,
1400     PullPin_BeginFlush,
1401     PullPin_EndFlush,
1402     PullPin_NewSegment
1403 };