comctl32/tests: Flush events before testing edit control IME messages.
[wine.git] / dlls / qcap / vfwcapture.c
blobd842117e9a5617fbb6a2d0d41bb31b146dc5c5f5
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 video_capture_device_t 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 = IMemAllocator_GetBuffer(filter->source.pAllocator, &sample, NULL, NULL, 0)))
170 ERR("Failed to get sample, hr %#lx.\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 %#lx.\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 (!filter->source.pin.peer)
203 return S_OK;
205 if (FAILED(hr = IMemAllocator_Commit(filter->source.pAllocator)))
206 ERR("Failed to commit allocator, hr %#lx.\n", hr);
208 EnterCriticalSection(&filter->state_cs);
209 filter->state = State_Paused;
210 LeaveCriticalSection(&filter->state_cs);
212 filter->thread = CreateThread(NULL, 0, stream_thread, filter, 0, NULL);
214 return S_OK;
217 static HRESULT vfw_capture_start_stream(struct strmbase_filter *iface, REFERENCE_TIME time)
219 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
221 if (!filter->source.pin.peer)
222 return S_OK;
224 EnterCriticalSection(&filter->state_cs);
225 filter->state = State_Running;
226 LeaveCriticalSection(&filter->state_cs);
227 WakeConditionVariable(&filter->state_cv);
228 return S_OK;
231 static HRESULT vfw_capture_stop_stream(struct strmbase_filter *iface)
233 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
235 if (!filter->source.pin.peer)
236 return S_OK;
238 EnterCriticalSection(&filter->state_cs);
239 filter->state = State_Paused;
240 LeaveCriticalSection(&filter->state_cs);
241 return S_OK;
244 static HRESULT vfw_capture_cleanup_stream(struct strmbase_filter *iface)
246 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
247 HRESULT hr;
249 if (!filter->source.pin.peer)
250 return S_OK;
252 EnterCriticalSection(&filter->state_cs);
253 filter->state = State_Stopped;
254 LeaveCriticalSection(&filter->state_cs);
255 WakeConditionVariable(&filter->state_cv);
257 WaitForSingleObject(filter->thread, INFINITE);
258 CloseHandle(filter->thread);
259 filter->thread = NULL;
261 hr = IMemAllocator_Decommit(filter->source.pAllocator);
262 if (hr != S_OK && hr != VFW_E_NOT_COMMITTED)
263 ERR("Failed to decommit allocator, hr %#lx.\n", hr);
265 return S_OK;
268 static HRESULT vfw_capture_wait_state(struct strmbase_filter *iface, DWORD timeout)
270 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
272 if (filter->source.pin.peer && filter->filter.state == State_Paused)
273 return VFW_S_CANT_CUE;
274 return S_OK;
277 static const struct strmbase_filter_ops filter_ops =
279 .filter_get_pin = vfw_capture_get_pin,
280 .filter_destroy = vfw_capture_destroy,
281 .filter_query_interface = vfw_capture_query_interface,
282 .filter_init_stream = vfw_capture_init_stream,
283 .filter_start_stream = vfw_capture_start_stream,
284 .filter_stop_stream = vfw_capture_stop_stream,
285 .filter_cleanup_stream = vfw_capture_cleanup_stream,
286 .filter_wait_state = vfw_capture_wait_state,
289 static HRESULT WINAPI AMStreamConfig_QueryInterface(IAMStreamConfig *iface, REFIID iid, void **out)
291 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
292 return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out);
295 static ULONG WINAPI AMStreamConfig_AddRef(IAMStreamConfig *iface)
297 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
298 return IPin_AddRef(&filter->source.pin.IPin_iface);
301 static ULONG WINAPI AMStreamConfig_Release(IAMStreamConfig *iface)
303 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
304 return IPin_Release(&filter->source.pin.IPin_iface);
307 static HRESULT WINAPI
308 AMStreamConfig_SetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE *pmt)
310 struct vfw_capture *This = impl_from_IAMStreamConfig(iface);
311 struct set_format_params params;
312 HRESULT hr;
314 TRACE("filter %p, mt %p.\n", This, pmt);
315 strmbase_dump_media_type(pmt);
317 if (This->filter.state != State_Stopped)
319 TRACE("Returning not stopped error\n");
320 return VFW_E_NOT_STOPPED;
323 if (!pmt)
325 TRACE("pmt is NULL\n");
326 return E_POINTER;
329 if (!IsEqualGUID(&pmt->majortype, &MEDIATYPE_Video))
330 return E_FAIL;
332 if (This->source.pin.peer)
334 hr = IPin_QueryAccept(This->source.pin.peer, pmt);
335 TRACE("QueryAccept() returned %#lx.\n", hr);
336 if (hr == S_FALSE)
337 return VFW_E_INVALIDMEDIATYPE;
340 params.device = This->device;
341 params.mt = pmt;
342 hr = V4L_CALL( set_format, &params );
343 if (SUCCEEDED(hr) && This->filter.graph && This->source.pin.peer)
345 hr = IFilterGraph_Reconnect(This->filter.graph, &This->source.pin.IPin_iface);
346 if (SUCCEEDED(hr))
347 TRACE("Reconnection completed, with new media format..\n");
349 TRACE("Returning %#lx.\n", hr);
350 return hr;
353 static HRESULT WINAPI AMStreamConfig_GetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE **mt)
355 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
356 VIDEOINFOHEADER *format;
357 HRESULT hr;
359 TRACE("filter %p, mt %p.\n", filter, mt);
361 if (!(*mt = CoTaskMemAlloc(sizeof(**mt))))
362 return E_OUTOFMEMORY;
364 EnterCriticalSection(&filter->filter.filter_cs);
366 if (filter->source.pin.peer)
368 hr = CopyMediaType(*mt, &filter->source.pin.mt);
370 else
372 if ((format = CoTaskMemAlloc(sizeof(VIDEOINFOHEADER))))
374 struct get_format_params params = { filter->device, *mt, format };
375 V4L_CALL( get_format, &params );
376 (*mt)->cbFormat = sizeof(VIDEOINFOHEADER);
377 (*mt)->pbFormat = (BYTE *)format;
378 hr = S_OK;
380 else
382 hr = E_OUTOFMEMORY;
386 LeaveCriticalSection(&filter->filter.filter_cs);
388 if (SUCCEEDED(hr))
389 strmbase_dump_media_type(*mt);
390 else
391 CoTaskMemFree(*mt);
392 return hr;
395 static HRESULT WINAPI AMStreamConfig_GetNumberOfCapabilities(IAMStreamConfig *iface,
396 int *count, int *size)
398 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
399 struct get_caps_count_params params = { filter->device, count };
401 TRACE("filter %p, count %p, size %p.\n", filter, count, size);
403 if (!count || !size)
404 return E_POINTER;
406 V4L_CALL( get_caps_count, &params );
407 *size = sizeof(VIDEO_STREAM_CONFIG_CAPS);
409 return S_OK;
412 static HRESULT WINAPI AMStreamConfig_GetStreamCaps(IAMStreamConfig *iface,
413 int index, AM_MEDIA_TYPE **pmt, BYTE *vscc)
415 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
416 VIDEOINFOHEADER *format;
417 AM_MEDIA_TYPE *mt;
418 int count;
419 struct get_caps_count_params count_params = { filter->device, &count };
420 struct get_caps_params caps_params;
422 TRACE("filter %p, index %d, pmt %p, vscc %p.\n", filter, index, pmt, vscc);
424 V4L_CALL( get_caps_count, &count_params );
425 if (index > count)
426 return S_FALSE;
428 if (!(mt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
429 return E_OUTOFMEMORY;
431 if (!(format = CoTaskMemAlloc(sizeof(VIDEOINFOHEADER))))
433 CoTaskMemFree(mt);
434 return E_OUTOFMEMORY;
437 caps_params.device = filter->device;
438 caps_params.index = index;
439 caps_params.mt = mt;
440 caps_params.format = format;
441 caps_params.caps = (VIDEO_STREAM_CONFIG_CAPS *)vscc;
442 V4L_CALL( get_caps, &caps_params );
443 mt->cbFormat = sizeof(VIDEOINFOHEADER);
444 mt->pbFormat = (BYTE *)format;
445 *pmt = mt;
446 return S_OK;
449 static const IAMStreamConfigVtbl IAMStreamConfig_VTable =
451 AMStreamConfig_QueryInterface,
452 AMStreamConfig_AddRef,
453 AMStreamConfig_Release,
454 AMStreamConfig_SetFormat,
455 AMStreamConfig_GetFormat,
456 AMStreamConfig_GetNumberOfCapabilities,
457 AMStreamConfig_GetStreamCaps
460 static HRESULT WINAPI AMVideoProcAmp_QueryInterface(IAMVideoProcAmp *iface, REFIID iid, void **out)
462 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
463 return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out);
466 static ULONG WINAPI AMVideoProcAmp_AddRef(IAMVideoProcAmp * iface)
468 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
469 return IUnknown_AddRef(filter->filter.outer_unk);
472 static ULONG WINAPI AMVideoProcAmp_Release(IAMVideoProcAmp * iface)
474 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
475 return IUnknown_Release(filter->filter.outer_unk);
478 static HRESULT WINAPI AMVideoProcAmp_GetRange(IAMVideoProcAmp *iface, LONG property,
479 LONG *min, LONG *max, LONG *step, LONG *default_value, LONG *flags)
481 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
482 struct get_prop_range_params params = { filter->device, property, min, max, step, default_value, flags };
484 TRACE("filter %p, property %#lx, min %p, max %p, step %p, default_value %p, flags %p.\n",
485 filter, property, min, max, step, default_value, flags);
487 return V4L_CALL( get_prop_range, &params );
490 static HRESULT WINAPI AMVideoProcAmp_Set(IAMVideoProcAmp *iface, LONG property,
491 LONG value, LONG flags)
493 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
494 struct set_prop_params params = { filter->device, property, value, flags };
496 TRACE("filter %p, property %#lx, value %ld, flags %#lx.\n", filter, property, value, flags);
498 return V4L_CALL( set_prop, &params );
501 static HRESULT WINAPI AMVideoProcAmp_Get(IAMVideoProcAmp *iface, LONG property,
502 LONG *value, LONG *flags)
504 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
505 struct get_prop_params params = { filter->device, property, value, flags };
507 TRACE("filter %p, property %#lx, value %p, flags %p.\n", filter, property, value, flags);
509 return V4L_CALL( get_prop, &params );
512 static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable =
514 AMVideoProcAmp_QueryInterface,
515 AMVideoProcAmp_AddRef,
516 AMVideoProcAmp_Release,
517 AMVideoProcAmp_GetRange,
518 AMVideoProcAmp_Set,
519 AMVideoProcAmp_Get,
522 static HRESULT WINAPI PPB_QueryInterface(IPersistPropertyBag *iface, REFIID iid, void **out)
524 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
525 return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out);
528 static ULONG WINAPI PPB_AddRef(IPersistPropertyBag * iface)
530 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
531 return IUnknown_AddRef(filter->filter.outer_unk);
534 static ULONG WINAPI PPB_Release(IPersistPropertyBag * iface)
536 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
537 return IUnknown_Release(filter->filter.outer_unk);
540 static HRESULT WINAPI
541 PPB_GetClassID( IPersistPropertyBag * iface, CLSID * pClassID )
543 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
545 FIXME("%p - stub\n", This);
547 return E_NOTIMPL;
550 static HRESULT WINAPI PPB_InitNew(IPersistPropertyBag * iface)
552 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
554 FIXME("%p - stub\n", This);
556 return E_NOTIMPL;
559 static HRESULT WINAPI PPB_Load(IPersistPropertyBag *iface, IPropertyBag *bag, IErrorLog *error_log)
561 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
562 struct create_params params;
563 HRESULT hr;
564 VARIANT var;
566 TRACE("filter %p, bag %p, error_log %p.\n", filter, bag, error_log);
568 V_VT(&var) = VT_I4;
569 if (FAILED(hr = IPropertyBag_Read(bag, L"VFWIndex", &var, error_log)))
570 return hr;
572 params.index = V_I4(&var);
573 params.device = &filter->device;
574 hr = V4L_CALL( create, &params );
576 if (SUCCEEDED(hr)) filter->init = TRUE;
577 return hr;
580 static HRESULT WINAPI
581 PPB_Save( IPersistPropertyBag * iface, IPropertyBag *pPropBag,
582 BOOL fClearDirty, BOOL fSaveAllProperties )
584 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
585 FIXME("%p - stub\n", This);
586 return E_NOTIMPL;
589 static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable =
591 PPB_QueryInterface,
592 PPB_AddRef,
593 PPB_Release,
594 PPB_GetClassID,
595 PPB_InitNew,
596 PPB_Load,
597 PPB_Save
600 /* IKsPropertySet interface */
601 static inline struct vfw_capture *impl_from_IKsPropertySet(IKsPropertySet *iface)
603 return CONTAINING_RECORD(iface, struct vfw_capture, IKsPropertySet_iface);
606 static HRESULT WINAPI KSP_QueryInterface(IKsPropertySet *iface, REFIID iid, void **out)
608 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
609 return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out);
612 static ULONG WINAPI KSP_AddRef(IKsPropertySet * iface)
614 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
615 return IPin_AddRef(&filter->source.pin.IPin_iface);
618 static ULONG WINAPI KSP_Release(IKsPropertySet * iface)
620 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
621 return IPin_Release(&filter->source.pin.IPin_iface);
624 static HRESULT WINAPI
625 KSP_Set( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID,
626 LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData,
627 DWORD cbPropData )
629 FIXME("%p: stub\n", iface);
630 return E_NOTIMPL;
633 static HRESULT WINAPI
634 KSP_Get( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID,
635 LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData,
636 DWORD cbPropData, DWORD *pcbReturned )
638 LPGUID pGuid;
640 TRACE("()\n");
642 if (!IsEqualIID(guidPropSet, &AMPROPSETID_Pin))
643 return E_PROP_SET_UNSUPPORTED;
644 if (pPropData == NULL && pcbReturned == NULL)
645 return E_POINTER;
646 if (pcbReturned)
647 *pcbReturned = sizeof(GUID);
648 if (pPropData == NULL)
649 return S_OK;
650 if (cbPropData < sizeof(GUID))
651 return E_UNEXPECTED;
652 pGuid = pPropData;
653 *pGuid = PIN_CATEGORY_CAPTURE;
654 FIXME("() Not adding a pin with PIN_CATEGORY_PREVIEW\n");
655 return S_OK;
658 static HRESULT WINAPI
659 KSP_QuerySupported( IKsPropertySet * iface, REFGUID guidPropSet,
660 DWORD dwPropID, DWORD *pTypeSupport )
662 FIXME("%p: stub\n", iface);
663 return E_NOTIMPL;
666 static const IKsPropertySetVtbl IKsPropertySet_VTable =
668 KSP_QueryInterface,
669 KSP_AddRef,
670 KSP_Release,
671 KSP_Set,
672 KSP_Get,
673 KSP_QuerySupported
676 static inline struct vfw_capture *impl_from_strmbase_pin(struct strmbase_pin *pin)
678 return CONTAINING_RECORD(pin, struct vfw_capture, source.pin);
681 static HRESULT source_query_accept(struct strmbase_pin *pin, const AM_MEDIA_TYPE *mt)
683 struct vfw_capture *filter = impl_from_strmbase_pin(pin);
684 struct check_format_params params = { filter->device, mt };
686 if (!mt) return E_POINTER;
687 return V4L_CALL( check_format, &params );
690 static HRESULT source_get_media_type(struct strmbase_pin *pin,
691 unsigned int index, AM_MEDIA_TYPE *mt)
693 struct vfw_capture *filter = impl_from_strmbase_pin(pin);
694 struct get_media_type_params params;
695 VIDEOINFOHEADER *format;
696 HRESULT hr;
698 if (!(format = CoTaskMemAlloc(sizeof(*format))))
699 return E_OUTOFMEMORY;
701 params.device = filter->device;
702 params.index = index;
703 params.mt = mt;
704 params.format = format;
705 if ((hr = V4L_CALL( get_media_type, &params )) != S_OK)
707 CoTaskMemFree(format);
708 return hr;
710 mt->cbFormat = sizeof(VIDEOINFOHEADER);
711 mt->pbFormat = (BYTE *)format;
712 return S_OK;
715 static HRESULT source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
717 struct vfw_capture *filter = impl_from_strmbase_pin(iface);
719 if (IsEqualGUID(iid, &IID_IKsPropertySet))
720 *out = &filter->IKsPropertySet_iface;
721 else if (IsEqualGUID(iid, &IID_IAMStreamConfig))
722 *out = &filter->IAMStreamConfig_iface;
723 else
724 return E_NOINTERFACE;
726 IUnknown_AddRef((IUnknown *)*out);
727 return S_OK;
730 static HRESULT WINAPI VfwPin_DecideBufferSize(struct strmbase_source *iface,
731 IMemAllocator *allocator, ALLOCATOR_PROPERTIES *req_props)
733 struct vfw_capture *filter = impl_from_strmbase_pin(&iface->pin);
734 ALLOCATOR_PROPERTIES ret_props;
736 if (!req_props->cBuffers)
737 req_props->cBuffers = 3;
738 if (!req_props->cbBuffer)
739 req_props->cbBuffer = get_image_size(filter);
740 if (!req_props->cbAlign)
741 req_props->cbAlign = 1;
743 return IMemAllocator_SetProperties(allocator, req_props, &ret_props);
746 static const struct strmbase_source_ops source_ops =
748 .base.pin_query_accept = source_query_accept,
749 .base.pin_get_media_type = source_get_media_type,
750 .base.pin_query_interface = source_query_interface,
751 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
752 .pfnDecideBufferSize = VfwPin_DecideBufferSize,
753 .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator,
756 static HRESULT WINAPI misc_flags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid, void **ppv)
758 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
759 return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppv);
762 static ULONG WINAPI misc_flags_AddRef(IAMFilterMiscFlags *iface)
764 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
765 return IUnknown_AddRef(filter->filter.outer_unk);
768 static ULONG WINAPI misc_flags_Release(IAMFilterMiscFlags *iface)
770 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
771 return IUnknown_Release(filter->filter.outer_unk);
774 static ULONG WINAPI misc_flags_GetMiscFlags(IAMFilterMiscFlags *iface)
776 return AM_FILTER_MISC_FLAGS_IS_SOURCE;
779 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_VTable =
781 misc_flags_QueryInterface,
782 misc_flags_AddRef,
783 misc_flags_Release,
784 misc_flags_GetMiscFlags
787 static HRESULT WINAPI video_control_QueryInterface(IAMVideoControl *iface, REFIID riid, void **ppv)
789 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
790 return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppv);
793 static ULONG WINAPI video_control_AddRef(IAMVideoControl *iface)
795 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
796 return IUnknown_AddRef(filter->filter.outer_unk);
799 static ULONG WINAPI video_control_Release(IAMVideoControl *iface)
801 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
802 return IUnknown_Release(filter->filter.outer_unk);
805 static HRESULT WINAPI video_control_GetCaps(IAMVideoControl *iface, IPin *pin, LONG *flags)
807 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
809 FIXME("filter %p, pin %p, flags %p: stub.\n", filter, pin, flags);
811 return E_NOTIMPL;
814 static HRESULT WINAPI video_control_SetMode(IAMVideoControl *iface, IPin *pin, LONG mode)
816 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
818 FIXME("filter %p, pin %p, mode %ld, stub.\n", filter, pin, mode);
820 return E_NOTIMPL;
823 static HRESULT WINAPI video_control_GetMode(IAMVideoControl *iface, IPin *pin, LONG *mode)
825 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
827 FIXME("filter %p, pin %p, mode %p: stub.\n", filter, pin, mode);
829 return E_NOTIMPL;
832 static HRESULT WINAPI video_control_GetCurrentActualFrameRate(IAMVideoControl *iface, IPin *pin,
833 LONGLONG *frame_rate)
835 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
837 FIXME("filter %p, pin %p, frame rate %p: stub.\n", filter, pin, frame_rate);
839 return E_NOTIMPL;
842 static HRESULT WINAPI video_control_GetMaxAvailableFrameRate(IAMVideoControl *iface, IPin *pin,
843 LONG index, SIZE dimensions, LONGLONG *frame_rate)
845 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
847 FIXME("filter %p, pin %p, index %ld, dimensions (%ldx%ld), frame rate %p, stub.\n",
848 filter, pin, index, dimensions.cx, dimensions.cy, frame_rate);
850 return E_NOTIMPL;
853 static HRESULT WINAPI video_control_GetFrameRateList(IAMVideoControl *iface, IPin *pin, LONG index,
854 SIZE dimensions, LONG *list_size, LONGLONG **frame_rate)
856 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
858 FIXME("filter %p, pin %p, index %ld, dimensions (%ldx%ld), list size %p, frame rate %p, stub.\n",
859 filter, pin, index, dimensions.cx, dimensions.cy, list_size, frame_rate);
861 return E_NOTIMPL;
864 static const IAMVideoControlVtbl IAMVideoControl_VTable =
866 video_control_QueryInterface,
867 video_control_AddRef,
868 video_control_Release,
869 video_control_GetCaps,
870 video_control_SetMode,
871 video_control_GetMode,
872 video_control_GetCurrentActualFrameRate,
873 video_control_GetMaxAvailableFrameRate,
874 video_control_GetFrameRateList
877 static BOOL WINAPI load_capture_funcs(INIT_ONCE *once, void *param, void **context)
879 NtQueryVirtualMemory( GetCurrentProcess(), qcap_instance, MemoryWineUnixFuncs,
880 &v4l_handle, sizeof(v4l_handle), NULL );
881 return TRUE;
884 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
886 HRESULT vfw_capture_create(IUnknown *outer, IUnknown **out)
888 struct vfw_capture *object;
890 if (!InitOnceExecuteOnce(&init_once, load_capture_funcs, NULL, NULL) || !v4l_handle)
891 return E_FAIL;
893 if (!(object = calloc(1, sizeof(*object))))
894 return E_OUTOFMEMORY;
896 strmbase_filter_init(&object->filter, outer, &CLSID_VfwCapture, &filter_ops);
898 object->IAMStreamConfig_iface.lpVtbl = &IAMStreamConfig_VTable;
899 object->IAMVideoControl_iface.lpVtbl = &IAMVideoControl_VTable;
900 object->IAMVideoProcAmp_iface.lpVtbl = &IAMVideoProcAmp_VTable;
901 object->IAMFilterMiscFlags_iface.lpVtbl = &IAMFilterMiscFlags_VTable;
902 object->IPersistPropertyBag_iface.lpVtbl = &IPersistPropertyBag_VTable;
904 strmbase_source_init(&object->source, &object->filter, L"Output", &source_ops);
906 object->IKsPropertySet_iface.lpVtbl = &IKsPropertySet_VTable;
908 object->state = State_Stopped;
909 InitializeConditionVariable(&object->state_cv);
910 InitializeCriticalSection(&object->state_cs);
911 object->state_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": vfw_capture.state_cs");
913 TRACE("Created VFW capture filter %p.\n", object);
914 *out = &object->filter.IUnknown_inner;
915 return S_OK;