Skip to content
Snippets Groups Projects
UnitTools.cpp 174 KiB
Newer Older
  • Learn to ignore specific revisions
  •   if ((refRightX >> ctuSizeLog2 <= xPos >> ctuSizeLog2) && (refLeftX >> ctuSizeLog2 >= (xPos >> ctuSizeLog2) - 1))
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      {
    
    
        // 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 JVET_N0175_N0251_N0384_IBC_SMALL_CTU
        if (((refLeftX >> ctuSizeLog2) == ((xPos >> ctuSizeLog2) - 1)) && (ctuSizeLog2 == 7))
    #else
    
        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;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    #if JVET_N0383_N0251_IBC_COL_VPDU_REMOVE
    
          if (refPosCol64x64 == pu.Y().topLeft())
            return false;
    #endif
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      }
      else
        return false;
    
    
      // 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;
    
    
    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;
      }
    }
    
    
    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];
          }
    
          currBaseNum++;
    
          if (currBaseNum == MMVD_BASE_MV_NUM)
            break;
        }
      }
    
    #if !JVET_N0448_N0380
    
      if (currBaseNum < MMVD_BASE_MV_NUM)
      {
        for (k = currBaseNum; k < MMVD_BASE_MV_NUM; k++)
        {
    
          mrgCtx.mmvdBaseMv[k][0] = MvField(Mv(0, 0), 0);
          const Slice &slice = *pu.cs->slice;
          mrgCtx.mmvdBaseMv[k][1] = MvField(Mv(0, 0), (slice.isInterB() ? 0 : -1));
    
          mrgCtx.GBiIdx[k] = GBI_DEFAULT;
          mrgCtx.interDirNeighbours[k] = (mrgCtx.mmvdBaseMv[k][0].refIdx >= 0) + (mrgCtx.mmvdBaseMv[k][1].refIdx >= 0) * 2;
    
    bool PU::getColocatedMVP(const PredictionUnit &pu, const RefPicList &eRefPicList, const Position &_pos, Mv& rcMv, const int &refIdx )
    {
      // 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;
      }
    
      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;
      }
    
      int iColRefIdx = mi.refIdx[eColRefPicList];
    
      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;
      }
      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;
        }
        else
        {
          rcMv = cColMv.scaleMv(distscale);
        }
      }
    
      return true;
    }
    
    bool PU::isDiffMER(const PredictionUnit &pu1, const PredictionUnit &pu2)
    {
      const unsigned xN = pu1.lumaPos().x;
      const unsigned yN = pu1.lumaPos().y;
      const unsigned xP = pu2.lumaPos().x;
      const unsigned yP = pu2.lumaPos().y;
    
      unsigned plevel = pu1.cs->pps->getLog2ParallelMergeLevelMinus2() + 2;
    
      if ((xN >> plevel) != (xP >> plevel))
      {
        return true;
      }
    
      if ((yN >> plevel) != (yP >> plevel))
      {
        return true;
      }
    
      return false;
    }
    
    
    #if JVET_N0329_IBC_SEARCH_IMP
    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;
      }
    }
    #endif
    
    #if JVET_N0329_IBC_SEARCH_IMP
    void PU::getIbcMVPsEncOnly(PredictionUnit &pu, Mv* mvPred, int& nbPred)
    #else
    
    Yu Han's avatar
    Yu Han committed
    void PU::getIbcMVPsEncOnly(PredictionUnit &pu, Mv* MvPred, int& nbPred)
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    {
    
    #if JVET_N0329_IBC_SEARCH_IMP
      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 = g_aucLog2[pcv.minCUWidth];
      const int  log2UnitHeight = g_aucLog2[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, pu.cs->chType);
      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, pu.cs->chType);
        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, pu.cs->chType);
        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);
      }
    #else
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      //-- Get Spatial MV
      Position posLT = pu.Y().topLeft();
      Position posRT = pu.Y().topRight();
      Position posLB = pu.Y().bottomLeft();
    
      unsigned int left = 0, above = 0;
    
      //left
      const PredictionUnit *neibLeftPU = NULL;
      neibLeftPU = pu.cs->getPURestricted(posLB.offset(-1, 0), pu, pu.cs->chType);
    
    Yu Han's avatar
    Yu Han committed
      left = (neibLeftPU) ? CU::isIBC(*neibLeftPU->cu) : 0;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
      if (left)
      {
        MvPred[nbPred++] = neibLeftPU->bv;
        if (getDerivedBV(pu, MvPred[nbPred - 1], MvPred[nbPred]))
          nbPred++;
      }
    
      //above
      const PredictionUnit *neibAbovePU = NULL;
      neibAbovePU = pu.cs->getPURestricted(posRT.offset(0, -1), pu, pu.cs->chType);
    
    Yu Han's avatar
    Yu Han committed
      above = (neibAbovePU) ? CU::isIBC(*neibAbovePU->cu) : 0;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
      if (above)
      {
        MvPred[nbPred++] = neibAbovePU->bv;
        if (getDerivedBV(pu, MvPred[nbPred - 1], MvPred[nbPred]))
          nbPred++;
      }
    
      // Below Left predictor search
      const PredictionUnit *neibBelowLeftPU = NULL;
      neibBelowLeftPU = pu.cs->getPURestricted(posLB.offset(-1, 1), pu, pu.cs->chType);
    
    Yu Han's avatar
    Yu Han committed
      unsigned int belowLeft = (neibBelowLeftPU) ? CU::isIBC(*neibBelowLeftPU->cu) : 0;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
      if (belowLeft)
      {
        MvPred[nbPred++] = neibBelowLeftPU->bv;
        if (getDerivedBV(pu, MvPred[nbPred - 1], MvPred[nbPred]))
          nbPred++;
      }
    
    
      // Above Right predictor search
      const PredictionUnit *neibAboveRightPU = NULL;
      neibAboveRightPU = pu.cs->getPURestricted(posRT.offset(1, -1), pu, pu.cs->chType);
    
    Yu Han's avatar
    Yu Han committed
      unsigned int aboveRight = (neibAboveRightPU) ? CU::isIBC(*neibAboveRightPU->cu) : 0;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
      if (aboveRight)
      {
        MvPred[nbPred++] = neibAboveRightPU->bv;
        if (getDerivedBV(pu, MvPred[nbPred - 1], MvPred[nbPred]))
          nbPred++;
      }
    
    
      // Above Left predictor search
      const PredictionUnit *neibAboveLeftPU = NULL;
      neibAboveLeftPU = pu.cs->getPURestricted(posLT.offset(-1, -1), pu, pu.cs->chType);
    
    Yu Han's avatar
    Yu Han committed
      unsigned int aboveLeft = (neibAboveLeftPU) ? CU::isIBC(*neibAboveLeftPU->cu) : 0;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
      if (aboveLeft)
      {
        MvPred[nbPred++] = neibAboveLeftPU->bv;
        if (getDerivedBV(pu, MvPred[nbPred - 1], MvPred[nbPred]))
          nbPred++;
      }
    
    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->getSPS()->getPicWidthInLumaSamples() || rY >= pu.cs->slice->getSPS()->getPicHeightInLumaSamples())
      {
        return false;
      }
    
      const PredictionUnit *neibRefPU = NULL;
      neibRefPU = pu.cs->getPURestricted(pu.lumaPos().offset(offsetX, offsetY), pu, pu.cs->chType);
    
    
    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
    #if JVET_N0843_BVP_SIMPLIFICATION==0
    
    Yu Han's avatar
    Yu Han committed
      CodingStructure &cs = *pu.cs;
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    Yu Han's avatar
    Yu Han committed
    
      AMVPInfo *pInfo = &amvpInfo;
    
      pInfo->numCand = 0;
    
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_N0843_BVP_SIMPLIFICATION==0
    
    Yu Han's avatar
    Yu Han committed
      //-- Get Spatial MV
      Position posLT = pu.Y().topLeft();
      Position posRT = pu.Y().topRight();
      Position posLB = pu.Y().bottomLeft();
    
      bool isScaledFlagLX = false; /// variable name from specification; true when the PUs below left or left are available (availableA0 || availableA1).
    
    roberta's avatar
    roberta committed
    
      const PredictionUnit* tmpPU = cs.getPURestricted(posLB.offset(-1, 1), pu, pu.chType); // getPUBelowLeft(idx, partIdxLB);
      isScaledFlagLX = tmpPU != NULL && CU::isIBC(*tmpPU->cu);
      if (!isScaledFlagLX)
    
    roberta's avatar
    roberta committed
        tmpPU = cs.getPURestricted(posLB.offset(-1, 0), pu, pu.chType);
    
    Yu Han's avatar
    Yu Han committed
        isScaledFlagLX = tmpPU != NULL && CU::isIBC(*tmpPU->cu);
      }
    
      // Left predictor search
      if (isScaledFlagLX)
      {
    
    Yu Han's avatar
    Yu Han committed
        bool isAdded = addIBCMVPCand(pu, posLB, MD_BELOW_LEFT, *pInfo);
    
    Yu Han's avatar
    Yu Han committed
        if (!isAdded)
    
    Yu Han's avatar
    Yu Han committed
          isAdded = addIBCMVPCand(pu, posLB, MD_LEFT, *pInfo);
    
    Yu Han's avatar
    Yu Han committed
        }
      }
    
      // Above predictor search
    
    roberta's avatar
    roberta committed
      bool isAdded = addIBCMVPCand(pu, posRT, MD_ABOVE_RIGHT, *pInfo);
    
      if (!isAdded)
    
    roberta's avatar
    roberta committed
        isAdded = addIBCMVPCand(pu, posRT, MD_ABOVE, *pInfo);
    
    Yu Han's avatar
    Yu Han committed
        if (!isAdded)
    
    roberta's avatar
    roberta committed
          addIBCMVPCand(pu, posLT, MD_ABOVE_LEFT, *pInfo);
    
    roberta's avatar
    roberta committed
      for( int i = 0; i < pInfo->numCand; i++ )
      {
        pInfo->mvCand[i].roundToAmvrSignalPrecision(MV_PRECISION_INTERNAL, pu.cu->imv);
      }
    
    Yu Han's avatar
    Yu Han committed
    
      if (pInfo->numCand == 2)
      {
        if (pInfo->mvCand[0] == pInfo->mvCand[1])
        {
          pInfo->numCand = 1;
        }
      }
    
      if (pInfo->numCand < AMVP_MAX_NUM_CANDS)
      {
    
    Yu Han's avatar
    Yu Han committed
        addAMVPHMVPCand(pu, REF_PIC_LIST_0, REF_PIC_LIST_1, cs.slice->getPOC(), *pInfo, pu.cu->imv);
    
    Yu Han's avatar
    Yu Han committed
      }
    
      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++;
      }
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    #if JVET_N0843_BVP_SIMPLIFICATION
      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++;
      }
    #endif
    
    Yu Han's avatar
    Yu Han committed
    
      for (Mv &mv : pInfo->mvCand)
    
    Yu Han's avatar
    Yu Han committed
        mv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER);
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_N0843_BVP_SIMPLIFICATION
        mv.roundToAmvrSignalPrecision(MV_PRECISION_QUARTER, pu.cu->imv);
    #endif
    
    /** 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 isScaledFlagLX = false; /// variable name from specification; true when the PUs below left or left are available (availableA0 || availableA1).
    
      {
        const PredictionUnit* tmpPU = cs.getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType ); // getPUBelowLeft(idx, partIdxLB);
        isScaledFlagLX = tmpPU != NULL && CU::isInter( *tmpPU->cu );
    
        if( !isScaledFlagLX )
        {
          tmpPU = cs.getPURestricted( posLB.offset( -1, 0 ), pu, pu.chType );
          isScaledFlagLX = tmpPU != NULL && CU::isInter( *tmpPU->cu );
        }
      }
    
      // Left predictor search
      if( isScaledFlagLX )
      {
        bool bAdded = addMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_BELOW_LEFT, *pInfo );
    
        if( !bAdded )
        {
          bAdded = addMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_LEFT, *pInfo );
    
          if( !bAdded )
          {
            bAdded = addMVPCandWithScaling( pu, eRefPicList, refIdx, posLB, MD_BELOW_LEFT, *pInfo );
    
            if( !bAdded )
            {
              addMVPCandWithScaling( 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 );
          }
        }
      }
    
      if( !isScaledFlagLX )
      {
        bool bAdded = addMVPCandWithScaling( pu, eRefPicList, refIdx, posRT, MD_ABOVE_RIGHT, *pInfo );
    
        if( !bAdded )
        {
          bAdded = addMVPCandWithScaling( pu, eRefPicList, refIdx, posRT, MD_ABOVE, *pInfo );
    
          if( !bAdded )
          {
            addMVPCandWithScaling( pu, eRefPicList, refIdx, posLT, MD_ABOVE_LEFT, *pInfo );
          }
        }
      }
    
    
      for( int i = 0; i < pInfo->numCand; i++ )
      {
        pInfo->mvCand[i].roundToAmvrSignalPrecision(MV_PRECISION_INTERNAL, pu.cu->imv);
      }
    
    
      if( pInfo->numCand == 2 )
      {
        if( pInfo->mvCand[0] == pInfo->mvCand[1] )
        {
          pInfo->numCand = 1;
        }
      }
    
    
      if( cs.slice->getEnableTMVPFlag() && pInfo->numCand < AMVP_MAX_NUM_CANDS )
    
      {
        // 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();
    
        bool C1Avail =  ( posC1.x  < pcv.lumaWidth ) && ( posC1.y < pcv.lumaHeight ) ;
    
        Mv cColMv;
    
        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
          {
            // in the reference the CTU address is not set - thus probably resulting in no using this C0 possibility
            posC0 = posRB.offset(4, 4);
          }
          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
          {
            // same as for last column but not last row
            posC0 = posRB.offset(4, 4);
          }
        }
    
    #if JVET_N0266_SMALL_BLOCKS
        if ( ( C0Avail && getColocatedMVP( pu, eRefPicList, posC0, cColMv, refIdx_Col ) ) || getColocatedMVP( pu, eRefPicList, posC1, cColMv, refIdx_Col ) )
    #else
    
        if ((C0Avail && getColocatedMVP(pu, eRefPicList, posC0, cColMv, refIdx_Col)) || (C1Avail && getColocatedMVP(pu, eRefPicList, posC1, cColMv, refIdx_Col)))
    
          cColMv.roundToAmvrSignalPrecision(MV_PRECISION_INTERNAL, pu.cu->imv);
    
          pInfo->mvCand[pInfo->numCand++] = cColMv;
    
      if (pInfo->numCand < AMVP_MAX_NUM_CANDS)
      {
        const int        currRefPOC = cs.slice->getRefPic(eRefPicList, refIdx)->getPOC();
        const RefPicList eRefPicList2nd = (eRefPicList == REF_PIC_LIST_0) ? REF_PIC_LIST_1 : REF_PIC_LIST_0;
        addAMVPHMVPCand(pu, eRefPicList, eRefPicList2nd, currRefPOC, *pInfo, pu.cu->imv);
      }
    
      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)
    
        mv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER);
    
    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 );
    
        if ( pu.cu->imv == 0 )
        {
          outputAffineMv[0].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER);
          outputAffineMv[1].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER);
        }
        else if ( pu.cu->imv == 2 )
        {
          outputAffineMv[0].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT );
          outputAffineMv[1].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT );
        }
    
        affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[0];
        affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[1];
        if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
        {
    
          if ( pu.cu->imv == 0 )
          {
            outputAffineMv[2].roundToPrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER);
          }
          else if ( pu.cu->imv == 2 )
          {
            outputAffineMv[2].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT );
          }
    
          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];
        mvRT = puNeighbour->getMotionInfo( posRB ).mv[eRefPicList];
        posNeiY += neiH;
    
    
      int shift = MAX_CU_DEPTH;
      int iDMvHorX, iDMvHorY, iDMvVerX, iDMvVerY;
    
      iDMvHorX = (mvRT - mvLT).getHor() << (shift - g_aucLog2[neiW]);
      iDMvHorY = (mvRT - mvLT).getVer() << (shift - g_aucLog2[neiW]);
    
      if ( puNeighbour->cu->affineType == AFFINEMODEL_6PARAM && !isTopCtuBoundary )
    
      {
        iDMvVerX = (mvLB - mvLT).getHor() << (shift - g_aucLog2[neiH]);
        iDMvVerY = (mvLB - mvLT).getVer() << (shift - g_aucLog2[neiH]);
      }
      else
      {
        iDMvVerX = -iDMvHorY;
        iDMvVerY = iDMvHorX;
      }
    
      int iMvScaleHor = mvLT.getHor() << shift;
      int iMvScaleVer = mvLT.getVer() << shift;
      int horTmp, verTmp;
    
      // v0
      horTmp = iMvScaleHor + iDMvHorX * (posCurX - posNeiX) + iDMvVerX * (posCurY - posNeiY);
      verTmp = iMvScaleVer + iDMvHorY * (posCurX - posNeiX) + iDMvVerY * (posCurY - posNeiY);
      roundAffineMv( horTmp, verTmp, shift );
    
      rcMv[0].hor = horTmp;
      rcMv[0].ver = verTmp;
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
      rcMv[0].clipToStorageBitDepth();
    
    
      // v1
      horTmp = iMvScaleHor + iDMvHorX * (posCurX + curW - posNeiX) + iDMvVerX * (posCurY - posNeiY);
      verTmp = iMvScaleVer + iDMvHorY * (posCurX + curW - posNeiX) + iDMvVerY * (posCurY - posNeiY);
      roundAffineMv( horTmp, verTmp, shift );
    
      rcMv[1].hor = horTmp;
      rcMv[1].ver = verTmp;
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
      rcMv[1].clipToStorageBitDepth();
    
    
      // v2
      if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
      {
        horTmp = iMvScaleHor + iDMvHorX * (posCurX - posNeiX) + iDMvVerX * (posCurY + curH - posNeiY);
        verTmp = iMvScaleVer + iDMvHorY * (posCurX - posNeiX) + iDMvVerY * (posCurY + curH - posNeiY);
        roundAffineMv( horTmp, verTmp, shift );
    
        rcMv[2].hor = horTmp;
        rcMv[2].ver = verTmp;
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
        rcMv[2].clipToStorageBitDepth();
    
      }
    }
    
    
    void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AffineAMVPInfo &affiAMVPInfo)
    {
      affiAMVPInfo.numCand = 0;
    
      if (refIdx < 0)
      {
        return;
      }
    
    
      // insert inherited affine candidates
      Mv outputAffineMv[3];
    
      Position posLT = pu.Y().topLeft();
      Position posRT = pu.Y().topRight();
      Position posLB = pu.Y().bottomLeft();
    
    
      // check left neighbor
    
      if ( !addAffineMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_BELOW_LEFT, affiAMVPInfo ) )
      {
        addAffineMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_LEFT, affiAMVPInfo );
      }
    
      // check above neighbor
      if ( !addAffineMVPCandUnscaled( pu, eRefPicList, refIdx, posRT, MD_ABOVE_RIGHT, affiAMVPInfo ) )
      {
        if ( !addAffineMVPCandUnscaled( pu, eRefPicList, refIdx, posRT, MD_ABOVE, affiAMVPInfo ) )
        {
          addAffineMVPCandUnscaled( pu, eRefPicList, refIdx, posLT, MD_ABOVE_LEFT, affiAMVPInfo );
        }
      }
    
        for (int i = 0; i < affiAMVPInfo.numCand; i++)
        {
    
          if ( pu.cu->imv != 1 )
          {
            affiAMVPInfo.mvCandLT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER);
            affiAMVPInfo.mvCandRT[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER);
            affiAMVPInfo.mvCandLB[i].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER);
          }
    
        return;
      }
    
      // insert constructed affine candidates
      int cornerMVPattern = 0;
    
      //-------------------  V0 (START) -------------------//
      AMVPInfo amvpInfo0;
      amvpInfo0.numCand = 0;
    
      // A->C: Above Left, Above, Left
    
    Huanbang Chen's avatar
    Huanbang Chen committed
      addMVPCandUnscaled( pu, eRefPicList, refIdx, posLT, MD_ABOVE_LEFT, amvpInfo0 );
    
    Huanbang Chen's avatar
    Huanbang Chen committed
        addMVPCandUnscaled( pu, eRefPicList, refIdx, posLT, MD_ABOVE, amvpInfo0 );
    
    Huanbang Chen's avatar
    Huanbang Chen committed
        addMVPCandUnscaled( pu, eRefPicList, refIdx, posLT, MD_LEFT, amvpInfo0 );
    
      }
      cornerMVPattern = cornerMVPattern | amvpInfo0.numCand;
    
      //-------------------  V1 (START) -------------------//
      AMVPInfo amvpInfo1;
      amvpInfo1.numCand = 0;