From f6b85523692b0e7d4c4efb8449fa201d313424fe Mon Sep 17 00:00:00 2001 From: Mark Thompson Date: Tue, 12 Apr 2016 23:13:31 +0100 Subject: [PATCH 1/7] vaapi_encode: Refactor slightly to allow easier setting of global options Signed-off-by: Anton Khirnov --- libavcodec/vaapi_encode.c | 13 +++++++++++ libavcodec/vaapi_encode.h | 10 +++++++-- libavcodec/vaapi_encode_h264.c | 30 +++++++++++++------------ libavcodec/vaapi_encode_h265.c | 40 ++++++++++++++++++++------------- libavcodec/vaapi_encode_mjpeg.c | 22 +++++++++--------- 5 files changed, 73 insertions(+), 42 deletions(-) diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c index 9f2083d1f7..b1f00695c7 100644 --- a/libavcodec/vaapi_encode.c +++ b/libavcodec/vaapi_encode.c @@ -202,6 +202,19 @@ static int vaapi_encode_issue(AVCodecContext *avctx, pic->nb_param_buffers = 0; + if (pic->encode_order == 0) { + // Global parameter buffers are set on the first picture only. + + for (i = 0; i < ctx->nb_global_params; i++) { + err = vaapi_encode_make_param_buffer(avctx, pic, + VAEncMiscParameterBufferType, + (char*)ctx->global_params[i], + ctx->global_params_size[i]); + if (err < 0) + goto fail; + } + } + if (pic->type == PICTURE_TYPE_IDR && ctx->codec->init_sequence_params) { err = vaapi_encode_make_param_buffer(avctx, pic, VAEncSequenceParameterBufferType, diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h index 1aea45884b..9716578e5a 100644 --- a/libavcodec/vaapi_encode.h +++ b/libavcodec/vaapi_encode.h @@ -32,6 +32,8 @@ struct VAAPIEncodeType; struct VAAPIEncodePicture; enum { + MAX_CONFIG_ATTRIBUTES = 4, + MAX_GLOBAL_PARAMS = 4, MAX_PICTURE_REFERENCES = 2, MAX_PICTURE_SLICES = 1, MAX_PARAM_BUFFERS = 16, @@ -128,15 +130,19 @@ typedef struct VAAPIEncodeContext { AVBufferRef *recon_frames_ref; AVHWFramesContext *recon_frames; - VAConfigAttrib *config_attributes; + VAConfigAttrib config_attributes[MAX_CONFIG_ATTRIBUTES]; int nb_config_attributes; + VAEncMiscParameterBuffer *global_params[MAX_GLOBAL_PARAMS]; + size_t global_params_size[MAX_GLOBAL_PARAMS]; + int nb_global_params; + // Per-sequence parameter structure (VAEncSequenceParameterBuffer*). void *codec_sequence_params; // Per-sequence parameters found in the per-picture parameter // structure (VAEncPictureParameterBuffer*). - void *codec_picture_params; + void *codec_picture_params; // Current encoding window, in display (input) order. VAAPIEncodePicture *pic_start, *pic_end; diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c index 12a0ec2db1..6a77ab1e18 100644 --- a/libavcodec/vaapi_encode_h264.c +++ b/libavcodec/vaapi_encode_h264.c @@ -690,20 +690,21 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, return 0; } -static VAConfigAttrib vaapi_encode_h264_config_attributes[] = { - { .type = VAConfigAttribRTFormat, - .value = VA_RT_FORMAT_YUV420 }, - { .type = VAConfigAttribRateControl, - .value = VA_RC_CQP }, - { .type = VAConfigAttribEncPackedHeaders, - .value = (VA_ENC_PACKED_HEADER_SEQUENCE | - VA_ENC_PACKED_HEADER_SLICE) }, -}; - static av_cold int vaapi_encode_h264_init_internal(AVCodecContext *avctx) { + static const VAConfigAttrib default_config_attributes[] = { + { .type = VAConfigAttribRTFormat, + .value = VA_RT_FORMAT_YUV420 }, + { .type = VAConfigAttribRateControl, + .value = VA_RC_CQP }, + { .type = VAConfigAttribEncPackedHeaders, + .value = (VA_ENC_PACKED_HEADER_SEQUENCE | + VA_ENC_PACKED_HEADER_SLICE) }, + }; + VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH264Context *priv = ctx->priv_data; + int i; switch (avctx->profile) { case FF_PROFILE_H264_CONSTRAINED_BASELINE: @@ -759,6 +760,11 @@ static av_cold int vaapi_encode_h264_init_internal(AVCodecContext *avctx) return AVERROR_PATCHWELCOME; } + for (i = 0; i < FF_ARRAY_ELEMS(default_config_attributes); i++) { + ctx->config_attributes[ctx->nb_config_attributes++] = + default_config_attributes[i]; + } + priv->fixed_qp_p = avctx->global_quality; if (avctx->i_quant_factor > 0.0) priv->fixed_qp_idr = (int)((priv->fixed_qp_p * avctx->i_quant_factor + @@ -773,10 +779,6 @@ static av_cold int vaapi_encode_h264_init_internal(AVCodecContext *avctx) av_log(avctx, AV_LOG_DEBUG, "QP = %d / %d / %d for IDR / P / B frames.\n", priv->fixed_qp_idr, priv->fixed_qp_p, priv->fixed_qp_b); - ctx->config_attributes = vaapi_encode_h264_config_attributes; - ctx->nb_config_attributes = - FF_ARRAY_ELEMS(vaapi_encode_h264_config_attributes); - ctx->nb_recon_frames = 20; return 0; diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c index 0aa40e31b6..323efd46a7 100644 --- a/libavcodec/vaapi_encode_h265.c +++ b/libavcodec/vaapi_encode_h265.c @@ -1125,20 +1125,21 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, return 0; } -static VAConfigAttrib vaapi_encode_h265_config_attributes[] = { - { .type = VAConfigAttribRTFormat, - .value = VA_RT_FORMAT_YUV420 }, - { .type = VAConfigAttribRateControl, - .value = VA_RC_CQP }, - { .type = VAConfigAttribEncPackedHeaders, - .value = (VA_ENC_PACKED_HEADER_SEQUENCE | - VA_ENC_PACKED_HEADER_SLICE) }, -}; - static av_cold int vaapi_encode_h265_init_internal(AVCodecContext *avctx) { + static const VAConfigAttrib default_config_attributes[] = { + { .type = VAConfigAttribRTFormat, + .value = VA_RT_FORMAT_YUV420 }, + { .type = VAConfigAttribEncPackedHeaders, + .value = (VA_ENC_PACKED_HEADER_SEQUENCE | + VA_ENC_PACKED_HEADER_SLICE) }, + { .type = VAConfigAttribRateControl, + .value = VA_RC_CQP }, + }; + VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH265Context *priv = ctx->priv_data; + int i; switch (avctx->profile) { case FF_PROFILE_HEVC_MAIN: @@ -1156,8 +1157,6 @@ static av_cold int vaapi_encode_h265_init_internal(AVCodecContext *avctx) } ctx->va_entrypoint = VAEntrypointEncSlice; - ctx->va_rc_mode = VA_RC_CQP; - ctx->input_width = avctx->width; ctx->input_height = avctx->height; ctx->aligned_width = FFALIGN(ctx->input_width, 16); @@ -1169,6 +1168,19 @@ static av_cold int vaapi_encode_h265_init_internal(AVCodecContext *avctx) ctx->input_width, ctx->input_height, ctx->aligned_width, ctx->aligned_height, priv->ctu_width, priv->ctu_height); + for (i = 0; i < FF_ARRAY_ELEMS(default_config_attributes); i++) { + ctx->config_attributes[ctx->nb_config_attributes++] = + default_config_attributes[i]; + } + + if (avctx->bit_rate > 0) { + av_log(avctx, AV_LOG_ERROR, "H.265 constant-bitrate encoding " + "is not supported.\n"); + return AVERROR_PATCHWELCOME; + } + + ctx->va_rc_mode = VA_RC_CQP; + priv->fixed_qp_p = avctx->global_quality; if (avctx->i_quant_factor > 0.0) priv->fixed_qp_idr = (int)((priv->fixed_qp_p * avctx->i_quant_factor + @@ -1183,10 +1195,6 @@ static av_cold int vaapi_encode_h265_init_internal(AVCodecContext *avctx) av_log(avctx, AV_LOG_DEBUG, "QP = %d / %d / %d for IDR / P / B frames.\n", priv->fixed_qp_idr, priv->fixed_qp_p, priv->fixed_qp_b); - ctx->config_attributes = vaapi_encode_h265_config_attributes; - ctx->nb_config_attributes = - FF_ARRAY_ELEMS(vaapi_encode_h265_config_attributes); - ctx->nb_recon_frames = 20; return 0; diff --git a/libavcodec/vaapi_encode_mjpeg.c b/libavcodec/vaapi_encode_mjpeg.c index 3ab3ab1e9f..e3bf191884 100644 --- a/libavcodec/vaapi_encode_mjpeg.c +++ b/libavcodec/vaapi_encode_mjpeg.c @@ -333,17 +333,18 @@ static int vaapi_encode_mjpeg_init_slice_params(AVCodecContext *avctx, return 0; } -static VAConfigAttrib vaapi_encode_mjpeg_config_attributes[] = { - { .type = VAConfigAttribRTFormat, - .value = VA_RT_FORMAT_YUV420 }, - { .type = VAConfigAttribEncPackedHeaders, - .value = VA_ENC_PACKED_HEADER_SEQUENCE }, -}; - static av_cold int vaapi_encode_mjpeg_init_internal(AVCodecContext *avctx) { + static const VAConfigAttrib default_config_attributes[] = { + { .type = VAConfigAttribRTFormat, + .value = VA_RT_FORMAT_YUV420 }, + { .type = VAConfigAttribEncPackedHeaders, + .value = VA_ENC_PACKED_HEADER_SEQUENCE }, + }; + VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeMJPEGContext *priv = ctx->priv_data; + int i; ctx->va_profile = VAProfileJPEGBaseline; ctx->va_entrypoint = VAEntrypointEncPicture; @@ -353,9 +354,10 @@ static av_cold int vaapi_encode_mjpeg_init_internal(AVCodecContext *avctx) ctx->aligned_width = FFALIGN(ctx->input_width, 8); ctx->aligned_height = FFALIGN(ctx->input_height, 8); - ctx->config_attributes = vaapi_encode_mjpeg_config_attributes; - ctx->nb_config_attributes = - FF_ARRAY_ELEMS(vaapi_encode_mjpeg_config_attributes); + for (i = 0; i < FF_ARRAY_ELEMS(default_config_attributes); i++) { + ctx->config_attributes[ctx->nb_config_attributes++] = + default_config_attributes[i]; + } priv->quality = avctx->global_quality; if (priv->quality < 1 || priv->quality > 100) { From 6e8f66fc932b9351055ff44ecb2bb328197099c1 Mon Sep 17 00:00:00 2001 From: Mark Thompson Date: Tue, 12 Apr 2016 23:14:23 +0100 Subject: [PATCH 2/7] vaapi_h264: Add constant-bitrate encode support Signed-off-by: Anton Khirnov --- libavcodec/vaapi_encode_h264.c | 135 +++++++++++++++++++++++++++------ 1 file changed, 110 insertions(+), 25 deletions(-) diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c index 6a77ab1e18..df4c169911 100644 --- a/libavcodec/vaapi_encode_h264.c +++ b/libavcodec/vaapi_encode_h264.c @@ -104,7 +104,15 @@ typedef struct VAAPIEncodeH264Context { int64_t idr_pic_count; int64_t last_idr_frame; - // RefPicList management. + // Rate control configuration. + struct { + VAEncMiscParameterBuffer misc; + VAEncMiscParameterRateControl rc; + } rc_params; + struct { + VAEncMiscParameterBuffer misc; + VAEncMiscParameterHRD hrd; + } hrd_params; } VAAPIEncodeH264Context; @@ -506,6 +514,19 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) } else { vseq->frame_cropping_flag = 0; } + + vseq->bits_per_second = avctx->bit_rate; + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + vseq->num_units_in_tick = avctx->framerate.num; + vseq->time_scale = 2 * avctx->framerate.den; + } else { + vseq->num_units_in_tick = avctx->time_base.num; + vseq->time_scale = 2 * avctx->time_base.den; + } + + vseq->intra_period = ctx->p_per_i * (ctx->b_per_p + 1); + vseq->intra_idr_period = vseq->intra_period; + vseq->ip_period = ctx->b_per_p + 1; } { @@ -690,13 +711,84 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, return 0; } +static av_cold int vaapi_encode_h264_init_constant_bitrate(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + int hrd_buffer_size; + int hrd_initial_buffer_fullness; + + if (avctx->rc_buffer_size) + hrd_buffer_size = avctx->rc_buffer_size; + else + hrd_buffer_size = avctx->bit_rate; + if (avctx->rc_initial_buffer_occupancy) + hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy; + else + hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4; + + priv->rc_params.misc.type = VAEncMiscParameterTypeRateControl; + priv->rc_params.rc = (VAEncMiscParameterRateControl) { + .bits_per_second = avctx->bit_rate, + .target_percentage = 66, + .window_size = 1000, + .initial_qp = (avctx->qmax >= 0 ? avctx->qmax : 40), + .min_qp = (avctx->qmin >= 0 ? avctx->qmin : 18), + .basic_unit_size = 0, + }; + ctx->global_params[ctx->nb_global_params] = + &priv->rc_params.misc; + ctx->global_params_size[ctx->nb_global_params++] = + sizeof(priv->rc_params); + + priv->hrd_params.misc.type = VAEncMiscParameterTypeHRD; + priv->hrd_params.hrd = (VAEncMiscParameterHRD) { + .initial_buffer_fullness = hrd_initial_buffer_fullness, + .buffer_size = hrd_buffer_size, + }; + ctx->global_params[ctx->nb_global_params] = + &priv->hrd_params.misc; + ctx->global_params_size[ctx->nb_global_params++] = + sizeof(priv->hrd_params); + + // These still need to be set for pic_init_qp/slice_qp_delta. + priv->fixed_qp_idr = 26; + priv->fixed_qp_p = 26; + priv->fixed_qp_b = 26; + + av_log(avctx, AV_LOG_DEBUG, "Using constant-bitrate = %d bps.\n", + avctx->bit_rate); + return 0; +} + +static av_cold int vaapi_encode_h264_init_fixed_qp(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + + priv->fixed_qp_p = avctx->global_quality; + if (avctx->i_quant_factor > 0.0) + priv->fixed_qp_idr = (int)((priv->fixed_qp_p * avctx->i_quant_factor + + avctx->i_quant_offset) + 0.5); + else + priv->fixed_qp_idr = priv->fixed_qp_p; + if (avctx->b_quant_factor > 0.0) + priv->fixed_qp_b = (int)((priv->fixed_qp_p * avctx->b_quant_factor + + avctx->b_quant_offset) + 0.5); + else + priv->fixed_qp_b = priv->fixed_qp_p; + + av_log(avctx, AV_LOG_DEBUG, "Using fixed QP = " + "%d / %d / %d for IDR / P / B frames.\n", + priv->fixed_qp_idr, priv->fixed_qp_p, priv->fixed_qp_b); + return 0; +} + static av_cold int vaapi_encode_h264_init_internal(AVCodecContext *avctx) { static const VAConfigAttrib default_config_attributes[] = { { .type = VAConfigAttribRTFormat, .value = VA_RT_FORMAT_YUV420 }, - { .type = VAConfigAttribRateControl, - .value = VA_RC_CQP }, { .type = VAConfigAttribEncPackedHeaders, .value = (VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_SLICE) }, @@ -704,7 +796,7 @@ static av_cold int vaapi_encode_h264_init_internal(AVCodecContext *avctx) VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH264Context *priv = ctx->priv_data; - int i; + int i, err; switch (avctx->profile) { case FF_PROFILE_H264_CONSTRAINED_BASELINE: @@ -745,8 +837,6 @@ static av_cold int vaapi_encode_h264_init_internal(AVCodecContext *avctx) } ctx->va_entrypoint = VAEntrypointEncSlice; - ctx->va_rc_mode = VA_RC_CQP; - ctx->input_width = avctx->width; ctx->input_height = avctx->height; ctx->aligned_width = FFALIGN(ctx->input_width, 16); @@ -754,30 +844,25 @@ static av_cold int vaapi_encode_h264_init_internal(AVCodecContext *avctx) priv->mb_width = ctx->aligned_width / 16; priv->mb_height = ctx->aligned_height / 16; - if (avctx->bit_rate > 0) { - av_log(avctx, AV_LOG_ERROR, "Constant bitrate encoding is not " - "supported!\n"); - return AVERROR_PATCHWELCOME; - } - for (i = 0; i < FF_ARRAY_ELEMS(default_config_attributes); i++) { ctx->config_attributes[ctx->nb_config_attributes++] = default_config_attributes[i]; } - priv->fixed_qp_p = avctx->global_quality; - if (avctx->i_quant_factor > 0.0) - priv->fixed_qp_idr = (int)((priv->fixed_qp_p * avctx->i_quant_factor + - avctx->i_quant_offset) + 0.5); - else - priv->fixed_qp_idr = priv->fixed_qp_p; - if (avctx->b_quant_factor > 0.0) - priv->fixed_qp_b = (int)((priv->fixed_qp_p * avctx->b_quant_factor + - avctx->b_quant_offset) + 0.5); - else - priv->fixed_qp_b = priv->fixed_qp_p; - av_log(avctx, AV_LOG_DEBUG, "QP = %d / %d / %d for IDR / P / B frames.\n", - priv->fixed_qp_idr, priv->fixed_qp_p, priv->fixed_qp_b); + if (avctx->bit_rate > 0) { + ctx->va_rc_mode = VA_RC_CBR; + err = vaapi_encode_h264_init_constant_bitrate(avctx); + } else { + ctx->va_rc_mode = VA_RC_CQP; + err = vaapi_encode_h264_init_fixed_qp(avctx); + } + if (err < 0) + return err; + + ctx->config_attributes[ctx->nb_config_attributes++] = (VAConfigAttrib) { + .type = VAConfigAttribRateControl, + .value = ctx->va_rc_mode, + }; ctx->nb_recon_frames = 20; From 69b06ed42809432b5892e29cfc496a77e60b7765 Mon Sep 17 00:00:00 2001 From: Mark Thompson Date: Tue, 12 Apr 2016 23:15:03 +0100 Subject: [PATCH 3/7] vaapi_encode: Add support for codec-local options Signed-off-by: Anton Khirnov --- libavcodec/vaapi_encode.c | 1 + libavcodec/vaapi_encode.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c index b1f00695c7..c80e638cad 100644 --- a/libavcodec/vaapi_encode.c +++ b/libavcodec/vaapi_encode.c @@ -905,6 +905,7 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx, } ctx->codec = type; + ctx->codec_options = ctx->codec_options_data; ctx->priv_data = av_mallocz(type->priv_data_size); if (!ctx->priv_data) { diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h index 9716578e5a..ec552dad0a 100644 --- a/libavcodec/vaapi_encode.h +++ b/libavcodec/vaapi_encode.h @@ -172,6 +172,11 @@ typedef struct VAAPIEncodeContext { int p_counter; int end_of_stream; + // Codec-local options are allocated to follow this structure in + // memory (in the AVCodec definition, set priv_data_size to + // sizeof(VAAPIEncodeContext) + sizeof(VAAPIEncodeFooOptions)). + void *codec_options; + char codec_options_data[0]; } VAAPIEncodeContext; From 9629701ce9debe295da09bb0e117ee9392ef1fe3 Mon Sep 17 00:00:00 2001 From: Mark Thompson Date: Tue, 12 Apr 2016 23:15:40 +0100 Subject: [PATCH 4/7] vaapi_h264: Add -qp option, use it to replace use of -global_quality Signed-off-by: Anton Khirnov --- libavcodec/vaapi_encode_h264.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c index df4c169911..940832e367 100644 --- a/libavcodec/vaapi_encode_h264.c +++ b/libavcodec/vaapi_encode_h264.c @@ -115,6 +115,10 @@ typedef struct VAAPIEncodeH264Context { } hrd_params; } VAAPIEncodeH264Context; +typedef struct VAAPIEncodeH264Options { + int qp; +} VAAPIEncodeH264Options; + #define vseq_var(name) vseq->name, name #define vseq_field(name) vseq->seq_fields.bits.name, name @@ -765,8 +769,9 @@ static av_cold int vaapi_encode_h264_init_fixed_qp(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH264Context *priv = ctx->priv_data; + VAAPIEncodeH264Options *opt = ctx->codec_options; - priv->fixed_qp_p = avctx->global_quality; + priv->fixed_qp_p = opt->qp; if (avctx->i_quant_factor > 0.0) priv->fixed_qp_idr = (int)((priv->fixed_qp_p * avctx->i_quant_factor + avctx->i_quant_offset) + 0.5); @@ -895,13 +900,21 @@ static av_cold int vaapi_encode_h264_init(AVCodecContext *avctx) return ff_vaapi_encode_init(avctx, &vaapi_encode_type_h264); } +#define OFFSET(x) (offsetof(VAAPIEncodeContext, codec_options_data) + \ + offsetof(VAAPIEncodeH264Options, x)) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) +static const AVOption vaapi_encode_h264_options[] = { + { "qp", "Constant QP (for P frames; scaled by qfactor/qoffset for I/B)", + OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 20 }, 0, 52, FLAGS }, + { NULL }, +}; + static const AVCodecDefault vaapi_encode_h264_defaults[] = { { "profile", "100" }, { "level", "51" }, { "b", "0" }, { "bf", "2" }, { "g", "120" }, - { "global_quality", "20" }, { "i_qfactor", "1.0" }, { "i_qoffset", "0.0" }, { "b_qfactor", "1.2" }, @@ -912,6 +925,7 @@ static const AVCodecDefault vaapi_encode_h264_defaults[] = { static const AVClass vaapi_encode_h264_class = { .class_name = "h264_vaapi", .item_name = av_default_item_name, + .option = vaapi_encode_h264_options, .version = LIBAVUTIL_VERSION_INT, }; @@ -920,7 +934,8 @@ AVCodec ff_h264_vaapi_encoder = { .long_name = NULL_IF_CONFIG_SMALL("H.264/AVC (VAAPI)"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, - .priv_data_size = sizeof(VAAPIEncodeContext), + .priv_data_size = (sizeof(VAAPIEncodeContext) + + sizeof(VAAPIEncodeH264Options)), .init = &vaapi_encode_h264_init, .encode2 = &ff_vaapi_encode2, .close = &ff_vaapi_encode_close, From fcf536b1301475c57a7f94d00b1aebf5d20fe9d3 Mon Sep 17 00:00:00 2001 From: Mark Thompson Date: Tue, 12 Apr 2016 23:16:30 +0100 Subject: [PATCH 5/7] vaapi_h264: Add encode quality option (for quality-speed tradeoff) Only supported on VAAPI 0.36 and higher. Signed-off-by: Anton Khirnov --- libavcodec/vaapi_encode_h264.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c index 940832e367..9841a708b6 100644 --- a/libavcodec/vaapi_encode_h264.c +++ b/libavcodec/vaapi_encode_h264.c @@ -113,10 +113,19 @@ typedef struct VAAPIEncodeH264Context { VAEncMiscParameterBuffer misc; VAEncMiscParameterHRD hrd; } hrd_params; + +#if VA_CHECK_VERSION(0, 36, 0) + // Speed-quality tradeoff setting. + struct { + VAEncMiscParameterBuffer misc; + VAEncMiscParameterBufferQualityLevel quality; + } quality_params; +#endif } VAAPIEncodeH264Context; typedef struct VAAPIEncodeH264Options { int qp; + int quality; } VAAPIEncodeH264Options; @@ -801,6 +810,7 @@ static av_cold int vaapi_encode_h264_init_internal(AVCodecContext *avctx) VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH264Context *priv = ctx->priv_data; + VAAPIEncodeH264Options *opt = ctx->codec_options; int i, err; switch (avctx->profile) { @@ -869,6 +879,22 @@ static av_cold int vaapi_encode_h264_init_internal(AVCodecContext *avctx) .value = ctx->va_rc_mode, }; + if (opt->quality > 0) { +#if VA_CHECK_VERSION(0, 36, 0) + priv->quality_params.misc.type = + VAEncMiscParameterTypeQualityLevel; + priv->quality_params.quality.quality_level = opt->quality; + + ctx->global_params[ctx->nb_global_params] = + &priv->quality_params.misc; + ctx->global_params_size[ctx->nb_global_params++] = + sizeof(priv->quality_params); +#else + av_log(avctx, AV_LOG_WARNING, "The encode quality option is not " + "supported with this VAAPI version.\n"); +#endif + } + ctx->nb_recon_frames = 20; return 0; @@ -906,6 +932,8 @@ static av_cold int vaapi_encode_h264_init(AVCodecContext *avctx) static const AVOption vaapi_encode_h264_options[] = { { "qp", "Constant QP (for P frames; scaled by qfactor/qoffset for I/B)", OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 20 }, 0, 52, FLAGS }, + { "quality", "Set encode quality (trades off against speed, higher is faster)", + OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, FLAGS }, { NULL }, }; From f70e4627933b8f38a964657aff26ef2d590877b4 Mon Sep 17 00:00:00 2001 From: Mark Thompson Date: Tue, 12 Apr 2016 23:18:13 +0100 Subject: [PATCH 6/7] vaapi_h265: Add constant-bitrate encode support Signed-off-by: Anton Khirnov --- libavcodec/vaapi_encode_h265.c | 132 +++++++++++++++++++++++++++------ 1 file changed, 109 insertions(+), 23 deletions(-) diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c index 323efd46a7..128b5a5e53 100644 --- a/libavcodec/vaapi_encode_h265.c +++ b/libavcodec/vaapi_encode_h265.c @@ -182,6 +182,16 @@ typedef struct VAAPIEncodeH265Context { int fixed_qp_b; int64_t last_idr_frame; + + // Rate control configuration. + struct { + VAEncMiscParameterBuffer misc; + VAEncMiscParameterRateControl rc; + } rc_params; + struct { + VAEncMiscParameterBuffer misc; + VAEncMiscParameterHRD hrd; + } hrd_params; } VAAPIEncodeH265Context; @@ -806,6 +816,19 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) vseq->max_transform_hierarchy_depth_intra = 3; vseq->vui_parameters_present_flag = 0; + + vseq->bits_per_second = avctx->bit_rate; + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + vseq->vui_num_units_in_tick = avctx->framerate.num; + vseq->vui_time_scale = avctx->framerate.den; + } else { + vseq->vui_num_units_in_tick = avctx->time_base.num; + vseq->vui_time_scale = avctx->time_base.den; + } + + vseq->intra_period = ctx->p_per_i * (ctx->b_per_p + 1); + vseq->intra_idr_period = vseq->intra_period; + vseq->ip_period = ctx->b_per_p + 1; } { @@ -841,8 +864,7 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) vpic->pic_fields.bits.screen_content_flag = 0; vpic->pic_fields.bits.enable_gpu_weighted_prediction = 0; - - //vpic->pic_fields.bits.cu_qp_delta_enabled_flag = 1; + vpic->pic_fields.bits.cu_qp_delta_enabled_flag = 1; } { @@ -1125,6 +1147,79 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, return 0; } +static av_cold int vaapi_encode_h265_init_constant_bitrate(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + int hrd_buffer_size; + int hrd_initial_buffer_fullness; + + if (avctx->rc_buffer_size) + hrd_buffer_size = avctx->rc_buffer_size; + else + hrd_buffer_size = avctx->bit_rate; + if (avctx->rc_initial_buffer_occupancy) + hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy; + else + hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4; + + priv->rc_params.misc.type = VAEncMiscParameterTypeRateControl; + priv->rc_params.rc = (VAEncMiscParameterRateControl) { + .bits_per_second = avctx->bit_rate, + .target_percentage = 66, + .window_size = 1000, + .initial_qp = (avctx->qmax >= 0 ? avctx->qmax : 40), + .min_qp = (avctx->qmin >= 0 ? avctx->qmin : 20), + .basic_unit_size = 0, + }; + ctx->global_params[ctx->nb_global_params] = + &priv->rc_params.misc; + ctx->global_params_size[ctx->nb_global_params++] = + sizeof(priv->rc_params); + + priv->hrd_params.misc.type = VAEncMiscParameterTypeHRD; + priv->hrd_params.hrd = (VAEncMiscParameterHRD) { + .initial_buffer_fullness = hrd_initial_buffer_fullness, + .buffer_size = hrd_buffer_size, + }; + ctx->global_params[ctx->nb_global_params] = + &priv->hrd_params.misc; + ctx->global_params_size[ctx->nb_global_params++] = + sizeof(priv->hrd_params); + + // These still need to be set for pic_init_qp/slice_qp_delta. + priv->fixed_qp_idr = 30; + priv->fixed_qp_p = 30; + priv->fixed_qp_b = 30; + + av_log(avctx, AV_LOG_DEBUG, "Using constant-bitrate = %d bps.\n", + avctx->bit_rate); + return 0; +} + +static av_cold int vaapi_encode_h265_init_fixed_qp(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + + priv->fixed_qp_p = avctx->global_quality; + if (avctx->i_quant_factor > 0.0) + priv->fixed_qp_idr = (int)((priv->fixed_qp_p * avctx->i_quant_factor + + avctx->i_quant_offset) + 0.5); + else + priv->fixed_qp_idr = priv->fixed_qp_p; + if (avctx->b_quant_factor > 0.0) + priv->fixed_qp_b = (int)((priv->fixed_qp_p * avctx->b_quant_factor + + avctx->b_quant_offset) + 0.5); + else + priv->fixed_qp_b = priv->fixed_qp_p; + + av_log(avctx, AV_LOG_DEBUG, "Using fixed QP = " + "%d / %d / %d for IDR / P / B frames.\n", + priv->fixed_qp_idr, priv->fixed_qp_p, priv->fixed_qp_b); + return 0; +} + static av_cold int vaapi_encode_h265_init_internal(AVCodecContext *avctx) { static const VAConfigAttrib default_config_attributes[] = { @@ -1133,13 +1228,11 @@ static av_cold int vaapi_encode_h265_init_internal(AVCodecContext *avctx) { .type = VAConfigAttribEncPackedHeaders, .value = (VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_SLICE) }, - { .type = VAConfigAttribRateControl, - .value = VA_RC_CQP }, }; VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH265Context *priv = ctx->priv_data; - int i; + int i, err; switch (avctx->profile) { case FF_PROFILE_HEVC_MAIN: @@ -1174,26 +1267,19 @@ static av_cold int vaapi_encode_h265_init_internal(AVCodecContext *avctx) } if (avctx->bit_rate > 0) { - av_log(avctx, AV_LOG_ERROR, "H.265 constant-bitrate encoding " - "is not supported.\n"); - return AVERROR_PATCHWELCOME; + ctx->va_rc_mode = VA_RC_CBR; + err = vaapi_encode_h265_init_constant_bitrate(avctx); + } else { + ctx->va_rc_mode = VA_RC_CQP; + err = vaapi_encode_h265_init_fixed_qp(avctx); } + if (err < 0) + return err; - ctx->va_rc_mode = VA_RC_CQP; - - priv->fixed_qp_p = avctx->global_quality; - if (avctx->i_quant_factor > 0.0) - priv->fixed_qp_idr = (int)((priv->fixed_qp_p * avctx->i_quant_factor + - avctx->i_quant_offset) + 0.5); - else - priv->fixed_qp_idr = priv->fixed_qp_p; - if (avctx->b_quant_factor > 0.0) - priv->fixed_qp_b = (int)((priv->fixed_qp_p * avctx->b_quant_factor + - avctx->b_quant_offset) + 0.5); - else - priv->fixed_qp_b = priv->fixed_qp_p; - av_log(avctx, AV_LOG_DEBUG, "QP = %d / %d / %d for IDR / P / B frames.\n", - priv->fixed_qp_idr, priv->fixed_qp_p, priv->fixed_qp_b); + ctx->config_attributes[ctx->nb_config_attributes++] = (VAConfigAttrib) { + .type = VAConfigAttribRateControl, + .value = ctx->va_rc_mode, + }; ctx->nb_recon_frames = 20; From 92fdea37477b5a2d1329e5ef0773e24473fa8f12 Mon Sep 17 00:00:00 2001 From: Mark Thompson Date: Tue, 12 Apr 2016 23:18:53 +0100 Subject: [PATCH 7/7] vaapi_h265: Add -qp option, use it to replace use of -global_quality Signed-off-by: Anton Khirnov --- libavcodec/vaapi_encode_h265.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c index 128b5a5e53..917268a080 100644 --- a/libavcodec/vaapi_encode_h265.c +++ b/libavcodec/vaapi_encode_h265.c @@ -194,6 +194,10 @@ typedef struct VAAPIEncodeH265Context { } hrd_params; } VAAPIEncodeH265Context; +typedef struct VAAPIEncodeH265Options { + int qp; +} VAAPIEncodeH265Options; + #define vseq_var(name) vseq->name, name #define vseq_field(name) vseq->seq_fields.bits.name, name @@ -1201,8 +1205,9 @@ static av_cold int vaapi_encode_h265_init_fixed_qp(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH265Context *priv = ctx->priv_data; + VAAPIEncodeH265Options *opt = ctx->codec_options; - priv->fixed_qp_p = avctx->global_quality; + priv->fixed_qp_p = opt->qp; if (avctx->i_quant_factor > 0.0) priv->fixed_qp_idr = (int)((priv->fixed_qp_p * avctx->i_quant_factor + avctx->i_quant_offset) + 0.5); @@ -1312,13 +1317,21 @@ static av_cold int vaapi_encode_h265_init(AVCodecContext *avctx) return ff_vaapi_encode_init(avctx, &vaapi_encode_type_h265); } +#define OFFSET(x) (offsetof(VAAPIEncodeContext, codec_options_data) + \ + offsetof(VAAPIEncodeH265Options, x)) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) +static const AVOption vaapi_encode_h265_options[] = { + { "qp", "Constant QP (for P frames; scaled by qfactor/qoffset for I/B)", + OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 25 }, 0, 52, FLAGS }, + { NULL }, +}; + static const AVCodecDefault vaapi_encode_h265_defaults[] = { { "profile", "1" }, { "level", "51" }, { "b", "0" }, { "bf", "2" }, { "g", "120" }, - { "global_quality", "25" }, { "i_qfactor", "1.0" }, { "i_qoffset", "0.0" }, { "b_qfactor", "1.2" }, @@ -1329,6 +1342,7 @@ static const AVCodecDefault vaapi_encode_h265_defaults[] = { static const AVClass vaapi_encode_h265_class = { .class_name = "h265_vaapi", .item_name = av_default_item_name, + .option = vaapi_encode_h265_options, .version = LIBAVUTIL_VERSION_INT, }; @@ -1337,7 +1351,8 @@ AVCodec ff_hevc_vaapi_encoder = { .long_name = NULL_IF_CONFIG_SMALL("H.265/HEVC (VAAPI)"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, - .priv_data_size = sizeof(VAAPIEncodeContext), + .priv_data_size = (sizeof(VAAPIEncodeContext) + + sizeof(VAAPIEncodeH265Options)), .init = &vaapi_encode_h265_init, .encode2 = &ff_vaapi_encode2, .close = &ff_vaapi_encode_close,