您现在的位置:首页 >> 前端 >> 内容

X265:HM_15.0量化部分代码理解

时间:2016/11/4 9:49:00 点击:

  核心提示:最近刚接触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:原理、标准与实现》以及在网上搜到的相关知识点。

放一张自己在书上做的笔记,以便于理解程序:

X265:HM_15.0量化部分代码理解

 

Tags:X2 26 65 5H 
作者:网络 来源:ftlisdcr的博