HEVC码率控制浅析——HM代码阅读之四

继续分析第一篇提到的compressSlice中对LCU的RC参数初始化:

[cpp]  view plain copy
  1. #if RATE_CONTROL_LAMBDA_DOMAIN  
  2.       Double oldLambda = m_pcRdCost->getLambda();  
  3.       if ( m_pcCfg->getUseRateCtrl() )  
  4.       {  
  5.         Int estQP        = pcSlice->getSliceQp();  
  6.         Double estLambda = -1.0;  
  7.         Double bpp       = -1.0;  
  8.   
  9. #if M0036_RC_IMPROVEMENT  
  10.         if ( ( rpcPic->getSlice( 0 )->getSliceType() == I_SLICE && m_pcCfg->getForceIntraQP() ) || !m_pcCfg->getLCULevelRC() )  
  11. #else  
  12.         if ( rpcPic->getSlice( 0 )->getSliceType() == I_SLICE || !m_pcCfg->getLCULevelRC() )  
  13. #endif  
  14.         { //!< 如果当前slice为I slice或者不进行LCU level RC,则LCU直接使用当前slice的QP  
  15.           estQP = pcSlice->getSliceQp();  
  16.         }  
  17.         else  
  18.         {  
  19. #if RATE_CONTROL_INTRA  
  20.           bpp = m_pcRateCtrl->getRCPic()->getLCUTargetBpp(pcSlice->getSliceType());  
  21.           if ( rpcPic->getSlice( 0 )->getSliceType() == I_SLICE)  
  22.           {  
  23.             estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambdaAndQP(bpp, pcSlice->getSliceQp(), &estQP);  
  24.           }  
  25.           else  
  26.           {  
  27.             estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambda( bpp );  
  28.             estQP     = m_pcRateCtrl->getRCPic()->getLCUEstQP    ( estLambda, pcSlice->getSliceQp() );  
  29.           }  
  30. #else  
  31.           bpp       = m_pcRateCtrl->getRCPic()->getLCUTargetBpp();  
  32.           estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambda( bpp );  
  33.           estQP     = m_pcRateCtrl->getRCPic()->getLCUEstQP    ( estLambda, pcSlice->getSliceQp() );  
  34. #endif  
  35.   
  36.           estQP     = Clip3( -pcSlice->getSPS()->getQpBDOffsetY(), MAX_QP, estQP );  
  37.   
  38.           m_pcRdCost->setLambda(estLambda);  
  39. #if M0036_RC_IMPROVEMENT  
  40. #if RDOQ_CHROMA_LAMBDA  
  41.           // set lambda for RDOQ  
  42.           Double weight=m_pcRdCost->getChromaWeight();  
  43.           m_pcTrQuant->setLambda( estLambda, estLambda / weight );  
  44. #else  
  45.           m_pcTrQuant->setLambda( estLambda );  
  46. #endif  
  47. #endif  
  48.         }  
  49.   
  50.         m_pcRateCtrl->setRCQP( estQP );  
  51.         pcCU->getSlice()->setSliceQpBase( estQP ); //!< 设置编码时使用的QP值  
  52.       }  
  53. #endif  


 compressSlice子函数getLCUTargetBpp()

