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