Message ID | 20220623053242.360909-1-wenbin.chen@intel.com |
---|---|
State | Accepted |
Commit | 53baf606038f710f0cbd3f19b3d416978b98167f |
Headers | show |
Series | [FFmpeg-devel,v3] libavcodec/qsvenc: Enable fixed QP configure in qsv CQP runtime | expand |
Context | Check | Description |
---|---|---|
yinshiyou/configure_loongarch64 | warning | Failed to run configure |
andriy/make_x86 | success | Make finished |
andriy/make_fate_x86 | success | Make fate finished |
andriy/make_armv7_RPi4 | success | Make finished |
andriy/make_fate_armv7_RPi4 | success | Make fate finished |
On Thu, 2022-06-23 at 13:32 +0800, Wenbin Chen wrote: > From: Yue Heng <yue.heng@intel.com> > > Enable dynamic QP configuration in runtime on qsv encoder. Through > AVFrame->metadata, we can set key "qsv_config_qp" to change QP > configuration when we encode video in CQP mode. > > Signed-off-by: Yue Heng <yue.heng@intel.com> > Signed-off-by: Wenbin Chen <wenbin.chen@intel.com> > --- > doc/encoders.texi | 10 +++++ > libavcodec/qsvenc.c | 89 +++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 99 insertions(+) > > diff --git a/doc/encoders.texi b/doc/encoders.texi > index 1850c99fe9..02a91ffe96 100644 > --- a/doc/encoders.texi > +++ b/doc/encoders.texi > @@ -3333,6 +3333,16 @@ Forcing I frames as IDR frames. > For encoders set this flag to ON to reduce power consumption and GPU usage. > @end table > > +@subsection Runtime Options > +Following options can be used durning qsv encoding. > + > +@table @option > +@item @var{qsv_config_qp} > +Supported in h264_qsv and hevc_qsv. > +This option can be set in per-frame metadata. QP parameter can be dynamically > +changed when encoding in CQP mode. > +@end table > + > @subsection H264 options > These options are used by h264_qsv > > diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c > index 902bada55b..2382c2f5f7 100644 > --- a/libavcodec/qsvenc.c > +++ b/libavcodec/qsvenc.c > @@ -146,6 +146,14 @@ static const struct { > { MFX_RATECONTROL_QVBR, "QVBR" }, > }; > > +#define UPDATE_PARAM(a, b) \ > +do { \ > + if ((a) != (b)) { \ > + a = b; \ > + updated = 1; \ > + } \ > +} while (0) \ > + > static const char *print_ratecontrol(mfxU16 rc_mode) > { > int i; > @@ -1613,6 +1621,83 @@ static int set_roi_encode_ctrl(AVCodecContext *avctx, > const AVFrame *frame, > return 0; > } > > +static int update_qp(AVCodecContext *avctx, QSVEncContext *q, > + const AVFrame *frame) > +{ > + int updated = 0, qp = 0, new_qp; > + char *tail; > + AVDictionaryEntry *entry = NULL; > + > + if (avctx->codec_id != AV_CODEC_ID_H264 && avctx->codec_id != > AV_CODEC_ID_HEVC) > + return 0; > + > + entry = av_dict_get(frame->metadata, "qsv_config_qp", NULL, 0); > + if (entry && q->param.mfx.RateControlMethod == MFX_RATECONTROL_CQP) { > + qp = strtol(entry->value, &tail, 10); > + if (*tail) { > + av_log(avctx, AV_LOG_WARNING, "Invalid qsv_config_qp string. > Ignore this metadata\n"); > + return 0; > + } > + if (qp < 0 || qp > 51) { > + av_log(avctx, AV_LOG_WARNING, "Invalid qp, clip to 0 ~ 51\n"); > + qp = av_clip(qp, 0, 51); > + } > + av_log(avctx, AV_LOG_DEBUG, "Configure qp: %d\n",qp); > + UPDATE_PARAM(q->param.mfx.QPP, qp); > + new_qp = av_clip(qp * fabs(avctx->i_quant_factor) + > + avctx->i_quant_offset, 0, 51); > + UPDATE_PARAM(q->param.mfx.QPI, new_qp); > + new_qp = av_clip(qp * fabs(avctx->b_quant_factor) + > + avctx->b_quant_offset, 0, 51); > + UPDATE_PARAM(q->param.mfx.QPB, new_qp); > + av_log(avctx, AV_LOG_DEBUG, > + "using fixed qp = %d/%d/%d for idr/p/b frames\n", > + q->param.mfx.QPI, q->param.mfx.QPP, q->param.mfx.QPB); > + } > + return updated; > +} > + > +static int update_parameters(AVCodecContext *avctx, QSVEncContext *q, > + const AVFrame *frame) > +{ > + int needReset = 0, ret = 0; > + > + if (!frame) > + return 0; > + > + needReset = update_qp(avctx, q, frame); > + if (!needReset) > + return 0; > + > + if (avctx->hwaccel_context) { > + AVQSVContext *qsv = avctx->hwaccel_context; > + int i, j; > + q->param.ExtParam = q->extparam; > + for (i = 0; i < qsv->nb_ext_buffers; i++) > + q->param.ExtParam[i] = qsv->ext_buffers[i]; > + q->param.NumExtParam = qsv->nb_ext_buffers; > + > + for (i = 0; i < q->nb_extparam_internal; i++) { > + for (j = 0; j < qsv->nb_ext_buffers; j++) { > + if (qsv->ext_buffers[j]->BufferId == q->extparam_internal[i]- > >BufferId) > + break; > + } > + if (j < qsv->nb_ext_buffers) > + continue; > + q->param.ExtParam[q->param.NumExtParam++] = q- > >extparam_internal[i]; > + } > + } else { > + q->param.ExtParam = q->extparam_internal; > + q->param.NumExtParam = q->nb_extparam_internal; > + } > + av_log(avctx, AV_LOG_DEBUG, "Parameter change, call msdk reset.\n"); > + ret = MFXVideoENCODE_Reset(q->session, &q->param); > + if (ret < 0) > + return ff_qsv_print_error(avctx, ret, "Error during resetting"); > + > + return 0; > +} > + > static int encode_frame(AVCodecContext *avctx, QSVEncContext *q, > const AVFrame *frame) > { > @@ -1731,6 +1816,10 @@ int ff_qsv_encode(AVCodecContext *avctx, QSVEncContext > *q, > { > int ret; > > + ret = update_parameters(avctx, q, frame); > + if (ret < 0) > + return ret; > + > ret = encode_frame(avctx, q, frame); > if (ret < 0) > return ret; LGTM, will apply. -Haihao
Quoting Wenbin Chen (2022-06-23 07:32:42) > From: Yue Heng <yue.heng@intel.com> > > Enable dynamic QP configuration in runtime on qsv encoder. Through > AVFrame->metadata, we can set key "qsv_config_qp" to change QP > configuration when we encode video in CQP mode. > > Signed-off-by: Yue Heng <yue.heng@intel.com> > Signed-off-by: Wenbin Chen <wenbin.chen@intel.com> > --- > doc/encoders.texi | 10 +++++ > libavcodec/qsvenc.c | 89 +++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 99 insertions(+) > > diff --git a/doc/encoders.texi b/doc/encoders.texi > index 1850c99fe9..02a91ffe96 100644 > --- a/doc/encoders.texi > +++ b/doc/encoders.texi > @@ -3333,6 +3333,16 @@ Forcing I frames as IDR frames. > For encoders set this flag to ON to reduce power consumption and GPU usage. > @end table > > +@subsection Runtime Options > +Following options can be used durning qsv encoding. > + > +@table @option > +@item @var{qsv_config_qp} > +Supported in h264_qsv and hevc_qsv. > +This option can be set in per-frame metadata. QP parameter can be dynamically > +changed when encoding in CQP mode. > +@end table > + > @subsection H264 options > These options are used by h264_qsv > > diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c > index 902bada55b..2382c2f5f7 100644 > --- a/libavcodec/qsvenc.c > +++ b/libavcodec/qsvenc.c > @@ -146,6 +146,14 @@ static const struct { > { MFX_RATECONTROL_QVBR, "QVBR" }, > }; > > +#define UPDATE_PARAM(a, b) \ > +do { \ > + if ((a) != (b)) { \ > + a = b; \ > + updated = 1; \ > + } \ > +} while (0) \ > + > static const char *print_ratecontrol(mfxU16 rc_mode) > { > int i; > @@ -1613,6 +1621,83 @@ static int set_roi_encode_ctrl(AVCodecContext *avctx, const AVFrame *frame, > return 0; > } > > +static int update_qp(AVCodecContext *avctx, QSVEncContext *q, > + const AVFrame *frame) > +{ > + int updated = 0, qp = 0, new_qp; > + char *tail; > + AVDictionaryEntry *entry = NULL; > + > + if (avctx->codec_id != AV_CODEC_ID_H264 && avctx->codec_id != AV_CODEC_ID_HEVC) > + return 0; > + > + entry = av_dict_get(frame->metadata, "qsv_config_qp", NULL, 0); Why is this using frame metadata rather than the AVVideoEncParams side data? Frame metadata should not be used in encoders at all. Longer term it should not be used at all by anything.
On Sat, Jul 2, 2022 at 11:39 AM Anton Khirnov <anton@khirnov.net> wrote: > Quoting Wenbin Chen (2022-06-23 07:32:42) > > From: Yue Heng <yue.heng@intel.com> > > > > Enable dynamic QP configuration in runtime on qsv encoder. Through > > AVFrame->metadata, we can set key "qsv_config_qp" to change QP > > configuration when we encode video in CQP mode. > > > > Signed-off-by: Yue Heng <yue.heng@intel.com> > > Signed-off-by: Wenbin Chen <wenbin.chen@intel.com> > > --- > > doc/encoders.texi | 10 +++++ > > libavcodec/qsvenc.c | 89 +++++++++++++++++++++++++++++++++++++++++++++ > > 2 files changed, 99 insertions(+) > > > > diff --git a/doc/encoders.texi b/doc/encoders.texi > > index 1850c99fe9..02a91ffe96 100644 > > --- a/doc/encoders.texi > > +++ b/doc/encoders.texi > > @@ -3333,6 +3333,16 @@ Forcing I frames as IDR frames. > > For encoders set this flag to ON to reduce power consumption and GPU > usage. > > @end table > > > > +@subsection Runtime Options > > +Following options can be used durning qsv encoding. > > + > > +@table @option > > +@item @var{qsv_config_qp} > > +Supported in h264_qsv and hevc_qsv. > > +This option can be set in per-frame metadata. QP parameter can be > dynamically > > +changed when encoding in CQP mode. > > +@end table > > + > > @subsection H264 options > > These options are used by h264_qsv > > > > diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c > > index 902bada55b..2382c2f5f7 100644 > > --- a/libavcodec/qsvenc.c > > +++ b/libavcodec/qsvenc.c > > @@ -146,6 +146,14 @@ static const struct { > > { MFX_RATECONTROL_QVBR, "QVBR" }, > > }; > > > > +#define UPDATE_PARAM(a, b) \ > > +do { \ > > + if ((a) != (b)) { \ > > + a = b; \ > > + updated = 1; \ > > + } \ > > +} while (0) \ > > + > > static const char *print_ratecontrol(mfxU16 rc_mode) > > { > > int i; > > @@ -1613,6 +1621,83 @@ static int set_roi_encode_ctrl(AVCodecContext > *avctx, const AVFrame *frame, > > return 0; > > } > > > > +static int update_qp(AVCodecContext *avctx, QSVEncContext *q, > > + const AVFrame *frame) > > +{ > > + int updated = 0, qp = 0, new_qp; > > + char *tail; > > + AVDictionaryEntry *entry = NULL; > > + > > + if (avctx->codec_id != AV_CODEC_ID_H264 && avctx->codec_id != > AV_CODEC_ID_HEVC) > > + return 0; > > + > > + entry = av_dict_get(frame->metadata, "qsv_config_qp", NULL, 0); > > Why is this using frame metadata rather than the AVVideoEncParams side > data? > > Frame metadata should not be used in encoders at all. Longer term it > should not be used at all by anything. > Disagreed. Stop sharing your agenda. > > -- > Anton Khirnov > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". >
> Quoting Wenbin Chen (2022-06-23 07:32:42) > > From: Yue Heng <yue.heng@intel.com> > > > > Enable dynamic QP configuration in runtime on qsv encoder. Through > > AVFrame->metadata, we can set key "qsv_config_qp" to change QP > > configuration when we encode video in CQP mode. > > > > Signed-off-by: Yue Heng <yue.heng@intel.com> > > Signed-off-by: Wenbin Chen <wenbin.chen@intel.com> > > --- > > doc/encoders.texi | 10 +++++ > > libavcodec/qsvenc.c | 89 > +++++++++++++++++++++++++++++++++++++++++++++ > > 2 files changed, 99 insertions(+) > > > > diff --git a/doc/encoders.texi b/doc/encoders.texi > > index 1850c99fe9..02a91ffe96 100644 > > --- a/doc/encoders.texi > > +++ b/doc/encoders.texi > > @@ -3333,6 +3333,16 @@ Forcing I frames as IDR frames. > > For encoders set this flag to ON to reduce power consumption and GPU > usage. > > @end table > > > > +@subsection Runtime Options > > +Following options can be used durning qsv encoding. > > + > > +@table @option > > +@item @var{qsv_config_qp} > > +Supported in h264_qsv and hevc_qsv. > > +This option can be set in per-frame metadata. QP parameter can be > dynamically > > +changed when encoding in CQP mode. > > +@end table > > + > > @subsection H264 options > > These options are used by h264_qsv > > > > diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c > > index 902bada55b..2382c2f5f7 100644 > > --- a/libavcodec/qsvenc.c > > +++ b/libavcodec/qsvenc.c > > @@ -146,6 +146,14 @@ static const struct { > > { MFX_RATECONTROL_QVBR, "QVBR" }, > > }; > > > > +#define UPDATE_PARAM(a, b) \ > > +do { \ > > + if ((a) != (b)) { \ > > + a = b; \ > > + updated = 1; \ > > + } \ > > +} while (0) \ > > + > > static const char *print_ratecontrol(mfxU16 rc_mode) > > { > > int i; > > @@ -1613,6 +1621,83 @@ static int set_roi_encode_ctrl(AVCodecContext > *avctx, const AVFrame *frame, > > return 0; > > } > > > > +static int update_qp(AVCodecContext *avctx, QSVEncContext *q, > > + const AVFrame *frame) > > +{ > > + int updated = 0, qp = 0, new_qp; > > + char *tail; > > + AVDictionaryEntry *entry = NULL; > > + > > + if (avctx->codec_id != AV_CODEC_ID_H264 && avctx->codec_id != > AV_CODEC_ID_HEVC) > > + return 0; > > + > > + entry = av_dict_get(frame->metadata, "qsv_config_qp", NULL, 0); > > Why is this using frame metadata rather than the AVVideoEncParams side > data? The usage of AVVideoEncParams relates to the "qp" variable in mfxEncodeCtrl which is passed to MFXVideoENCODE_encoderFrameAsync(). This variable in qsv is for per-frame QP configuration. There are other parameter changing supports I want to add besides QP, for example, gop_size, max_frame_size, intra_refresh. These parameter configurations are not all included in mfxEncodeCtrl, so I choose to use MFXVideoENCODE_Reset() to do this. This code changes the encoding parameters which means these changes are applied to all the following frames, but AVVideoEncParams is per-frame configuration, so I think AVVideoEncParams is not suitable for this. > > Frame metadata should not be used in encoders at all. Longer term it > should not be used at all by anything. > > -- > Anton Khirnov > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Quoting Chen, Wenbin (2022-07-04 08:33:49) > > Why is this using frame metadata rather than the AVVideoEncParams side > > data? > > The usage of AVVideoEncParams relates to the "qp" variable in mfxEncodeCtrl which is passed > to MFXVideoENCODE_encoderFrameAsync(). This variable in qsv is for per-frame QP > configuration. > There are other parameter changing supports I want to add besides QP, for > example, gop_size, max_frame_size, intra_refresh. These parameter configurations are not > all included in mfxEncodeCtrl, so I choose to use MFXVideoENCODE_Reset() to do this. This > code changes the encoding parameters which means these changes are applied to all > the following frames, but AVVideoEncParams is per-frame configuration, so I think > AVVideoEncParams is not suitable for this. AVFrame metadata is also per-frame, so your logic does not make sense to me. You could also just update the AVCodecContext/private context values directly or using AVOptions.
> Quoting Chen, Wenbin (2022-07-04 08:33:49) > > > Why is this using frame metadata rather than the AVVideoEncParams > side > > > data? > > > > The usage of AVVideoEncParams relates to the "qp" variable in > mfxEncodeCtrl which is passed > > to MFXVideoENCODE_encoderFrameAsync(). This variable in qsv is for per- > frame QP > > configuration. > > There are other parameter changing supports I want to add besides QP, for > > example, gop_size, max_frame_size, intra_refresh. These parameter > configurations are not > > all included in mfxEncodeCtrl, so I choose to use MFXVideoENCODE_Reset() > to do this. This > > code changes the encoding parameters which means these changes are > applied to all > > the following frames, but AVVideoEncParams is per-frame configuration, > so I think > > AVVideoEncParams is not suitable for this. > > AVFrame metadata is also per-frame, so your logic does not make sense to > me. > > You could also just update the AVCodecContext/private context values > directly or using AVOptions. This is a possible way. I will change it. Thanks for your advice. > > -- > Anton Khirnov > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
diff --git a/doc/encoders.texi b/doc/encoders.texi index 1850c99fe9..02a91ffe96 100644 --- a/doc/encoders.texi +++ b/doc/encoders.texi @@ -3333,6 +3333,16 @@ Forcing I frames as IDR frames. For encoders set this flag to ON to reduce power consumption and GPU usage. @end table +@subsection Runtime Options +Following options can be used durning qsv encoding. + +@table @option +@item @var{qsv_config_qp} +Supported in h264_qsv and hevc_qsv. +This option can be set in per-frame metadata. QP parameter can be dynamically +changed when encoding in CQP mode. +@end table + @subsection H264 options These options are used by h264_qsv diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c index 902bada55b..2382c2f5f7 100644 --- a/libavcodec/qsvenc.c +++ b/libavcodec/qsvenc.c @@ -146,6 +146,14 @@ static const struct { { MFX_RATECONTROL_QVBR, "QVBR" }, }; +#define UPDATE_PARAM(a, b) \ +do { \ + if ((a) != (b)) { \ + a = b; \ + updated = 1; \ + } \ +} while (0) \ + static const char *print_ratecontrol(mfxU16 rc_mode) { int i; @@ -1613,6 +1621,83 @@ static int set_roi_encode_ctrl(AVCodecContext *avctx, const AVFrame *frame, return 0; } +static int update_qp(AVCodecContext *avctx, QSVEncContext *q, + const AVFrame *frame) +{ + int updated = 0, qp = 0, new_qp; + char *tail; + AVDictionaryEntry *entry = NULL; + + if (avctx->codec_id != AV_CODEC_ID_H264 && avctx->codec_id != AV_CODEC_ID_HEVC) + return 0; + + entry = av_dict_get(frame->metadata, "qsv_config_qp", NULL, 0); + if (entry && q->param.mfx.RateControlMethod == MFX_RATECONTROL_CQP) { + qp = strtol(entry->value, &tail, 10); + if (*tail) { + av_log(avctx, AV_LOG_WARNING, "Invalid qsv_config_qp string. Ignore this metadata\n"); + return 0; + } + if (qp < 0 || qp > 51) { + av_log(avctx, AV_LOG_WARNING, "Invalid qp, clip to 0 ~ 51\n"); + qp = av_clip(qp, 0, 51); + } + av_log(avctx, AV_LOG_DEBUG, "Configure qp: %d\n",qp); + UPDATE_PARAM(q->param.mfx.QPP, qp); + new_qp = av_clip(qp * fabs(avctx->i_quant_factor) + + avctx->i_quant_offset, 0, 51); + UPDATE_PARAM(q->param.mfx.QPI, new_qp); + new_qp = av_clip(qp * fabs(avctx->b_quant_factor) + + avctx->b_quant_offset, 0, 51); + UPDATE_PARAM(q->param.mfx.QPB, new_qp); + av_log(avctx, AV_LOG_DEBUG, + "using fixed qp = %d/%d/%d for idr/p/b frames\n", + q->param.mfx.QPI, q->param.mfx.QPP, q->param.mfx.QPB); + } + return updated; +} + +static int update_parameters(AVCodecContext *avctx, QSVEncContext *q, + const AVFrame *frame) +{ + int needReset = 0, ret = 0; + + if (!frame) + return 0; + + needReset = update_qp(avctx, q, frame); + if (!needReset) + return 0; + + if (avctx->hwaccel_context) { + AVQSVContext *qsv = avctx->hwaccel_context; + int i, j; + q->param.ExtParam = q->extparam; + for (i = 0; i < qsv->nb_ext_buffers; i++) + q->param.ExtParam[i] = qsv->ext_buffers[i]; + q->param.NumExtParam = qsv->nb_ext_buffers; + + for (i = 0; i < q->nb_extparam_internal; i++) { + for (j = 0; j < qsv->nb_ext_buffers; j++) { + if (qsv->ext_buffers[j]->BufferId == q->extparam_internal[i]->BufferId) + break; + } + if (j < qsv->nb_ext_buffers) + continue; + q->param.ExtParam[q->param.NumExtParam++] = q->extparam_internal[i]; + } + } else { + q->param.ExtParam = q->extparam_internal; + q->param.NumExtParam = q->nb_extparam_internal; + } + av_log(avctx, AV_LOG_DEBUG, "Parameter change, call msdk reset.\n"); + ret = MFXVideoENCODE_Reset(q->session, &q->param); + if (ret < 0) + return ff_qsv_print_error(avctx, ret, "Error during resetting"); + + return 0; +} + static int encode_frame(AVCodecContext *avctx, QSVEncContext *q, const AVFrame *frame) { @@ -1731,6 +1816,10 @@ int ff_qsv_encode(AVCodecContext *avctx, QSVEncContext *q, { int ret; + ret = update_parameters(avctx, q, frame); + if (ret < 0) + return ret; + ret = encode_frame(avctx, q, frame); if (ret < 0) return ret;