Coverage Report

Created: 2026-02-26 08:10

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
804
#define PS_PACKET_PROBE 3
49
2
#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
104
vlc_module_begin ()
61
52
    set_description( N_("MPEG-PS demuxer") )
62
52
    set_shortname( N_("PS") )
63
52
    set_subcategory( SUBCAT_INPUT_DEMUX )
64
52
    set_capability( "demux", 1 )
65
104
    set_callbacks( OpenForce, Close )
66
52
    add_shortcut( "ps" )
67
68
52
    add_bool( "ps-trust-timestamps", true, TIME_TEXT,
69
52
                 TIME_LONGTEXT )
70
52
        change_safe ()
71
72
52
    add_submodule ()
73
52
    set_description( N_("MPEG-PS demuxer") )
74
52
    set_capability( "demux", 9 )
75
104
    set_callbacks( Open, Close )
76
52
    add_shortcut( "ps" )
77
52
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
8.42k
{
127
8.42k
    demux_sys_t *p_sys = p_demux->p_sys;
128
129
4.92M
    for( int i = 0; i < PS_TK_COUNT; i++ )
130
4.92M
    {
131
4.92M
        ps_track_t *tk = &p_sys->tk[i];
132
4.92M
        if( !tk->b_updated )
133
4.91M
            continue;
134
135
9.19k
        if( tk->es )
136
7.32k
            es_out_Del( p_demux->out, tk->es );
137
138
9.19k
        if( tk->fmt.i_cat != UNKNOWN_ES )
139
9.19k
            tk->es = es_out_Add( p_demux->out, &tk->fmt );
140
9.19k
        tk->b_updated = false;
141
9.19k
    }
142
8.42k
}
143
144
/*****************************************************************************
145
 * Open
146
 *****************************************************************************/
147
static int OpenCommon( vlc_object_t *p_this, bool b_force )
148
804
{
149
804
    demux_t     *p_demux = (demux_t*)p_this;
150
804
    demux_sys_t *p_sys;
151
152
804
    const uint8_t *p_peek;
153
804
    ssize_t i_peek = 0;
154
804
    ssize_t i_offset = 0;
155
804
    int i_skip = 0;
156
804
    unsigned i_max_packets = PS_PACKET_PROBE;
157
804
    int format = MPEG_PS;
158
804
    int i_mux_rate = 0;
159
804
    vlc_tick_t i_length = VLC_TICK_INVALID;
160
161
804
    i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 16 );
162
804
    if( i_peek < 16 )
163
0
        return VLC_EGENERIC;
164
165
804
    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
804
    else if( !memcmp( p_peek, "IMKH", 4 ) )
179
10
    {
180
10
        msg_Info( p_demux, "Detected Hikvision PVA header");
181
10
        i_skip = 40;
182
10
        format = IMKH_PS;
183
10
        i_max_packets = 0;
184
10
    }
185
794
    else if( !memcmp( p_peek, "RIFF", 4 ) && !memcmp( &p_peek[8], "CDXA", 4 ) )
186
2
    {
187
2
        format = CDXA_PS;
188
2
        i_max_packets = 0; /* We can't probe here */
189
2
        i_skip = CDXA_HEADER_SIZE;
190
2
        msg_Info( p_demux, "Detected CDXA-PS" );
191
        /* FIXME: have a proper way to decap CD sectors or make an access stream filter */
192
2
    }
193
792
    else if( b_force )
194
391
    {
195
391
        msg_Warn( p_demux, "this does not look like an MPEG PS stream, "
196
391
                  "continuing anyway" );
197
391
        i_max_packets = 0;
198
391
    }
199
200
805
    for( unsigned i=0; i<i_max_packets; i++ )
201
402
    {
202
402
        if( i_peek < i_offset + 16 )
203
1
        {
204
1
            i_peek = vlc_stream_Peek( p_demux->s, &p_peek, i_offset + 16 );
205
1
            if( i_peek < i_offset + 16 )
206
1
                return VLC_EGENERIC;
207
1
        }
208
209
401
        const uint8_t startcode[3] = { 0x00, 0x00, 0x01 };
210
401
        const uint8_t *p_header = &p_peek[i_offset];
211
401
        if( memcmp( p_header, startcode, 3 ) ||
212
1
           ( (p_header[3] & 0xB0) != 0xB0 &&
213
0
            !(p_header[3] >= 0xC0 && p_header[3] <= 0xEF) &&
214
0
              p_header[3] != STREAM_ID_EXTENDED_STREAM_ID &&
215
0
              p_header[3] != STREAM_ID_PROGRAM_STREAM_DIRECTORY ) )
216
400
            return VLC_EGENERIC;
217
218
1
        ssize_t i_pessize = ps_pkt_size( p_header, 16 );
219
1
        if( i_pessize < 5 )
220
0
            return VLC_EGENERIC;
221
1
        i_offset += i_pessize;
222
1
    }
