H.266/VVC代码学习36:VTM6.0帧间预测主要方式及编码方法

刚一开学就转向inter了,心里还是有点小激动的,虽说又要从零基础开始了!!!
本篇博客主要讲一下帧间预测的大体预测方式及主要预测方式的编码方法,算是一周快速入门的总结。

1 merge预测

最regular的merge通俗来说是指当前块的mv信息,是通过其相邻块来作为参考。通过一定的加工处理,在候选mv中选出一个最佳mv即作为当前块mv。

1.1 SubblockMerge

这个技术之前被称为affine_merge,所谓affine即仿射。这里指的是候选的几个mv,将通过渐变等方式,对当前块的每一个像素赋值不一定相同的mv。举个例子:如右上角的块mv指向正上方,左下角的块mv指向正左方,则靠近左下的像素值mv将指向偏左,靠近右上的像素值mv将指向偏上,而对角线处像素mv指向左上45度的位置。这样会有助于旋转等过程的编码。

1.2 MMVD

这个技术表示通过正常的merge预测,将merge列表的前两位作为备选,此时不将merge方式的mv完全作为预测,而是在此mv周围的四个方向,继续寻找更接近真实预测的mv。可以说是将merge和普通inter融合了起来:“我不完全相信merge的东西,我还要mvd一下”。

1.3 CIIP

这个技术在merge已经找到最佳的基础上,预测出帧间的像素值。再将帧内预测的方式(PLANAR和DM)预测出的像素值,按位置进行加权平均。这样就得到了帧内帧间联合的预测方式。

1.4 Triangle

这个技术相对来说好理解很多,就是将一个矩形块一分为二变成两个三角形(两种切分方式),将两个三角形分别进行merge,最后对预测出的(划分线上的?)像素值进行一个加权操作。

2 非merge的inter预测

普通的inter预测就是通过预测出的mv(即MVP)和真实的mv做差,编码得到的结果MVD。

2.1 affine

分为四参数的affine和六参数的affine。通过多个周围块的mv,以(x,y)为未知数列出一个多元方程,解得的mv作为当前块的mv

2.2 smvd

使用前向预测之后,假设物体运动方式为匀速,故通过时域对称的方式,得到当前块在后面时间的mv。

2.3 amvr

为了更好的处理mv的精度,有时整像素不够达到最佳预测精度,故引入1/4像素精度甚至1/16像素精度,来确定mv的大小。

3 编解码过程

最首先判断是否为帧间的merge模式,随后有如下的编码:

3.1 merge编码

1、判断是否为subblockMerge,如果是编1返回,否编0继续判断。(有上下文模型)
2、判断是否为MMVD或普通的merge:如果是编1继续,否编0继续:(有上下文模型,并有块尺寸限制)
2.1、如果为MMVD,编1返回(最终模式为MMVD),否编0返回(最终模式为普通merge)。(有上下文模型)
2.2、如果为CIIP,编1返回(最终模式为CIIP),否编0返回(最终模式为Triangle)。(有上下文模型)
3、若为MMVD:常规编码1位表示参考merge列表的第几个,随后旁路编码n位表示步长,最后旁路编码2位表示四个方向。
4、若为TMP:旁路编码1位表示当前处理哪个三角形。
5、除了MMVD模式,都要进行mergeIdx的编码:位于第几位就第几位编0,其前面的位都为1。(第一位有上下文模型)。

3.2 非merge编码

1、编码1位判断使用的是单向参考还是双向参考,若使用单向参考在实验一位判断是前向还是后向。(有上下文模型)。
2、编码1位判断是否使用affine。(有上下文模型)。
3、编码1位判断是否使用smvd。(有上下文模型)。
4、用mergeIdx编码的方式编码使用的是哪一帧(第一位有上下文模型)。
5、编码mvd:若为affine,需要编3个mvd,不是affine只需编1个
5.1、若mvd大于0,编1继续,否编0结束;若mvd大于1,编1继续,否编0结束;此时用哥伦布编码编大于2的部分。(有上下文模型)。
5.2、旁路编码该mvd值的正负号
5.3、编码1位判断该mvd使用的是前向列表还是后向列表(有上下文模型)。

3.3 后续编码

