libmpeg2.c 23.5 KB
Newer Older
gbazin's avatar
 
gbazin committed
1 2 3
/*****************************************************************************
 * libmpeg2.c: mpeg2 video decoder module making use of libmpeg2.
 *****************************************************************************
4
 * Copyright (C) 1999-2001 the VideoLAN team
5
 * $Id$
gbazin's avatar
 
gbazin committed
6
 *
7
 * Authors: Gildas Bazin <gbazin@videolan.org>
gbazin's avatar
 
gbazin committed
8
 *          Christophe Massiot <massiot@via.ecp.fr>
gbazin's avatar
 
gbazin committed
9 10 11 12 13
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
Sam Hocevar's avatar
Sam Hocevar committed
14
 *
gbazin's avatar
 
gbazin committed
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/decoder.h>

#include <mpeg2dec/mpeg2.h>

34 35
#include "vout_synchro.h"

gbazin's avatar
 
gbazin committed
36 37 38 39 40 41 42
/* Aspect ratio (ISO/IEC 13818-2 section 6.3.3, table 6-3) */
#define AR_SQUARE_PICTURE       1                           /* square pixels */
#define AR_3_4_PICTURE          2                        /* 3:4 picture (TV) */
#define AR_16_9_PICTURE         3              /* 16:9 picture (wide screen) */
#define AR_221_1_PICTURE        4                  /* 2.21:1 picture (movie) */

/*****************************************************************************
gbazin's avatar
 
gbazin committed
43
 * decoder_sys_t : libmpeg2 decoder descriptor
gbazin's avatar
 
gbazin committed
44
 *****************************************************************************/
gbazin's avatar
 
gbazin committed
45
struct decoder_sys_t
gbazin's avatar
 
gbazin committed
46 47 48 49 50 51
{
    /*
     * libmpeg2 properties
     */
    mpeg2dec_t          *p_mpeg2dec;
    const mpeg2_info_t  *p_info;
52
    vlc_bool_t          b_skip;
gbazin's avatar
 
gbazin committed
53 54 55 56 57 58

    /*
     * Input properties
     */
    mtime_t          i_previous_pts;
    mtime_t          i_current_pts;
59 60
    mtime_t          i_previous_dts;
    mtime_t          i_current_dts;
61 62
    int              i_current_rate;
    picture_t *      p_picture_to_destroy;
63 64 65 66
    vlc_bool_t       b_garbage_pic;
    vlc_bool_t       b_after_sequence_header; /* is it the next frame after
                                               * the sequence header ?    */
    vlc_bool_t       b_slice_i;             /* intra-slice refresh stream */
gbazin's avatar
 
gbazin committed
67

Laurent Aimar's avatar
Laurent Aimar committed
68 69
    vlc_bool_t      b_preroll;

gbazin's avatar
 
gbazin committed
70 71 72
    /*
     * Output properties
     */
73
    vout_synchro_t *p_synchro;
74 75
    int            i_aspect;
    mtime_t        i_last_frame_pts;
gbazin's avatar
 
gbazin committed
76

gbazin's avatar
 
gbazin committed
77
};
gbazin's avatar
 
gbazin committed
78 79 80 81

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
gbazin's avatar
 
gbazin committed
82 83 84 85
static int  OpenDecoder( vlc_object_t * );
static void CloseDecoder( vlc_object_t * );

static picture_t *DecodeBlock( decoder_t *, block_t ** );
gbazin's avatar
 
gbazin committed
86

gbazin's avatar
 
gbazin committed
87
static picture_t *GetNewPicture( decoder_t *, uint8_t ** );
88
static void GetAR( decoder_t *p_dec );
gbazin's avatar
 
gbazin committed
89

gbazin's avatar
 
gbazin committed
90 91 92 93 94
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
vlc_module_begin();
    set_description( _("MPEG I/II video decoder (using libmpeg2)") );
gbazin's avatar
 
gbazin committed
95
    set_capability( "decoder", 150 );
zorglub's avatar
zorglub committed
96 97
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_VCODEC );
gbazin's avatar
 
gbazin committed
98
    set_callbacks( OpenDecoder, CloseDecoder );
gbazin's avatar
 
gbazin committed
99 100 101 102 103 104 105 106
    add_shortcut( "libmpeg2" );
vlc_module_end();

/*****************************************************************************
 * OpenDecoder: probe the decoder and return score
 *****************************************************************************/
