]> git.sesse.net Git - vlc/blob - modules/access/v4l2/access.c
3cd0e56bf4f51d5a7ada26c56bc9f4e80f58ab16
[vlc] / modules / access / v4l2 / access.c
1 /*****************************************************************************
2  * access.c : V4L2 compressed byte stream input 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 <assert.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <poll.h>
34
35 #include <vlc_common.h>
36 #include <vlc_access.h>
37 #include <vlc_fs.h>
38
39 #include "v4l2.h"
40
41 struct access_sys_t
42 {
43     int fd;
44     uint32_t block_flags;
45     union
46     {
47         uint32_t bufc;
48         uint32_t blocksize;
49     };
50     struct buffer_t *bufv;
51     vlc_v4l2_ctrl_t *controls;
52 };
53
54 static block_t *AccessRead( access_t * );
55 static ssize_t AccessReadStream( access_t *, uint8_t *, size_t );
56 static int AccessControl( access_t *, int, va_list );
57 static int InitVideo(access_t *, int);
58
59 int AccessOpen( vlc_object_t *obj )
60 {
61     access_t *access = (access_t *)obj;
62
63     access_InitFields( access );
64
65     access_sys_t *sys = calloc (1, sizeof (*sys));
66     if( unlikely(sys == NULL) )
67         return VLC_ENOMEM;
68     access->p_sys = sys;
69
70     ParseMRL( obj, access->psz_location );
71
72     char *path = var_InheritString (obj, CFG_PREFIX"dev");
73     if (unlikely(path == NULL))
74         goto error; /* probably OOM */
75     msg_Dbg (obj, "opening device '%s'", path);
76
77     int rawfd = vlc_open (path, O_RDWR);
78     if (rawfd == -1)
79     {
80         msg_Err (obj, "cannot open device '%s': %m", path);
81         free (path);
82         goto error;
83     }
84     free (path);
85
86     int fd = v4l2_fd_open (rawfd, 0);
87     if (fd == -1)
88     {
89         msg_Warn (obj, "cannot initialize user-space library: %m");
90         /* fallback to direct kernel mode anyway */
91         fd = rawfd;
92     }
93
94     if (InitVideo (access, fd))
95     {
96         v4l2_close (fd);
97         goto error;
98     }
99
100     sys->fd = fd;
101     access->pf_seek = NULL;
102     access->pf_control = AccessControl;
103     return VLC_SUCCESS;
104 error:
105     free (sys);
106     return VLC_EGENERIC;
107 }
108
109 int InitVideo (access_t *access, int fd)
110 {
111     access_sys_t *sys = access->p_sys;
112
113     /* Get device capabilites */
114     struct v4l2_capability cap;
115     if (v4l2_ioctl (fd, VIDIOC_QUERYCAP, &cap) < 0)
116     {
117         msg_Err (access, "cannot get device capabilities: %m");
118         return -1;
119     }
120
121     msg_Dbg (access, "device %s using driver %s (version %u.%u.%u) on %s",
122              cap.card, cap.driver, (cap.version >> 16) & 0xFF,
123              (cap.version >> 8) & 0xFF, cap.version & 0xFF, cap.bus_info);
124     msg_Dbg (access, "the device has the capabilities: 0x%08X",
125              cap.capabilities);
126     msg_Dbg (access, " (%c) Video Capture, (%c) Audio, (%c) Tuner, (%c) Radio",
127              (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE  ? 'X':' '),
128              (cap.capabilities & V4L2_CAP_AUDIO  ? 'X':' '),
129              (cap.capabilities & V4L2_CAP_TUNER  ? 'X':' '),
130              (cap.capabilities & V4L2_CAP_RADIO  ? 'X':' '));
131     msg_Dbg (access, " (%c) Read/Write, (%c) Streaming, (%c) Asynchronous",
132              (cap.capabilities & V4L2_CAP_READWRITE ? 'X':' '),
133              (cap.capabilities & V4L2_CAP_STREAMING ? 'X':' '),
134              (cap.capabilities & V4L2_CAP_ASYNCIO ? 'X':' '));
135
136     if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
137     {
138         msg_Err (access, "not a video capture device");
139         return -1;
140     }
141
142     if (SetupInput (VLC_OBJECT(access), fd))
143         return -1;
144
145     sys->controls = ControlsInit (VLC_OBJECT(access), fd);
146
147     /* Try and find default resolution if not specified */
148     struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
149     if (v4l2_ioctl (fd, VIDIOC_G_FMT, &fmt) < 0)
150     {
151         msg_Err (access, "cannot get default format: %m");
152         return -1;
153     }
154
155     /* Print extra info */
156     msg_Dbg (access, "%d bytes maximum for complete image",
157              fmt.fmt.pix.sizeimage );
158     /* Check interlacing */
159     switch (fmt.fmt.pix.field)
160     {
161         case V4L2_FIELD_INTERLACED:
162             msg_Dbg (access, "Interlacing setting: interleaved");
163             /*if (NTSC)
164                 sys->block_flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
165             else*/
166                 sys->block_flags = BLOCK_FLAG_TOP_FIELD_FIRST;
167             break;
168         case V4L2_FIELD_INTERLACED_TB:
169             msg_Dbg (access, "Interlacing setting: interleaved top bottom" );
170             sys->block_flags = BLOCK_FLAG_TOP_FIELD_FIRST;
171             break;
172         case V4L2_FIELD_INTERLACED_BT:
173             msg_Dbg (access, "Interlacing setting: interleaved bottom top" );
174             sys->block_flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
175             break;
176         default:
177             break;
178     }
179
180     /* Init I/O method */
181     if (cap.capabilities & V4L2_CAP_STREAMING)
182     {
183         sys->bufc = 4;
184         sys->bufv = StartMmap (VLC_OBJECT(access), fd, &sys->bufc);
185         if (sys->bufv == NULL)
186             return -1;
187         access->pf_block = AccessRead;
188     }
189     else if (cap.capabilities & V4L2_CAP_READWRITE)
190     {
191         sys->blocksize = fmt.fmt.pix.sizeimage;
192         sys->bufv = NULL;
193         access->pf_read = AccessReadStream;
194     }
195     else
196     {
197         msg_Err (access, "no supported I/O method");
198         return -1;
199     }
200     return 0;
201 }
202
203 void AccessClose( vlc_object_t *obj )
204 {
205     access_t *access = (access_t *)obj;
206     access_sys_t *sys = access->p_sys;
207
208     if (sys->bufv != NULL)
209         StopMmap (sys->fd, sys->bufv, sys->bufc);
210     ControlsDeinit( obj, sys->controls );
211     v4l2_close (sys->fd);
212     free( sys );
213 }
214
215 static block_t *AccessRead( access_t *access )
216 {
217     access_sys_t *sys = access->p_sys;
218
219     struct pollfd fd;
220     fd.fd = sys->fd;
221     fd.events = POLLIN|POLLPRI;
222     fd.revents = 0;
223
224     /* Wait for data */
225     /* FIXME: kill timeout */
226     if( poll( &fd, 1, 500 ) <= 0 )
227         return NULL;
228
229     block_t *block = GrabVideo (VLC_OBJECT(access), sys->fd, sys->bufv);
230     if( block != NULL )
231     {
232         block->i_pts = block->i_dts = mdate();
233         block->i_flags |= sys->block_flags;
234     }
235     return block;
236 }
237
238 static ssize_t AccessReadStream( access_t *access, uint8_t *buf, size_t len )
239 {
240     access_sys_t *sys = access->p_sys;
241     struct pollfd ufd;
242     int i_ret;
243
244     ufd.fd = sys->fd;
245     ufd.events = POLLIN;
246
247     if( access->info.b_eof )
248         return 0;
249
250     /* FIXME: kill timeout and vlc_object_alive() */
251     do
252     {
253         if( !vlc_object_alive(access) )
254             return 0;
255
256         ufd.revents = 0;
257     }
258     while( ( i_ret = poll( &ufd, 1, 500 ) ) == 0 );
259
260     if( i_ret < 0 )
261     {
262         if( errno != EINTR )
263             msg_Err( access, "poll error: %m" );
264         return -1;
265     }
266
267     i_ret = v4l2_read (sys->fd, buf, len);
268     if( i_ret == 0 )
269         access->info.b_eof = true;
270     else if( i_ret > 0 )
271         access->info.i_pos += i_ret;
272
273     return i_ret;
274 }
275
276 static int AccessControl( access_t *access, int query, va_list args )
277 {
278     switch( query )
279     {
280         /* */
281         case ACCESS_CAN_SEEK:
282         case ACCESS_CAN_FASTSEEK:
283         case ACCESS_CAN_PAUSE:
284         case ACCESS_CAN_CONTROL_PACE:
285             *va_arg( args, bool* ) = false;
286             break;
287
288         /* */
289         case ACCESS_GET_PTS_DELAY:
290             *va_arg(args,int64_t *) = INT64_C(1000)
291                 * var_InheritInteger( access, "live-caching" );
292             break;
293
294         /* */
295         case ACCESS_SET_PAUSE_STATE:
296             /* Nothing to do */
297             break;
298
299         case ACCESS_GET_TITLE_INFO:
300         case ACCESS_SET_TITLE:
301         case ACCESS_SET_SEEKPOINT:
302         case ACCESS_SET_PRIVATE_ID_STATE:
303         case ACCESS_GET_CONTENT_TYPE:
304         case ACCESS_GET_META:
305             return VLC_EGENERIC;
306
307         default:
308             msg_Warn( access, "Unimplemented query %d in control", query );
309             return VLC_EGENERIC;
310
311     }
312     return VLC_SUCCESS;
313 }