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"
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 )
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
;
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
49 CONDITION_VARIABLE state_cv
;
50 CRITICAL_SECTION state_cs
;
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
);
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
);
101 struct destroy_params params
= { filter
->device
};
102 V4L_CALL( destroy
, ¶ms
);
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
);
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
;
130 return E_NOINTERFACE
;
132 IUnknown_AddRef((IUnknown
*)*out
);
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
;
151 IMediaSample
*sample
;
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
);
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
);
174 IMediaSample_SetActualDataLength(sample
, image_size
);
175 IMediaSample_GetPointer(sample
, &data
);
177 params
.device
= filter
->device
;
179 if (!V4L_CALL( read_frame
, ¶ms
))
181 IMediaSample_Release(sample
);
185 hr
= IMemInputPin_Receive(filter
->source
.pMemInputPin
, sample
);
186 IMediaSample_Release(sample
);
189 ERR("IMemInputPin::Receive() returned %#x.\n", hr
);
197 static HRESULT
vfw_capture_init_stream(struct strmbase_filter
*iface
)
199 struct vfw_capture
*filter
= impl_from_strmbase_filter(iface
);
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
);
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
);
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
);
235 static HRESULT
vfw_capture_cleanup_stream(struct strmbase_filter
*iface
)
237 struct vfw_capture
*filter
= impl_from_strmbase_filter(iface
);
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
);
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
;
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
;
309 TRACE("pmt is NULL\n");
313 if (!IsEqualGUID(&pmt
->majortype
, &MEDIATYPE_Video
))
316 if (This
->source
.pin
.peer
)
318 hr
= IPin_QueryAccept(This
->source
.pin
.peer
, pmt
);
319 TRACE("Would accept: %d\n", hr
);
321 return VFW_E_INVALIDMEDIATYPE
;
324 params
.device
= This
->device
;
326 hr
= V4L_CALL( set_format
, ¶ms
);
327 if (SUCCEEDED(hr
) && This
->filter
.graph
&& This
->source
.pin
.peer
)
329 hr
= IFilterGraph_Reconnect(This
->filter
.graph
, &This
->source
.pin
.IPin_iface
);
331 TRACE("Reconnection completed, with new media format..\n");
333 TRACE("Returning: %d\n", 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
;
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
);
356 if ((format
= CoTaskMemAlloc(sizeof(VIDEOINFOHEADER
))))
358 struct get_format_params params
= { filter
->device
, *mt
, format
};
359 V4L_CALL( get_format
, ¶ms
);
360 (*mt
)->cbFormat
= sizeof(VIDEOINFOHEADER
);
361 (*mt
)->pbFormat
= (BYTE
*)format
;
370 LeaveCriticalSection(&filter
->filter
.filter_cs
);
373 strmbase_dump_media_type(*mt
);
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
);
390 V4L_CALL( get_caps_count
, ¶ms
);
391 *size
= sizeof(VIDEO_STREAM_CONFIG_CAPS
);
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
;
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
);
412 if (!(mt
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
))))
413 return E_OUTOFMEMORY
;
415 if (!(format
= CoTaskMemAlloc(sizeof(VIDEOINFOHEADER
))))
418 return E_OUTOFMEMORY
;
421 caps_params
.device
= filter
->device
;
422 caps_params
.index
= index
;
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
;
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
, ¶ms
);
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
, ¶ms
);
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
, ¶ms
);
496 static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable
=
498 AMVideoProcAmp_QueryInterface
,
499 AMVideoProcAmp_AddRef
,
500 AMVideoProcAmp_Release
,
501 AMVideoProcAmp_GetRange
,
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
);
534 static HRESULT WINAPI
PPB_InitNew(IPersistPropertyBag
* iface
)
536 struct vfw_capture
*This
= impl_from_IPersistPropertyBag(iface
);
538 FIXME("%p - stub\n", This
);
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
;
550 TRACE("filter %p, bag %p, error_log %p.\n", filter
, bag
, error_log
);
553 if (FAILED(hr
= IPropertyBag_Read(bag
, L
"VFWIndex", &var
, error_log
)))
556 params
.index
= V_I4(&var
);
557 params
.device
= &filter
->device
;
558 hr
= V4L_CALL( create
, ¶ms
);
560 if (SUCCEEDED(hr
)) filter
->init
= TRUE
;
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
);
573 static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable
=
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
,
613 FIXME("%p: stub\n", iface
);
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
)
626 if (!IsEqualIID(guidPropSet
, &ROPSETID_Pin
))
627 return E_PROP_SET_UNSUPPORTED
;
628 if (pPropData
== NULL
&& pcbReturned
== NULL
)
631 *pcbReturned
= sizeof(GUID
);
632 if (pPropData
== NULL
)
634 if (cbPropData
< sizeof(GUID
))
637 *pGuid
= PIN_CATEGORY_CAPTURE
;
638 FIXME("() Not adding a pin with PIN_CATEGORY_PREVIEW\n");
642 static HRESULT WINAPI
643 KSP_QuerySupported( IKsPropertySet
* iface
, REFGUID guidPropSet
,
644 DWORD dwPropID
, DWORD
*pTypeSupport
)
646 FIXME("%p: stub\n", iface
);
650 static const IKsPropertySetVtbl IKsPropertySet_VTable
=
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
};
670 if (!mt
) return E_POINTER
;
671 return V4L_CALL( check_format
, ¶ms
);
674 static HRESULT
source_get_media_type(struct strmbase_pin
*pin
,
675 unsigned int index
, AM_MEDIA_TYPE
*mt
)
677 struct vfw_capture
*filter
= impl_from_strmbase_pin(pin
);
678 struct get_media_type_params params
;
679 VIDEOINFOHEADER
*format
;
682 if (!(format
= CoTaskMemAlloc(sizeof(*format
))))
683 return E_OUTOFMEMORY
;
685 params
.device
= filter
->device
;
686 params
.index
= index
;
688 params
.format
= format
;
689 if ((hr
= V4L_CALL( get_media_type
, ¶ms
)) != S_OK
)
691 CoTaskMemFree(format
);
694 mt
->cbFormat
= sizeof(VIDEOINFOHEADER
);
695 mt
->pbFormat
= (BYTE
*)format
;
699 static HRESULT
source_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
701 struct vfw_capture
*filter
= impl_from_strmbase_pin(iface
);
703 if (IsEqualGUID(iid
, &IID_IKsPropertySet
))
704 *out
= &filter
->IKsPropertySet_iface
;
705 else if (IsEqualGUID(iid
, &IID_IAMStreamConfig
))
706 *out
= &filter
->IAMStreamConfig_iface
;
708 return E_NOINTERFACE
;
710 IUnknown_AddRef((IUnknown
*)*out
);
714 static HRESULT WINAPI
VfwPin_DecideBufferSize(struct strmbase_source
*iface
,
715 IMemAllocator
*allocator
, ALLOCATOR_PROPERTIES
*req_props
)
717 struct vfw_capture
*filter
= impl_from_strmbase_pin(&iface
->pin
);
718 ALLOCATOR_PROPERTIES ret_props
;
720 if (!req_props
->cBuffers
)
721 req_props
->cBuffers
= 3;
722 if (!req_props
->cbBuffer
)
723 req_props
->cbBuffer
= get_image_size(filter
);
724 if (!req_props
->cbAlign
)
725 req_props
->cbAlign
= 1;
727 return IMemAllocator_SetProperties(allocator
, req_props
, &ret_props
);
730 static const struct strmbase_source_ops source_ops
=
732 .base
.pin_query_accept
= source_query_accept
,
733 .base
.pin_get_media_type
= source_get_media_type
,
734 .base
.pin_query_interface
= source_query_interface
,
735 .pfnAttemptConnection
= BaseOutputPinImpl_AttemptConnection
,
736 .pfnDecideBufferSize
= VfwPin_DecideBufferSize
,
737 .pfnDecideAllocator
= BaseOutputPinImpl_DecideAllocator
,
740 static HRESULT WINAPI
misc_flags_QueryInterface(IAMFilterMiscFlags
*iface
, REFIID riid
, void **ppv
)
742 struct vfw_capture
*filter
= impl_from_IAMFilterMiscFlags(iface
);
743 return IUnknown_QueryInterface(filter
->filter
.outer_unk
, riid
, ppv
);
746 static ULONG WINAPI
misc_flags_AddRef(IAMFilterMiscFlags
*iface
)
748 struct vfw_capture
*filter
= impl_from_IAMFilterMiscFlags(iface
);
749 return IUnknown_AddRef(filter
->filter
.outer_unk
);
752 static ULONG WINAPI
misc_flags_Release(IAMFilterMiscFlags
*iface
)
754 struct vfw_capture
*filter
= impl_from_IAMFilterMiscFlags(iface
);
755 return IUnknown_Release(filter
->filter
.outer_unk
);
758 static ULONG WINAPI
misc_flags_GetMiscFlags(IAMFilterMiscFlags
*iface
)
760 return AM_FILTER_MISC_FLAGS_IS_SOURCE
;
763 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_VTable
=
765 misc_flags_QueryInterface
,
768 misc_flags_GetMiscFlags
771 static HRESULT WINAPI
video_control_QueryInterface(IAMVideoControl
*iface
, REFIID riid
, void **ppv
)
773 struct vfw_capture
*filter
= impl_from_IAMVideoControl(iface
);
774 return IUnknown_QueryInterface(filter
->filter
.outer_unk
, riid
, ppv
);
777 static ULONG WINAPI
video_control_AddRef(IAMVideoControl
*iface
)
779 struct vfw_capture
*filter
= impl_from_IAMVideoControl(iface
);
780 return IUnknown_AddRef(filter
->filter
.outer_unk
);
783 static ULONG WINAPI
video_control_Release(IAMVideoControl
*iface
)
785 struct vfw_capture
*filter
= impl_from_IAMVideoControl(iface
);
786 return IUnknown_Release(filter
->filter
.outer_unk
);
789 static HRESULT WINAPI
video_control_GetCaps(IAMVideoControl
*iface
, IPin
*pin
, LONG
*flags
)
791 struct vfw_capture
*filter
= impl_from_IAMVideoControl(iface
);
793 FIXME("filter %p, pin %p, flags %p: stub.\n", filter
, pin
, flags
);
798 static HRESULT WINAPI
video_control_SetMode(IAMVideoControl
*iface
, IPin
*pin
, LONG mode
)
800 struct vfw_capture
*filter
= impl_from_IAMVideoControl(iface
);
802 FIXME("filter %p, pin %p, mode %d: stub.\n", filter
, pin
, mode
);
807 static HRESULT WINAPI
video_control_GetMode(IAMVideoControl
*iface
, IPin
*pin
, LONG
*mode
)
809 struct vfw_capture
*filter
= impl_from_IAMVideoControl(iface
);
811 FIXME("filter %p, pin %p, mode %p: stub.\n", filter
, pin
, mode
);
816 static HRESULT WINAPI
video_control_GetCurrentActualFrameRate(IAMVideoControl
*iface
, IPin
*pin
,
817 LONGLONG
*frame_rate
)
819 struct vfw_capture
*filter
= impl_from_IAMVideoControl(iface
);
821 FIXME("filter %p, pin %p, frame rate %p: stub.\n", filter
, pin
, frame_rate
);
826 static HRESULT WINAPI
video_control_GetMaxAvailableFrameRate(IAMVideoControl
*iface
, IPin
*pin
,
827 LONG index
, SIZE dimensions
, LONGLONG
*frame_rate
)
829 struct vfw_capture
*filter
= impl_from_IAMVideoControl(iface
);
831 FIXME("filter %p, pin %p, index %d, dimensions (%dx%d), frame rate %p: stub.\n",
832 filter
, pin
, index
, dimensions
.cx
, dimensions
.cy
, frame_rate
);
837 static HRESULT WINAPI
video_control_GetFrameRateList(IAMVideoControl
*iface
, IPin
*pin
, LONG index
,
838 SIZE dimensions
, LONG
*list_size
, LONGLONG
**frame_rate
)
840 struct vfw_capture
*filter
= impl_from_IAMVideoControl(iface
);
842 FIXME("filter %p, pin %p, index %d, dimensions (%dx%d), list size %p, frame rate: %p: stub.\n",
843 filter
, pin
, index
, dimensions
.cx
, dimensions
.cy
, list_size
, frame_rate
);
848 static const IAMVideoControlVtbl IAMVideoControl_VTable
=
850 video_control_QueryInterface
,
851 video_control_AddRef
,
852 video_control_Release
,
853 video_control_GetCaps
,
854 video_control_SetMode
,
855 video_control_GetMode
,
856 video_control_GetCurrentActualFrameRate
,
857 video_control_GetMaxAvailableFrameRate
,
858 video_control_GetFrameRateList
861 static BOOL WINAPI
load_capture_funcs(INIT_ONCE
*once
, void *param
, void **context
)
863 NtQueryVirtualMemory( GetCurrentProcess(), qcap_instance
, MemoryWineUnixFuncs
,
864 &v4l_handle
, sizeof(v4l_handle
), NULL
);
868 static INIT_ONCE init_once
= INIT_ONCE_STATIC_INIT
;
870 HRESULT
vfw_capture_create(IUnknown
*outer
, IUnknown
**out
)
872 struct vfw_capture
*object
;
874 if (!InitOnceExecuteOnce(&init_once
, load_capture_funcs
, NULL
, NULL
) || !v4l_handle
)
877 if (!(object
= calloc(1, sizeof(*object
))))
878 return E_OUTOFMEMORY
;
880 strmbase_filter_init(&object
->filter
, outer
, &CLSID_VfwCapture
, &filter_ops
);
882 object
->IAMStreamConfig_iface
.lpVtbl
= &IAMStreamConfig_VTable
;
883 object
->IAMVideoControl_iface
.lpVtbl
= &IAMVideoControl_VTable
;
884 object
->IAMVideoProcAmp_iface
.lpVtbl
= &IAMVideoProcAmp_VTable
;
885 object
->IAMFilterMiscFlags_iface
.lpVtbl
= &IAMFilterMiscFlags_VTable
;
886 object
->IPersistPropertyBag_iface
.lpVtbl
= &IPersistPropertyBag_VTable
;
888 strmbase_source_init(&object
->source
, &object
->filter
, L
"Output", &source_ops
);
890 object
->IKsPropertySet_iface
.lpVtbl
= &IKsPropertySet_VTable
;
892 object
->state
= State_Stopped
;
893 InitializeConditionVariable(&object
->state_cv
);
894 InitializeCriticalSection(&object
->state_cs
);
895 object
->state_cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": vfw_capture.state_cs");
897 TRACE("Created VFW capture filter %p.\n", object
);
898 *out
= &object
->filter
.IUnknown_inner
;