hid: Rewrite HidP_SetUsageValue using enum_value_caps.
[wine.git] / dlls / qcap / vfwcapture.c
blobae073b845e0b2e23752da571ecf315cd22780f7a
1 /* Video For Windows Steering structure
3 * Copyright 2005 Maarten Lankhorst
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.
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.
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
21 #include "qcap_private.h"
22 #include "winternl.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(qcap);
26 static const struct video_capture_funcs *capture_funcs;
28 struct vfw_capture
30 struct strmbase_filter filter;
31 IAMStreamConfig IAMStreamConfig_iface;
32 IAMVideoControl IAMVideoControl_iface;
33 IAMVideoProcAmp IAMVideoProcAmp_iface;
34 IAMFilterMiscFlags IAMFilterMiscFlags_iface;
35 IPersistPropertyBag IPersistPropertyBag_iface;
36 BOOL init;
38 struct strmbase_source source;
39 IKsPropertySet IKsPropertySet_iface;
41 struct video_capture_device *device;
43 /* FIXME: It would be nice to avoid duplicating this variable with strmbase.
44 * However, synchronization is tricky; we need access to be protected by a
45 * separate lock. */
46 FILTER_STATE state;
47 CONDITION_VARIABLE state_cv;
48 CRITICAL_SECTION state_cs;
50 HANDLE thread;
53 static inline struct vfw_capture *impl_from_strmbase_filter(struct strmbase_filter *iface)
55 return CONTAINING_RECORD(iface, struct vfw_capture, filter);
58 static inline struct vfw_capture *impl_from_IAMStreamConfig(IAMStreamConfig *iface)
60 return CONTAINING_RECORD(iface, struct vfw_capture, IAMStreamConfig_iface);
63 static inline struct vfw_capture *impl_from_IAMVideoControl(IAMVideoControl *iface)
65 return CONTAINING_RECORD(iface, struct vfw_capture, IAMVideoControl_iface);
68 static inline struct vfw_capture *impl_from_IAMVideoProcAmp(IAMVideoProcAmp *iface)
70 return CONTAINING_RECORD(iface, struct vfw_capture, IAMVideoProcAmp_iface);
73 static inline struct vfw_capture *impl_from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface)
75 return CONTAINING_RECORD(iface, struct vfw_capture, IAMFilterMiscFlags_iface);
78 static inline struct vfw_capture *impl_from_IPersistPropertyBag(IPersistPropertyBag *iface)
80 return CONTAINING_RECORD(iface, struct vfw_capture, IPersistPropertyBag_iface);
83 static struct strmbase_pin *vfw_capture_get_pin(struct strmbase_filter *iface, unsigned int index)
85 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
87 if (index >= 1)
88 return NULL;
90 return &filter->source.pin;
93 static void vfw_capture_destroy(struct strmbase_filter *iface)
95 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
97 if (filter->init)
98 capture_funcs->destroy(filter->device);
100 if (filter->source.pin.peer)
102 IPin_Disconnect(filter->source.pin.peer);
103 IPin_Disconnect(&filter->source.pin.IPin_iface);
105 filter->state_cs.DebugInfo->Spare[0] = 0;
106 DeleteCriticalSection(&filter->state_cs);
107 strmbase_source_cleanup(&filter->source);
108 strmbase_filter_cleanup(&filter->filter);
109 free(filter);
110 ObjectRefCount(FALSE);
113 static HRESULT vfw_capture_query_interface(struct strmbase_filter *iface, REFIID iid, void **out)
115 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
117 if (IsEqualGUID(iid, &IID_IPersistPropertyBag))
118 *out = &filter->IPersistPropertyBag_iface;
119 else if (IsEqualGUID(iid, &IID_IAMVideoControl))
120 *out = &filter->IAMVideoControl_iface;
121 else if (IsEqualGUID(iid, &IID_IAMVideoProcAmp))
122 *out = &filter->IAMVideoProcAmp_iface;
123 else if (IsEqualGUID(iid, &IID_IAMFilterMiscFlags))
124 *out = &filter->IAMFilterMiscFlags_iface;
125 else
126 return E_NOINTERFACE;
128 IUnknown_AddRef((IUnknown *)*out);
129 return S_OK;
132 static unsigned int get_image_size(struct vfw_capture *filter)
134 const VIDEOINFOHEADER *format = (const VIDEOINFOHEADER *)filter->source.pin.mt.pbFormat;
136 return format->bmiHeader.biWidth * format->bmiHeader.biHeight * format->bmiHeader.biBitCount / 8;
139 static DWORD WINAPI stream_thread(void *arg)
141 struct vfw_capture *filter = arg;
142 const unsigned int image_size = get_image_size(filter);
144 for (;;)
146 IMediaSample *sample;
147 HRESULT hr;
148 BYTE *data;
150 EnterCriticalSection(&filter->state_cs);
152 while (filter->state == State_Paused)
153 SleepConditionVariableCS(&filter->state_cv, &filter->state_cs, INFINITE);
155 if (filter->state == State_Stopped)
157 LeaveCriticalSection(&filter->state_cs);
158 break;
161 LeaveCriticalSection(&filter->state_cs);
163 if (FAILED(hr = BaseOutputPinImpl_GetDeliveryBuffer(&filter->source, &sample, NULL, NULL, 0)))
165 ERR("Failed to get sample, hr %#x.\n", hr);
166 break;
169 IMediaSample_SetActualDataLength(sample, image_size);
170 IMediaSample_GetPointer(sample, &data);
172 if (!capture_funcs->read_frame(filter->device, data))
174 IMediaSample_Release(sample);
175 break;
178 hr = IMemInputPin_Receive(filter->source.pMemInputPin, sample);
179 IMediaSample_Release(sample);
180 if (FAILED(hr))
182 ERR("IMemInputPin::Receive() returned %#x.\n", hr);
183 break;
187 return 0;
190 static HRESULT vfw_capture_init_stream(struct strmbase_filter *iface)
192 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
193 ALLOCATOR_PROPERTIES req_props, ret_props;
194 HRESULT hr;
196 req_props.cBuffers = 3;
197 req_props.cbBuffer = get_image_size(filter);
198 req_props.cbAlign = 1;
199 req_props.cbPrefix = 0;
200 if (FAILED(hr = IMemAllocator_SetProperties(filter->source.pAllocator, &req_props, &ret_props))
201 && hr != VFW_E_ALREADY_COMMITTED)
202 ERR("Failed to set allocator properties (buffer size %u), hr %#x.\n", req_props.cbBuffer, hr);
204 if (FAILED(hr = IMemAllocator_Commit(filter->source.pAllocator)))
205 ERR("Failed to commit allocator, hr %#x.\n", hr);
207 EnterCriticalSection(&filter->state_cs);
208 filter->state = State_Paused;
209 LeaveCriticalSection(&filter->state_cs);
211 filter->thread = CreateThread(NULL, 0, stream_thread, filter, 0, NULL);
213 return S_OK;
216 static HRESULT vfw_capture_start_stream(struct strmbase_filter *iface, REFERENCE_TIME time)
218 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
220 EnterCriticalSection(&filter->state_cs);
221 filter->state = State_Running;
222 LeaveCriticalSection(&filter->state_cs);
223 WakeConditionVariable(&filter->state_cv);
224 return S_OK;
227 static HRESULT vfw_capture_stop_stream(struct strmbase_filter *iface)
229 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
231 EnterCriticalSection(&filter->state_cs);
232 filter->state = State_Paused;
233 LeaveCriticalSection(&filter->state_cs);
234 return S_OK;
237 static HRESULT vfw_capture_cleanup_stream(struct strmbase_filter *iface)
239 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
240 HRESULT hr;
242 EnterCriticalSection(&filter->state_cs);
243 filter->state = State_Stopped;
244 LeaveCriticalSection(&filter->state_cs);
245 WakeConditionVariable(&filter->state_cv);
247 WaitForSingleObject(filter->thread, INFINITE);
248 CloseHandle(filter->thread);
249 filter->thread = NULL;
251 hr = IMemAllocator_Decommit(filter->source.pAllocator);
252 if (hr != S_OK && hr != VFW_E_NOT_COMMITTED)
253 ERR("Failed to decommit allocator, hr %#x.\n", hr);
255 return S_OK;
258 static HRESULT vfw_capture_wait_state(struct strmbase_filter *iface, DWORD timeout)
260 return iface->state == State_Paused ? VFW_S_CANT_CUE : S_OK;
263 static const struct strmbase_filter_ops filter_ops =
265 .filter_get_pin = vfw_capture_get_pin,
266 .filter_destroy = vfw_capture_destroy,
267 .filter_query_interface = vfw_capture_query_interface,
268 .filter_init_stream = vfw_capture_init_stream,
269 .filter_start_stream = vfw_capture_start_stream,
270 .filter_stop_stream = vfw_capture_stop_stream,
271 .filter_cleanup_stream = vfw_capture_cleanup_stream,
272 .filter_wait_state = vfw_capture_wait_state,
275 static HRESULT WINAPI AMStreamConfig_QueryInterface(IAMStreamConfig *iface, REFIID iid, void **out)
277 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
278 return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out);
281 static ULONG WINAPI AMStreamConfig_AddRef(IAMStreamConfig *iface)
283 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
284 return IPin_AddRef(&filter->source.pin.IPin_iface);
287 static ULONG WINAPI AMStreamConfig_Release(IAMStreamConfig *iface)
289 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
290 return IPin_Release(&filter->source.pin.IPin_iface);
293 static HRESULT WINAPI
294 AMStreamConfig_SetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE *pmt)
296 struct vfw_capture *This = impl_from_IAMStreamConfig(iface);
297 HRESULT hr;
299 TRACE("filter %p, mt %p.\n", This, pmt);
300 strmbase_dump_media_type(pmt);
302 if (This->filter.state != State_Stopped)
304 TRACE("Returning not stopped error\n");
305 return VFW_E_NOT_STOPPED;
308 if (!pmt)
310 TRACE("pmt is NULL\n");
311 return E_POINTER;
314 if (!IsEqualGUID(&pmt->majortype, &MEDIATYPE_Video))
315 return E_FAIL;
317 if (This->source.pin.peer)
319 hr = IPin_QueryAccept(This->source.pin.peer, pmt);
320 TRACE("Would accept: %d\n", hr);
321 if (hr == S_FALSE)
322 return VFW_E_INVALIDMEDIATYPE;
325 hr = capture_funcs->set_format(This->device, pmt);
326 if (SUCCEEDED(hr) && This->filter.graph && This->source.pin.peer)
328 hr = IFilterGraph_Reconnect(This->filter.graph, &This->source.pin.IPin_iface);
329 if (SUCCEEDED(hr))
330 TRACE("Reconnection completed, with new media format..\n");
332 TRACE("Returning: %d\n", hr);
333 return hr;
336 static HRESULT WINAPI AMStreamConfig_GetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE **mt)
338 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
339 VIDEOINFOHEADER *format;
340 HRESULT hr;
342 TRACE("filter %p, mt %p.\n", filter, mt);
344 if (!(*mt = CoTaskMemAlloc(sizeof(**mt))))
345 return E_OUTOFMEMORY;
347 EnterCriticalSection(&filter->filter.filter_cs);
349 if (filter->source.pin.peer)
351 hr = CopyMediaType(*mt, &filter->source.pin.mt);
353 else
355 if ((format = CoTaskMemAlloc(sizeof(VIDEOINFOHEADER))))
357 capture_funcs->get_format(filter->device, *mt, format);
358 (*mt)->cbFormat = sizeof(VIDEOINFOHEADER);
359 (*mt)->pbFormat = (BYTE *)format;
360 hr = S_OK;
362 else
364 hr = E_OUTOFMEMORY;
368 LeaveCriticalSection(&filter->filter.filter_cs);
370 if (SUCCEEDED(hr))
371 strmbase_dump_media_type(*mt);
372 else
373 CoTaskMemFree(*mt);
374 return hr;
377 static HRESULT WINAPI AMStreamConfig_GetNumberOfCapabilities(IAMStreamConfig *iface,
378 int *count, int *size)
380 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
382 TRACE("filter %p, count %p, size %p.\n", filter, count, size);
384 if (!count || !size)
385 return E_POINTER;
387 *count = capture_funcs->get_caps_count(filter->device);
388 *size = sizeof(VIDEO_STREAM_CONFIG_CAPS);
390 return S_OK;
393 static HRESULT WINAPI AMStreamConfig_GetStreamCaps(IAMStreamConfig *iface,
394 int index, AM_MEDIA_TYPE **pmt, BYTE *vscc)
396 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
397 VIDEOINFOHEADER *format;
398 AM_MEDIA_TYPE *mt;
400 TRACE("filter %p, index %d, pmt %p, vscc %p.\n", filter, index, pmt, vscc);
402 if (index > capture_funcs->get_caps_count(filter->device))
403 return S_FALSE;
405 if (!(mt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
406 return E_OUTOFMEMORY;
408 if (!(format = CoTaskMemAlloc(sizeof(VIDEOINFOHEADER))))
410 CoTaskMemFree(mt);
411 return E_OUTOFMEMORY;
414 capture_funcs->get_caps(filter->device, index, mt, format, (VIDEO_STREAM_CONFIG_CAPS *)vscc);
415 mt->cbFormat = sizeof(VIDEOINFOHEADER);
416 mt->pbFormat = (BYTE *)format;
417 *pmt = mt;
418 return S_OK;
421 static const IAMStreamConfigVtbl IAMStreamConfig_VTable =
423 AMStreamConfig_QueryInterface,
424 AMStreamConfig_AddRef,
425 AMStreamConfig_Release,
426 AMStreamConfig_SetFormat,
427 AMStreamConfig_GetFormat,
428 AMStreamConfig_GetNumberOfCapabilities,
429 AMStreamConfig_GetStreamCaps
432 static HRESULT WINAPI AMVideoProcAmp_QueryInterface(IAMVideoProcAmp *iface, REFIID iid, void **out)
434 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
435 return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out);
438 static ULONG WINAPI AMVideoProcAmp_AddRef(IAMVideoProcAmp * iface)
440 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
441 return IUnknown_AddRef(filter->filter.outer_unk);
444 static ULONG WINAPI AMVideoProcAmp_Release(IAMVideoProcAmp * iface)
446 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
447 return IUnknown_Release(filter->filter.outer_unk);
450 static HRESULT WINAPI AMVideoProcAmp_GetRange(IAMVideoProcAmp *iface, LONG property,
451 LONG *min, LONG *max, LONG *step, LONG *default_value, LONG *flags)
453 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
455 TRACE("filter %p, property %#x, min %p, max %p, step %p, default_value %p, flags %p.\n",
456 filter, property, min, max, step, default_value, flags);
458 return capture_funcs->get_prop_range(filter->device, property, min,
459 max, step, default_value, flags);
462 static HRESULT WINAPI AMVideoProcAmp_Set(IAMVideoProcAmp *iface, LONG property,
463 LONG value, LONG flags)
465 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
467 TRACE("filter %p, property %#x, value %d, flags %#x.\n", filter, property, value, flags);
469 return capture_funcs->set_prop(filter->device, property, value, flags);
472 static HRESULT WINAPI AMVideoProcAmp_Get(IAMVideoProcAmp *iface, LONG property,
473 LONG *value, LONG *flags)
475 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
477 TRACE("filter %p, property %#x, value %p, flags %p.\n", filter, property, value, flags);
479 return capture_funcs->get_prop(filter->device, property, value, flags);
482 static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable =
484 AMVideoProcAmp_QueryInterface,
485 AMVideoProcAmp_AddRef,
486 AMVideoProcAmp_Release,
487 AMVideoProcAmp_GetRange,
488 AMVideoProcAmp_Set,
489 AMVideoProcAmp_Get,
492 static HRESULT WINAPI PPB_QueryInterface(IPersistPropertyBag *iface, REFIID iid, void **out)
494 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
495 return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out);
498 static ULONG WINAPI PPB_AddRef(IPersistPropertyBag * iface)
500 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
501 return IUnknown_AddRef(filter->filter.outer_unk);
504 static ULONG WINAPI PPB_Release(IPersistPropertyBag * iface)
506 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
507 return IUnknown_Release(filter->filter.outer_unk);
510 static HRESULT WINAPI
511 PPB_GetClassID( IPersistPropertyBag * iface, CLSID * pClassID )
513 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
515 FIXME("%p - stub\n", This);
517 return E_NOTIMPL;
520 static HRESULT WINAPI PPB_InitNew(IPersistPropertyBag * iface)
522 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
524 FIXME("%p - stub\n", This);
526 return E_NOTIMPL;
529 static HRESULT WINAPI PPB_Load(IPersistPropertyBag *iface, IPropertyBag *bag, IErrorLog *error_log)
531 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
532 HRESULT hr;
533 VARIANT var;
535 TRACE("filter %p, bag %p, error_log %p.\n", filter, bag, error_log);
537 V_VT(&var) = VT_I4;
538 if (FAILED(hr = IPropertyBag_Read(bag, L"VFWIndex", &var, error_log)))
539 return hr;
541 if (!(filter->device = capture_funcs->create(V_I4(&var))))
542 return E_FAIL;
544 filter->init = TRUE;
545 return S_OK;
548 static HRESULT WINAPI
549 PPB_Save( IPersistPropertyBag * iface, IPropertyBag *pPropBag,
550 BOOL fClearDirty, BOOL fSaveAllProperties )
552 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
553 FIXME("%p - stub\n", This);
554 return E_NOTIMPL;
557 static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable =
559 PPB_QueryInterface,
560 PPB_AddRef,
561 PPB_Release,
562 PPB_GetClassID,
563 PPB_InitNew,
564 PPB_Load,
565 PPB_Save
568 /* IKsPropertySet interface */
569 static inline struct vfw_capture *impl_from_IKsPropertySet(IKsPropertySet *iface)
571 return CONTAINING_RECORD(iface, struct vfw_capture, IKsPropertySet_iface);
574 static HRESULT WINAPI KSP_QueryInterface(IKsPropertySet *iface, REFIID iid, void **out)
576 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
577 return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out);
580 static ULONG WINAPI KSP_AddRef(IKsPropertySet * iface)
582 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
583 return IPin_AddRef(&filter->source.pin.IPin_iface);
586 static ULONG WINAPI KSP_Release(IKsPropertySet * iface)
588 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
589 return IPin_Release(&filter->source.pin.IPin_iface);
592 static HRESULT WINAPI
593 KSP_Set( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID,
594 LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData,
595 DWORD cbPropData )
597 FIXME("%p: stub\n", iface);
598 return E_NOTIMPL;
601 static HRESULT WINAPI
602 KSP_Get( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID,
603 LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData,
604 DWORD cbPropData, DWORD *pcbReturned )
606 LPGUID pGuid;
608 TRACE("()\n");
610 if (!IsEqualIID(guidPropSet, &AMPROPSETID_Pin))
611 return E_PROP_SET_UNSUPPORTED;
612 if (pPropData == NULL && pcbReturned == NULL)
613 return E_POINTER;
614 if (pcbReturned)
615 *pcbReturned = sizeof(GUID);
616 if (pPropData == NULL)
617 return S_OK;
618 if (cbPropData < sizeof(GUID))
619 return E_UNEXPECTED;
620 pGuid = pPropData;
621 *pGuid = PIN_CATEGORY_CAPTURE;
622 FIXME("() Not adding a pin with PIN_CATEGORY_PREVIEW\n");
623 return S_OK;
626 static HRESULT WINAPI
627 KSP_QuerySupported( IKsPropertySet * iface, REFGUID guidPropSet,
628 DWORD dwPropID, DWORD *pTypeSupport )
630 FIXME("%p: stub\n", iface);
631 return E_NOTIMPL;
634 static const IKsPropertySetVtbl IKsPropertySet_VTable =
636 KSP_QueryInterface,
637 KSP_AddRef,
638 KSP_Release,
639 KSP_Set,
640 KSP_Get,
641 KSP_QuerySupported
644 static inline struct vfw_capture *impl_from_strmbase_pin(struct strmbase_pin *pin)
646 return CONTAINING_RECORD(pin, struct vfw_capture, source.pin);
649 static HRESULT source_query_accept(struct strmbase_pin *pin, const AM_MEDIA_TYPE *mt)
651 struct vfw_capture *filter = impl_from_strmbase_pin(pin);
652 return capture_funcs->check_format(filter->device, mt);
655 static HRESULT source_get_media_type(struct strmbase_pin *pin,
656 unsigned int index, AM_MEDIA_TYPE *mt)
658 struct vfw_capture *filter = impl_from_strmbase_pin(pin);
659 VIDEOINFOHEADER *format;
660 HRESULT hr;
662 if (!(format = CoTaskMemAlloc(sizeof(*format))))
663 return E_OUTOFMEMORY;
665 if ((hr = capture_funcs->get_media_type(filter->device, index, mt, format)) != S_OK)
667 CoTaskMemFree(format);
668 return hr;
670 mt->cbFormat = sizeof(VIDEOINFOHEADER);
671 mt->pbFormat = (BYTE *)format;
672 return S_OK;
675 static HRESULT source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
677 struct vfw_capture *filter = impl_from_strmbase_pin(iface);
679 if (IsEqualGUID(iid, &IID_IKsPropertySet))
680 *out = &filter->IKsPropertySet_iface;
681 else if (IsEqualGUID(iid, &IID_IAMStreamConfig))
682 *out = &filter->IAMStreamConfig_iface;
683 else
684 return E_NOINTERFACE;
686 IUnknown_AddRef((IUnknown *)*out);
687 return S_OK;
690 static HRESULT WINAPI VfwPin_DecideBufferSize(struct strmbase_source *iface,
691 IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
693 ALLOCATOR_PROPERTIES actual;
695 /* What we put here doesn't matter, the
696 driver function should override it then commit */
697 if (!ppropInputRequest->cBuffers)
698 ppropInputRequest->cBuffers = 3;
699 if (!ppropInputRequest->cbBuffer)
700 ppropInputRequest->cbBuffer = 230400;
701 if (!ppropInputRequest->cbAlign)
702 ppropInputRequest->cbAlign = 1;
704 return IMemAllocator_SetProperties(pAlloc, ppropInputRequest, &actual);
707 static const struct strmbase_source_ops source_ops =
709 .base.pin_query_accept = source_query_accept,
710 .base.pin_get_media_type = source_get_media_type,
711 .base.pin_query_interface = source_query_interface,
712 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
713 .pfnDecideBufferSize = VfwPin_DecideBufferSize,
714 .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator,
717 static HRESULT WINAPI misc_flags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid, void **ppv)
719 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
720 return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppv);
723 static ULONG WINAPI misc_flags_AddRef(IAMFilterMiscFlags *iface)
725 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
726 return IUnknown_AddRef(filter->filter.outer_unk);
729 static ULONG WINAPI misc_flags_Release(IAMFilterMiscFlags *iface)
731 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
732 return IUnknown_Release(filter->filter.outer_unk);
735 static ULONG WINAPI misc_flags_GetMiscFlags(IAMFilterMiscFlags *iface)
737 return AM_FILTER_MISC_FLAGS_IS_SOURCE;
740 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_VTable =
742 misc_flags_QueryInterface,
743 misc_flags_AddRef,
744 misc_flags_Release,
745 misc_flags_GetMiscFlags
748 static HRESULT WINAPI video_control_QueryInterface(IAMVideoControl *iface, REFIID riid, void **ppv)
750 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
751 return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppv);
754 static ULONG WINAPI video_control_AddRef(IAMVideoControl *iface)
756 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
757 return IUnknown_AddRef(filter->filter.outer_unk);
760 static ULONG WINAPI video_control_Release(IAMVideoControl *iface)
762 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
763 return IUnknown_Release(filter->filter.outer_unk);
766 static HRESULT WINAPI video_control_GetCaps(IAMVideoControl *iface, IPin *pin, LONG *flags)
768 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
770 FIXME("filter %p, pin %p, flags %p: stub.\n", filter, pin, flags);
772 return E_NOTIMPL;
775 static HRESULT WINAPI video_control_SetMode(IAMVideoControl *iface, IPin *pin, LONG mode)
777 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
779 FIXME("filter %p, pin %p, mode %d: stub.\n", filter, pin, mode);
781 return E_NOTIMPL;
784 static HRESULT WINAPI video_control_GetMode(IAMVideoControl *iface, IPin *pin, LONG *mode)
786 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
788 FIXME("filter %p, pin %p, mode %p: stub.\n", filter, pin, mode);
790 return E_NOTIMPL;
793 static HRESULT WINAPI video_control_GetCurrentActualFrameRate(IAMVideoControl *iface, IPin *pin,
794 LONGLONG *frame_rate)
796 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
798 FIXME("filter %p, pin %p, frame rate %p: stub.\n", filter, pin, frame_rate);
800 return E_NOTIMPL;
803 static HRESULT WINAPI video_control_GetMaxAvailableFrameRate(IAMVideoControl *iface, IPin *pin,
804 LONG index, SIZE dimensions, LONGLONG *frame_rate)
806 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
808 FIXME("filter %p, pin %p, index %d, dimensions (%dx%d), frame rate %p: stub.\n",
809 filter, pin, index, dimensions.cx, dimensions.cy, frame_rate);
811 return E_NOTIMPL;
814 static HRESULT WINAPI video_control_GetFrameRateList(IAMVideoControl *iface, IPin *pin, LONG index,
815 SIZE dimensions, LONG *list_size, LONGLONG **frame_rate)
817 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
819 FIXME("filter %p, pin %p, index %d, dimensions (%dx%d), list size %p, frame rate: %p: stub.\n",
820 filter, pin, index, dimensions.cx, dimensions.cy, list_size, frame_rate);
822 return E_NOTIMPL;
825 static const IAMVideoControlVtbl IAMVideoControl_VTable =
827 video_control_QueryInterface,
828 video_control_AddRef,
829 video_control_Release,
830 video_control_GetCaps,
831 video_control_SetMode,
832 video_control_GetMode,
833 video_control_GetCurrentActualFrameRate,
834 video_control_GetMaxAvailableFrameRate,
835 video_control_GetFrameRateList
838 static BOOL WINAPI load_capture_funcs(INIT_ONCE *once, void *param, void **context)
840 __wine_init_unix_lib(qcap_instance, DLL_PROCESS_ATTACH, NULL, &capture_funcs);
841 return TRUE;
844 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
846 HRESULT vfw_capture_create(IUnknown *outer, IUnknown **out)
848 struct vfw_capture *object;
850 if (!InitOnceExecuteOnce(&init_once, load_capture_funcs, NULL, NULL) || !capture_funcs)
851 return E_FAIL;
853 if (!(object = calloc(1, sizeof(*object))))
854 return E_OUTOFMEMORY;
856 strmbase_filter_init(&object->filter, outer, &CLSID_VfwCapture, &filter_ops);
858 object->IAMStreamConfig_iface.lpVtbl = &IAMStreamConfig_VTable;
859 object->IAMVideoControl_iface.lpVtbl = &IAMVideoControl_VTable;
860 object->IAMVideoProcAmp_iface.lpVtbl = &IAMVideoProcAmp_VTable;
861 object->IAMFilterMiscFlags_iface.lpVtbl = &IAMFilterMiscFlags_VTable;
862 object->IPersistPropertyBag_iface.lpVtbl = &IPersistPropertyBag_VTable;
864 strmbase_source_init(&object->source, &object->filter, L"Output", &source_ops);
866 object->IKsPropertySet_iface.lpVtbl = &IKsPropertySet_VTable;
868 object->state = State_Stopped;
869 InitializeConditionVariable(&object->state_cv);
870 InitializeCriticalSection(&object->state_cs);
871 object->state_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": vfw_capture.state_cs");
873 TRACE("Created VFW capture filter %p.\n", object);
874 ObjectRefCount(TRUE);
875 *out = &object->filter.IUnknown_inner;
876 return S_OK;