1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"> 2<HTML 3><HEAD 4><TITLE 5>Video Capture Example</TITLE 6><META 7NAME="GENERATOR" 8CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK 9REL="HOME" 10TITLE="Video for Linux Two API Specification" 11HREF="book1.htm"><LINK 12REL="PREVIOUS" 13TITLE="Video For Linux Two Header File" 14HREF="a16506.htm"><LINK 15REL="NEXT" 16TITLE="GNU Free Documentation License" 17HREF="a16721.htm"></HEAD 18><BODY 19CLASS="APPENDIX" 20BGCOLOR="#FFFFFF" 21TEXT="#000000" 22LINK="#0000FF" 23VLINK="#840084" 24ALINK="#0000FF" 25><DIV 26CLASS="NAVHEADER" 27><TABLE 28SUMMARY="Header navigation table" 29WIDTH="100%" 30BORDER="0" 31CELLPADDING="0" 32CELLSPACING="0" 33><TR 34><TH 35COLSPAN="3" 36ALIGN="center" 37>Video for Linux Two API Specification: Revision 0.24</TH 38></TR 39><TR 40><TD 41WIDTH="10%" 42ALIGN="left" 43VALIGN="bottom" 44><A 45HREF="a16506.htm" 46ACCESSKEY="P" 47>Prev</A 48></TD 49><TD 50WIDTH="80%" 51ALIGN="center" 52VALIGN="bottom" 53></TD 54><TD 55WIDTH="10%" 56ALIGN="right" 57VALIGN="bottom" 58><A 59HREF="a16721.htm" 60ACCESSKEY="N" 61>Next</A 62></TD 63></TR 64></TABLE 65><HR 66ALIGN="LEFT" 67WIDTH="100%"></DIV 68><DIV 69CLASS="APPENDIX" 70><H1 71><A 72NAME="CAPTURE-EXAMPLE" 73></A 74>Appendix B. Video Capture Example</H1 75><PRE 76CLASS="PROGRAMLISTING" 77>/* 78 * V4L2 video capture example 79 * 80 * This program can be used and distributed without restrictions. 81 */ 82 83#include <stdio.h> 84#include <stdlib.h> 85#include <string.h> 86#include <assert.h> 87 88#include <getopt.h> /* getopt_long() */ 89 90#include <fcntl.h> /* low-level i/o */ 91#include <unistd.h> 92#include <errno.h> 93#include <stdlib.h> 94#include <sys/stat.h> 95#include <sys/types.h> 96#include <sys/time.h> 97#include <sys/mman.h> 98#include <sys/ioctl.h> 99 100#include <asm/types.h> /* for videodev2.h */ 101 102#include <linux/videodev2.h> 103 104#define CLEAR(x) memset (&(x), 0, sizeof (x)) 105 106typedef enum { 107 IO_METHOD_READ, 108 IO_METHOD_MMAP, 109 IO_METHOD_USERPTR, 110} io_method; 111 112struct buffer { 113 void * start; 114 size_t length; 115}; 116 117static char * dev_name = NULL; 118static io_method io = IO_METHOD_MMAP; 119static int fd = -1; 120struct buffer * buffers = NULL; 121static unsigned int n_buffers = 0; 122 123static void 124errno_exit (const char * s) 125{ 126 fprintf (stderr, "%s error %d, %s\n", 127 s, errno, strerror (errno)); 128 129 exit (EXIT_FAILURE); 130} 131 132static int 133xioctl (int fd, 134 int request, 135 void * arg) 136{ 137 int r; 138 139 do r = ioctl (fd, request, arg); 140 while (-1 == r && EINTR == errno); 141 142 return r; 143} 144 145static void 146process_image (const void * p) 147{ 148 fputc ('.', stdout); 149 fflush (stdout); 150} 151 152static int 153read_frame (void) 154{ 155 struct <A 156HREF="x5953.htm#V4L2-BUFFER" 157>v4l2_buffer</A 158> buf; 159 unsigned int i; 160 161 switch (io) { 162 case IO_METHOD_READ: 163 if (-1 == read (fd, buffers[0].start, buffers[0].length)) { 164 switch (errno) { 165 case EAGAIN: 166 return 0; 167 168 case EIO: 169 /* Could ignore EIO, see spec. */ 170 171 /* fall through */ 172 173 default: 174 errno_exit ("read"); 175 } 176 } 177 178 process_image (buffers[0].start); 179 180 break; 181 182 case IO_METHOD_MMAP: 183 CLEAR (buf); 184 185 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 186 buf.memory = V4L2_MEMORY_MMAP; 187 188 if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) { 189 switch (errno) { 190 case EAGAIN: 191 return 0; 192 193 case EIO: 194 /* Could ignore EIO, see spec. */ 195 196 /* fall through */ 197 198 default: 199 errno_exit ("VIDIOC_DQBUF"); 200 } 201 } 202 203 assert (buf.index < n_buffers); 204 205 process_image (buffers[buf.index].start); 206 207 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) 208 errno_exit ("VIDIOC_QBUF"); 209 210 break; 211 212 case IO_METHOD_USERPTR: 213 CLEAR (buf); 214 215 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 216 buf.memory = V4L2_MEMORY_USERPTR; 217 218 if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) { 219 switch (errno) { 220 case EAGAIN: 221 return 0; 222 223 case EIO: 224 /* Could ignore EIO, see spec. */ 225 226 /* fall through */ 227 228 default: 229 errno_exit ("VIDIOC_DQBUF"); 230 } 231 } 232 233 for (i = 0; i < n_buffers; ++i) 234 if (buf.m.userptr == (unsigned long) buffers[i].start 235 && buf.length == buffers[i].length) 236 break; 237 238 assert (i < n_buffers); 239 240 process_image ((void *) buf.m.userptr); 241 242 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) 243 errno_exit ("VIDIOC_QBUF"); 244 245 break; 246 } 247 248 return 1; 249} 250 251static void 252mainloop (void) 253{ 254 unsigned int count; 255 256 count = 100; 257 258 while (count-- > 0) { 259 for (;;) { 260 fd_set fds; 261 struct timeval tv; 262 int r; 263 264 FD_ZERO (&fds); 265 FD_SET (fd, &fds); 266 267 /* Timeout. */ 268 tv.tv_sec = 2; 269 tv.tv_usec = 0; 270 271 r = select (fd + 1, &fds, NULL, NULL, &tv); 272 273 if (-1 == r) { 274 if (EINTR == errno) 275 continue; 276 277 errno_exit ("select"); 278 } 279 280 if (0 == r) { 281 fprintf (stderr, "select timeout\n"); 282 exit (EXIT_FAILURE); 283 } 284 285 if (read_frame ()) 286 break; 287 288 /* EAGAIN - continue select loop. */ 289 } 290 } 291} 292 293static void 294stop_capturing (void) 295{ 296 enum <A 297HREF="x5953.htm#V4L2-BUF-TYPE" 298>v4l2_buf_type</A 299> type; 300 301 switch (io) { 302 case IO_METHOD_READ: 303 /* Nothing to do. */ 304 break; 305 306 case IO_METHOD_MMAP: 307 case IO_METHOD_USERPTR: 308 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 309 310 if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type)) 311 errno_exit ("VIDIOC_STREAMOFF"); 312 313 break; 314 } 315} 316 317static void 318start_capturing (void) 319{ 320 unsigned int i; 321 enum <A 322HREF="x5953.htm#V4L2-BUF-TYPE" 323>v4l2_buf_type</A 324> type; 325 326 switch (io) { 327 case IO_METHOD_READ: 328 /* Nothing to do. */ 329 break; 330 331 case IO_METHOD_MMAP: 332 for (i = 0; i < n_buffers; ++i) { 333 struct <A 334HREF="x5953.htm#V4L2-BUFFER" 335>v4l2_buffer</A 336> buf; 337 338 CLEAR (buf); 339 340 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 341 buf.memory = V4L2_MEMORY_MMAP; 342 buf.index = i; 343 344 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) 345 errno_exit ("VIDIOC_QBUF"); 346 } 347 348 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 349 350 if (-1 == xioctl (fd, VIDIOC_STREAMON, &type)) 351 errno_exit ("VIDIOC_STREAMON"); 352 353 break; 354 355 case IO_METHOD_USERPTR: 356 for (i = 0; i < n_buffers; ++i) { 357 struct <A 358HREF="x5953.htm#V4L2-BUFFER" 359>v4l2_buffer</A 360> buf; 361 362 CLEAR (buf); 363 364 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 365 buf.memory = V4L2_MEMORY_USERPTR; 366 buf.index = i; 367 buf.m.userptr = (unsigned long) buffers[i].start; 368 buf.length = buffers[i].length; 369 370 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) 371 errno_exit ("VIDIOC_QBUF"); 372 } 373 374 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 375 376 if (-1 == xioctl (fd, VIDIOC_STREAMON, &type)) 377 errno_exit ("VIDIOC_STREAMON"); 378 379 break; 380 } 381} 382 383static void 384uninit_device (void) 385{ 386 unsigned int i; 387 388 switch (io) { 389 case IO_METHOD_READ: 390 free (buffers[0].start); 391 break; 392 393 case IO_METHOD_MMAP: 394 for (i = 0; i < n_buffers; ++i) 395 if (-1 == munmap (buffers[i].start, buffers[i].length)) 396 errno_exit ("munmap"); 397 break; 398 399 case IO_METHOD_USERPTR: 400 for (i = 0; i < n_buffers; ++i) 401 free (buffers[i].start); 402 break; 403 } 404 405 free (buffers); 406} 407 408static void 409init_read (unsigned int buffer_size) 410{ 411 buffers = calloc (1, sizeof (*buffers)); 412 413 if (!buffers) { 414 fprintf (stderr, "Out of memory\n"); 415 exit (EXIT_FAILURE); 416 } 417 418 buffers[0].length = buffer_size; 419 buffers[0].start = malloc (buffer_size); 420 421 if (!buffers[0].start) { 422 fprintf (stderr, "Out of memory\n"); 423 exit (EXIT_FAILURE); 424 } 425} 426 427static void 428init_mmap (void) 429{ 430 struct <A 431HREF="r13696.htm#V4L2-REQUESTBUFFERS" 432>v4l2_requestbuffers</A 433> req; 434 435 CLEAR (req); 436 437 req.count = 4; 438 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 439 req.memory = V4L2_MEMORY_MMAP; 440 441 if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) { 442 if (EINVAL == errno) { 443 fprintf (stderr, "%s does not support " 444 "memory mapping\n", dev_name); 445 exit (EXIT_FAILURE); 446 } else { 447 errno_exit ("VIDIOC_REQBUFS"); 448 } 449 } 450 451 if (req.count < 2) { 452 fprintf (stderr, "Insufficient buffer memory on %s\n", 453 dev_name); 454 exit (EXIT_FAILURE); 455 } 456 457 buffers = calloc (req.count, sizeof (*buffers)); 458 459 if (!buffers) { 460 fprintf (stderr, "Out of memory\n"); 461 exit (EXIT_FAILURE); 462 } 463 464 for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { 465 struct <A 466HREF="x5953.htm#V4L2-BUFFER" 467>v4l2_buffer</A 468> buf; 469 470 CLEAR (buf); 471 472 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 473 buf.memory = V4L2_MEMORY_MMAP; 474 buf.index = n_buffers; 475 476 if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf)) 477 errno_exit ("VIDIOC_QUERYBUF"); 478 479 buffers[n_buffers].length = buf.length; 480 buffers[n_buffers].start = 481 mmap (NULL /* start anywhere */, 482 buf.length, 483 PROT_READ | PROT_WRITE /* required */, 484 MAP_SHARED /* recommended */, 485 fd, buf.m.offset); 486 487 if (MAP_FAILED == buffers[n_buffers].start) 488 errno_exit ("mmap"); 489 } 490} 491 492static void 493init_userp (unsigned int buffer_size) 494{ 495 struct <A 496HREF="r13696.htm#V4L2-REQUESTBUFFERS" 497>v4l2_requestbuffers</A 498> req; 499 unsigned int page_size; 500 501 page_size = getpagesize (); 502 buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1); 503 504 CLEAR (req); 505 506 req.count = 4; 507 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 508 req.memory = V4L2_MEMORY_USERPTR; 509 510 if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) { 511 if (EINVAL == errno) { 512 fprintf (stderr, "%s does not support " 513 "user pointer i/o\n", dev_name); 514 exit (EXIT_FAILURE); 515 } else { 516 errno_exit ("VIDIOC_REQBUFS"); 517 } 518 } 519 520 buffers = calloc (4, sizeof (*buffers)); 521 522 if (!buffers) { 523 fprintf (stderr, "Out of memory\n"); 524 exit (EXIT_FAILURE); 525 } 526 527 for (n_buffers = 0; n_buffers < 4; ++n_buffers) { 528 buffers[n_buffers].length = buffer_size; 529 buffers[n_buffers].start = memalign (/* boundary */ page_size, 530 buffer_size); 531 532 if (!buffers[n_buffers].start) { 533 fprintf (stderr, "Out of memory\n"); 534 exit (EXIT_FAILURE); 535 } 536 } 537} 538 539static void 540init_device (void) 541{ 542 struct <A 543HREF="r13105.htm#V4L2-CAPABILITY" 544>v4l2_capability</A 545> cap; 546 struct <A 547HREF="r7771.htm#V4L2-CROPCAP" 548>v4l2_cropcap</A 549> cropcap; 550 struct <A 551HREF="r9994.htm#V4L2-CROP" 552>v4l2_crop</A 553> crop; 554 struct <A 555HREF="r10944.htm#V4L2-FORMAT" 556>v4l2_format</A 557> fmt; 558 unsigned int min; 559 560 if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) { 561 if (EINVAL == errno) { 562 fprintf (stderr, "%s is no V4L2 device\n", 563 dev_name); 564 exit (EXIT_FAILURE); 565 } else { 566 errno_exit ("VIDIOC_QUERYCAP"); 567 } 568 } 569 570 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { 571 fprintf (stderr, "%s is no video capture device\n", 572 dev_name); 573 exit (EXIT_FAILURE); 574 } 575 576 switch (io) { 577 case IO_METHOD_READ: 578 if (!(cap.capabilities & V4L2_CAP_READWRITE)) { 579 fprintf (stderr, "%s does not support read i/o\n", 580 dev_name); 581 exit (EXIT_FAILURE); 582 } 583 584 break; 585 586 case IO_METHOD_MMAP: 587 case IO_METHOD_USERPTR: 588 if (!(cap.capabilities & V4L2_CAP_STREAMING)) { 589 fprintf (stderr, "%s does not support streaming i/o\n", 590 dev_name); 591 exit (EXIT_FAILURE); 592 } 593 594 break; 595 } 596 597 598 /* Select video input, video standard and tune here. */ 599 600 601 CLEAR (cropcap); 602 603 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 604 605 if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) { 606 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 607 crop.c = cropcap.defrect; /* reset to default */ 608 609 if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) { 610 switch (errno) { 611 case EINVAL: 612 /* Cropping not supported. */ 613 break; 614 default: 615 /* Errors ignored. */ 616 break; 617 } 618 } 619 } else { 620 /* Errors ignored. */ 621 } 622 623 624 CLEAR (fmt); 625 626 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 627 fmt.fmt.pix.width = 640; 628 fmt.fmt.pix.height = 480; 629 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; 630 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; 631 632 if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)) 633 errno_exit ("VIDIOC_S_FMT"); 634 635 /* Note VIDIOC_S_FMT may change width and height. */ 636 637 /* Buggy driver paranoia. */ 638 min = fmt.fmt.pix.width * 2; 639 if (fmt.fmt.pix.bytesperline < min) 640 fmt.fmt.pix.bytesperline = min; 641 min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; 642 if (fmt.fmt.pix.sizeimage < min) 643 fmt.fmt.pix.sizeimage = min; 644 645 switch (io) { 646 case IO_METHOD_READ: 647 init_read (fmt.fmt.pix.sizeimage); 648 break; 649 650 case IO_METHOD_MMAP: 651 init_mmap (); 652 break; 653 654 case IO_METHOD_USERPTR: 655 init_userp (fmt.fmt.pix.sizeimage); 656 break; 657 } 658} 659 660static void 661close_device (void) 662{ 663 if (-1 == close (fd)) 664 errno_exit ("close"); 665 666 fd = -1; 667} 668 669static void 670open_device (void) 671{ 672 struct stat st; 673 674 if (-1 == stat (dev_name, &st)) { 675 fprintf (stderr, "Cannot identify '%s': %d, %s\n", 676 dev_name, errno, strerror (errno)); 677 exit (EXIT_FAILURE); 678 } 679 680 if (!S_ISCHR (st.st_mode)) { 681 fprintf (stderr, "%s is no device\n", dev_name); 682 exit (EXIT_FAILURE); 683 } 684 685 fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0); 686 687 if (-1 == fd) { 688 fprintf (stderr, "Cannot open '%s': %d, %s\n", 689 dev_name, errno, strerror (errno)); 690 exit (EXIT_FAILURE); 691 } 692} 693 694static void 695usage (FILE * fp, 696 int argc, 697 char ** argv) 698{ 699 fprintf (fp, 700 "Usage: %s [options]\n\n" 701 "Options:\n" 702 "-d | --device name Video device name [/dev/video]\n" 703 "-h | --help Print this message\n" 704 "-m | --mmap Use memory mapped buffers\n" 705 "-r | --read Use read() calls\n" 706 "-u | --userp Use application allocated buffers\n" 707 "", 708 argv[0]); 709} 710 711static const char short_options [] = "d:hmru"; 712 713static const struct option 714long_options [] = { 715 { "device", required_argument, NULL, 'd' }, 716 { "help", no_argument, NULL, 'h' }, 717 { "mmap", no_argument, NULL, 'm' }, 718 { "read", no_argument, NULL, 'r' }, 719 { "userp", no_argument, NULL, 'u' }, 720 { 0, 0, 0, 0 } 721}; 722 723int 724main (int argc, 725 char ** argv) 726{ 727 dev_name = "/dev/video"; 728 729 for (;;) { 730 int index; 731 int c; 732 733 c = getopt_long (argc, argv, 734 short_options, long_options, 735 &index); 736 737 if (-1 == c) 738 break; 739 740 switch (c) { 741 case 0: /* getopt_long() flag */ 742 break; 743 744 case 'd': 745 dev_name = optarg; 746 break; 747 748 case 'h': 749 usage (stdout, argc, argv); 750 exit (EXIT_SUCCESS); 751 752 case 'm': 753 io = IO_METHOD_MMAP; 754 break; 755 756 case 'r': 757 io = IO_METHOD_READ; 758 break; 759 760 case 'u': 761 io = IO_METHOD_USERPTR; 762 break; 763 764 default: 765 usage (stderr, argc, argv); 766 exit (EXIT_FAILURE); 767 } 768 } 769 770 open_device (); 771 772 init_device (); 773 774 start_capturing (); 775 776 mainloop (); 777 778 stop_capturing (); 779 780 uninit_device (); 781 782 close_device (); 783 784 exit (EXIT_SUCCESS); 785 786 return 0; 787}</PRE 788></DIV 789><DIV 790CLASS="NAVFOOTER" 791><HR 792ALIGN="LEFT" 793WIDTH="100%"><TABLE 794SUMMARY="Footer navigation table" 795WIDTH="100%" 796BORDER="0" 797CELLPADDING="0" 798CELLSPACING="0" 799><TR 800><TD 801WIDTH="33%" 802ALIGN="left" 803VALIGN="top" 804><A 805HREF="a16506.htm" 806ACCESSKEY="P" 807>Prev</A 808></TD 809><TD 810WIDTH="34%" 811ALIGN="center" 812VALIGN="top" 813><A 814HREF="book1.htm" 815ACCESSKEY="H" 816>Home</A 817></TD 818><TD 819WIDTH="33%" 820ALIGN="right" 821VALIGN="top" 822><A 823HREF="a16721.htm" 824ACCESSKEY="N" 825>Next</A 826></TD 827></TR 828><TR 829><TD 830WIDTH="33%" 831ALIGN="left" 832VALIGN="top" 833>Video For Linux Two Header File</TD 834><TD 835WIDTH="34%" 836ALIGN="center" 837VALIGN="top" 838> </TD 839><TD 840WIDTH="33%" 841ALIGN="right" 842VALIGN="top" 843>GNU Free Documentation License</TD 844></TR 845></TABLE 846></DIV 847></BODY 848></HTML 849> 850