X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=libavcodec%2Fvaapi_encode_mpeg2.c;h=4537955c40a3a02001f8c4ed3177ad82e03c9c45;hb=a247ac640df3da573cd661065bf53f37863e2b46;hp=02eca30dc5126ab7c2d044e336c7addb65ccac14;hpb=814e217d14e4edfb9932f10d323a0208c9af2068;p=ffmpeg diff --git a/libavcodec/vaapi_encode_mpeg2.c b/libavcodec/vaapi_encode_mpeg2.c index 02eca30dc51..af3a63dab73 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,11 +93,9 @@ 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; int err; - err = ff_cbs_insert_unit_content(priv->cbc, frag, -1, type, header); + err = ff_cbs_insert_unit_content(frag, -1, type, header, NULL); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to add header: " "type = %d.\n", type); @@ -105,8 +108,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; @@ -132,7 +134,7 @@ static int vaapi_encode_mpeg2_write_sequence_header(AVCodecContext *avctx, err = vaapi_encode_mpeg2_write_fragment(avctx, data, data_len, frag); fail: - ff_cbs_fragment_uninit(priv->cbc, frag); + ff_cbs_fragment_reset(frag); return 0; } @@ -140,8 +142,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; @@ -157,14 +158,14 @@ static int vaapi_encode_mpeg2_write_picture_header(AVCodecContext *avctx, err = vaapi_encode_mpeg2_write_fragment(avctx, data, data_len, frag); fail: - ff_cbs_fragment_uninit(priv->cbc, frag); + ff_cbs_fragment_reset(frag); return 0; } 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 +184,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. @@ -291,17 +292,16 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) priv->sequence_display_extension.extension_start_code_identifier = MPEG2_EXTENSION_SEQUENCE_DISPLAY; + // Unspecified video format, from table 6-6. sde->video_format = 5; - if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + + sde->colour_primaries = avctx->color_primaries; + sde->transfer_characteristics = avctx->color_trc; + sde->matrix_coefficients = avctx->colorspace; + sde->colour_description = + avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || avctx->color_trc != AVCOL_TRC_UNSPECIFIED || - avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { - sde->colour_description = 1; - sde->colour_primaries = avctx->color_primaries; - sde->transfer_characteristics = avctx->color_trc; - sde->matrix_coefficients = avctx->colorspace; - } else { - sde->colour_description = 0; - } + avctx->colorspace != AVCOL_SPC_UNSPECIFIED; sde->display_horizontal_size = avctx->width; sde->display_vertical_size = avctx->height; @@ -311,7 +311,8 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) goph->group_start_code = MPEG2_START_GROUP; - goph->time_code = 0; + // Marker bit in the middle of time_code. + goph->time_code = 1 << 12; goph->closed_gop = 1; goph->broken_link = 0; @@ -350,13 +351,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 +417,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 +473,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 +480,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,30 +512,25 @@ 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); + priv->quant_p = av_clip(ctx->rc_quality, 1, 31); if (avctx->i_quant_factor > 0.0) - priv->quant_i = av_clip((avctx->global_quality * - avctx->i_quant_factor + - avctx->i_quant_offset) + 0.5, - 1, 31); + priv->quant_i = + av_clip((avctx->i_quant_factor * priv->quant_p + + avctx->i_quant_offset) + 0.5, 1, 31); else priv->quant_i = priv->quant_p; if (avctx->b_quant_factor > 0.0) - priv->quant_b = av_clip((avctx->global_quality * - avctx->b_quant_factor + - avctx->b_quant_offset) + 0.5, - 1, 31); + priv->quant_b = + av_clip((avctx->b_quant_factor * priv->quant_p + + avctx->b_quant_offset) + 0.5, 1, 31); else priv->quant_b = priv->quant_p; @@ -547,17 +539,37 @@ static av_cold int vaapi_encode_mpeg2_configure(AVCodecContext *avctx) priv->quant_i, priv->quant_p, priv->quant_b); } else { - av_assert0(0 && "Invalid RC mode."); + priv->quant_i = 16; + priv->quant_p = 16; + priv->quant_b = 16; } + 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; + + ctx->roi_quant_range = 31; + 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, + + .flags = FLAG_B_PICTURES, .configure = &vaapi_encode_mpeg2_configure, + .default_quality = 10, + .sequence_params_size = sizeof(VAEncSequenceParameterBufferMPEG2), .init_sequence_params = &vaapi_encode_mpeg2_init_sequence_params, @@ -576,35 +588,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 +618,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,41 +629,83 @@ 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_fragment_free(&priv->current_fragment); + 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, + VAAPI_ENCODE_RC_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" }, { "i_qoffset", "0" }, { "b_qfactor", "6/5" }, { "b_qoffset", "0" }, - { "global_quality", "10" }, + { "qmin", "-1" }, + { "qmax", "-1" }, { NULL }, }; -AVCodec ff_mpeg2_vaapi_encoder = { +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, +}; + +const 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, + .receive_packet = &ff_vaapi_encode_receive_packet, .close = &vaapi_encode_mpeg2_close, - .capabilities = AV_CODEC_CAP_DELAY, + .priv_class = &vaapi_encode_mpeg2_class, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | + AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .defaults = vaapi_encode_mpeg2_defaults, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .hw_configs = ff_vaapi_encode_hw_configs, + .wrapper_name = "vaapi", };