ps.h 20.4 KB
Newer Older
1
2
3
/*****************************************************************************
 * ps.h: Program Stream demuxer helper
 *****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2004-2009 the VideoLAN team
5
 * $Id$
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 *
 * Authors: Laurent Aimar <fenrir@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.
 *
 * 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
dionoea's avatar
dionoea committed
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
23
 *****************************************************************************/

24
#include <assert.h>
25
26
#include <vlc_demux.h>
#include <vlc_memory.h>
zorglub's avatar
zorglub committed
27

28
29
30
/* 256-0xC0 for normal stream, 256 for 0xbd stream, 256 for 0xfd stream, 8 for 0xa0 AOB stream */
#define PS_TK_COUNT (256+256+256+8 - 0xc0)
#if 0
31
#define PS_ID_TO_TK( id ) ((id) <= 0xff ? (id) - 0xc0 : \
32
            ((id)&0xff) + (((id)&0xff00) == 0xbd00 ? 256-0xC0 : 512-0xc0) )
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#else
static inline int ps_id_to_tk( unsigned i_id )
{
    if( i_id <= 0xff )
        return i_id - 0xc0;
    else if( (i_id & 0xff00) == 0xbd00 )
        return 256-0xC0 + (i_id & 0xff);
    else if( (i_id & 0xff00) == 0xfd00 )
        return 512-0xc0 + (i_id & 0xff);
    else
        return 768-0xc0 + (i_id & 0x07);
}
#define PS_ID_TO_TK( id ) ps_id_to_tk( id )
#endif
47
48

typedef struct ps_psm_t ps_psm_t;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
49
50
static inline int ps_id_to_type( const ps_psm_t *, int );
static inline const uint8_t *ps_id_to_lang( const ps_psm_t *, int );
51
52
53

typedef struct
{
54
    bool  b_seen;
55
    int         i_skip;
56
    int         i_id;
57
58
    es_out_id_t *es;
    es_format_t fmt;
59
60
    mtime_t     i_first_pts;
    mtime_t     i_last_pts;
61

62
63
64
65
66
67
68
69
} ps_track_t;

/* Init a set of track */
static inline void ps_track_init( ps_track_t tk[PS_TK_COUNT] )
{
    int i;
    for( i = 0; i < PS_TK_COUNT; i++ )
    {
70
        tk[i].b_seen = false;
71
        tk[i].i_skip = 0;
72
        tk[i].i_id   = 0;
73
        tk[i].es     = NULL;
hartman's avatar
hartman committed
74
75
        tk[i].i_first_pts = -1;
        tk[i].i_last_pts = -1;
76
77
78
79
80
        es_format_Init( &tk[i].fmt, UNKNOWN_ES, 0 );
    }
}

