Coverage Report

Created: 2025-11-24 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/demux/mpeg/ps.c
Line
Count
Source
1
/*****************************************************************************
2
 * ps.c: Program Stream demux module for VLC.
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
/*****************************************************************************
24
 * Preamble
25
 *****************************************************************************/
26
27
#ifdef HAVE_CONFIG_H
28
# include "config.h"
29
#endif
30
31
#include <vlc_common.h>
32
#include <vlc_plugin.h>
33
#include <vlc_demux.h>
34
35
#include "pes.h"
36
#include "ps.h"
37
38
/* TODO:
39
 *  - re-add pre-scanning.
40
 *  - ...
41
 */
42
43
#define TIME_TEXT N_("Trust MPEG timestamps")
44
#define TIME_LONGTEXT N_("Normally we use the timestamps of the MPEG files " \
45
    "to calculate position and duration. However sometimes this might not " \
46
    "be usable. Disable this option to calculate from the bitrate instead." )
47
48
719
#define PS_PACKET_PROBE 3
49
1
#define CDXA_HEADER_SIZE 44
50
0
#define CDXA_SECTOR_SIZE 2352
51
0
#define CDXA_SECTOR_HEADER_SIZE 24
52
53
/*****************************************************************************
54
 * Module descriptor
55
 *****************************************************************************/
56
static int  OpenForce( vlc_object_t * );
57
static int  Open   ( vlc_object_t * );
58
static void Close  ( vlc_object_t * );
59
60
108
vlc_module_begin ()
61
54
    set_description( N_("MPEG-PS demuxer") )
62
54
    set_shortname( N_("PS") )
63
54
    set_subcategory( SUBCAT_INPUT_DEMUX )
64
54
    set_capability( "demux", 1 )
65
108
    set_callbacks( OpenForce, Close )
66
54
    add_shortcut( "ps" )
67
68
54
    add_bool( "ps-trust-timestamps", true, TIME_TEXT,
69
54
                 TIME_LONGTEXT )
70
54
        change_safe ()
71
72
54
    add_submodule ()
73
54
    set_description( N_("MPEG-PS demuxer") )
74
54
    set_capability( "demux", 9 )
75
108
    set_callbacks( Open, Close )
76
54
    add_shortcut( "ps" )
77
54
vlc_module_end ()
78
79
/*****************************************************************************
80
 * Local prototypes
81
 *****************************************************************************/
82
83
typedef struct
84
{
85
    ps_psm_t    psm;
86
    ps_track_t  tk[PS_TK_COUNT];
87
88
    vlc_tick_t  i_pack_scr; /* current read pack scr value, temp */
89
    vlc_tick_t  i_first_scr; /* media offset */
90
    vlc_tick_t  i_scr; /* committed, current position */
91
    int64_t     i_scr_track_id;
92
    int         i_mux_rate;
93
    vlc_tick_t  i_length;
94
    int         i_time_track_index;
95
    vlc_tick_t  i_current_pts;
96
    uint64_t    i_start_byte;
97
    uint64_t    i_lastpack_byte;
98
99
    int         i_aob_mlp_count;
100
101
    bool  b_lost_sync;
102
    bool  b_have_pack;
103
    bool  b_bad_scr;
104
    bool  b_seekable;
105
    enum
106
    {
107
        MPEG_PS = 0,
108
        CDXA_PS,
109
        PSMF_PS,
110
        IMKH_PS,
111
    } format;
112
    enum ps_source source;
113
114
    int         current_title;
115
    int         current_seekpoint;
116
    unsigned    updates;
117
} demux_sys_t;
118
119
static int Demux  ( demux_t *p_demux );
120
static int Control( demux_t *p_demux, int i_query, va_list args );
121
122
static int      ps_pkt_resynch( stream_t *, int, bool );
123
static block_t *ps_pkt_read   ( stream_t * );
124
125
static void CreateOrUpdateES( demux_t*p_demux )
126
9.52k
{
127
9.52k
    demux_sys_t *p_sys = p_demux->p_sys;
128
129
5.56M
    for( int i = 0; i < PS_TK_COUNT; i++ )
130
5.55M
    {
131
5.55M
        ps_track_t *tk = &p_sys->tk[i];
132
5.55M
        if( !tk->b_updated )
133
5.54M
            continue;
134
135
9.68k
        if( tk->es )
136
7.96k
            es_out_Del( p_demux->out, tk->es );
137
138
9.68k
        if( tk->fmt.i_cat != UNKNOWN_ES )
139
9.68k
            tk->es = es_out_Add( p_demux->out, &tk->fmt );
140
9.68k
        tk->b_updated = false;
141
9.68k
    }
142
9.52k
}
143
144
/*****************************************************************************
145
 * Open
146
 *****************************************************************************/
147
static int OpenCommon( vlc_object_t *p_this, bool b_force )
148
719
{
149
719
    demux_t     *p_demux = (demux_t*)p_this;
150
719
    demux_sys_t *p_sys;
151
152
719
    const uint8_t *p_peek;
153
719
    ssize_t i_peek = 0;
154
719
    ssize_t i_offset = 0;
155
719
    int i_skip = 0;
156
719
    unsigned i_max_packets = PS_PACKET_PROBE;
157
719
    int format = MPEG_PS;
158
719
    int i_mux_rate = 0;
159
719
    vlc_tick_t i_length = VLC_TICK_INVALID;
160
161
719
    i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 16 );
162
719
    if( i_peek < 16 )
163
0
        return VLC_EGENERIC;
164
165
719
    if( !memcmp( p_peek, "PSMF", 4 ) &&
166
0
        (GetDWBE( &p_peek[4] ) & 0x30303030) == 0x30303030 )
