mpegvideo.c 28.2 KB
Newer Older
1
/*****************************************************************************
gbazin's avatar
 
gbazin committed
2
 * mpegvideo.c: parse and packetize an MPEG1/2 video stream
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2001-2006 VLC authors and VideoLAN
5
 * $Id$
6 7 8
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *          Eric Petit <titer@videolan.org>
9
 *          Gildas Bazin <gbazin@videolan.org>
10
 *          Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
11
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
12 13 14
 * 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
15 16 17 18
 * (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
19 20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
21
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
22 23 24
 * 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.
25 26
 *****************************************************************************/

gbazin's avatar
 
gbazin committed
27 28 29 30 31 32 33 34 35 36 37 38 39 40
/*****************************************************************************
 * Problem with this implementation:
 *
 * Although we should time-stamp each picture with a PTS, this isn't possible
 * with the current implementation.
 * The problem comes from the fact that for non-low-delay streams we can't
 * calculate the PTS of pictures used as backward reference. Even the temporal
 * reference number doesn't help here because all the pictures don't
 * necessarily have the same duration (eg. 3:2 pulldown).
 *
 * However this doesn't really matter as far as the MPEG muxers are concerned
 * because they allow having empty PTS fields. --gibalou
 *****************************************************************************/

41 42 43
/*****************************************************************************
 * Preamble
 *****************************************************************************/
44

45 46 47 48
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

49
#include <vlc_common.h>
50
#include <vlc_plugin.h>
zorglub's avatar
zorglub committed
51 52 53
#include <vlc_block.h>
#include <vlc_codec.h>
#include <vlc_block_helper.h>
54
#include "../codec/cc.h"
55
#include "packetizer_helper.h"
56
#include "startcode_helper.h"
gbazin's avatar
 
gbazin committed
57

58
#define SYNC_INTRAFRAME_TEXT N_("Sync on Intra Frame")
59 60
#define SYNC_INTRAFRAME_LONGTEXT N_("Normally the packetizer would " \
    "sync on the next full frame. This flags instructs the packetizer " \
61
    "to sync on the first Intra Frame found.")
62

63 64 65
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
66 67
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );
68

69 70 71 72
vlc_module_begin ()
    set_category( CAT_SOUT )
    set_subcategory( SUBCAT_SOUT_PACKETIZER )
    set_description( N_("MPEG-I/II video packetizer") )
73
    set_shortname( N_("MPEG Video") )
74 75
    set_capability( "packetizer", 50 )
    set_callbacks( Open, Close )
76

77
    add_bool( "packetizer-mpegvideo-sync-iframe", false, SYNC_INTRAFRAME_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
78
              SYNC_INTRAFRAME_LONGTEXT, true )
79
vlc_module_end ()
80 81

/*****************************************************************************
82
 * Local prototypes
83
 *****************************************************************************/
84 85
struct decoder_sys_t
{
gbazin's avatar
 
gbazin committed
86 87 88
    /*
     * Input properties
     */
89
    packetizer_t packetizer;
gbazin's avatar
 
gbazin committed
90

91
    /* Sequence header and extension */
92 93 94
    block_t *p_seq;
    block_t *p_ext;

gbazin's avatar
 
gbazin committed
95
    /* Current frame being built */
96
    block_t    *p_frame;
97 98
    block_t    **pp_last;

99
    bool b_frame_slice;
100 101 102
    mtime_t i_pts;
    mtime_t i_dts;

103 104 105
    date_t  dts;
    date_t  prev_iframe_dts;

gbazin's avatar
 
gbazin committed
106
    /* Sequence properties */
107 108
    unsigned    i_frame_rate;
    unsigned    i_frame_rate_base;
109 110
    bool  b_seq_progressive;
    bool  b_low_delay;
gbazin's avatar
 
gbazin committed
111
    int         i_aspect_ratio_info;
112
    bool  b_inited;
113

gbazin's avatar
 
gbazin committed
114
    /* Picture properties */
115
    int i_temporal_ref;
116
    int i_prev_temporal_ref;
117 118 119 120 121 122 123
    int i_picture_type;
    int i_picture_structure;
    int i_top_field_first;
    int i_repeat_first_field;
    int i_progressive_frame;

    mtime_t i_last_ref_pts;
124 125 126 127

    mtime_t i_last_frame_pts;
    uint16_t i_last_frame_refid;

128
    bool b_second_field;
gbazin's avatar
 
gbazin committed
129

130
    /* Number of pictures since last sequence header */
131
    unsigned i_seq_old;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
132

133
    /* Sync behaviour */
134
    bool  b_sync_on_intra_frame;
135 136
    bool  b_waiting_iframe;
    int   i_next_block_flags;
137 138

