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 #define V4L_CALL( func, params ) WINE_UNIX_CALL( unix_ ## func, params )
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
;
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
47 CONDITION_VARIABLE state_cv
;
48 CRITICAL_SECTION state_cs
;
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
);
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
);
99 struct destroy_params params
= { filter
->device
};
100 V4L_CALL( destroy
, ¶ms
);
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
);
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
;
128 return E_NOINTERFACE
;
130 IUnknown_AddRef((IUnknown
*)*out
);
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
;
149 IMediaSample
*sample
;
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
);
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
);
172 IMediaSample_SetActualDataLength(sample
, image_size
);
173 IMediaSample_GetPointer(sample
, &data
);
175 params
.device
= filter
->device
;
177 if (!V4L_CALL( read_frame
, ¶ms
))
179 IMediaSample_Release(sample
);
183 hr
= IMemInputPin_Receive(filter
->source
.pMemInputPin
, sample
);
184 IMediaSample_Release(sample
);
187 ERR("IMemInputPin::Receive() returned %#lx.\n", hr
);
195 static HRESULT
vfw_capture_init_stream(struct strmbase_filter
*iface
)
197 struct vfw_capture
*filter
= impl_from_strmbase_filter(iface
);
200 if (!filter
->source
.pin
.peer
)
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
);
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
)
222 EnterCriticalSection(&filter
->state_cs
);
223 filter
->state
= State_Running
;
224 LeaveCriticalSection(&filter
->state_cs
);
225 WakeConditionVariable(&filter
->state_cv
);
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
)
236 EnterCriticalSection(&filter
->state_cs
);
237 filter
->state
= State_Paused
;
238 LeaveCriticalSection(&filter
->state_cs
);
242 static HRESULT
vfw_capture_cleanup_stream(struct strmbase_filter
*iface
)
244 struct vfw_capture
*filter
= impl_from_strmbase_filter(iface
);
247 if (!filter
->source
.pin
.peer
)
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
);
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
;
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
;
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
;
323 TRACE("pmt is NULL\n");
327 if (!IsEqualGUID(&pmt
->majortype
, &MEDIATYPE_Video
))
330 if (This
->source
.pin
.peer
)
332 hr
= IPin_QueryAccept(This
->source
.pin
.peer
, pmt
);
333 TRACE("QueryAccept() returned %#lx.\n", hr
);
335 return VFW_E_INVALIDMEDIATYPE
;
338 params
.device
= This
->device
;
340 hr
= V4L_CALL( set_format
, ¶ms
);
341 if (SUCCEEDED(hr
) && This
->filter
.graph
&& This
->source
.pin
.peer
)
343 hr
= IFilterGraph_Reconnect(This
->filter
.graph
, &This
->source
.pin
.IPin_iface
);
345 TRACE("Reconnection completed, with new media format..\n");
347 TRACE("Returning %#lx.\n", 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
;
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
);
370 if ((format
= CoTaskMemAlloc(sizeof(VIDEOINFOHEADER
))))
372 struct get_format_params params
= { filter
->device
, *mt
, format
};
373 V4L_CALL( get_format
, ¶ms
);
374 (*mt
)->cbFormat
= sizeof(VIDEOINFOHEADER
);
375 (*mt
)->pbFormat
= (BYTE
*)format
;
384 LeaveCriticalSection(&filter
->filter
.filter_cs
);
387 strmbase_dump_media_type(*mt
);
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
);
404 V4L_CALL( get_caps_count
, ¶ms
);
405 *size
= sizeof(VIDEO_STREAM_CONFIG_CAPS
);
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
;
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
);
426 if (!(mt
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
))))
427 return E_OUTOFMEMORY
;
429 if (!(format
= CoTaskMemAlloc(sizeof(VIDEOINFOHEADER
))))
432 return E_OUTOFMEMORY
;
435 caps_params
.device
= filter
->device
;
436 caps_params
.index
= index
;
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
;
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
, ¶ms
);
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
, ¶ms
);
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
, ¶ms
);
510 static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable
=
512 AMVideoProcAmp_QueryInterface
,
513 AMVideoProcAmp_AddRef
,
514 AMVideoProcAmp_Release
,
515 AMVideoProcAmp_GetRange
,
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
);
548 static HRESULT WINAPI
PPB_InitNew(IPersistPropertyBag
* iface
)
550 struct vfw_capture
*This
= impl_from_IPersistPropertyBag(iface
);
552 FIXME("%p - stub\n", This
);
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
;
564 TRACE("filter %p, bag %p, error_log %p.\n", filter
, bag
, error_log
);
567 if (FAILED(hr
= IPropertyBag_Read(bag
, L
"VFWIndex", &var
, error_log
)))
570 params
.index
= V_I4(&var
);
571 params
.device
= &filter
->device
;
572 hr
= V4L_CALL( create
, ¶ms
);
574 if (SUCCEEDED(hr
)) filter
->init
= TRUE
;
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
);
587 static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable
=
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
,
627 FIXME("%p: stub\n", iface
);
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
)
640 if (!IsEqualIID(guidPropSet
, &ROPSETID_Pin
))
641 return E_PROP_SET_UNSUPPORTED
;
642 if (pPropData
== NULL
&& pcbReturned
== NULL
)
645 *pcbReturned
= sizeof(GUID
);
646 if (pPropData
== NULL
)
648 if (cbPropData
< sizeof(GUID
))
651 *pGuid
= PIN_CATEGORY_CAPTURE
;
652 FIXME("() Not adding a pin with PIN_CATEGORY_PREVIEW\n");
656 static HRESULT WINAPI
657 KSP_QuerySupported( IKsPropertySet
* iface
, REFGUID guidPropSet
,
658 DWORD dwPropID
, DWORD
*pTypeSupport
)
660 FIXME("%p: stub\n", iface
);
664 static const IKsPropertySetVtbl IKsPropertySet_VTable
=
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
, ¶ms
);
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
;
696 if (!(format
= CoTaskMemAlloc(sizeof(*format
))))
697 return E_OUTOFMEMORY
;
699 params
.device
= filter
->device
;
700 params
.index
= index
;
702 params
.format
= format
;
703 if ((hr
= V4L_CALL( get_media_type
, ¶ms
)) != S_OK
)
705 CoTaskMemFree(format
);
708 mt
->cbFormat
= sizeof(VIDEOINFOHEADER
);
709 mt
->pbFormat
= (BYTE
*)format
;
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
;
722 return E_NOINTERFACE
;
724 IUnknown_AddRef((IUnknown
*)*out
);
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
,
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
);
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
);
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
);
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
);
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
);
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
);
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();
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
)
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
;