qcap: Move the video capture streaming thread to vfwcapture.c.
[wine.git] / dlls / qcap / vfwcapture.c
blob9fb694ba6785a8a5879abd5f964207ca76d0e646
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"
23 WINE_DEFAULT_DEBUG_CHANNEL(qcap);
25 static const struct video_capture_funcs *capture_funcs;
27 struct vfw_capture
29 struct strmbase_filter filter;
30 IAMStreamConfig IAMStreamConfig_iface;
31 IAMVideoControl IAMVideoControl_iface;
32 IAMVideoProcAmp IAMVideoProcAmp_iface;
33 IAMFilterMiscFlags IAMFilterMiscFlags_iface;
34 IPersistPropertyBag IPersistPropertyBag_iface;
35 BOOL init;
37 struct strmbase_source source;
38 IKsPropertySet IKsPropertySet_iface;
40 struct video_capture_device *device;
42 /* FIXME: It would be nice to avoid duplicating this variable with strmbase.
43 * However, synchronization is tricky; we need access to be protected by a
44 * separate lock. */
45 FILTER_STATE state;
46 CONDITION_VARIABLE state_cv;
47 CRITICAL_SECTION state_cs;
49 HANDLE thread;
52 static inline struct vfw_capture *impl_from_strmbase_filter(struct strmbase_filter *iface)
54 return CONTAINING_RECORD(iface, struct vfw_capture, filter);
57 static inline struct vfw_capture *impl_from_IAMStreamConfig(IAMStreamConfig *iface)
59 return CONTAINING_RECORD(iface, struct vfw_capture, IAMStreamConfig_iface);
62 static inline struct vfw_capture *impl_from_IAMVideoControl(IAMVideoControl *iface)
64 return CONTAINING_RECORD(iface, struct vfw_capture, IAMVideoControl_iface);
67 static inline struct vfw_capture *impl_from_IAMVideoProcAmp(IAMVideoProcAmp *iface)
69 return CONTAINING_RECORD(iface, struct vfw_capture, IAMVideoProcAmp_iface);
72 static inline struct vfw_capture *impl_from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface)
74 return CONTAINING_RECORD(iface, struct vfw_capture, IAMFilterMiscFlags_iface);
77 static inline struct vfw_capture *impl_from_IPersistPropertyBag(IPersistPropertyBag *iface)
79 return CONTAINING_RECORD(iface, struct vfw_capture, IPersistPropertyBag_iface);
82 static struct strmbase_pin *vfw_capture_get_pin(struct strmbase_filter *iface, unsigned int index)
84 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
86 if (index >= 1)
87 return NULL;
89 return &filter->source.pin;
92 static void vfw_capture_destroy(struct strmbase_filter *iface)
94 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
96 if (filter->init)
98 if (filter->filter.state != State_Stopped)
99 capture_funcs->cleanup_stream(filter->device);
100 capture_funcs->destroy(filter->device);
103 if (filter->source.pin.peer)
105 IPin_Disconnect(filter->source.pin.peer);
106 IPin_Disconnect(&filter->source.pin.IPin_iface);
108 filter->state_cs.DebugInfo->Spare[0] = 0;
109 DeleteCriticalSection(&filter->state_cs);
110 strmbase_source_cleanup(&filter->source);
111 strmbase_filter_cleanup(&filter->filter);
112 CoTaskMemFree(filter);
113 ObjectRefCount(FALSE);
116 static HRESULT vfw_capture_query_interface(struct strmbase_filter *iface, REFIID iid, void **out)
118 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
120 if (IsEqualGUID(iid, &IID_IPersistPropertyBag))
121 *out = &filter->IPersistPropertyBag_iface;
122 else if (IsEqualGUID(iid, &IID_IAMVideoControl))
123 *out = &filter->IAMVideoControl_iface;
124 else if (IsEqualGUID(iid, &IID_IAMVideoProcAmp))
125 *out = &filter->IAMVideoProcAmp_iface;
126 else if (IsEqualGUID(iid, &IID_IAMFilterMiscFlags))
127 *out = &filter->IAMFilterMiscFlags_iface;
128 else
129 return E_NOINTERFACE;
131 IUnknown_AddRef((IUnknown *)*out);
132 return S_OK;
135 static DWORD WINAPI stream_thread(void *arg)
137 struct vfw_capture *filter = arg;
138 const VIDEOINFOHEADER *format = (const VIDEOINFOHEADER *)filter->source.pin.mt.pbFormat;
139 const unsigned int image_size = format->bmiHeader.biWidth
140 * format->bmiHeader.biHeight * format->bmiHeader.biBitCount / 8;
142 for (;;)
144 IMediaSample *sample;
145 HRESULT hr;
146 BYTE *data;
148 EnterCriticalSection(&filter->state_cs);
150 while (filter->state == State_Paused)
151 SleepConditionVariableCS(&filter->state_cv, &filter->state_cs, INFINITE);
153 if (filter->state == State_Stopped)
155 LeaveCriticalSection(&filter->state_cs);
156 break;
159 LeaveCriticalSection(&filter->state_cs);
161 if (FAILED(hr = BaseOutputPinImpl_GetDeliveryBuffer(&filter->source, &sample, NULL, NULL, 0)))
163 ERR("Failed to get sample, hr %#x.\n", hr);
164 break;
167 IMediaSample_SetActualDataLength(sample, image_size);
168 IMediaSample_GetPointer(sample, &data);
170 if (!capture_funcs->read_frame(filter->device, data))
172 IMediaSample_Release(sample);
173 break;
176 hr = IMemInputPin_Receive(filter->source.pMemInputPin, sample);
177 IMediaSample_Release(sample);
178 if (FAILED(hr))
180 ERR("IMemInputPin::Receive() returned %#x.\n", hr);
181 break;
185 return 0;
188 static HRESULT vfw_capture_init_stream(struct strmbase_filter *iface)
190 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
192 capture_funcs->init_stream(filter->device);
194 EnterCriticalSection(&filter->state_cs);
195 filter->state = State_Paused;
196 LeaveCriticalSection(&filter->state_cs);
198 filter->thread = CreateThread(NULL, 0, stream_thread, filter, 0, NULL);
200 return S_OK;
203 static HRESULT vfw_capture_start_stream(struct strmbase_filter *iface, REFERENCE_TIME time)
205 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
207 EnterCriticalSection(&filter->state_cs);
208 filter->state = State_Running;
209 LeaveCriticalSection(&filter->state_cs);
210 WakeConditionVariable(&filter->state_cv);
211 return S_OK;
214 static HRESULT vfw_capture_stop_stream(struct strmbase_filter *iface)
216 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
218 EnterCriticalSection(&filter->state_cs);
219 filter->state = State_Paused;
220 LeaveCriticalSection(&filter->state_cs);
221 return S_OK;
224 static HRESULT vfw_capture_cleanup_stream(struct strmbase_filter *iface)
226 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
228 EnterCriticalSection(&filter->state_cs);
229 filter->state = State_Stopped;
230 LeaveCriticalSection(&filter->state_cs);
231 WakeConditionVariable(&filter->state_cv);
233 WaitForSingleObject(filter->thread, INFINITE);
234 CloseHandle(filter->thread);
235 filter->thread = NULL;
237 capture_funcs->cleanup_stream(filter->device);
238 return S_OK;
241 static HRESULT vfw_capture_wait_state(struct strmbase_filter *iface, DWORD timeout)
243 return iface->state == State_Paused ? VFW_S_CANT_CUE : S_OK;
246 static const struct strmbase_filter_ops filter_ops =
248 .filter_get_pin = vfw_capture_get_pin,
249 .filter_destroy = vfw_capture_destroy,
250 .filter_query_interface = vfw_capture_query_interface,
251 .filter_init_stream = vfw_capture_init_stream,
252 .filter_start_stream = vfw_capture_start_stream,
253 .filter_stop_stream = vfw_capture_stop_stream,
254 .filter_cleanup_stream = vfw_capture_cleanup_stream,
255 .filter_wait_state = vfw_capture_wait_state,
258 static HRESULT WINAPI AMStreamConfig_QueryInterface(IAMStreamConfig *iface, REFIID iid, void **out)
260 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
261 return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out);
264 static ULONG WINAPI AMStreamConfig_AddRef(IAMStreamConfig *iface)
266 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
267 return IPin_AddRef(&filter->source.pin.IPin_iface);
270 static ULONG WINAPI AMStreamConfig_Release(IAMStreamConfig *iface)
272 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
273 return IPin_Release(&filter->source.pin.IPin_iface);
276 static HRESULT WINAPI
277 AMStreamConfig_SetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE *pmt)
279 struct vfw_capture *This = impl_from_IAMStreamConfig(iface);
280 HRESULT hr;
282 TRACE("filter %p, mt %p.\n", This, pmt);
283 strmbase_dump_media_type(pmt);
285 if (This->filter.state != State_Stopped)
287 TRACE("Returning not stopped error\n");
288 return VFW_E_NOT_STOPPED;
291 if (!pmt)
293 TRACE("pmt is NULL\n");
294 return E_POINTER;
297 if (!IsEqualGUID(&pmt->majortype, &MEDIATYPE_Video))
298 return E_FAIL;
300 if (This->source.pin.peer)
302 hr = IPin_QueryAccept(This->source.pin.peer, pmt);
303 TRACE("Would accept: %d\n", hr);
304 if (hr == S_FALSE)
305 return VFW_E_INVALIDMEDIATYPE;
308 hr = capture_funcs->set_format(This->device, pmt);
309 if (SUCCEEDED(hr) && This->filter.graph && This->source.pin.peer)
311 hr = IFilterGraph_Reconnect(This->filter.graph, &This->source.pin.IPin_iface);
312 if (SUCCEEDED(hr))
313 TRACE("Reconnection completed, with new media format..\n");
315 TRACE("Returning: %d\n", hr);
316 return hr;
319 static HRESULT WINAPI AMStreamConfig_GetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE **mt)
321 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
322 HRESULT hr;
324 TRACE("filter %p, mt %p.\n", filter, mt);
326 if (!(*mt = CoTaskMemAlloc(sizeof(**mt))))
327 return E_OUTOFMEMORY;
329 if (SUCCEEDED(hr = capture_funcs->get_format(filter->device, *mt)))
330 strmbase_dump_media_type(*mt);
331 return hr;
334 static HRESULT WINAPI AMStreamConfig_GetNumberOfCapabilities(IAMStreamConfig *iface,
335 int *count, int *size)
337 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
339 TRACE("filter %p, count %p, size %p.\n", filter, count, size);
341 if (!count || !size)
342 return E_POINTER;
344 *count = capture_funcs->get_caps_count(filter->device);
345 *size = sizeof(VIDEO_STREAM_CONFIG_CAPS);
347 return S_OK;
350 static HRESULT WINAPI AMStreamConfig_GetStreamCaps(IAMStreamConfig *iface,
351 int index, AM_MEDIA_TYPE **pmt, BYTE *vscc)
353 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
355 TRACE("filter %p, index %d, pmt %p, vscc %p.\n", filter, index, pmt, vscc);
357 return capture_funcs->get_caps(filter->device, index, pmt, (VIDEO_STREAM_CONFIG_CAPS *)vscc);
360 static const IAMStreamConfigVtbl IAMStreamConfig_VTable =
362 AMStreamConfig_QueryInterface,
363 AMStreamConfig_AddRef,
364 AMStreamConfig_Release,
365 AMStreamConfig_SetFormat,
366 AMStreamConfig_GetFormat,
367 AMStreamConfig_GetNumberOfCapabilities,
368 AMStreamConfig_GetStreamCaps
371 static HRESULT WINAPI AMVideoProcAmp_QueryInterface(IAMVideoProcAmp *iface, REFIID iid, void **out)
373 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
374 return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out);
377 static ULONG WINAPI AMVideoProcAmp_AddRef(IAMVideoProcAmp * iface)
379 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
380 return IUnknown_AddRef(filter->filter.outer_unk);
383 static ULONG WINAPI AMVideoProcAmp_Release(IAMVideoProcAmp * iface)
385 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
386 return IUnknown_Release(filter->filter.outer_unk);
389 static HRESULT WINAPI AMVideoProcAmp_GetRange(IAMVideoProcAmp *iface, LONG property,
390 LONG *min, LONG *max, LONG *step, LONG *default_value, LONG *flags)
392 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
394 TRACE("filter %p, property %#x, min %p, max %p, step %p, default_value %p, flags %p.\n",
395 filter, property, min, max, step, default_value, flags);
397 return capture_funcs->get_prop_range(filter->device, property, min,
398 max, step, default_value, flags);
401 static HRESULT WINAPI AMVideoProcAmp_Set(IAMVideoProcAmp *iface, LONG property,
402 LONG value, LONG flags)
404 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
406 TRACE("filter %p, property %#x, value %d, flags %#x.\n", filter, property, value, flags);
408 return capture_funcs->set_prop(filter->device, property, value, flags);
411 static HRESULT WINAPI AMVideoProcAmp_Get(IAMVideoProcAmp *iface, LONG property,
412 LONG *value, LONG *flags)
414 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
416 TRACE("filter %p, property %#x, value %p, flags %p.\n", filter, property, value, flags);
418 return capture_funcs->get_prop(filter->device, property, value, flags);
421 static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable =
423 AMVideoProcAmp_QueryInterface,
424 AMVideoProcAmp_AddRef,
425 AMVideoProcAmp_Release,
426 AMVideoProcAmp_GetRange,
427 AMVideoProcAmp_Set,
428 AMVideoProcAmp_Get,
431 static HRESULT WINAPI PPB_QueryInterface(IPersistPropertyBag *iface, REFIID iid, void **out)
433 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
434 return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out);
437 static ULONG WINAPI PPB_AddRef(IPersistPropertyBag * iface)
439 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
440 return IUnknown_AddRef(filter->filter.outer_unk);
443 static ULONG WINAPI PPB_Release(IPersistPropertyBag * iface)
445 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
446 return IUnknown_Release(filter->filter.outer_unk);
449 static HRESULT WINAPI
450 PPB_GetClassID( IPersistPropertyBag * iface, CLSID * pClassID )
452 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
454 FIXME("%p - stub\n", This);
456 return E_NOTIMPL;
459 static HRESULT WINAPI PPB_InitNew(IPersistPropertyBag * iface)
461 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
463 FIXME("%p - stub\n", This);
465 return E_NOTIMPL;
468 static HRESULT WINAPI PPB_Load(IPersistPropertyBag *iface, IPropertyBag *bag, IErrorLog *error_log)
470 static const OLECHAR VFWIndex[] = {'V','F','W','I','n','d','e','x',0};
471 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
472 HRESULT hr;
473 VARIANT var;
475 TRACE("filter %p, bag %p, error_log %p.\n", filter, bag, error_log);
477 V_VT(&var) = VT_I4;
478 if (FAILED(hr = IPropertyBag_Read(bag, VFWIndex, &var, error_log)))
479 return hr;
481 if (!(filter->device = capture_funcs->create(&filter->source, V_I4(&var))))
482 return E_FAIL;
484 filter->init = TRUE;
485 return S_OK;
488 static HRESULT WINAPI
489 PPB_Save( IPersistPropertyBag * iface, IPropertyBag *pPropBag,
490 BOOL fClearDirty, BOOL fSaveAllProperties )
492 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
493 FIXME("%p - stub\n", This);
494 return E_NOTIMPL;
497 static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable =
499 PPB_QueryInterface,
500 PPB_AddRef,
501 PPB_Release,
502 PPB_GetClassID,
503 PPB_InitNew,
504 PPB_Load,
505 PPB_Save
508 /* IKsPropertySet interface */
509 static inline struct vfw_capture *impl_from_IKsPropertySet(IKsPropertySet *iface)
511 return CONTAINING_RECORD(iface, struct vfw_capture, IKsPropertySet_iface);
514 static HRESULT WINAPI KSP_QueryInterface(IKsPropertySet *iface, REFIID iid, void **out)
516 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
517 return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out);
520 static ULONG WINAPI KSP_AddRef(IKsPropertySet * iface)
522 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
523 return IPin_AddRef(&filter->source.pin.IPin_iface);
526 static ULONG WINAPI KSP_Release(IKsPropertySet * iface)
528 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
529 return IPin_Release(&filter->source.pin.IPin_iface);
532 static HRESULT WINAPI
533 KSP_Set( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID,
534 LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData,
535 DWORD cbPropData )
537 FIXME("%p: stub\n", iface);
538 return E_NOTIMPL;
541 static HRESULT WINAPI
542 KSP_Get( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID,
543 LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData,
544 DWORD cbPropData, DWORD *pcbReturned )
546 LPGUID pGuid;
548 TRACE("()\n");
550 if (!IsEqualIID(guidPropSet, &AMPROPSETID_Pin))
551 return E_PROP_SET_UNSUPPORTED;
552 if (pPropData == NULL && pcbReturned == NULL)
553 return E_POINTER;
554 if (pcbReturned)
555 *pcbReturned = sizeof(GUID);
556 if (pPropData == NULL)
557 return S_OK;
558 if (cbPropData < sizeof(GUID))
559 return E_UNEXPECTED;
560 pGuid = pPropData;
561 *pGuid = PIN_CATEGORY_CAPTURE;
562 FIXME("() Not adding a pin with PIN_CATEGORY_PREVIEW\n");
563 return S_OK;
566 static HRESULT WINAPI
567 KSP_QuerySupported( IKsPropertySet * iface, REFGUID guidPropSet,
568 DWORD dwPropID, DWORD *pTypeSupport )
570 FIXME("%p: stub\n", iface);
571 return E_NOTIMPL;
574 static const IKsPropertySetVtbl IKsPropertySet_VTable =
576 KSP_QueryInterface,
577 KSP_AddRef,
578 KSP_Release,
579 KSP_Set,
580 KSP_Get,
581 KSP_QuerySupported
584 static inline struct vfw_capture *impl_from_strmbase_pin(struct strmbase_pin *pin)
586 return CONTAINING_RECORD(pin, struct vfw_capture, source.pin);
589 static HRESULT source_query_accept(struct strmbase_pin *pin, const AM_MEDIA_TYPE *mt)
591 struct vfw_capture *filter = impl_from_strmbase_pin(pin);
592 return capture_funcs->check_format(filter->device, mt);
595 static HRESULT source_get_media_type(struct strmbase_pin *pin,
596 unsigned int index, AM_MEDIA_TYPE *mt)
598 struct vfw_capture *filter = impl_from_strmbase_pin(pin);
599 return capture_funcs->get_media_type(filter->device, index, mt);
602 static HRESULT source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
604 struct vfw_capture *filter = impl_from_strmbase_pin(iface);
606 if (IsEqualGUID(iid, &IID_IKsPropertySet))
607 *out = &filter->IKsPropertySet_iface;
608 else if (IsEqualGUID(iid, &IID_IAMStreamConfig))
609 *out = &filter->IAMStreamConfig_iface;
610 else
611 return E_NOINTERFACE;
613 IUnknown_AddRef((IUnknown *)*out);
614 return S_OK;
617 static HRESULT WINAPI VfwPin_DecideBufferSize(struct strmbase_source *iface,
618 IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
620 ALLOCATOR_PROPERTIES actual;
622 /* What we put here doesn't matter, the
623 driver function should override it then commit */
624 if (!ppropInputRequest->cBuffers)
625 ppropInputRequest->cBuffers = 3;
626 if (!ppropInputRequest->cbBuffer)
627 ppropInputRequest->cbBuffer = 230400;
628 if (!ppropInputRequest->cbAlign)
629 ppropInputRequest->cbAlign = 1;
631 return IMemAllocator_SetProperties(pAlloc, ppropInputRequest, &actual);
634 static const struct strmbase_source_ops source_ops =
636 .base.pin_query_accept = source_query_accept,
637 .base.pin_get_media_type = source_get_media_type,
638 .base.pin_query_interface = source_query_interface,
639 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
640 .pfnDecideBufferSize = VfwPin_DecideBufferSize,
641 .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator,
644 static HRESULT WINAPI misc_flags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid, void **ppv)
646 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
647 return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppv);
650 static ULONG WINAPI misc_flags_AddRef(IAMFilterMiscFlags *iface)
652 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
653 return IUnknown_AddRef(filter->filter.outer_unk);
656 static ULONG WINAPI misc_flags_Release(IAMFilterMiscFlags *iface)
658 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
659 return IUnknown_Release(filter->filter.outer_unk);
662 static ULONG WINAPI misc_flags_GetMiscFlags(IAMFilterMiscFlags *iface)
664 return AM_FILTER_MISC_FLAGS_IS_SOURCE;
667 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_VTable =
669 misc_flags_QueryInterface,
670 misc_flags_AddRef,
671 misc_flags_Release,
672 misc_flags_GetMiscFlags
675 static HRESULT WINAPI video_control_QueryInterface(IAMVideoControl *iface, REFIID riid, void **ppv)
677 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
678 return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppv);
681 static ULONG WINAPI video_control_AddRef(IAMVideoControl *iface)
683 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
684 return IUnknown_AddRef(filter->filter.outer_unk);
687 static ULONG WINAPI video_control_Release(IAMVideoControl *iface)
689 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
690 return IUnknown_Release(filter->filter.outer_unk);
693 static HRESULT WINAPI video_control_GetCaps(IAMVideoControl *iface, IPin *pin, LONG *flags)
695 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
697 FIXME("filter %p, pin %p, flags %p: stub.\n", filter, pin, flags);
699 return E_NOTIMPL;
702 static HRESULT WINAPI video_control_SetMode(IAMVideoControl *iface, IPin *pin, LONG mode)
704 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
706 FIXME("filter %p, pin %p, mode %d: stub.\n", filter, pin, mode);
708 return E_NOTIMPL;
711 static HRESULT WINAPI video_control_GetMode(IAMVideoControl *iface, IPin *pin, LONG *mode)
713 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
715 FIXME("filter %p, pin %p, mode %p: stub.\n", filter, pin, mode);
717 return E_NOTIMPL;
720 static HRESULT WINAPI video_control_GetCurrentActualFrameRate(IAMVideoControl *iface, IPin *pin,
721 LONGLONG *frame_rate)
723 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
725 FIXME("filter %p, pin %p, frame rate %p: stub.\n", filter, pin, frame_rate);
727 return E_NOTIMPL;
730 static HRESULT WINAPI video_control_GetMaxAvailableFrameRate(IAMVideoControl *iface, IPin *pin,
731 LONG index, SIZE dimensions, LONGLONG *frame_rate)
733 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
735 FIXME("filter %p, pin %p, index %d, dimensions (%dx%d), frame rate %p: stub.\n",
736 filter, pin, index, dimensions.cx, dimensions.cy, frame_rate);
738 return E_NOTIMPL;
741 static HRESULT WINAPI video_control_GetFrameRateList(IAMVideoControl *iface, IPin *pin, LONG index,
742 SIZE dimensions, LONG *list_size, LONGLONG **frame_rate)
744 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
746 FIXME("filter %p, pin %p, index %d, dimensions (%dx%d), list size %p, frame rate: %p: stub.\n",
747 filter, pin, index, dimensions.cx, dimensions.cy, list_size, frame_rate);
749 return E_NOTIMPL;
752 static const IAMVideoControlVtbl IAMVideoControl_VTable =
754 video_control_QueryInterface,
755 video_control_AddRef,
756 video_control_Release,
757 video_control_GetCaps,
758 video_control_SetMode,
759 video_control_GetMode,
760 video_control_GetCurrentActualFrameRate,
761 video_control_GetMaxAvailableFrameRate,
762 video_control_GetFrameRateList
765 static BOOL WINAPI load_capture_funcs(INIT_ONCE *once, void *param, void **context)
767 capture_funcs = &v4l_funcs;
768 return TRUE;
771 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
773 HRESULT vfw_capture_create(IUnknown *outer, IUnknown **out)
775 static const WCHAR source_name[] = {'O','u','t','p','u','t',0};
776 struct vfw_capture *object;
778 if (!InitOnceExecuteOnce(&init_once, load_capture_funcs, NULL, NULL))
779 return E_FAIL;
781 if (!(object = CoTaskMemAlloc(sizeof(*object))))
782 return E_OUTOFMEMORY;
784 strmbase_filter_init(&object->filter, outer, &CLSID_VfwCapture, &filter_ops);
786 object->IAMStreamConfig_iface.lpVtbl = &IAMStreamConfig_VTable;
787 object->IAMVideoControl_iface.lpVtbl = &IAMVideoControl_VTable;
788 object->IAMVideoProcAmp_iface.lpVtbl = &IAMVideoProcAmp_VTable;
789 object->IAMFilterMiscFlags_iface.lpVtbl = &IAMFilterMiscFlags_VTable;
790 object->IPersistPropertyBag_iface.lpVtbl = &IPersistPropertyBag_VTable;
791 object->init = FALSE;
793 strmbase_source_init(&object->source, &object->filter, source_name, &source_ops);
795 object->IKsPropertySet_iface.lpVtbl = &IKsPropertySet_VTable;
797 object->state = State_Stopped;
798 InitializeConditionVariable(&object->state_cv);
799 InitializeCriticalSection(&object->state_cs);
800 object->state_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": vfw_capture.state_cs");
802 TRACE("Created VFW capture filter %p.\n", object);
803 ObjectRefCount(TRUE);
804 *out = &object->filter.IUnknown_inner;
805 return S_OK;