Commit | Line | Data |
---|---|---|
5377d91f MH |
1 | .. -*- coding: utf-8; mode: rst -*- |
2 | ||
3 | file: media/v4l/v4l2grab.c | |
4 | ========================== | |
5 | ||
6 | .. code-block:: c | |
7 | ||
8 | /* V4L2 video picture grabber | |
9 | Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@infradead.org> | |
10 | ||
11 | This program is free software; you can redistribute it and/or modify | |
12 | it under the terms of the GNU General Public License as published by | |
13 | 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 of | |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | 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 { | |
0579e6e3 MCC |
36 | void *start; |
37 | size_t length; | |
5377d91f MH |
38 | }; |
39 | ||
40 | static void xioctl(int fh, int request, void *arg) | |
41 | { | |
0579e6e3 | 42 | int r; |
5377d91f | 43 | |
0579e6e3 MCC |
44 | do { |
45 | r = v4l2_ioctl(fh, request, arg); | |
46 | } while (r == -1 && ((errno == EINTR) || (errno == EAGAIN))); | |
5377d91f | 47 | |
0579e6e3 MCC |
48 | if (r == -1) { |
49 | fprintf(stderr, "error %d, %s\\n", errno, strerror(errno)); | |
50 | exit(EXIT_FAILURE); | |
51 | } | |
5377d91f MH |
52 | } |
53 | ||
54 | int main(int argc, char **argv) | |
55 | { | |
0579e6e3 MCC |
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"; | |
8968da9b | 65 | char out_name[256]; |
0579e6e3 MCC |
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; | |
5377d91f | 169 | } |