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