    /* */
139
    bool b_cc_reset;
140 141
    uint32_t i_cc_flags;
    mtime_t i_cc_pts;
Laurent Aimar's avatar
Laurent Aimar committed
142
    mtime_t i_cc_dts;
143
    cc_data_t cc;
gbazin's avatar
 
gbazin committed
144 145
};

146
static block_t *Packetize( decoder_t *, block_t ** );
147
static void PacketizeFlush( decoder_t * );
148 149 150 151 152 153 154 155 156
static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] );

static void PacketizeReset( void *p_private, bool b_broken );
static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t * );
static int PacketizeValidate( void *p_private, block_t * );

static block_t *ParseMPEGBlock( decoder_t *, block_t * );

static const uint8_t p_mp2v_startcode[3] = { 0x00, 0x00, 0x01 };
157 158

/*****************************************************************************
159
 * Open:
160
 *****************************************************************************/
161
static int Open( vlc_object_t *p_this )
162
{
163 164
    decoder_t *p_dec = (decoder_t*)p_this;
    decoder_sys_t *p_sys;
165

166
    if( p_dec->fmt_in.i_codec != VLC_CODEC_MPGV )
167
        return VLC_EGENERIC;
168

169
    es_format_Init( &p_dec->fmt_out, VIDEO_ES, VLC_CODEC_MPGV );
170 171
    p_dec->fmt_out.i_original_fourcc = p_dec->fmt_in.i_original_fourcc;

172

173
    p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
174 175 176
    if( !p_dec->p_sys )
        return VLC_ENOMEM;
    memset( p_dec->p_sys, 0, sizeof( decoder_sys_t ) );
177

gbazin's avatar
 
gbazin committed
178
    /* Misc init */
179
    packetizer_Init( &p_sys->packetizer,
180
                     p_mp2v_startcode, sizeof(p_mp2v_startcode), startcode_FindAnnexB,
181
                     NULL, 0, 4,
182
                     PacketizeReset, PacketizeParse, PacketizeValidate, p_dec );
gbazin's avatar
 
gbazin committed
183

184 185 186
    p_sys->p_seq = NULL;
    p_sys->p_ext = NULL;
    p_sys->p_frame = NULL;
187
    p_sys->pp_last = &p_sys->p_frame;
188
    p_sys->b_frame_slice = false;
189

190 191 192 193 194 195
    p_sys->i_dts =
    p_sys->i_pts = VLC_TS_INVALID;
    date_Init( &p_sys->dts, 1, 1 );
    date_Set( &p_sys->dts, VLC_TS_INVALID );
    date_Init( &p_sys->prev_iframe_dts, 1, 1 );
    date_Set( &p_sys->prev_iframe_dts, VLC_TS_INVALID );
196

197 198
    p_sys->i_frame_rate = 2 * 30000;
    p_sys->i_frame_rate_base = 1001;
199 200
    p_sys->b_seq_progressive = true;
    p_sys->b_low_delay = true;
201
    p_sys->i_seq_old = 0;
202

203
    p_sys->i_temporal_ref = 0;
204
    p_sys->i_prev_temporal_ref = 2048;
205 206 207 208 209
    p_sys->i_picture_type = 0;
    p_sys->i_picture_structure = 0x03; /* frame */
    p_sys->i_top_field_first = 0;
    p_sys->i_repeat_first_field = 0;
    p_sys->i_progressive_frame = 0;
210
    p_sys->b_inited = 0;
211

212
    p_sys->i_last_ref_pts = VLC_TS_INVALID;
213
    p_sys->b_second_field = 0;
214

215 216
    p_sys->i_next_block_flags = 0;

217 218
    p_sys->i_last_frame_refid = 0;

219
    p_sys->b_waiting_iframe =
220 221
    p_sys->b_sync_on_intra_frame = var_CreateGetBool( p_dec, "packetizer-mpegvideo-sync-iframe" );
    if( p_sys->b_sync_on_intra_frame )
222
        msg_Dbg( p_dec, "syncing on intra frame now" );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
223

224
    p_sys->b_cc_reset = false;
225
    p_sys->i_cc_pts = 0;
Laurent Aimar's avatar
Laurent Aimar committed
226
    p_sys->i_cc_dts = 0;
227 228 229
    p_sys->i_cc_flags = 0;
    cc_Init( &p_sys->cc );

230
    p_dec->pf_packetize = Packetize;
231
    p_dec->pf_flush = PacketizeFlush;
232 233
    p_dec->pf_get_cc = GetCc;

234
    return VLC_SUCCESS;
235 236 237
}

