1059b1c5bSMauro Carvalho Chehab.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later 254f38fcaSMauro Carvalho Chehab 354f38fcaSMauro Carvalho Chehabfile: media/v4l/capture.c 454f38fcaSMauro Carvalho Chehab========================= 554f38fcaSMauro Carvalho Chehab 654f38fcaSMauro Carvalho Chehab.. code-block:: c 754f38fcaSMauro Carvalho Chehab 854f38fcaSMauro Carvalho Chehab /* 954f38fcaSMauro Carvalho Chehab * V4L2 video capture example 1054f38fcaSMauro Carvalho Chehab * 1154f38fcaSMauro Carvalho Chehab * This program can be used and distributed without restrictions. 1254f38fcaSMauro Carvalho Chehab * 1354f38fcaSMauro Carvalho Chehab * This program is provided with the V4L2 API 1454f38fcaSMauro Carvalho Chehab * see https://linuxtv.org/docs.php for more information 1554f38fcaSMauro Carvalho Chehab */ 1654f38fcaSMauro Carvalho Chehab 1754f38fcaSMauro Carvalho Chehab #include <stdio.h> 1854f38fcaSMauro Carvalho Chehab #include <stdlib.h> 1954f38fcaSMauro Carvalho Chehab #include <string.h> 2054f38fcaSMauro Carvalho Chehab #include <assert.h> 2154f38fcaSMauro Carvalho Chehab 2254f38fcaSMauro Carvalho Chehab #include <getopt.h> /* getopt_long() */ 2354f38fcaSMauro Carvalho Chehab 2454f38fcaSMauro Carvalho Chehab #include <fcntl.h> /* low-level i/o */ 2554f38fcaSMauro Carvalho Chehab #include <unistd.h> 2654f38fcaSMauro Carvalho Chehab #include <errno.h> 2754f38fcaSMauro Carvalho Chehab #include <sys/stat.h> 2854f38fcaSMauro Carvalho Chehab #include <sys/types.h> 2954f38fcaSMauro Carvalho Chehab #include <sys/time.h> 3054f38fcaSMauro Carvalho Chehab #include <sys/mman.h> 3154f38fcaSMauro Carvalho Chehab #include <sys/ioctl.h> 3254f38fcaSMauro Carvalho Chehab 3354f38fcaSMauro Carvalho Chehab #include <linux/videodev2.h> 3454f38fcaSMauro Carvalho Chehab 3554f38fcaSMauro Carvalho Chehab #define CLEAR(x) memset(&(x), 0, sizeof(x)) 3654f38fcaSMauro Carvalho Chehab 3754f38fcaSMauro Carvalho Chehab enum io_method { 3854f38fcaSMauro Carvalho Chehab IO_METHOD_READ, 3954f38fcaSMauro Carvalho Chehab IO_METHOD_MMAP, 4054f38fcaSMauro Carvalho Chehab IO_METHOD_USERPTR, 4154f38fcaSMauro Carvalho Chehab }; 4254f38fcaSMauro Carvalho Chehab 4354f38fcaSMauro Carvalho Chehab struct buffer { 4454f38fcaSMauro Carvalho Chehab void *start; 4554f38fcaSMauro Carvalho Chehab size_t length; 4654f38fcaSMauro Carvalho Chehab }; 4754f38fcaSMauro Carvalho Chehab 4854f38fcaSMauro Carvalho Chehab static char *dev_name; 4954f38fcaSMauro Carvalho Chehab static enum io_method io = IO_METHOD_MMAP; 5054f38fcaSMauro Carvalho Chehab static int fd = -1; 5154f38fcaSMauro Carvalho Chehab struct buffer *buffers; 5254f38fcaSMauro Carvalho Chehab static unsigned int n_buffers; 5354f38fcaSMauro Carvalho Chehab static int out_buf; 5454f38fcaSMauro Carvalho Chehab static int force_format; 5554f38fcaSMauro Carvalho Chehab static int frame_count = 70; 5654f38fcaSMauro Carvalho Chehab 5754f38fcaSMauro Carvalho Chehab static void errno_exit(const char *s) 5854f38fcaSMauro Carvalho Chehab { 59*d7894721SKwang Son fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno)); 6054f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 6154f38fcaSMauro Carvalho Chehab } 6254f38fcaSMauro Carvalho Chehab 6354f38fcaSMauro Carvalho Chehab static int xioctl(int fh, int request, void *arg) 6454f38fcaSMauro Carvalho Chehab { 6554f38fcaSMauro Carvalho Chehab int r; 6654f38fcaSMauro Carvalho Chehab 6754f38fcaSMauro Carvalho Chehab do { 6854f38fcaSMauro Carvalho Chehab r = ioctl(fh, request, arg); 6954f38fcaSMauro Carvalho Chehab } while (-1 == r && EINTR == errno); 7054f38fcaSMauro Carvalho Chehab 7154f38fcaSMauro Carvalho Chehab return r; 7254f38fcaSMauro Carvalho Chehab } 7354f38fcaSMauro Carvalho Chehab 7454f38fcaSMauro Carvalho Chehab static void process_image(const void *p, int size) 7554f38fcaSMauro Carvalho Chehab { 7654f38fcaSMauro Carvalho Chehab if (out_buf) 7754f38fcaSMauro Carvalho Chehab fwrite(p, size, 1, stdout); 7854f38fcaSMauro Carvalho Chehab 7954f38fcaSMauro Carvalho Chehab fflush(stderr); 8054f38fcaSMauro Carvalho Chehab fprintf(stderr, "."); 8154f38fcaSMauro Carvalho Chehab fflush(stdout); 8254f38fcaSMauro Carvalho Chehab } 8354f38fcaSMauro Carvalho Chehab 8454f38fcaSMauro Carvalho Chehab static int read_frame(void) 8554f38fcaSMauro Carvalho Chehab { 8654f38fcaSMauro Carvalho Chehab struct v4l2_buffer buf; 8754f38fcaSMauro Carvalho Chehab unsigned int i; 8854f38fcaSMauro Carvalho Chehab 8954f38fcaSMauro Carvalho Chehab switch (io) { 9054f38fcaSMauro Carvalho Chehab case IO_METHOD_READ: 9154f38fcaSMauro Carvalho Chehab if (-1 == read(fd, buffers[0].start, buffers[0].length)) { 9254f38fcaSMauro Carvalho Chehab switch (errno) { 9354f38fcaSMauro Carvalho Chehab case EAGAIN: 9454f38fcaSMauro Carvalho Chehab return 0; 9554f38fcaSMauro Carvalho Chehab 9654f38fcaSMauro Carvalho Chehab case EIO: 9754f38fcaSMauro Carvalho Chehab /* Could ignore EIO, see spec. */ 9854f38fcaSMauro Carvalho Chehab 9954f38fcaSMauro Carvalho Chehab /* fall through */ 10054f38fcaSMauro Carvalho Chehab 10154f38fcaSMauro Carvalho Chehab default: 10254f38fcaSMauro Carvalho Chehab errno_exit("read"); 10354f38fcaSMauro Carvalho Chehab } 10454f38fcaSMauro Carvalho Chehab } 10554f38fcaSMauro Carvalho Chehab 10654f38fcaSMauro Carvalho Chehab process_image(buffers[0].start, buffers[0].length); 10754f38fcaSMauro Carvalho Chehab break; 10854f38fcaSMauro Carvalho Chehab 10954f38fcaSMauro Carvalho Chehab case IO_METHOD_MMAP: 11054f38fcaSMauro Carvalho Chehab CLEAR(buf); 11154f38fcaSMauro Carvalho Chehab 11254f38fcaSMauro Carvalho Chehab buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 11354f38fcaSMauro Carvalho Chehab buf.memory = V4L2_MEMORY_MMAP; 11454f38fcaSMauro Carvalho Chehab 11554f38fcaSMauro Carvalho Chehab if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) { 11654f38fcaSMauro Carvalho Chehab switch (errno) { 11754f38fcaSMauro Carvalho Chehab case EAGAIN: 11854f38fcaSMauro Carvalho Chehab return 0; 11954f38fcaSMauro Carvalho Chehab 12054f38fcaSMauro Carvalho Chehab case EIO: 12154f38fcaSMauro Carvalho Chehab /* Could ignore EIO, see spec. */ 12254f38fcaSMauro Carvalho Chehab 12354f38fcaSMauro Carvalho Chehab /* fall through */ 12454f38fcaSMauro Carvalho Chehab 12554f38fcaSMauro Carvalho Chehab default: 12654f38fcaSMauro Carvalho Chehab errno_exit("VIDIOC_DQBUF"); 12754f38fcaSMauro Carvalho Chehab } 12854f38fcaSMauro Carvalho Chehab } 12954f38fcaSMauro Carvalho Chehab 13054f38fcaSMauro Carvalho Chehab assert(buf.index < n_buffers); 13154f38fcaSMauro Carvalho Chehab 13254f38fcaSMauro Carvalho Chehab process_image(buffers[buf.index].start, buf.bytesused); 13354f38fcaSMauro Carvalho Chehab 13454f38fcaSMauro Carvalho Chehab if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) 13554f38fcaSMauro Carvalho Chehab errno_exit("VIDIOC_QBUF"); 13654f38fcaSMauro Carvalho Chehab break; 13754f38fcaSMauro Carvalho Chehab 13854f38fcaSMauro Carvalho Chehab case IO_METHOD_USERPTR: 13954f38fcaSMauro Carvalho Chehab CLEAR(buf); 14054f38fcaSMauro Carvalho Chehab 14154f38fcaSMauro Carvalho Chehab buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 14254f38fcaSMauro Carvalho Chehab buf.memory = V4L2_MEMORY_USERPTR; 14354f38fcaSMauro Carvalho Chehab 14454f38fcaSMauro Carvalho Chehab if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) { 14554f38fcaSMauro Carvalho Chehab switch (errno) { 14654f38fcaSMauro Carvalho Chehab case EAGAIN: 14754f38fcaSMauro Carvalho Chehab return 0; 14854f38fcaSMauro Carvalho Chehab 14954f38fcaSMauro Carvalho Chehab case EIO: 15054f38fcaSMauro Carvalho Chehab /* Could ignore EIO, see spec. */ 15154f38fcaSMauro Carvalho Chehab 15254f38fcaSMauro Carvalho Chehab /* fall through */ 15354f38fcaSMauro Carvalho Chehab 15454f38fcaSMauro Carvalho Chehab default: 15554f38fcaSMauro Carvalho Chehab errno_exit("VIDIOC_DQBUF"); 15654f38fcaSMauro Carvalho Chehab } 15754f38fcaSMauro Carvalho Chehab } 15854f38fcaSMauro Carvalho Chehab 15954f38fcaSMauro Carvalho Chehab for (i = 0; i < n_buffers; ++i) 16054f38fcaSMauro Carvalho Chehab if (buf.m.userptr == (unsigned long)buffers[i].start 16154f38fcaSMauro Carvalho Chehab && buf.length == buffers[i].length) 16254f38fcaSMauro Carvalho Chehab break; 16354f38fcaSMauro Carvalho Chehab 16454f38fcaSMauro Carvalho Chehab assert(i < n_buffers); 16554f38fcaSMauro Carvalho Chehab 16654f38fcaSMauro Carvalho Chehab process_image((void *)buf.m.userptr, buf.bytesused); 16754f38fcaSMauro Carvalho Chehab 16854f38fcaSMauro Carvalho Chehab if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) 16954f38fcaSMauro Carvalho Chehab errno_exit("VIDIOC_QBUF"); 17054f38fcaSMauro Carvalho Chehab break; 17154f38fcaSMauro Carvalho Chehab } 17254f38fcaSMauro Carvalho Chehab 17354f38fcaSMauro Carvalho Chehab return 1; 17454f38fcaSMauro Carvalho Chehab } 17554f38fcaSMauro Carvalho Chehab 17654f38fcaSMauro Carvalho Chehab static void mainloop(void) 17754f38fcaSMauro Carvalho Chehab { 17854f38fcaSMauro Carvalho Chehab unsigned int count; 17954f38fcaSMauro Carvalho Chehab 18054f38fcaSMauro Carvalho Chehab count = frame_count; 18154f38fcaSMauro Carvalho Chehab 18254f38fcaSMauro Carvalho Chehab while (count-- > 0) { 18354f38fcaSMauro Carvalho Chehab for (;;) { 18454f38fcaSMauro Carvalho Chehab fd_set fds; 18554f38fcaSMauro Carvalho Chehab struct timeval tv; 18654f38fcaSMauro Carvalho Chehab int r; 18754f38fcaSMauro Carvalho Chehab 18854f38fcaSMauro Carvalho Chehab FD_ZERO(&fds); 18954f38fcaSMauro Carvalho Chehab FD_SET(fd, &fds); 19054f38fcaSMauro Carvalho Chehab 19154f38fcaSMauro Carvalho Chehab /* Timeout. */ 19254f38fcaSMauro Carvalho Chehab tv.tv_sec = 2; 19354f38fcaSMauro Carvalho Chehab tv.tv_usec = 0; 19454f38fcaSMauro Carvalho Chehab 19554f38fcaSMauro Carvalho Chehab r = select(fd + 1, &fds, NULL, NULL, &tv); 19654f38fcaSMauro Carvalho Chehab 19754f38fcaSMauro Carvalho Chehab if (-1 == r) { 19854f38fcaSMauro Carvalho Chehab if (EINTR == errno) 19954f38fcaSMauro Carvalho Chehab continue; 20054f38fcaSMauro Carvalho Chehab errno_exit("select"); 20154f38fcaSMauro Carvalho Chehab } 20254f38fcaSMauro Carvalho Chehab 20354f38fcaSMauro Carvalho Chehab if (0 == r) { 204*d7894721SKwang Son fprintf(stderr, "select timeout\n"); 20554f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 20654f38fcaSMauro Carvalho Chehab } 20754f38fcaSMauro Carvalho Chehab 20854f38fcaSMauro Carvalho Chehab if (read_frame()) 20954f38fcaSMauro Carvalho Chehab break; 21054f38fcaSMauro Carvalho Chehab /* EAGAIN - continue select loop. */ 21154f38fcaSMauro Carvalho Chehab } 21254f38fcaSMauro Carvalho Chehab } 21354f38fcaSMauro Carvalho Chehab } 21454f38fcaSMauro Carvalho Chehab 21554f38fcaSMauro Carvalho Chehab static void stop_capturing(void) 21654f38fcaSMauro Carvalho Chehab { 21754f38fcaSMauro Carvalho Chehab enum v4l2_buf_type type; 21854f38fcaSMauro Carvalho Chehab 21954f38fcaSMauro Carvalho Chehab switch (io) { 22054f38fcaSMauro Carvalho Chehab case IO_METHOD_READ: 22154f38fcaSMauro Carvalho Chehab /* Nothing to do. */ 22254f38fcaSMauro Carvalho Chehab break; 22354f38fcaSMauro Carvalho Chehab 22454f38fcaSMauro Carvalho Chehab case IO_METHOD_MMAP: 22554f38fcaSMauro Carvalho Chehab case IO_METHOD_USERPTR: 22654f38fcaSMauro Carvalho Chehab type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 22754f38fcaSMauro Carvalho Chehab if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type)) 22854f38fcaSMauro Carvalho Chehab errno_exit("VIDIOC_STREAMOFF"); 22954f38fcaSMauro Carvalho Chehab break; 23054f38fcaSMauro Carvalho Chehab } 23154f38fcaSMauro Carvalho Chehab } 23254f38fcaSMauro Carvalho Chehab 23354f38fcaSMauro Carvalho Chehab static void start_capturing(void) 23454f38fcaSMauro Carvalho Chehab { 23554f38fcaSMauro Carvalho Chehab unsigned int i; 23654f38fcaSMauro Carvalho Chehab enum v4l2_buf_type type; 23754f38fcaSMauro Carvalho Chehab 23854f38fcaSMauro Carvalho Chehab switch (io) { 23954f38fcaSMauro Carvalho Chehab case IO_METHOD_READ: 24054f38fcaSMauro Carvalho Chehab /* Nothing to do. */ 24154f38fcaSMauro Carvalho Chehab break; 24254f38fcaSMauro Carvalho Chehab 24354f38fcaSMauro Carvalho Chehab case IO_METHOD_MMAP: 24454f38fcaSMauro Carvalho Chehab for (i = 0; i < n_buffers; ++i) { 24554f38fcaSMauro Carvalho Chehab struct v4l2_buffer buf; 24654f38fcaSMauro Carvalho Chehab 24754f38fcaSMauro Carvalho Chehab CLEAR(buf); 24854f38fcaSMauro Carvalho Chehab buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 24954f38fcaSMauro Carvalho Chehab buf.memory = V4L2_MEMORY_MMAP; 25054f38fcaSMauro Carvalho Chehab buf.index = i; 25154f38fcaSMauro Carvalho Chehab 25254f38fcaSMauro Carvalho Chehab if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) 25354f38fcaSMauro Carvalho Chehab errno_exit("VIDIOC_QBUF"); 25454f38fcaSMauro Carvalho Chehab } 25554f38fcaSMauro Carvalho Chehab type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 25654f38fcaSMauro Carvalho Chehab if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) 25754f38fcaSMauro Carvalho Chehab errno_exit("VIDIOC_STREAMON"); 25854f38fcaSMauro Carvalho Chehab break; 25954f38fcaSMauro Carvalho Chehab 26054f38fcaSMauro Carvalho Chehab case IO_METHOD_USERPTR: 26154f38fcaSMauro Carvalho Chehab for (i = 0; i < n_buffers; ++i) { 26254f38fcaSMauro Carvalho Chehab struct v4l2_buffer buf; 26354f38fcaSMauro Carvalho Chehab 26454f38fcaSMauro Carvalho Chehab CLEAR(buf); 26554f38fcaSMauro Carvalho Chehab buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 26654f38fcaSMauro Carvalho Chehab buf.memory = V4L2_MEMORY_USERPTR; 26754f38fcaSMauro Carvalho Chehab buf.index = i; 26854f38fcaSMauro Carvalho Chehab buf.m.userptr = (unsigned long)buffers[i].start; 26954f38fcaSMauro Carvalho Chehab buf.length = buffers[i].length; 27054f38fcaSMauro Carvalho Chehab 27154f38fcaSMauro Carvalho Chehab if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) 27254f38fcaSMauro Carvalho Chehab errno_exit("VIDIOC_QBUF"); 27354f38fcaSMauro Carvalho Chehab } 27454f38fcaSMauro Carvalho Chehab type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 27554f38fcaSMauro Carvalho Chehab if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) 27654f38fcaSMauro Carvalho Chehab errno_exit("VIDIOC_STREAMON"); 27754f38fcaSMauro Carvalho Chehab break; 27854f38fcaSMauro Carvalho Chehab } 27954f38fcaSMauro Carvalho Chehab } 28054f38fcaSMauro Carvalho Chehab 28154f38fcaSMauro Carvalho Chehab static void uninit_device(void) 28254f38fcaSMauro Carvalho Chehab { 28354f38fcaSMauro Carvalho Chehab unsigned int i; 28454f38fcaSMauro Carvalho Chehab 28554f38fcaSMauro Carvalho Chehab switch (io) { 28654f38fcaSMauro Carvalho Chehab case IO_METHOD_READ: 28754f38fcaSMauro Carvalho Chehab free(buffers[0].start); 28854f38fcaSMauro Carvalho Chehab break; 28954f38fcaSMauro Carvalho Chehab 29054f38fcaSMauro Carvalho Chehab case IO_METHOD_MMAP: 29154f38fcaSMauro Carvalho Chehab for (i = 0; i < n_buffers; ++i) 29254f38fcaSMauro Carvalho Chehab if (-1 == munmap(buffers[i].start, buffers[i].length)) 29354f38fcaSMauro Carvalho Chehab errno_exit("munmap"); 29454f38fcaSMauro Carvalho Chehab break; 29554f38fcaSMauro Carvalho Chehab 29654f38fcaSMauro Carvalho Chehab case IO_METHOD_USERPTR: 29754f38fcaSMauro Carvalho Chehab for (i = 0; i < n_buffers; ++i) 29854f38fcaSMauro Carvalho Chehab free(buffers[i].start); 29954f38fcaSMauro Carvalho Chehab break; 30054f38fcaSMauro Carvalho Chehab } 30154f38fcaSMauro Carvalho Chehab 30254f38fcaSMauro Carvalho Chehab free(buffers); 30354f38fcaSMauro Carvalho Chehab } 30454f38fcaSMauro Carvalho Chehab 30554f38fcaSMauro Carvalho Chehab static void init_read(unsigned int buffer_size) 30654f38fcaSMauro Carvalho Chehab { 30754f38fcaSMauro Carvalho Chehab buffers = calloc(1, sizeof(*buffers)); 30854f38fcaSMauro Carvalho Chehab 30954f38fcaSMauro Carvalho Chehab if (!buffers) { 310*d7894721SKwang Son fprintf(stderr, "Out of memory\n"); 31154f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 31254f38fcaSMauro Carvalho Chehab } 31354f38fcaSMauro Carvalho Chehab 31454f38fcaSMauro Carvalho Chehab buffers[0].length = buffer_size; 31554f38fcaSMauro Carvalho Chehab buffers[0].start = malloc(buffer_size); 31654f38fcaSMauro Carvalho Chehab 31754f38fcaSMauro Carvalho Chehab if (!buffers[0].start) { 318*d7894721SKwang Son fprintf(stderr, "Out of memory\n"); 31954f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 32054f38fcaSMauro Carvalho Chehab } 32154f38fcaSMauro Carvalho Chehab } 32254f38fcaSMauro Carvalho Chehab 32354f38fcaSMauro Carvalho Chehab static void init_mmap(void) 32454f38fcaSMauro Carvalho Chehab { 32554f38fcaSMauro Carvalho Chehab struct v4l2_requestbuffers req; 32654f38fcaSMauro Carvalho Chehab 32754f38fcaSMauro Carvalho Chehab CLEAR(req); 32854f38fcaSMauro Carvalho Chehab 32954f38fcaSMauro Carvalho Chehab req.count = 4; 33054f38fcaSMauro Carvalho Chehab req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 33154f38fcaSMauro Carvalho Chehab req.memory = V4L2_MEMORY_MMAP; 33254f38fcaSMauro Carvalho Chehab 33354f38fcaSMauro Carvalho Chehab if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { 33454f38fcaSMauro Carvalho Chehab if (EINVAL == errno) { 33554f38fcaSMauro Carvalho Chehab fprintf(stderr, "%s does not support " 33654f38fcaSMauro Carvalho Chehab "memory mappingn", dev_name); 33754f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 33854f38fcaSMauro Carvalho Chehab } else { 33954f38fcaSMauro Carvalho Chehab errno_exit("VIDIOC_REQBUFS"); 34054f38fcaSMauro Carvalho Chehab } 34154f38fcaSMauro Carvalho Chehab } 34254f38fcaSMauro Carvalho Chehab 34354f38fcaSMauro Carvalho Chehab if (req.count < 2) { 344*d7894721SKwang Son fprintf(stderr, "Insufficient buffer memory on %s\n", 34554f38fcaSMauro Carvalho Chehab dev_name); 34654f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 34754f38fcaSMauro Carvalho Chehab } 34854f38fcaSMauro Carvalho Chehab 34954f38fcaSMauro Carvalho Chehab buffers = calloc(req.count, sizeof(*buffers)); 35054f38fcaSMauro Carvalho Chehab 35154f38fcaSMauro Carvalho Chehab if (!buffers) { 352*d7894721SKwang Son fprintf(stderr, "Out of memory\n"); 35354f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 35454f38fcaSMauro Carvalho Chehab } 35554f38fcaSMauro Carvalho Chehab 35654f38fcaSMauro Carvalho Chehab for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { 35754f38fcaSMauro Carvalho Chehab struct v4l2_buffer buf; 35854f38fcaSMauro Carvalho Chehab 35954f38fcaSMauro Carvalho Chehab CLEAR(buf); 36054f38fcaSMauro Carvalho Chehab 36154f38fcaSMauro Carvalho Chehab buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 36254f38fcaSMauro Carvalho Chehab buf.memory = V4L2_MEMORY_MMAP; 36354f38fcaSMauro Carvalho Chehab buf.index = n_buffers; 36454f38fcaSMauro Carvalho Chehab 36554f38fcaSMauro Carvalho Chehab if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf)) 36654f38fcaSMauro Carvalho Chehab errno_exit("VIDIOC_QUERYBUF"); 36754f38fcaSMauro Carvalho Chehab 36854f38fcaSMauro Carvalho Chehab buffers[n_buffers].length = buf.length; 36954f38fcaSMauro Carvalho Chehab buffers[n_buffers].start = 37054f38fcaSMauro Carvalho Chehab mmap(NULL /* start anywhere */, 37154f38fcaSMauro Carvalho Chehab buf.length, 37254f38fcaSMauro Carvalho Chehab PROT_READ | PROT_WRITE /* required */, 37354f38fcaSMauro Carvalho Chehab MAP_SHARED /* recommended */, 37454f38fcaSMauro Carvalho Chehab fd, buf.m.offset); 37554f38fcaSMauro Carvalho Chehab 37654f38fcaSMauro Carvalho Chehab if (MAP_FAILED == buffers[n_buffers].start) 37754f38fcaSMauro Carvalho Chehab errno_exit("mmap"); 37854f38fcaSMauro Carvalho Chehab } 37954f38fcaSMauro Carvalho Chehab } 38054f38fcaSMauro Carvalho Chehab 38154f38fcaSMauro Carvalho Chehab static void init_userp(unsigned int buffer_size) 38254f38fcaSMauro Carvalho Chehab { 38354f38fcaSMauro Carvalho Chehab struct v4l2_requestbuffers req; 38454f38fcaSMauro Carvalho Chehab 38554f38fcaSMauro Carvalho Chehab CLEAR(req); 38654f38fcaSMauro Carvalho Chehab 38754f38fcaSMauro Carvalho Chehab req.count = 4; 38854f38fcaSMauro Carvalho Chehab req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 38954f38fcaSMauro Carvalho Chehab req.memory = V4L2_MEMORY_USERPTR; 39054f38fcaSMauro Carvalho Chehab 39154f38fcaSMauro Carvalho Chehab if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { 39254f38fcaSMauro Carvalho Chehab if (EINVAL == errno) { 39354f38fcaSMauro Carvalho Chehab fprintf(stderr, "%s does not support " 39454f38fcaSMauro Carvalho Chehab "user pointer i/on", dev_name); 39554f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 39654f38fcaSMauro Carvalho Chehab } else { 39754f38fcaSMauro Carvalho Chehab errno_exit("VIDIOC_REQBUFS"); 39854f38fcaSMauro Carvalho Chehab } 39954f38fcaSMauro Carvalho Chehab } 40054f38fcaSMauro Carvalho Chehab 40154f38fcaSMauro Carvalho Chehab buffers = calloc(4, sizeof(*buffers)); 40254f38fcaSMauro Carvalho Chehab 40354f38fcaSMauro Carvalho Chehab if (!buffers) { 404*d7894721SKwang Son fprintf(stderr, "Out of memory\n"); 40554f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 40654f38fcaSMauro Carvalho Chehab } 40754f38fcaSMauro Carvalho Chehab 40854f38fcaSMauro Carvalho Chehab for (n_buffers = 0; n_buffers < 4; ++n_buffers) { 40954f38fcaSMauro Carvalho Chehab buffers[n_buffers].length = buffer_size; 41054f38fcaSMauro Carvalho Chehab buffers[n_buffers].start = malloc(buffer_size); 41154f38fcaSMauro Carvalho Chehab 41254f38fcaSMauro Carvalho Chehab if (!buffers[n_buffers].start) { 413*d7894721SKwang Son fprintf(stderr, "Out of memory\n"); 41454f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 41554f38fcaSMauro Carvalho Chehab } 41654f38fcaSMauro Carvalho Chehab } 41754f38fcaSMauro Carvalho Chehab } 41854f38fcaSMauro Carvalho Chehab 41954f38fcaSMauro Carvalho Chehab static void init_device(void) 42054f38fcaSMauro Carvalho Chehab { 42154f38fcaSMauro Carvalho Chehab struct v4l2_capability cap; 42254f38fcaSMauro Carvalho Chehab struct v4l2_cropcap cropcap; 42354f38fcaSMauro Carvalho Chehab struct v4l2_crop crop; 42454f38fcaSMauro Carvalho Chehab struct v4l2_format fmt; 42554f38fcaSMauro Carvalho Chehab unsigned int min; 42654f38fcaSMauro Carvalho Chehab 42754f38fcaSMauro Carvalho Chehab if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) { 42854f38fcaSMauro Carvalho Chehab if (EINVAL == errno) { 429*d7894721SKwang Son fprintf(stderr, "%s is no V4L2 device\n", 43054f38fcaSMauro Carvalho Chehab dev_name); 43154f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 43254f38fcaSMauro Carvalho Chehab } else { 43354f38fcaSMauro Carvalho Chehab errno_exit("VIDIOC_QUERYCAP"); 43454f38fcaSMauro Carvalho Chehab } 43554f38fcaSMauro Carvalho Chehab } 43654f38fcaSMauro Carvalho Chehab 43754f38fcaSMauro Carvalho Chehab if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { 438*d7894721SKwang Son fprintf(stderr, "%s is no video capture device\n", 43954f38fcaSMauro Carvalho Chehab dev_name); 44054f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 44154f38fcaSMauro Carvalho Chehab } 44254f38fcaSMauro Carvalho Chehab 44354f38fcaSMauro Carvalho Chehab switch (io) { 44454f38fcaSMauro Carvalho Chehab case IO_METHOD_READ: 44554f38fcaSMauro Carvalho Chehab if (!(cap.capabilities & V4L2_CAP_READWRITE)) { 446*d7894721SKwang Son fprintf(stderr, "%s does not support read i/o\n", 44754f38fcaSMauro Carvalho Chehab dev_name); 44854f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 44954f38fcaSMauro Carvalho Chehab } 45054f38fcaSMauro Carvalho Chehab break; 45154f38fcaSMauro Carvalho Chehab 45254f38fcaSMauro Carvalho Chehab case IO_METHOD_MMAP: 45354f38fcaSMauro Carvalho Chehab case IO_METHOD_USERPTR: 45454f38fcaSMauro Carvalho Chehab if (!(cap.capabilities & V4L2_CAP_STREAMING)) { 455*d7894721SKwang Son fprintf(stderr, "%s does not support streaming i/o\n", 45654f38fcaSMauro Carvalho Chehab dev_name); 45754f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 45854f38fcaSMauro Carvalho Chehab } 45954f38fcaSMauro Carvalho Chehab break; 46054f38fcaSMauro Carvalho Chehab } 46154f38fcaSMauro Carvalho Chehab 46254f38fcaSMauro Carvalho Chehab 46354f38fcaSMauro Carvalho Chehab /* Select video input, video standard and tune here. */ 46454f38fcaSMauro Carvalho Chehab 46554f38fcaSMauro Carvalho Chehab 46654f38fcaSMauro Carvalho Chehab CLEAR(cropcap); 46754f38fcaSMauro Carvalho Chehab 46854f38fcaSMauro Carvalho Chehab cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 46954f38fcaSMauro Carvalho Chehab 47054f38fcaSMauro Carvalho Chehab if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) { 47154f38fcaSMauro Carvalho Chehab crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 47254f38fcaSMauro Carvalho Chehab crop.c = cropcap.defrect; /* reset to default */ 47354f38fcaSMauro Carvalho Chehab 47454f38fcaSMauro Carvalho Chehab if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) { 47554f38fcaSMauro Carvalho Chehab switch (errno) { 47654f38fcaSMauro Carvalho Chehab case EINVAL: 47754f38fcaSMauro Carvalho Chehab /* Cropping not supported. */ 47854f38fcaSMauro Carvalho Chehab break; 47954f38fcaSMauro Carvalho Chehab default: 48054f38fcaSMauro Carvalho Chehab /* Errors ignored. */ 48154f38fcaSMauro Carvalho Chehab break; 48254f38fcaSMauro Carvalho Chehab } 48354f38fcaSMauro Carvalho Chehab } 48454f38fcaSMauro Carvalho Chehab } else { 48554f38fcaSMauro Carvalho Chehab /* Errors ignored. */ 48654f38fcaSMauro Carvalho Chehab } 48754f38fcaSMauro Carvalho Chehab 48854f38fcaSMauro Carvalho Chehab 48954f38fcaSMauro Carvalho Chehab CLEAR(fmt); 49054f38fcaSMauro Carvalho Chehab 49154f38fcaSMauro Carvalho Chehab fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 49254f38fcaSMauro Carvalho Chehab if (force_format) { 49354f38fcaSMauro Carvalho Chehab fmt.fmt.pix.width = 640; 49454f38fcaSMauro Carvalho Chehab fmt.fmt.pix.height = 480; 49554f38fcaSMauro Carvalho Chehab fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; 49654f38fcaSMauro Carvalho Chehab fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; 49754f38fcaSMauro Carvalho Chehab 49854f38fcaSMauro Carvalho Chehab if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt)) 49954f38fcaSMauro Carvalho Chehab errno_exit("VIDIOC_S_FMT"); 50054f38fcaSMauro Carvalho Chehab 50154f38fcaSMauro Carvalho Chehab /* Note VIDIOC_S_FMT may change width and height. */ 50254f38fcaSMauro Carvalho Chehab } else { 50354f38fcaSMauro Carvalho Chehab /* Preserve original settings as set by v4l2-ctl for example */ 50454f38fcaSMauro Carvalho Chehab if (-1 == xioctl(fd, VIDIOC_G_FMT, &fmt)) 50554f38fcaSMauro Carvalho Chehab errno_exit("VIDIOC_G_FMT"); 50654f38fcaSMauro Carvalho Chehab } 50754f38fcaSMauro Carvalho Chehab 50854f38fcaSMauro Carvalho Chehab /* Buggy driver paranoia. */ 50954f38fcaSMauro Carvalho Chehab min = fmt.fmt.pix.width * 2; 51054f38fcaSMauro Carvalho Chehab if (fmt.fmt.pix.bytesperline < min) 51154f38fcaSMauro Carvalho Chehab fmt.fmt.pix.bytesperline = min; 51254f38fcaSMauro Carvalho Chehab min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; 51354f38fcaSMauro Carvalho Chehab if (fmt.fmt.pix.sizeimage < min) 51454f38fcaSMauro Carvalho Chehab fmt.fmt.pix.sizeimage = min; 51554f38fcaSMauro Carvalho Chehab 51654f38fcaSMauro Carvalho Chehab switch (io) { 51754f38fcaSMauro Carvalho Chehab case IO_METHOD_READ: 51854f38fcaSMauro Carvalho Chehab init_read(fmt.fmt.pix.sizeimage); 51954f38fcaSMauro Carvalho Chehab break; 52054f38fcaSMauro Carvalho Chehab 52154f38fcaSMauro Carvalho Chehab case IO_METHOD_MMAP: 52254f38fcaSMauro Carvalho Chehab init_mmap(); 52354f38fcaSMauro Carvalho Chehab break; 52454f38fcaSMauro Carvalho Chehab 52554f38fcaSMauro Carvalho Chehab case IO_METHOD_USERPTR: 52654f38fcaSMauro Carvalho Chehab init_userp(fmt.fmt.pix.sizeimage); 52754f38fcaSMauro Carvalho Chehab break; 52854f38fcaSMauro Carvalho Chehab } 52954f38fcaSMauro Carvalho Chehab } 53054f38fcaSMauro Carvalho Chehab 53154f38fcaSMauro Carvalho Chehab static void close_device(void) 53254f38fcaSMauro Carvalho Chehab { 53354f38fcaSMauro Carvalho Chehab if (-1 == close(fd)) 53454f38fcaSMauro Carvalho Chehab errno_exit("close"); 53554f38fcaSMauro Carvalho Chehab 53654f38fcaSMauro Carvalho Chehab fd = -1; 53754f38fcaSMauro Carvalho Chehab } 53854f38fcaSMauro Carvalho Chehab 53954f38fcaSMauro Carvalho Chehab static void open_device(void) 54054f38fcaSMauro Carvalho Chehab { 54154f38fcaSMauro Carvalho Chehab struct stat st; 54254f38fcaSMauro Carvalho Chehab 54354f38fcaSMauro Carvalho Chehab if (-1 == stat(dev_name, &st)) { 544*d7894721SKwang Son fprintf(stderr, "Cannot identify '%s': %d, %s\n", 54554f38fcaSMauro Carvalho Chehab dev_name, errno, strerror(errno)); 54654f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 54754f38fcaSMauro Carvalho Chehab } 54854f38fcaSMauro Carvalho Chehab 54954f38fcaSMauro Carvalho Chehab if (!S_ISCHR(st.st_mode)) { 55054f38fcaSMauro Carvalho Chehab fprintf(stderr, "%s is no devicen", dev_name); 55154f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 55254f38fcaSMauro Carvalho Chehab } 55354f38fcaSMauro Carvalho Chehab 55454f38fcaSMauro Carvalho Chehab fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0); 55554f38fcaSMauro Carvalho Chehab 55654f38fcaSMauro Carvalho Chehab if (-1 == fd) { 557*d7894721SKwang Son fprintf(stderr, "Cannot open '%s': %d, %s\n", 55854f38fcaSMauro Carvalho Chehab dev_name, errno, strerror(errno)); 55954f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 56054f38fcaSMauro Carvalho Chehab } 56154f38fcaSMauro Carvalho Chehab } 56254f38fcaSMauro Carvalho Chehab 56354f38fcaSMauro Carvalho Chehab static void usage(FILE *fp, int argc, char **argv) 56454f38fcaSMauro Carvalho Chehab { 56554f38fcaSMauro Carvalho Chehab fprintf(fp, 566*d7894721SKwang Son "Usage: %s [options]\n\n" 567*d7894721SKwang Son "Version 1.3\n" 568*d7894721SKwang Son "Options:\n" 569*d7894721SKwang Son "-d | --device name Video device name [%s]\n" 570*d7894721SKwang Son "-h | --help Print this message\n" 571*d7894721SKwang Son "-m | --mmap Use memory mapped buffers [default]\n" 572*d7894721SKwang Son "-r | --read Use read() calls\n" 573*d7894721SKwang Son "-u | --userp Use application allocated buffers\n" 574*d7894721SKwang Son "-o | --output Outputs stream to stdout\n" 575*d7894721SKwang Son "-f | --format Force format to 640x480 YUYV\n" 576*d7894721SKwang Son "-c | --count Number of frames to grab [%i]\n" 57754f38fcaSMauro Carvalho Chehab "", 57854f38fcaSMauro Carvalho Chehab argv[0], dev_name, frame_count); 57954f38fcaSMauro Carvalho Chehab } 58054f38fcaSMauro Carvalho Chehab 58154f38fcaSMauro Carvalho Chehab static const char short_options[] = "d:hmruofc:"; 58254f38fcaSMauro Carvalho Chehab 58354f38fcaSMauro Carvalho Chehab static const struct option 58454f38fcaSMauro Carvalho Chehab long_options[] = { 58554f38fcaSMauro Carvalho Chehab { "device", required_argument, NULL, 'd' }, 58654f38fcaSMauro Carvalho Chehab { "help", no_argument, NULL, 'h' }, 58754f38fcaSMauro Carvalho Chehab { "mmap", no_argument, NULL, 'm' }, 58854f38fcaSMauro Carvalho Chehab { "read", no_argument, NULL, 'r' }, 58954f38fcaSMauro Carvalho Chehab { "userp", no_argument, NULL, 'u' }, 59054f38fcaSMauro Carvalho Chehab { "output", no_argument, NULL, 'o' }, 59154f38fcaSMauro Carvalho Chehab { "format", no_argument, NULL, 'f' }, 59254f38fcaSMauro Carvalho Chehab { "count", required_argument, NULL, 'c' }, 59354f38fcaSMauro Carvalho Chehab { 0, 0, 0, 0 } 59454f38fcaSMauro Carvalho Chehab }; 59554f38fcaSMauro Carvalho Chehab 59654f38fcaSMauro Carvalho Chehab int main(int argc, char **argv) 59754f38fcaSMauro Carvalho Chehab { 59854f38fcaSMauro Carvalho Chehab dev_name = "/dev/video0"; 59954f38fcaSMauro Carvalho Chehab 60054f38fcaSMauro Carvalho Chehab for (;;) { 60154f38fcaSMauro Carvalho Chehab int idx; 60254f38fcaSMauro Carvalho Chehab int c; 60354f38fcaSMauro Carvalho Chehab 60454f38fcaSMauro Carvalho Chehab c = getopt_long(argc, argv, 60554f38fcaSMauro Carvalho Chehab short_options, long_options, &idx); 60654f38fcaSMauro Carvalho Chehab 60754f38fcaSMauro Carvalho Chehab if (-1 == c) 60854f38fcaSMauro Carvalho Chehab break; 60954f38fcaSMauro Carvalho Chehab 61054f38fcaSMauro Carvalho Chehab switch (c) { 61154f38fcaSMauro Carvalho Chehab case 0: /* getopt_long() flag */ 61254f38fcaSMauro Carvalho Chehab break; 61354f38fcaSMauro Carvalho Chehab 61454f38fcaSMauro Carvalho Chehab case 'd': 61554f38fcaSMauro Carvalho Chehab dev_name = optarg; 61654f38fcaSMauro Carvalho Chehab break; 61754f38fcaSMauro Carvalho Chehab 61854f38fcaSMauro Carvalho Chehab case 'h': 61954f38fcaSMauro Carvalho Chehab usage(stdout, argc, argv); 62054f38fcaSMauro Carvalho Chehab exit(EXIT_SUCCESS); 62154f38fcaSMauro Carvalho Chehab 62254f38fcaSMauro Carvalho Chehab case 'm': 62354f38fcaSMauro Carvalho Chehab io = IO_METHOD_MMAP; 62454f38fcaSMauro Carvalho Chehab break; 62554f38fcaSMauro Carvalho Chehab 62654f38fcaSMauro Carvalho Chehab case 'r': 62754f38fcaSMauro Carvalho Chehab io = IO_METHOD_READ; 62854f38fcaSMauro Carvalho Chehab break; 62954f38fcaSMauro Carvalho Chehab 63054f38fcaSMauro Carvalho Chehab case 'u': 63154f38fcaSMauro Carvalho Chehab io = IO_METHOD_USERPTR; 63254f38fcaSMauro Carvalho Chehab break; 63354f38fcaSMauro Carvalho Chehab 63454f38fcaSMauro Carvalho Chehab case 'o': 63554f38fcaSMauro Carvalho Chehab out_buf++; 63654f38fcaSMauro Carvalho Chehab break; 63754f38fcaSMauro Carvalho Chehab 63854f38fcaSMauro Carvalho Chehab case 'f': 63954f38fcaSMauro Carvalho Chehab force_format++; 64054f38fcaSMauro Carvalho Chehab break; 64154f38fcaSMauro Carvalho Chehab 64254f38fcaSMauro Carvalho Chehab case 'c': 64354f38fcaSMauro Carvalho Chehab errno = 0; 64454f38fcaSMauro Carvalho Chehab frame_count = strtol(optarg, NULL, 0); 64554f38fcaSMauro Carvalho Chehab if (errno) 64654f38fcaSMauro Carvalho Chehab errno_exit(optarg); 64754f38fcaSMauro Carvalho Chehab break; 64854f38fcaSMauro Carvalho Chehab 64954f38fcaSMauro Carvalho Chehab default: 65054f38fcaSMauro Carvalho Chehab usage(stderr, argc, argv); 65154f38fcaSMauro Carvalho Chehab exit(EXIT_FAILURE); 65254f38fcaSMauro Carvalho Chehab } 65354f38fcaSMauro Carvalho Chehab } 65454f38fcaSMauro Carvalho Chehab 65554f38fcaSMauro Carvalho Chehab open_device(); 65654f38fcaSMauro Carvalho Chehab init_device(); 65754f38fcaSMauro Carvalho Chehab start_capturing(); 65854f38fcaSMauro Carvalho Chehab mainloop(); 65954f38fcaSMauro Carvalho Chehab stop_capturing(); 66054f38fcaSMauro Carvalho Chehab uninit_device(); 66154f38fcaSMauro Carvalho Chehab close_device(); 662*d7894721SKwang Son fprintf(stderr, "\n"); 66354f38fcaSMauro Carvalho Chehab return 0; 66454f38fcaSMauro Carvalho Chehab } 665