From 7f07b046473061c737db1020591c767381b855cf Mon Sep 17 00:00:00 2001
From: Waqas Ahmad <waqas.ahmad@ericsson.com>
Date: Thu, 27 Jul 2023 10:08:23 +0200
Subject: [PATCH] JVET-AE0057: MTT split modes early termination

The proposal JVET-AE0057 is implemented under the define JVET_AE0057_MTT_ET in VTM software. A config file parameter (MTTSkipping) is also added to turn on or off the MTT early termination. The 64x64 luma CU no-split intra RD cost is compared against a threshold to decide whether to evaluate MTT splitting for current 64x64 luma CU.
---
 source/App/EncoderApp/EncApp.cpp      |  3 +++
 source/App/EncoderApp/EncAppCfg.cpp   |  3 +++
 source/App/EncoderApp/EncAppCfg.h     |  3 +++
 source/Lib/CommonLib/TypeDef.h        |  2 ++
 source/Lib/EncoderLib/EncCfg.h        |  8 +++++++
 source/Lib/EncoderLib/EncCu.cpp       | 25 ++++++++++++++++++++++
 source/Lib/EncoderLib/EncModeCtrl.cpp | 30 +++++++++++++++++++++++++++
 source/Lib/EncoderLib/EncModeCtrl.h   |  6 ++++++
 8 files changed, 80 insertions(+)

diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 5f6661305..615698d3e 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -865,6 +865,9 @@ void EncApp::xInitLibCfg( int layerIdx )
   m_cEncLib.setFastAdaptCostPredMode                             (m_fastAdaptCostPredMode);
   m_cEncLib.setDisableFastDecisionTT                             (m_disableFastDecisionTT);
 
+#if JVET_AE0057_MTT_ET 
+  m_cEncLib.setUseMttSkip                                        (m_useMttSkip);
+#endif
   // set internal bit-depth and constants
   for (const auto channelType: { ChannelType::LUMA, ChannelType::CHROMA })
   {
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index c17b69a2d..e76406e63 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -1082,6 +1082,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ("PBIntraFast",                                     m_usePbIntraFast,                                 false, "Fast assertion if the intra mode is probable")
   ("AMaxBT",                                          m_useAMaxBT,                                      false, "Adaptive maximal BT-size")
   ("E0023FastEnc",                                    m_e0023FastEnc,                                    true, "Fast encoding setting for QTBT (proposal E0023)")
+#if JVET_AE0057_MTT_ET
+  ("MTTSkipping",                                     m_useMttSkip,                                     false, "MTT split modes early termination (proposal JVET-AE0057)")
+#endif  
   ("ContentBasedFastQtbt",                            m_contentBasedFastQtbt,                           false, "Signal based QTBT speed-up")
   ("UseNonLinearAlfLuma",                             m_useNonLinearAlfLuma,                             true, "Non-linear adaptive loop filters for Luma Channel")
   ("UseNonLinearAlfChroma",                           m_useNonLinearAlfChroma,                           true, "Non-linear adaptive loop filters for Chroma Channels")
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index f394845be..494c39a4d 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -418,6 +418,9 @@ protected:
   unsigned              m_maxCuHeight;                                     ///< max. CU height in pixel
   unsigned m_log2MinCuSize;                                   ///< min. CU size log2
 
+#if JVET_AE0057_MTT_ET
+  bool      m_useMttSkip;
+#endif
   bool      m_useFastLCTU;
   bool      m_usePbIntraFast;
   bool      m_useAMaxBT;
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 66d1f64e0..3258b3709 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -80,6 +80,8 @@
 
 #define JVET_AD0067_INCLUDE_SYNTAX                        1 // include nnpfc_full_range_flag syntax element in the nnpfc sei message when nnpfc_separate_colour_description_present_flag is equal to 1 and when nnpfc_out_format_idc is equal to 1.
 
+#define JVET_AE0057_MTT_ET                                1 // JVET-AE0057: MTT split modes early termination
+
 #define REUSE_CU_RESULTS                                  1
 #if REUSE_CU_RESULTS
 #define REUSE_CU_RESULTS_WITH_MULTIPLE_TUS                1
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index 0d12353d8..461f94c6c 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -426,6 +426,9 @@ protected:
   int       m_fastAdaptCostPredMode;
   bool      m_disableFastDecisionTT;
   uint32_t  m_log2MaxTbSize;
+#if JVET_AE0057_MTT_ET
+  bool      m_useMttSkip;
+#endif
 
   //====== Loop/Deblock Filter ========
   bool      m_deblockingFilterDisable;
@@ -1605,6 +1608,11 @@ public:
   void      setDisableFastDecisionTT        (bool i)         { m_disableFastDecisionTT = i; }
   bool      getDisableFastDecisionTT        () const         { return m_disableFastDecisionTT; }
 
+#if JVET_AE0057_MTT_ET
+  void      setUseMttSkip                   (bool i)         { m_useMttSkip = i; }
+  bool      getUseMttSkip                   () const         { return m_useMttSkip; }
+#endif    
+ 
   void      setLog2MaxTbSize                ( uint32_t  u )   { m_log2MaxTbSize = u; }
 
   //====== Loop/Deblock Filter ========
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 439ae9344..e8507689f 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -830,6 +830,19 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par
       {
         xCheckRDCostIntra(tempCS, bestCS, partitioner, currTestMode, false);
       }
+#if JVET_AE0057_MTT_ET
+      if (partitioner.currQtDepth == 1 && partitioner.currBtDepth == 0 && partitioner.currArea().lwidth() == 64
+          && partitioner.currArea().lheight() == 64)
+      {
+        if ((ChannelType(0) == ChannelType::LUMA)
+            && ((partitioner.currArea().Y().x + 63 < bestCS->picture->lwidth())
+                && (partitioner.currArea().Y().y + 63 < bestCS->picture->lheight())))
+        {      
+          m_modeCtrl->setNoSplitIntraCost(bestCS->cost);
+        }
+      }
+#endif
+
       splitRdCostBest[CTU_LEVEL] = bestCS->cost;
       tempCS->splitRdCostBest = splitRdCostBest;
     }
