diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp index 8a15a0d49117e4d085f75c467d7bddd1ad0a1ec6..d41cff1692f25207d9d1385e392cf39dfb370fe6 100644 --- a/source/App/DecoderApp/DecApp.cpp +++ b/source/App/DecoderApp/DecApp.cpp @@ -270,6 +270,13 @@ uint32_t DecApp::decode() xWriteOutput( pcListPic, nalu.m_temporalId ); } } +#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP + if (bNewPicture || !bitstreamFile || nalu.m_nalUnitType == NAL_UNIT_EOS) + { + m_cDecLib.checkAPSInPictureUnit(); + m_cDecLib.resetPictureUnitNals(); + } +#endif if(bNewAccessUnit) { m_cDecLib.checkTidLayerIdInAccessUnit(); diff --git a/source/Lib/CommonLib/NAL.h b/source/Lib/CommonLib/NAL.h index 9e167bc790e85c3c2fc1cf49af324a887f54442c..f1605ce725c92e8e4d338817bd38a5c2a3155495 100644 --- a/source/Lib/CommonLib/NAL.h +++ b/source/Lib/CommonLib/NAL.h @@ -101,6 +101,24 @@ struct NALUnit || m_nalUnitType == NAL_UNIT_SUFFIX_SEI; } +#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP + bool isVcl() + { + return isVclNalUnitType(m_nalUnitType); + } + + static bool isVclNalUnitType(NalUnitType t) + { + return t == NAL_UNIT_CODED_SLICE_TRAIL + || t == NAL_UNIT_CODED_SLICE_STSA + || t == NAL_UNIT_CODED_SLICE_RADL + || t == NAL_UNIT_CODED_SLICE_RASL + || t == NAL_UNIT_CODED_SLICE_IDR_W_RADL + || t == NAL_UNIT_CODED_SLICE_IDR_N_LP + || t == NAL_UNIT_CODED_SLICE_CRA + || t == NAL_UNIT_CODED_SLICE_GDR; + } +#else bool isVcl() { return m_nalUnitType == NAL_UNIT_CODED_SLICE_TRAIL @@ -112,6 +130,7 @@ struct NALUnit || m_nalUnitType == NAL_UNIT_CODED_SLICE_CRA || m_nalUnitType == NAL_UNIT_CODED_SLICE_GDR; } +#endif }; struct OutputNALUnit; diff --git a/source/Lib/CommonLib/ParameterSetManager.h b/source/Lib/CommonLib/ParameterSetManager.h index 1824d492eee203f1dd974eb5aac8540aafc75efb..40d5a9ddfdc4685aa1c14941a39a4505bf3818b4 100644 --- a/source/Lib/CommonLib/ParameterSetManager.h +++ b/source/Lib/CommonLib/ParameterSetManager.h @@ -137,7 +137,21 @@ public: { CHECK( m_paramsetMap.find( apsId ) == m_paramsetMap.end(), "APS does not exist" ); APS* existedAPS = m_paramsetMap[apsId].parameterSet; - +#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP + bool sameNalUnitType = aps->getHasPrefixNalUnitType() == existedAPS->getHasPrefixNalUnitType(); + if( aps->getAPSType() == LMCS_APS ) + { + CHECK( sameNalUnitType && aps->getReshaperAPSInfo() != existedAPS->getReshaperAPSInfo(), "All APS NAL units with a particular value of nal_unit_type, a particular value of aps_adaptation_parameter_set_id, and a particular value of aps_params_type within a PU shall have the same content" ); + } + else if( aps->getAPSType() == ALF_APS ) + { + CHECK( sameNalUnitType && aps->getAlfAPSParam() != existedAPS->getAlfAPSParam(), "All APS NAL units with a particular value of nal_unit_type, a particular value of aps_adaptation_parameter_set_id, and a particular value of aps_params_type within a PU shall have the same content" ); + } + else if( aps->getAPSType() == SCALING_LIST_APS ) + { + CHECK( sameNalUnitType && aps->getScalingList() != existedAPS->getScalingList(), "All APS NAL units with a particular value of nal_unit_type, a particular value of aps_adaptation_parameter_set_id, and a particular value of aps_params_type within a PU shall have the same content" ); + } +#else if( aps->getAPSType() == LMCS_APS ) { CHECK( aps->getReshaperAPSInfo() != existedAPS->getReshaperAPSInfo(), "All APS NAL units with a particular value of adaptation_parameter_set_id and a particular value of aps_params_type within an access unit shall have the same content" ); @@ -150,6 +164,7 @@ public: { CHECK( aps->getScalingList() != existedAPS->getScalingList(), "All APS NAL units with a particular value of adaptation_parameter_set_id and a particular value of aps_params_type within an access unit shall have the same content" ); } +#endif else { CHECK( true, "Wrong APS type" ); diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index 65f2870b61bfeede0414a2f5f0bd6afcbfd38ace..c5ffa434b32fcfe610e5cd8f1aa38d2b809641be 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -2108,6 +2108,9 @@ private: SliceReshapeInfo m_reshapeAPSInfo; ScalingList m_scalingListApsInfo; CcAlfFilterParam m_ccAlfAPSParam; +#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP + bool m_hasPrefixNalUnitType; +#endif public: APS(); @@ -2132,7 +2135,12 @@ public: ScalingList& getScalingList() { return m_scalingListApsInfo; } void setCcAlfAPSParam(CcAlfFilterParam& ccAlfAPSParam) { m_ccAlfAPSParam = ccAlfAPSParam; } CcAlfFilterParam& getCcAlfAPSParam() { return m_ccAlfAPSParam; } +#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP + void setHasPrefixNalUnitType( bool b ) { m_hasPrefixNalUnitType = b; } + bool getHasPrefixNalUnitType() const { return m_hasPrefixNalUnitType; } +#endif }; + struct WPScalingParam { // Explicit weighted prediction parameters parsed in slice header, diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 0cb65647e1339579c0d9b929515296f7227456a7..e05227c83c9c18b539c2fb630a8ab0eb37bdbb28 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -89,6 +89,8 @@ #define JVET_R0202_WHEN_PH_IN_SH_INFO_FLAGS_EQUAL_0 1 // JVET-R0202 When sh_picture_header_in_slice_header_flag is equal to 1, rpl_info_in_ph_flag, dbf_info_in_ph_flag, sao_info_in_ph_flag, wp_info_in_ph_flag, qp_delta_info_in_ph_flag shall be be equal to 0 +#define JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP 1 // JVET-R0201 Cleanups on Prefix and Suffix APS + #define JVET_R0202_WHEN_PH_IN_SH_NO_SUBPIC_SEPARATE_COLOR 1 // JVET-R0202 Add constraints when sh_picture_header_in_slice_header_flag equal to 1 sps_subpic_info_present_flag and separate_colour_plane_flag shall be equal to 0 #define JVET_R0247_PPS_LP_FTR_ACROSS_SLICES_FLAG_CLEANUP 1 // JVET-R0247: Skip pps_loop_filter_across_slices_enabled_flag when the picture contains one slice diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index 34cf9a3344b0572e6496849cbac745cb62e0dace..3b0ea52c9ffeeb99cd4c3108d498244616056cb0 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -978,6 +978,30 @@ bool DecLib::isSliceNaluFirstInAU( bool newPicture, InputNALUnit &nalu ) return (m_apcSlicePilot->getPOC() != m_prevPOC); } +#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP +void DecLib::checkAPSInPictureUnit() +{ + bool firstVCLFound = false; + bool suffixAPSFound = false; + for (auto &nalu : m_pictureUnitNals) + { + if (NALUnit::isVclNalUnitType(nalu)) + { + firstVCLFound = true; + CHECK( suffixAPSFound, "When any suffix APS NAL units are present in a PU, they shall follow the last VCL unit of the PU" ); + } + else if (nalu == NAL_UNIT_PREFIX_APS) + { + CHECK( firstVCLFound, "When any prefix APS NAL units are present in a PU, they shall precede the first VCL unit of the PU"); + } + else if (nalu == NAL_UNIT_SUFFIX_APS) + { + suffixAPSFound = true; + } + } +} +#endif + void activateAPS(PicHeader* picHeader, Slice* pSlice, ParameterSetManager& parameterSetManager, APS** apss, APS* lmcsAPS, APS* scalingListAPS) { #if JVET_R0232_CCALF_APS_CONSTRAINT @@ -2177,6 +2201,9 @@ void DecLib::xDecodeAPS(InputNALUnit& nalu) m_HLSReader.parseAPS(aps); aps->setTemporalId(nalu.m_temporalId); aps->setLayerId( nalu.m_nuhLayerId ); +#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP + aps->setHasPrefixNalUnitType( nalu.m_nalUnitType == NAL_UNIT_PREFIX_APS ); +#endif m_parameterSetManager.checkAuApsContent( aps, m_accessUnitApsNals ); // aps will be deleted if it was already stored (and did not changed), @@ -2189,7 +2216,9 @@ bool DecLib::decode(InputNALUnit& nalu, int& iSkipFrame, int& iPOCLastDisplay, i // ignore all NAL units of layers > 0 m_accessUnitNals.push_back( std::pair<NalUnitType, int>( nalu.m_nalUnitType, nalu.m_temporalId ) ); - +#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP + m_pictureUnitNals.push_back( nalu.m_nalUnitType ); +#endif switch (nalu.m_nalUnitType) { case NAL_UNIT_VPS: diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h index c7ec5006f9dced19b86c08a2cfb28a2ebd635d8b..1b18ad0a03dad36adb18db8a57e47c3145932977 100644 --- a/source/Lib/DecoderLib/DecLib.h +++ b/source/Lib/DecoderLib/DecLib.h @@ -156,6 +156,11 @@ private: // NAL unit type, layer ID, and SEI payloadType std::vector<std::tuple<NalUnitType, int, SEI::PayloadType>> m_accessUnitSeiPayLoadTypes; + +#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP + std::vector<NalUnitType> m_pictureUnitNals; +#endif + VPS* m_vps; int m_maxDecSubPicIdx; int m_maxDecSliceAddrInSubPic; @@ -211,6 +216,11 @@ public: void checkSEIInAccessUnit(); bool isSliceNaluFirstInAU( bool newPicture, InputNALUnit &nalu ); +#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP + void checkAPSInPictureUnit(); + void resetPictureUnitNals() { m_pictureUnitNals.clear(); } +#endif + const VPS* getVPS() { return m_vps; } void deriveTargetOutputLayerSet( const int targetOlsIdx ) { if( m_vps != nullptr ) m_vps->deriveTargetOutputLayerSet( targetOlsIdx ); }