diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp
index 50bfe7562ff26d0ea4f615d19152a4751a4ea459..537392c947b6289c6b1fd214b749ae86c5649743 100644
--- a/source/Lib/CommonLib/ContextModelling.cpp
+++ b/source/Lib/CommonLib/ContextModelling.cpp
@@ -363,271 +363,6 @@ unsigned DeriveCtx::CtxIBCFlag(const CodingUnit& cu)
   return ctxId;
 }
 
-#if JVET_AC0139_UNIFIED_MERGE
-void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx ) const
-#else
-void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx )
-#endif
-{
-  CHECK( candIdx >= numValidMergeCand, "Merge candidate does not exist" );
-  pu.regularMergeFlag        = !(pu.ciipFlag || pu.cu->geoFlag);
-  pu.mergeFlag               = true;
-  pu.mmvdMergeFlag = false;
-  pu.interDir                = interDirNeighbours[candIdx];
-  pu.cu->imv = (!pu.cu->geoFlag && useAltHpelIf[candIdx]) ? IMV_HPEL : 0;
-  pu.mergeIdx                = candIdx;
-  pu.mergeType               = CU::isIBC(*pu.cu) ? MergeType::IBC : MergeType::DEFAULT_N;
-
-  for (const auto l: { REF_PIC_LIST_0, REF_PIC_LIST_1 })
-  {
-    pu.mv[l]     = mvFieldNeighbours[candIdx][l].mv;
-    pu.mvd[l]    = Mv();
-    pu.refIdx[l] = mvFieldNeighbours[candIdx][l].refIdx;
-    pu.mvpIdx[l] = NOT_VALID;
-    pu.mvpNum[l] = NOT_VALID;
-  }
-#if GDR_ENABLED
-  CodingStructure &cs = *pu.cs;
-  const bool       isEncodeGdrClean =
-    cs.sps->getGDREnabledFlag() && cs.pcv->isEncoder
-    && ((cs.picture->gdrParam.inGdrInterval && cs.isClean(pu.Y().topRight(), ChannelType::LUMA))
-        || (cs.picture->gdrParam.verBoundary == -1));
-
-  if (isEncodeGdrClean)
-  {
-    for (const auto l: { REF_PIC_LIST_0, REF_PIC_LIST_1 })
-    {
-      Mv mv = pu.mv[l];
-
-      int refIdx = pu.refIdx[l];
-
-      pu.mvSolid[l] = mvSolid[candIdx][l];
-      pu.mvValid[l] = cs.isClean(pu.Y().topRight(), mv, l, refIdx);
-    }
-  }
-#endif
-
-  if (CU::isIBC(*pu.cu))
-  {
-    pu.bv = pu.mv[REF_PIC_LIST_0];
-    pu.bv.changePrecision(MvPrecision::INTERNAL, MvPrecision::ONE);   // used for only integer resolution
-    pu.cu->imv = pu.cu->imv == IMV_HPEL ? 0 : pu.cu->imv;
-  }
-  pu.cu->bcwIdx = (interDirNeighbours[candIdx] == 3) ? bcwIdx[candIdx] : BCW_DEFAULT;
-
-  PU::restrictBiPredMergeCandsOne(pu);
-  pu.mmvdEncOptMode = 0;
-}
-
-void MergeCtx::getMmvdDeltaMv(const Slice& slice, const MmvdIdx candIdx, Mv deltaMv[NUM_REF_PIC_LIST_01]) const
-{
-  const int mvdBaseIdx = candIdx.pos.baseIdx;
-  const int mvdStep = candIdx.pos.step;
-  const int mvdPosition = candIdx.pos.position;
-
-  int offset = 1 << (mvdStep + MV_FRACTIONAL_BITS_DIFF);
-  if (slice.getPicHeader()->getDisFracMMVD())
-  {
-    offset <<= 2;
-  }
-  const int refList0 = mmvdBaseMv[mvdBaseIdx][REF_PIC_LIST_0].refIdx;
-  const int refList1 = mmvdBaseMv[mvdBaseIdx][REF_PIC_LIST_1].refIdx;
-
-  const Mv dMvTable[4] = { Mv(offset,0), Mv(-offset,0), Mv(0, offset), Mv(0, -offset) };
-  if ((refList0 != -1) && (refList1 != -1))
-  {
-    const int poc0 = slice.getRefPOC(REF_PIC_LIST_0, refList0);
-    const int poc1 = slice.getRefPOC(REF_PIC_LIST_1, refList1);
-    const int currPoc = slice.getPOC();
-    deltaMv[0] = dMvTable[mvdPosition];
-
-    if ((poc0 - currPoc) == (poc1 - currPoc))
-    {
-      deltaMv[1] = deltaMv[0];
-    }
-    else if (abs(poc1 - currPoc) > abs(poc0 - currPoc))
-    {
-      const int scale = PU::getDistScaleFactor(currPoc, poc0, currPoc, poc1);
-      deltaMv[1] = deltaMv[0];
-      const bool isL0RefLongTerm = slice.getRefPic(REF_PIC_LIST_0, refList0)->longTerm;
-      const bool isL1RefLongTerm = slice.getRefPic(REF_PIC_LIST_1, refList1)->longTerm;
-      if (isL0RefLongTerm || isL1RefLongTerm)
-      {
-        if ((poc1 - currPoc)*(poc0 - currPoc) > 0)
-        {
-          deltaMv[0] = deltaMv[1];
-        }
-        else
-        {
-          deltaMv[0].set(-1 * deltaMv[1].getHor(), -1 * deltaMv[1].getVer());
-        }
-      }
-      else
-      {
-        deltaMv[0] = deltaMv[1].getScaledMv(scale);
-      }
-    }
-    else
-    {
-      const int scale = PU::getDistScaleFactor(currPoc, poc1, currPoc, poc0);
-      const bool isL0RefLongTerm = slice.getRefPic(REF_PIC_LIST_0, refList0)->longTerm;
-      const bool isL1RefLongTerm = slice.getRefPic(REF_PIC_LIST_1, refList1)->longTerm;
-      if (isL0RefLongTerm || isL1RefLongTerm)
-      {
-        if ((poc1 - currPoc)*(poc0 - currPoc) > 0)
-        {
-          deltaMv[1] = deltaMv[0];
-        }
-        else
-        {
-          deltaMv[1].set(-1 * deltaMv[0].getHor(), -1 * deltaMv[0].getVer());
-        }
-      }
-      else
-      {
-        deltaMv[1] = deltaMv[0].getScaledMv(scale);
-      }
-    }
-  }
-  else if (refList0 != -1)
-  {
-    deltaMv[0] = dMvTable[mvdPosition];
-  }
-  else if (refList1 != -1)
-  {
-    deltaMv[1] = dMvTable[mvdPosition];
-  }
-}
-
-void MergeCtx::setMmvdMergeCandiInfo(PredictionUnit &pu, const MmvdIdx candIdx)
-{
-  Mv tempMv[NUM_REF_PIC_LIST_01];
-
-#if GDR_ENABLED
-  const CodingStructure &cs = *pu.cs;
-  const bool             isEncodeGdrClean =
-    cs.sps->getGDREnabledFlag() && cs.pcv->isEncoder
-    && ((cs.picture->gdrParam.inGdrInterval && cs.isClean(pu.Y().topRight(), ChannelType::LUMA))
-        || (cs.picture->gdrParam.verBoundary == -1));
-#endif
-
-  getMmvdDeltaMv(*pu.cs->slice, candIdx, tempMv);
-  const int mvdBaseIdx  = candIdx.pos.baseIdx;
-
-  const int refList0 = mmvdBaseMv[mvdBaseIdx][0].refIdx;
-  const int refList1 = mmvdBaseMv[mvdBaseIdx][1].refIdx;
-
-  if ((refList0 != -1) && (refList1 != -1))
-  {
-    pu.interDir = 3;
-    pu.mv[REF_PIC_LIST_0]     = mmvdBaseMv[mvdBaseIdx][0].mv + tempMv[0];
-    pu.refIdx[REF_PIC_LIST_0] = refList0;
-    pu.mv[REF_PIC_LIST_1]     = mmvdBaseMv[mvdBaseIdx][1].mv + tempMv[1];
-    pu.refIdx[REF_PIC_LIST_1] = refList1;
-#if GDR_ENABLED
-    if (isEncodeGdrClean)
-    {
-      Mv mv0 = pu.mv[REF_PIC_LIST_0];
-      Mv mv1 = pu.mv[REF_PIC_LIST_1];
-
-      int refIdx0 = pu.refIdx[REF_PIC_LIST_0];
-      int refIdx1 = pu.refIdx[REF_PIC_LIST_1];
-
-      mmvdValid[mvdBaseIdx][0] = cs.isClean(pu.Y().topRight(), mv0, REF_PIC_LIST_0, refIdx0);
-      mmvdValid[mvdBaseIdx][1] = cs.isClean(pu.Y().topRight(), mv1, REF_PIC_LIST_1, refIdx1);
-
-      pu.mvSolid[REF_PIC_LIST_0] = mmvdSolid[mvdBaseIdx][0];
-      pu.mvSolid[REF_PIC_LIST_1] = mmvdSolid[mvdBaseIdx][1];
-
-      pu.mvValid[REF_PIC_LIST_0] = mmvdValid[mvdBaseIdx][0];
-      pu.mvValid[REF_PIC_LIST_1] = mmvdValid[mvdBaseIdx][1];
-    }
-#endif
-  }
-  else if (refList0 != -1)
-  {
-    pu.interDir = 1;
-    pu.mv[REF_PIC_LIST_0]     = mmvdBaseMv[mvdBaseIdx][0].mv + tempMv[0];
-    pu.refIdx[REF_PIC_LIST_0] = refList0;
-    pu.mv[REF_PIC_LIST_1] = Mv(0, 0);
-    pu.refIdx[REF_PIC_LIST_1] = -1;
-
-#if GDR_ENABLED
-    if (isEncodeGdrClean)
-    {
-      Mv mv0 = pu.mv[REF_PIC_LIST_0];
-      //Mv mv1 = pu.mv[REF_PIC_LIST_1];
-
-      int refIdx0 = pu.refIdx[REF_PIC_LIST_0];
-      //int refIdx1 = pu.refIdx[REF_PIC_LIST_1];
-
-      pu.mvSolid[REF_PIC_LIST_0] = mmvdSolid[mvdBaseIdx][0];
-      pu.mvSolid[REF_PIC_LIST_1] = true;
-
-      mmvdValid[mvdBaseIdx][0] = cs.isClean(pu.Y().topRight(), mv0, REF_PIC_LIST_0, refIdx0);
-      mmvdValid[mvdBaseIdx][1] = true;
-
-      pu.mvValid[REF_PIC_LIST_0] = mmvdValid[mvdBaseIdx][0];
-      pu.mvValid[REF_PIC_LIST_1] = true;
-    }
-#endif
-  }
-  else if (refList1 != -1)
-  {
-    pu.interDir = 2;
-    pu.mv[REF_PIC_LIST_0] = Mv(0, 0);
-    pu.refIdx[REF_PIC_LIST_0] = -1;
-    pu.mv[REF_PIC_LIST_1]     = mmvdBaseMv[mvdBaseIdx][1].mv + tempMv[1];
-    pu.refIdx[REF_PIC_LIST_1] = refList1;
-#if GDR_ENABLED
-    if (isEncodeGdrClean)
-    {
-      // Mv mv0 = pu.mv[REF_PIC_LIST_0];
-      Mv mv1 = pu.mv[REF_PIC_LIST_1];
-
-      // int refIdx0 = pu.refIdx[REF_PIC_LIST_0];
-      int refIdx1 = pu.refIdx[REF_PIC_LIST_1];
-
-      mmvdValid[mvdBaseIdx][0] = true;
-      mmvdValid[mvdBaseIdx][1] = cs.isClean(pu.Y().topRight(), mv1, REF_PIC_LIST_1, refIdx1);
-
-      pu.mvSolid[REF_PIC_LIST_0] = true;
-      pu.mvSolid[REF_PIC_LIST_1] = mmvdSolid[mvdBaseIdx][1];
-
-      pu.mvValid[REF_PIC_LIST_0] = true;
-      pu.mvValid[REF_PIC_LIST_1] = mmvdValid[mvdBaseIdx][1];
-    }
-#endif
-  }
-
-  pu.mmvdMergeFlag    = true;
-  pu.mmvdMergeIdx     = candIdx;
-  pu.mergeFlag        = true;
-  pu.regularMergeFlag = true;
-  pu.mergeIdx         = candIdx.val;
-  pu.mergeType        = MergeType::DEFAULT_N;
-
-  pu.mvd[REF_PIC_LIST_0] = Mv();
-  pu.mvd[REF_PIC_LIST_1] = Mv();
-  pu.mvpIdx[REF_PIC_LIST_0] = NOT_VALID;
-  pu.mvpIdx[REF_PIC_LIST_1] = NOT_VALID;
-  pu.mvpNum[REF_PIC_LIST_0] = NOT_VALID;
-  pu.mvpNum[REF_PIC_LIST_1] = NOT_VALID;
-  pu.cu->imv                = mmvdUseAltHpelIf[mvdBaseIdx] ? IMV_HPEL : 0;
-
-  pu.cu->bcwIdx = (interDirNeighbours[mvdBaseIdx] == 3) ? bcwIdx[mvdBaseIdx] : BCW_DEFAULT;
-
-  for (int refList = 0; refList < 2; refList++)
-  {
-    if (pu.refIdx[refList] >= 0)
-    {
-      pu.mv[refList].clipToStorageBitDepth();
-    }
-  }
-
-  PU::restrictBiPredMergeCandsOne(pu);
-}
-
 unsigned DeriveCtx::CtxMipFlag( const CodingUnit& cu )
 {
   const CodingStructure *cs = cu.cs;
@@ -657,300 +392,3 @@ unsigned DeriveCtx::CtxPltCopyFlag( const unsigned prevRunType, const unsigned d
   }
 }
 
