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