From 3cdbf802e9cdf6b4bf0e0a07f02c57a4266fbef2 Mon Sep 17 00:00:00 2001
From: Vadim Seregin <vseregin@qti.qualcomm.com>
Date: Mon, 27 Jan 2020 17:08:16 -0800
Subject: [PATCH] JVET-Q0814: DPB requirements as for a single layer

---
 source/App/DecoderApp/DecApp.cpp     |  64 ++++++++++-
 source/App/DecoderApp/DecApp.h       |   8 ++
 source/App/DecoderApp/DecAppCfg.cpp  |   4 +-
 source/App/DecoderApp/DecAppCfg.h    |   2 +-
 source/App/EncoderApp/EncApp.cpp     |   7 ++
 source/App/EncoderApp/EncAppCfg.cpp  |   4 +-
 source/App/EncoderApp/EncAppCfg.h    |   3 +
 source/Lib/CommonLib/Slice.cpp       | 158 ++++++++++++++++++++++++++-
 source/Lib/CommonLib/Slice.h         |  66 ++++++++---
 source/Lib/CommonLib/TypeDef.h       |   1 +
 source/Lib/DecoderLib/DecLib.cpp     |  26 ++++-
 source/Lib/DecoderLib/DecLib.h       |   6 +-
 source/Lib/DecoderLib/VLCReader.cpp  |  70 ++++++++++++
 source/Lib/EncoderLib/EncCfg.h       |   4 +
 source/Lib/EncoderLib/EncLib.cpp     | 147 ++++++++++++++++++++++++-
 source/Lib/EncoderLib/EncLib.h       |  14 ++-
 source/Lib/EncoderLib/EncLibCommon.h |   7 +-
 source/Lib/EncoderLib/VLCWriter.cpp  |  52 +++++++++
 18 files changed, 614 insertions(+), 29 deletions(-)

diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp
index 69d4b1f7c..8d77c13a2 100644
--- a/source/App/DecoderApp/DecApp.cpp
+++ b/source/App/DecoderApp/DecApp.cpp
@@ -152,7 +152,11 @@ uint32_t DecApp::decode()
         }
 
         // parse NAL unit syntax if within target decoding layer
+#if JVET_Q0814_DPB
+        if( ( m_iMaxTemporalLayer < 0 || nalu.m_temporalId <= m_iMaxTemporalLayer ) && xIsNaluWithinTargetDecLayerIdSet( &nalu ) )
+#else
         if ((m_iMaxTemporalLayer < 0 || nalu.m_temporalId <= m_iMaxTemporalLayer) && isNaluWithinTargetDecLayerIdSet(&nalu))
+#endif
         {
           if (bPicSkipped)
           {
@@ -169,7 +173,13 @@ uint32_t DecApp::decode()
           m_cDecLib.decode(nalu, m_iSkipFrame, m_iPOCLastDisplay);
           if (nalu.m_nalUnitType == NAL_UNIT_VPS)
           {
+#if JVET_Q0814_DPB
+            m_cDecLib.deriveTargetOutputLayerSet( m_targetOlsIdx );
+            m_targetDecLayerIdSet = m_cDecLib.getVPS()->m_targetLayerIdSet;
+            m_targetOutputLayerIdSet = m_cDecLib.getVPS()->m_targetOutputLayerIdSet;
+#else
             deriveOutputLayerSet();
+#endif
           }
         }
         else
@@ -219,7 +229,11 @@ uint32_t DecApp::decode()
         }
 
         std::string reconFileName = m_reconFileName;
+#if JVET_Q0814_DPB
+        if( m_reconFileName.compare( "/dev/null" ) && m_cDecLib.getVPS() != nullptr && m_cDecLib.getVPS()->getMaxLayers() > 1 && xIsNaluWithinTargetOutputLayerIdSet( &nalu ) )
+#else
         if (m_reconFileName.compare("/dev/null") && (m_cDecLib.getVPS() != nullptr) && (m_cDecLib.getVPS()->getMaxLayers() > 1) && (isNaluWithinTargetOutputLayerIdSet(&nalu)))
+#endif
         {
           size_t pos = reconFileName.find_last_of('.');
           if (pos != string::npos)
@@ -231,10 +245,17 @@ uint32_t DecApp::decode()
             reconFileName.append( std::to_string( nalu.m_nuhLayerId ) );
           }
         }
+#if JVET_Q0814_DPB
+        if( ( m_cDecLib.getVPS() != nullptr && ( m_cDecLib.getVPS()->getMaxLayers() == 1 || xIsNaluWithinTargetOutputLayerIdSet( &nalu ) ) ) || m_cDecLib.getVPS() == nullptr )
+        {
+          m_cVideoIOYuvReconFile[nalu.m_nuhLayerId].open( reconFileName, true, m_outputBitDepth, m_outputBitDepth, bitDepths.recon ); // write mode
+        }
+#else
         if(((m_cDecLib.getVPS() != nullptr) &&
               ((m_cDecLib.getVPS()->getMaxLayers() == 1) || (isNaluWithinTargetOutputLayerIdSet(&nalu)))) ||
             (m_cDecLib.getVPS() == nullptr))
         m_cVideoIOYuvReconFile[nalu.m_nuhLayerId].open(reconFileName, true, m_outputBitDepth, m_outputBitDepth, bitDepths.recon); // write mode
+#endif
       }
       // write reconstruction to file
       if( bNewPicture )
@@ -279,6 +300,7 @@ uint32_t DecApp::decode()
   return nRet;
 }
 
+#if !JVET_Q0814_DPB
 bool DecApp::deriveOutputLayerSet()
 {
   int vps_max_layers_minus1 = m_cDecLib.getVPS()->getMaxLayers() - 1;
@@ -443,6 +465,7 @@ bool DecApp::deriveOutputLayerSet()
 
   return true;
 }
+#endif
 
 /**
  - lookahead through next NAL units to determine if current NAL unit is the first NAL unit in a new picture
@@ -703,6 +726,21 @@ void DecApp::xWriteOutput( PicList* pcListPic, uint32_t tId )
   uint32_t maxDecPicBufferingHighestTid;
   uint32_t maxNrSublayers = activeSPS->getMaxTLayers();
 
+#if JVET_Q0814_DPB
+  const VPS* referredVPS = pcListPic->front()->cs->vps;
+  const int temporalId = ( m_iMaxTemporalLayer == -1 || m_iMaxTemporalLayer >= maxNrSublayers ) ? maxNrSublayers - 1 : m_iMaxTemporalLayer;
+
+  if( referredVPS == nullptr || referredVPS->m_numLayersInOls[referredVPS->m_targetOlsIdx] == 1 )
+  {
+    numReorderPicsHighestTid = activeSPS->getNumReorderPics( temporalId );
+    maxDecPicBufferingHighestTid = activeSPS->getMaxDecPicBuffering( temporalId );
+  }
+  else
+  {
+    numReorderPicsHighestTid = referredVPS->getNumReorderPics( temporalId );
+    maxDecPicBufferingHighestTid = referredVPS->getMaxDecPicBuffering( temporalId );
+  }
+#else
   if(m_iMaxTemporalLayer == -1 || m_iMaxTemporalLayer >= maxNrSublayers)
   {
     numReorderPicsHighestTid = activeSPS->getNumReorderPics(maxNrSublayers-1);
@@ -713,6 +751,7 @@ void DecApp::xWriteOutput( PicList* pcListPic, uint32_t tId )
     numReorderPicsHighestTid = activeSPS->getNumReorderPics(m_iMaxTemporalLayer);
     maxDecPicBufferingHighestTid = activeSPS->getMaxDecPicBuffering(m_iMaxTemporalLayer);
   }
+#endif
 
   while (iterPic != pcListPic->end())
   {
@@ -1020,6 +1059,29 @@ void DecApp::xFlushOutput( PicList* pcListPic, const int layerId )
 
 /** \param nalu Input nalu to check whether its LayerId is within targetDecLayerIdSet
  */
