From c1435e4f51f4ad86bb1b6760227182a1e77f45d3 Mon Sep 17 00:00:00 2001
From: Jonatan Samuelsson <jonatan.samuelsson@divideon.com>
Date: Fri, 12 Aug 2022 15:30:14 +0000
Subject: [PATCH] JVET-A0110: Adding support for Phase indication SEI message

---
 cfg/sei_vui/phase_indication.cfg        |  5 +++
 cfg/sei_vui/phase_indication_rpr1.5.cfg | 10 ++++++
 cfg/sei_vui/phase_indication_rpr2.0.cfg | 10 ++++++
 doc/software-manual.tex                 | 44 +++++++++++++++++++++++++
 source/App/EncoderApp/EncApp.cpp        | 12 +++++++
 source/App/EncoderApp/EncAppCfg.cpp     | 37 +++++++++++++++++++++
 source/App/EncoderApp/EncAppCfg.h       | 13 ++++++++
 source/Lib/CommonLib/SEI.cpp            |  3 ++
 source/Lib/CommonLib/SEI.h              | 17 ++++++++++
 source/Lib/CommonLib/TypeDef.h          |  1 +
 source/Lib/DecoderLib/SEIread.cpp       | 26 +++++++++++++++
 source/Lib/DecoderLib/SEIread.h         |  3 ++
 source/Lib/EncoderLib/EncCfg.h          | 34 +++++++++++++++++++
 source/Lib/EncoderLib/EncGOP.cpp        | 38 +++++++++++++++++++++
 source/Lib/EncoderLib/EncGOP.h          |  7 ++++
 source/Lib/EncoderLib/SEIEncoder.cpp    | 23 +++++++++++++
 source/Lib/EncoderLib/SEIEncoder.h      |  3 ++
 source/Lib/EncoderLib/SEIwrite.cpp      | 15 +++++++++
 source/Lib/EncoderLib/SEIwrite.h        |  3 ++
 19 files changed, 304 insertions(+)
 create mode 100644 cfg/sei_vui/phase_indication.cfg
 create mode 100644 cfg/sei_vui/phase_indication_rpr1.5.cfg
 create mode 100644 cfg/sei_vui/phase_indication_rpr2.0.cfg

diff --git a/cfg/sei_vui/phase_indication.cfg b/cfg/sei_vui/phase_indication.cfg
new file mode 100644
index 000000000..a90add14e
--- /dev/null
+++ b/cfg/sei_vui/phase_indication.cfg
@@ -0,0 +1,5 @@
+SEIPhaseIndicationFullResolution:               1
+SEIPIHorPhaseNumFullResolution:                 1
+SEIPIHorPhaseDenMinus1FullResolution:           1
+SEIPIVerPhaseNumFullResolution:                 1
+SEIPIVerPhaseDenMinus1FullResolution:           1
\ No newline at end of file
diff --git a/cfg/sei_vui/phase_indication_rpr1.5.cfg b/cfg/sei_vui/phase_indication_rpr1.5.cfg
new file mode 100644
index 000000000..c1414ec14
--- /dev/null
+++ b/cfg/sei_vui/phase_indication_rpr1.5.cfg
@@ -0,0 +1,10 @@
+SEIPhaseIndicationFullResolution:               1
+SEIPIHorPhaseNumFullResolution:                 1
+SEIPIHorPhaseDenMinus1FullResolution:           1
+SEIPIVerPhaseNumFullResolution:                 1
+SEIPIVerPhaseDenMinus1FullResolution:           1
+SEIPhaseIndicationReducedResolution:            1
+SEIPIHorPhaseNumReducedResolution:              1
+SEIPIHorPhaseDenMinus1ReducedResolution:        2
+SEIPIVerPhaseNumReducedResolution:              1
+SEIPIVerPhaseDenMinus1ReducedResolution:        2
\ No newline at end of file
diff --git a/cfg/sei_vui/phase_indication_rpr2.0.cfg b/cfg/sei_vui/phase_indication_rpr2.0.cfg
new file mode 100644
index 000000000..a23443e28
--- /dev/null
+++ b/cfg/sei_vui/phase_indication_rpr2.0.cfg
@@ -0,0 +1,10 @@
+SEIPhaseIndicationFullResolution:               1
+SEIPIHorPhaseNumFullResolution:                 1
+SEIPIHorPhaseDenMinus1FullResolution:           1
+SEIPIVerPhaseNumFullResolution:                 1
+SEIPIVerPhaseDenMinus1FullResolution:           1
+SEIPhaseIndicationReducedResolution:            1
+SEIPIHorPhaseNumReducedResolution:              1
+SEIPIHorPhaseDenMinus1ReducedResolution:        3
+SEIPIVerPhaseNumReducedResolution:              1
+SEIPIVerPhaseDenMinus1ReducedResolution:        3
\ No newline at end of file
diff --git a/doc/software-manual.tex b/doc/software-manual.tex
index 9501d86cd..003198251 100644
--- a/doc/software-manual.tex
+++ b/doc/software-manual.tex
@@ -3733,6 +3733,7 @@ The table below lists the SEI messages defined for Version 1 and Range-Extension
   209 & Shutter Interval Information             & Table \ref{tab:sei-sii} \\
   210 & Neural network post-filter characteristics & Table \ref{tab:sei-nn-post-filter-characteristics} \\
   211 & Neural netowrk post-filter activation & Table \ref{tab:sei-nn-post-filter-activation} \\
