From f08451322d76444aafd3851469e78e4a721ef10d Mon Sep 17 00:00:00 2001
From: Mitsuru Katsumata <mitsuru.katsumata@sony.com>
Date: Tue, 14 Jul 2020 15:59:14 +0900
Subject: [PATCH] JVET-S0071

---
 source/App/EncoderApp/EncApp.cpp    |  3 ++
 source/App/EncoderApp/EncAppCfg.cpp | 59 ++++++++++++++++++++++-
 source/App/EncoderApp/EncAppCfg.h   |  3 ++
 source/Lib/CommonLib/Slice.cpp      |  3 ++
 source/Lib/CommonLib/Slice.h        |  7 +++
 source/Lib/CommonLib/TypeDef.h      |  4 +-
 source/Lib/DecoderLib/VLCReader.cpp | 74 +++++++++++++++++++++++++++++
 source/Lib/EncoderLib/EncCfg.h      | 17 ++++++-
 source/Lib/EncoderLib/EncLib.cpp    | 22 +++++++++
 source/Lib/EncoderLib/VLCWriter.cpp | 32 +++++++++++++
 10 files changed, 219 insertions(+), 5 deletions(-)

diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 2d092e9b3..e328b7157 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -420,6 +420,9 @@ void EncApp::xInitLibCfg()
   if(m_subPicInfoPresentFlag)
   {
     m_cEncLib.setNumSubPics                                      ( m_numSubPics );
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+    m_cEncLib.setSubPicSameSizeFlag                              ( m_subPicSameSizeFlag );
+#endif
     m_cEncLib.setSubPicCtuTopLeftX                               ( m_subPicCtuTopLeftX );
     m_cEncLib.setSubPicCtuTopLeftY                               ( m_subPicCtuTopLeftY );
     m_cEncLib.setSubPicWidth                                     ( m_subPicWidth );
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index c6da6cf15..db190aea4 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -832,6 +832,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ("Log2MinCuSize",                                   m_log2MinCuSize,                                     2u, "Log2 min CU size")
   ("SubPicInfoPresentFlag",                           m_subPicInfoPresentFlag,                          false, "equal to 1 specifies that subpicture parameters are present in in the SPS RBSP syntax")
   ("NumSubPics",                                      m_numSubPics,                                        0u, "specifies the number of subpictures")
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+  ("SubPicSameSizeFlag",                              m_subPicSameSizeFlag,                             false, "equal to 1 specifies that all subpictures in the CLVS have the same width specified by sps_subpic_width_minus1[ 0 ] and the same height specified by sps_subpic_height_minus1[ 0 ].")
+#endif
   ("SubPicCtuTopLeftX",                               cfg_subPicCtuTopLeftX,            cfg_subPicCtuTopLeftX, "specifies horizontal position of top left CTU of i-th subpicture in unit of CtbSizeY")
   ("SubPicCtuTopLeftY",                               cfg_subPicCtuTopLeftY,            cfg_subPicCtuTopLeftY, "specifies vertical position of top left CTU of i-th subpicture in unit of CtbSizeY")
   ("SubPicWidth",                                     cfg_subPicWidth,                        cfg_subPicWidth, "specifies the width of the i-th subpicture in units of CtbSizeY")
@@ -1566,11 +1569,28 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   }
   if ( m_subPicInfoPresentFlag )
   {
-    CHECK( m_numSubPics > MAX_NUM_SUB_PICS || m_numSubPics < 1, "Number of subpicture must be within 1 to 2^16" );
+    CHECK( m_numSubPics > MAX_NUM_SUB_PICS || m_numSubPics < 1, "Number of subpicture must be within 1 to 2^16" )
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+    if (!m_subPicSameSizeFlag)
+    {
+      CHECK(cfg_subPicCtuTopLeftX.values.size() != m_numSubPics, "Number of SubPicCtuTopLeftX values must be equal to NumSubPics");
+      CHECK(cfg_subPicCtuTopLeftY.values.size() != m_numSubPics, "Number of SubPicCtuTopLeftY values must be equal to NumSubPics");
+      CHECK(cfg_subPicWidth.values.size() != m_numSubPics, "Number of SubPicWidth values must be equal to NumSubPics");
+      CHECK(cfg_subPicHeight.values.size() != m_numSubPics, "Number of SubPicHeight values must be equal to NumSubPics");
+    }
+    else
+    {
+      CHECK(cfg_subPicCtuTopLeftX.values.size() != 0, "Number of SubPicCtuTopLeftX values must be equal to 0");
+      CHECK(cfg_subPicCtuTopLeftY.values.size() != 0, "Number of SubPicCtuTopLeftY values must be equal to 0");
+      CHECK(cfg_subPicWidth.values.size() != 1, "Number of SubPicWidth values must be equal to 1");
+      CHECK(cfg_subPicHeight.values.size() != 1, "Number of SubPicHeight values must be equal to 1");
+    }
+#else
     CHECK( cfg_subPicCtuTopLeftX.values.size() != m_numSubPics, "Number of SubPicCtuTopLeftX values must be equal to NumSubPics");
     CHECK( cfg_subPicCtuTopLeftY.values.size() != m_numSubPics, "Number of SubPicCtuTopLeftY values must be equal to NumSubPics");
     CHECK( cfg_subPicWidth.values.size() != m_numSubPics, "Number of SubPicWidth values must be equal to NumSubPics");
     CHECK( cfg_subPicHeight.values.size() != m_numSubPics, "Number of SubPicHeight values must be equal to NumSubPics");
+#endif
     CHECK( cfg_subPicTreatedAsPicFlag.values.size() != m_numSubPics, "Number of SubPicTreatedAsPicFlag values must be equal to NumSubPics");
     CHECK( cfg_loopFilterAcrossSubpicEnabledFlag.values.size() != m_numSubPics, "Number of LoopFilterAcrossSubpicEnabledFlag values must be equal to NumSubPics");
     if (m_subPicIdMappingExplicitlySignalledFlag)
@@ -1590,11 +1610,31 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
         m_subPicId[i]                   = cfg_subPicId.values[i];
       }
     }
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+    uint32_t tmpWidthVal = (m_iSourceWidth + m_uiCTUSize - 1) / m_uiCTUSize;
+    uint32_t tmpHeightVal = (m_iSourceHeight + m_uiCTUSize - 1) / m_uiCTUSize;
+    if (!m_subPicSameSizeFlag)
+    {
+      for (int i = 0; i < m_numSubPics; i++)
+      {
+        CHECK(m_subPicCtuTopLeftX[i] + m_subPicWidth[i] > tmpWidthVal, "Subpicture must not exceed picture boundary");
+        CHECK(m_subPicCtuTopLeftY[i] + m_subPicHeight[i] > tmpHeightVal, "Subpicture must not exceed picture boundary");
+      }
+    }
+    else
+    {
+      uint32_t numSubpicCols = tmpWidthVal / m_subPicWidth[0];
+      CHECK(tmpWidthVal % m_subPicWidth[0] != 0, "subpic_width_minus1[0] is invalid.");
+      CHECK(tmpHeightVal % m_subPicHeight[0] != 0, "subpic_height_minus1[0] is invalid.");
+      CHECK(numSubpicCols * (tmpHeightVal / m_subPicHeight[0]) != m_numSubPics, "when sps_subpic_same_size_flag is equal to, sps_num_subpics_minus1 is invalid");
+    }
+#else
     for(int i = 0; i < m_numSubPics; i++)
     {
       CHECK(m_subPicCtuTopLeftX[i] + m_subPicWidth[i] > (m_iSourceWidth + m_uiCTUSize - 1) / m_uiCTUSize, "Subpicture must not exceed picture boundary");
       CHECK(m_subPicCtuTopLeftY[i] + m_subPicHeight[i] > (m_iSourceHeight + m_uiCTUSize - 1) / m_uiCTUSize, "Subpicture must not exceed picture boundary");
     }
