ps.c 27.5 KB
Newer Older
1
/*****************************************************************************
2
 * ps.c: Program Stream demux module for VLC.
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2004-2009 VLC authors and VideoLAN
5
 * $Id$
6 7 8
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
9 10 11
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
12 13 14 15
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
16 17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
18
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
19 20 21
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 23 24 25 26 27
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

28 29 30 31
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

32
#include <vlc_common.h>
33
#include <vlc_plugin.h>
Clément Stenac's avatar
Clément Stenac committed
34
#include <vlc_demux.h>
35

36
#include "pes.h"
37 38 39 40 41 42 43
#include "ps.h"

/* TODO:
 *  - re-add pre-scanning.
 *  - ...
 */

44 45 46 47 48
#define TIME_TEXT N_("Trust MPEG timestamps")
#define TIME_LONGTEXT N_("Normally we use the timestamps of the MPEG files " \
    "to calculate position and duration. However sometimes this might not " \
    "be usable. Disable this option to calculate from the bitrate instead." )

49
#define PS_PACKET_PROBE 3
50
#define CDXA_HEADER_SIZE 44
51 52
#define CDXA_SECTOR_SIZE 2352
#define CDXA_SECTOR_HEADER_SIZE 24
53

54 55 56
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
57
static int  OpenForce( vlc_object_t * );
58 59
static int  Open   ( vlc_object_t * );
static void Close  ( vlc_object_t * );
60

61 62
vlc_module_begin ()
    set_description( N_("MPEG-PS demuxer") )
63
    set_shortname( N_("PS") )
64 65 66 67 68
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_DEMUX )
    set_capability( "demux", 1 )
    set_callbacks( OpenForce, Close )
    add_shortcut( "ps" )
69

70
    add_bool( "ps-trust-timestamps", true, TIME_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
71
                 TIME_LONGTEXT, true )
72
        change_safe ()
73

74 75 76 77
    add_submodule ()
    set_description( N_("MPEG-PS demuxer") )
    set_capability( "demux", 8 )
    set_callbacks( Open, Close )
78
    add_shortcut( "ps" )
79
vlc_module_end ()
80 81 82 83 84 85 86

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/

struct demux_sys_t
{
87
    ps_psm_t    psm;
88
    ps_track_t  tk[PS_TK_COUNT];
89

90 91 92
    int64_t     i_pack_scr; /* current read pack scr value, temp */
    int64_t     i_first_scr; /* media offset */
    int64_t     i_scr; /* committed, current position */
93
    int64_t     i_scr_track_id;
94
    int         i_mux_rate;
95
    int64_t     i_length;
96
    int         i_time_track_index;
97
    int64_t     i_current_pts;
98
    uint64_t    i_start_byte;
99
    uint64_t    i_lastpack_byte;
100

101 102
    int         i_aob_mlp_count;

103 104
    bool  b_lost_sync;
    bool  b_have_pack;
105
    bool  b_bad_scr;
106
    bool  b_seekable;
107 108 109 110 111 112
    enum
    {
        MPEG_PS = 0,
        CDXA_PS,
        PSMF_PS,
    } format;
113 114 115 116 117
};

static int Demux  ( demux_t *p_demux );
static int Control( demux_t *p_demux, int i_query, va_list args );

118
static int      ps_pkt_resynch( stream_t *, int, bool );
119
static block_t *ps_pkt_read   ( stream_t * );
120 121 122 123

/*****************************************************************************
 * Open
 *****************************************************************************/
124
static int OpenCommon( vlc_object_t *p_this, bool b_force )
125 126 127 128
{
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys;

129
    const uint8_t *p_peek;
130 131
    ssize_t i_peek = 0;
    ssize_t i_offset = 0;
132 133 134 135 136
    ssize_t i_skip = 0;
    unsigned i_max_packets = PS_PACKET_PROBE;
    int format = MPEG_PS;
    int i_mux_rate = 0;
    int i_length = -1;
137

138 139
    i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 16 );
    if( i_peek < 16 )
140
    {
141
        msg_Dbg( p_demux, "cannot peek" );
142 143 144
        return VLC_EGENERIC;
    }