/*****************************************************************************
238
 * Close:
239
 *****************************************************************************/
240
static void Close( vlc_object_t *p_this )
241
{
242 243
    decoder_t     *p_dec = (decoder_t*)p_this;
    decoder_sys_t *p_sys = p_dec->p_sys;
244

245
    if( p_sys->p_seq )
246
    {
247
        block_Release( p_sys->p_seq );
248
    }
249
    if( p_sys->p_ext )
250
    {
251 252 253 254
        block_Release( p_sys->p_ext );
    }
    if( p_sys->p_frame )
    {
gbazin's avatar
 
gbazin committed
255
        block_ChainRelease( p_sys->p_frame );
256
    }
257
    packetizer_Clean( &p_sys->packetizer );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
258

259
    var_Destroy( p_dec, "packetizer-mpegvideo-sync-iframe" );
gbazin's avatar
 
gbazin committed
260

261
    free( p_sys );
262 263 264
}

/*****************************************************************************
265
 * Packetize:
266
 *****************************************************************************/
267
static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
268
{
269
    decoder_sys_t *p_sys = p_dec->p_sys;
270

271
    return packetizer_Packetize( &p_sys->packetizer, pp_block );
gbazin's avatar
 
gbazin committed
272 273
}

274 275 276 277 278 279 280
static void PacketizeFlush( decoder_t *p_dec )
{
    decoder_sys_t *p_sys = p_dec->p_sys;

    packetizer_Flush( &p_sys->packetizer );
}

281 282 283
/*****************************************************************************
 * GetCc:
 *****************************************************************************/
284
static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] )
285 286 287 288 289 290 291 292 293 294 295
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t *p_cc;
    int i;

    for( i = 0; i < 4; i++ )
        pb_present[i] = p_sys->cc.pb_present[i];

    if( p_sys->cc.i_data <= 0 )
        return NULL;

296
    p_cc = block_Alloc( p_sys->cc.i_data );
297 298 299 300
    if( p_cc )
    {
        memcpy( p_cc->p_buffer, p_sys->cc.p_data, p_sys->cc.i_data );
        p_cc->i_dts = 
Laurent Aimar's avatar
Laurent Aimar committed
301
        p_cc->i_pts = p_sys->cc.b_reorder ? p_sys->i_cc_pts : p_sys->i_cc_dts;
302
        p_cc->i_flags = ( p_sys->cc.b_reorder ? p_sys->i_cc_flags : BLOCK_FLAG_TYPE_P ) & ( BLOCK_FLAG_TYPE_I|BLOCK_FLAG_TYPE_P|BLOCK_FLAG_TYPE_B);
303 304 305 306 307
    }
    cc_Flush( &p_sys->cc );
    return p_cc;
}

308 309 310 311 312
/*****************************************************************************
 * Helpers:
 *****************************************************************************/
static void PacketizeReset( void *p_private, bool b_broken )
{
313
    VLC_UNUSED(b_broken);
314 315 316
    decoder_t *p_dec = p_private;
    decoder_sys_t *p_sys = p_dec->p_sys;

317 318
    p_sys->i_next_block_flags = BLOCK_FLAG_DISCONTINUITY;
    if( p_sys->p_frame )
319
    {
320
        block_ChainRelease( p_sys->p_frame );
321 322 323 324
        p_sys->p_frame = NULL;
        p_sys->pp_last = &p_sys->p_frame;
        p_sys->b_frame_slice = false;
    }
325 326
    date_Set( &p_sys->dts, VLC_TS_INVALID );
    date_Set( &p_sys->prev_iframe_dts, VLC_TS_INVALID );
327 328 329
    p_sys->i_dts =
    p_sys->i_pts =
    p_sys->i_last_ref_pts = VLC_TS_INVALID;
330
    p_sys->b_waiting_iframe = p_sys->b_sync_on_intra_frame;
331
    p_sys->i_prev_temporal_ref = 2048;
332 333 334 335 336
}

static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t *p_block )
{
    decoder_t *p_dec = p_private;
337
    decoder_sys_t *p_sys = p_dec->p_sys;
338 339

    /* Check if we have a picture start code */
340
    *pb_ts_used = p_block->p_buffer[3] == 0x00;
341

342 343 344 345 346 347 348
    p_block = ParseMPEGBlock( p_dec, p_block );
    if( p_block )
    {
        p_block->i_flags |= p_sys->i_next_block_flags;
        p_sys->i_next_block_flags = 0;
    }
    return p_block;
349 350 351 352 353 354 355 356
}


