ts.c 62 KB
Newer Older
1
2
3
4
/*****************************************************************************
 * mpeg_ts.c : Transport Stream input module for vlc
 *****************************************************************************
 * Copyright (C) 2000-2001 VideoLAN
Laurent Aimar's avatar
Laurent Aimar committed
5
 * $Id: ts.c,v 1.27 2003/05/31 21:49:12 fenrir Exp $
6
7
8
9
10
11
12
13
 *
 * Authors: Henri Fallon <henri@via.ecp.fr>
 *          Johan Bilien <jobi@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
14
 *
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>
#include <string.h>

gbazin's avatar
   
gbazin committed
31
32
33
34
#ifdef HAVE_STDINT_H
#   include <stdint.h>                                            /* uint8_t */
#endif

35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <vlc/vlc.h>
#include <vlc/input.h>

#include "iso_lang.h"

#if defined MODULE_NAME_IS_ts_dvbpsi
#   ifdef HAVE_DVBPSI_DR_H
#       include <dvbpsi/dvbpsi.h>
#       include <dvbpsi/descriptor.h>
#       include <dvbpsi/pat.h>
#       include <dvbpsi/pmt.h>
#       include <dvbpsi/dr.h>
#   else
#       include "dvbpsi.h"
#       include "descriptor.h"
#       include "tables/pat.h"
#       include "tables/pmt.h"
#       include "descriptors/dr.h"
#   endif
#endif

56
#include "system.h"
57
#include "codecs.h"
58

59
60
61
62
63
/*****************************************************************************
 * Constants
 *****************************************************************************/
#define TS_READ_ONCE 200

64
65
66
67
68
69
70
71
72
/*****************************************************************************
 * Private structure
 *****************************************************************************/
struct demux_sys_t
{
    module_t *   p_module;
    mpeg_demux_t mpeg;
};

73
74
75
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
76
77
78
static int  Activate   ( vlc_object_t * );
static void Deactivate ( vlc_object_t * );
static int  Demux      ( input_thread_t * );
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

#if defined MODULE_NAME_IS_ts
static void TSDemuxPSI ( input_thread_t *, data_packet_t *,
                          es_descriptor_t *, vlc_bool_t );
static void TSDecodePAT( input_thread_t *, es_descriptor_t *);
static void TSDecodePMT( input_thread_t *, es_descriptor_t *);
#define PSI_CALLBACK TSDemuxPSI
#elif defined MODULE_NAME_IS_ts_dvbpsi
static void TS_DVBPSI_DemuxPSI  ( input_thread_t *, data_packet_t *,
                                  es_descriptor_t *, vlc_bool_t );
static void TS_DVBPSI_HandlePAT ( input_thread_t *, dvbpsi_pat_t * );
static void TS_DVBPSI_HandlePMT ( input_thread_t *, dvbpsi_pmt_t * );
#define PSI_CALLBACK TS_DVBPSI_DemuxPSI
#endif

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
Christophe Massiot's avatar
Christophe Massiot committed
97
#define VLS_BACKWARDS_COMPAT_TEXT N_("Compatibility with pre-0.4 VLS")
98
99
100
101
102
#define VLS_BACKWARDS_COMPAT_LONGTEXT N_( \
    "The protocol for transmitting A/52 audio streams changed between VLC " \
    "0.3.x and 0.4. By default VLC assumes you have the latest VLS. In case " \
    "you're using an old version, select this option.")

Christophe Massiot's avatar
Christophe Massiot committed
103
#define BUGGY_PSI_TEXT N_("Buggy PSI")
104
105
106
107
#define BUGGY_PSI_LONGTEXT N_( \
    "If you have a stream whose PSI packets do not feature incremented " \
    "continuity counters, select this option.")

108
109
110
111
112
113
114
115
116
117
vlc_module_begin();
#if defined MODULE_NAME_IS_ts
    set_description( _("ISO 13818-1 MPEG Transport Stream input") );
    set_capability( "demux", 160 );
    add_shortcut( "ts" );
#elif defined MODULE_NAME_IS_ts_dvbpsi
    set_description( _("ISO 13818-1 MPEG Transport Stream input (libdvbpsi)") );
    set_capability( "demux", 170 );
    add_shortcut( "ts_dvbpsi" );
#endif
118
    add_category_hint( N_("Miscellaneous"), NULL, VLC_TRUE );
119
    add_bool( "vls-backwards-compat", 0, NULL,
120
121
              VLS_BACKWARDS_COMPAT_TEXT, VLS_BACKWARDS_COMPAT_LONGTEXT, VLC_TRUE );
    add_bool( "buggy-psi", 0, NULL, BUGGY_PSI_TEXT, BUGGY_PSI_LONGTEXT, VLC_TRUE );
122
    set_callbacks( Activate, Deactivate );
123
124
125
vlc_module_end();

/*****************************************************************************
126
 * Activate: initialize TS structures
127
128
129
130
 *****************************************************************************/
