1 /*****************************************************************************
2 * access.c : V4L2 compressed byte stream input module for vlc
3 *****************************************************************************
4 * Copyright (C) 2002-2011 VLC authors and VideoLAN
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 it
12 * 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 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_access.h>
48 struct buffer_t *bufv;
49 vlc_v4l2_ctrl_t *controls;
52 static block_t *MMapBlock (access_t *);
53 static block_t *ReadBlock (access_t *);
54 static int AccessControl( access_t *, int, va_list );
55 static int InitVideo(access_t *, int, uint32_t);
57 int AccessOpen( vlc_object_t *obj )
59 access_t *access = (access_t *)obj;
61 access_InitFields( access );
63 access_sys_t *sys = calloc (1, sizeof (*sys));
64 if( unlikely(sys == NULL) )
68 ParseMRL( obj, access->psz_location );
70 char *path = var_InheritString (obj, CFG_PREFIX"dev");
71 if (unlikely(path == NULL))
72 goto error; /* probably OOM */
75 int fd = OpenDevice (obj, path, &caps);
81 if (InitVideo (access, fd, caps))
87 sys->controls = ControlsInit (VLC_OBJECT(access), fd);
88 access->pf_seek = NULL;
89 access->pf_control = AccessControl;
96 int InitVideo (access_t *access, int fd, uint32_t caps)
98 access_sys_t *sys = access->p_sys;
100 if (!(caps & V4L2_CAP_VIDEO_CAPTURE))
102 msg_Err (access, "not a video capture device");
107 if (SetupInput (VLC_OBJECT(access), fd, &std))
110 /* NOTE: The V4L access_demux expects a VLC FOURCC as "chroma". It is used to set the
111 * es_format_t structure correctly. However, the V4L access (*here*) has no use for a
112 * VLC FOURCC and expects a V4L2 format directly instead. That is confusing :-( */
114 char *fmtstr = var_InheritString (access, CFG_PREFIX"chroma");
115 if (fmtstr != NULL && strlen (fmtstr) <= 4)
117 memcpy (&pixfmt, fmtstr, strlen (fmtstr));
121 /* Use the default^Wprevious format if none specified */
123 struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
124 if (v4l2_ioctl (fd, VIDIOC_G_FMT, &fmt) < 0)
126 msg_Err (access, "cannot get default format: %m");
129 pixfmt = fmt.fmt.pix.pixelformat;
131 msg_Dbg (access, "selected format %4.4s", (const char *)&pixfmt);
133 struct v4l2_format fmt;
134 struct v4l2_streamparm parm;
135 if (SetupFormat (access, fd, pixfmt, &fmt, &parm))
138 msg_Dbg (access, "%"PRIu32" bytes for complete image", fmt.fmt.pix.sizeimage);
139 /* Check interlacing */
140 switch (fmt.fmt.pix.field)
142 case V4L2_FIELD_INTERLACED:
143 msg_Dbg (access, "Interlacing setting: interleaved");
145 sys->block_flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
147 sys->block_flags = BLOCK_FLAG_TOP_FIELD_FIRST;
149 case V4L2_FIELD_INTERLACED_TB:
150 msg_Dbg (access, "Interlacing setting: interleaved top bottom" );
151 sys->block_flags = BLOCK_FLAG_TOP_FIELD_FIRST;
153 case V4L2_FIELD_INTERLACED_BT:
154 msg_Dbg (access, "Interlacing setting: interleaved bottom top" );
155 sys->block_flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
161 /* Init I/O method */
162 if (caps & V4L2_CAP_STREAMING)
165 sys->bufv = StartMmap (VLC_OBJECT(access), fd, &sys->bufc);
166 if (sys->bufv == NULL)
168 access->pf_block = MMapBlock;
170 else if (caps & V4L2_CAP_READWRITE)
172 sys->blocksize = fmt.fmt.pix.sizeimage;
174 access->pf_block = ReadBlock;
178 msg_Err (access, "no supported capture method");
185 void AccessClose( vlc_object_t *obj )
187 access_t *access = (access_t *)obj;
188 access_sys_t *sys = access->p_sys;
190 if (sys->bufv != NULL)
191 StopMmap (sys->fd, sys->bufv, sys->bufc);
192 ControlsDeinit( obj, sys->controls );
193 v4l2_close (sys->fd);
198 static int AccessPoll (access_t *access)
200 access_sys_t *sys = access->p_sys;
206 switch (poll (&ufd, 1, 500))
211 /* FIXME: kill this case (arbitrary timeout) */
213 msg_Err (access, "poll error: %m");
214 access->info.b_eof = true;
221 static block_t *MMapBlock (access_t *access)
223 access_sys_t *sys = access->p_sys;
225 if (AccessPoll (access))
228 block_t *block = GrabVideo (VLC_OBJECT(access), sys->fd, sys->bufv);
231 block->i_pts = block->i_dts = mdate();
232 block->i_flags |= sys->block_flags;
237 static block_t *ReadBlock (access_t *access)
239 access_sys_t *sys = access->p_sys;
241 if (AccessPoll (access))
244 block_t *block = block_Alloc (sys->blocksize);
245 if (unlikely(block == NULL))
248 ssize_t val = v4l2_read (sys->fd, block->p_buffer, block->i_buffer);
251 block_Release (block);
252 msg_Err (access, "cannot read buffer: %m");
253 access->info.b_eof = true;
257 block->i_buffer = val;
258 access->info.i_pos += val;
262 static int AccessControl( access_t *access, int query, va_list args )
267 case ACCESS_CAN_SEEK:
268 case ACCESS_CAN_FASTSEEK:
269 case ACCESS_CAN_PAUSE:
270 case ACCESS_CAN_CONTROL_PACE:
271 *va_arg( args, bool* ) = false;
275 case ACCESS_GET_PTS_DELAY:
276 *va_arg(args,int64_t *) = INT64_C(1000)
277 * var_InheritInteger( access, "live-caching" );
281 case ACCESS_SET_PAUSE_STATE:
285 case ACCESS_GET_TITLE_INFO:
286 case ACCESS_SET_TITLE:
287 case ACCESS_SET_SEEKPOINT:
288 case ACCESS_SET_PRIVATE_ID_STATE:
289 case ACCESS_GET_CONTENT_TYPE:
290 case ACCESS_GET_META:
294 msg_Warn( access, "Unimplemented query %d in control", query );