diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c index 4a92506b41..ddd0308492 100644 --- a/libavcodec/vaapi_encode.c +++ b/libavcodec/vaapi_encode.c @@ -922,7 +922,7 @@ fail: return err; } -static av_cold int vaapi_encode_check_config(AVCodecContext *avctx) +static av_cold int vaapi_encode_config_attributes(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; VAStatus vas; @@ -930,6 +930,7 @@ static av_cold int vaapi_encode_check_config(AVCodecContext *avctx) VAProfile *profiles = NULL; VAEntrypoint *entrypoints = NULL; VAConfigAttrib attr[] = { + { VAConfigAttribRTFormat }, { VAConfigAttribRateControl }, { VAConfigAttribEncMaxRefFrames }, }; @@ -1001,13 +1002,33 @@ static av_cold int vaapi_encode_check_config(AVCodecContext *avctx) continue; } switch (attr[i].type) { - case VAConfigAttribRateControl: - if (!(ctx->va_rc_mode & attr[i].value)) { - av_log(avctx, AV_LOG_ERROR, "Rate control mode is not " - "supported: %x\n", attr[i].value); + case VAConfigAttribRTFormat: + if (!(ctx->va_rt_format & attr[i].value)) { + av_log(avctx, AV_LOG_ERROR, "Surface RT format %#x " + "is not supported (mask %#x).\n", + ctx->va_rt_format, attr[i].value); err = AVERROR(EINVAL); goto fail; } + ctx->config_attributes[ctx->nb_config_attributes++] = + (VAConfigAttrib) { + .type = VAConfigAttribRTFormat, + .value = ctx->va_rt_format, + }; + break; + case VAConfigAttribRateControl: + if (!(ctx->va_rc_mode & attr[i].value)) { + av_log(avctx, AV_LOG_ERROR, "Rate control mode %#x " + "is not supported (mask: %#x).\n", + ctx->va_rc_mode, attr[i].value); + err = AVERROR(EINVAL); + goto fail; + } + ctx->config_attributes[ctx->nb_config_attributes++] = + (VAConfigAttrib) { + .type = VAConfigAttribRateControl, + .value = ctx->va_rc_mode, + }; break; case VAConfigAttribEncMaxRefFrames: { @@ -1016,18 +1037,20 @@ static av_cold int vaapi_encode_check_config(AVCodecContext *avctx) if (avctx->gop_size > 1 && ref_l0 < 1) { av_log(avctx, AV_LOG_ERROR, "P frames are not " - "supported (%x).\n", attr[i].value); + "supported (%#x).\n", attr[i].value); err = AVERROR(EINVAL); goto fail; } if (avctx->max_b_frames > 0 && ref_l1 < 1) { av_log(avctx, AV_LOG_ERROR, "B frames are not " - "supported (%x).\n", attr[i].value); + "supported (%#x).\n", attr[i].value); err = AVERROR(EINVAL); goto fail; } } break; + default: + av_assert0(0 && "Unexpected config attribute."); } } @@ -1038,6 +1061,54 @@ fail: return err; } +static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + int hrd_buffer_size; + int hrd_initial_buffer_fullness; + + if (avctx->bit_rate > INT32_MAX) { + av_log(avctx, AV_LOG_ERROR, "Target bitrate of 2^31 bps or " + "higher is not supported.\n"); + return AVERROR(EINVAL); + } + + if (avctx->rc_buffer_size) + hrd_buffer_size = avctx->rc_buffer_size; + else + hrd_buffer_size = avctx->bit_rate; + if (avctx->rc_initial_buffer_occupancy) + hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy; + else + hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4; + + ctx->rc_params.misc.type = VAEncMiscParameterTypeRateControl; + ctx->rc_params.rc = (VAEncMiscParameterRateControl) { + .bits_per_second = avctx->bit_rate, + .target_percentage = 66, + .window_size = 1000, + .initial_qp = (avctx->qmax >= 0 ? avctx->qmax : 40), + .min_qp = (avctx->qmin >= 0 ? avctx->qmin : 18), + .basic_unit_size = 0, + }; + ctx->global_params[ctx->nb_global_params] = + &ctx->rc_params.misc; + ctx->global_params_size[ctx->nb_global_params++] = + sizeof(ctx->rc_params); + + ctx->hrd_params.misc.type = VAEncMiscParameterTypeHRD; + ctx->hrd_params.hrd = (VAEncMiscParameterHRD) { + .initial_buffer_fullness = hrd_initial_buffer_fullness, + .buffer_size = hrd_buffer_size, + }; + ctx->global_params[ctx->nb_global_params] = + &ctx->hrd_params.misc; + ctx->global_params_size[ctx->nb_global_params++] = + sizeof(ctx->hrd_params); + + return 0; +} + static void vaapi_encode_free_output_buffer(void *opaque, uint8_t *data) { @@ -1067,7 +1138,7 @@ static AVBufferRef *vaapi_encode_alloc_output_buffer(void *opaque, // bound on that. vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, VAEncCodedBufferType, - 3 * ctx->aligned_width * ctx->aligned_height + + 3 * ctx->surface_width * ctx->surface_height + (1 << 16), 1, 0, &buffer_id); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to create bitstream " @@ -1089,69 +1160,14 @@ static AVBufferRef *vaapi_encode_alloc_output_buffer(void *opaque, return ref; } -av_cold int ff_vaapi_encode_init(AVCodecContext *avctx, - const VAAPIEncodeType *type) +static av_cold int vaapi_encode_create_recon_frames(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; - AVVAAPIFramesContext *recon_hwctx = NULL; AVVAAPIHWConfig *hwconfig = NULL; AVHWFramesConstraints *constraints = NULL; enum AVPixelFormat recon_format; - VAStatus vas; int err, i; - if (!avctx->hw_frames_ctx) { - av_log(avctx, AV_LOG_ERROR, "A hardware frames reference is " - "required to associate the encoding device.\n"); - return AVERROR(EINVAL); - } - - ctx->codec = type; - ctx->codec_options = ctx->codec_options_data; - - ctx->va_config = VA_INVALID_ID; - ctx->va_context = VA_INVALID_ID; - - ctx->priv_data = av_mallocz(type->priv_data_size); - if (!ctx->priv_data) { - err = AVERROR(ENOMEM); - goto fail; - } - - ctx->input_frames_ref = av_buffer_ref(avctx->hw_frames_ctx); - if (!ctx->input_frames_ref) { - err = AVERROR(ENOMEM); - goto fail; - } - ctx->input_frames = (AVHWFramesContext*)ctx->input_frames_ref->data; - - ctx->device_ref = av_buffer_ref(ctx->input_frames->device_ref); - if (!ctx->device_ref) { - err = AVERROR(ENOMEM); - goto fail; - } - ctx->device = (AVHWDeviceContext*)ctx->device_ref->data; - ctx->hwctx = ctx->device->hwctx; - - err = ctx->codec->init(avctx); - if (err < 0) - goto fail; - - err = vaapi_encode_check_config(avctx); - if (err < 0) - goto fail; - - vas = vaCreateConfig(ctx->hwctx->display, - ctx->va_profile, ctx->va_entrypoint, - ctx->config_attributes, ctx->nb_config_attributes, - &ctx->va_config); - if (vas != VA_STATUS_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to create encode pipeline " - "configuration: %d (%s).\n", vas, vaErrorStr(vas)); - err = AVERROR(EIO); - goto fail; - } - hwconfig = av_hwdevice_hwconfig_alloc(ctx->device_ref); if (!hwconfig) { err = AVERROR(ENOMEM); @@ -1190,13 +1206,13 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx, av_log(avctx, AV_LOG_DEBUG, "Using %s as format of " "reconstructed frames.\n", av_get_pix_fmt_name(recon_format)); - if (ctx->aligned_width < constraints->min_width || - ctx->aligned_height < constraints->min_height || - ctx->aligned_width > constraints->max_width || - ctx->aligned_height > constraints->max_height) { + if (ctx->surface_width < constraints->min_width || + ctx->surface_height < constraints->min_height || + ctx->surface_width > constraints->max_width || + ctx->surface_height > constraints->max_height) { av_log(avctx, AV_LOG_ERROR, "Hardware does not support encoding at " "size %dx%d (constraints: width %d-%d height %d-%d).\n", - ctx->aligned_width, ctx->aligned_height, + ctx->surface_width, ctx->surface_height, constraints->min_width, constraints->max_width, constraints->min_height, constraints->max_height); err = AVERROR(EINVAL); @@ -1215,9 +1231,10 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx, ctx->recon_frames->format = AV_PIX_FMT_VAAPI; ctx->recon_frames->sw_format = recon_format; - ctx->recon_frames->width = ctx->aligned_width; - ctx->recon_frames->height = ctx->aligned_height; - ctx->recon_frames->initial_pool_size = ctx->nb_recon_frames; + ctx->recon_frames->width = ctx->surface_width; + ctx->recon_frames->height = ctx->surface_height; + ctx->recon_frames->initial_pool_size = + avctx->max_b_frames + 3; err = av_hwframe_ctx_init(ctx->recon_frames_ref); if (err < 0) { @@ -1225,10 +1242,75 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx, "frame context: %d.\n", err); goto fail; } - recon_hwctx = ctx->recon_frames->hwctx; + err = 0; + fail: + av_freep(&hwconfig); + av_hwframe_constraints_free(&constraints); + return err; +} + +av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + AVVAAPIFramesContext *recon_hwctx = NULL; + VAStatus vas; + int err; + + if (!avctx->hw_frames_ctx) { + av_log(avctx, AV_LOG_ERROR, "A hardware frames reference is " + "required to associate the encoding device.\n"); + return AVERROR(EINVAL); + } + + ctx->codec_options = ctx->codec_options_data; + + ctx->va_config = VA_INVALID_ID; + ctx->va_context = VA_INVALID_ID; + + ctx->priv_data = av_mallocz(ctx->codec->priv_data_size); + if (!ctx->priv_data) { + err = AVERROR(ENOMEM); + goto fail; + } + + ctx->input_frames_ref = av_buffer_ref(avctx->hw_frames_ctx); + if (!ctx->input_frames_ref) { + err = AVERROR(ENOMEM); + goto fail; + } + ctx->input_frames = (AVHWFramesContext*)ctx->input_frames_ref->data; + + ctx->device_ref = av_buffer_ref(ctx->input_frames->device_ref); + if (!ctx->device_ref) { + err = AVERROR(ENOMEM); + goto fail; + } + ctx->device = (AVHWDeviceContext*)ctx->device_ref->data; + ctx->hwctx = ctx->device->hwctx; + + err = vaapi_encode_config_attributes(avctx); + if (err < 0) + goto fail; + + vas = vaCreateConfig(ctx->hwctx->display, + ctx->va_profile, ctx->va_entrypoint, + ctx->config_attributes, ctx->nb_config_attributes, + &ctx->va_config); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to create encode pipeline " + "configuration: %d (%s).\n", vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail; + } + + err = vaapi_encode_create_recon_frames(avctx); + if (err < 0) + goto fail; + + recon_hwctx = ctx->recon_frames->hwctx; vas = vaCreateContext(ctx->hwctx->display, ctx->va_config, - ctx->aligned_width, ctx->aligned_height, + ctx->surface_width, ctx->surface_height, VA_PROGRESSIVE, recon_hwctx->surface_ids, recon_hwctx->nb_surfaces, @@ -1240,6 +1322,26 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx, goto fail; } + ctx->output_buffer_pool = + av_buffer_pool_init2(sizeof(VABufferID), avctx, + &vaapi_encode_alloc_output_buffer, NULL); + if (!ctx->output_buffer_pool) { + err = AVERROR(ENOMEM); + goto fail; + } + + if (ctx->va_rc_mode & ~VA_RC_CQP) { + err = vaapi_encode_init_rate_control(avctx); + if (err < 0) + goto fail; + } + + if (ctx->codec->configure) { + err = ctx->codec->configure(avctx); + if (err < 0) + goto fail; + } + ctx->input_order = 0; ctx->output_delay = avctx->max_b_frames; ctx->decode_delay = 1; @@ -1271,14 +1373,6 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx, } } - ctx->output_buffer_pool = - av_buffer_pool_init2(sizeof(VABufferID), avctx, - &vaapi_encode_alloc_output_buffer, NULL); - if (!ctx->output_buffer_pool) { - err = AVERROR(ENOMEM); - goto fail; - } - // All I are IDR for now. ctx->i_per_idr = 0; ctx->p_per_i = ((avctx->gop_size + avctx->max_b_frames) / @@ -1292,8 +1386,6 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx, return 0; fail: - av_freep(&hwconfig); - av_hwframe_constraints_free(&constraints); ff_vaapi_encode_close(avctx); return err; } @@ -1318,9 +1410,6 @@ av_cold int ff_vaapi_encode_close(AVCodecContext *avctx) ctx->va_config = VA_INVALID_ID; } - if (ctx->codec->close) - ctx->codec->close(avctx); - av_buffer_pool_uninit(&ctx->output_buffer_pool); av_freep(&ctx->codec_sequence_params); diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h index 0ac6feea02..4088897960 100644 --- a/libavcodec/vaapi_encode.h +++ b/libavcodec/vaapi_encode.h @@ -48,15 +48,6 @@ enum { PICTURE_TYPE_B = 3, }; -enum { - // All encode operations are done independently. - ISSUE_MODE_SERIALISE_EVERYTHING = 0, - // Overlap as many operations as possible. - ISSUE_MODE_MAXIMISE_THROUGHPUT, - // Overlap operations only when satisfying parallel dependencies. - ISSUE_MODE_MINIMISE_LATENCY, -}; - typedef struct VAAPIEncodeSlice { void *priv_data; void *codec_slice_params; @@ -102,43 +93,65 @@ typedef struct VAAPIEncodeContext { // Codec-specific hooks. const struct VAAPIEncodeType *codec; + // Encoding profile (VAProfileXXX). + VAProfile va_profile; + // Encoding entrypoint (usually VAEntryointEncSlice). + VAEntrypoint va_entrypoint; + // Surface colour/sampling format (usually VA_RT_FORMAT_YUV420). + unsigned int va_rt_format; + // Rate control mode. + unsigned int va_rc_mode; + + // The required size of surfaces. This is probably the input + // size (AVCodecContext.width|height) aligned up to whatever + // block size is required by the codec. + int surface_width; + int surface_height; + + // Everything above this point must be set before calling + // ff_vaapi_encode_init(). + // Codec-specific state. void *priv_data; - VAProfile va_profile; - VAEntrypoint va_entrypoint; + // Configuration attributes to use when creating va_config. + VAConfigAttrib config_attributes[MAX_CONFIG_ATTRIBUTES]; + int nb_config_attributes; + VAConfigID va_config; VAContextID va_context; - int va_rc_mode; - AVBufferRef *device_ref; AVHWDeviceContext *device; AVVAAPIDeviceContext *hwctx; + // The hardware frame context containing the input frames. AVBufferRef *input_frames_ref; AVHWFramesContext *input_frames; - // Input size, set from input frames. - int input_width; - int input_height; - // Aligned size, set by codec init, becomes hwframe size. - int aligned_width; - int aligned_height; - - int nb_recon_frames; + // The hardware frame context containing the reconstructed frames. AVBufferRef *recon_frames_ref; AVHWFramesContext *recon_frames; + // Pool of (reusable) bitstream output buffers. AVBufferPool *output_buffer_pool; - VAConfigAttrib config_attributes[MAX_CONFIG_ATTRIBUTES]; - int nb_config_attributes; - + // Global parameters which will be applied at the start of the + // sequence (includes rate control parameters below). VAEncMiscParameterBuffer *global_params[MAX_GLOBAL_PARAMS]; size_t global_params_size[MAX_GLOBAL_PARAMS]; int nb_global_params; + // Rate control parameters. + struct { + VAEncMiscParameterBuffer misc; + VAEncMiscParameterRateControl rc; + } rc_params; + struct { + VAEncMiscParameterBuffer misc; + VAEncMiscParameterHRD hrd; + } hrd_params; + // Per-sequence parameter structure (VAEncSequenceParameterBuffer*). void *codec_sequence_params; @@ -158,7 +171,15 @@ typedef struct VAAPIEncodeContext { // Next output order index (encode order). int64_t output_order; - int issue_mode; + enum { + // All encode operations are done independently (synchronise + // immediately after every operation). + ISSUE_MODE_SERIALISE_EVERYTHING = 0, + // Overlap as many operations as possible. + ISSUE_MODE_MAXIMISE_THROUGHPUT, + // Overlap operations only when satisfying parallel dependencies. + ISSUE_MODE_MINIMISE_LATENCY, + } issue_mode; // Timestamp handling. int64_t first_pts; @@ -183,15 +204,20 @@ typedef struct VAAPIEncodeContext { typedef struct VAAPIEncodeType { - size_t priv_data_size; + size_t priv_data_size; - int (*init)(AVCodecContext *avctx); - int (*close)(AVCodecContext *avctx); + // Perform any extra codec-specific configuration after the + // codec context is initialised (set up the private data and + // add any necessary global parameters). + int (*configure)(AVCodecContext *avctx); + // The size of the parameter structures: + // sizeof(VAEnc{type}ParameterBuffer{codec}). size_t sequence_params_size; size_t picture_params_size; size_t slice_params_size; + // Fill the parameter structures. int (*init_sequence_params)(AVCodecContext *avctx); int (*init_picture_params)(AVCodecContext *avctx, VAAPIEncodePicture *pic); @@ -199,10 +225,13 @@ typedef struct VAAPIEncodeType { VAAPIEncodePicture *pic, VAAPIEncodeSlice *slice); + // The type used by the packed header: this should look like + // VAEncPackedHeader{something}. int sequence_header_type; int picture_header_type; int slice_header_type; + // Write the packed header data to the provided buffer. int (*write_sequence_header)(AVCodecContext *avctx, char *data, size_t *data_len); int (*write_picture_header)(AVCodecContext *avctx, @@ -213,10 +242,18 @@ typedef struct VAAPIEncodeType { VAAPIEncodeSlice *slice, char *data, size_t *data_len); + // Fill an extra parameter structure, which will then be + // passed to vaRenderPicture(). Will be called repeatedly + // with increasing index argument until AVERROR_EOF is + // returned. int (*write_extra_buffer)(AVCodecContext *avctx, VAAPIEncodePicture *pic, int index, int *type, char *data, size_t *data_len); + + // Write an extra packed header. Will be called repeatedly + // with increasing index argument until AVERROR_EOF is + // returned. int (*write_extra_header)(AVCodecContext *avctx, VAAPIEncodePicture *pic, int index, int *type, @@ -227,8 +264,7 @@ typedef struct VAAPIEncodeType { int ff_vaapi_encode2(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *input_image, int *got_packet); -int ff_vaapi_encode_init(AVCodecContext *avctx, - const VAAPIEncodeType *type); +int ff_vaapi_encode_init(AVCodecContext *avctx); int ff_vaapi_encode_close(AVCodecContext *avctx); #endif /* AVCODEC_VAAPI_ENCODE_H */ diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c index ef9ce9dd5a..88fa566d66 100644 --- a/libavcodec/vaapi_encode_h264.c +++ b/libavcodec/vaapi_encode_h264.c @@ -148,14 +148,6 @@ typedef struct VAAPIEncodeH264Context { // Rate control configuration. int send_timing_sei; - struct { - VAEncMiscParameterBuffer misc; - VAEncMiscParameterRateControl rc; - } rc_params; - struct { - VAEncMiscParameterBuffer misc; - VAEncMiscParameterHRD hrd; - } hrd_params; #if VA_CHECK_VERSION(0, 36, 0) // Speed-quality tradeoff setting. @@ -797,16 +789,16 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) vseq->seq_fields.bits.log2_max_frame_num_minus4 = 4; vseq->seq_fields.bits.pic_order_cnt_type = 0; - if (ctx->input_width != ctx->aligned_width || - ctx->input_height != ctx->aligned_height) { + if (avctx->width != ctx->surface_width || + avctx->height != ctx->surface_height) { vseq->frame_cropping_flag = 1; vseq->frame_crop_left_offset = 0; vseq->frame_crop_right_offset = - (ctx->aligned_width - ctx->input_width) / 2; + (ctx->surface_width - avctx->width) / 2; vseq->frame_crop_top_offset = 0; vseq->frame_crop_bottom_offset = - (ctx->aligned_height - ctx->input_height) / 2; + (ctx->surface_height - avctx->height) / 2; } else { vseq->frame_cropping_flag = 0; } @@ -866,9 +858,9 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) (avctx->bit_rate >> mseq->bit_rate_scale + 6) - 1; mseq->cpb_size_scale = - av_clip_uintp2(av_log2(priv->hrd_params.hrd.buffer_size) - 15 - 4, 4); + av_clip_uintp2(av_log2(ctx->hrd_params.hrd.buffer_size) - 15 - 4, 4); mseq->cpb_size_value_minus1[0] = - (priv->hrd_params.hrd.buffer_size >> mseq->cpb_size_scale + 4) - 1; + (ctx->hrd_params.hrd.buffer_size >> mseq->cpb_size_scale + 4) - 1; // CBR mode isn't actually available here, despite naming. mseq->cbr_flag[0] = 0; @@ -880,8 +872,8 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) // This calculation can easily overflow 32 bits. mseq->initial_cpb_removal_delay = 90000 * - (uint64_t)priv->hrd_params.hrd.initial_buffer_fullness / - priv->hrd_params.hrd.buffer_size; + (uint64_t)ctx->hrd_params.hrd.initial_buffer_fullness / + ctx->hrd_params.hrd.buffer_size; mseq->initial_cpb_removal_delay_offset = 0; } else { @@ -1083,100 +1075,94 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, return 0; } -static av_cold int vaapi_encode_h264_init_constant_bitrate(AVCodecContext *avctx) +static av_cold int vaapi_encode_h264_configure(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH264Context *priv = ctx->priv_data; - int hrd_buffer_size; - int hrd_initial_buffer_fullness; + VAAPIEncodeH264Options *opt = ctx->codec_options; - if (avctx->bit_rate > INT32_MAX) { - av_log(avctx, AV_LOG_ERROR, "Target bitrate of 2^31 bps or " - "higher is not supported.\n"); - return AVERROR(EINVAL); + 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 (avctx->rc_buffer_size) - hrd_buffer_size = avctx->rc_buffer_size; - else - hrd_buffer_size = avctx->bit_rate; - if (avctx->rc_initial_buffer_occupancy) - hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy; - else - hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4; + 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; - priv->rc_params.misc.type = VAEncMiscParameterTypeRateControl; - priv->rc_params.rc = (VAEncMiscParameterRateControl) { - .bits_per_second = avctx->bit_rate, - .target_percentage = 66, - .window_size = 1000, - .initial_qp = (avctx->qmax >= 0 ? avctx->qmax : 40), - .min_qp = (avctx->qmin >= 0 ? avctx->qmin : 18), - .basic_unit_size = 0, - }; - ctx->global_params[ctx->nb_global_params] = - &priv->rc_params.misc; - ctx->global_params_size[ctx->nb_global_params++] = - sizeof(priv->rc_params); + 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 + } - priv->hrd_params.misc.type = VAEncMiscParameterTypeHRD; - priv->hrd_params.hrd = (VAEncMiscParameterHRD) { - .initial_buffer_fullness = hrd_initial_buffer_fullness, - .buffer_size = hrd_buffer_size, - }; - ctx->global_params[ctx->nb_global_params] = - &priv->hrd_params.misc; - ctx->global_params_size[ctx->nb_global_params++] = - sizeof(priv->hrd_params); - - // 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 = %"PRId64" bps.\n", - avctx->bit_rate); return 0; } -static av_cold int vaapi_encode_h264_init_fixed_qp(AVCodecContext *avctx) +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; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264Options *opt = ctx->codec_options; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Options *opt = + (VAAPIEncodeH264Options*)ctx->codec_options_data; - 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); - return 0; -} - -static av_cold int vaapi_encode_h264_init_internal(AVCodecContext *avctx) -{ - static const VAConfigAttrib default_config_attributes[] = { - { .type = VAConfigAttribRTFormat, - .value = VA_RT_FORMAT_YUV420 }, - { .type = VAConfigAttribEncPackedHeaders, - .value = (VA_ENC_PACKED_HEADER_SEQUENCE | - VA_ENC_PACKED_HEADER_SLICE) }, - }; - - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264Options *opt = ctx->codec_options; - int i, err; + ctx->codec = &vaapi_encode_type_h264; switch (avctx->profile) { case FF_PROFILE_H264_CONSTRAINED_BASELINE: @@ -1216,7 +1202,7 @@ static av_cold int vaapi_encode_h264_init_internal(AVCodecContext *avctx) return AVERROR(EINVAL); } if (opt->low_power) { -#if VA_CHECK_VERSION(0, 39, 1) +#if VA_CHECK_VERSION(0, 39, 2) ctx->va_entrypoint = VAEntrypointEncSliceLP; #else av_log(avctx, AV_LOG_ERROR, "Low-power encoding is not " @@ -1227,80 +1213,19 @@ static av_cold int vaapi_encode_h264_init_internal(AVCodecContext *avctx) ctx->va_entrypoint = VAEntrypointEncSlice; } - ctx->input_width = avctx->width; - ctx->input_height = avctx->height; - ctx->aligned_width = FFALIGN(ctx->input_width, 16); - ctx->aligned_height = FFALIGN(ctx->input_height, 16); - priv->mb_width = ctx->aligned_width / 16; - priv->mb_height = ctx->aligned_height / 16; + // Only 8-bit encode is supported. + ctx->va_rt_format = VA_RT_FORMAT_YUV420; - for (i = 0; i < FF_ARRAY_ELEMS(default_config_attributes); i++) { - ctx->config_attributes[ctx->nb_config_attributes++] = - default_config_attributes[i]; - } - - if (avctx->bit_rate > 0) { + if (avctx->bit_rate > 0) ctx->va_rc_mode = VA_RC_CBR; - err = vaapi_encode_h264_init_constant_bitrate(avctx); - } else { + else ctx->va_rc_mode = VA_RC_CQP; - err = vaapi_encode_h264_init_fixed_qp(avctx); - } - if (err < 0) - return err; - ctx->config_attributes[ctx->nb_config_attributes++] = (VAConfigAttrib) { - .type = VAConfigAttribRateControl, - .value = ctx->va_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->surface_width = FFALIGN(avctx->width, 16); + ctx->surface_height = FFALIGN(avctx->height, 16); - 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 - } - - ctx->nb_recon_frames = 20; - - return 0; -} - -static VAAPIEncodeType vaapi_encode_type_h264 = { - .priv_data_size = sizeof(VAAPIEncodeH264Context), - - .init = &vaapi_encode_h264_init_internal, - - .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) -{ - return ff_vaapi_encode_init(avctx, &vaapi_encode_type_h264); + return ff_vaapi_encode_init(avctx); } #define OFFSET(x) (offsetof(VAAPIEncodeContext, codec_options_data) + \ diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c index 45f6f6de29..f3f0b4d2c0 100644 --- a/libavcodec/vaapi_encode_h265.c +++ b/libavcodec/vaapi_encode_h265.c @@ -798,8 +798,8 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) vseq->intra_idr_period = 0; vseq->ip_period = 0; - vseq->pic_width_in_luma_samples = ctx->aligned_width; - vseq->pic_height_in_luma_samples = ctx->aligned_height; + vseq->pic_width_in_luma_samples = ctx->surface_width; + vseq->pic_height_in_luma_samples = ctx->surface_height; vseq->seq_fields.bits.chroma_format_idc = 1; // 4:2:0. vseq->seq_fields.bits.separate_colour_plane_flag = 0; @@ -911,15 +911,15 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) mseq->vps_poc_proportional_to_timing_flag = 1; mseq->vps_num_ticks_poc_diff_minus1 = 0; - if (ctx->input_width != ctx->aligned_width || - ctx->input_height != ctx->aligned_height) { + if (avctx->width != ctx->surface_width || + avctx->height != ctx->surface_height) { mseq->conformance_window_flag = 1; mseq->conf_win_left_offset = 0; mseq->conf_win_right_offset = - (ctx->aligned_width - ctx->input_width) / 2; + (ctx->surface_width - avctx->width) / 2; mseq->conf_win_top_offset = 0; mseq->conf_win_bottom_offset = - (ctx->aligned_height - ctx->input_height) / 2; + (ctx->surface_height - avctx->height) / 2; } else { mseq->conformance_window_flag = 0; } @@ -1154,156 +1154,56 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, return 0; } -static av_cold int vaapi_encode_h265_init_constant_bitrate(AVCodecContext *avctx) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH265Context *priv = ctx->priv_data; - int hrd_buffer_size; - int hrd_initial_buffer_fullness; - - if (avctx->bit_rate > INT32_MAX) { - av_log(avctx, AV_LOG_ERROR, "Target bitrate of 2^31 bps or " - "higher is not supported.\n"); - return AVERROR(EINVAL); - } - - if (avctx->rc_buffer_size) - hrd_buffer_size = avctx->rc_buffer_size; - else - hrd_buffer_size = avctx->bit_rate; - if (avctx->rc_initial_buffer_occupancy) - hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy; - else - hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4; - - priv->rc_params.misc.type = VAEncMiscParameterTypeRateControl; - priv->rc_params.rc = (VAEncMiscParameterRateControl) { - .bits_per_second = avctx->bit_rate, - .target_percentage = 66, - .window_size = 1000, - .initial_qp = (avctx->qmax >= 0 ? avctx->qmax : 40), - .min_qp = (avctx->qmin >= 0 ? avctx->qmin : 20), - .basic_unit_size = 0, - }; - ctx->global_params[ctx->nb_global_params] = - &priv->rc_params.misc; - ctx->global_params_size[ctx->nb_global_params++] = - sizeof(priv->rc_params); - - priv->hrd_params.misc.type = VAEncMiscParameterTypeHRD; - priv->hrd_params.hrd = (VAEncMiscParameterHRD) { - .initial_buffer_fullness = hrd_initial_buffer_fullness, - .buffer_size = hrd_buffer_size, - }; - ctx->global_params[ctx->nb_global_params] = - &priv->hrd_params.misc; - ctx->global_params_size[ctx->nb_global_params++] = - sizeof(priv->hrd_params); - - // These still need to be set for pic_init_qp/slice_qp_delta. - priv->fixed_qp_idr = 30; - priv->fixed_qp_p = 30; - priv->fixed_qp_b = 30; - - av_log(avctx, AV_LOG_DEBUG, "Using constant-bitrate = %"PRId64" bps.\n", - avctx->bit_rate); - return 0; -} - -static av_cold int vaapi_encode_h265_init_fixed_qp(AVCodecContext *avctx) +static av_cold int vaapi_encode_h265_configure(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH265Context *priv = ctx->priv_data; VAAPIEncodeH265Options *opt = ctx->codec_options; - 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; + priv->ctu_width = FFALIGN(ctx->surface_width, 32) / 32; + priv->ctu_height = FFALIGN(ctx->surface_height, 32) / 32; - 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); - return 0; -} + 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); -static av_cold int vaapi_encode_h265_init_internal(AVCodecContext *avctx) -{ - static const VAConfigAttrib default_config_attributes[] = { - { .type = VAConfigAttribRTFormat, - .value = VA_RT_FORMAT_YUV420 }, - { .type = VAConfigAttribEncPackedHeaders, - .value = (VA_ENC_PACKED_HEADER_SEQUENCE | - VA_ENC_PACKED_HEADER_SLICE) }, - }; + 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; - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH265Context *priv = ctx->priv_data; - int i, err; + 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); - switch (avctx->profile) { - case FF_PROFILE_HEVC_MAIN: - case FF_PROFILE_UNKNOWN: - ctx->va_profile = VAProfileHEVCMain; - break; - case FF_PROFILE_HEVC_MAIN_10: - av_log(avctx, AV_LOG_ERROR, "H.265 main 10-bit profile " - "is not supported.\n"); - return AVERROR_PATCHWELCOME; - default: - av_log(avctx, AV_LOG_ERROR, "Unknown H.265 profile %d.\n", - avctx->profile); - return AVERROR(EINVAL); - } - ctx->va_entrypoint = VAEntrypointEncSlice; + } 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 = 30; + priv->fixed_qp_p = 30; + priv->fixed_qp_b = 30; - ctx->input_width = avctx->width; - ctx->input_height = avctx->height; - ctx->aligned_width = FFALIGN(ctx->input_width, 16); - ctx->aligned_height = FFALIGN(ctx->input_height, 16); - priv->ctu_width = FFALIGN(ctx->aligned_width, 32) / 32; - priv->ctu_height = FFALIGN(ctx->aligned_height, 32) / 32; + av_log(avctx, AV_LOG_DEBUG, "Using constant-bitrate = %d bps.\n", + avctx->bit_rate); - av_log(avctx, AV_LOG_VERBOSE, "Input %ux%u -> Aligned %ux%u -> CTU %ux%u.\n", - ctx->input_width, ctx->input_height, ctx->aligned_width, - ctx->aligned_height, priv->ctu_width, priv->ctu_height); - - for (i = 0; i < FF_ARRAY_ELEMS(default_config_attributes); i++) { - ctx->config_attributes[ctx->nb_config_attributes++] = - default_config_attributes[i]; - } - - if (avctx->bit_rate > 0) { - ctx->va_rc_mode = VA_RC_CBR; - err = vaapi_encode_h265_init_constant_bitrate(avctx); } else { - ctx->va_rc_mode = VA_RC_CQP; - err = vaapi_encode_h265_init_fixed_qp(avctx); + av_assert0(0 && "Invalid RC mode."); } - if (err < 0) - return err; - - ctx->config_attributes[ctx->nb_config_attributes++] = (VAConfigAttrib) { - .type = VAConfigAttribRateControl, - .value = ctx->va_rc_mode, - }; - - ctx->nb_recon_frames = 20; return 0; } -static VAAPIEncodeType vaapi_encode_type_h265 = { +static const VAAPIEncodeType vaapi_encode_type_h265 = { .priv_data_size = sizeof(VAAPIEncodeH265Context), - .init = &vaapi_encode_h265_init_internal, + .configure = &vaapi_encode_h265_configure, .sequence_params_size = sizeof(VAEncSequenceParameterBufferHEVC), .init_sequence_params = &vaapi_encode_h265_init_sequence_params, @@ -1323,7 +1223,39 @@ static VAAPIEncodeType vaapi_encode_type_h265 = { static av_cold int vaapi_encode_h265_init(AVCodecContext *avctx) { - return ff_vaapi_encode_init(avctx, &vaapi_encode_type_h265); + VAAPIEncodeContext *ctx = avctx->priv_data; + + ctx->codec = &vaapi_encode_type_h265; + + switch (avctx->profile) { + case FF_PROFILE_HEVC_MAIN: + case FF_PROFILE_UNKNOWN: + ctx->va_profile = VAProfileHEVCMain; + break; + case FF_PROFILE_HEVC_MAIN_10: + av_log(avctx, AV_LOG_ERROR, "H.265 main 10-bit profile " + "is not supported.\n"); + return AVERROR_PATCHWELCOME; + default: + av_log(avctx, AV_LOG_ERROR, "Unknown H.265 profile %d.\n", + avctx->profile); + return AVERROR(EINVAL); + } + ctx->va_entrypoint = VAEntrypointEncSlice; + + // This will be dependent on profile when 10-bit is supported. + ctx->va_rt_format = VA_RT_FORMAT_YUV420; + + if (avctx->bit_rate > 0) + ctx->va_rc_mode = VA_RC_CBR; + else + ctx->va_rc_mode = VA_RC_CQP; + + + 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) + \ diff --git a/libavcodec/vaapi_encode_mjpeg.c b/libavcodec/vaapi_encode_mjpeg.c index 316b3595c8..3ca902a6af 100644 --- a/libavcodec/vaapi_encode_mjpeg.c +++ b/libavcodec/vaapi_encode_mjpeg.c @@ -277,8 +277,8 @@ static int vaapi_encode_mjpeg_init_picture_params(AVCodecContext *avctx, vpic->reconstructed_picture = pic->recon_surface; vpic->coded_buf = pic->output_buffer; - vpic->picture_width = ctx->input_width; - vpic->picture_height = ctx->input_height; + vpic->picture_width = avctx->width; + vpic->picture_height = avctx->height; vpic->pic_flags.bits.profile = 0; vpic->pic_flags.bits.progressive = 0; @@ -333,31 +333,10 @@ static int vaapi_encode_mjpeg_init_slice_params(AVCodecContext *avctx, return 0; } -static av_cold int vaapi_encode_mjpeg_init_internal(AVCodecContext *avctx) +static av_cold int vaapi_encode_mjpeg_configure(AVCodecContext *avctx) { - static const VAConfigAttrib default_config_attributes[] = { - { .type = VAConfigAttribRTFormat, - .value = VA_RT_FORMAT_YUV420 }, - { .type = VAConfigAttribEncPackedHeaders, - .value = VA_ENC_PACKED_HEADER_SEQUENCE }, - }; - VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeMJPEGContext *priv = ctx->priv_data; - int i; - - ctx->va_profile = VAProfileJPEGBaseline; - ctx->va_entrypoint = VAEntrypointEncPicture; - - ctx->input_width = avctx->width; - ctx->input_height = avctx->height; - ctx->aligned_width = FFALIGN(ctx->input_width, 8); - ctx->aligned_height = FFALIGN(ctx->input_height, 8); - - for (i = 0; i < FF_ARRAY_ELEMS(default_config_attributes); i++) { - ctx->config_attributes[ctx->nb_config_attributes++] = - default_config_attributes[i]; - } priv->quality = avctx->global_quality; if (priv->quality < 1 || priv->quality > 100) { @@ -374,7 +353,7 @@ static av_cold int vaapi_encode_mjpeg_init_internal(AVCodecContext *avctx) static VAAPIEncodeType vaapi_encode_type_mjpeg = { .priv_data_size = sizeof(VAAPIEncodeMJPEGContext), - .init = &vaapi_encode_mjpeg_init_internal, + .configure = &vaapi_encode_mjpeg_configure, .picture_params_size = sizeof(VAEncPictureParameterBufferJPEG), .init_picture_params = &vaapi_encode_mjpeg_init_picture_params, @@ -390,7 +369,21 @@ static VAAPIEncodeType vaapi_encode_type_mjpeg = { static av_cold int vaapi_encode_mjpeg_init(AVCodecContext *avctx) { - return ff_vaapi_encode_init(avctx, &vaapi_encode_type_mjpeg); + VAAPIEncodeContext *ctx = avctx->priv_data; + + ctx->codec = &vaapi_encode_type_mjpeg; + + ctx->va_profile = VAProfileJPEGBaseline; + ctx->va_entrypoint = VAEntrypointEncPicture; + + ctx->va_rt_format = VA_RT_FORMAT_YUV420; + + ctx->va_rc_mode = VA_RC_CQP; + + ctx->surface_width = FFALIGN(avctx->width, 8); + ctx->surface_height = FFALIGN(avctx->height, 8); + + return ff_vaapi_encode_init(avctx); } static const AVCodecDefault vaapi_encode_mjpeg_defaults[] = {