• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
2<HTML
3><HEAD
4><TITLE
5>Video Capture Example</TITLE
6><META
7NAME="GENERATOR"
8CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
9REL="HOME"
10TITLE="Video for Linux Two API Specification"
11HREF="book1.htm"><LINK
12REL="PREVIOUS"
13TITLE="Video For Linux Two Header File"
14HREF="a16506.htm"><LINK
15REL="NEXT"
16TITLE="GNU Free Documentation License"
17HREF="a16721.htm"></HEAD
18><BODY
19CLASS="APPENDIX"
20BGCOLOR="#FFFFFF"
21TEXT="#000000"
22LINK="#0000FF"
23VLINK="#840084"
24ALINK="#0000FF"
25><DIV
26CLASS="NAVHEADER"
27><TABLE
28SUMMARY="Header navigation table"
29WIDTH="100%"
30BORDER="0"
31CELLPADDING="0"
32CELLSPACING="0"
33><TR
34><TH
35COLSPAN="3"
36ALIGN="center"
37>Video for Linux Two API Specification: Revision 0.24</TH
38></TR
39><TR
40><TD
41WIDTH="10%"
42ALIGN="left"
43VALIGN="bottom"
44><A
45HREF="a16506.htm"
46ACCESSKEY="P"
47>Prev</A
48></TD
49><TD
50WIDTH="80%"
51ALIGN="center"
52VALIGN="bottom"
53></TD
54><TD
55WIDTH="10%"
56ALIGN="right"
57VALIGN="bottom"
58><A
59HREF="a16721.htm"
60ACCESSKEY="N"
61>Next</A
62></TD
63></TR
64></TABLE
65><HR
66ALIGN="LEFT"
67WIDTH="100%"></DIV
68><DIV
69CLASS="APPENDIX"
70><H1
71><A
72NAME="CAPTURE-EXAMPLE"
73></A
74>Appendix B. Video Capture Example</H1
75><PRE
76CLASS="PROGRAMLISTING"
77>/*
78 *  V4L2 video capture example
79 *
80 *  This program can be used and distributed without restrictions.
81 */
82
83#include &lt;stdio.h&gt;
84#include &lt;stdlib.h&gt;
85#include &lt;string.h&gt;
86#include &lt;assert.h&gt;
87
88#include &lt;getopt.h&gt;             /* getopt_long() */
89
90#include &lt;fcntl.h&gt;              /* low-level i/o */
91#include &lt;unistd.h&gt;
92#include &lt;errno.h&gt;
93#include &lt;stdlib.h&gt;
94#include &lt;sys/stat.h&gt;
95#include &lt;sys/types.h&gt;
96#include &lt;sys/time.h&gt;
97#include &lt;sys/mman.h&gt;
98#include &lt;sys/ioctl.h&gt;
99
100#include &lt;asm/types.h&gt;          /* for videodev2.h */
101
102#include &lt;linux/videodev2.h&gt;
103
104#define CLEAR(x) memset (&amp;(x), 0, sizeof (x))
105
106typedef enum {
107        IO_METHOD_READ,
108        IO_METHOD_MMAP,
109        IO_METHOD_USERPTR,
110} io_method;
111
112struct buffer {
113        void *                  start;
114        size_t                  length;
115};
116
117static char *           dev_name        = NULL;
118static io_method        io              = IO_METHOD_MMAP;
119static int              fd              = -1;
120struct buffer *         buffers         = NULL;
121static unsigned int     n_buffers       = 0;
122
123static void
124errno_exit                      (const char *           s)
125{
126        fprintf (stderr, "%s error %d, %s\n",
127                 s, errno, strerror (errno));
128
129        exit (EXIT_FAILURE);
130}
131
132static int
133xioctl                          (int                    fd,
134                                 int                    request,
135                                 void *                 arg)
136{
137        int r;
138
139        do r = ioctl (fd, request, arg);
140        while (-1 == r &amp;&amp; EINTR == errno);
141
142        return r;
143}
144
145static void
146process_image                   (const void *           p)
147{
148        fputc ('.', stdout);
149        fflush (stdout);
150}
151
152static int
153read_frame                      (void)
154{
155        struct <A
156HREF="x5953.htm#V4L2-BUFFER"
157>v4l2_buffer</A
158> buf;
159        unsigned int i;
160
161        switch (io) {
162        case IO_METHOD_READ:
163                if (-1 == read (fd, buffers[0].start, buffers[0].length)) {
164                        switch (errno) {
165                        case EAGAIN:
166                                return 0;
167
168                        case EIO:
169                                /* Could ignore EIO, see spec. */
170
171                                /* fall through */
172
173                        default:
174                                errno_exit ("read");
175                        }
176                }
177
178                process_image (buffers[0].start);
179
180                break;
181
182        case IO_METHOD_MMAP:
183                CLEAR (buf);
184
185                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
186                buf.memory = V4L2_MEMORY_MMAP;
187
188                if (-1 == xioctl (fd, VIDIOC_DQBUF, &amp;buf)) {
189                        switch (errno) {
190                        case EAGAIN:
191                                return 0;
192
193                        case EIO:
194                                /* Could ignore EIO, see spec. */
195
196                                /* fall through */
197
198                        default:
199                                errno_exit ("VIDIOC_DQBUF");
200                        }
201                }
202
203                assert (buf.index &lt; n_buffers);
204
205                process_image (buffers[buf.index].start);
206
207                if (-1 == xioctl (fd, VIDIOC_QBUF, &amp;buf))
208                        errno_exit ("VIDIOC_QBUF");
209
210                break;
211
212        case IO_METHOD_USERPTR:
213                CLEAR (buf);
214
215                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
216                buf.memory = V4L2_MEMORY_USERPTR;
217
218                if (-1 == xioctl (fd, VIDIOC_DQBUF, &amp;buf)) {
219                        switch (errno) {
220                        case EAGAIN:
221                                return 0;
222
223                        case EIO:
224                                /* Could ignore EIO, see spec. */
225
226                                /* fall through */
227
228                        default:
229                                errno_exit ("VIDIOC_DQBUF");
230                        }
231                }
232
233                for (i = 0; i &lt; n_buffers; ++i)
234                        if (buf.m.userptr == (unsigned long) buffers[i].start
235                            &amp;&amp; buf.length == buffers[i].length)
236                                break;
237
238                assert (i &lt; n_buffers);
239
240                process_image ((void *) buf.m.userptr);
241
242                if (-1 == xioctl (fd, VIDIOC_QBUF, &amp;buf))
243                        errno_exit ("VIDIOC_QBUF");
244
245                break;
246        }
247
248        return 1;
249}
250
251static void
252mainloop                        (void)
253{
254        unsigned int count;
255
256        count = 100;
257
258        while (count-- &gt; 0) {
259                for (;;) {
260                        fd_set fds;
261                        struct timeval tv;
262                        int r;
263
264                        FD_ZERO (&amp;fds);
265                        FD_SET (fd, &amp;fds);
266
267                        /* Timeout. */
268                        tv.tv_sec = 2;
269                        tv.tv_usec = 0;
270
271                        r = select (fd + 1, &amp;fds, NULL, NULL, &amp;tv);
272
273                        if (-1 == r) {
274                                if (EINTR == errno)
275                                        continue;
276
277                                errno_exit ("select");
278                        }
279
280                        if (0 == r) {
281                                fprintf (stderr, "select timeout\n");
282                                exit (EXIT_FAILURE);
283                        }
284
285                        if (read_frame ())
286                                break;
287
288                        /* EAGAIN - continue select loop. */
289                }
290        }
291}
292
293static void
294stop_capturing                  (void)
295{
296        enum <A
297HREF="x5953.htm#V4L2-BUF-TYPE"
298>v4l2_buf_type</A
299> type;
300
301        switch (io) {
302        case IO_METHOD_READ:
303                /* Nothing to do. */
304                break;
305
306        case IO_METHOD_MMAP:
307        case IO_METHOD_USERPTR:
308                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
309
310                if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &amp;type))
311                        errno_exit ("VIDIOC_STREAMOFF");
312
313                break;
314        }
315}
316
317static void
318start_capturing                 (void)
319{
320        unsigned int i;
321        enum <A
322HREF="x5953.htm#V4L2-BUF-TYPE"
323>v4l2_buf_type</A
324> type;
325
326        switch (io) {
327        case IO_METHOD_READ:
328                /* Nothing to do. */
329                break;
330
331        case IO_METHOD_MMAP:
332                for (i = 0; i &lt; n_buffers; ++i) {
333                        struct <A
334HREF="x5953.htm#V4L2-BUFFER"
335>v4l2_buffer</A
336> buf;
337
338                        CLEAR (buf);
339
340                        buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
341                        buf.memory      = V4L2_MEMORY_MMAP;
342                        buf.index       = i;
343
344                        if (-1 == xioctl (fd, VIDIOC_QBUF, &amp;buf))
345                                errno_exit ("VIDIOC_QBUF");
346                }
347
348                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
349
350                if (-1 == xioctl (fd, VIDIOC_STREAMON, &amp;type))
351                        errno_exit ("VIDIOC_STREAMON");
352
353                break;
354
355        case IO_METHOD_USERPTR:
356                for (i = 0; i &lt; n_buffers; ++i) {
357                        struct <A
358HREF="x5953.htm#V4L2-BUFFER"
359>v4l2_buffer</A
360> buf;
361
362                        CLEAR (buf);
363
364                        buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
365                        buf.memory      = V4L2_MEMORY_USERPTR;
366                        buf.index       = i;
367                        buf.m.userptr   = (unsigned long) buffers[i].start;
368                        buf.length      = buffers[i].length;
369
370                        if (-1 == xioctl (fd, VIDIOC_QBUF, &amp;buf))
371                                errno_exit ("VIDIOC_QBUF");
372                }
373
374                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
375
376                if (-1 == xioctl (fd, VIDIOC_STREAMON, &amp;type))
377                        errno_exit ("VIDIOC_STREAMON");
378
379                break;
380        }
381}
382
383static void
384uninit_device                   (void)
385{
386        unsigned int i;
387
388        switch (io) {
389        case IO_METHOD_READ:
390                free (buffers[0].start);
391                break;
392
393        case IO_METHOD_MMAP:
394                for (i = 0; i &lt; n_buffers; ++i)
395                        if (-1 == munmap (buffers[i].start, buffers[i].length))
396                                errno_exit ("munmap");
397                break;
398
399        case IO_METHOD_USERPTR:
400                for (i = 0; i &lt; n_buffers; ++i)
401                        free (buffers[i].start);
402                break;
403        }
404
405        free (buffers);
406}
407
408static void
409init_read                       (unsigned int           buffer_size)
410{
411        buffers = calloc (1, sizeof (*buffers));
412
413        if (!buffers) {
414                fprintf (stderr, "Out of memory\n");
415                exit (EXIT_FAILURE);
416        }
417
418        buffers[0].length = buffer_size;
419        buffers[0].start = malloc (buffer_size);
420
421        if (!buffers[0].start) {
422                fprintf (stderr, "Out of memory\n");
423                exit (EXIT_FAILURE);
424        }
425}
426
427static void
428init_mmap                       (void)
429{
430        struct <A
431HREF="r13696.htm#V4L2-REQUESTBUFFERS"
432>v4l2_requestbuffers</A
433> req;
434
435        CLEAR (req);
436
437        req.count               = 4;
438        req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
439        req.memory              = V4L2_MEMORY_MMAP;
440
441        if (-1 == xioctl (fd, VIDIOC_REQBUFS, &amp;req)) {
442                if (EINVAL == errno) {
443                        fprintf (stderr, "%s does not support "
444                                 "memory mapping\n", dev_name);
445                        exit (EXIT_FAILURE);
446                } else {
447                        errno_exit ("VIDIOC_REQBUFS");
448                }
449        }
450
451        if (req.count &lt; 2) {
452                fprintf (stderr, "Insufficient buffer memory on %s\n",
453                         dev_name);
454                exit (EXIT_FAILURE);
455        }
456
457        buffers = calloc (req.count, sizeof (*buffers));
458
459        if (!buffers) {
460                fprintf (stderr, "Out of memory\n");
461                exit (EXIT_FAILURE);
462        }
463
464        for (n_buffers = 0; n_buffers &lt; req.count; ++n_buffers) {
465                struct <A
466HREF="x5953.htm#V4L2-BUFFER"
467>v4l2_buffer</A
468> buf;
469
470                CLEAR (buf);
471
472                buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
473                buf.memory      = V4L2_MEMORY_MMAP;
474                buf.index       = n_buffers;
475
476                if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &amp;buf))
477                        errno_exit ("VIDIOC_QUERYBUF");
478
479                buffers[n_buffers].length = buf.length;
480                buffers[n_buffers].start =
481                        mmap (NULL /* start anywhere */,
482                              buf.length,
483                              PROT_READ | PROT_WRITE /* required */,
484                              MAP_SHARED /* recommended */,
485                              fd, buf.m.offset);
486
487                if (MAP_FAILED == buffers[n_buffers].start)
488                        errno_exit ("mmap");
489        }
490}
491
492static void
493init_userp                      (unsigned int           buffer_size)
494{
495        struct <A
496HREF="r13696.htm#V4L2-REQUESTBUFFERS"
497>v4l2_requestbuffers</A
498> req;
499        unsigned int page_size;
500
501        page_size = getpagesize ();
502        buffer_size = (buffer_size + page_size - 1) &amp; ~(page_size - 1);
503
504        CLEAR (req);
505
506        req.count               = 4;
507        req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
508        req.memory              = V4L2_MEMORY_USERPTR;
509
510        if (-1 == xioctl (fd, VIDIOC_REQBUFS, &amp;req)) {
511                if (EINVAL == errno) {
512                        fprintf (stderr, "%s does not support "
513                                 "user pointer i/o\n", dev_name);
514                        exit (EXIT_FAILURE);
515                } else {
516                        errno_exit ("VIDIOC_REQBUFS");
517                }
518        }
519
520        buffers = calloc (4, sizeof (*buffers));
521
522        if (!buffers) {
523                fprintf (stderr, "Out of memory\n");
524                exit (EXIT_FAILURE);
525        }
526
527        for (n_buffers = 0; n_buffers &lt; 4; ++n_buffers) {
528                buffers[n_buffers].length = buffer_size;
529                buffers[n_buffers].start = memalign (/* boundary */ page_size,
530                                                     buffer_size);
531
532                if (!buffers[n_buffers].start) {
533                        fprintf (stderr, "Out of memory\n");
534                        exit (EXIT_FAILURE);
535                }
536        }
537}
538
539static void
540init_device                     (void)
541{
542        struct <A
543HREF="r13105.htm#V4L2-CAPABILITY"
544>v4l2_capability</A
545> cap;
546        struct <A
547HREF="r7771.htm#V4L2-CROPCAP"
548>v4l2_cropcap</A
549> cropcap;
550        struct <A
551HREF="r9994.htm#V4L2-CROP"
552>v4l2_crop</A
553> crop;
554        struct <A
555HREF="r10944.htm#V4L2-FORMAT"
556>v4l2_format</A
557> fmt;
558        unsigned int min;
559
560        if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &amp;cap)) {
561                if (EINVAL == errno) {
562                        fprintf (stderr, "%s is no V4L2 device\n",
563                                 dev_name);
564                        exit (EXIT_FAILURE);
565                } else {
566                        errno_exit ("VIDIOC_QUERYCAP");
567                }
568        }
569
570        if (!(cap.capabilities &amp; V4L2_CAP_VIDEO_CAPTURE)) {
571                fprintf (stderr, "%s is no video capture device\n",
572                         dev_name);
573                exit (EXIT_FAILURE);
574        }
575
576        switch (io) {
577        case IO_METHOD_READ:
578                if (!(cap.capabilities &amp; V4L2_CAP_READWRITE)) {
579                        fprintf (stderr, "%s does not support read i/o\n",
580                                 dev_name);
581                        exit (EXIT_FAILURE);
582                }
583
584                break;
585
586        case IO_METHOD_MMAP:
587        case IO_METHOD_USERPTR:
588                if (!(cap.capabilities &amp; V4L2_CAP_STREAMING)) {
589                        fprintf (stderr, "%s does not support streaming i/o\n",
590                                 dev_name);
591                        exit (EXIT_FAILURE);
592                }
593
594                break;
595        }
596
597
598        /* Select video input, video standard and tune here. */
599
600
601        CLEAR (cropcap);
602
603        cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
604
605        if (0 == xioctl (fd, VIDIOC_CROPCAP, &amp;cropcap)) {
606                crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
607                crop.c = cropcap.defrect; /* reset to default */
608
609                if (-1 == xioctl (fd, VIDIOC_S_CROP, &amp;crop)) {
610                        switch (errno) {
611                        case EINVAL:
612                                /* Cropping not supported. */
613                                break;
614                        default:
615                                /* Errors ignored. */
616                                break;
617                        }
618                }
619        } else {
620                /* Errors ignored. */
621        }
622
623
624        CLEAR (fmt);
625
626        fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
627        fmt.fmt.pix.width       = 640;
628        fmt.fmt.pix.height      = 480;
629        fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
630        fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
631
632        if (-1 == xioctl (fd, VIDIOC_S_FMT, &amp;fmt))
633                errno_exit ("VIDIOC_S_FMT");
634
635        /* Note VIDIOC_S_FMT may change width and height. */
636
637        /* Buggy driver paranoia. */
638        min = fmt.fmt.pix.width * 2;
639        if (fmt.fmt.pix.bytesperline &lt; min)
640                fmt.fmt.pix.bytesperline = min;
641        min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
642        if (fmt.fmt.pix.sizeimage &lt; min)
643                fmt.fmt.pix.sizeimage = min;
644
645        switch (io) {
646        case IO_METHOD_READ:
647                init_read (fmt.fmt.pix.sizeimage);
648                break;
649
650        case IO_METHOD_MMAP:
651                init_mmap ();
652                break;
653
654        case IO_METHOD_USERPTR:
655                init_userp (fmt.fmt.pix.sizeimage);
656                break;
657        }
658}
659
660static void
661close_device                    (void)
662{
663        if (-1 == close (fd))
664                errno_exit ("close");
665
666        fd = -1;
667}
668
669static void
670open_device                     (void)
671{
672        struct stat st;
673
674        if (-1 == stat (dev_name, &amp;st)) {
675                fprintf (stderr, "Cannot identify '%s': %d, %s\n",
676                         dev_name, errno, strerror (errno));
677                exit (EXIT_FAILURE);
678        }
679
680        if (!S_ISCHR (st.st_mode)) {
681                fprintf (stderr, "%s is no device\n", dev_name);
682                exit (EXIT_FAILURE);
683        }
684
685        fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
686
687        if (-1 == fd) {
688                fprintf (stderr, "Cannot open '%s': %d, %s\n",
689                         dev_name, errno, strerror (errno));
690                exit (EXIT_FAILURE);
691        }
692}
693
694static void
695usage                           (FILE *                 fp,
696                                 int                    argc,
697                                 char **                argv)
698{
699        fprintf (fp,
700                 "Usage: %s [options]\n\n"
701                 "Options:\n"
702                 "-d | --device name   Video device name [/dev/video]\n"
703                 "-h | --help          Print this message\n"
704                 "-m | --mmap          Use memory mapped buffers\n"
705                 "-r | --read          Use read() calls\n"
706                 "-u | --userp         Use application allocated buffers\n"
707                 "",
708                 argv[0]);
709}
710
711static const char short_options [] = "d:hmru";
712
713static const struct option
714long_options [] = {
715        { "device",     required_argument,      NULL,           'd' },
716        { "help",       no_argument,            NULL,           'h' },
717        { "mmap",       no_argument,            NULL,           'm' },
718        { "read",       no_argument,            NULL,           'r' },
719        { "userp",      no_argument,            NULL,           'u' },
720        { 0, 0, 0, 0 }
721};
722
723int
724main                            (int                    argc,
725                                 char **                argv)
726{
727        dev_name = "/dev/video";
728
729        for (;;) {
730                int index;
731                int c;
732
733                c = getopt_long (argc, argv,
734                                 short_options, long_options,
735                                 &amp;index);
736
737                if (-1 == c)
738                        break;
739
740                switch (c) {
741                case 0: /* getopt_long() flag */
742                        break;
743
744                case 'd':
745                        dev_name = optarg;
746                        break;
747
748                case 'h':
749                        usage (stdout, argc, argv);
750                        exit (EXIT_SUCCESS);
751
752                case 'm':
753                        io = IO_METHOD_MMAP;
754                        break;
755
756                case 'r':
757                        io = IO_METHOD_READ;
758                        break;
759
760                case 'u':
761                        io = IO_METHOD_USERPTR;
762                        break;
763
764                default:
765                        usage (stderr, argc, argv);
766                        exit (EXIT_FAILURE);
767                }
768        }
769
770        open_device ();
771
772        init_device ();
773
774        start_capturing ();
775
776        mainloop ();
777
778        stop_capturing ();
779
780        uninit_device ();
781
782        close_device ();
783
784        exit (EXIT_SUCCESS);
785
786        return 0;
787}</PRE
788></DIV
789><DIV
790CLASS="NAVFOOTER"
791><HR
792ALIGN="LEFT"
793WIDTH="100%"><TABLE
794SUMMARY="Footer navigation table"
795WIDTH="100%"
796BORDER="0"
797CELLPADDING="0"
798CELLSPACING="0"
799><TR
800><TD
801WIDTH="33%"
802ALIGN="left"
803VALIGN="top"
804><A
805HREF="a16506.htm"
806ACCESSKEY="P"
807>Prev</A
808></TD
809><TD
810WIDTH="34%"
811ALIGN="center"
812VALIGN="top"
813><A
814HREF="book1.htm"
815ACCESSKEY="H"
816>Home</A
817></TD
818><TD
819WIDTH="33%"
820ALIGN="right"
821VALIGN="top"
822><A
823HREF="a16721.htm"
824ACCESSKEY="N"
825>Next</A
826></TD
827></TR
828><TR
829><TD
830WIDTH="33%"
831ALIGN="left"
832VALIGN="top"
833>Video For Linux Two Header File</TD
834><TD
835WIDTH="34%"
836ALIGN="center"
837VALIGN="top"
838>&nbsp;</TD
839><TD
840WIDTH="33%"
841ALIGN="right"
842VALIGN="top"
843>GNU Free Documentation License</TD
844></TR
845></TABLE
846></DIV
847></BODY
848></HTML
849>
850