From bdb945b3ef3fd11f1f79d60fdbb6364cd669010c Mon Sep 17 00:00:00 2001 From: Karl Sharman <karl.sharman@sony.com> Date: Thu, 5 Mar 2020 10:38:05 +0000 Subject: [PATCH] Added Encoder-side DPB check The encoder will now warn if it is likely that the decoder's DPB will be exceeded. In addition it will display the state of the DPB (excluding the current frame being decoded). --- source/App/TAppEncoder/TAppEncCfg.cpp | 114 ++++++++++ source/App/TAppEncoder/TAppEncCfg.h | 3 + .../Lib/TLibCommon/TComProfileTierLevel.cpp | 210 ++++++++++++++++++ source/Lib/TLibCommon/TComProfileTierLevel.h | 161 ++++++++++++++ source/Lib/TLibCommon/TypeDef.h | 2 + source/Lib/TLibDecoder/TDecConformance.cpp | 36 ++- source/Lib/TLibDecoder/TDecConformance.h | 7 + 7 files changed, 532 insertions(+), 1 deletion(-) create mode 100644 source/Lib/TLibCommon/TComProfileTierLevel.cpp create mode 100644 source/Lib/TLibCommon/TComProfileTierLevel.h diff --git a/source/App/TAppEncoder/TAppEncCfg.cpp b/source/App/TAppEncoder/TAppEncCfg.cpp index 8d43bf51a..b28e0f23a 100644 --- a/source/App/TAppEncoder/TAppEncCfg.cpp +++ b/source/App/TAppEncoder/TAppEncCfg.cpp @@ -45,6 +45,9 @@ #include <map> #include "TLibCommon/TComRom.h" +#if DPB_ENCODER_USAGE_CHECK +#include "TLibCommon/TComProfileTierLevel.h" +#endif template <class T1, class T2> static inline std::istream& operator >> (std::istream &in, std::map<T1, T2> &map); @@ -335,12 +338,14 @@ strToLevel[] = {"8.5", Level::LEVEL8_5}, }; +#if !DPB_ENCODER_USAGE_CHECK UInt g_uiMaxCpbSize[2][21] = { // LEVEL1, LEVEL2,LEVEL2_1, LEVEL3, LEVEL3_1, LEVEL4, LEVEL4_1, LEVEL5, LEVEL5_1, LEVEL5_2, LEVEL6, LEVEL6_1, LEVEL6_2 { 0, 0, 0, 350000, 0, 0, 1500000, 3000000, 0, 6000000, 10000000, 0, 12000000, 20000000, 0, 25000000, 40000000, 60000000, 60000000, 120000000, 240000000 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30000000, 50000000, 0, 100000000, 160000000, 240000000, 240000000, 480000000, 800000000 } }; +#endif static const struct MapStrToCostMode { @@ -2217,6 +2222,13 @@ Void TAppEncCfg::xCheckParameter() } #endif +#if DPB_ENCODER_USAGE_CHECK + ProfileLevelTierFeatures profileLevelTierFeatures; + profileLevelTierFeatures.activate(m_profile, m_bitDepthConstraint, m_chromaFormatConstraint, m_intraConstraintFlag, m_onePictureOnlyConstraintFlag, + m_level, m_levelTier, + m_uiMaxCUWidth, m_internalBitDepth[CHANNEL_TYPE_LUMA], m_internalBitDepth[CHANNEL_TYPE_CHROMA], m_chromaFormatIDC); +#endif + xConfirmPara( (m_MSBExtendedBitDepth[CHANNEL_TYPE_LUMA ] < m_inputBitDepth[CHANNEL_TYPE_LUMA ]), "MSB-extended bit depth for luma channel (--MSBExtendedBitDepth) must be greater than or equal to input bit depth for luma channel (--InputBitDepth)" ); xConfirmPara( (m_MSBExtendedBitDepth[CHANNEL_TYPE_CHROMA] < m_inputBitDepth[CHANNEL_TYPE_CHROMA]), "MSB-extended bit depth for chroma channel (--MSBExtendedBitDepthC) must be greater than or equal to input bit depth for chroma channel (--InputBitDepthC)" ); @@ -2532,6 +2544,9 @@ Void TAppEncCfg::xCheckParameter() else { //create a new GOPEntry for this frame containing all the reference pictures that were available (POC > 0) +#if DPB_ENCODER_USAGE_CHECK + assert(m_iGOPSize+m_extraRPSs < MAX_GOP); +#endif m_GOPList[m_iGOPSize+m_extraRPSs]=m_GOPList[curGOP]; Int newRefs=0; for(Int i = 0; i< m_GOPList[curGOP].m_numRefPics; i++) @@ -2728,6 +2743,21 @@ Void TAppEncCfg::xCheckParameter() m_maxDecPicBuffering[MAX_TLAYER-1] = m_numReorderPics[MAX_TLAYER-1] + 1; } +#if DPB_ENCODER_USAGE_CHECK + // Check DPB Usage: + Int dpbSize=profileLevelTierFeatures.getMaxDPBNumFrames(m_iSourceWidth*m_iSourceHeight); + if (dpbSize!=-1) + { + Int dpbUsage=xDPBUsage(0); + + if (dpbUsage > dpbSize) + { + std::cout << "WARNING - DPB SIZE (" << dpbSize << " pictures) IS LIKELY TO HAVE BEEN EXCEEDED:\n"; + xDPBUsage(&(std::cout)); + } + } +#endif + if(m_vuiParametersPresentFlag && m_bitstreamRestrictionFlag) { Int PicSizeInSamplesY = m_iSourceWidth * m_iSourceHeight; @@ -2849,10 +2879,16 @@ Void TAppEncCfg::xCheckParameter() } } xConfirmPara( m_uiDeltaQpRD > 0, "Rate control cannot be used together with slice level multiple-QP optimization!\n" ); +#if DPB_ENCODER_USAGE_CHECK + if ((m_RCCpbSaturationEnabled) && profileLevelTierFeatures.getCpbSizeInBits()!=0) + { + xConfirmPara(m_RCCpbSize > profileLevelTierFeatures.getCpbSizeInBits(), "RCCpbSize should be smaller than or equal to Max CPB size according to tier and level"); +#else if ((m_RCCpbSaturationEnabled) && (m_level!=Level::NONE) && (m_profile!=Profile::NONE)) { UInt uiLevelIdx = (m_level / 10) + (UInt)((m_level % 10) / 3); // (m_level / 30)*3 + ((m_level % 10) / 3); xConfirmPara(m_RCCpbSize > g_uiMaxCpbSize[m_levelTier][uiLevelIdx], "RCCpbSize should be smaller than or equal to Max CPB size according to tier and level"); +#endif xConfirmPara(m_RCInitialCpbFullness > 1, "RCInitialCpbFullness should be smaller than or equal to 1"); } } @@ -2980,6 +3016,84 @@ const TChar *profileToString(const Profile::Name profile) return ""; } +#if DPB_ENCODER_USAGE_CHECK + +Int TAppEncCfg::xDPBUsage(std::ostream *pOs) +{ + Int minimumOffset=0; + + // Calculate minimum delay caused by the gop structure - i.e. the biggest positive difference between the decoding and display order. + + for(Int gopEntry=0; gopEntry<m_iGOPSize; gopEntry++) + { + Int poc=m_GOPList[gopEntry].m_POC; + minimumOffset=std::max<Int>(minimumOffset, gopEntry-poc); + } + + if (pOs) + { + (*pOs) << "POCs marked with 'r' are reference frames. '!' are awaiting output.\n"; + } + + Int maxNumInDPB=0; + for(Int gopEntry=0; gopEntry<m_iGOPSize; gopEntry++) + { + if (pOs) + { + (*pOs) << "DPB Usage for GOP#" << std::setw(3) << gopEntry+1 << ": POC=" + << std::setw(3) << m_GOPList[gopEntry].m_POC << " Decoder output POC=" << std::setw(4) << gopEntry-minimumOffset << " frames= "; + for(Int i=0; i<m_GOPList[gopEntry].m_numRefPics; i++) + { + Int rplPoc=m_GOPList[gopEntry].m_referencePics[i]+m_GOPList[gopEntry].m_POC; + (*pOs) << " r" << std::setw(3) << rplPoc; + } + } + Int numInDPB=m_GOPList[gopEntry].m_numRefPics + 1; // 1 additional one required for the frame currently being decoded. + // When decoding gopEntry N, the decoder will be outputing POC N-minimumOffset, and we must make sure all POCs in the range (POC N-minimumOffset to POC N) are allocated space in the DPB. + // When decoding gopEntry N+minimumOffset, the decoder will be outputing POC N + for(Int n=gopEntry-minimumOffset; n<=gopEntry; n++) + { + // check if 'n' exists in the reference picture lists: + Bool bNeeded=true; + for(Int i=0; i<m_GOPList[gopEntry].m_numRefPics && bNeeded; i++) + { + Int rplPoc=m_GOPList[gopEntry].m_referencePics[i]+m_GOPList[gopEntry].m_POC; + bNeeded=(rplPoc!=n); + } + if (bNeeded && n>=0) + { + // 'n' is positive, so check that it has already been decoded within this GOP. + bNeeded=false; + for(Int i=0; i<gopEntry && !bNeeded; i++) + { + bNeeded=m_GOPList[i].m_POC == n; + } + + } + if (bNeeded) + { + numInDPB++; + if (pOs) + { + (*pOs) << " !" << std::setw(3)<< n; + } + } + } + maxNumInDPB=std::max(maxNumInDPB, numInDPB); + if (pOs) + { + (*pOs) << std::endl; + } + } + if (pOs) + { + (*pOs) << "Maximum number of pictures required in DPB:" << maxNumInDPB << std::endl; + } + + return maxNumInDPB; +} +#endif + Void TAppEncCfg::xPrintParameter() { printf("\n"); diff --git a/source/App/TAppEncoder/TAppEncCfg.h b/source/App/TAppEncoder/TAppEncCfg.h index 95057ff31..983caca1c 100644 --- a/source/App/TAppEncoder/TAppEncCfg.h +++ b/source/App/TAppEncoder/TAppEncCfg.h @@ -527,6 +527,9 @@ protected: Void xCheckParameter (); ///< check validity of configuration values Void xPrintParameter (); ///< print configuration values Void xPrintUsage (); ///< print usage +#if DPB_ENCODER_USAGE_CHECK + Int xDPBUsage(std::ostream *pOs); ///> Calculates maximum number of frames stored in DPB. Can optionally output usage to a stream +#endif public: TAppEncCfg(); virtual ~TAppEncCfg(); diff --git a/source/Lib/TLibCommon/TComProfileTierLevel.cpp b/source/Lib/TLibCommon/TComProfileTierLevel.cpp new file mode 100644 index 000000000..50387ee28 --- /dev/null +++ b/source/Lib/TLibCommon/TComProfileTierLevel.cpp @@ -0,0 +1,210 @@ +/* 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-2020, 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 TComProfileTierLevel.cpp + \brief Common profile tier level functions +*/ + +#include "TComProfileTierLevel.h" +#include "TLibCommon/TComSlice.h" +//#include "TLibCommon/TComPic.h" +//#include "TLibCommon/TComPicSym.h" +#include <math.h> + +UInt +LevelTierFeatures::getMaxPicWidthInLumaSamples() const +{ + return UInt(sqrt(maxLumaPs*8.0)); +} + +UInt +LevelTierFeatures::getMaxPicHeightInLumaSamples() const +{ + return UInt(sqrt(maxLumaPs*8.0)); +} + +static const UInt64 MAX_CNFUINT64 = std::numeric_limits<UInt64>::max(); + +static const LevelTierFeatures mainLevelTierInfo[] = +{ + { Level::LEVEL1 , 36864, { 350, 0 }, 16, 1, 1, 552960ULL, { 128, 0 }, { 2, 2} }, + { Level::LEVEL2 , 122880, { 1500, 0 }, 16, 1, 1, 3686400ULL, { 1500, 0 }, { 2, 2} }, + { Level::LEVEL2_1, 245760, { 3000, 0 }, 20, 1, 1, 7372800ULL, { 3000, 0 }, { 2, 2} }, + { Level::LEVEL3 , 552960, { 6000, 0 }, 30, 2, 2, 16588800ULL, { 6000, 0 }, { 2, 2} }, + { Level::LEVEL3_1, 983040, { 10000, 0 }, 40, 3, 3, 33177600ULL, { 10000, 0 }, { 2, 2} }, + { Level::LEVEL4 , 2228224, { 12000, 30000 }, 75, 5, 5, 66846720ULL, { 12000, 30000 }, { 4, 4} }, + { Level::LEVEL4_1, 2228224, { 20000, 50000 }, 75, 5, 5, 133693440ULL, { 20000, 50000 }, { 4, 4} }, + { Level::LEVEL5 , 8912896, { 25000, 100000 }, 200, 11, 10, 267386880ULL, { 25000, 100000 }, { 6, 4} }, + { Level::LEVEL5_1, 8912896, { 40000, 160000 }, 200, 11, 10, 534773760ULL, { 40000, 160000 }, { 8, 4} }, + { Level::LEVEL5_2, 8912896, { 60000, 240000 }, 200, 11, 10, 1069547520ULL, { 60000, 240000 }, { 8, 4} }, + { Level::LEVEL6 , 35651584, { 60000, 240000 }, 600, 22, 20, 1069547520ULL, { 60000, 240000 }, { 8, 4} }, + { Level::LEVEL6_1, 35651584, { 120000, 480000 }, 600, 22, 20, 2139095040ULL, { 120000, 480000 }, { 8, 4} }, + { Level::LEVEL6_2, 35651584, { 240000, 800000 }, 600, 22, 20, 4278190080ULL, { 240000, 800000 }, { 6, 4} }, + { Level::LEVEL8_5, MAX_UINT, { MAX_UINT, MAX_UINT }, MAX_UINT, MAX_UINT, MAX_UINT, MAX_CNFUINT64, {MAX_UINT, MAX_UINT }, { 0, 0} }, + { Level::NONE } +}; + +static const ProfileFeatures validProfiles[] = +{ // profile, pNameString, maxBitDepth, maxChrFmt, intra, 1pic, lowerBR, RExtTools, ExtPrec , ChrmQPOf, align, HBRFactor, , wve+t, tiles,, lvl8.5, cpbvcl, cpbnal, fcf*1000, mincr*10 + { Profile::MAIN, "Main", 8, CHROMA_420, false, false, ProfileFeatures::ENABLED , ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, HBR_1 , false, 256, 64, false, 1000, 1100, 1500, 10 , mainLevelTierInfo }, + { Profile::MAIN10, "Main10", 10, CHROMA_420, false, false, ProfileFeatures::ENABLED , ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, HBR_1 , false, 256, 64, false, 1000, 1100, 1875, 10 , mainLevelTierInfo }, + { Profile::MAIN10, "Main10 Still Picture", 10, CHROMA_420, false, true, ProfileFeatures::ENABLED , ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, HBR_1 , false, 256, 64, true , 1000, 1100, 1875, 10 , mainLevelTierInfo }, + { Profile::MAINSTILLPICTURE, "Main Still Picture", 8, CHROMA_420, false, false, ProfileFeatures::ENABLED , ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, HBR_1 , false, 256, 64, true , 1000, 1100, 1500, 10 , mainLevelTierInfo }, + { Profile::MAINREXT, "Monochrome", 8, CHROMA_400, false, false, ProfileFeatures::ENABLED , ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 667, 733, 1000, 10 , mainLevelTierInfo }, + { Profile::MAINREXT, "Monochrome 12", 12, CHROMA_400, false, false, ProfileFeatures::ENABLED , ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 1000, 1100, 1500, 10 , mainLevelTierInfo }, + { Profile::MAINREXT, "Monochrome 16", 16, CHROMA_400, false, false, ProfileFeatures::ENABLED , ProfileFeatures::OPTIONAL, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 1333, 1467, 2000, 10 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main 12", 12, CHROMA_420, false, false, ProfileFeatures::ENABLED , ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 1500, 1650, 2250, 10 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main 4:2:2 10", 10, CHROMA_422, false, false, ProfileFeatures::ENABLED , ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 1667, 1833, 2500, 5 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main 4:2:2 12", 12, CHROMA_422, false, false, ProfileFeatures::ENABLED , ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 2000, 2200, 3000, 5 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main 4:4:4", 8, CHROMA_444, false, false, ProfileFeatures::ENABLED , ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 2000, 2200, 3000, 5 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main 4:4:4 10", 10, CHROMA_444, false, false, ProfileFeatures::ENABLED , ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 2500, 2750, 3750, 5 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main 4:4:4 12", 12, CHROMA_444, false, false, ProfileFeatures::ENABLED , ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 3000, 3300, 4500, 5 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main Intra", 8, CHROMA_420, true , false, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 1000, 1100, 1500, 10 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main 10 Intra", 10, CHROMA_420, true , false, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 1000, 1100, 1875, 10 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main 12 Intra", 12, CHROMA_420, true , false, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 1500, 1650, 2250, 10 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main 4:2:2 10 Intra", 10, CHROMA_422, true , false, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 1667, 1833, 2500, 5 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main 4:2:2 12 Intra", 12, CHROMA_422, true , false, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, ProfileFeatures::DISABLED, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 2000, 2200, 3000, 5 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main 4:4:4 Intra", 8, CHROMA_444, true , false, ProfileFeatures::OPTIONAL, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 2000, 2200, 3000, 5 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main 4:4:4 10 Intra", 10, CHROMA_444, true , false, ProfileFeatures::OPTIONAL, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 2500, 2750, 3750, 5 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main 4:4:4 12 Intra", 12, CHROMA_444, true , false, ProfileFeatures::OPTIONAL, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 3000, 3300, 4500, 5 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main 4:4:4 16 Intra", 16, CHROMA_444, true , false, ProfileFeatures::OPTIONAL, ProfileFeatures::OPTIONAL, ProfileFeatures::OPTIONAL, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, false, 4000, 4400, 6000, 5 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main 4:4:4 Still Picture", 8, CHROMA_444, true , true , ProfileFeatures::OPTIONAL, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, true , 2000, 2200, 3000, 5 , mainLevelTierInfo }, + { Profile::MAINREXT, "Main 4:4:4 16 Still Picture", 16, CHROMA_444, true , true , ProfileFeatures::OPTIONAL, ProfileFeatures::OPTIONAL, ProfileFeatures::OPTIONAL, ProfileFeatures::OPTIONAL, ProfileFeatures::DISABLED, HBR_1_OR_2 , false, 256, 64, true , 4000, 4400, 6000, 5 , mainLevelTierInfo }, + { Profile::HIGHTHROUGHPUTREXT, "High Throughput 4:4:4 16 Intra", 16, CHROMA_444, true , false, ProfileFeatures::OPTIONAL, ProfileFeatures::OPTIONAL, ProfileFeatures::OPTIONAL, ProfileFeatures::OPTIONAL, ProfileFeatures::ENABLED , HBR_12_OR_24 , true , 256, 64, false, 4000, 4400, 6000, 5 , mainLevelTierInfo }, + { Profile::NONE, 0 } +}; + + + + +Void +ProfileLevelTierFeatures::activate(const TComSPS &sps) +{ + const ProfileTierLevel ptl=*(sps.getPTL()->getGeneralPTL()); + activate(ptl.getProfileIdc(), + ptl.getBitDepthConstraint(), + ptl.getChromaFormatConstraint(), + ptl.getIntraConstraintFlag(), + ptl.getOnePictureOnlyConstraintFlag(), + ptl.getLevelIdc(), + ptl.getTierFlag(), + sps.getMaxCUWidth(), + sps.getBitDepth(CHANNEL_TYPE_LUMA), + sps.getBitDepth(CHANNEL_TYPE_CHROMA), + sps.getChromaFormatIdc()); +} + +Void +ProfileLevelTierFeatures::activate(const Profile::Name profileIdc, + const UInt bitDepthConstraint, + const ChromaFormat chromaFormatConstraint, + const Bool intraConstraintFlag, + const Bool onePictureOnlyConstraintFlag, + const Level::Name level, + const Level::Tier tier, + const UInt ctbSizeY, + const UInt bitDepthY, + const UInt bitDepthC, + const ChromaFormat chFormat) +{ + m_tier = tier; + + for(Int i=0; validProfiles[i].profile != Profile::NONE; i++) + { + if (profileIdc == validProfiles[i].profile && + bitDepthConstraint == validProfiles[i].maxBitDepth && + chromaFormatConstraint == validProfiles[i].maxChromaFormat && + intraConstraintFlag == validProfiles[i].generalIntraConstraintFlag && + onePictureOnlyConstraintFlag == validProfiles[i].generalOnePictureOnlyConstraintFlag ) + { + m_pProfile = &(validProfiles[i]); + break; + } + } + + if (m_pProfile != 0) + { + // Now identify the level: + const LevelTierFeatures *pLTF = m_pProfile->pLevelTiersListInfo; + const Level::Name spsLevelName = level; + if (spsLevelName!=Level::LEVEL8_5 || m_pProfile->bCanUseLevel8p5) + { + for(Int i=0; pLTF[i].level!=Level::NONE; i++) + { + if (pLTF[i].level == spsLevelName) + { + m_pLevelTier = &(pLTF[i]); + } + } + } + } + + { + const UInt ctbWidthC = ctbSizeY >> getChannelTypeScaleX(CHANNEL_TYPE_CHROMA, chFormat); + const UInt ctbHeightC = ctbSizeY >> getChannelTypeScaleY(CHANNEL_TYPE_CHROMA, chFormat); + + const UInt rawCtuBits = ctbSizeY*ctbSizeY*bitDepthY+2*(ctbWidthC*ctbHeightC)*bitDepthC; + m_maxRawCtuBits=(rawCtuBits*5)/3; + } + +} + +Int ProfileLevelTierFeatures::getMaxDPBNumFrames(const UInt PicSizeInSamplesY) // returns -1 if no limit, otherwise a limit of DPB pictures is indicated. +{ + Int MaxDpbSize=-1; + + if (m_pLevelTier!=0) + { + UInt MaxLumaPs=m_pLevelTier->maxLumaPs; + Int maxDpbPicBuf=6; // SCC profiles may set this to 7. + + if( PicSizeInSamplesY <= ( MaxLumaPs >> 2 ) ) + { + MaxDpbSize = min( 4 * maxDpbPicBuf, 16 ); + } + else if( PicSizeInSamplesY <= ( MaxLumaPs >> 1 ) ) + { + MaxDpbSize = min( 2 * maxDpbPicBuf, 16 ); + } + else if( PicSizeInSamplesY <= ( ( 3 * MaxLumaPs ) >> 2 ) ) + { + MaxDpbSize = min( ( 4 * maxDpbPicBuf ) / 3, 16 ); + } + else + { + MaxDpbSize = maxDpbPicBuf; + } + } + return MaxDpbSize; +} + diff --git a/source/Lib/TLibCommon/TComProfileTierLevel.h b/source/Lib/TLibCommon/TComProfileTierLevel.h new file mode 100644 index 000000000..571537812 --- /dev/null +++ b/source/Lib/TLibCommon/TComProfileTierLevel.h @@ -0,0 +1,161 @@ +/* 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-2020, 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 TComProfileTierLevel.h + \brief Common profile tier level functions (header) +*/ + +#ifndef __TCOMPROFILETIERLEVEL__ +#define __TCOMPROFILETIERLEVEL__ + + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "TLibCommon/CommonDef.h" +#include <stdio.h> +#include <iostream> + + +// Forward declarations +class TComSPS; +class ProfileTierLevel; + + +typedef enum HBRFACTOREQN +{ + HBR_1 = 0, + HBR_1_OR_2 = 1, + HBR_12_OR_24 = 2 +} HBRFACTOREQN; + + +struct LevelTierFeatures +{ + Level::Name level; + UInt maxLumaPs; + UInt maxCpb[Level::NUMBER_OF_TIERS]; // in units of CpbVclFactor or CpbNalFactor bits + UInt maxSliceSegmentsPerPicture; + UInt maxTileRows; + UInt maxTileCols; + UInt64 maxLumaSr; + UInt maxBr[Level::NUMBER_OF_TIERS]; // in units of BrVclFactor or BrNalFactor bits/s + UInt minCrBase[Level::NUMBER_OF_TIERS]; + UInt getMaxPicWidthInLumaSamples() const; + UInt getMaxPicHeightInLumaSamples() const; +}; + + +struct ProfileFeatures +{ + + typedef enum TRISTATE + { + DISABLED=0, + OPTIONAL=1, + ENABLED=2 + } TRISTATE; + + Profile::Name profile; + const TChar *pNameString; + UInt maxBitDepth; + ChromaFormat maxChromaFormat; + Bool generalIntraConstraintFlag; + Bool generalOnePictureOnlyConstraintFlag; + TRISTATE generalLowerBitRateConstraint; + TRISTATE generalRExtToolsEnabled; + TRISTATE extendedPrecisionProcessingFlag; + TRISTATE chromaQpOffsetListEnabledFlag; + TRISTATE cabacBypassAlignmentEnabledFlag; + HBRFACTOREQN hbrFactorEqn; + Bool bWavefrontsAndTilesCanBeUsedSimultaneously; + + UInt minTileColumnWidthInLumaSamples; + UInt minTileRowHeightInLumaSamples; + Bool bCanUseLevel8p5; + UInt cpbVclFactor; + UInt cpbNalFactor; // currently not used for checking + UInt formatCapabilityFactorx1000; // currently not used for checking + UInt minCrScaleFactorx10; // currently not used for checking + const LevelTierFeatures *pLevelTiersListInfo; + + Bool chromaFormatValid(ChromaFormat chFmt) const { return (profile == Profile::MAINREXT || profile == Profile::HIGHTHROUGHPUTREXT) ? chFmt<=maxChromaFormat : (chFmt == maxChromaFormat ); } + Bool onlyIRAPPictures() const { return generalIntraConstraintFlag; } + UInt getHbrFactor(Bool bLowerBitRateConstraintFlag) const // currently not used for checking + { + return hbrFactorEqn==HBR_1_OR_2 ? (2-(bLowerBitRateConstraintFlag?1:0)) : + (hbrFactorEqn==HBR_12_OR_24 ? 12*(2-(bLowerBitRateConstraintFlag?1:0)) : + 1); + } +}; + + +class ProfileLevelTierFeatures +{ + private: + const ProfileFeatures *m_pProfile; + const LevelTierFeatures *m_pLevelTier; + UInt m_hbrFactor; // currently not used for checking + Level::Tier m_tier; + UInt m_maxRawCtuBits; + public: + ProfileLevelTierFeatures() : m_pProfile(0), m_pLevelTier(0), m_hbrFactor(0), m_tier(Level::MAIN), m_maxRawCtuBits(0) { } + + Void activate(const Profile::Name profileIdc, + const UInt bitDepthConstraint, + const ChromaFormat chromaFormatConstraint, + const Bool intraConstraintFlag, + const Bool onePictureOnlyConstraintFlag, + const Level::Name level, + const Level::Tier tier, + const UInt ctbSizeY, + const UInt bitDepthY, + const UInt bitDepthC, + const ChromaFormat chFormat); + + Void activate(const TComSPS &sps); + + const ProfileFeatures *getProfileFeatures() const { return m_pProfile; } + const LevelTierFeatures *getLevelTierFeatures() const { return m_pLevelTier; } + Level::Tier getTier() const { return m_tier; } + UInt64 getCpbSizeInBits() const { return (m_pLevelTier!=0 && m_pProfile!=0) ? UInt64(m_pProfile->cpbVclFactor) * m_pLevelTier->maxCpb[m_tier?1:0] : UInt64(0); } + Double getMinCr() const { return (m_pLevelTier!=0 && m_pProfile!=0) ? (m_pProfile->minCrScaleFactorx10 * m_pLevelTier->minCrBase[m_tier?1:0])/10.0 : 0.0 ; } // currently not used for checking + UInt getMaxRawCtuBits() const { return m_maxRawCtuBits; } + Int getMaxDPBNumFrames(const UInt PicSizeInSamplesY); // returns -1 if no limit, otherwise a limit of DPB pictures is indicated. + +}; + + +#endif diff --git a/source/Lib/TLibCommon/TypeDef.h b/source/Lib/TLibCommon/TypeDef.h index 17fe3dde2..f532e65ff 100644 --- a/source/Lib/TLibCommon/TypeDef.h +++ b/source/Lib/TLibCommon/TypeDef.h @@ -116,6 +116,8 @@ #define FIXSAORESETAFTERIRAP 1 // Fix the reset mechanism for SAO after an IRAP for the case of IRAP period equal to gop size. #define ADD_RESET_ENCODER_DECISIONS_AFTER_IRAP 1 // Add support to reseting encoder decisions after IRAP, to enable independent/parallel coding of randomaccess configuration intra-periods. +#define DPB_ENCODER_USAGE_CHECK 1 ///< Adds DPB encoder usage check. + // ==================================================================================================================== // Tool Switches // ==================================================================================================================== diff --git a/source/Lib/TLibDecoder/TDecConformance.cpp b/source/Lib/TLibDecoder/TDecConformance.cpp index b1af8093c..030ac2bf8 100644 --- a/source/Lib/TLibDecoder/TDecConformance.cpp +++ b/source/Lib/TLibDecoder/TDecConformance.cpp @@ -42,6 +42,7 @@ #include "NALread.h" #include <math.h> +#if !DPB_ENCODER_USAGE_CHECK UInt LevelTierFeatures::getMaxPicWidthInLumaSamples() const { @@ -53,6 +54,7 @@ LevelTierFeatures::getMaxPicHeightInLumaSamples() const { return UInt(sqrt(maxLumaPs*8.0)); } +#endif UInt TDecConformanceCheck::getMinLog2CtbSize(const TComPTL &ptl, @@ -89,6 +91,7 @@ TDecConformanceCheck::TDecConformanceCheck() #if DECODER_PARTIAL_CONFORMANCE_CHECK != 0 +#if !DPB_ENCODER_USAGE_CHECK static const UInt64 MAX_CNFUINT64 = std::numeric_limits<UInt64>::max(); static const LevelTierFeatures mainLevelTierInfo[] = @@ -139,6 +142,7 @@ static const ProfileFeatures validProfiles[] = { Profile::HIGHTHROUGHPUTREXT, "High Throughput 4:4:4 16 Intra", 16, CHROMA_444, true , false, OPTIONAL, OPTIONAL, OPTIONAL, OPTIONAL, ENABLED , HBR_12_OR_24 , true , 256, 64, false, 4000, 4400, 6000, 5 , mainLevelTierInfo }, { Profile::NONE, 0 } }; +#endif @@ -256,7 +260,7 @@ checkPPS(const TComSPS &sps, checkTiles(sps, pps, pic, features); } - +#if !DPB_ENCODER_USAGE_CHECK Void ProfileLevelTierFeatures::activate(const TComSPS &sps) { @@ -306,6 +310,7 @@ ProfileLevelTierFeatures::activate(const TComSPS &sps) } } +#endif static Void @@ -313,10 +318,17 @@ checkToolAvailability(const TComSPS &sps, const TComPPS &pps, const ProfileLevelTierFeatures &features) { +#if DPB_ENCODER_USAGE_CHECK + const ProfileFeatures::TRISTATE rextToolsEnabled = features.getProfileFeatures()->generalRExtToolsEnabled; + if ( rextToolsEnabled != ProfileFeatures::OPTIONAL) + { + const Bool bWantedFlagState = rextToolsEnabled == ProfileFeatures::ENABLED; +#else const TRISTATE rextToolsEnabled = features.getProfileFeatures()->generalRExtToolsEnabled; if ( rextToolsEnabled != OPTIONAL) { const Bool bWantedFlagState = rextToolsEnabled == ENABLED; +#endif std::string flags; if (sps.getSpsRangeExtension().getTransformSkipRotationEnabledFlag() != bWantedFlagState) flags+=", transform_skip_rotation_enabled_flag"; if (sps.getSpsRangeExtension().getTransformSkipContextEnabledFlag() != bWantedFlagState) flags+=", transform_skip_context_enabled_flag"; @@ -324,7 +336,11 @@ checkToolAvailability(const TComSPS &sps, if (sps.getSpsRangeExtension().getRdpcmEnabledFlag(RDPCM_SIGNAL_EXPLICIT) != bWantedFlagState) flags+=", explicit_rdpcm_enabled_flag"; if (sps.getSpsRangeExtension().getIntraSmoothingDisabledFlag() != bWantedFlagState) flags+=", intra_smoothing_disabled_flag"; if (sps.getSpsRangeExtension().getPersistentRiceAdaptationEnabledFlag() != bWantedFlagState) flags+=", persistent_rice_adaptation_enabled_flag"; +#if DPB_ENCODER_USAGE_CHECK + if (pps.getPpsRangeExtension().getLog2MaxTransformSkipBlockSize() != 2 && rextToolsEnabled==ProfileFeatures::DISABLED ) flags+=", log2_max_transform_skip_block_size_minus2"; +#else if (pps.getPpsRangeExtension().getLog2MaxTransformSkipBlockSize() != 2 && rextToolsEnabled==DISABLED ) flags+=", log2_max_transform_skip_block_size_minus2"; +#endif if (!flags.empty()) { @@ -337,9 +353,15 @@ checkToolAvailability(const TComSPS &sps, TDecConformanceCheck::checkRange<UInt>(pps.getPpsRangeExtension().getLog2MaxTransformSkipBlockSize()-2, "log2_max_transform_skip_block_size_minus2", 0, sps.getQuadtreeTULog2MaxSize()-2); } +#if DPB_ENCODER_USAGE_CHECK + if (features.getProfileFeatures()->extendedPrecisionProcessingFlag != ProfileFeatures::OPTIONAL) + { + const Bool bWantedFlagState = features.getProfileFeatures()->extendedPrecisionProcessingFlag == ProfileFeatures::ENABLED; +#else if (features.getProfileFeatures()->extendedPrecisionProcessingFlag != OPTIONAL) { const Bool bWantedFlagState = features.getProfileFeatures()->extendedPrecisionProcessingFlag == ENABLED; +#endif if (sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag() != bWantedFlagState) { TDecConformanceCheck::getStream() << "extended_precision_processing_flag must be " << (bWantedFlagState ? "1" : "0") << " in the profile '" << features.getProfileFeatures()->pNameString << "' conformance point\n"; @@ -347,9 +369,15 @@ checkToolAvailability(const TComSPS &sps, } } +#if DPB_ENCODER_USAGE_CHECK + if (features.getProfileFeatures()->chromaQpOffsetListEnabledFlag != ProfileFeatures::OPTIONAL) + { + const Bool bWantedFlagState = features.getProfileFeatures()->chromaQpOffsetListEnabledFlag == ProfileFeatures::ENABLED; +#else if (features.getProfileFeatures()->chromaQpOffsetListEnabledFlag != OPTIONAL) { const Bool bWantedFlagState = features.getProfileFeatures()->chromaQpOffsetListEnabledFlag == ENABLED; +#endif if (pps.getPpsRangeExtension().getChromaQpOffsetListEnabledFlag() != bWantedFlagState) { TDecConformanceCheck::getStream() << "chroma_qp_offset_list_enabled_flag must be " << (bWantedFlagState ? "1" : "0") << " in the profile '" << features.getProfileFeatures()->pNameString << "' conformance point\n"; @@ -361,9 +389,15 @@ checkToolAvailability(const TComSPS &sps, TDecConformanceCheck::checkRange<UInt>(pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth(), "diff_cu_chroma_qp_offset_depth", 0, sps.getLog2DiffMaxMinCodingBlockSize()); } +#if DPB_ENCODER_USAGE_CHECK + if (features.getProfileFeatures()->cabacBypassAlignmentEnabledFlag != ProfileFeatures::OPTIONAL) + { + const Bool bWantedFlagState = features.getProfileFeatures()->cabacBypassAlignmentEnabledFlag == ProfileFeatures::ENABLED; +#else if (features.getProfileFeatures()->cabacBypassAlignmentEnabledFlag != OPTIONAL) { const Bool bWantedFlagState = features.getProfileFeatures()->cabacBypassAlignmentEnabledFlag == ENABLED; +#endif if (sps.getSpsRangeExtension().getCabacBypassAlignmentEnabledFlag() != bWantedFlagState) { TDecConformanceCheck::getStream() << "cabac_bypass_alignment_enabled_flag must be " << (bWantedFlagState ? "1" : "0") << " in the profile '" << features.getProfileFeatures()->pNameString << "' conformance point\n"; diff --git a/source/Lib/TLibDecoder/TDecConformance.h b/source/Lib/TLibDecoder/TDecConformance.h index a9771d47e..e4993d59d 100644 --- a/source/Lib/TLibDecoder/TDecConformance.h +++ b/source/Lib/TLibDecoder/TDecConformance.h @@ -50,6 +50,9 @@ #endif // _MSC_VER > 1000 #include "TLibCommon/CommonDef.h" +#if DPB_ENCODER_USAGE_CHECK +#include "TLibCommon/TComProfileTierLevel.h" +#endif #include <stdio.h> #include <iostream> #if DECODER_PARTIAL_CONFORMANCE_CHECK == 2 @@ -59,12 +62,15 @@ // Forward declarations class TComSlice; +#if !DPB_ENCODER_USAGE_CHECK class TComSPS; class TComPPS; +#endif class InputNALUnit; class TComPTL; class TComPic; +#if !DPB_ENCODER_USAGE_CHECK typedef enum TRISTATE { DISABLED=0, @@ -153,6 +159,7 @@ class ProfileLevelTierFeatures Double getMinCr() const { return (m_pLevelTier!=0 && m_pProfile!=0) ? (m_pProfile->minCrScaleFactorx10 * m_pLevelTier->minCrBase[m_tier?1:0])/10.0 : 0.0 ; } // currently not used for checking UInt getMaxRawCtuBits() const { return m_maxRawCtuBits; } }; +#endif class TDecConformanceCheck -- GitLab