This undoes 7aa9a04f26.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qcap/v4l.c | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-)
diff --git a/dlls/qcap/v4l.c b/dlls/qcap/v4l.c index b1d7e68d426..cfae2b1d1ec 100644 --- a/dlls/qcap/v4l.c +++ b/dlls/qcap/v4l.c @@ -97,6 +97,7 @@ struct v4l_device LONG caps_count;
int image_size, image_pitch; + BYTE *image_data;
struct strmbase_source *pin; int fd, mmap; @@ -133,6 +134,7 @@ static void v4l_device_destroy(struct video_capture_device *iface) video_close(device->fd); if (device->caps_count) heap_free(device->caps); + heap_free(device->image_data); heap_free(device); }
@@ -174,13 +176,21 @@ static HRESULT v4l_device_check_format(struct video_capture_device *iface, const return E_FAIL; }
-static BOOL set_caps(struct v4l_device *device, const struct caps *caps) +static HRESULT set_caps(struct v4l_device *device, const struct caps *caps) { struct v4l2_format format = {0}; - LONG width, height; + LONG width, height, image_size; + BYTE *image_data;
width = caps->video_info.bmiHeader.biWidth; height = caps->video_info.bmiHeader.biHeight; + image_size = width * height * caps->video_info.bmiHeader.biBitCount / 8; + + if (!(image_data = heap_alloc(image_size))) + { + ERR("Failed to allocate memory.\n"); + return E_OUTOFMEMORY; + }
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; format.fmt.pix.pixelformat = caps->pixelformat; @@ -192,14 +202,16 @@ static BOOL set_caps(struct v4l_device *device, const struct caps *caps) || format.fmt.pix.height != height) { ERR("Failed to set pixel format: %s.\n", strerror(errno)); - return FALSE; + heap_free(image_data); + return VFW_E_TYPE_NOT_ACCEPTED; }
device->current_caps = caps; - device->image_size = width * height * caps->video_info.bmiHeader.biBitCount / 8; + device->image_size = image_size; device->image_pitch = width * caps->video_info.bmiHeader.biBitCount / 8; - - return TRUE; + heap_free(device->image_data); + device->image_data = image_data; + return S_OK; }
static HRESULT v4l_device_set_format(struct video_capture_device *iface, const AM_MEDIA_TYPE *mt) @@ -214,10 +226,7 @@ static HRESULT v4l_device_set_format(struct video_capture_device *iface, const A if (device->current_caps == caps) return S_OK;
- if (!set_caps(device, caps)) - return VFW_E_TYPE_NOT_ACCEPTED; - - return S_OK; + return set_caps(device, caps); }
static HRESULT v4l_device_get_format(struct video_capture_device *iface, AM_MEDIA_TYPE *mt) @@ -344,13 +353,7 @@ static DWORD WINAPI ReadThread(void *arg) struct v4l_device *device = arg; HRESULT hr; IMediaSample *pSample = NULL; - unsigned char *pTarget, *image_data; - - if (!(image_data = heap_alloc(device->image_size))) - { - ERR("Failed to allocate memory.\n"); - return 0; - } + unsigned char *pTarget;
for (;;) { @@ -379,7 +382,7 @@ static DWORD WINAPI ReadThread(void *arg)
IMediaSample_GetPointer(pSample, &pTarget);
- while (video_read(device->fd, image_data, device->image_size) == -1) + while (video_read(device->fd, device->image_data, device->image_size) == -1) { if (errno != EAGAIN) { @@ -388,7 +391,7 @@ static DWORD WINAPI ReadThread(void *arg) } }
- reverse_image(device, pTarget, image_data); + reverse_image(device, pTarget, device->image_data); hr = IMemInputPin_Receive(device->pin->pMemInputPin, pSample); IMediaSample_Release(pSample); } @@ -400,7 +403,6 @@ static DWORD WINAPI ReadThread(void *arg) } }
- heap_free(image_data); return 0; }
@@ -550,6 +552,7 @@ struct video_capture_device *v4l_device_create(struct strmbase_source *pin, USHO struct v4l_device *device; BOOL have_libv4l2; char path[20]; + HRESULT hr; int fd, i;
have_libv4l2 = video_init(); @@ -671,10 +674,9 @@ struct video_capture_device *v4l_device_create(struct strmbase_source *pin, USHO for (i = 0; i < device->caps_count; ++i) device->caps[i].media_type.pbFormat = (BYTE *)&device->caps[i].video_info;
- if (!set_caps(device, &device->caps[0])) + if (FAILED(hr = set_caps(device, &device->caps[0]))) { - ERR("Failed to set pixel format: %s\n", strerror(errno)); - if (!have_libv4l2) + if (hr == VFW_E_TYPE_NOT_ACCEPTED && !have_libv4l2) ERR_(winediag)("You may need libv4l2 to use this device.\n"); goto error; }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qcap/qcap_private.h | 10 +--- dlls/qcap/v4l.c | 121 ++++++++++++++++----------------------- dlls/qcap/vfwcapture.c | 69 +++++++++++----------- 3 files changed, 90 insertions(+), 110 deletions(-)
diff --git a/dlls/qcap/qcap_private.h b/dlls/qcap/qcap_private.h index bbbe2ef43ec..9df432f8d05 100644 --- a/dlls/qcap/qcap_private.h +++ b/dlls/qcap/qcap_private.h @@ -40,13 +40,9 @@ 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_device -{ - const struct video_capture_device_ops *ops; -}; - -struct video_capture_device_ops +struct video_capture_funcs { + struct video_capture_device *(*create)(struct strmbase_source *pin, USHORT index); void (*destroy)(struct video_capture_device *device); HRESULT (*check_format)(struct video_capture_device *device, const AM_MEDIA_TYPE *mt); HRESULT (*set_format)(struct video_capture_device *device, const AM_MEDIA_TYPE *mt); @@ -64,6 +60,6 @@ struct video_capture_device_ops void (*cleanup_stream)(struct video_capture_device *device); };
-struct video_capture_device *v4l_device_create(struct strmbase_source *pin, USHORT card); +extern const struct video_capture_funcs v4l_funcs;
#endif diff --git a/dlls/qcap/v4l.c b/dlls/qcap/v4l.c index cfae2b1d1ec..a007adce492 100644 --- a/dlls/qcap/v4l.c +++ b/dlls/qcap/v4l.c @@ -88,10 +88,8 @@ struct caps VIDEO_STREAM_CONFIG_CAPS config; };
-struct v4l_device +struct video_capture_device { - struct video_capture_device d; - const struct caps *current_caps; struct caps *caps; LONG caps_count; @@ -108,11 +106,6 @@ struct v4l_device CRITICAL_SECTION state_cs; };
-static inline struct v4l_device *v4l_device(struct video_capture_device *iface) -{ - return CONTAINING_RECORD(iface, struct v4l_device, d); -} - static int xioctl(int fd, int request, void * arg) { int r; @@ -124,10 +117,8 @@ static int xioctl(int fd, int request, void * arg) return r; }
-static void v4l_device_destroy(struct video_capture_device *iface) +static void v4l_device_destroy(struct video_capture_device *device) { - struct v4l_device *device = v4l_device(iface); - device->state_cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&device->state_cs); if (device->fd != -1) @@ -138,7 +129,7 @@ static void v4l_device_destroy(struct video_capture_device *iface) heap_free(device); }
-static const struct caps *find_caps(struct v4l_device *device, const AM_MEDIA_TYPE *mt) +static const struct caps *find_caps(struct video_capture_device *device, const AM_MEDIA_TYPE *mt) { const VIDEOINFOHEADER *video_info = (VIDEOINFOHEADER *)mt->pbFormat; LONG index; @@ -158,10 +149,8 @@ static const struct caps *find_caps(struct v4l_device *device, const AM_MEDIA_TY return NULL; }
-static HRESULT v4l_device_check_format(struct video_capture_device *iface, const AM_MEDIA_TYPE *mt) +static HRESULT v4l_device_check_format(struct video_capture_device *device, const AM_MEDIA_TYPE *mt) { - struct v4l_device *device = v4l_device(iface); - TRACE("device %p, mt %p.\n", device, mt);
if (!mt) @@ -176,7 +165,7 @@ static HRESULT v4l_device_check_format(struct video_capture_device *iface, const return E_FAIL; }
-static HRESULT set_caps(struct v4l_device *device, const struct caps *caps) +static HRESULT set_caps(struct video_capture_device *device, const struct caps *caps) { struct v4l2_format format = {0}; LONG width, height, image_size; @@ -214,9 +203,8 @@ static HRESULT set_caps(struct v4l_device *device, const struct caps *caps) return S_OK; }
-static HRESULT v4l_device_set_format(struct video_capture_device *iface, const AM_MEDIA_TYPE *mt) +static HRESULT v4l_device_set_format(struct video_capture_device *device, const AM_MEDIA_TYPE *mt) { - struct v4l_device *device = v4l_device(iface); const struct caps *caps;
caps = find_caps(device, mt); @@ -229,17 +217,14 @@ static HRESULT v4l_device_set_format(struct video_capture_device *iface, const A return set_caps(device, caps); }
-static HRESULT v4l_device_get_format(struct video_capture_device *iface, AM_MEDIA_TYPE *mt) +static HRESULT v4l_device_get_format(struct video_capture_device *device, AM_MEDIA_TYPE *mt) { - struct v4l_device *device = v4l_device(iface); - return CopyMediaType(mt, &device->current_caps->media_type); }
-static HRESULT v4l_device_get_media_type(struct video_capture_device *iface, +static HRESULT v4l_device_get_media_type(struct video_capture_device *device, unsigned int index, AM_MEDIA_TYPE *mt) { - struct v4l_device *device = v4l_device(iface); unsigned int caps_count = (device->current_caps) ? 1 : device->caps_count;
if (index >= caps_count) @@ -269,10 +254,9 @@ static __u32 v4l2_cid_from_qcap_property(VideoProcAmpProperty property) } }
-static HRESULT v4l_device_get_prop_range(struct video_capture_device *iface, VideoProcAmpProperty property, +static HRESULT v4l_device_get_prop_range(struct video_capture_device *device, VideoProcAmpProperty property, LONG *min, LONG *max, LONG *step, LONG *default_value, LONG *flags) { - struct v4l_device *device = v4l_device(iface); struct v4l2_queryctrl ctrl;
ctrl.id = v4l2_cid_from_qcap_property(property); @@ -291,10 +275,9 @@ static HRESULT v4l_device_get_prop_range(struct video_capture_device *iface, Vid return S_OK; }
-static HRESULT v4l_device_get_prop(struct video_capture_device *iface, +static HRESULT v4l_device_get_prop(struct video_capture_device *device, VideoProcAmpProperty property, LONG *value, LONG *flags) { - struct v4l_device *device = v4l_device(iface); struct v4l2_control ctrl;
ctrl.id = v4l2_cid_from_qcap_property(property); @@ -311,10 +294,9 @@ static HRESULT v4l_device_get_prop(struct video_capture_device *iface, return S_OK; }
-static HRESULT v4l_device_set_prop(struct video_capture_device *iface, +static HRESULT v4l_device_set_prop(struct video_capture_device *device, VideoProcAmpProperty property, LONG value, LONG flags) { - struct v4l_device *device = v4l_device(iface); struct v4l2_control ctrl;
ctrl.id = v4l2_cid_from_qcap_property(property); @@ -329,7 +311,7 @@ static HRESULT v4l_device_set_prop(struct video_capture_device *iface, return S_OK; }
-static void reverse_image(struct v4l_device *device, LPBYTE output, const BYTE *input) +static void reverse_image(struct video_capture_device *device, LPBYTE output, const BYTE *input) { int inoffset, outoffset, pitch;
@@ -350,7 +332,7 @@ static void reverse_image(struct v4l_device *device, LPBYTE output, const BYTE *
static DWORD WINAPI ReadThread(void *arg) { - struct v4l_device *device = arg; + struct video_capture_device *device = arg; HRESULT hr; IMediaSample *pSample = NULL; unsigned char *pTarget; @@ -406,9 +388,8 @@ static DWORD WINAPI ReadThread(void *arg) return 0; }
-static void v4l_device_init_stream(struct video_capture_device *iface) +static void v4l_device_init_stream(struct video_capture_device *device) { - struct v4l_device *device = v4l_device(iface); ALLOCATOR_PROPERTIES req_props, ret_props; HRESULT hr;
@@ -431,25 +412,22 @@ static void v4l_device_init_stream(struct video_capture_device *iface) device->thread = CreateThread(NULL, 0, ReadThread, device, 0, NULL); }
-static void v4l_device_start_stream(struct video_capture_device *iface) +static void v4l_device_start_stream(struct video_capture_device *device) { - struct v4l_device *device = v4l_device(iface); EnterCriticalSection(&device->state_cs); device->state = State_Running; LeaveCriticalSection(&device->state_cs); }
-static void v4l_device_stop_stream(struct video_capture_device *iface) +static void v4l_device_stop_stream(struct video_capture_device *device) { - struct v4l_device *device = v4l_device(iface); EnterCriticalSection(&device->state_cs); device->state = State_Paused; LeaveCriticalSection(&device->state_cs); }
-static void v4l_device_cleanup_stream(struct video_capture_device *iface) +static void v4l_device_cleanup_stream(struct video_capture_device *device) { - struct v4l_device *device = v4l_device(iface); HRESULT hr;
EnterCriticalSection(&device->state_cs); @@ -502,11 +480,9 @@ static void fill_caps(__u32 pixelformat, __u32 width, __u32 height, caps->pixelformat = pixelformat; }
-static HRESULT v4l_device_get_caps(struct video_capture_device *iface, LONG index, +static HRESULT v4l_device_get_caps(struct video_capture_device *device, LONG index, AM_MEDIA_TYPE **type, VIDEO_STREAM_CONFIG_CAPS *vscc) { - struct v4l_device *device = v4l_device(iface); - if (index >= device->caps_count) return S_FALSE;
@@ -519,37 +495,17 @@ static HRESULT v4l_device_get_caps(struct video_capture_device *iface, LONG inde return S_OK; }
-static LONG v4l_device_get_caps_count(struct video_capture_device *iface) +static LONG v4l_device_get_caps_count(struct video_capture_device *device) { - struct v4l_device *device = v4l_device(iface); - return device->caps_count; }
-static const struct video_capture_device_ops v4l_device_ops = -{ - .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, - .init_stream = v4l_device_init_stream, - .start_stream = v4l_device_start_stream, - .stop_stream = v4l_device_stop_stream, - .cleanup_stream = v4l_device_cleanup_stream, -}; - -struct video_capture_device *v4l_device_create(struct strmbase_source *pin, USHORT card) +struct video_capture_device *v4l_device_create(struct strmbase_source *pin, USHORT index) { struct v4l2_frmsizeenum frmsize = {0}; + struct video_capture_device *device; struct v4l2_capability caps = {{0}}; struct v4l2_format format = {0}; - struct v4l_device *device; BOOL have_libv4l2; char path[20]; HRESULT hr; @@ -560,7 +516,7 @@ struct video_capture_device *v4l_device_create(struct strmbase_source *pin, USHO if (!(device = heap_alloc_zero(sizeof(*device)))) return NULL;
- sprintf(path, "/dev/video%i", card); + sprintf(path, "/dev/video%i", index); TRACE("Opening device %s.\n", path); #ifdef O_CLOEXEC if ((fd = video_open(path, O_RDWR | O_NONBLOCK | O_CLOEXEC)) == -1 && errno == EINVAL) @@ -681,30 +637,53 @@ struct video_capture_device *v4l_device_create(struct strmbase_source *pin, USHO goto error; }
- device->d.ops = &v4l_device_ops; device->pin = pin; device->state = State_Stopped; InitializeConditionVariable(&device->state_cv); InitializeCriticalSection(&device->state_cs); - device->state_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": v4l_device.state_cs"); + device->state_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": video_capture_device.state_cs");
TRACE("Format: %d bpp - %dx%d.\n", device->current_caps->video_info.bmiHeader.biBitCount, device->current_caps->video_info.bmiHeader.biWidth, device->current_caps->video_info.bmiHeader.biHeight);
- return &device->d; + return device;
error: - v4l_device_destroy(&device->d); + v4l_device_destroy(device); return NULL; }
+const struct video_capture_funcs v4l_funcs = +{ + .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, + .init_stream = v4l_device_init_stream, + .start_stream = v4l_device_start_stream, + .stop_stream = v4l_device_stop_stream, + .cleanup_stream = v4l_device_cleanup_stream, +}; + #else
-struct video_capture_device *v4l_device_create(struct strmbase_source *pin, USHORT card) +static struct video_capture_device *v4l_device_create(struct strmbase_source *pin, USHORT index) { ERR("v4l2 was not present at compilation time.\n"); return NULL; }
+const struct video_capture_funcs v4l_funcs = +{ + .create = v4l_device_create, +}; + #endif /* defined(VIDIOCMCAPTURE) */ diff --git a/dlls/qcap/vfwcapture.c b/dlls/qcap/vfwcapture.c index a79cce50380..9ff96f13f91 100644 --- a/dlls/qcap/vfwcapture.c +++ b/dlls/qcap/vfwcapture.c @@ -22,6 +22,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+static const struct video_capture_funcs *capture_funcs; + struct vfw_capture { struct strmbase_filter filter; @@ -85,8 +87,8 @@ static void vfw_capture_destroy(struct strmbase_filter *iface) if (filter->init) { if (filter->filter.state != State_Stopped) - filter->device->ops->cleanup_stream(filter->device); - filter->device->ops->destroy(filter->device); + capture_funcs->cleanup_stream(filter->device); + capture_funcs->destroy(filter->device); }
if (filter->source.pin.peer) @@ -123,7 +125,7 @@ static HRESULT vfw_capture_init_stream(struct strmbase_filter *iface) { struct vfw_capture *filter = impl_from_strmbase_filter(iface);
- filter->device->ops->init_stream(filter->device); + capture_funcs->init_stream(filter->device); return S_OK; }
@@ -131,7 +133,7 @@ static HRESULT vfw_capture_start_stream(struct strmbase_filter *iface, REFERENCE { struct vfw_capture *filter = impl_from_strmbase_filter(iface);
- filter->device->ops->start_stream(filter->device); + capture_funcs->start_stream(filter->device); return S_OK; }
@@ -139,7 +141,7 @@ static HRESULT vfw_capture_stop_stream(struct strmbase_filter *iface) { struct vfw_capture *filter = impl_from_strmbase_filter(iface);
- filter->device->ops->stop_stream(filter->device); + capture_funcs->stop_stream(filter->device); return S_OK; }
@@ -147,7 +149,7 @@ static HRESULT vfw_capture_cleanup_stream(struct strmbase_filter *iface) { struct vfw_capture *filter = impl_from_strmbase_filter(iface);
- filter->device->ops->cleanup_stream(filter->device); + capture_funcs->cleanup_stream(filter->device); return S_OK; }
@@ -218,7 +220,7 @@ AMStreamConfig_SetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE *pmt) return VFW_E_INVALIDMEDIATYPE; }
- hr = This->device->ops->set_format(This->device, pmt); + hr = capture_funcs->set_format(This->device, pmt); if (SUCCEEDED(hr) && This->filter.graph && This->source.pin.peer) { hr = IFilterGraph_Reconnect(This->filter.graph, &This->source.pin.IPin_iface); @@ -239,7 +241,7 @@ static HRESULT WINAPI AMStreamConfig_GetFormat(IAMStreamConfig *iface, AM_MEDIA_ if (!(*mt = CoTaskMemAlloc(sizeof(**mt)))) return E_OUTOFMEMORY;
- if (SUCCEEDED(hr = filter->device->ops->get_format(filter->device, *mt))) + if (SUCCEEDED(hr = capture_funcs->get_format(filter->device, *mt))) strmbase_dump_media_type(*mt); return hr; } @@ -254,7 +256,7 @@ static HRESULT WINAPI AMStreamConfig_GetNumberOfCapabilities(IAMStreamConfig *if if (!count || !size) return E_POINTER;
- *count = filter->device->ops->get_caps_count(filter->device); + *count = capture_funcs->get_caps_count(filter->device); *size = sizeof(VIDEO_STREAM_CONFIG_CAPS);
return S_OK; @@ -267,7 +269,7 @@ static HRESULT WINAPI AMStreamConfig_GetStreamCaps(IAMStreamConfig *iface,
TRACE("filter %p, index %d, pmt %p, vscc %p.\n", filter, index, pmt, vscc);
- return filter->device->ops->get_caps(filter->device, index, pmt, (VIDEO_STREAM_CONFIG_CAPS *)vscc); + return capture_funcs->get_caps(filter->device, index, pmt, (VIDEO_STREAM_CONFIG_CAPS *)vscc); }
static const IAMStreamConfigVtbl IAMStreamConfig_VTable = @@ -307,7 +309,7 @@ static HRESULT WINAPI AMVideoProcAmp_GetRange(IAMVideoProcAmp *iface, LONG prope 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 filter->device->ops->get_prop_range(filter->device, property, min, + return capture_funcs->get_prop_range(filter->device, property, min, max, step, default_value, flags); }
@@ -318,7 +320,7 @@ static HRESULT WINAPI AMVideoProcAmp_Set(IAMVideoProcAmp *iface, LONG property,
TRACE("filter %p, property %#x, value %d, flags %#x.\n", filter, property, value, flags);
- return filter->device->ops->set_prop(filter->device, property, value, flags); + return capture_funcs->set_prop(filter->device, property, value, flags); }
static HRESULT WINAPI AMVideoProcAmp_Get(IAMVideoProcAmp *iface, LONG property, @@ -328,7 +330,7 @@ static HRESULT WINAPI AMVideoProcAmp_Get(IAMVideoProcAmp *iface, LONG property,
TRACE("filter %p, property %#x, value %p, flags %p.\n", filter, property, value, flags);
- return filter->device->ops->get_prop(filter->device, property, value, flags); + return capture_funcs->get_prop(filter->device, property, value, flags); }
static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable = @@ -378,32 +380,24 @@ static HRESULT WINAPI PPB_InitNew(IPersistPropertyBag * iface) return E_NOTIMPL; }
-static HRESULT WINAPI -PPB_Load( IPersistPropertyBag * iface, IPropertyBag *pPropBag, - IErrorLog *pErrorLog ) +static HRESULT WINAPI PPB_Load(IPersistPropertyBag *iface, IPropertyBag *bag, IErrorLog *error_log) { static const OLECHAR VFWIndex[] = {'V','F','W','I','n','d','e','x',0}; - struct vfw_capture *This = impl_from_IPersistPropertyBag(iface); + struct vfw_capture *filter = impl_from_IPersistPropertyBag(iface); HRESULT hr; VARIANT var;
- TRACE("%p/%p-> (%p, %p)\n", iface, This, pPropBag, pErrorLog); + TRACE("filter %p, bag %p, error_log %p.\n", filter, bag, error_log);
V_VT(&var) = VT_I4; - hr = IPropertyBag_Read(pPropBag, VFWIndex, &var, pErrorLog); + if (FAILED(hr = IPropertyBag_Read(bag, VFWIndex, &var, error_log))) + return hr;
- if (SUCCEEDED(hr)) - { - if ((This->device = v4l_device_create(&This->source, V_I4(&var)))) - { - This->init = TRUE; - hr = S_OK; - } - else - hr = E_FAIL; - } + if (!(filter->device = capture_funcs->create(&filter->source, V_I4(&var)))) + return E_FAIL;
- return hr; + filter->init = TRUE; + return S_OK; }
static HRESULT WINAPI @@ -510,14 +504,14 @@ 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 filter->device->ops->check_format(filter->device, mt); + return capture_funcs->check_format(filter->device, mt); }
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); - return filter->device->ops->get_media_type(filter->device, index, mt); + return capture_funcs->get_media_type(filter->device, index, mt); }
static HRESULT source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) @@ -683,11 +677,22 @@ static const IAMVideoControlVtbl IAMVideoControl_VTable = video_control_GetFrameRateList };
+static BOOL WINAPI load_capture_funcs(INIT_ONCE *once, void *param, void **context) +{ + capture_funcs = &v4l_funcs; + return TRUE; +} + +static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + HRESULT vfw_capture_create(IUnknown *outer, IUnknown **out) { static const WCHAR source_name[] = {'O','u','t','p','u','t',0}; struct vfw_capture *object;
+ if (!InitOnceExecuteOnce(&init_once, load_capture_funcs, NULL, NULL)) + return E_FAIL; + if (!(object = CoTaskMemAlloc(sizeof(*object)))) return E_OUTOFMEMORY;
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qcap/qcap_private.h | 3 +- dlls/qcap/v4l.c | 96 ++++----------------------------------- dlls/qcap/vfwcapture.c | 98 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 103 insertions(+), 94 deletions(-)
diff --git a/dlls/qcap/qcap_private.h b/dlls/qcap/qcap_private.h index 9df432f8d05..d715219c645 100644 --- a/dlls/qcap/qcap_private.h +++ b/dlls/qcap/qcap_private.h @@ -54,9 +54,8 @@ struct video_capture_funcs LONG *min, LONG *max, LONG *step, LONG *default_value, LONG *flags); HRESULT (*get_prop)(struct video_capture_device *device, VideoProcAmpProperty property, LONG *value, LONG *flags); HRESULT (*set_prop)(struct video_capture_device *device, VideoProcAmpProperty property, LONG value, LONG flags); + BOOL (*read_frame)(struct video_capture_device *device, BYTE *data); void (*init_stream)(struct video_capture_device *device); - void (*start_stream)(struct video_capture_device *device); - void (*stop_stream)(struct video_capture_device *device); void (*cleanup_stream)(struct video_capture_device *device); };
diff --git a/dlls/qcap/v4l.c b/dlls/qcap/v4l.c index a007adce492..e0095379b34 100644 --- a/dlls/qcap/v4l.c +++ b/dlls/qcap/v4l.c @@ -99,11 +99,6 @@ struct video_capture_device
struct strmbase_source *pin; int fd, mmap; - - HANDLE thread; - FILTER_STATE state; - CONDITION_VARIABLE state_cv; - CRITICAL_SECTION state_cs; };
static int xioctl(int fd, int request, void * arg) @@ -119,8 +114,6 @@ static int xioctl(int fd, int request, void * arg)
static void v4l_device_destroy(struct video_capture_device *device) { - device->state_cs.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&device->state_cs); if (device->fd != -1) video_close(device->fd); if (device->caps_count) @@ -330,62 +323,19 @@ static void reverse_image(struct video_capture_device *device, LPBYTE output, co } }
-static DWORD WINAPI ReadThread(void *arg) +static BOOL v4l_device_read_frame(struct video_capture_device *device, BYTE *data) { - struct video_capture_device *device = arg; - HRESULT hr; - IMediaSample *pSample = NULL; - unsigned char *pTarget; - - for (;;) + while (video_read(device->fd, device->image_data, device->image_size) < 0) { - EnterCriticalSection(&device->state_cs); - - while (device->state == State_Paused) - SleepConditionVariableCS(&device->state_cv, &device->state_cs, INFINITE); - - if (device->state == State_Stopped) + if (errno != EAGAIN) { - LeaveCriticalSection(&device->state_cs); - break; - } - - LeaveCriticalSection(&device->state_cs); - - hr = BaseOutputPinImpl_GetDeliveryBuffer(device->pin, &pSample, NULL, NULL, 0); - if (SUCCEEDED(hr)) - { - int len; - - IMediaSample_SetActualDataLength(pSample, device->image_size); - - len = IMediaSample_GetActualDataLength(pSample); - TRACE("Data length: %d KB\n", len / 1024); - - IMediaSample_GetPointer(pSample, &pTarget); - - while (video_read(device->fd, device->image_data, device->image_size) == -1) - { - if (errno != EAGAIN) - { - ERR("Failed to read frame: %s\n", strerror(errno)); - break; - } - } - - reverse_image(device, pTarget, device->image_data); - hr = IMemInputPin_Receive(device->pin->pMemInputPin, pSample); - IMediaSample_Release(pSample); - } - - if (FAILED(hr) && hr != VFW_E_NOT_CONNECTED) - { - TRACE("Return %x, stop IFilterGraph\n", hr); - break; + ERR("Failed to read frame: %s\n", strerror(errno)); + return FALSE; } }
- return 0; + reverse_image(device, data, device->image_data); + return TRUE; }
static void v4l_device_init_stream(struct video_capture_device *device) @@ -407,37 +357,12 @@ static void v4l_device_init_stream(struct video_capture_device *device) if (FAILED(hr = IMemAllocator_Commit(device->pin->pAllocator))) ERR("Failed to commit allocator, hr %#x.\n", hr); } - - device->state = State_Paused; - device->thread = CreateThread(NULL, 0, ReadThread, device, 0, NULL); -} - -static void v4l_device_start_stream(struct video_capture_device *device) -{ - EnterCriticalSection(&device->state_cs); - device->state = State_Running; - LeaveCriticalSection(&device->state_cs); -} - -static void v4l_device_stop_stream(struct video_capture_device *device) -{ - EnterCriticalSection(&device->state_cs); - device->state = State_Paused; - LeaveCriticalSection(&device->state_cs); }
static void v4l_device_cleanup_stream(struct video_capture_device *device) { HRESULT hr;
- EnterCriticalSection(&device->state_cs); - device->state = State_Stopped; - LeaveCriticalSection(&device->state_cs); - WakeConditionVariable(&device->state_cv); - WaitForSingleObject(device->thread, INFINITE); - CloseHandle(device->thread); - device->thread = NULL; - hr = IMemAllocator_Decommit(device->pin->pAllocator); if (hr != S_OK && hr != VFW_E_NOT_COMMITTED) ERR("Failed to decommit allocator, hr %#x.\n", hr); @@ -638,10 +563,6 @@ struct video_capture_device *v4l_device_create(struct strmbase_source *pin, USHO }
device->pin = pin; - device->state = State_Stopped; - InitializeConditionVariable(&device->state_cv); - InitializeCriticalSection(&device->state_cs); - device->state_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": video_capture_device.state_cs");
TRACE("Format: %d bpp - %dx%d.\n", device->current_caps->video_info.bmiHeader.biBitCount, device->current_caps->video_info.bmiHeader.biWidth, @@ -667,9 +588,8 @@ const struct video_capture_funcs v4l_funcs = .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, .init_stream = v4l_device_init_stream, - .start_stream = v4l_device_start_stream, - .stop_stream = v4l_device_stop_stream, .cleanup_stream = v4l_device_cleanup_stream, };
diff --git a/dlls/qcap/vfwcapture.c b/dlls/qcap/vfwcapture.c index 9ff96f13f91..9fb694ba678 100644 --- a/dlls/qcap/vfwcapture.c +++ b/dlls/qcap/vfwcapture.c @@ -34,10 +34,19 @@ struct vfw_capture IPersistPropertyBag IPersistPropertyBag_iface; BOOL init;
- struct video_capture_device *device; - struct strmbase_source source; IKsPropertySet IKsPropertySet_iface; + + struct video_capture_device *device; + + /* FIXME: It would be nice to avoid duplicating this variable with strmbase. + * However, synchronization is tricky; we need access to be protected by a + * separate lock. */ + FILTER_STATE state; + CONDITION_VARIABLE state_cv; + CRITICAL_SECTION state_cs; + + HANDLE thread; };
static inline struct vfw_capture *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -96,6 +105,8 @@ static void vfw_capture_destroy(struct strmbase_filter *iface) IPin_Disconnect(filter->source.pin.peer); IPin_Disconnect(&filter->source.pin.IPin_iface); } + filter->state_cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&filter->state_cs); strmbase_source_cleanup(&filter->source); strmbase_filter_cleanup(&filter->filter); CoTaskMemFree(filter); @@ -121,11 +132,71 @@ static HRESULT vfw_capture_query_interface(struct strmbase_filter *iface, REFIID return S_OK; }
+static DWORD WINAPI stream_thread(void *arg) +{ + struct vfw_capture *filter = arg; + const VIDEOINFOHEADER *format = (const VIDEOINFOHEADER *)filter->source.pin.mt.pbFormat; + const unsigned int image_size = format->bmiHeader.biWidth + * format->bmiHeader.biHeight * format->bmiHeader.biBitCount / 8; + + for (;;) + { + IMediaSample *sample; + HRESULT hr; + BYTE *data; + + EnterCriticalSection(&filter->state_cs); + + while (filter->state == State_Paused) + SleepConditionVariableCS(&filter->state_cv, &filter->state_cs, INFINITE); + + if (filter->state == State_Stopped) + { + LeaveCriticalSection(&filter->state_cs); + break; + } + + LeaveCriticalSection(&filter->state_cs); + + if (FAILED(hr = BaseOutputPinImpl_GetDeliveryBuffer(&filter->source, &sample, NULL, NULL, 0))) + { + ERR("Failed to get sample, hr %#x.\n", hr); + break; + } + + IMediaSample_SetActualDataLength(sample, image_size); + IMediaSample_GetPointer(sample, &data); + + if (!capture_funcs->read_frame(filter->device, data)) + { + IMediaSample_Release(sample); + break; + } + + hr = IMemInputPin_Receive(filter->source.pMemInputPin, sample); + IMediaSample_Release(sample); + if (FAILED(hr)) + { + ERR("IMemInputPin::Receive() returned %#x.\n", hr); + break; + } + } + + return 0; +} + static HRESULT vfw_capture_init_stream(struct strmbase_filter *iface) { struct vfw_capture *filter = impl_from_strmbase_filter(iface);
capture_funcs->init_stream(filter->device); + + EnterCriticalSection(&filter->state_cs); + filter->state = State_Paused; + LeaveCriticalSection(&filter->state_cs); + + filter->thread = CreateThread(NULL, 0, stream_thread, filter, 0, NULL); + return S_OK; }
@@ -133,7 +204,10 @@ static HRESULT vfw_capture_start_stream(struct strmbase_filter *iface, REFERENCE { struct vfw_capture *filter = impl_from_strmbase_filter(iface);
- capture_funcs->start_stream(filter->device); + EnterCriticalSection(&filter->state_cs); + filter->state = State_Running; + LeaveCriticalSection(&filter->state_cs); + WakeConditionVariable(&filter->state_cv); return S_OK; }
@@ -141,7 +215,9 @@ static HRESULT vfw_capture_stop_stream(struct strmbase_filter *iface) { struct vfw_capture *filter = impl_from_strmbase_filter(iface);
- capture_funcs->stop_stream(filter->device); + EnterCriticalSection(&filter->state_cs); + filter->state = State_Paused; + LeaveCriticalSection(&filter->state_cs); return S_OK; }
@@ -149,6 +225,15 @@ static HRESULT vfw_capture_cleanup_stream(struct strmbase_filter *iface) { struct vfw_capture *filter = impl_from_strmbase_filter(iface);
+ EnterCriticalSection(&filter->state_cs); + filter->state = State_Stopped; + LeaveCriticalSection(&filter->state_cs); + WakeConditionVariable(&filter->state_cv); + + WaitForSingleObject(filter->thread, INFINITE); + CloseHandle(filter->thread); + filter->thread = NULL; + capture_funcs->cleanup_stream(filter->device); return S_OK; } @@ -709,6 +794,11 @@ HRESULT vfw_capture_create(IUnknown *outer, IUnknown **out)
object->IKsPropertySet_iface.lpVtbl = &IKsPropertySet_VTable;
+ object->state = State_Stopped; + InitializeConditionVariable(&object->state_cv); + InitializeCriticalSection(&object->state_cs); + object->state_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": vfw_capture.state_cs"); + TRACE("Created VFW capture filter %p.\n", object); ObjectRefCount(TRUE); *out = &object->filter.IUnknown_inner;
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qcap/qcap_private.h | 4 +--- dlls/qcap/v4l.c | 40 ++-------------------------------------- dlls/qcap/vfwcapture.c | 38 ++++++++++++++++++++++++++++---------- 3 files changed, 31 insertions(+), 51 deletions(-)
diff --git a/dlls/qcap/qcap_private.h b/dlls/qcap/qcap_private.h index d715219c645..1d2b49d7394 100644 --- a/dlls/qcap/qcap_private.h +++ b/dlls/qcap/qcap_private.h @@ -42,7 +42,7 @@ HRESULT vfw_capture_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
struct video_capture_funcs { - struct video_capture_device *(*create)(struct strmbase_source *pin, USHORT index); + struct video_capture_device *(*create)(USHORT index); void (*destroy)(struct video_capture_device *device); HRESULT (*check_format)(struct video_capture_device *device, const AM_MEDIA_TYPE *mt); HRESULT (*set_format)(struct video_capture_device *device, const AM_MEDIA_TYPE *mt); @@ -55,8 +55,6 @@ struct video_capture_funcs HRESULT (*get_prop)(struct video_capture_device *device, VideoProcAmpProperty property, LONG *value, LONG *flags); HRESULT (*set_prop)(struct video_capture_device *device, VideoProcAmpProperty property, LONG value, LONG flags); BOOL (*read_frame)(struct video_capture_device *device, BYTE *data); - void (*init_stream)(struct video_capture_device *device); - void (*cleanup_stream)(struct video_capture_device *device); };
extern const struct video_capture_funcs v4l_funcs; diff --git a/dlls/qcap/v4l.c b/dlls/qcap/v4l.c index e0095379b34..d525989172a 100644 --- a/dlls/qcap/v4l.c +++ b/dlls/qcap/v4l.c @@ -97,7 +97,6 @@ struct video_capture_device int image_size, image_pitch; BYTE *image_data;
- struct strmbase_source *pin; int fd, mmap; };
@@ -338,37 +337,6 @@ static BOOL v4l_device_read_frame(struct video_capture_device *device, BYTE *dat return TRUE; }
-static void v4l_device_init_stream(struct video_capture_device *device) -{ - ALLOCATOR_PROPERTIES req_props, ret_props; - HRESULT hr; - - req_props.cBuffers = 3; - req_props.cbBuffer = device->image_size; - req_props.cbAlign = 1; - req_props.cbPrefix = 0; - - hr = IMemAllocator_SetProperties(device->pin->pAllocator, &req_props, &ret_props); - if (FAILED(hr)) - ERR("Failed to set allocator properties (buffer size %u), hr %#x.\n", req_props.cbBuffer, hr); - - if (SUCCEEDED(hr)) - { - if (FAILED(hr = IMemAllocator_Commit(device->pin->pAllocator))) - ERR("Failed to commit allocator, hr %#x.\n", hr); - } -} - -static void v4l_device_cleanup_stream(struct video_capture_device *device) -{ - HRESULT hr; - - hr = IMemAllocator_Decommit(device->pin->pAllocator); - if (hr != S_OK && hr != VFW_E_NOT_COMMITTED) - ERR("Failed to decommit allocator, hr %#x.\n", hr); -} - - static void fill_caps(__u32 pixelformat, __u32 width, __u32 height, __u32 max_fps, __u32 min_fps, struct caps *caps) { @@ -425,7 +393,7 @@ static LONG v4l_device_get_caps_count(struct video_capture_device *device) return device->caps_count; }
-struct video_capture_device *v4l_device_create(struct strmbase_source *pin, USHORT index) +struct video_capture_device *v4l_device_create(USHORT index) { struct v4l2_frmsizeenum frmsize = {0}; struct video_capture_device *device; @@ -562,8 +530,6 @@ struct video_capture_device *v4l_device_create(struct strmbase_source *pin, USHO goto error; }
- device->pin = pin; - TRACE("Format: %d bpp - %dx%d.\n", device->current_caps->video_info.bmiHeader.biBitCount, device->current_caps->video_info.bmiHeader.biWidth, device->current_caps->video_info.bmiHeader.biHeight); @@ -589,13 +555,11 @@ const struct video_capture_funcs v4l_funcs = .get_prop = v4l_device_get_prop, .set_prop = v4l_device_set_prop, .read_frame = v4l_device_read_frame, - .init_stream = v4l_device_init_stream, - .cleanup_stream = v4l_device_cleanup_stream, };
#else
-static struct video_capture_device *v4l_device_create(struct strmbase_source *pin, USHORT index) +static struct video_capture_device *v4l_device_create(USHORT index) { ERR("v4l2 was not present at compilation time.\n"); return NULL; diff --git a/dlls/qcap/vfwcapture.c b/dlls/qcap/vfwcapture.c index 9fb694ba678..f0a985d5f4b 100644 --- a/dlls/qcap/vfwcapture.c +++ b/dlls/qcap/vfwcapture.c @@ -94,11 +94,7 @@ static void vfw_capture_destroy(struct strmbase_filter *iface) struct vfw_capture *filter = impl_from_strmbase_filter(iface);
if (filter->init) - { - if (filter->filter.state != State_Stopped) - capture_funcs->cleanup_stream(filter->device); capture_funcs->destroy(filter->device); - }
if (filter->source.pin.peer) { @@ -132,12 +128,17 @@ static HRESULT vfw_capture_query_interface(struct strmbase_filter *iface, REFIID return S_OK; }
+static unsigned int get_image_size(struct vfw_capture *filter) +{ + const VIDEOINFOHEADER *format = (const VIDEOINFOHEADER *)filter->source.pin.mt.pbFormat; + + return format->bmiHeader.biWidth * format->bmiHeader.biHeight * format->bmiHeader.biBitCount / 8; +} + static DWORD WINAPI stream_thread(void *arg) { struct vfw_capture *filter = arg; - const VIDEOINFOHEADER *format = (const VIDEOINFOHEADER *)filter->source.pin.mt.pbFormat; - const unsigned int image_size = format->bmiHeader.biWidth - * format->bmiHeader.biHeight * format->bmiHeader.biBitCount / 8; + const unsigned int image_size = get_image_size(filter);
for (;;) { @@ -188,8 +189,21 @@ static DWORD WINAPI stream_thread(void *arg) static HRESULT vfw_capture_init_stream(struct strmbase_filter *iface) { struct vfw_capture *filter = impl_from_strmbase_filter(iface); + ALLOCATOR_PROPERTIES req_props, ret_props; + HRESULT hr;
- capture_funcs->init_stream(filter->device); + req_props.cBuffers = 3; + req_props.cbBuffer = get_image_size(filter); + req_props.cbAlign = 1; + req_props.cbPrefix = 0; + if (FAILED(hr = IMemAllocator_SetProperties(filter->source.pAllocator, &req_props, &ret_props))) + { + ERR("Failed to set allocator properties (buffer size %u), hr %#x.\n", req_props.cbBuffer, hr); + return hr; + } + + if (FAILED(hr = IMemAllocator_Commit(filter->source.pAllocator))) + ERR("Failed to commit allocator, hr %#x.\n", hr);
EnterCriticalSection(&filter->state_cs); filter->state = State_Paused; @@ -224,6 +238,7 @@ static HRESULT vfw_capture_stop_stream(struct strmbase_filter *iface) static HRESULT vfw_capture_cleanup_stream(struct strmbase_filter *iface) { struct vfw_capture *filter = impl_from_strmbase_filter(iface); + HRESULT hr;
EnterCriticalSection(&filter->state_cs); filter->state = State_Stopped; @@ -234,7 +249,10 @@ static HRESULT vfw_capture_cleanup_stream(struct strmbase_filter *iface) CloseHandle(filter->thread); filter->thread = NULL;
- capture_funcs->cleanup_stream(filter->device); + hr = IMemAllocator_Decommit(filter->source.pAllocator); + if (hr != S_OK && hr != VFW_E_NOT_COMMITTED) + ERR("Failed to decommit allocator, hr %#x.\n", hr); + return S_OK; }
@@ -478,7 +496,7 @@ static HRESULT WINAPI PPB_Load(IPersistPropertyBag *iface, IPropertyBag *bag, IE if (FAILED(hr = IPropertyBag_Read(bag, VFWIndex, &var, error_log))) return hr;
- if (!(filter->device = capture_funcs->create(&filter->source, V_I4(&var)))) + if (!(filter->device = capture_funcs->create(V_I4(&var)))) return E_FAIL;
filter->init = TRUE;