+  212 & Phase indication                         & Table \ref{tab:sei-phase-indication} \\
 \end{SEIListTable}
 %%
 %% SEI messages
@@ -5576,6 +5577,49 @@ Specifies sii_num_units_in_shutter_interval for single entry.If multiple entries
   \\
 \end{OptionTableNoShorthand}
 
+\begin{OptionTableNoShorthand}{Phase indication}{tab:sei-phase-indication}
+\Option{SEIPhaseIndicationFullResolution} &
+\Default{false} &
+Control generation of Phase Indication SEI messages for full resolution pictures.
+\\
+\Option{SEIPIHorPhaseNumFullResolution} &
+\Default{0} &
+Specifies the Horizontal Phase Numerator of Phase Indication SEI messages for full resolution pictures.
+\\
+\Option{SEIPIHorPhaseDenMinus1FullResolution} &
+\Default{0} &
+Specifies the Horizontal Phase Denominator minus 1 of Phase Indication SEI messages for full resolution pictures.
+\\
+\Option{SEIPIVerPhaseNumFullResolution} &
+\Default{0} &
+Specifies the Vertical Phase Numerator of Phase Indication SEI messages for full resolution pictures.
+\\
+\Option{SEIPIVerPhaseDenMinus1FullResolution} &
+\Default{0} &
+Specifies the Vertical Phase Denominator minus 1 of Phase Indication SEI messages for full resolution pictures.
+\\
+\Option{SEIPhaseIndicationReducedResolution} &
+\Default{false} &
+Control generation of Phase Indication SEI messages for reduced resolution pictures.
+\\
+\Option{SEIPIHorPhaseNumReducedResolution} &
+\Default{0} &
+Specifies the Horizontal Phase Numerator of Phase Indication SEI messages for reduced resolution pictures.
+\\
+\Option{SEIPIHorPhaseDenMinus1ReducedResolution} &
+\Default{0} &
+Specifies the Horizontal Phase Denominator minus 1 of Phase Indication SEI messages for reduced resolution pictures.
+\\
+\Option{SEIPIVerPhaseNumReducedResolution} &
+\Default{0} &
+Specifies the Vertical Phase Numerator of Phase Indication SEI messages for reduced resolution pictures.
+\\
+\Option{SEIPIVerPhaseDenMinus1ReducedResolution} &
+\Default{0} &
+Specifies the Vertical Phase Denominator minus 1 of Phase Indication SEI messages for reduced resolution pictures.
+\\
+\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 47e9fed22..6e7431219 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -974,6 +974,18 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setSariAspectRatioIdc                                (m_sariAspectRatioIdc);
   m_cEncLib.setSariSarWidth                                      (m_sariSarWidth);
   m_cEncLib.setSariSarHeight                                     (m_sariSarHeight);
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+  m_cEncLib.setPhaseIndicationSEIEnabledFullResolution           (m_phaseIndicationSEIEnabledFullResolution);
+  m_cEncLib.setHorPhaseNumFullResolution                         (m_piHorPhaseNumFullResolution);
+  m_cEncLib.setHorPhaseDenMinus1FullResolution                   (m_piHorPhaseDenMinus1FullResolution);
+  m_cEncLib.setVerPhaseNumFullResolution                         (m_piVerPhaseNumFullResolution);
+  m_cEncLib.setVerPhaseDenMinus1FullResolution                   (m_piVerPhaseDenMinus1FullResolution);
+  m_cEncLib.setPhaseIndicationSEIEnabledReducedResolution        (m_phaseIndicationSEIEnabledReducedResolution);
+  m_cEncLib.setHorPhaseNumReducedResolution                      (m_piHorPhaseNumReducedResolution);
+  m_cEncLib.setHorPhaseDenMinus1ReducedResolution                (m_piHorPhaseDenMinus1ReducedResolution);
+  m_cEncLib.setVerPhaseNumReducedResolution                      (m_piVerPhaseNumReducedResolution);
+  m_cEncLib.setVerPhaseDenMinus1ReducedResolution                (m_piVerPhaseDenMinus1ReducedResolution);
+#endif
   m_cEncLib.setMCTSEncConstraint                                 ( m_MCTSEncConstraint);
   m_cEncLib.setMasteringDisplaySEI                               ( m_masteringDisplay );
 #if U0033_ALTERNATIVE_TRANSFER_CHARACTERISTICS_SEI
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index 3d4be3f39..13c6213f4 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -1420,6 +1420,18 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ("SEISARIAspectRatioIdc",                           m_sariAspectRatioIdc,                     0, "Specifies the Sample Aspect Ratio IDC of Sample Aspect Ratio Information SEI messages")
   ("SEISARISarWidth",                                 m_sariSarWidth,                           0, "Specifies the Sample Aspect Ratio Width of Sample Aspect Ratio Information SEI messages, if extended SAR is chosen.")
   ("SEISARISarHeight",                                m_sariSarHeight,                          0, "Specifies the Sample Aspect Ratio Height of Sample Aspect Ratio Information SEI messages, if extended SAR is chosen.")
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+  ("SEIPhaseIndicationFullResolution",                m_phaseIndicationSEIEnabledFullResolution,          false, "Control generation of Phase Indication SEI messages for full resolution pictures.")
+  ("SEIPIHorPhaseNumFullResolution",                  m_piHorPhaseNumFullResolution,                      0, "Specifies the Horizontal Phase Numerator of Phase Indication SEI messages for full resolution pictures.")
+  ("SEIPIHorPhaseDenMinus1FullResolution",            m_piHorPhaseDenMinus1FullResolution,                0, "Specifies the Horizontal Phase Denominator minus 1 of Phase Indication SEI messages for full resolution pictures.")
+  ("SEIPIVerPhaseNumFullResolution",                  m_piVerPhaseNumFullResolution,                      0, "Specifies the Vertical Phase Numerator of Phase Indication SEI messages for full resolution pictures.")
+  ("SEIPIVerPhaseDenMinus1FullResolution",            m_piVerPhaseDenMinus1FullResolution,                0, "Specifies the Vertical Phase Denominator minus 1 of Phase Indication SEI messages for full resolution pictures.")
+  ("SEIPhaseIndicationReducedResolution",             m_phaseIndicationSEIEnabledReducedResolution,       false, "Control generation of Phase Indication SEI messages for reduced resolution pictures.")
+  ("SEIPIHorPhaseNumReducedResolution",               m_piHorPhaseNumReducedResolution,                   0, "Specifies the Horizontal Phase Numerator of Phase Indication SEI messages for reduced resolution pictures.")
+  ("SEIPIHorPhaseDenMinus1ReducedResolution",         m_piHorPhaseDenMinus1ReducedResolution,             0, "Specifies the Horizontal Phase Denominator minus 1 of Phase Indication SEI messages for reduced resolution pictures.")
+  ("SEIPIVerPhaseNumReducedResolution",               m_piVerPhaseNumReducedResolution,                   0, "Specifies the Vertical Phase Numerator of Phase Indication SEI messages for reduced resolution pictures.")
+  ("SEIPIVerPhaseDenMinus1ReducedResolution",         m_piVerPhaseDenMinus1ReducedResolution,             0, "Specifies the Vertical Phase Denominator minus 1 of Phase Indication SEI messages for reduced resolution pictures.")
+#endif
   ("MCTSEncConstraint",                               m_MCTSEncConstraint,                               false, "For MCTS, constrain motion vectors at tile boundaries")
   ("SEIShutterIntervalEnabled",                       m_siiSEIEnabled,                          false, "Controls if shutter interval information SEI message is enabled")
   ("SEISiiTimeScale",                                 m_siiSEITimeScale,                        27000000u, "Specifies sii_time_scale")
