summaryrefslogtreecommitdiff
path: root/videoout.c
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2011-07-30 14:33:37 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2011-07-30 14:33:37 +0200
commitfebcb53ca85d911619456c09c4be49fd73c4964b (patch)
tree12ae3a93d117b56da6e1213882f5cc6de3977adb /videoout.c
omap3-isp-live: Initial commit
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'videoout.c')
-rw-r--r--videoout.c228
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;
+}