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