diff --git a/cfg/sei_vui/constituent_rectangles.cfg b/cfg/sei_vui/constituent_rectangles.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..aade32e6f802ab635bd04f41487f5d32b16780f5
--- /dev/null
+++ b/cfg/sei_vui/constituent_rectangles.cfg
@@ -0,0 +1,25 @@
+
+SEICrEnabled                            : 1
+SEICrNumRectsMinus1                     : 3
+SEICrRectIdPresentFlag                  : 1
+SEICrRectIdLen                          : 2
+SEICrRectTypeEnabledFlag                : 1
+SEICrRectTypeDescriptionsEnabledFlag    : 1
+SEICrSubpicsPartitioningFlag            : 0
+SEICrRectSameSizeFlag                   : 0
+SEICrNumColsMinus1                      : 1
+SEICrNumRowsMinus1                      : 1
+SEICrLog2UnitSize                       : 0
+SEICrRectSizeLenMinus1                  : 10
+SEICrRectTypePresentFlag                : 1 1 1 1
+SEICrRectTypeIdc                        : 0 0 1 2
+SEICrSEIRectId                          : 0 1 2 3
+SEICrRectTypeDescriptionPresentFlag     : 1 1 1 1
+SEICrRectTopLeftInUnitsX                : 0 1920 0 1920
+SEICrRectTopLeftInUnitsY                : 0 0 1080 1080
+SEICrRectWidthInUnitsMinus1             : 1919 1919 1919 1919
+SEICrRectHeightInUnitsMinus1            : 1079 1079 539 539
+SEICrRectTypeDescription0               : Texture 1
+SEICrRectTypeDescription1               : Texture 2
+SEICrRectTypeDescription2               : Alpha 1
+SEICrRectTypeDescription3               : Depth 1
diff --git a/doc/software-manual.tex b/doc/software-manual.tex
index 3c2d6a3dd1c7da4f5917075aa2c1612e0404ff2d..1c78d2cb069b1241c642b424330c0ed97c4b4f28 100644
--- a/doc/software-manual.tex
+++ b/doc/software-manual.tex
@@ -3998,6 +3998,7 @@ The table below lists the SEI messages defined for Version 1 and Range-Extension
   TBD & EXIF metadata                            & Table \ref{tab:sei-exif}\\
   TBD & JFIF metadata                            & Table \ref{tab:sei-jfif}\\
   TBD & XMP metadata                             & Table \ref{tab:sei-xmp}\\
+  TBD & Constituent Rectangles                   & Table \ref{tab:sei-cr}\\
 \end{SEIListTable}
 %%
 %% SEI messages
@@ -6327,6 +6328,90 @@ An example file can be found in cfg/sei_vui/object_mask_infos/intra/mask_info_0.
   \\
 \end{OptionTableNoShorthand}
 
+\begin{OptionTableNoShorthand}{Constituent rectangles SEI message encoder parameters}{tab:sei-cr}
+  \Option{SEICrEnabled} &
+  \Default{false} &
+  Specifies whether constituent rectangles SEI is enabled.
+  \\
+  \Option{SEICrNumRectsMinus1} &
+  \Default{0} &
+  Specifies the number of constituent rectangles minus 1.
+  \\
+  \Option{SEICrRectIdPresentFlag} &
+  \Default{false} &
+  Specifies whether cr_rect_id[i] syntax element is present in the SEI message.
+  \\
+  \Option{SEICrRectIdLen} &
+  \Default{4} &
+  Specifies the length of the cr_rect_id[i] syntax element.
+  \\
+  \Option{SEICrRectTypeEnabledFlag} &
+  \Default{false} &
+  Specifies whether the cr_rect_type_present_flag[i] syntax element is present in the SEI message.
+  \\
+  \Option{SEICrRectTypeDescriptionsEnabledFlag} &
+  \Default{false} &
+  Specifies whether the cr_rect_type_description_present_flag[ i ] syntax element is present in the SEI message.
+  \\
+  \Option{SEICrSubpicsPartitioningFlag} &
+  \Default{false} &
+  Indicates whether the subpic partitioning parameters in the SPS are used to determine the of constituent rectangle sizes and positions.
+  \\
+  \Option{SEICrRectSameSizeFlag} &
+  \Default{false} &
+  Indicates whether all constituent rectangles have the same size and are arranged in a grid pattern.
+  \\
+  \Option{SEICrNumColsMinus1} &
+  \Default{0} &
+  Specify the number of columns of the constituent rectangle grid when SEICrRectSameSizeFlag is equal to 1.
+  \\
+  \Option{SEICrNumRowsMinus1} &
+  \Default{0} &
+  Specify the number of rows of the constituent rectangle grid when SEICrRectSameSizeFlag is equal to 1.
+  \\
+  \Option{SEICrLog2UnitSize} &
+  \Default{0} &
+  Specifies a unit size used in variable calculations for the constituent rectangle parameters.
+  \\
+  \Option{SEICrRectSizeLenMinus1} &
+  \Default{12} &
+  Specifies the length of syntax elements cr_rect_top_left_in_units_x[i], cr_rect_top_left_in_units_y[i], cr_rect_width_in_units_minus1[i], and cr_rect_height_in_units minus1[i].
+  \\
+  \Option{SEICrRectTypePresentFlag} &
+  \Default{} &
+  List of flags indicating the presence of cr_rect_type_idc[i] syntax elements in the SEI message.
+  \\
+  \Option{SEICrRectTypeIdc} &
+  \Default{} &
+  List of values indicating the constituent picture types.
+  \\
+  \Option{SEICrRectId} &
+  \Default{} &
+  List of unique IDs, one for each rectangle.
+  \\
+  \Option{SEICrRectTypeDescriptionPresentFlag} &
+  \Default{} &
+  List of flags indicating the presence of cr_rect_type_description[i] syntax elements in the SEI message.
+  \\
+  \Option{SEICrRectTopLeftInUnitsX} &
+  \Default{} &
+  List of horizontal positions of the rectangles in units.
+  \\
+  \Option{SEICrRectTopLeftInUnitsY} &
+  \Default{} &
+  List of vertical positions of the rectangles in units.
+  \\
+  \Option{SEICrRectWidthInUnitsMinus1} &
+  \Default{} &
+  List of widths of the rectangles in units.
+  \\
+  \Option{SEICrRectHeightInUnitsMinus1} &
+  \Default{} &
+  List of heights of the rectangles in units.
+  \\
+\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 5e517f4e141ce01b4cd3bf09a45f3a3e11832462..0a6327d1ce64bb0d63be86f9415e93b6dcabbff1 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -1422,6 +1422,38 @@ void EncApp::xInitLibCfg( int layerIdx )
   m_cEncLib.setPostFilterHintSEIChromaCoeffPresentFlag(m_postFilterHintSEIChromaCoeffPresentFlag);
   m_cEncLib.setPostFilterHintSEIValues(m_postFilterHintValues);
 
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+  m_cEncLib.setCrSEIEnabled(m_crSEIEnabled);
+  m_cEncLib.setCrSEINumRectsMinus1(m_crSEINumRectsMinus1);
+  m_cEncLib.setCrSEIRectIdPresentFlag(m_crSEIRectIdPresentFlag);
+  m_cEncLib.setCrSEIRectIdLen(m_crSEIRectIdLen);
+  m_cEncLib.setCrSEIRectTypeEnabledFlag(m_crSEIRectTypeEnabledFlag);
+  m_cEncLib.setCrSEIRectTypeDescriptionsEnabledFlag(m_crSEIRectTypeDescriptionsEnabledFlag);
+  m_cEncLib.setCrSEISubpicsPartitioningFlag(m_crSEISubpicsPartitioningFlag);
+  m_cEncLib.setCrSEIRectSameSizeFlag(m_crSEIRectSameSizeFlag);
+  m_cEncLib.setCrSEINumColsMinus1(m_crSEINumColsMinus1);
+  m_cEncLib.setCrSEINumRowsMinus1(m_crSEINumRowsMinus1);
+  m_cEncLib.setCrSEILog2UnitSize(m_crSEILog2UnitSize);
+  m_cEncLib.setCrSEIRectSizeLenMinus1(m_crSEIRectSizeLenMinus1);
+  m_cEncLib.setCrSEIRectTypePresentFlag(m_crSEIRectTypePresentFlag);
+  m_cEncLib.setCrSEIRectTypeIdc(m_crSEIRectTypeIdc);
+  m_cEncLib.setCrSEIRectId(m_crSEIRectId);
+  m_cEncLib.setCrSEISEIRectTypeDescriptionPresentFlag(m_crSEIRectTypeDescriptionPresentFlag);
+  m_cEncLib.setCrSEIRectTopLeftInUnitsX(m_crSEIRectTopLeftInUnitsX);
+  m_cEncLib.setCrSEIRectTopLeftInUnitsY(m_crSEIRectTopLeftInUnitsY);
+  m_cEncLib.setCrSEIRectWidthInUnitsMinus1(m_crSEIRectWidthInUnitsMinus1);
+  m_cEncLib.setCrSEIRectHeightInUnitsMinus1(m_crSEIRectHeightInUnitsMinus1);
+  if (m_crSEIEnabled)
+  {
+    std::vector<std::string> tmpDesc;
+    for (uint32_t i = 0; i <= m_crSEINumRectsMinus1; i++)
+    {
+      tmpDesc.push_back(m_crSEIRectTypeDescription[i]);
+    }
+    m_cEncLib.setCrSEIRectTypeDescription(tmpDesc);
+  }
+#endif
+
   m_cEncLib.setVuiParametersPresentFlag                          ( m_vuiParametersPresentFlag );
   m_cEncLib.setSamePicTimingInAllOLS                             (m_samePicTimingInAllOLS);
   m_cEncLib.setAspectRatioInfoPresentFlag                        ( m_aspectRatioInfoPresentFlag);
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index f745f901a2868a96fc746f2600e76a3f19e27f28..36fedf12bff3c2e425adafc842f7e1c75ba0b676 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -775,6 +775,16 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   SMultiValueInput<uint8_t>   cfg_xmpMetadataSEIDataValues (0, std::numeric_limits<uint8_t>::max(), 0, std::numeric_limits<uint32_t>::max());
   SMultiValueInput<uint8_t>   cfg_jfifMetadataSEIDataValues(0, std::numeric_limits<uint8_t>::max(), 0, std::numeric_limits<uint32_t>::max());
 #endif
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+  SMultiValueInput<bool>      cfg_crSEIRectTypePresentFlag(0, 1, 0, 4096);
+  SMultiValueInput<uint8_t>   cfg_crSEIRectTypeIdc(0, std::numeric_limits<uint8_t>::max(), 0, 4096);
+  SMultiValueInput<uint32_t>  cfg_crSEIRectId(0, 32767, 0, 4096);
+  SMultiValueInput<bool>      cfg_crSEIRectTypeDescriptionPresentFlag(0, 1, 0, 4096);
+  SMultiValueInput<uint32_t>  cfg_crSEIRectTopLeftInUnitsX(0, 65535, 0, 4096);
+  SMultiValueInput<uint32_t>  cfg_crSEIRectTopLeftInUnitsY(0, 65535, 0, 4096);
+  SMultiValueInput<uint32_t>  cfg_crSEIRectWidthInUnitsMinus1(0, 65535, 0, 4096);
+  SMultiValueInput<uint32_t>  cfg_crSEIRectHeightInUnitsMinus1(0, 65535, 0, 4096);
+#endif
 #if ENABLE_TRACING
   std::string sTracingRule;
   std::string sTracingFile;
