From 65e8347a4e50d8b89073b6c9540cf23d494f7331 Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Mon, 14 Apr 2014 13:32:38 +0200 Subject: v4l2: add format negotiation and OpenBSD support Changes are: * libv4l2 is not required for proper operation any more (it is still desirable, as it guarantees that librem-supported format will be available); * v4l2 module now iterates through the list of available formats and settles on first one supported by librem; * if libv4l2 is present, baresip will try to use native format and fall back to emulated one only if no usable combination found. --- modules/v4l2/module.mk | 3 +++ modules/v4l2/v4l2.c | 69 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 65 insertions(+), 7 deletions(-) (limited to 'modules/v4l2') diff --git a/modules/v4l2/module.mk b/modules/v4l2/module.mk index 61360cb..6c24eb6 100644 --- a/modules/v4l2/module.mk +++ b/modules/v4l2/module.mk @@ -6,6 +6,9 @@ MOD := v4l2 $(MOD)_SRCS += v4l2.c +ifeq ($(HAVE_LIBV4L2),yes) $(MOD)_LFLAGS += -lv4l2 +CFLAGS += -DHAVE_LIBV4L2 +endif include mk/mod.mk diff --git a/modules/v4l2/v4l2.c b/modules/v4l2/v4l2.c index 2b60908..424bf3c 100644 --- a/modules/v4l2/v4l2.c +++ b/modules/v4l2/v4l2.c @@ -14,13 +14,27 @@ #include #include #undef __STRICT_ANSI__ /* needed for RHEL4 kernel 2.6.9 */ -#include #include #include #include #include +#if defined (OPENBSD) +#include +#else +#include +#endif + +#ifdef HAVE_LIBV4L2 #include - +#else +#define v4l2_open open +#define v4l2_read read +#define v4l2_ioctl ioctl +#define v4l2_mmap mmap +#define v4l2_munmap munmap +#define v4l2_close close +#endif + enum io_method { IO_METHOD_READ = 0, @@ -39,6 +53,7 @@ struct vidsrc_st { pthread_t thread; bool run; struct vidsz sz, app_sz; + u_int32_t pixfmt; struct mbuf *mb; vidsrc_frame_h *frameh; void *arg; @@ -47,20 +62,35 @@ struct vidsrc_st { unsigned int n_buffers; }; - static struct vidsrc *vidsrc; +static enum vidfmt match_fmt(u_int32_t fmt) +{ + switch (fmt) { + case V4L2_PIX_FMT_YUV420: return VID_FMT_YUV420P; + case V4L2_PIX_FMT_YUYV: return VID_FMT_YUYV422; + case V4L2_PIX_FMT_UYVY: return VID_FMT_UYVY422; + case V4L2_PIX_FMT_RGB32: return VID_FMT_RGB32; + case V4L2_PIX_FMT_RGB565: return VID_FMT_RGB565; + case V4L2_PIX_FMT_RGB555: return VID_FMT_RGB555; + default: return VID_FMT_N; + } +} + + static void get_video_input(struct vidsrc_st *st) { struct v4l2_input input; memset(&input, 0, sizeof(input)); +#ifndef OPENBSD if (-1 == v4l2_ioctl(st->fd, VIDIOC_G_INPUT, &input.index)) { warning("v4l2: VIDIOC_G_INPUT: %m\n", errno); return; } +#endif if (-1 == v4l2_ioctl(st->fd, VIDIOC_ENUMINPUT, &input)) { warning("v4l2: VIDIOC_ENUMINPUT: %m\n", errno); @@ -165,10 +195,12 @@ static int v4l2_init_device(struct vidsrc_st *st, const char *dev_name) { struct v4l2_capability cap; struct v4l2_format fmt; + struct v4l2_fmtdesc fmts; unsigned int min; const char *pix; int err; + if (-1 == xioctl(st->fd, VIDIOC_QUERYCAP, &cap)) { if (EINVAL == errno) { warning("v4l2: %s is no V4L2 device\n", dev_name); @@ -203,6 +235,27 @@ static int v4l2_init_device(struct vidsrc_st *st, const char *dev_name) break; } + /* Negotiate video format */ + memset(&fmts, 0, sizeof(fmts)); + + fmts.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + for (fmts.index=0; !v4l2_ioctl(st->fd, VIDIOC_ENUM_FMT, &fmts); + fmts.index++) { + if (match_fmt(fmts.pixelformat) != VID_FMT_N) { + st->pixfmt = fmts.pixelformat; +#ifdef HAVE_LIBV4L2 + /* Prefer native formats */ + if (fmts.flags ^ V4L2_FMT_FLAG_EMULATED) +#endif + break; + } + } + + if (!st->pixfmt) { + warning("v4l2: format negotiation failed: %m\n", errno); + return errno; + } + /* Select video input, video standard and tune here. */ memset(&fmt, 0, sizeof(fmt)); @@ -210,7 +263,7 @@ static int v4l2_init_device(struct vidsrc_st *st, const char *dev_name) fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = st->app_sz.w; fmt.fmt.pix.height = st->app_sz.h; - fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; + fmt.fmt.pix.pixelformat = st->pixfmt; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; if (-1 == xioctl(st->fd, VIDIOC_S_FMT, &fmt)) { @@ -257,8 +310,8 @@ static int v4l2_init_device(struct vidsrc_st *st, const char *dev_name) pix = (char *)&fmt.fmt.pix.pixelformat; - if (V4L2_PIX_FMT_YUV420 != fmt.fmt.pix.pixelformat) { - warning("v4l2: %s: expected YUV420 got %c%c%c%c\n", dev_name, + if (st->pixfmt != fmt.fmt.pix.pixelformat) { + warning("v4l2: %s: unexpectedly got %c%c%c%c\n", dev_name, pix[0], pix[1], pix[2], pix[3]); return ENODEV; } @@ -357,7 +410,7 @@ static void call_frame_handler(struct vidsrc_st *st, uint8_t *buf) { struct vidframe frame; - vidframe_init_buf(&frame, VID_FMT_YUV420P, &st->sz, buf); + vidframe_init_buf(&frame, match_fmt(st->pixfmt), &st->sz, buf); st->frameh(&frame, st->arg); } @@ -516,6 +569,8 @@ static int alloc(struct vidsrc_st **stp, struct vidsrc *vs, st->frameh = frameh; st->arg = arg; + st->pixfmt = 0; + err = vd_open(st, dev); if (err) goto out; -- cgit v1.2.3