HM16.9代码阅读-帧内预测

先推荐几篇帧内预测的文章:
https://blog.csdn.net/shaqoneal/article/details/44856469
https://blog.csdn.net/nb_vol_1/article/details/51144828
https://blog.csdn.net/cpp12341234/article/details/46043615
https://blog.csdn.net/m0_37579288/article/details/79153952
和HEVC_CJL大神的帧内预测系列https://blog.csdn.net/HEVC_CJL/article/details/8175721
下面写一下我对HM16.9帧内预测部分代码的理解。
编码的入口函数是encmain.cpp文件中的main函数,调用encode函数进行编码

cTAppEncTop.encode();

TAppEncTop::encode函数的处理流程是读入m_iGOPSize大小的帧统一处理,调用下面函数

m_cTEncTop.encode( bEos, flush ? 0 : pcPicYuvOrg, flush ? 0 : &cPicYuvTrueOrg, snrCSC, m_cListPicYuvRec, outputAccessUnits, iNumEncoded );//帧编码

TEncTop::encode函数调用下面函数处理GOP:

// compress GOP
m_cGOPEncoder.compressGOP(m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut, accessUnitsOut, false, false, snrCSC, m_printFrameMSE);

TEncGOP::compressGOP函数的处理流程是遍历GOP中的每一帧,处理每一帧的Slice:

m_pcSliceEncoder->compressSlice   ( pcPic, false, false );

TEncSlice::compressSlice函数是对Slice中的每一个CTU(64x64)进行处理:

for( UInt ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ++ctuTsAddr )
  {
   ...
    // initialize CTU encoder
    TComDataCU* pCtu = pcPic->getCtu( ctuRsAddr );
    pCtu->initCtu( pcPic, ctuRsAddr );
    ...
    // run CTU trial encoder
    m_pcCuEncoder->compressCtu( pCtu );
    ...
    m_uiPicTotalBits += pCtu->getTotalBits();
    m_dPicRdCost     += pCtu->getTotalCost();
    m_uiPicDist      += pCtu->getTotalDistortion();
  }

TEncCu::compressCtu函数就是调用xCompressCU函数处理CU,其中最优的CU划分存储在m_ppcBestCU[0]变量中:

xCompressCU( m_ppcBestCU[0], m_ppcTempCU[0], 0 DEBUG_STRING_PASS_INTO(sDebug) );

对于帧内预测,TEncCu::xCompressCU函数的处理流程是先判断当前CU是否到边界,如果不到,则进行帧内预测的处理;然后判断当前CU是否可以继续划分CU,若可以,则划分成4个CU,递归调用xCompressCU函数进行处理:

Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, const UInt uiDepth DEBUG_STRING_FN_DECLARE(sDebug_), PartSize eParentPartSize )
{
//变量定义和初始化省略
...
//获取当前CU的左、右下像素位置,用于判断是否到达边界
  const UInt uiLPelX   = rpcBestCU->getCUPelX();
  const UInt uiRPelX   = uiLPelX + rpcBestCU->getWidth(0)  - 1;//m_puhWidth[uiIdx]
  const UInt uiTPelY   = rpcBestCU->getCUPelY();
  const UInt uiBPelY   = uiTPelY + rpcBestCU->getHeight(0) - 1;
  const UInt uiWidth   = rpcBestCU->getWidth(0);
  //各种控制判断处理,省略
  ...
  //判断是否到边界
  const Bool bBoundary = !( uiRPelX < sps.getPicWidthInLumaSamples() && uiBPelY < sps.getPicHeightInLumaSamples() );

  if ( !bBoundary )
  {
  ...
      // do inter modes, SKIP and 2Nx2N 帧间模式省略
      if( rpcBestCU->getSlice()->getSliceType() != I_SLICE )
      {
      ...
    }
    ...
        // do normal intra modes帧内模式
        // speedup for inter frames
        if((rpcBestCU->getSlice()->getSliceType() == I_SLICE)                                        ||
            ((!m_pcEncCfg->getDisableIntraPUsInInterSlices()) && (
              (rpcBestCU->getCbf( 0, COMPONENT_Y  ) != 0)                                            ||
             ((rpcBestCU->getCbf( 0, COMPONENT_Cb ) != 0) && (numberValidComponents > COMPONENT_Cb)) ||
             ((rpcBestCU->getCbf( 0, COMPONENT_Cr ) != 0) && (numberValidComponents > COMPONENT_Cr))  // avoid very complex intra if it is unlikely
            )))//判断是否进行帧内模式
        {
          xCheckRDCostIntra( rpcBestCU, rpcTempCU, SIZE_2Nx2N DEBUG_STRING_PASS_INTO(sDebug) );//帧内模式处理入口,2Nx2N的PU划分
          rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
          if( uiDepth == sps.getLog2DiffMaxMinCodingBlockSize())//如果当前CU的深度等于CB的最大块和最小块的差距,正常是3
          {
            if( rpcTempCU->getWidth(0) > ( 1 << sps.getQuadtreeTULog2MinSize() ) )//若当前CU的长大于最小TU块长度,正常是4
            {
              xCheckRDCostIntra( rpcBestCU, rpcTempCU, SIZE_NxN DEBUG_STRING_PASS_INTO(sDebug)   );//进行NxN的PU划分进行处理
              rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
            }
          }
        }
    ...           
  }
...
//判断子块是否到边界
  const Bool bSubBranch = bBoundary || !( m_pcEncCfg->getUseEarlyCU() && rpcBestCU->getTotalCost()!=MAX_DOUBLE && rpcBestCU->isSkipped(0) );
//若当前CU可以继续划分
  if( bSubBranch && uiDepth < sps.getLog2DiffMaxMinCodingBlockSize() && (!getFastDeltaQp() || uiWidth > fastDeltaQPCuMaxSize || bBoundary))
  {
...
//划分成4个CU继续调用 xCompressCU函数递归
      for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 4; uiPartUnitIdx++ )
      {
          if ( !(rpcBestCU->getTotalCost()!=MAX_DOUBLE && rpcBestCU->isInter(0)) )
          {
            xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth DEBUG_STRING_PASS_INTO(sChild), NUMBER_OF_PART_SIZES );
          }
          else
          {
            xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth DEBUG_STRING_PASS_INTO(sChild), rpcBestCU->getPartitionSize(0) );
          }
          DEBUG_STRING_APPEND(sTempDebug, sChild)
#else
          xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth );
  ...        
}
...
}
...
}

TEncCu::xCheckRDCostIntra函数是帧内预测的入口函数,它调用estIntraPredLumaQT函数进行亮度分量的预测、变换、量化和编码;调用estIntraPredChromaQT函数进行色度分量的处理;最后调用xCheckBestMode函数check最优的模式:

Void TEncCu::xCheckRDCostIntra( TComDataCU *&rpcBestCU,
                                TComDataCU *&rpcTempCU,
                                PartSize     eSize
                                DEBUG_STRING_FN_DECLARE(sDebug) )
{
  DEBUG_STRING_NEW(sTest)

  if(getFastDeltaQp())//默认false
  {
    const TComSPS &sps=*(rpcTempCU->getSlice()-&
  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值