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