率失真優化——程式碼
阿新 • • 發佈:2019-01-22
轉載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 )));
- }
- elseif (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;
- }