* "frequency=" is channel frequency in kHz again
[vlc.git] / modules / access / pvr / pvr.c
1 /*****************************************************************************
2  * pvr.c
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: pvr.c,v 1.6 2003/07/24 18:30:03 bigben 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 struct ivtv_ioctl_codec {
47     uint32_t aspect;
48     uint32_t audio;
49     uint32_t bframes;
50     uint32_t bitrate;
51     uint32_t bitrate_peak;
52     uint32_t dnr_mode;
53     uint32_t dnr_spatial;
54     uint32_t dnr_temporal;
55     uint32_t dnr_type;
56     uint32_t framerate;
57     uint32_t framespergop;
58     uint32_t gop_closure;
59     uint32_t pulldown;
60     uint32_t stream_type;
61 };
62
63 /*****************************************************************************
64  * Prototypes
65  *****************************************************************************/
66 static int     Open   ( vlc_object_t * );
67 static void    Close  ( vlc_object_t * );
68
69 static ssize_t Read   ( input_thread_t *, byte_t *, size_t );
70
71 /*****************************************************************************
72  * Module descriptor
73  *****************************************************************************/
74 vlc_module_begin();
75     set_description( _("Hauppauge PVR cards input") );
76     set_capability( "access", 0 );
77     add_shortcut( "pvr" );
78     set_callbacks( Open, Close );
79 vlc_module_end();
80
81 /*****************************************************************************
82  * Private access data
83  *****************************************************************************/
84 struct access_sys_t
85 {
86     /* file descriptor */
87     int i_fd;
88     
89     /* options */
90     int i_standard;
91     int i_width;
92     int i_height;
93     int i_frequency;
94     int i_framerate;
95     int i_bitrate;
96     int i_bitrate_peak;
97 };
98
99 /*****************************************************************************
100  * Open: open the device
101  *****************************************************************************/
102 static int Open( vlc_object_t * p_this )
103 {
104     input_thread_t * p_input = (input_thread_t*) p_this;
105     access_sys_t * p_sys;
106     char * psz_tofree, * psz_parser, * psz_device;
107
108     struct v4l2_format vfmt;
109     struct v4l2_frequency vf;
110     struct ivtv_ioctl_codec codec;
111     
112     //psz_device = calloc( strlen( "/dev/videox" ) + 1, 1 );    
113     
114     p_input->pf_read = Read;
115     p_input->stream.b_pace_control = 0;
116     p_input->stream.b_seekable = 0;
117     p_input->i_pts_delay = 1000000;
118
119     /* create private access data */
120     p_sys = calloc( sizeof( access_sys_t ), 1 );
121     p_input->p_access_data = p_sys;
122
123     /* defaults values */
124
125     psz_device = 0;
126     p_sys->i_standard = V4L2_STD_SECAM;
127     p_sys->i_width = 720;
128     p_sys->i_height = 576;
129     p_sys->i_frequency = 567250; /* M6 ;) */
130     p_sys->i_framerate = 25;
131     p_sys->i_bitrate = 3000000;
132     p_sys->i_bitrate_peak = 4000000;
133
134     /* parse command line options */
135     psz_tofree = strdup( p_input->psz_name );
136     psz_parser = psz_tofree;
137
138     if( *psz_parser )
139     {
140         for( ;; )
141         {
142             if ( !strncmp( psz_parser, "norm=", strlen( "norm=" ) ) )
143             {
144                 char *psz_parser_init;
145                 psz_parser += strlen( "norm=" );
146                 psz_parser_init = psz_parser;
147                 while ( *psz_parser != ':' && *psz_parser != ',' 
148                                                     && *psz_parser != '\0' )
149                 {
150                     psz_parser++;
151                 }
152                 
153                 if (!strncmp( psz_parser_init, "secam" , 
154                                                 psz_parser - psz_parser_init ) )
155                     {
156                     p_sys->i_standard = V4L2_STD_SECAM;
157                     }
158                 else if (!strncmp( psz_parser_init, "pal" , 
159                                                 psz_parser - psz_parser_init ) )
160                     {
161                     p_sys->i_standard = V4L2_STD_PAL;
162                     }
163                 else if (!strncmp( psz_parser_init, "ntsc" , 
164                                                 psz_parser - psz_parser_init ) )
165                     {
166                     p_sys->i_standard = V4L2_STD_NTSC;
167                     }
168                 else 
169                     {p_sys->i_standard = strtol( psz_parser_init ,
170                                           &psz_parser, 0 );}
171
172             }
173             else if( !strncmp( psz_parser, "device=", strlen( "device=" ) ) )
174             {
175                 psz_device = calloc( strlen( "/dev/videox" ) + 1, 1 );
176                 sprintf( psz_device, "/dev/video%ld", 
177                             strtol( psz_parser + strlen( "device=" ), 
178                             &psz_parser, 0 ) );
179             }
180             else if( !strncmp( psz_parser, "frequency=",
181                                strlen( "frequency=" ) ) )
182             {
183                 p_sys->i_frequency =
184                   strtol( psz_parser + strlen( "frequency=" ),
185                             &psz_parser, 0 );
186             }
187             else if( !strncmp( psz_parser, "framerate=",
188                                strlen( "framerate=" ) ) )
189             {
190                 p_sys->i_framerate =
191                     strtol( psz_parser + strlen( "framerate=" ),
192                             &psz_parser, 0 );
193             }
194             else if( !strncmp( psz_parser, "width=",
195                                strlen( "width=" ) ) )
196             {
197                 p_sys->i_width =
198                     strtol( psz_parser + strlen( "width=" ),
199                             &psz_parser, 0 );
200             }
201             else if( !strncmp( psz_parser, "height=",
202                                strlen( "height=" ) ) )
203             {
204                 p_sys->i_height =
205                     strtol( psz_parser + strlen( "height=" ),
206                             &psz_parser, 0 );
207             }
208             else if( !strncmp( psz_parser, "bitrate=",
209                                strlen( "bitrate=" ) ) )
210             {
211                 p_sys->i_bitrate =
212                     strtol( psz_parser + strlen( "bitrate=" ),
213                             &psz_parser, 0 );
214             }
215             else if( !strncmp( psz_parser, "maxbitrate=",
216                                strlen( "maxbitrate=" ) ) )
217             {
218                 p_sys->i_bitrate_peak =
219                     strtol( psz_parser + strlen( "maxbitrate=" ),
220                             &psz_parser, 0 );
221             }
222             else if( !strncmp( psz_parser, "size=",
223                                strlen( "size=" ) ) )
224             {
225                 p_sys->i_width =
226                     strtol( psz_parser + strlen( "size=" ),
227                             &psz_parser, 0 );
228                 p_sys->i_height =
229                     strtol( psz_parser + 1 ,
230                             &psz_parser, 0 );
231
232             }
233             else 
234             {
235                 char *psz_parser_init;
236                 psz_parser_init = psz_parser;
237                 while ( *psz_parser != ':' && *psz_parser != ',' 
238                                                     && *psz_parser != '\0' )
239                 {
240                     psz_parser++;
241                 }
242                 psz_device = calloc( psz_parser - psz_parser_init + 1, 1 );
243                 strncpy( psz_device, psz_parser_init, 
244                                     psz_parser - psz_parser_init );
245             }
246             if( *psz_parser )
247                 psz_parser++;
248             else
249                 break;
250         }
251     }
252
253     //give a default value to psz_device if none has bee specified
254
255     if (!psz_device)
256     {
257         psz_device = calloc( strlen( "/dev/videox" ) + 1, 1 );
258         strcpy( psz_device, "/dev/video0" );
259     }
260
261     free( psz_tofree );
262
263     msg_Dbg( p_input, "device: %s, standard: %x, size: %dx%d, "
264              "frequency: %d, framerate: %d, bitrate: %d/%d",
265              psz_device, p_sys->i_standard, p_sys->i_width,
266              p_sys->i_height, p_sys->i_frequency, p_sys->i_framerate,
267              p_sys->i_bitrate, p_sys->i_bitrate_peak );
268
269     /* open the device */
270     if( ( p_sys->i_fd = open( psz_device, O_RDWR ) ) < 0 )
271     {
272         msg_Err( p_input, "cannot open device (%s)", strerror( errno ) );
273         return VLC_EGENERIC;
274     }
275     free( psz_device );
276
277     /* set the video standard */
278     if( ioctl( p_sys->i_fd, VIDIOC_S_STD, &p_sys->i_standard ) < 0 )
279     {
280         msg_Warn( p_input, "VIDIOC_S_STD failed" );
281     }
282
283     /* set the picture size */
284     if( ioctl( p_sys->i_fd, VIDIOC_G_FMT, &vfmt ) < 0 )
285     {
286         msg_Warn( p_input, "VIDIOC_G_FMT failed" );
287     }
288     else
289     {
290         vfmt.fmt.pix.width = p_sys->i_width;
291         vfmt.fmt.pix.height = p_sys->i_height;
292         if( ioctl( p_sys->i_fd, VIDIOC_S_FMT, &vfmt ) < 0 )
293         {
294             msg_Warn( p_input, "VIDIOC_S_FMT failed" );
295         }
296     }
297
298     /* set the frequency */
299     vf.tuner = 0; /* TODO: let the user choose the tuner */
300     if( ioctl( p_sys->i_fd, VIDIOC_G_FREQUENCY, &vf ) < 0 )
301     {
302         msg_Warn( p_input, "VIDIOC_G_FREQUENCY failed (%s)",
303                   strerror( errno ) );
304     }
305     else
306     {
307         vf.frequency = p_sys->i_frequency * 16 / 1000;
308         if( ioctl( p_sys->i_fd, VIDIOC_S_FREQUENCY, &vf ) < 0 )
309         {
310             msg_Warn( p_input, "VIDIOC_S_FREQUENCY failed (%s)",
311                       strerror( errno ) );
312         }
313     }
314
315     /* codec parameters */
316     if( ioctl( p_sys->i_fd, IVTV_IOC_G_CODEC, &codec ) < 0 )
317     {
318         msg_Warn( p_input, "IVTV_IOC_G_CODEC failed" );
319     }
320     else
321     {
322         switch( p_sys->i_framerate )
323         {
324             case 30:
325                 codec.framerate = 0;
326                 break;
327
328             case 25:
329                 codec.framerate = 1;
330                 break;
331             
332             default:
333                 msg_Warn( p_input, "invalid framerate, reverting to 25" );
334                 codec.framerate = 1;
335                 break;
336         }
337         codec.bitrate = p_sys->i_bitrate;
338         codec.bitrate_peak = p_sys->i_bitrate_peak;
339         if( ioctl( p_sys->i_fd, IVTV_IOC_S_CODEC, &codec ) < 0 )
340         {
341             msg_Warn( p_input, "IVTV_IOC_S_CODEC failed" );
342         }
343     }
344
345     return VLC_SUCCESS;
346 }
347
348 /*****************************************************************************
349  * Close: close the device
350  *****************************************************************************/
351 static void Close( vlc_object_t * p_this )
352 {
353     input_thread_t * p_input = (input_thread_t*) p_this;
354     access_sys_t * p_sys = p_input->p_access_data;
355
356     close( p_sys->i_fd );
357     free( p_sys );
358 }
359
360 /*****************************************************************************
361  * Read
362  *****************************************************************************/
363 static ssize_t Read( input_thread_t * p_input, byte_t * p_buffer,
364                      size_t i_len )
365 {
366     access_sys_t * p_sys = p_input->p_access_data;
367
368     int i_ret;
369     
370     struct timeval timeout;
371     fd_set fds;
372
373     FD_ZERO( &fds );
374     FD_SET( p_sys->i_fd, &fds );
375     timeout.tv_sec = 0;
376     timeout.tv_usec = 500000;
377
378     while( !( i_ret = select( p_sys->i_fd + 1, &fds,
379                               NULL, NULL, &timeout ) ) )
380     {
381         FD_ZERO( &fds );
382         FD_SET( p_sys->i_fd, &fds );
383         timeout.tv_sec = 0;
384         timeout.tv_usec = 500000;
385
386         if( p_input->b_die || p_input->b_error )
387             return 0;
388     }
389
390     if( i_ret < 0 )
391     {
392         msg_Err( p_input, "select error (%s)", strerror( errno ) );
393         return -1;
394     }
395
396     i_ret = read( p_sys->i_fd, p_buffer, i_len );
397     return i_ret;
398 }
399