Skip to content
Snippets Groups Projects
UnitTools.cpp 168 KiB
Newer Older
  • Learn to ignore specific revisions
  • Yu Han's avatar
    Yu Han committed
        bool bFound = addMergeHMVPCand(slice, mrgCtx, canFastExit
          , mrgCandIdx
          , maxNumMergeCandMin1, cnt, cnt, isAvailableSubPu, subPuMvpPos
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC
    
    Yu Han's avatar
    Yu Han committed
          , true
    #endif
    #if JVET_M0170_MRG_SHARELIST
    
    Yu Han's avatar
    Yu Han committed
          , false
    
    Yu Han's avatar
    Yu Han committed
    #endif
        );
    #else
        bool bFound = addMergeHMVPCand(slice, mrgCtx, isCandInter, canFastExit
          , mrgCandIdx
          , maxNumMergeCandMin1, cnt, cnt, isAvailableSubPu, subPuMvpPos
        );
    #endif
        if (bFound)
        {
          return;
        }
      }
    
    #if JVET_L0090_PAIR_AVG
      // pairwise-average candidates
      {
        const int cutoff = std::min(cnt, 4);
        const int end = cutoff * (cutoff - 1) / 2;
        constexpr int PRIORITY_LIST0[] = { 0, 0, 1, 0, 1, 2 };
        constexpr int PRIORITY_LIST1[] = { 1, 2, 2, 3, 3, 3 };
    
        for (int idx = 0; idx < end && cnt != maxNumMergeCand; idx++)
        {
          const int i = PRIORITY_LIST0[idx];
          const int j = PRIORITY_LIST1[idx];
    
          mrgCtx.mvFieldNeighbours[cnt * 2].setMvField(Mv(0, 0), NOT_VALID);
          mrgCtx.mvFieldNeighbours[cnt * 2 + 1].setMvField(Mv(0, 0), NOT_VALID);
          // calculate average MV for L0 and L1 seperately
          unsigned char interDir = 0;
    
          for (int refListId = 0; refListId < 1; refListId++)
          {
            const short refIdxI = mrgCtx.mvFieldNeighbours[i * 2 + refListId].refIdx;
            const short refIdxJ = mrgCtx.mvFieldNeighbours[j * 2 + refListId].refIdx;
    
            // both MVs are invalid, skip
            if ((refIdxI == NOT_VALID) && (refIdxJ == NOT_VALID))
            {
              continue;
            }
    
            interDir += 1 << refListId;
            // both MVs are valid, average these two MVs
            if ((refIdxI != NOT_VALID) && (refIdxJ != NOT_VALID))
            {
              const Mv& MvI = mrgCtx.mvFieldNeighbours[i * 2 + refListId].mv;
              const Mv& MvJ = mrgCtx.mvFieldNeighbours[j * 2 + refListId].mv;
    
              // average two MVs
              Mv avgMv = MvI;
    
              avgMv += MvJ;
              mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC;
              avgMv.setHor(avgMv.getHor() / 2);
              avgMv.setVer(avgMv.getVer() / 2);
              avgMv.setHor((avgMv.getHor() / 16) << 4);
              avgMv.setVer((avgMv.getVer() / 16) << 4);
              mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField(avgMv, refIdxI);
            }
          }
          mrgCtx.interDirNeighbours[cnt] = interDir;
          if (interDir > 0)
          {
            cnt++;
          }
        }
    
        // early termination
        if (cnt == maxNumMergeCand)
        {
          return;
        }
      }
    #endif
    
      mrgCtx.numValidMergeCand = cnt;
    
    }
    #endif
    
    
    void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
    
                                     int mmvdList,
                                     const int& mrgCandIdx )
    
    {
      const CodingStructure &cs  = *pu.cs;
      const Slice &slice         = *pu.cs->slice;
      const uint32_t maxNumMergeCand = slice.getMaxNumMergeCand();
      const bool canFastExit     = pu.cs->pps->getLog2ParallelMergeLevelMinus2() == 0;
    
    
    #if !JVET_L0090_PAIR_AVG
      // this variable is unused if remove HEVC combined candidates
    
    Yu-Chi Su's avatar
    Yu-Chi Su committed
    #endif
    
        mrgCtx.GBiIdx[ui] = GBI_DEFAULT;
    
        mrgCtx.interDirNeighbours[ui] = 0;
        mrgCtx.mrgTypeNeighbours [ui] = MRG_TYPE_DEFAULT_N;
        mrgCtx.mvFieldNeighbours[(ui << 1)    ].refIdx = NOT_VALID;
        mrgCtx.mvFieldNeighbours[(ui << 1) + 1].refIdx = NOT_VALID;
      }
    
      mrgCtx.numValidMergeCand = maxNumMergeCand;
      // compute the location of the current PU
    
      int cnt = 0;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Yu Han's avatar
    Yu Han committed
      int mrgCandIdxIBC = mrgCandIdx;
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
    
    #if JVET_M0170_MRG_SHARELIST
      const Position posLT = pu.shareParentPos;
      const Position posRT = pu.shareParentPos.offset(pu.shareParentSize.width - 1, 0);
      const Position posLB = pu.shareParentPos.offset(0, pu.shareParentSize.height - 1);
    #else
    
      const Position posLT = pu.Y().topLeft();
      const Position posRT = pu.Y().topRight();
      const Position posLB = pu.Y().bottomLeft();
    
      MotionInfo miAbove, miLeft, miAboveLeft, miAboveRight, miBelowLeft;
    
      //left
      const PredictionUnit* puLeft = cs.getPURestricted( posLB.offset( -1, 0 ), pu, pu.chType );
    
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC
    
    Yu Han's avatar
    Yu Han committed
      const bool isAvailableA1 = puLeft && isDiffMER(pu, *puLeft) && pu.cu != puLeft->cu && (puLeft->cu->predMode == pu.cu->predMode);
    #else
    
      const bool isAvailableA1 = puLeft && isDiffMER( pu, *puLeft ) && pu.cu != puLeft->cu && CU::isInter( *puLeft->cu );
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    
      if( isAvailableA1 )
      {
        miLeft = puLeft->getMotionInfo( posLB.offset(-1, 0) );
    
    
    
        // get Inter Dir
        mrgCtx.interDirNeighbours[cnt] = miLeft.interDir;
    
        mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeft->cu->GBiIdx : GBI_DEFAULT;
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Yu Han's avatar
    Yu Han committed
        if (puLeft->cu->ibc)
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        {
    
    Yu Han's avatar
    Yu Han committed
          mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          if (mmvdList != 0 && mrgCandIdx != -1)
    
    Yu Han's avatar
    Yu Han committed
            mrgCandIdxIBC++;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        }
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
        mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miLeft.mv[0], miLeft.refIdx[0]);
    
        if (slice.isInterB())
        {
          mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miLeft.mv[1], miLeft.refIdx[1]);
        }
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Yu Han's avatar
    Yu Han committed
        if (mrgCandIdxIBC == cnt && canFastExit)
    
    Yu Han's avatar
    Yu Han committed
    #else
        if (mrgCandIdx == cnt && canFastExit)
    #endif
    
        {
          return;
        }
    
        cnt++;
      }
    
      // early termination
      if (cnt == maxNumMergeCand)
      {
        return;
      }
    
    
      // above
      const PredictionUnit *puAbove = cs.getPURestricted( posRT.offset( 0, -1 ), pu, pu.chType );
    
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC
    
    Yu Han's avatar
    Yu Han committed
      bool isAvailableB1 = puAbove && isDiffMER(pu, *puAbove) && pu.cu != puAbove->cu && puAbove->cu->predMode == pu.cu->predMode;
    #else
    
      bool isAvailableB1 = puAbove && isDiffMER( pu, *puAbove ) && pu.cu != puAbove->cu && CU::isInter( *puAbove->cu );
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    
      if( isAvailableB1 )
      {
        miAbove = puAbove->getMotionInfo( posRT.offset( 0, -1 ) );
    
        if( !isAvailableA1 || ( miAbove != miLeft ) )
        {
    
    
          // get Inter Dir
          mrgCtx.interDirNeighbours[cnt] = miAbove.interDir;
    
          mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAbove->cu->GBiIdx : GBI_DEFAULT;
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Yu Han's avatar
    Yu Han committed
          if (puAbove->cu->ibc)
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          {
    
    Yu Han's avatar
    Yu Han committed
            mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
            if (mmvdList != 0 && mrgCandIdx != -1)
    
    Yu Han's avatar
    Yu Han committed
              mrgCandIdxIBC++;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          }
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAbove.mv[0], miAbove.refIdx[0] );
    
    
          if( slice.isInterB() )
          {
            mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAbove.mv[1], miAbove.refIdx[1] );
          }
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Yu Han's avatar
    Yu Han committed
          if (mrgCandIdxIBC == cnt && canFastExit)
    
    Yu Han's avatar
    Yu Han committed
    #else
          if (mrgCandIdx == cnt && canFastExit)
    #endif
    
          {
            return;
          }
    
          cnt++;
        }
      }
    
      // early termination
      if( cnt == maxNumMergeCand )
      {
        return;
      }
    
      // above right
      const PredictionUnit *puAboveRight = cs.getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
    
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC
    
    Yu Han's avatar
    Yu Han committed
      bool isAvailableB0 = puAboveRight && isDiffMER(pu, *puAboveRight) && (puAboveRight->cu->predMode == pu.cu->predMode);
    #else
    
      bool isAvailableB0 = puAboveRight && isDiffMER( pu, *puAboveRight ) && CU::isInter( *puAboveRight->cu );
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    
      if( isAvailableB0 )
      {
        miAboveRight = puAboveRight->getMotionInfo( posRT.offset( 1, -1 ) );
    
    #if HM_JEM_MERGE_CANDS
        if( ( !isAvailableB1 || ( miAbove != miAboveRight ) ) && ( !isAvailableA1 || ( miLeft != miAboveRight ) ) )
    #else
        if( !isAvailableB1 || ( miAbove != miAboveRight ) )
    #endif
        {
    
    
          // get Inter Dir
          mrgCtx.interDirNeighbours[cnt] = miAboveRight.interDir;
    
          mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveRight->cu->GBiIdx : GBI_DEFAULT;
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Yu Han's avatar
    Yu Han committed
          if (puAboveRight->cu->ibc)
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          {
    
    Yu Han's avatar
    Yu Han committed
            mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
            if (mmvdList != 0 && mrgCandIdx != -1)
    
    Yu Han's avatar
    Yu Han committed
              mrgCandIdxIBC++;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          }
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveRight.mv[0], miAboveRight.refIdx[0] );
    
    
          if( slice.isInterB() )
          {
            mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveRight.mv[1], miAboveRight.refIdx[1] );
          }
    
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Yu Han's avatar
    Yu Han committed
          if (mrgCandIdxIBC == cnt && canFastExit)
    
    Yu Han's avatar
    Yu Han committed
    #else
          if (mrgCandIdx == cnt && canFastExit)
    #endif
    
          {
            return;
          }
    
          cnt++;
        }
      }
      // early termination
      if( cnt == maxNumMergeCand )
      {
        return;
      }
    
      //left bottom
      const PredictionUnit *puLeftBottom = cs.getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType );
    
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC
    
    Yu Han's avatar
    Yu Han committed
      bool isAvailableA0 = puLeftBottom && isDiffMER(pu, *puLeftBottom) && (puLeftBottom->cu->predMode == pu.cu->predMode);
    #else
    
      bool isAvailableA0 = puLeftBottom && isDiffMER( pu, *puLeftBottom ) && CU::isInter( *puLeftBottom->cu );
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    
      if( isAvailableA0 )
      {
        miBelowLeft = puLeftBottom->getMotionInfo( posLB.offset( -1, 1 ) );
    
    #if HM_JEM_MERGE_CANDS
        if( ( !isAvailableA1 || ( miBelowLeft != miLeft ) ) && ( !isAvailableB1 || ( miBelowLeft != miAbove ) ) && ( !isAvailableB0 || ( miBelowLeft != miAboveRight ) ) )
    #else
        if( !isAvailableA1 || ( miBelowLeft != miLeft ) )
    #endif
        {
    
    
          // get Inter Dir
          mrgCtx.interDirNeighbours[cnt] = miBelowLeft.interDir;
    
          mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeftBottom->cu->GBiIdx : GBI_DEFAULT;
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Yu Han's avatar
    Yu Han committed
          if (puLeftBottom->cu->ibc)
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          {
    
    Yu Han's avatar
    Yu Han committed
            mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
            if (mmvdList != 0 && mrgCandIdx != -1)
    
    Yu Han's avatar
    Yu Han committed
              mrgCandIdxIBC++;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          }
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
          mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miBelowLeft.mv[0], miBelowLeft.refIdx[0] );
    
          if( slice.isInterB() )
          {
            mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miBelowLeft.mv[1], miBelowLeft.refIdx[1] );
          }
    
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Yu Han's avatar
    Yu Han committed
          if (mrgCandIdxIBC == cnt && canFastExit)
    
    Yu Han's avatar
    Yu Han committed
    #else
          if (mrgCandIdx == cnt && canFastExit)
    #endif
    
      {
        const PredictionUnit *puAboveLeft = cs.getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType );
    
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC
    
    Yu Han's avatar
    Yu Han committed
        bool isAvailableB2 = puAboveLeft && isDiffMER(pu, *puAboveLeft) && (puAboveLeft->cu->predMode == pu.cu->predMode);
    #else
    
        bool isAvailableB2 = puAboveLeft && isDiffMER( pu, *puAboveLeft ) && CU::isInter( *puAboveLeft->cu );
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    
        if( isAvailableB2 )
        {
          miAboveLeft = puAboveLeft->getMotionInfo( posLT.offset( -1, -1 ) );
    
    #if HM_JEM_MERGE_CANDS
          if( ( !isAvailableA1 || ( miLeft != miAboveLeft ) ) && ( !isAvailableB1 || ( miAbove != miAboveLeft ) ) && ( !isAvailableA0 || ( miBelowLeft != miAboveLeft ) ) && ( !isAvailableB0 || ( miAboveRight != miAboveLeft ) ) )
    #else
          if( ( !isAvailableA1 || ( miLeft != miAboveLeft ) ) && ( !isAvailableB1 || ( miAbove != miAboveLeft ) ) )
    #endif
          {
    
    
            // get Inter Dir
            mrgCtx.interDirNeighbours[cnt] = miAboveLeft.interDir;
    
            mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveLeft->cu->GBiIdx : GBI_DEFAULT;
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Yu Han's avatar
    Yu Han committed
            if (puAboveLeft->cu->ibc)
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
            {
    
    Yu Han's avatar
    Yu Han committed
              mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
              if (mmvdList != 0 && mrgCandIdx != -1)
    
    Yu Han's avatar
    Yu Han committed
                mrgCandIdxIBC++;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
            }
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
            mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveLeft.mv[0], miAboveLeft.refIdx[0] );
    
            if( slice.isInterB() )
            {
              mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveLeft.mv[1], miAboveLeft.refIdx[1] );
            }
    
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Yu Han's avatar
    Yu Han committed
            if (mrgCandIdxIBC == cnt && canFastExit)
    
    Yu Han's avatar
    Yu Han committed
    #else
            if (mrgCandIdx == cnt && canFastExit)
    #endif
    
            {
              return;
            }
    
            cnt++;
          }
        }
      }
      // early termination
      if (cnt == maxNumMergeCand)
      {
        return;
      }
    
      if (slice.getEnableTMVPFlag())
      {
        //>> MTK colocated-RightBottom
        // offset the pos to be sure to "point" to the same position the uiAbsPartIdx would've pointed to
    
    #if JVET_M0170_MRG_SHARELIST
        Position posRB = pu.shareParentPos.offset(pu.shareParentSize.width-3, pu.shareParentSize.height - 3);
    #else
    
        Position posRB = pu.Y().bottomRight().offset(-3, -3);
    
    #if JVET_M0170_MRG_SHARELIST
        Position posC1 = pu.shareParentPos.offset((pu.shareParentSize.width/2), (pu.shareParentSize.height/2));
    #else
    
    #if JVET_M0170_MRG_SHARELIST
        bool C1Avail = (posC1.x < pcv.lumaWidth) && (posC1.y  < pcv.lumaHeight);
    #endif
    
    
        if (((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight))
        {
          {
            Position posInCtu( posRB.x & pcv.maxCUWidthMask, posRB.y & pcv.maxCUHeightMask );
    
            if( ( posInCtu.x + 4 < pcv.maxCUWidth ) &&           // is not at the last column of CTU
                ( posInCtu.y + 4 < pcv.maxCUHeight ) )           // is not at the last row    of CTU
            {
              posC0 = posRB.offset( 4, 4 );
              C0Avail = true;
            }
            else if( posInCtu.x + 4 < pcv.maxCUWidth )           // is not at the last column of CTU But is last row of CTU
            {
              posC0 = posRB.offset( 4, 4 );
              // in the reference the CTU address is not set - thus probably resulting in no using this C0 possibility
            }
            else if( posInCtu.y + 4 < pcv.maxCUHeight )          // is not at the last row of CTU But is last column of CTU
            {
              posC0 = posRB.offset( 4, 4 );
              C0Avail = true;
            }
            else //is the right bottom corner of CTU
            {
              posC0 = posRB.offset( 4, 4 );
              // same as for last column but not last row
            }
          }
        }
    
        Mv        cColMv;
        int       iRefIdx     = 0;
        int       dir         = 0;
        unsigned  uiArrayAddr = cnt;
        bool      bExistMV    = ( C0Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC0, cColMv, iRefIdx ) )
    
    #if JVET_M0170_MRG_SHARELIST
                                          || ( C1Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC1, cColMv, iRefIdx ));
    #else
    
                                          || getColocatedMVP(pu, REF_PIC_LIST_0, posC1, cColMv, iRefIdx );
    
    
        if (bExistMV)
        {
          dir     |= 1;
          mrgCtx.mvFieldNeighbours[2 * uiArrayAddr].setMvField(cColMv, iRefIdx);
        }
    
        if (slice.isInterB())
        {
          bExistMV = ( C0Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC0, cColMv, iRefIdx ) )
    
    #if JVET_M0170_MRG_SHARELIST
                               || (C1Avail &&  getColocatedMVP(pu, REF_PIC_LIST_1, posC1, cColMv, iRefIdx ) );
    #else
    
                               || getColocatedMVP(pu, REF_PIC_LIST_1, posC1, cColMv, iRefIdx );
    
          if (bExistMV)
          {
            dir     |= 2;
            mrgCtx.mvFieldNeighbours[2 * uiArrayAddr + 1].setMvField(cColMv, iRefIdx);
          }
        }
    
        if( dir != 0 )
        {
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC
    
    Yu Han's avatar
    Yu Han committed
          bool addTMvp = !CU::isIBC(*pu.cu);
    #else
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
          for( int i = 0; i < iSpanCand; i++ )
          {
            if( mrgCtx.interDirNeighbours[  i           ] == dir &&
                mrgCtx.mvFieldNeighbours [  i << 1      ] == mrgCtx.mvFieldNeighbours[  uiArrayAddr << 1      ] &&
                mrgCtx.mvFieldNeighbours [( i << 1 ) + 1] == mrgCtx.mvFieldNeighbours[( uiArrayAddr << 1 ) + 1] )
            {
              addTMvp = false;
            }
          }
    #endif
          if( addTMvp )
          {
            mrgCtx.interDirNeighbours[uiArrayAddr] = dir;
    
            mrgCtx.GBiIdx[uiArrayAddr] = GBI_DEFAULT;
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Yu Han's avatar
    Yu Han committed
            if (mrgCandIdxIBC == cnt && canFastExit)
    
    Yu Han's avatar
    Yu Han committed
    #else
            if (mrgCandIdx == cnt && canFastExit)
    #endif
    
      int maxNumMergeCandMin1 = maxNumMergeCand - 1;
      if (cnt != maxNumMergeCandMin1)
      {
    
        bool isAvailableSubPu = false;
        unsigned subPuMvpPos = 0;
    
    #if JVET_L0090_PAIR_AVG
    
    #if JVET_M0170_MRG_SHARELIST
        bool  isShared = ((pu.Y().lumaSize().width != pu.shareParentSize.width) || (pu.Y().lumaSize().height != pu.shareParentSize.height));
    #endif
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        bool bFound = addMergeHMVPCand(slice, mrgCtx, canFastExit
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Yu Han's avatar
    Yu Han committed
          , (mmvdList != 0 && mrgCandIdx != -1) ? (const int) mrgCandIdxIBC : mrgCandIdx
    
    Yu Han's avatar
    Yu Han committed
    #else
          , mrgCandIdx
    #endif
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          , maxNumMergeCandMin1, cnt, cnt, isAvailableSubPu, subPuMvpPos
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          , mmvdList
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC
    
    Yu Han's avatar
    Yu Han committed
          , CU::isIBC(*pu.cu)
    #endif
    
    #if JVET_M0170_MRG_SHARELIST
          , isShared
    #endif
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        );
    #else
        bool bFound = addMergeHMVPCand(slice, mrgCtx, isCandInter, canFastExit
    
    Yu Han's avatar
    Yu Han committed
          , (mmvdList != 0 && mrgCandIdx != -1) ? (const int)mrgCandIdxIBC : mrgCandIdx
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          , maxNumMergeCandMin1, cnt, cnt, isAvailableSubPu, subPuMvpPos
          , mmvdList
        );
    
    #if JVET_L0090_PAIR_AVG
      // pairwise-average candidates
      {
    
        const int cutoff = std::min( cnt, 4 );
        const int end = cutoff * (cutoff - 1) / 2;
        constexpr int PRIORITY_LIST0[] = { 0, 0, 1, 0, 1, 2 };
        constexpr int PRIORITY_LIST1[] = { 1, 2, 2, 3, 3, 3 };
    
    #if JVET_M0193_PAIR_AVG_REDUCTION
        // skip when only 1 candidate is added so far or one is BV and one is MV
        if( cnt > 1 && cnt < maxNumMergeCand && !(mrgCtx.mrgTypeNeighbours[0] != mrgCtx.mrgTypeNeighbours[1] && pu.cs->sps->getSpsNext().getIBCMode()))
    #else
    
        for( int idx = 0; idx < end && cnt != maxNumMergeCand; idx++ )
    
          const int i = PRIORITY_LIST0[idx];
          const int j = PRIORITY_LIST1[idx];
    
    
          mrgCtx.mvFieldNeighbours[cnt * 2].setMvField( Mv( 0, 0 ), NOT_VALID );
          mrgCtx.mvFieldNeighbours[cnt * 2 + 1].setMvField( Mv( 0, 0 ), NOT_VALID );
          // calculate average MV for L0 and L1 seperately
          unsigned char interDir = 0;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          // skip when one is BV and one is MV
    
    Yu Han's avatar
    Yu Han committed
          if (mrgCtx.mrgTypeNeighbours[i] != mrgCtx.mrgTypeNeighbours[j] && pu.cs->sps->getSpsNext().getIBCMode())
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          {
            continue;
          }
    
          for( int refListId = 0; refListId < (slice.isInterB() ? 2 : 1); refListId++ )
          {
    
    #if JVET_M0193_PAIR_AVG_REDUCTION
            const short refIdxI = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].refIdx;
            const short refIdxJ = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].refIdx;
    #else
    
            const short refIdxI = mrgCtx.mvFieldNeighbours[i * 2 + refListId].refIdx;
            const short refIdxJ = mrgCtx.mvFieldNeighbours[j * 2 + refListId].refIdx;
    
    
            // both MVs are invalid, skip
            if( (refIdxI == NOT_VALID) && (refIdxJ == NOT_VALID) )
            {
              continue;
            }
    
            interDir += 1 << refListId;
            // both MVs are valid, average these two MVs
            if( (refIdxI != NOT_VALID) && (refIdxJ != NOT_VALID) )
            {
    
    #if JVET_M0193_PAIR_AVG_REDUCTION
              const Mv& MvI = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].mv;
              const Mv& MvJ = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].mv;
    #else
    
              const Mv& MvI = mrgCtx.mvFieldNeighbours[i * 2 + refListId].mv;
              const Mv& MvJ = mrgCtx.mvFieldNeighbours[j * 2 + refListId].mv;
    
    #if JVET_M0265_MV_ROUNDING_CLEANUP
              roundAffineMv(avgMv.hor, avgMv.ver, 1);
    #else
    
              avgMv.setHor( avgMv.getHor() / 2 );
              avgMv.setVer( avgMv.getVer() / 2 );
    
    #if JVET_M0193_PAIR_AVG_REDUCTION
              if (mrgCtx.mrgTypeNeighbours[0] == MRG_TYPE_IBC && mrgCtx.mrgTypeNeighbours[1] == MRG_TYPE_IBC && pu.cs->sps->getSpsNext().getIBCMode())
    #else
    
    Yu Han's avatar
    Yu Han committed
              if (mrgCtx.mrgTypeNeighbours[i] == MRG_TYPE_IBC && mrgCtx.mrgTypeNeighbours[j] == MRG_TYPE_IBC && pu.cs->sps->getSpsNext().getIBCMode())
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
              {
    
    Yu Han's avatar
    Yu Han committed
                 mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
                 avgMv.setHor((avgMv.getHor() / 16) << 4);
                 avgMv.setVer((avgMv.getVer() / 16) << 4);
              }
    
    
              mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( avgMv, refIdxI );
            }
            // only one MV is valid, take the only one MV
            else if( refIdxI != NOT_VALID )
            {
    
    #if JVET_M0193_PAIR_AVG_REDUCTION
              Mv singleMv = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].mv;
    #else
    
              Mv singleMv = mrgCtx.mvFieldNeighbours[i * 2 + refListId].mv;
    
              mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( singleMv, refIdxI );
            }
            else if( refIdxJ != NOT_VALID )
            {
    
    #if JVET_M0193_PAIR_AVG_REDUCTION
              Mv singleMv = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].mv;
    #else
    
              Mv singleMv = mrgCtx.mvFieldNeighbours[j * 2 + refListId].mv;
    
              mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( singleMv, refIdxJ );
            }
          }
    
          mrgCtx.interDirNeighbours[cnt] = interDir;
          if( interDir > 0 )
          {
            cnt++;
          }
        }
    
        // early termination
        if( cnt == maxNumMergeCand )
        {
          return;
        }
      }
    #endif
    
    
      uint32_t uiCutoff    = std::min( uiArrayAddr, 3u );
    
      if (slice.isInterB())
      {
        static const uint32_t NUM_PRIORITY_LIST = 12;
        static const uint32_t uiPriorityList0[NUM_PRIORITY_LIST] = { 0 , 1, 0, 2, 1, 2, 0, 3, 1, 3, 2, 3 };
        static const uint32_t 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 != maxNumMergeCand; idx++)
        {
          CHECK( idx >= NUM_PRIORITY_LIST, "Invalid priority list number" );
          int i = uiPriorityList0[idx];
          int j = uiPriorityList1[idx];
          if (isCandInter[i] && isCandInter[j] && (mrgCtx.interDirNeighbours[i] & 0x1) && (mrgCtx.interDirNeighbours[j] & 0x2))
          {
            isCandInter[uiArrayAddr] = true;
            mrgCtx.interDirNeighbours[uiArrayAddr] = 3;
    
            mrgCtx.GBiIdx[uiArrayAddr] = ((mrgCtx.interDirNeighbours[uiArrayAddr] == 3)) ? CU::deriveGbiIdx(mrgCtx.GBiIdx[i], mrgCtx.GBiIdx[j]) : GBI_DEFAULT;
    
    
            // get Mv from cand[i] and cand[j]
            mrgCtx.mvFieldNeighbours[ uiArrayAddr << 1     ].setMvField(mrgCtx.mvFieldNeighbours[ i << 1     ].mv, mrgCtx.mvFieldNeighbours[ i << 1     ].refIdx);
            mrgCtx.mvFieldNeighbours[(uiArrayAddr << 1) + 1].setMvField(mrgCtx.mvFieldNeighbours[(j << 1) + 1].mv, mrgCtx.mvFieldNeighbours[(j << 1) + 1].refIdx);
    
            int iRefPOCL0 = slice.getRefPOC(REF_PIC_LIST_0, mrgCtx.mvFieldNeighbours[(uiArrayAddr << 1)    ].refIdx);
            int iRefPOCL1 = slice.getRefPOC(REF_PIC_LIST_1, mrgCtx.mvFieldNeighbours[(uiArrayAddr << 1) + 1].refIdx);
    
            if( iRefPOCL0 == iRefPOCL1 && mrgCtx.mvFieldNeighbours[( uiArrayAddr << 1 )].mv == mrgCtx.mvFieldNeighbours[( uiArrayAddr << 1 ) + 1].mv )
            {
              isCandInter[uiArrayAddr] = false;
            }
            else
            {
              uiArrayAddr++;
            }
          }
        }
      }
    
      // early termination
      if (uiArrayAddr == maxNumMergeCand)
      {
        return;
      }
    
    
      int iNumRefIdx = slice.isInterB() ? std::min(slice.getNumRefIdx(REF_PIC_LIST_0), slice.getNumRefIdx(REF_PIC_LIST_1)) : slice.getNumRefIdx(REF_PIC_LIST_0);
    
      int r = 0;
      int refcnt = 0;
      while (uiArrayAddr < maxNumMergeCand)
      {
    
        mrgCtx.interDirNeighbours [uiArrayAddr     ] = 1;
    
        mrgCtx.GBiIdx             [uiArrayAddr     ] = GBI_DEFAULT;
    
        mrgCtx.mvFieldNeighbours  [uiArrayAddr << 1].setMvField(Mv(0, 0), r);
    
        if (slice.isInterB())
        {
          mrgCtx.interDirNeighbours [ uiArrayAddr          ] = 3;
          mrgCtx.mvFieldNeighbours  [(uiArrayAddr << 1) + 1].setMvField(Mv(0, 0), r);
        }
    
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        if ( mrgCtx.interDirNeighbours[uiArrayAddr] == 1 && pu.cs->slice->getRefPic(REF_PIC_LIST_0, mrgCtx.mvFieldNeighbours[uiArrayAddr << 1].refIdx)->getPOC() == pu.cs->slice->getPOC())
        {
    
    Yu Han's avatar
    Yu Han committed
          mrgCtx.mrgTypeNeighbours[uiArrayAddr] = MRG_TYPE_IBC;
    
        uiArrayAddr++;
    
        if (refcnt == iNumRefIdx - 1)
        {
          r = 0;
        }
        else
        {
          ++r;
          ++refcnt;
        }
      }
      mrgCtx.numValidMergeCand = uiArrayAddr;
    }
    
    Yu Han's avatar
    Yu Han committed
    // for ibc pu validation
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    bool PU::isBlockVectorValid(PredictionUnit& pu, int xPos, int yPos, int width, int height, int picWidth, int picHeight, int xStartInCU, int yStartInCU, int xBv, int yBv, int ctuSize)
    {
      const int ctuSizeLog2 = g_aucLog2[ctuSize];
    
      int refRightX = xPos + xBv + width - 1;
      int refBottomY = yPos + yBv + height - 1;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      int refLeftX = xPos + xBv;
      int refTopY = yPos + yBv;
    
      if ((xPos + xBv) < 0)
      {
        return false;
      }
      if (refRightX >= picWidth)
      {
        return false;
      }
    
      if ((yPos + yBv) < 0)
      {
        return false;
      }
      if (refBottomY >= picHeight)
      {
        return false;
      }
      if ((xBv + width) > 0 && (yBv + height) > 0)
      {
        return false;
      }
    
      // cannot be in the above CTU row
      if (refTopY >> ctuSizeLog2 < yPos >> ctuSizeLog2)
        return false;
    
      // cannot be in the below CTU row
      if (refBottomY >> ctuSizeLog2 > yPos >> ctuSizeLog2)
      {
        return false;
      }
    
      // in the same CTU line
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0407_IBC_RANGE
    
      if ((refRightX >> ctuSizeLog2 <= xPos >> ctuSizeLog2) && (refLeftX >> ctuSizeLog2 >= (xPos >> ctuSizeLog2) - 1))
    #else
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      if ((refRightX >> ctuSizeLog2 <= xPos >> ctuSizeLog2) && (refLeftX >> ctuSizeLog2 >= (xPos >> ctuSizeLog2)))
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      {
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0407_IBC_RANGE
    
        // in the same CTU, or left CTU
        // if part of ref block is in the left CTU, some area can be referred from the not-yet updated local CTU buffer
        if ((refLeftX >> ctuSizeLog2) == ((xPos >> ctuSizeLog2) - 1))
        {
          // ref block's collocated block in current CTU
          const Position refPosCol = pu.Y().topLeft().offset(xBv + ctuSize, yBv);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          int offset64x = (refPosCol.x >> (ctuSizeLog2 - 1)) << (ctuSizeLog2 - 1);
          int offset64y = (refPosCol.y >> (ctuSizeLog2 - 1)) << (ctuSizeLog2 - 1);
          const Position refPosCol64x64 = {offset64x, offset64y};
    
          if (pu.cs->isDecomp(refPosCol64x64, toChannelType(COMPONENT_Y)))
            return false;
        }
    #endif
    
    Yu Han's avatar
    Yu Han committed
    #if !JVET_M0407_IBC_RANGE
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        // in the same CTU, check if the reference block is already coded
        const Position refPosLT = pu.Y().topLeft().offset(xBv, yBv);
        const Position refPosBR = pu.Y().bottomRight().offset(xBv, yBv);
        const ChannelType      chType = toChannelType(COMPONENT_Y);
        {
          if (!pu.cs->isDecomp(refPosBR, chType))
            return false;
          if (!pu.cs->isDecomp(refPosLT, chType))
            return false;
        }
        return true;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      }
      else
        return false;
    
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0407_IBC_RANGE
    
      // in the same CTU, or valid area from left CTU. Check if the reference block is already coded
      const Position refPosLT = pu.Y().topLeft().offset(xBv, yBv);
      const Position refPosBR = pu.Y().bottomRight().offset(xBv, yBv);
      const ChannelType      chType = toChannelType(COMPONENT_Y);
      if (!pu.cs->isDecomp(refPosBR, chType))
        return false;
      if (!pu.cs->isDecomp(refPosLT, chType))
        return false;
      return true;
    #endif
    
    
    Yu Han's avatar
    Yu Han committed
    }// for ibc pu validation
    
    
    static int xGetDistScaleFactor(const int &iCurrPOC, const int &iCurrRefPOC, const int &iColPOC, const int &iColRefPOC)
    {
      int iDiffPocD = iColPOC - iColRefPOC;
      int iDiffPocB = iCurrPOC - iCurrRefPOC;
    
      if (iDiffPocD == iDiffPocB)
      {
        return 4096;
      }
      else
      {
        int iTDB = Clip3(-128, 127, iDiffPocB);
        int iTDD = Clip3(-128, 127, iDiffPocD);
        int iX = (0x4000 + abs(iTDD / 2)) / iTDD;
        int iScale = Clip3(-4096, 4095, (iTDB * iX + 32) >> 6);
        return iScale;
      }
    }
    
    
    #if JVET_M0512_MOTION_BUFFER_COMPRESSION
    int convertMvFixedToFloat(int32_t val)
    {
      int sign  = val >> 31;
      int scale = floorLog2((val ^ sign) | MV_MANTISSA_UPPER_LIMIT) - (MV_MANTISSA_BITCOUNT - 1);
    
      int exponent;
      int mantissa;
      if (scale >= 0)
      {
        int round = (1 << scale) >> 1;
        int n     = (val + round) >> scale;
        exponent  = scale + ((n ^ sign) >> (MV_MANTISSA_BITCOUNT - 1));
        mantissa  = (n & MV_MANTISSA_UPPER_LIMIT) | (sign << (MV_MANTISSA_BITCOUNT - 1));
      }
      else
      {
        exponent = 0;
        mantissa = val;
      }
    
      return exponent | (mantissa << MV_EXPONENT_BITCOUNT);
    }
    
    int convertMvFloatToFixed(int val)
    {
      int exponent = val & MV_EXPONENT_MASK;
      int mantissa = val >> MV_EXPONENT_BITCOUNT;
      return exponent == 0 ? mantissa : (mantissa ^ MV_MANTISSA_LIMIT) << (exponent - 1);
    }
    
    int roundMvComp(int x)
    {
      return convertMvFloatToFixed(convertMvFixedToFloat(x));
    }
    #endif
    
    
    int PU::getDistScaleFactor(const int &currPOC, const int &currRefPOC, const int &colPOC, const int &colRefPOC)
    {
      return xGetDistScaleFactor(currPOC, currRefPOC, colPOC, colRefPOC);
    }
    
    void PU::getInterMMVDMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx)
    {
      int refIdxList0, refIdxList1;
      int k;
      int currBaseNum = 0;
      const uint16_t maxNumMergeCand = mrgCtx.numValidMergeCand;
    
      for (k = 0; k < maxNumMergeCand; k++)
      {
        if (mrgCtx.mrgTypeNeighbours[k] == MRG_TYPE_DEFAULT_N)
        {
          refIdxList0 = mrgCtx.mvFieldNeighbours[(k << 1)].refIdx;
          refIdxList1 = mrgCtx.mvFieldNeighbours[(k << 1) + 1].refIdx;
    
          if ((refIdxList0 >= 0) && (refIdxList1 >= 0))
          {
            mrgCtx.mmvdBaseMv[currBaseNum][0] = mrgCtx.mvFieldNeighbours[(k << 1)];
            mrgCtx.mmvdBaseMv[currBaseNum][1] = mrgCtx.mvFieldNeighbours[(k << 1) + 1];
          }
          else if (refIdxList0 >= 0)
          {
            mrgCtx.mmvdBaseMv[currBaseNum][0] = mrgCtx.mvFieldNeighbours[(k << 1)];
            mrgCtx.mmvdBaseMv[currBaseNum][1] = MvField(Mv(0, 0), -1);
          }
          else if (refIdxList1 >= 0)
          {
            mrgCtx.mmvdBaseMv[currBaseNum][0] = MvField(Mv(0, 0), -1);
            mrgCtx.mmvdBaseMv[currBaseNum][1] = mrgCtx.mvFieldNeighbours[(k << 1) + 1];
          }
    
          currBaseNum++;
    
          if (currBaseNum == MMVD_BASE_MV_NUM)
            break;
        }
      }