]> git.sesse.net Git - vlc/blob - modules/access/v4l2/demux.c
v4l2: fix race condition
[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 <fcntl.h>
34 #include <sys/ioctl.h>
35 #include <sys/mman.h>
36 #include <poll.h>
37
38 #include <vlc_common.h>
39 #include <vlc_demux.h>
40 #include <vlc_fs.h>
41
42 #include "v4l2.h"
43
44 struct demux_sys_t
45 {
46     int fd;
47     vlc_thread_t thread;
48
49     struct buffer_t *bufv;
50     union
51     {
52         uint32_t bufc;
53         uint32_t blocksize;
54     };
55     uint32_t block_flags;
56
57     es_out_id_t *es;
58     vlc_v4l2_ctrl_t *controls;
59 };
60
61 static void *StreamThread (void *);
62 static void *ReadThread (void *);
63 static int DemuxControl( demux_t *, int, va_list );
64 static int InitVideo (demux_t *, int);
65
66 int DemuxOpen( vlc_object_t *obj )
67 {
68     demux_t *demux = (demux_t *)obj;
69
70     demux_sys_t *sys = calloc( 1, sizeof( demux_sys_t ) );
71     if( unlikely(sys == NULL) )
72         return VLC_ENOMEM;
73     demux->p_sys = sys;
74
75     ParseMRL( obj, demux->psz_location );
76
77     char *path = var_InheritString (obj, CFG_PREFIX"dev");
78     if (unlikely(path == NULL))
79         goto error; /* probably OOM */
80     msg_Dbg (obj, "opening device '%s'", path);
81
82     int rawfd = vlc_open (path, O_RDWR);
83     if (rawfd == -1)
84     {
85         msg_Err (obj, "cannot open device '%s': %m", path);
86         free (path);
87         goto error;
88     }
89     free (path);
90
91     int fd = v4l2_fd_open (rawfd, 0);
92     if (fd == -1)
93     {
94         msg_Warn (obj, "cannot initialize user-space library: %m");
95         /* fallback to direct kernel mode anyway */
96         fd = rawfd;
97     }
98     sys->fd = fd;
99
100     if (InitVideo (demux, fd))
101     {
102         v4l2_close (fd);
103         goto error;
104     }
105
106     sys->controls = ControlsInit (VLC_OBJECT(demux), fd);
107     demux->pf_demux = NULL;
108     demux->pf_control = DemuxControl;
109     demux->info.i_update = 0;
110     demux->info.i_title = 0;
111     demux->info.i_seekpoint = 0;
112     return VLC_SUCCESS;
113 error:
114     free (sys);
115     return VLC_EGENERIC;
116 }
117
118 typedef struct
119 {
120     uint32_t v4l2;
121     vlc_fourcc_t vlc;
122     uint32_t red;
123     uint32_t green;
124     uint32_t blue;
125 } vlc_v4l2_fmt_t;
126
127 /* NOTE: Currently vlc_v4l2_fmt_rank() assumes format are sorted in order of
128  * decreasing preference. */
129 static const vlc_v4l2_fmt_t v4l2_fmts[] =
130 {
131     /* Planar YUV 4:2:0 */
132     { V4L2_PIX_FMT_YUV420,   VLC_CODEC_I420, 0, 0, 0 },
133     { V4L2_PIX_FMT_YVU420,   VLC_CODEC_YV12, 0, 0, 0 },
134     { V4L2_PIX_FMT_YUV422P,  VLC_CODEC_I422, 0, 0, 0 },
135     /* Packed YUV 4:2:2 */
136     { V4L2_PIX_FMT_YUYV,     VLC_CODEC_YUYV, 0, 0, 0 },
137     { V4L2_PIX_FMT_UYVY,     VLC_CODEC_UYVY, 0, 0, 0 },
138     { V4L2_PIX_FMT_YVYU,     VLC_CODEC_YVYU, 0, 0, 0 },
139     { V4L2_PIX_FMT_VYUY,     VLC_CODEC_VYUY, 0, 0, 0 },
140
141     { V4L2_PIX_FMT_YUV411P,  VLC_CODEC_I411, 0, 0, 0 },
142
143     { V4L2_PIX_FMT_YUV410,   VLC_CODEC_I410, 0, 0, 0 },
144 //  { V4L2_PIX_FMT_YVU410     },
145
146 //  { V4L2_PIX_FMT_NV24,      },
147 //  { V4L2_PIX_FMT_NV42,      },
148 //  { V4L2_PIX_FMT_NV16,     VLC_CODEC_NV16, 0, 0, 0 },
149 //  { V4L2_PIX_FMT_NV61,     VLC_CODEC_NV61, 0, 0, 0 },
150     { V4L2_PIX_FMT_NV12,     VLC_CODEC_NV12, 0, 0, 0 },
151     { V4L2_PIX_FMT_NV21,     VLC_CODEC_NV21, 0, 0, 0 },
152
153     /* V4L2-documented but VLC-unsupported misc. YUV formats */
154 //  { V4L2_PIX_FMT_Y41P       },
155 //  { V4L2_PIX_FMT_NV12MT,    },
156 //  { V4L2_PIX_FMT_M420,      },
157
158     /* Packed RGB */
159 #ifdef WORDS_BIGENDIAN
160     { V4L2_PIX_FMT_RGB32,    VLC_CODEC_RGB32,   0xFF00, 0xFF0000, 0xFF000000 },
161     { V4L2_PIX_FMT_BGR32,    VLC_CODEC_RGB32, 0xFF000000, 0xFF0000,   0xFF00 },
162     { V4L2_PIX_FMT_RGB24,    VLC_CODEC_RGB24,   0xFF0000, 0x00FF00, 0x0000FF },
163     { V4L2_PIX_FMT_BGR24,    VLC_CODEC_RGB24,   0x0000FF, 0x00FF00, 0xFF0000 },
164 //  { V4L2_PIX_FMT_BGR666,    },
165 //  { V4L2_PIX_FMT_RGB565,    },
166     { V4L2_PIX_FMT_RGB565X,  VLC_CODEC_RGB16,     0x001F,   0x07E0,   0xF800 },
167 //  { V4L2_PIX_FMT_RGB555,    },
168     { V4L2_PIX_FMT_RGB555X,  VLC_CODEC_RGB15,     0x001F,   0x03E0,   0x7C00 },
169 //  { V4L2_PIX_FMT_RGB444,   VLC_CODEC_RGB12,     0x000F,   0xF000,   0x0F00 },
170 #else
171     { V4L2_PIX_FMT_RGB32,    VLC_CODEC_RGB32,   0x0000FF, 0x00FF00, 0xFF0000 },
172     { V4L2_PIX_FMT_BGR32,    VLC_CODEC_RGB32,   0xFF0000, 0x00FF00, 0x0000FF },
173     { V4L2_PIX_FMT_RGB24,    VLC_CODEC_RGB24,   0x0000FF, 0x00FF00, 0xFF0000 },
174     { V4L2_PIX_FMT_BGR24,    VLC_CODEC_RGB24,   0xFF0000, 0x00FF00, 0x0000FF },
175 //  { V4L2_PIX_FMT_BGR666,    },
176     { V4L2_PIX_FMT_RGB565,   VLC_CODEC_RGB16,     0x001F,   0x07E0,   0xF800 },
177 //  { V4L2_PIX_FMT_RGB565X,   },
178     { V4L2_PIX_FMT_RGB555,   VLC_CODEC_RGB15,     0x001F,   0x03E0,   0x7C00 },
179 //  { V4L2_PIX_FMT_RGB555X,   },
180 //  { V4L2_PIX_FMT_RGB444,   VLC_CODEC_RGB12,     0x0F00,   0x00F0,   0x000F },
181 #endif
182 //  { V4L2_PIX_FMT_RGB332,   VLC_CODEC_RGB8,        0xC0,     0x38,     0x07 },
183
184     /* Bayer (sub-sampled RGB). Not supported. */
185 //  { V4L2_PIX_FMT_SBGGR16,  }
186 //  { V4L2_PIX_FMT_SRGGB12,  }
187 //  { V4L2_PIX_FMT_SGRBG12,  }
188 //  { V4L2_PIX_FMT_SGBRG12,  }
189 //  { V4L2_PIX_FMT_SBGGR12,  }
190 //  { V4L2_PIX_FMT_SRGGB10,  }
191 //  { V4L2_PIX_FMT_SGRBG10,  }
192 //  { V4L2_PIX_FMT_SGBRG10,  }
193 //  { V4L2_PIX_FMT_SBGGR10,  }
194 //  { V4L2_PIX_FMT_SBGGR8,   }
195 //  { V4L2_PIX_FMT_SGBRG8,   }
196 //  { V4L2_PIX_FMT_SGRBG8,   }
197 //  { V4L2_PIX_FMT_SRGGB8,   }
198
199     /* Compressed data types */
200     { V4L2_PIX_FMT_JPEG,   VLC_CODEC_MJPG, 0, 0, 0 },
201 #ifdef V4L2_PIX_FMT_H264
202     { V4L2_PIX_FMT_H264,   VLC_CODEC_H264, 0, 0, 0 },
203     /* FIXME: fill p_extra for avc1... */
204 //  { V4L2_PIX_FMT_H264_NO_SC, VLC_FOURCC('a','v','c','1'), 0, 0, 0 }
205     { V4L2_PIX_FMT_MPEG4,  VLC_CODEC_MP4V, 0, 0, 0 },
206     { V4L2_PIX_FMT_XVID,   VLC_CODEC_MP4V, 0, 0, 0 },
207     { V4L2_PIX_FMT_H263,   VLC_CODEC_H263, 0, 0, 0 },
208     { V4L2_PIX_FMT_MPEG2,  VLC_CODEC_MPGV, 0, 0, 0 },
209     { V4L2_PIX_FMT_MPEG1,  VLC_CODEC_MPGV, 0, 0, 0 },
210     { V4L2_PIX_FMT_VC1_ANNEX_G, VLC_CODEC_VC1, 0, 0, 0 },
211     { V4L2_PIX_FMT_VC1_ANNEX_L, VLC_CODEC_VC1, 0, 0, 0 },
212 #endif
213     //V4L2_PIX_FMT_MPEG -> use access
214
215     /* Reserved formats */
216     { V4L2_PIX_FMT_MJPEG,   VLC_CODEC_MJPG, 0, 0, 0 },
217     //V4L2_PIX_FMT_DV -> use access
218
219     /* Grey scale */
220 //  { V4L2_PIX_FMT_Y16,       },
221 //  { V4L2_PIX_FMT_Y12,       },
222 //  { V4L2_PIX_FMT_Y10,       },
223 //  { V4L2_PIX_FMT_Y10BPACK,  },
224     { V4L2_PIX_FMT_GREY,     VLC_CODEC_GREY, 0, 0, 0 },
225 };
226
227 static const vlc_v4l2_fmt_t *vlc_from_v4l2_fourcc (uint32_t fourcc)
228 {
229      for (size_t i = 0; i < sizeof (v4l2_fmts) / sizeof (v4l2_fmts[0]); i++)
230          if (v4l2_fmts[i].v4l2 == fourcc)
231              return v4l2_fmts + i;
232      return NULL;
233 }
234
235 static size_t vlc_v4l2_fmt_rank (const vlc_v4l2_fmt_t *fmt)
236 {
237     if (fmt == NULL)
238         return SIZE_MAX;
239
240     ptrdiff_t d = fmt - v4l2_fmts;
241     assert (d >= 0);
242     assert (d < (ptrdiff_t)(sizeof (v4l2_fmts) / sizeof (v4l2_fmts[0])));
243     return d;
244 }
245
246 static vlc_fourcc_t var_InheritFourCC (vlc_object_t *obj, const char *varname)
247 {
248     char *str = var_InheritString (obj, varname);
249     if (str == NULL)
250         return 0;
251
252     vlc_fourcc_t fourcc = vlc_fourcc_GetCodecFromString (VIDEO_ES, str);
253     if (fourcc == 0)
254         msg_Err (obj, "invalid codec %s", str);
255     free (str);
256     return fourcc;
257 }
258 #define var_InheritFourCC(o, v) var_InheritFourCC(VLC_OBJECT(o), v)
259
260 static void GetAR (int fd, unsigned *restrict num, unsigned *restrict den)
261 {
262     struct v4l2_cropcap cropcap = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
263
264     /* TODO: get CROPCAP only once (see ResetCrop()). */
265     if (v4l2_ioctl (fd, VIDIOC_CROPCAP, &cropcap) < 0)
266     {
267         *num = *den = 1;
268         return;
269     }
270     *num = cropcap.pixelaspect.numerator;
271     *den = cropcap.pixelaspect.denominator;
272 }
273
274 static int InitVideo (demux_t *demux, int fd)
275 {
276     demux_sys_t *sys = demux->p_sys;
277
278     /* Get device capabilites */
279     struct v4l2_capability cap;
280     if (v4l2_ioctl (fd, VIDIOC_QUERYCAP, &cap) < 0)
281     {
282         msg_Err (demux, "cannot get device capabilities: %m");
283         return -1;
284     }
285
286     msg_Dbg (demux, "device %s using driver %s (version %u.%u.%u) on %s",
287             cap.card, cap.driver, (cap.version >> 16) & 0xFF,
288             (cap.version >> 8) & 0xFF, cap.version & 0xFF, cap.bus_info);
289
290     uint32_t caps;
291 #ifdef V4L2_CAP_DEVICE_CAPS
292     if (cap.capabilities & V4L2_CAP_DEVICE_CAPS)
293     {
294         msg_Dbg (demux, " with capabilities 0x%08"PRIX32" "
295                  "(overall 0x%08"PRIX32")", cap.device_caps, cap.capabilities);
296         caps = cap.device_caps;
297     }
298     else
299 #endif
300     {
301         msg_Dbg (demux, " with unknown capabilities  "
302                  "(overall 0x%08"PRIX32")", cap.capabilities);
303         caps = cap.capabilities;
304     }
305     if (!(caps & V4L2_CAP_VIDEO_CAPTURE))
306     {
307         msg_Err (demux, "not a video capture device");
308         return -1;
309     }
310
311     if (SetupInput (VLC_OBJECT(demux), fd))
312         return -1;
313
314     /* Picture format negotiation */
315     const vlc_v4l2_fmt_t *selected = NULL;
316     vlc_fourcc_t reqfourcc = var_InheritFourCC (demux, CFG_PREFIX"chroma");
317     bool native = false;
318
319     for (struct v4l2_fmtdesc codec = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
320          v4l2_ioctl (fd, VIDIOC_ENUM_FMT, &codec) >= 0;
321          codec.index++)
322     {   /* Enumerate available chromas */
323         const vlc_v4l2_fmt_t *dsc = vlc_from_v4l2_fourcc (codec.pixelformat);
324
325         msg_Dbg (demux, " %s %s format %4.4s (%4.4s): %s",
326               (codec.flags & V4L2_FMT_FLAG_EMULATED) ? "emulates" : "supports",
327               (codec.flags & V4L2_FMT_FLAG_COMPRESSED) ? "compressed" : "raw",
328                  (char *)&codec.pixelformat,
329                  (dsc != NULL) ? (const char *)&dsc->vlc : "N.A.",
330                  codec.description);
331
332         if (dsc == NULL)
333             continue; /* ignore VLC-unsupported codec */
334
335         if (dsc->vlc == reqfourcc)
336         {
337             msg_Dbg (demux, "  matches the requested format");
338             selected = dsc;
339             break; /* always select the requested format if found */
340         }
341
342         if (codec.flags & V4L2_FMT_FLAG_EMULATED)
343         {
344             if (native)
345                 continue; /* ignore emulated format if possible */
346         }
347         else
348             native = true;
349
350         if (vlc_v4l2_fmt_rank (dsc) > vlc_v4l2_fmt_rank (selected))
351             continue; /* ignore if rank is worse */
352
353         selected = dsc;
354     }
355
356     if (selected == NULL)
357     {
358         msg_Err (demux, "cannot negotiate supported video format");
359         return -1;
360     }
361     msg_Dbg (demux, "selected format %4.4s (%4.4s)",
362              (const char *)&selected->v4l2, (const char *)&selected->vlc);
363
364     /* Find best resolution and frame rate available */
365     struct v4l2_format fmt;
366     struct v4l2_streamparm parm;
367     if (SetupFormat (demux, fd, selected->v4l2, &fmt, &parm))
368         return -1;
369
370     /* Print extra info */
371     msg_Dbg (demux, "%d bytes maximum for complete image",
372              fmt.fmt.pix.sizeimage);
373     /* Check interlacing */
374     switch (fmt.fmt.pix.field)
375     {
376         case V4L2_FIELD_NONE:
377             msg_Dbg (demux, "Interlacing setting: progressive");
378             break;
379         case V4L2_FIELD_TOP:
380             msg_Dbg (demux, "Interlacing setting: top field only");
381             break;
382         case V4L2_FIELD_BOTTOM:
383             msg_Dbg (demux, "Interlacing setting: bottom field only");
384             break;
385         case V4L2_FIELD_INTERLACED:
386             msg_Dbg (demux, "Interlacing setting: interleaved");
387             /*if (NTSC)
388                 sys->block_flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
389             else*/
390                 sys->block_flags = BLOCK_FLAG_TOP_FIELD_FIRST;
391             break;
392         case V4L2_FIELD_SEQ_TB:
393             msg_Dbg (demux, "Interlacing setting: sequential top bottom (TODO)");
394             break;
395         case V4L2_FIELD_SEQ_BT:
396             msg_Dbg (demux, "Interlacing setting: sequential bottom top (TODO)");
397             break;
398         case V4L2_FIELD_ALTERNATE:
399             msg_Dbg (demux, "Interlacing setting: alternate fields (TODO)");
400             fmt.fmt.pix.height *= 2;
401             break;
402         case V4L2_FIELD_INTERLACED_TB:
403             msg_Dbg (demux, "Interlacing setting: interleaved top bottom");
404             sys->block_flags = BLOCK_FLAG_TOP_FIELD_FIRST;
405             break;
406         case V4L2_FIELD_INTERLACED_BT:
407             msg_Dbg (demux, "Interlacing setting: interleaved bottom top");
408             sys->block_flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
409             break;
410         default:
411             msg_Warn (demux, "Interlacing setting: unknown type (%d)",
412                       fmt.fmt.pix.field);
413             break;
414     }
415
416     /* Declare our unique elementary (video) stream */
417     es_format_t es_fmt;
418
419     es_format_Init (&es_fmt, VIDEO_ES, selected->vlc);
420     es_fmt.video.i_rmask = selected->red;
421     es_fmt.video.i_gmask = selected->green;
422     es_fmt.video.i_bmask = selected->blue;
423     es_fmt.video.i_width = fmt.fmt.pix.width;
424     es_fmt.video.i_height = fmt.fmt.pix.height;
425     es_fmt.video.i_frame_rate = parm.parm.capture.timeperframe.denominator;
426     es_fmt.video.i_frame_rate_base = parm.parm.capture.timeperframe.numerator;
427     GetAR (fd, &es_fmt.video.i_sar_num, &es_fmt.video.i_sar_den);
428
429     msg_Dbg (demux, "added new video ES %4.4s %ux%u", (char *)&es_fmt.i_codec,
430              es_fmt.video.i_width, es_fmt.video.i_height);
431     msg_Dbg (demux, " frame rate: %u/%u", es_fmt.video.i_frame_rate,
432              es_fmt.video.i_frame_rate_base);
433     msg_Dbg (demux, " aspect ratio: %u/%u", es_fmt.video.i_sar_num,
434              es_fmt.video.i_sar_den);
435     sys->es = es_out_Add (demux->out, &es_fmt);
436
437     /* Init I/O method */
438     void *(*entry) (void *);
439     if (caps & V4L2_CAP_STREAMING)
440     {
441         sys->bufc = 4;
442         sys->bufv = StartMmap (VLC_OBJECT(demux), fd, &sys->bufc);
443         if (sys->bufv == NULL)
444             return -1;
445         entry = StreamThread;
446     }
447     else if (caps & V4L2_CAP_READWRITE)
448     {
449         sys->bufv = NULL;
450         sys->blocksize = fmt.fmt.pix.sizeimage;
451         entry = ReadThread;
452     }
453     else
454     {
455         msg_Err (demux, "no supported I/O method");
456         return -1;
457     }
458
459     if (vlc_clone (&sys->thread, entry, demux, VLC_THREAD_PRIORITY_INPUT))
460         return -1;
461     return 0;
462 }
463
464 void DemuxClose( vlc_object_t *obj )
465 {
466     demux_t *demux = (demux_t *)obj;
467     demux_sys_t *sys = demux->p_sys;
468
469     vlc_cancel (sys->thread);
470     vlc_join (sys->thread, NULL);
471     if (sys->bufv != NULL)
472         StopMmap (sys->fd, sys->bufv, sys->bufc);
473     ControlsDeinit( obj, sys->controls );
474     v4l2_close (sys->fd);
475     free( sys );
476 }
477
478 static void *StreamThread (void *data)
479 {
480     demux_t *demux = data;
481     demux_sys_t *sys = demux->p_sys;
482     int fd = sys->fd;
483     struct pollfd ufd[1];
484
485     ufd[0].fd = fd;
486     ufd[0].events = POLLIN | POLLPRI;
487
488     for (;;)
489     {
490         /* Wait for data */
491         if (poll (ufd, 1, -1) == -1)
492         {
493            if (errno != EINTR)
494                msg_Err (demux, "poll error: %m");
495            continue;
496         }
497
498         int canc = vlc_savecancel ();
499         block_t *block = GrabVideo (VLC_OBJECT(demux), fd, sys->bufv);
500         if (block != NULL)
501         {
502             block->i_pts = block->i_dts = mdate ();
503             block->i_flags |= sys->block_flags;
504             es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts);
505             es_out_Send (demux->out, sys->es, block);
506         }
507         vlc_restorecancel (canc);
508     }
509
510     assert (0);
511 }
512
513 static void *ReadThread (void *data)
514 {
515     demux_t *demux = data;
516     demux_sys_t *sys = demux->p_sys;
517     int fd = sys->fd;
518     struct pollfd ufd[1];
519
520     ufd[0].fd = fd;
521     ufd[0].events = POLLIN | POLLPRI;
522
523     for (;;)
524     {
525         /* Wait for data */
526         if (poll (ufd, 1, -1) == -1)
527         {
528            if (errno != EINTR)
529                msg_Err (demux, "poll error: %m");
530            continue;
531         }
532
533         block_t *block = block_Alloc (sys->blocksize);
534         if (unlikely(block == NULL))
535         {
536             msg_Err (demux, "read error: %m");
537             v4l2_read (fd, NULL, 0); /* discard frame */
538             continue;
539         }
540         block->i_pts = block->i_dts = mdate ();
541         block->i_flags |= sys->block_flags;
542
543         int canc = vlc_savecancel ();
544         ssize_t val = v4l2_read (fd, block->p_buffer, block->i_buffer);
545         if (val != -1)
546         {
547             block->i_buffer = val;
548             es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts);
549             es_out_Send (demux->out, sys->es, block);
550         }
551         else
552             block_Release (block);
553         vlc_restorecancel (canc);
554     }
555     assert (0);
556 }
557
558 static int DemuxControl( demux_t *demux, int query, va_list args )
559 {
560     switch( query )
561     {
562         /* Special for access_demux */
563         case DEMUX_CAN_PAUSE:
564         case DEMUX_CAN_SEEK:
565         case DEMUX_CAN_CONTROL_PACE:
566             *va_arg( args, bool * ) = false;
567             return VLC_SUCCESS;
568
569         case DEMUX_GET_PTS_DELAY:
570             *va_arg(args,int64_t *) = INT64_C(1000)
571                 * var_InheritInteger( demux, "live-caching" );
572             return VLC_SUCCESS;
573
574         case DEMUX_GET_TIME:
575             *va_arg( args, int64_t * ) = mdate();
576             return VLC_SUCCESS;
577
578         /* TODO implement others */
579         default:
580             return VLC_EGENERIC;
581     }
582
583     return VLC_EGENERIC;
584 }