[置顶] HEVC帧间预测之一——TComDataCU::getInterMergeCandidates函数分析

从今天开始,正式转入到帧间预测方向。由于帧间预测涉及到的方面广且复杂,所以我的理解出现错误的情况可能会更多,请大家以辩证的眼光来看待我的帖子,有问题欢迎大家批评指正。

 

大家都知道xCompressCU是实际进行预测编码的函数,故很容易就能锁定帧间预测的一个大致范围,在研究了帧内预测的基础上,相信很快就能在该函数中找到与帧间预测相关的函数:xCheckRDCostInter,xCheckRDCostMerge2Nx2N。前者进行除了merge模式以外的所有帧间预测,后者则是针对merge模式的。由于merge模式相对于H.264来说是个新事物,我们考虑先从研究它入手。

 

进入到xCheckRDCostMerge2Nx2N函数后,开头有一个比较重要的函数getInterMergeCandidates,它的功能是创建一个merge list,在该模式中是个很重要的函数,故我们先讨论它。下面按照惯例,给出我对这个函数的注释:

 

Void TComDataCU::getInterMergeCandidates( UInt uiAbsPartIdx, UInt uiPUIdx, TComMvField* pcMvFieldNeighbours, UChar* puhInterDirNeighbours, Int& numValidMergeCand, Int mrgCandIdx )
{
  UInt uiAbsPartAddr = m_uiAbsIdxInLCU + uiAbsPartIdx; //!< 当前CU的ZScan地址
  UInt uiIdx = 1;
  Bool abCandIsInter[ MRG_MAX_NUM_CANDS ];
  for( UInt ui = 0; ui < getSlice()->getMaxNumMergeCand(); ++ui ) //!< m_maxNumMergeCand = 5
  {
    abCandIsInter[ui] = false;
  }
  numValidMergeCand = getSlice()->getMaxNumMergeCand(); //!< 5
  // compute the location of the current PU
  Int xP, yP, nPSW, nPSH;
  this->getPartPosition(uiPUIdx, xP, yP, nPSW, nPSH); //!< 获得当前PU的地址和大小

  Int iCount = 0; //!< 统计Merge candidate的个数

  UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;
  PartSize cCurPS = getPartitionSize( uiAbsPartIdx ); //!< CU的分割模式
  deriveLeftRightTopIdxGeneral( uiAbsPartIdx, uiPUIdx, uiPartIdxLT, uiPartIdxRT ); //!< 左上部,右上部
  deriveLeftBottomIdxGeneral  ( uiAbsPartIdx, uiPUIdx, uiPartIdxLB ); //!< 左下部

  //left
  UInt uiLeftPartIdx = 0;
  TComDataCU* pcCULeft = 0;
  pcCULeft = getPULeft( uiLeftPartIdx, uiPartIdxLB, true, false );
#if MERGE_CLEANUP_AND_K0197 //!< 在有多个PU在一个CU中的时候,去除第二个PU对A1和B1的依赖性
  Bool isAvailableA1 = pcCULeft &&
  pcCULeft->isDiffMER(xP -1, yP+nPSH-1, xP, yP) && //!< 当前PU和它的相邻PU不在同一个ME区域
  !( uiPUIdx == 1 && (cCurPS == SIZE_Nx2N || cCurPS == SIZE_nLx2N || cCurPS == SIZE_nRx2N) ) &&
  !pcCULeft->isIntra( uiLeftPartIdx ) ;
  if ( isAvailableA1 )
#else
  if (pcCULeft)
  {
    if (!pcCULeft->isDiffMER(xP -1, yP+nPSH-1, xP, yP))
    {
      pcCULeft = NULL;
    }
  }
  PartSize partSize = getPartitionSize( uiAbsPartIdx );
  if (!(uiPUIdx == 1 && (partSize == SIZE_Nx2N || partSize == SIZE_nLx2N || partSize == SIZE_nRx2N)))
  {
  if ( pcCULeft && !pcCULeft->isIntra( uiLeftPartIdx ) )
#endif
  {
    abCandIsInter[iCount] = true;
    // get Inter Dir
    puhInterDirNeighbours[iCount] = pcCULeft->getInterDir( uiLeftPartIdx ); //!< inter dir分L0,L1,Bi
    // get Mv from Left,将pcCULeft的MV存放到pcMvFieldNeighbours中
    pcCULeft->getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
    if ( getSlice()->isInterB() )
    {
      pcCULeft->getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
    }
    if ( mrgCandIdx == iCount )
    {
      return;
    }
    iCount ++;
  }
#if !MERGE_CLEANUP_AND_K0197
  }
#endif
  
  // early termination
  if (iCount == getSlice()->getMaxNumMergeCand()) 
  {
    return;
  }
  // above
  UInt uiAbovePartIdx = 0;
  TComDataCU* pcCUAbove = 0;
#if LINEBUF_CLEANUP
  pcCUAbove = getPUAbove( uiAbovePartIdx, uiPartIdxRT, true, false );
#else
  pcCUAbove = getPUAbove( uiAbovePartIdx, uiPartIdxRT, true, false, true );
#endif
#if MERGE_CLEANUP_AND_K0197 //!< 
  Bool isAvailableB1 = pcCUAbove &&
  pcCUAbove->isDiffMER(xP+nPSW-1, yP-1, xP, yP) &&
  !( uiPUIdx == 1 && (cCurPS == SIZE_2NxN || cCurPS == SIZE_2NxnU || cCurPS == SIZE_2NxnD) ) &&
  !pcCUAbove->isIntra( uiAbovePartIdx );
  if ( isAvailableB1 && (!isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAbove, uiAbovePartIdx ) ) )
#else//!< 如果A1可用,则检查A1和B1的MV是否相同,否则不需要检查
  if (pcCUAbove)
  {
    if (!pcCUAbove->isDiffMER(xP+nPSW-1, yP-1, xP, yP))
    {
      pcCUAbove = NULL;
    }
  }
  if ( pcCUAbove && !pcCUAbove->isIntra( uiAbovePartIdx ) 
    && !(uiPUIdx == 1 && (cCurPS == SIZE_2NxN || cCurPS == SIZE_2NxnU || cCurPS == SIZE_2NxnD))
    && ( !pcCULeft || pcCULeft->isIntra( uiLeftPartIdx ) || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAbove, uiAbovePartIdx ) ) )
#endif
  {
    abCandIsInter[iCount] = true;
    // get Inter Dir
    puhInterDirNeighbours[iCount] = pcCUAbove->getInterDir( uiAbovePartIdx );
    // get Mv from Above
    pcCUAbove->getMvField( pcCUAbove, uiAbovePartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
    if ( getSlice()->isInterB() )
    {
      pcCUAbove->getMvField( pcCUAbove, uiAbovePartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
    }
    if ( mrgCandIdx == iCount )
    {
      return;
    }
    iCount ++;
  }
  // early termination
  if (iCount == getSlice()->getMaxNumMergeCand()) 
  {
    return;
  }

  // above right
  UInt uiAboveRightPartIdx = 0;
  TComDataCU* pcCUAboveRight = 0;
#if LINEBUF_CLEANUP
  pcCUAboveRight = getPUAboveRight( uiAboveRightPartIdx, uiPartIdxRT, true, false );
#else
  pcCUAboveRight = getPUAboveRight( uiAboveRightPartIdx, uiPartIdxRT, true, false, true );
#endif
#if MERGE_CLEANUP_AND_K0197
  Bool isAvailableB0 = pcCUAboveRight &&
  pcCUAboveRight->isDiffMER(xP+nPSW, yP-1, xP, yP) &&
  !pcCUAboveRight->isIntra( uiAboveRightPartIdx );
  if ( isAvailableB0 && ( !isAvailableB1 || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveRight, uiAboveRightPartIdx ) ) )
#else//!< 如果B1可用,则检查B1和B0的MV是否相同,否则不需要检查
  if (pcCUAboveRight)
  {
    if (!pcCUAboveRight->isDiffMER(xP+nPSW, yP-1, xP, yP))
    {
      pcCUAboveRight = NULL;
    }
  }
  if ( pcCUAboveRight && !pcCUAboveRight->isIntra( uiAboveRightPartIdx ) && ( !pcCUAbove || pcCUAbove->isIntra( uiAbovePartIdx ) || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveRight, uiAboveRightPartIdx ) ) )