static int PacketizeValidate( void *p_private, block_t *p_au )
{
    decoder_t *p_dec = p_private;
    decoder_sys_t *p_sys = p_dec->p_sys;

357
    if( unlikely( p_sys->b_waiting_iframe ) )
358 359 360 361 362 363 364
    {
        if( (p_au->i_flags & BLOCK_FLAG_TYPE_I) == 0 )
        {
            msg_Dbg( p_dec, "waiting on intra frame" );
            return VLC_EGENERIC;
        }
        msg_Dbg( p_dec, "synced on intra frame" );
365
        p_sys->b_waiting_iframe = false;
366 367 368 369
    }

    /* We've just started the stream, wait for the first PTS.
     * We discard here so we can still get the sequence header. */
370
    if( unlikely( p_sys->i_dts <= VLC_TS_INVALID && p_sys->i_pts <= VLC_TS_INVALID &&
371
        date_Get( &p_sys->dts ) <= VLC_TS_INVALID ))
372 373 374 375 376 377
    {
        msg_Dbg( p_dec, "need a starting pts/dts" );
        return VLC_EGENERIC;
    }

    /* When starting the stream we can have the first frame with
378
     * an invalid DTS (i_interpolated_pts is initialized to VLC_TS_INVALID) */
379
    if( unlikely( p_au->i_dts <= VLC_TS_INVALID ) )
380 381 382 383
        p_au->i_dts = p_au->i_pts;

    return VLC_SUCCESS;
}
gbazin's avatar
 
gbazin committed
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
/*****************************************************************************
 * ParseMPEGBlock: Re-assemble fragments into a block containing a picture
 *****************************************************************************/
