X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fvaapi_encode_h265.c;h=8d715f6e93ada7b13b5062a0794046f602d97c4b;hb=ed5680f37ed30a01933c0158b21e3bb3c8acfe4a;hp=8f191efc4b9b7beb2ab087ed119457d9f4e4068c;hpb=c5b4ad247b9d691a4ebfb464633098368d7fbb4f;p=ffmpeg diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c index 8f191efc4b9..8d715f6e93a 100644 --- a/libavcodec/vaapi_encode_h265.c +++ b/libavcodec/vaapi_encode_h265.c @@ -23,12 +23,14 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" +#include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "libavutil/mastering_display_metadata.h" #include "avcodec.h" #include "cbs.h" #include "cbs_h265.h" +#include "h265_profile_level.h" #include "hevc.h" #include "hevc_sei.h" #include "internal.h" @@ -47,13 +49,11 @@ typedef struct VAAPIEncodeH265Context { int qp; int aud; int profile; + int tier; int level; int sei; // Derived settings. - unsigned int ctu_width; - unsigned int ctu_height; - int fixed_qp_idr; int fixed_qp_p; int fixed_qp_b; @@ -260,9 +260,12 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) H265RawVPS *vps = &priv->raw_vps; H265RawSPS *sps = &priv->raw_sps; H265RawPPS *pps = &priv->raw_pps; + H265RawProfileTierLevel *ptl = &vps->profile_tier_level; H265RawVUI *vui = &sps->vui; VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; VAEncPictureParameterBufferHEVC *vpic = ctx->codec_picture_params; + const AVPixFmtDescriptor *desc; + int chroma_format, bit_depth; int i; memset(&priv->current_access_unit, 0, @@ -273,6 +276,26 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) memset(pps, 0, sizeof(*pps)); + desc = av_pix_fmt_desc_get(priv->common.input_frames->sw_format); + av_assert0(desc); + if (desc->nb_components == 1) { + chroma_format = 0; + } else { + if (desc->log2_chroma_w == 1 && desc->log2_chroma_h == 1) { + chroma_format = 1; + } else if (desc->log2_chroma_w == 1 && desc->log2_chroma_h == 0) { + chroma_format = 2; + } else if (desc->log2_chroma_w == 0 && desc->log2_chroma_h == 0) { + chroma_format = 3; + } else { + av_log(avctx, AV_LOG_ERROR, "Chroma format of input pixel format " + "%s is not supported.\n", desc->name); + return AVERROR(EINVAL); + } + } + bit_depth = desc->comp[0].depth; + + // VPS vps->nal_unit_header = (H265RawNALUnitHeader) { @@ -289,19 +312,53 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) vps->vps_max_sub_layers_minus1 = 0; vps->vps_temporal_id_nesting_flag = 1; - vps->profile_tier_level = (H265RawProfileTierLevel) { - .general_profile_space = 0, - .general_profile_idc = avctx->profile, - .general_tier_flag = 0, + ptl->general_profile_space = 0; + ptl->general_profile_idc = avctx->profile; + ptl->general_tier_flag = priv->tier; - .general_progressive_source_flag = 1, - .general_interlaced_source_flag = 0, - .general_non_packed_constraint_flag = 1, - .general_frame_only_constraint_flag = 1, + if (chroma_format == 1) { + ptl->general_profile_compatibility_flag[1] = bit_depth == 8; + ptl->general_profile_compatibility_flag[2] = bit_depth <= 10; + } + ptl->general_profile_compatibility_flag[4] = 1; - .general_level_idc = avctx->level, - }; - vps->profile_tier_level.general_profile_compatibility_flag[avctx->profile & 31] = 1; + ptl->general_progressive_source_flag = 1; + ptl->general_interlaced_source_flag = 0; + ptl->general_non_packed_constraint_flag = 1; + ptl->general_frame_only_constraint_flag = 1; + + ptl->general_max_12bit_constraint_flag = bit_depth <= 12; + ptl->general_max_10bit_constraint_flag = bit_depth <= 10; + ptl->general_max_8bit_constraint_flag = bit_depth == 8; + + ptl->general_max_422chroma_constraint_flag = chroma_format <= 2; + ptl->general_max_420chroma_constraint_flag = chroma_format <= 1; + ptl->general_max_monochrome_constraint_flag = chroma_format == 0; + + ptl->general_intra_constraint_flag = ctx->gop_size == 1; + + ptl->general_lower_bit_rate_constraint_flag = 1; + + if (avctx->level != FF_LEVEL_UNKNOWN) { + ptl->general_level_idc = avctx->level; + } else { + const H265LevelDescriptor *level; + + level = ff_h265_guess_level(ptl, avctx->bit_rate, + ctx->surface_width, ctx->surface_height, + ctx->nb_slices, 1, 1, + (ctx->b_per_p > 0) + 1); + if (level) { + av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name); + ptl->general_level_idc = level->level_idc; + } else { + av_log(avctx, AV_LOG_VERBOSE, "Stream will not conform to " + "any normal level; using level 8.5.\n"); + ptl->general_level_idc = 255; + // The tier flag must be set in level 8.5. + ptl->general_tier_flag = 1; + } + } vps->vps_sub_layer_ordering_info_present_flag = 0; vps->vps_max_dec_pic_buffering_minus1[0] = (ctx->b_per_p > 0) + 1; @@ -343,7 +400,7 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) sps->sps_seq_parameter_set_id = 0; - sps->chroma_format_idc = 1; // YUV 4:2:0. + sps->chroma_format_idc = chroma_format; sps->separate_colour_plane_flag = 0; sps->pic_width_in_luma_samples = ctx->surface_width; @@ -362,9 +419,8 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) sps->conformance_window_flag = 0; } - sps->bit_depth_luma_minus8 = - avctx->profile == FF_PROFILE_HEVC_MAIN_10 ? 2 : 0; - sps->bit_depth_chroma_minus8 = sps->bit_depth_luma_minus8; + sps->bit_depth_luma_minus8 = bit_depth - 8; + sps->bit_depth_chroma_minus8 = bit_depth - 8; sps->log2_max_pic_order_cnt_lsb_minus4 = 8; @@ -416,18 +472,20 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) { 80, 33 }, { 18, 11 }, { 15, 11 }, { 64, 33 }, { 160, 99 }, { 4, 3 }, { 3, 2 }, { 2, 1 }, }; - int i; + int num, den, i; + av_reduce(&num, &den, avctx->sample_aspect_ratio.num, + avctx->sample_aspect_ratio.den, 65535); for (i = 0; i < FF_ARRAY_ELEMS(sar_idc); i++) { - if (avctx->sample_aspect_ratio.num == sar_idc[i].num && - avctx->sample_aspect_ratio.den == sar_idc[i].den) { + if (num == sar_idc[i].num && + den == sar_idc[i].den) { vui->aspect_ratio_idc = i; break; } } if (i >= FF_ARRAY_ELEMS(sar_idc)) { vui->aspect_ratio_idc = 255; - vui->sar_width = avctx->sample_aspect_ratio.num; - vui->sar_height = avctx->sample_aspect_ratio.den; + vui->sar_width = num; + vui->sar_height = den; } vui->aspect_ratio_info_present_flag = 1; } @@ -509,10 +567,10 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) .general_level_idc = vps->profile_tier_level.general_level_idc, .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, - .bits_per_second = avctx->bit_rate, + .bits_per_second = ctx->va_bit_rate, .pic_width_in_luma_samples = sps->pic_width_in_luma_samples, .pic_height_in_luma_samples = sps->pic_height_in_luma_samples, @@ -792,8 +850,6 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx, av_assert0(0 && "invalid picture type"); } - pic->nb_slices = 1; - return 0; } @@ -818,9 +874,8 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, sh->slice_pic_parameter_set_id = pps->pps_pic_parameter_set_id; - // Currently we only support one slice per frame. - sh->first_slice_segment_in_pic_flag = 1; - sh->slice_segment_address = 0; + sh->first_slice_segment_in_pic_flag = slice->index == 0; + sh->slice_segment_address = slice->block_start; sh->slice_type = priv->slice_type; @@ -910,7 +965,7 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, *vslice = (VAEncSliceParameterBufferHEVC) { .slice_segment_address = sh->slice_segment_address, - .num_ctu_in_slice = priv->ctu_width * priv->ctu_height, + .num_ctu_in_slice = slice->block_size, .slice_type = sh->slice_type, .slice_pic_parameter_set_id = sh->slice_pic_parameter_set_id, @@ -931,7 +986,7 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, .slice_tc_offset_div2 = sh->slice_tc_offset_div2, .slice_fields.bits = { - .last_slice_of_pic_flag = 1, + .last_slice_of_pic_flag = slice->index == pic->nb_slices - 1, .dependent_slice_segment_flag = sh->dependent_slice_segment_flag, .colour_plane_id = sh->colour_plane_id, .slice_temporal_mvp_enabled_flag = @@ -983,13 +1038,6 @@ static av_cold int vaapi_encode_h265_configure(AVCodecContext *avctx) if (err < 0) return err; - priv->ctu_width = FFALIGN(ctx->surface_width, 32) / 32; - priv->ctu_height = FFALIGN(ctx->surface_height, 32) / 32; - - av_log(avctx, AV_LOG_VERBOSE, "Input %ux%u -> Surface %ux%u -> CTU %ux%u.\n", - avctx->width, avctx->height, ctx->surface_width, - ctx->surface_height, priv->ctu_width, priv->ctu_height); - if (ctx->va_rc_mode == VA_RC_CQP) { priv->fixed_qp_p = priv->qp; if (avctx->i_quant_factor > 0.0) @@ -1014,10 +1062,6 @@ static av_cold int vaapi_encode_h265_configure(AVCodecContext *avctx) priv->fixed_qp_p = 30; priv->fixed_qp_b = 30; - av_log(avctx, AV_LOG_DEBUG, "Using %s-bitrate = %"PRId64" bps.\n", - ctx->va_rc_mode == VA_RC_CBR ? "constant" : "variable", - avctx->bit_rate); - } else { av_assert0(0 && "Invalid RC mode."); } @@ -1025,7 +1069,21 @@ static av_cold int vaapi_encode_h265_configure(AVCodecContext *avctx) return 0; } +static const VAAPIEncodeProfile vaapi_encode_h265_profiles[] = { + { FF_PROFILE_HEVC_MAIN, 8, 3, 1, 1, VAProfileHEVCMain }, + { FF_PROFILE_HEVC_REXT, 8, 3, 1, 1, VAProfileHEVCMain }, +#if VA_CHECK_VERSION(0, 37, 0) + { FF_PROFILE_HEVC_MAIN_10, 10, 3, 1, 1, VAProfileHEVCMain10 }, + { FF_PROFILE_HEVC_REXT, 10, 3, 1, 1, VAProfileHEVCMain10 }, +#endif + { FF_PROFILE_UNKNOWN } +}; + static const VAAPIEncodeType vaapi_encode_type_h265 = { + .profiles = vaapi_encode_h265_profiles, + + .flags = FLAG_SLICE_CONTROL, + .configure = &vaapi_encode_h265_configure, .sequence_params_size = sizeof(VAEncSequenceParameterBufferHEVC), @@ -1058,38 +1116,13 @@ static av_cold int vaapi_encode_h265_init(AVCodecContext *avctx) if (avctx->level == FF_LEVEL_UNKNOWN) avctx->level = priv->level; - switch (avctx->profile) { - case FF_PROFILE_HEVC_MAIN: - case FF_PROFILE_UNKNOWN: - ctx->va_profile = VAProfileHEVCMain; - ctx->va_rt_format = VA_RT_FORMAT_YUV420; - break; - case FF_PROFILE_HEVC_MAIN_10: -#ifdef VA_RT_FORMAT_YUV420_10BPP - ctx->va_profile = VAProfileHEVCMain10; - ctx->va_rt_format = VA_RT_FORMAT_YUV420_10BPP; - break; -#else - av_log(avctx, AV_LOG_ERROR, "10-bit encoding is not " - "supported with this VAAPI version.\n"); - return AVERROR(ENOSYS); -#endif - default: - av_log(avctx, AV_LOG_ERROR, "Unknown H.265 profile %d.\n", - avctx->profile); + if (avctx->level != FF_LEVEL_UNKNOWN && avctx->level & ~0xff) { + av_log(avctx, AV_LOG_ERROR, "Invalid level %d: must fit " + "in 8-bit unsigned integer.\n", avctx->level); return AVERROR(EINVAL); } - ctx->va_entrypoint = VAEntrypointEncSlice; - if (avctx->bit_rate > 0) { - if (avctx->rc_max_rate == avctx->bit_rate) - ctx->va_rc_mode = VA_RC_CBR; - else - ctx->va_rc_mode = VA_RC_VBR; - } else - ctx->va_rc_mode = VA_RC_CQP; - - ctx->va_packed_headers = + ctx->desired_packed_headers = VA_ENC_PACKED_HEADER_SEQUENCE | // VPS, SPS and PPS. VA_ENC_PACKED_HEADER_SLICE | // Slice headers. VA_ENC_PACKED_HEADER_MISC; // SEI @@ -1097,6 +1130,9 @@ static av_cold int vaapi_encode_h265_init(AVCodecContext *avctx) ctx->surface_width = FFALIGN(avctx->width, 16); ctx->surface_height = FFALIGN(avctx->height, 16); + // CTU size is currently hard-coded to 32. + ctx->slice_block_width = ctx->slice_block_height = 32; + return ff_vaapi_encode_init(avctx); } @@ -1112,25 +1148,36 @@ static av_cold int vaapi_encode_h265_close(AVCodecContext *avctx) #define OFFSET(x) offsetof(VAAPIEncodeH265Context, x) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) static const AVOption vaapi_encode_h265_options[] = { + VAAPI_ENCODE_COMMON_OPTIONS, + { "qp", "Constant QP (for P-frames; scaled by qfactor/qoffset for I/B)", OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 25 }, 0, 52, FLAGS }, { "aud", "Include AUD", - OFFSET(aud), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS }, + OFFSET(aud), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, { "profile", "Set profile (general_profile_idc)", OFFSET(profile), AV_OPT_TYPE_INT, - { .i64 = FF_PROFILE_HEVC_MAIN }, 0x00, 0xff, FLAGS, "profile" }, + { .i64 = FF_PROFILE_UNKNOWN }, FF_PROFILE_UNKNOWN, 0xff, FLAGS, "profile" }, #define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ { .i64 = value }, 0, 0, FLAGS, "profile" { PROFILE("main", FF_PROFILE_HEVC_MAIN) }, { PROFILE("main10", FF_PROFILE_HEVC_MAIN_10) }, + { PROFILE("rext", FF_PROFILE_HEVC_REXT) }, #undef PROFILE + { "tier", "Set tier (general_tier_flag)", + OFFSET(tier), AV_OPT_TYPE_INT, + { .i64 = 0 }, 0, 1, FLAGS, "tier" }, + { "main", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = 0 }, 0, 0, FLAGS, "tier" }, + { "high", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = 1 }, 0, 0, FLAGS, "tier" }, + { "level", "Set level (general_level_idc)", OFFSET(level), AV_OPT_TYPE_INT, - { .i64 = 153 }, 0x00, 0xff, FLAGS, "level" }, + { .i64 = FF_LEVEL_UNKNOWN }, FF_LEVEL_UNKNOWN, 0xff, FLAGS, "level" }, #define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ { .i64 = value }, 0, 0, FLAGS, "level" @@ -1171,6 +1218,8 @@ static const AVCodecDefault vaapi_encode_h265_defaults[] = { { "i_qoffset", "0" }, { "b_qfactor", "6/5" }, { "b_qoffset", "0" }, + { "qmin", "-1" }, + { "qmax", "-1" }, { NULL }, };