Coverage Report

Created: 2025-07-23 06:11

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