diff --git a/cfg/sei_vui/packed_regions_info.cfg b/cfg/sei_vui/packed_regions_info.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..192e9d19861ce352824eb9b7275e611e8a1c63d9
--- /dev/null
+++ b/cfg/sei_vui/packed_regions_info.cfg
@@ -0,0 +1,25 @@
+RPR                                : 1
+SEIPRIEnabled                      : 1
+SEIPRICancelFlag                   : 0
+SEIPRIPersistenceFlag              : 1
+SEIPRINumRegionsMinus1             : 1
+SEIPRIUseMaxDimensionsFlag         : 0
+SEIPRILog2UnitSize                 : 0
+SEIPRIRegionSizeLenMinus1          : 12
+SEIPRIRegionIdPresentFlag          : 1
+SEIPRITargetPicParamsPresentFlag   : 1
+SEIPRITargetPicWidthMinus1         : 175
+SEIPRITargetPicHeightMinus1        : 143
+SEIPRINumResamplingRatiosMinus1    : 1
+SEIPRIResamplingWidthNumMinus1     : 0 1
+SEIPRIResamplingWidthDenomMinus1   : 0 0
+SEIPRIResamplingHeightNumMinus1    : 0 1
+SEIPRIResamplingHeightDenomMinus1  : 0 0
+SEIPRIRegionId                     : 1 0
+SEIPRIRegionTopLeftInUnitsX        : 88 0
+SEIPRIRegionTopLeftInUnitsY        : 0 0
+SEIPRIRegionWidthInUnitsMinus1     : 87 87
+SEIPRIRegionHeightInUnitsMinus1    : 71 71
+SEIPRIResamplingRatioIdx           : 0 1
+SEIPRITargetRegionTopLeftX         : 44 0
+SEIPRITargetRegionTopLeftY         : 36 0
diff --git a/doc/software-manual.tex b/doc/software-manual.tex
index 69d629fbf1e0b5a27bb7dc8fcdfa63eb2baf67cd..cf6f265b1d8cca27680944d2f5ffb3976a86a9c4 100644
--- a/doc/software-manual.tex
+++ b/doc/software-manual.tex
@@ -3999,6 +3999,7 @@ The table below lists the SEI messages defined for Version 1 and Range-Extension
   TBD & JFIF metadata                            & Table \ref{tab:sei-jfif}\\
   TBD & XMP metadata                             & Table \ref{tab:sei-xmp}\\
   TBD & Constituent Rectangles                   & Table \ref{tab:sei-cr}\\
+  TBD & Packed Regions Info                      & Table \ref{tab:sei-pri}\\
 \end{SEIListTable}
 %%
 %% SEI messages
@@ -6411,6 +6412,104 @@ An example file can be found in cfg/sei_vui/object_mask_infos/intra/mask_info_0.
   \\
 \end{OptionTableNoShorthand}
 
+\begin{OptionTableNoShorthand}{Packed Regions Info SEI message encoder parameters}{tab:sei-pri}
+  \Option{SEIPRIEnabled} &
+  \Default{false} &
+  Specifies whether packet regions info SEI is enabled.
+  \\
+  \Option{SEIPRICancelFlag} &
+  \Default{false} &
+  Specifies the persistence of any previous packed regions info SEI message in output order.
+  \\
+  \Option{SEIPRIPersistenceFlag} &
+  \Default{false} &
+  Specifies the persistence of the packed regions info SEI message for the current layer.
+  \\
+  \Option{SEIPRINumRegionsMinus1} &
+  \Default{0} &
+  Specifies the number of regions minus 1 for which information is signalled.
+  \\
+  \Option{SEIPRIUseMaxDimensionsFlag} &
+  \Default{0} &
+  Specifies that max pic dimensions are used in variable calculations.
+  \\
+  \Option{SEIPRILog2UnitSize} &
+  \Default{0} &
+  Specifies a unit size used in variable calculations for the region parameters.
+  \\
+  \Option{SEIPRIRegionSizeLenMinus1} &
+  \Default{0} &
+  Specifies the number of bits minus 1 used to signal region top-left offsets and region dimensions.
+  \\
+  \Option{SEIPRIRegionIdPresentFlag} &
+  \Default{0} &
+  Specifies whether region IDs are signalled.
+  \\
+  \Option{SEIPRITargetPicParamsPresentFlag} &
+  \Default{0} &
+  pecifies whether pri_target_region_top_left_x[ i ], pri_target_region_top_left_y[ i ], pri_target_pic_width_minus1, and pri_target_pic_height_minus1 are signalled.
+  \\
+  \Option{SEIPRITargetPicWidthMinus1} &
+  \Default{0} &
+  Target output picture width minus 1.
+  \\
+  \Option{SEIPRITargetPicHeightMinus1} &
+  \Default{0} &
+  Target output picture height minus 1.
+  \\
+  \Option{SEIPRINumResamplingRatiosMinus1} &
+  \Default{0} &
+  Specifies the number resampling ratios minus 1 that are signalled.
+  \\
+  \Option{SEIPRIResamplingWidthNumMinus1} &
+  \Default{""} &
+  Specifies a list of numerators minus 1 values for width resampling of the resampling ratio.
+  \\
+  \Option{SEIPRIResamplingWidthDenomMinus1} &
+  \Default{""} &
+  Specifies a list of denominators minus 1 values for width resampling of the resampling ratio.
+  \\
+  \Option{SEIPRIResamplingHeightNumMinus1} &
+  \Default{""} &
+  Specifies a list of numerators minus 1 values for height resampling of the resampling ratio.
+  \\
+  \Option{SEIPRIResamplingHeightDenomMinus1} &
+  \Default{""} &
+  Specifies a list of denominators minus 1 values for height resampling of the resampling ratio.
+  \\
+  \Option{SEIPRIRegionId} &
+  \Default{""} &
+  Specifies a list of IDs for the regions.
+  \\
+  \Option{SEIPRIRegionTopLeftInUnitsX} &
+  \Default{""} &
+  Specifies a list of horizontal top left positions for the regions.
+  \\
+  \Option{SEIPRIRegionTopLeftInUnitsY} &
+  \Default{""} &
+  Specifies a list of vertical top left positions for the regions.
+  \\
+  \Option{SEIPRIRegionWidthInUnitsMinus1} &
+  \Default{""} &
+  Specifies a list of widths minus 1 in units for the regions.
+  \\
+  \Option{SEIPRIRegionHeightInUnitsMinus1} &
+  \Default{""} &
+  Specifies a list of heights minus 1 in units for the regions.
+  \\
+  \Option{SEIPRIResamplingRatioIdx} &
+  \Default{""} &
+  Specifies a list of resampling ration indices for the regions.
+  \\
+  \Option{SEIPRITargetRegionTopLeftX} &
+  \Default{""} &
+  Specifies a list of horizontal top left postions in units of luma samples for the regions in reconstructed target picture.
+  \\
+  \Option{SEIPRITargetRegionTopLeftY} &
+  \Default{""} &
+  Specifies a list of vertical top left postions in units of luma samples for the regions in reconstructed target picture.
+  \\
+\end{OptionTableNoShorthand}
 
 %\Option{SEITimeCode} &
 %\Default{false} &
@@ -6669,6 +6768,12 @@ When a non-empty file name is specified, object mask information using the decod
 If no value is specified, the SEI message will not be output.
 \\
 
+\Option{SEIPackedRegionsInfoFilename} &
+%\ShortOption{\None} &
+\Default{\NotSet} &
+Packed regions info output file name. If empty, no object information will be saved.
+\\
+
 \end{OptionTableNoShorthand}
 
 
diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp
index 81882dcf14d7af643882c8aaa0181e1cf1a3cfd8..bb940b8fc813fcc2a9ccf19cd74ecb08cabf9074 100644
--- a/source/App/DecoderApp/DecApp.cpp
+++ b/source/App/DecoderApp/DecApp.cpp
@@ -158,6 +158,18 @@ uint32_t DecApp::decode()
   }
 #endif
 
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  if (!m_packedRegionsInfoSEIFileName.empty())
+  {
+    std::ofstream ofile(m_packedRegionsInfoSEIFileName.c_str());
+    if (!ofile.good() || !ofile.is_open())
+    {
+      fprintf(stderr, "\nUnable to open file '%s' for writing packed regions info SEI\n", m_packedRegionsInfoSEIFileName.c_str());
+      exit(EXIT_FAILURE);
+    }
+  }
+#endif
+
   // main decoder loop
   bool loopFiltered[MAX_VPS_LAYERS] = { false };
 
