diff options
Diffstat (limited to 'videoout.c')
-rw-r--r-- | videoout.c | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/videoout.c b/videoout.c new file mode 100644 index 0000000..6f68b30 --- /dev/null +++ b/videoout.c @@ -0,0 +1,228 @@ +/* + * V4L2 video output + * + * Copyright (C) 2010-2011 Ideas on board SPRL + * + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/videodev2.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <linux/fb.h> + +#include "videoout.h" +#include "isp/v4l2.h" +#include "isp/v4l2-pool.h" + +#define NUM_BUFFERS 3 + +struct videoout +{ + struct v4l2_device *dev; + struct v4l2_buffers_pool *pool; + const struct video_out_operations *ops; + + int streaming; + + int queued[NUM_BUFFERS]; + int num_queued; +}; + +struct videoout *vo_init(const char *devname, + const struct video_out_operations *ops, + unsigned int width, unsigned int height) +{ + struct v4l2_buffers_pool *pool = NULL; + struct v4l2_device *dev = NULL; + struct v4l2_pix_format pixfmt; + struct v4l2_format fmt; + struct v4l2_rect crop; + int ret; + + dev = v4l2_open(devname); + if (dev == NULL) { + perror("Failed to open display device\n"); + goto error; + } + + crop.left = 0; + crop.top = 0; + crop.width = width; + crop.height = height; + + ret = v4l2_set_crop(dev, &crop); + if (ret < 0) { + perror("VIDIOC_S_CROP\n"); + goto error; + } + + pixfmt.pixelformat = V4L2_PIX_FMT_YUYV; + pixfmt.width = width; + pixfmt.height = height; + pixfmt.field = V4L2_FIELD_ANY; + + ret = v4l2_set_format(dev, &pixfmt); + if (ret < 0) { + perror("VIDIOC_S_FMT(output)\n"); + goto error; + } + + fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + fmt.fmt.win.w.left = 0; + fmt.fmt.win.w.top = 0; + fmt.fmt.win.w.width = width; + fmt.fmt.win.w.height = height; + ret = ioctl(dev->fd, VIDIOC_S_FMT, &fmt); + if (ret < 0) { + perror("VIDIOC_S_FMT(overlay)\n"); + goto error; + } + + pool = v4l2_buffers_pool_new(NUM_BUFFERS); + if (pool == NULL) { + printf("error: unable to allocate buffers pool for display.\n"); + goto error; + } + + ret = v4l2_alloc_buffers(dev, pool, V4L2_MEMORY_MMAP); + if (ret < 0) { + printf("error: unable to allocate buffers pool for display.\n"); + goto error; + } + + struct videoout *vo = malloc(sizeof *vo); + memset(vo, 0, sizeof *vo); + vo->dev = dev; + vo->pool = pool; + vo->ops = ops; + + return vo; + +error: + if (dev) + v4l2_close(dev); + if (pool) + v4l2_buffers_pool_delete(pool); + return NULL; +} + +int vo_enable_colorkey(struct videoout *vo, unsigned int val) +{ + struct v4l2_framebuffer framebuffer; + struct v4l2_format fmt; + int ret; + + fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + ret = ioctl(vo->dev->fd, VIDIOC_G_FMT, &fmt); + if (ret < 0) { + perror("VIDIOC_G_FMT\n"); + return 0; + } + + fmt.fmt.win.chromakey = val; + ret = ioctl(vo->dev->fd, VIDIOC_S_FMT, &fmt); + if (ret < 0) { + perror("VIDIOC_G_FMT\n"); + return 0; + } + + ret = ioctl(vo->dev->fd, VIDIOC_G_FBUF, &framebuffer); + if (ret < 0) { + perror ("VIDIOC_G_FBUF"); + return 0; + } + + if (framebuffer.capability & V4L2_FBUF_CAP_CHROMAKEY) { + framebuffer.flags |= V4L2_FBUF_FLAG_CHROMAKEY; + framebuffer.flags &= ~V4L2_FBUF_FLAG_LOCAL_ALPHA; + ret = ioctl(vo->dev->fd, VIDIOC_S_FBUF, &framebuffer); + if (ret < 0) { + perror ("VIDIOC_S_FBUF"); + return 0; + } + } + + return 1; +} + +struct v4l2_buffers_pool *vo_get_pool(struct videoout *vo) +{ + return vo->pool; +} + +int vo_dequeue_buffer(struct videoout *vo, struct v4l2_video_buffer *buffer) +{ + int ret; + + if (vo->num_queued < 2) + return -ENOBUFS; + + ret = v4l2_dequeue_buffer(vo->dev, buffer); + if (ret < 0) { + if (errno != EIO) + perror("VIDIOC_DQBUF\n"); + return -errno; + } + + vo->queued[buffer->index] = 0; + vo->num_queued--; + + if (vo->num_queued == 0) + vo->ops->unwatch_fd(vo->dev->fd); + + return 0; +} + +int vo_queue_buffer(struct videoout *vo, struct v4l2_video_buffer *buffer) +{ + int ret; + + if (vo->queued[buffer->index]) { + fprintf (stderr, "buffer already queued\n"); + return 0; + } + + ret = v4l2_queue_buffer(vo->dev, buffer); + if (ret < 0) { + perror("VIDIOC_QBUF\n"); + return 0; + } + + vo->queued[buffer->index] = 1; + + if (!vo->streaming) { + if (v4l2_stream_on(vo->dev)) { + printf ("error: failed to start display streamon\n"); + } + vo->streaming = 1; + } + + if (vo->num_queued == 0) + vo->ops->watch_fd(vo->dev->fd); + + vo->num_queued++; + return 1; +} |