@@ -4664,6 +4676,31 @@ bool EncAppCfg::xCheckParameter()
     xConfirmPara(m_nnPostFilterSEIActivationId > (1 << 20) - 1, "SEINNPostFilterActivationId must be in the range of 0 to 2^20-1");
   }
 
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+  if (m_phaseIndicationSEIEnabledFullResolution)
+  {
+    xConfirmPara(m_piHorPhaseNumFullResolution < 0, "m_piHorPhaseNumFullResolution must be in the range of 0 to 511, inclusive");
+    xConfirmPara(m_piHorPhaseDenMinus1FullResolution < 0, "m_piHorPhaseDenMinus1FullResolution must be in the range of 0 to 511, inclusive");
+    xConfirmPara(m_piVerPhaseNumFullResolution < 0, "m_piVerPhaseNumFullResolution must be in the range of 0 to 511, inclusive");
+    xConfirmPara(m_piVerPhaseDenMinus1FullResolution < 0, "m_piVerPhaseDenMinus1FullResolution must be in the range of 0 to 511, inclusive");
+    xConfirmPara(m_piHorPhaseDenMinus1FullResolution > 511, "m_piHorPhaseDenMinus1FullResolution must be in the range of 0 to 511, inclusive");
+    xConfirmPara(m_piHorPhaseNumFullResolution > m_piHorPhaseDenMinus1FullResolution + 1, "m_piHorPhaseNumFullResolution must be in the range of 0 to m_piHorPhaseDenMinus1FullResolution + 1, inclusive");
+    xConfirmPara(m_piVerPhaseDenMinus1FullResolution > 511, "m_piVerPhaseDenMinus1FullResolution must be in the range of 0 to 511, inclusive");
+    xConfirmPara(m_piVerPhaseNumFullResolution > m_piVerPhaseDenMinus1FullResolution + 1, "m_piVerPhaseNumFullResolution must be in the range of 0 to m_piVerPhaseDenMinus1FullResolution + 1, inclusive");
+  }
+  if (m_phaseIndicationSEIEnabledReducedResolution)
+  {
+    xConfirmPara(m_piHorPhaseNumReducedResolution < 0, "m_piHorPhaseNumReducedResolution must be in the range of 0 to 511, inclusive");
+    xConfirmPara(m_piHorPhaseDenMinus1ReducedResolution < 0, "m_piHorPhaseDenMinus1ReducedResolution must be in the range of 0 to 511, inclusive");
+    xConfirmPara(m_piVerPhaseNumReducedResolution < 0, "m_piVerPhaseNumReducedResolution must be in the range of 0 to 511, inclusive");
+    xConfirmPara(m_piVerPhaseDenMinus1ReducedResolution < 0, "m_piVerPhaseDenMinus1ReducedResolution must be in the range of 0 to 511, inclusive");
+    xConfirmPara(m_piHorPhaseDenMinus1ReducedResolution > 511, "m_piHorPhaseDenMinus1ReducedResolution must be in the range of 0 to 511, inclusive");
+    xConfirmPara(m_piHorPhaseNumReducedResolution > m_piHorPhaseDenMinus1ReducedResolution + 1, "m_piHorPhaseNumReducedResolution must be in the range of 0 to m_piHorPhaseDenMinus1ReducedResolution + 1, inclusive");
+    xConfirmPara(m_piVerPhaseDenMinus1ReducedResolution > 511, "m_piVerPhaseDenMinus1ReducedResolution must be in the range of 0 to 511, inclusive");
+    xConfirmPara(m_piVerPhaseNumReducedResolution > m_piVerPhaseDenMinus1ReducedResolution + 1, "m_piVerPhaseNumReducedResolution must be in the range of 0 to m_piVerPhaseDenMinus1ReducedResolution + 1, inclusive");
+  }
+#endif
+
   xConfirmPara(m_log2ParallelMergeLevel < 2, "Log2ParallelMergeLevel should be larger than or equal to 2");
   xConfirmPara(m_log2ParallelMergeLevel > m_uiCTUSize, "Log2ParallelMergeLevel should be less than or equal to CTU size");
 #if U0033_ALTERNATIVE_TRANSFER_CHARACTERISTICS_SEI
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index 5cd8bdb2b..142c21994 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -779,6 +779,19 @@ protected:
   int                   m_sariSarWidth;
   int                   m_sariSarHeight;
 
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+  bool                  m_phaseIndicationSEIEnabledFullResolution;
+  int                   m_piHorPhaseNumFullResolution;
+  int                   m_piHorPhaseDenMinus1FullResolution;
+  int                   m_piVerPhaseNumFullResolution;
+  int                   m_piVerPhaseDenMinus1FullResolution;
+  bool                  m_phaseIndicationSEIEnabledReducedResolution;
+  int                   m_piHorPhaseNumReducedResolution;
+  int                   m_piHorPhaseDenMinus1ReducedResolution;
+  int                   m_piVerPhaseNumReducedResolution;
+  int                   m_piVerPhaseDenMinus1ReducedResolution;
+#endif
+
   bool      m_MCTSEncConstraint;
 
   // weighted prediction
