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