diff options
author | Alfred E. Heggestad <aeh@db.org> | 2014-02-09 11:50:07 +0100 |
---|---|---|
committer | Alfred E. Heggestad <aeh@db.org> | 2014-02-09 11:50:07 +0100 |
commit | 98bf08bdcf2edd9d397f32650a8bfe62186fbecf (patch) | |
tree | ebc6ec71f44bff8c42e4eefced61948623df02fc /modules/v4l | |
parent | e6ad5cf4401b860ba402d4b7b3c7c254bc87a019 (diff) |
baresip 0.4.10
Diffstat (limited to 'modules/v4l')
-rw-r--r-- | modules/v4l/module.mk | 11 | ||||
-rw-r--r-- | modules/v4l/v4l.c | 257 |
2 files changed, 268 insertions, 0 deletions
diff --git a/modules/v4l/module.mk b/modules/v4l/module.mk new file mode 100644 index 0000000..05ff278 --- /dev/null +++ b/modules/v4l/module.mk @@ -0,0 +1,11 @@ +# +# module.mk +# +# Copyright (C) 2010 Creytiv.com +# + +MOD := v4l +$(MOD)_SRCS += v4l.c +$(MOD)_LFLAGS += + +include mk/mod.mk diff --git a/modules/v4l/v4l.c b/modules/v4l/v4l.c new file mode 100644 index 0000000..1f3e760 --- /dev/null +++ b/modules/v4l/v4l.c @@ -0,0 +1,257 @@ +/** + * @file v4l.c Video4Linux video-source + * + * Copyright (C) 2010 Creytiv.com + */ +#define _BSD_SOURCE 1 +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#undef __STRICT_ANSI__ /* needed for RHEL4 kernel 2.6.9 */ +#include <libv4l1-videodev.h> +#include <pthread.h> +#include <re.h> +#include <rem.h> +#include <baresip.h> + + +struct vidsrc_st { + struct vidsrc *vs; /* inheritance */ + + int fd; + pthread_t thread; + bool run; + struct vidsz size; + struct mbuf *mb; + vidsrc_frame_h *frameh; + void *arg; +}; + + +static struct vidsrc *vidsrc; + + +static void v4l_get_caps(struct vidsrc_st *st) +{ + struct video_capability caps; + + if (-1 == ioctl(st->fd, VIDIOCGCAP, &caps)) { + warning("v4l: VIDIOCGCAP: %m\n", errno); + return; + } + + info("v4l: video: \"%s\" (%ux%u) - (%ux%u)\n", caps.name, + caps.minwidth, caps.minheight, + caps.maxwidth, caps.maxheight); + + if (VID_TYPE_CAPTURE != caps.type) { + warning("v4l: not a capture device (%d)\n", caps.type); + } +} + + +static int v4l_check_palette(struct vidsrc_st *st) +{ + struct video_picture pic; + + if (-1 == ioctl(st->fd, VIDIOCGPICT, &pic)) { + warning("v4l: VIDIOCGPICT: %m\n", errno); + return errno; + } + + if (VIDEO_PALETTE_RGB24 != pic.palette) { + warning("v4l: unsupported palette %d (only RGB24 supp.)\n", + pic.palette); + return ENODEV; + } + + return 0; +} + + +static int v4l_get_win(int fd, int width, int height) +{ + struct video_window win; + + if (-1 == ioctl(fd, VIDIOCGWIN, &win)) { + warning("v4l: VIDIOCGWIN: %m\n", errno); + return errno; + } + + info("v4l: video window: x,y=%u,%u (%u x %u)\n", + win.x, win.y, win.width, win.height); + + win.width = width; + win.height = height; + + if (-1 == ioctl(fd, VIDIOCSWIN, &win)) { + warning("v4l: VIDIOCSWIN: %m\n", errno); + return errno; + } + + return 0; +} + + +static void call_frame_handler(struct vidsrc_st *st, uint8_t *buf) +{ + struct vidframe frame; + + vidframe_init_buf(&frame, VID_FMT_RGB32, &st->size, buf); + + st->frameh(&frame, st->arg); +} + + +static void *read_thread(void *arg) +{ + struct vidsrc_st *st = arg; + + while (st->run) { + ssize_t n; + + n = read(st->fd, st->mb->buf, st->mb->size); + if ((ssize_t)st->mb->size != n) { + warning("v4l: video read: %d -> %d bytes\n", + st->mb->size, n); + continue; + } + + call_frame_handler(st, st->mb->buf); + } + + return NULL; +} + + +static int vd_open(struct vidsrc_st *v4l, const char *device) +{ + /* NOTE: with kernel 2.6.26 it takes ~2 seconds to open + * the video device. + */ + v4l->fd = open(device, O_RDWR); + if (v4l->fd < 0) { + warning("v4l: open %s: %m\n", device, errno); + return errno; + } + + return 0; +} + + +static void destructor(void *arg) +{ + struct vidsrc_st *st = arg; + + if (st->run) { + st->run = false; + pthread_join(st->thread, NULL); + } + + if (st->fd >= 0) + close(st->fd); + + mem_deref(st->mb); + mem_deref(st->vs); +} + + +static uint32_t rgb24_size(const struct vidsz *sz) +{ + return sz ? (sz->w * sz->h * 24/8) : 0; +} + + +static int alloc(struct vidsrc_st **stp, struct vidsrc *vs, + struct media_ctx **ctx, struct vidsrc_prm *prm, + const struct vidsz *size, const char *fmt, + const char *dev, vidsrc_frame_h *frameh, + vidsrc_error_h *errorh, void *arg) +{ + struct vidsrc_st *st; + int err; + + (void)ctx; + (void)prm; + (void)fmt; + (void)errorh; + + if (!stp || !size || !frameh) + return EINVAL; + + if (!str_isset(dev)) + dev = "/dev/video0"; + + st = mem_zalloc(sizeof(*st), destructor); + if (!st) + return ENOMEM; + + st->vs = mem_ref(vs); + st->fd = -1; + st->size = *size; + st->frameh = frameh; + st->arg = arg; + + info("v4l: open: %s (%u x %u)\n", dev, size->w, size->h); + + err = vd_open(st, dev); + if (err) + goto out; + + v4l_get_caps(st); + + err = v4l_check_palette(st); + if (err) + goto out; + + err = v4l_get_win(st->fd, st->size.w, st->size.h); + if (err) + goto out; + + /* note: assumes RGB24 */ + st->mb = mbuf_alloc(rgb24_size(&st->size)); + if (!st->mb) { + err = ENOMEM; + goto out; + } + + st->run = true; + err = pthread_create(&st->thread, NULL, read_thread, st); + if (err) { + st->run = false; + goto out; + } + + out: + if (err) + mem_deref(st); + else + *stp = st; + + return err; +} + + +static int v4l_init(void) +{ + return vidsrc_register(&vidsrc, "v4l", alloc, NULL); +} + + +static int v4l_close(void) +{ + vidsrc = mem_deref(vidsrc); + return 0; +} + + +EXPORT_SYM const struct mod_export DECL_EXPORTS(v4l) = { + "v4l", + "vidsrc", + v4l_init, + v4l_close +}; |