HEVC代码学习32:getInterMergeCandidates函数

来源:互联网 发布:cmm软件内涵 编辑:程序博客网 时间:2024/05/19 04:51

今天来看xCheckRDCostMerge2Nx2N函数中提到的重要函数getInterMergeCandidates,其功能是创建merge候选列表,这里重点来看空域候选列表的建立。

首先来回忆一下merge的空域候选列表。merge候选列表长度为5,空域最多提供4个候选,按顺序依次遍历A1-B1-B0-A0-B2,选出4个候选填入候选列表。注意,空域最终可能提供的候选数量可能少于4个。
这里写图片描述

下面来看getInterMergeCandidates工作流程:
1.初始化准备工作。
2.建立空域候选列表,按顺序依次遍历A1-B1-B0-A0-B2位置PU,对每个位置进行以下操作,选出最多4个候选。
(1)检测是否有效
(2)若有效则写入候选列表记录其MV
(3)检测列表是否已满
3.建立时域候选列表。
4.为B Slice建立组合列表。
5.候选列表未满时,用0填充。

代码分析:

//! Construct a list of merging candidates  构造merge候选列表Void TComDataCU::getInterMergeCandidates( UInt uiAbsPartIdx, UInt uiPUIdx, TComMvField* pcMvFieldNeighbours, UChar* puhInterDirNeighbours, Int& numValidMergeCand, Int mrgCandIdx ){  /******************************************初始化准备工作**************************************/  UInt uiAbsPartAddr = m_absZIdxInCtu + uiAbsPartIdx;       //当前CU的ZScan地址  Bool abCandIsInter[ MRG_MAX_NUM_CANDS ];      //MRG_MAX_NUM_CANDS最大候选数为5  for( UInt ui = 0; ui < getSlice()->getMaxNumMergeCand(); ++ui )  {    abCandIsInter[ui] = false;    pcMvFieldNeighbours[ ( ui << 1 )     ].setRefIdx(NOT_VALID);    pcMvFieldNeighbours[ ( ui << 1 ) + 1 ].setRefIdx(NOT_VALID);  }  numValidMergeCand = getSlice()->getMaxNumMergeCand(); //最大有效候选数为5  // compute the location of the current PU 计算当前PU的位置  Int xP, yP, nPSW, nPSH;  this->getPartPosition(uiPUIdx, xP, yP, nPSW, nPSH);       //获取当前PU的索引、起始坐标、高和宽  Int iCount = 0;  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 );       //获取左侧PU  //判断A1有效性  Bool isAvailableA1 = pcCULeft &&      //左侧PU是否有效                       pcCULeft->isDiffMER(xP -1, yP+nPSH-1, xP, yP) &&     //左侧PU与当前PU是否在同一运动估计区域                       !( uiPUIdx == 1 && (cCurPS == SIZE_Nx2N || cCurPS == SIZE_nLx2N || cCurPS == SIZE_nRx2N) ) &&        //分割模式判断                       pcCULeft->isInter( uiLeftPartIdx ) ;     //帧间预测是否有效  if ( isAvailableA1 )      //A1有效  {    abCandIsInter[iCount] = true;    // get Inter Dir    puhInterDirNeighbours[iCount] = pcCULeft->getInterDir( uiLeftPartIdx );     //获取帧间预测方向    // get Mv from Left    pcCULeft->getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );        //获取左侧PU list0的MV    if ( getSlice()->isInterB() )       //双向预测时,获取list1MV    {      pcCULeft->getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );    }    if ( mrgCandIdx == iCount )    {      return;    }    iCount ++;  }  // early termination 达到最大候选数则退出  if (iCount == getSlice()->getMaxNumMergeCand())     {    return;  }  // above 上方  UInt uiAbovePartIdx = 0;  TComDataCU* pcCUAbove = 0;  pcCUAbove = getPUAbove( uiAbovePartIdx, uiPartIdxRT );  //判断B1有效性  Bool isAvailableB1 = pcCUAbove &&                       pcCUAbove->isDiffMER(xP+nPSW-1, yP-1, xP, yP) &&                       !( uiPUIdx == 1 && (cCurPS == SIZE_2NxN || cCurPS == SIZE_2NxnU || cCurPS == SIZE_2NxnD) ) &&                       pcCUAbove->isInter( uiAbovePartIdx );  if ( isAvailableB1 && (!isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAbove, uiAbovePartIdx ) ) )  {    abCandIsInter[iCount] = true;    // get Inter Dir    puhInterDirNeighbours[iCount] = pcCUAbove->getInterDir( uiAbovePartIdx );    // get Mv from Left    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;  pcCUAboveRight = getPUAboveRight( uiAboveRightPartIdx, uiPartIdxRT );    //判断B0有效性  Bool isAvailableB0 = pcCUAboveRight &&                       pcCUAboveRight->isDiffMER(xP+nPSW, yP-1, xP, yP) &&                       pcCUAboveRight->isInter( uiAboveRightPartIdx );  if ( isAvailableB0 && ( !isAvailableB1 || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveRight, uiAboveRightPartIdx ) ) )  {    abCandIsInter[iCount] = true;    // get Inter Dir    puhInterDirNeighbours[iCount] = pcCUAboveRight->getInterDir( uiAboveRightPartIdx );    // get Mv from Left    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 );  //判断A0有效性  Bool isAvailableA0 = pcCULeftBottom &&                       pcCULeftBottom->isDiffMER(xP-1, yP+nPSH, xP, yP) &&                       pcCULeftBottom->isInter( uiLeftBottomPartIdx ) ;  if ( isAvailableA0 && ( !isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCULeftBottom, uiLeftBottomPartIdx ) ) )  {    abCandIsInter[iCount] = true;    // get Inter Dir    puhInterDirNeighbours[iCount] = pcCULeftBottom->getInterDir( uiLeftBottomPartIdx );    // get Mv from Left    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 )      //空域最多提供4个候选  {    UInt uiAboveLeftPartIdx = 0;    TComDataCU* pcCUAboveLeft = 0;    pcCUAboveLeft = getPUAboveLeft( uiAboveLeftPartIdx, uiAbsPartAddr );    //判断B2有效性    Bool isAvailableB2 = pcCUAboveLeft &&                         pcCUAboveLeft->isDiffMER(xP-1, yP-1, xP, yP) &&                         pcCUAboveLeft->isInter( uiAboveLeftPartIdx );    if ( isAvailableB2 && ( !isAvailableA1 || !pcCULeft->hasEqualMotion( uiLeftPartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) )        && ( !isAvailableB1 || !pcCUAbove->hasEqualMotion( uiAbovePartIdx, pcCUAboveLeft, uiAboveLeftPartIdx ) ) )    {      abCandIsInter[iCount] = true;      // get Inter Dir      puhInterDirNeighbours[iCount] = pcCUAboveLeft->getInterDir( uiAboveLeftPartIdx );      // get Mv from Left      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())  {    return;  }  /******************************************建立时域候选列表**************************************/  //由时域列表最多提供1个候选  if ( getSlice()->getEnableTMVPFlag() )  {    //>> MTK colocated-RightBottom    UInt uiPartIdxRB;    deriveRightBottomIdx( uiPUIdx, uiPartIdxRB );    UInt uiAbsPartIdxTmp = g_auiZscanToRaster[uiPartIdxRB];    const UInt numPartInCtuWidth  = m_pcPic->getNumPartInCtuWidth();    const UInt numPartInCtuHeight = m_pcPic->getNumPartInCtuHeight();    TComMv cColMv;    Int iRefIdx;    Int ctuRsAddr = -1;    if (   ( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelX() + g_auiRasterToPelX[uiAbsPartIdxTmp] + m_pcPic->getMinCUWidth () ) < m_pcSlice->getSPS()->getPicWidthInLumaSamples () )  // image boundary check        && ( ( m_pcPic->getCtu(m_ctuRsAddr)->getCUPelY() + g_auiRasterToPelY[uiAbsPartIdxTmp] + m_pcPic->getMinCUHeight() ) < m_pcSlice->getSPS()->getPicHeightInLumaSamples() ) )    {      if ( ( uiAbsPartIdxTmp % numPartInCtuWidth < numPartInCtuWidth - 1 ) &&           // is not at the last column of CTU        ( uiAbsPartIdxTmp / numPartInCtuWidth < numPartInCtuHeight - 1 ) )              // is not at the last row    of CTU      {        uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdxTmp + numPartInCtuWidth + 1 ];        ctuRsAddr = getCtuRsAddr();      }      else if ( uiAbsPartIdxTmp % numPartInCtuWidth < numPartInCtuWidth - 1 )           // is not at the last column of CTU But is last row of CTU      {        uiAbsPartAddr = g_auiRasterToZscan[ (uiAbsPartIdxTmp + numPartInCtuWidth + 1) % m_pcPic->getNumPartitionsInCtu() ];      }      else if ( uiAbsPartIdxTmp / numPartInCtuWidth < numPartInCtuHeight - 1 )          // is not at the last row of CTU But is last column of CTU      {        uiAbsPartAddr = g_auiRasterToZscan[ uiAbsPartIdxTmp + 1 ];        ctuRsAddr = getCtuRsAddr() + 1;      }      else //is the right bottom corner of CTU      {        uiAbsPartAddr = 0;      }    }    iRefIdx = 0;    Bool bExistMV = false;    UInt uiPartIdxCenter;    Int dir = 0;    UInt uiArrayAddr = iCount;    xDeriveCenterIdx( uiPUIdx, uiPartIdxCenter );    bExistMV = ctuRsAddr >= 0 && xGetColMVP( REF_PIC_LIST_0, ctuRsAddr, uiAbsPartAddr, cColMv, iRefIdx );    if( bExistMV == false )    {      bExistMV = xGetColMVP( REF_PIC_LIST_0, getCtuRsAddr(), uiPartIdxCenter,  cColMv, iRefIdx );    }    if( bExistMV )    {      dir |= 1;      pcMvFieldNeighbours[ 2 * uiArrayAddr ].setMvField( cColMv, iRefIdx );    }    if ( getSlice()->isInterB() )    {      bExistMV = ctuRsAddr >= 0 && xGetColMVP( REF_PIC_LIST_1, ctuRsAddr, uiAbsPartAddr, cColMv, iRefIdx);      if( bExistMV == false )      {        bExistMV = xGetColMVP( REF_PIC_LIST_1, getCtuRsAddr(), uiPartIdxCenter, cColMv, iRefIdx );      }      if( bExistMV )      {        dir |= 2;        pcMvFieldNeighbours[ 2 * uiArrayAddr + 1 ].setMvField( cColMv, iRefIdx );      }    }    if (dir != 0)    {      puhInterDirNeighbours[uiArrayAddr] = dir;      abCandIsInter[uiArrayAddr] = true;      if ( mrgCandIdx == iCount )      {        return;      }      iCount++;    }  }  // early termination  if (iCount == getSlice()->getMaxNumMergeCand())  {    return;  }  UInt uiArrayAddr = iCount;  UInt uiCutoff = uiArrayAddr;  /******************************************为B Slice建立组合列表**************************************/  //给B Slice建立组合列表  if ( getSlice()->isInterB() )  {    static const UInt NUM_PRIORITY_LIST=12;    static const UInt uiPriorityList0[NUM_PRIORITY_LIST] = {0 , 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3};    static const UInt uiPriorityList1[NUM_PRIORITY_LIST] = {1 , 0, 2, 0, 2, 1, 3, 0, 3, 1, 3, 2};    for (Int idx=0; idx<uiCutoff*(uiCutoff-1) && uiArrayAddr!= getSlice()->getMaxNumMergeCand(); idx++)    {      assert(idx<NUM_PRIORITY_LIST);      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;  }  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);    /******************************************列表未满,用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;}
原创粉丝点击