@@ -1678,6 +1688,29 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   //SEI prefix indication
   ("SEISEIPrefixIndicationEnabled",                   m_SEIPrefixIndicationSEIEnabled,                   false, "Controls if SEI Prefix Indications SEI messages enabled")
 
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+  ("SEICrEnabled",                                    m_crSEIEnabled,                                    false, "Specifies whether constituent rectangles SEI is enabled")
+  ("SEICrNumRectsMinus1",                             m_crSEINumRectsMinus1,                                0u, "Specifies the number of constituent rectangles minus 1")
+  ("SEICrRectIdPresentFlag",                          m_crSEIRectIdPresentFlag,                          false, "Specifies whether cr_rect_id[i] syntax element is present in the SEI message")
+  ("SEICrRectIdLen",                                  m_crSEIRectIdLen,                                     4u, "Specifies the length of the cr_rect_id[i] syntax element")
+  ("SEICrRectTypeEnabledFlag",                        m_crSEIRectTypeEnabledFlag,                        false, "Specifies whether the cr_rect_type_present_flag[i] syntax element is present in the SEI message")
+  ("SEICrRectTypeDescriptionsEnabledFlag",            m_crSEIRectTypeDescriptionsEnabledFlag,            false, "Specifies whether the cr_rect_type_description_present_flag[ i ] syntax element is present in the SEI message")
+  ("SEICrSubpicsPartitioningFlag",                    m_crSEISubpicsPartitioningFlag,                    false, "Indicates whether the subpic partitioning parameters in the SPS are used to determine the of constituent rectangle sizes and positions")
+  ("SEICrRectSameSizeFlag",                           m_crSEIRectSameSizeFlag,                           false, "Indicates whether all constituent rectangles have the same size and are arranged in a grid pattern")
+  ("SEICrNumColsMinus1",                              m_crSEINumColsMinus1,                                 0u, "Specify the number of columns of the constituent rectangle grid when SEICrRectSameSizeFlag is equal to 1")
+  ("SEICrNumRowsMinus1",                              m_crSEINumRowsMinus1,                                 0u, "Specify the number of rows of the constituent rectangle grid when SEICrRectSameSizeFlag is equal to 1")
+  ("SEICrLog2UnitSize",                               m_crSEILog2UnitSize,                                  0u, "Specifies a unit size used in variable calculations for the constituent rectangle parameters")
+  ("SEICrRectSizeLenMinus1",                          m_crSEIRectSizeLenMinus1,                            12u, "Specifies the length of syntax elements cr_rect_top_left_in_units_x[i], cr_rect_top_left_in_units_y[i], cr_rect_width_in_units_minus1[i], and cr_rect_height_in_units minus1[i]")
+  ("SEICrRectTypePresentFlag",                        cfg_crSEIRectTypePresentFlag, cfg_crSEIRectTypePresentFlag, "List of flags indicating the presence of cr_rect_type_idc[i] syntax elements in the SEI message")
+  ("SEICrRectTypeIdc",                                cfg_crSEIRectTypeIdc,                 cfg_crSEIRectTypeIdc, "List of values indicating the constituent picture types")
+  ("SEICrRectId",                                     cfg_crSEIRectId,                           cfg_crSEIRectId, "List of unique IDs, one for each rectangle")
+  ("SEICrRectTypeDescriptionPresentFlag",             cfg_crSEIRectTypeDescriptionPresentFlag, cfg_crSEIRectTypeDescriptionPresentFlag, "List of flags indicating the presence of cr_rect_type_description[i] syntax elements in the SEI message")
+  ("SEICrRectTopLeftInUnitsX",                        cfg_crSEIRectTopLeftInUnitsX, cfg_crSEIRectTopLeftInUnitsX, "List of horizontal positions of the rectangles in units")
+  ("SEICrRectTopLeftInUnitsY",                        cfg_crSEIRectTopLeftInUnitsY, cfg_crSEIRectTopLeftInUnitsY, "List of vertical positions of the rectangles in units")
+  ("SEICrRectWidthInUnitsMinus1",                     cfg_crSEIRectWidthInUnitsMinus1, cfg_crSEIRectWidthInUnitsMinus1, "List of widths of the rectangles in units")
+  ("SEICrRectHeightInUnitsMinus1",                    cfg_crSEIRectHeightInUnitsMinus1, cfg_crSEIRectHeightInUnitsMinus1, "List of heights of the rectangles in units")
+#endif
+
   ("DebugBitstream",                                  m_decodeBitstreams[0],             std::string( "" ), "Assume the frames up to POC DebugPOC will be the same as in this bitstream. Load those frames from the bitstream instead of encoding them." )
   ("DebugPOC",                                        m_switchPOC,                                 -1, "If DebugBitstream is present, load frames up to this POC from this bitstream. Starting with DebugPOC, return to normal encoding." )
   ("DecodeBitstream1",                                m_decodeBitstreams[0],             std::string( "" ), "Assume the frames up to POC DebugPOC will be the same as in this bitstream. Load those frames from the bitstream instead of encoding them." )
