frame-skip is required to implement network bandwidth self-adaptive vaapi encoding. To make a frame skipped, allocate its frame side data of AV_FRAME_DATA_SKIP_FRAME type and set its value to 1.
Signed-off-by: Jing SUN <jing.a....@intel.com> --- libavcodec/vaapi_encode.c | 132 ++++++++++++++++++++++++++++++++++++++++++++-- libavcodec/vaapi_encode.h | 5 ++ libavutil/frame.c | 1 + libavutil/frame.h | 5 ++ 4 files changed, 139 insertions(+), 4 deletions(-) diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c index 2fe8501..ea06404 100644 --- a/libavcodec/vaapi_encode.c +++ b/libavcodec/vaapi_encode.c @@ -23,6 +23,7 @@ #include "libavutil/common.h" #include "libavutil/log.h" #include "libavutil/pixdesc.h" +#include "libavutil/intreadwrite.h" #include "vaapi_encode.h" #include "avcodec.h" @@ -103,6 +104,47 @@ static int vaapi_encode_make_param_buffer(AVCodecContext *avctx, return 0; } +static int vaapi_encode_check_if_skip(AVCodecContext *avctx, + VAAPIEncodePicture *pic) +{ + AVFrameSideData *fside = NULL; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodePicture *cur = NULL; + int i = 0; + + if (!pic || !pic->input_image) + return AVERROR(EINVAL); + + fside = av_frame_get_side_data(pic->input_image, AV_FRAME_DATA_SKIP_FRAME); + if (fside) + pic->skipped_flag = AV_RL8(fside->data); + else + pic->skipped_flag = 0; + + if (0 == pic->skipped_flag) + return 0; + + if ((pic->type == PICTURE_TYPE_IDR) || (pic->type == PICTURE_TYPE_I)) { + av_log(avctx, AV_LOG_INFO, "Can't skip IDR/I pic %"PRId64"/%"PRId64".\n", + pic->display_order, pic->encode_order); + pic->skipped_flag = 0; + return 0; + } + + for (cur = ctx->pic_start; cur; cur = cur->next) { + for (i=0; i < cur->nb_refs; ++i) { + if (cur->refs[i] == pic) { + av_log(avctx, AV_LOG_INFO, "Can't skip ref pic %"PRId64"/%"PRId64".\n", + pic->display_order, pic->encode_order); + pic->skipped_flag = 0; + return 0; + } + } + } + + return 0; +} + static int vaapi_encode_wait(AVCodecContext *avctx, VAAPIEncodePicture *pic) { @@ -418,6 +460,59 @@ static int vaapi_encode_issue(AVCodecContext *avctx, } } + err = vaapi_encode_check_if_skip(avctx, pic); + if (err != 0) + av_log(avctx, AV_LOG_ERROR, "Fail to check if skip.\n"); + + if (pic->skipped_flag) { + av_log(avctx, AV_LOG_INFO, "Skip pic %"PRId64"/%"PRId64" as requested.\n", + pic->display_order, pic->encode_order); + + ++ctx->skipped_pic_count; + pic->encode_issued = 1; + + return 0; + } else if (ctx->skipped_pic_count > 0) { + VABufferID skip_param_id; + VAEncMiscParameterBuffer *misc_param; + VAEncMiscParameterSkipFrame *skip_param; + + err = vaapi_encode_make_param_buffer(avctx, pic, + VAEncMiscParameterBufferType, NULL, + (sizeof(VAEncMiscParameterBuffer) + + sizeof(VAEncMiscParameterSkipFrame))); + if (err < 0) + goto fail; + + skip_param_id = pic->param_buffers[pic->nb_param_buffers-1]; + + vas = vaMapBuffer(ctx->hwctx->display, + skip_param_id, + (void **)&misc_param); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to map skip-frame buffer: " + "%d (%s).\n", vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail; + } + + misc_param->type = (VAEncMiscParameterType)VAEncMiscParameterTypeSkipFrame; + skip_param = (VAEncMiscParameterSkipFrame *)misc_param->data; + skip_param->skip_frame_flag = 1; + skip_param->num_skip_frames = ctx->skipped_pic_count; + skip_param->size_skip_frames = 0; + + vas = vaUnmapBuffer(ctx->hwctx->display, skip_param_id); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to unmap skip-frame buffer: " + "%d (%s).\n", vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail; + } + + ctx->skipped_pic_count = 0; + } + vas = vaBeginPicture(ctx->hwctx->display, ctx->va_context, pic->input_surface); if (vas != VA_STATUS_SUCCESS) { @@ -500,9 +595,28 @@ static int vaapi_encode_output(AVCodecContext *avctx, VAStatus vas; int err; - err = vaapi_encode_wait(avctx, pic); - if (err < 0) - return err; + if (!pic->skipped_flag) { + err = vaapi_encode_wait(avctx, pic); + if (err < 0) + return err; + } else { + av_frame_free(&pic->input_image); + pic->encode_complete = 1; + + err = av_new_packet(pkt, 0); + if (err < 0) + goto fail; + + pkt->pts = pic->pts; + + av_buffer_unref(&pic->output_buffer_ref); + pic->output_buffer = VA_INVALID_ID; + + av_log(avctx, AV_LOG_DEBUG, "Output 0 byte for pic %"PRId64"/%"PRId64".\n", + pic->display_order, pic->encode_order); + + return 0; + } buf_list = NULL; vas = vaMapBuffer(ctx->hwctx->display, pic->output_buffer, @@ -523,6 +637,9 @@ static int vaapi_encode_output(AVCodecContext *avctx, goto fail_mapped; memcpy(pkt->data, buf->buf, buf->size); + + memset(buf->buf, 0, buf->size); + buf->size = 0; } if (pic->type == PICTURE_TYPE_IDR) @@ -556,7 +673,12 @@ fail: static int vaapi_encode_discard(AVCodecContext *avctx, VAAPIEncodePicture *pic) { - vaapi_encode_wait(avctx, pic); + if (!pic->skipped_flag) { + vaapi_encode_wait(avctx, pic); + } else { + av_frame_free(&pic->input_image); + pic->encode_complete = 1; + } if (pic->output_buffer_ref) { av_log(avctx, AV_LOG_DEBUG, "Discard output for pic " @@ -1994,6 +2116,8 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) } } + ctx->skipped_pic_count = 0; + return 0; fail: diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h index 965fe65..bcee0b6 100644 --- a/libavcodec/vaapi_encode.h +++ b/libavcodec/vaapi_encode.h @@ -92,6 +92,8 @@ typedef struct VAAPIEncodePicture { int nb_slices; VAAPIEncodeSlice *slices; + + uint8_t skipped_flag; } VAAPIEncodePicture; typedef struct VAAPIEncodeProfile { @@ -246,6 +248,9 @@ typedef struct VAAPIEncodeContext { int gop_counter; int p_counter; int end_of_stream; + + // Skipped frame info + unsigned int skipped_pic_count; } VAAPIEncodeContext; enum { diff --git a/libavutil/frame.c b/libavutil/frame.c index 9b3fb13..c5fa205 100644 --- a/libavutil/frame.c +++ b/libavutil/frame.c @@ -840,6 +840,7 @@ const char *av_frame_side_data_name(enum AVFrameSideDataType type) case AV_FRAME_DATA_QP_TABLE_PROPERTIES: return "QP table properties"; case AV_FRAME_DATA_QP_TABLE_DATA: return "QP table data"; #endif + case AV_FRAME_DATA_SKIP_FRAME: return "Skip frame"; } return NULL; } diff --git a/libavutil/frame.h b/libavutil/frame.h index 66f27f4..8ef6475 100644 --- a/libavutil/frame.h +++ b/libavutil/frame.h @@ -166,6 +166,11 @@ enum AVFrameSideDataType { * function in libavutil/timecode.c. */ AV_FRAME_DATA_S12M_TIMECODE, + + /** + * VAAPI Encode skip-frame indicator. + */ + AV_FRAME_DATA_SKIP_FRAME, }; enum AVActiveFormatDescription { -- 1.8.3.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel