]> git.sesse.net Git - vlc/blob - modules/access/v4l2/video.c
Qt: capture panel: Disable advanced options instead of being silent on
[vlc] / modules / access / v4l2 / video.c
1 /*****************************************************************************
2  * video.c : Video4Linux2 input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2002-2009 VLC authors and VideoLAN
5  * Copyright (C) 2011-2012 RĂ©mi Denis-Courmont
6  *
7  * Authors: Benjamin Pracht <bigben at videolan dot org>
8  *          Richard Hosking <richard at hovis dot net>
9  *          Antoine Cellerier <dionoea at videolan d.t org>
10  *          Dennis Lou <dlou99 at yahoo dot com>
11  *
12  * This program is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU Lesser General Public License as published by
14  * the Free Software Foundation; either version 2.1 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public License
23  * along with this program; if not, write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <errno.h>
32 #include <sys/ioctl.h>
33 #include <sys/mman.h>
34 #include <poll.h>
35
36 #include <vlc_common.h>
37 #include <vlc_block.h>
38
39 #include "v4l2.h"
40
41 static int SetupStandard (vlc_object_t *obj, int fd,
42                           const struct v4l2_input *restrict input,
43                           v4l2_std_id *restrict std)
44 {
45     if (!(input->capabilities & V4L2_IN_CAP_STD))
46     {
47         msg_Dbg (obj, "no video standard selection");
48         return 0;
49     }
50
51     *std = var_InheritStandard (obj, CFG_PREFIX"standard");
52     if (*std == V4L2_STD_UNKNOWN)
53     {
54         msg_Warn (obj, "video standard not set");
55
56         /* Grab the currently selected standard */
57         if (v4l2_ioctl (fd, VIDIOC_G_STD, std) < 0)
58             msg_Err (obj, "cannot get video standard");
59         return 0;
60     }
61     if (v4l2_ioctl (fd, VIDIOC_S_STD, std) < 0)
62     {
63         msg_Err (obj, "cannot set video standard 0x%"PRIx64": %m", *std);
64         return -1;
65     }
66     msg_Dbg (obj, "video standard set to 0x%"PRIx64":", *std);
67     return 0;
68 }
69
70 static int SetupAudio (vlc_object_t *obj, int fd,
71                        const struct v4l2_input *restrict input)
72 {
73     if (input->audioset == 0)
74     {
75         msg_Dbg (obj, "no audio input available");
76         return 0;
77     }
78     msg_Dbg (obj, "available audio inputs: 0x%08"PRIX32, input->audioset);
79
80     uint32_t idx = var_InheritInteger (obj, CFG_PREFIX"audio-input");
81     if (idx == (uint32_t)-1)
82     {
83         msg_Dbg (obj, "no audio input selected");
84         return 0;
85     }
86     if (((1 << idx) & input->audioset) == 0)
87     {
88         msg_Warn (obj, "skipped unavailable audio input %"PRIu32, idx);
89         return -1;
90     }
91
92     /* TODO: Enumerate other selectable audio inputs. How to expose them? */
93     struct v4l2_audio enumaudio = { .index = idx };
94
95     if (v4l2_ioctl (fd, VIDIOC_ENUMAUDIO, &enumaudio) < 0)
96     {
97         msg_Err (obj, "cannot get audio input %"PRIu32" properties: %m", idx);
98         return -1;
99     }
100
101     msg_Dbg (obj, "audio input %s (%"PRIu32") is %s"
102              " (capabilities: 0x%08"PRIX32")", enumaudio.name, enumaudio.index,
103              (enumaudio.capability & V4L2_AUDCAP_STEREO) ? "Stereo" : "Mono",
104              enumaudio.capability);
105     if (enumaudio.capability & V4L2_AUDCAP_AVL)
106         msg_Dbg (obj, " supports Automatic Volume Level");
107
108     /* TODO: AVL mode */
109     struct v4l2_audio audio = { .index = idx };
110
111     if (v4l2_ioctl (fd, VIDIOC_S_AUDIO, &audio) < 0)
112     {
113         msg_Err (obj, "cannot select audio input %"PRIu32": %m", idx);
114         return -1;
115     }
116     msg_Dbg (obj, "selected audio input %"PRIu32, idx);
117     return 0;
118 }
119
120 int SetupTuner (vlc_object_t *obj, int fd, uint32_t idx)
121 {
122     struct v4l2_tuner tuner = { .index = idx };
123
124     if (v4l2_ioctl (fd, VIDIOC_G_TUNER, &tuner) < 0)
125     {
126         msg_Err (obj, "cannot get tuner %"PRIu32" properties: %m", idx);
127         return -1;
128     }
129
130     /* NOTE: This is overkill. Only video devices currently work, so the
131      * type is always analog TV. */
132     const char *typename, *mult;
133     switch (tuner.type)
134     {
135         case V4L2_TUNER_RADIO:
136             typename = "Radio";
137             break;
138         case V4L2_TUNER_ANALOG_TV:
139             typename = "Analog TV";
140             break;
141         default:
142             typename = "unknown";
143     }
144     mult = (tuner.capability & V4L2_TUNER_CAP_LOW) ? "" : "k";
145
146     msg_Dbg (obj, "tuner %s (%"PRIu32") is %s", tuner.name, tuner.index,
147              typename);
148     msg_Dbg (obj, " ranges from %u.%u %sHz to %u.%u %sHz",
149              (tuner.rangelow * 125) >> 1, (tuner.rangelow & 1) * 5, mult,
150              (tuner.rangehigh * 125) >> 1, (tuner.rangehigh & 1) * 5,
151              mult);
152
153     /* TODO: only set video standard if the tuner requires it */
154
155     /* Configure the audio mode */
156     /* TODO: Ideally, L1 would be selected for stereo tuners, and L1_L2
157      * for mono tuners. When dual-mono is detected after tuning on a stereo
158      * tuner, we would fallback to L1_L2 too. Then we would flag dual-mono
159      * for the audio E/S. Unfortunately, we have no access to the audio E/S
160      * here (it belongs in the slave audio input...). */
161     tuner.audmode = var_InheritInteger (obj, CFG_PREFIX"tuner-audio-mode");
162     memset (tuner.reserved, 0, sizeof (tuner.reserved));
163
164     if (tuner.capability & V4L2_TUNER_CAP_LANG1)
165         msg_Dbg (obj, " supports primary audio language");
166     else if (tuner.audmode == V4L2_TUNER_MODE_LANG1)
167     {
168         msg_Warn (obj, " falling back to stereo mode");
169         tuner.audmode = V4L2_TUNER_MODE_STEREO;
170     }
171     if (tuner.capability & V4L2_TUNER_CAP_LANG2)
172         msg_Dbg (obj, " supports secondary audio language or program");
173     if (tuner.capability & V4L2_TUNER_CAP_STEREO)
174         msg_Dbg (obj, " supports stereo audio");
175     else if (tuner.audmode == V4L2_TUNER_MODE_STEREO)
176     {
177         msg_Warn (obj, " falling back to mono mode");
178         tuner.audmode = V4L2_TUNER_MODE_MONO;
179     }
180
181     if (v4l2_ioctl (fd, VIDIOC_S_TUNER, &tuner) < 0)
182     {
183         msg_Err (obj, "cannot set tuner %"PRIu32" audio mode: %m", idx);
184         return -1;
185     }
186     msg_Dbg (obj, "tuner %"PRIu32" audio mode %u set", idx, tuner.audmode);
187
188     /* Tune to the requested frequency */
189     uint32_t freq = var_InheritInteger (obj, CFG_PREFIX"tuner-frequency");
190     if (freq != (uint32_t)-1)
191     {
192         struct v4l2_frequency frequency = {
193             .tuner = idx,
194             .type = tuner.type,
195             .frequency = freq * 125 / 2
196         };
197
198         if (v4l2_ioctl (fd, VIDIOC_S_FREQUENCY, &frequency) < 0)
199         {
200             msg_Err (obj, "cannot tune tuner %"PRIu32
201                      " to frequency %u %sHz: %m", idx, freq, mult);
202             return -1;
203         }
204         msg_Dbg (obj, "tuner %"PRIu32" tuned to frequency %"PRIu32" %sHz",
205                  idx, freq, mult);
206     }
207     else
208         msg_Dbg (obj, "tuner not tuned");
209     return 0;
210 }
211
212 static int ResetCrop (vlc_object_t *obj, int fd)
213 {
214     struct v4l2_cropcap cropcap = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
215
216     /* In theory, this ioctl() must work for all video capture devices.
217      * In practice, it does not. */
218     if (v4l2_ioctl (fd, VIDIOC_CROPCAP, &cropcap) < 0)
219     {
220         msg_Dbg (obj, "cannot get cropping properties: %m");
221         return 0;
222     }
223
224     /* Reset to the default cropping rectangle */
225     struct v4l2_crop crop = {
226         .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
227         .c = cropcap.defrect,
228     };
229
230     if (v4l2_ioctl (fd, VIDIOC_S_CROP, &crop) < 0)
231     {
232         msg_Warn (obj, "cannot reset cropping limits: %m");
233         return -1;
234     }
235     return 0;
236 }
237
238 int SetupInput (vlc_object_t *obj, int fd, v4l2_std_id *std)
239 {
240     struct v4l2_input input;
241
242     input.index = var_InheritInteger (obj, CFG_PREFIX"input");
243     if (v4l2_ioctl (fd, VIDIOC_ENUMINPUT, &input) < 0)
244     {
245         msg_Err (obj, "invalid video input %"PRIu32": %m", input.index);
246         return -1;
247     }
248
249     const char *typename = "unknown";
250     switch (input.type)
251     {
252         case V4L2_INPUT_TYPE_TUNER:
253             typename = "tuner";
254             break;
255         case V4L2_INPUT_TYPE_CAMERA:
256             typename = "camera";
257             break;
258     }
259
260     msg_Dbg (obj, "video input %s (%"PRIu32") is %s", input.name,
261              input.index, typename);
262
263     /* Select input */
264     if (v4l2_ioctl (fd, VIDIOC_S_INPUT, &input.index) < 0)
265     {
266         msg_Err (obj, "cannot select input %"PRIu32": %m", input.index);
267         return -1;
268     }
269     msg_Dbg (obj, "selected input %"PRIu32, input.index);
270
271     SetupStandard (obj, fd, &input, std);
272
273     switch (input.type)
274     {
275         case V4L2_INPUT_TYPE_TUNER:
276             msg_Dbg (obj, "tuning required: tuner %"PRIu32, input.tuner);
277             SetupTuner (obj, fd, input.tuner);
278             break;
279         case V4L2_INPUT_TYPE_CAMERA:
280             msg_Dbg (obj, "no tuning required (analog baseband input)");
281             break;
282         default:
283             msg_Err (obj, "unknown input tuning type %"PRIu32, input.type);
284             break; // hopefully we can stream regardless...
285     }
286
287     SetupAudio (obj, fd, &input);
288     return 0;
289 }
290
291 /** Compares two V4L2 fractions. */
292 static int64_t fcmp (const struct v4l2_fract *a,
293                      const struct v4l2_fract *b)
294 {
295     return (uint64_t)a->numerator * b->denominator
296          - (uint64_t)b->numerator * a->denominator;
297 }
298
299 static const struct v4l2_fract infinity = { 1, 0 };
300
301 /**
302  * Finds the highest frame rate possible of a certain V4L2 format.
303  * @param fmt V4L2 capture format [IN]
304  * @param it V4L2 frame interval [OUT]
305  * @return 0 on success, -1 on error.
306  */
307 static int FindMaxRate (vlc_object_t *obj, int fd,
308                         const struct v4l2_format *restrict fmt,
309                         struct v4l2_fract *restrict it)
310 {
311     struct v4l2_frmivalenum fie = {
312         .pixel_format = fmt->fmt.pix.pixelformat,
313         .width = fmt->fmt.pix.width,
314         .height = fmt->fmt.pix.height,
315     };
316     /* Mind that maximum rate means minimum interval */
317
318     if (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &fie) < 0)
319     {
320         msg_Dbg (obj, "  unknown frame intervals: %m");
321         /* Frame intervals cannot be enumerated. Set the format and then
322          * get the streaming parameters to figure out the default frame
323          * interval. This is not necessarily the maximum though. */
324         struct v4l2_format dummy_fmt = *fmt;
325         struct v4l2_streamparm parm = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
326
327         if (v4l2_ioctl (fd, VIDIOC_S_FMT, &dummy_fmt) < 0
328          || v4l2_ioctl (fd, VIDIOC_G_PARM, &parm) < 0)
329         {
330             *it = infinity;
331             return -1;
332         }
333
334         *it = parm.parm.capture.timeperframe;
335         msg_Dbg (obj, "  %s frame interval: %"PRIu32"/%"PRIu32,
336                  (parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)
337                  ? "default" : "constant", it->numerator, it->denominator);
338     }
339     else
340     switch (fie.type)
341     {
342         case V4L2_FRMIVAL_TYPE_DISCRETE:
343             *it = infinity;
344             do
345             {
346                 if (fcmp (&fie.discrete, it) < 0)
347                     *it = fie.discrete;
348                 fie.index++;
349             }
350             while (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &fie) >= 0);
351
352             msg_Dbg (obj, "  %s frame interval: %"PRIu32"/%"PRIu32,
353                      "discrete", it->numerator, it->denominator);
354             break;
355
356         case V4L2_FRMIVAL_TYPE_STEPWISE:
357         case V4L2_FRMIVAL_TYPE_CONTINUOUS:
358             msg_Dbg (obj, "  frame intervals from %"PRIu32"/%"PRIu32
359                      "to %"PRIu32"/%"PRIu32" supported",
360                      fie.stepwise.min.numerator, fie.stepwise.min.denominator,
361                      fie.stepwise.max.numerator, fie.stepwise.max.denominator);
362             if (fie.type == V4L2_FRMIVAL_TYPE_STEPWISE)
363                 msg_Dbg (obj, "  with %"PRIu32"/%"PRIu32" step",
364                          fie.stepwise.step.numerator,
365                          fie.stepwise.step.denominator);
366             *it = fie.stepwise.min;
367             break;
368     }
369     return 0;
370 }
371
372 #undef SetupFormat
373 /**
374  * Finds the best possible frame rate and resolution.
375  * @param fourcc pixel format
376  * @param fmt V4L2 capture format [OUT]
377  * @param parm V4L2 capture streaming parameters [OUT]
378  * @return 0 on success, -1 on failure.
379  */
380 int SetupFormat (vlc_object_t *obj, int fd, uint32_t fourcc,
381                  struct v4l2_format *restrict fmt,
382                  struct v4l2_streamparm *restrict parm)
383 {
384     memset (fmt, 0, sizeof (*fmt));
385     fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
386     memset (parm, 0, sizeof (*parm));
387     parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
388
389     if (v4l2_ioctl (fd, VIDIOC_G_FMT, fmt) < 0)
390     {
391         msg_Err (obj, "cannot get default format: %m");
392         return -1;
393     }
394     fmt->fmt.pix.pixelformat = fourcc;
395
396     struct v4l2_frmsizeenum fse = {
397         .pixel_format = fourcc,
398     };
399     struct v4l2_fract best_it = infinity;
400     uint64_t best_area = 0;
401
402     uint32_t width = var_InheritInteger (obj, CFG_PREFIX"width");
403     uint32_t height = var_InheritInteger (obj, CFG_PREFIX"height");
404     if (width > 0 && height > 0)
405     {
406         fmt->fmt.pix.width = width;
407         fmt->fmt.pix.height = height;
408         msg_Dbg (obj, " requested frame size: %"PRIu32"x%"PRIu32,
409                  width, height);
410         FindMaxRate (obj, fd, fmt, &best_it);
411     }
412     else
413     if (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &fse) < 0)
414     {
415         /* Fallback to current format, try to maximize frame rate */
416         msg_Dbg (obj, " unknown frame sizes: %m");
417         msg_Dbg (obj, " current frame size: %"PRIu32"x%"PRIu32,
418                  fmt->fmt.pix.width, fmt->fmt.pix.height);
419         FindMaxRate (obj, fd, fmt, &best_it);
420     }
421     else
422     switch (fse.type)
423     {
424         case V4L2_FRMSIZE_TYPE_DISCRETE:
425             do
426             {
427                 struct v4l2_fract cur_it;
428
429                 msg_Dbg (obj, " frame size %"PRIu32"x%"PRIu32,
430                          fse.discrete.width, fse.discrete.height);
431                 FindMaxRate (obj, fd, fmt, &cur_it);
432
433                 int64_t c = fcmp (&cur_it, &best_it);
434                 uint64_t area = fse.discrete.width * fse.discrete.height;
435                 if (c < 0 || (c == 0 && area > best_area))
436                 {
437                     best_it = cur_it;
438                     best_area = area;
439                     fmt->fmt.pix.width = fse.discrete.width;
440                     fmt->fmt.pix.height = fse.discrete.height;
441                 }
442
443                 fse.index++;
444             }
445             while (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &fse) >= 0);
446
447             msg_Dbg (obj, " best discrete frame size: %"PRIu32"x%"PRIu32,
448                      fmt->fmt.pix.width, fmt->fmt.pix.height);
449             break;
450
451         case V4L2_FRMSIZE_TYPE_STEPWISE:
452         case V4L2_FRMSIZE_TYPE_CONTINUOUS:
453             msg_Dbg (obj, " frame sizes from %"PRIu32"x%"PRIu32" to "
454                      "%"PRIu32"x%"PRIu32" supported",
455                      fse.stepwise.min_width, fse.stepwise.min_height,
456                      fse.stepwise.max_width, fse.stepwise.max_height);
457             if (fse.type == V4L2_FRMSIZE_TYPE_STEPWISE)
458                 msg_Dbg (obj, "  with %"PRIu32"x%"PRIu32" steps",
459                          fse.stepwise.step_width, fse.stepwise.step_height);
460
461             /* FIXME: slow and dumb */
462             for (uint32_t width =  fse.stepwise.min_width;
463                           width <= fse.stepwise.max_width;
464                           width += fse.stepwise.step_width)
465                 for (uint32_t height =  fse.stepwise.min_height;
466                               height <= fse.stepwise.max_width;
467                               height += fse.stepwise.step_height)
468                 {
469                     struct v4l2_fract cur_it;
470
471                     FindMaxRate (obj, fd, fmt, &cur_it);
472
473                     int64_t c = fcmp (&cur_it, &best_it);
474                     uint64_t area = width * height;
475
476                     if (c < 0 || (c == 0 && area > best_area))
477                     {
478                         best_it = cur_it;
479                         best_area = area;
480                         fmt->fmt.pix.width = width;
481                         fmt->fmt.pix.height = height;
482                     }
483                 }
484
485             msg_Dbg (obj, " best frame size: %"PRIu32"x%"PRIu32,
486                      fmt->fmt.pix.width, fmt->fmt.pix.height);
487             break;
488     }
489
490     /* Set the final format */
491     if (v4l2_ioctl (fd, VIDIOC_S_FMT, fmt) < 0)
492     {
493         msg_Err (obj, "cannot set format: %m");
494         return -1;
495     }
496
497     /* Now that the final format is set, fetch and override parameters */
498     if (v4l2_ioctl (fd, VIDIOC_G_PARM, parm) < 0)
499     {
500         msg_Err (obj, "cannot get streaming parameters: %m");
501         memset (parm, 0, sizeof (*parm));
502         parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
503     }
504     parm->parm.capture.capturemode = 0; /* normal video mode */
505     parm->parm.capture.extendedmode = 0;
506     if (best_it.denominator != 0)
507         parm->parm.capture.timeperframe = best_it;
508     if (v4l2_ioctl (fd, VIDIOC_S_PARM, parm) < 0)
509         msg_Warn (obj, "cannot set streaming parameters: %m");
510
511     ResetCrop (obj, fd); /* crop depends on frame size */
512
513     return 0;
514 }
515
516
517 /*****************************************************************************
518  * GrabVideo: Grab a video frame
519  *****************************************************************************/
520 block_t *GrabVideo (vlc_object_t *demux, int fd,
521                     const struct buffer_t *restrict bufv)
522 {
523     struct v4l2_buffer buf = {
524         .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
525         .memory = V4L2_MEMORY_MMAP,
526     };
527
528     /* Wait for next frame */
529     if (v4l2_ioctl (fd, VIDIOC_DQBUF, &buf) < 0)
530     {
531         switch (errno)
532         {
533             case EAGAIN:
534                 return NULL;
535             case EIO:
536                 /* Could ignore EIO, see spec. */
537                 /* fall through */
538             default:
539                 msg_Err (demux, "dequeue error: %m");
540                 return NULL;
541         }
542     }
543
544     /* Copy frame */
545     block_t *block = block_Alloc (buf.bytesused);
546     if (unlikely(block == NULL))
547         return NULL;
548     memcpy (block->p_buffer, bufv[buf.index].start, buf.bytesused);
549
550     /* Unlock */
551     if (v4l2_ioctl (fd, VIDIOC_QBUF, &buf) < 0)
552     {
553         msg_Err (demux, "queue error: %m");
554         block_Release (block);
555         return NULL;
556     }
557     return block;
558 }
559
560 /**
561  * Allocates user pointer buffers, and start streaming.
562  */
563 int StartUserPtr (vlc_object_t *obj, int fd)
564 {
565     struct v4l2_requestbuffers reqbuf = {
566         .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
567         .memory = V4L2_MEMORY_USERPTR,
568         .count = 2,
569     };
570
571     if (v4l2_ioctl (fd, VIDIOC_REQBUFS, &reqbuf) < 0)
572     {
573         msg_Dbg (obj, "cannot reserve user buffers: %m");
574         return -1;
575     }
576     if (v4l2_ioctl (fd, VIDIOC_STREAMON, &reqbuf.type) < 0)
577     {
578         msg_Err (obj, "cannot start streaming: %m");
579         return -1;
580     }
581     return 0;
582 }
583
584 /**
585  * Allocates memory-mapped buffers, queues them and start streaming.
586  * @param n requested buffers count [IN], allocated buffers count [OUT]
587  * @return array of allocated buffers (use free()), or NULL on error.
588  */
589 struct buffer_t *StartMmap (vlc_object_t *obj, int fd, uint32_t *restrict n)
590 {
591     struct v4l2_requestbuffers req = {
592         .count = *n,
593         .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
594         .memory = V4L2_MEMORY_MMAP,
595     };
596
597     if (v4l2_ioctl (fd, VIDIOC_REQBUFS, &req) < 0)
598     {
599         msg_Err (obj, "cannot allocate buffers: %m" );
600         return NULL;
601     }
602
603     if (req.count < 2)
604     {
605         msg_Err (obj, "cannot allocate enough buffers");
606         return NULL;
607     }
608
609     struct buffer_t *bufv = malloc (req.count * sizeof (*bufv));
610     if (unlikely(bufv == NULL))
611         return NULL;
612
613     uint32_t bufc = 0;
614     while (bufc < req.count)
615     {
616         struct v4l2_buffer buf = {
617             .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
618             .memory = V4L2_MEMORY_MMAP,
619             .index = bufc,
620         };
621
622         if (v4l2_ioctl (fd, VIDIOC_QUERYBUF, &buf) < 0)
623         {
624             msg_Err (obj, "cannot query buffer %"PRIu32": %m", bufc);
625             goto error;
626         }
627
628         bufv[bufc].start = v4l2_mmap (NULL, buf.length, PROT_READ | PROT_WRITE,
629                                       MAP_SHARED, fd, buf.m.offset);
630         if (bufv[bufc].start == MAP_FAILED)
631         {
632             msg_Err (obj, "cannot map buffer %"PRIu32": %m", bufc);
633             goto error;
634         }
635         bufv[bufc].length = buf.length;
636         bufc++;
637
638         /* Some drivers refuse to queue buffers before they are mapped. Bug? */
639         if (v4l2_ioctl (fd, VIDIOC_QBUF, &buf) < 0)
640         {
641             msg_Err (obj, "cannot queue buffer %"PRIu32": %m", bufc);
642             goto error;
643         }
644     }
645
646     enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
647     if (v4l2_ioctl (fd, VIDIOC_STREAMON, &type) < 0)
648     {
649         msg_Err (obj, "cannot start streaming: %m");
650         goto error;
651     }
652     *n = bufc;
653     return bufv;
654 error:
655     StopMmap (fd, bufv, bufc);
656     return NULL;
657 }
658
659 void StopMmap (int fd, struct buffer_t *bufv, uint32_t bufc)
660 {
661     enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
662
663     /* STREAMOFF implicitly dequeues all buffers */
664     v4l2_ioctl (fd, VIDIOC_STREAMOFF, &type);
665     for (uint32_t i = 0; i < bufc; i++)
666         v4l2_munmap (bufv[i].start, bufv[i].length);
667     free (bufv);
668 }