static int OpenDecoder( vlc_object_t *p_this )
{
gbazin's avatar
 
gbazin committed
107
    decoder_t *p_dec = (decoder_t*)p_this;
gbazin's avatar
 
gbazin committed
108
    decoder_sys_t *p_sys;
Sam Hocevar's avatar
Sam Hocevar committed
109
    uint32_t i_accel = 0;
gbazin's avatar
 
gbazin committed
110

gbazin's avatar
 
gbazin committed
111 112
    if( p_dec->fmt_in.i_codec != VLC_FOURCC('m','p','g','v') &&
        p_dec->fmt_in.i_codec != VLC_FOURCC('m','p','g','1') &&
gbazin's avatar
 
gbazin committed
113
        /* Pinnacle hardware-mpeg1 */
gbazin's avatar
 
gbazin committed
114
        p_dec->fmt_in.i_codec != VLC_FOURCC('P','I','M','1') &&
gbazin's avatar
 
gbazin committed
115
        /* ATI Video */
gbazin's avatar
 
gbazin committed
116
        p_dec->fmt_in.i_codec != VLC_FOURCC('V','C','R','2') &&
117 118
        p_dec->fmt_in.i_codec != VLC_FOURCC('m','p','g','2') &&
        p_dec->fmt_in.i_codec != VLC_FOURCC('h','d','v','2') )
gbazin's avatar
 
gbazin committed
119 120 121 122
    {
        return VLC_EGENERIC;
    }

gbazin's avatar
 
gbazin committed
123
    /* Allocate the memory needed to store the decoder's structure */
gbazin's avatar
 
gbazin committed
124
    if( ( p_dec->p_sys = p_sys =
gbazin's avatar
 
gbazin committed
125
          (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
gbazin's avatar
 
gbazin committed
126
    {
gbazin's avatar
 
gbazin committed
127 128
        msg_Err( p_dec, "out of memory" );
        return VLC_EGENERIC;
gbazin's avatar
 
gbazin committed
129 130 131
    }

    /* Initialize the thread properties */
gbazin's avatar
 
gbazin committed
132 133 134 135 136 137
    memset( p_sys, 0, sizeof(decoder_sys_t) );
    p_sys->p_mpeg2dec = NULL;
    p_sys->p_synchro  = NULL;
    p_sys->p_info     = NULL;
    p_sys->i_current_pts  = 0;
    p_sys->i_previous_pts = 0;
138 139
    p_sys->i_current_dts  = 0;
    p_sys->i_previous_dts = 0;
gbazin's avatar
 
gbazin committed
140 141 142 143
    p_sys->p_picture_to_destroy = NULL;
    p_sys->b_garbage_pic = 0;
    p_sys->b_slice_i  = 0;
    p_sys->b_skip     = 0;
Laurent Aimar's avatar
Laurent Aimar committed
144
    p_sys->b_preroll = VLC_FALSE;
gbazin's avatar
 
gbazin committed
145

Christophe Massiot's avatar
Christophe Massiot committed
146
#if defined( __i386__ ) || defined( __x86_64__ )
Sam Hocevar's avatar
Sam Hocevar committed
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
    if( p_dec->p_libvlc->i_cpu & CPU_CAPABILITY_MMX )
    {
        i_accel |= MPEG2_ACCEL_X86_MMX;
    }

    if( p_dec->p_libvlc->i_cpu & CPU_CAPABILITY_3DNOW )
    {
        i_accel |= MPEG2_ACCEL_X86_3DNOW;
    }

    if( p_dec->p_libvlc->i_cpu & CPU_CAPABILITY_MMXEXT )
    {
        i_accel |= MPEG2_ACCEL_X86_MMXEXT;
    }

#elif defined( __powerpc__ ) || defined( SYS_DARWIN )
    if( p_dec->p_libvlc->i_cpu & CPU_CAPABILITY_ALTIVEC )
    {
        i_accel |= MPEG2_ACCEL_PPC_ALTIVEC;
    }

#else
    /* If we do not know this CPU, trust libmpeg2's feature detection */
    i_accel = MPEG2_ACCEL_DETECT;

#endif

    /* Set CPU acceleration features */
    mpeg2_accel( i_accel );

gbazin's avatar
 
gbazin committed
177
    /* Initialize decoder */
gbazin's avatar
 
gbazin committed
178 179
    p_sys->p_mpeg2dec = mpeg2_init();
    if( p_sys->p_mpeg2dec == NULL)
gbazin's avatar
 
gbazin committed
180 181
    {
        msg_Err( p_dec, "mpeg2_init() failed" );
gbazin's avatar
 
gbazin committed
182
        free( p_sys );
gbazin's avatar
 
gbazin committed
183 184
        return VLC_EGENERIC;
    }
gbazin's avatar
 
gbazin committed
185

gbazin's avatar
 
gbazin committed
186 187 188
    p_sys->p_info = mpeg2_info( p_sys->p_mpeg2dec );

    p_dec->pf_decode_video = DecodeBlock;
gbazin's avatar
 
gbazin committed
189 190 191

    return VLC_SUCCESS;
}
gbazin's avatar
 
gbazin committed
192

gbazin's avatar
 
gbazin committed
193 194 195
/*****************************************************************************
 * RunDecoder: the libmpeg2 decoder
 *****************************************************************************/
gbazin's avatar
 
gbazin committed
196
static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
gbazin's avatar
 
gbazin committed
197 198 199 200 201
{
    decoder_sys_t   *p_sys = p_dec->p_sys;
    mpeg2_state_t   state;
    picture_t       *p_pic;

gbazin's avatar
 
gbazin committed
202 203 204 205 206
    block_t *p_block;

    if( !pp_block || !*pp_block ) return NULL;

    p_block = *pp_block;
gbazin's avatar
 
gbazin committed
207 208

    while( 1 )
gbazin's avatar
 
gbazin committed
209
    {
gbazin's avatar
 
gbazin committed
210
        state = mpeg2_parse( p_sys->p_mpeg2dec );
gbazin's avatar
 
gbazin committed
211 212 213 214

        switch( state )
        {
        case STATE_BUFFER:
gbazin's avatar
 
gbazin committed
215
            if( !p_block->i_buffer )
gbazin's avatar
 
gbazin committed
216 217
            {
                block_Release( p_block );
gbazin's avatar
 
gbazin committed
218
                return NULL;
gbazin's avatar
 
gbazin committed
219 220
            }

221 222
            if( (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY
                                      | BLOCK_FLAG_CORRUPTED)) &&
223
                p_sys->p_synchro &&
224 225
                p_sys->p_info->sequence &&
                p_sys->p_info->sequence->width != (unsigned)-1 )
gbazin's avatar
 
gbazin committed
226 227 228 229
            {
                vout_SynchroReset( p_sys->p_synchro );
                if( p_sys->p_info->current_fbuf != NULL
                    && p_sys->p_info->current_fbuf->id != NULL )
gbazin's avatar
 
gbazin committed
230
                {
gbazin's avatar
 
gbazin committed
231 232
                    p_sys->b_garbage_pic = 1;
                    p_pic = p_sys->p_info->current_fbuf->id;
gbazin's avatar
 
gbazin committed
233
                }
gbazin's avatar
 
gbazin committed
234 235 236 237 238 239 240 241 242 243 244
                else
                {
                    uint8_t *buf[3];
                    buf[0] = buf[1] = buf[2] = NULL;
                    if( (p_pic = GetNewPicture( p_dec, buf )) == NULL )
                        break;
                    mpeg2_set_buf( p_sys->p_mpeg2dec, buf, p_pic );
                }
                p_sys->p_picture_to_destroy = p_pic;

                if ( p_sys->b_slice_i )
245
                {
gbazin's avatar
 
gbazin committed
246
                    vout_SynchroNewPicture( p_sys->p_synchro,
247 248
                        I_CODING_TYPE, 2, 0, 0, p_sys->i_current_rate,
                        p_sys->p_info->sequence->flags & SEQ_FLAG_LOW_DELAY );
gbazin's avatar
 
gbazin committed
249 250
                    vout_SynchroDecode( p_sys->p_synchro );
                    vout_SynchroEnd( p_sys->p_synchro, I_CODING_TYPE, 0 );
251
                }
gbazin's avatar
 
gbazin committed
252
            }
253

Laurent Aimar's avatar
Laurent Aimar committed
254 255 256 257 258 259 260 261 262 263 264
            if( p_block->i_flags & BLOCK_FLAG_PREROLL )
            {
                p_sys->b_preroll = VLC_TRUE;
            }
            else if( p_sys->b_preroll )
            {
                p_sys->b_preroll = VLC_FALSE;
                /* Reset synchro */
                vout_SynchroReset( p_sys->p_synchro );
            }

265
#ifdef PIC_FLAG_PTS
gbazin's avatar
 
gbazin committed
266 267 268
            if( p_block->i_pts )
            {
                mpeg2_pts( p_sys->p_mpeg2dec, (uint32_t)p_block->i_pts );
gbazin's avatar
 
gbazin committed
269 270

#else /* New interface */
271 272
            if( p_block->i_pts || p_block->i_dts )
            {
gbazin's avatar
 
gbazin committed
273
                mpeg2_tag_picture( p_sys->p_mpeg2dec,
274 275
                                   (uint32_t)p_block->i_pts,
                                   (uint32_t)p_block->i_dts );
gbazin's avatar
 
gbazin committed
276
#endif
gbazin's avatar
 
gbazin committed
277 278
                p_sys->i_previous_pts = p_sys->i_current_pts;
                p_sys->i_current_pts = p_block->i_pts;
279 280
                p_sys->i_previous_dts = p_sys->i_current_dts;
                p_sys->i_current_dts = p_block->i_dts;
gbazin's avatar
 
gbazin committed
281 282
            }

gbazin's avatar
 
gbazin committed
283
            p_sys->i_current_rate = p_block->i_rate;
gbazin's avatar
 
gbazin committed
284

gbazin's avatar
 
gbazin committed
285 286 287
            mpeg2_buffer( p_sys->p_mpeg2dec, p_block->p_buffer,
                          p_block->p_buffer + p_block->i_buffer );

288
            p_block->i_buffer = 0;
gbazin's avatar
 
gbazin committed
289 290
            break;

291
#ifdef STATE_SEQUENCE_MODIFIED
292 293 294
        case STATE_SEQUENCE_MODIFIED:
            GetAR( p_dec );
            break;
295
#endif
296

gbazin's avatar
 
gbazin committed
297
        case STATE_SEQUENCE:
gbazin's avatar
 
gbazin committed
298
        {
gbazin's avatar
 
gbazin committed
299
            /* Initialize video output */
gbazin's avatar
 
gbazin committed
300
            uint8_t *buf[3];
301
            buf[0] = buf[1] = buf[2] = NULL;
gbazin's avatar
 
gbazin committed
302

303
            GetAR( p_dec );
gbazin's avatar
 
gbazin committed
304 305

            mpeg2_custom_fbuf( p_sys->p_mpeg2dec, 1 );
gbazin's avatar
 
gbazin committed
306 307

            /* Set the first 2 reference frames */
gbazin's avatar
 
gbazin committed
308
            mpeg2_set_buf( p_sys->p_mpeg2dec, buf, NULL );
309

gbazin's avatar
 
gbazin committed
310
            if( (p_pic = GetNewPicture( p_dec, buf )) == NULL )
311 312 313 314
            {
                block_Release( p_block );
                return NULL;
            }
gbazin's avatar
 
gbazin committed
315

gbazin's avatar
 
gbazin committed
316
            mpeg2_set_buf( p_sys->p_mpeg2dec, buf, p_pic );
gbazin's avatar
 
gbazin committed
317

318
            /* This picture will never go through display_picture. */
gbazin's avatar
 
gbazin committed
319 320
            p_pic->date = 0;

321 322
            /* For some reason, libmpeg2 will put this pic twice in
             * discard_picture. This can be considered a bug in libmpeg2. */
gbazin's avatar
 
gbazin committed
323
            p_dec->pf_picture_link( p_dec, p_pic );
324

gbazin's avatar
 
gbazin committed
325
            if( p_sys->p_synchro )
326
            {
gbazin's avatar
 
gbazin committed
327
                vout_SynchroRelease( p_sys->p_synchro );
328
            }
gbazin's avatar
 
gbazin committed
329
            p_sys->p_synchro = vout_SynchroInit( p_dec,
gbazin's avatar
 
gbazin committed
330 331 332
                (uint32_t)((uint64_t)1001000000 * 27 /
                p_sys->p_info->sequence->frame_period) );
            p_sys->b_after_sequence_header = 1;
gbazin's avatar
 
gbazin committed
333 334
        }
        break;
gbazin's avatar
 
gbazin committed
335

336
        case STATE_PICTURE_2ND:
gbazin's avatar
 
gbazin committed
337 338 339
            vout_SynchroNewPicture( p_sys->p_synchro,
                p_sys->p_info->current_picture->flags & PIC_MASK_CODING_TYPE,
                p_sys->p_info->current_picture->nb_fields,
340 341
                0, 0, p_sys->i_current_rate,
                p_sys->p_info->sequence->flags & SEQ_FLAG_LOW_DELAY );
342

gbazin's avatar
 
gbazin committed
343
            if( p_sys->b_skip )
344
            {
gbazin's avatar
 
gbazin committed
345
                vout_SynchroTrash( p_sys->p_synchro );
346 347 348
            }
            else
            {
gbazin's avatar
 
gbazin committed
349
                vout_SynchroDecode( p_sys->p_synchro );
350 351 352
            }
            break;

gbazin's avatar
 
gbazin committed
353 354 355
        case STATE_PICTURE:
        {
            uint8_t *buf[3];
356
            mtime_t i_pts, i_dts;
357 358
            buf[0] = buf[1] = buf[2] = NULL;

gbazin's avatar
 
gbazin committed
359 360 361
            if ( p_sys->b_after_sequence_header &&
                 ((p_sys->p_info->current_picture->flags &
                       PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_P) )
362 363
            {
                /* Intra-slice refresh. Simulate a blank I picture. */
gbazin's avatar
 
gbazin committed
364 365
                msg_Dbg( p_dec, "intra-slice refresh stream" );
                vout_SynchroNewPicture( p_sys->p_synchro,
366 367
                    I_CODING_TYPE, 2, 0, 0, p_sys->i_current_rate,
                    p_sys->p_info->sequence->flags & SEQ_FLAG_LOW_DELAY );
gbazin's avatar
 
gbazin committed
368 369 370
                vout_SynchroDecode( p_sys->p_synchro );
                vout_SynchroEnd( p_sys->p_synchro, I_CODING_TYPE, 0 );
                p_sys->b_slice_i = 1;
371
            }
gbazin's avatar
 
gbazin committed
372 373
            p_sys->b_after_sequence_header = 0;

gbazin's avatar
 
gbazin committed
374
#ifdef PIC_FLAG_PTS
gbazin's avatar
 
gbazin committed
375 376 377 378
            i_pts = p_sys->p_info->current_picture->flags & PIC_FLAG_PTS ?
                ( ( p_sys->p_info->current_picture->pts ==
                    (uint32_t)p_sys->i_current_pts ) ?
                  p_sys->i_current_pts : p_sys->i_previous_pts ) : 0;
379
            i_dts = 0;
gbazin's avatar
 
gbazin committed
380

gbazin's avatar
 
gbazin committed
381 382 383 384 385 386 387 388 389 390 391 392 393
            /* Hack to handle demuxers which only have DTS timestamps */
            if( !i_pts && !p_block->i_pts && p_block->i_dts > 0 )
            {
                if( p_sys->p_info->sequence->flags & SEQ_FLAG_LOW_DELAY ||
                    (p_sys->p_info->current_picture->flags &
                      PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_B )
                {
                    i_pts = p_block->i_dts;
                }
            }
            p_block->i_pts = p_block->i_dts = 0;
            /* End hack */

394 395 396 397 398 399 400 401 402 403 404 405
#else /* New interface */

            i_pts = p_sys->p_info->current_picture->flags & PIC_FLAG_TAGS ?
                ( ( p_sys->p_info->current_picture->tag ==
                    (uint32_t)p_sys->i_current_pts ) ?
                  p_sys->i_current_pts : p_sys->i_previous_pts ) : 0;
            i_dts = p_sys->p_info->current_picture->flags & PIC_FLAG_TAGS ?
                ( ( p_sys->p_info->current_picture->tag2 ==
                    (uint32_t)p_sys->i_current_dts ) ?
                  p_sys->i_current_dts : p_sys->i_previous_dts ) : 0;
#endif

gbazin's avatar
 
gbazin committed
406 407
            vout_SynchroNewPicture( p_sys->p_synchro,
                p_sys->p_info->current_picture->flags & PIC_MASK_CODING_TYPE,
408
                p_sys->p_info->current_picture->nb_fields, i_pts, i_dts,
409 410
                p_sys->i_current_rate,
                p_sys->p_info->sequence->flags & SEQ_FLAG_LOW_DELAY );
gbazin's avatar
 
gbazin committed
411

Laurent Aimar's avatar
Laurent Aimar committed
412
            if( !p_dec->b_pace_control && !p_sys->b_preroll &&
413
                !(p_sys->b_slice_i
gbazin's avatar
 
gbazin committed
414
                   && ((p_sys->p_info->current_picture->flags
415
                         & PIC_MASK_CODING_TYPE) == P_CODING_TYPE))
gbazin's avatar
 
gbazin committed
416 417
                   && !vout_SynchroChoose( p_sys->p_synchro,
                              p_sys->p_info->current_picture->flags
gbazin's avatar
 
gbazin committed
418
                                & PIC_MASK_CODING_TYPE,
419 420
                              /*p_sys->p_vout->render_time*/ 0 /*FIXME*/,
                              p_sys->p_info->sequence->flags & SEQ_FLAG_LOW_DELAY ) )
421
            {
gbazin's avatar
 
gbazin committed
422 423 424 425
                mpeg2_skip( p_sys->p_mpeg2dec, 1 );
                p_sys->b_skip = 1;
                vout_SynchroTrash( p_sys->p_synchro );
                mpeg2_set_buf( p_sys->p_mpeg2dec, buf, NULL );
426 427
            }
            else
gbazin's avatar
 
gbazin committed
428
            {
gbazin's avatar
 
gbazin committed
429 430 431
                mpeg2_skip( p_sys->p_mpeg2dec, 0 );
                p_sys->b_skip = 0;
                vout_SynchroDecode( p_sys->p_synchro );
gbazin's avatar
 
gbazin committed
432 433

                if( (p_pic = GetNewPicture( p_dec, buf )) == NULL )
434 435 436 437
                {
                    block_Release( p_block );
                    return NULL;
                }
gbazin's avatar
 
gbazin committed
438

gbazin's avatar
 
gbazin committed
439
                mpeg2_set_buf( p_sys->p_mpeg2dec, buf, p_pic );
gbazin's avatar
 
gbazin committed
440 441
            }
        }
442
        break;
gbazin's avatar
 
gbazin committed
443 444

        case STATE_END:
445
        case STATE_SLICE:
gbazin's avatar
 
gbazin committed
446
            p_pic = NULL;
gbazin's avatar
 
gbazin committed
447 448
            if( p_sys->p_info->display_fbuf
                && p_sys->p_info->display_fbuf->id )
gbazin's avatar
 
gbazin committed
449
            {
gbazin's avatar
 
gbazin committed
450
                p_pic = (picture_t *)p_sys->p_info->display_fbuf->id;
gbazin's avatar
 
gbazin committed
451

gbazin's avatar
 
gbazin committed
452 453
                vout_SynchroEnd( p_sys->p_synchro,
                            p_sys->p_info->display_picture->flags
454
                             & PIC_MASK_CODING_TYPE,
gbazin's avatar
 
gbazin committed
455 456
                            p_sys->b_garbage_pic );
                p_sys->b_garbage_pic = 0;
457

gbazin's avatar
 
gbazin committed
458
                if ( p_sys->p_picture_to_destroy != p_pic )
459
                {
gbazin's avatar
 
gbazin committed
460
                    p_pic->date = vout_SynchroDate( p_sys->p_synchro );
461 462 463
                }
                else
                {
gbazin's avatar
 
gbazin committed
464
                    p_sys->p_picture_to_destroy = NULL;
gbazin's avatar
 
gbazin committed
465
                    p_pic->date = 0;
gbazin's avatar
 
gbazin committed
466
                }
467 468
            }

gbazin's avatar
 
gbazin committed
469 470
            if( p_sys->p_info->discard_fbuf &&
                p_sys->p_info->discard_fbuf->id )
471
            {
gbazin's avatar
 
gbazin committed
472 473
                p_dec->pf_picture_unlink( p_dec,
                                          p_sys->p_info->discard_fbuf->id );
gbazin's avatar
 
gbazin committed
474
            }
gbazin's avatar
 
gbazin committed
475

476 477 478 479 480 481 482 483 484 485 486 487
            /* For still frames */
            if( state == STATE_END && p_pic ) p_pic->b_force = VLC_TRUE;

            if( p_pic )
            {
                /* Avoid frames with identical timestamps.
                 * Especially needed for still frames in DVD menus. */
                if( p_sys->i_last_frame_pts == p_pic->date ) p_pic->date++;
                p_sys->i_last_frame_pts = p_pic->date;

                return p_pic;
            }
gbazin's avatar
 
gbazin committed
488

gbazin's avatar
 
gbazin committed
489 490
            break;

491
        case STATE_INVALID:
492 493 494 495
        {
            uint8_t *buf[3];
            buf[0] = buf[1] = buf[2] = NULL;

gbazin's avatar
 
gbazin committed
496
            msg_Warn( p_dec, "invalid picture encountered" );
Sam Hocevar's avatar
Sam Hocevar committed
497
            if ( ( p_sys->p_info->current_picture == NULL ) ||
gbazin's avatar
 
gbazin committed
498
               ( ( p_sys->p_info->current_picture->flags &
499
                   PIC_MASK_CODING_TYPE) != B_CODING_TYPE ) )
500
            {
501
                if( p_sys->p_synchro ) vout_SynchroReset( p_sys->p_synchro );
502
            }
gbazin's avatar
 
gbazin committed
503 504
            mpeg2_skip( p_sys->p_mpeg2dec, 1 );
            p_sys->b_skip = 1;
505

gbazin's avatar
 
gbazin committed
506 507
            if( p_sys->p_info->current_fbuf &&
                p_sys->p_info->current_fbuf->id )
508
            {
gbazin's avatar
 
gbazin committed
509 510
                p_sys->b_garbage_pic = 1;
                p_pic = p_sys->p_info->current_fbuf->id;
511
            }
512 513 514 515
            else if( !p_sys->p_info->sequence )
            {
                break;
            }
516 517 518 519
            else
            {
                if( (p_pic = GetNewPicture( p_dec, buf )) == NULL )
                    break;
gbazin's avatar
 
gbazin committed
520
                mpeg2_set_buf( p_sys->p_mpeg2dec, buf, p_pic );
521
            }
gbazin's avatar
 
gbazin committed
522
            p_sys->p_picture_to_destroy = p_pic;
523 524

            memset( p_pic->p[0].p_pixels, 0,
gbazin's avatar
 
gbazin committed
525 526
                    p_sys->p_info->sequence->width
                     * p_sys->p_info->sequence->height );
527
            memset( p_pic->p[1].p_pixels, 0x80,
gbazin's avatar
 
gbazin committed
528 529
                    p_sys->p_info->sequence->width
                     * p_sys->p_info->sequence->height / 4 );
530
            memset( p_pic->p[2].p_pixels, 0x80,
gbazin's avatar
 
gbazin committed
531 532
                    p_sys->p_info->sequence->width
                     * p_sys->p_info->sequence->height / 4 );
533

gbazin's avatar
 
gbazin committed
534
            if( p_sys->b_slice_i )
535
            {
gbazin's avatar
 
gbazin committed
536
                vout_SynchroNewPicture( p_sys->p_synchro,
537 538
                        I_CODING_TYPE, 2, 0, 0, p_sys->i_current_rate,
                        p_sys->p_info->sequence->flags & SEQ_FLAG_LOW_DELAY );
gbazin's avatar
 
gbazin committed
539 540
                vout_SynchroDecode( p_sys->p_synchro );
                vout_SynchroEnd( p_sys->p_synchro, I_CODING_TYPE, 0 );
541
            }
542
            break;
543
        }
544

gbazin's avatar
 
gbazin committed
545 546 547 548 549
        default:
            break;
        }
    }

gbazin's avatar
 
gbazin committed
550 551
    /* Never reached */
    return NULL;
gbazin's avatar
 
gbazin committed
552 553 554
}

/*****************************************************************************
gbazin's avatar
 
gbazin committed
555
 * CloseDecoder: libmpeg2 decoder destruction
gbazin's avatar
 
gbazin committed
556
 *****************************************************************************/
gbazin's avatar
 
gbazin committed
557
static void CloseDecoder( vlc_object_t *p_this )
gbazin's avatar
 
gbazin committed
558
{
gbazin's avatar
 
gbazin committed
559
    decoder_t *p_dec = (decoder_t *)p_this;
gbazin's avatar
 
gbazin committed
560 561
    decoder_sys_t *p_sys = p_dec->p_sys;

gbazin's avatar
 
gbazin committed
562
    if( p_sys->p_synchro ) vout_SynchroRelease( p_sys->p_synchro );
gbazin's avatar
 
gbazin committed
563

gbazin's avatar
 
gbazin committed
564
    if( p_sys->p_mpeg2dec ) mpeg2_close( p_sys->p_mpeg2dec );
gbazin's avatar
 
gbazin committed
565

gbazin's avatar
 
gbazin committed
566
    free( p_sys );
gbazin's avatar
 
gbazin committed
567
}
gbazin's avatar
 
gbazin committed
568 569 570 571

/*****************************************************************************
 * GetNewPicture: Get a new picture from the vout and set the buf struct
 *****************************************************************************/
gbazin's avatar
 
gbazin committed
572
static picture_t *GetNewPicture( decoder_t *p_dec, uint8_t **pp_buf )
gbazin's avatar
 
gbazin committed
573
{
gbazin's avatar
 
gbazin committed
574
    decoder_sys_t *p_sys = p_dec->p_sys;
gbazin's avatar
 
gbazin committed
575
    picture_t *p_pic;
gbazin's avatar
 
gbazin committed
576

gbazin's avatar
 
gbazin committed
577
    p_dec->fmt_out.video.i_width = p_sys->p_info->sequence->width;
578 579
    p_dec->fmt_out.video.i_visible_width =
        p_sys->p_info->sequence->picture_width;
gbazin's avatar
 
gbazin committed
580
    p_dec->fmt_out.video.i_height = p_sys->p_info->sequence->height;
581 582
    p_dec->fmt_out.video.i_visible_height =
        p_sys->p_info->sequence->picture_height;
gbazin's avatar
 
gbazin committed
583
    p_dec->fmt_out.video.i_aspect = p_sys->i_aspect;
gbazin's avatar
 
gbazin committed
584

585 586 587 588 589 590 591 592
    if( p_sys->p_info->sequence->frame_period > 0 )
    {
        p_dec->fmt_out.video.i_frame_rate =
            (uint32_t)( (uint64_t)1001000000 * 27 /
                        p_sys->p_info->sequence->frame_period );
        p_dec->fmt_out.video.i_frame_rate_base = 1001;
    }

gbazin's avatar
 
gbazin committed
593 594 595 596
    p_dec->fmt_out.i_codec =
        ( p_sys->p_info->sequence->chroma_height <
          p_sys->p_info->sequence->height ) ?
        VLC_FOURCC('I','4','2','0') : VLC_FOURCC('I','4','2','2');
gbazin's avatar
 
gbazin committed
597

gbazin's avatar
 
gbazin committed
598 599
    /* Get a new picture */
    p_pic = p_dec->pf_vout_buffer_new( p_dec );
gbazin's avatar
 
gbazin committed
600 601 602

    if( p_pic == NULL ) return NULL;

gbazin's avatar
 
gbazin committed
603 604 605 606 607 608 609
    p_pic->b_progressive = p_sys->p_info->current_picture != NULL ?
        p_sys->p_info->current_picture->flags & PIC_FLAG_PROGRESSIVE_FRAME : 1;
    p_pic->b_top_field_first = p_sys->p_info->current_picture != NULL ?
        p_sys->p_info->current_picture->flags & PIC_FLAG_TOP_FIELD_FIRST : 1;
    p_pic->i_nb_fields = p_sys->p_info->current_picture != NULL ?
        p_sys->p_info->current_picture->nb_fields : 2;

gbazin's avatar
 
gbazin committed
610
    p_dec->pf_picture_link( p_dec, p_pic );
gbazin's avatar
 
gbazin committed
611 612 613 614 615 616 617

    pp_buf[0] = p_pic->p[0].p_pixels;
    pp_buf[1] = p_pic->p[1].p_pixels;
    pp_buf[2] = p_pic->p[2].p_pixels;

    return p_pic;
}
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678

/*****************************************************************************
 * GetAR: Get aspect ratio
 *****************************************************************************/
static void GetAR( decoder_t *p_dec )
{
    decoder_sys_t   *p_sys = p_dec->p_sys;

    /* Check whether the input gave a particular aspect ratio */
    if( p_dec->fmt_in.video.i_aspect )
    {
        p_sys->i_aspect = p_dec->fmt_in.video.i_aspect;
        if( p_sys->i_aspect <= AR_221_1_PICTURE )
        switch( p_sys->i_aspect )
        {
        case AR_3_4_PICTURE:
            p_sys->i_aspect = VOUT_ASPECT_FACTOR * 4 / 3;
            break;
        case AR_16_9_PICTURE:
            p_sys->i_aspect = VOUT_ASPECT_FACTOR * 16 / 9;
            break;
        case AR_221_1_PICTURE:
            p_sys->i_aspect = VOUT_ASPECT_FACTOR * 221 / 100;
            break;
        case AR_SQUARE_PICTURE:
            p_sys->i_aspect = VOUT_ASPECT_FACTOR *
                           p_sys->p_info->sequence->width /
                           p_sys->p_info->sequence->height;
            break;
        }
    }
    else
    {
        /* Use the value provided in the MPEG sequence header */
        if( p_sys->p_info->sequence->pixel_height > 0 )
        {
            p_sys->i_aspect =
                ((uint64_t)p_sys->p_info->sequence->display_width) *
                p_sys->p_info->sequence->pixel_width *
                VOUT_ASPECT_FACTOR /
                p_sys->p_info->sequence->display_height /
                p_sys->p_info->sequence->pixel_height;
        }
        else
        {
            /* Invalid aspect, assume 4:3.
             * This shouldn't happen and if it does it is a bug
             * in libmpeg2 (likely triggered by an invalid stream) */
            p_sys->i_aspect = VOUT_ASPECT_FACTOR * 4 / 3;
        }
    }

    msg_Dbg( p_dec, "%dx%d, aspect %d, %u.%03u fps",
             p_sys->p_info->sequence->width,
             p_sys->p_info->sequence->height, p_sys->i_aspect,
             (uint32_t)((uint64_t)1001000000 * 27 /
                 p_sys->p_info->sequence->frame_period / 1001),
             (uint32_t)((uint64_t)1001000000 * 27 /
                 p_sys->p_info->sequence->frame_period % 1001) );
}