static int Activate( vlc_object_t * p_this )
{
    input_thread_t *    p_input = (input_thread_t *)p_this;
131
132
133
134
135
    demux_sys_t *       p_demux;
    es_descriptor_t *   p_pat_es;
    es_ts_data_t *      p_demux_data;
    stream_ts_data_t *  p_stream_data;
    byte_t *            p_peek;
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

    /* Set the demux function */
    p_input->pf_demux = Demux;

    /* Initialize access plug-in structures. */
    if( p_input->i_mtu == 0 )
    {
        /* Improve speed. */
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
    }

    /* Have a peep at the show. */
    if( input_Peek( p_input, &p_peek, 1 ) < 1 )
    {
        msg_Err( p_input, "cannot peek()" );
151
        return -1;
152
153
154
155
    }

    if( *p_peek != TS_SYNC_CODE )
    {
156
157
        if( *p_input->psz_demux && ( !strncmp( p_input->psz_demux, "ts", 3 )
                         || !strncmp( p_input->psz_demux, "ts_dvbpsi", 10 ) ) )
158
159
160
161
162
163
164
        {
            /* User forced */
            msg_Err( p_input, "this does not look like a TS stream, continuing" );
        }
        else
        {
            msg_Warn( p_input, "TS module discarded (no sync)" );
165
            return -1;
166
167
168
169
170
171
172
173
174
175
        }
    }

    /* Adapt the bufsize for our only use. */
    if( p_input->i_mtu != 0 )
    {
        /* Have minimum granularity to avoid bottlenecks at the input level. */
        p_input->i_bufsize = (p_input->i_mtu / TS_PACKET_SIZE) * TS_PACKET_SIZE;
    }

176
177
178
179
180
181
182
183
184
185
186
187
188
189
    p_demux = p_input->p_demux_data = malloc( sizeof(demux_sys_t ) );
    if( p_demux == NULL )
    {
        return -1;
    }

    p_input->p_private = (void*)&p_demux->mpeg;
    p_demux->p_module = module_Need( p_input, "mpeg-system", NULL );
    if( p_demux->p_module == NULL )
    {
        free( p_input->p_demux_data );
        return -1;
    }

190
191
192
193
    vlc_mutex_lock( &p_input->stream.stream_lock );

    if( input_InitStream( p_input, sizeof( stream_ts_data_t ) ) == -1 )
    {
194
195
196
        module_Unneed( p_input, p_demux->p_module );
        free( p_input->p_demux_data );
        return -1;
197
    }
198

199
200
    p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
    p_stream_data->i_pat_version = PAT_UNINITIALIZED ;
201
    p_stream_data->b_buggy_psi = config_GetInt( p_input, "buggy-psi" );
202
203
204

#ifdef MODULE_NAME_IS_ts_dvbpsi
    p_stream_data->p_pat_handle = (dvbpsi_handle *)
205
      dvbpsi_AttachPAT( (dvbpsi_pat_callback) &TS_DVBPSI_HandlePAT, p_input );
206
207
208
209

    if( p_stream_data->p_pat_handle == NULL )
    {
        msg_Err( p_input, "could not create PAT decoder" );
210
211
212
        module_Unneed( p_input, p_demux->p_module );
        free( p_input->p_demux_data );
        return -1;
213
214
    }
#endif
215

216
217
218
    /* We'll have to catch the PAT in order to continue
     * Then the input will catch the PMT and then the others ES
     * The PAT es is indepedent of any program. */
gbazin's avatar
   
gbazin committed
219
220
    p_pat_es = input_AddES( p_input, NULL, 0x00,
                            UNKNOWN_ES, NULL, sizeof( es_ts_data_t ) );
221
222
223
224
225
    p_demux_data = (es_ts_data_t *)p_pat_es->p_demux_data;
    p_demux_data->b_psi = 1;
    p_demux_data->i_psi_type = PSI_IS_PAT;
    p_demux_data->p_psi_section = malloc(sizeof(psi_section_t));
    p_demux_data->p_psi_section->b_is_complete = 1;
226
    p_demux_data->i_continuity_counter = 0xFF;
227
228

    vlc_mutex_unlock( &p_input->stream.stream_lock );
229

230
231
232
233
234
235
236
237
238
239
240
241
    return 0;
}

/*****************************************************************************
 * Deactivate: deinitialize TS structures
 *****************************************************************************/
static void Deactivate( vlc_object_t * p_this )
{
    input_thread_t *    p_input = (input_thread_t *)p_this;

    module_Unneed( p_input, p_input->p_demux_data->p_module );
    free( p_input->p_demux_data );
242
243
244
245
246
247
248
249
250
251
}

/*****************************************************************************
 * Demux: reads and demuxes data packets
 *****************************************************************************
 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
 * packets.
 *****************************************************************************/
