[vlc-commits] decoder: avcodec: rework framedrop
Francois Cartegnie
git at videolan.org
Sun Apr 22 21:30:43 CEST 2018
vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Fri Apr 20 16:44:59 2018 +0200| [5ebb1c252a31c073ae42944834103aceead0a0fc] | committer: Francois Cartegnie
decoder: avcodec: rework framedrop
Tries to recover in hevc case.
Avoids unwanted 5s drops in case of pause.
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=5ebb1c252a31c073ae42944834103aceead0a0fc
---
modules/codec/avcodec/video.c | 110 ++++++++++++++++++++----------------------
1 file changed, 51 insertions(+), 59 deletions(-)
diff --git a/modules/codec/avcodec/video.c b/modules/codec/avcodec/video.c
index a3a4316628..13223e0e59 100644
--- a/modules/codec/avcodec/video.c
+++ b/modules/codec/avcodec/video.c
@@ -78,9 +78,15 @@ struct decoder_sys_t
struct frame_info_s frame_info[FRAME_INFO_DEPTH];
+ enum
+ {
+ FRAMEDROP_NONE,
+ FRAMEDROP_NONREF,
+ FRAMEDROP_AGGRESSIVE_RECOVER,
+ } framedrop;
/* how many decoded frames are late */
int i_late_frames;
- mtime_t i_late_frames_start;
+ int64_t i_last_output_frame;
mtime_t i_last_late_delay;
/* for direct rendering */
@@ -606,6 +612,8 @@ int InitVideoDec( vlc_object_t *obj )
p_sys->b_first_frame = true;
p_sys->i_late_frames = 0;
p_sys->b_from_preroll = false;
+ p_sys->i_last_output_frame = -1;
+ p_sys->framedrop = FRAMEDROP_NONE;
/* Set output properties */
if( GetVlcChroma( &p_dec->fmt_out.video, p_context->pix_fmt ) != VLC_SUCCESS )
@@ -658,6 +666,7 @@ static void Flush( decoder_t *p_dec )
date_Set(&p_sys->pts, VLC_TS_INVALID); /* To make sure we recover properly */
p_sys->i_late_frames = 0;
+ p_sys->framedrop = FRAMEDROP_NONE;
cc_Flush( &p_sys->cc );
/* Abort pictures in order to unblock all avcodec workers threads waiting
@@ -675,53 +684,53 @@ static void Flush( decoder_t *p_dec )
decoder_AbortPictures( p_dec, false );
}
-static bool check_block_being_late( decoder_sys_t *p_sys, block_t *block, mtime_t current_time)
+static block_t * filter_earlydropped_blocks( decoder_t *p_dec, block_t *block )
{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+
if( !block )
- return false;
+ return NULL;
+
if( block->i_flags & BLOCK_FLAG_PREROLL )
{
/* Do not care about late frames when prerolling
* TODO avoid decoding of non reference frame
* (ie all B except for H264 where it depends only on nal_ref_idc) */
p_sys->i_late_frames = 0;
+ p_sys->framedrop = FRAMEDROP_NONE;
p_sys->b_from_preroll = true;
p_sys->i_last_late_delay = INT64_MAX;
}
- if( p_sys->i_late_frames <= 0 )
- return false;
+ if( p_sys->i_late_frames == 0 )
+ p_sys->framedrop = FRAMEDROP_NONE;
- if( current_time - p_sys->i_late_frames_start > (5*CLOCK_FREQ))
- {
- date_Set( &p_sys->pts, VLC_TS_INVALID ); /* To make sure we recover properly */
- block_Release( block );
- p_sys->i_late_frames--;
- return true;
- }
- return false;
-}
+ if( p_sys->framedrop == FRAMEDROP_NONE && p_sys->i_late_frames < 11 )
+ return block;
-static bool check_frame_should_be_dropped( decoder_sys_t *p_sys, AVCodecContext *p_context, bool *b_need_output_picture )
-{
- if( p_sys->i_late_frames <= 4)
- return false;
-
- *b_need_output_picture = false;
- if( p_sys->i_late_frames < 12 )
+ if( p_sys->i_last_output_frame >= 0 &&
+ p_sys->p_context->reordered_opaque - p_sys->i_last_output_frame > 24 )
{
- p_context->skip_frame =
- (p_sys->i_skip_frame <= AVDISCARD_NONREF) ?
- AVDISCARD_NONREF : p_sys->i_skip_frame;
+ p_sys->framedrop = FRAMEDROP_AGGRESSIVE_RECOVER;
}
- else
+
+ /* A good idea could be to decode all I pictures and see for the other */
+ if( p_sys->framedrop == FRAMEDROP_AGGRESSIVE_RECOVER )
{
- /* picture too late, won't decode
- * but break picture until a new I, and for mpeg4 ...*/
- p_sys->i_late_frames--; /* needed else it will never be decrease */
- return true;
+ if( !(block->i_flags & BLOCK_FLAG_TYPE_I) )
+ {
+ msg_Err( p_dec, "more than %"PRId64" frames of late video -> "
+ "dropping frame (computer too slow ?)",
+ p_sys->p_context->reordered_opaque - p_sys->i_last_output_frame );
+
+ date_Set( &p_sys->pts, VLC_TS_INVALID ); /* To make sure we recover properly */
+ block_Release( block );
+ p_sys->i_late_frames--;
+ return NULL;
+ }
}
- return false;
+
+ return block;
}
static void interpolate_next_pts( decoder_t *p_dec, AVFrame *frame )
@@ -741,7 +750,8 @@ static void interpolate_next_pts( decoder_t *p_dec, AVFrame *frame )
date_Increment( &p_sys->pts, i_tick + frame->repeat_pict );
}
-static void update_late_frame_count( decoder_t *p_dec, block_t *p_block, mtime_t current_time, mtime_t i_pts )
+static void update_late_frame_count( decoder_t *p_dec, block_t *p_block,
+ mtime_t current_time, mtime_t i_pts, int64_t i_fnum )
{
decoder_sys_t *p_sys = p_dec->p_sys;
/* Update frame late count (except when doing preroll) */
@@ -763,12 +773,10 @@ static void update_late_frame_count( decoder_t *p_dec, block_t *p_block, mtime_t
}
p_sys->i_late_frames++;
- if( p_sys->i_late_frames == 1 )
- p_sys->i_late_frames_start = current_time;
-
}
else
{
+ p_sys->i_last_output_frame = i_fnum;
p_sys->i_late_frames = 0;
}
}
@@ -897,7 +905,6 @@ static int DecodeBlock( decoder_t *p_dec, block_t **pp_block )
bool b_error = false;
block_t *p_block;
- mtime_t current_time;
if( !p_context->extradata_size && p_dec->fmt_in.i_extra )
{
@@ -917,17 +924,6 @@ static int DecodeBlock( decoder_t *p_dec, block_t **pp_block )
return VLCDEC_SUCCESS;
}
- current_time = mdate();
- if( p_dec->b_frame_drop_allowed && check_block_being_late( p_sys, p_block, current_time) )
- {
- msg_Err( p_dec, "more than 5 seconds of late video -> "
- "dropping frame (computer too slow ?)" );
- p_block = NULL;
- }
-
-
- /* A good idea could be to decode all I pictures and see for the other */
-
/* Defaults that if we aren't in prerolling, we want output picture
same for if we are flushing (p_block==NULL) */
if( !p_block || !(p_block->i_flags & BLOCK_FLAG_PREROLL) )
@@ -942,19 +938,13 @@ static int DecodeBlock( decoder_t *p_dec, block_t **pp_block )
/* Check also if we should/can drop the block and move to next block
as trying to catchup the speed*/
- if( p_dec->b_frame_drop_allowed &&
- check_frame_should_be_dropped( p_sys, p_context, &b_need_output_picture ) )
- {
- if( p_block )
- block_Release( p_block );
- msg_Warn( p_dec, "More than 11 late frames, dropping frame" );
- p_block = NULL;
- }
+ if( p_dec->b_frame_drop_allowed )
+ p_block = filter_earlydropped_blocks( p_dec, p_block );
}
- if( !b_need_output_picture )
+
+ if( !b_need_output_picture || p_sys->framedrop == FRAMEDROP_NONREF )
{
- p_context->skip_frame = __MAX( p_context->skip_frame,
- AVDISCARD_NONREF );
+ p_context->skip_frame = __MAX( p_context->skip_frame, AVDISCARD_NONREF );
}
/*
@@ -1105,7 +1095,7 @@ static int DecodeBlock( decoder_t *p_dec, block_t **pp_block )
interpolate_next_pts( p_dec, frame );
- update_late_frame_count( p_dec, p_block, current_time, i_pts);
+ update_late_frame_count( p_dec, p_block, mdate(), i_pts, frame->reordered_opaque);
if( ( !p_sys->p_va && !frame->linesize[0] ) ||
( p_dec->b_frame_drop_allowed && (frame->flags & AV_FRAME_FLAG_CORRUPT) &&
@@ -1246,11 +1236,13 @@ static int DecodeVideo( decoder_t *p_dec, block_t *p_block )
{
/* Drain */
DecodeBlock( p_dec, NULL );
+ p_sys->i_late_frames = 0;
+ p_sys->i_last_output_frame = -1;
+ p_sys->framedrop = FRAMEDROP_NONE;
date_Set( &p_sys->pts, VLC_TS_INVALID ); /* To make sure we recover properly */
cc_Flush( &p_sys->cc );
- p_sys->i_late_frames = 0;
if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
{
block_Release( p_block );
More information about the vlc-commits
mailing list