Coverage Report

Created: 2025-07-18 07:04

/src/vlc/modules/demux/mpeg/ps.h
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * ps.h: Program Stream demuxer helper
3
 *****************************************************************************
4
 * Copyright (C) 2004-2009 VLC authors and VideoLAN
5
 *
6
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7
 *
8
 * This program is free software; you can redistribute it and/or modify it
9
 * under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation; either version 2.1 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program; if not, write to the Free Software Foundation,
20
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21
 *****************************************************************************/
22
23
#include <assert.h>
24
#include <vlc_demux.h>
25
#include "timestamps.h"
26
27
0
#define PS_STREAM_ID_END_STREAM       0xB9
28
0
#define PS_STREAM_ID_PACK_HEADER      0xBA
29
0
#define PS_STREAM_ID_SYSTEM_HEADER    0xBB
30
31
/* 256-0xC0 for normal stream, 256 for 0xbd stream, 256 for 0xfd stream, 8 for 0xa0 AOB stream */
32
0
#define PS_TK_COUNT (256+256+256+8 - 0xc0)
33
static inline unsigned ps_id_to_tk( unsigned i_id )
34
0
{
35
0
    assert(i_id >= 0xc0);
36
0
    if(unlikely(i_id < 0xc0))
37
0
        return 0;
38
0
    else if( i_id <= 0xff )
39
0
        return i_id - 0xc0;
40
0
    else if( (i_id & 0xff00) == 0xbd00 )
41
0
        return 256-0xC0 + (i_id & 0xff);
42
0
    else if( (i_id & 0xff00) == 0xfd00 )
43
0
        return 512-0xc0 + (i_id & 0xff);
44
0
    else
45
0
        return 768-0xc0 + (i_id & 0x07);
46
0
}
47
48
typedef struct ps_psm_t ps_psm_t;
49
static inline uint8_t ps_id_to_type( const ps_psm_t *, uint16_t );
50
static inline const uint8_t *ps_id_to_lang( const ps_psm_t *, uint16_t );
51
52
typedef struct
53
{
54
    bool        b_configured;
55
    bool        b_updated;
56
    int         i_skip;
57
    int         i_id;
58
    int         i_next_block_flags;
59
    es_out_id_t *es;
60
    es_format_t fmt;
61
    vlc_tick_t  i_first_pts;
62
    vlc_tick_t  i_last_pts;
63
64
} ps_track_t;
65
66
/* Init a set of track */
67
static inline void ps_track_init( ps_track_t tk[PS_TK_COUNT] )
68
0
{
69
0
    int i;
70
0
    for( i = 0; i < PS_TK_COUNT; i++ )
71
0
    {
72
0
        tk[i].b_configured = false;
73
0
        tk[i].b_updated = false;
74
0
        tk[i].i_skip = 0;
75
0
        tk[i].i_id   = 0;
76
0
        tk[i].i_next_block_flags = 0;
77
0
        tk[i].es     = NULL;
78
0
        tk[i].i_first_pts = VLC_TICK_INVALID;
79
0
        tk[i].i_last_pts = VLC_TICK_INVALID;
80
0
        es_format_Init( &tk[i].fmt, UNKNOWN_ES, 0 );
81
0
    }
82
0
}
83
84
static inline bool ps_is_H264( const uint8_t *p_data, size_t i_data )
85
0
{
86
0
    const uint8_t startcode[3] = { 0, 0, 1 };
87
0
    int i_flags = 0;
88
89
0
    if( i_data < 9 ||
90
0
       (!memcmp( p_data, startcode, 3 ) &&
91
0
        !memcmp( &p_data[1], startcode, 3 )) )
92
0
        return false;
93
94
    /* Shitty H264 probing. We need a centralized way do to this */
95
0
    while( i_data > 5 )
96
0
    {
97
0
        if( !memcmp( p_data, startcode, 3 ) )
98
0
        {
99
0
            if(p_data[3] == 0x67)
100
0
                i_flags ^= 0x01;
101
0
            else if(p_data[3] == 0x68)
102
0
                i_flags ^= 0x02;
103
0
            else if( p_data[3] & 0x80 )
104
0
                return false;
105
0
            else if( (p_data[3] & 0x1F) > 23 || (p_data[3] & 0x1F) < 1 )
106
0
                return false;
107
0
            else if( (p_data[3] & 0x1F) < 6 )
108
0
                return (i_flags == 0x03);
109
0
        }
110
0
        p_data++;
111
0
        i_data--;
112
0
    }
113
114
0
    return false;
115
0
}
116
117
static inline bool ps_is_EAC3( const uint8_t *p_data, size_t i_data )
118
0
{
119
    /* AC-3 marking, see vlc_a52_header_Parse */
120
0
    if( i_data < 8 || p_data[0] != 0x0b || p_data[1] != 0x77 )
121
0
        return false;
122
0
    int bsid = p_data[5] >> 3;
123
0
    return bsid > 10 && bsid <= 16;
124
0
}
125
126
/* From id fill i_skip and es_format_t */
127
static inline int ps_track_fill( ps_track_t *tk, ps_psm_t *p_psm,
128
                                 int i_id,
129
                                 const uint8_t *p_pkt, size_t i_pkt,
130
                                 bool b_mpeg2only )