/* From id fill i_skip and es_format_t */
81
static inline int ps_track_fill( ps_track_t *tk, ps_psm_t *p_psm, int i_id )
82
83
{
    tk->i_skip = 0;
84
    tk->i_id = i_id;
85
86
    if( ( i_id&0xff00 ) == 0xbd00 )
    {
87
        if( ( i_id&0xf8 ) == 0x88 || (i_id&0xf8) == 0x98 )
88
        {
89
            es_format_Init( &tk->fmt, AUDIO_ES, VLC_CODEC_DTS );
Laurent Aimar's avatar
Laurent Aimar committed
90
            tk->i_skip = 4;
91
        }
92
93
        else if( ( i_id&0xf0 ) == 0x80
               ||  (i_id&0xf0) == 0xc0 ) /* AC-3, Can also be used for DD+/E-AC-3 */
94
        {
95
            es_format_Init( &tk->fmt, AUDIO_ES, VLC_CODEC_A52 );
96
97
            tk->i_skip = 4;
        }
98
99
        else if( (i_id&0xf0) == 0xb0 )
        {
100
            es_format_Init( &tk->fmt, AUDIO_ES, VLC_CODEC_MLP );
101
102
            /* FIXME / untested ... no known decoder (at least not in VLC/ffmpeg) */
        }
103
104
        else if( ( i_id&0xe0 ) == 0x20 )
        {
105
            es_format_Init( &tk->fmt, SPU_ES, VLC_CODEC_SPU );
106
107
108
109
            tk->i_skip = 1;
        }
        else if( ( i_id&0xf0 ) == 0xa0 )
        {
110
            es_format_Init( &tk->fmt, AUDIO_ES, VLC_CODEC_DVD_LPCM );
111
112
            tk->i_skip = 1;
        }
Laurent Aimar's avatar
Laurent Aimar committed
113
114
        else if( ( i_id&0xff ) == 0x70 )
        {
115
            es_format_Init( &tk->fmt, SPU_ES, VLC_CODEC_OGT );
Laurent Aimar's avatar
Laurent Aimar committed
116
117
118
        }
        else if( ( i_id&0xfc ) == 0x00 )
        {
119
            es_format_Init( &tk->fmt, SPU_ES, VLC_CODEC_CVD );
Laurent Aimar's avatar
Laurent Aimar committed
120
        }
121
122
        else if( ( i_id&0xff ) == 0x10 )
        {
123
            es_format_Init( &tk->fmt, SPU_ES, VLC_CODEC_TELETEXT );
124
        }
125
126
127
128
129
130
        else
        {
            es_format_Init( &tk->fmt, UNKNOWN_ES, 0 );
            return VLC_EGENERIC;
        }
    }
131
132
133
134
135
    else if( (i_id&0xff00) == 0xfd00 )
    {
        uint8_t i_sub_id = i_id & 0xff;
        if( i_sub_id >= 0x55 && i_sub_id <= 0x5f )
        {
136
            es_format_Init( &tk->fmt, VIDEO_ES, VLC_CODEC_VC1 );
137
138
139
140
141
142
143
        }
        else
        {
            es_format_Init( &tk->fmt, UNKNOWN_ES, 0 );
            return VLC_EGENERIC;
        }
    }
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
    else if( (i_id&0xff00) == 0xa000 )
    {
        uint8_t i_sub_id = i_id & 0x07;
        if( i_sub_id == 0 )
        {
            es_format_Init( &tk->fmt, AUDIO_ES, VLC_CODEC_DVDA_LPCM );
            tk->i_skip = 1;
        }
        else if( i_sub_id == 1 )
        {
            es_format_Init( &tk->fmt, AUDIO_ES, VLC_CODEC_MLP );
            tk->i_skip = -1; /* It's a hack for variable skip value */
        }
        else
        {
            es_format_Init( &tk->fmt, UNKNOWN_ES, 0 );
            return VLC_EGENERIC;
        }
    }
163
164
    else
    {
165
166
167
168
        int i_type = ps_id_to_type( p_psm , i_id );

        es_format_Init( &tk->fmt, UNKNOWN_ES, 0 );

169
170
        if( (i_id&0xf0) == 0xe0 && i_type == 0x1b )
        {
171
            es_format_Init( &tk->fmt, VIDEO_ES, VLC_CODEC_H264 );
172
173
        }
        else if( (i_id&0xf0) == 0xe0 && i_type == 0x10 )
174
        {
175
            es_format_Init( &tk->fmt, VIDEO_ES, VLC_CODEC_MP4V );
176
177
        }
        else if( (i_id&0xf0) == 0xe0 && i_type == 0x02 )
178
        {
179
            es_format_Init( &tk->fmt, VIDEO_ES, VLC_CODEC_MPGV );
180
        }
181
182
        else if( ( i_id&0xe0 ) == 0xc0 && i_type == 0x0f )
        {
183
            es_format_Init( &tk->fmt, AUDIO_ES, VLC_CODEC_MP4A );
184
185
186
        }
        else if( ( i_id&0xe0 ) == 0xc0 && i_type == 0x11 )
        {
187
            es_format_Init( &tk->fmt, AUDIO_ES, VLC_CODEC_MP4A );
188
        }
189
        else if( ( i_id&0xe0 ) == 0xc0 && i_type == 0x03 )
190
        {
191
            es_format_Init( &tk->fmt, AUDIO_ES, VLC_CODEC_MPGA );
192
        }
193
194

        if( tk->fmt.i_cat == UNKNOWN_ES && ( i_id&0xf0 ) == 0xe0 )
195
        {
196
            es_format_Init( &tk->fmt, VIDEO_ES, VLC_CODEC_MPGV );
197
        }
198
199
        else if( tk->fmt.i_cat == UNKNOWN_ES && ( i_id&0xe0 ) == 0xc0 )
        {
200
            es_format_Init( &tk->fmt, AUDIO_ES, VLC_CODEC_MPGA );
201
        }
202
        else if( tk->fmt.i_cat == UNKNOWN_ES ) return VLC_EGENERIC;
203
    }
204
205

    /* PES packets usually contain truncated frames */
206
    tk->fmt.b_packetized = false;
207

Jean-Paul Saman's avatar
Jean-Paul Saman committed
208
    if( ps_id_to_lang( p_psm, i_id ) )
209
210
    {
        tk->fmt.psz_language = malloc( 4 );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
211
212
213
214
215
        if( tk->fmt.psz_language )
        {
            memcpy( tk->fmt.psz_language, ps_id_to_lang( p_psm , i_id ), 3 );
            tk->fmt.psz_language[3] = 0;
        }
216
217
    }

218
219
220
221
222
223
224
225
    return VLC_SUCCESS;
}

