Commit | Line | Data |
---|---|---|
5377d91f MH |
1 | .. -*- coding: utf-8; mode: rst -*- |
2 | ||
3 | file: media/v4l/capture.c | |
4 | ========================= | |
5 | ||
6 | .. code-block:: c | |
7 | ||
8 | /* | |
9 | * V4L2 video capture example | |
10 | * | |
11 | * This program can be used and distributed without restrictions. | |
12 | * | |
13 | * This program is provided with the V4L2 API | |
14 | * see https://linuxtv.org/docs.php for more information | |
15 | */ | |
16 | ||
17 | #include <stdio.h> | |
18 | #include <stdlib.h> | |
19 | #include <string.h> | |
20 | #include <assert.h> | |
21 | ||
22 | #include <getopt.h> /* getopt_long() */ | |
23 | ||
24 | #include <fcntl.h> /* low-level i/o */ | |
25 | #include <unistd.h> | |
26 | #include <errno.h> | |
27 | #include <sys/stat.h> | |
28 | #include <sys/types.h> | |
29 | #include <sys/time.h> | |
30 | #include <sys/mman.h> | |
31 | #include <sys/ioctl.h> | |
32 | ||
33 | #include <linux/videodev2.h> | |
34 | ||
35 | #define CLEAR(x) memset(&(x), 0, sizeof(x)) | |
36 | ||
37 | enum io_method { | |
0579e6e3 MCC |
38 | IO_METHOD_READ, |
39 | IO_METHOD_MMAP, | |
40 | IO_METHOD_USERPTR, | |
5377d91f MH |
41 | }; |
42 | ||
43 | struct buffer { | |
0579e6e3 MCC |
44 | void *start; |
45 | size_t length; | |
5377d91f MH |
46 | }; |
47 | ||
48 | static char *dev_name; | |
49 | static enum io_method io = IO_METHOD_MMAP; | |
50 | static int fd = -1; | |
51 | struct buffer *buffers; | |
52 | static unsigned int n_buffers; | |
53 | static int out_buf; | |
54 | static int force_format; | |
55 | static int frame_count = 70; | |
56 | ||
57 | static void errno_exit(const char *s) | |
58 | { | |
0579e6e3 MCC |
59 | fprintf(stderr, "%s error %d, %s\\n", s, errno, strerror(errno)); |
60 | exit(EXIT_FAILURE); | |
5377d91f MH |
61 | } |
62 | ||
63 | static int xioctl(int fh, int request, void *arg) | |
64 | { | |
0579e6e3 | 65 | int r; |
5377d91f | 66 | |
0579e6e3 MCC |
67 | do { |
68 | r = ioctl(fh, request, arg); | |
69 | } while (-1 == r && EINTR == errno); | |
5377d91f | 70 | |
0579e6e3 | 71 | return r; |
5377d91f MH |
72 | } |
73 | ||
74 | static void process_image(const void *p, int size) | |
75 | { | |
0579e6e3 MCC |
76 | if (out_buf) |
77 | fwrite(p, size, 1, stdout); | |
5377d91f | 78 | |
0579e6e3 MCC |
79 | fflush(stderr); |
80 | fprintf(stderr, "."); | |
81 | fflush(stdout); | |
5377d91f MH |
82 | } |
83 | ||
84 | static int read_frame(void) | |
85 | { | |
0579e6e3 MCC |
86 | struct v4l2_buffer buf; |
87 | unsigned int i; | |
5377d91f | 88 | |
0579e6e3 MCC |
89 | switch (io) { |
90 | case IO_METHOD_READ: | |
91 | if (-1 == read(fd, buffers[0].start, buffers[0].length)) { | |
92 | switch (errno) { | |
93 | case EAGAIN: | |
94 | return 0; | |
5377d91f | 95 | |
0579e6e3 MCC |
96 | case EIO: |
97 | /* Could ignore EIO, see spec. */ | |
5377d91f | 98 | |
0579e6e3 | 99 | /* fall through */ |
5377d91f | 100 | |
0579e6e3 MCC |
101 | default: |
102 | errno_exit("read"); | |
103 | } | |
104 | } | |
5377d91f | 105 | |
0579e6e3 MCC |
106 | process_image(buffers[0].start, buffers[0].length); |
107 | break; | |
5377d91f | 108 | |
0579e6e3 MCC |
109 | case IO_METHOD_MMAP: |
110 | CLEAR(buf); | |
5377d91f | 111 | |
0579e6e3 MCC |
112 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
113 | buf.memory = V4L2_MEMORY_MMAP; | |
5377d91f | 114 | |
0579e6e3 MCC |
115 | if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) { |
116 | switch (errno) { | |
117 | case EAGAIN: | |
118 | return 0; | |
5377d91f | 119 | |
0579e6e3 MCC |
120 | case EIO: |
121 | /* Could ignore EIO, see spec. */ | |
5377d91f | 122 | |
0579e6e3 | 123 | /* fall through */ |
5377d91f | 124 | |
0579e6e3 MCC |
125 | default: |
126 | errno_exit("VIDIOC_DQBUF"); | |
127 | } | |
128 | } | |
5377d91f | 129 | |
0579e6e3 | 130 | assert(buf.index < n_buffers); |
5377d91f | 131 | |
0579e6e3 | 132 | process_image(buffers[buf.index].start, buf.bytesused); |
5377d91f | 133 | |
0579e6e3 MCC |
134 | if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) |
135 | errno_exit("VIDIOC_QBUF"); | |
136 | break; | |
5377d91f | 137 | |
0579e6e3 MCC |
138 | case IO_METHOD_USERPTR: |
139 | CLEAR(buf); | |
5377d91f | 140 | |
0579e6e3 MCC |
141 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
142 | buf.memory = V4L2_MEMORY_USERPTR; | |
5377d91f | 143 | |
0579e6e3 MCC |
144 | if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) { |
145 | switch (errno) { | |
146 | case EAGAIN: | |
147 | return 0; | |
5377d91f | 148 | |
0579e6e3 MCC |
149 | case EIO: |
150 | /* Could ignore EIO, see spec. */ | |
5377d91f | 151 | |
0579e6e3 | 152 | /* fall through */ |
5377d91f | 153 | |
0579e6e3 MCC |
154 | default: |
155 | errno_exit("VIDIOC_DQBUF"); | |
156 | } | |
157 | } | |
5377d91f | 158 | |
0579e6e3 MCC |
159 | for (i = 0; i < n_buffers; ++i) |
160 | if (buf.m.userptr == (unsigned long)buffers[i].start | |
161 | && buf.length == buffers[i].length) | |
162 | break; | |
5377d91f | 163 | |
0579e6e3 | 164 | assert(i < n_buffers); |
5377d91f | 165 | |
0579e6e3 | 166 | process_image((void *)buf.m.userptr, buf.bytesused); |
5377d91f | 167 | |
0579e6e3 MCC |
168 | if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) |
169 | errno_exit("VIDIOC_QBUF"); | |
170 | break; | |
171 | } | |
5377d91f | 172 | |
0579e6e3 | 173 | return 1; |
5377d91f MH |
174 | } |
175 | ||
176 | static void mainloop(void) | |
177 | { | |
0579e6e3 | 178 | unsigned int count; |
5377d91f | 179 | |
0579e6e3 | 180 | count = frame_count; |
5377d91f | 181 | |
0579e6e3 MCC |
182 | while (count-- > 0) { |
183 | for (;;) { | |
184 | fd_set fds; | |
185 | struct timeval tv; | |
186 | int r; | |
5377d91f | 187 | |
0579e6e3 MCC |
188 | FD_ZERO(&fds); |
189 | FD_SET(fd, &fds); | |
5377d91f | 190 | |
0579e6e3 MCC |
191 | /* Timeout. */ |
192 | tv.tv_sec = 2; | |
193 | tv.tv_usec = 0; | |
5377d91f | 194 | |
0579e6e3 | 195 | r = select(fd + 1, &fds, NULL, NULL, &tv); |
5377d91f | 196 | |
0579e6e3 MCC |
197 | if (-1 == r) { |
198 | if (EINTR == errno) | |
199 | continue; | |
200 | errno_exit("select"); | |
201 | } | |
5377d91f | 202 | |
0579e6e3 MCC |
203 | if (0 == r) { |
204 | fprintf(stderr, "select timeout\\n"); | |
205 | exit(EXIT_FAILURE); | |
206 | } | |
5377d91f | 207 | |
0579e6e3 MCC |
208 | if (read_frame()) |
209 | break; | |
210 | /* EAGAIN - continue select loop. */ | |
211 | } | |
212 | } | |
5377d91f MH |
213 | } |
214 | ||
215 | static void stop_capturing(void) | |
216 | { | |
0579e6e3 MCC |
217 | enum v4l2_buf_type type; |
218 | ||
219 | switch (io) { | |
220 | case IO_METHOD_READ: | |
221 | /* Nothing to do. */ | |
222 | break; | |
223 | ||
224 | case IO_METHOD_MMAP: | |
225 | case IO_METHOD_USERPTR: | |
226 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
227 | if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type)) | |
228 | errno_exit("VIDIOC_STREAMOFF"); | |
229 | break; | |
230 | } | |
5377d91f MH |
231 | } |
232 | ||
233 | static void start_capturing(void) | |
234 | { | |
0579e6e3 MCC |
235 | unsigned int i; |
236 | enum v4l2_buf_type type; | |
237 | ||
238 | switch (io) { | |
239 | case IO_METHOD_READ: | |
240 | /* Nothing to do. */ | |
241 | break; | |
242 | ||
243 | case IO_METHOD_MMAP: | |
244 | for (i = 0; i < n_buffers; ++i) { | |
245 | struct v4l2_buffer buf; | |
246 | ||
247 | CLEAR(buf); | |
248 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
249 | buf.memory = V4L2_MEMORY_MMAP; | |
250 | buf.index = i; | |
251 | ||
252 | if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) | |
253 | errno_exit("VIDIOC_QBUF"); | |
254 | } | |
255 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
256 | if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) | |
257 | errno_exit("VIDIOC_STREAMON"); | |
258 | break; | |
259 | ||
260 | case IO_METHOD_USERPTR: | |
261 | for (i = 0; i < n_buffers; ++i) { | |
262 | struct v4l2_buffer buf; | |
263 | ||
264 | CLEAR(buf); | |
265 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
266 | buf.memory = V4L2_MEMORY_USERPTR; | |
267 | buf.index = i; | |
268 | buf.m.userptr = (unsigned long)buffers[i].start; | |
269 | buf.length = buffers[i].length; | |
270 | ||
271 | if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) | |
272 | errno_exit("VIDIOC_QBUF"); | |
273 | } | |
274 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
275 | if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) | |
276 | errno_exit("VIDIOC_STREAMON"); | |
277 | break; | |
278 | } | |
5377d91f MH |
279 | } |
280 | ||
281 | static void uninit_device(void) | |
282 | { | |
0579e6e3 MCC |
283 | unsigned int i; |
284 | ||
285 | switch (io) { | |
286 | case IO_METHOD_READ: | |
287 | free(buffers[0].start); | |
288 | break; | |
289 | ||
290 | case IO_METHOD_MMAP: | |
291 | for (i = 0; i < n_buffers; ++i) | |
292 | if (-1 == munmap(buffers[i].start, buffers[i].length)) | |
293 | errno_exit("munmap"); | |
294 | break; | |
295 | ||
296 | case IO_METHOD_USERPTR: | |
297 | for (i = 0; i < n_buffers; ++i) | |
298 | free(buffers[i].start); | |
299 | break; | |
300 | } | |
301 | ||
302 | free(buffers); | |
5377d91f MH |
303 | } |
304 | ||
305 | static void init_read(unsigned int buffer_size) | |
306 | { | |
0579e6e3 | 307 | buffers = calloc(1, sizeof(*buffers)); |
5377d91f | 308 | |
0579e6e3 MCC |
309 | if (!buffers) { |
310 | fprintf(stderr, "Out of memory\\n"); | |
311 | exit(EXIT_FAILURE); | |
312 | } | |
5377d91f | 313 | |
0579e6e3 MCC |
314 | buffers[0].length = buffer_size; |
315 | buffers[0].start = malloc(buffer_size); | |
5377d91f | 316 | |
0579e6e3 MCC |
317 | if (!buffers[0].start) { |
318 | fprintf(stderr, "Out of memory\\n"); | |
319 | exit(EXIT_FAILURE); | |
320 | } | |
5377d91f MH |
321 | } |
322 | ||
323 | static void init_mmap(void) | |
324 | { | |
0579e6e3 MCC |
325 | struct v4l2_requestbuffers req; |
326 | ||
327 | CLEAR(req); | |
328 | ||
329 | req.count = 4; | |
330 | req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
331 | req.memory = V4L2_MEMORY_MMAP; | |
332 | ||
333 | if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { | |
334 | if (EINVAL == errno) { | |
335 | fprintf(stderr, "%s does not support " | |
336 | "memory mappingn", dev_name); | |
337 | exit(EXIT_FAILURE); | |
338 | } else { | |
339 | errno_exit("VIDIOC_REQBUFS"); | |
340 | } | |
341 | } | |
342 | ||
343 | if (req.count < 2) { | |
344 | fprintf(stderr, "Insufficient buffer memory on %s\\n", | |
345 | dev_name); | |
346 | exit(EXIT_FAILURE); | |
347 | } | |
348 | ||
349 | buffers = calloc(req.count, sizeof(*buffers)); | |
350 | ||
351 | if (!buffers) { | |
352 | fprintf(stderr, "Out of memory\\n"); | |
353 | exit(EXIT_FAILURE); | |
354 | } | |
355 | ||
356 | for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { | |
357 | struct v4l2_buffer buf; | |
358 | ||
359 | CLEAR(buf); | |
360 | ||
361 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
362 | buf.memory = V4L2_MEMORY_MMAP; | |
363 | buf.index = n_buffers; | |
364 | ||
365 | if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf)) | |
366 | errno_exit("VIDIOC_QUERYBUF"); | |
367 | ||
368 | buffers[n_buffers].length = buf.length; | |
369 | buffers[n_buffers].start = | |
370 | mmap(NULL /* start anywhere */, | |
371 | buf.length, | |
372 | PROT_READ | PROT_WRITE /* required */, | |
373 | MAP_SHARED /* recommended */, | |
374 | fd, buf.m.offset); | |
375 | ||
376 | if (MAP_FAILED == buffers[n_buffers].start) | |
377 | errno_exit("mmap"); | |
378 | } | |
5377d91f MH |
379 | } |
380 | ||
381 | static void init_userp(unsigned int buffer_size) | |
382 | { | |
0579e6e3 MCC |
383 | struct v4l2_requestbuffers req; |
384 | ||
385 | CLEAR(req); | |
386 | ||
387 | req.count = 4; | |
388 | req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
389 | req.memory = V4L2_MEMORY_USERPTR; | |
390 | ||
391 | if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { | |
392 | if (EINVAL == errno) { | |
393 | fprintf(stderr, "%s does not support " | |
394 | "user pointer i/on", dev_name); | |
395 | exit(EXIT_FAILURE); | |
396 | } else { | |
397 | errno_exit("VIDIOC_REQBUFS"); | |
398 | } | |
399 | } | |
400 | ||
401 | buffers = calloc(4, sizeof(*buffers)); | |
402 | ||
403 | if (!buffers) { | |
404 | fprintf(stderr, "Out of memory\\n"); | |
405 | exit(EXIT_FAILURE); | |
406 | } | |
407 | ||
408 | for (n_buffers = 0; n_buffers < 4; ++n_buffers) { | |
409 | buffers[n_buffers].length = buffer_size; | |
410 | buffers[n_buffers].start = malloc(buffer_size); | |
411 | ||
412 | if (!buffers[n_buffers].start) { | |
413 | fprintf(stderr, "Out of memory\\n"); | |
414 | exit(EXIT_FAILURE); | |
415 | } | |
416 | } | |
5377d91f MH |
417 | } |
418 | ||
419 | static void init_device(void) | |
420 | { | |
0579e6e3 MCC |
421 | struct v4l2_capability cap; |
422 | struct v4l2_cropcap cropcap; | |
423 | struct v4l2_crop crop; | |
424 | struct v4l2_format fmt; | |
425 | unsigned int min; | |
426 | ||
427 | if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) { | |
428 | if (EINVAL == errno) { | |
429 | fprintf(stderr, "%s is no V4L2 device\\n", | |
430 | dev_name); | |
431 | exit(EXIT_FAILURE); | |
432 | } else { | |
433 | errno_exit("VIDIOC_QUERYCAP"); | |
434 | } | |
435 | } | |
436 | ||
437 | if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { | |
438 | fprintf(stderr, "%s is no video capture device\\n", | |
439 | dev_name); | |
440 | exit(EXIT_FAILURE); | |
441 | } | |
442 | ||
443 | switch (io) { | |
444 | case IO_METHOD_READ: | |
445 | if (!(cap.capabilities & V4L2_CAP_READWRITE)) { | |
446 | fprintf(stderr, "%s does not support read i/o\\n", | |
447 | dev_name); | |
448 | exit(EXIT_FAILURE); | |
449 | } | |
450 | break; | |
451 | ||
452 | case IO_METHOD_MMAP: | |
453 | case IO_METHOD_USERPTR: | |
454 | if (!(cap.capabilities & V4L2_CAP_STREAMING)) { | |
455 | fprintf(stderr, "%s does not support streaming i/o\\n", | |
456 | dev_name); | |
457 | exit(EXIT_FAILURE); | |
458 | } | |
459 | break; | |
460 | } | |
461 | ||
462 | ||
463 | /* Select video input, video standard and tune here. */ | |
464 | ||
465 | ||
466 | CLEAR(cropcap); | |
467 | ||
468 | cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
469 | ||
470 | if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) { | |
471 | crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
472 | crop.c = cropcap.defrect; /* reset to default */ | |
473 | ||
474 | if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) { | |
475 | switch (errno) { | |
476 | case EINVAL: | |
477 | /* Cropping not supported. */ | |
478 | break; | |
479 | default: | |
480 | /* Errors ignored. */ | |
481 | break; | |
482 | } | |
483 | } | |
484 | } else { | |
485 | /* Errors ignored. */ | |
486 | } | |
487 | ||
488 | ||
489 | CLEAR(fmt); | |
490 | ||
491 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
492 | if (force_format) { | |
493 | fmt.fmt.pix.width = 640; | |
494 | fmt.fmt.pix.height = 480; | |
495 | fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; | |
496 | fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; | |
497 | ||
498 | if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt)) | |
499 | errno_exit("VIDIOC_S_FMT"); | |
500 | ||
501 | /* Note VIDIOC_S_FMT may change width and height. */ | |
502 | } else { | |
503 | /* Preserve original settings as set by v4l2-ctl for example */ | |
504 | if (-1 == xioctl(fd, VIDIOC_G_FMT, &fmt)) | |
505 | errno_exit("VIDIOC_G_FMT"); | |
506 | } | |
507 | ||
508 | /* Buggy driver paranoia. */ | |
509 | min = fmt.fmt.pix.width * 2; | |
510 | if (fmt.fmt.pix.bytesperline < min) | |
511 | fmt.fmt.pix.bytesperline = min; | |
512 | min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; | |
513 | if (fmt.fmt.pix.sizeimage < min) | |
514 | fmt.fmt.pix.sizeimage = min; | |
515 | ||
516 | switch (io) { | |
517 | case IO_METHOD_READ: | |
518 | init_read(fmt.fmt.pix.sizeimage); | |
519 | break; | |
520 | ||
521 | case IO_METHOD_MMAP: | |
522 | init_mmap(); | |
523 | break; | |
524 | ||
525 | case IO_METHOD_USERPTR: | |
526 | init_userp(fmt.fmt.pix.sizeimage); | |
527 | break; | |
528 | } | |
5377d91f MH |
529 | } |
530 | ||
531 | static void close_device(void) | |
532 | { | |
0579e6e3 MCC |
533 | if (-1 == close(fd)) |
534 | errno_exit("close"); | |
5377d91f | 535 | |
0579e6e3 | 536 | fd = -1; |
5377d91f MH |
537 | } |
538 | ||
539 | static void open_device(void) | |
540 | { | |
0579e6e3 MCC |
541 | struct stat st; |
542 | ||
543 | if (-1 == stat(dev_name, &st)) { | |
544 | fprintf(stderr, "Cannot identify '%s': %d, %s\\n", | |
545 | dev_name, errno, strerror(errno)); | |
546 | exit(EXIT_FAILURE); | |
547 | } | |
548 | ||
549 | if (!S_ISCHR(st.st_mode)) { | |
550 | fprintf(stderr, "%s is no devicen", dev_name); | |
551 | exit(EXIT_FAILURE); | |
552 | } | |
553 | ||
554 | fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0); | |
555 | ||
556 | if (-1 == fd) { | |
557 | fprintf(stderr, "Cannot open '%s': %d, %s\\n", | |
558 | dev_name, errno, strerror(errno)); | |
559 | exit(EXIT_FAILURE); | |
560 | } | |
5377d91f MH |
561 | } |
562 | ||
563 | static void usage(FILE *fp, int argc, char **argv) | |
564 | { | |
0579e6e3 MCC |
565 | fprintf(fp, |
566 | "Usage: %s [options]\\n\\n" | |
567 | "Version 1.3\\n" | |
568 | "Options:\\n" | |
569 | "-d | --device name Video device name [%s]n" | |
570 | "-h | --help Print this messagen" | |
571 | "-m | --mmap Use memory mapped buffers [default]n" | |
572 | "-r | --read Use read() callsn" | |
573 | "-u | --userp Use application allocated buffersn" | |
574 | "-o | --output Outputs stream to stdoutn" | |
575 | "-f | --format Force format to 640x480 YUYVn" | |
576 | "-c | --count Number of frames to grab [%i]n" | |
577 | "", | |
578 | argv[0], dev_name, frame_count); | |
5377d91f MH |
579 | } |
580 | ||
581 | static const char short_options[] = "d:hmruofc:"; | |
582 | ||
583 | static const struct option | |
584 | long_options[] = { | |
0579e6e3 MCC |
585 | { "device", required_argument, NULL, 'd' }, |
586 | { "help", no_argument, NULL, 'h' }, | |
587 | { "mmap", no_argument, NULL, 'm' }, | |
588 | { "read", no_argument, NULL, 'r' }, | |
589 | { "userp", no_argument, NULL, 'u' }, | |
590 | { "output", no_argument, NULL, 'o' }, | |
591 | { "format", no_argument, NULL, 'f' }, | |
592 | { "count", required_argument, NULL, 'c' }, | |
593 | { 0, 0, 0, 0 } | |
5377d91f MH |
594 | }; |
595 | ||
596 | int main(int argc, char **argv) | |
597 | { | |
0579e6e3 MCC |
598 | dev_name = "/dev/video0"; |
599 | ||
600 | for (;;) { | |
601 | int idx; | |
602 | int c; | |
603 | ||
604 | c = getopt_long(argc, argv, | |
605 | short_options, long_options, &idx); | |
606 | ||
607 | if (-1 == c) | |
608 | break; | |
609 | ||
610 | switch (c) { | |
611 | case 0: /* getopt_long() flag */ | |
612 | break; | |
613 | ||
614 | case 'd': | |
615 | dev_name = optarg; | |
616 | break; | |
617 | ||
618 | case 'h': | |
619 | usage(stdout, argc, argv); | |
620 | exit(EXIT_SUCCESS); | |
621 | ||
622 | case 'm': | |
623 | io = IO_METHOD_MMAP; | |
624 | break; | |
625 | ||
626 | case 'r': | |
627 | io = IO_METHOD_READ; | |
628 | break; | |
629 | ||
630 | case 'u': | |
631 | io = IO_METHOD_USERPTR; | |
632 | break; | |
633 | ||
634 | case 'o': | |
635 | out_buf++; | |
636 | break; | |
637 | ||
638 | case 'f': | |
639 | force_format++; | |
640 | break; | |
641 | ||
642 | case 'c': | |
643 | errno = 0; | |
644 | frame_count = strtol(optarg, NULL, 0); | |
645 | if (errno) | |
646 | errno_exit(optarg); | |
647 | break; | |
648 | ||
649 | default: | |
650 | usage(stderr, argc, argv); | |
651 | exit(EXIT_FAILURE); | |
652 | } | |
653 | } | |
654 | ||
655 | open_device(); | |
656 | init_device(); | |
657 | start_capturing(); | |
658 | mainloop(); | |
659 | stop_capturing(); | |
660 | uninit_device(); | |
661 | close_device(); | |
662 | fprintf(stderr, "\\n"); | |
663 | return 0; | |
5377d91f | 664 | } |