美文网首页
Merge模式和AMVP模式

Merge模式和AMVP模式

作者: 温柔的大灰熊 | 来源:发表于2018-04-04 11:20 被阅读0次

    -Merge模式

    Merge模式定义

    Merge模式为当前PU建立一个MV的候选列表(包含5个候选MV及其对应的参考图像)。计算这五个候选MV的率失真代价(RDcost),选取最优的MV。(其中空域最多4个)

    Merge模式候选列表的建立

    空域列表

    列表按照A1→B1→B0→A0(B2是替补)
    若PU不是正方形,则需要注意其他的位置,则A1不存在,因为PU1与PU2MV不能一样(否则就直接是2N*2N模式)

    时域列表

    临近已编码图像中对应位置PU。此时不能直接选择候选块的信息,需要根据与参考图像的位置关系做相应的比例伸缩调整。
    下面是merge模式的代码。

    Void TComDataCU::getInterMergeCandidates( UInt uiAbsPartIdx, UInt uiPUIdx, TComMvField* pcMvFieldNeighbours, UChar* puhInterDirNeighbours, Int& numValidMergeCand, Int mrgCandIdx ) const
    {
      UInt uiAbsPartAddr = m_absZIdxInCtu + uiAbsPartIdx;
      // 候选MV对应的标记
      Bool abCandIsInter[ MRG_MAX_NUM_CANDS ];
      // 先清空列表
      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();
      // compute the location of the current PU 计算当前PU的位置
      Int xP, yP, nPSW, nPSH;  //xp,yp表示location of the upper-left corner pixel of the current PU
      this->getPartPosition(uiPUIdx, xP, yP, nPSW, nPSH);//  nPSW,nPSH       当前PU的大小
    
      Int iCount = 0; // 候选模式的数量
    
      UInt uiPartIdxLT, uiPartIdxRT, uiPartIdxLB;
      PartSize cCurPS = getPartitionSize( uiAbsPartIdx );
      // 转换成索引 
      deriveLeftRightTopIdxGeneral( uiAbsPartIdx, uiPUIdx, uiPartIdxLT, uiPartIdxRT );
      deriveLeftBottomIdxGeneral( uiAbsPartIdx, uiPUIdx, uiPartIdxLB );
    
      // 开始进行空域MV预测,处理的顺序是 左边——>上边——>右上角——>左下角——>左上角
      //left 左侧
      UInt uiLeftPartIdx = 0;
      const TComDataCU *pcCULeft = getPULeft( uiLeftPartIdx, uiPartIdxLB );
    
      Bool isAvailableA1 = pcCULeft &&
                           pcCULeft->isDiffMER(xP -1, yP+nPSH-1, xP, yP) &&
    
                           !( uiPUIdx == 1 && (cCurPS == SIZE_Nx2N || cCurPS == SIZE_nLx2N || cCurPS == SIZE_nRx2N) ) &&
                           pcCULeft->isInter( uiLeftPartIdx ) ;
    
      if ( isAvailableA1 )
      {
        abCandIsInter[iCount] = true;
        // get Inter Dir
        puhInterDirNeighbours[iCount] = pcCULeft->getInterDir( uiLeftPartIdx );
        // get Mv from Left
        TComDataCU::getMvField( pcCULeft, uiLeftPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
        if ( getSlice()->isInterB() )
        {
          TComDataCU::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;
      const TComDataCU *pcCUAbove = getPUAbove( uiAbovePartIdx, uiPartIdxRT );
    
      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
        TComDataCU::getMvField( pcCUAbove, uiAbovePartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
        if ( getSlice()->isInterB() )
        {
          TComDataCU::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;
      const TComDataCU *pcCUAboveRight = getPUAboveRight( uiAboveRightPartIdx, uiPartIdxRT );
    
      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
        TComDataCU::getMvField( pcCUAboveRight, uiAboveRightPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
        if ( getSlice()->isInterB() )
        {
          TComDataCU::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;
      const TComDataCU *pcCULeftBottom = this->getPUBelowLeft( uiLeftBottomPartIdx, uiPartIdxLB );
    
      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
        TComDataCU::getMvField( pcCULeftBottom, uiLeftBottomPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
        if ( getSlice()->isInterB() )
        {
          TComDataCU::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;
        const TComDataCU *pcCUAboveLeft = getPUAboveLeft( uiAboveLeftPartIdx, uiAbsPartAddr );
    
        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
          TComDataCU::getMvField( pcCUAboveLeft, uiAboveLeftPartIdx, REF_PIC_LIST_0, pcMvFieldNeighbours[iCount<<1] );
          if ( getSlice()->isInterB() )
          {
            TComDataCU::getMvField( pcCUAboveLeft, uiAboveLeftPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
          }
          if ( mrgCandIdx == iCount )
          {
            return;
          }
          iCount ++;
        }
      }
      // early termination
      if (iCount == getSlice()->getMaxNumMergeCand())
      {
        return;
      }
    
    
      // 如果使用了TMVP(就是时域的MVP(MVP是MV预测)),上面的都是空域MV预测
      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 );
    
        // 从参考列表中找到预测的MV(xGetColMVP是个比较重要的函数,它的作用是从参考帧中找打MVP)
        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 );
        }
        // 如果是B帧,那么还需要在list中查找
        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帧
      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);
    
      Int r = 0;
      Int refcnt = 0;
    
      // 如果有必要,那么填充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;
    }
    
    /** Check whether the current PU and a spatial neighboring PU are in a same ME region.
     * \param xN, yN   location of the upper-left corner pixel of a neighboring PU
     * \param xP, yP   location of the upper-left corner pixel of the current PU
     */
    Bool TComDataCU::isDiffMER(Int xN, Int yN, Int xP, Int yP) const
    {
    
      UInt plevel = this->getSlice()->getPPS()->getLog2ParallelMergeLevelMinus2() + 2;
      if ((xN>>plevel)!= (xP>>plevel))
      {
        return true;
      }
      if ((yN>>plevel)!= (yP>>plevel))
      {
        return true;
      }
      return false;
    }
    

    相关文章

      网友评论

          本文标题:Merge模式和AMVP模式

          本文链接:https://www.haomeiwen.com/subject/mpdqhftx.html