/* return the id of a PES (should be valid) */
static inline int ps_pkt_id( block_t *p_pkt )
{
    if( p_pkt->p_buffer[3] == 0xbd &&
        p_pkt->i_buffer >= 9 &&
226
        p_pkt->i_buffer >= 9 + (size_t)p_pkt->p_buffer[8] )
227
    {
228
229
230
231
232
        const unsigned i_start = 9 + p_pkt->p_buffer[8];
        const uint8_t i_sub_id = p_pkt->p_buffer[i_start];

        if( (i_sub_id & 0xfe) == 0xa0 &&
            p_pkt->i_buffer >= i_start + 7 &&
233
234
            ( p_pkt->p_buffer[i_start + 5] >=  0xc0 ||
              p_pkt->p_buffer[i_start + 6] != 0x80 ) )
235
236
237
238
239
240
241
        {
            /* AOB LPCM/MLP extension
             * XXX for MLP I think that the !=0x80 test is not good and
             * will fail for some valid files */
            return 0xa000 | (i_sub_id & 0x01);
        }

242
        /* VOB extension */
243
        return 0xbd00 | i_sub_id;
244
    }
245
246
247
248
249
250
251
    else if( p_pkt->p_buffer[3] == 0xfd &&
             p_pkt->i_buffer >= 9 &&
             (p_pkt->p_buffer[6]&0xC0) == 0x80 &&   /* mpeg2 */
             (p_pkt->p_buffer[7]&0x01) == 0x01 )    /* extension_flag */
    {
        /* ISO 13818 amendment 2 and SMPTE RP 227 */
        const uint8_t i_flags = p_pkt->p_buffer[7];
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
252
        unsigned int i_skip = 9;
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298

        /* Find PES extension */
        if( (i_flags & 0x80 ) )
        {
            i_skip += 5;        /* pts */
            if( (i_flags & 0x40) )
                i_skip += 5;    /* dts */
        }
        if( (i_flags & 0x20 ) )
            i_skip += 6;
        if( (i_flags & 0x10 ) )
            i_skip += 3;
        if( (i_flags & 0x08 ) )
            i_skip += 1;
        if( (i_flags & 0x04 ) )
            i_skip += 1;
        if( (i_flags & 0x02 ) )
            i_skip += 2;

        if( i_skip < p_pkt->i_buffer && (p_pkt->p_buffer[i_skip]&0x01) )
        {
            const uint8_t i_flags2 = p_pkt->p_buffer[i_skip];

            /* Find PES extension 2 */
            i_skip += 1;
            if( i_flags2 & 0x80 )
                i_skip += 16;
            if( (i_flags2 & 0x40) && i_skip < p_pkt->i_buffer )
                i_skip += 1 + p_pkt->p_buffer[i_skip];
            if( i_flags2 & 0x20 )
                i_skip += 2;
            if( i_flags2 & 0x10 )
                i_skip += 2;

            if( i_skip + 1 < p_pkt->i_buffer )
            {
                const int i_extension_field_length = p_pkt->p_buffer[i_skip]&0x7f;
                if( i_extension_field_length >=1 )
                {
                    int i_stream_id_extension_flag = (p_pkt->p_buffer[i_skip+1] >> 7)&0x1;
                    if( i_stream_id_extension_flag == 0 )
                        return 0xfd00 | (p_pkt->p_buffer[i_skip+1]&0x7f);
                }
            }
        }
    }
299
300
301
    return p_pkt->p_buffer[3];
}

