diff --git a/cfg/sei_vui/source_picture_timing_info.cfg b/cfg/sei_vui/source_picture_timing_info.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..c7078fe0145949de8d181ba95dbee34b22550a54
--- /dev/null
+++ b/cfg/sei_vui/source_picture_timing_info.cfg
@@ -0,0 +1,6 @@
+#======== Source Picture Timing Information SEI message =====================
+SEISourcePictureTimingInfo : 1
+SEISPTISourceTimingEqualsOutputTimingFlag : 0
+SEISPTISourceType : 0
+SEISPTITimeScale : 27000000
+SEISPTINumUnitsInElementalInterval : 1080000
\ No newline at end of file
diff --git a/doc/software-manual.tex b/doc/software-manual.tex
index 490e9016e7a6db4abef2541b2a829a263498857a..58190b6459691245eeacbd7f83167bfb10f8fb12 100644
--- a/doc/software-manual.tex
+++ b/doc/software-manual.tex
@@ -3978,6 +3978,7 @@ The table below lists the SEI messages defined for Version 1 and Range-Extension
   211 & Neural netowrk post-filter activation & Table \ref{tab:sei-nn-post-filter-activation} \\
   212 & Phase indication                         & Table \ref{tab:sei-phase-indication} \\
   213 & Processing order SEI messages            & Table \ref{tab:sei-processing order}\\
+  215 & Source Picture Timing Information        & Table \ref{tab:sei-source-picture-timing-info}\\
 \end{SEIListTable}
 %%
 %% SEI messages
@@ -6082,6 +6083,28 @@ Specifies type of information the of privacy protection optimization that is app
 \\
 \end{OptionTableNoShorthand}
 
+\begin{OptionTableNoShorthand}{Source picture timing information SEI message encoder parameters}{tab:sei-source-picture-timing-info}
+\Option{SEISourcePictureTimingInfo} &
+\Default{false} &
+Enables (true) or disables (false) the insertion of Source picture timing information SEI message.
+\\
+\Option{SEISPTISourceTimingEqualsOutputTimingFlag} &
+\Default{true} &
+Indicates the timing of source pictures is the same as the timing of corresponding decoded output pictures(true) or indicates the timing of source pictures might not be the same as the timing of corresponding decoded output pictures(false).
+\\
+\Option{SEISPTISourceType} &
+\Default{0} &
+Indicates the timing relationship between source pictures and corresponding decoded output pictures.
+\\
+\Option{SEISPTITimeScale} &
+\Default{27000000} &
+Specifies the number of time units that pass in one second.
+\\
+\Option{SEISPTINumUnitsInElementalInterval} &
+\Default{1080000} &
+Specifies the number of time units of a clock operating at the frequency spti_time_scale Hz that corresponds to the indicated elemental source picture interval of consecutive pictures in output order in the CLVS.
+\\
+\end{OptionTableNoShorthand}
 %\Option{SEITimeCode} &
 %\Default{false} &
 %When true, generate time code SEI messages.
diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 7b933585adeb07fbe41a1246c4794793d4bde983..dfafd548a28545b3ca9581e61d20f4024db19200 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -1397,6 +1397,18 @@ void EncApp::xInitLibCfg( int layerIdx )
 
   m_cEncLib.setPoSEIEnabled                                      (m_poSEIEnabled);
   m_cEncLib.setPoSEIId                                           (m_poSEIId);
