核心提示:最近刚接触X265,由于需要在265的量化部分进行一定的研究,因此最近把HM的量化部分代码仔细看了一遍,现在对HM中的量化部分有了一定的理解,将自己的理解写在了注释中,贴出来献丑一下。其中很多都是比较...
最近刚接触X265,由于需要在265的量化部分进行一定的研究,因此最近把HM的量化部分代码仔细看了一遍,现在对HM中的量化部分有了一定的理解,将自己的理解写在了注释中,贴出来献丑一下。其中很多都是比较小白的注释,大神请忽略。另外由于刚接触不久,注释中肯定会有很多理解不对的地方,希望有大牛看了能随时批评与指正~~~~
HM中的变换量化函数是transformNxN(),其中先是调用xTransformSkip()或xT()进行变换,之后调用xQuant()进行量化:
Void TComTrQuant::xQuant( TComDataCU* pcCU, Int* pSrc, TCoeff* pDes, #if ADAPTIVE_QP_SELECTION Int*& pArlDes, #endif Int iWidth, Int iHeight, UInt& uiAcSum, TextType eTType, UInt uiAbsPartIdx ) { Int* piCoef = pSrc; TCoeff* piQCoef = pDes; #if ADAPTIVE_QP_SELECTION Int* piArlCCoef = pArlDes; #endif Int iAdd = 0; Bool useRDOQ = pcCU->getTransformSkip(uiAbsPartIdx,eTType) ? m_useRDOQTS:m_useRDOQ; if ( useRDOQ && (eTType == TEXT_LUMA || RDOQ_CHROMA)) { #if ADAPTIVE_QP_SELECTION xRateDistOptQuant( pcCU, piCoef, pDes, pArlDes, iWidth, iHeight, uiAcSum, eTType, uiAbsPartIdx ); #else xRateDistOptQuant( pcCU, piCoef, pDes, iWidth, iHeight, uiAcSum, eTType, uiAbsPartIdx ); #endif } else//标准量化??? { const UInt log2BlockSize = g_aucConvertToBit[ iWidth ] + 2;//log2 N UInt scanIdx = pcCU->getCoefScanIdx(uiAbsPartIdx, iWidth, eTType==TEXT_LUMA, pcCU->isIntra(uiAbsPartIdx));//扫描索引 const UInt *scan = g_auiSigLastScan[ scanIdx ][ log2BlockSize - 1 ];//光栅扫描与zig-zag扫描的位置对应表 Int deltaU[32*32] ; #if ADAPTIVE_QP_SELECTION QpParam cQpBase; Int iQpBase = pcCU->getSlice()->getSliceQpBase();//slice层的QP值 用来对实际QP值进行预测 Int qpScaled; Int qpBDOffset = (eTType == TEXT_LUMA)? pcCU->getSlice()->getSPS()->getQpBDOffsetY() : pcCU->getSlice()->getSPS()->getQpBDOffsetC(); if(eTType == TEXT_LUMA)//亮度分量的情况 { qpScaled = iQpBase + qpBDOffset;//预测得出亮度块的QP } else//色度分量Cb Cr的情况 { Int chromaQPOffset; if(eTType == TEXT_CHROMA_U)//U分量 { chromaQPOffset = pcCU->getSlice()->getPPS()->getChromaCbQpOffset() + pcCU->getSlice()->getSliceQpDeltaCb();//得出色度块Cr的pps和slice层的偏移之和 pps_offset + slice_offset } else//V分量 { chromaQPOffset = pcCU->getSlice()->getPPS()->getChromaCrQpOffset() + pcCU->getSlice()->getSliceQpDeltaCr();//得出色度块Cb的pps和slice层的偏移之和 pps_offset + slice_offset } iQpBase = iQpBase + chromaQPOffset;//QP(pred) + pps_offset + slice_offset qpScaled = Clip3( -qpBDOffset, 57, iQpBase);//使得 qpBDOffset <= iQpBase <= 57 if(qpScaled < 0) { qpScaled = qpScaled + qpBDOffset;//预测得到色度的QP: QP(pred) + pps_offset + slice_offset + QP(delta) } else { qpScaled = g_aucChromaScale[ qpScaled ] + qpBDOffset;//预测得到色度的QP: QP(pred) + pps_offset + slice_offset + QP(delta) } } cQpBase.setQpParam(qpScaled);//设置m_iQP m_iPer m_iRem的值 #endif UInt uiLog2TrSize = g_aucConvertToBit[ iWidth ] + 2;//log2 N Int scalingListType = (pcCU->isIntra(uiAbsPartIdx) ? 0 : 3) + g_eTTable[(Int)eTType];//扫描方式 assert(scalingListType < SCALING_LIST_NUM); Int *piQuantCoeff = 0; piQuantCoeff = getQuantCoeff(scalingListType,m_cQP.m_iRem,uiLog2TrSize-2);//获取量化矩阵中的系数 UInt uiBitDepth = eTType == TEXT_LUMA ? g_bitDepthY : g_bitDepthC; Int iTransformShift = MAX_TR_DYNAMIC_RANGE - uiBitDepth - uiLog2TrSize; //之前的变换中的缩放比例 Represents scaling through forward transform #if ADAPTIVE_QP_SELECTION Int iQBits = QUANT_SHIFT + cQpBase.m_iPer + iTransformShift;//非RDO量化器的右偏移量 iAdd = (pcCU->getSlice()->getSliceType()==I_SLICE ? 171 : 85) << (iQBits-9);//用于计算f = 1/3(I) 或1/6(B/P) Int iQBitsC = QUANT_SHIFT + cQpBase.m_iPer + iTransformShift - ARL_C_PRECISION; Int iAddC = 1 << (iQBitsC-1);//用于计算f = 0.5 #else Int iQBits = QUANT_SHIFT + m_cQP.m_iPer + iTransformShift; //非RDO量化器的右偏移量 Right shift of non-RDOQ quantizer; level = (coeff*uiQ + offset)>>q_bits iAdd = (pcCU->getSlice()->getSliceType()==I_SLICE ? 171 : 85) << (iQBits-9); #endif Int qBits8 = iQBits-8; for( Int n = 0; n < iWidth*iHeight; n++ ) { Int iLevel; Int iSign; UInt uiBlockPos = n; iLevel = piCoef[uiBlockPos];//变换后的系数 iSign = (iLevel < 0 ? -1: 1); //变换后的系数的符号 #if ADAPTIVE_QP_SELECTION Int64 tmpLevel = (Int64)abs(iLevel) * piQuantCoeff[uiBlockPos];//QM:比例缩放 if( m_bUseAdaptQpSelect ) { piArlCCoef[uiBlockPos] = (Int)((tmpLevel + iAddC ) >> iQBitsC); } iLevel = (Int)((tmpLevel + iAdd ) >> iQBits);//计算量化后的系数 f = 1/3(I) 或1/6(B/P) deltaU[uiBlockPos] = (Int)((tmpLevel - (iLevel<<iQBits) )>> qBits8);//= -iAdd >> qBits8 #else iLevel = ((Int64)abs(iLevel) * piQuantCoeff[uiBlockPos] + iAdd ) >> iQBits; deltaU[uiBlockPos] = (Int)( ((Int64)abs(piCoef[uiBlockPos]) * piQuantCoeff[uiBlockPos] - (iLevel<<iQBits) )>> qBits8 ); #endif uiAcSum += iLevel;//变换量化系数的绝对和 absolute sum of quantized transform coefficient iLevel *= iSign; piQCoef[uiBlockPos] = Clip3( -32768, 32767, iLevel );// -32768 <= iLevel <=32767 } // for n if( pcCU->getSlice()->getPPS()->getSignHideFlag() ) { if(uiAcSum>=2) { signBitHidingHDQ( piQCoef, piCoef, scan, deltaU, iWidth, iHeight ) ;//符号数据隐藏 } } } //if RDOQ //return; }其中,RDOQ部分调用了xRateDistOptQuant()函数,对量化过程进行率失真优化:
Void TComTrQuant::xRateDistOptQuant ( TComDataCU* pcCU, Int* plSrcCoeff, TCoeff* piDstCoeff, #if ADAPTIVE_QP_SELECTION Int*& piArlDstCoeff, #endif UInt uiWidth, UInt uiHeight, UInt& uiAbsSum, TextType eTType, UInt uiAbsPartIdx ) { UInt uiLog2TrSize = g_aucConvertToBit[ uiWidth ] + 2;//log2 N UInt uiBitDepth = eTType == TEXT_LUMA ? g_bitDepthY : g_bitDepthC;//比特深度 : 8/10 Int iTransformShift = MAX_TR_DYNAMIC_RANGE - uiBitDepth - uiLog2TrSize; //之前的变换中的缩放比例 Represents scaling through forward transform UInt uiGoRiceParam = 0; Double d64BlockUncodedCost = 0; const UInt uiLog2BlkSize = g_aucConvertToBit[ uiWidth ] + 2;//log2 N const UInt uiMaxNumCoeff = uiWidth * uiHeight;//系数的个数 Int scalingListType = (pcCU->isIntra(uiAbsPartIdx) ? 0 : 3) + g_eTTable[(Int)eTType];//扫描方式 assert(scalingListType < SCALING_LIST_NUM); Int iQBits = QUANT_SHIFT + m_cQP.m_iPer + iTransformShift; //非RDO量化器的右偏移量// Right shift of non-RDOQ quantizer; level = (coeff*uiQ + offset)>>q_bits Double *pdErrScaleOrg = getErrScaleCoeff(scalingListType,uiLog2TrSize-2,m_cQP.m_iRem); Int *piQCoefOrg = getQuantCoeff(scalingListType,m_cQP.m_iRem,uiLog2TrSize-2);//获取量化矩阵中的系数 Int *piQCoef = piQCoefOrg; Double *pdErrScale = pdErrScaleOrg; #if ADAPTIVE_QP_SELECTION Int iQBitsC = iQBits - ARL_C_PRECISION; Int iAddC = 1 << (iQBitsC-1); #endif UInt uiScanIdx = pcCU->getCoefScanIdx(uiAbsPartIdx, uiWidth, eTType==TEXT_LUMA, pcCU->isIntra(uiAbsPartIdx));//获取系数扫描的方式 #if ADAPTIVE_QP_SELECTION memset(piArlDstCoeff, 0, sizeof(Int) * uiMaxNumCoeff); #endif Double pdCostCoeff [ 32 * 32 ]; Double pdCostSig [ 32 * 32 ]; Double pdCostCoeff0[ 32 * 32 ]; ::memset( pdCostCoeff, 0, sizeof(Double) * uiMaxNumCoeff ); ::memset( pdCostSig, 0, sizeof(Double) * uiMaxNumCoeff ); Int rateIncUp [ 32 * 32 ]; Int rateIncDown [ 32 * 32 ]; Int sigRateDelta[ 32 * 32 ]; Int deltaU [ 32 * 32 ]; ::memset( rateIncUp, 0, sizeof(Int) * uiMaxNumCoeff ); ::memset( rateIncDown, 0, sizeof(Int) * uiMaxNumCoeff ); ::memset( sigRateDelta, 0, sizeof(Int) * uiMaxNumCoeff ); ::memset( deltaU, 0, sizeof(Int) * uiMaxNumCoeff ); const UInt * scanCG; { scanCG = g_auiSigLastScan[ uiScanIdx ][ uiLog2BlkSize > 3 ? uiLog2BlkSize-2-1 : 0 ]; if( uiLog2BlkSize == 3 )//N = 8 { scanCG = g_sigLastScan8x8[ uiScanIdx ]; } else if( uiLog2BlkSize == 5 )//N = 32 { scanCG = g_sigLastScanCG32x32; } } const UInt uiCGSize = (1 << MLS_CG_SIZE); // 16 Double pdCostCoeffGroupSig[ MLS_GRP_NUM ]; UInt uiSigCoeffGroupFlag[ MLS_GRP_NUM ]; UInt uiNumBlkSide = uiWidth / MLS_CG_SIZE; Int iCGLastScanPos = -1; UInt uiCtxSet = 0; Int c1 = 1; Int c2 = 0; Double d64BaseCost = 0; Int iLastScanPos = -1; UInt c1Idx = 0; UInt c2Idx = 0; Int baseLevel; const UInt *scan = g_auiSigLastScan[ uiScanIdx ][ uiLog2BlkSize - 1 ]; ::memset( pdCostCoeffGroupSig, 0, sizeof(Double) * MLS_GRP_NUM ); ::memset( uiSigCoeffGroupFlag, 0, sizeof(UInt) * MLS_GRP_NUM ); UInt uiCGNum = uiWidth * uiHeight >> MLS_CG_SIZE; Int iScanPos; coeffGroupRDStats rdStats; for (Int iCGScanPos = uiCGNum-1; iCGScanPos >= 0; iCGScanPos--)//对每个4x4块遍历 从最后一个开始 { UInt uiCGBlkPos = scanCG[ iCGScanPos ]; UInt uiCGPosY = uiCGBlkPos / uiNumBlkSide; UInt uiCGPosX = uiCGBlkPos - (uiCGPosY * uiNumBlkSide); ::memset( &rdStats, 0, sizeof (coeffGroupRDStats)); const Int patternSigCtx = TComTrQuant::calcPatternSigCtx(uiSigCoeffGroupFlag, uiCGPosX, uiCGPosY, uiWidth, uiHeight); for (Int iScanPosinCG = uiCGSize-1; iScanPosinCG >= 0; iScanPosinCG--)//对4x4块的每个元素遍历 从最后一个开始 { iScanPos = iCGScanPos*uiCGSize + iScanPosinCG;//当前元素在图像中的位置索引 //===== quantization ===== //******************************************** // 1.预量化 //******************************************** UInt uiBlkPos = scan[iScanPos];//iScanPos;扫描位置 uiBlkPos :扫描位置对应的在变换系数内存中位置 // set coeff Int uiQ = piQCoef[uiBlkPos];//uiQ : MF Double dTemp = pdErrScale[uiBlkPos]; Int lLevelDouble = plSrcCoeff[ uiBlkPos ];//变换后的系数, 量化模块的输入量 lLevelDouble = (Int)min<Int64>((Int64)abs((Int)lLevelDouble) * uiQ , MAX_INT - (1 << (iQBits - 1)));//QM:比例缩放 #if ADAPTIVE_QP_SELECTION if( m_bUseAdaptQpSelect ) { piArlDstCoeff[uiBlkPos] = (Int)(( lLevelDouble + iAddC) >> iQBitsC ); } #endif UInt uiMaxAbsLevel = (lLevelDouble + (1 << (iQBits - 1))) >> iQBits;//得到量化值 f取值0.5 书p175 Double dErr = Double( lLevelDouble ); pdCostCoeff0[ iScanPos ] = dErr * dErr * dTemp;//计算量化值为0时的代价 ( D ) d64BlockUncodedCost += pdCostCoeff0[ iScanPos ]; piDstCoeff[ uiBlkPos ] = uiMaxAbsLevel; if ( uiMaxAbsLevel > 0 && iLastScanPos < 0 ) { iLastScanPos = iScanPos;//最后一个非零系数的位置 uiCtxSet = (iScanPos < SCAN_SET_SIZE || eTType!=TEXT_LUMA) ? 0 : 2; iCGLastScanPos = iCGScanPos; } //******************************************** // 2.根据RDO准则 得到最优量化值 //******************************************** if ( iLastScanPos >= 0 ) { //===== coefficient level estimation ===== UInt uiLevel; UInt uiOneCtx = 4 * uiCtxSet + c1; UInt uiAbsCtx = uiCtxSet + c2; if( iScanPos == iLastScanPos )//当前元素是最后一个非零系数 { uiLevel = xGetCodedLevel( pdCostCoeff[ iScanPos ], pdCostCoeff0[ iScanPos ], pdCostSig[ iScanPos ], lLevelDouble, uiMaxAbsLevel, 0, uiOneCtx, uiAbsCtx, uiGoRiceParam, c1Idx, c2Idx, iQBits, dTemp, 1 );//选择最优QP 存放在uiLevel中 } else { UInt uiPosY = uiBlkPos >> uiLog2BlkSize; UInt uiPosX = uiBlkPos - ( uiPosY << uiLog2BlkSize ); UShort uiCtxSig = getSigCtxInc( patternSigCtx, uiScanIdx, uiPosX, uiPosY, uiLog2BlkSize, eTType ); uiLevel = xGetCodedLevel( pdCostCoeff[ iScanPos ], pdCostCoeff0[ iScanPos ], pdCostSig[ iScanPos ], lLevelDouble, uiMaxAbsLevel, uiCtxSig, uiOneCtx, uiAbsCtx, uiGoRiceParam, c1Idx, c2Idx, iQBits, dTemp, 0 ); sigRateDelta[ uiBlkPos ] = m_pcEstBitsSbac->significantBits[ uiCtxSig ][ 1 ] - m_pcEstBitsSbac->significantBits[ uiCtxSig ][ 0 ];//标志位码率的差值 } deltaU[ uiBlkPos ] = (lLevelDouble - ((Int)uiLevel << iQBits)) >> (iQBits-8); if( uiLevel > 0 )//lamda * R { Int rateNow = xGetICRate( uiLevel, uiOneCtx, uiAbsCtx, uiGoRiceParam, c1Idx, c2Idx ); rateIncUp [ uiBlkPos ] = xGetICRate( uiLevel+1, uiOneCtx, uiAbsCtx, uiGoRiceParam, c1Idx, c2Idx ) - rateNow; rateIncDown [ uiBlkPos ] = xGetICRate( uiLevel-1, uiOneCtx, uiAbsCtx, uiGoRiceParam, c1Idx, c2Idx ) - rateNow; } else // uiLevel == 0 { rateIncUp [ uiBlkPos ] = m_pcEstBitsSbac->m_greaterOneBits[ uiOneCtx ][ 0 ]; } piDstCoeff[ uiBlkPos ] = uiLevel; d64BaseCost += pdCostCoeff [ iScanPos ]; baseLevel = (c1Idx < C1FLAG_NUMBER) ? (2 + (c2Idx < C2FLAG_NUMBER)) : 1; if( uiLevel >= baseLevel ) { if(uiLevel > 3*(1<<uiGoRiceParam)) { uiGoRiceParam = min<UInt>(uiGoRiceParam+ 1, 4); } } if ( uiLevel >= 1) { c1Idx ++; } //===== update bin model ===== if( uiLevel > 1 ) { c1 = 0; c2 += (c2 < 2); c2Idx ++; } else if( (c1 < 3) && (c1 > 0) && uiLevel) { c1++; } //===== context set update ===== if( ( iScanPos % SCAN_SET_SIZE == 0 ) && ( iScanPos > 0 ) ) { c2 = 0; uiGoRiceParam = 0; c1Idx = 0; c2Idx = 0; uiCtxSet = (iScanPos == SCAN_SET_SIZE || eTType!=TEXT_LUMA) ? 0 : 2; if( c1 == 0 ) { uiCtxSet++; } c1 = 1; } } else { d64BaseCost += pdCostCoeff0[ iScanPos ]; } rdStats.d64SigCost += pdCostSig[ iScanPos ]; if (iScanPosinCG == 0 ) { rdStats.d64SigCost_0 = pdCostSig[ iScanPos ]; } if (piDstCoeff[ uiBlkPos ] ) { uiSigCoeffGroupFlag[ uiCGBlkPos ] = 1; rdStats.d64CodedLevelandDist += pdCostCoeff[ iScanPos ] - pdCostSig[ iScanPos ]; rdStats.d64UncodedDist += pdCostCoeff0[ iScanPos ]; if ( iScanPosinCG != 0 ) { rdStats.iNNZbeforePos0++; } } } //end for (iScanPosinCG) //******************************************** // 3.根据RDO准则决定是否将系数组块(CG)量化为全零组 //******************************************** if (iCGLastScanPos >= 0) { if( iCGScanPos )//对非第一个4x4块进行处理 { if (uiSigCoeffGroupFlag[ uiCGBlkPos ] == 0) { UInt uiCtxSig = getSigCoeffGroupCtxInc( uiSigCoeffGroupFlag, uiCGPosX, uiCGPosY, uiWidth, uiHeight); d64BaseCost += xGetRateSigCoeffGroup(0, uiCtxSig) - rdStats.d64SigCost;; pdCostCoeffGroupSig[ iCGScanPos ] = xGetRateSigCoeffGroup(0, uiCtxSig); } else { if (iCGScanPos < iCGLastScanPos) //skip the last coefficient group, which will be handled together with last position below. { if ( rdStats.iNNZbeforePos0 == 0 ) { d64BaseCost -= rdStats.d64SigCost_0; rdStats.d64SigCost -= rdStats.d64SigCost_0; } // rd-cost if SigCoeffGroupFlag = 0, initialization Double d64CostZeroCG = d64BaseCost; // add SigCoeffGroupFlag cost to total cost UInt uiCtxSig = getSigCoeffGroupCtxInc( uiSigCoeffGroupFlag, uiCGPosX, uiCGPosY, uiWidth, uiHeight); if (iCGScanPos < iCGLastScanPos) { d64BaseCost += xGetRateSigCoeffGroup(1, uiCtxSig); d64CostZeroCG += xGetRateSigCoeffGroup(0, uiCtxSig); pdCostCoeffGroupSig[ iCGScanPos ] = xGetRateSigCoeffGroup(1, uiCtxSig); } // try to convert the current coeff group from non-zero to all-zero d64CostZeroCG += rdStats.d64UncodedDist; // distortion for resetting non-zero levels to zero levels d64CostZeroCG -= rdStats.d64CodedLevelandDist; // distortion and level cost for keeping all non-zero levels d64CostZeroCG -= rdStats.d64SigCost; // sig cost for all coeffs, including zero levels and non-zerl levels // if we can save cost, change this block to all-zero block if ( d64CostZeroCG < d64BaseCost ) { uiSigCoeffGroupFlag[ uiCGBlkPos ] = 0; d64BaseCost = d64CostZeroCG; if (iCGScanPos < iCGLastScanPos) { pdCostCoeffGroupSig[ iCGScanPos ] = xGetRateSigCoeffGroup(0, uiCtxSig); } // reset coeffs to 0 in this block for (Int iScanPosinCG = uiCGSize-1; iScanPosinCG >= 0; iScanPosinCG--) { iScanPos = iCGScanPos*uiCGSize + iScanPosinCG; UInt uiBlkPos = scan[ iScanPos ]; if (piDstCoeff[ uiBlkPos ]) { piDstCoeff [ uiBlkPos ] = 0; pdCostCoeff[ iScanPos ] = pdCostCoeff0[ iScanPos ]; pdCostSig [ iScanPos ] = 0; } } } // end if ( d64CostAllZeros < d64BaseCost ) } } // end if if (uiSigCoeffGroupFlag[ uiCGBlkPos ] == 0) } else { uiSigCoeffGroupFlag[ uiCGBlkPos ] = 1; } } } //end for (iCGScanPos) //******************************************** // 4.根据RDO准则确定当前TU的最后一个非零系数的位置 //******************************************** //===== estimate last position ===== if ( iLastScanPos < 0 )//该块为全零块 { return; } Double d64BestCost = 0; Int ui16CtxCbf = 0; Int iBestLastIdxP1 = 0; if( !pcCU->isIntra( uiAbsPartIdx ) && eTType == TEXT_LUMA && pcCU->getTransformIdx( uiAbsPartIdx ) == 0 )//帧间亮度块 变换系数为零???? { ui16CtxCbf = 0; d64BestCost = d64BlockUncodedCost + xGetICost( m_pcEstBitsSbac->blockRootCbpBits[ ui16CtxCbf ][ 0 ] );//D + lamda * R d64BaseCost += xGetICost( m_pcEstBitsSbac->blockRootCbpBits[ ui16CtxCbf ][ 1 ] ); } else { ui16CtxCbf = pcCU->getCtxQtCbf( eTType, pcCU->getTransformIdx( uiAbsPartIdx ) ); ui16CtxCbf = ( eTType ? TEXT_CHROMA : eTType ) * NUM_QT_CBF_CTX + ui16CtxCbf; d64BestCost = d64BlockUncodedCost + xGetICost( m_pcEstBitsSbac->blockCbpBits[ ui16CtxCbf ][ 0 ] ); d64BaseCost += xGetICost( m_pcEstBitsSbac->blockCbpBits[ ui16CtxCbf ][ 1 ] ); } Bool bFoundLast = false; for (Int iCGScanPos = iCGLastScanPos; iCGScanPos >= 0; iCGScanPos--)//遍历所有的系数快 { UInt uiCGBlkPos = scanCG[ iCGScanPos ];//不同扫描方式位置对应表 d64BaseCost -= pdCostCoeffGroupSig [ iCGScanPos ]; if (uiSigCoeffGroupFlag[ uiCGBlkPos ]) { for (Int iScanPosinCG = uiCGSize-1; iScanPosinCG >= 0; iScanPosinCG--)//遍历块中所有系数 { iScanPos = iCGScanPos*uiCGSize + iScanPosinCG; if (iScanPos > iLastScanPos) continue;//当前系数在最后一个非零系数之后 UInt uiBlkPos = scan[iScanPos]; if( piDstCoeff[ uiBlkPos ] )//当前系数非零 { UInt uiPosY = uiBlkPos >> uiLog2BlkSize; UInt uiPosX = uiBlkPos - ( uiPosY << uiLog2BlkSize ); Double d64CostLast = uiScanIdx == SCAN_VER ? xGetRateLast( uiPosY, uiPosX ) : xGetRateLast( uiPosX, uiPosY );//计算当前系数为最后一个非零系数的代价 Double totalCost = d64BaseCost + d64CostLast - pdCostSig[ iScanPos ];//D + lamda * R if( totalCost < d64BestCost )//? { iBestLastIdxP1 = iScanPos + 1;//iScanPos从0开始,因此需要+1 d64BestCost = totalCost; } if( piDstCoeff[ uiBlkPos ] > 1 )//系数 >= 2 结束循环 { bFoundLast = true; break; } d64BaseCost -= pdCostCoeff[ iScanPos ]; d64BaseCost += pdCostCoeff0[ iScanPos ]; } else { d64BaseCost -= pdCostSig[ iScanPos ]; } } //end for if (bFoundLast) { break; } } // end if (uiSigCoeffGroupFlag[ uiCGBlkPos ]) } // end for for ( Int scanPos = 0; scanPos < iBestLastIdxP1; scanPos++ )//从第一个系数到最后一个非零系数遍历 { Int blkPos = scan[ scanPos ]; Int level = piDstCoeff[ blkPos ]; uiAbsSum += level; piDstCoeff[ blkPos ] = ( plSrcCoeff[ blkPos ] < 0 ) ? -level : level; } //===== clean uncoded coefficients ===== for ( Int scanPos = iBestLastIdxP1; scanPos <= iLastScanPos; scanPos++ )//遍历原本最后一个非零系数和最佳的最后一个非零系数之间的系数 { piDstCoeff[ scan[ scanPos ] ] = 0; } //******************************************** // 5.符号数据隐藏(sign data hiding)----熵编码 //******************************************** if( pcCU->getSlice()->getPPS()->getSignHideFlag() && uiAbsSum>=2) { Int64 rdFactor = (Int64) ( g_invQuantScales[m_cQP.rem()] * g_invQuantScales[m_cQP.rem()] * (1<<(2*m_cQP.m_iPer)) / m_dLambda / 16 / (1<<DISTORTION_PRECISION_ADJUSTMENT(2*(uiBitDepth-8))) + 0.5); Int lastCG = -1; Int absSum = 0 ; Int n ; for( Int subSet = (uiWidth*uiHeight-1) >> LOG2_SCAN_SET_SIZE; subSet >= 0; subSet-- ) { Int subPos = subSet << LOG2_SCAN_SET_SIZE; Int firstNZPosInCG=SCAN_SET_SIZE , lastNZPosInCG=-1 ; absSum = 0 ; for(n = SCAN_SET_SIZE-1; n >= 0; --n ) { if( piDstCoeff[ scan[ n + subPos ]] ) { lastNZPosInCG = n; break; } } for(n = 0; n <SCAN_SET_SIZE; n++ ) { if( piDstCoeff[ scan[ n + subPos ]] ) { firstNZPosInCG = n; break; } } for(n = firstNZPosInCG; n <=lastNZPosInCG; n++ ) { absSum += piDstCoeff[ scan[ n + subPos ]]; } if(lastNZPosInCG>=0 && lastCG==-1) { lastCG = 1; } if( lastNZPosInCG-firstNZPosInCG>=SBH_THRESHOLD ) { UInt signbit = (piDstCoeff[scan[subPos+firstNZPosInCG]]>0?0:1); if( signbit!=(absSum&0x1) ) // hide but need tune { // calculate the cost Int64 minCostInc = MAX_INT64, curCost=MAX_INT64; Int minPos =-1, finalChange=0, curChange=0; for( n = (lastCG==1?lastNZPosInCG:SCAN_SET_SIZE-1) ; n >= 0; --n ) { UInt uiBlkPos = scan[ n + subPos ]; if(piDstCoeff[ uiBlkPos ] != 0 ) { Int64 costUp = rdFactor * ( - deltaU[uiBlkPos] ) + rateIncUp[uiBlkPos] ; Int64 costDown = rdFactor * ( deltaU[uiBlkPos] ) + rateIncDown[uiBlkPos] - ((abs(piDstCoeff[uiBlkPos]) == 1) ? sigRateDelta[uiBlkPos] : 0); if(lastCG==1 && lastNZPosInCG==n && abs(piDstCoeff[uiBlkPos])==1) { costDown -= (4<<15) ; } if(costUp<costDown) { curCost = costUp; curChange = 1 ; } else { curChange = -1 ; if(n==firstNZPosInCG && abs(piDstCoeff[uiBlkPos])==1) { curCost = MAX_INT64 ; } else { curCost = costDown ; } } } else { curCost = rdFactor * ( - (abs(deltaU[uiBlkPos])) ) + (1<<15) + rateIncUp[uiBlkPos] + sigRateDelta[uiBlkPos] ; curChange = 1 ; if(n<firstNZPosInCG) { UInt thissignbit = (plSrcCoeff[uiBlkPos]>=0?0:1); if(thissignbit != signbit ) { curCost = MAX_INT64; } } } if( curCost<minCostInc) { minCostInc = curCost ; finalChange = curChange ; minPos = uiBlkPos ; } } if(piDstCoeff[minPos] == 32767 || piDstCoeff[minPos] == -32768) { finalChange = -1; } if(plSrcCoeff[minPos]>=0) { piDstCoeff[minPos] += finalChange ; } else { piDstCoeff[minPos] -= finalChange ; } } } if(lastCG==1) { lastCG=0 ; } } } }两化过程大概就包含这些,目前尚未看懂的有:
1.计算码率和失真的具体函数的实现(跟踪代码发现失真和码率的计算是查表所得,也找到了对应的表的初始化与赋值(estimateBit()函数中),所以问题就在于还没看懂那些表中值的意义及其得到的方法与过程)
2.从最上层一层一层传递下来的有关量化部分的相关参数的赋值,由于我是直接看的量化部分,对HM中其他部分的代码没有怎么看,因此参数赋值与传递部分尚未研究。
PS:看代码过程中,算法主要参考了万帅和杨付正写的《新一代高效视频编码H.265/HEVC:原理、标准与实现》以及在网上搜到的相关知识点。
放一张自己在书上做的笔记,以便于理解程序: