summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitrij D. Czarkoff <czarkoff@gmail.com>2014-04-14 13:32:38 +0200
committerDmitrij D. Czarkoff <czarkoff@gmail.com>2014-04-14 13:32:38 +0200
commit65e8347a4e50d8b89073b6c9540cf23d494f7331 (patch)
tree99b75c2900fbc88a7427850532b216168c93a73c
parent907939540035984a345a754f0ff4884d07d6bf0b (diff)
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.
-rw-r--r--mk/modules.mk6
-rw-r--r--modules/v4l2/module.mk3
-rw-r--r--modules/v4l2/v4l2.c69
3 files changed, 70 insertions, 8 deletions
diff --git a/mk/modules.mk b/mk/modules.mk
index 3c96156..90c877c 100644
--- a/mk/modules.mk
+++ b/mk/modules.mk
@@ -154,9 +154,13 @@ USE_UUID := $(shell [ -f $(SYSROOT)/include/uuid/uuid.h ] && echo "yes")
USE_V4L := $(shell [ -f $(SYSROOT)/include/libv4l1.h ] || \
[ -f $(SYSROOT)/local/include/libv4l1.h ] \
&& echo "yes")
-USE_V4L2 := $(shell [ -f $(SYSROOT)/include/libv4l2.h ] || \
+HAVE_LIBV4L2 := $(shell [ -f $(SYSROOT)/include/libv4l2.h ] || \
[ -f $(SYSROOT)/local/include/libv4l2.h ] \
&& echo "yes")
+USE_V4L2 := $(shell [ -f $(SYSROOT)/include/linux/videodev2.h ] || \
+ [ -f $(SYSROOT)/local/include/linux/videodev2.h ] || \
+ [ -f $(SYSROOT)/include/sys/videoio.h ] \
+ && echo "yes")
USE_X11 := $(shell [ -f $(SYSROOT)/include/X11/Xlib.h ] || \
[ -f $(SYSROOT)/local/include/X11/Xlib.h ] || \
[ -f $(SYSROOT_ALT)/include/X11/Xlib.h ] && echo "yes")
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 <fcntl.h>
#include <unistd.h>
#undef __STRICT_ANSI__ /* needed for RHEL4 kernel 2.6.9 */
-#include <linux/videodev2.h>
#include <pthread.h>
#include <re.h>
#include <rem.h>
#include <baresip.h>
+#if defined (OPENBSD)
+#include <sys/videoio.h>
+#else
+#include <linux/videodev2.h>
+#endif
+
+#ifdef HAVE_LIBV4L2
#include <libv4l2.h>
-
+#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;