167
0
    {
168
0
        i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 100 );
169
0
        if( i_peek < 100 )
170
0
            return VLC_EGENERIC;
171
0
        i_skip = i_offset = GetWBE( &p_peek[10] );
172
0
        format = PSMF_PS;
173
0
        msg_Info( p_demux, "Detected PSMF-PS header");
174
0
        i_mux_rate = GetDWBE( &p_peek[96] );
175
0
        if( GetDWBE( &p_peek[86] ) > 0 )
176
0
            i_length = vlc_tick_from_samples( GetDWBE( &p_peek[92] ), GetDWBE( &p_peek[86] ));
177
0
    }
178
719
    else if( !memcmp( p_peek, "IMKH", 4 ) )
179
2
    {
180
2
        msg_Info( p_demux, "Detected Hikvision PVA header");
181
2
        i_skip = 40;
182
2
        format = IMKH_PS;
183
2
        i_max_packets = 0;
184
2
    }
185
717
    else if( !memcmp( p_peek, "RIFF", 4 ) && !memcmp( &p_peek[8], "CDXA", 4 ) )
186
1
    {
187
1
        format = CDXA_PS;
188
1
        i_max_packets = 0; /* We can't probe here */
189
1
        i_skip = CDXA_HEADER_SIZE;
190
1
        msg_Info( p_demux, "Detected CDXA-PS" );
191
        /* FIXME: have a proper way to decap CD sectors or make an access stream filter */
192
1
    }
193
716
    else if( b_force )
194
351
    {
195
351
        msg_Warn( p_demux, "this does not look like an MPEG PS stream, "
196
351
                  "continuing anyway" );
197
351
        i_max_packets = 0;
198
351
    }
199
200
723
    for( unsigned i=0; i<i_max_packets; i++ )
201
369
    {
202
369
        if( i_peek < i_offset + 16 )
203
4
        {
204
4
            i_peek = vlc_stream_Peek( p_demux->s, &p_peek, i_offset + 16 );
205
4
            if( i_peek < i_offset + 16 )
206
2
                return VLC_EGENERIC;
207
4
        }
208
209
367
        const uint8_t startcode[3] = { 0x00, 0x00, 0x01 };
210
367
        const uint8_t *p_header = &p_peek[i_offset];
211
367
        if( memcmp( p_header, startcode, 3 ) ||
212
8
           ( (p_header[3] & 0xB0) != 0xB0 &&
213
1
            !(p_header[3] >= 0xC0 && p_header[3] <= 0xEF) &&
214
1
              p_header[3] != STREAM_ID_EXTENDED_STREAM_ID &&
215
1
              p_header[3] != STREAM_ID_PROGRAM_STREAM_DIRECTORY ) )
216
360
            return VLC_EGENERIC;
217
218
7
        ssize_t i_pessize = ps_pkt_size( p_header, 16 );
219
7
        if( i_pessize < 5 )
220
3
            return VLC_EGENERIC;
221
4
        i_offset += i_pessize;
222
4
    }
223
224
354
    if( i_skip && !p_demux->b_preparsing &&
225
3
        vlc_stream_Read( p_demux->s, NULL, i_skip ) != i_skip )
226
0
        return VLC_EGENERIC;
227
228
    /* Fill p_demux field */
229
354
    p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
230
354
    if( !p_sys ) return VLC_ENOMEM;
231
232
354
    p_demux->pf_demux = Demux;
233
354
    p_demux->pf_control = Control;
234
235
    /* Init p_sys */
236
354
    p_sys->i_mux_rate = i_mux_rate;
237
354
    p_sys->i_pack_scr  = VLC_TICK_INVALID;
238
354
    p_sys->i_first_scr = VLC_TICK_INVALID;
239
354
    p_sys->i_scr = VLC_TICK_INVALID;
240
354
    p_sys->i_scr_track_id = 0;
241
354
    p_sys->i_length   = i_length;
242
354
    p_sys->i_current_pts = VLC_TICK_INVALID;
243
354
    p_sys->i_time_track_index = -1;
244
354
    p_sys->i_aob_mlp_count = 0;
245
354
    p_sys->i_start_byte = i_skip;
246
354
    p_sys->i_lastpack_byte = i_skip;
247
248
354
    p_sys->b_lost_sync = false;
249
354
    p_sys->b_have_pack = false;
250
354
    p_sys->b_bad_scr   = false;
251
354
    p_sys->b_seekable  = false;
252
354
    p_sys->format      = format;
253
354
    p_sys->current_title = 0;
254
354
    p_sys->current_seekpoint = 0;
255
354
    p_sys->updates = 0;
256
257
354
    p_sys->source = PS_SOURCE_UNKNOWN;
258
354
    if ( likely(p_demux->s->psz_url != NULL) )
259
0
    {
260
0
        size_t url_len = strlen( p_demux->s->psz_url );
261
0
        if ( url_len >= 4 )
262
0
        {
263
0
            if ( !strncasecmp( &p_demux->s->psz_url[url_len-4], ".AOB", 4 ))
264
0
                p_sys->source = PS_SOURCE_AOB;
265
0
            if ( !strncasecmp( &p_demux->s->psz_url[url_len-4], ".VOB", 4 ))
266
0
                p_sys->source = PS_SOURCE_VOB;
267
0
        }
268
0
    }
269
270
354
    vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &p_sys->b_seekable );
271
272
354
    ps_psm_init( &p_sys->psm );
273
354
    ps_track_init( p_sys->tk );
274
275
    /* TODO prescanning of ES */
276
277
354
    return VLC_SUCCESS;
