3 * V4L2 video capture example
5 * This program can be used and distributed without restrictions.
7 * This program is provided with the V4L2 API
8 * see http://linuxtv.org/docs.php for more information
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <assert.h>
16 #include <getopt.h> /* getopt_long() */
18 #include <fcntl.h> /* low-level i/o */
19 #include <unistd.h>
20 #include <errno.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #include <sys/mman.h>
25 #include <sys/ioctl.h>
27 #include <linux/videodev2.h>
29 #define CLEAR(x) memset(&(x), 0, sizeof(x))
42 static char *dev_name;
43 static enum io_method io = IO_METHOD_MMAP;
45 struct buffer *buffers;
46 static unsigned int n_buffers;
48 static int force_format;
49 static int frame_count = 70;
51 static void errno_exit(const char *s)
53 fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno));
57 static int xioctl(int fh, int request, void *arg)
62 r = ioctl(fh, request, arg);
63 } while (-1 == r && EINTR == errno);
68 static void process_image(const void *p, int size)
71 fwrite(p, size, 1, stdout);
78 static int read_frame(void)
80 struct <link linkend="v4l2-buffer">v4l2_buffer</link> buf;
85 if (-1 == read(fd, buffers[0].start, buffers[0].length)) {
91 /* Could ignore EIO, see spec. */
100 process_image(buffers[0].start, buffers[0].length);
106 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
107 buf.memory = V4L2_MEMORY_MMAP;
109 if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
115 /* Could ignore EIO, see spec. */
120 errno_exit("VIDIOC_DQBUF");
124 assert(buf.index < n_buffers);
126 process_image(buffers[buf.index].start, buf.bytesused);
128 if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
129 errno_exit("VIDIOC_QBUF");
132 case IO_METHOD_USERPTR:
135 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
136 buf.memory = V4L2_MEMORY_USERPTR;
138 if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
144 /* Could ignore EIO, see spec. */
149 errno_exit("VIDIOC_DQBUF");
153 for (i = 0; i < n_buffers; ++i)
154 if (buf.m.userptr == (unsigned long)buffers[i].start
155 && buf.length == buffers[i].length)
158 assert(i < n_buffers);
160 process_image((void *)buf.m.userptr, buf.bytesused);
162 if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
163 errno_exit("VIDIOC_QBUF");
170 static void mainloop(void)
176 while (count-- > 0) {
183 FD_SET(fd, &fds);
189 r = select(fd + 1, &fds, NULL, NULL, &tv);
194 errno_exit("select");
198 fprintf(stderr, "select timeout\n");
204 /* EAGAIN - continue select loop. */
209 static void stop_capturing(void)
211 enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> type;
219 case IO_METHOD_USERPTR:
220 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
221 if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type))
222 errno_exit("VIDIOC_STREAMOFF");
227 static void start_capturing(void)
230 enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> type;
238 for (i = 0; i < n_buffers; ++i) {
239 struct <link linkend="v4l2-buffer">v4l2_buffer</link> buf;
242 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
243 buf.memory = V4L2_MEMORY_MMAP;
246 if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
247 errno_exit("VIDIOC_QBUF");
249 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
250 if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
251 errno_exit("VIDIOC_STREAMON");
254 case IO_METHOD_USERPTR:
255 for (i = 0; i < n_buffers; ++i) {
256 struct <link linkend="v4l2-buffer">v4l2_buffer</link> buf;
259 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
260 buf.memory = V4L2_MEMORY_USERPTR;
262 buf.m.userptr = (unsigned long)buffers[i].start;
263 buf.length = buffers[i].length;
265 if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
266 errno_exit("VIDIOC_QBUF");
268 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
269 if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
270 errno_exit("VIDIOC_STREAMON");
275 static void uninit_device(void)
281 free(buffers[0].start);
285 for (i = 0; i < n_buffers; ++i)
286 if (-1 == munmap(buffers[i].start, buffers[i].length))
287 errno_exit("munmap");
290 case IO_METHOD_USERPTR:
291 for (i = 0; i < n_buffers; ++i)
292 free(buffers[i].start);
299 static void init_read(unsigned int buffer_size)
301 buffers = calloc(1, sizeof(*buffers));
304 fprintf(stderr, "Out of memory\n");
308 buffers[0].length = buffer_size;
309 buffers[0].start = malloc(buffer_size);
311 if (!buffers[0].start) {
312 fprintf(stderr, "Out of memory\n");
317 static void init_mmap(void)
319 struct <link linkend="v4l2-requestbuffers">v4l2_requestbuffers</link> req;
324 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
325 req.memory = V4L2_MEMORY_MMAP;
327 if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
328 if (EINVAL == errno) {
329 fprintf(stderr, "%s does not support "
330 "memory mapping\n", dev_name);
333 errno_exit("VIDIOC_REQBUFS");
337 if (req.count < 2) {
338 fprintf(stderr, "Insufficient buffer memory on %s\n",
343 buffers = calloc(req.count, sizeof(*buffers));
346 fprintf(stderr, "Out of memory\n");
350 for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
351 struct <link linkend="v4l2-buffer">v4l2_buffer</link> buf;
355 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
356 buf.memory = V4L2_MEMORY_MMAP;
357 buf.index = n_buffers;
359 if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
360 errno_exit("VIDIOC_QUERYBUF");
362 buffers[n_buffers].length = buf.length;
363 buffers[n_buffers].start =
364 mmap(NULL /* start anywhere */,
366 PROT_READ | PROT_WRITE /* required */,
367 MAP_SHARED /* recommended */,
370 if (MAP_FAILED == buffers[n_buffers].start)
375 static void init_userp(unsigned int buffer_size)
377 struct <link linkend="v4l2-requestbuffers">v4l2_requestbuffers</link> req;
382 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
383 req.memory = V4L2_MEMORY_USERPTR;
385 if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
386 if (EINVAL == errno) {
387 fprintf(stderr, "%s does not support "
388 "user pointer i/o\n", dev_name);
391 errno_exit("VIDIOC_REQBUFS");
395 buffers = calloc(4, sizeof(*buffers));
398 fprintf(stderr, "Out of memory\n");
402 for (n_buffers = 0; n_buffers < 4; ++n_buffers) {
403 buffers[n_buffers].length = buffer_size;
404 buffers[n_buffers].start = malloc(buffer_size);
406 if (!buffers[n_buffers].start) {
407 fprintf(stderr, "Out of memory\n");
413 static void init_device(void)
415 struct <link linkend="v4l2-capability">v4l2_capability</link> cap;
416 struct <link linkend="v4l2-cropcap">v4l2_cropcap</link> cropcap;
417 struct <link linkend="v4l2-crop">v4l2_crop</link> crop;
418 struct <link linkend="v4l2-format">v4l2_format</link> fmt;
421 if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) {
422 if (EINVAL == errno) {
423 fprintf(stderr, "%s is no V4L2 device\n",
427 errno_exit("VIDIOC_QUERYCAP");
431 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
432 fprintf(stderr, "%s is no video capture device\n",
439 if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
440 fprintf(stderr, "%s does not support read i/o\n",
447 case IO_METHOD_USERPTR:
448 if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
449 fprintf(stderr, "%s does not support streaming i/o\n",
457 /* Select video input, video standard and tune here. */
462 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
464 if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
465 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
466 crop.c = cropcap.defrect; /* reset to default */
468 if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
471 /* Cropping not supported. */
474 /* Errors ignored. */
479 /* Errors ignored. */
485 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
487 fmt.fmt.pix.width = 640;
488 fmt.fmt.pix.height = 480;
489 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
490 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
492 if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
493 errno_exit("VIDIOC_S_FMT");
495 /* Note VIDIOC_S_FMT may change width and height. */
497 /* Preserve original settings as set by v4l2-ctl for example */
498 if (-1 == xioctl(fd, VIDIOC_G_FMT, &fmt))
499 errno_exit("VIDIOC_G_FMT");
502 /* Buggy driver paranoia. */
503 min = fmt.fmt.pix.width * 2;
504 if (fmt.fmt.pix.bytesperline < min)
505 fmt.fmt.pix.bytesperline = min;
506 min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
507 if (fmt.fmt.pix.sizeimage < min)
508 fmt.fmt.pix.sizeimage = min;
512 init_read(fmt.fmt.pix.sizeimage);
519 case IO_METHOD_USERPTR:
520 init_userp(fmt.fmt.pix.sizeimage);
525 static void close_device(void)
533 static void open_device(void)
537 if (-1 == stat(dev_name, &st)) {
538 fprintf(stderr, "Cannot identify '%s': %d, %s\n",
539 dev_name, errno, strerror(errno));
543 if (!S_ISCHR(st.st_mode)) {
544 fprintf(stderr, "%s is no device\n", dev_name);
548 fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
551 fprintf(stderr, "Cannot open '%s': %d, %s\n",
552 dev_name, errno, strerror(errno));
557 static void usage(FILE *fp, int argc, char **argv)
560 "Usage: %s [options]\n\n"
563 "-d | --device name Video device name [%s]\n"
564 "-h | --help Print this message\n"
565 "-m | --mmap Use memory mapped buffers [default]\n"
566 "-r | --read Use read() calls\n"
567 "-u | --userp Use application allocated buffers\n"
568 "-o | --output Outputs stream to stdout\n"
569 "-f | --format Force format to 640x480 YUYV\n"
570 "-c | --count Number of frames to grab [%i]\n"
572 argv[0], dev_name, frame_count);
575 static const char short_options[] = "d:hmruofc:";
577 static const struct option
579 { "device", required_argument, NULL, 'd' },
580 { "help", no_argument, NULL, 'h' },
581 { "mmap", no_argument, NULL, 'm' },
582 { "read", no_argument, NULL, 'r' },
583 { "userp", no_argument, NULL, 'u' },
584 { "output", no_argument, NULL, 'o' },
585 { "format", no_argument, NULL, 'f' },
586 { "count", required_argument, NULL, 'c' },
590 int main(int argc, char **argv)
592 dev_name = "/dev/video0";
598 c = getopt_long(argc, argv,
599 short_options, long_options, &idx);
605 case 0: /* getopt_long() flag */
613 usage(stdout, argc, argv);
625 io = IO_METHOD_USERPTR;
638 frame_count = strtol(optarg, NULL, 0);
644 usage(stderr, argc, argv);
656 fprintf(stderr, "\n");