1、编码AMVR:
1.1、对非affine_inter有四种方式:1/4像素精度编0,1/2像素精度编10,1像素精度编110,4像素精度编111(都有上下文模型)。
1.2、对affine_inter有三种方式:分别编码0,10,11(都有上下文模型)。
2、编码gbi:使用mergeIdx的方式。

4 编解码代码

首先先说明一下一些代码内容的含义:

REF_PIC_LIST_0 		// 参考列表0(前向参考列表)
REF_PIC_LIST_1 		// 参考列表1(后向参考列表)

pu.interdir = 1		// 使用前向参考列表,即L0
pu.interdir = 2		// 使用后向参考列表,即L1
pu.interdir = 3		// 使用双向参考列表,即L0、L1都使用

4.1 预测编码入口

void CABACWriter::cu_pred_data( const CodingUnit& cu )//CU预测数据
{
	/******* 帧内 *******/
  if( CU::isIntra( cu ) )
  {
    intra_luma_pred_modes  ( cu );//亮度编码
    intra_chroma_pred_modes( cu );//色度编码
    return;
  }

  if (!cu.Y().valid()) // dual tree chroma CU
  {
    return;
  }

  /******* 帧间 *******/
  for( auto &pu : CU::traversePUs( cu ) )
  {
    prediction_unit( pu );//帧间编码
  }

  imv_mode   ( cu );	 // AMVR(非affine)时使用
  affine_amvr_mode( cu );// AMVR(且affine)时使用

  cu_gbi_flag( cu );//双向加权预测标志

}

4.2 帧间预测入口

void CABACWriter::prediction_unit( const PredictionUnit& pu )
{
#if JVET_O0050_LOCAL_DUAL_TREE
  CHECK( pu.cu->treeType == TREE_C, "cannot be chroma CU" );
#endif
#if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM
  CHECK( pu.cacheUsed, "Processing a PU that should be in cache!" );
  CHECK( pu.cu->cacheUsed, "Processing a CU that should be in cache!" );

#endif
  /******************************************* skip *********************************************/
  if( pu.cu->skip )//****** 1.skip or merge
  {
    CHECK( !pu.mergeFlag, "merge_flag must be true for skipped CUs" );
  }

  /******************************************* merge ********************************************/
  else
  {
    merge_flag( pu );//确定是否为merge模式
  }
  if( pu.mergeFlag )
  {
#if JVET_O0249_MERGE_SYNTAX
    merge_data(pu);//若为merge模式,找到是第几种merge
#else
    if (CU::isIBC(*pu.cu))
    {
      merge_idx(pu);
      return;
    }
    if (pu.regularMergeFlag)
    {
      merge_idx(pu);
    }
    else
    {
      subblock_merge_flag( *pu.cu );
      MHIntra_flag( pu );
      if (!pu.mhIntraFlag)
      {
        if (!pu.cu->affine && !pu.mmvdMergeFlag && !pu.cu->mmvdSkip)
        {
          CHECK(!pu.cu->triangle, "triangle_flag must be true");
        }
      }
      if (pu.mmvdMergeFlag)
      {
        mmvd_merge_idx(pu);
      }
      else
        merge_idx    ( pu );
    }
#endif
  }
  
  /******************************************* IBC ********************************************/
  else if (CU::isIBC(*pu.cu))
  {
    ref_idx(pu, REF_PIC_LIST_0);
    Mv mvd = pu.mvd[REF_PIC_LIST_0];
    mvd.changeIbcPrecInternal2Amvr(pu.cu->imv);
    mvd_coding(mvd, 0); // already changed to signaling precision
#if JVET_O0162_IBC_MVP_FLAG
#if JVET_O0455_IBC_MAX_MERGE_NUM
    if ( pu.cu->slice->getMaxNumIBCMergeCand() == 1 )
#else
    if ( pu.cu->slice->getMaxNumMergeCand() == 1 )
#endif
    {
      CHECK( pu.mvpIdx[REF_PIC_LIST_0], "mvpIdx for IBC mode should be 0" );
    }
    else
#endif
    mvp_flag(pu, REF_PIC_LIST_0);
  }

  /**************************************** MVD(AMVR) ******************************************/
  else//非merge模式的编码
  {
    inter_pred_idc( pu );//编码几位,确定pu.interDir是多少
    affine_flag   ( *pu.cu );//对宽高都大于8的块,编出来了1-2位确定affine
    smvd_mode( pu );//对pu.interDir == 3,编了1位

    if( pu.interDir != 2 /* PRED_L1 */ )//不是后向参考:即前向参考和双向参考
    {
      ref_idx     ( pu, REF_PIC_LIST_0 );//找到前向的参考哪个帧!!!!!!!

      if ( pu.cu->affine )//如果是affine,编码三个MV值,即6个参数可以得出!!!!
      {
        Mv mvd = pu.mvdAffi[REF_PIC_LIST_0][0];
        mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
        mvd_coding(mvd, 0); // already changed to signaling precision

        mvd = pu.mvdAffi[REF_PIC_LIST_0][1];
        mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
        mvd_coding(mvd, 0); // already changed to signaling precision

        if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
        {
          mvd = pu.mvdAffi[REF_PIC_LIST_0][2];
          mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
          mvd_coding(mvd, 0); // already changed to signaling precision
        }
      }
      else//如果不是affine
      {
        Mv mvd = pu.mvd[REF_PIC_LIST_0];
        mvd.changeTransPrecInternal2Amvr(pu.cu->imv);
        mvd_coding(mvd, 0); // already changed to signaling precision
      }
      
	  mvp_flag    ( pu, REF_PIC_LIST_0 );//使用L0列表:前向参考标志上

    }
    if( pu.interDir != 1 /* PRED_L0 */ )//不是前向参考:即后向参考和双向参考
    {
      if ( pu.cu->smvdMode != 1 )
      {
		ref_idx     ( pu, REF_PIC_LIST_1 ); //找到后向的参考哪个帧!!!!!!!
		  if( !pu.cs->slice->getMvdL1ZeroFlag() || pu.interDir != 3 /* PRED_BI */ )
		  {

			if ( pu.cu->affine )//如果是affine
			{
			  Mv mvd = pu.mvdAffi[REF_PIC_LIST_1][0];
			  mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
			  mvd_coding(mvd, 0); // already changed to signaling precision

			  mvd = pu.mvdAffi[REF_PIC_LIST_1][1];
			  mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
			  mvd_coding(mvd, 0); // already changed to signaling precision

			  if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
			  {
				mvd = pu.mvdAffi[REF_PIC_LIST_1][2];
				mvd.changeAffinePrecInternal2Amvr(pu.cu->imv);
				mvd_coding(mvd, 0); // already changed to signaling precision
			  }
			}

			else//如果不是affine
			{
			  Mv mvd = pu.mvd[REF_PIC_LIST_1];
			  mvd.changeTransPrecInternal2Amvr(pu.cu->imv);
			  mvd_coding(mvd, 0); // already changed to signaling precision
			}
		  }

      }
      mvp_flag    ( pu, REF_PIC_LIST_1 );//使用L1列表:后向参考标志上
    }
  }
}