278
354
}
279
280
static int OpenForce( vlc_object_t *p_this )
281
351
{
282
351
    return OpenCommon( p_this, true );
283
351
}
284
285
static int Open( vlc_object_t *p_this )
286
368
{
287
368
    return OpenCommon( p_this, p_this->force );
288
368
}
289
290
/*****************************************************************************
291
 * Close
292
 *****************************************************************************/
293
static void Close( vlc_object_t *p_this )
294
354
{
295
354
    demux_t     *p_demux = (demux_t*)p_this;
296
354
    demux_sys_t *p_sys = p_demux->p_sys;
297
354
    int i;
298
299
207k
    for( i = 0; i < PS_TK_COUNT; i++ )
300
206k
    {
301
206k
        ps_track_t *tk = &p_sys->tk[i];
302
206k
        es_format_Clean( &tk->fmt );
303
206k
        if( tk->b_configured && tk->es != NULL )
304
1.72k
            es_out_Del( p_demux->out, tk->es );
305
206k
    }
306
307
354
    ps_psm_destroy( &p_sys->psm );
308
309
354
    free( p_sys );
310
354
}
311
312
static int Probe( demux_t *p_demux, bool b_end )
313
74.0k
{
314
74.0k
    demux_sys_t *p_sys = p_demux->p_sys;
315
74.0k
    int i_ret, i_id;
316
74.0k
    block_t *p_pkt;
317
318
74.0k
    i_ret = ps_pkt_resynch( p_demux->s, p_sys->format, p_sys->b_have_pack );
319
74.0k
    if( i_ret < 0 )
320
263
    {
321
263
        return VLC_DEMUXER_EOF;
322
263
    }
323
73.7k
    else if( i_ret == 0 )
324
14.1k
    {
325
14.1k
        if( !p_sys->b_lost_sync )
326
14.1k
            msg_Warn( p_demux, "garbage at input, trying to resync..." );
327
328
14.1k
        p_sys->b_lost_sync = true;
329
14.1k
        return VLC_DEMUXER_SUCCESS;
330
14.1k
    }
331
332
59.5k
    if( p_sys->b_lost_sync ) msg_Warn( p_demux, "found sync code" );
333
59.5k
    p_sys->b_lost_sync = false;
334
335
59.5k
    if( ( p_pkt = ps_pkt_read( p_demux->s ) ) == NULL )
336
61
    {
337
61
        return VLC_DEMUXER_EOF;
338
61
    }
339
340
59.4k
    i_id = ps_pkt_id( p_pkt->p_buffer, p_pkt->i_buffer, p_sys->source );
341
59.4k
    if( i_id >= 0xc0 )
342
47.0k
    {
343
47.0k
        ps_track_t *tk = &p_sys->tk[ps_id_to_tk(i_id)];
344
47.0k
        if( !ps_pkt_parse_pes( VLC_OBJECT(p_demux), p_pkt, tk->i_skip ) &&
345
30.3k
             p_pkt->i_pts != VLC_TICK_INVALID )
346
12.7k
        {
347
12.7k
            if( b_end && (tk->i_last_pts == VLC_TICK_INVALID || p_pkt->i_pts > tk->i_last_pts) )
348
659
            {
349
659
                tk->i_last_pts = p_pkt->i_pts;
350
659
            }
351
12.1k
            else if ( tk->i_first_pts == VLC_TICK_INVALID )
352
557
            {
353
557
                tk->i_first_pts = p_pkt->i_pts;
354
557
            }
355
12.7k
        }
356
47.0k
    }
357
12.4k
    else if( i_id == PS_STREAM_ID_PACK_HEADER )
358
522
    {
359
522
        vlc_tick_t i_scr; int dummy;
360
522
        if( !b_end && !ps_pkt_parse_pack( p_pkt->p_buffer, p_pkt->i_buffer,
361
148
                                          &i_scr, &dummy ) )
362
117
        {
363
117
            if( p_sys->i_first_scr == VLC_TICK_INVALID )
364
16
                p_sys->i_first_scr = i_scr;
365
117
        }
366
522
        p_sys->b_have_pack = true;
367
522
    }
368
369
59.4k
    block_Release( p_pkt );
370
59.4k
    return VLC_DEMUXER_SUCCESS;
371
59.5k
}
372
373
static bool FindLength( demux_t *p_demux )
374
321
{
375
321
    demux_sys_t *p_sys = p_demux->p_sys;
376
377
321
    if( !var_CreateGetBool( p_demux, "ps-trust-timestamps" ) )
378
0
        return true;
379
380
321
    if( p_sys->i_length == VLC_TICK_INVALID ) /* First time */
381
321
    {
382
321
        p_sys->i_length = VLC_TICK_0;
383
        /* Check beginning */
384
321
        int i = 0;
385
321
        uint64_t i_current_pos = vlc_stream_Tell( p_demux->s );
386
11.2k
        while( i < 40 && Probe( p_demux, false ) > 0 ) i++;
387
388
        /* Check end */
389
321
        uint64_t i_size;
390
321
        if( vlc_stream_GetSize( p_demux->s, &i_size ) != VLC_SUCCESS )
391
0
          return false;
392
321
        uint64_t i_end = VLC_CLIP( i_size, 0, 200000 );
393
321
        if( vlc_stream_Seek( p_demux->s, i_size - i_end ) == VLC_SUCCESS )
394
321
        {
395
321
            i = 0;
396
63.1k
            while( i < 400 && Probe( p_demux, true ) > 0 ) i++;
397
321
            if( vlc_stream_Seek( p_demux->s, i_current_pos ) != VLC_SUCCESS )
398
0
                    return false;
399
321
        }
400
0
        else return false;
401
321
    }
402
403
    /* Find the longest track */
404
187k
    for( int i = 0; i < PS_TK_COUNT; i++ )
405
187k
    {
406
187k
        ps_track_t *tk = &p_sys->tk[i];
407
187k
        if( tk->i_first_pts != VLC_TICK_INVALID &&
408
557
            tk->i_last_pts > tk->i_first_pts )
409
92
        {
410
92
            vlc_tick_t i_length = tk->i_last_pts - tk->i_first_pts;
411
92
            if( i_length > p_sys->i_length )
412
91
            {
413
91
                p_sys->i_length = i_length;
414
91
                p_sys->i_time_track_index = i;
415
91
                msg_Dbg( p_demux, "we found a length of: %"PRId64 "s", SEC_FROM_VLC_TICK(p_sys->i_length) );
416
91
            }
417
92
        }
418
187k
    }
419
321
    return true;
420
321
}
421
422
static void NotifyDiscontinuity( ps_track_t *p_tk, es_out_t *out )
423
2.79k
{
424
2.79k
    bool b_selected;
425
1.63M
    for( size_t i = 0; i < PS_TK_COUNT; i++ )
426
1.63M
    {
427
1.63M
        ps_track_t *tk = &p_tk[i];
428
1.63M
        if( tk->es &&
429
17.6k
                es_out_Control( out, ES_OUT_GET_ES_STATE, tk->es, &b_selected ) == VLC_SUCCESS
430
17.6k
                && b_selected )
431
17.6k
        {
432
17.6k
            tk->i_next_block_flags |= BLOCK_FLAG_DISCONTINUITY;
433
17.6k
        }
434
1.63M
    }
435
2.79k
}
436
437
static void CheckPCR( demux_sys_t *p_sys, es_out_t *out, vlc_tick_t i_scr )
438
3.17k
{
439
3.17k
    if( p_sys->i_scr != VLC_TICK_INVALID &&
440
3.05k
        llabs( p_sys->i_scr - i_scr ) > VLC_TICK_FROM_SEC(1) )
441
137
        NotifyDiscontinuity( p_sys->tk, out );
442
3.17k
}
443
444
/*****************************************************************************
445
 * Demux:
446
 *****************************************************************************/
