openh264 宏块级码率控制函数关系
宏块级核心函数分析
WelsRcMbInitGom函数
- 功能:openh264 码率控制框架中宏块级码率控制函数,根据是否启用GOM QP来决定如何设置宏块的QP值,以控制编码的质量和比特率。
- 原理过程:
- 函数参数:
- pEncCtx: 指向编码上下文的指针,包含编码过程中所需的全局信息。
- pCurMb: 指向当前宏块的指针,宏块是视频编码的基本单位。
- pSlice: 指向当前切片的指针,切片是一系列连续宏块的集合。
- 局部变量:
- pWelsSvcRc: 指向服务层码率控制结构的指针。
- pSOverRc: 指向切片覆盖码率控制结构的指针。
- pCurLayer: 指向当前解码质量层的指针。
- kuiChromaQpIndexOffset: 色度QP索引偏移量,用于调整色度通道的量化参数。
- 主要逻辑:
- 首先,获取当前宏块的比特流位置,并更新到切片覆盖码率控制结构中。
- 如果全局优化码率控制(GOM QP)被启用:
- 如果当前宏块是GOM的起始宏块(即其索引能被GOM的数量整除),并且不是切片的起始宏块,则增加复杂度指数。
- 调用
RcCalculateGomQp
函数计算GOM的QP值。- 调用
RcGomTargetBits
函数计算GOM的目标比特数。- 调用
RcCalculateMbQp
函数计算当前宏块的QP值。- 如果GOM QP未启用:
- 将当前宏块的亮度QP值设置为全局QP值。
- 根据亮度QP值和色度QP索引偏移量,计算并设置色度QP值。
- 关键功能:
- 函数通过判断是否启用GOM QP来决定如何设置宏块的量化参数(QP),这影响编码后视频的质量和比特率。
- 使用CLIP3_QP_0_51宏来确保QP值在有效范围内(0到51)。
- 源码:
cpp
void WelsRcMbInitGom (sWelsEncCtx* pEncCtx, SMB* pCurMb, SSlice* pSlice) {
SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SRCSlicing* pSOverRc = &pSlice->sSlicingOverRc;
SDqLayer* pCurLayer = pEncCtx->pCurDqLayer;
const uint8_t kuiChromaQpIndexOffset = pCurLayer->sLayerInfo.pPpsP->uiChromaQpIndexOffset;
pSOverRc->iBsPosSlice = pEncCtx->pFuncList->pfGetBsPosition (pSlice);
if (pWelsSvcRc->bEnableGomQp) {
//calculate gom qp and target bits at the beginning of gom
if (0 == (pCurMb->iMbXY % pWelsSvcRc->iNumberMbGom)) {
if (pCurMb->iMbXY != pSOverRc->iStartMbSlice) {
pSOverRc->iComplexityIndexSlice++;
RcCalculateGomQp (pEncCtx, pSlice, pCurMb);
}
RcGomTargetBits (pEncCtx, pSlice);
}
RcCalculateMbQp (pEncCtx, pSlice, pCurMb);
} else {
pCurMb->uiLumaQp = pEncCtx->iGlobalQp;
pCurMb->uiChromaQp = g_kuiChromaQpTable[CLIP3_QP_0_51 (pCurMb->uiLumaQp + kuiChromaQpIndexOffset)];
}
}
RcCalculateGomQp函数
- 功能:计算宏块组的量化参数 qp 的具体实现
- 原理过程:
- 函数参数:
- pEncCtx: 指向编码上下文的指针,包含编码过程中所需的全局信息。
- pSlice: 指向当前切片的指针。
- pCurMb: 指向当前宏块的指针,虽然在这段代码中没有直接使用。
- 局部变量:
- pWelsSvcRc: 指向服务层码率控制结构的指针。
- pSOverRc: 指向切片覆盖码率控制结构的指针。
- iBitsRatio: 用于计算比特率比例的变量。
- 主要逻辑:
- 计算剩余的比特数 iLeftBits,即目标比特数减去已使用的比特数。
- 计算目标剩余比特数 iTargetLeftBits,考虑了当前GOM的已用比特数。
- QP调整逻辑:
- 如果剩余比特数小于或等于0,增加QP以降低质量,减少比特率的使用。
- 否则,根据比特率比例 iBitsRatio 来调整QP:
- 如果 iBitsRatio 小于 8409,增加QP 2。
- 如果 iBitsRatio 在 8409 和 9439 之间,增加QP 1。
- 如果 iBitsRatio 大于 10600,减少QP 1。
- 如果 iBitsRatio 大于 11900,减少QP 2。
- QP值的边界限制:
- 使用 WELS_CLIP3 宏来确保计算出的QP值在允许的最小值和最大值之间。
- 重置GOM比特计数器:
- 将 iGomBitsSlice 重置为0,为下一个GOM的比特计数做准备。
- 注释:
- 注释中提到了一个可能的日志记录语句,但在这段代码中被注释掉了。
- 设计目的:
- 函数的目的是根据当前的编码比特率情况动态调整量化参数,以控制视频的质量和编码效率。
- 关键功能:
- 函数通过计算剩余比特数与目标比特数的比例,动态调整QP值,实现码率控制。
- 源码:
cpp
void RcCalculateGomQp (sWelsEncCtx* pEncCtx, SSlice* pSlice, SMB* pCurMb) {
SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SRCSlicing* pSOverRc = &pSlice->sSlicingOverRc;
int64_t iBitsRatio = 1;
int64_t iLeftBits = pSOverRc->iTargetBitsSlice - pSOverRc->iFrameBitsSlice;
int64_t iTargetLeftBits = iLeftBits + pSOverRc->iGomBitsSlice - pSOverRc->iGomTargetBits;
if ((iLeftBits <= 0) || (iTargetLeftBits <= 0)) {
pSOverRc->iCalculatedQpSlice += 2;
} else {
//globe decision
iBitsRatio = 10000 * iLeftBits / (iTargetLeftBits + 1);
if (iBitsRatio < 8409) //2^(-1.5/6)*10000
pSOverRc->iCalculatedQpSlice += 2;
else if (iBitsRatio < 9439) //2^(-0.5/6)*10000
pSOverRc->iCalculatedQpSlice += 1;
else if (iBitsRatio > 10600) //2^(0.5/6)*10000
pSOverRc->iCalculatedQpSlice -= 1;
else if (iBitsRatio > 11900) //2^(1.5/6)*10000
pSOverRc->iCalculatedQpSlice -= 2;
}
pSOverRc->iCalculatedQpSlice = WELS_CLIP3 (pSOverRc->iCalculatedQpSlice, pWelsSvcRc->iMinFrameQp,
pWelsSvcRc->iMaxFrameQp);
// WelsLog (& (pEncCtx->sLogCtx), WELS_LOG_DEBUG,"iCalculatedQpSlice =%d,iBitsRatio = %d\n",pSOverRc->iCalculatedQpSlice,iBitsRatio);
pSOverRc->iGomBitsSlice = 0;
}
RcGomTargetBits函数
- 功能:在视频编码过程中为一个组(Group of Macroblocks,GOM)分配目标比特数。
- 原理过程:
- 函数参数:
- pEncCtx: 指向编码上下文的指针,包含编码过程中所需的全局信息。
- pSlice: 指向当前切片的指针。
- 局部变量:
- pWelsSvcRc: 指向当前依赖层的码率控制服务结构体的指针。
- pWelsSvcRc_Base: 指向基础码率控制服务结构体的指针,可能用于比较或计算。
- pSOverRc: 指向切片覆盖码率控制结构的指针。
- iAllocateBits: 用于存储分配给当前GOM的比特数。
- iSumSad: 用于累加GOM的总SAD(Sum of Absolute Differences)值。
- iLastGomIndex: 表示最后一个GOM的索引。
- iLeftBits: 表示剩余的比特数。
- kiComplexityIndex: 表示当前GOM的复杂度指数。
- 主要逻辑:
- 计算最后一个GOM的索引 iLastGomIndex。
- 计算剩余的比特数 iLeftBits。
- 如果剩余比特数小于或等于0,将GOM的目标比特数设置为0并返回。
- 如果当前复杂度指数等于最后一个GOM的索引,将所有剩余比特数分配给当前GOM。
- 否则,计算从当前复杂度指数到最后一个GOM的SAD总和 iSumSad。
- 根据SAD值按比例分配剩余比特数。
- 比特分配策略:
- 如果 iSumSad 为0,等比例分配剩余比特数。
- 如果 iSumSad 不为0,根据当前GOM的SAD值占总SAD的比例来分配比特数。
- 辅助函数:
RcJudgeBaseUsability
: 用于判断基础码率控制服务结构体的可用性,其返回值可能用于计算。- 设计目的:
- 函数的目的是根据宏块的复杂度和剩余的比特资源,动态地为每个GOM分配目标比特数,以优化视频质量和编码效率。
- 关键功能:
- 函数通过计算SAD值来评估宏块的复杂度,并据此分配比特数,实现码率控制。
- 源码:
cpp
void RcGomTargetBits (sWelsEncCtx* pEncCtx, SSlice* pSlice) {
SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SWelsSvcRc* pWelsSvcRc_Base = NULL;
SRCSlicing* pSOverRc = &pSlice->sSlicingOverRc;
int32_t iAllocateBits = 0;
int32_t iSumSad = 0;
int32_t iLastGomIndex = 0;
int32_t iLeftBits = 0;
const int32_t kiComplexityIndex = pSOverRc->iComplexityIndexSlice;
int32_t i;
iLastGomIndex = pSOverRc->iEndMbSlice / pWelsSvcRc->iNumberMbGom;
iLeftBits = pSOverRc->iTargetBitsSlice - pSOverRc->iFrameBitsSlice;
if (iLeftBits <= 0) {
pSOverRc->iGomTargetBits = 0;
return;
} else if (kiComplexityIndex >= iLastGomIndex) {
iAllocateBits = iLeftBits;
} else {
pWelsSvcRc_Base = RcJudgeBaseUsability (pEncCtx);
pWelsSvcRc_Base = (pWelsSvcRc_Base) ? pWelsSvcRc_Base : pWelsSvcRc;
for (i = kiComplexityIndex + 1; i <= iLastGomIndex; i++) {
iSumSad += pWelsSvcRc_Base->pCurrentFrameGomSad[i];
}
if (0 == iSumSad)
iAllocateBits = WELS_DIV_ROUND (iLeftBits, (iLastGomIndex - kiComplexityIndex));
else
iAllocateBits = WELS_DIV_ROUND ((int64_t)iLeftBits * pWelsSvcRc_Base->pCurrentFrameGomSad[kiComplexityIndex + 1],
iSumSad);
}
pSOverRc->iGomTargetBits = iAllocateBits;
}
RcCalculateMbQp函数
- 功能:作用是在视频编码过程中为当前宏块(Macroblock, MB)计算量化参数(Quantization Parameter, QP)
- 原理过程:
- 函数参数:
- pEncCtx: 指向编码上下文的指针,包含编码过程中所需的全局信息。
- pSlice: 指向当前切片的指针。
- pCurMb: 指向当前宏块的指针。
- 局部变量:
- pWelsSvcRc: 指向服务层码率控制结构的指针。
- pSOverRc: 指向切片覆盖码率控制结构的指针。
- iLumaQp: 存储计算得到的亮度QP值。
- pCurLayer: 指向当前解码质量层的指针。
- kuiChromaQpIndexOffset: 色度QP索引偏移量。
- 主要逻辑:
- 从切片覆盖码率控制结构中获取iCalculatedQpSlice计算得到的亮度QP值 iLumaQp。
- 如果启用了自适应量化(bEnableAdaptiveQuant),则根据宏块的运动和纹理信息调整QP值。
- 自适应量化:
- 如果启用自适应量化,使用 pMotionTextureIndexToDeltaQp 数组,根据宏块的位置 MbXY 来获取QP调整值,并将其加到基础QP值iLumaQp上。
- 调整后的QP值通过 WELS_CLIP3 宏确保在允许的范围内。
- 色度QP计算:
- 使用色度QP表 g_kuiChromaQpTable 和色度QP索引偏移量 kuiChromaQpIndexOffset 来计算色度QP值。
- 色度QP值通过 CLIP3_QP_0_51 宏确保在0到51的范围内。
- 宏块QP赋值:
- 将计算得到的亮度QP和色度QP值赋给当前宏块 pCurMb。
- 源码:
cpp
void RcCalculateMbQp (sWelsEncCtx* pEncCtx, SSlice* pSlice, SMB* pCurMb) {
SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SRCSlicing* pSOverRc = &pSlice->sSlicingOverRc;
int32_t iLumaQp = pSOverRc->iCalculatedQpSlice;
SDqLayer* pCurLayer = pEncCtx->pCurDqLayer;
const uint8_t kuiChromaQpIndexOffset = pCurLayer->sLayerInfo.pPpsP->uiChromaQpIndexOffset;
if (pEncCtx->pSvcParam->bEnableAdaptiveQuant) {
iLumaQp = (int8_t)WELS_CLIP3 (iLumaQp +
pEncCtx->pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp[pCurMb->iMbXY], pWelsSvcRc->iMinFrameQp,
pWelsSvcRc->iMaxFrameQp);
}
pCurMb->uiChromaQp = g_kuiChromaQpTable[CLIP3_QP_0_51 (iLumaQp + kuiChromaQpIndexOffset)];
pCurMb->uiLumaQp = iLumaQp;
}
WelsRcMbInfoUpdateGom函数
- 功能:通过收集和更新宏块的编码信息来帮助编码器动态调整编码参数,以优化视频质量和编码效率。
- 原理过程:
- 函数参数:
- pEncCtx: 指向编码上下文的指针,包含编码过程中所需的全局信息。
- pCurMb: 指向当前宏块的指针。
- iCostLuma: 当前宏块的亮度成本,用于码率控制。
- pSlice: 指向当前切片的指针。
- 局部变量:
- pWelsSvcRc: 指向服务层码率控制结构的指针。
- pSOverRc: 指向切片覆盖码率控制结构的指针。
- kiComplexityIndex: 复杂度指数,用于码率控制策略。
- 主要逻辑:
- 计算当前宏块的比特数iCurMbBits,即从切片开始到当前宏块的比特流位置差。
- 更新切片的总比特数iFrameBitsSlice和GOM(Group of Macroblocks)的总比特数iGomBitsSlice。
- 码率控制相关操作:
- 累加当前宏块的亮度成本iCostLuma到对应复杂度指数的成本数组pGomCost中。
- 如果当前宏块的比特数大于0,更新切片的总QP(量化参数)和宏块计数器。
- 设计目的:
- 该函数的目的是在编码过程中收集和更新宏块的相关信息,以便进行有效的码率控制。
- 关键功能:
- 函数通过更新宏块的比特数和亮度成本,为后续的码率控制决策提供数据支持。
- 源码:
cpp
void WelsRcMbInfoUpdateGom (sWelsEncCtx* pEncCtx, SMB* pCurMb, int32_t iCostLuma, SSlice* pSlice) {
SWelsSvcRc* pWelsSvcRc = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
SRCSlicing* pSOverRc = &pSlice->sSlicingOverRc;
const int32_t kiComplexityIndex = pSOverRc->iComplexityIndexSlice;
int32_t iCurMbBits = pEncCtx->pFuncList->pfGetBsPosition (pSlice) - pSOverRc->iBsPosSlice;
pSOverRc->iFrameBitsSlice += iCurMbBits;
pSOverRc->iGomBitsSlice += iCurMbBits;
pWelsSvcRc->pGomCost[kiComplexityIndex] += iCostLuma;
if (iCurMbBits > 0) {
pSOverRc->iTotalQpSlice += pCurMb->uiLumaQp;
pSOverRc->iTotalMbSlice++;
}
}