~ubuntu-branches/ubuntu/precise/v4l-utils/precise

« back to all changes in this revision

Viewing changes to contrib/test/capture-example.c

  • Committer: Bazaar Package Importer
  • Author(s): Gregor Jasny
  • Date: 2010-02-28 19:44:15 UTC
  • Revision ID: james.westby@ubuntu.com-20100228194415-067hdj8rvawj91zw
Tags: upstream-0.7.90
ImportĀ upstreamĀ versionĀ 0.7.90

Show diffs side-by-side

added added

removed removed

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