Message ID | 20190603231905.9536-4-sw@jkqxz.net |
---|---|
State | New |
Headers | show |
On Tue, Jun 04, 2019 at 12:19:04AM +0100, Mark Thompson wrote: > --- > 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 breaks build CC libavcodec/vaapi_encode.o libavcodec/vaapi_encode.c: In function ‘vaapi_encode_issue’: libavcodec/vaapi_encode.c:570:18: error: ‘VAAPIEncodePicture’ has no member named ‘roi’ av_freep(&pic->roi); ^ libavcodec/vaapi_encode.c:169:22: warning: variable ‘sd’ set but not used [-Wunused-but-set-variable] AVFrameSideData *sd; ^ libavcodec/vaapi_encode.c: In function ‘vaapi_encode_free’: libavcodec/vaapi_encode.c:705:18: error: ‘VAAPIEncodePicture’ has no member named ‘roi’ av_freep(&pic->roi); ^ make: *** [libavcodec/vaapi_encode.o] Error 1 make: Target `all' not remade because of errors. [...]
> -----Original Message----- > From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of > Mark Thompson > Sent: Tuesday, June 04, 2019 7:19 AM > To: ffmpeg-devel@ffmpeg.org > Subject: [FFmpeg-devel] [PATCH v3 4/5] vaapi_encode: Add ROI support > > + // 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, it is typo, the correct is: .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), > + }; > + } > +
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; }