VTM1.0代码阅读:motionCompensation函数

motionCompensation运动补偿,在帧间模式(merge和inter_ME)中,根据之前获取到的Qter精度的mv,就能在参考帧中得到pu的参考块,在pu的参考块位置处,通过亚像素插值来得到亚像素位置的pu的预测像素pred。
总之,MC运动补偿,就是根据运动向量mv,得到当前pu的预测像素。

motionCompensation调用了xPredInterUni函数进行单向预测的运动补偿,调用xPredInterBi函数进行双向预测的运动补偿,
VTM中,调用motionCompensation时,参数eRefPicList只有三种情况:REF_PIC_LIST_0、REF_PIC_LIST_1、REF_PIC_LIST_X,表示前向、后向、不确定。

Void InterPrediction::motionCompensation( PredictionUnit &pu, PelUnitBuf &predBuf, const RefPicList &eRefPicList )
{
        CodingStructure &cs = *pu.cs;
  const PPS &pps            = *cs.pps;
  const SliceType sliceType =  cs.slice->getSliceType();

  if( eRefPicList != REF_PIC_LIST_X )		//指明了pu的参考列表,单向预测
  {																				//使用加权预测
    if( ( ( sliceType == P_SLICE && pps.getUseWP() ) || ( sliceType == B_SLICE && pps.getWPBiPred() ) ) )
    {
      xPredInterUni         ( pu,          eRefPicList, predBuf, true );	//单向预测	最后一个参数为true表示之后还要进行加权预测
      xWeightedPredictionUni( pu, predBuf, eRefPicList, predBuf, -1, m_maxCompIDToPred );	//单向加权预测
    }
    else		//不使用加权预测
    {
      xPredInterUni( pu, eRefPicList, predBuf, false );		//单向预测
    }
  }
  else				//没有指明参考列表,当作Bi处理
  {
    if( xCheckIdenticalMotion( pu ) )		//如果前后两个方向的参考poc相同,mv相同,则归为单向处理
    {
      xPredInterUni( pu, REF_PIC_LIST_0, predBuf, false );	//前向预测
    }
    else
    {
      xPredInterBi( pu, predBuf );		//双向预测	其中会进行双向预测的加权预测
    }
  }
  return;
}

单向预测的运动补偿算法
xPredInterUni调用xPredInterBlk函数进行pu的每个通道的预测像素的获取

Void InterPrediction::xPredInterUni(const PredictionUnit& pu, const RefPicList& eRefPicList, PelUnitBuf& pcYuvPred, const Bool& bi )
{
  const SPS &sps = *pu.cs->sps;

  Int iRefIdx = pu.refIdx[eRefPicList];			//参考帧refIdx
  Mv mv[3];

  {
    mv[0] = pu.mv[eRefPicList];
  }
  clipMv(mv[0], pu.cu->lumaPos(), sps);

  for( UInt comp = COMPONENT_Y; comp < pcYuvPred.bufs.size() && comp <= m_maxCompIDToPred; comp++ )
  {
    const ComponentID compID = ComponentID( comp );			//Y/Cb/Cr
	
    {										//pu块的每个通道,进行运动补偿,获取pu预测像素
      xPredInterBlk( compID, pu, pu.cu->slice->getRefPic( eRefPicList, iRefIdx ), mv[0], pcYuvPred, bi, pu.cu->slice->clpRng( compID )
                    );
    }
  }
}

双向预测的运动补偿算法
双向运动补偿,可以看做是分别进行前向运动补偿和后向运动补偿,分别获得前向的预测像素和后向的预测像素
之后分情况进行加权预测

