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