qcap: Convert the Unix library to the __wine_unix_call interface.
[wine.git] / dlls / qcap / vfwcapture.c
blob817fae85d80a3302ab9da4f5026bf46273bfa166
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(quartz);
26 static unixlib_handle_t v4l_handle;
28 #define V4L_CALL( func, params ) __wine_unix_call( v4l_handle, unix_ ## func, params )
30 struct vfw_capture
32 struct strmbase_filter filter;
33 IAMStreamConfig IAMStreamConfig_iface;
34 IAMVideoControl IAMVideoControl_iface;
35 IAMVideoProcAmp IAMVideoProcAmp_iface;
36 IAMFilterMiscFlags IAMFilterMiscFlags_iface;
37 IPersistPropertyBag IPersistPropertyBag_iface;
38 BOOL init;
40 struct strmbase_source source;
41 IKsPropertySet IKsPropertySet_iface;
43 struct video_capture_device *device;
45 /* FIXME: It would be nice to avoid duplicating this variable with strmbase.
46 * However, synchronization is tricky; we need access to be protected by a
47 * separate lock. */
48 FILTER_STATE state;
49 CONDITION_VARIABLE state_cv;
50 CRITICAL_SECTION state_cs;
52 HANDLE thread;
55 static inline struct vfw_capture *impl_from_strmbase_filter(struct strmbase_filter *iface)
57 return CONTAINING_RECORD(iface, struct vfw_capture, filter);
60 static inline struct vfw_capture *impl_from_IAMStreamConfig(IAMStreamConfig *iface)
62 return CONTAINING_RECORD(iface, struct vfw_capture, IAMStreamConfig_iface);
65 static inline struct vfw_capture *impl_from_IAMVideoControl(IAMVideoControl *iface)
67 return CONTAINING_RECORD(iface, struct vfw_capture, IAMVideoControl_iface);
70 static inline struct vfw_capture *impl_from_IAMVideoProcAmp(IAMVideoProcAmp *iface)
72 return CONTAINING_RECORD(iface, struct vfw_capture, IAMVideoProcAmp_iface);
75 static inline struct vfw_capture *impl_from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface)
77 return CONTAINING_RECORD(iface, struct vfw_capture, IAMFilterMiscFlags_iface);
80 static inline struct vfw_capture *impl_from_IPersistPropertyBag(IPersistPropertyBag *iface)
82 return CONTAINING_RECORD(iface, struct vfw_capture, IPersistPropertyBag_iface);
85 static struct strmbase_pin *vfw_capture_get_pin(struct strmbase_filter *iface, unsigned int index)
87 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
89 if (index >= 1)
90 return NULL;
92 return &filter->source.pin;
95 static void vfw_capture_destroy(struct strmbase_filter *iface)
97 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
99 if (filter->init)
101 struct destroy_params params = { filter->device };
102 V4L_CALL( destroy, &params );
105 if (filter->source.pin.peer)
107 IPin_Disconnect(filter->source.pin.peer);
108 IPin_Disconnect(&filter->source.pin.IPin_iface);
110 filter->state_cs.DebugInfo->Spare[0] = 0;
111 DeleteCriticalSection(&filter->state_cs);
112 strmbase_source_cleanup(&filter->source);
113 strmbase_filter_cleanup(&filter->filter);
114 free(filter);
117 static HRESULT vfw_capture_query_interface(struct strmbase_filter *iface, REFIID iid, void **out)
119 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
121 if (IsEqualGUID(iid, &IID_IPersistPropertyBag))
122 *out = &filter->IPersistPropertyBag_iface;
123 else if (IsEqualGUID(iid, &IID_IAMVideoControl))
124 *out = &filter->IAMVideoControl_iface;
125 else if (IsEqualGUID(iid, &IID_IAMVideoProcAmp))
126 *out = &filter->IAMVideoProcAmp_iface;
127 else if (IsEqualGUID(iid, &IID_IAMFilterMiscFlags))
128 *out = &filter->IAMFilterMiscFlags_iface;
129 else
130 return E_NOINTERFACE;
132 IUnknown_AddRef((IUnknown *)*out);
133 return S_OK;
136 static unsigned int get_image_size(struct vfw_capture *filter)
138 const VIDEOINFOHEADER *format = (const VIDEOINFOHEADER *)filter->source.pin.mt.pbFormat;
140 return format->bmiHeader.biWidth * format->bmiHeader.biHeight * format->bmiHeader.biBitCount / 8;
143 static DWORD WINAPI stream_thread(void *arg)
145 struct vfw_capture *filter = arg;
146 const unsigned int image_size = get_image_size(filter);
147 struct read_frame_params params;
149 for (;;)
151 IMediaSample *sample;
152 HRESULT hr;
153 BYTE *data;
155 EnterCriticalSection(&filter->state_cs);
157 while (filter->state == State_Paused)
158 SleepConditionVariableCS(&filter->state_cv, &filter->state_cs, INFINITE);
160 if (filter->state == State_Stopped)
162 LeaveCriticalSection(&filter->state_cs);
163 break;
166 LeaveCriticalSection(&filter->state_cs);
168 if (FAILED(hr = BaseOutputPinImpl_GetDeliveryBuffer(&filter->source, &sample, NULL, NULL, 0)))
170 ERR("Failed to get sample, hr %#x.\n", hr);
171 break;
174 IMediaSample_SetActualDataLength(sample, image_size);
175 IMediaSample_GetPointer(sample, &data);
177 params.device = filter->device;
178 params.data = data;
179 if (!V4L_CALL( read_frame, &params ))
181 IMediaSample_Release(sample);
182 break;
185 hr = IMemInputPin_Receive(filter->source.pMemInputPin, sample);
186 IMediaSample_Release(sample);
187 if (FAILED(hr))
189 ERR("IMemInputPin::Receive() returned %#x.\n", hr);
190 break;
194 return 0;
197 static HRESULT vfw_capture_init_stream(struct strmbase_filter *iface)
199 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
200 HRESULT hr;
202 if (FAILED(hr = IMemAllocator_Commit(filter->source.pAllocator)))
203 ERR("Failed to commit allocator, hr %#x.\n", hr);
205 EnterCriticalSection(&filter->state_cs);
206 filter->state = State_Paused;
207 LeaveCriticalSection(&filter->state_cs);
209 filter->thread = CreateThread(NULL, 0, stream_thread, filter, 0, NULL);
211 return S_OK;
214 static HRESULT vfw_capture_start_stream(struct strmbase_filter *iface, REFERENCE_TIME time)
216 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
218 EnterCriticalSection(&filter->state_cs);
219 filter->state = State_Running;
220 LeaveCriticalSection(&filter->state_cs);
221 WakeConditionVariable(&filter->state_cv);
222 return S_OK;
225 static HRESULT vfw_capture_stop_stream(struct strmbase_filter *iface)
227 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
229 EnterCriticalSection(&filter->state_cs);
230 filter->state = State_Paused;
231 LeaveCriticalSection(&filter->state_cs);
232 return S_OK;
235 static HRESULT vfw_capture_cleanup_stream(struct strmbase_filter *iface)
237 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
238 HRESULT hr;
240 EnterCriticalSection(&filter->state_cs);
241 filter->state = State_Stopped;
242 LeaveCriticalSection(&filter->state_cs);
243 WakeConditionVariable(&filter->state_cv);
245 WaitForSingleObject(filter->thread, INFINITE);
246 CloseHandle(filter->thread);
247 filter->thread = NULL;
249 hr = IMemAllocator_Decommit(filter->source.pAllocator);
250 if (hr != S_OK && hr != VFW_E_NOT_COMMITTED)
251 ERR("Failed to decommit allocator, hr %#x.\n", hr);
253 return S_OK;
256 static HRESULT vfw_capture_wait_state(struct strmbase_filter *iface, DWORD timeout)
258 return iface->state == State_Paused ? VFW_S_CANT_CUE : S_OK;
261 static const struct strmbase_filter_ops filter_ops =
263 .filter_get_pin = vfw_capture_get_pin,
264 .filter_destroy = vfw_capture_destroy,
265 .filter_query_interface = vfw_capture_query_interface,
266 .filter_init_stream = vfw_capture_init_stream,
267 .filter_start_stream = vfw_capture_start_stream,
268 .filter_stop_stream = vfw_capture_stop_stream,
269 .filter_cleanup_stream = vfw_capture_cleanup_stream,
270 .filter_wait_state = vfw_capture_wait_state,
273 static HRESULT WINAPI AMStreamConfig_QueryInterface(IAMStreamConfig *iface, REFIID iid, void **out)
275 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
276 return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out);
279 static ULONG WINAPI AMStreamConfig_AddRef(IAMStreamConfig *iface)
281 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
282 return IPin_AddRef(&filter->source.pin.IPin_iface);
285 static ULONG WINAPI AMStreamConfig_Release(IAMStreamConfig *iface)
287 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
288 return IPin_Release(&filter->source.pin.IPin_iface);
291 static HRESULT WINAPI
292 AMStreamConfig_SetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE *pmt)
294 struct vfw_capture *This = impl_from_IAMStreamConfig(iface);
295 struct set_format_params params;
296 HRESULT hr;
298 TRACE("filter %p, mt %p.\n", This, pmt);
299 strmbase_dump_media_type(pmt);
301 if (This->filter.state != State_Stopped)
303 TRACE("Returning not stopped error\n");
304 return VFW_E_NOT_STOPPED;
307 if (!pmt)
309 TRACE("pmt is NULL\n");
310 return E_POINTER;
313 if (!IsEqualGUID(&pmt->majortype, &MEDIATYPE_Video))
314 return E_FAIL;
316 if (This->source.pin.peer)
318 hr = IPin_QueryAccept(This->source.pin.peer, pmt);
319 TRACE("Would accept: %d\n", hr);
320 if (hr == S_FALSE)
321 return VFW_E_INVALIDMEDIATYPE;
324 params.device = This->device;
325 params.mt = pmt;
326 hr = V4L_CALL( set_format, &params );
327 if (SUCCEEDED(hr) && This->filter.graph && This->source.pin.peer)
329 hr = IFilterGraph_Reconnect(This->filter.graph, &This->source.pin.IPin_iface);
330 if (SUCCEEDED(hr))
331 TRACE("Reconnection completed, with new media format..\n");
333 TRACE("Returning: %d\n", hr);
334 return hr;
337 static HRESULT WINAPI AMStreamConfig_GetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE **mt)
339 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
340 VIDEOINFOHEADER *format;
341 HRESULT hr;
343 TRACE("filter %p, mt %p.\n", filter, mt);
345 if (!(*mt = CoTaskMemAlloc(sizeof(**mt))))
346 return E_OUTOFMEMORY;
348 EnterCriticalSection(&filter->filter.filter_cs);
350 if (filter->source.pin.peer)
352 hr = CopyMediaType(*mt, &filter->source.pin.mt);
354 else
356 if ((format = CoTaskMemAlloc(sizeof(VIDEOINFOHEADER))))
358 struct get_format_params params = { filter->device, *mt, format };
359 V4L_CALL( get_format, &params );
360 (*mt)->cbFormat = sizeof(VIDEOINFOHEADER);
361 (*mt)->pbFormat = (BYTE *)format;
362 hr = S_OK;
364 else
366 hr = E_OUTOFMEMORY;
370 LeaveCriticalSection(&filter->filter.filter_cs);
372 if (SUCCEEDED(hr))
373 strmbase_dump_media_type(*mt);
374 else
375 CoTaskMemFree(*mt);
376 return hr;
379 static HRESULT WINAPI AMStreamConfig_GetNumberOfCapabilities(IAMStreamConfig *iface,
380 int *count, int *size)
382 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
383 struct get_caps_count_params params = { filter->device, count };
385 TRACE("filter %p, count %p, size %p.\n", filter, count, size);
387 if (!count || !size)
388 return E_POINTER;
390 V4L_CALL( get_caps_count, &params );
391 *size = sizeof(VIDEO_STREAM_CONFIG_CAPS);
393 return S_OK;
396 static HRESULT WINAPI AMStreamConfig_GetStreamCaps(IAMStreamConfig *iface,
397 int index, AM_MEDIA_TYPE **pmt, BYTE *vscc)
399 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
400 VIDEOINFOHEADER *format;
401 AM_MEDIA_TYPE *mt;
402 int count;
403 struct get_caps_count_params count_params = { filter->device, &count };
404 struct get_caps_params caps_params;
406 TRACE("filter %p, index %d, pmt %p, vscc %p.\n", filter, index, pmt, vscc);
408 V4L_CALL( get_caps_count, &count_params );
409 if (index > count)
410 return S_FALSE;
412 if (!(mt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
413 return E_OUTOFMEMORY;
415 if (!(format = CoTaskMemAlloc(sizeof(VIDEOINFOHEADER))))
417 CoTaskMemFree(mt);
418 return E_OUTOFMEMORY;
421 caps_params.device = filter->device;
422 caps_params.index = index;
423 caps_params.mt = mt;
424 caps_params.format = format;
425 caps_params.caps = (VIDEO_STREAM_CONFIG_CAPS *)vscc;
426 V4L_CALL( get_caps, &caps_params );
427 mt->cbFormat = sizeof(VIDEOINFOHEADER);
428 mt->pbFormat = (BYTE *)format;
429 *pmt = mt;
430 return S_OK;
433 static const IAMStreamConfigVtbl IAMStreamConfig_VTable =
435 AMStreamConfig_QueryInterface,
436 AMStreamConfig_AddRef,
437 AMStreamConfig_Release,
438 AMStreamConfig_SetFormat,
439 AMStreamConfig_GetFormat,
440 AMStreamConfig_GetNumberOfCapabilities,
441 AMStreamConfig_GetStreamCaps
444 static HRESULT WINAPI AMVideoProcAmp_QueryInterface(IAMVideoProcAmp *iface, REFIID iid, void **out)
446 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
447 return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out);
450 static ULONG WINAPI AMVideoProcAmp_AddRef(IAMVideoProcAmp * iface)
452 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
453 return IUnknown_AddRef(filter->filter.outer_unk);
456 static ULONG WINAPI AMVideoProcAmp_Release(IAMVideoProcAmp * iface)
458 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
459 return IUnknown_Release(filter->filter.outer_unk);
462 static HRESULT WINAPI AMVideoProcAmp_GetRange(IAMVideoProcAmp *iface, LONG property,
463 LONG *min, LONG *max, LONG *step, LONG *default_value, LONG *flags)
465 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
466 struct get_prop_range_params params = { filter->device, property, min, max, step, default_value, flags };
468 TRACE("filter %p, property %#x, min %p, max %p, step %p, default_value %p, flags %p.\n",
469 filter, property, min, max, step, default_value, flags);
471 return V4L_CALL( get_prop_range, &params );
474 static HRESULT WINAPI AMVideoProcAmp_Set(IAMVideoProcAmp *iface, LONG property,
475 LONG value, LONG flags)
477 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
478 struct set_prop_params params = { filter->device, property, value, flags };
480 TRACE("filter %p, property %#x, value %d, flags %#x.\n", filter, property, value, flags);
482 return V4L_CALL( set_prop, &params );
485 static HRESULT WINAPI AMVideoProcAmp_Get(IAMVideoProcAmp *iface, LONG property,
486 LONG *value, LONG *flags)
488 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
489 struct get_prop_params params = { filter->device, property, value, flags };
491 TRACE("filter %p, property %#x, value %p, flags %p.\n", filter, property, value, flags);
493 return V4L_CALL( get_prop, &params );
496 static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable =
498 AMVideoProcAmp_QueryInterface,
499 AMVideoProcAmp_AddRef,
500 AMVideoProcAmp_Release,
501 AMVideoProcAmp_GetRange,
502 AMVideoProcAmp_Set,
503 AMVideoProcAmp_Get,
506 static HRESULT WINAPI PPB_QueryInterface(IPersistPropertyBag *iface, REFIID iid, void **out)
508 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
509 return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out);
512 static ULONG WINAPI PPB_AddRef(IPersistPropertyBag * iface)
514 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
515 return IUnknown_AddRef(filter->filter.outer_unk);
518 static ULONG WINAPI PPB_Release(IPersistPropertyBag * iface)
520 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
521 return IUnknown_Release(filter->filter.outer_unk);
524 static HRESULT WINAPI
525 PPB_GetClassID( IPersistPropertyBag * iface, CLSID * pClassID )
527 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
529 FIXME("%p - stub\n", This);
531 return E_NOTIMPL;
534 static HRESULT WINAPI PPB_InitNew(IPersistPropertyBag * iface)
536 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
538 FIXME("%p - stub\n", This);
540 return E_NOTIMPL;
543 static HRESULT WINAPI PPB_Load(IPersistPropertyBag *iface, IPropertyBag *bag, IErrorLog *error_log)
545 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
546 struct create_params params;
547 HRESULT hr;
548 VARIANT var;
550 TRACE("filter %p, bag %p, error_log %p.\n", filter, bag, error_log);
552 V_VT(&var) = VT_I4;
553 if (FAILED(hr = IPropertyBag_Read(bag, L"VFWIndex", &var, error_log)))
554 return hr;
556 params.index = V_I4(&var);
557 params.device = &filter->device;
558 hr = V4L_CALL( create, &params );
560 if (SUCCEEDED(hr)) filter->init = TRUE;
561 return hr;
564 static HRESULT WINAPI
565 PPB_Save( IPersistPropertyBag * iface, IPropertyBag *pPropBag,
566 BOOL fClearDirty, BOOL fSaveAllProperties )
568 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
569 FIXME("%p - stub\n", This);
570 return E_NOTIMPL;
573 static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable =
575 PPB_QueryInterface,
576 PPB_AddRef,
577 PPB_Release,
578 PPB_GetClassID,
579 PPB_InitNew,
580 PPB_Load,
581 PPB_Save
584 /* IKsPropertySet interface */
585 static inline struct vfw_capture *impl_from_IKsPropertySet(IKsPropertySet *iface)
587 return CONTAINING_RECORD(iface, struct vfw_capture, IKsPropertySet_iface);
590 static HRESULT WINAPI KSP_QueryInterface(IKsPropertySet *iface, REFIID iid, void **out)
592 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
593 return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out);
596 static ULONG WINAPI KSP_AddRef(IKsPropertySet * iface)
598 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
599 return IPin_AddRef(&filter->source.pin.IPin_iface);
602 static ULONG WINAPI KSP_Release(IKsPropertySet * iface)
604 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
605 return IPin_Release(&filter->source.pin.IPin_iface);
608 static HRESULT WINAPI
609 KSP_Set( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID,
610 LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData,
611 DWORD cbPropData )
613 FIXME("%p: stub\n", iface);
614 return E_NOTIMPL;
617 static HRESULT WINAPI
618 KSP_Get( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID,
619 LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData,
620 DWORD cbPropData, DWORD *pcbReturned )
622 LPGUID pGuid;
624 TRACE("()\n");
626 if (!IsEqualIID(guidPropSet, &AMPROPSETID_Pin))
627 return E_PROP_SET_UNSUPPORTED;
628 if (pPropData == NULL && pcbReturned == NULL)
629 return E_POINTER;
630 if (pcbReturned)
631 *pcbReturned = sizeof(GUID);
632 if (pPropData == NULL)
633 return S_OK;
634 if (cbPropData < sizeof(GUID))
635 return E_UNEXPECTED;
636 pGuid = pPropData;
637 *pGuid = PIN_CATEGORY_CAPTURE;
638 FIXME("() Not adding a pin with PIN_CATEGORY_PREVIEW\n");
639 return S_OK;
642 static HRESULT WINAPI
643 KSP_QuerySupported( IKsPropertySet * iface, REFGUID guidPropSet,
644 DWORD dwPropID, DWORD *pTypeSupport )
646 FIXME("%p: stub\n", iface);
647 return E_NOTIMPL;
650 static const IKsPropertySetVtbl IKsPropertySet_VTable =
652 KSP_QueryInterface,
653 KSP_AddRef,
654 KSP_Release,
655 KSP_Set,
656 KSP_Get,
657 KSP_QuerySupported
660 static inline struct vfw_capture *impl_from_strmbase_pin(struct strmbase_pin *pin)
662 return CONTAINING_RECORD(pin, struct vfw_capture, source.pin);
665 static HRESULT source_query_accept(struct strmbase_pin *pin, const AM_MEDIA_TYPE *mt)
667 struct vfw_capture *filter = impl_from_strmbase_pin(pin);
668 struct check_format_params params = { filter->device, mt };
669 return V4L_CALL( check_format, &params );
672 static HRESULT source_get_media_type(struct strmbase_pin *pin,
673 unsigned int index, AM_MEDIA_TYPE *mt)
675 struct vfw_capture *filter = impl_from_strmbase_pin(pin);
676 struct get_media_type_params params;
677 VIDEOINFOHEADER *format;
678 HRESULT hr;
680 if (!(format = CoTaskMemAlloc(sizeof(*format))))
681 return E_OUTOFMEMORY;
683 params.device = filter->device;
684 params.index = index;
685 params.mt = mt;
686 params.format = format;
687 if ((hr = V4L_CALL( get_media_type, &params )) != S_OK)
689 CoTaskMemFree(format);
690 return hr;
692 mt->cbFormat = sizeof(VIDEOINFOHEADER);
693 mt->pbFormat = (BYTE *)format;
694 return S_OK;
697 static HRESULT source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
699 struct vfw_capture *filter = impl_from_strmbase_pin(iface);
701 if (IsEqualGUID(iid, &IID_IKsPropertySet))
702 *out = &filter->IKsPropertySet_iface;
703 else if (IsEqualGUID(iid, &IID_IAMStreamConfig))
704 *out = &filter->IAMStreamConfig_iface;
705 else
706 return E_NOINTERFACE;
708 IUnknown_AddRef((IUnknown *)*out);
709 return S_OK;
712 static HRESULT WINAPI VfwPin_DecideBufferSize(struct strmbase_source *iface,
713 IMemAllocator *allocator, ALLOCATOR_PROPERTIES *req_props)
715 struct vfw_capture *filter = impl_from_strmbase_pin(&iface->pin);
716 ALLOCATOR_PROPERTIES ret_props;
718 if (!req_props->cBuffers)
719 req_props->cBuffers = 3;
720 if (!req_props->cbBuffer)
721 req_props->cbBuffer = get_image_size(filter);
722 if (!req_props->cbAlign)
723 req_props->cbAlign = 1;
725 return IMemAllocator_SetProperties(allocator, req_props, &ret_props);
728 static const struct strmbase_source_ops source_ops =
730 .base.pin_query_accept = source_query_accept,
731 .base.pin_get_media_type = source_get_media_type,
732 .base.pin_query_interface = source_query_interface,
733 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
734 .pfnDecideBufferSize = VfwPin_DecideBufferSize,
735 .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator,
738 static HRESULT WINAPI misc_flags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid, void **ppv)
740 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
741 return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppv);
744 static ULONG WINAPI misc_flags_AddRef(IAMFilterMiscFlags *iface)
746 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
747 return IUnknown_AddRef(filter->filter.outer_unk);
750 static ULONG WINAPI misc_flags_Release(IAMFilterMiscFlags *iface)
752 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
753 return IUnknown_Release(filter->filter.outer_unk);
756 static ULONG WINAPI misc_flags_GetMiscFlags(IAMFilterMiscFlags *iface)
758 return AM_FILTER_MISC_FLAGS_IS_SOURCE;
761 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_VTable =
763 misc_flags_QueryInterface,
764 misc_flags_AddRef,
765 misc_flags_Release,
766 misc_flags_GetMiscFlags
769 static HRESULT WINAPI video_control_QueryInterface(IAMVideoControl *iface, REFIID riid, void **ppv)
771 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
772 return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppv);
775 static ULONG WINAPI video_control_AddRef(IAMVideoControl *iface)
777 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
778 return IUnknown_AddRef(filter->filter.outer_unk);
781 static ULONG WINAPI video_control_Release(IAMVideoControl *iface)
783 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
784 return IUnknown_Release(filter->filter.outer_unk);
787 static HRESULT WINAPI video_control_GetCaps(IAMVideoControl *iface, IPin *pin, LONG *flags)
789 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
791 FIXME("filter %p, pin %p, flags %p: stub.\n", filter, pin, flags);
793 return E_NOTIMPL;
796 static HRESULT WINAPI video_control_SetMode(IAMVideoControl *iface, IPin *pin, LONG mode)
798 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
800 FIXME("filter %p, pin %p, mode %d: stub.\n", filter, pin, mode);
802 return E_NOTIMPL;
805 static HRESULT WINAPI video_control_GetMode(IAMVideoControl *iface, IPin *pin, LONG *mode)
807 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
809 FIXME("filter %p, pin %p, mode %p: stub.\n", filter, pin, mode);
811 return E_NOTIMPL;
814 static HRESULT WINAPI video_control_GetCurrentActualFrameRate(IAMVideoControl *iface, IPin *pin,
815 LONGLONG *frame_rate)
817 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
819 FIXME("filter %p, pin %p, frame rate %p: stub.\n", filter, pin, frame_rate);
821 return E_NOTIMPL;
824 static HRESULT WINAPI video_control_GetMaxAvailableFrameRate(IAMVideoControl *iface, IPin *pin,
825 LONG index, SIZE dimensions, LONGLONG *frame_rate)
827 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
829 FIXME("filter %p, pin %p, index %d, dimensions (%dx%d), frame rate %p: stub.\n",
830 filter, pin, index, dimensions.cx, dimensions.cy, frame_rate);
832 return E_NOTIMPL;
835 static HRESULT WINAPI video_control_GetFrameRateList(IAMVideoControl *iface, IPin *pin, LONG index,
836 SIZE dimensions, LONG *list_size, LONGLONG **frame_rate)
838 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
840 FIXME("filter %p, pin %p, index %d, dimensions (%dx%d), list size %p, frame rate: %p: stub.\n",
841 filter, pin, index, dimensions.cx, dimensions.cy, list_size, frame_rate);
843 return E_NOTIMPL;
846 static const IAMVideoControlVtbl IAMVideoControl_VTable =
848 video_control_QueryInterface,
849 video_control_AddRef,
850 video_control_Release,
851 video_control_GetCaps,
852 video_control_SetMode,
853 video_control_GetMode,
854 video_control_GetCurrentActualFrameRate,
855 video_control_GetMaxAvailableFrameRate,
856 video_control_GetFrameRateList
859 static BOOL WINAPI load_capture_funcs(INIT_ONCE *once, void *param, void **context)
861 NtQueryVirtualMemory( GetCurrentProcess(), qcap_instance, MemoryWineUnixFuncs,
862 &v4l_handle, sizeof(v4l_handle), NULL );
863 return TRUE;
866 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
868 HRESULT vfw_capture_create(IUnknown *outer, IUnknown **out)
870 struct vfw_capture *object;
872 if (!InitOnceExecuteOnce(&init_once, load_capture_funcs, NULL, NULL) || !v4l_handle)
873 return E_FAIL;
875 if (!(object = calloc(1, sizeof(*object))))
876 return E_OUTOFMEMORY;
878 strmbase_filter_init(&object->filter, outer, &CLSID_VfwCapture, &filter_ops);
880 object->IAMStreamConfig_iface.lpVtbl = &IAMStreamConfig_VTable;
881 object->IAMVideoControl_iface.lpVtbl = &IAMVideoControl_VTable;
882 object->IAMVideoProcAmp_iface.lpVtbl = &IAMVideoProcAmp_VTable;
883 object->IAMFilterMiscFlags_iface.lpVtbl = &IAMFilterMiscFlags_VTable;
884 object->IPersistPropertyBag_iface.lpVtbl = &IPersistPropertyBag_VTable;
886 strmbase_source_init(&object->source, &object->filter, L"Output", &source_ops);
888 object->IKsPropertySet_iface.lpVtbl = &IKsPropertySet_VTable;
890 object->state = State_Stopped;
891 InitializeConditionVariable(&object->state_cv);
892 InitializeCriticalSection(&object->state_cs);
893 object->state_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": vfw_capture.state_cs");
895 TRACE("Created VFW capture filter %p.\n", object);
896 *out = &object->filter.IUnknown_inner;
897 return S_OK;