Newer
Older
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
pic->nb_slices = 1;
return 0;
}
static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
VAAPIEncodePicture *pic,
VAAPIEncodeSlice *slice)
{
VAAPIEncodeContext *ctx = avctx->priv_data;
VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params;
VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params;
VAEncSliceParameterBufferH264 *vslice = slice->codec_slice_params;
VAAPIEncodeH264Context *priv = ctx->priv_data;
VAAPIEncodeH264Slice *pslice;
VAAPIEncodeH264MiscSliceParams *mslice;
int i;
slice->priv_data = av_mallocz(sizeof(*pslice));
if (!slice->priv_data)
return AVERROR(ENOMEM);
pslice = slice->priv_data;
mslice = &pslice->misc_slice_params;
if (pic->type == PICTURE_TYPE_IDR)
mslice->nal_unit_type = H264_NAL_IDR_SLICE;
mslice->nal_unit_type = H264_NAL_SLICE;
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
switch (pic->type) {
case PICTURE_TYPE_IDR:
vslice->slice_type = SLICE_TYPE_I;
mslice->nal_ref_idc = 3;
break;
case PICTURE_TYPE_I:
vslice->slice_type = SLICE_TYPE_I;
mslice->nal_ref_idc = 2;
break;
case PICTURE_TYPE_P:
vslice->slice_type = SLICE_TYPE_P;
mslice->nal_ref_idc = 1;
break;
case PICTURE_TYPE_B:
vslice->slice_type = SLICE_TYPE_B;
mslice->nal_ref_idc = 0;
break;
default:
av_assert0(0 && "invalid picture type");
}
// Only one slice per frame.
vslice->macroblock_address = 0;
vslice->num_macroblocks = priv->mb_width * priv->mb_height;
vslice->macroblock_info = VA_INVALID_ID;
vslice->pic_parameter_set_id = vpic->pic_parameter_set_id;
vslice->idr_pic_id = priv->idr_pic_count++;
vslice->pic_order_cnt_lsb = pic->display_order &
((1 << (4 + vseq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4)) - 1);
for (i = 0; i < FF_ARRAY_ELEMS(vslice->RefPicList0); i++) {
vslice->RefPicList0[i].picture_id = VA_INVALID_ID;
vslice->RefPicList0[i].flags = VA_PICTURE_H264_INVALID;
vslice->RefPicList1[i].picture_id = VA_INVALID_ID;
vslice->RefPicList1[i].flags = VA_PICTURE_H264_INVALID;
}
av_assert0(pic->nb_refs <= 2);
if (pic->nb_refs >= 1) {
// Backward reference for P- or B-frame.
av_assert0(pic->type == PICTURE_TYPE_P ||
pic->type == PICTURE_TYPE_B);
vslice->num_ref_idx_l0_active_minus1 = 0;
vslice->RefPicList0[0] = vpic->ReferenceFrames[0];
}
if (pic->nb_refs >= 2) {
av_assert0(pic->type == PICTURE_TYPE_B);
vslice->num_ref_idx_l1_active_minus1 = 0;
vslice->RefPicList1[0] = vpic->ReferenceFrames[1];
}
if (pic->type == PICTURE_TYPE_B)
vslice->slice_qp_delta = priv->fixed_qp_b - vpic->pic_init_qp;
else if (pic->type == PICTURE_TYPE_P)
vslice->slice_qp_delta = priv->fixed_qp_p - vpic->pic_init_qp;
else
vslice->slice_qp_delta = priv->fixed_qp_idr - vpic->pic_init_qp;
vslice->direct_spatial_mv_pred_flag = 1;
return 0;
}
static av_cold int vaapi_encode_h264_configure(AVCodecContext *avctx)
{
VAAPIEncodeContext *ctx = avctx->priv_data;
VAAPIEncodeH264Context *priv = ctx->priv_data;
VAAPIEncodeH264Options *opt = ctx->codec_options;
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
priv->mb_width = FFALIGN(avctx->width, 16) / 16;
priv->mb_height = FFALIGN(avctx->height, 16) / 16;
if (ctx->va_rc_mode == VA_RC_CQP) {
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);
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);
} else if (ctx->va_rc_mode == VA_RC_CBR) {
// 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);
} else {
av_assert0(0 && "Invalid 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
}
return 0;
}
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
static const VAAPIEncodeType vaapi_encode_type_h264 = {
.priv_data_size = sizeof(VAAPIEncodeH264Context),
.configure = &vaapi_encode_h264_configure,
.sequence_params_size = sizeof(VAEncSequenceParameterBufferH264),
.init_sequence_params = &vaapi_encode_h264_init_sequence_params,
.picture_params_size = sizeof(VAEncPictureParameterBufferH264),
.init_picture_params = &vaapi_encode_h264_init_picture_params,
.slice_params_size = sizeof(VAEncSliceParameterBufferH264),
.init_slice_params = &vaapi_encode_h264_init_slice_params,
.sequence_header_type = VAEncPackedHeaderSequence,
.write_sequence_header = &vaapi_encode_h264_write_sequence_header,
.slice_header_type = VAEncPackedHeaderH264_Slice,
.write_slice_header = &vaapi_encode_h264_write_slice_header,
.write_extra_header = &vaapi_encode_h264_write_extra_header,
};
static av_cold int vaapi_encode_h264_init(AVCodecContext *avctx)
VAAPIEncodeContext *ctx = avctx->priv_data;
VAAPIEncodeH264Options *opt =
(VAAPIEncodeH264Options*)ctx->codec_options_data;
ctx->codec = &vaapi_encode_type_h264;
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
switch (avctx->profile) {
case FF_PROFILE_H264_CONSTRAINED_BASELINE:
ctx->va_profile = VAProfileH264ConstrainedBaseline;
break;
case FF_PROFILE_H264_BASELINE:
ctx->va_profile = VAProfileH264Baseline;
break;
case FF_PROFILE_H264_MAIN:
ctx->va_profile = VAProfileH264Main;
break;
case FF_PROFILE_H264_EXTENDED:
av_log(avctx, AV_LOG_ERROR, "H.264 extended profile "
"is not supported.\n");
return AVERROR_PATCHWELCOME;
case FF_PROFILE_UNKNOWN:
case FF_PROFILE_H264_HIGH:
ctx->va_profile = VAProfileH264High;
break;
case FF_PROFILE_H264_HIGH_10:
case FF_PROFILE_H264_HIGH_10_INTRA:
av_log(avctx, AV_LOG_ERROR, "H.264 10-bit profiles "
"are not supported.\n");
return AVERROR_PATCHWELCOME;
case FF_PROFILE_H264_HIGH_422:
case FF_PROFILE_H264_HIGH_422_INTRA:
case FF_PROFILE_H264_HIGH_444:
case FF_PROFILE_H264_HIGH_444_PREDICTIVE:
case FF_PROFILE_H264_HIGH_444_INTRA:
case FF_PROFILE_H264_CAVLC_444:
av_log(avctx, AV_LOG_ERROR, "H.264 non-4:2:0 profiles "
"are not supported.\n");
return AVERROR_PATCHWELCOME;
default:
av_log(avctx, AV_LOG_ERROR, "Unknown H.264 profile %d.\n",
avctx->profile);
return AVERROR(EINVAL);
}
if (opt->low_power) {
ctx->va_entrypoint = VAEntrypointEncSliceLP;
#else
av_log(avctx, AV_LOG_ERROR, "Low-power encoding is not "
"supported with this VAAPI version.\n");
return AVERROR(EINVAL);
#endif
} else {
ctx->va_entrypoint = VAEntrypointEncSlice;
}
// Only 8-bit encode is supported.
ctx->va_rt_format = VA_RT_FORMAT_YUV420;
ctx->va_rc_mode = VA_RC_CBR;
ctx->va_rc_mode = VA_RC_CQP;
ctx->va_packed_headers =
VA_ENC_PACKED_HEADER_SEQUENCE | // SPS and PPS.
VA_ENC_PACKED_HEADER_SLICE | // Slice headers.
VA_ENC_PACKED_HEADER_MISC; // SEI.
ctx->surface_width = FFALIGN(avctx->width, 16);
ctx->surface_height = FFALIGN(avctx->height, 16);
return ff_vaapi_encode_init(avctx);
#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 },
{ "quality", "Set encode quality (trades off against speed, higher is faster)",
OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 8, FLAGS },
{ "low_power", "Use low-power encoding mode (experimental: only supported "
"on some platforms, does not support all features)",
OFFSET(low_power), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
{ NULL },
};
static const AVCodecDefault vaapi_encode_h264_defaults[] = {
{ "profile", "100" },
{ "level", "51" },
{ "b", "0" },
{ "bf", "2" },
{ "g", "120" },
{ "i_qfactor", "1.0" },
{ "i_qoffset", "0.0" },
{ "b_qfactor", "1.2" },
{ "b_qoffset", "0.0" },
{ NULL },
};
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,
};
AVCodec ff_h264_vaapi_encoder = {
.name = "h264_vaapi",
.long_name = NULL_IF_CONFIG_SMALL("H.264/AVC (VAAPI)"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_H264,
.priv_data_size = (sizeof(VAAPIEncodeContext) +
sizeof(VAAPIEncodeH264Options)),
.init = &vaapi_encode_h264_init,
.encode2 = &ff_vaapi_encode2,
.close = &ff_vaapi_encode_close,
.priv_class = &vaapi_encode_h264_class,
.capabilities = AV_CODEC_CAP_DELAY,
.defaults = vaapi_encode_h264_defaults,
.pix_fmts = (const enum AVPixelFormat[]) {
AV_PIX_FMT_VAAPI,
AV_PIX_FMT_NONE,
},
};