223
224
403
    if( i_skip && !p_demux->b_preparsing &&
225
12
        vlc_stream_Read( p_demux->s, NULL, i_skip ) != i_skip )
226
0
        return VLC_EGENERIC;
227
228
    /* Fill p_demux field */
229
403
    p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
230
403
    if( !p_sys ) return VLC_ENOMEM;
231
232
403
    p_demux->pf_demux = Demux;
233
403
    p_demux->pf_control = Control;
234
235
    /* Init p_sys */
236
403
    p_sys->i_mux_rate = i_mux_rate;
237
403
    p_sys->i_pack_scr  = VLC_TICK_INVALID;
238
403
    p_sys->i_first_scr = VLC_TICK_INVALID;
239
403
    p_sys->i_scr = VLC_TICK_INVALID;
240
403
    p_sys->i_scr_track_id = 0;
241
403
    p_sys->i_length   = i_length;
242
403
    p_sys->i_current_pts = VLC_TICK_INVALID;
243
403
    p_sys->i_time_track_index = -1;
244
403
    p_sys->i_aob_mlp_count = 0;
245
403
    p_sys->i_start_byte = i_skip;
246
403
    p_sys->i_lastpack_byte = i_skip;
247
248
403
    p_sys->b_lost_sync = false;
249
403
    p_sys->b_have_pack = false;
250
403
    p_sys->b_bad_scr   = false;
251
403
    p_sys->b_seekable  = false;
252
403
    p_sys->format      = format;
253
403
    p_sys->current_title = 0;
254
403
    p_sys->current_seekpoint = 0;
255
403
    p_sys->updates = 0;
256
257
403
    p_sys->source = PS_SOURCE_UNKNOWN;
258
403
    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
403
    vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &p_sys->b_seekable );
271
272
403
    ps_psm_init( &p_sys->psm );
273
403
    ps_track_init( p_sys->tk );
274
275
    /* TODO prescanning of ES */
276
277
403
    return VLC_SUCCESS;
278
403
}
279
280
static int OpenForce( vlc_object_t *p_this )
281
391
{
282
391
    return OpenCommon( p_this, true );
283
391
}
284
285
static int Open( vlc_object_t *p_this )
286
413
{
287
413
    return OpenCommon( p_this, p_this->force );
288
413
}
289
290
/*****************************************************************************
291
 * Close
292
 *****************************************************************************/
