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