+
+#if JVET_AG2034_SPTI_SEI
+  m_cEncLib.setSptiSEIEnabled(m_sptiSEIEnabled);
+  if (m_sptiSEIEnabled)
+  {
+    m_cEncLib.setmSptiSEISourceTimingEqualsOutputTimingFlag(m_sptiSourceTimingEqualsOutputTimingFlag);
+    m_cEncLib.setmSptiSEISourceType(m_sptiSourceType);
+    m_cEncLib.setmSptiSEITimeScale(m_sptiTimeScale);
+    m_cEncLib.setmSptiSEINumUnitsInElementalInterval(m_sptiNumUnitsInElementalInterval);
+  }
+#endif
+
   m_cEncLib.setPoSEINumMinus2                                    (m_poSEINumMinus2);
   m_cEncLib.setPoSEIWrappingFlag                                 (m_poSEIWrappingFlag);
   m_cEncLib.setPoSEIImportanceFlag                               (m_poSEIImportanceFlag);
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index 7176d2fc81a6bad3c6616e86ca2ac4c3b713de3d..38966e4cfee66ce2d9e72d25537a6ca71d4f3586 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -1460,6 +1460,13 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
 ("SEISiiTimeScale", m_siiSEITimeScale, 27000000u, "Specifies sii_time_scale")
 ("SEISiiInputNumUnitsInShutterInterval", cfg_siiSEIInputNumUnitsInSI, cfg_siiSEIInputNumUnitsInSI, "Specifies sub_layer_num_units_in_shutter_interval")
 
+#if JVET_AG2034_SPTI_SEI
+("SEISourcePictureTimingInfo", m_sptiSEIEnabled, false, "Controls if source picture timing information SEI message is enabled")
+("SEISPTISourceTimingEqualsOutputTimingFlag", m_sptiSourceTimingEqualsOutputTimingFlag, true, "Indicates the timing of source pictures is the same as the timing of corresponding decoded output pictures")
+("SEISPTISourceType", m_sptiSourceType, 0u, "Indicates the timing relationship between source pictures and corresponding decoded output pictures.")
+("SEISPTITimeScale", m_sptiTimeScale, 27000000u, "Specifies the number of time units that pass in one second.")
+("SEISPTINumUnitsInElementalInterval", m_sptiNumUnitsInElementalInterval, 1080000u, "Specifies the number of time units of a clock operating at the frequency spti_time_scale Hz that corresponds to the indicated elemental source picture interval of consecutive pictures in output order in the CLVS.")
+#endif
 #if ENABLE_TRACING
 ("TraceChannelsList", bTracingChannelsList, false, "List all available tracing channels")
 ("TraceRule", sTracingRule, std::string(""), "Tracing rule (ex: \"D_CABAC:poc==8\" or \"D_REC_CB_LUMA:poc==8\")")
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index b435d25183338273081eb6f6eafa1428ec2a1e98..4aeb297123293bf4a3194135b0b2608e6c03ef4e 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -941,6 +941,13 @@ protected:
   std::string m_shutterIntervalPreFileName;                   ///< output Pre-Filtering video
   int         m_SII_BlendingRatio;
   void        setBlendingRatioSII(int value) { m_SII_BlendingRatio = value; }
+#if JVET_AG2034_SPTI_SEI
+  bool     m_sptiSEIEnabled;
+  bool     m_sptiSourceTimingEqualsOutputTimingFlag;
+  uint32_t m_sptiSourceType;
+  uint32_t m_sptiTimeScale;
+  uint32_t m_sptiNumUnitsInElementalInterval;
+#endif
 #if GREEN_METADATA_SEI_ENABLED
 public:
   std::string getGMFAFile ();
diff --git a/source/Lib/CommonLib/SEI.cpp b/source/Lib/CommonLib/SEI.cpp
index 6bd1aeefd2e37581a9905facc2eca3edcb87b338..75cc4c3007cb5f0d150d7d1468dfd85c2ca90039 100644
--- a/source/Lib/CommonLib/SEI.cpp
+++ b/source/Lib/CommonLib/SEI.cpp
@@ -483,6 +483,9 @@ static const std::map<SEI::PayloadType, const char *> payloadTypeStrings = {
   { SEI::PayloadType::NEURAL_NETWORK_POST_FILTER_ACTIVATION, "Neural network post-filter activation" },
   { SEI::PayloadType::PHASE_INDICATION, "Phase Indication" },
   { SEI::PayloadType::SEI_PROCESSING_ORDER, "SEI messages Processing order" },
+#if JVET_AG2034_SPTI_SEI
+  { SEI::PayloadType::SOURCE_PICTURE_TIMING_INFO, "Source picture timing info" },
+#endif
 };
 
 const char *SEI::getSEIMessageString(SEI::PayloadType payloadType)