@@ -1195,7 +1207,21 @@ void DecApp::xWriteOutput( PicList* pcListPic, uint32_t tId )
         {
           const Window &conf = pcPic->getConformanceWindow();
           ChromaFormat  chromaFormatIdc = pcPic->m_chromaFormatIdc;
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+          if (pcPic->m_priProcess.m_enabled && pcPic->m_priProcess.m_targetPicWidth > 0 && pcPic->m_priProcess.m_targetPicHeight > 0)
+          {
+            PelStorage outPic;
+            const Area a = Area( Position(0, 0), Size(pcPic->m_priProcess.m_targetPicWidth, pcPic->m_priProcess.m_targetPicHeight) );
+            outPic.create( chromaFormatIdc, a, 0 );
+            pcPic->m_priProcess.reconstruct(pcPic->getRecoBuf(), outPic, *pcPic->cs->sps, *pcPic->cs->pps);
+            m_cVideoIOYuvReconFile[pcPic->layerId].write(
+              outPic.get(COMPONENT_Y).width, outPic.get(COMPONENT_Y).height, outPic, m_outputColourSpaceConvert,
+              m_packedYUVMode, 0, 0, 0, 0, ChromaFormat::UNDEFINED, m_clipOutputVideoToRec709Range);
+          }
+          else if( m_upscaledOutput )
+#else
           if( m_upscaledOutput )
+#endif
           {
             const SPS* sps = pcPic->cs->sps;
             m_cVideoIOYuvReconFile[pcPic->layerId].writeUpscaledPicture(
@@ -1311,6 +1337,12 @@ void DecApp::xWriteOutput( PicList* pcListPic, uint32_t tId )
         {
           xOutputObjectMaskInfos(pcPic);
         }
+#endif
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+        if (!m_packedRegionsInfoSEIFileName.empty())
+        {
+          xOutputPackedRegionsInfo(pcPic);
+        }
 #endif
         // update POC of display order
         m_iPOCLastDisplay = pcPic->getPOC();
@@ -1437,7 +1469,21 @@ void DecApp::xFlushOutput( PicList* pcListPic, const int layerId )
           {
             const Window &conf = pcPic->getConformanceWindow();
             ChromaFormat  chromaFormatIdc = pcPic->m_chromaFormatIdc;
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+            if (pcPic->m_priProcess.m_enabled && pcPic->m_priProcess.m_targetPicWidth > 0 && pcPic->m_priProcess.m_targetPicHeight > 0)
+            {
+              PelStorage outPic;
+              const Area a = Area( Position(0, 0), Size(pcPic->m_priProcess.m_targetPicWidth, pcPic->m_priProcess.m_targetPicHeight) );
+              outPic.create( chromaFormatIdc, a, 0 );
+              pcPic->m_priProcess.reconstruct(pcPic->getRecoBuf(), outPic, *pcPic->cs->sps, *pcPic->cs->pps);
+              m_cVideoIOYuvReconFile[pcPic->layerId].write(
+                outPic.get(COMPONENT_Y).width, outPic.get(COMPONENT_Y).height, outPic, m_outputColourSpaceConvert,
+                m_packedYUVMode, 0, 0, 0, 0, ChromaFormat::UNDEFINED, m_clipOutputVideoToRec709Range);
+            }
+            else if( m_upscaledOutput )
+#else
             if( m_upscaledOutput )
+#endif
             {
               const SPS* sps = pcPic->cs->sps;
               m_cVideoIOYuvReconFile[pcPic->layerId].writeUpscaledPicture(
@@ -1553,7 +1599,13 @@ void DecApp::xFlushOutput( PicList* pcListPic, const int layerId )
             xOutputObjectMaskInfos(pcPic);
           }
 #endif
-        // update POC of display order
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+          if (!m_packedRegionsInfoSEIFileName.empty())
+          {
+            xOutputPackedRegionsInfo(pcPic);
+          }
+#endif
+          // update POC of display order
         m_iPOCLastDisplay = pcPic->getPOC();
 
         // erase non-referenced picture in the reference picture list after display
@@ -1859,6 +1911,66 @@ void DecApp::xOutputObjectMaskInfos(Picture* pcPic)
 }
 #endif
 
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+void DecApp::xOutputPackedRegionsInfo(Picture* pcPic)
+{
+  SEIMessages seis = getSeisByType(pcPic->SEIs, SEI::PayloadType::PACKED_REGIONS_INFO);
+  if (!seis.empty())
+  {
+    const SEIPackedRegionsInfo& sei = *((SEIPackedRegionsInfo*)seis.front());
+    FILE* fp = fopen(m_packedRegionsInfoSEIFileName.c_str(), "a");
+    if (fp == nullptr)
+    {
+      std::cout << "Not able to open file for writing packed regions info SEI messages" << std::endl;
+    }
+    else
+    {
+      fprintf(fp, "SEIPRICancelFlag : %d\n", sei.m_cancelFlag);
+      fprintf(fp, "SEIPRIPersistenceFlag : %d\n", sei.m_persistenceFlag);
+      fprintf(fp, "SEIPRINumRegionsMinus1 : %d\n", sei.m_numRegionsMinus1);
+      fprintf(fp, "SEIPRIUseMaxDimensionsFlag : %d\n", sei.m_useMaxDimensionsFlag);
+      fprintf(fp, "SEIPRILog2UnitSize : %d\n", sei.m_log2UnitSize);
+      fprintf(fp, "SEIPRIRegionSizeLenMinus1 : %d\n", sei.m_regionSizeLenMinus1);
+      fprintf(fp, "SEIPRIRegionIdPresentFlag : %d\n", sei.m_regionIdPresentFlag);
+      fprintf(fp, "SEIPRITargetPicParamsPresentFlag : %d\n", sei.m_targetPicParamsPresentFlag);
+      if (sei.m_targetPicParamsPresentFlag)
+      {
+        fprintf(fp, "SEIPRITargetPicWidthMinus1 : %d\n", sei.m_targetPicWidthMinus1);
+        fprintf(fp, "SEIPRITargetPicHeightMinus1 : %d\n", sei.m_targetPicHeightMinus1);
+      }
+      fprintf(fp, "SEIPRINumResamplingRatiosMinus1 : %d\n", sei.m_numResamplingRatiosMinus1);
+      xOutputPackedRegionsInfoVector(fp, "SEIPRIResamplingWidthNumMinus1 :", sei.m_resamplingWidthNumMinus1);
+      xOutputPackedRegionsInfoVector(fp, "SEIPRIResamplingWidthDenomMinus1 :", sei.m_resamplingWidthDenomMinus1);
+      xOutputPackedRegionsInfoVector(fp, "SEIPRIResamplingHeightNumMinus1 :", sei.m_resamplingHeightNumMinus1);
+      xOutputPackedRegionsInfoVector(fp, "SEIPRIResamplingHeightDenomMinus1 :", sei.m_resamplingHeightDenomMinus1);
+      xOutputPackedRegionsInfoVector(fp, "SEIPRIRegionId :", sei.m_regionId);
+      xOutputPackedRegionsInfoVector(fp, "SEIPRIRegionTopLeftInUnitsX :", sei.m_regionTopLeftInUnitsX);
+      xOutputPackedRegionsInfoVector(fp, "SEIPRIRegionTopLeftInUnitsY :", sei.m_regionTopLeftInUnitsY);
+      xOutputPackedRegionsInfoVector(fp, "SEIPRIRegionWidthInUnitsMinus1 :", sei.m_regionWidthInUnitsMinus1);
+      xOutputPackedRegionsInfoVector(fp, "SEIPRIRegionHeightInUnitsMinus1 :", sei.m_regionHeightInUnitsMinus1);
+      xOutputPackedRegionsInfoVector(fp, "SEIPRIResamplingRatioIdx :", sei.m_resamplingRatioIdx);
+      if (sei.m_targetPicParamsPresentFlag)
+      {
+        xOutputPackedRegionsInfoVector(fp, "SEIPRITargetRegionTopLeftX :", sei.m_targetRegionTopLeftX);
+        xOutputPackedRegionsInfoVector(fp, "SEIPRITargetRegionTopLeftY :", sei.m_targetRegionTopLeftY);
+      }
+      fclose(fp);
+    }
+  }
+}
+
+void DecApp::xOutputPackedRegionsInfoVector(FILE* fp, const char* paramName, const std::vector<uint32_t>& l)
+{
+  fprintf(fp, "%s", paramName);
+  for (auto it : l)
+  {
+    fprintf(fp, " %d", it);
+  }
+  fprintf(fp, "\n");
+}
+
+#endif
+
 /** \param nalu Input nalu to check whether its LayerId is within targetDecLayerIdSet
  */
 bool DecApp::xIsNaluWithinTargetDecLayerIdSet( const InputNALUnit* nalu ) const
diff --git a/source/App/DecoderApp/DecApp.h b/source/App/DecoderApp/DecApp.h
index 68be62618c8d5e850e8a51d838d1482a1037693a..59846858e24206da8ae938b0ad15b4a340af1ae8 100644
--- a/source/App/DecoderApp/DecApp.h
+++ b/source/App/DecoderApp/DecApp.h
@@ -138,6 +138,10 @@ private:
 #if JVET_AF0088_OMI_SEI
   void xOutputObjectMaskInfos(Picture* pcPic);
 #endif
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  void xOutputPackedRegionsInfo(Picture* pcPic);
+  void xOutputPackedRegionsInfoVector(FILE* fp, const char* paramName, const std::vector<uint32_t>& v);
+#endif
 };
 
 //! \}
diff --git a/source/App/DecoderApp/DecAppCfg.cpp b/source/App/DecoderApp/DecAppCfg.cpp
index f18ca29b14a29245f587f4d88d548113b008b794..5a332537ff8263a225acb4ccd503497eebca7d79 100644
--- a/source/App/DecoderApp/DecAppCfg.cpp
+++ b/source/App/DecoderApp/DecAppCfg.cpp
@@ -108,6 +108,9 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] )
   ("OutputDecodedSEIMessagesFilename", m_outputDecodedSEIMessagesFilename, std::string(""), "When non empty, output decoded SEI messages to the indicated file. If file is '-', then output to stdout\n")
 #if JVET_S0257_DUMP_360SEI_MESSAGE
   ("360DumpFile",               m_outputDecoded360SEIMessagesFilename, std::string(""), "When non empty, output decoded 360 SEI messages to the indicated file.\n")
+#endif
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  ("SEIPackedRegionsInfoFilename", m_packedRegionsInfoSEIFileName,     std::string(""), "Packed regions info output file name. If empty, no object information will be saved\n")
 #endif
   ("ClipOutputVideoToRec709Range",      m_clipOutputVideoToRec709Range,  false,   "If true then clip output video to the Rec. 709 Range on saving")
   ("PYUV",                      m_packedYUVMode,                       false,      "If true then output 10-bit and 12-bit YUV data as 5-byte and 3-byte (respectively) packed YUV data. Ignored for interlaced output.")
diff --git a/source/App/DecoderApp/DecAppCfg.h b/source/App/DecoderApp/DecAppCfg.h
index 9a4171e9e2c4226252ab065dfba7fbf0519314ea..5cdb8e3e8c51cfad17021a56c0b0253c75ce51ed 100644
--- a/source/App/DecoderApp/DecAppCfg.h
+++ b/source/App/DecoderApp/DecAppCfg.h
@@ -86,6 +86,9 @@ protected:
 #if JVET_S0257_DUMP_360SEI_MESSAGE
   std::string   m_outputDecoded360SEIMessagesFilename;   ///< filename to output decoded 360 SEI messages to.
 #endif
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  std::string   m_packedRegionsInfoSEIFileName;       ///< packed regions file name
+#endif
 
   std::string   m_shutterIntervalPostFileName;        ///< output Post Filtering file name
 #if JVET_AF0167_MULTI_PLANE_IMAGE_INFO_SEI
diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 0a6327d1ce64bb0d63be86f9415e93b6dcabbff1..c38efff57cf29ce5056aa73163c9fa2e1eaea758 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -45,6 +45,9 @@
 #include "EncApp.h"
 #include "EncoderLib/AnnexBwrite.h"
 #include "EncoderLib/EncLibCommon.h"
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+#include "CommonLib/SEIPackedRegionsInfoProcess.h"
+#endif
 
 //! \ingroup EncoderApp
 //! \{
@@ -1411,7 +1414,33 @@ void EncApp::xInitLibCfg( int layerIdx )
   m_cEncLib.setPoSEIProcessingOrder                              (m_poSEIProcessingOrder);
   m_cEncLib.setPoSEIPrefixByte                                   (m_poSEIPrefixByte);
 
-
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  m_cEncLib.setPriSEIEnabled(m_priSEIEnabled);
+  m_cEncLib.setPriSEICancelFlag(m_priSEICancelFlag);
+  m_cEncLib.setPriSEIPersistenceFlag(m_priSEIPersistenceFlag);
+  m_cEncLib.setPriSEINumRegionsMinus1(m_priSEINumRegionsMinus1);
+  m_cEncLib.setPriSEIUseMaxDimensionsFlag(m_priSEIUseMaxDimensionsFlag);
+  m_cEncLib.setPriSEILog2UnitSize(m_priSEILog2UnitSize);
+  m_cEncLib.setPriSEIRegionSizeLenMinus1(m_priSEIRegionSizeLenMinus1);
+  m_cEncLib.setPriSEIRegionIdPresentFlag(m_priSEIRegionIdPresentFlag);
+  m_cEncLib.setPriSEITargetPicParamsPresentFlag(m_priSEITargetPicParamsPresentFlag);
+  m_cEncLib.setPriSEITargetPicWidthMinus1(m_priSEITargetPicWidthMinus1);
+  m_cEncLib.setPriSEITargetPicHeightMinus1(m_priSEITargetPicHeightMinus1);
+  m_cEncLib.setPriSEINumResamplingRatiosMinus1(m_priSEINumResamplingRatiosMinus1);
+  m_cEncLib.setPriSEIResamplingWidthNumMinus1(m_priSEIResamplingWidthNumMinus1);
+  m_cEncLib.setPriSEIResamplingWidthDenomMinus1(m_priSEIResamplingWidthDenomMinus1);
+  m_cEncLib.setPriSEIFixedAspectRatioFlag(m_priSEIFixedAspectRatioFlag);
+  m_cEncLib.setPriSEIResamplingHeightNumMinus1(m_priSEIResamplingHeightNumMinus1);
+  m_cEncLib.setPriSEIResamplingHeightDenomMinus1(m_priSEIResamplingHeightDenomMinus1);
+  m_cEncLib.setPriSEIRegionId(m_priSEIRegionId);
+  m_cEncLib.setPriSEIRegionTopLeftInUnitsX(m_priSEIRegionTopLeftInUnitsX);
+  m_cEncLib.setPriSEIRegionTopLeftInUnitsY(m_priSEIRegionTopLeftInUnitsY);
+  m_cEncLib.setPriSEIRegionWidthInUnitsMinus1(m_priSEIRegionWidthInUnitsMinus1);
+  m_cEncLib.setPriSEIRegionHeightInUnitsMinus1(m_priSEIRegionHeightInUnitsMinus1);
+  m_cEncLib.setPriSEIResamplingRatioIdx(m_priSEIResamplingRatioIdx);
+  m_cEncLib.setPriSEITargetRegionTopLeftX(m_priSEITargetRegionTopLeftX);
+  m_cEncLib.setPriSEITargetRegionTopLeftY(m_priSEITargetRegionTopLeftY);
+#endif
 
   m_cEncLib.setPostFilterHintSEIEnabled(m_postFilterHintSEIEnabled);
   m_cEncLib.setPostFilterHintSEICancelFlag(m_postFilterHintSEICancelFlag);
@@ -1999,7 +2028,11 @@ void EncApp::xWriteOutput(int numEncoded, std::list<PelUnitBuf *> &recBufList)
         }
         else
         {
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+          ppsID = ((sps.getMaxPicWidthInLumaSamples() != pcPicYuvRec->get(COMPONENT_Y).width || sps.getMaxPicHeightInLumaSamples() != pcPicYuvRec->get(COMPONENT_Y).height) && !m_explicitScalingWindowEnabled) ? (m_resChangeInClvsEnabled || m_priSEIEnabled) ? (ENC_PPS_ID_RPR + layerId) : layerId : layerId;
+#else
           ppsID = ((sps.getMaxPicWidthInLumaSamples() != pcPicYuvRec->get(COMPONENT_Y).width || sps.getMaxPicHeightInLumaSamples() != pcPicYuvRec->get(COMPONENT_Y).height) && !m_explicitScalingWindowEnabled) ? m_resChangeInClvsEnabled ? (ENC_PPS_ID_RPR + layerId) : layerId : layerId;
+#endif
         }
         const PPS& pps = *m_cEncLib.getPPS(ppsID);
         if( m_cEncLib.isResChangeInClvsEnabled() && m_cEncLib.getUpscaledOutput() )
