diff options
author | Mark Thompson <sw@jkqxz.net> | 2019-07-07 20:26:49 +0100 |
---|---|---|
committer | Mark Thompson <sw@jkqxz.net> | 2019-07-28 22:34:26 +0100 |
commit | 33871478605812a94502e33a6d1b965f71e6818a (patch) | |
tree | 0ab852ce17cf378ecdda0c74283e5d4852d080a7 /libavcodec/vaapi_encode.c | |
parent | 62e6b634a8022c24d53d9c3c3ce958b20f55a5fe (diff) | |
download | ffmpeg-33871478605812a94502e33a6d1b965f71e6818a.tar.gz |
vaapi_encode: Add ROI support
Diffstat (limited to 'libavcodec/vaapi_encode.c')
-rw-r--r-- | libavcodec/vaapi_encode.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c index dd2a24de04..e69b59fa37 100644 --- a/libavcodec/vaapi_encode.c +++ b/libavcodec/vaapi_encode.c @@ -166,6 +166,7 @@ static int vaapi_encode_issue(AVCodecContext *avctx, int err, i; char data[MAX_PARAM_BUFFER_SIZE]; size_t bit_len; + av_unused AVFrameSideData *sd; av_log(avctx, AV_LOG_DEBUG, "Issuing encode for pic %"PRId64"/%"PRId64" " "as type %s.\n", pic->display_order, pic->encode_order, @@ -435,6 +436,71 @@ static int vaapi_encode_issue(AVCodecContext *avctx, } } +#if VA_CHECK_VERSION(1, 0, 0) + sd = av_frame_get_side_data(pic->input_image, + AV_FRAME_DATA_REGIONS_OF_INTEREST); + if (sd && ctx->roi_allowed) { + const AVRegionOfInterest *roi; + uint32_t roi_size; + VAEncMiscParameterBufferROI param_roi; + int nb_roi, i, v; + + roi = (const AVRegionOfInterest*)sd->data; + roi_size = roi->self_size; + av_assert0(roi_size && sd->size % roi_size == 0); + nb_roi = sd->size / roi_size; + if (nb_roi > ctx->roi_max_regions) { + if (!ctx->roi_warned) { + av_log(avctx, AV_LOG_WARNING, "More ROIs set than " + "supported by driver (%d > %d).\n", + nb_roi, ctx->roi_max_regions); + ctx->roi_warned = 1; + } + nb_roi = ctx->roi_max_regions; + } + + pic->roi = av_mallocz_array(nb_roi, sizeof(*pic->roi)); + if (!pic->roi) { + err = AVERROR(ENOMEM); + goto fail; + } + // For overlapping regions, the first in the array takes priority. + for (i = 0; i < nb_roi; i++) { + roi = (const AVRegionOfInterest*)(sd->data + roi_size * i); + + av_assert0(roi->qoffset.den != 0); + v = roi->qoffset.num * ctx->roi_quant_range / roi->qoffset.den; + av_log(avctx, AV_LOG_DEBUG, "ROI: (%d,%d)-(%d,%d) -> %+d.\n", + roi->top, roi->left, roi->bottom, roi->right, v); + + pic->roi[i] = (VAEncROI) { + .roi_rectangle = { + .x = roi->left, + .y = roi->top, + .width = roi->right - roi->left, + .height = roi->bottom - roi->top, + }, + .roi_value = av_clip_c(v, INT8_MIN, INT8_MAX), + }; + } + + param_roi = (VAEncMiscParameterBufferROI) { + .num_roi = nb_roi, + .max_delta_qp = INT8_MAX, + .min_delta_qp = INT8_MIN, + .roi = pic->roi, + .roi_flags.bits.roi_value_is_qp_delta = 1, + }; + + err = vaapi_encode_make_misc_param_buffer(avctx, pic, + VAEncMiscParameterTypeROI, + ¶m_roi, + sizeof(param_roi)); + if (err < 0) + goto fail; + } +#endif + vas = vaBeginPicture(ctx->hwctx->display, ctx->va_context, pic->input_surface); if (vas != VA_STATUS_SUCCESS) { @@ -500,6 +566,7 @@ fail_at_end: av_freep(&pic->codec_picture_params); av_freep(&pic->param_buffers); av_freep(&pic->slices); + av_freep(&pic->roi); av_frame_free(&pic->recon_image); av_buffer_unref(&pic->output_buffer_ref); pic->output_buffer = VA_INVALID_ID; @@ -634,6 +701,7 @@ static int vaapi_encode_free(AVCodecContext *avctx, av_freep(&pic->priv_data); av_freep(&pic->codec_picture_params); + av_freep(&pic->roi); av_free(pic); @@ -948,6 +1016,17 @@ static int vaapi_encode_check_frame(AVCodecContext *avctx, ctx->crop_warned = 1; } + if (!ctx->roi_allowed) { + AVFrameSideData *sd = + av_frame_get_side_data(frame, AV_FRAME_DATA_REGIONS_OF_INTEREST); + + if (sd && !ctx->roi_warned) { + av_log(avctx, AV_LOG_WARNING, "ROI side data on input " + "frames ignored due to lack of driver support.\n"); + ctx->roi_warned = 1; + } + } + return 0; } @@ -1942,6 +2021,39 @@ static av_cold int vaapi_encode_init_quality(AVCodecContext *avctx) return 0; } +static av_cold int vaapi_encode_init_roi(AVCodecContext *avctx) +{ +#if VA_CHECK_VERSION(1, 0, 0) + VAAPIEncodeContext *ctx = avctx->priv_data; + VAStatus vas; + VAConfigAttrib attr = { VAConfigAttribEncROI }; + + vas = vaGetConfigAttributes(ctx->hwctx->display, + ctx->va_profile, + ctx->va_entrypoint, + &attr, 1); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query ROI " + "config attribute: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR_EXTERNAL; + } + + if (attr.value == VA_ATTRIB_NOT_SUPPORTED) { + ctx->roi_allowed = 0; + } else { + VAConfigAttribValEncROI roi = { + .value = attr.value, + }; + + ctx->roi_max_regions = roi.bits.num_roi_regions; + ctx->roi_allowed = ctx->roi_max_regions > 0 && + (ctx->va_rc_mode == VA_RC_CQP || + roi.bits.roi_rc_qp_delta_support); + } +#endif + return 0; +} + static void vaapi_encode_free_output_buffer(void *opaque, uint8_t *data) { @@ -2132,6 +2244,10 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) if (err < 0) goto fail; + err = vaapi_encode_init_roi(avctx); + if (err < 0) + goto fail; + if (avctx->compression_level >= 0) { err = vaapi_encode_init_quality(avctx); if (err < 0) |