]> git.sesse.net Git - vlc/blob - modules/access/v4l2/demux.c
v4l: measure time from start (fixes #7400)
[vlc] / modules / access / v4l2 / demux.c
1 /*****************************************************************************
2  * demux.c : V4L2 raw video demux module for vlc
3  *****************************************************************************
4  * Copyright (C) 2002-2011 the VideoLAN team
5  *
6  * Authors: Benjamin Pracht <bigben at videolan dot org>
7  *          Richard Hosking <richard at hovis dot net>
8  *          Antoine Cellerier <dionoea at videolan d.t org>
9  *          Dennis Lou <dlou99 at yahoo dot com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation; either version 2.1 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <math.h>
31 #include <errno.h>
32 #include <assert.h>
33 #include <sys/ioctl.h>
34 #include <sys/mman.h>
35 #ifndef MAP_ANONYMOUS
36 # define MAP_ANONYMOUS MAP_ANON
37 #endif
38 #include <poll.h>
39
40 #include <vlc_common.h>
41 #include <vlc_demux.h>
42
43 #include "v4l2.h"
44
45 struct demux_sys_t
46 {
47     int fd;
48     vlc_thread_t thread;
49
50     struct buffer_t *bufv;
51     union
52     {
53         uint32_t bufc;
54         uint32_t blocksize;
55     };
56     uint32_t block_flags;
57
58     es_out_id_t *es;
59     vlc_v4l2_ctrl_t *controls;
60     mtime_t start;
61 };
62
63 static void *UserPtrThread (void *);
64 static void *MmapThread (void *);
65 static void *ReadThread (void *);
66 static int DemuxControl( demux_t *, int, va_list );
67 static int InitVideo (demux_t *, int fd, uint32_t caps);
68
69 int DemuxOpen( vlc_object_t *obj )
70 {
71     demux_t *demux = (demux_t *)obj;
72
73     demux_sys_t *sys = malloc (sizeof (*sys));
74     if (unlikely(sys == NULL))
75         return VLC_ENOMEM;
76     demux->p_sys = sys;
77
78     ParseMRL( obj, demux->psz_location );
79
80     char *path = var_InheritString (obj, CFG_PREFIX"dev");
81     if (unlikely(path == NULL))
82         goto error; /* probably OOM */
83
84     uint32_t caps;
85     int fd = OpenDevice (obj, path, &caps);
86     free (path);
87     if (fd == -1)
88         goto error;
89     sys->fd = fd;
90
91     if (InitVideo (demux, fd, caps))
92     {
93         v4l2_close (fd);
94         goto error;
95     }
96
97     sys->controls = ControlsInit (VLC_OBJECT(demux), fd);
98     sys->start = mdate ();
99     demux->pf_demux = NULL;
100     demux->pf_control = DemuxControl;
101     demux->info.i_update = 0;
102     demux->info.i_title = 0;
103     demux->info.i_seekpoint = 0;
104     return VLC_SUCCESS;
105 error:
106     free (sys);
107     return VLC_EGENERIC;
108 }
109
110 typedef struct
111 {
112     uint32_t v4l2;
113     vlc_fourcc_t vlc;
114     uint32_t red;
115     uint32_t green;
116     uint32_t blue;
117 } vlc_v4l2_fmt_t;
118
119 /* NOTE: Currently vlc_v4l2_fmt_rank() assumes format are sorted in order of
120  * decreasing preference. */
121 static const vlc_v4l2_fmt_t v4l2_fmts[] =
122 {
123     /* Planar YUV 4:2:0 */
124     { V4L2_PIX_FMT_YUV420,   VLC_CODEC_I420, 0, 0, 0 },
125     { V4L2_PIX_FMT_YVU420,   VLC_CODEC_YV12, 0, 0, 0 },
126     { V4L2_PIX_FMT_YUV422P,  VLC_CODEC_I422, 0, 0, 0 },
127     /* Packed YUV 4:2:2 */
128     { V4L2_PIX_FMT_YUYV,     VLC_CODEC_YUYV, 0, 0, 0 },
129     { V4L2_PIX_FMT_UYVY,     VLC_CODEC_UYVY, 0, 0, 0 },
130     { V4L2_PIX_FMT_YVYU,     VLC_CODEC_YVYU, 0, 0, 0 },
131     { V4L2_PIX_FMT_VYUY,     VLC_CODEC_VYUY, 0, 0, 0 },
132
133     { V4L2_PIX_FMT_YUV411P,  VLC_CODEC_I411, 0, 0, 0 },
134
135     { V4L2_PIX_FMT_YUV410,   VLC_CODEC_I410, 0, 0, 0 },
136 //  { V4L2_PIX_FMT_YVU410     },
137
138 //  { V4L2_PIX_FMT_NV24,      },
139 //  { V4L2_PIX_FMT_NV42,      },
140 //  { V4L2_PIX_FMT_NV16,     VLC_CODEC_NV16, 0, 0, 0 },
141 //  { V4L2_PIX_FMT_NV61,     VLC_CODEC_NV61, 0, 0, 0 },
142     { V4L2_PIX_FMT_NV12,     VLC_CODEC_NV12, 0, 0, 0 },
143     { V4L2_PIX_FMT_NV21,     VLC_CODEC_NV21, 0, 0, 0 },
144
145     /* V4L2-documented but VLC-unsupported misc. YUV formats */
146 //  { V4L2_PIX_FMT_Y41P       },
147 //  { V4L2_PIX_FMT_NV12MT,    },
148 //  { V4L2_PIX_FMT_M420,      },
149
150     /* Packed RGB */
151 #ifdef WORDS_BIGENDIAN
152     { V4L2_PIX_FMT_RGB32,    VLC_CODEC_RGB32,   0xFF00, 0xFF0000, 0xFF000000 },
153     { V4L2_PIX_FMT_BGR32,    VLC_CODEC_RGB32, 0xFF000000, 0xFF0000,   0xFF00 },
154     { V4L2_PIX_FMT_RGB24,    VLC_CODEC_RGB24,   0xFF0000, 0x00FF00, 0x0000FF },
155     { V4L2_PIX_FMT_BGR24,    VLC_CODEC_RGB24,   0x0000FF, 0x00FF00, 0xFF0000 },
156 //  { V4L2_PIX_FMT_BGR666,    },
157 //  { V4L2_PIX_FMT_RGB565,    },
158     { V4L2_PIX_FMT_RGB565X,  VLC_CODEC_RGB16,     0x001F,   0x07E0,   0xF800 },
159 //  { V4L2_PIX_FMT_RGB555,    },
160     { V4L2_PIX_FMT_RGB555X,  VLC_CODEC_RGB15,     0x001F,   0x03E0,   0x7C00 },
161 //  { V4L2_PIX_FMT_RGB444,   VLC_CODEC_RGB12,     0x000F,   0xF000,   0x0F00 },
162 #else
163     { V4L2_PIX_FMT_RGB32,    VLC_CODEC_RGB32,   0x0000FF, 0x00FF00, 0xFF0000 },
164     { V4L2_PIX_FMT_BGR32,    VLC_CODEC_RGB32,   0xFF0000, 0x00FF00, 0x0000FF },
165     { V4L2_PIX_FMT_RGB24,    VLC_CODEC_RGB24,   0x0000FF, 0x00FF00, 0xFF0000 },
166     { V4L2_PIX_FMT_BGR24,    VLC_CODEC_RGB24,   0xFF0000, 0x00FF00, 0x0000FF },
167 //  { V4L2_PIX_FMT_BGR666,    },
168     { V4L2_PIX_FMT_RGB565,   VLC_CODEC_RGB16,     0x001F,   0x07E0,   0xF800 },
169 //  { V4L2_PIX_FMT_RGB565X,   },
170     { V4L2_PIX_FMT_RGB555,   VLC_CODEC_RGB15,     0x001F,   0x03E0,   0x7C00 },
171 //  { V4L2_PIX_FMT_RGB555X,   },
172 //  { V4L2_PIX_FMT_RGB444,   VLC_CODEC_RGB12,     0x0F00,   0x00F0,   0x000F },
173 #endif
174 //  { V4L2_PIX_FMT_RGB332,   VLC_CODEC_RGB8,        0xC0,     0x38,     0x07 },
175
176     /* Bayer (sub-sampled RGB). Not supported. */
177 //  { V4L2_PIX_FMT_SBGGR16,  }
178 //  { V4L2_PIX_FMT_SRGGB12,  }
179 //  { V4L2_PIX_FMT_SGRBG12,  }
180 //  { V4L2_PIX_FMT_SGBRG12,  }
181 //  { V4L2_PIX_FMT_SBGGR12,  }
182 //  { V4L2_PIX_FMT_SRGGB10,  }
183 //  { V4L2_PIX_FMT_SGRBG10,  }
184 //  { V4L2_PIX_FMT_SGBRG10,  }
185 //  { V4L2_PIX_FMT_SBGGR10,  }
186 //  { V4L2_PIX_FMT_SBGGR8,   }
187 //  { V4L2_PIX_FMT_SGBRG8,   }
188 //  { V4L2_PIX_FMT_SGRBG8,   }
189 //  { V4L2_PIX_FMT_SRGGB8,   }
190
191     /* Compressed data types */
192     { V4L2_PIX_FMT_JPEG,   VLC_CODEC_MJPG, 0, 0, 0 },
193 #ifdef V4L2_PIX_FMT_H264
194     { V4L2_PIX_FMT_H264,   VLC_CODEC_H264, 0, 0, 0 },
195     /* FIXME: fill p_extra for avc1... */
196 //  { V4L2_PIX_FMT_H264_NO_SC, VLC_FOURCC('a','v','c','1'), 0, 0, 0 }
197     { V4L2_PIX_FMT_MPEG4,  VLC_CODEC_MP4V, 0, 0, 0 },
198     { V4L2_PIX_FMT_XVID,   VLC_CODEC_MP4V, 0, 0, 0 },
199     { V4L2_PIX_FMT_H263,   VLC_CODEC_H263, 0, 0, 0 },
200     { V4L2_PIX_FMT_MPEG2,  VLC_CODEC_MPGV, 0, 0, 0 },
201     { V4L2_PIX_FMT_MPEG1,  VLC_CODEC_MPGV, 0, 0, 0 },
202     { V4L2_PIX_FMT_VC1_ANNEX_G, VLC_CODEC_VC1, 0, 0, 0 },
203     { V4L2_PIX_FMT_VC1_ANNEX_L, VLC_CODEC_VC1, 0, 0, 0 },
204 #endif
205     //V4L2_PIX_FMT_MPEG -> use access
206
207     /* Reserved formats */
208     { V4L2_PIX_FMT_MJPEG,   VLC_CODEC_MJPG, 0, 0, 0 },
209     //V4L2_PIX_FMT_DV -> use access
210
211     /* Grey scale */
212 //  { V4L2_PIX_FMT_Y16,       },
213 //  { V4L2_PIX_FMT_Y12,       },
214 //  { V4L2_PIX_FMT_Y10,       },
215 //  { V4L2_PIX_FMT_Y10BPACK,  },
216     { V4L2_PIX_FMT_GREY,     VLC_CODEC_GREY, 0, 0, 0 },
217 };
218
219 static const vlc_v4l2_fmt_t *vlc_from_v4l2_fourcc (uint32_t fourcc)
220 {
221      for (size_t i = 0; i < sizeof (v4l2_fmts) / sizeof (v4l2_fmts[0]); i++)
222          if (v4l2_fmts[i].v4l2 == fourcc)
223              return v4l2_fmts + i;
224      return NULL;
225 }
226
227 static size_t vlc_v4l2_fmt_rank (const vlc_v4l2_fmt_t *fmt)
228 {
229     if (fmt == NULL)
230         return SIZE_MAX;
231
232     ptrdiff_t d = fmt - v4l2_fmts;
233     assert (d >= 0);
234     assert (d < (ptrdiff_t)(sizeof (v4l2_fmts) / sizeof (v4l2_fmts[0])));
235     return d;
236 }
237
238 static vlc_fourcc_t var_InheritFourCC (vlc_object_t *obj, const char *varname)
239 {
240     char *str = var_InheritString (obj, varname);
241     if (str == NULL)
242         return 0;
243
244     vlc_fourcc_t fourcc = vlc_fourcc_GetCodecFromString (VIDEO_ES, str);
245     if (fourcc == 0)
246         msg_Err (obj, "invalid codec %s", str);
247     free (str);
248     return fourcc;
249 }
250 #define var_InheritFourCC(o, v) var_InheritFourCC(VLC_OBJECT(o), v)
251
252 static void GetAR (int fd, unsigned *restrict num, unsigned *restrict den)
253 {
254     struct v4l2_cropcap cropcap = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
255
256     /* TODO: get CROPCAP only once (see ResetCrop()). */
257     if (v4l2_ioctl (fd, VIDIOC_CROPCAP, &cropcap) < 0)
258     {
259         *num = *den = 1;
260         return;
261     }
262     *num = cropcap.pixelaspect.numerator;
263     *den = cropcap.pixelaspect.denominator;
264 }
265
266 static int InitVideo (demux_t *demux, int fd, uint32_t caps)
267 {
268     demux_sys_t *sys = demux->p_sys;
269
270     if (!(caps & V4L2_CAP_VIDEO_CAPTURE))
271     {
272         msg_Err (demux, "not a video capture device");
273         return -1;
274     }
275
276     if (SetupInput (VLC_OBJECT(demux), fd))
277         return -1;
278
279     /* Picture format negotiation */
280     const vlc_v4l2_fmt_t *selected = NULL;
281     vlc_fourcc_t reqfourcc = var_InheritFourCC (demux, CFG_PREFIX"chroma");
282     bool native = false;
283
284     for (struct v4l2_fmtdesc codec = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
285          v4l2_ioctl (fd, VIDIOC_ENUM_FMT, &codec) >= 0;
286          codec.index++)
287     {   /* Enumerate available chromas */
288         const vlc_v4l2_fmt_t *dsc = vlc_from_v4l2_fourcc (codec.pixelformat);
289
290         msg_Dbg (demux, " %s %s format %4.4s (%4.4s): %s",
291               (codec.flags & V4L2_FMT_FLAG_EMULATED) ? "emulates" : "supports",
292               (codec.flags & V4L2_FMT_FLAG_COMPRESSED) ? "compressed" : "raw",
293                  (char *)&codec.pixelformat,
294                  (dsc != NULL) ? (const char *)&dsc->vlc : "N.A.",
295                  codec.description);
296
297         if (dsc == NULL)
298             continue; /* ignore VLC-unsupported codec */
299
300         if (dsc->vlc == reqfourcc)
301         {
302             msg_Dbg (demux, "  matches the requested format");
303             selected = dsc;
304             break; /* always select the requested format if found */
305         }
306
307         if (codec.flags & V4L2_FMT_FLAG_EMULATED)
308         {
309             if (native)
310                 continue; /* ignore emulated format if possible */
311         }
312         else
313             native = true;
314
315         if (vlc_v4l2_fmt_rank (dsc) > vlc_v4l2_fmt_rank (selected))
316             continue; /* ignore if rank is worse */
317
318         selected = dsc;
319     }
320
321     if (selected == NULL)
322     {
323         msg_Err (demux, "cannot negotiate supported video format");
324         return -1;
325     }
326     msg_Dbg (demux, "selected format %4.4s (%4.4s)",
327              (const char *)&selected->v4l2, (const char *)&selected->vlc);
328
329     /* Find best resolution and frame rate available */
330     struct v4l2_format fmt;
331     struct v4l2_streamparm parm;
332     if (SetupFormat (demux, fd, selected->v4l2, &fmt, &parm))
333         return -1;
334
335     /* Print extra info */
336     msg_Dbg (demux, "%d bytes maximum for complete image",
337              fmt.fmt.pix.sizeimage);
338     /* Check interlacing */
339     sys->block_flags = 0;
340     switch (fmt.fmt.pix.field)
341     {
342         case V4L2_FIELD_NONE:
343             msg_Dbg (demux, "Interlacing setting: progressive");
344             break;
345         case V4L2_FIELD_TOP:
346             msg_Dbg (demux, "Interlacing setting: top field only");
347             break;
348         case V4L2_FIELD_BOTTOM:
349             msg_Dbg (demux, "Interlacing setting: bottom field only");
350             break;
351         case V4L2_FIELD_INTERLACED:
352             msg_Dbg (demux, "Interlacing setting: interleaved");
353             /*if (NTSC)
354                 sys->block_flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
355             else*/
356                 sys->block_flags = BLOCK_FLAG_TOP_FIELD_FIRST;
357             break;
358         case V4L2_FIELD_SEQ_TB:
359             msg_Dbg (demux, "Interlacing setting: sequential top bottom (TODO)");
360             break;
361         case V4L2_FIELD_SEQ_BT:
362             msg_Dbg (demux, "Interlacing setting: sequential bottom top (TODO)");
363             break;
364         case V4L2_FIELD_ALTERNATE:
365             msg_Dbg (demux, "Interlacing setting: alternate fields (TODO)");
366             fmt.fmt.pix.height *= 2;
367             break;
368         case V4L2_FIELD_INTERLACED_TB:
369             msg_Dbg (demux, "Interlacing setting: interleaved top bottom");
370             sys->block_flags = BLOCK_FLAG_TOP_FIELD_FIRST;
371             break;
372         case V4L2_FIELD_INTERLACED_BT:
373             msg_Dbg (demux, "Interlacing setting: interleaved bottom top");
374             sys->block_flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
375             break;
376         default:
377             msg_Warn (demux, "Interlacing setting: unknown type (%d)",
378                       fmt.fmt.pix.field);
379             break;
380     }
381
382     /* Declare our unique elementary (video) stream */
383     es_format_t es_fmt;
384
385     es_format_Init (&es_fmt, VIDEO_ES, selected->vlc);
386     es_fmt.video.i_rmask = selected->red;
387     es_fmt.video.i_gmask = selected->green;
388     es_fmt.video.i_bmask = selected->blue;
389     es_fmt.video.i_width = fmt.fmt.pix.width;
390     es_fmt.video.i_height = fmt.fmt.pix.height;
391     es_fmt.video.i_frame_rate = parm.parm.capture.timeperframe.denominator;
392     es_fmt.video.i_frame_rate_base = parm.parm.capture.timeperframe.numerator;
393     GetAR (fd, &es_fmt.video.i_sar_num, &es_fmt.video.i_sar_den);
394
395     msg_Dbg (demux, "added new video ES %4.4s %ux%u", (char *)&es_fmt.i_codec,
396              es_fmt.video.i_width, es_fmt.video.i_height);
397     msg_Dbg (demux, " frame rate: %u/%u", es_fmt.video.i_frame_rate,
398              es_fmt.video.i_frame_rate_base);
399     msg_Dbg (demux, " aspect ratio: %u/%u", es_fmt.video.i_sar_num,
400              es_fmt.video.i_sar_den);
401     sys->es = es_out_Add (demux->out, &es_fmt);
402
403     /* Init I/O method */
404     void *(*entry) (void *);
405     if (caps & V4L2_CAP_STREAMING)
406     {
407         if (StartUserPtr (VLC_OBJECT(demux), fd) == 0)
408         {
409             /* In principles, mmap() will pad the length to a multiple of the
410              * page size, so there is no need to care. Nevertheless with the
411              * page size, block->i_size can be set optimally. */
412             const long pagemask = sysconf (_SC_PAGE_SIZE) - 1;
413
414             sys->blocksize = (fmt.fmt.pix.sizeimage + pagemask) & ~pagemask;
415             sys->bufv = NULL;
416             entry = UserPtrThread;
417             msg_Dbg (demux, "streaming with %"PRIu32"-bytes user buffers",
418                      sys->blocksize);
419         }
420         else /* fall back to memory map */
421         {
422             sys->bufc = 4;
423             sys->bufv = StartMmap (VLC_OBJECT(demux), fd, &sys->bufc);
424             if (sys->bufv == NULL)
425                 return -1;
426             entry = MmapThread;
427             msg_Dbg (demux, "streaming with %"PRIu32" memory-mapped buffers",
428                      sys->bufc);
429         }
430     }
431     else if (caps & V4L2_CAP_READWRITE)
432     {
433         sys->blocksize = fmt.fmt.pix.sizeimage;
434         sys->bufv = NULL;
435         entry = ReadThread;
436         msg_Dbg (demux, "reading %"PRIu32" bytes at a time", sys->blocksize);
437     }
438     else
439     {
440         msg_Err (demux, "no supported capture method");
441         return -1;
442     }
443
444     if (vlc_clone (&sys->thread, entry, demux, VLC_THREAD_PRIORITY_INPUT))
445     {
446         if (sys->bufv != NULL)
447             StopMmap (sys->fd, sys->bufv, sys->bufc);
448         return -1;
449     }
450     return 0;
451 }
452
453 void DemuxClose( vlc_object_t *obj )
454 {
455     demux_t *demux = (demux_t *)obj;
456     demux_sys_t *sys = demux->p_sys;
457
458     vlc_cancel (sys->thread);
459     vlc_join (sys->thread, NULL);
460     if (sys->bufv != NULL)
461         StopMmap (sys->fd, sys->bufv, sys->bufc);
462     ControlsDeinit( obj, sys->controls );
463     v4l2_close (sys->fd);
464     free( sys );
465 }
466
467 /** Allocates and queue a user buffer using mmap(). */
468 static block_t *UserPtrQueue (vlc_object_t *obj, int fd, size_t length)
469 {
470     void *ptr = mmap (NULL, length, PROT_READ | PROT_WRITE,
471                       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
472     if (ptr == MAP_FAILED)
473     {
474         msg_Err (obj, "cannot allocate %zu-bytes buffer: %m", length);
475         return NULL;
476     }
477
478     block_t *block = block_mmap_Alloc (ptr, length);
479     if (unlikely(block == NULL))
480     {
481         munmap (ptr, length);
482         return NULL;
483     }
484
485     struct v4l2_buffer buf = {
486         .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
487         .memory = V4L2_MEMORY_USERPTR,
488         .m = {
489             .userptr = (uintptr_t)ptr,
490         },
491         .length = length,
492     };
493
494     if (v4l2_ioctl (fd, VIDIOC_QBUF, &buf) < 0)
495     {
496         msg_Err (obj, "cannot queue buffer: %m");
497         block_Release (block);
498         return NULL;
499     }
500     return block;
501 }
502
503 static void *UserPtrThread (void *data)
504 {
505     demux_t *demux = data;
506     demux_sys_t *sys = demux->p_sys;
507     int fd = sys->fd;
508     struct pollfd ufd[1];
509
510     ufd[0].fd = fd;
511     ufd[0].events = POLLIN;
512
513     int canc = vlc_savecancel ();
514     for (;;)
515     {
516         struct v4l2_buffer buf = {
517             .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
518             .memory = V4L2_MEMORY_USERPTR,
519         };
520         block_t *block = UserPtrQueue (VLC_OBJECT(demux), fd, sys->blocksize);
521         if (block == NULL)
522             break;
523
524         /* Wait for data */
525         vlc_restorecancel (canc);
526         block_cleanup_push (block);
527         while (poll (ufd, 1, -1) == -1)
528            if (errno != EINTR)
529                msg_Err (demux, "poll error: %m");
530         vlc_cleanup_pop ();
531         canc = vlc_savecancel ();
532
533         if (v4l2_ioctl (fd, VIDIOC_DQBUF, &buf) < 0)
534         {
535             msg_Err (demux, "cannot dequeue buffer: %m");
536             block_Release (block);
537             continue;
538         }
539
540         assert (block->p_buffer == (void *)buf.m.userptr);
541         block->i_buffer = buf.length;
542         block->i_pts = block->i_dts = mdate ();
543         block->i_flags |= sys->block_flags;
544         es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts);
545         es_out_Send (demux->out, sys->es, block);
546     }
547     vlc_restorecancel (canc); /* <- hmm, this is purely cosmetic */
548     return NULL;
549 }
550
551 static void *MmapThread (void *data)
552 {
553     demux_t *demux = data;
554     demux_sys_t *sys = demux->p_sys;
555     int fd = sys->fd;
556     struct pollfd ufd[1];
557
558     ufd[0].fd = fd;
559     ufd[0].events = POLLIN;
560
561     for (;;)
562     {
563         /* Wait for data */
564         if (poll (ufd, 1, -1) == -1)
565         {
566            if (errno != EINTR)
567                msg_Err (demux, "poll error: %m");
568            continue;
569         }
570
571         int canc = vlc_savecancel ();
572         block_t *block = GrabVideo (VLC_OBJECT(demux), fd, sys->bufv);
573         if (block != NULL)
574         {
575             block->i_pts = block->i_dts = mdate ();
576             block->i_flags |= sys->block_flags;
577             es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts);
578             es_out_Send (demux->out, sys->es, block);
579         }
580         vlc_restorecancel (canc);
581     }
582
583     assert (0);
584 }
585
586 static void *ReadThread (void *data)
587 {
588     demux_t *demux = data;
589     demux_sys_t *sys = demux->p_sys;
590     int fd = sys->fd;
591     struct pollfd ufd[1];
592
593     ufd[0].fd = fd;
594     ufd[0].events = POLLIN;
595
596     for (;;)
597     {
598         /* Wait for data */
599         if (poll (ufd, 1, -1) == -1)
600         {
601            if (errno != EINTR)
602                msg_Err (demux, "poll error: %m");
603            continue;
604         }
605
606         block_t *block = block_Alloc (sys->blocksize);
607         if (unlikely(block == NULL))
608         {
609             msg_Err (demux, "read error: %m");
610             v4l2_read (fd, NULL, 0); /* discard frame */
611             continue;
612         }
613         block->i_pts = block->i_dts = mdate ();
614         block->i_flags |= sys->block_flags;
615
616         int canc = vlc_savecancel ();
617         ssize_t val = v4l2_read (fd, block->p_buffer, block->i_buffer);
618         if (val != -1)
619         {
620             block->i_buffer = val;
621             es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts);
622             es_out_Send (demux->out, sys->es, block);
623         }
624         else
625             block_Release (block);
626         vlc_restorecancel (canc);
627     }
628     assert (0);
629 }
630
631 static int DemuxControl( demux_t *demux, int query, va_list args )
632 {
633     demux_sys_t *sys = demux->p_sys;
634
635     switch( query )
636     {
637         /* Special for access_demux */
638         case DEMUX_CAN_PAUSE:
639         case DEMUX_CAN_SEEK:
640         case DEMUX_CAN_CONTROL_PACE:
641             *va_arg( args, bool * ) = false;
642             return VLC_SUCCESS;
643
644         case DEMUX_GET_PTS_DELAY:
645             *va_arg(args,int64_t *) = INT64_C(1000)
646                 * var_InheritInteger( demux, "live-caching" );
647             return VLC_SUCCESS;
648
649         case DEMUX_GET_TIME:
650             *va_arg (args, int64_t *) = mdate() - sys->start;
651             return VLC_SUCCESS;
652
653         /* TODO implement others */
654         default:
655             return VLC_EGENERIC;
656     }
657
658     return VLC_EGENERIC;
659 }