Release 1.5.29.
[wine] / dlls / qcap / vfwcapture.c
1 /* Video For Windows Steering structure
2  *
3  * Copyright 2005 Maarten Lankhorst
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  *
19  */
20
21 #define NONAMELESSSTRUCT
22 #define NONAMELESSUNION
23 #define COBJMACROS
24
25 #include "config.h"
26 #include <stdarg.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wtypes.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "dshow.h"
34
35 #include "qcap_main.h"
36 #include "wine/debug.h"
37
38 #include "capture.h"
39 #include "uuids.h"
40 #include "vfwmsgs.h"
41 #include "amvideo.h"
42 #include "strmif.h"
43 #include "ddraw.h"
44 #include "ocidl.h"
45 #include "oleauto.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(qcap);
48
49 #define ICOM_THIS_MULTI(impl,field,iface) \
50     impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
51
52 static const IBaseFilterVtbl VfwCapture_Vtbl;
53 static const IAMStreamConfigVtbl IAMStreamConfig_VTable;
54 static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable;
55 static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable;
56 static const IPinVtbl VfwPin_Vtbl;
57
58 static HRESULT VfwPin_Construct( IBaseFilter *, LPCRITICAL_SECTION, IPin ** );
59
60 typedef struct VfwCapture
61 {
62     BaseFilter filter;
63     IAMStreamConfig IAMStreamConfig_iface;
64     IAMVideoProcAmp IAMVideoProcAmp_iface;
65     IPersistPropertyBag IPersistPropertyBag_iface;
66
67     BOOL init;
68     Capture *driver_info;
69
70     IPin * pOutputPin;
71 } VfwCapture;
72
73 static inline VfwCapture *impl_from_IAMStreamConfig(IAMStreamConfig *iface)
74 {
75     return CONTAINING_RECORD(iface, VfwCapture, IAMStreamConfig_iface);
76 }
77
78 static inline VfwCapture *impl_from_IAMVideoProcAmp(IAMVideoProcAmp *iface)
79 {
80     return CONTAINING_RECORD(iface, VfwCapture, IAMVideoProcAmp_iface);
81 }
82
83 static inline VfwCapture *impl_from_IPersistPropertyBag(IPersistPropertyBag *iface)
84 {
85     return CONTAINING_RECORD(iface, VfwCapture, IPersistPropertyBag_iface);
86 }
87
88 /* VfwPin implementation */
89 typedef struct VfwPinImpl
90 {
91     BaseOutputPin pin;
92     Capture *driver_info;
93     VfwCapture *parent;
94     const IKsPropertySetVtbl * KSP_VT;
95 } VfwPinImpl;
96
97 static IPin* WINAPI VfwCapture_GetPin(BaseFilter *iface, int pos)
98 {
99     VfwCapture *This = (VfwCapture *)iface;
100
101     if (pos >= 1 || pos < 0)
102         return NULL;
103
104     IPin_AddRef(This->pOutputPin);
105     return This->pOutputPin;
106 }
107
108 static LONG WINAPI VfwCapture_GetPinCount(BaseFilter *iface)
109 {
110     return 1;
111 }
112
113 static const BaseFilterFuncTable BaseFuncTable = {
114     VfwCapture_GetPin,
115     VfwCapture_GetPinCount
116 };
117
118 IUnknown * WINAPI QCAP_createVFWCaptureFilter(IUnknown *pUnkOuter, HRESULT *phr)
119 {
120     VfwCapture *pVfwCapture;
121     HRESULT hr;
122
123     TRACE("%p - %p\n", pUnkOuter, phr);
124
125     *phr = CLASS_E_NOAGGREGATION;
126     if (pUnkOuter)
127         return NULL;
128     *phr = E_OUTOFMEMORY;
129
130     pVfwCapture = CoTaskMemAlloc( sizeof(VfwCapture) );
131
132     if (!pVfwCapture)
133         return NULL;
134
135     BaseFilter_Init(&pVfwCapture->filter, &VfwCapture_Vtbl, &CLSID_VfwCapture, (DWORD_PTR)(__FILE__ ": VfwCapture.csFilter"), &BaseFuncTable);
136
137     pVfwCapture->IAMStreamConfig_iface.lpVtbl = &IAMStreamConfig_VTable;
138     pVfwCapture->IAMVideoProcAmp_iface.lpVtbl = &IAMVideoProcAmp_VTable;
139     pVfwCapture->IPersistPropertyBag_iface.lpVtbl = &IPersistPropertyBag_VTable;
140     pVfwCapture->init = FALSE;
141
142     hr = VfwPin_Construct(&pVfwCapture->filter.IBaseFilter_iface,
143                    &pVfwCapture->filter.csFilter, &pVfwCapture->pOutputPin);
144     if (FAILED(hr))
145     {
146         CoTaskMemFree(pVfwCapture);
147         return NULL;
148     }
149     TRACE("-- created at %p\n", pVfwCapture);
150
151     ObjectRefCount(TRUE);
152     *phr = S_OK;
153     return (IUnknown *)pVfwCapture;
154 }
155
156 static HRESULT WINAPI VfwCapture_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
157 {
158     VfwCapture *This = (VfwCapture *)iface;
159     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
160     *ppv = NULL;
161
162     if (IsEqualIID(riid, &IID_IUnknown) ||
163         IsEqualIID(riid, &IID_IPersist) ||
164         IsEqualIID(riid, &IID_IMediaFilter) ||
165         IsEqualIID(riid, &IID_IBaseFilter))
166     {
167         *ppv = This;
168     }
169     else if (IsEqualIID(riid, &IID_IAMStreamConfig))
170         *ppv = &This->IAMStreamConfig_iface;
171     else if (IsEqualIID(riid, &IID_IAMVideoProcAmp))
172         *ppv = &This->IAMVideoProcAmp_iface;
173     else if (IsEqualIID(riid, &IID_IPersistPropertyBag))
174         *ppv = &This->IPersistPropertyBag_iface;
175
176     if (!IsEqualIID(riid, &IID_IUnknown) &&
177         !IsEqualIID(riid, &IID_IPersist) &&
178         !IsEqualIID(riid, &IID_IPersistPropertyBag) &&
179         !This->init)
180     {
181         FIXME("Capture system not initialised when looking for %s, "
182               "trying it on primary device now\n", debugstr_guid(riid));
183         This->driver_info = qcap_driver_init( This->pOutputPin, 0 );
184         if (!This->driver_info)
185         {
186             ERR("VfwCapture initialisation failed\n");
187             return E_UNEXPECTED;
188         }
189         This->init = TRUE;
190     }
191
192     if (*ppv)
193     {
194         TRACE("Returning %s interface\n", debugstr_guid(riid));
195         IUnknown_AddRef((IUnknown *)(*ppv));
196         return S_OK;
197     }
198
199     FIXME("No interface for %s!\n", debugstr_guid(riid));
200     return E_NOINTERFACE;
201 }
202
203 static ULONG WINAPI VfwCapture_Release(IBaseFilter * iface)
204 {
205     VfwCapture *This = (VfwCapture *)iface;
206     ULONG refCount = BaseFilterImpl_Release(iface);
207
208     TRACE("%p->() New refcount: %d\n", This, refCount);
209
210     if (!refCount)
211     {
212         BasePin *pin;
213
214         TRACE("destroying everything\n");
215         if (This->init)
216         {
217             if (This->filter.state != State_Stopped)
218                 qcap_driver_stop(This->driver_info, &This->filter.state);
219             qcap_driver_destroy(This->driver_info);
220         }
221         pin = (BasePin*) This->pOutputPin;
222         if (pin->pConnectedTo != NULL)
223         {
224             IPin_Disconnect(pin->pConnectedTo);
225             IPin_Disconnect(This->pOutputPin);
226         }
227         IPin_Release(This->pOutputPin);
228         CoTaskMemFree(This);
229         ObjectRefCount(FALSE);
230     }
231     return refCount;
232 }
233
234 /** IMediaFilter methods **/
235
236 static HRESULT WINAPI VfwCapture_Stop(IBaseFilter * iface)
237 {
238     VfwCapture *This = (VfwCapture *)iface;
239
240     TRACE("()\n");
241     return qcap_driver_stop(This->driver_info, &This->filter.state);
242 }
243
244 static HRESULT WINAPI VfwCapture_Pause(IBaseFilter * iface)
245 {
246     VfwCapture *This = (VfwCapture *)iface;
247
248     TRACE("()\n");
249     return qcap_driver_pause(This->driver_info, &This->filter.state);
250 }
251
252 static HRESULT WINAPI VfwCapture_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
253 {
254     VfwCapture *This = (VfwCapture *)iface;
255     TRACE("(%x%08x)\n", (ULONG)(tStart >> 32), (ULONG)tStart);
256     return qcap_driver_run(This->driver_info, &This->filter.state);
257 }
258
259 /** IBaseFilter methods **/
260 static HRESULT WINAPI VfwCapture_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
261 {
262     FIXME("(%s, %p) - stub\n", debugstr_w(Id), ppPin);
263     return E_NOTIMPL;
264 }
265
266 static const IBaseFilterVtbl VfwCapture_Vtbl =
267 {
268     VfwCapture_QueryInterface,
269     BaseFilterImpl_AddRef,
270     VfwCapture_Release,
271     BaseFilterImpl_GetClassID,
272     VfwCapture_Stop,
273     VfwCapture_Pause,
274     VfwCapture_Run,
275     BaseFilterImpl_GetState,
276     BaseFilterImpl_SetSyncSource,
277     BaseFilterImpl_GetSyncSource,
278     BaseFilterImpl_EnumPins,
279     VfwCapture_FindPin,
280     BaseFilterImpl_QueryFilterInfo,
281     BaseFilterImpl_JoinFilterGraph,
282     BaseFilterImpl_QueryVendorInfo
283 };
284
285 /* AMStreamConfig interface, we only need to implement {G,S}etFormat */
286 static HRESULT WINAPI
287 AMStreamConfig_QueryInterface( IAMStreamConfig * iface, REFIID riid, LPVOID * ppv )
288 {
289     VfwCapture *This = impl_from_IAMStreamConfig(iface);
290
291     TRACE("%p --> %s\n", This, debugstr_guid(riid));
292
293     if (IsEqualIID(riid, &IID_IUnknown) ||
294         IsEqualIID(riid, &IID_IAMStreamConfig))
295     {
296         IAMStreamConfig_AddRef(iface);
297         *ppv = iface;
298         return S_OK;
299     }
300
301     FIXME("No interface for iid %s\n", debugstr_guid(riid));
302     return E_NOINTERFACE;
303 }
304
305 static ULONG WINAPI AMStreamConfig_AddRef( IAMStreamConfig * iface )
306 {
307     VfwCapture *This = impl_from_IAMStreamConfig(iface);
308
309     TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This);
310     return IUnknown_AddRef((IUnknown *)This);
311 }
312
313 static ULONG WINAPI AMStreamConfig_Release( IAMStreamConfig * iface )
314 {
315     VfwCapture *This = impl_from_IAMStreamConfig(iface);
316
317     TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This);
318     return IUnknown_Release((IUnknown *)This);
319 }
320
321 static HRESULT WINAPI
322 AMStreamConfig_SetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE *pmt)
323 {
324     HRESULT hr;
325     VfwCapture *This = impl_from_IAMStreamConfig(iface);
326     BasePin *pin;
327
328     TRACE("(%p): %p->%p\n", iface, pmt, pmt ? pmt->pbFormat : NULL);
329
330     if (This->filter.state != State_Stopped)
331     {
332         TRACE("Returning not stopped error\n");
333         return VFW_E_NOT_STOPPED;
334     }
335
336     if (!pmt)
337     {
338         TRACE("pmt is NULL\n");
339         return E_POINTER;
340     }
341
342     dump_AM_MEDIA_TYPE(pmt);
343
344     pin = (BasePin *)This->pOutputPin;
345     if (pin->pConnectedTo != NULL)
346     {
347         hr = IPin_QueryAccept(pin->pConnectedTo, pmt);
348         TRACE("Would accept: %d\n", hr);
349         if (hr == S_FALSE)
350             return VFW_E_INVALIDMEDIATYPE;
351     }
352
353     hr = qcap_driver_set_format(This->driver_info, pmt);
354     if (SUCCEEDED(hr) && This->filter.filterInfo.pGraph && pin->pConnectedTo )
355     {
356         hr = IFilterGraph_Reconnect(This->filter.filterInfo.pGraph, This->pOutputPin);
357         if (SUCCEEDED(hr))
358             TRACE("Reconnection completed, with new media format..\n");
359     }
360     TRACE("Returning: %d\n", hr);
361     return hr;
362 }
363
364 static HRESULT WINAPI
365 AMStreamConfig_GetFormat( IAMStreamConfig *iface, AM_MEDIA_TYPE **pmt )
366 {
367     VfwCapture *This = impl_from_IAMStreamConfig(iface);
368
369     TRACE("%p -> (%p)\n", iface, pmt);
370     return qcap_driver_get_format(This->driver_info, pmt);
371 }
372
373 static HRESULT WINAPI
374 AMStreamConfig_GetNumberOfCapabilities( IAMStreamConfig *iface, int *piCount,
375                                         int *piSize )
376 {
377     FIXME("%p: %p %p - stub, intentional\n", iface, piCount, piSize);
378     return E_NOTIMPL; /* Not implemented for this interface */
379 }
380
381 static HRESULT WINAPI
382 AMStreamConfig_GetStreamCaps( IAMStreamConfig *iface, int iIndex,
383                               AM_MEDIA_TYPE **pmt, BYTE *pSCC )
384 {
385     FIXME("%p: %d %p %p - stub, intentional\n", iface, iIndex, pmt, pSCC);
386     return E_NOTIMPL; /* Not implemented for this interface */
387 }
388
389 static const IAMStreamConfigVtbl IAMStreamConfig_VTable =
390 {
391     AMStreamConfig_QueryInterface,
392     AMStreamConfig_AddRef,
393     AMStreamConfig_Release,
394     AMStreamConfig_SetFormat,
395     AMStreamConfig_GetFormat,
396     AMStreamConfig_GetNumberOfCapabilities,
397     AMStreamConfig_GetStreamCaps
398 };
399
400 static HRESULT WINAPI
401 AMVideoProcAmp_QueryInterface( IAMVideoProcAmp * iface, REFIID riid,
402                                LPVOID * ppv )
403 {
404     if (IsEqualIID(riid, &IID_IUnknown) ||
405         IsEqualIID(riid, &IID_IAMVideoProcAmp))
406     {
407         *ppv = iface;
408         IAMVideoProcAmp_AddRef( iface );
409         return S_OK;
410     }
411
412     FIXME("No interface for iid %s\n", debugstr_guid(riid));
413     return E_NOINTERFACE;
414 }
415
416 static ULONG WINAPI AMVideoProcAmp_AddRef(IAMVideoProcAmp * iface)
417 {
418     VfwCapture *This = impl_from_IAMVideoProcAmp(iface);
419
420     return IUnknown_AddRef((IUnknown *)This);
421 }
422
423 static ULONG WINAPI AMVideoProcAmp_Release(IAMVideoProcAmp * iface)
424 {
425     VfwCapture *This = impl_from_IAMVideoProcAmp(iface);
426
427     return IUnknown_Release((IUnknown *)This);
428 }
429
430 static HRESULT WINAPI
431 AMVideoProcAmp_GetRange( IAMVideoProcAmp * iface, LONG Property, LONG *pMin,
432         LONG *pMax, LONG *pSteppingDelta, LONG *pDefault, LONG *pCapsFlags )
433 {
434     VfwCapture *This = impl_from_IAMVideoProcAmp(iface);
435
436     return qcap_driver_get_prop_range( This->driver_info, Property, pMin, pMax,
437                    pSteppingDelta, pDefault, pCapsFlags );
438 }
439
440 static HRESULT WINAPI
441 AMVideoProcAmp_Set( IAMVideoProcAmp * iface, LONG Property, LONG lValue,
442                     LONG Flags )
443 {
444     VfwCapture *This = impl_from_IAMVideoProcAmp(iface);
445
446     return qcap_driver_set_prop(This->driver_info, Property, lValue, Flags);
447 }
448
449 static HRESULT WINAPI
450 AMVideoProcAmp_Get( IAMVideoProcAmp * iface, LONG Property, LONG *lValue,
451                     LONG *Flags )
452 {
453     VfwCapture *This = impl_from_IAMVideoProcAmp(iface);
454
455     return qcap_driver_get_prop(This->driver_info, Property, lValue, Flags);
456 }
457
458 static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable =
459 {
460     AMVideoProcAmp_QueryInterface,
461     AMVideoProcAmp_AddRef,
462     AMVideoProcAmp_Release,
463     AMVideoProcAmp_GetRange,
464     AMVideoProcAmp_Set,
465     AMVideoProcAmp_Get,
466 };
467
468 static HRESULT WINAPI
469 PPB_QueryInterface( IPersistPropertyBag * iface, REFIID riid, LPVOID * ppv )
470 {
471     if (IsEqualIID(riid, &IID_IUnknown) ||
472         IsEqualIID(riid, &IID_IPersist) ||
473         IsEqualIID(riid, &IID_IPersistPropertyBag))
474     {
475         IPersistPropertyBag_AddRef(iface);
476         *ppv = iface;
477         return S_OK;
478     }
479     if (IsEqualIID(riid, &IID_IBaseFilter))
480     {
481         /* FIXME: native devenum asks for IBaseFilter, should we return it? */
482         IPersistPropertyBag_AddRef(iface);
483         *ppv = iface;
484         return S_OK;
485     }
486
487     FIXME("No interface for iid %s\n", debugstr_guid(riid));
488     return E_NOINTERFACE;
489 }
490
491 static ULONG WINAPI PPB_AddRef(IPersistPropertyBag * iface)
492 {
493     VfwCapture *This = impl_from_IPersistPropertyBag(iface);
494
495     TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This);
496
497     return IUnknown_AddRef((IUnknown *)This);
498 }
499
500 static ULONG WINAPI PPB_Release(IPersistPropertyBag * iface)
501 {
502     VfwCapture *This = impl_from_IPersistPropertyBag(iface);
503
504     TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This);
505
506     return IUnknown_Release((IUnknown *)This);
507 }
508
509 static HRESULT WINAPI
510 PPB_GetClassID( IPersistPropertyBag * iface, CLSID * pClassID )
511 {
512     VfwCapture *This = impl_from_IPersistPropertyBag(iface);
513
514     FIXME("%p - stub\n", This);
515
516     return E_NOTIMPL;
517 }
518
519 static HRESULT WINAPI PPB_InitNew(IPersistPropertyBag * iface)
520 {
521     VfwCapture *This = impl_from_IPersistPropertyBag(iface);
522
523     FIXME("%p - stub\n", This);
524
525     return E_NOTIMPL;
526 }
527
528 static HRESULT WINAPI
529 PPB_Load( IPersistPropertyBag * iface, IPropertyBag *pPropBag,
530           IErrorLog *pErrorLog )
531 {
532     VfwCapture *This = impl_from_IPersistPropertyBag(iface);
533     HRESULT hr;
534     VARIANT var;
535     const OLECHAR VFWIndex[] = {'V','F','W','I','n','d','e','x',0};
536
537     TRACE("%p/%p-> (%p, %p)\n", iface, This, pPropBag, pErrorLog);
538
539     V_VT(&var) = VT_I4;
540     hr = IPropertyBag_Read(pPropBag, VFWIndex, &var, pErrorLog);
541
542     if (SUCCEEDED(hr))
543     {
544         VfwPinImpl *pin;
545
546         This->driver_info = qcap_driver_init( This->pOutputPin,
547                var.__VARIANT_NAME_1.__VARIANT_NAME_2.__VARIANT_NAME_3.ulVal );
548         if (This->driver_info)
549         {
550             pin = (VfwPinImpl *)This->pOutputPin;
551             pin->driver_info = This->driver_info;
552             pin->parent = This;
553             This->init = TRUE;
554             hr = S_OK;
555         }
556         else
557             hr = E_FAIL;
558     }
559
560     return hr;
561 }
562
563 static HRESULT WINAPI
564 PPB_Save( IPersistPropertyBag * iface, IPropertyBag *pPropBag,
565           BOOL fClearDirty, BOOL fSaveAllProperties )
566 {
567     VfwCapture *This = impl_from_IPersistPropertyBag(iface);
568     FIXME("%p - stub\n", This);
569     return E_NOTIMPL;
570 }
571
572 static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable =
573 {
574     PPB_QueryInterface,
575     PPB_AddRef,
576     PPB_Release,
577     PPB_GetClassID,
578     PPB_InitNew,
579     PPB_Load,
580     PPB_Save
581 };
582
583 /* IKsPropertySet interface */
584 static HRESULT WINAPI
585 KSP_QueryInterface( IKsPropertySet * iface, REFIID riid, LPVOID * ppv )
586 {
587     if (IsEqualIID(riid, &IID_IUnknown) ||
588         IsEqualIID(riid, &IID_IKsPropertySet))
589     {
590         *ppv = iface;
591         IKsPropertySet_AddRef( iface );
592         return S_OK;
593     }
594
595     FIXME("No interface for iid %s\n", debugstr_guid(riid));
596     return E_NOINTERFACE;
597 }
598
599 static ULONG WINAPI KSP_AddRef(IKsPropertySet * iface)
600 {
601     ICOM_THIS_MULTI(VfwPinImpl, KSP_VT, iface);
602
603     TRACE("%p --> Forwarding to VfwPin (%p)\n", iface, This);
604
605     return IUnknown_AddRef((IUnknown *)This);
606 }
607
608 static ULONG WINAPI KSP_Release(IKsPropertySet * iface)
609 {
610     ICOM_THIS_MULTI(VfwPinImpl, KSP_VT, iface);
611
612     TRACE("%p --> Forwarding to VfwPin (%p)\n", iface, This);
613
614     return IUnknown_Release((IUnknown *)This);
615 }
616
617 static HRESULT WINAPI
618 KSP_Set( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID,
619          LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData,
620          DWORD cbPropData )
621 {
622     FIXME("%p: stub\n", iface);
623     return E_NOTIMPL;
624 }
625
626 static HRESULT WINAPI
627 KSP_Get( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID,
628          LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData,
629          DWORD cbPropData, DWORD *pcbReturned )
630 {
631     LPGUID pGuid;
632
633     TRACE("()\n");
634
635     if (!IsEqualIID(guidPropSet, &AMPROPSETID_Pin))
636         return E_PROP_SET_UNSUPPORTED;
637     if (pPropData == NULL && pcbReturned == NULL)
638         return E_POINTER;
639     if (pcbReturned)
640         *pcbReturned = sizeof(GUID);
641     if (pPropData == NULL)
642         return S_OK;
643     if (cbPropData < sizeof(GUID))
644         return E_UNEXPECTED;
645     pGuid = pPropData;
646     *pGuid = PIN_CATEGORY_PREVIEW;
647     FIXME("() Not adding a pin with PIN_CATEGORY_CAPTURE\n");
648     return S_OK;
649 }
650
651 static HRESULT WINAPI
652 KSP_QuerySupported( IKsPropertySet * iface, REFGUID guidPropSet,
653                     DWORD dwPropID, DWORD *pTypeSupport )
654 {
655    FIXME("%p: stub\n", iface);
656    return E_NOTIMPL;
657 }
658
659 static const IKsPropertySetVtbl KSP_VTable =
660 {
661    KSP_QueryInterface,
662    KSP_AddRef,
663    KSP_Release,
664    KSP_Set,
665    KSP_Get,
666    KSP_QuerySupported
667 };
668
669 static HRESULT WINAPI VfwPin_GetMediaType(BasePin *iface, int iPosition, AM_MEDIA_TYPE *pmt)
670 {
671     VfwPinImpl *This = (VfwPinImpl *)iface;
672     AM_MEDIA_TYPE *vfw_pmt;
673     HRESULT hr;
674
675     if (iPosition < 0)
676         return E_INVALIDARG;
677     if (iPosition > 0)
678         return VFW_S_NO_MORE_ITEMS;
679
680     hr = qcap_driver_get_format(This->driver_info, &vfw_pmt);
681     if (SUCCEEDED(hr)) {
682         CopyMediaType(pmt, vfw_pmt);
683         DeleteMediaType(vfw_pmt);
684     }
685     return hr;
686 }
687
688 static LONG WINAPI VfwPin_GetMediaTypeVersion(BasePin *iface)
689 {
690     return 1;
691 }
692
693 static HRESULT WINAPI VfwPin_DecideBufferSize(BaseOutputPin *iface, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
694 {
695     ALLOCATOR_PROPERTIES actual;
696
697     /* What we put here doesn't matter, the
698        driver function should override it then commit */
699     if (!ppropInputRequest->cBuffers)
700         ppropInputRequest->cBuffers = 3;
701     if (!ppropInputRequest->cbBuffer)
702         ppropInputRequest->cbBuffer = 230400;
703     if (!ppropInputRequest->cbAlign)
704         ppropInputRequest->cbAlign = 1;
705
706     return IMemAllocator_SetProperties(pAlloc, ppropInputRequest, &actual);
707 }
708
709 static const  BasePinFuncTable output_BaseFuncTable = {
710     NULL,
711     BaseOutputPinImpl_AttemptConnection,
712     VfwPin_GetMediaTypeVersion,
713     VfwPin_GetMediaType
714 };
715
716 static const BaseOutputPinFuncTable output_BaseOutputFuncTable = {
717     VfwPin_DecideBufferSize,
718     BaseOutputPinImpl_DecideAllocator,
719     BaseOutputPinImpl_BreakConnect
720 };
721
722 static HRESULT
723 VfwPin_Construct( IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec,
724                   IPin ** ppPin )
725 {
726     static const WCHAR wszOutputPinName[] = { 'O','u','t','p','u','t',0 };
727     PIN_INFO piOutput;
728     HRESULT hr;
729
730     *ppPin = NULL;
731
732     piOutput.dir = PINDIR_OUTPUT;
733     piOutput.pFilter = pBaseFilter;
734     lstrcpyW(piOutput.achName, wszOutputPinName);
735     ObjectRefCount(TRUE);
736
737     hr = BaseOutputPin_Construct(&VfwPin_Vtbl, sizeof(VfwPinImpl), &piOutput, &output_BaseFuncTable, &output_BaseOutputFuncTable, pCritSec, ppPin);
738
739     if (SUCCEEDED(hr))
740     {
741         VfwPinImpl *pPinImpl = (VfwPinImpl*)*ppPin;
742         pPinImpl->KSP_VT = &KSP_VTable;
743     }
744
745     return hr;
746 }
747
748 static HRESULT WINAPI VfwPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
749 {
750     VfwPinImpl *This = (VfwPinImpl *)iface;
751
752     TRACE("%s %p\n", debugstr_guid(riid), ppv);
753
754     *ppv = NULL;
755     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin))
756         *ppv = This;
757     else if (IsEqualIID(riid, &IID_IKsPropertySet))
758         *ppv = &(This->KSP_VT);
759     else if (IsEqualIID(riid, &IID_IAMStreamConfig))
760         return IUnknown_QueryInterface((IUnknown *)This->parent, riid, ppv);
761
762     if (*ppv)
763     {
764         IUnknown_AddRef((IUnknown *)(*ppv));
765         return S_OK;
766     }
767
768     FIXME("No interface for %s!\n", debugstr_guid(riid));
769     return E_NOINTERFACE;
770 }
771
772 static ULONG WINAPI
773 VfwPin_Release(IPin * iface)
774 {
775    VfwPinImpl *This = (VfwPinImpl *)iface;
776    ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
777
778    TRACE("() -> new refcount: %u\n", refCount);
779
780    if (!refCount)
781    {
782       CoTaskMemFree(This);
783       ObjectRefCount(FALSE);
784    }
785    return refCount;
786 }
787
788 static HRESULT WINAPI
789 VfwPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
790 {
791     AM_MEDIA_TYPE *pmt;
792     HRESULT hr;
793
794     VfwPinImpl *This = (VfwPinImpl *)iface;
795     hr = qcap_driver_get_format(This->driver_info, &pmt);
796     if (SUCCEEDED(hr)) {
797         hr = BasePinImpl_EnumMediaTypes(iface, ppEnum);
798         DeleteMediaType(pmt);
799     }
800     TRACE("%p -- %x\n", This, hr);
801     return hr;
802 }
803
804 static HRESULT WINAPI
805 VfwPin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
806 {
807     TRACE("(%p)->(%p, %p)\n", iface, apPin, cPin);
808     return E_NOTIMPL;
809 }
810
811 static const IPinVtbl VfwPin_Vtbl =
812 {
813     VfwPin_QueryInterface,
814     BasePinImpl_AddRef,
815     VfwPin_Release,
816     BaseOutputPinImpl_Connect,
817     BaseOutputPinImpl_ReceiveConnection,
818     BaseOutputPinImpl_Disconnect,
819     BasePinImpl_ConnectedTo,
820     BasePinImpl_ConnectionMediaType,
821     BasePinImpl_QueryPinInfo,
822     BasePinImpl_QueryDirection,
823     BasePinImpl_QueryId,
824     BasePinImpl_QueryAccept,
825     VfwPin_EnumMediaTypes,
826     VfwPin_QueryInternalConnections,
827     BaseOutputPinImpl_EndOfStream,
828     BaseOutputPinImpl_BeginFlush,
829     BaseOutputPinImpl_EndFlush,
830     BasePinImpl_NewSegment
831 };