qcap: Convert the Unix library to the __wine_unix_call interface.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-11-02 18:38:11 +01:00
parent 626f85f5f6
commit 62e2d7a99b
4 changed files with 255 additions and 110 deletions

View File

@ -1,4 +1,5 @@
MODULE = qcap.dll
UNIXLIB = qcap.so
IMPORTS = strmbase strmiids uuid ole32 oleaut32
DELAYIMPORTS = msvfw32

View File

@ -25,6 +25,8 @@
#define NONAMELESSSTRUCT
#define NONAMELESSUNION
#include "dshow.h"
#include "winternl.h"
#include "wine/unixlib.h"
#include "wine/debug.h"
#include "wine/strmbase.h"
@ -38,25 +40,108 @@ HRESULT file_writer_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
HRESULT smart_tee_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
HRESULT vfw_capture_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
struct video_capture_funcs
struct video_capture_device;
struct create_params
{
struct video_capture_device *(CDECL *create)(USHORT index);
void (CDECL *destroy)(struct video_capture_device *device);
HRESULT (CDECL *check_format)(struct video_capture_device *device, const AM_MEDIA_TYPE *mt);
HRESULT (CDECL *set_format)(struct video_capture_device *device, const AM_MEDIA_TYPE *mt);
void (CDECL *get_format)(struct video_capture_device *device, AM_MEDIA_TYPE *mt, VIDEOINFOHEADER *format);
HRESULT (CDECL *get_media_type)(struct video_capture_device *device,
unsigned int index, AM_MEDIA_TYPE *mt, VIDEOINFOHEADER *format);
void (CDECL *get_caps)(struct video_capture_device *device, LONG index, AM_MEDIA_TYPE *mt,
VIDEOINFOHEADER *format, VIDEO_STREAM_CONFIG_CAPS *caps);
LONG (CDECL *get_caps_count)(struct video_capture_device *device);
HRESULT (CDECL *get_prop_range)(struct video_capture_device *device, VideoProcAmpProperty property,
LONG *min, LONG *max, LONG *step, LONG *default_value, LONG *flags);
HRESULT (CDECL *get_prop)(struct video_capture_device *device,
VideoProcAmpProperty property, LONG *value, LONG *flags);
HRESULT (CDECL *set_prop)(struct video_capture_device *device,
VideoProcAmpProperty property, LONG value, LONG flags);
BOOL (CDECL *read_frame)(struct video_capture_device *device, BYTE *data);
unsigned int index;
struct video_capture_device **device;
};
struct destroy_params
{
struct video_capture_device *device;
};
struct check_format_params
{
struct video_capture_device *device;
const AM_MEDIA_TYPE *mt;
};
struct set_format_params
{
struct video_capture_device *device;
const AM_MEDIA_TYPE *mt;
};
struct get_format_params
{
struct video_capture_device *device;
AM_MEDIA_TYPE *mt;
VIDEOINFOHEADER *format;
};
struct get_media_type_params
{
struct video_capture_device *device;
unsigned int index;
AM_MEDIA_TYPE *mt;
VIDEOINFOHEADER *format;
};
struct get_caps_params
{
struct video_capture_device *device;
unsigned int index;
AM_MEDIA_TYPE *mt;
VIDEOINFOHEADER *format;
VIDEO_STREAM_CONFIG_CAPS *caps;
};
struct get_caps_count_params
{
struct video_capture_device *device;
int *count;
};
struct get_prop_range_params
{
struct video_capture_device *device;
VideoProcAmpProperty property;
LONG *min;
LONG *max;
LONG *step;
LONG *default_value;
LONG *flags;
};
struct get_prop_params
{
struct video_capture_device *device;
VideoProcAmpProperty property;
LONG *value;
LONG *flags;
};
struct set_prop_params
{
struct video_capture_device *device;
VideoProcAmpProperty property;
LONG value;
LONG flags;
};
struct read_frame_params
{
struct video_capture_device *device;
void *data;
};
enum unix_funcs
{
unix_create,
unix_destroy,
unix_check_format,
unix_set_format,
unix_get_format,
unix_get_media_type,
unix_get_caps,
unix_get_caps_count,
unix_get_prop_range,
unix_get_prop,
unix_set_prop,
unix_read_frame,
};
#endif

