~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/Documentation/userspace-api/media/v4l/capture.c.rst

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php