RcCalculatePictureQp 函数
函数功能
在码控中,当eSliceType为P_SLICE时 计算 P 帧的帧级量化参数QP 值。
函数原理过程
- 初始化各类变量;
- 计算帧复杂度iFrameComplexity,如果iUsageType是SCREEN_CONTENT_REAL_TIME,重复赋值帧复杂度iFrameComplexity;
- 如果iPFrameNum 等于 0;
- 第一个 P 帧,则iLumaQp等于iInitialQp;
- 如果iCurrentBitsLevel等于BITS_EXCEEDED;
- iLumaQp等于iLastCalculatedQScale加上 一个常量;
- 声明并计算一个变量iLastIdxCodecInVGop,它代表在视频组(Video Group of Pictures, VGop)中最后一个编码帧的索引。这里通过从iFrameCodedInVGop减去1来得到;
- 如果iLastIdxCodecInVGop 小于 0,就通过加上VGOP_SIZE(视频组的大小)来调整;
- 声明并计算一个变量iTlLast,它是根据iLastIdxCodecInVGop索引在iTlOfFrames数组中的时间层ID;
- 计算时间层量化参数差iDeltaQpTemporal,它是当前时间层iTl与上一个时间层iTlLast的差值;
- 如果上一个时间层是0(表示基础层),而当前时间层大于0(表示增强层),则增加iDeltaQpTemporal的值;
- 如果当前时间层是0,而上一个时间层大于0,那么减少iDeltaQpTemporal的值;
- 否则,
- 调用
WELS_DIV_ROUND64
函数根据帧复杂度iFrameComplexity和帧复杂度均值iFrameCmplxMean计算复杂度变化率iCmplxRatio;- 调用
WELS_CLIP3
函数限制复杂度变化率iCmplxRatio值;- 调用
WELS_DIV_ROUND
函数根据iLinearCmplx、iCmplxRatio、iTargetBits计算量化步长iQStep;- 调用
RcConvertQStep2Qp
函数将量化步长iQStep转化为量化参数iLumaQp;- 声明并计算一个变量iLastIdxCodecInVGop,它代表在视频组(Video Group of Pictures, VGop)中最后一个编码帧的索引。这里通过从iFrameCodedInVGop减去1来得到;
- 如果iLastIdxCodecInVGop 小于 0,就通过加上VGOP_SIZE(视频组的大小)来调整;
- 声明并计算一个变量iTlLast,它是根据iLastIdxCodecInVGop索引在iTlOfFrames数组中的时间层ID;
- 计算时间层量化参数差iDeltaQpTemporal,它是当前时间层iTl与上一个时间层iTlLast的差值;
- 如果上一个时间层是0(表示基础层),而当前时间层大于0(表示增强层),则增加iDeltaQpTemporal的值;
- 如果当前时间层是0,而上一个时间层大于0,那么减少iDeltaQpTemporal的值;
- 根据iLastCalculatedQScale、iFrameDeltaQpLower、iDeltaQpTemporal、iMinQp、iMaxQp计算出量化参数最大值iMaxFrameQp和最小值iMinFrameQp;
- 根据最大值iMaxFrameQp和最小值iMinFrameQp,限制亮度 qp 值iLumaQp;
- 如果开启自适应量化;
- 调用
WELS_DIV_ROUND
函数根据iAverMotionTextureIndexToDeltaQp重新计算出亮度 qp 值iLumaQp;- 根据最大值iMaxFrameQp和最小值iMinFrameQp,限制亮度 qp 值iLumaQp;
- 调用
RcConvertQp2QStep
函数将亮度 qp 值iLumaQp转为量化步长iQStep;- 将亮度 qp 值iLumaQp赋值给iLastCalculatedQScale和帧级 qp 值iGlobalQp。
函数原理图
函数源码
void RcCalculatePictureQp (sWelsEncCtx* pEncCtx) {
SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
int32_t iTl = pEncCtx->uiTemporalId;
SRCTemporal* pTOverRc = &pWelsSvcRc->pTemporalOverRc[iTl];
int32_t iLumaQp = 0;
int32_t iDeltaQpTemporal = 0;
int64_t iFrameComplexity = pEncCtx->pVaa->sComplexityAnalysisParam.iFrameComplexity;
if (pEncCtx->pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) {
SVAAFrameInfoExt* pVaa = static_cast<SVAAFrameInfoExt*> (pEncCtx->pVaa);
iFrameComplexity = pVaa->sComplexityScreenParam.iFrameComplexity;
}
if (0 == pTOverRc->iPFrameNum) {
iLumaQp = pWelsSvcRc->iInitialQp;
} else if (pWelsSvcRc->iCurrentBitsLevel == BITS_EXCEEDED) {
iLumaQp = pWelsSvcRc->iLastCalculatedQScale + DELTA_QP_BGD_THD;
//limit QP
int32_t iLastIdxCodecInVGop = pWelsSvcRc->iFrameCodedInVGop - 1;
if (iLastIdxCodecInVGop < 0)
iLastIdxCodecInVGop += VGOP_SIZE;
int32_t iTlLast = pWelsSvcRc->iTlOfFrames[iLastIdxCodecInVGop];
iDeltaQpTemporal = iTl - iTlLast;
if (0 == iTlLast && iTl > 0)
iDeltaQpTemporal += 1;
else if (0 == iTl && iTlLast > 0)
iDeltaQpTemporal -= 1;
} else {
int64_t iCmplxRatio = WELS_DIV_ROUND64 (iFrameComplexity * INT_MULTIPLY,
pTOverRc->iFrameCmplxMean);
iCmplxRatio = WELS_CLIP3 (iCmplxRatio, INT_MULTIPLY - FRAME_CMPLX_RATIO_RANGE, INT_MULTIPLY + FRAME_CMPLX_RATIO_RANGE);
pWelsSvcRc->iQStep = WELS_DIV_ROUND ((pTOverRc->iLinearCmplx * iCmplxRatio), (pWelsSvcRc->iTargetBits * INT_MULTIPLY));
iLumaQp = RcConvertQStep2Qp (pWelsSvcRc->iQStep);
WelsLog (& (pEncCtx->sLogCtx), WELS_LOG_DEBUG,
"iCmplxRatio = %d,frameComplexity = %" PRId64 ",iFrameCmplxMean = %" PRId64 ",iQStep = %d,iLumaQp = %d", (int)iCmplxRatio,
iFrameComplexity, pTOverRc->iFrameCmplxMean, pWelsSvcRc->iQStep, iLumaQp);
//limit QP
int32_t iLastIdxCodecInVGop = pWelsSvcRc->iFrameCodedInVGop - 1;
if (iLastIdxCodecInVGop < 0)
iLastIdxCodecInVGop += VGOP_SIZE;
int32_t iTlLast = pWelsSvcRc->iTlOfFrames[iLastIdxCodecInVGop];
int32_t iDeltaQpTemporal = iTl - iTlLast;
if (0 == iTlLast && iTl > 0)
iDeltaQpTemporal += 1;
else if (0 == iTl && iTlLast > 0)
iDeltaQpTemporal -= 1;
}
pWelsSvcRc->iMinFrameQp = WELS_CLIP3 (pWelsSvcRc->iLastCalculatedQScale - pWelsSvcRc->iFrameDeltaQpLower +
iDeltaQpTemporal, pTOverRc->iMinQp, pTOverRc->iMaxQp) ;
pWelsSvcRc->iMaxFrameQp = WELS_CLIP3 (pWelsSvcRc->iLastCalculatedQScale + pWelsSvcRc->iFrameDeltaQpUpper +
iDeltaQpTemporal, pTOverRc->iMinQp, pTOverRc->iMaxQp);
iLumaQp = WELS_CLIP3 (iLumaQp, pWelsSvcRc->iMinFrameQp, pWelsSvcRc->iMaxFrameQp);
if (pEncCtx->pSvcParam->bEnableAdaptiveQuant) {
iLumaQp = WELS_DIV_ROUND (iLumaQp * INT_MULTIPLY - pEncCtx->pVaa->sAdaptiveQuantParam.iAverMotionTextureIndexToDeltaQp,
INT_MULTIPLY);
iLumaQp = WELS_CLIP3 (iLumaQp, pWelsSvcRc->iMinFrameQp, pWelsSvcRc->iMaxFrameQp);
}
pWelsSvcRc->iQStep = RcConvertQp2QStep (iLumaQp);
pWelsSvcRc->iLastCalculatedQScale = iLumaQp;
pEncCtx->iGlobalQp = iLumaQp;
}