vaapi_h264: Add constant-bitrate encode support

Signed-off-by: Anton Khirnov <anton@khirnov.net>
This commit is contained in:
Mark Thompson 2016-04-12 23:14:23 +01:00 committed by Anton Khirnov
parent f6b8552369
commit 6e8f66fc93
1 changed files with 110 additions and 25 deletions

View File

@ -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;