/* * v4l2loopback.c -- video4linux2 loopback driver * * Copyright (C) 2014 Nicolas Dufresne */ #include #include #include #include #include #include #include #include #include #include #include #define COUNT 4 #define sysfail(msg) \ { \ printf("%s failed: %s\n", (msg), strerror(errno)); \ return -1; \ } void usage(const char *progname) { printf("usage: %s \n", progname); exit(1); } int main(int argc, char **argv) { struct v4l2_format fmt = { 0 }; struct v4l2_requestbuffers breq = { 0 }; struct v4l2_buffer bufs[COUNT]; void *data[COUNT] = { 0 }; int fd; int i; if (argc < 2) usage(argv[0]); fd = open(argv[1], O_RDWR); if (fd < 0) sysfail("open"); fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; fmt.fmt.pix.width = 320; fmt.fmt.pix.height = 240; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) sysfail("S_FMT"); breq.count = COUNT; breq.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; breq.memory = V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_REQBUFS, &breq) < 0) sysfail("REQBUFS"); assert(breq.count == COUNT); memset(bufs, 0, sizeof(bufs)); for (i = 0; i < COUNT; i++) { int p; bufs[i].index = i; bufs[i].type = breq.type; bufs[i].memory = breq.memory; if (ioctl(fd, VIDIOC_QUERYBUF, &bufs[i]) < 0) sysfail("QUERYBUF"); data[i] = mmap(NULL, bufs[i].length, PROT_WRITE, MAP_SHARED, fd, bufs[i].m.offset); if (data[i] == MAP_FAILED) sysfail("mmap"); for (p = 0; p < (bufs[i].bytesused >> 2); p++) ((unsigned int *)data[i])[p] = 0xFF00FF00; } if (ioctl(fd, VIDIOC_QBUF, &bufs[0]) < 0) sysfail("QBUF"); if ((bufs[0].flags & V4L2_BUF_FLAG_QUEUED) == 0) { printf("BUG #1: Driver should set the QUEUED flag before returning from QBUF\n"); bufs[0].flags |= V4L2_BUF_FLAG_QUEUED; } if (ioctl(fd, VIDIOC_STREAMON, &fmt.type) < 0) sysfail("STREAMON"); i = 1; while (1) { struct v4l2_buffer buf = { 0 }; if (ioctl(fd, VIDIOC_QBUF, &bufs[i]) < 0) sysfail("QBUF"); printf("\tQUEUED=%d\tDONE=%d\n", bufs[i].flags & V4L2_BUF_FLAG_QUEUED, bufs[i].flags & V4L2_BUF_FLAG_DONE); if ((bufs[i].flags & V4L2_BUF_FLAG_QUEUED) == 0) { printf("BUG #1: Driver should set the QUEUED flag before returning from QBUF\n"); bufs[i].flags |= V4L2_BUF_FLAG_QUEUED; } buf.type = breq.type; buf.memory = breq.memory; if (ioctl(fd, VIDIOC_DQBUF, &buf) < 0) sysfail("DBBUF"); i = buf.index; if ((bufs[i].flags & V4L2_BUF_FLAG_QUEUED) == 0) { printf("BUG #2: Driver should not dequeue a buffer that was not initially queued\n"); } #if 0 assert (bufs[i].flags & V4L2_BUF_FLAG_QUEUED); assert (!(buf.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))); #endif bufs[i] = buf; } return 0; }