]> git.sesse.net Git - vlc/blob - plugins/mpeg_system/mpeg_ts.c
d2ff7c9b21eb3d2e558bc474d2678f2e4a0afea9
[vlc] / plugins / mpeg_system / mpeg_ts.c
1 /*****************************************************************************
2  * mpeg_ts.c : Transport Stream input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2001 VideoLAN
5  * $Id: mpeg_ts.c,v 1.16 2002/07/23 00:39:17 sam Exp $
6  *
7  * Authors: Henri Fallon <henri@via.ecp.fr>
8  *          Johan Bilien <jobi@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31
32 #include <vlc/vlc.h>
33 #include <vlc/input.h>
34
35 #include "iso_lang.h"
36
37 #if defined MODULE_NAME_IS_mpeg_ts_dvbpsi
38 #   ifdef HAVE_DVBPSI_DR_H
39 #       include <dvbpsi/dvbpsi.h>
40 #       include <dvbpsi/descriptor.h>
41 #       include <dvbpsi/pat.h>
42 #       include <dvbpsi/pmt.h>
43 #       include <dvbpsi/dr.h>
44 #   else
45 #       include "dvbpsi.h"
46 #       include "descriptor.h"
47 #       include "tables/pat.h"
48 #       include "tables/pmt.h"
49 #       include "descriptors/dr.h"
50 #   endif
51 #endif
52
53 /*****************************************************************************
54  * Constants
55  *****************************************************************************/
56 #define TS_READ_ONCE 200
57
58 /*****************************************************************************
59  * Local prototypes
60  *****************************************************************************/
61 static void input_getfunctions( function_list_t * p_function_list );
62 static int  TSInit  ( input_thread_t * );
63 static void TSEnd   ( input_thread_t * );
64 static int  TSDemux ( input_thread_t * );
65
66 #if defined MODULE_NAME_IS_mpeg_ts
67 static void TSDemuxPSI ( input_thread_t *, data_packet_t *,
68                           es_descriptor_t *, vlc_bool_t );
69 static void TSDecodePAT( input_thread_t *, es_descriptor_t *);
70 static void TSDecodePMT( input_thread_t *, es_descriptor_t *);
71 #define PSI_CALLBACK TSDemuxPSI
72 #elif defined MODULE_NAME_IS_mpeg_ts_dvbpsi
73 static void TS_DVBPSI_DemuxPSI  ( input_thread_t *, data_packet_t *,
74                                   es_descriptor_t *, vlc_bool_t );
75 static void TS_DVBPSI_HandlePAT ( input_thread_t *, dvbpsi_pat_t * );
76 static void TS_DVBPSI_HandlePMT ( input_thread_t *, dvbpsi_pmt_t * );
77 #define PSI_CALLBACK TS_DVBPSI_DemuxPSI
78 #endif
79
80 /*****************************************************************************
81  * Build configuration tree.
82  *****************************************************************************/
83 MODULE_CONFIG_START
84 MODULE_CONFIG_STOP
85
86 MODULE_INIT_START
87 #if defined MODULE_NAME_IS_mpeg_ts
88     SET_DESCRIPTION( _("ISO 13818-1 MPEG Transport Stream input") )
89     ADD_CAPABILITY( DEMUX, 160 )
90     ADD_SHORTCUT( "ts" )
91 #elif defined MODULE_NAME_IS_mpeg_ts_dvbpsi
92     SET_DESCRIPTION( _("ISO 13818-1 MPEG Transport Stream input (libdvbpsi)") )
93     ADD_CAPABILITY( DEMUX, 170 )
94     ADD_SHORTCUT( "ts_dvbpsi" )
95 #endif
96 MODULE_INIT_STOP
97
98 MODULE_ACTIVATE_START
99     input_getfunctions( &p_module->p_functions->demux );
100 MODULE_ACTIVATE_STOP
101
102 MODULE_DEACTIVATE_START
103 MODULE_DEACTIVATE_STOP
104
105 /*****************************************************************************
106  * Functions exported as capabilities. They are declared as static so that
107  * we don't pollute the namespace too much.
108  *****************************************************************************/
109 static void input_getfunctions( function_list_t * p_function_list )
110 {
111 #define input p_function_list->functions.demux
112     input.pf_init             = TSInit;
113     input.pf_end              = TSEnd;
114     input.pf_demux            = TSDemux;
115     input.pf_rewind           = NULL;
116 #undef input
117 }
118
119 /*****************************************************************************
120  * TSInit: initializes TS structures
121  *****************************************************************************/
122 static int TSInit( input_thread_t * p_input )
123 {
124     es_descriptor_t     * p_pat_es;
125     es_ts_data_t        * p_demux_data;
126     stream_ts_data_t    * p_stream_data;
127     byte_t              * p_peek;
128
129     /* Initialize access plug-in structures. */
130     if( p_input->i_mtu == 0 )
131     {
132         /* Improve speed. */
133         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
134     }
135
136     /* Have a peep at the show. */
137     if( input_Peek( p_input, &p_peek, 1 ) < 1 )
138     {
139         msg_Err( p_input, "cannot peek()" );
140         return( -1 );
141     }
142
143     if( *p_peek != TS_SYNC_CODE )
144     {
145         if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ts", 3 ) )
146         {
147             /* User forced */
148             msg_Err( p_input, "this does not look like a TS stream, continuing" );
149         }
150         else
151         {
152             msg_Warn( p_input, "TS module discarded (no sync)" );
153             return( -1 );
154         }
155     }
156
157     /* Adapt the bufsize for our only use. */
158     if( p_input->i_mtu != 0 )
159     {
160         /* Have minimum granularity to avoid bottlenecks at the input level. */
161         p_input->i_bufsize = (p_input->i_mtu / TS_PACKET_SIZE) * TS_PACKET_SIZE;
162     }
163
164     vlc_mutex_lock( &p_input->stream.stream_lock );
165
166     if( input_InitStream( p_input, sizeof( stream_ts_data_t ) ) == -1 )
167     {
168         return( -1 );
169     }
170     
171     p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
172     p_stream_data->i_pat_version = PAT_UNINITIALIZED ;
173
174 #ifdef MODULE_NAME_IS_mpeg_ts_dvbpsi
175     p_stream_data->p_pat_handle = (dvbpsi_handle *)
176       dvbpsi_AttachPAT( (dvbpsi_pat_callback) &TS_DVBPSI_HandlePAT, p_input ); 
177
178     if( p_stream_data->p_pat_handle == NULL )
179     {
180         msg_Err( p_input, "could not create PAT decoder" );
181         return( -1 );
182     }
183 #endif
184     
185     /* We'll have to catch the PAT in order to continue
186      * Then the input will catch the PMT and then the others ES
187      * The PAT es is indepedent of any program. */
188     p_pat_es = input_AddES( p_input, NULL,
189                             0x00, sizeof( es_ts_data_t ) );
190     p_demux_data = (es_ts_data_t *)p_pat_es->p_demux_data;
191     p_demux_data->b_psi = 1;
192     p_demux_data->i_psi_type = PSI_IS_PAT;
193     p_demux_data->p_psi_section = malloc(sizeof(psi_section_t));
194     p_demux_data->p_psi_section->b_is_complete = 1;
195
196     vlc_mutex_unlock( &p_input->stream.stream_lock );
197     
198     return( 0 );
199 }
200
201 /*****************************************************************************
202  * TSEnd: frees unused data
203  *****************************************************************************/
204 static void TSEnd( input_thread_t * p_input )
205 {
206 }
207
208 /*****************************************************************************
209  * TSDemux: reads and demuxes data packets
210  *****************************************************************************
211  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
212  * packets.
213  *****************************************************************************/
214 static int TSDemux( input_thread_t * p_input )
215 {
216     int             i_read_once = (p_input->i_mtu ?
217                                    p_input->i_bufsize / TS_PACKET_SIZE :
218                                    TS_READ_ONCE);
219     int             i;
220
221     for( i = 0; i < i_read_once; i++ )
222     {
223         data_packet_t *     p_data;
224         ssize_t             i_result;
225
226         i_result = input_ReadTS( p_input, &p_data );
227
228         if( i_result <= 0 )
229         {
230             return( i_result );
231         }
232
233         input_DemuxTS( p_input, p_data, (psi_callback_t) &PSI_CALLBACK );
234     }
235
236     return( i_read_once );
237 }
238
239
240 #if defined MODULE_NAME_IS_mpeg_ts
241 /*
242  * PSI demultiplexing and decoding without libdvbpsi
243  */
244
245 /*****************************************************************************
246  * DemuxPSI : makes up complete PSI data
247  *****************************************************************************/
248 static void TSDemuxPSI( input_thread_t * p_input, data_packet_t * p_data, 
249         es_descriptor_t * p_es, vlc_bool_t b_unit_start )
250 {
251     es_ts_data_t  * p_demux_data;
252     
253     p_demux_data = (es_ts_data_t *)p_es->p_demux_data;
254
255 #define p_psi (p_demux_data->p_psi_section)
256 #define p (p_data->p_payload_start)
257
258     if( b_unit_start )
259     {
260         /* unit_start set to 1 -> presence of a pointer field
261          * (see ISO/IEC 13818 (2.4.4.2) which should be set to 0x00 */
262         if( (u8)p[0] != 0x00 )
263         {
264             msg_Warn( p_input,
265                       "non-zero pointer field found, trying to continue" );
266             p+=(u8)p[0];
267         }
268         else
269         {
270             p++;
271         }
272
273         /* This is the begining of a new section */
274
275         if( ((u8)(p[1]) & 0xc0) != 0x80 ) 
276         {
277             msg_Warn( p_input, "invalid PSI packet" );
278             p_psi->b_trash = 1;
279         }
280         else 
281         {
282             p_psi->i_section_length = ((p[1] & 0xF) << 8) | p[2];
283             p_psi->b_section_complete = 0;
284             p_psi->i_read_in_section = 0;
285             p_psi->i_section_number = (u8)p[6];
286
287             if( p_psi->b_is_complete || p_psi->i_section_number == 0 )
288             {
289                 /* This is a new PSI packet */
290                 p_psi->b_is_complete = 0;
291                 p_psi->b_trash = 0;
292                 p_psi->i_version_number = ( p[5] >> 1 ) & 0x1f;
293                 p_psi->i_last_section_number = (u8)p[7];
294
295                 /* We'll write at the begining of the buffer */
296                 p_psi->p_current = p_psi->buffer;
297             }
298             else
299             {
300                 if( p_psi->b_section_complete )
301                 {
302                     /* New Section of an already started PSI */
303                     p_psi->b_section_complete = 0;
304                     
305                     if( p_psi->i_version_number != (( p[5] >> 1 ) & 0x1f) )
306                     {
307                         msg_Warn( p_input,
308                                   "PSI version differs inside same PAT" );
309                         p_psi->b_trash = 1;
310                     }
311                     if( p_psi->i_section_number + 1 != (u8)p[6] )
312                     {
313                         msg_Warn( p_input,
314                                   "PSI Section discontinuity, packet lost?" );
315                         p_psi->b_trash = 1;
316                     }
317                     else
318                         p_psi->i_section_number++;
319                 }
320                 else
321                 {
322                     msg_Warn( p_input, "got unexpected new PSI section" );
323                     p_psi->b_trash = 1;
324                 }
325             }
326         }
327     } /* b_unit_start */
328     
329     if( !p_psi->b_trash )
330     {
331         /* read */
332         if( (p_data->p_payload_end - p) >=
333             ( p_psi->i_section_length - p_psi->i_read_in_section ) )
334         {
335             /* The end of the section is in this TS packet */
336             memcpy( p_psi->p_current, p, 
337             (p_psi->i_section_length - p_psi->i_read_in_section) );
338     
339             p_psi->b_section_complete = 1;
340             p_psi->p_current += 
341                 (p_psi->i_section_length - p_psi->i_read_in_section);
342                         
343             if( p_psi->i_section_number == p_psi->i_last_section_number )
344             {
345                 /* This was the last section of PSI */
346                 p_psi->b_is_complete = 1;
347
348                 switch( p_demux_data->i_psi_type)
349                 {
350                 case PSI_IS_PAT:
351                     TSDecodePAT( p_input, p_es );
352                     break;
353                 case PSI_IS_PMT:
354                     TSDecodePMT( p_input, p_es );
355                     break;
356                 default:
357                     msg_Warn( p_input, "received unknown PSI in DemuxPSI" );
358                 }
359             }
360         }
361         else
362         {
363             memcpy( p_psi->buffer, p, p_data->p_payload_end - p );
364             p_psi->i_read_in_section += p_data->p_payload_end - p;
365
366             p_psi->p_current += p_data->p_payload_end - p;
367         }
368     }
369
370 #undef p_psi    
371 #undef p
372    
373     input_DeletePacket( p_input->p_method_data, p_data );
374     
375     return ;
376 }
377
378 /*****************************************************************************
379  * DecodePAT : Decodes Programm association table and deal with it
380  *****************************************************************************/
381 static void TSDecodePAT( input_thread_t * p_input, es_descriptor_t * p_es )
382 {
383     stream_ts_data_t  * p_stream_data;
384     es_ts_data_t      * p_demux_data;
385
386     pgrm_descriptor_t * p_pgrm;
387     es_descriptor_t   * p_current_es;
388     byte_t            * p_current_data;           
389
390     int                 i_section_length, i_program_id, i_pmt_pid;
391     int                 i_loop, i_current_section;
392
393     vlc_bool_t          b_changed = 0;
394
395     p_demux_data = (es_ts_data_t *)p_es->p_demux_data;
396     p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
397     
398 #define p_psi (p_demux_data->p_psi_section)
399
400     /* Not so fast, Mike ! If the PAT version has changed, we first check
401      * that its content has really changed before doing anything */
402     if( p_stream_data->i_pat_version != p_psi->i_version_number )
403     {
404         int i_programs = p_input->stream.i_pgrm_number;
405
406         p_current_data = p_psi->buffer;
407
408         do
409         {
410             i_section_length = ((u32)(p_current_data[1] & 0xF) << 8) |
411                                  p_current_data[2];
412             i_current_section = (u8)p_current_data[6];
413     
414             for( i_loop = 0;
415                  ( i_loop < (i_section_length - 9) / 4 ) && !b_changed;
416                  i_loop++ )
417             {
418                 i_program_id = ( (u32)*(p_current_data + i_loop * 4 + 8) << 8 )
419                                  | *(p_current_data + i_loop * 4 + 9);
420                 i_pmt_pid = ( ((u32)*(p_current_data + i_loop * 4 + 10) & 0x1F)
421                                     << 8 )
422                                | *(p_current_data + i_loop * 4 + 11);
423
424                 if( i_program_id )
425                 {
426                     if( (p_pgrm = input_FindProgram( p_input, i_program_id ))
427                         && (p_current_es = input_FindES( p_input, i_pmt_pid ))
428                         && p_current_es->p_pgrm == p_pgrm
429                         && p_current_es->i_id == i_pmt_pid
430                         && ((es_ts_data_t *)p_current_es->p_demux_data)->b_psi
431                         && ((es_ts_data_t *)p_current_es->p_demux_data)
432                             ->i_psi_type == PSI_IS_PMT )
433                     {
434                         i_programs--;
435                     }
436                     else
437                     {
438                         b_changed = 1;
439                     }
440                 }
441             }
442             
443             p_current_data += 3 + i_section_length;
444
445         } while( ( i_current_section < p_psi->i_last_section_number )
446                   && !b_changed );
447
448         /* If we didn't find the expected amount of programs, the PAT has
449          * changed. Otherwise, it only changed if b_changed is already != 0 */
450         b_changed = b_changed || i_programs;
451     }
452
453     if( b_changed )
454     {
455         /* PAT has changed. We are going to delete all programs and 
456          * create new ones. We chose not to only change what was needed
457          * as a PAT change may mean the stream is radically changing and
458          * this is a secure method to avoid crashes */
459         es_ts_data_t      * p_es_demux;
460         pgrm_ts_data_t    * p_pgrm_demux;
461         
462         p_current_data = p_psi->buffer;
463
464         /* Delete all programs */
465         while( p_input->stream.i_pgrm_number )
466         {
467             input_DelProgram( p_input, p_input->stream.pp_programs[0] );
468         }
469         
470         do
471         {
472             i_section_length = ((u32)(p_current_data[1] & 0xF) << 8) |
473                                  p_current_data[2];
474             i_current_section = (u8)p_current_data[6];
475     
476             for( i_loop = 0; i_loop < (i_section_length - 9) / 4 ; i_loop++ )
477             {
478                 i_program_id = ( (u32)*(p_current_data + i_loop * 4 + 8) << 8 )
479                                  | *(p_current_data + i_loop * 4 + 9);
480                 i_pmt_pid = ( ((u32)*(p_current_data + i_loop * 4 + 10) & 0x1F)
481                                     << 8 )
482                                | *(p_current_data + i_loop * 4 + 11);
483     
484                 /* If program = 0, we're having info about NIT not PMT */
485                 if( i_program_id )
486                 {
487                     /* Add this program */
488                     p_pgrm = input_AddProgram( p_input, i_program_id, 
489                                                sizeof( pgrm_ts_data_t ) );
490                    
491                     /* whatis the PID of the PMT of this program */
492                     p_pgrm_demux = (pgrm_ts_data_t *)p_pgrm->p_demux_data;
493                     p_pgrm_demux->i_pmt_version = PMT_UNINITIALIZED;
494     
495                     /* Add the PMT ES to this program */
496                     p_current_es = input_AddES( p_input, p_pgrm,(u16)i_pmt_pid,
497                                         sizeof( es_ts_data_t) );
498                     p_es_demux = (es_ts_data_t *)p_current_es->p_demux_data;
499                     p_es_demux->b_psi = 1;
500                     p_es_demux->i_psi_type = PSI_IS_PMT;
501                     
502                     p_es_demux->p_psi_section = 
503                                             malloc( sizeof( psi_section_t ) );
504                     p_es_demux->p_psi_section->b_is_complete = 0;
505                 }
506             }
507             
508             p_current_data += 3 + i_section_length;
509
510         } while( i_current_section < p_psi->i_last_section_number );
511
512         /* Go to the beginning of the next section */
513         p_stream_data->i_pat_version = p_psi->i_version_number;
514
515     }
516 #undef p_psi
517
518 }
519
520 /*****************************************************************************
521  * DecodePMT : decode a given Program Stream Map
522  * ***************************************************************************
523  * When the PMT changes, it may mean a deep change in the stream, and it is
524  * careful to delete the ES and add them again. If the PMT doesn't change,
525  * there no need to do anything.
526  *****************************************************************************/
527 static void TSDecodePMT( input_thread_t * p_input, es_descriptor_t * p_es )
528 {
529
530     pgrm_ts_data_t            * p_pgrm_data;
531     es_ts_data_t              * p_demux_data;
532
533     p_demux_data = (es_ts_data_t *)p_es->p_demux_data;
534     p_pgrm_data = (pgrm_ts_data_t *)p_es->p_pgrm->p_demux_data;
535     
536 #define p_psi (p_demux_data->p_psi_section)
537
538     if( p_psi->i_version_number != p_pgrm_data->i_pmt_version ) 
539     {
540         es_descriptor_t   * p_new_es;  
541         es_ts_data_t      * p_es_demux;
542         byte_t            * p_current_data, * p_current_section;
543         int                 i_section_length,i_current_section;
544         int                 i_prog_info_length, i_loop;
545         int                 i_es_info_length, i_pid, i_stream_type;
546         
547         p_current_section = p_psi->buffer;
548         p_current_data = p_psi->buffer;
549
550         p_pgrm_data->i_pcr_pid = ( ((u32)*(p_current_section + 8) & 0x1F) << 8 ) |
551                                     *(p_current_section + 9);
552
553
554         /* Lock stream information */
555         vlc_mutex_lock( &p_input->stream.stream_lock );
556
557         /* Delete all ES in this program  except the PSI. We start from the
558          * end because i_es_number gets decremented after each deletion. */
559         for( i_loop = p_es->p_pgrm->i_es_number ; i_loop ; )
560         {
561             i_loop--;
562             p_es_demux = (es_ts_data_t *)
563                          p_es->p_pgrm->pp_es[i_loop]->p_demux_data;
564             if ( ! p_es_demux->b_psi )
565             {
566                 input_DelES( p_input, p_es->p_pgrm->pp_es[i_loop] );
567             }
568         }
569
570         /* Then add what we received in this PMT */
571         do
572         {
573             i_section_length = ( ((u32)*(p_current_data + 1) & 0xF) << 8 ) |
574                                   *(p_current_data + 2);
575             i_current_section = (u8)p_current_data[6];
576             i_prog_info_length = ( ((u32)*(p_current_data + 10) & 0xF) << 8 ) |
577                                     *(p_current_data + 11);
578
579             /* For the moment we ignore program descriptors */
580             p_current_data += 12 + i_prog_info_length;
581     
582             /* The end of the section, before the CRC is at 
583              * p_current_section + i_section_length -1 */
584             while( p_current_data < p_current_section + i_section_length -1 )
585             {
586                 i_stream_type = (int)p_current_data[0];
587                 i_pid = ( ((u32)*(p_current_data + 1) & 0x1F) << 8 ) |
588                            *(p_current_data + 2);
589                 i_es_info_length = ( ((u32)*(p_current_data + 3) & 0xF) << 8 ) |
590                                       *(p_current_data + 4);
591                 
592                 /* Add this ES to the program */
593                 p_new_es = input_AddES( p_input, p_es->p_pgrm, 
594                                         (u16)i_pid, sizeof( es_ts_data_t ) );
595
596                 /* Tell the interface what kind of stream it is and select 
597                  * the required ones */
598                 {
599                     switch( i_stream_type )
600                     {
601                         case MPEG1_VIDEO_ES:
602                         case MPEG2_VIDEO_ES:
603                             p_new_es->i_fourcc = VLC_FOURCC('m','p','g','v');
604                             p_new_es->i_cat = VIDEO_ES;
605                             break;
606                         case MPEG1_AUDIO_ES:
607                         case MPEG2_AUDIO_ES:
608                             p_new_es->i_fourcc = VLC_FOURCC('m','p','g','a');
609                             p_new_es->i_cat = AUDIO_ES;
610                             break;
611                         case LPCM_AUDIO_ES:
612                             p_new_es->i_fourcc = VLC_FOURCC('l','p','c','m');
613                             p_new_es->i_stream_id = 0xBD;
614                             p_new_es->i_cat = AUDIO_ES;
615                             break;
616                         case AC3_AUDIO_ES:
617                             p_new_es->i_fourcc = VLC_FOURCC('a','5','2',' ');
618                             p_new_es->i_stream_id = 0xBD;
619                             p_new_es->i_cat = AUDIO_ES;
620                             break;
621                         /* Not sure this one is fully specification-compliant */
622                         case DVD_SPU_ES:
623                             p_new_es->i_fourcc = VLC_FOURCC('s','p','u',' ');
624                             p_new_es->i_stream_id = 0xBD;
625                             p_new_es->i_cat = SPU_ES;
626                             break;
627                         default :
628                             p_new_es->i_fourcc = 0;
629                             p_new_es->i_cat = UNKNOWN_ES;
630                             break;
631                     }
632                 }
633                 
634                 p_current_data += 5 + i_es_info_length;
635             }
636
637             /* Go to the beginning of the next section*/
638             p_current_data += 3 + i_section_length;
639            
640             p_current_section++;
641             
642         } while( i_current_section < p_psi->i_last_section_number );
643
644         p_pgrm_data->i_pmt_version = p_psi->i_version_number;
645
646         /* if no program is selected :*/
647         if( !p_input->stream.p_selected_program )
648         {
649             pgrm_descriptor_t *     p_pgrm_to_select;
650             u16 i_id = (u16)config_GetInt( p_input, "program" );
651
652             if( i_id != 0 ) /* if user specified a program */
653             {
654                 p_pgrm_to_select = input_FindProgram( p_input, i_id );
655
656                 if( p_pgrm_to_select && p_pgrm_to_select == p_es->p_pgrm )
657                     p_input->pf_set_program( p_input, p_pgrm_to_select );
658             }
659             else
660                     p_input->pf_set_program( p_input, p_es->p_pgrm );
661         }
662         
663         /* inform interface that stream has changed */
664         p_input->stream.b_changed = 1;
665         /*  Remove lock */
666         vlc_mutex_unlock( &p_input->stream.stream_lock );
667     }
668     
669 #undef p_psi
670 }
671
672 #elif defined MODULE_NAME_IS_mpeg_ts_dvbpsi
673 /*
674  * PSI Decoding using libdvbcss 
675  */
676
677 /*****************************************************************************
678  * DemuxPSI : send the PSI to the right libdvbpsi decoder
679  *****************************************************************************/
680 static void TS_DVBPSI_DemuxPSI( input_thread_t  * p_input, 
681                                 data_packet_t   * p_data, 
682                                 es_descriptor_t * p_es, 
683                                 vlc_bool_t        b_unit_start )
684 {
685     es_ts_data_t        * p_es_demux_data;
686     pgrm_ts_data_t      * p_pgrm_demux_data;
687     stream_ts_data_t    * p_stream_demux_data;
688
689     p_es_demux_data = ( es_ts_data_t * ) p_es->p_demux_data;
690     p_stream_demux_data = ( stream_ts_data_t * ) p_input->stream.p_demux_data;
691
692     switch( p_es_demux_data->i_psi_type)
693     {
694         case PSI_IS_PAT:
695             dvbpsi_PushPacket( 
696                     ( dvbpsi_handle ) p_stream_demux_data->p_pat_handle,
697                     p_data->p_demux_start );
698             break;
699         case PSI_IS_PMT:
700             p_pgrm_demux_data = ( pgrm_ts_data_t * )p_es->p_pgrm->p_demux_data;
701             dvbpsi_PushPacket( 
702                     ( dvbpsi_handle ) p_pgrm_demux_data->p_pmt_handle,
703                     p_data->p_demux_start );
704             break;
705         default:
706             msg_Warn( p_input, "received unknown PSI in DemuxPSI" );
707     }
708     
709     input_DeletePacket( p_input->p_method_data, p_data );
710 }
711
712 /*****************************************************************************
713  * HandlePAT: will treat a PAT returned by dvbpsi
714  *****************************************************************************/
715
716 void TS_DVBPSI_HandlePAT( input_thread_t * p_input, dvbpsi_pat_t * p_new_pat )
717 {
718     dvbpsi_pat_program_t *      p_pgrm;
719     pgrm_descriptor_t *         p_new_pgrm;
720     pgrm_ts_data_t *            p_pgrm_demux;
721     es_descriptor_t *           p_current_es;
722     es_ts_data_t *              p_es_demux;
723     stream_ts_data_t *          p_stream_data;
724
725     vlc_mutex_lock( &p_input->stream.stream_lock );
726     
727     p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
728     
729     if ( !p_new_pat->b_current_next || 
730             p_stream_data->i_pat_version == PAT_UNINITIALIZED  )
731     {
732         /* Delete all programs */
733         while( p_input->stream.i_pgrm_number )
734         {
735             input_DelProgram( p_input, p_input->stream.pp_programs[0] );
736         }
737     
738         /* treat the new programs list */
739         p_pgrm = p_new_pat->p_first_program;
740         
741         while( p_pgrm )
742         {
743             /* If program = 0, we're having info about NIT not PMT */
744             if( p_pgrm->i_number )
745             {
746                 /* Add this program */
747                 p_new_pgrm = input_AddProgram( p_input, p_pgrm->i_number, 
748                                             sizeof( pgrm_ts_data_t ) );
749
750                 p_pgrm_demux = (pgrm_ts_data_t *)p_new_pgrm->p_demux_data;
751                 p_pgrm_demux->i_pmt_version = PMT_UNINITIALIZED;
752         
753                 /* Add the PMT ES to this program */
754                 p_current_es = input_AddES( p_input, p_new_pgrm,
755                                             (u16) p_pgrm->i_pid,
756                                             sizeof( es_ts_data_t) );
757                 p_es_demux = (es_ts_data_t *)p_current_es->p_demux_data;
758                 p_es_demux->b_psi = 1;
759                 p_es_demux->i_psi_type = PSI_IS_PMT;
760                         
761                 p_es_demux->p_psi_section = malloc( sizeof( psi_section_t ) );
762                 if ( p_es_demux->p_psi_section == NULL )
763                 {
764                     msg_Err( p_input, "out of memory" );
765                     p_input->b_error = 1;
766                     return;
767                 }
768             
769                 p_es_demux->p_psi_section->b_is_complete = 0;
770                 
771                 /* Create a PMT decoder */
772                 p_pgrm_demux->p_pmt_handle = (dvbpsi_handle *)
773                     dvbpsi_AttachPMT( p_pgrm->i_number,
774                             (dvbpsi_pmt_callback) &TS_DVBPSI_HandlePMT, 
775                             p_input );
776
777                 if( p_pgrm_demux->p_pmt_handle == NULL )
778                 {
779                     msg_Err( p_input, "could not create PMT decoder" );
780                     p_input->b_error = 1;
781                     return;
782                 }
783
784             }
785             p_pgrm = p_pgrm->p_next; 
786         }
787         
788         p_stream_data->i_pat_version = p_new_pat->i_version;
789     }
790     vlc_mutex_unlock( &p_input->stream.stream_lock );
791 }
792
793 /*****************************************************************************
794  * HandlePMT: will treat a PMT returned by dvbpsi
795  *****************************************************************************/
796 void TS_DVBPSI_HandlePMT( input_thread_t * p_input, dvbpsi_pmt_t * p_new_pmt )
797 {
798     dvbpsi_pmt_es_t *       p_es;
799     pgrm_descriptor_t *     p_pgrm;
800     es_descriptor_t *       p_new_es;
801     pgrm_ts_data_t *        p_pgrm_demux;
802    
803     vlc_mutex_lock( &p_input->stream.stream_lock );
804     
805     p_pgrm = input_FindProgram( p_input, p_new_pmt->i_program_number );
806
807     if( p_pgrm == NULL )
808     {
809         msg_Warn( p_input, "PMT of unreferenced program found" );
810         return;
811     }
812
813     p_pgrm_demux = (pgrm_ts_data_t *)p_pgrm->p_demux_data;
814     p_pgrm_demux->i_pcr_pid = p_new_pmt->i_pcr_pid;
815
816     if( !p_new_pmt->b_current_next || 
817             p_pgrm_demux->i_pmt_version == PMT_UNINITIALIZED )
818     {
819         p_es = p_new_pmt->p_first_es;
820         while( p_es )
821         {
822             /* Add this ES */
823             p_new_es = input_AddES( p_input, p_pgrm, 
824                             (u16)p_es->i_pid, sizeof( es_ts_data_t ) );
825             if( p_new_es == NULL )
826             {
827                 msg_Err( p_input, "could not add ES %d", p_es->i_pid );
828                 p_input->b_error = 1;
829                 return;
830             }
831
832             switch( p_es->i_type )
833             {
834                 case MPEG1_VIDEO_ES:
835                 case MPEG2_VIDEO_ES:
836                     p_new_es->i_fourcc = VLC_FOURCC('m','p','g','v');
837                     p_new_es->i_cat = VIDEO_ES;
838                     break;
839                 case MPEG1_AUDIO_ES:
840                 case MPEG2_AUDIO_ES:
841                     p_new_es->i_fourcc = VLC_FOURCC('m','p','g','a');
842                     p_new_es->i_cat = AUDIO_ES;
843                     break;
844                 case LPCM_AUDIO_ES:
845                     p_new_es->i_fourcc = VLC_FOURCC('l','p','c','m');
846                     p_new_es->i_cat = AUDIO_ES;
847                     p_new_es->i_stream_id = 0xBD;
848                     break;
849                 case AC3_AUDIO_ES:
850                     p_new_es->i_fourcc = VLC_FOURCC('a','5','2',' ');
851                     p_new_es->i_cat = AUDIO_ES;
852                     p_new_es->i_stream_id = 0xBD;
853                     break;
854                 case DVD_SPU_ES:
855                     p_new_es->i_fourcc = VLC_FOURCC('s','p','u',' ');
856                     p_new_es->i_cat = SPU_ES;
857                     p_new_es->i_stream_id = 0xBD;
858                     break;
859                 default:
860                     p_new_es->i_fourcc = 0;
861                     p_new_es->i_cat = UNKNOWN_ES;
862             }
863
864             if(    ( p_new_es->i_cat == AUDIO_ES )
865                 || (p_new_es->i_cat == SPU_ES ) )
866             {
867                 dvbpsi_descriptor_t *p_dr = p_es->p_first_descriptor;
868                 while( p_dr && ( p_dr->i_tag != 0x0a ) )
869                     p_dr = p_dr->p_next;
870                 if( p_dr )
871                 {
872                     dvbpsi_iso639_dr_t *p_decoded =
873                                                 dvbpsi_DecodeISO639Dr( p_dr );
874                     if( p_decoded->i_code_count > 0 )
875                     {
876                         const iso639_lang_t * p_iso;
877                         p_iso = GetLang_2T(p_decoded->i_iso_639_code);
878                         if(p_iso)
879                         {
880                             if(p_iso->psz_native_name[0])
881                                 strcpy( p_new_es->psz_desc,
882                                         p_iso->psz_native_name );
883                             else
884                                 strcpy( p_new_es->psz_desc,
885                                         p_iso->psz_eng_name );
886                         }
887                         else
888                         {
889                             strncpy( p_new_es->psz_desc,
890                                      p_decoded->i_iso_639_code, 3 );
891                         }
892                     }
893                 }
894                 switch( p_es->i_type )
895                 {
896                     case MPEG1_AUDIO_ES:
897                     case MPEG2_AUDIO_ES:
898                         strcat( p_new_es->psz_desc, " (mpeg)" );
899                         break;
900                     case LPCM_AUDIO_ES:
901                         strcat( p_new_es->psz_desc, " (lpcm)" );
902                         break;
903                     case AC3_AUDIO_ES:
904                         strcat( p_new_es->psz_desc, " (ac3)" );
905                         break;
906                 }
907             }
908
909             p_es = p_es->p_next;
910         }
911         
912         /* if no program is selected :*/
913         if( !p_input->stream.p_selected_program )
914         {
915             pgrm_descriptor_t *     p_pgrm_to_select;
916             u16 i_id = (u16)config_GetInt( p_input, "program" );
917
918             if( i_id != 0 ) /* if user specified a program */
919             {
920                 p_pgrm_to_select = input_FindProgram( p_input, i_id );
921
922                 if( p_pgrm_to_select && p_pgrm_to_select == p_pgrm )
923                     p_input->pf_set_program( p_input, p_pgrm_to_select );
924             }
925             else
926                     p_input->pf_set_program( p_input, p_pgrm );
927         }
928         /* if the pmt belongs to the currently selected program, we
929          * reselect it to update its ES */
930         else if( p_pgrm == p_input->stream.p_selected_program )
931         {
932             p_input->pf_set_program( p_input, p_pgrm );
933         }
934         
935         p_pgrm_demux->i_pmt_version = p_new_pmt->i_version;
936         p_input->stream.b_changed = 1;
937     }
938     vlc_mutex_unlock( &p_input->stream.stream_lock );
939 }
940 #endif