View File

@ -26,11 +26,12 @@
#define BIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD /* work around ioctl breakage on Android */
#include "config.h"
#include "wine/port.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <dlfcn.h>
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
@ -118,7 +119,7 @@ static int xioctl(int fd, int request, void * arg)
return r;
}
static void CDECL v4l_device_destroy(struct video_capture_device *device)
static void device_destroy(struct video_capture_device *device)
{
if (device->fd != -1)
video_close(device->fd);
@ -148,17 +149,20 @@ static const struct caps *find_caps(struct video_capture_device *device, const A
return NULL;
}
static HRESULT CDECL v4l_device_check_format(struct video_capture_device *device, const AM_MEDIA_TYPE *mt)
static NTSTATUS v4l_device_check_format( void *args )
{
TRACE("device %p, mt %p.\n", device, mt);
struct check_format_params *params = args;
struct video_capture_device *device = params->device;
if (!mt)
TRACE("device %p, mt %p.\n", device, params->mt);
if (!params->mt)
return E_POINTER;
if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Video))
if (!IsEqualGUID(&params->mt->majortype, &MEDIATYPE_Video))
return E_FAIL;
if (find_caps(device, mt))
if (find_caps(device, params->mt))
return S_OK;
return E_FAIL;
@ -202,11 +206,13 @@ static HRESULT set_caps(struct video_capture_device *device, const struct caps *
return S_OK;
}
static HRESULT CDECL v4l_device_set_format(struct video_capture_device *device, const AM_MEDIA_TYPE *mt)
static NTSTATUS v4l_device_set_format( void *args )
{
struct set_format_params *params = args;
struct video_capture_device *device = params->device;
const struct caps *caps;
caps = find_caps(device, mt);
caps = find_caps(device, params->mt);
if (!caps)
return E_FAIL;
@ -216,29 +222,34 @@ static HRESULT CDECL v4l_device_set_format(struct video_capture_device *device,
return set_caps(device, caps);
}
static void CDECL v4l_device_get_format(struct video_capture_device *device, AM_MEDIA_TYPE *mt, VIDEOINFOHEADER *format)
static NTSTATUS v4l_device_get_format( void *args )
{
*mt = device->current_caps->media_type;
*format = device->current_caps->video_info;
struct get_format_params *params = args;
struct video_capture_device *device = params->device;
*params->mt = device->current_caps->media_type;
*params->format = device->current_caps->video_info;
return S_OK;
}
static HRESULT CDECL v4l_device_get_media_type(struct video_capture_device *device,
unsigned int index, AM_MEDIA_TYPE *mt, VIDEOINFOHEADER *format)
static NTSTATUS v4l_device_get_media_type( void *args )
{
struct get_media_type_params *params = args;
struct video_capture_device *device = params->device;
unsigned int caps_count = (device->current_caps) ? 1 : device->caps_count;
if (index >= caps_count)
if (params->index >= caps_count)
return VFW_S_NO_MORE_ITEMS;
if (device->current_caps)
{
*mt = device->current_caps->media_type;
*format = device->current_caps->video_info;
*params->mt = device->current_caps->media_type;
*params->format = device->current_caps->video_info;
}
else
{
*mt = device->caps[index].media_type;
*format = device->caps[index].video_info;
*params->mt = device->caps[params->index].media_type;
*params->format = device->caps[params->index].video_info;
}
return S_OK;
}
@ -261,12 +272,13 @@ static __u32 v4l2_cid_from_qcap_property(VideoProcAmpProperty property)
}
}
static HRESULT CDECL v4l_device_get_prop_range(struct video_capture_device *device, VideoProcAmpProperty property,
LONG *min, LONG *max, LONG *step, LONG *default_value, LONG *flags)
static NTSTATUS v4l_device_get_prop_range( void *args )
{
struct get_prop_range_params *params = args;
struct video_capture_device *device = params->device;
struct v4l2_queryctrl ctrl;
ctrl.id = v4l2_cid_from_qcap_property(property);
ctrl.id = v4l2_cid_from_qcap_property(params->property);
if (xioctl(device->fd, VIDIOC_QUERYCTRL, &ctrl) == -1)
{
@ -274,20 +286,21 @@ static HRESULT CDECL v4l_device_get_prop_range(struct video_capture_device *devi
return E_PROP_ID_UNSUPPORTED;
}
*min = ctrl.minimum;
*max = ctrl.maximum;
*step = ctrl.step;
*default_value = ctrl.default_value;
*flags = VideoProcAmp_Flags_Manual;
*params->min = ctrl.minimum;
*params->max = ctrl.maximum;
*params->step = ctrl.step;
*params->default_value = ctrl.default_value;
*params->flags = VideoProcAmp_Flags_Manual;
return S_OK;
}
static HRESULT CDECL v4l_device_get_prop(struct video_capture_device *device,
VideoProcAmpProperty property, LONG *value, LONG *flags)
static NTSTATUS v4l_device_get_prop( void *args )
{
struct get_prop_params *params = args;
struct video_capture_device *device = params->device;
struct v4l2_control ctrl;
ctrl.id = v4l2_cid_from_qcap_property(property);
ctrl.id = v4l2_cid_from_qcap_property(params->property);
if (xioctl(device->fd, VIDIOC_G_CTRL, &ctrl) == -1)
{
@ -295,19 +308,20 @@ static HRESULT CDECL v4l_device_get_prop(struct video_capture_device *device,
return E_FAIL;
}
*value = ctrl.value;
*flags = VideoProcAmp_Flags_Manual;
*params->value = ctrl.value;
*params->flags = VideoProcAmp_Flags_Manual;
return S_OK;
}
static HRESULT CDECL v4l_device_set_prop(struct video_capture_device *device,
VideoProcAmpProperty property, LONG value, LONG flags)
static NTSTATUS v4l_device_set_prop( void *args )
{
struct set_prop_params *params = args;
struct video_capture_device *device = params->device;
struct v4l2_control ctrl;
ctrl.id = v4l2_cid_from_qcap_property(property);
ctrl.value = value;
ctrl.id = v4l2_cid_from_qcap_property(params->property);
ctrl.value = params->value;
if (xioctl(device->fd, VIDIOC_S_CTRL, &ctrl) == -1)
{
@ -337,8 +351,11 @@ static void reverse_image(struct video_capture_device *device, LPBYTE output, co
}
}
static BOOL CDECL v4l_device_read_frame(struct video_capture_device *device, BYTE *data)
static NTSTATUS v4l_device_read_frame( void *args )
{
struct read_frame_params *params = args;
struct video_capture_device *device = params->device;
while (video_read(device->fd, device->image_data, device->image_size) < 0)
{
if (errno != EAGAIN)
@ -348,7 +365,7 @@ static BOOL CDECL v4l_device_read_frame(struct video_capture_device *device, BYT
}
}
reverse_image(device, data, device->image_data);
reverse_image(device, params->data, device->image_data);
return TRUE;
}
@ -388,21 +405,29 @@ static void fill_caps(__u32 pixelformat, __u32 width, __u32 height,
caps->pixelformat = pixelformat;
}
static void CDECL v4l_device_get_caps(struct video_capture_device *device, LONG index,
AM_MEDIA_TYPE *type, VIDEOINFOHEADER *format, VIDEO_STREAM_CONFIG_CAPS *vscc)
static NTSTATUS v4l_device_get_caps( void *args )
{
*vscc = device->caps[index].config;
*type = device->caps[index].media_type;
*format = device->caps[index].video_info;
struct get_caps_params *params = args;
struct video_capture_device *device = params->device;
*params->caps = device->caps[params->index].config;
*params->mt = device->caps[params->index].media_type;
*params->format = device->caps[params->index].video_info;
return S_OK;
}
static LONG CDECL v4l_device_get_caps_count(struct video_capture_device *device)
static NTSTATUS v4l_device_get_caps_count( void *args )
{
return device->caps_count;
struct get_caps_count_params *params = args;
struct video_capture_device *device = params->device;
*params->count = device->caps_count;
return S_OK;
}
static struct video_capture_device * CDECL v4l_device_create(USHORT index)
static NTSTATUS v4l_device_create( void *args )
{
struct create_params *params = args;
struct v4l2_frmsizeenum frmsize = {0};
struct video_capture_device *device;
struct v4l2_capability caps = {{0}};
@ -415,9 +440,9 @@ static struct video_capture_device * CDECL v4l_device_create(USHORT index)
have_libv4l2 = video_init();
if (!(device = calloc(1, sizeof(*device))))
return NULL;
return E_OUTOFMEMORY;
sprintf(path, "/dev/video%i", index);
sprintf(path, "/dev/video%i", params->index);
TRACE("Opening device %s.\n", path);
#ifdef O_CLOEXEC
if ((fd = video_open(path, O_RDWR | O_NONBLOCK | O_CLOEXEC)) == -1 && errno == EINVAL)
@ -542,35 +567,36 @@ static struct video_capture_device * CDECL v4l_device_create(USHORT index)
device->current_caps->video_info.bmiHeader.biWidth,
device->current_caps->video_info.bmiHeader.biHeight);
return device;
*params->device = device;
return S_OK;
error:
v4l_device_destroy(device);
return NULL;
device_destroy(device);
return E_FAIL;
}
const struct video_capture_funcs v4l_funcs =
static NTSTATUS v4l_device_destroy( void *args )
{
.create = v4l_device_create,
.destroy = v4l_device_destroy,
.check_format = v4l_device_check_format,
.set_format = v4l_device_set_format,
.get_format = v4l_device_get_format,
.get_media_type = v4l_device_get_media_type,
.get_caps = v4l_device_get_caps,
.get_caps_count = v4l_device_get_caps_count,
.get_prop_range = v4l_device_get_prop_range,
.get_prop = v4l_device_get_prop,
.set_prop = v4l_device_set_prop,
.read_frame = v4l_device_read_frame,
struct destroy_params *params = args;
device_destroy( params->device );
return S_OK;
}
unixlib_entry_t __wine_unix_call_funcs[] =
{
v4l_device_create,
v4l_device_destroy,
v4l_device_check_format,
v4l_device_set_format,
v4l_device_get_format,
v4l_device_get_media_type,
v4l_device_get_caps,
v4l_device_get_caps_count,
v4l_device_get_prop_range,
v4l_device_get_prop,
v4l_device_set_prop,
v4l_device_read_frame,
};
NTSTATUS CDECL __wine_init_unix_lib(HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out)
{
if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS;
*(const struct video_capture_funcs **)ptr_out = &v4l_funcs;
return STATUS_SUCCESS;
}
#endif /* HAVE_LINUX_VIDEODEV2_H */

View File

@ -23,7 +23,9 @@
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
static const struct video_capture_funcs *capture_funcs;
static unixlib_handle_t v4l_handle;
#define V4L_CALL( func, params ) __wine_unix_call( v4l_handle, unix_ ## func, params )
struct vfw_capture
{
@ -95,7 +97,10 @@ static void vfw_capture_destroy(struct strmbase_filter *iface)
struct vfw_capture *filter = impl_from_strmbase_filter(iface);
if (filter->init)
capture_funcs->destroy(filter->device);
{
struct destroy_params params = { filter->device };
V4L_CALL( destroy, &params );
}
if (filter->source.pin.peer)
{
@ -139,6 +144,7 @@ static DWORD WINAPI stream_thread(void *arg)
{
struct vfw_capture *filter = arg;
const unsigned int image_size = get_image_size(filter);
struct read_frame_params params;
for (;;)
{
@ -168,7 +174,9 @@ static DWORD WINAPI stream_thread(void *arg)
IMediaSample_SetActualDataLength(sample, image_size);
IMediaSample_GetPointer(sample, &data);
if (!capture_funcs->read_frame(filter->device, data))
params.device = filter->device;
params.data = data;
if (!V4L_CALL( read_frame, &params ))
{
IMediaSample_Release(sample);
break;
@ -284,6 +292,7 @@ static HRESULT WINAPI
AMStreamConfig_SetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE *pmt)
{
struct vfw_capture *This = impl_from_IAMStreamConfig(iface);
struct set_format_params params;
HRESULT hr;
TRACE("filter %p, mt %p.\n", This, pmt);
@ -312,7 +321,9 @@ AMStreamConfig_SetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE *pmt)
return VFW_E_INVALIDMEDIATYPE;
}
hr = capture_funcs->set_format(This->device, pmt);
params.device = This->device;
params.mt = pmt;
hr = V4L_CALL( set_format, &params );
if (SUCCEEDED(hr) && This->filter.graph && This->source.pin.peer)
{
hr = IFilterGraph_Reconnect(This->filter.graph, &This->source.pin.IPin_iface);
@ -344,7 +355,8 @@ static HRESULT WINAPI AMStreamConfig_GetFormat(IAMStreamConfig *iface, AM_MEDIA_
{
if ((format = CoTaskMemAlloc(sizeof(VIDEOINFOHEADER))))
{
capture_funcs->get_format(filter->device, *mt, format);
struct get_format_params params = { filter->device, *mt, format };
V4L_CALL( get_format, &params );
(*mt)->cbFormat = sizeof(VIDEOINFOHEADER);
(*mt)->pbFormat = (BYTE *)format;
hr = S_OK;
@ -368,13 +380,14 @@ static HRESULT WINAPI AMStreamConfig_GetNumberOfCapabilities(IAMStreamConfig *if
int *count, int *size)
{
struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
struct get_caps_count_params params = { filter->device, count };
TRACE("filter %p, count %p, size %p.\n", filter, count, size);
if (!count || !size)
return E_POINTER;
*count = capture_funcs->get_caps_count(filter->device);
V4L_CALL( get_caps_count, &params );
*size = sizeof(VIDEO_STREAM_CONFIG_CAPS);
return S_OK;
@ -386,10 +399,14 @@ static HRESULT WINAPI AMStreamConfig_GetStreamCaps(IAMStreamConfig *iface,
struct vfw_capture *filter = impl_from_IAMStreamConfig(iface);
VIDEOINFOHEADER *format;
AM_MEDIA_TYPE *mt;
int count;
struct get_caps_count_params count_params = { filter->device, &count };
struct get_caps_params caps_params;
TRACE("filter %p, index %d, pmt %p, vscc %p.\n", filter, index, pmt, vscc);
if (index > capture_funcs->get_caps_count(filter->device))
V4L_CALL( get_caps_count, &count_params );
if (index > count)
return S_FALSE;
if (!(mt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
@ -401,7 +418,12 @@ static HRESULT WINAPI AMStreamConfig_GetStreamCaps(IAMStreamConfig *iface,
return E_OUTOFMEMORY;
}
capture_funcs->get_caps(filter->device, index, mt, format, (VIDEO_STREAM_CONFIG_CAPS *)vscc);
caps_params.device = filter->device;
caps_params.index = index;
caps_params.mt = mt;
caps_params.format = format;
caps_params.caps = (VIDEO_STREAM_CONFIG_CAPS *)vscc;
V4L_CALL( get_caps, &caps_params );
mt->cbFormat = sizeof(VIDEOINFOHEADER);
mt->pbFormat = (BYTE *)format;
*pmt = mt;
@ -441,32 +463,34 @@ static HRESULT WINAPI AMVideoProcAmp_GetRange(IAMVideoProcAmp *iface, LONG prope
LONG *min, LONG *max, LONG *step, LONG *default_value, LONG *flags)
{
struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
struct get_prop_range_params params = { filter->device, property, min, max, step, default_value, flags };
TRACE("filter %p, property %#x, min %p, max %p, step %p, default_value %p, flags %p.\n",
filter, property, min, max, step, default_value, flags);
return capture_funcs->get_prop_range(filter->device, property, min,
max, step, default_value, flags);
return V4L_CALL( get_prop_range, &params );
}
static HRESULT WINAPI AMVideoProcAmp_Set(IAMVideoProcAmp *iface, LONG property,
LONG value, LONG flags)
{
struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
struct set_prop_params params = { filter->device, property, value, flags };
TRACE("filter %p, property %#x, value %d, flags %#x.\n", filter, property, value, flags);
return capture_funcs->set_prop(filter->device, property, value, flags);
return V4L_CALL( set_prop, &params );
}
static HRESULT WINAPI AMVideoProcAmp_Get(IAMVideoProcAmp *iface, LONG property,
LONG *value, LONG *flags)
{
struct vfw_capture *filter = impl_from_IAMVideoProcAmp(iface);
struct get_prop_params params = { filter->device, property, value, flags };
TRACE("filter %p, property %#x, value %p, flags %p.\n", filter, property, value, flags);
return capture_funcs->get_prop(filter->device, property, value, flags);
return V4L_CALL( get_prop, &params );
}
static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable =
@ -519,6 +543,7 @@ static HRESULT WINAPI PPB_InitNew(IPersistPropertyBag * iface)
static HRESULT WINAPI PPB_Load(IPersistPropertyBag *iface, IPropertyBag *bag, IErrorLog *error_log)
{
struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface);
struct create_params params;
HRESULT hr;
VARIANT var;
@ -528,11 +553,12 @@ static HRESULT WINAPI PPB_Load(IPersistPropertyBag *iface, IPropertyBag *bag, IE
if (FAILED(hr = IPropertyBag_Read(bag, L"VFWIndex", &var, error_log)))
return hr;
if (!(filter->device = capture_funcs->create(V_I4(&var))))
return E_FAIL;
params.index = V_I4(&var);
params.device = &filter->device;
hr = V4L_CALL( create, &params );
filter->init = TRUE;
return S_OK;
if (SUCCEEDED(hr)) filter->init = TRUE;
return hr;
}
static HRESULT WINAPI
@ -639,20 +665,26 @@ static inline struct vfw_capture *impl_from_strmbase_pin(struct strmbase_pin *pi
static HRESULT source_query_accept(struct strmbase_pin *pin, const AM_MEDIA_TYPE *mt)
{
struct vfw_capture *filter = impl_from_strmbase_pin(pin);
return capture_funcs->check_format(filter->device, mt);
struct check_format_params params = { filter->device, mt };
return V4L_CALL( check_format, &params );
}
static HRESULT source_get_media_type(struct strmbase_pin *pin,
unsigned int index, AM_MEDIA_TYPE *mt)
{
struct vfw_capture *filter = impl_from_strmbase_pin(pin);
struct get_media_type_params params;
VIDEOINFOHEADER *format;
HRESULT hr;
if (!(format = CoTaskMemAlloc(sizeof(*format))))
return E_OUTOFMEMORY;
if ((hr = capture_funcs->get_media_type(filter->device, index, mt, format)) != S_OK)
params.device = filter->device;
params.index = index;
params.mt = mt;
params.format = format;
if ((hr = V4L_CALL( get_media_type, &params )) != S_OK)
{
CoTaskMemFree(format);
return hr;
@ -826,7 +858,8 @@ static const IAMVideoControlVtbl IAMVideoControl_VTable =
static BOOL WINAPI load_capture_funcs(INIT_ONCE *once, void *param, void **context)
{
__wine_init_unix_lib(qcap_instance, DLL_PROCESS_ATTACH, NULL, &capture_funcs);
NtQueryVirtualMemory( GetCurrentProcess(), qcap_instance, MemoryWineUnixFuncs,
&v4l_handle, sizeof(v4l_handle), NULL );
return TRUE;
}
@ -836,7 +869,7 @@ HRESULT vfw_capture_create(IUnknown *outer, IUnknown **out)
{
struct vfw_capture *object;
if (!InitOnceExecuteOnce(&init_once, load_capture_funcs, NULL, NULL) || !capture_funcs)
if (!InitOnceExecuteOnce(&init_once, load_capture_funcs, NULL, NULL) || !v4l_handle)
return E_FAIL;
if (!(object = calloc(1, sizeof(*object))))