Void InterPrediction::xPredInterBi(PredictionUnit& pu, PelUnitBuf &pcYuvPred)
{
  const PPS   &pps   = *pu.cs->pps;
  const Slice &slice = *pu.cs->slice;

  for (UInt refList = 0; refList < NUM_REF_PIC_LIST_01; refList++)	//前后向两次单向补偿,合起来就是双向预测运动补偿
  {
    if( pu.refIdx[refList] < 0)
    {
      continue;
    }

    RefPicList eRefPicList = (refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);	//参考列表

    CHECK( pu.refIdx[refList] >= slice.getNumRefIdx( eRefPicList ), "Invalid reference index" );
    m_iRefListIdx = refList;
									//单向运动补偿获得的前向和后向预测像素,存储于m_acYuvPred
    PelUnitBuf pcMbBuf = ( pu.chromaFormat == CHROMA_400 ?
                           PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvPred[refList][0], pcYuvPred.Y())) :
                           PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvPred[refList][0], pcYuvPred.Y()), PelBuf(m_acYuvPred[refList][1], pcYuvPred.Cb()), PelBuf(m_acYuvPred[refList][2], pcYuvPred.Cr())) );

    if (pu.refIdx[0] >= 0 && pu.refIdx[1] >= 0)			//pu的前后向预测皆可用
    {
      xPredInterUni ( pu, eRefPicList, pcMbBuf, true	//单向运动补偿
                     );
    }
    else			//单向预测
    {
      if( ( (pps.getUseWP() && slice.getSliceType() == P_SLICE) || (pps.getWPBiPred() && slice.getSliceType() == B_SLICE) ) )
      {
        xPredInterUni ( pu, eRefPicList, pcMbBuf, true );
      }
      else
      {
        xPredInterUni ( pu, eRefPicList, pcMbBuf, false );		//最后一个参数false,表示不会采用加权预测
      }
    }
  }
			//m_acYuvPred中存储的,就是前面通过单向运动补偿获得的前向和后向预测像素
			//srcPred0为前向运动补偿的预测像素,srcPred1为后向运动补偿的预测像素
  CPelUnitBuf srcPred0 = ( pu.chromaFormat == CHROMA_400 ?
                           CPelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvPred[0][0], pcYuvPred.Y())) :
                           CPelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvPred[0][0], pcYuvPred.Y()), PelBuf(m_acYuvPred[0][1], pcYuvPred.Cb()), PelBuf(m_acYuvPred[0][2], pcYuvPred.Cr())) );
  CPelUnitBuf srcPred1 = ( pu.chromaFormat == CHROMA_400 ?
                           CPelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvPred[1][0], pcYuvPred.Y())) :
                           CPelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvPred[1][0], pcYuvPred.Y()), PelBuf(m_acYuvPred[1][1], pcYuvPred.Cb()), PelBuf(m_acYuvPred[1][2], pcYuvPred.Cr())) );
  if( pps.getWPBiPred() && slice.getSliceType() == B_SLICE )		//加权预测
  {
    xWeightedPredictionBi( pu, srcPred0, srcPred1, pcYuvPred, m_maxCompIDToPred );	//B帧且采用加权预测时,双向加权预测
  }
  else if( pps.getUseWP() && slice.getSliceType() == P_SLICE )
  {
    xWeightedPredictionUni( pu, srcPred0, REF_PIC_LIST_0, pcYuvPred, -1, m_maxCompIDToPred );	//P帧且采用加权预测时,单向加权预测
  }
  else			//平均加权预测
  {
    xWeightedAverage( pu, srcPred0, srcPred1, pcYuvPred, slice.getSPS()->getBitDepths(), slice.clpRngs() );
  }
}

xPredInterBlk调用了filterHor和filterVer进行pu参考块位置的亚像素插值,得到pu预测像素

Void InterPrediction::xPredInterBlk ( const ComponentID& compID, const PredictionUnit& pu, const Picture* refPic, const Mv& _mv, PelUnitBuf& dstPic, const Bool& bi, const ClpRng& clpRng
                                    )
{
  const ChromaFormat  chFmt  = pu.chromaFormat;
  const bool          rndRes = !bi;						//bi表示xPredInterBlk之后是否还需要进行加权预测

  int shiftHor = 2 + ::getComponentScaleX( compID, chFmt );
  int shiftVer = 2 + ::getComponentScaleY( compID, chFmt );
  
  int xFrac = _mv.hor & ( ( 1 << shiftHor ) - 1 );
  int yFrac = _mv.ver & ( ( 1 << shiftVer ) - 1 );		//mv

  PelBuf &dstBuf  = dstPic.bufs[compID];		//存入预测像素
  unsigned width  = dstBuf.width;
  unsigned height = dstBuf.height;

  CPelBuf refBuf;
  {
    Position offset = pu.blocks[compID].pos().offset( _mv.getHor() >> shiftHor, _mv.getVer() >> shiftVer );	//参考块的位置
    refBuf = refPic->getRecoBuf( CompArea( compID, chFmt, offset, pu.blocks[compID].size() ) );		//参考块像素
  }								//注意,运动补偿时参考块用的是reco像素信息

  if( yFrac == 0 )		//根据mv,分别对参考块进行横向纵向插值,获取当期pu的预测像素
  {
    m_if.filterHor(compID, (Pel*) refBuf.buf, refBuf.stride, dstBuf.buf, dstBuf.stride, width, height, xFrac, rndRes, chFmt, clpRng);
  }
  else if( xFrac == 0 )
  {
    m_if.filterVer(compID, (Pel*) refBuf.buf, refBuf.stride, dstBuf.buf, dstBuf.stride, width, height, yFrac, true, rndRes, chFmt, clpRng);
  }
  else
  {
    PelBuf tmpBuf = PelBuf(m_filteredBlockTmp[0][compID], pu.blocks[compID]);

    Int vFilterSize = isLuma(compID) ? NTAPS_LUMA : NTAPS_CHROMA;
    m_if.filterHor(compID, (Pel*) refBuf.buf - ((vFilterSize >> 1) - 1) * refBuf.stride, refBuf.stride, tmpBuf.buf, tmpBuf.stride, width, height + vFilterSize - 1, xFrac, false,         chFmt, clpRng);
    m_if.filterVer(compID, (Pel*) tmpBuf.buf + ((vFilterSize >> 1) - 1) * tmpBuf.stride, tmpBuf.stride, dstBuf.buf, dstBuf.stride, width, height,                   yFrac, false, rndRes, chFmt, clpRng);
  }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值