转载https://blog.csdn.net/nb_vol_1/article/details/56036991
代码实现
某个模式下的率失真代价,是通过该模式下编码的失真和占用的比特比特数来计算的
TComDataCU中有三个成员以及函数和率失真相关:
- UInt& getTotalDistortion() { return m_uiTotalDistortion; } //总的失真,某一种模式下总的失真
- Double& getTotalCost() { return m_dTotalCost; } //总的代价,某一种模式下总的代价
- UInt& getTotalBits() { return m_uiTotalBits; } //总得比特数,按照某一种模式进行编码之后的总比特数
失真的计算
一个像素块的总的失真就是该像素块中三个分量的失真之和。失真是通过TComRdCost::getDistPart函数进行计算的,DistParam是失真参数结构体,用于存放计算失真的参数,以及处理计算过程的函数指针,至于使用哪个具体的率失真计算函数,可以通过DFunc枚举来指定,默认使用DF_SSE(即xGetSSE,平方误差和)。
- UInt TComRdCost::getDistPart(Int bitDepth, Pel* piCur, Int iCurStride, Pel* piOrg, Int iOrgStride, UInt uiBlkWidth, UInt uiBlkHeight, TextType eText, DFunc eDFunc)
- {
- // DistParam是失真参数结构体,用于存放计算失真的参数,以及处理计算过程的函数指针
- DistParam cDtParam;
- // eDFunc指定了使用哪个失真计算函数(默认使用SSE的方式计算)
- setDistParam( uiBlkWidth, uiBlkHeight, eDFunc, cDtParam );
- cDtParam.pOrg = piOrg;
- cDtParam.pCur = piCur;
- cDtParam.iStrideOrg = iOrgStride;
- cDtParam.iStrideCur = iCurStride;
- cDtParam.iStep = 1;
- cDtParam.bApplyWeight = false;
- cDtParam.uiComp = 255; // just for assert: to be sure it was set before use, since only values 0,1 or 2 are allowed.
- cDtParam.bitDepth = bitDepth;
- if (eText == TEXT_CHROMA_U)
- {
- return ((Int) (m_cbDistortionWeight * cDtParam.DistFunc( &cDtParam )));
- }
- else if (eText == TEXT_CHROMA_V)
- {
- return ((Int) (m_crDistortionWeight * cDtParam.DistFunc( &cDtParam )));
- }
- else
- {
- return cDtParam.DistFunc( &cDtParam );
- }
- }
- /*
- ** 默认的失真计算函数(使用SSE的方法)
- */
- UInt TComRdCost::xGetSSE( DistParam* pcDtParam )
- {
- if ( pcDtParam->bApplyWeight )
- {
- return xGetSSEw( pcDtParam );
- }
- Pel* piOrg = pcDtParam->pOrg;
- Pel* piCur = pcDtParam->pCur;
- Int iRows = pcDtParam->iRows;
- Int iCols = pcDtParam->iCols;
- Int iStrideOrg = pcDtParam->iStrideOrg;
- Int iStrideCur = pcDtParam->iStrideCur;
- UInt uiSum = 0;
- UInt uiShift = DISTORTION_PRECISION_ADJUSTMENT((pcDtParam->bitDepth-8) << 1);
- Int iTemp;
- for( ; iRows != 0; iRows-- )
- {
- for (Int n = 0; n < iCols; n++ )
- {
- iTemp = piOrg[n ] - piCur[n ];
- uiSum += ( iTemp * iTemp ) >> uiShift;
- }
- piOrg += iStrideOrg;
- piCur += iStrideCur;
- }
- return ( uiSum );
- }
比特总数的计算
这个就比较简单了,熵编码之后统计比特数就可以了,具体的就是调用TEncEntropy::getNumberOfWrittenBits()函数得到比特数
率失真代价的计算
计算完成失真与比特数之后,就可以利用失真与比特数来计算代价了,计算代价是通过TComRdCost::calcRdCost函数来进行的
- Double TComRdCost::calcRdCost( UInt uiBits, UInt uiDistortion, Bool bFlag, DFunc eDFunc )
- {
- Double dRdCost = 0.0;
- Double dLambda = 0.0;
- // 根据率失真计算函数的类型来确定lambda参数
- switch ( eDFunc )
- {
- case DF_SSE:
- assert(0);
- break;
- case DF_SAD:
- dLambda = (Double)m_uiLambdaMotionSAD;
- break;
- case DF_DEFAULT:
- dLambda = m_dLambda;
- break;
- case DF_SSE_FRAME:
- dLambda = m_dFrameLambda;
- break;
- default:
- assert (0);
- break;
- }
- // 根据失真和比特数来计算代价
- // 是否选用某种模式,要根据代价来决定,代价要在失真和比特数之间达到平衡
- // 既要让失真小,也要让比特数少
- if (bFlag)
- {
- // Intra8x8, Intra4x4 Block only...
- #if SEQUENCE_LEVEL_LOSSLESS
- dRdCost = (Double)(uiBits);
- #else
- dRdCost = (((Double)uiDistortion) + ((Double)uiBits * dLambda));
- #endif
- }
- else
- {
- if (eDFunc == DF_SAD)
- {
- dRdCost = ((Double)uiDistortion + (Double)((Int)(uiBits * dLambda+.5)>>16));
- dRdCost = (Double)(UInt)floor(dRdCost);
- }
- else
- {
- #if SEQUENCE_LEVEL_LOSSLESS
- dRdCost = (Double)(uiBits);
- #else
- dRdCost = ((Double)uiDistortion + (Double)((Int)(uiBits * dLambda+.5)));
- dRdCost = (Double)(UInt)floor(dRdCost);
- #endif
- }
- }
- return dRdCost;
- }