@@ -2057,6 +2090,16 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   opts.addOptions()("SEIXmpPersistenceFlag", m_xmpPersistenceFlag, false, "Specifies that Xmp metadata SEI persists beyond the scope of a single picture");
   opts.addOptions()("SEIXmpData", cfg_xmpMetadataSEIDataValues, cfg_xmpMetadataSEIDataValues, "Xmp metadata");
 #endif
+
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+  for (int i = 0; i < MAX_RECT_TYPE_DESCRIPTIONS; i++)
+  {
+    std::ostringstream crSEIRectTypeDescription;
+    crSEIRectTypeDescription << "SEICrRectTypeDescription" << i;
+    opts.addOptions()(crSEIRectTypeDescription.str(), m_crSEIRectTypeDescription[i], std::string(""), "Specifies a text description of the i-th constituent rectangle");
+  }
+#endif
+
   po::setDefaults(opts);
   po::ErrorReporter err;
   const std::list<const char *> &argv_unhandled = po::scanArgv(opts, argc, (const char **) argv, err);
@@ -3841,6 +3884,20 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   }
 #endif
 
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+  if (m_crSEIEnabled)
+  {
+    m_crSEIRectTypePresentFlag = cfg_crSEIRectTypePresentFlag.values;
+    m_crSEIRectTypeIdc = cfg_crSEIRectTypeIdc.values;
+    m_crSEIRectId = cfg_crSEIRectId.values;
+    m_crSEIRectTypeDescriptionPresentFlag = cfg_crSEIRectTypeDescriptionPresentFlag.values;
+    m_crSEIRectTopLeftInUnitsX = cfg_crSEIRectTopLeftInUnitsX.values;
+    m_crSEIRectTopLeftInUnitsY = cfg_crSEIRectTopLeftInUnitsY.values;
+    m_crSEIRectWidthInUnitsMinus1 = cfg_crSEIRectWidthInUnitsMinus1.values;
+    m_crSEIRectHeightInUnitsMinus1 = cfg_crSEIRectHeightInUnitsMinus1.values;
+  }
+#endif
+
   // check validity of input parameters
   if( xCheckParameter() )
   {
@@ -5341,6 +5398,44 @@ bool EncAppCfg::xCheckParameter()
     xConfirmPara(m_piVerPhaseNumReducedResolution > m_piVerPhaseDenMinus1ReducedResolution + 1, "m_piVerPhaseNumReducedResolution must be in the range of 0 to m_piVerPhaseDenMinus1ReducedResolution + 1, inclusive");
   }
 
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+  if (m_crSEIEnabled)
+  {
+    xConfirmPara(m_crSEINumRectsMinus1 > 4095, "m_crSEINumRectsMinus1 must be in the range of 0 to 4095, inclusive");
+    if (m_crSEIRectIdPresentFlag)
+    {
+      xConfirmPara(m_crSEIRectIdLen > 15, "m_crSEIRectIdLen must be in the range of 0 to 15, inclusive");
+    }
+    if (!m_crSEISubpicsPartitioningFlag && !m_crSEIRectSameSizeFlag)
+    {
+      xConfirmPara(m_crSEILog2UnitSize > 15, "m_crSEILog2UnitSize must be in the range of 0 to 15, inclusive");
+      xConfirmPara(m_crSEIRectSizeLenMinus1 > 15, "m_crSEIRectSizeLenMinus1 must be in the range of 0 to 15, inclusive");
+    }
+    for (uint32_t i = 0; i <= m_crSEINumRectsMinus1; i++)
+    {
+      if (m_crSEIRectTypeEnabledFlag && m_crSEIRectTypePresentFlag[i])
+      {
+        xConfirmPara(m_crSEIRectTypeIdc[i] != 0 && m_crSEIRectTypeIdc[i] != 1 && m_crSEIRectTypeIdc[i] != 2 && m_crSEIRectTypeIdc[i] != 3 && m_crSEIRectTypeIdc[i] != 255, "m_crSEIRectTypeIdc[i] must have value of 0, 1, 2, 3, or 255");
+      }
+      if (!m_crSEISubpicsPartitioningFlag && !m_crSEIRectSameSizeFlag)
+      {
+        xConfirmPara(m_crSEIRectTopLeftInUnitsX[i] >= (1 << (m_crSEIRectSizeLenMinus1 + 1)) , "m_crSEIRectTopLeftInUnitsX values must be less than (1 << (m_crSEIRectSizeLenMinus1 + 1))");
+        xConfirmPara(m_crSEIRectTopLeftInUnitsY[i] >= (1 << (m_crSEIRectSizeLenMinus1 + 1)) , "m_crSEIRectTopLeftInUnitsY values must be less than (1 << (m_crSEIRectSizeLenMinus1 + 1))");
+        xConfirmPara(m_crSEIRectWidthInUnitsMinus1[i] >= (1 << (m_crSEIRectSizeLenMinus1 + 1)) , "m_crSEIRectWidthInUnitsMinus1 values must be less than (1 << (m_crSEIRectSizeLenMinus1 + 1))");
+        xConfirmPara(m_crSEIRectHeightInUnitsMinus1[i] >= (1 << (m_crSEIRectSizeLenMinus1 + 1)) , "m_crSEIRectHeightInUnitsMinus1 values must be less than (1 << (m_crSEIRectSizeLenMinus1 + 1))");
+      }
+    }
+    if (m_crSEIRectIdPresentFlag)
+    {
+      xConfirmPara(*std::max_element(m_crSEIRectId.begin(), m_crSEIRectId.end()) >= (1 << m_crSEIRectIdLen) , "m_crSEIRectId values must be less than (1 << m_crSEIRectIdLen)");
+      std::vector<uint32_t> tmpRectId = m_crSEIRectId;
+      std::sort(tmpRectId.begin(), tmpRectId.end());
+      auto it = std::unique(tmpRectId.begin(), tmpRectId.end());
+      xConfirmPara(it != tmpRectId.end() , "m_crSEIRectId values must be unique");
+    }
+  }
+#endif
+
   xConfirmPara(m_log2ParallelMergeLevel < 2, "Log2ParallelMergeLevel should be larger than or equal to 2");
   xConfirmPara(m_log2ParallelMergeLevel > m_ctuSize, "Log2ParallelMergeLevel should be less than or equal to CTU size");
   xConfirmPara(m_preferredTransferCharacteristics > 255, "transfer_characteristics_idc should not be greater than 255.");
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index 066c708731df1f6b1bedd5d0236fc77a29ecc413..073c88df79c487e5497de7feb153a646e88ce10c 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -824,6 +824,30 @@ protected:
   bool                 m_postFilterHintSEIChromaCoeffPresentFlag;
   std::vector<int32_t> m_postFilterHintValues;
 
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+  bool        m_crSEIEnabled;
+  uint32_t    m_crSEINumRectsMinus1;
+  bool        m_crSEIRectIdPresentFlag;
+  uint32_t    m_crSEIRectIdLen;
+  bool        m_crSEIRectTypeEnabledFlag;
+  bool        m_crSEIRectTypeDescriptionsEnabledFlag;
+  bool        m_crSEISubpicsPartitioningFlag;
+  bool        m_crSEIRectSameSizeFlag;
+  uint32_t    m_crSEINumColsMinus1;
+  uint32_t    m_crSEINumRowsMinus1;
+  uint32_t    m_crSEILog2UnitSize;
+  uint32_t    m_crSEIRectSizeLenMinus1;
+  std::vector<bool>        m_crSEIRectTypePresentFlag;
+  std::vector<uint8_t>     m_crSEIRectTypeIdc;
+  std::vector<uint32_t>    m_crSEIRectId;
+  std::vector<bool>        m_crSEIRectTypeDescriptionPresentFlag;
+  std::vector<uint32_t>    m_crSEIRectTopLeftInUnitsX;
+  std::vector<uint32_t>    m_crSEIRectTopLeftInUnitsY;
+  std::vector<uint32_t>    m_crSEIRectWidthInUnitsMinus1;
+  std::vector<uint32_t>    m_crSEIRectHeightInUnitsMinus1;
+  std::string              m_crSEIRectTypeDescription[MAX_RECT_TYPE_DESCRIPTIONS];
+#endif
+
   bool                  m_constrainedRaslEncoding;
 
   bool                  m_sampleAspectRatioInfoSEIEnabled;
diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h
index 17b613601b66b44c0ed70a791cd9ebeb31c7d7b9..d8d98134732acc4bc06c607c06a0b49185f0f371 100644
--- a/source/Lib/CommonLib/CommonDef.h
+++ b/source/Lib/CommonLib/CommonDef.h
@@ -575,6 +575,10 @@ static const uint32_t MAX_NNPFA_ID =                               0xfffffffe; /
 static const uint32_t MAX_NNPFC_ID =                               0xfffffffe; // Maximum supported nnpfc_id
 static constexpr double SII_PF_W2 =                                       0.6; // weight for current picture
 static constexpr double SII_PF_W1 =                                       0.4; // weight for previous picture , it must be equal to 1.0 - SII_PF_W2
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+static constexpr int MAX_RECT_TYPE_DESCRIPTIONS =                          64; // Maximum constituent rectangle type description strings supported by this encoder implementation
+#endif
+
 // ====================================================================================================================
 // Macro functions
 // ====================================================================================================================
diff --git a/source/Lib/CommonLib/SEI.cpp b/source/Lib/CommonLib/SEI.cpp
index 22951289f6ef02521a89d59ced15ca7ab963f390..90e103a96bbba8c1cbaa2ae789b91eee13a2ec6d 100644
--- a/source/Lib/CommonLib/SEI.cpp
+++ b/source/Lib/CommonLib/SEI.cpp
@@ -549,6 +549,9 @@ static const std::map<SEI::PayloadType, const char *> payloadTypeStrings = {
   { SEI::PayloadType::JFIF_METADATA, "Jfif metadata information" },
   { SEI::PayloadType::XMP_METADATA, "Xmp metadata information" },
 #endif
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+  { SEI::PayloadType::CONSTITUENT_RECTANGLES, "Constituent rectangles" },
+#endif
 };
 
 const char *SEI::getSEIMessageString(SEI::PayloadType payloadType)
@@ -1316,3 +1319,29 @@ SEIXmpMetadata::SEIXmpMetadata(const SEIXmpMetadata& sei)
   m_xmpData = sei.m_xmpData;
 }
 #endif
+
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+SEIConstituentRectangles::SEIConstituentRectangles(const SEIConstituentRectangles& sei)
+{
+  m_numRectsMinus1 = sei.m_numRectsMinus1;
+  m_rectIdPresentFlag = sei.m_rectIdPresentFlag;
+  m_rectIdLen = sei.m_rectIdLen;
+  m_rectTypeEnabledFlag = sei.m_rectTypeEnabledFlag;
+  m_rectTypeDescriptionsEnabledFlag = sei.m_rectTypeDescriptionsEnabledFlag;
+  m_subpicsPartitioningFlag = sei.m_subpicsPartitioningFlag;
+  m_rectSameSizeFlag = sei.m_rectSameSizeFlag;
+  m_numColsMinus1 = sei.m_numColsMinus1;
+  m_numRowsMinus1 = sei.m_numRowsMinus1;
+  m_log2UnitSize = sei.m_log2UnitSize;
+  m_rectSizeLenMinus1 = sei.m_rectSizeLenMinus1;
+  m_rectTypePresentFlag = sei.m_rectTypePresentFlag;
+  m_rectTypeIdc = sei.m_rectTypeIdc;
+  m_rectId = sei.m_rectId;
+  m_rectTypeDescriptionPresentFlag = sei.m_rectTypeDescriptionPresentFlag;
+  m_rectTopLeftInUnitsX = sei.m_rectTopLeftInUnitsX;
+  m_rectTopLeftInUnitsY = sei.m_rectTopLeftInUnitsY;
+  m_rectWidthInUnitsMinus1 = sei.m_rectWidthInUnitsMinus1;
+  m_rectHeightInUnitsMinus1 = sei.m_rectHeightInUnitsMinus1;
+  m_rectTypeDescription = sei.m_rectTypeDescription;
+}
+#endif
diff --git a/source/Lib/CommonLib/SEI.h b/source/Lib/CommonLib/SEI.h
index 5b14686fa385d0aa455f91202f55c244be36819d..acdc1077145ea2d203c3b12c801827b924861d86 100644
--- a/source/Lib/CommonLib/SEI.h
+++ b/source/Lib/CommonLib/SEI.h
@@ -116,6 +116,9 @@ public:
 #endif
 #if JVET_AF0167_MULTI_PLANE_IMAGE_INFO_SEI
     MULTIPLANE_IMAGE_INFO, // payload_type value TBD
+#endif
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+    CONSTITUENT_RECTANGLES, // payload_type value TBD
 #endif
   };
 
@@ -1571,3 +1574,51 @@ public:
   std::string m_aiMarkerInfoData;
 };
 #endif
