richedit: Use system colour for highlighting after v2.0.
[wine] / dlls / quartz / pin.c
1 /*
2  * Generic Implementation of IPin Interface
3  *
4  * Copyright 2003 Robert Shearman
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "quartz_private.h"
22 #include "pin.h"
23
24 #include "wine/debug.h"
25 #include "wine/unicode.h"
26 #include "uuids.h"
27 #include "vfwmsgs.h"
28 #include <assert.h>
29
30 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
31
32 static const IPinVtbl InputPin_Vtbl;
33 static const IPinVtbl OutputPin_Vtbl;
34 static const IMemInputPinVtbl MemInputPin_Vtbl;
35 static const IPinVtbl PullPin_Vtbl;
36
37 #define ALIGNDOWN(value,boundary) ((value)/(boundary)*(boundary))
38 #define ALIGNUP(value,boundary) (ALIGNDOWN((value)+(boundary)-1, (boundary)))
39
40 typedef HRESULT (*SendPinFunc)( IPin *to, LPVOID arg );
41
42 /** Helper function, there are a lot of places where the error code is inherited
43  * The following rules apply:
44  *
45  * Return the first received error code (E_NOTIMPL is ignored)
46  * If no errors occur: return the first received non-error-code that isn't S_OK
47  */
48 HRESULT updatehres( HRESULT original, HRESULT new )
49 {
50     if (FAILED( original ) || new == E_NOTIMPL)
51         return original;
52
53     if (FAILED( new ) || original == S_OK)
54         return new;
55
56     return original;
57 }
58
59 /** Sends a message from a pin further to other, similar pins
60  * fnMiddle is called on each pin found further on the stream.
61  * fnEnd (can be NULL) is called when the message can't be sent any further (this is a renderer or source)
62  *
63  * If the pin given is an input pin, the message will be sent downstream to other input pins
64  * If the pin given is an output pin, the message will be sent upstream to other output pins
65  */
66 static HRESULT SendFurther( IPin *from, SendPinFunc fnMiddle, LPVOID arg, SendPinFunc fnEnd )
67 {
68     PIN_INFO pin_info;
69     ULONG amount = 0;
70     HRESULT hr = S_OK;
71     HRESULT hr_return = S_OK;
72     IEnumPins *enumpins = NULL;
73     BOOL foundend = TRUE;
74     PIN_DIRECTION from_dir;
75
76     IPin_QueryDirection( from, &from_dir );
77
78     hr = IPin_QueryInternalConnections( from, NULL, &amount );
79     if (hr != E_NOTIMPL && amount)
80         FIXME("Use QueryInternalConnections!\n");
81      hr = S_OK;
82
83     pin_info.pFilter = NULL;
84     hr = IPin_QueryPinInfo( from, &pin_info );
85     if (FAILED(hr))
86         goto out;
87
88     hr = IBaseFilter_EnumPins( pin_info.pFilter, &enumpins );
89     if (FAILED(hr))
90         goto out;
91
92     hr = IEnumPins_Reset( enumpins );
93     while (hr == S_OK) {
94         IPin *pin = NULL;
95         hr = IEnumPins_Next( enumpins, 1, &pin, NULL );
96         if (hr == VFW_E_ENUM_OUT_OF_SYNC)
97         {
98             hr = IEnumPins_Reset( enumpins );
99             continue;
100         }
101         if (pin)
102         {
103             PIN_DIRECTION dir;
104
105             IPin_QueryDirection( pin, &dir );
106             if (dir != from_dir)
107             {
108                 IPin *connected = NULL;
109
110                 foundend = FALSE;
111                 IPin_ConnectedTo( pin, &connected );
112                 if (connected)
113                 {
114                     HRESULT hr_local;
115
116                     hr_local = fnMiddle( connected, arg );
117                     hr_return = updatehres( hr_return, hr_local );
118                     IPin_Release(connected);
119                 }
120             }
121             IPin_Release( pin );
122         }
123         else
124         {
125             hr = S_OK;
126             break;
127         }
128     }
129
130     if (!foundend)
131         hr = hr_return;
132     else if (fnEnd) {
133         HRESULT hr_local;
134
135         hr_local = fnEnd( from, arg );
136         hr_return = updatehres( hr_return, hr_local );
137     }
138
139 out:
140     if (pin_info.pFilter)
141         IBaseFilter_Release( pin_info.pFilter );
142     return hr;
143 }
144
145 static inline InputPin *impl_from_IMemInputPin( IMemInputPin *iface )
146 {
147     return (InputPin *)((char*)iface - FIELD_OFFSET(InputPin, lpVtblMemInput));
148 }
149
150
151 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
152 {
153     /* Tempting to just do a memcpy, but the name field is
154        128 characters long! We will probably never exceed 10
155        most of the time, so we are better off copying 
156        each field manually */
157     strcpyW(pDest->achName, pSrc->achName);
158     pDest->dir = pSrc->dir;
159     pDest->pFilter = pSrc->pFilter;
160 }
161
162 /* Function called as a helper to IPin_Connect */
163 /* specific AM_MEDIA_TYPE - it cannot be NULL */
164 /* NOTE: not part of standard interface */
165 static HRESULT OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
166 {
167     OutputPin *This = (OutputPin *)iface;
168     HRESULT hr;
169     IMemAllocator * pMemAlloc = NULL;
170     ALLOCATOR_PROPERTIES actual; /* FIXME: should we put the actual props back in to This? */
171
172     TRACE("(%p, %p)\n", pReceivePin, pmt);
173     dump_AM_MEDIA_TYPE(pmt);
174
175     /* FIXME: call queryacceptproc */
176
177     This->pin.pConnectedTo = pReceivePin;
178     IPin_AddRef(pReceivePin);
179     CopyMediaType(&This->pin.mtCurrent, pmt);
180
181     hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
182
183     /* get the IMemInputPin interface we will use to deliver samples to the
184      * connected pin */
185     if (SUCCEEDED(hr))
186     {
187         This->pMemInputPin = NULL;
188         hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin);
189
190         if (SUCCEEDED(hr) && !This->custom_allocator)
191         {
192             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pMemAlloc);
193
194             if (hr == VFW_E_NO_ALLOCATOR)
195             {
196                 /* Input pin provides no allocator, use standard memory allocator */
197                 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)&pMemAlloc);
198
199                 if (SUCCEEDED(hr))
200                 {
201                     hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, pMemAlloc, This->readonly);
202                 }
203             }
204
205             if (SUCCEEDED(hr))
206                 hr = IMemAllocator_SetProperties(pMemAlloc, &This->allocProps, &actual);
207
208             if (pMemAlloc)
209                 IMemAllocator_Release(pMemAlloc);
210         }
211         else if (SUCCEEDED(hr))
212         {
213             if (This->alloc)
214             {
215                 hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, This->alloc, This->readonly);
216             }
217             else
218                 hr = VFW_E_NO_ALLOCATOR;
219         }
220
221         /* break connection if we couldn't get the allocator */
222         if (FAILED(hr))
223         {
224             if (This->pMemInputPin)
225                 IMemInputPin_Release(This->pMemInputPin);
226             This->pMemInputPin = NULL;
227
228             IPin_Disconnect(pReceivePin);
229         }
230     }
231
232     if (FAILED(hr))
233     {
234         IPin_Release(This->pin.pConnectedTo);
235         This->pin.pConnectedTo = NULL;
236         FreeMediaType(&This->pin.mtCurrent);
237     }
238
239     TRACE(" -- %x\n", hr);
240     return hr;
241 }
242
243 static HRESULT InputPin_Init(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData,
244                              QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, InputPin * pPinImpl)
245 {
246     TRACE("\n");
247
248     /* Common attributes */
249     pPinImpl->pin.refCount = 1;
250     pPinImpl->pin.pConnectedTo = NULL;
251     pPinImpl->pin.fnQueryAccept = pQueryAccept;
252     pPinImpl->pin.pUserData = pUserData;
253     pPinImpl->pin.pCritSec = pCritSec;
254     Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
255     ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
256
257     /* Input pin attributes */
258     pPinImpl->fnSampleProc = pSampleProc;
259     pPinImpl->fnCleanProc = pCleanUp;
260     pPinImpl->pAllocator = pPinImpl->preferred_allocator = allocator;
261     if (pPinImpl->preferred_allocator)
262         IMemAllocator_AddRef(pPinImpl->preferred_allocator);
263     pPinImpl->tStart = 0;
264     pPinImpl->tStop = 0;
265     pPinImpl->dRate = 1.0;
266     pPinImpl->pin.lpVtbl = InputPin_Vtbl;
267     pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl;
268     pPinImpl->flushing = pPinImpl->end_of_stream = 0;
269
270     return S_OK;
271 }
272
273 static HRESULT OutputPin_Init(const IPinVtbl *OutputPin_Vtbl, const PIN_INFO * pPinInfo, const ALLOCATOR_PROPERTIES * props, LPVOID pUserData,
274                               QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl)
275 {
276     TRACE("\n");
277
278     /* Common attributes */
279     pPinImpl->pin.lpVtbl = OutputPin_Vtbl;
280     pPinImpl->pin.refCount = 1;
281     pPinImpl->pin.pConnectedTo = NULL;
282     pPinImpl->pin.fnQueryAccept = pQueryAccept;
283     pPinImpl->pin.pUserData = pUserData;
284     pPinImpl->pin.pCritSec = pCritSec;
285     Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
286     ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
287
288     /* Output pin attributes */
289     pPinImpl->pMemInputPin = NULL;
290     pPinImpl->pConnectSpecific = OutputPin_ConnectSpecific;
291     /* If custom_allocator is set, you will need to specify an allocator
292      * in the alloc member of the struct before an output pin can connect
293      */
294     pPinImpl->custom_allocator = 0;
295     pPinImpl->alloc = NULL;
296     pPinImpl->readonly = FALSE;
297     if (props)
298     {
299         pPinImpl->allocProps = *props;
300         if (pPinImpl->allocProps.cbAlign == 0)
301             pPinImpl->allocProps.cbAlign = 1;
302     }
303     else
304         ZeroMemory(&pPinImpl->allocProps, sizeof(pPinImpl->allocProps));
305
306     return S_OK;
307 }
308
309 HRESULT InputPin_Construct(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, IPin ** ppPin)
310 {
311     InputPin * pPinImpl;
312
313     *ppPin = NULL;
314
315     if (pPinInfo->dir != PINDIR_INPUT)
316     {
317         ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
318         return E_INVALIDARG;
319     }
320
321     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
322
323     if (!pPinImpl)
324         return E_OUTOFMEMORY;
325
326     if (SUCCEEDED(InputPin_Init(InputPin_Vtbl, pPinInfo, pSampleProc, pUserData, pQueryAccept, pCleanUp, pCritSec, allocator, pPinImpl)))
327     {
328         *ppPin = (IPin *)pPinImpl;
329         return S_OK;
330     }
331
332     CoTaskMemFree(pPinImpl);
333     return E_FAIL;
334 }
335
336 HRESULT OutputPin_Construct(const IPinVtbl *OutputPin_Vtbl, long outputpin_size, const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
337 {
338     OutputPin * pPinImpl;
339
340     *ppPin = NULL;
341
342     if (pPinInfo->dir != PINDIR_OUTPUT)
343     {
344         ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo->dir);
345         return E_INVALIDARG;
346     }
347
348     assert(outputpin_size >= sizeof(OutputPin));
349
350     pPinImpl = CoTaskMemAlloc(outputpin_size);
351
352     if (!pPinImpl)
353         return E_OUTOFMEMORY;
354
355     if (SUCCEEDED(OutputPin_Init(OutputPin_Vtbl, pPinInfo, props, pUserData, pQueryAccept, pCritSec, pPinImpl)))
356     {
357         *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
358         return S_OK;
359     }
360
361     CoTaskMemFree(pPinImpl);
362     return E_FAIL;
363 }
364
365 /*** Common pin functions ***/
366
367 ULONG WINAPI IPinImpl_AddRef(IPin * iface)
368 {
369     IPinImpl *This = (IPinImpl *)iface;
370     ULONG refCount = InterlockedIncrement(&This->refCount);
371     
372     TRACE("(%p)->() AddRef from %d\n", iface, refCount - 1);
373     
374     return refCount;
375 }
376
377 HRESULT WINAPI IPinImpl_Disconnect(IPin * iface)
378 {
379     HRESULT hr;
380     IPinImpl *This = (IPinImpl *)iface;
381
382     TRACE("()\n");
383
384     EnterCriticalSection(This->pCritSec);
385     {
386         if (This->pConnectedTo)
387         {
388             IPin_Release(This->pConnectedTo);
389             This->pConnectedTo = NULL;
390             hr = S_OK;
391         }
392         else
393             hr = S_FALSE;
394     }
395     LeaveCriticalSection(This->pCritSec);
396     
397     return hr;
398 }
399
400 HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin)
401 {
402     HRESULT hr;
403     IPinImpl *This = (IPinImpl *)iface;
404
405     TRACE("(%p)\n", ppPin);
406
407     EnterCriticalSection(This->pCritSec);
408     {
409         if (This->pConnectedTo)
410         {
411             *ppPin = This->pConnectedTo;
412             IPin_AddRef(*ppPin);
413             hr = S_OK;
414         }
415         else
416         {
417             hr = VFW_E_NOT_CONNECTED;
418             *ppPin = NULL;
419         }
420     }
421     LeaveCriticalSection(This->pCritSec);
422
423     return hr;
424 }
425
426 HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
427 {
428     HRESULT hr;
429     IPinImpl *This = (IPinImpl *)iface;
430
431     TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
432
433     EnterCriticalSection(This->pCritSec);
434     {
435         if (This->pConnectedTo)
436         {
437             CopyMediaType(pmt, &This->mtCurrent);
438             hr = S_OK;
439         }
440         else
441         {
442             ZeroMemory(pmt, sizeof(*pmt));
443             hr = VFW_E_NOT_CONNECTED;
444         }
445     }
446     LeaveCriticalSection(This->pCritSec);
447
448     return hr;
449 }
450
451 HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
452 {
453     IPinImpl *This = (IPinImpl *)iface;
454
455     TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
456
457     Copy_PinInfo(pInfo, &This->pinInfo);
458     IBaseFilter_AddRef(pInfo->pFilter);
459
460     return S_OK;
461 }
462
463 HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
464 {
465     IPinImpl *This = (IPinImpl *)iface;
466
467     TRACE("(%p/%p)->(%p)\n", This, iface, pPinDir);
468
469     *pPinDir = This->pinInfo.dir;
470
471     return S_OK;
472 }
473
474 HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id)
475 {
476     IPinImpl *This = (IPinImpl *)iface;
477
478     TRACE("(%p/%p)->(%p)\n", This, iface, Id);
479
480     *Id = CoTaskMemAlloc((strlenW(This->pinInfo.achName) + 1) * sizeof(WCHAR));
481     if (!*Id)
482         return E_OUTOFMEMORY;
483
484     strcpyW(*Id, This->pinInfo.achName);
485
486     return S_OK;
487 }
488
489 HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
490 {
491     IPinImpl *This = (IPinImpl *)iface;
492
493     TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
494
495     return (This->fnQueryAccept(This->pUserData, pmt) == S_OK ? S_OK : S_FALSE);
496 }
497
498 HRESULT WINAPI IPinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
499 {
500     IPinImpl *This = (IPinImpl *)iface;
501     ENUMMEDIADETAILS emd;
502
503     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
504
505     /* override this method to allow enumeration of your types */
506     emd.cMediaTypes = 0;
507     emd.pMediaTypes = NULL;
508
509     return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
510 }
511
512 HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
513 {
514     IPinImpl *This = (IPinImpl *)iface;
515
516     TRACE("(%p/%p)->(%p, %p)\n", This, iface, apPin, cPin);
517
518     return E_NOTIMPL; /* to tell caller that all input pins connected to all output pins */
519 }
520
521 /*** IPin implementation for an input pin ***/
522
523 HRESULT WINAPI InputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
524 {
525     InputPin *This = (InputPin *)iface;
526
527     TRACE("(%p)->(%s, %p)\n", iface, qzdebugstr_guid(riid), ppv);
528
529     *ppv = NULL;
530
531     if (IsEqualIID(riid, &IID_IUnknown))
532         *ppv = (LPVOID)iface;
533     else if (IsEqualIID(riid, &IID_IPin))
534         *ppv = (LPVOID)iface;
535     else if (IsEqualIID(riid, &IID_IMemInputPin))
536         *ppv = (LPVOID)&This->lpVtblMemInput;
537     else if (IsEqualIID(riid, &IID_IMediaSeeking))
538     {
539         return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
540     }
541
542     if (*ppv)
543     {
544         IUnknown_AddRef((IUnknown *)(*ppv));
545         return S_OK;
546     }
547
548     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
549
550     return E_NOINTERFACE;
551 }
552
553 ULONG WINAPI InputPin_Release(IPin * iface)
554 {
555     InputPin *This = (InputPin *)iface;
556     ULONG refCount = InterlockedDecrement(&This->pin.refCount);
557     
558     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
559     
560     if (!refCount)
561     {
562         FreeMediaType(&This->pin.mtCurrent);
563         if (This->pAllocator)
564             IMemAllocator_Release(This->pAllocator);
565         This->pAllocator = NULL;
566         This->pin.lpVtbl = NULL;
567         CoTaskMemFree(This);
568         return 0;
569     }
570     else
571         return refCount;
572 }
573
574 HRESULT WINAPI InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
575 {
576     ERR("Outgoing connection on an input pin! (%p, %p)\n", pConnector, pmt);
577
578     return E_UNEXPECTED;
579 }
580
581
582 HRESULT WINAPI InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
583 {
584     InputPin *This = (InputPin *)iface;
585     PIN_DIRECTION pindirReceive;
586     HRESULT hr = S_OK;
587
588     TRACE("(%p, %p)\n", pReceivePin, pmt);
589     dump_AM_MEDIA_TYPE(pmt);
590
591     EnterCriticalSection(This->pin.pCritSec);
592     {
593         if (This->pin.pConnectedTo)
594             hr = VFW_E_ALREADY_CONNECTED;
595
596         if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)
597             hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto
598                                            * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
599
600         if (SUCCEEDED(hr))
601         {
602             IPin_QueryDirection(pReceivePin, &pindirReceive);
603
604             if (pindirReceive != PINDIR_OUTPUT)
605             {
606                 ERR("Can't connect from non-output pin\n");
607                 hr = VFW_E_INVALID_DIRECTION;
608             }
609         }
610
611         if (SUCCEEDED(hr))
612         {
613             CopyMediaType(&This->pin.mtCurrent, pmt);
614             This->pin.pConnectedTo = pReceivePin;
615             IPin_AddRef(pReceivePin);
616         }
617     }
618     LeaveCriticalSection(This->pin.pCritSec);
619
620     return hr;
621 }
622
623 static HRESULT deliver_endofstream(IPin* pin, LPVOID unused)
624 {
625     return IPin_EndOfStream( pin );
626 }
627
628 HRESULT WINAPI InputPin_EndOfStream(IPin * iface)
629 {
630     HRESULT hr = S_OK;
631     InputPin *This = (InputPin *)iface;
632
633     TRACE("(%p)\n", This);
634
635     EnterCriticalSection(This->pin.pCritSec);
636     if (This->flushing)
637         hr = S_FALSE;
638     else
639         This->end_of_stream = 1;
640     LeaveCriticalSection(This->pin.pCritSec);
641
642     if (hr == S_OK)
643         hr = SendFurther( iface, deliver_endofstream, NULL, NULL );
644     return hr;
645 }
646
647 static HRESULT deliver_beginflush(IPin* pin, LPVOID unused)
648 {
649     return IPin_BeginFlush( pin );
650 }
651
652 HRESULT WINAPI InputPin_BeginFlush(IPin * iface)
653 {
654     InputPin *This = (InputPin *)iface;
655     HRESULT hr;
656     TRACE("() semi-stub\n");
657
658     EnterCriticalSection(This->pin.pCritSec);
659     This->flushing = 1;
660
661     if (This->fnCleanProc)
662         This->fnCleanProc(This->pin.pUserData);
663
664     hr = SendFurther( iface, deliver_beginflush, NULL, NULL );
665     LeaveCriticalSection(This->pin.pCritSec);
666
667     return hr;
668 }
669
670 static HRESULT deliver_endflush(IPin* pin, LPVOID unused)
671 {
672     return IPin_EndFlush( pin );
673 }
674
675 HRESULT WINAPI InputPin_EndFlush(IPin * iface)
676 {
677     InputPin *This = (InputPin *)iface;
678     HRESULT hr;
679     TRACE("(%p)\n", This);
680
681     EnterCriticalSection(This->pin.pCritSec);
682     This->flushing = This->end_of_stream = 0;
683
684     hr = SendFurther( iface, deliver_endflush, NULL, NULL );
685     LeaveCriticalSection(This->pin.pCritSec);
686
687     return hr;
688 }
689
690 typedef struct newsegmentargs
691 {
692     REFERENCE_TIME tStart, tStop;
693     double rate;
694 } newsegmentargs;
695
696 static HRESULT deliver_newsegment(IPin *pin, LPVOID data)
697 {
698     newsegmentargs *args = data;
699     return IPin_NewSegment(pin, args->tStart, args->tStop, args->rate);
700 }
701
702 HRESULT WINAPI InputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
703 {
704     InputPin *This = (InputPin *)iface;
705     newsegmentargs args;
706
707     TRACE("(%x%08x, %x%08x, %e)\n", (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate);
708
709     args.tStart = This->tStart = tStart;
710     args.tStop = This->tStop = tStop;
711     args.rate = This->dRate = dRate;
712
713     return SendFurther( iface, deliver_newsegment, &args, NULL );
714 }
715
716 static const IPinVtbl InputPin_Vtbl = 
717 {
718     InputPin_QueryInterface,
719     IPinImpl_AddRef,
720     InputPin_Release,
721     InputPin_Connect,
722     InputPin_ReceiveConnection,
723     IPinImpl_Disconnect,
724     IPinImpl_ConnectedTo,
725     IPinImpl_ConnectionMediaType,
726     IPinImpl_QueryPinInfo,
727     IPinImpl_QueryDirection,
728     IPinImpl_QueryId,
729     IPinImpl_QueryAccept,
730     IPinImpl_EnumMediaTypes,
731     IPinImpl_QueryInternalConnections,
732     InputPin_EndOfStream,
733     InputPin_BeginFlush,
734     InputPin_EndFlush,
735     InputPin_NewSegment
736 };
737
738 /*** IMemInputPin implementation ***/
739
740 HRESULT WINAPI MemInputPin_QueryInterface(IMemInputPin * iface, REFIID riid, LPVOID * ppv)
741 {
742     InputPin *This = impl_from_IMemInputPin(iface);
743
744     return IPin_QueryInterface((IPin *)&This->pin, riid, ppv);
745 }
746
747 ULONG WINAPI MemInputPin_AddRef(IMemInputPin * iface)
748 {
749     InputPin *This = impl_from_IMemInputPin(iface);
750
751     return IPin_AddRef((IPin *)&This->pin);
752 }
753
754 ULONG WINAPI MemInputPin_Release(IMemInputPin * iface)
755 {
756     InputPin *This = impl_from_IMemInputPin(iface);
757
758     return IPin_Release((IPin *)&This->pin);
759 }
760
761 HRESULT WINAPI MemInputPin_GetAllocator(IMemInputPin * iface, IMemAllocator ** ppAllocator)
762 {
763     InputPin *This = impl_from_IMemInputPin(iface);
764
765     TRACE("(%p/%p)->(%p)\n", This, iface, ppAllocator);
766
767     *ppAllocator = This->pAllocator;
768     if (*ppAllocator)
769         IMemAllocator_AddRef(*ppAllocator);
770     
771     return *ppAllocator ? S_OK : VFW_E_NO_ALLOCATOR;
772 }
773
774 HRESULT WINAPI MemInputPin_NotifyAllocator(IMemInputPin * iface, IMemAllocator * pAllocator, BOOL bReadOnly)
775 {
776     InputPin *This = impl_from_IMemInputPin(iface);
777
778     TRACE("(%p/%p)->(%p, %d)\n", This, iface, pAllocator, bReadOnly);
779
780     if (bReadOnly)
781         FIXME("Read only flag not handled yet!\n");
782
783     /* FIXME: Should we release the allocator on disconnection? */
784     if (!pAllocator)
785     {
786         WARN("Null allocator\n");
787         return E_POINTER;
788     }
789
790     if (This->preferred_allocator && pAllocator != This->preferred_allocator)
791         return E_FAIL;
792
793     if (This->pAllocator)
794         IMemAllocator_Release(This->pAllocator);
795     This->pAllocator = pAllocator;
796     if (This->pAllocator)
797         IMemAllocator_AddRef(This->pAllocator);
798
799     return S_OK;
800 }
801
802 HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin * iface, ALLOCATOR_PROPERTIES * pProps)
803 {
804     InputPin *This = impl_from_IMemInputPin(iface);
805
806     TRACE("(%p/%p)->(%p)\n", This, iface, pProps);
807
808     /* override this method if you have any specific requirements */
809
810     return E_NOTIMPL;
811 }
812
813 HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample)
814 {
815     InputPin *This = impl_from_IMemInputPin(iface);
816     HRESULT hr;
817
818     /* this trace commented out for performance reasons */
819     /*TRACE("(%p/%p)->(%p)\n", This, iface, pSample);*/
820     hr = This->fnSampleProc(This->pin.pUserData, pSample);
821     return hr;
822 }
823
824 HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, long nSamples, long *nSamplesProcessed)
825 {
826     HRESULT hr = S_OK;
827     InputPin *This = impl_from_IMemInputPin(iface);
828
829     TRACE("(%p/%p)->(%p, %ld, %p)\n", This, iface, pSamples, nSamples, nSamplesProcessed);
830
831     for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; (*nSamplesProcessed)++)
832     {
833         hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
834         if (hr != S_OK)
835             break;
836     }
837
838     return hr;
839 }
840
841 HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface)
842 {
843     InputPin *This = impl_from_IMemInputPin(iface);
844
845     TRACE("(%p/%p)->()\n", This, iface);
846
847     return S_OK;
848 }
849
850 static const IMemInputPinVtbl MemInputPin_Vtbl = 
851 {
852     MemInputPin_QueryInterface,
853     MemInputPin_AddRef,
854     MemInputPin_Release,
855     MemInputPin_GetAllocator,
856     MemInputPin_NotifyAllocator,
857     MemInputPin_GetAllocatorRequirements,
858     MemInputPin_Receive,
859     MemInputPin_ReceiveMultiple,
860     MemInputPin_ReceiveCanBlock
861 };
862
863 HRESULT WINAPI OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
864 {
865     OutputPin *This = (OutputPin *)iface;
866
867     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
868
869     *ppv = NULL;
870
871     if (IsEqualIID(riid, &IID_IUnknown))
872         *ppv = (LPVOID)iface;
873     else if (IsEqualIID(riid, &IID_IPin))
874         *ppv = (LPVOID)iface;
875     else if (IsEqualIID(riid, &IID_IMediaSeeking))
876     {
877         return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
878     }
879
880     if (*ppv)
881     {
882         IUnknown_AddRef((IUnknown *)(*ppv));
883         return S_OK;
884     }
885
886     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
887
888     return E_NOINTERFACE;
889 }
890
891 ULONG WINAPI OutputPin_Release(IPin * iface)
892 {
893     OutputPin *This = (OutputPin *)iface;
894     ULONG refCount = InterlockedDecrement(&This->pin.refCount);
895
896     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
897
898     if (!refCount)
899     {
900         FreeMediaType(&This->pin.mtCurrent);
901         CoTaskMemFree(This);
902         return 0;
903     }
904     return refCount;
905 }
906
907 HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
908 {
909     HRESULT hr;
910     OutputPin *This = (OutputPin *)iface;
911
912     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
913     dump_AM_MEDIA_TYPE(pmt);
914
915     /* If we try to connect to ourself, we will definitely deadlock.
916      * There are other cases where we could deadlock too, but this
917      * catches the obvious case */
918     assert(pReceivePin != iface);
919
920     EnterCriticalSection(This->pin.pCritSec);
921     {
922         /* if we have been a specific type to connect with, then we can either connect
923          * with that or fail. We cannot choose different AM_MEDIA_TYPE */
924         if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
925             hr = This->pConnectSpecific(iface, pReceivePin, pmt);
926         else
927         {
928             /* negotiate media type */
929
930             IEnumMediaTypes * pEnumCandidates;
931             AM_MEDIA_TYPE * pmtCandidate; /* Candidate media type */
932
933             if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates)))
934             {
935                 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
936
937                 /* try this filter's media types first */
938                 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
939                 {
940                     if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && 
941                         (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
942                     {
943                         hr = S_OK;
944                         CoTaskMemFree(pmtCandidate);
945                         break;
946                     }
947                     CoTaskMemFree(pmtCandidate);
948                 }
949                 IEnumMediaTypes_Release(pEnumCandidates);
950             }
951
952             /* then try receiver filter's media types */
953             if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */
954             {
955                 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
956
957                 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
958                 {
959                     if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && 
960                         (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
961                     {
962                         hr = S_OK;
963                         CoTaskMemFree(pmtCandidate);
964                         break;
965                     }
966                     CoTaskMemFree(pmtCandidate);
967                 } /* while */
968                 IEnumMediaTypes_Release(pEnumCandidates);
969             } /* if not found */
970         } /* if negotiate media type */
971     } /* if succeeded */
972     LeaveCriticalSection(This->pin.pCritSec);
973
974     TRACE(" -- %x\n", hr);
975     return hr;
976 }
977
978 HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
979 {
980     ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin, pmt);
981
982     return E_UNEXPECTED;
983 }
984
985 HRESULT WINAPI OutputPin_Disconnect(IPin * iface)
986 {
987     HRESULT hr;
988     OutputPin *This = (OutputPin *)iface;
989
990     TRACE("()\n");
991
992     EnterCriticalSection(This->pin.pCritSec);
993     {
994         if (This->pMemInputPin)
995         {
996             IMemInputPin_Release(This->pMemInputPin);
997             This->pMemInputPin = NULL;
998         }
999         if (This->pin.pConnectedTo)
1000         {
1001             IPin_Release(This->pin.pConnectedTo);
1002             This->pin.pConnectedTo = NULL;
1003             hr = S_OK;
1004         }
1005         else
1006             hr = S_FALSE;
1007     }
1008     LeaveCriticalSection(This->pin.pCritSec);
1009
1010     return hr;
1011 }
1012
1013 HRESULT WINAPI OutputPin_EndOfStream(IPin * iface)
1014 {
1015     TRACE("()\n");
1016
1017     /* not supposed to do anything in an output pin */
1018
1019     return E_UNEXPECTED;
1020 }
1021
1022 HRESULT WINAPI OutputPin_BeginFlush(IPin * iface)
1023 {
1024     TRACE("(%p)->()\n", iface);
1025
1026     /* not supposed to do anything in an output pin */
1027
1028     return E_UNEXPECTED;
1029 }
1030
1031 HRESULT WINAPI OutputPin_EndFlush(IPin * iface)
1032 {
1033     TRACE("(%p)->()\n", iface);
1034
1035     /* not supposed to do anything in an output pin */
1036
1037     return E_UNEXPECTED;
1038 }
1039
1040 HRESULT WINAPI OutputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1041 {
1042     TRACE("(%p)->(%x%08x, %x%08x, %e)\n", iface, (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate);
1043
1044     /* not supposed to do anything in an output pin */
1045
1046     return E_UNEXPECTED;
1047 }
1048
1049 static const IPinVtbl OutputPin_Vtbl = 
1050 {
1051     OutputPin_QueryInterface,
1052     IPinImpl_AddRef,
1053     OutputPin_Release,
1054     OutputPin_Connect,
1055     OutputPin_ReceiveConnection,
1056     OutputPin_Disconnect,
1057     IPinImpl_ConnectedTo,
1058     IPinImpl_ConnectionMediaType,
1059     IPinImpl_QueryPinInfo,
1060     IPinImpl_QueryDirection,
1061     IPinImpl_QueryId,
1062     IPinImpl_QueryAccept,
1063     IPinImpl_EnumMediaTypes,
1064     IPinImpl_QueryInternalConnections,
1065     OutputPin_EndOfStream,
1066     OutputPin_BeginFlush,
1067     OutputPin_EndFlush,
1068     OutputPin_NewSegment
1069 };
1070
1071 HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags)
1072 {
1073     HRESULT hr;
1074
1075     TRACE("(%p, %p, %p, %x)\n", ppSample, tStart, tStop, dwFlags);
1076
1077     EnterCriticalSection(This->pin.pCritSec);
1078     {
1079         if (!This->pin.pConnectedTo)
1080             hr = VFW_E_NOT_CONNECTED;
1081         else
1082         {
1083             IMemAllocator * pAlloc = NULL;
1084             
1085             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
1086
1087             if (SUCCEEDED(hr))
1088                 hr = IMemAllocator_GetBuffer(pAlloc, ppSample, tStart, tStop, dwFlags);
1089
1090             if (SUCCEEDED(hr))
1091                 hr = IMediaSample_SetTime(*ppSample, tStart, tStop);
1092
1093             if (pAlloc)
1094                 IMemAllocator_Release(pAlloc);
1095         }
1096     }
1097     LeaveCriticalSection(This->pin.pCritSec);
1098     
1099     return hr;
1100 }
1101
1102 HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample)
1103 {
1104     HRESULT hr = S_OK;
1105     IMemInputPin * pMemConnected = NULL;
1106     PIN_INFO pinInfo;
1107
1108     EnterCriticalSection(This->pin.pCritSec);
1109     {
1110         if (!This->pin.pConnectedTo || !This->pMemInputPin)
1111             hr = VFW_E_NOT_CONNECTED;
1112         else
1113         {
1114             /* we don't have the lock held when using This->pMemInputPin,
1115              * so we need to AddRef it to stop it being deleted while we are
1116              * using it. Same with its filter. */
1117             pMemConnected = This->pMemInputPin;
1118             IMemInputPin_AddRef(pMemConnected);
1119             hr = IPin_QueryPinInfo(This->pin.pConnectedTo, &pinInfo);
1120         }
1121     }
1122     LeaveCriticalSection(This->pin.pCritSec);
1123
1124     if (SUCCEEDED(hr))
1125     {
1126         /* NOTE: if we are in a critical section when Receive is called
1127          * then it causes some problems (most notably with the native Video
1128          * Renderer) if we are re-entered for whatever reason */
1129         hr = IMemInputPin_Receive(pMemConnected, pSample);
1130
1131         /* If the filter's destroyed, tell upstream to stop sending data */
1132         if(IBaseFilter_Release(pinInfo.pFilter) == 0 && SUCCEEDED(hr))
1133             hr = S_FALSE;
1134     }
1135     if (pMemConnected)
1136         IMemInputPin_Release(pMemConnected);
1137
1138     return hr;
1139 }
1140
1141 HRESULT OutputPin_DeliverNewSegment(OutputPin * This, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1142 {
1143     HRESULT hr;
1144
1145     EnterCriticalSection(This->pin.pCritSec);
1146     {
1147         if (!This->pin.pConnectedTo)
1148             hr = VFW_E_NOT_CONNECTED;
1149         else
1150             hr = IPin_NewSegment(This->pin.pConnectedTo, tStart, tStop, dRate);
1151     }
1152     LeaveCriticalSection(This->pin.pCritSec);
1153     
1154     return hr;
1155 }
1156
1157 HRESULT OutputPin_CommitAllocator(OutputPin * This)
1158 {
1159     HRESULT hr = S_OK;
1160
1161     TRACE("(%p)->()\n", This);
1162
1163     EnterCriticalSection(This->pin.pCritSec);
1164     {
1165         if (!This->pin.pConnectedTo || !This->pMemInputPin)
1166             hr = VFW_E_NOT_CONNECTED;
1167         else
1168         {
1169             IMemAllocator * pAlloc = NULL;
1170
1171             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
1172
1173             if (SUCCEEDED(hr))
1174                 hr = IMemAllocator_Commit(pAlloc);
1175
1176             if (pAlloc)
1177                 IMemAllocator_Release(pAlloc);
1178         }
1179     }
1180     LeaveCriticalSection(This->pin.pCritSec);
1181
1182     TRACE("--> %08x\n", hr);
1183     return hr;
1184 }
1185
1186 HRESULT OutputPin_DecommitAllocator(OutputPin * This)
1187 {
1188     HRESULT hr = S_OK;
1189
1190     TRACE("(%p)->()\n", This);
1191
1192     EnterCriticalSection(This->pin.pCritSec);
1193     {
1194         if (!This->pin.pConnectedTo || !This->pMemInputPin)
1195             hr = VFW_E_NOT_CONNECTED;
1196         else
1197         {
1198             IMemAllocator * pAlloc = NULL;
1199
1200             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
1201
1202             if (SUCCEEDED(hr))
1203                 hr = IMemAllocator_Decommit(pAlloc);
1204
1205             if (pAlloc)
1206                 IMemAllocator_Release(pAlloc);
1207         }
1208     }
1209     LeaveCriticalSection(This->pin.pCritSec);
1210
1211     TRACE("--> %08x\n", hr);
1212     return hr;
1213 }
1214
1215 HRESULT OutputPin_DeliverDisconnect(OutputPin * This)
1216 {
1217     HRESULT hr;
1218
1219     TRACE("(%p)->()\n", This);
1220
1221     EnterCriticalSection(This->pin.pCritSec);
1222     {
1223         if (!This->pin.pConnectedTo || !This->pMemInputPin)
1224             hr = VFW_E_NOT_CONNECTED;
1225         else if (!This->custom_allocator)
1226         {
1227             IMemAllocator * pAlloc = NULL;
1228
1229             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
1230
1231             if (SUCCEEDED(hr))
1232                 hr = IMemAllocator_Decommit(pAlloc);
1233
1234             if (pAlloc)
1235                 IMemAllocator_Release(pAlloc);
1236
1237             if (SUCCEEDED(hr))
1238                 hr = IPin_Disconnect(This->pin.pConnectedTo);
1239         }
1240         else /* Kill the allocator! */
1241         {
1242             hr = IPin_Disconnect(This->pin.pConnectedTo);
1243         }
1244         IPin_Disconnect((IPin *)This);
1245     }
1246     LeaveCriticalSection(This->pin.pCritSec);
1247
1248     return hr;
1249 }
1250
1251
1252 static HRESULT PullPin_Init(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData,
1253                             QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, STOPPROCESSPROC pDone, LPCRITICAL_SECTION pCritSec, PullPin * pPinImpl)
1254 {
1255     /* Common attributes */
1256     pPinImpl->pin.lpVtbl = PullPin_Vtbl;
1257     pPinImpl->pin.refCount = 1;
1258     pPinImpl->pin.pConnectedTo = NULL;
1259     pPinImpl->pin.fnQueryAccept = pQueryAccept;
1260     pPinImpl->pin.pUserData = pUserData;
1261     pPinImpl->pin.pCritSec = pCritSec;
1262     Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
1263     ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
1264
1265     /* Input pin attributes */
1266     pPinImpl->fnSampleProc = pSampleProc;
1267     pPinImpl->fnCleanProc = pCleanUp;
1268     pPinImpl->fnDone = pDone;
1269     pPinImpl->fnPreConnect = NULL;
1270     pPinImpl->pAlloc = NULL;
1271     pPinImpl->pReader = NULL;
1272     pPinImpl->hThread = NULL;
1273     pPinImpl->hEventStateChanged = CreateEventW(NULL, TRUE, TRUE, NULL);
1274     pPinImpl->thread_sleepy = CreateEventW(NULL, FALSE, FALSE, NULL);
1275
1276     pPinImpl->rtStart = 0;
1277     pPinImpl->rtCurrent = 0;
1278     pPinImpl->rtStop = ((LONGLONG)0x7fffffff << 32) | 0xffffffff;
1279     pPinImpl->dRate = 1.0;
1280     pPinImpl->state = Req_Die;
1281     pPinImpl->fnCustomRequest = pCustomRequest;
1282     pPinImpl->stop_playback = 1;
1283
1284     InitializeCriticalSection(&pPinImpl->thread_lock);
1285     pPinImpl->thread_lock.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": PullPin.thread_lock");
1286
1287     return S_OK;
1288 }
1289
1290 HRESULT PullPin_Construct(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, STOPPROCESSPROC pDone, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
1291 {
1292     PullPin * pPinImpl;
1293
1294     *ppPin = NULL;
1295
1296     if (pPinInfo->dir != PINDIR_INPUT)
1297     {
1298         ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
1299         return E_INVALIDARG;
1300     }
1301
1302     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
1303
1304     if (!pPinImpl)
1305         return E_OUTOFMEMORY;
1306
1307     if (SUCCEEDED(PullPin_Init(PullPin_Vtbl, pPinInfo, pSampleProc, pUserData, pQueryAccept, pCleanUp, pCustomRequest, pDone, pCritSec, pPinImpl)))
1308     {
1309         *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
1310         return S_OK;
1311     }
1312
1313     CoTaskMemFree(pPinImpl);
1314     return E_FAIL;
1315 }
1316
1317 static HRESULT PullPin_InitProcessing(PullPin * This);
1318
1319 HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
1320 {
1321     PIN_DIRECTION pindirReceive;
1322     HRESULT hr = S_OK;
1323     PullPin *This = (PullPin *)iface;
1324
1325     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
1326     dump_AM_MEDIA_TYPE(pmt);
1327
1328     EnterCriticalSection(This->pin.pCritSec);
1329     if (!This->pin.pConnectedTo)
1330     {
1331         ALLOCATOR_PROPERTIES props;
1332
1333         props.cBuffers = 3;
1334         props.cbBuffer = 64 * 1024; /* 64k bytes */
1335         props.cbAlign = 1;
1336         props.cbPrefix = 0;
1337
1338         if (SUCCEEDED(hr) && (This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK))
1339             hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto 
1340                                            * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
1341
1342         if (SUCCEEDED(hr))
1343         {
1344             IPin_QueryDirection(pReceivePin, &pindirReceive);
1345
1346             if (pindirReceive != PINDIR_OUTPUT)
1347             {
1348                 ERR("Can't connect from non-output pin\n");
1349                 hr = VFW_E_INVALID_DIRECTION;
1350             }
1351         }
1352
1353         This->pReader = NULL;
1354         This->pAlloc = NULL;
1355         if (SUCCEEDED(hr))
1356         {
1357             hr = IPin_QueryInterface(pReceivePin, &IID_IAsyncReader, (LPVOID *)&This->pReader);
1358         }
1359
1360         if (SUCCEEDED(hr) && This->fnPreConnect)
1361         {
1362             hr = This->fnPreConnect(iface, pReceivePin, &props);
1363         }
1364
1365         if (SUCCEEDED(hr))
1366         {
1367             hr = IAsyncReader_RequestAllocator(This->pReader, NULL, &props, &This->pAlloc);
1368         }
1369
1370         if (SUCCEEDED(hr))
1371         {
1372             CopyMediaType(&This->pin.mtCurrent, pmt);
1373             This->pin.pConnectedTo = pReceivePin;
1374             IPin_AddRef(pReceivePin);
1375             hr = IMemAllocator_Commit(This->pAlloc);
1376         }
1377
1378         if (SUCCEEDED(hr))
1379             hr = PullPin_InitProcessing(This);
1380
1381         if (FAILED(hr))
1382         {
1383              if (This->pReader)
1384                  IAsyncReader_Release(This->pReader);
1385              This->pReader = NULL;
1386              if (This->pAlloc)
1387                  IMemAllocator_Release(This->pAlloc);
1388              This->pAlloc = NULL;
1389         }
1390     }
1391     else
1392         hr = VFW_E_ALREADY_CONNECTED;
1393     LeaveCriticalSection(This->pin.pCritSec);
1394     return hr;
1395 }
1396
1397 HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
1398 {
1399     PullPin *This = (PullPin *)iface;
1400
1401     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
1402
1403     *ppv = NULL;
1404
1405     if (IsEqualIID(riid, &IID_IUnknown))
1406         *ppv = (LPVOID)iface;
1407     else if (IsEqualIID(riid, &IID_IPin))
1408         *ppv = (LPVOID)iface;
1409     else if (IsEqualIID(riid, &IID_IMediaSeeking))
1410     {
1411         return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
1412     }
1413
1414     if (*ppv)
1415     {
1416         IUnknown_AddRef((IUnknown *)(*ppv));
1417         return S_OK;
1418     }
1419
1420     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
1421
1422     return E_NOINTERFACE;
1423 }
1424
1425 ULONG WINAPI PullPin_Release(IPin *iface)
1426 {
1427     PullPin *This = (PullPin *)iface;
1428     ULONG refCount = InterlockedDecrement(&This->pin.refCount);
1429
1430     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
1431
1432     if (!refCount)
1433     {
1434         WaitForSingleObject(This->hEventStateChanged, INFINITE);
1435         assert(!This->hThread);
1436
1437         if(This->pAlloc)
1438             IMemAllocator_Release(This->pAlloc);
1439         if(This->pReader)
1440             IAsyncReader_Release(This->pReader);
1441         CloseHandle(This->thread_sleepy);
1442         CloseHandle(This->hEventStateChanged);
1443         This->thread_lock.DebugInfo->Spare[0] = 0;
1444         DeleteCriticalSection(&This->thread_lock);
1445         CoTaskMemFree(This);
1446         return 0;
1447     }
1448     return refCount;
1449 }
1450
1451 static void CALLBACK PullPin_Flush(PullPin *This)
1452 {
1453     IMediaSample *pSample;
1454     TRACE("Flushing!\n");
1455
1456     if (This->pReader)
1457     {
1458         /* Flush outstanding samples */
1459         IAsyncReader_BeginFlush(This->pReader);
1460
1461         for (;;)
1462         {
1463             DWORD_PTR dwUser;
1464
1465             IAsyncReader_WaitForNext(This->pReader, 0, &pSample, &dwUser);
1466
1467             if (!pSample)
1468                 break;
1469
1470             assert(!IMediaSample_GetActualDataLength(pSample));
1471
1472             IMediaSample_Release(pSample);
1473         }
1474
1475         IAsyncReader_EndFlush(This->pReader);
1476     }
1477 }
1478
1479 static void CALLBACK PullPin_Thread_Process(PullPin *This)
1480 {
1481     HRESULT hr;
1482     IMediaSample * pSample = NULL;
1483     ALLOCATOR_PROPERTIES allocProps;
1484
1485     hr = IMemAllocator_GetProperties(This->pAlloc, &allocProps);
1486
1487     This->cbAlign = allocProps.cbAlign;
1488
1489     if (This->rtCurrent < This->rtStart)
1490         This->rtCurrent = MEDIATIME_FROM_BYTES(ALIGNDOWN(BYTES_FROM_MEDIATIME(This->rtStart), This->cbAlign));
1491
1492     TRACE("Start\n");
1493
1494     if (This->rtCurrent >= This->rtStop)
1495     {
1496         IPin_EndOfStream((IPin *)This);
1497         return;
1498     }
1499
1500     /* There is no sample in our buffer */
1501     hr = This->fnCustomRequest(This->pin.pUserData);
1502
1503     if (FAILED(hr))
1504         ERR("Request error: %x\n", hr);
1505
1506     EnterCriticalSection(This->pin.pCritSec);
1507     SetEvent(This->hEventStateChanged);
1508     LeaveCriticalSection(This->pin.pCritSec);
1509
1510     if (SUCCEEDED(hr))
1511     do
1512     {
1513         DWORD_PTR dwUser;
1514
1515         TRACE("Process sample\n");
1516
1517         hr = IAsyncReader_WaitForNext(This->pReader, 10000, &pSample, &dwUser);
1518
1519         /* Return an empty sample on error to the implementation in case it does custom parsing, so it knows it's gone */
1520         if (SUCCEEDED(hr))
1521         {
1522             hr = This->fnSampleProc(This->pin.pUserData, pSample, dwUser);
1523         }
1524         else
1525         {
1526             /* FIXME: This is not well handled yet! */
1527             ERR("Processing error: %x\n", hr);
1528         }
1529
1530         if (pSample)
1531         {
1532             IMediaSample_Release(pSample);
1533             pSample = NULL;
1534         }
1535     } while (This->rtCurrent < This->rtStop && hr == S_OK && !This->stop_playback);
1536
1537     /* Sample was rejected, and we are asked to terminate */
1538     if (pSample)
1539     {
1540         IMediaSample_Release(pSample);
1541     }
1542
1543     /* Can't reset state to Sleepy here because that might race, instead PauseProcessing will do that for us
1544      * Flush remaining samples
1545      */
1546     if (This->fnDone)
1547         This->fnDone(This->pin.pUserData);
1548
1549     TRACE("End: %08x, %d\n", hr, This->stop_playback);
1550 }
1551
1552 static void CALLBACK PullPin_Thread_Pause(PullPin *This)
1553 {
1554     EnterCriticalSection(This->pin.pCritSec);
1555     This->state = Req_Sleepy;
1556     SetEvent(This->hEventStateChanged);
1557     LeaveCriticalSection(This->pin.pCritSec);
1558 }
1559
1560 static void CALLBACK PullPin_Thread_Stop(PullPin *This)
1561 {
1562     TRACE("(%p)->()\n", This);
1563
1564     EnterCriticalSection(This->pin.pCritSec);
1565     {
1566         CloseHandle(This->hThread);
1567         This->hThread = NULL;
1568         SetEvent(This->hEventStateChanged);
1569     }
1570     LeaveCriticalSection(This->pin.pCritSec);
1571
1572     IBaseFilter_Release(This->pin.pinInfo.pFilter);
1573
1574     CoUninitialize();
1575     ExitThread(0);
1576 }
1577
1578 static void CALLBACK PullPin_Thread_Flush(PullPin *This)
1579 {
1580     PullPin_Flush(This);
1581
1582     EnterCriticalSection(This->pin.pCritSec);
1583     This->state = Req_Sleepy;
1584     SetEvent(This->hEventStateChanged);
1585     LeaveCriticalSection(This->pin.pCritSec);
1586 }
1587
1588 static DWORD WINAPI PullPin_Thread_Main(LPVOID pv)
1589 {
1590     PullPin *This = pv;
1591     CoInitializeEx(NULL, COINIT_MULTITHREADED);
1592
1593     PullPin_Flush(This);
1594
1595     for (;;)
1596     {
1597         WaitForSingleObject(This->thread_sleepy, INFINITE);
1598
1599         TRACE("State: %d\n", This->state);
1600
1601         switch (This->state)
1602         {
1603         case Req_Die: PullPin_Thread_Stop(This); break;
1604         case Req_Run: PullPin_Thread_Process(This); break;
1605         case Req_Pause: PullPin_Thread_Pause(This); break;
1606         case Req_Flush: PullPin_Thread_Flush(This); break;
1607         case Req_Sleepy: ERR("Should not be signalled with SLEEPY!\n"); break;
1608         default: ERR("Unknown state request: %d\n", This->state); break;
1609         }
1610     }
1611 }
1612
1613 static HRESULT PullPin_InitProcessing(PullPin * This)
1614 {
1615     HRESULT hr = S_OK;
1616
1617     TRACE("(%p)->()\n", This);
1618
1619     /* if we are connected */
1620     if (This->pAlloc)
1621     {
1622         DWORD dwThreadId;
1623
1624         WaitForSingleObject(This->hEventStateChanged, INFINITE);
1625         EnterCriticalSection(This->pin.pCritSec);
1626
1627         assert(!This->hThread);
1628         assert(This->state == Req_Die);
1629         assert(This->stop_playback);
1630         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1631         This->state = Req_Sleepy;
1632
1633         /* AddRef the filter to make sure it and it's pins will be around
1634          * as long as the thread */
1635         IBaseFilter_AddRef(This->pin.pinInfo.pFilter);
1636
1637
1638         This->hThread = CreateThread(NULL, 0, PullPin_Thread_Main, This, 0, &dwThreadId);
1639         if (!This->hThread)
1640         {
1641             hr = HRESULT_FROM_WIN32(GetLastError());
1642             IBaseFilter_Release(This->pin.pinInfo.pFilter);
1643         }
1644
1645         if (SUCCEEDED(hr))
1646         {
1647             SetEvent(This->hEventStateChanged);
1648             /* If assert fails, that means a command was not processed before the thread previously terminated */
1649         }
1650         LeaveCriticalSection(This->pin.pCritSec);
1651     }
1652
1653     TRACE(" -- %x\n", hr);
1654
1655     return hr;
1656 }
1657
1658 HRESULT PullPin_StartProcessing(PullPin * This)
1659 {
1660     /* if we are connected */
1661     TRACE("(%p)->()\n", This);
1662     if(This->pAlloc)
1663     {
1664         assert(This->hThread);
1665
1666         PullPin_WaitForStateChange(This, INFINITE);
1667
1668         assert(This->state == Req_Sleepy);
1669
1670         /* Wake up! */
1671         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1672         This->state = Req_Run;
1673         This->stop_playback = 0;
1674         ResetEvent(This->hEventStateChanged);
1675         SetEvent(This->thread_sleepy);
1676     }
1677
1678     return S_OK;
1679 }
1680
1681 HRESULT PullPin_PauseProcessing(PullPin * This)
1682 {
1683     /* if we are connected */
1684     TRACE("(%p)->()\n", This);
1685     if(This->pAlloc)
1686     {
1687         assert(This->hThread);
1688
1689         PullPin_WaitForStateChange(This, INFINITE);
1690
1691         EnterCriticalSection(This->pin.pCritSec);
1692
1693         assert(!This->stop_playback);
1694         assert(This->state == Req_Run|| This->state == Req_Sleepy);
1695
1696         assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1697         This->state = Req_Pause;
1698         This->stop_playback = 1;
1699         ResetEvent(This->hEventStateChanged);
1700         SetEvent(This->thread_sleepy);
1701
1702         LeaveCriticalSection(This->pin.pCritSec);
1703     }
1704
1705     return S_OK;
1706 }
1707
1708 static HRESULT PullPin_StopProcessing(PullPin * This)
1709 {
1710     TRACE("(%p)->()\n", This);
1711
1712     /* if we are alive */
1713     assert(This->hThread);
1714
1715     PullPin_WaitForStateChange(This, INFINITE);
1716
1717     assert(This->state == Req_Pause || This->state == Req_Sleepy);
1718
1719     This->stop_playback = 1;
1720     This->state = Req_Die;
1721     assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT);
1722     ResetEvent(This->hEventStateChanged);
1723     SetEvent(This->thread_sleepy);
1724     return S_OK;
1725 }
1726
1727 HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds)
1728 {
1729     if (WaitForSingleObject(This->hEventStateChanged, dwMilliseconds) == WAIT_TIMEOUT)
1730         return S_FALSE;
1731     return S_OK;
1732 }
1733
1734 HRESULT WINAPI PullPin_EndOfStream(IPin * iface)
1735 {
1736     FIXME("(%p)->() stub\n", iface);
1737
1738     return SendFurther( iface, deliver_endofstream, NULL, NULL );
1739 }
1740
1741 HRESULT WINAPI PullPin_BeginFlush(IPin * iface)
1742 {
1743     PullPin *This = (PullPin *)iface;
1744     TRACE("(%p)->()\n", This);
1745
1746     EnterCriticalSection(This->pin.pCritSec);
1747     {
1748         SendFurther( iface, deliver_beginflush, NULL, NULL );
1749     }
1750     LeaveCriticalSection(This->pin.pCritSec);
1751
1752     EnterCriticalSection(&This->thread_lock);
1753     {
1754         if (This->pReader)
1755             IAsyncReader_BeginFlush(This->pReader);
1756         PullPin_WaitForStateChange(This, INFINITE);
1757
1758         if (This->hThread && This->state == Req_Run)
1759         {
1760             PullPin_PauseProcessing(This);
1761             PullPin_WaitForStateChange(This, INFINITE);
1762         }
1763
1764         This->state = Req_Flush;
1765         ResetEvent(This->hEventStateChanged);
1766         SetEvent(This->thread_sleepy);
1767         PullPin_WaitForStateChange(This, INFINITE);
1768     }
1769     LeaveCriticalSection(&This->thread_lock);
1770
1771     EnterCriticalSection(This->pin.pCritSec);
1772     {
1773         This->fnCleanProc(This->pin.pUserData);
1774     }
1775     LeaveCriticalSection(This->pin.pCritSec);
1776
1777     return S_OK;
1778 }
1779
1780 HRESULT WINAPI PullPin_EndFlush(IPin * iface)
1781 {
1782     PullPin *This = (PullPin *)iface;
1783
1784     TRACE("(%p)->()\n", iface);
1785
1786     /* Send further first: Else a race condition might terminate processing early */
1787     EnterCriticalSection(This->pin.pCritSec);
1788     SendFurther( iface, deliver_endflush, NULL, NULL );
1789     LeaveCriticalSection(This->pin.pCritSec);
1790
1791     EnterCriticalSection(&This->thread_lock);
1792     {
1793         FILTER_STATE state;
1794         IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state);
1795
1796         if (state != State_Stopped)
1797             PullPin_StartProcessing(This);
1798
1799         PullPin_WaitForStateChange(This, INFINITE);
1800     }
1801     LeaveCriticalSection(&This->thread_lock);
1802
1803     return S_OK;
1804 }
1805
1806 HRESULT WINAPI PullPin_Disconnect(IPin *iface)
1807 {
1808     HRESULT hr;
1809     PullPin *This = (PullPin *)iface;
1810
1811     TRACE("()\n");
1812
1813     EnterCriticalSection(This->pin.pCritSec);
1814     {
1815         if (FAILED(hr = IMemAllocator_Decommit(This->pAlloc)))
1816             ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr);
1817
1818         if (This->pin.pConnectedTo)
1819         {
1820             IPin_Release(This->pin.pConnectedTo);
1821             This->pin.pConnectedTo = NULL;
1822             PullPin_StopProcessing(This);
1823             hr = S_OK;
1824         }
1825         else
1826             hr = S_FALSE;
1827     }
1828     LeaveCriticalSection(This->pin.pCritSec);
1829
1830     return hr;
1831 }
1832
1833 HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1834 {
1835     newsegmentargs args;
1836     FIXME("(%p)->(%s, %s, %g) stub\n", iface, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate);
1837
1838     args.tStart = tStart;
1839     args.tStop = tStop;
1840     args.rate = dRate;
1841
1842     return SendFurther( iface, deliver_newsegment, &args, NULL );
1843 }
1844
1845 static const IPinVtbl PullPin_Vtbl = 
1846 {
1847     PullPin_QueryInterface,
1848     IPinImpl_AddRef,
1849     PullPin_Release,
1850     InputPin_Connect,
1851     PullPin_ReceiveConnection,
1852     PullPin_Disconnect,
1853     IPinImpl_ConnectedTo,
1854     IPinImpl_ConnectionMediaType,
1855     IPinImpl_QueryPinInfo,
1856     IPinImpl_QueryDirection,
1857     IPinImpl_QueryId,
1858     IPinImpl_QueryAccept,
1859     IPinImpl_EnumMediaTypes,
1860     IPinImpl_QueryInternalConnections,
1861     PullPin_EndOfStream,
1862     PullPin_BeginFlush,
1863     PullPin_EndFlush,
1864     PullPin_NewSegment
1865 };