131
0
{
132
0
    tk->i_skip = 0;
133
0
    tk->i_id = i_id;
134
135
0
    if( ( i_id&0xff00 ) == 0xbd00 ) /* 0xBD00 -> 0xBDFF, Private Stream 1 */
136
0
    {
137
0
        if( ( i_id&0xf8 ) == 0x88 || /* 0x88 -> 0x8f - Can be DTS-HD primary audio in evob */
138
0
            ( i_id&0xf8 ) == 0x98 )  /* 0x98 -> 0x9f - Can be DTS-HD secondary audio in evob */
139
0
        {
140
0
            es_format_Change( &tk->fmt, AUDIO_ES, VLC_CODEC_DTS );
141
0
            tk->i_skip = 4;
142
0
        }
143
0
        else if( ( i_id&0xf8 ) == 0x80 || /* 0x80 -> 0x87 */
144
0
                 ( i_id&0xf0 ) == 0xc0 )  /* 0xc0 -> 0xcf AC-3, Can also be DD+/E-AC3 in evob */
145
0
        {
146
0
            bool b_eac3 = false;
147
0
            if( ( i_id&0xf0 ) == 0xc0 )
148
0
            {
149
0
                if( p_pkt == NULL || i_pkt < 9 )
150
0
                    return VLC_EGENERIC;
151
152
0
                unsigned i_start = 9 + p_pkt[8];
153
0
                if( i_start + 9 < i_pkt )
154
0
                    b_eac3 = ps_is_EAC3( &p_pkt[i_start + 4], i_pkt - i_start - 4 );
155
0
            }
156
157
0
            es_format_Change( &tk->fmt, AUDIO_ES, b_eac3 ? VLC_CODEC_EAC3 : VLC_CODEC_A52 );
158
0
            tk->i_skip = 4;
159
0
        }
160
0
        else if( ( i_id&0xfc ) == 0x00 ) /* 0x00 -> 0x03 */
161
0
        {
162
0
            es_format_Change( &tk->fmt, SPU_ES, VLC_CODEC_CVD );
163
0
        }
164
0
        else if( ( i_id&0xff ) == 0x0b ) /* 0x0b */
165
0
        {
166
0
            bool b_eac3 = i_pkt > 8 && ps_is_EAC3( &p_pkt[9], i_pkt - 9 );
167
0
            es_format_Change( &tk->fmt, AUDIO_ES, b_eac3 ? VLC_CODEC_EAC3 : VLC_CODEC_A52 );
168
0
        }
169
0
        else if( ( i_id&0xff ) == 0x10 ) /* 0x10 */
170
0
        {
171
0
            es_format_Change( &tk->fmt, SPU_ES, VLC_CODEC_TELETEXT );
172
0
        }
173
0
        else if( ( i_id&0xe0 ) == 0x20 ) /* 0x20 -> 0x3f */
174
0
        {
175
0
            es_format_Change( &tk->fmt, SPU_ES, VLC_CODEC_SPU );
176
0
            tk->i_skip = 1;
177
0
        }
178
0
        else if( ( i_id&0xff ) == 0x70 ) /* 0x70 */
179
0
        {
180
0
            es_format_Change( &tk->fmt, SPU_ES, VLC_CODEC_OGT );
181
0
        }
182
0
        else if( ( i_id&0xf0 ) == 0xa0 ) /* 0xa0 -> 0xaf */
183
0
        {
184
0
            es_format_Change( &tk->fmt, AUDIO_ES, VLC_CODEC_DVD_LPCM );
185
0
            tk->i_skip = 1;
186
0
        }
187
0
        else if( ( i_id&0xf0 ) == 0xb0 ) /* 0xb0 -> 0xbf */
188
0
        {
189
0
            es_format_Change( &tk->fmt, AUDIO_ES, VLC_CODEC_TRUEHD );
190
0
            tk->i_skip = 5;
191
0
        }
192
0
        else
193
0
        {
194
0
            es_format_Change( &tk->fmt, UNKNOWN_ES, 0 );
195
0
            return VLC_EGENERIC;
196
0
        }
197
0
    }
198
0
    else if( (i_id&0xff00) == 0xfd00 ) /* 0xFD00 -> 0xFDFF */
199
0
    {
200
0
        uint8_t i_sub_id = i_id & 0xff;
201
0
        if( ( i_sub_id >= 0x55 && i_sub_id <= 0x5f ) || /* Can be primary VC-1 in evob */
202
0
            ( i_sub_id >= 0x75 && i_sub_id <= 0x7f ) )  /* Secondary VC-1 */
203
0
        {
204
0
            es_format_Change( &tk->fmt, VIDEO_ES, VLC_CODEC_VC1 );
205
0
        }
206
0
        else
207
0
        {
208
0
            es_format_Change( &tk->fmt, UNKNOWN_ES, 0 );
209
0
            return VLC_EGENERIC;
210
0
        }
211
0
    }
212
0
    else if( (i_id&0xff00) == 0xa000 ) /* 0xA000 -> 0xA0FF */
213
0
    {
214
0
        uint8_t i_sub_id = i_id & 0x07;
215
0
        if( i_sub_id == 0 )
216
0
        {
217
0
            es_format_Change( &tk->fmt, AUDIO_ES, VLC_CODEC_DVDA_LPCM );
218
0
            tk->i_skip = 1;
219
0
        }
220
0
        else if( i_sub_id == 1 )
221
0
        {
222
0
            es_format_Change( &tk->fmt, AUDIO_ES, VLC_CODEC_MLP );
223
0
            tk->i_skip = -1; /* It's a hack for variable skip value */
224
0
        }
225
0
        else
226
0
        {
227
0
            es_format_Change( &tk->fmt, UNKNOWN_ES, 0 );
228
0
            return VLC_EGENERIC;
229
0
        }
230
0
    }
231
0
    else
232
0
    {
233
0
        int i_type = ps_id_to_type( p_psm , i_id );
234
235
0
        es_format_Change( &tk->fmt, UNKNOWN_ES, 0 );
236
237
0
        if( (i_id&0xf0) == 0xe0 ) /* 0xe0 -> 0xef */
238
0
        {
239
0
            if( i_type == 0x01 )
240
0
            {
241
0
                es_format_Change( &tk->fmt, VIDEO_ES, VLC_CODEC_MPGV );
242
0
                tk->fmt.i_original_fourcc = VLC_CODEC_MP1V;
243
0
            }
244
0
            else if( i_type == 0x02 )
245
0
            {
246
0
                es_format_Change( &tk->fmt, VIDEO_ES, VLC_CODEC_MPGV );
247
0
            }
248
0
            else if( i_type == 0x10 )
249
0
            {
250
0
                es_format_Change( &tk->fmt, VIDEO_ES, VLC_CODEC_MP4V );
251
0
            }
252
0
            else if( i_type == 0x1b )
253
0
            {
254
0
                es_format_Change( &tk->fmt, VIDEO_ES, VLC_CODEC_H264 );
255
0
            }
256
0
            else if( i_type == 0x24 )
257
0
            {
258
0
                es_format_Change( &tk->fmt, VIDEO_ES, VLC_CODEC_HEVC );
259
0
            }
260
0
            else if( i_id == 0xe2 || /* Primary H.264 in evob */
261
0
                     i_id == 0xe3 )  /* Secondary H.264 in evob */
262
0
            {
263
0
                es_format_Change( &tk->fmt, VIDEO_ES, VLC_CODEC_H264 );
264
0
            }
265
0
            else if( p_pkt && i_type == 0x00 && /* Not from PSM */
266
0
                     i_pkt > 9 + 5 &&
267
0
                     i_pkt > 9U + 5 + p_pkt[8] &&
268
0
                     ps_is_H264( &p_pkt[ 9 + p_pkt[8] ],
269
0
                                  i_pkt - 9 - p_pkt[8] ) )
270
0
            {
271
0
                es_format_Change( &tk->fmt, VIDEO_ES, VLC_CODEC_H264 );
272
0
            }
273
0
            else if( tk->fmt.i_cat == UNKNOWN_ES &&
274
0
                     ( p_pkt != NULL /* Not system */ || b_mpeg2only ) )
275
0
            {
276
0
                es_format_Change( &tk->fmt, VIDEO_ES, VLC_CODEC_MPGV );
277
0
            }
278
0
        }
279
0
        else if( ( i_id&0xe0 ) == 0xc0 ) /* 0xc0 -> 0xdf */
280
0
        {
281
0
            if( i_type == 0x03 ||
282
0
                i_type == 0x04 )
283
0
            {
284
0
                es_format_Change( &tk->fmt, AUDIO_ES, VLC_CODEC_MPGA );
285
0
            }
286
0
            else if( i_type == 0x0f )
287
0
            {
288
0
                es_format_Change( &tk->fmt, AUDIO_ES, VLC_CODEC_MP4A );
289
0
                tk->fmt.i_original_fourcc = VLC_FOURCC('A','D','T','S');
290
0
            }
291
0
            else if( i_type == 0x11 )
292
0
            {
293
0
                es_format_Change( &tk->fmt, AUDIO_ES, VLC_CODEC_MP4A );
294
0
                tk->fmt.i_original_fourcc = VLC_FOURCC('L','A','T','M');
295
0
            }
296
0
            else if( i_type == 0x2d )
297
0
            {
298
0
                es_format_Change( &tk->fmt, AUDIO_ES, VLC_CODEC_MPEGH );
299
0
            }
300
0
            else if( tk->fmt.i_cat == UNKNOWN_ES )
301
0
            {
302
0
                es_format_Change( &tk->fmt, AUDIO_ES, VLC_CODEC_MPGA );
303
0
            }
304
0
        }
305
0
        else if( tk->fmt.i_cat == UNKNOWN_ES ) return VLC_EGENERIC;
306
0
    }
307
308
    /* PES packets usually contain truncated frames */
309
0
    tk->fmt.b_packetized = false;
310
0
    tk->fmt.i_priority = ~i_id & 0x0F;
311
312
0
    if( ps_id_to_lang( p_psm, i_id ) )
313
0
    {
314
0
        tk->fmt.psz_language = malloc( 4 );
315
0
        if( tk->fmt.psz_language )
316
0
        {
317
0
            memcpy( tk->fmt.psz_language, ps_id_to_lang( p_psm , i_id ), 3 );
318
0
            tk->fmt.psz_language[3] = 0;
319
0
        }
320
0
    }
321
322
0
    return (tk->fmt.i_cat != UNKNOWN_ES || p_pkt) ? VLC_SUCCESS : VLC_EGENERIC;
323
0
}
324
325
/* return the id of a PES (should be valid) */
326
static inline int ps_pkt_id( const uint8_t *p_pkt, size_t i_pkt )
327
0
{
328
0
    if(unlikely(i_pkt < 4))
329
0
        return 0;
330
0
    if( p_pkt[3] == 0xbd )
331
0
    {
332
0
        uint8_t i_sub_id = 0;
333
0
        if( i_pkt >= 9 &&
334
0
            i_pkt > 9 + (size_t)p_pkt[8] )
335
0
        {
336
0
            const unsigned i_start = 9 + p_pkt[8];
337
0
            i_sub_id = p_pkt[i_start];
338
339
0
            if( (i_sub_id & 0xfe) == 0xa0 &&
340
0
                i_pkt >= i_start + 7 &&
341
0
                ( p_pkt[i_start + 5] >=  0xc0 ||
342
0
                  p_pkt[i_start + 6] != 0x80 ) )
343
0
            {
344
                /* AOB LPCM/MLP extension
345
                * XXX for MLP I think that the !=0x80 test is not good and
346
                * will fail for some valid files */
347
0
                return 0xa000 | (i_sub_id & 0x01);
348
0
            }
349
0
        }
350
351
        /* VOB extension */
352
0
        return 0xbd00 | i_sub_id;
353
0
    }
354
0
    else if( i_pkt >= 9 &&
355
0
             p_pkt[3] == 0xfd &&
356
0
             (p_pkt[6]&0xC0) == 0x80 &&   /* mpeg2 */
357
0
             (p_pkt[7]&0x01) == 0x01 )    /* extension_flag */
358
0
    {
359
        /* ISO 13818 amendment 2 and SMPTE RP 227 */
360
0
        const uint8_t i_flags = p_pkt[7];
361
0
        unsigned int i_skip = 9;
362
363
        /* Find PES extension */
364
0
        if( (i_flags & 0x80 ) )
365
0
        {
366
0
            i_skip += 5;        /* pts */
367
0
            if( (i_flags & 0x40) )
368
0
                i_skip += 5;    /* dts */
369
0
        }
370
0
        if( (i_flags & 0x20 ) )
371
0
            i_skip += 6;
372
0
        if( (i_flags & 0x10 ) )
373
0
            i_skip += 3;
374
0
        if( (i_flags & 0x08 ) )
375
0
            i_skip += 1;
376
0
        if( (i_flags & 0x04 ) )
377
0
            i_skip += 1;
378
0
        if( (i_flags & 0x02 ) )
379
0
            i_skip += 2;
380
381
0
        if( i_skip < i_pkt && (p_pkt[i_skip]&0x01) )
382
0
        {
383
0
            const uint8_t i_flags2 = p_pkt[i_skip];
384
385
            /* Find PES extension 2 */
386
0
            i_skip += 1;
387
0
            if( i_flags2 & 0x80 )
388
0
                i_skip += 16;
389
0
            if( (i_flags2 & 0x40) && i_skip < i_pkt )
390
0
                i_skip += 1 + p_pkt[i_skip];
391
0
            if( i_flags2 & 0x20 )
392
0
                i_skip += 2;
393
0
            if( i_flags2 & 0x10 )
394
0
                i_skip += 2;
395
396
0
            if( i_skip + 1 < i_pkt )
397
0
            {
398
0
                const int i_extension_field_length = p_pkt[i_skip]&0x7f;
399
0
                if( i_extension_field_length >=1 )
400
0
                {
401
0
                    int i_stream_id_extension_flag = (p_pkt[i_skip+1] >> 7)&0x1;
402
0
                    if( i_stream_id_extension_flag == 0 )
403
0
                        return 0xfd00 | (p_pkt[i_skip+1]&0x7f);
404
0
                }
405
0
            }
406
0
        }
407
0
    }
408
0
    return p_pkt[3];
409
0
}
410
411
/* return the size of the next packet */
412
static inline int ps_pkt_size( const uint8_t *p, int i_peek )
413
0
{
414
0
    if( unlikely(i_peek < 4) )
415
0
        return -1;
416
417
0
    switch( p[3] )
418
0
    {
419
0
        case PS_STREAM_ID_END_STREAM:
420
0
            return 4;
421
422
0
        case PS_STREAM_ID_PACK_HEADER:
423
0
            if( i_peek > 4 )
424
0
            {
425
0
                if( i_peek >= 14 && (p[4] >> 6) == 0x01 )
426
0
                    return 14 + (p[13]&0x07);
427
0
                else if( i_peek >= 12 && (p[4] >> 4) == 0x02 )
428
0
                    return 12;
429
0
            }
430
0
            break;
431
432
0
        case PS_STREAM_ID_SYSTEM_HEADER:
433
0
        case STREAM_ID_PROGRAM_STREAM_MAP:
434
0
        case STREAM_ID_PROGRAM_STREAM_DIRECTORY:
435
0
        default:
436
0
            if( i_peek >= 6 )
437
0
                return 6 + ((p[4]<<8) | p[5] );
438
0
    }
439
0
    return -1;
440
0
}
441
442
/* parse a PACK PES */
443
static inline int ps_pkt_parse_pack( const uint8_t *p_pkt, size_t i_pkt,
444
                                     vlc_tick_t *pi_scr, int *pi_mux_rate )