@@ -2008,6 +2041,19 @@ void EncApp::xWriteOutput(int numEncoded, std::list<PelUnitBuf *> &recBufList)
                                                       m_cEncLib.getUpscaledOutput(), ChromaFormat::UNDEFINED,
                                                       m_clipOutputVideoToRec709Range, m_upscaleFilterForDisplay);
         }
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+        else if (m_cEncLib.getPriSEIEnabled() && m_cEncLib.getPriSEITargetPicParamsPresentFlag())
+        {
+          const PPS& pps = *m_cEncLib.getPPS(ppsID);
+          PelStorage outPic;
+          const Area a = Area( Position(0, 0), Size(m_cEncLib.getPriSEITargetPicWidthMinus1() + 1, m_cEncLib.getPriSEITargetPicHeightMinus1() + 1) );
+          outPic.create( pcPicYuvRec->chromaFormat, a, m_cEncLib.getMaxCUWidth() );
+          m_cEncLib.getPriProcess().reconstruct(*pcPicYuvRec, outPic, sps, pps);
+          m_cVideoIOYuvReconFile.write(
+            outPic.get(COMPONENT_Y).width, outPic.get(COMPONENT_Y).height, outPic, ipCSC,
+            m_packedYUVMode, 0, 0, 0, 0, ChromaFormat::UNDEFINED, m_clipOutputVideoToRec709Range);
+        }
+#endif
         else
         {
           Window confWindowPPS = pps.getConformanceWindow();
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index 36fedf12bff3c2e425adafc842f7e1c75ba0b676..a2a6096bc3abfeb8a4ae85bdaaee2a14d9d482ea 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -785,6 +785,20 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   SMultiValueInput<uint32_t>  cfg_crSEIRectWidthInUnitsMinus1(0, 65535, 0, 4096);
   SMultiValueInput<uint32_t>  cfg_crSEIRectHeightInUnitsMinus1(0, 65535, 0, 4096);
 #endif
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  SMultiValueInput<uint32_t> cfg_priSEIResamplingWidthNumMinus1(0, 65535, 0, std::numeric_limits<uint32_t>::max());
+  SMultiValueInput<uint32_t> cfg_priSEIResamplingWidthDenomMinus1(0, 65535, 0, std::numeric_limits<uint32_t>::max());
+  SMultiValueInput<uint32_t> cfg_priSEIResamplingHeightNumMinus1(0, std::numeric_limits<uint32_t>::max() - 1, 0, std::numeric_limits<uint32_t>::max());
+  SMultiValueInput<uint32_t> cfg_priSEIResamplingHeightDenomMinus1(0, std::numeric_limits<uint32_t>::max() - 1, 0, std::numeric_limits<uint32_t>::max());
+  SMultiValueInput<uint32_t> cfg_priSEIRegionId(0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max());
+  SMultiValueInput<uint32_t> cfg_priSEIRegionTopLeftInUnitsX(0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max());
+  SMultiValueInput<uint32_t> cfg_priSEIRegionTopLeftInUnitsY(0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max());
+  SMultiValueInput<uint32_t> cfg_priSEIRegionWidthInUnitsMinus1(0, std::numeric_limits<uint32_t>::max() - 1, 0, std::numeric_limits<uint32_t>::max());
+  SMultiValueInput<uint32_t> cfg_priSEIRegionHeightInUnitsMinus1(0, std::numeric_limits<uint32_t>::max() - 1, 0, std::numeric_limits<uint32_t>::max());
+  SMultiValueInput<uint32_t> cfg_priSEIResamplingRatioIdx(0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max());
+  SMultiValueInput<uint32_t> cfg_priSEITargetRegionTopLeftX(0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max());
+  SMultiValueInput<uint32_t> cfg_priSEITargetRegionTopLeftY(0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max());
+#endif
 #if ENABLE_TRACING
   std::string sTracingRule;
   std::string sTracingFile;
@@ -1710,6 +1724,32 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ("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
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  ("SEIPRIEnabled",                                   m_priSEIEnabled,                                   false, "Specifies whether packet regions info SEI is enabled")
+  ("SEIPRICancelFlag",                                m_priSEICancelFlag,                                false, "Specifies the persistence of any previous packed regions info SEI message in output order")
+  ("SEIPRIPersistenceFlag",                           m_priSEIPersistenceFlag,                            true, "Specifies the persistence of the packed regions info SEI message for the current layer")
+  ("SEIPRINumRegionsMinus1",                          m_priSEINumRegionsMinus1,                             0u, "Specifies the number of regions minus 1 for which information is signalled")
+  ("SEIPRIUseMaxDimensionsFlag",                      m_priSEIUseMaxDimensionsFlag,                      false, "Specifies that max pic dimensions are used in variable calculations")
+  ("SEIPRILog2UnitSize",                              m_priSEILog2UnitSize,                                 0u, "Specifies a unit size used in variable calculations for the region parameters")
+  ("SEIPRIRegionSizeLenMinus1",                       m_priSEIRegionSizeLenMinus1,                         12u, "Specifies the number of bits minus 1 used to signal region top left offsets and region dimensions")
+  ("SEIPRIRegionIdPresentFlag",                       m_priSEIRegionIdPresentFlag,                       false, "Specifies whether region IDs are signalled")
+  ("SEIPRITargetPicParamsPresentFlag",                m_priSEITargetPicParamsPresentFlag,                false, "Specifies whether pri_target_region_top_left_x[ i ], pri_target_region_top_left_y[ i ], pri_target_pic_width_minus1, and pri_target_pic_height_minus1 are signalled")
+  ("SEIPRITargetPicWidthMinus1",                      m_priSEITargetPicWidthMinus1,                         0u, "Target output picture width minus 1")
+  ("SEIPRITargetPicHeightMinus1",                     m_priSEITargetPicHeightMinus1,                        0u, "Target output picture height minus 1")
+  ("SEIPRINumResamplingRatiosMinus1",                 m_priSEINumResamplingRatiosMinus1,                    0u, "Specifies the number resampling ratios minus 1 that are signalled")
+  ("SEIPRIResamplingWidthNumMinus1",                  cfg_priSEIResamplingWidthNumMinus1, cfg_priSEIResamplingWidthNumMinus1, "Specifies a list of numerators minus 1 values for width resampling of the resampling ratio")
+  ("SEIPRIResamplingWidthDenomMinus1",                cfg_priSEIResamplingWidthDenomMinus1, cfg_priSEIResamplingWidthDenomMinus1, "Specifies a list of denominators minus 1 values for width resampling of the resampling ratio")
+  ("SEIPRIResamplingHeightNumMinus1",                 cfg_priSEIResamplingHeightNumMinus1, cfg_priSEIResamplingHeightNumMinus1, "Specifies a list of numerators minus 1 values for height resampling of the resampling ratio")
+  ("SEIPRIResamplingHeightDenomMinus1",               cfg_priSEIResamplingHeightDenomMinus1, cfg_priSEIResamplingHeightDenomMinus1, "Specifies a list of denominators minus 1 values for height resampling of the resampling ratio")
+  ("SEIPRIRegionId",                                  cfg_priSEIRegionId, cfg_priSEIRegionId,                   "Specifies a list of IDs for the regions")
+  ("SEIPRIRegionTopLeftInUnitsX",                     cfg_priSEIRegionTopLeftInUnitsX, cfg_priSEIRegionTopLeftInUnitsX, "Specifies a list of horizontal top left positions for the regions")
+  ("SEIPRIRegionTopLeftInUnitsY",                     cfg_priSEIRegionTopLeftInUnitsY, cfg_priSEIRegionTopLeftInUnitsY, "Specifies a list of vertical top left positions for the regions")
+  ("SEIPRIRegionWidthInUnitsMinus1",                  cfg_priSEIRegionWidthInUnitsMinus1, cfg_priSEIRegionWidthInUnitsMinus1, "Specifies a list of widths minus 1 in units for the regions")
+  ("SEIPRIRegionHeightInUnitsMinus1",                 cfg_priSEIRegionHeightInUnitsMinus1, cfg_priSEIRegionHeightInUnitsMinus1, "Specifies a list of heights minus 1 in units for the regions")
+  ("SEIPRIResamplingRatioIdx",                        cfg_priSEIResamplingRatioIdx, cfg_priSEIResamplingRatioIdx, "Specifies a list of resampling ration indices for the regions")
+  ("SEIPRITargetRegionTopLeftX",                      cfg_priSEITargetRegionTopLeftX, cfg_priSEITargetRegionTopLeftX, "Specifies a list of horizontal top left postions in units of luma samples for the regions in reconstructed target picture")
+  ("SEIPRITargetRegionTopLeftY",                      cfg_priSEITargetRegionTopLeftY, cfg_priSEITargetRegionTopLeftY, "Specifies a list of vertical top left postions in units of luma samples for the regions in reconstructed target picture")
+#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." )
@@ -3898,6 +3938,81 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   }
 #endif
 
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  if (m_priSEIEnabled)
+  {
+    CHECK(m_priSEICancelFlag, "SEIPRICancelFlag must be 0 in this implementation");
+    CHECK(!m_priSEIPersistenceFlag, "SEIPRIPersistenceFlag must be 1 in this implementation");
+    CHECK(cfg_priSEIResamplingWidthNumMinus1.values.size() != (m_priSEINumResamplingRatiosMinus1 + 1), "Number of elements in SEIRPRIesamplingWidthNumMinus1 must be equal to SEIPRINumResamplingRatiosMinus1 + 1");
+    CHECK(cfg_priSEIResamplingWidthDenomMinus1.values.size() != (m_priSEINumResamplingRatiosMinus1 + 1), "Number of elements in SEIPRIResamplingWidthNumMinus1 must be equal to SEIPRIResamplingWidthDenomMinus1 + 1");
+    CHECK(cfg_priSEIResamplingHeightNumMinus1.values.size() != (m_priSEINumResamplingRatiosMinus1 + 1), "Number of elements in SEIPRIResamplingHeightNumMinus1 must be equal to SEIPRINumResamplingRatiosMinus1 + 1");
+    CHECK(cfg_priSEIResamplingHeightDenomMinus1.values.size() != (m_priSEINumResamplingRatiosMinus1 + 1), "Number of elements in SEIPRIResamplingHeightNumMinus1 must be equal to SEIPRIResamplingWidthDenomMinus1 + 1");
+    if (m_priSEINumResamplingRatiosMinus1 > 0)
+    {
+      m_priSEIResamplingWidthNumMinus1 = cfg_priSEIResamplingWidthNumMinus1.values;
+      m_priSEIResamplingWidthDenomMinus1 = cfg_priSEIResamplingWidthDenomMinus1.values;
+      m_priSEIResamplingHeightNumMinus1 = cfg_priSEIResamplingHeightNumMinus1.values;
+      m_priSEIResamplingHeightDenomMinus1 = cfg_priSEIResamplingHeightDenomMinus1.values;
+      m_priSEIFixedAspectRatioFlag.resize(m_priSEINumResamplingRatiosMinus1 + 1);
+      for (uint32_t i = 1; i <= m_priSEINumResamplingRatiosMinus1; i++)
+      {
+        m_priSEIFixedAspectRatioFlag[i] =
+          m_priSEIResamplingWidthNumMinus1[i] == m_priSEIResamplingHeightNumMinus1[i] &&
+          m_priSEIResamplingWidthDenomMinus1[i] == m_priSEIResamplingHeightDenomMinus1[i];
+      }
+      // First entry has fixed values
+      m_priSEIResamplingWidthNumMinus1[0] = 0;
+      m_priSEIResamplingWidthDenomMinus1[0] = 0;
+      m_priSEIFixedAspectRatioFlag[0] = true;
+      m_priSEIResamplingHeightNumMinus1[0] = 0;
+      m_priSEIResamplingHeightDenomMinus1[0] = 0;
+    }
+    else
+    {
+      m_priSEIResamplingWidthNumMinus1 = {0};
+      m_priSEIResamplingWidthDenomMinus1 = {0};
+      m_priSEIFixedAspectRatioFlag = {true};
+      m_priSEIResamplingHeightNumMinus1 = {0};
+      m_priSEIResamplingHeightDenomMinus1 = {0};
+    }
+
+    if (m_priSEIRegionIdPresentFlag)
+    {
+      CHECK(cfg_priSEIRegionId.values.size() != (m_priSEINumRegionsMinus1 + 1), "Number of elements in SEIPRIRegionId must be equal to SEIPRINumRegionsMinus1 + 1");
+      std::vector<uint32_t> tmpVec = cfg_priSEIRegionId.values;
+      std::sort(tmpVec.begin(), tmpVec.end());
+      auto it = std::unique(tmpVec.begin(), tmpVec.end());
+      CHECK(it != tmpVec.end(), "SEIRegionId values must be unique");
+    }
+    CHECK(cfg_priSEIRegionTopLeftInUnitsX.values.size() != (m_priSEINumRegionsMinus1 + 1), "Number of elements in SEIPRIRegionTopLeftInUnitsX must be equal to SEIPRINumRegionsMinus1 + 1");
+    CHECK(cfg_priSEIRegionTopLeftInUnitsY.values.size() != (m_priSEINumRegionsMinus1 + 1), "Number of elements in SEIPRIRegionTopLeftInUnitsY must be equal to SEIPRINumRegionsMinus1 + 1");
+    CHECK(cfg_priSEIRegionWidthInUnitsMinus1.values.size() != (m_priSEINumRegionsMinus1 + 1), "Number of elements in SEIPRIRegionWidthInUnitsMinus1 must be equal to SEIPRINumRegionsMinus1 + 1");
+    CHECK(cfg_priSEIRegionHeightInUnitsMinus1.values.size() != (m_priSEINumRegionsMinus1 + 1), "Number of elements in SEIPRIRegionHeightInUnitsMinus1 must be equal to SEIPRINumRegionsMinus1 + 1");
+    if (m_priSEINumResamplingRatiosMinus1 > 0)
+    {
+      CHECK(cfg_priSEIResamplingRatioIdx.values.size() != (m_priSEINumRegionsMinus1 + 1), "Number of elements in SEIPRIResamplingRatioIdx must be equal to SEIPRINumRegionsMinus1 + 1");
+    }
+    CHECK(cfg_priSEITargetRegionTopLeftX.values.size() != (m_priSEINumRegionsMinus1 + 1), "Number of elements in SEIPRITargetRegionTopLeftX must be equal to SEIPRINumRegionsMinus1 + 1");
+    CHECK(cfg_priSEITargetRegionTopLeftY.values.size() != (m_priSEINumRegionsMinus1 + 1), "Number of elements in SEIPRITargetRegionTopLeftY must be equal to SEIPRINumRegionsMinus1 + 1");
+
+    m_priSEIRegionId = cfg_priSEIRegionId.values;
+    m_priSEIRegionTopLeftInUnitsX = cfg_priSEIRegionTopLeftInUnitsX.values;
+    m_priSEIRegionTopLeftInUnitsY = cfg_priSEIRegionTopLeftInUnitsY.values;
+    m_priSEIRegionWidthInUnitsMinus1 = cfg_priSEIRegionWidthInUnitsMinus1.values;
+    m_priSEIRegionHeightInUnitsMinus1 = cfg_priSEIRegionHeightInUnitsMinus1.values;
+    if (m_priSEINumResamplingRatiosMinus1 > 0)
+    {
+      m_priSEIResamplingRatioIdx = cfg_priSEIResamplingRatioIdx.values;
+    }
+    else
+    {
+      m_priSEIResamplingRatioIdx = {0};
+    }
+    m_priSEITargetRegionTopLeftX = cfg_priSEITargetRegionTopLeftX.values;
+    m_priSEITargetRegionTopLeftY = cfg_priSEITargetRegionTopLeftY.values;
+  }
+#endif
+
   // check validity of input parameters
   if( xCheckParameter() )
   {
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index 073c88df79c487e5497de7feb153a646e88ce10c..7e58d22b7a515bd5447abecac2cd0eb59986ef1c 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -1137,6 +1137,34 @@ protected:
   std::string m_aiMarkerInfoData;
 #endif
 
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  bool     m_priSEIEnabled;
+  bool     m_priSEICancelFlag;
+  bool     m_priSEIPersistenceFlag;
+  uint32_t m_priSEINumRegionsMinus1;
+  bool     m_priSEIUseMaxDimensionsFlag;
+  uint32_t m_priSEILog2UnitSize;
+  uint32_t m_priSEIRegionSizeLenMinus1;
+  bool     m_priSEIRegionIdPresentFlag;
+  bool     m_priSEITargetPicParamsPresentFlag;
+  uint32_t m_priSEITargetPicWidthMinus1;
+  uint32_t m_priSEITargetPicHeightMinus1;
+  uint32_t m_priSEINumResamplingRatiosMinus1;
+  std::vector<uint32_t> m_priSEIResamplingWidthNumMinus1;
+  std::vector<uint32_t> m_priSEIResamplingWidthDenomMinus1;
+  std::vector<bool>     m_priSEIFixedAspectRatioFlag;
+  std::vector<uint32_t> m_priSEIResamplingHeightNumMinus1;
+  std::vector<uint32_t> m_priSEIResamplingHeightDenomMinus1;
+  std::vector<uint32_t> m_priSEIRegionId;
+  std::vector<uint32_t> m_priSEIRegionTopLeftInUnitsX;
+  std::vector<uint32_t> m_priSEIRegionTopLeftInUnitsY;
+  std::vector<uint32_t> m_priSEIRegionWidthInUnitsMinus1;
+  std::vector<uint32_t> m_priSEIRegionHeightInUnitsMinus1;
+  std::vector<uint32_t> m_priSEIResamplingRatioIdx;
+  std::vector<uint32_t> m_priSEITargetRegionTopLeftX;
+  std::vector<uint32_t> m_priSEITargetRegionTopLeftY;
+#endif
+
   // internal member functions
   bool  xCheckParameter ();                                   ///< check validity of configuration values
   void  xPrintParameter ();                                   ///< print configuration values
diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h
index b988f97ba1ebba5f003ffd10ccffbe3130f3085a..e2e7047b41b8a515a289e4dca8512cb46c2ac434 100644
--- a/source/Lib/CommonLib/Picture.h
+++ b/source/Lib/CommonLib/Picture.h
@@ -51,6 +51,9 @@
 #include "SEIColourTransform.h"
 #include <deque>
 #include "SEIFilmGrainSynthesizer.h"
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+#include "SEIPackedRegionsInfoProcess.h"
+#endif
 
 class SEI;
 class AQpLayer;
@@ -273,6 +276,9 @@ public:
 #endif
   std::deque<Slice*> slices;
   SEIMessages        SEIs;
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  SEIPackedRegionsInfoProcess m_priProcess;
+#endif
 
   uint32_t           getPicWidthInLumaSamples() const                                { return  getRecoBuf( COMPONENT_Y ).width; }
   uint32_t           getPicHeightInLumaSamples() const                               { return  getRecoBuf( COMPONENT_Y ).height; }
diff --git a/source/Lib/CommonLib/SEI.cpp b/source/Lib/CommonLib/SEI.cpp
index 90e103a96bbba8c1cbaa2ae789b91eee13a2ec6d..0cb0333ab2b9ce7a2dbd8000e2184f3d19fd95cf 100644
--- a/source/Lib/CommonLib/SEI.cpp
+++ b/source/Lib/CommonLib/SEI.cpp
@@ -1345,3 +1345,33 @@ SEIConstituentRectangles::SEIConstituentRectangles(const SEIConstituentRectangle
   m_rectTypeDescription = sei.m_rectTypeDescription;
 }
 #endif
+
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+SEIPackedRegionsInfo::SEIPackedRegionsInfo(SEIPackedRegionsInfo& sei)
+{
+  m_cancelFlag = sei.m_cancelFlag;
+  m_persistenceFlag = sei.m_persistenceFlag;
+  m_numRegionsMinus1 = sei.m_numRegionsMinus1;
+  m_useMaxDimensionsFlag = sei.m_useMaxDimensionsFlag;
+  m_log2UnitSize = sei.m_log2UnitSize;
+  m_regionSizeLenMinus1 = sei.m_regionSizeLenMinus1;
+  m_regionIdPresentFlag = sei.m_regionIdPresentFlag;
+  m_targetPicParamsPresentFlag = sei.m_targetPicParamsPresentFlag;
+  m_targetPicWidthMinus1 = sei.m_targetPicWidthMinus1;
+  m_targetPicHeightMinus1 = sei.m_targetPicHeightMinus1;
+  m_numResamplingRatiosMinus1 = sei.m_numResamplingRatiosMinus1;
+  m_resamplingWidthNumMinus1 = sei.m_resamplingWidthNumMinus1;
+  m_resamplingWidthDenomMinus1 = sei.m_resamplingWidthDenomMinus1;
+  m_fixedAspectRatioFlag = sei.m_fixedAspectRatioFlag;
+  m_resamplingHeightNumMinus1 = sei.m_resamplingHeightNumMinus1;
+  m_resamplingHeightDenomMinus1 = sei.m_resamplingHeightDenomMinus1;
+  m_regionId = sei.m_regionId;
+  m_regionTopLeftInUnitsX = sei.m_regionTopLeftInUnitsX;
+  m_regionTopLeftInUnitsY = sei.m_regionTopLeftInUnitsY;
+  m_regionWidthInUnitsMinus1 = sei.m_regionWidthInUnitsMinus1;
+  m_regionHeightInUnitsMinus1 = sei.m_regionHeightInUnitsMinus1;
+  m_resamplingRatioIdx = sei.m_resamplingRatioIdx;
+  m_targetRegionTopLeftX = sei.m_targetRegionTopLeftX;
+  m_targetRegionTopLeftY = sei.m_targetRegionTopLeftY;
+}
+#endif
diff --git a/source/Lib/CommonLib/SEI.h b/source/Lib/CommonLib/SEI.h
index acdc1077145ea2d203c3b12c801827b924861d86..a9bc7591ab797f26e44ac4262b84b53991489c02 100644
--- a/source/Lib/CommonLib/SEI.h
+++ b/source/Lib/CommonLib/SEI.h
@@ -119,6 +119,9 @@ public:
 #endif
 #if JVET_AH0162_CONSTITUENT_RECTANGLES
     CONSTITUENT_RECTANGLES, // payload_type value TBD
+#endif
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+    PACKED_REGIONS_INFO,
 #endif
   };
 
@@ -1622,3 +1625,51 @@ public:
   std::vector<std::string> m_rectTypeDescription;
 };
 #endif
