]> git.sesse.net Git - vlc/blob - modules/access/pvr/pvr.c
68be85b62bf20182c3f154183fdfebb50156dbda
[vlc] / modules / access / pvr / pvr.c
1 /*****************************************************************************
2  * pvr.c
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: pvr.c,v 1.5 2003/07/22 20:25:07 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                 {
149                     psz_parser++;
150                 }
151                 
152                 if (!strncmp( psz_parser_init, "secam" , 
153                                                 psz_parser - psz_parser_init ) )
154                     {
155                     p_sys->i_standard = V4L2_STD_SECAM;
156                     }
157                 else if (!strncmp( psz_parser_init, "pal" , 
158                                                 psz_parser - psz_parser_init ) )
159                     {
160                     p_sys->i_standard = V4L2_STD_PAL;
161                     }
162                 else if (!strncmp( psz_parser_init, "ntsc" , 
163                                                 psz_parser - psz_parser_init ) )
164                     {
165                     p_sys->i_standard = V4L2_STD_NTSC;
166                     }
167                 else 
168                     {p_sys->i_standard = strtol( psz_parser_init ,
169                                           &psz_parser, 0 );}
170
171             }
172             else if( !strncmp( psz_parser, "device=", strlen( "device=" ) ) )
173             {
174                 psz_device = calloc( strlen( "/dev/videox" ) + 1, 1 );
175                 sprintf( psz_device, "/dev/video%ld", 
176                             strtol( psz_parser + strlen( "device=" ), 
177                             &psz_parser, 0 ) );
178             }
179             else if( !strncmp( psz_parser, "frequency=",
180                                strlen( "frequency=" ) ) )
181             {
182                 p_sys->i_frequency =
183                     1000 * strtol( psz_parser + strlen( "frequency=" ),
184                             &psz_parser, 0 ) / 16;
185             }
186             else if( !strncmp( psz_parser, "framerate=",
187                                strlen( "framerate=" ) ) )
188             {
189                 p_sys->i_framerate =
190                     strtol( psz_parser + strlen( "framerate=" ),
191                             &psz_parser, 0 );
192             }
193             else if( !strncmp( psz_parser, "width=",
194                                strlen( "width=" ) ) )
195             {
196                 p_sys->i_width =
197                     strtol( psz_parser + strlen( "width=" ),
198                             &psz_parser, 0 );
199             }
200             else if( !strncmp( psz_parser, "height=",
201                                strlen( "height=" ) ) )
202             {
203                 p_sys->i_height =
204                     strtol( psz_parser + strlen( "height=" ),
205                             &psz_parser, 0 );
206             }
207             else if( !strncmp( psz_parser, "bitrate=",
208                                strlen( "bitrate=" ) ) )
209             {
210                 p_sys->i_bitrate =
211                     strtol( psz_parser + strlen( "bitrate=" ),
212                             &psz_parser, 0 );
213             }
214             else if( !strncmp( psz_parser, "maxbitrate=",
215                                strlen( "maxbitrate=" ) ) )
216             {
217                 p_sys->i_bitrate_peak =
218                     strtol( psz_parser + strlen( "maxbitrate=" ),
219                             &psz_parser, 0 );
220             }
221             else if( !strncmp( psz_parser, "size=",
222                                strlen( "size=" ) ) )
223             {
224                 p_sys->i_width =
225                     strtol( psz_parser + strlen( "size=" ),
226                             &psz_parser, 0 );
227                 p_sys->i_height =
228                     strtol( psz_parser + 1 ,
229                             &psz_parser, 0 );
230
231             }
232             else 
233             {
234                 char *psz_parser_init;
235                 psz_parser_init = psz_parser;
236                 while ( *psz_parser != ':' && *psz_parser != ',' )
237                 {
238                     psz_parser++;
239                 }
240                 psz_device = calloc( psz_parser - psz_parser_init + 1, 1 );
241                 strncpy( psz_device, psz_parser_init, 
242                                     psz_parser - psz_parser_init );
243             }
244             if( *psz_parser )
245                 psz_parser++;
246             else
247                 break;
248         }
249     }
250
251     //give a default value to psz_device if none has bee specified
252
253     if (!psz_device)
254     {
255         psz_device = calloc( strlen( "/dev/videox" ) + 1, 1 );
256         strcpy( psz_device, "/dev/video0" );
257     }
258
259     free( psz_tofree );
260
261     msg_Dbg( p_input, "device: %s, standard: %x, size: %dx%d, "
262              "frequency: %d, framerate: %d, bitrate: %d/%d",
263              psz_device, p_sys->i_standard, p_sys->i_width,
264              p_sys->i_height, p_sys->i_frequency, p_sys->i_framerate,
265              p_sys->i_bitrate, p_sys->i_bitrate_peak );
266
267     /* open the device */
268     if( ( p_sys->i_fd = open( psz_device, O_RDWR ) ) < 0 )
269     {
270         msg_Err( p_input, "cannot open device (%s)", strerror( errno ) );
271         return VLC_EGENERIC;
272     }
273     free( psz_device );
274
275     /* set the video standard */
276     if( ioctl( p_sys->i_fd, VIDIOC_S_STD, &p_sys->i_standard ) < 0 )
277     {
278         msg_Warn( p_input, "VIDIOC_S_STD failed" );
279     }
280
281     /* set the picture size */
282     if( ioctl( p_sys->i_fd, VIDIOC_G_FMT, &vfmt ) < 0 )
283     {
284         msg_Warn( p_input, "VIDIOC_G_FMT failed" );
285     }
286     else
287     {
288         vfmt.fmt.pix.width = p_sys->i_width;
289         vfmt.fmt.pix.height = p_sys->i_height;
290         if( ioctl( p_sys->i_fd, VIDIOC_S_FMT, &vfmt ) < 0 )
291         {
292             msg_Warn( p_input, "VIDIOC_S_FMT failed" );
293         }
294     }
295
296     /* set the frequency */
297     vf.tuner = 0; /* TODO: let the user choose the tuner */
298     if( ioctl( p_sys->i_fd, VIDIOC_G_FREQUENCY, &vf ) < 0 )
299     {
300         msg_Warn( p_input, "VIDIOC_G_FREQUENCY failed (%s)",
301                   strerror( errno ) );
302     }
303     else
304     {
305         vf.frequency = p_sys->i_frequency * 16 / 1000;
306         if( ioctl( p_sys->i_fd, VIDIOC_S_FREQUENCY, &vf ) < 0 )
307         {
308             msg_Warn( p_input, "VIDIOC_S_FREQUENCY failed (%s)",
309                       strerror( errno ) );
310         }
311     }
312
313     /* codec parameters */
314     if( ioctl( p_sys->i_fd, IVTV_IOC_G_CODEC, &codec ) < 0 )
315     {
316         msg_Warn( p_input, "IVTV_IOC_G_CODEC failed" );
317     }
318     else
319     {
320         switch( p_sys->i_framerate )
321         {
322             case 30:
323                 codec.framerate = 0;
324                 break;
325
326             case 25:
327                 codec.framerate = 1;
328                 break;
329             
330             default:
331                 msg_Warn( p_input, "invalid framerate, reverting to 25" );
332                 codec.framerate = 1;
333                 break;
334         }
335         codec.bitrate = p_sys->i_bitrate;
336         codec.bitrate_peak = p_sys->i_bitrate_peak;
337         if( ioctl( p_sys->i_fd, IVTV_IOC_S_CODEC, &codec ) < 0 )
338         {
339             msg_Warn( p_input, "IVTV_IOC_S_CODEC failed" );
340         }
341     }
342
343     return VLC_SUCCESS;
344 }
345
346 /*****************************************************************************
347  * Close: close the device
348  *****************************************************************************/
349 static void Close( vlc_object_t * p_this )
350 {
351     input_thread_t * p_input = (input_thread_t*) p_this;
352     access_sys_t * p_sys = p_input->p_access_data;
353
354     close( p_sys->i_fd );
355     free( p_sys );
356 }
357
358 /*****************************************************************************
359  * Read
360  *****************************************************************************/
361 static ssize_t Read( input_thread_t * p_input, byte_t * p_buffer,
362                      size_t i_len )
363 {
364     access_sys_t * p_sys = p_input->p_access_data;
365
366     int i_ret;
367     
368     struct timeval timeout;
369     fd_set fds;
370
371     FD_ZERO( &fds );
372     FD_SET( p_sys->i_fd, &fds );
373     timeout.tv_sec = 0;
374     timeout.tv_usec = 500000;
375
376     while( !( i_ret = select( p_sys->i_fd + 1, &fds,
377                               NULL, NULL, &timeout ) ) )
378     {
379         FD_ZERO( &fds );
380         FD_SET( p_sys->i_fd, &fds );
381         timeout.tv_sec = 0;
382         timeout.tv_usec = 500000;
383
384         if( p_input->b_die || p_input->b_error )
385             return 0;
386     }
387
388     if( i_ret < 0 )
389     {
390         msg_Err( p_input, "select error (%s)", strerror( errno ) );
391         return -1;
392     }
393
394     i_ret = read( p_sys->i_fd, p_buffer, i_len );
395     return i_ret;
396 }
397