X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fvaapi_encode_mpeg2.c;h=4c81d785d6d8b75377b9b8832e52486348fcf272;hb=84ac1440b2a726b8a989dafdf634081651de1c10;hp=5577fa9e048abffb82d38aea46afb8fd35b32e1f;hpb=8e789d244cc946bc350672eeb02453918b21a09f;p=ffmpeg diff --git a/libavcodec/vaapi_encode_mpeg2.c b/libavcodec/vaapi_encode_mpeg2.c index 5577fa9e048..4c81d785d6d 100644 --- a/libavcodec/vaapi_encode_mpeg2.c +++ b/libavcodec/vaapi_encode_mpeg2.c @@ -30,10 +30,11 @@ typedef struct VAAPIEncodeMPEG2Context { VAAPIEncodeContext common; - // Derived settings. - int mb_width; - int mb_height; + // User options. + int profile; + int level; + // Derived settings. int quant_i; int quant_p; int quant_b; @@ -92,10 +93,9 @@ static int vaapi_encode_mpeg2_add_header(AVCodecContext *avctx, CodedBitstreamFragment *frag, int type, void *header) { - VAAPIEncodeMPEG2Context *priv = avctx->priv_data; int err; - err = ff_cbs_insert_unit_content(priv->cbc, frag, -1, type, header, NULL); + 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); @@ -134,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; } @@ -158,7 +158,7 @@ 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; } @@ -184,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. @@ -292,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; @@ -312,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; @@ -351,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, @@ -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; } @@ -486,8 +484,8 @@ static int vaapi_encode_mpeg2_init_slice_params(AVCodecContext *avctx, VAEncSliceParameterBufferMPEG2 *vslice = slice->codec_slice_params; 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: @@ -521,23 +519,18 @@ static av_cold int vaapi_encode_mpeg2_configure(AVCodecContext *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; @@ -546,15 +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 = { + .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, @@ -573,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 @@ -620,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); @@ -637,24 +631,63 @@ static av_cold int vaapi_encode_mpeg2_close(AVCodecContext *avctx) { VAAPIEncodeMPEG2Context *priv = avctx->priv_data; + 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 }, }; +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)"), @@ -662,13 +695,17 @@ AVCodec ff_mpeg2_vaapi_encoder = { .id = AV_CODEC_ID_MPEG2VIDEO, .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 | AV_CODEC_CAP_HARDWARE, + .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", };