445
0
{
446
0
    const uint8_t *p = p_pkt;
447
0
    ts_90khz_t i_scr;
448
0
    if( i_pkt >= 14 && (p[4] >> 6) == 0x01 ) /* 0b01 H.222 MPEG-2 Pack Header */
449
0
    {
450
0
        i_scr = ExtractPackHeaderTimestamp( &p[4] );
451
0
        *pi_mux_rate = ( p[10] << 14 )|( p[11] << 6 )|( p[12] >> 2);
452
0
    }
453
0
    else if( i_pkt >= 12 && (p[4] >> 4) == 0x02 ) /* 0b0010 ISO 11172-1 MPEG-1 Pack Header */
454
0
    {
455
0
        if(!ExtractPESTimestamp( &p[4], 0x02, &i_scr )) /* same bits as PES/PTS */
456
0
            return VLC_EGENERIC;
457
0
        *pi_mux_rate = ( ( p[9]&0x7f )<< 15 )|( p[10] << 7 )|( p[11] >> 1);
458
0
    }
459
0
    else
460
0
    {
461
0
        return VLC_EGENERIC;
462
0
    }
463
0
    *pi_scr = FROM_SCALE( i_scr );
464
0
    return VLC_SUCCESS;
465
0
}
466
467
/* Parse a SYSTEM PES */
468
static inline int ps_pkt_parse_system( const uint8_t *p_pkt, size_t i_pkt,
469
                                       ps_psm_t *p_psm,
470
                                       ps_track_t tk[PS_TK_COUNT] )
