]> git.sesse.net Git - vlc/blob - plugins/satellite/input_satellite.c
* Fixed a bug that made vlc segfault when choosing a program, change to
[vlc] / plugins / satellite / input_satellite.c
1 /*****************************************************************************
2  * input_satellite.c: Satellite card input
3  *****************************************************************************
4  * Copyright (C) 1998-2002 VideoLAN
5  *
6  * Authors: Johan Bilien <jobi@via.ecp.fr>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include <videolan/vlc.h>
31
32 #ifdef HAVE_UNISTD_H
33 #   include <unistd.h>
34 #endif
35
36 #include <fcntl.h>
37 #include <sys/types.h>
38 #include <string.h>
39 #include <errno.h>
40
41 #ifdef STRNCASECMP_IN_STRINGS_H
42 #   include <strings.h>
43 #endif
44
45 #include "stream_control.h"
46 #include "input_ext-intf.h"
47 #include "input_ext-dec.h"
48 #include "input_ext-plugins.h"
49
50 #include "debug.h"
51
52 #include "satellite_tools.h"
53
54 #define DISEQC 0                            /* Wether you should use Diseqc*/
55 #define FEC 2                                                      /* FEC */
56 #define LNB_LOF_1 9750000
57 #define LNB_LOF_2 10600000
58 #define LNB_SLOF 11700000
59
60 #define SATELLITE_READ_ONCE 3
61
62 /*****************************************************************************
63  * Local prototypes
64  *****************************************************************************/
65 static int  SatelliteOpen       ( input_thread_t * );
66 static void SatelliteClose      ( input_thread_t * );
67 static int  SatelliteSetArea    ( input_thread_t *, input_area_t * );
68 static int  SatelliteSetProgram ( input_thread_t *, pgrm_descriptor_t * );
69 static void SatelliteSeek       ( input_thread_t *, off_t );
70
71 static int  SatelliteInit       ( input_thread_t * );
72 static void SatelliteEnd        ( input_thread_t * );
73 static int  SatelliteDemux      ( input_thread_t * );
74 static int  SatelliteRewind     ( input_thread_t * );
75
76 /*****************************************************************************
77  * Functions exported as capabilities. They are declared as static so that
78  * we don't pollute the namespace too much.
79  *****************************************************************************/
80 void _M( access_getfunctions )( function_list_t * p_function_list )
81 {
82 #define access p_function_list->functions.access
83     access.pf_open             = SatelliteOpen;
84     access.pf_close            = SatelliteClose;
85     access.pf_read             = input_FDRead;
86     access.pf_set_area         = SatelliteSetArea;
87     access.pf_set_program      = SatelliteSetProgram;
88     access.pf_seek             = SatelliteSeek;
89 #undef access
90 }
91
92
93 void _M( demux_getfunctions )( function_list_t * p_function_list )
94 {
95 #define demux p_function_list->functions.demux
96     demux.pf_init             = SatelliteInit;
97     demux.pf_end              = SatelliteEnd;
98     demux.pf_demux            = SatelliteDemux;
99     demux.pf_rewind           = SatelliteRewind;
100 #undef demux
101 }
102
103
104
105
106 /*****************************************************************************
107  * SatelliteOpen : open the dvr device
108  *****************************************************************************/
109 static int SatelliteOpen( input_thread_t * p_input )
110 {
111     input_socket_t *   p_satellite;
112     char *                      psz_parser;
113     char *                      psz_next;
114     int                         i_fd = 0;
115     int                         i_freq = 0;
116     int                         i_srate = 0;
117     boolean_t                   b_pol = 0;
118
119     /* parse the options passed in command line : */
120
121     psz_parser = strdup( p_input->psz_name );
122
123     if( !psz_parser )
124     {
125         return( -1 );
126     }
127
128     i_freq = (int)strtol( psz_parser, &psz_next, 10 );
129
130     if ( *psz_next )
131     {
132         psz_parser = psz_next + 1;
133         b_pol = (boolean_t)strtol( psz_parser, &psz_next, 10 );
134             if ( *psz_next )
135             {
136                 psz_parser = psz_next + 1;
137                 i_srate = (boolean_t)strtol( psz_parser, &psz_next, 10 );
138             }
139
140     }
141
142     i_freq = i_freq ? i_freq : config_GetIntVariable( "sat_frequency" );
143     i_srate = i_srate ? i_srate : config_GetIntVariable( "sat_symbol_rate" );
144     if ( !b_pol && b_pol != 1 )
145         b_pol = config_GetIntVariable( "sat_polarization" );
146
147
148     /* Initialise structure */
149     p_satellite = malloc( sizeof( input_socket_t ) );
150
151     if( p_satellite == NULL )
152     {
153         intf_ErrMsg( "input: satellite: Out of memory" );
154         return -1;
155     }
156
157     p_input->p_access_data = (void *)p_satellite;
158
159     /* Open the DVR device */
160
161     intf_WarnMsg( 2, "input: opening file `%s'", DVR);
162
163     if( (p_satellite->i_handle = open( DVR,
164                                    /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
165     {
166         intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
167         return -1;
168     }
169
170
171     /* Initialize the Satellite Card */
172
173     intf_WarnMsg( 2, "Initializing Sat Card with Freq: %d, Pol: %d, Srate: %d",
174                         i_freq, b_pol, i_srate );
175
176     if ( ioctl_SECControl( i_freq * 1000, b_pol, LNB_SLOF, DISEQC ) < 0 )
177     {
178         intf_ErrMsg("input: satellite: An error occured when controling SEC");
179         return -1;
180     }
181
182     intf_WarnMsg( 3, "Initializing Frontend device" );
183     switch (ioctl_SetQPSKFrontend ( i_freq * 1000, i_srate* 1000, FEC,
184                          LNB_LOF_1, LNB_LOF_2, LNB_SLOF))
185     {
186         case -2:
187             intf_ErrMsg( "input: satellite: Frontend returned\
188                     an unexpected event" );
189             close( p_satellite->i_handle );
190             free( p_satellite );
191             return -1;
192             break;
193         case -3:
194             intf_ErrMsg( "input: satellite: Frontend returned\
195                     no event" );
196             close( p_satellite->i_handle );
197             free( p_satellite );
198             return -1;
199             break;
200         case -4:
201             intf_ErrMsg( "input: satellite: Frontend: time out\
202                     when polling for event" );
203             close( p_satellite->i_handle );
204             free( p_satellite );
205             return -1;
206             break;
207         case -5:
208              intf_ErrMsg( "input: satellite: An error occured when polling\
209                     Frontend device" );
210             close( p_satellite->i_handle );
211             free( p_satellite );
212             return -1;
213             break;
214         case -1:
215              intf_ErrMsg( "input: satellite: Frontend returned\
216                     an failure event" );
217             close( p_satellite->i_handle );
218             free( p_satellite );
219             return -1;
220             break;
221         default:
222             break;
223     }
224
225     intf_WarnMsg( 3, " Setting filter on PAT " );
226
227     if ( ioctl_SetDMXFilter( 0, &i_fd, 3 ) < 0 )
228     {
229         intf_ErrMsg( "input: satellite: An error occured when setting\
230                 filter on PAT" );
231         return -1;
232     }
233
234     if( input_InitStream( p_input, sizeof( stream_ts_data_t ) ) == -1 )
235     {
236         intf_ErrMsg( "input: satellite: Not enough memory to allow stream\
237                         structure" );
238         return( -1 );
239     }
240
241     vlc_mutex_lock( &p_input->stream.stream_lock );
242
243     p_input->stream.b_pace_control = 1;
244     p_input->stream.b_seekable = 0;
245     p_input->stream.p_selected_area->i_tell = 0;
246
247     vlc_mutex_unlock( &p_input->stream.stream_lock );
248
249     p_input->i_mtu = SATELLITE_READ_ONCE * TS_PACKET_SIZE;
250     p_input->stream.i_method = INPUT_METHOD_SATELLITE;
251     p_input->psz_demux = "satellite";
252
253     return 0;
254
255    }
256
257 /*****************************************************************************
258  * SatelliteClose : Closes the device
259  *****************************************************************************/
260 static void SatelliteClose( input_thread_t * p_input )
261 {
262     input_socket_t *    p_satellite;
263     int                 i_es_index;
264
265     if ( p_input->stream.p_selected_program )
266     {
267         for ( i_es_index = 1 ;
268                 i_es_index < p_input->stream.p_selected_program->
269                     i_es_number ;
270                 i_es_index ++ )
271         {
272 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
273             if ( p_es->p_decoder_fifo )
274             {
275                 ioctl_UnsetDMXFilter( p_es->i_dmx_fd );
276             }
277 #undef p_es
278         }
279     }
280
281     p_satellite = (input_socket_t *)p_input;
282     close( p_satellite->i_handle );
283 }
284
285 /*****************************************************************************
286  * SatelliteSetArea : Does nothing
287  *****************************************************************************/
288 static int SatelliteSetArea( input_thread_t * p_input, input_area_t * p_area )
289 {
290     return -1;
291 }
292
293 /*****************************************************************************
294  * SatelliteSetProgram : Sets the card filters according to the
295  *                 selected program,
296  *                 and makes the appropriate changes to stream structure.
297  *****************************************************************************/
298 int SatelliteSetProgram( input_thread_t    * p_input,
299                          pgrm_descriptor_t * p_new_prg )
300 {
301     int                 i_es_index;
302
303     if ( p_input->stream.p_selected_program )
304     {
305         for ( i_es_index = 1 ; /* 0 should be the PMT */
306                 i_es_index < p_input->stream.p_selected_program->
307                     i_es_number ;
308                 i_es_index ++ )
309         {
310 #define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
311             if ( p_es->p_decoder_fifo )
312             {
313                 input_UnselectES( p_input , p_es );
314                 p_es->p_pes = NULL; /* FIXME */
315             }
316             if ( p_es->i_dmx_fd )
317             {
318                 ioctl_UnsetDMXFilter( p_es->i_dmx_fd );
319                 p_es->i_dmx_fd = 0;
320             }
321 #undef p_es
322         }
323     }
324
325     for (i_es_index = 1 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
326     {
327 #define p_es p_new_prg->pp_es[i_es_index]
328         switch( p_es->i_cat )
329         {
330             case MPEG1_VIDEO_ES:
331             case MPEG2_VIDEO_ES:
332                 if ( p_main->b_video )
333                 {
334                     ioctl_SetDMXFilter( p_es->i_id, &p_es->i_dmx_fd, 1);
335                     input_SelectES( p_input , p_es );
336                 }
337                 break;
338             case MPEG1_AUDIO_ES:
339             case MPEG2_AUDIO_ES:
340                 if ( p_main->b_audio )
341                 {
342                     ioctl_SetDMXFilter( p_es->i_id, &p_es->i_dmx_fd, 2);
343                     input_SelectES( p_input , p_es );
344                 }
345                 break;
346             default:
347                 ioctl_SetDMXFilter( p_es->i_id, &p_es->i_dmx_fd, 3);
348                 input_SelectES( p_input , p_es );
349                 break;
350 #undef p_es
351         }
352     }
353
354     p_input->stream.p_selected_program = p_new_prg;
355
356     return( 0 );
357 }
358
359 /*****************************************************************************
360  * SatelliteSeek: does nothing (not a seekable stream
361  *****************************************************************************/
362 static void SatelliteSeek( input_thread_t * p_input, off_t i_off )
363 {
364     return;
365 }
366
367 /*****************************************************************************
368  * SatelliteInit: initializes TS structures
369  *****************************************************************************/
370 static int SatelliteInit( input_thread_t * p_input )
371 {
372     es_descriptor_t     * p_pat_es;
373     es_ts_data_t        * p_demux_data;
374     stream_ts_data_t    * p_stream_data;
375
376     /* Initialize the stream */
377     input_InitStream( p_input, sizeof( stream_ts_data_t ) );
378
379
380     /* Init */
381     p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
382     p_stream_data->i_pat_version = PAT_UNINITIALIZED ;
383
384     /* We'll have to catch the PAT in order to continue
385      * Then the input will catch the PMT and then the others ES
386      * The PAT es is indepedent of any program. */
387     p_pat_es = input_AddES( p_input, NULL,
388                            0x00, sizeof( es_ts_data_t ) );
389     p_demux_data=(es_ts_data_t *)p_pat_es->p_demux_data;
390     p_demux_data->b_psi = 1;
391     p_demux_data->i_psi_type = PSI_IS_PAT;
392     p_demux_data->p_psi_section = malloc(sizeof(psi_section_t));
393     p_demux_data->p_psi_section->b_is_complete = 1;
394
395     return 0;
396
397 }
398
399 /*****************************************************************************
400  * SatelliteEnd: frees unused data
401  *****************************************************************************/
402 static void SatelliteEnd( input_thread_t * p_input )
403 {
404 }
405
406 /*****************************************************************************
407  * SatelliteDemux
408  *****************************************************************************/
409 static int SatelliteDemux( input_thread_t * p_input )
410 {
411     int             i_read_once = (p_input->i_mtu ?
412                                    p_input->i_bufsize / TS_PACKET_SIZE :
413                                    SATELLITE_READ_ONCE);
414     int             i;
415
416     /* if not set, set filters to the PMTs */
417
418     for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
419     {
420         if ( p_input->stream.pp_programs[i]->pp_es[0]->i_dmx_fd == 0 )
421         {
422             intf_WarnMsg( 2, "input: satellite: setting filter on pmt pid %d",
423                         p_input->stream.pp_programs[i]->pp_es[0]->i_id);
424             ioctl_SetDMXFilter( p_input->stream.pp_programs[i]->pp_es[0]->i_id,
425                        &p_input->stream.pp_programs[i]->pp_es[0]->i_dmx_fd,
426                        3 );
427         }
428     }
429
430
431     for( i = 0; i < SATELLITE_READ_ONCE; i++ )
432     {
433         data_packet_t *     p_data;
434         ssize_t             i_result;
435
436         i_result = input_ReadTS( p_input, &p_data );
437
438         if( i_result <= 0 )
439         {
440             return( i_result );
441         }
442
443         input_DemuxTS( p_input, p_data );
444     }
445
446     return( i_read_once );
447 }
448
449 /*****************************************************************************
450  * SatelliteRewind: Does nothing
451  *****************************************************************************/
452 static int SatelliteRewind( input_thread_t * p_input )
453 {
454     return -1;
455 }
456