@@ -507,6 +510,16 @@ SEIShutterIntervalInfo::SEIShutterIntervalInfo(const SEIShutterIntervalInfo& sei
   m_siiFixedSIwithinCLVS = sei.m_siiFixedSIwithinCLVS;
   m_siiSubLayerNumUnitsInSI = sei.m_siiSubLayerNumUnitsInSI;
 }
+#if JVET_AG2034_SPTI_SEI
+SEISourcePictureTimingInfo::SEISourcePictureTimingInfo(const SEISourcePictureTimingInfo& sei)
+{
+  m_sptiSEIEnabled                         = sei.m_sptiSEIEnabled;
+  m_sptiSourceTimingEqualsOutputTimingFlag = sei.m_sptiSourceTimingEqualsOutputTimingFlag;
+  m_sptiSourceType                         = sei.m_sptiSourceType;
+  m_sptiTimeScale                          = sei.m_sptiTimeScale;
+  m_sptiNumUnitsInElementalInterval        = sei.m_sptiNumUnitsInElementalInterval;
+}
+#endif
 
 SEIProcessingOrderInfo::SEIProcessingOrderInfo(const SEIProcessingOrderInfo& sei)
 {
diff --git a/source/Lib/CommonLib/SEI.h b/source/Lib/CommonLib/SEI.h
index d786c4e04244efff8fc65000d1f77abd32204c2b..27cac5298724827f07ad59e34eeaf355aabf16af 100644
--- a/source/Lib/CommonLib/SEI.h
+++ b/source/Lib/CommonLib/SEI.h
@@ -104,6 +104,9 @@ public:
 #if JVET_AH2006_EOI_SEI
     ENCODER_OPTIMIZATION_INFO = 215,
 #endif 
+#if JVET_AG2034_SPTI_SEI
+    SOURCE_PICTURE_TIMING_INFO = 216,
+#endif
   };
 
   SEI() {}
@@ -155,6 +158,29 @@ public:
   std::vector<unsigned> m_siiSubLayerNumUnitsInSI;
 };
 
