H.266代码学习:xRecurIntraCodingLumaQT函数

本文介绍了在转向H.266研究后,从HM转向JEM的过程中,对JEM7.0中的xRecurIntraCodingLumaQT函数的学习。该函数负责亮度帧内预测,包括CU、PU和TU的概念统一,以及EMT多核变换和KLT模板匹配的处理。文章详细分析了函数流程,包括TS模式和非TS模式的处理,并对比了JEM与HM的区别。
摘要由CSDN通过智能技术生成

目前实验室的研究方向全面转向了H.266,以后我也将由HM转向JEM,不再更新HEVC代码学习了。JEM相对于HM看起来繁杂很多,毕竟加了很多内容,但框架是一样的,建议看的时候和HM比对着看,我也会在这里记录JEM相对于HM的对比学习。这里使用的是JEM7.0。

如果有从看过我之前博客的同学们,会发现我近期更加注意版面了有木有?嘿嘿=.=,舒服了很多有没有。好吧,我承认,是我有强迫症。

今天就来看JEM中的xRecurIntraCodingLumaQT函数。在之前的 HEVC代码学习37:帧内预测代码整体学习 中已经提到estIntraPredLumaQT进行亮度帧内预测时,会调用xRecurIntraCodingLumaQT,是正式预测的入口函数,其中会完成变换、量化、率失真计算的工作。整体流程和HM中的xRecurIntraCodingQT相同,推荐阅读NB_vol_1大神的博客很详细,不过他所学习的HM版本较早,和现在的有区别。

JEM中与HM主要区别在于
1.在JEM中,统一了CU、PU和TU的概念,也就是说在完成CU划分之后不再进行PU和TU的划分。在HM中,xRecurIntraCodingQT会进行自调用来完成TU的划分,而在JEM中是没有进一步的TU划分的
2.增加了EMT多核变换和KLT的模板匹配部分的代码。

流程如下:
一、初始化参数,其中JEM中增加了checkTM,表示是否使用模板匹配。
二、检测bCheckFull是否为true,如果是true,执行1,否则执行2。
1.检测checkTransformSkip是否为true,如果是true,将使用TS模式,跳过变换步骤。
  (1)进行两次遍历,第一次将遍历numTrIdxCands个模式,第二次只遍历一次(这里遍历两次的意义我还不清楚,之后学习清楚之后会补充,如果有大神知道请留言给讲一下,在这先谢过了)。其中每一次遍历都会设置子块的EMT和TS的Flag,然后调用xIntraCodingTUBlock来进行亮度分量的预测、计算残差(没有变换步骤)、量化生成重构信号。
 (2)选取两次遍历中最优模式。
2.检测checkTransformSkip是否为false,则会进行变换。
 (1)遍历numTrIdxCands个模式调用xIntraCodingTUBlock来进行亮度分量的预测、计算残差并进行变换、量化生成重构信号。
 (2)选取最优模式。
三、使用TM,则调用xIntraCodingTUBlockTM进行模板匹配预测、计算残差进行变换(KLT可用)、量化。

代码太长进行了一些删减,分析如下:

Void
TEncSearch::xRecurIntraCodingLumaQT(TComYuv*    pcOrgYuv,
                                    TComYuv*    pcPredYuv,
                                    TComYuv*    pcResiYuv,
#if COM16_C806_LARGE_CTU
                                    Pel*        resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES],
#else
                                    Pel         resiLuma[NUMBER_OF_STORED_RESIDUAL_TYPES][MAX_CU_SIZE * MAX_CU_SIZE],
#endif
                                    Distortion& ruiDistY,
#if HHI_RQT_INTRA_SPEEDUP
                                    Bool        bCheckFirst,