145 146 147 148 149 150 151 152 153 154 155 156 157 158
    if( !memcmp( p_peek, "PSMF", 4 ) &&
        (GetDWBE( &p_peek[4] ) & 0x30303030) == 0x30303030 )
    {
        i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 100 );
        if( i_peek < 100 )
            return VLC_EGENERIC;
        i_skip = i_offset = GetWBE( &p_peek[10] );
        format = PSMF_PS;
        msg_Info( p_demux, "Detected PSMF-PS header");
        i_mux_rate = GetDWBE( &p_peek[96] );
        if( GetDWBE( &p_peek[86] ) > 0 )
            i_length = CLOCK_FREQ * GetDWBE( &p_peek[92] ) / GetDWBE( &p_peek[86] );
    }
    else if( !memcmp( p_peek, "RIFF", 4 ) && !memcmp( &p_peek[8], "CDXA", 4 ) )
159
    {
160 161 162
        format = CDXA_PS;
        i_max_packets = 0; /* We can't probe here */
        i_skip = CDXA_HEADER_SIZE;
163
        msg_Info( p_demux, "Detected CDXA-PS" );
164
        /* FIXME: have a proper way to decap CD sectors or make an access stream filter */
165 166 167 168 169
    }
    else if( b_force )
    {
        msg_Warn( p_demux, "this does not look like an MPEG PS stream, "
                  "continuing anyway" );
170
        i_max_packets = 0;
171
    }
172 173

    for( unsigned i=0; i<i_max_packets; i++ )
174
    {
175
        if( i_peek < i_offset + 16 )
176
        {
177 178
            i_peek = vlc_stream_Peek( p_demux->s, &p_peek, i_offset + 16 );
            if( i_peek < i_offset + 16 )
179 180
                return VLC_EGENERIC;
        }
181 182 183 184 185 186

        const uint8_t startcode[3] = { 0x00, 0x00, 0x01 };
        const uint8_t *p_header = &p_peek[i_offset];
        if( memcmp( p_header, startcode, 3 ) ||
           ( (p_header[3] & 0xB0) != 0xB0 &&
            !(p_header[3] >= 0xC0 && p_header[3] <= 0xEF) &&
187 188
              p_header[3] != PS_STREAM_ID_EXTENDED &&
              p_header[3] != PS_STREAM_ID_DIRECTORY ) )
189 190 191 192 193 194
            return VLC_EGENERIC;

        ssize_t i_pessize = ps_pkt_size( p_header, 16 );
        if( i_pessize < 5 )
            return VLC_EGENERIC;
        i_offset += i_pessize;
195 196
    }

197 198 199 200
    if( i_skip > 0 && !p_demux->b_preparsing &&
        vlc_stream_Read( p_demux->s, NULL, i_skip ) != i_skip )
        return VLC_EGENERIC;

201 202
    /* Fill p_demux field */
    p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
203
    if( !p_sys ) return VLC_ENOMEM;
204

205 206 207
    p_demux->pf_demux = Demux;
    p_demux->pf_control = Control;

208
    /* Init p_sys */
209
    p_sys->i_mux_rate = i_mux_rate;
210 211 212
    p_sys->i_pack_scr      = -1;
    p_sys->i_first_scr = -1;
    p_sys->i_scr = -1;
213
    p_sys->i_scr_track_id = 0;
214
    p_sys->i_length   = i_length;
215
    p_sys->i_current_pts = (mtime_t) 0;
216
    p_sys->i_time_track_index = -1;
217
    p_sys->i_aob_mlp_count = 0;
218
    p_sys->i_start_byte = i_skip;
219
    p_sys->i_lastpack_byte = i_skip;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
220

221 222
    p_sys->b_lost_sync = false;
    p_sys->b_have_pack = false;
223
    p_sys->b_bad_scr   = false;
224
    p_sys->b_seekable  = false;
225
    p_sys->format      = format;
226

227
    vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &p_sys->b_seekable );
228

229
    ps_psm_init( &p_sys->psm );
230 231 232 233 234 235 236
    ps_track_init( p_sys->tk );

    /* TODO prescanning of ES */

    return VLC_SUCCESS;
}

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
237
static int OpenForce( vlc_object_t *p_this )
238
{
239
    return OpenCommon( p_this, true );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
240
}
241

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
242 243
static int Open( vlc_object_t *p_this )
{
244
    return OpenCommon( p_this, p_this->obj.force );
245 246
}

