170 lines · plain
1.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later2 3file: media/v4l/v4l2grab.c4==========================5 6.. code-block:: c7 8 /* V4L2 video picture grabber9 Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@kernel.org>10 11 This program is free software; you can redistribute it and/or modify12 it under the terms of the GNU General Public License as published by13 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 of17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the18 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