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