[FFmpeg-devel] [PATCH v3 4/5] vaapi_encode: Add ROI support
Mark Thompson
sw at jkqxz.net
Tue Jun 4 02:19:04 EEST 2019
---
For example:
$ ./ffmpeg_g -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format vaapi -i in.mp4 -an -vf 'scale_vaapi=96:96,addroi=iw/3:ih/3:iw/3:ih/3:-1/2' -c:v h264_vaapi -rc_mode CQP -global_quality 44 -frames:v 1 test.264
...
$ ldecod.exe
...
$ cat trace_dec.txt | grep qp
@30 SPS: lossless_qpprime_y_zero_flag 0 ( 0)
@214 PPS: pic_init_qp_minus26 00000100100 ( 18)
@226 PPS: chroma_qp_index_offset 1 ( 0)
@232 PPS: second_chroma_qp_index_offset 1 ( 0)
@261 SH: slice_qp_delta 1 ( 0)
@20 mb_qp_delta ( 0)
@29 mb_qp_delta ( 0)
@35 mb_qp_delta ( 0)
@40 mb_qp_delta ( 0)
@45 mb_qp_delta ( 0)
@50 mb_qp_delta ( 0)
@55 mb_qp_delta ( 0)
@61 mb_qp_delta ( 0)
@66 mb_qp_delta ( 0)
@71 mb_qp_delta ( 0)
@76 mb_qp_delta ( 0)
@81 mb_qp_delta ( 0)
@86 mb_qp_delta ( 0)
@91 mb_qp_delta ( 0)
@96 mb_qp_delta (-25)
@106 mb_qp_delta ( 0)
@112 mb_qp_delta ( 25)
@117 mb_qp_delta ( 0)
@122 mb_qp_delta ( 0)
@127 mb_qp_delta ( 0)
@132 mb_qp_delta (-25)
@138 mb_qp_delta ( 0)
@143 mb_qp_delta ( 25)
@148 mb_qp_delta ( 0)
@153 mb_qp_delta ( 0)
@158 mb_qp_delta ( 0)
@163 mb_qp_delta ( 0)
@168 mb_qp_delta ( 0)
@173 mb_qp_delta ( 0)
@178 mb_qp_delta ( 0)
@183 mb_qp_delta ( 0)
@188 mb_qp_delta ( 0)
@193 mb_qp_delta ( 0)
@198 mb_qp_delta ( 0)
@203 mb_qp_delta ( 0)
@208 mb_qp_delta ( 0)
libavcodec/vaapi_encode.c | 119 ++++++++++++++++++++++++++++++++
libavcodec/vaapi_encode.h | 16 +++++
libavcodec/vaapi_encode_h264.c | 2 +
libavcodec/vaapi_encode_h265.c | 2 +
libavcodec/vaapi_encode_mpeg2.c | 2 +
libavcodec/vaapi_encode_vp8.c | 2 +
libavcodec/vaapi_encode_vp9.c | 2 +
7 files changed, 145 insertions(+)
diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c
index dd2a24de04..d2e3a9bee8 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;
+ 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,72 @@ static int vaapi_encode_issue(AVCodecContext *avctx,
}
}
+ sd = av_frame_get_side_data(pic->input_image,
+ AV_FRAME_DATA_REGIONS_OF_INTEREST);
+
+#if VA_CHECK_VERSION(1, 0, 0)
+ 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->top,
+ .y = roi->left,
+ .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 +567,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 +702,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 +1017,19 @@ 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) {
+ 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 +2024,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 +2247,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)
diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h
index eeec06036b..c3b6e203f8 100644
--- a/libavcodec/vaapi_encode.h
+++ b/libavcodec/vaapi_encode.h
@@ -69,6 +69,11 @@ typedef struct VAAPIEncodePicture {
int64_t pts;
int force_idr;
+#if VA_CHECK_VERSION(1, 0, 0)
+ // ROI regions.
+ VAEncROI *roi;
+#endif
+
int type;
int b_depth;
int encode_issued;
@@ -304,9 +309,20 @@ typedef struct VAAPIEncodeContext {
int gop_counter;
int end_of_stream;
+ // Whether the driver supports ROI at all.
+ int roi_allowed;
+ // Maximum number of regions supported by the driver.
+ int roi_max_regions;
+ // Quantisation range for offset calculations. Set by codec-specific
+ // code, as it may change based on parameters.
+ int roi_quant_range;
+
// The encoder does not support cropping information, so warn about
// it the first time we encounter any nonzero crop fields.
int crop_warned;
+ // If the driver does not support ROI then warn the first time we
+ // encounter a frame with ROI side data.
+ int roi_warned;
} VAAPIEncodeContext;
enum {
diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c
index d1427112ea..f4965d8b09 100644
--- a/libavcodec/vaapi_encode_h264.c
+++ b/libavcodec/vaapi_encode_h264.c
@@ -1130,6 +1130,8 @@ static av_cold int vaapi_encode_h264_configure(AVCodecContext *avctx)
}
}
+ ctx->roi_quant_range = 51 + 6 * (ctx->profile->depth - 8);
+
return 0;
}
diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c
index 758bd40a37..538862a9d5 100644
--- a/libavcodec/vaapi_encode_h265.c
+++ b/libavcodec/vaapi_encode_h265.c
@@ -1102,6 +1102,8 @@ static av_cold int vaapi_encode_h265_configure(AVCodecContext *avctx)
priv->fixed_qp_b = 30;
}
+ ctx->roi_quant_range = 51 + 6 * (ctx->profile->depth - 8);
+
return 0;
}
diff --git a/libavcodec/vaapi_encode_mpeg2.c b/libavcodec/vaapi_encode_mpeg2.c
index fb1ef71fdc..bac9ea1fa6 100644
--- a/libavcodec/vaapi_encode_mpeg2.c
+++ b/libavcodec/vaapi_encode_mpeg2.c
@@ -552,6 +552,8 @@ static av_cold int vaapi_encode_mpeg2_configure(AVCodecContext *avctx)
ctx->nb_slices = ctx->slice_block_rows;
ctx->slice_size = 1;
+ ctx->roi_quant_range = 31;
+
return 0;
}
diff --git a/libavcodec/vaapi_encode_vp8.c b/libavcodec/vaapi_encode_vp8.c
index ddbe4c9075..6e7bf9d106 100644
--- a/libavcodec/vaapi_encode_vp8.c
+++ b/libavcodec/vaapi_encode_vp8.c
@@ -173,6 +173,8 @@ static av_cold int vaapi_encode_vp8_configure(AVCodecContext *avctx)
else
priv->q_index_i = priv->q_index_p;
+ ctx->roi_quant_range = VP8_MAX_QUANT;
+
return 0;
}
diff --git a/libavcodec/vaapi_encode_vp9.c b/libavcodec/vaapi_encode_vp9.c
index f89fd0d07a..d7f415d704 100644
--- a/libavcodec/vaapi_encode_vp9.c
+++ b/libavcodec/vaapi_encode_vp9.c
@@ -202,6 +202,8 @@ static av_cold int vaapi_encode_vp9_configure(AVCodecContext *avctx)
priv->q_idx_idr = priv->q_idx_p = priv->q_idx_b = 100;
}
+ ctx->roi_quant_range = VP9_MAX_QUANT;
+
return 0;
}
--
2.20.1
More information about the ffmpeg-devel
mailing list