-#if JVET_AC0139_UNIFIED_MERGE
-MergeItem::MergeItem()
-{
-
-}
-MergeItem::~MergeItem()
-{
-
-}
-
-void MergeItem::create(ChromaFormat chromaFormat, const Area& area)
-{
-  if (m_pelStorage.bufs.empty())
-  {
-    m_pelStorage.create(chromaFormat, area);
-    m_mvStorage.resize(area.area() >> (MIN_CU_LOG2 << 1));
-  }
-
-  // reset data
-  cost = MAX_DOUBLE;
-  mergeIdx = 0;
-  bcwIdx = 0;
-  interDir = 0;
-  useAltHpelIf = false;
-  affineType = AffineModel::_4_PARAMS;
-  mergeItemType = MergeItemType::NUM;
-
-  noBdofRefine = false;
-  noResidual = false;
-
-  lumaPredReady = false;
-  chromaPredReady = false;
-}
-
-void MergeItem::importMergeInfo(const MergeCtx& mergeCtx, int _mergeIdx, MergeItemType _mergeItemType, PredictionUnit& pu)
-{
-  mergeIdx = _mergeIdx;
-  mergeItemType = _mergeItemType;
-
-  if (mergeItemType != MergeItemType::GPM)
-  {
-    mvField[0][REF_PIC_LIST_0] = mergeCtx.mvFieldNeighbours[mergeIdx][REF_PIC_LIST_0];
-    mvField[0][REF_PIC_LIST_1] = mergeCtx.mvFieldNeighbours[mergeIdx][REF_PIC_LIST_1];
-    interDir = mergeCtx.interDirNeighbours[mergeIdx];
-    bcwIdx = mergeCtx.bcwIdx[mergeIdx];
-    useAltHpelIf = mergeCtx.useAltHpelIf[mergeIdx];
-  }
-
-  switch (_mergeItemType)
-  {
-  case MergeItemType::REGULAR:
-    break;
-
-  case MergeItemType::CIIP:
-    break;
-
-  case MergeItemType::MMVD:
-  {
-    MmvdIdx candIdx;
-    candIdx.val = mergeIdx;
-    const int mmvdBaseIdx = candIdx.pos.baseIdx;
-    mvField[0][REF_PIC_LIST_0] = mergeCtx.mmvdBaseMv[mmvdBaseIdx][REF_PIC_LIST_0];
-    mvField[0][REF_PIC_LIST_1] = mergeCtx.mmvdBaseMv[mmvdBaseIdx][REF_PIC_LIST_1];
-    Mv tempMv[NUM_REF_PIC_LIST_01];
-    mergeCtx.getMmvdDeltaMv(*pu.cs->slice, candIdx, tempMv);
-    mvField[0][REF_PIC_LIST_0].mv += tempMv[REF_PIC_LIST_0];
-    mvField[0][REF_PIC_LIST_1].mv += tempMv[REF_PIC_LIST_1];
-    interDir = mergeCtx.interDirNeighbours[mmvdBaseIdx];
-    bcwIdx = mergeCtx.bcwIdx[mmvdBaseIdx];
-    useAltHpelIf = mergeCtx.useAltHpelIf[mmvdBaseIdx];
-    break;
-  }
-  case MergeItemType::GPM:
-    mvField[0][REF_PIC_LIST_0].setMvField(Mv(0, 0), -1);
-    mvField[0][REF_PIC_LIST_1].setMvField(Mv(0, 0), -1);
-    bcwIdx = BCW_DEFAULT;
-    useAltHpelIf = false;
-    MergeItem::updateGpmIdx(mergeIdx, pu.geoSplitDir, pu.geoMergeIdx);
-    pu.mergeFlag = true;
-    pu.cu->affine = false;
-    pu.cu->geoFlag = true;
-    pu.mergeType = MergeType::DEFAULT_N;
-    PU::spanMotionInfo(pu, getMvBuf(pu));
-    PU::spanGeoMotionInfo(pu, mergeCtx, pu.geoSplitDir, pu.geoMergeIdx);
-    getMvBuf(pu).copyFrom(pu.getMotionBuf());
-    break;
-
-  case MergeItemType::IBC:
-  default:
-    THROW("Wrong merge item type");
-  }
-}
-
-void MergeItem::importMergeInfo(const AffineMergeCtx& mergeCtx, int _mergeIdx, MergeItemType _mergeItemType, const UnitArea& unitArea)
-{
-  mergeIdx = _mergeIdx;
-  mergeItemType = _mergeItemType;
-
-  affineType = mergeCtx.affineType[mergeIdx];
-  interDir = mergeCtx.interDirNeighbours[mergeIdx];
-  bcwIdx = mergeCtx.bcwIdx[mergeIdx];
-  useAltHpelIf = false;
-
-  switch (_mergeItemType)
-  {
-  case MergeItemType::SBTMVP:
-    mvField = mergeCtx.mvFieldNeighbours[mergeIdx];
-    getMvBuf(unitArea).copyFrom(mergeCtx.mrgCtx->subPuMvpMiBuf);
-    break;
-
-  case MergeItemType::AFFINE:
-    mvField = mergeCtx.mvFieldNeighbours[mergeIdx];
-    break;
-
-  default:
-    THROW("Wrong merge item type");
-  }
-}
-
-bool MergeItem::exportMergeInfo(PredictionUnit& pu, bool forceNoResidual)
-{
-  pu.mergeFlag = true;
-  pu.regularMergeFlag = false;
-  pu.mmvdMergeFlag = false;
-  pu.interDir = interDir;
-  pu.mergeIdx = mergeIdx;
-  pu.mergeType = MergeType::DEFAULT_N;
-  pu.mv[REF_PIC_LIST_0] = mvField[0][REF_PIC_LIST_0].mv;
-  pu.mv[REF_PIC_LIST_1] = mvField[0][REF_PIC_LIST_1].mv;
-  pu.refIdx[REF_PIC_LIST_0] = mvField[0][REF_PIC_LIST_0].refIdx;
-  pu.refIdx[REF_PIC_LIST_1] = mvField[0][REF_PIC_LIST_1].refIdx;
-  pu.mvd[REF_PIC_LIST_0] = Mv();
-  pu.mvd[REF_PIC_LIST_1] = Mv();
-  pu.mvpIdx[REF_PIC_LIST_0] = NOT_VALID;
-  pu.mvpIdx[REF_PIC_LIST_1] = NOT_VALID;
-  pu.mvpNum[REF_PIC_LIST_0] = NOT_VALID;
-  pu.mvpNum[REF_PIC_LIST_1] = NOT_VALID;
-  pu.cu->bcwIdx = (interDir == 3) ? bcwIdx : BCW_DEFAULT;
-  pu.mmvdEncOptMode = 0;
-  pu.cu->mmvdSkip = false;
-  pu.cu->affine = false;
-  pu.cu->affineType = AffineModel::_4_PARAMS;
-  pu.cu->geoFlag = false;
-  pu.cu->mtsFlag = false;
-  pu.ciipFlag = false;
-  pu.cu->imv = (!pu.cu->geoFlag && useAltHpelIf) ? IMV_HPEL : 0;
-
-  const bool resetCiip2Regular = mergeItemType == MergeItemType::CIIP && forceNoResidual;
-  MergeItemType updatedType = resetCiip2Regular ? MergeItemType::REGULAR : mergeItemType;
-  switch (updatedType)
-  {
-  case MergeItemType::REGULAR:
-    pu.regularMergeFlag = true;
-    PU::restrictBiPredMergeCandsOne(pu);
-    break;
-
-  case MergeItemType::CIIP:
-    CHECK(forceNoResidual, "Cannot force no residuals for CIIP");
-    pu.ciipFlag = true;
-    pu.intraDir[ChannelType::LUMA] = PLANAR_IDX;
-    pu.intraDir[ChannelType::CHROMA] = DM_CHROMA_IDX;
-    break;
-
-  case MergeItemType::MMVD:
-    pu.mmvdMergeFlag = true;
-    pu.mmvdMergeIdx.val = mergeIdx;
-    pu.regularMergeFlag = true;
-    if (forceNoResidual)
-    {
-      pu.cu->mmvdSkip = true;
-    }
-    PU::restrictBiPredMergeCandsOne(pu);
-    break;
-
-  case MergeItemType::SBTMVP:
-    pu.cu->affine = true;
-    pu.mergeType = MergeType::SUBPU_ATMVP;
-    break;
-
-  case MergeItemType::AFFINE:
-    pu.cu->affine = true;
-    pu.cu->affineType = affineType;
-    PU::setAllAffineMvField(pu, mvField, REF_PIC_LIST_0);
-    PU::setAllAffineMvField(pu, mvField, REF_PIC_LIST_1);
-    break;
-
-  case MergeItemType::GPM:
-    pu.mergeIdx = -1;
-    pu.cu->geoFlag = true;
-    pu.cu->bcwIdx = BCW_DEFAULT;
-    MergeItem::updateGpmIdx(mergeIdx, pu.geoSplitDir, pu.geoMergeIdx);
-    pu.cu->imv = 0;
-    break;
-
-  case MergeItemType::IBC:
-  default:
-    THROW("Wrong merge item type");
-  }
-
-  if (mergeItemType == MergeItemType::GPM)
-  {
-    pu.getMotionBuf().copyFrom(getMvBuf(pu));
-  }
-  else
-  {
-    PU::spanMotionInfo(pu, getMvBuf(pu));
-  }
-
-#if GDR_ENABLED
-  CodingStructure &cs = *pu.cs;
-  const bool isEncodeGdrClean = cs.sps->getGDREnabledFlag() && cs.pcv->isEncoder 
-    && ((cs.picture->gdrParam.inGdrInterval && cs.isClean(pu.Y().topRight(), ChannelType::LUMA)) 
-    || (cs.picture->gdrParam.verBoundary == -1));
-  if (isEncodeGdrClean)
-  {
-    Mv mv0 = pu.mv[REF_PIC_LIST_0];
-    Mv mv1 = pu.mv[REF_PIC_LIST_1];
-
-    int refIdx0 = pu.refIdx[REF_PIC_LIST_0];
-    int refIdx1 = pu.refIdx[REF_PIC_LIST_1];
-
-    pu.mvSolid[REF_PIC_LIST_0] = mvSolid[0];
-    pu.mvSolid[REF_PIC_LIST_1] = mvSolid[1];
-    pu.mvValid[REF_PIC_LIST_0] = cs.isClean(pu.Y().topRight(), mv0, REF_PIC_LIST_0, refIdx0);
-    pu.mvValid[REF_PIC_LIST_1] = cs.isClean(pu.Y().topRight(), mv1, REF_PIC_LIST_1, refIdx1);
-  }
-#endif
-
-  return resetCiip2Regular;
-}
-
-MergeItemList::MergeItemList()
-{
-
-}
-
-MergeItemList::~MergeItemList()
-{
-}
-
-void MergeItemList::init(size_t maxSize, ChromaFormat chromaFormat, int ctuWidth, int ctuHeight)
-{
-  m_list.reserve(maxSize + 1); // to avoid reallocation when inserting a new item
-  m_chromaFormat = chromaFormat;
-  m_ctuArea.x = 0;
-  m_ctuArea.y = 0;
-  m_ctuArea.width = ctuWidth;
-  m_ctuArea.height = ctuHeight;
-}
-
-MergeItem* MergeItemList::allocateNewMergeItem()
-{
-  MergeItem* p = m_mergeItemPool.get();
-  p->create(m_chromaFormat, m_ctuArea);
-
-  return p;
-}
-
-void MergeItemList::insertMergeItemToList(MergeItem* p)
-{
-  if (m_list.empty())
-  {
-    m_list.push_back(p);
-  }
-  else if (m_list.size() == m_maxTrackingNum && p->cost >= m_list.back()->cost)
-  {
-    m_mergeItemPool.giveBack(p);
-  }
-  else
-  {
-    if (m_list.size() == m_maxTrackingNum)
-    {
-      m_mergeItemPool.giveBack(m_list.back());
-      m_list.pop_back();
-    }
-    auto it = std::find_if(m_list.begin(), m_list.end(), [&p](const MergeItem *mi) { return p->cost < mi->cost; });
-    m_list.insert(it, p);
-  }
-}
-
-MergeItem* MergeItemList::getMergeItemInList(size_t index)
-{
-  return index < m_maxTrackingNum ? m_list[index] : nullptr;
-}
-
-void MergeItemList::resetList(size_t maxTrackingNum)
-{
-  for (auto p : m_list)
-  {
-    m_mergeItemPool.giveBack(p);
-  }
-  m_list.clear();
-  m_list.reserve(maxTrackingNum);
-  m_maxTrackingNum = maxTrackingNum;
-}
-
-#endif
\ No newline at end of file
diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h
index aba6f57080a6e13703306107f5ec1b8ac9030c7c..919aa548a9788ff975c53e3c1223ac742527004d 100644
--- a/source/Lib/CommonLib/ContextModelling.h
+++ b/source/Lib/CommonLib/ContextModelling.h
@@ -584,177 +584,6 @@ public:
   bool      mtsLastScanPos;
 };
 
