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