Skip to content
Snippets Groups Projects
UnitTools.cpp 160 KiB
Newer Older
  • Learn to ignore specific revisions
  • 
        if ((C0Avail && getColocatedMVP(pu, eRefPicList, posC0, cColMv, refIdx_Col)) || getColocatedMVP(pu, eRefPicList, posC1, cColMv, refIdx_Col))
        {
    
    #if JVET_L0266_HMVP
          if (pu.cu->imv != 0)
          {
            unsigned imvShift = pu.cu->imv << 1;
            roundMV(cColMv, imvShift);
          }
          int i = 0;
          for (i = 0; i < pInfo->numCand; i++)
          {
            if (cColMv == pInfo->mvCand[i])
            {
              break;
            }
          }
          if (i == pInfo->numCand)
          {
            pInfo->mvCand[pInfo->numCand++] = cColMv;
          }
    #else
    
    #if JVET_L0266_HMVP
      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);
      }
    #endif
    
      if (pInfo->numCand > AMVP_MAX_NUM_CANDS)
      {
        pInfo->numCand = AMVP_MAX_NUM_CANDS;
      }
    
      while (pInfo->numCand < AMVP_MAX_NUM_CANDS)
      {
    
    #if !REMOVE_MV_ADAPT_PREC
    
        const bool prec = pInfo->mvCand[pInfo->numCand].highPrec;
        pInfo->mvCand[pInfo->numCand] = Mv( 0, 0, prec );
    #else
        pInfo->mvCand[pInfo->numCand] = Mv( 0, 0 );
    #endif
        pInfo->numCand++;
      }
    
    #if !REMOVE_MV_ADAPT_PREC
      if (pu.cs->sps->getSpsNext().getUseHighPrecMv())
    
    #endif
        for (Mv &mv : pInfo->mvCand)
    
    #if REMOVE_MV_ADAPT_PREC
          const int nShift = VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
          const int nOffset = 1 << (nShift - 1);
          mv.hor = mv.hor >= 0 ? (mv.hor + nOffset) >> nShift : -((-mv.hor + nOffset) >> nShift);
          mv.ver = mv.ver >= 0 ? (mv.ver + nOffset) >> nShift : -((-mv.ver + nOffset) >> nShift);
    #else
          if (mv.highPrec) mv.setLowPrec();
    #endif
    
    #if !REMOVE_MV_ADAPT_PREC
    
      if (pu.cu->imv != 0)
      {
        unsigned imvShift = pu.cu->imv << 1;
        for (int i = 0; i < pInfo->numCand; i++)
        {
          roundMV(pInfo->mvCand[i], imvShift);
        }
      }
    
    #if !REMOVE_MV_ADAPT_PREC
    
      if (pu.cs->sps->getSpsNext().getUseHighPrecMv())
      {
        for (Mv &mv : pInfo->mvCand)
        {
          if (mv.highPrec) mv.setLowPrec();
        }
      }
    #endif
    }
    
    
    #if JVET_L0271_AFFINE_AMVP_SIMPLIFY
    
    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
    #if JVET_L0369_SUBBLOCK_MERGE
        || neibPU->mergeType != MRG_TYPE_DEFAULT_N
    #endif
        )
      {
        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 );
    
        outputAffineMv[0].roundMV2SignalPrecision();
        outputAffineMv[1].roundMV2SignalPrecision();
        affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[0];
        affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[1];
        if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
        {
          outputAffineMv[2].roundMV2SignalPrecision();
          affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[2];
        }
        affiAMVPInfo.numCand++;
        return true;
      }
    
      return false;
    }
    #else
    
    const int getAvailableAffineNeighbours( const PredictionUnit &pu, const PredictionUnit* npu[] )
    {
      const Position posLT = pu.Y().topLeft();
      const Position posRT = pu.Y().topRight();
      const Position posLB = pu.Y().bottomLeft();
    
      int num = 0;
      const PredictionUnit* puLeft = pu.cs->getPURestricted( posLB.offset( -1, 0 ), pu, pu.chType );
    
      if ( puLeft && puLeft->cu->affine
    #if JVET_L0369_SUBBLOCK_MERGE
        && puLeft->mergeType == MRG_TYPE_DEFAULT_N
    #endif
        )
    
      {
        npu[num++] = puLeft;
      }
    
      const PredictionUnit* puAbove = pu.cs->getPURestricted( posRT.offset( 0, -1 ), pu, pu.chType );
    
      if ( puAbove && puAbove->cu->affine
    #if JVET_L0369_SUBBLOCK_MERGE
        && puAbove->mergeType == MRG_TYPE_DEFAULT_N
    #endif
        )
    
      {
        npu[num++] = puAbove;
      }
    
      const PredictionUnit* puAboveRight = pu.cs->getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
    
      if ( puAboveRight && puAboveRight->cu->affine
    #if JVET_L0369_SUBBLOCK_MERGE
        && puAboveRight->mergeType == MRG_TYPE_DEFAULT_N
    #endif
        )
    
      {
        npu[num++] = puAboveRight;
      }
    
      const PredictionUnit *puLeftBottom = pu.cs->getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType );
    
      if ( puLeftBottom && puLeftBottom->cu->affine
    #if JVET_L0369_SUBBLOCK_MERGE
        && puLeftBottom->mergeType == MRG_TYPE_DEFAULT_N
    #endif
        )
    
      {
        npu[num++] = puLeftBottom;
      }
    
      const PredictionUnit *puAboveLeft = pu.cs->getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType );
    
      if ( puAboveLeft && puAboveLeft->cu->affine
    #if JVET_L0369_SUBBLOCK_MERGE
        && puAboveLeft->mergeType == MRG_TYPE_DEFAULT_N
    #endif
        )
    
    
    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;
      
      Mv mvLT, mvRT, mvLB;
    
    #if JVET_L0694_AFFINE_LINEBUFFER_CLEANUP
      mvLT = puNeighbour->mvAffi[eRefPicList][0];
      mvRT = puNeighbour->mvAffi[eRefPicList][1];
      mvLB = puNeighbour->mvAffi[eRefPicList][2];
    #else
    
      const Position posLT = puNeighbour->Y().topLeft();
      const Position posRT = puNeighbour->Y().topRight();
      const Position posLB = puNeighbour->Y().bottomLeft();
      mvLT = puNeighbour->getMotionInfo( posLT ).mv[eRefPicList];
      mvRT = puNeighbour->getMotionInfo( posRT ).mv[eRefPicList];
      mvLB = puNeighbour->getMotionInfo( posLB ).mv[eRefPicList];
    
    #endif
    
    #if JVET_L0694_AFFINE_LINEBUFFER_CLEANUP
    
      bool isTopCtuBoundary = false;
    
      if ( (posNeiY + neiH) % pu.cs->sps->getSpsNext().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 JVET_L0694_AFFINE_LINEBUFFER_CLEANUP // degrade to 4-parameter model
    
      if ( puNeighbour->cu->affineType == AFFINEMODEL_6PARAM && !isTopCtuBoundary )
    
      if ( puNeighbour->cu->affineType == AFFINEMODEL_6PARAM )
    
      {
        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 );
    
    #if REMOVE_MV_ADAPT_PREC
      rcMv[0].hor = horTmp;
      rcMv[0].ver = verTmp;
    #else
      rcMv[0] = Mv(horTmp, verTmp, true);
    #endif
    
    
      // v1
      horTmp = iMvScaleHor + iDMvHorX * (posCurX + curW - posNeiX) + iDMvVerX * (posCurY - posNeiY);
      verTmp = iMvScaleVer + iDMvHorY * (posCurX + curW - posNeiX) + iDMvVerY * (posCurY - posNeiY);
      roundAffineMv( horTmp, verTmp, shift );
    
    #if REMOVE_MV_ADAPT_PREC
      rcMv[1].hor = horTmp;
      rcMv[1].ver = verTmp;
    #else
      rcMv[1] = Mv(horTmp, verTmp, true);
    #endif
    
    
      // 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 );
    
    #if REMOVE_MV_ADAPT_PREC
        rcMv[2].hor = horTmp;
        rcMv[2].ver = verTmp;
    #else
        rcMv[2] = Mv(horTmp, verTmp, true);
    #endif
    
      }
    }
    
    
    void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AffineAMVPInfo &affiAMVPInfo)
    {
    
    #if REMOVE_MV_ADAPT_PREC
      const int nShift = VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
      const int nOffset = 1 << (nShift - 1);
    #endif
    
    #if !JVET_L0271_AFFINE_AMVP_SIMPLIFY
    
      const int curWidth = pu.Y().width;
      const int curHeight = pu.Y().height;
    
    
      // insert inherited affine candidates
      Mv outputAffineMv[3];
    
    #if JVET_L0271_AFFINE_AMVP_SIMPLIFY
      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 );
        }
      }
    #else
    
      const int maxNei = 5;
      const PredictionUnit* npu[maxNei];
      int numAffNeigh = getAvailableAffineNeighbours( pu, npu );
      int targetRefPOC = pu.cu->slice->getRefPOC( eRefPicList, refIdx );
    
      for ( int refPicList = 0; refPicList < 2 && affiAMVPInfo.numCand < AMVP_MAX_NUM_CANDS; refPicList++ )
      {
        RefPicList eTestRefPicList = (refPicList == 0) ? eRefPicList : RefPicList( 1 - eRefPicList );
    
        for ( int neighIdx = 0; neighIdx < numAffNeigh && affiAMVPInfo.numCand < AMVP_MAX_NUM_CANDS; neighIdx++ )
        {
          const PredictionUnit* puNeighbour = npu[neighIdx];
    
          if ( ((puNeighbour->interDir & (eTestRefPicList + 1)) == 0) || pu.cu->slice->getRefPOC( eTestRefPicList, puNeighbour->refIdx[eTestRefPicList] ) != targetRefPOC )
          {
            continue;
          }
    
          xInheritedAffineMv( pu, puNeighbour, eTestRefPicList, outputAffineMv );
    
          outputAffineMv[0].roundMV2SignalPrecision();
          outputAffineMv[1].roundMV2SignalPrecision();
          if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
          {
            outputAffineMv[2].roundMV2SignalPrecision();
          }
    
          if ( affiAMVPInfo.numCand == 0
            || (pu.cu->affineType == AFFINEMODEL_4PARAM && (outputAffineMv[0] != affiAMVPInfo.mvCandLT[0] || outputAffineMv[1] != affiAMVPInfo.mvCandRT[0]))
            || (pu.cu->affineType == AFFINEMODEL_6PARAM && (outputAffineMv[0] != affiAMVPInfo.mvCandLT[0] || outputAffineMv[1] != affiAMVPInfo.mvCandRT[0] || outputAffineMv[2] != affiAMVPInfo.mvCandLB[0]))
            )
          {
            affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[0];
            affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[1];
            affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[2];
            affiAMVPInfo.numCand++;
          }
        }
      }
    
    #if REMOVE_MV_ADAPT_PREC
        for (int i = 0; i < affiAMVPInfo.numCand; i++)
        {
          affiAMVPInfo.mvCandLT[i].hor = affiAMVPInfo.mvCandLT[i].hor >= 0 ? (affiAMVPInfo.mvCandLT[i].hor + nOffset) >> nShift : -((-affiAMVPInfo.mvCandLT[i].hor + nOffset) >> nShift);
          affiAMVPInfo.mvCandLT[i].ver = affiAMVPInfo.mvCandLT[i].ver >= 0 ? (affiAMVPInfo.mvCandLT[i].ver + nOffset) >> nShift : -((-affiAMVPInfo.mvCandLT[i].ver + nOffset) >> nShift);
          affiAMVPInfo.mvCandRT[i].hor = affiAMVPInfo.mvCandRT[i].hor >= 0 ? (affiAMVPInfo.mvCandRT[i].hor + nOffset) >> nShift : -((-affiAMVPInfo.mvCandRT[i].hor + nOffset) >> nShift);
          affiAMVPInfo.mvCandRT[i].ver = affiAMVPInfo.mvCandRT[i].ver >= 0 ? (affiAMVPInfo.mvCandRT[i].ver + nOffset) >> nShift : -((-affiAMVPInfo.mvCandRT[i].ver + nOffset) >> nShift);
          affiAMVPInfo.mvCandLB[i].hor = affiAMVPInfo.mvCandLB[i].hor >= 0 ? (affiAMVPInfo.mvCandLB[i].hor + nOffset) >> nShift : -((-affiAMVPInfo.mvCandLB[i].hor + nOffset) >> nShift);
          affiAMVPInfo.mvCandLB[i].ver = affiAMVPInfo.mvCandLB[i].ver >= 0 ? (affiAMVPInfo.mvCandLB[i].ver + nOffset) >> nShift : -((-affiAMVPInfo.mvCandLB[i].ver + nOffset) >> nShift);
        }
    #endif
    
        return;
      }
    
      // insert constructed affine candidates
      int cornerMVPattern = 0;
    
    #if !JVET_L0271_AFFINE_AMVP_SIMPLIFY
    
      Position posLT = pu.Y().topLeft();
      Position posRT = pu.Y().topRight();
      Position posLB = pu.Y().bottomLeft();
    
    
      //-------------------  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;
    
      // D->E: Above, Above Right
    
    Huanbang Chen's avatar
    Huanbang Chen committed
      addMVPCandUnscaled( pu, eRefPicList, refIdx, posRT, MD_ABOVE, amvpInfo1 );
    
    Huanbang Chen's avatar
    Huanbang Chen committed
        addMVPCandUnscaled( pu, eRefPicList, refIdx, posRT, MD_ABOVE_RIGHT, amvpInfo1 );
    
      }
      cornerMVPattern = cornerMVPattern | (amvpInfo1.numCand << 1);
    
      //-------------------  V2 (START) -------------------//
      AMVPInfo amvpInfo2;
      amvpInfo2.numCand = 0;
    
      // F->G: Left, Below Left
    
    Huanbang Chen's avatar
    Huanbang Chen committed
      addMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_LEFT, amvpInfo2 );
    
    Huanbang Chen's avatar
    Huanbang Chen committed
        addMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_BELOW_LEFT, amvpInfo2 );
    
      }
      cornerMVPattern = cornerMVPattern | (amvpInfo2.numCand << 2);
    
      outputAffineMv[0] = amvpInfo0.mvCand[0];
      outputAffineMv[1] = amvpInfo1.mvCand[0];
      outputAffineMv[2] = amvpInfo2.mvCand[0];
    
    
    #if !REMOVE_MV_ADAPT_PREC
    
      outputAffineMv[0].setHighPrec();
      outputAffineMv[1].setHighPrec();
      outputAffineMv[2].setHighPrec();
    
    
      outputAffineMv[0].roundMV2SignalPrecision();
      outputAffineMv[1].roundMV2SignalPrecision();
      outputAffineMv[2].roundMV2SignalPrecision();
    
    
    #if JVET_L0271_AFFINE_AMVP_SIMPLIFY
      if ( cornerMVPattern == 7 || (cornerMVPattern == 3 && pu.cu->affineType == AFFINEMODEL_4PARAM) )
      {
        affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[0];
        affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[1];
        affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[2];
        affiAMVPInfo.numCand++;
      }
    #else
    
      if ( cornerMVPattern == 7 || cornerMVPattern == 3 || cornerMVPattern == 5 )
      {
        if ( cornerMVPattern == 3 && pu.cu->affineType == AFFINEMODEL_6PARAM ) // V0 V1 are available, derived V2 for 6-para
        {
          int shift = MAX_CU_DEPTH;
          int vx2 = (outputAffineMv[0].getHor() << shift) - ((outputAffineMv[1].getVer() - outputAffineMv[0].getVer()) << (shift + g_aucLog2[curHeight] - g_aucLog2[curWidth]));
          int vy2 = (outputAffineMv[0].getVer() << shift) + ((outputAffineMv[1].getHor() - outputAffineMv[0].getHor()) << (shift + g_aucLog2[curHeight] - g_aucLog2[curWidth]));
          roundAffineMv( vx2, vy2, shift );
          outputAffineMv[2].set( vx2, vy2 );
          outputAffineMv[2].roundMV2SignalPrecision();
        }
    
        if ( cornerMVPattern == 5 ) // V0 V2 are available, derived V1
        {
          int shift = MAX_CU_DEPTH;
          int vx1 = (outputAffineMv[0].getHor() << shift) + ((outputAffineMv[2].getVer() - outputAffineMv[0].getVer()) << (shift + g_aucLog2[curWidth] - g_aucLog2[curHeight]));
          int vy1 = (outputAffineMv[0].getVer() << shift) - ((outputAffineMv[2].getHor() - outputAffineMv[0].getHor()) << (shift + g_aucLog2[curWidth] - g_aucLog2[curHeight]));
          roundAffineMv( vx1, vy1, shift );
          outputAffineMv[1].set( vx1, vy1 );
          outputAffineMv[1].roundMV2SignalPrecision();
        }
    
        if ( affiAMVPInfo.numCand == 0
          || (pu.cu->affineType == AFFINEMODEL_4PARAM && (outputAffineMv[0] != affiAMVPInfo.mvCandLT[0] || outputAffineMv[1] != affiAMVPInfo.mvCandRT[0]))
          || (pu.cu->affineType == AFFINEMODEL_6PARAM && (outputAffineMv[0] != affiAMVPInfo.mvCandLT[0] || outputAffineMv[1] != affiAMVPInfo.mvCandRT[0] || outputAffineMv[2] != affiAMVPInfo.mvCandLB[0]))
          )
        {
          affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[0];
          affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[1];
          affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[2];
          affiAMVPInfo.numCand++;
        }
      }
    
    #endif
    
    
    #if JVET_L0271_AFFINE_AMVP_SIMPLIFY
      if ( affiAMVPInfo.numCand < 2 )
      {
        // check corner MVs
        for ( int i = 2; i >= 0 && affiAMVPInfo.numCand < AMVP_MAX_NUM_CANDS; i-- )
        {
          if ( cornerMVPattern & (1 << i) ) // MV i exist
          {
            affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[i];
            affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[i];
            affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[i];
            affiAMVPInfo.numCand++;
          }
        }
    
        // Get Temporal Motion Predictor
        if ( affiAMVPInfo.numCand < 2 && pu.cs->slice->getEnableTMVPFlag() )
        {
    
          const int refIdxCol = refIdx;
    
    
          Position posRB = pu.Y().bottomRight().offset( -3, -3 );
    
          const PreCalcValues& pcv = *pu.cs->pcv;
    
          Position posC0;
          bool C0Avail = false;
          Position posC1 = pu.Y().center();
    
          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 ( (C0Avail && getColocatedMVP( pu, eRefPicList, posC0, cColMv, refIdxCol )) || getColocatedMVP( pu, eRefPicList, posC1, cColMv, refIdxCol ) )
    
          {
    #if !REMOVE_MV_ADAPT_PREC
            cColMv.setHighPrec();
    #endif
            cColMv.roundMV2SignalPrecision();
            affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = cColMv;
            affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = cColMv;
            affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = cColMv;
            affiAMVPInfo.numCand++;
          }
        }
    
        if ( affiAMVPInfo.numCand < 2 )
        {
          // add zero MV
          for ( int i = affiAMVPInfo.numCand; i < AMVP_MAX_NUM_CANDS; i++ )
          {
            affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand].setZero();
            affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand].setZero();
            affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand].setZero();
    #if !REMOVE_MV_ADAPT_PREC
            affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand].setHighPrec();
            affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand].setHighPrec();
            affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand].setHighPrec();
    #endif
            affiAMVPInfo.numCand++;
          }
        }
      }
    #endif
    
    
    #if REMOVE_MV_ADAPT_PREC
      for (int i = 0; i < affiAMVPInfo.numCand; i++)
      {
        affiAMVPInfo.mvCandLT[i].hor = affiAMVPInfo.mvCandLT[i].hor >= 0 ? (affiAMVPInfo.mvCandLT[i].hor + nOffset) >> nShift : -((-affiAMVPInfo.mvCandLT[i].hor + nOffset) >> nShift);
        affiAMVPInfo.mvCandLT[i].ver = affiAMVPInfo.mvCandLT[i].ver >= 0 ? (affiAMVPInfo.mvCandLT[i].ver + nOffset) >> nShift : -((-affiAMVPInfo.mvCandLT[i].ver + nOffset) >> nShift);
        affiAMVPInfo.mvCandRT[i].hor = affiAMVPInfo.mvCandRT[i].hor >= 0 ? (affiAMVPInfo.mvCandRT[i].hor + nOffset) >> nShift : -((-affiAMVPInfo.mvCandRT[i].hor + nOffset) >> nShift);
        affiAMVPInfo.mvCandRT[i].ver = affiAMVPInfo.mvCandRT[i].ver >= 0 ? (affiAMVPInfo.mvCandRT[i].ver + nOffset) >> nShift : -((-affiAMVPInfo.mvCandRT[i].ver + nOffset) >> nShift);
        affiAMVPInfo.mvCandLB[i].hor = affiAMVPInfo.mvCandLB[i].hor >= 0 ? (affiAMVPInfo.mvCandLB[i].hor + nOffset) >> nShift : -((-affiAMVPInfo.mvCandLB[i].hor + nOffset) >> nShift);
        affiAMVPInfo.mvCandLB[i].ver = affiAMVPInfo.mvCandLB[i].ver >= 0 ? (affiAMVPInfo.mvCandLB[i].ver + nOffset) >> nShift : -((-affiAMVPInfo.mvCandLB[i].ver + nOffset) >> nShift);
      }
    #endif
    
      if ( affiAMVPInfo.numCand < 2 )
      {
        AMVPInfo amvpInfo;
        PU::fillMvpCand( pu, eRefPicList, refIdx, amvpInfo );
    
        int iAdd = amvpInfo.numCand - affiAMVPInfo.numCand;
        for ( int i = 0; i < iAdd; i++ )
        {
    
    #if !REMOVE_MV_ADAPT_PREC
    
          amvpInfo.mvCand[i].setHighPrec();
    #endif
          affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = amvpInfo.mvCand[i];
          affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = amvpInfo.mvCand[i];
          affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = amvpInfo.mvCand[i];
          affiAMVPInfo.numCand++;
        }
      }
    
    Huanbang Chen's avatar
    Huanbang Chen committed
    bool PU::addMVPCandUnscaled( const PredictionUnit &pu, const RefPicList &eRefPicList, const int &iRefIdx, const Position &pos, const MvpDir &eDir, AMVPInfo &info )
    
    {
            CodingStructure &cs    = *pu.cs;
      const PredictionUnit *neibPU = NULL;
            Position neibPos;
    
      switch (eDir)
      {
      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 ) )
      {
        return false;
      }
    
      const MotionInfo& neibMi        = neibPU->getMotionInfo( neibPos );
    
      const int        currRefPOC     = cs.slice->getRefPic( eRefPicList, iRefIdx )->getPOC();
      const RefPicList eRefPicList2nd = ( eRefPicList == 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 ) ? eRefPicList : eRefPicList2nd;
        const int        neibRefIdx       = neibMi.refIdx[eRefPicListIndex];
    
        if( neibRefIdx >= 0 && currRefPOC == cs.slice->getRefPOC( eRefPicListIndex, neibRefIdx ) )
        {
    
    Huanbang Chen's avatar
    Huanbang Chen committed
          info.mvCand[info.numCand++] = neibMi.mv[eRefPicListIndex];
          return true;
    
        }
      }
    
      return false;
    }
    
    /**
    * \param pInfo
    * \param eRefPicList
    * \param iRefIdx
    * \param uiPartUnitIdx
    * \param eDir
    * \returns bool
    */
    
    Huanbang Chen's avatar
    Huanbang Chen committed
    bool PU::addMVPCandWithScaling( const PredictionUnit &pu, const RefPicList &eRefPicList, const int &iRefIdx, const Position &pos, const MvpDir &eDir, AMVPInfo &info )
    
    {
            CodingStructure &cs    = *pu.cs;
      const Slice &slice           = *cs.slice;
      const PredictionUnit *neibPU = NULL;
            Position neibPos;
    
      switch( eDir )
      {
      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 ) )
      {
        return false;
      }
    
      const MotionInfo& neibMi        = neibPU->getMotionInfo( neibPos );
    
      const RefPicList eRefPicList2nd = ( eRefPicList == REF_PIC_LIST_0 ) ? REF_PIC_LIST_1 : REF_PIC_LIST_0;
    
      const int  currPOC            = slice.getPOC();
      const int  currRefPOC         = slice.getRefPic( eRefPicList, iRefIdx )->poc;
      const bool bIsCurrRefLongTerm = slice.getRefPic( eRefPicList, iRefIdx )->longTerm;
      const int  neibPOC            = currPOC;
    
      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) ? eRefPicList : eRefPicList2nd;
        const int        neibRefIdx       = neibMi.refIdx[eRefPicListIndex];
        if( neibRefIdx >= 0 )
        {
          const bool bIsNeibRefLongTerm = slice.getRefPic(eRefPicListIndex, neibRefIdx)->longTerm;
    
          if (bIsCurrRefLongTerm == bIsNeibRefLongTerm)
          {
            Mv cMv = neibMi.mv[eRefPicListIndex];
    
            if( !( bIsCurrRefLongTerm /* || bIsNeibRefLongTerm*/) )
            {
              const int neibRefPOC = slice.getRefPOC( eRefPicListIndex, neibRefIdx );
              const int scale      = xGetDistScaleFactor( currPOC, currRefPOC, neibPOC, neibRefPOC );
    
              if( scale != 4096 )
              {
    
    #if !REMOVE_MV_ADAPT_PREC
    
                if( slice.getSPS()->getSpsNext().getUseHighPrecMv() )
                {
                  cMv.setHighPrec();
                }
    #endif
                cMv = cMv.scaleMv( scale );
              }
            }
    
    
    Huanbang Chen's avatar
    Huanbang Chen committed
            info.mvCand[info.numCand++] = cMv;
            return true;
    
    #if JVET_L0266_HMVP
    void PU::addAMVPHMVPCand(const PredictionUnit &pu, const RefPicList eRefPicList, const RefPicList eRefPicList2nd, const int currRefPOC, AMVPInfo &info, uint8_t imv)
    {
      const Slice &slice = *(*pu.cs).slice;
    
      MotionInfo neibMi;
      int i = 0;
      unsigned imvShift = imv << 1;
    
      int num_avai_candInLUT = slice.getAvailableLUTMrgNum();
      int num_allowedCand = std::min(MAX_NUM_HMVP_AVMPCANDS, num_avai_candInLUT);
    
      for (int mrgIdx = 1; mrgIdx <= num_allowedCand; mrgIdx++)
      {
        if (info.numCand >= AMVP_MAX_NUM_CANDS)
        {
          return;
        }
        neibMi = slice.getMotionInfoFromLUTs(num_avai_candInLUT - mrgIdx);
    
    
    Li's avatar
    Li committed
        for (int predictorSource = 0; predictorSource < 2; predictorSource++) 
    
        {
          const RefPicList eRefPicListIndex = (predictorSource == 0) ? eRefPicList : eRefPicList2nd;
          const int        neibRefIdx = neibMi.refIdx[eRefPicListIndex];
    
          if (neibRefIdx >= 0 && currRefPOC == slice.getRefPOC(eRefPicListIndex, neibRefIdx))
          {
            Mv pmv = neibMi.mv[eRefPicListIndex];
            if (imv != 0)
            {
              roundMV(pmv, imvShift);
            }
            for (i = 0; i < info.numCand; i++)
            {
              if (pmv == info.mvCand[i])
              {
                break;
              }
            }
            if (i == info.numCand)
            {
              info.mvCand[info.numCand++] = pmv;
              if (info.numCand >= AMVP_MAX_NUM_CANDS)
              {
                return;
              }
            }
          }
        }
      }
    }
    #endif
    
    bool PU::isBipredRestriction(const PredictionUnit &pu)
    {
      const SPSNext &spsNext = pu.cs->sps->getSpsNext();
    
    #if JVET_L0104_NO_4x4BI_INTER_CU
      if(pu.cu->lumaSize().width == 4 && pu.cu->lumaSize().height ==4 )
      {
        return true;
      }
    #endif
    
      if( !pu.cs->pcv->only2Nx2N && !spsNext.getUseSubPuMvp() && pu.cu->lumaSize().width == 8 && ( pu.lumaSize().width < 8 || pu.lumaSize().height < 8 ) )
      {
        return true;
      }
      return false;
    }
    
    
    void PU::getAffineControlPointCand( const PredictionUnit &pu, MotionInfo mi[4], bool isAvailable[4], int verIdx[4], int modelIdx, int verNum, AffineMergeCtx& affMrgType )
    
    {
      int cuW = pu.Y().width;
      int cuH = pu.Y().height;
      int vx, vy;
      int shift = MAX_CU_DEPTH;
      int shiftHtoW = shift + g_aucLog2[cuW] - g_aucLog2[cuH];
    
      // motion info
      Mv cMv[2][4];
      int refIdx[2] = { -1, -1 };
      int dir = 0;
      EAffineModel curType = (verNum == 2) ? AFFINEMODEL_4PARAM : AFFINEMODEL_6PARAM;
    
      if ( verNum == 2 )
      {
        int idx0 = verIdx[0], idx1 = verIdx[1];
    
        if ( !isAvailable[idx0] || !isAvailable[idx1] )
    
        {
          return;
        }
    
        for ( int l = 0; l < 2; l++ )
        {
          if ( mi[idx0].refIdx[l] >= 0 && mi[idx1].refIdx[l] >= 0 )
          {
            // check same refidx and different mv
            if ( mi[idx0].refIdx[l] == mi[idx1].refIdx[l] && mi[idx0].mv[l] != mi[idx1].mv[l] )
            {
              dir |= (l + 1);
              refIdx[l] = mi[idx0].refIdx[l];
            }
          }
        }
      }
      else if ( verNum == 3 )
      {
        int idx0 = verIdx[0], idx1 = verIdx[1], idx2 = verIdx[2];
    
        if ( !isAvailable[idx0] || !isAvailable[idx1] || !isAvailable[idx2] )
    
        {
          return;
        }
    
        for ( int l = 0; l < 2; l++ )
        {
          if ( mi[idx0].refIdx[l] >= 0 && mi[idx1].refIdx[l] >= 0 && mi[idx2].refIdx[l] >= 0 )
          {
            // check same refidx and different mv
            if ( mi[idx0].refIdx[l] == mi[idx1].refIdx[l] && mi[idx0].refIdx[l] == mi[idx2].refIdx[l] && (mi[idx0].mv[l] != mi[idx1].mv[l] || mi[idx0].mv[l] != mi[idx2].mv[l]) )
            {
              dir |= (l + 1);
              refIdx[l] = mi[idx0].refIdx[l];
            }
          }
        }
      }
    
      if ( dir == 0 )
      {
        return;
      }
    
    #if !REMOVE_MV_ADAPT_PREC
      for ( int l = 0; l < 2; l++ )
      {
        for ( int i = 0; i < 4; i++ )
        {
          cMv[l][i].highPrec = true;
        }
      }
    #endif
    
      for ( int l = 0; l < 2; l++ )
      {
        if ( dir & (l + 1) )
        {
          for ( int i = 0; i < verNum; i++ )
          {
            cMv[l][verIdx[i]] = mi[verIdx[i]].mv[l];
          }
    
          // convert to LT, RT[, [LB]]
          switch ( modelIdx )
          {
          case 0: // 0 : LT, RT, LB
            break;
    
          case 1: // 1 : LT, RT, RB
            cMv[l][2].hor = cMv[l][3].hor + cMv[l][0].hor - cMv[l][1].hor;
            cMv[l][2].ver = cMv[l][3].ver + cMv[l][0].ver - cMv[l][1].ver;
            break;
    
          case 2: // 2 : LT, LB, RB
            cMv[l][1].hor = cMv[l][3].hor + cMv[l][0].hor - cMv[l][2].hor;
            cMv[l][1].ver = cMv[l][3].ver + cMv[l][0].ver - cMv[l][2].ver;
            break;
    
          case 3: // 3 : RT, LB, RB
            cMv[l][0].hor = cMv[l][1].hor + cMv[l][2].hor - cMv[l][3].hor;
            cMv[l][0].ver = cMv[l][1].ver + cMv[l][2].ver - cMv[l][3].ver;
            break;
    
          case 4: // 4 : LT, RT
            break;
    
          case 5: // 5 : LT, LB
            vx = (cMv[l][0].hor << shift) + ((cMv[l][2].ver - cMv[l][0].ver) << shiftHtoW);
            vy = (cMv[l][0].ver << shift) - ((cMv[l][2].hor - cMv[l][0].hor) << shiftHtoW);
            roundAffineMv( vx, vy, shift );
            cMv[l][1].set( vx, vy );
            break;
    
          default:
            CHECK( 1, "Invalid model index!\n" );
            break;
          }
        }
        else
        {
          for ( int i = 0; i < 4; i++ )
          {
            cMv[l][i].hor = 0;
            cMv[l][i].ver = 0;
          }
        }
      }
    
      for ( int i = 0; i < 3; i++ )
      {
        affMrgType.mvFieldNeighbours[(affMrgType.numValidMergeCand << 1) + 0][i].mv = cMv[0][i];
        affMrgType.mvFieldNeighbours[(affMrgType.numValidMergeCand << 1) + 0][i].refIdx = refIdx[0];
    
        affMrgType.mvFieldNeighbours[(affMrgType.numValidMergeCand << 1) + 1][i].mv = cMv[1][i];
        affMrgType.mvFieldNeighbours[(affMrgType.numValidMergeCand << 1) + 1][i].refIdx = refIdx[1];
      }
      affMrgType.interDirNeighbours[affMrgType.numValidMergeCand] = dir;
      affMrgType.affineType[affMrgType.numValidMergeCand] = curType;
      affMrgType.numValidMergeCand++;