+#endif
     // automatically determine subpicture ID lenght in case it is not specified
     if (m_subPicIdLen == 0)
     {
@@ -3593,14 +3633,29 @@ void EncAppCfg::xPrintParameter()
   if (m_subPicInfoPresentFlag)
   {
     msg(DETAILS, "number of subpictures                            : %d\n", m_numSubPics);
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+    msg(DETAILS, "subpicture size same flag                        : %d\n", m_subPicSameSizeFlag);
+    if (m_subPicSameSizeFlag)
+      msg(DETAILS, "[0]th subpictures size                           :[%d %d]\n", m_subPicWidth[0], m_subPicHeight[0]);
+    for (int i = 0; i < m_numSubPics; i++)
+    {
+      if (!m_subPicSameSizeFlag)
+      {
+        msg(DETAILS, "[%d]th subpictures location                           :[%d %d]\n", i, m_subPicCtuTopLeftX[i], m_subPicCtuTopLeftY[i]);
+        msg(DETAILS, "[%d]th subpictures size                           :[%d %d]\n", i, m_subPicWidth[i], m_subPicHeight[i]);
+      }
+      msg(DETAILS, "[%d]th subpictures treated as picture flag                           :%d\n", i, m_subPicTreatedAsPicFlag[i]);
+      msg(DETAILS, "loop filter cross [%d]th subpictures enabled flag                           :%d\n", i, m_loopFilterAcrossSubpicEnabledFlag[i]);
+    }
+#else
     for (int i = 0; i < m_numSubPics; i++)
     {
       msg(DETAILS, "[%d]th subpictures location                           :[%d %d]\n", i, m_subPicCtuTopLeftX[i], m_subPicCtuTopLeftY[i]);
       msg(DETAILS, "[%d]th subpictures size                           :[%d %d]\n", i, m_subPicWidth[i], m_subPicHeight[i]);
       msg(DETAILS, "[%d]th subpictures treated as picture flag                           :%d\n", i, m_subPicTreatedAsPicFlag[i]);
       msg(DETAILS, "loop filter cross [%d]th subpictures enabled flag                           :%d\n", i, m_loopFilterAcrossSubpicEnabledFlag[i]);
-
     }
+#endif
   }
 
   msg(DETAILS, "subpicture ID present flag                            : %d\n", m_subPicIdMappingExplicitlySignalledFlag);
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index 8de7603e3..76edb6523 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -278,6 +278,9 @@ protected:
   unsigned  m_uiCTUSize;
   bool m_subPicInfoPresentFlag;
   unsigned m_numSubPics;
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+  bool m_subPicSameSizeFlag;
+#endif
   std::vector<uint32_t> m_subPicCtuTopLeftX;
   std::vector<uint32_t> m_subPicCtuTopLeftY;
   std::vector<uint32_t> m_subPicWidth;
diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp
index 9a4a634f8..7ec20d0fd 100644
--- a/source/Lib/CommonLib/Slice.cpp
+++ b/source/Lib/CommonLib/Slice.cpp
@@ -2701,6 +2701,9 @@ SPS::SPS()
 , m_subPicInfoPresentFlag     (false)
 , m_numSubPics(1)
 , m_independentSubPicsFlag     (false)
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+, m_subPicSameSizeFlag        (false)
+#endif
 , m_subPicIdMappingExplicitlySignalledFlag ( false )
 , m_subPicIdMappingInSpsFlag ( false )
 , m_subPicIdLen(16)
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index 0cfaca12b..313f46e94 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -1288,6 +1288,9 @@ private:
   bool                  m_subPicInfoPresentFlag;                // indicates the presence of sub-picture info
   uint32_t              m_numSubPics;                        //!< number of sub-pictures used
   bool                  m_independentSubPicsFlag;
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+  bool                  m_subPicSameSizeFlag;
+#endif
   std::vector<uint32_t> m_subPicCtuTopLeftX;
   std::vector<uint32_t> m_subPicCtuTopLeftY;
   std::vector<uint32_t> m_subPicWidth;
@@ -1481,6 +1484,10 @@ public:
                                                                                             }
   void      setIndependentSubPicsFlag(bool b)                                                { m_independentSubPicsFlag = b;                    }
   bool      getIndependentSubPicsFlag() const                                                { return m_independentSubPicsFlag;                 }
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+  void      setSubPicSameSizeFlag(bool b)                                                   { m_subPicSameSizeFlag = b;                       }
+  bool      getSubPicSameSizeFlag() const                                                   { return m_subPicSameSizeFlag;                    }
+#endif
   uint32_t  getNumSubPics( ) const                                                          { return  m_numSubPics;                           }
   void      setSubPicCtuTopLeftX( int i, uint32_t u )                                       { m_subPicCtuTopLeftX[i] = u;                     }
   uint32_t  getSubPicCtuTopLeftX( int i ) const                                             { return  m_subPicCtuTopLeftX[i];                 }
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index acde67751..96fb1fcf4 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -53,7 +53,7 @@
 
 //########### place macros to be removed in next cycle below this line ###############
 
