diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index bf4190311f19db34dd02cd8b3603a33204b9f94e..7e4fa4b0d6dd36b9a11ae0aff24c8d0d2f525070 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -68,6 +68,7 @@
 #define JVET_X0144_MAX_MTT_DEPTH_TID                      1 // JVET-X0144: max MTT hierarchy depth set by temporal ID
 #define JVET_X0049_BDMVR_SW_OPT                           1 // JVET-X0049: software optimization for BDMVR (lossless)
 #define INTRA_TRANS_ENC_OPT                               1 // JVET-Y0141: Software optimization, including TIMD/DIMD/MTS/LFNS encoder fast algorithm, SIMD implementation and CM initial value retraining 
+#define JVET_AA0129_INTERHASH_OBMCOFF_RD                  1 // JVET-AA0129: improved encoder RDO of inter-hash based ME considering OBMC off
 
 // SIMD optimizations
 #define MCIF_SIMD_NEW                                     1 // SIMD for interpolation
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index df96beb44d76c0baaecde9b4ce58ffbda439f313..d0557810bee374097ccdf271ddb5a05c5f3aaee3 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -1129,6 +1129,12 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par
     {
 #if ENABLE_OBMC
       bool tryObmc = true;
+#if JVET_AA0129_INTERHASH_OBMCOFF_RD
+      if (m_pcEncCfg->getUseHashME())
+      {
+        tryObmc = false;
+      }
+#endif
 #endif
 
       if( ( currTestMode.opts & ETO_IMV ) != 0 )
@@ -1152,7 +1158,11 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par
       else
       {
         tempCS->bestCS = bestCS;
+#if ENABLE_OBMC && JVET_AA0129_INTERHASH_OBMCOFF_RD
+        tryObmc = xCheckRDCostInter(tempCS, bestCS, partitioner, currTestMode);
+#else
         xCheckRDCostInter( tempCS, bestCS, partitioner, currTestMode );
+#endif
         tempCS->bestCS = nullptr;
 #if JVET_Y0152_TT_ENC_SPEEDUP
         splitRdCostBest[CTU_LEVEL] = bestCS->cost;
@@ -1160,7 +1170,11 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par
 #endif
       }
 #if ENABLE_OBMC
+#if JVET_AA0129_INTERHASH_OBMCOFF_RD
+      if ((!m_pcEncCfg->getUseHashME() && tryObmc && tempCS->cus.size() != 0) || (m_pcEncCfg->getUseHashME() && tryObmc))//todo 
+#else
       if (tryObmc && tempCS->cus.size() != 0)//todo
+#endif
       {
         xCheckRDCostInterWoOBMC(tempCS, bestCS, partitioner, currTestMode);
       }
@@ -1168,10 +1182,20 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par
     }
     else if (currTestMode.type == ETM_HASH_INTER)
     {
+#if ENABLE_OBMC && JVET_AA0129_INTERHASH_OBMCOFF_RD
+      bool tryObmc = xCheckRDCostHashInter( tempCS, bestCS, partitioner, currTestMode );
+#else
       xCheckRDCostHashInter( tempCS, bestCS, partitioner, currTestMode );
+#endif
 #if JVET_Y0152_TT_ENC_SPEEDUP
       splitRdCostBest[CTU_LEVEL] = bestCS->cost;
       tempCS->splitRdCostBest = splitRdCostBest;
+#endif
+#if ENABLE_OBMC && JVET_AA0129_INTERHASH_OBMCOFF_RD
+      if (tryObmc)
+      {
+        xCheckRDCostInterWoOBMC(  tempCS, bestCS, partitioner, currTestMode );
+      }
 #endif
     }
 #if !MERGE_ENC_OPT
@@ -3017,10 +3041,17 @@ void EncCu::xFillPCMBuffer( CodingUnit &cu )
 }
 #endif
 
