#ifndef VIDEODEVICE_H |
02 | #define VIDEODEVICE_H |
03 | |
04 | #include <string.h> |
05 | #include <stdlib.h> |
06 | #include <errno.h> |
07 | #include <fcntl.h> |
08 | |
09 | |
10 | #include <sys/ioctl.h> |
11 | #include <sys/mman.h> |
12 | |
13 | #include <asm/types.h> |
14 | #include <linux/videodev2.h> |
15 | |
16 | #include <QString> |
17 | #include <QObject> |
18 | |
19 | #define CLEAR(x) memset(&(x), 0, sizeof(x)) |
20 | |
21 | class VideoDevice : public QObject |
22 | { |
23 | Q_OBJECT |
24 | public : |
25 | VideoDevice(QString dev_name); |
26 | //VideoDevice(); |
27 | int open_device(); |
28 | int close_device(); |
29 | int init_device(); |
30 | int start_capturing(); |
31 | int stop_capturing(); |
32 | int uninit_device(); |
33 | int get_frame( void **, size_t *); |
34 | int unget_frame(); |
35 | |
36 | private : |
37 | int init_mmap(); |
38 | |
39 | struct buffer |
40 | { |
41 | void * start; |
42 | size_t length; |
43 | }; |
44 | QString dev_name; |
45 | int fd; |
46 | buffer* buffers; |
47 | unsigned int n_buffers; |
48 | int index; |
49 | |
50 | signals: |
51 | void display_error(QString); |
52 | |
53 | }; |
54 | |
|
|
#include "videodevice.h" |
002 | |
003 | VideoDevice::VideoDevice(QString dev_name) |
004 | { |
005 | this ->dev_name = dev_name; |
006 | this ->fd = -1; |
007 | this ->buffers = NULL; |
008 | this ->n_buffers = 0; |
009 | this ->index = -1; |
010 | |
011 | } |
012 | |
013 | int VideoDevice::open_device() |
014 | { |
015 | fd = open(dev_name.toStdString().c_str(), O_RDWR /*|O_NONBLOCK*/ , 0); |
016 | // fd = open(dev_name.toStdString().c_str(), O_RDWR|O_NONBLOCK, 0); |
017 | |
018 | if (-1 == fd) |
019 | { |
020 | emit display_error(tr( "open: %1" ).arg(QString( strerror ( errno )))); |
021 | return -1; |
022 | } |
023 | return 0; |
024 | } |
025 | |
026 | int VideoDevice::close_device() |
027 | { |
028 | if (-1 == close(fd)) |
029 | { |
030 | emit display_error(tr( "close: %1" ).arg(QString( strerror ( errno )))); |
031 | return -1; |
032 | } |
033 | return 0; |
034 | } |
035 | |
036 | int VideoDevice::init_device() |
037 | { |
038 | v4l2_capability cap; |
039 | v4l2_cropcap cropcap; |
040 | v4l2_crop crop; |
041 | v4l2_format fmt; |
042 | |
043 | if (-1 == ioctl(fd, VIDIOC_QUERYCAP, &cap)) |
044 | { |
045 | if (EINVAL == errno ) |
046 | { |
047 | emit display_error(tr( "%1 is no V4l2 device" ).arg(dev_name)); |
048 | } |
049 | else |
050 | { |
051 | emit display_error(tr( "VIDIOC_QUERYCAP: %1" ).arg(QString( strerror ( errno )))); |
052 | } |
053 | return -1; |
054 | } |
055 | |
056 | if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) |
057 | { |
058 | emit display_error(tr( "%1 is no video capture device" ).arg(dev_name)); |
059 | return -1; |
060 | } |
061 | |
062 | if (!(cap.capabilities & V4L2_CAP_STREAMING)) |
063 | { |
064 | emit display_error(tr( "%1 does not support streaming i/o" ).arg(dev_name)); |
065 | return -1; |
066 | } |
067 | |
068 | CLEAR(cropcap); |
069 | |
070 | cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
071 | |
072 | if (0 == ioctl(fd, VIDIOC_CROPCAP, &cropcap)) |
073 | { |
074 | CLEAR(crop); |
075 | crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
076 | crop.c = cropcap.defrect; |
077 | |
078 | if (-1 == ioctl(fd, VIDIOC_S_CROP, &crop)) |
079 | { |
080 | if (EINVAL == errno ) |
081 | { |
082 | // emit display_error(tr("VIDIOC_S_CROP not supported")); |
083 | } |
084 | else |
085 | { |
086 | emit display_error(tr( "VIDIOC_S_CROP: %1" ).arg(QString( strerror ( errno )))); |
087 | return -1; |
088 | } |
089 | } |
090 | } |
091 | else |
092 | { |
093 | emit display_error(tr( "VIDIOC_CROPCAP: %1" ).arg(QString( strerror ( errno )))); |
094 | return -1; |
095 | } |
096 | |
097 | CLEAR(fmt); |
098 | |
099 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
100 | fmt.fmt.pix.width = 640; |
101 | fmt.fmt.pix.height = 480; |
102 | fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; |
103 | fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; |
104 | |
105 | if (-1 == ioctl(fd, VIDIOC_S_FMT, &fmt)) |
106 | { |
107 | emit display_error(tr( "VIDIOC_S_FMT" ).arg(QString( strerror ( errno )))); |
108 | return -1; |
109 | } |
110 | |
111 | if (-1 == init_mmap()) |
112 | { |
113 | return -1; |
114 | } |
115 | |
116 | return 0; |
117 | } |
118 | |
119 | int VideoDevice::init_mmap() |
120 | { |
121 | v4l2_requestbuffers req; |
122 | CLEAR(req); |
123 | |
124 | req.count = 4; |
125 | req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
126 | req.memory = V4L2_MEMORY_MMAP; |
127 | |
128 | if (-1 == ioctl(fd, VIDIOC_REQBUFS, &req)) |
129 | { |
130 | if (EINVAL == errno ) |
131 | { |
132 | emit display_error(tr( "%1 does not support memory mapping" ).arg(dev_name)); |
133 | return -1; |
134 | } |
135 | else |
136 | { |
137 | emit display_error(tr( "VIDIOC_REQBUFS %1" ).arg(QString( strerror ( errno )))); |
138 | return -1; |
139 | } |
140 | } |
141 | |
142 | if (req.count < 2) |
143 | { |
144 | emit display_error(tr( "Insufficient buffer memory on %1" ).arg(dev_name)); |
145 | return -1; |
146 | } |
147 | |
148 | buffers = (buffer*) calloc (req.count, sizeof (*buffers)); |
149 | |
150 | if (!buffers) |
151 | { |
152 | emit display_error(tr( "out of memory" )); |
153 | return -1; |
154 | } |
155 | |
156 | for (n_buffers = 0; n_buffers < req.count; ++n_buffers) |
157 | { |
158 | v4l2_buffer buf; |
159 | CLEAR(buf); |
160 | |
161 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
162 | buf.memory = V4L2_MEMORY_MMAP; |
163 | buf.index = n_buffers; |
164 | |
165 | if (-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf)) |
166 | { |
167 | emit display_error(tr( "VIDIOC_QUERYBUF: %1" ).arg(QString( strerror ( errno )))); |
168 | return -1; |
169 | } |
170 | |
171 | buffers[n_buffers].length = buf.length; |
172 | buffers[n_buffers].start = |
173 | mmap(NULL, // start anywhere |
174 | buf.length, |
175 | PROT_READ | PROT_WRITE, |
176 | MAP_SHARED, |
177 | fd, buf.m.offset); |
178 | |
179 | if (MAP_FAILED == buffers[n_buffers].start) |
180 | { |
181 | emit display_error(tr( "mmap %1" ).arg(QString( strerror ( errno )))); |
182 | return -1; |
183 | } |
184 | } |
185 | return 0; |
186 | |
187 | } |
188 | |
189 | int VideoDevice::start_capturing() |
190 | { |
191 | unsigned int i; |
192 | for (i = 0; i < n_buffers; ++i) |
193 | { |
194 | v4l2_buffer buf; |
195 | CLEAR(buf); |
196 | |
197 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
198 | buf.memory =V4L2_MEMORY_MMAP; |
199 | buf.index = i; |
200 | // fprintf(stderr, "n_buffers: %d\n", i); |
201 | |
202 | if (-1 == ioctl(fd, VIDIOC_QBUF, &buf)) |
203 | { |
204 | emit display_error(tr( "VIDIOC_QBUF: %1" ).arg(QString( strerror ( errno )))); |
205 | return -1; |
206 | } |
207 | } |
208 | |
209 | v4l2_buf_type type; |
210 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
211 | |
212 | if (-1 == ioctl(fd, VIDIOC_STREAMON, &type)) |
213 | { |
214 | emit display_error(tr( "VIDIOC_STREAMON: %1" ).arg(QString( strerror ( errno )))); |
215 | return -1; |
216 | } |
217 | return 0; |
218 | } |
219 | |
220 | int VideoDevice::stop_capturing() |
221 | { |
222 | v4l2_buf_type type; |
223 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
224 | |
225 | if (-1 == ioctl(fd, VIDIOC_STREAMOFF, &type)) |
226 | { |
227 | emit display_error(tr( "VIDIOC_STREAMOFF: %1" ).arg(QString( strerror ( errno )))); |
228 | return -1; |
229 | } |
230 | return 0; |
231 | } |
232 | |
233 | int VideoDevice::uninit_device() |
234 | { |
235 | unsigned int i; |
236 | for (i = 0; i < n_buffers; ++i) |
237 | { |
238 | if (-1 == munmap(buffers[i].start, buffers[i].length)) |
239 | { |
240 | emit display_error(tr( "munmap: %1" ).arg(QString( strerror ( errno )))); |
241 | return -1; |
242 | } |
243 | |
244 | } |
245 | free (buffers); |
246 | return 0; |
247 | } |
248 | |
249 | int VideoDevice::get_frame( void **frame_buf, size_t * len) |
250 | { |
251 | v4l2_buffer queue_buf; |
252 | CLEAR(queue_buf); |
253 | |
254 | queue_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
255 | queue_buf.memory = V4L2_MEMORY_MMAP; |
256 | |
257 | if (-1 == ioctl(fd, VIDIOC_DQBUF, &queue_buf)) |
258 | { |
259 | switch ( errno ) |
260 | { |
261 | case EAGAIN: |
262 | // perror("dqbuf"); |
263 | return -1; |
264 | case EIO: |
265 | return -1 ; |
266 | default : |
267 | emit display_error(tr( "VIDIOC_DQBUF: %1" ).arg(QString( strerror ( errno )))); |
268 | return -1; |
269 | } |
270 | } |
271 | |
272 | *frame_buf = buffers[queue_buf.index].start; |
273 | *len = buffers[queue_buf.index].length; |
274 | index = queue_buf.index; |
275 | |
276 | return 0; |
277 | |
278 | } |
279 | |
280 | int VideoDevice::unget_frame() |
281 | { |
282 | if (index != -1) |
283 | { |
284 | v4l2_buffer queue_buf; |
285 | CLEAR(queue_buf); |
286 | |
287 | queue_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
288 | queue_buf.memory = V4L2_MEMORY_MMAP; |
289 | queue_buf.index = index; |
290 | |
291 | if (-1 == ioctl(fd, VIDIOC_QBUF, &queue_buf)) |
292 | { |
293 | emit display_error(tr( "VIDIOC_QBUF: %1" ).arg(QString( strerror ( errno )))); |
294 | return -1; |
295 | } |
296 | return 0; |
297 | } |
298 | return -1; |
}
http://www.oschina.net/code/snippet_124925_3789