471
0
{
472
0
    const uint8_t *p = &p_pkt[6 + 3 + 1 + 1 + 1];
473
0
    const uint8_t *p_pktend = &p_pkt[i_pkt];
474
475
    /* System header is not usable if it references private streams (0xBD)
476
     * or 'all audio streams' (0xB8) or 'all video streams' (0xB9) */
477
0
    while( p < p_pktend && (p[0] & 0x80) )
478
0
    {
479
0
        int i_id = p[0];
480
0
        switch( i_id )
481
0
        {
482
0
            case 0xB7:
483
0
                if( p_pktend - p < 6 )
484
0
                    return VLC_EGENERIC;
485
0
                i_id = ((int)STREAM_ID_EXTENDED_STREAM_ID << 8) | (p[2] & 0x7F);
486
0
                p += 6;
487
0
                break;
488
0
            default:
489
0
                if( p_pktend - p < 3 )
490
0
                    return VLC_EGENERIC;
491
0
                p += 3;
492
0
                break;
493
0
        }
494
495
0
        if( i_id < 0xc0 )
496
0
            continue;
497
498
0
        unsigned i_tk = ps_id_to_tk( i_id );
499
0
        if( !tk[i_tk].b_configured )
500
0
            ps_track_fill( &tk[i_tk], p_psm, i_id, NULL, 0, false );
501
0
    }
502
0
    return VLC_SUCCESS;
503
0
}
504
505
/* Parse a PES (and skip i_skip_extra in the payload) */
506
static inline int ps_pkt_parse_pes( vlc_object_t *p_object, block_t *p_pes, int i_skip_extra )
507
0
{
508
0
    unsigned int i_skip;
509
0
    ts_pes_header_t pesh;
510
0
    ts_pes_header_init( &pesh );
511
512
0
    if( ParsePESHeader( p_object->logger, p_pes->p_buffer, p_pes->i_buffer, &pesh ) != VLC_SUCCESS )
513
0
        return VLC_EGENERIC;
514
515
0
    i_skip = pesh.i_size;
516
517
0
    if( pesh.b_scrambling )
518
0
        p_pes->i_flags |= BLOCK_FLAG_SCRAMBLED;
519
520
0
    if( i_skip_extra >= 0 )
521
0
        i_skip += i_skip_extra;
522
0
    else if( p_pes->i_buffer > i_skip + 3 &&
523
0
             ( ps_pkt_id( p_pes->p_buffer, p_pes->i_buffer ) == 0xa001 ||
524
0
               ps_pkt_id( p_pes->p_buffer, p_pes->i_buffer ) == 0xbda1 ) )
525
0
        i_skip += 4 + p_pes->p_buffer[i_skip+3];
526
527
0
    if( p_pes->i_buffer <= i_skip )
528
0
    {
529
0
        return VLC_EGENERIC;
530
0
    }
531
532
0
    p_pes->p_buffer += i_skip;
533
0
    p_pes->i_buffer -= i_skip;
534
535
0
    if( pesh.i_pts != TS_90KHZ_INVALID )
536
0
    {
537
0
        p_pes->i_pts = FROM_SCALE( pesh.i_pts );
538
0
        if( pesh.i_dts != TS_90KHZ_INVALID )
539
0
            p_pes->i_dts = FROM_SCALE( pesh.i_dts );
540
0
        else /* ISO/IEC 13818-1 2.7.5: if pts and no dts, then dts == pts */
541
0
            p_pes->i_dts = p_pes->i_pts;
542
0
    }
543
544
0
    return VLC_SUCCESS;
545
0
}
546
547
typedef struct
548
{
549
    /* Language is iso639-2T */
550
    uint8_t lang[3];
551
} ps_descriptors_t;
552
553
/* Program stream map handling */
554
typedef struct ps_es_t
555
{
556
    uint8_t i_type;
557
    uint16_t i_id;
558
559
    ps_descriptors_t desc;
560
561
} ps_es_t;
562
563
struct ps_psm_t
564
{
565
    uint8_t i_version;
566
567
    size_t  i_es;
568
    ps_es_t *es;
569
570
    ps_descriptors_t uniqueextdesc;
571
};
572
573
static inline uint8_t ps_id_to_type( const ps_psm_t *p_psm, uint16_t i_id )
574
0
{
575
0
    size_t i;
576
0
    for( i = 0; p_psm && i < p_psm->i_es; i++ )
577
0
    {
578
0
        if( p_psm->es[i].i_id == i_id ) return p_psm->es[i].i_type;
579
0
    }
580
0
    return 0;
581
0
}
582
583
static inline const uint8_t *ps_id_to_lang( const ps_psm_t *p_psm, uint16_t i_id )
584
0
{
585
0
    size_t i;
586
0
    for( i = 0; p_psm && i < p_psm->i_es; i++ )
587
0
    {
588
0
        if( p_psm->es[i].i_id == i_id )
589
0
            return p_psm->es[i].desc.lang;
590
0
    }
591
0
    return 0;
592
0
}
593
594
static inline void ps_psm_init( ps_psm_t *p_psm )
595
0
{
596
0
    p_psm->i_version = 0xFF;
597
0
    p_psm->i_es = 0;
598
0
    p_psm->es = 0;
599
0
    memset( &p_psm->uniqueextdesc, 0, 3 );
600
0
}
601
602
static inline void ps_psm_destroy( ps_psm_t *p_psm )
603
0
{
604
0
    free( p_psm->es );
605
0
    p_psm->es = NULL;
606
0
    p_psm->i_es = 0;
607
0
}
608
609
static inline void ps_parse_descriptors( const uint8_t *p_data, size_t i_data,
610
                                        ps_descriptors_t *p_desc )
