Skip to content
Snippets Groups Projects
InterSearch.cpp 223 KiB
Newer Older
  • Learn to ignore specific revisions
  • Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          sad += m_cDistParam.distFunc(m_cDistParam);
    
    
    Yu Han's avatar
    Yu Han committed
          xIBCSearchMVCandUpdate(sad, 0, y, sadBestCand, cMVCand);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          tempSadBest = sadBestCand[0];
          if (sadBestCand[0] <= 3)
          {
            bestX = cMVCand[0].getHor();
            bestY = cMVCand[0].getVer();
            sadBest = sadBestCand[0];
            rcMv.set(bestX, bestY);
            ruiCost = sadBest;
            goto end;
          }
        }
    
        const int boundX = std::max(srchRngHorLeft, -cuPelX);
        for (int x = 0 - roiWidth - puPelOffsetX; x >= boundX; --x)
        {
          if (!PU::isBlockVectorValid(pu, cuPelX, cuPelY, roiWidth, roiHeight, picWidth, picHeight, 0, 0, x, 0, lcuWidth))
          {
            continue;
          }
    
          sad = m_pcRdCost->getBvCostMultiplePreds(x, 0, pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL);
          m_cDistParam.cur.buf = piRefSrch + x;
          sad += m_cDistParam.distFunc(m_cDistParam);
    
    
    
    Yu Han's avatar
    Yu Han committed
          xIBCSearchMVCandUpdate(sad, x, 0, sadBestCand, cMVCand);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          tempSadBest = sadBestCand[0];
          if (sadBestCand[0] <= 3)
          {
            bestX = cMVCand[0].getHor();
            bestY = cMVCand[0].getVer();
            sadBest = sadBestCand[0];
            rcMv.set(bestX, bestY);
            ruiCost = sadBest;
            goto end;
          }
        }
    
        bestX = cMVCand[0].getHor();
        bestY = cMVCand[0].getVer();
        sadBest = sadBestCand[0];
        if ((!bestX && !bestY) || (sadBest - m_pcRdCost->getBvCostMultiplePreds(bestX, bestY, pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL) <= 32))
        {
          //chroma refine
    
    Yu Han's avatar
    Yu Han committed
          bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          bestX = cMVCand[bestCandIdx].getHor();
          bestY = cMVCand[bestCandIdx].getVer();
          sadBest = sadBestCand[bestCandIdx];
          rcMv.set(bestX, bestY);
          ruiCost = sadBest;
          goto end;
        }
    
    
        if (pu.lwidth() < 16 && pu.lheight() < 16)
        {
          for (int y = std::max(srchRngVerTop, -cuPelY); y <= srchRngVerBottom; y += 2)
          {
            if ((y == 0) || ((int)(cuPelY + y + roiHeight) >= picHeight))
              continue;
    
            for (int x = std::max(srchRngHorLeft, -cuPelX); x <= srchRngHorRight; x++)
            {
              if ((x == 0) || ((int)(cuPelX + x + roiWidth) >= picWidth))
                continue;
    
              if (!PU::isBlockVectorValid(pu, cuPelX, cuPelY, roiWidth, roiHeight, picWidth, picHeight, 0, 0, x, y, lcuWidth))
              {
                continue;
              }
    
              sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL);
              m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * y + x;
              sad += m_cDistParam.distFunc(m_cDistParam);
    
    
    Yu Han's avatar
    Yu Han committed
              xIBCSearchMVCandUpdate(sad, x, y, sadBestCand, cMVCand);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
            }
          }
    
          bestX = cMVCand[0].getHor();
          bestY = cMVCand[0].getVer();
          sadBest = sadBestCand[0];
          if (sadBest - m_pcRdCost->getBvCostMultiplePreds(bestX, bestY, pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL) <= 16)
          {
            //chroma refine
    
    Yu Han's avatar
    Yu Han committed
            bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
            bestX = cMVCand[bestCandIdx].getHor();
            bestY = cMVCand[bestCandIdx].getVer();
            sadBest = sadBestCand[bestCandIdx];
            rcMv.set(bestX, bestY);
            ruiCost = sadBest;
            goto end;
          }
    
    
          for (int y = (std::max(srchRngVerTop, -cuPelY) + 1); y <= srchRngVerBottom; y += 2)
          {
            if ((y == 0) || ((int)(cuPelY + y + roiHeight) >= picHeight))
              continue;
    
            for (int x = std::max(srchRngHorLeft, -cuPelX); x <= srchRngHorRight; x += 2)
            {
              if ((x == 0) || ((int)(cuPelX + x + roiWidth) >= picWidth))
                continue;
    
              if (!PU::isBlockVectorValid(pu, cuPelX, cuPelY, roiWidth, roiHeight, picWidth, picHeight, 0, 0, x, y, lcuWidth))
              {
                continue;
              }
    
              sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL);
              m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * y + x;
              sad += m_cDistParam.distFunc(m_cDistParam);
    
    
    
    Yu Han's avatar
    Yu Han committed
              xIBCSearchMVCandUpdate(sad, x, y, sadBestCand, cMVCand);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
              if (sadBestCand[0] <= 5)
              {
                //chroma refine & return
    
    Yu Han's avatar
    Yu Han committed
                bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
                bestX = cMVCand[bestCandIdx].getHor();
                bestY = cMVCand[bestCandIdx].getVer();
                sadBest = sadBestCand[bestCandIdx];
                rcMv.set(bestX, bestY);
                ruiCost = sadBest;
                goto end;
              }
            }
          }
    
          bestX = cMVCand[0].getHor();
          bestY = cMVCand[0].getVer();
          sadBest = sadBestCand[0];
    
          if ((sadBest >= tempSadBest) || ((sadBest - m_pcRdCost->getBvCostMultiplePreds(bestX, bestY, pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL)) <= 32))
          {
            //chroma refine
    
    Yu Han's avatar
    Yu Han committed
            bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
            bestX = cMVCand[bestCandIdx].getHor();
            bestY = cMVCand[bestCandIdx].getVer();
            sadBest = sadBestCand[bestCandIdx];
            rcMv.set(bestX, bestY);
            ruiCost = sadBest;
            goto end;
          }
    
          tempSadBest = sadBestCand[0];
    
    
          for (int y = (std::max(srchRngVerTop, -cuPelY) + 1); y <= srchRngVerBottom; y += 2)
          {
            if ((y == 0) || ((int)(cuPelY + y + roiHeight) >= picHeight))
              continue;
    
    
    
            for (int x = (std::max(srchRngHorLeft, -cuPelX) + 1); x <= srchRngHorRight; x += 2)
            {
    
              if ((x == 0) || ((int)(cuPelX + x + roiWidth) >= picWidth))
                continue;
    
              if (!PU::isBlockVectorValid(pu, cuPelX, cuPelY, roiWidth, roiHeight, picWidth, picHeight, 0, 0, x, y, lcuWidth))
              {
                continue;
              }
    
              sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL);
              m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * y + x;
              sad += m_cDistParam.distFunc(m_cDistParam);
    
    
    
    Yu Han's avatar
    Yu Han committed
              xIBCSearchMVCandUpdate(sad, x, y, sadBestCand, cMVCand);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
              if (sadBestCand[0] <= 5)
              {
                //chroma refine & return
    
    Yu Han's avatar
    Yu Han committed
                bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
                bestX = cMVCand[bestCandIdx].getHor();
                bestY = cMVCand[bestCandIdx].getVer();
                sadBest = sadBestCand[bestCandIdx];
                rcMv.set(bestX, bestY);
                ruiCost = sadBest;
                goto end;
              }
            }
          }
        }
      }
    
    
    Yu Han's avatar
    Yu Han committed
      bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
      bestX = cMVCand[bestCandIdx].getHor();
      bestY = cMVCand[bestCandIdx].getVer();
      sadBest = sadBestCand[bestCandIdx];
      rcMv.set(bestX, bestY);
      ruiCost = sadBest;
    
    end:
      if (roiWidth + roiHeight > 8)
      {
        m_numBVs = xMergeCandLists(m_acBVs, m_numBVs, cMVCand, CHROMA_REFINEMENT_CANDIDATES);
    
        if (roiWidth + roiHeight == 32)
        {
          m_numBV16s = m_numBVs;
        }
      }
    
      return;
    }
    
    
    
    // based on xMotionEstimation
    
    Yu Han's avatar
    Yu Han committed
    void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf,
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      Mv     *pcMvPred,
      Mv     &rcMv,
      Distortion &ruiCost, const int localSearchRangeX, const int localSearchRangeY
    )
    {
      bool buffered = false;
    
    Yu Han's avatar
    Yu Han committed
      if (m_pcEncCfg->getIBCFastMethod() & IBC_FAST_METHOD_BUFFERBV)
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      {
        ruiCost = MAX_UINT;
        const int iPicWidth = pu.cs->slice->getSPS()->getPicWidthInLumaSamples();
        const int iPicHeight = pu.cs->slice->getSPS()->getPicHeightInLumaSamples();
        const int   cuPelX = pu.Y().x;
        const int   cuPelY = pu.Y().y;
    
        int          iRoiWidth = pu.lwidth();
        int          iRoiHeight = pu.lheight();
        std::unordered_map<Mv, Distortion>& history = m_ctuRecord[pu.lumaPos()][pu.lumaSize()].bvRecord;
        const unsigned int  lcuWidth = pu.cs->slice->getSPS()->getMaxCUWidth();
        for (std::unordered_map<Mv, Distortion>::iterator p = history.begin(); p != history.end(); p++)
        {
          const Mv& bv = p->first;
    
          int xBv = bv.hor;
          int yBv = bv.ver;
          if (PU::isBlockVectorValid(pu, cuPelX, cuPelY, iRoiWidth, iRoiHeight, iPicWidth, iPicHeight, 0, 0, xBv, yBv, lcuWidth))
           {
            if (p->second < ruiCost)
            {
              rcMv = bv;
              ruiCost = p->second;
              buffered = true;
            }
    
    Gordon CLARE's avatar
    Gordon CLARE committed
            else if (p->second == ruiCost)
            {
              // stabilise the search through the unordered list
              if (bv.hor < rcMv.getHor()
                  || (bv.hor == rcMv.getHor() && bv.ver < rcMv.getVer()))
              {
                // update the vector.
                rcMv = bv;
              }
            }
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          }
        }
      }
    
      if (!buffered)
      {
        Mv        cMvSrchRngLT;
        Mv        cMvSrchRngRB;
    
        //cMvSrchRngLT.highPrec = false;
        //cMvSrchRngRB.highPrec = false;
    
        PelUnitBuf* pBuf = &origBuf;
    
        //  Search key pattern initialization
        CPelBuf  tmpPattern = pBuf->Y();
        CPelBuf* pcPatternKey = &tmpPattern;
    
    
    Taoran Lu's avatar
    Taoran Lu committed
    #if JVET_M0427_INLOOP_RESHAPER
        if ((pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag()))
        {
          const CompArea &area = pu.blocks[COMPONENT_Y];
          CompArea    tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size());
          PelBuf tmpOrgLuma = m_tmpStorageLCU.getBuf(tmpArea);
          tmpOrgLuma.copyFrom(tmpPattern);
          tmpOrgLuma.rspSignal(m_pcReshape->getFwdLUT());
          pcPatternKey = (CPelBuf*)&tmpOrgLuma;
        }
    #endif
    
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        m_lumaClpRng = pu.cs->slice->clpRng(COMPONENT_Y);
        Picture* refPic = pu.cu->slice->getPic();
    
        const CPelBuf refBuf = refPic->getRecoBuf(pu.blocks[COMPONENT_Y]);
    
        IntTZSearchStruct cStruct;
        cStruct.pcPatternKey = pcPatternKey;
        cStruct.iRefStride = refBuf.stride;
        cStruct.piRefY = refBuf.buf;
        cStruct.imvShift = pu.cu->imv << 1;
        cStruct.subShiftMode = 0; // used by intra pattern search function
    
                                  // assume that intra BV is integer-pel precision
        xSetIntraSearchRange(pu, pu.lwidth(), pu.lheight(), localSearchRangeX, localSearchRangeY, cMvSrchRngLT, cMvSrchRngRB);
    
        // disable weighted prediction
        setWpScalingDistParam(-1, REF_PIC_LIST_X, pu.cs->slice);
    
        m_pcRdCost->getMotionCost(0, pu.cu->transQuantBypass);
        m_pcRdCost->setPredictors(pcMvPred);
        m_pcRdCost->setCostScale(0);
    
        //  Do integer search
    
        xIntraPatternSearch(pu, cStruct, rcMv, ruiCost, &cMvSrchRngLT, &cMvSrchRngRB, pcMvPred);
      }
    }
    
    // based on xSetSearchRange
    void InterSearch::xSetIntraSearchRange(PredictionUnit& pu, int iRoiWidth, int iRoiHeight, const int localSearchRangeX, const int localSearchRangeY, Mv& rcMvSrchRngLT, Mv& rcMvSrchRngRB)
    {
      const SPS &sps = *pu.cs->sps;
    
      int srLeft, srRight, srTop, srBottom;
    
      const int cuPelX = pu.Y().x;
      const int cuPelY = pu.Y().y;
    
      const int iPicWidth = pu.cs->slice->getSPS()->getPicWidthInLumaSamples();
      const int iPicHeight = pu.cs->slice->getSPS()->getPicHeightInLumaSamples();
    
      srLeft = -std::min(cuPelX, localSearchRangeX);
      srTop = -std::min(cuPelY, localSearchRangeY);
    
      srRight = std::min(iPicWidth - cuPelX - iRoiWidth, localSearchRangeX);
      srBottom = std::min(iPicHeight - cuPelY - iRoiHeight, localSearchRangeY);
    
      rcMvSrchRngLT.setHor(srLeft);
      rcMvSrchRngLT.setVer(srTop);
      rcMvSrchRngRB.setHor(srRight);
      rcMvSrchRngRB.setVer(srBottom);
    
      rcMvSrchRngLT <<= 2;
      rcMvSrchRngRB <<= 2;
    
      xClipMv(rcMvSrchRngLT, pu.cu->lumaPos(),
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
             pu.cu->lumaSize(),
             sps);
    
      xClipMv(rcMvSrchRngRB, pu.cu->lumaPos(),
    
    Philippe Hanhart's avatar
    Philippe Hanhart committed
             pu.cu->lumaSize(),
             sps);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      rcMvSrchRngLT >>= 2;
      rcMvSrchRngRB >>= 2;
    }
    
    
    Yu Han's avatar
    Yu Han committed
    bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap)
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    {
    
    Yu Han's avatar
    Yu Han committed
      // check only no greater than IBC_MAX_CAND_SIZE
      if (cu.Y().width > IBC_MAX_CAND_SIZE || cu.Y().height > IBC_MAX_CAND_SIZE)
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        return false;
      Mv           cMvSrchRngLT;
      Mv           cMvSrchRngRB;
    
      Mv           cMv;
      Mv           cMvPred;
    
      for (auto &pu : CU::traversePUs(cu))
      {
        m_maxCompIDToPred = MAX_NUM_COMPONENT;
    
        CHECK(pu.cu != &cu, "PU is contained in another CU");
        //////////////////////////////////////////////////////////
    
    Yu Han's avatar
    Yu Han committed
        /// ibc search
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        pu.cu->imv = 2;
        AMVPInfo amvpInfo4Pel;
        PU::fillMvpCand(pu, REF_PIC_LIST_0, pu.refIdx[REF_PIC_LIST_0], amvpInfo4Pel);
    
    
        pu.cu->imv = 0;// (Int)cu.cs->sps->getSpsNext().getUseIMV(); // set as IMV=0 initially
        Mv    cMv, cMvPred[2];
        AMVPInfo amvpInfo;
        PU::fillMvpCand(pu, REF_PIC_LIST_0, pu.refIdx[REF_PIC_LIST_0], amvpInfo);
        cMvPred[0].set(amvpInfo.mvCand[0].getHor() >> (2), amvpInfo.mvCand[0].getVer() >> (2)); // store in full pel accuracy, shift before use in search
        cMvPred[1].set(amvpInfo.mvCand[1].getHor() >> (2), amvpInfo.mvCand[1].getVer() >> (2));
    
        int iBvpNum = 2;
        int bvpIdxBest = 0;
        cMv.setZero();
        Distortion cost = 0;
    
    
    Yu Han's avatar
    Yu Han committed
        if (m_pcEncCfg->getIBCHashSearch())
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        {
    
    Yu Han's avatar
    Yu Han committed
          xxIBCHashSearch(pu, cMvPred, iBvpNum, cMv, bvpIdxBest, ibcHashMap);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        }
    
        if (cMv.getHor() == 0 && cMv.getVer() == 0)
        {
          // if hash search does not work or is not enabled
          PelUnitBuf origBuf = pu.cs->getOrgBuf(pu);
    
    Yu Han's avatar
    Yu Han committed
          xIBCEstimation(pu, origBuf, cMvPred, cMv, cost, localSearchRangeX, localSearchRangeY);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        }
    
        if (cMv.getHor() == 0 && cMv.getVer() == 0)
        {
          return false;
        }
    
    Yu Han's avatar
    Yu Han committed
        /// ibc search
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
        /////////////////////////////////////////////////////////
        unsigned int bitsBVPBest, bitsBVPTemp;
        bitsBVPBest = MAX_INT;
        m_pcRdCost->setCostScale(0);
    
        for (int bvpIdxTemp = 0; bvpIdxTemp<iBvpNum; bvpIdxTemp++)
        {
          m_pcRdCost->setPredictor(cMvPred[bvpIdxTemp]);
    
          bitsBVPTemp = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor(), cMv.getVer(), 0);
    
          if (bitsBVPTemp < bitsBVPBest)
          {
            bitsBVPBest = bitsBVPTemp;
            bvpIdxBest = bvpIdxTemp;
    
            if (cu.cs->sps->getSpsNext().getImvMode() && cMv != cMvPred[bvpIdxTemp])
              pu.cu->imv = 1; // set as full-pel
            else
              pu.cu->imv = 0; // set as fractional-pel
    
          }
    
          unsigned int bitsBVPQP = MAX_UINT;
    
    
          Mv mvPredQuadPel;
          if ((cMv.getHor() % 4 == 0) && (cMv.getVer() % 4 == 0) && (pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL))
          {
            mvPredQuadPel = amvpInfo4Pel.mvCand[bvpIdxTemp];// cMvPred[bvpIdxTemp];
    
            mvPredQuadPel >>= (4);
    
            m_pcRdCost->setPredictor(mvPredQuadPel);
    
            bitsBVPQP = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor() >> 2, cMv.getVer() >> 2, 0);
    
          }
          mvPredQuadPel <<= (2);
          if (bitsBVPQP < bitsBVPBest && cMv != mvPredQuadPel)
          {
            bitsBVPBest = bitsBVPQP;
            bvpIdxBest = bvpIdxTemp;
    
            if (cu.cs->sps->getSpsNext().getImvMode())
              pu.cu->imv = 2; // set as quad-pel
          }
    
        }
    
        pu.bv = cMv;
        cMv <<= (2);
        pu.mv[REF_PIC_LIST_0] = cMv; // store in fractional pel accuracy
    
        pu.mvpIdx[REF_PIC_LIST_0] = bvpIdxBest;
    
        if(pu.cu->imv == 2 && cMv != amvpInfo4Pel.mvCand[bvpIdxBest])
          pu.mvd[REF_PIC_LIST_0] = cMv - amvpInfo4Pel.mvCand[bvpIdxBest];
        else
          pu.mvd[REF_PIC_LIST_0] = cMv - amvpInfo.mvCand[bvpIdxBest];
    
        if (pu.mvd[REF_PIC_LIST_0] == Mv(0, 0))
          pu.cu->imv = 0;
        if (pu.cu->imv == 2)
          assert((cMv.getHor() % 16 == 0) && (cMv.getVer() % 16 == 0));
        if (cu.cs->sps->getSpsNext().getUseIMV())
          assert(pu.cu->imv>0 || pu.mvd[REF_PIC_LIST_0] == Mv());
    
        if (!cu.cs->sps->getSpsNext().getUseIMV())
          pu.mvd[REF_PIC_LIST_0] >>= (2);
    
        pu.refIdx[REF_PIC_LIST_0] = pu.cs->slice->getNumRefIdx(REF_PIC_LIST_0) - 1;
    
        pu.mv[REF_PIC_LIST_0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
        m_ctuRecord[cu.lumaPos()][cu.lumaSize()].bvRecord[pu.bv] = cost;
      }
    
      return true;
    }
    
    
    Yu Han's avatar
    Yu Han committed
    void InterSearch::xxIBCHashSearch(PredictionUnit& pu, Mv* mvPred, int numMvPred, Mv &mv, int& idxMvPred, IbcHashMap& ibcHashMap)
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    {
      mv.setZero();
      m_pcRdCost->setCostScale(0);
    
      std::vector<Position> candPos;
    
    Yu Han's avatar
    Yu Han committed
      if (ibcHashMap.ibcHashMatch(pu.Y(), candPos, *pu.cs, m_pcEncCfg->getIBCHashSearchMaxCand(), m_pcEncCfg->getIBCHashSearchRange4SmallBlk()))
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      {
        unsigned int minCost = MAX_UINT;
    
        const unsigned int  lcuWidth = pu.cs->slice->getSPS()->getMaxCUWidth();
        const int   cuPelX = pu.Y().x;
        const int   cuPelY = pu.Y().y;
        const int   picWidth = pu.cs->slice->getSPS()->getPicWidthInLumaSamples();
        const int   picHeight = pu.cs->slice->getSPS()->getPicHeightInLumaSamples();
        int         roiWidth = pu.lwidth();
        int         roiHeight = pu.lheight();
    
        for (std::vector<Position>::iterator pos = candPos.begin(); pos != candPos.end(); pos++)
        {
          Position bottomRight = pos->offset(pu.Y().width - 1, pu.Y().height - 1);
          if (pu.cs->isDecomp(*pos, pu.cs->chType) && pu.cs->isDecomp(bottomRight, pu.cs->chType))
          {
            Position tmp = *pos - pu.Y().pos();
            Mv candMv;
            candMv.set(tmp.x, tmp.y);
    
            if (!PU::isBlockVectorValid(pu, cuPelX, cuPelY, roiWidth, roiHeight, picWidth, picHeight, 0, 0, candMv.getHor(), candMv.getVer(), lcuWidth))
            {
              continue;
            }
    
            for (int n = 0; n < numMvPred; n++)
            {
              m_pcRdCost->setPredictor(mvPred[n]);
    
              unsigned int cost = m_pcRdCost->getBitsOfVectorWithPredictor(candMv.getHor(), candMv.getVer(), 0);
    
              if (cost < minCost)
              {
                mv = candMv;
                idxMvPred = n;
                minCost = cost;
              }
    
              int costQuadPel = MAX_UINT;
              if ((candMv.getHor() % 4 == 0) && (candMv.getVer() % 4 == 0) && (pu.cs->sps->getSpsNext().getImvMode() == IMV_4PEL))
              {
                Mv mvPredQuadPel;
                int imvShift = 2;
                int offset = 1 << (imvShift - 1);
    
                mvPredQuadPel.set(((mvPred[n].hor + offset) >> 2), ((mvPred[n].ver + offset) >> 2));
    
                m_pcRdCost->setPredictor(mvPredQuadPel);
    
                costQuadPel = m_pcRdCost->getBitsOfVectorWithPredictor(candMv.getHor() >> 2, candMv.getVer() >> 2, 0);
    
              }
              if (costQuadPel < minCost)
              {
                mv = candMv;
                idxMvPred = n;
                minCost = costQuadPel;
              }
    
            }
          }
        }
      }
    
    }
    
    //! search of the best candidate for inter prediction
    void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
    {
      CodingStructure& cs = *cu.cs;
    
      AMVPInfo     amvp[2];
      Mv           cMvSrchRngLT;
      Mv           cMvSrchRngRB;
    
      Mv           cMvZero;
    
      Mv           cMv[2];
      Mv           cMvBi[2];
      Mv           cMvTemp[2][33];
      Mv           cMvHevcTemp[2][33];
      int          iNumPredDir = cs.slice->isInterP() ? 1 : 2;
    
      Mv           cMvPred[2][33];
    
      Mv           cMvPredBi[2][33];
      int          aaiMvpIdxBi[2][33];
    
      int          aaiMvpIdx[2][33];
      int          aaiMvpNum[2][33];
    
      AMVPInfo     aacAMVPInfo[2][33];
    
      int          iRefIdx[2]={0,0}; //If un-initialized, may cause SEGV in bi-directional prediction iterative stage.
      int          iRefIdxBi[2];
    
      uint32_t         uiMbBits[3] = {1, 1, 0};
    
      uint32_t         uiLastMode = 0;
      uint32_t         uiLastModeTemp = 0;
      int          iRefStart, iRefEnd;
    
    
    #if JVET_M0444_SMVD
      int          symMode = 0;
    #endif
    
    
      int          bestBiPRefIdxL1 = 0;
      int          bestBiPMvpL1    = 0;
      Distortion   biPDistTemp     = std::numeric_limits<Distortion>::max();
    
    
      uint8_t      gbiIdx          = (cu.cs->slice->isInterB() ? cu.GBiIdx : GBI_DEFAULT);
      bool         enforceGBiPred = false;
    
      MergeCtx     mergeCtx;
    
      // Loop over Prediction Units
      CHECK(!cu.firstPU, "CU does not contain any PUs");
      uint32_t         puIdx = 0;
      auto &pu = *cu.firstPU;
    
    
    #if JVET_M0246_AFFINE_AMVR
      bool checkAffine    = pu.cu->imv == 0 || pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag();
      bool checkNonAffine = pu.cu->imv == 0 || ( pu.cu->slice->getSPS()->getSpsNext().getUseIMV() && 
                                                 pu.cu->imv <= pu.cu->slice->getSPS()->getSpsNext().getImvMode() );
      CodingUnit *bestCU  = pu.cu->cs->bestCS != nullptr ? pu.cu->cs->bestCS->getCU( CHANNEL_TYPE_LUMA ) : nullptr;
    #if JVET_M0444_SMVD
      bool trySmvd        = ( bestCU != nullptr && pu.cu->imv == 2 && checkAffine ) ? ( !bestCU->firstPU->mergeFlag && !bestCU->affine ) : true;
    #endif
      if ( pu.cu->imv && bestCU != nullptr && checkAffine )
      {
        checkAffine = !( bestCU->firstPU->mergeFlag || !bestCU->affine );
      }
    
      if ( pu.cu->imv == 2 && checkNonAffine && pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag() )
      {
        checkNonAffine = m_affineMotion.hevcCost[1] < m_affineMotion.hevcCost[0] * 1.06f;
      }
    #endif
    
    
      {
        // motion estimation only evaluates luma component
        m_maxCompIDToPred = MAX_NUM_COMPONENT;
    //    m_maxCompIDToPred = COMPONENT_Y;
    
        CHECK(pu.cu != &cu, "PU is contained in another CU");
    
    
        if (cu.cs->sps->getSBTMVPEnabledFlag())
    
        {
          Size bufSize = g_miScaling.scale(pu.lumaSize());
          mergeCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
        }
    
        PU::spanMotionInfo( pu );
        Distortion   uiHevcCost = std::numeric_limits<Distortion>::max();
        Distortion   uiAffineCost = std::numeric_limits<Distortion>::max();
        Distortion   uiCost[2] = { std::numeric_limits<Distortion>::max(), std::numeric_limits<Distortion>::max() };
        Distortion   uiCostBi  =   std::numeric_limits<Distortion>::max();
        Distortion   uiCostTemp;
    
        uint32_t         uiBits[3];
        uint32_t         uiBitsTemp;
        Distortion   bestBiPDist = std::numeric_limits<Distortion>::max();
    
        Distortion   uiCostTempL0[MAX_NUM_REF];
        for (int iNumRef=0; iNumRef < MAX_NUM_REF; iNumRef++)
        {
          uiCostTempL0[iNumRef] = std::numeric_limits<Distortion>::max();
        }
        uint32_t         uiBitsTempL0[MAX_NUM_REF];
    
        Mv           mvValidList1;
        int          refIdxValidList1 = 0;
        uint32_t         bitsValidList1   = MAX_UINT;
        Distortion   costValidList1   = std::numeric_limits<Distortion>::max();
    
        PelUnitBuf origBuf = pu.cs->getOrgBuf( pu );
    
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        xGetBlkBits( cs.slice->isInterP(), puIdx, uiLastMode, uiMbBits );
    
    
        m_pcRdCost->selectMotionLambda( cu.transQuantBypass );
    
        unsigned imvShift = pu.cu->imv << 1;
    
    #if JVET_M0246_AFFINE_AMVR
        if ( checkNonAffine )
        {
    #endif
    
          //  Uni-directional prediction
          for ( int iRefList = 0; iRefList < iNumPredDir; iRefList++ )
          {
            RefPicList  eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 );
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
            int refPicNumber = cs.slice->getNumRefIdx(eRefPicList);
    
    Yu Han's avatar
    Yu Han committed
            if (cs.slice->getSPS()->getSpsNext().getIBCMode() && eRefPicList == REF_PIC_LIST_0)
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
            {
              refPicNumber--;
            }
            for (int iRefIdxTemp = 0; iRefIdxTemp < refPicNumber; iRefIdxTemp++)
    
            {
              uiBitsTemp = uiMbBits[iRefList];
              if ( cs.slice->getNumRefIdx(eRefPicList) > 1 )
              {
                uiBitsTemp += iRefIdxTemp+1;
                if ( iRefIdxTemp == cs.slice->getNumRefIdx(eRefPicList)-1 )
                {
                  uiBitsTemp--;
                }
              }
              xEstimateMvPredAMVP( pu, origBuf, eRefPicList, iRefIdxTemp, cMvPred[iRefList][iRefIdxTemp], amvp[eRefPicList], false, &biPDistTemp);
    
              aaiMvpIdx[iRefList][iRefIdxTemp] = pu.mvpIdx[eRefPicList];
              aaiMvpNum[iRefList][iRefIdxTemp] = pu.mvpNum[eRefPicList];
    
              if(cs.slice->getMvdL1ZeroFlag() && iRefList==1 && biPDistTemp < bestBiPDist)
              {
                bestBiPDist = biPDistTemp;
                bestBiPMvpL1 = aaiMvpIdx[iRefList][iRefIdxTemp];
                bestBiPRefIdxL1 = iRefIdxTemp;
              }
    
              uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdx[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS];
    
              if ( m_pcEncCfg->getFastMEForGenBLowDelayEnabled() && iRefList == 1 )    // list 1
              {
                if ( cs.slice->getList1IdxToList0Idx( iRefIdxTemp ) >= 0 )
                {
                  cMvTemp[1][iRefIdxTemp] = cMvTemp[0][cs.slice->getList1IdxToList0Idx( iRefIdxTemp )];
                  uiCostTemp = uiCostTempL0[cs.slice->getList1IdxToList0Idx( iRefIdxTemp )];
                  /*first subtract the bit-rate part of the cost of the other list*/
                  uiCostTemp -= m_pcRdCost->getCost( uiBitsTempL0[cs.slice->getList1IdxToList0Idx( iRefIdxTemp )] );
                  /*correct the bit-rate part of the current ref*/
                  m_pcRdCost->setPredictor  ( cMvPred[iRefList][iRefIdxTemp] );
                  uiBitsTemp += m_pcRdCost->getBitsOfVectorWithPredictor( cMvTemp[1][iRefIdxTemp].getHor(), cMvTemp[1][iRefIdxTemp].getVer(), imvShift );
                  /*calculate the correct cost*/
                  uiCostTemp += m_pcRdCost->getCost( uiBitsTemp );
                }
                else
                {
                  xMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, amvp[eRefPicList] );
                }
              }
              else
              {
                xMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, amvp[eRefPicList] );
              }
    
              if( cu.cs->sps->getSpsNext().getUseGBi() && cu.GBiIdx == GBI_DEFAULT && cu.cs->slice->isInterB() )
              {
                const bool checkIdentical = true;
    
                m_uniMotions.setReadMode(checkIdentical, (uint32_t)iRefList, (uint32_t)iRefIdxTemp);
                m_uniMotions.copyFrom(cMvTemp[iRefList][iRefIdxTemp], uiCostTemp - m_pcRdCost->getCost(uiBitsTemp), (uint32_t)iRefList, (uint32_t)iRefIdxTemp);
    
              xCopyAMVPInfo( &amvp[eRefPicList], &aacAMVPInfo[iRefList][iRefIdxTemp]); // must always be done ( also when AMVP_MODE = AM_NONE )
              xCheckBestMVP( eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], amvp[eRefPicList], uiBitsTemp, uiCostTemp, pu.cu->imv );
    
              if ( iRefList == 0 )
              {
                uiCostTempL0[iRefIdxTemp] = uiCostTemp;
                uiBitsTempL0[iRefIdxTemp] = uiBitsTemp;
              }
              if ( uiCostTemp < uiCost[iRefList] )
              {
                uiCost[iRefList] = uiCostTemp;
                uiBits[iRefList] = uiBitsTemp; // storing for bi-prediction
    
                // set motion
                cMv    [iRefList] = cMvTemp[iRefList][iRefIdxTemp];
                iRefIdx[iRefList] = iRefIdxTemp;
              }
    
              if ( iRefList == 1 && uiCostTemp < costValidList1 && cs.slice->getList1IdxToList0Idx( iRefIdxTemp ) < 0 )
              {
                costValidList1 = uiCostTemp;
                bitsValidList1 = uiBitsTemp;
    
                // set motion
                mvValidList1     = cMvTemp[iRefList][iRefIdxTemp];
                refIdxValidList1 = iRefIdxTemp;
              }
            }
          }
    
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          if (cu.Y().width > 8 && cu.Y().height > 8 && cu.slice->getSPS()->getSpsNext().getUseAffine()
    
    #if JVET_M0246_AFFINE_AMVR
            && checkAffine
    #else
    
            && (gbiIdx == GBI_DEFAULT || m_affineModeSelected || !m_pcEncCfg->getUseGBiFast())
    
            )
          {
            ::memcpy( cMvHevcTemp, cMvTemp, sizeof( cMvTemp ) );
          }
          //  Bi-predictive Motion estimation
    
          if( ( cs.slice->isInterB() ) && ( PU::isBipredRestriction( pu ) == false ) 
            && (cu.slice->getCheckLDC() || gbiIdx == GBI_DEFAULT || !m_affineModeSelected || !m_pcEncCfg->getUseGBiFast())
            )
    
          {
            cMvBi[0] = cMv[0];
            cMvBi[1] = cMv[1];
            iRefIdxBi[0] = iRefIdx[0];
            iRefIdxBi[1] = iRefIdx[1];
    
            ::memcpy( cMvPredBi,   cMvPred,   sizeof( cMvPred   ) );
            ::memcpy( aaiMvpIdxBi, aaiMvpIdx, sizeof( aaiMvpIdx ) );
    
            uint32_t uiMotBits[2];
    
            if(cs.slice->getMvdL1ZeroFlag())
            {
              xCopyAMVPInfo(&aacAMVPInfo[1][bestBiPRefIdxL1], &amvp[REF_PIC_LIST_1]);
              aaiMvpIdxBi[1][bestBiPRefIdxL1] = bestBiPMvpL1;
              cMvPredBi  [1][bestBiPRefIdxL1] = amvp[REF_PIC_LIST_1].mvCand[bestBiPMvpL1];
    
              cMvBi    [1] = cMvPredBi[1][bestBiPRefIdxL1];
              iRefIdxBi[1] = bestBiPRefIdxL1;
              pu.mv    [REF_PIC_LIST_1] = cMvBi[1];
    
              pu.mv[REF_PIC_LIST_1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
    
              pu.refIdx[REF_PIC_LIST_1] = iRefIdxBi[1];
              pu.mvpIdx[REF_PIC_LIST_1] = bestBiPMvpL1;
    
              PelUnitBuf predBufTmp = m_tmpPredStorage[REF_PIC_LIST_1].getBuf( UnitAreaRelative(cu, pu) );
              motionCompensation( pu, predBufTmp, REF_PIC_LIST_1 );
    
              uiMotBits[0] = uiBits[0] - uiMbBits[0];
              uiMotBits[1] = uiMbBits[1];
    
              if ( cs.slice->getNumRefIdx(REF_PIC_LIST_1) > 1 )
              {
                uiMotBits[1] += bestBiPRefIdxL1 + 1;
                if ( bestBiPRefIdxL1 == cs.slice->getNumRefIdx(REF_PIC_LIST_1)-1 )
                {
                  uiMotBits[1]--;
                }
              }
    
              uiMotBits[1] += m_auiMVPIdxCost[aaiMvpIdxBi[1][bestBiPRefIdxL1]][AMVP_MAX_NUM_CANDS];
    
              uiBits[2] = uiMbBits[2] + uiMotBits[0] + uiMotBits[1];
    
              cMvTemp[1][bestBiPRefIdxL1] = cMvBi[1];
            }
            else
            {
              uiMotBits[0] = uiBits[0] - uiMbBits[0];
              uiMotBits[1] = uiBits[1] - uiMbBits[1];
              uiBits[2] = uiMbBits[2] + uiMotBits[0] + uiMotBits[1];
            }
    
            // 4-times iteration (default)
            int iNumIter = 4;
    
            // fast encoder setting: only one iteration
            if ( m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE1 || m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE2 || cs.slice->getMvdL1ZeroFlag() )
            {
              iNumIter = 1;
            }
    
    
            enforceGBiPred = (gbiIdx != GBI_DEFAULT);
    
            for ( int iIter = 0; iIter < iNumIter; iIter++ )
            {
              int         iRefList    = iIter % 2;
    
              if ( m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE1 || m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE2 )
              {
                if( uiCost[0] <= uiCost[1] )
                {
                  iRefList = 1;
                }
                else
                {
                  iRefList = 0;
                }
    
                if( gbiIdx != GBI_DEFAULT )
                {
                  iRefList = ( abs( getGbiWeight(gbiIdx, REF_PIC_LIST_0 ) ) > abs( getGbiWeight(gbiIdx, REF_PIC_LIST_1 ) ) ? 1 : 0 );
                }
    
              }
              else if ( iIter == 0 )
              {
                iRefList = 0;
              }
              if ( iIter == 0 && !cs.slice->getMvdL1ZeroFlag())
              {
                pu.mv    [1 - iRefList] = cMv    [1 - iRefList];
    
                pu.mv[1 - iRefList].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
    
                pu.refIdx[1 - iRefList] = iRefIdx[1 - iRefList];
    
                PelUnitBuf predBufTmp = m_tmpPredStorage[1 - iRefList].getBuf( UnitAreaRelative(cu, pu) );
                motionCompensation( pu, predBufTmp, RefPicList(1 - iRefList) );
              }
    
              RefPicList  eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 );
    
              if(cs.slice->getMvdL1ZeroFlag())
              {
                iRefList = 0;
                eRefPicList = REF_PIC_LIST_0;
              }
    
              bool bChanged = false;
    
              iRefStart = 0;
              iRefEnd   = cs.slice->getNumRefIdx(eRefPicList)-1;
    
    Yu Han's avatar
    Yu Han committed
              if (cs.slice->getSPS()->getSpsNext().getIBCMode() && eRefPicList == REF_PIC_LIST_0)
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
              {
                iRefEnd--;
              }
    
              for (int iRefIdxTemp = iRefStart; iRefIdxTemp <= iRefEnd; iRefIdxTemp++)
    
                if( m_pcEncCfg->getUseGBiFast() && (gbiIdx != GBI_DEFAULT)
                  && (pu.cu->slice->getRefPic(eRefPicList, iRefIdxTemp)->getPOC() == pu.cu->slice->getRefPic(RefPicList(1 - iRefList), pu.refIdx[1 - iRefList])->getPOC())
                  && (!pu.cu->imv && pu.cu->slice->getTLayer()>1))
                {
                  continue;
                }
    
                uiBitsTemp = uiMbBits[2] + uiMotBits[1-iRefList];
    
                uiBitsTemp += ((cs.slice->getSPS()->getSpsNext().getUseGBi() == true) ? getWeightIdxBits(gbiIdx) : 0);
    
                if ( cs.slice->getNumRefIdx(eRefPicList) > 1 )
                {
                  uiBitsTemp += iRefIdxTemp+1;
                  if ( iRefIdxTemp == cs.slice->getNumRefIdx(eRefPicList)-1 )
                  {
                    uiBitsTemp--;
                  }
                }
                uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdxBi[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS];
    
    #if JVET_M0444_SMVD
                if ( cs.slice->getBiDirPred() )
                {
                  uiBitsTemp += 1; // add one bit for symmetrical MVD mode
                }
    #endif
    
                // call ME
                xCopyAMVPInfo(&aacAMVPInfo[iRefList][iRefIdxTemp], &amvp[eRefPicList] );
                xMotionEstimation ( pu, origBuf, eRefPicList, cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, amvp[eRefPicList], true );
                xCheckBestMVP( eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], amvp[eRefPicList], uiBitsTemp, uiCostTemp, pu.cu->imv);
                if ( uiCostTemp < uiCostBi )
                {
                  bChanged = true;
    
                  cMvBi[iRefList]     = cMvTemp[iRefList][iRefIdxTemp];
                  iRefIdxBi[iRefList] = iRefIdxTemp;
    
                  uiCostBi            = uiCostTemp;
                  uiMotBits[iRefList] = uiBitsTemp - uiMbBits[2] - uiMotBits[1-iRefList];
    
                  uiMotBits[iRefList] -= ((cs.slice->getSPS()->getSpsNext().getUseGBi() == true) ? getWeightIdxBits(gbiIdx) : 0);
    
                  uiBits[2]           = uiBitsTemp;
    
                  if(iNumIter!=1)
                  {
                    //  Set motion
                    pu.mv    [eRefPicList] = cMvBi    [iRefList];
    
                    pu.mv[eRefPicList].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
    
                    pu.refIdx[eRefPicList] = iRefIdxBi[iRefList];
    
                    PelUnitBuf predBufTmp = m_tmpPredStorage[iRefList].getBuf( UnitAreaRelative(cu, pu) );
                    motionCompensation( pu, predBufTmp, eRefPicList );
                  }
                }
              } // for loop-iRefIdxTemp
    
              if ( !bChanged )
              {
    
                if ((uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) || enforceGBiPred)
    
                {
                  xCopyAMVPInfo(&aacAMVPInfo[0][iRefIdxBi[0]], &amvp[REF_PIC_LIST_0]);
                  xCheckBestMVP( REF_PIC_LIST_0, cMvBi[0], cMvPredBi[0][iRefIdxBi[0]], aaiMvpIdxBi[0][iRefIdxBi[0]], amvp[eRefPicList], uiBits[2], uiCostBi, pu.cu->imv);
                  if(!cs.slice->getMvdL1ZeroFlag())
                  {
                    xCopyAMVPInfo(&aacAMVPInfo[1][iRefIdxBi[1]], &amvp[REF_PIC_LIST_1]);
                    xCheckBestMVP( REF_PIC_LIST_1, cMvBi[1], cMvPredBi[1][iRefIdxBi[1]], aaiMvpIdxBi[1][iRefIdxBi[1]], amvp[eRefPicList], uiBits[2], uiCostBi, pu.cu->imv);
                  }
                }
                break;
              }
            } // for loop-iter
    
            cu.refIdxBi[0] = iRefIdxBi[0];
            cu.refIdxBi[1] = iRefIdxBi[1];
    
    
    #if JVET_M0444_SMVD
    
    #if JVET_M0246_AFFINE_AMVR
            if ( cs.slice->getBiDirPred() && trySmvd )
    #else
    
            if ( cs.slice->getBiDirPred() )
    
            {
              Distortion symCost;
              Mv cMvPredSym[2];
              int mvpIdxSym[2];
    
              int curRefList = REF_PIC_LIST_0;
              int tarRefList = 1 - curRefList;
              RefPicList eCurRefList = (curRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);
              int refIdxCur = cs.slice->getSymRefIdx( curRefList );
              int refIdxTar = cs.slice->getSymRefIdx( tarRefList );
    
              MvField cCurMvField, cTarMvField;
              Distortion costStart = std::numeric_limits<Distortion>::max();
              for ( int i = 0; i < aacAMVPInfo[curRefList][refIdxCur].numCand; i++ )
              {
                for ( int j = 0; j < aacAMVPInfo[tarRefList][refIdxTar].numCand; j++ )
                {
                  cCurMvField.setMvField( aacAMVPInfo[curRefList][refIdxCur].mvCand[i], refIdxCur );
                  cTarMvField.setMvField( aacAMVPInfo[tarRefList][refIdxTar].mvCand[j], refIdxTar );
                  Distortion cost = xGetSymmetricCost( pu, origBuf, eCurRefList, cCurMvField, cTarMvField, gbiIdx );
                  if ( cost < costStart )
                  {