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