611
0
{
612
0
    while( i_data > 3 && i_data > 2u + p_data[1] )
613
0
    {
614
0
        switch( p_data[0] )
615
0
        {
616
0
            case 0x0A: /* ISO_639_language_descriptor */
617
0
                if( i_data >= 6 )
618
0
                    memcpy( p_desc->lang, &p_data[2], 3 );
619
0
                break;
620
621
0
            default:
622
0
                break;
623
0
        }
624
0
        uint8_t i_desc_size = p_data[1];
625
0
        p_data += 2 + i_desc_size;
626
0
        i_data -= 2 + i_desc_size;
627
0
    }
628
0
}
629
630
static inline int ps_psm_fill( ps_psm_t *p_psm,
631
                               const uint8_t *p_buffer, size_t i_pkt,
632
                               ps_track_t tk[PS_TK_COUNT])
633
0
{
634
0
    size_t i_length, i_info_length, i_es_base;
635
0
    uint8_t i_version;
636
0
    bool b_single_extension;
637
638
    // Demux() checks that we have at least 4 bytes, but we need
639
    // at least 10 to read up to the info_length field
640
0
    assert(i_pkt >= 4);
641
0
    if( !p_psm || i_pkt < 10 || p_buffer[3] != STREAM_ID_PROGRAM_STREAM_MAP)
642
0
        return VLC_EGENERIC;
643
644
0
    i_length = GetWBE(&p_buffer[4]) + 6;
645
0
    if( i_length > i_pkt ) return VLC_EGENERIC;
646
647
0
    if((p_buffer[6] & 0x80) == 0) /* current_next_indicator */
648
0
        return VLC_EGENERIC;
649
650
0
    b_single_extension = p_buffer[6] & 0x40;
651
0
    i_version = (p_buffer[6] & 0xf8);
652
653
0
    if( p_psm->i_version == i_version ) return VLC_EGENERIC;
654
655
0
    ps_psm_destroy( p_psm );
656
657
0
    i_info_length = GetWBE(&p_buffer[8]);
658
0
    if( i_info_length + 10 > i_length )
659
0
        return VLC_EGENERIC;
660
661
    /* Elementary stream map */
662
    /* int i_esm_length = (uint16_t)(p_buffer[ 10 + i_info_length ] << 8) +
663
        p_buffer[ 11 + i_info_length]; */
664
0
    i_es_base = 12 + i_info_length;
665
666
0
    while( i_es_base + 4 < i_length )
667
0
    {
668
0
        ps_es_t *tmp_es = realloc( p_psm->es, sizeof(ps_es_t) * (p_psm->i_es+1) );
669
0
        if( tmp_es == NULL )
670
0
            break;
671
0
        p_psm->es = tmp_es;
672
673
0
        ps_es_t *p_es = &p_psm->es[ p_psm->i_es++ ];
674
0
        p_es->i_type = p_buffer[ i_es_base  ];
675
0
        p_es->i_id = p_buffer[ i_es_base + 1 ];
676
677
0
        i_info_length = GetWBE(&p_buffer[ i_es_base + 2 ]);
678
679
0
        if( i_es_base + 4 + i_info_length > i_length )
680
0
            break;
681
682
        /* TODO Add support for VC-1 stream:
683
         *      stream_type=0xea, stream_id=0xfd AND registration
684
         *      descriptor 0x5 with format_identifier == 0x56432D31 (VC-1)
685
         *      (I need a sample that use PSM with VC-1) */
686
687
0
        if( p_es->i_id == STREAM_ID_EXTENDED_STREAM_ID && b_single_extension == 0 )
688
0
        {
689
0
            if( i_info_length < 3 )
690
0
                break;
691
0
            p_es->i_id = (p_es->i_id << 8) | (p_buffer[i_es_base + 6] & 0x7F);
692
0
            ps_parse_descriptors( &p_buffer[i_es_base + 4 + 3],
693
0
                                  i_info_length - 3,
694
0
                                  &p_psm->uniqueextdesc );
695
0
        }
696
0
        else
697
0
        {
698
0
            ps_parse_descriptors( &p_buffer[i_es_base + 4],
699
0
                                  i_info_length, &p_es->desc );
700
0
        }
701
702
0
        i_es_base += 4 + i_info_length;
703
0
    }
704
705
    /* TODO: CRC */
706
707
0
    p_psm->i_version = i_version;
708
709
    /* Check/Modify our existing tracks */
710
0
    for( int i = 0; i < PS_TK_COUNT; i++ )
711
0
    {
712
0
        if( !tk[i].b_configured )
713
0
            continue;
714
715
0
        ps_track_t tk_tmp;
716
0
        es_format_Init( &tk_tmp.fmt, UNKNOWN_ES, 0 );
717
718
0
        if( ps_track_fill( &tk_tmp, p_psm, tk[i].i_id,
719
0
                           p_buffer, i_pkt, false ) != VLC_SUCCESS )
720
0
            continue;
721
722
0
        if( tk_tmp.fmt.i_codec == tk[i].fmt.i_codec )
723
0
        {
724
0
            es_format_Clean( &tk_tmp.fmt );
725
0
            continue;
726
0
        }
727
728
        /* replace with new version */
729
0
        tk_tmp.b_configured = true;
730
0
        tk_tmp.b_updated = true;
731
0
        tk_tmp.es = tk[i].es;
732
0
        es_format_Clean( &tk[i].fmt );
733
0
        tk[i] = tk_tmp;
734
0
    }
735
736
0
    return VLC_SUCCESS;
737
0
}