gdi32: Fix leak in GdiDeleteSpoolFileHandle.
[wine.git] / dlls / qcap / vfwcapture.c
bloba51b39c0a11a7287009b7b1b4fbb7f12170b8905
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 #define V4L_CALL( func, params ) WINE_UNIX_CALL( unix_ ## func, params )
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 video_capture_device_t 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)
99 struct destroy_params params = { filter->device };
100 V4L_CALL( destroy, &params );
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 free(filter);
115 static HRESULT vfw_capture_query_interface(struct strmbase_filter *iface, REFIID iid, void **out)
117 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
119 if (IsEqualGUID(iid, &IID_IPersistPropertyBag))
120 *out = &filter->IPersistPropertyBag_iface;
121 else if (IsEqualGUID(iid, &IID_IAMVideoControl))
122 *out = &filter->IAMVideoControl_iface;
123 else if (IsEqualGUID(iid, &IID_IAMVideoProcAmp))
124 *out = &filter->IAMVideoProcAmp_iface;
125 else if (IsEqualGUID(iid, &IID_IAMFilterMiscFlags))
126 *out = &filter->IAMFilterMiscFlags_iface;
127 else
128 return E_NOINTERFACE;
130 IUnknown_AddRef((IUnknown *)*out);
131 return S_OK;
134 static unsigned int get_image_size(struct vfw_capture *filter)
136 const VIDEOINFOHEADER *format = (const VIDEOINFOHEADER *)filter->source.pin.mt.pbFormat;
138 return format->bmiHeader.biWidth * format->bmiHeader.biHeight * format->bmiHeader.biBitCount / 8;
141 static DWORD WINAPI stream_thread(void *arg)
143 struct vfw_capture *filter = arg;
144 const unsigned int image_size = get_image_size(filter);
145 struct read_frame_params params;
147 for (;;)
149 IMediaSample *sample;
150 HRESULT hr;
151 BYTE *data;
153 EnterCriticalSection(&filter->state_cs);
155 while (filter->state == State_Paused)
156 SleepConditionVariableCS(&filter->state_cv, &filter->state_cs, INFINITE);
158 if (filter->state == State_Stopped)
160 LeaveCriticalSection(&filter->state_cs);
161 break;
164 LeaveCriticalSection(&filter->state_cs);
166 if (FAILED(hr = IMemAllocator_GetBuffer(filter->source.pAllocator, &sample, NULL, NULL, 0)))
168 ERR("Failed to get sample, hr %#lx.\n", hr);
169 break;
172 IMediaSample_SetActualDataLength(sample, image_size);
173 IMediaSample_GetPointer(sample, &data);
175 params.device = filter->device;
176 params.data = data;
177 if (!V4L_CALL( read_frame, &params ))
179 IMediaSample_Release(sample);
180 break;
183 hr = IMemInputPin_Receive(filter->source.pMemInputPin, sample);
184 IMediaSample_Release(sample);
185 if (FAILED(hr))
187 ERR("IMemInputPin::Receive() returned %#lx.\n", hr);
188 break;
192 return 0;
195 static HRESULT vfw_capture_init_stream(struct strmbase_filter *iface)
197 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
198 HRESULT hr;
200 if (!filter->source.pin.peer)
201 return S_OK;
203 if (FAILED(hr = IMemAllocator_Commit(filter->source.pAllocator)))
204 ERR("Failed to commit allocator, hr %#lx.\n", hr);
206 EnterCriticalSection(&filter->state_cs);
207 filter->state = State_Paused;
208 LeaveCriticalSection(&filter->state_cs);
210 filter->thread = CreateThread(NULL, 0, stream_thread, filter, 0, NULL);
212 return S_OK;
215 static HRESULT vfw_capture_start_stream(struct strmbase_filter *iface, REFERENCE_TIME time)
217 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
219 if (!filter->source.pin.peer)
220 return S_OK;
222 EnterCriticalSection(&filter->state_cs);
223 filter->state = State_Running;
224 LeaveCriticalSection(&filter->state_cs);
225 WakeConditionVariable(&filter->state_cv);
226 return S_OK;
229 static HRESULT vfw_capture_stop_stream(struct strmbase_filter *iface)
231 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
233 if (!filter->source.pin.peer)
234 return S_OK;
236 EnterCriticalSection(&filter->state_cs);
237 filter->state = State_Paused;
238 LeaveCriticalSection(&filter->state_cs);
239 return S_OK;
242 static HRESULT vfw_capture_cleanup_stream(struct strmbase_filter *iface)
244 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
245 HRESULT hr;
247 if (!filter->source.pin.peer)
248 return S_OK;
250 EnterCriticalSection(&filter->state_cs);
251 filter->state = State_Stopped;
252 LeaveCriticalSection(&filter->state_cs);
253 WakeConditionVariable(&filter->state_cv);
255 WaitForSingleObject(filter->thread, INFINITE);
256 CloseHandle(filter->thread);
257 filter->thread = NULL;
259 hr = IMemAllocator_Decommit(filter->source.pAllocator);
260 if (hr != S_OK && hr != VFW_E_NOT_COMMITTED)
261 ERR("Failed to decommit allocator, hr %#lx.\n", hr);
263 return S_OK;
266 static HRESULT vfw_capture_wait_state(struct strmbase_filter *iface, DWORD timeout)
268 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
270 if (filter->source.pin.peer && filter->filter.state == State_Paused)
271 return VFW_S_CANT_CUE;
272 return S_OK;
275 static const struct strmbase_filter_ops filter_ops =
277 .filter_get_pin = vfw_capture_get_pin,
278 .filter_destroy = vfw_capture_destroy,
279 .filter_query_interface = vfw_capture_query_interface,
280 .filter_init_stream = vfw_capture_init_stream,
281 .filter_start_stream = vfw_capture_start_stream,
282 .filter_stop_stream = vfw_capture_stop_stream,
283 .filter_cleanup_stream = vfw_capture_cleanup_stream,
284 .filter_wait_state = vfw_capture_wait_state,
287 static HRESULT WINAPI AMStreamConfig_QueryInterface(IAMStreamConfig *iface, REFIID iid, void **out)
289 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
290 return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out);
293 static ULONG WINAPI AMStreamConfig_AddRef(IAMStreamConfig *iface)
295 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
296 return IPin_AddRef(&filter->source.pin.IPin_iface);
299 static ULONG WINAPI AMStreamConfig_Release(IAMStreamConfig *iface)
301 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
302 return IPin_Release(&filter->source.pin.IPin_iface);
305 static HRESULT WINAPI
306 AMStreamConfig_SetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE *pmt)
308 struct vfw_capture *This = impl_from_IAMStreamConfig(iface);
309 struct set_format_params params;
310 HRESULT hr;
312 TRACE("filter %p, mt %p.\n", This, pmt);
313 strmbase_dump_media_type(pmt);
315 if (This->filter.state != State_Stopped)
317 TRACE("Returning not stopped error\n");
318 return VFW_E_NOT_STOPPED;
321 if (!pmt)
323 TRACE("pmt is NULL\n");
324 return E_POINTER;
327 if (!IsEqualGUID(&pmt->majortype, &MEDIATYPE_Video))
328 return E_FAIL;
330 if (This->source.pin.peer)
332 hr = IPin_QueryAccept(This->source.pin.peer, pmt);
333 TRACE("QueryAccept() returned %#lx.\n", hr);
334 if (hr == S_FALSE)
335 return VFW_E_INVALIDMEDIATYPE;
338 params.device = This->device;
339 params.mt = pmt;
340 hr = V4L_CALL( set_format, &params );
341 if (SUCCEEDED(hr) && This->filter.graph && This->source.pin.peer)
343 hr = IFilterGraph_Reconnect(This->filter.graph, &This->source.pin.IPin_iface);
344 if (SUCCEEDED(hr))
345 TRACE("Reconnection completed, with new media format..\n");
347 TRACE("Returning %#lx.\n", hr);
348 return hr;
351 static HRESULT WINAPI AMStreamConfig_GetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE **mt)
353 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
354 VIDEOINFOHEADER *format;
355 HRESULT hr;
357 TRACE("filter %p, mt %p.\n", filter, mt);
359 if (!(*mt = CoTaskMemAlloc(sizeof(**mt))))
360 return E_OUTOFMEMORY;
362 EnterCriticalSection(&filter->filter.filter_cs);
364 if (filter->source.pin.peer)
366 hr = CopyMediaType(*mt, &filter->source.pin.mt);
368 else
370 if ((format = CoTaskMemAlloc(sizeof(VIDEOINFOHEADER))))
372 struct get_format_params params = { filter->device, *mt, format };
373 V4L_CALL( get_format, &params );
374 (*mt)->cbFormat = sizeof(VIDEOINFOHEADER);
375 (*mt)->pbFormat = (BYTE *)format;
376 hr = S_OK;
378 else
380 hr = E_OUTOFMEMORY;
384 LeaveCriticalSection(&filter->filter.filter_cs);
386 if (SUCCEEDED(hr))
387 strmbase_dump_media_type(*mt);
388 else
389 CoTaskMemFree(*mt);
390 return hr;
393 static HRESULT WINAPI AMStreamConfig_GetNumberOfCapabilities(IAMStreamConfig *iface,
394 int *count, int *size)
396 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
397 struct get_caps_count_params params = { filter->device, count };
399 TRACE("filter %p, count %p, size %p.\n", filter, count, size);
401 if (!count || !size)
402 return E_POINTER;
404 V4L_CALL( get_caps_count, &params );
405 *size = sizeof(VIDEO_STREAM_CONFIG_CAPS);
407 return S_OK;
410 static HRESULT WINAPI AMStreamConfig_GetStreamCaps(IAMStreamConfig *iface,
411 int index, AM_MEDIA_TYPE **pmt, BYTE *vscc)
413 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
414 VIDEOINFOHEADER *format;
415 AM_MEDIA_TYPE *mt;
416 int count;
417 struct get_caps_count_params count_params = { filter->device, &count };
418 struct get_caps_params caps_params;
420 TRACE("filter %p, index %d, pmt %p, vscc %p.\n", filter, index, pmt, vscc);
422 V4L_CALL( get_caps_count, &count_params );
423 if (index > count)
424 return S_FALSE;
426 if (!(mt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
427 return E_OUTOFMEMORY;
429 if (!(format = CoTaskMemAlloc(sizeof(VIDEOINFOHEADER))))
431 CoTaskMemFree(mt);
432 return E_OUTOFMEMORY;
435 caps_params.device = filter->device;
436 caps_params.index = index;
437 caps_params.mt = mt;
438 caps_params.format = format;
439 caps_params.caps = (VIDEO_STREAM_CONFIG_CAPS *)vscc;
440 V4L_CALL( get_caps, &caps_params );
441 mt->cbFormat = sizeof(VIDEOINFOHEADER);
442 mt->pbFormat = (BYTE *)format;
443 *pmt = mt;
444 return S_OK;
447 static const IAMStreamConfigVtbl IAMStreamConfig_VTable =
449 AMStreamConfig_QueryInterface,
450 AMStreamConfig_AddRef,
451 AMStreamConfig_Release,
452 AMStreamConfig_SetFormat,
453 AMStreamConfig_GetFormat,
454 AMStreamConfig_GetNumberOfCapabilities,
455 AMStreamConfig_GetStreamCaps
458 static HRESULT WINAPI AMVideoProcAmp_QueryInterface(IAMVideoProcAmp *iface, REFIID iid, void **out)
460 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
461 return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out);
464 static ULONG WINAPI AMVideoProcAmp_AddRef(IAMVideoProcAmp * iface)
466 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
467 return IUnknown_AddRef(filter->filter.outer_unk);
470 static ULONG WINAPI AMVideoProcAmp_Release(IAMVideoProcAmp * iface)
472 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
473 return IUnknown_Release(filter->filter.outer_unk);
476 static HRESULT WINAPI AMVideoProcAmp_GetRange(IAMVideoProcAmp *iface, LONG property,
477 LONG *min, LONG *max, LONG *step, LONG *default_value, LONG *flags)
479 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
480 struct get_prop_range_params params = { filter->device, property, min, max, step, default_value, flags };
482 TRACE("filter %p, property %#lx, min %p, max %p, step %p, default_value %p, flags %p.\n",
483 filter, property, min, max, step, default_value, flags);
485 return V4L_CALL( get_prop_range, &params );
488 static HRESULT WINAPI AMVideoProcAmp_Set(IAMVideoProcAmp *iface, LONG property,
489 LONG value, LONG flags)
491 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
492 struct set_prop_params params = { filter->device, property, value, flags };
494 TRACE("filter %p, property %#lx, value %ld, flags %#lx.\n", filter, property, value, flags);
496 return V4L_CALL( set_prop, &params );
499 static HRESULT WINAPI AMVideoProcAmp_Get(IAMVideoProcAmp *iface, LONG property,
500 LONG *value, LONG *flags)
502 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
503 struct get_prop_params params = { filter->device, property, value, flags };
505 TRACE("filter %p, property %#lx, value %p, flags %p.\n", filter, property, value, flags);
507 return V4L_CALL( get_prop, &params );
510 static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable =
512 AMVideoProcAmp_QueryInterface,
513 AMVideoProcAmp_AddRef,
514 AMVideoProcAmp_Release,
515 AMVideoProcAmp_GetRange,
516 AMVideoProcAmp_Set,
517 AMVideoProcAmp_Get,
520 static HRESULT WINAPI PPB_QueryInterface(IPersistPropertyBag *iface, REFIID iid, void **out)
522 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
523 return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out);
526 static ULONG WINAPI PPB_AddRef(IPersistPropertyBag * iface)
528 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
529 return IUnknown_AddRef(filter->filter.outer_unk);
532 static ULONG WINAPI PPB_Release(IPersistPropertyBag * iface)
534 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
535 return IUnknown_Release(filter->filter.outer_unk);
538 static HRESULT WINAPI
539 PPB_GetClassID( IPersistPropertyBag * iface, CLSID * pClassID )
541 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
543 FIXME("%p - stub\n", This);
545 return E_NOTIMPL;
548 static HRESULT WINAPI PPB_InitNew(IPersistPropertyBag * iface)
550 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
552 FIXME("%p - stub\n", This);
554 return E_NOTIMPL;
557 static HRESULT WINAPI PPB_Load(IPersistPropertyBag *iface, IPropertyBag *bag, IErrorLog *error_log)
559 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
560 struct create_params params;
561 HRESULT hr;
562 VARIANT var;
564 TRACE("filter %p, bag %p, error_log %p.\n", filter, bag, error_log);
566 V_VT(&var) = VT_I4;
567 if (FAILED(hr = IPropertyBag_Read(bag, L"VFWIndex", &var, error_log)))
568 return hr;
570 params.index = V_I4(&var);
571 params.device = &filter->device;
572 hr = V4L_CALL( create, &params );
574 if (SUCCEEDED(hr)) filter->init = TRUE;
575 return hr;
578 static HRESULT WINAPI
579 PPB_Save( IPersistPropertyBag * iface, IPropertyBag *pPropBag,
580 BOOL fClearDirty, BOOL fSaveAllProperties )
582 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
583 FIXME("%p - stub\n", This);
584 return E_NOTIMPL;
587 static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable =
589 PPB_QueryInterface,
590 PPB_AddRef,
591 PPB_Release,
592 PPB_GetClassID,
593 PPB_InitNew,
594 PPB_Load,
595 PPB_Save
598 /* IKsPropertySet interface */
599 static inline struct vfw_capture *impl_from_IKsPropertySet(IKsPropertySet *iface)
601 return CONTAINING_RECORD(iface, struct vfw_capture, IKsPropertySet_iface);
604 static HRESULT WINAPI KSP_QueryInterface(IKsPropertySet *iface, REFIID iid, void **out)
606 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
607 return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out);
610 static ULONG WINAPI KSP_AddRef(IKsPropertySet * iface)
612 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
613 return IPin_AddRef(&filter->source.pin.IPin_iface);
616 static ULONG WINAPI KSP_Release(IKsPropertySet * iface)
618 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
619 return IPin_Release(&filter->source.pin.IPin_iface);
622 static HRESULT WINAPI
623 KSP_Set( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID,
624 LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData,
625 DWORD cbPropData )
627 FIXME("%p: stub\n", iface);
628 return E_NOTIMPL;
631 static HRESULT WINAPI
632 KSP_Get( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID,
633 LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData,
634 DWORD cbPropData, DWORD *pcbReturned )
636 LPGUID pGuid;
638 TRACE("()\n");
640 if (!IsEqualIID(guidPropSet, &AMPROPSETID_Pin))
641 return E_PROP_SET_UNSUPPORTED;
642 if (pPropData == NULL && pcbReturned == NULL)
643 return E_POINTER;
644 if (pcbReturned)
645 *pcbReturned = sizeof(GUID);
646 if (pPropData == NULL)
647 return S_OK;
648 if (cbPropData < sizeof(GUID))
649 return E_UNEXPECTED;
650 pGuid = pPropData;
651 *pGuid = PIN_CATEGORY_CAPTURE;
652 FIXME("() Not adding a pin with PIN_CATEGORY_PREVIEW\n");
653 return S_OK;
656 static HRESULT WINAPI
657 KSP_QuerySupported( IKsPropertySet * iface, REFGUID guidPropSet,
658 DWORD dwPropID, DWORD *pTypeSupport )
660 FIXME("%p: stub\n", iface);
661 return E_NOTIMPL;
664 static const IKsPropertySetVtbl IKsPropertySet_VTable =
666 KSP_QueryInterface,
667 KSP_AddRef,
668 KSP_Release,
669 KSP_Set,
670 KSP_Get,
671 KSP_QuerySupported
674 static inline struct vfw_capture *impl_from_strmbase_pin(struct strmbase_pin *pin)
676 return CONTAINING_RECORD(pin, struct vfw_capture, source.pin);
679 static HRESULT source_query_accept(struct strmbase_pin *pin, const AM_MEDIA_TYPE *mt)
681 struct vfw_capture *filter = impl_from_strmbase_pin(pin);
682 struct check_format_params params = { filter->device, mt };
684 if (!mt) return E_POINTER;
685 return V4L_CALL( check_format, &params );
688 static HRESULT source_get_media_type(struct strmbase_pin *pin,
689 unsigned int index, AM_MEDIA_TYPE *mt)
691 struct vfw_capture *filter = impl_from_strmbase_pin(pin);
692 struct get_media_type_params params;
693 VIDEOINFOHEADER *format;
694 HRESULT hr;
696 if (!(format = CoTaskMemAlloc(sizeof(*format))))
697 return E_OUTOFMEMORY;
699 params.device = filter->device;
700 params.index = index;
701 params.mt = mt;
702 params.format = format;
703 if ((hr = V4L_CALL( get_media_type, &params )) != S_OK)
705 CoTaskMemFree(format);
706 return hr;
708 mt->cbFormat = sizeof(VIDEOINFOHEADER);
709 mt->pbFormat = (BYTE *)format;
710 return S_OK;
713 static HRESULT source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
715 struct vfw_capture *filter = impl_from_strmbase_pin(iface);
717 if (IsEqualGUID(iid, &IID_IKsPropertySet))
718 *out = &filter->IKsPropertySet_iface;
719 else if (IsEqualGUID(iid, &IID_IAMStreamConfig))
720 *out = &filter->IAMStreamConfig_iface;
721 else
722 return E_NOINTERFACE;
724 IUnknown_AddRef((IUnknown *)*out);
725 return S_OK;
728 static HRESULT WINAPI VfwPin_DecideBufferSize(struct strmbase_source *iface,
729 IMemAllocator *allocator, ALLOCATOR_PROPERTIES *req_props)
731 struct vfw_capture *filter = impl_from_strmbase_pin(&iface->pin);
732 ALLOCATOR_PROPERTIES ret_props;
734 if (!req_props->cBuffers)
735 req_props->cBuffers = 3;
736 if (!req_props->cbBuffer)
737 req_props->cbBuffer = get_image_size(filter);
738 if (!req_props->cbAlign)
739 req_props->cbAlign = 1;
741 return IMemAllocator_SetProperties(allocator, req_props, &ret_props);
744 static const struct strmbase_source_ops source_ops =
746 .base.pin_query_accept = source_query_accept,
747 .base.pin_get_media_type = source_get_media_type,
748 .base.pin_query_interface = source_query_interface,
749 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
750 .pfnDecideBufferSize = VfwPin_DecideBufferSize,
751 .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator,
754 static HRESULT WINAPI misc_flags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid, void **ppv)
756 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
757 return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppv);
760 static ULONG WINAPI misc_flags_AddRef(IAMFilterMiscFlags *iface)
762 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
763 return IUnknown_AddRef(filter->filter.outer_unk);
766 static ULONG WINAPI misc_flags_Release(IAMFilterMiscFlags *iface)
768 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
769 return IUnknown_Release(filter->filter.outer_unk);
772 static ULONG WINAPI misc_flags_GetMiscFlags(IAMFilterMiscFlags *iface)
774 return AM_FILTER_MISC_FLAGS_IS_SOURCE;
777 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_VTable =
779 misc_flags_QueryInterface,
780 misc_flags_AddRef,
781 misc_flags_Release,
782 misc_flags_GetMiscFlags
785 static HRESULT WINAPI video_control_QueryInterface(IAMVideoControl *iface, REFIID riid, void **ppv)
787 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
788 return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppv);
791 static ULONG WINAPI video_control_AddRef(IAMVideoControl *iface)
793 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
794 return IUnknown_AddRef(filter->filter.outer_unk);
797 static ULONG WINAPI video_control_Release(IAMVideoControl *iface)
799 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
800 return IUnknown_Release(filter->filter.outer_unk);
803 static HRESULT WINAPI video_control_GetCaps(IAMVideoControl *iface, IPin *pin, LONG *flags)
805 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
807 FIXME("filter %p, pin %p, flags %p: stub.\n", filter, pin, flags);
809 return E_NOTIMPL;
812 static HRESULT WINAPI video_control_SetMode(IAMVideoControl *iface, IPin *pin, LONG mode)
814 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
816 FIXME("filter %p, pin %p, mode %ld, stub.\n", filter, pin, mode);
818 return E_NOTIMPL;
821 static HRESULT WINAPI video_control_GetMode(IAMVideoControl *iface, IPin *pin, LONG *mode)
823 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
825 FIXME("filter %p, pin %p, mode %p: stub.\n", filter, pin, mode);
827 return E_NOTIMPL;
830 static HRESULT WINAPI video_control_GetCurrentActualFrameRate(IAMVideoControl *iface, IPin *pin,
831 LONGLONG *frame_rate)
833 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
835 FIXME("filter %p, pin %p, frame rate %p: stub.\n", filter, pin, frame_rate);
837 return E_NOTIMPL;
840 static HRESULT WINAPI video_control_GetMaxAvailableFrameRate(IAMVideoControl *iface, IPin *pin,
841 LONG index, SIZE dimensions, LONGLONG *frame_rate)
843 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
845 FIXME("filter %p, pin %p, index %ld, dimensions (%ldx%ld), frame rate %p, stub.\n",
846 filter, pin, index, dimensions.cx, dimensions.cy, frame_rate);
848 return E_NOTIMPL;
851 static HRESULT WINAPI video_control_GetFrameRateList(IAMVideoControl *iface, IPin *pin, LONG index,
852 SIZE dimensions, LONG *list_size, LONGLONG **frame_rate)
854 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
856 FIXME("filter %p, pin %p, index %ld, dimensions (%ldx%ld), list size %p, frame rate %p, stub.\n",
857 filter, pin, index, dimensions.cx, dimensions.cy, list_size, frame_rate);
859 return E_NOTIMPL;
862 static const IAMVideoControlVtbl IAMVideoControl_VTable =
864 video_control_QueryInterface,
865 video_control_AddRef,
866 video_control_Release,
867 video_control_GetCaps,
868 video_control_SetMode,
869 video_control_GetMode,
870 video_control_GetCurrentActualFrameRate,
871 video_control_GetMaxAvailableFrameRate,
872 video_control_GetFrameRateList
875 static BOOL WINAPI load_capture_funcs(INIT_ONCE *once, void *param, void **context)
877 __wine_init_unix_call();
878 return TRUE;
881 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
883 HRESULT vfw_capture_create(IUnknown *outer, IUnknown **out)
885 struct vfw_capture *object;
887 if (!InitOnceExecuteOnce(&init_once, load_capture_funcs, NULL, NULL) || !__wine_unixlib_handle)
888 return E_FAIL;
890 if (!(object = calloc(1, sizeof(*object))))
891 return E_OUTOFMEMORY;
893 strmbase_filter_init(&object->filter, outer, &CLSID_VfwCapture, &filter_ops);
895 object->IAMStreamConfig_iface.lpVtbl = &IAMStreamConfig_VTable;
896 object->IAMVideoControl_iface.lpVtbl = &IAMVideoControl_VTable;
897 object->IAMVideoProcAmp_iface.lpVtbl = &IAMVideoProcAmp_VTable;
898 object->IAMFilterMiscFlags_iface.lpVtbl = &IAMFilterMiscFlags_VTable;
899 object->IPersistPropertyBag_iface.lpVtbl = &IPersistPropertyBag_VTable;
901 strmbase_source_init(&object->source, &object->filter, L"Output", &source_ops);
903 object->IKsPropertySet_iface.lpVtbl = &IKsPropertySet_VTable;
905 object->state = State_Stopped;
906 InitializeConditionVariable(&object->state_cv);
907 InitializeCriticalSection(&object->state_cs);
908 object->state_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": vfw_capture.state_cs");
910 TRACE("Created VFW capture filter %p.\n", object);
911 *out = &object->filter.IUnknown_inner;
912 return S_OK;