Commit | Line | Data |
---|---|---|
8e080c2e MCC |
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> |