From 81e12266c817759d05a8cb33647fa68b2d4ec15f Mon Sep 17 00:00:00 2001
From: Vadim Seregin <vseregin@qti.qualcomm.com>
Date: Thu, 14 Nov 2024 15:29:20 +0000
Subject: [PATCH] JVET-AJ0260: SBT corner mode (Test 4.3a)

---
 source/.DS_Store                          | Bin 6148 -> 0 bytes
 source/Lib/.DS_Store                      | Bin 6148 -> 0 bytes
 source/Lib/CommonLib/CommonDef.h          |   4 +
 source/Lib/CommonLib/Contexts_ecm14.0.inl |  55 +++++++++++
 source/Lib/CommonLib/TrQuant.cpp          |  34 +++++++
 source/Lib/CommonLib/TypeDef.h            |  26 ++++-
 source/Lib/CommonLib/Unit.cpp             | 103 ++++++++++++++++++--
 source/Lib/CommonLib/Unit.h               |   3 +
 source/Lib/CommonLib/UnitPartitioner.cpp  |  95 ++++++++++++++++++
 source/Lib/CommonLib/UnitPartitioner.h    |  10 ++
 source/Lib/CommonLib/UnitTools.cpp        |  65 +++++++++++++
 source/Lib/DecoderLib/CABACReader.cpp     |  95 ++++++++++++++++++
 source/Lib/EncoderLib/CABACWriter.cpp     | 112 ++++++++++++++++++++++
 source/Lib/EncoderLib/EncCu.cpp           |   4 +
 source/Lib/EncoderLib/EncSlice.cpp        |  11 +++
 source/Lib/EncoderLib/InterSearch.cpp     |  85 ++++++++++++++++
 16 files changed, 690 insertions(+), 12 deletions(-)
 delete mode 100644 source/.DS_Store
 delete mode 100644 source/Lib/.DS_Store

diff --git a/source/.DS_Store b/source/.DS_Store
deleted file mode 100644
index 00be350596ca0f4a0ee2086f58497b295d59e5c7..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 6148
zcmeHKPfNov6i?iA8AIqnK|BS#4%|9W!Aq(0=E;g4RA$SD7Hc!s&K|~~A3(p5AH>h&
zdr1lodlqr;LGpWlljaA_AI2E>=i@$O4r5F}L*%H`2)b)S8#Wn{;~3dAN>l{aM>Msu
zzYh5A4R*m|7DdJP?@!_^@AW?UMx(j8)e<ey5%<B9DuO)B=b0bQZqd3@Dv2sRjIQHJ
zF>-d!RGNozI+^K$cszlWyPG&2tHM|Fbe!qhzyw5Fv`5bVVli+}y3##zmtDE&AEVLl
zxr61hEp`tMPcKK$$xEu<451wO*0OD}f_G5tdR~KBnyB;<JXLm;MMw+~1H=F^u+9wF
zQ$cjrnFLxpF+dE|GJyMogofx@EDh?d13J7uW4wuo0y@4W5T!-WVrdW}Al#G!no@3`
z7~GVDU)ns+VrkHnGp=WbaqP_1<Av+l!7p_><DNn4i2-6@m4Sva9X$Wf;g_j><gb>H
zMGO!F|BM0N90o%l7G=-YAIrnDRziD#hJtw|Dj=Y*TmrzrePmAuO<bZ5d7j16AdZ55
RT@FYW0Zj;X#K12w@CBw4NsIsh

