H.266/VVC代码学习9:xIntraCodingTUBlock函数

时间:2019-03-18
本文章向大家介绍H.266/VVC代码学习9:xIntraCodingTUBlock函数,主要包括H.266/VVC代码学习9:xIntraCodingTUBlock函数使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

这个函数将确定的帧内预测模式进行残差计算、变换量化和反变换重建等操作。具体含义可见代码中注释:

#if JVET_M0464_UNI_MTS
void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &compID, const bool &checkCrossCPrediction, Distortion& ruiDist, const int &default0Save1Load2, uint32_t* numSig, std::vector<TrMode>* trModes, const bool loadTr)
#else
void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &compID, const bool &checkCrossCPrediction, Distortion& ruiDist, const int &default0Save1Load2, uint32_t* numSig )
#endif
{
  if (!tu.blocks[compID].valid())
  {
    return;
  }

  /****************************************** 初始化 ***************************************/
  CodingStructure &cs                       = *tu.cs;

  const CompArea      &area                 = tu.blocks[compID];
  const SPS           &sps                  = *cs.sps;
  const PPS           &pps                  = *cs.pps;

  const ChannelType    chType               = toChannelType(compID);
  const int            bitDepth             = sps.getBitDepth(chType);

  PelBuf         piOrg                      = cs.getOrgBuf    (area);//原始
  PelBuf         piPred                     = cs.getPredBuf   (area);//预测
  PelBuf         piResi                     = cs.getResiBuf   (area);//残差
  PelBuf         piOrgResi                  = cs.getOrgResiBuf(area);
  PelBuf         piReco                     = cs.getRecoBuf   (area);//重建

  const PredictionUnit &pu                  = *cs.getPU(area.pos(), chType);
  const uint32_t           uiChFinalMode        = PU::getFinalIntraMode(pu, chType);//编码模式,1.DM获取模式的入口,得到预测角度

  const bool           bUseCrossCPrediction = pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && isChroma( compID ) && PU::isChromaIntraModeCrossCheckMode( pu ) && checkCrossCPrediction;
  const bool           ccUseRecoResi        = m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate();
#if JVET_M0102_INTRA_SUBPARTITIONS
  const bool           ispSplitIsAllowed    = CU::canUseISPSplit( *tu.cu, compID );
#endif


  //===== init availability pattern 初始化 =====
  PelBuf sharedPredTS( m_pSharedPredTransformSkip[compID], area );
  if( default0Save1Load2 != 2 )//如果是不是2个预测值(2个预测值条件:1.不是LM模式 2. 允许使用CCP 3. Y分量的cbf不为0)
  {
    const bool bUseFilteredPredictions = IntraPrediction::useFilteredIntraRefSamples( compID, pu, true, tu );
    initIntraPatternChType( *tu.cu, area, bUseFilteredPredictions );

    //===== get prediction signal 计算预测值 =====
    if( compID != COMPONENT_Y && PU::isLMCMode( uiChFinalMode ) )//2.LM模式预测,得到预测角度
    {
      {
        xGetLumaRecPixels( pu, area );//获取重建像素
      }
      predIntraChromaLM( compID, piPred, pu, area, uiChFinalMode );//LM模式
    }
    else//2.角度模式预测
    {
      predIntraAng( compID, piPred, pu, bUseFilteredPredictions );//正常角度模式
    }


    // save prediction 保存预测值
    if( default0Save1Load2 == 1 )//如果是1个预测值
    {
      sharedPredTS.copyFrom( piPred );
    }
  }
  else//如果是2个预测值
  {
    // load prediction 加载预测值
    piPred.copyFrom( sharedPredTS );
  }


  DTRACE( g_trace_ctx, D_PRED, "@(%4d,%4d) [%2dx%2d] IMode=%d\n", tu.lx(), tu.ly(), tu.lwidth(), tu.lheight(), uiChFinalMode );
  //DTRACE_PEL_BUF( D_PRED, piPred, tu, tu.cu->predMode, COMPONENT_Y );

#if JVET_M0427_INLOOP_RESHAPER
  const Slice           &slice = *cs.slice;
#if JVET_M0483_IBC
  bool flag = slice.getReshapeInfo().getUseSliceReshaper() && (slice.isIntra() || (!slice.isIntra() && m_pcReshape->getCTUFlag()));
#else
  bool flag = slice.getReshapeInfo().getUseSliceReshaper() && (slice.isIntra() || (!slice.isIntra() && m_pcReshape->getCTUFlag()) || (slice.getSliceType() == P_SLICE && slice.getSPS()->getIBCMode()));
#endif
  /******* 色度模式时 *******/
  if (flag && slice.getReshapeInfo().getSliceReshapeChromaAdj() && isChroma(compID))
  {
    const Area area = tu.Y().valid() ? tu.Y() : Area(recalcPosition(tu.chromaFormat, tu.chType, CHANNEL_TYPE_LUMA, tu.blocks[tu.chType].pos()), recalcSize(tu.chromaFormat, tu.chType, CHANNEL_TYPE_LUMA, tu.blocks[tu.chType].size()));
    const CompArea &areaY = CompArea(COMPONENT_Y, tu.chromaFormat, area );//亮度块
    PelBuf piPredY;
    piPredY = cs.picture->getPredBuf(areaY);//获取亮度预测缓存
    const Pel avgLuma = piPredY.computeAvg();//平均亮度预测值
    int adj = m_pcReshape->calculateChromaAdj(avgLuma);//色度预测值
    tu.setChromaAdj(adj);//设置色度预测值
  }
#endif
  //===== get residual signal 计算残差 =====
  piResi.copyFrom( piOrg  );// 暂时给残差赋值为原始值
#if JVET_M0427_INLOOP_RESHAPER
  if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && compID==COMPONENT_Y)
  {
    CompArea      tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size());
    PelBuf tmpPred = m_tmpStorageLCU.getBuf(tmpArea);
    tmpPred.copyFrom(piPred);
    piResi.rspSignal(m_pcReshape->getFwdLUT());
    piResi.subtract(tmpPred);
  }
  else
