]> git.sesse.net Git - vlc/blob - modules/access/v4l2/access.c
Add NTSC EIA-608 caption rendering support via V4L2 VBI devices
[vlc] / modules / access / v4l2 / access.c
1 /*****************************************************************************
2  * access.c : V4L2 compressed byte stream input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2002-2011 VLC authors and VideoLAN
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 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.
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 <poll.h>
33
34 #include <vlc_common.h>
35 #include <vlc_access.h>
36
37 #include "v4l2.h"
38
39 struct access_sys_t
40 {
41     int fd;
42     uint32_t block_flags;
43     union
44     {
45         uint32_t bufc;
46         uint32_t blocksize;
47     };
48     struct buffer_t *bufv;
49     vlc_v4l2_ctrl_t *controls;
50 };
51
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);
56
57 int AccessOpen( vlc_object_t *obj )
58 {
59     access_t *access = (access_t *)obj;
60
61     access_InitFields( access );
62
63     access_sys_t *sys = calloc (1, sizeof (*sys));
64     if( unlikely(sys == NULL) )
65         return VLC_ENOMEM;
66     access->p_sys = sys;
67
68     ParseMRL( obj, access->psz_location );
69
70     char *path = var_InheritString (obj, CFG_PREFIX"dev");
71     if (unlikely(path == NULL))
72         goto error; /* probably OOM */
73
74     uint32_t caps;
75     int fd = OpenDevice (obj, path, &caps);
76     free (path);
77     if (fd == -1)
78         goto error;
79     sys->fd = fd;
80
81     if (InitVideo (access, fd, caps))
82     {
83         v4l2_close (fd);
84         goto error;
85     }
86
87     sys->controls = ControlsInit (VLC_OBJECT(access), fd);
88     access->pf_seek = NULL;
89     access->pf_control = AccessControl;
90     return VLC_SUCCESS;
91 error:
92     free (sys);
93     return VLC_EGENERIC;
94 }
95
96 int InitVideo (access_t *access, int fd, uint32_t caps)
97 {
98     access_sys_t *sys = access->p_sys;
99
100     if (!(caps & V4L2_CAP_VIDEO_CAPTURE))
101     {
102         msg_Err (access, "not a video capture device");
103         return -1;
104     }
105
106     v4l2_std_id std;
107     if (SetupInput (VLC_OBJECT(access), fd, &std))
108         return -1;
109
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 :-( */
113     uint32_t pixfmt = 0;
114     char *fmtstr = var_InheritString (access, CFG_PREFIX"chroma");
115     if (fmtstr != NULL && strlen (fmtstr) <= 4)
116     {
117         memcpy (&pixfmt, fmtstr, strlen (fmtstr));
118         free (fmtstr);
119     }
120     else
121     /* Use the default^Wprevious format if none specified */
122     {
123         struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
124         if (v4l2_ioctl (fd, VIDIOC_G_FMT, &fmt) < 0)
125         {
126             msg_Err (access, "cannot get default format: %m");
127             return -1;
128         }
129         pixfmt = fmt.fmt.pix.pixelformat;
130     }
131     msg_Dbg (access, "selected format %4.4s", (const char *)&pixfmt);
132
133     struct v4l2_format fmt;
134     struct v4l2_streamparm parm;
135     if (SetupFormat (access, fd, pixfmt, &fmt, &parm))
136         return -1;
137
138     msg_Dbg (access, "%"PRIu32" bytes for complete image", fmt.fmt.pix.sizeimage);
139     /* Check interlacing */
140     switch (fmt.fmt.pix.field)
141     {
142         case V4L2_FIELD_INTERLACED:
143             msg_Dbg (access, "Interlacing setting: interleaved");
144             /*if (NTSC)
145                 sys->block_flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
146             else*/
147                 sys->block_flags = BLOCK_FLAG_TOP_FIELD_FIRST;
148             break;
149         case V4L2_FIELD_INTERLACED_TB:
150             msg_Dbg (access, "Interlacing setting: interleaved top bottom" );
151             sys->block_flags = BLOCK_FLAG_TOP_FIELD_FIRST;
152             break;
153         case V4L2_FIELD_INTERLACED_BT:
154             msg_Dbg (access, "Interlacing setting: interleaved bottom top" );
155             sys->block_flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
156             break;
157         default:
158             break;
159     }
160
161     /* Init I/O method */
162     if (caps & V4L2_CAP_STREAMING)
163     {
164         sys->bufc = 4;
165         sys->bufv = StartMmap (VLC_OBJECT(access), fd, &sys->bufc);
166         if (sys->bufv == NULL)
167             return -1;
168         access->pf_block = MMapBlock;
169     }
170     else if (caps & V4L2_CAP_READWRITE)
171     {
172         sys->blocksize = fmt.fmt.pix.sizeimage;
173         sys->bufv = NULL;
174         access->pf_block = ReadBlock;
175     }
176     else
177     {
178         msg_Err (access, "no supported capture method");
179         return -1;
180     }
181
182     return 0;
183 }
184
185 void AccessClose( vlc_object_t *obj )
186 {
187     access_t *access = (access_t *)obj;
188     access_sys_t *sys = access->p_sys;
189
190     if (sys->bufv != NULL)
191         StopMmap (sys->fd, sys->bufv, sys->bufc);
192     ControlsDeinit( obj, sys->controls );
193     v4l2_close (sys->fd);
194     free( sys );
195 }
196
197 /* Wait for data */
198 static int AccessPoll (access_t *access)
199 {
200     access_sys_t *sys = access->p_sys;
201     struct pollfd ufd;
202
203     ufd.fd = sys->fd;
204     ufd.events = POLLIN;
205
206     switch (poll (&ufd, 1, 500))
207     {
208         case -1:
209             if (errno == EINTR)
210         case 0:
211             /* FIXME: kill this case (arbitrary timeout) */
212                 return -1;
213             msg_Err (access, "poll error: %m");
214             access->info.b_eof = true;
215             return -1;
216     }
217     return 0;
218 }
219
220
221 static block_t *MMapBlock (access_t *access)
222 {
223     access_sys_t *sys = access->p_sys;
224
225     if (AccessPoll (access))
226         return NULL;
227
228     block_t *block = GrabVideo (VLC_OBJECT(access), sys->fd, sys->bufv);
229     if( block != NULL )
230     {
231         block->i_pts = block->i_dts = mdate();
232         block->i_flags |= sys->block_flags;
233     }
234     return block;
235 }
236
237 static block_t *ReadBlock (access_t *access)
238 {
239     access_sys_t *sys = access->p_sys;
240
241     if (AccessPoll (access))
242         return NULL;
243
244     block_t *block = block_Alloc (sys->blocksize);
245     if (unlikely(block == NULL))
246         return NULL;
247
248     ssize_t val = v4l2_read (sys->fd, block->p_buffer, block->i_buffer);
249     if (val < 0)
250     {
251         block_Release (block);
252         msg_Err (access, "cannot read buffer: %m");
253         access->info.b_eof = true;
254         return NULL;
255     }
256
257     block->i_buffer = val;
258     access->info.i_pos += val;
259     return block;
260 }
261
262 static int AccessControl( access_t *access, int query, va_list args )
263 {
264     switch( query )
265     {
266         /* */
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;
272             break;
273
274         /* */
275         case ACCESS_GET_PTS_DELAY:
276             *va_arg(args,int64_t *) = INT64_C(1000)
277                 * var_InheritInteger( access, "live-caching" );
278             break;
279
280         /* */
281         case ACCESS_SET_PAUSE_STATE:
282             /* Nothing to do */
283             break;
284
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:
291             return VLC_EGENERIC;
292
293         default:
294             msg_Warn( access, "Unimplemented query %d in control", query );
295             return VLC_EGENERIC;
296
297     }
298     return VLC_SUCCESS;
299 }