+
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+class SEIConstituentRectangles : public SEI
+{
+public:
+  PayloadType payloadType() const
+  {
+    return PayloadType::CONSTITUENT_RECTANGLES;
+  }
+
+  SEIConstituentRectangles()
+  {}
+  SEIConstituentRectangles(const SEIConstituentRectangles& sei);
+
+  virtual ~SEIConstituentRectangles()
+  {}
+
+  enum RectTypeIdc : uint8_t
+  {
+    CR_TEXTURE,
+    CR_ALPHA,
+    CR_DEPTH,
+    CR_OBJECT_MASK,
+    CR_EMPTY = 255
+  };
+
+  uint32_t    m_numRectsMinus1;
+  bool        m_rectIdPresentFlag;
+  uint8_t     m_rectIdLen;
+  bool        m_rectTypeEnabledFlag;
+  bool        m_rectTypeDescriptionsEnabledFlag;
+  bool        m_subpicsPartitioningFlag;
+  bool        m_rectSameSizeFlag;
+  uint32_t    m_numColsMinus1;
+  uint32_t    m_numRowsMinus1;
+  uint8_t     m_log2UnitSize;
+  uint8_t     m_rectSizeLenMinus1;
+  std::vector<bool>        m_rectTypePresentFlag;
+  std::vector<RectTypeIdc> m_rectTypeIdc;
+  std::vector<uint32_t>    m_rectId;
+  std::vector<bool>        m_rectTypeDescriptionPresentFlag;
+  std::vector<uint32_t>    m_rectTopLeftInUnitsX;
+  std::vector<uint32_t>    m_rectTopLeftInUnitsY;
+  std::vector<uint32_t>    m_rectWidthInUnitsMinus1;
+  std::vector<uint32_t>    m_rectHeightInUnitsMinus1;
+  std::vector<std::string> m_rectTypeDescription;
+};
+#endif
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 804001822a7729db60ec0a33d6ee2e356f202836..9193a8ec89bef20969d79e665609f0b0d0363e6f 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -79,6 +79,8 @@
 #define JVET_AG0045_AI_MARKER_SEI                         1
 #define JVET_AF0141_IMAGE_METADATA_SEIS                   1
 
+#define JVET_AH0162_CONSTITUENT_RECTANGLES                1
+
 //########### 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 b5a94cd3e29b7ee2174cce1e8f3bf3be0651c011..1c61cf5303cdf0d123c3e730c3eba886e333cf22 100644
--- a/source/Lib/DecoderLib/SEIread.cpp
+++ b/source/Lib/DecoderLib/SEIread.cpp
@@ -570,6 +570,12 @@ bool SEIReader::xReadSEImessage(SEIMessages& seis, const NalUnitType nalUnitType
       sei = new SEIXmpMetadata();
       xParseSEIXmpMetadata((SEIXmpMetadata &) *sei, payloadSize, pDecodedMessageOutputStream);
       break;
+#endif
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+    case SEI::PayloadType::CONSTITUENT_RECTANGLES:
+      sei = new SEIConstituentRectangles();
+      xParseSEIConstituentRectangles((SEIConstituentRectangles&) *sei, payloadSize, pDecodedMessageOutputStream);
+      break;
 #endif
     default:
       for (uint32_t i = 0; i < payloadSize; i++)
@@ -3894,4 +3900,124 @@ void SEIReader::xParseSEIXmpMetadata(SEIXmpMetadata &sei, uint32_t payLoadSize,
   }
 }
 #endif
+
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+void SEIReader::xParseSEIConstituentRectangles(SEIConstituentRectangles& sei, uint32_t payLoadSize, std::ostream* pDecodedMessageOutputStream)
+{
+  output_sei_message_header(sei, pDecodedMessageOutputStream, payLoadSize);
+  uint32_t val;
+  xReadCode(12, val, "cr_num_rects_minus1");
+  sei.m_numRectsMinus1 = val;
+  xReadFlag(val, "cr_rect_id_present_flag");
+  sei.m_rectIdPresentFlag = val;
+  if (sei.m_rectIdPresentFlag)
+  {
+    xReadCode(4, val, "cr_rect_id_len");
+    sei.m_rectIdLen = val;
+  }
+  xReadFlag(val, "cr_rect_type_enabled_flag");
+  sei.m_rectTypeEnabledFlag = val;
+  xReadFlag(val, "cr_rect_type_descriptions_enabled_flag");
+  sei.m_rectTypeDescriptionsEnabledFlag = val;
+  xReadFlag(val, "cr_subpics_partitioning_flag");
+  sei.m_subpicsPartitioningFlag = val;
+  if (!sei.m_subpicsPartitioningFlag)
+  {
+    xReadFlag(val, "cr_rect_same_size_flag");
+    sei.m_rectSameSizeFlag = val;
+    if (sei.m_rectSameSizeFlag)
+    {
+      xReadUvlc(val, "cr_num_cols_minus1");
+      sei.m_numColsMinus1 = val;
+      xReadUvlc(val, "cr_num_rows_minus1");
+      sei.m_numRowsMinus1 = val;
+    }
+    else
+    {
+      xReadCode(4, val, "cr_log2_unit_size");
+      sei.m_log2UnitSize = val;
+      xReadCode(4, val, "cr_rect_size_len_minus1");
+      sei.m_rectSizeLenMinus1 = val;
+    }
+  }
+
+  sei.m_rectTypePresentFlag.resize(sei.m_numRectsMinus1 + 1);
+  sei.m_rectTypeIdc.resize(sei.m_numRectsMinus1 + 1);
+  sei.m_rectId.resize(sei.m_numRectsMinus1 + 1);
+  sei.m_rectTypeDescriptionPresentFlag.resize(sei.m_numRectsMinus1 + 1);
+  sei.m_rectTopLeftInUnitsX.resize(sei.m_numRectsMinus1 + 1);
+  sei.m_rectTopLeftInUnitsY.resize(sei.m_numRectsMinus1 + 1);
+  sei.m_rectWidthInUnitsMinus1.resize(sei.m_numRectsMinus1 + 1);
+  sei.m_rectHeightInUnitsMinus1.resize(sei.m_numRectsMinus1 + 1);
+  sei.m_rectTypeDescription.resize(sei.m_numRectsMinus1 + 1);
+
+  for (uint32_t i = 0; i <= sei.m_numRectsMinus1; i++)
+  {
+    if (sei.m_rectTypeEnabledFlag)
+    {
+      xReadFlag(val, "cr_rect_type_present_flag[i]");
+      sei.m_rectTypePresentFlag[i] = val;
+      if (sei.m_rectTypePresentFlag[i])
+      {
+        xReadCode(8, val, "cr_rect_type_idc[i]");
+        sei.m_rectTypeIdc[i] = (SEIConstituentRectangles::RectTypeIdc)val;
+        CHECK(sei.m_rectTypeIdc[i] != 0 && sei.m_rectTypeIdc[i] != 1 && sei.m_rectTypeIdc[i] != 2 && sei.m_rectTypeIdc[i] != 3 && sei.m_rectTypeIdc[i] != 255, "cr_rect_type_idc[i] must have value of 0, 1, 2, 3, or 255");
+      }
+    }
+    if (!sei.m_rectTypeEnabledFlag || !sei.m_rectTypePresentFlag[i])
+    {
+      sei.m_rectTypeIdc[i] = (i == 0) ? SEIConstituentRectangles::CR_TEXTURE : sei.m_rectTypeIdc[i - 1];
+    }
+    sei.m_rectId[i] = i;
+    sei.m_rectTypeDescriptionPresentFlag[i] = false;
+    if (sei.m_rectTypeIdc[i] != SEIConstituentRectangles::CR_EMPTY)
+    {
+      if (sei.m_rectIdPresentFlag)
+      {
+        xReadCode(sei.m_rectIdLen, val, "cr_rect_id[i]");
+        sei.m_rectId[i] = val;
+      }
+      if (sei.m_rectTypeDescriptionsEnabledFlag)
+      {
+        xReadFlag(val, "cr_rect_type_description_present_flag[i]");
+        sei.m_rectTypeDescriptionPresentFlag[i] = val;
+      }
+    }
+    if (!sei.m_subpicsPartitioningFlag && !sei.m_rectSameSizeFlag)
+    {
+      xReadCode(sei.m_rectSizeLenMinus1 + 1, val, "cr_rect_top_left_in_units_x[i]");
+      sei.m_rectTopLeftInUnitsX[i] = val;
+      xReadCode(sei.m_rectSizeLenMinus1 + 1, val, "cr_rect_top_left_in_units_y[i]");
+      sei.m_rectTopLeftInUnitsY[i] = val;
+      xReadCode(sei.m_rectSizeLenMinus1 + 1, val, "cr_rect_width_in_units_minus1[i]");
+      sei.m_rectWidthInUnitsMinus1[i] = val;
+      xReadCode(sei.m_rectSizeLenMinus1 + 1, val, "cr_rect_height_in_units_minus1[i]");
+      sei.m_rectHeightInUnitsMinus1[i] = val;
+    }
+  }
+  if (sei.m_rectTypeDescriptionsEnabledFlag)
+  {
+    while (!isByteAligned())
+    {
+      xReadFlag(val, "cr_bit_equal_to_zero");
+      CHECK(val != 0, "cr_bit_equal_to_zero must be zero");
+    }
+    for (uint32_t i = 0; i <= sei.m_numRectsMinus1; i++)
+    {
+      if (sei.m_rectTypeDescriptionPresentFlag[i])
+      {
+        xReadString(sei.m_rectTypeDescription[i], "cr_rect_type_description[i]");
+      }
+    }
+  }
+  if (sei.m_rectIdPresentFlag)
+  {
+    std::vector<uint32_t> tmpRectId = sei.m_rectId;
+    std::sort(tmpRectId.begin(), tmpRectId.end());
+    auto it = std::unique(tmpRectId.begin(), tmpRectId.end());
+    CHECK(it != tmpRectId.end() , "cr_rect_id[i] values must be unique");
+  }
+}
+#endif
+
 //! \}
