diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 314e6107e2fde7363acdc8788ff643d4a9ef2d85..e1483ee3c17f745febaadf9411caad51b27f5461 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -818,10 +818,16 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setLFNST                                             ( m_LFNST );
 #endif
   m_cEncLib.setUseFastLFNST                                      ( m_useFastLFNST );
+#if JVET_AI0050_INTER_MTSS
+  m_cEncLib.setUseInterMTSS                                      ( m_useInterMTSS );
+#endif
+#if JVET_AI0050_SBT_LFNST
+  m_cEncLib.setUseSBTLFNST                                       ( m_useSbtLFNST );
+#endif
 #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
   m_cEncLib.setUseFastInterLFNST                                 ( m_useFastInterLFNST );
 #endif
-  m_cEncLib.setSbTmvpEnabledFlag(m_sbTmvpEnableFlag);
+  m_cEncLib.setSbTmvpEnabledFlag                                 ( m_sbTmvpEnableFlag );
   m_cEncLib.setAffine                                            ( m_Affine );
   m_cEncLib.setAffineType                                        ( m_AffineType );
 #if JVET_AH0185_ADAPTIVE_COST_IN_MERGE_MODE
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index 7b160512a50e84825abefd5e981a5c91ea378719..59b69bb2a865ca96df744c0d0b521fb1235568f7 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -1040,6 +1040,12 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ( "FastLFNST",                                      m_useFastLFNST,                                   false, "Fast methods for LFNST" )
 #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
   ( "FastInterLFNST",                                 m_useFastInterLFNST,                              false, "Fast methods for inter-LFNST/NSPT" )
+#endif
+#if JVET_AI0050_INTER_MTSS
+  ("InterMTSS",                                       m_useInterMTSS,                                    true, "Inter MTSS (0:off, 1:on)  [default: on]")
+#endif
+#if JVET_AI0050_SBT_LFNST
+  ("SbtLFNST",                                        m_useSbtLFNST,                                     true, "SBT-LFNST (0:off, 1:on)  [default: on]")
 #endif
   ("SbTMVP",                                          m_sbTmvpEnableFlag,                               false, "Enable Subblock Temporal Motion Vector Prediction (0: off, 1: on) [default: off]")
   ("MMVD",                                            m_MMVD,                                            true, "Enable Merge mode with Motion Vector Difference (0:off, 1:on)  [default: 1]")
@@ -5611,6 +5617,12 @@ void EncAppCfg::xPrintParameter()
     msg( VERBOSE, "InterLFNST:%d ", m_interLFNST );
 #else
     msg( VERBOSE, "LFNST:%d ", m_LFNST );
+#endif
+#if JVET_AI0050_INTER_MTSS
+    msg( VERBOSE, "InterMTSS:%d ", m_useInterMTSS );
+#endif
+#if JVET_AI0050_SBT_LFNST
+    msg( VERBOSE, "SbtLFNST:%d ", m_useSbtLFNST );
 #endif
     msg( VERBOSE, "MMVD:%d ", m_MMVD);
     msg( VERBOSE, "Affine:%d ", m_Affine );
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index 575cc28da064fa486c80f1566e3741d5ddb37302..6c50a6d66d2d29a018e6ec1d484cc3a3150aef2f 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -405,6 +405,12 @@ protected:
   bool      m_useFastLFNST;
 #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
   bool      m_useFastInterLFNST;
+#endif
+#if JVET_AI0050_INTER_MTSS
+  bool      m_useInterMTSS;
+#endif
+#if JVET_AI0050_SBT_LFNST
+  bool      m_useSbtLFNST;
 #endif
   bool      m_sbTmvpEnableFlag;
   bool      m_Affine;
diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h
index a087ad31f93504d23bde207d6d1d1efcd01abef0..51cb7e3cc107222060f8f21d133b45da4366f97e 100644
--- a/source/Lib/CommonLib/CommonDef.h
+++ b/source/Lib/CommonLib/CommonDef.h
@@ -1554,6 +1554,9 @@ static const int SBT_MAX_SIZE =                                    64; ///< maxi
 #endif
 static const int SBT_NUM_SL =                                      10; ///< maximum number of historical PU decision saved for a CU
 static const int SBT_NUM_RDO =                                      2; ///< maximum number of SBT mode tried for a PU
+#if JVET_AI0050_SBT_LFNST
+static const int NUM_SBT_LFNST_RDO =                                2;
+#endif
 #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
 static const int NUM_INTER_CU_INFO_SAVE =                           8; ///< maximum number of inter cu information saved for fast algorithm
 static const int LDT_MODE_TYPE_INHERIT =                            0; ///< No need to signal mode_constraint_flag, and the modeType of the region is inherited from its parent node
diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h
index ef4ba72feb6d0f88daa0fd5b2972e0c8e8b37a6f..e96d70a087aa0b8cae56237f39a8fc68979a7bb2 100644
--- a/source/Lib/CommonLib/Contexts.h
+++ b/source/Lib/CommonLib/Contexts.h
@@ -712,6 +712,9 @@ public:
   static const CtxSet   LFNSTIdx;
 #if JVET_AG0061_INTER_LFNST_NSPT
   static const CtxSet   InterLFNSTIdx;
+#endif
+#if JVET_AI0050_INTER_MTSS
+  static const CtxSet   InterLFNSTIntraIdx;
 #endif
   static const CtxSet   PLTFlag;
   static const CtxSet   RotationFlag;
diff --git a/source/Lib/CommonLib/Contexts_ecm14.0.inl b/source/Lib/CommonLib/Contexts_ecm14.0.inl
index f6f8b4082085735922d9ee3ade079cd083093ae9..5e3bc38da798f973b4cfb8ccca13cee02c58e371 100644
--- a/source/Lib/CommonLib/Contexts_ecm14.0.inl
+++ b/source/Lib/CommonLib/Contexts_ecm14.0.inl
@@ -6445,6 +6445,31 @@ const CtxSet ContextSetCfg::obicFlag = ContextSetCfg::addCtxSet
   { 133 },
   });
 #endif