+#if JVET_Q0814_DPB
+bool DecApp::xIsNaluWithinTargetDecLayerIdSet( const InputNALUnit* nalu ) const
+{
+  if( !m_targetDecLayerIdSet.size() ) // By default, the set is empty, meaning all LayerIds are allowed
+  {
+    return true;
+  }
+
+  return std::find( m_targetDecLayerIdSet.begin(), m_targetDecLayerIdSet.end(), nalu->m_nuhLayerId ) != m_targetDecLayerIdSet.end();
+}
+
+/** \param nalu Input nalu to check whether its LayerId is within targetOutputLayerIdSet
+ */
+bool DecApp::xIsNaluWithinTargetOutputLayerIdSet( const InputNALUnit* nalu ) const
+{
+  if( !m_targetOutputLayerIdSet.size() ) // By default, the set is empty, meaning all LayerIds are allowed
+  {
+    return true;
+  }
+
+  return std::find( m_targetOutputLayerIdSet.begin(), m_targetOutputLayerIdSet.end(), nalu->m_nuhLayerId ) != m_targetOutputLayerIdSet.end();
+}
+#else
 bool DecApp::isNaluWithinTargetDecLayerIdSet( InputNALUnit* nalu )
 {
   if ( m_targetDecLayerIdSet.size() == 0 ) // By default, the set is empty, meaning all LayerIds are allowed
@@ -1053,6 +1115,6 @@ bool DecApp::isNaluWithinTargetOutputLayerIdSet(InputNALUnit* nalu)
   }
   return false;
 }
-
+#endif
 
 //! \}
diff --git a/source/App/DecoderApp/DecApp.h b/source/App/DecoderApp/DecApp.h
index 2d5c0fcda..1675fc108 100644
--- a/source/App/DecoderApp/DecApp.h
+++ b/source/App/DecoderApp/DecApp.h
@@ -70,6 +70,12 @@ private:
   ColourRemapping m_cColourRemapping;             ///< colour remapping handler
 #endif
 
+#if JVET_Q0814_DPB
+private:
+  bool  xIsNaluWithinTargetDecLayerIdSet( const InputNALUnit* nalu ) const; ///< check whether given Nalu is within targetDecLayerIdSet
+  bool  xIsNaluWithinTargetOutputLayerIdSet( const InputNALUnit* nalu ) const; ///< check whether given Nalu is within targetOutputLayerIdSet
+#endif
+
 public:
   DecApp();
   virtual ~DecApp         ()  {}
@@ -81,9 +87,11 @@ private:
   void  xDestroyDecLib    (); ///< destroy internal classes
   void  xWriteOutput      ( PicList* pcListPic , uint32_t tId); ///< write YUV to file
   void  xFlushOutput( PicList* pcListPic, const int layerId = NOT_VALID ); ///< flush all remaining decoded pictures to file
+#if !JVET_Q0814_DPB
   bool  isNaluWithinTargetDecLayerIdSet ( InputNALUnit* nalu ); ///< check whether given Nalu is within targetDecLayerIdSet
   bool  isNaluWithinTargetOutputLayerIdSet(InputNALUnit* nalu); ///< check whether given Nalu is within targetOutputLayerIdSet
   bool  deriveOutputLayerSet(); ///< derive OLS and layer sets
+#endif
   bool  isNewPicture(ifstream *bitstreamFile, class InputByteStream *bytestream);  ///< check if next NAL unit will be the first NAL unit from a new picture
   bool  isNewAccessUnit(bool newPicture, ifstream *bitstreamFile, class InputByteStream *bytestream);  ///< check if next NAL unit will be the first NAL unit from a new access unit
 };
diff --git a/source/App/DecoderApp/DecAppCfg.cpp b/source/App/DecoderApp/DecAppCfg.cpp
index 310251e87..fdd2bf7fa 100644
--- a/source/App/DecoderApp/DecAppCfg.cpp
+++ b/source/App/DecoderApp/DecAppCfg.cpp
@@ -87,7 +87,7 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] )
   ("OutputBitDepthC,d",         m_outputBitDepth[CHANNEL_TYPE_CHROMA], 0,          "bit depth of YUV output chroma component (default: use luma output bit-depth)")
   ("OutputColourSpaceConvert",  outputColourSpaceConvert,              string(""), "Colour space conversion to apply to input 444 video. Permitted values are (empty string=UNCHANGED) " + getListOfColourSpaceConverts(false))
   ("MaxTemporalLayer,t",        m_iMaxTemporalLayer,                   -1,         "Maximum Temporal Layer to be decoded. -1 to decode all layers")
-  ("TargetOutputLayerSet,p",    m_iTargetOLS,                          -1,         "Target output layer set.")
+  ("TargetOutputLayerSet,p",    m_targetOlsIdx,                          -1,       "Target output layer set index")
   ("SEIDecodedPictureHash,-dph",m_decodedPictureHashSEIEnabled,        1,          "Control handling of decoded picture hash SEI messages\n"
                                                                                    "\t1: check hash in SEI messages if available in the bitstream\n"
                                                                                    "\t0: ignore SEI message")
@@ -226,7 +226,7 @@ DecAppCfg::DecAppCfg()
 , m_iSkipFrame(0)
 // m_outputBitDepth array initialised below
 , m_outputColourSpaceConvert(IPCOLOURSPACE_UNCHANGED)
-, m_iTargetOLS(0)
+, m_targetOlsIdx(0)
 , m_iMaxTemporalLayer(-1)
 , m_decodedPictureHashSEIEnabled(0)
 , m_decodedNoDisplaySEIEnabled(false)
diff --git a/source/App/DecoderApp/DecAppCfg.h b/source/App/DecoderApp/DecAppCfg.h
index cc45bfdd8..d1f1fffb5 100644
--- a/source/App/DecoderApp/DecAppCfg.h
+++ b/source/App/DecoderApp/DecAppCfg.h
@@ -61,7 +61,7 @@ protected:
   int           m_iSkipFrame;                           ///< counter for frames prior to the random access point to skip
   int           m_outputBitDepth[MAX_NUM_CHANNEL_TYPE]; ///< bit depth used for writing output
   InputColourSpaceConversion m_outputColourSpaceConvert;
-  int           m_iTargetOLS;                         ///< target output layer set
+  int           m_targetOlsIdx;                       ///< target output layer set
   std::vector<int> m_targetOutputLayerIdSet;          ///< set of LayerIds to be outputted           
   int           m_iMaxTemporalLayer;                  ///< maximum temporal layer to be decoded
   int           m_decodedPictureHashSEIEnabled;       ///< Checksum(3)/CRC(2)/MD5(1)/disable(0) acting on decoded picture hash SEI message
diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 77f765178..40fa767e9 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -75,7 +75,12 @@ EncApp::~EncApp()
 
 void EncApp::xInitLibCfg()
 {
+#if JVET_Q0814_DPB
+  VPS& vps = *m_cEncLib.getVPS();
+  vps.m_targetOlsIdx = m_targetOlsIdx;
+#else
   VPS vps;
+#endif
 
   vps.setMaxLayers( m_maxLayers );
 
@@ -171,7 +176,9 @@ void EncApp::xInitLibCfg()
     }
   }
   vps.setVPSExtensionFlag                                        ( false );
+#if !JVET_Q0814_DPB
   m_cEncLib.setVPS(&vps);
+#endif
   m_cEncLib.setProfile                                           ( m_profile);
   m_cEncLib.setLevel                                             ( m_levelTier, m_level);
   m_cEncLib.setNumSubProfile                                     ( m_numSubProfile );
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index cdad7cff4..3e09fc687 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -1364,7 +1364,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ( "SwitchPocPeriod",                                m_switchPocPeriod,                            0, "Switch POC period for RPR" )
   ( "UpscaledOutput",                                 m_upscaledOutput,                             0, "Output upscaled (2), decoded but in full resolution buffer (1) or decoded cropped (0, default) picture for RPR" )
   ( "MaxLayers",                                      m_maxLayers,                                  1, "Max number of layers" )
-
+#if JVET_Q0814_DPB
+  ( "TargetOutputLayerSet,p",                         m_targetOlsIdx,                              -1, "Target output layer set index" )
+#endif
   ;
   opts.addOptions()
   ( "MaxSublayers",                                   m_maxSublayers,                               1, "Max number of Sublayers")
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index 4ce37e402..f38ba8c10 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -677,6 +677,9 @@ protected:
   std::map<int, double> m_gopBasedTemporalFilterStrengths;             ///< Filter strength per frame for the GOP-based Temporal Filter
 
   int         m_maxLayers;
+#if JVET_Q0814_DPB
+  int         m_targetOlsIdx;
+#endif
 
   int         m_layerId[MAX_VPS_LAYERS];
   int         m_layerIdx;
diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp
index e923fdf52..fd57555bd 100644
--- a/source/Lib/CommonLib/Slice.cpp
+++ b/source/Lib/CommonLib/Slice.cpp
@@ -1512,7 +1512,13 @@ VPS::VPS()
   , m_vpsEachLayerIsAnOlsFlag (1)
   , m_vpsOlsModeIdc (0)
   , m_vpsNumOutputLayerSets (1)
-, m_vpsExtensionFlag()
+  , m_vpsExtensionFlag()
+#if JVET_Q0814_DPB
+  , m_numDpbParams( 0 )
+  , m_sublayerDpbParamsPresentFlag( false )
+  , m_targetOlsIdx( -1 )
+  , m_totalNumOLSs( 0 )
+#endif
 {
   for (int i = 0; i < MAX_VPS_LAYERS; i++)
   {
@@ -1538,6 +1544,156 @@ VPS::~VPS()
 {
 }
 
+#if JVET_Q0814_DPB
+void VPS::deriveOutputLayerSets()
+{
+  if( m_uiMaxLayers == 1 )
+  {
+    m_totalNumOLSs = 1;
+  }
+  else if( m_vpsEachLayerIsAnOlsFlag || m_vpsOlsModeIdc < 2 )
+  {
+    m_totalNumOLSs = m_uiMaxLayers;
+  }
+  else if( m_vpsOlsModeIdc == 2 )
+  {
+    m_totalNumOLSs = m_vpsNumOutputLayerSets;
+  }
+
+  m_olsDpbParamsIdx.resize( m_totalNumOLSs );
+  m_olsDpbPicSize.resize( m_totalNumOLSs, Size(0, 0) );
+  m_numOutputLayersInOls.resize( m_totalNumOLSs );
+  m_numLayersInOls.resize( m_totalNumOLSs );
+  m_outputLayerIdInOls.resize( m_totalNumOLSs, std::vector<int>( m_uiMaxLayers, NOT_VALID ) );
+  m_layerIdInOls.resize( m_totalNumOLSs, std::vector<int>( m_uiMaxLayers, NOT_VALID ) );
+
+  std::vector<int> numRefLayers( m_uiMaxLayers );
+  std::vector<std::vector<int>> outputLayerIdx( m_totalNumOLSs, std::vector<int>( m_uiMaxLayers, NOT_VALID ) );
+  std::vector<std::vector<int>> layerIncludedInOlsFlag( m_totalNumOLSs, std::vector<int>( m_uiMaxLayers, 0 ) );
+  std::vector<std::vector<int>> dependencyFlag( m_uiMaxLayers, std::vector<int>( m_uiMaxLayers, NOT_VALID ) );
+  std::vector<std::vector<int>> refLayerIdx( m_uiMaxLayers, std::vector<int>( m_uiMaxLayers, NOT_VALID ) );
+
+  for( int i = 0; i < m_uiMaxLayers; i++ )
+  {
+    int r = 0;
+
+    for( int j = 0; j < m_uiMaxLayers; j++ )
+    {
+      dependencyFlag[i][j] = m_vpsDirectRefLayerFlag[i][j];
+
+      for( int k = 0; k < i; k++ )
+      {
+        if( m_vpsDirectRefLayerFlag[i][k] && dependencyFlag[k][j] )
+        {
+          dependencyFlag[i][j] = 1;
+        }
+      }
+
+      if( dependencyFlag[i][j] )
+      {
+        refLayerIdx[i][r++] = j;
+      }
+    }
+
+    numRefLayers[i] = r;
+  }
+
+  m_numOutputLayersInOls[0] = 1;
+  m_outputLayerIdInOls[0][0] = m_vpsLayerId[0];
+
+  for( int i = 1; i < m_totalNumOLSs; i++ )
+  {
+    if( m_vpsEachLayerIsAnOlsFlag || m_vpsOlsModeIdc == 0 )
+    {
+      m_numOutputLayersInOls[i] = 1;
+      m_outputLayerIdInOls[i][0] = m_vpsLayerId[i];
+    }
+    else if( m_vpsOlsModeIdc == 1 )
+    {
+      m_numOutputLayersInOls[i] = i + 1;
+
+      for( int j = 0; j < m_numOutputLayersInOls[i]; j++ )
+      {
+        m_outputLayerIdInOls[i][j] = m_vpsLayerId[j];
+      }
+    }
+    else if( m_vpsOlsModeIdc == 2 )
+    {
+      int j = 0;
+      for( int k = 0; k < m_uiMaxLayers; k++ )
+      {
+        if( m_vpsOlsOutputLayerFlag[i][k] )
+        {
+          layerIncludedInOlsFlag[i][k] = 1;
+          outputLayerIdx[i][j] = k;
+          m_outputLayerIdInOls[i][j++] = m_vpsLayerId[k];
+        }
+      }
+      m_numOutputLayersInOls[i] = j;
+
+      for( j = 0; j < m_numOutputLayersInOls[i]; j++ )
+      {
+        int idx = outputLayerIdx[i][j];
+        for( int k = 0; k < numRefLayers[idx]; k++ )
+        {
+          layerIncludedInOlsFlag[i][refLayerIdx[idx][k]] = 1;
+        }
+      }
+    }
+  }
+
+  m_numLayersInOls[0] = 1;
+  m_layerIdInOls[0][0] = m_vpsLayerId[0];
+
+  for( int i = 1; i < m_totalNumOLSs; i++ )
+  {
+    if( m_vpsEachLayerIsAnOlsFlag )
+    {
+      m_numLayersInOls[i] = 1;
+      m_layerIdInOls[i][0] = m_vpsLayerId[i];
+    }
+    else if( m_vpsOlsModeIdc == 0 || m_vpsOlsModeIdc == 1 )
+    {
+      m_numLayersInOls[i] = i + 1;
+      for( int j = 0; j < m_numLayersInOls[i]; j++ )
+      {
+        m_layerIdInOls[i][j] = m_vpsLayerId[j];
+      }
+    }
+    else if( m_vpsOlsModeIdc == 2 )
+    {
+      int j = 0;
+      for( int k = 0; k < m_uiMaxLayers; k++ )
+      {
+        if( layerIncludedInOlsFlag[i][k] )
+        {
+          m_layerIdInOls[i][j++] = m_vpsLayerId[k];
+        }
+      }
+
+      m_numLayersInOls[i] = j;
+    }
+  }
+}
+
+void VPS::deriveTargetOutputLayerSet( int targetOlsIdx )
+{
+  m_targetOlsIdx = targetOlsIdx < 0 ? m_uiMaxLayers - 1 : targetOlsIdx;
+  m_targetOutputLayerIdSet.clear();
+  m_targetLayerIdSet.clear();
+
+  for( int i = 0; i < m_numOutputLayersInOls[m_targetOlsIdx]; i++ )
+  {
+    m_targetOutputLayerIdSet.push_back( m_outputLayerIdInOls[m_targetOlsIdx][i] );
+  }
+
+  for( int i = 0; i < m_numLayersInOls[m_targetOlsIdx]; i++ )
+  {
+    m_targetLayerIdSet.push_back( m_layerIdInOls[m_targetOlsIdx][i] );
+  }
+}
+#endif
+
 // ------------------------------------------------------------------------------------------------
 // Picture Header
 // ------------------------------------------------------------------------------------------------
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index b95485113..7f042017e 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -71,6 +71,14 @@ typedef std::list<Picture*> PicList;
 // Class definition
 // ====================================================================================================================
 
+#if JVET_Q0814_DPB
+struct DpbParameters
+{
+  int m_maxDecPicBuffering[MAX_TLAYER] = { 0 };
+  int m_numReorderPics[MAX_TLAYER] = { 0 };
+  int m_maxLatencyIncreasePlus1[MAX_TLAYER] = { 0 };
+};
+#endif
 
 class ReferencePictureList
 {
@@ -748,8 +756,6 @@ public:
   const ProfileTierLevel& getProfileTierLevel(int idx) const            { return m_profileTierLevel[idx]; }
 };
 
-
-
 class VPS
 {
 private:
@@ -773,6 +779,24 @@ private:
   uint32_t              m_interLayerRefIdx[MAX_VPS_LAYERS][MAX_VPS_LAYERS];
   bool                  m_vpsExtensionFlag;
 
+#if JVET_Q0814_DPB
+  std::vector<Size>             m_olsDpbPicSize;
+  std::vector<int>              m_olsDpbParamsIdx;
+  std::vector<std::vector<int>> m_outputLayerIdInOls;
+public:
+  int                           m_totalNumOLSs;
+  int                           m_numDpbParams;
+  std::vector<DpbParameters>    m_dpbParameters;
+  bool                          m_sublayerDpbParamsPresentFlag;
+  std::vector<int>              m_dpbMaxTemporalId;
+  std::vector<int>              m_targetOutputLayerIdSet;          ///< set of LayerIds to be outputted
+  std::vector<int>              m_targetLayerIdSet;                ///< set of LayerIds to be included in the sub-bitstream extraction process.
+  int                           m_targetOlsIdx;
+  std::vector<int>              m_numOutputLayersInOls;
+  std::vector<int>              m_numLayersInOls;
+  std::vector<std::vector<int>> m_layerIdInOls;
+#endif
+
 public:
                     VPS();
 
@@ -824,6 +848,22 @@ public:
 
   bool              getVPSExtensionFlag() const                          { return m_vpsExtensionFlag;                                 }
   void              setVPSExtensionFlag(bool t)                          { m_vpsExtensionFlag = t;                                    }
+
+#if JVET_Q0814_DPB
+  int               getMaxDecPicBuffering( int temporalId ) const        { return m_dpbParameters[m_olsDpbParamsIdx[m_targetOlsIdx]].m_maxDecPicBuffering[temporalId]; }
+  int               getNumReorderPics( int temporalId ) const            { return m_dpbParameters[m_olsDpbParamsIdx[m_targetOlsIdx]].m_numReorderPics[temporalId]; }
+  int               getTotalNumOLSs() const                              { return m_totalNumOLSs; }
+  Size              getOlsDpbPicSize( int olsIdx ) const                 { return m_olsDpbPicSize[olsIdx];          }
+  void              setOlsDpbPicSize( int olsIdx, Size size )            { m_olsDpbPicSize[olsIdx] = size;          }
+  void              setOlsDpbPicWidth( int olsIdx, int width )           { m_olsDpbPicSize[olsIdx].width = width;   }
+  void              setOlsDpbPicHeight( int olsIdx, int height )         { m_olsDpbPicSize[olsIdx].height = height; }
+
+  int               getOlsDpbParamsIdx( int olsIdx ) const               { return m_olsDpbParamsIdx[olsIdx];        }
+  void              setOlsDpbParamsIdx( int olsIdx, int paramIdx )       { m_olsDpbParamsIdx[olsIdx] = paramIdx;    }
+  
+  void              deriveOutputLayerSets();
+  void              deriveTargetOutputLayerSet( int targetOlsIdx );
+#endif
 };
 
 class Window
@@ -1092,13 +1132,13 @@ private:
   bool              m_BdofControlPresentFlag;
   bool              m_DmvrControlPresentFlag;
   bool              m_ProfControlPresentFlag;
-  uint32_t              m_uiBitsForPOC;
-  uint32_t              m_numLongTermRefPicSPS;
-  uint32_t              m_ltRefPicPocLsbSps[MAX_NUM_LONG_TERM_REF_PICS];
+  uint32_t          m_uiBitsForPOC;
+  uint32_t          m_numLongTermRefPicSPS;
+  uint32_t          m_ltRefPicPocLsbSps[MAX_NUM_LONG_TERM_REF_PICS];
   bool              m_usedByCurrPicLtSPSFlag[MAX_NUM_LONG_TERM_REF_PICS];
   uint32_t          m_log2MaxTbSize;
-  bool             m_useWeightPred;                     //!< Use of Weighting Prediction (P_SLICE)
-  bool             m_useWeightedBiPred;                 //!< Use of Weighting Bi-Prediction (B_SLICE)
+  bool              m_useWeightPred;                     //!< Use of Weighting Prediction (P_SLICE)
+  bool              m_useWeightedBiPred;                 //!< Use of Weighting Bi-Prediction (B_SLICE)
 
   bool              m_saoEnabledFlag;
 
@@ -1110,8 +1150,8 @@ private:
   unsigned          m_numHorVirtualBoundaries;                         //!< number of horizontal virtual boundaries
   unsigned          m_virtualBoundariesPosX[3];                        //!< horizontal position of each vertical virtual boundary
   unsigned          m_virtualBoundariesPosY[3];                        //!< vertical position of each horizontal virtual boundary
-  uint32_t              m_uiMaxDecPicBuffering[MAX_TLAYER];
-  uint32_t              m_uiMaxLatencyIncreasePlus1[MAX_TLAYER];
+  uint32_t          m_uiMaxDecPicBuffering[MAX_TLAYER];
+  uint32_t          m_uiMaxLatencyIncreasePlus1[MAX_TLAYER];
 
 
   TimingInfo        m_timingInfo;
@@ -1364,10 +1404,10 @@ public:
   unsigned                getVirtualBoundariesPosX(unsigned idx) const                                    { CHECK( idx >= 3, "vitrual boundary index exceeds valid range" ); return m_virtualBoundariesPosX[idx]; }
   void                    setVirtualBoundariesPosY(unsigned u, unsigned idx)                              { CHECK( idx >= 3, "vitrual boundary index exceeds valid range" ); m_virtualBoundariesPosY[idx] = u;    }
   unsigned                getVirtualBoundariesPosY(unsigned idx) const                                    { CHECK( idx >= 3, "vitrual boundary index exceeds valid range" ); return m_virtualBoundariesPosY[idx]; }
-  uint32_t                    getMaxDecPicBuffering(uint32_t tlayer) const                                        { return m_uiMaxDecPicBuffering[tlayer];                               }
-  void                    setMaxDecPicBuffering( uint32_t ui, uint32_t tlayer )                                   { CHECK(tlayer >= MAX_TLAYER, "Invalid T-layer"); m_uiMaxDecPicBuffering[tlayer] = ui;    }
-  uint32_t                    getMaxLatencyIncreasePlus1(uint32_t tlayer) const                                   { return m_uiMaxLatencyIncreasePlus1[tlayer];                          }
-  void                    setMaxLatencyIncreasePlus1( uint32_t ui , uint32_t tlayer)                              { m_uiMaxLatencyIncreasePlus1[tlayer] = ui;                            }
+  uint32_t                getMaxDecPicBuffering(uint32_t tlayer) const                                    { return m_uiMaxDecPicBuffering[tlayer];                               }
+  void                    setMaxDecPicBuffering( uint32_t ui, uint32_t tlayer )                           { CHECK(tlayer >= MAX_TLAYER, "Invalid T-layer"); m_uiMaxDecPicBuffering[tlayer] = ui;    }
+  uint32_t                getMaxLatencyIncreasePlus1(uint32_t tlayer) const                               { return m_uiMaxLatencyIncreasePlus1[tlayer];                          }
+  void                    setMaxLatencyIncreasePlus1( uint32_t ui , uint32_t tlayer)                      { m_uiMaxLatencyIncreasePlus1[tlayer] = ui;                            }
 
   void                    setAffineAmvrEnabledFlag( bool val )                                            { m_affineAmvrEnabledFlag = val;                                       }
   bool                    getAffineAmvrEnabledFlag() const                                                { return m_affineAmvrEnabledFlag;                                      }
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 26ff96885..942f7ff00 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -50,6 +50,7 @@
 #include <assert.h>
 #include <cassert>
 
+#define JVET_Q0814_DPB                                    1 // JVET-Q0814: DPB capacity is based on picture units regardless of the resoltuion
 
 #define JVET_Q0147_JCCR_SIGNALLING                        1 // JVET-Q0147: Conditional signaling of sps_joint_cbcr_enabled_flag based on ChromaArrayType
 
diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp
index 6b62da634..de3141e9e 100644
--- a/source/Lib/DecoderLib/DecLib.cpp
+++ b/source/Lib/DecoderLib/DecLib.cpp
@@ -262,6 +262,15 @@ bool tryDecodePicture( Picture* pcEncPic, const int expectedPoc, const std::stri
             uint32_t maxNrSublayers = activeSPS->getMaxTLayers();
             uint32_t numReorderPicsHighestTid = activeSPS->getNumReorderPics(maxNrSublayers-1);
             uint32_t maxDecPicBufferingHighestTid =  activeSPS->getMaxDecPicBuffering(maxNrSublayers-1);
+#if JVET_Q0814_DPB
+            const VPS* referredVPS = pcListPic->front()->cs->vps;
+
+            if( referredVPS != nullptr && referredVPS->m_numLayersInOls[referredVPS->m_targetOlsIdx] > 1 )
+            {
+              numReorderPicsHighestTid = referredVPS->getNumReorderPics( maxNrSublayers - 1 );
+              maxDecPicBufferingHighestTid = referredVPS->getMaxDecPicBuffering( maxNrSublayers - 1 );
+            }
+#endif
 
             while (iterPic != pcListPic->end())
             {
@@ -491,7 +500,11 @@ void DecLib::deletePicBuffer ( )
 Picture* DecLib::xGetNewPicBuffer( const SPS &sps, const PPS &pps, const uint32_t temporalLayer, const int layerId )
 {
   Picture * pcPic = nullptr;
+#if JVET_Q0814_DPB
+  m_iMaxRefPicNum = ( m_vps == nullptr || m_vps->m_numLayersInOls[m_vps->m_targetOlsIdx] == 1 ) ? sps.getMaxDecPicBuffering( temporalLayer ) : m_vps->getMaxDecPicBuffering( temporalLayer );     // m_uiMaxDecPicBuffering has the space for the picture currently being decoded
+#else
   m_iMaxRefPicNum = sps.getMaxDecPicBuffering(temporalLayer);     // m_uiMaxDecPicBuffering has the space for the picture currently being decoded
+#endif
   if (m_cListPic.size() < (uint32_t)m_iMaxRefPicNum)
   {
     pcPic = new Picture();
@@ -1151,6 +1164,9 @@ void DecLib::xActivateParameterSets( const int layerId )
   Slice *pSlice = m_pcPic->slices[m_uiSliceSegmentIdx];
   const SPS *sps = pSlice->getSPS();
   const PPS *pps = pSlice->getPPS();
+#if JVET_Q0814_DPB
+  const VPS *vps = pSlice->getVPS();
+#endif
 
   if( !sps->getUseWP() )
   {
@@ -1164,7 +1180,7 @@ void DecLib::xActivateParameterSets( const int layerId )
 
   CHECK( ( pps->getPicWidthInLumaSamples() % ( std::max( 8, int( sps->getMaxCUWidth() >> ( sps->getMaxCodingDepth() - 1 ) ) ) ) ) != 0, "Coded frame width must be a multiple of Max(8, the minimum unit size)" );
   CHECK( ( pps->getPicHeightInLumaSamples() % ( std::max( 8, int( sps->getMaxCUHeight() >> ( sps->getMaxCodingDepth() - 1 ) ) ) ) ) != 0, "Coded frame height must be a multiple of Max(8, the minimum unit size)" );
-  if( !sps->getRprEnabledFlag() ) // subpics_present_flag is equal to 1 condition shall be added
+  if( !sps->getRprEnabledFlag() && sps->getSubPicPresentFlag() )
   {
     CHECK( pps->getPicWidthInLumaSamples() != sps->getMaxPicWidthInLumaSamples(), "When subpics_present_flag is equal to 1 or ref_pic_resampling_enabled_flag equal to 0, the value of pic_width_in_luma_samples shall be equal to pic_width_max_in_luma_samples." );
     CHECK( pps->getPicHeightInLumaSamples() != sps->getMaxPicHeightInLumaSamples(), "When subpics_present_flag is equal to 1 or ref_pic_resampling_enabled_flag equal to 0, the value of pic_height_in_luma_samples shall be equal to pic_height_max_in_luma_samples." );
@@ -1176,6 +1192,14 @@ void DecLib::xActivateParameterSets( const int layerId )
   {
     CHECK( sps->getWrapAroundEnabledFlag(), "Wraparound shall be disabled when the value of ( CtbSizeY / MinCbSizeY + 1) is less than or equal to ( pic_width_in_luma_samples / MinCbSizeY - 1 )" );
   }
+
+#if JVET_Q0814_DPB
+  if( vps->m_numOutputLayersInOls[vps->m_targetOlsIdx] > 1 )
+  {
+    CHECK( sps->getMaxPicWidthInLumaSamples() > vps->getOlsDpbPicSize( vps->m_targetOlsIdx ).width, "pic_width_max_in_luma_samples shall be less than or equal to the value of ols_dpb_pic_width[ i ]" );
+    CHECK( sps->getMaxPicHeightInLumaSamples() > vps->getOlsDpbPicSize( vps->m_targetOlsIdx ).height, "pic_height_max_in_luma_samples shall be less than or equal to the value of ols_dpb_pic_height[ i ]" );
+  }
+#endif
 }
 
 
diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h
index 7c9e0fa6b..304655f9a 100644
--- a/source/Lib/DecoderLib/DecLib.h
+++ b/source/Lib/DecoderLib/DecLib.h
@@ -106,7 +106,7 @@ private:
 #endif
   bool isRandomAccessSkipPicture(int& iSkipFrame,  int& iPOCLastDisplay);
   Picture*                m_pcPic;
-  uint32_t                    m_uiSliceSegmentIdx;
+  uint32_t                m_uiSliceSegmentIdx;
   uint32_t                m_prevLayerID;
   int                     m_prevPOC;
   int                     m_prevTid0POC;
@@ -183,6 +183,10 @@ public:
   bool isSliceNaluFirstInAU( bool newPicture, InputNALUnit &nalu );
 
   const VPS* getVPS()                     { return m_vps; }
+#if JVET_Q0814_DPB
+  void deriveTargetOutputLayerSet( const int targetOlsIdx ) { if( m_vps != nullptr ) m_vps->deriveTargetOutputLayerSet( targetOlsIdx ); }
+#endif
+
   void  initScalingList()
   {
     m_cTrQuantScalingList.init(nullptr, MAX_TB_SIZEY, false, false, false, false);
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index fd516bb03..9b3292a4d 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -1709,6 +1709,76 @@ void HLSyntaxReader::parseVPS(VPS* pcVPS)
       }
     }
   }
+
+#if JVET_Q0814_DPB
+  if( !pcVPS->getAllIndependentLayersFlag() )
+  {
+    READ_UVLC( uiCode, "vps_num_dpb_params" ); pcVPS->m_numDpbParams = uiCode;
+  }
+
+  if( pcVPS->m_numDpbParams > 0 && pcVPS->getMaxSubLayers() > 1 )
+  {
+    READ_FLAG( uiCode, "vps_sublayer_dpb_params_present_flag" ); pcVPS->m_sublayerDpbParamsPresentFlag = uiCode;
+  }
+
+  pcVPS->m_dpbParameters.resize( pcVPS->m_numDpbParams );
+
+  for( int i = 0; i < pcVPS->m_numDpbParams; i++ )
+  {
+    if( pcVPS->getMaxSubLayers() == 1 )
+    {
+      // When vps_max_sublayers_minus1 is equal to 0, the value of dpb_max_temporal_id[ i ] is inferred to be equal to 0.
+      pcVPS->m_dpbMaxTemporalId.push_back( 0 );
+    }
+    else
+    {
+      if( pcVPS->getAllLayersSameNumSublayersFlag() )
+      {
+        // When vps_max_sublayers_minus1 is greater than 0 and vps_all_layers_same_num_sublayers_flag is equal to 1, the value of dpb_max_temporal_id[ i ] is inferred to be equal to vps_max_sublayers_minus1.
+        pcVPS->m_dpbMaxTemporalId.push_back( pcVPS->getMaxSubLayers() - 1 );
+      }
+      else
+      {
+        READ_CODE( 3, uiCode, "dpb_max_temporal_id[i]" );  pcVPS->m_dpbMaxTemporalId.push_back( uiCode );
+      }
+    }
+
+    for( int j = ( pcVPS->m_sublayerDpbParamsPresentFlag ? 0 : pcVPS->m_dpbMaxTemporalId[i] ); j <= pcVPS->m_dpbMaxTemporalId[i]; j++ )
+    {
+      READ_UVLC( uiCode, "max_dec_pic_buffering_minus1[i]" );  pcVPS->m_dpbParameters[i].m_maxDecPicBuffering[j] = uiCode;
+      READ_UVLC( uiCode, "max_num_reorder_pics[i]" );          pcVPS->m_dpbParameters[i].m_numReorderPics[j] = uiCode;
+      READ_UVLC( uiCode, "max_latency_increase_plus1[i]" );    pcVPS->m_dpbParameters[i].m_maxLatencyIncreasePlus1[j] = uiCode;
+    }
+
+    for( int j = ( pcVPS->m_sublayerDpbParamsPresentFlag ? pcVPS->m_dpbMaxTemporalId[i] : 0 ); j < pcVPS->m_dpbMaxTemporalId[i]; j++ )
+    {
+      // When max_dec_pic_buffering_minus1[ i ] is not present for i in the range of 0 to maxSubLayersMinus1 - 1, inclusive, due to subLayerInfoFlag being equal to 0, it is inferred to be equal to max_dec_pic_buffering_minus1[ maxSubLayersMinus1 ].
+      pcVPS->m_dpbParameters[i].m_maxDecPicBuffering[j] = pcVPS->m_dpbParameters[i].m_maxDecPicBuffering[pcVPS->m_dpbMaxTemporalId[i]];
+
+      // When max_num_reorder_pics[ i ] is not present for i in the range of 0 to maxSubLayersMinus1 - 1, inclusive, due to subLayerInfoFlag being equal to 0, it is inferred to be equal to max_num_reorder_pics[ maxSubLayersMinus1 ].
+      pcVPS->m_dpbParameters[i].m_numReorderPics[j] = pcVPS->m_dpbParameters[i].m_numReorderPics[pcVPS->m_dpbMaxTemporalId[i]];
+
+      // When max_latency_increase_plus1[ i ] is not present for i in the range of 0 to maxSubLayersMinus1 - 1, inclusive, due to subLayerInfoFlag being equal to 0, it is inferred to be equal to max_latency_increase_plus1[ maxSubLayersMinus1 ].
+      pcVPS->m_dpbParameters[i].m_maxLatencyIncreasePlus1[j] = pcVPS->m_dpbParameters[i].m_maxLatencyIncreasePlus1[pcVPS->m_dpbMaxTemporalId[i]];
+    }
+  }
+
+  pcVPS->deriveOutputLayerSets();
+
+  for( int i = 0; i < pcVPS->getTotalNumOLSs(); i++ )
+  {
+    if( pcVPS->m_numLayersInOls[i] > 1 )
+    {
+      READ_UVLC( uiCode, "ols_dpb_pic_width[i]" ); pcVPS->setOlsDpbPicWidth( i, uiCode );
+      READ_UVLC( uiCode, "ols_dpb_pic_height[i]" ); pcVPS->setOlsDpbPicHeight( i, uiCode );
+      if( pcVPS->m_numDpbParams > 1 )
+      {
+        READ_UVLC( uiCode, "ols_dpb_params_idx[i]" ); pcVPS->setOlsDpbParamsIdx( i, uiCode );
+      }
+    }
+  }
+#endif
+
   READ_FLAG(uiCode, "vps_extension_flag");
   if (uiCode)
   {
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index f27bb3c10..dbfc776ab 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -628,7 +628,9 @@ protected:
 #endif
   CostMode  m_costMode;                                       ///< The cost function to use, primarily when considering lossless coding.
 
+#if !JVET_Q0814_DPB
   VPS       m_cVPS;
+#endif
   DPS       m_dps;
   bool      m_decodingParameterSetEnabled;                   ///< enable decoding parameter set
   bool      m_recalculateQPAccordingToLambda;                 ///< recalculate QP value according to the lambda value
@@ -1652,8 +1654,10 @@ public:
   CostMode     getCostMode( ) const                                  { return m_costMode; }
   void         setCostMode(CostMode m )                              { m_costMode = m; }
 
+#if !JVET_Q0814_DPB
   void         setVPS(VPS *p)                                        { m_cVPS = *p; }
   VPS *        getVPS()                                              { return &m_cVPS; }
+#endif
   void         setDPS(DPS *p)                                        { m_dps = *p; }
   DPS*         getDPS()                                              { return &m_dps; }
   void         setUseRecalculateQPAccordingToLambda (bool b)         { m_recalculateQPAccordingToLambda = b;    }
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index 3eb5c0846..ebe700b7b 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -68,6 +68,9 @@ EncLib::EncLib( EncLibCommon* encLibCommon )
   , m_lmcsAPS(nullptr)
   , m_scalinglistAPS( nullptr )
   , m_doPlt( true )
+#if JVET_Q0814_DPB
+  , m_vps( encLibCommon->getVPS() )
+#endif
 {
   m_iPOCLast          = -1;
   m_iNumPicRcvd       =  0;
@@ -213,8 +216,13 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf )
   aps0.setAPSType( SCALING_LIST_APS );
 
   // initialize SPS
+#if JVET_Q0814_DPB
+  xInitSPS( sps0 );
+  xInitVPS( sps0 );
+#else
   xInitSPS( sps0, m_cVPS );
   xInitVPS(m_cVPS, sps0);
+#endif
 
   int dpsId = getDecodingParameterSetEnabled() ? 1 : 0;
   xInitDPS(m_dps, sps0, dpsId);
@@ -419,7 +427,11 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf )
     Picture *picBg = new Picture;
     picBg->create( sps0.getChromaFormatIdc(), Size( pps0.getPicWidthInLumaSamples(), pps0.getPicHeightInLumaSamples() ), sps0.getMaxCUWidth(), sps0.getMaxCUWidth() + 16, false, m_layerId );
     picBg->getRecoBuf().fill(0);
+#if JVET_Q0814_DPB
+    picBg->finalInit( m_vps, sps0, pps0, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS );
+#else
     picBg->finalInit( &m_cVPS, sps0, pps0, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS );
+#endif
     picBg->allocateNewSlice();
     picBg->createSpliceIdx(pps0.pcv->sizeInCtus);
     m_cGOPEncoder.setPicBg(picBg);
@@ -546,7 +558,11 @@ bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* cPicYu
     const SPS *sps = m_spsMap.getPS( pps->getSPSId() );
 
     picCurr->M_BUFS( 0, PIC_ORIGINAL ).copyFrom( m_cGOPEncoder.getPicBg()->getRecoBuf() );
+#if JVET_Q0814_DPB
+    picCurr->finalInit( m_vps, *sps, *pps, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS );
+#else
     picCurr->finalInit( &m_cVPS, *sps, *pps, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS );
+#endif
     picCurr->poc = m_iPOCLast - 1;
     m_iPOCLast -= 2;
     if( getUseAdaptiveQP() )
@@ -602,7 +618,11 @@ bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* cPicYu
       }
     }
 
+#if JVET_Q0814_DPB
+    if( m_vps->getMaxLayers() > 1 )
+#else
     if( m_cVPS.getMaxLayers() > 1 )
+#endif
     {
       ppsID = m_layerId;
     }
@@ -657,7 +677,12 @@ bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* cPicYu
       pcPicCurr->M_BUFS( 0, PIC_ORIGINAL ).swap( *pcPicYuvOrg );
       pcPicCurr->M_BUFS( 0, PIC_TRUE_ORIGINAL ).swap( *cPicYuvTrueOrg );
     }
+
+#if JVET_Q0814_DPB
+    pcPicCurr->finalInit( m_vps, *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS );
+#else
     pcPicCurr->finalInit( &m_cVPS, *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS );
+#endif
 
     pcPicCurr->poc = m_iPOCLast;
 
@@ -788,12 +813,15 @@ bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* pcPicY
         }
       }
 
