From patchwork Mon Nov 19 09:04:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jing SUN X-Patchwork-Id: 11072 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 8FBDA44D601 for ; Mon, 19 Nov 2018 10:14:39 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 0A1E1689BA3; Mon, 19 Nov 2018 10:14:40 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id D24F4689AD8 for ; Mon, 19 Nov 2018 10:14:33 +0200 (EET) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 19 Nov 2018 00:14:33 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,251,1539673200"; d="scan'208";a="87514838" Received: from unknown (HELO localhost.localdomain.bj.intel.com) ([172.16.181.151]) by fmsmga008.fm.intel.com with ESMTP; 19 Nov 2018 00:14:32 -0800 From: Jing SUN To: ffmpeg-devel@ffmpeg.org Date: Mon, 19 Nov 2018 17:04:37 +0800 Message-Id: <1542618277-22111-1-git-send-email-jing.a.sun@intel.com> X-Mailer: git-send-email 1.8.3.1 Subject: [FFmpeg-devel] [PATCH 1/1] avcodec/vaapi_encode: add frame-skip func X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Jing SUN MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" 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 --- libavcodec/vaapi_encode.c | 142 ++++++++++++++++++++++++++++++++++++++++++++-- libavcodec/vaapi_encode.h | 5 ++ libavutil/frame.c | 1 + libavutil/frame.h | 5 ++ 4 files changed, 149 insertions(+), 4 deletions(-) diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c index 2fe8501..a401d61 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,69 @@ 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"); + +#ifdef VAEncMiscParameterSkipFrame + 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; + } +#else + if (pic->skipped_flag) { + av_log(avctx, AV_LOG_INFO, "Skip-frame isn't supported and pic %"PRId64"/%"PRId64" isn't skipped.\n", + pic->display_order, pic->encode_order); + + pic->skipped_flag = 0; + ctx->skipped_pic_count = 0; + } +#endif + vas = vaBeginPicture(ctx->hwctx->display, ctx->va_context, pic->input_surface); if (vas != VA_STATUS_SUCCESS) { @@ -500,9 +605,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 +647,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 +683,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 +2126,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 {