#endif
  piResi.subtract( piPred );// 残差 = 原始 - 预测

  if (pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && isLuma(compID))
  {
    piOrgResi.copyFrom (piResi);
  }

  if (bUseCrossCPrediction)
  {
    if (xCalcCrossComponentPredictionAlpha(tu, compID, ccUseRecoResi) == 0)
    {
      return;
    }
    CrossComponentPrediction::crossComponentPrediction(tu, compID, cs.getResiBuf(tu.Y()), piResi, piResi, false);
  }

  //===== transform and quantization 变换量化 =====
  //--- init rate estimation arrays for RDOQ ---
  //--- transform and quantization           ---
  TCoeff uiAbsSum = 0;

  const QpParam cQP(tu, compID);

#if RDOQ_CHROMA_LAMBDA
  m_pcTrQuant->selectLambda(compID);//确定lambda
#endif
  /****** 色度块不小时,调整lambda *******/
#if JVET_M0427_INLOOP_RESHAPER
  flag =flag && (tu.blocks[compID].width*tu.blocks[compID].height > 4);//TU的 宽*高>4 时flag为true
  if (flag && isChroma(compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj() )
  {
    int cResScaleInv = tu.getChromaAdj();
    double cResScale = round((double)(1 << CSCALE_FP_PREC) / (double)cResScaleInv);
    m_pcTrQuant->setLambda(m_pcTrQuant->getLambda() / (cResScale*cResScale));//调整lambda
    piResi.scaleSignal(cResScaleInv, 1, tu.cu->cs->slice->clpRng(compID));
  }
#endif

#if JVET_M0102_INTRA_SUBPARTITIONS
  double diagRatio = 0, horVerRatio = 0;
#endif

#if JVET_M0464_UNI_MTS
  if( trModes )//残差的变换:transformNxN是残差信号变换量化的入口函数:重点!!
  {
#if JVET_M0102_INTRA_SUBPARTITIONS
    m_pcTrQuant->transformNxN( tu, compID, cQP, trModes, CU::isIntra( *tu.cu ) ? m_pcEncCfg->getIntraMTSMaxCand() : m_pcEncCfg->getInterMTSMaxCand(), ispSplitIsAllowed ? &diagRatio : nullptr, ispSplitIsAllowed ? &horVerRatio : nullptr );
#else
    m_pcTrQuant->transformNxN( tu, compID, cQP, trModes, CU::isIntra( *tu.cu ) ? m_pcEncCfg->getIntraMTSMaxCand() : m_pcEncCfg->getInterMTSMaxCand() );
#endif
    tu.mtsIdx = trModes->at(0).first;
  }
#if JVET_M0102_INTRA_SUBPARTITIONS
  m_pcTrQuant->transformNxN( tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr, &diagRatio, &horVerRatio );
#else
  m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr);