diff --git a/source/Lib/DecoderLib/SEIread.h b/source/Lib/DecoderLib/SEIread.h
index 1123cc975d45da969a347ea5b40c2803729e0b59..e96efef4806fc7f0a974c08c673c49333eea58de 100644
--- a/source/Lib/DecoderLib/SEIread.h
+++ b/source/Lib/DecoderLib/SEIread.h
@@ -134,6 +134,10 @@ protected:
   void xParseSEIXmpMetadata  (SEIXmpMetadata  &sei, uint32_t payLoadSize, std::ostream *pDecodedMessageOutputStream);
 #endif
 
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+  void xParseSEIConstituentRectangles(SEIConstituentRectangles& 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);
   void sei_read_uvlc(std::ostream *pOS,                uint32_t& ruiCode, const char *pSymbolName);
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index 5c3a675e6df2e762c8630cbfd840ad10c0a3d96d..65b5565f68d9b0496faeb277b6b9303dbc4aa420 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -954,6 +954,31 @@ protected:
   std::vector<uint8_t> m_jfifSEIData;
 
 #endif
+
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+  bool        m_crSEIEnabled;
+  uint32_t    m_crSEINumRectsMinus1;
+  bool        m_crSEIRectIdPresentFlag;
+  uint8_t     m_crSEIRectIdLen;
+  bool        m_crSEIRectTypeEnabledFlag;
+  bool        m_crSEIRectTypeDescriptionsEnabledFlag;
+  bool        m_crSEISubpicsPartitioningFlag;
+  bool        m_crSEIRectSameSizeFlag;
+  bool        m_crSEINumColsMinus1;
+  bool        m_crSEINumRowsMinus1;
+  uint8_t     m_crSEILog2UnitSize;
+  uint8_t     m_crSEIRectSizeLenMinus1;
+  std::vector<bool>        m_crSEIRectTypePresentFlag;
+  std::vector<uint8_t>     m_crSEIRectTypeIdc;
+  std::vector<uint32_t>    m_crSEIRectId;
+  std::vector<bool>        m_crSEIRectTypeDescriptionPresentFlag;
+  std::vector<uint32_t>    m_crSEIRectTopLeftInUnitsX;
+  std::vector<uint32_t>    m_crSEIRectTopLeftInUnitsY;
+  std::vector<uint32_t>    m_crSEIRectWidthInUnitsMinus1;
+  std::vector<uint32_t>    m_crSEIRectHeightInUnitsMinus1;
+  std::vector<std::string> m_crSEIRectTypeDescription;
+#endif
+
   bool      m_constrainedRaslEncoding;
 
   //====== Weighted Prediction ========
@@ -2736,6 +2761,51 @@ public:
   void                        setJfifSEIJfifData(std::vector<uint8_t> source) { m_jfifSEIData = source; }
 #endif
 
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+  bool        getCrSEIEnabled() const { return m_crSEIEnabled; }
+  void        setCrSEIEnabled(bool b) { m_crSEIEnabled = b; }
+  uint32_t    getCrSEINumRectsMinus1() const { return m_crSEINumRectsMinus1; }
+  void        setCrSEINumRectsMinus1(uint32_t b) { m_crSEINumRectsMinus1 = b; }
+  bool        getCrSEIRectIdPresentFlag() const { return m_crSEIRectIdPresentFlag; }
+  void        setCrSEIRectIdPresentFlag(bool b) { m_crSEIRectIdPresentFlag = b; }
+  uint8_t     getCrSEIRectIdLen() const { return m_crSEIRectIdLen; }
+  void        setCrSEIRectIdLen(uint8_t b) { m_crSEIRectIdLen = b; }
+  bool        getCrSEIRectTypeEnabledFlag() const { return m_crSEIRectTypeEnabledFlag; }
+  void        setCrSEIRectTypeEnabledFlag(bool b) { m_crSEIRectTypeEnabledFlag = b; }
+  bool        getCrSEIRectTypeDescriptionsEnabledFlag() const { return m_crSEIRectTypeDescriptionsEnabledFlag; }
+  void        setCrSEIRectTypeDescriptionsEnabledFlag(bool b) { m_crSEIRectTypeDescriptionsEnabledFlag = b; }
+  bool        getCrSEISubpicsPartitioningFlag() const { return m_crSEISubpicsPartitioningFlag; }
+  void        setCrSEISubpicsPartitioningFlag(bool b) { m_crSEISubpicsPartitioningFlag = b; }
+  bool        getCrSEIRectSameSizeFlag() const { return m_crSEIRectSameSizeFlag; }
+  void        setCrSEIRectSameSizeFlag(bool b) { m_crSEIRectSameSizeFlag = b; }
+  uint32_t    getCrSEINumColsMinus1() const { return m_crSEINumColsMinus1; }
+  void        setCrSEINumColsMinus1(uint32_t b) { m_crSEINumColsMinus1 = b; }
+  uint32_t    getCrSEINumRowsMinus1() const { return m_crSEINumRowsMinus1; }
+  void        setCrSEINumRowsMinus1(uint32_t b) { m_crSEINumRowsMinus1 = b; }
+  uint8_t     getCrSEILog2UnitSize() const { return m_crSEILog2UnitSize; }
+  void        setCrSEILog2UnitSize(uint8_t b) { m_crSEILog2UnitSize = b; }
+  uint8_t     getCrSEIRectSizeLenMinus1() const { return m_crSEIRectSizeLenMinus1; }
+  void        setCrSEIRectSizeLenMinus1(uint8_t b) { m_crSEIRectSizeLenMinus1 = b; }
+  bool        getCrSEIRectTypePresentFlag(uint32_t i) const { return m_crSEIRectTypePresentFlag[i]; }
+  void        setCrSEIRectTypePresentFlag(const std::vector<bool>& b) { m_crSEIRectTypePresentFlag = b; }
+  uint8_t     getCrSEIRectTypeIdc(uint32_t i) const { return m_crSEIRectTypeIdc[i]; }
+  void        setCrSEIRectTypeIdc(const std::vector<uint8_t>& b) { m_crSEIRectTypeIdc = b; }
+  uint32_t    getCrSEIRectId(uint32_t i) const { return m_crSEIRectId[i]; }
+  void        setCrSEIRectId(const std::vector<uint32_t>& b) { m_crSEIRectId = b; }
+  bool        getCrSEIRectTypeDescriptionPresentFlag(uint32_t i) const { return m_crSEIRectTypeDescriptionPresentFlag[i]; }
+  void        setCrSEISEIRectTypeDescriptionPresentFlag(const std::vector<bool>& b) { m_crSEIRectTypeDescriptionPresentFlag = b; }
+  uint32_t    getCrSEIRectTopLeftInUnitsX(uint32_t i) const { return m_crSEIRectTopLeftInUnitsX[i]; }
+  void        setCrSEIRectTopLeftInUnitsX(const std::vector<uint32_t>& b) { m_crSEIRectTopLeftInUnitsX = b; }
+  uint32_t    getCrSEIRectTopLeftInUnitsY(uint32_t i) const { return m_crSEIRectTopLeftInUnitsY[i]; }
+  void        setCrSEIRectTopLeftInUnitsY(const std::vector<uint32_t>& b) { m_crSEIRectTopLeftInUnitsY = b; }
+  uint32_t    getCrSEIRectWidthInUnitsMinus1(uint32_t i) const { return m_crSEIRectWidthInUnitsMinus1[i]; }
+  void        setCrSEIRectWidthInUnitsMinus1(const std::vector<uint32_t>& b) { m_crSEIRectWidthInUnitsMinus1 = b; }
+  uint32_t    getCrSEIRectHeightInUnitsMinus1(uint32_t i) const { return m_crSEIRectHeightInUnitsMinus1[i]; }
+  void        setCrSEIRectHeightInUnitsMinus1(const std::vector<uint32_t>& b) { m_crSEIRectHeightInUnitsMinus1 = b; }
+  std::string getCrSEIRectTypeDescription(uint32_t i) const { return m_crSEIRectTypeDescription[i]; }
+  void        setCrSEIRectTypeDescription(const std::vector<std::string>& b) { m_crSEIRectTypeDescription = b; }
+#endif
+
   void         setUseWP               ( bool b )                     { m_useWeightedPred   = b;    }
   void         setWPBiPred            ( bool b )                     { m_useWeightedBiPred = b;    }
   bool         getUseWP               ()                             { return m_useWeightedPred;   }
diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp
index 61d0520ac9b5407cd2dccdb7883728c37d75df1f..5d014e740b05abcb966dba6b1b175a4695162c9a 100644
--- a/source/Lib/EncoderLib/EncGOP.cpp
+++ b/source/Lib/EncoderLib/EncGOP.cpp
@@ -937,6 +937,14 @@ void EncGOP::xCreateIRAPLeadingSEIMessages (SEIMessages& seiMessages, const SPS
     m_seiEncoder.initSEIProcessingOrderInfo(seiProcessingOrder);
     seiMessages.push_back(seiProcessingOrder);
   }
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+  if (m_pcCfg->getCrSEIEnabled())
+  {
+    SEIConstituentRectangles *seiConstituentRectangles = new SEIConstituentRectangles;
+    m_seiEncoder.initSEIConstituentRectanges(seiConstituentRectangles);
+    seiMessages.push_back(seiConstituentRectangles);
+  }
+#endif
 }
 
 void EncGOP::xCreatePerPictureSEIMessages (int picInGOP, SEIMessages& seiMessages, SEIMessages& nestedSeiMessages, Slice *slice)
diff --git a/source/Lib/EncoderLib/SEIEncoder.cpp b/source/Lib/EncoderLib/SEIEncoder.cpp
index 611d82c697f392ff505786d939702f17ba4736a6..507e7e4bbd5f8366a6fa9920e6f247f8d41877fd 100644
--- a/source/Lib/EncoderLib/SEIEncoder.cpp
+++ b/source/Lib/EncoderLib/SEIEncoder.cpp
@@ -1866,4 +1866,72 @@ void SEIEncoder::initSEIXmpMetadata(SEIXmpMetadata *sei)
 
 #endif
 
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+void SEIEncoder::initSEIConstituentRectanges(SEIConstituentRectangles* sei)
+{
+  CHECK(!m_isInitialized, "Constituent rectangles SEI already initialized");
+  CHECK(sei == nullptr, "Need a SEIConstituentRectangles for initialization (got nullptr)");
+
+  sei->m_numRectsMinus1 = m_pcCfg->getCrSEINumRectsMinus1();
+  sei->m_rectIdPresentFlag = m_pcCfg->getCrSEIRectIdPresentFlag();
+  sei->m_rectIdLen = m_pcCfg->getCrSEIRectIdLen();
+  sei->m_rectTypeEnabledFlag = m_pcCfg->getCrSEIRectTypeEnabledFlag();
+  sei->m_rectTypeDescriptionsEnabledFlag = m_pcCfg->getCrSEIRectTypeDescriptionsEnabledFlag();
+  sei->m_subpicsPartitioningFlag = m_pcCfg->getCrSEISubpicsPartitioningFlag();
+  sei->m_rectSameSizeFlag = m_pcCfg->getCrSEIRectSameSizeFlag();
+  sei->m_numColsMinus1 = m_pcCfg->getCrSEINumColsMinus1();
+  sei->m_numRowsMinus1 = m_pcCfg->getCrSEINumRowsMinus1();
+  sei->m_log2UnitSize = m_pcCfg->getCrSEILog2UnitSize();
+  sei->m_rectSizeLenMinus1 = m_pcCfg->getCrSEIRectSizeLenMinus1();
+
+  sei->m_rectTypePresentFlag.resize(sei->m_numRectsMinus1 + 1);
+  sei->m_rectTypeIdc.resize(sei->m_numRectsMinus1 + 1);
+  sei->m_rectId.resize(sei->m_numRectsMinus1 + 1);
+  sei->m_rectTypeDescriptionPresentFlag.resize(sei->m_numRectsMinus1 + 1);
+  sei->m_rectTopLeftInUnitsX.resize(sei->m_numRectsMinus1 + 1);
+  sei->m_rectTopLeftInUnitsY.resize(sei->m_numRectsMinus1 + 1);
+  sei->m_rectWidthInUnitsMinus1.resize(sei->m_numRectsMinus1 + 1);
+  sei->m_rectHeightInUnitsMinus1.resize(sei->m_numRectsMinus1 + 1);
+  sei->m_rectTypeDescription.resize(sei->m_numRectsMinus1 + 1);
+
+  for (uint32_t i = 0; i <= sei->m_numRectsMinus1; i++)
+  {
+    if (sei->m_rectTypeEnabledFlag)
+    {
+      sei->m_rectTypePresentFlag[i] = m_pcCfg->getCrSEIRectTypePresentFlag(i);
+      if (sei->m_rectTypePresentFlag[i])
+      {
+        sei->m_rectTypeIdc[i] = (SEIConstituentRectangles::RectTypeIdc)m_pcCfg->getCrSEIRectTypeIdc(i);
+      }
+    }
+    if (!sei->m_rectTypeEnabledFlag || !sei->m_rectTypePresentFlag[i])
+    {
+      sei->m_rectTypeIdc[i] = (i == 0) ? SEIConstituentRectangles::CR_TEXTURE : sei->m_rectTypeIdc[i - 1];
+    }
+    if (sei->m_rectTypeIdc[i] != SEIConstituentRectangles::CR_EMPTY)
+    {
+      if (sei->m_rectIdPresentFlag)
+      {
+        sei->m_rectId[i] = m_pcCfg->getCrSEIRectId(i);
+      }
+      if (sei->m_rectTypeDescriptionsEnabledFlag)
+      {
+        sei->m_rectTypeDescriptionPresentFlag[i] = m_pcCfg->getCrSEIRectTypeDescriptionPresentFlag(i);
+      }
+    }
+    if (!sei->m_subpicsPartitioningFlag && !sei->m_rectSameSizeFlag)
+    {
+      sei->m_rectTopLeftInUnitsX[i] = m_pcCfg->getCrSEIRectTopLeftInUnitsX(i);
+      sei->m_rectTopLeftInUnitsY[i] = m_pcCfg->getCrSEIRectTopLeftInUnitsY(i);
+      sei->m_rectWidthInUnitsMinus1[i] = m_pcCfg->getCrSEIRectWidthInUnitsMinus1(i);
+      sei->m_rectHeightInUnitsMinus1[i] = m_pcCfg->getCrSEIRectHeightInUnitsMinus1(i);
+    }
+    if (sei->m_rectTypeDescriptionsEnabledFlag)
+    {
+      sei->m_rectTypeDescription[i] = m_pcCfg->getCrSEIRectTypeDescription(i);
+    }
+  }
+}
+#endif
+
 //! \}
