From 79b972ba28a443a80f014b7ffbbb066da39b1b3f Mon Sep 17 00:00:00 2001 From: Tomasz Stanislawski Date: Wed, 14 Nov 2012 17:18:49 +0100 Subject: v4l2-dmabuf-test-01: version 0.1.1 Simple test with vivi and 2 V4L2 mem-to-mem devices. The output data is written to a file. Signed-off-by: Tomasz Stanislawski Signed-off-by: Sylwester Nawrocki --- v4l2-dmabuf-test/CHANGELOG | 17 ++ v4l2-dmabuf-test/Makefile | 17 ++ v4l2-dmabuf-test/v4l2-dbuf.c | 527 +++++++++++++++++++++++++++++++++++-------- 3 files changed, 472 insertions(+), 89 deletions(-) create mode 100644 v4l2-dmabuf-test/Makefile 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 + * + * 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 #include #include @@ -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; } -- cgit v1.2.3