4.3 具体技术细节

void CABACWriter::smvd_mode( const PredictionUnit& pu )
{
  if ( pu.interDir != 3 || pu.cu->affine )//只有在双向预测且affine时才会smvd
  {
    return;
  }

  if ( pu.cs->slice->getBiDirPred() == false )
  {
    return;
  }

  m_BinEncoder.encodeBin( pu.cu->smvdMode ? 1 : 0, Ctx::SmvdFlag() );

  DTRACE( g_trace_ctx, D_SYNTAX, "symmvd_flag() symmvd=%d pos=(%d,%d) size=%dx%d\n", pu.cu->smvdMode ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height );
}

void CABACWriter::subblock_merge_flag( const CodingUnit& cu )//和affine有挺大的关系
{
#if !JVET_O0249_MERGE_SYNTAX
  if ( cu.firstPU->mergeFlag && (cu.firstPU->mmvdMergeFlag || cu.mmvdSkip) )
  {
    return;
  }
#endif

#if JVET_O0220_METHOD1_SUBBLK_FLAG_PARSING
  if ( !cu.cs->slice->isIntra() && (cu.slice->getMaxNumAffineMergeCand() > 0) && cu.lumaSize().width >= 8 && cu.lumaSize().height >= 8 )
	  //不是帧内模式,亮度块宽高大于8
#else
  if ( !cu.cs->slice->isIntra() && (cu.cs->sps->getUseAffine() || cu.cs->sps->getSBTMVPEnabledFlag()) && cu.lumaSize().width >= 8 && cu.lumaSize().height >= 8 )
#endif
  {
    unsigned ctxId = DeriveCtx::CtxAffineFlag( cu );//用哪个上下文
#if JVET_O0500_SEP_CTX_AFFINE_SUBBLOCK_MRG
    m_BinEncoder.encodeBin( cu.affine, Ctx::SubblockMergeFlag( ctxId ) );//使用子块merge上下文,是affine编1,不是编0
#else
    m_BinEncoder.encodeBin( cu.affine, Ctx::AffineFlag( ctxId ) );
#endif
    DTRACE( g_trace_ctx, D_SYNTAX, "subblock_merge_flag() subblock_merge_flag=%d ctx=%d pos=(%d,%d)\n", cu.affine ? 1 : 0, ctxId, cu.Y().x, cu.Y().y );
  }
}