#endif
#else
#if JVET_M0102_INTRA_SUBPARTITIONS
  m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), ispSplitIsAllowed ? &diagRatio : nullptr, ispSplitIsAllowed ? &horVerRatio : nullptr);
#else
  m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx());
#endif
#endif
#if JVET_M0102_INTRA_SUBPARTITIONS
  if (!tu.cu->ispMode && isLuma(compID) && ispSplitIsAllowed &&
#if JVET_M0464_UNI_MTS
    tu.mtsIdx == 0
#else
    !tu.cu->emtFlag
#endif
    )
  {
    m_intraModeDiagRatio        .push_back(diagRatio);
    m_intraModeHorVerRatio      .push_back(horVerRatio);
    m_intraModeTestedNormalIntra.push_back((int)uiChFinalMode);
  }
#endif


  DTRACE( g_trace_ctx, D_TU_ABS_SUM, "%d: comp=%d, abssum=%d\n", DTRACE_GET_COUNTER( g_trace_ctx, D_TU_ABS_SUM ), compID, uiAbsSum );


  //--- inverse transform 反变换---
  if (uiAbsSum > 0)
  {
    m_pcTrQuant->invTransformNxN(tu, compID, piResi, cQP);//invtransformNxN是残差信号反变换的入口函数:重点!!
  }
  else
  {
    piResi.fill(0);
  }

  //===== reconstruction 重建 =====
#if JVET_M0427_INLOOP_RESHAPER
  if (flag && uiAbsSum > 0 && isChroma(compID) && slice.getReshapeInfo().getSliceReshapeChromaAdj() )
  {
    piResi.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(compID));
  }
#endif
  if (bUseCrossCPrediction)
  {
    CrossComponentPrediction::crossComponentPrediction(tu, compID, cs.getResiBuf(tu.Y()), piResi, piResi, true);
  }

#if JVET_M0427_INLOOP_RESHAPER
  if (slice.getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag() && compID == COMPONENT_Y)
  {
    CompArea      tmpArea(COMPONENT_Y, area.chromaFormat, Position(0,0), area.size());
    PelBuf tmpPred = m_tmpStorageLCU.getBuf(tmpArea);
    tmpPred.copyFrom(piPred);
    piReco.reconstruct(tmpPred, piResi, cs.slice->clpRng(compID));
  }
  else
#endif
  piReco.reconstruct(piPred, piResi, cs.slice->clpRng( compID ));

  //===== update distortion 更新失真值 =====
#if WCG_EXT
#if JVET_M0427_INLOOP_RESHAPER
  if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcEncCfg->getReshaper()
    && slice.getReshapeInfo().getUseSliceReshaper() && (m_pcReshape->getCTUFlag() || (isChroma(compID) && m_pcEncCfg->getReshapeIntraCMD()))))
#else
  if( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() )
#endif
  {
    const CPelBuf orgLuma = cs.getOrgBuf( cs.area.blocks[COMPONENT_Y] );
#if JVET_M0427_INLOOP_RESHAPER
    if (compID == COMPONENT_Y  && !(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled()))
    {
      CompArea      tmpArea1(COMPONENT_Y, area.chromaFormat, Position(0, 0