302
/* return the size of the next packet */
303
static inline int ps_pkt_size( const uint8_t *p, int i_peek )
304
{
305
306
307
308
309
    if( unlikely(i_peek < 4) )
    {
        return -1;
    }
    else if( p[3] == 0xb9 )
310
311
312
313
314
    {
        return 4;
    }
    else if( p[3] == 0xba )
    {
315
        if( i_peek >= 14 && (p[4] >> 6) == 0x01 )
316
317
318
        {
            return 14 + (p[13]&0x07);
        }
319
        else if( i_peek >= 12 && (p[4] >> 4) == 0x02 )
320
321
322
323
324
325
326
327
328
329
330
331
332
        {
            return 12;
        }
        return -1;
    }
    else if( i_peek >= 6 )
    {
        return 6 + ((p[4]<<8) | p[5] );
    }
    return -1;
}

/* parse a PACK PES */
gbazin's avatar
   
gbazin committed
333
334
static inline int ps_pkt_parse_pack( block_t *p_pkt, int64_t *pi_scr,
                                     int *pi_mux_rate )
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
{
    uint8_t *p = p_pkt->p_buffer;
    if( p_pkt->i_buffer >= 14 && (p[4] >> 6) == 0x01 )
    {
        *pi_scr =((((int64_t)p[4]&0x38) << 27 )|
                  (((int64_t)p[4]&0x03) << 28 )|
                   ((int64_t)p[5] << 20 )|
                  (((int64_t)p[6]&0xf8) << 12 )|
                  (((int64_t)p[6]&0x03) << 13 )|
                   ((int64_t)p[7] << 5 )|
                   ((int64_t)p[8] >> 3 )) * 100 / 9;

        *pi_mux_rate = ( p[10] << 14 )|( p[11] << 6 )|( p[12] >> 2);
    }
    else if( p_pkt->i_buffer >= 12 && (p[4] >> 4) == 0x02 )
    {
        *pi_scr =((((int64_t)p[4]&0x0e) << 29 )|
                   ((int64_t)p[5] << 22 )|
                  (((int64_t)p[6]&0xfe) << 14 )|
                   ((int64_t)p[7] <<  7 )|
                   ((int64_t)p[8] >> 1 )) * 100 / 9;

        *pi_mux_rate = ( ( p[9]&0x7f )<< 15 )|( p[10] << 7 )|( p[11] >> 1);
    }
    else
    {
        return VLC_EGENERIC;
    }
    return VLC_SUCCESS;
}

/* Parse a SYSTEM PES */
367
static inline int ps_pkt_parse_system( block_t *p_pkt, ps_psm_t *p_psm,
gbazin's avatar
   
gbazin committed
368
                                       ps_track_t tk[PS_TK_COUNT] )