447
static int Demux( demux_t *p_demux )
448
139k
{
449
139k
    demux_sys_t *p_sys = p_demux->p_sys;
450
139k
    int i_ret, i_mux_rate;
451
139k
    block_t *p_pkt;
452
453
139k
    i_ret = ps_pkt_resynch( p_demux->s, p_sys->format, p_sys->b_have_pack );
454
139k
    if( i_ret < 0 )
455
270
    {
456
270
        return VLC_DEMUXER_EOF;
457
270
    }
458
138k
    else if( i_ret == 0 )
459
30.5k
    {
460
30.5k
        if( !p_sys->b_lost_sync )
461
2.66k
        {
462
2.66k
            msg_Warn( p_demux, "garbage at input from %"PRIu64", trying to resync...",
463
2.66k
                                vlc_stream_Tell(p_demux->s) );
464
2.66k
            NotifyDiscontinuity( p_sys->tk, p_demux->out );
465
2.66k
        }
466
467
30.5k
        p_sys->b_lost_sync = true;
468
30.5k
        return VLC_DEMUXER_SUCCESS;
469
30.5k
    }
470
471
108k
    if( p_sys->b_lost_sync ) msg_Warn( p_demux, "found sync code" );
472
108k
    p_sys->b_lost_sync = false;
473
474
108k
    if( p_sys->i_length == VLC_TICK_INVALID && p_sys->b_seekable )
475
321
    {
476
321
        if( !FindLength( p_demux ) )
477
0
            return VLC_DEMUXER_EGENERIC;
478
321
    }
479
480
108k
    if( ( p_pkt = ps_pkt_read( p_demux->s ) ) == NULL )
481
84
    {
482
84
        return VLC_DEMUXER_EOF;
483
84
    }
484
485
108k
    if( p_pkt->i_buffer < 4 )
486
0
    {
487
0
        block_Release( p_pkt );
488
0
        return VLC_DEMUXER_EGENERIC;
489
0
    }
490
491
108k
    const uint8_t i_stream_id = p_pkt->p_buffer[3];
492
108k
    switch( i_stream_id )
493
108k
    {
494
748
    case PS_STREAM_ID_END_STREAM:
495
958
    case STREAM_ID_PADDING:
496
958
        block_Release( p_pkt );
497
958
        break;
498
499
821
    case PS_STREAM_ID_PACK_HEADER:
500
821
        if( !ps_pkt_parse_pack( p_pkt->p_buffer, p_pkt->i_buffer,
501
821
                                &p_sys->i_pack_scr, &i_mux_rate ) )
502
765
        {
503
765
            if( p_sys->i_first_scr == VLC_TICK_INVALID )
504
3
                p_sys->i_first_scr = p_sys->i_pack_scr;
505
765
            CheckPCR( p_sys, p_demux->out, p_sys->i_pack_scr );
506
765
            p_sys->i_scr = p_sys->i_pack_scr;
507
765
            p_sys->i_lastpack_byte = vlc_stream_Tell( p_demux->s );
508
765
            if( !p_sys->b_have_pack ) p_sys->b_have_pack = true;
509
            /* done later on to work around bad vcd/svcd streams */
510
            /* es_out_SetPCR( p_demux->out, p_sys->i_scr ); */
511
765
            if( i_mux_rate > 0 ) p_sys->i_mux_rate = i_mux_rate;
512
765
        }
513
821
        block_Release( p_pkt );
514
821
        break;
515
516
1.14k
    case PS_STREAM_ID_SYSTEM_HEADER:
517
1.14k
        ps_pkt_parse_system( p_pkt->p_buffer, p_pkt->i_buffer,
518
1.14k
                            &p_sys->psm, p_sys->tk );
519
1.14k
        block_Release( p_pkt );
520
1.14k
        break;
521
522
31.2k
    case STREAM_ID_PROGRAM_STREAM_MAP:
523
31.2k
        if( p_sys->psm.i_version == 0xFF )
524
31.2k
            msg_Dbg( p_demux, "contains a PSM");
525
526
31.2k
        ps_psm_fill( &p_sys->psm,
527
31.2k
                     p_pkt->p_buffer, p_pkt->i_buffer,
528
31.2k
                     p_sys->tk );
529
31.2k
        block_Release( p_pkt );
530
31.2k
        break;
531
532
36.3k
    default:
533
        /* Reject non video/audio nor PES */
534
36.3k
        if( i_stream_id < 0xC0 || i_stream_id > 0xEF )
535
2.42k
        {
536
2.42k
            block_Release( p_pkt );
537
2.42k
            break;
538
2.42k
        }
539
        /* fallthrough */
540
67.5k
    case STREAM_ID_PRIVATE_STREAM_1:
541
71.5k
    case STREAM_ID_EXTENDED_STREAM_ID:
542
71.5k
        {
543
71.5k
            int i_id = ps_pkt_id( p_pkt->p_buffer, p_pkt->i_buffer, p_sys->source );
544
            /* Small heuristic to improve MLP detection from AOB */
545
71.5k
            if( i_id == PS_AOB_PACKET_ID_MLP &&
546
0
                p_sys->i_aob_mlp_count < 500 )
547
0
            {
548
0
                p_sys->i_aob_mlp_count++;
549
0
            }
550
71.5k
            else if( i_id == PS_VOB_PACKET_ID_MLP &&
551
930
                     p_sys->i_aob_mlp_count > 0 )
552
0
            {
553
0
                p_sys->i_aob_mlp_count--;
554
0
                i_id = PS_AOB_PACKET_ID_MLP;
555
0
            }
556
557
71.5k
            bool b_new = false;
558
71.5k
            ps_track_t *tk = &p_sys->tk[ps_id_to_tk(i_id)];
559
560
71.5k
            if( !tk->b_configured )
561
7.40k
            {
562
7.40k
                if( !ps_track_fill( tk, &p_sys->psm, i_id,
563
7.40k
                                    p_pkt->p_buffer, p_pkt->i_buffer, false ) )
564
1.72k
                {
565
1.72k
                    if( p_sys->format == IMKH_PS )
566
7
                    {
567
7
                        if( ps_id_to_type( &p_sys->psm , i_id ) == 0x91 )
568
0
                        {
569
0
                            tk->fmt.i_codec = VLC_CODEC_MULAW;
570
0
                            tk->fmt.audio.i_channels = 1;
571
0
                            tk->fmt.audio.i_rate = 8000;
572
0
                        }
573
7
                    }
574
1.71k
                    else
575
                    /* No PSM and no probing yet */
576
1.71k
                    if( p_sys->format == PSMF_PS )
577
0
                    {
578
0
                        if( tk->fmt.i_cat == VIDEO_ES )
579
0
                            tk->fmt.i_codec = VLC_CODEC_H264;
580
#if 0
581
                        if( i_stream_id == PS_STREAM_ID_PRIVATE_STREAM1 )
582
                        {
583
                            es_format_Change( &tk->fmt, AUDIO_ES, VLC_CODEC_ATRAC3P );
584
                            tk->fmt.audio.i_blockalign = 376;
585
                            tk->fmt.audio.i_channels = 2;
586
                            tk->fmt.audio.i_rate = 44100;
587
                        }
588
#endif
589
0
                    }
590
591
1.72k
                    b_new = true;
592
1.72k
                    tk->b_configured = true;
593
1.72k
                    tk->b_updated = true;
594
1.72k
                }
595
5.67k
                else
596
5.67k
                {
597
5.67k
                    msg_Dbg( p_demux, "es id=0x%x format unknown", i_id );
598
5.67k
                }
599
7.40k
            }
600
601
            /* Create all configured/updated ES when seeing a track packet */
602
71.5k
            if( tk->b_updated )
603
9.52k
                CreateOrUpdateES( p_demux );
604
605
            /* The popular VCD/SVCD subtitling WinSubMux does not
606
             * renumber the SCRs when merging subtitles into the PES */
607
71.5k
            if( !p_sys->b_bad_scr && p_sys->format == MPEG_PS &&
608
12.1k
                ( tk->fmt.i_codec == VLC_CODEC_OGT ||
609
12.1k
                  tk->fmt.i_codec == VLC_CODEC_CVD ) )
610
208
            {
611
208
                p_sys->b_bad_scr = true;
612
208
                p_sys->i_first_scr = VLC_TICK_INVALID;
613
208
            }
614
615
71.5k
            if( p_sys->i_pack_scr != VLC_TICK_INVALID && !p_sys->b_bad_scr )
616
681
            {
617
681
                if( (tk->fmt.i_cat == AUDIO_ES || tk->fmt.i_cat == VIDEO_ES) &&
618
582
                    tk->i_first_pts != VLC_TICK_INVALID && tk->i_first_pts - p_sys->i_pack_scr > VLC_TICK_FROM_SEC(2))
619
1
                {
620
1
                    msg_Warn( p_demux, "Incorrect SCR timing offset by of %"PRId64 "ms, disabling",
621
1
                                       MS_FROM_VLC_TICK(tk->i_first_pts - p_sys->i_pack_scr) );
622
1
                    p_sys->b_bad_scr = true; /* Disable Offset SCR */
623
1
                    p_sys->i_first_scr = VLC_TICK_INVALID;
624
1
                }
625
680
                else
626
680
                    es_out_SetPCR( p_demux->out, p_sys->i_pack_scr );
627
681
            }
628
629
71.5k
            if( tk->b_configured && tk->es &&
630
65.8k
                !ps_pkt_parse_pes( VLC_OBJECT(p_demux), p_pkt, tk->i_skip ) )
631
36.6k
            {
632
36.6k
                if( tk->fmt.i_cat == AUDIO_ES || tk->fmt.i_cat == VIDEO_ES )
633
13.4k
                {
634
13.4k
                    if( !p_sys->b_bad_scr && p_sys->i_pack_scr != VLC_TICK_INVALID && p_pkt->i_pts != VLC_TICK_INVALID &&
635
0
                        p_sys->i_pack_scr > p_pkt->i_pts + VLC_TICK_FROM_MS(250) )
636
0
                    {
637
0
                        msg_Warn( p_demux, "Incorrect SCR timing in advance of %" PRId64 "ms, disabling",
638
0
                                           MS_FROM_VLC_TICK(p_sys->i_pack_scr - p_pkt->i_pts) );
639
0
                        p_sys->b_bad_scr = true;
640
0
                        p_sys->i_first_scr = VLC_TICK_INVALID;
641
0
                    }
642
643
13.4k
                    if( (p_sys->b_bad_scr || !p_sys->b_have_pack) && !p_sys->i_scr_track_id )
644
198
                    {
645
198
                        p_sys->i_scr_track_id = tk->i_id;
646
198
                    }
647
13.4k
                }
648
649
36.6k
                if( ((!b_new && !p_sys->b_have_pack) || p_sys->b_bad_scr) &&
650
35.2k
                    p_sys->i_scr_track_id == tk->i_id &&
651
4.88k
                    p_pkt->i_pts != VLC_TICK_INVALID )
652
2.41k
                {
653
                    /* A hack to sync the A/V on PES files. */
654
2.41k
                    msg_Dbg( p_demux, "force SCR: %"PRId64, p_pkt->i_pts );
655
2.41k
                    CheckPCR( p_sys, p_demux->out, p_pkt->i_pts );
656
2.41k
                    p_sys->i_scr = p_pkt->i_pts;
657
2.41k
                    if( p_sys->i_first_scr == VLC_TICK_INVALID )
658
117
                        p_sys->i_first_scr = p_sys->i_scr;
659
2.41k
                    es_out_SetPCR( p_demux->out, p_pkt->i_pts );
660
2.41k
                }
661
662
36.6k
                if( p_sys->format == IMKH_PS )
663
174
                {
664
                    /* Synchronization on NVR is always broken */
665
174
                    if( llabs( p_pkt->i_dts - p_sys->i_scr ) > VLC_TICK_FROM_SEC(2) )
666
73
                    {
667
73
                        p_pkt->i_pts = p_pkt->i_pts - p_pkt->i_dts;
668
73
                        p_pkt->i_dts = p_sys->i_scr;
669
73
                        p_pkt->i_pts += p_sys->i_scr;
670
73
                    }
671
174
                }
672
673
36.6k
                if( tk->fmt.i_codec == VLC_CODEC_TELETEXT &&
674
385
                    p_pkt->i_pts == VLC_TICK_INVALID && p_sys->i_scr != VLC_TICK_INVALID )
675
286
                {
676
                    /* Teletext may have missing PTS (ETSI EN 300 472 Annexe A)
677
                     * In this case use the last SCR + 40ms */
678
286
                    p_pkt->i_pts = p_sys->i_scr + VLC_TICK_FROM_MS(40);
679
286
                }
680
681
36.6k
                if( p_pkt->i_pts > p_sys->i_current_pts )
682
424
                {
683
424
                    p_sys->i_current_pts = p_pkt->i_pts;
684
424
                }
685
686
36.6k
                if( tk->i_next_block_flags )
687
3.34k
                {
688
3.34k
                    p_pkt->i_flags = tk->i_next_block_flags;
689
3.34k
                    tk->i_next_block_flags = 0;
690
3.34k
                }
691
#if 0
692
                if( tk->fmt.i_codec == VLC_CODEC_ATRAC3P )
693
                {
694
                    p_pkt->p_buffer += 14;
695
                    p_pkt->i_buffer -= 14;
696
                }
697
#endif
698
36.6k
                es_out_Send( p_demux->out, tk->es, p_pkt );
699
36.6k
            }
700
34.8k
            else
701
34.8k
            {
702
34.8k
                block_Release( p_pkt );
703
34.8k
            }
704
705
71.5k
            p_sys->i_pack_scr = VLC_TICK_INVALID;
706
71.5k
        }
707
71.5k
        break;
708
108k
    }
709
710
108k
    demux_UpdateTitleFromStream( p_demux );
711
108k
    return VLC_DEMUXER_SUCCESS;
712
108k
}
713
714
/*****************************************************************************
715
 * Control:
716
 *****************************************************************************/
