Declaration, implemention and test for BuildTrusteeWithSid.
[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     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     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
495     InputPin_QueryInterface,
496     IPinImpl_AddRef,
497     InputPin_Release,
498     InputPin_Connect,
499     InputPin_ReceiveConnection,
500     IPinImpl_Disconnect,
501     IPinImpl_ConnectedTo,
502     IPinImpl_ConnectionMediaType,
503     IPinImpl_QueryPinInfo,
504     IPinImpl_QueryDirection,
505     IPinImpl_QueryId,
506     IPinImpl_QueryAccept,
507     IPinImpl_EnumMediaTypes,
508     IPinImpl_QueryInternalConnections,
509     InputPin_EndOfStream,
510     InputPin_BeginFlush,
511     InputPin_EndFlush,
512     InputPin_NewSegment
513 };
514
515 /*** IMemInputPin implementation ***/
516
517 HRESULT WINAPI MemInputPin_QueryInterface(IMemInputPin * iface, REFIID riid, LPVOID * ppv)
518 {
519     ICOM_THIS_From_IMemInputPin(InputPin, iface);
520
521     return IPin_QueryInterface((IPin *)&This->pin, riid, ppv);
522 }
523
524 ULONG WINAPI MemInputPin_AddRef(IMemInputPin * iface)
525 {
526     ICOM_THIS_From_IMemInputPin(InputPin, iface);
527
528     return IPin_AddRef((IPin *)&This->pin);
529 }
530
531 ULONG WINAPI MemInputPin_Release(IMemInputPin * iface)
532 {
533     ICOM_THIS_From_IMemInputPin(InputPin, iface);
534
535     return IPin_Release((IPin *)&This->pin);
536 }
537
538 HRESULT WINAPI MemInputPin_GetAllocator(IMemInputPin * iface, IMemAllocator ** ppAllocator)
539 {
540     ICOM_THIS_From_IMemInputPin(InputPin, iface);
541
542     TRACE("(%p/%p)->(%p)\n", This, iface, ppAllocator);
543
544     *ppAllocator = This->pAllocator;
545     if (*ppAllocator)
546         IMemAllocator_AddRef(*ppAllocator);
547     
548     return *ppAllocator ? S_OK : VFW_E_NO_ALLOCATOR;
549 }
550
551 HRESULT WINAPI MemInputPin_NotifyAllocator(IMemInputPin * iface, IMemAllocator * pAllocator, BOOL bReadOnly)
552 {
553     ICOM_THIS_From_IMemInputPin(InputPin, iface);
554
555     TRACE("(%p/%p)->(%p, %d)\n", This, iface, pAllocator, bReadOnly);
556
557     if (This->pAllocator)
558         IMemAllocator_Release(This->pAllocator);
559     This->pAllocator = pAllocator;
560     if (This->pAllocator)
561         IMemAllocator_AddRef(This->pAllocator);
562
563     return S_OK;
564 }
565
566 HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin * iface, ALLOCATOR_PROPERTIES * pProps)
567 {
568     ICOM_THIS_From_IMemInputPin(InputPin, iface);
569
570     TRACE("(%p/%p)->(%p)\n", This, iface, pProps);
571
572     /* override this method if you have any specific requirements */
573
574     return E_NOTIMPL;
575 }
576
577 HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample)
578 {
579     ICOM_THIS_From_IMemInputPin(InputPin, iface);
580
581     /* this trace commented out for performance reasons */
582     /*TRACE("(%p/%p)->(%p)\n", This, iface, pSample);*/
583
584     return This->fnSampleProc(This->pin.pUserData, pSample);
585 }
586
587 HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, long nSamples, long *nSamplesProcessed)
588 {
589     HRESULT hr = S_OK;
590     ICOM_THIS_From_IMemInputPin(InputPin, iface);
591
592     TRACE("(%p/%p)->(%p, %ld, %p)\n", This, iface, pSamples, nSamples, nSamplesProcessed);
593
594     for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; (*nSamplesProcessed)++)
595     {
596         hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
597         if (hr != S_OK)
598             break;
599     }
600
601     return hr;
602 }
603
604 HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface)
605 {
606     ICOM_THIS_From_IMemInputPin(InputPin, iface);
607
608     FIXME("(%p/%p)->()\n", This, iface);
609
610     /* FIXME: we should check whether any output pins will block */
611
612     return S_OK;
613 }
614
615 static const IMemInputPinVtbl MemInputPin_Vtbl = 
616 {
617     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
618     MemInputPin_QueryInterface,
619     MemInputPin_AddRef,
620     MemInputPin_Release,
621     MemInputPin_GetAllocator,
622     MemInputPin_NotifyAllocator,
623     MemInputPin_GetAllocatorRequirements,
624     MemInputPin_Receive,
625     MemInputPin_ReceiveMultiple,
626     MemInputPin_ReceiveCanBlock
627 };
628
629 HRESULT WINAPI OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
630 {
631     ICOM_THIS(OutputPin, iface);
632
633     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
634
635     *ppv = NULL;
636
637     if (IsEqualIID(riid, &IID_IUnknown))
638         *ppv = (LPVOID)iface;
639     else if (IsEqualIID(riid, &IID_IPin))
640         *ppv = (LPVOID)iface;
641
642     if (*ppv)
643     {
644         IUnknown_AddRef((IUnknown *)(*ppv));
645         return S_OK;
646     }
647
648     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
649
650     return E_NOINTERFACE;
651 }
652
653 ULONG WINAPI OutputPin_Release(IPin * iface)
654 {
655     ICOM_THIS(OutputPin, iface);
656     
657     TRACE("(%p/%p)->()\n", This, iface);
658     
659     if (!InterlockedDecrement(&This->pin.refCount))
660     {
661         DeleteMediaType(&This->pin.mtCurrent);
662         CoTaskMemFree(This);
663         return 0;
664     }
665     return This->pin.refCount;
666 }
667
668 HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
669 {
670     HRESULT hr;
671     ICOM_THIS(OutputPin, iface);
672
673     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
674     dump_AM_MEDIA_TYPE(pmt);
675
676     /* If we try to connect to ourself, we will definitely deadlock.
677      * There are other cases where we could deadlock too, but this
678      * catches the obvious case */
679     assert(pReceivePin != iface);
680
681     EnterCriticalSection(This->pin.pCritSec);
682     {
683         /* if we have been a specific type to connect with, then we can either connect
684          * with that or fail. We cannot choose different AM_MEDIA_TYPE */
685         if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
686             hr = This->pConnectSpecific(iface, pReceivePin, pmt);
687         else
688         {
689             /* negotiate media type */
690
691             IEnumMediaTypes * pEnumCandidates;
692             AM_MEDIA_TYPE * pmtCandidate; /* Candidate media type */
693
694             if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates)))
695             {
696                 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
697
698                 /* try this filter's media types first */
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                 }
710                 IEnumMediaTypes_Release(pEnumCandidates);
711             }
712
713             /* then try receiver filter's media types */
714             if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */
715             {
716                 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
717
718                 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
719                 {
720                     if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && 
721                         (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
722                     {
723                         hr = S_OK;
724                         CoTaskMemFree(pmtCandidate);
725                         break;
726                     }
727                     CoTaskMemFree(pmtCandidate);
728                 } /* while */
729                 IEnumMediaTypes_Release(pEnumCandidates);
730             } /* if not found */
731         } /* if negotiate media type */
732     } /* if succeeded */
733     LeaveCriticalSection(This->pin.pCritSec);
734
735     FIXME(" -- %lx\n", hr);
736     return hr;
737 }
738
739 HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
740 {
741     ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin, pmt);
742
743     return E_UNEXPECTED;
744 }
745
746 HRESULT WINAPI OutputPin_Disconnect(IPin * iface)
747 {
748     HRESULT hr;
749     ICOM_THIS(OutputPin, iface);
750
751     TRACE("()\n");
752
753     EnterCriticalSection(This->pin.pCritSec);
754     {
755         if (This->pMemInputPin)
756         {
757             IMemInputPin_Release(This->pMemInputPin);
758             This->pMemInputPin = NULL;
759         }
760         if (This->pin.pConnectedTo)
761         {
762             IPin_Release(This->pin.pConnectedTo);
763             This->pin.pConnectedTo = NULL;
764             hr = S_OK;
765         }
766         else
767             hr = S_FALSE;
768     }
769     LeaveCriticalSection(This->pin.pCritSec);
770     
771     return hr;
772 }
773
774 HRESULT WINAPI OutputPin_EndOfStream(IPin * iface)
775 {
776     TRACE("()\n");
777
778     /* not supposed to do anything in an output pin */
779
780     return E_UNEXPECTED;
781 }
782
783 HRESULT WINAPI OutputPin_BeginFlush(IPin * iface)
784 {
785     TRACE("(%p)->()\n", iface);
786
787     /* not supposed to do anything in an output pin */
788
789     return E_UNEXPECTED;
790 }
791
792 HRESULT WINAPI OutputPin_EndFlush(IPin * iface)
793 {
794     TRACE("(%p)->()\n", iface);
795
796     /* not supposed to do anything in an output pin */
797
798     return E_UNEXPECTED;
799 }
800
801 HRESULT WINAPI OutputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
802 {
803     TRACE("(%p)->(%lx%08lx, %lx%08lx, %e)\n", iface, (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate);
804
805     /* not supposed to do anything in an output pin */
806
807     return E_UNEXPECTED;
808 }
809
810 static const IPinVtbl OutputPin_Vtbl = 
811 {
812     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
813     OutputPin_QueryInterface,
814     IPinImpl_AddRef,
815     OutputPin_Release,
816     OutputPin_Connect,
817     OutputPin_ReceiveConnection,
818     OutputPin_Disconnect,
819     IPinImpl_ConnectedTo,
820     IPinImpl_ConnectionMediaType,
821     IPinImpl_QueryPinInfo,
822     IPinImpl_QueryDirection,
823     IPinImpl_QueryId,
824     IPinImpl_QueryAccept,
825     IPinImpl_EnumMediaTypes,
826     IPinImpl_QueryInternalConnections,
827     OutputPin_EndOfStream,
828     OutputPin_BeginFlush,
829     OutputPin_EndFlush,
830     OutputPin_NewSegment
831 };
832
833 HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, const REFERENCE_TIME * tStart, const REFERENCE_TIME * tStop, DWORD dwFlags)
834 {
835     HRESULT hr;
836
837     TRACE("(%p, %p, %p, %lx)\n", ppSample, tStart, tStop, dwFlags);
838
839     EnterCriticalSection(This->pin.pCritSec);
840     {
841         if (!This->pin.pConnectedTo)
842             hr = VFW_E_NOT_CONNECTED;
843         else
844         {
845             IMemInputPin * pMemInputPin = NULL;
846             IMemAllocator * pAlloc = NULL;
847             
848             /* FIXME: should we cache this? */
849             hr = IPin_QueryInterface(This->pin.pConnectedTo, &IID_IMemInputPin, (LPVOID *)&pMemInputPin);
850
851             if (SUCCEEDED(hr))
852                 hr = IMemInputPin_GetAllocator(pMemInputPin, &pAlloc);
853
854             if (SUCCEEDED(hr))
855                 hr = IMemAllocator_GetBuffer(pAlloc, ppSample, (REFERENCE_TIME *)tStart, (REFERENCE_TIME *)tStop, dwFlags);
856
857             if (SUCCEEDED(hr))
858                 hr = IMediaSample_SetTime(*ppSample, (REFERENCE_TIME *)tStart, (REFERENCE_TIME *)tStop);
859
860             if (pAlloc)
861                 IMemAllocator_Release(pAlloc);
862             if (pMemInputPin)
863                 IMemInputPin_Release(pMemInputPin);
864         }
865     }
866     LeaveCriticalSection(This->pin.pCritSec);
867     
868     return hr;
869 }
870
871 HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample)
872 {
873     HRESULT hr;
874     IMemInputPin * pMemConnected = NULL;
875
876     EnterCriticalSection(This->pin.pCritSec);
877     {
878         if (!This->pin.pConnectedTo)
879             hr = VFW_E_NOT_CONNECTED;
880         else
881         {
882             /* FIXME: should we cache this? - if we do, then we need to keep the local version
883              * and AddRef here instead */
884             hr = IPin_QueryInterface(This->pin.pConnectedTo, &IID_IMemInputPin, (LPVOID *)&pMemConnected);
885         }
886     }
887     LeaveCriticalSection(This->pin.pCritSec);
888
889     if (SUCCEEDED(hr) && pMemConnected)
890     {
891         /* NOTE: if we are in a critical section when Receive is called
892          * then it causes some problems (most notably with the native Video
893          * Renderer) if we are re-entered for whatever reason */
894         hr = IMemInputPin_Receive(pMemConnected, pSample);
895         IMemInputPin_Release(pMemConnected);
896     }
897     
898     return hr;
899 }
900
901 HRESULT OutputPin_DeliverNewSegment(OutputPin * This, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
902 {
903     HRESULT hr;
904
905     EnterCriticalSection(This->pin.pCritSec);
906     {
907         if (!This->pin.pConnectedTo)
908             hr = VFW_E_NOT_CONNECTED;
909         else
910             hr = IPin_NewSegment(This->pin.pConnectedTo, tStart, tStop, dRate);
911     }
912     LeaveCriticalSection(This->pin.pCritSec);
913     
914     return hr;
915 }
916
917 HRESULT OutputPin_CommitAllocator(OutputPin * This)
918 {
919     HRESULT hr;
920
921     TRACE("(%p)->()\n", This);
922
923     EnterCriticalSection(This->pin.pCritSec);
924     {
925         if (!This->pin.pConnectedTo)
926             hr = VFW_E_NOT_CONNECTED;
927         else
928         {
929             IMemInputPin * pMemInputPin = NULL;
930             IMemAllocator * pAlloc = NULL;
931             /* FIXME: should we cache this? */
932             hr = IPin_QueryInterface(This->pin.pConnectedTo, &IID_IMemInputPin, (LPVOID *)&pMemInputPin);
933
934             if (SUCCEEDED(hr))
935                 hr = IMemInputPin_GetAllocator(pMemInputPin, &pAlloc);
936
937             if (SUCCEEDED(hr))
938                 hr = IMemAllocator_Commit(pAlloc);
939
940             if (pAlloc)
941                 IMemAllocator_Release(pAlloc);
942
943             if (pMemInputPin)
944                 IMemInputPin_Release(pMemInputPin);
945         }
946     }
947     LeaveCriticalSection(This->pin.pCritSec);
948     
949     return hr;
950 }
951
952 HRESULT OutputPin_DeliverDisconnect(OutputPin * This)
953 {
954     HRESULT hr;
955
956     TRACE("(%p)->()\n", This);
957
958     EnterCriticalSection(This->pin.pCritSec);
959     {
960         if (!This->pin.pConnectedTo)
961             hr = VFW_E_NOT_CONNECTED;
962         else
963         {
964             IMemInputPin * pMemInputPin = NULL;
965             IMemAllocator * pAlloc = NULL;
966             /* FIXME: should we cache this? */
967             hr = IPin_QueryInterface(This->pin.pConnectedTo, &IID_IMemInputPin, (LPVOID *)&pMemInputPin);
968
969             if (SUCCEEDED(hr))
970                 hr = IMemInputPin_GetAllocator(pMemInputPin, &pAlloc);
971
972             if (SUCCEEDED(hr))
973                 hr = IMemAllocator_Decommit(pAlloc);
974
975             if (pAlloc)
976                 IMemAllocator_Release(pAlloc);
977
978             if (pMemInputPin)
979                 IMemInputPin_Release(pMemInputPin);
980
981             if (SUCCEEDED(hr))
982                 hr = IPin_Disconnect(This->pin.pConnectedTo);
983         }
984     }
985     LeaveCriticalSection(This->pin.pCritSec);
986
987     return hr;
988 }
989
990
991 HRESULT PullPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
992 {
993     PullPin * pPinImpl;
994
995     *ppPin = NULL;
996
997     if (pPinInfo->dir != PINDIR_INPUT)
998     {
999         ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
1000         return E_INVALIDARG;
1001     }
1002
1003     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
1004
1005     if (!pPinImpl)
1006         return E_OUTOFMEMORY;
1007
1008     if (SUCCEEDED(PullPin_Init(pPinInfo, pSampleProc, pUserData, pQueryAccept, pCritSec, pPinImpl)))
1009     {
1010         pPinImpl->pin.lpVtbl = &PullPin_Vtbl;
1011         
1012         *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
1013         return S_OK;
1014     }
1015     return E_FAIL;
1016 }
1017
1018 HRESULT PullPin_Init(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, PullPin * pPinImpl)
1019 {
1020     /* Common attributes */
1021     pPinImpl->pin.refCount = 1;
1022     pPinImpl->pin.pConnectedTo = NULL;
1023     pPinImpl->pin.fnQueryAccept = pQueryAccept;
1024     pPinImpl->pin.pUserData = pUserData;
1025     pPinImpl->pin.pCritSec = pCritSec;
1026     Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
1027
1028     /* Input pin attributes */
1029     pPinImpl->fnSampleProc = pSampleProc;
1030     pPinImpl->fnPreConnect = NULL;
1031     pPinImpl->pAlloc = NULL;
1032     pPinImpl->pReader = NULL;
1033     pPinImpl->hThread = NULL;
1034     pPinImpl->hEventStateChanged = CreateEventW(NULL, FALSE, TRUE, NULL);
1035
1036     pPinImpl->rtStart = 0;
1037     pPinImpl->rtStop = ((LONGLONG)0x7fffffff << 32) | 0xffffffff;
1038
1039     return S_OK;
1040 }
1041
1042 HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
1043 {
1044     PIN_DIRECTION pindirReceive;
1045     HRESULT hr = S_OK;
1046     ICOM_THIS(PullPin, iface);
1047
1048     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
1049     dump_AM_MEDIA_TYPE(pmt);
1050
1051     EnterCriticalSection(This->pin.pCritSec);
1052     {
1053         if (This->pin.pConnectedTo)
1054             hr = VFW_E_ALREADY_CONNECTED;
1055
1056         if (SUCCEEDED(hr) && (This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK))
1057             hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto 
1058                                            * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
1059
1060         if (SUCCEEDED(hr))
1061         {
1062             IPin_QueryDirection(pReceivePin, &pindirReceive);
1063
1064             if (pindirReceive != PINDIR_OUTPUT)
1065             {
1066                 ERR("Can't connect from non-output pin\n");
1067                 hr = VFW_E_INVALID_DIRECTION;
1068             }
1069         }
1070
1071         if (SUCCEEDED(hr))
1072         {
1073             hr = IPin_QueryInterface(pReceivePin, &IID_IAsyncReader, (LPVOID *)&This->pReader);
1074         }
1075
1076         if (SUCCEEDED(hr))
1077         {
1078             ALLOCATOR_PROPERTIES props;
1079             props.cBuffers = 3;
1080             props.cbBuffer = 64 * 1024; /* 64k bytes */
1081             props.cbAlign = 1;
1082             props.cbPrefix = 0;
1083             hr = IAsyncReader_RequestAllocator(This->pReader, NULL, &props, &This->pAlloc);
1084         }
1085
1086         if (SUCCEEDED(hr) && This->fnPreConnect)
1087         {
1088             hr = This->fnPreConnect(iface, pReceivePin);
1089         }
1090
1091         if (SUCCEEDED(hr))
1092         {
1093             CopyMediaType(&This->pin.mtCurrent, pmt);
1094             This->pin.pConnectedTo = pReceivePin;
1095             IPin_AddRef(pReceivePin);
1096         }
1097     }
1098     LeaveCriticalSection(This->pin.pCritSec);
1099     return hr;
1100 }
1101
1102 HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
1103 {
1104     ICOM_THIS(PullPin, iface);
1105
1106     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
1107
1108     *ppv = NULL;
1109
1110     if (IsEqualIID(riid, &IID_IUnknown))
1111         *ppv = (LPVOID)iface;
1112     else if (IsEqualIID(riid, &IID_IPin))
1113         *ppv = (LPVOID)iface;
1114
1115     if (*ppv)
1116     {
1117         IUnknown_AddRef((IUnknown *)(*ppv));
1118         return S_OK;
1119     }
1120
1121     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
1122
1123     return E_NOINTERFACE;
1124 }
1125
1126 ULONG WINAPI PullPin_Release(IPin * iface)
1127 {
1128     ICOM_THIS(PullPin, iface);
1129
1130     TRACE("(%p/%p)->()\n", This, iface);
1131
1132     if (!InterlockedDecrement(&This->pin.refCount))
1133     {
1134         if (This->hThread)
1135             PullPin_StopProcessing(This);
1136         IMemAllocator_Release(This->pAlloc);
1137         IAsyncReader_Release(This->pReader);
1138         CloseHandle(This->hEventStateChanged);
1139         CoTaskMemFree(This);
1140         return 0;
1141     }
1142     return This->pin.refCount;
1143 }
1144
1145 static DWORD WINAPI PullPin_Thread_Main(LPVOID pv)
1146 {
1147     for (;;)
1148         SleepEx(INFINITE, TRUE);
1149 }
1150
1151 static void CALLBACK PullPin_Thread_Process(ULONG_PTR iface)
1152 {
1153     ICOM_THIS(PullPin, iface);
1154     HRESULT hr;
1155
1156     REFERENCE_TIME rtCurrent;
1157     ALLOCATOR_PROPERTIES allocProps;
1158
1159     SetEvent(This->hEventStateChanged);
1160
1161     hr = IMemAllocator_GetProperties(This->pAlloc, &allocProps);
1162
1163     rtCurrent = MEDIATIME_FROM_BYTES(ALIGNDOWN(BYTES_FROM_MEDIATIME(This->rtStart), allocProps.cbAlign));
1164
1165     while (rtCurrent < This->rtStop)
1166     {
1167         /* FIXME: to improve performance by quite a bit this should be changed
1168          * so that one sample is processed while one sample is fetched. However,
1169          * it is harder to debug so for the moment it will stay as it is */
1170         IMediaSample * pSample = NULL;
1171         REFERENCE_TIME rtSampleStop;
1172         DWORD dwUser;
1173
1174         hr = IMemAllocator_GetBuffer(This->pAlloc, &pSample, NULL, NULL, 0);
1175
1176         if (SUCCEEDED(hr))
1177         {
1178             rtSampleStop = rtCurrent + MEDIATIME_FROM_BYTES(IMediaSample_GetSize(pSample));
1179             if (rtSampleStop > This->rtStop)
1180                 rtSampleStop = MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(This->rtStop), allocProps.cbAlign));
1181             hr = IMediaSample_SetTime(pSample, &rtCurrent, &rtSampleStop);
1182             rtCurrent = rtSampleStop;
1183         }
1184
1185         if (SUCCEEDED(hr))
1186             hr = IAsyncReader_Request(This->pReader, pSample, (ULONG_PTR)0);
1187
1188         if (SUCCEEDED(hr))
1189             hr = IAsyncReader_WaitForNext(This->pReader, 10000, &pSample, &dwUser);
1190
1191         if (SUCCEEDED(hr))
1192             hr = This->fnSampleProc(This->pin.pUserData, pSample);
1193         else
1194             ERR("Processing error: %lx\n", hr);
1195         
1196         if (pSample)
1197             IMediaSample_Release(pSample);
1198     }
1199 }
1200
1201 static void CALLBACK PullPin_Thread_Stop(ULONG_PTR iface)
1202 {
1203     ICOM_THIS(PullPin, iface);
1204
1205     TRACE("(%p/%p)->()\n", This, (LPVOID)iface);
1206
1207     EnterCriticalSection(This->pin.pCritSec);
1208     {
1209         HRESULT hr;
1210
1211         CloseHandle(This->hThread);
1212         This->hThread = NULL;
1213         if (FAILED(hr = IMemAllocator_Decommit(This->pAlloc)))
1214             ERR("Allocator decommit failed with error %lx. Possible memory leak\n", hr);
1215     }
1216     LeaveCriticalSection(This->pin.pCritSec);
1217
1218     SetEvent(This->hEventStateChanged);
1219
1220     ExitThread(0);
1221 }
1222
1223 HRESULT PullPin_InitProcessing(PullPin * This)
1224 {
1225     HRESULT hr = S_OK;
1226
1227     TRACE("(%p)->()\n", This);
1228
1229     assert(!This->hThread);
1230
1231     /* if we are connected */
1232     if (This->pAlloc)
1233     {
1234         EnterCriticalSection(This->pin.pCritSec);
1235         {
1236             DWORD dwThreadId;
1237             assert(!This->hThread);
1238         
1239             This->hThread = CreateThread(NULL, 0, PullPin_Thread_Main, NULL, 0, &dwThreadId);
1240             if (!This->hThread)
1241                 hr = HRESULT_FROM_WIN32(GetLastError());
1242
1243             if (SUCCEEDED(hr))
1244                 hr = IMemAllocator_Commit(This->pAlloc);
1245         }
1246         LeaveCriticalSection(This->pin.pCritSec);
1247     }
1248
1249     TRACE(" -- %lx\n", hr);
1250
1251     return hr;
1252 }
1253
1254 HRESULT PullPin_StartProcessing(PullPin * This)
1255 {
1256     /* if we are connected */
1257     TRACE("(%p)->()\n", This);
1258     if(This->pAlloc)
1259     {
1260         assert(This->hThread);
1261         
1262         ResetEvent(This->hEventStateChanged);
1263         
1264         if (!QueueUserAPC(PullPin_Thread_Process, This->hThread, (ULONG_PTR)This))
1265             return HRESULT_FROM_WIN32(GetLastError());
1266     }
1267
1268     return S_OK;
1269 }
1270
1271 HRESULT PullPin_PauseProcessing(PullPin * This)
1272 {
1273     /* make the processing function exit its loop */
1274     This->rtStop = 0;
1275
1276     return S_OK;
1277 }
1278
1279 HRESULT PullPin_StopProcessing(PullPin * This)
1280 {
1281     /* if we are connected */
1282     if (This->pAlloc)
1283     {
1284         assert(This->hThread);
1285
1286         ResetEvent(This->hEventStateChanged);
1287
1288         PullPin_PauseProcessing(This);
1289
1290         if (!QueueUserAPC(PullPin_Thread_Stop, This->hThread, (ULONG_PTR)This))
1291             return HRESULT_FROM_WIN32(GetLastError());
1292     }
1293
1294     return S_OK;
1295 }
1296
1297 HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds)
1298 {
1299     if (WaitForSingleObject(This->hEventStateChanged, dwMilliseconds) == WAIT_TIMEOUT)
1300         return S_FALSE;
1301     return S_OK;
1302 }
1303
1304 HRESULT PullPin_Seek(PullPin * This, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop)
1305 {
1306     FIXME("(%p)->(%lx%08lx, %lx%08lx)\n", This, (LONG)(rtStart >> 32), (LONG)rtStart, (LONG)(rtStop >> 32), (LONG)rtStop);
1307
1308     PullPin_BeginFlush((IPin *)This);
1309     /* FIXME: need critical section? */
1310     This->rtStart = rtStart;
1311     This->rtStop = rtStop;
1312     PullPin_EndFlush((IPin *)This);
1313
1314     return S_OK;
1315 }
1316
1317 HRESULT WINAPI PullPin_EndOfStream(IPin * iface)
1318 {
1319     FIXME("(%p)->()\n", iface);
1320     return E_NOTIMPL;
1321 }
1322
1323 HRESULT WINAPI PullPin_BeginFlush(IPin * iface)
1324 {
1325     FIXME("(%p)->()\n", iface);
1326     return E_NOTIMPL;
1327 }
1328
1329 HRESULT WINAPI PullPin_EndFlush(IPin * iface)
1330 {
1331     FIXME("(%p)->()\n", iface);
1332     return E_NOTIMPL;
1333 }
1334
1335 HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1336 {
1337     FIXME("(%p)->(%s, %s, %g)\n", iface, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate);
1338     return E_NOTIMPL;
1339 }
1340
1341 static const IPinVtbl PullPin_Vtbl = 
1342 {
1343     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1344     PullPin_QueryInterface,
1345     IPinImpl_AddRef,
1346     PullPin_Release,
1347     OutputPin_Connect,
1348     PullPin_ReceiveConnection,
1349     IPinImpl_Disconnect,
1350     IPinImpl_ConnectedTo,
1351     IPinImpl_ConnectionMediaType,
1352     IPinImpl_QueryPinInfo,
1353     IPinImpl_QueryDirection,
1354     IPinImpl_QueryId,
1355     IPinImpl_QueryAccept,
1356     IPinImpl_EnumMediaTypes,
1357     IPinImpl_QueryInternalConnections,
1358     PullPin_EndOfStream,
1359     PullPin_BeginFlush,
1360     PullPin_EndFlush,
1361     PullPin_NewSegment
1362 };