VVC帧内亮度角度预测--帧内编码学习(二)

对于帧内预测来说,主要包括角度预测和划分。

在xCompressCU函数中体现为

xCheckRDCostIntra( tempCS, bestCS, partitioner, currTestMode );

以及

 xCheckModeSplit( tempCS, bestCS, partitioner, currTestMode
        , tempMotCandLUTs
        , bestMotCandLUTs
        , partitioner.currArea()
      );

xCheckModeSplit函数中主要是根据划分模式进行划分,再递归回xCompressCU,与HEVC中递归差不多。

这里主要讲帧内亮度角度预测过程,VTM版本为4.0.1。

xCheckRDCostIntra函数进来之后,会进行相应参数的初始化,之后调用亮度角度预测

m_pcIntraSearch->estIntraPredLumaQT( cu, partitioner, bestCostSoFar );

和色度角度预测

 m_pcIntraSearch->estIntraPredChromaQT( cu, ( !useIntraSubPartitions || ( CS::isDualITree( *cu.cs ) && !isLuma( CHANNEL_TYPE_CHROMA ) ) ) ? partitioner : subTuPartitioner, maxCostAllowedForChroma );

帧内亮度预测主要过程为:

1、参考像素的获取与滤波;具体可见---https://blog.youkuaiyun.com/pengyouyou/article/details/89027301

2、在原HEVC的35种模式中,挑选出numModesForFullRD种哈达玛代价最小的模式-------RMD第一步;

      其中planner模式讲解见---https://blog.youkuaiyun.com/pengyouyou/article/details/89041932

3、在RMD第一步得到的角度模式中,对其相邻的新增角度模式计算哈达玛代价值,同样保留numModesForFullRD种代价最小的模式-------RMD第二步;

4、添加MPM模式;

5、对候选模式进行RDO过程,选出代价最小的模式。

虽然大致过程为这5个步骤,但是在MRL和ISP等技术的引入使得具体过程更加复杂。

具体程序注释如下:

#if JVET_M0102_INTRA_SUBPARTITIONS
void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, const double bestCostSoFar )//亮度角度预测
#else
void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner )
#endif
{
  CodingStructure       &cs            = *cu.cs;
  const SPS             &sps           = *cs.sps;
  const uint32_t             uiWidthBit    = g_aucLog2[partitioner.currArea().lwidth() ];//
  const uint32_t             uiHeightBit   =                   g_aucLog2[partitioner.currArea().lheight()];
  // Lambda calculation at equivalent Qp of 4 is recommended because at that Qp, the quantization divisor is 1.
  const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda(cu.transQuantBypass) / double(1 << SCALE_BITS);
  //===== loop over partitions =====
  const TempCtx ctxStart          ( m_CtxCache, m_CABACEstimator->getCtx() );
  const TempCtx ctxStartIntraMode(m_CtxCache, SubCtx(Ctx::IntraLumaMpmFlag, m_CABACEstimator->getCtx()));
  const TempCtx ctxStartMHIntraMode ( m_CtxCache, SubCtx( Ctx::MHIntraPredMode,        m_CABACEstimator->getCtx() ) );
  const TempCtx ctxStartMrlIdx      ( m_CtxCache, SubCtx( Ctx::MultiRefLineIdx,        m_CABACEstimator->getCtx() ) );
  CHECK( !cu.firstPU, "CU has no PUs" );
  const bool keepResi   = cs.pps->getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() || KEEP_PRED_AND_RESI_SIGNALS;
  uint32_t extraModes = 0; // add two extra modes, which would be used after uiMode <= DC_IDX is removed for cu.nsstIdx == 3

#if !JVET_M0464_UNI_MTS
  const int width   = partitioner.currArea().lwidth();
  const int height  = partitioner.currArea().lheight();

  // Marking EMT usage for faster EMT
  // 0: EMT is either not applicable for current CU (cuWidth > EMT_INTRA_MAX_CU or cuHeight > EMT_INTRA_MAX_CU), not active in the config file or the fast decision algorithm is not used in this case
  // 1: EMT fast algorithm can be applied for the current CU, and the DCT2 is being checked
  // 2: EMT is being checked for current CU. Stored results of DCT2 can be utilized for speedup
  uint8_t emtUsageFlag = 0;
  const int maxSizeEMT = EMT_INTRA_MAX_CU_WITH_QTBT;
  if( width <= maxSizeEMT && height <= maxSizeEMT && sps.getUseIntraEMT() )
  {
    emtUsageFlag = cu.emtFlag == 1 ? 2 : 1;
  }

  bool isAllIntra = m_pcEncCfg->getIntraPeriod() == 1;

  if( width * height < 64 && !isAllIntra )
  {
    emtUsageFlag = 0; //this forces the recalculation of the candidates list. Why is this necessary? (to be checked)
  }
#endif
#if JVET_M0102_INTRA_SUBPARTITIONS
#if JVET_M0464_UNI_MTS
  const int width   = partitioner.currArea().lwidth();
  const int height  = partitioner.currArea().lheight();
  int nOptionsForISP = NUM_INTRA_SUBPARTITIONS_MODES;//ISP划分模式:HOR_INTRA_SUBPARTITIONS = 1,  VER_INTRA_SUBPARTITIONS = 2,
  //默认的NUM_INTRA_SUBPARTITIONS_MODES=3
#else
  int nOptionsForISP = cu.emtFlag == 0 ? NUM_INTRA_SUBPARTITIONS_MODES : 1;
#endif
  double bestCurrentCost = bestCostSoFar;//当前最佳代价

  int ispOptions[NUM_INTRA_SUBPARTITIONS_MODES] = { 0 };//ISP模式初始为non-ISP

  if( nOptionsForISP > 1 ) {
    auto splitsThatCanBeUsedForISP = CU::canUseISPSplit( width, height, cu.cs->sps->getMaxTrSize() );//得到可能进行的ISP模式
    if( splitsThatCanBeUsedForISP == CAN_USE_VER_AND_HORL_SPLITS ) {//水平和垂直ISP均可以
      const CodingUnit* cuLeft  = cu.ispMode != NOT_INTRA_SUBPARTITIONS ? cs.getCU( cs.area.blocks[partitioner.chType].pos().offset( -1, 0 ), partitioner.chType ) : nullptr;
      const CodingUnit* cuAbove = cu.ispMode != NOT_INTRA_SUBPARTITIONS ? cs.getCU( cs.area.blocks[partitioner.chType].pos().offset( 0, -1 ), partitioner.chType ) : nullptr;
      bool ispHorIsFirstTest = CU::firstTestISPHorSplit( width, height, COMPONENT_Y, cuLeft, cuAbove );
      if( ispHorIsFirstTest )//先水平ISP,默认nOptionsForISP=3
      {
        ispOptions[1] = HOR_INTRA_SUBPARTITIONS;
        ispOptions[2] = VER_INTRA_SUBPARTITIONS;
      }
      else//先垂直ISP,默认nOptionsForISP=3
      {
        ispOptions[1] = VER_INTRA_SUBPARTITIONS;
        ispOptions[2] = HOR_INTRA_SUBPARTITIONS;
      }
    }
    else if( splitsThatCanBeUsedForISP == HOR_INTRA_SUBPARTITIONS )
    {
      nOptionsForISP = 2;
      ispOptions[1] = HOR_INTRA_SUBPARTITIONS;//水平ISP
    }
    else if( splitsThatCanBeUsedForISP == VER_INTRA_SUBPARTITIONS )
    {
      nOptionsForISP = 2;
      ispOptions[1] = VER_INTRA_SUBPARTITIONS;//垂直ISP
    }
    else
    {
      nOptionsForISP = 1;//non-ISP
    }
  }
  if( nOptionsForISP > 1 )//ISP模式清空列表
  {
    //variables for the full RD list without MRL modes
    m_rdModeListWithoutMrl      .clear();
    m_rdModeListWithoutMrlHor   .clear();
    m_rdModeListWithoutMrlVer   .clear();
    //variables with data from regular intra used to skip ISP splits
    m_intraModeDiagRatio        .clear();
    m_intraModeHorVerRatio      .clear();
    m_intraModeTestedNormalIntra.clear();
  }
#endif

  static_vector<uint32_t,   FAST_UDI_MAX_RDMODE_NUM> uiHadModeList;//哈达玛模式列表
  static_vector<double, FAST
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值