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