717
static int Control( demux_t *p_demux, int i_query, va_list args )
718
0
{
719
0
    demux_sys_t *p_sys = p_demux->p_sys;
720
0
    double f, *pf;
721
0
    uint64_t u64;
722
0
    int i_ret;
723
724
0
    switch( i_query )
725
0
    {
726
0
        case DEMUX_CAN_SEEK:
727
0
            *va_arg( args, bool * ) = p_sys->b_seekable;
728
0
            return VLC_SUCCESS;
729
730
0
        case DEMUX_GET_TITLE:
731
0
            *va_arg( args, int * ) = p_sys->current_title;
732
0
            return VLC_SUCCESS;
733
734
0
        case DEMUX_GET_SEEKPOINT:
735
0
            *va_arg( args, int * ) = p_sys->current_seekpoint;
736
0
            return VLC_SUCCESS;
737
738
0
        case DEMUX_GET_POSITION:
739
0
            pf = va_arg( args, double * );
740
0
            if( vlc_stream_GetSize( p_demux->s, &u64 ) == VLC_SUCCESS )
741
0
            {
742
0
                double current = vlc_stream_Tell( p_demux->s ) - p_sys->i_start_byte;
743
0
                u64 = u64 - p_sys->i_start_byte;
744
0
                *pf = current / (double)u64;
745
0
            }
746
0
            else
747
0
            {
748
0
                *pf = 0.0;
749
0
            }
750
0
            return VLC_SUCCESS;
751
752
0
        case DEMUX_SET_POSITION:
753
0
            f = va_arg( args, double );
754
755
0
            if( vlc_stream_GetSize( p_demux->s, &u64 ) != VLC_SUCCESS )
756
0
                return VLC_EGENERIC;
757
758
0
            u64 = u64 - p_sys->i_start_byte;
759
0
            p_sys->i_current_pts = VLC_TICK_INVALID;
760
0
            p_sys->i_scr = VLC_TICK_INVALID;
761
762
0
            if( p_sys->format == CDXA_PS )
763
0
            {
764
0
                u64 = (uint64_t)(u64  * f); /* Align to sector payload */
765
0
                u64 = p_sys->i_start_byte + u64 - (u64 % CDXA_SECTOR_SIZE) + CDXA_SECTOR_HEADER_SIZE;
766
0
            }
767
0
            else
768
0
            {
769
0
                u64 = p_sys->i_start_byte + (uint64_t)(u64 * f);
770
0
            }
771
772
0
            i_ret = vlc_stream_Seek( p_demux->s, u64 );
773
0
            if( i_ret == VLC_SUCCESS )
774
0
            {
775
0
                NotifyDiscontinuity( p_sys->tk, p_demux->out );
776
0
                return i_ret;
777
0
            }
778
0
            break;
779
780
0
        case DEMUX_GET_TIME:
781
0
            if( p_sys->i_time_track_index >= 0 && p_sys->i_current_pts != VLC_TICK_INVALID )
782
0
            {
783
0
                *va_arg( args, vlc_tick_t * ) = p_sys->i_current_pts - p_sys->tk[p_sys->i_time_track_index].i_first_pts;
784
0
                return VLC_SUCCESS;
785
0
            }
786
0
            if( p_sys->i_first_scr != VLC_TICK_INVALID && p_sys->i_scr != VLC_TICK_INVALID )
787
0
            {
788
0
                vlc_tick_t i_time = p_sys->i_scr - p_sys->i_first_scr;
789
                /* H.222 2.5.2.2 */
790
0
                if( p_sys->i_mux_rate > 0 && p_sys->b_have_pack )
791
0
                {
792
0
                    uint64_t i_offset = vlc_stream_Tell( p_demux->s ) - p_sys->i_lastpack_byte;
793
0
                    i_time += vlc_tick_from_samples(i_offset, p_sys->i_mux_rate * 50);
794
0
                }
795
0
                *va_arg( args, vlc_tick_t * ) = i_time;
796
0
                return VLC_SUCCESS;
797
0
            }
798
0
            *va_arg( args, vlc_tick_t * ) = 0;
799
0
            break;
800
801
0
        case DEMUX_GET_LENGTH:
802
0
            if( p_sys->i_length > VLC_TICK_0 )
803
0
            {
804
0
                *va_arg( args, vlc_tick_t * ) = p_sys->i_length;
805
0
                return VLC_SUCCESS;
806
0
            }
807
0
            else if( p_sys->i_mux_rate > 0 &&
808
0
                     vlc_stream_GetSize( p_demux->s, &u64 ) == VLC_SUCCESS )
809
0
            {
810
0
                *va_arg( args, vlc_tick_t * ) =
811
0
                    vlc_tick_from_samples( u64 - p_sys->i_start_byte / 50, p_sys->i_mux_rate );
812
0
                return VLC_SUCCESS;
813
0
            }
814
0
            *va_arg( args, vlc_tick_t * ) = 0;
815
0
            break;
816
817
0
        case DEMUX_SET_TIME:
818
0
        {
819
0
            if( p_sys->i_time_track_index >= 0 && p_sys->i_current_pts != VLC_TICK_INVALID &&
820
0
                p_sys->i_length > VLC_TICK_0)
821
0
            {
822
0
                vlc_tick_t i_time = va_arg( args, vlc_tick_t );
823
0
                i_time -= p_sys->tk[p_sys->i_time_track_index].i_first_pts;
824
0
                return demux_SetPosition( p_demux, (double) i_time / p_sys->i_length, false );
825
0
            }
826
0
            break;
827
0
        }
828
829
0
        case DEMUX_GET_TITLE_INFO:
830
0
        {
831
0
            struct input_title_t ***v = va_arg( args, struct input_title_t*** );
832
0
            int *c = va_arg( args, int * );
833
834
0
            *va_arg( args, int* ) = 0; /* Title offset */
835
0
            *va_arg( args, int* ) = 0; /* Chapter offset */
836
0
            return vlc_stream_Control( p_demux->s, STREAM_GET_TITLE_INFO, v,
837
0
                                       c );
838
0
        }
839
840
0
        case DEMUX_SET_TITLE:
841
0
            return vlc_stream_vaControl( p_demux->s, STREAM_SET_TITLE, args );
842
843
0
        case DEMUX_SET_SEEKPOINT:
844
0
            return vlc_stream_vaControl( p_demux->s, STREAM_SET_SEEKPOINT,
845
0
                                         args );
846
847
0
        case DEMUX_TEST_AND_CLEAR_FLAGS:
848
0
        {
849
0
            unsigned *restrict flags = va_arg(args, unsigned *);
850
0
            *flags &= p_sys->updates;
851
0
            p_sys->updates &= ~*flags;
852
0
            return VLC_SUCCESS;
853
0
        }
854
855
0
        case DEMUX_GET_META:
856
0
            return vlc_stream_vaControl( p_demux->s, STREAM_GET_META, args );
857
858
0
        case DEMUX_GET_FPS:
859
0
            break;
860
861
0
        case DEMUX_CAN_PAUSE:
862
0
        case DEMUX_SET_PAUSE_STATE:
863
0
        case DEMUX_CAN_CONTROL_PACE:
864
0
        case DEMUX_GET_PTS_DELAY:
865
0
            return demux_vaControlHelper( p_demux->s, 0, -1, 0, 1, i_query, args );
866
867
0
        default:
868
0
            break;
869
870
0
    }
871
0
    return VLC_EGENERIC;
872
0
}
873
874
/*****************************************************************************
875
 * Divers:
876
 *****************************************************************************/
