From 3cdbf802e9cdf6b4bf0e0a07f02c57a4266fbef2 Mon Sep 17 00:00:00 2001 From: Vadim Seregin <vseregin@qti.qualcomm.com> Date: Mon, 27 Jan 2020 17:08:16 -0800 Subject: [PATCH] JVET-Q0814: DPB requirements as for a single layer --- source/App/DecoderApp/DecApp.cpp | 64 ++++++++++- source/App/DecoderApp/DecApp.h | 8 ++ source/App/DecoderApp/DecAppCfg.cpp | 4 +- source/App/DecoderApp/DecAppCfg.h | 2 +- source/App/EncoderApp/EncApp.cpp | 7 ++ source/App/EncoderApp/EncAppCfg.cpp | 4 +- source/App/EncoderApp/EncAppCfg.h | 3 + source/Lib/CommonLib/Slice.cpp | 158 ++++++++++++++++++++++++++- source/Lib/CommonLib/Slice.h | 66 ++++++++--- source/Lib/CommonLib/TypeDef.h | 1 + source/Lib/DecoderLib/DecLib.cpp | 26 ++++- source/Lib/DecoderLib/DecLib.h | 6 +- source/Lib/DecoderLib/VLCReader.cpp | 70 ++++++++++++ source/Lib/EncoderLib/EncCfg.h | 4 + source/Lib/EncoderLib/EncLib.cpp | 147 ++++++++++++++++++++++++- source/Lib/EncoderLib/EncLib.h | 14 ++- source/Lib/EncoderLib/EncLibCommon.h | 7 +- source/Lib/EncoderLib/VLCWriter.cpp | 52 +++++++++ 18 files changed, 614 insertions(+), 29 deletions(-) diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp index 69d4b1f7c..8d77c13a2 100644 --- a/source/App/DecoderApp/DecApp.cpp +++ b/source/App/DecoderApp/DecApp.cpp @@ -152,7 +152,11 @@ uint32_t DecApp::decode() } // parse NAL unit syntax if within target decoding layer +#if JVET_Q0814_DPB + if( ( m_iMaxTemporalLayer < 0 || nalu.m_temporalId <= m_iMaxTemporalLayer ) && xIsNaluWithinTargetDecLayerIdSet( &nalu ) ) +#else if ((m_iMaxTemporalLayer < 0 || nalu.m_temporalId <= m_iMaxTemporalLayer) && isNaluWithinTargetDecLayerIdSet(&nalu)) +#endif { if (bPicSkipped) { @@ -169,7 +173,13 @@ uint32_t DecApp::decode() m_cDecLib.decode(nalu, m_iSkipFrame, m_iPOCLastDisplay); if (nalu.m_nalUnitType == NAL_UNIT_VPS) { +#if JVET_Q0814_DPB + m_cDecLib.deriveTargetOutputLayerSet( m_targetOlsIdx ); + m_targetDecLayerIdSet = m_cDecLib.getVPS()->m_targetLayerIdSet; + m_targetOutputLayerIdSet = m_cDecLib.getVPS()->m_targetOutputLayerIdSet; +#else deriveOutputLayerSet(); +#endif } } else @@ -219,7 +229,11 @@ uint32_t DecApp::decode() } std::string reconFileName = m_reconFileName; +#if JVET_Q0814_DPB + if( m_reconFileName.compare( "/dev/null" ) && m_cDecLib.getVPS() != nullptr && m_cDecLib.getVPS()->getMaxLayers() > 1 && xIsNaluWithinTargetOutputLayerIdSet( &nalu ) ) +#else if (m_reconFileName.compare("/dev/null") && (m_cDecLib.getVPS() != nullptr) && (m_cDecLib.getVPS()->getMaxLayers() > 1) && (isNaluWithinTargetOutputLayerIdSet(&nalu))) +#endif { size_t pos = reconFileName.find_last_of('.'); if (pos != string::npos) @@ -231,10 +245,17 @@ uint32_t DecApp::decode() reconFileName.append( std::to_string( nalu.m_nuhLayerId ) ); } } +#if JVET_Q0814_DPB + if( ( m_cDecLib.getVPS() != nullptr && ( m_cDecLib.getVPS()->getMaxLayers() == 1 || xIsNaluWithinTargetOutputLayerIdSet( &nalu ) ) ) || m_cDecLib.getVPS() == nullptr ) + { + m_cVideoIOYuvReconFile[nalu.m_nuhLayerId].open( reconFileName, true, m_outputBitDepth, m_outputBitDepth, bitDepths.recon ); // write mode + } +#else if(((m_cDecLib.getVPS() != nullptr) && ((m_cDecLib.getVPS()->getMaxLayers() == 1) || (isNaluWithinTargetOutputLayerIdSet(&nalu)))) || (m_cDecLib.getVPS() == nullptr)) m_cVideoIOYuvReconFile[nalu.m_nuhLayerId].open(reconFileName, true, m_outputBitDepth, m_outputBitDepth, bitDepths.recon); // write mode +#endif } // write reconstruction to file if( bNewPicture ) @@ -279,6 +300,7 @@ uint32_t DecApp::decode() return nRet; } +#if !JVET_Q0814_DPB bool DecApp::deriveOutputLayerSet() { int vps_max_layers_minus1 = m_cDecLib.getVPS()->getMaxLayers() - 1; @@ -443,6 +465,7 @@ bool DecApp::deriveOutputLayerSet() return true; } +#endif /** - lookahead through next NAL units to determine if current NAL unit is the first NAL unit in a new picture @@ -703,6 +726,21 @@ void DecApp::xWriteOutput( PicList* pcListPic, uint32_t tId ) uint32_t maxDecPicBufferingHighestTid; uint32_t maxNrSublayers = activeSPS->getMaxTLayers(); +#if JVET_Q0814_DPB + const VPS* referredVPS = pcListPic->front()->cs->vps; + const int temporalId = ( m_iMaxTemporalLayer == -1 || m_iMaxTemporalLayer >= maxNrSublayers ) ? maxNrSublayers - 1 : m_iMaxTemporalLayer; + + if( referredVPS == nullptr || referredVPS->m_numLayersInOls[referredVPS->m_targetOlsIdx] == 1 ) + { + numReorderPicsHighestTid = activeSPS->getNumReorderPics( temporalId ); + maxDecPicBufferingHighestTid = activeSPS->getMaxDecPicBuffering( temporalId ); + } + else + { + numReorderPicsHighestTid = referredVPS->getNumReorderPics( temporalId ); + maxDecPicBufferingHighestTid = referredVPS->getMaxDecPicBuffering( temporalId ); + } +#else if(m_iMaxTemporalLayer == -1 || m_iMaxTemporalLayer >= maxNrSublayers) { numReorderPicsHighestTid = activeSPS->getNumReorderPics(maxNrSublayers-1); @@ -713,6 +751,7 @@ void DecApp::xWriteOutput( PicList* pcListPic, uint32_t tId ) numReorderPicsHighestTid = activeSPS->getNumReorderPics(m_iMaxTemporalLayer); maxDecPicBufferingHighestTid = activeSPS->getMaxDecPicBuffering(m_iMaxTemporalLayer); } +#endif while (iterPic != pcListPic->end()) { @@ -1020,6 +1059,29 @@ void DecApp::xFlushOutput( PicList* pcListPic, const int layerId ) /** \param nalu Input nalu to check whether its LayerId is within targetDecLayerIdSet */ +#if JVET_Q0814_DPB +bool DecApp::xIsNaluWithinTargetDecLayerIdSet( const InputNALUnit* nalu ) const +{ + if( !m_targetDecLayerIdSet.size() ) // By default, the set is empty, meaning all LayerIds are allowed + { + return true; + } + + return std::find( m_targetDecLayerIdSet.begin(), m_targetDecLayerIdSet.end(), nalu->m_nuhLayerId ) != m_targetDecLayerIdSet.end(); +} + +/** \param nalu Input nalu to check whether its LayerId is within targetOutputLayerIdSet + */ +bool DecApp::xIsNaluWithinTargetOutputLayerIdSet( const InputNALUnit* nalu ) const +{ + if( !m_targetOutputLayerIdSet.size() ) // By default, the set is empty, meaning all LayerIds are allowed + { + return true; + } + + return std::find( m_targetOutputLayerIdSet.begin(), m_targetOutputLayerIdSet.end(), nalu->m_nuhLayerId ) != m_targetOutputLayerIdSet.end(); +} +#else bool DecApp::isNaluWithinTargetDecLayerIdSet( InputNALUnit* nalu ) { if ( m_targetDecLayerIdSet.size() == 0 ) // By default, the set is empty, meaning all LayerIds are allowed @@ -1053,6 +1115,6 @@ bool DecApp::isNaluWithinTargetOutputLayerIdSet(InputNALUnit* nalu) } return false; } - +#endif //! \} diff --git a/source/App/DecoderApp/DecApp.h b/source/App/DecoderApp/DecApp.h index 2d5c0fcda..1675fc108 100644 --- a/source/App/DecoderApp/DecApp.h +++ b/source/App/DecoderApp/DecApp.h @@ -70,6 +70,12 @@ private: ColourRemapping m_cColourRemapping; ///< colour remapping handler #endif +#if JVET_Q0814_DPB +private: + bool xIsNaluWithinTargetDecLayerIdSet( const InputNALUnit* nalu ) const; ///< check whether given Nalu is within targetDecLayerIdSet + bool xIsNaluWithinTargetOutputLayerIdSet( const InputNALUnit* nalu ) const; ///< check whether given Nalu is within targetOutputLayerIdSet +#endif + public: DecApp(); virtual ~DecApp () {} @@ -81,9 +87,11 @@ private: void xDestroyDecLib (); ///< destroy internal classes void xWriteOutput ( PicList* pcListPic , uint32_t tId); ///< write YUV to file void xFlushOutput( PicList* pcListPic, const int layerId = NOT_VALID ); ///< flush all remaining decoded pictures to file +#if !JVET_Q0814_DPB bool isNaluWithinTargetDecLayerIdSet ( InputNALUnit* nalu ); ///< check whether given Nalu is within targetDecLayerIdSet bool isNaluWithinTargetOutputLayerIdSet(InputNALUnit* nalu); ///< check whether given Nalu is within targetOutputLayerIdSet bool deriveOutputLayerSet(); ///< derive OLS and layer sets +#endif bool isNewPicture(ifstream *bitstreamFile, class InputByteStream *bytestream); ///< check if next NAL unit will be the first NAL unit from a new picture bool isNewAccessUnit(bool newPicture, ifstream *bitstreamFile, class InputByteStream *bytestream); ///< check if next NAL unit will be the first NAL unit from a new access unit }; diff --git a/source/App/DecoderApp/DecAppCfg.cpp b/source/App/DecoderApp/DecAppCfg.cpp index 310251e87..fdd2bf7fa 100644 --- a/source/App/DecoderApp/DecAppCfg.cpp +++ b/source/App/DecoderApp/DecAppCfg.cpp @@ -87,7 +87,7 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] ) ("OutputBitDepthC,d", m_outputBitDepth[CHANNEL_TYPE_CHROMA], 0, "bit depth of YUV output chroma component (default: use luma output bit-depth)") ("OutputColourSpaceConvert", outputColourSpaceConvert, string(""), "Colour space conversion to apply to input 444 video. Permitted values are (empty string=UNCHANGED) " + getListOfColourSpaceConverts(false)) ("MaxTemporalLayer,t", m_iMaxTemporalLayer, -1, "Maximum Temporal Layer to be decoded. -1 to decode all layers") - ("TargetOutputLayerSet,p", m_iTargetOLS, -1, "Target output layer set.") + ("TargetOutputLayerSet,p", m_targetOlsIdx, -1, "Target output layer set index") ("SEIDecodedPictureHash,-dph",m_decodedPictureHashSEIEnabled, 1, "Control handling of decoded picture hash SEI messages\n" "\t1: check hash in SEI messages if available in the bitstream\n" "\t0: ignore SEI message") @@ -226,7 +226,7 @@ DecAppCfg::DecAppCfg() , m_iSkipFrame(0) // m_outputBitDepth array initialised below , m_outputColourSpaceConvert(IPCOLOURSPACE_UNCHANGED) -, m_iTargetOLS(0) +, m_targetOlsIdx(0) , m_iMaxTemporalLayer(-1) , m_decodedPictureHashSEIEnabled(0) , m_decodedNoDisplaySEIEnabled(false) diff --git a/source/App/DecoderApp/DecAppCfg.h b/source/App/DecoderApp/DecAppCfg.h index cc45bfdd8..d1f1fffb5 100644 --- a/source/App/DecoderApp/DecAppCfg.h +++ b/source/App/DecoderApp/DecAppCfg.h @@ -61,7 +61,7 @@ protected: int m_iSkipFrame; ///< counter for frames prior to the random access point to skip int m_outputBitDepth[MAX_NUM_CHANNEL_TYPE]; ///< bit depth used for writing output InputColourSpaceConversion m_outputColourSpaceConvert; - int m_iTargetOLS; ///< target output layer set + int m_targetOlsIdx; ///< target output layer set std::vector<int> m_targetOutputLayerIdSet; ///< set of LayerIds to be outputted int m_iMaxTemporalLayer; ///< maximum temporal layer to be decoded int m_decodedPictureHashSEIEnabled; ///< Checksum(3)/CRC(2)/MD5(1)/disable(0) acting on decoded picture hash SEI message diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 77f765178..40fa767e9 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -75,7 +75,12 @@ EncApp::~EncApp() void EncApp::xInitLibCfg() { +#if JVET_Q0814_DPB + VPS& vps = *m_cEncLib.getVPS(); + vps.m_targetOlsIdx = m_targetOlsIdx; +#else VPS vps; +#endif vps.setMaxLayers( m_maxLayers ); @@ -171,7 +176,9 @@ void EncApp::xInitLibCfg() } } vps.setVPSExtensionFlag ( false ); +#if !JVET_Q0814_DPB m_cEncLib.setVPS(&vps); +#endif m_cEncLib.setProfile ( m_profile); m_cEncLib.setLevel ( m_levelTier, m_level); m_cEncLib.setNumSubProfile ( m_numSubProfile ); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index cdad7cff4..3e09fc687 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -1364,7 +1364,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ( "SwitchPocPeriod", m_switchPocPeriod, 0, "Switch POC period for RPR" ) ( "UpscaledOutput", m_upscaledOutput, 0, "Output upscaled (2), decoded but in full resolution buffer (1) or decoded cropped (0, default) picture for RPR" ) ( "MaxLayers", m_maxLayers, 1, "Max number of layers" ) - +#if JVET_Q0814_DPB + ( "TargetOutputLayerSet,p", m_targetOlsIdx, -1, "Target output layer set index" ) +#endif ; opts.addOptions() ( "MaxSublayers", m_maxSublayers, 1, "Max number of Sublayers") diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 4ce37e402..f38ba8c10 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -677,6 +677,9 @@ protected: std::map<int, double> m_gopBasedTemporalFilterStrengths; ///< Filter strength per frame for the GOP-based Temporal Filter int m_maxLayers; +#if JVET_Q0814_DPB + int m_targetOlsIdx; +#endif int m_layerId[MAX_VPS_LAYERS]; int m_layerIdx; diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index e923fdf52..fd57555bd 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -1512,7 +1512,13 @@ VPS::VPS() , m_vpsEachLayerIsAnOlsFlag (1) , m_vpsOlsModeIdc (0) , m_vpsNumOutputLayerSets (1) -, m_vpsExtensionFlag() + , m_vpsExtensionFlag() +#if JVET_Q0814_DPB + , m_numDpbParams( 0 ) + , m_sublayerDpbParamsPresentFlag( false ) + , m_targetOlsIdx( -1 ) + , m_totalNumOLSs( 0 ) +#endif { for (int i = 0; i < MAX_VPS_LAYERS; i++) { @@ -1538,6 +1544,156 @@ VPS::~VPS() { } +#if JVET_Q0814_DPB +void VPS::deriveOutputLayerSets() +{ + if( m_uiMaxLayers == 1 ) + { + m_totalNumOLSs = 1; + } + else if( m_vpsEachLayerIsAnOlsFlag || m_vpsOlsModeIdc < 2 ) + { + m_totalNumOLSs = m_uiMaxLayers; + } + else if( m_vpsOlsModeIdc == 2 ) + { + m_totalNumOLSs = m_vpsNumOutputLayerSets; + } + + m_olsDpbParamsIdx.resize( m_totalNumOLSs ); + m_olsDpbPicSize.resize( m_totalNumOLSs, Size(0, 0) ); + m_numOutputLayersInOls.resize( m_totalNumOLSs ); + m_numLayersInOls.resize( m_totalNumOLSs ); + m_outputLayerIdInOls.resize( m_totalNumOLSs, std::vector<int>( m_uiMaxLayers, NOT_VALID ) ); + m_layerIdInOls.resize( m_totalNumOLSs, std::vector<int>( m_uiMaxLayers, NOT_VALID ) ); + + std::vector<int> numRefLayers( m_uiMaxLayers ); + std::vector<std::vector<int>> outputLayerIdx( m_totalNumOLSs, std::vector<int>( m_uiMaxLayers, NOT_VALID ) ); + std::vector<std::vector<int>> layerIncludedInOlsFlag( m_totalNumOLSs, std::vector<int>( m_uiMaxLayers, 0 ) ); + std::vector<std::vector<int>> dependencyFlag( m_uiMaxLayers, std::vector<int>( m_uiMaxLayers, NOT_VALID ) ); + std::vector<std::vector<int>> refLayerIdx( m_uiMaxLayers, std::vector<int>( m_uiMaxLayers, NOT_VALID ) ); + + for( int i = 0; i < m_uiMaxLayers; i++ ) + { + int r = 0; + + for( int j = 0; j < m_uiMaxLayers; j++ ) + { + dependencyFlag[i][j] = m_vpsDirectRefLayerFlag[i][j]; + + for( int k = 0; k < i; k++ ) + { + if( m_vpsDirectRefLayerFlag[i][k] && dependencyFlag[k][j] ) + { + dependencyFlag[i][j] = 1; + } + } + + if( dependencyFlag[i][j] ) + { + refLayerIdx[i][r++] = j; + } + } + + numRefLayers[i] = r; + } + + m_numOutputLayersInOls[0] = 1; + m_outputLayerIdInOls[0][0] = m_vpsLayerId[0]; + + for( int i = 1; i < m_totalNumOLSs; i++ ) + { + if( m_vpsEachLayerIsAnOlsFlag || m_vpsOlsModeIdc == 0 ) + { + m_numOutputLayersInOls[i] = 1; + m_outputLayerIdInOls[i][0] = m_vpsLayerId[i]; + } + else if( m_vpsOlsModeIdc == 1 ) + { + m_numOutputLayersInOls[i] = i + 1; + + for( int j = 0; j < m_numOutputLayersInOls[i]; j++ ) + { + m_outputLayerIdInOls[i][j] = m_vpsLayerId[j]; + } + } + else if( m_vpsOlsModeIdc == 2 ) + { + int j = 0; + for( int k = 0; k < m_uiMaxLayers; k++ ) + { + if( m_vpsOlsOutputLayerFlag[i][k] ) + { + layerIncludedInOlsFlag[i][k] = 1; + outputLayerIdx[i][j] = k; + m_outputLayerIdInOls[i][j++] = m_vpsLayerId[k]; + } + } + m_numOutputLayersInOls[i] = j; + + for( j = 0; j < m_numOutputLayersInOls[i]; j++ ) + { + int idx = outputLayerIdx[i][j]; + for( int k = 0; k < numRefLayers[idx]; k++ ) + { + layerIncludedInOlsFlag[i][refLayerIdx[idx][k]] = 1; + } + } + } + } + + m_numLayersInOls[0] = 1; + m_layerIdInOls[0][0] = m_vpsLayerId[0]; + + for( int i = 1; i < m_totalNumOLSs; i++ ) + { + if( m_vpsEachLayerIsAnOlsFlag ) + { + m_numLayersInOls[i] = 1; + m_layerIdInOls[i][0] = m_vpsLayerId[i]; + } + else if( m_vpsOlsModeIdc == 0 || m_vpsOlsModeIdc == 1 ) + { + m_numLayersInOls[i] = i + 1; + for( int j = 0; j < m_numLayersInOls[i]; j++ ) + { + m_layerIdInOls[i][j] = m_vpsLayerId[j]; + } + } + else if( m_vpsOlsModeIdc == 2 ) + { + int j = 0; + for( int k = 0; k < m_uiMaxLayers; k++ ) + { + if( layerIncludedInOlsFlag[i][k] ) + { + m_layerIdInOls[i][j++] = m_vpsLayerId[k]; + } + } + + m_numLayersInOls[i] = j; + } + } +} + +void VPS::deriveTargetOutputLayerSet( int targetOlsIdx ) +{ + m_targetOlsIdx = targetOlsIdx < 0 ? m_uiMaxLayers - 1 : targetOlsIdx; + m_targetOutputLayerIdSet.clear(); + m_targetLayerIdSet.clear(); + + for( int i = 0; i < m_numOutputLayersInOls[m_targetOlsIdx]; i++ ) + { + m_targetOutputLayerIdSet.push_back( m_outputLayerIdInOls[m_targetOlsIdx][i] ); + } + + for( int i = 0; i < m_numLayersInOls[m_targetOlsIdx]; i++ ) + { + m_targetLayerIdSet.push_back( m_layerIdInOls[m_targetOlsIdx][i] ); + } +} +#endif + // ------------------------------------------------------------------------------------------------ // Picture Header // ------------------------------------------------------------------------------------------------ diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index b95485113..7f042017e 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -71,6 +71,14 @@ typedef std::list<Picture*> PicList; // Class definition // ==================================================================================================================== +#if JVET_Q0814_DPB +struct DpbParameters +{ + int m_maxDecPicBuffering[MAX_TLAYER] = { 0 }; + int m_numReorderPics[MAX_TLAYER] = { 0 }; + int m_maxLatencyIncreasePlus1[MAX_TLAYER] = { 0 }; +}; +#endif class ReferencePictureList { @@ -748,8 +756,6 @@ public: const ProfileTierLevel& getProfileTierLevel(int idx) const { return m_profileTierLevel[idx]; } }; - - class VPS { private: @@ -773,6 +779,24 @@ private: uint32_t m_interLayerRefIdx[MAX_VPS_LAYERS][MAX_VPS_LAYERS]; bool m_vpsExtensionFlag; +#if JVET_Q0814_DPB + std::vector<Size> m_olsDpbPicSize; + std::vector<int> m_olsDpbParamsIdx; + std::vector<std::vector<int>> m_outputLayerIdInOls; +public: + int m_totalNumOLSs; + int m_numDpbParams; + std::vector<DpbParameters> m_dpbParameters; + bool m_sublayerDpbParamsPresentFlag; + std::vector<int> m_dpbMaxTemporalId; + std::vector<int> m_targetOutputLayerIdSet; ///< set of LayerIds to be outputted + std::vector<int> m_targetLayerIdSet; ///< set of LayerIds to be included in the sub-bitstream extraction process. + int m_targetOlsIdx; + std::vector<int> m_numOutputLayersInOls; + std::vector<int> m_numLayersInOls; + std::vector<std::vector<int>> m_layerIdInOls; +#endif + public: VPS(); @@ -824,6 +848,22 @@ public: bool getVPSExtensionFlag() const { return m_vpsExtensionFlag; } void setVPSExtensionFlag(bool t) { m_vpsExtensionFlag = t; } + +#if JVET_Q0814_DPB + int getMaxDecPicBuffering( int temporalId ) const { return m_dpbParameters[m_olsDpbParamsIdx[m_targetOlsIdx]].m_maxDecPicBuffering[temporalId]; } + int getNumReorderPics( int temporalId ) const { return m_dpbParameters[m_olsDpbParamsIdx[m_targetOlsIdx]].m_numReorderPics[temporalId]; } + int getTotalNumOLSs() const { return m_totalNumOLSs; } + Size getOlsDpbPicSize( int olsIdx ) const { return m_olsDpbPicSize[olsIdx]; } + void setOlsDpbPicSize( int olsIdx, Size size ) { m_olsDpbPicSize[olsIdx] = size; } + void setOlsDpbPicWidth( int olsIdx, int width ) { m_olsDpbPicSize[olsIdx].width = width; } + void setOlsDpbPicHeight( int olsIdx, int height ) { m_olsDpbPicSize[olsIdx].height = height; } + + int getOlsDpbParamsIdx( int olsIdx ) const { return m_olsDpbParamsIdx[olsIdx]; } + void setOlsDpbParamsIdx( int olsIdx, int paramIdx ) { m_olsDpbParamsIdx[olsIdx] = paramIdx; } + + void deriveOutputLayerSets(); + void deriveTargetOutputLayerSet( int targetOlsIdx ); +#endif }; class Window @@ -1092,13 +1132,13 @@ private: bool m_BdofControlPresentFlag; bool m_DmvrControlPresentFlag; bool m_ProfControlPresentFlag; - uint32_t m_uiBitsForPOC; - uint32_t m_numLongTermRefPicSPS; - uint32_t m_ltRefPicPocLsbSps[MAX_NUM_LONG_TERM_REF_PICS]; + uint32_t m_uiBitsForPOC; + uint32_t m_numLongTermRefPicSPS; + uint32_t m_ltRefPicPocLsbSps[MAX_NUM_LONG_TERM_REF_PICS]; bool m_usedByCurrPicLtSPSFlag[MAX_NUM_LONG_TERM_REF_PICS]; uint32_t m_log2MaxTbSize; - bool m_useWeightPred; //!< Use of Weighting Prediction (P_SLICE) - bool m_useWeightedBiPred; //!< Use of Weighting Bi-Prediction (B_SLICE) + bool m_useWeightPred; //!< Use of Weighting Prediction (P_SLICE) + bool m_useWeightedBiPred; //!< Use of Weighting Bi-Prediction (B_SLICE) bool m_saoEnabledFlag; @@ -1110,8 +1150,8 @@ private: unsigned m_numHorVirtualBoundaries; //!< number of horizontal virtual boundaries unsigned m_virtualBoundariesPosX[3]; //!< horizontal position of each vertical virtual boundary unsigned m_virtualBoundariesPosY[3]; //!< vertical position of each horizontal virtual boundary - uint32_t m_uiMaxDecPicBuffering[MAX_TLAYER]; - uint32_t m_uiMaxLatencyIncreasePlus1[MAX_TLAYER]; + uint32_t m_uiMaxDecPicBuffering[MAX_TLAYER]; + uint32_t m_uiMaxLatencyIncreasePlus1[MAX_TLAYER]; TimingInfo m_timingInfo; @@ -1364,10 +1404,10 @@ public: unsigned getVirtualBoundariesPosX(unsigned idx) const { CHECK( idx >= 3, "vitrual boundary index exceeds valid range" ); return m_virtualBoundariesPosX[idx]; } void setVirtualBoundariesPosY(unsigned u, unsigned idx) { CHECK( idx >= 3, "vitrual boundary index exceeds valid range" ); m_virtualBoundariesPosY[idx] = u; } unsigned getVirtualBoundariesPosY(unsigned idx) const { CHECK( idx >= 3, "vitrual boundary index exceeds valid range" ); return m_virtualBoundariesPosY[idx]; } - uint32_t getMaxDecPicBuffering(uint32_t tlayer) const { return m_uiMaxDecPicBuffering[tlayer]; } - void setMaxDecPicBuffering( uint32_t ui, uint32_t tlayer ) { CHECK(tlayer >= MAX_TLAYER, "Invalid T-layer"); m_uiMaxDecPicBuffering[tlayer] = ui; } - uint32_t getMaxLatencyIncreasePlus1(uint32_t tlayer) const { return m_uiMaxLatencyIncreasePlus1[tlayer]; } - void setMaxLatencyIncreasePlus1( uint32_t ui , uint32_t tlayer) { m_uiMaxLatencyIncreasePlus1[tlayer] = ui; } + uint32_t getMaxDecPicBuffering(uint32_t tlayer) const { return m_uiMaxDecPicBuffering[tlayer]; } + void setMaxDecPicBuffering( uint32_t ui, uint32_t tlayer ) { CHECK(tlayer >= MAX_TLAYER, "Invalid T-layer"); m_uiMaxDecPicBuffering[tlayer] = ui; } + uint32_t getMaxLatencyIncreasePlus1(uint32_t tlayer) const { return m_uiMaxLatencyIncreasePlus1[tlayer]; } + void setMaxLatencyIncreasePlus1( uint32_t ui , uint32_t tlayer) { m_uiMaxLatencyIncreasePlus1[tlayer] = ui; } void setAffineAmvrEnabledFlag( bool val ) { m_affineAmvrEnabledFlag = val; } bool getAffineAmvrEnabledFlag() const { return m_affineAmvrEnabledFlag; } diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 26ff96885..942f7ff00 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,6 +50,7 @@ #include <assert.h> #include <cassert> +#define JVET_Q0814_DPB 1 // JVET-Q0814: DPB capacity is based on picture units regardless of the resoltuion #define JVET_Q0147_JCCR_SIGNALLING 1 // JVET-Q0147: Conditional signaling of sps_joint_cbcr_enabled_flag based on ChromaArrayType diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index 6b62da634..de3141e9e 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -262,6 +262,15 @@ bool tryDecodePicture( Picture* pcEncPic, const int expectedPoc, const std::stri uint32_t maxNrSublayers = activeSPS->getMaxTLayers(); uint32_t numReorderPicsHighestTid = activeSPS->getNumReorderPics(maxNrSublayers-1); uint32_t maxDecPicBufferingHighestTid = activeSPS->getMaxDecPicBuffering(maxNrSublayers-1); +#if JVET_Q0814_DPB + const VPS* referredVPS = pcListPic->front()->cs->vps; + + if( referredVPS != nullptr && referredVPS->m_numLayersInOls[referredVPS->m_targetOlsIdx] > 1 ) + { + numReorderPicsHighestTid = referredVPS->getNumReorderPics( maxNrSublayers - 1 ); + maxDecPicBufferingHighestTid = referredVPS->getMaxDecPicBuffering( maxNrSublayers - 1 ); + } +#endif while (iterPic != pcListPic->end()) { @@ -491,7 +500,11 @@ void DecLib::deletePicBuffer ( ) Picture* DecLib::xGetNewPicBuffer( const SPS &sps, const PPS &pps, const uint32_t temporalLayer, const int layerId ) { Picture * pcPic = nullptr; +#if JVET_Q0814_DPB + m_iMaxRefPicNum = ( m_vps == nullptr || m_vps->m_numLayersInOls[m_vps->m_targetOlsIdx] == 1 ) ? sps.getMaxDecPicBuffering( temporalLayer ) : m_vps->getMaxDecPicBuffering( temporalLayer ); // m_uiMaxDecPicBuffering has the space for the picture currently being decoded +#else m_iMaxRefPicNum = sps.getMaxDecPicBuffering(temporalLayer); // m_uiMaxDecPicBuffering has the space for the picture currently being decoded +#endif if (m_cListPic.size() < (uint32_t)m_iMaxRefPicNum) { pcPic = new Picture(); @@ -1151,6 +1164,9 @@ void DecLib::xActivateParameterSets( const int layerId ) Slice *pSlice = m_pcPic->slices[m_uiSliceSegmentIdx]; const SPS *sps = pSlice->getSPS(); const PPS *pps = pSlice->getPPS(); +#if JVET_Q0814_DPB + const VPS *vps = pSlice->getVPS(); +#endif if( !sps->getUseWP() ) { @@ -1164,7 +1180,7 @@ void DecLib::xActivateParameterSets( const int layerId ) CHECK( ( pps->getPicWidthInLumaSamples() % ( std::max( 8, int( sps->getMaxCUWidth() >> ( sps->getMaxCodingDepth() - 1 ) ) ) ) ) != 0, "Coded frame width must be a multiple of Max(8, the minimum unit size)" ); CHECK( ( pps->getPicHeightInLumaSamples() % ( std::max( 8, int( sps->getMaxCUHeight() >> ( sps->getMaxCodingDepth() - 1 ) ) ) ) ) != 0, "Coded frame height must be a multiple of Max(8, the minimum unit size)" ); - if( !sps->getRprEnabledFlag() ) // subpics_present_flag is equal to 1 condition shall be added + if( !sps->getRprEnabledFlag() && sps->getSubPicPresentFlag() ) { CHECK( pps->getPicWidthInLumaSamples() != sps->getMaxPicWidthInLumaSamples(), "When subpics_present_flag is equal to 1 or ref_pic_resampling_enabled_flag equal to 0, the value of pic_width_in_luma_samples shall be equal to pic_width_max_in_luma_samples." ); CHECK( pps->getPicHeightInLumaSamples() != sps->getMaxPicHeightInLumaSamples(), "When subpics_present_flag is equal to 1 or ref_pic_resampling_enabled_flag equal to 0, the value of pic_height_in_luma_samples shall be equal to pic_height_max_in_luma_samples." ); @@ -1176,6 +1192,14 @@ void DecLib::xActivateParameterSets( const int layerId ) { CHECK( sps->getWrapAroundEnabledFlag(), "Wraparound shall be disabled when the value of ( CtbSizeY / MinCbSizeY + 1) is less than or equal to ( pic_width_in_luma_samples / MinCbSizeY - 1 )" ); } + +#if JVET_Q0814_DPB + if( vps->m_numOutputLayersInOls[vps->m_targetOlsIdx] > 1 ) + { + CHECK( sps->getMaxPicWidthInLumaSamples() > vps->getOlsDpbPicSize( vps->m_targetOlsIdx ).width, "pic_width_max_in_luma_samples shall be less than or equal to the value of ols_dpb_pic_width[ i ]" ); + CHECK( sps->getMaxPicHeightInLumaSamples() > vps->getOlsDpbPicSize( vps->m_targetOlsIdx ).height, "pic_height_max_in_luma_samples shall be less than or equal to the value of ols_dpb_pic_height[ i ]" ); + } +#endif } diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h index 7c9e0fa6b..304655f9a 100644 --- a/source/Lib/DecoderLib/DecLib.h +++ b/source/Lib/DecoderLib/DecLib.h @@ -106,7 +106,7 @@ private: #endif bool isRandomAccessSkipPicture(int& iSkipFrame, int& iPOCLastDisplay); Picture* m_pcPic; - uint32_t m_uiSliceSegmentIdx; + uint32_t m_uiSliceSegmentIdx; uint32_t m_prevLayerID; int m_prevPOC; int m_prevTid0POC; @@ -183,6 +183,10 @@ public: bool isSliceNaluFirstInAU( bool newPicture, InputNALUnit &nalu ); const VPS* getVPS() { return m_vps; } +#if JVET_Q0814_DPB + void deriveTargetOutputLayerSet( const int targetOlsIdx ) { if( m_vps != nullptr ) m_vps->deriveTargetOutputLayerSet( targetOlsIdx ); } +#endif + void initScalingList() { m_cTrQuantScalingList.init(nullptr, MAX_TB_SIZEY, false, false, false, false); diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index fd516bb03..9b3292a4d 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -1709,6 +1709,76 @@ void HLSyntaxReader::parseVPS(VPS* pcVPS) } } } + +#if JVET_Q0814_DPB + if( !pcVPS->getAllIndependentLayersFlag() ) + { + READ_UVLC( uiCode, "vps_num_dpb_params" ); pcVPS->m_numDpbParams = uiCode; + } + + if( pcVPS->m_numDpbParams > 0 && pcVPS->getMaxSubLayers() > 1 ) + { + READ_FLAG( uiCode, "vps_sublayer_dpb_params_present_flag" ); pcVPS->m_sublayerDpbParamsPresentFlag = uiCode; + } + + pcVPS->m_dpbParameters.resize( pcVPS->m_numDpbParams ); + + for( int i = 0; i < pcVPS->m_numDpbParams; i++ ) + { + if( pcVPS->getMaxSubLayers() == 1 ) + { + // When vps_max_sublayers_minus1 is equal to 0, the value of dpb_max_temporal_id[ i ] is inferred to be equal to 0. + pcVPS->m_dpbMaxTemporalId.push_back( 0 ); + } + else + { + if( pcVPS->getAllLayersSameNumSublayersFlag() ) + { + // When vps_max_sublayers_minus1 is greater than 0 and vps_all_layers_same_num_sublayers_flag is equal to 1, the value of dpb_max_temporal_id[ i ] is inferred to be equal to vps_max_sublayers_minus1. + pcVPS->m_dpbMaxTemporalId.push_back( pcVPS->getMaxSubLayers() - 1 ); + } + else + { + READ_CODE( 3, uiCode, "dpb_max_temporal_id[i]" ); pcVPS->m_dpbMaxTemporalId.push_back( uiCode ); + } + } + + for( int j = ( pcVPS->m_sublayerDpbParamsPresentFlag ? 0 : pcVPS->m_dpbMaxTemporalId[i] ); j <= pcVPS->m_dpbMaxTemporalId[i]; j++ ) + { + READ_UVLC( uiCode, "max_dec_pic_buffering_minus1[i]" ); pcVPS->m_dpbParameters[i].m_maxDecPicBuffering[j] = uiCode; + READ_UVLC( uiCode, "max_num_reorder_pics[i]" ); pcVPS->m_dpbParameters[i].m_numReorderPics[j] = uiCode; + READ_UVLC( uiCode, "max_latency_increase_plus1[i]" ); pcVPS->m_dpbParameters[i].m_maxLatencyIncreasePlus1[j] = uiCode; + } + + for( int j = ( pcVPS->m_sublayerDpbParamsPresentFlag ? pcVPS->m_dpbMaxTemporalId[i] : 0 ); j < pcVPS->m_dpbMaxTemporalId[i]; j++ ) + { + // When max_dec_pic_buffering_minus1[ i ] is not present for i in the range of 0 to maxSubLayersMinus1 - 1, inclusive, due to subLayerInfoFlag being equal to 0, it is inferred to be equal to max_dec_pic_buffering_minus1[ maxSubLayersMinus1 ]. + pcVPS->m_dpbParameters[i].m_maxDecPicBuffering[j] = pcVPS->m_dpbParameters[i].m_maxDecPicBuffering[pcVPS->m_dpbMaxTemporalId[i]]; + + // When max_num_reorder_pics[ i ] is not present for i in the range of 0 to maxSubLayersMinus1 - 1, inclusive, due to subLayerInfoFlag being equal to 0, it is inferred to be equal to max_num_reorder_pics[ maxSubLayersMinus1 ]. + pcVPS->m_dpbParameters[i].m_numReorderPics[j] = pcVPS->m_dpbParameters[i].m_numReorderPics[pcVPS->m_dpbMaxTemporalId[i]]; + + // When max_latency_increase_plus1[ i ] is not present for i in the range of 0 to maxSubLayersMinus1 - 1, inclusive, due to subLayerInfoFlag being equal to 0, it is inferred to be equal to max_latency_increase_plus1[ maxSubLayersMinus1 ]. + pcVPS->m_dpbParameters[i].m_maxLatencyIncreasePlus1[j] = pcVPS->m_dpbParameters[i].m_maxLatencyIncreasePlus1[pcVPS->m_dpbMaxTemporalId[i]]; + } + } + + pcVPS->deriveOutputLayerSets(); + + for( int i = 0; i < pcVPS->getTotalNumOLSs(); i++ ) + { + if( pcVPS->m_numLayersInOls[i] > 1 ) + { + READ_UVLC( uiCode, "ols_dpb_pic_width[i]" ); pcVPS->setOlsDpbPicWidth( i, uiCode ); + READ_UVLC( uiCode, "ols_dpb_pic_height[i]" ); pcVPS->setOlsDpbPicHeight( i, uiCode ); + if( pcVPS->m_numDpbParams > 1 ) + { + READ_UVLC( uiCode, "ols_dpb_params_idx[i]" ); pcVPS->setOlsDpbParamsIdx( i, uiCode ); + } + } + } +#endif + READ_FLAG(uiCode, "vps_extension_flag"); if (uiCode) { diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index f27bb3c10..dbfc776ab 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -628,7 +628,9 @@ protected: #endif CostMode m_costMode; ///< The cost function to use, primarily when considering lossless coding. +#if !JVET_Q0814_DPB VPS m_cVPS; +#endif DPS m_dps; bool m_decodingParameterSetEnabled; ///< enable decoding parameter set bool m_recalculateQPAccordingToLambda; ///< recalculate QP value according to the lambda value @@ -1652,8 +1654,10 @@ public: CostMode getCostMode( ) const { return m_costMode; } void setCostMode(CostMode m ) { m_costMode = m; } +#if !JVET_Q0814_DPB void setVPS(VPS *p) { m_cVPS = *p; } VPS * getVPS() { return &m_cVPS; } +#endif void setDPS(DPS *p) { m_dps = *p; } DPS* getDPS() { return &m_dps; } void setUseRecalculateQPAccordingToLambda (bool b) { m_recalculateQPAccordingToLambda = b; } diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index 3eb5c0846..ebe700b7b 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -68,6 +68,9 @@ EncLib::EncLib( EncLibCommon* encLibCommon ) , m_lmcsAPS(nullptr) , m_scalinglistAPS( nullptr ) , m_doPlt( true ) +#if JVET_Q0814_DPB + , m_vps( encLibCommon->getVPS() ) +#endif { m_iPOCLast = -1; m_iNumPicRcvd = 0; @@ -213,8 +216,13 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf ) aps0.setAPSType( SCALING_LIST_APS ); // initialize SPS +#if JVET_Q0814_DPB + xInitSPS( sps0 ); + xInitVPS( sps0 ); +#else xInitSPS( sps0, m_cVPS ); xInitVPS(m_cVPS, sps0); +#endif int dpsId = getDecodingParameterSetEnabled() ? 1 : 0; xInitDPS(m_dps, sps0, dpsId); @@ -419,7 +427,11 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf ) Picture *picBg = new Picture; picBg->create( sps0.getChromaFormatIdc(), Size( pps0.getPicWidthInLumaSamples(), pps0.getPicHeightInLumaSamples() ), sps0.getMaxCUWidth(), sps0.getMaxCUWidth() + 16, false, m_layerId ); picBg->getRecoBuf().fill(0); +#if JVET_Q0814_DPB + picBg->finalInit( m_vps, sps0, pps0, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); +#else picBg->finalInit( &m_cVPS, sps0, pps0, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); +#endif picBg->allocateNewSlice(); picBg->createSpliceIdx(pps0.pcv->sizeInCtus); m_cGOPEncoder.setPicBg(picBg); @@ -546,7 +558,11 @@ bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* cPicYu const SPS *sps = m_spsMap.getPS( pps->getSPSId() ); picCurr->M_BUFS( 0, PIC_ORIGINAL ).copyFrom( m_cGOPEncoder.getPicBg()->getRecoBuf() ); +#if JVET_Q0814_DPB + picCurr->finalInit( m_vps, *sps, *pps, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); +#else picCurr->finalInit( &m_cVPS, *sps, *pps, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); +#endif picCurr->poc = m_iPOCLast - 1; m_iPOCLast -= 2; if( getUseAdaptiveQP() ) @@ -602,7 +618,11 @@ bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* cPicYu } } +#if JVET_Q0814_DPB + if( m_vps->getMaxLayers() > 1 ) +#else if( m_cVPS.getMaxLayers() > 1 ) +#endif { ppsID = m_layerId; } @@ -657,7 +677,12 @@ bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* cPicYu pcPicCurr->M_BUFS( 0, PIC_ORIGINAL ).swap( *pcPicYuvOrg ); pcPicCurr->M_BUFS( 0, PIC_TRUE_ORIGINAL ).swap( *cPicYuvTrueOrg ); } + +#if JVET_Q0814_DPB + pcPicCurr->finalInit( m_vps, *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); +#else pcPicCurr->finalInit( &m_cVPS, *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); +#endif pcPicCurr->poc = m_iPOCLast; @@ -788,12 +813,15 @@ bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* pcPicY } } - { - int ppsID = -1; // Use default PPS ID - const PPS *pPPS = ( ppsID < 0 ) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS( ppsID ); - const SPS *pSPS = m_spsMap.getPS( pPPS->getSPSId() ); - pcField->finalInit( &m_cVPS, *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); - } + int ppsID = -1; // Use default PPS ID + const PPS *pPPS = ( ppsID < 0 ) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS( ppsID ); + const SPS *pSPS = m_spsMap.getPS( pPPS->getSPSId() ); + +#if JVET_Q0814_DPB + pcField->finalInit( m_vps, *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); +#else + pcField->finalInit( &m_cVPS, *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); +#endif pcField->poc = m_iPOCLast; pcField->reconstructed = false; @@ -881,7 +909,13 @@ void EncLib::xGetNewPicBuffer ( std::list<PelUnitBuf*>& rcListPicYuvRecOut, Pict Slice::sortPicList(m_cListPic); // use an entry in the buffered list if the maximum number that need buffering has been reached: +#if JVET_Q0814_DPB + int maxDecPicBuffering = ( m_vps == nullptr || m_vps->m_numLayersInOls[m_vps->m_targetOlsIdx] == 1 ) ? sps.getMaxDecPicBuffering( MAX_TLAYER - 1 ) : m_vps->getMaxDecPicBuffering( MAX_TLAYER - 1 ); + + if( m_cListPic.size() >= (uint32_t)( m_iGOPSize + maxDecPicBuffering + 2 ) ) +#else if( m_cListPic.size() >= (uint32_t)( m_iGOPSize + getMaxDecPicBuffering( MAX_TLAYER - 1 ) + 2 ) ) +#endif { PicList::iterator iterPic = m_cListPic.begin(); int iSize = int( m_cListPic.size() ); @@ -942,12 +976,96 @@ void EncLib::xGetNewPicBuffer ( std::list<PelUnitBuf*>& rcListPicYuvRecOut, Pict m_iNumPicRcvd++; } +#if JVET_Q0814_DPB +void EncLib::xInitVPS( const SPS& sps ) +{ + // The SPS must have already been set up. + // set the VPS profile information. + m_vps->setMaxSubLayers( sps.getMaxTLayers() ); + + m_vps->deriveOutputLayerSets(); + m_vps->deriveTargetOutputLayerSet( m_vps->m_targetOlsIdx ); + + if( !m_vps->getAllIndependentLayersFlag() ) + { + m_vps->m_numDpbParams = m_vps->m_totalNumOLSs; + } + + if( m_vps->m_dpbParameters.size() != m_vps->m_numDpbParams ) + { + m_vps->m_dpbParameters.resize( m_vps->m_numDpbParams ); + } + + if( m_vps->m_dpbMaxTemporalId.size() != m_vps->m_numDpbParams ) + { + m_vps->m_dpbMaxTemporalId.resize( m_vps->m_numDpbParams ); + } + + for( int i = 0; i < m_vps->m_numDpbParams; i++ ) + { + if( m_vps->getMaxSubLayers() == 1 ) + { + // When vps_max_sublayers_minus1 is equal to 0, the value of dpb_max_temporal_id[ i ] is inferred to be equal to 0. + m_vps->m_dpbMaxTemporalId[i] = 0; + } + else + { + if( m_vps->getAllLayersSameNumSublayersFlag() ) + { + // When vps_max_sublayers_minus1 is greater than 0 and vps_all_layers_same_num_sublayers_flag is equal to 1, the value of dpb_max_temporal_id[ i ] is inferred to be equal to vps_max_sublayers_minus1. + m_vps->m_dpbMaxTemporalId[i] = m_vps->getMaxSubLayers() - 1; + } + else + { + m_vps->m_dpbMaxTemporalId[i] = m_maxTempLayer; + } + } + + // accumulate DPB paramters from the SPS referring by each layer, inlucded into i-th OLS + if( std::find( m_vps->m_layerIdInOls[i].begin(), m_vps->m_layerIdInOls[i].end(), m_layerId ) != m_vps->m_layerIdInOls[i].end() ) + { + for( int j = ( m_vps->m_sublayerDpbParamsPresentFlag ? 0 : m_vps->m_dpbMaxTemporalId[i] ); j <= m_vps->m_dpbMaxTemporalId[i]; j++ ) + { + m_vps->m_dpbParameters[i].m_maxDecPicBuffering[j] += sps.getMaxDecPicBuffering( j ); + m_vps->m_dpbParameters[i].m_numReorderPics[j] += sps.getNumReorderPics( j ); + m_vps->m_dpbParameters[i].m_maxLatencyIncreasePlus1[j] += sps.getMaxLatencyIncreasePlus1( j ); + + CHECK( m_vps->m_dpbParameters[i].m_maxDecPicBuffering[j] >= MAX_NUM_REF_PICS, "max_dec_pic_buffering_minus1 exceeded MaxDpbSize" ); + } + + for( int j = ( m_vps->m_sublayerDpbParamsPresentFlag ? m_vps->m_dpbMaxTemporalId[i] : 0 ); j < m_vps->m_dpbMaxTemporalId[i]; j++ ) + { + // When max_dec_pic_buffering_minus1[ i ] is not present for i in the range of 0 to maxSubLayersMinus1 - 1, inclusive, due to subLayerInfoFlag being equal to 0, it is inferred to be equal to max_dec_pic_buffering_minus1[ maxSubLayersMinus1 ]. + m_vps->m_dpbParameters[i].m_maxDecPicBuffering[j] = m_vps->m_dpbParameters[i].m_maxDecPicBuffering[m_vps->m_dpbMaxTemporalId[i]]; + + // When max_num_reorder_pics[ i ] is not present for i in the range of 0 to maxSubLayersMinus1 - 1, inclusive, due to subLayerInfoFlag being equal to 0, it is inferred to be equal to max_num_reorder_pics[ maxSubLayersMinus1 ]. + m_vps->m_dpbParameters[i].m_numReorderPics[j] = m_vps->m_dpbParameters[i].m_numReorderPics[m_vps->m_dpbMaxTemporalId[i]]; + + // When max_latency_increase_plus1[ i ] is not present for i in the range of 0 to maxSubLayersMinus1 - 1, inclusive, due to subLayerInfoFlag being equal to 0, it is inferred to be equal to max_latency_increase_plus1[ maxSubLayersMinus1 ]. + m_vps->m_dpbParameters[i].m_maxLatencyIncreasePlus1[j] = m_vps->m_dpbParameters[i].m_maxLatencyIncreasePlus1[m_vps->m_dpbMaxTemporalId[i]]; + } + } + } + + for( int olsIdx = 0; olsIdx < m_vps->m_numOutputLayersInOls.size(); olsIdx++ ) + { + if( std::find( m_vps->m_layerIdInOls[olsIdx].begin(), m_vps->m_layerIdInOls[olsIdx].end(), m_layerId ) != m_vps->m_layerIdInOls[olsIdx].end() ) + { + m_vps->setOlsDpbPicWidth( olsIdx, std::max<int>( sps.getMaxPicWidthInLumaSamples(), m_vps->getOlsDpbPicSize( olsIdx ).width ) ); + m_vps->setOlsDpbPicHeight( olsIdx, std::max<int>( sps.getMaxPicHeightInLumaSamples(), m_vps->getOlsDpbPicSize( olsIdx ).height ) ); + } + + m_vps->setOlsDpbParamsIdx( olsIdx, olsIdx ); + } +} +#else void EncLib::xInitVPS(VPS& vps, const SPS& sps) { // The SPS must have already been set up. // set the VPS profile information. vps.setMaxSubLayers(sps.getMaxTLayers()); } +#endif void EncLib::xInitDPS(DPS &dps, const SPS &sps, const int dpsId) { @@ -961,7 +1079,11 @@ void EncLib::xInitDPS(DPS &dps, const SPS &sps, const int dpsId) dps.setProfileTierLevel(ptls); } +#if JVET_Q0814_DPB +void EncLib::xInitSPS( SPS& sps ) +#else void EncLib::xInitSPS( SPS& sps, VPS& vps ) +#endif { ProfileTierLevel* profileTierLevel = sps.getProfileTierLevel(); ConstraintInfo* cinfo = profileTierLevel->getConstraintInfo(); @@ -1018,7 +1140,11 @@ void EncLib::xInitSPS( SPS& sps, VPS& vps ) /* XXX: should Main be marked as compatible with still picture? */ /* XXX: may be a good idea to refactor the above into a function * that chooses the actual compatibility based upon options */ +#if JVET_Q0814_DPB + sps.setVPSId( m_vps->getVPSId() ); +#else sps.setVPSId(m_cVPS.getVPSId()); +#endif sps.setMaxPicWidthInLumaSamples( m_iSourceWidth ); sps.setMaxPicHeightInLumaSamples( m_iSourceHeight ); sps.setMaxCUWidth ( m_maxCUWidth ); @@ -1253,11 +1379,20 @@ void EncLib::xInitSPS( SPS& sps, VPS& vps ) sps.setVirtualBoundariesPosY ( m_virtualBoundariesPosY[i], i ); } +#if JVET_Q0814_DPB + sps.setInterLayerPresentFlag( m_vps->getMaxLayers() > 1 && !m_vps->getAllIndependentLayersFlag() ); + + for( int i = 0; i < m_vps->getMaxLayers(); ++i ) + { + //CHECK((m_vps->getIndependentLayerFlag(i) == 1) && (sps.getInterLayerPresentFlag() != 0), " 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."); + } +#else sps.setInterLayerPresentFlag( vps.getMaxLayers() > 1 && !vps.getAllIndependentLayersFlag() ); for (unsigned int i = 0; i < vps.getMaxLayers(); ++i) { CHECK((vps.getIndependentLayerFlag(i) == 1) && (sps.getInterLayerPresentFlag() != 0), " 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."); } +#endif sps.setRprEnabledFlag( m_rprEnabled || sps.getInterLayerPresentFlag() ); } diff --git a/source/Lib/EncoderLib/EncLib.h b/source/Lib/EncoderLib/EncLib.h index f9b13233e..12f8768a0 100644 --- a/source/Lib/EncoderLib/EncLib.h +++ b/source/Lib/EncoderLib/EncLib.h @@ -155,6 +155,10 @@ private: #endif int m_picIdInGOP; +#if JVET_Q0814_DPB + VPS* m_vps; +#endif + public: SPS* getSPS( int spsId ) { return m_spsMap.getPS( spsId ); }; APS** getApss() { return m_apss; } @@ -162,9 +166,14 @@ public: protected: void xGetNewPicBuffer ( std::list<PelUnitBuf*>& rcListPicYuvRecOut, Picture*& rpcPic, int ppsId ); ///< get picture buffer which will be processed. If ppsId<0, then the ppsMap will be queried for the first match. - void xInitVPS(VPS& vps, const SPS& sps); ///< initialize VPS from encoder options void xInitDPS (DPS &dps, const SPS &sps, const int dpsId); ///< initialize DPS from encoder options +#if JVET_Q0814_DPB + void xInitVPS( const SPS& sps ); ///< initialize VPS from encoder options + void xInitSPS( SPS& sps ); ///< initialize SPS from encoder options +#else + void xInitVPS(VPS& vps, const SPS& sps); ///< initialize VPS from encoder options void xInitSPS ( SPS& sps, VPS& vps ); ///< initialize SPS from encoder options +#endif void xInitPPS (PPS &pps, const SPS &sps); ///< initialize PPS from encoder options void xInitPicHeader (PicHeader &picHeader, const SPS &sps, const PPS &pps); ///< initialize Picture Header from encoder options void xInitAPS (APS &aps); ///< initialize APS from encoder options @@ -283,6 +292,9 @@ public: void printSummary( bool isField ) { m_cGOPEncoder.printOutSummary( m_uiNumAllPicCoded, isField, m_printMSEBasedSequencePSNR, m_printSequenceMSE, m_printHexPsnr, m_rprEnabled, m_spsMap.getFirstPS()->getBitDepths() ); } int getLayerId() const { return m_layerId; } +#if JVET_Q0814_DPB + VPS* getVPS() { return m_vps; } +#endif }; //! \} diff --git a/source/Lib/EncoderLib/EncLibCommon.h b/source/Lib/EncoderLib/EncLibCommon.h index 989fdf7e4..353b7410f 100644 --- a/source/Lib/EncoderLib/EncLibCommon.h +++ b/source/Lib/EncoderLib/EncLibCommon.h @@ -48,6 +48,9 @@ private: ParameterSetMap<PPS> m_ppsMap; ///< PPS, it is shared across all layers ParameterSetMap<APS> m_apsMap; ///< APS, it is shared across all layers PicList m_cListPic; ///< DPB, it is shared across all layers +#if JVET_Q0814_DPB + VPS m_vps; +#endif public: EncLibCommon(); @@ -58,6 +61,8 @@ public: ParameterSetMap<SPS>& getSpsMap() { return m_spsMap; } ParameterSetMap<PPS>& getPpsMap() { return m_ppsMap; } ParameterSetMap<APS>& getApsMap() { return m_apsMap; } - +#if JVET_Q0814_DPB + VPS* getVPS() { return &m_vps; } +#endif }; diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 4a1fdcc80..ef816e15f 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -1162,6 +1162,58 @@ void HLSWriter::codeVPS(const VPS* pcVPS) } } } + +#if JVET_Q0814_DPB + if( !pcVPS->getAllIndependentLayersFlag() ) + { + WRITE_UVLC( pcVPS->m_numDpbParams, "vps_num_dpb_params" ); + } + + if( pcVPS->m_numDpbParams > 0 && pcVPS->getMaxSubLayers() > 1 ) + { + WRITE_FLAG( pcVPS->m_sublayerDpbParamsPresentFlag, "vps_sublayer_dpb_params_present_flag" ); + } + + for( int i = 0; i < pcVPS->m_numDpbParams; i++ ) + { + if( pcVPS->getMaxSubLayers() == 1 ) + { + CHECK( pcVPS->m_dpbMaxTemporalId[i] != 0, "When vps_max_sublayers_minus1 is equal to 0, the value of dpb_max_temporal_id[ i ] is inferred to be equal to 0" ); + } + else + { + if( pcVPS->getAllLayersSameNumSublayersFlag() ) + { + CHECK( pcVPS->m_dpbMaxTemporalId[i] != pcVPS->getMaxSubLayers() - 1, "When vps_max_sublayers_minus1 is greater than 0 and vps_all_layers_same_num_sublayers_flag is equal to 1, the value of dpb_max_temporal_id[ i ] is inferred to be equal to vps_max_sublayers_minus1" ); + } + else + { + WRITE_CODE( pcVPS->m_dpbMaxTemporalId[i], 3, "dpb_max_temporal_id[i]" ); + } + } + + for( int j = ( pcVPS->m_sublayerDpbParamsPresentFlag ? 0 : pcVPS->m_dpbMaxTemporalId[i] ); j <= pcVPS->m_dpbMaxTemporalId[i]; j++ ) + { + WRITE_UVLC( pcVPS->m_dpbParameters[i].m_maxDecPicBuffering[j], "max_dec_pic_buffering_minus1[i]" ); + WRITE_UVLC( pcVPS->m_dpbParameters[i].m_numReorderPics[j], "max_num_reorder_pics[i]" ); + WRITE_UVLC( pcVPS->m_dpbParameters[i].m_maxLatencyIncreasePlus1[j], "max_latency_increase_plus1[i]" ); + } + } + + for( int i = 0; i < pcVPS->getTotalNumOLSs(); i++ ) + { + if( pcVPS->m_numLayersInOls[i] > 1 ) + { + WRITE_UVLC( pcVPS->getOlsDpbPicSize( i ).width, "ols_dpb_pic_width[i]" ); + WRITE_UVLC( pcVPS->getOlsDpbPicSize( i ).height, "ols_dpb_pic_height[i]" ); + if( pcVPS->m_numDpbParams > 1 ) + { + WRITE_UVLC( pcVPS->getOlsDpbParamsIdx( i ), "ols_dpb_params_idx[i]" ); + } + } + } +#endif + WRITE_FLAG(0, "vps_extension_flag"); //future extensions here.. -- GitLab