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


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

    #if RATE_CONTROL_LAMBDA_DOMAIN
          Double oldLambda = m_pcRdCost->getLambda();
          if ( m_pcCfg->getUseRateCtrl() )
          {
            Int estQP        = pcSlice->getSliceQp();
            Double estLambda = -1.0;
            Double bpp       = -1.0;
    
    #if M0036_RC_IMPROVEMENT
            if ( ( rpcPic->getSlice( 0 )->getSliceType() == I_SLICE && m_pcCfg->getForceIntraQP() ) || !m_pcCfg->getLCULevelRC() )
    #else
            if ( rpcPic->getSlice( 0 )->getSliceType() == I_SLICE || !m_pcCfg->getLCULevelRC() )
    #endif
            { //!< 如果当前slice为I slice或者不进行LCU level RC,则LCU直接使用当前slice的QP
              estQP = pcSlice->getSliceQp();
            }
            else
            {
    #if RATE_CONTROL_INTRA
              bpp = m_pcRateCtrl->getRCPic()->getLCUTargetBpp(pcSlice->getSliceType());
              if ( rpcPic->getSlice( 0 )->getSliceType() == I_SLICE)
              {
                estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambdaAndQP(bpp, pcSlice->getSliceQp(), &estQP);
              }
              else
              {
                estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambda( bpp );
                estQP     = m_pcRateCtrl->getRCPic()->getLCUEstQP    ( estLambda, pcSlice->getSliceQp() );
              }
    #else
              bpp       = m_pcRateCtrl->getRCPic()->getLCUTargetBpp();
              estLambda = m_pcRateCtrl->getRCPic()->getLCUEstLambda( bpp );
              estQP     = m_pcRateCtrl->getRCPic()->getLCUEstQP    ( estLambda, pcSlice->getSliceQp() );
    #endif
    
              estQP     = Clip3( -pcSlice->getSPS()->getQpBDOffsetY(), MAX_QP, estQP );
    
              m_pcRdCost->setLambda(estLambda);
    #if M0036_RC_IMPROVEMENT
    #if RDOQ_CHROMA_LAMBDA
              // set lambda for RDOQ
              Double weight=m_pcRdCost->getChromaWeight();
              m_pcTrQuant->setLambda( estLambda, estLambda / weight );
    #else
              m_pcTrQuant->setLambda( estLambda );
    #endif
    #endif
            }
    
            m_pcRateCtrl->setRCQP( estQP );
            pcCU->getSlice()->setSliceQpBase( estQP ); //!< 设置编码时使用的QP值
          }
    #endif


     

    #if RATE_CONTROL_INTRA
    Double TEncRCPic::getLCUTargetBpp(SliceType eSliceType)  
    #else 
    Double TEncRCPic::getLCUTargetBpp() //!< LCU level bit allocation
    #endif
    {
      Int   LCUIdx    = getLCUCoded(); //!< 未编码LCU数
      Double bpp      = -1.0;
      Int avgBits     = 0;
    #if !M0036_RC_IMPROVEMENT
      Double totalMAD = -1.0;
      Double MAD      = -1.0;
    #endif
    
    #if RATE_CONTROL_INTRA
      if (eSliceType == I_SLICE){
        Int noOfLCUsLeft = m_numberOfLCU - LCUIdx + 1;
        Int bitrateWindow = min(4,noOfLCUsLeft);
        Double MAD      = getLCU(LCUIdx).m_costIntra;
    
        if (m_remainingCostIntra > 0.1 )
        {
          Double weightedBitsLeft = (m_bitsLeft*bitrateWindow+(m_bitsLeft-getLCU(LCUIdx).m_targetBitsLeft)*noOfLCUsLeft)/(Double)bitrateWindow;
          avgBits = Int( MAD*weightedBitsLeft/m_remainingCostIntra );
        }
        else
        {
          avgBits = Int( m_bitsLeft / m_LCULeft );
        }
        m_remainingCostIntra -= MAD;
      }
      else
      {
    #endif
    #if M0036_RC_IMPROVEMENT
      Double totalWeight = 0;
      for ( Int i=LCUIdx; i<m_numberOfLCU; i++ )
      {
        totalWeight += m_LCUs[i].m_bitWeight;
      }
      Int realInfluenceLCU = min( g_RCLCUSmoothWindowSize, getLCULeft() );
      avgBits = (Int)( m_LCUs[LCUIdx].m_bitWeight - ( totalWeight - m_bitsLeft ) / realInfluenceLCU + 0.5 );
    #else
      if ( m_lastPicture == NULL ) //!< 如果前一帧图像为空,则直接求平均比特数
      {
        avgBits = Int( m_bitsLeft / m_LCULeft );
      }
      else //!< 利用前一帧保存下来的MAD求出当前LCU对应的权重,注意:此处的MAD已经进行过K0103中公式的两个处理了。
      {
        MAD = m_lastPicture->getLCU(LCUIdx).m_MAD;
        totalMAD = m_lastPicture->getTotalMAD();
        for ( Int i=0; i<LCUIdx; i++ )
        {
          totalMAD -= m_lastPicture->getLCU(i).m_MAD;
        }
    
        if ( totalMAD > 0.1 )
        {
          avgBits = Int( m_bitsLeft * MAD / totalMAD );
        }
        else
        {
          avgBits = Int( m_bitsLeft / m_LCULeft );
        }
      }
    #endif
    #if RATE_CONTROL_INTRA
      }
    #endif
    
      if ( avgBits < 1 )
      {
        avgBits = 1;
      }
    
      bpp = ( Double )avgBits/( Double )m_LCUs[ LCUIdx ].m_numberOfPixel;
      m_LCUs[ LCUIdx ].m_targetBits = avgBits;
    
      return bpp;
    }
    
    Double TEncRCPic::getLCUEstLambda( Double bpp )
    {
      Int   LCUIdx = getLCUCoded();
      Double alpha;
      Double beta;
      if ( m_encRCSeq->getUseLCUSeparateModel() ) //!< enable LCU level RC
      {
        alpha = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_alpha;
        beta  = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_beta;
      }
      else //!< 只进行picture level 的 RC,故alpha,beta使用的是picture level的值
      {
        alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha;
        beta  = m_encRCSeq->getPicPara( m_frameLevel ).m_beta;
      }
    
      Double estLambda = alpha * pow( bpp, beta );
      //for Lambda clip, picture level clip
      Double clipPicLambda = m_estPicLambda;
    
      //for Lambda clip, LCU level clip
      Double clipNeighbourLambda = -1.0;
      for ( int i=LCUIdx - 1; i>=0; i-- )
      {
        if ( m_LCUs[i].m_lambda > 0 )
        {
          clipNeighbourLambda = m_LCUs[i].m_lambda;
          break;
        }
      }
      //!< 在K0103的section 3.2中进行了定义
      if ( clipNeighbourLambda > 0.0 )
      {
        estLambda = Clip3( clipNeighbourLambda * pow( 2.0, -1.0/3.0 ), clipNeighbourLambda * pow( 2.0, 1.0/3.0 ), estLambda );
      }  
    
      if ( clipPicLambda > 0.0 )
      {
        estLambda = Clip3( clipPicLambda * pow( 2.0, -2.0/3.0 ), clipPicLambda * pow( 2.0, 2.0/3.0 ), estLambda );
      }
      else
      {
        estLambda = Clip3( 10.0, 1000.0, estLambda );
      }
    
      if ( estLambda < 0.1 )
      {
        estLambda = 0.1;
      }
    
      return estLambda;
    }
    
    Int TEncRCPic::getLCUEstQP( Double lambda, Int clipPicQP )
    {
      Int LCUIdx = getLCUCoded();
      Int estQP = Int( 4.2005 * log( lambda ) + 13.7122 + 0.5 );
    
      //for Lambda clip, LCU level clip
      Int clipNeighbourQP = g_RCInvalidQPValue;
      for ( int i=LCUIdx - 1; i>=0; i-- )
      {
        if ( (getLCU(i)).m_QP > g_RCInvalidQPValue )
        {
          clipNeighbourQP = getLCU(i).m_QP;
          break;
        }
      } 
    
      //!< 在K0103的section 3.2中进行了定义
      if ( clipNeighbourQP > g_RCInvalidQPValue )
      {
        estQP = Clip3( clipNeighbourQP - 1, clipNeighbourQP + 1, estQP );
      }
    
      estQP = Clip3( clipPicQP - 2, clipPicQP + 2, estQP );
    
      return estQP;
    }


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

  • 相关阅读:
    Java入门——数组和方法
    Java入门——选择与循环语句
    Java入门——面向对象基础
    十天学会Oracle数据库(Day2)
    Java入门——理解面向对象:UML设计
    十天学会Oracle数据库(Day1)
    Codeforces Round #482 (Div. 2) :B
    Codeforces Round #482 (Div. 2) :C
    Codeforces Round #490 (Div. 3) :F. Cards and Joy(组合背包)
    POJ-2155:Matrix(二维树状数祖)
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3303949.html
Copyright © 2020-2023  润新知