|
|
|
@ -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) |
|
|
|
|