Choose what types of reference frames will be used based on what types are available, and make the intra-only mode explicit (GOP size one, which must be used for MJPEG).tags/n4.1
@@ -671,7 +671,7 @@ static int vaapi_encode_get_next(AVCodecContext *avctx, | |||||
return AVERROR(ENOMEM); | return AVERROR(ENOMEM); | ||||
if (ctx->input_order == 0 || ctx->force_idr || | if (ctx->input_order == 0 || ctx->force_idr || | ||||
ctx->gop_counter >= avctx->gop_size) { | |||||
ctx->gop_counter >= ctx->gop_size) { | |||||
pic->type = PICTURE_TYPE_IDR; | pic->type = PICTURE_TYPE_IDR; | ||||
ctx->force_idr = 0; | ctx->force_idr = 0; | ||||
ctx->gop_counter = 1; | ctx->gop_counter = 1; | ||||
@@ -694,7 +694,7 @@ static int vaapi_encode_get_next(AVCodecContext *avctx, | |||||
// encode-after it, but not exceeding the GOP size. | // encode-after it, but not exceeding the GOP size. | ||||
for (i = 0; i < ctx->b_per_p && | for (i = 0; i < ctx->b_per_p && | ||||
ctx->gop_counter < avctx->gop_size; i++) { | |||||
ctx->gop_counter < ctx->gop_size; i++) { | |||||
pic = vaapi_encode_alloc(); | pic = vaapi_encode_alloc(); | ||||
if (!pic) | if (!pic) | ||||
goto fail; | goto fail; | ||||
@@ -1213,7 +1213,6 @@ static av_cold int vaapi_encode_config_attributes(AVCodecContext *avctx) | |||||
int i; | int i; | ||||
VAConfigAttrib attr[] = { | VAConfigAttrib attr[] = { | ||||
{ VAConfigAttribEncMaxRefFrames }, | |||||
{ VAConfigAttribEncPackedHeaders }, | { VAConfigAttribEncPackedHeaders }, | ||||
}; | }; | ||||
@@ -1236,24 +1235,6 @@ static av_cold int vaapi_encode_config_attributes(AVCodecContext *avctx) | |||||
continue; | continue; | ||||
} | } | ||||
switch (attr[i].type) { | switch (attr[i].type) { | ||||
case VAConfigAttribEncMaxRefFrames: | |||||
{ | |||||
unsigned int ref_l0 = attr[i].value & 0xffff; | |||||
unsigned int ref_l1 = (attr[i].value >> 16) & 0xffff; | |||||
if (avctx->gop_size > 1 && ref_l0 < 1) { | |||||
av_log(avctx, AV_LOG_ERROR, "P frames are not " | |||||
"supported (%#x).\n", attr[i].value); | |||||
return AVERROR(EINVAL); | |||||
} | |||||
if (avctx->max_b_frames > 0 && ref_l1 < 1) { | |||||
av_log(avctx, AV_LOG_WARNING, "B frames are not " | |||||
"supported (%#x) by the underlying driver.\n", | |||||
attr[i].value); | |||||
avctx->max_b_frames = 0; | |||||
} | |||||
} | |||||
break; | |||||
case VAConfigAttribEncPackedHeaders: | case VAConfigAttribEncPackedHeaders: | ||||
if (ctx->va_packed_headers & ~attr[i].value) { | if (ctx->va_packed_headers & ~attr[i].value) { | ||||
// This isn't fatal, but packed headers are always | // This isn't fatal, but packed headers are always | ||||
@@ -1469,6 +1450,54 @@ static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx) | |||||
return 0; | return 0; | ||||
} | } | ||||
static av_cold int vaapi_encode_init_gop_structure(AVCodecContext *avctx) | |||||
{ | |||||
VAAPIEncodeContext *ctx = avctx->priv_data; | |||||
VAStatus vas; | |||||
VAConfigAttrib attr = { VAConfigAttribEncMaxRefFrames }; | |||||
uint32_t ref_l0, ref_l1; | |||||
vas = vaGetConfigAttributes(ctx->hwctx->display, | |||||
ctx->va_profile, | |||||
ctx->va_entrypoint, | |||||
&attr, 1); | |||||
if (vas != VA_STATUS_SUCCESS) { | |||||
av_log(avctx, AV_LOG_ERROR, "Failed to query reference frames " | |||||
"attribute: %d (%s).\n", vas, vaErrorStr(vas)); | |||||
return AVERROR_EXTERNAL; | |||||
} | |||||
if (attr.value == VA_ATTRIB_NOT_SUPPORTED) { | |||||
ref_l0 = ref_l1 = 0; | |||||
} else { | |||||
ref_l0 = attr.value & 0xffff; | |||||
ref_l1 = attr.value >> 16 & 0xffff; | |||||
} | |||||
if (avctx->gop_size <= 1) { | |||||
av_log(avctx, AV_LOG_VERBOSE, "Using intra frames only.\n"); | |||||
ctx->gop_size = 1; | |||||
} else if (ref_l0 < 1) { | |||||
av_log(avctx, AV_LOG_ERROR, "Driver does not support any " | |||||
"reference frames.\n"); | |||||
return AVERROR(EINVAL); | |||||
} else if (ref_l1 < 1 || avctx->max_b_frames < 1) { | |||||
av_log(avctx, AV_LOG_VERBOSE, "Using intra and P-frames " | |||||
"(supported references: %d / %d).\n", ref_l0, ref_l1); | |||||
ctx->gop_size = avctx->gop_size; | |||||
ctx->p_per_i = INT_MAX; | |||||
ctx->b_per_p = 0; | |||||
} else { | |||||
av_log(avctx, AV_LOG_VERBOSE, "Using intra, P- and B-frames " | |||||
"(supported references: %d / %d).\n", ref_l0, ref_l1); | |||||
ctx->gop_size = avctx->gop_size; | |||||
ctx->p_per_i = INT_MAX; | |||||
ctx->b_per_p = avctx->max_b_frames; | |||||
} | |||||
return 0; | |||||
} | |||||
static av_cold int vaapi_encode_init_quality(AVCodecContext *avctx) | static av_cold int vaapi_encode_init_quality(AVCodecContext *avctx) | ||||
{ | { | ||||
#if VA_CHECK_VERSION(0, 36, 0) | #if VA_CHECK_VERSION(0, 36, 0) | ||||
@@ -1640,7 +1669,7 @@ static av_cold int vaapi_encode_create_recon_frames(AVCodecContext *avctx) | |||||
ctx->recon_frames->height = ctx->surface_height; | ctx->recon_frames->height = ctx->surface_height; | ||||
// At most three IDR/I/P frames and two runs of B frames can be in | // At most three IDR/I/P frames and two runs of B frames can be in | ||||
// flight at any one time. | // flight at any one time. | ||||
ctx->recon_frames->initial_pool_size = 3 + 2 * avctx->max_b_frames; | |||||
ctx->recon_frames->initial_pool_size = 3 + 2 * ctx->b_per_p; | |||||
err = av_hwframe_ctx_init(ctx->recon_frames_ref); | err = av_hwframe_ctx_init(ctx->recon_frames_ref); | ||||
if (err < 0) { | if (err < 0) { | ||||
@@ -1695,6 +1724,10 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) | |||||
if (err < 0) | if (err < 0) | ||||
goto fail; | goto fail; | ||||
err = vaapi_encode_init_gop_structure(avctx); | |||||
if (err < 0) | |||||
goto fail; | |||||
err = vaapi_encode_config_attributes(avctx); | err = vaapi_encode_config_attributes(avctx); | ||||
if (err < 0) | if (err < 0) | ||||
goto fail; | goto fail; | ||||
@@ -1749,14 +1782,10 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) | |||||
} | } | ||||
ctx->input_order = 0; | ctx->input_order = 0; | ||||
ctx->output_delay = avctx->max_b_frames; | |||||
ctx->output_delay = ctx->b_per_p; | |||||
ctx->decode_delay = 1; | ctx->decode_delay = 1; | ||||
ctx->output_order = - ctx->output_delay - 1; | ctx->output_order = - ctx->output_delay - 1; | ||||
// Currently we never generate I frames, only IDR. | |||||
ctx->p_per_i = INT_MAX; | |||||
ctx->b_per_p = avctx->max_b_frames; | |||||
if (ctx->codec->sequence_params_size > 0) { | if (ctx->codec->sequence_params_size > 0) { | ||||
ctx->codec_sequence_params = | ctx->codec_sequence_params = | ||||
av_mallocz(ctx->codec->sequence_params_size); | av_mallocz(ctx->codec->sequence_params_size); | ||||
@@ -224,6 +224,7 @@ typedef struct VAAPIEncodeContext { | |||||
int64_t ts_ring[MAX_REORDER_DELAY * 3]; | int64_t ts_ring[MAX_REORDER_DELAY * 3]; | ||||
// Frame type decision. | // Frame type decision. | ||||
int gop_size; | |||||
int p_per_i; | int p_per_i; | ||||
int b_per_p; | int b_per_p; | ||||
int force_idr; | int force_idr; | ||||
@@ -493,8 +493,8 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) | |||||
*vseq = (VAEncSequenceParameterBufferH264) { | *vseq = (VAEncSequenceParameterBufferH264) { | ||||
.seq_parameter_set_id = sps->seq_parameter_set_id, | .seq_parameter_set_id = sps->seq_parameter_set_id, | ||||
.level_idc = sps->level_idc, | .level_idc = sps->level_idc, | ||||
.intra_period = avctx->gop_size, | |||||
.intra_idr_period = avctx->gop_size, | |||||
.intra_period = ctx->gop_size, | |||||
.intra_idr_period = ctx->gop_size, | |||||
.ip_period = ctx->b_per_p + 1, | .ip_period = ctx->b_per_p + 1, | ||||
.bits_per_second = ctx->va_bit_rate, | .bits_per_second = ctx->va_bit_rate, | ||||
@@ -509,8 +509,8 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) | |||||
.general_level_idc = vps->profile_tier_level.general_level_idc, | .general_level_idc = vps->profile_tier_level.general_level_idc, | ||||
.general_tier_flag = vps->profile_tier_level.general_tier_flag, | .general_tier_flag = vps->profile_tier_level.general_tier_flag, | ||||
.intra_period = avctx->gop_size, | |||||
.intra_idr_period = avctx->gop_size, | |||||
.intra_period = ctx->gop_size, | |||||
.intra_idr_period = ctx->gop_size, | |||||
.ip_period = ctx->b_per_p + 1, | .ip_period = ctx->b_per_p + 1, | ||||
.bits_per_second = ctx->va_bit_rate, | .bits_per_second = ctx->va_bit_rate, | ||||
@@ -401,6 +401,7 @@ static av_cold int vaapi_encode_mjpeg_init(AVCodecContext *avctx) | |||||
static const AVCodecDefault vaapi_encode_mjpeg_defaults[] = { | static const AVCodecDefault vaapi_encode_mjpeg_defaults[] = { | ||||
{ "global_quality", "80" }, | { "global_quality", "80" }, | ||||
{ "b", "0" }, | { "b", "0" }, | ||||
{ "g", "1" }, | |||||
{ NULL }, | { NULL }, | ||||
}; | }; | ||||
@@ -355,7 +355,7 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) | |||||
*vseq = (VAEncSequenceParameterBufferMPEG2) { | *vseq = (VAEncSequenceParameterBufferMPEG2) { | ||||
.intra_period = avctx->gop_size, | |||||
.intra_period = ctx->gop_size, | |||||
.ip_period = ctx->b_per_p + 1, | .ip_period = ctx->b_per_p + 1, | ||||
.picture_width = avctx->width, | .picture_width = avctx->width, | ||||
@@ -66,7 +66,7 @@ static int vaapi_encode_vp8_init_sequence_params(AVCodecContext *avctx) | |||||
if (!(ctx->va_rc_mode & VA_RC_CQP)) { | if (!(ctx->va_rc_mode & VA_RC_CQP)) { | ||||
vseq->bits_per_second = ctx->va_bit_rate; | vseq->bits_per_second = ctx->va_bit_rate; | ||||
vseq->intra_period = avctx->gop_size; | |||||
vseq->intra_period = ctx->gop_size; | |||||
} | } | ||||
return 0; | return 0; | ||||
@@ -198,11 +198,6 @@ static av_cold int vaapi_encode_vp8_init(AVCodecContext *avctx) | |||||
{ | { | ||||
VAAPIEncodeContext *ctx = avctx->priv_data; | VAAPIEncodeContext *ctx = avctx->priv_data; | ||||
if (avctx->max_b_frames > 0) { | |||||
av_log(avctx, AV_LOG_ERROR, "B-frames are not supported.\n"); | |||||
return AVERROR_PATCHWELCOME; | |||||
} | |||||
ctx->codec = &vaapi_encode_type_vp8; | ctx->codec = &vaapi_encode_type_vp8; | ||||
// Packed headers are not currently supported. | // Packed headers are not currently supported. | ||||
@@ -72,7 +72,7 @@ static int vaapi_encode_vp9_init_sequence_params(AVCodecContext *avctx) | |||||
if (!(ctx->va_rc_mode & VA_RC_CQP)) { | if (!(ctx->va_rc_mode & VA_RC_CQP)) { | ||||
vseq->bits_per_second = ctx->va_bit_rate; | vseq->bits_per_second = ctx->va_bit_rate; | ||||
vseq->intra_period = avctx->gop_size; | |||||
vseq->intra_period = ctx->gop_size; | |||||
} | } | ||||
vpic->frame_width_src = avctx->width; | vpic->frame_width_src = avctx->width; | ||||
@@ -86,6 +86,7 @@ static int vaapi_encode_vp9_init_sequence_params(AVCodecContext *avctx) | |||||
static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx, | static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx, | ||||
VAAPIEncodePicture *pic) | VAAPIEncodePicture *pic) | ||||
{ | { | ||||
VAAPIEncodeContext *ctx = avctx->priv_data; | |||||
VAAPIEncodeVP9Context *priv = avctx->priv_data; | VAAPIEncodeVP9Context *priv = avctx->priv_data; | ||||
VAEncPictureParameterBufferVP9 *vpic = pic->codec_picture_params; | VAEncPictureParameterBufferVP9 *vpic = pic->codec_picture_params; | ||||
int i; | int i; | ||||
@@ -102,7 +103,7 @@ static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx, | |||||
break; | break; | ||||
case PICTURE_TYPE_P: | case PICTURE_TYPE_P: | ||||
av_assert0(pic->nb_refs == 1); | av_assert0(pic->nb_refs == 1); | ||||
if (avctx->max_b_frames > 0) { | |||||
if (ctx->b_per_p > 0) { | |||||
if (priv->last_ref_dir) { | if (priv->last_ref_dir) { | ||||
vpic->ref_flags.bits.ref_frame_ctrl_l0 = 2; | vpic->ref_flags.bits.ref_frame_ctrl_l0 = 2; | ||||
vpic->ref_flags.bits.ref_gf_idx = 1; | vpic->ref_flags.bits.ref_gf_idx = 1; | ||||
@@ -174,7 +175,7 @@ static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx, | |||||
vpic->filter_level = priv->loop_filter_level; | vpic->filter_level = priv->loop_filter_level; | ||||
vpic->sharpness_level = priv->loop_filter_sharpness; | vpic->sharpness_level = priv->loop_filter_sharpness; | ||||
if (avctx->max_b_frames > 0 && pic->type == PICTURE_TYPE_P) | |||||
if (ctx->b_per_p > 0 && pic->type == PICTURE_TYPE_P) | |||||
priv->last_ref_dir = !priv->last_ref_dir; | priv->last_ref_dir = !priv->last_ref_dir; | ||||
return 0; | return 0; | ||||