+
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+class SEIPackedRegionsInfo : public SEI
+{
+public:
+  PayloadType payloadType() const { return PayloadType::PACKED_REGIONS_INFO; }
+  SEIPackedRegionsInfo()
+    : m_cancelFlag(false)
+    , m_persistenceFlag(false)
+    , m_numRegionsMinus1(0)
+    , m_useMaxDimensionsFlag(false)
+    , m_log2UnitSize(0)
+    , m_regionSizeLenMinus1(0)
+    , m_regionIdPresentFlag(false)
+    , m_targetPicParamsPresentFlag(false)
+    , m_targetPicWidthMinus1(0)
+    , m_targetPicHeightMinus1(0)
+    , m_numResamplingRatiosMinus1(0)
+  {}
+  SEIPackedRegionsInfo(SEIPackedRegionsInfo& sei);
+  virtual ~SEIPackedRegionsInfo() {}
+
+  bool     m_cancelFlag;
+  bool     m_persistenceFlag;
+  uint32_t m_numRegionsMinus1;
+  bool     m_useMaxDimensionsFlag;
+  uint32_t m_log2UnitSize;
+  uint32_t m_regionSizeLenMinus1;
+  bool     m_regionIdPresentFlag;
+  bool     m_targetPicParamsPresentFlag;
+  uint32_t m_targetPicWidthMinus1;
+  uint32_t m_targetPicHeightMinus1;
+  uint32_t m_numResamplingRatiosMinus1;
+  std::vector<uint32_t> m_resamplingWidthNumMinus1;
+  std::vector<uint32_t> m_resamplingWidthDenomMinus1;
+  std::vector<bool>     m_fixedAspectRatioFlag;
+  std::vector<uint32_t> m_resamplingHeightNumMinus1;
+  std::vector<uint32_t> m_resamplingHeightDenomMinus1;
+  std::vector<uint32_t> m_regionId;
+  std::vector<uint32_t> m_regionTopLeftInUnitsX;
+  std::vector<uint32_t> m_regionTopLeftInUnitsY;
+  std::vector<uint32_t> m_regionWidthInUnitsMinus1;
+  std::vector<uint32_t> m_regionHeightInUnitsMinus1;
+  std::vector<uint32_t> m_resamplingRatioIdx;
+  std::vector<uint32_t> m_targetRegionTopLeftX;
+  std::vector<uint32_t> m_targetRegionTopLeftY;
+};
+#endif
diff --git a/source/Lib/CommonLib/SEIPackedRegionsInfoProcess.cpp b/source/Lib/CommonLib/SEIPackedRegionsInfoProcess.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..95325ecdb681496ceb980368ebde7daa2aa5c3f1
--- /dev/null
+++ b/source/Lib/CommonLib/SEIPackedRegionsInfoProcess.cpp
@@ -0,0 +1,179 @@
+/* The copyright in this software is being made available under the BSD
+ * License, included below. This software may be subject to other third party
+ * and contributor rights, including patent rights, and no such rights are
+ * granted under this license.
+ *
+ * Copyright (c) 2010-2023, ITU/ISO/IEC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
+ *    be used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ /** \file     SEIPackedRegionsInfoProcess.cpp
+     \brief    Packed regions info SEI processing
+ */
+
+#include "SequenceParameterSet.h"
+#include "Picture.h"
+#include "SEIPackedRegionsInfoProcess.h"
+
+
+void SEIPackedRegionsInfoProcess::init(SEIPackedRegionsInfo& sei, const SPS& sps, uint32_t picWidth, uint32_t picHeight)
+{
+  m_enabled = true;
+  m_persistence = sei.m_persistenceFlag;
+  m_priUnitSize = 1 << sei.m_log2UnitSize;
+  m_picWidth = picWidth;
+  m_picHeight = picHeight;
+  m_maxPicWidth = sps.getMaxPicWidthInLumaSamples();
+  m_maxPicHeight = sps.getMaxPicHeightInLumaSamples();
+  m_targetPicWidth = 0;
+  m_targetPicHeight = 0;
+  if (sei.m_targetPicParamsPresentFlag)
+  {
+    m_targetPicWidth = sei.m_targetPicWidthMinus1 + 1;
+    m_targetPicHeight = sei.m_targetPicHeightMinus1 + 1;
+  }
+  m_bitDepthY = sps.getBitDepth(ChannelType::LUMA);
+  m_bitDepthC = sps.getBitDepth(ChannelType::CHROMA);
+  m_chromaFormat = sps.getChromaFormatIdc();
+  m_subWidthC = SPS::getWinUnitX(sps.getChromaFormatIdc());
+  m_subHeightC = SPS::getWinUnitY(sps.getChromaFormatIdc());
+
+  m_priNumRegions = sei.m_numRegionsMinus1 + 1;
+  m_priRegionTopLeftX.resize(sei.m_numRegionsMinus1 + 1);
+  m_priRegionTopLeftY.resize(sei.m_numRegionsMinus1 + 1);
+  m_priRegionWidth.resize(sei.m_numRegionsMinus1 + 1);
+  m_priRegionHeight.resize(sei.m_numRegionsMinus1 + 1);
+  m_priResampleWidthNum.resize(sei.m_numRegionsMinus1 + 1);
+  m_priResampleWidthDenom.resize(sei.m_numRegionsMinus1 + 1);
+  m_priResampleHeightNum.resize(sei.m_numRegionsMinus1 + 1);
+  m_priResampleHeightDenom.resize(sei.m_numRegionsMinus1 + 1);
+  m_priTargetRegionWidth.resize(sei.m_numRegionsMinus1 + 1);
+  m_priTargetRegionHeight.resize(sei.m_numRegionsMinus1 + 1);
+  m_priRegionId.resize(sei.m_numRegionsMinus1 + 1);
+
+  for (uint32_t i = 0; i <= sei.m_numRegionsMinus1; i++)
+  {
+    if (!sei.m_useMaxDimensionsFlag)
+    {
+      m_priRegionTopLeftX[i] = sei.m_regionTopLeftInUnitsX[i] * m_priUnitSize;
+      m_priRegionTopLeftY[i] = sei.m_regionTopLeftInUnitsY[i] * m_priUnitSize;
+      m_priRegionWidth[i] = (sei.m_regionWidthInUnitsMinus1[i] + 1) * m_priUnitSize;
+      m_priRegionHeight[i] = (sei.m_regionHeightInUnitsMinus1[i] + 1) * m_priUnitSize;
+    }
+    else
+    {
+      m_priRegionTopLeftX[i] = (sei.m_regionTopLeftInUnitsX[i] * m_priUnitSize * m_picWidth + m_maxPicWidth/2) / m_maxPicWidth;
+      m_priRegionTopLeftY[i] = (sei.m_regionTopLeftInUnitsY[i] * m_priUnitSize * m_picHeight + m_maxPicHeight/2) / m_maxPicHeight;
+      m_priRegionWidth[i] = ((sei.m_regionWidthInUnitsMinus1[i] + 1) * m_priUnitSize * m_picWidth + m_maxPicWidth/2) / m_maxPicWidth;
+      m_priRegionHeight[i] = ((sei.m_regionHeightInUnitsMinus1[i] + 1) * m_priUnitSize * m_picHeight + m_maxPicHeight/2) / m_maxPicHeight;
+    }
+    uint32_t resamplingRatioIdx = 0;
+    if (sei.m_numResamplingRatiosMinus1 > 0)
+    {
+      resamplingRatioIdx = sei.m_resamplingRatioIdx[i];
+    }
+    m_priResampleWidthNum[i] = sei.m_resamplingWidthNumMinus1[resamplingRatioIdx] + 1;
+    m_priResampleWidthDenom[i] = sei.m_resamplingWidthDenomMinus1[resamplingRatioIdx] + 1;
+    m_priResampleHeightNum[i] = sei.m_resamplingHeightNumMinus1[resamplingRatioIdx] + 1;
+    m_priResampleHeightDenom[i] = sei.m_resamplingHeightDenomMinus1[resamplingRatioIdx] + 1;
+    m_priTargetRegionWidth[i] = ((uint32_t)(((double)m_priRegionWidth[i] * m_priResampleWidthNum[i]) / (m_priResampleWidthDenom[i] * m_subWidthC) + 0.5)) * m_subWidthC;
+    m_priTargetRegionHeight[i] = ((uint32_t)(((double)m_priRegionHeight[i] * m_priResampleHeightNum[i]) / (m_priResampleHeightDenom[i] * m_subHeightC) + 0.5)) * m_subHeightC;
+  }
+  m_priTargetRegionTopLeftX = sei.m_targetRegionTopLeftX;
+  m_priTargetRegionTopLeftY = sei.m_targetRegionTopLeftY;
+  m_priRegionId = sei.m_regionId;
+}
+
+void SEIPackedRegionsInfoProcess::packRegions(PelUnitBuf& src, PelUnitBuf& dst, const SPS& sps)
+{
+  for (uint32_t i = 0; i < m_priNumRegions; i++)
+  {
+    int xScale = ((m_priTargetRegionWidth[i] << ScalingRatio::BITS) + (m_priRegionWidth[i] >> 1)) / m_priRegionWidth[i];
+    int yScale = ((m_priTargetRegionHeight[i] << ScalingRatio::BITS) + (m_priRegionHeight[i] >> 1)) / m_priRegionHeight[i];
+    ScalingRatio scalingRatio = { xScale, yScale };
+    for (int comp = 0; comp < ::getNumberValidComponents(m_chromaFormat); comp++)
+    {
+      ComponentID compID = ComponentID(comp);
+      const CPelBuf& beforeScale = src.get(compID);
+      PelBuf& afterScale = dst.get(compID);
+      int cx = isLuma(compID) ? 1 : m_subWidthC;
+      int cy = isLuma(compID) ? 1 : m_subHeightC;
+      CPelBuf beforeScaleSub = beforeScale.subBuf(m_priTargetRegionTopLeftX[i] / cx, m_priTargetRegionTopLeftY[i] / cy, m_priTargetRegionWidth[i] / cx, m_priTargetRegionHeight[i] / cy);
+      PelBuf afterScaleSub = afterScale.subBuf(m_priRegionTopLeftX[i] / cx, m_priRegionTopLeftY[i] / cy, m_priRegionWidth[i] / cx, m_priRegionHeight[i] / cy);
+      bool downsampling = (m_priTargetRegionWidth[i] > m_priRegionWidth[i]) || (m_priTargetRegionHeight[i] > m_priRegionHeight[i]);
+      bool useLumaFilter = downsampling;
+      Picture::sampleRateConv(
+        scalingRatio, ::getComponentScaleX(compID, m_chromaFormat), ::getComponentScaleY(compID, m_chromaFormat),
+        beforeScaleSub, 0, 0, afterScaleSub, 0, 0, isLuma(compID) ? m_bitDepthY : m_bitDepthC,
+        downsampling || useLumaFilter ? true : isLuma(compID), downsampling, isLuma(compID) ? 1 : sps.getHorCollocatedChromaFlag(),
+        isLuma(compID) ? 1 : sps.getVerCollocatedChromaFlag(), false, false);
+    }
+  }
+}
+
+void SEIPackedRegionsInfoProcess::reconstruct(const PelUnitBuf& src, PelUnitBuf& dst, const SPS& sps, const PPS& pps)
+{
+  Window win = pps.getConformanceWindow();
+  int winLeftOffset = win.getWindowLeftOffset() * m_subWidthC;
+  int winTopOffset = win.getWindowTopOffset() * m_subHeightC;
+
+  for (int comp = 0; comp < ::getNumberValidComponents(m_chromaFormat); comp++)
+  {
+    ComponentID compID = ComponentID(comp);
+    dst.get(compID).fill(1 << ((isLuma(compID) ? m_bitDepthY : m_bitDepthC) - 1));
+  }
+
+  uint32_t maxId = *std::max_element(m_priRegionId.begin(), m_priRegionId.end());
+  for (uint32_t regionId = 0; regionId <= maxId; regionId++)
+  {
+    auto it = std::find(m_priRegionId.begin(), m_priRegionId.end(), regionId);
+    if (it != m_priRegionId.end())
+    {
+      int i = (int)(it - m_priRegionId.begin());
+      int xScale = ((m_priRegionWidth[i] << ScalingRatio::BITS) + (m_priTargetRegionWidth[i] >> 1)) / m_priTargetRegionWidth[i];
+      int yScale = ((m_priRegionHeight[i] << ScalingRatio::BITS) + (m_priTargetRegionHeight[i] >> 1)) / m_priTargetRegionHeight[i];
+      ScalingRatio scalingRatio = { xScale, yScale };
+      for (int comp = 0; comp < ::getNumberValidComponents(m_chromaFormat); comp++)
+      {
+        ComponentID compID = ComponentID(comp);
+        const CPelBuf& beforeScale = src.get(compID);
+        PelBuf& afterScale = dst.get(compID);
+        int cx = isLuma(compID) ? 1 : m_subWidthC;
+        int cy = isLuma(compID) ? 1 : m_subHeightC;
+        CPelBuf beforeScaleSub = beforeScale.subBuf((winLeftOffset + m_priRegionTopLeftX[i]) / cx, (winTopOffset + m_priRegionTopLeftY[i]) / cy, m_priRegionWidth[i] / cx, m_priRegionHeight[i] / cy);
+        PelBuf afterScaleSub = afterScale.subBuf(m_priTargetRegionTopLeftX[i] / cx, m_priTargetRegionTopLeftY[i] / cy, m_priTargetRegionWidth[i] / cx, m_priTargetRegionHeight[i] / cy);
+        bool downsampling = (m_priRegionWidth[i] > m_priTargetRegionWidth[i]) || (m_priRegionHeight[i] > m_priTargetRegionHeight[i]);
+        bool useLumaFilter = downsampling;
+        Picture::sampleRateConv(
+          scalingRatio, ::getComponentScaleX(compID, m_chromaFormat), ::getComponentScaleY(compID, m_chromaFormat),
+          beforeScaleSub, 0, 0, afterScaleSub, 0, 0, isLuma(compID) ? m_bitDepthY : m_bitDepthC,
+          downsampling || useLumaFilter ? true : isLuma(compID), downsampling, isLuma(compID) ? 1 : sps.getHorCollocatedChromaFlag(),
+          isLuma(compID) ? 1 : sps.getVerCollocatedChromaFlag(), false, false);
+      }
+    }
+  }
+}
diff --git a/source/Lib/CommonLib/SEIPackedRegionsInfoProcess.h b/source/Lib/CommonLib/SEIPackedRegionsInfoProcess.h
new file mode 100644
index 0000000000000000000000000000000000000000..c4be0b94bb8eecebdbc5b57f9acfae1d1ef2ed58
--- /dev/null
+++ b/source/Lib/CommonLib/SEIPackedRegionsInfoProcess.h
@@ -0,0 +1,111 @@
+/* The copyright in this software is being made available under the BSD
+ * License, included below. This software may be subject to other third party
+ * and contributor rights, including patent rights, and no such rights are
+ * granted under this license.
+ *
+ * Copyright (c) 2010-2023, ITU/ISO/IEC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
+ *    be used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file     SEIPackedRegionsInfo.h
+    \brief    Packed regions info SEI processing
+*/
+
+#ifndef __SEIPACKEDREGIONSINFOPROCESS__
+#define __SEIPACKEDREGIONSINFOPROCESS__
+
+#include "SEI.h"
+#include "Unit.h"
+#include "Buffer.h"
+#include "Unit.h"
+
+
+//! \ingroup CommonLib
+//! \{
+
+// ====================================================================================================================
+// Class definition
+// ====================================================================================================================
+
+class SEIPackedRegionsInfoProcess
+{
+public:
+  SEIPackedRegionsInfoProcess()
+    : m_enabled(false)
+    , m_persistence(false)
+    , m_picWidth(0)
+    , m_picHeight(0)
+    , m_maxPicWidth(0)
+    , m_maxPicHeight(0)
+    , m_targetPicWidth(0)
+    , m_targetPicHeight(0)
+    , m_bitDepthY(10)
+    , m_bitDepthC(10)
+    , m_priUnitSize(1)
+    , m_chromaFormat(ChromaFormat::_420)
+    , m_subWidthC(2)
+    , m_subHeightC(2)
+    , m_priNumRegions(0)
+  {}
+  ~SEIPackedRegionsInfoProcess() {}
+  void init(SEIPackedRegionsInfo& sei, const SPS& sps, uint32_t picWidth, uint32_t picHeight);
+  void packRegions(PelUnitBuf& src, PelUnitBuf& dst, const SPS& sps);
+  void reconstruct(const PelUnitBuf& src, PelUnitBuf& dst, const SPS& sps, const PPS& pps);
+
+  bool                  m_enabled;
+  bool                  m_persistence;
+  uint32_t              m_picWidth;
+  uint32_t              m_picHeight;
+  uint32_t              m_maxPicWidth;
+  uint32_t              m_maxPicHeight;
+  uint32_t              m_targetPicWidth;
+  uint32_t              m_targetPicHeight;
+  uint32_t              m_bitDepthY;
+  uint32_t              m_bitDepthC;
+  uint32_t              m_priUnitSize;
+  ChromaFormat          m_chromaFormat;
+  uint32_t              m_subWidthC;
+  uint32_t              m_subHeightC;
+  uint32_t              m_priNumRegions;
+  std::vector<uint32_t> m_priRegionTopLeftX;
+  std::vector<uint32_t> m_priRegionTopLeftY;
+  std::vector<uint32_t> m_priRegionWidth;
+  std::vector<uint32_t> m_priRegionHeight;
+  std::vector<uint32_t> m_priResampleWidthNum;
+  std::vector<uint32_t> m_priResampleWidthDenom;
+  std::vector<uint32_t> m_priResampleHeightNum;
+  std::vector<uint32_t> m_priResampleHeightDenom;
+  std::vector<uint32_t> m_priTargetRegionTopLeftX;
+  std::vector<uint32_t> m_priTargetRegionTopLeftY;
+  std::vector<uint32_t> m_priTargetRegionWidth;
+  std::vector<uint32_t> m_priTargetRegionHeight;
+  std::vector<uint32_t> m_priRegionId;
+};
+
+//! \}
+
+#endif // __SEIPACKEDREGIONSINFO__
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 9193a8ec89bef20969d79e665609f0b0d0363e6f..a975baf73ee686472dc7570571caa083d93e125f 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -81,6 +81,8 @@
 
 #define JVET_AH0162_CONSTITUENT_RECTANGLES                1
 