static int Demux( input_thread_t * p_input )
{
252
    demux_sys_t *   p_demux = p_input->p_demux_data;
253
254
255
256
257
258
259
260
261
262
    int             i_read_once = (p_input->i_mtu ?
                                   p_input->i_bufsize / TS_PACKET_SIZE :
                                   TS_READ_ONCE);
    int             i;

    for( i = 0; i < i_read_once; i++ )
    {
        data_packet_t *     p_data;
        ssize_t             i_result;

263
        i_result = p_demux->mpeg.pf_read_ts( p_input, &p_data );
264
265
266

        if( i_result <= 0 )
        {
267
            return i_result;
268
269
        }

270
271
        p_demux->mpeg.pf_demux_ts( p_input, p_data,
                                   (psi_callback_t) &PSI_CALLBACK );
272
273
    }

274
    return i_read_once;
275
276
277
278
279
280
281
282
283
284
285
}


#if defined MODULE_NAME_IS_ts
/*
 * PSI demultiplexing and decoding without libdvbpsi
 */

/*****************************************************************************
 * DemuxPSI : makes up complete PSI data
 *****************************************************************************/
286
static void TSDemuxPSI( input_thread_t * p_input, data_packet_t * p_data,
287
288
289
        es_descriptor_t * p_es, vlc_bool_t b_unit_start )
{
    es_ts_data_t  * p_demux_data;
290

291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
    p_demux_data = (es_ts_data_t *)p_es->p_demux_data;

#define p_psi (p_demux_data->p_psi_section)
#define p (p_data->p_payload_start)

    if( b_unit_start )
    {
        /* unit_start set to 1 -> presence of a pointer field
         * (see ISO/IEC 13818 (2.4.4.2) which should be set to 0x00 */
        if( (u8)p[0] != 0x00 )
        {
            msg_Warn( p_input,
                      "non-zero pointer field found, trying to continue" );
            p+=(u8)p[0];
        }
        else
        {
            p++;
        }

        /* This is the begining of a new section */

313
        if( ((u8)(p[1]) & 0xc0) != 0x80 )
314
315
316
317
        {
            msg_Warn( p_input, "invalid PSI packet" );
            p_psi->b_trash = 1;
        }
318
        else
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
        {
            p_psi->i_section_length = ((p[1] & 0xF) << 8) | p[2];
            p_psi->b_section_complete = 0;
            p_psi->i_read_in_section = 0;
            p_psi->i_section_number = (u8)p[6];

            if( p_psi->b_is_complete || p_psi->i_section_number == 0 )
            {
                /* This is a new PSI packet */
                p_psi->b_is_complete = 0;
                p_psi->b_trash = 0;
                p_psi->i_version_number = ( p[5] >> 1 ) & 0x1f;
                p_psi->i_last_section_number = (u8)p[7];

                /* We'll write at the begining of the buffer */
                p_psi->p_current = p_psi->buffer;
            }
            else
            {
                if( p_psi->b_section_complete )
                {
                    /* New Section of an already started PSI */
                    p_psi->b_section_complete = 0;
342

343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
                    if( p_psi->i_version_number != (( p[5] >> 1 ) & 0x1f) )
                    {
                        msg_Warn( p_input,
                                  "PSI version differs inside same PAT" );
                        p_psi->b_trash = 1;
                    }
                    if( p_psi->i_section_number + 1 != (u8)p[6] )
                    {
                        msg_Warn( p_input,
                                  "PSI Section discontinuity, packet lost?" );
                        p_psi->b_trash = 1;
                    }
                    else
                        p_psi->i_section_number++;
                }
                else
                {
                    msg_Warn( p_input, "got unexpected new PSI section" );
                    p_psi->b_trash = 1;
                }
            }
        }
    } /* b_unit_start */
366

367
368
369
370
371
372
373
    if( !p_psi->b_trash )
    {
        /* read */
        if( (p_data->p_payload_end - p) >=
            ( p_psi->i_section_length - p_psi->i_read_in_section ) )
        {
            /* The end of the section is in this TS packet */
374
            memcpy( p_psi->p_current, p,
375
            (p_psi->i_section_length - p_psi->i_read_in_section) );
376

377
            p_psi->b_section_complete = 1;
378
            p_psi->p_current +=
379
                (p_psi->i_section_length - p_psi->i_read_in_section);
380

381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
            if( p_psi->i_section_number == p_psi->i_last_section_number )
            {
                /* This was the last section of PSI */
                p_psi->b_is_complete = 1;

                switch( p_demux_data->i_psi_type)
                {
                case PSI_IS_PAT:
                    TSDecodePAT( p_input, p_es );
                    break;
                case PSI_IS_PMT:
                    TSDecodePMT( p_input, p_es );
                    break;
                default:
                    msg_Warn( p_input, "received unknown PSI in DemuxPSI" );
                }
            }
        }
        else
        {
            memcpy( p_psi->buffer, p, p_data->p_payload_end - p );
            p_psi->i_read_in_section += p_data->p_payload_end - p;

            p_psi->p_current += p_data->p_payload_end - p;
        }
    }

408
#undef p_psi
409
#undef p
410

411
    input_DeletePacket( p_input->p_method_data, p_data );
412

413
414
415
416
417
418
419
420
421
422
423
424
425
    return ;
}