-
+#define JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT       1 // JVET-S0071 : shortcut when all subpictures have the same size
 
 //########### place macros to be be kept below this line ###############
 #define JVET_R0351_HIGH_BIT_DEPTH_SUPPORT                 1 // JVET-R0351: high bit depth coding support (syntax changes, no mathematical differences for CTCs)
@@ -109,7 +109,7 @@ typedef std::pair<int, int>  TrCost;
 // ====================================================================================================================
 
 #ifndef ENABLE_TRACING
-#define ENABLE_TRACING                                    0 // DISABLE by default (enable only when debugging, requires 15% run-time in decoding) -- see documentation in 'doc/DTrace for NextSoftware.pdf'
+#define ENABLE_TRACING                                    1 // DISABLE by default (enable only when debugging, requires 15% run-time in decoding) -- see documentation in 'doc/DTrace for NextSoftware.pdf'
 #endif
 
 #if ENABLE_TRACING
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index 276c3fd50..5e19ce944 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -1365,12 +1365,85 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
       pcSPS->setSubPicHeight( 0, ( pcSPS->getMaxPicHeightInLumaSamples() + pcSPS->getCTUSize() - 1 ) >> floorLog2( pcSPS->getCTUSize() ) );
 
       pcSPS->setIndependentSubPicsFlag(1);
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+      pcSPS->setSubPicSameSizeFlag(0);
+#endif
 
       pcSPS->setSubPicTreatedAsPicFlag(0, 1);
       pcSPS->setLoopFilterAcrossSubpicEnabledFlag(0, 0);
     }
     else
     {
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+      READ_FLAG(uiCode, "sps_independent_subpics_flag"); pcSPS->setIndependentSubPicsFlag(uiCode != 0);
+      READ_FLAG(uiCode, "sps_subpic_same_size_flag"); pcSPS->setSubPicSameSizeFlag(uiCode);
+      uint32_t tmpWidthVal = (pcSPS->getMaxPicWidthInLumaSamples() + pcSPS->getCTUSize() - 1) / pcSPS->getCTUSize();
+      uint32_t tmpHeightVal = (pcSPS->getMaxPicHeightInLumaSamples() + pcSPS->getCTUSize() - 1) / pcSPS->getCTUSize();
+      uint32_t numSubpicCols = 1;
+      for (int picIdx = 0; picIdx < pcSPS->getNumSubPics(); picIdx++)
+      {
+        if (!pcSPS->getSubPicSameSizeFlag() || picIdx == 0)
+        {
+          if ((picIdx > 0) && (pcSPS->getMaxPicWidthInLumaSamples() > pcSPS->getCTUSize()))
+          {
+            READ_CODE(ceilLog2(tmpWidthVal), uiCode, "subpic_ctu_top_left_x[ i ]");
+            pcSPS->setSubPicCtuTopLeftX(picIdx, uiCode);
+          }
+          else
+          {
+            pcSPS->setSubPicCtuTopLeftX(picIdx, 0);
+          }
+          if ((picIdx > 0) && (pcSPS->getMaxPicHeightInLumaSamples() > pcSPS->getCTUSize()))
+          {
+            READ_CODE(ceilLog2(tmpHeightVal), uiCode, "subpic_ctu_top_left_y[ i ]");
+            pcSPS->setSubPicCtuTopLeftY(picIdx, uiCode);
+          }
+          else
+          {
+            pcSPS->setSubPicCtuTopLeftY(picIdx, 0);
+          }
+          if (picIdx <pcSPS->getNumSubPics() - 1 && pcSPS->getMaxPicWidthInLumaSamples() > pcSPS->getCTUSize())
+          {
+            READ_CODE(ceilLog2(tmpWidthVal), uiCode, "subpic_width_minus1[ i ]");
+            pcSPS->setSubPicWidth(picIdx, uiCode + 1);
+          }
+          else
+          {
+            pcSPS->setSubPicWidth(picIdx, tmpWidthVal - pcSPS->getSubPicCtuTopLeftX(picIdx));
+          }
+          if (picIdx <pcSPS->getNumSubPics() - 1 && pcSPS->getMaxPicHeightInLumaSamples() > pcSPS->getCTUSize())
+          {
+            READ_CODE(ceilLog2(tmpHeightVal), uiCode, "subpic_height_minus1[ i ]");
+            pcSPS->setSubPicHeight(picIdx, uiCode + 1);
+          }
+          else
+          {
+            pcSPS->setSubPicHeight(picIdx, tmpHeightVal - pcSPS->getSubPicCtuTopLeftY(picIdx));
+          }
+          if (pcSPS->getSubPicSameSizeFlag())
+          {
+            numSubpicCols = tmpWidthVal / pcSPS->getSubPicWidth(0);
+            CHECK(!(tmpWidthVal % pcSPS->getSubPicWidth(0) == 0), "subpic_width_minus1[0] is invalid.");
+            CHECK(!(tmpHeightVal % pcSPS->getSubPicHeight(0) == 0), "subpic_height_minus1[0] is invalid.");
+            CHECK(!(numSubpicCols * (tmpHeightVal / pcSPS->getSubPicHeight(0)) == pcSPS->getNumSubPics()), "when sps_subpic_same_size_flag is equal to, sps_num_subpics_minus1 is invalid");
+          }
+        }
+        else
+        {
+          pcSPS->setSubPicCtuTopLeftX(picIdx, (picIdx % numSubpicCols) * pcSPS->getSubPicWidth(0));
+          pcSPS->setSubPicCtuTopLeftY(picIdx, (picIdx / numSubpicCols) * pcSPS->getSubPicHeight(0));
+          pcSPS->setSubPicWidth(picIdx, pcSPS->getSubPicWidth(0));
+          pcSPS->setSubPicHeight(picIdx, pcSPS->getSubPicHeight(0));
+        }
+        if (!pcSPS->getIndependentSubPicsFlag())
+        {
+          READ_FLAG(uiCode, "subpic_treated_as_pic_flag[ i ]");
+          pcSPS->setSubPicTreatedAsPicFlag(picIdx, uiCode);
+          READ_FLAG(uiCode, "loop_filter_across_subpic_enabled_flag[ i ]");
+          pcSPS->setLoopFilterAcrossSubpicEnabledFlag(picIdx, uiCode);
+        }
+      }
+#else
     READ_FLAG(uiCode, "sps_independent_subpics_flag"); pcSPS->setIndependentSubPicsFlag(uiCode != 0);
     for (int picIdx = 0; picIdx < pcSPS->getNumSubPics(); picIdx++)
     {
@@ -1418,6 +1491,7 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
         pcSPS->setLoopFilterAcrossSubpicEnabledFlag(picIdx, uiCode);
       }
     }