void CABACWriter::affine_flag( const CodingUnit& cu )
{
  if ( !cu.cs->slice->isIntra() && cu.cs->sps->getUseAffine() && cu.lumaSize().width > 8 && cu.lumaSize().height > 8 )
  {
    unsigned ctxId = DeriveCtx::CtxAffineFlag( cu );
    m_BinEncoder.encodeBin( cu.affine, Ctx::AffineFlag( ctxId ) );//编码是否使用affine
    DTRACE( g_trace_ctx, D_SYNTAX, "affine_flag() affine=%d ctx=%d pos=(%d,%d)\n", cu.affine ? 1 : 0, ctxId, cu.Y().x, cu.Y().y );

    if ( cu.affine && cu.cs->sps->getUseAffineType() )//如果使用的是affine
    {
      unsigned ctxId = 0;
      m_BinEncoder.encodeBin( cu.affineType, Ctx::AffineType( ctxId ) );//编码一下是哪种affine
      DTRACE( g_trace_ctx, D_SYNTAX, "affine_type() affine_type=%d ctx=%d pos=(%d,%d)\n", cu.affineType ? 1 : 0, ctxId, cu.Y().x, cu.Y().y );
    }
  }
}

void CABACWriter::merge_flag( const PredictionUnit& pu )
{
  m_BinEncoder.encodeBin( pu.mergeFlag, Ctx::MergeFlag() );//如果是merge模式,编1;不是编0

  DTRACE( g_trace_ctx, D_SYNTAX, "merge_flag() merge=%d pos=(%d,%d) size=%dx%d\n", pu.mergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height );

#if !JVET_O0249_MERGE_SYNTAX
  if (pu.mergeFlag && CU::isIBC(*pu.cu))
  {
    return;
  }
  if (pu.mergeFlag)
  {
    if (!pu.cs->sps->getUseMMVD() && (pu.lwidth() * pu.lheight() == 32))
    {
      CHECK(!pu.regularMergeFlag, "regular_merge_flag must be true!");
    }
    else
    {
      m_BinEncoder.encodeBin(pu.regularMergeFlag, Ctx::RegularMergeFlag(1));
      DTRACE(g_trace_ctx, D_SYNTAX, "regularMergeFlag() ctx=%d regularMergeFlag=%d\n", 1, pu.regularMergeFlag?1:0);
    }
    if (pu.cs->sps->getUseMMVD())
    {
      bool isCUWithOnlyRegularAndMMVD=((pu.lwidth() == 8 && pu.lheight() == 4) || (pu.lwidth() == 4 && pu.lheight() == 8));
      if (isCUWithOnlyRegularAndMMVD)
      {
        CHECK(pu.mmvdMergeFlag==pu.regularMergeFlag, "mmvdMergeFlag must be !regularMergeFlag");
      }
      else if (!pu.regularMergeFlag)
      {
        m_BinEncoder.encodeBin(pu.mmvdMergeFlag, Ctx::MmvdFlag(0));
        DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_merge_flag() mmvd_merge=%d pos=(%d,%d) size=%dx%d\n", pu.mmvdMergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height);
      }
    }
  }
#endif
}