369
370
371
{
    uint8_t *p = &p_pkt->p_buffer[6 + 3 + 1 + 1 + 1];

372
373
    /* System header is not useable if it references private streams (0xBD)
     * or 'all audio streams' (0xB8) or 'all video streams' (0xB9) */
374
375
    while( p < &p_pkt->p_buffer[p_pkt->i_buffer] )
    {
376
377
378
379
380
381
        int i_id = p[0];

        /* fprintf( stderr, "   SYSTEM_START_CODEEE: id=0x%x\n", p[0] ); */
        if( p[0] >= 0xBC || p[0] == 0xB8 || p[0] == 0xB9 ) p += 2;
        p++;

382
        if( i_id >= 0xc0 )
383
384
385
386
387
        {
            int i_tk = PS_ID_TO_TK( i_id );

            if( !tk[i_tk].b_seen )
            {
388
                if( !ps_track_fill( &tk[i_tk], p_psm, i_id ) )
389
                {
390
                    tk[i_tk].b_seen = true;
391
392
393
394
395
396
397
398
399
400
                }
            }
        }
    }
    return VLC_SUCCESS;
}

/* Parse a PES (and skip i_skip_extra in the payload) */
static inline int ps_pkt_parse_pes( block_t *p_pes, int i_skip_extra )
{
401
    uint8_t header[34];
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
402
    unsigned int i_skip  = 0;
403
404
    int64_t i_pts = -1;
    int64_t i_dts = -1;
405

406
    memcpy( header, p_pes->p_buffer, __MIN( p_pes->i_buffer, 34 ) );
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428

    switch( header[3] )
    {
        case 0xBC:  /* Program stream map */
        case 0xBE:  /* Padding */
        case 0xBF:  /* Private stream 2 */
        case 0xB0:  /* ECM */
        case 0xB1:  /* EMM */
        case 0xFF:  /* Program stream directory */
        case 0xF2:  /* DSMCC stream */
        case 0xF8:  /* ITU-T H.222.1 type E stream */
            i_skip = 6;
            break;

        default:
            if( ( header[6]&0xC0 ) == 0x80 )
            {
                /* mpeg2 PES */
                i_skip = header[8] + 9;

                if( header[7]&0x80 )    /* has pts */
                {
429
430
431
432
433
                    i_pts = ((mtime_t)(header[ 9]&0x0e ) << 29)|
                             (mtime_t)(header[10] << 22)|
                            ((mtime_t)(header[11]&0xfe) << 14)|
                             (mtime_t)(header[12] << 7)|
                             (mtime_t)(header[13] >> 1);
434
435
436

                    if( header[7]&0x40 )    /* has dts */
                    {
437
438
439
440
441
                         i_dts = ((mtime_t)(header[14]&0x0e ) << 29)|
                                  (mtime_t)(header[15] << 22)|
                                 ((mtime_t)(header[16]&0xfe) << 14)|
                                  (mtime_t)(header[17] << 7)|
                                  (mtime_t)(header[18] >> 1);
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
                    }
                }
            }
            else
            {
                i_skip = 6;
                while( i_skip < 23 && header[i_skip] == 0xff )
                {
                    i_skip++;
                }
                if( i_skip == 23 )
                {
                    /* msg_Err( p_demux, "too much MPEG-1 stuffing" ); */
                    return VLC_EGENERIC;
                }
                if( ( header[i_skip] & 0xC0 ) == 0x40 )
                {
                    i_skip += 2;
                }

                if(  header[i_skip]&0x20 )
                {
464
465
466
467
468
                     i_pts = ((mtime_t)(header[i_skip]&0x0e ) << 29)|
                              (mtime_t)(header[i_skip+1] << 22)|
                             ((mtime_t)(header[i_skip+2]&0xfe) << 14)|
                              (mtime_t)(header[i_skip+3] << 7)|
                              (mtime_t)(header[i_skip+4] >> 1);
469
470
471

                    if( header[i_skip]&0x10 )    /* has dts */
                    {
472
473
474
475
476
                         i_dts = ((mtime_t)(header[i_skip+5]&0x0e ) << 29)|
                                  (mtime_t)(header[i_skip+6] << 22)|
                                 ((mtime_t)(header[i_skip+7]&0xfe) << 14)|
                                  (mtime_t)(header[i_skip+8] << 7)|
                                  (mtime_t)(header[i_skip+9] >> 1);
477
478
479
480
481
482
483
484
485
486
487
488
489
490
                         i_skip += 10;
                    }
                    else
                    {
                        i_skip += 5;
                    }
                }
                else
                {
                    i_skip += 1;
                }
            }
    }

491
492
    if( i_skip_extra >= 0 )
        i_skip += i_skip_extra;
493
494
    else if( p_pes->i_buffer > i_skip + 3 &&
             ( ps_pkt_id( p_pes ) == 0xa001 || ps_pkt_id( p_pes ) == 0xbda1 ) )
495
        i_skip += 4 + p_pes->p_buffer[i_skip+3];
496
497
498
499
500
501
502
503
504

    if( p_pes->i_buffer <= i_skip )
    {
        return VLC_EGENERIC;
    }

    p_pes->p_buffer += i_skip;
    p_pes->i_buffer -= i_skip;

505
506
507
508
    if( i_dts >= 0 )
        p_pes->i_dts = VLC_TS_0 + 100 * i_dts / 9;
    if( i_pts >= 0 )
        p_pes->i_pts = VLC_TS_0 + 100 * i_pts / 9;
509
510
511

    return VLC_SUCCESS;
}
512
513

