diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 76fd1f61365192974d7c829703e6f738073e58d8..b33cb34a48fdfb8583a87e36694dd9b91f11c96e 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -854,6 +854,9 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setIBCHashSearchMaxCand                              ( m_IBCHashSearchMaxCand );
   m_cEncLib.setIBCHashSearchRange4SmallBlk                       ( m_IBCHashSearchRange4SmallBlk );
   m_cEncLib.setIBCFastMethod                                     ( m_IBCFastMethod );
+#if JVET_AA0061_IBC_MBVD
+  m_cEncLib.setIbcMbvd                                           ( m_ibcMbvd );
+#endif
 
   m_cEncLib.setUseWrapAround                                     ( m_wrapAround );
   m_cEncLib.setWrapAroundOffset                                  ( m_wrapAroundOffset );
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index 869e21c862f3b690ebb022404568776c3060b761..dd451e192fe718649e56cc3bc197728338d9277c 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -1101,6 +1101,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ( "IBCHashSearchMaxCand",                           m_IBCHashSearchMaxCand,                            256u, "Max candidates for hash based IBC search")
   ( "IBCHashSearchRange4SmallBlk",                    m_IBCHashSearchRange4SmallBlk,                     256u, "Small block search range in based IBC search")
   ( "IBCFastMethod",                                  m_IBCFastMethod,                                     6u, "Fast methods for IBC")
+#if JVET_AA0061_IBC_MBVD
+  ("IBCMBVD",                                         m_ibcMbvd,                                         true, "IBC MMVD mode (0:off, 1:on)  [default: on]" )
+#endif
 
   ("WrapAround",                                      m_wrapAround,                                     false, "Enable horizontal wrap-around motion compensation for inter prediction (0:off, 1:on)  [default: off]")
   ("WrapAroundOffset",                                m_wrapAroundOffset,                                  0u, "Offset in luma samples used for computing the horizontal wrap-around position")
@@ -4944,6 +4947,9 @@ void EncAppCfg::xPrintParameter()
   msg(VERBOSE, "ACT:%d ", m_useColorTrans);
     msg(VERBOSE, "PLT:%d ", m_PLTMode);
     msg(VERBOSE, "IBC:%d ", m_IBCMode);
+#if JVET_AA0061_IBC_MBVD
+    msg( VERBOSE, "IBCMBVD:%d ", m_ibcMbvd );
+#endif
   msg( VERBOSE, "HashME:%d ", m_HashME );
   msg( VERBOSE, "WrapAround:%d ", m_wrapAround);
   if( m_wrapAround )
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index 4170416e34b9a67ab0e1cda53f45e7f7a351fe0a..06b451d8dcdc193347bee0a8eae64e3b6094bf6d 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -464,6 +464,9 @@ protected:
   unsigned  m_IBCHashSearchMaxCand;
   unsigned  m_IBCHashSearchRange4SmallBlk;
   unsigned  m_IBCFastMethod;
+#if JVET_AA0061_IBC_MBVD
+  bool      m_ibcMbvd;
+#endif
 
   bool      m_wrapAround;
   unsigned  m_wrapAroundOffset;
diff --git a/source/Lib/CommonLib/Buffer.cpp b/source/Lib/CommonLib/Buffer.cpp
index 2f73ff97c8d6730293a9aebee430ac701632c6c8..41850a46415a38c40580d12e8576449732331b2b 100644
--- a/source/Lib/CommonLib/Buffer.cpp
+++ b/source/Lib/CommonLib/Buffer.cpp
@@ -1216,6 +1216,46 @@ void AreaBuf<Pel>::rspSignal( const AreaBuf<Pel> &toReshape, std::vector<Pel>& p
   }
 }
 
+#if JVET_AA0070_RRIBC
+template<>
+void AreaBuf<Pel>::flipSignal(bool isFlipHor)
+{
+  Pel *tempPel;
+  Size tSize(width, height);
+  tempPel       = new Pel[tSize.area()];
+  PelBuf tmpBuf = PelBuf(tempPel, tSize);
+  copyBufferCore(buf, stride, tmpBuf.buf, tmpBuf.stride, tmpBuf.width, tmpBuf.height);
+
+  Pel *dstbuf = buf;
+  Pel *srcbuf = tmpBuf.buf;
+  if (isFlipHor)
+  {
+    for (unsigned y = 0; y < height; y++)
+    {
+      for (unsigned x = 0; x < width; x++)
+      {
+        dstbuf[x] = srcbuf[width - 1 - x];
+      }
+      dstbuf += stride;
+      srcbuf += tmpBuf.stride;
+    }
+  }
+  else
+  {
+    for (unsigned y = 0; y < height; y++)
+    {
+      for (unsigned x = 0; x < width; x++)
+      {
+        dstbuf[x] = srcbuf[(height - 1 - y) * tmpBuf.stride + x];
+      }
+      dstbuf += stride;
+    }
+  }
+
+  delete[] tempPel;
+}
+#endif
+
 template<>
 void AreaBuf<Pel>::rspSignalAllAndSubtract( const AreaBuf<Pel> &buffer1, const AreaBuf<Pel> &buffer2, std::vector<Pel>& pLUT )
 {
diff --git a/source/Lib/CommonLib/Buffer.h b/source/Lib/CommonLib/Buffer.h
index 5a67cf41dabac313632da090d30b6ff6b7ff265a..701f1f6af8a5478a617eaa6dc6ac03bfcca5cddd 100644
--- a/source/Lib/CommonLib/Buffer.h
+++ b/source/Lib/CommonLib/Buffer.h
@@ -206,6 +206,10 @@ struct AreaBuf : public Size
 
   void toLast               ( const ClpRng& clpRng );
 
+#if JVET_AA0070_RRIBC
+  void flipSignal(bool isFlipHor);
+#endif
+
   void rspSignal            ( std::vector<Pel>& pLUT );
   void rspSignal            ( const AreaBuf<const Pel>& other, std::vector<Pel>& pLUT );
   void rspSignal            ( const AreaBuf<Pel> &toReshape, std::vector<Pel>& pLUT );
diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h
index af2b778f3014f7c6969ce02b90e2086e583a83f7..5c17fe4b1b18966d083e988200eec812d0c07723 100644
--- a/source/Lib/CommonLib/CommonDef.h
+++ b/source/Lib/CommonLib/CommonDef.h
@@ -654,7 +654,7 @@ static const int MMVD_MRG_MAX_RD_NUM =                              20;
 static const int MMVD_MRG_MAX_RD_NUM =                              MRG_MAX_NUM_CANDS;
 #endif
 static const int MMVD_MRG_MAX_RD_BUF_NUM =                          (MMVD_MRG_MAX_RD_NUM + 1);///< increase buffer size by 1
-#if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
+#if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED || JVET_AA0061_IBC_MBVD
 static const int LAST_MERGE_MMVD_IDX_CABAC =                        5;
 #endif
 #if JVET_W0097_GPM_MMVD_TM
@@ -748,6 +748,9 @@ static const int    THRES_AFFINE =                                  4;
 #if !MERGE_ENC_OPT
 static const int    NUM_MRG_SATD_CAND =                             4;
 #endif
+#if JVET_AA0061_IBC_MBVD
+static const int    NUM_IBC_MRG_SATD_CAND =                         3;
+#endif
 static const double MRG_FAST_RATIO    =                             1.25;
 static const int    NUM_AFF_MRG_SATD_CAND =                         2;
 #if AFFINE_MMVD
@@ -1021,6 +1024,15 @@ static const int CHROMA_REFINEMENT_CANDIDATES = 8; /// 8 candidates BV to choose
 static const int IBC_FAST_METHOD_NOINTRA_IBCCBF0 = 0x01;
 static const int IBC_FAST_METHOD_BUFFERBV = 0X02;
 static const int IBC_FAST_METHOD_ADAPTIVE_SEARCHRANGE = 0X04;
+#if JVET_AA0061_IBC_MBVD
+static const int IBC_MBVD_BASE_NUM =                                 5;
+static const int IBC_MBVD_STEP_NUM =                                 20; // number of distance offset
+static const int IBC_MBVD_OFFSET_DIR =                               4; // (+, 0); (-, 0); (0, +); (0, -);
+static const int IBC_MBVD_MAX_REFINE_NUM = IBC_MBVD_STEP_NUM * IBC_MBVD_OFFSET_DIR; ///< max number of candidate from a base candidate
+static const int IBC_MBVD_NUM = IBC_MBVD_BASE_NUM * IBC_MBVD_MAX_REFINE_NUM;        ///< total number of IBC mmvd candidate
+static const int IBC_MBVD_SIZE_ENC =                                 8;
+static const int ADAPTIVE_SUB_GROUP_SIZE_IBC_MBVD = IBC_MBVD_MAX_REFINE_NUM;
+#endif
 static constexpr int MV_EXPONENT_BITCOUNT    = 4;
 static constexpr int MV_MANTISSA_BITCOUNT    = 6;
 static constexpr int MV_MANTISSA_UPPER_LIMIT = ((1 << (MV_MANTISSA_BITCOUNT - 1)) - 1);
diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp
index 4258d75e88064aae67af583182063ec4247d0f8a..f7b2a4dfa2b2280b73f26bce7c8bde7ea300bb57 100644
--- a/source/Lib/CommonLib/ContextModelling.cpp
+++ b/source/Lib/CommonLib/ContextModelling.cpp
@@ -324,6 +324,23 @@ unsigned DeriveCtx::CtxBMMrgFlag(const CodingUnit& cu)
   return ctxId;
 }
 #endif
+
+#if JVET_AA0070_RRIBC
+unsigned DeriveCtx::CtxRribcFlipType(const CodingUnit& cu)
+{
+  const CodingStructure *cs = cu.cs;
+  unsigned ctxId = 0;
+
+  const CodingUnit *cuLeft = cs->getCURestricted(cu.lumaPos().offset(-1, 0), cu, CH_L);
+  ctxId = (cuLeft && cuLeft->predMode == MODE_IBC && !cuLeft->firstPU->mergeFlag && cuLeft->rribcFlipType) ? 1 : 0;
+
+  const CodingUnit *cuAbove = cs->getCURestricted(cu.lumaPos().offset(0, -1), cu, CH_L);
+  ctxId += (cuAbove && cuAbove->predMode == MODE_IBC && !cuAbove->firstPU->mergeFlag && cuAbove->rribcFlipType) ? 1 : 0;
+
+  return ctxId;
+}
+#endif
+
 unsigned DeriveCtx::CtxAffineFlag( const CodingUnit& cu )
 {
   const CodingStructure *cs = cu.cs;
@@ -498,6 +515,13 @@ void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx )
 #if MULTI_HYP_PRED
     pu.addHypData.clear();
     pu.numMergedAddHyps = 0;
+#endif
+#if JVET_AA0070_RRIBC
+    pu.cu->rribcFlipType = rribcFlipTypes[candIdx];
+  }
+  else
+  {
+    pu.cu->rribcFlipType = 0;
 #endif
   }
   pu.cu->BcwIdx = ( interDirNeighbours[candIdx] == 3 ) ? BcwIdx[candIdx] : BCW_DEFAULT;
@@ -1164,6 +1188,93 @@ void MergeCtx::setMmvdMergeCandiInfo(PredictionUnit& pu, int candIdx)
   PU::restrictBiPredMergeCandsOne(pu);
 }
 
+#if JVET_AA0061_IBC_MBVD
+bool MergeCtx::setIbcMbvdMergeCandiInfo(PredictionUnit& pu, int candIdx, int candIdxMaped)
+{
+  const int mvShift = MV_FRACTIONAL_BITS_DIFF + 2;
+  const int refMvdCands[IBC_MBVD_STEP_NUM] = { 1 << mvShift , 2 << mvShift , 4 << mvShift , 8 << mvShift , 12 << mvShift , 16 << mvShift , 24 << mvShift , 32 << mvShift , 40 << mvShift , 48 << mvShift , 56 << mvShift ,
+    64 << mvShift , 72 << mvShift , 80 << mvShift , 88 << mvShift , 96 << mvShift , 104 << mvShift , 112 << mvShift , 120 << mvShift , 128 << mvShift };
+  int fPosGroup = 0;
+  int fPosBaseIdx = 0;
+  int fPosStep = 0;
+  int tempIdx = 0;
+  int fPosPosition = 0;
+  Mv tempMv;
+
+  if(candIdxMaped == -1)
+  {
+    candIdxMaped = candIdx;
+  }
+  tempIdx = candIdxMaped;
+
+  fPosGroup = tempIdx / (IBC_MBVD_BASE_NUM * IBC_MBVD_MAX_REFINE_NUM);
+  tempIdx = tempIdx - fPosGroup * (IBC_MBVD_BASE_NUM * IBC_MBVD_MAX_REFINE_NUM);
+  fPosBaseIdx = tempIdx / IBC_MBVD_MAX_REFINE_NUM;
+  tempIdx = tempIdx - fPosBaseIdx * (IBC_MBVD_MAX_REFINE_NUM);
+  fPosStep = tempIdx / IBC_MBVD_OFFSET_DIR;
+  fPosPosition = tempIdx - fPosStep * (IBC_MBVD_OFFSET_DIR);
+  int offset = refMvdCands[fPosStep];
+
+  const int refList0 = ibcMbvdBaseBv[fPosBaseIdx][0].refIdx;
+  const int xDir[] = {1, -1,  0,  0,  1, -1,  1, -1, 2, -2,  2, -2, 1,  1, -1, -1};
+  const int yDir[] = {0,  0,  1, -1,  1, -1, -1,  1, 1,  1, -1, -1, 2, -2,  2, -2};
+
+  if (refList0 != -1)
+  {
+    tempMv = Mv(xDir[fPosPosition] * offset, yDir[fPosPosition] * offset);
+#if JVET_AA0070_RRIBC
+    //check the BVD direction and base BV flip direction
+    if ((rribcFlipTypes[fPosBaseIdx] == 1) && (yDir[fPosPosition] != 0))
+    {
+      return true;
+    }
+    if ((rribcFlipTypes[fPosBaseIdx] == 2) && (xDir[fPosPosition] != 0))
+    {
+      return true;
+    }
+#endif
+    pu.interDir = 1;
+    pu.mv[REF_PIC_LIST_0] = ibcMbvdBaseBv[fPosBaseIdx][0].mv + tempMv;
+    pu.refIdx[REF_PIC_LIST_0] = refList0;
+    pu.mv[REF_PIC_LIST_1] = Mv(0, 0);
+    pu.refIdx[REF_PIC_LIST_1] = -1;
+  }
+
+  pu.ibcMbvdMergeFlag = true;
+  pu.ibcMbvdMergeIdx = candIdx;
+  pu.mergeFlag = true;
+  pu.mergeType = MRG_TYPE_IBC;
+
+  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 = (interDirNeighbours[fPosBaseIdx] == 3) ? BcwIdx[fPosBaseIdx] : BCW_DEFAULT;
+
+  for (int refList = 0; refList < 2; refList++)
+  {
+    if (pu.refIdx[refList] >= 0)
+    {
+      pu.mv[refList].clipToStorageBitDepth();
+    }
+  }
+  pu.bv = pu.mv[REF_PIC_LIST_0];
+  pu.bv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT); // used for only integer resolution
+  pu.cu->imv = pu.cu->imv == IMV_HPEL ? 0 : pu.cu->imv;
+#if JVET_AA0070_RRIBC
+  pu.cu->rribcFlipType = rribcFlipTypes[fPosBaseIdx];
+#endif
+#if MULTI_HYP_PRED
+  pu.addHypData.clear();
+  pu.numMergedAddHyps = 0;
+#endif
+  return false;
+}
+#endif
+
 #if JVET_V0130_INTRA_TMP
 unsigned DeriveCtx::CtxTmpFlag(const CodingUnit& cu)
 {
diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h
index 446f3ad05a1a3f6eff54a2789c968d84640ec599..2bc404197eb1586b3aaf337065564aa0e3ef2876 100644
--- a/source/Lib/CommonLib/ContextModelling.h
+++ b/source/Lib/CommonLib/ContextModelling.h
@@ -560,6 +560,9 @@ public:
   uint8_t       BcwIdx[NUM_MERGE_CANDS];
 #if INTER_LIC
   bool          LICFlags[NUM_MERGE_CANDS];
+#endif
+#if JVET_AA0070_RRIBC
+  int       rribcFlipTypes[NUM_MERGE_CANDS];
 #endif
   unsigned char interDirNeighbours[NUM_MERGE_CANDS];
 #if MULTI_HYP_PRED
@@ -574,6 +577,9 @@ public:
   uint8_t       BcwIdx            [ MRG_MAX_NUM_CANDS      ];
 #if INTER_LIC
   bool          LICFlags          [ MRG_MAX_NUM_CANDS      ];
+#endif
+#if JVET_AA0070_RRIBC
+  int rribcFlipTypes[MRG_MAX_NUM_CANDS];
 #endif
   unsigned char interDirNeighbours[ MRG_MAX_NUM_CANDS      ];
 #if MULTI_HYP_PRED
@@ -593,6 +599,10 @@ public:
   void setMmvdMergeCandiInfo(PredictionUnit& pu, int candIdx, int candIdxMaped = -1);
 #else
   void setMmvdMergeCandiInfo(PredictionUnit& pu, int candIdx);
+#endif
+#if JVET_AA0061_IBC_MBVD
+  MvField ibcMbvdBaseBv[IBC_MBVD_BASE_NUM][2];
+  bool setIbcMbvdMergeCandiInfo(PredictionUnit& pu, int candIdx, int candIdxMaped = -1);
 #endif
   bool          mmvdUseAltHpelIf  [ MMVD_BASE_MV_NUM ];
 #if (JVET_Y0134_TMVP_NAMVP_CAND_REORDERING && JVET_W0090_ARMC_TM) || JVET_Z0075_IBC_HMVP_ENLARGE
@@ -685,6 +695,9 @@ unsigned CtxAffineFlag( const CodingUnit& cu );
 #if JVET_X0049_ADAPT_DMVR
 unsigned CtxBMMrgFlag(const CodingUnit& cu);
 #endif
+#if JVET_AA0070_RRIBC
+unsigned CtxRribcFlipType(const CodingUnit& cu);
+#endif
 unsigned CtxPredModeFlag( const CodingUnit& cu );
 unsigned CtxIBCFlag(const CodingUnit& cu);
 unsigned CtxMipFlag   ( const CodingUnit& cu );
diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp
index 24568d429a95caf310338b9a7979eff8897edc71..a5164509bd83c1c9b69125ca7863bb883d5c5820 100644
--- a/source/Lib/CommonLib/Contexts.cpp
+++ b/source/Lib/CommonLib/Contexts.cpp
@@ -1152,6 +1152,53 @@ const CtxSet ContextSetCfg::AfMmvdOffsetStep = ContextSetCfg::addCtxSet
   });
 #endif
 
+#if JVET_AA0061_IBC_MBVD
+const CtxSet ContextSetCfg::IbcMbvdFlag = ContextSetCfg::addCtxSet
+({
+  {  18, },
+  {  18, },
+  { CNU, },
+  {   6, },
+  {   5, },
+  { DWS, },
+  {  18, },
+  {  18, },
+  { DWE, },
+  { 117, },
+  { 117, },
+  });
+
+const CtxSet ContextSetCfg::IbcMbvdMergeIdx = ContextSetCfg::addCtxSet
+({
+  {  58, },
+  {  43, },
+  { CNU, },
+  {   9, },
+  {  10, },
+  { DWS, },
+  {  18, },
+  {  11, },
+  { DWE, },
+  { 116, },
+  { 118, },
+  });
+
+const CtxSet ContextSetCfg::IbcMbvdStepMvpIdx = ContextSetCfg::addCtxSet
+({
+  {  43,  36,  36,  28,  35, },
+  {  28,  21,  36,  28,  43, },
+  { CNU, CNU, CNU, CNU, CNU, },
+  {   5,   4,   4,   4,   4, },
+  {   5,   5,   5,   5,   4, },
+  { DWS, DWS, DWS, DWS, DWS, },
+  {  18,  11,  11,  11,  11, },
+  {  18,  18,  18,  18,  11, },
+  { DWE, DWE, DWE, DWE, DWE, },
+  { 142, 157, 157, 142, 155, },
+  { 116, 103, 104, 108, 117, },
+  });
+#endif
+
 #if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
 const CtxSet ContextSetCfg::TMMergeFlag = ContextSetCfg::addCtxSet
 ({
@@ -1572,6 +1619,23 @@ const CtxSet ContextSetCfg::BMMergeFlag = ContextSetCfg::addCtxSet
   });
 #endif
 
+#if JVET_AA0070_RRIBC
+const CtxSet ContextSetCfg::rribcFlipType = ContextSetCfg::addCtxSet
+({
+  {  48,  50,  50,  50, },
+  {  56,  50,  43,  28, },
+  { CNU, CNU, CNU, CNU, },
+  {   5,   5,   9,   5, },
+  {   5,   5,   5,   5, },
+  { DWS, DWS, DWS, DWS, },
+  {  18,  18,  25,  18, },
+  {  18,  18,  11,  18, },
+  { DWE, DWE, DWE, DWE, },
+  { 126, 126, 181, 126, },
+  { 117, 117, 110, 116, },
+  });
+#endif
+
 const CtxSet ContextSetCfg::AffineFlag = ContextSetCfg::addCtxSet
 ({
   {  19,   6,   7, },
@@ -3198,6 +3262,38 @@ const CtxSet ContextSetCfg::AfMmvdOffsetStep = ContextSetCfg::addCtxSet
 });
 #endif
 
+#if JVET_AA0061_IBC_MBVD
+const CtxSet ContextSetCfg::IbcMbvdFlag = ContextSetCfg::addCtxSet
+({
+  { 25 },
+  { 33 },
+  { 35 },
+  { 5 },
+  { 4 },
+  { 4 }
+  });
+
+const CtxSet ContextSetCfg::IbcMbvdMergeIdx = ContextSetCfg::addCtxSet
+({
+  { 58 },
+  { 43 },
+  { 35 },
+  { 9 },
+  { 10 },
+  { 10 }
+  });
+
+const CtxSet ContextSetCfg::IbcMbvdStepMvpIdx = ContextSetCfg::addCtxSet
+({
+  { 35, 35, 35, 35, 35},
+  { 35, 35, 35, 35, 35},
+  { 35, 35, 35, 35, 35},
+  { 4,  4,  4,  4,  4 },
+  { 4,  4,  4,  4,  4 },
+  { 4,  4,  4,  4,  4 }
+  });
+#endif
+
 #if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
 const CtxSet ContextSetCfg::TMMergeFlag = ContextSetCfg::addCtxSet
 ({
@@ -3484,6 +3580,18 @@ const CtxSet ContextSetCfg::BMMergeFlag = ContextSetCfg::addCtxSet
 });
 #endif
 
+#if JVET_AA0070_RRIBC
+const CtxSet ContextSetCfg::rribcFlipType = ContextSetCfg::addCtxSet
+({
+  { 25, CNU, CNU, CNU },
+  { 26, CNU, CNU, CNU },
+  { 35, CNU, CNU, CNU },
+  { 4, 4, 4, 4 },
+  { 4, 4, 4, 4 },
+  { 4, 4, 4, 4 }
+  });
+#endif
+
 const CtxSet ContextSetCfg::AffineFlag = ContextSetCfg::addCtxSet
 ({
 	{ 34, 27,  6 },
@@ -4641,6 +4749,32 @@ const CtxSet ContextSetCfg::AfMmvdOffsetStep = ContextSetCfg::addCtxSet
 });
 #endif
 
+#if JVET_AA0061_IBC_MBVD
+const CtxSet ContextSetCfg::IbcMbvdFlag = ContextSetCfg::addCtxSet
+({
+  {  25, },
+  {  26, },
+  { CNU, },
+  {   4, },
+  });
+
+const CtxSet ContextSetCfg::IbcMbvdMergeIdx = ContextSetCfg::addCtxSet
+({
+  {  43, },
+  {  43, },
+  { CNU, },
+  {  10, },
+  });
+
+const CtxSet ContextSetCfg::IbcMbvdStepMvpIdx = ContextSetCfg::addCtxSet
+({
+  {  59, },
+  {  60, },
+  { CNU, },
+  {   0, },
+  });
+#endif
+
 #if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
 const CtxSet ContextSetCfg::TMMergeFlag = ContextSetCfg::addCtxSet
 ({
@@ -4843,6 +4977,17 @@ const CtxSet ContextSetCfg::BMMergeFlag = ContextSetCfg::addCtxSet
   { 4, 4, 4, 4 },
 });
 #endif
+
+#if JVET_AA0070_RRIBC
+const CtxSet ContextSetCfg::rribcFlipType = ContextSetCfg::addCtxSet
+({
+ { 25, CNU, CNU, CNU },
+  { 26, CNU, CNU, CNU },
+  { CNU, CNU, CNU, CNU },
+  { 4, 4, 4, 4 },
+  });
+#endif
+
 const CtxSet ContextSetCfg::AffineFlag = ContextSetCfg::addCtxSet
 ({
   {  19,  13,   6, },
diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h
index 9b051f6e040db202ca019b82d4ced09d6f9f10b2..491ea1c3e3471f5ad9b48b98ad2339fa5dddfbfe 100644
--- a/source/Lib/CommonLib/Contexts.h
+++ b/source/Lib/CommonLib/Contexts.h
@@ -342,6 +342,9 @@ public:
 #if JVET_X0049_ADAPT_DMVR
   static const CtxSet   BMMergeFlag;
 #endif
+#if JVET_AA0070_RRIBC
+  static const CtxSet   rribcFlipType;
+#endif
 #if JVET_Y0065_GPM_INTRA
   static const CtxSet   GPMIntraFlag;
 #endif
@@ -399,6 +402,12 @@ public:
   static const CtxSet   AfMmvdIdx;
   static const CtxSet   AfMmvdOffsetStep;
 #endif
+  #if JVET_AA0061_IBC_MBVD
+  static const CtxSet   IbcMbvdFlag;
+  static const CtxSet   IbcMbvdMergeIdx;
+  static const CtxSet   IbcMbvdStepMvpIdx;
+#endif
+
 #if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
   static const CtxSet   TMMergeFlag;
 #endif
diff --git a/source/Lib/CommonLib/IbcHashMap.cpp b/source/Lib/CommonLib/IbcHashMap.cpp
index 1d1d6cf46036ccb2604f151dec6911154564dcfb..e8ef1e9aef3f015f877da722c10d0077e111a638 100644
--- a/source/Lib/CommonLib/IbcHashMap.cpp
+++ b/source/Lib/CommonLib/IbcHashMap.cpp
@@ -243,7 +243,11 @@ void IbcHashMap::xxBuildPicHashMap(const PelUnitBuf& pic)
   }
 }
 
+#if JVET_AA0070_RRIBC
+void IbcHashMap::rebuildPicHashMap(const PelUnitBuf &pic, bool isDualTree)
+#else
 void IbcHashMap::rebuildPicHashMap(const PelUnitBuf& pic)
+#endif
 {
   m_hash2Pos.clear();
 
@@ -252,9 +256,13 @@ void IbcHashMap::rebuildPicHashMap(const PelUnitBuf& pic)
   case CHROMA_400:
     xxBuildPicHashMap<CHROMA_400>(pic);
     break;
+#if JVET_AA0070_RRIBC
+  case CHROMA_420: isDualTree ? xxBuildPicHashMap<CHROMA_400>(pic) :  xxBuildPicHashMap<CHROMA_420>(pic); break;
+#else
   case CHROMA_420:
     xxBuildPicHashMap<CHROMA_420>(pic);
     break;
+#endif
   case CHROMA_422:
     xxBuildPicHashMap<CHROMA_422>(pic);
     break;
@@ -267,8 +275,90 @@ void IbcHashMap::rebuildPicHashMap(const PelUnitBuf& pic)
   }
 }
 
+#if JVET_AA0070_RRIBC
+void IbcHashMap::buildFlipHashTable(PredictionUnit &pu, unsigned int pos2HashCurPU[MAX_CU_SIZE][MAX_CU_SIZE], const int rribcFlipType)
+{
+  if (rribcFlipType == 0)
+  {
+    return;
+  }
+  for (int i = 0; i < MAX_CU_SIZE; i++)
+  {
+    std::fill_n(pos2HashCurPU[i], MAX_CU_SIZE, 0x1FF);
+  }
+  PelStorage m_tmpStorageCU;
+  m_tmpStorageCU.create(UnitArea(pu.chromaFormat, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE)));
+  const UnitArea tmpArea(pu.chromaFormat, Area(0, 0, pu.cs->getOrgBuf(pu).Y().width, pu.cs->getOrgBuf(pu).Y().height));
+  PelUnitBuf     flipCU = m_tmpStorageCU.getBuf(tmpArea);
+  if (CS::isDualITree(*pu.cs))
+  {
+    flipCU.Y().copyFrom(pu.cs->getOrgBuf(pu).Y());
+  }
+  else
+  {
+    flipCU.copyFrom(pu.cs->getOrgBuf(pu));
+  }
+  flipCU.Y().flipSignal(rribcFlipType == 1);
+  if (pu.chromaFormat != CHROMA_400 && !(CS::isDualITree(*pu.cs)))
+  {
+    flipCU.Cb().flipSignal(rribcFlipType == 1);
+    flipCU.Cr().flipSignal(rribcFlipType == 1);
+  }
+
+  const int  chromaScalingX     = getChannelTypeScaleX(CHANNEL_TYPE_CHROMA, pu.chromaFormat);
+  const int  chromaScalingY     = getChannelTypeScaleY(CHANNEL_TYPE_CHROMA, pu.chromaFormat);
+  const int  chromaMinBlkWidth  = MIN_PU_SIZE >> chromaScalingX;
+  const int  chromaMinBlkHeight = MIN_PU_SIZE >> chromaScalingY;
+  const Pel *pelY               = NULL;
+  const Pel *pelCb              = NULL;
+  const Pel *pelCr              = NULL;
+
+  Position pos;
+  for (pos.y = 0; pos.y < flipCU.Y().height; pos.y += MIN_PU_SIZE)
+  {
+    // row pointer
+    pelY = flipCU.Y().bufAt(0, pos.y);
+    if (pu.chromaFormat != CHROMA_400 && !(CS::isDualITree(*pu.cs)))
+    {
+      int chromaY = pos.y >> chromaScalingY;
+      pelCb       = flipCU.Cb().bufAt(0, chromaY);
+      pelCr       = flipCU.Cr().bufAt(0, chromaY);
+    }
+
+    for (pos.x = 0; pos.x < flipCU.Y().width; pos.x += MIN_PU_SIZE)
+    {
+      // 0x1FF is just an initial value
+      unsigned int hashValue = 0x1FF;
+
+      // luma part
+      hashValue = xxCalcBlockHash(&pelY[pos.x], flipCU.Y().stride, MIN_PU_SIZE, MIN_PU_SIZE, hashValue);
+
+      // chroma part
+      if (pu.chromaFormat != CHROMA_400 && !(CS::isDualITree(*pu.cs)))
+      {
+        int chromaX = pos.x >> chromaScalingX;
+        hashValue = xxCalcBlockHash(&pelCb[chromaX], flipCU.Cb().stride, chromaMinBlkWidth, chromaMinBlkHeight, hashValue);
+        hashValue = xxCalcBlockHash(&pelCr[chromaX], flipCU.Cr().stride, chromaMinBlkWidth, chromaMinBlkHeight, hashValue);
+      }
+
+      pos2HashCurPU[pos.y][pos.x] = hashValue;
+    }
+  }
+
+  m_tmpStorageCU.destroy();
+}
+
+bool IbcHashMap::ibcHashMatch(PredictionUnit &pu, const Area &lumaArea, std::vector<Position> &cand,
+                              const CodingStructure &cs, const int maxCand, const int searchRange4SmallBlk,
+                              const int rribcFlipType)
+{
+  unsigned int pos2HashCurPU[MAX_CU_SIZE][MAX_CU_SIZE];
+
+  buildFlipHashTable(pu, pos2HashCurPU, rribcFlipType);
+#else
 bool IbcHashMap::ibcHashMatch(const Area& lumaArea, std::vector<Position>& cand, const CodingStructure& cs, const int maxCand, const int searchRange4SmallBlk)
 {
+#endif
   cand.clear();
 
   // find the block with least candidates
@@ -280,6 +370,12 @@ bool IbcHashMap::ibcHashMatch(const Area& lumaArea, std::vector<Position>& cand,
     for (SizeType x = 0; x < lumaArea.width && minSize > 1; x += MIN_PU_SIZE)
     {
       unsigned int hash = m_pos2Hash[lumaArea.pos().y + y][lumaArea.pos().x + x];
+#if JVET_AA0070_RRIBC
+      if (rribcFlipType)
+      {
+        hash = pos2HashCurPU[y][x];
+      }
+#endif
       if (m_hash2Pos[hash].size() < minSize)
       {
         minSize = m_hash2Pos[hash].size();
@@ -291,7 +387,7 @@ bool IbcHashMap::ibcHashMatch(const Area& lumaArea, std::vector<Position>& cand,
 
   if (m_hash2Pos[targetHashOneBlock].size() > 1)
   {
-    std::vector<Position>& candOneBlock = m_hash2Pos[targetHashOneBlock];
+    std::vector<Position> &candOneBlock = m_hash2Pos[targetHashOneBlock];
 
     // check whether whole block match
     for (std::vector<Position>::iterator refBlockPos = candOneBlock.begin(); refBlockPos != candOneBlock.end(); refBlockPos++)
@@ -310,6 +406,13 @@ bool IbcHashMap::ibcHashMatch(const Area& lumaArea, std::vector<Position>& cand,
           for (SizeType x = 0; x < lumaArea.width && wholeBlockMatch; x += MIN_PU_SIZE)
           {
             // whether the reference block and current block has the same hash
+#if JVET_AA0070_RRIBC
+            if (rribcFlipType)
+            {
+              wholeBlockMatch &= (pos2HashCurPU[y][x] == m_pos2Hash[topLeft.y + y][topLeft.x + x]);
+            }
+            else
+#endif
             wholeBlockMatch &= (m_pos2Hash[lumaArea.pos().y + y][lumaArea.pos().x + x] == m_pos2Hash[topLeft.y + y][topLeft.x + x]);
           }
         }
diff --git a/source/Lib/CommonLib/IbcHashMap.h b/source/Lib/CommonLib/IbcHashMap.h
index 84d575418685dd63d1f90c3b458a11e1bcf3b211..3639b7ea18786cfeaa3798917a458039ed57b8ca 100644
--- a/source/Lib/CommonLib/IbcHashMap.h
+++ b/source/Lib/CommonLib/IbcHashMap.h
@@ -78,8 +78,14 @@ public:
 
   void    init(const int picWidth, const int picHeight);
   void    destroy();
+#if JVET_AA0070_RRIBC
+  void rebuildPicHashMap(const PelUnitBuf &pic, bool isDualTree);
+  void buildFlipHashTable(PredictionUnit &pu, unsigned int pos2HashCurPU[MAX_CU_SIZE][MAX_CU_SIZE], const int rribcFlipType);
+  bool ibcHashMatch(PredictionUnit &pu, const Area &lumaArea, std::vector<Position> &cand, const CodingStructure &cs, const int maxCand, const int searchRange4SmallBlk, const int rribcFlipType);
+#else
   void    rebuildPicHashMap(const PelUnitBuf& pic);
   bool    ibcHashMatch(const Area& lumaArea, std::vector<Position>& cand, const CodingStructure& cs, const int maxCand, const int searchRange4SmallBlk);
+#endif
   int     getHashHitRatio(const Area& lumaArea);
 
   int     calHashBlkMatchPerc(const Area& lumaArea);
diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp
index 01b504a9e7110e47c78de340ed29771aeae06188..8b609952ba9e866dfe6c31658d86b6d171fc6923 100644
--- a/source/Lib/CommonLib/InterPrediction.cpp
+++ b/source/Lib/CommonLib/InterPrediction.cpp
@@ -5903,6 +5903,109 @@ void InterPrediction::xProcessDMVR(PredictionUnit& pu, PelUnitBuf &pcYuvDst, con
 #endif
 }
 
+#if JVET_AA0061_IBC_MBVD
+void  InterPrediction::sortIbcMergeMbvdCandidates(PredictionUnit &pu, MergeCtx& mrgCtx, uint32_t * ibcMbvdLUT,uint32_t * ibcMbvdValidNum, int ibcMbvdIdx)
+{
+
+  const int tempNum = (const int) (std::min<int>(IBC_MBVD_BASE_NUM, mrgCtx.numValidMergeCand) * IBC_MBVD_MAX_REFINE_NUM);
+  const int groupSize = std::min<int>(tempNum, ADAPTIVE_SUB_GROUP_SIZE_IBC_MBVD);
+
+  Distortion candCostList[IBC_MBVD_BASE_NUM* IBC_MBVD_MAX_REFINE_NUM];
+
+  for (uint32_t i = 0; i < tempNum; i++)
+  {
+    ibcMbvdLUT[i] = i;
+    candCostList[i] = MAX_UINT;
+  }
+  Distortion uiCost;
+  DistParam cDistParam;
+  cDistParam.applyWeight = false;
+  int nWidth = pu.lumaSize().width;
+  int nHeight = pu.lumaSize().height;
+  if (!xAMLIBCGetCurBlkTemplate(pu, nWidth, nHeight))
+  {
+    return;
+  }
+
+  int startMMVDIdx = 0;
+  int endMMVDIdx = tempNum;
+  if(ibcMbvdIdx!= -1)
+  {
+    uint32_t gpId = ibcMbvdIdx/groupSize;
+    startMMVDIdx = gpId * groupSize;
+    endMMVDIdx = (gpId+1) * groupSize;
+  }
+
+  int encGrpSize = IBC_MBVD_SIZE_ENC;
+  int baseIdx = 0;
+  const int cuPelX = pu.Y().x;
+  const int cuPelY = pu.Y().y;
+  int roiWidth = pu.lwidth();
+  int roiHeight = pu.lheight();
+  const int picWidth = pu.cs->slice->getPPS()->getPicWidthInLumaSamples();
+  const int picHeight = pu.cs->slice->getPPS()->getPicHeightInLumaSamples();
+  const unsigned int  lcuWidth = pu.cs->slice->getSPS()->getMaxCUWidth();
+  for (int mmvdMergeCand = startMMVDIdx; mmvdMergeCand < endMMVDIdx; mmvdMergeCand++)
+  {
+    bool mbvdCandMisAlign = mrgCtx.setIbcMbvdMergeCandiInfo(pu, mmvdMergeCand, mmvdMergeCand);
+    if (mbvdCandMisAlign)
+    {
+      continue;
+    }
+    int xPred = pu.bv.getHor();
+    int yPred = pu.bv.getVer();
+
+    if (!PU::searchBv(pu, cuPelX, cuPelY, roiWidth, roiHeight, picWidth, picHeight, xPred, yPred, lcuWidth)) // not valid bv derived
+    {
+      continue;
+    }
+    baseIdx = mmvdMergeCand / IBC_MBVD_MAX_REFINE_NUM;
+    ibcMbvdValidNum[baseIdx]++;
+    uiCost = 0;
+
+    PelUnitBuf pcBufPredRefTop = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAMLTemplate[0][0], nWidth, AML_MERGE_TEMPLATE_SIZE)));
+    PelUnitBuf pcBufPredCurTop = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvCurAMLTemplate[0][0], nWidth, AML_MERGE_TEMPLATE_SIZE)));
+    PelUnitBuf pcBufPredRefLeft = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvRefAMLTemplate[1][0], AML_MERGE_TEMPLATE_SIZE, nHeight)));
+    PelUnitBuf pcBufPredCurLeft = (PelUnitBuf(pu.chromaFormat, PelBuf(m_acYuvCurAMLTemplate[1][0], AML_MERGE_TEMPLATE_SIZE, nHeight)));
+
+    getIBCAMLRefTemplate(pu, nWidth, nHeight);
+
+    if (m_bAMLTemplateAvailabe[0])
+    {
+      m_pcRdCost->setDistParam(cDistParam, pcBufPredCurTop.Y(), pcBufPredRefTop.Y(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, false);
+
+      uiCost += cDistParam.distFunc(cDistParam);
+    }
+
+    if (m_bAMLTemplateAvailabe[1])
+    {
+      m_pcRdCost->setDistParam(cDistParam, pcBufPredCurLeft.Y(), pcBufPredRefLeft.Y(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, false);
+
+      uiCost += cDistParam.distFunc(cDistParam);
+    }
+    // update part
+    uint32_t i;
+    uint32_t shift = 0;
+    uint32_t gpIdx = mmvdMergeCand/groupSize;
+    uint32_t endIdx = gpIdx * groupSize + encGrpSize;
+    while (shift < encGrpSize && uiCost < candCostList[endIdx - 1 - shift])
+    {
+      shift++;
+    }
+    if (shift != 0)
+    {
+      for (i = 1; i < shift; i++)
+      {
+        ibcMbvdLUT[endIdx - i] = ibcMbvdLUT[endIdx - 1 - i];
+        candCostList[endIdx - i] = candCostList[endIdx - 1 - i];
+      }
+      ibcMbvdLUT[endIdx - shift] = mmvdMergeCand;
+      candCostList[endIdx - shift] = uiCost;
+    }
+  }
+}
+#endif
+
 #if JVET_J0090_MEMORY_BANDWITH_MEASURE
 void InterPrediction::cacheAssign( CacheModel *cache )
 {
@@ -8686,6 +8789,9 @@ void  InterPrediction::updateIBCCandInfo(PredictionUnit &pu, MergeCtx& mrgCtx, u
     mrgCtxTmp.useAltHpelIf[ui] = false;
 #if INTER_LIC
     mrgCtxTmp.LICFlags[ui] = false;
+#endif
+#if JVET_AA0070_RRIBC
+    mrgCtxTmp.rribcFlipTypes[ui] = 0;
 #endif
   }
   for (uint32_t uiMergeCand = ((mrgCandIdx < 0) ? 0 : (mrgCandIdx / ADAPTIVE_IBC_SUB_GROUP_SIZE)*ADAPTIVE_IBC_SUB_GROUP_SIZE); uiMergeCand < (((mrgCandIdx < 0) || ((mrgCandIdx / ADAPTIVE_IBC_SUB_GROUP_SIZE + 1)*ADAPTIVE_IBC_SUB_GROUP_SIZE > mrgCtx.numValidMergeCand)) ? mrgCtx.numValidMergeCand : ((mrgCandIdx / ADAPTIVE_IBC_SUB_GROUP_SIZE + 1)*ADAPTIVE_IBC_SUB_GROUP_SIZE)); ++uiMergeCand)
@@ -8708,6 +8814,9 @@ void  InterPrediction::updateIBCCandInfo(PredictionUnit &pu, MergeCtx& mrgCtx, u
     mrgCtxTmp.useAltHpelIf[uiMergeCand] = mrgCtx.useAltHpelIf[uiMergeCand];
 #if INTER_LIC 
     mrgCtxTmp.LICFlags[uiMergeCand] = mrgCtx.LICFlags[uiMergeCand];
+#endif
+#if JVET_AA0070_RRIBC
+    mrgCtxTmp.rribcFlipTypes[uiMergeCand] = mrgCtx.rribcFlipTypes[uiMergeCand];
 #endif
   }
   //update
@@ -8731,6 +8840,9 @@ void  InterPrediction::updateIBCCandInfo(PredictionUnit &pu, MergeCtx& mrgCtx, u
     mrgCtx.useAltHpelIf[uiMergeCand] = mrgCtxTmp.useAltHpelIf[RdCandList[uiMergeCand / ADAPTIVE_IBC_SUB_GROUP_SIZE][uiMergeCand%ADAPTIVE_IBC_SUB_GROUP_SIZE]];
 #if INTER_LIC
     mrgCtx.LICFlags[uiMergeCand] = mrgCtxTmp.LICFlags[RdCandList[uiMergeCand / ADAPTIVE_IBC_SUB_GROUP_SIZE][uiMergeCand%ADAPTIVE_IBC_SUB_GROUP_SIZE]];
+#endif
+#if JVET_AA0070_RRIBC
+    mrgCtx.rribcFlipTypes[uiMergeCand] = mrgCtxTmp.rribcFlipTypes[RdCandList[uiMergeCand / ADAPTIVE_IBC_SUB_GROUP_SIZE][uiMergeCand % ADAPTIVE_IBC_SUB_GROUP_SIZE]];
 #endif
   }
 }
