VVC/JEM代码学习15:xCheckRDCostAffineMerge2Nx2N

本文介绍JEM编码器中的Affine模式,这是一种新的帧间预测技术,用于提高视频压缩效率。文章详细解释了Affine模式的工作原理,包括如何通过合并候选来预测运动矢量,并介绍了相关代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Affine模式是JEM中新加的,属于帧间预测,与FRUC,merge,inter形成竞争关系。

#if COM16_C1016_AFFINE

Void TEncCu::xCheckRDCostAffineMerge2Nx2N( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU )
{
  assert( rpcTempCU->getSlice()->getSliceType() != I_SLICE );
  if ( getFastDeltaQp() )
  {
    return;
  }


  TComMvField cAffineMvField[2][3];
  UChar uhInterDirNeighbours[1] = {0};
  Int numValidMergeCand = 0;
  const Bool bTransquantBypassFlag = rpcTempCU->getCUTransquantBypass(0);


  UChar uhDepth = rpcTempCU->getDepth( 0 );
#if JVET_C0024_QTBT
  if (rpcBestCU->getWidth(0) * rpcBestCU->getHeight(0) < 64)//只对大于等于8*8的块执行affine merge;
  {
    return;
  }
  UInt uiWIdx = g_aucConvertToBit[rpcBestCU->getWidth(0)];
  UInt uiHIdx = g_aucConvertToBit[rpcBestCU->getHeight(0)];
#else
  rpcTempCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uhDepth );
