summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: f0a117f)
raw | patch | inline | side by side (parent: f0a117f)
author | Nikhil Devshatwar <nikhil.nd@ti.com> | |
Wed, 25 Sep 2013 16:25:18 +0000 (21:55 +0530) | ||
committer | Nikhil Devshatwar <nikhil.nd@ti.com> | |
Tue, 8 Oct 2013 06:35:46 +0000 (12:05 +0530) |
This is a new app which captures buffers from v4l2 device and
displays via drm in fullscreeen.
Currently only memory mapped buffers are handled
Also, only YUYV format is supported for capture
v2->v3
======
Corrected coding style
Removed unused functions, debug code
Signed-off-by: Nikhil Devshatwar <nikhil.nd@ti.com>
displays via drm in fullscreeen.
Currently only memory mapped buffers are handled
Also, only YUYV format is supported for capture
v2->v3
======
Corrected coding style
Removed unused functions, debug code
Signed-off-by: Nikhil Devshatwar <nikhil.nd@ti.com>
Makefile.am | patch | blob | history | |
v4l2capturedisplay.c | [new file with mode: 0644] | patch | blob |
diff --git a/Makefile.am b/Makefile.am
index 44c595ed09222988bd2a3d772d227ec0db48aa95..70472509504691b4648c39b48188c64fe820d17a 100644 (file)
--- a/Makefile.am
+++ b/Makefile.am
#
SUBDIRS = util omx_cam
#
SUBDIRS = util omx_cam
-bin_PROGRAMS = fliptest
+bin_PROGRAMS = fliptest v4l2capturedisplay
if ENABLE_V4L2_DMABUF
#bin_PROGRAMS += dmabuftest
if ENABLE_V4L2_DMABUF
#bin_PROGRAMS += dmabuftest
fliptest_SOURCES = fliptest.c
fliptest_LDADD = $(LDADD_COMMON)
fliptest_SOURCES = fliptest.c
fliptest_LDADD = $(LDADD_COMMON)
+v4l2capturedisplay_SOURCES = v4l2capturedisplay.c
+v4l2capturedisplay_LDADD = $(LDADD_COMMON)
+
if ENABLE_V4L2_DMABUF
#dmabuftest_SOURCES = dmabuftest.c
#dmabuftest_LDADD = $(LDADD_COMMON)
if ENABLE_V4L2_DMABUF
#dmabuftest_SOURCES = dmabuftest.c
#dmabuftest_LDADD = $(LDADD_COMMON)
diff --git a/v4l2capturedisplay.c b/v4l2capturedisplay.c
--- /dev/null
+++ b/v4l2capturedisplay.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Nikhil Devshatwar <nikhil.nd@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/*
+ * This is a drm test app to capture and display frames from a v4l2 device
+ * It uses standard single planar V4L2 API to capture progressive frames
+ * Displays the buffers via drm in fullscreen
+ * Currently only YUYV format is allowed
+ * This can be used to test VIP (Video Input Port) on DRA7xx SoC
+ * For this, vpdma firmware should be copied in /lib/firmware on target
+ */
+
+#include "util.h"
+
+#include <linux/videodev2.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#define NBUF 6
+
+int width = 640, height = 480;
+
+void *buffer_addr[NBUF];
+int size[NBUF];
+
+static int xioctl(int fd, int request, void *arg)
+{
+ int r;
+
+ do r = ioctl (fd, request, arg);
+ while (-1 == r && EINTR == errno);
+
+ return r;
+}
+
+int init_device(int fd)
+{
+ char fourcc[5];
+ unsigned int i;
+ struct v4l2_format fmt;
+ struct v4l2_requestbuffers req;
+ struct v4l2_buffer buf;
+ struct v4l2_capability caps;
+
+ /* Check for capture device */
+ memset(&caps, 0, sizeof(caps));
+
+ if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &caps)) {
+ perror("Setting Pixel Format");
+ return 1;
+ }
+ MSG("Driver: %s\ncaps: %8x", caps.driver, caps.capabilities);
+ if(~caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
+ MSG("Not a capture device");
+ return 1;
+ }
+
+ /* Set capture format to YUYV */
+ memset(&fmt, 0, sizeof(fmt));
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt.fmt.pix.width = width;
+ fmt.fmt.pix.height = height;
+ fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ fmt.fmt.pix.field = V4L2_FIELD_NONE;
+
+ if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt)) {
+ perror("Setting Pixel Format");
+ return 1;
+ }
+
+ strncpy(fourcc, (char *)&fmt.fmt.pix.pixelformat, 4);
+ MSG( "Selected Camera Mode:\n"
+ " Width: %d\n"
+ " Height: %d\n"
+ " PixFmt: %s\n"
+ " Field: %d",
+ fmt.fmt.pix.width,
+ fmt.fmt.pix.height,
+ fourcc,
+ fmt.fmt.pix.field);
+
+ /* Currently driver supports only mmap buffers
+ * Request memory mapped buffers */
+ memset(&req, 0, sizeof(req));
+ req.count = 6;
+ req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req.memory = V4L2_MEMORY_MMAP;
+
+ if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
+ perror("Requesting Buffer");
+ return 1;
+ }
+
+ for (i = 0; i < req.count; i++) {
+ memset(&buf, 0, sizeof(buf));
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = i;
+ if(-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf)) {
+ perror("Querying Buffer");
+ return 1;
+ }
+
+ /* Memory map all the buffers and save the addresses */
+ buffer_addr[i] = mmap (NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
+ size[i] = buf.length;
+ MSG("Length: %d\nAddress: %p", buf.length, buffer_addr[i]);
+ MSG("Image Length: %d", buf.bytesused);
+
+ /* Queue the buffer for capture */
+ memset(&buf, 0, sizeof(buf));
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = i;
+ if(-1 == xioctl(fd, VIDIOC_QBUF, &buf)) {
+ perror("Queue Buffer");
+ return 1;
+ }
+
+ }
+ if(-1 == xioctl(fd, VIDIOC_STREAMON, &buf.type)) {
+ perror("Start Capture");
+ return 1;
+ }
+ return 0;
+}
+
+void release_device(int fd)
+{
+ int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ xioctl(fd, VIDIOC_STREAMOFF, &type);
+ close(fd);
+}
+
+static void usage(char *name) {
+ MSG("Usage: %s [OPTION]...", name);
+ MSG("V4L2 capture display test");
+ MSG("");
+ MSG("v4l2capturedisplay options:");
+ MSG("\t-h, --help: Print this help and exit.");
+ MSG("\t-n:\t Number of frames to capture (0 for infinite)");
+ MSG("\t-d:\t Device node to be used as capture device");
+ MSG("");
+ disp_usage();
+}
+
+void copy_buf(struct buffer *buf, void *deqbuf)
+{
+ int i, height = buf->height, stride = buf->pitches[0];
+ int capStride = 2 * width;
+ uint8_t *dst, *src;
+
+ dst = omap_bo_map(buf->bo[0]);
+ src = deqbuf;
+
+ /* Call this before you start accessing display buffers */
+ for (i = 0; i < buf->nbo; i++)
+ omap_bo_cpu_prep(buf->bo[i], OMAP_GEM_WRITE);
+
+ /* YUYV format - Only one bo expected
+ * TODO: Change this for all formats */
+ for(i=0; i<height; i++) {
+ dst += stride;
+ src += capStride;
+ memcpy(dst, src, capStride);
+ }
+
+ /* Call this after you are done with accessing display buffers */
+ for (i = 0; i < buf->nbo; i++)
+ omap_bo_cpu_fini(buf->bo[i], OMAP_GEM_WRITE);
+
+}
+
+int main(int argc, char **argv)
+{
+ struct display *disp;
+ struct buffer **buffers;
+ int ret, i, idx, fd, count = 0;
+ char devnode[100] = "/dev/video1";
+
+ /* Parse command line arguments */
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-h")) {
+ argv[i++] = NULL;
+ if(sscanf(argv[i], "%d", &height) != 1) {
+ ERROR("invalid height: %s", argv[i]);
+ return 1;
+ }
+ argv[i] = NULL;
+ } else if (!strcmp(argv[i], "-w")) {
+ argv[i++] = NULL;
+ if(sscanf(argv[i], "%d", &width) != 1) {
+ ERROR("invalid width: %s", argv[i]);
+ return 1;
+ }
+ argv[i] = NULL;
+ } else if (!strcmp(argv[i], "-n")) {
+ argv[i++] = NULL;
+ if(sscanf(argv[i], "%d", &count) != 1) {
+ ERROR("invalid count: %s", argv[i]);
+ return 1;
+ }
+ argv[i] = NULL;
+ } else if (!strcmp(argv[i], "-d")) {
+ argv[i++] = NULL;
+ strncpy(devnode, argv[i],100);
+ argv[i] = NULL;
+ }
+ }
+
+ MSG("Opening Video device %s", devnode);
+ fd = open(devnode, O_RDWR);
+ if (fd == -1) {
+ perror("Opening video device");
+ return 1;
+ }
+
+ ret = init_device(fd);
+ if (0 != ret) {
+ MSG("Exiting");
+ return ret;
+ }
+
+ MSG("Opening Display..");
+ disp = disp_open(argc, argv);
+ if (NULL == disp) {
+ usage(argv[0]);
+ return 1;
+ }
+
+ if (check_args(argc, argv)) {
+ /* remaining args.. print usage msg */
+ usage(argv[0]);
+ return 1;
+ }
+
+ /* Request drm to allocate some buffers */
+ buffers = disp_get_vid_buffers(disp, NBUF, FOURCC_STR("YUYV"), width, height);
+ if (!buffers) {
+ return 1;
+ }
+
+ for (i = 1; i != count; i++) {
+ struct buffer *dispbuf = buffers[i % NBUF];
+ struct v4l2_buffer buf;
+
+ /* Dequeue one buffer */
+ memset(&buf, 0, sizeof(buf));
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ if(-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
+ perror("Queue Buffer");
+ return 1;
+ }
+ idx = buf.index;
+
+ /* Copy data from dequeued buffer into display buffer */
+ copy_buf(dispbuf, buffer_addr[idx]);
+ /* Give it to display */
+ ret = disp_post_vid_buffer(disp, dispbuf, 0, 0, width, height);
+ if (ret) {
+ return ret;
+ }
+
+ /* Queue it back for next capture */
+ memset(&buf, 0, sizeof(buf));
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = idx;
+ if(-1 == xioctl(fd, VIDIOC_QBUF, &buf)) {
+ perror("Queue Buffer");
+ return 1;
+ }
+ }
+
+ disp_free_buffers(disp, NBUF);
+ disp_close(disp);
+ release_device(fd);
+
+ return 0;
+}