HEVC代码学习15:AMVP相关函数

来源:互联网 发布:大数据平台 联想 网易 编辑:程序博客网 时间:2024/05/16 04:20

在HEVC中,使用了AMVP技术,利用空域和时域上的运动向量的相关性,为当前PU建立候选预测MV(MVP)列表。编码器从中选出最优的预测MV,并对MV进行差分编码;解码端会构造相同的列表,仅需要运动向量残差(MVD)与预测MV在该列表中的序号即可计算当前PU的MV。
简单来说,AMVP的作用就是建立当前PU的候选MVP列表,运动估计ME会从该列表中找到率失真最优的MVP作为起点,进行搜索。

AMVP整体处理在predInterSearch中完成,主要调用的函数有xEstimateMvPredAMVP,xMotionEstimation,xCopyAMVPInfo,xCheckBestMVP。

主要包含4个过程:
1.调用xEstimateMvPredAMVP建立候选列表并选出最优候选MVP。其中候选列表的建立是通过fillMvpCand函数完成,详见:http://blog.csdn.net/lin453701006/article/details/78419479。
2.调用xMotionEstimation进行运动估计找到最优MV。
3.调用xCheckBestMVP比较更新最优MVP。
4.更新失真和bit信息。

xMotionEstimation在之前已经进行了学习,xCopyAMVPInfo代码很少,很容易看懂,就是完成了AMVP信息的复制,不再详细学习了。下面来学习一下另外两个函数。

xEstimateMvPredAMVP

xEstimateMvPredAMVP首先调用fillMvpCand构造候选列表,然后计算每一个候选的Cost,最后比较Cost找到最优MV设为最优MVP。

// AMVPVoid TEncSearch::xEstimateMvPredAMVP( TComDataCU* pcCU, TComYuv* pcOrgYuv, UInt uiPartIdx, RefPicList eRefPicList, Int iRefIdx, TComMv& rcMvPred, Bool bFilled, Distortion* puiDistBiP ){  AMVPInfo*  pcAMVPInfo = pcCU->getCUMvField(eRefPicList)->getAMVPInfo();   //获取AMVP信息  TComMv     cBestMv;  Int        iBestIdx   = 0;  TComMv     cZeroMv;  TComMv     cMvPred;  Distortion uiBestCost = std::numeric_limits<Distortion>::max();  UInt       uiPartAddr = 0;  Int        iRoiWidth, iRoiHeight;  Int        i;  pcCU->getPartIndexAndSize( uiPartIdx, uiPartAddr, iRoiWidth, iRoiHeight );    //获取PU的地址和尺寸  // Fill the MV Candidates  if (!bFilled)  {    pcCU->fillMvpCand( uiPartIdx, uiPartAddr, eRefPicList, iRefIdx, pcAMVPInfo );   //构造AMVP候选列表  }  // initialize Mvp index & Mvp  iBestIdx = 0;  cBestMv  = pcAMVPInfo->m_acMvCand[0];     //初始化最优MVP为第一个MVP  if (pcAMVPInfo->iN <= 1)  {    rcMvPred = cBestMv;    pcCU->setMVPIdxSubParts( iBestIdx, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr));    pcCU->setMVPNumSubParts( pcAMVPInfo->iN, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr));    if(pcCU->getSlice()->getMvdL1ZeroFlag() && eRefPicList==REF_PIC_LIST_1)    {      (*puiDistBiP) = xGetTemplateCost( pcCU, uiPartAddr, pcOrgYuv, &m_cYuvPredTemp, rcMvPred, 0, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight);    }    return;  }  if (bFilled)  {    assert(pcCU->getMVPIdx(eRefPicList,uiPartAddr) >= 0);    rcMvPred = pcAMVPInfo->m_acMvCand[pcCU->getMVPIdx(eRefPicList,uiPartAddr)];    return;  }  m_cYuvPredTemp.clear();  //-- Check Minimum Cost. 比较代价,找到最优MVP  for ( i = 0 ; i < pcAMVPInfo->iN; i++)  {    Distortion uiTmpCost;       uiTmpCost = xGetTemplateCost( pcCU, uiPartAddr, pcOrgYuv, &m_cYuvPredTemp, pcAMVPInfo->m_acMvCand[i], i, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight);    if ( uiBestCost > uiTmpCost )    {      uiBestCost = uiTmpCost;      cBestMv   = pcAMVPInfo->m_acMvCand[i];      iBestIdx  = i;      (*puiDistBiP) = uiTmpCost;    }  }  m_cYuvPredTemp.clear();  // Setting Best MVP   设置最优MVP  rcMvPred = cBestMv;  pcCU->setMVPIdxSubParts( iBestIdx, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr));  pcCU->setMVPNumSubParts( pcAMVPInfo->iN, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr));  return;}

xCheckBestMVP

在执行完AMVP后,会进行运动估计确定MV。之后通过xCheckBestMVP更新最优MVP。xCheckBestMVP的功能就是在已知MV的情况下,比较当前的MVP和之前最优的MVP的bit数,选择最优MVP。

//已知MV的情况下,找最优MVPVoid TEncSearch::xCheckBestMVP ( TComDataCU* pcCU, RefPicList eRefPicList, TComMv cMv, TComMv& rcMvPred, Int& riMVPIdx, UInt& ruiBits, Distortion& ruiCost ){  AMVPInfo* pcAMVPInfo = pcCU->getCUMvField(eRefPicList)->getAMVPInfo();    //获取AMVP信息  assert(pcAMVPInfo->m_acMvCand[riMVPIdx] == rcMvPred);  if (pcAMVPInfo->iN < 2)   //候选数小于2直接返回  {    return;  }  m_pcRdCost->getMotionCost( true, 0, pcCU->getCUTransquantBypass(0) );  m_pcRdCost->setCostScale ( 0    );  Int iBestMVPIdx = riMVPIdx;   //最优MVP索引置为参考帧MVP索引  m_pcRdCost->setPredictor( rcMvPred );  Int iOrgMvBits  = m_pcRdCost->getBits(cMv.getHor(), cMv.getVer());    //计算当前MV的bit数  iOrgMvBits += m_auiMVPIdxCost[riMVPIdx][AMVP_MAX_NUM_CANDS];      //加参考帧MVP的bit数  Int iBestMvBits = iOrgMvBits;       for (Int iMVPIdx = 0; iMVPIdx < pcAMVPInfo->iN; iMVPIdx++)  {    if (iMVPIdx == riMVPIdx)        {      continue;    }    m_pcRdCost->setPredictor( pcAMVPInfo->m_acMvCand[iMVPIdx] );    Int iMvBits = m_pcRdCost->getBits(cMv.getHor(), cMv.getVer());    iMvBits += m_auiMVPIdxCost[iMVPIdx][AMVP_MAX_NUM_CANDS];    //计算当前MVP的bit数    if (iMvBits < iBestMvBits)      //比较当前MVP和最优MVP,选择最优MVP    {      iBestMvBits = iMvBits;      iBestMVPIdx = iMVPIdx;    }  }  if (iBestMVPIdx != riMVPIdx)  //if changed 如果改变,重置AMVP信息  {    rcMvPred = pcAMVPInfo->m_acMvCand[iBestMVPIdx];     riMVPIdx = iBestMVPIdx;    UInt uiOrgBits = ruiBits;    ruiBits = uiOrgBits - iOrgMvBits + iBestMvBits;    ruiCost = (ruiCost - m_pcRdCost->getCost( uiOrgBits ))  + m_pcRdCost->getCost( ruiBits );  }}
原创粉丝点击