Skip to content
Snippets Groups Projects
UnitTools.cpp 121 KiB
Newer Older
  • Learn to ignore specific revisions
  •   const PredictionUnit* puLeft = cs.getPURestricted(posLB.offset(-1, 0), pu, pu.chType);
    
    
    Han Huang's avatar
    Han Huang committed
      const bool isAvailableA1 = puLeft && isDiffMER(pu.lumaPos(), posLB.offset(-1, 0), plevel) && pu.cu != puLeft->cu && CU::isInter(*puLeft->cu);
    
    
      if (isAvailableA1)
      {
        miLeft = puLeft->getMotionInfo(posLB.offset(-1, 0));
    
        if (!isAvailableB1 || (miAbove != miLeft))
        {
          // get Inter Dir
          mrgCtx.interDirNeighbours[cnt] = miLeft.interDir;
          mrgCtx.useAltHpelIf[cnt] = miLeft.useAltHpelIf;
    
          mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeft->cu->BcwIdx : BCW_DEFAULT;
    
          // get Mv from Left
          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]);
          }
    
    Remy Foray's avatar
    Remy Foray committed
          if (mrgCandIdx == cnt)
    
    
      // early termination
      if( cnt == maxNumMergeCand )
      {
        return;
      }
    
      // above right
      const PredictionUnit *puAboveRight = cs.getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
    
    
    Han Huang's avatar
    Han Huang committed
      bool isAvailableB0 = puAboveRight && isDiffMER( pu.lumaPos(), posRT.offset(1, -1), plevel) && CU::isInter( *puAboveRight->cu );
    
    
      if( isAvailableB0 )
      {
        miAboveRight = puAboveRight->getMotionInfo( posRT.offset( 1, -1 ) );
    
        if( !isAvailableB1 || ( miAbove != miAboveRight ) )
        {
    
          // get Inter Dir
          mrgCtx.interDirNeighbours[cnt] = miAboveRight.interDir;
    
          mrgCtx.useAltHpelIf[cnt] = miAboveRight.useAltHpelIf;
    
          mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveRight->cu->BcwIdx : BCW_DEFAULT;
    
          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] );
          }
    
    
    Remy Foray's avatar
    Remy Foray committed
          if (mrgCandIdx == cnt)
    
          {
            return;
          }
    
          cnt++;
        }
      }
      // early termination
      if( cnt == maxNumMergeCand )
      {
        return;
      }
    
      //left bottom
      const PredictionUnit *puLeftBottom = cs.getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType );
    
    
    Han Huang's avatar
    Han Huang committed
      bool isAvailableA0 = puLeftBottom && isDiffMER( pu.lumaPos(), posLB.offset(-1, 1), plevel) && CU::isInter( *puLeftBottom->cu );
    
    
      if( isAvailableA0 )
      {
        miBelowLeft = puLeftBottom->getMotionInfo( posLB.offset( -1, 1 ) );
    
        if( !isAvailableA1 || ( miBelowLeft != miLeft ) )
        {
    
          // get Inter Dir
          mrgCtx.interDirNeighbours[cnt] = miBelowLeft.interDir;
    
          mrgCtx.useAltHpelIf[cnt] = miBelowLeft.useAltHpelIf;
    
          mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeftBottom->cu->BcwIdx : BCW_DEFAULT;
    
          // get Mv from Bottom-Left
          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] );
          }
    
    
    Remy Foray's avatar
    Remy Foray committed
          if (mrgCandIdx == cnt)
    
      {
        const PredictionUnit *puAboveLeft = cs.getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType );
    
    
    Han Huang's avatar
    Han Huang committed
        bool isAvailableB2 = puAboveLeft && isDiffMER( pu.lumaPos(), posLT.offset(-1, -1), plevel ) && CU::isInter( *puAboveLeft->cu );
    
    
        if( isAvailableB2 )
        {
          miAboveLeft = puAboveLeft->getMotionInfo( posLT.offset( -1, -1 ) );
    
          if( ( !isAvailableA1 || ( miLeft != miAboveLeft ) ) && ( !isAvailableB1 || ( miAbove != miAboveLeft ) ) )
          {
    
            // get Inter Dir
            mrgCtx.interDirNeighbours[cnt] = miAboveLeft.interDir;
    
            mrgCtx.useAltHpelIf[cnt] = miAboveLeft.useAltHpelIf;
    
            mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveLeft->cu->BcwIdx : BCW_DEFAULT;
    
            // get Mv from Above-Left
            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] );
            }
    
    
    Remy Foray's avatar
    Remy Foray committed
            if (mrgCandIdx == cnt)
    
    Brian Heng's avatar
    Brian Heng committed
      if (slice.getPicHeader()->getEnableTMVPFlag() && (pu.lumaSize().width + pu.lumaSize().height > 12))
    
      {
        //>> MTK colocated-RightBottom
        // offset the pos to be sure to "point" to the same position the uiAbsPartIdx would've pointed to
    
        Position posRB = pu.Y().bottomRight().offset( -3, -3 );
    
        bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight);
    
        const SubPic& curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
    
        if (curSubPic.getTreatedAsPicFlag())
        {
          boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() &&
                          (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom());
    
          int posYInCtu = posRB.y & pcv.maxCUHeightMask;
          if (posYInCtu + 4 < pcv.maxCUHeight)
    
            posC0 = posRB.offset(4, 4);
            C0Avail = true;
    
        bool      bExistMV    = ( C0Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC0, cColMv, iRefIdx, false ) )
                                  || getColocatedMVP( pu, REF_PIC_LIST_0, posC1, cColMv, iRefIdx, false );
    
        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, false ) )
                       || getColocatedMVP( pu, REF_PIC_LIST_1, posC1, cColMv, iRefIdx, false );
    
          if (bExistMV)
          {
            dir     |= 2;
            mrgCtx.mvFieldNeighbours[2 * uiArrayAddr + 1].setMvField(cColMv, iRefIdx);
          }
        }
    
        if( dir != 0 )
        {
    
          if( addTMvp )
          {
            mrgCtx.interDirNeighbours[uiArrayAddr] = dir;
    
            mrgCtx.BcwIdx[uiArrayAddr] = BCW_DEFAULT;
    
            mrgCtx.useAltHpelIf[uiArrayAddr] = false;
    
    Remy Foray's avatar
    Remy Foray committed
            if (mrgCandIdx == cnt)
    
      int maxNumMergeCandMin1 = maxNumMergeCand - 1;
      if (cnt != maxNumMergeCandMin1)
      {
    
        bool isGt4x4 = true;
    
    Remy Foray's avatar
    Remy Foray committed
        bool bFound = addMergeHMVPCand(cs, mrgCtx, mrgCandIdx, maxNumMergeCandMin1, cnt
    
          , isAvailableA1, miLeft, isAvailableB1, miAbove
    
    Yu Han's avatar
    Yu Han committed
          , CU::isIBC(*pu.cu)
    
    Yu Han's avatar
    Yu Han committed
        if (cnt > 1 && cnt < maxNumMergeCand)
    
        {
    
          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;
    
          mrgCtx.useAltHpelIf[cnt] = (mrgCtx.useAltHpelIf[0] == mrgCtx.useAltHpelIf[1]) ? mrgCtx.useAltHpelIf[0] : false;
    
          for( int refListId = 0; refListId < (slice.isInterB() ? 2 : 1); refListId++ )
          {
    
            const short refIdxI = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].refIdx;
            const short refIdxJ = mrgCtx.mvFieldNeighbours[1 * 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[0 * 2 + refListId].mv;
              const Mv& MvJ = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].mv;
    
              roundAffineMv(avgMv.hor, avgMv.ver, 1);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
    
              mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( avgMv, refIdxI );
            }
            // only one MV is valid, take the only one MV
            else if( refIdxI != NOT_VALID )
            {
    
              Mv singleMv = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].mv;
    
              mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( singleMv, refIdxI );
            }
            else if( refIdxJ != NOT_VALID )
            {
    
              Mv singleMv = mrgCtx.mvFieldNeighbours[1 * 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;
        }
      }
    
    
      uint32_t uiArrayAddr = cnt;
    
      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.BcwIdx             [uiArrayAddr     ] = BCW_DEFAULT;
    
        mrgCtx.mvFieldNeighbours  [uiArrayAddr << 1].setMvField(Mv(0, 0), r);
    
        mrgCtx.useAltHpelIf[uiArrayAddr] = false;
    
    
        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;
    }
    
    bool PU::checkDMVRCondition(const PredictionUnit& pu)
    {
    
      WPScalingParam *wp0;
      WPScalingParam *wp1;
      int refIdx0 = pu.refIdx[REF_PIC_LIST_0];
      int refIdx1 = pu.refIdx[REF_PIC_LIST_1];
      pu.cu->slice->getWpScaling(REF_PIC_LIST_0, refIdx0, wp0);
      pu.cu->slice->getWpScaling(REF_PIC_LIST_1, refIdx1, wp1);
    
      if (pu.cs->sps->getUseDMVR() && (!pu.cs->picHeader->getDisDmvrFlag()))
    
      {
        return pu.mergeFlag
          && pu.mergeType == MRG_TYPE_DEFAULT_N
    
          && !pu.cu->affine
          && !pu.mmvdMergeFlag
          && !pu.cu->mmvdSkip
          && PU::isBiPredFromDifferentDirEqDistPoc(pu)
          && (pu.lheight() >= 8)
    
          && (pu.lwidth() >= 8)
          && ((pu.lheight() * pu.lwidth()) >= 128)
    
          && (pu.cu->BcwIdx == BCW_DEFAULT)
    
          && ((!wp0[COMPONENT_Y].bPresentFlag) && (!wp0[COMPONENT_Cb].bPresentFlag) && (!wp0[COMPONENT_Cr].bPresentFlag) && (!wp1[COMPONENT_Y].bPresentFlag) && (!wp1[COMPONENT_Cb].bPresentFlag) && (!wp1[COMPONENT_Cr].bPresentFlag))
    
          && ( refIdx0 < 0 ? true : (pu.cu->slice->getRefPic( REF_PIC_LIST_0, refIdx0 )->isRefScaled( pu.cs->pps ) == false) )
          && ( refIdx1 < 0 ? true : (pu.cu->slice->getRefPic( REF_PIC_LIST_1, refIdx1 )->isRefScaled( pu.cs->pps ) == false) )
    
    
    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;
      }
    }
    
    
    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));
    }
    
    
    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];
          }
    
          mrgCtx.mmvdUseAltHpelIf[currBaseNum] = mrgCtx.useAltHpelIf[k];
    
          currBaseNum++;
    
          if (currBaseNum == MMVD_BASE_MV_NUM)
            break;
        }
      }
    }
    
    bool PU::getColocatedMVP(const PredictionUnit &pu, const RefPicList &eRefPicList, const Position &_pos, Mv& rcMv, const int &refIdx, bool sbFlag)
    
    {
      // don't perform MV compression when generally disabled or subPuMvp is used
    
      const unsigned scale = 4 * std::max<int>(1, 4 * AMVP_DECIMATION_FACTOR / 4);
    
      const unsigned mask  = ~( scale - 1 );
    
      const Position pos = Position{ PosType( _pos.x & mask ), PosType( _pos.y & mask ) };
    
      const Slice &slice = *pu.cs->slice;
    
      // use coldir.
      const Picture* const pColPic = slice.getRefPic(RefPicList(slice.isInterB() ? 1 - slice.getColFromL0Flag() : 0), slice.getColRefIdx());
    
      if( !pColPic )
      {
        return false;
      }
    
    
      // Check the position of colocated block is within a subpicture
    
      const SubPic &curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
    
      if (curSubPic.getTreatedAsPicFlag())
      {
        if (!curSubPic.isContainingPos(pos))
          return false;
      }
    
      RefPicList eColRefPicList = slice.getCheckLDC() ? eRefPicList : RefPicList(slice.getColFromL0Flag());
    
      const MotionInfo& mi = pColPic->cs->getMotionInfo( pos );
    
      if( !mi.isInter )
      {
        return false;
      }
    
    Yu Han's avatar
    Yu Han committed
      if (mi.isIBCmot)
      {
        return false;
      }
      if (CU::isIBC(*pu.cu))
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      {
        return false;
      }
    
      if (sbFlag && !slice.getCheckLDC())
    
        eColRefPicList = eRefPicList;
    
        iColRefIdx = mi.refIdx[eColRefPicList];
        if (iColRefIdx < 0)
        {
          return false;
        }
      }
    
      else
      {
        if (iColRefIdx < 0)
        {
          eColRefPicList = RefPicList(1 - eColRefPicList);
          iColRefIdx = mi.refIdx[eColRefPicList];
    
          if (iColRefIdx < 0)
          {
            return false;
          }
        }
      }
    
    
      const Slice *pColSlice = nullptr;
    
      for( const auto s : pColPic->slices )
      {
        if( s->getIndependentSliceIdx() == mi.sliceIdx )
        {
          pColSlice = s;
          break;
        }
      }
    
      CHECK( pColSlice == nullptr, "Slice segment not found" );
    
      const Slice &colSlice = *pColSlice;
    
      const bool bIsCurrRefLongTerm = slice.getRefPic(eRefPicList, refIdx)->longTerm;
      const bool bIsColRefLongTerm  = colSlice.getIsUsedAsLongTerm(eColRefPicList, iColRefIdx);
    
      if (bIsCurrRefLongTerm != bIsColRefLongTerm)
      {
        return false;
      }
    
    
      // Scale the vector.
      Mv cColMv = mi.mv[eColRefPicList];
    
      cColMv.setHor(roundMvComp(cColMv.getHor()));
      cColMv.setVer(roundMvComp(cColMv.getVer()));
    
    
      if (bIsCurrRefLongTerm /*|| bIsColRefLongTerm*/)
      {
        rcMv = cColMv;
    
        rcMv.clipToStorageBitDepth();
    
      }
      else
      {
        const int currPOC    = slice.getPOC();
        const int colPOC     = colSlice.getPOC();
        const int colRefPOC  = colSlice.getRefPOC(eColRefPicList, iColRefIdx);
        const int currRefPOC = slice.getRefPic(eRefPicList, refIdx)->getPOC();
        const int distscale  = xGetDistScaleFactor(currPOC, currRefPOC, colPOC, colRefPOC);
    
        if (distscale == 4096)
        {
          rcMv = cColMv;
    
          rcMv.clipToStorageBitDepth();
    
    Han Huang's avatar
    Han Huang committed
    bool PU::isDiffMER(const Position &pos1, const Position &pos2, const unsigned plevel)
    {
      const unsigned xN = pos1.x;
      const unsigned yN = pos1.y;
      const unsigned xP = pos2.x;
      const unsigned yP = pos2.y;
    
    
      if ((xN >> plevel) != (xP >> plevel))
      {
        return true;
      }
    
      if ((yN >> plevel) != (yP >> plevel))
      {
        return true;
    
    Han Huang's avatar
    Han Huang committed
      }
    
      return false;
    
    
    bool PU::isAddNeighborMv(const Mv& currMv, Mv* neighborMvs, int numNeighborMv)
    {
      bool existed = false;
      for (uint32_t cand = 0; cand < numNeighborMv && !existed; cand++)
      {
        if (currMv == neighborMvs[cand])
        {
          existed = true;
        }
      }
    
      if (!existed)
      {
        return true;
      }
      else
      {
        return false;
      }
    }
    
    void PU::getIbcMVPsEncOnly(PredictionUnit &pu, Mv* mvPred, int& nbPred)
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    {
    
      const PreCalcValues   &pcv = *pu.cs->pcv;
      const int  cuWidth = pu.blocks[COMPONENT_Y].width;
      const int  cuHeight = pu.blocks[COMPONENT_Y].height;
    
      const int  log2UnitWidth = floorLog2(pcv.minCUWidth);
      const int  log2UnitHeight = floorLog2(pcv.minCUHeight);
    
      const int  totalAboveUnits = (cuWidth >> log2UnitWidth) + 1;
      const int  totalLeftUnits = (cuHeight >> log2UnitHeight) + 1;
    
      nbPred = 0;
      Position posLT = pu.Y().topLeft();
    
      // above-left
    
      const PredictionUnit *aboveLeftPU = pu.cs->getPURestricted(posLT.offset(-1, -1), pu, CHANNEL_TYPE_LUMA);
    
      if (aboveLeftPU && CU::isIBC(*aboveLeftPU->cu))
      {
        if (isAddNeighborMv(aboveLeftPU->bv, mvPred, nbPred))
        {
          mvPred[nbPred++] = aboveLeftPU->bv;
        }
      }
    
      // above neighbors
      for (uint32_t dx = 0; dx < totalAboveUnits && nbPred < IBC_NUM_CANDIDATES; dx++)
      {
    
        const PredictionUnit* tmpPU = pu.cs->getPURestricted(posLT.offset((dx << log2UnitWidth), -1), pu, CHANNEL_TYPE_LUMA);
    
        if (tmpPU && CU::isIBC(*tmpPU->cu))
        {
          if (isAddNeighborMv(tmpPU->bv, mvPred, nbPred))
          {
            mvPred[nbPred++] = tmpPU->bv;
          }
        }
      }
    
      // left neighbors
      for (uint32_t dy = 0; dy < totalLeftUnits && nbPred < IBC_NUM_CANDIDATES; dy++)
      {
    
        const PredictionUnit* tmpPU = pu.cs->getPURestricted(posLT.offset(-1, (dy << log2UnitHeight)), pu, CHANNEL_TYPE_LUMA);
    
        if (tmpPU && CU::isIBC(*tmpPU->cu))
        {
          if (isAddNeighborMv(tmpPU->bv, mvPred, nbPred))
          {
            mvPred[nbPred++] = tmpPU->bv;
          }
        }
      }
    
      size_t numAvaiCandInLUT = pu.cs->motionLut.lutIbc.size();
      for (uint32_t cand = 0; cand < numAvaiCandInLUT && nbPred < IBC_NUM_CANDIDATES; cand++)
      {
        MotionInfo neibMi = pu.cs->motionLut.lutIbc[cand];
        if (isAddNeighborMv(neibMi.bv, mvPred, nbPred))
        {
          mvPred[nbPred++] = neibMi.bv;
        }
      }
    
      bool isBvCandDerived[IBC_NUM_CANDIDATES];
      ::memset(isBvCandDerived, false, IBC_NUM_CANDIDATES);
    
      int curNbPred = nbPred;
      if (curNbPred < IBC_NUM_CANDIDATES)
      {
        do
        {
          curNbPred = nbPred;
          for (uint32_t idx = 0; idx < curNbPred && nbPred < IBC_NUM_CANDIDATES; idx++)
          {
            if (!isBvCandDerived[idx])
            {
              Mv derivedBv;
              if (getDerivedBV(pu, mvPred[idx], derivedBv))
              {
                if (isAddNeighborMv(derivedBv, mvPred, nbPred))
                {
                  mvPred[nbPred++] = derivedBv;
                }
              }
              isBvCandDerived[idx] = true;
            }
          }
        } while (nbPred > curNbPred && nbPred < IBC_NUM_CANDIDATES);
      }
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    }
    
    bool PU::getDerivedBV(PredictionUnit &pu, const Mv& currentMv, Mv& derivedMv)
    {
      int   cuPelX = pu.lumaPos().x;
      int   cuPelY = pu.lumaPos().y;
      int rX = cuPelX + currentMv.getHor();
      int rY = cuPelY + currentMv.getVer();
      int offsetX = currentMv.getHor();
      int offsetY = currentMv.getVer();
    
    
    
      if( rX < 0 || rY < 0 || rX >= pu.cs->slice->getPPS()->getPicWidthInLumaSamples() || rY >= pu.cs->slice->getPPS()->getPicHeightInLumaSamples() )
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      {
        return false;
      }
    
      const PredictionUnit *neibRefPU = NULL;
    
      neibRefPU = pu.cs->getPURestricted(pu.lumaPos().offset(offsetX, offsetY), pu, CHANNEL_TYPE_LUMA);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
    
    Yu Han's avatar
    Yu Han committed
      bool isIBC = (neibRefPU) ? CU::isIBC(*neibRefPU->cu) : 0;
    
    Yu Han's avatar
    Yu Han committed
      if (isIBC)
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      {
        derivedMv = neibRefPU->bv;
        derivedMv += currentMv;
      }
    
    Yu Han's avatar
    Yu Han committed
      return isIBC;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    }
    
    Yu Han's avatar
    Yu Han committed
     * Constructs a list of candidates for IBC AMVP (See specification, section "Derivation process for motion vector predictor candidates")
     */
    
    Yu Han's avatar
    Yu Han committed
    void PU::fillIBCMvpCand(PredictionUnit &pu, AMVPInfo &amvpInfo)
    
    Yu Han's avatar
    Yu Han committed
    {
    
      AMVPInfo *pInfo = &amvpInfo;
    
      pInfo->numCand = 0;
    
    
    
    Yu Han's avatar
    Yu Han committed
      MergeCtx mergeCtx;
      PU::getIBCMergeCandidates(pu, mergeCtx, AMVP_MAX_NUM_CANDS - 1);
      int candIdx = 0;
      while (pInfo->numCand < AMVP_MAX_NUM_CANDS)
      {
        pInfo->mvCand[pInfo->numCand] = mergeCtx.mvFieldNeighbours[(candIdx << 1) + 0].mv;;
        pInfo->numCand++;
        candIdx++;
      }
    
    Yu Han's avatar
    Yu Han committed
    
      for (Mv &mv : pInfo->mvCand)
    
    Xiang Li's avatar
    Xiang Li committed
        mv.roundIbcPrecInternal2Amvr(pu.cu->imv);
    
    /** Constructs a list of candidates for AMVP (See specification, section "Derivation process for motion vector predictor candidates")
    * \param uiPartIdx
    * \param uiPartAddr
    * \param eRefPicList
    * \param iRefIdx
    * \param pInfo
    */
    void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AMVPInfo &amvpInfo)
    {
      CodingStructure &cs = *pu.cs;
    
      AMVPInfo *pInfo = &amvpInfo;
    
      pInfo->numCand = 0;
    
      if (refIdx < 0)
      {
        return;
      }
    
      //-- Get Spatial MV
      Position posLT = pu.Y().topLeft();
      Position posRT = pu.Y().topRight();
      Position posLB = pu.Y().bottomLeft();
    
      {
        bool bAdded = addMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_BELOW_LEFT, *pInfo );
    
        if( !bAdded )
        {
          bAdded = addMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_LEFT, *pInfo );
    
        }
      }
    
      // Above predictor search
      {
        bool bAdded = addMVPCandUnscaled( pu, eRefPicList, refIdx, posRT, MD_ABOVE_RIGHT, *pInfo );
    
        if( !bAdded )
        {
          bAdded = addMVPCandUnscaled( pu, eRefPicList, refIdx, posRT, MD_ABOVE, *pInfo );
    
          if( !bAdded )
          {
            addMVPCandUnscaled( pu, eRefPicList, refIdx, posLT, MD_ABOVE_LEFT, *pInfo );
          }
        }
      }
    
    
    
      for( int i = 0; i < pInfo->numCand; i++ )
      {
    
    Xiang Li's avatar
    Xiang Li committed
        pInfo->mvCand[i].roundTransPrecInternal2Amvr(pu.cu->imv);
    
    
      if( pInfo->numCand == 2 )
      {
        if( pInfo->mvCand[0] == pInfo->mvCand[1] )
        {
          pInfo->numCand = 1;
        }
      }
    
    
    Brian Heng's avatar
    Brian Heng committed
      if (cs.picHeader->getEnableTMVPFlag() && pInfo->numCand < AMVP_MAX_NUM_CANDS && (pu.lumaSize().width + pu.lumaSize().height > 12))
    
      {
        // Get Temporal Motion Predictor
        const int refIdx_Col = refIdx;
    
        Position posRB = pu.Y().bottomRight().offset(-3, -3);
    
        const PreCalcValues& pcv = *cs.pcv;
    
        Position posC0;
        bool C0Avail = false;
        Position posC1 = pu.Y().center();
        Mv cColMv;
    
    
        bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight);
    
        const SubPic &curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos());
    
        if (curSubPic.getTreatedAsPicFlag())
        {
          boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() &&
                          (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom());
    
          int posYInCtu = posRB.y & pcv.maxCUHeightMask;
          if (posYInCtu + 4 < pcv.maxCUHeight)
    
        if ( ( C0Avail && getColocatedMVP( pu, eRefPicList, posC0, cColMv, refIdx_Col, false ) ) || getColocatedMVP( pu, eRefPicList, posC1, cColMv, refIdx_Col, false ) )
    
    Xiang Li's avatar
    Xiang Li committed
          cColMv.roundTransPrecInternal2Amvr(pu.cu->imv);
    
          pInfo->mvCand[pInfo->numCand++] = cColMv;
    
      if (pInfo->numCand < AMVP_MAX_NUM_CANDS)
      {
    
        const int currRefPOC = cs.slice->getRefPic(eRefPicList, refIdx)->getPOC();
        addAMVPHMVPCand(pu, eRefPicList, currRefPOC, *pInfo);
    
      if (pInfo->numCand > AMVP_MAX_NUM_CANDS)
      {
        pInfo->numCand = AMVP_MAX_NUM_CANDS;
      }
    
      while (pInfo->numCand < AMVP_MAX_NUM_CANDS)
      {
        pInfo->mvCand[pInfo->numCand] = Mv( 0, 0 );
        pInfo->numCand++;
      }
    
      for (Mv &mv : pInfo->mvCand)
    
    Xiang Li's avatar
    Xiang Li committed
        mv.roundTransPrecInternal2Amvr(pu.cu->imv);
    
    bool PU::addAffineMVPCandUnscaled( const PredictionUnit &pu, const RefPicList &refPicList, const int &refIdx, const Position &pos, const MvpDir &dir, AffineAMVPInfo &affiAMVPInfo )
    
    {
      CodingStructure &cs = *pu.cs;
      const PredictionUnit *neibPU = NULL;
      Position neibPos;
    
      {
      case MD_LEFT:
        neibPos = pos.offset( -1, 0 );
        break;
      case MD_ABOVE:
        neibPos = pos.offset( 0, -1 );
        break;
      case MD_ABOVE_RIGHT:
        neibPos = pos.offset( 1, -1 );
        break;
      case MD_BELOW_LEFT:
        neibPos = pos.offset( -1, 1 );
        break;
      case MD_ABOVE_LEFT:
        neibPos = pos.offset( -1, -1 );
        break;
      default:
        break;
      }
    
      neibPU = cs.getPURestricted( neibPos, pu, pu.chType );
    
      if ( neibPU == NULL || !CU::isInter( *neibPU->cu ) || !neibPU->cu->affine
        || neibPU->mergeType != MRG_TYPE_DEFAULT_N
        )
      {
        return false;
      }
    
      Mv outputAffineMv[3];
      const MotionInfo& neibMi = neibPU->getMotionInfo( neibPos );
    
    
      const int        currRefPOC = cs.slice->getRefPic( refPicList, refIdx )->getPOC();
      const RefPicList refPicList2nd = (refPicList == REF_PIC_LIST_0) ? REF_PIC_LIST_1 : REF_PIC_LIST_0;
    
    
      for ( int predictorSource = 0; predictorSource < 2; predictorSource++ ) // examine the indicated reference picture list, then if not available, examine the other list.
      {
    
        const RefPicList eRefPicListIndex = (predictorSource == 0) ? refPicList : refPicList2nd;
    
        const int        neibRefIdx = neibMi.refIdx[eRefPicListIndex];
    
        if ( ((neibPU->interDir & (eRefPicListIndex + 1)) == 0) || pu.cu->slice->getRefPOC( eRefPicListIndex, neibRefIdx ) != currRefPOC )
        {
          continue;
        }
    
        xInheritedAffineMv( pu, neibPU, eRefPicListIndex, outputAffineMv );
    
    Xiang Li's avatar
    Xiang Li committed
        outputAffineMv[0].roundAffinePrecInternal2Amvr(pu.cu->imv);
        outputAffineMv[1].roundAffinePrecInternal2Amvr(pu.cu->imv);
    
        affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[0];
        affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[1];
        if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
        {
    
    Xiang Li's avatar
    Xiang Li committed
          outputAffineMv[2].roundAffinePrecInternal2Amvr(pu.cu->imv);
    
          affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[2];
        }
        affiAMVPInfo.numCand++;
        return true;
      }
    
      return false;
    }
    
    
    void PU::xInheritedAffineMv( const PredictionUnit &pu, const PredictionUnit* puNeighbour, RefPicList eRefPicList, Mv rcMv[3] )
    {
      int posNeiX = puNeighbour->Y().pos().x;
      int posNeiY = puNeighbour->Y().pos().y;
      int posCurX = pu.Y().pos().x;
      int posCurY = pu.Y().pos().y;
    
      int neiW = puNeighbour->Y().width;
      int curW = pu.Y().width;
      int neiH = puNeighbour->Y().height;
      int curH = pu.Y().height;
    
      mvLT = puNeighbour->mvAffi[eRefPicList][0];
      mvRT = puNeighbour->mvAffi[eRefPicList][1];
      mvLB = puNeighbour->mvAffi[eRefPicList][2];
    
    
      bool isTopCtuBoundary = false;
    
      if ( (posNeiY + neiH) % pu.cs->sps->getCTUSize() == 0 && (posNeiY + neiH) == posCurY )
    
      {
        // use bottom-left and bottom-right sub-block MVs for inheritance
        const Position posRB = puNeighbour->Y().bottomRight();
        const Position posLB = puNeighbour->Y().bottomLeft();
        mvLT = puNeighbour->getMotionInfo( posLB ).mv[eRefPicList];