]> git.sesse.net Git - vlc/blob - modules/access/pvr/pvr.c
cc065d02ae2945f888cfdfc26360a10febecaea0
[vlc] / modules / access / pvr / pvr.c
1 /*****************************************************************************
2  * pvr.c
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id$
6  *
7  * Authors: Eric Petit <titer@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <vlc/vlc.h>
28 #include <vlc/input.h>
29
30 #include <stdlib.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <linux/types.h>
37 #include <sys/ioctl.h>
38 #include "videodev2.h"
39
40 /* ivtv specific ioctls */
41 #define IVTV_IOC_G_CODEC    0xFFEE7703
42 #define IVTV_IOC_S_CODEC    0xFFEE7704
43
44
45 /* for use with IVTV_IOC_G_CODEC and IVTV_IOC_S_CODEC */
46
47 struct ivtv_ioctl_codec {
48         uint32_t aspect;
49         uint32_t audio_bitmask;
50         uint32_t bframes;
51         uint32_t bitrate_mode;
52         uint32_t bitrate;
53         uint32_t bitrate_peak;
54         uint32_t dnr_mode;
55         uint32_t dnr_spatial;
56         uint32_t dnr_temporal;
57         uint32_t dnr_type;
58         uint32_t framerate;
59         uint32_t framespergop;
60         uint32_t gop_closure;
61         uint32_t pulldown;
62         uint32_t stream_type;
63 };
64
65 /*****************************************************************************
66  * Prototypes
67  *****************************************************************************/
68 static int     Open   ( vlc_object_t * );
69 static void    Close  ( vlc_object_t * );
70
71 static ssize_t Read   ( input_thread_t *, byte_t *, size_t );
72
73 /*****************************************************************************
74  * Module descriptor
75  *****************************************************************************/
76 vlc_module_begin();
77     set_description( _("MPEG Encoding cards input (with ivtv drivers)") );
78     set_capability( "access", 0 );
79     add_shortcut( "pvr" );
80     set_callbacks( Open, Close );
81 vlc_module_end();
82
83 /*****************************************************************************
84  * Private access data
85  *****************************************************************************/
86 struct access_sys_t
87 {
88     /* file descriptor */
89     int i_fd;
90     
91     /* options */
92     int i_standard;
93     int i_width;
94     int i_height;
95     int i_frequency;
96     int i_framerate;
97     int i_bitrate;
98     int i_bitrate_peak;
99     int i_bitrate_mode;
100     int i_audio_bitmask;
101     int i_input;
102 };
103
104 /*****************************************************************************
105  * Open: open the device
106  *****************************************************************************/
107 static int Open( vlc_object_t * p_this )
108 {
109     input_thread_t * p_input = (input_thread_t*) p_this;
110     access_sys_t * p_sys;
111     char * psz_tofree, * psz_parser, * psz_device;
112     char psz_tmp[5];
113
114     struct v4l2_format vfmt;
115     struct v4l2_frequency vf;
116     struct ivtv_ioctl_codec codec;
117
118     //psz_device = calloc( strlen( "/dev/videox" ) + 1, 1 );
119
120     p_input->pf_read = Read;
121     p_input->stream.b_pace_control = 0;
122     p_input->stream.b_seekable = 0;
123     p_input->i_pts_delay = 1000000;
124
125     /* create private access data */
126     p_sys = calloc( sizeof( access_sys_t ), 1 );
127     p_input->p_access_data = p_sys;
128
129     /* defaults values */
130
131     psz_device = 0;
132     p_sys->i_standard = V4L2_STD_UNKNOWN;
133     p_sys->i_width = -1;
134     p_sys->i_height = -1;
135     p_sys->i_frequency = -1;
136     p_sys->i_framerate = -1;
137     p_sys->i_bitrate = -1;
138     p_sys->i_bitrate_peak = -1;
139     p_sys->i_bitrate_mode = -1;
140     p_sys->i_audio_bitmask = -1;
141     p_sys->i_input = -1;
142
143     /* parse command line options */
144     psz_tofree = strdup( p_input->psz_name );
145     psz_parser = psz_tofree;
146
147     if( *psz_parser )
148     {
149         for( ;; )
150         {
151             if ( !strncmp( psz_parser, "norm=", strlen( "norm=" ) ) )
152             {
153                 char *psz_parser_init;
154                 psz_parser += strlen( "norm=" );
155                 psz_parser_init = psz_parser;
156                 while ( *psz_parser != ':' && *psz_parser != ','
157                                                     && *psz_parser != '\0' )
158                 {
159                     psz_parser++;
160                 }
161
162                 if ( !strncmp( psz_parser_init, "secam" ,
163                                psz_parser - psz_parser_init ) )
164                 {
165                     p_sys->i_standard = V4L2_STD_SECAM;
166                 }
167                 else if ( !strncmp( psz_parser_init, "pal" ,
168                                     psz_parser - psz_parser_init ) )
169                 {
170                     p_sys->i_standard = V4L2_STD_PAL;
171                 }
172                 else if ( !strncmp( psz_parser_init, "ntsc" ,
173                                     psz_parser - psz_parser_init ) )
174                 {
175                     p_sys->i_standard = V4L2_STD_NTSC;
176                 }
177                 else
178                 {
179                     p_sys->i_standard = strtol( psz_parser_init ,
180                                                 &psz_parser, 0 );
181                 }
182             }
183             else if( !strncmp( psz_parser, "channel=",
184                                strlen( "channel=" ) ) )
185             {
186                 p_sys->i_input =
187                   strtol( psz_parser + strlen( "channel=" ),
188                             &psz_parser, 0 );
189             }
190             else if( !strncmp( psz_parser, "device=", strlen( "device=" ) ) )
191             {
192                 psz_device = calloc( strlen( "/dev/videox" ) + 1, 1 );
193                 sprintf( psz_device, "/dev/video%ld",
194                             strtol( psz_parser + strlen( "device=" ),
195                             &psz_parser, 0 ) );
196             }
197             else if( !strncmp( psz_parser, "frequency=",
198                                strlen( "frequency=" ) ) )
199             {
200                 p_sys->i_frequency =
201                   strtol( psz_parser + strlen( "frequency=" ),
202                             &psz_parser, 0 );
203             }
204             else if( !strncmp( psz_parser, "framerate=",
205                                strlen( "framerate=" ) ) )
206             {
207                 p_sys->i_framerate =
208                     strtol( psz_parser + strlen( "framerate=" ),
209                             &psz_parser, 0 );
210             }
211             else if( !strncmp( psz_parser, "width=",
212                                strlen( "width=" ) ) )
213             {
214                 p_sys->i_width =
215                     strtol( psz_parser + strlen( "width=" ),
216                             &psz_parser, 0 );
217             }
218             else if( !strncmp( psz_parser, "height=",
219                                strlen( "height=" ) ) )
220             {
221                 p_sys->i_height =
222                     strtol( psz_parser + strlen( "height=" ),
223                             &psz_parser, 0 );
224             }
225             else if( !strncmp( psz_parser, "audio=",
226                                strlen( "audio=" ) ) )
227             {
228                 p_sys->i_audio_bitmask =
229                     strtol( psz_parser + strlen( "audio=" ),
230                             &psz_parser, 0 );
231             }
232             else if( !strncmp( psz_parser, "bitrate=",
233                                strlen( "bitrate=" ) ) )
234             {
235                 p_sys->i_bitrate =
236                     strtol( psz_parser + strlen( "bitrate=" ),
237                             &psz_parser, 0 );
238             }
239             else if( !strncmp( psz_parser, "maxbitrate=",
240                                strlen( "maxbitrate=" ) ) )
241             {
242                 p_sys->i_bitrate_peak =
243                     strtol( psz_parser + strlen( "maxbitrate=" ),
244                             &psz_parser, 0 );
245             }
246             else if( !strncmp( psz_parser, "bitratemode=",
247                                strlen( "bitratemode=" ) ) )
248             {
249                 char *psz_parser_init;
250                 psz_parser += strlen( "bitratemode=" );
251                 psz_parser_init = psz_parser;
252                 while ( *psz_parser != ':' && *psz_parser != ','
253                          && *psz_parser != '\0' )
254                 {
255                     psz_parser++;
256                 }
257
258                 if ( !strncmp( psz_parser_init, "vbr" ,
259                                psz_parser - psz_parser_init ) )
260                 {
261                      p_sys->i_bitrate_mode = 0;
262                 }
263                 else if ( !strncmp( psz_parser_init, "cbr" ,
264                                     psz_parser - psz_parser_init ) )
265                 {
266                     p_sys->i_bitrate_mode = 1;
267                 }
268             }
269             else if( !strncmp( psz_parser, "size=",
270                                strlen( "size=" ) ) )
271             {
272                 p_sys->i_width =
273                     strtol( psz_parser + strlen( "size=" ),
274                             &psz_parser, 0 );
275                 p_sys->i_height =
276                     strtol( psz_parser + 1 ,
277                             &psz_parser, 0 );
278             }
279             else
280             {
281                 char *psz_parser_init;
282                 psz_parser_init = psz_parser;
283                 while ( *psz_parser != ':' && *psz_parser != ',' && *psz_parser != '\0' )
284                 {
285                     psz_parser++;
286                 }
287                 psz_device = calloc( psz_parser - psz_parser_init + 1, 1 );
288                 strncpy( psz_device, psz_parser_init,
289                          psz_parser - psz_parser_init );
290             }
291             if( *psz_parser )
292                 psz_parser++;
293             else
294                 break;
295         }
296     }
297
298     //give a default value to psz_device if none has bee specified
299
300     if (!psz_device)
301     {
302         psz_device = calloc( strlen( "/dev/videox" ) + 1, 1 );
303         strcpy( psz_device, "/dev/video0" );
304     }
305
306     free( psz_tofree );
307
308     /* open the device */
309     if( ( p_sys->i_fd = open( psz_device, O_RDWR ) ) < 0 )
310     {
311         msg_Err( p_input, "cannot open device (%s)", strerror( errno ) );
312         return VLC_EGENERIC;
313     }
314     else
315     {
316         msg_Dbg( p_input, "using video device: %s",psz_device);
317     }
318
319     free( psz_device );
320
321     /* set the input */
322     if ( p_sys->i_input != -1 )
323     {
324         if ( ioctl( p_sys->i_fd, VIDIOC_S_INPUT, &p_sys->i_input ) < 0 )
325         {
326             msg_Warn( p_input, "VIDIOC_S_INPUT failed" );
327         }
328         else
329         {
330             msg_Dbg( p_input, "input set to:%d", p_sys->i_input);
331         }
332     }
333
334     /* set the video standard */
335     if ( p_sys->i_standard != V4L2_STD_UNKNOWN )
336     {
337         if ( ioctl( p_sys->i_fd, VIDIOC_S_STD, &p_sys->i_standard ) < 0 )
338         {
339             msg_Warn( p_input, "VIDIOC_S_STD failed" );
340         }
341         else
342         {
343             msg_Dbg( p_input, "video standard set to:%x", p_sys->i_standard);
344         }
345     }
346
347     /* set the picture size */
348     if ( p_sys->i_width != -1 || p_sys->i_height != -1 )
349     {
350         if ( ioctl( p_sys->i_fd, VIDIOC_G_FMT, &vfmt ) < 0 )
351         {
352             msg_Warn( p_input, "VIDIOC_G_FMT failed" );
353         }
354         else
355         {
356             if ( p_sys->i_width != -1 )
357             {
358                 vfmt.fmt.pix.width = p_sys->i_width;
359             }
360
361             if ( p_sys->i_height != -1 )
362             {
363                 vfmt.fmt.pix.height = p_sys->i_height;
364             }
365
366             if ( ioctl( p_sys->i_fd, VIDIOC_S_FMT, &vfmt ) < 0 )
367             {
368                 msg_Warn( p_input, "VIDIOC_S_FMT failed" );
369             }
370             else
371             {
372                 msg_Dbg( p_input, "picture size set to:%dx%d",
373                          vfmt.fmt.pix.width, vfmt.fmt.pix.height );
374             }
375         }
376     }
377
378     /* set the frequency */
379     if ( p_sys->i_frequency != -1 )
380     {
381         vf.tuner = 0; /* TODO: let the user choose the tuner */
382         if ( ioctl( p_sys->i_fd, VIDIOC_G_FREQUENCY, &vf ) < 0 )
383         {
384             msg_Warn( p_input, "VIDIOC_G_FREQUENCY failed (%s)",
385                       strerror( errno ) );
386         }
387         else
388         {
389             vf.frequency = p_sys->i_frequency * 16 / 1000;
390             if( ioctl( p_sys->i_fd, VIDIOC_S_FREQUENCY, &vf ) < 0 )
391             {
392                 msg_Warn( p_input, "VIDIOC_S_FREQUENCY failed (%s)",
393                           strerror( errno ) );
394             }
395             else
396             {
397                 msg_Dbg( p_input, "Tuner frequency set to:%d",
398                          p_sys->i_frequency);
399             }
400         }
401     }
402
403     /* codec parameters */
404     if ( p_sys->i_framerate != -1
405             || p_sys->i_bitrate_mode != -1
406             || p_sys->i_bitrate_peak != -1
407             || p_sys->i_bitrate != -1
408             || p_sys->i_audio_bitmask != -1 )
409     {
410         if ( ioctl( p_sys->i_fd, IVTV_IOC_G_CODEC, &codec ) < 0 )
411         {
412             msg_Warn( p_input, "IVTV_IOC_G_CODEC failed" );
413         }
414         else
415         {
416             if ( p_sys->i_framerate != -1 )
417             {
418                 switch ( p_sys->i_framerate )
419                 {
420                     case 30:
421                         codec.framerate = 0;
422                         break;
423
424                     case 25:
425                         codec.framerate = 1;
426                         break;
427
428                     default:
429                         msg_Warn( p_input, "invalid framerate, reverting to 25" );
430                         codec.framerate = 1;
431                         break;
432                 }
433             }
434
435             if ( p_sys->i_bitrate != -1 )
436             {
437                 codec.bitrate = p_sys->i_bitrate;
438             }
439
440             if ( p_sys->i_bitrate_peak != -1 )
441             {
442                 codec.bitrate_peak = p_sys->i_bitrate_peak;
443             }
444
445             if ( p_sys->i_bitrate_mode != -1 )
446             {
447                 codec.bitrate_mode = p_sys->i_bitrate_mode;
448             }
449
450             if ( p_sys->i_audio_bitmask != -1 )
451             {
452                 codec.audio_bitmask = p_sys->i_audio_bitmask;
453             }
454
455             if( ioctl( p_sys->i_fd, IVTV_IOC_S_CODEC, &codec ) < 0 )
456             {
457                 msg_Warn( p_input, "IVTV_IOC_S_CODEC failed" );
458             }
459             else
460             {
461                 msg_Dbg( p_input, "Setting codec parameters to:  framerate: %d, bitrate: %d/%d/%d",
462                codec.framerate, codec.bitrate, codec.bitrate_peak, codec.bitrate_mode );
463             }
464         }
465     }
466
467     /* do a quick read */
468 #if 0
469     if ( p_sys->i_fd )
470     {
471         if ( read( p_sys->i_fd, psz_tmp, 1 ) )
472         {
473             msg_Dbg(p_input, "Could read byte from device");
474         }
475         else
476         {
477             msg_Warn(p_input, "Could not read byte from device");
478         }
479     }
480 #endif
481     return VLC_SUCCESS;
482 }
483
484 /*****************************************************************************
485  * Close: close the device
486  *****************************************************************************/
487 static void Close( vlc_object_t * p_this )
488 {
489     input_thread_t * p_input = (input_thread_t*) p_this;
490     access_sys_t * p_sys = p_input->p_access_data;
491
492     close( p_sys->i_fd );
493     free( p_sys );
494 }
495
496 /*****************************************************************************
497  * Read
498  *****************************************************************************/
499 static ssize_t Read( input_thread_t * p_input, byte_t * p_buffer,
500                      size_t i_len )
501 {
502     access_sys_t * p_sys = p_input->p_access_data;
503
504     int i_ret;
505     
506     struct timeval timeout;
507     fd_set fds;
508
509     FD_ZERO( &fds );
510     FD_SET( p_sys->i_fd, &fds );
511     timeout.tv_sec = 0;
512     timeout.tv_usec = 500000;
513
514     while( !( i_ret = select( p_sys->i_fd + 1, &fds,
515                               NULL, NULL, &timeout ) ) )
516     {
517         FD_ZERO( &fds );
518         FD_SET( p_sys->i_fd, &fds );
519         timeout.tv_sec = 0;
520         timeout.tv_usec = 500000;
521
522         if( p_input->b_die || p_input->b_error )
523             return 0;
524     }
525
526     if( i_ret < 0 )
527     {
528         msg_Err( p_input, "select error (%s)", strerror( errno ) );
529         return -1;
530     }
531
532     i_ret = read( p_sys->i_fd, p_buffer, i_len );
533     return i_ret;
534 }
535