/*****************************************************************************
 * DecodePAT : Decodes Programm association table and deal with it
 *****************************************************************************/
static void TSDecodePAT( input_thread_t * p_input, es_descriptor_t * p_es )
{
    stream_ts_data_t  * p_stream_data;
    es_ts_data_t      * p_demux_data;

    pgrm_descriptor_t * p_pgrm;
    es_descriptor_t   * p_current_es;
426
    byte_t            * p_current_data;
427
428
429
430
431
432
433
434

    int                 i_section_length, i_program_id, i_pmt_pid;
    int                 i_loop, i_current_section;

    vlc_bool_t          b_changed = 0;

    p_demux_data = (es_ts_data_t *)p_es->p_demux_data;
    p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
435

436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
#define p_psi (p_demux_data->p_psi_section)

    /* Not so fast, Mike ! If the PAT version has changed, we first check
     * that its content has really changed before doing anything */
    if( p_stream_data->i_pat_version != p_psi->i_version_number )
    {
        int i_programs = p_input->stream.i_pgrm_number;

        p_current_data = p_psi->buffer;

        do
        {
            i_section_length = ((u32)(p_current_data[1] & 0xF) << 8) |
                                 p_current_data[2];
            i_current_section = (u8)p_current_data[6];
451

452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
            for( i_loop = 0;
                 ( i_loop < (i_section_length - 9) / 4 ) && !b_changed;
                 i_loop++ )
            {
                i_program_id = ( (u32)*(p_current_data + i_loop * 4 + 8) << 8 )
                                 | *(p_current_data + i_loop * 4 + 9);
                i_pmt_pid = ( ((u32)*(p_current_data + i_loop * 4 + 10) & 0x1F)
                                    << 8 )
                               | *(p_current_data + i_loop * 4 + 11);

                if( i_program_id )
                {
                    if( (p_pgrm = input_FindProgram( p_input, i_program_id ))
                        && (p_current_es = input_FindES( p_input, i_pmt_pid ))
                        && p_current_es->p_pgrm == p_pgrm
                        && p_current_es->i_id == i_pmt_pid
                        && ((es_ts_data_t *)p_current_es->p_demux_data)->b_psi
                        && ((es_ts_data_t *)p_current_es->p_demux_data)
                            ->i_psi_type == PSI_IS_PMT )
                    {
                        i_programs--;
                    }
                    else
                    {
                        b_changed = 1;
                    }
                }
            }
480

481
482
483
484
485
486
487
488
489
490
491
492
            p_current_data += 3 + i_section_length;

        } while( ( i_current_section < p_psi->i_last_section_number )
                  && !b_changed );

        /* If we didn't find the expected amount of programs, the PAT has
         * changed. Otherwise, it only changed if b_changed is already != 0 */
        b_changed = b_changed || i_programs;
    }

    if( b_changed )
    {
493
        /* PAT has changed. We are going to delete all programs and
494
495
496
497
498
         * create new ones. We chose not to only change what was needed
         * as a PAT change may mean the stream is radically changing and
         * this is a secure method to avoid crashes */
        es_ts_data_t      * p_es_demux;
        pgrm_ts_data_t    * p_pgrm_demux;
499

500
501
502
503
504
505
506
        p_current_data = p_psi->buffer;

        /* Delete all programs */
        while( p_input->stream.i_pgrm_number )
        {
            input_DelProgram( p_input, p_input->stream.pp_programs[0] );
        }
507

508
509
510
511
512
        do
        {
            i_section_length = ((u32)(p_current_data[1] & 0xF) << 8) |
                                 p_current_data[2];
            i_current_section = (u8)p_current_data[6];
513

514
515
516
517
518
519
520
            for( i_loop = 0; i_loop < (i_section_length - 9) / 4 ; i_loop++ )
            {
                i_program_id = ( (u32)*(p_current_data + i_loop * 4 + 8) << 8 )
                                 | *(p_current_data + i_loop * 4 + 9);
                i_pmt_pid = ( ((u32)*(p_current_data + i_loop * 4 + 10) & 0x1F)
                                    << 8 )
                               | *(p_current_data + i_loop * 4 + 11);
521

522
523
524
525
                /* If program = 0, we're having info about NIT not PMT */
                if( i_program_id )
                {
                    /* Add this program */
526
                    p_pgrm = input_AddProgram( p_input, i_program_id,
527
                                               sizeof( pgrm_ts_data_t ) );
528

529
530
531
                    /* whatis the PID of the PMT of this program */
                    p_pgrm_demux = (pgrm_ts_data_t *)p_pgrm->p_demux_data;
                    p_pgrm_demux->i_pmt_version = PMT_UNINITIALIZED;
532

533
534
                    /* Add the PMT ES to this program */
                    p_current_es = input_AddES( p_input, p_pgrm,(u16)i_pmt_pid,
gbazin's avatar
   
gbazin committed
535
                        UNKNOWN_ES, NULL, sizeof( es_ts_data_t) );
536
537
538
                    p_es_demux = (es_ts_data_t *)p_current_es->p_demux_data;
                    p_es_demux->b_psi = 1;
                    p_es_demux->i_psi_type = PSI_IS_PMT;
539
540

                    p_es_demux->p_psi_section =
541
542
                                            malloc( sizeof( psi_section_t ) );
                    p_es_demux->p_psi_section->b_is_complete = 0;
543
                    p_es_demux->i_continuity_counter = 0xFF;
544
545
                }
            }
546

547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
            p_current_data += 3 + i_section_length;

        } while( i_current_section < p_psi->i_last_section_number );

        /* Go to the beginning of the next section */
        p_stream_data->i_pat_version = p_psi->i_version_number;

    }
#undef p_psi

}