#if JVET_O0249_MERGE_SYNTAX
void CABACWriter::merge_data(const PredictionUnit& pu)
{
  if (CU::isIBC(*pu.cu))//如果是IBC
  {
    merge_idx(pu);
    return;
  }
  subblock_merge_flag(*pu.cu);//使用子块merge上下文affine编1,不是编0
  if (pu.cu->affine)//如果是affine,编码affine
  {
    merge_idx(pu);
    return;
  }
  const bool triangleAvailable = pu.cu->cs->slice->getSPS()->getUseTriangle() && pu.cu->cs->slice->isInterB() && pu.cu->cs->slice->getMaxNumTriangleCand() > 1;//triangle是否可用
  const bool ciipAvailable = pu.cs->sps->getUseMHIntra() && !pu.cu->skip && pu.cu->lwidth() < MAX_CU_SIZE && pu.cu->lheight() < MAX_CU_SIZE;//ciip是否可用
  if (pu.cu->lwidth() * pu.cu->lheight() >= 64
    && (triangleAvailable || ciipAvailable))//宽*高大于等于64,即8*8,4*16等,且triangleAvailable和ciipAvailable至少一个可用???????????????????
  {
    m_BinEncoder.encodeBin(pu.regularMergeFlag, Ctx::RegularMergeFlag(pu.cu->skip ? 0 : 1));//是正常的merge,编1,不是编0。上下文模型采用判断是否为skip
  }


  if (pu.regularMergeFlag)//如果是普通的merge模式
  {
    if (pu.cs->sps->getUseMMVD())//先看是否使用MMVD技术
    {
      m_BinEncoder.encodeBin(pu.mmvdMergeFlag, Ctx::MmvdFlag(0));
      DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_merge_flag() mmvd_merge=%d pos=(%d,%d) size=%dx%d\n", pu.mmvdMergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height);
    }
    if (pu.mmvdMergeFlag || pu.cu->mmvdSkip)//如果是mmvd,需要编三个值
    {
      mmvd_merge_idx(pu);
    }
    else
    {
      merge_idx(pu);
    }
  }
  else//不是普通的merge模式,即CIIP或triangle或两个都可用
  {
    if (triangleAvailable && ciipAvailable)//如果triangle和ciip都可用
    {
      MHIntra_flag(pu);//都可用,则多编一位MHIntraFlag
    }
    merge_idx(pu);
  }
}
#endif

void CABACWriter::imv_mode( const CodingUnit& cu )
{
  const SPS *sps = cu.cs->sps;

  if( !sps->getAMVREnabledFlag() )//不使用AMVR时,直接返回。即使用AMVR就进这里
  {
    return;
  }
  if ( cu.affine )//非affine时使用
  {
    return;
  }

  bool bNonZeroMvd = CU::hasSubCUNonZeroMVd( cu );
  if( !bNonZeroMvd )
  {
    return;
  }

  if (CU::isIBC(cu) == false)
    m_BinEncoder.encodeBin( (cu.imv > 0), Ctx::ImvFlag( 0 ) ); //编码是不是采用amvr像素精度,不使用:编0
  DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() value=%d ctx=%d\n", (cu.imv > 0), 0 );

  if( sps->getAMVREnabledFlag() && cu.imv > 0 )
  {
#if JVET_O0057_ALTHPELIF
    if (!CU::isIBC(cu))
    {
      m_BinEncoder.encodeBin(cu.imv < IMV_HPEL, Ctx::ImvFlag(4)); //编码是不是采用 1或4 像素精度:  即半像素精度时:编10
      DTRACE(g_trace_ctx, D_SYNTAX, "imv_mode() value=%d ctx=%d\n", cu.imv < 3, 4);
    }
    if (cu.imv < IMV_HPEL)
    {
#endif
    m_BinEncoder.encodeBin( (cu.imv > 1), Ctx::ImvFlag( 1 ) );// 编码是不是采用4像素精度: 即1像素精度时 110 ; 4像素精度时111
    DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() value=%d ctx=%d\n", (cu.imv > 1), 1 );
#if JVET_O0057_ALTHPELIF
    }
#endif
  }

  DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() IMVFlag=%d\n", cu.imv );
}

void CABACWriter::affine_amvr_mode( const CodingUnit& cu )
{
  const SPS* sps = cu.slice->getSPS();

  if( !sps->getAffineAmvrEnabledFlag() || !cu.affine )//affine且amvr时,进入这个里面
  {
    return;
  }

  if ( !CU::hasSubCUNonZeroAffineMVd( cu ) )
  {
    return;
  }

  m_BinEncoder.encodeBin( (cu.imv > 0), Ctx::ImvFlag( 2 ) );//是否使用像素精度:  即不使用时,编0
  DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() value=%d ctx=%d\n", (cu.imv > 0), 2 );

  if( cu.imv > 0 )
  {
    m_BinEncoder.encodeBin( (cu.imv > 1), Ctx::ImvFlag( 3 ) );//是否使用1像素精度: 即使用1像素精度时,编10,其他11
    DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() value=%d ctx=%d\n", (cu.imv > 1), 3 );
  }
  DTRACE( g_trace_ctx, D_SYNTAX, "affine_amvr_mode() IMVFlag=%d\n", cu.imv );
}

