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