+#endif
     }
 
     READ_UVLC( uiCode, "sps_subpic_id_len_minus1" );                       pcSPS->setSubPicIdLen( uiCode + 1 );
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index 2547b7c62..abc860cca 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -278,6 +278,9 @@ protected:
   unsigned  m_CTUSize;
   bool                  m_subPicInfoPresentFlag;
   uint32_t              m_numSubPics;
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+  bool                  m_subPicSameSizeFlag;
+#endif
   std::vector<uint32_t> m_subPicCtuTopLeftX;
   std::vector<uint32_t> m_subPicCtuTopLeftY;
   std::vector<uint32_t> m_subPicWidth;
@@ -967,17 +970,26 @@ public:
                                                                                       m_loopFilterAcrossSubpicEnabledFlag.resize(m_numSubPics);
                                                                                       m_subPicId.resize(m_numSubPics);
                                                                                     }
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+  void      setSubPicSameSizeFlag                       (bool b)                    { m_subPicSameSizeFlag = b; }
+#endif
   void      setSubPicCtuTopLeftX                        (uint32_t u, int i)         { m_subPicCtuTopLeftX[i] = u; }
   void      setSubPicCtuTopLeftY                        (uint32_t u, int i)         { m_subPicCtuTopLeftY[i] = u; }
   void      setSubPicWidth                              (uint32_t u, int i)         { m_subPicWidth[i] = u; }
   void      setSubPicHeight                             (uint32_t u, int i)         { m_subPicHeight[i] = u; }
   void      setSubPicTreatedAsPicFlag                   (bool b, int i)             { m_subPicTreatedAsPicFlag[i] = b; }
   void      setLoopFilterAcrossSubpicEnabledFlag        (bool b, int i)             { m_loopFilterAcrossSubpicEnabledFlag[i] = b; }