247 248 249 250 251 252 253
/*****************************************************************************
 * Close
 *****************************************************************************/
static void Close( vlc_object_t *p_this )
{
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys = p_demux->p_sys;
254 255 256 257 258
    int i;

    for( i = 0; i < PS_TK_COUNT; i++ )
    {
        ps_track_t *tk = &p_sys->tk[i];
259
        if( tk->b_configured )
260 261 262 263 264
        {
            es_format_Clean( &tk->fmt );
            if( tk->es ) es_out_Del( p_demux->out, tk->es );
        }
    }
265

266 267
    ps_psm_destroy( &p_sys->psm );

268 269 270
    free( p_sys );
}

271
static int Probe( demux_t *p_demux, bool b_end )
272 273 274 275 276
{
    demux_sys_t *p_sys = p_demux->p_sys;
    int i_ret, i_id;
    block_t *p_pkt;

277
    i_ret = ps_pkt_resynch( p_demux->s, p_sys->format, p_sys->b_have_pack );
278 279
    if( i_ret < 0 )
    {
280
        return VLC_DEMUXER_EOF;
281 282 283 284 285 286
    }
    else if( i_ret == 0 )
    {
        if( !p_sys->b_lost_sync )
            msg_Warn( p_demux, "garbage at input, trying to resync..." );

287
        p_sys->b_lost_sync = true;
288
        return VLC_DEMUXER_SUCCESS;
289 290 291
    }

    if( p_sys->b_lost_sync ) msg_Warn( p_demux, "found sync code" );
292
    p_sys->b_lost_sync = false;
293

294
    if( ( p_pkt = ps_pkt_read( p_demux->s ) ) == NULL )
295
    {
296
        return VLC_DEMUXER_EOF;
297
    }
298 299 300

    i_id = ps_pkt_id( p_pkt );
    if( i_id >= 0xc0 )
301
    {
François Cartegnie's avatar
François Cartegnie committed
302
        ps_track_t *tk = &p_sys->tk[ps_id_to_tk(i_id)];
303 304
        if( !ps_pkt_parse_pes( VLC_OBJECT(p_demux), p_pkt, tk->i_skip ) &&
             p_pkt->i_pts > VLC_TS_INVALID )
305
        {
306 307 308 309 310 311 312 313
            if( b_end && p_pkt->i_pts > tk->i_last_pts )
            {
                tk->i_last_pts = p_pkt->i_pts;
            }
            else if ( tk->i_first_pts == -1 )
            {
                tk->i_first_pts = p_pkt->i_pts;
            }
314 315
        }
    }
316 317 318 319 320
    else if( i_id == PS_STREAM_ID_PACK_HEADER )
    {
        int64_t i_scr; int dummy;
        if( !b_end && !ps_pkt_parse_pack( p_pkt, &i_scr, &dummy ) )
        {
321
            if( p_sys->i_first_scr == -1 )
322 323
                p_sys->i_first_scr = i_scr;
        }
324
        p_sys->b_have_pack = true;
325
    }
326

327
    block_Release( p_pkt );
328
    return VLC_DEMUXER_SUCCESS;
329 330
}