293
static void Close( vlc_object_t *p_this )
294
403
{
295
403
    demux_t     *p_demux = (demux_t*)p_this;
296
403
    demux_sys_t *p_sys = p_demux->p_sys;
297
403
    int i;
298
299
235k
    for( i = 0; i < PS_TK_COUNT; i++ )
300
235k
    {
301
235k
        ps_track_t *tk = &p_sys->tk[i];
302
235k
        es_format_Clean( &tk->fmt );
303
235k
        if( tk->b_configured && tk->es != NULL )
304
1.87k
            es_out_Del( p_demux->out, tk->es );
305
235k
    }
306
307
403
    ps_psm_destroy( &p_sys->psm );
308
309
403
    free( p_sys );
310
403
}
311
312
static int Probe( demux_t *p_demux, bool b_end )
313
81.7k
{
314
81.7k
    demux_sys_t *p_sys = p_demux->p_sys;
315
81.7k
    int i_ret, i_id;
316
81.7k
    block_t *p_pkt;
317
318
81.7k
    i_ret = ps_pkt_resynch( p_demux->s, p_sys->format, p_sys->b_have_pack );
319
81.7k
    if( i_ret < 0 )
320
261
    {
321
261
        return VLC_DEMUXER_EOF;
322
261
    }
323
81.5k
    else if( i_ret == 0 )
324
10.9k
    {
325
10.9k
        if( !p_sys->b_lost_sync )
326
10.9k
            msg_Warn( p_demux, "garbage at input, trying to resync..." );
327
328
10.9k
        p_sys->b_lost_sync = true;
329
10.9k
        return VLC_DEMUXER_SUCCESS;
330
10.9k
    }
331
332
70.5k
    if( p_sys->b_lost_sync ) msg_Warn( p_demux, "found sync code" );
333
70.5k
    p_sys->b_lost_sync = false;
334
335
70.5k
    if( ( p_pkt = ps_pkt_read( p_demux->s ) ) == NULL )
336
104
    {
337
104
        return VLC_DEMUXER_EOF;
338
104
    }
339
340
70.4k
    i_id = ps_pkt_id( p_pkt->p_buffer, p_pkt->i_buffer, p_sys->source );
341
70.4k
    if( i_id >= 0xc0 )
342
53.5k
    {
343
53.5k
        ps_track_t *tk = &p_sys->tk[ps_id_to_tk(i_id)];
344
53.5k
        if( !ps_pkt_parse_pes( VLC_OBJECT(p_demux), p_pkt, tk->i_skip ) &&
345
35.7k
             p_pkt->i_pts != VLC_TICK_INVALID )
346
17.6k
        {
347
17.6k
            if( b_end && (tk->i_last_pts == VLC_TICK_INVALID || p_pkt->i_pts > tk->i_last_pts) )
348
831
            {
349
831
                tk->i_last_pts = p_pkt->i_pts;
350
831
            }
351
16.7k
            else if ( tk->i_first_pts == VLC_TICK_INVALID )
352
687
            {
353
687
                tk->i_first_pts = p_pkt->i_pts;
354
687
            }
355
17.6k
        }
356
53.5k
    }
357
16.8k
    else if( i_id == PS_STREAM_ID_PACK_HEADER )
358
228
    {
359
228
        vlc_tick_t i_scr; int dummy;
360
228
        if( !b_end && !ps_pkt_parse_pack( p_pkt->p_buffer, p_pkt->i_buffer,
361
83
                                          &i_scr, &dummy ) )
362
79
        {
363
79
            if( p_sys->i_first_scr == VLC_TICK_INVALID )
364
16
                p_sys->i_first_scr = i_scr;
365
79
        }
366
228
        p_sys->b_have_pack = true;
367
228
    }
368
369
70.4k
    block_Release( p_pkt );
370
70.4k
    return VLC_DEMUXER_SUCCESS;
371
70.5k
}
372
373
static bool FindLength( demux_t *p_demux )
374
358
{
375
358
    demux_sys_t *p_sys = p_demux->p_sys;
376
377
358
    if( !var_CreateGetBool( p_demux, "ps-trust-timestamps" ) )
378
0
        return true;
379
380
358
    if( p_sys->i_length == VLC_TICK_INVALID ) /* First time */
381
358
    {
382
358
        p_sys->i_length = VLC_TICK_0;
383
        /* Check beginning */
384
358
        int i = 0;
385
358
        uint64_t i_current_pos = vlc_stream_Tell( p_demux->s );
386
12.1k
        while( i < 40 && Probe( p_demux, false ) > 0 ) i++;
387
388
        /* Check end */
389
358
        uint64_t i_size;
390
358
        if( vlc_stream_GetSize( p_demux->s, &i_size ) != VLC_SUCCESS )
391
0
          return false;
392
358
        uint64_t i_end = VLC_CLIP( i_size, 0, 200000 );
393
358
        if( vlc_stream_Seek( p_demux->s, i_size - i_end ) == VLC_SUCCESS )
394
358
        {
395
358
            i = 0;
396
69.9k
            while( i < 400 && Probe( p_demux, true ) > 0 ) i++;
397
358
            if( vlc_stream_Seek( p_demux->s, i_current_pos ) != VLC_SUCCESS )
398
0
                    return false;
399
358
        }
400
0
        else return false;
401
358
    }
402
403
    /* Find the longest track */
404
209k
    for( int i = 0; i < PS_TK_COUNT; i++ )
405
209k
    {
406
209k
        ps_track_t *tk = &p_sys->tk[i];
407
209k
        if( tk->i_first_pts != VLC_TICK_INVALID &&
408
687
            tk->i_last_pts > tk->i_first_pts )
409
95
        {
410
95
            vlc_tick_t i_length = tk->i_last_pts - tk->i_first_pts;
411
95
            if( i_length > p_sys->i_length )
412
88
            {
413
88
                p_sys->i_length = i_length;
414
88
                p_sys->i_time_track_index = i;
415
88
                msg_Dbg( p_demux, "we found a length of: %"PRId64 "s", SEC_FROM_VLC_TICK(p_sys->i_length) );
416
88
            }
417
95
        }
418
209k
    }
419
358
    return true;
420
358
}
421
422
static void NotifyDiscontinuity( ps_track_t *p_tk, es_out_t *out )
423
3.17k
{
424
3.17k
    bool b_selected;
425
1.85M
    for( size_t i = 0; i < PS_TK_COUNT; i++ )
426
1.85M
    {
427
1.85M
        ps_track_t *tk = &p_tk[i];
428
1.85M
        if( tk->es &&
429
15.5k
                es_out_Control( out, ES_OUT_GET_ES_STATE, tk->es, &b_selected ) == VLC_SUCCESS
430
15.5k
                && b_selected )
431
15.5k
        {
432
15.5k
            tk->i_next_block_flags |= BLOCK_FLAG_DISCONTINUITY;
433
15.5k
        }
434
1.85M
    }
435
3.17k
}
436
437
static void CheckPCR( demux_sys_t *p_sys, es_out_t *out, vlc_tick_t i_scr )
438
4.58k
{
439
4.58k
    if( p_sys->i_scr != VLC_TICK_INVALID &&
440
4.46k
        llabs( p_sys->i_scr - i_scr ) > VLC_TICK_FROM_SEC(1) )
441
1.08k
        NotifyDiscontinuity( p_sys->tk, out );
442
4.58k
}
443
444
/*****************************************************************************
445
 * Demux:
446
 *****************************************************************************/