-class MergeCtx
-{
-public:
-  MergeCtx() : numValidMergeCand(0), hasMergedCandList(false) {}
-  ~MergeCtx() {}
-public:
-  MvField mvFieldNeighbours[MRG_MAX_NUM_CANDS][2];
-#if GDR_ENABLED
-  // note : check if source of mv and mv itself is valid
-  bool     mvSolid[MRG_MAX_NUM_CANDS][2];
-  bool     mvValid[MRG_MAX_NUM_CANDS][2];
-  Position mvPos[MRG_MAX_NUM_CANDS][2];
-  MvpType  mvType[MRG_MAX_NUM_CANDS][2];
-#endif
-  uint8_t       bcwIdx[MRG_MAX_NUM_CANDS];
-  unsigned char interDirNeighbours[ MRG_MAX_NUM_CANDS      ];
-  int           numValidMergeCand;
-  bool          hasMergedCandList;
-
-  MotionBuf     subPuMvpMiBuf;
-  MvField       mmvdBaseMv[MmvdIdx::BASE_MV_NUM][2];
-#if GDR_ENABLED
-  bool mmvdSolid[MmvdIdx::BASE_MV_NUM][2];
-  bool mmvdValid[MmvdIdx::BASE_MV_NUM][2];
-#endif
-  void          setMmvdMergeCandiInfo(PredictionUnit &pu, MmvdIdx candIdx);
-  void          getMmvdDeltaMv(const Slice& slice, const MmvdIdx candIdx, Mv deltaMv[NUM_REF_PIC_LIST_01]) const;
-  bool          mmvdUseAltHpelIf[MmvdIdx::BASE_MV_NUM];
-  bool          useAltHpelIf      [ MRG_MAX_NUM_CANDS ];
-#if JVET_AC0139_UNIFIED_MERGE
-  void setMergeInfo( PredictionUnit& pu, int candIdx ) const;
-#else
-  void setMergeInfo( PredictionUnit& pu, int candIdx );
-#endif
-};
-
-class AffineMergeCtx
-{
-public:
-  AffineMergeCtx() : numValidMergeCand(0)
-  {
-    for (int i = 0; i < AFFINE_MRG_MAX_NUM_CANDS; i++)
-    {
-      affineType[i] = AffineModel::_4_PARAMS;
-    }
-  }
-  ~AffineMergeCtx() {}
-public:
-  std::array<MvField[2], AFFINE_MAX_NUM_CP> mvFieldNeighbours[AFFINE_MRG_MAX_NUM_CANDS];
-#if GDR_ENABLED
-  std::array<bool[2], AFFINE_MAX_NUM_CP> mvSolid[AFFINE_MRG_MAX_NUM_CANDS];
-  std::array<bool[2], AFFINE_MAX_NUM_CP> mvValid[AFFINE_MRG_MAX_NUM_CANDS];
-
-  bool isSolid(const int idx, const int l)
-  {
-    bool solid = true;
-    for (auto &c: mvSolid[idx])
-    {
-      solid &= c[l];
-    }
-    return solid;
-  }
-
-  bool isValid(const int idx, const int l)
-  {
-    bool valid = true;
-    for (auto &c: mvValid[idx])
-    {
-      valid &= c[l];
-    }
-    return valid;
-  }
-#endif
-  unsigned char interDirNeighbours[AFFINE_MRG_MAX_NUM_CANDS];
-  AffineModel   affineType[AFFINE_MRG_MAX_NUM_CANDS];
-  uint8_t       bcwIdx[AFFINE_MRG_MAX_NUM_CANDS];
-  int           numValidMergeCand;
-  int           maxNumMergeCand;
-
-  MergeCtx     *mrgCtx;
-  MergeType     mergeType[AFFINE_MRG_MAX_NUM_CANDS];
-};
-
-#if JVET_AC0139_UNIFIED_MERGE
-class MergeItem
-{
-private:
-  PelStorage m_pelStorage;
-  std::vector<MotionInfo> m_mvStorage;
-
-public:
-  enum class MergeItemType
-  {
-    REGULAR,
-    SBTMVP,
-    AFFINE,
-    MMVD,
-    CIIP,
-    GPM,
-    IBC,
-    NUM,
-  };
-
-  double        cost;
-  std::array<MvField[2], AFFINE_MAX_NUM_CP> mvField;
-  int           mergeIdx;
-  uint8_t       bcwIdx;
-  uint8_t       interDir;
-  bool          useAltHpelIf;
-  AffineModel   affineType;
-
-  bool          noResidual;
-  bool          noBdofRefine;
-
-  bool          lumaPredReady;
-  bool          chromaPredReady;
-
-  MergeItemType mergeItemType;
-  MotionBuf     mvBuf;
-
-#if GDR_ENABLED
-  bool          mvSolid[2];
-  bool          mvValid[2];
-#endif
-
-  MergeItem();
-  ~MergeItem();
-
-  void          create(ChromaFormat chromaFormat, const Area& area);
-  void          importMergeInfo(const MergeCtx& mergeCtx, int _mergeIdx, MergeItemType _mergeItemType, PredictionUnit& pu);
-  void          importMergeInfo(const AffineMergeCtx& mergeCtx, int _mergeIdx, MergeItemType _mergeItemType, const UnitArea& unitArea);
-  bool          exportMergeInfo(PredictionUnit& pu, bool forceNoResidual);
-  PelUnitBuf    getPredBuf(const UnitArea& unitArea) { return m_pelStorage.getBuf(unitArea); }
-  MotionBuf     getMvBuf(const UnitArea& unitArea) { return MotionBuf(m_mvStorage.data(), g_miScaling.scale(unitArea.lumaSize())); }
-
-  static int getGpmUnfiedIndex(int splitDir, const MergeIdxPair& geoMergeIdx)
-  {
-    return (splitDir << 8) | (geoMergeIdx[0] << 4) | geoMergeIdx[1];
-  }
-  static void updateGpmIdx(int mergeIdx, uint8_t& splitDir, MergeIdxPair& geoMergeIdx)
-  {
-    splitDir = (mergeIdx >> 8) & 0xFF;
-    geoMergeIdx[0] = (mergeIdx >> 4) & 0xF;
-    geoMergeIdx[1] = mergeIdx & 0xF;
-  }
-};
-
-class MergeItemList
-{
-private:
-  Pool<MergeItem> m_mergeItemPool;
-  std::vector<MergeItem *> m_list;
-  size_t m_maxTrackingNum = 0;
-  ChromaFormat  m_chromaFormat;
-  Area m_ctuArea;
-
-public:
-  MergeItemList();
-  ~MergeItemList();
-
-  void          init(size_t maxSize, ChromaFormat chromaFormat, int ctuWidth, int ctuHeight);
-  MergeItem*    allocateNewMergeItem();
-  void          insertMergeItemToList(MergeItem* p);
-  void          resetList(size_t maxTrackingNum);
-  MergeItem*    getMergeItemInList(size_t index);
-  size_t        size() { return m_list.size(); }
-
-};
-
-#endif
-
 namespace DeriveCtx
 {
 void     CtxSplit     ( const CodingStructure& cs, Partitioner& partitioner, unsigned& ctxSpl, unsigned& ctxQt, unsigned& ctxHv, unsigned& ctxHorBt, unsigned& ctxVerBt, bool* canSplit = nullptr );
diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp
index 895ac31133ec7e65816c96bdb03a3005ab046e6e..237c79440953ceed692d47996f73f7fdee1b01fd 100644
--- a/source/Lib/CommonLib/InterPrediction.cpp
+++ b/source/Lib/CommonLib/InterPrediction.cpp
@@ -2255,3 +2255,268 @@ bool InterPrediction::xPredInterBlkRPR(const ScalingRatio scalingRatio, const PP
 
   return scaled;
 }
+
+#if JVET_AC0139_UNIFIED_MERGE
+void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx ) const
+#else
+void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx )
+#endif
+{
+  CHECK( candIdx >= numValidMergeCand, "Merge candidate does not exist" );
+  pu.regularMergeFlag        = !(pu.ciipFlag || pu.cu->geoFlag);
+  pu.mergeFlag               = true;
+  pu.mmvdMergeFlag = false;
+  pu.interDir                = interDirNeighbours[candIdx];
+  pu.cu->imv = (!pu.cu->geoFlag && useAltHpelIf[candIdx]) ? IMV_HPEL : 0;
+  pu.mergeIdx                = candIdx;
+  pu.mergeType               = CU::isIBC(*pu.cu) ? MergeType::IBC : MergeType::DEFAULT_N;
+
+  for (const auto l: { REF_PIC_LIST_0, REF_PIC_LIST_1 })
+  {
+    pu.mv[l]     = mvFieldNeighbours[candIdx][l].mv;
+    pu.mvd[l]    = Mv();
+    pu.refIdx[l] = mvFieldNeighbours[candIdx][l].refIdx;
+    pu.mvpIdx[l] = NOT_VALID;
+    pu.mvpNum[l] = NOT_VALID;
+  }
+#if GDR_ENABLED
+  CodingStructure &cs = *pu.cs;
+  const bool       isEncodeGdrClean =
+    cs.sps->getGDREnabledFlag() && cs.pcv->isEncoder
+    && ((cs.picture->gdrParam.inGdrInterval && cs.isClean(pu.Y().topRight(), ChannelType::LUMA))
+        || (cs.picture->gdrParam.verBoundary == -1));
+
+  if (isEncodeGdrClean)
+  {
+    for (const auto l: { REF_PIC_LIST_0, REF_PIC_LIST_1 })
+    {
+      Mv mv = pu.mv[l];
+
+      int refIdx = pu.refIdx[l];
+
+      pu.mvSolid[l] = mvSolid[candIdx][l];
+      pu.mvValid[l] = cs.isClean(pu.Y().topRight(), mv, l, refIdx);
+    }
+  }
+#endif
+
+  if (CU::isIBC(*pu.cu))
+  {
+    pu.bv = pu.mv[REF_PIC_LIST_0];
+    pu.bv.changePrecision(MvPrecision::INTERNAL, MvPrecision::ONE);   // used for only integer resolution
+    pu.cu->imv = pu.cu->imv == IMV_HPEL ? 0 : pu.cu->imv;
+  }
+  pu.cu->bcwIdx = (interDirNeighbours[candIdx] == 3) ? bcwIdx[candIdx] : BCW_DEFAULT;
+
+  PU::restrictBiPredMergeCandsOne(pu);
+  pu.mmvdEncOptMode = 0;
+}
+
+void MergeCtx::getMmvdDeltaMv(const Slice& slice, const MmvdIdx candIdx, Mv deltaMv[NUM_REF_PIC_LIST_01]) const
+{
+  const int mvdBaseIdx = candIdx.pos.baseIdx;
+  const int mvdStep = candIdx.pos.step;
+  const int mvdPosition = candIdx.pos.position;
+
+  int offset = 1 << (mvdStep + MV_FRACTIONAL_BITS_DIFF);
+  if (slice.getPicHeader()->getDisFracMMVD())
+  {
+    offset <<= 2;
+  }
+  const int refList0 = mmvdBaseMv[mvdBaseIdx][REF_PIC_LIST_0].refIdx;
+  const int refList1 = mmvdBaseMv[mvdBaseIdx][REF_PIC_LIST_1].refIdx;
+
+  const Mv dMvTable[4] = { Mv(offset,0), Mv(-offset,0), Mv(0, offset), Mv(0, -offset) };
+  if ((refList0 != -1) && (refList1 != -1))
+  {
+    const int poc0 = slice.getRefPOC(REF_PIC_LIST_0, refList0);
+    const int poc1 = slice.getRefPOC(REF_PIC_LIST_1, refList1);
+    const int currPoc = slice.getPOC();
+    deltaMv[0] = dMvTable[mvdPosition];
+
+    if ((poc0 - currPoc) == (poc1 - currPoc))
+    {
+      deltaMv[1] = deltaMv[0];
+    }
+    else if (abs(poc1 - currPoc) > abs(poc0 - currPoc))
+    {
+      const int scale = PU::getDistScaleFactor(currPoc, poc0, currPoc, poc1);
+      deltaMv[1] = deltaMv[0];
+      const bool isL0RefLongTerm = slice.getRefPic(REF_PIC_LIST_0, refList0)->longTerm;
+      const bool isL1RefLongTerm = slice.getRefPic(REF_PIC_LIST_1, refList1)->longTerm;
+      if (isL0RefLongTerm || isL1RefLongTerm)
+      {
+        if ((poc1 - currPoc)*(poc0 - currPoc) > 0)
+        {
+          deltaMv[0] = deltaMv[1];
+        }
+        else
+        {
+          deltaMv[0].set(-1 * deltaMv[1].getHor(), -1 * deltaMv[1].getVer());
+        }
+      }
+      else
+      {
+        deltaMv[0] = deltaMv[1].getScaledMv(scale);
+      }
+    }
+    else
+    {
+      const int scale = PU::getDistScaleFactor(currPoc, poc1, currPoc, poc0);
+      const bool isL0RefLongTerm = slice.getRefPic(REF_PIC_LIST_0, refList0)->longTerm;
+      const bool isL1RefLongTerm = slice.getRefPic(REF_PIC_LIST_1, refList1)->longTerm;
+      if (isL0RefLongTerm || isL1RefLongTerm)
+      {
+        if ((poc1 - currPoc)*(poc0 - currPoc) > 0)
+        {
+          deltaMv[1] = deltaMv[0];
+        }
+        else
+        {
+          deltaMv[1].set(-1 * deltaMv[0].getHor(), -1 * deltaMv[0].getVer());
+        }
+      }
+      else
+      {
+        deltaMv[1] = deltaMv[0].getScaledMv(scale);
+      }
+    }
+  }
+  else if (refList0 != -1)
+  {
+    deltaMv[0] = dMvTable[mvdPosition];
+  }
+  else if (refList1 != -1)
+  {
+    deltaMv[1] = dMvTable[mvdPosition];
+  }
+}
+
+void MergeCtx::setMmvdMergeCandiInfo(PredictionUnit &pu, const MmvdIdx candIdx)
+{
+  Mv tempMv[NUM_REF_PIC_LIST_01];
+
+#if GDR_ENABLED
+  const CodingStructure &cs = *pu.cs;
+  const bool             isEncodeGdrClean =
+    cs.sps->getGDREnabledFlag() && cs.pcv->isEncoder
+    && ((cs.picture->gdrParam.inGdrInterval && cs.isClean(pu.Y().topRight(), ChannelType::LUMA))
+        || (cs.picture->gdrParam.verBoundary == -1));
+#endif
+
+  getMmvdDeltaMv(*pu.cs->slice, candIdx, tempMv);
+  const int mvdBaseIdx  = candIdx.pos.baseIdx;
+
+  const int refList0 = mmvdBaseMv[mvdBaseIdx][0].refIdx;
+  const int refList1 = mmvdBaseMv[mvdBaseIdx][1].refIdx;
+
+  if ((refList0 != -1) && (refList1 != -1))
+  {
+    pu.interDir = 3;
+    pu.mv[REF_PIC_LIST_0]     = mmvdBaseMv[mvdBaseIdx][0].mv + tempMv[0];
+    pu.refIdx[REF_PIC_LIST_0] = refList0;
+    pu.mv[REF_PIC_LIST_1]     = mmvdBaseMv[mvdBaseIdx][1].mv + tempMv[1];
+    pu.refIdx[REF_PIC_LIST_1] = refList1;
+#if GDR_ENABLED
+    if (isEncodeGdrClean)
+    {
+      Mv mv0 = pu.mv[REF_PIC_LIST_0];
+      Mv mv1 = pu.mv[REF_PIC_LIST_1];
+
+      int refIdx0 = pu.refIdx[REF_PIC_LIST_0];
+      int refIdx1 = pu.refIdx[REF_PIC_LIST_1];
+
+      mmvdValid[mvdBaseIdx][0] = cs.isClean(pu.Y().topRight(), mv0, REF_PIC_LIST_0, refIdx0);
+      mmvdValid[mvdBaseIdx][1] = cs.isClean(pu.Y().topRight(), mv1, REF_PIC_LIST_1, refIdx1);
+
+      pu.mvSolid[REF_PIC_LIST_0] = mmvdSolid[mvdBaseIdx][0];
+      pu.mvSolid[REF_PIC_LIST_1] = mmvdSolid[mvdBaseIdx][1];
+
+      pu.mvValid[REF_PIC_LIST_0] = mmvdValid[mvdBaseIdx][0];
+      pu.mvValid[REF_PIC_LIST_1] = mmvdValid[mvdBaseIdx][1];
+    }
+#endif
+  }
+  else if (refList0 != -1)
+  {
+    pu.interDir = 1;
+    pu.mv[REF_PIC_LIST_0]     = mmvdBaseMv[mvdBaseIdx][0].mv + tempMv[0];
+    pu.refIdx[REF_PIC_LIST_0] = refList0;
+    pu.mv[REF_PIC_LIST_1] = Mv(0, 0);
+    pu.refIdx[REF_PIC_LIST_1] = -1;
+
+#if GDR_ENABLED
+    if (isEncodeGdrClean)
+    {
+      Mv mv0 = pu.mv[REF_PIC_LIST_0];
+      //Mv mv1 = pu.mv[REF_PIC_LIST_1];
+
+      int refIdx0 = pu.refIdx[REF_PIC_LIST_0];
+      //int refIdx1 = pu.refIdx[REF_PIC_LIST_1];
+
+      pu.mvSolid[REF_PIC_LIST_0] = mmvdSolid[mvdBaseIdx][0];
+      pu.mvSolid[REF_PIC_LIST_1] = true;
+
+      mmvdValid[mvdBaseIdx][0] = cs.isClean(pu.Y().topRight(), mv0, REF_PIC_LIST_0, refIdx0);
+      mmvdValid[mvdBaseIdx][1] = true;
+
+      pu.mvValid[REF_PIC_LIST_0] = mmvdValid[mvdBaseIdx][0];
+      pu.mvValid[REF_PIC_LIST_1] = true;
+    }
+#endif
+  }
+  else if (refList1 != -1)
+  {
+    pu.interDir = 2;
+    pu.mv[REF_PIC_LIST_0] = Mv(0, 0);
+    pu.refIdx[REF_PIC_LIST_0] = -1;
+    pu.mv[REF_PIC_LIST_1]     = mmvdBaseMv[mvdBaseIdx][1].mv + tempMv[1];
+    pu.refIdx[REF_PIC_LIST_1] = refList1;
+#if GDR_ENABLED
+    if (isEncodeGdrClean)
+    {
+      // Mv mv0 = pu.mv[REF_PIC_LIST_0];
+      Mv mv1 = pu.mv[REF_PIC_LIST_1];
+
+      // int refIdx0 = pu.refIdx[REF_PIC_LIST_0];
+      int refIdx1 = pu.refIdx[REF_PIC_LIST_1];
+
+      mmvdValid[mvdBaseIdx][0] = true;
+      mmvdValid[mvdBaseIdx][1] = cs.isClean(pu.Y().topRight(), mv1, REF_PIC_LIST_1, refIdx1);
+
+      pu.mvSolid[REF_PIC_LIST_0] = true;
+      pu.mvSolid[REF_PIC_LIST_1] = mmvdSolid[mvdBaseIdx][1];
+
+      pu.mvValid[REF_PIC_LIST_0] = true;
+      pu.mvValid[REF_PIC_LIST_1] = mmvdValid[mvdBaseIdx][1];
+    }
+#endif
+  }
+
+  pu.mmvdMergeFlag    = true;
+  pu.mmvdMergeIdx     = candIdx;
+  pu.mergeFlag        = true;
+  pu.regularMergeFlag = true;
+  pu.mergeIdx         = candIdx.val;
+  pu.mergeType        = MergeType::DEFAULT_N;
+
+  pu.mvd[REF_PIC_LIST_0] = Mv();
+  pu.mvd[REF_PIC_LIST_1] = Mv();
+  pu.mvpIdx[REF_PIC_LIST_0] = NOT_VALID;
+  pu.mvpIdx[REF_PIC_LIST_1] = NOT_VALID;
+  pu.mvpNum[REF_PIC_LIST_0] = NOT_VALID;
+  pu.mvpNum[REF_PIC_LIST_1] = NOT_VALID;
+  pu.cu->imv                = mmvdUseAltHpelIf[mvdBaseIdx] ? IMV_HPEL : 0;
+
+  pu.cu->bcwIdx = (interDirNeighbours[mvdBaseIdx] == 3) ? bcwIdx[mvdBaseIdx] : BCW_DEFAULT;
+
+  for (int refList = 0; refList < 2; refList++)
+  {
+    if (pu.refIdx[refList] >= 0)
+    {
+      pu.mv[refList].clipToStorageBitDepth();
+    }
+  }
+
+  PU::restrictBiPredMergeCandsOne(pu);
+}
diff --git a/source/Lib/CommonLib/InterPrediction.h b/source/Lib/CommonLib/InterPrediction.h
index f5b0d771a6662c12735a99c803454a8e0d368ce2..58958b9c074f1c18d962e3a156e88e3833e26616 100644
--- a/source/Lib/CommonLib/InterPrediction.h
+++ b/source/Lib/CommonLib/InterPrediction.h
@@ -48,7 +48,6 @@
 #include "Picture.h"
 
 #include "RdCost.h"