void CABACWriter::merge_idx( const PredictionUnit& pu )
{

  if ( pu.cu->affine )//如果是affine===============0
  {
    int numCandminus1 = int( pu.cs->slice->getMaxNumAffineMergeCand() ) - 1;
    if ( numCandminus1 > 0 )
    {
      if ( pu.mergeIdx == 0 )//mergeIdx就是第几个merge,如果是第0个
      {
        m_BinEncoder.encodeBin( 0, Ctx::AffMergeIdx() );//采用Merge上下文来编一个0
        DTRACE( g_trace_ctx, D_SYNTAX, "aff_merge_idx() aff_merge_idx=%d\n", pu.mergeIdx );
        return;
      }
      else//如果不是第0个
      {
        m_BinEncoder.encodeBin( 1, Ctx::AffMergeIdx() );//采用Merge上下文来编一个1
        for ( unsigned idx = 1; idx < numCandminus1; idx++ )//其余的用旁路编码
        {
            m_BinEncoder.encodeBinEP( pu.mergeIdx == idx ? 0 : 1 );
          if ( pu.mergeIdx == idx )
          {
            break;
          }
        }
      }
    }
    DTRACE( g_trace_ctx, D_SYNTAX, "aff_merge_idx() aff_merge_idx=%d\n", pu.mergeIdx );
  }
  else//如果是最常规的merge,和affine相比,单纯的只是上下文不一样了
  {
    if( pu.cu->triangle )//如果是triangle
    {
      bool    splitDir = pu.triangleSplitDir;
      uint8_t candIdx0 = pu.triangleMergeIdx0;
      uint8_t candIdx1 = pu.triangleMergeIdx1;
      DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_split_dir=%d\n", splitDir );
      DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_idx0=%d\n", candIdx0 );
      DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() triangle_idx1=%d\n", candIdx1 );
      candIdx1 -= candIdx1 < candIdx0 ? 0 : 1;//candIdx1比candIdx0小1
      
	  auto encodeOneIdx = [this](uint8_t mrgIdx, int numCandminus1)
      {
        if (numCandminus1 == 0)
        {
          CHECK(mrgIdx, "Incorrect index!");
          return;
        }
        if(mrgIdx == 0)
        {
          this->m_BinEncoder.encodeBin( 0, Ctx::MergeIdx() );
          return;
        }
        else
        {
          this->m_BinEncoder.encodeBin( 1, Ctx::MergeIdx() );
          for( unsigned idx = 1; idx < numCandminus1; idx++ )
          {
            this->m_BinEncoder.encodeBinEP( mrgIdx == idx ? 0 : 1 );
            if( mrgIdx == idx )
            {
              break;
            }
          }
        }
      };

      m_BinEncoder.encodeBinEP(splitDir);//旁路编码splitDir:划分方式是左上到右下,还是右上到左下
      const int maxNumTriangleCand = pu.cs->slice->getMaxNumTriangleCand();
      CHECK(maxNumTriangleCand < 2, "Incorrect max number of triangle candidates");
      CHECK(candIdx0 >= maxNumTriangleCand, "Incorrect candIdx0");
      CHECK(candIdx1 >= maxNumTriangleCand, "Incorrect candIdx1");
      encodeOneIdx(candIdx0, maxNumTriangleCand - 1);//上下文编码candIdx0
      encodeOneIdx(candIdx1, maxNumTriangleCand - 2);//上下文编码candIdx1
      return;
    }
#if JVET_O0455_IBC_MAX_MERGE_NUM
    int numCandminus1;
    if (pu.cu->predMode == MODE_IBC)//如果是IBC模式
      numCandminus1 = int(pu.cs->slice->getMaxNumIBCMergeCand()) - 1;
    else
      numCandminus1 = int(pu.cs->slice->getMaxNumMergeCand()) - 1;
#else
    int numCandminus1 = int(pu.cs->slice->getMaxNumMergeCand()) - 1;
#endif
	  if( numCandminus1 > 0 )
	  {
		if( pu.mergeIdx == 0 )
		{
		  m_BinEncoder.encodeBin( 0, Ctx::MergeIdx() );
		  DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() merge_idx=%d\n", pu.mergeIdx );
		  return;
		}
		else
		{
		  m_BinEncoder.encodeBin( 1, Ctx::MergeIdx() );
		  for( unsigned idx = 1; idx < numCandminus1; idx++ )
		  {
			  m_BinEncoder.encodeBinEP( pu.mergeIdx == idx ? 0 : 1 );
				if( pu.mergeIdx == idx )
				{
				  break;
				}
		  }
		}
	  }
  DTRACE( g_trace_ctx, D_SYNTAX, "merge_idx() merge_idx=%d\n", pu.mergeIdx );
  }
}
void CABACWriter::mmvd_merge_idx(const PredictionUnit& pu)//
{
  int var0, var1, var2;
  int mvpIdx = pu.mmvdMergeIdx;
  var0 = mvpIdx / MMVD_MAX_REFINE_NUM;
  var1 = (mvpIdx - (var0 * MMVD_MAX_REFINE_NUM)) / 4;
  var2 = mvpIdx - (var0 * MMVD_MAX_REFINE_NUM) - var1 * 4;

  if (pu.cs->slice->getMaxNumMergeCand() > 1)
  {
    static_assert(MMVD_BASE_MV_NUM == 2, "");
    assert(var0 < 2);
    m_BinEncoder.encodeBin(var0, Ctx::MmvdMergeIdx());//编var0,上下文模型mmvd_cand_flag
  }
  DTRACE(g_trace_ctx, D_SYNTAX, "base_mvp_idx() base_mvp_idx=%d\n", var0);

  int numCandminus1_step = MMVD_REFINE_STEP - 1;
  if (numCandminus1_step > 0)
  {
    if (var1 == 0)
    {
      m_BinEncoder.encodeBin(0, Ctx::MmvdStepMvpIdx());// var1 == 0时编0,上下文模型MmvdStepMvpIdx
    }
    else
    {
      m_BinEncoder.encodeBin(1, Ctx::MmvdStepMvpIdx()); // var1 != 0时编1,上下文模型MmvdStepMvpIdx,随后旁路编码var1的哪个值是所求
      
	  for (unsigned idx = 1; idx < numCandminus1_step; idx++)//步长
      {
        m_BinEncoder.encodeBinEP(var1 == idx ? 0 : 1);
        if (var1 == idx)
        {
          break;
        }
      }

    }
  }
  DTRACE(g_trace_ctx, D_SYNTAX, "MmvdStepMvpIdx() MmvdStepMvpIdx=%d\n", var1);

  m_BinEncoder.encodeBinsEP(var2, 2);//用2位旁路编var2

  DTRACE(g_trace_ctx, D_SYNTAX, "pos() pos=%d\n", var2);
  DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_merge_idx() mmvd_merge_idx=%d\n", pu.mmvdMergeIdx);
}
void CABACWriter::inter_pred_idc( const PredictionUnit& pu )//帧间模式编码
{
  if( !pu.cs->slice->isInterB() )//B帧要编码几位,P帧不编码
  {
    return;
  }
  if( !(PU::isBipredRestriction(pu)) )
  {
    unsigned ctxId = DeriveCtx::CtxInterDir(pu);
    if( pu.interDir == 3 )//如果interDir == 3,上下文编1并返回
    {
      m_BinEncoder.encodeBin( 1, Ctx::InterDir(ctxId) );
      DTRACE( g_trace_ctx, D_SYNTAX, "inter_pred_idc() ctx=%d value=%d pos=(%d,%d)\n", ctxId, pu.interDir, pu.lumaPos().x, pu.lumaPos().y );
      return;
    }
    else // 如果interDir != 3,上下文编0
    {
      m_BinEncoder.encodeBin( 0, Ctx::InterDir(ctxId) );
    }
  }
  m_BinEncoder.encodeBin( ( pu.interDir == 2 ), Ctx::InterDir( 4 ) ); 如果interDir == 2,上下文编1
  DTRACE( g_trace_ctx, D_SYNTAX, "inter_pred_idc() ctx=4 value=%d pos=(%d,%d)\n", pu.interDir, pu.lumaPos().x, pu.lumaPos().y );
}