331
static bool FindLength( demux_t *p_demux )
332 333 334 335
{
    demux_sys_t *p_sys = p_demux->p_sys;
    int64_t i_current_pos = -1, i_size = 0, i_end = 0;

Rémi Duraffort's avatar
Rémi Duraffort committed
336
    if( !var_CreateGetBool( p_demux, "ps-trust-timestamps" ) )
337
        return true;
338 339 340

    if( p_sys->i_length == -1 ) /* First time */
    {
341 342
        p_sys->i_length = 0;
        /* Check beginning */
343
        int i = 0;
344
        i_current_pos = vlc_stream_Tell( p_demux->s );
345
        while( i < 40 && Probe( p_demux, false ) > 0 ) i++;
346 347

        /* Check end */
348
        i_size = stream_Size( p_demux->s );
349
        i_end = VLC_CLIP( i_size, 0, 200000 );
350
        if( vlc_stream_Seek( p_demux->s, i_size - i_end ) == VLC_SUCCESS )
351 352
        {
            i = 0;
353
            while( i < 400 && Probe( p_demux, true ) > 0 ) i++;
354
            if( i_current_pos >= 0 &&
355
                vlc_stream_Seek( p_demux->s, i_current_pos ) != VLC_SUCCESS )
356 357 358
                    return false;
        }
        else return false;
359 360
    }

Tobias Güntner's avatar
Tobias Güntner committed
361
    /* Find the longest track */
362
    for( int i = 0; i < PS_TK_COUNT; i++ )
363 364
    {
        ps_track_t *tk = &p_sys->tk[i];
365
        if( tk->i_first_pts >= 0 &&
Tobias Güntner's avatar
Tobias Güntner committed
366 367 368 369
            tk->i_last_pts > tk->i_first_pts )
        {
            int64_t i_length = (int64_t)tk->i_last_pts - tk->i_first_pts;
            if( i_length > p_sys->i_length )
370
            {
Tobias Güntner's avatar
Tobias Güntner committed
371
                p_sys->i_length = i_length;
372
                p_sys->i_time_track_index = i;
373
                msg_Dbg( p_demux, "we found a length of: %"PRId64 "s", p_sys->i_length / CLOCK_FREQ );
374
            }
Tobias Güntner's avatar
Tobias Güntner committed
375
        }
376
    }
377
    return true;
378 379
}

380 381 382 383 384 385
static void NotifyDiscontinuity( ps_track_t *p_tk, es_out_t *out )
{
    bool b_selected;
    for( size_t i = 0; i < PS_TK_COUNT; i++ )
    {
        ps_track_t *tk = &p_tk[i];
386
        if( tk->es &&
387 388 389 390 391 392 393 394
                es_out_Control( out, ES_OUT_GET_ES_STATE, tk->es, &b_selected ) == VLC_SUCCESS
                && b_selected )
        {
            tk->i_next_block_flags |= BLOCK_FLAG_DISCONTINUITY;
        }
    }
}

395 396 397 398 399 400
/*****************************************************************************
 * Demux:
 *****************************************************************************/
