From f70e4627933b8f38a964657aff26ef2d590877b4 Mon Sep 17 00:00:00 2001 From: Mark Thompson Date: Tue, 12 Apr 2016 23:18:13 +0100 Subject: 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(-) (limited to 'libavcodec') 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; -- cgit v1.2.3