162306a36Sopenharmony_ci.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later 262306a36Sopenharmony_ci 362306a36Sopenharmony_cifile: media/v4l/v4l2grab.c 462306a36Sopenharmony_ci========================== 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci.. code-block:: c 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci /* V4L2 video picture grabber 962306a36Sopenharmony_ci Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@kernel.org> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci This program is free software; you can redistribute it and/or modify 1262306a36Sopenharmony_ci it under the terms of the GNU General Public License as published by 1362306a36Sopenharmony_ci the Free Software Foundation version 2 of the License. 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci This program is distributed in the hope that it will be useful, 1662306a36Sopenharmony_ci but WITHOUT ANY WARRANTY; without even the implied warranty of 1762306a36Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1862306a36Sopenharmony_ci GNU General Public License for more details. 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci #include <stdio.h> 2262306a36Sopenharmony_ci #include <stdlib.h> 2362306a36Sopenharmony_ci #include <string.h> 2462306a36Sopenharmony_ci #include <fcntl.h> 2562306a36Sopenharmony_ci #include <errno.h> 2662306a36Sopenharmony_ci #include <sys/ioctl.h> 2762306a36Sopenharmony_ci #include <sys/types.h> 2862306a36Sopenharmony_ci #include <sys/time.h> 2962306a36Sopenharmony_ci #include <sys/mman.h> 3062306a36Sopenharmony_ci #include <linux/videodev2.h> 3162306a36Sopenharmony_ci #include "../libv4l/include/libv4l2.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci #define CLEAR(x) memset(&(x), 0, sizeof(x)) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci struct buffer { 3662306a36Sopenharmony_ci void *start; 3762306a36Sopenharmony_ci size_t length; 3862306a36Sopenharmony_ci }; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci static void xioctl(int fh, int request, void *arg) 4162306a36Sopenharmony_ci { 4262306a36Sopenharmony_ci int r; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci do { 4562306a36Sopenharmony_ci r = v4l2_ioctl(fh, request, arg); 4662306a36Sopenharmony_ci } while (r == -1 && ((errno == EINTR) || (errno == EAGAIN))); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (r == -1) { 4962306a36Sopenharmony_ci fprintf(stderr, "error %d, %s\n", errno, strerror(errno)); 5062306a36Sopenharmony_ci exit(EXIT_FAILURE); 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci int main(int argc, char **argv) 5562306a36Sopenharmony_ci { 5662306a36Sopenharmony_ci struct v4l2_format fmt; 5762306a36Sopenharmony_ci struct v4l2_buffer buf; 5862306a36Sopenharmony_ci struct v4l2_requestbuffers req; 5962306a36Sopenharmony_ci enum v4l2_buf_type type; 6062306a36Sopenharmony_ci fd_set fds; 6162306a36Sopenharmony_ci struct timeval tv; 6262306a36Sopenharmony_ci int r, fd = -1; 6362306a36Sopenharmony_ci unsigned int i, n_buffers; 6462306a36Sopenharmony_ci char *dev_name = "/dev/video0"; 6562306a36Sopenharmony_ci char out_name[256]; 6662306a36Sopenharmony_ci FILE *fout; 6762306a36Sopenharmony_ci struct buffer *buffers; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0); 7062306a36Sopenharmony_ci if (fd < 0) { 7162306a36Sopenharmony_ci perror("Cannot open device"); 7262306a36Sopenharmony_ci exit(EXIT_FAILURE); 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci CLEAR(fmt); 7662306a36Sopenharmony_ci fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 7762306a36Sopenharmony_ci fmt.fmt.pix.width = 640; 7862306a36Sopenharmony_ci fmt.fmt.pix.height = 480; 7962306a36Sopenharmony_ci fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; 8062306a36Sopenharmony_ci fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; 8162306a36Sopenharmony_ci xioctl(fd, VIDIOC_S_FMT, &fmt); 8262306a36Sopenharmony_ci if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24) { 8362306a36Sopenharmony_ci printf("Libv4l didn't accept RGB24 format. Can't proceed.\n"); 8462306a36Sopenharmony_ci exit(EXIT_FAILURE); 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci if ((fmt.fmt.pix.width != 640) || (fmt.fmt.pix.height != 480)) 8762306a36Sopenharmony_ci printf("Warning: driver is sending image at %dx%d\n", 8862306a36Sopenharmony_ci fmt.fmt.pix.width, fmt.fmt.pix.height); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci CLEAR(req); 9162306a36Sopenharmony_ci req.count = 2; 9262306a36Sopenharmony_ci req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 9362306a36Sopenharmony_ci req.memory = V4L2_MEMORY_MMAP; 9462306a36Sopenharmony_ci xioctl(fd, VIDIOC_REQBUFS, &req); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci buffers = calloc(req.count, sizeof(*buffers)); 9762306a36Sopenharmony_ci for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { 9862306a36Sopenharmony_ci CLEAR(buf); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 10162306a36Sopenharmony_ci buf.memory = V4L2_MEMORY_MMAP; 10262306a36Sopenharmony_ci buf.index = n_buffers; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci xioctl(fd, VIDIOC_QUERYBUF, &buf); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci buffers[n_buffers].length = buf.length; 10762306a36Sopenharmony_ci buffers[n_buffers].start = v4l2_mmap(NULL, buf.length, 10862306a36Sopenharmony_ci PROT_READ | PROT_WRITE, MAP_SHARED, 10962306a36Sopenharmony_ci fd, buf.m.offset); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (MAP_FAILED == buffers[n_buffers].start) { 11262306a36Sopenharmony_ci perror("mmap"); 11362306a36Sopenharmony_ci exit(EXIT_FAILURE); 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci for (i = 0; i < n_buffers; ++i) { 11862306a36Sopenharmony_ci CLEAR(buf); 11962306a36Sopenharmony_ci buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 12062306a36Sopenharmony_ci buf.memory = V4L2_MEMORY_MMAP; 12162306a36Sopenharmony_ci buf.index = i; 12262306a36Sopenharmony_ci xioctl(fd, VIDIOC_QBUF, &buf); 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci xioctl(fd, VIDIOC_STREAMON, &type); 12762306a36Sopenharmony_ci for (i = 0; i < 20; i++) { 12862306a36Sopenharmony_ci do { 12962306a36Sopenharmony_ci FD_ZERO(&fds); 13062306a36Sopenharmony_ci FD_SET(fd, &fds); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* Timeout. */ 13362306a36Sopenharmony_ci tv.tv_sec = 2; 13462306a36Sopenharmony_ci tv.tv_usec = 0; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci r = select(fd + 1, &fds, NULL, NULL, &tv); 13762306a36Sopenharmony_ci } while ((r == -1 && (errno == EINTR))); 13862306a36Sopenharmony_ci if (r == -1) { 13962306a36Sopenharmony_ci perror("select"); 14062306a36Sopenharmony_ci return errno; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci CLEAR(buf); 14462306a36Sopenharmony_ci buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 14562306a36Sopenharmony_ci buf.memory = V4L2_MEMORY_MMAP; 14662306a36Sopenharmony_ci xioctl(fd, VIDIOC_DQBUF, &buf); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci sprintf(out_name, "out%03d.ppm", i); 14962306a36Sopenharmony_ci fout = fopen(out_name, "w"); 15062306a36Sopenharmony_ci if (!fout) { 15162306a36Sopenharmony_ci perror("Cannot open image"); 15262306a36Sopenharmony_ci exit(EXIT_FAILURE); 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci fprintf(fout, "P6\n%d %d 255\n", 15562306a36Sopenharmony_ci fmt.fmt.pix.width, fmt.fmt.pix.height); 15662306a36Sopenharmony_ci fwrite(buffers[buf.index].start, buf.bytesused, 1, fout); 15762306a36Sopenharmony_ci fclose(fout); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci xioctl(fd, VIDIOC_QBUF, &buf); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 16362306a36Sopenharmony_ci xioctl(fd, VIDIOC_STREAMOFF, &type); 16462306a36Sopenharmony_ci for (i = 0; i < n_buffers; ++i) 16562306a36Sopenharmony_ci v4l2_munmap(buffers[i].start, buffers[i].length); 16662306a36Sopenharmony_ci v4l2_close(fd); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return 0; 16962306a36Sopenharmony_ci } 170