Skip to content
Snippets Groups Projects
UnitTools.cpp 166 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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];
    
    
    Xiang Li's avatar
    Xiang Li committed
      outputAffineMv[0].roundAffinePrecInternal2Amvr(pu.cu->imv);
      outputAffineMv[1].roundAffinePrecInternal2Amvr(pu.cu->imv);
      outputAffineMv[2].roundAffinePrecInternal2Amvr(pu.cu->imv);
    
      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++;
      }
    
      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
    
    Brian Heng's avatar
    Brian Heng committed
        if ( affiAMVPInfo.numCand < 2 && pu.cs->picHeader->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;
    
          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());
          }
          if (boundaryCond)
    
            int posYInCtu = posRB.y & pcv.maxCUHeightMask;
            if (posYInCtu + 4 < pcv.maxCUHeight)
    
              posC0 = posRB.offset(4, 4);
    
          if ( ( C0Avail && getColocatedMVP( pu, eRefPicList, posC0, cColMv, refIdxCol, false ) ) || getColocatedMVP( pu, eRefPicList, posC1, cColMv, refIdxCol, false ) )
    
    Xiang Li's avatar
    Xiang Li committed
            cColMv.roundAffinePrecInternal2Amvr(pu.cu->imv);
    
            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();
            affiAMVPInfo.numCand++;
          }
        }
      }
    
    
      for (int i = 0; i < affiAMVPInfo.numCand; i++)
      {
    
    Xiang Li's avatar
    Xiang Li committed
        affiAMVPInfo.mvCandLT[i].roundAffinePrecInternal2Amvr(pu.cu->imv);
        affiAMVPInfo.mvCandRT[i].roundAffinePrecInternal2Amvr(pu.cu->imv);
        affiAMVPInfo.mvCandLB[i].roundAffinePrecInternal2Amvr(pu.cu->imv);
    
    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 ) )
        {
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if TM_AMVP
          info.mvCand[info.numCand] = neibMi.mv[eRefPicListIndex];
          if (!info.xCheckSimilarMotion(info.numCand))
          {
            info.numCand++;
            return true;
          }
    #else
    
    Huanbang Chen's avatar
    Huanbang Chen committed
          info.mvCand[info.numCand++] = neibMi.mv[eRefPicListIndex];
          return true;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    void PU::addAMVPHMVPCand(const PredictionUnit &pu, const RefPicList eRefPicList, const int currRefPOC, AMVPInfo &info)
    
    {
      const Slice &slice = *(*pu.cs).slice;
    
      MotionInfo neibMi;
    
      auto &lut = CU::isIBC(*pu.cu) ? pu.cs->motionLut.lutIbc : pu.cs->motionLut.lut;
      int num_avai_candInLUT = (int) lut.size();
    
      int num_allowedCand = std::min(MAX_NUM_HMVP_AVMPCANDS, num_avai_candInLUT);
    
      const RefPicList eRefPicList2nd = (eRefPicList == REF_PIC_LIST_0) ? REF_PIC_LIST_1 : REF_PIC_LIST_0;
    
    
      for (int mrgIdx = 1; mrgIdx <= num_allowedCand; mrgIdx++)
      {
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if TM_AMVP
        if (info.numCand >= info.maxStorageSize)
    #else
    
        if (info.numCand >= AMVP_MAX_NUM_CANDS)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
        neibMi = lut[mrgIdx - 1];
    
        for (int predictorSource = 0; predictorSource < 2; predictorSource++)
    
        {
          const RefPicList eRefPicListIndex = (predictorSource == 0) ? eRefPicList : eRefPicList2nd;
          const int        neibRefIdx = neibMi.refIdx[eRefPicListIndex];
    
    
    Yu Han's avatar
    Yu Han committed
          if (neibRefIdx >= 0 && (CU::isIBC(*pu.cu) || (currRefPOC == slice.getRefPOC(eRefPicListIndex, neibRefIdx))))
    
          {
            Mv pmv = neibMi.mv[eRefPicListIndex];
    
    Xiang Li's avatar
    Xiang Li committed
            pmv.roundTransPrecInternal2Amvr(pu.cu->imv);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if TM_AMVP
            info.mvCand[info.numCand] = pmv;
            if (!info.xCheckSimilarMotion(info.numCand))
            {
              info.numCand++;
            }
    
            if( info.numCand >= info.maxStorageSize )
            {
              return;
            }
    #else
    
            info.mvCand[info.numCand++] = pmv;
            if (info.numCand >= AMVP_MAX_NUM_CANDS)
            {
              return;
            }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    bool PU::isBipredRestriction(const PredictionUnit &pu)
    {
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !INTER_RM_SIZE_CONSTRAINTS
    
      if(pu.cu->lumaSize().width == 4 && pu.cu->lumaSize().height ==4 )
      {
        return true;
      }
    
      /* disable bi-prediction for 4x8/8x4 */
      if ( pu.cu->lumaSize().width + pu.cu->lumaSize().height == 12 )
      {
        return true;
      }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    void PU::getAffineControlPointCand(const PredictionUnit &pu, MotionInfo mi[4], bool isAvailable[4], int verIdx[4], int8_t bcwIdx, 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 + floorLog2(cuW) - floorLog2(cuH);
    
    
      // motion info
      Mv cMv[2][4];
      int refIdx[2] = { -1, -1 };
      int dir = 0;
      EAffineModel curType = (verNum == 2) ? AFFINEMODEL_4PARAM : AFFINEMODEL_6PARAM;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if INTER_LIC
      bool LICFlag = false;
    #endif
    
      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])
    
            {
              dir |= (l + 1);
              refIdx[l] = mi[idx0].refIdx[l];
            }
          }
        }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if INTER_LIC
        LICFlag = mi[idx0].usesLIC || mi[idx1].usesLIC;
    #endif
    
      }
      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])
    
            {
              dir |= (l + 1);
              refIdx[l] = mi[idx0].refIdx[l];
            }
          }
        }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if INTER_LIC
        LICFlag = mi[idx0].usesLIC || mi[idx1].usesLIC || mi[idx2].usesLIC;
    #endif
    
      }
    
      if ( dir == 0 )
      {
        return;
      }
    
      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;
    
            cMv[l][2].clipToStorageBitDepth();
    
            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;
    
            cMv[l][1].clipToStorageBitDepth();
    
            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;
    
            cMv[l][0].clipToStorageBitDepth();
    
            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 );
    
            cMv[l][1].clipToStorageBitDepth();
    
            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.BcwIdx[affMrgType.numValidMergeCand] = (dir == 3) ? bcwIdx : BCW_DEFAULT;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if INTER_LIC
      affMrgType.LICFlags[affMrgType.numValidMergeCand] = LICFlag;
    #endif
    
      affMrgType.numValidMergeCand++;
    
      return;
    }
    
    const int getAvailableAffineNeighboursForLeftPredictor( const PredictionUnit &pu, const PredictionUnit* npu[] )
    {
      const Position posLB = pu.Y().bottomLeft();
      int num = 0;
    
    Han Huang's avatar
    Han Huang committed
      const unsigned plevel = pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2;
    
    
      const PredictionUnit *puLeftBottom = pu.cs->getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType );
    
      if (puLeftBottom && puLeftBottom->cu->affine && puLeftBottom->mergeType == MRG_TYPE_DEFAULT_N
          && PU::isDiffMER(pu.lumaPos(), posLB.offset(-1, 1), plevel))
    
      {
        npu[num++] = puLeftBottom;
        return num;
      }
    
      const PredictionUnit* puLeft = pu.cs->getPURestricted( posLB.offset( -1, 0 ), pu, pu.chType );
    
      if (puLeft && puLeft->cu->affine && puLeft->mergeType == MRG_TYPE_DEFAULT_N
          && PU::isDiffMER(pu.lumaPos(), posLB.offset(-1, 0), plevel))
    
      {
        npu[num++] = puLeft;
        return num;
      }
    
      return num;
    }
    
    const int getAvailableAffineNeighboursForAbovePredictor( const PredictionUnit &pu, const PredictionUnit* npu[], int numAffNeighLeft )
    {
      const Position posLT = pu.Y().topLeft();
      const Position posRT = pu.Y().topRight();
    
    Han Huang's avatar
    Han Huang committed
      const unsigned plevel = pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2;
    
      int num = numAffNeighLeft;
    
      const PredictionUnit* puAboveRight = pu.cs->getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
    
      if (puAboveRight && puAboveRight->cu->affine && puAboveRight->mergeType == MRG_TYPE_DEFAULT_N
          && PU::isDiffMER(pu.lumaPos(), posRT.offset(1, -1), plevel))
    
      {
        npu[num++] = puAboveRight;
        return num;
      }
    
      const PredictionUnit* puAbove = pu.cs->getPURestricted( posRT.offset( 0, -1 ), pu, pu.chType );
    
      if (puAbove && puAbove->cu->affine && puAbove->mergeType == MRG_TYPE_DEFAULT_N
          && PU::isDiffMER(pu.lumaPos(), posRT.offset(0, -1), plevel))
    
      {
        npu[num++] = puAbove;
        return num;
      }
    
      const PredictionUnit *puAboveLeft = pu.cs->getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType );
    
      if (puAboveLeft && puAboveLeft->cu->affine && puAboveLeft->mergeType == MRG_TYPE_DEFAULT_N
          && PU::isDiffMER(pu.lumaPos(), posLT.offset(-1, -1), plevel))
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx,
    #if !AFFINE_MMVD
                                 const int mrgCandIdx
    #else
                                       int mrgCandIdx, bool isAfMmvd
    #endif
    )
    
    {
      const CodingStructure &cs = *pu.cs;
      const Slice &slice = *pu.cs->slice;
    
    Brian Heng's avatar
    Brian Heng committed
      const uint32_t maxNumAffineMergeCand = slice.getPicHeader()->getMaxNumAffineMergeCand();
    
    Han Huang's avatar
    Han Huang committed
      const unsigned plevel = pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2;
    
    
      for ( int i = 0; i < maxNumAffineMergeCand; i++ )
      {
        for ( int mvNum = 0; mvNum < 3; mvNum++ )
        {
          affMrgCtx.mvFieldNeighbours[(i << 1) + 0][mvNum].setMvField( Mv(), -1 );
          affMrgCtx.mvFieldNeighbours[(i << 1) + 1][mvNum].setMvField( Mv(), -1 );
        }
        affMrgCtx.interDirNeighbours[i] = 0;
        affMrgCtx.affineType[i] = AFFINEMODEL_4PARAM;
        affMrgCtx.mergeType[i] = MRG_TYPE_DEFAULT_N;
    
        affMrgCtx.BcwIdx[i] = BCW_DEFAULT;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if INTER_LIC
        affMrgCtx.LICFlags[i] = false;
    #endif
    
      }
    
      affMrgCtx.numValidMergeCand = 0;
      affMrgCtx.maxNumMergeCand = maxNumAffineMergeCand;
    
    
      bool sbTmvpEnableFlag = slice.getSPS()->getSbTMVPEnabledFlag()
                              && !(slice.getPOC() == slice.getRefPic(REF_PIC_LIST_0, 0)->getPOC() && slice.isIRAP());
    
      bool isAvailableSubPu = false;
    
      if (sbTmvpEnableFlag && slice.getPicHeader()->getEnableTMVPFlag())
    
      {
        MergeCtx mrgCtx = *affMrgCtx.mrgCtx;
        bool tmpLICFlag = false;
    
        CHECK( mrgCtx.subPuMvpMiBuf.area() == 0 || !mrgCtx.subPuMvpMiBuf.buf, "Buffer not initialized" );
        mrgCtx.subPuMvpMiBuf.fill( MotionInfo() );
    
        int pos = 0;
        // Get spatial MV
    
        const Position posCurLB = pu.Y().bottomLeft();
        MotionInfo miLeft;
    
    
        //left
        const PredictionUnit* puLeft = cs.getPURestricted( posCurLB.offset( -1, 0 ), pu, pu.chType );
    
    Han Huang's avatar
    Han Huang committed
        const bool isAvailableA1 = puLeft && isDiffMER(pu.lumaPos(), posCurLB.offset(-1, 0), plevel) && pu.cu != puLeft->cu && CU::isInter( *puLeft->cu );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if INTER_LIC
          affMrgCtx.mrgCtx->LICFlags[pos] = false;
    #endif
    
    
          miLeft = puLeft->getMotionInfo( posCurLB.offset( -1, 0 ) );
          // get Inter Dir
          mrgCtx.interDirNeighbours[pos] = miLeft.interDir;
    
          // get Mv from Left
          mrgCtx.mvFieldNeighbours[pos << 1].setMvField( miLeft.mv[0], miLeft.refIdx[0] );
    
          if ( slice.isInterB() )
          {
            mrgCtx.mvFieldNeighbours[(pos << 1) + 1].setMvField( miLeft.mv[1], miLeft.refIdx[1] );
          }
          pos++;
        }
    
        mrgCtx.numValidMergeCand = pos;
    
    
        isAvailableSubPu = getInterMergeSubPuMvpCand(pu, mrgCtx, tmpLICFlag, pos, 0);
    
        if ( isAvailableSubPu )
        {
          for ( int mvNum = 0; mvNum < 3; mvNum++ )
          {
            affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand << 1) + 0][mvNum].setMvField( mrgCtx.mvFieldNeighbours[(pos << 1) + 0].mv, mrgCtx.mvFieldNeighbours[(pos << 1) + 0].refIdx );
            affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand << 1) + 1][mvNum].setMvField( mrgCtx.mvFieldNeighbours[(pos << 1) + 1].mv, mrgCtx.mvFieldNeighbours[(pos << 1) + 1].refIdx );
          }
          affMrgCtx.interDirNeighbours[affMrgCtx.numValidMergeCand] = mrgCtx.interDirNeighbours[pos];
    
          affMrgCtx.affineType[affMrgCtx.numValidMergeCand] = AFFINE_MODEL_NUM;
          affMrgCtx.mergeType[affMrgCtx.numValidMergeCand] = MRG_TYPE_SUBPU_ATMVP;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if AFFINE_MMVD
          mrgCandIdx += (isAfMmvd && mrgCandIdx >= 0 ? 1 : 0);
    #endif
    
          if ( affMrgCtx.numValidMergeCand == mrgCandIdx )
          {
            return;
          }
    
          affMrgCtx.numValidMergeCand++;
    
          // early termination
          if ( affMrgCtx.numValidMergeCand == maxNumAffineMergeCand )
          {
            return;
          }
        }
      }
    
    
      if ( slice.getSPS()->getUseAffine() )
    
      {
        ///> Start: inherited affine candidates
        const PredictionUnit* npu[5];
        int numAffNeighLeft = getAvailableAffineNeighboursForLeftPredictor( pu, npu );
        int numAffNeigh = getAvailableAffineNeighboursForAbovePredictor( pu, npu, numAffNeighLeft );
        for ( int idx = 0; idx < numAffNeigh; idx++ )
        {
          // derive Mv from Neigh affine PU
          Mv cMv[2][3];
          const PredictionUnit* puNeigh = npu[idx];
          pu.cu->affineType = puNeigh->cu->affineType;
          if ( puNeigh->interDir != 2 )
          {
            xInheritedAffineMv( pu, puNeigh, REF_PIC_LIST_0, cMv[0] );
          }
          if ( slice.isInterB() )
          {
            if ( puNeigh->interDir != 1 )
            {
              xInheritedAffineMv( pu, puNeigh, REF_PIC_LIST_1, cMv[1] );
            }
          }
    
          for ( int mvNum = 0; mvNum < 3; mvNum++ )
          {
            affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand << 1) + 0][mvNum].setMvField( cMv[0][mvNum], puNeigh->refIdx[0] );
            affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand << 1) + 1][mvNum].setMvField( cMv[1][mvNum], puNeigh->refIdx[1] );
          }
          affMrgCtx.interDirNeighbours[affMrgCtx.numValidMergeCand] = puNeigh->interDir;
          affMrgCtx.affineType[affMrgCtx.numValidMergeCand] = (EAffineModel)(puNeigh->cu->affineType);
    
          affMrgCtx.BcwIdx[affMrgCtx.numValidMergeCand] = puNeigh->cu->BcwIdx;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if INTER_LIC
          CHECK( puNeigh->interDir == 3 && puNeigh->cu->LICFlag, "LIC should not be enabled for affine bi-pred" );
          affMrgCtx.LICFlags[affMrgCtx.numValidMergeCand] = puNeigh->cu->LICFlag;
    #endif
    
          if ( affMrgCtx.numValidMergeCand == mrgCandIdx )
          {
            return;
          }
    
          // early termination
          affMrgCtx.numValidMergeCand++;
          if ( affMrgCtx.numValidMergeCand == maxNumAffineMergeCand )
          {
            return;
          }
        }
        ///> End: inherited affine candidates
    
        ///> Start: Constructed affine candidates
        {
          MotionInfo mi[4];
    
          bool isAvailable[4] = { false };
    
          int8_t neighBcw[2] = { BCW_DEFAULT, BCW_DEFAULT };
    
          // control point: LT B2->B3->A2
          const Position posLT[3] = { pu.Y().topLeft().offset( -1, -1 ), pu.Y().topLeft().offset( 0, -1 ), pu.Y().topLeft().offset( -1, 0 ) };
          for ( int i = 0; i < 3; i++ )
          {
            const Position pos = posLT[i];
            const PredictionUnit* puNeigh = cs.getPURestricted( pos, pu, pu.chType );
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
    
            if (puNeigh && CU::isInter(*puNeigh->cu) && PU::isDiffMER(pu.lumaPos(), pos, plevel))
    
              mi[0] = puNeigh->getMotionInfo( pos );
    
              neighBcw[0] = puNeigh->cu->BcwIdx;
    
              break;
            }
          }
    
          // control point: RT B1->B0
          const Position posRT[2] = { pu.Y().topRight().offset( 0, -1 ), pu.Y().topRight().offset( 1, -1 ) };
          for ( int i = 0; i < 2; i++ )
          {
            const Position pos = posRT[i];
            const PredictionUnit* puNeigh = cs.getPURestricted( pos, pu, pu.chType );
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
    
            if (puNeigh && CU::isInter(*puNeigh->cu) && PU::isDiffMER(pu.lumaPos(), pos, plevel))
    
              mi[1] = puNeigh->getMotionInfo( pos );
    
              neighBcw[1] = puNeigh->cu->BcwIdx;
    
              break;
            }
          }
    
          // control point: LB A1->A0
          const Position posLB[2] = { pu.Y().bottomLeft().offset( -1, 0 ), pu.Y().bottomLeft().offset( -1, 1 ) };
          for ( int i = 0; i < 2; i++ )
          {
            const Position pos = posLB[i];
            const PredictionUnit* puNeigh = cs.getPURestricted( pos, pu, pu.chType );
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
    
            if (puNeigh && CU::isInter(*puNeigh->cu) && PU::isDiffMER(pu.lumaPos(), pos, plevel))
    
              mi[2] = puNeigh->getMotionInfo( pos );
              break;
            }
          }
    
          // control point: RB
    
    Brian Heng's avatar
    Brian Heng committed
          if ( slice.getPicHeader()->getEnableTMVPFlag() )
    
          {
            //>> 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 );
    
            const PreCalcValues& pcv = *cs.pcv;
            Position posC0;
            bool C0Avail = false;
    
    
            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());
            }
            if (boundaryCond)
    
              int posYInCtu = posRB.y & pcv.maxCUHeightMask;
              if (posYInCtu + 4 < pcv.maxCUHeight)
    
                posC0 = posRB.offset(4, 4);
    
            bool      bExistMV = C0Avail && getColocatedMVP( pu, REF_PIC_LIST_0, posC0, cColMv, refIdx, false );
    
            if ( bExistMV )
            {
              mi[3].mv[0] = cColMv;
              mi[3].refIdx[0] = refIdx;
              mi[3].interDir = 1;
    
              bExistMV = C0Avail && getColocatedMVP( pu, REF_PIC_LIST_1, posC0, cColMv, refIdx, false );
    
              if ( bExistMV )
              {
                mi[3].mv[1] = cColMv;
                mi[3].refIdx[1] = refIdx;
                mi[3].interDir |= 2;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if INTER_LIC
            mi[3].usesLIC = false;
    #endif
    
          }
    
          //-------------------  insert model  -------------------//
          int order[6] = { 0, 1, 2, 3, 4, 5 };
          int modelNum = 6;
          int model[6][4] = {
            { 0, 1, 2 },          // 0:  LT, RT, LB
            { 0, 1, 3 },          // 1:  LT, RT, RB
            { 0, 2, 3 },          // 2:  LT, LB, RB
            { 1, 2, 3 },          // 3:  RT, LB, RB
            { 0, 1 },             // 4:  LT, RT
            { 0, 2 },             // 5:  LT, LB
          };
    
          int verNum[6] = { 3, 3, 3, 3, 2, 2 };
    
          int startIdx = pu.cs->sps->getUseAffineType() ? 0 : 4;
    
          for ( int idx = startIdx; idx < modelNum; idx++ )
          {
            int modelIdx = order[idx];
    
            getAffineControlPointCand(pu, mi, isAvailable, model[modelIdx], ((modelIdx == 3) ? neighBcw[1] : neighBcw[0]), modelIdx, verNum[modelIdx], affMrgCtx);
    
            if ( affMrgCtx.numValidMergeCand != 0 && affMrgCtx.numValidMergeCand - 1 == mrgCandIdx )
            {
              return;
            }
    
            // early termination
            if ( affMrgCtx.numValidMergeCand == maxNumAffineMergeCand )
            {
              return;
            }
          }
        }
        ///> End: Constructed affine candidates
      }
    
      ///> zero padding
      int cnt = affMrgCtx.numValidMergeCand;
      while ( cnt < maxNumAffineMergeCand )
      {
        for ( int mvNum = 0; mvNum < 3; mvNum++ )
        {
          affMrgCtx.mvFieldNeighbours[(cnt << 1) + 0][mvNum].setMvField( Mv( 0, 0 ), 0 );
        }
        affMrgCtx.interDirNeighbours[cnt] = 1;
    
        if ( slice.isInterB() )
        {
          for ( int mvNum = 0; mvNum < 3; mvNum++ )
          {
            affMrgCtx.mvFieldNeighbours[(cnt << 1) + 1][mvNum].setMvField( Mv( 0, 0 ), 0 );
          }
          affMrgCtx.interDirNeighbours[cnt] = 3;
        }
        affMrgCtx.affineType[cnt] = AFFINEMODEL_4PARAM;
    
    roberta's avatar
    roberta committed
        if ( cnt == mrgCandIdx )
    
    roberta's avatar
    roberta committed
        cnt++;
        affMrgCtx.numValidMergeCand++;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if AFFINE_MMVD
    uint8_t PU::getMergeIdxFromAfMmvdBaseIdx(AffineMergeCtx& affMrgCtx, uint16_t afMmvdBaseIdx)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      uint8_t mergeIdx = (uint8_t)afMmvdBaseIdx;
      for (int i = 0; i < affMrgCtx.numValidMergeCand; i++)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        if (affMrgCtx.mergeType[i] != MRG_TYPE_DEFAULT_N)
        {
          ++mergeIdx;
        }
        else
        {
          break;
        }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      return mergeIdx;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    void PU::getAfMmvdMvf(const PredictionUnit& pu, const AffineMergeCtx& affineMergeCtx, MvField mvfMmvd[2][3], const uint16_t afMmvdBase, const uint16_t offsetStep, const uint16_t offsetDir)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
      CHECK(!pu.cu->affine, "Affine flag is not on for Affine MMVD mode!");
      CHECK(affineMergeCtx.mergeType[afMmvdBase] != MRG_TYPE_DEFAULT_N, "AFF_MMVD base candidate type is not regular Affine!");
    
      static const int32_t refMvdCands[AF_MMVD_STEP_NUM] = { 1, 2, 4, 8, 16 };
      static const int32_t iPicSize = pu.cu->slice->getPic()->lumaSize().area();
      static const int32_t mvShift  = iPicSize < 921600 ? 0 : ( iPicSize < 4096000 ? 2 : MV_FRACTIONAL_BITS_INTERNAL - 1); // 921600 = 1280x720, 4096000 = 2560x1600
      int step = refMvdCands[offsetStep] << mvShift;
      int affineType = affineMergeCtx.affineType[afMmvdBase];
    
      uint8_t interDir = affineMergeCtx.interDirNeighbours[afMmvdBase];
      int8_t refIdxL0 = affineMergeCtx.mvFieldNeighbours[(afMmvdBase << 1)    ][0].refIdx;
      int8_t refIdxL1 = affineMergeCtx.mvFieldNeighbours[(afMmvdBase << 1) + 1][0].refIdx;
    
      Mv baseMv[2][3];
      for (int i = 0; i < 3; i++)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        baseMv[0][i] = affineMergeCtx.mvFieldNeighbours[(afMmvdBase << 1)    ][i].mv;
        baseMv[1][i] = affineMergeCtx.mvFieldNeighbours[(afMmvdBase << 1) + 1][i].mv;
        mvfMmvd[0][i].refIdx = refIdxL0;
        mvfMmvd[1][i].refIdx = refIdxL1;
        mvfMmvd[0][i].mv = Mv();
        mvfMmvd[1][i].mv = Mv();
      }
    
      int magY = (offsetDir >> 1) & 0x1;
      int sign = (offsetDir & 0x1) ? -1 : 1;
      int offsetX = (1 - magY) * sign * step;
      int offsetY = (    magY) * sign * step;
      Mv offsetMv(offsetX, offsetY);
    
      int numCp = (affineType == AFFINEMODEL_4PARAM) ? 2 : 3;
      for (int cpIdx = 0; cpIdx < numCp; cpIdx++)
      {
        if (interDir == 1)
        {
          mvfMmvd[0][cpIdx].mv = baseMv[0][cpIdx] + offsetMv;
        }
        else if (interDir == 2)
        {
          mvfMmvd[1][cpIdx].mv = baseMv[1][cpIdx] + offsetMv;
        }
        else if (interDir == 3)
        {
          int poc_cur = pu.cu->slice->getPOC();
          int poc_l0  = pu.cu->slice->getRefPOC(REF_PIC_LIST_0, refIdxL0);
          int poc_l1  = pu.cu->slice->getRefPOC(REF_PIC_LIST_1, refIdxL1);
    
          int distL0 = poc_l0 - poc_cur;
          int distL1 = poc_l1 - poc_cur;
          mvfMmvd[0][cpIdx].mv =                                                     baseMv[0][cpIdx] + offsetMv;
          mvfMmvd[1][cpIdx].mv = distL0 * distL1 < 0 ? baseMv[1][cpIdx] - offsetMv : baseMv[1][cpIdx] + offsetMv;
        }
      }
    }
    
    int32_t PU::getAfMmvdEstBits(const PredictionUnit &pu)
    {
      int baseBits = (AF_MMVD_BASE_NUM == 1 ? 0 : pu.afMmvdBaseIdx + (pu.afMmvdBaseIdx == AF_MMVD_BASE_NUM - 1 ? 0: 1));
      int stepBits = pu.afMmvdStep + (pu.afMmvdStep == AF_MMVD_STEP_NUM - 1 ? 0 : 1);
      int dirBits  = gp_sizeIdxInfo->idxFrom(AF_MMVD_OFFSET_DIR);
    
      return stepBits + dirBits + baseBits;
    }
    #endif
    
    void PU::setAllAffineMvField( PredictionUnit &pu, MvField *mvField, RefPicList eRefList )
    {
      // Set Mv
      Mv mv[3];
      for ( int i = 0; i < 3; i++ )
      {
        mv[i] = mvField[i].mv;
      }
      setAllAffineMv( pu, mv[0], mv[1], mv[2], eRefList );
    
      // Set RefIdx
      CHECK( mvField[0].refIdx != mvField[1].refIdx || mvField[0].refIdx != mvField[2].refIdx, "Affine mv corners don't have the same refIdx." );
      pu.refIdx[eRefList] = mvField[0].refIdx;
    }
    
    void PU::setAllAffineMv(PredictionUnit& pu, Mv affLT, Mv affRT, Mv affLB, RefPicList eRefList, bool clipCPMVs)
    {
      int width  = pu.Y().width;
      int shift = MAX_CU_DEPTH;
      const bool isTranslational = (affLT == affRT && affLT == affLB);
    
      if (clipCPMVs)
      {
        affLT.mvCliptoStorageBitDepth();
    
        affRT.mvCliptoStorageBitDepth();
        if (pu.cu->affineType == AFFINEMODEL_6PARAM)
        {
          affLB.mvCliptoStorageBitDepth();
        }
      }
    
      int deltaMvHorX, deltaMvHorY, deltaMvVerX, deltaMvVerY;
    
      deltaMvHorX = (affRT - affLT).getHor() << (shift - floorLog2(width));
      deltaMvHorY = (affRT - affLT).getVer() << (shift - floorLog2(width));
    
      int height = pu.Y().height;
      if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
      {
    
        deltaMvVerX = (affLB - affLT).getHor() << (shift - floorLog2(height));
        deltaMvVerY = (affLB - affLT).getVer() << (shift - floorLog2(height));
    
      }
      else
      {
        deltaMvVerX = -deltaMvHorY;
        deltaMvVerY = deltaMvHorX;
      }
    
      int mvScaleHor = affLT.getHor() << shift;
      int mvScaleVer = affLT.getVer() << shift;
    
      int blockWidth = AFFINE_MIN_BLOCK_SIZE;
      int blockHeight = AFFINE_MIN_BLOCK_SIZE;
      const int halfBW = blockWidth >> 1;
      const int halfBH = blockHeight >> 1;
    
      MotionBuf mb = pu.getMotionBuf();
      int mvScaleTmpHor, mvScaleTmpVer;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !AFFINE_RM_CONSTRAINTS_AND_OPT
    
      const bool subblkMVSpreadOverLimit = InterPrediction::isSubblockVectorSpreadOverLimit( deltaMvHorX, deltaMvHorY, deltaMvVerX, deltaMvVerY, pu.interDir );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
      if (isTranslational)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
        mvScaleTmpHor = mvScaleHor;
        mvScaleTmpVer = mvScaleVer;
        roundAffineMv(mvScaleTmpHor, mvScaleTmpVer, shift);
        Mv curMv(mvScaleTmpHor, mvScaleTmpVer);
        curMv.clipToStorageBitDepth();
        MotionInfo *mi = mb.buf;
    
        for (int y = 0; y < (pu.Y().height >> MIN_CU_LOG2); y++)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          for (int x = 0; x < (pu.Y().width >> MIN_CU_LOG2); x++)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            mi[x].mv[eRefList] = curMv;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          mi += mb.stride;
        }
      }
    #if !AFFINE_RM_CONSTRAINTS_AND_OPT
      else if (subblkMVSpreadOverLimit)
      {
          mvScaleTmpHor = mvScaleHor + deltaMvHorX * ( pu.Y().width >> 1 ) + deltaMvVerX * ( pu.Y().height >> 1 );
          mvScaleTmpVer = mvScaleVer + deltaMvHorY * ( pu.Y().width >> 1 ) + deltaMvVerY * ( pu.Y().height >> 1 );
          roundAffineMv(mvScaleTmpHor, mvScaleTmpVer, shift);
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
          Mv curMv(mvScaleTmpHor, mvScaleTmpVer);
          curMv.clipToStorageBitDepth();
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          MotionInfo *mi = mb.buf;
          for (int y = 0; y < (pu.Y().height >> MIN_CU_LOG2); y++)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            for (int x = 0; x < (pu.Y().width >> MIN_CU_LOG2); x++)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
              mi[x].mv[eRefList] = curMv;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            mi += mb.stride;
          }
      }
    #endif
      else
      {
        int mvScaleHorLine = mvScaleHor + deltaMvHorX * halfBW + deltaMvVerX * halfBH;
        int mvScaleVerLine = mvScaleVer + deltaMvHorY * halfBW + deltaMvVerY * halfBH;
        int deltaMvVerXLine = deltaMvVerX * blockHeight;
        int deltaMvVerYLine = deltaMvVerY * blockHeight;
        int deltaMvHorXBlk = deltaMvHorX * blockWidth;
        int deltaMvHorYBlk = deltaMvHorY * blockWidth;
    
        MotionInfo *mi = mb.buf;
    
        for( int h = 0; h < pu.Y().height; h += blockHeight )
        {
          int mvScaleHorBlk = mvScaleHorLine;
          int mvScaleVerBlk = mvScaleVerLine;
    
          for( int w = 0; w < pu.Y().width; w += blockWidth )
          {
            mvScaleTmpHor = mvScaleHorBlk;
            mvScaleTmpVer = mvScaleVerBlk;
    
            mvScaleHorBlk += deltaMvHorXBlk;
            mvScaleVerBlk += deltaMvHorYBlk;
    
            roundAffineMv( mvScaleTmpHor, mvScaleTmpVer, shift );
            Mv curMv( mvScaleTmpHor, mvScaleTmpVer );
            curMv.clipToStorageBitDepth();
    
            mi[w >> MIN_CU_LOG2].mv[eRefList] = curMv;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    
          mi += ( blockHeight >> MIN_CU_LOG2 ) * mb.stride;
          mvScaleHorLine += deltaMvVerXLine;
          mvScaleVerLine += deltaMvVerYLine;