-      {
-        int ppsID = -1; // Use default PPS ID
-        const PPS *pPPS = ( ppsID < 0 ) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS( ppsID );
-        const SPS *pSPS = m_spsMap.getPS( pPPS->getSPSId() );
-        pcField->finalInit( &m_cVPS, *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS );
-      }
+      int ppsID = -1; // Use default PPS ID
+      const PPS *pPPS = ( ppsID < 0 ) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS( ppsID );
+      const SPS *pSPS = m_spsMap.getPS( pPPS->getSPSId() );
+
+#if JVET_Q0814_DPB
+      pcField->finalInit( m_vps, *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS );
+#else
+      pcField->finalInit( &m_cVPS, *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS );
+#endif
 
       pcField->poc = m_iPOCLast;
       pcField->reconstructed = false;
@@ -881,7 +909,13 @@ void EncLib::xGetNewPicBuffer ( std::list<PelUnitBuf*>& rcListPicYuvRecOut, Pict
   Slice::sortPicList(m_cListPic);
 
   // use an entry in the buffered list if the maximum number that need buffering has been reached:
+#if JVET_Q0814_DPB
+  int maxDecPicBuffering = ( m_vps == nullptr || m_vps->m_numLayersInOls[m_vps->m_targetOlsIdx] == 1 ) ? sps.getMaxDecPicBuffering( MAX_TLAYER - 1 ) : m_vps->getMaxDecPicBuffering( MAX_TLAYER - 1 );
+
+  if( m_cListPic.size() >= (uint32_t)( m_iGOPSize + maxDecPicBuffering + 2 ) )
+#else
   if( m_cListPic.size() >= (uint32_t)( m_iGOPSize + getMaxDecPicBuffering( MAX_TLAYER - 1 ) + 2 ) )
+#endif
   {
     PicList::iterator iterPic = m_cListPic.begin();
     int iSize = int( m_cListPic.size() );
@@ -942,12 +976,96 @@ void EncLib::xGetNewPicBuffer ( std::list<PelUnitBuf*>& rcListPicYuvRecOut, Pict
   m_iNumPicRcvd++;
 }
 
+#if JVET_Q0814_DPB
+void EncLib::xInitVPS( const SPS& sps )
+{
+  // The SPS must have already been set up.
+  // set the VPS profile information.
+  m_vps->setMaxSubLayers( sps.getMaxTLayers() );
+
+  m_vps->deriveOutputLayerSets();
+  m_vps->deriveTargetOutputLayerSet( m_vps->m_targetOlsIdx );
+
+  if( !m_vps->getAllIndependentLayersFlag() )
+  {
+    m_vps->m_numDpbParams = m_vps->m_totalNumOLSs;
+  }
+
+  if( m_vps->m_dpbParameters.size() != m_vps->m_numDpbParams )
+  {
+    m_vps->m_dpbParameters.resize( m_vps->m_numDpbParams );
+  }
+
+  if( m_vps->m_dpbMaxTemporalId.size() != m_vps->m_numDpbParams )
+  {
+    m_vps->m_dpbMaxTemporalId.resize( m_vps->m_numDpbParams );
+  }
+
+  for( int i = 0; i < m_vps->m_numDpbParams; i++ )
+  {
+    if( m_vps->getMaxSubLayers() == 1 )
+    {
+      // When vps_max_sublayers_minus1 is equal to 0, the value of dpb_max_temporal_id[ i ] is inferred to be equal to 0.
+      m_vps->m_dpbMaxTemporalId[i] = 0;
+    }
+    else
+    {
+      if( m_vps->getAllLayersSameNumSublayersFlag() )
+      {
+        // When vps_max_sublayers_minus1 is greater than 0 and vps_all_layers_same_num_sublayers_flag is equal to 1, the value of dpb_max_temporal_id[ i ] is inferred to be equal to vps_max_sublayers_minus1.
+        m_vps->m_dpbMaxTemporalId[i] = m_vps->getMaxSubLayers() - 1;
+      }
+      else
+      {
+        m_vps->m_dpbMaxTemporalId[i] = m_maxTempLayer;
+      }
+    }
+
+    // accumulate DPB paramters from the SPS referring by each layer, inlucded into i-th OLS
+    if( std::find( m_vps->m_layerIdInOls[i].begin(), m_vps->m_layerIdInOls[i].end(), m_layerId ) != m_vps->m_layerIdInOls[i].end() )
+    {
+      for( int j = ( m_vps->m_sublayerDpbParamsPresentFlag ? 0 : m_vps->m_dpbMaxTemporalId[i] ); j <= m_vps->m_dpbMaxTemporalId[i]; j++ )
+      {
+        m_vps->m_dpbParameters[i].m_maxDecPicBuffering[j] += sps.getMaxDecPicBuffering( j );
+        m_vps->m_dpbParameters[i].m_numReorderPics[j] += sps.getNumReorderPics( j );
+        m_vps->m_dpbParameters[i].m_maxLatencyIncreasePlus1[j] += sps.getMaxLatencyIncreasePlus1( j );
+
+        CHECK( m_vps->m_dpbParameters[i].m_maxDecPicBuffering[j] >= MAX_NUM_REF_PICS, "max_dec_pic_buffering_minus1 exceeded MaxDpbSize" );
+      }
+
+      for( int j = ( m_vps->m_sublayerDpbParamsPresentFlag ? m_vps->m_dpbMaxTemporalId[i] : 0 ); j < m_vps->m_dpbMaxTemporalId[i]; j++ )
+      {
+        // When max_dec_pic_buffering_minus1[ i ] is not present for i in the range of 0 to maxSubLayersMinus1 - 1, inclusive, due to subLayerInfoFlag being equal to 0, it is inferred to be equal to max_dec_pic_buffering_minus1[ maxSubLayersMinus1 ].
+        m_vps->m_dpbParameters[i].m_maxDecPicBuffering[j] = m_vps->m_dpbParameters[i].m_maxDecPicBuffering[m_vps->m_dpbMaxTemporalId[i]];
+
+        // When max_num_reorder_pics[ i ] is not present for i in the range of 0 to maxSubLayersMinus1 - 1, inclusive, due to subLayerInfoFlag being equal to 0, it is inferred to be equal to max_num_reorder_pics[ maxSubLayersMinus1 ].
+        m_vps->m_dpbParameters[i].m_numReorderPics[j] = m_vps->m_dpbParameters[i].m_numReorderPics[m_vps->m_dpbMaxTemporalId[i]];
+
+        // When max_latency_increase_plus1[ i ] is not present for i in the range of 0 to maxSubLayersMinus1 - 1, inclusive, due to subLayerInfoFlag being equal to 0, it is inferred to be equal to max_latency_increase_plus1[ maxSubLayersMinus1 ].
+        m_vps->m_dpbParameters[i].m_maxLatencyIncreasePlus1[j] = m_vps->m_dpbParameters[i].m_maxLatencyIncreasePlus1[m_vps->m_dpbMaxTemporalId[i]];
+      }
+    }
+  }
+
+  for( int olsIdx = 0; olsIdx < m_vps->m_numOutputLayersInOls.size(); olsIdx++ )
+  {
+    if( std::find( m_vps->m_layerIdInOls[olsIdx].begin(), m_vps->m_layerIdInOls[olsIdx].end(), m_layerId ) != m_vps->m_layerIdInOls[olsIdx].end() )
+    {
+      m_vps->setOlsDpbPicWidth( olsIdx, std::max<int>( sps.getMaxPicWidthInLumaSamples(), m_vps->getOlsDpbPicSize( olsIdx ).width ) );
+      m_vps->setOlsDpbPicHeight( olsIdx, std::max<int>( sps.getMaxPicHeightInLumaSamples(), m_vps->getOlsDpbPicSize( olsIdx ).height ) );
+    }
+
+    m_vps->setOlsDpbParamsIdx( olsIdx, olsIdx );
+  }
+}
+#else
 void EncLib::xInitVPS(VPS& vps, const SPS& sps)
 {
   // The SPS must have already been set up.
   // set the VPS profile information.
   vps.setMaxSubLayers(sps.getMaxTLayers());
 }
+#endif
 
 void EncLib::xInitDPS(DPS &dps, const SPS &sps, const int dpsId)
 {
@@ -961,7 +1079,11 @@ void EncLib::xInitDPS(DPS &dps, const SPS &sps, const int dpsId)
   dps.setProfileTierLevel(ptls);
 }
 
+#if JVET_Q0814_DPB
+void EncLib::xInitSPS( SPS& sps )
+#else
 void EncLib::xInitSPS( SPS& sps, VPS& vps )
+#endif
 {
   ProfileTierLevel* profileTierLevel = sps.getProfileTierLevel();
   ConstraintInfo* cinfo = profileTierLevel->getConstraintInfo();
@@ -1018,7 +1140,11 @@ void EncLib::xInitSPS( SPS& sps, VPS& vps )
   /* XXX: should Main be marked as compatible with still picture? */
   /* XXX: may be a good idea to refactor the above into a function
    * that chooses the actual compatibility based upon options */
+#if JVET_Q0814_DPB
+  sps.setVPSId( m_vps->getVPSId() );
+#else
   sps.setVPSId(m_cVPS.getVPSId());
+#endif
   sps.setMaxPicWidthInLumaSamples( m_iSourceWidth );
   sps.setMaxPicHeightInLumaSamples( m_iSourceHeight );
   sps.setMaxCUWidth             ( m_maxCUWidth        );
@@ -1253,11 +1379,20 @@ void EncLib::xInitSPS( SPS& sps, VPS& vps )
     sps.setVirtualBoundariesPosY            ( m_virtualBoundariesPosY[i], i );
   }
 
+#if JVET_Q0814_DPB
+  sps.setInterLayerPresentFlag( m_vps->getMaxLayers() > 1 && !m_vps->getAllIndependentLayersFlag() );
+  
+  for( int i = 0; i < m_vps->getMaxLayers(); ++i )
+  {
+    //CHECK((m_vps->getIndependentLayerFlag(i) == 1) && (sps.getInterLayerPresentFlag() != 0), " When vps_independent_layer_flag[GeneralLayerIdx[nuh_layer_id ]]  is equal to 1, the value of inter_layer_ref_pics_present_flag shall be equal to 0.");
+  }
+#else
   sps.setInterLayerPresentFlag( vps.getMaxLayers() > 1 && !vps.getAllIndependentLayersFlag() );
   for (unsigned int i = 0; i < vps.getMaxLayers(); ++i)
   {
     CHECK((vps.getIndependentLayerFlag(i) == 1) && (sps.getInterLayerPresentFlag() != 0), " When vps_independent_layer_flag[GeneralLayerIdx[nuh_layer_id ]]  is equal to 1, the value of inter_layer_ref_pics_present_flag shall be equal to 0.");
   }
+#endif
 
   sps.setRprEnabledFlag( m_rprEnabled || sps.getInterLayerPresentFlag() );
 }
diff --git a/source/Lib/EncoderLib/EncLib.h b/source/Lib/EncoderLib/EncLib.h
index f9b13233e..12f8768a0 100644
--- a/source/Lib/EncoderLib/EncLib.h
+++ b/source/Lib/EncoderLib/EncLib.h
@@ -155,6 +155,10 @@ private:
 #endif
   int                       m_picIdInGOP;
 
+#if JVET_Q0814_DPB
+  VPS*                      m_vps;
+#endif
+
 public:
   SPS*                      getSPS( int spsId ) { return m_spsMap.getPS( spsId ); };
   APS**                     getApss() { return m_apss; }
@@ -162,9 +166,14 @@ public:
 
 protected:
   void  xGetNewPicBuffer  ( std::list<PelUnitBuf*>& rcListPicYuvRecOut, Picture*& rpcPic, int ppsId ); ///< get picture buffer which will be processed. If ppsId<0, then the ppsMap will be queried for the first match.
-  void  xInitVPS(VPS& vps, const SPS& sps); ///< initialize VPS from encoder options
   void  xInitDPS          (DPS &dps, const SPS &sps, const int dpsId); ///< initialize DPS from encoder options
+#if JVET_Q0814_DPB
+  void  xInitVPS( const SPS& sps ); ///< initialize VPS from encoder options
+  void  xInitSPS( SPS& sps );       ///< initialize SPS from encoder options
+#else
+  void  xInitVPS(VPS& vps, const SPS& sps); ///< initialize VPS from encoder options
   void  xInitSPS          ( SPS& sps, VPS& vps );       ///< initialize SPS from encoder options
+#endif
   void  xInitPPS          (PPS &pps, const SPS &sps); ///< initialize PPS from encoder options
   void  xInitPicHeader    (PicHeader &picHeader, const SPS &sps, const PPS &pps); ///< initialize Picture Header from encoder options
   void  xInitAPS          (APS &aps);                 ///< initialize APS from encoder options
@@ -283,6 +292,9 @@ public:
   void printSummary( bool isField ) { m_cGOPEncoder.printOutSummary( m_uiNumAllPicCoded, isField, m_printMSEBasedSequencePSNR, m_printSequenceMSE, m_printHexPsnr, m_rprEnabled, m_spsMap.getFirstPS()->getBitDepths() ); }
 
   int getLayerId() const { return m_layerId; }
+#if JVET_Q0814_DPB
+  VPS* getVPS()          { return m_vps;     }
+#endif
 };
 
 //! \}