diff --git a/source/Lib/CommonLib/SEI.cpp b/source/Lib/CommonLib/SEI.cpp
index f7e38c829..dbc60dd81 100644
--- a/source/Lib/CommonLib/SEI.cpp
+++ b/source/Lib/CommonLib/SEI.cpp
@@ -480,6 +480,9 @@ const char *SEI::getSEIMessageString(SEI::PayloadType payloadType)
     case SEI::SHUTTER_INTERVAL_INFO:                return "Shutter interval information";
     case SEI::NEURAL_NETWORK_POST_FILTER_CHARACTERISTICS: return "Neural network post-filter characteristics";
     case SEI::NEURAL_NETWORK_POST_FILTER_ACTIVATION:      return "Neural network post-filter activation";
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+    case SEI::PHASE_INDICATION:                     return "Phase Indication";
+#endif
     default:                                        return "Unknown";
   }
 }
diff --git a/source/Lib/CommonLib/SEI.h b/source/Lib/CommonLib/SEI.h
index 75b711637..2e3ad7225 100644
--- a/source/Lib/CommonLib/SEI.h
+++ b/source/Lib/CommonLib/SEI.h
@@ -94,6 +94,9 @@ public:
     SHUTTER_INTERVAL_INFO                = 209,
     NEURAL_NETWORK_POST_FILTER_CHARACTERISTICS = 210,
     NEURAL_NETWORK_POST_FILTER_ACTIVATION      = 211,
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+    PHASE_INDICATION                     = 212,
+#endif
   };
 
   SEI() {}
@@ -436,6 +439,20 @@ public:
   int                   m_sariSarHeight;
 };
 
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+class SEIPhaseIndication : public SEI
+{
+public:
+  PayloadType payloadType() const { return PHASE_INDICATION; }
+  SEIPhaseIndication() {}
+  virtual ~SEIPhaseIndication() {}
+  int                   m_horPhaseNum;
+  int                   m_horPhaseDenMinus1;
+  int                   m_verPhaseNum;
+  int                   m_verPhaseDenMinus1;
+};
+#endif
+
 static constexpr uint32_t ISO_IEC_11578_LEN=16;
 
 class SEIuserDataUnregistered : public SEI
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index f391d1276..ddedfe523 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -57,6 +57,7 @@
 #define JVET_AA0056_GATING_FILTER_CHARACTERISTICS         1 // JVET-AA0056 AHG9: on syntax gating in the neural-network post-filter characteristics SEI message
 #define JVET_AA0100_SEPERATE_COLOR_CHARACTERISTICS        1 // JVET-AA0100 AHG9: On auxiliary input and separate colour description in the neural-network post-filter characteristics SEI message
 #define JVET_AA0067_NNPFC_SEI_FIX                         1 // JVET-AA0067 AHG9: Some specification improvements for neural-network post-filter characteristics SEI message	
