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