[cpp]  view plain copy
  1. #if RATE_CONTROL_INTRA  
  2. Double TEncRCPic::getLCUTargetBpp(SliceType eSliceType)    
  3. #else   
  4. Double TEncRCPic::getLCUTargetBpp() //!< LCU level bit allocation  
  5. #endif  
  6. {  
  7.   Int   LCUIdx    = getLCUCoded(); //!< 未编码LCU数  
  8.   Double bpp      = -1.0;  
  9.   Int avgBits     = 0;  
  10. #if !M0036_RC_IMPROVEMENT  
  11.   Double totalMAD = -1.0;  
  12.   Double MAD      = -1.0;  
  13. #endif  
  14.   
  15. #if RATE_CONTROL_INTRA  
  16.   if (eSliceType == I_SLICE){  
  17.     Int noOfLCUsLeft = m_numberOfLCU - LCUIdx + 1;  
  18.     Int bitrateWindow = min(4,noOfLCUsLeft);  
  19.     Double MAD      = getLCU(LCUIdx).m_costIntra;  
  20.   
  21.     if (m_remainingCostIntra > 0.1 )  
  22.     {  
  23.       Double weightedBitsLeft = (m_bitsLeft*bitrateWindow+(m_bitsLeft-getLCU(LCUIdx).m_targetBitsLeft)*noOfLCUsLeft)/(Double)bitrateWindow;  
  24.       avgBits = Int( MAD*weightedBitsLeft/m_remainingCostIntra );  
  25.     }  
  26.     else  
  27.     {  
  28.       avgBits = Int( m_bitsLeft / m_LCULeft );  
  29.     }  
  30.     m_remainingCostIntra -= MAD;  
  31.   }  
  32.   else  
  33.   {  
  34. #endif  
  35. #if M0036_RC_IMPROVEMENT  
  36.   Double totalWeight = 0;  
  37.   for ( Int i=LCUIdx; i<m_numberOfLCU; i++ )  
  38.   {  
  39.     totalWeight += m_LCUs[i].m_bitWeight;  
  40.   }  
  41.   Int realInfluenceLCU = min( g_RCLCUSmoothWindowSize, getLCULeft() );  
  42.   avgBits = (Int)( m_LCUs[LCUIdx].m_bitWeight - ( totalWeight - m_bitsLeft ) / realInfluenceLCU + 0.5 );  
  43. #else  
  44.   if ( m_lastPicture == NULL ) //!< 如果前一帧图像为空,则直接求平均比特数  
  45.   {  
  46.     avgBits = Int( m_bitsLeft / m_LCULeft );  
  47.   }  
  48.   else //!< 利用前一帧保存下来的MAD求出当前LCU对应的权重,注意:此处的MAD已经进行过K0103中公式的两个处理了。  
  49.   {  
  50.     MAD = m_lastPicture->getLCU(LCUIdx).m_MAD;  
  51.     totalMAD = m_lastPicture->getTotalMAD();  
  52.     for ( Int i=0; i<LCUIdx; i++ )  
  53.     {  
  54.       totalMAD -= m_lastPicture->getLCU(i).m_MAD;  
  55.     }  
  56.   
  57.     if ( totalMAD > 0.1 )  
  58.     {  
  59.       avgBits = Int( m_bitsLeft * MAD / totalMAD );  
  60.     }  
  61.     else  
  62.     {  
  63.       avgBits = Int( m_bitsLeft / m_LCULeft );  
  64.     }  
  65.   }  
  66. #endif  
  67. #if RATE_CONTROL_INTRA  
  68.   }  
  69. #endif  
  70.   
  71.   if ( avgBits < 1 )  
  72.   {  
  73.     avgBits = 1;  
  74.   }  
  75.   
  76.   bpp = ( Double )avgBits/( Double )m_LCUs[ LCUIdx ].m_numberOfPixel;  
  77.   m_LCUs[ LCUIdx ].m_targetBits = avgBits;  
  78.   
  79.   return bpp;  
  80. }  
  81.   

 compressSlice子函数getLCUEstLambda( Double bpp )
  1. Double TEncRCPic::getLCUEstLambda( Double bpp )  
  2. {  
  3.   Int   LCUIdx = getLCUCoded();  
  4.   Double alpha;  
  5.   Double beta;  
  6.   if ( m_encRCSeq->getUseLCUSeparateModel() ) //!< enable LCU level RC  
  7.   {  
  8.     alpha = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_alpha;  
  9.     beta  = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_beta;  
  10.   }  
  11.   else //!< 只进行picture level 的 RC,故alpha,beta使用的是picture level的值  
  12.   {  
  13.     alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha;  
  14.     beta  = m_encRCSeq->getPicPara( m_frameLevel ).m_beta;  
  15.   }  
  16.   
  17.   Double estLambda = alpha * pow( bpp, beta );  
  18.   //for Lambda clip, picture level clip  
  19.   Double clipPicLambda = m_estPicLambda;  
  20.   
  21.   //for Lambda clip, LCU level clip  
  22.   Double clipNeighbourLambda = -1.0;  
  23.   for ( int i=LCUIdx - 1; i>=0; i-- )  
  24.   {  
  25.     if ( m_LCUs[i].m_lambda > 0 )  
  26.     {  
  27.       clipNeighbourLambda = m_LCUs[i].m_lambda;  
  28.       break;  
  29.     }  
  30.   }  
  31.   //!< 在K0103的section 3.2中进行了定义  
  32.   if ( clipNeighbourLambda > 0.0 )  
  33.   {  
  34.     estLambda = Clip3( clipNeighbourLambda * pow( 2.0, -1.0/3.0 ), clipNeighbourLambda * pow( 2.0, 1.0/3.0 ), estLambda );  
  35.   }    
  36.   
  37.   if ( clipPicLambda > 0.0 )  
  38.   {  
  39.     estLambda = Clip3( clipPicLambda * pow( 2.0, -2.0/3.0 ), clipPicLambda * pow( 2.0, 2.0/3.0 ), estLambda );  
  40.   }  
  41.   else  
  42.   {  
  43.     estLambda = Clip3( 10.0, 1000.0, estLambda );  
  44.   }  
  45.   
  46.   if ( estLambda < 0.1 )  
  47.   {  
  48.     estLambda = 0.1;  
  49.   }  
  50.   
  51.   return estLambda;  
  52. }  
  53.   
 compressSlice子函数getLCUEstQP()
  1. Int TEncRCPic::getLCUEstQP( Double lambda, Int clipPicQP )  
  2. {  
  3.   Int LCUIdx = getLCUCoded();  
  4.   Int estQP = Int( 4.2005 * log( lambda ) + 13.7122 + 0.5 );  
  5.   
  6.   //for Lambda clip, LCU level clip  
  7.   Int clipNeighbourQP = g_RCInvalidQPValue;  
  8.   for ( int i=LCUIdx - 1; i>=0; i-- )  
  9.   {  
  10.     if ( (getLCU(i)).m_QP > g_RCInvalidQPValue )  
  11.     {  
  12.       clipNeighbourQP = getLCU(i).m_QP;  
  13.       break;  
  14.     }  
  15.   }   
  16.   
  17.   //!< 在K0103的section 3.2中进行了定义  
  18.   if ( clipNeighbourQP > g_RCInvalidQPValue )  
  19.   {  
  20.     estQP = Clip3( clipNeighbourQP - 1, clipNeighbourQP + 1, estQP );  
  21.   }  
  22.   
  23.   estQP = Clip3( clipPicQP - 2, clipPicQP + 2, estQP );  
  24.   
  25.   return estQP;  
  26. }  


至此,RC的初始化过程分析完毕,从之前几篇也能发现,其实看懂代码并不难,只要把提案看明白了,对整个流程熟悉,再把HM的框架搞清楚了,基本上就是照着提案找对应代码的事情了。但是,应该指出的是,这里仅仅只是浅显分析代码的含义,有关算法的深层内涵,比如为什么要这么做,这个值为什么要设置成这样等问题,需要在了解代码的基础上,进一步地仔细研究才行。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值