+#define JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE          1 //  Software support of Phase Indication SEI message
 
 //########### place macros to be be kept below this line ###############
 #define JVET_X0143_ALF_APS_ID_OFFSET                      0 // A value between 0 to 7 inclusive. This macro should be kept, or to be defined as a configuration parameter if possible.
diff --git a/source/Lib/DecoderLib/SEIread.cpp b/source/Lib/DecoderLib/SEIread.cpp
index da8ad658c..248436a83 100644
--- a/source/Lib/DecoderLib/SEIread.cpp
+++ b/source/Lib/DecoderLib/SEIread.cpp
@@ -414,6 +414,12 @@ void SEIReader::xReadSEImessage(SEIMessages& seis, const NalUnitType nalUnitType
       sei = new SEINeuralNetworkPostFilterActivation;
       xParseSEINNPostFilterActivation((SEINeuralNetworkPostFilterActivation&)*sei, payloadSize, pDecodedMessageOutputStream);
       break;
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+    case SEI::PHASE_INDICATION:
+      sei = new SEIPhaseIndication;
+      xParseSEIPhaseIndication((SEIPhaseIndication&)*sei, payloadSize, pDecodedMessageOutputStream);
+      break;
+#endif
     default:
       for (uint32_t i = 0; i < payloadSize; i++)
       {
@@ -2621,6 +2627,26 @@ void SEIReader::xParseSEINNPostFilterActivation(SEINeuralNetworkPostFilterActiva
   sei.m_id =val;
 }
 
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+void SEIReader::xParseSEIPhaseIndication(SEIPhaseIndication& sei, uint32_t payloadSize, std::ostream* pDecodedMessageOutputStream)
+{
+  output_sei_message_header(sei, pDecodedMessageOutputStream, payloadSize);
+  uint32_t val;
+
+  sei_read_code(pDecodedMessageOutputStream, 8, val, "hor_phase_num");
+  sei.m_horPhaseNum = val;
+  sei_read_code(pDecodedMessageOutputStream, 8, val, "hor_phase_den_minus1");
+  sei.m_horPhaseDenMinus1 = val;
+  sei_read_code(pDecodedMessageOutputStream, 8, val, "ver_phase_num");
+  sei.m_verPhaseNum = val;
+  sei_read_code(pDecodedMessageOutputStream, 8, val, "ver_phase_den_minus1");
+  sei.m_verPhaseDenMinus1 = val;
+
+  CHECK(sei.m_horPhaseNum > sei.m_horPhaseDenMinus1 + 1, "The value of hor_phase_num shall be in the range of 0 to hor_phase_den_minus1 + 1, inclusive");
+  CHECK(sei.m_verPhaseNum > sei.m_verPhaseDenMinus1 + 1, "The value of ver_phase_num shall be in the range of 0 to ver_phase_den_minus1 + 1, inclusive");
+}
+#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 3eb2df80a..d8553e03b 100644
--- a/source/Lib/DecoderLib/SEIread.h
+++ b/source/Lib/DecoderLib/SEIread.h
@@ -105,6 +105,9 @@ protected:
   void xParseSEIShutterInterval(SEIShutterIntervalInfo& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream);
   void xParseSEINNPostFilterCharacteristics(SEINeuralNetworkPostFilterCharacteristics& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream);
   void xParseSEINNPostFilterActivation(SEINeuralNetworkPostFilterActivation& sei, uint32_t payloadSize, std::ostream *pDecodedMessageOutputStream);
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+  void xParseSEIPhaseIndication(SEIPhaseIndication& 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 0fc08479d..3898ea7be 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -650,6 +650,18 @@ protected:
   int                   m_sariAspectRatioIdc;
   int                   m_sariSarWidth;
   int                   m_sariSarHeight;
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+  bool                  m_phaseIndicationSEIEnabledFullResolution;
+  int                   m_horPhaseNumFullResolution;
+  int                   m_horPhaseDenMinus1FullResolution;
+  int                   m_verPhaseNumFullResolution;
+  int                   m_verPhaseDenMinus1FullResolution;
+  bool                  m_phaseIndicationSEIEnabledReducedResolution;
+  int                   m_horPhaseNumReducedResolution;
+  int                   m_horPhaseDenMinus1ReducedResolution;
+  int                   m_verPhaseNumReducedResolution;
+  int                   m_verPhaseDenMinus1ReducedResolution;
+#endif
   bool      m_MCTSEncConstraint;
   SEIMasteringDisplay m_masteringDisplay;
 #if U0033_ALTERNATIVE_TRANSFER_CHARACTERISTICS_SEI
@@ -2035,6 +2047,28 @@ public:
   void     setSariSarWidth(const int val)                                                                   { m_sariSarWidth = val; }
   int      getSariSarHeight() const                                                                         { return m_sariSarHeight; }
   void     setSariSarHeight(const int val)                                                                  { m_sariSarHeight = val; }
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+  bool     getPhaseIndicationSEIEnabledFullResolution() const                                               { return m_phaseIndicationSEIEnabledFullResolution; }
+  void     setPhaseIndicationSEIEnabledFullResolution(const bool val)                                       { m_phaseIndicationSEIEnabledFullResolution = val; }
+  int      getHorPhaseNumFullResolution() const                                                             { return m_horPhaseNumFullResolution; }
+  void     setHorPhaseNumFullResolution(const int val)                                                      { m_horPhaseNumFullResolution = val; }
+  int      getHorPhaseDenMinus1FullResolution() const                                                       { return m_horPhaseDenMinus1FullResolution; }
+  void     setHorPhaseDenMinus1FullResolution(const int val)                                                { m_horPhaseDenMinus1FullResolution = val; }
+  int      getVerPhaseNumFullResolution() const                                                             { return m_verPhaseNumFullResolution; }
+  void     setVerPhaseNumFullResolution(const int   val)                                                    { m_verPhaseNumFullResolution = val; }
+  int      getVerPhaseDenMinus1FullResolution() const                                                       { return m_verPhaseDenMinus1FullResolution; }
+  void     setVerPhaseDenMinus1FullResolution(const int val)                                                { m_verPhaseDenMinus1FullResolution = val; }
+  bool     getPhaseIndicationSEIEnabledReducedResolution() const                                            { return m_phaseIndicationSEIEnabledReducedResolution; }
+  void     setPhaseIndicationSEIEnabledReducedResolution(const bool val)                                    { m_phaseIndicationSEIEnabledReducedResolution = val; }
+  int      getHorPhaseNumReducedResolution() const                                                          { return m_horPhaseNumReducedResolution; }
+  void     setHorPhaseNumReducedResolution(const int val)                                                   { m_horPhaseNumReducedResolution = val; }
+  int      getHorPhaseDenMinus1ReducedResolution() const                                                    { return m_horPhaseDenMinus1ReducedResolution; }
+  void     setHorPhaseDenMinus1ReducedResolution(const int val)                                             { m_horPhaseDenMinus1ReducedResolution = val; }
+  int      getVerPhaseNumReducedResolution() const                                                          { return m_verPhaseNumReducedResolution; }
+  void     setVerPhaseNumReducedResolution(const int   val)                                                 { m_verPhaseNumReducedResolution = val; }
+  int      getVerPhaseDenMinus1ReducedResolution() const                                                    { return m_verPhaseDenMinus1ReducedResolution; }
+  void     setVerPhaseDenMinus1ReducedResolution(const int val)                                             { m_verPhaseDenMinus1ReducedResolution = val; }
+#endif
   void  setMCTSEncConstraint(bool b)                                 { m_MCTSEncConstraint = b; }
   bool  getMCTSEncConstraint()                                       { return m_MCTSEncConstraint; }
   void  setMasteringDisplaySEI(const SEIMasteringDisplay &src)       { m_masteringDisplay = src; }
diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp
index 1a1970719..4a893aff0 100644
--- a/source/Lib/EncoderLib/EncGOP.cpp
+++ b/source/Lib/EncoderLib/EncGOP.cpp
@@ -409,7 +409,11 @@ int EncGOP::xWriteAPS( AccessUnit &accessUnit, APS *aps, const int layerId, cons
   return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
 }
 
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+int EncGOP::xWriteParameterSets(AccessUnit &accessUnit, Slice *slice, const bool bSeqFirst, const int layerIdx, bool newPPS)
+#else
 int EncGOP::xWriteParameterSets(AccessUnit &accessUnit, Slice *slice, const bool bSeqFirst, const int layerIdx)
+#endif
 {
   int actualTotalBits = 0;
 
@@ -437,7 +441,11 @@ int EncGOP::xWriteParameterSets(AccessUnit &accessUnit, Slice *slice, const bool
     }
   }
 
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+  if( newPPS ) // Note this assumes that all changes to the PPS are made at the EncLib level prior to picture creation (EncLib::xGetNewPicBuffer).
+#else
   if( m_pcEncLib->PPSNeedsWriting( slice->getPPS()->getPPSId() ) ) // Note this assumes that all changes to the PPS are made at the EncLib level prior to picture creation (EncLib::xGetNewPicBuffer).
+#endif
   {
     actualTotalBits += xWritePPS( accessUnit, slice->getPPS(), m_pcEncLib->getLayerId() );
   }
@@ -957,6 +965,24 @@ void EncGOP::xCreatePerPictureSEIMessages (int picInGOP, SEIMessages& seiMessage
   }
 }
 
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+void EncGOP::xCreatePhaseIndicationSEIMessages(SEIMessages& seiMessages, Slice* slice, int ppsId)
+{
+  if (m_pcCfg->getPhaseIndicationSEIEnabledFullResolution() && ppsId == 0)
+  {
+    SEIPhaseIndication* seiPhaseIndication = new SEIPhaseIndication;
+    m_seiEncoder.initSEIPhaseIndication(seiPhaseIndication, ppsId);
+    seiMessages.push_back(seiPhaseIndication);
+  }
+  else if (m_pcCfg->getPhaseIndicationSEIEnabledReducedResolution() && ppsId == ENC_PPS_ID_RPR)
+  {
+    SEIPhaseIndication* seiPhaseIndication = new SEIPhaseIndication;
+    m_seiEncoder.initSEIPhaseIndication(seiPhaseIndication, ppsId);
+    seiMessages.push_back(seiPhaseIndication);
+  }
+}
+#endif
+
 void EncGOP::xCreateScalableNestingSEI(SEIMessages& seiMessages, SEIMessages& nestedSeiMessages, const std::vector<int> &targetOLSs, const std::vector<int> &targetLayers, const std::vector<uint16_t>& subpicIDs, uint16_t maxSubpicIdInPic)
 {
   SEIMessages tmpMessages;
@@ -3708,7 +3734,13 @@ void EncGOP::compressGOP(int pocLast, int numPicRcvd, PicList &rcListPic, std::l
       }
 
       // it is assumed that layerIdx equal to 0 is always present
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+      bool newPPS = m_pcEncLib->PPSNeedsWriting(pcSlice->getPPS()->getPPSId());
+      actualTotalBits += xWriteParameterSets(accessUnit, pcSlice, writePS, layerIdx, newPPS);
+#else
       actualTotalBits += xWriteParameterSets(accessUnit, pcSlice, writePS, layerIdx);
+#endif
+
       if (writePS)
       {
         // create prefix SEI messages at the beginning of the sequence
@@ -3834,6 +3866,12 @@ void EncGOP::compressGOP(int pocLast, int numPicRcvd, PicList &rcListPic, std::l
       // create prefix SEI associated with a picture
       xCreatePerPictureSEIMessages(gopId, leadingSeiMessages, nestedSeiMessages, pcSlice);
 
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+      if (newPPS)
+      {
+        xCreatePhaseIndicationSEIMessages(leadingSeiMessages, pcSlice, pcSlice->getPPS()->getPPSId());
+      }
+#endif
       // pcSlice is currently slice 0.
       std::size_t binCountsInNalUnits   = 0; // For implementation of cabac_zero_word stuffing (section 7.4.3.10)
       std::size_t numBytesInVclNalUnits = 0; // For implementation of cabac_zero_word stuffing (section 7.4.3.10)
diff --git a/source/Lib/EncoderLib/EncGOP.h b/source/Lib/EncoderLib/EncGOP.h
index c16f5a0f8..c999c563e 100644
--- a/source/Lib/EncoderLib/EncGOP.h
+++ b/source/Lib/EncoderLib/EncGOP.h
@@ -326,6 +326,9 @@ protected:
   void xCreateIRAPLeadingSEIMessages (SEIMessages& seiMessages, const SPS *sps, const PPS *pps);
   void xCreatePerPictureSEIMessages (int picInGOP, SEIMessages& seiMessages, SEIMessages& nestedSeiMessages, Slice *slice);
   void xCreateFrameFieldInfoSEI (SEIMessages& seiMessages, Slice *slice, bool isField);
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+  void xCreatePhaseIndicationSEIMessages (SEIMessages& seiMessages, Slice* slice, int ppsId);
+#endif
   void xCreatePictureTimingSEI  (int IRAPGOPid, SEIMessages& seiMessages, SEIMessages& nestedSeiMessages, SEIMessages& duInfoSeiMessages, Slice *slice, bool isField, std::deque<DUData> &duData);
   void xUpdateDuData(AccessUnit &testAU, std::deque<DUData> &duData);
   void xUpdateTimingSEI(SEIPictureTiming *pictureTimingSEI, std::deque<DUData> &duData, const SPS *sps);
@@ -345,7 +348,11 @@ protected:
   int xWriteSPS( AccessUnit &accessUnit, const SPS *sps, const int layerId = 0 );
   int xWritePPS( AccessUnit &accessUnit, const PPS *pps, const int layerId = 0 );
   int xWriteAPS( AccessUnit &accessUnit, APS *aps, const int layerId, const bool isPrefixNUT );
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+  int xWriteParameterSets(AccessUnit &accessUnit, Slice *slice, const bool bSeqFirst, const int layerIdx, bool newPPS);
+#else
   int xWriteParameterSets(AccessUnit &accessUnit, Slice *slice, const bool bSeqFirst, const int layerIdx);
+#endif
   int xWritePicHeader( AccessUnit &accessUnit, PicHeader *picHeader );
 
   void applyDeblockingFilterMetric( Picture* pcPic, uint32_t uiNumSlices );
diff --git a/source/Lib/EncoderLib/SEIEncoder.cpp b/source/Lib/EncoderLib/SEIEncoder.cpp
index 05302155f..355755e97 100644
--- a/source/Lib/EncoderLib/SEIEncoder.cpp
+++ b/source/Lib/EncoderLib/SEIEncoder.cpp
@@ -394,6 +394,29 @@ void SEIEncoder::initSEISampleAspectRatioInfo(SEISampleAspectRatioInfo* seiSampl
   }
 }
 
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+void SEIEncoder::initSEIPhaseIndication(SEIPhaseIndication* seiPhaseIndication, int ppsId)
+{
+  CHECK(!(m_isInitialized), "seiPhaseIndication already initialized");
+  CHECK(!(seiPhaseIndication != nullptr), "Need a seiPhaseIndication for initialization (got nullptr)");
+
+  if (ppsId == 0)
+  {
+    seiPhaseIndication->m_horPhaseNum = m_pcCfg->getHorPhaseNumFullResolution();
+    seiPhaseIndication->m_horPhaseDenMinus1 = m_pcCfg->getHorPhaseDenMinus1FullResolution();
+    seiPhaseIndication->m_verPhaseNum = m_pcCfg->getVerPhaseNumFullResolution();
+    seiPhaseIndication->m_verPhaseDenMinus1 = m_pcCfg->getVerPhaseDenMinus1FullResolution();
+  }
+  else if (ppsId == ENC_PPS_ID_RPR)
+  {
+    seiPhaseIndication->m_horPhaseNum = m_pcCfg->getHorPhaseNumReducedResolution();
+    seiPhaseIndication->m_horPhaseDenMinus1 = m_pcCfg->getHorPhaseDenMinus1ReducedResolution();
+    seiPhaseIndication->m_verPhaseNum = m_pcCfg->getVerPhaseNumReducedResolution();
+    seiPhaseIndication->m_verPhaseDenMinus1 = m_pcCfg->getVerPhaseDenMinus1ReducedResolution();
+  }
+}
+#endif
+
 //! initialize scalable nesting SEI message.
 //! Note: The SEI message structures input into this function will become part of the scalable nesting SEI and will be
 //!       automatically freed, when the nesting SEI is disposed.
diff --git a/source/Lib/EncoderLib/SEIEncoder.h b/source/Lib/EncoderLib/SEIEncoder.h
index 0c1d0809c..0a99a23a7 100644
--- a/source/Lib/EncoderLib/SEIEncoder.h
+++ b/source/Lib/EncoderLib/SEIEncoder.h
@@ -77,6 +77,9 @@ public:
   void initSEIGcmp(SEIGeneralizedCubemapProjection *sei);
   void initSEISubpictureLevelInfo(SEISubpicureLevelInfo *sei, const SPS *sps);
   void initSEISampleAspectRatioInfo(SEISampleAspectRatioInfo *sei);
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+  void initSEIPhaseIndication(SEIPhaseIndication* sei, int ppsId);
+#endif
   void initSEIFilmGrainCharacteristics(SEIFilmGrainCharacteristics *sei);
   void initSEIMasteringDisplayColourVolume(SEIMasteringDisplayColourVolume *sei);
   void initSEIContentLightLevel(SEIContentLightLevelInfo *sei);
diff --git a/source/Lib/EncoderLib/SEIwrite.cpp b/source/Lib/EncoderLib/SEIwrite.cpp
index d2d300ffd..75206f9cd 100644
--- a/source/Lib/EncoderLib/SEIwrite.cpp
+++ b/source/Lib/EncoderLib/SEIwrite.cpp
@@ -151,6 +151,11 @@ void SEIWriter::xWriteSEIpayloadData(OutputBitstream &bs, const SEI& sei, HRD &h
   case SEI::SAMPLE_ASPECT_RATIO_INFO:
     xWriteSEISampleAspectRatioInfo(*static_cast<const SEISampleAspectRatioInfo*>(&sei));
     break;
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+  case SEI::PHASE_INDICATION:
+    xWriteSEIPhaseIndication(*static_cast<const SEIPhaseIndication*>(&sei));
+    break;
+#endif
   case SEI::ANNOTATED_REGIONS:
     xWriteSEIAnnotatedRegions(*static_cast<const SEIAnnotatedRegions*>(&sei));
     break;
@@ -1201,6 +1206,16 @@ void SEIWriter::xWriteSEISampleAspectRatioInfo(const SEISampleAspectRatioInfo &s
   }
 }
 
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+void SEIWriter::xWriteSEIPhaseIndication(const SEIPhaseIndication& sei)
+{
+  WRITE_CODE((uint32_t)sei.m_horPhaseNum, 8, "hor_phase_num");
+  WRITE_CODE((uint32_t)sei.m_horPhaseDenMinus1, 8, "hor_phase_den_minus1");
+  WRITE_CODE((uint32_t)sei.m_verPhaseNum, 8, "ver_phase_num");
+  WRITE_CODE((uint32_t)sei.m_verPhaseDenMinus1, 8, "ver_phase_den_minus1");
+}
+#endif
+
 void SEIWriter::xWriteSEIUserDataRegistered(const SEIUserDataRegistered &sei)
 {
   WRITE_CODE((sei.m_ituCountryCode>255) ? 0xff : sei.m_ituCountryCode, 8, "itu_t_t35_country_code");
diff --git a/source/Lib/EncoderLib/SEIwrite.h b/source/Lib/EncoderLib/SEIwrite.h
index 519a679a4..eae18f461 100644
--- a/source/Lib/EncoderLib/SEIwrite.h
+++ b/source/Lib/EncoderLib/SEIwrite.h
@@ -83,6 +83,9 @@ protected:
   void xWriteSEIDepthRepInfoElement               (double f);
   void xWriteSEISubpictureLevelInfo               (const SEISubpicureLevelInfo &sei);
   void xWriteSEISampleAspectRatioInfo             (const SEISampleAspectRatioInfo &sei);
+#if JVET_AA0110_PHASE_INDICATION_SEI_MESSAGE
+  void xWriteSEIPhaseIndication                   (const SEIPhaseIndication&sei);
+#endif
   void xWriteSEIConstrainedRaslIndication         (const SEIConstrainedRaslIndication &sei);
   void xWriteSEIUserDataRegistered(const SEIUserDataRegistered& sei);
   void xWriteSEIFilmGrainCharacteristics(const SEIFilmGrainCharacteristics& sei);
-- 
GitLab