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