summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomasz Stanislawski <t.stanislaws@samsung.com>2012-10-09 11:45:16 +0200
committerSylwester Nawrocki <s.nawrocki@samsung.com>2012-10-09 11:46:23 +0200
commite1dfdd991612931681df969141587365b9d8e4d7 (patch)
tree52d0a797e802b0f97be76787826ffe5533e0397d
parent2e7c05969d7923419f2536a92d5e53f4f829ab71 (diff)
v4l2-dmabuf-test-01: version 0.1
Simple test with vivi and 2 V4L2 mem-to-mem devices. The output data is written to a file. Image sizes are small due to Exynos SYMMU issues in the mainline kernel. Signed-off-by: Tomasz Stanislawski <t.stanislaws@samsung.com> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
-rw-r--r--v4l2-dmabuf-test/CHANGELOG1
-rw-r--r--v4l2-dmabuf-test/v4l2-dmabuf-test-01.c670
2 files changed, 671 insertions, 0 deletions
diff --git a/v4l2-dmabuf-test/CHANGELOG b/v4l2-dmabuf-test/CHANGELOG
new file mode 100644
index 0000000..673729c
--- /dev/null
+++ b/v4l2-dmabuf-test/CHANGELOG
@@ -0,0 +1 @@
+Version 0.1
diff --git a/v4l2-dmabuf-test/v4l2-dmabuf-test-01.c b/v4l2-dmabuf-test/v4l2-dmabuf-test-01.c
new file mode 100644
index 0000000..79894b2
--- /dev/null
+++ b/v4l2-dmabuf-test/v4l2-dmabuf-test-01.c
@@ -0,0 +1,670 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/videodev2.h>
+
+#define ARRAY_SIZE(tab) \
+ (sizeof(tab) / sizeof(*tab))
+
+#define CLEAR(s) memset(&s, 0, sizeof(s))
+
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+
+static inline int __info(const char *prefix, const char *file, int line,
+ const char *fmt, ...)
+{
+ int errsv = errno;
+ va_list va;
+
+ va_start(va, fmt);
+ fprintf(stderr, "%s(%s:%d): ", prefix, file, line);
+ vfprintf(stderr, fmt, va);
+ va_end(va);
+ errno = errsv;
+
+ return 1;
+}
+
+#define ERRSTR strerror(errno)
+
+#define LOG(...) fprintf(stdout, __VA_ARGS__)
+
+#define ERR(...) __info("Error", __FILE__, __LINE__, __VA_ARGS__)
+#define ERR_ON(cond, ...) ((cond) ? ERR(__VA_ARGS__) : 0)
+
+#define CRIT(...) \
+ do { \
+ __info("Critical", __FILE__, __LINE__, __VA_ARGS__); \
+ exit(EXIT_FAILURE); \
+ } while(0)
+#define CRIT_ON(cond, ...) do { if (cond) CRIT(__VA_ARGS__); } while(0)
+
+struct format {
+ unsigned long fourcc;
+ unsigned long width;
+ unsigned long height;
+};
+
+struct config {
+ char vivi_path[256];
+ char fimc0_path[256];
+ char fimc1_path[256];
+ int rotate;
+ bool hflip;
+ bool vflip;
+ bool help;
+};
+
+struct state {
+ struct config config;
+ int vivi_fd;
+ int fimc0_fd;
+ int fimc1_fd;
+};
+
+static void usage(void)
+{
+#define HELP(...) fprintf(stderr, __VA_ARGS__)
+ HELP("Usage:\n");
+ HELP("\t-v path path to vivi [default /dev/video0]\n");
+ HELP("\t-0 path path to fimc0 [default /dev/video1]\n");
+ HELP("\t-1 path path to fimc1 [default /dev/video3]\n");
+ HELP("\t-V vertical flip\n");
+ HELP("\t-H horizontal flip\n");
+ HELP("\t-R angle rotation by angle [default 0]\n");
+ HELP("\t-h print this help\n");
+ HELP("\n");
+#undef HELP
+}
+
+static int config_create(struct config *config, int argc, char *argv[])
+{
+ int opt, ret = -EINVAL;
+
+ CLEAR(*config);
+ strcpy(config->vivi_path, "/dev/video0");
+ strcpy(config->fimc0_path, "/dev/video1");
+ strcpy(config->fimc1_path, "/dev/video3");
+
+ /* parse options */
+ while ((opt = getopt(argc, argv, ":v:0:1:VHR:h")) != -1) {
+ switch (opt) {
+ case 'v':
+ strcpy(config->vivi_path, optarg);
+ break;
+ case '0':
+ strcpy(config->fimc0_path, optarg);
+ break;
+ case '1':
+ strcpy(config->fimc1_path, optarg);
+ break;
+ case 'V':
+ config->vflip = true;
+ break;
+ case 'H':
+ config->hflip = true;
+ break;
+ case 'R':
+ ret = sscanf(optarg, "%d", &config->rotate);
+ if (ERR_ON(ret != 1, "invalid rotation\n"))
+ return -EILSEQ;
+ break;
+ case 'h':
+ config->help = true;
+ break;
+ case ':':
+ ERR("missing argument\n");
+ return -EINVAL;
+ default: /* '?' */
+ ERR("invalid option\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+void dump_format(char *str, struct v4l2_format *fmt)
+{
+ if (V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
+ struct v4l2_pix_format_mplane *pix = &fmt->fmt.pix_mp;
+ LOG("%s: width=%u height=%u format=%.4s\n", str,
+ pix->width, pix->height, (char*)&pix->pixelformat);
+ } else {
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+ LOG("%s: width=%u height=%u format=%.4s\n", str,
+ pix->width, pix->height, (char*)&pix->pixelformat);
+ }
+}
+
+int dump_yuyv(int fd, uint8_t *src, int w, int h)
+{
+ uint8_t buf[512], *dst = buf;
+ for (int wh = w * h; wh; wh--) {
+ int y0, y1, u, v;
+ int r, g, b;
+ y0 = *src++;
+ u = *src++;
+ y1 = *src++;
+ v = *src++;
+ u -= 128;
+ v -= 128;
+ g = MAX(y0 - (u + v) / 4, 0);
+ r = MIN(u + g, 0xff);
+ b = MIN(v + g, 0xff);
+ *dst++ = r;
+ *dst++ = g;
+ *dst++ = b;
+ g = MAX(y1 - (u + v) / 4, 0);
+ r = MIN(u + g, 0xff);
+ b = MIN(v + g, 0xff);
+ *dst++ = r;
+ *dst++ = g;
+ *dst++ = b;
+ if (dst - buf < ARRAY_SIZE(buf) - 6)
+ continue;
+ int ret = write(fd, buf, dst - buf);
+ if (ERR_ON(ret < 0, "write: %s\n", ERRSTR))
+ return -errno;
+ dst = buf;
+ }
+ int ret = write(fd, buf, dst - buf);
+ if (ERR_ON(ret < 0, "write: %s\n", ERRSTR))
+ return -errno;
+ return 0;
+}
+
+int dump_image(char *name, unsigned long fourcc, int w, int h, void *data)
+{
+ int fd = open(name, O_WRONLY | O_CREAT, 0644);
+ if (ERR_ON(fd < 0, "open: %s\n", ERRSTR))
+ return -errno;
+ char buf[64];
+ sprintf(buf, "P6\n%d %d\n255\n", w, h);
+ int ret = write(fd, buf, strlen(buf));
+ if (ERR_ON(ret < 0, "write: %s\n", ERRSTR))
+ return -errno;
+ ret = 0;
+ switch (fourcc) {
+ case V4L2_PIX_FMT_YUYV:
+ ret = dump_yuyv(fd, data, w, h);
+ break;
+ default:
+ ERR("format %.4s not supported\n", (char*)&fourcc);
+ ret = -EINVAL;
+ }
+ close(fd);
+ ERR_ON(ret, "failed to dump %s\n", name);
+ return ret;
+}
+
+int setup_formats(struct state *st)
+{
+ struct v4l2_format fmt;
+ CLEAR(fmt);
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ /* get default format from VIVI */
+ int ret = ioctl(st->vivi_fd, VIDIOC_G_FMT, &fmt);
+ if (ERR_ON(ret < 0, "vivi: VIDIOC_G_FMT: %s\n", ERRSTR))
+ return -errno;
+ dump_format("vivi", &fmt);
+
+ /* setup format for FIMC 0 */
+ /* keep copy of format for to-mplane conversion */
+ struct v4l2_pix_format pix = fmt.fmt.pix;
+
+ CLEAR(fmt);
+ fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ struct v4l2_pix_format_mplane *pix_mp = &fmt.fmt.pix_mp;
+
+ pix_mp->width = pix.width;
+ pix_mp->height = pix.height;
+ pix_mp->pixelformat = pix.pixelformat;
+ pix_mp->num_planes = 1;
+
+ ret = ioctl(st->fimc0_fd, VIDIOC_S_FMT, &fmt);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_S_FMT: %s\n", ERRSTR))
+ return -errno;
+ dump_format("fimc0-output", &fmt);
+
+ /* setup image conversion */
+ struct v4l2_control ctrl;
+
+ if (st->config.hflip) {
+ CLEAR(ctrl);
+ ctrl.id = V4L2_CID_HFLIP;
+ ctrl.value = 1;
+ ret = ioctl(st->fimc0_fd, VIDIOC_S_CTRL, &ctrl);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_S_CTRL(hflip): %s\n",
+ ERRSTR))
+ return -errno;
+ }
+
+ if (st->config.vflip) {
+ CLEAR(ctrl);
+ ctrl.id = V4L2_CID_VFLIP;
+ ctrl.value = 1;
+ ret = ioctl(st->fimc0_fd, VIDIOC_S_CTRL, &ctrl);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_S_CTRL(vflip): %s\n",
+ ERRSTR))
+ return -errno;
+ }
+
+ if (st->config.rotate) {
+ CLEAR(ctrl);
+ ctrl.id = V4L2_CID_ROTATE;
+ ctrl.value = st->config.rotate;
+ ret = ioctl(st->fimc0_fd, VIDIOC_S_CTRL, &ctrl);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_S_CTRL(rotate): %s\n",
+ ERRSTR))
+ return -errno;
+ }
+
+ /* set the same format on fimc0 capture */
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ret = ioctl(st->fimc0_fd, VIDIOC_S_FMT, &fmt);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_S_FMT: %s\n", ERRSTR))
+ return -errno;
+
+ /* copy format from fimc0 capture to fimc1 output */
+ CLEAR(fmt);
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ret = ioctl(st->fimc0_fd, VIDIOC_G_FMT, &fmt);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_G_FMT: %s\n", ERRSTR))
+ return -errno;
+ dump_format("fimc0-capture", &fmt);
+
+ fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ ret = ioctl(st->fimc1_fd, VIDIOC_S_FMT, &fmt);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_S_FMT: %s\n", ERRSTR))
+ return -errno;
+ ret = ioctl(st->fimc1_fd, VIDIOC_G_FMT, &fmt);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_G_FMT: %s\n", ERRSTR))
+ return -errno;
+ dump_format("fimc1-output", &fmt);
+
+ /* and the same at FIMC1 output */
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ fmt.fmt.pix_mp.width = 32;
+ fmt.fmt.pix_mp.height = 32;
+ fmt.fmt.pix_mp.plane_fmt[0].bytesperline = 0;
+ ret = ioctl(st->fimc1_fd, VIDIOC_S_FMT, &fmt);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_S_FMT: %s\n", ERRSTR))
+ return -errno;
+
+ ret = ioctl(st->fimc1_fd, VIDIOC_G_FMT, &fmt);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_G_FMT: %s\n", ERRSTR))
+ return -errno;
+ dump_format("fimc1-capture", &fmt);
+
+ return 0;
+}
+
+int allocate_buffers(struct state *st)
+{
+ int ret;
+ struct v4l2_requestbuffers rb;
+ CLEAR(rb);
+
+ /* request buffers for VIVI */
+ rb.count = 1;
+ rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ rb.memory = V4L2_MEMORY_DMABUF;
+ ret = ioctl(st->vivi_fd, VIDIOC_REQBUFS, &rb);
+ if (ERR_ON(ret < 0, "vivi: VIDIOC_REQBUFS: %s\n", ERRSTR))
+ return -errno;
+
+ /* request buffers for FIMC0 */
+ rb.count = 1;
+ rb.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ rb.memory = V4L2_MEMORY_MMAP;
+ ret = ioctl(st->fimc0_fd, VIDIOC_REQBUFS, &rb);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_REQBUFS: %s\n", ERRSTR))
+ return -errno;
+
+ rb.count = 1;
+ rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ rb.memory = V4L2_MEMORY_DMABUF;
+ ret = ioctl(st->fimc0_fd, VIDIOC_REQBUFS, &rb);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_REQBUFS: %s\n", ERRSTR))
+ return -errno;
+
+ /* request buffers for FIMC1 */
+ rb.count = 1;
+ rb.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ rb.memory = V4L2_MEMORY_MMAP;
+ ret = ioctl(st->fimc1_fd, VIDIOC_REQBUFS, &rb);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_REQBUFS: %s\n", ERRSTR))
+ return -errno;
+
+ rb.count = 1;
+ rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ rb.memory = V4L2_MEMORY_USERPTR;
+ ret = ioctl(st->fimc1_fd, VIDIOC_REQBUFS, &rb);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_REQBUFS: %s\n", ERRSTR))
+ return -errno;
+
+ return 0;
+}
+
+int process_vivi(struct state *st)
+{
+ int ret;
+ struct v4l2_exportbuffer eb;
+ CLEAR(eb);
+
+ /* export buffer index=0 from FIMC0 */
+ eb.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ ret = ioctl(st->fimc0_fd, VIDIOC_EXPBUF, &eb);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_EXPBUF: %s\n", ERRSTR))
+ return -errno;
+
+ /* enqueue the dmabuf to vivi */
+ struct v4l2_buffer b;
+ CLEAR(b);
+
+ b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ b.memory = V4L2_MEMORY_DMABUF;
+ b.m.fd = eb.fd;
+ ret = ioctl(st->vivi_fd, VIDIOC_QBUF, &b);
+ if (ERR_ON(ret < 0, "vivi: VIDIOC_QBUF: %s\n", ERRSTR))
+ return -errno;
+
+ int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ ret = ioctl(st->vivi_fd, VIDIOC_STREAMON, &type);
+ if (ERR_ON(ret < 0, "vivi: VIDIOC_STREAMON: %s\n", ERRSTR))
+ return -errno;
+
+ /* dequeue buffer from VIVI */
+ CLEAR(b);
+ b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ b.memory = V4L2_MEMORY_DMABUF;
+
+ ret = ioctl(st->vivi_fd, VIDIOC_DQBUF, &b);
+ if (ERR_ON(ret < 0, "vivi: VIDIOC_DQBUF: %s\n", ERRSTR))
+ return -errno;
+
+ /* stop streaming */
+ ret = ioctl(st->vivi_fd, VIDIOC_STREAMOFF, &type);
+ if (ERR_ON(ret < 0, "vivi: VIDIOC_STREAMOFF: %s\n", ERRSTR))
+ return -errno;
+
+ /* TODO: mmap DMABUF and dump result */
+ struct v4l2_format fmt;
+ CLEAR(fmt);
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = ioctl(st->vivi_fd, VIDIOC_G_FMT, &fmt);
+ if (ERR_ON(ret < 0, "vivi: VIDIOC_G_FMT: %s\n", ERRSTR))
+ return -errno;
+
+ /* mapping DMABUF for dumping */
+ void *ptr = mmap(NULL, fmt.fmt.pix.sizeimage, PROT_READ,
+ MAP_SHARED, eb.fd, 0);
+ if (ERR_ON(ptr == MAP_FAILED, "mmap: %s\n", ERRSTR))
+ return -errno;
+
+ /* dump image, ignore errors */
+ dump_image("dmabuf-vivi-fimc0.ppm", fmt.fmt.pix.pixelformat,
+ fmt.fmt.pix.width, fmt.fmt.pix.height, ptr);
+
+ /* small cleanup */
+ munmap(ptr, fmt.fmt.pix.sizeimage);
+ close(eb.fd);
+
+ return 0;
+}
+
+int process_fimc0(struct state *st)
+{
+ int ret;
+ struct v4l2_buffer b;
+ struct v4l2_plane plane;
+ CLEAR(plane);
+ CLEAR(b);
+ b.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ b.memory = V4L2_MEMORY_MMAP;
+ b.index = 0;
+ b.m.planes = &plane;
+ b.length = 1;
+
+ ret = ioctl(st->fimc0_fd, VIDIOC_QBUF, &b);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_QBUF: %s\n", ERRSTR))
+ return -errno;
+
+ /* export the first buffer from FIMC1 */
+ struct v4l2_exportbuffer eb;
+ CLEAR(eb);
+ eb.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ ret = ioctl(st->fimc1_fd, VIDIOC_EXPBUF, &eb);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_EXPBUF: %s\n", ERRSTR))
+ return -errno;
+
+ /* enqueue the DMABUF as FIMC0's cature */
+ CLEAR(plane);
+ CLEAR(b);
+ b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ b.memory = V4L2_MEMORY_DMABUF;
+ b.index = 0;
+ b.m.planes = &plane;
+ b.length = 1;
+ plane.m.fd = eb.fd;
+
+ ret = ioctl(st->fimc0_fd, VIDIOC_QBUF, &b);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_QBUF: %s\n", ERRSTR))
+ return -errno;
+
+ /* start processing */
+ int type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ret = ioctl(st->fimc0_fd, VIDIOC_STREAMON, &type);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_STREAMON: %s\n", ERRSTR))
+ return -errno;
+
+ type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ ret = ioctl(st->fimc0_fd, VIDIOC_STREAMON, &type);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_STREAMON: %s\n", ERRSTR))
+ return -errno;
+
+ CLEAR(plane);
+ CLEAR(b);
+ b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ b.memory = V4L2_MEMORY_DMABUF;
+ b.m.planes = &plane;
+
+ /* grab processed buffers */
+ ret = ioctl(st->fimc0_fd, VIDIOC_DQBUF, &b);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_DQBUF: %s\n", ERRSTR))
+ return -errno;
+
+ CLEAR(plane);
+ CLEAR(b);
+ b.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ b.memory = V4L2_MEMORY_MMAP;
+ b.m.planes = &plane;
+
+ ret = ioctl(st->fimc0_fd, VIDIOC_DQBUF, &b);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_DQBUF: %s\n", ERRSTR))
+ return -errno;
+
+ /* stop processing */
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ret = ioctl(st->fimc0_fd, VIDIOC_STREAMOFF, &type);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_STREAMOFF: %s\n", ERRSTR))
+ return -errno;
+
+ type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ ret = ioctl(st->fimc0_fd, VIDIOC_STREAMOFF, &type);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_STREAMOFF: %s\n", ERRSTR))
+ return -errno;
+
+ return 0;
+}
+
+int process_fimc1(struct state *st)
+{
+ int ret;
+ /* enqueue buffer 0 as FIMC1's output */
+ struct v4l2_buffer b;
+ struct v4l2_plane plane;
+ CLEAR(plane);
+ CLEAR(b);
+ b.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ b.memory = V4L2_MEMORY_MMAP;
+ b.index = 0;
+ b.m.planes = &plane;
+ b.length = 1;
+
+ ret = ioctl(st->fimc1_fd, VIDIOC_QBUF, &b);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_QBUF: %s\n", ERRSTR))
+ return -errno;
+
+ /* allocate malloc memory suitable for FIMC1 */
+ struct v4l2_format fmt;
+ CLEAR(fmt);
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ret = ioctl(st->fimc1_fd, VIDIOC_G_FMT, &fmt);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_G_FMT: %s\n", ERRSTR))
+ return -errno;
+
+ long page_size = sysconf(_SC_PAGESIZE);
+ if (ERR_ON(page_size == -1, "sysconf: %s\n", ERRSTR))
+ return -errno;
+
+ /* someone should be shot because of the layout of v4l2_format */
+ size_t size = fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
+ /* align to page size */
+ size_t size_align = (size + page_size - 1) & ~(page_size - 1);
+
+ void *ptr;
+ ret = posix_memalign(&ptr, page_size, size_align);
+ if (ERR_ON(ret, "posix_memalign: %s\n", ERRSTR))
+ return -errno;
+
+ /* enqueue userptr as FIMC1's capture */
+ CLEAR(plane);
+ CLEAR(b);
+ b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ b.memory = V4L2_MEMORY_USERPTR;
+ b.index = 0;
+ b.m.planes = &plane;
+ b.length = 1;
+ plane.m.userptr = (unsigned long)ptr;
+ plane.length = size_align;
+
+ ret = ioctl(st->fimc1_fd, VIDIOC_QBUF, &b);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_QBUF: %s\n", ERRSTR))
+ return -errno;
+
+ /* start processing */
+ int type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ret = ioctl(st->fimc1_fd, VIDIOC_STREAMON, &type);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_STREAMON: %s\n", ERRSTR))
+ return -errno;
+
+ type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ ret = ioctl(st->fimc1_fd, VIDIOC_STREAMON, &type);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_STREAMON: %s\n", ERRSTR))
+ return -errno;
+
+ CLEAR(plane);
+ CLEAR(b);
+ b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ b.memory = V4L2_MEMORY_USERPTR;
+ b.m.planes = &plane;
+
+ /* grab processed buffers */
+ ret = ioctl(st->fimc1_fd, VIDIOC_DQBUF, &b);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_DQBUF: %s\n", ERRSTR))
+ return -errno;
+
+ CLEAR(plane);
+ CLEAR(b);
+ b.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ b.memory = V4L2_MEMORY_MMAP;
+ b.m.planes = &plane;
+
+ ret = ioctl(st->fimc1_fd, VIDIOC_DQBUF, &b);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_DQBUF: %s\n", ERRSTR))
+ return -errno;
+
+ /* stop processing */
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ret = ioctl(st->fimc1_fd, VIDIOC_STREAMOFF, &type);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_STREAMOFF: %s\n", ERRSTR))
+ return -errno;
+
+ type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ ret = ioctl(st->fimc1_fd, VIDIOC_STREAMOFF, &type);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_STREAMOFF: %s\n", ERRSTR))
+ return -errno;
+
+ /* dump image, ignore errors */
+ dump_image("fimc1-cature.ppm", fmt.fmt.pix_mp.pixelformat,
+ fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
+ ptr);
+
+ return 0;
+}
+int main(int argc, char *argv[])
+{
+ struct state st;
+ CLEAR(st);
+
+ int ret = config_create(&st.config, argc, argv);
+ if (ret) {
+ usage();
+ CRIT("bad arguments\n");
+ }
+
+ if (st.config.help) {
+ usage();
+ return EXIT_SUCCESS;
+ }
+
+ st.vivi_fd = open(st.config.vivi_path, O_RDWR);
+ CRIT_ON(st.vivi_fd < 0, "failed to open VIVI at %s: %s\n",
+ st.config.vivi_path, ERRSTR);
+
+ st.fimc0_fd = open(st.config.fimc0_path, O_RDWR);
+ CRIT_ON(st.vivi_fd < 0, "failed to open FIMC0 at %s: %s\n",
+ st.config.fimc0_path, ERRSTR);
+
+ st.fimc1_fd = open(st.config.fimc1_path, O_RDWR);
+ CRIT_ON(st.vivi_fd < 0, "failed to open FIMC1 at %s: %s\n",
+ st.config.fimc1_path, ERRSTR);
+
+ ret = setup_formats(&st);
+ CRIT_ON(ret, "failed to setup formats\n");
+
+ ret = allocate_buffers(&st);
+ CRIT_ON(ret, "failed to allocate buffers\n");
+
+ ret = process_vivi(&st);
+ CRIT_ON(ret, "failed to do vivi processing\n");
+
+ ret = process_fimc0(&st);
+ CRIT_ON(ret, "failed to do fimc0 processing\n");
+
+ ret = process_fimc1(&st);
+ CRIT_ON(ret, "failed to do fimc1 processing\n");
+
+ return EXIT_SUCCESS;
+}