1.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later 2 3file: media/v4l/v4l2grab.c 4========================== 5 6.. code-block:: c 7 8 /* V4L2 video picture grabber 9 Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@kernel.org> 10 11 This program is free software; you can redistribute it and/or modify 12 it under the terms of the GNU General Public License as published by 13 the Free Software Foundation version 2 of the License. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 */ 20 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <fcntl.h> 25 #include <errno.h> 26 #include <sys/ioctl.h> 27 #include <sys/types.h> 28 #include <sys/time.h> 29 #include <sys/mman.h> 30 #include <linux/videodev2.h> 31 #include "../libv4l/include/libv4l2.h" 32 33 #define CLEAR(x) memset(&(x), 0, sizeof(x)) 34 35 struct buffer { 36 void *start; 37 size_t length; 38 }; 39 40 static void xioctl(int fh, int request, void *arg) 41 { 42 int r; 43 44 do { 45 r = v4l2_ioctl(fh, request, arg); 46 } while (r == -1 && ((errno == EINTR) || (errno == EAGAIN))); 47 48 if (r == -1) { 49 fprintf(stderr, "error %d, %s\n", errno, strerror(errno)); 50 exit(EXIT_FAILURE); 51 } 52 } 53 54 int main(int argc, char **argv) 55 { 56 struct v4l2_format fmt; 57 struct v4l2_buffer buf; 58 struct v4l2_requestbuffers req; 59 enum v4l2_buf_type type; 60 fd_set fds; 61 struct timeval tv; 62 int r, fd = -1; 63 unsigned int i, n_buffers; 64 char *dev_name = "/dev/video0"; 65 char out_name[256]; 66 FILE *fout; 67 struct buffer *buffers; 68 69 fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0); 70 if (fd < 0) { 71 perror("Cannot open device"); 72 exit(EXIT_FAILURE); 73 } 74 75 CLEAR(fmt); 76 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 77 fmt.fmt.pix.width = 640; 78 fmt.fmt.pix.height = 480; 79 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; 80 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; 81 xioctl(fd, VIDIOC_S_FMT, &fmt); 82 if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24) { 83 printf("Libv4l didn't accept RGB24 format. Can't proceed.\n"); 84 exit(EXIT_FAILURE); 85 } 86 if ((fmt.fmt.pix.width != 640) || (fmt.fmt.pix.height != 480)) 87 printf("Warning: driver is sending image at %dx%d\n", 88 fmt.fmt.pix.width, fmt.fmt.pix.height); 89 90 CLEAR(req); 91 req.count = 2; 92 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 93 req.memory = V4L2_MEMORY_MMAP; 94 xioctl(fd, VIDIOC_REQBUFS, &req); 95 96 buffers = calloc(req.count, sizeof(*buffers)); 97 for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { 98 CLEAR(buf); 99 100 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 101 buf.memory = V4L2_MEMORY_MMAP; 102 buf.index = n_buffers; 103 104 xioctl(fd, VIDIOC_QUERYBUF, &buf); 105 106 buffers[n_buffers].length = buf.length; 107 buffers[n_buffers].start = v4l2_mmap(NULL, buf.length, 108 PROT_READ | PROT_WRITE, MAP_SHARED, 109 fd, buf.m.offset); 110 111 if (MAP_FAILED == buffers[n_buffers].start) { 112 perror("mmap"); 113 exit(EXIT_FAILURE); 114 } 115 } 116 117 for (i = 0; i < n_buffers; ++i) { 118 CLEAR(buf); 119 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 120 buf.memory = V4L2_MEMORY_MMAP; 121 buf.index = i; 122 xioctl(fd, VIDIOC_QBUF, &buf); 123 } 124 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 125 126 xioctl(fd, VIDIOC_STREAMON, &type); 127 for (i = 0; i < 20; i++) { 128 do { 129 FD_ZERO(&fds); 130 FD_SET(fd, &fds); 131 132 /* Timeout. */ 133 tv.tv_sec = 2; 134 tv.tv_usec = 0; 135 136 r = select(fd + 1, &fds, NULL, NULL, &tv); 137 } while ((r == -1 && (errno == EINTR))); 138 if (r == -1) { 139 perror("select"); 140 return errno; 141 } 142 143 CLEAR(buf); 144 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 145 buf.memory = V4L2_MEMORY_MMAP; 146 xioctl(fd, VIDIOC_DQBUF, &buf); 147 148 sprintf(out_name, "out%03d.ppm", i); 149 fout = fopen(out_name, "w"); 150 if (!fout) { 151 perror("Cannot open image"); 152 exit(EXIT_FAILURE); 153 } 154 fprintf(fout, "P6\n%d %d 255\n", 155 fmt.fmt.pix.width, fmt.fmt.pix.height); 156 fwrite(buffers[buf.index].start, buf.bytesused, 1, fout); 157 fclose(fout); 158 159 xioctl(fd, VIDIOC_QBUF, &buf); 160 } 161 162 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 163 xioctl(fd, VIDIOC_STREAMOFF, &type); 164 for (i = 0; i < n_buffers; ++i) 165 v4l2_munmap(buffers[i].start, buffers[i].length); 166 v4l2_close(fd); 167 168 return 0; 169 } 170