From 47ff0117bc6bb32ec1dae545202127754636aac8 Mon Sep 17 00:00:00 2001
From: vdrugeon <virginie.drugeon@eu.panasonic.com>
Date: Wed, 12 Feb 2020 16:44:37 +0000
Subject: [PATCH] JVET-Q0044: slice index with subpictures

---
 .../TwoSubpictures_with_EightSlices.cfg       | 28 ++++++++++++
 source/Lib/CommonLib/Slice.cpp                | 43 +++++++++++++++++++
 source/Lib/CommonLib/Slice.h                  | 18 ++++++++
 source/Lib/CommonLib/TypeDef.h                |  2 +
 source/Lib/DecoderLib/DecLib.cpp              | 29 ++++++++++++-
 source/Lib/DecoderLib/DecLib.h                |  4 ++
 source/Lib/DecoderLib/VLCReader.cpp           | 24 +++++++++++
 source/Lib/EncoderLib/EncGOP.cpp              | 17 ++++++++
 source/Lib/EncoderLib/EncLib.cpp              | 12 ++++++
 source/Lib/EncoderLib/VLCWriter.cpp           | 15 +++++++
 10 files changed, 191 insertions(+), 1 deletion(-)
 create mode 100644 cfg/nonCTC-SliceConfigExamples/TwoSubpictures_with_EightSlices.cfg

