diff --git a/doc/software-manual.tex b/doc/software-manual.tex
index 21d80063e3c767809c5d561cfc87fd00dad42271..d56638614a6963cda53f0f33a80b3c486583fe28 100644
--- a/doc/software-manual.tex
+++ b/doc/software-manual.tex
@@ -1434,12 +1434,32 @@ Specifies the value to use to derive the vps_max_layers_minus1 for layered codin
 Specifies the maximum number of temporal sublayers to signal in the VPS
 \\
 
+
 \Option{DefaultPtlDpbHrdMaxTidFlag} &
 %\ShortOption{\None} &
 \Default{true} &
 Specifies the value of vps_default_ptl_dpb_hrd_max_tid_flag in the VPS
 \\
 
+\Option{EnableOperatingPointInformation} &
+%\ShortOption{\None} &
+\Default{false} &
+Enables writing of a operating point information (OPI). If disabled, no OPI will
+be written.
+\\
+
+\Option{TargetOutputLayerSet} &
+%\ShortOption{\None} &
+\Default{\NotSet} &
+Specifies the target Output Layer Set Idx to be signalled in OPI. When not provided the value may be inferred from the VPS.
+\\
+
+\Option{MaxTemporalLayer} &
+%\ShortOption{\None} &
+\Default{\NotSet} &
+Defines the maximum temporal layer to be signalled in OPI. When not provided the value may be inferred from the VPS.
+\\
+
 \Option{AllowablePredDirection} &
 %\ShortOption{\None} &
 \Default{""} &
@@ -4650,7 +4670,7 @@ Defines the input bit stream file name.
 \Option{ReconFile (-o)} &
 %\ShortOption{-o} &
 \Default{\NotSet} &
-Defines the reconstructed video file name. If empty, no file is generated. If the bitstream contains multiple layer and no single target layer is specified (i.e. TargetLayer=-1), a reconstructed file is written for each layer and the layer index is added as suffix to ReconFile. If one or more dots exist in the file name, the layer id is added before the last dot, e.g. 'decoded.yuv' becomes 'decoded0.yuv' for layer id 0, 'decoded' becomes 'decoded0'.
+Defines the reconstructed video file name. If empty, no file is generated. If the bitstream contains multiple layer and no single target layer is specified (i.e. TargetOutputLayerSet=-1), a reconstructed file is written for each layer and the layer index is added as suffix to ReconFile. If one or more dots exist in the file name, the layer id is added before the last dot, e.g. 'decoded.yuv' becomes 'decoded0.yuv' for layer id 0, 'decoded' becomes 'decoded0'.
 \\
 
 \Option{OplFile (-opl)} &
@@ -4667,8 +4687,8 @@ Defines the number of pictures in decoding order to skip.
 
 \Option{MaxTemporalLayer (-t)} &
 %\ShortOption{-t} &
-\Default{-1} &
-Defines the maximum temporal layer to be decoded. If -1, then all layers are decoded.
+\Default{\NotSet} &
+Defines the maximum temporal layer to be decoded. If -1, then all layers are decoded. When not provided the value may be inferred from the OPI NAL unit or the VPS NAL unit of the bitstream.
 \\
 
 \Option{TarDecLayerIdSetFile (-l)} &
@@ -4692,11 +4712,11 @@ Defines the chroma bit-depth of the reconstructed YUV file (the value 0 indicate
 that the native bit-depth is used)
 \\
 
-\Option{TargetLayer (-p)} &
+\Option{TargetOutputLayerSet (-p)} &
 %\ShortOption{-p} &
-\Default{-1 \\ (Native)} &
+\Default{\NotSet} &
 Specifies the target bitstream Layer to be decoded. (the value -1 indicates
-that decoding the whole bitstream )
+that decoding the whole bitstream ). When not provided the value may be inferred from the OPI NAL unit or the VPS NAL unit of the bitstream.
 \\
 
 \Option{SEIDecodedPictureHash} &
diff --git a/source/App/BitstreamExtractorApp/BitstreamExtractorApp.cpp b/source/App/BitstreamExtractorApp/BitstreamExtractorApp.cpp
index 3d49f70d3df140ac9dd9db51200d880e178a6f4b..15009db24e9c9fe261458cd3d85f0053b05f4856 100644
--- a/source/App/BitstreamExtractorApp/BitstreamExtractorApp.cpp
+++ b/source/App/BitstreamExtractorApp/BitstreamExtractorApp.cpp
@@ -643,7 +643,11 @@ uint32_t BitstreamExtractorApp::decode()
         }
         // Remove NAL units with nal_unit_type not equal to any of VPS_NUT, DPS_NUT, and EOB_NUT and with nuh_layer_id not included in the list LayerIdInOls[targetOlsIdx].
         NalUnitType t = nalu.m_nalUnitType;
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+        bool isSpecialNalTypes = t == NAL_UNIT_OPI || t == NAL_UNIT_VPS || t == NAL_UNIT_DCI || t == NAL_UNIT_EOB;
+#else
         bool isSpecialNalTypes = t == NAL_UNIT_VPS || t == NAL_UNIT_DCI || t == NAL_UNIT_EOB;
+#endif
         vps = m_parameterSetManager.getVPS(m_vpsId);
         if (m_vpsId == 0)
         {
diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp
index b0af3fd9e4532f8b84ae95ad6e73000473961e8d..95d01efe9ab2824f77e0ae734e056c508fc7b5ba 100644
--- a/source/App/DecoderApp/DecApp.cpp
+++ b/source/App/DecoderApp/DecApp.cpp
@@ -147,6 +147,11 @@ uint32_t DecApp::decode()
     }
   };
 
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+    m_cDecLib.setHTidExternalSetFlag(m_mTidExternalSet);
+    m_cDecLib.setTOlsIdxExternalFlag(m_tOlsIdxTidExternalSet);
+#endif
+
   while (!!bitstreamFile)
   {
     InputNALUnit nalu;
@@ -216,9 +221,23 @@ uint32_t DecApp::decode()
             }
           }
           m_cDecLib.decode(nalu, m_iSkipFrame, m_iPOCLastDisplay, m_targetOlsIdx);
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+          if (nalu.m_nalUnitType == NAL_UNIT_OPI)
+          {
+            if (!m_cDecLib.getHTidExternalSetFlag() && m_cDecLib.getOPI()->getHtidInfoPresentFlag())
+            {
+              m_iMaxTemporalLayer = m_cDecLib.getOPI()->getOpiHtidPlus1()-1;
+            }
+            m_cDecLib.setHTidOpiSetFlag(m_cDecLib.getOPI()->getHtidInfoPresentFlag());
+          }
+#endif
           if (nalu.m_nalUnitType == NAL_UNIT_VPS)
           {
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+            m_cDecLib.deriveTargetOutputLayerSet( m_cDecLib.getVPS()->m_targetOlsIdx );
+#else
             m_cDecLib.deriveTargetOutputLayerSet( m_targetOlsIdx );
+#endif
             m_targetDecLayerIdSet = m_cDecLib.getVPS()->m_targetLayerIdSet;
             m_targetOutputLayerIdSet = m_cDecLib.getVPS()->m_targetOutputLayerIdSet;
           }