#endif
  {
    abCandIsInter[iCount] = true;
    // get Inter Dir
    puhInterDirNeighbours[iCount] = pcCUAboveRight->getInterDir( uiAboveRightPartIdx );
    // get Mv from AboveRight
    pcCUAboveRight->getMvField( pcCUAboveRight, uiAboveRightPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
    if ( getSlice()->isInterB() )
    {
      pcCUAboveRight->getMvField( pcCUAboveRight, uiAboveRightPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
    }
    if ( mrgCandIdx == iCount )
    {
      return;
    }
    iCount ++;
  }
  // early termination
  if (iCount == getSlice()->getMaxNumMergeCand()) 
  {
    return;
  }

  //left bottom
  UInt uiLeftBottomPartIdx = 0;
  TComDataCU* pcCULeftBottom = 0;
  pcCULeftBottom = this->getPUBelowLeft( uiLeftBottomPartIdx, uiPartIdxLB, true, false );
#if MERGE_CLEANUP_AND_K0197
  Bool isAvailableA0 = pcCULeftBottom &&
  pcCULeftBottom->isDiffMER(xP-1, yP+nPSH, xP, yP) &&
  !pcCULeftBottom->isIntra( uiLeftBottomPartIdx ) ;
  if ( isAvailableA0 && ( !isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCULeftBottom, uiLeftBottomPartIdx ) ) )
#else//!< 如果A1可用,则检查A1和A0的MV是否相同,否则不需要检查
  if (pcCULeftBottom)
  {
    if (!pcCULeftBottom->isDiffMER(xP-1, yP+nPSH, xP, yP))
    {
      pcCULeftBottom = NULL;
    }
  }
  if ( pcCULeftBottom && !pcCULeftBottom->isIntra( uiLeftBottomPartIdx ) && ( !pcCULeft || pcCULeft->isIntra( uiLeftPartIdx ) || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCULeftBottom, uiLeftBottomPartIdx ) ) )
#endif
  {
    abCandIsInter[iCount] = true;
    // get Inter Dir
    puhInterDirNeighbours[iCount] = pcCULeftBottom->getInterDir( uiLeftBottomPartIdx );
    // get Mv from LeftBottom
    pcCULeftBottom->getMvField( pcCULeftBottom, uiLeftBottomPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
    if ( getSlice()->isInterB() )
    {
      pcCULeftBottom->getMvField( pcCULeftBottom, uiLeftBottomPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
    }
    if ( mrgCandIdx == iCount )
    {
      return;
    }
    iCount ++;
  }
  // early termination
  if (iCount == getSlice()->getMaxNumMergeCand()) 
  {
    return;
  }
  // above left 
  if( iCount < 4 )
  {
    UInt uiAboveLeftPartIdx = 0;
    TComDataCU* pcCUAboveLeft = 0;
#if LINEBUF_CLEANUP
    pcCUAboveLeft = getPUAboveLeft( uiAboveLeftPartIdx, uiAbsPartAddr, true, false );
#else
    pcCUAboveLeft = getPUAboveLeft( uiAboveLeftPartIdx, uiAbsPartAddr, true, false, true );
#endif
#if MERGE_CLEANUP_AND_K0197
    Bool isAvailableB2 = pcCUAboveLeft &&
    pcCUAboveLeft->isDiffMER(xP-1, yP-1, xP, yP) &&
    !pcCUAboveLeft->isIntra( uiAboveLeftPartIdx );
    if ( isAvailableB2 && ( !isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) )
        && ( !isAvailableB1 || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) ) )
#else//!< 分别将B2与A1、B1的mv进行比较
    if (pcCUAboveLeft)
    {
      if (!pcCUAboveLeft->isDiffMER(xP-1, yP-1, xP, yP))
      {
        pcCUAboveLeft = NULL;
      }
    }
    if( pcCUAboveLeft && !pcCUAboveLeft->isIntra( uiAboveLeftPartIdx )
     && ( !pcCULeft || pcCULeft->isIntra( uiLeftPartIdx ) || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) )
     && ( !pcCUAbove || pcCUAbove->isIntra( uiAbovePartIdx ) || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) )
     )