diff --git a/source/Lib/.DS_Store b/source/Lib/.DS_Store
deleted file mode 100644
index 691e492705ea5cea1d548ce866399be2f4e2eb62..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 6148
zcmeHK%}T>S5T0$TO(;SR3gRi?wP1fh1ur43H%~_Npi&!JG?->fo0>x@<N@@Bd=Q_<
znca<8ss}G3cBagJv-6W>zm%OU00@6JXaYC@V4)J0Y#hE2ij%HL$#@8bdWM7q&LDy?
z%vQ45@fR7OcV|NfB#iL)>HST|VJt(8zJ}vCnx>7$n<$kl8=F<DYSpaU;6Y|V+D~Uw
zzdyOA*@cvGSlIpWG8$$*XS*Ylv>zqIi7JQ&Lrl53ijslMd^t-7Q&k)2fMr{D&)J*L
z+pXie+d6D5>h8RGM3ZKt)m|)YYiIx9<h=J7j}rN;2^IL?Q?g~SfEP5r*xOSuNn)AY
zW3;F&Dj1moW`G%34+hNXXVunYySz(gfEoA!19U#PsDz%uT%$TVaG=jeidP6p(5AZt
zp=;1Hm}|rciqNHqx>T4ehS25ccTJvWFxRNdL8z7SIc8;HZYV;nj(%6AgYY!+$P6$8
z%M6tD)S>==`u+WXxrk@X05kBf7!Z|i(DiXkrnjzaj(V+&dWT9vdAY`q5;RmR#$0N}
cyQoUg?~;M&8O$}J2ZcWb6b(Eu1Ha0^JF|^VEC2ui

diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h
index bee99bcb2..459b4247f 100644
--- a/source/Lib/CommonLib/CommonDef.h
+++ b/source/Lib/CommonLib/CommonDef.h
@@ -1689,6 +1689,10 @@ 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_AJ0260_SBT_CORNER_MODE
+static const int SBT_QUAD_MIN_BLOCK_SIZE =                          8;
+static const int SBT_QUARTER_MIN_BLOCK_SIZE =                      16;
+#endif
 #if JVET_AI0050_SBT_LFNST
 static const int NUM_SBT_LFNST_RDO =                                2;
 #endif
diff --git a/source/Lib/CommonLib/Contexts_ecm14.0.inl b/source/Lib/CommonLib/Contexts_ecm14.0.inl
index 2498b51ef..826ca751f 100644
--- a/source/Lib/CommonLib/Contexts_ecm14.0.inl
+++ b/source/Lib/CommonLib/Contexts_ecm14.0.inl
@@ -5189,6 +5189,33 @@ const CtxSet ContextSetCfg::SbtFlag = ContextSetCfg::addCtxSet({
 
 const CtxSet ContextSetCfg::SbtQuadFlag = ContextSetCfg::addCtxSet({
 // ctx 1453 1453
+#if JVET_AJ0260_SBT_CORNER_MODE
+// 0 - half/quarter flag
+// 1 - rectangular
+// 2 - quad
+// 3 - quarter
+
+ {  35,  35,  35,  35 },
+ {  35,  35,  35,  35 },
+ {  35,  35,  35,  35 },
+ {  50,  50,  50,  50 },
+ {  10,  10,  10,  10 },
+ {  10,  10,  10,  10 },
+ {   8,   8,   8,   8 },
+ {  10,  10,  10,  10 },
+ {   4,   4,   4,   4 },
+ {  11,  11,  11,  11 },
+ {  18,  18,  18,  18 },
+ {   4,   4,   4,   4 },
+ { 130, 130, 130, 130 },
+ { 102, 102, 102, 102 },
+ { 119, 119, 119, 119 },
+ { 100, 100, 100, 100 },
+ { 119, 119, 119, 119 },
+ { 119, 119, 119, 119 },
+ { 102, 102, 102, 102 },
+ { 100, 100, 100, 100 },
+#else
  {  35 },
  {  35 },
  {  35 },
@@ -5209,6 +5236,7 @@ const CtxSet ContextSetCfg::SbtQuadFlag = ContextSetCfg::addCtxSet({
  { 119 },
  { 102 },
  { 100 },
+#endif
 });
 
 const CtxSet ContextSetCfg::SbtHorFlag = ContextSetCfg::addCtxSet({
@@ -5237,6 +5265,32 @@ const CtxSet ContextSetCfg::SbtHorFlag = ContextSetCfg::addCtxSet({
 
 const CtxSet ContextSetCfg::SbtPosFlag = ContextSetCfg::addCtxSet({
 // ctx 1457 1457
+#if JVET_AJ0260_SBT_CORNER_MODE
+// 0 - rectangular mode (anchor)
+// 1,2 - quad
+// 3,4 - quarter
+
+ {  28,  28,  28,  28,  28 },
+ {  20,  20,  20,  20,  20 },
+ {  35,  35,  35,  35,  35 },
+ {  20,  20,  20,  20,  20 },
+ {  13,  13,  13,  13,  13 },
+ {  13,  13,  13,  13,  13 },
+ {   8,   8,   8,   8,   8 },
+ {  13,  13,  13,  13,  13 },
+ {  11,  11,  11,  11,  11 },
+ {   4,   4,   4,   4,   4 },
+ {  18,  18,  18,  18,  18 },
+ {  11,  11,  11,  11,  11 },
+ {  84,  84,  84,  84,  84 },
+ { 163, 163, 163, 163, 163 },
+ {  83,  83,  83,  83,  83 },
+ { 122, 122, 122, 122, 122 },
+ { 119, 119, 119, 119, 119 },
+ { 119, 119, 119, 119, 119 },
+ {  83,  83,  83,  83,  83 },
+ { 103, 103, 103, 103, 103 },
+#else
  {  28 },
  {  20 },
  {  35 },
@@ -5257,6 +5311,7 @@ const CtxSet ContextSetCfg::SbtPosFlag = ContextSetCfg::addCtxSet({
  { 119 },
  {  83 },
  { 103 },
+#endif
 });
 
 const CtxSet ContextSetCfg::ChromaQpAdjFlag = ContextSetCfg::addCtxSet({
diff --git a/source/Lib/CommonLib/TrQuant.cpp b/source/Lib/CommonLib/TrQuant.cpp
index d10f3a8ba..fd9f01e03 100644
--- a/source/Lib/CommonLib/TrQuant.cpp
+++ b/source/Lib/CommonLib/TrQuant.cpp
@@ -1280,6 +1280,40 @@ void TrQuant::getTrTypes(const TransformUnit tu, const ComponentID compID, int &
     uint8_t sbtIdx = tu.cu->getSbtIdx();
     uint8_t sbtPos = tu.cu->getSbtPos();
 
+#if JVET_AJ0260_SBT_CORNER_MODE
+    if( sbtIdx == SBT_QUAD || sbtIdx == SBT_QUARTER )
+    {
+      if( tu.lwidth() > MTS_INTER_MAX_CU_SIZE || tu.lheight() > MTS_INTER_MAX_CU_SIZE )
+      {
+        trTypeHor = trTypeVer = DCT2;
+      }
+      else if( sbtPos == 0 )
+      {
+        trTypeHor = DCT8;
+        trTypeVer = DCT8;
+      }
+      else if( sbtPos == 1 )
+      {
+        trTypeHor = DST7;
+        trTypeVer = DCT8;
+      }
+      else if( sbtPos == 2 )
+      {
+        trTypeHor = DCT8;
+        trTypeVer = DST7;
+      }
+      else if( sbtPos == 3 )
+      {
+        trTypeHor = DST7;
+        trTypeVer = DST7;
+      }
+      else
+      {
+        CHECK( true, "Wrong SBT QUAD position" );
+      }
+    }   
+    else
+#endif
     if( sbtIdx == SBT_VER_HALF || sbtIdx == SBT_VER_QUAD )
     {
       assert( tu.lwidth() <= MTS_INTER_MAX_CU_SIZE );
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 3d4fabef4..fc5920dc1 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -52,6 +52,7 @@
 #include <cstdint>
 
 
+
 #define BASE_ENCODER                                      1
 #define BASE_NORMATIVE                                    1
 #define TOOLS                                             1
@@ -442,11 +443,12 @@
 #define JVET_AE0125_SHIFT_QUANTIZATION_CENTER             1 // JVET-AE0125: Shifting quantization center
 #define JVET_AE0102_LFNST_CTX                             1 // JVET-AE0102: Context modelling for transform coefficients for LFNST/NSPT
 #define JVET_AG0061_INTER_LFNST_NSPT                      1 // JVET-AG0061: 3.3 Utilizing LFNST/NSPT for inter coding
-#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
+#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
+#define JVET_AJ0260_SBT_CORNER_MODE                       1 // JVET-AJ0260: Corner mode for SBT
 
 // Entropy Coding
 #define EC_HIGH_PRECISION                                 1 // CABAC high precision
@@ -1002,6 +1004,10 @@ enum SbtIdx
   SBT_HOR_HALF = 2,
   SBT_VER_QUAD = 3,
   SBT_HOR_QUAD = 4,
+#if JVET_AJ0260_SBT_CORNER_MODE
+  SBT_QUAD,
+  SBT_QUARTER,
+#endif
   NUMBER_SBT_IDX,
   SBT_OFF_MTS, //note: must be after all SBT modes, only used in fast algorithm to discern the best mode is inter EMT
 };
@@ -1023,6 +1029,16 @@ enum SbtMode
   SBT_VER_Q1 = 5,
   SBT_HOR_Q0 = 6,
   SBT_HOR_Q1 = 7,
+#if JVET_AJ0260_SBT_CORNER_MODE
+  SBT_Q0,
+  SBT_Q1,
+  SBT_Q2,
+  SBT_Q3,
+  SBT_QT0,
+  SBT_QT1,
+  SBT_QT2,
+  SBT_QT3,
+#endif
   NUMBER_SBT_MODE
 };
 
diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp
index 8140f4f0d..83b66da48 100644
--- a/source/Lib/CommonLib/Unit.cpp
+++ b/source/Lib/CommonLib/Unit.cpp
@@ -1028,8 +1028,8 @@ const uint8_t CodingUnit::checkAllowedSbt() const
   uint8_t sbtAllowed = 0;
   int cuWidth  = lwidth();
   int cuHeight = lheight();
-  bool allow_type[NUMBER_SBT_IDX];
-  memset( allow_type, false, NUMBER_SBT_IDX * sizeof( bool ) );
+  bool allowType[NUMBER_SBT_IDX];
+  memset( allowType, false, NUMBER_SBT_IDX * sizeof( bool ) );
 
   //parameter
   int maxSbtCUSize = cs->sps->getMaxTbSize();
@@ -1041,14 +1041,18 @@ const uint8_t CodingUnit::checkAllowedSbt() const
     return 0;
   }
 
-  allow_type[SBT_VER_HALF] = cuWidth  >= minSbtCUSize;
-  allow_type[SBT_HOR_HALF] = cuHeight >= minSbtCUSize;
-  allow_type[SBT_VER_QUAD] = cuWidth  >= ( minSbtCUSize << 1 );
-  allow_type[SBT_HOR_QUAD] = cuHeight >= ( minSbtCUSize << 1 );
+  allowType[SBT_VER_HALF] = cuWidth  >= minSbtCUSize;
+  allowType[SBT_HOR_HALF] = cuHeight >= minSbtCUSize;
+  allowType[SBT_VER_QUAD] = cuWidth  >= ( minSbtCUSize << 1 );
+  allowType[SBT_HOR_QUAD] = cuHeight >= ( minSbtCUSize << 1 );
+#if JVET_AJ0260_SBT_CORNER_MODE
+  allowType[ SBT_QUAD ]    = cuWidth >= minSbtCUSize && cuHeight >= minSbtCUSize && cuWidth >= SBT_QUAD_MIN_BLOCK_SIZE    && cuHeight >= SBT_QUAD_MIN_BLOCK_SIZE;
+  allowType[ SBT_QUARTER ] = cuWidth >= minSbtCUSize && cuHeight >= minSbtCUSize && cuWidth >= SBT_QUARTER_MIN_BLOCK_SIZE && cuHeight >= SBT_QUARTER_MIN_BLOCK_SIZE;
+#endif
 
   for( int i = 0; i < NUMBER_SBT_IDX; i++ )
   {
-    sbtAllowed += (uint8_t)allow_type[i] << i;
+    sbtAllowed += (uint8_t)allowType[i] << i;
   }
 
   return sbtAllowed;
@@ -1064,13 +1068,69 @@ uint8_t CodingUnit::getSbtTuSplit() const
   case SBT_HOR_HALF: sbtTuSplitType = ( getSbtPos() == SBT_POS0 ? 0 : 1 ) + SBT_HOR_HALF_POS0_SPLIT; break;
   case SBT_VER_QUAD: sbtTuSplitType = ( getSbtPos() == SBT_POS0 ? 0 : 1 ) + SBT_VER_QUAD_POS0_SPLIT; break;
   case SBT_HOR_QUAD: sbtTuSplitType = ( getSbtPos() == SBT_POS0 ? 0 : 1 ) + SBT_HOR_QUAD_POS0_SPLIT; break;
+#if JVET_AJ0260_SBT_CORNER_MODE
+  case SBT_QUAD:     sbtTuSplitType = getSbtPos() + SBT_QUAD_POSTL_SPLIT;    break;
+  case SBT_QUARTER:  sbtTuSplitType = getSbtPos() + SBT_QUARTER_POSTL_SPLIT; break;
+#endif
   default: assert( 0 );  break;
   }
 
+#if JVET_AJ0260_SBT_CORNER_MODE
+  CHECK( sbtTuSplitType < SBT_VER_HALF_POS0_SPLIT || sbtTuSplitType >= NUM_PART_SPLIT, "Wrong SBT split type" );
+#else
   assert( sbtTuSplitType <= SBT_HOR_QUAD_POS1_SPLIT && sbtTuSplitType >= SBT_VER_HALF_POS0_SPLIT );
+#endif
   return sbtTuSplitType;
 }
 
+
+#if JVET_AJ0260_SBT_CORNER_MODE
+int CodingUnit::getSbtTuIdx() const
+{
+  int idx = 0;
+
+  if( sbtInfo )
+  {
+    const int sbtIdx = getSbtIdx();
+    const int sbtPos = getSbtPos();
+
+    if( sbtIdx == SBT_QUAD )
+    {
+      idx = sbtPos;
+    }
+    else if( sbtIdx == SBT_QUARTER )
+    {
+      if( sbtPos == 0 )
+      {
+        idx = 0;
+      }
+      else if( sbtPos == 1 )
+      {
+        idx = 3;
+      }
+      else if( sbtPos == 2 )
+      {
+        idx = 12;
+      }
+      else if( sbtPos == 3 )
+      {
+        idx = 15;
+      }
+      else
+      {
+        CHECK( true, "Wrong SBT position" );
+      }
+    }
+    else
+    {
+      idx = sbtPos;
+    }
+  }
+
+  return idx;
+}
+#endif
+
 // ---------------------------------------------------------------------------
 // prediction unit method definitions
 // ---------------------------------------------------------------------------
@@ -2358,6 +2418,35 @@ void TransformUnit::checkTuNoResidual( unsigned idx )
   {
     noResidual = true;
   }
+#if JVET_AJ0260_SBT_CORNER_MODE
+  else if( CU::getSbtIdx( cu->sbtInfo ) == SBT_QUAD )
+  {
+    noResidual = CU::getSbtPos( cu->sbtInfo ) != idx ? true : false;
+  }
+  else if( CU::getSbtIdx( cu->sbtInfo ) == SBT_QUARTER )
+  {
+    if( CU::getSbtPos( cu->sbtInfo ) == 0 && idx == 0 )
+    {
+      noResidual = false;
+    }
+    else if( CU::getSbtPos( cu->sbtInfo ) == 1 && idx == 3 )
+    {
+      noResidual = false;
+    }
+    else if( CU::getSbtPos( cu->sbtInfo ) == 2 && idx == 12 )
+    {
+      noResidual = false;
+    }
+    else if( CU::getSbtPos( cu->sbtInfo ) == 3 && idx == 15 )
+    {
+      noResidual = false;
+    }
+    else
+    {
+      noResidual = true;
+    }
+  }
+#endif
 }
 
 int TransformUnit::getTbAreaAfterCoefZeroOut(ComponentID compID) const
diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h
index 2f54ebf44..26dfc9747 100644
--- a/source/Lib/CommonLib/Unit.h
+++ b/source/Lib/CommonLib/Unit.h
@@ -583,6 +583,9 @@ struct CodingUnit : public UnitArea
   const bool        isConsInter() const { return modeType == MODE_TYPE_INTER; }
   const bool        isConsIntra() const { return modeType == MODE_TYPE_INTRA; }
 #endif
+#if JVET_AJ0260_SBT_CORNER_MODE
+  int                getSbtTuIdx() const;
+#endif
 };
 
 // ---------------------------------------------------------------------------
diff --git a/source/Lib/CommonLib/UnitPartitioner.cpp b/source/Lib/CommonLib/UnitPartitioner.cpp
index 7f989dfb2..b20ef5877 100644
--- a/source/Lib/CommonLib/UnitPartitioner.cpp
+++ b/source/Lib/CommonLib/UnitPartitioner.cpp
@@ -339,6 +339,16 @@ void QTBTPartitioner::splitCurrArea( const PartSplit split, const CodingStructur
   case SBT_VER_QUAD_POS1_SPLIT:
   case SBT_HOR_QUAD_POS0_SPLIT:
   case SBT_HOR_QUAD_POS1_SPLIT:
+#if JVET_AJ0260_SBT_CORNER_MODE
+  case SBT_QUAD_POSTL_SPLIT:
+  case SBT_QUAD_POSTR_SPLIT:
+  case SBT_QUAD_POSBL_SPLIT:
+  case SBT_QUAD_POSBR_SPLIT:
+  case SBT_QUARTER_POSTL_SPLIT:
+  case SBT_QUARTER_POSTR_SPLIT:
+  case SBT_QUARTER_POSBL_SPLIT:
+  case SBT_QUARTER_POSBR_SPLIT:
+#endif
     m_partStack.push_back( PartLevel( split, PartitionerImpl::getSbtTuTiling( currArea(), cs, split ) ) );
     break;
   default:
@@ -356,7 +366,12 @@ void QTBTPartitioner::splitCurrArea( const PartSplit split, const CodingStructur
   {
     currTrDepth++;
   }
+
+#if JVET_AJ0260_SBT_CORNER_MODE
+  else if( split >= SBT_VER_HALF_POS0_SPLIT && split < NUM_PART_SPLIT )
+#else
   else if( split >= SBT_VER_HALF_POS0_SPLIT && split <= SBT_HOR_QUAD_POS1_SPLIT )
+#endif
   {
     currTrDepth++;
   }
@@ -732,6 +747,16 @@ bool QTBTPartitioner::canSplit( const PartSplit split, const CodingStructure &cs
   case SBT_VER_QUAD_POS1_SPLIT:
   case SBT_HOR_QUAD_POS0_SPLIT:
   case SBT_HOR_QUAD_POS1_SPLIT:
+#if JVET_AJ0260_SBT_CORNER_MODE
+  case SBT_QUAD_POSTL_SPLIT:
+  case SBT_QUAD_POSTR_SPLIT:
+  case SBT_QUAD_POSBL_SPLIT:
+  case SBT_QUAD_POSBR_SPLIT:
+  case SBT_QUARTER_POSTL_SPLIT:
+  case SBT_QUARTER_POSTR_SPLIT:
+  case SBT_QUARTER_POSBL_SPLIT:
+  case SBT_QUARTER_POSBR_SPLIT:
+#endif
     return currTrDepth == 0;
     break;
   case CU_QUAD_SPLIT:
@@ -866,7 +891,12 @@ void QTBTPartitioner::exitCurrSplit()
     CHECK( currTrDepth == 0, "TR depth is '0', although a TU split was performed" );
     currTrDepth--;
   }
+
+#if JVET_AJ0260_SBT_CORNER_MODE
+  else if( currSplit >= SBT_VER_HALF_POS0_SPLIT && currSplit < NUM_PART_SPLIT )
+#else
   else if( currSplit >= SBT_VER_HALF_POS0_SPLIT && currSplit <= SBT_HOR_QUAD_POS1_SPLIT )
+#endif
   {
     CHECK( currTrDepth == 0, "TR depth is '0', although a TU split was performed" );
     currTrDepth--;
@@ -1365,6 +1395,71 @@ Partitioning PartitionerImpl::getSbtTuTiling( const UnitArea& cuArea, const Codi
   Partitioning ret;
   int numTiles = 2;
   int widthFactor, heightFactor, xOffsetFactor, yOffsetFactor; // y = (x * factor) >> 2;
+
+#if JVET_AJ0260_SBT_CORNER_MODE
+  CHECK( splitType < SBT_VER_HALF_POS0_SPLIT || splitType >= NUM_PART_SPLIT, "Wrong SBT split" );
+
+  if( splitType >= SBT_QUAD_POSTL_SPLIT && splitType <= SBT_QUAD_POSBR_SPLIT )
+  {
+    // SBT QUAD restriction
+    CHECK( cuArea.lwidth() < SBT_QUAD_MIN_BLOCK_SIZE, "Width must be SBT_QUAD_MIN_BLOCK_SIZE or larger for SBT QUAD" );
+    CHECK( cuArea.lheight() < SBT_QUAD_MIN_BLOCK_SIZE, "Height must be SBT_QUAD_MIN_BLOCK_SIZE or larger for SBT QUAD" );
+
+    numTiles = 4;
+    ret.resize( numTiles, cuArea );
+    for( int i = 0; i < numTiles; i++ )
+    {
+      widthFactor = heightFactor = 2;
+      xOffsetFactor = ( i % 2 ) * 2;
+      yOffsetFactor = ( i / 2 ) * 2;
+
+      UnitArea& tile = ret[ i ];
+      for( CompArea& comp : tile.blocks )
+      {
+        if( !comp.valid() )
+        {
+          continue;
+        }
+
+        comp.x += ( comp.width * xOffsetFactor ) >> 2;
+        comp.y += ( comp.height * yOffsetFactor ) >> 2;
+        comp.width = ( comp.width * widthFactor ) >> 2;
+        comp.height = ( comp.height * heightFactor ) >> 2;
+      }
+    }
+    return ret;
+  }
+  else if( splitType >= SBT_QUARTER_POSTL_SPLIT && splitType <= SBT_QUARTER_POSBR_SPLIT )
+  {
+    // SBT QUARTER restriction
+    CHECK( cuArea.lwidth() < SBT_QUARTER_MIN_BLOCK_SIZE, "Width must be SBT_QUARTER_MIN_BLOCK_SIZE or larger for SBT QUARTER" );
+    CHECK( cuArea.lheight() < SBT_QUARTER_MIN_BLOCK_SIZE, "Height must be SBT_QUARTER_MIN_BLOCK_SIZE or larger for SBT QUARTER" );
+
+    numTiles = 16;
+    ret.resize( numTiles, cuArea );
+    for( int i = 0; i < numTiles; i++ )
+    {
+      const int x = i % 4;
+      const int y = i / 4;
+
+      UnitArea& tile = ret[ i ];
+      for( CompArea& comp : tile.blocks )
+      {
+        if( !comp.valid() )
+        {
+          continue;
+        }
+
+        comp.x += ( comp.width * x ) >> 2;
+        comp.y += ( comp.height * y ) >> 2;
+        comp.width = comp.width  >> 2;
+        comp.height = comp.height >> 2;
+      }
+    }
+    return ret;
+  }
+#endif
+
   assert( splitType >= SBT_VER_HALF_POS0_SPLIT && splitType <= SBT_HOR_QUAD_POS1_SPLIT );
 
   ret.resize( numTiles, cuArea );
diff --git a/source/Lib/CommonLib/UnitPartitioner.h b/source/Lib/CommonLib/UnitPartitioner.h
index 73ac1eb45..47503e2e7 100644
--- a/source/Lib/CommonLib/UnitPartitioner.h
+++ b/source/Lib/CommonLib/UnitPartitioner.h
@@ -74,6 +74,16 @@ enum PartSplit
   SBT_VER_QUAD_POS1_SPLIT,
   SBT_HOR_QUAD_POS0_SPLIT,
   SBT_HOR_QUAD_POS1_SPLIT,
+#if JVET_AJ0260_SBT_CORNER_MODE
+  SBT_QUAD_POSTL_SPLIT,
+  SBT_QUAD_POSTR_SPLIT,
+  SBT_QUAD_POSBL_SPLIT,
+  SBT_QUAD_POSBR_SPLIT,
+  SBT_QUARTER_POSTL_SPLIT,
+  SBT_QUARTER_POSTR_SPLIT,
+  SBT_QUARTER_POSBL_SPLIT,
+  SBT_QUARTER_POSBR_SPLIT,
+#endif
   NUM_PART_SPLIT,
   CU_MT_SPLIT             = 1000, ///< dummy element to indicate the MT (multi-type-tree) split
   CU_BT_SPLIT             = 1001, ///< dummy element to indicate the BT split
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 64f18539c..3aaf19e2a 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -31942,6 +31942,10 @@ uint8_t CU::getSbtMode( uint8_t sbtIdx, uint8_t sbtPos )
   case SBT_HOR_HALF: sbtMode = sbtPos + SBT_HOR_H0;  break;
   case SBT_VER_QUAD: sbtMode = sbtPos + SBT_VER_Q0;  break;
   case SBT_HOR_QUAD: sbtMode = sbtPos + SBT_HOR_Q0;  break;
+#if JVET_AJ0260_SBT_CORNER_MODE
+  case SBT_QUAD:     sbtMode = sbtPos + SBT_Q0;  break;
+  case SBT_QUARTER:  sbtMode = sbtPos + SBT_QT0;  break;
+#endif
   default:           assert( 0 );
   }
 
@@ -31967,6 +31971,16 @@ uint8_t CU::getSbtIdxFromSbtMode( uint8_t sbtMode )
   {
     return SBT_HOR_QUAD;
   }
+#if JVET_AJ0260_SBT_CORNER_MODE
+  else if( sbtMode <= SBT_Q3 )
+  {
+    return SBT_QUAD;
+  }
+  else if( sbtMode <= SBT_QT3 )
+  {
+    return SBT_QUARTER;
+  }
+#endif
   else
   {
     assert( 0 );
@@ -31992,6 +32006,16 @@ uint8_t CU::getSbtPosFromSbtMode( uint8_t sbtMode )
   {
     return sbtMode - SBT_HOR_Q0;
   }
+#if JVET_AJ0260_SBT_CORNER_MODE
+  else if( sbtMode <= SBT_Q3 )
+  {
+    return sbtMode - SBT_Q0;
+  }
+  else if( sbtMode <= SBT_QT3 )
+  {
+    return sbtMode - SBT_QT0;
+  }
+#endif
   else
   {
     assert( 0 );
@@ -32008,6 +32032,10 @@ uint8_t CU::targetSbtAllowed( uint8_t sbtIdx, uint8_t sbtAllowed )
   case SBT_HOR_HALF: val = ( ( sbtAllowed >> SBT_HOR_HALF ) & 0x1 ); break;
   case SBT_VER_QUAD: val = ( ( sbtAllowed >> SBT_VER_QUAD ) & 0x1 ); break;
   case SBT_HOR_QUAD: val = ( ( sbtAllowed >> SBT_HOR_QUAD ) & 0x1 ); break;
+#if JVET_AJ0260_SBT_CORNER_MODE
+  case SBT_QUAD:     val = ( ( sbtAllowed >> SBT_QUAD )     & 0x1 ); break;
+  case SBT_QUARTER:  val = ( ( sbtAllowed >> SBT_QUARTER )  & 0x1 ); break;
+#endif
   default:           CHECK( 1, "unknown SBT type" );
   }
   return val;
@@ -32019,15 +32047,29 @@ uint8_t CU::numSbtModeRdo( uint8_t sbtAllowed )
   uint8_t sum = 0;
   num = targetSbtAllowed( SBT_VER_HALF, sbtAllowed ) + targetSbtAllowed( SBT_HOR_HALF, sbtAllowed );
   sum += std::min( SBT_NUM_RDO, ( num << 1 ) );
+
+#if JVET_AJ0260_SBT_CORNER_MODE
+  num = ( ( targetSbtAllowed( SBT_VER_QUAD, sbtAllowed ) + targetSbtAllowed( SBT_HOR_QUAD, sbtAllowed ) ) << 1 ) + ( CU::targetSbtAllowed( SBT_QUAD, sbtAllowed ) << 2 );
+  sum += std::min<uint8_t>( SBT_NUM_RDO, num );
+
+  num = targetSbtAllowed( SBT_QUARTER, sbtAllowed );
+  sum += std::min( SBT_NUM_RDO, ( num << 2 ) );
+#else
   num = targetSbtAllowed( SBT_VER_QUAD, sbtAllowed ) + targetSbtAllowed( SBT_HOR_QUAD, sbtAllowed );
   sum += std::min( SBT_NUM_RDO, ( num << 1 ) );
+#endif
+
   return sum;
 }
 
 bool CU::isSbtMode( const uint8_t sbtInfo )
 {
   uint8_t sbtIdx = getSbtIdx( sbtInfo );
+#if JVET_AJ0260_SBT_CORNER_MODE
+  return sbtIdx >= SBT_VER_HALF && sbtIdx < NUMBER_SBT_IDX;
+#else
   return sbtIdx >= SBT_VER_HALF && sbtIdx <= SBT_HOR_QUAD;
+#endif
 }
 #if JVET_AI0050_SBT_LFNST
 void CU::getSBTPosAndSize(const CodingUnit &cu, Position& pos, Size& size, uint8_t sbtMode)
@@ -32042,6 +32084,16 @@ void CU::getSBTPosAndSize(const CodingUnit &cu, Position& pos, Size& size, uint8
   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;
+#if JVET_AJ0260_SBT_CORNER_MODE
+  case SBT_Q0:  pos = Position( 0, 0 );  size = Size( cu.lwidth() >> 1, cu.lheight() >> 1 );  break;
+  case SBT_Q1:  pos = Position( cu.lwidth() >> 1, 0 );  size = Size( cu.lwidth() >> 1, cu.lheight() >> 1 );  break;
+  case SBT_Q2:  pos = Position( 0, cu.lheight() >> 1 );  size = Size( cu.lwidth() >> 1, cu.lheight() >> 1 );  break;
+  case SBT_Q3:  pos = Position( cu.lwidth() >> 1, cu.lheight() >> 1 );  size = Size( cu.lwidth() >> 1, cu.lheight() >> 1 );  break;
+  case SBT_QT0: pos = Position( 0, 0 );  size = Size( cu.lwidth() >> 2, cu.lheight() >> 2 );  break;
+  case SBT_QT1: pos = Position( 3 * cu.lwidth() >> 2, 0 );  size = Size( cu.lwidth() >> 2, cu.lheight() >> 2 );  break;
+  case SBT_QT2: pos = Position( 0, 3 * cu.lheight() >> 2 );  size = Size( cu.lwidth() >> 2, cu.lheight() >> 2 );  break;
+  case SBT_QT3: pos = Position( 3 * cu.lwidth() >> 2, 3 * cu.lheight() >> 2 );  size = Size( cu.lwidth() >> 2, cu.lheight() >> 2 );  break;
+#endif
   default:           assert(0);
   }
 }
@@ -32054,10 +32106,23 @@ bool CU::isSameSbtSize( const uint8_t sbtInfo1, const uint8_t sbtInfo2 )
   {
     return sbtIdx2 == SBT_HOR_HALF || sbtIdx2 == SBT_VER_HALF;
   }
+#if JVET_AJ0260_SBT_CORNER_MODE
+  else if( sbtIdx1 == SBT_VER_QUAD || sbtIdx1 == SBT_HOR_QUAD || sbtIdx1 == SBT_QUAD )
+  {
+    const bool isSame = sbtIdx2 == SBT_VER_QUAD || sbtIdx2 == SBT_HOR_QUAD || sbtIdx2 == SBT_QUAD;
+
+    return isSame;
+  }
+  else if( sbtIdx1 == SBT_QUARTER )
+  {
+    return sbtIdx2 == SBT_QUARTER;
+  }
+#else
   else if( sbtIdx1 == SBT_HOR_QUAD || sbtIdx1 == SBT_VER_QUAD )
   {
     return sbtIdx2 == SBT_HOR_QUAD || sbtIdx2 == SBT_VER_QUAD;
   }
+#endif
   else
   {
     return false;
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index 03972d32e..75237a09a 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -3721,6 +3721,78 @@ void CABACReader::sbt_mode( CodingUnit& cu )
   uint8_t sbtVerQuadAllow = CU::targetSbtAllowed( SBT_VER_QUAD, sbtAllowed );
   uint8_t sbtHorQuadAllow = CU::targetSbtAllowed( SBT_HOR_QUAD, sbtAllowed );
 
+#if JVET_AJ0260_SBT_CORNER_MODE
+  const uint8_t sbtQuadModeAllowed = CU::targetSbtAllowed( SBT_QUAD, sbtAllowed );
+  const uint8_t sbtQuarterModeAllowed = CU::targetSbtAllowed( SBT_QUARTER, sbtAllowed );
+
+  auto sbtQuadMode = [&]( const bool isLast, int& modeIdx )
+  {
+    if( sbtQuadModeAllowed )
+    {
+      modeIdx++;
+
+      CHECK( !sbtVerHalfAllow && !sbtHorHalfAllow, "Wrong SBT QUAD setting");
+
+      // SBT QUAD restriction
+      CHECK( cuWidth < SBT_QUAD_MIN_BLOCK_SIZE, "Width must be SBT_QUAD_MIN_BLOCK_SIZE or larger for SBT QUAD" );
+      CHECK( cuHeight < SBT_QUAD_MIN_BLOCK_SIZE, "Height must be SBT_QUAD_MIN_BLOCK_SIZE or larger for SBT QUAD" );
+
+      bool sbtQuad = isLast ? true : m_BinDecoder.decodeBin( Ctx::SbtQuadFlag( 2 ) );
+
+      if( sbtQuad )
+      {
+        cu.setSbtIdx( SBT_QUAD );
+        //pos
+        uint8_t horIdx = m_BinDecoder.decodeBin( Ctx::SbtPosFlag( 1 ) );
+        uint8_t verIdx = m_BinDecoder.decodeBin( Ctx::SbtPosFlag( 2 ) );
+        cu.setSbtPos( ( verIdx << 1 ) + horIdx );
+        DTRACE( g_trace_ctx, D_SYNTAX, "sbt_mode() pos=(%d,%d) sbtInfo=%d\n", cu.lx(), cu.ly(), ( int ) cu.sbtInfo );
+        return true;
+      }
+    }
+
+    return false;
+  };
+
+  auto sbtQuarterMode = [&]( const bool isLast, int& modeIdx )
+  {
+    if( sbtQuarterModeAllowed )
+    {
+      modeIdx++;
+
+      // SBT QUARTER restriction
+      CHECK( cuWidth < SBT_QUAD_MIN_BLOCK_SIZE, "Width must be SBT_QUAD_MIN_BLOCK_SIZE or larger for SBT QUAD" );
+      CHECK( cuHeight < SBT_QUAD_MIN_BLOCK_SIZE, "Height must be SBT_QUAD_MIN_BLOCK_SIZE or larger for SBT QUAD" );
+
+      bool bSbtQuarter = isLast ? true : m_BinDecoder.decodeBin( Ctx::SbtQuadFlag( 3 ) );
+
+      if( bSbtQuarter )
+      {
+        cu.setSbtIdx( SBT_QUARTER );
+        //pos
+        uint8_t horIdx = m_BinDecoder.decodeBin( Ctx::SbtPosFlag( 3 ) );
+        uint8_t verIdx = m_BinDecoder.decodeBin( Ctx::SbtPosFlag( 4 ) );
+        cu.setSbtPos( ( verIdx << 1 ) + horIdx );
+        DTRACE( g_trace_ctx, D_SYNTAX, "sbt_mode() pos=(%d,%d) sbtInfo=%d\n", cu.lx(), cu.ly(), ( int ) cu.sbtInfo );
+        return true;
+      }
+    }
+
+    return false;
+  };
+
+  auto sbtRectMode = [&]( const bool isLast, int& modeIdx )
+  {
+    modeIdx++;
+
+    const bool sbtRect = isLast ? true : m_BinDecoder.decodeBin( Ctx::SbtQuadFlag( 1 ) );
+
+    if( !sbtRect )
+    {
+      return false;
+    }
+#endif
+
   //bin - type
   bool sbtQuadFlag = false;
   if( ( sbtHorHalfAllow || sbtVerHalfAllow ) && ( sbtHorQuadAllow || sbtVerQuadAllow ) )
@@ -3750,6 +3822,29 @@ void CABACReader::sbt_mode( CodingUnit& cu )
   cu.setSbtPos( sbtPosFlag ? SBT_POS1 : SBT_POS0 );
 
   DTRACE( g_trace_ctx, D_SYNTAX, "sbt_mode() pos=(%d,%d) sbt_info=%d\n", cu.lx(), cu.ly(), (int)cu.sbtInfo );
+
+#if JVET_AJ0260_SBT_CORNER_MODE
+  return true;
+
+  };
+
+  int numSbtModesM1 = 1 - ( ( sbtVerHalfAllow + sbtHorHalfAllow + sbtVerQuadAllow + sbtHorQuadAllow ) ? 1 : 0 ) + ( sbtQuadModeAllowed ? 1 : 0 ) + ( sbtQuarterModeAllowed ? 1 : 0 );
+
+  int modeIdx = 0;
+
+  if( sbtRectMode( modeIdx == numSbtModesM1, modeIdx ) )
+  {
+    return;
+  }
+  else if( sbtQuadMode( modeIdx == numSbtModesM1, modeIdx ) )
+  {
+    return;
+  }
+  else if( sbtQuarterMode( modeIdx == numSbtModesM1, modeIdx ) )
+  {
+    return;
+  }
+#endif
 }
 
 
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index 137ebf1a8..e3bdcaa02 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -3558,6 +3558,94 @@ void CABACWriter::sbt_mode( const CodingUnit& cu )
   uint8_t sbtHorHalfAllow = CU::targetSbtAllowed( SBT_HOR_HALF, sbtAllowed );
   uint8_t sbtVerQuadAllow = CU::targetSbtAllowed( SBT_VER_QUAD, sbtAllowed );
   uint8_t sbtHorQuadAllow = CU::targetSbtAllowed( SBT_HOR_QUAD, sbtAllowed );
+
+#if JVET_AJ0260_SBT_CORNER_MODE
+  const uint8_t sbtQuadModeAllowed = CU::targetSbtAllowed( SBT_QUAD, sbtAllowed );
+  const uint8_t sbtQuarterModeAllowed = CU::targetSbtAllowed( SBT_QUARTER, sbtAllowed );
+
+  auto sbtQuadMode = [&]( const bool isLast, int& modeIdx )
+  {
+    if( sbtQuadModeAllowed )
+    {
+      modeIdx++;
+
+      const bool bSbtQuad = sbtIdx == SBT_QUAD;
+
+      CHECK( !sbtVerHalfAllow && !sbtHorHalfAllow, "Wrong SBT QUAD setting" );
+
+      // SBT QUAD restriction
+      CHECK( cuWidth < SBT_QUAD_MIN_BLOCK_SIZE, "Width must be SBT_QUAD_MIN_BLOCK_SIZE or larger for SBT QUAD" );
+      CHECK( cuHeight < SBT_QUAD_MIN_BLOCK_SIZE, "Height must be SBT_QUAD_MIN_BLOCK_SIZE or larger for SBT QUAD" );
+
+      if( !isLast )
+      {
+        m_BinEncoder.encodeBin( bSbtQuad, Ctx::SbtQuadFlag( 2 ) );
+      }
+
+      if( bSbtQuad )
+      {
+        //pos
+        uint8_t horIdx = ( sbtPos >> 0 ) & 0x1;
+        uint8_t verIdx = ( sbtPos >> 1 ) & 0x1;
+        m_BinEncoder.encodeBin( horIdx, Ctx::SbtPosFlag( 1 ) );
+        m_BinEncoder.encodeBin( verIdx, Ctx::SbtPosFlag( 2 ) );
+        DTRACE( g_trace_ctx, D_SYNTAX, "sbt_mode() pos=(%d,%d) sbtInfo=%d\n", cu.lx(), cu.ly(), ( int ) cu.sbtInfo );
+        return true;
+      }
+    }
+
+    return false;
+  };
+
+  auto sbtQuarterMode = [&]( const bool isLast, int& modeIdx )
+  {
+    if( sbtQuarterModeAllowed )
+    {
+      modeIdx++;
+
+      const bool bSbtQuarter = sbtIdx == SBT_QUARTER;
+
+      // SBT QUARTER restriction
+      CHECK( cuWidth < SBT_QUARTER_MIN_BLOCK_SIZE, "Width must be SBT_QUARTER_MIN_BLOCK_SIZE or larger for SBT QUARTER" );
+      CHECK( cuHeight < SBT_QUARTER_MIN_BLOCK_SIZE, "Height must be SBT_QUARTER_MIN_BLOCK_SIZE or larger for SBT QUARTER" );
+
+      if( !isLast )
+      {
+        m_BinEncoder.encodeBin( bSbtQuarter, Ctx::SbtQuadFlag( 3 ) );
+      }
+
+      if( bSbtQuarter )
+      {
+        //pos
+        uint8_t horIdx = ( sbtPos >> 0 ) & 0x1;
+        uint8_t verIdx = ( sbtPos >> 1 ) & 0x1;
+        m_BinEncoder.encodeBin( horIdx, Ctx::SbtPosFlag( 3 ) );
+        m_BinEncoder.encodeBin( verIdx, Ctx::SbtPosFlag( 4 ) );
+        DTRACE( g_trace_ctx, D_SYNTAX, "sbt_mode() pos=(%d,%d) sbtInfo=%d\n", cu.lx(), cu.ly(), ( int ) cu.sbtInfo );
+        return true;
+      }
+    }
+
+    return false;
+  };
+
+  auto sbtRectMode = [&]( const bool isLast, int& modeIdx )
+  {
+    modeIdx++;
+
+    const bool sbtRect = sbtIdx <= SBT_HOR_QUAD;
+
+    if( !isLast )
+    {
+      m_BinEncoder.encodeBin( sbtRect, Ctx::SbtQuadFlag( 1 ) );
+    }
+
+    if( !sbtRect )
+    {
+      return false;
+    }
+#endif
+
   //bin - type
   if( ( sbtHorHalfAllow || sbtVerHalfAllow ) && ( sbtHorQuadAllow || sbtVerQuadAllow ) )
   {
@@ -3583,6 +3671,29 @@ void CABACWriter::sbt_mode( const CodingUnit& cu )
   m_BinEncoder.encodeBin( sbtPosFlag, Ctx::SbtPosFlag( 0 ) );
 
   DTRACE( g_trace_ctx, D_SYNTAX, "sbt_mode() pos=(%d,%d) sbt_info=%d\n", cu.lx(), cu.ly(), (int)cu.sbtInfo );
+
+#if JVET_AJ0260_SBT_CORNER_MODE
+  return true;
+
+  };
+
+  int numSbtModesM1 = 1 - ( ( sbtVerHalfAllow + sbtHorHalfAllow + sbtVerQuadAllow + sbtHorQuadAllow ) ? 1 : 0 ) + ( sbtQuadModeAllowed ? 1 : 0 ) + ( sbtQuarterModeAllowed ? 1 : 0 );
+
+  int modeIdx = 0;
+
+  if( sbtRectMode( modeIdx == numSbtModesM1, modeIdx ) )
+  {
+    return;
+  }
+  else if( sbtQuadMode( modeIdx == numSbtModesM1, modeIdx ) )
+  {
+    return;
+  }
+  else if( sbtQuarterMode( modeIdx == numSbtModesM1, modeIdx ) )
+  {
+    return;
+  }
+#endif
 }
 
 void CABACWriter::end_of_ctu( const CodingUnit& cu, CUCtx& cuCtx )
@@ -9476,6 +9587,7 @@ void CABACWriter::residual_lfnst_mode( const CodingUnit& cu, CUCtx& cuCtx )
   {
     uint32_t idxLFNST = cu.lfnstIdx;
     assert(idxLFNST < 4);
+
     m_BinEncoder.encodeBin(idxLFNST > 0, Ctx::InterLFNSTIdx(0));
     if (idxLFNST > 0)
     {
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 6e8558062..b826a8c45 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -25193,7 +25193,11 @@ void EncCu::xEncodeInterResidual(   CodingStructure *&tempCS
           if (tempCS->cost < currBestCost)
           {
             currBestSbt = cu->sbtInfo;
+#if JVET_AJ0260_SBT_CORNER_MODE
+            currBestTrs = tempCS->tus[cu->getSbtTuIdx()]->mtsIdx[COMPONENT_Y];
+#else
             currBestTrs = tempCS->tus[cu->sbtInfo ? cu->getSbtPos() : 0]->mtsIdx[COMPONENT_Y];
+#endif
             assert(currBestTrs == 0 || currBestTrs == 1);
             currBestCost = tempCS->cost;
           }
diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp
index 305a7379e..95cbbf76a 100644
--- a/source/Lib/EncoderLib/EncSlice.cpp
+++ b/source/Lib/EncoderLib/EncSlice.cpp
@@ -2111,6 +2111,17 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons
     }
   }
 #endif
+#if JVET_AJ0260_SBT_CORNER_MODE
+  if( m_pcCuEncoder->getEncCfg()->getUseSBT() )
+  {
+    if( cs.slice->getPOC() == 0 || cs.slice->getSliceType() == I_SLICE ) // ensure sequential and parallel simulation generate same output
+    {
+      hashBlkHitPerc = hashBlkHitPerc == -1 ? m_pcCuEncoder->getIbcHashMap().calHashBlkMatchPerc( cs.area.Y() ) : hashBlkHitPerc;
+      bool isSCC = hashBlkHitPerc >= 20;
+      m_pcCuEncoder->getEncCfg()->setSBTFast64WidthTh( isSCC ? 1920 : 0 );
+    }
+  }
+#endif
 
 #if JVET_AJ0057_HL_INTRA_METHOD_CONTROL
   if (m_pcCuEncoder->getEncCfg()->getIntraToolControlMode() == 0)
diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp
index 3adf360af..f4824391e 100644
--- a/source/Lib/EncoderLib/InterSearch.cpp
+++ b/source/Lib/EncoderLib/InterSearch.cpp
@@ -12891,10 +12891,17 @@ void InterSearch::calcMinDistSbt( CodingStructure &cs, const CodingUnit& cu, con
   //                         if this cost is larger than the best cost, no need to try a specific SBT mode
   int cuWidth  = cu.lwidth();
   int cuHeight = cu.lheight();
+#if JVET_AJ0260_SBT_CORNER_MODE
+  const int numPartX = cuWidth  >= 8 ? 4 : 1;
+  const int numPartY = cuHeight >= 8 ? 4 : 1;
+
+  std::vector<std::vector<Distortion>> dist( numPartY, std::vector<Distortion>( numPartX, 0 ));
+#else
   int numPartX = cuWidth  >= 16 ? 4 : ( cuWidth  == 4 ? 1 : 2 );
   int numPartY = cuHeight >= 16 ? 4 : ( cuHeight == 4 ? 1 : 2 );
   Distortion dist[4][4];
   memset( dist, 0, sizeof( Distortion ) * 16 );
+#endif
 
   for( uint32_t c = 0; c < getNumberValidTBlocks( *cs.pcv ); c++ )
   {
@@ -13027,6 +13034,48 @@ void InterSearch::calcMinDistSbt( CodingStructure &cs, const CodingUnit& cu, con
     m_estMinDistSbt[SBT_HOR_Q1] = m_estMinDistSbt[SBT_HOR_Q1] >> shift;
   }
 
+#if JVET_AJ0260_SBT_CORNER_MODE
+  if( CU::targetSbtAllowed( SBT_QUAD, sbtAllowed ) )
+  {
+    m_estMinDistSbt[ SBT_Q0 ] = m_estMinDistSbt[ SBT_Q1 ] = m_estMinDistSbt[ SBT_Q2 ] = m_estMinDistSbt[ SBT_Q3 ] = 0;
+
+    for( int j = 0; j < numPartY / 2; j++ )
+    {
+      for( int i = 0; i < numPartX / 2; i++ )
+      {
+        m_estMinDistSbt[ SBT_Q0 ] += dist[ j ][ i ];
+        m_estMinDistSbt[ SBT_Q1 ] += dist[ j ][ i + ( numPartX >> 1 ) ];
+        m_estMinDistSbt[ SBT_Q2 ] += dist[ j + ( numPartY >> 1 ) ][ i ];
+        m_estMinDistSbt[ SBT_Q3 ] += dist[ j + ( numPartY >> 1 ) ][ i + ( numPartX >> 1 ) ];
+      }
+    }
+    m_estMinDistSbt[ SBT_Q0 ] = ( m_estMinDistSbt[ NUMBER_SBT_MODE ] - m_estMinDistSbt[ SBT_Q0 ] ) + ( m_estMinDistSbt[ SBT_Q0 ] >> shift );
+    m_estMinDistSbt[ SBT_Q1 ] = ( m_estMinDistSbt[ NUMBER_SBT_MODE ] - m_estMinDistSbt[ SBT_Q1 ] ) + ( m_estMinDistSbt[ SBT_Q1 ] >> shift );
+    m_estMinDistSbt[ SBT_Q2 ] = ( m_estMinDistSbt[ NUMBER_SBT_MODE ] - m_estMinDistSbt[ SBT_Q2 ] ) + ( m_estMinDistSbt[ SBT_Q2 ] >> shift );
+    m_estMinDistSbt[ SBT_Q3 ] = ( m_estMinDistSbt[ NUMBER_SBT_MODE ] - m_estMinDistSbt[ SBT_Q3 ] ) + ( m_estMinDistSbt[ SBT_Q3 ] >> shift );
+  }
+
+  if( CU::targetSbtAllowed( SBT_QUARTER, sbtAllowed ) )
+  {
+    m_estMinDistSbt[ SBT_QT0 ] = m_estMinDistSbt[ SBT_QT1 ] = m_estMinDistSbt[ SBT_QT2 ] = m_estMinDistSbt[ SBT_QT3 ] = 0;
+
+    for( int j = 0; j < numPartY / 4; j++ )
+    {
+      for( int i = 0; i < numPartX / 4; i++ )
+      {
+        m_estMinDistSbt[ SBT_QT0 ] += dist[ j ][ i ];
+        m_estMinDistSbt[ SBT_QT1 ] += dist[ j ][ i + ( 3 * numPartX >> 2 ) ];
+        m_estMinDistSbt[ SBT_QT2 ] += dist[ j + ( 3 * numPartY >> 2 ) ][ i ];
+        m_estMinDistSbt[ SBT_QT3 ] += dist[ j + ( 3 * numPartY >> 2 ) ][ i + ( 3 * numPartX >> 2 ) ];
+      }
+    }
+    m_estMinDistSbt[ SBT_QT0 ] = ( m_estMinDistSbt[ NUMBER_SBT_MODE ] - m_estMinDistSbt[ SBT_QT0 ] ) + ( m_estMinDistSbt[ SBT_QT0 ] >> shift );
+    m_estMinDistSbt[ SBT_QT1 ] = ( m_estMinDistSbt[ NUMBER_SBT_MODE ] - m_estMinDistSbt[ SBT_QT1 ] ) + ( m_estMinDistSbt[ SBT_QT1 ] >> shift );
+    m_estMinDistSbt[ SBT_QT2 ] = ( m_estMinDistSbt[ NUMBER_SBT_MODE ] - m_estMinDistSbt[ SBT_QT2 ] ) + ( m_estMinDistSbt[ SBT_QT2 ] >> shift );
+    m_estMinDistSbt[ SBT_QT3 ] = ( m_estMinDistSbt[ NUMBER_SBT_MODE ] - m_estMinDistSbt[ SBT_QT3 ] ) + ( m_estMinDistSbt[ SBT_QT3 ] >> shift );
+  }
+#endif
+
   //SBT fast algorithm 5: try N SBT modes with the lowest distortion
   Distortion temp[NUMBER_SBT_MODE];
   memcpy( temp, m_estMinDistSbt, sizeof( Distortion ) * NUMBER_SBT_MODE );
@@ -13049,13 +13098,29 @@ void InterSearch::calcMinDistSbt( CodingStructure &cs, const CodingUnit& cu, con
   }
 
   startIdx += numRDO;
+#if JVET_AJ0260_SBT_CORNER_MODE
+  numRDO = ( ( CU::targetSbtAllowed( SBT_VER_QUAD, sbtAllowed ) + CU::targetSbtAllowed( SBT_HOR_QUAD, sbtAllowed ) ) << 1 ) + ( CU::targetSbtAllowed( SBT_QUAD, sbtAllowed ) << 2 );
+  numRDO = std::min( numRDO, SBT_NUM_RDO );
+#else
   numRDO = CU::targetSbtAllowed( SBT_VER_QUAD, sbtAllowed ) + CU::targetSbtAllowed( SBT_HOR_QUAD, sbtAllowed );
   numRDO = std::min( ( numRDO << 1 ), SBT_NUM_RDO );
+#endif
+
   for( int i = startIdx; i < startIdx + numRDO; i++ )
   {
     Distortion minDist = std::numeric_limits<uint64_t>::max();
+
+#if JVET_AJ0260_SBT_CORNER_MODE
+    for( int n = SBT_VER_Q0; n < NUMBER_SBT_MODE; n++ )
+    {
+      if( n >= SBT_QT0 && n <= SBT_QT3 )
+      {
+        continue;
+      }
+#else
     for( int n = SBT_VER_Q0; n <= SBT_HOR_Q1; n++ )
     {
+#endif
       if( temp[n] < minDist )
       {
         minDist = temp[n];
@@ -13064,6 +13129,26 @@ void InterSearch::calcMinDistSbt( CodingStructure &cs, const CodingUnit& cu, con
     }
     temp[m_sbtRdoOrder[i]] = std::numeric_limits<uint64_t>::max();
   }
+
+#if JVET_AJ0260_SBT_CORNER_MODE
+  startIdx += numRDO;
+  numRDO = CU::targetSbtAllowed( SBT_QUARTER, sbtAllowed );
+  numRDO = std::min( ( numRDO << 2 ), SBT_NUM_RDO );
+
+  for( int i = startIdx; i < startIdx + numRDO; i++ )
+  {
+    Distortion minDist = std::numeric_limits<uint64_t>::max();
+    for( int n = SBT_QT0; n <= SBT_QT3; n++ )
+    {
+      if( temp[ n ] < minDist )
+      {
+        minDist = temp[ n ];
+        m_sbtRdoOrder[ i ] = n;
+      }
+    }
+    temp[ m_sbtRdoOrder[ i ] ] = std::numeric_limits<uint64_t>::max();
+  }
+#endif
 }
 
 uint8_t InterSearch::skipSbtByRDCost( int width, int height, int mtDepth, uint8_t sbtIdx, uint8_t sbtPos, double bestCost, Distortion distSbtOff, double costSbtOff, bool rootCbfSbtOff )
-- 
GitLab