diff --git a/source/Lib/EncoderLib/EncLibCommon.h b/source/Lib/EncoderLib/EncLibCommon.h
index 989fdf7e4..353b7410f 100644
--- a/source/Lib/EncoderLib/EncLibCommon.h
+++ b/source/Lib/EncoderLib/EncLibCommon.h
@@ -48,6 +48,9 @@ private:
   ParameterSetMap<PPS>      m_ppsMap;             ///< PPS, it is shared across all layers
   ParameterSetMap<APS>      m_apsMap;             ///< APS, it is shared across all layers
   PicList                   m_cListPic;           ///< DPB, it is shared across all layers
+#if JVET_Q0814_DPB
+  VPS                       m_vps;
+#endif
 
 public:
   EncLibCommon();
@@ -58,6 +61,8 @@ public:
   ParameterSetMap<SPS>&    getSpsMap()             { return m_spsMap;     }
   ParameterSetMap<PPS>&    getPpsMap()             { return m_ppsMap;     }
   ParameterSetMap<APS>&    getApsMap()             { return m_apsMap;     }
-
+#if JVET_Q0814_DPB
+  VPS*                     getVPS()                { return &m_vps;       }
+#endif
 };
 
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index 4a1fdcc80..ef816e15f 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -1162,6 +1162,58 @@ void HLSWriter::codeVPS(const VPS* pcVPS)
       }
     }
   }