/*****************************************************************************
 * DecodePMT : decode a given Program Stream Map
 * ***************************************************************************
 * When the PMT changes, it may mean a deep change in the stream, and it is
 * careful to delete the ES and add them again. If the PMT doesn't change,
 * there no need to do anything.
 *****************************************************************************/
static void TSDecodePMT( input_thread_t * p_input, es_descriptor_t * p_es )
{

    pgrm_ts_data_t            * p_pgrm_data;
    es_ts_data_t              * p_demux_data;
571
    vlc_bool_t b_vls_compat = config_GetInt( p_input, "vls-backwards-compat" );
572
573
574

    p_demux_data = (es_ts_data_t *)p_es->p_demux_data;
    p_pgrm_data = (pgrm_ts_data_t *)p_es->p_pgrm->p_demux_data;
575

576
577
#define p_psi (p_demux_data->p_psi_section)

578
    if( p_psi->i_version_number != p_pgrm_data->i_pmt_version )
579
    {
580
        es_descriptor_t   * p_new_es;
581
582
583
584
585
        es_ts_data_t      * p_es_demux;
        byte_t            * p_current_data, * p_current_section;
        int                 i_section_length,i_current_section;
        int                 i_prog_info_length, i_loop;
        int                 i_es_info_length, i_pid, i_stream_type;
586

587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
        p_current_section = p_psi->buffer;
        p_current_data = p_psi->buffer;

        p_pgrm_data->i_pcr_pid = ( ((u32)*(p_current_section + 8) & 0x1F) << 8 ) |
                                    *(p_current_section + 9);


        /* Lock stream information */
        vlc_mutex_lock( &p_input->stream.stream_lock );

        /* Delete all ES in this program  except the PSI. We start from the
         * end because i_es_number gets decremented after each deletion. */
        for( i_loop = p_es->p_pgrm->i_es_number ; i_loop ; )
        {
            i_loop--;
            p_es_demux = (es_ts_data_t *)
                         p_es->p_pgrm->pp_es[i_loop]->p_demux_data;
            if ( ! p_es_demux->b_psi )
            {
                input_DelES( p_input, p_es->p_pgrm->pp_es[i_loop] );
            }
        }

        /* Then add what we received in this PMT */
        do
        {
            i_section_length = ( ((u32)*(p_current_data + 1) & 0xF) << 8 ) |
                                  *(p_current_data + 2);
            i_current_section = (u8)p_current_data[6];
            i_prog_info_length = ( ((u32)*(p_current_data + 10) & 0xF) << 8 ) |
                                    *(p_current_data + 11);

            /* For the moment we ignore program descriptors */
            p_current_data += 12 + i_prog_info_length;
621
622

            /* The end of the section, before the CRC is at
623
624
625
626
627
628
629
630
             * p_current_section + i_section_length -1 */
            while( p_current_data < p_current_section + i_section_length -1 )
            {
                i_stream_type = (int)p_current_data[0];
                i_pid = ( ((u32)*(p_current_data + 1) & 0x1F) << 8 ) |
                           *(p_current_data + 2);
                i_es_info_length = ( ((u32)*(p_current_data + 3) & 0xF) << 8 ) |
                                      *(p_current_data + 4);
631
632

                /* Tell the interface what kind of stream it is and select
633
634
                 * the required ones */
                {
gbazin's avatar
   
gbazin committed
635
636
                    int i_fourcc, i_cat, i_stream_id;

637
638
639
640
                    switch( i_stream_type )
                    {
                        case MPEG1_VIDEO_ES:
                        case MPEG2_VIDEO_ES:
641
                        case MPEG2_MOTO_VIDEO_ES:
642
643
                            /* This isn't real, but we don't actually use
                             * it. */
gbazin's avatar
   
gbazin committed
644
645
646
                            i_stream_id = 0xE0;
                            i_fourcc = VLC_FOURCC('m','p','g','v');
                            i_cat = VIDEO_ES;
647
648
649
                            break;
                        case MPEG1_AUDIO_ES:
                        case MPEG2_AUDIO_ES:
650
651
                            /* This isn't real, but we don't actually use
                             * it. */
gbazin's avatar
   
gbazin committed
652
653
654
                            i_stream_id = 0xC0;
                            i_fourcc = VLC_FOURCC('m','p','g','a');
                            i_cat = AUDIO_ES;
655
                            break;
656
                        case A52_AUDIO_ES:
657
                        case A52DVB_AUDIO_ES:
658
                            if ( !b_vls_compat )
gbazin's avatar
   
gbazin committed
659
                                i_fourcc = VLC_FOURCC('a','5','2',' ');
660
                            else
gbazin's avatar
   
gbazin committed
661
662
663
                                i_fourcc = VLC_FOURCC('a','5','2','b');
                            i_stream_id = 0xBD;
                            i_cat = AUDIO_ES;
664
                            break;
665
                        case LPCM_AUDIO_ES:
gbazin's avatar
   
gbazin committed
666
667
668
                            i_fourcc = VLC_FOURCC('l','p','c','m');
                            i_stream_id = 0xBD;
                            i_cat = AUDIO_ES;
669
670
                            break;
                        case DVD_SPU_ES:
671
                            if ( !b_vls_compat )
gbazin's avatar
   
gbazin committed
672
                                i_fourcc = VLC_FOURCC('s','p','u',' ');
673
                            else
gbazin's avatar
   
gbazin committed
674
675
676
                                i_fourcc = VLC_FOURCC('s','p','u','b');
                            i_stream_id = 0xBD;
                            i_cat = SPU_ES;
677
                            break;
678
                        case SDDS_AUDIO_ES:
gbazin's avatar
   
gbazin committed
679
680
681
                            i_fourcc = VLC_FOURCC('s','d','d','s');
                            i_stream_id = 0xBD;
                            i_cat = AUDIO_ES;
682
683
                            break;
                        case DTS_AUDIO_ES:
gbazin's avatar
   
gbazin committed
684
685
686
                            i_fourcc = VLC_FOURCC('d','t','s',' ');
                            i_stream_id = 0xBD;
                            i_cat = AUDIO_ES;
687
688
689
                            break;
                        /* 'b' stands for 'buggy' */
                        case A52B_AUDIO_ES:
gbazin's avatar
   
gbazin committed
690
691
692
                            i_fourcc = VLC_FOURCC('a','5','2','b');
                            i_stream_id = 0xBD;
                            i_cat = AUDIO_ES;
693
694
                            break;
                        case LPCMB_AUDIO_ES:
gbazin's avatar
   
gbazin committed
695
696
697
                            i_fourcc = VLC_FOURCC('l','p','c','b');
                            i_stream_id = 0xBD;
                            i_cat = AUDIO_ES;
698
699
                            break;
                        case DVDB_SPU_ES:
gbazin's avatar
   
gbazin committed
700
701
702
                            i_fourcc = VLC_FOURCC('s','p','u','b');
                            i_stream_id = 0xBD;
                            i_cat = SPU_ES;
703
                            break;
704

705
                        default :
gbazin's avatar
   
gbazin committed
706
707
708
                            i_stream_id = 0;
                            i_fourcc = 0;
                            i_cat = UNKNOWN_ES;
709
710
                            break;
                    }
gbazin's avatar
   
gbazin committed
711
712
713
714
715
716
717
718
719
720

                    /* Add this ES to the program */
                    p_new_es = input_AddES( p_input, p_es->p_pgrm, (u16)i_pid,
                                   i_cat, NULL, sizeof( es_ts_data_t ) );

                    ((es_ts_data_t *)p_new_es->p_demux_data)->i_continuity_counter = 0xFF;

                    p_new_es->i_stream_id = i_stream_id;
                    p_new_es->i_fourcc = i_fourcc;

721
                }
722

723
724
725
726
727
                p_current_data += 5 + i_es_info_length;
            }

            /* Go to the beginning of the next section*/
            p_current_data += 3 + i_section_length;
728

729
            p_current_section++;
730

731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
        } while( i_current_section < p_psi->i_last_section_number );

        p_pgrm_data->i_pmt_version = p_psi->i_version_number;

        /* if no program is selected :*/
        if( !p_input->stream.p_selected_program )
        {
            pgrm_descriptor_t *     p_pgrm_to_select;
            u16 i_id = (u16)config_GetInt( p_input, "program" );

            if( i_id != 0 ) /* if user specified a program */
            {
                p_pgrm_to_select = input_FindProgram( p_input, i_id );

                if( p_pgrm_to_select && p_pgrm_to_select == p_es->p_pgrm )
                    p_input->pf_set_program( p_input, p_pgrm_to_select );
            }
            else
                    p_input->pf_set_program( p_input, p_es->p_pgrm );
        }
751

752
753
754
755
756
757
758
        /* if the pmt belongs to the currently selected program, we
         * reselect it to update its ES */
        else if( p_es->p_pgrm == p_input->stream.p_selected_program )
        {
            p_input->pf_set_program( p_input, p_es->p_pgrm );
        }

759
760
761
762
763
        /* inform interface that stream has changed */
        p_input->stream.b_changed = 1;
        /*  Remove lock */
        vlc_mutex_unlock( &p_input->stream.stream_lock );
    }
764

765
766
767
768
769
#undef p_psi
}

