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的框架搞清楚了,基本上就是照着提案找对应代码的事情了。但是,应该指出的是,这里仅仅只是浅显分析代码的含义,有关算法的深层内涵,比如为什么要这么做,这个值为什么要设置成这样等问题,需要在了解代码的基础上,进一步地仔细研究才行。

 

你可能感兴趣的:(代码)