-
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+  void      setSubPicCtuTopLeftX                        (const std::vector<uint32_t> &v)   { CHECK(v.size() != (m_subPicSameSizeFlag ? 0 : m_numSubPics), "number of vector entries must be equal to numSubPics(subPicSameSize=0) or 0(subPicSameSize=1)"); m_subPicCtuTopLeftX = v; }
+  void      setSubPicCtuTopLeftY                        (const std::vector<uint32_t> &v)   { CHECK(v.size() != (m_subPicSameSizeFlag ? 0 : m_numSubPics), "number of vector entries must be equal to numSubPics(subPicSameSize=0) or 0(subPicSameSize=1)"); m_subPicCtuTopLeftY = v; }
+  void      setSubPicWidth                              (const std::vector<uint32_t> &v)   { CHECK(v.size() != (m_subPicSameSizeFlag ? 1 : m_numSubPics), "number of vector entries must be equal to numSubPics(subPicSameSize=0) or 1(subPicSameSize=1)"); m_subPicWidth = v; }
+  void      setSubPicHeight                             (const std::vector<uint32_t> &v)   { CHECK(v.size() != (m_subPicSameSizeFlag ? 1 : m_numSubPics), "number of vector entries must be equal to numSubPics(subPicSameSize=0) or 1(subPicSameSize=1)"); m_subPicHeight = v; }
+#else
   void      setSubPicCtuTopLeftX                        (const std::vector<uint32_t> &v)   { CHECK(v.size()!=m_numSubPics, "number of vector entries must be equal to numSubPics") ;m_subPicCtuTopLeftX = v; }
   void      setSubPicCtuTopLeftY                        (const std::vector<uint32_t> &v)   { CHECK(v.size()!=m_numSubPics, "number of vector entries must be equal to numSubPics") ;m_subPicCtuTopLeftY = v; }
   void      setSubPicWidth                              (const std::vector<uint32_t> &v)   { CHECK(v.size()!=m_numSubPics, "number of vector entries must be equal to numSubPics") ;m_subPicWidth = v; }
   void      setSubPicHeight                             (const std::vector<uint32_t> &v)   { CHECK(v.size()!=m_numSubPics, "number of vector entries must be equal to numSubPics") ;m_subPicHeight = v; }