+#if JVET_AI0050_INTER_MTSS
+const CtxSet ContextSetCfg::InterLFNSTIntraIdx = ContextSetCfg::addCtxSet({
+// ctx 1599 1599
+  { CNU },
+  { CNU },
+  { CNU },
+  { CNU },
+  { DWS },
+  { DWS },
+  { DWS },
+  { DWS },
+  { DWE },
+  { DWE },
+  { DWE },
+  { DWE },
+  { DWO },
+  { DWO },
+  { DWO },
+  { DWO },
+  { DWO },
+  { DWO },
+  { DWO },
+  { DWO },
+  });
+#endif
 #if JVET_AI0136_ADAPTIVE_DUAL_TREE
 const CtxSet ContextSetCfg::SeparateTree = ContextSetCfg::addCtxSet
 ({
diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp
index 8987e8af9989c277975d139c0c648db3cf44284b..7d9ba857eec8cae15eee5afacbd03ddfaac0356c 100644
--- a/source/Lib/CommonLib/IntraPrediction.cpp
+++ b/source/Lib/CommonLib/IntraPrediction.cpp
@@ -11541,7 +11541,11 @@ void IntraPrediction::predChromaTM(const CompArea &areaCb, const CompArea &areaC
 #endif
 
 #if ENABLE_DIMD && (JVET_AB0067_MIP_DIMD_LFNST || JVET_AC0115_INTRA_TMP_DIMD_MTS_LFNST || JVET_AG0058_EIP || JVET_AG0061_INTER_LFNST_NSPT)
-int IntraPrediction::deriveIpmForTransform(CPelBuf predBuf, CodingUnit& cu)
+int IntraPrediction::deriveIpmForTransform(CPelBuf predBuf, CodingUnit& cu
+#if JVET_AI0050_INTER_MTSS
+  , int &secondMode
+#endif
+)
 {
   if (!cu.slice->getSPS()->getUseDimd())
   {
@@ -11559,15 +11563,29 @@ int IntraPrediction::deriveIpmForTransform(CPelBuf predBuf, CodingUnit& cu)
 
   int firstAmp = 0, curAmp = 0;
   int firstMode = 0, curMode = 0;
+#if JVET_AI0050_INTER_MTSS
+  int secondAmp = 0;
+#endif
   for (int i = 0; i < NUM_LUMA_MODE; i++)
   {
     curAmp = histogram[i];
     curMode = i;
     if (curAmp > firstAmp)
     {
+#if JVET_AI0050_INTER_MTSS
+      secondAmp = firstAmp;
+      secondMode = firstMode;
+#endif
       firstAmp = curAmp;
       firstMode = curMode;
     }
+#if JVET_AI0050_INTER_MTSS
+    else if (curAmp > secondAmp)
+    {
+      secondAmp = curAmp;
+      secondMode = curMode;
+    }
+#endif
   }
   return firstMode;
 }
@@ -13602,7 +13620,17 @@ void IntraPrediction::predIntraMip( const ComponentID compId, PelBuf &piPred, co
       }
       pReducePred += reducedPredTemp.stride;
     }
-    int iMode = deriveIpmForTransform(reducedPredTemp, *pu.cu);
+#if JVET_AI0050_INTER_MTSS
+    int secondDimdIntraDir = 0;
+#endif
+    int iMode = deriveIpmForTransform(reducedPredTemp, *pu.cu
+#if JVET_AI0050_INTER_MTSS
+      , secondDimdIntraDir
+#endif
+    );
+#if JVET_AI0050_INTER_MTSS
+    pu.cu->dimdDerivedIntraDir2nd = secondDimdIntraDir;
+#endif
     pu.cu->mipDimdMode = iMode;
   }
   else
@@ -16714,7 +16742,17 @@ void IntraPrediction::xTMPFusionApplyModel(PelBuf &piPred, unsigned int uiBlkWid
   if (bDeriveDimdMode)
   {
     CPelBuf predBuf      = piPred;
-    cu->intraTmpDimdMode = deriveIpmForTransform(predBuf, *cu);
+#if JVET_AI0050_INTER_MTSS
+    int secondDimdIntraDir = 0;
+#endif
+    cu->intraTmpDimdMode = deriveIpmForTransform(predBuf, *cu
+#if JVET_AI0050_INTER_MTSS
+      , secondDimdIntraDir
+#endif
+    );
+#if JVET_AI0050_INTER_MTSS
+    cu->dimdDerivedIntraDir2nd = secondDimdIntraDir;
+#endif
   }
 #endif
   return;
@@ -16766,7 +16804,17 @@ void IntraPrediction::xGenerateTmpFlmPred(PelBuf &piPred, unsigned int uiBlkWidt
   if (bDeriveDimdMode)
   {
     CPelBuf predBuf      = piPred;
-    cu->intraTmpDimdMode = deriveIpmForTransform(predBuf, *cu);
+#if JVET_AI0050_INTER_MTSS
+    int secondDimdIntraDir = 0;
+#endif
+    cu->intraTmpDimdMode = deriveIpmForTransform(predBuf, *cu
+#if JVET_AI0050_INTER_MTSS
+     , secondDimdIntraDir
+#endif
+    );
+#if JVET_AI0050_INTER_MTSS
+    cu->dimdDerivedIntraDir2nd = secondDimdIntraDir;
+#endif
   }
 #endif
   return;
@@ -16968,7 +17016,17 @@ bool IntraPrediction::generateTMPrediction( Pel* piPred, unsigned int uiStride,
 
 #if JVET_AC0115_INTRA_TMP_DIMD_MTS_LFNST
   CPelBuf predBuf(pPred, uiStride, uiWidth, uiHeight);
-  cu->intraTmpDimdMode = deriveIpmForTransform(predBuf, *cu);
+#if JVET_AI0050_INTER_MTSS
+  int secondDimdIntraDir = 0;
+#endif
+  cu->intraTmpDimdMode = deriveIpmForTransform(predBuf, *cu
+#if JVET_AI0050_INTER_MTSS
+    , secondDimdIntraDir
+#endif
+  );
+#if JVET_AI0050_INTER_MTSS
+  cu->dimdDerivedIntraDir2nd = secondDimdIntraDir;
+#endif
 #endif
   return bSucceedFlag;
 }
@@ -17330,7 +17388,17 @@ bool IntraPrediction::generateTMPrediction(Pel *piPred, unsigned int uiStride, i
   {
 #endif
     CPelBuf predBuf(pPred, uiStride, uiWidth, uiHeight);
-    pu.cu->intraTmpDimdMode = deriveIpmForTransform(predBuf, *pu.cu);
+#if JVET_AI0050_INTER_MTSS
+    int secondDimdIntraDir = 0;
+#endif
+    pu.cu->intraTmpDimdMode = deriveIpmForTransform(predBuf, *pu.cu
+#if JVET_AI0050_INTER_MTSS
+      , secondDimdIntraDir
+#endif
+    );
+#if JVET_AI0050_INTER_MTSS
+    pu.cu->dimdDerivedIntraDir2nd = secondDimdIntraDir;
+#endif
 #if JVET_AD0086_ENHANCED_INTRA_TMP
   }
 #endif
@@ -17745,7 +17813,17 @@ bool IntraPrediction::generateTmDcPrediction( Pel* piPred, unsigned int uiStride
   }
 #if JVET_AC0115_INTRA_TMP_DIMD_MTS_LFNST
   CPelBuf predBuf(pPred, uiStride, uiBlkWidth, uiBlkHeight);
-  cu->intraTmpDimdMode = deriveIpmForTransform(predBuf, *cu);
+#if JVET_AI0050_INTER_MTSS
+  int secondDimdIntraDir = 0;
+#endif
+  cu->intraTmpDimdMode = deriveIpmForTransform(predBuf, *cu
+#if JVET_AI0050_INTER_MTSS
+    , secondDimdIntraDir
+#endif
+  );
+#if JVET_AI0050_INTER_MTSS
+  cu->dimdDerivedIntraDir2nd = secondDimdIntraDir;
+#endif
 #endif
   return bSucceedFlag;
 }
diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h
index faa92c10712db077ca31014e55cde2223211bf93..782590472d841805d9e0402a5de087b54af4efb9 100644
--- a/source/Lib/CommonLib/IntraPrediction.h
+++ b/source/Lib/CommonLib/IntraPrediction.h
@@ -801,7 +801,11 @@ public:
 #endif
 #endif
 #if ENABLE_DIMD && (JVET_AB0067_MIP_DIMD_LFNST || JVET_AC0115_INTRA_TMP_DIMD_MTS_LFNST || JVET_AG0058_EIP || JVET_AG0061_INTER_LFNST_NSPT)
-  static int deriveIpmForTransform(CPelBuf predBuf, CodingUnit& cu);
+  static int deriveIpmForTransform(CPelBuf predBuf, CodingUnit& cu
+#if JVET_AI0050_INTER_MTSS
+    , int &secondMode
+#endif
+  );
 #endif
 #if !JVET_AG0061_INTER_LFNST_NSPT
   static int  buildHistogram      ( const Pel *pReco, int iStride, uint32_t uiHeight, uint32_t uiWidth, int* piHistogram, int direction, int bw, int bh );
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index f6086c6aa73e55bc1bb209deb9dc564a8f7d6479..ae3e064254d97f445d6e5fcb9c32b4b27c7ae576 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -1624,6 +1624,12 @@ private:
   bool              m_enableMaxMttIncrease;
 #endif
   bool              m_SBT;
+#if JVET_AI0050_INTER_MTSS
+  bool              m_interMTSS; 
+#endif
+#if JVET_AI0050_SBT_LFNST
+  bool              m_sbtLFNST;
+#endif
   bool              m_ISP;
   ChromaFormat      m_chromaFormatIdc;
 #if !JVET_S0052_RM_SEPARATE_COLOUR_PLANE
@@ -2463,6 +2469,14 @@ void                    setCCALFEnabledFlag( bool b )
   unsigned                getPLTMode() const                                                              { return m_PLTMode; }
   void                    setUseSBT( bool b )                                                             { m_SBT = b; }
   bool                    getUseSBT() const                                                               { return m_SBT; }
+#if JVET_AI0050_INTER_MTSS
+  void                    setUseInterMTSS(bool b)                                                         { m_interMTSS = b; }
+  bool                    getUseInterMTSS() const                                                         { return m_interMTSS; }
+#endif
+#if JVET_AI0050_SBT_LFNST
+  void                    setUseSbtLFNST(bool b)                                                          { m_sbtLFNST = b; }
+  bool                    getUseSbtLFNST() const                                                          { return m_sbtLFNST; }
+#endif
   void                    setUseISP( bool b )                                                             { m_ISP = b; }
   bool                    getUseISP() const                                                               { return m_ISP; }
 
diff --git a/source/Lib/CommonLib/TrQuant.cpp b/source/Lib/CommonLib/TrQuant.cpp
index ed8e0e8073a967a10b7d93d396da5619897d3615..079c9c4e20992d18f63889cc8b0c801bc02845c5 100644
--- a/source/Lib/CommonLib/TrQuant.cpp
+++ b/source/Lib/CommonLib/TrQuant.cpp
@@ -528,7 +528,17 @@ void TrQuant::xInvLfnst( const TransformUnit &tu, const ComponentID compID )
     }
     if (tu.cu->geoFlag)
     {
+#if JVET_AI0050_INTER_MTSS
+      intraMode = tu.cu->dimdDerivedIntraDir;
+#else
       intraMode = g_geoAngle2IntraAng[g_geoParams[tu.cu->firstPU->geoSplitDir][0]];
+#endif
+    }
+#endif
+#if JVET_AI0050_INTER_MTSS
+    if (tu.cu->lfnstIntra)
+    {
+      intraMode = tu.cu->dimdDerivedIntraDir2nd;
     }
 #endif
 #if JVET_AB0155_SGPM
@@ -773,6 +783,9 @@ void TrQuant::xFwdLfnst( const TransformUnit &tu, const ComponentID compID, cons
   const uint32_t  width    = area.width;
   const uint32_t  height   = area.height;
   const uint32_t  lfnstIdx = tu.cu->lfnstIdx;
+#if JVET_AI0050_INTER_MTSS
+  const uint32_t  lfnstIntra = tu.cu->lfnstIntra;
+#endif
 #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
   if( lfnstIdx && tu.mtsIdx[compID] != MTS_SKIP && (tu.cu->isSepTree() ? true : isLuma(compID)) )
 #else
@@ -841,7 +854,17 @@ void TrQuant::xFwdLfnst( const TransformUnit &tu, const ComponentID compID, cons
     }
     if (tu.cu->geoFlag)
     {
+#if JVET_AI0050_INTER_MTSS
+      intraMode = tu.cu->dimdDerivedIntraDir;
+#else
       intraMode = g_geoAngle2IntraAng[g_geoParams[tu.cu->firstPU->geoSplitDir][0]];
+#endif
+    }
+#endif
+#if JVET_AI0050_INTER_MTSS
+    if (tu.cu->lfnstIntra)
+    {
+      intraMode = tu.cu->dimdDerivedIntraDir2nd;
     }
 #endif
 #if JVET_AB0155_SGPM
@@ -915,7 +938,11 @@ void TrQuant::xFwdLfnst( const TransformUnit &tu, const ComponentID compID, cons
       TCoeff*         lfnstTemp;
       TCoeff*         coeffTemp;
 #if JVET_AG0061_INTER_LFNST_NSPT
+#if JVET_AI0050_INTER_MTSS
+      TCoeff *        tempCoeff = loadTr ? m_mtsCoeffs[lfnstIdx ? lfnstIdx + NUM_TRAFO_MODES_MTS + 3 * lfnstIntra - 1 : tu.mtsIdx[compID]] : m_tempCoeff;
+#else
       TCoeff *        tempCoeff = loadTr ? m_mtsCoeffs[lfnstIdx ? lfnstIdx + NUM_TRAFO_MODES_MTS - 1 : tu.mtsIdx[compID]] : m_tempCoeff;
+#endif
 #else
       TCoeff *        tempCoeff = loadTr ? m_mtsCoeffs[tu.mtsIdx[compID]] : m_tempCoeff;
 #endif
@@ -1186,6 +1213,12 @@ void TrQuant::getTrTypes(const TransformUnit tu, const ComponentID compID, int &
 
   trTypeHor = DCT2;
   trTypeVer = DCT2;
+#if JVET_AI0050_SBT_LFNST
+  if (isSBT && tu.cu->lfnstIdx)
+  {
+    return;
+  }
+#endif
 
   if (isISP && tu.cu->lfnstIdx)
   {
@@ -2013,10 +2046,23 @@ void TrQuant::transformNxN( TransformUnit& tu, const ComponentID& compID, const
   {
 #if JVET_AG0061_INTER_LFNST_NSPT
     tu.mtsIdx[compID]   = it->first < NUM_TRAFO_MODES_MTS ? it->first : 0;
+#if JVET_AI0050_INTER_MTSS
+    int factor = (it->first - NUM_TRAFO_MODES_MTS) / 3;
+    tu.lfnstIdx[compID] = it->first < NUM_TRAFO_MODES_MTS ? 0 : it->first - NUM_TRAFO_MODES_MTS - 3 * factor + 1;
+    tu.lfnstIntra[compID] = it->first < (NUM_TRAFO_MODES_MTS + 3) ? 0 : (it->first < (NUM_TRAFO_MODES_MTS + 6) ? 1 : 2);
+#else
     tu.lfnstIdx[compID] = it->first < NUM_TRAFO_MODES_MTS ? 0 : it->first - NUM_TRAFO_MODES_MTS + 1;
+#endif
+#if JVET_AI0050_SBT_LFNST
+    if ((compID == COMPONENT_Y && !tu.cu->sbtInfo) || (!tu.noResidual && compID == COMPONENT_Y && tu.cu->sbtInfo))
+#else
     if (compID == COMPONENT_Y)
+#endif
     {
       tu.cu->lfnstIdx = tu.lfnstIdx[compID];
+#if JVET_AI0050_INTER_MTSS
+      tu.cu->lfnstIntra = tu.lfnstIntra[compID];
+#endif
     }
     CoeffBuf tempCoeff(m_mtsCoeffs[it->first], rect);
 #else
@@ -2167,7 +2213,11 @@ void TrQuant::transformNxN( TransformUnit& tu, const ComponentID& compID, const
   CHECK(cs.sps->getMaxTbSize() < uiWidth, "Unsupported transformation size");
 
 #if JVET_AG0061_INTER_LFNST_NSPT
+#if JVET_AI0050_INTER_MTSS
+  CoeffBuf tempCoeff(loadTr ? m_mtsCoeffs[tu.lfnstIdx[compID] ? (tu.lfnstIdx[compID] + NUM_TRAFO_MODES_MTS + 3 * tu.lfnstIntra[compID] - 1) : tu.mtsIdx[compID]] : m_tempCoeff, rect);
+#else
   CoeffBuf tempCoeff(loadTr ? m_mtsCoeffs[tu.lfnstIdx[compID] ? tu.lfnstIdx[compID] + NUM_TRAFO_MODES_MTS - 1 : tu.mtsIdx[compID]] : m_tempCoeff, rect);
+#endif
 #else
   CoeffBuf tempCoeff(loadTr ? m_mtsCoeffs[tu.mtsIdx[compID]] : m_tempCoeff, rect);
 #endif
@@ -2823,7 +2873,17 @@ int TrQuant::getLfnstIdx(const TransformUnit &tu, ComponentID compID)
   }
   if (tu.cu->geoFlag)
   {
+#if JVET_AI0050_INTER_MTSS
+    intraMode = tu.cu->dimdDerivedIntraDir;
+#else
     intraMode = g_geoAngle2IntraAng[g_geoParams[tu.cu->firstPU->geoSplitDir][0]];
+#endif
+  }
+#endif
+#if JVET_AI0050_INTER_MTSS
+  if (tu.cu->lfnstIntra)
+  {
+    intraMode = tu.cu->dimdDerivedIntraDir2nd;
   }
 #endif
 #if JVET_AB0155_SGPM
diff --git a/source/Lib/CommonLib/TrQuant.h b/source/Lib/CommonLib/TrQuant.h
index 8d08972dbe53f097bcd04f36da01bcb32d569094..fd64488af58203dc77c937cedb2aa8952ec427be 100644
--- a/source/Lib/CommonLib/TrQuant.h
+++ b/source/Lib/CommonLib/TrQuant.h
@@ -174,7 +174,11 @@ protected:
 private:
   DepQuant *m_quant;          //!< Quantizer
 #if JVET_AG0061_INTER_LFNST_NSPT
+#if JVET_AI0050_INTER_MTSS
+  TCoeff   m_mtsCoeffs[NUM_TRAFO_MODES_MTS + 6][MAX_TB_SIZEY * MAX_TB_SIZEY];
+#else
   TCoeff   m_mtsCoeffs[NUM_TRAFO_MODES_MTS + 3][MAX_TB_SIZEY * MAX_TB_SIZEY];
+#endif
 #else
   TCoeff   m_mtsCoeffs[NUM_TRAFO_MODES_MTS][MAX_TB_SIZEY * MAX_TB_SIZEY];
 #endif
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 11cd0a4f9468a4a18135c5b023d86bf39549c74d..431bac7969951e9eb829a2115ddf367f0dabfd7c 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -419,6 +419,8 @@
 #define JVET_AG0100_TRANSFORM_COEFFICIENT_CODING          1 // JVET_AG0100: 3.2b Transform coefficient coding
 #define JVET_AG0143_INTER_INTRA                           1 // JVET_AG0143: 3.1c CABAC inter/intra model switch
 #define JVET_AH0103_LOW_DELAY_LFNST_NSPT                  1 // JVET_AH0103: Low-delay configurations for LFNST/NSPT
+#define JVET_AI0050_INTER_MTSS                            1 // JVET_AI0050: Multiple LFNST/NSPT kernel set selection for GPM coded block
+#define JVET_AI0050_SBT_LFNST                             1 // JVET_AI0050: Enable LFNST/NSPT for SBT coded block
 
 // Entropy Coding
 #define EC_HIGH_PRECISION                                 1 // CABAC high precision
diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp
index e3f0d49736f1384a75eaaca2da38dc87f510f1bb..0718864168aa9b8d5e4b41c2d6be38d43391f097 100644
--- a/source/Lib/CommonLib/Unit.cpp
+++ b/source/Lib/CommonLib/Unit.cpp
@@ -286,6 +286,9 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other )
   mtsFlag           = other.mtsFlag;
 #if JVET_AG0061_INTER_LFNST_NSPT
   lfnstFlag         = other.lfnstFlag;
+#if JVET_AI0050_INTER_MTSS
+  lfnstIntra        = other.lfnstIntra;
+#endif
 #endif
   lfnstIdx          = other.lfnstIdx;
   tileIdx           = other.tileIdx;
@@ -457,6 +460,9 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other )
 #endif
 #if JVET_AG0061_INTER_LFNST_NSPT
   dimdDerivedIntraDir = other.dimdDerivedIntraDir;
+#if JVET_AI0050_INTER_MTSS
+  dimdDerivedIntraDir2nd = other.dimdDerivedIntraDir2nd;
+#endif
 #endif
 #endif
 #if JVET_AG0276_NLIC
@@ -577,6 +583,9 @@ void CodingUnit::initData()
   mtsFlag           = 0;
 #if JVET_AG0061_INTER_LFNST_NSPT
   lfnstFlag         = 0;
+#if JVET_AI0050_INTER_MTSS
+  lfnstIntra        = 0;
+#endif
 #endif
   lfnstIdx          = 0;
   tileIdx           = 0;
@@ -738,6 +747,9 @@ void CodingUnit::initData()
 #endif
 #if JVET_AG0061_INTER_LFNST_NSPT
   dimdDerivedIntraDir = 0;
+#if JVET_AI0050_INTER_MTSS
+  dimdDerivedIntraDir2nd = 0;
+#endif
 #endif
 #endif
 #if JVET_AG0276_NLIC
@@ -960,7 +972,7 @@ const uint8_t CodingUnit::checkAllowedSbt() const
   {
     return 0;
   }
-#if JVET_Y0065_GPM_INTRA
+#if JVET_Y0065_GPM_INTRA && !JVET_AI0050_SBT_LFNST
   if (firstPU->gpmIntraFlag)
   {
     return 0;
@@ -2018,6 +2030,9 @@ void TransformUnit::initData()
     mtsIdx[i]        = MTS_DCT2_DCT2;
 #if JVET_AG0061_INTER_LFNST_NSPT
     lfnstIdx[i]      = 0;
+#if JVET_AI0050_INTER_MTSS
+    lfnstIntra[i]    = 0;
+#endif
 #endif
   }
   depth              = 0;
@@ -2114,6 +2129,9 @@ TransformUnit& TransformUnit::operator=(const TransformUnit& other)
     mtsIdx[i]        = other.mtsIdx[i];
 #if JVET_AG0061_INTER_LFNST_NSPT
     lfnstIdx[i]      = other.lfnstIdx[i];
+#if JVET_AI0050_INTER_MTSS
+    lfnstIntra[i]    = other.lfnstIntra[i];
+#endif
 #endif
   }
   depth              = other.depth;
@@ -2161,6 +2179,9 @@ void TransformUnit::copyComponentFrom(const TransformUnit& other, const Componen
   mtsIdx[i]        = other.mtsIdx[i];
 #if JVET_AG0061_INTER_LFNST_NSPT
   lfnstIdx[i]      = other.lfnstIdx[i];
+#if JVET_AI0050_INTER_MTSS
+  lfnstIntra[i]    = other.lfnstIntra[i];
+#endif
 #endif
   noResidual       = other.noResidual;
   jointCbCr        = isChroma( i ) ? other.jointCbCr : jointCbCr;
diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h
index 1dce80296e5e80436f5e985ff1408d40dbfbaa42..fb1d0386ec5083ef2eae5005dd01e769a326050a 100644
--- a/source/Lib/CommonLib/Unit.h
+++ b/source/Lib/CommonLib/Unit.h
@@ -434,9 +434,15 @@ struct CodingUnit : public UnitArea
   uint8_t        mtsFlag;
 #if JVET_AG0061_INTER_LFNST_NSPT
   uint8_t        lfnstFlag;
+#if JVET_AI0050_INTER_MTSS
+  uint8_t        lfnstIntra;
+#endif
 #endif
 #if JVET_AG0061_INTER_LFNST_NSPT
   int            dimdDerivedIntraDir;
+#if JVET_AI0050_INTER_MTSS
+  int            dimdDerivedIntraDir2nd;
+#endif
 #endif
   uint8_t        lfnstIdx;
   uint8_t        bcwIdx;
@@ -923,6 +929,9 @@ struct TransformUnit : public UnitArea
   uint8_t        mtsIdx     [ MAX_NUM_TBLOCKS ];
 #if JVET_AG0061_INTER_LFNST_NSPT
   uint8_t        lfnstIdx   [ MAX_NUM_TBLOCKS ];
+#if JVET_AI0050_INTER_MTSS
+  uint8_t        lfnstIntra [ MAX_NUM_TBLOCKS ];
+#endif
 #endif
   bool           noResidual;
   uint8_t        jointCbCr;
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index c5263fb5a69860f71eaef148060a7fc740ef419c..1e5d5f177b149b037e428b808901ef32b3fa39cc 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -29775,7 +29775,23 @@ bool CU::isSbtMode( const uint8_t sbtInfo )
   uint8_t sbtIdx = getSbtIdx( sbtInfo );
   return sbtIdx >= SBT_VER_HALF && sbtIdx <= SBT_HOR_QUAD;
 }
-
+#if JVET_AI0050_SBT_LFNST
+void CU::getSBTPosAndSize(const CodingUnit &cu, Position& pos, Size& size, uint8_t sbtMode)
+{
+  switch (sbtMode)
+  {
+  case SBT_VER_H0: pos = Position(0, 0);  size = Size(cu.lwidth() >> 1, cu.lheight());  break;
+  case SBT_VER_H1: pos = Position(cu.lwidth() >> 1, 0);  size = Size(cu.lwidth() >> 1, cu.lheight());  break;
+  case SBT_HOR_H0: pos = Position(0, 0);  size = Size(cu.lwidth(), cu.lheight() >> 1);  break;
+  case SBT_HOR_H1: pos = Position(0, cu.lheight() >> 1);  size = Size(cu.lwidth(), cu.lheight() >> 1);  break;
+  case SBT_VER_Q0: pos = Position(0, 0);  size = Size(cu.lwidth() >> 2, cu.lheight());  break;
+  case SBT_VER_Q1: pos = Position((3 * cu.lwidth()) >> 2, 0);  size = Size(cu.lwidth() >> 2, cu.lheight());  break;
+  case SBT_HOR_Q0: pos = Position(0, 0);  size = Size(cu.lwidth(), cu.lheight() >> 2);  break;
+  case SBT_HOR_Q1: pos = Position(0, (3 * cu.lheight()) >> 2);  size = Size(cu.lwidth(), cu.lheight() >> 2);  break;
+  default:           assert(0);
+  }
+}
+#endif
 bool CU::isSameSbtSize( const uint8_t sbtInfo1, const uint8_t sbtInfo2 )
 {
   uint8_t sbtIdx1 = getSbtIdxFromSbtMode( sbtInfo1 );
@@ -31290,7 +31306,17 @@ uint32_t PU::getFinalIntraModeForTransform( const TransformUnit &tu, const Compo
   }
   if (tu.cu->geoFlag)
   {
+#if JVET_AI0050_INTER_MTSS
+    intraMode = tu.cu->dimdDerivedIntraDir;
+#else
     intraMode = g_geoAngle2IntraAng[g_geoParams[tu.cu->firstPU->geoSplitDir][0]];
+#endif
+  }
+#endif
+#if JVET_AI0050_INTER_MTSS
+  if (tu.cu->lfnstIntra)
+  {
+    intraMode = tu.cu->dimdDerivedIntraDir2nd;
   }
 #endif
 #if JVET_AB0155_SGPM
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index 3e677b6145b0b31528dcd71232149bf1012347a2..fd02a6b691ea5a65ae7dc909baafc53f01733d56 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -172,6 +172,9 @@ namespace CU
   uint8_t numSbtModeRdo               (uint8_t sbtAllowed);
   bool    isSbtMode                   (const uint8_t sbtInfo);
   bool    isSameSbtSize               (const uint8_t sbtInfo1, const uint8_t sbtInfo2);
+#if JVET_AI0050_SBT_LFNST
+  void    getSBTPosAndSize            (const CodingUnit &cu, Position& pos, Size& size, uint8_t sbtMode);
+#endif
   bool    getRprScaling               ( const SPS* sps, const PPS* curPPS, Picture* refPic, int& xScale, int& yScale );
   void    checkConformanceILRP        (Slice *slice);
 #if JVET_AB0157_TMRL
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index ad92a4d5f0c334cf4762b3a37e249dc04e36fad1..208045eb9529ce022bce2f05f09a0ea24b3a75f1 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -9218,7 +9218,9 @@ void CABACReader::residual_lfnst_mode( CodingUnit& cu,  CUCtx& cuCtx  )
 #else
     || (cu.isSepTree() && cu.chType == CHANNEL_TYPE_CHROMA && std::min(cu.blocks[1].width, cu.blocks[1].height) < 4)
 #endif
-#if JVET_AG0061_INTER_LFNST_NSPT
+#if JVET_AG0061_INTER_LFNST_NSPT && JVET_AI0050_SBT_LFNST
+    || ( !cu.cs->sps->getUseSbtLFNST() && cu.sbtInfo && CU::isInter( cu ) )
+#elif JVET_AG0061_INTER_LFNST_NSPT
     || ( cu.sbtInfo && CU::isInter( cu ) ) //JVET-AG0208 (EE2-related: On LFNST/NSPT index signalling)
 #endif
     || (cu.blocks[chIdx].lumaSize().width > cu.cs->sps->getMaxTbSize()
@@ -9294,6 +9296,12 @@ void CABACReader::residual_lfnst_mode( CodingUnit& cu,  CUCtx& cuCtx  )
       }
     }
     cu.lfnstIdx = idxLFNST;
+#if JVET_AI0050_INTER_MTSS
+    if (cu.cs->sps->getUseInterMTSS() && cu.lfnstIdx > 0 && cu.geoFlag)
+    {
+      cu.lfnstIntra = m_BinDecoder.decodeBin(Ctx::InterLFNSTIntraIdx());
+    }
+#endif
   }
   else
   {
diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp
index 9be322508766d5cc1be4125ef4c7db59e6f10164..58e3e321636965a7e559c1c67e08289bacd35609 100644
--- a/source/Lib/DecoderLib/DecCu.cpp
+++ b/source/Lib/DecoderLib/DecCu.cpp
@@ -1236,7 +1236,17 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID )
       m_pcIntraPred->eipPred(pu, piPred);
       if (!isEncoder)
       {
-        pu.cu->eipModel.eipDimdMode = IntraPrediction::deriveIpmForTransform(piPred, *pu.cu);
+#if JVET_AI0050_INTER_MTSS
+        int secondDimdIntraDir = 0;
+#endif
+        pu.cu->eipModel.eipDimdMode = IntraPrediction::deriveIpmForTransform(piPred, *pu.cu
+#if JVET_AI0050_INTER_MTSS
+          , secondDimdIntraDir
+#endif
+        );
+#if JVET_AI0050_INTER_MTSS
+        pu.cu->dimdDerivedIntraDir2nd = secondDimdIntraDir;
+#endif
       }
     }
 #endif
@@ -2699,7 +2709,37 @@ void DecCu::xDecodeInterTexture(CodingUnit &cu)
 #if JVET_AG0061_INTER_LFNST_NSPT
   if (cu.lfnstIdx)
   {
-    cu.dimdDerivedIntraDir = m_pcIntraPred->deriveIpmForTransform(cu.cs->getPredBuf(*cu.firstPU).Y(), cu);
+#if JVET_AI0050_INTER_MTSS
+    int secondDimdIntraDir = 0;
+#endif
+#if JVET_AI0050_SBT_LFNST
+    if (cu.cs->sps->getUseSbtLFNST() && cu.sbtInfo)
+    {
+      Position pos(0, 0);
+      Size size(0, 0);
+      int sbtIdx = cu.getSbtIdx();
+      int sbtPos = cu.getSbtPos();
+      CU::getSBTPosAndSize(cu, pos, size, CU::getSbtMode(sbtIdx, sbtPos));
+      cu.dimdDerivedIntraDir = m_pcIntraPred->deriveIpmForTransform(cu.cs->getPredBuf(*cu.firstPU).Y().subBuf(pos, size), cu
+#if JVET_AI0050_INTER_MTSS
+        , secondDimdIntraDir
+#endif
+      );
+    }
+    else
+    {
+#endif
+      cu.dimdDerivedIntraDir = m_pcIntraPred->deriveIpmForTransform(cu.cs->getPredBuf(*cu.firstPU).Y(), cu
+#if JVET_AI0050_INTER_MTSS
+        , secondDimdIntraDir
+#endif
+      );
+#if JVET_AI0050_SBT_LFNST
+    }
+#endif
+#if JVET_AI0050_INTER_MTSS
+    cu.dimdDerivedIntraDir2nd = secondDimdIntraDir;
+#endif
   }
 #endif
 
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index bf2732572d60d58b357046f5fbad96d1a585e529..ffc93c24df6de8db0687cce6bb8bf10ee51206f3 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -2100,6 +2100,12 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
   READ_FLAG( uiCode, "sps_intra_lfnst_intra_slice_enabled_flag" );               pcSPS->setUseIntraLFNSTISlice( uiCode != 0 );
   READ_FLAG( uiCode, "sps_intra_lfnst_inter_slice_enabled_flag" );               pcSPS->setUseIntraLFNSTPBSlice( uiCode != 0 );
   READ_FLAG( uiCode, "sps_inter_lfnst_enabled_flag" );            pcSPS->setUseInterLFNST( uiCode != 0 );
+#if JVET_AI0050_INTER_MTSS
+  if (pcSPS->getUseInterLFNST())
+  {
+    READ_FLAG( uiCode, "sps_inter_mtss_enabled_flag" );            pcSPS->setUseInterMTSS( uiCode != 0 );
+  }
+#endif
 #else
   READ_FLAG(uiCode, "sps_lfnst_enabled_flag");                    pcSPS->setUseLFNST(uiCode != 0);
 #endif
@@ -2447,6 +2453,12 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
   }
 #endif
   READ_FLAG(uiCode, "sps_sbt_enabled_flag");                        pcSPS->setUseSBT                 ( uiCode != 0 );
+#if JVET_AI0050_SBT_LFNST
+  if (pcSPS->getUseSBT())
+  {
+    READ_FLAG(uiCode, "sps_sbt_lfnst_enabled_flag");            pcSPS->setUseSbtLFNST(uiCode != 0);
+  }
+#endif
 #if TM_AMVP || TM_MRG || JVET_Z0084_IBC_TM || MULTI_PASS_DMVR
   READ_FLAG( uiCode,    "sps_dmvd_enabled_flag" );                      pcSPS->setUseDMVDMode( uiCode != 0 );
 #endif
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index 68de12b38ec15efe9def52541ad1456d1c11bb29..58d66b58559eb80230f85f66bfe8d28c62cfd3a4 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -9040,7 +9040,9 @@ void CABACWriter::residual_lfnst_mode( const CodingUnit& cu, CUCtx& cuCtx )
     ( cu.isSepTree() && cu.chType == CHANNEL_TYPE_CHROMA && std::min( cu.blocks[ 1 ].width, cu.blocks[ 1 ].height ) < 4 )
 #endif
     || ( cu.blocks[ chIdx ].lumaSize().width > cu.cs->sps->getMaxTbSize() || cu.blocks[ chIdx ].lumaSize().height > cu.cs->sps->getMaxTbSize() )
-#if JVET_AG0061_INTER_LFNST_NSPT
+#if JVET_AG0061_INTER_LFNST_NSPT && JVET_AI0050_SBT_LFNST
+    || ( !cu.cs->sps->getUseSbtLFNST() && cu.sbtInfo && CU::isInter( cu ))
+#elif JVET_AG0061_INTER_LFNST_NSPT
     || ( cu.sbtInfo && CU::isInter( cu ) ) //JVET-AG0208 (EE2-related: On LFNST/NSPT index signalling)
 #endif
     )
@@ -9112,6 +9114,12 @@ void CABACWriter::residual_lfnst_mode( const CodingUnit& cu, CUCtx& cuCtx )
         m_BinEncoder.encodeBin(idxLFNST > 2, Ctx::InterLFNSTIdx(2));
       }
     }