-#include "ContextModelling.h"
 // forward declaration
 class Mv;
 
@@ -60,6 +59,89 @@ class Mv;
 // Class definition
 // ====================================================================================================================
 
+class MergeCtx
+{
+public:
+  MergeCtx() : numValidMergeCand(0), hasMergedCandList(false) {}
+  ~MergeCtx() {}
+public:
+  MvField mvFieldNeighbours[MRG_MAX_NUM_CANDS][2];
+#if GDR_ENABLED
+  // note : check if source of mv and mv itself is valid
+  bool     mvSolid[MRG_MAX_NUM_CANDS][2];
+  bool     mvValid[MRG_MAX_NUM_CANDS][2];
+  Position mvPos[MRG_MAX_NUM_CANDS][2];
+  MvpType  mvType[MRG_MAX_NUM_CANDS][2];
+#endif
+  uint8_t       bcwIdx[MRG_MAX_NUM_CANDS];
+  unsigned char interDirNeighbours[ MRG_MAX_NUM_CANDS      ];
+  int           numValidMergeCand;
+  bool          hasMergedCandList;
+
+  MotionBuf     subPuMvpMiBuf;
+  MvField       mmvdBaseMv[MmvdIdx::BASE_MV_NUM][2];
+#if GDR_ENABLED
+  bool mmvdSolid[MmvdIdx::BASE_MV_NUM][2];
+  bool mmvdValid[MmvdIdx::BASE_MV_NUM][2];
+#endif
+  void          setMmvdMergeCandiInfo(PredictionUnit &pu, MmvdIdx candIdx);
+  void          getMmvdDeltaMv(const Slice& slice, const MmvdIdx candIdx, Mv deltaMv[NUM_REF_PIC_LIST_01]) const;
+  bool          mmvdUseAltHpelIf[MmvdIdx::BASE_MV_NUM];
+  bool          useAltHpelIf      [ MRG_MAX_NUM_CANDS ];
+#if JVET_AC0139_UNIFIED_MERGE
+  void setMergeInfo( PredictionUnit& pu, int candIdx ) const;
+#else
+  void setMergeInfo( PredictionUnit& pu, int candIdx );
+#endif
+};
+
+class AffineMergeCtx
+{
+public:
+  AffineMergeCtx() : numValidMergeCand(0)
+  {
+    for (int i = 0; i < AFFINE_MRG_MAX_NUM_CANDS; i++)
+    {
+      affineType[i] = AffineModel::_4_PARAMS;
+    }
+  }
+  ~AffineMergeCtx() {}
+public:
+  std::array<MvField[2], AFFINE_MAX_NUM_CP> mvFieldNeighbours[AFFINE_MRG_MAX_NUM_CANDS];
+#if GDR_ENABLED
+  std::array<bool[2], AFFINE_MAX_NUM_CP> mvSolid[AFFINE_MRG_MAX_NUM_CANDS];
+  std::array<bool[2], AFFINE_MAX_NUM_CP> mvValid[AFFINE_MRG_MAX_NUM_CANDS];
+
+  bool isSolid(const int idx, const int l)
+  {
+    bool solid = true;
+    for (auto &c: mvSolid[idx])
+    {
+      solid &= c[l];
+    }
+    return solid;
+  }
+
+  bool isValid(const int idx, const int l)
+  {
+    bool valid = true;
+    for (auto &c: mvValid[idx])
+    {
+      valid &= c[l];
+    }
+    return valid;
+  }
+#endif
+  unsigned char interDirNeighbours[AFFINE_MRG_MAX_NUM_CANDS];
+  AffineModel   affineType[AFFINE_MRG_MAX_NUM_CANDS];
+  uint8_t       bcwIdx[AFFINE_MRG_MAX_NUM_CANDS];
+  int           numValidMergeCand;
+  int           maxNumMergeCand;
+
+  MergeCtx     *mrgCtx;
+  MergeType     mergeType[AFFINE_MRG_MAX_NUM_CANDS];
+};
+
 class InterPrediction : public WeightPrediction
 {
 private:
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index 25adf4ec35fd53c56e04c5fec888d92eeb5ce737..bdfa640b2a20c895ca6e92895dcb563b27d9cc79 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -889,8 +889,7 @@ void CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx&
   {
     cu.colorTransform = false;
     cs.addEmptyTUs( partitioner );
-    MergeCtx           mrgCtx;
-    prediction_unit  ( pu, mrgCtx );
+    prediction_unit  ( pu );
     end_of_ctu( cu, cuCtx );
     return;
   }
@@ -1023,7 +1022,7 @@ void CABACReader::cu_skip_flag( CodingUnit& cu )
   }
 }
 
