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