X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fvaapi_encode_mpeg2.c;h=22d7e306bb4f3e2078b585e091010f5a374d527a;hb=420ab946ace27e4b4bfb6c2be0a65a4ffd6e05a1;hp=42df77ea498adb8e264203f2051f1e33f847de0e;hpb=a123e576a485931013c9fae85025d0e78ff3102d;p=ffmpeg diff --git a/libavcodec/vaapi_encode_mpeg2.c b/libavcodec/vaapi_encode_mpeg2.c index 42df77ea498..22d7e306bb4 100644 --- a/libavcodec/vaapi_encode_mpeg2.c +++ b/libavcodec/vaapi_encode_mpeg2.c @@ -28,22 +28,17 @@ #include "vaapi_encode.h" typedef struct VAAPIEncodeMPEG2Context { - int mb_width; - int mb_height; + VAAPIEncodeContext common; + // User options. + int profile; + int level; + + // Derived settings. int quant_i; int quant_p; int quant_b; - MPEG2RawSequenceHeader sequence_header; - MPEG2RawExtensionData sequence_extension; - MPEG2RawExtensionData sequence_display_extension; - MPEG2RawGroupOfPicturesHeader gop_header; - MPEG2RawPictureHeader picture_header; - MPEG2RawExtensionData picture_coding_extension; - - int64_t last_i_frame; - unsigned int bit_rate; unsigned int vbv_buffer_size; @@ -52,6 +47,17 @@ typedef struct VAAPIEncodeMPEG2Context { unsigned int f_code_horizontal; unsigned int f_code_vertical; + // Stream state. + int64_t last_i_frame; + + // Writer structures. + MPEG2RawSequenceHeader sequence_header; + MPEG2RawExtensionData sequence_extension; + MPEG2RawExtensionData sequence_display_extension; + MPEG2RawGroupOfPicturesHeader gop_header; + MPEG2RawPictureHeader picture_header; + MPEG2RawExtensionData picture_coding_extension; + CodedBitstreamContext *cbc; CodedBitstreamFragment current_fragment; } VAAPIEncodeMPEG2Context; @@ -61,8 +67,7 @@ static int vaapi_encode_mpeg2_write_fragment(AVCodecContext *avctx, char *data, size_t *data_len, CodedBitstreamFragment *frag) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; int err; err = ff_cbs_write_fragment_data(priv->cbc, frag); @@ -88,8 +93,7 @@ static int vaapi_encode_mpeg2_add_header(AVCodecContext *avctx, CodedBitstreamFragment *frag, int type, void *header) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; int err; err = ff_cbs_insert_unit_content(priv->cbc, frag, -1, type, header, NULL); @@ -105,8 +109,7 @@ static int vaapi_encode_mpeg2_add_header(AVCodecContext *avctx, static int vaapi_encode_mpeg2_write_sequence_header(AVCodecContext *avctx, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; CodedBitstreamFragment *frag = &priv->current_fragment; int err; @@ -140,8 +143,7 @@ static int vaapi_encode_mpeg2_write_picture_header(AVCodecContext *avctx, VAAPIEncodePicture *pic, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; CodedBitstreamFragment *frag = &priv->current_fragment; int err; @@ -164,7 +166,7 @@ fail: static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; MPEG2RawSequenceHeader *sh = &priv->sequence_header; MPEG2RawSequenceExtension *se = &priv->sequence_extension.data.sequence; MPEG2RawSequenceDisplayExtension *sde = &priv->sequence_display_extension.data.sequence_display; @@ -183,8 +185,8 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) memset(pce, 0, sizeof(*pce)); - if (avctx->bit_rate > 0) { - priv->bit_rate = (avctx->bit_rate + 399) / 400; + if (ctx->va_bit_rate > 0) { + priv->bit_rate = (ctx->va_bit_rate + 399) / 400; } else { // Unknown (not a bitrate-targetting mode), so just use the // highest value. @@ -350,13 +352,13 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) *vseq = (VAEncSequenceParameterBufferMPEG2) { - .intra_period = avctx->gop_size, + .intra_period = ctx->gop_size, .ip_period = ctx->b_per_p + 1, .picture_width = avctx->width, .picture_height = avctx->height, - .bits_per_second = avctx->bit_rate, + .bits_per_second = ctx->va_bit_rate, .frame_rate = av_q2d(priv->frame_rate), .aspect_ratio_information = sh->aspect_ratio_information, .vbv_buffer_size = priv->vbv_buffer_size, @@ -416,8 +418,7 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx, VAAPIEncodePicture *pic) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; MPEG2RawPictureHeader *ph = &priv->picture_header; MPEG2RawPictureCodingExtension *pce = &priv->picture_coding_extension.data.picture_coding; VAEncPictureParameterBufferMPEG2 *vpic = pic->codec_picture_params; @@ -473,8 +474,6 @@ static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx, vpic->f_code[1][0] = pce->f_code[1][0]; vpic->f_code[1][1] = pce->f_code[1][1]; - pic->nb_slices = priv->mb_height; - return 0; } @@ -482,13 +481,12 @@ static int vaapi_encode_mpeg2_init_slice_params(AVCodecContext *avctx, VAAPIEncodePicture *pic, VAAPIEncodeSlice *slice) { - VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; VAEncSliceParameterBufferMPEG2 *vslice = slice->codec_slice_params; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; int qp; - vslice->macroblock_address = priv->mb_width * slice->index; - vslice->num_macroblocks = priv->mb_width; + vslice->macroblock_address = slice->block_start; + vslice->num_macroblocks = slice->block_size; switch (pic->type) { case PICTURE_TYPE_IDR: @@ -515,16 +513,13 @@ static int vaapi_encode_mpeg2_init_slice_params(AVCodecContext *avctx, static av_cold int vaapi_encode_mpeg2_configure(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; int err; err = ff_cbs_init(&priv->cbc, AV_CODEC_ID_MPEG2VIDEO, avctx); if (err < 0) return err; - 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->quant_p = av_clip(avctx->global_quality, 1, 31); if (avctx->i_quant_factor > 0.0) @@ -550,11 +545,23 @@ static av_cold int vaapi_encode_mpeg2_configure(AVCodecContext *avctx) av_assert0(0 && "Invalid RC mode."); } + ctx->slice_block_rows = FFALIGN(avctx->height, 16) / 16; + ctx->slice_block_cols = FFALIGN(avctx->width, 16) / 16; + + ctx->nb_slices = ctx->slice_block_rows; + ctx->slice_size = 1; + return 0; } +static const VAAPIEncodeProfile vaapi_encode_mpeg2_profiles[] = { + { FF_PROFILE_MPEG2_MAIN, 8, 3, 1, 1, VAProfileMPEG2Main }, + { FF_PROFILE_MPEG2_SIMPLE, 8, 3, 1, 1, VAProfileMPEG2Simple }, + { FF_PROFILE_UNKNOWN } +}; + static const VAAPIEncodeType vaapi_encode_type_mpeg2 = { - .priv_data_size = sizeof(VAAPIEncodeMPEG2Context), + .profiles = vaapi_encode_mpeg2_profiles, .configure = &vaapi_encode_mpeg2_configure, @@ -576,35 +583,18 @@ static const VAAPIEncodeType vaapi_encode_type_mpeg2 = { static av_cold int vaapi_encode_mpeg2_init(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; ctx->codec = &vaapi_encode_type_mpeg2; - switch (avctx->profile) { - case FF_PROFILE_MPEG2_SIMPLE: - ctx->va_profile = VAProfileMPEG2Simple; - break; - case FF_PROFILE_MPEG2_MAIN: - ctx->va_profile = VAProfileMPEG2Main; - break; - case FF_PROFILE_MPEG2_422: - av_log(avctx, AV_LOG_ERROR, "MPEG-2 4:2:2 profile " - "is not supported.\n"); - return AVERROR_PATCHWELCOME; - case FF_PROFILE_MPEG2_HIGH: - av_log(avctx, AV_LOG_ERROR, "MPEG-2 high profile " - "is not supported.\n"); - return AVERROR_PATCHWELCOME; - case FF_PROFILE_MPEG2_SS: - case FF_PROFILE_MPEG2_SNR_SCALABLE: - av_log(avctx, AV_LOG_ERROR, "MPEG-2 scalable profiles " - "are not supported.\n"); - return AVERROR_PATCHWELCOME; - default: - av_log(avctx, AV_LOG_ERROR, "Unknown MPEG-2 profile %d.\n", - avctx->profile); - return AVERROR(EINVAL); - } + if (avctx->profile == FF_PROFILE_UNKNOWN) + avctx->profile = priv->profile; + if (avctx->level == FF_LEVEL_UNKNOWN) + avctx->level = priv->level; + + // Reject unknown levels (these are required to set f_code for + // motion vector encoding). switch (avctx->level) { case 4: // High case 6: // High 1440 @@ -623,12 +613,8 @@ static av_cold int vaapi_encode_mpeg2_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - ctx->va_entrypoint = VAEntrypointEncSlice; - ctx->va_rt_format = VA_RT_FORMAT_YUV420; - ctx->va_rc_mode = VA_RC_CQP; - - ctx->va_packed_headers = VA_ENC_PACKED_HEADER_SEQUENCE | - VA_ENC_PACKED_HEADER_PICTURE; + ctx->desired_packed_headers = VA_ENC_PACKED_HEADER_SEQUENCE | + VA_ENC_PACKED_HEADER_PICTURE; ctx->surface_width = FFALIGN(avctx->width, 16); ctx->surface_height = FFALIGN(avctx->height, 16); @@ -638,18 +624,45 @@ static av_cold int vaapi_encode_mpeg2_init(AVCodecContext *avctx) static av_cold int vaapi_encode_mpeg2_close(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; - if (priv) - ff_cbs_close(&priv->cbc); + ff_cbs_close(&priv->cbc); return ff_vaapi_encode_close(avctx); } +#define OFFSET(x) offsetof(VAAPIEncodeMPEG2Context, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) +static const AVOption vaapi_encode_mpeg2_options[] = { + VAAPI_ENCODE_COMMON_OPTIONS, + + { "profile", "Set profile (in profile_and_level_indication)", + OFFSET(profile), AV_OPT_TYPE_INT, + { .i64 = FF_PROFILE_UNKNOWN }, FF_PROFILE_UNKNOWN, 7, FLAGS, "profile" }, + +#define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "profile" + { PROFILE("simple", FF_PROFILE_MPEG2_SIMPLE) }, + { PROFILE("main", FF_PROFILE_MPEG2_MAIN) }, +#undef PROFILE + + { "level", "Set level (in profile_and_level_indication)", + OFFSET(level), AV_OPT_TYPE_INT, + { .i64 = 4 }, 0, 15, FLAGS, "level" }, + +#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "level" + { LEVEL("low", 10) }, + { LEVEL("main", 8) }, + { LEVEL("high_1440", 6) }, + { LEVEL("high", 4) }, +#undef LEVEL + + { NULL }, +}; + static const AVCodecDefault vaapi_encode_mpeg2_defaults[] = { - { "profile", "4" }, - { "level", "4" }, + { "b", "0" }, { "bf", "1" }, { "g", "120" }, { "i_qfactor", "1" }, @@ -657,18 +670,28 @@ static const AVCodecDefault vaapi_encode_mpeg2_defaults[] = { { "b_qfactor", "6/5" }, { "b_qoffset", "0" }, { "global_quality", "10" }, + { "qmin", "-1" }, + { "qmax", "-1" }, { NULL }, }; +static const AVClass vaapi_encode_mpeg2_class = { + .class_name = "mpeg2_vaapi", + .item_name = av_default_item_name, + .option = vaapi_encode_mpeg2_options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVCodec ff_mpeg2_vaapi_encoder = { .name = "mpeg2_vaapi", .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 (VAAPI)"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, - .priv_data_size = sizeof(VAAPIEncodeContext), + .priv_data_size = sizeof(VAAPIEncodeMPEG2Context), .init = &vaapi_encode_mpeg2_init, .encode2 = &ff_vaapi_encode2, .close = &vaapi_encode_mpeg2_close, + .priv_class = &vaapi_encode_mpeg2_class, .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .defaults = vaapi_encode_mpeg2_defaults, .pix_fmts = (const enum AVPixelFormat[]) {