* libmpeg2.c: mpeg2 video decoder module making use of libmpeg2.
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
- * $Id: libmpeg2.c,v 1.19 2003/06/02 12:42:15 hartman Exp $
+ * $Id: libmpeg2.c,v 1.22 2003/06/10 23:01:40 massiot Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
*
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 */
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 )
/* 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 )
{
}
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;
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;
{
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 );
}
}
if( p_dec->p_info->current_fbuf &&
p_dec->p_info->current_fbuf->id )
{
- p_pic = (picture_t *)p_dec->p_info->current_fbuf->id;
- vout_UnlinkPicture( p_dec->p_vout, p_pic );
- vout_DestroyPicture( p_dec->p_vout, p_pic );
+ 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 );
}
- mpeg2_set_buf( p_dec->p_mpeg2dec, buf, NULL );
break;
}
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;