0001 .. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
0002
0003 file: media/v4l/v4l2grab.c
0004 ==========================
0005
0006 .. code-block:: c
0007
0008 /* V4L2 video picture grabber
0009 Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@kernel.org>
0010
0011 This program is free software; you can redistribute it and/or modify
0012 it under the terms of the GNU General Public License as published by
0013 the Free Software Foundation version 2 of the License.
0014
0015 This program is distributed in the hope that it will be useful,
0016 but WITHOUT ANY WARRANTY; without even the implied warranty of
0017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0018 GNU General Public License for more details.
0019 */
0020
0021 #include <stdio.h>
0022 #include <stdlib.h>
0023 #include <string.h>
0024 #include <fcntl.h>
0025 #include <errno.h>
0026 #include <sys/ioctl.h>
0027 #include <sys/types.h>
0028 #include <sys/time.h>
0029 #include <sys/mman.h>
0030 #include <linux/videodev2.h>
0031 #include "../libv4l/include/libv4l2.h"
0032
0033 #define CLEAR(x) memset(&(x), 0, sizeof(x))
0034
0035 struct buffer {
0036 void *start;
0037 size_t length;
0038 };
0039
0040 static void xioctl(int fh, int request, void *arg)
0041 {
0042 int r;
0043
0044 do {
0045 r = v4l2_ioctl(fh, request, arg);
0046 } while (r == -1 && ((errno == EINTR) || (errno == EAGAIN)));
0047
0048 if (r == -1) {
0049 fprintf(stderr, "error %d, %s\n", errno, strerror(errno));
0050 exit(EXIT_FAILURE);
0051 }
0052 }
0053
0054 int main(int argc, char **argv)
0055 {
0056 struct v4l2_format fmt;
0057 struct v4l2_buffer buf;
0058 struct v4l2_requestbuffers req;
0059 enum v4l2_buf_type type;
0060 fd_set fds;
0061 struct timeval tv;
0062 int r, fd = -1;
0063 unsigned int i, n_buffers;
0064 char *dev_name = "/dev/video0";
0065 char out_name[256];
0066 FILE *fout;
0067 struct buffer *buffers;
0068
0069 fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
0070 if (fd < 0) {
0071 perror("Cannot open device");
0072 exit(EXIT_FAILURE);
0073 }
0074
0075 CLEAR(fmt);
0076 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
0077 fmt.fmt.pix.width = 640;
0078 fmt.fmt.pix.height = 480;
0079 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
0080 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
0081 xioctl(fd, VIDIOC_S_FMT, &fmt);
0082 if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24) {
0083 printf("Libv4l didn't accept RGB24 format. Can't proceed.\n");
0084 exit(EXIT_FAILURE);
0085 }
0086 if ((fmt.fmt.pix.width != 640) || (fmt.fmt.pix.height != 480))
0087 printf("Warning: driver is sending image at %dx%d\n",
0088 fmt.fmt.pix.width, fmt.fmt.pix.height);
0089
0090 CLEAR(req);
0091 req.count = 2;
0092 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
0093 req.memory = V4L2_MEMORY_MMAP;
0094 xioctl(fd, VIDIOC_REQBUFS, &req);
0095
0096 buffers = calloc(req.count, sizeof(*buffers));
0097 for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
0098 CLEAR(buf);
0099
0100 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
0101 buf.memory = V4L2_MEMORY_MMAP;
0102 buf.index = n_buffers;
0103
0104 xioctl(fd, VIDIOC_QUERYBUF, &buf);
0105
0106 buffers[n_buffers].length = buf.length;
0107 buffers[n_buffers].start = v4l2_mmap(NULL, buf.length,
0108 PROT_READ | PROT_WRITE, MAP_SHARED,
0109 fd, buf.m.offset);
0110
0111 if (MAP_FAILED == buffers[n_buffers].start) {
0112 perror("mmap");
0113 exit(EXIT_FAILURE);
0114 }
0115 }
0116
0117 for (i = 0; i < n_buffers; ++i) {
0118 CLEAR(buf);
0119 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
0120 buf.memory = V4L2_MEMORY_MMAP;
0121 buf.index = i;
0122 xioctl(fd, VIDIOC_QBUF, &buf);
0123 }
0124 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
0125
0126 xioctl(fd, VIDIOC_STREAMON, &type);
0127 for (i = 0; i < 20; i++) {
0128 do {
0129 FD_ZERO(&fds);
0130 FD_SET(fd, &fds);
0131
0132 /* Timeout. */
0133 tv.tv_sec = 2;
0134 tv.tv_usec = 0;
0135
0136 r = select(fd + 1, &fds, NULL, NULL, &tv);
0137 } while ((r == -1 && (errno == EINTR)));
0138 if (r == -1) {
0139 perror("select");
0140 return errno;
0141 }
0142
0143 CLEAR(buf);
0144 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
0145 buf.memory = V4L2_MEMORY_MMAP;
0146 xioctl(fd, VIDIOC_DQBUF, &buf);
0147
0148 sprintf(out_name, "out%03d.ppm", i);
0149 fout = fopen(out_name, "w");
0150 if (!fout) {
0151 perror("Cannot open image");
0152 exit(EXIT_FAILURE);
0153 }
0154 fprintf(fout, "P6\n%d %d 255\n",
0155 fmt.fmt.pix.width, fmt.fmt.pix.height);
0156 fwrite(buffers[buf.index].start, buf.bytesused, 1, fout);
0157 fclose(fout);
0158
0159 xioctl(fd, VIDIOC_QBUF, &buf);
0160 }
0161
0162 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
0163 xioctl(fd, VIDIOC_STREAMOFF, &type);
0164 for (i = 0; i < n_buffers; ++i)
0165 v4l2_munmap(buffers[i].start, buffers[i].length);
0166 v4l2_close(fd);
0167
0168 return 0;
0169 }