@@ -1201,6 +1214,18 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS,
       CodingStructure *tempSubCS = m_pTempCS[wIdx][hIdx];
       CodingStructure *bestSubCS = m_pBestCS[wIdx][hIdx];
 
+#if JVET_AE0057_MTT_ET
+      if (partitioner.currQtDepth == 1 && partitioner.currBtDepth == 0 && partitioner.currArea().lwidth() == 64
+          && partitioner.currArea().lheight() == 64)
+      {
+        if ((ChannelType(0) == ChannelType::LUMA)
+            && ((partitioner.currArea().Y().x + 63 < bestCS->picture->lwidth())
+                && (partitioner.currArea().Y().y + 63 < bestCS->picture->lheight())))
+        {
+          m_modeCtrl->setNoSplitIntraCost(0.0);
+        }
+      }
+#endif 
       tempCS->initSubStructure( *tempSubCS, partitioner.chType, subCUArea, false );
       tempCS->initSubStructure( *bestSubCS, partitioner.chType, subCUArea, false );
       tempSubCS->bestParent = bestSubCS->bestParent = bestCS;
diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp
index 87fd8f45a..632926e84 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.cpp
+++ b/source/Lib/EncoderLib/EncModeCtrl.cpp
@@ -1424,6 +1424,36 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
 {
   ComprCUCtx& cuECtx = m_ComprCUCtxList.back();
 
+#if JVET_AE0057_MTT_ET
+  if (m_pcEncCfg->getUseMttSkip() && partitioner.currQtDepth == 1 && partitioner.currBtDepth == 0
+      && partitioner.currArea().lwidth() == 64
+      && partitioner.currArea().lheight() == 64)
+  {
+    if (((partitioner.currArea().Y().x + 63 < cs.picture->lwidth())
+         && (partitioner.currArea().Y().y + 63 < cs.picture->lheight()))
+
+        && (encTestmode.type == ETM_SPLIT_BT_H || encTestmode.type == ETM_SPLIT_BT_V
+            || encTestmode.type == ETM_SPLIT_TT_H || encTestmode.type == ETM_SPLIT_TT_V)
+        && partitioner.chType == ChannelType::LUMA)
+    {
+      if (m_noSplitIntraRdCost > (120 - ((m_pcEncCfg->getBaseQP() - 22) * 4)) * 1000000)
+      {
+        const PartSplit split = getPartSplit(encTestmode);
+
+        if (split == CU_HORZ_SPLIT)
+        {
+          cuECtx.set(DID_HORZ_SPLIT, false);
+        }
+        if (split == CU_VERT_SPLIT)
+        {
+          cuECtx.set(DID_VERT_SPLIT, false);
+        }
+        return false;
+      }
+    }
+  }
+#endif
+
   // Fast checks, partitioning depended
   if (cuECtx.isHashPerfectMatch && encTestmode.type != ETM_MERGE_SKIP && encTestmode.type != ETM_INTER_ME)
   {
diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h
index e3fb983eb..270beb334 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.h
+++ b/source/Lib/EncoderLib/EncModeCtrl.h
@@ -296,6 +296,9 @@ protected:
   bool                  m_HashMEPOCchecked;
   int                   m_HashMEPOC2;
 
+#if JVET_AE0057_MTT_ET
+  double                m_noSplitIntraRdCost;
+#endif
 public:
 
   virtual ~EncModeCtrl              () {}
@@ -334,6 +337,9 @@ public:
   virtual void setBest              ( CodingStructure& cs );
   bool         anyMode              () const;
 
+#if JVET_AE0057_MTT_ET
+  void         setNoSplitIntraCost  (double cost) { m_noSplitIntraRdCost = cost; }
+#endif
   const ComprCUCtx& getComprCUCtx   () { CHECK( m_ComprCUCtxList.empty(), "Accessing empty list!"); return m_ComprCUCtxList.back(); }
 
 #if SHARP_LUMA_DELTA_QP
-- 
GitLab