+#if ENABLE_OBMC && JVET_AA0129_INTERHASH_OBMCOFF_RD
+bool EncCu::xCheckRDCostHashInter( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
+#else
 void EncCu::xCheckRDCostHashInter( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
+#endif
 {
 #if ENABLE_OBMC
   double bestOBMCCost = MAX_DOUBLE;
+#if ENABLE_OBMC && JVET_AA0129_INTERHASH_OBMCOFF_RD
+  bool   validMode = false;
+#endif
 #endif
   bool isPerfectMatch = false;
 
@@ -3076,6 +3107,9 @@ void EncCu::xCheckRDCostHashInter( CodingStructure *&tempCS, CodingStructure *&b
     m_pTempCUWoOBMC[wIdx][hIdx]->getPredBuf(cu).copyFrom(prevCS->getPredBuf(cu));
 
     bestOBMCCost = tempCost;
+#if ENABLE_OBMC && JVET_AA0129_INTERHASH_OBMCOFF_RD
+    validMode = true;
+#endif
   }
 #endif
     if ( m_bestModeUpdated && bestCS->cost != MAX_DOUBLE )
@@ -3090,6 +3124,9 @@ void EncCu::xCheckRDCostHashInter( CodingStructure *&tempCS, CodingStructure *&b
     isPerfectMatch = false;
   }
   m_modeCtrl->setIsHashPerfectMatch(isPerfectMatch);
+#if ENABLE_OBMC && JVET_AA0129_INTERHASH_OBMCOFF_RD
+  return validMode;
+#endif
 }
 
 void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
@@ -10463,12 +10500,23 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best
   // check ibc mode in encoder RD
   //////////////////////////////////////////////////////////////////////////////////////////////
 
+#if ENABLE_OBMC && JVET_AA0129_INTERHASH_OBMCOFF_RD
+bool EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
+#else
 void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
+#endif
 {
+#if ENABLE_OBMC && JVET_AA0129_INTERHASH_OBMCOFF_RD
+  bool validMode = false;
+#endif
 #if INTER_LIC
   if (m_pcInterSearch->m_fastLicCtrl.skipRDCheckForLIC((encTestMode.opts & ETO_LIC) > 0, IMV_OFF, bestCS->cost, tempCS->area.Y().area()))
   {
+#if ENABLE_OBMC && JVET_AA0129_INTERHASH_OBMCOFF_RD
+    return (m_pcEncCfg->getUseHashME() ? validMode : true);
+#else
     return;
+#endif
   }
 #endif
 #if ENABLE_OBMC
@@ -10665,6 +10713,9 @@ void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestC
     m_pTempCUWoOBMC[wIdx][hIdx]->getPredBuf(cu).copyFrom(prevCS->getPredBuf(cu));
 
     bestOBMCCost = tempCost;
+#if JVET_AA0129_INTERHASH_OBMCOFF_RD
+    validMode = true;
+#endif
   }
 #endif
   if( g_BcwSearchOrder[bcwLoopIdx] == BCW_DEFAULT )
@@ -10698,6 +10749,9 @@ void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestC
 #if JVET_X0083_BM_AMVP_MERGE_MODE
   }
 #endif
+#if ENABLE_OBMC && JVET_AA0129_INTERHASH_OBMCOFF_RD
+  return (m_pcEncCfg->getUseHashME() ? validMode : true);
+#endif
 }
 
 
@@ -10749,6 +10803,9 @@ bool EncCu::xCheckRDCostInterIMV(CodingStructure *&tempCS, CodingStructure *&bes
   }
 
   bool validMode = false;
+#if ENABLE_OBMC && JVET_AA0129_INTERHASH_OBMCOFF_RD
+  bool availMode = false;
+#endif
   double curBestCost = bestCS->cost;
   double equBcwCost = MAX_DOUBLE;
 
@@ -10932,6 +10989,9 @@ bool EncCu::xCheckRDCostInterIMV(CodingStructure *&tempCS, CodingStructure *&bes
     m_pTempCUWoOBMC[wIdx][hIdx]->getPredBuf(cu).copyFrom(prevCS->getPredBuf(cu));
 
     bestOBMCCost = tempCost;
+#if JVET_AA0129_INTERHASH_OBMCOFF_RD
+    availMode = true;
+#endif
   }
 #endif
   if( cu.imv == IMV_FPEL && tempCS->cost < bestIntPelCost )
@@ -10966,6 +11026,13 @@ bool EncCu::xCheckRDCostInterIMV(CodingStructure *&tempCS, CodingStructure *&bes
     xCalDebCost( *bestCS, partitioner );
   }
 
+#if ENABLE_OBMC && JVET_AA0129_INTERHASH_OBMCOFF_RD
+  if (m_pcEncCfg->getUseHashME())
+  {
+    return availMode;
+  }
+  else
+#endif
   return tempCS->slice->getSPS()->getAffineAmvrEnabledFlag() ? validMode : true;
 }
 
diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h
index 62616891d433cee97e95a15886a5665e3f0b4afa..cf62ce5eacb265e5a0bab4ec7588f130c02776a3 100644
--- a/source/Lib/EncoderLib/EncCu.h
+++ b/source/Lib/EncoderLib/EncCu.h
@@ -431,7 +431,11 @@ protected:
   void xFillPCMBuffer         ( CodingUnit &cu);
 #endif
 
+#if ENABLE_OBMC && JVET_AA0129_INTERHASH_OBMCOFF_RD
+  bool xCheckRDCostHashInter  ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode );
+#else
   void xCheckRDCostHashInter  ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode );
+#endif
 #if MERGE_ENC_OPT
   void xCheckSATDCostRegularMerge 
                               ( CodingStructure *&tempCS, CodingUnit &cu, PredictionUnit &pu, MergeCtx mergeCtx, PelUnitBuf *acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM], PelUnitBuf *&singleMergeTempBuffer, PelUnitBuf  acMergeTmpBuffer[MRG_MAX_NUM_CANDS]
@@ -505,7 +509,11 @@ protected:
   void xCheckRDCostTMMerge2Nx2N
                               ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode );
 #endif
+#if ENABLE_OBMC && JVET_AA0129_INTERHASH_OBMCOFF_RD
+  bool xCheckRDCostInter      ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode );
+#else
   void xCheckRDCostInter      ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode );
+#endif
   bool xCheckRDCostInterIMV(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode, double &bestIntPelCost);
   void xEncodeDontSplit       ( CodingStructure &cs, Partitioner &partitioner);