libavcodec/qsvenc: Enable fixed QP configure in qsv CQP runtime

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>
Signed-off-by: Haihao Xiang <haihao.xiang@intel.com>
release/5.1
Yue Heng 3 years ago committed by Haihao Xiang
parent afa20e6db8
commit 53baf60603
  1. 10
      doc/encoders.texi
  2. 89
      libavcodec/qsvenc.c

@ -3333,6 +3333,16 @@ Forcing I frames as IDR frames.
For encoders set this flag to ON to reduce power consumption and GPU usage. For encoders set this flag to ON to reduce power consumption and GPU usage.
@end table @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 @subsection H264 options
These options are used by h264_qsv These options are used by h264_qsv

@ -146,6 +146,14 @@ static const struct {
{ MFX_RATECONTROL_QVBR, "QVBR" }, { 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) static const char *print_ratecontrol(mfxU16 rc_mode)
{ {
int i; int i;
@ -1613,6 +1621,83 @@ static int set_roi_encode_ctrl(AVCodecContext *avctx, const AVFrame *frame,
return 0; 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, static int encode_frame(AVCodecContext *avctx, QSVEncContext *q,
const AVFrame *frame) const AVFrame *frame)
{ {
@ -1731,6 +1816,10 @@ int ff_qsv_encode(AVCodecContext *avctx, QSVEncContext *q,
{ {
int ret; int ret;
ret = update_parameters(avctx, q, frame);
if (ret < 0)
return ret;
ret = encode_frame(avctx, q, frame); ret = encode_frame(avctx, q, frame);
if (ret < 0) if (ret < 0)
return ret; return ret;

Loading…
Cancel
Save