+#if JVET_AG2034_SPTI_SEI
+class SEISourcePictureTimingInfo : public SEI
+{
+public:
+  PayloadType payloadType() const { return PayloadType::SOURCE_PICTURE_TIMING_INFO; }
+  SEISourcePictureTimingInfo() {}
+
+  SEISourcePictureTimingInfo(const SEISourcePictureTimingInfo& sei);
+  virtual ~SEISourcePictureTimingInfo() {}
+
+  bool                  m_sptiSEIEnabled;
+  bool                  m_sptiSourceTimingEqualsOutputTimingFlag;
+  uint32_t              m_sptiSourceType;
+  uint32_t              m_sptiTimeScale;
+  uint32_t              m_sptiNumUnitsInElementalInterval;
+  bool                  m_sptiCancelFlag;
+  bool                  m_sptiPersistenceFlag;
+  bool                  m_sptiSourceTypePresentFlag;
+  uint32_t              m_sptiMaxSublayersMinus1;
+  std::vector<uint32_t> m_sptiSublayerIntervalScaleFactor;
+  std::vector<bool>     m_sptiSublayerSynthesizedPictureFlag;
+};
+#endif
 class SEIProcessingOrderInfo : public SEI
 {
 public:
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 0271535d9aecfb4193ce142add4f897bf9d2d996..96b4c540d8c5afb0e92b7186e8506adfded2145c 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -62,8 +62,12 @@
 
 
 
+
 #define JVET_AF2032_NNPFC_APPLICATION_INFORMATION_SIGNALING 1 // JVET-AF2032: Conditionally signal application tag URI presence flag and tag URI in the NNPFC metadata extension
 
+#define JVET_AG2034_SPTI_SEI 1 //JVET-AE0079, JVET-AF0055, JVET-AF0069, JVET-AF0097, JVET-AG0191, JVET-AG0188 
+
+
 //########### place macros to be be kept below this line ###############
 
 #define GDR_ENABLED   1
diff --git a/source/Lib/DecoderLib/SEIread.cpp b/source/Lib/DecoderLib/SEIread.cpp
index d70e5cb9126397af800bb1fc5581ae78df7c6b4c..19f2573d36d4d55b15e6cf53b6dbdbd91c829f36 100644
--- a/source/Lib/DecoderLib/SEIread.cpp
+++ b/source/Lib/DecoderLib/SEIread.cpp
@@ -547,6 +547,12 @@ bool SEIReader::xReadSEImessage(SEIMessages& seis, const NalUnitType nalUnitType
       sei = new SEIEncoderOptimizationInfo;
       xParseSEIEncoderOptimizationInfo((SEIEncoderOptimizationInfo &)*sei, payloadSize, pDecodedMessageOutputStream);
       break;
+#endif
+#if JVET_AG2034_SPTI_SEI
+    case SEI::PayloadType::SOURCE_PICTURE_TIMING_INFO:
+      sei = new SEISourcePictureTimingInfo;
+      xParseSEISourcePictureTimingInfo((SEISourcePictureTimingInfo&) *sei, payloadSize, pDecodedMessageOutputStream);
+      break;
 #endif
     default:
       for (uint32_t i = 0; i < payloadSize; i++)
@@ -3332,6 +3338,57 @@ void SEIReader::xParseSEIPostFilterHint(SEIPostFilterHint &sei, uint32_t payload
   }
 }
 
+#if JVET_AG2034_SPTI_SEI
+void SEIReader::xParseSEISourcePictureTimingInfo(SEISourcePictureTimingInfo& sei, uint32_t payloadSize,
+                                                 std::ostream* pDecodedMessageOutputStream)
+{
+  uint32_t val;
+  output_sei_message_header(sei, pDecodedMessageOutputStream, payloadSize);
+
+  sei_read_flag(pDecodedMessageOutputStream, val, "spti_cancel_flag");
+  sei.m_sptiCancelFlag = val;
+
+  if (!sei.m_sptiCancelFlag)
+  {
+    sei_read_flag(pDecodedMessageOutputStream, val, "spti_persistence_flag");
+    sei.m_sptiPersistenceFlag = val;
+
+    sei_read_flag(pDecodedMessageOutputStream, val, "spti_source_timing_equals_output_timing_flag");
+    sei.m_sptiSourceTimingEqualsOutputTimingFlag = val;
+
+    if (!sei.m_sptiSourceTimingEqualsOutputTimingFlag)
+    {
+      sei_read_flag(pDecodedMessageOutputStream, val, "spti_source_type_present_flag");
+      sei.m_sptiSourceTypePresentFlag = val;
+
+      if (sei.m_sptiSourceTypePresentFlag)
+      {
+          sei_read_code(pDecodedMessageOutputStream, 16, val, "spti_source_type");
+          sei.m_sptiSourceType = val;
+      }
+      sei_read_code(pDecodedMessageOutputStream, 32, val, "spti_time_scale");
+      sei.m_sptiTimeScale = val;
+      sei_read_code(pDecodedMessageOutputStream, 32, val, "spti_num_units_in_elemental_interval");
+      sei.m_sptiNumUnitsInElementalInterval = val;
+
+      if (sei.m_sptiPersistenceFlag)
+      {
+          sei_read_code(pDecodedMessageOutputStream, 3, val, "spti_max_sublayers_minus_1");
+          sei.m_sptiMaxSublayersMinus1 = val;
+      }
+
+      for (int i = 0; i <= sei.m_sptiMaxSublayersMinus1; i++)
+      {
+          sei_read_uvlc(pDecodedMessageOutputStream, val, "spti_sublayer_interval_scale_factor");
+          sei.m_sptiSublayerIntervalScaleFactor.push_back(val);
+          sei_read_flag(pDecodedMessageOutputStream, val, "spti_sublayer_synthesized_picture_flag");
+          sei.m_sptiSublayerSynthesizedPictureFlag.push_back(val);
+      }
+    }
+  }
+}
+#endif
+
 #if JVET_S0257_DUMP_360SEI_MESSAGE
 void SeiCfgFileDump::write360SeiDump (std::string decoded360MessageFileName, SEIMessages& seis, const SPS* sps)
 {
diff --git a/source/Lib/DecoderLib/SEIread.h b/source/Lib/DecoderLib/SEIread.h
index e35547404db179f2771b0dd715b8af87d489f5df..47d52f2d50e7c809934da87fb15273f5316484fe 100644
--- a/source/Lib/DecoderLib/SEIread.h
+++ b/source/Lib/DecoderLib/SEIread.h
@@ -124,6 +124,10 @@ protected:
   void xParseSEIProcessingOrder(SEIProcessingOrderInfo& sei, const NalUnitType nalUnitType, const uint32_t nuhLayerId, uint32_t payloadSize, const VPS* vps, const SPS* sps, HRD& hrd, std::ostream* decodedMessageOutputStream);
   void xParseSEIProcessingOrderNesting(SEIProcessingOrderNesting& sei, const NalUnitType nalUnitType, const uint32_t nuhLayerId, uint32_t payloadSize, const VPS* vps, const SPS* sps, HRD& hrd, std::ostream* decodedMessageOutputStream);
   void xParseSEIPostFilterHint(SEIPostFilterHint &sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream);
+#if JVET_AG2034_SPTI_SEI
+  void xParseSEISourcePictureTimingInfo(SEISourcePictureTimingInfo& sei, uint32_t payloadSize,
+                                        std::ostream* pDecodedMessageOutputStream);
+#endif
 
   void sei_read_scode(std::ostream *pOS, uint32_t length, int& code, const char *pSymbolName);
   void sei_read_code(std::ostream *pOS, uint32_t length, uint32_t &ruiCode, const char *pSymbolName);
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index 0df5442af348f194008d7043b277914f56643dc2..699df615bdb54eb1f5e4949749a0f3904035d053 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -690,6 +690,13 @@ protected:
   uint32_t                m_siiSEINumUnitsInShutterInterval;
   uint32_t                m_siiSEITimeScale;
   std::vector<uint32_t>   m_siiSEISubLayerNumUnitsInSI;
+#if JVET_AG2034_SPTI_SEI
+  bool     m_sptiSEIEnabled;
+  bool     m_sptiSourceTimingEqualsOutputTimingFlag;
+  uint32_t m_sptiSourceType;
+  uint32_t m_sptiTimeScale;
+  uint32_t m_sptiNumUnitsInElementalInterval;
+#endif
 
   bool                    m_nnPostFilterSEICharacteristicsEnabled;
   bool                    m_nnPostFilterSEICharacteristicsUseSuffixSEI;
@@ -1950,6 +1957,19 @@ public:
   void     setSiiSEISubLayerNumUnitsInSI(const std::vector<uint32_t>& b) { m_siiSEISubLayerNumUnitsInSI = b; }
   uint32_t getSiiSEISubLayerNumUnitsInSI(uint32_t idx) const { return m_siiSEISubLayerNumUnitsInSI[idx]; }
 
+#if JVET_AG2034_SPTI_SEI
+  void     setSptiSEIEnabled(bool b) { m_sptiSEIEnabled = b; }
+  bool     getSptiSEIEnabled() { return m_sptiSEIEnabled; }
+  void     setmSptiSEISourceTimingEqualsOutputTimingFlag(bool b) { m_sptiSourceTimingEqualsOutputTimingFlag = b; }
+  bool     getmSptiSEISourceTimingEqualsOutputTimingFlag() { return m_sptiSourceTimingEqualsOutputTimingFlag; }
+  void     setmSptiSEISourceType(uint32_t b) { m_sptiSourceType = b; }
+  uint32_t getmSptiSEISourceType() { return m_sptiSourceType; }
+  void     setmSptiSEITimeScale(uint32_t b) { m_sptiTimeScale = b; }
+  uint32_t getmSptiSEITimeScale() { return m_sptiTimeScale; }
+  void     setmSptiSEINumUnitsInElementalInterval(uint32_t b) { m_sptiNumUnitsInElementalInterval = b; }
+  uint32_t getmSptiSEINumUnitsInElementalInterval() { return m_sptiNumUnitsInElementalInterval; }
+#endif
+
   void        setNNPostFilterSEICharacteristicsEnabled(bool enabledFlag)                                                { m_nnPostFilterSEICharacteristicsEnabled = enabledFlag; }
   bool        getNNPostFilterSEICharacteristicsEnabled() const                                                          { return m_nnPostFilterSEICharacteristicsEnabled; }
   void        setNNPostFilterSEICharacteristicsUseSuffixSEI(bool suffixFlag)                                            { m_nnPostFilterSEICharacteristicsUseSuffixSEI = suffixFlag; }
diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp
index fa672a7c8c238fb1b93c1e982f4824c15f4e0277..b2c280c7c438fd0659c2bf68835f5716962147cf 100644
--- a/source/Lib/EncoderLib/EncGOP.cpp
+++ b/source/Lib/EncoderLib/EncGOP.cpp
@@ -919,6 +919,14 @@ void EncGOP::xCreateIRAPLeadingSEIMessages (SEIMessages& seiMessages, const SPS
     m_seiEncoder.initSEIShutterIntervalInfo(seiShutterInterval);
     seiMessages.push_back(seiShutterInterval);
   }
+#if JVET_AG2034_SPTI_SEI
+  if (m_pcCfg->getSptiSEIEnabled())
+  {
+    SEISourcePictureTimingInfo* seiSourcePictureTimingInfo = new SEISourcePictureTimingInfo;
+    m_seiEncoder.initSEISourcePictureTimingInfo(seiSourcePictureTimingInfo);
+    seiMessages.push_back(seiSourcePictureTimingInfo);
+  }
+#endif
   if (m_pcCfg->getNNPostFilterSEICharacteristicsEnabled() && !m_pcCfg->getNNPostFilterSEICharacteristicsUseSuffixSEI())
   {
     xCreateNNPostFilterCharacteristicsSEIMessages(seiMessages);
diff --git a/source/Lib/EncoderLib/SEIEncoder.cpp b/source/Lib/EncoderLib/SEIEncoder.cpp
index 22d9333b339dba9c127bb270ae5d591c9e40ce0b..71ab049bf5eed7ad546c818941d9e55e65e8eaf2 100644
--- a/source/Lib/EncoderLib/SEIEncoder.cpp
+++ b/source/Lib/EncoderLib/SEIEncoder.cpp
@@ -572,7 +572,33 @@ void SEIEncoder::initSEIShutterIntervalInfo(SEIShutterIntervalInfo *seiShutterIn
     }
   }
 }
+#if JVET_AG2034_SPTI_SEI
+void SEIEncoder::initSEISourcePictureTimingInfo(SEISourcePictureTimingInfo* SEISourcePictureTimingInfo)
+{
 
+  CHECK(!(m_isInitialized), "Source picture timing SEI already initialized");
+  CHECK(!(SEISourcePictureTimingInfo != nullptr), "Need a SEISourcePictureTimingInfo for initialization (got nullptr)");
+
+  SEISourcePictureTimingInfo->m_sptiSEIEnabled = m_pcCfg->getSptiSEIEnabled();
+  SEISourcePictureTimingInfo->m_sptiSourceTimingEqualsOutputTimingFlag =
+    m_pcCfg->getmSptiSEISourceTimingEqualsOutputTimingFlag();
+  SEISourcePictureTimingInfo->m_sptiSourceType                  = m_pcCfg->getmSptiSEISourceType();
+  SEISourcePictureTimingInfo->m_sptiTimeScale                   = m_pcCfg->getmSptiSEITimeScale();
+  SEISourcePictureTimingInfo->m_sptiNumUnitsInElementalInterval = m_pcCfg->getmSptiSEINumUnitsInElementalInterval();
+  SEISourcePictureTimingInfo->m_sptiMaxSublayersMinus1          = m_pcCfg->getMaxTempLayer() - 1;
+  SEISourcePictureTimingInfo->m_sptiCancelFlag                  = 0;
+  SEISourcePictureTimingInfo->m_sptiPersistenceFlag             = 1;
+  SEISourcePictureTimingInfo->m_sptiSourceTypePresentFlag = (SEISourcePictureTimingInfo->m_sptiSourceType == 0 ? 0 : 1);
+  SEISourcePictureTimingInfo->m_sptiSublayerSynthesizedPictureFlag =
+    std::vector<bool>(SEISourcePictureTimingInfo->m_sptiMaxSublayersMinus1 + 1, 0);
+
+  for (int i = 0; i <= SEISourcePictureTimingInfo->m_sptiMaxSublayersMinus1; i++)
+  {
+    SEISourcePictureTimingInfo->m_sptiSublayerIntervalScaleFactor.push_back(
+      1 << (SEISourcePictureTimingInfo->m_sptiMaxSublayersMinus1 - i));
+  }
+}
+#endif
 void SEIEncoder::initSEIProcessingOrderInfo(SEIProcessingOrderInfo *seiProcessingOrderInfo, SEIProcessingOrderNesting *seiProcessingOrderNesting)
 {
   assert(m_isInitialized);
diff --git a/source/Lib/EncoderLib/SEIEncoder.h b/source/Lib/EncoderLib/SEIEncoder.h
index 6cd2e28e8ae6e44800086b85d8a020c6fc3fd5c7..bbc2a3dbe448afba45213c2ca1a1dd4102c2eaef 100644
--- a/source/Lib/EncoderLib/SEIEncoder.h
+++ b/source/Lib/EncoderLib/SEIEncoder.h
@@ -93,6 +93,9 @@ public:
   void initSEISEIManifest(SEIManifest *seiSeiManifest, const SEIMessages &seiMessage);
   void initSEISEIPrefixIndication(SEIPrefixIndication *seiSeiPrefixIndications, const SEI *sei);
 
+#if JVET_AG2034_SPTI_SEI
+  void initSEISourcePictureTimingInfo(SEISourcePictureTimingInfo* SEISourcePictureTimingInfo);
+#endif
   void initSEIMultiviewViewPosition(SEIMultiviewViewPosition *sei);
   void initSEIShutterIntervalInfo(SEIShutterIntervalInfo *sei);
   void initSEINeuralNetworkPostFilterCharacteristics(SEINeuralNetworkPostFilterCharacteristics *sei, int filterIdx);
diff --git a/source/Lib/EncoderLib/SEIwrite.cpp b/source/Lib/EncoderLib/SEIwrite.cpp
index 9fc717505637f39394be7f903a293b98ad876ffa..c3417c5a34d6e5a7aa9d8cc7e5817effa330d09b 100644
--- a/source/Lib/EncoderLib/SEIwrite.cpp
+++ b/source/Lib/EncoderLib/SEIwrite.cpp
@@ -196,6 +196,11 @@ void SEIWriter::xWriteSEIpayloadData(OutputBitstream &bs, const SEI &sei, HRD &h
     xWriteSEIEncoderOptimizationInfo(*static_cast<const SEIEncoderOptimizationInfo *>(&sei));
     break;
 #endif 
+#if JVET_AG2034_SPTI_SEI
+  case SEI::PayloadType::SOURCE_PICTURE_TIMING_INFO:
+    xWriteSEISourcePictureTimingInfo(*static_cast<const SEISourcePictureTimingInfo*>(&sei));
+    break;
+#endif
   default:
     THROW("Trying to write unhandled SEI message");
     break;
@@ -1977,7 +1982,6 @@ void SEIWriter::xWriteSEIPostFilterHint(const SEIPostFilterHint &sei)
     }
   }
 }