diff --git a/cfg/nonCTC-SliceConfigExamples/TwoSubpictures_with_EightSlices.cfg b/cfg/nonCTC-SliceConfigExamples/TwoSubpictures_with_EightSlices.cfg
new file mode 100644
index 000000000..3371a0a7b
--- /dev/null
+++ b/cfg/nonCTC-SliceConfigExamples/TwoSubpictures_with_EightSlices.cfg
@@ -0,0 +1,28 @@
+# example cfg file, assuming an 1920x1080 input sequence with CTU size = 128x128, and split to 8 rectangular slices, 12 tiles and 2 subpictures
+
+SourceWidth                             : 1920
+SourceHeight                            : 1080
+
+SubPicInfoPresentFlag                   : 1             # subpicture information present flag(0: OFF, 1: ON)
+NumSubPics                              : 2             # number of subpictures in a picture
+SubPicCtuTopLeftX                       : 0 11           # specifies horizontal position of top left CTU of i-th subpicture in unit of CtbSizeY 
+SubPicCtuTopLeftY                       : 0 0           # specifies vertical position of top left CTU of i-th subpicture in unit of CtbSizeY
+SubPicWidth                             : 11 4           # specifies the width of the i-th subpicture in units of CtbSizeY
+SubPicHeight                            : 9 9           # specifies the height of the i-th subpicture in units of CtbSizeY
+SubPicTreatedAsPicFlag                  : 1 1           # equal to 1 specifies that the i-th subpicture of each coded picture in the CLVS is treated as a picture in the decoding process excluding in-loop filtering operations
+LoopFilterAcrossSubpicEnabledFlag       : 0 0           # equal to 1 specifies that in-loop filtering operations may be performed across the boundaries of the i-th subpicture in each coded picture in the CLVS
+SubPicIdMappingExplicitlySignalledFlag  : 0             # equal to 1 specifies that the subpicture ID mapping is explicitly signalled, either in the SPS or in the PPSs
+
+
+#============ Tiles / Slices ================
+EnablePicPartitioning         : 1                       # Enable picture partitioning (0: single tile, single slice, 1: multiple tiles/slices can be used)
+
+# 24 tiles and 6 rectangular slices
+TileColumnWidthArray          : 3 4                        # Tile column widths in units of CTUs. Last column width will be repeated uniformly to cover any remaining picture width
+TileRowHeightArray            : 3                       # Tile row heights in units of CTUs. Last row height will be repeated uniformly to cover any remaining picture height  
+RasterScanSlices              : 0                       # Raster-scan or rectangular slices (0: rectangular, 1: raster-scan)
+RectSliceFixedWidth           : 0                       # Fixed rectangular slice width in units of tiles (0: disable this feature and use RectSlicePositions instead)
+RectSliceFixedHeight          : 0                       # Fixed rectangular slice height in units of tiles (0: disable this feature and use RectSlicePositions instead)
+RectSlicePositions            : 0 17 30 32 45 62 75 77 3 85 90 130 11 89 101 134 # Rectangular slices positions - list containing pairs of top-left CTU index and bottom-right CTU index
+DisableLoopFilterAcrossTiles  : 1                       # Loop filtering (DBLK/SAO/ALF) applied across tile boundaries or not (0: filter across tile boundaries  1: do not filter across tile boundaries)
+DisableLoopFilterAcrossSlices : 1                       # Loop filtering (DBLK/SAO/ALF) applied across slice boundaries or not (0: filter across slice boundaries 1: do not filter across slice boundaries)
diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp
index 19441135d..10a9ed5fb 100644
--- a/source/Lib/CommonLib/Slice.cpp
+++ b/source/Lib/CommonLib/Slice.cpp
@@ -2707,6 +2707,23 @@ void PPS::initSubPic(const SPS &sps)
   for (int i=0; i< getNumSubPics(); i++)
   {
     m_subPics[i].setSubPicIdx(i);
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+    if(sps.getSubPicIdMappingExplicitlySignalledFlag())
+    {
+      if(m_subPicIdMappingInPpsFlag)
+      {
+        m_subPics[i].setSubPicID(m_subPicId[i]);
+      }
+      else
+      {
+        m_subPics[i].setSubPicID(sps.getSubPicId(i));
+      }
+    }
+    else
+    {
+      m_subPics[i].setSubPicID(i);
+    }
+#endif
     m_subPics[i].setSubPicCtuTopLeftX(sps.getSubPicCtuTopLeftX(i));
     m_subPics[i].setSubPicCtuTopLeftY(sps.getSubPicCtuTopLeftY(i));
     m_subPics[i].setSubPicWidthInCTUs(sps.getSubPicWidth(i));
@@ -2740,9 +2757,15 @@ void PPS::initSubPic(const SPS &sps)
     {
       CHECK(getNumSubPics() != 1, "only one slice in picture, but number of subpic is not one");
       m_subPics[i].addAllCtusInPicToSubPic(0, getPicWidthInCtu(), 0, getPicHeightInCtu(), getPicWidthInCtu());
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+      m_subPics[i].setNumSlicesInSubPic(1);
+#endif
     }
     else
     {
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+      int numSlicesInSubPic = 0;
+#endif
       for (int j = 0; j < m_numSlicesInPic; j++)
       {
         uint32_t ctu = m_sliceMap[j].getCtuAddrInSlice(0);
@@ -2755,8 +2778,14 @@ void PPS::initSubPic(const SPS &sps)
         {
           // add ctus in a slice to the subpicture it belongs to
           m_subPics[i].addCTUsToSubPic(m_sliceMap[j].getCtuAddrList());
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+	  numSlicesInSubPic++;
+#endif
         }
       }
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+      m_subPics[i].setNumSlicesInSubPic(numSlicesInSubPic);
+#endif
     }
     m_subPics[i].setTreatedAsPicFlag(sps.getSubPicTreatedAsPicFlag(i));
     m_subPics[i].setloopFilterAcrossEnabledFlag(sps.getLoopFilterAcrossSubpicEnabledFlag(i));
@@ -2782,6 +2811,20 @@ SubPic  PPS::getSubPicFromCU(const CodingUnit& cu) const
 }
 #endif
 
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+uint32_t PPS::getSubPicIdxFromSubPicId( uint32_t subPicId ) const
+{
+  for (int i = 0; i < m_numSubPics; i++)
+  {
+    if(m_subPics[i].getSubPicID() == subPicId)
+    {
+      return i;
+    }
+  }
+  return 0;
+}
+#endif
+
 void PPS::initRasterSliceMap( std::vector<uint32_t> numTilesInSlice )
 {
   uint32_t tileIdx = 0;
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index 9246c7508..9e4602054 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -752,6 +752,9 @@ private:
 
   bool             m_treatedAsPicFlag;                          //!< whether the subpicture is treated as a picture in the decoding process excluding in-loop filtering operations
   bool             m_loopFilterAcrossSubPicEnabledFlag;         //!< whether in-loop filtering operations may be performed across the boundaries of the subpicture
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+  uint32_t         m_numSlicesInSubPic;                         //!< Number of slices contained in this subpicture
+#endif
   
 public:
   SubPic();
@@ -818,6 +821,15 @@ public:
 
   bool             isFirstCTUinSubPic(uint32_t ctuAddr)    { return  ctuAddr == m_firstCtuInSubPic;  }
   bool              isLastCTUinSubPic(uint32_t ctuAddr)    { return  ctuAddr == m_lastCtuInSubPic;   }
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+  void             setNumSlicesInSubPic( uint32_t val )    { m_numSlicesInSubPic = val; }
+  uint32_t         getNumSlicesInSubPic() const            { return m_numSlicesInSubPic; }
+  bool             containsCtu(const Position& pos) const
+  {
+    return pos.x >= m_subPicCtuTopLeftX && pos.x < m_subPicCtuTopLeftX + m_subPicWidth &&
+           pos.y >= m_subPicCtuTopLeftY && pos.y < m_subPicCtuTopLeftY + m_subPicHeight;
+  }
+#endif
 };
 #endif
 class DPS