/* Program stream map handling */
514
typedef struct ps_es_t
515
516
517
518
519
520
521
{
    int i_type;
    int i_id;

    int i_descriptor;
    uint8_t *p_descriptor;

522
523
524
    /* Language is iso639-2T */
    uint8_t lang[3];

525
526
527
528
529
530
531
532
533
534
} ps_es_t;

struct ps_psm_t
{
    int i_version;

    int     i_es;
    ps_es_t **es;
};

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
535
static inline int ps_id_to_type( const ps_psm_t *p_psm, int i_id )
536
537
538
539
{
    int i;
    for( i = 0; p_psm && i < p_psm->i_es; i++ )
    {
540
        if( p_psm->es[i]->i_id == i_id ) return p_psm->es[i]->i_type;
541
542
543
544
    }
    return 0;
}

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
545
static inline const uint8_t *ps_id_to_lang( const ps_psm_t *p_psm, int i_id )
546
547
548
549
{
    int i;
    for( i = 0; p_psm && i < p_psm->i_es; i++ )
    {
550
        if( p_psm->es[i]->i_id == i_id ) return p_psm->es[i]->lang;
551
552
553
554
    }
    return 0;
}

555
556
557
558
559
560
561
562
563
564
565
static inline void ps_psm_init( ps_psm_t *p_psm )
{
    p_psm->i_version = 0xFFFF;
    p_psm->i_es = 0;
    p_psm->es = 0;
}

static inline void ps_psm_destroy( ps_psm_t *p_psm )
{
    while( p_psm->i_es-- )
    {
566
        free( p_psm->es[p_psm->i_es]->p_descriptor );
567
568
        free( p_psm->es[p_psm->i_es] );
    }
569
    free( p_psm->es );
570
571
572
573
574

    p_psm->es = 0;
    p_psm->i_es = 0;
}

575
576
static inline int ps_psm_fill( ps_psm_t *p_psm, block_t *p_pkt,
                               ps_track_t tk[PS_TK_COUNT], es_out_t *out )
