winedump: Dump MSC's S_UNAMESPACE entries.
[wine.git] / dlls / qcap / vfwcapture.c
blob504d41b58144dc9232aa0edbcafe792af77d2807
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 const struct video_capture_funcs *capture_funcs;
28 struct vfw_capture
30 struct strmbase_filter filter;
31 IAMStreamConfig IAMStreamConfig_iface;
32 IAMVideoControl IAMVideoControl_iface;
33 IAMVideoProcAmp IAMVideoProcAmp_iface;
34 IAMFilterMiscFlags IAMFilterMiscFlags_iface;
35 IPersistPropertyBag IPersistPropertyBag_iface;
36 BOOL init;
38 struct strmbase_source source;
39 IKsPropertySet IKsPropertySet_iface;
41 struct video_capture_device *device;
43 /* FIXME: It would be nice to avoid duplicating this variable with strmbase.
44 * However, synchronization is tricky; we need access to be protected by a
45 * separate lock. */
46 FILTER_STATE state;
47 CONDITION_VARIABLE state_cv;
48 CRITICAL_SECTION state_cs;
50 HANDLE thread;
53 static inline struct vfw_capture *impl_from_strmbase_filter(struct strmbase_filter *iface)
55 return CONTAINING_RECORD(iface, struct vfw_capture, filter);
58 static inline struct vfw_capture *impl_from_IAMStreamConfig(IAMStreamConfig *iface)
60 return CONTAINING_RECORD(iface, struct vfw_capture, IAMStreamConfig_iface);
63 static inline struct vfw_capture *impl_from_IAMVideoControl(IAMVideoControl *iface)
65 return CONTAINING_RECORD(iface, struct vfw_capture, IAMVideoControl_iface);
68 static inline struct vfw_capture *impl_from_IAMVideoProcAmp(IAMVideoProcAmp *iface)
70 return CONTAINING_RECORD(iface, struct vfw_capture, IAMVideoProcAmp_iface);
73 static inline struct vfw_capture *impl_from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface)
75 return CONTAINING_RECORD(iface, struct vfw_capture, IAMFilterMiscFlags_iface);
78 static inline struct vfw_capture *impl_from_IPersistPropertyBag(IPersistPropertyBag *iface)
80 return CONTAINING_RECORD(iface, struct vfw_capture, IPersistPropertyBag_iface);
83 static struct strmbase_pin *vfw_capture_get_pin(struct strmbase_filter *iface, unsigned int index)
85 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
87 if (index >= 1)
88 return NULL;
90 return &filter->source.pin;
93 static void vfw_capture_destroy(struct strmbase_filter *iface)
95 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
97 if (filter->init)
98 capture_funcs->destroy(filter->device);
100 if (filter->source.pin.peer)
102 IPin_Disconnect(filter->source.pin.peer);
103 IPin_Disconnect(&filter->source.pin.IPin_iface);
105 filter->state_cs.DebugInfo->Spare[0] = 0;
106 DeleteCriticalSection(&filter->state_cs);
107 strmbase_source_cleanup(&filter->source);
108 strmbase_filter_cleanup(&filter->filter);
109 free(filter);
112 static HRESULT vfw_capture_query_interface(struct strmbase_filter *iface, REFIID iid, void **out)
114 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
116 if (IsEqualGUID(iid, &IID_IPersistPropertyBag))
117 *out = &filter->IPersistPropertyBag_iface;
118 else if (IsEqualGUID(iid, &IID_IAMVideoControl))
119 *out = &filter->IAMVideoControl_iface;
120 else if (IsEqualGUID(iid, &IID_IAMVideoProcAmp))
121 *out = &filter->IAMVideoProcAmp_iface;
122 else if (IsEqualGUID(iid, &IID_IAMFilterMiscFlags))
123 *out = &filter->IAMFilterMiscFlags_iface;
124 else
125 return E_NOINTERFACE;
127 IUnknown_AddRef((IUnknown *)*out);
128 return S_OK;
131 static unsigned int get_image_size(struct vfw_capture *filter)
133 const VIDEOINFOHEADER *format = (const VIDEOINFOHEADER *)filter->source.pin.mt.pbFormat;
135 return format->bmiHeader.biWidth * format->bmiHeader.biHeight * format->bmiHeader.biBitCount / 8;
138 static DWORD WINAPI stream_thread(void *arg)
140 struct vfw_capture *filter = arg;
141 const unsigned int image_size = get_image_size(filter);
143 for (;;)
145 IMediaSample *sample;
146 HRESULT hr;
147 BYTE *data;
149 EnterCriticalSection(&filter->state_cs);
151 while (filter->state == State_Paused)
152 SleepConditionVariableCS(&filter->state_cv, &filter->state_cs, INFINITE);
154 if (filter->state == State_Stopped)
156 LeaveCriticalSection(&filter->state_cs);
157 break;
160 LeaveCriticalSection(&filter->state_cs);
162 if (FAILED(hr = BaseOutputPinImpl_GetDeliveryBuffer(&filter->source, &sample, NULL, NULL, 0)))
164 ERR("Failed to get sample, hr %#x.\n", hr);
165 break;
168 IMediaSample_SetActualDataLength(sample, image_size);
169 IMediaSample_GetPointer(sample, &data);
171 if (!capture_funcs->read_frame(filter->device, data))
173 IMediaSample_Release(sample);
174 break;
177 hr = IMemInputPin_Receive(filter->source.pMemInputPin, sample);
178 IMediaSample_Release(sample);
179 if (FAILED(hr))
181 ERR("IMemInputPin::Receive() returned %#x.\n", hr);
182 break;
186 return 0;
189 static HRESULT vfw_capture_init_stream(struct strmbase_filter *iface)
191 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
192 HRESULT hr;
194 if (FAILED(hr = IMemAllocator_Commit(filter->source.pAllocator)))
195 ERR("Failed to commit allocator, hr %#x.\n", hr);
197 EnterCriticalSection(&filter->state_cs);
198 filter->state = State_Paused;
199 LeaveCriticalSection(&filter->state_cs);
201 filter->thread = CreateThread(NULL, 0, stream_thread, filter, 0, NULL);
203 return S_OK;
206 static HRESULT vfw_capture_start_stream(struct strmbase_filter *iface, REFERENCE_TIME time)
208 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
210 EnterCriticalSection(&filter->state_cs);
211 filter->state = State_Running;
212 LeaveCriticalSection(&filter->state_cs);
213 WakeConditionVariable(&filter->state_cv);
214 return S_OK;
217 static HRESULT vfw_capture_stop_stream(struct strmbase_filter *iface)
219 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
221 EnterCriticalSection(&filter->state_cs);
222 filter->state = State_Paused;
223 LeaveCriticalSection(&filter->state_cs);
224 return S_OK;
227 static HRESULT vfw_capture_cleanup_stream(struct strmbase_filter *iface)
229 struct vfw_capture *filter = impl_from_strmbase_filter(iface);
230 HRESULT hr;
232 EnterCriticalSection(&filter->state_cs);
233 filter->state = State_Stopped;
234 LeaveCriticalSection(&filter->state_cs);
235 WakeConditionVariable(&filter->state_cv);
237 WaitForSingleObject(filter->thread, INFINITE);
238 CloseHandle(filter->thread);
239 filter->thread = NULL;
241 hr = IMemAllocator_Decommit(filter->source.pAllocator);
242 if (hr != S_OK && hr != VFW_E_NOT_COMMITTED)
243 ERR("Failed to decommit allocator, hr %#x.\n", hr);
245 return S_OK;
248 static HRESULT vfw_capture_wait_state(struct strmbase_filter *iface, DWORD timeout)
250 return iface->state == State_Paused ? VFW_S_CANT_CUE : S_OK;
253 static const struct strmbase_filter_ops filter_ops =
255 .filter_get_pin = vfw_capture_get_pin,
256 .filter_destroy = vfw_capture_destroy,
257 .filter_query_interface = vfw_capture_query_interface,
258 .filter_init_stream = vfw_capture_init_stream,
259 .filter_start_stream = vfw_capture_start_stream,
260 .filter_stop_stream = vfw_capture_stop_stream,
261 .filter_cleanup_stream = vfw_capture_cleanup_stream,
262 .filter_wait_state = vfw_capture_wait_state,
265 static HRESULT WINAPI AMStreamConfig_QueryInterface(IAMStreamConfig *iface, REFIID iid, void **out)
267 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
268 return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out);
271 static ULONG WINAPI AMStreamConfig_AddRef(IAMStreamConfig *iface)
273 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
274 return IPin_AddRef(&filter->source.pin.IPin_iface);
277 static ULONG WINAPI AMStreamConfig_Release(IAMStreamConfig *iface)
279 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
280 return IPin_Release(&filter->source.pin.IPin_iface);
283 static HRESULT WINAPI
284 AMStreamConfig_SetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE *pmt)
286 struct vfw_capture *This = impl_from_IAMStreamConfig(iface);
287 HRESULT hr;
289 TRACE("filter %p, mt %p.\n", This, pmt);
290 strmbase_dump_media_type(pmt);
292 if (This->filter.state != State_Stopped)
294 TRACE("Returning not stopped error\n");
295 return VFW_E_NOT_STOPPED;
298 if (!pmt)
300 TRACE("pmt is NULL\n");
301 return E_POINTER;
304 if (!IsEqualGUID(&pmt->majortype, &MEDIATYPE_Video))
305 return E_FAIL;
307 if (This->source.pin.peer)
309 hr = IPin_QueryAccept(This->source.pin.peer, pmt);
310 TRACE("Would accept: %d\n", hr);
311 if (hr == S_FALSE)
312 return VFW_E_INVALIDMEDIATYPE;
315 hr = capture_funcs->set_format(This->device, pmt);
316 if (SUCCEEDED(hr) && This->filter.graph && This->source.pin.peer)
318 hr = IFilterGraph_Reconnect(This->filter.graph, &This->source.pin.IPin_iface);
319 if (SUCCEEDED(hr))
320 TRACE("Reconnection completed, with new media format..\n");
322 TRACE("Returning: %d\n", hr);
323 return hr;
326 static HRESULT WINAPI AMStreamConfig_GetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE **mt)
328 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
329 VIDEOINFOHEADER *format;
330 HRESULT hr;
332 TRACE("filter %p, mt %p.\n", filter, mt);
334 if (!(*mt = CoTaskMemAlloc(sizeof(**mt))))
335 return E_OUTOFMEMORY;
337 EnterCriticalSection(&filter->filter.filter_cs);
339 if (filter->source.pin.peer)
341 hr = CopyMediaType(*mt, &filter->source.pin.mt);
343 else
345 if ((format = CoTaskMemAlloc(sizeof(VIDEOINFOHEADER))))
347 capture_funcs->get_format(filter->device, *mt, format);
348 (*mt)->cbFormat = sizeof(VIDEOINFOHEADER);
349 (*mt)->pbFormat = (BYTE *)format;
350 hr = S_OK;
352 else
354 hr = E_OUTOFMEMORY;
358 LeaveCriticalSection(&filter->filter.filter_cs);
360 if (SUCCEEDED(hr))
361 strmbase_dump_media_type(*mt);
362 else
363 CoTaskMemFree(*mt);
364 return hr;
367 static HRESULT WINAPI AMStreamConfig_GetNumberOfCapabilities(IAMStreamConfig *iface,
368 int *count, int *size)
370 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
372 TRACE("filter %p, count %p, size %p.\n", filter, count, size);
374 if (!count || !size)
375 return E_POINTER;
377 *count = capture_funcs->get_caps_count(filter->device);
378 *size = sizeof(VIDEO_STREAM_CONFIG_CAPS);
380 return S_OK;
383 static HRESULT WINAPI AMStreamConfig_GetStreamCaps(IAMStreamConfig *iface,
384 int index, AM_MEDIA_TYPE **pmt, BYTE *vscc)
386 struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
387 VIDEOINFOHEADER *format;
388 AM_MEDIA_TYPE *mt;
390 TRACE("filter %p, index %d, pmt %p, vscc %p.\n", filter, index, pmt, vscc);
392 if (index > capture_funcs->get_caps_count(filter->device))
393 return S_FALSE;
395 if (!(mt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
396 return E_OUTOFMEMORY;
398 if (!(format = CoTaskMemAlloc(sizeof(VIDEOINFOHEADER))))
400 CoTaskMemFree(mt);
401 return E_OUTOFMEMORY;
404 capture_funcs->get_caps(filter->device, index, mt, format, (VIDEO_STREAM_CONFIG_CAPS *)vscc);
405 mt->cbFormat = sizeof(VIDEOINFOHEADER);
406 mt->pbFormat = (BYTE *)format;
407 *pmt = mt;
408 return S_OK;
411 static const IAMStreamConfigVtbl IAMStreamConfig_VTable =
413 AMStreamConfig_QueryInterface,
414 AMStreamConfig_AddRef,
415 AMStreamConfig_Release,
416 AMStreamConfig_SetFormat,
417 AMStreamConfig_GetFormat,
418 AMStreamConfig_GetNumberOfCapabilities,
419 AMStreamConfig_GetStreamCaps
422 static HRESULT WINAPI AMVideoProcAmp_QueryInterface(IAMVideoProcAmp *iface, REFIID iid, void **out)
424 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
425 return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out);
428 static ULONG WINAPI AMVideoProcAmp_AddRef(IAMVideoProcAmp * iface)
430 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
431 return IUnknown_AddRef(filter->filter.outer_unk);
434 static ULONG WINAPI AMVideoProcAmp_Release(IAMVideoProcAmp * iface)
436 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
437 return IUnknown_Release(filter->filter.outer_unk);
440 static HRESULT WINAPI AMVideoProcAmp_GetRange(IAMVideoProcAmp *iface, LONG property,
441 LONG *min, LONG *max, LONG *step, LONG *default_value, LONG *flags)
443 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
445 TRACE("filter %p, property %#x, min %p, max %p, step %p, default_value %p, flags %p.\n",
446 filter, property, min, max, step, default_value, flags);
448 return capture_funcs->get_prop_range(filter->device, property, min,
449 max, step, default_value, flags);
452 static HRESULT WINAPI AMVideoProcAmp_Set(IAMVideoProcAmp *iface, LONG property,
453 LONG value, LONG flags)
455 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
457 TRACE("filter %p, property %#x, value %d, flags %#x.\n", filter, property, value, flags);
459 return capture_funcs->set_prop(filter->device, property, value, flags);
462 static HRESULT WINAPI AMVideoProcAmp_Get(IAMVideoProcAmp *iface, LONG property,
463 LONG *value, LONG *flags)
465 struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
467 TRACE("filter %p, property %#x, value %p, flags %p.\n", filter, property, value, flags);
469 return capture_funcs->get_prop(filter->device, property, value, flags);
472 static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable =
474 AMVideoProcAmp_QueryInterface,
475 AMVideoProcAmp_AddRef,
476 AMVideoProcAmp_Release,
477 AMVideoProcAmp_GetRange,
478 AMVideoProcAmp_Set,
479 AMVideoProcAmp_Get,
482 static HRESULT WINAPI PPB_QueryInterface(IPersistPropertyBag *iface, REFIID iid, void **out)
484 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
485 return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out);
488 static ULONG WINAPI PPB_AddRef(IPersistPropertyBag * iface)
490 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
491 return IUnknown_AddRef(filter->filter.outer_unk);
494 static ULONG WINAPI PPB_Release(IPersistPropertyBag * iface)
496 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
497 return IUnknown_Release(filter->filter.outer_unk);
500 static HRESULT WINAPI
501 PPB_GetClassID( IPersistPropertyBag * iface, CLSID * pClassID )
503 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
505 FIXME("%p - stub\n", This);
507 return E_NOTIMPL;
510 static HRESULT WINAPI PPB_InitNew(IPersistPropertyBag * iface)
512 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
514 FIXME("%p - stub\n", This);
516 return E_NOTIMPL;
519 static HRESULT WINAPI PPB_Load(IPersistPropertyBag *iface, IPropertyBag *bag, IErrorLog *error_log)
521 struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
522 HRESULT hr;
523 VARIANT var;
525 TRACE("filter %p, bag %p, error_log %p.\n", filter, bag, error_log);
527 V_VT(&var) = VT_I4;
528 if (FAILED(hr = IPropertyBag_Read(bag, L"VFWIndex", &var, error_log)))
529 return hr;
531 if (!(filter->device = capture_funcs->create(V_I4(&var))))
532 return E_FAIL;
534 filter->init = TRUE;
535 return S_OK;
538 static HRESULT WINAPI
539 PPB_Save( IPersistPropertyBag * iface, IPropertyBag *pPropBag,
540 BOOL fClearDirty, BOOL fSaveAllProperties )
542 struct vfw_capture *This = impl_from_IPersistPropertyBag(iface);
543 FIXME("%p - stub\n", This);
544 return E_NOTIMPL;
547 static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable =
549 PPB_QueryInterface,
550 PPB_AddRef,
551 PPB_Release,
552 PPB_GetClassID,
553 PPB_InitNew,
554 PPB_Load,
555 PPB_Save
558 /* IKsPropertySet interface */
559 static inline struct vfw_capture *impl_from_IKsPropertySet(IKsPropertySet *iface)
561 return CONTAINING_RECORD(iface, struct vfw_capture, IKsPropertySet_iface);
564 static HRESULT WINAPI KSP_QueryInterface(IKsPropertySet *iface, REFIID iid, void **out)
566 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
567 return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out);
570 static ULONG WINAPI KSP_AddRef(IKsPropertySet * iface)
572 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
573 return IPin_AddRef(&filter->source.pin.IPin_iface);
576 static ULONG WINAPI KSP_Release(IKsPropertySet * iface)
578 struct vfw_capture *filter = impl_from_IKsPropertySet(iface);
579 return IPin_Release(&filter->source.pin.IPin_iface);
582 static HRESULT WINAPI
583 KSP_Set( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID,
584 LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData,
585 DWORD cbPropData )
587 FIXME("%p: stub\n", iface);
588 return E_NOTIMPL;
591 static HRESULT WINAPI
592 KSP_Get( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID,
593 LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData,
594 DWORD cbPropData, DWORD *pcbReturned )
596 LPGUID pGuid;
598 TRACE("()\n");
600 if (!IsEqualIID(guidPropSet, &AMPROPSETID_Pin))
601 return E_PROP_SET_UNSUPPORTED;
602 if (pPropData == NULL && pcbReturned == NULL)
603 return E_POINTER;
604 if (pcbReturned)
605 *pcbReturned = sizeof(GUID);
606 if (pPropData == NULL)
607 return S_OK;
608 if (cbPropData < sizeof(GUID))
609 return E_UNEXPECTED;
610 pGuid = pPropData;
611 *pGuid = PIN_CATEGORY_CAPTURE;
612 FIXME("() Not adding a pin with PIN_CATEGORY_PREVIEW\n");
613 return S_OK;
616 static HRESULT WINAPI
617 KSP_QuerySupported( IKsPropertySet * iface, REFGUID guidPropSet,
618 DWORD dwPropID, DWORD *pTypeSupport )
620 FIXME("%p: stub\n", iface);
621 return E_NOTIMPL;
624 static const IKsPropertySetVtbl IKsPropertySet_VTable =
626 KSP_QueryInterface,
627 KSP_AddRef,
628 KSP_Release,
629 KSP_Set,
630 KSP_Get,
631 KSP_QuerySupported
634 static inline struct vfw_capture *impl_from_strmbase_pin(struct strmbase_pin *pin)
636 return CONTAINING_RECORD(pin, struct vfw_capture, source.pin);
639 static HRESULT source_query_accept(struct strmbase_pin *pin, const AM_MEDIA_TYPE *mt)
641 struct vfw_capture *filter = impl_from_strmbase_pin(pin);
642 return capture_funcs->check_format(filter->device, mt);
645 static HRESULT source_get_media_type(struct strmbase_pin *pin,
646 unsigned int index, AM_MEDIA_TYPE *mt)
648 struct vfw_capture *filter = impl_from_strmbase_pin(pin);
649 VIDEOINFOHEADER *format;
650 HRESULT hr;
652 if (!(format = CoTaskMemAlloc(sizeof(*format))))
653 return E_OUTOFMEMORY;
655 if ((hr = capture_funcs->get_media_type(filter->device, index, mt, format)) != S_OK)
657 CoTaskMemFree(format);
658 return hr;
660 mt->cbFormat = sizeof(VIDEOINFOHEADER);
661 mt->pbFormat = (BYTE *)format;
662 return S_OK;
665 static HRESULT source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
667 struct vfw_capture *filter = impl_from_strmbase_pin(iface);
669 if (IsEqualGUID(iid, &IID_IKsPropertySet))
670 *out = &filter->IKsPropertySet_iface;
671 else if (IsEqualGUID(iid, &IID_IAMStreamConfig))
672 *out = &filter->IAMStreamConfig_iface;
673 else
674 return E_NOINTERFACE;
676 IUnknown_AddRef((IUnknown *)*out);
677 return S_OK;
680 static HRESULT WINAPI VfwPin_DecideBufferSize(struct strmbase_source *iface,
681 IMemAllocator *allocator, ALLOCATOR_PROPERTIES *req_props)
683 struct vfw_capture *filter = impl_from_strmbase_pin(&iface->pin);
684 ALLOCATOR_PROPERTIES ret_props;
686 if (!req_props->cBuffers)
687 req_props->cBuffers = 3;
688 if (!req_props->cbBuffer)
689 req_props->cbBuffer = get_image_size(filter);
690 if (!req_props->cbAlign)
691 req_props->cbAlign = 1;
693 return IMemAllocator_SetProperties(allocator, req_props, &ret_props);
696 static const struct strmbase_source_ops source_ops =
698 .base.pin_query_accept = source_query_accept,
699 .base.pin_get_media_type = source_get_media_type,
700 .base.pin_query_interface = source_query_interface,
701 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
702 .pfnDecideBufferSize = VfwPin_DecideBufferSize,
703 .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator,
706 static HRESULT WINAPI misc_flags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid, void **ppv)
708 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
709 return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppv);
712 static ULONG WINAPI misc_flags_AddRef(IAMFilterMiscFlags *iface)
714 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
715 return IUnknown_AddRef(filter->filter.outer_unk);
718 static ULONG WINAPI misc_flags_Release(IAMFilterMiscFlags *iface)
720 struct vfw_capture *filter = impl_from_IAMFilterMiscFlags(iface);
721 return IUnknown_Release(filter->filter.outer_unk);
724 static ULONG WINAPI misc_flags_GetMiscFlags(IAMFilterMiscFlags *iface)
726 return AM_FILTER_MISC_FLAGS_IS_SOURCE;
729 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_VTable =
731 misc_flags_QueryInterface,
732 misc_flags_AddRef,
733 misc_flags_Release,
734 misc_flags_GetMiscFlags
737 static HRESULT WINAPI video_control_QueryInterface(IAMVideoControl *iface, REFIID riid, void **ppv)
739 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
740 return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppv);
743 static ULONG WINAPI video_control_AddRef(IAMVideoControl *iface)
745 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
746 return IUnknown_AddRef(filter->filter.outer_unk);
749 static ULONG WINAPI video_control_Release(IAMVideoControl *iface)
751 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
752 return IUnknown_Release(filter->filter.outer_unk);
755 static HRESULT WINAPI video_control_GetCaps(IAMVideoControl *iface, IPin *pin, LONG *flags)
757 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
759 FIXME("filter %p, pin %p, flags %p: stub.\n", filter, pin, flags);
761 return E_NOTIMPL;
764 static HRESULT WINAPI video_control_SetMode(IAMVideoControl *iface, IPin *pin, LONG mode)
766 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
768 FIXME("filter %p, pin %p, mode %d: stub.\n", filter, pin, mode);
770 return E_NOTIMPL;
773 static HRESULT WINAPI video_control_GetMode(IAMVideoControl *iface, IPin *pin, LONG *mode)
775 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
777 FIXME("filter %p, pin %p, mode %p: stub.\n", filter, pin, mode);
779 return E_NOTIMPL;
782 static HRESULT WINAPI video_control_GetCurrentActualFrameRate(IAMVideoControl *iface, IPin *pin,
783 LONGLONG *frame_rate)
785 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
787 FIXME("filter %p, pin %p, frame rate %p: stub.\n", filter, pin, frame_rate);
789 return E_NOTIMPL;
792 static HRESULT WINAPI video_control_GetMaxAvailableFrameRate(IAMVideoControl *iface, IPin *pin,
793 LONG index, SIZE dimensions, LONGLONG *frame_rate)
795 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
797 FIXME("filter %p, pin %p, index %d, dimensions (%dx%d), frame rate %p: stub.\n",
798 filter, pin, index, dimensions.cx, dimensions.cy, frame_rate);
800 return E_NOTIMPL;
803 static HRESULT WINAPI video_control_GetFrameRateList(IAMVideoControl *iface, IPin *pin, LONG index,
804 SIZE dimensions, LONG *list_size, LONGLONG **frame_rate)
806 struct vfw_capture *filter = impl_from_IAMVideoControl(iface);
808 FIXME("filter %p, pin %p, index %d, dimensions (%dx%d), list size %p, frame rate: %p: stub.\n",
809 filter, pin, index, dimensions.cx, dimensions.cy, list_size, frame_rate);
811 return E_NOTIMPL;
814 static const IAMVideoControlVtbl IAMVideoControl_VTable =
816 video_control_QueryInterface,
817 video_control_AddRef,
818 video_control_Release,
819 video_control_GetCaps,
820 video_control_SetMode,
821 video_control_GetMode,
822 video_control_GetCurrentActualFrameRate,
823 video_control_GetMaxAvailableFrameRate,
824 video_control_GetFrameRateList
827 static BOOL WINAPI load_capture_funcs(INIT_ONCE *once, void *param, void **context)
829 __wine_init_unix_lib(qcap_instance, DLL_PROCESS_ATTACH, NULL, &capture_funcs);
830 return TRUE;
833 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
835 HRESULT vfw_capture_create(IUnknown *outer, IUnknown **out)
837 struct vfw_capture *object;
839 if (!InitOnceExecuteOnce(&init_once, load_capture_funcs, NULL, NULL) || !capture_funcs)
840 return E_FAIL;
842 if (!(object = calloc(1, sizeof(*object))))
843 return E_OUTOFMEMORY;
845 strmbase_filter_init(&object->filter, outer, &CLSID_VfwCapture, &filter_ops);
847 object->IAMStreamConfig_iface.lpVtbl = &IAMStreamConfig_VTable;
848 object->IAMVideoControl_iface.lpVtbl = &IAMVideoControl_VTable;
849 object->IAMVideoProcAmp_iface.lpVtbl = &IAMVideoProcAmp_VTable;
850 object->IAMFilterMiscFlags_iface.lpVtbl = &IAMFilterMiscFlags_VTable;
851 object->IPersistPropertyBag_iface.lpVtbl = &IPersistPropertyBag_VTable;
853 strmbase_source_init(&object->source, &object->filter, L"Output", &source_ops);
855 object->IKsPropertySet_iface.lpVtbl = &IKsPropertySet_VTable;
857 object->state = State_Stopped;
858 InitializeConditionVariable(&object->state_cv);
859 InitializeCriticalSection(&object->state_cs);
860 object->state_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": vfw_capture.state_cs");
862 TRACE("Created VFW capture filter %p.\n", object);
863 *out = &object->filter.IUnknown_inner;
864 return S_OK;