]> git.sesse.net Git - vlc/blob - plugins/satellite/input_satellite.c
* When unselecting an ES, we must ged rid of p_es->p_pes so that it is
[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             }
315             if ( p_es->i_dmx_fd )
316             {
317                 ioctl_UnsetDMXFilter( p_es->i_dmx_fd );
318                 p_es->i_dmx_fd = 0;
319             }
320 #undef p_es
321         }
322     }
323
324     for (i_es_index = 1 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
325     {
326 #define p_es p_new_prg->pp_es[i_es_index]
327         switch( p_es->i_cat )
328         {
329             case MPEG1_VIDEO_ES:
330             case MPEG2_VIDEO_ES:
331                 if ( p_main->b_video )
332                 {
333                     ioctl_SetDMXFilter( p_es->i_id, &p_es->i_dmx_fd, 1);
334                     input_SelectES( p_input , p_es );
335                 }
336                 break;
337             case MPEG1_AUDIO_ES:
338             case MPEG2_AUDIO_ES:
339                 if ( p_main->b_audio )
340                 {
341                     ioctl_SetDMXFilter( p_es->i_id, &p_es->i_dmx_fd, 2);
342                     input_SelectES( p_input , p_es );
343                 }
344                 break;
345             default:
346                 ioctl_SetDMXFilter( p_es->i_id, &p_es->i_dmx_fd, 3);
347                 input_SelectES( p_input , p_es );
348                 break;
349 #undef p_es
350         }
351     }
352
353     p_input->stream.p_selected_program = p_new_prg;
354
355     return( 0 );
356 }
357
358 /*****************************************************************************
359  * SatelliteSeek: does nothing (not a seekable stream
360  *****************************************************************************/
361 static void SatelliteSeek( input_thread_t * p_input, off_t i_off )
362 {
363     return;
364 }
365
366 /*****************************************************************************
367  * SatelliteInit: initializes TS structures
368  *****************************************************************************/
369 static int SatelliteInit( input_thread_t * p_input )
370 {
371     es_descriptor_t     * p_pat_es;
372     es_ts_data_t        * p_demux_data;
373     stream_ts_data_t    * p_stream_data;
374
375     /* Initialize the stream */
376     input_InitStream( p_input, sizeof( stream_ts_data_t ) );
377
378
379     /* Init */
380     p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
381     p_stream_data->i_pat_version = PAT_UNINITIALIZED ;
382
383     /* We'll have to catch the PAT in order to continue
384      * Then the input will catch the PMT and then the others ES
385      * The PAT es is indepedent of any program. */
386     p_pat_es = input_AddES( p_input, NULL,
387                            0x00, sizeof( es_ts_data_t ) );
388     p_demux_data=(es_ts_data_t *)p_pat_es->p_demux_data;
389     p_demux_data->b_psi = 1;
390     p_demux_data->i_psi_type = PSI_IS_PAT;
391     p_demux_data->p_psi_section = malloc(sizeof(psi_section_t));
392     p_demux_data->p_psi_section->b_is_complete = 1;
393
394     return 0;
395
396 }
397
398 /*****************************************************************************
399  * SatelliteEnd: frees unused data
400  *****************************************************************************/
401 static void SatelliteEnd( input_thread_t * p_input )
402 {
403 }
404
405 /*****************************************************************************
406  * SatelliteDemux
407  *****************************************************************************/
408 static int SatelliteDemux( input_thread_t * p_input )
409 {
410     int             i_read_once = (p_input->i_mtu ?
411                                    p_input->i_bufsize / TS_PACKET_SIZE :
412                                    SATELLITE_READ_ONCE);
413     int             i;
414
415     /* if not set, set filters to the PMTs */
416
417     for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
418     {
419         if ( p_input->stream.pp_programs[i]->pp_es[0]->i_dmx_fd == 0 )
420         {
421             intf_WarnMsg( 2, "input: satellite: setting filter on pmt pid %d",
422                         p_input->stream.pp_programs[i]->pp_es[0]->i_id);
423             ioctl_SetDMXFilter( p_input->stream.pp_programs[i]->pp_es[0]->i_id,
424                        &p_input->stream.pp_programs[i]->pp_es[0]->i_dmx_fd,
425                        3 );
426         }
427     }
428
429
430     for( i = 0; i < SATELLITE_READ_ONCE; i++ )
431     {
432         data_packet_t *     p_data;
433         ssize_t             i_result;
434
435         i_result = input_ReadTS( p_input, &p_data );
436
437         if( i_result <= 0 )
438         {
439             return( i_result );
440         }
441
442         input_DemuxTS( p_input, p_data );
443     }
444
445     return( i_read_once );
446 }
447
448 /*****************************************************************************
449  * SatelliteRewind: Does nothing
450  *****************************************************************************/
451 static int SatelliteRewind( input_thread_t * p_input )
452 {
453     return -1;
454 }
455