diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp index 7ef205b856c9f01b64238b25a1723be2177ebce5..35534502401fc2287f763d4157f5fd25135ac681 100644 --- a/source/App/DecoderApp/DecApp.cpp +++ b/source/App/DecoderApp/DecApp.cpp @@ -124,6 +124,10 @@ uint32_t DecApp::decode() bool bPicSkipped = false; +#if JVET_S0155_EOS_NALU_CHECK + bool isEosPresentInPu = false; +#endif + while (!!bitstreamFile) { InputNALUnit nalu; @@ -194,6 +198,18 @@ uint32_t DecApp::decode() bPicSkipped = true; } } +#if JVET_S0155_EOS_NALU_CHECK + // once an EOS NAL unit appears in the current PU, mark the variable isEosPresentInPu as true + if (nalu.m_nalUnitType == NAL_UNIT_EOS) + { + isEosPresentInPu = true; + } + // within the current PU, only EOS and EOB are allowed to be sent after an EOS nal unit + if(isEosPresentInPu) + { + CHECK(nalu.m_nalUnitType != NAL_UNIT_EOS && nalu.m_nalUnitType != NAL_UNIT_EOB, "When an EOS NAL unit is present in a PU, it shall be the last NAL unit among all NAL units within the PU other than other EOS NAL units or an EOB NAL unit"); + } +#endif } if ((bNewPicture || !bitstreamFile || nalu.m_nalUnitType == NAL_UNIT_EOS) && !m_cDecLib.getFirstSliceInSequence(nalu.m_nuhLayerId) && !bPicSkipped) @@ -276,6 +292,10 @@ uint32_t DecApp::decode() { m_cDecLib.checkSeiInPictureUnit(); m_cDecLib.resetPictureSeiNalus(); +#if JVET_S0155_EOS_NALU_CHECK + // reset the EOS present status for the next PU check + isEosPresentInPu = false; +#endif } if (bNewPicture || !bitstreamFile || nalu.m_nalUnitType == NAL_UNIT_EOS) { diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index fcd9b8e242f52c2903ceac5abda413e09aceaa8f..1642c2b199835112615992adfc2e76c673c1eb63 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -67,6 +67,9 @@ #define JVET_S0065_SPS_INFERENCE_RULE 1 // JVET_S0065_PROPOSAL1: Inference rule for sps_virtual_boundaries_present_flag +#define JVET_S0155_EOS_NALU_CHECK 1 // JVET-S0155: Constraints on EOS NAL units + + //########### place macros to be be kept below this line ############### #define JVET_S0257_DUMP_360SEI_MESSAGE 1 // Software support of 360 SEI messages diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index 3fe5ead148584045af796b1f0b18d05445e2bd39..0ee14c9ff1154790e5ca5009b8f8174e4fe1603c 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -455,6 +455,9 @@ DecLib::DecLib() { #if ENABLE_SIMD_OPT_BUFFER g_pelBufOP.initPelBufOpsX86(); +#endif +#if JVET_S0155_EOS_NALU_CHECK + memset(m_prevEOS, false, sizeof(m_prevEOS)); #endif memset(m_accessUnitEos, false, sizeof(m_accessUnitEos)); for (int i = 0; i < MAX_VPS_LAYERS; i++) @@ -893,6 +896,19 @@ void DecLib::xCreateUnavailablePicture(int iUnavailablePoc, bool longTermFlag, c m_pocRandomAccess = iUnavailablePoc; } } +#if JVET_S0155_EOS_NALU_CHECK +void DecLib::checkPicTypeAfterEos() +{ + int layerId = m_pcPic->slices[0]->getNalUnitLayerId(); + if (m_prevEOS[layerId]) + { + bool isIrapOrGdrPu = !m_pcPic->cs->pps->getMixedNaluTypesInPicFlag() && ( m_pcPic->slices[0]->isIRAP() || m_pcPic->slices[0]->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR ); + CHECK(!isIrapOrGdrPu, "when present, the next PU of a particular layer after an EOS NAL unit that belongs to the same layer shall be an IRAP or GDR PU"); + + m_prevEOS[layerId] = false; + } +} +#endif void DecLib::checkLayerIdIncludedInCvss() { @@ -923,6 +939,28 @@ void DecLib::checkLayerIdIncludedInCvss() } CHECK(!layerIdFind, "each picture in an AU in a CVS shall have nuh_layer_id equal to the nuh_layer_id of one of the pictures present in the first AU of the CVS"); } + + +#if JVET_S0155_EOS_NALU_CHECK + // check whether the layerID of EOS_NUT is included in the layerIDs of the first AU + for (int i = 0; i < getVPS()->getMaxLayers(); i++) + { + int eosLayerId = getVPS()->getLayerId(i); + if (m_accessUnitEos[eosLayerId]) + { + bool eosLayerIdFind; + for (auto picFirst = m_firstAccessUnitPicInfo.begin(); picFirst != m_firstAccessUnitPicInfo.end(); picFirst++) + { + eosLayerIdFind = eosLayerId == picFirst->m_nuhLayerId ? true : false; + if (eosLayerIdFind) + { + break; + } + } + CHECK(!eosLayerIdFind, "When nal_unit_type is equal to EOS_NUT, nuh_layer_id shall be equal to one of the nuh_layer_id values of the layers present in the CVS"); + } + } +#endif } // update the value of m_isFirstAuInCvs for the next AU according to NAL_UNIT_EOS in each layer @@ -2181,6 +2219,9 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl m_pcPic->setDecodingOrderNumber(m_decodingOrderCounter); m_decodingOrderCounter++; m_pcPic->setPictureType(nalu.m_nalUnitType); +#if JVET_S0155_EOS_NALU_CHECK + checkPicTypeAfterEos(); +#endif // store sub-picture numbers, sizes, and locations with a picture pcSlice->getPic()->numSubpics = sps->getNumSubPics(); pcSlice->getPic()->subpicWidthInCTUs.clear(); @@ -2735,6 +2776,9 @@ bool DecLib::decode(InputNALUnit& nalu, int& iSkipFrame, int& iPOCLastDisplay, i m_prevSliceSkipped = false; m_skippedPOC = 0; m_accessUnitEos[nalu.m_nuhLayerId] = true; +#if JVET_S0155_EOS_NALU_CHECK + m_prevEOS[nalu.m_nuhLayerId] = true; +#endif return false; case NAL_UNIT_ACCESS_UNIT_DELIMITER: diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h index 6202c7de30e74073ef28cceb00e083d1e969552b..7279c30f0fec70ed027b39e908db49a71e14e9ce 100644 --- a/source/Lib/DecoderLib/DecLib.h +++ b/source/Lib/DecoderLib/DecLib.h @@ -85,6 +85,9 @@ private: int m_prevIRAPSubpicDecOrderNo[MAX_VPS_LAYERS][MAX_NUM_SUB_PICS]; int m_pocRandomAccess; ///< POC number of the random access point (the first IDR or CRA picture) int m_lastRasPoc; +#if JVET_S0155_EOS_NALU_CHECK + bool m_prevEOS[MAX_VPS_LAYERS]; +#endif PicList m_cListPic; // Dynamic buffer ParameterSetManager m_parameterSetManager; // storage for parameter sets @@ -217,6 +220,9 @@ public: void finishPictureLight(int& poc, PicList*& rpcListPic ); void checkNoOutputPriorPics (PicList* rpcListPic); void checkNalUnitConstraints( uint32_t naluType ); +#if JVET_S0155_EOS_NALU_CHECK + void checkPicTypeAfterEos(); +#endif void updateAssociatedIRAP(); void updatePrevGDRInSameLayer(); void updatePrevIRAPAndGDRSubpic();