877
878
/* PSResynch: resynch on a system startcode
879
 *  It doesn't skip more than 512 bytes
880
 *  -1 -> error, 0 -> not synch, 1 -> ok
881
 */
882
static int ps_pkt_resynch( stream_t *s, int format, bool b_pack )
883
213k
{
884
213k
    const uint8_t *p_peek;
885
213k
    ssize_t      i_peek;
886
213k
    unsigned int i_skip;
887
888
213k
    if( vlc_stream_Peek( s, &p_peek, 4 ) < 4 )
889
533
    {
890
533
        return -1;
891
533
    }
892
212k
    if( p_peek[0] == 0 && p_peek[1] == 0 && p_peek[2] == 1 &&
893
88.5k
        p_peek[3] >= PS_STREAM_ID_END_STREAM )
894
83.4k
    {
895
83.4k
        return 1;
896
83.4k
    }
897
898
129k
    if( ( i_peek = vlc_stream_Peek( s, &p_peek, 512 ) ) < 4 )
899
0
    {
900
0
        return -1;
901
0
    }
902
129k
    i_skip = 0;
903
904
129k
    for( ;; )
905
28.1M
    {
906
28.1M
        if( i_peek < 4 )
907
44.7k
        {
908
44.7k
            break;
909
44.7k
        }
910
        /* Handle mid stream 24 bytes padding+CRC creating emulated sync codes with incorrect
911
           PES sizes and frelling up to UINT16_MAX bytes followed by 24 bytes CDXA Header */
912
28.0M
        if( format == CDXA_PS && i_skip == 0 && i_peek >= 48 )
913
1.00k
        {
914
1.00k
            const uint8_t cdxasynccode[12] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
915
1.00k
                                               0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
916
1.00k
            if( !memcmp( &p_peek[24], cdxasynccode, 12 ) )
917
403
            {
918
403
                i_peek -= 48;
919
403
                p_peek += 48;
920
403
                i_skip += 48;
921
403
                continue;
922
403
            }
923
1.00k
        }
924
925
28.0M
        if( p_peek[0] == 0 && p_peek[1] == 0 && p_peek[2] == 1 &&
926
249k
            p_peek[3] >= PS_STREAM_ID_END_STREAM &&
927
90.8k
            ( !b_pack || p_peek[3] == PS_STREAM_ID_PACK_HEADER ) )
928
84.3k
        {
929
84.3k
            return vlc_stream_Read( s, NULL, i_skip ) != i_skip ? -1 : 1;
930
84.3k
        }
931
932
28.0M
        p_peek++;
933
28.0M
        i_peek--;
934
28.0M
        i_skip++;
935
28.0M
    }
936
44.7k
    return vlc_stream_Read( s, NULL, i_skip ) != i_skip ? -1 : 0;
937
129k
}
938
939
static block_t *ps_pkt_read( stream_t *s )
940
167k
{
941
167k
    const uint8_t *p_peek;
942
167k
    int i_peek = vlc_stream_Peek( s, &p_peek, 14 );
943
167k
    if( i_peek < 4 )
944
0
        return NULL;
945
946
167k
    int i_size = ps_pkt_size( p_peek, i_peek );
947
167k
    if( i_size <= 6 && p_peek[3] > PS_STREAM_ID_PACK_HEADER )
948
79.8k
    {
949
        /* Special case, search the next start code */
950
79.8k
        i_size = 6;
951
79.8k
        for( ;; )
952
88.0k
        {
953
88.0k
            i_peek = vlc_stream_Peek( s, &p_peek, i_size + 1024 );
954
88.0k
            if( i_peek <= i_size + 4 )
955
135
            {
956
135
                return NULL;
957
135
            }
958
15.2M
            while( i_size <= i_peek - 4 )
959
15.2M
            {
960
15.2M
                if( p_peek[i_size] == 0x00 && p_peek[i_size+1] == 0x00 &&
961
2.14M
                    p_peek[i_size+2] == 0x01 && p_peek[i_size+3] >= PS_STREAM_ID_END_STREAM )
962
79.7k
                {
963
79.7k
                    return vlc_stream_Block( s, i_size );
964
79.7k
                }
965
15.1M
                i_size++;
966
15.1M
            }
967
87.9k
        }
968
79.8k
    }
969
87.8k
    else
970
87.8k
    {
971
        /* Normal case */
972
87.8k
        return vlc_stream_Block( s, i_size );
973
87.8k
    }
974
975
0
    return NULL;
976
167k
}