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, &ROPSETID_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