[vlc-commits] decodec: avcodec: rework decoding loop
Francois Cartegnie
git at videolan.org
Sun Apr 22 14:41:34 CEST 2018
vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Thu Apr 19 15:52:26 2018 +0200| [44cc0d5633697d58f1b88c4f71b83250ed794efd] | committer: Francois Cartegnie
decodec: avcodec: rework decoding loop
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=44cc0d5633697d58f1b88c4f71b83250ed794efd
---
modules/codec/avcodec/video.c | 201 ++++++++++++++++++++++--------------------
1 file changed, 106 insertions(+), 95 deletions(-)
diff --git a/modules/codec/avcodec/video.c b/modules/codec/avcodec/video.c
index b505d34846..a3a4316628 100644
--- a/modules/codec/avcodec/video.c
+++ b/modules/codec/avcodec/video.c
@@ -48,6 +48,13 @@
#include "va.h"
#include "../codec/cc.h"
+#define FRAME_INFO_DEPTH 64
+
+struct frame_info_s
+{
+ bool b_eos;
+ bool b_display;
+};
/*****************************************************************************
* decoder_sys_t : decoder descriptor
@@ -69,6 +76,8 @@ struct decoder_sys_t
bool b_from_preroll;
enum AVDiscard i_skip_frame;
+ struct frame_info_s frame_info[FRAME_INFO_DEPTH];
+
/* how many decoded frames are late */
int i_late_frames;
mtime_t i_late_frames_start;
@@ -547,6 +556,7 @@ int InitVideoDec( vlc_object_t *obj )
* PTS correctly */
p_context->get_buffer2 = lavc_GetFrame;
p_context->opaque = p_dec;
+ p_context->reordered_opaque = 0;
int i_thread_count = var_InheritInteger( p_dec, "avcodec-threads" );
if( i_thread_count <= 0 )
@@ -665,26 +675,6 @@ static void Flush( decoder_t *p_dec )
decoder_AbortPictures( p_dec, false );
}
-static bool check_block_validity( decoder_sys_t *p_sys, block_t *block )
-{
- if( !block)
- return true;
-
- if( block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
- {
- 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( block->i_flags & BLOCK_FLAG_CORRUPTED )
- {
- block_Release( block );
- return false;
- }
- }
- return true;
-}
-
static bool check_block_being_late( decoder_sys_t *p_sys, block_t *block, mtime_t current_time)
{
if( !block )
@@ -895,17 +885,16 @@ static int DecodeSidedata( decoder_t *p_dec, const AVFrame *frame, picture_t *p_
/*****************************************************************************
* DecodeBlock: Called to decode one or more frames
+ * drains if pp_block == NULL
+ * tries to output only if p_block == NULL
*****************************************************************************/
-static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block, bool *error )
+static int DecodeBlock( decoder_t *p_dec, block_t **pp_block )
{
decoder_sys_t *p_sys = p_dec->p_sys;
AVCodecContext *p_context = p_sys->p_context;
/* Boolean if we assume that we should get valid pic as result */
bool b_need_output_picture = true;
-
- /* Boolean for END_OF_SEQUENCE */
- bool eos_spotted = false;
-
+ bool b_error = false;
block_t *p_block;
mtime_t current_time;
@@ -919,24 +908,21 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block, bool *error
p_block = pp_block ? *pp_block : NULL;
if(!p_block && !(p_sys->p_codec->capabilities & AV_CODEC_CAP_DELAY) )
- return NULL;
+ return VLCDEC_SUCCESS;
if( !avcodec_is_open( p_context ) )
{
if( p_block )
block_Release( p_block );
- return NULL;
+ return VLCDEC_SUCCESS;
}
- if( !check_block_validity( p_sys, p_block ) )
- return NULL;
-
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 ?)" );
- return NULL;
+ p_block = NULL;
}
@@ -962,7 +948,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block, bool *error
if( p_block )
block_Release( p_block );
msg_Warn( p_dec, "More than 11 late frames, dropping frame" );
- return NULL;
+ p_block = NULL;
}
}
if( !b_need_output_picture )
@@ -978,89 +964,99 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block, bool *error
* that the real frame size */
if( p_block && p_block->i_buffer > 0 )
{
- eos_spotted = ( p_block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE ) != 0;
-
p_block = block_Realloc( p_block, 0,
p_block->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE );
if( !p_block )
- return NULL;
+ return VLCDEC_SUCCESS;
p_block->i_buffer -= FF_INPUT_BUFFER_PADDING_SIZE;
*pp_block = p_block;
memset( p_block->p_buffer + p_block->i_buffer, 0,
FF_INPUT_BUFFER_PADDING_SIZE );
}
- while( !p_block || p_block->i_buffer > 0 || eos_spotted )
+ do
{
- int i_used;
- AVPacket pkt;
+ int i_used = 0;
post_mt( p_sys );
- av_init_packet( &pkt );
- if( p_block && p_block->i_buffer > 0 )
+ if( (p_block && p_block->i_buffer > 0) || pp_block == NULL /* drain */ )
{
- pkt.data = p_block->p_buffer;
- pkt.size = p_block->i_buffer;
- pkt.pts = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : AV_NOPTS_VALUE;
- pkt.dts = p_block->i_dts > VLC_TS_INVALID ? p_block->i_dts : AV_NOPTS_VALUE;
- }
- else
- {
- /* Return delayed frames if codec has CODEC_CAP_DELAY */
- pkt.data = NULL;
- pkt.size = 0;
- }
+ AVPacket pkt;
+ av_init_packet( &pkt );
+ if( p_block && p_block->i_buffer > 0 )
+ {
+ pkt.data = p_block->p_buffer;
+ pkt.size = p_block->i_buffer;
+ pkt.pts = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : AV_NOPTS_VALUE;
+ pkt.dts = p_block->i_dts > VLC_TS_INVALID ? p_block->i_dts : AV_NOPTS_VALUE;
+ }
+ else
+ {
+ /* Drain */
+ pkt.data = NULL;
+ pkt.size = 0;
+ }
- if( !p_sys->palette_sent )
- {
- uint8_t *pal = av_packet_new_side_data(&pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
- if (pal) {
- memcpy(pal, p_dec->fmt_in.video.p_palette->palette, AVPALETTE_SIZE);
- p_sys->palette_sent = true;
+ if( !p_sys->palette_sent )
+ {
+ uint8_t *pal = av_packet_new_side_data(&pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
+ if (pal) {
+ memcpy(pal, p_dec->fmt_in.video.p_palette->palette, AVPALETTE_SIZE);
+ p_sys->palette_sent = true;
+ }
}
- }
- /* Make sure we don't reuse the same timestamps twice */
- if( p_block )
- {
- p_block->i_pts =
- p_block->i_dts = VLC_TS_INVALID;
- }
+ /* Make sure we don't reuse the same timestamps twice */
+ if( p_block )
+ {
+ p_block->i_pts =
+ p_block->i_dts = VLC_TS_INVALID;
+ }
#if LIBAVCODEC_VERSION_CHECK( 57, 0, 0xFFFFFFFFU, 64, 101 )
- if( !b_need_output_picture )
- pkt.flags |= AV_PKT_FLAG_DISCARD;
+ if( !b_need_output_picture )
+ pkt.flags |= AV_PKT_FLAG_DISCARD;
#endif
- int ret = avcodec_send_packet(p_context, &pkt);
- if( ret != 0 && ret != AVERROR(EAGAIN) )
- {
- if (ret == AVERROR(ENOMEM) || ret == AVERROR(EINVAL))
+ int ret = avcodec_send_packet(p_context, &pkt);
+ if( ret != 0 && ret != AVERROR(EAGAIN) )
{
- msg_Err(p_dec, "avcodec_send_packet critical error");
- *error = true;
+ if (ret == AVERROR(ENOMEM) || ret == AVERROR(EINVAL))
+ {
+ msg_Err(p_dec, "avcodec_send_packet critical error");
+ b_error = true;
+ }
+ av_packet_unref( &pkt );
+ break;
}
+
+ struct frame_info_s *p_frame_info = &p_sys->frame_info[p_context->reordered_opaque % FRAME_INFO_DEPTH];
+ p_frame_info->b_eos = p_block && (p_block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE);
+ p_frame_info->b_display = b_need_output_picture;
+
+ p_context->reordered_opaque++;
+ i_used = ret != AVERROR(EAGAIN) ? pkt.size : 0;
av_packet_unref( &pkt );
- break;
+
+ if( p_frame_info->b_eos )
+ avcodec_send_packet( p_context, NULL );
}
- i_used = ret != AVERROR(EAGAIN) ? pkt.size : 0;
- av_packet_unref( &pkt );
AVFrame *frame = av_frame_alloc();
if (unlikely(frame == NULL))
{
- *error = true;
+ b_error = true;
break;
}
- ret = avcodec_receive_frame(p_context, frame);
+ int ret = avcodec_receive_frame(p_context, frame);
if( ret != 0 && ret != AVERROR(EAGAIN) )
{
if (ret == AVERROR(ENOMEM) || ret == AVERROR(EINVAL))
{
msg_Err(p_dec, "avcodec_receive_frame critical error");
- *error = true;
+ b_error = true;
}
av_frame_free(&frame);
/* After draining, we need to reset decoder with a flush */
@@ -1072,14 +1068,8 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block, bool *error
wait_mt( p_sys );
- if( eos_spotted )
- p_sys->b_first_frame = true;
-
if( p_block )
{
- if( p_block->i_buffer <= 0 )
- eos_spotted = false;
-
/* Consumed bytes */
p_block->p_buffer += i_used;
p_block->i_buffer -= i_used;
@@ -1093,6 +1083,10 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block, bool *error
continue;
}
+ struct frame_info_s *p_frame_info = &p_sys->frame_info[frame->reordered_opaque % FRAME_INFO_DEPTH];
+ if( p_frame_info->b_eos )
+ p_sys->b_first_frame = true;
+
/* Compute the PTS */
#ifdef FF_API_PKT_PTS
mtime_t i_pts = frame->pts;
@@ -1122,7 +1116,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block, bool *error
}
#if !LIBAVCODEC_VERSION_CHECK( 57, 0, 0xFFFFFFFFU, 64, 101 )
- if( !b_need_output_picture )
+ if( !p_frame_info->b_display )
{
av_frame_free(&frame);
continue;
@@ -1142,7 +1136,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block, bool *error
= malloc( sizeof(video_palette_t) );
if( !p_palette )
{
- *error = true;
+ b_error = true;
av_frame_free(&frame);
break;
}
@@ -1229,25 +1223,42 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block, bool *error
if (i_pts > VLC_TS_INVALID)
{
p_sys->b_first_frame = false;
- return p_pic;
+ decoder_QueueVideo( p_dec, p_pic );
}
else
picture_Release( p_pic );
- }
+
+ } while( true );
if( p_block )
block_Release( p_block );
- return NULL;
+
+ return b_error ? VLCDEC_ECRITICAL : VLCDEC_SUCCESS;
}
static int DecodeVideo( decoder_t *p_dec, block_t *p_block )
{
- block_t **pp_block = p_block ? &p_block : NULL;
- picture_t *p_pic;
- bool error = false;
- while( ( p_pic = DecodeBlock( p_dec, pp_block, &error ) ) != NULL )
- decoder_QueueVideo( p_dec, p_pic );
- return error ? VLCDEC_ECRITICAL : VLCDEC_SUCCESS;
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ block_t **pp_block = p_block ? &p_block : NULL /* drain signal */;
+
+ if( p_block &&
+ p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
+ {
+ /* Drain */
+ DecodeBlock( p_dec, NULL );
+
+ 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 );
+ p_block = NULL; /* output only */
+ }
+ }
+
+ return DecodeBlock( p_dec, pp_block );
}
/*****************************************************************************
More information about the vlc-commits
mailing list