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