#endif
                                    Double&     dRDCost,
                                    TComTU&     rTu
                                    DEBUG_STRING_FN_DECLARE(sDebug))
{
  TComDataCU   *pcCU          = rTu.getCU();        //当前CU
  const UInt    uiAbsPartIdx  = rTu.GetAbsPartIdxTU();      //分块索引
  const UInt    uiFullDepth   = rTu.GetTransformDepthTotal();
  const UInt    uiTrDepth     = rTu.GetTransformDepthRel(); 
#if JVET_C0024_QTBT
  Bool bCheckFull = true;
  Bool bCheckSplit = false;
  assert(uiAbsPartIdx ==0 && uiTrDepth==0);     //uiAbsPartIdx =0,uiTrDepth=0
  UInt uiWidth = pcCU->getWidth(uiAbsPartIdx);      //当前块宽度
  UInt uiHeight = pcCU->getHeight(uiAbsPartIdx);        //当前块高度

  UInt uiWIdx  = g_aucConvertToBit[ uiWidth ] ;     //bit表示的宽度
  UInt uiHIdx  = g_aucConvertToBit[ uiHeight ] ;        //bit表示的高度
#else
 // 删除默认不启用的代码
#endif

#if !COM16_C806_LARGE_CTU
// 删除默认不启用的代码
#endif

        Bool    bMaintainResidual[NUMBER_OF_STORED_RESIDUAL_TYPES];
        for (UInt residualTypeIndex = 0; residualTypeIndex < NUMBER_OF_STORED_RESIDUAL_TYPES; residualTypeIndex++)
        {
          bMaintainResidual[residualTypeIndex] = true; //assume true unless specified otherwise
        }

        bMaintainResidual[RESIDUAL_ENCODER_SIDE] = !(m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate());

#if COM16_C806_EMT
  UInt    uiSigNum;
#endif

#if HHI_RQT_INTRA_SPEEDUP
#if JVET_C0024_QTBT
  Int isIntraSlice = (pcCU->getSlice()->getSliceType() == I_SLICE);     //I Slice
#else
// 删除默认不启用的代码
#endif
#else
// 删除默认不启用的代码
#endif

#if COM16_C806_EMT && HHI_RQT_INTRA_SPEEDUP
  // Re-use the selected transform indexes in the previous call of xRecurIntraCodingQT
#if JVET_C0024_QTBT
  UInt    uiInitTrDepth  = 0;   //初始变换深度0
#else
  UInt    uiInitTrDepth     = pcCU->getPartitionSize(0) == SIZE_2Nx2N ? 0 : 1;
#endif
  UChar   ucSavedEmtTrIdx   = 0;
  Bool    bCheckInitTrDepth = false;
  static UInt uiInitAbsPartIdx;
  if ( uiTrDepth==uiInitTrDepth )   //uiTrDepth一定等于uiInitTrDepth啊?
  {
    uiInitAbsPartIdx = uiAbsPartIdx;
  }
  if ( !bCheckFirst && uiTrDepth==uiInitTrDepth )
  {
    ucSavedEmtTrIdx   = m_puhQTTempEmtTuIdx[uiAbsPartIdx-uiInitAbsPartIdx];
    bCheckInitTrDepth = true;
  }
#endif

#if JVET_C0024_QTBT
  assert(bCheckFull && !bCheckSplit);
#endif

  Double     dSingleCost                        = MAX_DOUBLE;       //初始代价取最大
  Distortion uiSingleDistLuma                   = 0;        //初始亮度失真为0
  UInt       uiSingleCbfLuma                    = 0;            
  Bool       checkTransformSkip  = pcCU->getSlice()->getPPS()->getUseTransformSkip();       //检测是否为TS模式
  Int        bestModeId[MAX_NUM_COMPONENT] = { 0, 0, 0};        //最优模式列表
#if COM16_C806_EMT
  UChar   bestTrIdx     = 0;        //最优变换索引
  UChar   nNumTrCands   = pcCU->getEmtCuFlag(uiAbsPartIdx) ? 4 : 1;     //EMT可用时,变换列表候选数为4,否则为1
  Bool    bAllIntra     = (m_pcEncCfg->getIntraPeriod()==1);
#endif

#if JVET_C0024_QTBT
  //检测是否使用TS模式
  checkTransformSkip           &= TUCompRectHasAssociatedTransformSkipFlag(pcCU->getSlice()->isIntra(), rTu.getRect(COMPONENT_Y), pcCU->getSlice()->getPPS()->getPpsRangeExtension().getLog2MaxTransformSkipBlockSize());
#else
  checkTransformSkip           &= TUCompRectHasAssociatedTransformSkipFlag(rTu.getRect(COMPONENT_Y), pcCU->getSlice()->getPPS()->getPpsRangeExtension().getLog2MaxTransformSkipBlock
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值