static int Demux( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;
401
    int i_ret, i_mux_rate;
402
    block_t *p_pkt;
403

404
    i_ret = ps_pkt_resynch( p_demux->s, p_sys->format, p_sys->b_have_pack );
405 406
    if( i_ret < 0 )
    {
407
        return VLC_DEMUXER_EOF;
408 409 410
    }
    else if( i_ret == 0 )
    {
411
        if( !p_sys->b_lost_sync )
412 413 414 415 416
        {
            msg_Warn( p_demux, "garbage at input from %"PRIu64", trying to resync...",
                                vlc_stream_Tell(p_demux->s) );
            NotifyDiscontinuity( p_sys->tk, p_demux->out );
        }
417

418
        p_sys->b_lost_sync = true;
419
        return VLC_DEMUXER_SUCCESS;
420 421
    }

422
    if( p_sys->b_lost_sync ) msg_Warn( p_demux, "found sync code" );
423
    p_sys->b_lost_sync = false;
424

425
    if( p_sys->i_length < 0 && p_sys->b_seekable )
426 427 428 429
    {
        if( !FindLength( p_demux ) )
            return VLC_DEMUXER_EGENERIC;
    }
430

431
    if( ( p_pkt = ps_pkt_read( p_demux->s ) ) == NULL )
432
    {
433
        return VLC_DEMUXER_EOF;
434 435
    }

436
    if( p_pkt->i_buffer < 4 )
437
    {
438 439 440 441 442 443 444 445
        block_Release( p_pkt );
        return VLC_DEMUXER_EGENERIC;
    }

    const uint8_t i_stream_id = p_pkt->p_buffer[3];
    switch( i_stream_id )
    {
    case PS_STREAM_ID_END_STREAM:
446 447 448
        block_Release( p_pkt );
        break;

449
    case PS_STREAM_ID_PACK_HEADER:
450
        if( !ps_pkt_parse_pack( p_pkt, &p_sys->i_pack_scr, &i_mux_rate ) )
451
        {
452 453 454
            if( p_sys->i_first_scr == -1 )
                p_sys->i_first_scr = p_sys->i_pack_scr;
            p_sys->i_scr = p_sys->i_pack_scr;
455
            p_sys->i_lastpack_byte = vlc_stream_Tell( p_demux->s );
456
            if( !p_sys->b_have_pack ) p_sys->b_have_pack = true;
457
            /* done later on to work around bad vcd/svcd streams */
458
            /* es_out_SetPCR( p_demux->out, p_sys->i_scr ); */
459 460 461 462
            if( i_mux_rate > 0 ) p_sys->i_mux_rate = i_mux_rate;
        }
        block_Release( p_pkt );
        break;
463

464
    case PS_STREAM_ID_SYSTEM_HEADER:
465
        if( !ps_pkt_parse_system( p_pkt, &p_sys->psm, p_sys->tk ) )
466 467 468
        {
            int i;
            for( i = 0; i < PS_TK_COUNT; i++ )
469
            {
470 471
                ps_track_t *tk = &p_sys->tk[i];

472
                if( !tk->b_configured && tk->fmt.i_cat != UNKNOWN_ES )
473
                {
474 475 476
                    if( tk->b_seen )
                        tk->es = es_out_Add( p_demux->out, &tk->fmt );
                     /* else create when seeing packet */
477
                    tk->b_configured = true;
478 479 480
                }
            }
        }
481 482
        block_Release( p_pkt );
        break;
483

484
    case PS_STREAM_ID_MAP:
485 486 487
        if( p_sys->psm.i_version == 0xFFFF )
            msg_Dbg( p_demux, "contains a PSM");

488
        ps_psm_fill( &p_sys->psm, p_pkt, p_sys->tk, p_demux->out );
489 490
        block_Release( p_pkt );
        break;
491

492
    default:
493 494 495 496 497 498 499 500
        /* Reject non video/audio nor PES */
        if( i_stream_id < 0xC0 || i_stream_id > 0xEF )
        {
            block_Release( p_pkt );
            break;
        }
        //ft
    case PS_STREAM_ID_PRIVATE_STREAM1:
501
    case PS_STREAM_ID_EXTENDED:
502
        {
503
            int i_id = ps_pkt_id( p_pkt );
504 505 506 507 508 509 510 511 512 513 514 515 516
            /* Small heuristic to improve MLP detection from AOB */
            if( i_id == 0xa001 &&
                p_sys->i_aob_mlp_count < 500 )
            {
                p_sys->i_aob_mlp_count++;
            }
            else if( i_id == 0xbda1 &&
                     p_sys->i_aob_mlp_count > 0 )
            {
                p_sys->i_aob_mlp_count--;
                i_id = 0xa001;
            }

517
            bool b_new = false;
François Cartegnie's avatar
François Cartegnie committed
518
            ps_track_t *tk = &p_sys->tk[ps_id_to_tk(i_id)];
519

520
            if( !tk->b_configured )
521
            {
522
                if( !ps_track_fill( tk, &p_sys->psm, i_id, p_pkt, false ) )
523
                {
524 525 526 527 528 529 530 531
                    /* No PSM and no probing yet */
                    if( p_sys->format == PSMF_PS )
                    {
                        if( tk->fmt.i_cat == VIDEO_ES )
                            tk->fmt.i_codec = VLC_CODEC_H264;
#if 0
                        if( i_stream_id == PS_STREAM_ID_PRIVATE_STREAM1 )
                        {
532
                            es_format_Change( &tk->fmt, AUDIO_ES, VLC_CODEC_ATRAC3P );
533 534 535 536 537 538 539
                            tk->fmt.audio.i_blockalign = 376;
                            tk->fmt.audio.i_channels = 2;
                            tk->fmt.audio.i_rate = 44100;
                        }
#endif
                    }

540
                    tk->es = es_out_Add( p_demux->out, &tk->fmt );
541
                    b_new = true;
542
                    tk->b_configured = true;
543
                }
544 545 546 547
                else
                {
                    msg_Dbg( p_demux, "es id=0x%x format unknown", i_id );
                }
548
            }
549

550 551 552 553 554 555
            /* Late creation from system header */
            if( !tk->b_seen && tk->b_configured && !tk->es && tk->fmt.i_cat != UNKNOWN_ES )
                tk->es = es_out_Add( p_demux->out, &tk->fmt );

            tk->b_seen = true;

556 557
            /* The popular VCD/SVCD subtitling WinSubMux does not
             * renumber the SCRs when merging subtitles into the PES */
558
            if( tk->b_seen && !p_sys->b_bad_scr &&
559 560
                ( tk->fmt.i_codec == VLC_CODEC_OGT ||
                  tk->fmt.i_codec == VLC_CODEC_CVD ) )
561
            {
562
                p_sys->b_bad_scr = true;
563
                p_sys->i_first_scr = -1;
564 565
            }

566
            if( p_sys->i_pack_scr >= 0 && !p_sys->b_bad_scr )
567
            {
568
                if( (tk->fmt.i_cat == AUDIO_ES || tk->fmt.i_cat == VIDEO_ES) &&
569
                    tk->i_first_pts > VLC_TS_INVALID && tk->i_first_pts - p_sys->i_pack_scr > CLOCK_FREQ )
570 571
                {
                    msg_Warn( p_demux, "Incorrect SCR timing offset by of %ld ms, disabling",
572
                                       tk->i_first_pts - p_sys->i_pack_scr / 1000 );
573
                    p_sys->b_bad_scr = true; /* Disable Offset SCR */
574
                    p_sys->i_first_scr = -1;
575
                }
576
                else
577
                    es_out_SetPCR( p_demux->out, VLC_TS_0 + p_sys->i_pack_scr );
578
            }
579

580
            if( tk->b_configured && tk->es &&
581
                !ps_pkt_parse_pes( VLC_OBJECT(p_demux), p_pkt, tk->i_skip ) )
582
            {
583
                if( tk->fmt.i_cat == AUDIO_ES || tk->fmt.i_cat == VIDEO_ES )
584
                {
585 586 587 588 589 590 591 592 593 594 595 596 597
                    if( !p_sys->b_bad_scr && p_sys->i_pack_scr > 0 && p_pkt->i_pts > 0 &&
                        p_sys->i_pack_scr > p_pkt->i_pts + CLOCK_FREQ / 4 )
                    {
                        msg_Warn( p_demux, "Incorrect SCR timing in advance of %ld ms, disabling",
                                           p_sys->i_pack_scr - p_pkt->i_pts / 1000 );
                        p_sys->b_bad_scr = true;
                        p_sys->i_first_scr = -1;
                    }

                    if( (p_sys->b_bad_scr || !p_sys->b_have_pack) && !p_sys->i_scr_track_id )
                    {
                        p_sys->i_scr_track_id = tk->i_id;
                    }
598 599
                }

600
                if( ((!b_new && !p_sys->b_have_pack) || p_sys->b_bad_scr) &&
601 602
                    p_sys->i_scr_track_id == tk->i_id &&
                    p_pkt->i_pts > VLC_TS_INVALID )
603 604
                {
                    /* A hack to sync the A/V on PES files. */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
605
                    msg_Dbg( p_demux, "force SCR: %"PRId64, p_pkt->i_pts );
606 607 608
                    p_sys->i_scr = p_pkt->i_pts;
                    if( p_sys->i_first_scr == -1 )
                        p_sys->i_first_scr = p_sys->i_scr;
609
                    es_out_SetPCR( p_demux->out, p_pkt->i_pts );
610
                }
611

612
                if( tk->fmt.i_codec == VLC_CODEC_TELETEXT &&
613
                    p_pkt->i_pts <= VLC_TS_INVALID && p_sys->i_scr >= 0 )
614 615 616
                {
                    /* Teletext may have missing PTS (ETSI EN 300 472 Annexe A)
                     * In this case use the last SCR + 40ms */
617
                    p_pkt->i_pts = VLC_TS_0 + p_sys->i_scr + 40000;
618
                }
619

620 621 622 623 624
                if( (int64_t)p_pkt->i_pts > p_sys->i_current_pts )
                {
                    p_sys->i_current_pts = (int64_t)p_pkt->i_pts;
                }

625 626 627 628 629
                if( tk->i_next_block_flags )
                {
                    p_pkt->i_flags = tk->i_next_block_flags;
                    tk->i_next_block_flags = 0;
                }
630 631 632 633 634 635 636
#if 0
                if( tk->fmt.i_codec == VLC_CODEC_ATRAC3P )
                {
                    p_pkt->p_buffer += 14;
                    p_pkt->i_buffer -= 14;
                }
#endif
637
                es_out_Send( p_demux->out, tk->es, p_pkt );
638 639 640 641 642
            }
            else
            {
                block_Release( p_pkt );
            }
643

644
            p_sys->i_pack_scr = -1;
645
        }
646
        break;
647
    }
648

649
    demux_UpdateTitleFromStream( p_demux );
650
    return VLC_DEMUXER_SUCCESS;
651 652 653 654 655 656 657 658 659 660
}

