]> git.sesse.net Git - vlc/blob - modules/access/pvr/pvr.c
- Updated French translation (still a lot of work to do...)
[vlc] / modules / access / pvr / pvr.c
1 /*****************************************************************************
2  * pvr.c
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: pvr.c,v 1.10 2003/11/23 18:31:54 alexis Exp $
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( _("input for encoding cards supported by the 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_input;
101 };
102
103 /*****************************************************************************
104  * Open: open the device
105  *****************************************************************************/
106 static int Open( vlc_object_t * p_this )
107 {
108     input_thread_t * p_input = (input_thread_t*) p_this;
109     access_sys_t * p_sys;
110     char * psz_tofree, * psz_parser, * psz_device;
111
112     struct v4l2_format vfmt;
113     struct v4l2_frequency vf;
114     struct ivtv_ioctl_codec codec;
115     
116     //psz_device = calloc( strlen( "/dev/videox" ) + 1, 1 );    
117     
118     p_input->pf_read = Read;
119     p_input->stream.b_pace_control = 0;
120     p_input->stream.b_seekable = 0;
121     p_input->i_pts_delay = 1000000;
122
123     /* create private access data */
124     p_sys = calloc( sizeof( access_sys_t ), 1 );
125     p_input->p_access_data = p_sys;
126
127     /* defaults values */
128
129     psz_device = 0;
130     p_sys->i_standard = V4L2_STD_SECAM;
131     p_sys->i_width = 720;
132     p_sys->i_height = 576;
133     p_sys->i_frequency = 567250; /* M6 ;) */
134     p_sys->i_framerate = 25;
135     p_sys->i_bitrate = 3000000;
136     p_sys->i_bitrate_peak = 4000000;
137     p_sys->i_input = 4;
138
139     /* parse command line options */
140     psz_tofree = strdup( p_input->psz_name );
141     psz_parser = psz_tofree;
142
143     if( *psz_parser )
144     {
145         for( ;; )
146         {
147             if ( !strncmp( psz_parser, "norm=", strlen( "norm=" ) ) )
148             {
149                 char *psz_parser_init;
150                 psz_parser += strlen( "norm=" );
151                 psz_parser_init = psz_parser;
152                 while ( *psz_parser != ':' && *psz_parser != ',' 
153                                                     && *psz_parser != '\0' )
154                 {
155                     psz_parser++;
156                 }
157                 
158                 if (!strncmp( psz_parser_init, "secam" , 
159                                                 psz_parser - psz_parser_init ) )
160                     {
161                     p_sys->i_standard = V4L2_STD_SECAM;
162                     }
163                 else if (!strncmp( psz_parser_init, "pal" , 
164                                                 psz_parser - psz_parser_init ) )
165                     {
166                     p_sys->i_standard = V4L2_STD_PAL;
167                     }
168                 else if (!strncmp( psz_parser_init, "ntsc" , 
169                                                 psz_parser - psz_parser_init ) )
170                     {
171                     p_sys->i_standard = V4L2_STD_NTSC;
172                     }
173                 else 
174                     {p_sys->i_standard = strtol( psz_parser_init ,
175                                           &psz_parser, 0 );}
176
177             }
178             else if( !strncmp( psz_parser, "channel=",
179                                strlen( "channel=" ) ) )
180             {
181                 p_sys->i_input =
182                   strtol( psz_parser + strlen( "channel=" ),
183                             &psz_parser, 0 );
184             }
185             else if( !strncmp( psz_parser, "device=", strlen( "device=" ) ) )
186             {
187                 psz_device = calloc( strlen( "/dev/videox" ) + 1, 1 );
188                 sprintf( psz_device, "/dev/video%ld", 
189                             strtol( psz_parser + strlen( "device=" ), 
190                             &psz_parser, 0 ) );
191             }
192             else if( !strncmp( psz_parser, "frequency=",
193                                strlen( "frequency=" ) ) )
194             {
195                 p_sys->i_frequency =
196                   strtol( psz_parser + strlen( "frequency=" ),
197                             &psz_parser, 0 );
198             }
199             else if( !strncmp( psz_parser, "framerate=",
200                                strlen( "framerate=" ) ) )
201             {
202                 p_sys->i_framerate =
203                     strtol( psz_parser + strlen( "framerate=" ),
204                             &psz_parser, 0 );
205             }
206             else if( !strncmp( psz_parser, "width=",
207                                strlen( "width=" ) ) )
208             {
209                 p_sys->i_width =
210                     strtol( psz_parser + strlen( "width=" ),
211                             &psz_parser, 0 );
212             }
213             else if( !strncmp( psz_parser, "height=",
214                                strlen( "height=" ) ) )
215             {
216                 p_sys->i_height =
217                     strtol( psz_parser + strlen( "height=" ),
218                             &psz_parser, 0 );
219             }
220             else if( !strncmp( psz_parser, "bitrate=",
221                                strlen( "bitrate=" ) ) )
222             {
223                 p_sys->i_bitrate =
224                     strtol( psz_parser + strlen( "bitrate=" ),
225                             &psz_parser, 0 );
226             }
227             else if( !strncmp( psz_parser, "maxbitrate=",
228                                strlen( "maxbitrate=" ) ) )
229             {
230                 p_sys->i_bitrate_peak =
231                     strtol( psz_parser + strlen( "maxbitrate=" ),
232                             &psz_parser, 0 );
233             }
234             else if( !strncmp( psz_parser, "bitratemode=",
235                                strlen( "bitratemode=" ) ) )
236             {
237                 char *psz_parser_init;
238                 psz_parser += strlen( "bitratemode=" );
239                 psz_parser_init = psz_parser;
240                 while ( *psz_parser != ':' && *psz_parser != ','
241                                                     && *psz_parser != '\0' )
242                 {
243                     psz_parser++;
244                 }
245
246                 if (!strncmp( psz_parser_init, "vbr" ,
247                                                 psz_parser - psz_parser_init ) )
248                     {
249                     p_sys->i_bitrate_mode = 0;
250                     }
251                 else if  (!strncmp( psz_parser_init, "cbr" ,
252                                                 psz_parser - psz_parser_init ) )
253                     {
254                     p_sys->i_bitrate_mode = 1;
255                     }
256             }
257
258             else if( !strncmp( psz_parser, "size=",
259                                strlen( "size=" ) ) )
260             {
261                 p_sys->i_width =
262                     strtol( psz_parser + strlen( "size=" ),
263                             &psz_parser, 0 );
264                 p_sys->i_height =
265                     strtol( psz_parser + 1 ,
266                             &psz_parser, 0 );
267
268             }
269             else 
270             {
271                 char *psz_parser_init;
272                 psz_parser_init = psz_parser;
273                 while ( *psz_parser != ':' && *psz_parser != ',' 
274                                                     && *psz_parser != '\0' )
275                 {
276                     psz_parser++;
277                 }
278                 psz_device = calloc( psz_parser - psz_parser_init + 1, 1 );
279                 strncpy( psz_device, psz_parser_init, 
280                                     psz_parser - psz_parser_init );
281             }
282             if( *psz_parser )
283                 psz_parser++;
284             else
285                 break;
286         }
287     }
288
289     //give a default value to psz_device if none has bee specified
290
291     if (!psz_device)
292     {
293         psz_device = calloc( strlen( "/dev/videox" ) + 1, 1 );
294         strcpy( psz_device, "/dev/video0" );
295     }
296
297     free( psz_tofree );
298
299     msg_Dbg( p_input, "device: %s, input: %d, standard: %x, size: %dx%d, "
300              "frequency: %d, framerate: %d, bitrate: %d/%d/%d",
301              psz_device, p_sys->i_input, p_sys->i_standard, p_sys->i_width,
302              p_sys->i_height, p_sys->i_frequency, p_sys->i_framerate,
303              p_sys->i_bitrate, p_sys->i_bitrate_peak,p_sys->i_bitrate_mode );
304
305     /* open the device */
306     if( ( p_sys->i_fd = open( psz_device, O_RDWR ) ) < 0 )
307     {
308         msg_Err( p_input, "cannot open device (%s)", strerror( errno ) );
309         return VLC_EGENERIC;
310     }
311     free( psz_device );
312
313     /* set the input */
314     if( ioctl( p_sys->i_fd, VIDIOC_S_INPUT, &p_sys->i_input ) < 0 )
315     {
316         msg_Warn( p_input, "VIDIOC_S_INPUT failed" );
317     }
318
319
320     /* set the video standard */
321     if( ioctl( p_sys->i_fd, VIDIOC_S_STD, &p_sys->i_standard ) < 0 )
322     {
323         msg_Warn( p_input, "VIDIOC_S_STD failed" );
324     }
325
326     /* set the picture size */
327     if( ioctl( p_sys->i_fd, VIDIOC_G_FMT, &vfmt ) < 0 )
328     {
329         msg_Warn( p_input, "VIDIOC_G_FMT failed" );
330     }
331     else
332     {
333         vfmt.fmt.pix.width = p_sys->i_width;
334         vfmt.fmt.pix.height = p_sys->i_height;
335         if( ioctl( p_sys->i_fd, VIDIOC_S_FMT, &vfmt ) < 0 )
336         {
337             msg_Warn( p_input, "VIDIOC_S_FMT failed" );
338         }
339     }
340
341     /* set the frequency */
342     vf.tuner = 0; /* TODO: let the user choose the tuner */
343     if( ioctl( p_sys->i_fd, VIDIOC_G_FREQUENCY, &vf ) < 0 )
344     {
345         msg_Warn( p_input, "VIDIOC_G_FREQUENCY failed (%s)",
346                   strerror( errno ) );
347     }
348     else
349     {
350         vf.frequency = p_sys->i_frequency * 16 / 1000;
351         if( ioctl( p_sys->i_fd, VIDIOC_S_FREQUENCY, &vf ) < 0 )
352         {
353             msg_Warn( p_input, "VIDIOC_S_FREQUENCY failed (%s)",
354                       strerror( errno ) );
355         }
356     }
357
358     /* codec parameters */
359     if( ioctl( p_sys->i_fd, IVTV_IOC_G_CODEC, &codec ) < 0 )
360     {
361         msg_Warn( p_input, "IVTV_IOC_G_CODEC failed" );
362     }
363     else
364     {
365         switch( p_sys->i_framerate )
366         {
367             case 30:
368                 codec.framerate = 0;
369                 break;
370
371             case 25:
372                 codec.framerate = 1;
373                 break;
374             
375             default:
376                 msg_Warn( p_input, "invalid framerate, reverting to 25" );
377                 codec.framerate = 1;
378                 break;
379         }
380         codec.bitrate = p_sys->i_bitrate;
381         codec.bitrate_peak = p_sys->i_bitrate_peak;
382         codec.bitrate_mode = p_sys->i_bitrate_mode;
383         if( ioctl( p_sys->i_fd, IVTV_IOC_S_CODEC, &codec ) < 0 )
384         {
385             msg_Warn( p_input, "IVTV_IOC_S_CODEC failed" );
386         }
387     }
388
389     return VLC_SUCCESS;
390 }
391
392 /*****************************************************************************
393  * Close: close the device
394  *****************************************************************************/
395 static void Close( vlc_object_t * p_this )
396 {
397     input_thread_t * p_input = (input_thread_t*) p_this;
398     access_sys_t * p_sys = p_input->p_access_data;
399
400     close( p_sys->i_fd );
401     free( p_sys );
402 }
403
404 /*****************************************************************************
405  * Read
406  *****************************************************************************/
407 static ssize_t Read( input_thread_t * p_input, byte_t * p_buffer,
408                      size_t i_len )
409 {
410     access_sys_t * p_sys = p_input->p_access_data;
411
412     int i_ret;
413     
414     struct timeval timeout;
415     fd_set fds;
416
417     FD_ZERO( &fds );
418     FD_SET( p_sys->i_fd, &fds );
419     timeout.tv_sec = 0;
420     timeout.tv_usec = 500000;
421
422     while( !( i_ret = select( p_sys->i_fd + 1, &fds,
423                               NULL, NULL, &timeout ) ) )
424     {
425         FD_ZERO( &fds );
426         FD_SET( p_sys->i_fd, &fds );
427         timeout.tv_sec = 0;
428         timeout.tv_usec = 500000;
429
430         if( p_input->b_die || p_input->b_error )
431             return 0;
432     }
433
434     if( i_ret < 0 )
435     {
436         msg_Err( p_input, "select error (%s)", strerror( errno ) );
437         return -1;
438     }
439
440     i_ret = read( p_sys->i_fd, p_buffer, i_len );
441     return i_ret;
442 }
443