#elif defined MODULE_NAME_IS_ts_dvbpsi
/*
770
 * PSI Decoding using libdvbpsi
771
772
773
774
775
 */

/*****************************************************************************
 * DemuxPSI : send the PSI to the right libdvbpsi decoder
 *****************************************************************************/
776
777
778
static void TS_DVBPSI_DemuxPSI( input_thread_t  * p_input,
                                data_packet_t   * p_data,
                                es_descriptor_t * p_es,
779
780
781
782
783
784
                                vlc_bool_t        b_unit_start )
{
    es_ts_data_t        * p_es_demux_data;
    pgrm_ts_data_t      * p_pgrm_demux_data;
    stream_ts_data_t    * p_stream_demux_data;

785
786
    p_es_demux_data = (es_ts_data_t *)p_es->p_demux_data;
    p_stream_demux_data = (stream_ts_data_t *) p_input->stream.p_demux_data;
787
788
789
790

    switch( p_es_demux_data->i_psi_type)
    {
        case PSI_IS_PAT:
791
            dvbpsi_PushPacket(
792
                    (dvbpsi_handle)p_stream_demux_data->p_pat_handle,
793
794
795
796
                    p_data->p_demux_start );
            break;
        case PSI_IS_PMT:
            p_pgrm_demux_data = ( pgrm_ts_data_t * )p_es->p_pgrm->p_demux_data;
797
            dvbpsi_PushPacket(
798
                    (dvbpsi_handle)p_pgrm_demux_data->p_pmt_handle,
799
800
801
802
803
                    p_data->p_demux_start );
            break;
        default:
            msg_Warn( p_input, "received unknown PSI in DemuxPSI" );
    }
804

805
806
    input_DeletePacket( p_input->p_method_data, p_data );
}
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*****************************************************************************
 * MP4 specific functions
 *****************************************************************************/