/*****************************************************************************
 * Control:
 *****************************************************************************/
static int Control( demux_t *p_demux, int i_query, va_list args )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    double f, *pf;
    int64_t i64, *pi64;
661
    int i_ret;
662 663 664

    switch( i_query )
    {
665 666 667 668
        case DEMUX_CAN_SEEK:
            *va_arg( args, bool * ) = p_sys->b_seekable;
            return VLC_SUCCESS;

669
        case DEMUX_GET_POSITION:
670
            pf = va_arg( args, double * );
671
            i64 = stream_Size( p_demux->s ) - p_sys->i_start_byte;
672 673
            if( i64 > 0 )
            {
674
                double current = vlc_stream_Tell( p_demux->s ) - p_sys->i_start_byte;
675
                *pf = current / (double)i64;
676 677 678 679 680 681
            }
            else
            {
                *pf = 0.0;
            }
            return VLC_SUCCESS;
682

683
        case DEMUX_SET_POSITION:
684
            f = va_arg( args, double );
685
            i64 = stream_Size( p_demux->s ) - p_sys->i_start_byte;
686
            p_sys->i_current_pts = 0;
687
            p_sys->i_scr = -1;
688

689 690 691 692 693 694 695 696 697 698 699
            if( p_sys->format == CDXA_PS )
            {
                i64 = (int64_t)(i64  * f); /* Align to sector payload */
                i64 = p_sys->i_start_byte + i64 - (i64 % CDXA_SECTOR_SIZE) + CDXA_SECTOR_HEADER_SIZE;
            }
            else
            {
                i64 = p_sys->i_start_byte + (int64_t)(i64 * f);
            }

            i_ret = vlc_stream_Seek( p_demux->s, i64 );
700 701 702 703 704 705
            if( i_ret == VLC_SUCCESS )
            {
                NotifyDiscontinuity( p_sys->tk, p_demux->out );
                return i_ret;
            }
            break;
706 707

        case DEMUX_GET_TIME:
708
            pi64 = va_arg( args, int64_t * );
709
            if( p_sys->i_time_track_index >= 0 && p_sys->i_current_pts > 0 )
710
            {
711
                *pi64 = p_sys->i_current_pts - p_sys->tk[p_sys->i_time_track_index].i_first_pts;
712 713
                return VLC_SUCCESS;
            }
714
            if( p_sys->i_first_scr > -1 && p_sys->i_scr > -1 )
715
            {
716
                *pi64 = p_sys->i_scr - p_sys->i_first_scr;
717
                /* H.222 2.5.2.2 */
718 719 720 721 722
                if( p_sys->i_mux_rate > 0 && p_sys->b_have_pack )
                {
                    uint64_t i_offset = vlc_stream_Tell( p_demux->s ) - p_sys->i_lastpack_byte;
                    *pi64 += CLOCK_FREQ * i_offset / (p_sys->i_mux_rate * 50);
                }
723 724 725
                return VLC_SUCCESS;
            }
            *pi64 = 0;
726
            break;
727 728

        case DEMUX_GET_LENGTH:
729
            pi64 = va_arg( args, int64_t * );
730 731 732 733 734 735
            if( p_sys->i_length > 0 )
            {
                *pi64 = p_sys->i_length;
                return VLC_SUCCESS;
            }
            else if( p_sys->i_mux_rate > 0 )
736
            {
737
                *pi64 = CLOCK_FREQ * ( stream_Size( p_demux->s ) - p_sys->i_start_byte / 50 ) /
738
                    p_sys->i_mux_rate;
739 740 741
                return VLC_SUCCESS;
            }
            *pi64 = 0;
742
            break;
743 744

        case DEMUX_SET_TIME:
745
            i64 = va_arg( args, int64_t );
746
            if( p_sys->i_time_track_index >= 0 && p_sys->i_current_pts > 0 && p_sys->i_length )
747
            {
748
                i64 -= p_sys->tk[p_sys->i_time_track_index].i_first_pts;
749
                return demux_Control( p_demux, DEMUX_SET_POSITION, (double) i64 / p_sys->i_length );
750
            }
751
            break;
752

753 754 755 756 757 758 759
        case DEMUX_GET_TITLE_INFO:
        {
            struct input_title_t ***v = va_arg( args, struct input_title_t*** );
            int *c = va_arg( args, int * );

            *va_arg( args, int* ) = 0; /* Title offset */
            *va_arg( args, int* ) = 0; /* Chapter offset */
760 761
            return vlc_stream_Control( p_demux->s, STREAM_GET_TITLE_INFO, v,
                                       c );
762 763 764
        }

        case DEMUX_SET_TITLE:
765
            return vlc_stream_vaControl( p_demux->s, STREAM_SET_TITLE, args );
766 767

        case DEMUX_SET_SEEKPOINT:
768 769
            return vlc_stream_vaControl( p_demux->s, STREAM_SET_SEEKPOINT,
                                         args );
770

771
        case DEMUX_GET_META:
772
            return vlc_stream_vaControl( p_demux->s, STREAM_GET_META, args );
773

774 775
        case DEMUX_GET_FPS:
        default:
776
            break;
777
    }
