1 /*****************************************************************************
2 * demux.c : V4L2 raw video demux module for vlc
3 *****************************************************************************
4 * Copyright (C) 2002-2011 the VideoLAN team
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>
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.
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.
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 *****************************************************************************/
33 #include <sys/ioctl.h>
36 # define MAP_ANONYMOUS MAP_ANON
40 #include <vlc_common.h>
41 #include <vlc_demux.h>
50 struct buffer_t *bufv;
59 vlc_v4l2_ctrl_t *controls;
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);
69 int DemuxOpen( vlc_object_t *obj )
71 demux_t *demux = (demux_t *)obj;
73 demux_sys_t *sys = malloc (sizeof (*sys));
74 if (unlikely(sys == NULL))
78 ParseMRL( obj, demux->psz_location );
80 char *path = var_InheritString (obj, CFG_PREFIX"dev");
81 if (unlikely(path == NULL))
82 goto error; /* probably OOM */
85 int fd = OpenDevice (obj, path, &caps);
91 if (InitVideo (demux, fd, caps))
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;
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[] =
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 },
133 { V4L2_PIX_FMT_YUV411P, VLC_CODEC_I411, 0, 0, 0 },
135 { V4L2_PIX_FMT_YUV410, VLC_CODEC_I410, 0, 0, 0 },
136 // { V4L2_PIX_FMT_YVU410 },
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 },
145 /* V4L2-documented but VLC-unsupported misc. YUV formats */
146 // { V4L2_PIX_FMT_Y41P },
147 // { V4L2_PIX_FMT_NV12MT, },
148 // { V4L2_PIX_FMT_M420, },
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 },
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 },
174 // { V4L2_PIX_FMT_RGB332, VLC_CODEC_RGB8, 0xC0, 0x38, 0x07 },
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, }
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 },
205 //V4L2_PIX_FMT_MPEG -> use access
207 /* Reserved formats */
208 { V4L2_PIX_FMT_MJPEG, VLC_CODEC_MJPG, 0, 0, 0 },
209 //V4L2_PIX_FMT_DV -> use access
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 },
219 static const vlc_v4l2_fmt_t *vlc_from_v4l2_fourcc (uint32_t fourcc)
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;
227 static size_t vlc_v4l2_fmt_rank (const vlc_v4l2_fmt_t *fmt)
232 ptrdiff_t d = fmt - v4l2_fmts;
234 assert (d < (ptrdiff_t)(sizeof (v4l2_fmts) / sizeof (v4l2_fmts[0])));
238 static vlc_fourcc_t var_InheritFourCC (vlc_object_t *obj, const char *varname)
240 char *str = var_InheritString (obj, varname);
244 vlc_fourcc_t fourcc = vlc_fourcc_GetCodecFromString (VIDEO_ES, str);
246 msg_Err (obj, "invalid codec %s", str);
250 #define var_InheritFourCC(o, v) var_InheritFourCC(VLC_OBJECT(o), v)
252 static void GetAR (int fd, unsigned *restrict num, unsigned *restrict den)
254 struct v4l2_cropcap cropcap = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
256 /* TODO: get CROPCAP only once (see ResetCrop()). */
257 if (v4l2_ioctl (fd, VIDIOC_CROPCAP, &cropcap) < 0)
262 *num = cropcap.pixelaspect.numerator;
263 *den = cropcap.pixelaspect.denominator;
266 static int InitVideo (demux_t *demux, int fd, uint32_t caps)
268 demux_sys_t *sys = demux->p_sys;
270 if (!(caps & V4L2_CAP_VIDEO_CAPTURE))
272 msg_Err (demux, "not a video capture device");
276 if (SetupInput (VLC_OBJECT(demux), fd))
279 /* Picture format negotiation */
280 const vlc_v4l2_fmt_t *selected = NULL;
281 vlc_fourcc_t reqfourcc = var_InheritFourCC (demux, CFG_PREFIX"chroma");
284 for (struct v4l2_fmtdesc codec = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
285 v4l2_ioctl (fd, VIDIOC_ENUM_FMT, &codec) >= 0;
287 { /* Enumerate available chromas */
288 const vlc_v4l2_fmt_t *dsc = vlc_from_v4l2_fourcc (codec.pixelformat);
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.",
298 continue; /* ignore VLC-unsupported codec */
300 if (dsc->vlc == reqfourcc)
302 msg_Dbg (demux, " matches the requested format");
304 break; /* always select the requested format if found */
307 if (codec.flags & V4L2_FMT_FLAG_EMULATED)
310 continue; /* ignore emulated format if possible */
315 if (vlc_v4l2_fmt_rank (dsc) > vlc_v4l2_fmt_rank (selected))
316 continue; /* ignore if rank is worse */
321 if (selected == NULL)
323 msg_Err (demux, "cannot negotiate supported video format");
326 msg_Dbg (demux, "selected format %4.4s (%4.4s)",
327 (const char *)&selected->v4l2, (const char *)&selected->vlc);
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))
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)
342 case V4L2_FIELD_NONE:
343 msg_Dbg (demux, "Interlacing setting: progressive");
346 msg_Dbg (demux, "Interlacing setting: top field only");
348 case V4L2_FIELD_BOTTOM:
349 msg_Dbg (demux, "Interlacing setting: bottom field only");
351 case V4L2_FIELD_INTERLACED:
352 msg_Dbg (demux, "Interlacing setting: interleaved");
354 sys->block_flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
356 sys->block_flags = BLOCK_FLAG_TOP_FIELD_FIRST;
358 case V4L2_FIELD_SEQ_TB:
359 msg_Dbg (demux, "Interlacing setting: sequential top bottom (TODO)");
361 case V4L2_FIELD_SEQ_BT:
362 msg_Dbg (demux, "Interlacing setting: sequential bottom top (TODO)");
364 case V4L2_FIELD_ALTERNATE:
365 msg_Dbg (demux, "Interlacing setting: alternate fields (TODO)");
366 fmt.fmt.pix.height *= 2;
368 case V4L2_FIELD_INTERLACED_TB:
369 msg_Dbg (demux, "Interlacing setting: interleaved top bottom");
370 sys->block_flags = BLOCK_FLAG_TOP_FIELD_FIRST;
372 case V4L2_FIELD_INTERLACED_BT:
373 msg_Dbg (demux, "Interlacing setting: interleaved bottom top");
374 sys->block_flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
377 msg_Warn (demux, "Interlacing setting: unknown type (%d)",
382 /* Declare our unique elementary (video) stream */
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);
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);
403 /* Init I/O method */
404 void *(*entry) (void *);
405 if (caps & V4L2_CAP_STREAMING)
407 if (StartUserPtr (VLC_OBJECT(demux), fd) == 0)
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;
414 sys->blocksize = (fmt.fmt.pix.sizeimage + pagemask) & ~pagemask;
416 entry = UserPtrThread;
417 msg_Dbg (demux, "streaming with %"PRIu32"-bytes user buffers",
420 else /* fall back to memory map */
423 sys->bufv = StartMmap (VLC_OBJECT(demux), fd, &sys->bufc);
424 if (sys->bufv == NULL)
427 msg_Dbg (demux, "streaming with %"PRIu32" memory-mapped buffers",
431 else if (caps & V4L2_CAP_READWRITE)
433 sys->blocksize = fmt.fmt.pix.sizeimage;
436 msg_Dbg (demux, "reading %"PRIu32" bytes at a time", sys->blocksize);
440 msg_Err (demux, "no supported capture method");
444 if (vlc_clone (&sys->thread, entry, demux, VLC_THREAD_PRIORITY_INPUT))
446 if (sys->bufv != NULL)
447 StopMmap (sys->fd, sys->bufv, sys->bufc);
453 void DemuxClose( vlc_object_t *obj )
455 demux_t *demux = (demux_t *)obj;
456 demux_sys_t *sys = demux->p_sys;
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);
467 /** Allocates and queue a user buffer using mmap(). */
468 static block_t *UserPtrQueue (vlc_object_t *obj, int fd, size_t length)
470 void *ptr = mmap (NULL, length, PROT_READ | PROT_WRITE,
471 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
472 if (ptr == MAP_FAILED)
474 msg_Err (obj, "cannot allocate %zu-bytes buffer: %m", length);
478 block_t *block = block_mmap_Alloc (ptr, length);
479 if (unlikely(block == NULL))
481 munmap (ptr, length);
485 struct v4l2_buffer buf = {
486 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
487 .memory = V4L2_MEMORY_USERPTR,
489 .userptr = (uintptr_t)ptr,
494 if (v4l2_ioctl (fd, VIDIOC_QBUF, &buf) < 0)
496 msg_Err (obj, "cannot queue buffer: %m");
497 block_Release (block);
503 static void *UserPtrThread (void *data)
505 demux_t *demux = data;
506 demux_sys_t *sys = demux->p_sys;
508 struct pollfd ufd[1];
511 ufd[0].events = POLLIN;
513 int canc = vlc_savecancel ();
516 struct v4l2_buffer buf = {
517 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
518 .memory = V4L2_MEMORY_USERPTR,
520 block_t *block = UserPtrQueue (VLC_OBJECT(demux), fd, sys->blocksize);
525 vlc_restorecancel (canc);
526 block_cleanup_push (block);
527 while (poll (ufd, 1, -1) == -1)
529 msg_Err (demux, "poll error: %m");
531 canc = vlc_savecancel ();
533 if (v4l2_ioctl (fd, VIDIOC_DQBUF, &buf) < 0)
535 msg_Err (demux, "cannot dequeue buffer: %m");
536 block_Release (block);
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);
547 vlc_restorecancel (canc); /* <- hmm, this is purely cosmetic */
551 static void *MmapThread (void *data)
553 demux_t *demux = data;
554 demux_sys_t *sys = demux->p_sys;
556 struct pollfd ufd[1];
559 ufd[0].events = POLLIN;
564 if (poll (ufd, 1, -1) == -1)
567 msg_Err (demux, "poll error: %m");
571 int canc = vlc_savecancel ();
572 block_t *block = GrabVideo (VLC_OBJECT(demux), fd, sys->bufv);
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);
580 vlc_restorecancel (canc);
586 static void *ReadThread (void *data)
588 demux_t *demux = data;
589 demux_sys_t *sys = demux->p_sys;
591 struct pollfd ufd[1];
594 ufd[0].events = POLLIN;
599 if (poll (ufd, 1, -1) == -1)
602 msg_Err (demux, "poll error: %m");
606 block_t *block = block_Alloc (sys->blocksize);
607 if (unlikely(block == NULL))
609 msg_Err (demux, "read error: %m");
610 v4l2_read (fd, NULL, 0); /* discard frame */
613 block->i_pts = block->i_dts = mdate ();
614 block->i_flags |= sys->block_flags;
616 int canc = vlc_savecancel ();
617 ssize_t val = v4l2_read (fd, block->p_buffer, block->i_buffer);
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);
625 block_Release (block);
626 vlc_restorecancel (canc);
631 static int DemuxControl( demux_t *demux, int query, va_list args )
633 demux_sys_t *sys = demux->p_sys;
637 /* Special for access_demux */
638 case DEMUX_CAN_PAUSE:
640 case DEMUX_CAN_CONTROL_PACE:
641 *va_arg( args, bool * ) = false;
644 case DEMUX_GET_PTS_DELAY:
645 *va_arg(args,int64_t *) = INT64_C(1000)
646 * var_InheritInteger( demux, "live-caching" );
650 *va_arg (args, int64_t *) = mdate() - sys->start;
653 /* TODO implement others */