Skip to content
Snippets Groups Projects
UnitTools.cpp 171 KiB
Newer Older
  • Learn to ignore specific revisions
  •       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;
    
    #if REMOVE_MV_ADAPT_PREC
      imvShift += VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
    #endif
    
    
      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)
    {
    
    #if JVET_L0104_NO_4x4BI_INTER_CU
      if(pu.cu->lumaSize().width == 4 && pu.cu->lumaSize().height ==4 )
      {
        return true;
      }
    #endif
    
    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++;
    
    
      return;
    }
    
    const int getAvailableAffineNeighboursForLeftPredictor( const PredictionUnit &pu, const PredictionUnit* npu[] )
    {
      const Position posLB = pu.Y().bottomLeft();
      int num = 0;
    
      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;
        return num;
      }
    
      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;
        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();
      int num = numAffNeighLeft;
    
      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;
        return num;
      }
    
      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;
        return num;
      }
    
      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
        )
      {
        npu[num++] = puAboveLeft;
        return num;
      }
    
      return num;
    }
    
    void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx, const int mrgCandIdx )
    {
      const CodingStructure &cs = *pu.cs;
      const Slice &slice = *pu.cs->slice;
      const uint32_t maxNumAffineMergeCand = slice.getMaxNumAffineMergeCand();
    
      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;
    #if JVET_L0369_SUBBLOCK_MERGE
        affMrgCtx.mergeType[i] = MRG_TYPE_DEFAULT_N;
    #endif
    #if JVET_L0646_GBI
        affMrgCtx.GBiIdx[i] = GBI_DEFAULT;
    #endif
      }
    
      affMrgCtx.numValidMergeCand = 0;
      affMrgCtx.maxNumMergeCand = maxNumAffineMergeCand;
    
    #if JVET_L0369_SUBBLOCK_MERGE ///> insert ATMVP candidate
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    #if JVET_L0293_CPR
      bool enableSubPuMvp = slice.getSPS()->getSpsNext().getUseSubPuMvp() && !(slice.getPOC() == slice.getRefPic(REF_PIC_LIST_0, 0)->getPOC() && slice.isIRAP());
    #else
    
      bool enableSubPuMvp = slice.getSPS()->getSpsNext().getUseSubPuMvp();
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    #endif
    
      bool isAvailableSubPu = false;
      if ( enableSubPuMvp && slice.getEnableTMVPFlag() )
      {
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    #if JVET_L0293_CPR
        int  cntCPR = 0;
    #endif
    
        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 posCurRT = pu.Y().topRight();
        const Position posCurLB = pu.Y().bottomLeft();
        MotionInfo miAbove, miLeft, miAboveRight, miBelowLeft;
    
        //left
        const PredictionUnit* puLeft = cs.getPURestricted( posCurLB.offset( -1, 0 ), pu, pu.chType );
        const bool isAvailableA1 = puLeft && isDiffMER( pu, *puLeft ) && pu.cu != puLeft->cu && CU::isInter( *puLeft->cu );
        if ( isAvailableA1 )
        {
          miLeft = puLeft->getMotionInfo( posCurLB.offset( -1, 0 ) );
          // get Inter Dir
          mrgCtx.interDirNeighbours[pos] = miLeft.interDir;
    
          // get Mv from Left
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    #if JVET_L0293_CPR
          if (puLeft->cu->cpr)
          {
            cntCPR++;
          }
    #endif
    
          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++;
        }
    
        // above
        const PredictionUnit *puAbove = cs.getPURestricted( posCurRT.offset( 0, -1 ), pu, pu.chType );
        bool isAvailableB1 = puAbove && isDiffMER( pu, *puAbove ) && pu.cu != puAbove->cu && CU::isInter( *puAbove->cu );
        if ( isAvailableB1 )
        {
          miAbove = puAbove->getMotionInfo( posCurRT.offset( 0, -1 ) );
    
          if ( !isAvailableA1 || (miAbove != miLeft) )
          {
            // get Inter Dir
            mrgCtx.interDirNeighbours[pos] = miAbove.interDir;
            // get Mv from Left
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    #if JVET_L0293_CPR
            if (puAbove->cu->cpr)
            {
              cntCPR++;
            }
    #endif
    
            mrgCtx.mvFieldNeighbours[pos << 1].setMvField( miAbove.mv[0], miAbove.refIdx[0] );
    
            if ( slice.isInterB() )
            {
              mrgCtx.mvFieldNeighbours[(pos << 1) + 1].setMvField( miAbove.mv[1], miAbove.refIdx[1] );
            }
    
            pos++;
          }
        }
    
        // above right
        const PredictionUnit *puAboveRight = cs.getPURestricted( posCurRT.offset( 1, -1 ), pu, pu.chType );
        bool isAvailableB0 = puAboveRight && isDiffMER( pu, *puAboveRight ) && CU::isInter( *puAboveRight->cu );
        if ( isAvailableB0 )
        {
          miAboveRight = puAboveRight->getMotionInfo( posCurRT.offset( 1, -1 ) );
    
    #if HM_JEM_MERGE_CANDS
          if ( (!isAvailableB1 || (miAbove != miAboveRight)) && (!isAvailableA1 || (miLeft != miAboveRight)) )
    #else
          if ( !isAvailableB1 || (miAbove != miAboveRight) )
    #endif
          {
            // get Inter Dir
            mrgCtx.interDirNeighbours[pos] = miAboveRight.interDir;
            // get Mv from Left
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    #if JVET_L0293_CPR
            if (puAboveRight->cu->cpr)
            {
              cntCPR++;
            }
    #endif
    
            mrgCtx.mvFieldNeighbours[pos << 1].setMvField( miAboveRight.mv[0], miAboveRight.refIdx[0] );
    
            if ( slice.isInterB() )
            {
              mrgCtx.mvFieldNeighbours[(pos << 1) + 1].setMvField( miAboveRight.mv[1], miAboveRight.refIdx[1] );
            }
    
            pos++;
          }
        }
    
        //left bottom
        const PredictionUnit *puLeftBottom = cs.getPURestricted( posCurLB.offset( -1, 1 ), pu, pu.chType );
        bool isAvailableA0 = puLeftBottom && isDiffMER( pu, *puLeftBottom ) && CU::isInter( *puLeftBottom->cu );
        if ( isAvailableA0 )
        {
          miBelowLeft = puLeftBottom->getMotionInfo( posCurLB.offset( -1, 1 ) );
    
    #if HM_JEM_MERGE_CANDS
          if ( (!isAvailableA1 || (miBelowLeft != miLeft)) && (!isAvailableB1 || (miBelowLeft != miAbove)) && (!isAvailableB0 || (miBelowLeft != miAboveRight)) )
    #else
          if ( !isAvailableA1 || (miBelowLeft != miLeft) )
    #endif
          {
            // get Inter Dir
            mrgCtx.interDirNeighbours[pos] = miBelowLeft.interDir;
            // get Mv from Bottom-Left
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    #if JVET_L0293_CPR
            if (puLeftBottom->cu->cpr)
            {
              cntCPR++;
            }
    #endif
    
            mrgCtx.mvFieldNeighbours[pos << 1].setMvField( miBelowLeft.mv[0], miBelowLeft.refIdx[0] );
    
            if ( slice.isInterB() )
            {
              mrgCtx.mvFieldNeighbours[(pos << 1) + 1].setMvField( miBelowLeft.mv[1], miBelowLeft.refIdx[1] );
            }
            pos++;
          }
        }
        mrgCtx.numValidMergeCand = pos;
    
        isAvailableSubPu = getInterMergeSubPuMvpCand( pu, mrgCtx, tmpLICFlag, pos
    #if JVET_L0054_MMVD
          , 0
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    #endif
    #if JVET_L0293_CPR
          , cntCPR
    
    #endif
        );
        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;
          if ( affMrgCtx.numValidMergeCand == mrgCandIdx )
          {
            return;
          }
    
          affMrgCtx.numValidMergeCand++;
    
          // early termination
          if ( affMrgCtx.numValidMergeCand == maxNumAffineMergeCand )
          {
            return;
          }
        }
      }
    #endif
    
    #if JVET_L0369_SUBBLOCK_MERGE
      if ( slice.getSPS()->getSpsNext().getUseAffine() )
      {
    #endif
        ///> 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);
    #if JVET_L0646_GBI
          affMrgCtx.GBiIdx[affMrgCtx.numValidMergeCand] = puNeigh->cu->GBiIdx;
    #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 };
    
    
          // 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 )
    #if JVET_L0293_CPR
              && !puNeigh->cu->cpr
    #endif
              )
    
              mi[0] = puNeigh->getMotionInfo( pos );
    #if !REMOVE_MV_ADAPT_PREC
              mi[0].mv[0].setHighPrec();
              mi[0].mv[1].setHighPrec();
    #endif
              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 ) 
    #if JVET_L0293_CPR
              && !puNeigh->cu->cpr
    #endif
              )
    
              mi[1] = puNeigh->getMotionInfo( pos );
    #if !REMOVE_MV_ADAPT_PREC
              mi[1].mv[0].setHighPrec();
              mi[1].mv[1].setHighPrec();
    #endif
              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 ) 
    #if JVET_L0293_CPR
              && !puNeigh->cu->cpr
    #endif
              )
    
              mi[2] = puNeigh->getMotionInfo( pos );
    #if !REMOVE_MV_ADAPT_PREC
              mi[2].mv[0].setHighPrec();
              mi[2].mv[1].setHighPrec();
    #endif
              break;
            }
          }
    
          // control point: RB
          if ( slice.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;
    
            if ( ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight) )
            {
              Position posInCtu( posRB.x & pcv.maxCUWidthMask, posRB.y & pcv.maxCUHeightMask );
    
              if ( (posInCtu.x + 4 < pcv.maxCUWidth) &&  // is not at the last column of CTU
                (posInCtu.y + 4 < pcv.maxCUHeight) )     // is not at the last row    of CTU
              {
                posC0 = posRB.offset( 4, 4 );
                C0Avail = true;
              }
              else if ( posInCtu.x + 4 < pcv.maxCUWidth ) // is not at the last column of CTU But is last row of CTU
              {
                posC0 = posRB.offset( 4, 4 );
                // in the reference the CTU address is not set - thus probably resulting in no using this C0 possibility
              }
              else if ( posInCtu.y + 4 < pcv.maxCUHeight ) // is not at the last row of CTU But is last column of CTU
              {
                posC0 = posRB.offset( 4, 4 );
                C0Avail = true;
              }
              else //is the right bottom corner of CTU
              {
                posC0 = posRB.offset( 4, 4 );
                // same as for last column but not last row
              }
            }
    
            Mv        cColMv;
            int       refIdx = 0;
            bool      bExistMV = C0Avail && getColocatedMVP( pu, REF_PIC_LIST_0, posC0, cColMv, refIdx );
            if ( bExistMV )
            {
              mi[3].mv[0] = cColMv;
    #if !REMOVE_MV_ADAPT_PREC
              mi[3].mv[0].setHighPrec();
    #endif
              mi[3].refIdx[0] = refIdx;
              mi[3].interDir = 1;
    
            }
    
            if ( slice.isInterB() )
            {
              bExistMV = C0Avail && getColocatedMVP( pu, REF_PIC_LIST_1, posC0, cColMv, refIdx );
              if ( bExistMV )
              {
                mi[3].mv[1] = cColMv;
    #if !REMOVE_MV_ADAPT_PREC
                mi[3].mv[1].setHighPrec();
    #endif
                mi[3].refIdx[1] = refIdx;
                mi[3].interDir |= 2;
    
              }
            }
          }
    
          //-------------------  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->getSpsNext().getUseAffineType() ? 0 : 4;
          for ( int idx = startIdx; idx < modelNum; idx++ )
          {
            int modelIdx = order[idx];
    
            getAffineControlPointCand( pu, mi, isAvailable, model[modelIdx], modelIdx, verNum[modelIdx], affMrgCtx );
    
            if ( affMrgCtx.numValidMergeCand != 0 && affMrgCtx.numValidMergeCand - 1 == mrgCandIdx )
            {
              return;
            }
    
            // early termination
            if ( affMrgCtx.numValidMergeCand == maxNumAffineMergeCand )
            {
              return;
            }
          }
        }
        ///> End: Constructed affine candidates
    #if JVET_L0369_SUBBLOCK_MERGE
      }
    #endif
    
      ///> 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;
        cnt++;
    
        if ( cnt == maxNumAffineMergeCand )
        {
          return;
        }
      }
    }
    #else
    
    const PredictionUnit* getFirstAvailableAffineNeighbour( const PredictionUnit &pu )
    {
      const Position posLT = pu.Y().topLeft();
      const Position posRT = pu.Y().topRight();
      const Position posLB = pu.Y().bottomLeft();
    
      const PredictionUnit* puLeft = pu.cs->getPURestricted( posLB.offset( -1, 0 ), pu, pu.chType );
      if( puLeft && puLeft->cu->affine )
      {
        return puLeft;
      }
      const PredictionUnit* puAbove = pu.cs->getPURestricted( posRT.offset( 0, -1 ), pu, pu.chType );
      if( puAbove && puAbove->cu->affine )
      {
        return puAbove;
      }
      const PredictionUnit* puAboveRight = pu.cs->getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
      if( puAboveRight && puAboveRight->cu->affine )
      {
        return puAboveRight;
      }
      const PredictionUnit *puLeftBottom = pu.cs->getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType );
      if( puLeftBottom && puLeftBottom->cu->affine )
      {
        return puLeftBottom;
      }
      const PredictionUnit *puAboveLeft = pu.cs->getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType );
      if( puAboveLeft && puAboveLeft->cu->affine )
      {
        return puAboveLeft;
      }
      return nullptr;
    }
    
    bool PU::isAffineMrgFlagCoded( const PredictionUnit &pu )
    {
      if ( pu.cu->lumaSize().width < 8 || pu.cu->lumaSize().height < 8 )
      {
        return false;
      }
      return getFirstAvailableAffineNeighbour( pu ) != nullptr;
    }
    
    #if JVET_L0646_GBI
    void PU::getAffineMergeCand( const PredictionUnit &pu, MvField(*mvFieldNeighbours)[3], unsigned char &interDirNeighbours, unsigned char &gbiIdx, int &numValidMergeCand )
    #else
    
    void PU::getAffineMergeCand( const PredictionUnit &pu, MvField (*mvFieldNeighbours)[3], unsigned char &interDirNeighbours, int &numValidMergeCand )
    
    {
      for ( int mvNum = 0; mvNum < 3; mvNum++ )
      {
        mvFieldNeighbours[0][mvNum].setMvField( Mv(), -1 );
        mvFieldNeighbours[1][mvNum].setMvField( Mv(), -1 );
      }
    
      const PredictionUnit* puFirstNeighbour = getFirstAvailableAffineNeighbour( pu );
      if( puFirstNeighbour == nullptr )
      {
        numValidMergeCand = -1;
    
    #if JVET_L0646_GBI
        gbiIdx = GBI_DEFAULT;
    #endif
    
        return;
      }
      else
      {
        numValidMergeCand = 1;
      }
    
      // get Inter Dir
      interDirNeighbours = puFirstNeighbour->getMotionInfo().interDir;
    
      pu.cu->affineType = puFirstNeighbour->cu->affineType;
    
      // derive Mv from neighbor affine block
      Mv cMv[3];
      if ( interDirNeighbours != 2 )
      {
        xInheritedAffineMv( pu, puFirstNeighbour, REF_PIC_LIST_0, cMv );
        for ( int mvNum = 0; mvNum < 3; mvNum++ )
        {
          mvFieldNeighbours[0][mvNum].setMvField( cMv[mvNum], puFirstNeighbour->refIdx[0] );
        }
      }
    
      if ( pu.cs->slice->isInterB() )
      {
        if ( interDirNeighbours != 1 )
        {
          xInheritedAffineMv( pu, puFirstNeighbour, REF_PIC_LIST_1, cMv );
          for ( int mvNum = 0; mvNum < 3; mvNum++ )
          {
            mvFieldNeighbours[1][mvNum].setMvField( cMv[mvNum], puFirstNeighbour->refIdx[1] );
          }
        }
      }
    
    #if JVET_L0646_GBI
      gbiIdx = puFirstNeighbour->cu->GBiIdx;
    #endif