diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp
index 6a503fec6b227a776a27de68ffc805b5852714d5..7c13731dfb649bfe2a75a885963504ccdac65f1a 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 };
 
@@ -1325,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();
@@ -1581,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
@@ -1887,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, char* paramName, const std::vector<uint32_t>& l)
+{
+  fprintf(fp, 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..6193799f73d04d02c5fd39ce96bd195a06774ec4 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, 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