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