diff --git a/cfg/multi-layer/two_layers.cfg b/cfg/multi-layer/two_layers.cfg index 85dd7842a892e8617c939aad587838494bc7b415..5b18a5f3f9976caee637d47183197c3c170b3c68 100644 --- a/cfg/multi-layer/two_layers.cfg +++ b/cfg/multi-layer/two_layers.cfg @@ -1,6 +1,6 @@ #======== Layers =============== MaxLayers : 2 -MaxSublayers : 1 +MaxSublayers : 7 AllLayersSameNumSublayersFlag : 0 AllIndependentLayersFlag : 0 #======== OLSs =============== diff --git a/cfg/multi-layer/two_layers_max_tid_ref_pic.cfg b/cfg/multi-layer/two_layers_max_tid_ref_pic.cfg new file mode 100644 index 0000000000000000000000000000000000000000..99fb9a26f0d96f235bec9793c27fb110cd82a44c --- /dev/null +++ b/cfg/multi-layer/two_layers_max_tid_ref_pic.cfg @@ -0,0 +1,30 @@ +# example config file for MaxTidILRefPicsPlus1 +# combines with random-access GOP config file + +#======== Layers =============== +MaxLayers : 2 +MaxSublayers : 7 # allow up to 7 temporal layers +AllLayersSameNumSublayersFlag : 0 +AllIndependentLayersFlag : 0 + +MaxTidILRefPicsPlus1 : 3 # don't use pictures with temoporal_id > 2 for inter-layer reference +#======== OLSs =============== +EachLayerIsAnOlsFlag : 0 +OlsModeIdc : 2 +NumOutputLayerSets : 2 +OlsOutputLayer1 : 1 # only one output layer in OLS #1 +NumPTLsInVPS : 2 +#======== Layer-0 =============== +LayerId0 : 0 +#======== Layer-1 =============== +LayerId1 : 1 +NumRefLayers1 : 1 +RefLayerIdx1 : 0 +#======== OLS-0 =============== +OlsPTLIdx0 : 0 +#======== OLS-1 =============== +LevelPTL1 : 6.2 +OlsPTLIdx1 : 1 + + + diff --git a/doc/software-manual.tex b/doc/software-manual.tex index d5cd6a8bd0168e06c45eca7cf39968fba4cb080e..2cd15f91755bc5ac67c245676aec35c8b1d15a6d 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -1104,7 +1104,7 @@ Specifies the value to use to derive the vps_max_layers_minus1 for layered codin \Option{MaxSubLayers} & %\ShortOption{\None} & -\Default{1} & +\Default{7} & Specifies the maximum number of temporal sublayers to signal in the VPS \\ @@ -1192,6 +1192,12 @@ Specifies the index of the PTL that applies to the i-th OLS (with i an integer g Indicates that all OLSs are using the same (not nested) picture timing SEI message, i.e. picture timing SEI will not be included in scalable nesting SEI messages (if scalable nesting SEI is enabled). \\ + +\Option{MaxTidILRefPicsPlus1} & +%\ShortOption{\None} & +\Default{-1} & +Specifies the maximum temporal ID for inter-layer reference pictures plus 1. The value 0 allows only to use IRAP pictures for inter-layer prediction. +\\ \end{OptionTableNoShorthand} diff --git a/source/App/BitstreamExtractorApp/BitstreamExtractorApp.cpp b/source/App/BitstreamExtractorApp/BitstreamExtractorApp.cpp index 47d4618830b2c009b9dd3e72d59538e48ba89944..4ff1da950965cefa6f7f41fdbfaa8de427f8009f 100644 --- a/source/App/BitstreamExtractorApp/BitstreamExtractorApp.cpp +++ b/source/App/BitstreamExtractorApp/BitstreamExtractorApp.cpp @@ -356,6 +356,17 @@ void BitstreamExtractorApp::xWritePPS(PPS *pps, std::ostream& out, int layerId, writeAnnexB (out, tmpAu); } +#if JVET_Q0398_SUBLAYER_DEP +// returns true, if the NAL unit is to be discarded +bool BitstreamExtractorApp::xCheckNumSubLayers(InputNALUnit &nalu, VPS *vps) +{ + bool retval = (nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_IDR_N_LP) && (nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_IDR_W_RADL) && (nalu.m_nalUnitType != NAL_UNIT_CODED_SLICE_CRA); + + retval &= nalu.m_temporalId >= vps->getNumSubLayersInLayerInOLS(m_targetOlsIdx, vps->getGeneralLayerIdx(nalu.m_nuhLayerId)); + + return retval; +} +#endif uint32_t BitstreamExtractorApp::decode() { @@ -451,6 +462,9 @@ uint32_t BitstreamExtractorApp::decode() std::vector<int> layerIdInOls = vps->getLayerIdsInOls(m_targetOlsIdx); bool isIncludedInTargetOls = std::find(layerIdInOls.begin(), layerIdInOls.end(), nalu.m_nuhLayerId) != layerIdInOls.end(); writeInpuNalUnitToStream &= (isSpecialNalTypes || isIncludedInTargetOls); +#if JVET_Q0398_SUBLAYER_DEP + writeInpuNalUnitToStream &= !xCheckNumSubLayers(nalu, vps); +#endif #if JVET_Q0394_TIMING_SEI m_removeTimingSEI = !vps->getGeneralHrdParameters()->getGeneralSamePicTimingInAllOlsFlag(); #endif diff --git a/source/App/BitstreamExtractorApp/BitstreamExtractorApp.h b/source/App/BitstreamExtractorApp/BitstreamExtractorApp.h index 5ad386ac25c2dd2875bb27e4bcc28b74f69a63e7..f80d19770a6f5ab42dc6a7741243ec272f6a1c80 100644 --- a/source/App/BitstreamExtractorApp/BitstreamExtractorApp.h +++ b/source/App/BitstreamExtractorApp/BitstreamExtractorApp.h @@ -73,6 +73,10 @@ protected: bool xIsSPSUpdate(int spsId) { return (std::find(m_updatedSPSList.begin(),m_updatedSPSList.end(), spsId) != m_updatedSPSList.end()); } void xClearSPSUpdated(int spsId) { m_updatedSPSList.erase(std::remove(m_updatedSPSList.begin(), m_updatedSPSList.end(), spsId)); }; +#if JVET_Q0398_SUBLAYER_DEP + bool xCheckNumSubLayers(InputNALUnit &nalu, VPS *vps); +#endif + void xWriteVPS(VPS *vps, std::ostream& out, int layerId, int temporalId); void xWriteSPS(SPS *sps, std::ostream& out, int layerId, int temporalId); void xWritePPS(PPS *pps, std::ostream& out, int layerId, int temporalId); diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index cf379e3c07f9ca3f6febf94b1e30a08dffd0a9a1..a0d08c1f71b2a4611e78289272515864a0eb1de7 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -890,6 +890,10 @@ void EncApp::xInitLibCfg() #endif m_cEncLib.setGopBasedTemporalFilterEnabled(m_gopBasedTemporalFilterEnabled); m_cEncLib.setNumRefLayers ( m_numRefLayers ); + +#if JVET_Q0398_SUBLAYER_DEP + m_cEncLib.setVPSParameters(m_cfgVPSParameters); +#endif } void EncApp::xCreateLib( std::list<PelUnitBuf*>& recBufList, const int layerId ) diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index bd85d35cc91e050916d026f9993b0d876b03b5a5..69c32de88ec8ed12b502d086096c63970f97c0f4 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -1386,7 +1386,7 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ( "TargetOutputLayerSet,p", m_targetOlsIdx, -1, "Target output layer set index" ) ; opts.addOptions() - ( "MaxSublayers", m_maxSublayers, 1, "Max number of Sublayers") + ( "MaxSublayers", m_maxSublayers, 7, "Max number of Sublayers") ( "AllLayersSameNumSublayersFlag", m_allLayersSameNumSublayersFlag, true, "All layers same num sublayersflag") ( "AllIndependentLayersFlag", m_allIndependentLayersFlag, true, "All layers are independent layer") #if JVET_R0058 @@ -1400,6 +1400,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ( "NumOutputLayerSets", m_numOutputLayerSets, 1, "Number of output layer sets") ( "OlsOutputLayer%d", m_olsOutputLayerStr, string(""), MAX_VPS_LAYERS, "Output layer index of i-th OLS") ( "NumPTLsInVPS", m_numPtlsInVps, 1, "Number of profile_tier_level structures in VPS" ) +#if JVET_Q0398_SUBLAYER_DEP + ( "MaxTidILRefPicsPlus1", m_cfgVPSParameters.m_maxTidILRefPicsPlus1, -1, "Maximum temporal ID for inter-layer reference pictures plus 1, 0 for IRAP only" ) +#endif ; opts.addOptions() @@ -2861,6 +2864,9 @@ bool EncAppCfg::xCheckParameter() xConfirmPara( abs(m_sliceChromaQpOffsetIntraOrPeriodic[1] + m_crQpOffset ) > 12, "Intra/periodic Cr QP Offset, when combined with the PPS Cr offset, exceeds supported range (-12 to 12)" ); #endif + xConfirmPara( m_maxSublayers < 1 || m_maxSublayers > 7, "MaxSublayers must be in range [1..7]" ); + + xConfirmPara( m_fastLocalDualTreeMode < 0 || m_fastLocalDualTreeMode > 2, "FastLocalDualTreeMode must be in range [0..2]" ); int extraRPLs = 0; @@ -3467,7 +3473,6 @@ bool EncAppCfg::xCheckParameter() m_BIO = false; } - xConfirmPara( m_sariAspectRatioIdc < 0 || m_sariAspectRatioIdc > 255, "SEISARISampleAspectRatioIdc must be in the range of 0 to 255"); if ( m_RCEnableRateControl ) diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index f6acaea7a665463245ff66074586a7ae1a0dfb33..7d2f9bc6052729ecfb26a947950afee06a211644 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -607,7 +607,7 @@ protected: bool m_gcmpSEIGuardBandBoundaryExteriorFlag; uint32_t m_gcmpSEIGuardBandSamplesMinus1; - EncCfgParam::CfgSEISubpictureLevel m_cfgSubpictureLevelInfoSEI; + CfgSEISubpictureLevel m_cfgSubpictureLevelInfoSEI; bool m_sampleAspectRatioInfoSEIEnabled; bool m_sariCancelFlag; @@ -747,6 +747,10 @@ protected: std::string m_olsOutputLayerStr[MAX_VPS_LAYERS]; int m_numPtlsInVps; + +#if JVET_Q0398_SUBLAYER_DEP + CfgVPSParameters m_cfgVPSParameters; +#endif Level::Name m_levelPtl[MAX_NUM_OLSS]; int m_olsPtlIdx[MAX_NUM_OLSS]; diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp index 3f70b6e976fe3b73df8e37857ca78b79959ed0e7..4d30eb83fb1e49f5fa470aa6e022f688fb0e2b19 100644 --- a/source/Lib/CommonLib/Picture.cpp +++ b/source/Lib/CommonLib/Picture.cpp @@ -184,7 +184,7 @@ Picture::Picture() reconstructed = false; neededForOutput = false; referenced = false; - layer = std::numeric_limits<uint32_t>::max(); + temporalId = std::numeric_limits<uint32_t>::max(); fieldPic = false; topField = false; precedingDRAP = false; diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h index 771e69a13f1a3f20da8c9cd7e8bd23a8b8f897e8..8e9f05dea3469d566f7f1a4547d365c915030ae1 100644 --- a/source/Lib/CommonLib/Picture.h +++ b/source/Lib/CommonLib/Picture.h @@ -219,8 +219,7 @@ public: bool precedingDRAP; // preceding a DRAP picture in decoding order int poc; - uint32_t layer; - uint32_t depth; + uint32_t temporalId; int layerId; #if JVET_R0058 int numSubpics; diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index c0e4e92f31e09eaa7a5cb84a08c9d1cc7ba192f8..6eeb1a6d2977e0c94d30684108ea1303a9ec96f3 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -865,7 +865,7 @@ void Slice::checkSTSA(PicList& rcListPic) if( m_eNalUnitType == NAL_UNIT_CODED_SLICE_STSA && pcRefPic->layerId == m_pcPic->layerId ) { - CHECK( pcRefPic->layer == m_uiTLayer, "When the current picture is an STSA picture and nuh_layer_id equal to that of the current picture, there shall be no active entry in the RPL that has TemporalId equal to that of the current picture" ); + CHECK( pcRefPic->temporalId == m_uiTLayer, "When the current picture is an STSA picture and nuh_layer_id equal to that of the current picture, there shall be no active entry in the RPL that has TemporalId equal to that of the current picture" ); } // Checking this: "When the current picture is a picture that follows, in decoding order, an STSA picture that has TemporalId equal to that of the current picture, there shall be no @@ -880,7 +880,7 @@ void Slice::checkSTSA(PicList& rcListPic) if( m_eNalUnitType == NAL_UNIT_CODED_SLICE_STSA && pcRefPic->layerId == m_pcPic->layerId ) { - CHECK( pcRefPic->layer == m_uiTLayer, "When the current picture is an STSA picture and nuh_layer_id equal to that of the current picture, there shall be no active entry in the RPL that has TemporalId equal to that of the current picture" ); + CHECK( pcRefPic->temporalId == m_uiTLayer, "When the current picture is an STSA picture and nuh_layer_id equal to that of the current picture, there shall be no active entry in the RPL that has TemporalId equal to that of the current picture" ); } // Checking this: "When the current picture is a picture that follows, in decoding order, an STSA picture that has TemporalId equal to that of the current picture, there shall be no @@ -903,7 +903,7 @@ void Slice::checkSTSA(PicList& rcListPic) continue; } - if (pcRefPic->layer == m_uiTLayer) + if (pcRefPic->temporalId == m_uiTLayer) { pcRefPic->subLayerNonReferencePictureDueToSTSA = true; } @@ -1151,7 +1151,7 @@ bool Slice::isTemporalLayerSwitchingPoint(PicList& rcListPic) const const Picture* pcPic = *(iterPic++); if( pcPic->referenced && pcPic->poc != getPOC()) { - if( pcPic->layer >= getTLayer()) + if( pcPic->temporalId >= getTLayer()) { return false; } @@ -1170,7 +1170,7 @@ bool Slice::isStepwiseTemporalLayerSwitchingPointCandidate(PicList& rcListPic) c const Picture* pcPic = *(iterPic++); if( pcPic->referenced && pcPic->poc != getPOC()) { - if( pcPic->layer >= getTLayer()) + if( pcPic->temporalId >= getTLayer()) { return false; } @@ -1672,7 +1672,7 @@ void Slice::applyReferencePictureListBasedMarking( PicList& rcListPic, const Ref if (pcPic->referenced) { //check that pictures of higher temporal layers are not used - CHECK(pcPic->usedByCurr && !(pcPic->layer <= this->getTLayer()), "Invalid state"); + CHECK(pcPic->usedByCurr && !(pcPic->temporalId <= this->getTLayer()), "Invalid state"); } } } @@ -2148,6 +2148,9 @@ VPS::VPS() { m_vpsLayerId[i] = 0; m_vpsIndependentLayerFlag[i] = true; +#if JVET_Q0398_SUBLAYER_DEP + m_vpsMaxTidIlRefPicsPlus1[i] = 7; +#endif m_generalLayerIdx[i] = 0; for (int j = 0; j < MAX_VPS_LAYERS; j++) { @@ -2197,6 +2200,9 @@ void VPS::deriveOutputLayerSets() m_numOutputLayersInOls.resize( m_totalNumOLSs ); m_numLayersInOls.resize( m_totalNumOLSs ); m_outputLayerIdInOls.resize( m_totalNumOLSs, std::vector<int>( m_uiMaxLayers, NOT_VALID ) ); +#if JVET_Q0398_SUBLAYER_DEP + m_numSubLayersInLayerInOLS.resize( m_totalNumOLSs, std::vector<int>( m_uiMaxLayers, NOT_VALID ) ); +#endif m_layerIdInOls.resize( m_totalNumOLSs, std::vector<int>( m_uiMaxLayers, NOT_VALID ) ); #if JVET_R0066_DPB_NO_OUTPUT_PRIOR_PIC_FLAG m_olsDpbChromaFormatIdc.resize(m_totalNumOLSs); @@ -2242,6 +2248,9 @@ void VPS::deriveOutputLayerSets() m_numOutputLayersInOls[0] = 1; m_outputLayerIdInOls[0][0] = m_vpsLayerId[0]; +#if JVET_Q0398_SUBLAYER_DEP + m_numSubLayersInLayerInOLS[0][0] = m_vpsMaxSubLayers; +#endif layerUsedAsOutputLayerFlag[0] = 1; for (int i = 1; i < m_uiMaxLayers; i++) { @@ -2261,6 +2270,13 @@ void VPS::deriveOutputLayerSets() { m_numOutputLayersInOls[i] = 1; m_outputLayerIdInOls[i][0] = m_vpsLayerId[i]; +#if JVET_Q0398_SUBLAYER_DEP + for(int j = 0; j < i && ( m_vpsOlsModeIdc == 0 ); j++ ) + { + m_numSubLayersInLayerInOLS[i][j] = m_vpsMaxTidIlRefPicsPlus1[i]; + } + m_numSubLayersInLayerInOLS[i][i] = m_vpsMaxSubLayers; +#endif } else if( m_vpsOlsModeIdc == 1 ) { @@ -2269,11 +2285,21 @@ void VPS::deriveOutputLayerSets() for( int j = 0; j < m_numOutputLayersInOls[i]; j++ ) { m_outputLayerIdInOls[i][j] = m_vpsLayerId[j]; +#if JVET_Q0398_SUBLAYER_DEP + m_numSubLayersInLayerInOLS[i][j] = m_vpsMaxSubLayers; +#endif } } else if( m_vpsOlsModeIdc == 2 ) { int j = 0; +#if JVET_Q0398_SUBLAYER_DEP + for( j = 0; j < m_uiMaxLayers; j++ ) + { + m_numSubLayersInLayerInOLS[i][j] = 0; + } + j = 0; +#endif for( int k = 0; k < m_uiMaxLayers; k++ ) { if( m_vpsOlsOutputLayerFlag[i][k] ) @@ -2282,6 +2308,9 @@ void VPS::deriveOutputLayerSets() layerUsedAsOutputLayerFlag[k] = 1; outputLayerIdx[i][j] = k; m_outputLayerIdInOls[i][j++] = m_vpsLayerId[k]; +#if JVET_Q0398_SUBLAYER_DEP + m_numSubLayersInLayerInOLS[i][k] = m_vpsMaxSubLayers; +#endif } } m_numOutputLayersInOls[i] = j; @@ -2292,6 +2321,12 @@ void VPS::deriveOutputLayerSets() for( int k = 0; k < numRefLayers[idx]; k++ ) { layerIncludedInOlsFlag[i][refLayerIdx[idx][k]] = 1; +#if JVET_Q0398_SUBLAYER_DEP + if( m_numSubLayersInLayerInOLS[i][ refLayerIdx[idx][k] ] < m_vpsMaxTidIlRefPicsPlus1[ m_outputLayerIdInOls[i][j] ] ) + { + m_numSubLayersInLayerInOLS[i][ refLayerIdx[idx][k] ] = m_vpsMaxTidIlRefPicsPlus1[ m_outputLayerIdInOls[i][j] ]; + } +#endif } } } diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index 738072470ad26a52b8ea386911cdc7a16bf2ad80..f0826f1f6bd546ea80f07537e69342b1b3c97c63 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -949,6 +949,9 @@ private: #endif bool m_vpsIndependentLayerFlag[MAX_VPS_LAYERS]; bool m_vpsDirectRefLayerFlag[MAX_VPS_LAYERS][MAX_VPS_LAYERS]; +#if JVET_Q0398_SUBLAYER_DEP + uint32_t m_vpsMaxTidIlRefPicsPlus1[MAX_VPS_LAYERS]; +#endif bool m_vpsEachLayerIsAnOlsFlag; uint32_t m_vpsOlsModeIdc; uint32_t m_vpsNumOutputLayerSets; @@ -974,6 +977,9 @@ private: std::vector<Size> m_olsDpbPicSize; std::vector<int> m_olsDpbParamsIdx; std::vector<std::vector<int>> m_outputLayerIdInOls; +#if JVET_Q0398_SUBLAYER_DEP + std::vector<std::vector<int>> m_numSubLayersInLayerInOLS; +#endif public: std::vector<std::vector<OlsHrdParams>> m_olsHrdParams; int m_totalNumOLSs; @@ -1025,6 +1031,11 @@ public: bool getIndependentLayerFlag(uint32_t layerIdx) const { return m_vpsIndependentLayerFlag[layerIdx]; } void setIndependentLayerFlag(uint32_t layerIdx, bool t) { m_vpsIndependentLayerFlag[layerIdx] = t; } +#if JVET_Q0398_SUBLAYER_DEP + uint32_t getMaxTidIlRefPicsPlus1(uint32_t layerIdx) const { return m_vpsMaxTidIlRefPicsPlus1[layerIdx]; } + void setMaxTidIlRefPicsPlus1(uint32_t layerIdx, uint32_t i) { m_vpsMaxTidIlRefPicsPlus1[layerIdx] = i; } +#endif + bool getDirectRefLayerFlag(uint32_t layerIdx, uint32_t refLayerIdx) const { return m_vpsDirectRefLayerFlag[layerIdx][refLayerIdx]; } void setDirectRefLayerFlag(uint32_t layerIdx, uint32_t refLayerIdx, bool t) { m_vpsDirectRefLayerFlag[layerIdx][refLayerIdx] = t; } @@ -1115,6 +1126,10 @@ public: void setLayerIdInOls (int olsIdx, int layerIdx, int layerId) { m_layerIdInOls[olsIdx][layerIdx] = layerId; } uint32_t getLayerIdInOls (int olsIdx, int layerIdx) const { return m_layerIdInOls[olsIdx][layerIdx] ; } std::vector<int> getLayerIdsInOls(int targetOlsIdx) { return m_layerIdInOls[targetOlsIdx]; } + +#if JVET_Q0398_SUBLAYER_DEP + int getNumSubLayersInLayerInOLS (int olsIdx, int layerIdx) const { return m_numSubLayersInLayerInOLS[olsIdx][layerIdx] ; } +#endif }; class Window diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index b7f6483d9928845be825fff0ac876fc4e75b9002..08490c84fa60d989e93796604934f8161c7c9fbb 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -214,6 +214,8 @@ #define JVET_Q0394_TIMING_SEI 1 // JVET_Q0394: Picture timing for OLSs +#define JVET_Q0398_SUBLAYER_DEP 1 // JVET_Q0398: sub-layer dependency + #define JVET_Q0404_CBR_SUBPIC 1 // JVET_Q0404: Constant bitrate extraction for subpictures #define JVET_R0100 1 // JVET-R0100: Proposal 1 DUI Signalling and inference diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index 0b3f1c6a04e8be03545935acc1a217df1531dc62..06cfb4f34a5ebfd86c93983a767eae10ac377b3e 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -2234,10 +2234,9 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl Slice* pcSlice = m_pcPic->slices[m_uiSliceSegmentIdx]; pcSlice->setPic( m_pcPic ); m_pcPic->poc = pcSlice->getPOC(); - m_pcPic->layer = pcSlice->getTLayer(); m_pcPic->referenced = true; - m_pcPic->layer = nalu.m_temporalId; - m_pcPic->layerId = nalu.m_nuhLayerId; + m_pcPic->temporalId = nalu.m_temporalId; + m_pcPic->layerId = nalu.m_nuhLayerId; m_pcPic->subLayerNonReferencePictureDueToSTSA = false; #if JVET_R0194_CONSTRAINT_PS_SHARING_REFERENCING diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 75dbaa8b79e6e190bfc8e5f8e948ce7cba191d53..a4d1a75d8e298e06379bdaacb54a079212518966 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -2443,6 +2443,18 @@ void HLSyntaxReader::parseVPS(VPS* pcVPS) } } CHECK(sumUiCode == 0, "There has to be at least one value of j such that the value of vps_direct_dependency_flag[ i ][ j ] is equal to 1,when vps_independent_layer_flag[ i ] is equal to 0 "); +#if JVET_Q0398_SUBLAYER_DEP + READ_FLAG(uiCode, "max_tid_ref_present_flag[ i ]"); + if (uiCode) + { + READ_CODE(3, uiCode, "max_tid_il_ref_pics_plus1[ i ]"); + pcVPS->setMaxTidIlRefPicsPlus1(i, uiCode); + } + else + { + pcVPS->setMaxTidIlRefPicsPlus1(i, 7); + } +#endif } } } diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 5a2593e7786a6d6337edaee5c582b548fe502af9..05e943559878562d84217bb51e01807f0b46762b 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -49,6 +49,8 @@ #include "EncCfgParam.h" +using namespace EncCfgParam; + #if JVET_O0756_CALCULATE_HDRMETRICS #include "HDRLib/inc/DistortionMetric.H" #endif @@ -599,7 +601,7 @@ protected: uint8_t m_gcmpSEIGuardBandType; bool m_gcmpSEIGuardBandBoundaryExteriorFlag; uint8_t m_gcmpSEIGuardBandSamplesMinus1; - EncCfgParam::CfgSEISubpictureLevel m_cfgSubpictureLevelInfoSEI; + CfgSEISubpictureLevel m_cfgSubpictureLevelInfoSEI; bool m_sampleAspectRatioInfoSEIEnabled; bool m_sariCancelFlag; bool m_sariPersistenceFlag; @@ -739,7 +741,9 @@ protected: int m_debugCTU; ///< dbg ctu bool m_bs2ModPOCAndType; - +#if JVET_Q0398_SUBLAYER_DEP + CfgVPSParameters m_cfgVPSParameters; +#endif #if ENABLE_SPLIT_PARALLELISM int m_numSplitThreads; @@ -1637,8 +1641,8 @@ public: bool getGcmpSEIGuardBandBoundaryExteriorFlag() { return m_gcmpSEIGuardBandBoundaryExteriorFlag; } void setGcmpSEIGuardBandSamplesMinus1( uint8_t u ) { m_gcmpSEIGuardBandSamplesMinus1 = u; } uint8_t getGcmpSEIGuardBandSamplesMinus1() { return m_gcmpSEIGuardBandSamplesMinus1; } - const EncCfgParam::CfgSEISubpictureLevel getSubpicureLevelInfoSEICfg() const { return m_cfgSubpictureLevelInfoSEI; } - void setSubpicureLevelInfoSEICfg(EncCfgParam::CfgSEISubpictureLevel cfg) { m_cfgSubpictureLevelInfoSEI = cfg; } + const CfgSEISubpictureLevel& getSubpicureLevelInfoSEICfg() const { return m_cfgSubpictureLevelInfoSEI; } + void setSubpicureLevelInfoSEICfg(const CfgSEISubpictureLevel& cfg) { m_cfgSubpictureLevelInfoSEI = cfg; } bool getSampleAspectRatioInfoSEIEnabled() const { return m_sampleAspectRatioInfoSEIEnabled; } void setSampleAspectRatioInfoSEIEnabled(const bool val) { m_sampleAspectRatioInfoSEIEnabled = val; } bool getSariCancelFlag() const { return m_sariCancelFlag; } @@ -1967,6 +1971,11 @@ public: void setNumRefLayers( int* numRefLayers ) { std::memcpy( m_numRefLayers, numRefLayers, sizeof( m_numRefLayers ) ); } int getNumRefLayers( int layerIdx ) const { return m_numRefLayers[layerIdx]; } + +#if JVET_Q0398_SUBLAYER_DEP + const CfgVPSParameters& getVPSParameters() const { return m_cfgVPSParameters; } + void setVPSParameters(const CfgVPSParameters& cfg) { m_cfgVPSParameters = cfg; } +#endif }; //! \} diff --git a/source/Lib/EncoderLib/EncCfgParam.h b/source/Lib/EncoderLib/EncCfgParam.h index 13e5f839e0312c0d8ecbcab9a233aa56531163a8..020ad09bd6ec4a3647837478e543d3588533d8af 100644 --- a/source/Lib/EncoderLib/EncCfgParam.h +++ b/source/Lib/EncoderLib/EncCfgParam.h @@ -44,6 +44,20 @@ namespace EncCfgParam { +#if JVET_Q0398_SUBLAYER_DEP +class CfgVPSParameters +{ +public: + CfgVPSParameters() + : m_maxTidILRefPicsPlus1(-1) + {} + + virtual ~CfgVPSParameters(){} + + int m_maxTidILRefPicsPlus1; +}; +#endif + class CfgSEISubpictureLevel { public: diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index 3f5a08199ccbb245599490fb737ccb0b4752f42e..77d7fba771181fa72761b6bacf9b2d42baf9f898 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -1589,7 +1589,7 @@ void trySkipOrDecodePicture( bool& decPic, bool& encPic, const EncCfg& cfg, Pict // this is the forward to poc section static bool bHitFastForwardPOC = false; /* TODO: MT */ - if( bHitFastForwardPOC || isPicEncoded( cfg.getFastForwardToPOC(), pcPic->getPOC(), pcPic->layer, cfg.getGOPSize(), cfg.getIntraPeriod() ) ) + if( bHitFastForwardPOC || isPicEncoded( cfg.getFastForwardToPOC(), pcPic->getPOC(), pcPic->temporalId, cfg.getGOPSize(), cfg.getIntraPeriod() ) ) { bHitFastForwardPOC |= cfg.getFastForwardToPOC() == pcPic->getPOC(); // once we hit the poc we continue encoding @@ -5311,6 +5311,28 @@ void EncGOP::applyDeblockingFilterParameterSelection( Picture* pcPic, const uint } #endif +#if JVET_Q0398_SUBLAYER_DEP +bool EncGOP::xCheckMaxTidILRefPics(Picture* refPic, bool currentPicIsIRAP) +{ + const int maxTidILRefPicsPlus1 = m_pcCfg->getVPSParameters().m_maxTidILRefPicsPlus1; + + // -1 means not set + if (maxTidILRefPicsPlus1 < 0) + { + return true; + } + + // 0 allows only IRAP pictures to use inter-layer prediction + if (maxTidILRefPicsPlus1 == 0) + { + return currentPicIsIRAP; + } + + // all other cases filter by temporalID + return ( refPic->temporalId < maxTidILRefPicsPlus1 ); +} +#endif + void EncGOP::xCreateExplicitReferencePictureSetFromReference( Slice* slice, PicList& rcListPic, const ReferencePictureList *rpl0, const ReferencePictureList *rpl1 ) { Picture* rpcPic; @@ -5393,7 +5415,12 @@ void EncGOP::xCreateExplicitReferencePictureSetFromReference( Slice* slice, PicL { rpcPic = *( iterPic++ ); int refLayerIdx = vps->getGeneralLayerIdx( rpcPic->layerId ); +#if JVET_Q0398_SUBLAYER_DEP + if (rpcPic->referenced && rpcPic->getPOC() == pic->getPOC() && vps->getDirectRefLayerFlag(layerIdx, refLayerIdx) + && xCheckMaxTidILRefPics(rpcPic, slice->isIRAP()) ) +#else if (rpcPic->referenced && rpcPic->getPOC() == pic->getPOC() && vps->getDirectRefLayerFlag(layerIdx, refLayerIdx)) +#endif { pLocalRPL0->setRefPicIdentifier( refPicIdxL0, 0, true, true, vps->getInterLayerRefIdc( layerIdx, refLayerIdx ) ); refPicIdxL0++; @@ -5498,7 +5525,12 @@ void EncGOP::xCreateExplicitReferencePictureSetFromReference( Slice* slice, PicL { rpcPic = *( iterPic++ ); int refLayerIdx = vps->getGeneralLayerIdx( rpcPic->layerId ); +#if JVET_Q0398_SUBLAYER_DEP + if (rpcPic->referenced && rpcPic->getPOC() == pic->getPOC() && vps->getDirectRefLayerFlag(layerIdx, refLayerIdx) + && xCheckMaxTidILRefPics( rpcPic, slice->isIRAP() ) ) +#else if (rpcPic->referenced && rpcPic->getPOC() == pic->getPOC() && vps->getDirectRefLayerFlag(layerIdx, refLayerIdx)) +#endif { pLocalRPL1->setRefPicIdentifier( refPicIdxL1, 0, true, true, vps->getInterLayerRefIdc( layerIdx, refLayerIdx ) ); refPicIdxL1++; diff --git a/source/Lib/EncoderLib/EncGOP.h b/source/Lib/EncoderLib/EncGOP.h index 8b119e0e12646cdf5ba3c89ba408a8f8c64d8ef8..c3386d707de56ff94475a3febdd001a9b38b4c25 100644 --- a/source/Lib/EncoderLib/EncGOP.h +++ b/source/Lib/EncoderLib/EncGOP.h @@ -340,6 +340,9 @@ protected: void applyDeblockingFilterParameterSelection( Picture* pcPic, const uint32_t numSlices, const int gopID ); #endif void xCreateExplicitReferencePictureSetFromReference( Slice* slice, PicList& rcListPic, const ReferencePictureList *rpl0, const ReferencePictureList *rpl1 ); +#if JVET_Q0398_SUBLAYER_DEP + bool xCheckMaxTidILRefPics(Picture* refPic, bool currentPicIsIRAP); +#endif };// END CLASS DEFINITION EncGOP //! \} diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index 30b27752f429e6af4a404480cf474a679fa3d6b5..9be7d2a03a5dde64c39b4af6aa0c7128818ac286 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -1103,6 +1103,16 @@ void EncLib::xInitVPS( const SPS& sps ) } } } + +#if JVET_Q0398_SUBLAYER_DEP + if (m_cfgVPSParameters.m_maxTidILRefPicsPlus1 >= 0) + { + for (int i = 0; i < m_vps->getMaxLayers(); i++) + { + m_vps->setMaxTidIlRefPicsPlus1(i, m_cfgVPSParameters.m_maxTidILRefPicsPlus1); + } + } +#endif } void EncLib::xInitDCI(DCI& dci, const SPS& sps) diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp index f5a22f9f302c3f286b4a692f0129831f73d71ebd..60d94c0dd808b611647bc2e0789294d05fe1bdf0 100644 --- a/source/Lib/EncoderLib/EncSlice.cpp +++ b/source/Lib/EncoderLib/EncSlice.cpp @@ -703,12 +703,12 @@ void EncSlice::initEncSlice(Picture* pcPic, const int pocLast, const int pocCurr rpcSlice->setDeblockingFilterCrTcOffsetDiv2( 0 ); } - pcPic->layer = temporalId; + pcPic->temporalId = temporalId; if(eSliceType==I_SLICE) { - pcPic->layer = 0; + pcPic->temporalId = 0; } - rpcSlice->setTLayer( pcPic->layer ); + rpcSlice->setTLayer( pcPic->temporalId ); rpcSlice->setDisableSATDForRD(false); diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index ae0309c3232e398d19aa531d696f6dcaf3d15efe..c5ee7bac68a6bee83468b1d102125ed9bd7979ce 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -1557,6 +1557,14 @@ void HLSWriter::codeVPS(const VPS* pcVPS) { WRITE_FLAG(pcVPS->getDirectRefLayerFlag(i, j), "vps_direct_dependency_flag"); } +#if JVET_Q0398_SUBLAYER_DEP + bool presentFlag = ( pcVPS->getMaxTidIlRefPicsPlus1(i) != 7 ); + WRITE_FLAG(presentFlag, "max_tid_ref_present_flag[ i ]"); + if (presentFlag) + { + WRITE_CODE(pcVPS->getMaxTidIlRefPicsPlus1(i), 3, "max_tid_il_ref_pics_plus1[ i ]"); + } +#endif } } }