static block_t *ParseMPEGBlock( decoder_t *p_dec, block_t *p_frag )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t *p_pic = NULL;

    /*
     * Check if previous picture is finished
     */
    if( ( p_sys->b_frame_slice &&
          (p_frag->p_buffer[3] == 0x00 || p_frag->p_buffer[3] > 0xaf) ) &&
          p_sys->p_seq == NULL )
    {
        /* We have a picture but without a sequence header we can't
         * do anything */
        msg_Dbg( p_dec, "waiting for sequence start" );
        if( p_sys->p_frame ) block_ChainRelease( p_sys->p_frame );
        p_sys->p_frame = NULL;
404
        p_sys->pp_last = &p_sys->p_frame;
405
        p_sys->b_frame_slice = false;
gbazin's avatar
 
gbazin committed
406 407 408 409 410

    }
    else if( p_sys->b_frame_slice &&
             (p_frag->p_buffer[3] == 0x00 || p_frag->p_buffer[3] > 0xaf) )
    {
411 412 413 414 415 416 417 418
        const bool b_eos = p_frag->p_buffer[3] == 0xb7;

        if( b_eos )
        {
            block_ChainLastAppend( &p_sys->pp_last, p_frag );
            p_frag = NULL;
        }

gbazin's avatar
 
gbazin committed
419 420
        p_pic = block_ChainGather( p_sys->p_frame );

421 422 423
        if( b_eos )
            p_pic->i_flags |= BLOCK_FLAG_END_OF_SEQUENCE;

424
        unsigned i_num_fields;
gbazin's avatar
 
gbazin committed
425

426 427 428 429
        if( !p_sys->b_seq_progressive && p_sys->i_picture_structure != 0x03 /* Field Picture */ )
            i_num_fields = 1;
        else
            i_num_fields = 2;
gbazin's avatar
 
gbazin committed
430 431 432 433 434

        if( p_sys->b_seq_progressive )
        {
            if( p_sys->i_top_field_first == 0 &&
                p_sys->i_repeat_first_field == 1 )
435
            {
436
                i_num_fields *= 2;
437
            }
gbazin's avatar
 
gbazin committed
438 439
            else if( p_sys->i_top_field_first == 1 &&
                     p_sys->i_repeat_first_field == 1 )
gbazin's avatar
 
gbazin committed
440
            {
441
                i_num_fields *= 3;
gbazin's avatar
 
gbazin committed
442 443 444 445
            }
        }
        else
        {
446
            if( p_sys->i_picture_structure == 0x03 /* Frame Picture */ )
gbazin's avatar
 
gbazin committed
447 448
            {
                if( p_sys->i_progressive_frame && p_sys->i_repeat_first_field )
449
                {
450
                    i_num_fields += 1;
451
                }
gbazin's avatar
 
gbazin committed
452 453
            }
        }
454

455 456 457 458 459 460 461 462 463 464 465 466 467
        switch ( p_sys->i_picture_type )
        {
        case 0x01:
            p_pic->i_flags |= BLOCK_FLAG_TYPE_I;
            break;
        case 0x02:
            p_pic->i_flags |= BLOCK_FLAG_TYPE_P;
            break;
        case 0x03:
            p_pic->i_flags |= BLOCK_FLAG_TYPE_B;
            break;
        }

468
        if( !p_sys->b_seq_progressive )
469
        {
470 471 472 473 474 475 476 477 478 479 480
            if( p_sys->i_picture_structure < 0x03 )
            {
                p_pic->i_flags |= BLOCK_FLAG_SINGLE_FIELD;
                p_pic->i_flags |= (p_sys->i_picture_structure == 0x01) ? BLOCK_FLAG_TOP_FIELD_FIRST
                                                                       : BLOCK_FLAG_BOTTOM_FIELD_FIRST;
            }
            else /* if( p_sys->i_picture_structure == 0x03 ) */
            {
                p_pic->i_flags |= (p_sys->i_top_field_first) ? BLOCK_FLAG_TOP_FIELD_FIRST
                                                             : BLOCK_FLAG_BOTTOM_FIELD_FIRST;
            }
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
        }

        /* Special case for DVR-MS where we need to fully build pts from scratch
         * and only use first dts as it does not monotonically increase
         * This will NOT work with frame repeats and such, as we would need to fully
         * fill the DPB to get accurate pts timings. */
        if( unlikely( p_dec->fmt_in.i_original_fourcc == VLC_FOURCC( 'D','V','R',' ') ) )
        {
            const bool b_first_xmited = (p_sys->i_prev_temporal_ref != p_sys->i_temporal_ref );

            if( ( p_pic->i_flags & BLOCK_FLAG_TYPE_I ) && b_first_xmited )
            {
                if( date_Get( &p_sys->prev_iframe_dts ) == VLC_TS_INVALID )
                {
                    if( p_sys->i_dts != VLC_TS_INVALID )
                    {
                        date_Set( &p_sys->dts, p_sys->i_dts );
                    }
                    else
                    {
                        if( date_Get( &p_sys->dts ) == VLC_TS_INVALID )
                        {
                            date_Set( &p_sys->dts, VLC_TS_0 );
                        }
                    }
                }
                p_sys->prev_iframe_dts = p_sys->dts;
            }

            p_pic->i_dts = date_Get( &p_sys->dts );

            /* Compute pts from poc */
            date_t datepts = p_sys->prev_iframe_dts;
            date_Increment( &datepts, (1 + p_sys->i_temporal_ref) * 2 );

            /* Field picture second field case */
            if( p_sys->i_picture_structure != 0x03 )
            {
                /* first sent is not the first in display order */
                if( (p_sys->i_picture_structure >> 1) != !p_sys->i_top_field_first &&
                        b_first_xmited )
                {
                    date_Increment( &datepts, 2 );
                }
            }

            p_pic->i_pts = date_Get( &datepts );

            date_Increment( &p_sys->dts,  i_num_fields );

            p_pic->i_length = date_Get( &p_sys->dts ) - p_pic->i_dts;
            p_sys->i_prev_temporal_ref = p_sys->i_temporal_ref;
        }
        else /* General case, use demuxer's dts/pts when set or interpolate */
        {
            if( p_sys->b_low_delay || p_sys->i_picture_type == 0x03 )
            {
                /* Trivial case (DTS == PTS) */
                /* Correct interpolated dts when we receive a new pts/dts */
                if( p_sys->i_pts > VLC_TS_INVALID )
                    date_Set( &p_sys->dts, p_sys->i_pts );
                if( p_sys->i_dts > VLC_TS_INVALID )
                    date_Set( &p_sys->dts, p_sys->i_dts );
            }
            else
            {
                /* Correct interpolated dts when we receive a new pts/dts */
                if(p_sys->i_last_ref_pts > VLC_TS_INVALID && !p_sys->b_second_field)
                    date_Set( &p_sys->dts, p_sys->i_last_ref_pts );
                if( p_sys->i_dts > VLC_TS_INVALID )
                    date_Set( &p_sys->dts, p_sys->i_dts );

                if( !p_sys->b_second_field )
                    p_sys->i_last_ref_pts = p_sys->i_pts;
            }

            p_pic->i_dts = date_Get( &p_sys->dts );

            /* Set PTS only if we have a B frame or if it comes from the stream */
            if( p_sys->i_pts > VLC_TS_INVALID )
            {
                p_pic->i_pts = p_sys->i_pts;
            }
            else if( p_sys->i_picture_type == 0x03 )
            {
                p_pic->i_pts = p_pic->i_dts;
            }
            else
            {
                p_pic->i_pts = VLC_TS_INVALID;
            }

            date_Increment( &p_sys->dts,  i_num_fields );

            p_pic->i_length = date_Get( &p_sys->dts ) - p_pic->i_dts;
        }
577

578
#if 0
579 580 581 582
        msg_Dbg( p_dec, "pic: type=%d ref=%d nf=%d tff=%d dts=%"PRId64" ptsdiff=%"PRId64" len=%"PRId64,
                 p_sys->i_picture_structure, p_sys->i_temporal_ref, i_num_fields,
                 p_sys->i_top_field_first,
                 p_pic->i_dts , (p_pic->i_pts > VLC_TS_INVALID) ? p_pic->i_pts - p_pic->i_dts : 0, p_pic->i_length );
583
#endif
gbazin's avatar
 
gbazin committed
584

585

gbazin's avatar
 
gbazin committed
586 587
        /* Reset context */
        p_sys->p_frame = NULL;
588
        p_sys->pp_last = &p_sys->p_frame;
589
        p_sys->b_frame_slice = false;
590 591 592 593 594 595 596 597 598

        if( p_sys->i_picture_structure != 0x03 )
        {
            p_sys->b_second_field = !p_sys->b_second_field;
        }
        else
        {
            p_sys->b_second_field = 0;
        }
599 600

        /* CC */
601
        p_sys->b_cc_reset = true;
602
        p_sys->i_cc_pts = p_pic->i_pts;
Laurent Aimar's avatar
Laurent Aimar committed
603
        p_sys->i_cc_dts = p_pic->i_dts;
604 605 606 607 608
        p_sys->i_cc_flags = p_pic->i_flags;
    }

    if( !p_pic && p_sys->b_cc_reset )
    {
609
        p_sys->b_cc_reset = false;
610
        cc_Flush( &p_sys->cc );
gbazin's avatar
 
gbazin committed
611 612
    }