void CABACWriter::ref_idx( const PredictionUnit& pu, RefPicList eRefList )
{
  if ( pu.cu->smvdMode )//如果使用了smvd,直接返回
  {
    CHECK( pu.refIdx[eRefList] != pu.cs->slice->getSymRefIdx( eRefList ), "Invalid reference index!\n" );
    return;
  }

  int numRef  = pu.cs->slice->getNumRefIdx(eRefList);//一共多少个

  if (eRefList == REF_PIC_LIST_0 && pu.cs->sps->getIBCFlag())
  {
    if (CU::isIBC(*pu.cu))
      return;
  }

  if( numRef <= 1 )
  {
    return;
  }
  int refIdx  = pu.refIdx[eRefList];//几个参考方向

  m_BinEncoder.encodeBin( (refIdx > 0), Ctx::RefPic() );//标志refIdx(参考图片)是否为0
  if( numRef <= 2 || refIdx == 0 )
  {
    DTRACE( g_trace_ctx, D_SYNTAX, "ref_idx() value=%d pos=(%d,%d)\n", refIdx, pu.lumaPos().x, pu.lumaPos().y );
    return;
  }

  m_BinEncoder.encodeBin( (refIdx > 1), Ctx::RefPic(1) );//标志refIdx(参考图片)是否为1(单向)
  if( numRef <= 3 || refIdx == 1 )
  {
    DTRACE( g_trace_ctx, D_SYNTAX, "ref_idx() value=%d pos=(%d,%d)\n", refIdx, pu.lumaPos().x, pu.lumaPos().y );
    return;
  }


  //下面是超过2个参考图片了
  for( int idx = 3; idx < numRef; idx++ )//编码3到numRef-1的这部分
  {
    if( refIdx > idx - 1 )//比index-1大,则旁路编1
    {
      m_BinEncoder.encodeBinEP( 1 );
    }
    else
    {
      m_BinEncoder.encodeBinEP( 0 );
      break;
    }
  }
  DTRACE( g_trace_ctx, D_SYNTAX, "ref_idx() value=%d pos=(%d,%d)\n", refIdx, pu.lumaPos().x, pu.lumaPos().y );
}

