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
= IMemAllocator_GetBuffer(filter
->source
.pAllocator
, &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 (!filter
->source
.pin
.peer
)
205 if (FAILED(hr
= IMemAllocator_Commit(filter
->source
.pAllocator
)))
206 ERR("Failed to commit allocator, hr %#x.\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
);
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
)
224 EnterCriticalSection(&filter
->state_cs
);
225 filter
->state
= State_Running
;
226 LeaveCriticalSection(&filter
->state_cs
);
227 WakeConditionVariable(&filter
->state_cv
);
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
)
238 EnterCriticalSection(&filter
->state_cs
);
239 filter
->state
= State_Paused
;
240 LeaveCriticalSection(&filter
->state_cs
);
244 static HRESULT
vfw_capture_cleanup_stream(struct strmbase_filter
*iface
)
246 struct vfw_capture
*filter
= impl_from_strmbase_filter(iface
);
249 if (!filter
->source
.pin
.peer
)
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 %#x.\n", hr
);
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
;
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
;
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
;
325 TRACE("pmt is NULL\n");
329 if (!IsEqualGUID(&pmt
->majortype
, &MEDIATYPE_Video
))
332 if (This
->source
.pin
.peer
)
334 hr
= IPin_QueryAccept(This
->source
.pin
.peer
, pmt
);
335 TRACE("Would accept: %d\n", hr
);
337 return VFW_E_INVALIDMEDIATYPE
;
340 params
.device
= This
->device
;
342 hr
= V4L_CALL( set_format
, ¶ms
);
343 if (SUCCEEDED(hr
) && This
->filter
.graph
&& This
->source
.pin
.peer
)
345 hr
= IFilterGraph_Reconnect(This
->filter
.graph
, &This
->source
.pin
.IPin_iface
);
347 TRACE("Reconnection completed, with new media format..\n");
349 TRACE("Returning: %d\n", 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
;
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
);
372 if ((format
= CoTaskMemAlloc(sizeof(VIDEOINFOHEADER
))))
374 struct get_format_params params
= { filter
->device
, *mt
, format
};
375 V4L_CALL( get_format
, ¶ms
);
376 (*mt
)->cbFormat
= sizeof(VIDEOINFOHEADER
);
377 (*mt
)->pbFormat
= (BYTE
*)format
;
386 LeaveCriticalSection(&filter
->filter
.filter_cs
);
389 strmbase_dump_media_type(*mt
);
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
);
406 V4L_CALL( get_caps_count
, ¶ms
);
407 *size
= sizeof(VIDEO_STREAM_CONFIG_CAPS
);
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
;
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
);
428 if (!(mt
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
))))
429 return E_OUTOFMEMORY
;
431 if (!(format
= CoTaskMemAlloc(sizeof(VIDEOINFOHEADER
))))
434 return E_OUTOFMEMORY
;
437 caps_params
.device
= filter
->device
;
438 caps_params
.index
= index
;
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
;
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 %#x, 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
, ¶ms
);
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 %#x, value %d, flags %#x.\n", filter
, property
, value
, flags
);
498 return V4L_CALL( set_prop
, ¶ms
);
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 %#x, value %p, flags %p.\n", filter
, property
, value
, flags
);
509 return V4L_CALL( get_prop
, ¶ms
);
512 static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable
=
514 AMVideoProcAmp_QueryInterface
,
515 AMVideoProcAmp_AddRef
,
516 AMVideoProcAmp_Release
,
517 AMVideoProcAmp_GetRange
,
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
);
550 static HRESULT WINAPI
PPB_InitNew(IPersistPropertyBag
* iface
)
552 struct vfw_capture
*This
= impl_from_IPersistPropertyBag(iface
);
554 FIXME("%p - stub\n", This
);
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
;
566 TRACE("filter %p, bag %p, error_log %p.\n", filter
, bag
, error_log
);
569 if (FAILED(hr
= IPropertyBag_Read(bag
, L
"VFWIndex", &var
, error_log
)))
572 params
.index
= V_I4(&var
);
573 params
.device
= &filter
->device
;
574 hr
= V4L_CALL( create
, ¶ms
);
576 if (SUCCEEDED(hr
)) filter
->init
= TRUE
;
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
);
589 static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable
=
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
,
629 FIXME("%p: stub\n", iface
);
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
)
642 if (!IsEqualIID(guidPropSet
, &ROPSETID_Pin
))
643 return E_PROP_SET_UNSUPPORTED
;
644 if (pPropData
== NULL
&& pcbReturned
== NULL
)
647 *pcbReturned
= sizeof(GUID
);
648 if (pPropData
== NULL
)
650 if (cbPropData
< sizeof(GUID
))
653 *pGuid
= PIN_CATEGORY_CAPTURE
;
654 FIXME("() Not adding a pin with PIN_CATEGORY_PREVIEW\n");
658 static HRESULT WINAPI
659 KSP_QuerySupported( IKsPropertySet
* iface
, REFGUID guidPropSet
,
660 DWORD dwPropID
, DWORD
*pTypeSupport
)
662 FIXME("%p: stub\n", iface
);
666 static const IKsPropertySetVtbl IKsPropertySet_VTable
=
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
, ¶ms
);
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
;
698 if (!(format
= CoTaskMemAlloc(sizeof(*format
))))
699 return E_OUTOFMEMORY
;
701 params
.device
= filter
->device
;
702 params
.index
= index
;
704 params
.format
= format
;
705 if ((hr
= V4L_CALL( get_media_type
, ¶ms
)) != S_OK
)
707 CoTaskMemFree(format
);
710 mt
->cbFormat
= sizeof(VIDEOINFOHEADER
);
711 mt
->pbFormat
= (BYTE
*)format
;
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
;
724 return E_NOINTERFACE
;
726 IUnknown_AddRef((IUnknown
*)*out
);
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
,
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
);
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 %d: stub.\n", filter
, pin
, mode
);
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
);
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
);
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 %d, dimensions (%dx%d), frame rate %p: stub.\n",
848 filter
, pin
, index
, dimensions
.cx
, dimensions
.cy
, frame_rate
);
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 %d, dimensions (%dx%d), list size %p, frame rate: %p: stub.\n",
859 filter
, pin
, index
, dimensions
.cx
, dimensions
.cy
, list_size
, frame_rate
);
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
);
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
)
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
;