-void CABACReader::imv_mode( CodingUnit& cu, MergeCtx& mrgCtx )
+void CABACReader::imv_mode( CodingUnit& cu )
 {
   RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__OTHER );
 
@@ -1077,7 +1076,7 @@ void CABACReader::imv_mode( CodingUnit& cu, MergeCtx& mrgCtx )
   DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() IMVFlag=%d\n", cu.imv );
 }
 
-void CABACReader::affine_amvr_mode( CodingUnit& cu, MergeCtx& mrgCtx )
+void CABACReader::affine_amvr_mode( CodingUnit& cu )
 {
   RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__OTHER );
 
@@ -1270,15 +1269,14 @@ void CABACReader::cu_pred_data( CodingUnit &cu )
     cu.predMode = MODE_IBC;
     return;
   }
-  MergeCtx mrgCtx;
 
   for( auto &pu : CU::traversePUs( cu ) )
   {
-    prediction_unit( pu, mrgCtx );
+    prediction_unit( pu );
   }
 
-  imv_mode   ( cu, mrgCtx );
-  affine_amvr_mode( cu, mrgCtx );
+  imv_mode   ( cu );
+  affine_amvr_mode( cu );
   cu_bcw_flag( cu );
 }
 
@@ -2084,7 +2082,7 @@ void CABACReader::xAdjustPLTIndex(CodingUnit& cu, Pel curLevel, uint32_t idx, Pe
 //    void  mvp_flag        ( pu, refList );
 //================================================================================
 
-void CABACReader::prediction_unit( PredictionUnit& pu, MergeCtx& mrgCtx )
+void CABACReader::prediction_unit( PredictionUnit& pu )
 {
   if( pu.cu->skip )
   {
diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h
index e8fcf54ebf35dbb2aebdd869642c86b727a8a07b..98704b00f3cdc3453bc53a03c69b1d091ad2af6f 100644
--- a/source/Lib/DecoderLib/CABACReader.h
+++ b/source/Lib/DecoderLib/CABACReader.h
@@ -106,15 +106,15 @@ public:
   void        cu_palette_info           ( CodingUnit&                   cu,     ComponentID     compBegin, uint32_t numComp, CUCtx& cuCtx );
   void        cuPaletteSubblockInfo     ( CodingUnit&                   cu,     ComponentID     compBegin, uint32_t numComp, int subSetId, uint32_t& prevRunPos, unsigned& prevRunType );
   // prediction unit (clause 7.3.8.6)
-  void        prediction_unit           ( PredictionUnit&               pu,     MergeCtx&       mrgCtx );
+  void        prediction_unit           ( PredictionUnit&               pu );
   void        merge_flag                ( PredictionUnit&               pu );
   void        merge_data                ( PredictionUnit&               pu );
   void        affine_flag               ( CodingUnit&                   cu );
   void        subblock_merge_flag       ( CodingUnit&                   cu );
   void        merge_idx                 ( PredictionUnit&               pu );
   void        mmvd_merge_idx(PredictionUnit&               pu);
-  void        imv_mode                  ( CodingUnit&                   cu,     MergeCtx&       mrgCtx );
-  void        affine_amvr_mode          ( CodingUnit&                   cu,     MergeCtx&       mrgCtx );
+  void        imv_mode                  ( CodingUnit&                   cu );
+  void        affine_amvr_mode          ( CodingUnit&                   cu );
   void        inter_pred_idc            ( PredictionUnit&               pu );
   void        ref_idx                   ( PredictionUnit&               pu,     RefPicList      eRefList );
   void        mvp_flag                  ( PredictionUnit&               pu,     RefPicList      eRefList );
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 86cd7eabad3cf8ef96c6e3c88f40ab59233b12f8..7f865ad6483d930ff3aaa2f2f057f1ee1d67ad85 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -5791,5 +5791,301 @@ void EncCu::xReuseCachedResult( CodingStructure *&tempCS, CodingStructure *&best
 }
 #endif
 
+#if JVET_AC0139_UNIFIED_MERGE
+MergeItem::MergeItem()
+{
+
+}
+MergeItem::~MergeItem()
+{
+
+}
+
+void MergeItem::create(ChromaFormat chromaFormat, const Area& area)
+{
+  if (m_pelStorage.bufs.empty())
+  {
+    m_pelStorage.create(chromaFormat, area);
+    m_mvStorage.resize(area.area() >> (MIN_CU_LOG2 << 1));
+  }
+
+  // reset data
+  cost = MAX_DOUBLE;
+  mergeIdx = 0;
+  bcwIdx = 0;
+  interDir = 0;
+  useAltHpelIf = false;
+  affineType = AffineModel::_4_PARAMS;
+  mergeItemType = MergeItemType::NUM;
+
+  noBdofRefine = false;
+  noResidual = false;
+
+  lumaPredReady = false;
+  chromaPredReady = false;
+}
+
+void MergeItem::importMergeInfo(const MergeCtx& mergeCtx, int _mergeIdx, MergeItemType _mergeItemType, PredictionUnit& pu)
+{
+  mergeIdx = _mergeIdx;
+  mergeItemType = _mergeItemType;
+
+  if (mergeItemType != MergeItemType::GPM)
+  {
+    mvField[0][REF_PIC_LIST_0] = mergeCtx.mvFieldNeighbours[mergeIdx][REF_PIC_LIST_0];
+    mvField[0][REF_PIC_LIST_1] = mergeCtx.mvFieldNeighbours[mergeIdx][REF_PIC_LIST_1];
+    interDir = mergeCtx.interDirNeighbours[mergeIdx];
+    bcwIdx = mergeCtx.bcwIdx[mergeIdx];
+    useAltHpelIf = mergeCtx.useAltHpelIf[mergeIdx];
+  }
+
+  switch (_mergeItemType)
+  {
+  case MergeItemType::REGULAR:
+    break;
+
+  case MergeItemType::CIIP:
+    break;
+
+  case MergeItemType::MMVD:
+  {
+    MmvdIdx candIdx;
+    candIdx.val = mergeIdx;
+    const int mmvdBaseIdx = candIdx.pos.baseIdx;
+    mvField[0][REF_PIC_LIST_0] = mergeCtx.mmvdBaseMv[mmvdBaseIdx][REF_PIC_LIST_0];
+    mvField[0][REF_PIC_LIST_1] = mergeCtx.mmvdBaseMv[mmvdBaseIdx][REF_PIC_LIST_1];
+    Mv tempMv[NUM_REF_PIC_LIST_01];
+    mergeCtx.getMmvdDeltaMv(*pu.cs->slice, candIdx, tempMv);
+    mvField[0][REF_PIC_LIST_0].mv += tempMv[REF_PIC_LIST_0];
+    mvField[0][REF_PIC_LIST_1].mv += tempMv[REF_PIC_LIST_1];
+    interDir = mergeCtx.interDirNeighbours[mmvdBaseIdx];
+    bcwIdx = mergeCtx.bcwIdx[mmvdBaseIdx];
+    useAltHpelIf = mergeCtx.useAltHpelIf[mmvdBaseIdx];
+    break;
+  }
+  case MergeItemType::GPM:
+    mvField[0][REF_PIC_LIST_0].setMvField(Mv(0, 0), -1);
+    mvField[0][REF_PIC_LIST_1].setMvField(Mv(0, 0), -1);
+    bcwIdx = BCW_DEFAULT;
+    useAltHpelIf = false;
+    MergeItem::updateGpmIdx(mergeIdx, pu.geoSplitDir, pu.geoMergeIdx);
+    pu.mergeFlag = true;
+    pu.cu->affine = false;
+    pu.cu->geoFlag = true;
+    pu.mergeType = MergeType::DEFAULT_N;
+    PU::spanMotionInfo(pu, getMvBuf(pu));
+    PU::spanGeoMotionInfo(pu, mergeCtx, pu.geoSplitDir, pu.geoMergeIdx);
+    getMvBuf(pu).copyFrom(pu.getMotionBuf());
+    break;
+
+  case MergeItemType::IBC:
+  default:
+    THROW("Wrong merge item type");
+  }
+}
+
+void MergeItem::importMergeInfo(const AffineMergeCtx& mergeCtx, int _mergeIdx, MergeItemType _mergeItemType, const UnitArea& unitArea)
+{
+  mergeIdx = _mergeIdx;
+  mergeItemType = _mergeItemType;
+
+  affineType = mergeCtx.affineType[mergeIdx];
+  interDir = mergeCtx.interDirNeighbours[mergeIdx];
+  bcwIdx = mergeCtx.bcwIdx[mergeIdx];
+  useAltHpelIf = false;
+
+  switch (_mergeItemType)
+  {
+  case MergeItemType::SBTMVP:
+    mvField = mergeCtx.mvFieldNeighbours[mergeIdx];
+    getMvBuf(unitArea).copyFrom(mergeCtx.mrgCtx->subPuMvpMiBuf);
+    break;
+
+  case MergeItemType::AFFINE:
+    mvField = mergeCtx.mvFieldNeighbours[mergeIdx];
+    break;
+
+  default:
+    THROW("Wrong merge item type");
+  }
+}
+
+bool MergeItem::exportMergeInfo(PredictionUnit& pu, bool forceNoResidual)
+{
+  pu.mergeFlag = true;
+  pu.regularMergeFlag = false;
+  pu.mmvdMergeFlag = false;
+  pu.interDir = interDir;
+  pu.mergeIdx = mergeIdx;
+  pu.mergeType = MergeType::DEFAULT_N;
+  pu.mv[REF_PIC_LIST_0] = mvField[0][REF_PIC_LIST_0].mv;
+  pu.mv[REF_PIC_LIST_1] = mvField[0][REF_PIC_LIST_1].mv;
+  pu.refIdx[REF_PIC_LIST_0] = mvField[0][REF_PIC_LIST_0].refIdx;
+  pu.refIdx[REF_PIC_LIST_1] = mvField[0][REF_PIC_LIST_1].refIdx;
+  pu.mvd[REF_PIC_LIST_0] = Mv();
+  pu.mvd[REF_PIC_LIST_1] = Mv();
+  pu.mvpIdx[REF_PIC_LIST_0] = NOT_VALID;
+  pu.mvpIdx[REF_PIC_LIST_1] = NOT_VALID;
+  pu.mvpNum[REF_PIC_LIST_0] = NOT_VALID;
+  pu.mvpNum[REF_PIC_LIST_1] = NOT_VALID;
+  pu.cu->bcwIdx = (interDir == 3) ? bcwIdx : BCW_DEFAULT;
+  pu.mmvdEncOptMode = 0;
+  pu.cu->mmvdSkip = false;
+  pu.cu->affine = false;
+  pu.cu->affineType = AffineModel::_4_PARAMS;
+  pu.cu->geoFlag = false;
+  pu.cu->mtsFlag = false;
+  pu.ciipFlag = false;
+  pu.cu->imv = (!pu.cu->geoFlag && useAltHpelIf) ? IMV_HPEL : 0;
+
+  const bool resetCiip2Regular = mergeItemType == MergeItemType::CIIP && forceNoResidual;
+  MergeItemType updatedType = resetCiip2Regular ? MergeItemType::REGULAR : mergeItemType;
+  switch (updatedType)
+  {
+  case MergeItemType::REGULAR:
+    pu.regularMergeFlag = true;
+    PU::restrictBiPredMergeCandsOne(pu);
+    break;
+
+  case MergeItemType::CIIP:
+    CHECK(forceNoResidual, "Cannot force no residuals for CIIP");
+    pu.ciipFlag = true;
+    pu.intraDir[ChannelType::LUMA] = PLANAR_IDX;
+    pu.intraDir[ChannelType::CHROMA] = DM_CHROMA_IDX;
+    break;
+
+  case MergeItemType::MMVD:
+    pu.mmvdMergeFlag = true;
+    pu.mmvdMergeIdx.val = mergeIdx;
+    pu.regularMergeFlag = true;
+    if (forceNoResidual)
+    {
+      pu.cu->mmvdSkip = true;
+    }
+    PU::restrictBiPredMergeCandsOne(pu);
+    break;
+
+  case MergeItemType::SBTMVP:
+    pu.cu->affine = true;
+    pu.mergeType = MergeType::SUBPU_ATMVP;
+    break;
+
+  case MergeItemType::AFFINE:
+    pu.cu->affine = true;
+    pu.cu->affineType = affineType;
+    PU::setAllAffineMvField(pu, mvField, REF_PIC_LIST_0);
+    PU::setAllAffineMvField(pu, mvField, REF_PIC_LIST_1);
+    break;
+
+  case MergeItemType::GPM:
+    pu.mergeIdx = -1;
+    pu.cu->geoFlag = true;
+    pu.cu->bcwIdx = BCW_DEFAULT;
+    MergeItem::updateGpmIdx(mergeIdx, pu.geoSplitDir, pu.geoMergeIdx);
+    pu.cu->imv = 0;
+    break;
+
+  case MergeItemType::IBC:
+  default:
+    THROW("Wrong merge item type");
+  }
+
+  if (mergeItemType == MergeItemType::GPM)
+  {
+    pu.getMotionBuf().copyFrom(getMvBuf(pu));
+  }
+  else
+  {
+    PU::spanMotionInfo(pu, getMvBuf(pu));
+  }
+
+#if GDR_ENABLED
+  CodingStructure &cs = *pu.cs;
+  const bool isEncodeGdrClean = cs.sps->getGDREnabledFlag() && cs.pcv->isEncoder 
+    && ((cs.picture->gdrParam.inGdrInterval && cs.isClean(pu.Y().topRight(), ChannelType::LUMA)) 
+    || (cs.picture->gdrParam.verBoundary == -1));
+  if (isEncodeGdrClean)
+  {
+    Mv mv0 = pu.mv[REF_PIC_LIST_0];
+    Mv mv1 = pu.mv[REF_PIC_LIST_1];
+
+    int refIdx0 = pu.refIdx[REF_PIC_LIST_0];
+    int refIdx1 = pu.refIdx[REF_PIC_LIST_1];
+
+    pu.mvSolid[REF_PIC_LIST_0] = mvSolid[0];
+    pu.mvSolid[REF_PIC_LIST_1] = mvSolid[1];
+    pu.mvValid[REF_PIC_LIST_0] = cs.isClean(pu.Y().topRight(), mv0, REF_PIC_LIST_0, refIdx0);
+    pu.mvValid[REF_PIC_LIST_1] = cs.isClean(pu.Y().topRight(), mv1, REF_PIC_LIST_1, refIdx1);
+  }
+#endif
+
+  return resetCiip2Regular;
+}
+
+MergeItemList::MergeItemList()
+{
+
+}
+
+MergeItemList::~MergeItemList()
+{
+}
+
+void MergeItemList::init(size_t maxSize, ChromaFormat chromaFormat, int ctuWidth, int ctuHeight)
+{
+  m_list.reserve(maxSize + 1); // to avoid reallocation when inserting a new item
+  m_chromaFormat = chromaFormat;
+  m_ctuArea.x = 0;
+  m_ctuArea.y = 0;
+  m_ctuArea.width = ctuWidth;
+  m_ctuArea.height = ctuHeight;
+}
+
+MergeItem* MergeItemList::allocateNewMergeItem()
+{
+  MergeItem* p = m_mergeItemPool.get();
+  p->create(m_chromaFormat, m_ctuArea);
+
+  return p;
+}
+
+void MergeItemList::insertMergeItemToList(MergeItem* p)
+{
+  if (m_list.empty())
+  {
+    m_list.push_back(p);
+  }
+  else if (m_list.size() == m_maxTrackingNum && p->cost >= m_list.back()->cost)
+  {
+    m_mergeItemPool.giveBack(p);
+  }
+  else
+  {
+    if (m_list.size() == m_maxTrackingNum)
+    {
+      m_mergeItemPool.giveBack(m_list.back());
+      m_list.pop_back();
+    }
+    auto it = std::find_if(m_list.begin(), m_list.end(), [&p](const MergeItem *mi) { return p->cost < mi->cost; });
+    m_list.insert(it, p);
+  }
+}
+
+MergeItem* MergeItemList::getMergeItemInList(size_t index)
+{
+  return index < m_maxTrackingNum ? m_list[index] : nullptr;
+}
+
+void MergeItemList::resetList(size_t maxTrackingNum)
+{
+  for (auto p : m_list)
+  {
+    m_mergeItemPool.giveBack(p);
+  }
+  m_list.clear();
+  m_list.reserve(maxTrackingNum);
+  m_maxTrackingNum = maxTrackingNum;
+}
+#endif
 
 //! \}
diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h
index f855765796bfd2f07b3fa2c95de86dade1d3c641..164791e031b2d5bc901b3e1cf3181a0b43151e95 100644
--- a/source/Lib/EncoderLib/EncCu.h
+++ b/source/Lib/EncoderLib/EncCu.h
@@ -135,6 +135,93 @@ public:
   }
 };
 
+#if JVET_AC0139_UNIFIED_MERGE
+class MergeItem
+{
+private:
+  PelStorage m_pelStorage;
+  std::vector<MotionInfo> m_mvStorage;
+
+public:
+  enum class MergeItemType
+  {
+    REGULAR,
+    SBTMVP,
+    AFFINE,
+    MMVD,
+    CIIP,
+    GPM,
+    IBC,
+    NUM,
+  };
+
+  double        cost;
+  std::array<MvField[2], AFFINE_MAX_NUM_CP> mvField;
+  int           mergeIdx;
+  uint8_t       bcwIdx;
+  uint8_t       interDir;
+  bool          useAltHpelIf;
+  AffineModel   affineType;
+
+  bool          noResidual;
+  bool          noBdofRefine;
+
+  bool          lumaPredReady;
+  bool          chromaPredReady;
+
+  MergeItemType mergeItemType;
+  MotionBuf     mvBuf;
+
+#if GDR_ENABLED
+  bool          mvSolid[2];
+  bool          mvValid[2];
+#endif
+
+  MergeItem();
+  ~MergeItem();
+
+  void          create(ChromaFormat chromaFormat, const Area& area);
+  void          importMergeInfo(const MergeCtx& mergeCtx, int _mergeIdx, MergeItemType _mergeItemType, PredictionUnit& pu);
+  void          importMergeInfo(const AffineMergeCtx& mergeCtx, int _mergeIdx, MergeItemType _mergeItemType, const UnitArea& unitArea);
+  bool          exportMergeInfo(PredictionUnit& pu, bool forceNoResidual);
+  PelUnitBuf    getPredBuf(const UnitArea& unitArea) { return m_pelStorage.getBuf(unitArea); }
+  MotionBuf     getMvBuf(const UnitArea& unitArea) { return MotionBuf(m_mvStorage.data(), g_miScaling.scale(unitArea.lumaSize())); }
+
+  static int getGpmUnfiedIndex(int splitDir, const MergeIdxPair& geoMergeIdx)
+  {
+    return (splitDir << 8) | (geoMergeIdx[0] << 4) | geoMergeIdx[1];
+  }
+  static void updateGpmIdx(int mergeIdx, uint8_t& splitDir, MergeIdxPair& geoMergeIdx)
+  {
+    splitDir = (mergeIdx >> 8) & 0xFF;
+    geoMergeIdx[0] = (mergeIdx >> 4) & 0xF;
+    geoMergeIdx[1] = mergeIdx & 0xF;
+  }
+};
+
+class MergeItemList
+{
+private:
+  Pool<MergeItem> m_mergeItemPool;
+  std::vector<MergeItem *> m_list;
+  size_t m_maxTrackingNum = 0;
+  ChromaFormat  m_chromaFormat;
+  Area m_ctuArea;
+
+public:
+  MergeItemList();
+  ~MergeItemList();
+
+  void          init(size_t maxSize, ChromaFormat chromaFormat, int ctuWidth, int ctuHeight);
+  MergeItem*    allocateNewMergeItem();
+  void          insertMergeItemToList(MergeItem* p);
+  void          resetList(size_t maxTrackingNum);
+  MergeItem*    getMergeItemInList(size_t index);
+  size_t        size() { return m_list.size(); }
+
+};
+#endif
+
 class EncCu
   : DecCu
 {