void CABACWriter::mvp_flag( const PredictionUnit& pu, RefPicList eRefList )
{
  m_BinEncoder.encodeBin( pu.mvpIdx[eRefList], Ctx::MVPIdx() );//使用第几个列表
  DTRACE( g_trace_ctx, D_SYNTAX, "mvp_flag() value=%d pos=(%d,%d)\n", pu.mvpIdx[eRefList], pu.lumaPos().x, pu.lumaPos().y );
  DTRACE( g_trace_ctx, D_SYNTAX, "mvpIdx(refList:%d)=%d\n", eRefList, pu.mvpIdx[eRefList] );
}

void CABACWriter::MHIntra_flag(const PredictionUnit& pu)
{
  if (!pu.cs->sps->getUseMHIntra())
  {
    CHECK(pu.mhIntraFlag == true, "invalid MHIntra SPS");
    return;
  }
  if (pu.cu->skip)
  {
    CHECK(pu.mhIntraFlag == true, "invalid MHIntra and skip");
    return;
  }
#if !JVET_O0249_MERGE_SYNTAX
  if (pu.mmvdMergeFlag)
  {
    CHECK(pu.mhIntraFlag == true, "invalid MHIntra and mmvd");
    return;
  }
  if (pu.cu->affine)
  {
    CHECK(pu.mhIntraFlag == true, "invalid MHIntra and affine");
    return;
  }
  if (pu.cu->lwidth() * pu.cu->lheight() < 64 || pu.cu->lwidth() >= MAX_CU_SIZE || pu.cu->lheight() >= MAX_CU_SIZE)
  {
    CHECK(pu.mhIntraFlag == true, "invalid MHIntra and blk");
    return;
  }
#endif
  m_BinEncoder.encodeBin(pu.mhIntraFlag, Ctx::MHIntraFlag());//编一位MHIntraFlag,确定使用的究竟是ciip还是triangle
  DTRACE(g_trace_ctx, D_SYNTAX, "MHIntra_flag() MHIntra=%d pos=(%d,%d) size=%dx%d\n", pu.mhIntraFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height);
}
  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值