summaryrefslogtreecommitdiff
path: root/v4l2-dmabuf-test
diff options
context:
space:
mode:
Diffstat (limited to 'v4l2-dmabuf-test')
-rw-r--r--v4l2-dmabuf-test/CHANGELOG17
-rw-r--r--v4l2-dmabuf-test/Makefile17
-rw-r--r--v4l2-dmabuf-test/v4l2-dbuf.c527
3 files changed, 472 insertions, 89 deletions
diff --git a/v4l2-dmabuf-test/CHANGELOG b/v4l2-dmabuf-test/CHANGELOG
index 673729c..1b4764c 100644
--- a/v4l2-dmabuf-test/CHANGELOG
+++ b/v4l2-dmabuf-test/CHANGELOG
@@ -1 +1,18 @@
+Version 0.1.1
+- add Makefile
+- add Apache License
+- use arg to set format at each stage
+- use arg to set backing storage at last stage
+- rename options -0, -1 to -f, -F
+- revise code of YUYV dumping to PPM
+- supoprt for RGB565 and RGB4 formats
+- fix missing bytesperline at some S_FMT calls
+- fix missing length=1 at some QBUF calls
+- change PPM naming convention
+- modify pipeline to
+ VIVI_CAPTURE(DMABUF import)->
+ FIMC0_OUTPUT(MMAP, EXPORT DMABUF) -> FIMC0_CAPTURE(MMAP, EXPORT DMABUF) ->
+ FIMC1_OUTPUT(DMABUF import) -> FIMC1_CAPTURE(USERPTR) -> file/anonymous memory
+- make PPM dumping optional
+
Version 0.1
diff --git a/v4l2-dmabuf-test/Makefile b/v4l2-dmabuf-test/Makefile
new file mode 100644
index 0000000..cfd7436
--- /dev/null
+++ b/v4l2-dmabuf-test/Makefile
@@ -0,0 +1,17 @@
+CROSS_COMPILE ?= arm-linux-gnueabi-
+KDIR ?= /usr/src/linux
+CC=$(CROSS_COMPILE)gcc
+OBJS = v4l2-dbuf
+CFLAGS += -I$(KDIR)/usr/include -std=gnu99 -Wall -pedantic -O2
+
+all: $(OBJS)
+
+%.o : %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+% : %.c
+ $(CC) $(CFLAGS) $< -o $@
+
+clean:
+ rm -f *.o
+ rm -f $(OBJS)
diff --git a/v4l2-dmabuf-test/v4l2-dbuf.c b/v4l2-dmabuf-test/v4l2-dbuf.c
index 79894b2..3c6806b 100644
--- a/v4l2-dmabuf-test/v4l2-dbuf.c
+++ b/v4l2-dmabuf-test/v4l2-dbuf.c
@@ -1,3 +1,25 @@
+/*
+ * V4L2 VIVI + FIMC + DMABUF sharing Test Application
+ * Tomasz Stanislawski <t.stanislaws@samsung.com>
+ *
+ * This application is used to test DMABUF sharing between VIVI and FIMC
+ * device.
+ *
+ * Copyright 2012 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
@@ -26,6 +48,7 @@
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#define CLAMP(x,l,h) ((x) < (l) ? (l) : ((x) > (h) ? (h) : (x)))
static inline int __info(const char *prefix, const char *file, int line,
const char *fmt, ...)
@@ -44,7 +67,7 @@ static inline int __info(const char *prefix, const char *file, int line,
#define ERRSTR strerror(errno)
-#define LOG(...) fprintf(stdout, __VA_ARGS__)
+#define LOG(...) fprintf(stderr, __VA_ARGS__)
#define ERR(...) __info("Error", __FILE__, __LINE__, __VA_ARGS__)
#define ERR_ON(cond, ...) ((cond) ? ERR(__VA_ARGS__) : 0)
@@ -69,7 +92,12 @@ struct config {
int rotate;
bool hflip;
bool vflip;
+ bool dump;
bool help;
+ char dst_path[256];
+ int dst_size;
+ int dst_offset;
+ struct format fmt[3];
};
struct state {
@@ -77,6 +105,8 @@ struct state {
int vivi_fd;
int fimc0_fd;
int fimc1_fd;
+ void *dst_ptr;
+ unsigned long dst_size;
};
static void usage(void)
@@ -84,16 +114,40 @@ 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-f path path to fimc0 [default /dev/video1]\n");
+ HELP("\t-F path path to fimc1 [default /dev/video3]\n");
+ HELP("\t-0 4cc@WxH format between VIVI and FIMC0\n");
+ HELP("\t-1 4cc@WxH format between FIMC0 and FIMC1\n");
+ HELP("\t-2 4cc@WxH format between FIMC1 and destination\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-m size[@file[+offset]] destination mapping\n");
+ HELP("\t-d dump PPMs\n");
HELP("\t-h print this help\n");
HELP("\n");
#undef HELP
}
+int parse_format(char *s, struct format *fmt)
+{
+ char fourcc[5] = "";
+ int ret = sscanf(s, "%4[^@]@%lux%lu", fourcc,
+ &fmt->width, &fmt->height);
+
+ if (ERR_ON(ret != 3, "'%s' is not in 4cc@WxH format\n", s)) {
+ CLEAR(*fmt);
+ return -EILSEQ;
+ }
+
+ fmt->fourcc = ((unsigned)fourcc[0] << 0) |
+ ((unsigned)fourcc[1] << 8) |
+ ((unsigned)fourcc[2] << 16) |
+ ((unsigned)fourcc[3] << 24);
+
+ return 0;
+}
+
static int config_create(struct config *config, int argc, char *argv[])
{
int opt, ret = -EINVAL;
@@ -104,17 +158,24 @@ static int config_create(struct config *config, int argc, char *argv[])
strcpy(config->fimc1_path, "/dev/video3");
/* parse options */
- while ((opt = getopt(argc, argv, ":v:0:1:VHR:h")) != -1) {
+ while ((opt = getopt(argc, argv, ":v:f:F:0:1:2:VHR:m:dh")) != -1) {
switch (opt) {
case 'v':
strcpy(config->vivi_path, optarg);
break;
- case '0':
+ case 'f':
strcpy(config->fimc0_path, optarg);
break;
- case '1':
+ case 'F':
strcpy(config->fimc1_path, optarg);
break;
+ case '0':
+ case '1':
+ case '2':
+ ret = parse_format(optarg, &config->fmt[opt - '0']);
+ if (ERR_ON(ret < 0, "invalid format\n"))
+ return ret;
+ break;
case 'V':
config->vflip = true;
break;
@@ -126,14 +187,23 @@ static int config_create(struct config *config, int argc, char *argv[])
if (ERR_ON(ret != 1, "invalid rotation\n"))
return -EILSEQ;
break;
+ case 'd':
+ config->dump = true;
+ break;
case 'h':
config->help = true;
break;
+ case 'm':
+ ret = sscanf(optarg, "%i@%255[^+-]%i", &config->dst_size,
+ config->dst_path, &config->dst_offset);
+ if (ERR_ON(ret < 1, "invalid mapping\n"))
+ return -EILSEQ;
+ break;
case ':':
- ERR("missing argument\n");
+ ERR("missing argument for option %c\n", optopt);
return -EINVAL;
default: /* '?' */
- ERR("invalid option\n");
+ ERR("invalid option %c\n", optopt);
return -EINVAL;
}
}
@@ -145,18 +215,20 @@ 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);
+ LOG("%s: width=%u height=%u format=%.4s bpl=%u\n", str,
+ pix->width, pix->height, (char*)&pix->pixelformat,
+ pix->plane_fmt[0].bytesperline);
} 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);
+ LOG("%s: width=%u height=%u format=%.4s bpl=%u\n", str,
+ pix->width, pix->height, (char*)&pix->pixelformat,
+ pix->bytesperline);
}
}
int dump_yuyv(int fd, uint8_t *src, int w, int h)
{
- uint8_t buf[512], *dst = buf;
+ uint8_t buf[6 * 256], *dst = buf;
for (int wh = w * h; wh; wh--) {
int y0, y1, u, v;
int r, g, b;
@@ -164,21 +236,93 @@ int dump_yuyv(int fd, uint8_t *src, int w, int h)
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)
+ r = (298 * y0 + 409 * v - 56992) >> 8;
+ g = (298 * y0 - 100 * u - 208 * v + 34784) >> 8;
+ b = (298 * y0 + 516 * u - 70688) >> 8;
+ *dst++ = CLAMP(r, 0, 255);
+ *dst++ = CLAMP(g, 0, 255);
+ *dst++ = CLAMP(b, 0, 255);
+ r = (298 * y1 + 409 * v - 56992) >> 8;
+ g = (298 * y1 - 100 * u - 208 * v + 34784) >> 8;
+ b = (298 * y1 + 516 * u - 70688) >> 8;
+ *dst++ = CLAMP(r, 0, 255);
+ *dst++ = CLAMP(g, 0, 255);
+ *dst++ = CLAMP(b, 0, 255);
+ if (dst - buf < ARRAY_SIZE(buf))
+ 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;
+}
+
+static inline uint8_t expand8(int v, int size)
+{
+ switch (size) {
+ case 0:
+ return 0xff;
+ case 1:
+ return v & 0x01 ? 0xff : 0;
+ case 2:
+ v &= 0x03;
+ return (v << 6) | (v << 4) | (v << 2) | v;
+ case 3:
+ v &= 0x07;
+ return (v << 5) | (v << 2) | (v >> 1);
+ case 4:
+ v &= 0x0f;
+ return (v << 4) | v;
+ case 5:
+ v &= 0x1f;
+ return (v << 3) | (v >> 2);
+ case 6:
+ v &= 0x3f;
+ return (v << 2) | (v >> 4);
+ case 7:
+ v &= 0x7f;
+ return (v << 1) | (v >> 6);
+ default:
+ return v;
+ }
+}
+
+int dump_rgb565(int fd, uint8_t *src, int w, int h)
+{
+ uint8_t buf[3 * 256], *dst = buf;
+ for (int wh = w * h; wh; wh--) {
+ int v = 0;
+ v |= (int)(*src++);
+ v |= (int)(*src++) << 8;
+ *dst++ = expand8(v, 5);
+ *dst++ = expand8(v >> 5, 6);
+ *dst++ = expand8(v >> 11, 5);
+ if (dst - buf < ARRAY_SIZE(buf))
+ 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_rgb32(int fd, uint8_t *src, int w, int h)
+{
+ uint8_t buf[3 * 256], *dst = buf;
+ for (int wh = w * h; wh; wh--) {
+ ++src;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ if (dst - buf < ARRAY_SIZE(buf))
continue;
int ret = write(fd, buf, dst - buf);
if (ERR_ON(ret < 0, "write: %s\n", ERRSTR))
@@ -206,26 +350,48 @@ int dump_image(char *name, unsigned long fourcc, int w, int h, void *data)
case V4L2_PIX_FMT_YUYV:
ret = dump_yuyv(fd, data, w, h);
break;
+ case V4L2_PIX_FMT_RGB565:
+ ret = dump_rgb565(fd, data, w, h);
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ ret = dump_rgb32(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);
+ if (ret)
+ ERR("failed to dump %s\n", name);
+ else
+ LOG("%s dumped successfully\n", name);
return ret;
}
int setup_formats(struct state *st)
{
+ int ret = 0;
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);
+ /* apply cmdline format if available */
+ if (st->config.fmt[0].fourcc) {
+ struct v4l2_pix_format *pix = &fmt.fmt.pix;
+ pix->pixelformat = st->config.fmt[0].fourcc;
+ pix->width = st->config.fmt[0].width;
+ pix->height = st->config.fmt[0].height;
+ ret = ioctl(st->vivi_fd, VIDIOC_S_FMT, &fmt);
+ if (ERR_ON(ret < 0, "vivi: VIDIOC_G_FMT: %s\n", ERRSTR))
+ return -errno;
+ dump_format("pre-vivi-capture", &fmt);
+ }
+
+ /* get format from VIVI */
+ 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);
+ dump_format("vivi-capture", &fmt);
/* setup format for FIMC 0 */
/* keep copy of format for to-mplane conversion */
@@ -239,6 +405,7 @@ int setup_formats(struct state *st)
pix_mp->height = pix.height;
pix_mp->pixelformat = pix.pixelformat;
pix_mp->num_planes = 1;
+ pix_mp->plane_fmt[0].bytesperline = pix.bytesperline;
ret = ioctl(st->fimc0_fd, VIDIOC_S_FMT, &fmt);
if (ERR_ON(ret < 0, "fimc0: VIDIOC_S_FMT: %s\n", ERRSTR))
@@ -278,8 +445,19 @@ int setup_formats(struct state *st)
return -errno;
}
- /* set the same format on fimc0 capture */
+ /* set format on fimc0 capture */
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ /* try cmdline format, or use fimc0-output instead */
+ if (st->config.fmt[1].fourcc) {
+ struct v4l2_pix_format_mplane *pix = &fmt.fmt.pix_mp;
+ CLEAR(*pix);
+ pix->pixelformat = st->config.fmt[1].fourcc;
+ pix->width = st->config.fmt[1].width;
+ pix->height = st->config.fmt[1].height;
+ pix->plane_fmt[0].bytesperline = 0;
+ }
+
+ dump_format("pre-fimc0-capture", &fmt);
ret = ioctl(st->fimc0_fd, VIDIOC_S_FMT, &fmt);
if (ERR_ON(ret < 0, "fimc0: VIDIOC_S_FMT: %s\n", ERRSTR))
return -errno;
@@ -301,11 +479,17 @@ int setup_formats(struct state *st)
return -errno;
dump_format("fimc1-output", &fmt);
- /* and the same at FIMC1 output */
+ /* set format on fimc1 capture */
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;
+ /* try cmdline format, or use fimc1-output instead */
+ if (st->config.fmt[2].fourcc) {
+ struct v4l2_pix_format_mplane *pix = &fmt.fmt.pix_mp;
+ pix->pixelformat = st->config.fmt[2].fourcc;
+ pix->width = st->config.fmt[2].width;
+ pix->height = st->config.fmt[2].height;
+ pix->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;
@@ -342,7 +526,7 @@ int allocate_buffers(struct state *st)
rb.count = 1;
rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- rb.memory = V4L2_MEMORY_DMABUF;
+ 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;
@@ -350,7 +534,7 @@ int allocate_buffers(struct state *st)
/* request buffers for FIMC1 */
rb.count = 1;
rb.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- rb.memory = V4L2_MEMORY_MMAP;
+ rb.memory = V4L2_MEMORY_DMABUF;
ret = ioctl(st->fimc1_fd, VIDIOC_REQBUFS, &rb);
if (ERR_ON(ret < 0, "fimc1: VIDIOC_REQBUFS: %s\n", ERRSTR))
return -errno;
@@ -362,6 +546,43 @@ int allocate_buffers(struct state *st)
if (ERR_ON(ret < 0, "fimc1: VIDIOC_REQBUFS: %s\n", ERRSTR))
return -errno;
+ /* allocate memory for destination data */
+ int fd = -1; /* assume anonymous mapping */
+ int flags = MAP_ANONYMOUS | MAP_PRIVATE;
+ if (st->config.dst_path[0]) {
+ fd = open(st->config.dst_path, O_RDWR);
+ if (ERR_ON(fd < 0, "open: %s\n", ERRSTR))
+ return -errno;
+ flags = MAP_SHARED;
+ }
+
+ LOG("dst_path=%s dst_size=%i dst_offset=%i\n",
+ st->config.dst_path, st->config.dst_size,
+ st->config.dst_offset);
+
+ size_t size = st->config.dst_size;
+ /* get size from FIMC1 format if none is given at cmdline */
+ if (!size) {
+ 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;
+ /* someone should be shot for the layout of v4l2_format */
+ size = fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
+ }
+
+ st->dst_ptr = mmap(NULL, size, PROT_READ, flags, fd,
+ st->config.dst_offset);
+
+ if (ERR_ON(st->dst_ptr == MAP_FAILED, "mmap: %s\n", ERRSTR))
+ return -errno;
+
+ st->dst_size = size;
+
+ close(fd);
+
return 0;
}
@@ -407,7 +628,29 @@ int process_vivi(struct state *st)
if (ERR_ON(ret < 0, "vivi: VIDIOC_STREAMOFF: %s\n", ERRSTR))
return -errno;
- /* TODO: mmap DMABUF and dump result */
+ LOG("VIVI worked correctly\n");
+
+ /* mmap DMABUF */
+ 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_QUERYBUF, &b);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_QUERYBUF: %s\n", ERRSTR))
+ return -errno;
+
+ void *ptr = mmap(NULL, plane.length, PROT_READ, MAP_SHARED, eb.fd, 0);
+ if (ERR_ON(ptr == MAP_FAILED, "mmap: %s\n", ERRSTR))
+ return -errno;
+
+ LOG("DMABUF from FIMC0 OUTPUT mmapped correctly\n");
+
+ /* get format for dumping */
struct v4l2_format fmt;
CLEAR(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -416,18 +659,13 @@ int process_vivi(struct state *st)
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);
+ if (st->config.dump)
+ dump_image("0-vivi-capture-dmabuf.ppm", fmt.fmt.pix.pixelformat,
+ fmt.fmt.pix.width, fmt.fmt.pix.height, ptr);
/* small cleanup */
- munmap(ptr, fmt.fmt.pix.sizeimage);
+ munmap(ptr, plane.length);
close(eb.fd);
return 0;
@@ -438,6 +676,8 @@ int process_fimc0(struct state *st)
int ret;
struct v4l2_buffer b;
struct v4l2_plane plane;
+
+ /* enqueue buffer to fimc0 output */
CLEAR(plane);
CLEAR(b);
b.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
@@ -450,23 +690,14 @@ int process_fimc0(struct state *st)
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 */
+ /* enqueue buffer to fimc0 capture */
CLEAR(plane);
CLEAR(b);
b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- b.memory = V4L2_MEMORY_DMABUF;
+ b.memory = V4L2_MEMORY_MMAP;
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))
@@ -488,6 +719,7 @@ int process_fimc0(struct state *st)
b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
b.memory = V4L2_MEMORY_DMABUF;
b.m.planes = &plane;
+ b.length = 1;
/* grab processed buffers */
ret = ioctl(st->fimc0_fd, VIDIOC_DQBUF, &b);
@@ -499,6 +731,7 @@ int process_fimc0(struct state *st)
b.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
b.memory = V4L2_MEMORY_MMAP;
b.m.planes = &plane;
+ b.length = 1;
ret = ioctl(st->fimc0_fd, VIDIOC_DQBUF, &b);
if (ERR_ON(ret < 0, "fimc0: VIDIOC_DQBUF: %s\n", ERRSTR))
@@ -515,15 +748,9 @@ int process_fimc0(struct state *st)
if (ERR_ON(ret < 0, "fimc0: VIDIOC_STREAMOFF: %s\n", ERRSTR))
return -errno;
- return 0;
-}
+ LOG("FIMC0 worked correctly\n");
-int process_fimc1(struct state *st)
-{
- int ret;
- /* enqueue buffer 0 as FIMC1's output */
- struct v4l2_buffer b;
- struct v4l2_plane plane;
+ /* querybuf and mmap fimc0 output */
CLEAR(plane);
CLEAR(b);
b.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
@@ -532,30 +759,100 @@ int process_fimc1(struct state *st)
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))
+ ret = ioctl(st->fimc0_fd, VIDIOC_QUERYBUF, &b);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_QUERYBUF: %s\n", ERRSTR))
+ return -errno;
+
+ /* mmap FIMC0 output and dump it */
+ void *ptr = mmap(NULL, plane.length,
+ PROT_READ | PROT_WRITE, MAP_SHARED, st->fimc0_fd,
+ plane.m.mem_offset);
+ if (ERR_ON(ptr == MAP_FAILED, "mmap: %s\n", ERRSTR))
return -errno;
- /* allocate malloc memory suitable for FIMC1 */
+ LOG("FIMC0 output mmapped correctly\n");
+
+ /* get format, dump image, ignore result */
struct v4l2_format fmt;
CLEAR(fmt);
+ fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+
+ ret = ioctl(st->fimc0_fd, VIDIOC_G_FMT, &fmt);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_G_FMT: %s\n", ERRSTR))
+ return -errno;
+
+ if (st->config.dump)
+ dump_image("1-fimc0-output-mmap.ppm",
+ fmt.fmt.pix_mp.pixelformat,
+ fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height, ptr);
+
+ munmap(ptr, plane.length);
+
+ /* querybuf and mmap fimc0 capture */
+ CLEAR(plane);
+ CLEAR(b);
+ b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ b.memory = V4L2_MEMORY_MMAP;
+ b.index = 0;
+ b.m.planes = &plane;
+ b.length = 1;
+
+ ret = ioctl(st->fimc0_fd, VIDIOC_QUERYBUF, &b);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_QUERYBUF: %s\n", ERRSTR))
+ return -errno;
+
+ ptr = mmap(NULL, plane.length,
+ PROT_READ | PROT_WRITE, MAP_SHARED, st->fimc0_fd,
+ plane.m.mem_offset);
+ if (ERR_ON(ptr == MAP_FAILED, "mmap: %s\n", ERRSTR))
+ return -errno;
+
+ LOG("FIMC0 capture mmapped correctly\n");
+
+ /* get format, dump image, ignore result */
+ 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))
+
+ ret = ioctl(st->fimc0_fd, VIDIOC_G_FMT, &fmt);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_G_FMT: %s\n", ERRSTR))
return -errno;
- long page_size = sysconf(_SC_PAGESIZE);
- if (ERR_ON(page_size == -1, "sysconf: %s\n", ERRSTR))
+ if (st->config.dump)
+ dump_image("2-fimc0-capture-mmap.ppm",
+ fmt.fmt.pix_mp.pixelformat,
+ fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height, ptr);
+
+ munmap(ptr, plane.length);
+
+ return 0;
+}
+
+int process_fimc1(struct state *st)
+{
+ int ret;
+
+ /* export the first buffer from FIMC0 capture */
+ struct v4l2_exportbuffer eb;
+ CLEAR(eb);
+ eb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ret = ioctl(st->fimc0_fd, VIDIOC_EXPBUF, &eb);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_EXPBUF: %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);
+ /* enqueue the DMABUF 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_DMABUF;
+ b.index = 0;
+ b.m.planes = &plane;
+ b.length = 1;
+ plane.m.fd = eb.fd;
- void *ptr;
- ret = posix_memalign(&ptr, page_size, size_align);
- if (ERR_ON(ret, "posix_memalign: %s\n", ERRSTR))
+ ret = ioctl(st->fimc1_fd, VIDIOC_QBUF, &b);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_QBUF: %s\n", ERRSTR))
return -errno;
/* enqueue userptr as FIMC1's capture */
@@ -566,8 +863,8 @@ int process_fimc1(struct state *st)
b.index = 0;
b.m.planes = &plane;
b.length = 1;
- plane.m.userptr = (unsigned long)ptr;
- plane.length = size_align;
+ plane.m.userptr = (unsigned long)st->dst_ptr;
+ plane.length = st->dst_size;
ret = ioctl(st->fimc1_fd, VIDIOC_QBUF, &b);
if (ERR_ON(ret < 0, "fimc1: VIDIOC_QBUF: %s\n", ERRSTR))
@@ -584,13 +881,14 @@ int process_fimc1(struct state *st)
if (ERR_ON(ret < 0, "fimc1: VIDIOC_STREAMON: %s\n", ERRSTR))
return -errno;
+ /* grab processed buffers */
CLEAR(plane);
CLEAR(b);
b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
b.memory = V4L2_MEMORY_USERPTR;
b.m.planes = &plane;
+ b.length = 1;
- /* grab processed buffers */
ret = ioctl(st->fimc1_fd, VIDIOC_DQBUF, &b);
if (ERR_ON(ret < 0, "fimc1: VIDIOC_DQBUF: %s\n", ERRSTR))
return -errno;
@@ -600,6 +898,7 @@ int process_fimc1(struct state *st)
b.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
b.memory = V4L2_MEMORY_MMAP;
b.m.planes = &plane;
+ b.length = 1;
ret = ioctl(st->fimc1_fd, VIDIOC_DQBUF, &b);
if (ERR_ON(ret < 0, "fimc1: VIDIOC_DQBUF: %s\n", ERRSTR))
@@ -616,10 +915,58 @@ int process_fimc1(struct state *st)
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);
+ LOG("FIMC1 worked correctly\n");
+
+ /* mmap FIMC0 capture DMABUF and dump result */
+ CLEAR(plane);
+ CLEAR(b);
+ b.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ b.memory = V4L2_MEMORY_MMAP;
+ b.m.planes = &plane;
+ b.length = 1;
+
+ ret = ioctl(st->fimc0_fd, VIDIOC_QUERYBUF, &b);
+ if (ERR_ON(ret < 0, "fimc0: VIDIOC_QUERYBUF: %s\n", ERRSTR))
+ return -errno;
+
+ /* mapping DMABUF */
+ void *ptr = mmap(NULL, plane.length, PROT_READ, MAP_SHARED, eb.fd, 0);
+ if (ERR_ON(ptr == MAP_FAILED, "mmap: %s\n", ERRSTR))
+ return -errno;
+
+ LOG("DMABUF from FIMC0 capture mmapped correctly\n");
+
+ /* get format, dump image, ignore result */
+ struct v4l2_format fmt;
+ CLEAR(fmt);
+ fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ ret = ioctl(st->fimc1_fd, VIDIOC_G_FMT, &fmt);
+ if (ERR_ON(ret < 0, "fimc1: VIDIOC_G_FMT: %s\n", ERRSTR))
+ return 0;
+
+ if (st->config.dump)
+ dump_image("3-fimc1-output-dmabuf.ppm",
+ fmt.fmt.pix_mp.pixelformat,
+ fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height, ptr);
+
+ /* cleanup DMABUF stuff */
+ munmap(ptr, plane.length);
+ close(eb.fd);
+
+ /* get format, dump fimc1-capture image, ignore errors */
+ 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 0;
+
+ msync(st->dst_ptr, st->dst_size, MS_SYNC);
+
+ if (st->config.dump)
+ dump_image("4-fimc1-capture-userptr.ppm",
+ fmt.fmt.pix_mp.pixelformat,
+ fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
+ st->dst_ptr);
return 0;
}
@@ -666,5 +1013,7 @@ int main(int argc, char *argv[])
ret = process_fimc1(&st);
CRIT_ON(ret, "failed to do fimc1 processing\n");
+ LOG("Test passed\n");
+
return EXIT_SUCCESS;
}