+
+#if JVET_Q0814_DPB
+  if( !pcVPS->getAllIndependentLayersFlag() )
+  {
+    WRITE_UVLC( pcVPS->m_numDpbParams, "vps_num_dpb_params" );
+  }
+
+  if( pcVPS->m_numDpbParams > 0 && pcVPS->getMaxSubLayers() > 1 )
+  {
+    WRITE_FLAG( pcVPS->m_sublayerDpbParamsPresentFlag, "vps_sublayer_dpb_params_present_flag" );
+  }
+
+  for( int i = 0; i < pcVPS->m_numDpbParams; i++ )
+  {
+    if( pcVPS->getMaxSubLayers() == 1 )
+    {
+      CHECK( pcVPS->m_dpbMaxTemporalId[i] != 0, "When vps_max_sublayers_minus1 is equal to 0, the value of dpb_max_temporal_id[ i ] is inferred to be equal to 0" );
+    }
+    else
+    {
+      if( pcVPS->getAllLayersSameNumSublayersFlag() )
+      {
+        CHECK( pcVPS->m_dpbMaxTemporalId[i] != pcVPS->getMaxSubLayers() - 1, "When vps_max_sublayers_minus1 is greater than 0 and vps_all_layers_same_num_sublayers_flag is equal to 1, the value of dpb_max_temporal_id[ i ] is inferred to be equal to vps_max_sublayers_minus1" );
+      }
+      else
+      {
+        WRITE_CODE( pcVPS->m_dpbMaxTemporalId[i], 3, "dpb_max_temporal_id[i]" );
+      }
+    }
+
+    for( int j = ( pcVPS->m_sublayerDpbParamsPresentFlag ? 0 : pcVPS->m_dpbMaxTemporalId[i] ); j <= pcVPS->m_dpbMaxTemporalId[i]; j++ )
+    {
+      WRITE_UVLC( pcVPS->m_dpbParameters[i].m_maxDecPicBuffering[j], "max_dec_pic_buffering_minus1[i]" );
+      WRITE_UVLC( pcVPS->m_dpbParameters[i].m_numReorderPics[j], "max_num_reorder_pics[i]" );
+      WRITE_UVLC( pcVPS->m_dpbParameters[i].m_maxLatencyIncreasePlus1[j], "max_latency_increase_plus1[i]" );
+    }
+  }
+
+  for( int i = 0; i < pcVPS->getTotalNumOLSs(); i++ )
+  {
+    if( pcVPS->m_numLayersInOls[i] > 1 )
+    {
+      WRITE_UVLC( pcVPS->getOlsDpbPicSize( i ).width, "ols_dpb_pic_width[i]" );
+      WRITE_UVLC( pcVPS->getOlsDpbPicSize( i ).height, "ols_dpb_pic_height[i]" );
+      if( pcVPS->m_numDpbParams > 1 )
+      {
+        WRITE_UVLC( pcVPS->getOlsDpbParamsIdx( i ), "ols_dpb_params_idx[i]" );
+      }
+    }
+  }
+#endif
+
   WRITE_FLAG(0, "vps_extension_flag");
 
   //future extensions here..
-- 
GitLab