Commit 79cb45a4 authored by Laurent Aimar's avatar Laurent Aimar

es_out: do not flush decoder fifo when unwanted (fix broken picture on pause)

        do not convert pts/dts of prerolled samples
decoder: fixed ES_OUT_SET_NEXT_DISPLAY_TIME implementation (improved seek)
         proper handling of DISCONTINUITY
         reset video picture heap on seek/pause/rate change (avoid old
         pictures)
Please report any regression.
parent ab1b0ebe
......@@ -263,19 +263,20 @@ void input_DecoderDecode( decoder_t * p_dec, block_t *p_block )
}
}
void input_DecoderDiscontinuity( decoder_t * p_dec )
void input_DecoderDiscontinuity( decoder_t * p_dec, vlc_bool_t b_flush )
{
block_t *p_null;
/* Empty the fifo */
if( p_dec->p_owner->b_own_thread )
{
if( p_dec->p_owner->b_own_thread && b_flush )
block_FifoEmpty( p_dec->p_owner->p_fifo );
}
/* Send a special block */
p_null = block_New( p_dec, 128 );
p_null->i_flags |= BLOCK_FLAG_DISCONTINUITY;
/* FIXME check for p_packetizer or b_packitized from es_format_t of input ? */
if( p_dec->p_owner->p_packetizer && b_flush )
p_null->i_flags |= BLOCK_FLAG_CORRUPTED;
memset( p_null->p_buffer, 0, p_null->i_buffer );
input_DecoderDecode( p_dec, p_null );
......@@ -290,10 +291,6 @@ vlc_bool_t input_DecoderEmpty( decoder_t * p_dec )
return VLC_TRUE;
}
void input_DecoderPreroll( decoder_t *p_dec, int64_t i_preroll_end )
{
p_dec->p_owner->i_preroll_end = i_preroll_end;
}
/**
* Create a decoder object
*
......@@ -440,16 +437,11 @@ static int DecoderThread( decoder_t * p_dec )
return 0;
}
/**
* Decode a block
*
* \param p_dec the decoder object
* \param p_block the block to decode
* \return VLC_SUCCESS or an error code
*/
static inline void DecoderUpdatePreroll( int64_t *pi_preroll, const block_t *p )
{
if( p->i_pts > 0 )
if( p->i_flags & (BLOCK_FLAG_PREROLL|BLOCK_FLAG_DISCONTINUITY) )
*pi_preroll = INT64_MAX;
else if( p->i_pts > 0 )
*pi_preroll = __MIN( *pi_preroll, p->i_pts );
else if( p->i_dts > 0 )
*pi_preroll = __MIN( *pi_preroll, p->i_dts );
......@@ -459,65 +451,110 @@ static void DecoderDecodeAudio( decoder_t *p_dec, block_t *p_block )
input_thread_t *p_input = p_dec->p_owner->p_input;
aout_buffer_t *p_aout_buf;
//DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) )
{
vlc_mutex_lock( &p_input->p->counters.counters_lock );
stats_UpdateInteger( p_dec, p_input->p->counters.p_decoded_audio, 1, NULL );
vlc_mutex_unlock( &p_input->p->counters.counters_lock );
/* FIXME the best would be to handle the case
* start_date < preroll < end_date
* but that's not easy with non raw audio stream */
// if( p_dec->p_owner->i_preroll_end > 0 )
// msg_Err( p_dec, "Prerolling %lld - %lld", p_dec->p_owner->i_preroll_end, p_aout_buf->start_date );
if( p_dec->p_owner->i_preroll_end > 0 &&
p_aout_buf->start_date < p_dec->p_owner->i_preroll_end )
if( p_aout_buf->start_date < p_dec->p_owner->i_preroll_end )
{
aout_DecDeleteBuffer( p_dec->p_owner->p_aout,
p_dec->p_owner->p_aout_input, p_aout_buf );
continue;
}
else
if( p_dec->p_owner->i_preroll_end > 0 )
{
/* FIXME TODO flush audio output (don't know how to do that) */
msg_Dbg( p_dec, "End of audio preroll" );
p_dec->p_owner->i_preroll_end = -1;
aout_DecPlay( p_dec->p_owner->p_aout,
p_dec->p_owner->p_aout_input,
p_aout_buf );
}
aout_DecPlay( p_dec->p_owner->p_aout,
p_dec->p_owner->p_aout_input,
p_aout_buf );
}
}
static void VoutDisplayedPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
vlc_mutex_lock( &p_vout->picture_lock );
if( p_pic->i_status == READY_PICTURE )
{
/* Grr cannot destroy ready picture by myself so be sure vout won't like it */
p_pic->date = 1;
}
else if( p_pic->i_refcount > 0 )
{
p_pic->i_status = DISPLAYED_PICTURE;
}
else
{
p_pic->i_status = DESTROYED_PICTURE;
p_vout->i_heap_size--;
}
vlc_mutex_unlock( &p_vout->picture_lock );
}
static void VoutFlushPicture( vout_thread_t *p_vout )
{
int i;
vlc_mutex_lock( &p_vout->picture_lock );
for( i = 0; i < p_vout->render.i_pictures; i++ )
{
picture_t *p_pic = p_vout->render.pp_picture[i];
if( p_pic->i_status != READY_PICTURE )
{
/* We cannot change picture status if it is in READY_PICTURE state,
* Just make sure they won't be displayed */
p_pic->date = 1;
}
}
vlc_mutex_unlock( &p_vout->picture_lock );
}
static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block )
{
input_thread_t *p_input = p_dec->p_owner->p_input;
picture_t *p_pic;
//DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
while( (p_pic = p_dec->pf_decode_video( p_dec, &p_block )) )
{
vlc_mutex_lock( &p_input->p->counters.counters_lock );
stats_UpdateInteger( p_dec, p_input->p->counters.p_decoded_video, 1, NULL );
vlc_mutex_unlock( &p_input->p->counters.counters_lock );
if( p_dec->p_owner->i_preroll_end > 0 &&
p_pic->date < p_dec->p_owner->i_preroll_end )
if( p_pic->date < p_dec->p_owner->i_preroll_end )
{
vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
VoutDisplayedPicture( p_dec->p_owner->p_vout, p_pic );
continue;
}
else
if( p_dec->p_owner->i_preroll_end > 0 )
{
msg_Dbg( p_dec, "End of video preroll" );
if( p_dec->p_owner->p_vout )
VoutFlushPicture( p_dec->p_owner->p_vout );
/* */
p_dec->p_owner->i_preroll_end = -1;
vout_DatePicture( p_dec->p_owner->p_vout, p_pic,
p_pic->date );
vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
}
vout_DatePicture( p_dec->p_owner->p_vout, p_pic,
p_pic->date );
vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
}
}
/**
* Decode a block
*
* \param p_dec the decoder object
* \param p_block the block to decode
* \return VLC_SUCCESS or an error code
*/
static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
{
int i_rate = p_block ? p_block->i_rate : 1000;
const int i_rate = p_block ? p_block->i_rate : INPUT_RATE_DEFAULT;
if( p_block && p_block->i_buffer <= 0 )
{
......@@ -596,6 +633,8 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
}
else if( p_dec->fmt_in.i_cat == AUDIO_ES )
{
DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
if( p_dec->p_owner->p_packetizer )
{
block_t *p_packetized_block;
......@@ -629,6 +668,8 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
}
else if( p_dec->fmt_in.i_cat == VIDEO_ES )
{
DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
if( p_dec->p_owner->p_packetizer )
{
block_t *p_packetized_block;
......@@ -665,22 +706,22 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
input_thread_t *p_input = p_dec->p_owner->p_input;
vout_thread_t *p_vout;
subpicture_t *p_spu;
//DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
DecoderUpdatePreroll( &p_dec->p_owner->i_preroll_end, p_block );
while( (p_spu = p_dec->pf_decode_sub( p_dec, &p_block ) ) )
{
vlc_mutex_lock( &p_input->p->counters.counters_lock );
stats_UpdateInteger( p_dec, p_input->p->counters.p_decoded_sub, 1, NULL );
vlc_mutex_unlock( &p_input->p->counters.counters_lock );
if( p_dec->p_owner->i_preroll_end > 0 &&
p_spu->i_start < p_dec->p_owner->i_preroll_end &&
if( p_spu->i_start < p_dec->p_owner->i_preroll_end &&
( p_spu->i_stop <= 0 || p_spu->i_stop <= p_dec->p_owner->i_preroll_end ) )
{
spu_DestroySubpicture( p_dec->p_owner->p_vout->p_spu, p_spu );
continue;
}
p_dec->p_owner->i_preroll_end = -1;
p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
if( p_vout )
{
......@@ -977,7 +1018,7 @@ static picture_t *vout_new_buffer( decoder_t *p_dec )
static void vout_del_buffer( decoder_t *p_dec, picture_t *p_pic )
{
vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
VoutDisplayedPicture( p_dec->p_owner->p_vout, p_pic );
}
static void vout_link_picture( decoder_t *p_dec, picture_t *p_pic )
......
......@@ -70,9 +70,6 @@ struct es_out_id_t
int i_id;
es_out_pgrm_t *p_pgrm;
/* Signal a discontinuity in the timeline for every PID */
vlc_bool_t b_discontinuity;
/* Misc. */
int64_t i_preroll_end;
......@@ -302,7 +299,7 @@ es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id )
return NULL;
}
void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_audio )
void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_flush, vlc_bool_t b_audio )
{
es_out_sys_t *p_sys = out->p_sys;
int i;
......@@ -310,14 +307,11 @@ void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_audio )
for( i = 0; i < p_sys->i_es; i++ )
{
es_out_id_t *es = p_sys->es[i];
es->b_discontinuity = VLC_TRUE; /* signal discontinuity */
/* Send a dummy block to let decoder know that
* there is a discontinuity */
if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) )
{
input_DecoderDiscontinuity( es->p_dec );
}
input_DecoderDiscontinuity( es->p_dec, b_flush );
}
}
......@@ -851,7 +845,6 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
es->p_pgrm = p_pgrm;
es_format_Copy( &es->fmt, fmt );
es->i_preroll_end = -1;
es->b_discontinuity = VLC_FALSE;
switch( fmt->i_cat )
{
......@@ -1225,13 +1218,21 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
}
/* +11 -> avoid null value with non null dts/pts */
if( p_block->i_dts > 0 )
if( p_block->i_dts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) )
{
p_block->i_dts += i_delay;
}
else if( p_block->i_dts > 0 )
{
p_block->i_dts =
input_ClockGetTS( p_input, &p_pgrm->clock,
( p_block->i_dts + 11 ) * 9 / 100 ) + i_delay;
}
if( p_block->i_pts > 0 )
if( p_block->i_pts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) )
{
p_block->i_pts += i_delay;
}
else if( p_block->i_pts > 0 )
{
p_block->i_pts =
input_ClockGetTS( p_input, &p_pgrm->clock,
......@@ -1607,8 +1608,10 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
if( !es || !es->p_dec )
return VLC_EGENERIC;
/* XXX We should call input_ClockGetTS but PCR has been reseted
* and it will return 0, so we won't call input_ClockGetTS on all preroll samples
* but that's ugly(more time discontinuity), it need to be improved -- fenrir */
es->i_preroll_end = i_date;
input_DecoderPreroll( es->p_dec, i_date );
return VLC_SUCCESS;
}
......
......@@ -1480,7 +1480,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
if( f_pos > 1.0 ) f_pos = 1.0;
/* Reset the decoders states and clock sync (before calling the demuxer */
es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE );
input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
if( demux2_Control( p_input->p->input.p_demux, DEMUX_SET_POSITION,
f_pos ) )
{
......@@ -1518,7 +1518,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
/* Reset the decoders states and clock sync (before calling the demuxer */
es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE );
input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
i_ret = demux2_Control( p_input->p->input.p_demux,
DEMUX_SET_TIME, i_time );
......@@ -1609,11 +1609,9 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
p_input->i_state = val.i_int;
var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
#if 0 /* This will need modifications to decoders to work properly. */
/* Send discontinuity to decoders (it will allow them to flush
* if implemented */
input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE );
#endif
input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE, VLC_FALSE );
}
else if( val.i_int == PAUSE_S && !p_input->p->b_can_pause )
{
......@@ -1666,7 +1664,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
/* We will not send audio data if new rate != default */
if( i_rate != INPUT_RATE_DEFAULT && p_input->p->i_rate == INPUT_RATE_DEFAULT )
input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE );
input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_TRUE );
p_input->p->i_rate = i_rate;
......@@ -1726,8 +1724,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
if( i_title >= 0 && i_title < p_input->p->input.i_title )
{
input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE );
es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
demux2_Control( p_demux, DEMUX_SET_TITLE, i_title );
input_ControlVarTitle( p_input, i_title );
......@@ -1747,8 +1745,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
if( i_title >= 0 && i_title < p_input->p->input.i_title )
{
input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE );
es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
access2_Control( p_access, ACCESS_SET_TITLE, i_title );
stream_AccessReset( p_input->p->input.p_stream );
......@@ -1788,8 +1786,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
if( i_seekpoint >= 0 && i_seekpoint <
p_input->p->input.title[p_demux->info.i_title]->i_seekpoint )
{
input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE );
es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
demux2_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint );
}
......@@ -1824,8 +1822,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
if( i_seekpoint >= 0 && i_seekpoint <
p_input->p->input.title[p_access->info.i_title]->i_seekpoint )
{
input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE );
es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
access2_Control( p_access, ACCESS_SET_SEEKPOINT,
i_seekpoint );
......
......@@ -246,15 +246,14 @@ void stream_AccessReset( stream_t *s );
void stream_AccessUpdate( stream_t *s );
/* decoder.c */
void input_DecoderDiscontinuity( decoder_t * p_dec );
void input_DecoderDiscontinuity( decoder_t * p_dec, vlc_bool_t b_flush );
vlc_bool_t input_DecoderEmpty( decoder_t * p_dec );
void input_DecoderPreroll( decoder_t *p_dec, int64_t i_preroll_end );
/* es_out.c */
es_out_t *input_EsOutNew( input_thread_t * );
void input_EsOutDelete( es_out_t * );
es_out_id_t *input_EsOutGetFromID( es_out_t *, int i_id );
void input_EsOutDiscontinuity( es_out_t *, vlc_bool_t b_audio );
void input_EsOutDiscontinuity( es_out_t *, vlc_bool_t b_flush, vlc_bool_t b_audio );
void input_EsOutSetDelay( es_out_t *, int i_cat, int64_t );
vlc_bool_t input_EsOutDecodersEmpty( es_out_t * );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment