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