openh264 帧级码率控制原理:RcCalculatePictureQp 函数

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;
}
  • 17
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Codec Conductor

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值