]> git.sesse.net Git - vlc/blob - modules/access/v4l2/demux.c
v4l2: inline OpenVideo()
[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 "v4l2.h"
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <sys/ioctl.h>
34 #include <sys/mman.h>
35 #include <poll.h>
36
37 #include <vlc_demux.h>
38 #include <vlc_fs.h>
39
40 static int DemuxControl( demux_t *, int, va_list );
41 static int Demux( demux_t * );
42
43 int DemuxOpen( vlc_object_t *obj )
44 {
45     demux_t *demux = (demux_t *)obj;
46
47     demux_sys_t *sys = calloc( 1, sizeof( demux_sys_t ) );
48     if( unlikely(sys == NULL) )
49         return VLC_ENOMEM;
50     demux->p_sys = sys;
51
52     ParseMRL( obj, demux->psz_location );
53
54     char *path = var_InheritString (obj, CFG_PREFIX"dev");
55     if (unlikely(path == NULL))
56         goto error; /* probably OOM */
57     msg_Dbg (obj, "opening device '%s'", path);
58
59     int rawfd = vlc_open (path, O_RDWR);
60     if (rawfd == -1)
61     {
62         msg_Err (obj, "cannot open device '%s': %m", path);
63         free (path);
64         goto error;
65     }
66     free (path);
67
68     int fd = v4l2_fd_open (rawfd, 0);
69     if (fd == -1)
70     {
71         msg_Warn (obj, "cannot initialize user-space library: %m");
72         /* fallback to direct kernel mode anyway */
73         fd = rawfd;
74     }
75
76     if (InitVideo (obj, fd, sys, true))
77     {
78         v4l2_close (fd);
79         goto error;
80     }
81
82     sys->i_fd = fd;
83     demux->pf_demux = Demux;
84     demux->pf_control = DemuxControl;
85     demux->info.i_update = 0;
86     demux->info.i_title = 0;
87     demux->info.i_seekpoint = 0;
88     return VLC_SUCCESS;
89 error:
90     free (sys);
91     return VLC_EGENERIC;
92 }
93
94 void DemuxClose( vlc_object_t *obj )
95 {
96     demux_t *demux = (demux_t *)obj;
97     demux_sys_t *sys = demux->p_sys;
98     int fd = sys->i_fd;
99
100     /* Stop video capture */
101     switch( sys->io )
102     {
103         case IO_METHOD_READ:
104             /* Nothing to do */
105             break;
106
107         case IO_METHOD_MMAP:
108         case IO_METHOD_USERPTR:
109         {
110             /* NOTE: Some buggy drivers hang if buffers are not unmapped before
111              * streamoff */
112             for( unsigned i = 0; i < sys->i_nbuffers; i++ )
113             {
114                 struct v4l2_buffer buf = {
115                     .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
116                     .memory = ( sys->io == IO_METHOD_USERPTR ) ?
117                     V4L2_MEMORY_USERPTR : V4L2_MEMORY_MMAP,
118                 };
119                 v4l2_ioctl( fd, VIDIOC_DQBUF, &buf );
120             }
121             enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
122             v4l2_ioctl( sys->i_fd, VIDIOC_STREAMOFF, &buf_type );
123             break;
124         }
125     }
126
127     /* Free Video Buffers */
128     if( sys->p_buffers ) {
129         switch( sys->io )
130         {
131         case IO_METHOD_READ:
132             free( sys->p_buffers[0].start );
133             break;
134
135         case IO_METHOD_MMAP:
136             for( unsigned i = 0; i < sys->i_nbuffers; ++i )
137                 v4l2_munmap( sys->p_buffers[i].start,
138                              sys->p_buffers[i].length );
139             break;
140
141         case IO_METHOD_USERPTR:
142             for( unsigned i = 0; i < sys->i_nbuffers; ++i )
143                free( sys->p_buffers[i].start );
144             break;
145         }
146         free( sys->p_buffers );
147     }
148
149     ControlsDeinit( obj, sys->controls );
150     v4l2_close( fd );
151     free( sys );
152 }
153
154 static int DemuxControl( demux_t *demux, int query, va_list args )
155 {
156     switch( query )
157     {
158         /* Special for access_demux */
159         case DEMUX_CAN_PAUSE:
160         case DEMUX_CAN_SEEK:
161         case DEMUX_CAN_CONTROL_PACE:
162             *va_arg( args, bool * ) = false;
163             return VLC_SUCCESS;
164
165         case DEMUX_GET_PTS_DELAY:
166             *va_arg(args,int64_t *) = INT64_C(1000)
167                 * var_InheritInteger( demux, "live-caching" );
168             return VLC_SUCCESS;
169
170         case DEMUX_GET_TIME:
171             *va_arg( args, int64_t * ) = mdate();
172             return VLC_SUCCESS;
173
174         /* TODO implement others */
175         default:
176             return VLC_EGENERIC;
177     }
178
179     return VLC_EGENERIC;
180 }
181
182 /** Gets a frame in read/write mode */
183 static block_t *BlockRead( vlc_object_t *obj, int fd, size_t size )
184 {
185     block_t *block = block_Alloc( size );
186     if( unlikely(block == NULL) )
187         return NULL;
188
189     ssize_t val = v4l2_read( fd, block->p_buffer, size );
190     if( val == -1 )
191     {
192         block_Release( block );
193         switch( errno )
194         {
195             case EAGAIN:
196                 return NULL;
197             case EIO: /* could be ignored per specification */
198                 /* fall through */
199             default:
200                 msg_Err( obj, "cannot read frame: %m" );
201                 return NULL;
202         }
203     }
204     block->i_buffer = val;
205     return block;
206 }
207
208 static int Demux( demux_t *demux )
209 {
210     demux_sys_t *sys = demux->p_sys;
211     struct pollfd ufd;
212
213     ufd.fd = sys->i_fd;
214     ufd.events = POLLIN|POLLPRI;
215     /* Wait for data */
216     /* FIXME: remove timeout */
217     while( poll( &ufd, 1, 500 ) == -1 )
218         if( errno != EINTR )
219         {
220             msg_Err( demux, "poll error: %m" );
221             return -1;
222         }
223
224     if( ufd.revents == 0 )
225         return 1;
226
227     block_t *block;
228
229     if( sys->io == IO_METHOD_READ )
230         block = BlockRead( VLC_OBJECT(demux), ufd.fd, sys->blocksize );
231     else
232         block = GrabVideo( VLC_OBJECT(demux), sys );
233     if( block == NULL )
234         return 1;
235
236     block->i_pts = block->i_dts = mdate();
237     block->i_flags |= sys->i_block_flags;
238     es_out_Control( demux->out, ES_OUT_SET_PCR, block->i_pts );
239     es_out_Send( demux->out, sys->p_es, block );
240     return 1;
241 }
242
243 static float GetMaxFPS( vlc_object_t *obj, int fd, uint32_t pixel_format,
244                         uint32_t width, uint32_t height )
245 {
246 #ifdef VIDIOC_ENUM_FRAMEINTERVALS
247     /* This is new in Linux 2.6.19 */
248     struct v4l2_frmivalenum fie = {
249         .pixel_format = pixel_format,
250         .width = width,
251         .height = height,
252     };
253
254     if( v4l2_ioctl( fd, VIDIOC_ENUM_FRAMEINTERVALS, &fie ) < 0 )
255         return -1.;
256
257     switch( fie.type )
258     {
259         case V4L2_FRMIVAL_TYPE_DISCRETE:
260         {
261             float max = -1.;
262             do
263             {
264                 float fps = (float)fie.discrete.denominator
265                           / (float)fie.discrete.numerator;
266                 if( fps > max )
267                     max = fps;
268                 msg_Dbg( obj, "  discrete frame interval %"PRIu32"/%"PRIu32
269                          " supported",
270                          fie.discrete.numerator, fie.discrete.denominator );
271                 fie.index++;
272             } while( v4l2_ioctl( fd, VIDIOC_ENUM_FRAMEINTERVALS, &fie ) >= 0 );
273             return max;
274         }
275
276         case V4L2_FRMIVAL_TYPE_STEPWISE:
277         case V4L2_FRMIVAL_TYPE_CONTINUOUS:
278             msg_Dbg( obj, "  frame intervals from %"PRIu32"/%"PRIu32
279                     "to %"PRIu32"/%"PRIu32" supported",
280                     fie.stepwise.min.numerator, fie.stepwise.min.denominator,
281                     fie.stepwise.max.numerator, fie.stepwise.max.denominator );
282             if( fie.type == V4L2_FRMIVAL_TYPE_STEPWISE )
283                 msg_Dbg( obj, "  with %"PRIu32"/%"PRIu32" step",
284                          fie.stepwise.step.numerator,
285                          fie.stepwise.step.denominator );
286             return __MAX( (float)fie.stepwise.max.denominator
287                         / (float)fie.stepwise.max.numerator,
288                           (float)fie.stepwise.min.denominator
289                         / (float)fie.stepwise.min.numerator );
290     }
291 #endif
292     return -1.;
293 }
294
295 float GetAbsoluteMaxFrameRate( vlc_object_t *obj, int fd,
296                                uint32_t pixel_format )
297 {
298 #ifdef VIDIOC_ENUM_FRAMESIZES
299     /* This is new in Linux 2.6.19 */
300     struct v4l2_frmsizeenum fse = {
301         .pixel_format = pixel_format
302     };
303
304     if( v4l2_ioctl( fd, VIDIOC_ENUM_FRAMESIZES, &fse ) < 0 )
305         return -1.;
306
307     float max = -1.;
308     switch( fse.type )
309     {
310       case V4L2_FRMSIZE_TYPE_DISCRETE:
311         do
312         {
313             float fps = GetMaxFPS( obj, fd, pixel_format,
314                                    fse.discrete.width, fse.discrete.height );
315             if( fps > max )
316                 max = fps;
317             fse.index++;
318         } while( v4l2_ioctl( fd, VIDIOC_ENUM_FRAMESIZES, &fse ) >= 0 );
319         break;
320
321       case V4L2_FRMSIZE_TYPE_STEPWISE:
322       case V4L2_FRMSIZE_TYPE_CONTINUOUS:
323         msg_Dbg( obj, " sizes from %"PRIu32"x%"PRIu32" "
324                  "to %"PRIu32"x%"PRIu32" supported",
325                  fse.stepwise.min_width, fse.stepwise.min_height,
326                  fse.stepwise.max_width, fse.stepwise.max_height );
327         if( fse.type == V4L2_FRMSIZE_TYPE_STEPWISE )
328             msg_Dbg( obj, "  with %"PRIu32"x%"PRIu32" steps",
329                      fse.stepwise.step_width, fse.stepwise.step_height );
330
331         for( uint32_t width =  fse.stepwise.min_width;
332                       width <= fse.stepwise.max_width;
333                       width += fse.stepwise.step_width )
334             for( uint32_t height =  fse.stepwise.min_height;
335                           height <= fse.stepwise.max_width;
336                           height += fse.stepwise.step_height )
337             {
338                 float fps = GetMaxFPS( obj, fd, pixel_format, width, height );
339                 if( fps > max )
340                     max = fps;
341             }
342         break;
343     }
344     return max;
345 #else
346     return -1.;
347 #endif
348 }
349
350 void GetMaxDimensions( vlc_object_t *obj, int fd, uint32_t pixel_format,
351                        float fps_min, uint32_t *pwidth, uint32_t *pheight )
352 {
353     *pwidth = 0;
354     *pheight = 0;
355
356 #ifdef VIDIOC_ENUM_FRAMESIZES
357     /* This is new in Linux 2.6.19 */
358     struct v4l2_frmsizeenum fse = {
359         .pixel_format = pixel_format
360     };
361
362     if( v4l2_ioctl( fd, VIDIOC_ENUM_FRAMESIZES, &fse ) < 0 )
363         return;
364
365     switch( fse.type )
366     {
367       case V4L2_FRMSIZE_TYPE_DISCRETE:
368         do
369         {
370             msg_Dbg( obj, " discrete size %"PRIu32"x%"PRIu32" supported",
371                      fse.discrete.width, fse.discrete.height );
372
373             float fps = GetMaxFPS( obj, fd, pixel_format,
374                                    fse.discrete.width, fse.discrete.height );
375             if( fps >= fps_min && fse.discrete.width > *pwidth )
376             {
377                 *pwidth = fse.discrete.width;
378                 *pheight = fse.discrete.height;
379             }
380             fse.index++;
381         }
382         while( v4l2_ioctl( fd, VIDIOC_ENUM_FRAMESIZES, &fse ) >= 0 );
383         break;
384
385       case V4L2_FRMSIZE_TYPE_STEPWISE:
386       case V4L2_FRMSIZE_TYPE_CONTINUOUS:
387         msg_Dbg( obj, " sizes from %"PRIu32"x%"PRIu32" "
388                  "to %"PRIu32"x%"PRIu32" supported",
389                  fse.stepwise.min_width, fse.stepwise.min_height,
390                  fse.stepwise.max_width, fse.stepwise.max_height );
391         if( fse.type == V4L2_FRMSIZE_TYPE_STEPWISE )
392             msg_Dbg( obj, "  with %"PRIu32"x%"PRIu32" steps",
393                      fse.stepwise.step_width, fse.stepwise.step_height );
394
395         for( uint32_t width =  fse.stepwise.min_width;
396                       width <= fse.stepwise.max_width;
397                       width += fse.stepwise.step_width )
398             for( uint32_t height = fse.stepwise.min_height;
399                           height <= fse.stepwise.max_width;
400                           height += fse.stepwise.step_height )
401             {
402                 float fps = GetMaxFPS( obj, fd, pixel_format, width, height );
403                 if( fps >= fps_min && width > *pwidth )
404                 {
405                     *pwidth = width;
406                     *pheight = height;
407                 }
408             }
409         break;
410     }
411 #endif
412 }