@@ -2013,6 +2025,9 @@ public:
   uint32_t               getSubPicIdLen() const                                           { return  m_subPicIdLen;                        }
   void                   setSubPicId( int i, uint8_t u )                                  { CHECK( i >= MAX_NUM_SUB_PICS, "Sub-picture index exceeds valid range" ); m_subPicId[i] = u;     }
   uint8_t                getSubPicId( int i ) const                                       { CHECK( i >= MAX_NUM_SUB_PICS, "Sub-picture index exceeds valid range" ); return  m_subPicId[i]; }
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+  uint32_t               getSubPicIdxFromSubPicId( uint32_t subPicId ) const;
+#endif
   void                   setNoPicPartitionFlag( bool b )                                  { m_noPicPartitionFlag = b;                     }
   bool                   getNoPicPartitionFlag( ) const                                   { return  m_noPicPartitionFlag;                 }
   void                   setLog2CtuSize( uint8_t u )                                      { m_log2CtuSize = u; m_ctuSize = 1 << m_log2CtuSize; 
@@ -2082,6 +2097,9 @@ public:
   void                   initRectSliceMap();
 #if JVET_O1143_SUBPIC_BOUNDARY
   std::vector<SubPic>    getSubPics()  const                                              {return m_subPics;          };
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+  SubPic                 getSubPic(uint32_t idx) const                                    { return m_subPics[idx]; }
+#endif
   void                   initSubPic(const SPS &sps);
   SubPic                 getSubPicFromPos(const Position& pos)  const;
   SubPic                 getSubPicFromCU (const CodingUnit& cu) const;
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index d86528e0b..6db873ef7 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -50,6 +50,8 @@
 #include <assert.h>
 #include <cassert>
 
+#define JVET_Q0044_SLICE_IDX_WITH_SUBPICS                 1 // JVET-Q0044: slice index with subpictures
+
 #define JVET_Q0471_CHROMA_QT_SPLIT                        1 // JVET-Q0471: Chroma QT split
 
 #define JVET_P0117_PTL_SCALABILITY                        1 // JVET-P0117: sps_ptl_dpb_hrd_params_present_flag related syntax change, others in JVET-Q0786
diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp
index e15d1dc6e..82cd41d61 100644
--- a/source/Lib/DecoderLib/DecLib.cpp
+++ b/source/Lib/DecoderLib/DecLib.cpp
@@ -439,6 +439,10 @@ DecLib::DecLib()
   , m_vps( nullptr )
   , m_scalingListUpdateFlag(true)
   , m_PreScalingListAPSId(-1)
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+  , m_maxDecSubPicIdx(0)
+  , m_maxDecSliceAddrInSubPic(-1)
+#endif
 {
 #if ENABLE_SIMD_OPT_BUFFER
   g_pelBufOP.initPelBufOpsX86();
@@ -742,6 +746,10 @@ void DecLib::finishPicture(int& poc, PicList*& rpcListPic, MsgLevel msgl )
   poc                 = pcSlice->getPOC();
   rpcListPic          = &m_cListPic;
   m_bFirstSliceInPicture  = true; // TODO: immer true? hier ist irgendwas faul
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+  m_maxDecSubPicIdx = 0;
+  m_maxDecSliceAddrInSubPic = -1;
+#endif
 
   m_pcPic->destroyTempBuffers();
   m_pcPic->cs->destroyCoeffs();
@@ -1066,7 +1074,7 @@ void DecLib::xActivateParameterSets( const int layerId )
       THROW("Parameter set activation failed!");
     }
     
-#if JVET_O1143_SUBPIC_BOUNDARY
+#if JVET_O1143_SUBPIC_BOUNDARY && !JVET_Q0044_SLICE_IDX_WITH_SUBPICS
     PPS* nonconstPPS = m_parameterSetManager.getPPS(m_picHeader.getPPSId());
     nonconstPPS->initSubPic(*sps);
 #endif
@@ -1508,6 +1516,25 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl
   CHECK(sps == 0, "No SPS present");
   VPS *vps = m_parameterSetManager.getVPS(sps->getVPSId());
 #endif
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+  int currSubPicIdx = pps->getSubPicIdxFromSubPicId( m_apcSlicePilot->getSliceSubPicId() );
+  int currSliceAddr = m_apcSlicePilot->getSliceID();
+  for(int sp = 0; sp < currSubPicIdx; sp++)
+  {
+    currSliceAddr -= pps->getSubPic(sp).getNumSlicesInSubPic();
+  }
+  CHECK( currSubPicIdx < m_maxDecSubPicIdx, "Error in the order of coded slice NAL units of subpictures" );
+  CHECK( currSubPicIdx == m_maxDecSubPicIdx && currSliceAddr <= m_maxDecSliceAddrInSubPic, "Error in the order of coded slice NAL units within a subpicture" );
+  if( currSubPicIdx == m_maxDecSubPicIdx )
+  {
+    m_maxDecSliceAddrInSubPic = currSliceAddr;
+  }
+  if( currSubPicIdx > m_maxDecSubPicIdx )
+  {
+    m_maxDecSubPicIdx = currSubPicIdx; 
+    m_maxDecSliceAddrInSubPic = currSliceAddr;
+  }
+#endif
 #if JVET_P0097_REMOVE_VPS_DEP_NONSCALABLE_LAYER
   if ((sps->getVPSId() == 0) && (m_prevLayerID != MAX_INT))
   {
diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h
index 4f60dc184..0a0dd9d5a 100644
--- a/source/Lib/DecoderLib/DecLib.h
+++ b/source/Lib/DecoderLib/DecLib.h
@@ -146,6 +146,10 @@ private:
   VPS*                    m_vps;
   bool                    m_scalingListUpdateFlag;
   int                     m_PreScalingListAPSId;
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+  int                     m_maxDecSubPicIdx;
+  int                     m_maxDecSliceAddrInSubPic;
+#endif
 
 #if JVET_O1143_SUBPIC_BOUNDARY
 public:
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index 231d771c0..08126b695 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -2605,6 +2605,10 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag
     CHECK(pps->getCtuSize() != sps->getCTUSize(), "PPS CTU size does not match CTU size in SPS");
   }
 
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+  pps->initSubPic(*sps);
+#endif
+
 #if !JVET_Q0119_CLEANUPS
   // sub-picture IDs
   if( sps->getSubPicIdPresentFlag() ) 
@@ -3682,17 +3686,37 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, PicHeader* picHeader, Par
     uint32_t sliceAddr;
 
     // slice address is the index of the slice within the current sub-picture
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+    uint32_t currSubPicIdx = pps->getSubPicIdxFromSubPicId( pcSlice->getSliceSubPicId() );
+    SubPic currSubPic = pps->getSubPic(currSubPicIdx);
+    if( currSubPic.getNumSlicesInSubPic() > 1 )
+#else
     if( pps->getNumSlicesInPic() > 1 ) 
+#endif
     {
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+      int bitsSliceAddress = ceilLog2(currSubPic.getNumSlicesInSubPic());  
+#else
       int bitsSliceAddress = ceilLog2(pps->getNumSlicesInPic());  // change to NumSlicesInSubPic when available
+#endif
       READ_CODE(bitsSliceAddress, uiCode, "slice_address");  sliceAddr = uiCode;
       CHECK(sliceAddr >= pps->getNumSlicesInPic(), "Invalid slice address");
     }
     else {
       sliceAddr = 0;
     }
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+    uint32_t picLevelSliceIdx = sliceAddr;
+    for(int subpic = 0; subpic < currSubPicIdx; subpic++)
+    {
+      picLevelSliceIdx += pps->getSubPic(subpic).getNumSlicesInSubPic();
+    }
+    pcSlice->setSliceMap( pps->getSliceMap(picLevelSliceIdx) );
+    pcSlice->setSliceID(picLevelSliceIdx);
+#else
     pcSlice->setSliceMap( pps->getSliceMap(sliceAddr) );
     pcSlice->setSliceID(sliceAddr);
+#endif
   }
 
 #if JVET_Q0819_PH_CHANGES
diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp
index ea48b9e31..36f9cb5e7 100644
--- a/source/Lib/EncoderLib/EncGOP.cpp
+++ b/source/Lib/EncoderLib/EncGOP.cpp
@@ -2809,6 +2809,23 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
       for(uint32_t sliceIdx = 0; sliceIdx < pcPic->cs->pps->getNumSlicesInPic(); sliceIdx++ )
       {
         pcSlice->setSliceMap( pcPic->cs->pps->getSliceMap( sliceIdx ) );
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+	if( pcPic->cs->pps->getRectSliceFlag() )
+	{
+          Position firstCtu;
+          firstCtu.x = pcSlice->getFirstCtuRsAddrInSlice() % pcPic->cs->pps->getPicWidthInCtu();
+          firstCtu.y = pcSlice->getFirstCtuRsAddrInSlice() / pcPic->cs->pps->getPicWidthInCtu();
+          int subPicIdx = 0;
+          for(int sp = 0; sp < pcPic->cs->pps->getNumSubPics(); sp++)
+          {
+            if(pcPic->cs->pps->getSubPic(sp).containsCtu(firstCtu))
+            {
+              subPicIdx = sp;
+            }
+          }
+          pcSlice->setSliceSubPicId( pcPic->cs->pps->getSubPic(subPicIdx).getSubPicID() );
+	}
+#endif
         m_pcSliceEncoder->precompressSlice( pcPic );
         m_pcSliceEncoder->compressSlice   ( pcPic, false, false );
 
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index b58fa77ad..b1b5618c5 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -1480,6 +1480,18 @@ void EncLib::xInitSPS( SPS& sps, VPS& vps )
       sps.setLoopFilterAcrossSubpicEnabledFlag(i, m_loopFilterAcrossSubpicEnabledFlag[i]);
     }
   }
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+  else   //In that case, there is only one subpicture that contains the whole picture
+  {
+    sps.setNumSubPics(1);
+    sps.setSubPicCtuTopLeftX(0, 0);
+    sps.setSubPicCtuTopLeftY(0, 0);
+    sps.setSubPicWidth(0, m_iSourceWidth);
+    sps.setSubPicHeight(0, m_iSourceHeight);
+    sps.setSubPicTreatedAsPicFlag(0, 1);
+    sps.setLoopFilterAcrossSubpicEnabledFlag(0, 0);
+  }
+#endif
 #if JVET_Q0119_CLEANUPS
   sps.setSubPicIdMappingExplicitlySignalledFlag(m_subPicIdMappingExplicitlySignalledFlag);
   if (m_subPicIdMappingExplicitlySignalledFlag)
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index fc5f52b73..fab86f38a 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -2618,11 +2618,26 @@ void HLSWriter::codeSliceHeader         ( Slice* pcSlice )
   else 
   {
     // slice address is the index of the slice within the current sub-picture
+#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS
+    uint32_t currSubPicIdx = pcSlice->getPPS()->getSubPicIdxFromSubPicId( pcSlice->getSliceSubPicId() );
+    SubPic currSubPic = pcSlice->getPPS()->getSubPic(currSubPicIdx);
+    if( currSubPic.getNumSlicesInSubPic() > 1 ) 
+    {
+      int numSlicesInPreviousSubPics = 0;
+      for(int sp = 0; sp < currSubPicIdx; sp++)
+      {
+        numSlicesInPreviousSubPics += pcSlice->getPPS()->getSubPic(sp).getNumSlicesInSubPic();
+      }
+      int bitsSliceAddress = ceilLog2(currSubPic.getNumSlicesInSubPic());
+      WRITE_CODE( pcSlice->getSliceID() - numSlicesInPreviousSubPics, bitsSliceAddress, "slice_address");
+    }
+#else
     if( pcSlice->getPPS()->getNumSlicesInPic() > 1 ) 
     {
       int bitsSliceAddress = ceilLog2(pcSlice->getPPS()->getNumSlicesInPic());  // change to NumSlicesInSubPic when available
       WRITE_CODE( pcSlice->getSliceID(), bitsSliceAddress, "slice_address");
     }
+#endif
   }
 
 #if JVET_Q0819_PH_CHANGES
-- 
GitLab