+#define JVET_AH0161_REGION_PACKING_INFORMATION_SEI        1
+
 //########### place macros to be be kept below this line ###############
 
 #define GDR_ENABLED   1
diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp
index 25c19924680546b4c8b5f41b35ddfc5ea33b21eb..1a89469eeddc1160b7170552f333f8937933e589 100644
--- a/source/Lib/DecoderLib/DecLib.cpp
+++ b/source/Lib/DecoderLib/DecLib.cpp
@@ -2098,6 +2098,19 @@ void DecLib::xActivateParameterSets( const InputNALUnit nalu )
     m_pcPic->createColourTransfProcessor(m_firstPictureInSequence, &m_colourTranfParams, &m_invColourTransfBuf,
                                          pps->getPicWidthInLumaSamples(), pps->getPicHeightInLumaSamples(),
                                          sps->getChromaFormatIdc(), sps->getBitDepth(ChannelType::LUMA));
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+    SEIMessages packedRegionsInfoSEIs = getSeisByType(m_SEIs, SEI::PayloadType::PACKED_REGIONS_INFO);
+    if (!packedRegionsInfoSEIs.empty())
+    {
+      SEIPackedRegionsInfo* sei = (SEIPackedRegionsInfo*)packedRegionsInfoSEIs.front();
+      m_priProcess.init(*sei, *sps, pps->getPicWidthInLumaSamples(), pps->getPicHeightInLumaSamples());
+      m_pcPic->m_priProcess = m_priProcess;
+    }
+    else if (m_priProcess.m_enabled)
+    {
+      m_pcPic->m_priProcess = m_priProcess;
+    }
+#endif
     m_firstPictureInSequence = false;
     m_pcPic->createTempBuffers( m_pcPic->cs->pps->pcv->maxCUWidth, false, false, true, false );
     m_pcPic->cs->createTemporaryCsData((bool)m_pcPic->cs->sps->getPLTMode());
diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h
index 53ca18d269c139883c5e1a642ebaff0dbcb88638..72e42e5ced61efe96c7a75880e710315c963ee54 100644
--- a/source/Lib/DecoderLib/DecLib.h
+++ b/source/Lib/DecoderLib/DecLib.h
@@ -55,6 +55,9 @@
 #include "CommonLib/Unit.h"
 #include "CommonLib/Reshape.h"
 #include "CommonLib/SEINeuralNetworkPostFiltering.h"
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+#include "CommonLib/SEIPackedRegionsInfoProcess.h"
+#endif
 
 class InputNALUnit;
 
@@ -233,6 +236,9 @@ private:
   int m_lastGdrRecoveryPocCnt;
 #endif
   SEINeuralNetworkPostFiltering m_nnPostFiltering;
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  SEIPackedRegionsInfoProcess m_priProcess;
+#endif
 
 public:
   int                     m_targetSubPicIdx;
