1.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
2
3file: 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 mappingn", 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/on", 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 devicen", 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 messagen"
571		     "-m | --mmap          Use memory mapped buffers [default]n"
572		     "-r | --read          Use read() callsn"
573		     "-u | --userp         Use application allocated buffersn"
574		     "-o | --output        Outputs stream to stdoutn"
575		     "-f | --format        Force format to 640x480 YUYVn"
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    }
665