447
static int Demux( demux_t *p_demux )
448
142k
{
449
142k
    demux_sys_t *p_sys = p_demux->p_sys;
450
142k
    int i_ret, i_mux_rate;
451
142k
    block_t *p_pkt;
452
453
142k
    i_ret = ps_pkt_resynch( p_demux->s, p_sys->format, p_sys->b_have_pack );
454
142k
    if( i_ret < 0 )
455
279
    {
456
279
        return VLC_DEMUXER_EOF;
457
279
    }
458
142k
    else if( i_ret == 0 )
459
18.6k
    {
460
18.6k
        if( !p_sys->b_lost_sync )
461
2.09k
        {
462
2.09k
            msg_Warn( p_demux, "garbage at input from %"PRIu64", trying to resync...",
463
2.09k
                                vlc_stream_Tell(p_demux->s) );
464
2.09k
            NotifyDiscontinuity( p_sys->tk, p_demux->out );
465
2.09k
        }
466
467
18.6k
        p_sys->b_lost_sync = true;
468
18.6k
        return VLC_DEMUXER_SUCCESS;
469
18.6k
    }
470
471
123k
    if( p_sys->b_lost_sync ) msg_Warn( p_demux, "found sync code" );
472
123k
    p_sys->b_lost_sync = false;
473
474
123k
    if( p_sys->i_length == VLC_TICK_INVALID && p_sys->b_seekable )
475
358
    {
476
358
        if( !FindLength( p_demux ) )
477
0
            return VLC_DEMUXER_EGENERIC;
478
358
    }
479
480
123k
    if( ( p_pkt = ps_pkt_read( p_demux->s ) ) == NULL )
481
124
    {
482
124
        return VLC_DEMUXER_EOF;
483
124
    }
484
485
123k
    if( p_pkt->i_buffer < 4 )
486
0
    {
487
0
        block_Release( p_pkt );
488
0
        return VLC_DEMUXER_EGENERIC;
489
0
    }
490
491
123k
    const uint8_t i_stream_id = p_pkt->p_buffer[3];
492
123k
    switch( i_stream_id )
493
123k
    {
494
5.13k
    case PS_STREAM_ID_END_STREAM:
495
5.14k
    case STREAM_ID_PADDING:
496
5.14k
        block_Release( p_pkt );
497
5.14k
        break;
498
499
146
    case PS_STREAM_ID_PACK_HEADER:
500
146
        if( !ps_pkt_parse_pack( p_pkt->p_buffer, p_pkt->i_buffer,
501
146
                                &p_sys->i_pack_scr, &i_mux_rate ) )
502
142
        {
503
142
            if( p_sys->i_first_scr == VLC_TICK_INVALID )
504
2
                p_sys->i_first_scr = p_sys->i_pack_scr;
505
142
            CheckPCR( p_sys, p_demux->out, p_sys->i_pack_scr );
506
142
            p_sys->i_scr = p_sys->i_pack_scr;
507
142
            p_sys->i_lastpack_byte = vlc_stream_Tell( p_demux->s );
508
142
            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
142
            if( i_mux_rate > 0 ) p_sys->i_mux_rate = i_mux_rate;
512
142
        }
513
146
        block_Release( p_pkt );
514
146
        break;
515
516
5.36k
    case PS_STREAM_ID_SYSTEM_HEADER:
517
5.36k
        ps_pkt_parse_system( p_pkt->p_buffer, p_pkt->i_buffer,
518
5.36k
                            &p_sys->psm, p_sys->tk );
519
5.36k
        block_Release( p_pkt );
520
5.36k
        break;
521
522
31.8k
    case STREAM_ID_PROGRAM_STREAM_MAP:
523
31.8k
        if( p_sys->psm.i_version == 0xFF )
524
31.8k
            msg_Dbg( p_demux, "contains a PSM");
525
526
31.8k
        ps_psm_fill( &p_sys->psm,
527
31.8k
                     p_pkt->p_buffer, p_pkt->i_buffer,
528
31.8k
                     p_sys->tk );
529
31.8k
        block_Release( p_pkt );
530
31.8k
        break;
531
532
31.1k
    default:
533
        /* Reject non video/audio nor PES */
534
31.1k
        if( i_stream_id < 0xC0 || i_stream_id > 0xEF )
535
1.54k
        {
536
1.54k
            block_Release( p_pkt );
537
1.54k
            break;
538
1.54k
        }
539
        /* fallthrough */
540
75.8k
    case STREAM_ID_PRIVATE_STREAM_1:
541
79.6k
    case STREAM_ID_EXTENDED_STREAM_ID:
542
79.6k
        {
543
79.6k
            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
79.6k
            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
79.6k
            else if( i_id == PS_VOB_PACKET_ID_MLP &&
551
111
                     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
79.6k
            bool b_new = false;
558
79.6k
            ps_track_t *tk = &p_sys->tk[ps_id_to_tk(i_id)];
559
560
79.6k
            if( !tk->b_configured )
561
8.99k
            {
562
8.99k
                if( !ps_track_fill( tk, &p_sys->psm, i_id,
563
8.99k
                                    p_pkt->p_buffer, p_pkt->i_buffer, false ) )
564
1.87k
                {
565
1.87k
                    if( p_sys->format == IMKH_PS )
566
87
                    {
567
87
                        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
87
                    }
574
1.78k
                    else
575
                    /* No PSM and no probing yet */
576
1.78k
                    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.87k
                    b_new = true;
592
1.87k
                    tk->b_configured = true;
593
1.87k
                    tk->b_updated = true;
594
1.87k
                }
595
7.12k
                else
596
7.12k
                {
597
7.12k
                    msg_Dbg( p_demux, "es id=0x%x format unknown", i_id );
598
7.12k
                }
599
8.99k
            }
600
601
            /* Create all configured/updated ES when seeing a track packet */
602
79.6k
            if( tk->b_updated )
603
8.42k
                CreateOrUpdateES( p_demux );
604
605
            /* The popular VCD/SVCD subtitling WinSubMux does not
606
             * renumber the SCRs when merging subtitles into the PES */
607
79.6k
            if( !p_sys->b_bad_scr && p_sys->format == MPEG_PS &&
608
9.17k
                ( tk->fmt.i_codec == VLC_CODEC_OGT ||
609
9.12k
                  tk->fmt.i_codec == VLC_CODEC_CVD ) )
610
243
            {
611
243
                p_sys->b_bad_scr = true;
612
243
                p_sys->i_first_scr = VLC_TICK_INVALID;
613
243
            }
614
615
79.6k
            if( p_sys->i_pack_scr != VLC_TICK_INVALID && !p_sys->b_bad_scr )
616
22
            {
617
22
                if( (tk->fmt.i_cat == AUDIO_ES || tk->fmt.i_cat == VIDEO_ES) &&
618
3
                    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
21
                else
626
21
                    es_out_SetPCR( p_demux->out, p_sys->i_pack_scr );
627
22
            }
628
629
79.6k
            if( tk->b_configured && tk->es &&
630
72.4k
                !ps_pkt_parse_pes( VLC_OBJECT(p_demux), p_pkt, tk->i_skip ) )
631
44.2k
            {
632
44.2k
                if( tk->fmt.i_cat == AUDIO_ES || tk->fmt.i_cat == VIDEO_ES )
633
13.2k
                {
634
13.2k
                    if( !p_sys->b_bad_scr && p_sys->i_pack_scr != VLC_TICK_INVALID && p_pkt->i_pts != VLC_TICK_INVALID &&
635
2
                        p_sys->i_pack_scr > p_pkt->i_pts + VLC_TICK_FROM_MS(250) )
636
2
                    {
637
2
                        msg_Warn( p_demux, "Incorrect SCR timing in advance of %" PRId64 "ms, disabling",
638
2
                                           MS_FROM_VLC_TICK(p_sys->i_pack_scr - p_pkt->i_pts) );
639
2
                        p_sys->b_bad_scr = true;
640
2
                        p_sys->i_first_scr = VLC_TICK_INVALID;
641
2
                    }
642
643
13.2k
                    if( (p_sys->b_bad_scr || !p_sys->b_have_pack) && !p_sys->i_scr_track_id )
644
214
                    {
645
214
                        p_sys->i_scr_track_id = tk->i_id;
646
214
                    }
647
13.2k
                }
648
649
44.2k
                if( ((!b_new && !p_sys->b_have_pack) || p_sys->b_bad_scr) &&
650
43.9k
                    p_sys->i_scr_track_id == tk->i_id &&
651
6.84k
                    p_pkt->i_pts != VLC_TICK_INVALID )
652
4.44k
                {
653
                    /* A hack to sync the A/V on PES files. */
654
4.44k
                    msg_Dbg( p_demux, "force SCR: %"PRId64, p_pkt->i_pts );
655
4.44k
                    CheckPCR( p_sys, p_demux->out, p_pkt->i_pts );
656
4.44k
                    p_sys->i_scr = p_pkt->i_pts;
657
4.44k
                    if( p_sys->i_first_scr == VLC_TICK_INVALID )
658
117
                        p_sys->i_first_scr = p_sys->i_scr;
659
4.44k
                    es_out_SetPCR( p_demux->out, p_pkt->i_pts );
660
4.44k
                }
661
662
44.2k
                if( p_sys->format == IMKH_PS )
663
1.99k
                {
664
                    /* Synchronization on NVR is always broken */
665
1.99k
                    if( llabs( p_pkt->i_dts - p_sys->i_scr ) > VLC_TICK_FROM_SEC(2) )
666
1.14k
                    {
667
1.14k
                        p_pkt->i_pts = p_pkt->i_pts - p_pkt->i_dts;
668
1.14k
                        p_pkt->i_dts = p_sys->i_scr;
669
1.14k
                        p_pkt->i_pts += p_sys->i_scr;
670
1.14k
                    }
671
1.99k
                }
672
673
44.2k
                if( tk->fmt.i_codec == VLC_CODEC_TELETEXT &&
674
909
                    p_pkt->i_pts == VLC_TICK_INVALID && p_sys->i_scr != VLC_TICK_INVALID )
675
476
                {
676
                    /* Teletext may have missing PTS (ETSI EN 300 472 Annexe A)
677
                     * In this case use the last SCR + 40ms */
678
476
                    p_pkt->i_pts = p_sys->i_scr + VLC_TICK_FROM_MS(40);
679
476
                }
680
681
44.2k
                if( p_pkt->i_pts > p_sys->i_current_pts )
682
444
                {
683
444
                    p_sys->i_current_pts = p_pkt->i_pts;
684
444
                }
685
686
44.2k
                if( tk->i_next_block_flags )
687
4.92k
                {
688
4.92k
                    p_pkt->i_flags = tk->i_next_block_flags;
689
4.92k
                    tk->i_next_block_flags = 0;
690
4.92k
                }
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
44.2k
                es_out_Send( p_demux->out, tk->es, p_pkt );
699
44.2k
            }
700
35.3k
            else
701
35.3k
            {
702
35.3k
                block_Release( p_pkt );
703
35.3k
            }
704
705
79.6k
            p_sys->i_pack_scr = VLC_TICK_INVALID;
706
79.6k
        }
707
79.6k
        break;
708
123k
    }
709
710
123k
    demux_UpdateTitleFromStream( p_demux );
711
123k
    return VLC_DEMUXER_SUCCESS;
712
123k
}
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
224k
{
884
224k
    const uint8_t *p_peek;
885
224k
    ssize_t      i_peek;
886
224k
    unsigned int i_skip;
887
888
224k
    if( vlc_stream_Peek( s, &p_peek, 4 ) < 4 )
889
540
    {
890
540
        return -1;
891
540
    }
892
223k
    if( p_peek[0] == 0 && p_peek[1] == 0 && p_peek[2] == 1 &&
893
117k
        p_peek[3] >= PS_STREAM_ID_END_STREAM )
894
113k
    {
895
113k
        return 1;
896
113k
    }
897
898
110k
    if( ( i_peek = vlc_stream_Peek( s, &p_peek, 512 ) ) < 4 )
899
0
    {
900
0
        return -1;
901
0
    }
902
110k
    i_skip = 0;
903
904
110k
    for( ;; )
905
20.1M
    {
906
20.1M
        if( i_peek < 4 )
907
29.6k
        {
908
29.6k
            break;
909
29.6k
        }
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
20.1M
        if( format == CDXA_PS && i_skip == 0 && i_peek >= 48 )
913
1.44k
        {
914
1.44k
            const uint8_t cdxasynccode[12] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
915
1.44k
                                               0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
916
1.44k
            if( !memcmp( &p_peek[24], cdxasynccode, 12 ) )
917
0
            {
918
0
                i_peek -= 48;
919
0
                p_peek += 48;
920
0
                i_skip += 48;
921
0
                continue;
922
0
            }
923
1.44k
        }
924
925
20.1M
        if( p_peek[0] == 0 && p_peek[1] == 0 && p_peek[2] == 1 &&
926
253k
            p_peek[3] >= PS_STREAM_ID_END_STREAM &&
927
84.9k
            ( !b_pack || p_peek[3] == PS_STREAM_ID_PACK_HEADER ) )
928
81.0k
        {
929
81.0k
            return vlc_stream_Read( s, NULL, i_skip ) != i_skip ? -1 : 1;
930
81.0k
        }
931
932
20.0M
        p_peek++;
933
20.0M
        i_peek--;
934
20.0M
        i_skip++;
935
20.0M
    }
936
29.6k
    return vlc_stream_Read( s, NULL, i_skip ) != i_skip ? -1 : 0;
937
110k
}
938
939
static block_t *ps_pkt_read( stream_t *s )
940
194k
{
941
194k
    const uint8_t *p_peek;
942
194k
    int i_peek = vlc_stream_Peek( s, &p_peek, 14 );
943
194k
    if( i_peek < 4 )
944
0
        return NULL;
945
946
194k
    int i_size = ps_pkt_size( p_peek, i_peek );
947
194k
    if( i_size <= 6 && p_peek[3] > PS_STREAM_ID_PACK_HEADER )
948
112k
    {
949
        /* Special case, search the next start code */
950
112k
        i_size = 6;
951
112k
        for( ;; )
952
121k
        {
953
121k
            i_peek = vlc_stream_Peek( s, &p_peek, i_size + 1024 );
954
121k
            if( i_peek <= i_size + 4 )
955
223
            {
956
223
                return NULL;
957
223
            }
958
17.8M
            while( i_size <= i_peek - 4 )
959
17.8M
            {
960
17.8M
                if( p_peek[i_size] == 0x00 && p_peek[i_size+1] == 0x00 &&
961
2.02M
                    p_peek[i_size+2] == 0x01 && p_peek[i_size+3] >= PS_STREAM_ID_END_STREAM )
962
112k
                {
963
112k
                    return vlc_stream_Block( s, i_size );
964
112k
                }
965
17.7M
                i_size++;
966
17.7M
            }
967
121k
        }
968
112k
    }
969
81.9k
    else
970
81.9k
    {
971
        /* Normal case */
972
81.9k
        return vlc_stream_Block( s, i_size );
973
81.9k
    }
974
975
0
    return NULL;
976
194k
}