613 614
    if( !p_frag )
        return p_pic;
gbazin's avatar
 
gbazin committed
615 616 617 618 619 620 621 622 623
    /*
     * Check info of current fragment
     */
    if( p_frag->p_buffer[3] == 0xb8 )
    {
        /* Group start code */
        if( p_sys->p_seq &&
            p_sys->i_seq_old > p_sys->i_frame_rate/p_sys->i_frame_rate_base )
        {
ivoire's avatar
ivoire committed
624
            /* Useful for mpeg1: repeat sequence header every second */
625
            block_ChainLastAppend( &p_sys->pp_last, block_Duplicate( p_sys->p_seq ) );
gbazin's avatar
 
gbazin committed
626
            if( p_sys->p_ext )
627
            {
628
                block_ChainLastAppend( &p_sys->pp_last, block_Duplicate( p_sys->p_ext ) );
629
            }
gbazin's avatar
 
gbazin committed
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644

            p_sys->i_seq_old = 0;
        }
    }
    else if( p_frag->p_buffer[3] == 0xb3 && p_frag->i_buffer >= 8 )
    {
        /* Sequence header code */
        static const int code_to_frame_rate[16][2] =
        {
            { 1, 1 },  /* invalid */
            { 24000, 1001 }, { 24, 1 }, { 25, 1 },       { 30000, 1001 },
            { 30, 1 },       { 50, 1 }, { 60000, 1001 }, { 60, 1 },
            /* Unofficial 15fps from Xing*/
            { 15, 1001 },
            /* Unofficial economy rates from libmpeg3 */
645
            { 5000, 1001 }, { 1000, 1001 }, { 12000, 1001 }, { 15000, 1001 },
gbazin's avatar
 
gbazin committed
646 647 648 649 650 651 652 653 654 655
            { 1, 1 },  { 1, 1 }  /* invalid */
        };

        if( p_sys->p_seq ) block_Release( p_sys->p_seq );
        if( p_sys->p_ext ) block_Release( p_sys->p_ext );

        p_sys->p_seq = block_Duplicate( p_frag );
        p_sys->i_seq_old = 0;
        p_sys->p_ext = NULL;

656
        p_dec->fmt_out.video.i_visible_width =
gbazin's avatar
 
gbazin committed
657
            ( p_frag->p_buffer[4] << 4)|(p_frag->p_buffer[5] >> 4 );
658 659
        p_dec->fmt_out.video.i_width = (p_dec->fmt_out.video.i_visible_width + 0x0F) & ~0x0F;
        p_dec->fmt_out.video.i_visible_height =
gbazin's avatar
 
gbazin committed
660
            ( (p_frag->p_buffer[5]&0x0f) << 8 )|p_frag->p_buffer[6];
661 662 663 664
        if( p_sys->b_seq_progressive )
            p_dec->fmt_out.video.i_height = (p_dec->fmt_out.video.i_visible_height + 0x0F) & ~0x0F;
        else
            p_dec->fmt_out.video.i_height = (p_dec->fmt_out.video.i_visible_height + 0x1F) & ~0x1F;
gbazin's avatar
 
gbazin committed
665 666 667 668 669 670 671 672
        p_sys->i_aspect_ratio_info = p_frag->p_buffer[7] >> 4;

        /* TODO: MPEG1 aspect ratio */

        p_sys->i_frame_rate = code_to_frame_rate[p_frag->p_buffer[7]&0x0f][0];
        p_sys->i_frame_rate_base =
            code_to_frame_rate[p_frag->p_buffer[7]&0x0f][1];

673 674 675
        if( ( p_sys->i_frame_rate != p_dec->fmt_out.video.i_frame_rate ||
              p_dec->fmt_out.video.i_frame_rate_base != p_sys->i_frame_rate_base ) &&
            p_sys->i_frame_rate && p_sys->i_frame_rate_base )
676 677 678 679
        {
            date_Change( &p_sys->dts, 2 * p_sys->i_frame_rate, p_sys->i_frame_rate_base );
            date_Change( &p_sys->prev_iframe_dts, 2 * p_sys->i_frame_rate, p_sys->i_frame_rate_base );
        }
680 681 682
        p_dec->fmt_out.video.i_frame_rate = p_sys->i_frame_rate;
        p_dec->fmt_out.video.i_frame_rate_base = p_sys->i_frame_rate_base;

683 684
        p_sys->b_seq_progressive = true;
        p_sys->b_low_delay = true;
gbazin's avatar
 
gbazin committed
685

686

687 688
        if ( !p_sys->b_inited )
        {
689 690
            msg_Dbg( p_dec, "size %dx%d/%dx%d fps=%.3f",
                 p_dec->fmt_out.video.i_visible_width, p_dec->fmt_out.video.i_visible_height,
gbazin's avatar
 
gbazin committed
691
                 p_dec->fmt_out.video.i_width, p_dec->fmt_out.video.i_height,
692
                 p_sys->i_frame_rate / (float)(p_sys->i_frame_rate_base ? p_sys->i_frame_rate_base : 1) );
693 694
            p_sys->b_inited = 1;
        }
gbazin's avatar
 
gbazin committed
695 696 697 698 699
    }
    else if( p_frag->p_buffer[3] == 0xb5 )
    {
        int i_type = p_frag->p_buffer[4] >> 4;

700
        /* Extension start code */
gbazin's avatar
 
gbazin committed
701 702
        if( i_type == 0x01 )
        {
703
#if 0
gbazin's avatar
 
gbazin committed
704
            static const int mpeg2_aspect[16][2] =
705
            {
gbazin's avatar
 
gbazin committed
706 707 708 709
                {0,1}, {1,1}, {4,3}, {16,9}, {221,100},
                {0,1}, {0,1}, {0,1}, {0,1}, {0,1}, {0,1}, {0,1}, {0,1}, {0,1},
                {0,1}, {0,1}
            };
710
#endif
711

712
            /* sequence extension */
gbazin's avatar
 
gbazin committed
713 714 715 716
            if( p_sys->p_ext) block_Release( p_sys->p_ext );
            p_sys->p_ext = block_Duplicate( p_frag );

            if( p_frag->i_buffer >= 10 )
717
            {
gbazin's avatar
 
gbazin committed
718
                p_sys->b_seq_progressive =
719
                    p_frag->p_buffer[5]&0x08 ? true : false;
gbazin's avatar
 
gbazin committed
720
                p_sys->b_low_delay =
721
                    p_frag->p_buffer[9]&0x80 ? true : false;
gbazin's avatar
 
gbazin committed
722
            }
723

724 725 726 727 728 729 730
            /* Do not set aspect ratio : in case we're transcoding,
             * transcode will take our fmt_out as a fmt_in to libmpeg2.
             * libmpeg2.c will then believe that the user has requested
             * a specific aspect ratio, which she hasn't. Thus in case
             * of aspect ratio change, we're screwed. --Meuuh
             */
#if 0
Laurent Aimar's avatar
Laurent Aimar committed
731
            p_dec->fmt_out.video.i_sar_num =
gbazin's avatar
 
gbazin committed
732
                mpeg2_aspect[p_sys->i_aspect_ratio_info][0] *
Laurent Aimar's avatar
Laurent Aimar committed
733 734 735 736
                p_dec->fmt_out.video.i_height;
            p_dec->fmt_out.video.i_sar_den =
                mpeg2_aspect[p_sys->i_aspect_ratio_info][1] *
                p_dec->fmt_out.video.i_width;
737
#endif
gbazin's avatar
 
gbazin committed
738 739

        }
740
        else if( i_type == 0x08 && p_frag->i_buffer > 8 )
gbazin's avatar
 
gbazin committed
741
        {
742
            /* picture extension */
gbazin's avatar
 
gbazin committed
743 744 745 746
            p_sys->i_picture_structure = p_frag->p_buffer[6]&0x03;
            p_sys->i_top_field_first   = p_frag->p_buffer[7] >> 7;
            p_sys->i_repeat_first_field= (p_frag->p_buffer[7]>>1)&0x01;
            p_sys->i_progressive_frame = p_frag->p_buffer[8] >> 7;
747
        }
748
        else if( i_type == 0x02 && p_frag->i_buffer > 8 )
749 750 751 752 753
        {
            /* Sequence display extension */
            bool contains_color_description = (p_frag->p_buffer[4] & 0x01);
            //uint8_t video_format = (p_frag->p_buffer[4] & 0x0f) >> 1;

754
            if( contains_color_description && p_frag->i_buffer > 11 )
755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
            {
                uint8_t color_primaries = p_frag->p_buffer[5];
                uint8_t color_transfer  = p_frag->p_buffer[6];
                uint8_t color_matrix    = p_frag->p_buffer[7];
                switch( color_primaries )
                {
                    case 1:
                        p_dec->fmt_out.video.primaries = COLOR_PRIMARIES_BT709;
                        break;
                    case 4: /* BT.470M    */
                    case 5: /* BT.470BG   */
                        p_dec->fmt_out.video.primaries = COLOR_PRIMARIES_BT601_625;
                        break;
                    case 6: /* SMPTE 170M */
                    case 7: /* SMPTE 240M */
                        p_dec->fmt_out.video.primaries = COLOR_PRIMARIES_BT601_525;
                        break;
                    default:
                        break;
                }
                switch( color_transfer )
                {
                    case 1:
                        p_dec->fmt_out.video.transfer = TRANSFER_FUNC_BT709;
                        break;
                    case 4: /* BT.470M assumed gamma 2.2  */
                        p_dec->fmt_out.video.transfer = TRANSFER_FUNC_SRGB;
                        break;
                    case 5: /* BT.470BG */
                    case 6: /* SMPTE 170M */
                        p_dec->fmt_out.video.transfer = TRANSFER_FUNC_BT2020;
                        break;
                    case 8: /* Linear */
                        p_dec->fmt_out.video.transfer = TRANSFER_FUNC_LINEAR;
                        break;
                    default:
                        break;
                }
                switch( color_matrix )
                {
                    case 1:
                        p_dec->fmt_out.video.space = COLOR_SPACE_BT709;
                        break;
                    case 5: /* BT.470BG */
                    case 6: /* SMPTE 170 M */
                        p_dec->fmt_out.video.space = COLOR_SPACE_BT601;
                        break;
                    default:
                        break;
                }
            }

        }
808
    }