diff --git a/source/Lib/DecoderLib/SEIread.cpp b/source/Lib/DecoderLib/SEIread.cpp
index 1c61cf5303cdf0d123c3e730c3eba886e333cf22..74d44b66d989ed3d91b0b6bbb020266ce7b3778c 100644
--- a/source/Lib/DecoderLib/SEIread.cpp
+++ b/source/Lib/DecoderLib/SEIread.cpp
@@ -576,6 +576,12 @@ bool SEIReader::xReadSEImessage(SEIMessages& seis, const NalUnitType nalUnitType
       sei = new SEIConstituentRectangles();
       xParseSEIConstituentRectangles((SEIConstituentRectangles&) *sei, payloadSize, pDecodedMessageOutputStream);
       break;
+#endif
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+    case SEI::PayloadType::PACKED_REGIONS_INFO:
+      sei = new SEIPackedRegionsInfo;
+      xParsePackedRegionsInfo((SEIPackedRegionsInfo &) *sei, payloadSize, pDecodedMessageOutputStream);
+      break;
 #endif
     default:
       for (uint32_t i = 0; i < payloadSize; i++)
@@ -4020,4 +4026,125 @@ void SEIReader::xParseSEIConstituentRectangles(SEIConstituentRectangles& sei, ui
 }
 #endif
 
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+void SEIReader::xParsePackedRegionsInfo(SEIPackedRegionsInfo& sei, uint32_t payLoadSize, std::ostream* pDecodedMessageOutputStream)
+{
+  output_sei_message_header(sei, pDecodedMessageOutputStream, payLoadSize);
+  uint32_t val;
+
+  sei_read_flag(pDecodedMessageOutputStream, val, "pri_cancel_flag");
+  sei.m_cancelFlag = val != 0;
+  if (!sei.m_cancelFlag)
+  {
+    sei_read_flag(pDecodedMessageOutputStream, val, "pri_persistence_flag");
+    sei.m_persistenceFlag = val != 0;
+    sei_read_uvlc(pDecodedMessageOutputStream, val, "pri_num_regions_minus1");
+    sei.m_numRegionsMinus1 = val;
+    sei_read_flag(pDecodedMessageOutputStream, val, "pri_use_max_dimensions_flag");
+    sei.m_useMaxDimensionsFlag = val != 0;
+    sei_read_code(pDecodedMessageOutputStream, 4, val, "pri_log2_unit_size");
+    sei.m_log2UnitSize = val;
+    sei_read_code(pDecodedMessageOutputStream, 4, val, "pri_region_size_len_minus1");
+    sei.m_regionSizeLenMinus1 = val;
+    sei_read_flag(pDecodedMessageOutputStream, val, "pri_region_id_present_flag");
+    sei.m_regionIdPresentFlag = val != 0;
+    sei_read_flag(pDecodedMessageOutputStream, val, "pri_target_pic_params_present_flag");
+    sei.m_targetPicParamsPresentFlag = val != 0;
+    if (sei.m_targetPicParamsPresentFlag)
+    {
+      sei_read_code(pDecodedMessageOutputStream, 16, val, "pri_target_pic_width_minus1");
+      sei.m_targetPicWidthMinus1 = val;
+      sei_read_code(pDecodedMessageOutputStream, 16, val, "pri_target_pic_height_minus1");
+      sei.m_targetPicHeightMinus1 = val;
+    }
+    sei_read_uvlc(pDecodedMessageOutputStream, val, "pri_num_resampling_ratios_minus1");
+    sei.m_numResamplingRatiosMinus1 = val;
+
+    sei.m_resamplingWidthNumMinus1.resize(sei.m_numResamplingRatiosMinus1 + 1);
+    sei.m_resamplingWidthDenomMinus1.resize(sei.m_numResamplingRatiosMinus1 + 1);
+    sei.m_fixedAspectRatioFlag.resize(sei.m_numResamplingRatiosMinus1 + 1);
+    sei.m_resamplingHeightNumMinus1.resize(sei.m_numResamplingRatiosMinus1 + 1);
+    sei.m_resamplingHeightDenomMinus1.resize(sei.m_numResamplingRatiosMinus1 + 1);
+    sei.m_resamplingWidthNumMinus1[0] = 0;
+    sei.m_resamplingWidthDenomMinus1[0] = 0;
+    sei.m_fixedAspectRatioFlag[0] = true;
+    sei.m_resamplingHeightNumMinus1[0] = 0;
+    sei.m_resamplingHeightDenomMinus1[0] = 0;
+    for (uint32_t i = 1; i <= sei.m_numResamplingRatiosMinus1; i++)
+    {
+      sei_read_uvlc(pDecodedMessageOutputStream, val, "pri_resampling_width_num_minus1[i]");
+      sei.m_resamplingWidthNumMinus1[i] = val;
+      sei_read_uvlc(pDecodedMessageOutputStream, val, "pri_resampling_width_denom_minus1[i]");
+      sei.m_resamplingWidthDenomMinus1[i] = val;
+      sei_read_flag(pDecodedMessageOutputStream, val, "pri_fixed_aspect_ratio_flag[i]");
+      sei.m_fixedAspectRatioFlag[i] = val != 0;
+      if (!sei.m_fixedAspectRatioFlag[i])
+      {
+        sei_read_uvlc(pDecodedMessageOutputStream, val, "pri_resampling_height_num_minus1[i]");
+        sei.m_resamplingHeightNumMinus1[i] = val;
+        sei_read_uvlc(pDecodedMessageOutputStream, val, "pri_resampling_height_denom_minus1[i]");
+        sei.m_resamplingHeightDenomMinus1[i] = val;
+      }
+      else
+      {
+        sei.m_resamplingHeightNumMinus1[i] = sei.m_resamplingWidthNumMinus1[i];
+        sei.m_resamplingHeightDenomMinus1[i] = sei.m_resamplingWidthDenomMinus1[i];
+      }
+    }
+
+    sei.m_regionId.resize(sei.m_numRegionsMinus1 + 1);
+    sei.m_regionTopLeftInUnitsX.resize(sei.m_numRegionsMinus1 + 1);
+    sei.m_regionTopLeftInUnitsY.resize(sei.m_numRegionsMinus1 + 1);
+    sei.m_regionWidthInUnitsMinus1.resize(sei.m_numRegionsMinus1 + 1);
+    sei.m_regionHeightInUnitsMinus1.resize(sei.m_numRegionsMinus1 + 1);
+    sei.m_resamplingRatioIdx.resize(sei.m_numRegionsMinus1 + 1);
+    sei.m_targetRegionTopLeftX.resize(sei.m_numRegionsMinus1 + 1);
+    sei.m_targetRegionTopLeftY.resize(sei.m_numRegionsMinus1 + 1);
+    for (uint32_t i = 0; i <= sei.m_numRegionsMinus1; i++)
+    {
+      if (sei.m_regionIdPresentFlag)
+      {
+        sei_read_uvlc(pDecodedMessageOutputStream, val, "pri_region_id[i]");
+        sei.m_regionId[i] = val;
+      }
+      else
+      {
+        sei.m_regionId[i] = i;
+      }
+      sei_read_code(pDecodedMessageOutputStream, sei.m_regionSizeLenMinus1 + 1, val, "pri_region_top_left_in_units_x[i]");
+      sei.m_regionTopLeftInUnitsX[i] = val;
+      sei_read_code(pDecodedMessageOutputStream, sei.m_regionSizeLenMinus1 + 1, val, "pri_region_top_left_in_units_y[i]");
+      sei.m_regionTopLeftInUnitsY[i] = val;
+      sei_read_code(pDecodedMessageOutputStream, sei.m_regionSizeLenMinus1 + 1, val, "pri_region_width_in_units_minus1[i]");
+      sei.m_regionWidthInUnitsMinus1[i] = val;
+      sei_read_code(pDecodedMessageOutputStream, sei.m_regionSizeLenMinus1 + 1, val, "pri_region_height_in_units_minus1[i]");
+      sei.m_regionHeightInUnitsMinus1[i] = val;
+      if (sei.m_numResamplingRatiosMinus1 > 0)
+      {
+        sei_read_code(pDecodedMessageOutputStream, ceilLog2(sei.m_numResamplingRatiosMinus1 + 1), val, "pri_resampling_ratio_idx[i]");
+        sei.m_resamplingRatioIdx[i] = val;
+      }
+      else
+      {
+        sei.m_resamplingRatioIdx[i] = 0;
+      }
+      if (sei.m_targetPicParamsPresentFlag)
+      {
+        sei_read_code(pDecodedMessageOutputStream, sei.m_regionSizeLenMinus1 + 1, val, "pri_target_region_top_left_x[i]");
+        sei.m_targetRegionTopLeftX[i] = val;
+        sei_read_code(pDecodedMessageOutputStream, sei.m_regionSizeLenMinus1 + 1, val, "pri_target_region_top_left_y[i]");
+        sei.m_targetRegionTopLeftY[i] = val;
+      }
+    }
+    if (sei.m_regionIdPresentFlag)
+    {
+      std::vector<uint32_t> tmpVec = sei.m_regionId;
+      std::sort(tmpVec.begin(), tmpVec.end());
+      auto it = std::unique(tmpVec.begin(), tmpVec.end());
+      CHECK(it != tmpVec.end(), "pri_region_id values must be unique");
+    }
+  }
+}
+#endif
+
 //! \}
diff --git a/source/Lib/DecoderLib/SEIread.h b/source/Lib/DecoderLib/SEIread.h
index e96efef4806fc7f0a974c08c673c49333eea58de..13d21eb05d71affdaba57432705518c3a278badf 100644
--- a/source/Lib/DecoderLib/SEIread.h
+++ b/source/Lib/DecoderLib/SEIread.h
@@ -133,6 +133,9 @@ protected:
   void xParseSEIJfifMetadata (SEIJfifMetadata &sei, uint32_t payLoadSize, std::ostream *pDecodedMessageOutputStream);
   void xParseSEIXmpMetadata  (SEIXmpMetadata  &sei, uint32_t payLoadSize, std::ostream *pDecodedMessageOutputStream);
 #endif
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  void xParsePackedRegionsInfo(SEIPackedRegionsInfo &sei, uint32_t payLoadSize, std::ostream *pDecodedMessageOutputStream);
+#endif
 
 #if JVET_AH0162_CONSTITUENT_RECTANGLES
   void xParseSEIConstituentRectangles(SEIConstituentRectangles& sei, uint32_t payLoadSize, std::ostream *pDecodedMessageOutputStream);
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index 65b5565f68d9b0496faeb277b6b9303dbc4aa420..d535d19b3603fe1fc5b75f74419c0fd351f80b8b 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -979,6 +979,34 @@ protected:
   std::vector<std::string> m_crSEIRectTypeDescription;
 #endif
 
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  bool     m_priSEIEnabled;
+  bool     m_priSEICancelFlag;
+  bool     m_priSEIPersistenceFlag;
+  uint32_t m_priSEINumRegionsMinus1;
+  bool     m_priSEIUseMaxDimensionsFlag;
+  uint32_t m_priSEILog2UnitSize;
+  uint32_t m_priSEIRegionSizeLenMinus1;
+  bool     m_priSEIRegionIdPresentFlag;
+  bool     m_priSEITargetPicParamsPresentFlag;
+  uint32_t m_priSEITargetPicWidthMinus1;
+  uint32_t m_priSEITargetPicHeightMinus1;
+  uint32_t m_priSEINumResamplingRatiosMinus1;
+  std::vector<uint32_t> m_priSEIResamplingWidthNumMinus1;
+  std::vector<uint32_t> m_priSEIResamplingWidthDenomMinus1;
+  std::vector<bool>     m_priSEIFixedAspectRatioFlag;
+  std::vector<uint32_t> m_priSEIResamplingHeightNumMinus1;
+  std::vector<uint32_t> m_priSEIResamplingHeightDenomMinus1;
+  std::vector<uint32_t> m_priSEIRegionId;
+  std::vector<uint32_t> m_priSEIRegionTopLeftInUnitsX;
+  std::vector<uint32_t> m_priSEIRegionTopLeftInUnitsY;
+  std::vector<uint32_t> m_priSEIRegionWidthInUnitsMinus1;
+  std::vector<uint32_t> m_priSEIRegionHeightInUnitsMinus1;
+  std::vector<uint32_t> m_priSEIResamplingRatioIdx;
+  std::vector<uint32_t> m_priSEITargetRegionTopLeftX;
+  std::vector<uint32_t> m_priSEITargetRegionTopLeftY;
+#endif
+
   bool      m_constrainedRaslEncoding;
 
   //====== Weighted Prediction ========
@@ -2806,6 +2834,59 @@ public:
   void        setCrSEIRectTypeDescription(const std::vector<std::string>& b) { m_crSEIRectTypeDescription = b; }
 #endif
 
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  void     setPriSEIEnabled(bool b)                                       { m_priSEIEnabled = b; }
+  bool     getPriSEIEnabled()                                             { return m_priSEIEnabled; }
+  void     setPriSEICancelFlag(bool b)                                    { m_priSEICancelFlag = b; }
+  bool     getPriSEICancelFlag()                                          { return m_priSEICancelFlag; }
+  void     setPriSEIPersistenceFlag(bool b)                               { m_priSEIPersistenceFlag = b; }
+  bool     getPriSEIPersistenceFlag()                                     { return m_priSEIPersistenceFlag; }
+  void     setPriSEINumRegionsMinus1(uint32_t i)                          { m_priSEINumRegionsMinus1 = i; }
+  uint32_t getPriSEINumRegionsMinus1()                                    { return m_priSEINumRegionsMinus1; }
+  void     setPriSEIUseMaxDimensionsFlag(bool b)                          { m_priSEIUseMaxDimensionsFlag = b; }
+  bool     getPriSEIUseMaxDimensionsFlag()                                { return m_priSEIUseMaxDimensionsFlag; }
+  void     setPriSEILog2UnitSize(uint32_t i)                              { m_priSEILog2UnitSize = i; }
+  uint32_t getPriSEILog2UnitSize()                                        { return m_priSEILog2UnitSize; }
+  void     setPriSEIRegionSizeLenMinus1(uint32_t i)                       { m_priSEIRegionSizeLenMinus1 = i; }
+  uint32_t getPriSEIRegionSizeLenMinus1()                                 { return m_priSEIRegionSizeLenMinus1; }
+  void     setPriSEIRegionIdPresentFlag(bool b)                           { m_priSEIRegionIdPresentFlag = b; }
+  bool     getPriSEIRegionIdPresentFlag()                                 { return m_priSEIRegionIdPresentFlag; }
+  void     setPriSEITargetPicParamsPresentFlag(bool b)                    { m_priSEITargetPicParamsPresentFlag = b; }
+  bool     getPriSEITargetPicParamsPresentFlag()                          { return m_priSEITargetPicParamsPresentFlag; }
+  void     setPriSEITargetPicWidthMinus1(uint32_t i)                      { m_priSEITargetPicWidthMinus1 = i; }
+  uint32_t getPriSEITargetPicWidthMinus1()                                { return m_priSEITargetPicWidthMinus1; }
+  void     setPriSEITargetPicHeightMinus1(uint32_t i)                     { m_priSEITargetPicHeightMinus1 = i; }
+  uint32_t getPriSEITargetPicHeightMinus1()                               { return m_priSEITargetPicHeightMinus1; }
+  void     setPriSEINumResamplingRatiosMinus1(uint32_t i)                 { m_priSEINumResamplingRatiosMinus1 = i; }
+  uint32_t getPriSEINumResamplingRatiosMinus1()                           { return m_priSEINumResamplingRatiosMinus1; }
+  void     setPriSEIResamplingWidthNumMinus1(std::vector<uint32_t>& b)    { m_priSEIResamplingWidthNumMinus1 = b; }
+  uint32_t getPriSEIResamplingWidthNumMinus1(int i)                       { return m_priSEIResamplingWidthNumMinus1[i]; }
+  void     setPriSEIResamplingWidthDenomMinus1(std::vector<uint32_t>& b)  { m_priSEIResamplingWidthDenomMinus1 = b; }
+  uint32_t getPriSEIResamplingWidthDenomMinus1(int i)                     { return m_priSEIResamplingWidthDenomMinus1[i]; }
+  void     setPriSEIFixedAspectRatioFlag(std::vector<bool>& b)            { m_priSEIFixedAspectRatioFlag = b; }
+  bool     getPriSEIFixedAspectRatioFlag(int i)                           { return m_priSEIFixedAspectRatioFlag[i]; }
+  void     setPriSEIResamplingHeightNumMinus1(std::vector<uint32_t>& b)   { m_priSEIResamplingHeightNumMinus1 = b; }
+  uint32_t getPriSEIResamplingHeightNumMinus1(int i)                      { return m_priSEIResamplingHeightNumMinus1[i]; }
+  void     setPriSEIResamplingHeightDenomMinus1(std::vector<uint32_t>& b) { m_priSEIResamplingHeightDenomMinus1 = b; }
+  uint32_t getPriSEIResamplingHeightDenomMinus1(int i)                    { return m_priSEIResamplingHeightDenomMinus1[i]; }
+  void     setPriSEIRegionId(std::vector<uint32_t>& b)                    { m_priSEIRegionId = b; }
+  uint32_t getPriSEIRegionId(int i)                                       { return m_priSEIRegionId[i]; }
+  void     setPriSEIRegionTopLeftInUnitsX(std::vector<uint32_t>& b)       { m_priSEIRegionTopLeftInUnitsX = b; }
+  uint32_t getPriSEIRegionTopLeftInUnitsX(int i)                          { return m_priSEIRegionTopLeftInUnitsX[i]; }
+  void     setPriSEIRegionTopLeftInUnitsY(std::vector<uint32_t>& b)       { m_priSEIRegionTopLeftInUnitsY = b; }
+  uint32_t getPriSEIRegionTopLeftInUnitsY(int i)                          { return m_priSEIRegionTopLeftInUnitsY[i]; }
+  void     setPriSEIRegionWidthInUnitsMinus1(std::vector<uint32_t>& b)    { m_priSEIRegionWidthInUnitsMinus1 = b; }
+  uint32_t getPriSEIRegionWidthInUnitsMinus1(int i)                       { return m_priSEIRegionWidthInUnitsMinus1[i]; }
+  void     setPriSEIRegionHeightInUnitsMinus1(std::vector<uint32_t>& b)   { m_priSEIRegionHeightInUnitsMinus1 = b; }
+  uint32_t getPriSEIRegionHeightInUnitsMinus1(int i)                      { return m_priSEIRegionHeightInUnitsMinus1[i]; }
+  void     setPriSEIResamplingRatioIdx(std::vector<uint32_t>& b)          { m_priSEIResamplingRatioIdx = b; }
+  uint32_t getPriSEIResamplingRatioIdx(int i)                             { return m_priSEIResamplingRatioIdx[i]; }
+  void     setPriSEITargetRegionTopLeftX(std::vector<uint32_t>& b)        { m_priSEITargetRegionTopLeftX = b; }
+  uint32_t getPriSEITargetRegionTopLeftX(int i)                           { return m_priSEITargetRegionTopLeftX[i]; }
+  void     setPriSEITargetRegionTopLeftY(std::vector<uint32_t>& b)        { m_priSEITargetRegionTopLeftY = b; }
+  uint32_t getPriSEITargetRegionTopLeftY(int i)                           { return m_priSEITargetRegionTopLeftY[i]; }
+#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 5d014e740b05abcb966dba6b1b175a4695162c9a..4e50d73571dc41d391f57bfc8bce5bbecb1612e5 100644
--- a/source/Lib/EncoderLib/EncGOP.cpp
+++ b/source/Lib/EncoderLib/EncGOP.cpp
@@ -44,6 +44,9 @@
 #include "Analyze.h"
 #include "libmd5/MD5.h"
 #include "CommonLib/SEI.h"
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+#include "CommonLib/SEIPackedRegionsInfoProcess.h"
+#endif
 #include "CommonLib/NAL.h"
 #include "NALwrite.h"
 
@@ -945,6 +948,14 @@ void EncGOP::xCreateIRAPLeadingSEIMessages (SEIMessages& seiMessages, const SPS
     seiMessages.push_back(seiConstituentRectangles);
   }
 #endif
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  if (m_pcCfg->getPriSEIEnabled())
+  {
+    SEIPackedRegionsInfo *seiPackedRegionsInfo = new SEIPackedRegionsInfo;
+    m_seiEncoder.initSEIPackedRegionsInfo(seiPackedRegionsInfo);
+    seiMessages.push_back(seiPackedRegionsInfo);
+  }
+#endif
 }
 
 void EncGOP::xCreatePerPictureSEIMessages (int picInGOP, SEIMessages& seiMessages, SEIMessages& nestedSeiMessages, Slice *slice)