778
    return VLC_EGENERIC;
779 780 781 782 783 784
}

/*****************************************************************************
 * Divers:
 *****************************************************************************/

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
785
/* PSResynch: resynch on a system startcode
786 787 788
 *  It doesn't skip more than 512 bytes
 *  -1 -> error, 0 -> not synch, 1 -> ok
 */
789
static int ps_pkt_resynch( stream_t *s, int format, bool b_pack )
790
{
791
    const uint8_t *p_peek;
792 793 794
    int     i_peek;
    int     i_skip;

795
    if( vlc_stream_Peek( s, &p_peek, 4 ) < 4 )
796 797 798
    {
        return -1;
    }
799
    if( p_peek[0] == 0 && p_peek[1] == 0 && p_peek[2] == 1 &&
800
        p_peek[3] >= PS_STREAM_ID_END_STREAM )
801 802 803 804
    {
        return 1;
    }

805
    if( ( i_peek = vlc_stream_Peek( s, &p_peek, 512 ) ) < 4 )
806 807 808 809 810 811 812 813 814 815 816
    {
        return -1;
    }
    i_skip = 0;

    for( ;; )
    {
        if( i_peek < 4 )
        {
            break;
        }
817 818
        /* Handle mid stream 24 bytes padding+CRC creating emulated sync codes with incorrect
           PES sizes and frelling up to UINT16_MAX bytes followed by 24 bytes CDXA Header */
819
        if( format == CDXA_PS && i_skip == 0 && i_peek >= 48 )
820
        {
821 822 823
            const uint8_t cdxasynccode[12] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
                                               0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
            if( !memcmp( &p_peek[24], cdxasynccode, 12 ) )
824
            {
825 826 827 828
                i_peek -= 48;
                p_peek += 48;
                i_skip += 48;
                continue;
829 830
            }
        }
831

832
        if( p_peek[0] == 0 && p_peek[1] == 0 && p_peek[2] == 1 &&
833 834
            p_peek[3] >= PS_STREAM_ID_END_STREAM &&
            ( !b_pack || p_peek[3] == PS_STREAM_ID_PACK_HEADER ) )
835
        {
836
            return vlc_stream_Read( s, NULL, i_skip ) == i_skip ? 1 : -1;
837 838 839 840 841 842
        }

        p_peek++;
        i_peek--;
        i_skip++;
    }
843
    return vlc_stream_Read( s, NULL, i_skip ) == i_skip ? 0 : -1;
844 845
}

846
static block_t *ps_pkt_read( stream_t *s )
847
{
848
    const uint8_t *p_peek;
849
    int i_peek = vlc_stream_Peek( s, &p_peek, 14 );
850 851
    if( i_peek < 4 )
        return NULL;
852

853
    int i_size = ps_pkt_size( p_peek, i_peek );
854
    if( i_size <= 6 && p_peek[3] > PS_STREAM_ID_PACK_HEADER )
855
    {
856 857 858 859
        /* Special case, search the next start code */
        i_size = 6;
        for( ;; )
        {
860