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