]> git.sesse.net Git - vlc/blob - modules/access/pvr/pvr.c
* include/modules_inner.h, include/modules.h: added a shortname field to the module...
[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_shortname( _("PVR") );
78     set_description( _("MPEG Encoding cards input (with ivtv drivers)") );
79     set_capability( "access", 0 );
80     add_shortcut( "pvr" );
81     set_callbacks( Open, Close );
82 vlc_module_end();
83
84 /*****************************************************************************
85  * Private access data
86  *****************************************************************************/
87 struct access_sys_t
88 {
89     /* file descriptor */
90     int i_fd;
91     
92     /* options */
93     int i_standard;
94     int i_width;
95     int i_height;
96     int i_frequency;
97     int i_framerate;
98     int i_bitrate;
99     int i_bitrate_peak;
100     int i_bitrate_mode;
101     int i_audio_bitmask;
102     int i_input;
103 };
104
105 /*****************************************************************************
106  * Open: open the device
107  *****************************************************************************/
108 static int Open( vlc_object_t * p_this )
109 {
110     input_thread_t * p_input = (input_thread_t*) p_this;
111     access_sys_t * p_sys;
112     char * psz_tofree, * psz_parser, * psz_device;
113     char psz_tmp[5];
114
115     struct v4l2_format vfmt;
116     struct v4l2_frequency vf;
117     struct ivtv_ioctl_codec codec;
118
119     //psz_device = calloc( strlen( "/dev/videox" ) + 1, 1 );
120
121     p_input->pf_read = Read;
122     p_input->stream.b_pace_control = 0;
123     p_input->stream.b_seekable = 0;
124     p_input->i_pts_delay = 1000000;
125
126     /* create private access data */
127     p_sys = calloc( sizeof( access_sys_t ), 1 );
128     p_input->p_access_data = p_sys;
129
130     /* defaults values */
131
132     psz_device = 0;
133     p_sys->i_standard = V4L2_STD_UNKNOWN;
134     p_sys->i_width = -1;
135     p_sys->i_height = -1;
136     p_sys->i_frequency = -1;
137     p_sys->i_framerate = -1;
138     p_sys->i_bitrate = -1;
139     p_sys->i_bitrate_peak = -1;
140     p_sys->i_bitrate_mode = -1;
141     p_sys->i_audio_bitmask = -1;
142     p_sys->i_input = -1;
143
144     /* parse command line options */
145     psz_tofree = strdup( p_input->psz_name );
146     psz_parser = psz_tofree;
147
148     if( *psz_parser )
149     {
150         for( ;; )
151         {
152             if ( !strncmp( psz_parser, "norm=", strlen( "norm=" ) ) )
153             {
154                 char *psz_parser_init;
155                 psz_parser += strlen( "norm=" );
156                 psz_parser_init = psz_parser;
157                 while ( *psz_parser != ':' && *psz_parser != ','
158                                                     && *psz_parser != '\0' )
159                 {
160                     psz_parser++;
161                 }
162
163                 if ( !strncmp( psz_parser_init, "secam" ,
164                                psz_parser - psz_parser_init ) )
165                 {
166                     p_sys->i_standard = V4L2_STD_SECAM;
167                 }
168                 else if ( !strncmp( psz_parser_init, "pal" ,
169                                     psz_parser - psz_parser_init ) )
170                 {
171                     p_sys->i_standard = V4L2_STD_PAL;
172                 }
173                 else if ( !strncmp( psz_parser_init, "ntsc" ,
174                                     psz_parser - psz_parser_init ) )
175                 {
176                     p_sys->i_standard = V4L2_STD_NTSC;
177                 }
178                 else
179                 {
180                     p_sys->i_standard = strtol( psz_parser_init ,
181                                                 &psz_parser, 0 );
182                 }
183             }
184             else if( !strncmp( psz_parser, "channel=",
185                                strlen( "channel=" ) ) )
186             {
187                 p_sys->i_input =
188                   strtol( psz_parser + strlen( "channel=" ),
189                             &psz_parser, 0 );
190             }
191             else if( !strncmp( psz_parser, "device=", strlen( "device=" ) ) )
192             {
193                 psz_device = calloc( strlen( "/dev/videox" ) + 1, 1 );
194                 sprintf( psz_device, "/dev/video%ld",
195                             strtol( psz_parser + strlen( "device=" ),
196                             &psz_parser, 0 ) );
197             }
198             else if( !strncmp( psz_parser, "frequency=",
199                                strlen( "frequency=" ) ) )
200             {
201                 p_sys->i_frequency =
202                   strtol( psz_parser + strlen( "frequency=" ),
203                             &psz_parser, 0 );
204             }
205             else if( !strncmp( psz_parser, "framerate=",
206                                strlen( "framerate=" ) ) )
207             {
208                 p_sys->i_framerate =
209                     strtol( psz_parser + strlen( "framerate=" ),
210                             &psz_parser, 0 );
211             }
212             else if( !strncmp( psz_parser, "width=",
213                                strlen( "width=" ) ) )
214             {
215                 p_sys->i_width =
216                     strtol( psz_parser + strlen( "width=" ),
217                             &psz_parser, 0 );
218             }
219             else if( !strncmp( psz_parser, "height=",
220                                strlen( "height=" ) ) )
221             {
222                 p_sys->i_height =
223                     strtol( psz_parser + strlen( "height=" ),
224                             &psz_parser, 0 );
225             }
226             else if( !strncmp( psz_parser, "audio=",
227                                strlen( "audio=" ) ) )
228             {
229                 p_sys->i_audio_bitmask =
230                     strtol( psz_parser + strlen( "audio=" ),
231                             &psz_parser, 0 );
232             }
233             else if( !strncmp( psz_parser, "bitrate=",
234                                strlen( "bitrate=" ) ) )
235             {
236                 p_sys->i_bitrate =
237                     strtol( psz_parser + strlen( "bitrate=" ),
238                             &psz_parser, 0 );
239             }
240             else if( !strncmp( psz_parser, "maxbitrate=",
241                                strlen( "maxbitrate=" ) ) )
242             {
243                 p_sys->i_bitrate_peak =
244                     strtol( psz_parser + strlen( "maxbitrate=" ),
245                             &psz_parser, 0 );
246             }
247             else if( !strncmp( psz_parser, "bitratemode=",
248                                strlen( "bitratemode=" ) ) )
249             {
250                 char *psz_parser_init;
251                 psz_parser += strlen( "bitratemode=" );
252                 psz_parser_init = psz_parser;
253                 while ( *psz_parser != ':' && *psz_parser != ','
254                          && *psz_parser != '\0' )
255                 {
256                     psz_parser++;
257                 }
258
259                 if ( !strncmp( psz_parser_init, "vbr" ,
260                                psz_parser - psz_parser_init ) )
261                 {
262                      p_sys->i_bitrate_mode = 0;
263                 }
264                 else if ( !strncmp( psz_parser_init, "cbr" ,
265                                     psz_parser - psz_parser_init ) )
266                 {
267                     p_sys->i_bitrate_mode = 1;
268                 }
269             }
270             else if( !strncmp( psz_parser, "size=",
271                                strlen( "size=" ) ) )
272             {
273                 p_sys->i_width =
274                     strtol( psz_parser + strlen( "size=" ),
275                             &psz_parser, 0 );
276                 p_sys->i_height =
277                     strtol( psz_parser + 1 ,
278                             &psz_parser, 0 );
279             }
280             else
281             {
282                 char *psz_parser_init;
283                 psz_parser_init = psz_parser;
284                 while ( *psz_parser != ':' && *psz_parser != ',' && *psz_parser != '\0' )
285                 {
286                     psz_parser++;
287                 }
288                 psz_device = calloc( psz_parser - psz_parser_init + 1, 1 );
289                 strncpy( psz_device, psz_parser_init,
290                          psz_parser - psz_parser_init );
291             }
292             if( *psz_parser )
293                 psz_parser++;
294             else
295                 break;
296         }
297     }
298
299     //give a default value to psz_device if none has bee specified
300
301     if (!psz_device)
302     {
303         psz_device = calloc( strlen( "/dev/videox" ) + 1, 1 );
304         strcpy( psz_device, "/dev/video0" );
305     }
306
307     free( psz_tofree );
308
309     /* open the device */
310     if( ( p_sys->i_fd = open( psz_device, O_RDWR ) ) < 0 )
311     {
312         msg_Err( p_input, "cannot open device (%s)", strerror( errno ) );
313         return VLC_EGENERIC;
314     }
315     else
316     {
317         msg_Dbg( p_input, "using video device: %s",psz_device);
318     }
319
320     free( psz_device );
321
322     /* set the input */
323     if ( p_sys->i_input != -1 )
324     {
325         if ( ioctl( p_sys->i_fd, VIDIOC_S_INPUT, &p_sys->i_input ) < 0 )
326         {
327             msg_Warn( p_input, "VIDIOC_S_INPUT failed" );
328         }
329         else
330         {
331             msg_Dbg( p_input, "input set to:%d", p_sys->i_input);
332         }
333     }
334
335     /* set the video standard */
336     if ( p_sys->i_standard != V4L2_STD_UNKNOWN )
337     {
338         if ( ioctl( p_sys->i_fd, VIDIOC_S_STD, &p_sys->i_standard ) < 0 )
339         {
340             msg_Warn( p_input, "VIDIOC_S_STD failed" );
341         }
342         else
343         {
344             msg_Dbg( p_input, "video standard set to:%x", p_sys->i_standard);
345         }
346     }
347
348     /* set the picture size */
349     if ( p_sys->i_width != -1 || p_sys->i_height != -1 )
350     {
351         if ( ioctl( p_sys->i_fd, VIDIOC_G_FMT, &vfmt ) < 0 )
352         {
353             msg_Warn( p_input, "VIDIOC_G_FMT failed" );
354         }
355         else
356         {
357             if ( p_sys->i_width != -1 )
358             {
359                 vfmt.fmt.pix.width = p_sys->i_width;
360             }
361
362             if ( p_sys->i_height != -1 )
363             {
364                 vfmt.fmt.pix.height = p_sys->i_height;
365             }
366
367             if ( ioctl( p_sys->i_fd, VIDIOC_S_FMT, &vfmt ) < 0 )
368             {
369                 msg_Warn( p_input, "VIDIOC_S_FMT failed" );
370             }
371             else
372             {
373                 msg_Dbg( p_input, "picture size set to:%dx%d",
374                          vfmt.fmt.pix.width, vfmt.fmt.pix.height );
375             }
376         }
377     }
378
379     /* set the frequency */
380     if ( p_sys->i_frequency != -1 )
381     {
382         vf.tuner = 0; /* TODO: let the user choose the tuner */
383         if ( ioctl( p_sys->i_fd, VIDIOC_G_FREQUENCY, &vf ) < 0 )
384         {
385             msg_Warn( p_input, "VIDIOC_G_FREQUENCY failed (%s)",
386                       strerror( errno ) );
387         }
388         else
389         {
390             vf.frequency = p_sys->i_frequency * 16 / 1000;
391             if( ioctl( p_sys->i_fd, VIDIOC_S_FREQUENCY, &vf ) < 0 )
392             {
393                 msg_Warn( p_input, "VIDIOC_S_FREQUENCY failed (%s)",
394                           strerror( errno ) );
395             }
396             else
397             {
398                 msg_Dbg( p_input, "Tuner frequency set to:%d",
399                          p_sys->i_frequency);
400             }
401         }
402     }
403
404     /* codec parameters */
405     if ( p_sys->i_framerate != -1
406             || p_sys->i_bitrate_mode != -1
407             || p_sys->i_bitrate_peak != -1
408             || p_sys->i_bitrate != -1
409             || p_sys->i_audio_bitmask != -1 )
410     {
411         if ( ioctl( p_sys->i_fd, IVTV_IOC_G_CODEC, &codec ) < 0 )
412         {
413             msg_Warn( p_input, "IVTV_IOC_G_CODEC failed" );
414         }
415         else
416         {
417             if ( p_sys->i_framerate != -1 )
418             {
419                 switch ( p_sys->i_framerate )
420                 {
421                     case 30:
422                         codec.framerate = 0;
423                         break;
424
425                     case 25:
426                         codec.framerate = 1;
427                         break;
428
429                     default:
430                         msg_Warn( p_input, "invalid framerate, reverting to 25" );
431                         codec.framerate = 1;
432                         break;
433                 }
434             }
435
436             if ( p_sys->i_bitrate != -1 )
437             {
438                 codec.bitrate = p_sys->i_bitrate;
439             }
440
441             if ( p_sys->i_bitrate_peak != -1 )
442             {
443                 codec.bitrate_peak = p_sys->i_bitrate_peak;
444             }
445
446             if ( p_sys->i_bitrate_mode != -1 )
447             {
448                 codec.bitrate_mode = p_sys->i_bitrate_mode;
449             }
450
451             if ( p_sys->i_audio_bitmask != -1 )
452             {
453                 codec.audio_bitmask = p_sys->i_audio_bitmask;
454             }
455
456             if( ioctl( p_sys->i_fd, IVTV_IOC_S_CODEC, &codec ) < 0 )
457             {
458                 msg_Warn( p_input, "IVTV_IOC_S_CODEC failed" );
459             }
460             else
461             {
462                 msg_Dbg( p_input, "Setting codec parameters to:  framerate: %d, bitrate: %d/%d/%d",
463                codec.framerate, codec.bitrate, codec.bitrate_peak, codec.bitrate_mode );
464             }
465         }
466     }
467
468     /* do a quick read */
469 #if 0
470     if ( p_sys->i_fd )
471     {
472         if ( read( p_sys->i_fd, psz_tmp, 1 ) )
473         {
474             msg_Dbg(p_input, "Could read byte from device");
475         }
476         else
477         {
478             msg_Warn(p_input, "Could not read byte from device");
479         }
480     }
481 #endif
482     return VLC_SUCCESS;
483 }
484
485 /*****************************************************************************
486  * Close: close the device
487  *****************************************************************************/
488 static void Close( vlc_object_t * p_this )
489 {
490     input_thread_t * p_input = (input_thread_t*) p_this;
491     access_sys_t * p_sys = p_input->p_access_data;
492
493     close( p_sys->i_fd );
494     free( p_sys );
495 }
496
497 /*****************************************************************************
498  * Read
499  *****************************************************************************/
500 static ssize_t Read( input_thread_t * p_input, byte_t * p_buffer,
501                      size_t i_len )
502 {
503     access_sys_t * p_sys = p_input->p_access_data;
504
505     int i_ret;
506     
507     struct timeval timeout;
508     fd_set fds;
509
510     FD_ZERO( &fds );
511     FD_SET( p_sys->i_fd, &fds );
512     timeout.tv_sec = 0;
513     timeout.tv_usec = 500000;
514
515     while( !( i_ret = select( p_sys->i_fd + 1, &fds,
516                               NULL, NULL, &timeout ) ) )
517     {
518         FD_ZERO( &fds );
519         FD_SET( p_sys->i_fd, &fds );
520         timeout.tv_sec = 0;
521         timeout.tv_usec = 500000;
522
523         if( p_input->b_die || p_input->b_error )
524             return 0;
525     }
526
527     if( i_ret < 0 )
528     {
529         msg_Err( p_input, "select error (%s)", strerror( errno ) );
530         return -1;
531     }
532
533     i_ret = read( p_sys->i_fd, p_buffer, i_len );
534     return i_ret;
535 }
536