@@ -314,8 +333,13 @@ uint32_t DecApp::decode()
         m_cDecLib.setFirstSliceInPicture (false);
       }
       // write reconstruction to file -- for additional bumping as defined in C.5.2.3
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+      if (!bNewPicture && ((nalu.m_nalUnitType >= NAL_UNIT_CODED_SLICE_TRAIL && nalu.m_nalUnitType <= NAL_UNIT_RESERVED_IRAP_VCL_11)
+        || (nalu.m_nalUnitType >= NAL_UNIT_CODED_SLICE_IDR_W_RADL && nalu.m_nalUnitType <= NAL_UNIT_CODED_SLICE_GDR)))
+#else
       if (!bNewPicture && ((nalu.m_nalUnitType >= NAL_UNIT_CODED_SLICE_TRAIL && nalu.m_nalUnitType <= NAL_UNIT_RESERVED_IRAP_VCL_12)
         || (nalu.m_nalUnitType >= NAL_UNIT_CODED_SLICE_IDR_W_RADL && nalu.m_nalUnitType <= NAL_UNIT_CODED_SLICE_GDR)))
+#endif
       {
         setOutputPicturePresentInStream();
         xWriteOutput( pcListPic, nalu.m_temporalId );
diff --git a/source/App/DecoderApp/DecAppCfg.cpp b/source/App/DecoderApp/DecAppCfg.cpp
index 6e95abb7490b528857241b043d8f8300eea2d7e3..d96c20493f7fe9759ff8016909921467fff3796b 100644
--- a/source/App/DecoderApp/DecAppCfg.cpp
+++ b/source/App/DecoderApp/DecAppCfg.cpp
@@ -88,8 +88,13 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] )
   ("OutputBitDepth,d",          m_outputBitDepth[CHANNEL_TYPE_LUMA],   0,          "bit depth of YUV output luma component (default: use 0 for native depth)")
   ("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))
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  ("MaxTemporalLayer,t",        m_iMaxTemporalLayer,                   500,    "Maximum Temporal Layer to be decoded. -1 to decode all layers")
+  ("TargetOutputLayerSet,p",    m_targetOlsIdx,                        500,    "Target output layer set index")
+#else
   ("MaxTemporalLayer,t",        m_iMaxTemporalLayer,                   -1,         "Maximum Temporal Layer to be decoded. -1 to decode all layers")
   ("TargetOutputLayerSet,p",    m_targetOlsIdx,                          -1,       "Target output layer set index")
+#endif
   ("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")
@@ -220,6 +225,24 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] )
       msg( ERROR, "File %s could not be opened. Using all LayerIds as default.\n", cfg_TargetDecLayerIdSetFile.c_str() );
     }
   }
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  if (m_iMaxTemporalLayer != 500)
+  {
+    m_mTidExternalSet = true;
+  }
+  else
+  {
+    m_iMaxTemporalLayer = -1;
+  }
+  if ( m_targetOlsIdx != 500)
+  {
+    m_tOlsIdxTidExternalSet = true;
+  }
+  else
+  {
+    m_targetOlsIdx = -1;
+  }
+#endif
   return true;
 }
 
@@ -233,6 +256,10 @@ DecAppCfg::DecAppCfg()
 , m_outputColourSpaceConvert(IPCOLOURSPACE_UNCHANGED)
 , m_targetOlsIdx(0)
 , m_iMaxTemporalLayer(-1)
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+, m_mTidExternalSet(false)
+, m_tOlsIdxTidExternalSet(false)
+#endif
 , m_decodedPictureHashSEIEnabled(0)
 , m_decodedNoDisplaySEIEnabled(false)
 , m_colourRemapSEIFileName()
diff --git a/source/App/DecoderApp/DecAppCfg.h b/source/App/DecoderApp/DecAppCfg.h
index 607425be31a2556128d12fc0d9c193bdd24121b7..ba7c0338ef6372fc153146f77902783e3953a852 100644
--- a/source/App/DecoderApp/DecAppCfg.h
+++ b/source/App/DecoderApp/DecAppCfg.h
@@ -67,6 +67,10 @@ protected:
   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
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  bool          m_mTidExternalSet;                    ///< maximum temporal layer set externally
+  bool          m_tOlsIdxTidExternalSet;              ///< target output layer set index externally set
+#endif
   int           m_decodedPictureHashSEIEnabled;       ///< Checksum(3)/CRC(2)/MD5(1)/disable(0) acting on decoded picture hash SEI message
   bool          m_decodedNoDisplaySEIEnabled;         ///< Enable(true)/disable(false) writing only pictures that get displayed based on the no display SEI message
   std::string   m_colourRemapSEIFileName;             ///< output Colour Remapping file name
diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 56e190e7feb966352b1ef5cbdd6116485d7bf772..e8c47bafd57aa947ec188d9be7e21a522849ec91 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -76,7 +76,18 @@ EncApp::~EncApp()
 void EncApp::xInitLibCfg()
 {
   VPS& vps = *m_cEncLib.getVPS();
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  if (m_targetOlsIdx != 500)
+  {
+    vps.m_targetOlsIdx = m_targetOlsIdx;
+  }
+  else
+  {
+    vps.m_targetOlsIdx = -1;
+  }
+#else
   vps.m_targetOlsIdx = m_targetOlsIdx;
+#endif
 
   vps.setMaxLayers( m_maxLayers );
 
@@ -1063,6 +1074,20 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setCropOffsetRight                                   (m_cropOffsetRight);
   m_cEncLib.setCropOffsetBottom                                  (m_cropOffsetBottom);
   m_cEncLib.setCalculateHdrMetrics                               (m_calculateHdrMetrics);
+#endif
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  m_cEncLib.setOPIEnabled                                         ( m_OPIEnabled );
+  if (m_OPIEnabled)
+  {
+    if (m_maxTemporalLayer != 500)
+    {
+      m_cEncLib.setHtidPlus1                                     ( m_maxTemporalLayer + 1);
+    }
+    if (m_targetOlsIdx != 500)
+    {
+      m_cEncLib.setTargetOlsIdx                                   (m_targetOlsIdx);
+    }
+  }
 #endif
   m_cEncLib.setGopBasedTemporalFilterEnabled(m_gopBasedTemporalFilterEnabled);
   m_cEncLib.setNumRefLayers                                       ( m_numRefLayers );
@@ -1409,6 +1434,9 @@ void EncApp::rateStatsAccum(const AccessUnit& au, const std::vector<uint32_t>& a
     case NAL_UNIT_CODED_SLICE_GDR:
     case NAL_UNIT_CODED_SLICE_RADL:
     case NAL_UNIT_CODED_SLICE_RASL:
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+    case NAL_UNIT_OPI:
+#endif
     case NAL_UNIT_DCI:
     case NAL_UNIT_VPS:
     case NAL_UNIT_SPS:
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index faea0ed16167c400a79673b7c9a56ddfb8089c9d..53c0dbb30fc1f32867c54b43a664f56b44aafb9d 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -1384,7 +1384,13 @@ 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_S0163_ON_TARGETOLS_SUBLAYERS
+  ( "EnableOperatingPointInformation",                m_OPIEnabled,                             false, "Enables writing of Operating Point Information (OPI)" )
+  ( "MaxTemporalLayer",                               m_maxTemporalLayer,                         500, "Maximum temporal layer to be signalled in OPI" )
+  ( "TargetOutputLayerSet",                           m_targetOlsIdx,                             500, "Target output layer set index to be signalled in OPI" )
+#else
   ( "TargetOutputLayerSet,p",                         m_targetOlsIdx,                              -1, "Target output layer set index" )
+#endif
   ;
   opts.addOptions()
   ( "MaxSublayers",                                   m_maxSublayers,                               7, "Max number of Sublayers")
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index 7f8d114143fcd8d48b52a476efc032c74f59c3fd..c11ee5d2d6483b18b45db6e285ff2e9278213d1c 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -711,7 +711,10 @@ protected:
 
   int         m_maxLayers;
   int         m_targetOlsIdx;
-
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  bool        m_OPIEnabled;                                     ///< enable Operating Point Information (OPI)
+  int         m_maxTemporalLayer;
+#endif
   int         m_layerId[MAX_VPS_LAYERS];
   int         m_layerIdx;
   int         m_maxSublayers;
diff --git a/source/App/Parcat/parcat.cpp b/source/App/Parcat/parcat.cpp
index 8de2b4b22bab3dcd77e322154feee21a1545d56c..ad869476ffab48867057371049d9229ee37f98c3 100644
--- a/source/App/Parcat/parcat.cpp
+++ b/source/App/Parcat/parcat.cpp
@@ -279,7 +279,11 @@ std::vector<uint8_t> filter_segment(const std::vector<uint8_t> & v, int idx, int
       }
       first_idr_slice_after_ph_nal = false;
     }
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+    if(inp_nalu.m_nalUnitType == NAL_UNIT_PH || (nalu_type < NAL_UNIT_CODED_SLICE_IDR_W_RADL) || (nalu_type > NAL_UNIT_CODED_SLICE_IDR_N_LP && nalu_type <= NAL_UNIT_RESERVED_IRAP_VCL_11) )
+#else
     if(inp_nalu.m_nalUnitType == NAL_UNIT_PH || (nalu_type < NAL_UNIT_CODED_SLICE_IDR_W_RADL) || (nalu_type > NAL_UNIT_CODED_SLICE_IDR_N_LP && nalu_type <= NAL_UNIT_RESERVED_IRAP_VCL_12) )
+#endif
     {
       parcatHLSReader.setBitstream( &inp_nalu.getBitstream() );
       if (inp_nalu.m_nalUnitType == NAL_UNIT_PH)
@@ -329,8 +333,14 @@ std::vector<uint8_t> filter_segment(const std::vector<uint8_t> & v, int idx, int
       skip_next_sei = true;
       idr_found = true;
     }
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+    if ((idx > 1 && (nalu_type == NAL_UNIT_CODED_SLICE_IDR_W_RADL || nalu_type == NAL_UNIT_CODED_SLICE_IDR_N_LP)) 
+      || ((idx > 1 && !idr_found) && (nalu_type == NAL_UNIT_OPI || nalu_type == NAL_UNIT_DCI || nalu_type == NAL_UNIT_VPS || nalu_type == NAL_UNIT_SPS || nalu_type == NAL_UNIT_PPS || nalu_type == NAL_UNIT_PREFIX_APS || nalu_type == NAL_UNIT_SUFFIX_APS || nalu_type == NAL_UNIT_PH || nalu_type == NAL_UNIT_ACCESS_UNIT_DELIMITER)) 
+      || (nalu_type == NAL_UNIT_SUFFIX_SEI && skip_next_sei))
+#else
     if ((idx > 1 && (nalu_type == NAL_UNIT_CODED_SLICE_IDR_W_RADL || nalu_type == NAL_UNIT_CODED_SLICE_IDR_N_LP)) || ((idx > 1 && !idr_found) && (nalu_type == NAL_UNIT_DCI || nalu_type == NAL_UNIT_VPS || nalu_type == NAL_UNIT_SPS || nalu_type == NAL_UNIT_PPS || nalu_type == NAL_UNIT_PREFIX_APS || nalu_type == NAL_UNIT_SUFFIX_APS || nalu_type == NAL_UNIT_PH || nalu_type == NAL_UNIT_ACCESS_UNIT_DELIMITER))
       || (nalu_type == NAL_UNIT_SUFFIX_SEI && skip_next_sei))
+#endif
     {
     }
     else
diff --git a/source/App/SubpicMergeApp/SubpicMergeApp.cpp b/source/App/SubpicMergeApp/SubpicMergeApp.cpp
index b6bc02979f3a982b1636e57dcbc4972bc9591ce3..3dbda5f4a9b1989a6a010f9d50eb35cbe6ada421 100644
--- a/source/App/SubpicMergeApp/SubpicMergeApp.cpp
+++ b/source/App/SubpicMergeApp/SubpicMergeApp.cpp
@@ -166,6 +166,9 @@ bool SubpicMergeApp::isNewPicture(std::ifstream *bitstreamFile, InputByteStream
 
         // NUT that indicate the start of a new picture
         case NAL_UNIT_ACCESS_UNIT_DELIMITER:
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+        case NAL_UNIT_OPI:
+#endif
         case NAL_UNIT_DCI:
         case NAL_UNIT_VPS:
         case NAL_UNIT_SPS:
@@ -188,7 +191,9 @@ bool SubpicMergeApp::isNewPicture(std::ifstream *bitstreamFile, InputByteStream
         case NAL_UNIT_CODED_SLICE_CRA:
         case NAL_UNIT_CODED_SLICE_GDR:
         case NAL_UNIT_RESERVED_IRAP_VCL_11:
+#if !JVET_S0163_ON_TARGETOLS_SUBLAYERS
         case NAL_UNIT_RESERVED_IRAP_VCL_12:
+#endif
           ret = checkPictureHeaderInSliceHeaderFlag(nalu);
           finished = true;
           break;
diff --git a/source/Lib/CommonLib/Rom.cpp b/source/Lib/CommonLib/Rom.cpp
index c63489c95dfdd7f257acd6ef6b632dc969a4d836..dc1c29aedeb1bd14078082f975495715280ea495 100644
--- a/source/Lib/CommonLib/Rom.cpp
+++ b/source/Lib/CommonLib/Rom.cpp
@@ -70,6 +70,9 @@ const char* nalUnitTypeToString(NalUnitType type)
   case NAL_UNIT_CODED_SLICE_IDR_N_LP:   return "IDR_N_LP";
   case NAL_UNIT_CODED_SLICE_CRA:        return "CRA";
   case NAL_UNIT_CODED_SLICE_GDR:        return "GDR";
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  case NAL_UNIT_OPI:                    return "OPI";
+#endif
   case NAL_UNIT_DCI:                    return "DCI";
   case NAL_UNIT_VPS:                    return "VPS";
   case NAL_UNIT_SPS:                    return "SPS";
diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp
index a0dd315dfb7c9b01da9f969f0bbc6b96938e026e..bb538e9bc8aac63d003518b7f249d598bb796a19 100644
--- a/source/Lib/CommonLib/Slice.cpp
+++ b/source/Lib/CommonLib/Slice.cpp
@@ -2511,6 +2511,43 @@ void VPS::deriveTargetOutputLayerSet( int targetOlsIdx )
   }
 }
 
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+int VPS::deriveTargetOLSIdx(void)
+{
+  int lowestIdx = 0;
+  int highestNumLayers = m_numLayersInOls[lowestIdx];
+
+  if ((m_numLayersInOls.size() > 1 ))
+  {
+    int idx = 1;
+    for (std::vector<int>::const_iterator it = (m_numLayersInOls.begin() + 1); it != m_numLayersInOls.end(); it++)
+    {
+      if(highestNumLayers == it[idx])
+      {
+        if (m_numOutputLayersInOls[lowestIdx] < m_numOutputLayersInOls[idx])
+        {
+          highestNumLayers = it[idx];
+          lowestIdx       = idx;
+        }
+      }
+      else if(highestNumLayers < it[idx])
+      {
+        highestNumLayers = it[idx];
+        lowestIdx       = idx;
+      }
+      idx++;
+    }
+  }
+  return lowestIdx;
+}
+
+uint32_t VPS::getMaxTidinTOls(int m_targetOlsIdx)
+{
+  return getPtlMaxTemporalId(getOlsPtlIdx(m_targetOlsIdx));
+}
+
+#endif
+
 // ------------------------------------------------------------------------------------------------
 // Picture Header
 // ------------------------------------------------------------------------------------------------
@@ -4503,6 +4540,13 @@ void xTraceVPSHeader()
   DTRACE( g_trace_ctx, D_HEADER, "=========== Video Parameter Set     ===========\n" );
 }
 
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+void xTraceOPIHeader()
+{
+  DTRACE(g_trace_ctx, D_HEADER, "=========== Operating Point Information     ===========\n");
+}
+#endif
+
 void xTraceDCIHeader()
 {
   DTRACE( g_trace_ctx, D_HEADER, "=========== Decoding Capability Information     ===========\n" );
@@ -4542,4 +4586,4 @@ void xTraceFillerData ()
 {
   DTRACE( g_trace_ctx, D_HEADER, "=========== Filler Data ===========\n" );
 }
-#endif
+#endif
\ No newline at end of file
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index a068cdfd8cc2e661e78620dd6d893630580d6492..48905c14ed0d69e74cadbd5a662332e722a5049c 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -923,6 +923,36 @@ public:
   }
 };
 
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+class OPI
+{
+private:
+  bool m_olsinfopresentflag;
+  bool m_htidinfopresentflag;
+  uint32_t  m_opiolsidx;
+  uint32_t  m_opihtidplus1;
+
+public:
+  OPI()
+    : m_olsinfopresentflag (false)
+    ,  m_htidinfopresentflag (false)
+    ,  m_opiolsidx (-1)
+    ,  m_opihtidplus1 (-1)
+  {};
+
+  virtual ~OPI() {};
+
+  bool getOlsInfoPresentFlag() const { return m_olsinfopresentflag; }
+  void setOlsInfoPresentFlag(bool val) { m_olsinfopresentflag = val; }
+  bool getHtidInfoPresentFlag() const { return m_htidinfopresentflag; }
+  void setHtidInfoPresentFlag(bool val) { m_htidinfopresentflag = val; }
+  uint32_t getOpiOlsIdx() const { return m_opiolsidx; }
+  void setOpiOlsIdx(uint32_t val) { m_opiolsidx = val; }
+  uint32_t getOpiHtidPlus1() const { return m_opihtidplus1; }
+  void setOpiHtidPlus1(uint32_t val) { m_opihtidplus1 = val; }
+
+};
+#endif
 
 class VPS
 {
@@ -1102,6 +1132,10 @@ public:
 
   void              deriveOutputLayerSets();
   void              deriveTargetOutputLayerSet( int targetOlsIdx );
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  int               deriveTargetOLSIdx();
+  uint32_t          getMaxTidinTOls(int m_targetOlsIdx);
+#endif
 
   void              checkVPS();
 
@@ -3077,6 +3111,9 @@ public:
 
 #if ENABLE_TRACING
 void xTraceVPSHeader();
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+void xTraceOPIHeader();
+#endif
 void xTraceDCIHeader();
 void xTraceSPSHeader();
 void xTracePPSHeader();
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index cc2dfbb46bbb7a48497909cfff66ceb0c7f6c7c8..4a73aded09d06eaa9fb3105d205847186a8e8592 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -56,6 +56,7 @@
 #define JVET_R0193                                        1 // JVET-R0193: signalling of the number of maximum sublayers used for inter-layer prediction for each layer
 #define JVET_R0193_S0141                                  1 // JVET-S0141 item 47 : item 47: In the general sub-bitstream extraction process, specify the conditions under which an output sub-bitstream is required to be a conforming bitstream such that the value of tIdTarget is specified to be in the range of 0 to vps_ptl_max_tid[ vps_ols_ptl_idx[ targetOlsIdx ] ], inclusive (instead of 0 to 6 inclusive). (JVET-S0158 aspect 1)
 #define JVET_T0091_LMCS_ENC_OVERFLOW_FIX                  1 // JVET-T0091: LMCS encoder overflow fix at high bit-depth for SDR
+#define JVET_S0163_ON_TARGETOLS_SUBLAYERS                 1 // JVET-S0163: On target OLS and sublayers for decoding (OPI NAL Unit)
 
 //########### place macros to be be kept below this line ###############
 #define JVET_S0257_DUMP_360SEI_MESSAGE                    1 // Software support of 360 SEI messages
@@ -773,7 +774,11 @@ enum NalUnitType
   NAL_UNIT_CODED_SLICE_GDR,         // 10
 
   NAL_UNIT_RESERVED_IRAP_VCL_11,
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  NAL_UNIT_OPI,                     // 12
+#else
   NAL_UNIT_RESERVED_IRAP_VCL_12,
+#endif
   NAL_UNIT_DCI,                     // 13
   NAL_UNIT_VPS,                     // 14
   NAL_UNIT_SPS,                     // 15
diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp
index e237aa6b735a5f21cafdf8eb8e274a68e100fef7..8ec94e236e12d86535a3e8c45511ffa2f7a85ecb 100644
--- a/source/Lib/DecoderLib/DecLib.cpp
+++ b/source/Lib/DecoderLib/DecLib.cpp
@@ -444,6 +444,13 @@ DecLib::DecLib()
   , m_prefixSEINALUs()
   , m_debugPOC( -1 )
   , m_debugCTU( -1 )
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  , m_opi( nullptr )
+  , m_mTidExternalSet(false)
+  , m_mTidOpiSet(false)
+  , m_tOlsIdxTidExternalSet(false)
+  , m_tOlsIdxTidOpiSet(false)
+#endif
   , m_vps( nullptr )
   , m_maxDecSubPicIdx(0)
   , m_maxDecSliceAddrInSubPic(-1)
@@ -1996,6 +2003,9 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl
   for( auto& naluTemporalId : m_accessUnitNals )
   {
     if (
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+      naluTemporalId.m_nalUnitType != NAL_UNIT_OPI &&
+#endif
       naluTemporalId.m_nalUnitType != NAL_UNIT_DCI
       && naluTemporalId.m_nalUnitType != NAL_UNIT_VPS
       && naluTemporalId.m_nalUnitType != NAL_UNIT_SPS
@@ -2711,6 +2721,18 @@ void DecLib::updatePrevIRAPAndGDRSubpic()
   }
 }
 
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+void DecLib::xDecodeOPI( InputNALUnit& nalu )
+{
+  m_opi = new OPI();
+  m_HLSReader.setBitstream( &nalu.getBitstream() );
+
+  CHECK( nalu.m_temporalId, "The value of TemporalId of OPI NAL units shall be equal to 0" );
+
+  m_HLSReader.parseOPI( m_opi );
+}
+#endif
+
 void DecLib::xDecodeVPS( InputNALUnit& nalu )
 {
   VPS* vps = new VPS();
@@ -2810,8 +2832,28 @@ bool DecLib::decode(InputNALUnit& nalu, int& iSkipFrame, int& iPOCLastDisplay, i
   {
     case NAL_UNIT_VPS:
       xDecodeVPS( nalu );
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+      if (getTOlsIdxExternalFlag())
+      {
+        m_vps->m_targetOlsIdx = iTargetOlsIdx;
+      }
+      else if (getTOlsIdxOpiFlag())
+      {
+        m_vps->m_targetOlsIdx = m_opi->getOpiOlsIdx();
+      }
+      else
+      {
+        m_vps->m_targetOlsIdx = m_vps->deriveTargetOLSIdx();
+      }
+#else
       m_vps->m_targetOlsIdx = iTargetOlsIdx;
+#endif
       return false;
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+    case NAL_UNIT_OPI:
+      xDecodeOPI( nalu );
+      return false;
+#endif
     case NAL_UNIT_DCI:
       xDecodeDCI( nalu );
       return false;
@@ -2906,7 +2948,9 @@ bool DecLib::decode(InputNALUnit& nalu, int& iSkipFrame, int& iPOCLastDisplay, i
     }
 
     case NAL_UNIT_RESERVED_IRAP_VCL_11:
+#if !JVET_S0163_ON_TARGETOLS_SUBLAYERS
     case NAL_UNIT_RESERVED_IRAP_VCL_12:
+#endif
       msg( NOTICE, "Note: found reserved VCL NAL unit.\n");
       xParsePrefixSEIsForUnknownVCLNal();
       return false;
@@ -3101,6 +3145,9 @@ bool DecLib::isNewPicture(std::ifstream *bitstreamFile, class InputByteStream *b
 
       // NUT that indicate the start of a new picture
       case NAL_UNIT_ACCESS_UNIT_DELIMITER:
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+      case NAL_UNIT_OPI:
+#endif
       case NAL_UNIT_DCI:
       case NAL_UNIT_VPS:
       case NAL_UNIT_SPS:
@@ -3123,7 +3170,9 @@ bool DecLib::isNewPicture(std::ifstream *bitstreamFile, class InputByteStream *b
       case NAL_UNIT_CODED_SLICE_CRA:
       case NAL_UNIT_CODED_SLICE_GDR:
       case NAL_UNIT_RESERVED_IRAP_VCL_11:
+#if !JVET_S0163_ON_TARGETOLS_SUBLAYERS
       case NAL_UNIT_RESERVED_IRAP_VCL_12:
+#endif
         ret = checkPictureHeaderInSliceHeaderFlag(nalu);
         finished = true;
         break;
diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h
index 733a58590988a84d85ddfd017652c3b5e26ca24c..1a9364287429359fe40b579bff50888b0193f147 100644
--- a/source/Lib/DecoderLib/DecLib.h
+++ b/source/Lib/DecoderLib/DecLib.h
@@ -186,6 +186,13 @@ private:
   std::vector<NalUnitType> m_pictureUnitNals;
   std::list<InputNALUnit*> m_pictureSeiNalus; 
 
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  OPI*                    m_opi;
+  bool                    m_mTidExternalSet;
+  bool                    m_mTidOpiSet;
+  bool                    m_tOlsIdxTidExternalSet;
+  bool                    m_tOlsIdxTidOpiSet;
+#endif
   VPS*                    m_vps;
   int                     m_maxDecSubPicIdx;
   int                     m_maxDecSliceAddrInSubPic;
@@ -270,6 +277,18 @@ public:
   bool  isNewPicture( std::ifstream *bitstreamFile, class InputByteStream *bytestream );
   bool  isNewAccessUnit( bool newPicture, std::ifstream *bitstreamFile, class InputByteStream *bytestream );
 
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  bool      getHTidExternalSetFlag()               const { return m_mTidExternalSet; }
+  void      setHTidExternalSetFlag(bool mTidExternalSet)  { m_mTidExternalSet = mTidExternalSet; }
+  bool      getHTidOpiSetFlag()               const { return m_mTidOpiSet; }
+  void      setHTidOpiSetFlag(bool mTidOpiSet)  { m_mTidOpiSet = mTidOpiSet; }
+  bool      getTOlsIdxExternalFlag()               const { return m_tOlsIdxTidExternalSet; }
+  void      setTOlsIdxExternalFlag (bool tOlsIdxExternalSet)  { m_tOlsIdxTidExternalSet = tOlsIdxExternalSet; }
+  bool      getTOlsIdxOpiFlag()               const { return m_tOlsIdxTidOpiSet; }
+  void      setTOlsIdxOpiFlag(bool tOlsIdxOpiSet)  { m_tOlsIdxTidOpiSet = tOlsIdxOpiSet; }
+  const OPI* getOPI()                     { return m_opi; }
+#endif
+
 protected:
   void  xUpdateRasInit(Slice* slice);
 
@@ -281,6 +300,9 @@ protected:
   void  xCheckParameterSetConstraints( const int layerId );
   void      xDecodePicHeader( InputNALUnit& nalu );
   bool      xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDisplay);
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  void      xDecodeOPI( InputNALUnit& nalu );
+#endif
   void      xDecodeVPS( InputNALUnit& nalu );
   void      xDecodeDCI( InputNALUnit& nalu );
   void      xDecodeSPS( InputNALUnit& nalu );
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index 9cb9e2152dfc9808106aa0c7a7b43f7984e4f3fa..0734e11ef777e865d5cedc8c7ce25bb516bee858 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -2109,6 +2109,44 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
   xReadRbspTrailingBits();
 }
 
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+void HLSyntaxReader::parseOPI(OPI* opi)
+{
+#if ENABLE_TRACING
+  xTraceOPIHeader();
+#endif
+  uint32_t  symbol;
+
+  READ_FLAG(symbol, "opi_ols_info_present_flag");
+  opi->setOlsInfoPresentFlag(symbol);
+  READ_FLAG(symbol, "opi_htid_info_present_flag");
+  opi->setHtidInfoPresentFlag(symbol);
+
+  if (opi->getOlsInfoPresentFlag()) 
+  {
+    READ_UVLC(symbol, "opi_ols_idx");  
+    opi->setOpiOlsIdx(symbol);
+  }
+
+  if (opi->getHtidInfoPresentFlag()) 
+  {
+    READ_CODE(3, symbol, "opi_htid_plus1");
+    opi->setOpiHtidPlus1(symbol);
+  }
+
+  READ_FLAG(symbol, "opi_extension_flag");
+  if (symbol)
+  {
+    while (xMoreRbspData())
+    {
+      READ_FLAG(symbol, "opi_extension_data_flag");
+    }
+  }
+  xReadRbspTrailingBits();
+}
+#endif
+
+
 void HLSyntaxReader::parseDCI(DCI* dci)
 {
 #if ENABLE_TRACING
diff --git a/source/Lib/DecoderLib/VLCReader.h b/source/Lib/DecoderLib/VLCReader.h
index b49813eba5bb55df7fa60f35f64be5d68526bc35..5c2534500abb22be92c477132e12c59451c54b66 100644
--- a/source/Lib/DecoderLib/VLCReader.h
+++ b/source/Lib/DecoderLib/VLCReader.h
@@ -156,6 +156,9 @@ protected:
 
 public:
   void  setBitstream        ( InputBitstream* p )   { m_pcBitstream = p; }
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  void  parseOPI            ( OPI* opi );
+#endif
   void  parseVPS            ( VPS* pcVPS );
   void  parseDCI            ( DCI* dci );
   void  parseSPS            ( SPS* pcSPS );
diff --git a/source/Lib/EncoderLib/AnnexBwrite.h b/source/Lib/EncoderLib/AnnexBwrite.h
index e696e68f68c43584380426beef03ce5ff2c9dc49..d9007085fbe75a4cc0b1bbaf37f9c8a4e88f5975 100644
--- a/source/Lib/EncoderLib/AnnexBwrite.h
+++ b/source/Lib/EncoderLib/AnnexBwrite.h
@@ -78,8 +78,14 @@ std::vector<uint32_t> writeAnnexBAccessUnit(std::ostream& out, const AccessUnit&
   for (AccessUnit::const_iterator it = au.begin(); it != au.end(); it++)
   {
     const NALUnitEBSP& nalu = **it;
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+    const bool useLongStartCode = (it == au.begin() || nalu.m_nalUnitType == NAL_UNIT_OPI || nalu.m_nalUnitType == NAL_UNIT_DCI || nalu.m_nalUnitType == NAL_UNIT_VPS || nalu.m_nalUnitType == NAL_UNIT_SPS
+                                   || nalu.m_nalUnitType == NAL_UNIT_PPS || nalu.m_nalUnitType == NAL_UNIT_PREFIX_APS || nalu.m_nalUnitType == NAL_UNIT_SUFFIX_APS);
+#else
     const bool useLongStartCode = (it == au.begin() || nalu.m_nalUnitType == NAL_UNIT_DCI || nalu.m_nalUnitType == NAL_UNIT_VPS || nalu.m_nalUnitType == NAL_UNIT_SPS
                                    || nalu.m_nalUnitType == NAL_UNIT_PPS || nalu.m_nalUnitType == NAL_UNIT_PREFIX_APS || nalu.m_nalUnitType == NAL_UNIT_SUFFIX_APS);
+#endif
+
     const uint32_t size = writeAnnexBNalUnit(out, nalu, useLongStartCode);
 
     annexBsizes.push_back(size);
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index 1f15e503e1b5343ca95726ac46d23228304a6df2..b4b60bab2815549fe1b411600ef8d739239e0a02 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -682,6 +682,11 @@ protected:
   CostMode  m_costMode;                                       ///< The cost function to use, primarily when considering lossless coding.
   bool      m_TSRCdisableLL;                                  ///< Disable TSRC for lossless
 
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  OPI       m_opi;
+  bool      m_OPIEnabled;                                     ///< enable Operating Point Information (OPI)
+#endif
+
   DCI       m_dci;
   bool      m_DCIEnabled;                                     ///< enable Decoding Capability Information (DCI)
 
@@ -1776,6 +1781,11 @@ public:
   bool         getTSRCdisableLL       ()                             { return m_TSRCdisableLL;         }
   void         setTSRCdisableLL       ( bool b )                     { m_TSRCdisableLL = b;            }
 
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  void         setOPI(OPI *p)                                        { m_opi = *p; }
+  OPI*         getOPI()                                              { return &m_opi; }
+#endif
+
   void         setDCI(DCI *p)                                        { m_dci = *p; }
   DCI*         getDCI()                                              { return &m_dci; }
   void         setUseRecalculateQPAccordingToLambda (bool b)         { m_recalculateQPAccordingToLambda = b;    }
@@ -1787,6 +1797,12 @@ public:
   void         setHarmonizeGopFirstFieldCoupleEnabled( bool b )      { m_bHarmonizeGopFirstFieldCoupleEnabled = b; }
   bool         getHarmonizeGopFirstFieldCoupleEnabled( ) const       { return m_bHarmonizeGopFirstFieldCoupleEnabled; }
 
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  bool         getOPIEnabled()                      { return m_OPIEnabled; }
+  void         setOPIEnabled(bool i)                { m_OPIEnabled = i; }
+  void         setHtidPlus1(int HTid)               { m_opi.setHtidInfoPresentFlag(true); m_opi.setOpiHtidPlus1(HTid); }
+  void         setTargetOlsIdx(int TOlsIdx)         { m_opi.setOlsInfoPresentFlag(true); m_opi.setOpiOlsIdx(TOlsIdx); }
+#endif
 
   bool         getDCIEnabled()                      { return m_DCIEnabled; }
   void         setDCIEnabled(bool i)                { m_DCIEnabled = i; }
diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp
index cb5dd2b16fe64584e9edeaebd6dc02c494248dbb..7da281222cb26f534afb1da3876839887a3c36ef 100644
--- a/source/Lib/EncoderLib/EncGOP.cpp
+++ b/source/Lib/EncoderLib/EncGOP.cpp
@@ -310,6 +310,18 @@ void EncGOP::init ( EncLib* pcEncLib )
 #endif
 }
 
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+int EncGOP::xWriteOPI (AccessUnit &accessUnit, const OPI *opi)
+{
+  OutputNALUnit nalu(NAL_UNIT_OPI);
+  m_HLSWriter->setBitstream( &nalu.m_Bitstream );
+  CHECK( nalu.m_temporalId, "The value of TemporalId of OPI NAL units shall be equal to 0" );
+  m_HLSWriter->codeOPI( opi );
+  accessUnit.push_back(new NALUnitEBSP(nalu));
+  return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
+}
+#endif
+
 int EncGOP::xWriteVPS (AccessUnit &accessUnit, const VPS *vps)
 {
   OutputNALUnit nalu(NAL_UNIT_VPS);
@@ -373,6 +385,12 @@ int EncGOP::xWriteParameterSets(AccessUnit &accessUnit, Slice *slice, const bool
   {
     if (layerIdx == 0)
     {
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+      if (m_pcCfg->getOPIEnabled())
+      {
+        actualTotalBits += xWriteOPI(accessUnit, m_pcEncLib->getOPI());
+      }
+#endif
       if (m_pcCfg->getDCIEnabled())
       {
         actualTotalBits += xWriteDCI(accessUnit, m_pcEncLib->getDCI());
@@ -496,13 +514,24 @@ void EncGOP::xWriteLeadingSEIOrdered (SEIMessages& seiMessages, SEIMessages& duI
 {
   AccessUnit::iterator itNalu = accessUnit.begin();
 
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
   while ((itNalu != accessUnit.end()) &&
     ((*itNalu)->m_nalUnitType == NAL_UNIT_ACCESS_UNIT_DELIMITER
+      || (*itNalu)->m_nalUnitType == NAL_UNIT_OPI
       || (*itNalu)->m_nalUnitType == NAL_UNIT_VPS
       || (*itNalu)->m_nalUnitType == NAL_UNIT_DCI
       || (*itNalu)->m_nalUnitType == NAL_UNIT_SPS
       || (*itNalu)->m_nalUnitType == NAL_UNIT_PPS
       ))
+#else
+  while ((itNalu != accessUnit.end()) &&
+    ((*itNalu)->m_nalUnitType == NAL_UNIT_ACCESS_UNIT_DELIMITER
+      || (*itNalu)->m_nalUnitType == NAL_UNIT_VPS
+      || (*itNalu)->m_nalUnitType == NAL_UNIT_DCI
+      || (*itNalu)->m_nalUnitType == NAL_UNIT_SPS
+      || (*itNalu)->m_nalUnitType == NAL_UNIT_PPS
+      ))
+#endif
   {
     itNalu++;
   }
@@ -4289,7 +4318,11 @@ void EncGOP::xCalculateAddPSNR(Picture* pcPic, PelUnitBuf cPicD, const AccessUni
     if( ( *it )->m_nalUnitType != NAL_UNIT_PREFIX_SEI && ( *it )->m_nalUnitType != NAL_UNIT_SUFFIX_SEI )
     {
       numRBSPBytes += numRBSPBytes_nal;
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+      if (it == accessUnit.begin() || (*it)->m_nalUnitType == NAL_UNIT_OPI || (*it)->m_nalUnitType == NAL_UNIT_VPS || (*it)->m_nalUnitType == NAL_UNIT_DCI || (*it)->m_nalUnitType == NAL_UNIT_SPS || (*it)->m_nalUnitType == NAL_UNIT_PPS || (*it)->m_nalUnitType == NAL_UNIT_PREFIX_APS || (*it)->m_nalUnitType == NAL_UNIT_SUFFIX_APS)
+#else
       if (it == accessUnit.begin() || (*it)->m_nalUnitType == NAL_UNIT_VPS || (*it)->m_nalUnitType == NAL_UNIT_DCI || (*it)->m_nalUnitType == NAL_UNIT_SPS || (*it)->m_nalUnitType == NAL_UNIT_PPS || (*it)->m_nalUnitType == NAL_UNIT_PREFIX_APS || (*it)->m_nalUnitType == NAL_UNIT_SUFFIX_APS)
+#endif
       {
         numRBSPBytes += 4;
       }
diff --git a/source/Lib/EncoderLib/EncGOP.h b/source/Lib/EncoderLib/EncGOP.h
index 41750c24c4da036d4f5c98126e1c822b19831904..16f0de8ebcaef9099f5180a42815feaa36e44165 100644
--- a/source/Lib/EncoderLib/EncGOP.h
+++ b/source/Lib/EncoderLib/EncGOP.h
@@ -318,6 +318,9 @@ protected:
   void xWriteTrailingSEIMessages (SEIMessages& seiMessages, AccessUnit &accessUnit, int temporalId);
   void xWriteDuSEIMessages       (SEIMessages& duInfoSeiMessages, AccessUnit &accessUnit, int temporalId, std::deque<DUData> &duData);
 
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  int xWriteOPI (AccessUnit &accessUnit, const OPI *opi);
+#endif
   int xWriteVPS (AccessUnit &accessUnit, const VPS *vps);
   int xWriteDCI (AccessUnit &accessUnit, const DCI *dci);
   int xWriteSPS( AccessUnit &accessUnit, const SPS *sps, const int layerId = 0 );
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index a8599060f02da7deb427bea2d0ebbb6df3b4f082..08e9ccf2ed9a2c4292f0464855fef10bcdad6ab7 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -233,7 +233,9 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf )
   }
 
   xInitVPS( sps0 );
-
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  xInitOPI(m_opi);
+#endif
   xInitDCI(m_dci, sps0);
 #if ENABLE_SPLIT_PARALLELISM
   if( omp_get_dynamic() )
@@ -1153,6 +1155,25 @@ void EncLib::xInitVPS( const SPS& sps )
   m_vps->checkVPS();
 }
 
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+void EncLib::xInitOPI(OPI& opi)
+{
+  if (m_OPIEnabled && m_vps)
+  {
+    if (!opi.getOlsInfoPresentFlag())
+    {
+      opi.setOpiOlsIdx(m_vps->deriveTargetOLSIdx());
+      opi.setOlsInfoPresentFlag(true);    
+    }
+    if (!opi.getHtidInfoPresentFlag())
+    {
+      opi.setOpiHtidPlus1(m_vps->getMaxTidinTOls(opi.getOpiOlsIdx()) + 1);
+      opi.setHtidInfoPresentFlag(true);
+    }
+  }
+}
+#endif
+
 void EncLib::xInitDCI(DCI& dci, const SPS& sps)
 {
   dci.setMaxSubLayersMinus1(sps.getMaxTLayers() - 1);
diff --git a/source/Lib/EncoderLib/EncLib.h b/source/Lib/EncoderLib/EncLib.h
index c8885d9873b322b73978ad3bb186879a4017c476..61b9d9b4c12e1fa3e0c8bc2c928c9c88bd2f1c1b 100644
--- a/source/Lib/EncoderLib/EncLib.h
+++ b/source/Lib/EncoderLib/EncLib.h
@@ -167,6 +167,9 @@ 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.
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  void  xInitOPI(OPI& opi); ///< initialize Operating point Information (OPI) from encoder options
+#endif
   void  xInitDCI(DCI& dci, const SPS& sps); ///< initialize Decoding Capability Information (DCI) from encoder options
   void  xInitVPS( const SPS& sps ); ///< initialize VPS from encoder options
   void  xInitSPS( SPS& sps );       ///< initialize SPS from encoder options
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index fddfc8971df047afea025d9c9f91a3835007981f..84628f2c13b9eb7ee2650b3822f8521bfe882d43 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -1323,6 +1323,30 @@ void HLSWriter::codeDCI(const DCI* dci)
   WRITE_FLAG(0, "dci_extension_flag");
   xWriteRbspTrailingBits();
 }
+
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+void HLSWriter::codeOPI(const OPI *opi)
+{
+#if ENABLE_TRACING
+  xTraceOPIHeader();
+#endif
+  WRITE_FLAG(opi->getOlsInfoPresentFlag(), "opi_ols_info_present_flag");
+  WRITE_FLAG(opi->getHtidInfoPresentFlag(), "opi_htid_info_present_flag");
+
+  if (opi->getOlsInfoPresentFlag()) 
+  {
+    WRITE_UVLC(opi->getOpiOlsIdx(), "opi_ols_idx");  
+  }
+
+  if (opi->getHtidInfoPresentFlag()) 
+  {
+    WRITE_CODE(opi->getOpiHtidPlus1(), 3, "opi_htid_plus1");  
+  }
+  WRITE_FLAG(0, "opi_extension_flag");
+  xWriteRbspTrailingBits();
+}
+#endif
+
 void HLSWriter::codeVPS(const VPS* pcVPS)
 {
 #if ENABLE_TRACING
@@ -3038,4 +3062,4 @@ void HLSWriter::alfFilter( const AlfParam& alfParam, const bool isChroma, const
 }
 
 
-//! \}
+//! \}
\ No newline at end of file
diff --git a/source/Lib/EncoderLib/VLCWriter.h b/source/Lib/EncoderLib/VLCWriter.h
index 9de8b80880ca76d5730ada81a9a2ae3f48776458..5496858cc8bce0f75547af3e7f636f2e0908e6f6 100644
--- a/source/Lib/EncoderLib/VLCWriter.h
+++ b/source/Lib/EncoderLib/VLCWriter.h
@@ -141,6 +141,9 @@ public:
   void  codeDCI                 ( const DCI* dci );
   void  codePictureHeader       ( PicHeader* picHeader, bool writeRbspTrailingBits, Slice *slice = 0 );
   void  codeSliceHeader         ( Slice* pcSlice, PicHeader *picheader = 0 );
+#if JVET_S0163_ON_TARGETOLS_SUBLAYERS
+  void  codeOPI                 ( const OPI* opi );
+#endif
   void  codeConstraintInfo      ( const ConstraintInfo* cinfo );
   void  codeProfileTierLevel    ( const ProfileTierLevel* ptl, bool profileTierPresentFlag, int maxNumSubLayersMinus1 );
   void  codeOlsHrdParameters(const GeneralHrdParams * generalHrd, const OlsHrdParams *olsHrd , const uint32_t firstSubLayer, const uint32_t maxNumSubLayersMinus1);