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; };