#endif
  //得到仿射Merge候选;
  rpcTempCU->getAffineMergeCandidates( 0, 0, cAffineMvField, uhInterDirNeighbours, numValidMergeCand );
  if ( numValidMergeCand == -1 )//如果merge候选个数为-1,则退出,不执行Affine merge
  {
    return;
  }
  Int mergeCandBuffer[1] = {0};


  UInt iteration;
  if ( rpcTempCU->isLosslessCoded(0))//无损编码迭代次数为1,否则为2;
  {
    iteration = 1;
  }
  else
  {
    iteration = 2;
  }
  ///至少迭代一次,如果没有残差,则不会进行第二次迭代//
  for ( UInt uiNoResidual = 0; uiNoResidual < iteration; ++uiNoResidual )
  {//遍历所有有效的Merge候选;
    for ( UInt uiMergeCand = 0; uiMergeCand < numValidMergeCand; ++uiMergeCand )//numValidMergeCand=1;
    {//第一次迭代uiNoResidual=0,if条件一定成立,会执行里面的内容;
	 //第二次迭代中,如果在第一次迭代时,没有残差,则mergeCandBuffer[uiMergeCand]=1 ,此时不满足if条件,不进入下面的步骤;
      if ( !( uiNoResidual==1 && mergeCandBuffer[uiMergeCand]==1 ) )
      {
        // set MC parameters,设置运动补偿参数;
        rpcTempCU->setPredModeSubParts( MODE_INTER, 0, uhDepth );//设置预测模式为帧间;
        rpcTempCU->setCUTransquantBypassSubParts( bTransquantBypassFlag, 0, uhDepth );//设置TransquantBypassFlag;
        rpcTempCU->setChromaQpAdjSubParts( bTransquantBypassFlag ? 0 : m_cuChromaQpOffsetIdxPlus1, 0, uhDepth );//设置色度QP调整
#if !JVET_C0024_QTBT
        rpcTempCU->setPartSizeSubParts( SIZE_2Nx2N, 0, uhDepth );
#endif
        rpcTempCU->setAffineFlagSubParts( true, 0, 0, uhDepth );//设置Affine flag为true;
        rpcTempCU->setMergeFlagSubParts( true, 0, 0, uhDepth );//设置merge flag为true;
        rpcTempCU->setMergeIndexSubParts( uiMergeCand, 0, 0, uhDepth );//设置mergeidx 设置为0;
        rpcTempCU->setInterDirSubParts( uhInterDirNeighbours[uiMergeCand], 0, 0, uhDepth );//将帧间模式设置为uhInterDirNeighbours[uiMergeCand]
        rpcTempCU->setAllAffineMvField( 0, 0, cAffineMvField[0 + 2*uiMergeCand], REF_PIC_LIST_0, 0 );//设置affine mvf;
        rpcTempCU->setAllAffineMvField( 0, 0, cAffineMvField[1 + 2*uiMergeCand], REF_PIC_LIST_1, 0 );


#if COM16_C806_OBMC
        rpcTempCU->setOBMCFlagSubParts( true, 0, uhDepth );//设置OBMC Flag为true
#endif


        // do MC,做运动补偿
#if JVET_C0024_QTBT
        m_pcPredSearch->motionCompensation ( rpcTempCU, m_pppcPredYuvTemp[uiWIdx][uiHIdx] );


#if COM16_C806_OBMC//进行重叠块运动补偿;
        m_pcPredSearch->subBlockOBMC( rpcTempCU, 0, m_pppcPredYuvTemp[uiWIdx][uiHIdx], m_pppcTmpYuv1[uiWIdx][uiHIdx], m_pppcTmpYuv2[uiWIdx][uiHIdx] );
#endif
        // estimate residual and encode everything,估计残差和编码所有数据
        m_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU,
                                                   m_pppcOrigYuv    [uiWIdx][uiHIdx],
                                                   m_pppcPredYuvTemp[uiWIdx][uiHIdx],
                                                   m_pppcResiYuvTemp[uiWIdx][uiHIdx],
                                                   m_pppcResiYuvBest[uiWIdx][uiHIdx],
                                                   m_pppcRecoYuvTemp[uiWIdx][uiHIdx],
                                                   (uiNoResidual != 0) 
#if COM16_C806_EMT
                                                   , rpcBestCU->getTotalCost()
#endif
          );
#else
        m_pcPredSearch->motionCompensation ( rpcTempCU, m_ppcPredYuvTemp[uhDepth] );


#if COM16_C806_OBMC
        m_pcPredSearch->subBlockOBMC( rpcTempCU, 0, m_ppcPredYuvTemp[uhDepth], m_ppcTmpYuv1[uhDepth], m_ppcTmpYuv2[uhDepth] );
#endif
        // estimate residual and encode everything
        m_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU,
                                                   m_ppcOrigYuv    [uhDepth],
                                                   m_ppcPredYuvTemp[uhDepth],
                                                   m_ppcResiYuvTemp[uhDepth],
                                                   m_ppcResiYuvBest[uhDepth],
                                                   m_ppcRecoYuvTemp[uhDepth],
                                                   (uiNoResidual != 0) 
#if COM16_C806_EMT
                                                   , rpcBestCU->getTotalCost()
#endif
          );
#endif
        if ( uiNoResidual == 0 && rpcTempCU->getQtRootCbf(0) == 0 )
        { //如果是第一次迭代,且cbf为0时(即无残差时),令mergeCandBuffer[uiMergeCnad]=1;
          // If no residual when allowing for one, then set mark to not try case where residual is forced to 0
          mergeCandBuffer[uiMergeCand] = 1;
        }


        rpcTempCU->setSkipFlagSubParts( rpcTempCU->getQtRootCbf(0) == 0, 0, uhDepth );//如果当前CU的cbf为0时,设置Skip Flag为true,否则为false
        Int orgQP = rpcTempCU->getQP( 0 );
        xCheckDQP( rpcTempCU );
        xCheckBestMode(rpcBestCU, rpcTempCU, uhDepth);
        rpcTempCU->initEstData( uhDepth, orgQP, bTransquantBypassFlag );//比较完TempCU和BestCU,就将TempCU重新初始化
      }
    }//遍历merge候选结束/
  }///迭代结束///
}
#endif
//得到Affine的merge候选预测模式
Void TComDataCU::getAffineMergeCandidates( UInt uiAbsPartIdx, UInt uiPUIdx, TComMvField (*pcMvFieldNeighbours)[3], UChar* puhInterDirNeighbours, Int& numValidMergeCand, Int mrgCandIdx )
{
  TComMvField affineMvField[2][3];//2是表示有两个双向预测,3是表示3种运动矢量场???
  UInt uiAbsPartAddr = m_absZIdxInCtu + uiAbsPartIdx;

  TComDataCU *pcTempCU = NULL;
  Bool bAvailable = false;
  UInt uiPartIdx = 0;
  //初始化运动场
  for ( Int mvNum = 0; mvNum < 3; mvNum++ )
  {
    pcMvFieldNeighbours[0][mvNum].setMvField( TComMv(0,0), -1 );
    pcMvFieldNeighbours[1][mvNum].setMvField( TComMv(0,0), -1 );
  }

  // Get Part Index in LCU,得到CU在LCU的索引
  UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;
  deriveLeftRightTopIdxGeneral( uiAbsPartIdx, uiPUIdx, uiPartIdxLT, uiPartIdxRT );//推导左上part和右上part的索引
  deriveLeftBottomIdxGeneral  ( uiAbsPartIdx, uiPUIdx, uiPartIdxLB );//推导左下part的索引
  //当一个CU应用AF_MERGE模式时,从有效的相邻重建块中得到第一个用仿射模式的编码块。候选块的选择顺序是从左,上,右上,左下到左上
  // left
  pcTempCU = getPULeft( uiPartIdx, uiPartIdxLB );
  bAvailable = pcTempCU && pcTempCU->isAffine( uiPartIdx );//左边CU是否是Affine模式

  // above
  if ( !bAvailable )//如果左边不是,则查看上边的CU
  {
    pcTempCU = getPUAbove( uiPartIdx, uiPartIdxRT );
    bAvailable = pcTempCU && pcTempCU->isAffine( uiPartIdx );
  }

  // aboveRight
  if ( !bAvailable )//上边不是,则查看右上CU
  {
    pcTempCU = getPUAboveRight( uiPartIdx, uiPartIdxRT );
    bAvailable = pcTempCU && pcTempCU->isAffine( uiPartIdx );
  }

  // leftBottom
  if ( !bAvailable )//右上不是,则查看左下CU
  {
    pcTempCU = getPUBelowLeft( uiPartIdx, uiPartIdxLB );
    bAvailable = pcTempCU && pcTempCU->isAffine( uiPartIdx );
  }

  // aboveLeft
  if ( !bAvailable )//左下不是,则查看左上CU
  {
    pcTempCU = getPUAboveLeft( uiPartIdx, uiAbsPartAddr );
    bAvailable = pcTempCU && pcTempCU->isAffine( uiPartIdx );
  }

  if ( !bAvailable )//如果5个相邻块都不是仿射模式,则有效的merge候选个数为0,退出;
  {
    numValidMergeCand = -1;
    return;
  }
  else//否则,有效的merge候选个数为1;
  {
    assert( pcTempCU );
    numValidMergeCand = 1;
  }

  Int width = pcTempCU->getWidth(uiPartIdx);
  Int height = pcTempCU->getHeight(uiPartIdx);
#if !JVET_C0024_QTBT
  Int depth  = pcTempCU->getDepth(uiPartIdx);
  Int numPart = pcTempCU->getPic()->getNumPartitionsInCtu() >> ( depth << 1 );
#endif
  Int iPartW = width / getPic()->getMinCUWidth();
  Int iPartH = height / getPic()->getMinCUHeight();

#if JVET_C0024_QTBT
  Int iBlkY = g_auiZscanToRaster[uiPartIdx]/(getPic()->getNumPartInCtuWidth()*iPartH);
  Int iBlkX = (g_auiZscanToRaster[uiPartIdx]%getPic()->getNumPartInCtuWidth())/iPartW;
  Int aboveLeftIdx = g_auiRasterToZscan[iBlkY * getPic()->getNumPartInCtuWidth() * iPartH + iBlkX * iPartW];
#else
  Int aboveLeftIdx = uiPartIdx - ( uiPartIdx % numPart );
#endif
  Int aboveRightIdx = g_auiRasterToZscan[ g_auiZscanToRaster[aboveLeftIdx] + iPartW - 1 ];
  Int bottomLeftIdx = g_auiRasterToZscan[ g_auiZscanToRaster[aboveLeftIdx] + ( iPartH - 1 ) * getPic()->getNumPartInCtuWidth() ];

  // list0
  affineMvField[0][0].setMvField( pcTempCU->getCUMvField(REF_PIC_LIST_0)->getMv( aboveLeftIdx ),  pcTempCU->getCUMvField(REF_PIC_LIST_0)->getRefIdx( aboveLeftIdx ) );
  affineMvField[0][1].setMvField( pcTempCU->getCUMvField(REF_PIC_LIST_0)->getMv( aboveRightIdx ), pcTempCU->getCUMvField(REF_PIC_LIST_0)->getRefIdx( aboveRightIdx ) );
  affineMvField[0][2].setMvField( pcTempCU->getCUMvField(REF_PIC_LIST_0)->getMv( bottomLeftIdx ), pcTempCU->getCUMvField(REF_PIC_LIST_0)->getRefIdx( bottomLeftIdx ) );

  // list1
  affineMvField[1][0].setMvField( pcTempCU->getCUMvField(REF_PIC_LIST_1)->getMv( aboveLeftIdx ),  pcTempCU->getCUMvField(REF_PIC_LIST_1)->getRefIdx( aboveLeftIdx ) );
  affineMvField[1][1].setMvField( pcTempCU->getCUMvField(REF_PIC_LIST_1)->getMv( aboveRightIdx ), pcTempCU->getCUMvField(REF_PIC_LIST_1)->getRefIdx( aboveRightIdx ) );
  affineMvField[1][2].setMvField( pcTempCU->getCUMvField(REF_PIC_LIST_1)->getMv( bottomLeftIdx ), pcTempCU->getCUMvField(REF_PIC_LIST_1)->getRefIdx( bottomLeftIdx ) );

  Int pixelOrgX    = g_auiRasterToPelX[ g_auiZscanToRaster[ aboveLeftIdx ] ] + pcTempCU->getCUPelX();
  Int pixelCurrX   = getCUPelX();
  Int pixelOrgY    = g_auiRasterToPelY[ g_auiZscanToRaster[ aboveLeftIdx ] ] + pcTempCU->getCUPelY();
  Int pixelCurrY   = getCUPelY();
  //计算运动矢量场;
  //vx0,vx1,vx2,vy0,vy1,vy2表示G1001里等式15???
  Int vx0 = Int( affineMvField[0][0].getHor() + 1.0 * ( affineMvField[0][2].getHor() - affineMvField[0][0].getHor() ) * ( pixelCurrY - pixelOrgY ) / height
    + 1.0 * ( affineMvField[0][1].getHor() - affineMvField[0][0].getHor() ) * ( pixelCurrX - pixelOrgX ) / width );
  Int vy0 = Int( affineMvField[0][0].getVer() + 1.0 * ( affineMvField[0][2].getVer() - affineMvField[0][0].getVer() ) * ( pixelCurrY - pixelOrgY ) / height
    + 1.0 * ( affineMvField[0][1].getVer() - affineMvField[0][0].getVer() ) * ( pixelCurrX - pixelOrgX ) / width );
  pcMvFieldNeighbours[0][0].setMvField( TComMv(vx0, vy0), affineMvField[0][0].getRefIdx() );
  if ( getSlice()->isInterB() )//如果是B_SLICE,则还要计算另一个方向的运动矢量场;
  {
    vx0 = Int( affineMvField[1][0].getHor() + 1.0 * ( affineMvField[1][2].getHor() - affineMvField[1][0].getHor() ) * ( pixelCurrY - pixelOrgY ) / height 
      + 1.0 * ( affineMvField[1][1].getHor() - affineMvField[1][0].getHor() ) * ( pixelCurrX - pixelOrgX ) / width );
    vy0 = Int( affineMvField[1][0].getVer() + 1.0 * ( affineMvField[1][2].getVer() - affineMvField[1][0].getVer() ) * ( pixelCurrY - pixelOrgY ) / height 
      + 1.0 * ( affineMvField[1][1].getVer() - affineMvField[1][0].getVer() ) * ( pixelCurrX - pixelOrgX ) / width );
    pcMvFieldNeighbours[1][0].setMvField( TComMv(vx0, vy0), affineMvField[1][0].getRefIdx() );
  }

  Int vx1 = Int( 1.0 * ( affineMvField[0][1].getHor() - affineMvField[0][0].getHor() ) * getWidth(0) / width + pcMvFieldNeighbours[0][0].getHor() );
  Int vy1 = Int( 1.0 * ( affineMvField[0][1].getVer() - affineMvField[0][0].getVer() ) * getWidth(0) / width + pcMvFieldNeighbours[0][0].getVer() );
  pcMvFieldNeighbours[0][1].setMvField( TComMv(vx1, vy1), affineMvField[0][0].getRefIdx() );
  if ( getSlice()->isInterB() )//如果是B_SLICE,则还要计算另一个方向的运动矢量场;
  {
    vx1 = Int( 1.0 * ( affineMvField[1][1].getHor() - affineMvField[1][0].getHor() ) * getWidth(0) / width + pcMvFieldNeighbours[1][0].getHor() );
    vy1 = Int( 1.0 * ( affineMvField[1][1].getVer() - affineMvField[1][0].getVer() ) * getWidth(0) / width + pcMvFieldNeighbours[1][0].getVer() );
    pcMvFieldNeighbours[1][1].setMvField( TComMv(vx1, vy1), affineMvField[1][0].getRefIdx() );
  }

  Int vx2 = Int( 1.0 * ( affineMvField[0][2].getHor() - affineMvField[0][0].getHor() ) * getHeight(0) / height + pcMvFieldNeighbours[0][0].getHor() );
  Int vy2 = Int( 1.0 * ( affineMvField[0][2].getVer() - affineMvField[0][0].getVer() ) * getHeight(0) / height + pcMvFieldNeighbours[0][0].getVer() );
  pcMvFieldNeighbours[0][2].setMvField( TComMv(vx2, vy2), affineMvField[0][0].getRefIdx() );
  if ( getSlice()->isInterB() )//如果是B_SLICE,则还要计算另一个方向的运动矢量场;
  {
    vx2 = Int( 1.0 * ( affineMvField[1][2].getHor() - affineMvField[1][0].getHor() ) * getHeight(0) / height + pcMvFieldNeighbours[1][0].getHor() );
    vy2 = Int( 1.0 * ( affineMvField[1][2].getVer() - affineMvField[1][0].getVer() ) * getHeight(0) / height + pcMvFieldNeighbours[1][0].getVer() );
    pcMvFieldNeighbours[1][2].setMvField( TComMv(vx2, vy2), affineMvField[1][0].getRefIdx() );
  }

  puhInterDirNeighbours[0] = pcTempCU->getInterDir( uiPartIdx );
  return;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值