-
 #if JVET_AH2006_EOI_SEI
 void SEIWriter::xWriteSEIEncoderOptimizationInfo(const SEIEncoderOptimizationInfo &sei)
 {
@@ -2012,4 +2016,40 @@ void SEIWriter::xWriteSEIEncoderOptimizationInfo(const SEIEncoderOptimizationInf
   }
 }
 #endif
+#if JVET_AG2034_SPTI_SEI
+void SEIWriter::xWriteSEISourcePictureTimingInfo(const SEISourcePictureTimingInfo& sei)
+{
+  xWriteFlag(sei.m_sptiCancelFlag, "spti_cancel_flag");
+
+  if (!sei.m_sptiCancelFlag)
+  {
+    xWriteFlag(sei.m_sptiPersistenceFlag, "spti_persistance_flag");
+    xWriteFlag(sei.m_sptiSourceTimingEqualsOutputTimingFlag, "spti_source_timing_equals_output_timing_flag");
+
+    if (!sei.m_sptiSourceTimingEqualsOutputTimingFlag)
+    {
+      xWriteFlag(sei.m_sptiSourceTypePresentFlag, "spti_source_type_present_flag");
+
+      if (sei.m_sptiSourceTypePresentFlag)
+      {
+        xWriteCode(sei.m_sptiSourceType, 16, "spti_source_type");
+      }
+
+      xWriteCode(sei.m_sptiTimeScale, 32, "spti_time_scale");
+      xWriteCode(sei.m_sptiNumUnitsInElementalInterval, 32, "spti_num_units_in_elemental_interval");
+
+      if (sei.m_sptiPersistenceFlag)
+      {
+        xWriteCode(sei.m_sptiMaxSublayersMinus1, 3, "spti_max_sublayers_minus_1");
+      }
+
+      for (int i = 0; i <= sei.m_sptiMaxSublayersMinus1; i++)
+      {
+        xWriteUvlc(sei.m_sptiSublayerIntervalScaleFactor[i], "spti_sublayer_interval_scale_factor");
+        xWriteFlag(sei.m_sptiSublayerSynthesizedPictureFlag[i], "spti_sublayer_synthesized_picture_flag");
+      }
+    }
+  }
+}
+#endif
 //! \}
diff --git a/source/Lib/EncoderLib/SEIwrite.h b/source/Lib/EncoderLib/SEIwrite.h
index 7b18c32ce4c52b64211100acb9cd715eeb5ff201..1052b24a1f47dd77e9761ae8a36aeb21357cb99b 100644
--- a/source/Lib/EncoderLib/SEIwrite.h
+++ b/source/Lib/EncoderLib/SEIwrite.h
@@ -114,9 +114,13 @@ protected:
   void xWriteSEIGreenMetadataInfo                 (const SEIGreenMetadataInfo &sei);
 #endif
   void xWriteSEIPostFilterHint(const SEIPostFilterHint &sei);
+
 #if JVET_AH2006_EOI_SEI
   void xWriteSEIEncoderOptimizationInfo(const SEIEncoderOptimizationInfo &sei);
 #endif
+#if JVET_AG2034_SPTI_SEI
+  void xWriteSEISourcePictureTimingInfo(const SEISourcePictureTimingInfo& sei);
+#endif
 protected:
   HRD m_nestingHrd;
 };