+#if JVET_AI0050_INTER_MTSS
+    if (cu.cs->sps->getUseInterMTSS() && idxLFNST > 0 && cu.geoFlag)
+    {
+      m_BinEncoder.encodeBin(cu.lfnstIntra, Ctx::InterLFNSTIntraIdx());
+    }
+#endif
   }
   else
   {
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index b753a0a8e938421ab95f43dec24da81f36933148..2bd1cf6a5c461515aed3cfce320c6f61e2206ff7 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -413,6 +413,12 @@ protected:
   bool      m_interLFNST;
 #else
   bool      m_LFNST;
+#endif
+#if JVET_AI0050_INTER_MTSS
+  bool      m_useInterMTSS;
+#endif
+#if JVET_AI0050_SBT_LFNST
+  bool      m_useSbtLFNST;
 #endif
   bool      m_useFastLFNST;
 #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
@@ -1579,7 +1585,14 @@ public:
   void      setUseFastInterLFNST            ( bool b )       { m_useFastInterLFNST = b; }
   bool      getUseFastInterLFNST()                     const { return m_useFastInterLFNST; }
 #endif
-
+#if JVET_AI0050_INTER_MTSS
+  void      setUseInterMTSS                 ( bool b )       { m_useInterMTSS = b; }
+  bool      getUseInterMTSS()                          const { return m_useInterMTSS; }
+#endif
+#if JVET_AI0050_SBT_LFNST
+  void      setUseSBTLFNST                  ( bool b )       { m_useSbtLFNST = b; }
+  bool      getUseSBTLFNST()                           const { return m_useSbtLFNST; }
+#endif
   void      setUseLMChroma                  ( int n )        { m_LMChroma = n; }
   int       getUseLMChroma()                           const { return m_LMChroma; }
   void      setHorCollocatedChromaFlag( bool b )             { m_horCollocatedChromaFlag = b; }
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 0c959a7f138a8c072fc78fcfb82678b36cce9bdc..94a0ac381e017cd2140d09da6299ccf1802c06c9 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -9618,6 +9618,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if JVET_AG0061_INTER_LFNST_NSPT
   cu.lfnstFlag = false;
   cu.lfnstIdx = 0;
+#if JVET_AI0050_INTER_MTSS
+  cu.lfnstIntra = 0;
+#endif
 #endif
 #if INTER_LIC
   cu.licFlag = false;
@@ -11488,6 +11491,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if JVET_AG0061_INTER_LFNST_NSPT
       cu.lfnstFlag = false;
       cu.lfnstIdx = 0;
+#if JVET_AI0050_INTER_MTSS
+      cu.lfnstIntra = 0;
+#endif
 #endif
       cu.imv = 0;
       cu.mmvdSkip = false;
@@ -11829,6 +11835,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if JVET_AG0061_INTER_LFNST_NSPT
     cu.lfnstFlag = false;
     cu.lfnstIdx  = 0;
+#if JVET_AI0050_INTER_MTSS
+    cu.lfnstIntra = 0;
+#endif
 #endif
     cu.imv = 0;
     cu.mmvdSkip = false;
@@ -13862,6 +13871,9 @@ void EncCu::xCheckRDCostMergeGeoComb2Nx2N(CodingStructure *&tempCS, CodingStruct
 #if JVET_AG0061_INTER_LFNST_NSPT
         cu.lfnstFlag = false;
         cu.lfnstIdx  = 0;
+#if JVET_AI0050_INTER_MTSS
+        cu.lfnstIntra = 0;
+#endif
 #endif
         cu.imv = 0;
         cu.mmvdSkip = false;
@@ -22844,6 +22856,9 @@ void EncCu::xEncodeInterResidual(   CodingStructure *&tempCS
 #if JVET_AG0061_INTER_LFNST_NSPT
   cu->lfnstFlag           = false;
   cu->lfnstIdx            = 0;
+#if JVET_AI0050_INTER_MTSS
+  cu->lfnstIntra          = 0;
+#endif
 #if JVET_AH0103_LOW_DELAY_LFNST_NSPT
   const bool lfnstAllowed = tempCS->sps->getUseInterLFNST() && CU::isInter( *cu )
 #else
@@ -22942,6 +22957,9 @@ void EncCu::xEncodeInterResidual(   CodingStructure *&tempCS
 #if JVET_AG0061_INTER_LFNST_NSPT
     cu->lfnstFlag = false;
     cu->lfnstIdx  = 0;
+#if JVET_AI0050_INTER_MTSS
+    cu->lfnstIntra = 0;
+#endif
 #endif
     const bool skipResidual = residualPass == 1;
     if( skipResidual || histBestSbt == MAX_UCHAR || !CU::isSbtMode( histBestSbt ) )
@@ -23034,107 +23052,194 @@ void EncCu::xEncodeInterResidual(   CodingStructure *&tempCS
       numSbtRdo = 1;
       m_pcInterSearch->initSbtRdoOrder( CU::getSbtMode( CU::getSbtIdx( histBestSbt ), CU::getSbtPos( histBestSbt ) ) );
     }
+#if JVET_AI0050_SBT_LFNST
+    std::vector<TrCost> trCosts;
+    double costSBT[NUMBER_SBT_MODE];
+    bool   skipCurSBT[NUMBER_SBT_MODE];
+    std::fill_n(costSBT, NUMBER_SBT_MODE, MAX_DOUBLE);
+    std::fill_n(skipCurSBT, NUMBER_SBT_MODE, true);
 
-    for( int sbtModeIdx = 0; sbtModeIdx < numSbtRdo; sbtModeIdx++ )
-    {
-      uint8_t sbtMode = m_pcInterSearch->getSbtRdoOrder( sbtModeIdx );
-      uint8_t sbtIdx = CU::getSbtIdxFromSbtMode( sbtMode );
-      uint8_t sbtPos = CU::getSbtPosFromSbtMode( sbtMode );
-
-      //fast algorithm (early skip, save & load)
-      if( histBestSbt == MAX_UCHAR )
+    const int32_t iPicSize = pu.cu->slice->getPic()->lumaSize().area();
+    bool iPicSizeCondition = iPicSize < 4096000;
+    for (int lfnstIdx = 0; lfnstIdx < (tempCS->sps->getUseSbtLFNST() ? 2 : 1); lfnstIdx++)
+    { 
+      if (lfnstIdx && prevBestSbt == 0 && trCosts[0].second != MAX_DOUBLE && trCosts[0].second != std::numeric_limits<int>::max() && iPicSizeCondition) // 4096000 = 2560 * 1600
       {
-        uint8_t skipCode = m_pcInterSearch->skipSbtByRDCost( cu->lwidth(), cu->lheight(), cu->mtDepth, sbtIdx, sbtPos, bestCS->cost, sbtOffDist, sbtOffCost, sbtOffRootCbf );
-        if( skipCode != MAX_UCHAR )
+        double th = pu.cu->slice->getCheckLDB() ? (iPicSize < 2073600 ? 1.04 : 1.07) : 1.04; // 2073600 = 1920 * 1080
+        if (trCosts[0].second > bestCS->cost * th)
         {
           continue;
         }
+      }
+#endif
+      for (int sbtModeIdx = 0; sbtModeIdx < numSbtRdo; sbtModeIdx++)
+      {
+#if JVET_AI0050_SBT_LFNST
+        if (lfnstIdx && skipCurSBT[sbtModeIdx] && iPicSizeCondition)
+        {
+          continue;
+        }
+#endif
+        uint8_t sbtMode = m_pcInterSearch->getSbtRdoOrder(sbtModeIdx);
+        uint8_t sbtIdx = CU::getSbtIdxFromSbtMode(sbtMode);
+        uint8_t sbtPos = CU::getSbtPosFromSbtMode(sbtMode);
 
-        if( sbtModeIdx > 0 )
+        //fast algorithm (early skip, save & load)
+        if (histBestSbt == MAX_UCHAR)
         {
-          uint8_t prevSbtMode = m_pcInterSearch->getSbtRdoOrder( sbtModeIdx - 1 );
-          //make sure the prevSbtMode is the same size as the current SBT mode (otherwise the estimated dist may not be comparable)
-          if( CU::isSameSbtSize( prevSbtMode, sbtMode ) )
+          uint8_t skipCode = m_pcInterSearch->skipSbtByRDCost(cu->lwidth(), cu->lheight(), cu->mtDepth, sbtIdx, sbtPos, bestCS->cost, sbtOffDist, sbtOffCost, sbtOffRootCbf);
+          if (skipCode != MAX_UCHAR)
+          {
+            continue;
+          }
+
+          if (sbtModeIdx > 0)
           {
-            Distortion currEstDist = m_pcInterSearch->getEstDistSbt( sbtMode );
-            Distortion prevEstDist = m_pcInterSearch->getEstDistSbt( prevSbtMode );
-            if( currEstDist > prevEstDist * 1.15 )
+            uint8_t prevSbtMode = m_pcInterSearch->getSbtRdoOrder(sbtModeIdx - 1);
+            //make sure the prevSbtMode is the same size as the current SBT mode (otherwise the estimated dist may not be comparable)
+            if (CU::isSameSbtSize(prevSbtMode, sbtMode))
             {
-              continue;
+              Distortion currEstDist = m_pcInterSearch->getEstDistSbt(sbtMode);
+              Distortion prevEstDist = m_pcInterSearch->getEstDistSbt(prevSbtMode);
+              if (currEstDist > prevEstDist * 1.15)
+              {
+                continue;
+              }
             }
           }
         }
-      }
 
-      //init tempCS and TU
-      if( bestCost == bestCS->cost ) //The first EMT pass didn't become the bestCS, so we clear the TUs generated
-      {
-        tempCS->clearTUs();
-      }
-      else if( false == swapped )
-      {
-        tempCS->initStructData( encTestMode.qp );
-        tempCS->copyStructure( *bestCS, partitioner.chType );
-        tempCS->getPredBuf().copyFrom( bestCS->getPredBuf() );
-        bestCost = bestCS->cost;
-        cu = tempCS->getCU( partitioner.chType );
-        swapped = true;
-      }
-      else
-      {
-        tempCS->clearTUs();
-        bestCost = bestCS->cost;
-        cu = tempCS->getCU( partitioner.chType );
-      }
+        //init tempCS and TU
+        if (bestCost == bestCS->cost) //The first EMT pass didn't become the bestCS, so we clear the TUs generated
+        {
+          tempCS->clearTUs();
+        }
+        else if (false == swapped)
+        {
+          tempCS->initStructData(encTestMode.qp);
+          tempCS->copyStructure(*bestCS, partitioner.chType);
+          tempCS->getPredBuf().copyFrom(bestCS->getPredBuf());
+          bestCost = bestCS->cost;
+          cu = tempCS->getCU(partitioner.chType);
+          swapped = true;
+        }
+        else
+        {
+          tempCS->clearTUs();
+          bestCost = bestCS->cost;
+          cu = tempCS->getCU(partitioner.chType);
+        }
 
-      //we need to restart the distortion for the new tempCS, the bit count and the cost
-      tempCS->dist = 0;
-      tempCS->fracBits = 0;
-      tempCS->cost = MAX_DOUBLE;
-      cu->skip = false;
+        //we need to restart the distortion for the new tempCS, the bit count and the cost
+        tempCS->dist = 0;
+        tempCS->fracBits = 0;
+        tempCS->cost = MAX_DOUBLE;
+        cu->skip = false;
 #if JVET_AG0061_INTER_LFNST_NSPT
-      cu->lfnstFlag = false;
-      cu->lfnstIdx  = 0;
+#if JVET_AI0050_SBT_LFNST
+        cu->lfnstFlag = lfnstIdx;
+        if (cu->lfnstFlag)
+        {
+#if JVET_AI0050_INTER_MTSS
+          int secondDimdIntraDir = 0;
 #endif
-      //set SBT info
-      cu->setSbtIdx( sbtIdx );
-      cu->setSbtPos( sbtPos );
-
-      //try residual coding
-      m_pcInterSearch->encodeResAndCalcRdInterCU( *tempCS, partitioner, skipResidual );
-      if (tempCS->slice->getSPS()->getUseColorTrans())
-      {
-        bestCS->tmpColorSpaceCost = tempCS->tmpColorSpaceCost;
-        bestCS->firstColorSpaceSelected = tempCS->firstColorSpaceSelected;
-      }
-      numRDOTried++;
+          Position pos(0, 0);
+          Size size(0, 0);
+          CU::getSBTPosAndSize(*cu, pos, size, sbtMode);
+          cu->dimdDerivedIntraDir = m_pcIntraSearch->deriveIpmForTransform(cu->cs->getPredBuf(*cu->firstPU).Y().subBuf(pos, size), *cu
+#if JVET_AI0050_INTER_MTSS
+            , secondDimdIntraDir
+#endif
+          );
+#if JVET_AI0050_INTER_MTSS
+          cu->dimdDerivedIntraDir2nd = secondDimdIntraDir;
+#endif
+        }
+#else
+        cu->lfnstFlag = false;
+#endif
+        cu->lfnstIdx = 0;
+#if JVET_AI0050_INTER_MTSS
+        cu->lfnstIntra = 0;
+#endif
+#endif
+        //set SBT info
+        cu->setSbtIdx(sbtIdx);
+        cu->setSbtPos(sbtPos);
 
-      xEncodeDontSplit( *tempCS, partitioner );
+        //try residual coding
+#if JVET_AI0050_SBT_LFNST
+        bool isValid = m_pcInterSearch->encodeResAndCalcRdInterCU(*tempCS, partitioner, skipResidual);
+#else
+        m_pcInterSearch->encodeResAndCalcRdInterCU(*tempCS, partitioner, skipResidual);
+#endif
+#if JVET_AI0050_SBT_LFNST
+        if (isValid || !cu->lfnstFlag)
+        {
+#endif
+          if (tempCS->slice->getSPS()->getUseColorTrans())
+          {
+            bestCS->tmpColorSpaceCost = tempCS->tmpColorSpaceCost;
+            bestCS->firstColorSpaceSelected = tempCS->firstColorSpaceSelected;
+          }
+          numRDOTried++;
 
-      xCheckDQP( *tempCS, partitioner );
-      xCheckChromaQPOffset( *tempCS, partitioner );
+          xEncodeDontSplit(*tempCS, partitioner);
 
-      if( NULL != bestHasNonResi && ( bestCostInternal > tempCS->cost ) )
-      {
-        bestCostInternal = tempCS->cost;
-        if( !( tempCS->getPU( partitioner.chType )->ciipFlag ) )
-          *bestHasNonResi = !cu->rootCbf;
-      }
+          xCheckDQP(*tempCS, partitioner);
+          xCheckChromaQPOffset(*tempCS, partitioner);
 
-      if( tempCS->cost < currBestCost )
-      {
-        currBestSbt = cu->sbtInfo;
-        currBestTrs = tempCS->tus[cu->sbtInfo ? cu->getSbtPos() : 0]->mtsIdx[COMPONENT_Y];
-        assert( currBestTrs == 0 || currBestTrs == 1 );
-        currBestCost = tempCS->cost;
-      }
+          if (NULL != bestHasNonResi && (bestCostInternal > tempCS->cost))
+          {
+            bestCostInternal = tempCS->cost;
+            if (!(tempCS->getPU(partitioner.chType)->ciipFlag))
+            {
+              *bestHasNonResi = !cu->rootCbf;
+            }
+          }
 
+          if (tempCS->cost < currBestCost)
+          {
+            currBestSbt = cu->sbtInfo;
+            currBestTrs = tempCS->tus[cu->sbtInfo ? cu->getSbtPos() : 0]->mtsIdx[COMPONENT_Y];
+            assert(currBestTrs == 0 || currBestTrs == 1);
+            currBestCost = tempCS->cost;
+          }
+#if JVET_AI0050_SBT_LFNST
+          if (lfnstIdx == 0)
+          {
+            costSBT[sbtModeIdx] = tempCS->cost;
+          }
+#endif
 #if WCG_EXT
-      DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda( true ) );
+          DTRACE_MODE_COST(*tempCS, m_pcRdCost->getLambda(true));
 #else
-      DTRACE_MODE_COST( *tempCS, m_pcRdCost->getLambda() );
+          DTRACE_MODE_COST(*tempCS, m_pcRdCost->getLambda());
+#endif
+          xCheckBestMode(tempCS, bestCS, partitioner, encTestMode);
+#if JVET_AI0050_SBT_LFNST
+        }
+      }
+      if (lfnstIdx == 0)
+      {
+        for (int i = 0; i < NUMBER_SBT_MODE; i++)
+        {
+          trCosts.push_back(TrCost(i, int(std::min<double>(costSBT[i], std::numeric_limits<int>::max()))));
+        }
+        std::stable_sort(trCosts.begin(), trCosts.end(), [](const TrCost  l, const TrCost r) {return l.second < r.second; });
+        for (int i = 0; i < NUM_SBT_LFNST_RDO; i++)
+        {
+          if (trCosts[i].second != MAX_DOUBLE && trCosts[i].second != std::numeric_limits<int>::max())
+          {
+            double th = 1.1;
+            if (i == 0 || (i > 0 && (trCosts[i].second < th * trCosts[0].second)))
+            {
+              skipCurSBT[trCosts[i].first] = false;
+            }
+          }
+        }
+      }
 #endif
-      xCheckBestMode( tempCS, bestCS, partitioner, encTestMode );
     }
 #if JVET_AA0133_INTER_MTS_OPT
     if (!skipResidual && mtsAllowed)
@@ -23171,6 +23276,9 @@ void EncCu::xEncodeInterResidual(   CodingStructure *&tempCS
 #if JVET_AG0061_INTER_LFNST_NSPT
       cu->lfnstFlag = false;
       cu->lfnstIdx  = 0;
+#if JVET_AI0050_INTER_MTSS
+      cu->lfnstIntra = 0;
+#endif
 #endif
 #endif
       m_pcInterSearch->setBestCost(bestCS->cost);
@@ -23222,6 +23330,9 @@ void EncCu::xEncodeInterResidual(   CodingStructure *&tempCS
         cu->mtsFlag          = true;
         cu->lfnstFlag        = false;
         cu->lfnstIdx         = 0;
+#if JVET_AI0050_INTER_MTSS
+        cu->lfnstIntra       = 0;
+#endif
 #endif
       //try residual coding
         bool isValid = m_pcInterSearch->encodeResAndCalcRdInterCU(*tempCS, partitioner, skipResidual);
@@ -23329,7 +23440,17 @@ void EncCu::xEncodeInterResidual(   CodingStructure *&tempCS
           bestCost = bestCS->cost;
           cu       = tempCS->getCU(partitioner.chType);
         }
-        cu->dimdDerivedIntraDir = m_pcIntraSearch->deriveIpmForTransform(cu->cs->getPredBuf(*cu->firstPU).Y(), *cu);
+#if JVET_AI0050_INTER_MTSS
+        int secondDimdIntraDir = 0;
+#endif
+        cu->dimdDerivedIntraDir = m_pcIntraSearch->deriveIpmForTransform(cu->cs->getPredBuf(*cu->firstPU).Y(), *cu
+#if JVET_AI0050_INTER_MTSS
+          , secondDimdIntraDir
+#endif
+        );
+#if JVET_AI0050_INTER_MTSS
+        cu->dimdDerivedIntraDir2nd = secondDimdIntraDir;
+#endif
         // we need to restart the distortion for the new tempCS, the bit count and the cost
         tempCS->dist         = 0;
         tempCS->fracBits     = 0;
@@ -23340,6 +23461,9 @@ void EncCu::xEncodeInterResidual(   CodingStructure *&tempCS
         cu->mtsFlag          = false;
         cu->lfnstFlag        = true;
         cu->lfnstIdx         = 0;
+#if JVET_AI0050_INTER_MTSS
+        cu->lfnstIntra       = 0;
+#endif
         m_pcInterSearch->setBestCost(bestCS->cost);
         {
           // try residual coding
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index 52deaa69eae7a93654d3747cbff63fe68ebcc24c..1f35e46e9f6536d59a6648a765755ab926147c1d 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -1971,6 +1971,12 @@ void EncLib::xInitSPS( SPS& sps )
   sps.setUseIntraMTS           ( m_IntraMTS );
   sps.setUseInterMTS           ( m_InterMTS );
   sps.setUseSBT                             ( m_SBT );
+#if JVET_AI0050_INTER_MTSS
+  sps.setUseInterMTSS          ( m_useInterMTSS );
+#endif
+#if JVET_AI0050_SBT_LFNST
+  sps.setUseSbtLFNST           ( m_useSbtLFNST );
+#endif
   sps.setUseSMVD                ( m_SMVD );
   sps.setUseBcw                ( m_bcw );
 #if INTER_LIC
diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp
index 5777a304521117d9a1cc67ac72d9cfce1a29ed7c..da4eedd5e920bfb3fdeca7d275b679841c929031 100644
--- a/source/Lib/EncoderLib/InterSearch.cpp
+++ b/source/Lib/EncoderLib/InterSearch.cpp
@@ -13197,8 +13197,12 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
       const bool mtsAllowed = CU::isMTSAllowed( *tu.cu, compID );
 #endif
 #if JVET_AG0061_INTER_LFNST_NSPT
+#if JVET_AI0050_SBT_LFNST
+      const bool lfnstAllowed = CU::isLfnstAllowed(*tu.cu, compID) && cu.lfnstFlag && !tu.noResidual;
+#else
       const bool lfnstAllowed = CU::isLfnstAllowed(*tu.cu, compID) && cu.lfnstFlag;
 #endif
+#endif
 
 #if JVET_AG0061_INTER_LFNST_NSPT
       uint8_t nNumTransformCands = 0;
@@ -13213,7 +13217,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
 #endif
       std::vector<TrMode> trModes;
 #if TU_256
-      if(tu.idx != cu.firstTU->idx)
+#if JVET_AI0050_SBT_LFNST
+      if (tu.idx != cu.firstTU->idx && ((cu.sbtInfo && tu.noResidual) || !cu.sbtInfo))
+#else
+      if (tu.idx != cu.firstTU->idx)
+#endif
       {
         trModes.push_back( TrMode( cu.firstTU->mtsIdx[compID], true ) );
         nNumTransformCands = 1;
@@ -13226,7 +13234,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
           nNumTransformCands = 0;
         }
 #if JVET_AG0061_INTER_LFNST_NSPT
+#if JVET_AI0050_SBT_LFNST
+        else if (!((cu.mtsFlag || (cu.lfnstFlag && !tu.noResidual)) && compID == COMPONENT_Y))
+#else
         else if (!((cu.mtsFlag || cu.lfnstFlag) && compID == COMPONENT_Y))
+#endif
 #elif JVET_AA0133_INTER_MTS_OPT
         else if (!(cu.mtsFlag && compID == COMPONENT_Y))
 #else
@@ -13273,7 +13285,12 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
 #if JVET_AG0061_INTER_LFNST_NSPT
         if (lfnstAllowed)
         {
+#if JVET_AI0050_INTER_MTSS
+          int numMode = cu.cs->sps->getUseInterMTSS() && tu.cu->geoFlag ? 6 : 3;
+          for (int i = NUM_TRAFO_MODES_MTS; i < NUM_TRAFO_MODES_MTS + numMode; i++)   // 3 or 6 lfnst
+#else
           for (int i = NUM_TRAFO_MODES_MTS; i < NUM_TRAFO_MODES_MTS + 3; i++)   // 3 lfnst
+#endif
           {
             {
               trModes.push_back(TrMode(i, true));
@@ -13487,12 +13504,25 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
             }
 #if JVET_AG0061_INTER_LFNST_NSPT
             tu.mtsIdx[compID]   = trModes[transformMode].first < NUM_TRAFO_MODES_MTS ? trModes[transformMode].first : 0;
+#if JVET_AI0050_INTER_MTSS
+            int factor = (trModes[transformMode].first - NUM_TRAFO_MODES_MTS) / 3;
+            tu.lfnstIdx[compID] = trModes[transformMode].first < NUM_TRAFO_MODES_MTS ? 0 : trModes[transformMode].first - NUM_TRAFO_MODES_MTS - 3 * factor + 1;
+            tu.lfnstIntra[compID] = trModes[transformMode].first < (NUM_TRAFO_MODES_MTS + 3) ? 0 : (trModes[transformMode].first < (NUM_TRAFO_MODES_MTS + 6) ? 1 : 2);
+#else
             tu.lfnstIdx[compID] = trModes[transformMode].first < NUM_TRAFO_MODES_MTS
                                     ? 0
                                     : trModes[transformMode].first - NUM_TRAFO_MODES_MTS + 1;
+#endif
+#if JVET_AI0050_SBT_LFNST
+            if ((compID == COMPONENT_Y && !cu.sbtInfo) || (!tu.noResidual && compID == COMPONENT_Y && cu.sbtInfo))
+#else
             if (compID == COMPONENT_Y)
+#endif
             {
               tu.cu->lfnstIdx = tu.lfnstIdx[compID];
+#if JVET_AI0050_INTER_MTSS
+              tu.cu->lfnstIntra = tu.lfnstIntra[compID];
+#endif
             }
 #else
             tu.mtsIdx[compID] = trModes[transformMode].first;
@@ -13546,13 +13576,30 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
             if( transformMode == 0 )
             {
 #if JVET_AG0061_INTER_LFNST_NSPT
+#if JVET_AI0050_INTER_MTSS
+              m_pcTrQuant->transformNxN(tu, compID, cQP, &trModes, m_pcEncCfg->getMTSInterMaxCand() + 6);
+#else
               m_pcTrQuant->transformNxN(tu, compID, cQP, &trModes, m_pcEncCfg->getMTSInterMaxCand() + 3);
+#endif
               tu.mtsIdx[compID] = trModes[0].first < NUM_TRAFO_MODES_MTS ? trModes[0].first : 0;
+#if JVET_AI0050_INTER_MTSS
+              int factor = (trModes[0].first - NUM_TRAFO_MODES_MTS) / 3;
+              tu.lfnstIdx[compID] = trModes[0].first < NUM_TRAFO_MODES_MTS ? 0 : trModes[0].first - NUM_TRAFO_MODES_MTS - 3 * factor + 1;
+              tu.lfnstIntra[compID] = trModes[0].first < (NUM_TRAFO_MODES_MTS + 3) ? 0 : (trModes[0].first < (NUM_TRAFO_MODES_MTS + 6) ? 1 : 2);
+#else
               tu.lfnstIdx[compID] =
                 trModes[0].first < NUM_TRAFO_MODES_MTS ? 0 : trModes[0].first - NUM_TRAFO_MODES_MTS + 1;
+#endif
+#if JVET_AI0050_SBT_LFNST
+              if ((compID == COMPONENT_Y && !tu.cu->sbtInfo) || (!tu.noResidual && compID == COMPONENT_Y && tu.cu->sbtInfo))
+#else
               if (compID == COMPONENT_Y)
+#endif
               {
                 tu.cu->lfnstIdx = tu.lfnstIdx[compID];
+#if JVET_AI0050_INTER_MTSS
+                tu.cu->lfnstIntra = tu.lfnstIntra[compID];
+#endif
               }
 #else
               m_pcTrQuant->transformNxN(tu, compID, cQP, &trModes, m_pcEncCfg->getMTSInterMaxCand());
@@ -13924,7 +13971,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
 #endif
           }
 #if JVET_AG0061_INTER_LFNST_NSPT
+#if JVET_AI0050_SBT_LFNST
+          else if ((cu.mtsFlag && compID == COMPONENT_Y) || (transformMode > 0) || (cu.lfnstFlag && !tu.noResidual && compID == COMPONENT_Y))
+#else
           else if ((cu.mtsFlag && compID == COMPONENT_Y) || (transformMode > 0) || (cu.lfnstFlag && compID == COMPONENT_Y))
+#endif
 #elif JVET_AA0133_INTER_MTS_OPT
           else if ((cu.mtsFlag && compID == COMPONENT_Y) || (transformMode > 0))
 #else
@@ -14007,7 +14058,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
       if (compID == 0)
       {
 #if JVET_AG0061_INTER_LFNST_NSPT
+#if JVET_AI0050_SBT_LFNST
+        if (cu.mtsFlag || (cu.lfnstFlag && !bestTU.noResidual))
+#else
         if (cu.mtsFlag || cu.lfnstFlag)
+#endif
 #else
         if (cu.mtsFlag)
 #endif
@@ -14033,9 +14088,16 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
       // copy component
       tu.copyComponentFrom(bestTU, compID);
 #if JVET_AG0061_INTER_LFNST_NSPT
+#if JVET_AI0050_SBT_LFNST
+      if ((compID == COMPONENT_Y && !tu.cu->sbtInfo) || (!tu.noResidual && compID == COMPONENT_Y && tu.cu->sbtInfo))
+#else
       if (compID == COMPONENT_Y)
+#endif
       {
         tu.cu->lfnstIdx = tu.lfnstIdx[compID];
+#if JVET_AI0050_INTER_MTSS
+        tu.cu->lfnstIntra = tu.lfnstIntra[compID];
+#endif
       }
 #endif
       csFull->getResiBuf( compArea ).copyFrom( saveCS.getResiBuf( compArea ) );
@@ -14691,12 +14753,34 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
     else
       THROW( "Implicit TU split not available!" );
 
+#if JVET_AI0050_SBT_LFNST
+    bool isValid = false;
+#endif
     do
     {
+#if JVET_AI0050_SBT_LFNST
+      if (cu.sbtInfo)
+      {
+        bool isSubValid = false;
+        isSubValid = xEstimateInterResidualQT(*csSplit, partitioner, bCheckFull ? nullptr : puiZeroDist, luma, chroma, orgResi);
+        if (!csSplit->tus.back()->noResidual)
+        {
+          isValid = isSubValid;
+        }
+      }
+      else
+      {
+        xEstimateInterResidualQT(*csSplit, partitioner, bCheckFull ? nullptr : puiZeroDist
+          , luma, chroma
+          , orgResi
+        );
+      }
+#else
       xEstimateInterResidualQT(*csSplit, partitioner, bCheckFull ? nullptr : puiZeroDist
         , luma, chroma
         , orgResi
       );
+#endif
 
       csSplit->cost = m_pcRdCost->calcRdCost( csSplit->fracBits, csSplit->dist );
     } while( partitioner.nextPart( *csSplit ) );
@@ -14773,6 +14857,12 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
       csSplit->releaseIntermediateData();
       csFull ->releaseIntermediateData();
     }
+#if JVET_AI0050_SBT_LFNST
+    if (cu.sbtInfo)
+    {
+      return isValid;
+    }
+#endif
   }
 #if JVET_AA0133_INTER_MTS_OPT
   return true;
diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp
index 73c9ad5c6318859cb09fbf0b4fd250c39cabb95b..346021d07f138760c3aae185592172f4a0c94d17 100644
--- a/source/Lib/EncoderLib/IntraSearch.cpp
+++ b/source/Lib/EncoderLib/IntraSearch.cpp
@@ -2774,13 +2774,33 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c
                 if(modeInfo.mipTrFlg)
                 {
                   PelBuf eipSaveBuf(m_eipMergePredBuf[modeIdx], pu.Y());
-                  m_eipMergeModel[modeIdx].eipDimdMode = deriveIpmForTransform(eipSaveBuf, cu);
+#if JVET_AI0050_INTER_MTSS
+                  int secondDimdIntraDir = 0;
+#endif
+                  m_eipMergeModel[modeIdx].eipDimdMode = deriveIpmForTransform(eipSaveBuf, cu
+#if JVET_AI0050_INTER_MTSS
+                    , secondDimdIntraDir
+#endif
+                  );
+#if JVET_AI0050_INTER_MTSS
+                  cu.dimdDerivedIntraDir2nd = secondDimdIntraDir;
+#endif
                   CHECK(modeIdx >= NUM_EIP_MERGE_SIGNAL, "modeIdx >= NUM_EIP_MERGE_SIGNAL");
                 }
                 else
                 {
                   PelBuf eipSaveBuf(m_eipPredBuf[modeIdx], pu.Y());
-                  m_eipModel[modeIdx].eipDimdMode = deriveIpmForTransform(eipSaveBuf, cu);
+#if JVET_AI0050_INTER_MTSS
+                  int secondDimdIntraDir = 0;
+#endif
+                  m_eipModel[modeIdx].eipDimdMode = deriveIpmForTransform(eipSaveBuf, cu
+#if JVET_AI0050_INTER_MTSS
+                    , secondDimdIntraDir
+#endif
+                  );
+#if JVET_AI0050_INTER_MTSS
+                  cu.dimdDerivedIntraDir2nd = secondDimdIntraDir;
+#endif
                   CHECK(modeIdx >= NUM_DERIVED_EIP, "modeIdx >= NUM_DERIVED_EIP");
                 }
               }
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index e2be260307c3dd4f3b82cbdc7c9acbe2d9736e74..d6f48b26a83df345186042afdd139ef1df64bd7f 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -1287,6 +1287,12 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
   WRITE_FLAG( pcSPS->getUseIntraLFNSTISlice() ? 1 : 0, "sps_intra_lfnst_intra_slice_enabled_flag" );
   WRITE_FLAG( pcSPS->getUseIntraLFNSTPBSlice() ? 1 : 0, "sps_intra_lfnst_inter_slice_enabled_flag" );
   WRITE_FLAG( pcSPS->getUseInterLFNST() ? 1 : 0, "sps_inter_lfnst_enabled_flag" );
+#if JVET_AI0050_INTER_MTSS
+  if (pcSPS->getUseInterLFNST())
+  {
+    WRITE_FLAG(pcSPS->getUseInterMTSS() ? 1 : 0, "sps_inter_mtss_enabled_flag");
+  }
+#endif
 #else
   WRITE_FLAG(pcSPS->getUseLFNST() ? 1 : 0, "sps_lfnst_enabled_flag");
 #endif
@@ -1534,6 +1540,12 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
   }
 #endif
   WRITE_FLAG( pcSPS->getUseSBT() ? 1 : 0,                                                      "sps_sbt_enabled_flag");
+#if JVET_AI0050_SBT_LFNST
+  if (pcSPS->getUseSBT())
+  {
+    WRITE_FLAG( pcSPS->getUseSbtLFNST() ? 1 : 0,                                               "sps_sbt_lfnst_enabled_flag");
+  }
+#endif
 #if TM_AMVP || TM_MRG || JVET_Z0084_IBC_TM || MULTI_PASS_DMVR
   WRITE_FLAG( pcSPS->getUseDMVDMode() ? 1 : 0,                                                 "sps_dmvd_enabled_flag" );
 #endif