* libmpeg2.c: mpeg2 video decoder module making use of libmpeg2.
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
- * $Id: libmpeg2.c,v 1.12 2003/04/20 23:42:17 massiot Exp $
+ * $Id: libmpeg2.c,v 1.22 2003/06/10 23:01:40 massiot Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
*
*/
mpeg2dec_t *p_mpeg2dec;
const mpeg2_info_t *p_info;
+ vlc_bool_t b_skip;
/*
* Input properties
mtime_t i_period_remainder;
int i_current_rate;
picture_t * p_picture_to_destroy;
+ 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 */
/*
* Output properties
p_dec->i_previous_pts = 0;
p_dec->i_period_remainder = 0;
p_dec->p_picture_to_destroy = NULL;
+ p_dec->b_garbage_pic = 0;
+ p_dec->b_slice_i = 0;
+ p_dec->b_skip = 0;
/* Initialize decoder */
p_dec->p_mpeg2dec = mpeg2_init();
break;
}
- if( p_dec->p_pes->b_discontinuity && p_dec->p_synchro )
+ if( p_dec->p_pes->b_discontinuity && p_dec->p_synchro
+ && p_dec->p_info->sequence->width != (unsigned)-1 )
{
vout_SynchroReset( p_dec->p_synchro );
- if ( p_dec->p_info->current_fbuf != NULL )
- p_dec->p_picture_to_destroy
- = p_dec->p_info->current_fbuf->id;
+ if ( p_dec->p_info->current_fbuf != NULL
+ && p_dec->p_info->current_fbuf->id != NULL )
+ {
+ p_dec->b_garbage_pic = 1;
+ p_pic = p_dec->p_info->current_fbuf->id;
+ }
+ 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_dec->p_mpeg2dec, buf, p_pic );
+ }
+ p_dec->p_picture_to_destroy = p_pic;
+
+ memset( p_pic->p[0].p_pixels, 0,
+ p_dec->p_info->sequence->width
+ * p_dec->p_info->sequence->height );
+ memset( p_pic->p[1].p_pixels, 0x80,
+ p_dec->p_info->sequence->width
+ * p_dec->p_info->sequence->height / 4 );
+ memset( p_pic->p[2].p_pixels, 0x80,
+ p_dec->p_info->sequence->width
+ * p_dec->p_info->sequence->height / 4 );
+
+ if ( p_dec->b_slice_i )
+ {
+ vout_SynchroNewPicture( p_dec->p_synchro,
+ I_CODING_TYPE, 2, 0, 0, p_dec->i_current_rate );
+ vout_SynchroDecode( p_dec->p_synchro );
+ vout_SynchroEnd( p_dec->p_synchro, I_CODING_TYPE, 0 );
+ }
}
if( p_dec->p_pes->i_pts )
else
{
/* Use the value provided in the MPEG sequence header */
- i_aspect = ((uint64_t)p_dec->p_info->sequence->width) *
+ i_aspect = ((uint64_t)p_dec->p_info->sequence->display_width) *
p_dec->p_info->sequence->pixel_width * VOUT_ASPECT_FACTOR /
- p_dec->p_info->sequence->height /
+ p_dec->p_info->sequence->display_height /
p_dec->p_info->sequence->pixel_height;
}
/* Set the first 2 reference frames */
mpeg2_set_buf( p_dec->p_mpeg2dec, buf, NULL );
- mpeg2_set_buf( p_dec->p_mpeg2dec, buf, NULL );
+ if( (p_pic = GetNewPicture( p_dec, buf )) == NULL ) break;
+ memset( p_pic->p[0].p_pixels, 0,
+ p_dec->p_info->sequence->width
+ * p_dec->p_info->sequence->height );
+ memset( p_pic->p[1].p_pixels, 0x80,
+ p_dec->p_info->sequence->width
+ * p_dec->p_info->sequence->height / 4 );
+ memset( p_pic->p[2].p_pixels, 0x80,
+ p_dec->p_info->sequence->width
+ * p_dec->p_info->sequence->height / 4 );
+ mpeg2_set_buf( p_dec->p_mpeg2dec, buf, p_pic );
+ /* This picture will never go through display_picture. */
+ vout_DatePicture( p_dec->p_vout, p_pic, 0 );
+ vout_DisplayPicture( p_dec->p_vout, p_pic );
+ /* For some reason, libmpeg2 will put this pic twice in
+ * discard_picture. This can be considered a bug in libmpeg2. */
+ vout_LinkPicture( p_dec->p_vout, p_pic );
+
+ if ( p_dec->p_synchro )
+ {
+ vout_SynchroRelease( p_dec->p_synchro );
+ }
p_dec->p_synchro = vout_SynchroInit( p_dec->p_fifo, p_dec->p_vout,
(u32)((u64)1001000000 * 27 / p_dec->p_info->sequence->frame_period) );
+ p_dec->b_after_sequence_header = 1;
}
break;
+ case STATE_PICTURE_2ND:
+ vout_SynchroNewPicture( p_dec->p_synchro,
+ p_dec->p_info->current_picture->flags & PIC_MASK_CODING_TYPE,
+ p_dec->p_info->current_picture->nb_fields,
+ 0, 0,
+ p_dec->i_current_rate );
+
+ if ( p_dec->b_skip )
+ {
+ vout_SynchroTrash( p_dec->p_synchro );
+ }
+ else
+ {
+ vout_SynchroDecode( p_dec->p_synchro );
+ }
+ break;
+
case STATE_PICTURE:
{
uint8_t *buf[3];
buf[0] = buf[1] = buf[2] = NULL;
+ if ( p_dec->b_after_sequence_header
+ && ((p_dec->p_info->current_picture->flags
+ & PIC_MASK_CODING_TYPE)
+ == PIC_FLAG_CODING_TYPE_P) )
+ {
+ /* Intra-slice refresh. Simulate a blank I picture. */
+ msg_Dbg( p_dec->p_fifo, "intra-slice refresh stream" );
+ vout_SynchroNewPicture( p_dec->p_synchro,
+ I_CODING_TYPE, 2, 0, 0, p_dec->i_current_rate );
+ vout_SynchroDecode( p_dec->p_synchro );
+ vout_SynchroEnd( p_dec->p_synchro, I_CODING_TYPE, 0 );
+ p_dec->b_slice_i = 1;
+ }
+ p_dec->b_after_sequence_header = 0;
+
vout_SynchroNewPicture( p_dec->p_synchro,
p_dec->p_info->current_picture->flags & PIC_MASK_CODING_TYPE,
p_dec->p_info->current_picture->nb_fields,
0,
p_dec->i_current_rate );
- if ( !vout_SynchroChoose( p_dec->p_synchro,
- p_dec->p_info->current_picture->flags & PIC_MASK_CODING_TYPE ) )
+ if ( !(p_dec->b_slice_i
+ && ((p_dec->p_info->current_picture->flags
+ & PIC_MASK_CODING_TYPE) == P_CODING_TYPE))
+ && !vout_SynchroChoose( p_dec->p_synchro,
+ p_dec->p_info->current_picture->flags
+ & PIC_MASK_CODING_TYPE ) )
{
mpeg2_skip( p_dec->p_mpeg2dec, 1 );
+ p_dec->b_skip = 1;
vout_SynchroTrash( p_dec->p_synchro );
mpeg2_set_buf( p_dec->p_mpeg2dec, buf, NULL );
}
else
{
mpeg2_skip( p_dec->p_mpeg2dec, 0 );
+ p_dec->b_skip = 0;
vout_SynchroDecode( p_dec->p_synchro );
if( (p_pic = GetNewPicture( p_dec, buf )) == NULL ) break;
mpeg2_set_buf( p_dec->p_mpeg2dec, buf, p_pic );
{
p_pic = (picture_t *)p_dec->p_info->display_fbuf->id;
- if ( p_pic != NULL )
- {
- if ( p_dec->p_picture_to_destroy != p_pic )
- {
- vout_SynchroEnd( p_dec->p_synchro,
+ vout_SynchroEnd( p_dec->p_synchro,
p_dec->p_info->display_picture->flags
& PIC_MASK_CODING_TYPE,
- 0 );
- vout_DatePicture( p_dec->p_vout, p_pic,
- vout_SynchroDate( p_dec->p_synchro ) );
- vout_DisplayPicture( p_dec->p_vout, p_pic );
- }
- else
- {
- p_dec->p_picture_to_destroy = NULL;
- vout_SynchroEnd( p_dec->p_synchro,
- p_dec->p_info->display_picture->flags
- & PIC_MASK_CODING_TYPE,
- 1 );
- vout_DatePicture( p_dec->p_vout, p_pic, 0 );
- vout_DisplayPicture( p_dec->p_vout, p_pic );
- }
+ p_dec->b_garbage_pic );
+ p_dec->b_garbage_pic = 0;
+ vout_DisplayPicture( p_dec->p_vout, p_pic );
+
+ if ( p_dec->p_picture_to_destroy != p_pic )
+ {
+ vout_DatePicture( p_dec->p_vout, p_pic,
+ vout_SynchroDate( p_dec->p_synchro ) );
+ }
+ else
+ {
+ p_dec->p_picture_to_destroy = NULL;
+ vout_DatePicture( p_dec->p_vout, p_pic, 0 );
}
}
break;
case STATE_INVALID:
+ {
+ uint8_t *buf[3];
+ buf[0] = buf[1] = buf[2] = NULL;
+
msg_Warn( p_dec->p_fifo, "invalid picture encountered" );
+ if ( ( p_dec->p_info->current_picture == NULL ) ||
+ ( ( p_dec->p_info->current_picture->flags & PIC_MASK_CODING_TYPE)
+ != B_CODING_TYPE ) )
+ {
+ vout_SynchroReset( p_dec->p_synchro );
+ }
+ mpeg2_skip( p_dec->p_mpeg2dec, 1 );
+ p_dec->b_skip = 1;
+
+ if( p_dec->p_info->current_fbuf &&
+ p_dec->p_info->current_fbuf->id )
+ {
+ p_dec->b_garbage_pic = 1;
+ p_pic = p_dec->p_info->current_fbuf->id;
+ }
+ else
+ {
+ if( (p_pic = GetNewPicture( p_dec, buf )) == NULL )
+ break;
+ mpeg2_set_buf( p_dec->p_mpeg2dec, buf, p_pic );
+ }
+ p_dec->p_picture_to_destroy = p_pic;
+
+ memset( p_pic->p[0].p_pixels, 0,
+ p_dec->p_info->sequence->width
+ * p_dec->p_info->sequence->height );
+ memset( p_pic->p[1].p_pixels, 0x80,
+ p_dec->p_info->sequence->width
+ * p_dec->p_info->sequence->height / 4 );
+ memset( p_pic->p[2].p_pixels, 0x80,
+ p_dec->p_info->sequence->width
+ * p_dec->p_info->sequence->height / 4 );
+
+ if ( p_dec->b_slice_i )
+ {
+ vout_SynchroNewPicture( p_dec->p_synchro,
+ I_CODING_TYPE, 2, 0, 0, p_dec->i_current_rate );
+ vout_SynchroDecode( p_dec->p_synchro );
+ vout_SynchroEnd( p_dec->p_synchro, I_CODING_TYPE, 0 );
+ }
break;
+ }
default:
break;
if( p_dec->p_pes )
input_DeletePES( p_dec->p_fifo->p_packets_mgt, p_dec->p_pes );
+ if( p_dec->p_synchro )
+ vout_SynchroRelease( p_dec->p_synchro );
+
if( p_dec->p_vout )
{
/* Temporary hack to free the pictures in use by libmpeg2 */
RESERVED_PICTURE )
vout_DestroyPicture( p_dec->p_vout,
p_dec->p_vout->render.pp_picture[i_pic] );
+ if( p_dec->p_vout->render.pp_picture[i_pic]->i_refcount > 0 )
+ vout_UnlinkPicture( p_dec->p_vout,
+ p_dec->p_vout->render.pp_picture[i_pic] );
}
vout_Request( p_dec->p_fifo, p_dec->p_vout, 0, 0, 0, 0 );
}
- if( p_dec->p_synchro )
- vout_SynchroRelease( p_dec->p_synchro );
-
if( p_dec->p_mpeg2dec ) mpeg2_close( p_dec->p_mpeg2dec );
free( p_dec );
static picture_t *GetNewPicture( dec_thread_t *p_dec, uint8_t **pp_buf )
{
picture_t *p_pic;
+ vlc_bool_t b_progressive = p_dec->p_info->current_picture != NULL ?
+ p_dec->p_info->current_picture->flags & PIC_FLAG_PROGRESSIVE_FRAME :
+ 1;
+ vlc_bool_t b_top_field_first = p_dec->p_info->current_picture != NULL ?
+ p_dec->p_info->current_picture->flags & PIC_FLAG_TOP_FIELD_FIRST :
+ 1;
+ unsigned int i_nb_fields = p_dec->p_info->current_picture != NULL ?
+ p_dec->p_info->current_picture->nb_fields : 2;
/* Get a new picture */
- while( !(p_pic = vout_CreatePicture( p_dec->p_vout, 0, 0, 0 ) ) )
+ while( !(p_pic = vout_CreatePicture( p_dec->p_vout,
+ b_progressive, b_top_field_first, i_nb_fields )) )
{
if( p_dec->p_fifo->b_die || p_dec->p_fifo->b_error )
break;