@@ -8758,12 +8870,6 @@ bool InterPrediction::xAMLIBCGetCurBlkTemplate(PredictionUnit& pu, int nCurBlkWi
       for (int l = 0; l < AML_MERGE_TEMPLATE_SIZE; l++)
       {
         int recVal = rec[k + l * recBuf.stride];
-
-        //if (m_pcReshape->getSliceReshaperInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())
-        //{
-        //  recVal = invLUT[recVal];
-        //}
-
         pcY[k + l * nCurBlkWidth] = recVal;
       }
     }
@@ -8779,12 +8885,6 @@ bool InterPrediction::xAMLIBCGetCurBlkTemplate(PredictionUnit& pu, int nCurBlkWi
       for (int l = 0; l < AML_MERGE_TEMPLATE_SIZE; l++)
       {
         int recVal = rec[recBuf.stride * k + l];
-
-        //if (m_pcReshape->getSliceReshaperInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())
-        //{
-        //  recVal = invLUT[recVal];
-        //}
-
         pcY[AML_MERGE_TEMPLATE_SIZE * k + l] = recVal;
       }
     }
@@ -8805,11 +8905,27 @@ void InterPrediction::getIBCAMLRefTemplate(PredictionUnit &pu, int nCurBlkWidth,
   if (m_bAMLTemplateAvailabe[0])
   {
     Mv mvTop(0, -AML_MERGE_TEMPLATE_SIZE);
+#if JVET_AA0070_RRIBC
+    if (pu.cu->rribcFlipType == 2)
+    {
+      mvTop.setVer(nCurBlkHeight);
+    }
+#endif
     mvTop += mvCurr;
 
     MotionInfo miTop;
     miTop.mv[0] = Mv(mvTop.hor <<horShift , mvTop.ver<< verShift);
     miTop.refIdx[0] = MAX_NUM_REF;
+#if JVET_AA0070_RRIBC
+    if (pu.cu->rribcFlipType == 2)
+    {
+      if (!PU::checkIsIBCCandidateValid(pu, miTop, true, true))
+      {
+        mvTop.setVer(mvCurr.getVer() + nCurBlkHeight - AML_MERGE_TEMPLATE_SIZE);
+      }
+    }
+    else
+#endif
     if (!PU::checkIsIBCCandidateValid(pu, miTop))
     {
       mvTop = mvCurr;
@@ -8821,13 +8937,23 @@ void InterPrediction::getIBCAMLRefTemplate(PredictionUnit &pu, int nCurBlkWidth,
     {
       for (int l = 0; l < AML_MERGE_TEMPLATE_SIZE; l++)
       {
+#if JVET_AA0070_RRIBC
+        int recVal;
+        if (pu.cu->rribcFlipType == 0)
+        {
+           recVal = rec[k + l * recBuf.stride];
+        }
+        else if (pu.cu->rribcFlipType == 1)
+        {
+          recVal = rec[nCurBlkWidth - 1 - k + l * recBuf.stride];
+        }
+        else
+        {
+          recVal = rec[k + (AML_MERGE_TEMPLATE_SIZE - 1 - l) * recBuf.stride];
+        }
+#else
         int recVal = rec[k + l * recBuf.stride];
-
-        //if (m_pcReshape->getSliceReshaperInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())
-        //{
-        //  recVal = invLUT[recVal];
-        //}
-
+#endif
         pcY[k + l * nCurBlkWidth] = recVal;
       }
     }
@@ -8836,11 +8962,27 @@ void InterPrediction::getIBCAMLRefTemplate(PredictionUnit &pu, int nCurBlkWidth,
   if (m_bAMLTemplateAvailabe[1])
   {
     Mv mvLeft(-AML_MERGE_TEMPLATE_SIZE, 0);
+#if JVET_AA0070_RRIBC
+    if (pu.cu->rribcFlipType == 1)
+    {
+      mvLeft.setHor(nCurBlkWidth);
+    }
+#endif
     mvLeft += mvCurr;
 
     MotionInfo miLeft;
     miLeft.mv[0] = Mv(mvLeft.hor <<horShift , mvLeft.ver<< verShift);
     miLeft.refIdx[0] = MAX_NUM_REF;
+#if JVET_AA0070_RRIBC
+    if (pu.cu->rribcFlipType == 1)
+    {
+      if (!PU::checkIsIBCCandidateValid(pu, miLeft, true, false))
+      {
+         mvLeft.setHor(mvCurr.getHor() + nCurBlkWidth - AML_MERGE_TEMPLATE_SIZE);
+      }
+    }
+    else
+#endif
     if (!PU::checkIsIBCCandidateValid(pu, miLeft))
     {
       mvLeft = mvCurr;
@@ -8852,19 +8994,30 @@ void InterPrediction::getIBCAMLRefTemplate(PredictionUnit &pu, int nCurBlkWidth,
     {
       for (int l = 0; l < AML_MERGE_TEMPLATE_SIZE; l++)
       {
+#if JVET_AA0070_RRIBC
+        int recVal;
+        if (pu.cu->rribcFlipType == 0)
+        {
+          recVal = rec[recBuf.stride * k + l];
+        }
+        else if (pu.cu->rribcFlipType == 1) 
+        {
+          recVal = rec[recBuf.stride * k + AML_MERGE_TEMPLATE_SIZE - 1 - l];
+        }
+        else
+        {
+          recVal = rec[recBuf.stride * (nCurBlkHeight - 1 - k) + l];
+        }
+#else
         int recVal = rec[recBuf.stride * k + l];
-
-        //if (m_pcReshape->getSliceReshaperInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())
-        //{
-        //  recVal = invLUT[recVal];
-        //}
-
+#endif
         pcY[AML_MERGE_TEMPLATE_SIZE * k + l] = recVal;
       }
     }
   }
 }
 #endif
+
 #if JVET_Z0075_IBC_HMVP_ENLARGE
 void  InterPrediction::adjustIBCMergeCandidates(PredictionUnit &pu, MergeCtx& mrgCtx,uint32_t startPos,uint32_t endPos)
 {
@@ -8948,6 +9101,9 @@ void  InterPrediction::updateIBCCandInfo(PredictionUnit &pu, MergeCtx& mrgCtx, u
     mrgCtxTmp.useAltHpelIf[ui] = false;
 #if INTER_LIC
     mrgCtxTmp.LICFlags[ui] = false;
+#endif
+#if JVET_AA0070_RRIBC
+    mrgCtxTmp.rribcFlipTypes[ui] = 0;
 #endif
   }
   for (uint32_t uiMergeCand = startPos; uiMergeCand < endPos; ++uiMergeCand)
@@ -8964,6 +9120,9 @@ void  InterPrediction::updateIBCCandInfo(PredictionUnit &pu, MergeCtx& mrgCtx, u
     mrgCtxTmp.useAltHpelIf[uiMergeCand] = mrgCtx.useAltHpelIf[uiMergeCand];
 #if INTER_LIC 
     mrgCtxTmp.LICFlags[uiMergeCand] = mrgCtx.LICFlags[uiMergeCand];
+#endif
+#if JVET_AA0070_RRIBC
+    mrgCtxTmp.rribcFlipTypes[uiMergeCand] = mrgCtx.rribcFlipTypes[uiMergeCand];
 #endif
   }
   //update
@@ -8981,6 +9140,9 @@ void  InterPrediction::updateIBCCandInfo(PredictionUnit &pu, MergeCtx& mrgCtx, u
     mrgCtx.useAltHpelIf[uiMergeCand] = mrgCtxTmp.useAltHpelIf[RdCandList[uiMergeCand -startPos]];
 #if INTER_LIC
     mrgCtx.LICFlags[uiMergeCand] = mrgCtxTmp.LICFlags[RdCandList[uiMergeCand -startPos]];
+#endif
+#if JVET_AA0070_RRIBC
+    mrgCtx.rribcFlipTypes[uiMergeCand] = mrgCtxTmp.rribcFlipTypes[RdCandList[uiMergeCand -startPos]];
 #endif
   }
 }
diff --git a/source/Lib/CommonLib/InterPrediction.h b/source/Lib/CommonLib/InterPrediction.h
index aa0b7f12a8d08f2ffce4ca0989ef99712ba45e23..5a2cb82be53edfc2aab433ac48cacb21717583be 100644
--- a/source/Lib/CommonLib/InterPrediction.h
+++ b/source/Lib/CommonLib/InterPrediction.h
@@ -509,6 +509,9 @@ public:
   uint64_t xDMVRCost(int bitDepth, Pel* pRef, uint32_t refStride, const Pel* pOrg, uint32_t orgStride, int width, int height);
   void xinitMC(PredictionUnit& pu, const ClpRngs &clpRngs);
   void xProcessDMVR(PredictionUnit& pu, PelUnitBuf &pcYuvDst, const ClpRngs &clpRngs, const bool bioApplied );
+#if JVET_AA0061_IBC_MBVD
+  void sortIbcMergeMbvdCandidates(PredictionUnit &pu, MergeCtx& mrgCtx, uint32_t * ibcMbvdLUT, uint32_t * ibcMbvdValidNum, int ibcMbvdIdx= -1);
+#endif
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
 #if JVET_Z0054_BLK_REF_PIC_REORDER
   void deriveMVDcand(const PredictionUnit& pu, RefPicList eRefPicList, std::vector<Mv>& cMvdCandList);
diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp
index 181f18601588648479fd25005766efc33e23e45a..b276406c64e62ed303edd0fb681daa27957d5d1e 100644
--- a/source/Lib/CommonLib/IntraPrediction.cpp
+++ b/source/Lib/CommonLib/IntraPrediction.cpp
@@ -276,7 +276,6 @@ void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepth
 #endif
 #if JVET_V0130_INTRA_TMP
   unsigned int blkSize;
-
   if( m_pppTarPatch == NULL )
   {
     m_pppTarPatch = new Pel * *[USE_MORE_BLOCKSIZE_DEPTH_MAX];
@@ -6785,6 +6784,7 @@ void IntraPrediction::candidateSearchIntra( CodingUnit* pcCU, unsigned int uiBlk
   unsigned int uiPatchWidth = uiBlkWidth + TMP_TEMPLATE_SIZE;
   unsigned int uiPatchHeight = uiBlkHeight + TMP_TEMPLATE_SIZE;
   unsigned int uiTarDepth = floorLog2( std::max( uiBlkWidth, uiBlkHeight ) ) - 2;
+
   Pel** tarPatch = getTargetPatch( uiTarDepth );
   //Initialize the library for saving the best candidates
   m_tempLibFast.initTemplateDiff( uiPatchWidth, uiPatchHeight, uiBlkWidth, uiBlkHeight, channelBitDepth );
diff --git a/source/Lib/CommonLib/MotionInfo.h b/source/Lib/CommonLib/MotionInfo.h
index 2c753477ce012922760d911ac8dba74cb8fa2844..ab4595ae0de29bc8c4ea714c03f2cc856c055753 100644
--- a/source/Lib/CommonLib/MotionInfo.h
+++ b/source/Lib/CommonLib/MotionInfo.h
@@ -176,6 +176,10 @@ struct MotionInfo
 #if INTER_LIC
   bool     usesLIC;
 #endif
+#if JVET_AA0070_RRIBC
+  int  rribcFlipType;
+  Position centerPos;
+#endif
 #if MULTI_HYP_PRED  
   MultiHypVec addHypData;
 #endif
diff --git a/source/Lib/CommonLib/RdCost.cpp b/source/Lib/CommonLib/RdCost.cpp
index c1187bbbc6aab180997a880de72470e697e7ba05..5f23a3ff629272d58e599a061fe27037895bb9c5 100644
--- a/source/Lib/CommonLib/RdCost.cpp
+++ b/source/Lib/CommonLib/RdCost.cpp
@@ -58,6 +58,26 @@ RdCost::RdCost()
 RdCost::~RdCost()
 {
 }
+#if JVET_AA0070_RRIBC
+void RdCost::setPredictors(Mv pcMv[3][2])
+  {
+    for (int j = 0; j < 3; j++)
+    {
+      for (int i = 0; i < 2; i++)
+      {
+        m_bvPredictors[j][i] = pcMv[j][i];
+      }
+    }
+  }
+#else
+void RdCost::setPredictors(Mv* pcMv)
+  {
+    for (int i = 0; i < 2; i++)
+    {
+      m_bvPredictors[i] = pcMv[i];
+    }
+  }
+#endif
 
 #if WCG_EXT
 double RdCost::calcRdCost( uint64_t fracBits, Distortion distortion, bool useUnadjustedLambda )
diff --git a/source/Lib/CommonLib/RdCost.h b/source/Lib/CommonLib/RdCost.h
index 7d19adc09664d3847eb4bd0c4e64666131090b17..d70e715b22ba82dcb61fe8c884de2b60e8dfaa79 100644
--- a/source/Lib/CommonLib/RdCost.h
+++ b/source/Lib/CommonLib/RdCost.h
@@ -155,14 +155,18 @@ private:
 
   // for motion cost
   Mv                      m_mvPredictor;
+#if JVET_AA0070_RRIBC
+  Mv                      m_bvPredictors[3][2];
+#else
   Mv                      m_bvPredictors[2];
+#endif
   double                  m_motionLambda;
   int                     m_iCostScale;
-
   double                  m_dCost; // for ibc
 #if JVET_Z0131_IBC_BVD_BINARIZATION
   EstBvdBitsStruct        m_cBvdBitCosts;
 #endif
+
 public:
   RdCost();
   virtual ~RdCost();
@@ -221,17 +225,234 @@ public:
   // for ibc
   void           getMotionCost(int add) { m_dCost = m_dLambdaMotionSAD + add; }
 
-  void    setPredictors(Mv* pcMv)
+
+#if JVET_AA0070_RRIBC
+  void setPredictors(Mv pcMv[3][2]);
+#if JVET_Z0131_IBC_BVD_BINARIZATION
+  EstBvdBitsStruct *getBvdBitCosts() { return &m_cBvdBitCosts; }
+#if JVET_Z0084_IBC_TM && IBC_TM_AMVP
+  inline Distortion getBvCostMultiplePreds(int x, int y, bool useIMV, int rribcFlipType, uint8_t *bvImvResBest = NULL, int *bvpIdxBest = NULL, bool flag = false, AMVPInfo *amvpInfo4Pel = NULL)
+#else
+  inline Distortion getBvCostMultiplePreds(int x, int y, bool useIMV, int rribcFlipType, uint8_t *bvImvResBest = NULL, int *bvpIdxBest = NULL)
+#endif
   {
-    for (int i = 0; i<2; i++)
+    uint32_t b0 = (rribcFlipType == 1) ? 0 : xGetExpGolombNumberOfBitsIBCV(y - m_bvPredictors[rribcFlipType][0].getVer());
+    b0 += (rribcFlipType == 2) ? 0 : xGetExpGolombNumberOfBitsIBCH(x - m_bvPredictors[rribcFlipType][0].getHor());
+    b0 += m_cBvdBitCosts.bitsIdx[0];
+
+    uint32_t b1 = (rribcFlipType == 1) ? 0 : xGetExpGolombNumberOfBitsIBCV(y - m_bvPredictors[rribcFlipType][1].getVer());
+    b1 += (rribcFlipType == 2) ? 0 : xGetExpGolombNumberOfBitsIBCH(x - m_bvPredictors[rribcFlipType][1].getHor());
+    b1 += m_cBvdBitCosts.bitsIdx[1];
+
+    if (useIMV)
+    {
+      if (rribcFlipType == 0)
+      {
+        b0 += (x != m_bvPredictors[rribcFlipType][0].getHor() || y != m_bvPredictors[rribcFlipType][0].getVer()) ? m_cBvdBitCosts.bitsImv[0] : 0;
+        b1 += (x != m_bvPredictors[rribcFlipType][1].getHor() || y != m_bvPredictors[rribcFlipType][1].getVer()) ? m_cBvdBitCosts.bitsImv[0] : 0;
+      }
+      else if (rribcFlipType == 1)
+      {
+        b0 += (x != m_bvPredictors[rribcFlipType][0].getHor()) ? m_cBvdBitCosts.bitsImv[0] : 0;
+        b1 += (x != m_bvPredictors[rribcFlipType][1].getHor()) ? m_cBvdBitCosts.bitsImv[0] : 0;
+      }
+      else
+      {
+        b0 += (y != m_bvPredictors[rribcFlipType][0].getVer()) ? m_cBvdBitCosts.bitsImv[0] : 0;
+        b1 += (y != m_bvPredictors[rribcFlipType][1].getVer()) ? m_cBvdBitCosts.bitsImv[0] : 0;
+      }
+    }
+    uint32_t bBest    = (b1 < b0) ? b1 : b0;
+    int      bBestIdx = (b1 < b0) ? 1 : 0;
+    uint8_t  bestRes;
+    if (rribcFlipType == 0)
     {
-      m_bvPredictors[i] = pcMv[i];
+      bestRes = (useIMV && (x != m_bvPredictors[rribcFlipType][bBestIdx].getHor() || y != m_bvPredictors[rribcFlipType][bBestIdx].getVer())) ? 1 : 0;
+    }
+    else if (rribcFlipType == 1)
+    {
+      bestRes = (useIMV && (x != m_bvPredictors[rribcFlipType][bBestIdx].getHor())) ? 1 : 0;
+    }
+    else
+    {
+      bestRes = (useIMV && (y != m_bvPredictors[rribcFlipType][bBestIdx].getVer())) ? 1 : 0;
+    }
+
+    if (bvImvResBest)
+    {
+      *bvImvResBest = bestRes;
+      *bvpIdxBest   = bBestIdx;
+    }
+
+    if (bestRes && x % 4 == 0 && y % 4 == 0)
+    {
+      Mv cMv(x >> 2, y >> 2);
+
+#if JVET_Z0084_IBC_TM && IBC_TM_AMVP
+      Mv tmpBv0;
+      Mv tmpBv1;
+      if (flag)
+      {
+        tmpBv0 = amvpInfo4Pel->mvCand[0];
+        tmpBv1 = amvpInfo4Pel->mvCand[1];
+        tmpBv0.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_4PEL);
+        tmpBv1.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_4PEL);
+      }
+      else
+      {
+        tmpBv0 = m_bvPredictors[rribcFlipType][0];
+        tmpBv1 = m_bvPredictors[rribcFlipType][1];
+        tmpBv0.changePrecision(MV_PRECISION_INT, MV_PRECISION_4PEL);
+        tmpBv1.changePrecision(MV_PRECISION_INT, MV_PRECISION_4PEL);
+      }
+#else
+      Mv tmpBv0 = m_bvPredictors[rribcFlipType][0];
+      Mv tmpBv1 = m_bvPredictors[rribcFlipType][1];
+      tmpBv0.changePrecision(MV_PRECISION_INT, MV_PRECISION_4PEL);
+      tmpBv1.changePrecision(MV_PRECISION_INT, MV_PRECISION_4PEL);
+#endif
+
+      uint32_t bQ0, bQ1;
+      if (rribcFlipType == 0)
+      {
+        bQ0 = (cMv == tmpBv0) ? std::numeric_limits<uint32_t>::max() : (xGetExpGolombNumberOfBitsIBCH(cMv.getHor() - tmpBv0.getHor()) + xGetExpGolombNumberOfBitsIBCV(cMv.getVer() - tmpBv0.getVer()) + m_cBvdBitCosts.bitsIdx[0]);
+        bQ1 = (cMv == tmpBv1) ? std::numeric_limits<uint32_t>::max() : (xGetExpGolombNumberOfBitsIBCH(cMv.getHor() - tmpBv1.getHor()) + xGetExpGolombNumberOfBitsIBCV(cMv.getVer() - tmpBv1.getVer()) + m_cBvdBitCosts.bitsIdx[1]);
+      }
+      else if (rribcFlipType == 1)
+      {
+        bQ0 = (cMv.getHor() == tmpBv0.getHor()) ? std::numeric_limits<uint32_t>::max() : (xGetExpGolombNumberOfBitsIBCH(cMv.getHor() - tmpBv0.getHor()) + m_cBvdBitCosts.bitsIdx[0]);
+        bQ1 = (cMv.getHor() == tmpBv1.getHor()) ? std::numeric_limits<uint32_t>::max() : (xGetExpGolombNumberOfBitsIBCH(cMv.getHor() - tmpBv1.getHor()) + m_cBvdBitCosts.bitsIdx[1]);
+      }
+      else
+      {
+        bQ0 = (cMv.getVer() == tmpBv0.getVer()) ? std::numeric_limits<uint32_t>::max() : (xGetExpGolombNumberOfBitsIBCV(cMv.getVer() - tmpBv0.getVer()) + m_cBvdBitCosts.bitsIdx[0]);
+        bQ1 = (cMv.getVer() == tmpBv1.getVer()) ? std::numeric_limits<uint32_t>::max() : (xGetExpGolombNumberOfBitsIBCV(cMv.getVer() - tmpBv1.getVer()) + m_cBvdBitCosts.bitsIdx[1]);
+      }
+
+      uint32_t bQBest = (bQ1 < bQ0) ? bQ1 : bQ0;
+      bQBest += (bQBest < std::numeric_limits<uint32_t>::max()) ? m_cBvdBitCosts.bitsImv[1] : 0;
+
+      if (bQBest < bBest)
+      {
+        if (bvImvResBest)
+        {
+          *bvImvResBest = 2;
+          *bvpIdxBest   = (bQ1 < bQ0) ? 1 : 0;
+        }
+        bBest = bQBest;
+      }
     }
+    return Distortion(m_dCost * bBest) >> SCALE_BITS;
+  }
+#else
+  inline Distortion getBvCostMultiplePreds(int x, int y, bool useIMV, int rribcFlipType)
+  {
+    return Distortion(m_dCost * getBitsMultiplePreds(x, y, useIMV, rribcFlipType));
   }
+  unsigned int getBitsMultiplePreds(int x, int y, bool useIMV, int rribcFlipType)
+  {
+    int rmvH[2];
+    int rmvV[2];
+    rmvH[0] = x - m_bvPredictors[rribcFlipType][0].getHor();
+    rmvH[1] = x - m_bvPredictors[rribcFlipType][1].getHor();
+
+    rmvV[0] = y - m_bvPredictors[rribcFlipType][0].getVer();
+    rmvV[1] = y - m_bvPredictors[rribcFlipType][1].getVer();
+
+    int absCand[2];
+    absCand[0] = abs(rmvH[0]) + abs(rmvV[0]);
+    absCand[1] = abs(rmvH[1]) + abs(rmvV[1]);
+
+    int rmvHQP[2];
+    int rmvVQP[2];
+    if (x % 4 == 0 && y % 4 == 0 && useIMV)
+    {
+      int imvShift = 2;
+      int offset   = 1 << (imvShift - 1);
+
+      rmvHQP[0] = (x >> 2) - ((m_bvPredictors[rribcFlipType][0].getHor() + offset) >> 2);
+      rmvHQP[1] = (x >> 2) - ((m_bvPredictors[rribcFlipType][1].getHor() + offset) >> 2);
+      rmvVQP[0] = (y >> 2) - ((m_bvPredictors[rribcFlipType][0].getVer() + offset) >> 2);
+      rmvVQP[1] = (y >> 2) - ((m_bvPredictors[rribcFlipType][1].getVer() + offset) >> 2);
+
+      int absCandQP[2];
+      absCandQP[0] = abs(rmvHQP[0]) + abs(rmvVQP[0]);
+      absCandQP[1] = abs(rmvHQP[1]) + abs(rmvVQP[1]);
+      unsigned int candBits0QP, candBits1QP;
+      if (absCand[0] < absCand[1])
+      {
+        unsigned int candBits0 = (rribcFlipType == 1) ? 0 : getIComponentBits(rmvV[0]);
+        candBits0 += (rribcFlipType == 2) ? 0 : getIComponentBits(rmvH[0]);
+        if (absCandQP[0] < absCandQP[1])
+        {
+          candBits0QP = (rribcFlipType == 1) ? 0 : getIComponentBits(rmvVQP[0]);
+          candBits0QP += (rribcFlipType == 2) ? 0 : getIComponentBits(rmvHQP[0]);
+          return candBits0QP < candBits0 ? candBits0QP : candBits0;
+        }
+        else
+        {
+          candBits1QP = (rribcFlipType == 1) ? 0 : getIComponentBits(rmvVQP[1]);
+          candBits1QP = (rribcFlipType == 2) ? 0 : getIComponentBits(rmvHQP[1]);
+          return candBits1QP < candBits0 ? candBits1QP : candBits0;
+        }
+      }
+      else
+      {
+        unsigned int candBits1 = (rribcFlipType == 1) ? 0 : getIComponentBits(rmvV[1]);
+        candBits1 += (rribcFlipType == 2) ? 0 : getIComponentBits(rmvH[1]);
+        if (absCandQP[0] < absCandQP[1])
+        {
+          candBits0QP = (rribcFlipType == 1) ? 0 : getIComponentBits(rmvVQP[0]);
+          candBits0QP += (rribcFlipType == 2) ? 0 : getIComponentBits(rmvHQP[0]);
+          return candBits0QP < candBits1 ? candBits0QP : candBits1;
+        }
+        else
+        {
+          candBits1QP = (rribcFlipType == 1) ? 0 : getIComponentBits(rmvVQP[1]);
+          candBits1QP = (rribcFlipType == 2) ? 0 : getIComponentBits(rmvHQP[1]);
+          return candBits1QP < candBits1 ? candBits1QP : candBits1;
+        }
+      }
+    }
+    else
+    {
+      if (absCand[0] < absCand[1])
+      {
+        return ((rribcFlipType == 1) ? (getIComponentBits(rmvH[0])) : ((rribcFlipType == 2) ? (getIComponentBits(rmvV[0])) : (getIComponentBits(rmvH[0]) + getIComponentBits(rmvV[0]))));
+      }
+      else
+      {
+        return ((rribcFlipType == 1) ? (getIComponentBits(rmvH[1])) : ((rribcFlipType == 2) ? (getIComponentBits(rmvV[1])) : (getIComponentBits(rmvH[1]) + getIComponentBits(rmvV[1]))));
+      }
+    }
+  }
+
+  unsigned int getIComponentBits(int val)
+  {
+    if (!val)
+    {
+      return 1;
+    }
+
+    unsigned int length = 1;
+    unsigned int temp   = (val <= 0) ? (-val << 1) + 1 : (val << 1);
+
+    while (1 != temp)
+    {
+      temp >>= 1;
+      length += 2;
+    }
+
+    return length;
+  }
+#endif
+#else
+  void            setPredictors(Mv *pcMv);
+
 #if JVET_Z0131_IBC_BVD_BINARIZATION
-  EstBvdBitsStruct*  getBvdBitCosts() 
-  { 
-    return &m_cBvdBitCosts; 
+  EstBvdBitsStruct*  getBvdBitCosts()
+  {
+    return &m_cBvdBitCosts;
   }
 #if JVET_Z0084_IBC_TM && IBC_TM_AMVP
   inline Distortion getBvCostMultiplePreds(int x, int y, bool useIMV, uint8_t *bvImvResBest = NULL, int *bvpIdxBest = NULL, bool flag = false, AMVPInfo* amvpInfo4Pel = NULL)
@@ -262,7 +483,7 @@ public:
 #if JVET_Z0084_IBC_TM && IBC_TM_AMVP
       Mv tmpBv0;
       Mv tmpBv1;
-      if (flag) 
+      if (flag)
       {
         tmpBv0 = amvpInfo4Pel->mvCand[0];
         tmpBv1 = amvpInfo4Pel->mvCand[1];
@@ -381,7 +602,10 @@ public:
 
   unsigned int getIComponentBits(int val)
   {
-    if (!val) return 1;
+    if (!val)
+    {
+      return 1;
+    }
 
     unsigned int length = 1;
     unsigned int temp = (val <= 0) ? (-val << 1) + 1 : (val << 1);
@@ -395,6 +619,7 @@ public:
     return length;
   }
 #endif
+#endif
 
 #if ENABLE_SPLIT_PARALLELISM
   void copyState( const RdCost& other );
@@ -414,8 +639,19 @@ public:
 
     return uiLength2 + ( floorLog2(uiTemp2) << 1 );
   }
+
   Distortion     getCostOfVectorWithPredictor( const int x, const int y, const unsigned imvShift )  { return Distortion( m_motionLambda * getBitsOfVectorWithPredictor(x, y, imvShift )); }
-  uint32_t           getBitsOfVectorWithPredictor( const int x, const int y, const unsigned imvShift )  { return xGetExpGolombNumberOfBits(((x << m_iCostScale) - m_mvPredictor.getHor())>>imvShift) + xGetExpGolombNumberOfBits(((y << m_iCostScale) - m_mvPredictor.getVer())>>imvShift); }
+#if JVET_AA0070_RRIBC && !JVET_Z0131_IBC_BVD_BINARIZATION
+  uint32_t getBitsOfVectorWithPredictor( const int x, const int y, const unsigned imvShift, const int &rribcFlipType = 0)
+  {
+    return ((rribcFlipType == 1) ? (xGetExpGolombNumberOfBits(((x << m_iCostScale) - m_mvPredictor.getHor()) >> imvShift)) : ((rribcFlipType == 2) ? xGetExpGolombNumberOfBits(((y << m_iCostScale) - m_mvPredictor.getVer()) >> imvShift)
+                  : (xGetExpGolombNumberOfBits(((x << m_iCostScale) - m_mvPredictor.getHor()) >> imvShift) + xGetExpGolombNumberOfBits(((y << m_iCostScale) - m_mvPredictor.getVer()) >> imvShift))));
+  }
+#else
+  uint32_t       getBitsOfVectorWithPredictor( const int x, const int y, const unsigned imvShift )  { return xGetExpGolombNumberOfBits(((x << m_iCostScale) - m_mvPredictor.getHor())>>imvShift) + xGetExpGolombNumberOfBits(((y << m_iCostScale) - m_mvPredictor.getVer())>>imvShift); }
+#endif
+
+
 #if JVET_Z0131_IBC_BVD_BINARIZATION
   // for block vector cost
   uint32_t    xGetExpGolombNumberOfBitsIBCH( int iVal )
@@ -472,6 +708,7 @@ public:
     }
   }
 
+#if !JVET_AA0070_RRIBC
   Distortion     getCostOfVectorWithPredictorIBC( const int x, const int y, const unsigned imvShift )  
   { 
     return Distortion( m_motionLambda * getBitsOfVectorWithPredictorIBC(x, y, imvShift )) >> SCALE_BITS; 
@@ -481,6 +718,7 @@ public:
     return xGetExpGolombNumberOfBitsIBCH(((x << m_iCostScale) - m_mvPredictor.getHor())>>imvShift) + xGetExpGolombNumberOfBitsIBCV(((y << m_iCostScale) - m_mvPredictor.getVer())>>imvShift); 
   }
 #endif
+#endif
 #if WCG_EXT
          void    saveUnadjustedLambda       ();
          void    initLumaLevelToWeightTable ();
diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp
index bf2331c9e8f5832fcae8431d01af6cb167c6ee55..f6698ee24376111a4fa79a63e61d6a1ba626c66a 100644
--- a/source/Lib/CommonLib/Slice.cpp
+++ b/source/Lib/CommonLib/Slice.cpp
@@ -3485,6 +3485,9 @@ SPS::SPS()
 #if AFFINE_MMVD
  , m_AffineMmvdMode           ( false )
 #endif
+#if JVET_AA0061_IBC_MBVD
+  , m_ibcMbvd                 ( false )
+#endif
 #if TM_AMVP || TM_MRG || JVET_Z0084_IBC_TM || MULTI_PASS_DMVR
  , m_DMVDMode                 ( false )
 #endif
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index 1ca1eeebbc16eba3af3dea0c4ecce3e5c2bd663a..6214c6bc13a1ad8341c686526a66071712dbe7f2 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -1520,6 +1520,9 @@ private:
 #if AFFINE_MMVD
   bool              m_AffineMmvdMode;
 #endif
+#if JVET_AA0061_IBC_MBVD
+  bool              m_ibcMbvd;
+#endif
 #if TM_AMVP || TM_MRG || JVET_Z0084_IBC_TM || MULTI_PASS_DMVR
   bool              m_DMVDMode;
 #endif
@@ -2018,6 +2021,10 @@ void                    setCCALFEnabledFlag( bool b )
   void                    setUseAffineMmvdMode(bool b)                                                    { m_AffineMmvdMode = b; }
   bool                    getUseAffineMmvdMode() const                                                    { return m_AffineMmvdMode; }
 #endif
+#if JVET_AA0061_IBC_MBVD
+  void                    setUseIbcMbvd(bool b)                                                           { m_ibcMbvd = b; }
+  bool                    getUseIbcMbvd() const                                                           { return m_ibcMbvd; }
+#endif
 #if TM_AMVP || TM_MRG || JVET_Z0084_IBC_TM || MULTI_PASS_DMVR
   void                    setUseDMVDMode(bool b)                                                          { m_DMVDMode = b; }
   bool                    getUseDMVDMode() const                                                          { return m_DMVDMode; }
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index af3c1cf8233158638dafa7ce639421b5f71e804d..e83c5cb8641a3884884d812b3bbe9cb20d5a0514 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -150,6 +150,8 @@
 #define JVET_Z0153_IBC_EXT_REF                            1 // JVET-Z0153: Extend reference area for IBC
 #define JVET_Z0160_IBC_ZERO_PADDING                       1 // JVET-Z0160: Replacement of zero-padding candidates
 #define JVET_AA0106_IBCBUF_CTU256                         1 // JVET-AA0106: Adjust IBC reference area to 2*128 rows above the current CTU
+#define JVET_AA0061_IBC_MBVD                              1 // JVET-AA0061: IBC merge mode with block vector differences
+#define JVET_AA0070_RRIBC                                 1 // JVET-AA0070: Reconstruction-Reordered IBC
 
 // Inter
 #define CIIP_PDPC                                         1 // Apply pdpc to megre prediction as a new CIIP mode (CIIP_PDPC) additional to CIIP mode
diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp
index 81e67cd6e40f2287255dc0cdbed3caf33c1cd3cb..cb7507a43d697c4a729cf97aff2b3a58a7418832 100644
--- a/source/Lib/CommonLib/Unit.cpp
+++ b/source/Lib/CommonLib/Unit.cpp
@@ -320,6 +320,9 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other )
 #if INTER_LIC
   LICFlag           = other.LICFlag;
 #endif
+#if JVET_AA0070_RRIBC
+  rribcFlipType = other.rribcFlipType;
+#endif
 
   for (int idx = 0; idx < MAX_NUM_CHANNEL_TYPE; idx++)
   {
@@ -415,6 +418,9 @@ void CodingUnit::initData()
 #if INTER_LIC
   LICFlag = false;
 #endif
+#if JVET_AA0070_RRIBC
+  rribcFlipType = 0;
+#endif
 
   for (int idx = 0; idx < MAX_NUM_CHANNEL_TYPE; idx++)
   {
@@ -682,6 +688,10 @@ void PredictionUnit::initData()
 #endif
   mmvdMergeFlag = false;
   mmvdMergeIdx = MAX_UCHAR;
+#if JVET_AA0061_IBC_MBVD
+  ibcMbvdMergeFlag = false;
+  ibcMbvdMergeIdx = MAX_INT;
+#endif
 #if AFFINE_MMVD
   afMmvdFlag    = false;
   afMmvdBaseIdx = UINT8_MAX;
@@ -813,6 +823,10 @@ PredictionUnit& PredictionUnit::operator=(const InterPredictionData& predData)
 #endif
   mmvdMergeFlag = predData.mmvdMergeFlag;
   mmvdMergeIdx = predData.mmvdMergeIdx;
+#if JVET_AA0061_IBC_MBVD
+  ibcMbvdMergeFlag = predData.ibcMbvdMergeFlag;
+  ibcMbvdMergeIdx = predData.ibcMbvdMergeIdx;
+#endif
 #if AFFINE_MMVD
   afMmvdFlag    = predData.afMmvdFlag;
   afMmvdBaseIdx = predData.afMmvdBaseIdx;
@@ -940,6 +954,10 @@ PredictionUnit& PredictionUnit::operator=( const PredictionUnit& other )
 #endif
   mmvdMergeFlag = other.mmvdMergeFlag;
   mmvdMergeIdx = other.mmvdMergeIdx;
+#if JVET_AA0061_IBC_MBVD
+  ibcMbvdMergeFlag = other.ibcMbvdMergeFlag;
+  ibcMbvdMergeIdx = other.ibcMbvdMergeIdx;
+#endif
 #if AFFINE_MMVD
   afMmvdFlag    = other.afMmvdFlag;
   afMmvdBaseIdx = other.afMmvdBaseIdx;
diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h
index f0c868563e6da4f3666c936f08f45d4da82e83ea..66f9521870f16c614e31a4d5a66d11962168cd0b 100644
--- a/source/Lib/CommonLib/Unit.h
+++ b/source/Lib/CommonLib/Unit.h
@@ -350,6 +350,9 @@ struct CodingUnit : public UnitArea
 #if INTER_LIC
   bool           LICFlag;
 #endif
+#if JVET_AA0070_RRIBC
+  int    rribcFlipType;
+#endif
 
   // needed for fast imv mode decisions
   int8_t          imvNumCand;
@@ -476,6 +479,10 @@ struct InterPredictionData
 #else
   uint8_t       mmvdMergeIdx;
 #endif
+#if JVET_AA0061_IBC_MBVD
+  bool          ibcMbvdMergeFlag;
+  int           ibcMbvdMergeIdx;
+#endif
 #if AFFINE_MMVD
   bool        afMmvdFlag;
   uint8_t     afMmvdBaseIdx; // base vector's merge index at the affine merge list, excluding sbTmvp
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index eaca0c884545156cb54d149e812a1b2b28396b93..e627446672db1a76e1f669d8d4654c52efd5d8f3 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -445,6 +445,13 @@ void CU::saveMotionInHMVP( const CodingUnit& cu, const bool isToBeDone )
 #if MULTI_HYP_PRED
     mi.addHypData = pu.addHypData;
 #endif
+#if JVET_AA0070_RRIBC
+    if(CU::isIBC(cu))
+    {
+      mi.centerPos.x = cu.lx() + (cu.lwidth() >> 1);
+      mi.centerPos.y = cu.ly() + (cu.lheight() >> 1);
+    }
+#endif
 
     mi.BcwIdx = (mi.interDir == 3) ? cu.BcwIdx : BCW_DEFAULT;
 
@@ -1870,10 +1877,28 @@ bool PU::addMergeHMVPCand(const CodingStructure &cs, MergeCtx &mrgCtx, const int
 
   int num_avai_candInLUT = (int)lut.size();
 
+#if JVET_AA0070_RRIBC && !JVET_Z0075_IBC_HMVP_ENLARGE
+  int cPosCurX = pu.lx() + (pu.lwidth() >> 1);
+  int cPosCurY = pu.ly() + (pu.lheight() >> 1);
+  int thW      = (pu.lwidth() >> 1) * 3;
+  int thH      = (pu.lheight() >> 1) * 3;
+#endif
+
   for (int mrgIdx = 1; mrgIdx <= num_avai_candInLUT; mrgIdx++)
   {
     miNeighbor = lut[num_avai_candInLUT - mrgIdx];
 
+#if JVET_AA0070_RRIBC && !JVET_Z0075_IBC_HMVP_ENLARGE
+    if (ibcFlag)
+    {
+      Position cPos(miNeighbor.centerPos.x, miNeighbor.centerPos.y);
+      if (pu.mergeFlag || ((abs(cPosCurX - (int) cPos.x) <= thW) && (abs(cPosCurY - (int) cPos.y) <= thH)))
+      {
+        rribcAdjustMotion(pu, &cPos, miNeighbor);
+      }
+    }
+#endif
+
 #if JVET_X0083_BM_AMVP_MERGE_MODE
 #if JVET_Y0128_NON_CTC
     bool isValidAmMode = checkIsValidMergeMvCand(pu, miNeighbor.refIdx);
@@ -1910,9 +1935,15 @@ bool PU::addMergeHMVPCand(const CodingStructure &cs, MergeCtx &mrgCtx, const int
       mrgCtx.BcwIdx            [cnt] = (miNeighbor.interDir == 3) ? miNeighbor.BcwIdx : BCW_DEFAULT;
 #if INTER_LIC
       mrgCtx.LICFlags          [cnt] = miNeighbor.usesLIC;
+#if JVET_AA0070_RRIBC
+      mrgCtx.rribcFlipTypes    [cnt] = 0;
+#endif
 #if !JVET_Z0075_IBC_HMVP_ENLARGE
       if (ibcFlag)
       {
+#if JVET_AA0070_RRIBC
+        mrgCtx.rribcFlipTypes[cnt] = !pu.tmMergeFlag ? miNeighbor.rribcFlipType : 0;
+#endif
         CHECK(mrgCtx.LICFlags[cnt], "addMergeHMVPCand: LIC is not used with IBC mode")
       }
 #endif
@@ -2015,15 +2046,35 @@ bool PU::addIBCMergeHMVPCand(const CodingStructure &cs, MergeCtx &mrgCtx, const
   int num_avai_candInLUT = (int)lut.size();
   int compareNum = cnt;
 
+#if JVET_AA0070_RRIBC
+  int cPosCurX = pu.lx() + (pu.lwidth() >> 1);
+  int cPosCurY = pu.ly() + (pu.lheight() >> 1);
+  int thW      = (pu.lwidth() >> 1) * 3;
+  int thH      = (pu.lheight() >> 1) * 3;
+#endif
   for (int mrgIdx = 1; mrgIdx <= num_avai_candInLUT; mrgIdx++)
   {
     miNeighbor = lut[num_avai_candInLUT - mrgIdx];
+#if JVET_AA0070_RRIBC
+    Position cPos(miNeighbor.centerPos.x, miNeighbor.centerPos.y);
+    if (pu.mergeFlag || ((abs(cPosCurX - (int) cPos.x) <= thW) && (abs(cPosCurY - (int) cPos.y) <= thH)))
+    {
+      rribcAdjustMotion(pu, &cPos, miNeighbor);
+    }
+#endif
 
 #if JVET_Y0058_IBC_LIST_MODIFY && JVET_Z0084_IBC_TM
     if (checkIsIBCCandidateValid(pu, miNeighbor))
     {
 #endif
       mrgCtx.interDirNeighbours[cnt] = miNeighbor.interDir;
+#if JVET_AA0070_RRIBC
+#if IBC_TM_MRG
+      mrgCtx.rribcFlipTypes[cnt] = !pu.tmMergeFlag ? miNeighbor.rribcFlipType : 0;
+#else
+      mrgCtx.rribcFlipTypes[cnt] = miNeighbor.rribcFlipType;
+#endif
+#endif
 #if !JVET_Z0084_IBC_TM
       mrgCtx.useAltHpelIf      [cnt] = false;
       mrgCtx.BcwIdx            [cnt] = (miNeighbor.interDir == 3) ? miNeighbor.BcwIdx : BCW_DEFAULT;
@@ -2090,6 +2141,59 @@ bool PU::addIBCMergeHMVPCand(const CodingStructure &cs, MergeCtx &mrgCtx, const
   return false;
 }
 #endif
+
+#if JVET_AA0070_RRIBC
+void PU::rribcAdjustMotion(const PredictionUnit &pu, const Position *cPos, MotionInfo &miNeighbor)
+{
+#if IBC_TM_MRG
+  if (pu.tmMergeFlag)
+  {
+    return;
+  }
+#endif
+
+#if JVET_AA0061_IBC_MBVD
+  if (pu.ibcMbvdMergeFlag)
+  {
+    return;
+  }
+#endif
+
+  int curCPosX = pu.lx() + (pu.lwidth() >> 1);
+  int curCPosY = pu.ly() + (pu.lheight() >> 1);
+
+  if (miNeighbor.isIBCmot && miNeighbor.rribcFlipType && (pu.mergeFlag || (!pu.mergeFlag && (pu.cu->rribcFlipType == miNeighbor.rribcFlipType))))
+  {
+    if (miNeighbor.rribcFlipType == 1)
+    {
+      int shift = (cPos->x - curCPosX) << 1;
+      if (shift)
+      {
+        int storeHor = miNeighbor.mv[0].getHor();
+        miNeighbor.mv[0].setHor(storeHor + (shift << 4));
+        if (!checkIsIBCCandidateValid(pu, miNeighbor))
+        {
+          miNeighbor.mv[0].setHor(storeHor);
+        }
+      }
+    }
+    else if (miNeighbor.rribcFlipType == 2)
+    {
+      int shift = (cPos->y - curCPosY) << 1;
+      if (shift)
+      {
+        int storeVer = miNeighbor.mv[0].getVer();
+        miNeighbor.mv[0].setVer(storeVer + (shift << 4));
+        if (!checkIsIBCCandidateValid(pu, miNeighbor))
+        {
+          miNeighbor.mv[0].setVer(storeVer);
+        }
+      }
+    }
+  }
+}
+#endif
+
 void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx)
 {
   const CodingStructure &cs = *pu.cs;
@@ -2100,7 +2204,11 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
 #endif
 #if JVET_Z0084_IBC_TM
 #if IBC_TM_MRG
+#if JVET_AA0070_RRIBC
+  const uint32_t mvdSimilarityThresh = ((pu.tmMergeFlag && pu.mergeFlag) || (!pu.mergeFlag && !pu.cu->rribcFlipType)) ? PU::getTMMvdThreshold(pu) : 1;
+#else
   const uint32_t mvdSimilarityThresh = pu.tmMergeFlag ? PU::getTMMvdThreshold(pu) : 1;
+#endif
 #else
   const uint32_t mvdSimilarityThresh = 1;
 #endif
@@ -2115,6 +2223,9 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
     mrgCtx.useAltHpelIf[ui] = false;
 #if INTER_LIC
     mrgCtx.LICFlags[ui] = false;
+#endif
+#if JVET_AA0070_RRIBC
+    mrgCtx.rribcFlipTypes[ui] = 0;
 #endif
   }
 
@@ -2142,6 +2253,10 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
   if (isGt4x4 && isAvailableA1)
   {
     miLeft = puLeft->getMotionInfo(posLB.offset(-1, 0));
+#if JVET_AA0070_RRIBC
+    Position cPos(puLeft->lx() + (puLeft->lwidth() >> 1), puLeft->ly() + (puLeft->lheight() >> 1));
+    rribcAdjustMotion(pu, &cPos, miLeft);
+#endif
 
 #if JVET_Y0058_IBC_LIST_MODIFY
     if (checkIsIBCCandidateValid(pu, miLeft))
@@ -2151,6 +2266,21 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
     mrgCtx.interDirNeighbours[cnt] = miLeft.interDir;
     // get Mv from Left
     mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miLeft.mv[0], miLeft.refIdx[0]);
+#if JVET_AA0070_RRIBC
+#if IBC_TM_MRG
+#if JVET_AA0061_IBC_MBVD
+    mrgCtx.rribcFlipTypes[cnt] = (miLeft.isIBCmot && !pu.tmMergeFlag && !pu.ibcMbvdMergeFlag) ? miLeft.rribcFlipType : 0;
+#else
+    mrgCtx.rribcFlipTypes[cnt] = (miLeft.isIBCmot && !pu.tmMergeFlag) ? miLeft.rribcFlipType : 0;
+#endif
+#else
+#if JVET_AA0061_IBC_MBVD
+    mrgCtx.rribcFlipTypes[cnt] = (miLeft.isIBCmot && !pu.ibcMbvdMergeFlag) ? miLeft.rribcFlipType : 0;
+#else
+    mrgCtx.rribcFlipTypes[cnt] = miLeft.isIBCmot ? miLeft.rribcFlipType : 0;
+#endif
+#endif
+#endif
     if (mrgCandIdx == cnt)
     {
       return;
@@ -2173,6 +2303,10 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
   if (isGt4x4 && isAvailableB1)
   {
     miAbove = puAbove->getMotionInfo(posRT.offset(0, -1));
+#if JVET_AA0070_RRIBC
+    Position cPos(puAbove->lx() + (puAbove->lwidth() >> 1), puAbove->ly() + (puAbove->lheight() >> 1));
+    rribcAdjustMotion(pu, &cPos, miAbove);
+#endif
 
     if (!isAvailableA1 || (miAbove != miLeft))
     {
@@ -2184,6 +2318,21 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
       mrgCtx.interDirNeighbours[cnt] = miAbove.interDir;
       // get Mv from Above
       mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAbove.mv[0], miAbove.refIdx[0]);
+#if JVET_AA0070_RRIBC
+#if IBC_TM_MRG
+#if JVET_AA0061_IBC_MBVD
+      mrgCtx.rribcFlipTypes[cnt] = (miAbove.isIBCmot && !pu.tmMergeFlag && !pu.ibcMbvdMergeFlag) ? miAbove.rribcFlipType : 0;
+#else
+      mrgCtx.rribcFlipTypes[cnt] = (miAbove.isIBCmot && !pu.tmMergeFlag) ? miAbove.rribcFlipType : 0;
+#endif
+#else
+#if JVET_AA0061_IBC_MBVD
+      mrgCtx.rribcFlipTypes[cnt] = (miAbove.isIBCmot && !pu.ibcMbvdMergeFlag) ? miAbove.rribcFlipType : 0;
+#else
+      mrgCtx.rribcFlipTypes[cnt] = miAbove.isIBCmot ? miAbove.rribcFlipType : 0;
+#endif
+#endif
+#endif
 
 #if JVET_Z0084_IBC_TM
       if( !mrgCtx.xCheckSimilarIBCMotion(cnt, mvdSimilarityThresh) )
@@ -2214,6 +2363,10 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
   if (isGt4x4 && isAvailableB0)
   {
     miAboveRight = puAboveRight->getMotionInfo(posRT.offset(1, -1));
+#if JVET_AA0070_RRIBC
+    Position cPos(puAboveRight->lx() + (puAboveRight->lwidth() >> 1), puAboveRight->ly() + (puAboveRight->lheight() >> 1));
+    rribcAdjustMotion(pu, &cPos, miAboveRight);
+#endif
 
     if ((!isAvailableB1 || (miAbove != miAboveRight)) && (!isAvailableA1 || (miLeft != miAboveRight)))
     {
@@ -2223,6 +2376,21 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
         mrgCtx.interDirNeighbours[cnt] = miAboveRight.interDir;
         // get Mv from Above-right
         mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAboveRight.mv[0], miAboveRight.refIdx[0]);
+#if JVET_AA0070_RRIBC
+#if IBC_TM_MRG
+#if JVET_AA0061_IBC_MBVD
+        mrgCtx.rribcFlipTypes[cnt] = (miAboveRight.isIBCmot && !pu.tmMergeFlag && !pu.ibcMbvdMergeFlag) ? miAboveRight.rribcFlipType : 0;
+#else
+        mrgCtx.rribcFlipTypes[cnt] = (miAboveRight.isIBCmot && !pu.tmMergeFlag) ? miAboveRight.rribcFlipType : 0;
+#endif
+#else
+#if JVET_AA0061_IBC_MBVD
+        mrgCtx.rribcFlipTypes[cnt] = (miAboveRight.isIBCmot && !pu.ibcMbvdMergeFlag) ? miAboveRight.rribcFlipType : 0;
+#else
+        mrgCtx.rribcFlipTypes[cnt] = miAboveRight.isIBCmot ? miAboveRight.rribcFlipType : 0;
+#endif
+#endif
+#endif
 
 #if JVET_Z0084_IBC_TM
         if( !mrgCtx.xCheckSimilarIBCMotion(cnt, mvdSimilarityThresh) )
@@ -2250,6 +2418,10 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
   if (isGt4x4 && isAvailableA0)
   {
     miBelowLeft = puLeftBottom->getMotionInfo(posLB.offset(-1, 1));
+#if JVET_AA0070_RRIBC
+    Position cPos(puLeftBottom->lx() + (puLeftBottom->lwidth() >> 1), puLeftBottom->ly() + (puLeftBottom->lheight() >> 1));
+    rribcAdjustMotion(pu, &cPos, miBelowLeft);
+#endif
 
     if ((!isAvailableA1 || (miBelowLeft != miLeft)) && (!isAvailableB1 || (miBelowLeft != miAbove)) && (!isAvailableB0 || (miBelowLeft != miAboveRight)))
     {
@@ -2258,6 +2430,21 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
         // get Inter Dir
         mrgCtx.interDirNeighbours[cnt] = miBelowLeft.interDir;
         mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miBelowLeft.mv[0], miBelowLeft.refIdx[0]);
+#if JVET_AA0070_RRIBC
+#if IBC_TM_MRG
+#if JVET_AA0061_IBC_MBVD
+        mrgCtx.rribcFlipTypes[cnt] = (miBelowLeft.isIBCmot && !pu.tmMergeFlag && !pu.ibcMbvdMergeFlag) ? miBelowLeft.rribcFlipType : 0;
+#else
+        mrgCtx.rribcFlipTypes[cnt] = (miBelowLeft.isIBCmot && !pu.tmMergeFlag) ? miBelowLeft.rribcFlipType : 0;
+#endif
+#else
+#if JVET_AA0061_IBC_MBVD
+        mrgCtx.rribcFlipTypes[cnt] = (miBelowLeft.isIBCmot && !pu.ibcMbvdMergeFlag) ? miBelowLeft.rribcFlipType : 0;
+#else
+        mrgCtx.rribcFlipTypes[cnt] = miBelowLeft.isIBCmot ? miBelowLeft.rribcFlipType : 0;
+#endif
+#endif
+#endif
 
 #if JVET_Z0084_IBC_TM
         if( !mrgCtx.xCheckSimilarIBCMotion(cnt, mvdSimilarityThresh) )
@@ -2291,6 +2478,10 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
     if (isGt4x4 && isAvailableB2)
     {
       miAboveLeft = puAboveLeft->getMotionInfo(posLT.offset(-1, -1));
+#if JVET_AA0070_RRIBC
+      Position cPos(puAboveLeft->lx() + (puAboveLeft->lwidth() >> 1), puAboveLeft->ly() + (puAboveLeft->lheight() >> 1));
+      rribcAdjustMotion(pu, &cPos, miAboveLeft);
+#endif
 
       if ((!isAvailableA1 || (miLeft != miAboveLeft)) && (!isAvailableB1 || (miAbove != miAboveLeft)) && (!isAvailableA0 || (miBelowLeft != miAboveLeft)) && (!isAvailableB0 || (miAboveRight != miAboveLeft)))
       {
@@ -2299,6 +2490,21 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
           // get Inter Dir
           mrgCtx.interDirNeighbours[cnt] = miAboveLeft.interDir;
           mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAboveLeft.mv[0], miAboveLeft.refIdx[0]);
+#if JVET_AA0070_RRIBC
+#if IBC_TM_MRG
+#if JVET_AA0061_IBC_MBVD
+          mrgCtx.rribcFlipTypes[cnt] = (miAboveLeft.isIBCmot && !pu.tmMergeFlag && !pu.ibcMbvdMergeFlag) ? miAboveLeft.rribcFlipType : 0;
+#else
+        mrgCtx.rribcFlipTypes[cnt] = (miAboveLeft.isIBCmot && !pu.tmMergeFlag) ? miAboveLeft.rribcFlipType : 0;
+#endif
+#else
+#if JVET_AA0061_IBC_MBVD
+          mrgCtx.rribcFlipTypes[cnt] = (miAboveLeft.isIBCmot && !pu.ibcMbvdMergeFlag) ? miAboveLeft.rribcFlipType : 0;
+#else
+        mrgCtx.rribcFlipTypes[cnt] = (miAboveLeft.isIBCmot) ? miAboveLeft.rribcFlipType : 0;
+#endif
+#endif
+#endif
 
 #if JVET_Z0084_IBC_TM
           if( !mrgCtx.xCheckSimilarIBCMotion(cnt, mvdSimilarityThresh) )
@@ -2493,6 +2699,9 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
     miCand.mv[0] = mvp;
     mrgCtx.mvFieldNeighbours[cnt * 2].setMvField(mvp, MAX_NUM_REF);
     mrgCtx.interDirNeighbours[cnt] = 1;
+#if JVET_AA0070_RRIBC
+    mrgCtx.rribcFlipTypes[cnt] = 0;
+#endif
 
 #if JVET_Z0084_IBC_TM
     if (!mrgCtx.xCheckSimilarIBCMotion(cnt, mvdSimilarityThresh) && checkIsIBCCandidateValid(pu, miCand))
@@ -2514,6 +2723,9 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
   {
     mrgCtx.interDirNeighbours[cnt] = 1;
     mrgCtx.mvFieldNeighbours[cnt * 2].setMvField(Mv(0, 0), MAX_NUM_REF);
+#if JVET_AA0070_RRIBC
+    mrgCtx.rribcFlipTypes[cnt] = 0;
+#endif
     if (mrgCandIdx == cnt)
     {
       return;
@@ -2539,14 +2751,23 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
 }
 
 #if  JVET_Y0058_IBC_LIST_MODIFY
+#if JVET_AA0070_RRIBC
+bool PU::checkIsIBCCandidateValid(const PredictionUnit& pu, const MotionInfo miNeighbor, bool isRefTemplate, bool isRefAbove)
+#else
 bool PU::checkIsIBCCandidateValid(const PredictionUnit& pu, const MotionInfo miNeighbor)
+#endif
 {
   Mv bv = miNeighbor.mv[REF_PIC_LIST_0];
   bv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT); // used for only integer resolution
   const int cuPelX = pu.Y().x;
   const int cuPelY = pu.Y().y;
+#if JVET_AA0070_RRIBC
+  int roiWidth  = (isRefTemplate && !isRefAbove) ? AML_MERGE_TEMPLATE_SIZE : pu.lwidth();
+  int roiHeight = (isRefTemplate && isRefAbove) ? AML_MERGE_TEMPLATE_SIZE : pu.lheight();
+#else
   int roiWidth = pu.lwidth();
   int roiHeight = pu.lheight();
+#endif
   const int picWidth = pu.cs->slice->getPPS()->getPicWidthInLumaSamples();
   const int picHeight = pu.cs->slice->getPPS()->getPicHeightInLumaSamples();
   const unsigned int  lcuWidth = pu.cs->slice->getSPS()->getMaxCUWidth();
@@ -2747,6 +2968,45 @@ bool PU::searchBv(const PredictionUnit& pu, int xPos, int yPos, int width, int h
 }
 #endif
 
+#if JVET_AA0061_IBC_MBVD
+void PU::getIbcMbvdMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, int numValidBv)
+{
+  int refIdxList0;
+  int k;
+  int currBaseNum = 0;
+
+  for( k = 0; k < numValidBv; k++ )
+  {
+    refIdxList0 = mrgCtx.mvFieldNeighbours[( k << 1 )].refIdx;
+
+    if( refIdxList0 >= 0 )
+    {
+      mrgCtx.ibcMbvdBaseBv[currBaseNum][0] = mrgCtx.mvFieldNeighbours[( k << 1 )];
+      mrgCtx.ibcMbvdBaseBv[currBaseNum][1] = MvField( Mv( 0, 0 ), -1 );
+    }
+
+    currBaseNum++;
+
+    if( currBaseNum == IBC_MBVD_BASE_NUM )
+    {
+      break;
+    }
+  }
+}
+int32_t PU::getIbcMbvdEstBits(const PredictionUnit &pu,unsigned int mmvdMergeCand)
+{
+  int baseIdx = mmvdMergeCand / IBC_MBVD_MAX_REFINE_NUM;
+  int baseBits = (IBC_MBVD_BASE_NUM == 1 ? 0 : baseIdx + (baseIdx == IBC_MBVD_BASE_NUM - 1 ? 0: 1));
+  int ricePar = 1;
+  unsigned int mvpIdx = mmvdMergeCand;
+  mvpIdx -= baseIdx * IBC_MBVD_MAX_REFINE_NUM;
+  mvpIdx >>= ricePar;
+  int numCandStepMinus1 = (IBC_MBVD_SIZE_ENC >> ricePar) - 1;
+  int mmvdUnaryBits = mvpIdx + (mvpIdx == numCandStepMinus1 ? 0 : 1);
+  return baseBits + mmvdUnaryBits + ricePar;
+}
+#endif
+
 #if MULTI_PASS_DMVR || JVET_W0097_GPM_MMVD_TM
 uint32_t PU::getBDMVRMvdThreshold(const PredictionUnit &pu)
 {
@@ -2875,6 +3135,9 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
     mrgCtx.BcwIdx[ui] = BCW_DEFAULT;
 #if INTER_LIC
     mrgCtx.LICFlags[ui] = false;
+#endif
+#if JVET_AA0070_RRIBC
+    mrgCtx.rribcFlipTypes[ui] = 0;
 #endif
     mrgCtx.interDirNeighbours[ui] = 0;
     mrgCtx.mvFieldNeighbours[(ui << 1)    ].refIdx = NOT_VALID;
@@ -6929,11 +7192,20 @@ void PU::fillIBCMvpCand(PredictionUnit &pu, AMVPInfo &amvpInfo)
 
   MergeCtx mergeCtx;
 #if JVET_Z0084_IBC_TM && IBC_TM_AMVP
+#if JVET_AA0070_RRIBC
+  pInfo->maxSimilarityThreshold = (pu.cs->sps->getUseDMVDMode() && pcInter && !pu.cu->rribcFlipType) ? PU::getTMMvdThreshold(pu) : 1;
+#if IBC_TM_MRG
+  if (!pu.cu->rribcFlipType)
+  {
+   pu.tmMergeFlag = true;
+  }
+#endif
+#else
   pInfo->maxSimilarityThreshold = (pu.cs->sps->getUseDMVDMode() && pcInter) ? PU::getTMMvdThreshold(pu) : 1;
-
 #if IBC_TM_MRG
   pu.tmMergeFlag = true;
 #endif
+#endif
 #if JVET_Z0075_IBC_HMVP_ENLARGE
   PU::getIBCMergeCandidates(pu, mergeCtx, pu.cs->sps->getMaxNumIBCMergeCand());
 #else
@@ -6955,7 +7227,11 @@ void PU::fillIBCMvpCand(PredictionUnit &pu, AMVPInfo &amvpInfo)
     candIdx++;
   }
 
+#if JVET_AA0070_RRIBC
+  if (pu.cs->sps->getUseDMVDMode() && pcInter && pInfo->numCand > 0 && !pu.cu->rribcFlipType)
+#else
   if (pu.cs->sps->getUseDMVDMode() && pcInter && pInfo->numCand > 0)
+#endif
   {
     struct AMVPSort
     {
@@ -11382,6 +11658,9 @@ void PU::spanMotionInfo( PredictionUnit &pu, const MergeCtx &mrgCtx )
 #if INTER_LIC
     mi.usesLIC = pu.cu->LICFlag;
 #endif
+#if JVET_AA0070_RRIBC
+    mi.rribcFlipType = mi.isIBCmot ? pu.cu->rribcFlipType : 0;
+#endif
 
     if( mi.isInter )
     {
@@ -11845,6 +12124,16 @@ void PU::applyImv( PredictionUnit& pu, MergeCtx &mrgCtx, InterPrediction *interP
 #endif
       pu.mv    [0] = amvpInfo.mvCand[mvpIdx] + pu.mvd[0];
       pu.mv[0].mvCliptoStorageBitDepth();
+#if JVET_AA0070_RRIBC
+      if (CU::isIBC(*pu.cu) && pu.cu->rribcFlipType == 1)
+      {
+        pu.mv[0].setVer(0);
+      }
+      else if (CU::isIBC(*pu.cu) && pu.cu->rribcFlipType == 2)
+      {
+        pu.mv[0].setHor(0);
+      }
+#endif
 #if JVET_Z0160_IBC_ZERO_PADDING
       pu.bv = pu.mv[0];
       pu.bv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT);
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index f8908e63f0a8b028f5fded92cc4d9f453b587464..f8eb6f82499345763c8b7b2c9e0418e72ee4424a 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -192,11 +192,22 @@ namespace PU
   void getNonAdjacentMergeCand        (const PredictionUnit &pu, MergeCtx& mvpMrgCtx);
 #endif
   void getIBCMergeCandidates          (const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx = -1);
+#if JVET_AA0070_RRIBC
+  void rribcAdjustMotion(const PredictionUnit &pu, const Position *cPos, MotionInfo &miNeighbor);
+#if  JVET_Y0058_IBC_LIST_MODIFY
+  bool checkIsIBCCandidateValid       (const PredictionUnit &pu,const MotionInfo miNeighbor, bool isRefTemplate = false, bool isRefAbove = false );
+#endif
+#else
 #if  JVET_Y0058_IBC_LIST_MODIFY
   bool checkIsIBCCandidateValid       (const PredictionUnit &pu,const MotionInfo miNeighbor);
 #endif
-#if JVET_Y0058_IBC_LIST_MODIFY || JVET_Z0084_IBC_TM
+#endif
+#if JVET_Y0058_IBC_LIST_MODIFY || JVET_Z0084_IBC_TM || JVET_AA0061_IBC_MBVD
   bool searchBv(const PredictionUnit& pu, int xPos, int yPos, int width, int height, int picWidth, int picHeight, int xBv, int yBv, int ctuSize);
+#endif
+#if JVET_AA0061_IBC_MBVD
+  void getIbcMbvdMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, int numValidBv);
+  int32_t getIbcMbvdEstBits      (const PredictionUnit &pu, unsigned int mmvdMergeCand);
 #endif
   void getInterMMVDMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx = -1);
   int getDistScaleFactor(const int &currPOC, const int &currRefPOC, const int &colPOC, const int &colRefPOC);
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index 544d56b07966f49f0abfec16b490195384f2525c..6ac643054e1f366e55f3ea03db268697d10ba1ff 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -3044,6 +3044,11 @@ void CABACReader::prediction_unit( PredictionUnit& pu, MergeCtx& mrgCtx )
   {
     merge_flag( pu );
   }
+
+#if JVET_AA0070_RRIBC
+  rribcData(*pu.cu);
+#endif
+
   if( pu.mergeFlag )
   {
     merge_data(pu);
@@ -3061,10 +3066,18 @@ void CABACReader::prediction_unit( PredictionUnit& pu, MergeCtx& mrgCtx )
     pu.cu->affine = false;
     pu.refIdx[REF_PIC_LIST_0] = MAX_NUM_REF;
     RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE(STATS__CABAC_BITS__MVD, pu.lumaSize());
+#if JVET_AA0070_RRIBC
+#if JVET_Z0131_IBC_BVD_BINARIZATION
+    bvdCoding(pu.mvd[REF_PIC_LIST_0], pu.cu->rribcFlipType);
+#else
+    mvd_coding(pu.mvd[REF_PIC_LIST_0], true, pu.cu->rribcFlipType);
+#endif
+#else
 #if JVET_Z0131_IBC_BVD_BINARIZATION
     bvdCoding(pu.mvd[REF_PIC_LIST_0]);
 #else
     mvd_coding(pu.mvd[REF_PIC_LIST_0]);
+#endif
 #endif
     if (pu.cs->sps->getMaxNumIBCMergeCand() == 1)
     {
@@ -3476,6 +3489,62 @@ void CABACReader::affine_mmvd_data(PredictionUnit& pu)
 }
 #endif
 
+#if JVET_AA0061_IBC_MBVD
+void CABACReader::ibcMbvdData(PredictionUnit& pu)
+{
+  if (!pu.cs->sps->getUseIbcMbvd() || !pu.mergeFlag || !CU::isIBC(*pu.cu))
+  {
+    return;
+  }
+
+  pu.ibcMbvdMergeFlag = (m_BinDecoder.decodeBin(Ctx::IbcMbvdFlag()));
+  DTRACE(g_trace_ctx, D_SYNTAX, "IBC_mbvd_flag() IBC_mbvd_merge=%d pos=(%d,%d) size=%dx%d\n", pu.ibcMbvdMergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height);
+
+  if (!pu.ibcMbvdMergeFlag)
+  {
+    return;
+  }
+
+  // Base IBC merge candidate idx
+  uint8_t var0 = 0;
+  int numBaseCandMinus1 = IBC_MBVD_BASE_NUM - 1;
+  if (numBaseCandMinus1 > 0)
+  {
+    // to support more base candidates
+    if (m_BinDecoder.decodeBin(Ctx::IbcMbvdMergeIdx()))
+    {
+      var0++;
+      for (; var0 < numBaseCandMinus1; var0++)
+      {
+        if (!m_BinDecoder.decodeBinEP())
+        {
+          break;
+        }
+      }
+    }
+  }
+  DTRACE(g_trace_ctx, D_SYNTAX, "ibcMbvdBaseIdx() ibcMbvdBaseIdx=%d\n", var0);
+
+  unsigned int uiUnaryIdx = 0;
+  unsigned int ricePar = 1;
+  int numCandStepMinus1 = (IBC_MBVD_SIZE_ENC >> ricePar) - 1;
+  int temp = 0;
+  temp = m_BinDecoder.decodeBinsEP(ricePar);
+
+  for (; uiUnaryIdx < numCandStepMinus1; ++uiUnaryIdx)
+  {
+    if (!m_BinDecoder.decodeBin(Ctx::IbcMbvdStepMvpIdx((uiUnaryIdx > LAST_MERGE_MMVD_IDX_CABAC - 1 ? LAST_MERGE_MMVD_IDX_CABAC - 1 : uiUnaryIdx))))
+    {
+      break;
+    }
+  }
+  uiUnaryIdx <<= ricePar;
+  uiUnaryIdx += temp;
+  pu.ibcMbvdMergeIdx = var0 * IBC_MBVD_MAX_REFINE_NUM  +uiUnaryIdx;
+  DTRACE(g_trace_ctx, D_SYNTAX, "IBC_mbvd_merge_idx() IBC_mbvd_merge_idx=%d\n", pu.ibcMbvdMergeIdx);
+}
+#endif
+
 #if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
 void CABACReader::tm_merge_flag(PredictionUnit& pu)
 {
@@ -3539,8 +3608,18 @@ void CABACReader::merge_data( PredictionUnit& pu )
 {
   if (CU::isIBC(*pu.cu))
   {
+#if JVET_AA0061_IBC_MBVD
+    ibcMbvdData(pu);
+#endif
 #if JVET_Z0084_IBC_TM && IBC_TM_MRG
-    tm_merge_flag(pu);
+#if JVET_AA0061_IBC_MBVD
+    if (!pu.ibcMbvdMergeFlag)
+    {
+#endif
+      tm_merge_flag(pu);
+#if JVET_AA0061_IBC_MBVD
+    }
+#endif
 #endif
     merge_idx(pu);
     return;
@@ -3892,6 +3971,12 @@ void CABACReader::merge_idx( PredictionUnit& pu )
 
   if (pu.cu->predMode == MODE_IBC)
   {
+#if JVET_AA0061_IBC_MBVD
+    if (pu.ibcMbvdMergeFlag)
+    {
+      return;
+    }
+#endif
     numCandminus1 = int(pu.cs->sps->getMaxNumIBCMergeCand()) - 1;
   }
 #if TM_MRG
@@ -4851,8 +4936,26 @@ bool CABACReader::cbf_comp( CodingStructure& cs, const CompArea& area, unsigned
 //--------------------------------------------------------------------------------
 //    void  mvd_coding( pu, refList )
 //================================================================================
-
-void CABACReader::mvd_coding( Mv &rMvd 
+#if JVET_AA0070_RRIBC
+void CABACReader::mvd_coding( Mv &rMvd
+#if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
+  , bool codeSign
+#endif
+  , const int &rribcFlipType
+)
+{
+  // abs_mvd_greater0_flag[ 0 | 1 ]
+  int horAbs = 0, verAbs = 0;
+  if (rribcFlipType != 2)
+  {
+    horAbs = (int) m_BinDecoder.decodeBin(Ctx::Mvd());
+  }
+  if (rribcFlipType != 1)
+  {
+    verAbs = (int) m_BinDecoder.decodeBin(Ctx::Mvd());
+  }
+#else
+void CABACReader::mvd_coding( Mv &rMvd
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
   , bool codeSign
 #endif
@@ -4861,6 +4964,7 @@ void CABACReader::mvd_coding( Mv &rMvd
   // abs_mvd_greater0_flag[ 0 | 1 ]
   int horAbs = (int)m_BinDecoder.decodeBin(Ctx::Mvd());
   int verAbs = (int)m_BinDecoder.decodeBin(Ctx::Mvd());
+#endif
 
   // abs_mvd_greater1_flag[ 0 | 1 ]
   if (horAbs)
@@ -4934,10 +5038,24 @@ unsigned CABACReader::xReadBvdContext(unsigned ctxT, int offset, int param)
 #endif
 
 #if JVET_Z0131_IBC_BVD_BINARIZATION
+#if JVET_AA0070_RRIBC
+void CABACReader::bvdCoding(Mv &rMvd, const int &rribcFlipType)
+{
+  int horAbs = 0, verAbs = 0;
+  if (rribcFlipType != 2)
+  {
+    horAbs = (int) m_BinDecoder.decodeBin(Ctx::Bvd(HOR_BVD_CTX_OFFSET));
+  }
+  if (rribcFlipType != 1)
+  {
+    verAbs = (int) m_BinDecoder.decodeBin(Ctx::Bvd(VER_BVD_CTX_OFFSET));
+  }
+#else
 void CABACReader::bvdCoding( Mv &rMvd )
 {
   int horAbs = (int)m_BinDecoder.decodeBin(Ctx::Bvd(HOR_BVD_CTX_OFFSET));
   int verAbs = (int)m_BinDecoder.decodeBin(Ctx::Bvd(VER_BVD_CTX_OFFSET));
+#endif
 
   if (horAbs)
   {
@@ -6427,6 +6545,27 @@ void CABACReader::cu_lic_flag( CodingUnit& cu )
 }
 #endif
 
+#if JVET_AA0070_RRIBC
+void CABACReader::rribcData(CodingUnit &cu)
+{
+  if (!CU::isIBC(cu) || cu.firstPU->mergeFlag)
+  {
+    return;
+  }
+
+  cu.rribcFlipType = 0;
+
+  unsigned ctxId   = DeriveCtx::CtxRribcFlipType(cu);
+  cu.rribcFlipType = (m_BinDecoder.decodeBin(Ctx::rribcFlipType(ctxId)));
+  if (cu.rribcFlipType)
+  {
+    cu.rribcFlipType += m_BinDecoder.decodeBin(Ctx::rribcFlipType(3));
+  }
+  DTRACE(g_trace_ctx, D_SYNTAX, "rribcData() rribcFlipType = %d\n", cu.rribcFlipType);
+}
+#endif
+
+
 #if SIGN_PREDICTION
 void CABACReader::parsePredictedSigns( TransformUnit &tu, ComponentID compID )
 {
diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h
index 3825af393018ae55d76c0d3b2ac144af430b7ade..1f5b452f32fac785920aa8f91ce02836a6c9ab3b 100644
--- a/source/Lib/DecoderLib/CABACReader.h
+++ b/source/Lib/DecoderLib/CABACReader.h
@@ -155,6 +155,9 @@ public:
 #if AFFINE_MMVD
   void        affine_mmvd_data          ( PredictionUnit&               pu );
 #endif
+#if JVET_AA0061_IBC_MBVD
+  void        ibcMbvdData             ( PredictionUnit&               pu );
+#endif
 #if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
   void        tm_merge_flag             ( PredictionUnit&               pu );
 #endif
@@ -205,6 +208,17 @@ public:
   bool        cbf_comp                  ( CodingStructure&              cs,     const CompArea& area,     unsigned depth, const bool prevCbf = false, const bool useISP = false );
 
   // mvd coding (clause 7.3.8.9)
+#if JVET_AA0070_RRIBC
+#if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
+   void        mvd_coding                ( Mv &rMvd, bool codeSign = true, const int &rribcFlipType = 0);
+#else
+   void        mvd_coding                ( Mv &rMvd, const int &rribcFlipType = 0);
+#endif
+#if JVET_Z0131_IBC_BVD_BINARIZATION
+  void        bvdCoding                ( Mv &rMvd, const int &rribcFlipType = 0);
+  unsigned    xReadBvdContext(unsigned ctxT, int offset, int param);
+#endif
+#else
   void        mvd_coding                ( Mv &rMvd 
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
     , bool codeSign = true
@@ -214,6 +228,7 @@ public:
   void        bvdCoding                ( Mv &rMvd );
   unsigned    xReadBvdContext(unsigned ctxT, int offset, int param);
 #endif
+#endif
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
   void        mvsdIdxFunc(PredictionUnit &pu, RefPicList eRefList);
   void        mvsdAffineIdxFunc(PredictionUnit &pu, RefPicList eRefList);
@@ -268,6 +283,9 @@ public:
   void        cu_lic_flag               ( CodingUnit& cu );
 #endif
 
+#if JVET_AA0070_RRIBC
+  void        rribcData                ( CodingUnit &cu );
+#endif
 #if JVET_Z0135_TEMP_CABAC_WIN_WEIGHT
   CABACDataStore*         m_CABACDataStore;
 #endif
diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp
index f00b2d95a114868980d389d1d2e1eb63c9db7388..4a75ab93182938b52e11f817f9946d20a8acdf95 100644
--- a/source/Lib/DecoderLib/DecCu.cpp
+++ b/source/Lib/DecoderLib/DecCu.cpp
@@ -1376,6 +1376,17 @@ void DecCu::xReconInter(CodingUnit &cu)
       cs.getRecoBuf(cu).get(COMPONENT_Y).rspSignal(m_pcReshape->getFwdLUT());
     }
   }
+#if JVET_AA0070_RRIBC
+  if (CU::isIBC(cu) && cu.rribcFlipType)
+  {
+    cu.cs->getRecoBuf(cu).get(COMPONENT_Y).flipSignal(cu.rribcFlipType == 1);
+    if (isChromaEnabled(cu.chromaFormat) && cu.Cb().valid())
+    {
+      cu.cs->getRecoBuf(cu).get(COMPONENT_Cb).flipSignal(cu.rribcFlipType == 1);
+      cu.cs->getRecoBuf(cu).get(COMPONENT_Cr).flipSignal(cu.rribcFlipType == 1);
+    }
+  }
+#endif
 #endif
 
   DTRACE    ( g_trace_ctx, D_TMP, "reco " );
@@ -1503,6 +1514,12 @@ void DecCu::xDecodeInterTU( TransformUnit & currTU, const ComponentID compID )
     else
     {
       currTU.cs->getRecoBuf( currTU.blocks[currCompID] ).reconstruct( cs.getPredBuf( currTU.blocks[currCompID] ), compResiBuf, currTU.cu->cs->slice->clpRng( currCompID ) );
+#if JVET_AA0070_RRIBC
+      if (CU::isIBC(*currTU.cu) && currTU.cu->rribcFlipType)
+      {
+        currTU.cs->getRecoBuf(currTU.blocks[currCompID]).flipSignal(currTU.cu->rribcFlipType == 1);
+      }
+#endif
     }
   }
 #endif
@@ -1523,7 +1540,21 @@ void DecCu::xDecodeInterTexture(CodingUnit &cu)
     {
       cs.getRecoBuf(cu).get(COMPONENT_Y).rspSignal(m_pcReshape->getFwdLUT());
     }
+
+#if JVET_AA0070_RRIBC
+    if (CU::isIBC(cu) && cu.rribcFlipType)
+    {
+      cu.cs->getRecoBuf(cu).get(COMPONENT_Y).flipSignal(cu.rribcFlipType == 1);
+      if (isChromaEnabled(cu.chromaFormat) && cu.Cb().valid())
+      {
+        cu.cs->getRecoBuf(cu).get(COMPONENT_Cb).flipSignal(cu.rribcFlipType == 1);
+        cu.cs->getRecoBuf(cu).get(COMPONENT_Cr).flipSignal(cu.rribcFlipType == 1);
+      }
+    }
+#endif
 #endif
+
+
     return;
   }
 
@@ -1934,26 +1965,48 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
 #endif
           if (CU::isIBC(*pu.cu))
           {
-#if JVET_Y0058_IBC_LIST_MODIFY && JVET_W0090_ARMC_TM
-            if (pu.cs->sps->getUseAML())
+#if JVET_AA0061_IBC_MBVD
+            if (pu.ibcMbvdMergeFlag)
+            {
+              int fPosIBCBaseIdx = pu.ibcMbvdMergeIdx / IBC_MBVD_MAX_REFINE_NUM;
+              PU::getIBCMergeCandidates(pu, mrgCtx);
+              m_pcInterPred->adjustIBCMergeCandidates(pu, mrgCtx, 0, IBC_MRG_MAX_NUM_CANDS_MEM);
+
+              PU::getIbcMbvdMergeCandidates(pu, mrgCtx, fPosIBCBaseIdx + 1);
+
+              uint32_t ibcMbvdLUT[IBC_MBVD_NUM];
+              uint32_t ibcMbvdValidNum[IBC_MBVD_BASE_NUM] = { 0 };
+              int      ibcMbvdIdx= pu.ibcMbvdMergeIdx;
+              m_pcInterPred->sortIbcMergeMbvdCandidates(pu, mrgCtx, ibcMbvdLUT, ibcMbvdValidNum, ibcMbvdIdx);
+              bool mbvdCandMisAlign = mrgCtx.setIbcMbvdMergeCandiInfo(pu, ibcMbvdIdx, ibcMbvdLUT[ibcMbvdIdx]);
+              CHECK(mbvdCandMisAlign, "MBVD candidate is invalid");
+            }
+            else
             {
+#endif
+#if JVET_Y0058_IBC_LIST_MODIFY && JVET_W0090_ARMC_TM
+              if (pu.cs->sps->getUseAML())
+              {
 #if JVET_Z0075_IBC_HMVP_ENLARGE
 #if JVET_AA0093_ENHANCED_MMVD_EXTENSION
               uint16_t mrgCandIdx = pu.mergeIdx;
 #else
               uint8_t mrgCandIdx = pu.mergeIdx;
 #endif
-              PU::getIBCMergeCandidates(pu, mrgCtx);
-              m_pcInterPred->adjustIBCMergeCandidates(pu, mrgCtx, 0, IBC_MRG_MAX_NUM_CANDS_MEM);
-              pu.mergeIdx = mrgCandIdx;
+                PU::getIBCMergeCandidates(pu, mrgCtx);
+                m_pcInterPred->adjustIBCMergeCandidates(pu, mrgCtx, 0, IBC_MRG_MAX_NUM_CANDS_MEM);
+                pu.mergeIdx = mrgCandIdx;
 #else
-              PU::getIBCMergeCandidates(pu, mrgCtx, (((pu.mergeIdx / ADAPTIVE_IBC_SUB_GROUP_SIZE + 1)*ADAPTIVE_IBC_SUB_GROUP_SIZE < pu.cs->sps->getMaxNumIBCMergeCand()) || (pu.mergeIdx / ADAPTIVE_IBC_SUB_GROUP_SIZE) == 0) ? pu.mergeIdx / ADAPTIVE_IBC_SUB_GROUP_SIZE * ADAPTIVE_IBC_SUB_GROUP_SIZE + ADAPTIVE_IBC_SUB_GROUP_SIZE - 1 : pu.mergeIdx);
-              m_pcInterPred->adjustIBCMergeCandidates(pu, mrgCtx, pu.mergeIdx);
+                PU::getIBCMergeCandidates(pu, mrgCtx, (((pu.mergeIdx / ADAPTIVE_IBC_SUB_GROUP_SIZE + 1) * ADAPTIVE_IBC_SUB_GROUP_SIZE < pu.cs->sps->getMaxNumIBCMergeCand()) || (pu.mergeIdx / ADAPTIVE_IBC_SUB_GROUP_SIZE) == 0) ? pu.mergeIdx / ADAPTIVE_IBC_SUB_GROUP_SIZE * ADAPTIVE_IBC_SUB_GROUP_SIZE + ADAPTIVE_IBC_SUB_GROUP_SIZE - 1 : pu.mergeIdx);
+                m_pcInterPred->adjustIBCMergeCandidates(pu, mrgCtx, pu.mergeIdx);
+#endif
+              }
+              else
 #endif
+                PU::getIBCMergeCandidates(pu, mrgCtx, pu.mergeIdx);
+#if JVET_AA0061_IBC_MBVD
             }
-            else
 #endif
-              PU::getIBCMergeCandidates(pu, mrgCtx, pu.mergeIdx);
           }
           else
 #if JVET_X0049_ADAPT_DMVR
@@ -2405,8 +2458,15 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
             }
 #else
             PU::getInterMergeCandidates(pu, mrgCtx, 0, pu.mergeIdx);
+#endif
+#if JVET_AA0061_IBC_MBVD
+          if (!pu.ibcMbvdMergeFlag)
+          {
 #endif
           mrgCtx.setMergeInfo( pu, pu.mergeIdx );
+#if JVET_AA0061_IBC_MBVD
+          }
+#endif
 #if JVET_AA0093_REFINED_MOTION_FOR_ARMC
           if (pu.tmMergeFlag && tmMergeRefinedMotion)
           {
@@ -2716,6 +2776,16 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
           }
           pu.mv[REF_PIC_LIST_0] = amvpInfo.mvCand[pu.mvpIdx[REF_PIC_LIST_0]] + mvd;
           pu.mv[REF_PIC_LIST_0].mvCliptoStorageBitDepth();
+#if JVET_AA0070_RRIBC
+          if (pu.cu->rribcFlipType == 1)
+          {
+            pu.mv[REF_PIC_LIST_0].setVer(0);
+          }
+          else if (pu.cu->rribcFlipType == 2)
+          {
+            pu.mv[REF_PIC_LIST_0].setHor(0);
+          }
+#endif
 #if JVET_Z0160_IBC_ZERO_PADDING
           pu.bv = pu.mv[0];
           pu.bv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT);
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index d3539facebf902f6ad8106aabc73babf93c81611..377df7775dfee0d1899b9b8cf9a60e6db6285c33 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -2464,6 +2464,9 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
     READ_UVLC(uiCode, "six_minus_max_num_ibc_merge_cand");
     CHECK(IBC_MRG_MAX_NUM_CANDS <= uiCode, "Incorrrect max number of IBC merge candidates!");
     pcSPS->setMaxNumIBCMergeCand(IBC_MRG_MAX_NUM_CANDS - uiCode);
+#if JVET_AA0061_IBC_MBVD
+    READ_FLAG( uiCode, "sps_ibc_mbvd_enabled_flag" );                   pcSPS->setUseIbcMbvd             ( uiCode != 0 );
+#endif
   }
   else
     pcSPS->setMaxNumIBCMergeCand(0);
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index e4730b65018b3554b82529efcc81f1e47c7aaef7..bfd0b401fc82d6e80f25e8f450be5cb46fb4efca 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -2670,6 +2670,9 @@ void CABACWriter::prediction_unit( const PredictionUnit& pu )
   {
     merge_flag( pu );
   }
+#if JVET_AA0070_RRIBC
+  rribcData(*pu.cu);
+#endif
   if( pu.mergeFlag )
   {
     merge_data(pu);
@@ -2690,10 +2693,18 @@ void CABACWriter::prediction_unit( const PredictionUnit& pu )
     ref_idx(pu, REF_PIC_LIST_0);
     Mv mvd = pu.mvd[REF_PIC_LIST_0];
     mvd.changeIbcPrecInternal2Amvr(pu.cu->imv);
+#if JVET_AA0070_RRIBC
+#if JVET_Z0131_IBC_BVD_BINARIZATION
+    bvdCoding(mvd, 0, pu.cu->rribcFlipType); // already changed to signaling precision
+#else
+    mvd_coding(mvd, 0, true, pu.cu->rribcFlipType); // already changed to signaling precision
+#endif
+#else
 #if JVET_Z0131_IBC_BVD_BINARIZATION
     bvdCoding(mvd, 0); // already changed to signaling precision
 #else
     mvd_coding(mvd, 0); // already changed to signaling precision
+#endif
 #endif
     if (pu.cs->sps->getMaxNumIBCMergeCand() == 1)
     {
@@ -3083,6 +3094,68 @@ void CABACWriter::affine_mmvd_data(const PredictionUnit& pu)
 }
 #endif
 
+#if JVET_AA0061_IBC_MBVD
+void CABACWriter::ibcMbvdData(const PredictionUnit& pu)
+{
+  if (!pu.cs->sps->getUseIbcMbvd() || !pu.mergeFlag || !CU::isIBC(*pu.cu))
+  {
+    return;
+  }
+  m_BinEncoder.encodeBin(pu.ibcMbvdMergeFlag, Ctx::IbcMbvdFlag());
+  DTRACE(g_trace_ctx, D_SYNTAX, "IBC_mbvd_flag() IBC_mbvd_merge=%d pos=(%d,%d) size=%dx%d\n", pu.ibcMbvdMergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height);
+
+  if (!pu.ibcMbvdMergeFlag)
+  {
+    return;
+  }
+  int mvpIdx = pu.ibcMbvdMergeIdx;
+  uint8_t var0;
+  var0 = mvpIdx / IBC_MBVD_MAX_REFINE_NUM;
+  mvpIdx -= var0 * IBC_MBVD_MAX_REFINE_NUM;
+
+  // Base affine merge candidate idx
+
+  int numBaseCandMinus1 = IBC_MBVD_BASE_NUM - 1;
+  if (numBaseCandMinus1 > 0)
+  {
+    // to support more base candidates
+    m_BinEncoder.encodeBin((var0 == 0 ? 0 : 1), Ctx::IbcMbvdMergeIdx());
+
+    if (var0 > 0)
+    {
+      for (unsigned idx = 1; idx < numBaseCandMinus1; idx++)
+      {
+        m_BinEncoder.encodeBinEP(var0 == idx ? 0 : 1);
+        if (var0 == idx)
+        {
+          break;
+        }
+      }
+    }
+  }
+  DTRACE(g_trace_ctx, D_SYNTAX, "ibcMbvdBaseIdx() ibcMbvdBaseIdx=%d\n", var0);
+
+  unsigned int ricePar = 1;
+  int numCandStepMinus1 = (IBC_MBVD_SIZE_ENC >> ricePar) - 1;
+  if(ricePar > 0)
+  {
+    m_BinEncoder.encodeBinsEP( mvpIdx % (1 << ricePar), ricePar);
+  }
+  mvpIdx >>= ricePar;
+  for (unsigned int uiUnaryIdx = 0; uiUnaryIdx < numCandStepMinus1; ++uiUnaryIdx)
+  {
+    unsigned int uiSymbol = mvpIdx == uiUnaryIdx ? 0 : 1;
+    m_BinEncoder.encodeBin(uiSymbol, Ctx::IbcMbvdStepMvpIdx((uiUnaryIdx > LAST_MERGE_MMVD_IDX_CABAC - 1 ? LAST_MERGE_MMVD_IDX_CABAC - 1 : uiUnaryIdx)));
+    if (uiSymbol == 0)
+    {
+      break;
+    }
+  }
+
+  DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_merge_idx() mmvd_merge_idx=%d\n", pu.ibcMbvdMergeIdx);
+}
+#endif
+
 #if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
 void CABACWriter::tm_merge_flag(const PredictionUnit& pu)
 {
@@ -3145,8 +3218,18 @@ void CABACWriter::merge_data(const PredictionUnit& pu)
 {
   if (CU::isIBC(*pu.cu))
   {
+#if JVET_AA0061_IBC_MBVD
+    ibcMbvdData(pu);
+#endif
 #if JVET_Z0084_IBC_TM && IBC_TM_MRG
-    tm_merge_flag(pu);
+#if JVET_AA0061_IBC_MBVD
+    if (!pu.ibcMbvdMergeFlag)
+    {
+#endif
+      tm_merge_flag(pu);
+#if JVET_AA0061_IBC_MBVD
+    }
+#endif
 #endif
     merge_idx(pu);
     return;
@@ -3525,7 +3608,17 @@ void CABACWriter::merge_idx( const PredictionUnit& pu )
 #endif
 #endif
     if (pu.cu->predMode == MODE_IBC)
+#if JVET_AA0061_IBC_MBVD
+    {
+      if (pu.ibcMbvdMergeFlag)
+      {
+        return;
+      }
+#endif
       numCandminus1 = int(pu.cs->sps->getMaxNumIBCMergeCand()) - 1;
+#if JVET_AA0061_IBC_MBVD
+    }
+#endif
 #if TM_MRG
     else if (pu.tmMergeFlag)
 #if JVET_X0141_CIIP_TIMD_TM
@@ -4627,6 +4720,9 @@ void CABACWriter::mvd_coding( const Mv &rMvd, int8_t imv
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
   , bool codeSign
 #endif
+#if JVET_AA0070_RRIBC
+  , const int &rribcFlipType
+#endif
 )
 {
   int       horMvd = rMvd.getHor();
@@ -4654,8 +4750,19 @@ void CABACWriter::mvd_coding( const Mv &rMvd, int8_t imv
 
 
   // abs_mvd_greater0_flag[ 0 | 1 ]
-  m_BinEncoder.encodeBin( (horAbs > 0), Ctx::Mvd() );
-  m_BinEncoder.encodeBin( (verAbs > 0), Ctx::Mvd() );
+#if JVET_AA0070_RRIBC
+  if (rribcFlipType != 2)
+  {
+    m_BinEncoder.encodeBin((horAbs > 0), Ctx::Mvd());
+  }
+  if (rribcFlipType != 1)
+  {
+    m_BinEncoder.encodeBin((verAbs > 0), Ctx::Mvd());
+  }
+#else
+  m_BinEncoder.encodeBin((horAbs > 0), Ctx::Mvd());
+  m_BinEncoder.encodeBin((verAbs > 0), Ctx::Mvd());
+#endif
 
   // abs_mvd_greater1_flag[ 0 | 1 ]
   if( horAbs > 0 )
@@ -4729,7 +4836,11 @@ void CABACWriter::xWriteBvdContext(unsigned uiSymbol, unsigned ctxT, int offset,
 #endif
 
 #if JVET_Z0131_IBC_BVD_BINARIZATION
-void CABACWriter::bvdCoding( const Mv &rMvd, int8_t imv )
+#if JVET_AA0070_RRIBC
+void CABACWriter::bvdCoding(const Mv &rMvd, int8_t imv, const int &rribcFlipType)
+#else
+void CABACWriter::bvdCoding( const Mv &rMvd, int8_t imv)
+#endif
 {
   int       horMvd = rMvd.getHor();
   int       verMvd = rMvd.getVer();
@@ -4737,8 +4848,19 @@ void CABACWriter::bvdCoding( const Mv &rMvd, int8_t imv )
   unsigned  horAbs  = unsigned( horMvd < 0 ? -horMvd : horMvd );
   unsigned  verAbs  = unsigned( verMvd < 0 ? -verMvd : verMvd );
 
+#if JVET_AA0070_RRIBC
+  if (rribcFlipType != 2)
+  {
+    m_BinEncoder.encodeBin((horAbs > 0), Ctx::Bvd(HOR_BVD_CTX_OFFSET));
+  }
+  if (rribcFlipType != 1)
+  {
+    m_BinEncoder.encodeBin((verAbs > 0), Ctx::Bvd(VER_BVD_CTX_OFFSET));
+  }
+#else
   m_BinEncoder.encodeBin( (horAbs > 0), Ctx::Bvd(HOR_BVD_CTX_OFFSET) );
   m_BinEncoder.encodeBin( (verAbs > 0), Ctx::Bvd(VER_BVD_CTX_OFFSET) );
+#endif
 
   if( horAbs > 0 )
   {
@@ -6377,6 +6499,25 @@ void CABACWriter::cu_lic_flag(const CodingUnit& cu)
 }
 #endif
 
+#if JVET_AA0070_RRIBC
+void CABACWriter::rribcData(const CodingUnit& cu)
+{
+  if (!CU::isIBC(cu) || cu.firstPU->mergeFlag)
+  {
+    return;
+  }
+
+  unsigned ctxId = DeriveCtx::CtxRribcFlipType(cu);
+  m_BinEncoder.encodeBin(cu.rribcFlipType > 0, Ctx::rribcFlipType(ctxId));
+  if (cu.rribcFlipType)
+  {
+    CHECK(cu.rribcFlipType != 1 && cu.rribcFlipType != 2, "cu.rribcFlipType != 1 && cu.rribcFlipType != 2");
+    m_BinEncoder.encodeBin(cu.rribcFlipType >> 1, Ctx::rribcFlipType(3));
+  }
+  DTRACE(g_trace_ctx, D_SYNTAX, "rribcData() rribcFlipType = %d\n", cu.rribcFlipType);
+}
+#endif
+
 #if SIGN_PREDICTION
 #if JVET_Y0141_SIGN_PRED_IMPROVE
 struct signCombInfo
diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h
index 05c2bf5d0c05c19e5e70dbf0bb09b08cd816a831..09e5b24573169b537d54923b396f3bcc9940ac69 100644
--- a/source/Lib/EncoderLib/CABACWriter.h
+++ b/source/Lib/EncoderLib/CABACWriter.h
@@ -166,6 +166,9 @@ public:
 #if AFFINE_MMVD
   void        affine_mmvd_data          ( const PredictionUnit&         pu );
 #endif
+#if JVET_AA0061_IBC_MBVD
+  void        ibcMbvdData             ( const PredictionUnit&         pu );
+#endif
 #if TM_MRG || (JVET_Z0084_IBC_TM && IBC_TM_MRG)
   void        tm_merge_flag             ( const PredictionUnit&         pu);
 #endif
@@ -231,15 +234,28 @@ public:
   void        cbf_comp                  ( const CodingStructure&        cs,       bool              cbf,    const CompArea& area, unsigned depth, const bool prevCbf = false, const bool useISP = false );
 
   // mvd coding (clause 7.3.8.9)
+#if JVET_AA0070_RRIBC
+#if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
+  void        mvd_coding                ( const Mv &rMvd, int8_t imv, bool codeSign = true, const int &rribcFlipType = 0 );
+#else
+  void        mvd_coding                ( const Mv &rMvd, int8_t imv, const int &rribcFlipType = 0 );
+#endif
+#if JVET_Z0131_IBC_BVD_BINARIZATION
+  void        bvdCoding                ( const Mv &rMvd, int8_t imv, const int &rribcFlipType = 0 );
+  void        xWriteBvdContext(unsigned uiSymbol, unsigned ctxT, int offset, int param);
+#endif
+#else
   void        mvd_coding                ( const Mv &rMvd, int8_t imv 
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
     , bool codeSign = true
 #endif
   );
+
 #if JVET_Z0131_IBC_BVD_BINARIZATION
   void        bvdCoding                ( const Mv &rMvd, int8_t imv );
   void        xWriteBvdContext(unsigned uiSymbol, unsigned ctxT, int offset, int param);
 #endif
+#endif
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
   void mvsdIdxFunc(const PredictionUnit &pu, RefPicList eRefList);
   void mvsdAffineIdxFunc(const PredictionUnit &pu, RefPicList eRefList);
@@ -288,6 +304,9 @@ public:
   void        cu_lic_flag               ( const CodingUnit& cu );
 #endif
 
+#if JVET_AA0070_RRIBC
+  void        rribcData                ( const CodingUnit &cu);
+#endif
 #if JVET_Z0135_TEMP_CABAC_WIN_WEIGHT
   CABACDataStore*         m_CABACDataStore;
 #endif
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index 8a488b86cbd8aec3e0dc18db7a0c2c929535da0d..fd74572ac1f8c6dc35a31803937c487336be57e4 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -470,6 +470,9 @@ protected:
   unsigned  m_IBCHashSearchMaxCand;
   unsigned  m_IBCHashSearchRange4SmallBlk;
   unsigned  m_IBCFastMethod;
+#if JVET_AA0061_IBC_MBVD
+  bool      m_ibcMbvd;
+#endif
 
   bool      m_wrapAround;
   unsigned  m_wrapAroundOffset;
@@ -1328,6 +1331,10 @@ public:
   void      setAffineMmvdMode               ( bool b )       { m_AffineMmvdMode = b; }
   bool      getAffineMmvdMode               ()         const { return m_AffineMmvdMode; }
 #endif
+#if JVET_AA0061_IBC_MBVD
+  void      setIbcMbvd                      ( bool b )       { m_ibcMbvd = b; }
+  bool      getIbcMbvd                      ()         const { return m_ibcMbvd; }
+#endif
 #if TM_AMVP || TM_MRG || JVET_Z0084_IBC_TM || MULTI_PASS_DMVR
   void      setUseDMVDMode                  (bool b)         { m_DMVDMode = b; }
   bool      getUseDMVDMode                  ()         const { return m_DMVDMode; }
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 946892d1bbebe2d67a62008ad3ee4a7b71f03d35..01cd9327a692c857d93228e18d725f0be89505be 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -1337,6 +1337,22 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par
     }
     else if (currTestMode.type == ETM_IBC)
     {
+#if JVET_AA0070_RRIBC
+      if (m_pcEncCfg->getIntraPeriod() <= 1)
+      {
+        CodedCUInfo &relatedCU = ((EncModeCtrlMTnoRQT *) m_modeCtrl)->getBlkInfo(partitioner.currArea());
+        if (!relatedCU.isRribcTested)
+        {
+          xCheckRDCostIBCMode(tempCS, bestCS, partitioner, currTestMode);
+          relatedCU.isRribcTested = 1;
+        }
+        else
+        {
+          xCheckRDCostIBCMode(tempCS, bestCS, partitioner, currTestMode, true);
+        }
+      }
+      else
+#endif
       xCheckRDCostIBCMode(tempCS, bestCS, partitioner, currTestMode);
 #if JVET_Y0152_TT_ENC_SPEEDUP
       splitRdCostBest[CTU_LEVEL] = bestCS->cost;
@@ -3895,7 +3911,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #endif
   };
 #endif
-  static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  RdModeList;
+  static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  rdModeList;
   bool                                        mrgTempBufSet = false;
   const int candNum = mergeCtx.numValidMergeCand + (tempCS->sps->getUseMMVD() ? std::min<int>(MMVD_BASE_MV_NUM, mergeCtx.numValidMergeCand) * MMVD_MAX_REFINE_NUM : 0);
 
@@ -3906,22 +3922,22 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #if CIIP_PDPC
 #if MERGE_ENC_OPT
 #if JVET_X0141_CIIP_TIMD_TM && JVET_W0123_TIMD_FUSION
-      RdModeList.push_back(ModeInfo(i, true, false, false, false, 0, false));
+      rdModeList.push_back(ModeInfo(i, true, false, false, false, 0, false));
 #else
-      RdModeList.push_back(ModeInfo(i, true, false, false, false, false));
+      rdModeList.push_back(ModeInfo(i, true, false, false, false, false));
 #endif
 #else
-      RdModeList.push_back(ModeInfo(i, true, false, false, false));
+      rdModeList.push_back(ModeInfo(i, true, false, false, false));
 #endif
 #else
 #if MERGE_ENC_OPT
 #if JVET_X0141_CIIP_TIMD_TM && JVET_W0123_TIMD_FUSION
-      RdModeList.push_back(ModeInfo(i, true, false, false, 0, false));
+      rdModeList.push_back(ModeInfo(i, true, false, false, 0, false));
 #else
-      RdModeList.push_back(ModeInfo(i, true, false, false, false));
+      rdModeList.push_back(ModeInfo(i, true, false, false, false));
 #endif
 #else
-      RdModeList.push_back(ModeInfo(i, true, false, false));
+      rdModeList.push_back(ModeInfo(i, true, false, false));
 #endif
 #endif
     }
@@ -3930,22 +3946,22 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #if MERGE_ENC_OPT
 #if CIIP_PDPC
 #if JVET_X0141_CIIP_TIMD_TM && JVET_W0123_TIMD_FUSION
-      RdModeList.push_back(ModeInfo(std::min(MMVD_ADD_NUM, i - mergeCtx.numValidMergeCand), false, true, false, false, 0, false));
+      rdModeList.push_back(ModeInfo(std::min(MMVD_ADD_NUM, i - mergeCtx.numValidMergeCand), false, true, false, false, 0, false));
 #else
-      RdModeList.push_back(ModeInfo(std::min(MMVD_ADD_NUM, i - mergeCtx.numValidMergeCand), false, true, false, false, false));
+      rdModeList.push_back(ModeInfo(std::min(MMVD_ADD_NUM, i - mergeCtx.numValidMergeCand), false, true, false, false, false));
 #endif
 #else
 #if JVET_X0141_CIIP_TIMD_TM && JVET_W0123_TIMD_FUSION
-      RdModeList.push_back(ModeInfo(std::min(MMVD_ADD_NUM, i - mergeCtx.numValidMergeCand), false, true, false, 0, false));
+      rdModeList.push_back(ModeInfo(std::min(MMVD_ADD_NUM, i - mergeCtx.numValidMergeCand), false, true, false, 0, false));
 #else
-      RdModeList.push_back(ModeInfo(std::min(MMVD_ADD_NUM, i - mergeCtx.numValidMergeCand), false, true, false, false));
+      rdModeList.push_back(ModeInfo(std::min(MMVD_ADD_NUM, i - mergeCtx.numValidMergeCand), false, true, false, false));
 #endif
 #endif
 #else
 #if CIIP_PDPC
-      RdModeList.push_back(ModeInfo(std::min(MMVD_ADD_NUM, i - mergeCtx.numValidMergeCand), false, true, false, false));
+      rdModeList.push_back(ModeInfo(std::min(MMVD_ADD_NUM, i - mergeCtx.numValidMergeCand), false, true, false, false));
 #else
-      RdModeList.push_back(ModeInfo(std::min(MMVD_ADD_NUM, i - mergeCtx.numValidMergeCand), false, true, false));
+      rdModeList.push_back(ModeInfo(std::min(MMVD_ADD_NUM, i - mergeCtx.numValidMergeCand), false, true, false));
 #endif
 #endif
     }
@@ -4038,7 +4054,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
     // 1. Pass: get SATD-cost for selected candidates and reduce their count
     if( !bestIsSkip )
     {
-      RdModeList.clear();
+      rdModeList.clear();
       mrgTempBufSet       = true;
       const TempCtx ctxStart(m_CtxCache, m_CABACEstimator->getCtx());
 
@@ -4093,7 +4109,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #if !MULTI_PASS_DMVR
                                , refinedMvdL0
 #endif
-                               , uiNumMrgSATDCand, RdModeList, candCostList, distParam, ctxStart
+                               , uiNumMrgSATDCand, rdModeList, candCostList, distParam, ctxStart
 #if MULTI_PASS_DMVR
                                , applyBDMVR
 #endif
@@ -4209,26 +4225,26 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #endif
         insertPos = -1;
 #if CIIP_PDPC
-        updateCandList(ModeInfo(uiMergeCand, true, false, false, false), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+        updateCandList(ModeInfo(uiMergeCand, true, false, false, false), cost, rdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
 #else
-        updateCandList(ModeInfo(uiMergeCand, true, false, false), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+        updateCandList(ModeInfo(uiMergeCand, true, false, false), cost, rdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
 #endif
         if (insertPos != -1)
         {
-          if (insertPos == RdModeList.size() - 1)
+          if (insertPos == rdModeList.size() - 1)
           {
             swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
           }
           else
           {
-            for (uint32_t i = uint32_t(RdModeList.size()) - 1; i > insertPos; i--)
+            for (uint32_t i = uint32_t(rdModeList.size()) - 1; i > insertPos; i--)
             {
               swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
             }
             swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
           }
         }
-        CHECK(std::min(uiMergeCand + 1, uiNumMrgSATDCand) != RdModeList.size(), "");
+        CHECK(std::min(uiMergeCand + 1, uiNumMrgSATDCand) != rdModeList.size(), "");
 #if MULTI_PASS_DMVR
         pu.bdmvrRefine = false;
 #endif
@@ -4237,11 +4253,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
       if (isIntrainterEnabled)
       {
 #if MERGE_ENC_OPT
-        xCheckSATDCostCiipMerge(tempCS, cu, pu, mergeCtx, acMergeTempBuffer, singleMergeTempBuffer, acMergeTmpBuffer, uiNumMrgSATDCand, RdModeList, candCostList, distParam, ctxStart);
+        xCheckSATDCostCiipMerge(tempCS, cu, pu, mergeCtx, acMergeTempBuffer, singleMergeTempBuffer, acMergeTmpBuffer, uiNumMrgSATDCand, rdModeList, candCostList, distParam, ctxStart);
 #if JVET_X0141_CIIP_TIMD_TM && TM_MRG
         if (sps.getUseCiipTmMrg())
         {
-            xCheckSATDCostCiipTmMerge(tempCS, cu, pu, ciipTmMrgCtx, acMergeTempBuffer, singleMergeTempBuffer, acTmMergeTmpBuffer, uiNumMrgSATDCand, RdModeList, candCostList, distParam, ctxStart);
+            xCheckSATDCostCiipTmMerge(tempCS, cu, pu, ciipTmMrgCtx, acMergeTempBuffer, singleMergeTempBuffer, acTmMergeTmpBuffer, uiNumMrgSATDCand, rdModeList, candCostList, distParam, ctxStart);
         }
 #endif
 #else
@@ -4252,7 +4268,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
         uint32_t CiipMergeCand[NUM_MRG_SATD_CAND];
         for (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, (const int)mergeCtx.numValidMergeCand); mergeCnt++)
         {
-          CiipMergeCand[mergeCnt] = RdModeList[mergeCnt].mergeCand;
+          CiipMergeCand[mergeCnt] = rdModeList[mergeCnt].mergeCand;
         }
 #if JVET_X0141_CIIP_TIMD_TM && JVET_W0123_TIMD_FUSION
         int intraMode = PLANAR_IDX;
@@ -4336,13 +4352,13 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
           double cost = (double)sadValue + (double)fracBits * sqrtLambdaForFirstPassIntra;
           insertPos = -1;
 #if CIIP_PDPC
-          updateCandList(ModeInfo(mergeCand, false, false, true, pu.ciipPDPC), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+          updateCandList(ModeInfo(mergeCand, false, false, true, pu.ciipPDPC), cost, rdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
 #else
-          updateCandList(ModeInfo(mergeCand, false, false, true), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+          updateCandList(ModeInfo(mergeCand, false, false, true), cost, rdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
 #endif
           if (insertPos != -1)
           {
-            for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
+            for (int i = int(rdModeList.size()) - 1; i > insertPos; i--)
             {
               swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
             }
@@ -4362,13 +4378,13 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
       {
 #if MERGE_ENC_OPT
 #if JVET_W0090_ARMC_TM
-        xCheckSATDCostMmvdMerge(tempCS, cu, pu, mergeCtxtmp, acMergeTempBuffer, singleMergeTempBuffer, uiNumMrgSATDCand, RdModeList, candCostList, distParam, ctxStart
+        xCheckSATDCostMmvdMerge(tempCS, cu, pu, mergeCtxtmp, acMergeTempBuffer, singleMergeTempBuffer, uiNumMrgSATDCand, rdModeList, candCostList, distParam, ctxStart
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
                            ,     mmvdLUT
 #endif
                                 );
 #else
-        xCheckSATDCostMmvdMerge(tempCS, cu, pu, mergeCtx, acMergeTempBuffer, singleMergeTempBuffer, uiNumMrgSATDCand, RdModeList, candCostList, distParam, ctxStart
+        xCheckSATDCostMmvdMerge(tempCS, cu, pu, mergeCtx, acMergeTempBuffer, singleMergeTempBuffer, uiNumMrgSATDCand, rdModeList, candCostList, distParam, ctxStart
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
                            ,     mmvdLUT
 #endif
@@ -4418,13 +4434,13 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #endif
           insertPos = -1;
 #if CIIP_PDPC
-          updateCandList(ModeInfo(mmvdMergeCand, false, true, false, false), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+          updateCandList(ModeInfo(mmvdMergeCand, false, true, false, false), cost, rdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
 #else
-          updateCandList(ModeInfo(mmvdMergeCand, false, true, false), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+          updateCandList(ModeInfo(mmvdMergeCand, false, true, false), cost, rdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
 #endif
           if (insertPos != -1)
           {
-            for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
+            for (int i = int(rdModeList.size()) - 1; i > insertPos; i--)
             {
               swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
             }
@@ -4437,7 +4453,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #if TM_MRG
       if (sps.getUseDMVDMode())
       {
-        xCheckSATDCostTMMerge(tempCS, cu, pu, tmMrgCtx, acMergeTempBuffer, singleMergeTempBuffer, uiNumMrgSATDCand, RdModeList, candCostList, distParam, ctxStart
+        xCheckSATDCostTMMerge(tempCS, cu, pu, tmMrgCtx, acMergeTempBuffer, singleMergeTempBuffer, uiNumMrgSATDCand, rdModeList, candCostList, distParam, ctxStart
 #if MULTI_PASS_DMVR
           , applyBDMVR4TM
 #endif
@@ -4446,13 +4462,13 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #endif
       if (affineMrgAvail)
       {
-        xCheckSATDCostAffineMerge(tempCS, cu, pu, affineMergeCtx, mrgCtx, acMergeTempBuffer, singleMergeTempBuffer, uiNumMrgSATDCand, RdModeList, candCostList, distParam, ctxStart);
+        xCheckSATDCostAffineMerge(tempCS, cu, pu, affineMergeCtx, mrgCtx, acMergeTempBuffer, singleMergeTempBuffer, uiNumMrgSATDCand, rdModeList, candCostList, distParam, ctxStart);
       }
 #if AFFINE_MMVD
       if (affineMmvdAvail)
       {
 #if JVET_W0090_ARMC_TM
-        xCheckSATDCostAffineMmvdMerge(tempCS, cu, pu, affineMergeCtxTmp, mrgCtx, acMergeTempBuffer, singleMergeTempBuffer, uiNumMrgSATDCand, RdModeList, candCostList, distParam, ctxStart
+        xCheckSATDCostAffineMmvdMerge(tempCS, cu, pu, affineMergeCtxTmp, mrgCtx, acMergeTempBuffer, singleMergeTempBuffer, uiNumMrgSATDCand, rdModeList, candCostList, distParam, ctxStart
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
                                           , affMmvdLUT
 #if JVET_AA0093_ENHANCED_MMVD_EXTENSION
@@ -4461,7 +4477,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #endif
                                       );
 #else
-        xCheckSATDCostAffineMmvdMerge(tempCS, cu, pu, affineMergeCtx, mrgCtx, acMergeTempBuffer, singleMergeTempBuffer, uiNumMrgSATDCand, RdModeList, candCostList, distParam, ctxStart
+        xCheckSATDCostAffineMmvdMerge(tempCS, cu, pu, affineMergeCtx, mrgCtx, acMergeTempBuffer, singleMergeTempBuffer, uiNumMrgSATDCand, rdModeList, candCostList, distParam, ctxStart
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
                                           , affMmvdLUT
 #endif
@@ -4474,13 +4490,13 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
       if (sps.getUseDMVDMode() && checkBmMrg)
       {
 #if JVET_AA0093_REFINED_MOTION_FOR_ARMC
-        xCheckSATDCostBMMerge(tempCS, cu, pu, bmMrgCtx, bmMrgCtxDir2, admvrRefinedMotion, acMergeTempBuffer, singleMergeTempBuffer, uiNumMrgSATDCand, RdModeList, candCostList, distParam, ctxStart
+        xCheckSATDCostBMMerge(tempCS, cu, pu, bmMrgCtx, bmMrgCtxDir2, admvrRefinedMotion, acMergeTempBuffer, singleMergeTempBuffer, uiNumMrgSATDCand, rdModeList, candCostList, distParam, ctxStart
 #if MULTI_PASS_DMVR
           , applyBDMVR4BM
 #endif
         );
 #else
-        xCheckSATDCostBMMerge(tempCS, cu, pu, bmMrgCtx, acMergeTempBuffer, singleMergeTempBuffer, uiNumMrgSATDCand, RdModeList, candCostList, distParam, ctxStart
+        xCheckSATDCostBMMerge(tempCS, cu, pu, bmMrgCtx, acMergeTempBuffer, singleMergeTempBuffer, uiNumMrgSATDCand, rdModeList, candCostList, distParam, ctxStart
 #if MULTI_PASS_DMVR
           , applyBDMVR4BM
 #endif
@@ -4507,7 +4523,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 
         for (uint32_t mergeCnt = 0; mergeCnt < uiNumMrgSATDCand; mergeCnt++)
         {
-          if (RdModeList[mergeCnt].isCIIP)
+          if (rdModeList[mergeCnt].isCIIP)
           {
             pu.intraDir[0] = PLANAR_IDX;
             pu.intraDir[1] = DM_CHROMA_IDX;
@@ -4516,13 +4532,13 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
               continue;
 #endif
 #if CIIP_PDPC
-            pu.ciipPDPC = RdModeList[mergeCnt].isCiipPDPC;
+            pu.ciipPDPC = rdModeList[mergeCnt].isCiipPDPC;
             uint32_t bufIdx = pu.ciipPDPC ? 1 : 0;
 #else
             uint32_t bufIdx = 0;
 #endif
 #if JVET_X0141_CIIP_TIMD_TM && JVET_W0123_TIMD_FUSION
-              pu.intraDir[0] = RdModeList[mergeCnt].intraMode;
+              pu.intraDir[0] = rdModeList[mergeCnt].intraMode;
 #endif
             if (!tag[bufIdx])
             {
@@ -4571,9 +4587,9 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
   {
     for( uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++ )
     {
-      uint32_t uiMergeCand = RdModeList[uiMrgHADIdx].mergeCand;
+      uint32_t uiMergeCand = rdModeList[uiMrgHADIdx].mergeCand;
 
-      if (uiNoResidualPass != 0 && RdModeList[uiMrgHADIdx].isCIIP) // intrainter does not support skip mode
+      if (uiNoResidualPass != 0 && rdModeList[uiMrgHADIdx].isCIIP) // intrainter does not support skip mode
       {
         if (isTestSkipMerge[uiMergeCand])
         {
@@ -4581,7 +4597,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
         }
       }
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
-     if (RdModeList[uiMrgHADIdx].isMMVD && (uiMergeCand - (uiMergeCand / MMVD_MAX_REFINE_NUM)* MMVD_MAX_REFINE_NUM >= (MMVD_MAX_REFINE_NUM >> MMVD_SIZE_SHIFT)))
+     if (rdModeList[uiMrgHADIdx].isMMVD && (uiMergeCand - (uiMergeCand / MMVD_MAX_REFINE_NUM)* MMVD_MAX_REFINE_NUM >= (MMVD_MAX_REFINE_NUM >> MMVD_SIZE_SHIFT)))
      {
 	     continue;
      }
@@ -4633,11 +4649,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #if JVET_X0141_CIIP_TIMD_TM
       pu.intraDir[0] = PLANAR_IDX;
 #endif
-      if (uiNoResidualPass == 0 && RdModeList[uiMrgHADIdx].isCIIP)
+      if (uiNoResidualPass == 0 && rdModeList[uiMrgHADIdx].isCIIP)
       {
         cu.mmvdSkip = false;
 #if JVET_X0141_CIIP_TIMD_TM && TM_MRG
-        pu.tmMergeFlag = RdModeList[uiMrgHADIdx].isTMMrg;
+        pu.tmMergeFlag = rdModeList[uiMrgHADIdx].isTMMrg;
 #endif
 #if MULTI_HYP_PRED
         pu.ciipFlag = true;
@@ -4654,18 +4670,18 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
         pu.ciipFlag = true;
 #endif
 #if CIIP_PDPC
-        pu.ciipPDPC = RdModeList[uiMrgHADIdx].isCiipPDPC;
+        pu.ciipPDPC = rdModeList[uiMrgHADIdx].isCiipPDPC;
 #endif
         pu.regularMergeFlag = false;
 #if JVET_X0141_CIIP_TIMD_TM && JVET_W0123_TIMD_FUSION
-        pu.intraDir[0] = RdModeList[uiMrgHADIdx].intraMode;
+        pu.intraDir[0] = rdModeList[uiMrgHADIdx].intraMode;
 #else
         pu.intraDir[0] = PLANAR_IDX;
 #endif
         CHECK(pu.intraDir[0]<0 || pu.intraDir[0]>(NUM_LUMA_MODE - 1), "out of intra mode");
         pu.intraDir[1] = DM_CHROMA_IDX;
       }
-      else if (RdModeList[uiMrgHADIdx].isMMVD)
+      else if (rdModeList[uiMrgHADIdx].isMMVD)
       {
         cu.mmvdSkip = true;
         pu.regularMergeFlag = true;
@@ -4685,7 +4701,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
       }
 #if MERGE_ENC_OPT
 #if AFFINE_MMVD
-      else if (RdModeList[uiMrgHADIdx].isAffineMmvd)
+      else if (rdModeList[uiMrgHADIdx].isAffineMmvd)
       {
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
         int uiMergeCandTemp = affMmvdLUT[uiMergeCand];
@@ -4756,7 +4772,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
         PU::spanMotionInfo(pu);
       }
 #endif
-      else if (RdModeList[uiMrgHADIdx].isAffine)
+      else if (rdModeList[uiMrgHADIdx].isAffine)
       {
         CHECK(uiMergeCand >= affineMergeCtx.numValidMergeCand, "");
         cu.mmvdSkip = false;
@@ -4802,9 +4818,9 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
       }
 #if TM_MRG && MERGE_ENC_OPT
 #if JVET_X0141_CIIP_TIMD_TM
-      else if (RdModeList[uiMrgHADIdx].isTMMrg && !RdModeList[uiMrgHADIdx].isCIIP)
+      else if (rdModeList[uiMrgHADIdx].isTMMrg && !rdModeList[uiMrgHADIdx].isCIIP)
 #else
-      else if (RdModeList[uiMrgHADIdx].isTMMrg)
+      else if (rdModeList[uiMrgHADIdx].isTMMrg)
 #endif
       {
         cu.mmvdSkip         = false;
@@ -4825,12 +4841,12 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
       }
 #endif
 #if JVET_X0049_ADAPT_DMVR
-      else if (RdModeList[uiMrgHADIdx].isBMMrg)
+      else if (rdModeList[uiMrgHADIdx].isBMMrg)
       {
         cu.mmvdSkip = false;
         pu.regularMergeFlag = true;
         pu.bmMergeFlag = true;
-        pu.bmDir = RdModeList[uiMrgHADIdx].bmDir;
+        pu.bmDir = rdModeList[uiMrgHADIdx].bmDir;
 #if JVET_AA0093_REFINED_MOTION_FOR_ARMC
         if (pu.bmDir == 1)
         {
@@ -4871,7 +4887,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #endif
       }
 #if MERGE_ENC_OPT
-      if (!RdModeList[uiMrgHADIdx].isAffine && !RdModeList[uiMrgHADIdx].isGeo)
+      if (!rdModeList[uiMrgHADIdx].isAffine && !rdModeList[uiMrgHADIdx].isGeo)
 #endif
 #if MULTI_PASS_DMVR
       if( !pu.bdmvrRefine )
@@ -4995,9 +5011,9 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
         }
         else
         {
-          if (RdModeList[uiMrgHADIdx].isMMVD
+          if (rdModeList[uiMrgHADIdx].isMMVD
 #if AFFINE_MMVD && MERGE_ENC_OPT
-            || RdModeList[uiMrgHADIdx].isAffineMmvd
+            || rdModeList[uiMrgHADIdx].isAffineMmvd
 #endif
             )
           {
@@ -5005,18 +5021,18 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
             m_pcInterSearch->motionCompensation(pu);
           }
 #if MERGE_ENC_OPT
-          else if (uiNoResidualPass != 0 && RdModeList[uiMrgHADIdx].isCIIP)
+          else if (uiNoResidualPass != 0 && rdModeList[uiMrgHADIdx].isCIIP)
           {
             // perform regular MC instead, i.e. test skip mode
             pu.mvRefine = true;
             m_pcInterSearch->motionCompensation(pu);
             pu.mvRefine = false;
 #if MULTI_PASS_DMVR
-            if (!RdModeList[uiMrgHADIdx].isAffine && !RdModeList[uiMrgHADIdx].isGeo && pu.bdmvrRefine)
+            if (!rdModeList[uiMrgHADIdx].isAffine && !rdModeList[uiMrgHADIdx].isGeo && pu.bdmvrRefine)
             {
 #if TM_MRG
 #if JVET_X0141_CIIP_TIMD_TM
-              if (pu.tmMergeFlag && !RdModeList[uiMrgHADIdx].isCIIP)
+              if (pu.tmMergeFlag && !rdModeList[uiMrgHADIdx].isCIIP)
 #else
               if ( pu.tmMergeFlag )
 #endif
@@ -5037,7 +5053,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #endif
           }
 #else
-          else if (uiNoResidualPass != 0 && RdModeList[uiMrgHADIdx].isCIIP)
+          else if (uiNoResidualPass != 0 && rdModeList[uiMrgHADIdx].isCIIP)
           {
             tempCS->getPredBuf().copyFrom(acMergeBuffer[uiMergeCand]);
 #if MULTI_PASS_DMVR
@@ -5056,7 +5072,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
           }
 #endif
 #if MERGE_ENC_OPT
-          else if (RdModeList[uiMrgHADIdx].isAffine)
+          else if (rdModeList[uiMrgHADIdx].isAffine)
           {
             tempCS->getPredBuf().copyFrom(*acMergeTempBuffer[uiMrgHADIdx], true);
 #if JVET_Z0136_OOB
@@ -5071,7 +5087,7 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
             tempCS->getPredBuf().copyFrom(*acMergeTempBuffer[uiMrgHADIdx]);
 #if MULTI_PASS_DMVR
 #if MERGE_ENC_OPT
-            if (!RdModeList[uiMrgHADIdx].isAffine && !RdModeList[uiMrgHADIdx].isGeo && pu.bdmvrRefine)
+            if (!rdModeList[uiMrgHADIdx].isAffine && !rdModeList[uiMrgHADIdx].isGeo && pu.bdmvrRefine)
 #else
             if(pu.bdmvrRefine)
 #endif
@@ -8228,7 +8244,7 @@ void EncCu::xCheckSATDCostRegularMerge(CodingStructure *&tempCS, CodingUnit &cu,
 #if !MULTI_PASS_DMVR
   , Mv   refinedMvdL0[MAX_NUM_PARTS_IN_CTU][MRG_MAX_NUM_CANDS]
 #endif
-  , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart
+  , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart
 #if MULTI_PASS_DMVR
   , bool* applyBDMVR
 #endif
@@ -8359,23 +8375,23 @@ void EncCu::xCheckSATDCostRegularMerge(CodingStructure *&tempCS, CodingUnit &cu,
     }
 #endif
     insertPos = -1;
-    updateCandList(ModeInfo(cu, pu), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+    updateCandList(ModeInfo(cu, pu), cost, rdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
     if (insertPos != -1 && insertPos < MMVD_MRG_MAX_RD_NUM)
     {
-      if (insertPos == RdModeList.size() - 1)
+      if (insertPos == rdModeList.size() - 1)
       {
         swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
       }
       else
       {
-        for (uint32_t i = uint32_t(RdModeList.size()) - 1; i > insertPos; i--)
+        for (uint32_t i = uint32_t(rdModeList.size()) - 1; i > insertPos; i--)
         {
           swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
         }
         swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
       }
     }
-    CHECK(std::min(uiMergeCand + 1, uiNumMrgSATDCand) != RdModeList.size(), "");
+    CHECK(std::min(uiMergeCand + 1, uiNumMrgSATDCand) != rdModeList.size(), "");
   }
 #if MULTI_PASS_DMVR
   pu.bdmvrRefine = false;
@@ -8383,7 +8399,7 @@ void EncCu::xCheckSATDCostRegularMerge(CodingStructure *&tempCS, CodingUnit &cu,
 }
 
 void EncCu::xCheckSATDCostCiipMerge(CodingStructure *&tempCS, CodingUnit &cu, PredictionUnit &pu, MergeCtx mergeCtx, PelUnitBuf *acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM], PelUnitBuf *&singleMergeTempBuffer, PelUnitBuf  acMergeTmpBuffer[MRG_MAX_NUM_CANDS]
-  , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart)
+  , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart)
 {
 #if INTER_LIC
   cu.LICFlag = false;
@@ -8475,10 +8491,10 @@ void EncCu::xCheckSATDCostCiipMerge(CodingStructure *&tempCS, CodingUnit &cu, Pr
     uint64_t fracBits = m_pcInterSearch->xCalcPuMeBits(pu);
     double cost = (double)sadValue + (double)fracBits * sqrtLambdaForFirstPassIntra; // need to check the cost calculation again???
     insertPos = -1;
-    updateCandList(ModeInfo(cu, pu), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+    updateCandList(ModeInfo(cu, pu), cost, rdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
     if (insertPos != -1 && insertPos < MMVD_MRG_MAX_RD_NUM)
     {
-      for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
+      for (int i = int(rdModeList.size()) - 1; i > insertPos; i--)
       {
         swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
       }
@@ -8496,7 +8512,7 @@ pu.ciipPDPC = false;
 
 #if JVET_X0141_CIIP_TIMD_TM && TM_MRG
 void EncCu::xCheckSATDCostCiipTmMerge(CodingStructure *&tempCS, CodingUnit &cu, PredictionUnit &pu, MergeCtx mergeCtx, PelUnitBuf *acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM], PelUnitBuf *&singleMergeTempBuffer, PelUnitBuf  acTmMergeTmpBuffer[MRG_MAX_NUM_CANDS]
-  , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart)
+  , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart)
 {
 #if INTER_LIC
   cu.LICFlag = false;
@@ -8593,10 +8609,10 @@ void EncCu::xCheckSATDCostCiipTmMerge(CodingStructure *&tempCS, CodingUnit &cu,
     uint64_t fracBits = m_pcInterSearch->xCalcPuMeBits(pu);
     double cost = (double)sadValue + (double)fracBits * sqrtLambdaForFirstPassIntra; // need to check the cost calculation again???
     insertPos = -1;
-    updateCandList(ModeInfo(cu, pu), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+    updateCandList(ModeInfo(cu, pu), cost, rdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
     if (insertPos != -1 && insertPos < MMVD_MRG_MAX_RD_NUM)
     {
-      for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
+      for (int i = int(rdModeList.size()) - 1; i > insertPos; i--)
       {
         swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
       }
@@ -8615,7 +8631,7 @@ pu.tmMergeFlag = false;
 #endif
 
 void EncCu::xCheckSATDCostMmvdMerge(CodingStructure *&tempCS, CodingUnit &cu, PredictionUnit &pu, MergeCtx mergeCtx, PelUnitBuf *acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM], PelUnitBuf *&singleMergeTempBuffer
-  , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart
+  , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
     , uint32_t * mmvdLUT
 #endif
@@ -8714,10 +8730,10 @@ void EncCu::xCheckSATDCostMmvdMerge(CodingStructure *&tempCS, CodingUnit &cu, Pr
     }
 #endif
     insertPos = -1;
-    updateCandList(ModeInfo(cu, pu), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+    updateCandList(ModeInfo(cu, pu), cost, rdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
     if (insertPos != -1 && insertPos < MMVD_MRG_MAX_RD_NUM)
     {
-      for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
+      for (int i = int(rdModeList.size()) - 1; i > insertPos; i--)
       {
         swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
       }
@@ -8727,7 +8743,7 @@ void EncCu::xCheckSATDCostMmvdMerge(CodingStructure *&tempCS, CodingUnit &cu, Pr
 }
 
 void EncCu::xCheckSATDCostAffineMerge(CodingStructure *&tempCS, CodingUnit &cu, PredictionUnit &pu, AffineMergeCtx affineMergeCtx, MergeCtx& mrgCtx, PelUnitBuf *acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM], PelUnitBuf *&singleMergeTempBuffer
-  , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart)
+  , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart)
 {
   cu.mmvdSkip = false;
   cu.geoFlag = false;
@@ -8807,14 +8823,14 @@ void EncCu::xCheckSATDCostAffineMerge(CodingStructure *&tempCS, CodingUnit &cu,
     }
 #endif
     insertPos = -1;
-    updateCandList(ModeInfo(cu, pu), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+    updateCandList(ModeInfo(cu, pu), cost, rdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
 #if MERGE_ENC_OPT
     if (insertPos != -1 && insertPos < MMVD_MRG_MAX_RD_NUM)
 #else
     if (insertPos != -1)
 #endif
     {
-      for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
+      for (int i = int(rdModeList.size()) - 1; i > insertPos; i--)
       {
         swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
       }
@@ -8833,7 +8849,7 @@ void EncCu::xCheckSATDCostTMMerge(       CodingStructure*& tempCS,
                                          PelUnitBuf*       acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM],
                                          PelUnitBuf*&      singleMergeTempBuffer,
                                          unsigned&         uiNumMrgSATDCand,
-                                         static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList,
+                                         static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList,
                                          static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>    &candCostList,
                                          DistParam         distParam,
                                    const TempCtx&          ctxStart
@@ -8897,11 +8913,11 @@ void EncCu::xCheckSATDCostTMMerge(       CodingStructure*& tempCS,
     uint64_t fracBits = m_pcInterSearch->xCalcPuMeBits(pu);
     double cost = (double)uiSad + (double)fracBits * sqrtLambdaForFirstPassIntra;
     insertPos = -1;
-    updateCandList(ModeInfo(cu, pu), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+    updateCandList(ModeInfo(cu, pu), cost, rdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
 
     if (insertPos != -1 && insertPos < MMVD_MRG_MAX_RD_NUM)
     {
-      for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
+      for (int i = int(rdModeList.size()) - 1; i > insertPos; i--)
       {
         swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
       }
@@ -8929,7 +8945,7 @@ void EncCu::xCheckSATDCostAffineMmvdMerge(       CodingStructure*& tempCS,
                                                  PelUnitBuf*       acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM],
                                                  PelUnitBuf*&      singleMergeTempBuffer,
                                                  unsigned&         uiNumMrgSATDCand,
-                                                 static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList,
+                                                 static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList,
                                                  static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>    &candCostList,
                                                  DistParam         distParam,
                                            const TempCtx&          ctxStart
@@ -9052,11 +9068,11 @@ void EncCu::xCheckSATDCostAffineMmvdMerge(       CodingStructure*& tempCS,
     }
 #endif
     insertPos = -1;
-    updateCandList(ModeInfo(cu, pu), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+    updateCandList(ModeInfo(cu, pu), cost, rdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
 
     if (insertPos != -1 && insertPos < MMVD_MRG_MAX_RD_NUM)
     {
-      for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
+      for (int i = int(rdModeList.size()) - 1; i > insertPos; i--)
       {
         swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
       }
@@ -9070,7 +9086,7 @@ void EncCu::xCheckSATDCostAffineMmvdMerge(       CodingStructure*& tempCS,
 #endif
 #if !JVET_W0097_GPM_MMVD_TM && !JVET_Z0056_GPM_SPLIT_MODE_REORDERING
 void EncCu::xCheckSATDCostGeoMerge(CodingStructure *&tempCS, CodingUnit &cu, PredictionUnit &pu, MergeCtx geoMergeCtx, PelUnitBuf *acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM], PelUnitBuf *&singleMergeTempBuffer
-  , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart)
+  , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart)
 {
   const SPS &sps = *tempCS->sps;
   int numGeoChecked = 0;
@@ -9247,7 +9263,7 @@ void EncCu::xCheckSATDCostGeoMerge(CodingStructure *&tempCS, CodingUnit &cu, Pre
         }
         numGeoChecked++;
         insertPos = -1;
-        updateCandList(ModeInfo(cu, pu), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+        updateCandList(ModeInfo(cu, pu), cost, rdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
 #if MERGE_ENC_OPT
         if (insertPos != -1 && insertPos < MMVD_MRG_MAX_RD_NUM)
 #else
@@ -9255,7 +9271,7 @@ void EncCu::xCheckSATDCostGeoMerge(CodingStructure *&tempCS, CodingUnit &cu, Pre
 #endif
         {
           m_pcInterSearch->weightedGeoBlk(pu, splitDir, CHANNEL_TYPE_CHROMA, *singleMergeTempBuffer, geoBuffer[pu.geoMergeIdx0], geoBuffer[pu.geoMergeIdx1]); //have to use pu.geoMergeIdx1 since  mergeCand1 maybe changed
-          for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
+          for (int i = int(rdModeList.size()) - 1; i > insertPos; i--)
           {
             swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
           }
@@ -9271,9 +9287,9 @@ void EncCu::xCheckSATDCostGeoMerge(CodingStructure *&tempCS, CodingUnit &cu, Pre
     uiNumMrgSATDCand = uiNumMrgSATDCand - GEO_MAX_TRY_WEIGHTED_SATD + numGeoChecked;
   }
 
-  if (uiNumMrgSATDCand > RdModeList.size()) //to make sure we have engough candidates in the list
+  if (uiNumMrgSATDCand > rdModeList.size()) //to make sure we have engough candidates in the list
   {
-    uiNumMrgSATDCand = (unsigned int)RdModeList.size();
+    uiNumMrgSATDCand = (unsigned int)rdModeList.size();
   }
 }
 #endif
@@ -9356,12 +9372,12 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct
   bool                                        bestIsSkip = false;
   uint32_t                                    uiNumMrgSATDCand = affineMergeCtx.numValidMergeCand;
   PelUnitBuf                                  acMergeBuffer[AFFINE_MRG_MAX_NUM_CANDS];
-  static_vector<uint32_t, AFFINE_MRG_MAX_NUM_CANDS>  RdModeList;
+  static_vector<uint32_t, AFFINE_MRG_MAX_NUM_CANDS>  rdModeList;
   bool                                        mrgTempBufSet = false;
 
   for ( uint32_t i = 0; i < AFFINE_MRG_MAX_NUM_CANDS; i++ )
   {
-    RdModeList.push_back( i );
+    rdModeList.push_back( i );
   }
 
   if ( m_pcEncCfg->getUseFastMerge() )
@@ -9379,7 +9395,7 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct
     // 1. Pass: get SATD-cost for selected candidates and reduce their count
     if ( !bestIsSkip )
     {
-      RdModeList.clear();
+      rdModeList.clear();
       mrgTempBufSet = true;
 #if JVET_W0097_GPM_MMVD_TM
       const double sqrtLambdaForFirstPassIntra = m_pcRdCost->getMotionLambda() * FRAC_BITS_SCALE;
@@ -9477,10 +9493,10 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct
           m_baseResultsForMH.push_back(mergeResult);
         }
 #endif
-        updateCandList( uiMergeCand, cost, RdModeList, candCostList
+        updateCandList( uiMergeCand, cost, rdModeList, candCostList
           , uiNumMrgSATDCand );
 
-        CHECK( std::min( uiMergeCand + 1, uiNumMrgSATDCand ) != RdModeList.size(), "" );
+        CHECK( std::min( uiMergeCand + 1, uiNumMrgSATDCand ) != rdModeList.size(), "" );
       }
 
       // Try to limit number of candidates using SATD-costs
@@ -9512,7 +9528,7 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct
   {
     for ( uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++ )
     {
-      uint32_t uiMergeCand = RdModeList[uiMrgHADIdx];
+      uint32_t uiMergeCand = rdModeList[uiMrgHADIdx];
 
       if ( ((uiNoResidualPass != 0) && candHasNoResidual[uiMergeCand])
         || ((uiNoResidualPass == 0) && bestIsSkip) )
@@ -9696,11 +9712,11 @@ void EncCu::xCheckRDCostAffineMmvd2Nx2N(CodingStructure *&tempCS, CodingStructur
   bool                                    bestIsSkip       = false;
   int                                     afMmvdCandCount  = baseCount * AF_MMVD_MAX_REFINE_NUM;
   uint32_t                                uiNumMrgSATDCand = std::min( AF_MMVD_NUM, afMmvdCandCount );
-  static_vector<uint32_t, AF_MMVD_NUM>    RdModeList;
+  static_vector<uint32_t, AF_MMVD_NUM>    rdModeList;
 
   for (uint32_t i = 0; i < AF_MMVD_NUM; i++)
   {
-    RdModeList.push_back(i);
+    rdModeList.push_back(i);
   }
 
   if (m_pcEncCfg->getUseFastMerge())
@@ -9717,7 +9733,7 @@ void EncCu::xCheckRDCostAffineMmvd2Nx2N(CodingStructure *&tempCS, CodingStructur
     // 1. Pass: get SATD-cost for selected candidates and reduce their count
     if (!bestIsSkip)
     {
-      RdModeList.clear();
+      rdModeList.clear();
       const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda();
 
       CodingUnit &cu = tempCS->addCU(tempCS->area, partitioner.chType);
@@ -9804,9 +9820,9 @@ void EncCu::xCheckRDCostAffineMmvd2Nx2N(CodingStructure *&tempCS, CodingStructur
             m_baseResultsForMH.push_back(mergeResult);
           }
 #endif
-          updateCandList(uiMergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand);
+          updateCandList(uiMergeCand, cost, rdModeList, candCostList, uiNumMrgSATDCand);
 
-          CHECK(std::min(uiMergeCand + 1, uiNumMrgSATDCand) != RdModeList.size(), "");
+          CHECK(std::min(uiMergeCand + 1, uiNumMrgSATDCand) != rdModeList.size(), "");
         }
       }
 
@@ -9838,7 +9854,7 @@ void EncCu::xCheckRDCostAffineMmvd2Nx2N(CodingStructure *&tempCS, CodingStructur
   {
     for (uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++)
     {
-      uint32_t uiMergeCand = RdModeList[uiMrgHADIdx];
+      uint32_t uiMergeCand = rdModeList[uiMrgHADIdx];
 
       if (((uiNoResidualPass != 0) && candHasNoResidual[uiMergeCand])
         || ((uiNoResidualPass == 0) && bestIsSkip))
@@ -10046,10 +10062,10 @@ void EncCu::xCheckRDCostTMMerge2Nx2N(CodingStructure *&tempCS, CodingStructure *
   int32_t numMrgSATDCand = candNum;
   bool    mrgTempBufSet = false;
 
-  static_vector<uint32_t, TM_MRG_MAX_NUM_CANDS> RdModeList;
+  static_vector<uint32_t, TM_MRG_MAX_NUM_CANDS> rdModeList;
   for (uint32_t i = 0; i < TM_MRG_MAX_NUM_CANDS; i++)
   {
-    RdModeList.push_back(i);
+    rdModeList.push_back(i);
   }
 
   const UnitArea localUnitArea(tempCS->area.chromaFormat, Area(0, 0, tempCS->area.Y().width, tempCS->area.Y().height));
@@ -10078,7 +10094,7 @@ void EncCu::xCheckRDCostTMMerge2Nx2N(CodingStructure *&tempCS, CodingStructure *
     // 1. Pass: get SATD-cost for selected candidates and reduce their count
     if( !bestIsSkip )
     {
-      RdModeList.clear();
+      rdModeList.clear();
       mrgTempBufSet = true;
       const TempCtx ctxStart(m_CtxCache, m_CABACEstimator->getCtx());
 
@@ -10146,9 +10162,9 @@ void EncCu::xCheckRDCostTMMerge2Nx2N(CodingStructure *&tempCS, CodingStructure *
         uint64_t fracBits = m_pcInterSearch->xCalcPuMeBits(pu);
         double cost = (double)uiSad + (double)fracBits * sqrtLambdaForFirstPassIntra;
 
-        updateCandList(uiMergeCand, cost, RdModeList, candCostList, numMrgSATDCand);
+        updateCandList(uiMergeCand, cost, rdModeList, candCostList, numMrgSATDCand);
 
-        CHECK(std::min(uiMergeCand + 1, (uint32_t)numMrgSATDCand) != RdModeList.size(), "");
+        CHECK(std::min(uiMergeCand + 1, (uint32_t)numMrgSATDCand) != rdModeList.size(), "");
       }
 
       // Try to limit number of candidates using SATD-costs
@@ -10177,7 +10193,7 @@ void EncCu::xCheckRDCostTMMerge2Nx2N(CodingStructure *&tempCS, CodingStructure *
   {
     for( uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < numMrgSATDCand; uiMrgHADIdx++ )
     {
-      uint32_t uiMergeCand = RdModeList[uiMrgHADIdx];
+      uint32_t uiMergeCand = rdModeList[uiMrgHADIdx];
 
       if (((uiNoResidualPass != 0) && candHasNoResidual[uiMrgHADIdx])
        || ( (uiNoResidualPass == 0) && bestIsSkip ) )
@@ -10320,6 +10336,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if JVET_Z0084_IBC_TM && IBC_TM_MRG
   MergeCtx mergeCtxTm;
 #endif
+#if JVET_AA0061_IBC_MBVD
+  MergeCtx mergeCtxTmp;
+  uint32_t ibcMbvdLUT[IBC_MBVD_NUM];
+  uint32_t ibcMbvdValidNum[IBC_MBVD_BASE_NUM] = { 0 };
+#endif
 
   if (sps.getSbTMVPEnabledFlag())
   {
@@ -10343,9 +10364,15 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if INTER_LIC
     cu.LICFlag = false;
 #endif
-
     cu.geoFlag = false;
+#if JVET_AA0070_RRIBC
+    cu.rribcFlipType = 0;
+    pu.mergeFlag = true;
     PU::getIBCMergeCandidates(pu, mergeCtx);
+    pu.mergeFlag = false;
+#else
+    PU::getIBCMergeCandidates(pu, mergeCtx);
+#endif
 #if JVET_Y0058_IBC_LIST_MODIFY && JVET_W0090_ARMC_TM
     if(pu.cs->sps->getUseAML())
     {
@@ -10361,7 +10388,13 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
     if (pu.cs->sps->getUseDMVDMode() == true)
     {
     pu.tmMergeFlag = true;
+#if JVET_AA0070_RRIBC
+    pu.mergeFlag = true;
     PU::getIBCMergeCandidates(pu, mergeCtxTm);
+    pu.mergeFlag = false;
+#else
+    PU::getIBCMergeCandidates(pu, mergeCtxTm);
+#endif
 #if JVET_Y0058_IBC_LIST_MODIFY && JVET_W0090_ARMC_TM
     if (pu.cs->sps->getUseAML())
     {
@@ -10378,42 +10411,80 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
     {
       mergeCtxTm.numValidMergeCand = 0;
     }
+#endif
+#if JVET_AA0070_RRIBC && JVET_AA0061_IBC_MBVD
+    pu.ibcMbvdMergeFlag = true;
+    pu.mergeFlag = true;
+    PU::getIBCMergeCandidates(pu, mergeCtxTmp);
+    pu.mergeFlag = false;
+
+#if JVET_Y0058_IBC_LIST_MODIFY && JVET_W0090_ARMC_TM
+#if JVET_Z0075_IBC_HMVP_ENLARGE
+    m_pcInterSearch->adjustIBCMergeCandidates(pu, mergeCtxTmp, 0, IBC_MRG_MAX_NUM_CANDS_MEM);
+#else
+    m_pcInterSearch->adjustIBCMergeCandidates(pu, mergeCtxTmp);
+#endif
+#endif
+    pu.ibcMbvdMergeFlag = false;
 #endif
   }
 
 #if JVET_Z0084_IBC_TM && IBC_TM_MRG
-  int candHasNoResidual[IBC_MRG_MAX_NUM_CANDS<<1];
-  for (unsigned int ui = 0; ui < IBC_MRG_MAX_NUM_CANDS<<1; ui++)
+#if JVET_AA0061_IBC_MBVD
+  int candHasNoResidual[((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM)] = {0,};
+  bool                                                 bestIsSkip = false;
+  int32_t                                              numMrgSATDCand = NUM_IBC_MRG_SATD_CAND;
+  if (m_pcEncCfg->getIntraPeriod() != 1)
   {
-    candHasNoResidual[ui] = 0;
+    numMrgSATDCand += 2;
+  }
+  numMrgSATDCand = std::min(numMrgSATDCand, (const int)(mergeCtx.numValidMergeCand + mergeCtxTm.numValidMergeCand));
+  static_vector<unsigned, ((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM)>  rdModeList((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM);
+  for (unsigned i = 0; i < ((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM); i++)
+  {
+    rdModeList[i] = i;
   }
 
+  static_vector<double, ((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM)>  candCostList(((IBC_MRG_MAX_NUM_CANDS<<1)+IBC_MBVD_NUM), MAX_DOUBLE);
+#else
+  int candHasNoResidual[IBC_MRG_MAX_NUM_CANDS<<1] = {0,};
   bool                                                 bestIsSkip = false;
   unsigned                                             numMrgSATDCand = mergeCtx.numValidMergeCand + mergeCtxTm.numValidMergeCand;
-  static_vector<unsigned, (IBC_MRG_MAX_NUM_CANDS<<1)>  RdModeList(IBC_MRG_MAX_NUM_CANDS<<1);
+  static_vector<unsigned, (IBC_MRG_MAX_NUM_CANDS<<1)>  rdModeList(IBC_MRG_MAX_NUM_CANDS<<1);
   for (unsigned i = 0; i < IBC_MRG_MAX_NUM_CANDS<<1; i++)
   {
-    RdModeList[i] = i;
+    rdModeList[i] = i;
   }
 
   static_vector<double, (IBC_MRG_MAX_NUM_CANDS<<1)>  candCostList(IBC_MRG_MAX_NUM_CANDS<<1, MAX_DOUBLE);
+#endif
 #else
-  int candHasNoResidual[MRG_MAX_NUM_CANDS];
-  for (unsigned int ui = 0; ui < mergeCtx.numValidMergeCand; ui++)
+#if JVET_AA0061_IBC_MBVD
+  int candHasNoResidual[MRG_MAX_NUM_CANDS + IBC_MBVD_NUM] = {0,};
+  bool                                        bestIsSkip = false;
+  int32_t                                     numMrgSATDCand = NUM_IBC_MRG_SATD_CAND;
+  numMrgSATDCand = std::min(numMrgSATDCand, (const int)(mergeCtx.numValidMergeCand));
+  static_vector<unsigned, MRG_MAX_NUM_CANDS + IBC_MBVD_NUM>  rdModeList(MRG_MAX_NUM_CANDS + IBC_MBVD_NUM);
+  for (unsigned i = 0; i < MRG_MAX_NUM_CANDS + IBC_MBVD_NUM; i++)
   {
-    candHasNoResidual[ui] = 0;
+    rdModeList[i] = i;
   }
 
+  //{
+  static_vector<double, MRG_MAX_NUM_CANDS + IBC_MBVD_NUM>  candCostList(MRG_MAX_NUM_CANDS + IBC_MBVD_NUM, MAX_DOUBLE);
+#else
+  int candHasNoResidual[MRG_MAX_NUM_CANDS] = {0,};
   bool                                        bestIsSkip = false;
   unsigned                                    numMrgSATDCand = mergeCtx.numValidMergeCand;
-  static_vector<unsigned, MRG_MAX_NUM_CANDS>  RdModeList(MRG_MAX_NUM_CANDS);
+  static_vector<unsigned, MRG_MAX_NUM_CANDS>  rdModeList(MRG_MAX_NUM_CANDS);
   for (unsigned i = 0; i < MRG_MAX_NUM_CANDS; i++)
   {
-    RdModeList[i] = i;
+    rdModeList[i] = i;
   }
 
   //{
     static_vector<double, MRG_MAX_NUM_CANDS>  candCostList(MRG_MAX_NUM_CANDS, MAX_DOUBLE);
+#endif
 #endif
     // 1. Pass: get SATD-cost for selected candidates and reduce their count
     {
@@ -10443,6 +10514,28 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
       Picture* refPic = pu.cu->slice->getPic();
       const CPelBuf refBuf = refPic->getRecoBuf(pu.blocks[COMPONENT_Y]);
       const Pel*        piRefSrch = refBuf.buf;
+#if JVET_AA0070_RRIBC
+      pu.cu->rribcFlipType = 0;
+      const CompArea &area = cu.blocks[COMPONENT_Y];
+      CompArea        tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size());
+      PelBuf          tmpOrgLuma = m_tmpStorageLCU->getBuf(tmpArea);
+      tmpOrgLuma.copyFrom(tempCS->getOrgBuf().Y());
+      if (tempCS->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag())
+      {
+        tmpOrgLuma.rspSignal(tempCS->getOrgBuf().Y(), m_pcReshape->getFwdLUT());
+      }
+      PelStorage m_tmpStorageCUflipH;
+      m_tmpStorageCUflipH.create(UnitArea(pu.chromaFormat, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE)));
+      PelBuf tmpOrgLumaFlipH = m_tmpStorageCUflipH.getBuf(tmpArea);
+      tmpOrgLumaFlipH.copyFrom(tmpOrgLuma);
+      tmpOrgLumaFlipH.flipSignal(true);
+
+      PelStorage m_tmpStorageCUflipV;
+      m_tmpStorageCUflipV.create(UnitArea(pu.chromaFormat, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE)));
+      PelBuf tmpOrgLumaFlipV = m_tmpStorageCUflipV.getBuf(tmpArea);
+      tmpOrgLumaFlipV.copyFrom(tmpOrgLuma);
+      tmpOrgLumaFlipV.flipSignal(false);
+#else
       if (tempCS->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag())
       {
         const CompArea &area = cu.blocks[COMPONENT_Y];
@@ -10453,6 +10546,7 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
       }
       else
         m_pcRdCost->setDistParam(distParam, tempCS->getOrgBuf().Y(), refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
+#endif
 
       int refStride = refBuf.stride;
 #if !JVET_Y0058_IBC_LIST_MODIFY
@@ -10470,6 +10564,9 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
       int numValidBv = mergeCtx.numValidMergeCand + mergeCtxTm.numValidMergeCand;
 #else
       int numValidBv = mergeCtx.numValidMergeCand;
+#endif
+#if JVET_AA0061_IBC_MBVD && !JVET_AA0070_RRIBC
+      int numValidBvIBC = mergeCtx.numValidMergeCand;
 #endif
       for (unsigned int mergeCand = 0; mergeCand < mergeCtx.numValidMergeCand; mergeCand++)
       {
@@ -10488,10 +10585,28 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
 #endif
         {
           numValidBv--;
+#if JVET_AA0061_IBC_MBVD && !JVET_AA0070_RRIBC
+          numValidBvIBC--;
+#endif
           continue;
         }
         PU::spanMotionInfo(pu, mergeCtx);
 
+#if JVET_AA0070_RRIBC
+        if (pu.cu->rribcFlipType == 0)
+        {
+          m_pcRdCost->setDistParam(distParam, tmpOrgLuma, refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
+        }
+        else if (pu.cu->rribcFlipType == 1)
+        {
+          m_pcRdCost->setDistParam(distParam, tmpOrgLumaFlipH, refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
+        }
+        else
+        {
+          m_pcRdCost->setDistParam(distParam, tmpOrgLumaFlipV, refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
+        }
+#endif
+
         distParam.cur.buf = piRefSrch + refStride * yPred + xPred;
 
         Distortion sad = distParam.distFunc(distParam);
@@ -10504,9 +10619,12 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
         {
           bitsCand--;
         }
+#if JVET_AA0061_IBC_MBVD
+        bitsCand++; // for ibc_mbvd_flag
+#endif
         double cost = (double)sad + (double)bitsCand * sqrtLambdaForFirstPass;
 
-        updateCandList(mergeCand, cost, RdModeList, candCostList
+        updateCandList(mergeCand, cost, rdModeList, candCostList
          , numMrgSATDCand);
       }
 
@@ -10546,6 +10664,20 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
       }
       PU::spanMotionInfo(pu, mergeCtxTm);
 
+#if JVET_AA0070_RRIBC
+      if (pu.cu->rribcFlipType == 0)
+      {
+        m_pcRdCost->setDistParam(distParam, tmpOrgLuma, refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
+      }
+      else if (pu.cu->rribcFlipType == 1)
+      {
+        m_pcRdCost->setDistParam(distParam, tmpOrgLumaFlipH, refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
+      }
+      else
+      {
+        m_pcRdCost->setDistParam(distParam, tmpOrgLumaFlipV, refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
+      }
+#endif
       distParam.cur.buf = piRefSrch + refStride * yPred + xPred;
 
       Distortion sad = distParam.distFunc(distParam);
@@ -10554,17 +10686,122 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
       {
         bitsCand--;
       }
+#if JVET_AA0061_IBC_MBVD
+      bitsCand++; // for ibc_mbvd_flag
+#endif
       double cost = (double)sad + (double)bitsCand * sqrtLambdaForFirstPass;
 
-      updateCandList(mergeCand+mergeCtx.numValidMergeCand, cost, RdModeList, candCostList, numMrgSATDCand);
+      updateCandList(mergeCand+mergeCtx.numValidMergeCand, cost, rdModeList, candCostList, numMrgSATDCand);
+    }
+#endif
+#if JVET_AA0061_IBC_MBVD
+#if JVET_AA0070_RRIBC
+    int numValidBvIBC = mergeCtxTmp.numValidMergeCand;
+#endif
+    if (numValidBvIBC)
+    {
+      if (pu.cs->sps->getUseIbcMbvd())
+      {
+#if JVET_AA0070_RRIBC
+        for (unsigned int mergeCand = 0; mergeCand < mergeCtxTmp.numValidMergeCand; mergeCand++)
+        {
+          mergeCtxTmp.setMergeInfo(pu, mergeCand); // set bv info in merge mode
+
+#if !JVET_Y0058_IBC_LIST_MODIFY  //should have already been checked at merge list construction
+#if JVET_Z0084_IBC_TM
+          if (!PU::searchBv(pu, cuPelX, cuPelY, roiWidth, roiHeight, picWidth, picHeight, xPred, yPred, lcuWidth)) // not valid bv derived
+#else
+          if (!m_pcInterSearch->searchBv(pu, cuPelX, cuPelY, roiWidth, roiHeight, picWidth, picHeight, xPred, yPred, lcuWidth)) // not valid bv derived
+#endif
+#else
+          if (pu.bv == Mv(0, 0))
+#endif
+          {
+            numValidBvIBC--;
+            continue;
+          }
+        }
+#endif
+        const int baseNum = std::min(numValidBvIBC, IBC_MBVD_BASE_NUM);
+#if !JVET_AA0070_RRIBC
+        mergeCtxTmp = mergeCtx;
+#endif
+
+        PU::getIbcMbvdMergeCandidates(pu, mergeCtxTmp, baseNum);
+
+        bool flag = pu.ibcMbvdMergeFlag;
+        pu.ibcMbvdMergeFlag = true;
+        m_pcInterSearch->sortIbcMergeMbvdCandidates(pu, mergeCtxTmp, ibcMbvdLUT, ibcMbvdValidNum);
+        pu.ibcMbvdMergeFlag = flag;
+
+        const int tempNum = baseNum * IBC_MBVD_MAX_REFINE_NUM;
+        int baseIdx = 0;
+        for (unsigned int mmvdMergeCandtemp = 0; mmvdMergeCandtemp < tempNum; mmvdMergeCandtemp++)
+        {
+          baseIdx = mmvdMergeCandtemp / IBC_MBVD_MAX_REFINE_NUM;
+          if (mmvdMergeCandtemp - (mmvdMergeCandtemp / IBC_MBVD_MAX_REFINE_NUM) * IBC_MBVD_MAX_REFINE_NUM >= IBC_MBVD_SIZE_ENC)
+          {
+            continue;
+          }
+          if (mmvdMergeCandtemp - (mmvdMergeCandtemp / IBC_MBVD_MAX_REFINE_NUM) * IBC_MBVD_MAX_REFINE_NUM >= ibcMbvdValidNum[baseIdx])
+          {
+            continue;
+          }
+          unsigned int mmvdMergeCand = ibcMbvdLUT[mmvdMergeCandtemp];
+          bool mbvdCandMisAlign = mergeCtxTmp.setIbcMbvdMergeCandiInfo(pu, mmvdMergeCandtemp, mmvdMergeCand);
+          CHECK(mbvdCandMisAlign, "MBVD candidate is invalid");
+
+          int xPred = pu.bv.getHor();
+          int yPred = pu.bv.getVer();
+
+          PU::spanMotionInfo(pu, mergeCtxTmp);
+
+#if JVET_AA0070_RRIBC
+          if (pu.cu->rribcFlipType == 0)
+          {
+            m_pcRdCost->setDistParam(distParam, tmpOrgLuma, refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
+          }
+          else if (pu.cu->rribcFlipType == 1)
+          {
+            m_pcRdCost->setDistParam(distParam, tmpOrgLumaFlipH, refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
+          }
+          else
+          {
+            m_pcRdCost->setDistParam(distParam, tmpOrgLumaFlipV, refBuf, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
+          }
+#endif
+          distParam.cur.buf = piRefSrch + refStride * yPred + xPred;
+
+          Distortion sad = distParam.distFunc(distParam);
+          uint32_t bitsCand = PU::getIbcMbvdEstBits(pu, mmvdMergeCandtemp);
+          bitsCand++; // for ibc_mbvd_flag
+          double cost = (double)sad + (double)bitsCand * sqrtLambdaForFirstPass;
+#if JVET_Z0084_IBC_TM
+          updateCandList(mmvdMergeCandtemp + mergeCtx.numValidMergeCand + mergeCtxTm.numValidMergeCand, cost, rdModeList, candCostList
+            , numMrgSATDCand);
+#else
+          updateCandList(mmvdMergeCandtemp + mergeCtx.numValidMergeCand, cost, rdModeList, candCostList
+            , numMrgSATDCand);
+#endif
+        }
+      }
     }
 #endif
+#if JVET_AA0070_RRIBC
+    m_tmpStorageCUflipH.destroy();
+    m_tmpStorageCUflipV.destroy();
+#endif
 
       // Try to limit number of candidates using SATD-costs
       if (numValidBv)
       {
+#if JVET_AA0061_IBC_MBVD
+        numMrgSATDCand = std::min(numMrgSATDCand,numValidBv);
+        for (int i = 1; i < numMrgSATDCand; i++)
+#else
         numMrgSATDCand = numValidBv;
         for (unsigned int i = 1; i < numValidBv; i++)
+#endif
         {
           if (candCostList[i] > MRG_FAST_RATIO*candCostList[0])
           {
@@ -10595,7 +10832,7 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
   {
     for (unsigned int mrgHADIdx = 0; mrgHADIdx < numMrgSATDCand; mrgHADIdx++)
     {
-      unsigned int mergeCand = RdModeList[mrgHADIdx];
+      unsigned int mergeCand = rdModeList[mrgHADIdx];
       if (!(numResidualPass == 1 && candHasNoResidual[mergeCand] == 1))
       {
         if (!(bestIsSkip && (numResidualPass == 0)))
@@ -10617,6 +10854,9 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
             cu.LICFlag = false;
 #endif
 
+#if JVET_AA0070_RRIBC
+            cu.rribcFlipType = 0;
+#endif
             PredictionUnit &pu = tempCS->addPU(cu, partitioner.chType);// tempCS->addPU(cu);
             pu.intraDir[0] = DC_IDX; // set intra pred for ibc block
             pu.intraDir[1] = PLANAR_IDX; // set intra pred for ibc block
@@ -10624,21 +10864,39 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
             pu.mmvdMergeFlag = false;
             pu.regularMergeFlag = false;
             cu.geoFlag = false;
+#if JVET_AA0061_IBC_MBVD
 #if JVET_Z0084_IBC_TM && IBC_TM_MRG
-            pu.tmMergeFlag      = false;
-            if (mergeCand >= mergeCtx.numValidMergeCand)
+            int numPreviousBv = mergeCtx.numValidMergeCand + mergeCtxTm.numValidMergeCand;
+#else
+            int numPreviousBv = mergeCtx.numValidMergeCand;
+#endif          
+            if (mergeCand >= numPreviousBv)
             {
-              pu.tmMergeFlag    = true;
-              mergeCand        -= mergeCtx.numValidMergeCand;
-              mergeCtxTm.setMergeInfo(pu, mergeCand);
-              PU::spanMotionInfo(pu, mergeCtxTm);
+              bool mbvdCandMisAlign = mergeCtxTmp.setIbcMbvdMergeCandiInfo(pu, mergeCand - numPreviousBv, ibcMbvdLUT[mergeCand - numPreviousBv]);
+              CHECK(mbvdCandMisAlign, "MBVD candidate is invalid");
+              PU::spanMotionInfo(pu, mergeCtxTmp);
             }
             else
-#endif
             {
-              mergeCtx.setMergeInfo(pu, mergeCand);
-              PU::spanMotionInfo(pu, mergeCtx);
+#endif
+#if JVET_Z0084_IBC_TM && IBC_TM_MRG
+              pu.tmMergeFlag = false;
+              if (mergeCand >= mergeCtx.numValidMergeCand)
+              {
+                pu.tmMergeFlag = true;
+                mergeCand -= mergeCtx.numValidMergeCand;
+                mergeCtxTm.setMergeInfo(pu, mergeCand);
+                PU::spanMotionInfo(pu, mergeCtxTm);
+              }
+              else
+#endif
+              {
+                mergeCtx.setMergeInfo(pu, mergeCand);
+                PU::spanMotionInfo(pu, mergeCtx);
+              }
+#if JVET_AA0061_IBC_MBVD
             }
+#endif
 #if INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
             const bool chroma = !(CS::isDualITree(*tempCS));
 #else
@@ -10691,7 +10949,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
   }
 }
 
+#if JVET_AA0070_RRIBC
+void EncCu::xCheckRDCostIBCMode( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode, bool isSecondPass)
+#else
 void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode)
+#endif
 {
 #if CTU_256
   if( tempCS->area.lwidth() >= 128 || tempCS->area.lheight() >= 128 ) // disable IBC mode larger than 64x64
@@ -10735,7 +10997,12 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best
 
     pu.interDir = 1; // use list 0 for IBC mode
     pu.refIdx[REF_PIC_LIST_0] = MAX_NUM_REF; // last idx in the list
+#if JVET_AA0070_RRIBC
+      pu.cu->rribcFlipType = 0;
+      bool bValid = m_pcInterSearch->predIBCSearch(cu, partitioner, m_ctuIbcSearchRangeX, m_ctuIbcSearchRangeY, m_ibcHashMap, isSecondPass);
+#else
       bool bValid = m_pcInterSearch->predIBCSearch(cu, partitioner, m_ctuIbcSearchRangeX, m_ctuIbcSearchRangeY, m_ibcHashMap);
+#endif
 
       if (bValid)
       {
@@ -12739,7 +13006,7 @@ void EncCu::xCheckSATDCostBMMerge(CodingStructure*& tempCS,
   PelUnitBuf*       acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM],
   PelUnitBuf*&      singleMergeTempBuffer,
   unsigned&         uiNumMrgSATDCand,
-  static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList,
+  static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList,
   static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>    &candCostList,
   DistParam         distParam,
   const TempCtx&          ctxStart
@@ -12957,10 +13224,10 @@ void EncCu::xCheckSATDCostBMMerge(CodingStructure*& tempCS,
       uint64_t fracBits = m_pcInterSearch->xCalcPuMeBits(pu);
       double cost = (double)uiSad + (double)fracBits * sqrtLambdaForFirstPassIntra;
       insertPos = -1;
-      updateCandList(ModeInfo(cu, pu), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+      updateCandList(ModeInfo(cu, pu), cost, rdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
       if (insertPos != -1 && insertPos < MMVD_MRG_MAX_RD_NUM)
       {
-        for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
+        for (int i = int(rdModeList.size()) - 1; i > insertPos; i--)
         {
           swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
         }
diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h
index 22ba1bc679e91c7576696986a3f9a9e88e96daf7..98ed1f40ea4dee82fd33723d87089a1fd8eaf1f3 100644
--- a/source/Lib/EncoderLib/EncCu.h
+++ b/source/Lib/EncoderLib/EncCu.h
@@ -454,7 +454,7 @@ protected:
 #if !MULTI_PASS_DMVR
                                 , Mv   refinedMvdL0[MAX_NUM_PARTS_IN_CTU][MRG_MAX_NUM_CANDS]
 #endif
-                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart
+                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart
 #if MULTI_PASS_DMVR
                                 , bool* applyBDMVR
 #endif
@@ -463,7 +463,7 @@ protected:
 #if JVET_AA0093_REFINED_MOTION_FOR_ARMC
   void xCheckSATDCostBMMerge
                               ( CodingStructure *&tempCS, CodingUnit &cu, PredictionUnit &pu, MergeCtx& mrgCtx, MergeCtx& mrgCtxDir2, bool armcRefinedMotion, PelUnitBuf *acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM], PelUnitBuf *&singleMergeTempBuffer
-                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart
+                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart
 #if MULTI_PASS_DMVR
                                 , bool* applyBDMVR
 #endif
@@ -471,7 +471,7 @@ protected:
 #else
   void xCheckSATDCostBMMerge
                               ( CodingStructure *&tempCS, CodingUnit &cu, PredictionUnit &pu, MergeCtx& mrgCtx, PelUnitBuf *acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM], PelUnitBuf *&singleMergeTempBuffer
-                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart
+                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart
 #if MULTI_PASS_DMVR
                                 , bool* applyBDMVR
 #endif
@@ -480,26 +480,26 @@ protected:
 #endif
   void xCheckSATDCostCiipMerge 
                               ( CodingStructure *&tempCS, CodingUnit &cu, PredictionUnit &pu, MergeCtx mergeCtx, PelUnitBuf *acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM], PelUnitBuf *&singleMergeTempBuffer, PelUnitBuf  acMergeTmpBuffer[MRG_MAX_NUM_CANDS]
-                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart);
+                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart);
 #if JVET_X0141_CIIP_TIMD_TM && TM_MRG
   void xCheckSATDCostCiipTmMerge
                               (CodingStructure *&tempCS, CodingUnit &cu, PredictionUnit &pu, MergeCtx mergeCtx, PelUnitBuf *acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM], PelUnitBuf *&singleMergeTempBuffer, PelUnitBuf  acTmMergeTmpBuffer[MRG_MAX_NUM_CANDS]
-                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart);
+                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart);
 #endif
   void xCheckSATDCostMmvdMerge 
                               ( CodingStructure *&tempCS, CodingUnit &cu, PredictionUnit &pu, MergeCtx mergeCtx, PelUnitBuf *acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM], PelUnitBuf *&singleMergeTempBuffer
-                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart
+                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
                                , uint32_t * mmvdLUT = NULL
 #endif
                                );
   void xCheckSATDCostAffineMerge 
                               ( CodingStructure *&tempCS, CodingUnit &cu, PredictionUnit &pu, AffineMergeCtx affineMergeCtx, MergeCtx& mrgCtx, PelUnitBuf *acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM], PelUnitBuf *&singleMergeTempBuffer
-                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart);
+                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart);
 #if AFFINE_MMVD
   void xCheckSATDCostAffineMmvdMerge
                               ( CodingStructure *&tempCS, CodingUnit &cu, PredictionUnit &pu, AffineMergeCtx affineMergeCtx, MergeCtx& mrgCtx, PelUnitBuf *acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM], PelUnitBuf *&singleMergeTempBuffer
-                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart
+                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart
 #if JVET_Y0067_ENHANCED_MMVD_MVD_SIGN_PRED
                                           , uint32_t * affMmvdLUT
 #if JVET_AA0093_ENHANCED_MMVD_EXTENSION
@@ -511,7 +511,7 @@ protected:
 #if TM_MRG
   void xCheckSATDCostTMMerge
                               ( CodingStructure *&tempCS, CodingUnit &cu, PredictionUnit &pu, MergeCtx& mrgCtx, PelUnitBuf *acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM], PelUnitBuf *&singleMergeTempBuffer
-                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart
+                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart
 #if MULTI_PASS_DMVR
                                 , bool* applyBDMVR
 #endif
@@ -520,7 +520,7 @@ protected:
 #if !JVET_W0097_GPM_MMVD_TM && !JVET_Z0056_GPM_SPLIT_MODE_REORDERING
   void xCheckSATDCostGeoMerge 
                               ( CodingStructure *&tempCS, CodingUnit &cu, PredictionUnit &pu, MergeCtx geoMergeCtx, PelUnitBuf *acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM], PelUnitBuf *&singleMergeTempBuffer
-                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &RdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart);
+                                , unsigned& uiNumMrgSATDCand, static_vector<ModeInfo, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  &rdModeList, static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> &candCostList, DistParam distParam, const TempCtx &ctxStart);
 #endif
 #else
   void xCheckRDCostAffineMerge2Nx2N
@@ -577,8 +577,13 @@ protected:
        && (abs(cu.slice->getPOC() - cu.slice->getRefPOC(REF_PIC_LIST_0, cu.refIdxBi[0])) == 1
        ||  abs(cu.slice->getPOC() - cu.slice->getRefPOC(REF_PIC_LIST_1, cu.refIdxBi[1])) == 1))));
   }
+#if JVET_AA0070_RRIBC
+  void xCheckRDCostIBCMode    ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode, bool isSecondPass = false );
+#else
   void xCheckRDCostIBCMode    ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode );
-  void xCheckRDCostIBCModeMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode );
+#endif
+  void xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner,      \
+                                    const EncTestMode &encTestMode);
 
   void xCheckPLT              ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode );
 };
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index 7f40f141b505d9ac8668051e1c9c10d8c8ebd4c8..cf39a5696ddf259adae2c4da6e8e17736d751031 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -1654,6 +1654,9 @@ void EncLib::xInitSPS( SPS& sps )
   sps.setUseColorTrans(m_useColorTrans);
   sps.setPLTMode                            ( m_PLTMode);
   sps.setIBCFlag                            ( m_IBCMode);
+#if JVET_AA0061_IBC_MBVD
+  sps.setUseIbcMbvd                         ( m_ibcMbvd );
+#endif
   sps.setWrapAroundEnabledFlag                      ( m_wrapAround );
 #if MULTI_HYP_PRED
   sps.setMaxNumAddHyps(m_maxNumAddHyps);
diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp
index 3b87cc63c606635a49078dd71a5eae2df7c81d84..462e57b11fb4670fa64c838285e2d79554a60dc8 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.cpp
+++ b/source/Lib/EncoderLib/EncModeCtrl.cpp
@@ -2259,6 +2259,9 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
         }
         else if (CU::isIBC(*bestCU))
         {
+#if JVET_AA0070_RRIBC
+          relatedCU.isRribcCoded = bestCU->rribcFlipType > 0;
+#endif
           relatedCU.isIBC = true;
           relatedCU.isSkip |= bestCU->skip;
           if (bestCU->slice->getSPS()->getUseColorTrans())
diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h
index e347c668e916fa3bfa61907d3d94506578123cc1..ee5734cbb7498c1081dd423c50d1cf0e0d857603 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.h
+++ b/source/Lib/EncoderLib/EncModeCtrl.h
@@ -966,6 +966,10 @@ struct CodedCUInfo
   int     numGeoDirCand;
   int     geoMrgIdx0List[GEO_MAX_TRY_WEIGHTED_SATD];
   int     geoMrgIdx1List[GEO_MAX_TRY_WEIGHTED_SATD];
+#endif
+#if JVET_AA0070_RRIBC
+  bool    isRribcCoded;
+  bool    isRribcTested;
 #endif
   bool validMv[NUM_REF_PIC_LIST_01][MAX_STORED_CU_INFO_REFS];
   Mv   saveMv [NUM_REF_PIC_LIST_01][MAX_STORED_CU_INFO_REFS];
diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp
index 5afacf2091433b0cb1e9013111ef39b46f6c5851..291a39d586aa6d6d8164bbc56c00e688466f5609 100644
--- a/source/Lib/EncoderLib/EncSlice.cpp
+++ b/source/Lib/EncoderLib/EncSlice.cpp
@@ -1751,7 +1751,11 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons
 
   if( ( !pcSlice->isIntra() && pcSlice->getSPS()->getFpelMmvdEnabledFlag() ) || ( pcSlice->getSPS()->getIBCFlag() && m_pcCuEncoder->getEncCfg()->getIBCHashSearch() ) )
   {
+#if JVET_AA0070_RRIBC
+    m_pcCuEncoder->getIbcHashMap().rebuildPicHashMap(cs.picture->getTrueOrigBuf(), CS::isDualITree(cs));
+#else
     m_pcCuEncoder->getIbcHashMap().rebuildPicHashMap(cs.picture->getTrueOrigBuf());
+#endif
     if (m_pcCfg->getIntraPeriod() != -1)
     {
       int hashBlkHitPerc = m_pcCuEncoder->getIbcHashMap().calHashBlkMatchPerc(cs.area.Y());
diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp
index fa1f06e3e01439daf2f1de95b69adb2566efc236..890858ebdf442acb9743ce98bc47fa2bb28972c0 100644
--- a/source/Lib/EncoderLib/InterSearch.cpp
+++ b/source/Lib/EncoderLib/InterSearch.cpp
@@ -923,6 +923,9 @@ void InterSearch::xIBCSearchMVCandUpdate(Distortion  sad, int x, int y, Distorti
   }
 }
 
+#if JVET_AA0070_RRIBC
+int InterSearch::xIBCSearchMVChromaRefine( PredictionUnit& pu, int roiWidth, int roiHeight, int cuPelX, int cuPelY, Distortion* sadBestCand, Mv* cMVCand, int rribcFlipType )
+#else
 int InterSearch::xIBCSearchMVChromaRefine(PredictionUnit& pu,
   int         roiWidth,
   int         roiHeight,
@@ -930,8 +933,8 @@ int InterSearch::xIBCSearchMVChromaRefine(PredictionUnit& pu,
   int         cuPelY,
   Distortion* sadBestCand,
   Mv*     cMVCand
-
 )
+#endif
 {
   if ( (!isChromaEnabled(pu.chromaFormat)) || (!pu.Cb().valid()) )
   {
@@ -957,6 +960,12 @@ int InterSearch::xIBCSearchMVChromaRefine(PredictionUnit& pu,
     {
       continue;
     }
+#if JVET_AA0070_RRIBC
+    if ((rribcFlipType == 1 && cMVCand[cand].getVer() != 0) || (rribcFlipType == 2 && cMVCand[cand].getHor() != 0))
+    {
+      continue;
+    }
+#endif
 
     if ((!cMVCand[cand].getHor()) && (!cMVCand[cand].getVer()))
       continue;
@@ -984,7 +993,22 @@ int InterSearch::xIBCSearchMVChromaRefine(PredictionUnit& pu,
 
       PelUnitBuf origBuf = pu.cs->getOrgBuf(allCompBlocks);
       PelUnitBuf* pBuf = &origBuf;
+#if JVET_AA0070_RRIBC
+      PelBuf tmpPattern;
+      if (rribcFlipType)
+      {
+        CompArea tmpArea(ComponentID(ch), pu.chromaFormat, Position(0, 0), Size(pBuf->get(ComponentID(ch)).width, pBuf->get(ComponentID(ch)).height));
+        tmpPattern = m_tmpStorageLCU.getBuf(tmpArea);
+        tmpPattern.copyFrom(pBuf->get(ComponentID(ch)));
+        tmpPattern.flipSignal(rribcFlipType == 1);
+      }
+      else
+      {
+        tmpPattern = pBuf->get(ComponentID(ch));
+      }
+#else
       CPelBuf  tmpPattern = pBuf->get(ComponentID(ch));
+#endif
       pOrg = (Pel*)tmpPattern.buf;
 
       Picture* refPic = pu.cu->slice->getPic();
@@ -1050,7 +1074,11 @@ static unsigned int xMergeCandLists(Mv *dst, unsigned int dn, unsigned int dstTo
   return dn;
 }
 
-void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cStruct, Mv& rcMv, Distortion&  ruiCost, Mv*  pcMvSrchRngLT, Mv*  pcMvSrchRngRB, Mv* pcMvPred)
+#if JVET_AA0070_RRIBC
+void InterSearch::xIntraPatternSearch( PredictionUnit &pu, IntTZSearchStruct &cStruct, Mv &rcMv, Distortion &ruiCost, Mv *pcMvSrchRngLT, Mv *pcMvSrchRngRB, Mv *pcMvPred, int rribcFlipType )
+#else
+void InterSearch::xIntraPatternSearch(PredictionUnit &pu, IntTZSearchStruct &cStruct, Mv &rcMv, Distortion &ruiCost, Mv *pcMvSrchRngLT, Mv *pcMvSrchRngRB, Mv *pcMvPred)
+#endif
 {
   const int   srchRngHorLeft = pcMvSrchRngLT->getHor();
   const int   srchRngHorRight = pcMvSrchRngRB->getHor();
@@ -1111,6 +1139,13 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
       int xPred = m_acBVs[cand].getHor();
       int yPred = m_acBVs[cand].getVer();
 
+#if JVET_AA0070_RRIBC
+      if ((rribcFlipType == 1 && yPred != 0) || (rribcFlipType == 2 && xPred != 0))
+      {
+        continue;
+      }
+#endif
+
       if (!(xPred == 0 && yPred == 0)
         && !((yPred < srTop) || (yPred > srBottom))
         && !((xPred < srLeft) || (xPred > srRight)))
@@ -1123,7 +1158,11 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
 
         if (validCand)
         {
+#if JVET_AA0070_RRIBC
+          sad = m_pcRdCost->getBvCostMultiplePreds(xPred, yPred, pu.cs->sps->getAMVREnabledFlag(), rribcFlipType);
+#else
           sad = m_pcRdCost->getBvCostMultiplePreds(xPred, yPred, pu.cs->sps->getAMVREnabledFlag());
+#endif
           m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * yPred + xPred;
           sad += m_cDistParam.distFunc(m_cDistParam);
 
@@ -1140,6 +1179,12 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
     const int boundY = (0 - roiHeight - puPelOffsetY);
     for (int y = std::max(srchRngVerTop, 0 - cuPelY); y <= boundY; ++y)
     {
+#if JVET_AA0070_RRIBC
+      if (rribcFlipType == 1 && y != 0)
+      {
+        continue;
+      }
+#endif
 #if JVET_Z0084_IBC_TM
       if (!PU::searchBv(pu, cuPelX, cuPelY, roiWidth, roiHeight, picWidth, picHeight, 0, y, lcuWidth))
 #else
@@ -1149,7 +1194,11 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
         continue;
       }
 
+#if JVET_AA0070_RRIBC
+      sad = m_pcRdCost->getBvCostMultiplePreds(0, y, pu.cs->sps->getAMVREnabledFlag(), rribcFlipType);
+#else
       sad = m_pcRdCost->getBvCostMultiplePreds(0, y, pu.cs->sps->getAMVREnabledFlag());
+#endif
       m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * y;
       sad += m_cDistParam.distFunc(m_cDistParam);
 
@@ -1169,6 +1218,12 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
     const int boundX = std::max(srchRngHorLeft, -cuPelX);
     for (int x = 0 - roiWidth - puPelOffsetX; x >= boundX; --x)
     {
+#if JVET_AA0070_RRIBC
+      if (rribcFlipType == 2 && x != 0)
+      {
+        continue;
+      }
+#endif
 #if JVET_Z0084_IBC_TM
       if (!PU::searchBv(pu, cuPelX, cuPelY, roiWidth, roiHeight, picWidth, picHeight, x, 0, lcuWidth))
 #else
@@ -1178,7 +1233,11 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
         continue;
       }
 
+#if JVET_AA0070_RRIBC
+      sad = m_pcRdCost->getBvCostMultiplePreds(x, 0, pu.cs->sps->getAMVREnabledFlag(), rribcFlipType);
+#else
       sad = m_pcRdCost->getBvCostMultiplePreds(x, 0, pu.cs->sps->getAMVREnabledFlag());
+#endif
       m_cDistParam.cur.buf = piRefSrch + x;
       sad += m_cDistParam.distFunc(m_cDistParam);
 
@@ -1199,10 +1258,17 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
     bestX = cMVCand[0].getHor();
     bestY = cMVCand[0].getVer();
     sadBest = sadBestCand[0];
+#if JVET_AA0070_RRIBC
+    if ((!bestX && !bestY) || (sadBest - m_pcRdCost->getBvCostMultiplePreds(bestX, bestY, pu.cs->sps->getAMVREnabledFlag(), rribcFlipType) <= 32))
+    {
+      //chroma refine
+      bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand, rribcFlipType);
+#else
     if ((!bestX && !bestY) || (sadBest - m_pcRdCost->getBvCostMultiplePreds(bestX, bestY, pu.cs->sps->getAMVREnabledFlag()) <= 32))
     {
       //chroma refine
       bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand);
+#endif
       bestX = cMVCand[bestCandIdx].getHor();
       bestY = cMVCand[bestCandIdx].getVer();
       sadBest = sadBestCand[bestCandIdx];
@@ -1222,20 +1288,44 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
 
       for (int y = std::max(verTop, -cuPelY); y <= verBottom; y += 2)
       {
+#if JVET_AA0070_RRIBC
+        if (rribcFlipType == 1 && y != 0)
+        {
+          continue;
+        }
+#endif
         if ((y == 0) || ((int)(cuPelY + y + roiHeight) >= picHeight))
         {
           continue;
         }        
         for (int x = std::max(horLeft, -cuPelX); x <= horRight; x++)
         {
+#if JVET_AA0070_RRIBC
+          if (rribcFlipType == 2 && x != 0)
+          {
+            continue;
+          }
+#endif
 #else
       for (int y = std::max(srchRngVerTop, -cuPelY); y <= srchRngVerBottom; y += 2)
       {
+#if JVET_AA0070_RRIBC
+        if (rribcFlipType == 1 && y != 0)
+        {
+          continue;
+        }
+#endif
         if ((y == 0) || ((int)(cuPelY + y + roiHeight) >= picHeight))
           continue;
 
         for (int x = std::max(srchRngHorLeft, -cuPelX); x <= srchRngHorRight; x++)
         {
+#if JVET_AA0070_RRIBC
+          if (rribcFlipType == 2 && x != 0)
+          {
+            continue;
+          }
+#endif
 #endif
           if ((x == 0) || ((int)(cuPelX + x + roiWidth) >= picWidth))
             continue;
@@ -1249,7 +1339,11 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
             continue;
           }
 
+#if JVET_AA0070_RRIBC
+          sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getAMVREnabledFlag(), rribcFlipType);
+#else
           sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getAMVREnabledFlag());
+#endif
           m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * y + x;
           sad += m_cDistParam.distFunc(m_cDistParam);
 
@@ -1260,11 +1354,16 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
       bestX = cMVCand[0].getHor();
       bestY = cMVCand[0].getVer();
       sadBest = sadBestCand[0];
+#if JVET_AA0070_RRIBC
+      if (sadBest - m_pcRdCost->getBvCostMultiplePreds(bestX, bestY, pu.cs->sps->getAMVREnabledFlag(), rribcFlipType) <= 16)
+      {
+        bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand, rribcFlipType);
+#else
       if (sadBest - m_pcRdCost->getBvCostMultiplePreds(bestX, bestY, pu.cs->sps->getAMVREnabledFlag()) <= 16)
       {
-        //chroma refine
+        // chroma refine
         bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand);
-
+#endif
         bestX = cMVCand[bestCandIdx].getHor();
         bestY = cMVCand[bestCandIdx].getVer();
         sadBest = sadBestCand[bestCandIdx];
@@ -1276,6 +1375,12 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
 #if JVET_Z0153_IBC_EXT_REF
       for (int y = (std::max(verTop, -cuPelY) + 1); y <= verBottom; y += 2)
       {
+#if JVET_AA0070_RRIBC
+        if (rribcFlipType == 1 && y != 0)
+        {
+          continue;
+        }
+#endif
         if ((y == 0) || ((int)(cuPelY + y + roiHeight) >= picHeight))
         {
           continue;
@@ -1285,12 +1390,24 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
 #else
       for (int y = (std::max(srchRngVerTop, -cuPelY) + 1); y <= srchRngVerBottom; y += 2)
       {
+#if JVET_AA0070_RRIBC
+        if (rribcFlipType == 1 && y != 0)
+        {
+          continue;
+        }
+#endif
         if ((y == 0) || ((int)(cuPelY + y + roiHeight) >= picHeight))
           continue;
 
         for (int x = std::max(srchRngHorLeft, -cuPelX); x <= srchRngHorRight; x += 2)
 #endif
         {
+#if JVET_AA0070_RRIBC
+          if (rribcFlipType == 2 && x != 0)
+          {
+            continue;
+          }
+#endif
           if ((x == 0) || ((int)(cuPelX + x + roiWidth) >= picWidth))
             continue;
 
@@ -1303,7 +1420,12 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
             continue;
           }
 
+#if JVET_AA0070_RRIBC
+          sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getAMVREnabledFlag(), rribcFlipType);
+#else
           sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getAMVREnabledFlag());
+#endif
+
           m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * y + x;
           sad += m_cDistParam.distFunc(m_cDistParam);
 
@@ -1311,8 +1433,12 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
           xIBCSearchMVCandUpdate(sad, x, y, sadBestCand, cMVCand);
           if (sadBestCand[0] <= 5)
           {
-            //chroma refine & return
+            // chroma refine & return
+#if JVET_AA0070_RRIBC
+            bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand, rribcFlipType);
+#else
             bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand);
+#endif
             bestX = cMVCand[bestCandIdx].getHor();
             bestY = cMVCand[bestCandIdx].getVer();
             sadBest = sadBestCand[bestCandIdx];
@@ -1327,10 +1453,17 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
       bestY = cMVCand[0].getVer();
       sadBest = sadBestCand[0];
 
+#if JVET_AA0070_RRIBC
+      if ((sadBest >= tempSadBest) || ((sadBest - m_pcRdCost->getBvCostMultiplePreds(bestX, bestY, pu.cs->sps->getAMVREnabledFlag(), rribcFlipType)) <= 32))
+      {
+        // chroma refine
+        bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand, rribcFlipType);
+#else
       if ((sadBest >= tempSadBest) || ((sadBest - m_pcRdCost->getBvCostMultiplePreds(bestX, bestY, pu.cs->sps->getAMVREnabledFlag())) <= 32))
       {
-        //chroma refine
+        // chroma refine
         bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand);
+#endif
         bestX = cMVCand[bestCandIdx].getHor();
         bestY = cMVCand[bestCandIdx].getVer();
         sadBest = sadBestCand[bestCandIdx];
@@ -1344,6 +1477,12 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
 #if JVET_Z0153_IBC_EXT_REF
       for (int y = (std::max(verTop, -cuPelY) + 1); y <= verBottom; y += 2)
       {
+#if JVET_AA0070_RRIBC
+        if (rribcFlipType == 1 && y != 0)
+        {
+          continue;
+        }
+#endif
         if ((y == 0) || ((int)(cuPelY + y + roiHeight) >= picHeight))
         {
           continue;
@@ -1352,6 +1491,12 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
 #else
       for (int y = (std::max(srchRngVerTop, -cuPelY) + 1); y <= srchRngVerBottom; y += 2)
       {
+#if JVET_AA0070_RRIBC
+        if (rribcFlipType == 1 && y != 0)
+        {
+          continue;
+        }
+#endif
         if ((y == 0) || ((int)(cuPelY + y + roiHeight) >= picHeight))
           continue;
 
@@ -1359,6 +1504,12 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
 #endif
         {
 
+#if JVET_AA0070_RRIBC
+          if (rribcFlipType == 2 && x != 0)
+          {
+            continue;
+          }
+#endif
           if ((x == 0) || ((int)(cuPelX + x + roiWidth) >= picWidth))
             continue;
 
@@ -1371,7 +1522,11 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
             continue;
           }
 
+#if JVET_AA0070_RRIBC
+          sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getAMVREnabledFlag(), rribcFlipType);
+#else
           sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getAMVREnabledFlag());
+#endif
           m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * y + x;
           sad += m_cDistParam.distFunc(m_cDistParam);
 
@@ -1379,8 +1534,12 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
           xIBCSearchMVCandUpdate(sad, x, y, sadBestCand, cMVCand);
           if (sadBestCand[0] <= 5)
           {
-            //chroma refine & return
+            // chroma refine & return
+#if JVET_AA0070_RRIBC
+            bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand, rribcFlipType);
+#else
             bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand);
+#endif
             bestX = cMVCand[bestCandIdx].getHor();
             bestY = cMVCand[bestCandIdx].getVer();
             sadBest = sadBestCand[bestCandIdx];
@@ -1393,7 +1552,11 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct&  cS
     }
   }
 
+#if JVET_AA0070_RRIBC
+  bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand, rribcFlipType);
+#else
   bestCandIdx = xIBCSearchMVChromaRefine(pu, roiWidth, roiHeight, cuPelX, cuPelY, sadBestCand, cMVCand);
+#endif
 
   bestX = cMVCand[bestCandIdx].getHor();
   bestY = cMVCand[bestCandIdx].getVer();
@@ -1411,10 +1574,28 @@ end:
 
   for (unsigned int cand = 0; cand < CHROMA_REFINEMENT_CANDIDATES; cand++)
   {
+#if JVET_AA0070_RRIBC
+    if ((rribcFlipType == 1 && cMVCand[cand].getVer() != 0) || (rribcFlipType == 2 && cMVCand[cand].getHor() != 0))
+    {
+      continue;
+    }
+    if (m_pcEncCfg->getIntraPeriod() < 1 && m_pcEncCfg->getIBCFastMethod())
+    {
+      if (sadBestCand[cand] >= minCostProj)
+      {
+        break;
+      }
+      else if (!cand && rribcFlipType)
+      {
+        minCostProj =  3 * sadBestCand[0];
+      }
+    }
+#endif
     if (cMVCand[cand].getHor() == 0 && cMVCand[cand].getVer() == 0)
     {
       continue;
     }
+
     m_ctuRecord[pu.lumaPos()][pu.lumaSize()].bvRecord[cMVCand[cand]] = sadBestCand[cand];
   }
 
@@ -1424,11 +1605,11 @@ end:
 
 
 // based on xMotionEstimation
-void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf,
-  Mv     *pcMvPred,
-  Mv     &rcMv,
-  Distortion &ruiCost, const int localSearchRangeX, const int localSearchRangeY
-)
+#if JVET_AA0070_RRIBC
+void InterSearch::xIBCEstimation(PredictionUnit &pu, PelUnitBuf &origBuf, Mv pcMvPred[3][2], Mv &rcMv, Distortion &ruiCost, const int localSearchRangeX, const int localSearchRangeY, int numRribcType)
+#else
+void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, Mv *pcMvPred, Mv &rcMv, Distortion &ruiCost, const int localSearchRangeX, const int localSearchRangeY)
+#endif
 {
   const int iPicWidth = pu.cs->slice->getPPS()->getPicWidthInLumaSamples();
   const int iPicHeight = pu.cs->slice->getPPS()->getPicHeightInLumaSamples();
@@ -1444,7 +1625,47 @@ void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf,
   CPelBuf  tmpPattern = pBuf->Y();
   CPelBuf* pcPatternKey = &tmpPattern;
   PelBuf tmpOrgLuma;
+#if JVET_AA0070_RRIBC
+  const CompArea &area = pu.blocks[COMPONENT_Y];
+  CompArea        tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size());
+  if ((pu.cs->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()))
+  {
+    tmpOrgLuma = m_tmpStorageLCU.getBuf(tmpArea);
+    tmpOrgLuma.rspSignal(tmpPattern, m_pcReshape->getFwdLUT());
+    pcPatternKey = (CPelBuf *) &tmpOrgLuma;
+  }
+
+  CPelBuf   *pcPatternKeyFlipH;
+  CPelBuf   *pcPatternKeyFlipV;
+  PelStorage m_tmpStorageCUflipH;
+  PelStorage m_tmpStorageCUflipV;
+  PelBuf tmpOrgLumaFlipH, tmpOrgLumaFlipV;
 
+  if (numRribcType > 1)
+  {
+    m_tmpStorageCUflipH.create(UnitArea(pu.chromaFormat, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE)));
+    tmpOrgLumaFlipH = m_tmpStorageCUflipH.getBuf(tmpArea);
+
+    m_tmpStorageCUflipV.create(UnitArea(pu.chromaFormat, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE)));
+    tmpOrgLumaFlipV = m_tmpStorageCUflipV.getBuf(tmpArea);
+
+    if ((pu.cs->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()))
+    {
+      tmpOrgLumaFlipH.copyFrom(tmpOrgLuma);
+      tmpOrgLumaFlipV.copyFrom(tmpOrgLuma);
+    }
+    else
+    {
+      tmpOrgLumaFlipH.copyFrom(tmpPattern);
+      tmpOrgLumaFlipV.copyFrom(tmpPattern);
+    }
+    tmpOrgLumaFlipH.flipSignal(true);
+    pcPatternKeyFlipH = (CPelBuf *) &tmpOrgLumaFlipH;
+
+    tmpOrgLumaFlipV.flipSignal(false);
+    pcPatternKeyFlipV = (CPelBuf *) &tmpOrgLumaFlipV;
+  }
+#else
   if ((pu.cs->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()))
   {
     const CompArea &area = pu.blocks[COMPONENT_Y];
@@ -1453,13 +1674,16 @@ void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf,
     tmpOrgLuma.rspSignal( tmpPattern, m_pcReshape->getFwdLUT() );
     pcPatternKey = (CPelBuf*)&tmpOrgLuma;
   }
+#endif
 
   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;
+#if !JVET_AA0070_RRIBC
   cStruct.pcPatternKey = pcPatternKey;
+#endif
   cStruct.iRefStride = refBuf.stride;
   cStruct.piRefY = refBuf.buf;
   CHECK(pu.cu->imv == IMV_HPEL, "IF_IBC");
@@ -1474,15 +1698,187 @@ void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf,
   m_pcRdCost->setCostScale(0);
 
   m_cDistParam.useMR = false;
+#if !JVET_AA0070_RRIBC
   m_pcRdCost->setDistParam(m_cDistParam, *cStruct.pcPatternKey, cStruct.piRefY, cStruct.iRefStride, m_lumaClpRng.bd, COMPONENT_Y, cStruct.subShiftMode);
+#endif
   bool buffered = false;
+#if JVET_AA0070_RRIBC
+  minCostProj = MAX_INT;
+  if (m_pcEncCfg->getIntraPeriod() < 1 && m_pcEncCfg->getIBCFastMethod())
+  {
+    ruiCost  = MAX_UINT;
+    std::unordered_map<Mv, Distortion> &history = m_ctuRecord[pu.lumaPos()][pu.lumaSize()].bvRecord;
+    if (history.size())
+    {
+      std::vector<std::pair<Mv, Distortion>> historyOrdered(history.size());
+      int                                    i = 0;
+      for (std::unordered_map<Mv, Distortion>::iterator p = history.begin(); p != history.end(); p++)
+      {
+        historyOrdered[i] = { p->first, p->second };
+        i++;
+      }
+     std::stable_sort(historyOrdered.begin(), historyOrdered.end(),[](const std::pair<Mv, Distortion> &l, const std::pair<Mv, Distortion> &r)
+                     { return (l.second < r.second) || (l.second == r.second && (l.first.getHor() < r.first.getHor() || (l.first.getHor() == r.first.getHor() && l.first.getVer() < r.first.getVer()))); });
+     minCostProj = 3 * historyOrdered[0].second;
+
+      Distortion cand0Cost[3] = { MAX_UINT, MAX_UINT, MAX_UINT };
+      bool       isCalc[3] = { false }, isSkip[3] = { false }, checkDone[3] = { false };
+      int        map[6] = { 1, 2, 0, 2, 0, 1 };
+      for (int i = 0; i < history.size(); i++)
+      {
+        if (historyOrdered[i].second >= minCostProj)
+        {
+          break;
+        }
+        const Mv &bv  = historyOrdered[i].first;
+        int       xBv = bv.hor;
+        int       yBv = bv.ver;
+
+        for (int rribcFlipType = 0; rribcFlipType < numRribcType; rribcFlipType++)
+        {
+          if (isSkip[rribcFlipType])
+          {
+            continue;
+          }
+          if (!checkDone[rribcFlipType] && isCalc[rribcFlipType] && (isCalc[map[rribcFlipType * 2]] || isCalc[map[rribcFlipType * 2 + 1]]))
+          {
+            if (isCalc[map[rribcFlipType * 2]] && cand0Cost[rribcFlipType] >= 1.1 * cand0Cost[map[rribcFlipType * 2]])
+            {
+              isSkip[rribcFlipType] = true;
+            }
+            else if (isCalc[map[rribcFlipType * 2]] && cand0Cost[rribcFlipType] >= 1.1 * cand0Cost[map[rribcFlipType * 2 + 1]])
+            {
+              isSkip[rribcFlipType] = true;
+            }
+            checkDone[rribcFlipType] = true;
+          }
+          if ((rribcFlipType == 1 && yBv != 0) || (rribcFlipType == 2 && xBv != 0))
+          {
+            continue;
+          }
+#if JVET_Z0084_IBC_TM
+          if (PU::searchBv(pu, cuPelX, cuPelY, iRoiWidth, iRoiHeight, iPicWidth, iPicHeight, xBv, yBv, lcuWidth))
+#else
+          if (searchBv(pu, cuPelX, cuPelY, iRoiWidth, iRoiHeight, iPicWidth, iPicHeight, xBv, yBv, lcuWidth))
+#endif
+          {
+            buffered = true;
+            Distortion sad = m_pcRdCost->getBvCostMultiplePreds(xBv, yBv, pu.cs->sps->getAMVREnabledFlag(), rribcFlipType);
+            cStruct.pcPatternKey = (rribcFlipType == 0) ? pcPatternKey : ((rribcFlipType == 1) ? pcPatternKeyFlipH : pcPatternKeyFlipV);
+            m_pcRdCost->setDistParam(m_cDistParam, *cStruct.pcPatternKey, cStruct.piRefY, cStruct.iRefStride, m_lumaClpRng.bd, COMPONENT_Y, cStruct.subShiftMode);
+            m_cDistParam.cur.buf = cStruct.piRefY + cStruct.iRefStride * yBv + xBv;
+            sad += m_cDistParam.distFunc(m_cDistParam);
+            if (!isCalc[rribcFlipType])
+            {
+              cand0Cost[rribcFlipType] = sad;
+              isCalc[rribcFlipType]    = true;
+            }
+            if (sad < ruiCost)
+            {
+              rcMv                 = bv;
+              ruiCost              = sad;
+              pu.cu->rribcFlipType = rribcFlipType;
+            }
+            else if (sad == ruiCost)
+            {
+              // stabilise the search through the unordered list
+              if (abs(bv.hor) < abs(rcMv.getHor()) || (bv.hor == rcMv.getHor() && abs(bv.ver) < abs(rcMv.getVer())))
+              {
+                // update the vector.
+                rcMv                 = bv;
+                pu.cu->rribcFlipType = rribcFlipType;
+              }
+            }
+          }
+        }
+      }
+
+      if (buffered)
+      {
+        Mv  cMvPredEncOnly[IBC_NUM_CANDIDATES];
+        int nbPreds = 0;
+        PU::getIbcMVPsEncOnly(pu, cMvPredEncOnly, nbPreds);
+
+        for (unsigned int cand = 0; cand < nbPreds; cand++)
+        {
+          int xPred = cMvPredEncOnly[cand].getHor();
+          int yPred = cMvPredEncOnly[cand].getVer();
+
+          for (int rribcFlipType = 0; rribcFlipType < numRribcType; rribcFlipType++)
+          {
+            if (isSkip[rribcFlipType])
+            {
+              continue;
+            }
+            if ((rribcFlipType == 1 && yPred != 0) || (rribcFlipType == 2 && xPred != 0))
+            {
+              continue;
+            }
+#if JVET_Z0084_IBC_TM
+            if (PU::searchBv(pu, cuPelX, cuPelY, iRoiWidth, iRoiHeight, iPicWidth, iPicHeight, xPred, yPred, lcuWidth))
+#else
+            if (searchBv(pu, cuPelX, cuPelY, iRoiWidth, iRoiHeight, iPicWidth, iPicHeight, xPred, yPred, lcuWidth))
+#endif
+            {
+              Distortion sad = m_pcRdCost->getBvCostMultiplePreds(xPred, yPred, pu.cs->sps->getAMVREnabledFlag(), rribcFlipType);
+              cStruct.pcPatternKey = (rribcFlipType == 0) ? pcPatternKey : ((rribcFlipType == 1) ? pcPatternKeyFlipH : pcPatternKeyFlipV);
+              m_pcRdCost->setDistParam(m_cDistParam, *cStruct.pcPatternKey, cStruct.piRefY, cStruct.iRefStride, m_lumaClpRng.bd, COMPONENT_Y, cStruct.subShiftMode);
+              m_cDistParam.cur.buf = cStruct.piRefY + cStruct.iRefStride * yPred + xPred;
+              sad += m_cDistParam.distFunc(m_cDistParam);
+              if (sad >= minCostProj)
+              {
+                continue;
+              }
+              if (sad < ruiCost)
+              {
+                rcMv.set(xPred, yPred);
+                ruiCost              = sad;
+                pu.cu->rribcFlipType = rribcFlipType;
+              }
+              else if (sad == ruiCost)
+              {
+                // stabilise the search through the unordered list
+                if (abs(xPred) < abs(rcMv.getHor()) || (xPred == rcMv.getHor() && abs(yPred) < abs(rcMv.getVer())))
+                {
+                  // update the vector.
+                  rcMv.set(xPred, yPred);
+                  pu.cu->rribcFlipType = rribcFlipType;
+                }
+              }
+
+              m_ctuRecord[pu.lumaPos()][pu.lumaSize()].bvRecord[Mv(xPred, yPred)] = sad;
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (m_pcEncCfg->getIBCFastMethod() & IBC_FAST_METHOD_BUFFERBV)
+#else
   if (m_pcEncCfg->getIBCFastMethod() & IBC_FAST_METHOD_BUFFERBV)
+#endif
   {
     ruiCost = MAX_UINT;
     std::unordered_map<Mv, Distortion>& history = m_ctuRecord[pu.lumaPos()][pu.lumaSize()].bvRecord;
+#if JVET_AA0070_RRIBC
+    std::vector<std::pair<Mv, Distortion>> historyOrdered(history.size());
+    int                                    i = 0;
+    for (std::unordered_map<Mv, Distortion>::iterator p = history.begin(); p != history.end(); p++)
+    {
+      historyOrdered[i] = { p->first, p->second };
+      i++;
+    }
+    std::stable_sort(historyOrdered.begin(), historyOrdered.end(),[](const std::pair<Mv, Distortion> &l, const std::pair<Mv, Distortion> &r)
+                     { return (l.second < r.second) || (l.second == r.second && (l.first.getHor() < r.first.getHor() || (l.first.getHor() == r.first.getHor() && l.first.getVer() < r.first.getVer()))); });
+
+    for (int i = 0; i < history.size(); i++)
+    {
+        const Mv &bv  = historyOrdered[i].first;
+#else
     for (std::unordered_map<Mv, Distortion>::iterator p = history.begin(); p != history.end(); p++)
     {
       const Mv& bv = p->first;
+#endif
 
       int xBv = bv.hor;
       int yBv = bv.ver;
@@ -1492,26 +1888,53 @@ void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf,
       if (searchBv(pu, cuPelX, cuPelY, iRoiWidth, iRoiHeight, iPicWidth, iPicHeight, xBv, yBv, lcuWidth))
 #endif
       {
+#if JVET_AA0070_RRIBC
+        for (int rribcFlipType = 0; rribcFlipType < numRribcType; rribcFlipType++)
+        {
+          if ((rribcFlipType == 1 && yBv != 0) || (rribcFlipType == 2 && xBv != 0))
+          {
+            continue;
+          }
+          buffered = true;
+          Distortion sad = m_pcRdCost->getBvCostMultiplePreds(xBv, yBv, pu.cs->sps->getAMVREnabledFlag(), rribcFlipType);
+          cStruct.pcPatternKey = (rribcFlipType == 0) ? pcPatternKey : ((rribcFlipType == 1) ? pcPatternKeyFlipH : pcPatternKeyFlipV);
+          m_pcRdCost->setDistParam(m_cDistParam, *cStruct.pcPatternKey, cStruct.piRefY, cStruct.iRefStride, m_lumaClpRng.bd, COMPONENT_Y, cStruct.subShiftMode);
+#else
         buffered = true;
         Distortion sad = m_pcRdCost->getBvCostMultiplePreds(xBv, yBv, pu.cs->sps->getAMVREnabledFlag());
+#endif
         m_cDistParam.cur.buf = cStruct.piRefY + cStruct.iRefStride * yBv + xBv;
         sad += m_cDistParam.distFunc(m_cDistParam);
         if (sad < ruiCost)
         {
           rcMv = bv;
           ruiCost = sad;
+#if JVET_AA0070_RRIBC
+          pu.cu->rribcFlipType = rribcFlipType;
+#endif
         }
         else if (sad == ruiCost)
         {
           // stabilise the search through the unordered list
-          if (bv.hor < rcMv.getHor()
-            || (bv.hor == rcMv.getHor() && bv.ver < rcMv.getVer()))
+#if JVET_AA0070_RRIBC
+          if (abs(bv.hor) < abs(rcMv.getHor()) || (bv.hor == rcMv.getHor() && abs(bv.ver) < abs(rcMv.getVer())))
+          {
+            // update the vector.
+            rcMv                 = bv;
+            pu.cu->rribcFlipType = rribcFlipType;
+          }
+        }
+        }
+      }
+#else
+          if (bv.hor < rcMv.getHor() || (bv.hor == rcMv.getHor() && bv.ver < rcMv.getVer()))
           {
             // update the vector.
             rcMv = bv;
           }
         }
       }
+#endif
     }
 
     if (buffered)
@@ -1531,26 +1954,46 @@ void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf,
         if (searchBv(pu, cuPelX, cuPelY, iRoiWidth, iRoiHeight, iPicWidth, iPicHeight, xPred, yPred, lcuWidth))
 #endif
         {
+#if JVET_AA0070_RRIBC
+          for (int rribcFlipType = 0; rribcFlipType < numRribcType; rribcFlipType++)
+          {
+            if ((rribcFlipType == 1 && yPred != 0) || (rribcFlipType == 2 && xPred != 0))
+            {
+              continue;
+            }
+            Distortion sad = m_pcRdCost->getBvCostMultiplePreds(xPred, yPred, pu.cs->sps->getAMVREnabledFlag(), rribcFlipType);
+            cStruct.pcPatternKey = (rribcFlipType == 0) ? pcPatternKey : ((rribcFlipType == 1) ? pcPatternKeyFlipH : pcPatternKeyFlipV);
+            m_pcRdCost->setDistParam(m_cDistParam, *cStruct.pcPatternKey, cStruct.piRefY, cStruct.iRefStride, m_lumaClpRng.bd, COMPONENT_Y, cStruct.subShiftMode);
+#else
           Distortion sad = m_pcRdCost->getBvCostMultiplePreds(xPred, yPred, pu.cs->sps->getAMVREnabledFlag());
+#endif
           m_cDistParam.cur.buf = cStruct.piRefY + cStruct.iRefStride * yPred + xPred;
           sad += m_cDistParam.distFunc(m_cDistParam);
           if (sad < ruiCost)
           {
             rcMv.set(xPred, yPred);
             ruiCost = sad;
+#if JVET_AA0070_RRIBC
+            pu.cu->rribcFlipType = rribcFlipType;
+#endif
           }
           else if (sad == ruiCost)
           {
             // stabilise the search through the unordered list
-            if (xPred < rcMv.getHor()
-              || (xPred == rcMv.getHor() && yPred < rcMv.getVer()))
+            if (xPred < rcMv.getHor() || (xPred == rcMv.getHor() && yPred < rcMv.getVer()))
             {
               // update the vector.
               rcMv.set(xPred, yPred);
+#if JVET_AA0070_RRIBC
+              pu.cu->rribcFlipType = rribcFlipType;
+#endif
             }
           }
 
           m_ctuRecord[pu.lumaPos()][pu.lumaSize()].bvRecord[Mv(xPred, yPred)] = sad;
+#if JVET_AA0070_RRIBC
+          }
+#endif
         }
       }
     }
@@ -1565,8 +2008,32 @@ void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf,
     xSetIntraSearchRange(pu, pu.lwidth(), pu.lheight(), localSearchRangeX, localSearchRangeY, cMvSrchRngLT, cMvSrchRngRB);
 
     //  Do integer search
+#if JVET_AA0070_RRIBC
+    Distortion minCost = MAX_UINT;
+    Mv         tempMv;
+    tempMv.setZero();
+    for (int rribcFlipType = 0; rribcFlipType < numRribcType; rribcFlipType++)
+    {
+      cStruct.pcPatternKey = (rribcFlipType == 0) ? pcPatternKey : ((rribcFlipType == 1) ? pcPatternKeyFlipH : pcPatternKeyFlipV);
+      m_pcRdCost->setDistParam(m_cDistParam, *cStruct.pcPatternKey, cStruct.piRefY, cStruct.iRefStride, m_lumaClpRng.bd, COMPONENT_Y, cStruct.subShiftMode);
+      xIntraPatternSearch(pu, cStruct, tempMv, ruiCost, &cMvSrchRngLT, &cMvSrchRngRB, pcMvPred[rribcFlipType], rribcFlipType);
+      if (ruiCost < minCost)
+      {
+        minCost = ruiCost;
+        rcMv.set(tempMv.getHor(), tempMv.getVer());
+        pu.cu->rribcFlipType = rribcFlipType;
+      }
+    }
+  }
+  if (numRribcType > 1)
+  {
+    m_tmpStorageCUflipH.destroy();
+    m_tmpStorageCUflipV.destroy();
+  }
+#else
     xIntraPatternSearch(pu, cStruct, rcMv, ruiCost, &cMvSrchRngLT, &cMvSrchRngRB, pcMvPred);
   }
+#endif
 }
 
 // based on xSetSearchRange
@@ -1622,7 +2089,11 @@ void InterSearch::xSetIntraSearchRange(PredictionUnit& pu, int iRoiWidth, int iR
   rcMvSrchRngRB >>= 2;
 }
 
+#if JVET_AA0070_RRIBC
+bool InterSearch::predIBCSearch( CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap, bool isSecondPass)
+#else
 bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap)
+#endif
 {
   Mv           cMvSrchRngLT;
   Mv           cMvSrchRngRB;
@@ -1633,12 +2104,66 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const
 #if JVET_Z0131_IBC_BVD_BINARIZATION
   xEstBvdBitCosts(m_pcRdCost->getBvdBitCosts());
 #endif
+#if JVET_AA0070_RRIBC
+  CodedCUInfo& relatedCU = ((EncModeCtrlMTnoRQT *)m_modeCtrl)->getBlkInfo(partitioner.currArea());
+#endif
 
   for (auto &pu : CU::traversePUs(cu))
   {
     m_maxCompIDToPred = MAX_NUM_COMPONENT;
 
     CHECK(pu.cu != &cu, "PU is contained in another CU");
+#if JVET_AA0070_RRIBC
+    int numRribcType = 3;
+    if (isSecondPass)
+    {
+      if (!relatedCU.isRribcCoded)
+      {
+        numRribcType = 1;
+      }
+    }
+    Mv       cMv;
+    cMv.setZero();
+    int iBvpNum    = 2;
+    int bvpIdxBest = 0;
+    Distortion cost = 0;
+
+    AMVPInfo amvpInfo4Pel[3];
+    AMVPInfo amvpInfo[3];
+    Mv       cMvPred[3][2];
+    for (int i = 0; i < numRribcType; i++)
+    {
+      pu.cu->rribcFlipType = i;
+
+      // prepare imv = 2 accuracy predictor info
+      pu.cu->imv      = 2;
+#if JVET_Z0084_IBC_TM && TM_AMVP
+      PU::fillIBCMvpCand(pu, amvpInfo4Pel[i], this);
+#else
+      PU::fillIBCMvpCand(pu, amvpInfo4Pel[i]);
+#endif
+
+      // prepare imv = 0 accuracy predictor info
+      pu.cu->imv = 0;
+#if JVET_Z0084_IBC_TM && TM_AMVP
+      PU::fillIBCMvpCand(pu, amvpInfo[i], this);
+#else
+      PU::fillIBCMvpCand(pu, amvpInfo[i]);
+#endif
+
+      // store in full pel accuracy, shift before use in search
+      cMvPred[i][0] = amvpInfo[i].mvCand[0];
+      cMvPred[i][0].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT);
+      cMvPred[i][1] = amvpInfo[i].mvCand[1];
+      cMvPred[i][1].changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT);
+      if (pu.cs->sps->getMaxNumIBCMergeCand() == 1)
+      {
+        iBvpNum    = 1;
+        cMvPred[i][1] = cMvPred[i][0];
+      }
+    }
+    pu.cu->rribcFlipType = 0;
+#else
     //////////////////////////////////////////////////////////
     /// ibc search
     pu.cu->imv = 2;
@@ -1673,17 +2198,26 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const
       iBvpNum = 1;
       cMvPred[1] = cMvPred[0];
     }
+#endif
 
     if (m_pcEncCfg->getIBCHashSearch())
     {
+#if JVET_AA0070_RRIBC
+      xxIBCHashSearch(pu, cMvPred, iBvpNum, cMv, bvpIdxBest, ibcHashMap, amvpInfo4Pel, numRribcType);
+#else
       xxIBCHashSearch(pu, cMvPred, iBvpNum, cMv, bvpIdxBest, ibcHashMap);
+#endif
     }
 
     if (cMv.getHor() == 0 && cMv.getVer() == 0)
     {
       // if hash search does not work or is not enabled
       PelUnitBuf origBuf = pu.cs->getOrgBuf(pu);
+#if JVET_AA0070_RRIBC
+      xIBCEstimation(pu, origBuf, cMvPred, cMv, cost, localSearchRangeX, localSearchRangeY, numRribcType);
+#else
       xIBCEstimation(pu, origBuf, cMvPred, cMv, cost, localSearchRangeX, localSearchRangeY);
+#endif
     }
 
     if (cMv.getHor() == 0 && cMv.getVer() == 0)
@@ -1695,11 +2229,19 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const
 #if JVET_Z0131_IBC_BVD_BINARIZATION
     m_pcRdCost->setPredictors(cMvPred);
     m_pcRdCost->setCostScale(0);
+#if JVET_AA0070_RRIBC
+#if JVET_Z0084_IBC_TM && IBC_TM_AMVP
+    m_pcRdCost->getBvCostMultiplePreds(cMv.getHor(), cMv.getVer(), pu.cs->sps->getAMVREnabledFlag(), pu.cu->rribcFlipType, &pu.cu->imv, &bvpIdxBest, true, &amvpInfo4Pel[pu.cu->rribcFlipType]);
+#else
+    m_pcRdCost->getBvCostMultiplePreds(cMv.getHor(), cMv.getVer(), pu.cs->sps->getAMVREnabledFlag(), pu.cu->rribcFlipType, &pu.cu->imv, &bvpIdxBest);
+#endif
+#else
 #if JVET_Z0084_IBC_TM && IBC_TM_AMVP
     m_pcRdCost->getBvCostMultiplePreds(cMv.getHor(), cMv.getVer(), pu.cs->sps->getAMVREnabledFlag(), &pu.cu->imv, &bvpIdxBest, true, &amvpInfo4Pel);
 #else
     m_pcRdCost->getBvCostMultiplePreds(cMv.getHor(), cMv.getVer(), pu.cs->sps->getAMVREnabledFlag(), &pu.cu->imv, &bvpIdxBest);
 #endif
+#endif
 #else
     unsigned int bitsBVPBest, bitsBVPTemp;
     bitsBVPBest = MAX_INT;
@@ -1707,16 +2249,31 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const
 
     for (int bvpIdxTemp = 0; bvpIdxTemp<iBvpNum; bvpIdxTemp++)
     {
+#if JVET_AA0070_RRIBC
+      Mv ccMvPred = cMvPred[pu.cu->rribcFlipType][bvpIdxTemp];
+      m_pcRdCost->setPredictor(ccMvPred);
+      bitsBVPTemp = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor(), cMv.getVer(), 0, cu.rribcFlipType);
+#else
       m_pcRdCost->setPredictor(cMvPred[bvpIdxTemp]);
 
       bitsBVPTemp = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor(), cMv.getVer(), 0);
+#endif
 
       if (bitsBVPTemp < bitsBVPBest)
       {
         bitsBVPBest = bitsBVPTemp;
         bvpIdxBest = bvpIdxTemp;
 
+#if JVET_AA0070_RRIBC
+        bool diffMV = false;
+        if ((pu.cu->rribcFlipType == 1 && cMv.getHor() != ccMvPred.getHor()) || (pu.cu->rribcFlipType == 2 && cMv.getVer() != ccMvPred.getVer()) || (pu.cu->rribcFlipType == 0 && cMv != ccMvPred))
+        {
+          diffMV = true;
+        }
+        if (cu.cs->sps->getAMVREnabledFlag() && diffMV)
+#else
         if (cu.cs->sps->getAMVREnabledFlag() && cMv != cMvPred[bvpIdxTemp])
+#endif
           pu.cu->imv = 1; // set as full-pel
         else
           pu.cu->imv = 0; // set as fractional-pel
@@ -1729,17 +2286,35 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const
       Mv mvPredQuadPel;
       if ((cMv.getHor() % 4 == 0) && (cMv.getVer() % 4 == 0) && (pu.cs->sps->getAMVREnabledFlag()))
       {
+#if JVET_AA0070_RRIBC
+        mvPredQuadPel = amvpInfo4Pel[pu.cu->rribcFlipType].mvCand[bvpIdxTemp];
+#else
         mvPredQuadPel = amvpInfo4Pel.mvCand[bvpIdxTemp];// cMvPred[bvpIdxTemp];
 
+#endif
+
         mvPredQuadPel.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_4PEL);
 
         m_pcRdCost->setPredictor(mvPredQuadPel);
 
+#if JVET_AA0070_RRIBC
+        bitsBVPQP = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor() >> 2, cMv.getVer() >> 2, 0, cu.rribcFlipType);
+#else
         bitsBVPQP = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor() >> 2, cMv.getVer() >> 2, 0);
+#endif
 
       }
       mvPredQuadPel.changePrecision(MV_PRECISION_4PEL, MV_PRECISION_INT);
+#if JVET_AA0070_RRIBC
+      bool diffMV = false;
+      if ((pu.cu->rribcFlipType == 1 && cMv.getHor() != mvPredQuadPel.getHor()) || (pu.cu->rribcFlipType == 2 && cMv.getVer() != mvPredQuadPel.getVer()) || (pu.cu->rribcFlipType == 0 && cMv != mvPredQuadPel))
+      {
+        diffMV = true;
+      }
+      if ((bitsBVPQP < bitsBVPBest) && diffMV)
+#else
       if (bitsBVPQP < bitsBVPBest && cMv != mvPredQuadPel)
+#endif
       {
         bitsBVPBest = bitsBVPQP;
         bvpIdxBest = bvpIdxTemp;
@@ -1751,16 +2326,36 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const
     }
 #endif
 
+
     pu.bv = cMv; // bv is always at integer accuracy
     cMv.changePrecision(MV_PRECISION_INT, MV_PRECISION_INTERNAL);
     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])
+#if JVET_AA0070_RRIBC
+    if (pu.cu->imv == 2 && cMv != amvpInfo4Pel[pu.cu->rribcFlipType].mvCand[bvpIdxBest])
+    {
+      pu.mvd[REF_PIC_LIST_0] = cMv - amvpInfo4Pel[pu.cu->rribcFlipType].mvCand[bvpIdxBest];
+    }
+    else
+    {
+      pu.mvd[REF_PIC_LIST_0] = cMv - amvpInfo[pu.cu->rribcFlipType].mvCand[bvpIdxBest];
+    }
+    if (pu.cu->rribcFlipType == 1)
+    {
+      pu.mvd[REF_PIC_LIST_0].setVer(0);
+    }
+    else if (pu.cu->rribcFlipType == 2)
+    {
+      pu.mvd[REF_PIC_LIST_0].setHor(0);
+    }
+#else
+    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];
+#endif
 
     if (pu.mvd[REF_PIC_LIST_0] == Mv(0, 0))
       pu.cu->imv = 0;
@@ -1776,11 +2371,61 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const
   return true;
 }
 
-void InterSearch::xxIBCHashSearch(PredictionUnit& pu, Mv* mvPred, int numMvPred, Mv &mv, int& idxMvPred, IbcHashMap& ibcHashMap)
+#if JVET_AA0070_RRIBC
+void InterSearch::xxIBCHashSearch(PredictionUnit &pu, Mv mvPred[3][2], int numMvPred, Mv &mv, int &idxMvPred, IbcHashMap &ibcHashMap, AMVPInfo amvpInfo4Pel[3], int numRribcType)
+#else
+void InterSearch::xxIBCHashSearch(PredictionUnit &pu, Mv *mvPred, int numMvPred, Mv &mv, int &idxMvPred, IbcHashMap &ibcHashMap)
+#endif
 {
   mv.setZero();
   m_pcRdCost->setCostScale(0);
 
+#if JVET_AA0070_RRIBC
+  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->getPPS()->getPicWidthInLumaSamples();
+  const int          picHeight = pu.cs->slice->getPPS()->getPicHeightInLumaSamples();
+  int                roiWidth  = pu.lwidth();
+  int                roiHeight = pu.lheight();
+#if JVET_Z0131_IBC_BVD_BINARIZATION
+  Distortion minCost = MAX_UINT64;
+  m_pcRdCost->setPredictors(mvPred);
+#else
+  unsigned int minCost = MAX_UINT;
+#endif
+
+  std::vector<Position> candPos[3];
+  bool                  isHashMatch[3] = { false };
+  for (int rribcFlipType = 0; rribcFlipType < numRribcType; rribcFlipType++)
+  {
+    if(rribcFlipType && m_pcEncCfg->getIntraPeriod() <= 1)
+    {
+      Distortion th = m_pcEncCfg->getIntraPeriod() == -1 ? 50 : 200;
+      if ((minCost < th) || (!isHashMatch[rribcFlipType - 1]))
+      {
+        continue;
+      }
+    }
+    else if (rribcFlipType)
+    {
+      if (minCost < 100 || (rribcFlipType == 1 && !isHashMatch[0]) || (rribcFlipType == 2 && !isHashMatch[0] && !isHashMatch[1]))
+      {
+        continue;
+      }
+    }
+    isHashMatch[rribcFlipType] = ibcHashMap.ibcHashMatch(pu, pu.Y(), candPos[rribcFlipType], *pu.cs, m_pcEncCfg->getIBCHashSearchMaxCand(), m_pcEncCfg->getIBCHashSearchRange4SmallBlk(), rribcFlipType);
+    if (!isHashMatch[rribcFlipType])
+    {
+      continue;
+    }
+    for (std::vector<Position>::iterator pos = candPos[rribcFlipType].begin(); pos != candPos[rribcFlipType].end(); pos++)
+    {
+      if ((rribcFlipType == 1 && (*pos - pu.Y().pos()).y != 0) || (rribcFlipType == 2 && (*pos - pu.Y().pos()).x != 0))
+      {
+        continue;
+      }
+#else
   std::vector<Position> candPos;
   if (ibcHashMap.ibcHashMatch(pu.Y(), candPos, *pu.cs, m_pcEncCfg->getIBCHashSearchMaxCand(), m_pcEncCfg->getIBCHashSearchRange4SmallBlk()))
   {
@@ -1801,6 +2446,7 @@ void InterSearch::xxIBCHashSearch(PredictionUnit& pu, Mv* mvPred, int numMvPred,
 
     for (std::vector<Position>::iterator pos = candPos.begin(); pos != candPos.end(); pos++)
     {
+#endif
       Position bottomRight = pos->offset(pu.Y().width - 1, pu.Y().height - 1);
       if (pu.cs->isDecomp(*pos, CHANNEL_TYPE_LUMA) && pu.cs->isDecomp(bottomRight, CHANNEL_TYPE_LUMA))
       {
@@ -1817,25 +2463,44 @@ void InterSearch::xxIBCHashSearch(PredictionUnit& pu, Mv* mvPred, int numMvPred,
           continue;
         }
 
+
 #if JVET_Z0131_IBC_BVD_BINARIZATION
+#if JVET_AA0070_RRIBC
+#if JVET_Z0084_IBC_TM && IBC_TM_AMVP
+        Distortion cost = m_pcRdCost->getBvCostMultiplePreds(candMv.getHor(), candMv.getVer(), pu.cs->sps->getAMVREnabledFlag(), rribcFlipType, &pu.cu->imv, &idxMvPred, true, &amvpInfo4Pel[rribcFlipType]);
+#else
+        Distortion cost = m_pcRdCost->getBvCostMultiplePreds(candMv.getHor(), candMv.getVer(), pu.cs->sps->getAMVREnabledFlag(), rribcFlipType, &pu.cu->imv, &idxMvPred);
+#endif
+#else
         Distortion cost = m_pcRdCost->getBvCostMultiplePreds(candMv.getHor(), candMv.getVer(), pu.cs->sps->getAMVREnabledFlag());
+#endif
         if (cost < minCost)
         {
           mv = candMv;
           minCost = cost;
+#if JVET_AA0070_RRIBC
+          pu.cu->rribcFlipType = rribcFlipType;
+#endif
         }
 #else
         for (int n = 0; n < numMvPred; n++)
         {
+#if JVET_AA0070_RRIBC
+          m_pcRdCost->setPredictor(mvPred[rribcFlipType][n]);
+          unsigned int cost = m_pcRdCost->getBitsOfVectorWithPredictor(candMv.getHor(), candMv.getVer(), 0, rribcFlipType);
+#else
           m_pcRdCost->setPredictor(mvPred[n]);
-
           unsigned int cost = m_pcRdCost->getBitsOfVectorWithPredictor(candMv.getHor(), candMv.getVer(), 0);
+#endif
 
           if (cost < minCost)
           {
             mv = candMv;
             idxMvPred = n;
             minCost = cost;
+#if JVET_AA0070_RRIBC
+            pu.cu->rribcFlipType = rribcFlipType;
+#endif
           }
 
           int costQuadPel = MAX_UINT;
@@ -1845,13 +2510,22 @@ void InterSearch::xxIBCHashSearch(PredictionUnit& pu, Mv* mvPred, int numMvPred,
             int imvShift = 2;
             int offset = 1 << (imvShift - 1);
 
+#if JVET_AA0070_RRIBC
+            int x = (mvPred[rribcFlipType][n].hor + offset - (mvPred[rribcFlipType][n].hor >= 0)) >> 2;
+            int y = (mvPred[rribcFlipType][n].ver + offset - (mvPred[rribcFlipType][n].ver >= 0)) >> 2;
+#else
             int x = (mvPred[n].hor + offset - (mvPred[n].hor >= 0)) >> 2;
             int y = (mvPred[n].ver + offset - (mvPred[n].ver >= 0)) >> 2;
+#endif
             mvPredQuadPel.set(x, y);
 
             m_pcRdCost->setPredictor(mvPredQuadPel);
 
+#if JVET_AA0070_RRIBC
+            costQuadPel = m_pcRdCost->getBitsOfVectorWithPredictor(candMv.getHor() >> 2, candMv.getVer() >> 2, 0, rribcFlipType);
+#else
             costQuadPel = m_pcRdCost->getBitsOfVectorWithPredictor(candMv.getHor() >> 2, candMv.getVer() >> 2, 0);
+#endif
 
           }
           if (costQuadPel < minCost)
@@ -1859,6 +2533,9 @@ void InterSearch::xxIBCHashSearch(PredictionUnit& pu, Mv* mvPred, int numMvPred,
             mv = candMv;
             idxMvPred = n;
             minCost = costQuadPel;
+#if JVET_AA0070_RRIBC
+            pu.cu->rribcFlipType = rribcFlipType;
+#endif
           }
 
         }
@@ -1866,7 +2543,6 @@ void InterSearch::xxIBCHashSearch(PredictionUnit& pu, Mv* mvPred, int numMvPred,
       }
     }
   }
-
 }
 
 
@@ -9897,6 +10573,14 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa
     else
     {
       cs.getRecoBuf().copyFrom( cs.getPredBuf() );
+#if JVET_AA0070_RRIBC
+      if (CU::isIBC(cu) && cu.rribcFlipType)
+      {
+        cs.getRecoBuf().Y().flipSignal(cu.rribcFlipType == 1);
+        cs.getRecoBuf().Cb().flipSignal(cu.rribcFlipType == 1);
+        cs.getRecoBuf().Cr().flipSignal(cu.rribcFlipType == 1);
+      }
+#endif
     }
 
     // add empty TU(s)
@@ -9968,19 +10652,65 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa
       }
       else
       {
+#if JVET_AA0070_RRIBC
+        if (CU::isIBC(cu) && cu.rribcFlipType)
+        {
+          PelBuf   tmpPattern;
+          CompArea tmpArea(COMPONENT_Y, cu.chromaFormat, Position(0, 0), Size(cs.getOrgBuf(COMPONENT_Y).width, cs.getOrgBuf(COMPONENT_Y).height));
+          tmpPattern = m_tmpStorageLCU.getBuf(tmpArea);
+          tmpPattern.copyFrom(cs.getOrgBuf(COMPONENT_Y));
+          tmpPattern.flipSignal(cu.rribcFlipType == 1);
+          cs.getResiBuf(COMPONENT_Y).rspSignalAndSubtract(tmpPattern, cs.getPredBuf(COMPONENT_Y), m_pcReshape->getFwdLUT());
+        }
+        else
+#endif
         cs.getResiBuf( COMPONENT_Y ).rspSignalAndSubtract( cs.getOrgBuf( COMPONENT_Y ), cs.getPredBuf( COMPONENT_Y ), m_pcReshape->getFwdLUT() );
       }
     }
     else
     {
+#if JVET_AA0070_RRIBC
+      if (CU::isIBC(cu) && cu.rribcFlipType)
+      {
+        PelBuf   tmpPattern;
+        CompArea tmpArea(COMPONENT_Y, cu.chromaFormat, Position(0, 0), Size(cs.getOrgBuf(COMPONENT_Y).width, cs.getOrgBuf(COMPONENT_Y).height));
+        tmpPattern = m_tmpStorageLCU.getBuf(tmpArea);
+        tmpPattern.copyFrom(cs.getOrgBuf(COMPONENT_Y));
+        tmpPattern.flipSignal(cu.rribcFlipType == 1);
+        cs.getResiBuf(COMPONENT_Y).subtract(tmpPattern, cs.getPredBuf(COMPONENT_Y));
+      }
+      else
+#endif
       cs.getResiBuf( COMPONENT_Y ).subtract( cs.getOrgBuf( COMPONENT_Y ), cs.getPredBuf( COMPONENT_Y ) );
     }
   }
 
   if( chroma && isChromaEnabled( cs.pcv->chrFormat ) )
   {
+#if JVET_AA0070_RRIBC
+    if (CU::isIBC(cu) && cu.rribcFlipType)
+    {
+      PelBuf   tmpPattern;
+      CompArea tmpArea1(COMPONENT_Cb, cu.chromaFormat, Position(0, 0), Size(cs.getOrgBuf(COMPONENT_Cb).width, cs.getOrgBuf(COMPONENT_Cb).height));
+      tmpPattern = m_tmpStorageLCU.getBuf(tmpArea1);
+      tmpPattern.copyFrom(cs.getOrgBuf(COMPONENT_Cb));
+      tmpPattern.flipSignal(cu.rribcFlipType == 1);
+      cs.getResiBuf(COMPONENT_Cb).subtract(tmpPattern, cs.getPredBuf(COMPONENT_Cb));
+
+      CompArea tmpArea2(COMPONENT_Cr, cu.chromaFormat, Position(0, 0), Size(cs.getOrgBuf(COMPONENT_Cr).width, cs.getOrgBuf(COMPONENT_Cr).height));
+      tmpPattern = m_tmpStorageLCU.getBuf(tmpArea2);
+      tmpPattern.copyFrom(cs.getOrgBuf(COMPONENT_Cr));
+      tmpPattern.flipSignal(cu.rribcFlipType == 1);
+      cs.getResiBuf(COMPONENT_Cr).subtract(tmpPattern, cs.getPredBuf(COMPONENT_Cr));
+    }
+    else
+    {
+#endif
     cs.getResiBuf( COMPONENT_Cb ).subtract( cs.getOrgBuf( COMPONENT_Cb ), cs.getPredBuf( COMPONENT_Cb ) );
     cs.getResiBuf( COMPONENT_Cr ).subtract( cs.getOrgBuf( COMPONENT_Cr ), cs.getPredBuf( COMPONENT_Cr ) );
+#if JVET_AA0070_RRIBC
+    }
+#endif
   }
 
   const UnitArea curUnitArea = partitioner.currArea();
@@ -10259,7 +10989,14 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa
       }
       else
       {
-        cs.getRecoBuf( COMPONENT_Y ).reconstruct( cs.getPredBuf( COMPONENT_Y ), cs.getResiBuf( COMPONENT_Y ), cs.slice->clpRng( COMPONENT_Y ) );
+        cs.getRecoBuf(COMPONENT_Y)
+          .reconstruct(cs.getPredBuf(COMPONENT_Y), cs.getResiBuf(COMPONENT_Y), cs.slice->clpRng(COMPONENT_Y));
+#if JVET_AA0070_RRIBC
+        if (CU::isIBC(cu) && cu.rribcFlipType)
+        {
+          cs.getRecoBuf(COMPONENT_Y).flipSignal(cu.rribcFlipType == 1);
+        }
+#endif
       }
     }
     else
@@ -10273,12 +11010,25 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa
       {
         cs.getRecoBuf().bufs[0].rspSignal(m_pcReshape->getFwdLUT());
       }
+#if JVET_AA0070_RRIBC
+      if (CU::isIBC(cu) && cu.rribcFlipType)
+      {
+        cs.getRecoBuf().bufs[0].flipSignal(cu.rribcFlipType == 1);
+      }
+#endif
     }
   }
   if (chroma && isChromaEnabled(cs.pcv->chrFormat))
   {
     cs.getRecoBuf().bufs[1].reconstruct(cs.getPredBuf().bufs[1], cs.getResiBuf().bufs[1], cs.slice->clpRngs().comp[1]);
     cs.getRecoBuf().bufs[2].reconstruct(cs.getPredBuf().bufs[2], cs.getResiBuf().bufs[2], cs.slice->clpRngs().comp[2]);
+#if JVET_AA0070_RRIBC
+    if (CU::isIBC(cu) && cu.rribcFlipType)
+    {
+      cs.getRecoBuf().bufs[1].flipSignal(cu.rribcFlipType == 1);
+      cs.getRecoBuf().bufs[2].flipSignal(cu.rribcFlipType == 1);
+    }
+#endif
   }
 
   // update with clipped distortion and cost (previously unclipped reconstruction values were used)
diff --git a/source/Lib/EncoderLib/InterSearch.h b/source/Lib/EncoderLib/InterSearch.h
index 7cd239f081b9905d7642d7973963ebfd8a15b18c..6340850c4b848acaf70331d70443ec58dca71abe 100644
--- a/source/Lib/EncoderLib/InterSearch.h
+++ b/source/Lib/EncoderLib/InterSearch.h
@@ -121,6 +121,9 @@ struct ModeInfo
 #if JVET_X0049_ADAPT_DMVR
   bool     isBMMrg;
   uint8_t  bmDir;
+#endif
+#if JVET_AA0070_RRIBC
+  int rribcFlipType;
 #endif
   bool     isGeo;
   uint8_t     geoSplitDir;
@@ -147,6 +150,9 @@ struct ModeInfo
 #if JVET_X0049_ADAPT_DMVR
     , isBMMrg(false)
     , bmDir(0)
+#endif
+#if JVET_AA0070_RRIBC
+    , rribcFlipType(0)
 #endif
   , isGeo(false), geoSplitDir(0), geoMergeIdx0(0), geoMergeIdx1(0)
 #if ENABLE_OBMC
@@ -224,6 +230,9 @@ struct ModeInfo
 #if JVET_X0049_ADAPT_DMVR
     isBMMrg = pu.bmMergeFlag;
     bmDir = pu.bmDir;
+#endif
+#if JVET_AA0070_RRIBC
+    rribcFlipType = cu.rribcFlipType;
 #endif
     isGeo = cu.geoFlag;
     geoSplitDir = pu.geoSplitDir;
@@ -314,6 +323,9 @@ private:
   BcwMotionParam  m_uniMotions;
   bool            m_affineModeSelected;
   std::unordered_map< Position, std::unordered_map< Size, BlkRecord> > m_ctuRecord;
+#if JVET_AA0070_RRIBC
+  Distortion      minCostProj;
+#endif
   AffineMVInfo       *m_affMVList;
   int             m_affMVListIdx;
   int             m_affMVListSize;
@@ -658,8 +670,13 @@ public:
 
   /// set ME search range
   void setAdaptiveSearchRange       ( int iDir, int iRefIdx, int iSearchRange) { CHECK(iDir >= MAX_NUM_REF_LIST_ADAPT_SR || iRefIdx>=int(MAX_IDX_ADAPT_SR), "Invalid index"); m_aaiAdaptSR[iDir][iRefIdx] = iSearchRange; }
+#if JVET_AA0070_RRIBC
+  bool  predIBCSearch           ( CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap, bool isSecondPass = false );
+  void  xIntraPatternSearch          ( PredictionUnit& pu, IntTZSearchStruct&  cStruct, Mv& rcMv, Distortion&  ruiCost, Mv* cMvSrchRngLT, Mv* cMvSrchRngRB, Mv* pcMvPred, int rribcFlipType );
+#else
   bool  predIBCSearch           ( CodingUnit& cu, Partitioner& partitioner, const int localSearchRangeX, const int localSearchRangeY, IbcHashMap& ibcHashMap);
-  void  xIntraPatternSearch         ( PredictionUnit& pu, IntTZSearchStruct&  cStruct, Mv& rcMv, Distortion&  ruiCost, Mv* cMvSrchRngLT, Mv* cMvSrchRngRB, Mv* pcMvPred);
+  void  xIntraPatternSearch         ( PredictionUnit& pu, IntTZSearchStruct&  cStruct, Mv& rcMv, Distortion&  ruiCost, Mv* cMvSrchRngLT, Mv* cMvSrchRngRB, Mv* pcMvPred );
+#endif
   void  xSetIntraSearchRange        ( PredictionUnit& pu, int iRoiWidth, int iRoiHeight, const int localSearchRangeX, const int localSearchRangeY, Mv& rcMvSrchRngLT, Mv& rcMvSrchRngRB);
   void  resetIbcSearch()
   {
@@ -669,9 +686,15 @@ public:
     }
     m_defaultCachedBvs.currCnt = 0;
   }
+#if JVET_AA0070_RRIBC
+  void xIBCEstimation(PredictionUnit &pu, PelUnitBuf &origBuf, Mv pcMvPred[3][2], Mv &rcMv, Distortion &ruiCost, const int localSearchRangeX, const int localSearchRangeY, int numRribcType);
+  void xIBCSearchMVCandUpdate( Distortion uiSad, int x, int y, Distortion *uiSadBestCand, Mv *cMVCand);
+  int  xIBCSearchMVChromaRefine( PredictionUnit &pu, int iRoiWidth, int iRoiHeight, int cuPelX, int cuPelY, Distortion *uiSadBestCand, Mv *cMVCand, int rribcFlipType );
+#else
   void  xIBCEstimation   ( PredictionUnit& pu, PelUnitBuf& origBuf, Mv     *pcMvPred, Mv     &rcMv, Distortion &ruiCost, const int localSearchRangeX, const int localSearchRangeY);
   void  xIBCSearchMVCandUpdate  ( Distortion  uiSad, int x, int y, Distortion* uiSadBestCand, Mv* cMVCand);
-  int   xIBCSearchMVChromaRefine( PredictionUnit& pu, int iRoiWidth, int iRoiHeight, int cuPelX, int cuPelY, Distortion* uiSadBestCand, Mv*     cMVCand);
+  int   xIBCSearchMVChromaRefine( PredictionUnit& pu, int iRoiWidth, int iRoiHeight, int cuPelX, int cuPelY, Distortion* uiSadBestCand, Mv*     cMVCand );
+#endif
   void addToSortList(std::list<BlockHash>& listBlockHash, std::list<int>& listCost, int cost, const BlockHash& blockHash);
   bool predInterHashSearch(CodingUnit& cu, Partitioner& partitioner, bool& isPerfectMatch);
   bool xHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPicList, int& bestRefIndex, Mv& bestMv, Mv& bestMvd, int& bestMVPIndex, bool& isPerfectMatch);
@@ -989,7 +1012,11 @@ protected:
 
   void  setWpScalingDistParam     ( int iRefIdx, RefPicList eRefPicListCur, Slice *slice );
 private:
+#if JVET_AA0070_RRIBC
+  void xxIBCHashSearch(PredictionUnit &pu, Mv mvPred[3][2], int numMvPred, Mv &mv, int &idxMvPred, IbcHashMap &ibcHashMap, AMVPInfo amvpInfo4Pel[3], int numRribcType);
+#else
   void  xxIBCHashSearch(PredictionUnit& pu, Mv* mvPred, int numMvPred, Mv &mv, int& idxMvPred, IbcHashMap& ibcHashMap);
+#endif
 public:
 #if JVET_AA0133_INTER_MTS_OPT
   bool encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &partitioner, const bool &skipResidual
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index 0611d87735f235c2e1c738f353f454da6c270974..9da96f496113ef5f5d948d83f6d52226b6867947 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -1545,6 +1545,9 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
   {
     CHECK(pcSPS->getMaxNumIBCMergeCand() > IBC_MRG_MAX_NUM_CANDS, "More IBC merge candidates signalled than supported");
     WRITE_UVLC(IBC_MRG_MAX_NUM_CANDS - pcSPS->getMaxNumIBCMergeCand(), "six_minus_max_num_ibc_merge_cand");
+#if JVET_AA0061_IBC_MBVD
+    WRITE_FLAG( pcSPS->getUseIbcMbvd() ? 1 : 0,                                         "sps_ibc_mbvd_enabled_flag" );
+#endif
   }
 #if !JVET_S0074_SPS_REORDER
   WRITE_FLAG(pcSPS->getUseLmcs() ? 1 : 0, "sps_lmcs_enable_flag");