diff --git a/source/Lib/EncoderLib/SEIEncoder.h b/source/Lib/EncoderLib/SEIEncoder.h
index 26a5230e008529251b3a6c1b5cd69b407b5daba6..0b6608e99aef2e959ed4310790a3ef71e28febe6 100644
--- a/source/Lib/EncoderLib/SEIEncoder.h
+++ b/source/Lib/EncoderLib/SEIEncoder.h
@@ -121,6 +121,9 @@ public:
   void initSEIJfifMetadata(SEIJfifMetadata *sei);
   void initSEIXmpMetadata(SEIXmpMetadata *sei);
 #endif
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+  void initSEIConstituentRectanges(SEIConstituentRectangles* sei);
+#endif
 private:
   EncCfg* m_pcCfg;
   EncLib* m_pcEncLib;
diff --git a/source/Lib/EncoderLib/SEIwrite.cpp b/source/Lib/EncoderLib/SEIwrite.cpp
index 7278b063623e4347617b1a457022a8bd0a078810..3296af8b7d56563c2a65cd56aec4185988b1999e 100644
--- a/source/Lib/EncoderLib/SEIwrite.cpp
+++ b/source/Lib/EncoderLib/SEIwrite.cpp
@@ -218,6 +218,11 @@ void SEIWriter::xWriteSEIpayloadData(OutputBitstream &bs, const SEI &sei, HRD &h
   case SEI::PayloadType::XMP_METADATA:
     xWriteSEIXmpMetadata(*static_cast<const SEIXmpMetadata*>(&sei));
     break;
+#endif
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+  case SEI::PayloadType::CONSTITUENT_RECTANGLES:
+    xWriteSEIConstituentRectangles(*static_cast<const SEIConstituentRectangles*>(&sei));
+    break;
 #endif
   default:
     THROW("Trying to write unhandled SEI message");
@@ -2137,4 +2142,77 @@ void SEIWriter::xWriteSEIPostFilterHint(const SEIPostFilterHint &sei)
     }
   }
 }
+
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+void SEIWriter::xWriteSEIConstituentRectangles(const SEIConstituentRectangles& sei)
+{
+  xWriteCode(sei.m_numRectsMinus1, 12, "cr_num_rects_minus1");
+  xWriteFlag(sei.m_rectIdPresentFlag, "cr_rect_id_present_flag");
+  if (sei.m_rectIdPresentFlag)
+  {
+    xWriteCode(sei.m_rectIdLen, 4, "cr_rect_id_len");
+  }
+  xWriteFlag(sei.m_rectTypeEnabledFlag, "cr_rect_type_enabled_flag");
+  xWriteFlag(sei.m_rectTypeDescriptionsEnabledFlag, "cr_rect_type_descriptions_enabled_flag");
+  xWriteFlag(sei.m_subpicsPartitioningFlag, "cr_subpics_partitioning_flag");
+  if (!sei.m_subpicsPartitioningFlag)
+  {
+    xWriteFlag(sei.m_rectSameSizeFlag, "cr_rect_same_size_flag");
+    if (sei.m_rectSameSizeFlag)
+    {
+      xWriteUvlc(sei.m_numColsMinus1, "cr_num_cols_minus1");
+      xWriteUvlc(sei.m_numRowsMinus1, "cr_num_rows_minus1");
+    }
+    else
+    {
+      xWriteCode(sei.m_log2UnitSize, 4, "cr_log2_unit_size");
+      xWriteCode(sei.m_rectSizeLenMinus1, 4, "cr_rect_size_len_minus1");
+    }
+  }
+  for (uint32_t i = 0; i <= sei.m_numRectsMinus1; i++)
+  {
+    if (sei.m_rectTypeEnabledFlag)
+    {
+      xWriteFlag(sei.m_rectTypePresentFlag[i], "cr_rect_type_present_flag[i]");
+      if (sei.m_rectTypePresentFlag[i])
+      {
+        xWriteCode(sei.m_rectTypeIdc[i], 8, "cr_rect_type_idc[i]");
+      }
+    }
+    if (sei.m_rectTypeIdc[i] != SEIConstituentRectangles::CR_EMPTY)
+    {
+      if (sei.m_rectIdPresentFlag)
+      {
+        xWriteCode(sei.m_rectId[i], sei.m_rectIdLen, "cr_rect_id[i]");
+      }
+      if (sei.m_rectTypeDescriptionsEnabledFlag)
+      {
+        xWriteFlag(sei.m_rectTypeDescriptionPresentFlag[i], "cr_rect_type_description_present_flag[i]");
+      }
+    }
+    if (!sei.m_subpicsPartitioningFlag && !sei.m_rectSameSizeFlag)
+    {
+      xWriteCode(sei.m_rectTopLeftInUnitsX[i], sei.m_rectSizeLenMinus1 + 1, "cr_rect_top_left_in_units_x[i]");
+      xWriteCode(sei.m_rectTopLeftInUnitsY[i], sei.m_rectSizeLenMinus1 + 1, "cr_rect_top_left_in_units_y[i]");
+      xWriteCode(sei.m_rectWidthInUnitsMinus1[i], sei.m_rectSizeLenMinus1 + 1, "cr_rect_width_in_units_minus1[i]");
+      xWriteCode(sei.m_rectHeightInUnitsMinus1[i], sei.m_rectSizeLenMinus1 + 1, "cr_rect_height_in_units_minus1[i]");
+    }
+  }
+  if (sei.m_rectTypeDescriptionsEnabledFlag)
+  {
+    while (!isByteAligned())
+    {
+      xWriteFlag(0, "cr_bit_equal_to_zero");
+    }
+    for (uint32_t i = 0; i <= sei.m_numRectsMinus1; i++)
+    {
+      if (sei.m_rectTypeDescriptionPresentFlag[i])
+      {
+        xWriteString(sei.m_rectTypeDescription[i], "cr_rect_type_description[i]");
+      }
+    }
+  }
+}
+#endif
+
 //! \}
diff --git a/source/Lib/EncoderLib/SEIwrite.h b/source/Lib/EncoderLib/SEIwrite.h
index 789d2ea8974a129fee510f5546bcb65748546e42..b2b4a8750947371356f9b5c0c610bcd971353720 100644
--- a/source/Lib/EncoderLib/SEIwrite.h
+++ b/source/Lib/EncoderLib/SEIwrite.h
@@ -129,6 +129,9 @@ protected:
   void xWriteSEIJfifMetadata(const SEIJfifMetadata &sei);
   void xWriteSEIXmpMetadata(const SEIXmpMetadata &sei);
 #endif
+#if JVET_AH0162_CONSTITUENT_RECTANGLES
+  void xWriteSEIConstituentRectangles(const SEIConstituentRectangles &sei);
+#endif
 protected:
   HRD m_nestingHrd;
 };