static int  MP4_DescriptorLength( int *pi_data, uint8_t **pp_data )
{
    unsigned int i_b;
    unsigned int i_len = 0;
    do
    {
        i_b = **pp_data;
        (*pp_data)++;
        (*pi_data)--;
        i_len = ( i_len << 7 ) + ( i_b&0x7f );

    } while( i_b&0x80 );

    return( i_len );
}
static int MP4_GetByte( int *pi_data, uint8_t **pp_data )
{
    if( *pi_data > 0 )
    {
        int i_b = **pp_data;
        (*pp_data)++;
        (*pi_data)--;
        return( i_b );
    }
    else
    {
        return( 0 );
    }
}

static int MP4_GetWord( int *pi_data, uint8_t **pp_data )
{
    int i1, i2;
    i1 = MP4_GetByte( pi_data, pp_data );
    i2 = MP4_GetByte( pi_data, pp_data );
    return( ( i1 << 8 ) | i2 );
}
static int MP4_Get3Bytes( int *pi_data, uint8_t **pp_data )
{
    int i1, i2, i3;
    i1 = MP4_GetByte( pi_data, pp_data );
    i2 = MP4_GetByte( pi_data, pp_data );
    i3 = MP4_GetByte( pi_data, pp_data );
    return( ( i1 << 16 ) | ( i2 << 8) | i3 );
}

static uint32_t MP4_GetDWord( int *pi_data, uint8_t **pp_data )
{
    uint32_t i1, i2;
    i1 = MP4_GetWord( pi_data, pp_data );
    i2 = MP4_GetWord( pi_data, pp_data );
    return( ( i1 << 16 ) | i2 );
}

static char* MP4_GetURL( int *pi_data, uint8_t **pp_data )
{
    char *url;
    int i_url_len, i;

    i_url_len = MP4_GetByte( pi_data, pp_data );
    url = malloc( i_url_len + 1 );
    for( i = 0; i < i_url_len; i++ )
    {
        url[i] = MP4_GetByte( pi_data, pp_data );
    }
    url[i_url_len] = '\0';
    return( url );
}