577
578
579
{
    int i_buffer = p_pkt->i_buffer;
    uint8_t *p_buffer = p_pkt->p_buffer;
Laurent Aimar's avatar
Laurent Aimar committed
580
    int i_length, i_version, i_info_length, i_esm_length, i_es_base;
581
582
583

    if( !p_psm || p_buffer[3] != 0xbc ) return VLC_EGENERIC;

584
    i_length = (uint16_t)(p_buffer[4] << 8) + p_buffer[5] + 6;
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
    if( i_length > i_buffer ) return VLC_EGENERIC;

    //i_current_next_indicator = (p_buffer[6] && 0x01);
    i_version = (p_buffer[6] && 0xf8);

    if( p_psm->i_version == i_version ) return VLC_EGENERIC;

    ps_psm_destroy( p_psm );

    i_info_length = (uint16_t)(p_buffer[8] << 8) + p_buffer[9];
    if( i_info_length + 10 > i_length ) return VLC_EGENERIC;

    /* Elementary stream map */
    i_esm_length = (uint16_t)(p_buffer[ 10 + i_info_length ] << 8) +
        p_buffer[ 11 + i_info_length];
    i_es_base = 12 + i_info_length;

    while( i_es_base + 4 < i_length )
    {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
604
        ps_es_t **tmp_es;
605
        ps_es_t es;
606
        es.lang[0] = es.lang[1] = es.lang[2] = 0;
607
608
609
610
611
612
613
614

        es.i_type = p_buffer[ i_es_base  ];
        es.i_id = p_buffer[ i_es_base + 1 ];
        i_info_length = (uint16_t)(p_buffer[ i_es_base + 2 ] << 8) +
            p_buffer[ i_es_base + 3 ];

        if( i_es_base + 4 + i_info_length > i_length ) break;

615
616
617
618
619
        /* TODO Add support for VC-1 stream:
         *      stream_type=0xea, stream_id=0xfd AND registration
         *      descriptor 0x5 with format_identifier == 0x56432D31 (VC-1)
         *      (I need a sample that use PSM with VC-1) */

620
621
622
623
        es.p_descriptor = 0;
        es.i_descriptor = i_info_length;
        if( i_info_length > 0 )
        {
624
625
            int i = 0;

626
            es.p_descriptor = malloc( i_info_length );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
627
            if( es.p_descriptor )
628
            {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
629
                memcpy( es.p_descriptor, p_buffer + i_es_base + 4, i_info_length);
630

Jean-Paul Saman's avatar
Jean-Paul Saman committed
631
                while( i <= es.i_descriptor - 2 )
632
                {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
633
634
635
636
637
638
639
640
641
642
643
644
645
646
                    /* Look for the ISO639 language descriptor */
                    if( es.p_descriptor[i] != 0x0a )
                    {
                        i += es.p_descriptor[i+1] + 2;
                        continue;
                    }

                    if( i <= es.i_descriptor - 6 )
                    {
                        es.lang[0] = es.p_descriptor[i+2];
                        es.lang[1] = es.p_descriptor[i+3];
                        es.lang[2] = es.p_descriptor[i+4];
                    }
                    break;
647
648
                }
            }
649
650
        }

651
        tmp_es = realloc_or_free( p_psm->es, sizeof(ps_es_t *) * (p_psm->i_es+1) );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
652
653
654
655
656
657
658
659
660
661
        if( tmp_es )
        {
            p_psm->es = tmp_es;
            p_psm->es[p_psm->i_es] = malloc( sizeof(ps_es_t) );
            if( p_psm->es[p_psm->i_es] )
            {
                *p_psm->es[p_psm->i_es++] = es;
                i_es_base += 4 + i_info_length;
            }
        }
662
663
664
665
666
667
    }

    /* TODO: CRC */

    p_psm->i_version = i_version;

668
    /* Check/Modify our existing tracks */
Laurent Aimar's avatar
Laurent Aimar committed
669
    for( int i = 0; i < PS_TK_COUNT; i++ )
670
671
672
673
674
675
676
677
    {
        ps_track_t tk_tmp;

        if( !tk[i].b_seen || !tk[i].es ) continue;

        if( ps_track_fill( &tk_tmp, p_psm, tk[i].i_id ) != VLC_SUCCESS )
            continue;

678
679
680
681
682
        if( tk_tmp.fmt.i_codec == tk[i].fmt.i_codec )
        {
            es_format_Clean( &tk_tmp.fmt );
            continue;
        }
683
684

        es_out_Del( out, tk[i].es );
685
686
        es_format_Clean( &tk[i].fmt );

687
        tk[i] = tk_tmp;
688
        tk[i].b_seen = true;
689
690
691
        tk[i].es = es_out_Add( out, &tk[i].fmt );
    }

692
693
    return VLC_SUCCESS;
}