+#endif
   void      setSubPicTreatedAsPicFlag                   (const std::vector<bool> &v)       { CHECK(v.size()!=m_numSubPics, "number of vector entries must be equal to numSubPics") ;m_subPicTreatedAsPicFlag = v; }
   void      setLoopFilterAcrossSubpicEnabledFlag        (const std::vector<bool> &v)       { CHECK(v.size()!=m_numSubPics, "number of vector entries must be equal to numSubPics") ;m_loopFilterAcrossSubpicEnabledFlag = v; }
 
@@ -988,6 +1000,9 @@ public:
   void      setSubPicId                                 (const std::vector<uint16_t> &v)   { CHECK(v.size()!=m_numSubPics, "number of vector entries must be equal to numSubPics"); m_subPicId = v; }
 
   bool      getSubPicInfoPresentFlag                    ()                          { return m_subPicInfoPresentFlag; }
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+  bool      getSubPicSameSizeFlag                       ()                          { return m_subPicSameSizeFlag; }
+#endif
   uint32_t  getNumSubPics                               ()                          { return m_numSubPics; }
   uint32_t  getSubPicCtuTopLeftX                        (int i)                     { return m_subPicCtuTopLeftX[i]; }
   uint32_t  getSubPicCtuTopLeftY                        (int i)                     { return m_subPicCtuTopLeftY[i]; }
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index 9a51e592a..30d8c8f68 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -1371,10 +1371,32 @@ void EncLib::xInitSPS( SPS& sps )
   if (m_subPicInfoPresentFlag)
   {
     sps.setNumSubPics(m_numSubPics);
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+    sps.setSubPicSameSizeFlag(m_subPicSameSizeFlag);
+    if (m_subPicSameSizeFlag)
+    {
+      uint32_t numSubpicCols = (m_iSourceWidth + m_CTUSize - 1) / m_CTUSize / m_subPicWidth[0];
+      for (unsigned int i = 0; i < m_numSubPics; i++)
+      {
+        sps.setSubPicCtuTopLeftX(i, (i % numSubpicCols) * m_subPicWidth[0]);
+        sps.setSubPicCtuTopLeftY(i, (i / numSubpicCols) * m_subPicHeight[0]);
+        sps.setSubPicWidth(i, m_subPicWidth[0]);
+        sps.setSubPicHeight(i, m_subPicHeight[0]);
+      }
+    }
+    else
+    {
+      sps.setSubPicCtuTopLeftX(m_subPicCtuTopLeftX);
+      sps.setSubPicCtuTopLeftY(m_subPicCtuTopLeftY);
+      sps.setSubPicWidth(m_subPicWidth);
+      sps.setSubPicHeight(m_subPicHeight);
+    }
+#else
     sps.setSubPicCtuTopLeftX(m_subPicCtuTopLeftX);
     sps.setSubPicCtuTopLeftY(m_subPicCtuTopLeftY);
     sps.setSubPicWidth(m_subPicWidth);
     sps.setSubPicHeight(m_subPicHeight);
+#endif
     sps.setSubPicTreatedAsPicFlag(m_subPicTreatedAsPicFlag);
     sps.setLoopFilterAcrossSubpicEnabledFlag(m_loopFilterAcrossSubpicEnabledFlag);
     sps.setSubPicIdLen(m_subPicIdLen);
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index 88afee44d..aef52cff4 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -816,6 +816,37 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
     WRITE_UVLC(pcSPS->getNumSubPics() - 1, "sps_num_subpics_minus1");
     if( pcSPS->getNumSubPics() > 1 )
     {
+#if JVET_S0071_SAME_SIZE_SUBPIC_LAYOUT
+      WRITE_FLAG(pcSPS->getIndependentSubPicsFlag(), "sps_independent_subpics_flag");
+      WRITE_FLAG(pcSPS->getSubPicSameSizeFlag(), "sps_subpic_same_size_flag");
+      for (int picIdx = 0; picIdx < pcSPS->getNumSubPics(); picIdx++)
+      {
+        if (!pcSPS->getSubPicSameSizeFlag() || picIdx == 0)
+        {
+          if ((picIdx > 0) && (pcSPS->getMaxPicWidthInLumaSamples() > pcSPS->getCTUSize()))
+          {
+            WRITE_CODE(pcSPS->getSubPicCtuTopLeftX(picIdx), ceilLog2((pcSPS->getMaxPicWidthInLumaSamples() + pcSPS->getCTUSize() - 1) / pcSPS->getCTUSize()), "subpic_ctu_top_left_x[ i ]");
+          }
+          if ((picIdx > 0) && (pcSPS->getMaxPicHeightInLumaSamples() > pcSPS->getCTUSize()))
+          {
+            WRITE_CODE(pcSPS->getSubPicCtuTopLeftY(picIdx), ceilLog2((pcSPS->getMaxPicHeightInLumaSamples() + pcSPS->getCTUSize() - 1) / pcSPS->getCTUSize()), "subpic_ctu_top_left_y[ i ]");
+          }
+          if (picIdx<pcSPS->getNumSubPics() - 1 && pcSPS->getMaxPicWidthInLumaSamples() > pcSPS->getCTUSize())
+          {
+            WRITE_CODE(pcSPS->getSubPicWidth(picIdx) - 1, ceilLog2((pcSPS->getMaxPicWidthInLumaSamples() + pcSPS->getCTUSize() - 1) / pcSPS->getCTUSize()), "subpic_width_minus1[ i ]");
+          }
+          if (picIdx<pcSPS->getNumSubPics() - 1 && pcSPS->getMaxPicHeightInLumaSamples() > pcSPS->getCTUSize())
+          {
+            WRITE_CODE(pcSPS->getSubPicHeight(picIdx) - 1, ceilLog2((pcSPS->getMaxPicHeightInLumaSamples() + pcSPS->getCTUSize() - 1) / pcSPS->getCTUSize()), "subpic_height_minus1[ i ]");
+          }
+          if (!pcSPS->getIndependentSubPicsFlag())
+          {
+            WRITE_FLAG(pcSPS->getSubPicTreatedAsPicFlag(picIdx), "subpic_treated_as_pic_flag[ i ]");
+            WRITE_FLAG(pcSPS->getLoopFilterAcrossSubpicEnabledFlag(picIdx), "loop_filter_across_subpic_enabled_flag[ i ]");
+          }
+        }
+      }
+#else
     WRITE_FLAG(pcSPS->getIndependentSubPicsFlag(), "sps_independent_subpics_flag");
     for (int picIdx = 0; picIdx < pcSPS->getNumSubPics(); picIdx++)
     {
@@ -841,6 +872,7 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
         WRITE_FLAG( pcSPS->getLoopFilterAcrossSubpicEnabledFlag(picIdx),  "loop_filter_across_subpic_enabled_flag[ i ]" );
       }
     }
+#endif
     }
 
     CHECK(pcSPS->getSubPicIdLen() < 1, "SPS: SubPicIdLen cannot be less than 1");
-- 
GitLab