809 810
    else if( p_frag->p_buffer[3] == 0xb2 && p_frag->i_buffer > 4 )
    {
811
        cc_ProbeAndExtract( &p_sys->cc, p_sys->i_top_field_first,
812
                    &p_frag->p_buffer[4], p_frag->i_buffer - 4 );
813
    }
gbazin's avatar
 
gbazin committed
814
    else if( p_frag->p_buffer[3] == 0x00 )
815
    {
gbazin's avatar
 
gbazin committed
816 817 818 819
        /* Picture start code */
        p_sys->i_seq_old++;

        if( p_frag->i_buffer >= 6 )
820
        {
gbazin's avatar
 
gbazin committed
821 822 823
            p_sys->i_temporal_ref =
                ( p_frag->p_buffer[4] << 2 )|(p_frag->p_buffer[5] >> 6);
            p_sys->i_picture_type = ( p_frag->p_buffer[5] >> 3 ) & 0x03;
824 825
        }

gbazin's avatar
 
gbazin committed
826 827 828 829 830 831
        p_sys->i_dts = p_frag->i_dts;
        p_sys->i_pts = p_frag->i_pts;
    }
    else if( p_frag->p_buffer[3] >= 0x01 && p_frag->p_buffer[3] <= 0xaf )
    {
        /* Slice start code */
832
        p_sys->b_frame_slice = true;
gbazin's avatar
 
gbazin committed
833
    }
834

gbazin's avatar
 
gbazin committed
835
    /* Append the block */
836
    block_ChainLastAppend( &p_sys->pp_last, p_frag );
837

gbazin's avatar
 
gbazin committed
838 839
    return p_pic;
}