#endif
    {
      abCandIsInter[iCount] = true;
      // get Inter Dir
      puhInterDirNeighbours[iCount] = pcCUAboveLeft->getInterDir( uiAboveLeftPartIdx );
      // get Mv from AboveLeft
      pcCUAboveLeft->getMvField( pcCUAboveLeft, uiAboveLeftPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
      if ( getSlice()->isInterB() )
      {
        pcCUAboveLeft->getMvField( pcCUAboveLeft, uiAboveLeftPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
      }
      if ( mrgCandIdx == iCount )
      {
        return;
      }
      iCount ++;
    }
  }
  // early termination
  if (iCount == getSlice()->getMaxNumMergeCand()) //!< 如果可用的merge candidates达到预设的最大值(5),则提前退出
  {
    return;
  }
  if ( getSlice()->getEnableTMVPFlag()) //!< default is 1
  {
    //>> MTK colocated-RightBottom
    UInt uiPartIdxRB;
    Int uiLCUIdx = getAddr();

    deriveRightBottomIdx( uiPUIdx, uiPartIdxRB ); //!< 当前PU的右下部的地址

    UInt uiAbsPartIdxTmp = g_auiZscanToRaster[uiPartIdxRB];
    UInt uiNumPartInCUWidth = m_pcPic->getNumPartInWidth(); //!< CU以partition为单位的宽度

    TComMv cColMv;
    Int iRefIdx;

    if      ( ( m_pcPic->getCU(m_uiCUAddr)->getCUPelX() + g_auiRasterToPelX[uiAbsPartIdxTmp] + m_pcPic->getMinCUWidth() ) >= m_pcSlice->getSPS()->getPicWidthInLumaSamples() )  // image boundary check
    {
      uiLCUIdx = -1;
    }//!< 横坐标超出图像边界
    else if ( ( m_pcPic->getCU(m_uiCUAddr)->getCUPelY() + g_auiRasterToPelY[uiAbsPartIdxTmp] + m_pcPic->getMinCUHeight() ) >= m_pcSlice->getSPS()->getPicHeightInLumaSamples() )
    {
      uiLCUIdx = -1;
    }//!< 纵坐标超出图像边界
    else
    {
      if ( ( uiAbsPartIdxTmp % uiNumPartInCUWidth < uiNumPartInCUWidth - 1 ) &&           // is not at the last column of LCU 
        ( uiAbsPartIdxTmp / uiNumPartInCUWidth < m_pcPic->getNumPartInHeight() - 1 ) ) // is not at the last row    of LCU
      {//!< 不在LCU的最后一列且不在LCU的最后一行,SIZE_NxN的第1个PU
        uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdxTmp + uiNumPartInCUWidth + 1 ]; //!< 下一行+1
        uiLCUIdx = getAddr(); //!< 与当前PU属于相同的CU
      }
      else if ( uiAbsPartIdxTmp % uiNumPartInCUWidth < uiNumPartInCUWidth - 1 )           // is not at the last column of LCU But is last row of LCU
      {//!< 不在LCU的最后一列但在LCU的最后一行,SIZE_Nx2N的第1个PU,SIZE_NxN的第3个PU,SIZE_nLx2N的第1个PU,SIZE_nRx2N的第1个PU
        uiAbsPartAddr = g_auiRasterToZscan[ (uiAbsPartIdxTmp + uiNumPartInCUWidth + 1) % m_pcPic->getNumPartInCU() ];
        uiLCUIdx = -1 ; 
      }
      else if ( uiAbsPartIdxTmp / uiNumPartInCUWidth < m_pcPic->getNumPartInHeight() - 1 ) // is not at the last row of LCU But is last column of LCU
      {//!< 不在LCU的最后一行但在LCU的最后一列,SIZE_2NxN的第1个PU,SIZE_NxN的第2个PU,SIZE_2NxnU的第1个PU,SIZE_2NxnD的第1个PU
        uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdxTmp + 1 ];
        uiLCUIdx = getAddr() + 1;
      }
      else //is the right bottom corner of LCU,SIZE_2Nx2N                       
      {
        uiAbsPartAddr = 0;
        uiLCUIdx = -1 ; 
      }
    }
    iRefIdx = 0;

    Bool bExistMV = false;
    UInt uiPartIdxCenter;
    UInt uiCurLCUIdx = getAddr();
    xDeriveCenterIdx( uiPUIdx, uiPartIdxCenter ); //!< 根据uiPUIdx计算PU的中心地址uiPartIdxCenter
	//! 获取colocated CU的mv,并经scaled过的。
    bExistMV = uiLCUIdx >= 0 && xGetColMVP( REF_PIC_LIST_0, uiLCUIdx, uiAbsPartAddr, cColMv, iRefIdx );
    if( bExistMV == false )
    {
      bExistMV = xGetColMVP( REF_PIC_LIST_0, uiCurLCUIdx, uiPartIdxCenter,  cColMv, iRefIdx );
    }
    if( bExistMV )
    {
      UInt uiArrayAddr = iCount;
      abCandIsInter[uiArrayAddr] = true;
      pcMvFieldNeighbours[uiArrayAddr << 1].setMvField( cColMv, iRefIdx );

      if ( getSlice()->isInterB() )
      {       
        iRefIdx = 0;
        bExistMV = uiLCUIdx >= 0 && xGetColMVP( REF_PIC_LIST_1, uiLCUIdx, uiAbsPartAddr, cColMv, iRefIdx);
        if( bExistMV == false )
        {
          bExistMV = xGetColMVP( REF_PIC_LIST_1, uiCurLCUIdx, uiPartIdxCenter,  cColMv, iRefIdx );
        }
        if( bExistMV )
        {
          pcMvFieldNeighbours[ ( uiArrayAddr << 1 ) + 1 ].setMvField( cColMv, iRefIdx );
          puhInterDirNeighbours[uiArrayAddr] = 3; //!< Bi
        }
        else
        {
          puhInterDirNeighbours[uiArrayAddr] = 1; //!< L0
        }
      }
      else
      {
        puhInterDirNeighbours[uiArrayAddr] = 1; //!< L0
      }
      if ( mrgCandIdx == iCount )
      {
        return;
      }
      iCount++;
    }
    uiIdx++;

  }
  // early termination
  if (iCount == getSlice()->getMaxNumMergeCand()) 
  {
    return;
  }
  UInt uiArrayAddr = iCount;
  UInt uiCutoff = uiArrayAddr;
    
  if ( getSlice()->isInterB())
  {//! 参考draft Table 8-6 ---- Specification of l0CandIdx and l1CandIdx
    UInt uiPriorityList0[12] = {0 , 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3};
    UInt uiPriorityList1[12] = {1 , 0, 2, 0, 2, 1, 3, 0, 3, 1, 3, 2};

    for (Int idx=0; idx<uiCutoff*(uiCutoff-1) && uiArrayAddr!= getSlice()->getMaxNumMergeCand(); idx++)
    {
      Int i = uiPriorityList0[idx]; Int j = uiPriorityList1[idx];
      if (abCandIsInter[i] && abCandIsInter[j]&& (puhInterDirNeighbours[i]&0x1)&&(puhInterDirNeighbours[j]&0x2))
      {
        abCandIsInter[uiArrayAddr] = true;
        puhInterDirNeighbours[uiArrayAddr] = 3;

        // get Mv from cand[i] and cand[j]
        pcMvFieldNeighbours[uiArrayAddr << 1].setMvField(pcMvFieldNeighbours[i<<1].getMv(), pcMvFieldNeighbours[i<<1].getRefIdx());
        pcMvFieldNeighbours[( uiArrayAddr << 1 ) + 1].setMvField(pcMvFieldNeighbours[(j<<1)+1].getMv(), pcMvFieldNeighbours[(j<<1)+1].getRefIdx());

        Int iRefPOCL0 = m_pcSlice->getRefPOC( REF_PIC_LIST_0, pcMvFieldNeighbours[(uiArrayAddr<<1)].getRefIdx() );
        Int iRefPOCL1 = m_pcSlice->getRefPOC( REF_PIC_LIST_1, pcMvFieldNeighbours[(uiArrayAddr<<1)+1].getRefIdx() );
        if (iRefPOCL0 == iRefPOCL1 && pcMvFieldNeighbours[(uiArrayAddr<<1)].getMv() == pcMvFieldNeighbours[(uiArrayAddr<<1)+1].getMv())
        {
          abCandIsInter[uiArrayAddr] = false;
        }
        else
        {
          uiArrayAddr++;
        }
      }
    }
  }
  // early termination
  if (uiArrayAddr == getSlice()->getMaxNumMergeCand()) 
  {
    return;
  }
  //! 当可用的merge candidates数目仍小于预设值时,将余量均设置为零运动矢量
  Int iNumRefIdx = (getSlice()->isInterB()) ? min(m_pcSlice->getNumRefIdx(REF_PIC_LIST_0), m_pcSlice->getNumRefIdx(REF_PIC_LIST_1)) : m_pcSlice->getNumRefIdx(REF_PIC_LIST_0);
  Int r = 0;
  Int refcnt = 0;
  while (uiArrayAddr < getSlice()->getMaxNumMergeCand())
  {
    abCandIsInter[uiArrayAddr] = true;
    puhInterDirNeighbours[uiArrayAddr] = 1;
    pcMvFieldNeighbours[uiArrayAddr << 1].setMvField( TComMv(0, 0), r); //!< 设置为零运动矢量

    if ( getSlice()->isInterB() )
    {
      puhInterDirNeighbours[uiArrayAddr] = 3;
      pcMvFieldNeighbours[(uiArrayAddr << 1) + 1].setMvField(TComMv(0, 0), r);
    }
    uiArrayAddr++;
    if ( refcnt == iNumRefIdx - 1 ) //!< 达到参考帧列表的参考帧数
    {
      r = 0;
    }
    else
    {
      ++r;
      ++refcnt;
    }
  }

  numValidMergeCand = uiArrayAddr;
}


你可能感兴趣的:(merge,HEVC,帧间预测)