static void MP4_IODParse( iod_descriptor_t *p_iod, int i_data, uint8_t *p_data )
{
    int i;
    int i_es_index;
    uint8_t     i_flags;
    vlc_bool_t  b_url;
    int         i_iod_length;

    fprintf( stderr, "\n************ IOD ************" );
    for( i = 0; i < 255; i++ )
    {
        p_iod->es_descr[i].b_ok = 0;
    }
    i_es_index = 0;

    if( i_data < 3 )
    {
        return;
    }

    p_iod->i_iod_label = MP4_GetByte( &i_data, &p_data );
    fprintf( stderr, "\n* iod_label:%d", p_iod->i_iod_label );
    fprintf( stderr, "\n* ===========" );
    fprintf( stderr, "\n* tag:0x%x", p_data[0] );

    if( MP4_GetByte( &i_data, &p_data ) != 0x02 )
    {
        fprintf( stderr, "\n ERR: tag != 0x02" );
        return;
    }

    i_iod_length = MP4_DescriptorLength( &i_data, &p_data );
    fprintf( stderr, "\n* length:%d", i_iod_length );
    if( i_iod_length > i_data )
    {
        i_iod_length = i_data;
    }

    p_iod->i_od_id = ( MP4_GetByte( &i_data, &p_data ) << 2 );
    i_flags = MP4_GetByte( &i_data, &p_data );
    p_iod->i_od_id |= i_flags >> 6;
    b_url = ( i_flags >> 5  )&0x01;

    fprintf( stderr, "\n* od_id:%d", p_iod->i_od_id );
    fprintf( stderr, "\n* url flag:%d", b_url );
    fprintf( stderr, "\n* includeInlineProfileLevel flag:%d", ( i_flags >> 4 )&0x01 );

    if( b_url )
    {
        p_iod->psz_url = MP4_GetURL( &i_data, &p_data );
        fprintf( stderr, "\n* url string:%s", p_iod->psz_url );
        fprintf( stderr, "\n*****************************\n" );
        return;
    }
    else
    {
        p_iod->psz_url = NULL;
    }

    p_iod->i_ODProfileLevelIndication = MP4_GetByte( &i_data, &p_data );
    p_iod->i_sceneProfileLevelIndication = MP4_GetByte( &i_data, &p_data );
    p_iod->i_audioProfileLevelIndication = MP4_GetByte( &i_data, &p_data );
    p_iod->i_visualProfileLevelIndication = MP4_GetByte( &i_data, &p_data );
    p_iod->i_graphicsProfileLevelIndication = MP4_GetByte( &i_data, &p_data );

    fprintf( stderr, "\n* ODProfileLevelIndication:%d", p_iod->i_ODProfileLevelIndication );
    fprintf( stderr, "\n* sceneProfileLevelIndication:%d", p_iod->i_sceneProfileLevelIndication );
    fprintf( stderr, "\n* audioProfileLevelIndication:%d", p_iod->i_audioProfileLevelIndication );
    fprintf( stderr, "\n* visualProfileLevelIndication:%d", p_iod->i_visualProfileLevelIndication );
    fprintf( stderr, "\n* graphicsProfileLevelIndication:%d", p_iod->i_graphicsProfileLevelIndication );


    while( i_data > 0 && i_es_index < 255)
    {
        int i_tag, i_length;
        int     i_data_sav;
        uint8_t *p_data_sav;

        i_tag = MP4_GetByte( &i_data, &p_data );
        i_length = MP4_DescriptorLength( &i_data, &p_data );

        i_data_sav = i_data;
        p_data_sav = p_data;

        i_data = i_length;

        switch( i_tag )
        {
            case 0x03:
                {
#define es_descr    p_iod->es_descr[i_es_index]
                    int i_decoderConfigDescr_length;
                    fprintf( stderr, "\n* - ES_Descriptor length:%d", i_length );
                    es_descr.b_ok = 1;

                    es_descr.i_es_id = MP4_GetWord( &i_data, &p_data );
                    i_flags = MP4_GetByte( &i_data, &p_data );
                    es_descr.b_streamDependenceFlag = ( i_flags >> 7 )&0x01;
                    b_url = ( i_flags >> 6 )&0x01;
                    es_descr.b_OCRStreamFlag = ( i_flags >> 5 )&0x01;
                    es_descr.i_streamPriority = i_flags & 0x1f;
                    fprintf( stderr, "\n*   * streamDependenceFlag:%d", es_descr.b_streamDependenceFlag );
                    fprintf( stderr, "\n*   * OCRStreamFlag:%d", es_descr.b_OCRStreamFlag );
                    fprintf( stderr, "\n*   * streamPriority:%d", es_descr.i_streamPriority );

                    if( es_descr.b_streamDependenceFlag )
                    {
                        es_descr.i_dependOn_es_id = MP4_GetWord( &i_data, &p_data );
                        fprintf( stderr, "\n*   * dependOn_es_id:%d", es_descr.i_dependOn_es_id );
                    }

                    if( b_url )
                    {
                        es_descr.psz_url = MP4_GetURL( &i_data, &p_data );
                        fprintf( stderr, "\n* url string:%s", es_descr.psz_url );
                    }
                    else
                    {
                        es_descr.psz_url = NULL;
                    }

                    if( es_descr.b_OCRStreamFlag )
For faster browsing, not all history is shown. View entire blame