1059b1c5bSMauro Carvalho Chehab.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
254f38fcaSMauro Carvalho Chehab
354f38fcaSMauro Carvalho Chehabfile: media/v4l/capture.c
454f38fcaSMauro Carvalho Chehab=========================
554f38fcaSMauro Carvalho Chehab
654f38fcaSMauro Carvalho Chehab.. code-block:: c
754f38fcaSMauro Carvalho Chehab
854f38fcaSMauro Carvalho Chehab    /*
954f38fcaSMauro Carvalho Chehab     *  V4L2 video capture example
1054f38fcaSMauro Carvalho Chehab     *
1154f38fcaSMauro Carvalho Chehab     *  This program can be used and distributed without restrictions.
1254f38fcaSMauro Carvalho Chehab     *
1354f38fcaSMauro Carvalho Chehab     *      This program is provided with the V4L2 API
1454f38fcaSMauro Carvalho Chehab     * see https://linuxtv.org/docs.php for more information
1554f38fcaSMauro Carvalho Chehab     */
1654f38fcaSMauro Carvalho Chehab
1754f38fcaSMauro Carvalho Chehab    #include <stdio.h>
1854f38fcaSMauro Carvalho Chehab    #include <stdlib.h>
1954f38fcaSMauro Carvalho Chehab    #include <string.h>
2054f38fcaSMauro Carvalho Chehab    #include <assert.h>
2154f38fcaSMauro Carvalho Chehab
2254f38fcaSMauro Carvalho Chehab    #include <getopt.h>             /* getopt_long() */
2354f38fcaSMauro Carvalho Chehab
2454f38fcaSMauro Carvalho Chehab    #include <fcntl.h>              /* low-level i/o */
2554f38fcaSMauro Carvalho Chehab    #include <unistd.h>
2654f38fcaSMauro Carvalho Chehab    #include <errno.h>
2754f38fcaSMauro Carvalho Chehab    #include <sys/stat.h>
2854f38fcaSMauro Carvalho Chehab    #include <sys/types.h>
2954f38fcaSMauro Carvalho Chehab    #include <sys/time.h>
3054f38fcaSMauro Carvalho Chehab    #include <sys/mman.h>
3154f38fcaSMauro Carvalho Chehab    #include <sys/ioctl.h>
3254f38fcaSMauro Carvalho Chehab
3354f38fcaSMauro Carvalho Chehab    #include <linux/videodev2.h>
3454f38fcaSMauro Carvalho Chehab
3554f38fcaSMauro Carvalho Chehab    #define CLEAR(x) memset(&(x), 0, sizeof(x))
3654f38fcaSMauro Carvalho Chehab
3754f38fcaSMauro Carvalho Chehab    enum io_method {
3854f38fcaSMauro Carvalho Chehab	    IO_METHOD_READ,
3954f38fcaSMauro Carvalho Chehab	    IO_METHOD_MMAP,
4054f38fcaSMauro Carvalho Chehab	    IO_METHOD_USERPTR,
4154f38fcaSMauro Carvalho Chehab    };
4254f38fcaSMauro Carvalho Chehab
4354f38fcaSMauro Carvalho Chehab    struct buffer {
4454f38fcaSMauro Carvalho Chehab	    void   *start;
4554f38fcaSMauro Carvalho Chehab	    size_t  length;
4654f38fcaSMauro Carvalho Chehab    };
4754f38fcaSMauro Carvalho Chehab
4854f38fcaSMauro Carvalho Chehab    static char            *dev_name;
4954f38fcaSMauro Carvalho Chehab    static enum io_method   io = IO_METHOD_MMAP;
5054f38fcaSMauro Carvalho Chehab    static int              fd = -1;
5154f38fcaSMauro Carvalho Chehab    struct buffer          *buffers;
5254f38fcaSMauro Carvalho Chehab    static unsigned int     n_buffers;
5354f38fcaSMauro Carvalho Chehab    static int              out_buf;
5454f38fcaSMauro Carvalho Chehab    static int              force_format;
5554f38fcaSMauro Carvalho Chehab    static int              frame_count = 70;
5654f38fcaSMauro Carvalho Chehab
5754f38fcaSMauro Carvalho Chehab    static void errno_exit(const char *s)
5854f38fcaSMauro Carvalho Chehab    {
59*d7894721SKwang Son	    fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno));
6054f38fcaSMauro Carvalho Chehab	    exit(EXIT_FAILURE);
6154f38fcaSMauro Carvalho Chehab    }
6254f38fcaSMauro Carvalho Chehab
6354f38fcaSMauro Carvalho Chehab    static int xioctl(int fh, int request, void *arg)
6454f38fcaSMauro Carvalho Chehab    {
6554f38fcaSMauro Carvalho Chehab	    int r;
6654f38fcaSMauro Carvalho Chehab
6754f38fcaSMauro Carvalho Chehab	    do {
6854f38fcaSMauro Carvalho Chehab		    r = ioctl(fh, request, arg);
6954f38fcaSMauro Carvalho Chehab	    } while (-1 == r && EINTR == errno);
7054f38fcaSMauro Carvalho Chehab
7154f38fcaSMauro Carvalho Chehab	    return r;
7254f38fcaSMauro Carvalho Chehab    }
7354f38fcaSMauro Carvalho Chehab
7454f38fcaSMauro Carvalho Chehab    static void process_image(const void *p, int size)
7554f38fcaSMauro Carvalho Chehab    {
7654f38fcaSMauro Carvalho Chehab	    if (out_buf)
7754f38fcaSMauro Carvalho Chehab		    fwrite(p, size, 1, stdout);
7854f38fcaSMauro Carvalho Chehab
7954f38fcaSMauro Carvalho Chehab	    fflush(stderr);
8054f38fcaSMauro Carvalho Chehab	    fprintf(stderr, ".");
8154f38fcaSMauro Carvalho Chehab	    fflush(stdout);
8254f38fcaSMauro Carvalho Chehab    }
8354f38fcaSMauro Carvalho Chehab
8454f38fcaSMauro Carvalho Chehab    static int read_frame(void)
8554f38fcaSMauro Carvalho Chehab    {
8654f38fcaSMauro Carvalho Chehab	    struct v4l2_buffer buf;
8754f38fcaSMauro Carvalho Chehab	    unsigned int i;
8854f38fcaSMauro Carvalho Chehab
8954f38fcaSMauro Carvalho Chehab	    switch (io) {
9054f38fcaSMauro Carvalho Chehab	    case IO_METHOD_READ:
9154f38fcaSMauro Carvalho Chehab		    if (-1 == read(fd, buffers[0].start, buffers[0].length)) {
9254f38fcaSMauro Carvalho Chehab			    switch (errno) {
9354f38fcaSMauro Carvalho Chehab			    case EAGAIN:
9454f38fcaSMauro Carvalho Chehab				    return 0;
9554f38fcaSMauro Carvalho Chehab
9654f38fcaSMauro Carvalho Chehab			    case EIO:
9754f38fcaSMauro Carvalho Chehab				    /* Could ignore EIO, see spec. */
9854f38fcaSMauro Carvalho Chehab
9954f38fcaSMauro Carvalho Chehab				    /* fall through */
10054f38fcaSMauro Carvalho Chehab
10154f38fcaSMauro Carvalho Chehab			    default:
10254f38fcaSMauro Carvalho Chehab				    errno_exit("read");
10354f38fcaSMauro Carvalho Chehab			    }
10454f38fcaSMauro Carvalho Chehab		    }
10554f38fcaSMauro Carvalho Chehab
10654f38fcaSMauro Carvalho Chehab		    process_image(buffers[0].start, buffers[0].length);
10754f38fcaSMauro Carvalho Chehab		    break;
10854f38fcaSMauro Carvalho Chehab
10954f38fcaSMauro Carvalho Chehab	    case IO_METHOD_MMAP:
11054f38fcaSMauro Carvalho Chehab		    CLEAR(buf);
11154f38fcaSMauro Carvalho Chehab
11254f38fcaSMauro Carvalho Chehab		    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
11354f38fcaSMauro Carvalho Chehab		    buf.memory = V4L2_MEMORY_MMAP;
11454f38fcaSMauro Carvalho Chehab
11554f38fcaSMauro Carvalho Chehab		    if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
11654f38fcaSMauro Carvalho Chehab			    switch (errno) {
11754f38fcaSMauro Carvalho Chehab			    case EAGAIN:
11854f38fcaSMauro Carvalho Chehab				    return 0;
11954f38fcaSMauro Carvalho Chehab
12054f38fcaSMauro Carvalho Chehab			    case EIO:
12154f38fcaSMauro Carvalho Chehab				    /* Could ignore EIO, see spec. */
12254f38fcaSMauro Carvalho Chehab
12354f38fcaSMauro Carvalho Chehab				    /* fall through */
12454f38fcaSMauro Carvalho Chehab
12554f38fcaSMauro Carvalho Chehab			    default:
12654f38fcaSMauro Carvalho Chehab				    errno_exit("VIDIOC_DQBUF");
12754f38fcaSMauro Carvalho Chehab			    }
12854f38fcaSMauro Carvalho Chehab		    }
12954f38fcaSMauro Carvalho Chehab
13054f38fcaSMauro Carvalho Chehab		    assert(buf.index < n_buffers);
13154f38fcaSMauro Carvalho Chehab
13254f38fcaSMauro Carvalho Chehab		    process_image(buffers[buf.index].start, buf.bytesused);
13354f38fcaSMauro Carvalho Chehab
13454f38fcaSMauro Carvalho Chehab		    if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
13554f38fcaSMauro Carvalho Chehab			    errno_exit("VIDIOC_QBUF");
13654f38fcaSMauro Carvalho Chehab		    break;
13754f38fcaSMauro Carvalho Chehab
13854f38fcaSMauro Carvalho Chehab	    case IO_METHOD_USERPTR:
13954f38fcaSMauro Carvalho Chehab		    CLEAR(buf);
14054f38fcaSMauro Carvalho Chehab
14154f38fcaSMauro Carvalho Chehab		    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
14254f38fcaSMauro Carvalho Chehab		    buf.memory = V4L2_MEMORY_USERPTR;
14354f38fcaSMauro Carvalho Chehab
14454f38fcaSMauro Carvalho Chehab		    if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
14554f38fcaSMauro Carvalho Chehab			    switch (errno) {
14654f38fcaSMauro Carvalho Chehab			    case EAGAIN:
14754f38fcaSMauro Carvalho Chehab				    return 0;
14854f38fcaSMauro Carvalho Chehab
14954f38fcaSMauro Carvalho Chehab			    case EIO:
15054f38fcaSMauro Carvalho Chehab				    /* Could ignore EIO, see spec. */
15154f38fcaSMauro Carvalho Chehab
15254f38fcaSMauro Carvalho Chehab				    /* fall through */
15354f38fcaSMauro Carvalho Chehab
15454f38fcaSMauro Carvalho Chehab			    default:
15554f38fcaSMauro Carvalho Chehab				    errno_exit("VIDIOC_DQBUF");
15654f38fcaSMauro Carvalho Chehab			    }
15754f38fcaSMauro Carvalho Chehab		    }
15854f38fcaSMauro Carvalho Chehab
15954f38fcaSMauro Carvalho Chehab		    for (i = 0; i < n_buffers; ++i)
16054f38fcaSMauro Carvalho Chehab			    if (buf.m.userptr == (unsigned long)buffers[i].start
16154f38fcaSMauro Carvalho Chehab				&& buf.length == buffers[i].length)
16254f38fcaSMauro Carvalho Chehab				    break;
16354f38fcaSMauro Carvalho Chehab
16454f38fcaSMauro Carvalho Chehab		    assert(i < n_buffers);
16554f38fcaSMauro Carvalho Chehab
16654f38fcaSMauro Carvalho Chehab		    process_image((void *)buf.m.userptr, buf.bytesused);
16754f38fcaSMauro Carvalho Chehab
16854f38fcaSMauro Carvalho Chehab		    if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
16954f38fcaSMauro Carvalho Chehab			    errno_exit("VIDIOC_QBUF");
17054f38fcaSMauro Carvalho Chehab		    break;
17154f38fcaSMauro Carvalho Chehab	    }
17254f38fcaSMauro Carvalho Chehab
17354f38fcaSMauro Carvalho Chehab	    return 1;
17454f38fcaSMauro Carvalho Chehab    }
17554f38fcaSMauro Carvalho Chehab
17654f38fcaSMauro Carvalho Chehab    static void mainloop(void)
17754f38fcaSMauro Carvalho Chehab    {
17854f38fcaSMauro Carvalho Chehab	    unsigned int count;
17954f38fcaSMauro Carvalho Chehab
18054f38fcaSMauro Carvalho Chehab	    count = frame_count;
18154f38fcaSMauro Carvalho Chehab
18254f38fcaSMauro Carvalho Chehab	    while (count-- > 0) {
18354f38fcaSMauro Carvalho Chehab		    for (;;) {
18454f38fcaSMauro Carvalho Chehab			    fd_set fds;
18554f38fcaSMauro Carvalho Chehab			    struct timeval tv;
18654f38fcaSMauro Carvalho Chehab			    int r;
18754f38fcaSMauro Carvalho Chehab
18854f38fcaSMauro Carvalho Chehab			    FD_ZERO(&fds);
18954f38fcaSMauro Carvalho Chehab			    FD_SET(fd, &fds);
19054f38fcaSMauro Carvalho Chehab
19154f38fcaSMauro Carvalho Chehab			    /* Timeout. */
19254f38fcaSMauro Carvalho Chehab			    tv.tv_sec = 2;
19354f38fcaSMauro Carvalho Chehab			    tv.tv_usec = 0;
19454f38fcaSMauro Carvalho Chehab
19554f38fcaSMauro Carvalho Chehab			    r = select(fd + 1, &fds, NULL, NULL, &tv);
19654f38fcaSMauro Carvalho Chehab
19754f38fcaSMauro Carvalho Chehab			    if (-1 == r) {
19854f38fcaSMauro Carvalho Chehab				    if (EINTR == errno)
19954f38fcaSMauro Carvalho Chehab					    continue;
20054f38fcaSMauro Carvalho Chehab				    errno_exit("select");
20154f38fcaSMauro Carvalho Chehab			    }
20254f38fcaSMauro Carvalho Chehab
20354f38fcaSMauro Carvalho Chehab			    if (0 == r) {
204*d7894721SKwang Son				    fprintf(stderr, "select timeout\n");
20554f38fcaSMauro Carvalho Chehab				    exit(EXIT_FAILURE);
20654f38fcaSMauro Carvalho Chehab			    }
20754f38fcaSMauro Carvalho Chehab
20854f38fcaSMauro Carvalho Chehab			    if (read_frame())
20954f38fcaSMauro Carvalho Chehab				    break;
21054f38fcaSMauro Carvalho Chehab			    /* EAGAIN - continue select loop. */
21154f38fcaSMauro Carvalho Chehab		    }
21254f38fcaSMauro Carvalho Chehab	    }
21354f38fcaSMauro Carvalho Chehab    }
21454f38fcaSMauro Carvalho Chehab
21554f38fcaSMauro Carvalho Chehab    static void stop_capturing(void)
21654f38fcaSMauro Carvalho Chehab    {
21754f38fcaSMauro Carvalho Chehab	    enum v4l2_buf_type type;
21854f38fcaSMauro Carvalho Chehab
21954f38fcaSMauro Carvalho Chehab	    switch (io) {
22054f38fcaSMauro Carvalho Chehab	    case IO_METHOD_READ:
22154f38fcaSMauro Carvalho Chehab		    /* Nothing to do. */
22254f38fcaSMauro Carvalho Chehab		    break;
22354f38fcaSMauro Carvalho Chehab
22454f38fcaSMauro Carvalho Chehab	    case IO_METHOD_MMAP:
22554f38fcaSMauro Carvalho Chehab	    case IO_METHOD_USERPTR:
22654f38fcaSMauro Carvalho Chehab		    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
22754f38fcaSMauro Carvalho Chehab		    if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type))
22854f38fcaSMauro Carvalho Chehab			    errno_exit("VIDIOC_STREAMOFF");
22954f38fcaSMauro Carvalho Chehab		    break;
23054f38fcaSMauro Carvalho Chehab	    }
23154f38fcaSMauro Carvalho Chehab    }
23254f38fcaSMauro Carvalho Chehab
23354f38fcaSMauro Carvalho Chehab    static void start_capturing(void)
23454f38fcaSMauro Carvalho Chehab    {
23554f38fcaSMauro Carvalho Chehab	    unsigned int i;
23654f38fcaSMauro Carvalho Chehab	    enum v4l2_buf_type type;
23754f38fcaSMauro Carvalho Chehab
23854f38fcaSMauro Carvalho Chehab	    switch (io) {
23954f38fcaSMauro Carvalho Chehab	    case IO_METHOD_READ:
24054f38fcaSMauro Carvalho Chehab		    /* Nothing to do. */
24154f38fcaSMauro Carvalho Chehab		    break;
24254f38fcaSMauro Carvalho Chehab
24354f38fcaSMauro Carvalho Chehab	    case IO_METHOD_MMAP:
24454f38fcaSMauro Carvalho Chehab		    for (i = 0; i < n_buffers; ++i) {
24554f38fcaSMauro Carvalho Chehab			    struct v4l2_buffer buf;
24654f38fcaSMauro Carvalho Chehab
24754f38fcaSMauro Carvalho Chehab			    CLEAR(buf);
24854f38fcaSMauro Carvalho Chehab			    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
24954f38fcaSMauro Carvalho Chehab			    buf.memory = V4L2_MEMORY_MMAP;
25054f38fcaSMauro Carvalho Chehab			    buf.index = i;
25154f38fcaSMauro Carvalho Chehab
25254f38fcaSMauro Carvalho Chehab			    if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
25354f38fcaSMauro Carvalho Chehab				    errno_exit("VIDIOC_QBUF");
25454f38fcaSMauro Carvalho Chehab		    }
25554f38fcaSMauro Carvalho Chehab		    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
25654f38fcaSMauro Carvalho Chehab		    if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
25754f38fcaSMauro Carvalho Chehab			    errno_exit("VIDIOC_STREAMON");
25854f38fcaSMauro Carvalho Chehab		    break;
25954f38fcaSMauro Carvalho Chehab
26054f38fcaSMauro Carvalho Chehab	    case IO_METHOD_USERPTR:
26154f38fcaSMauro Carvalho Chehab		    for (i = 0; i < n_buffers; ++i) {
26254f38fcaSMauro Carvalho Chehab			    struct v4l2_buffer buf;
26354f38fcaSMauro Carvalho Chehab
26454f38fcaSMauro Carvalho Chehab			    CLEAR(buf);
26554f38fcaSMauro Carvalho Chehab			    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
26654f38fcaSMauro Carvalho Chehab			    buf.memory = V4L2_MEMORY_USERPTR;
26754f38fcaSMauro Carvalho Chehab			    buf.index = i;
26854f38fcaSMauro Carvalho Chehab			    buf.m.userptr = (unsigned long)buffers[i].start;
26954f38fcaSMauro Carvalho Chehab			    buf.length = buffers[i].length;
27054f38fcaSMauro Carvalho Chehab
27154f38fcaSMauro Carvalho Chehab			    if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
27254f38fcaSMauro Carvalho Chehab				    errno_exit("VIDIOC_QBUF");
27354f38fcaSMauro Carvalho Chehab		    }
27454f38fcaSMauro Carvalho Chehab		    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
27554f38fcaSMauro Carvalho Chehab		    if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
27654f38fcaSMauro Carvalho Chehab			    errno_exit("VIDIOC_STREAMON");
27754f38fcaSMauro Carvalho Chehab		    break;
27854f38fcaSMauro Carvalho Chehab	    }
27954f38fcaSMauro Carvalho Chehab    }
28054f38fcaSMauro Carvalho Chehab
28154f38fcaSMauro Carvalho Chehab    static void uninit_device(void)
28254f38fcaSMauro Carvalho Chehab    {
28354f38fcaSMauro Carvalho Chehab	    unsigned int i;
28454f38fcaSMauro Carvalho Chehab
28554f38fcaSMauro Carvalho Chehab	    switch (io) {
28654f38fcaSMauro Carvalho Chehab	    case IO_METHOD_READ:
28754f38fcaSMauro Carvalho Chehab		    free(buffers[0].start);
28854f38fcaSMauro Carvalho Chehab		    break;
28954f38fcaSMauro Carvalho Chehab
29054f38fcaSMauro Carvalho Chehab	    case IO_METHOD_MMAP:
29154f38fcaSMauro Carvalho Chehab		    for (i = 0; i < n_buffers; ++i)
29254f38fcaSMauro Carvalho Chehab			    if (-1 == munmap(buffers[i].start, buffers[i].length))
29354f38fcaSMauro Carvalho Chehab				    errno_exit("munmap");
29454f38fcaSMauro Carvalho Chehab		    break;
29554f38fcaSMauro Carvalho Chehab
29654f38fcaSMauro Carvalho Chehab	    case IO_METHOD_USERPTR:
29754f38fcaSMauro Carvalho Chehab		    for (i = 0; i < n_buffers; ++i)
29854f38fcaSMauro Carvalho Chehab			    free(buffers[i].start);
29954f38fcaSMauro Carvalho Chehab		    break;
30054f38fcaSMauro Carvalho Chehab	    }
30154f38fcaSMauro Carvalho Chehab
30254f38fcaSMauro Carvalho Chehab	    free(buffers);
30354f38fcaSMauro Carvalho Chehab    }
30454f38fcaSMauro Carvalho Chehab
30554f38fcaSMauro Carvalho Chehab    static void init_read(unsigned int buffer_size)
30654f38fcaSMauro Carvalho Chehab    {
30754f38fcaSMauro Carvalho Chehab	    buffers = calloc(1, sizeof(*buffers));
30854f38fcaSMauro Carvalho Chehab
30954f38fcaSMauro Carvalho Chehab	    if (!buffers) {
310*d7894721SKwang Son		    fprintf(stderr, "Out of memory\n");
31154f38fcaSMauro Carvalho Chehab		    exit(EXIT_FAILURE);
31254f38fcaSMauro Carvalho Chehab	    }
31354f38fcaSMauro Carvalho Chehab
31454f38fcaSMauro Carvalho Chehab	    buffers[0].length = buffer_size;
31554f38fcaSMauro Carvalho Chehab	    buffers[0].start = malloc(buffer_size);
31654f38fcaSMauro Carvalho Chehab
31754f38fcaSMauro Carvalho Chehab	    if (!buffers[0].start) {
318*d7894721SKwang Son		    fprintf(stderr, "Out of memory\n");
31954f38fcaSMauro Carvalho Chehab		    exit(EXIT_FAILURE);
32054f38fcaSMauro Carvalho Chehab	    }
32154f38fcaSMauro Carvalho Chehab    }
32254f38fcaSMauro Carvalho Chehab
32354f38fcaSMauro Carvalho Chehab    static void init_mmap(void)
32454f38fcaSMauro Carvalho Chehab    {
32554f38fcaSMauro Carvalho Chehab	    struct v4l2_requestbuffers req;
32654f38fcaSMauro Carvalho Chehab
32754f38fcaSMauro Carvalho Chehab	    CLEAR(req);
32854f38fcaSMauro Carvalho Chehab
32954f38fcaSMauro Carvalho Chehab	    req.count = 4;
33054f38fcaSMauro Carvalho Chehab	    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
33154f38fcaSMauro Carvalho Chehab	    req.memory = V4L2_MEMORY_MMAP;
33254f38fcaSMauro Carvalho Chehab
33354f38fcaSMauro Carvalho Chehab	    if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
33454f38fcaSMauro Carvalho Chehab		    if (EINVAL == errno) {
33554f38fcaSMauro Carvalho Chehab			    fprintf(stderr, "%s does not support "
33654f38fcaSMauro Carvalho Chehab				     "memory mappingn", dev_name);
33754f38fcaSMauro Carvalho Chehab			    exit(EXIT_FAILURE);
33854f38fcaSMauro Carvalho Chehab		    } else {
33954f38fcaSMauro Carvalho Chehab			    errno_exit("VIDIOC_REQBUFS");
34054f38fcaSMauro Carvalho Chehab		    }
34154f38fcaSMauro Carvalho Chehab	    }
34254f38fcaSMauro Carvalho Chehab
34354f38fcaSMauro Carvalho Chehab	    if (req.count < 2) {
344*d7894721SKwang Son		    fprintf(stderr, "Insufficient buffer memory on %s\n",
34554f38fcaSMauro Carvalho Chehab			     dev_name);
34654f38fcaSMauro Carvalho Chehab		    exit(EXIT_FAILURE);
34754f38fcaSMauro Carvalho Chehab	    }
34854f38fcaSMauro Carvalho Chehab
34954f38fcaSMauro Carvalho Chehab	    buffers = calloc(req.count, sizeof(*buffers));
35054f38fcaSMauro Carvalho Chehab
35154f38fcaSMauro Carvalho Chehab	    if (!buffers) {
352*d7894721SKwang Son		    fprintf(stderr, "Out of memory\n");
35354f38fcaSMauro Carvalho Chehab		    exit(EXIT_FAILURE);
35454f38fcaSMauro Carvalho Chehab	    }
35554f38fcaSMauro Carvalho Chehab
35654f38fcaSMauro Carvalho Chehab	    for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
35754f38fcaSMauro Carvalho Chehab		    struct v4l2_buffer buf;
35854f38fcaSMauro Carvalho Chehab
35954f38fcaSMauro Carvalho Chehab		    CLEAR(buf);
36054f38fcaSMauro Carvalho Chehab
36154f38fcaSMauro Carvalho Chehab		    buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
36254f38fcaSMauro Carvalho Chehab		    buf.memory      = V4L2_MEMORY_MMAP;
36354f38fcaSMauro Carvalho Chehab		    buf.index       = n_buffers;
36454f38fcaSMauro Carvalho Chehab
36554f38fcaSMauro Carvalho Chehab		    if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
36654f38fcaSMauro Carvalho Chehab			    errno_exit("VIDIOC_QUERYBUF");
36754f38fcaSMauro Carvalho Chehab
36854f38fcaSMauro Carvalho Chehab		    buffers[n_buffers].length = buf.length;
36954f38fcaSMauro Carvalho Chehab		    buffers[n_buffers].start =
37054f38fcaSMauro Carvalho Chehab			    mmap(NULL /* start anywhere */,
37154f38fcaSMauro Carvalho Chehab				  buf.length,
37254f38fcaSMauro Carvalho Chehab				  PROT_READ | PROT_WRITE /* required */,
37354f38fcaSMauro Carvalho Chehab				  MAP_SHARED /* recommended */,
37454f38fcaSMauro Carvalho Chehab				  fd, buf.m.offset);
37554f38fcaSMauro Carvalho Chehab
37654f38fcaSMauro Carvalho Chehab		    if (MAP_FAILED == buffers[n_buffers].start)
37754f38fcaSMauro Carvalho Chehab			    errno_exit("mmap");
37854f38fcaSMauro Carvalho Chehab	    }
37954f38fcaSMauro Carvalho Chehab    }
38054f38fcaSMauro Carvalho Chehab
38154f38fcaSMauro Carvalho Chehab    static void init_userp(unsigned int buffer_size)
38254f38fcaSMauro Carvalho Chehab    {
38354f38fcaSMauro Carvalho Chehab	    struct v4l2_requestbuffers req;
38454f38fcaSMauro Carvalho Chehab
38554f38fcaSMauro Carvalho Chehab	    CLEAR(req);
38654f38fcaSMauro Carvalho Chehab
38754f38fcaSMauro Carvalho Chehab	    req.count  = 4;
38854f38fcaSMauro Carvalho Chehab	    req.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
38954f38fcaSMauro Carvalho Chehab	    req.memory = V4L2_MEMORY_USERPTR;
39054f38fcaSMauro Carvalho Chehab
39154f38fcaSMauro Carvalho Chehab	    if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
39254f38fcaSMauro Carvalho Chehab		    if (EINVAL == errno) {
39354f38fcaSMauro Carvalho Chehab			    fprintf(stderr, "%s does not support "
39454f38fcaSMauro Carvalho Chehab				     "user pointer i/on", dev_name);
39554f38fcaSMauro Carvalho Chehab			    exit(EXIT_FAILURE);
39654f38fcaSMauro Carvalho Chehab		    } else {
39754f38fcaSMauro Carvalho Chehab			    errno_exit("VIDIOC_REQBUFS");
39854f38fcaSMauro Carvalho Chehab		    }
39954f38fcaSMauro Carvalho Chehab	    }
40054f38fcaSMauro Carvalho Chehab
40154f38fcaSMauro Carvalho Chehab	    buffers = calloc(4, sizeof(*buffers));
40254f38fcaSMauro Carvalho Chehab
40354f38fcaSMauro Carvalho Chehab	    if (!buffers) {
404*d7894721SKwang Son		    fprintf(stderr, "Out of memory\n");
40554f38fcaSMauro Carvalho Chehab		    exit(EXIT_FAILURE);
40654f38fcaSMauro Carvalho Chehab	    }
40754f38fcaSMauro Carvalho Chehab
40854f38fcaSMauro Carvalho Chehab	    for (n_buffers = 0; n_buffers < 4; ++n_buffers) {
40954f38fcaSMauro Carvalho Chehab		    buffers[n_buffers].length = buffer_size;
41054f38fcaSMauro Carvalho Chehab		    buffers[n_buffers].start = malloc(buffer_size);
41154f38fcaSMauro Carvalho Chehab
41254f38fcaSMauro Carvalho Chehab		    if (!buffers[n_buffers].start) {
413*d7894721SKwang Son			    fprintf(stderr, "Out of memory\n");
41454f38fcaSMauro Carvalho Chehab			    exit(EXIT_FAILURE);
41554f38fcaSMauro Carvalho Chehab		    }
41654f38fcaSMauro Carvalho Chehab	    }
41754f38fcaSMauro Carvalho Chehab    }
41854f38fcaSMauro Carvalho Chehab
41954f38fcaSMauro Carvalho Chehab    static void init_device(void)
42054f38fcaSMauro Carvalho Chehab    {
42154f38fcaSMauro Carvalho Chehab	    struct v4l2_capability cap;
42254f38fcaSMauro Carvalho Chehab	    struct v4l2_cropcap cropcap;
42354f38fcaSMauro Carvalho Chehab	    struct v4l2_crop crop;
42454f38fcaSMauro Carvalho Chehab	    struct v4l2_format fmt;
42554f38fcaSMauro Carvalho Chehab	    unsigned int min;
42654f38fcaSMauro Carvalho Chehab
42754f38fcaSMauro Carvalho Chehab	    if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) {
42854f38fcaSMauro Carvalho Chehab		    if (EINVAL == errno) {
429*d7894721SKwang Son			    fprintf(stderr, "%s is no V4L2 device\n",
43054f38fcaSMauro Carvalho Chehab				     dev_name);
43154f38fcaSMauro Carvalho Chehab			    exit(EXIT_FAILURE);
43254f38fcaSMauro Carvalho Chehab		    } else {
43354f38fcaSMauro Carvalho Chehab			    errno_exit("VIDIOC_QUERYCAP");
43454f38fcaSMauro Carvalho Chehab		    }
43554f38fcaSMauro Carvalho Chehab	    }
43654f38fcaSMauro Carvalho Chehab
43754f38fcaSMauro Carvalho Chehab	    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
438*d7894721SKwang Son		    fprintf(stderr, "%s is no video capture device\n",
43954f38fcaSMauro Carvalho Chehab			     dev_name);
44054f38fcaSMauro Carvalho Chehab		    exit(EXIT_FAILURE);
44154f38fcaSMauro Carvalho Chehab	    }
44254f38fcaSMauro Carvalho Chehab
44354f38fcaSMauro Carvalho Chehab	    switch (io) {
44454f38fcaSMauro Carvalho Chehab	    case IO_METHOD_READ:
44554f38fcaSMauro Carvalho Chehab		    if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
446*d7894721SKwang Son			    fprintf(stderr, "%s does not support read i/o\n",
44754f38fcaSMauro Carvalho Chehab				     dev_name);
44854f38fcaSMauro Carvalho Chehab			    exit(EXIT_FAILURE);
44954f38fcaSMauro Carvalho Chehab		    }
45054f38fcaSMauro Carvalho Chehab		    break;
45154f38fcaSMauro Carvalho Chehab
45254f38fcaSMauro Carvalho Chehab	    case IO_METHOD_MMAP:
45354f38fcaSMauro Carvalho Chehab	    case IO_METHOD_USERPTR:
45454f38fcaSMauro Carvalho Chehab		    if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
455*d7894721SKwang Son			    fprintf(stderr, "%s does not support streaming i/o\n",
45654f38fcaSMauro Carvalho Chehab				     dev_name);
45754f38fcaSMauro Carvalho Chehab			    exit(EXIT_FAILURE);
45854f38fcaSMauro Carvalho Chehab		    }
45954f38fcaSMauro Carvalho Chehab		    break;
46054f38fcaSMauro Carvalho Chehab	    }
46154f38fcaSMauro Carvalho Chehab
46254f38fcaSMauro Carvalho Chehab
46354f38fcaSMauro Carvalho Chehab	    /* Select video input, video standard and tune here. */
46454f38fcaSMauro Carvalho Chehab
46554f38fcaSMauro Carvalho Chehab
46654f38fcaSMauro Carvalho Chehab	    CLEAR(cropcap);
46754f38fcaSMauro Carvalho Chehab
46854f38fcaSMauro Carvalho Chehab	    cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
46954f38fcaSMauro Carvalho Chehab
47054f38fcaSMauro Carvalho Chehab	    if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
47154f38fcaSMauro Carvalho Chehab		    crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
47254f38fcaSMauro Carvalho Chehab		    crop.c = cropcap.defrect; /* reset to default */
47354f38fcaSMauro Carvalho Chehab
47454f38fcaSMauro Carvalho Chehab		    if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
47554f38fcaSMauro Carvalho Chehab			    switch (errno) {
47654f38fcaSMauro Carvalho Chehab			    case EINVAL:
47754f38fcaSMauro Carvalho Chehab				    /* Cropping not supported. */
47854f38fcaSMauro Carvalho Chehab				    break;
47954f38fcaSMauro Carvalho Chehab			    default:
48054f38fcaSMauro Carvalho Chehab				    /* Errors ignored. */
48154f38fcaSMauro Carvalho Chehab				    break;
48254f38fcaSMauro Carvalho Chehab			    }
48354f38fcaSMauro Carvalho Chehab		    }
48454f38fcaSMauro Carvalho Chehab	    } else {
48554f38fcaSMauro Carvalho Chehab		    /* Errors ignored. */
48654f38fcaSMauro Carvalho Chehab	    }
48754f38fcaSMauro Carvalho Chehab
48854f38fcaSMauro Carvalho Chehab
48954f38fcaSMauro Carvalho Chehab	    CLEAR(fmt);
49054f38fcaSMauro Carvalho Chehab
49154f38fcaSMauro Carvalho Chehab	    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
49254f38fcaSMauro Carvalho Chehab	    if (force_format) {
49354f38fcaSMauro Carvalho Chehab		    fmt.fmt.pix.width       = 640;
49454f38fcaSMauro Carvalho Chehab		    fmt.fmt.pix.height      = 480;
49554f38fcaSMauro Carvalho Chehab		    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
49654f38fcaSMauro Carvalho Chehab		    fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
49754f38fcaSMauro Carvalho Chehab
49854f38fcaSMauro Carvalho Chehab		    if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
49954f38fcaSMauro Carvalho Chehab			    errno_exit("VIDIOC_S_FMT");
50054f38fcaSMauro Carvalho Chehab
50154f38fcaSMauro Carvalho Chehab		    /* Note VIDIOC_S_FMT may change width and height. */
50254f38fcaSMauro Carvalho Chehab	    } else {
50354f38fcaSMauro Carvalho Chehab		    /* Preserve original settings as set by v4l2-ctl for example */
50454f38fcaSMauro Carvalho Chehab		    if (-1 == xioctl(fd, VIDIOC_G_FMT, &fmt))
50554f38fcaSMauro Carvalho Chehab			    errno_exit("VIDIOC_G_FMT");
50654f38fcaSMauro Carvalho Chehab	    }
50754f38fcaSMauro Carvalho Chehab
50854f38fcaSMauro Carvalho Chehab	    /* Buggy driver paranoia. */
50954f38fcaSMauro Carvalho Chehab	    min = fmt.fmt.pix.width * 2;
51054f38fcaSMauro Carvalho Chehab	    if (fmt.fmt.pix.bytesperline < min)
51154f38fcaSMauro Carvalho Chehab		    fmt.fmt.pix.bytesperline = min;
51254f38fcaSMauro Carvalho Chehab	    min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
51354f38fcaSMauro Carvalho Chehab	    if (fmt.fmt.pix.sizeimage < min)
51454f38fcaSMauro Carvalho Chehab		    fmt.fmt.pix.sizeimage = min;
51554f38fcaSMauro Carvalho Chehab
51654f38fcaSMauro Carvalho Chehab	    switch (io) {
51754f38fcaSMauro Carvalho Chehab	    case IO_METHOD_READ:
51854f38fcaSMauro Carvalho Chehab		    init_read(fmt.fmt.pix.sizeimage);
51954f38fcaSMauro Carvalho Chehab		    break;
52054f38fcaSMauro Carvalho Chehab
52154f38fcaSMauro Carvalho Chehab	    case IO_METHOD_MMAP:
52254f38fcaSMauro Carvalho Chehab		    init_mmap();
52354f38fcaSMauro Carvalho Chehab		    break;
52454f38fcaSMauro Carvalho Chehab
52554f38fcaSMauro Carvalho Chehab	    case IO_METHOD_USERPTR:
52654f38fcaSMauro Carvalho Chehab		    init_userp(fmt.fmt.pix.sizeimage);
52754f38fcaSMauro Carvalho Chehab		    break;
52854f38fcaSMauro Carvalho Chehab	    }
52954f38fcaSMauro Carvalho Chehab    }
53054f38fcaSMauro Carvalho Chehab
53154f38fcaSMauro Carvalho Chehab    static void close_device(void)
53254f38fcaSMauro Carvalho Chehab    {
53354f38fcaSMauro Carvalho Chehab	    if (-1 == close(fd))
53454f38fcaSMauro Carvalho Chehab		    errno_exit("close");
53554f38fcaSMauro Carvalho Chehab
53654f38fcaSMauro Carvalho Chehab	    fd = -1;
53754f38fcaSMauro Carvalho Chehab    }
53854f38fcaSMauro Carvalho Chehab
53954f38fcaSMauro Carvalho Chehab    static void open_device(void)
54054f38fcaSMauro Carvalho Chehab    {
54154f38fcaSMauro Carvalho Chehab	    struct stat st;
54254f38fcaSMauro Carvalho Chehab
54354f38fcaSMauro Carvalho Chehab	    if (-1 == stat(dev_name, &st)) {
544*d7894721SKwang Son		    fprintf(stderr, "Cannot identify '%s': %d, %s\n",
54554f38fcaSMauro Carvalho Chehab			     dev_name, errno, strerror(errno));
54654f38fcaSMauro Carvalho Chehab		    exit(EXIT_FAILURE);
54754f38fcaSMauro Carvalho Chehab	    }
54854f38fcaSMauro Carvalho Chehab
54954f38fcaSMauro Carvalho Chehab	    if (!S_ISCHR(st.st_mode)) {
55054f38fcaSMauro Carvalho Chehab		    fprintf(stderr, "%s is no devicen", dev_name);
55154f38fcaSMauro Carvalho Chehab		    exit(EXIT_FAILURE);
55254f38fcaSMauro Carvalho Chehab	    }
55354f38fcaSMauro Carvalho Chehab
55454f38fcaSMauro Carvalho Chehab	    fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
55554f38fcaSMauro Carvalho Chehab
55654f38fcaSMauro Carvalho Chehab	    if (-1 == fd) {
557*d7894721SKwang Son		    fprintf(stderr, "Cannot open '%s': %d, %s\n",
55854f38fcaSMauro Carvalho Chehab			     dev_name, errno, strerror(errno));
55954f38fcaSMauro Carvalho Chehab		    exit(EXIT_FAILURE);
56054f38fcaSMauro Carvalho Chehab	    }
56154f38fcaSMauro Carvalho Chehab    }
56254f38fcaSMauro Carvalho Chehab
56354f38fcaSMauro Carvalho Chehab    static void usage(FILE *fp, int argc, char **argv)
56454f38fcaSMauro Carvalho Chehab    {
56554f38fcaSMauro Carvalho Chehab	    fprintf(fp,
566*d7894721SKwang Son		     "Usage: %s [options]\n\n"
567*d7894721SKwang Son		     "Version 1.3\n"
568*d7894721SKwang Son		     "Options:\n"
569*d7894721SKwang Son		     "-d | --device name   Video device name [%s]\n"
570*d7894721SKwang Son		     "-h | --help          Print this message\n"
571*d7894721SKwang Son		     "-m | --mmap          Use memory mapped buffers [default]\n"
572*d7894721SKwang Son		     "-r | --read          Use read() calls\n"
573*d7894721SKwang Son		     "-u | --userp         Use application allocated buffers\n"
574*d7894721SKwang Son		     "-o | --output        Outputs stream to stdout\n"
575*d7894721SKwang Son		     "-f | --format        Force format to 640x480 YUYV\n"
576*d7894721SKwang Son		     "-c | --count         Number of frames to grab [%i]\n"
57754f38fcaSMauro Carvalho Chehab		     "",
57854f38fcaSMauro Carvalho Chehab		     argv[0], dev_name, frame_count);
57954f38fcaSMauro Carvalho Chehab    }
58054f38fcaSMauro Carvalho Chehab
58154f38fcaSMauro Carvalho Chehab    static const char short_options[] = "d:hmruofc:";
58254f38fcaSMauro Carvalho Chehab
58354f38fcaSMauro Carvalho Chehab    static const struct option
58454f38fcaSMauro Carvalho Chehab    long_options[] = {
58554f38fcaSMauro Carvalho Chehab	    { "device", required_argument, NULL, 'd' },
58654f38fcaSMauro Carvalho Chehab	    { "help",   no_argument,       NULL, 'h' },
58754f38fcaSMauro Carvalho Chehab	    { "mmap",   no_argument,       NULL, 'm' },
58854f38fcaSMauro Carvalho Chehab	    { "read",   no_argument,       NULL, 'r' },
58954f38fcaSMauro Carvalho Chehab	    { "userp",  no_argument,       NULL, 'u' },
59054f38fcaSMauro Carvalho Chehab	    { "output", no_argument,       NULL, 'o' },
59154f38fcaSMauro Carvalho Chehab	    { "format", no_argument,       NULL, 'f' },
59254f38fcaSMauro Carvalho Chehab	    { "count",  required_argument, NULL, 'c' },
59354f38fcaSMauro Carvalho Chehab	    { 0, 0, 0, 0 }
59454f38fcaSMauro Carvalho Chehab    };
59554f38fcaSMauro Carvalho Chehab
59654f38fcaSMauro Carvalho Chehab    int main(int argc, char **argv)
59754f38fcaSMauro Carvalho Chehab    {
59854f38fcaSMauro Carvalho Chehab	    dev_name = "/dev/video0";
59954f38fcaSMauro Carvalho Chehab
60054f38fcaSMauro Carvalho Chehab	    for (;;) {
60154f38fcaSMauro Carvalho Chehab		    int idx;
60254f38fcaSMauro Carvalho Chehab		    int c;
60354f38fcaSMauro Carvalho Chehab
60454f38fcaSMauro Carvalho Chehab		    c = getopt_long(argc, argv,
60554f38fcaSMauro Carvalho Chehab				    short_options, long_options, &idx);
60654f38fcaSMauro Carvalho Chehab
60754f38fcaSMauro Carvalho Chehab		    if (-1 == c)
60854f38fcaSMauro Carvalho Chehab			    break;
60954f38fcaSMauro Carvalho Chehab
61054f38fcaSMauro Carvalho Chehab		    switch (c) {
61154f38fcaSMauro Carvalho Chehab		    case 0: /* getopt_long() flag */
61254f38fcaSMauro Carvalho Chehab			    break;
61354f38fcaSMauro Carvalho Chehab
61454f38fcaSMauro Carvalho Chehab		    case 'd':
61554f38fcaSMauro Carvalho Chehab			    dev_name = optarg;
61654f38fcaSMauro Carvalho Chehab			    break;
61754f38fcaSMauro Carvalho Chehab
61854f38fcaSMauro Carvalho Chehab		    case 'h':
61954f38fcaSMauro Carvalho Chehab			    usage(stdout, argc, argv);
62054f38fcaSMauro Carvalho Chehab			    exit(EXIT_SUCCESS);
62154f38fcaSMauro Carvalho Chehab
62254f38fcaSMauro Carvalho Chehab		    case 'm':
62354f38fcaSMauro Carvalho Chehab			    io = IO_METHOD_MMAP;
62454f38fcaSMauro Carvalho Chehab			    break;
62554f38fcaSMauro Carvalho Chehab
62654f38fcaSMauro Carvalho Chehab		    case 'r':
62754f38fcaSMauro Carvalho Chehab			    io = IO_METHOD_READ;
62854f38fcaSMauro Carvalho Chehab			    break;
62954f38fcaSMauro Carvalho Chehab
63054f38fcaSMauro Carvalho Chehab		    case 'u':
63154f38fcaSMauro Carvalho Chehab			    io = IO_METHOD_USERPTR;
63254f38fcaSMauro Carvalho Chehab			    break;
63354f38fcaSMauro Carvalho Chehab
63454f38fcaSMauro Carvalho Chehab		    case 'o':
63554f38fcaSMauro Carvalho Chehab			    out_buf++;
63654f38fcaSMauro Carvalho Chehab			    break;
63754f38fcaSMauro Carvalho Chehab
63854f38fcaSMauro Carvalho Chehab		    case 'f':
63954f38fcaSMauro Carvalho Chehab			    force_format++;
64054f38fcaSMauro Carvalho Chehab			    break;
64154f38fcaSMauro Carvalho Chehab
64254f38fcaSMauro Carvalho Chehab		    case 'c':
64354f38fcaSMauro Carvalho Chehab			    errno = 0;
64454f38fcaSMauro Carvalho Chehab			    frame_count = strtol(optarg, NULL, 0);
64554f38fcaSMauro Carvalho Chehab			    if (errno)
64654f38fcaSMauro Carvalho Chehab				    errno_exit(optarg);
64754f38fcaSMauro Carvalho Chehab			    break;
64854f38fcaSMauro Carvalho Chehab
64954f38fcaSMauro Carvalho Chehab		    default:
65054f38fcaSMauro Carvalho Chehab			    usage(stderr, argc, argv);
65154f38fcaSMauro Carvalho Chehab			    exit(EXIT_FAILURE);
65254f38fcaSMauro Carvalho Chehab		    }
65354f38fcaSMauro Carvalho Chehab	    }
65454f38fcaSMauro Carvalho Chehab
65554f38fcaSMauro Carvalho Chehab	    open_device();
65654f38fcaSMauro Carvalho Chehab	    init_device();
65754f38fcaSMauro Carvalho Chehab	    start_capturing();
65854f38fcaSMauro Carvalho Chehab	    mainloop();
65954f38fcaSMauro Carvalho Chehab	    stop_capturing();
66054f38fcaSMauro Carvalho Chehab	    uninit_device();
66154f38fcaSMauro Carvalho Chehab	    close_device();
662*d7894721SKwang Son	    fprintf(stderr, "\n");
66354f38fcaSMauro Carvalho Chehab	    return 0;
66454f38fcaSMauro Carvalho Chehab    }
665