@@ -2559,9 +2570,17 @@ void EncGOP::compressGOP(int pocLast, int numPicRcvd, PicList &rcListPic, std::l
 
     const bool isCurrentFrameFiltered = m_pcCfg->getGopBasedTemporalFilterEnabled() || m_pcCfg->getBIM();
     const bool isFgFiltered = m_pcCfg->getFilmGrainAnalysisEnabled() && m_pcCfg->getFilmGrainExternalDenoised().empty();
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+    pcPic->createTempBuffers(pcPic->cs->pps->pcv->maxCUWidth, isCurrentFrameFiltered, m_pcEncLib->isResChangeInClvsEnabled() || m_pcEncLib->getPriSEIEnabled(), false, isFgFiltered);
+#else
     pcPic->createTempBuffers(pcPic->cs->pps->pcv->maxCUWidth, isCurrentFrameFiltered, m_pcEncLib->isResChangeInClvsEnabled(), false, isFgFiltered);
+#endif
     pcPic->getTrueOrigBuf().copyFrom(pcPic->getOrigBuf());
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+    if (m_pcEncLib->isResChangeInClvsEnabled() || m_pcEncLib->getPriSEIEnabled())
+#else
     if (m_pcEncLib->isResChangeInClvsEnabled())
+#endif
     {
       pcPic->M_BUFS(0, PIC_TRUE_ORIGINAL_INPUT).copyFrom(pcPic->M_BUFS(0, PIC_ORIGINAL_INPUT));
     }
@@ -2590,6 +2609,13 @@ void EncGOP::compressGOP(int pocLast, int numPicRcvd, PicList &rcListPic, std::l
         Picture::rescalePicture(scalingRatio, pcPic->M_BUFS(0, PIC_ORIGINAL_INPUT), curScalingWindow, pcPic->M_BUFS(0, PIC_ORIGINAL), pps->getScalingWindow(), chromaFormatIdc, sps.getBitDepths(), true, true,
           sps.getHorCollocatedChromaFlag(), sps.getVerCollocatedChromaFlag());
       }
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+      else if (m_pcEncLib->getPriSEIEnabled())
+      {
+        m_pcEncLib->getTemporalFilter().filter(&pcPic->M_BUFS(0, PIC_ORIGINAL_INPUT), pocCurr);
+        m_pcEncLib->getPriProcess().packRegions(pcPic->M_BUFS(0, PIC_ORIGINAL_INPUT), pcPic->M_BUFS(0, PIC_ORIGINAL), *pcPic->cs->sps);
+      }
+#endif
       else
       {
         m_pcEncLib->getTemporalFilter().filter(&pcPic->M_BUFS(0, PIC_ORIGINAL), pocCurr);
diff --git a/source/Lib/EncoderLib/EncGOP.h b/source/Lib/EncoderLib/EncGOP.h
index 5640b63b50b59a39cbfabb448ceafbfdf8e8404d..d8852aacc0937c01e16605d6de277452856c86cd 100644
--- a/source/Lib/EncoderLib/EncGOP.h
+++ b/source/Lib/EncoderLib/EncGOP.h
@@ -282,6 +282,9 @@ public:
                        const BitDepths &bitDepths, int layerId);
   uint64_t  preLoopFilterPicAndCalcDist( Picture* pcPic );
   EncSlice*  getSliceEncoder()   { return m_pcSliceEncoder; }
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  SEIEncoder& getSEIEncoder()    { return m_seiEncoder; };
+#endif
   NalUnitType getNalUnitType( int pocCurr, int lastIdr, bool isField );
   void arrangeCompositeReference(Slice* pcSlice, PicList& rcListPic, int pocCurr);
   void updateCompositeReference(Slice* pcSlice, PicList& rcListPic, int pocCurr);
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index ac09801999a8f248cf9c677b12dcdb8503bdb390..59b5031c01aa0974be576268b5a1c1b95910912d 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -44,6 +44,9 @@
 #include "CommonLib/CommonDef.h"
 #include "CommonLib/ChromaFormat.h"
 #include "EncLibCommon.h"
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+#include "CommonLib/SEIPackedRegionsInfoProcess.h"
+#endif
 #include "CommonLib/ProfileTierLevel.h"
 
 //! \ingroup EncoderLib
@@ -442,6 +445,53 @@ void EncLib::init(AUWriterIf *auWriterIf)
     }
   }
 
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  int packedRegionsWidth = 0;
+  int packedRegionsHeight = 0;
+  if (m_priSEIEnabled)
+  {
+    CHECK(m_resChangeInClvsEnabled, "Cannot use RPR resolution change with packed regions info SEI");
+    PPS& pps = *(m_ppsMap.allocatePS(ENC_PPS_ID_RPR + m_layerId));  // Reuse RPR pps for packed regions info SEI
+    int minSizeUnit = std::max(8, 1 << sps0.getLog2MinCodingBlockSize());
+    uint32_t priUnitSize = 1 << m_priSEILog2UnitSize;
+    for (uint32_t i = 0; i <= m_priSEINumRegionsMinus1; i++)
+    {
+      packedRegionsWidth = std::max(packedRegionsWidth, (int)(m_priSEIRegionTopLeftInUnitsX[i] + (m_priSEIRegionWidthInUnitsMinus1[i] + 1) * priUnitSize));
+      packedRegionsHeight = std::max(packedRegionsHeight, (int)(m_priSEIRegionTopLeftInUnitsY[i] + (m_priSEIRegionHeightInUnitsMinus1[i] + 1) * priUnitSize));
+    }
+    packedRegionsWidth = (packedRegionsWidth + (minSizeUnit - 1)) & ~(minSizeUnit - 1);
+    packedRegionsHeight = (packedRegionsHeight + (minSizeUnit - 1)) & ~(minSizeUnit - 1);
+    pps.setPicWidthInLumaSamples(packedRegionsWidth);
+    pps.setPicHeightInLumaSamples(packedRegionsHeight);
+    pps.setSliceChromaQpFlag(true);
+
+    //register the width/height of the current pic into reference SPS
+    if (!sps0.getPPSValidFlag(pps.getPPSId()))
+    {
+      sps0.setPPSValidFlag(pps.getPPSId(), true);
+      sps0.setScalingWindowSizeInPPS(pps.getPPSId(), packedRegionsWidth, packedRegionsHeight);
+    }
+
+    // disable picture partitioning for scaled RPR pictures (slice/tile config only provided for the original resolution)
+    m_noPicPartitionFlag = true;
+
+    xInitPPS(pps, sps0); // will allocate memory for and initialize pps.pcv inside
+
+    if (pps.getWrapAroundEnabledFlag())
+    {
+      const int minCbSizeY = 1 << sps0.getLog2MinCodingBlockSize();
+      pps.setPicWidthMinusWrapAroundOffset((pps.getPicWidthInLumaSamples() / minCbSizeY) - (m_wrapAroundOffset * pps.getPicWidthInLumaSamples() / pps0.getPicWidthInLumaSamples() / minCbSizeY));
+      pps.setWrapAroundOffset(minCbSizeY * (pps.getPicWidthInLumaSamples() / minCbSizeY - pps.getPicWidthMinusWrapAroundOffset()));
+
+    }
+    else
+    {
+      pps.setPicWidthMinusWrapAroundOffset(0);
+      pps.setWrapAroundOffset(0);
+    }
+  }
+#endif
+
 #if ER_CHROMA_QP_WCG_PPS
   if (m_wcgChromaQpControl.isEnabled())
   {
@@ -472,6 +522,15 @@ void EncLib::init(AUWriterIf *auWriterIf)
   m_cSliceEncoder.init( this, sps0 );
   m_cCuEncoder.   init( this, sps0 );
 
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  if (m_priSEIEnabled)
+  {
+    SEIPackedRegionsInfo sei;
+    m_cGOPEncoder.getSEIEncoder().initSEIPackedRegionsInfo(&sei);
+    m_priProcess.init(sei, sps0, packedRegionsWidth, packedRegionsHeight);
+  }
+#endif
+
   // initialize transform & quantization class
   m_cTrQuant.init( nullptr,
                    1 << m_log2MaxTbSize,
@@ -505,7 +564,11 @@ void EncLib::init(AUWriterIf *auWriterIf)
   {
     xInitScalingLists( sps0, aps0 );
   }
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  if (m_resChangeInClvsEnabled || m_priSEIEnabled)
+#else
   if (m_resChangeInClvsEnabled)
+#endif
   {
     xInitScalingLists(sps0, *m_apsMaps[ApsType::SCALING_LIST].getPS(ENC_PPS_ID_RPR + m_layerId));
   }
@@ -795,6 +858,13 @@ bool EncLib::encodePrep(bool flush, PelStorage *pcPicYuvOrg, const InputColourSp
       ppsID = m_vps->getGeneralLayerIdx( m_layerId );
     }
 
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+    if (m_priSEIEnabled)
+    {
+      ppsID = ENC_PPS_ID_RPR + m_layerId;
+    }
+#endif
+
     xGetNewPicBuffer( rcListPicYuvRecOut, pcPicCurr, ppsID );
 
     const PPS *pPPS = ( ppsID < 0 ) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS( ppsID );
@@ -836,6 +906,17 @@ bool EncLib::encodePrep(bool flush, PelStorage *pcPicYuvOrg, const InputColourSp
                               pPPS->getScalingWindow(), chromaFormatIdc, pSPS->getBitDepths(), true, true,
                               pSPS->getHorCollocatedChromaFlag(), pSPS->getVerCollocatedChromaFlag());
     }
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+    else if (m_priSEIEnabled)
+    {
+      pcPicCurr->M_BUFS( 0, PIC_ORIGINAL_INPUT ).getBuf( COMPONENT_Y ).copyFrom( pcPicYuvOrg->getBuf( COMPONENT_Y ) );
+      pcPicCurr->M_BUFS( 0, PIC_ORIGINAL_INPUT ).getBuf( COMPONENT_Cb ).copyFrom( pcPicYuvOrg->getBuf( COMPONENT_Cb ) );
+      pcPicCurr->M_BUFS( 0, PIC_ORIGINAL_INPUT ).getBuf( COMPONENT_Cr ).copyFrom( pcPicYuvOrg->getBuf( COMPONENT_Cr ) );
+
+      PelUnitBuf dst = pcPicCurr->getOrigBuf();
+      m_priProcess.packRegions(*pcPicYuvOrg, dst, *pSPS);
+    }
+#endif
     else
     {
       pcPicCurr->M_BUFS( 0, PIC_ORIGINAL ).swap( *pcPicYuvOrg );
@@ -1117,7 +1198,11 @@ void EncLib::xGetNewPicBuffer ( std::list<PelUnitBuf*>& rcListPicYuvRecOut, Pict
     rpcPic->create(sps.getWrapAroundEnabledFlag(), sps.getChromaFormatIdc(), Size(pps.getPicWidthInLumaSamples(), pps.getPicHeightInLumaSamples()),
       sps.getMaxCUWidth(), sps.getMaxCUWidth() + PIC_MARGIN, false, m_layerId, getShutterFilterFlag());
 
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+    if (m_resChangeInClvsEnabled || m_priSEIEnabled)
+#else
     if (m_resChangeInClvsEnabled)
+#endif
     {
       int thePPS = m_layerId;
       const PPS& pps0 = *m_ppsMap.getPS(thePPS);
@@ -1726,7 +1811,11 @@ void EncLib::xInitSPS( SPS& sps )
   sps.setInterLayerPresentFlag( m_layerId > 0 && m_vps->getMaxLayers() > 1 && !m_vps->getAllIndependentLayersFlag() && !m_vps->getIndependentLayerFlag( m_vps->getGeneralLayerIdx( m_layerId ) ) );
   CHECK( m_vps->getIndependentLayerFlag( m_vps->getGeneralLayerIdx( m_layerId ) ) && sps.getInterLayerPresentFlag(), " When vps_independent_layer_flag[GeneralLayerIdx[nuh_layer_id ]]  is equal to 1, the value of inter_layer_ref_pics_present_flag shall be equal to 0." );
 
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  sps.setResChangeInClvsEnabledFlag(m_resChangeInClvsEnabled || m_constrainedRaslEncoding || scalingWindowResChanged || m_priSEIEnabled);
+#else
   sps.setResChangeInClvsEnabledFlag(m_resChangeInClvsEnabled || m_constrainedRaslEncoding || scalingWindowResChanged);
+#endif
   sps.setRprEnabledFlag(m_rprEnabledFlag || m_explicitScalingWindowEnabled || scalingWindowResChanged);
   sps.setGOPBasedRPREnabledFlag(m_gopBasedRPREnabledFlag);
   sps.setLog2ParallelMergeLevelMinus2( m_log2ParallelMergeLevelMinus2 );
diff --git a/source/Lib/EncoderLib/EncLib.h b/source/Lib/EncoderLib/EncLib.h
index 72d42d07ae858bbd57524133e13c6a8e68085611..1a8779a16e933292a22160a6f08e45aa715b4217 100644
--- a/source/Lib/EncoderLib/EncLib.h
+++ b/source/Lib/EncoderLib/EncLib.h
@@ -60,6 +60,9 @@
 #include "EncTemporalFilter.h"
 
 #include "CommonLib/SEINeuralNetworkPostFiltering.h"
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+#include "CommonLib/SEIPackedRegionsInfoProcess.h"
+#endif
 
 class EncLibCommon;
 
@@ -141,6 +144,9 @@ private:
   EncTemporalFilter         m_temporalFilter;
   EncTemporalFilter         m_temporalFilterForFG;
   SEINeuralNetworkPostFiltering m_nnPostFiltering;
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  SEIPackedRegionsInfoProcess m_priProcess;
+#endif
 public:
   SPS*                      getSPS( int spsId ) { return m_spsMap.getPS( spsId ); };
   APS**                     getApss() { return m_apss; }
@@ -208,6 +214,10 @@ public:
   void setGMFAFile(std::string b){m_GMFAFile = b;}
 #endif
 
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  SEIPackedRegionsInfoProcess& getPriProcess() { return m_priProcess; }
+#endif
+
   void selectReferencePictureList(Slice *slice, int pocCurr, int gopId, int ltPoc);
 
   void                   setParamSetChanged(int spsId, int ppsId);
diff --git a/source/Lib/EncoderLib/SEIEncoder.cpp b/source/Lib/EncoderLib/SEIEncoder.cpp
index 507e7e4bbd5f8366a6fa9920e6f247f8d41877fd..f0748669b64fea378881185d6037ec4a2c4155ff 100644
--- a/source/Lib/EncoderLib/SEIEncoder.cpp
+++ b/source/Lib/EncoderLib/SEIEncoder.cpp
@@ -1934,4 +1934,58 @@ void SEIEncoder::initSEIConstituentRectanges(SEIConstituentRectangles* sei)
 }
 #endif
 
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+void SEIEncoder::initSEIPackedRegionsInfo(SEIPackedRegionsInfo* sei)
+{
+  CHECK(!m_isInitialized, "SEIPackedRegionsInfo already initialized");
+  CHECK(sei == nullptr, "Need a SEIPackedRegionsInfo for initialization (got nullptr)");
+
+  sei->m_cancelFlag = m_pcCfg->getPriSEICancelFlag();
+  sei->m_persistenceFlag = m_pcCfg->getPriSEIPersistenceFlag();
+  sei->m_numRegionsMinus1 = m_pcCfg->getPriSEINumRegionsMinus1();
+  sei->m_useMaxDimensionsFlag = m_pcCfg->getPriSEIUseMaxDimensionsFlag();
+  sei->m_log2UnitSize = m_pcCfg->getPriSEILog2UnitSize();
+  sei->m_regionSizeLenMinus1 = m_pcCfg->getPriSEIRegionSizeLenMinus1();
+  sei->m_regionIdPresentFlag = m_pcCfg->getPriSEIRegionIdPresentFlag();
+  sei->m_targetPicParamsPresentFlag = m_pcCfg->getPriSEITargetPicParamsPresentFlag();
+  sei->m_targetPicWidthMinus1 = m_pcCfg->getPriSEITargetPicWidthMinus1();
+  sei->m_targetPicHeightMinus1 = m_pcCfg->getPriSEITargetPicHeightMinus1();
+  sei->m_numResamplingRatiosMinus1 = m_pcCfg->getPriSEINumResamplingRatiosMinus1();
+
+  sei->m_resamplingWidthNumMinus1.resize(sei->m_numResamplingRatiosMinus1 + 1);
+  sei->m_resamplingWidthDenomMinus1.resize(sei->m_numResamplingRatiosMinus1 + 1);
+  sei->m_fixedAspectRatioFlag.resize(sei->m_numResamplingRatiosMinus1 + 1);
+  sei->m_resamplingHeightNumMinus1.resize(sei->m_numResamplingRatiosMinus1 + 1);
+  sei->m_resamplingHeightDenomMinus1.resize(sei->m_numResamplingRatiosMinus1 + 1);
+  for (uint32_t i = 0; i <= sei->m_numResamplingRatiosMinus1; i++)
+  {
+    sei->m_resamplingWidthNumMinus1[i] = m_pcCfg->getPriSEIResamplingWidthNumMinus1(i);
+    sei->m_resamplingWidthDenomMinus1[i] = m_pcCfg->getPriSEIResamplingWidthDenomMinus1(i);
+    sei->m_fixedAspectRatioFlag[i] = m_pcCfg->getPriSEIFixedAspectRatioFlag(i);
+    sei->m_resamplingHeightNumMinus1[i] = m_pcCfg->getPriSEIResamplingHeightNumMinus1(i);
+    sei->m_resamplingHeightDenomMinus1[i] = m_pcCfg->getPriSEIResamplingHeightDenomMinus1(i);
+  }
+
+  sei->m_regionId.resize(sei->m_numRegionsMinus1 + 1);
+  sei->m_regionTopLeftInUnitsX.resize(sei->m_numRegionsMinus1 + 1);
+  sei->m_regionTopLeftInUnitsY.resize(sei->m_numRegionsMinus1 + 1);
+  sei->m_regionWidthInUnitsMinus1.resize(sei->m_numRegionsMinus1 + 1);
+  sei->m_regionHeightInUnitsMinus1.resize(sei->m_numRegionsMinus1 + 1);
+  sei->m_resamplingRatioIdx.resize(sei->m_numRegionsMinus1 + 1);
+  sei->m_targetRegionTopLeftX.resize(sei->m_numRegionsMinus1 + 1);
+  sei->m_targetRegionTopLeftY.resize(sei->m_numRegionsMinus1 + 1);
+  for (uint32_t i = 0; i <= sei->m_numRegionsMinus1; i++)
+  {
+    sei->m_regionId[i] = m_pcCfg->getPriSEIRegionId(i);
+    sei->m_regionTopLeftInUnitsX[i] = m_pcCfg->getPriSEIRegionTopLeftInUnitsX(i);
+    sei->m_regionTopLeftInUnitsY[i] = m_pcCfg->getPriSEIRegionTopLeftInUnitsY(i);
+    sei->m_regionWidthInUnitsMinus1[i] = m_pcCfg->getPriSEIRegionWidthInUnitsMinus1(i);
+    sei->m_regionHeightInUnitsMinus1[i] = m_pcCfg->getPriSEIRegionHeightInUnitsMinus1(i);
+    sei->m_resamplingRatioIdx[i] = m_pcCfg->getPriSEIResamplingRatioIdx(i);
+    sei->m_targetRegionTopLeftX[i] = m_pcCfg->getPriSEITargetRegionTopLeftX(i);
+    sei->m_targetRegionTopLeftY[i] = m_pcCfg->getPriSEITargetRegionTopLeftY(i);
+  }
+}
+#endif
+
 //! \}
diff --git a/source/Lib/EncoderLib/SEIEncoder.h b/source/Lib/EncoderLib/SEIEncoder.h
index 0b6608e99aef2e959ed4310790a3ef71e28febe6..7e2f63e7bd1e71e7f3c958d081c8a4bae37dadc5 100644
--- a/source/Lib/EncoderLib/SEIEncoder.h
+++ b/source/Lib/EncoderLib/SEIEncoder.h
@@ -124,6 +124,9 @@ public:
 #if JVET_AH0162_CONSTITUENT_RECTANGLES
   void initSEIConstituentRectanges(SEIConstituentRectangles* sei);
 #endif
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  void initSEIPackedRegionsInfo(SEIPackedRegionsInfo *sei);
+#endif
 private:
   EncCfg* m_pcCfg;
   EncLib* m_pcEncLib;
diff --git a/source/Lib/EncoderLib/SEIwrite.cpp b/source/Lib/EncoderLib/SEIwrite.cpp
index 3296af8b7d56563c2a65cd56aec4185988b1999e..9a2461b71691753ef81ec7612bae0d65f35005e6 100644
--- a/source/Lib/EncoderLib/SEIwrite.cpp
+++ b/source/Lib/EncoderLib/SEIwrite.cpp
@@ -223,6 +223,11 @@ void SEIWriter::xWriteSEIpayloadData(OutputBitstream &bs, const SEI &sei, HRD &h
   case SEI::PayloadType::CONSTITUENT_RECTANGLES:
     xWriteSEIConstituentRectangles(*static_cast<const SEIConstituentRectangles*>(&sei));
     break;
+#endif
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  case SEI::PayloadType::PACKED_REGIONS_INFO:
+    xWriteSEIPackedRegionsInfo(*static_cast<const SEIPackedRegionsInfo*>(&sei));
+    break;
 #endif
   default:
     THROW("Trying to write unhandled SEI message");
@@ -2215,4 +2220,58 @@ void SEIWriter::xWriteSEIConstituentRectangles(const SEIConstituentRectangles& s
 }
 #endif
 
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+void SEIWriter::xWriteSEIPackedRegionsInfo(const SEIPackedRegionsInfo& sei)
+{
+  xWriteFlag(sei.m_cancelFlag, "pri_cancel_flag");
+  if (!sei.m_cancelFlag)
+  {
+    xWriteFlag(sei.m_persistenceFlag, "pri_persistence_flag");
+    xWriteUvlc(sei.m_numRegionsMinus1, "pri_num_regions_minus1");
+    xWriteFlag(sei.m_useMaxDimensionsFlag, "pri_use_max_dimensions_flag");
+    xWriteCode(sei.m_log2UnitSize, 4, "pri_log2_unit_size");
+    xWriteCode(sei.m_regionSizeLenMinus1, 4, "pri_region_size_len_minus1");
+    xWriteFlag(sei.m_regionIdPresentFlag, "pri_region_id_present_flag");
+    xWriteFlag(sei.m_targetPicParamsPresentFlag, "pri_target_pic_params_present_flag");
+    if (sei.m_targetPicParamsPresentFlag)
+    {
+      xWriteCode(sei.m_targetPicWidthMinus1, 16, "pri_target_pic_width_minus1");
+      xWriteCode(sei.m_targetPicHeightMinus1, 16, "pri_target_pic_height_minus1");
+    }
+    xWriteUvlc(sei.m_numResamplingRatiosMinus1, "pri_num_resampling_ratios_minus1");
+    for (uint32_t i = 1; i <= sei.m_numResamplingRatiosMinus1; i++)
+    {
+      xWriteUvlc(sei.m_resamplingWidthNumMinus1[i], "pri_resampling_width_num_minus1[i]");
+      xWriteUvlc(sei.m_resamplingWidthDenomMinus1[i], "pri_resampling_width_denom_minus1[i]");
+      xWriteFlag(sei.m_fixedAspectRatioFlag[i], "pri_fixed_aspect_ratio_flag[i]");
+      if (!sei.m_fixedAspectRatioFlag[i])
+      {
+        xWriteUvlc(sei.m_resamplingHeightNumMinus1[i], "pri_resampling_height_num_minus1[i]");
+        xWriteUvlc(sei.m_resamplingHeightDenomMinus1[i], "pri_resampling_height_denom_minus1[i]");
+      }
+    }
+    for (uint32_t i = 0; i <= sei.m_numRegionsMinus1; i++)
+    {
+      if (sei.m_regionIdPresentFlag)
+      {
+        xWriteUvlc(sei.m_regionId[i], "pri_region_id[i]");
+      }
+      xWriteCode(sei.m_regionTopLeftInUnitsX[i], sei.m_regionSizeLenMinus1 + 1, "pri_region_top_left_in_units_x[i]");
+      xWriteCode(sei.m_regionTopLeftInUnitsY[i], sei.m_regionSizeLenMinus1 + 1, "pri_region_top_left_in_units_y[i]");
+      xWriteCode(sei.m_regionWidthInUnitsMinus1[i], sei.m_regionSizeLenMinus1 + 1, "pri_region_width_in_units_minus1[i]");
+      xWriteCode(sei.m_regionHeightInUnitsMinus1[i], sei.m_regionSizeLenMinus1 + 1, "pri_region_height_in_units_minus1[i]");
+      if (sei.m_numResamplingRatiosMinus1 > 0)
+      {
+        xWriteCode(sei.m_resamplingRatioIdx[i], ceilLog2(sei.m_numResamplingRatiosMinus1 + 1), "pri_resampling_ratio_idx[i]");
+      }
+      if (sei.m_targetPicParamsPresentFlag)
+      {
+        xWriteCode(sei.m_targetRegionTopLeftX[i], sei.m_regionSizeLenMinus1 + 1, "pri_target_region_top_left_x[i]");
+        xWriteCode(sei.m_targetRegionTopLeftY[i], sei.m_regionSizeLenMinus1 + 1, "pri_target_region_top_left_y[i]");
+      }
+    }
+  }
+}
+#endif
+
 //! \}
diff --git a/source/Lib/EncoderLib/SEIwrite.h b/source/Lib/EncoderLib/SEIwrite.h
index b2b4a8750947371356f9b5c0c610bcd971353720..f19fef1833260239df412eebd4bd4b9936ad1906 100644
--- a/source/Lib/EncoderLib/SEIwrite.h
+++ b/source/Lib/EncoderLib/SEIwrite.h
@@ -132,6 +132,9 @@ protected:
 #if JVET_AH0162_CONSTITUENT_RECTANGLES
   void xWriteSEIConstituentRectangles(const SEIConstituentRectangles &sei);
 #endif
+#if JVET_AH0161_REGION_PACKING_INFORMATION_SEI
+  void xWriteSEIPackedRegionsInfo(const SEIPackedRegionsInfo& sei);
+#endif
 protected:
   HRD m_nestingHrd;
 };