diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp index 81e1e9ed9ed8c73e9d998ae9d89b983a8e1425d2..9cf659f95a3be631fd4b3815d988c2dea75a90a4 100644 --- a/source/Lib/CommonLib/CodingStructure.cpp +++ b/source/Lib/CommonLib/CodingStructure.cpp @@ -1746,7 +1746,13 @@ TransformUnit& CodingStructure::addTU( const UnitArea &unit, const ChannelType c void CodingStructure::addEmptyTUs( Partitioner &partitioner ) { const UnitArea& area = partitioner.currArea(); - bool split = partitioner.canSplit(TU_MAX_TR_SPLIT, *this); + bool split = partitioner.canSplit(TU_MAX_TR_SPLIT, *this +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); + + const unsigned trDepth = partitioner.currTrDepth; if( split ) diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h index a75e9e6b1df08fe6549c0083844408f4964abf4b..3385f27468227b89d1c1fe6ca07ba3fccf8ea88e 100644 --- a/source/Lib/CommonLib/CodingStructure.h +++ b/source/Lib/CommonLib/CodingStructure.h @@ -87,7 +87,9 @@ public: Slice *slice; UnitScale unitScale[MAX_NUM_COMPONENT]; - +#if JVET_AI0087_BTCUS_RESTRICTION + int btFirstPartDecs[4]; +#endif int baseQP; int prevQP[MAX_NUM_CHANNEL_TYPE]; int currQP[MAX_NUM_CHANNEL_TYPE]; diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp index e22ef789058ead2278b4833862a9eeb2b3160bd8..cd14376d4e78989092f12946d212faf41521da41 100644 --- a/source/Lib/CommonLib/ContextModelling.cpp +++ b/source/Lib/CommonLib/ContextModelling.cpp @@ -237,7 +237,12 @@ unsigned DeriveCtx::CtxModeConsFlag( const CodingStructure& cs, Partitioner& par } #endif -void DeriveCtx::CtxSplit( const CodingStructure& cs, Partitioner& partitioner, unsigned& ctxSpl, unsigned& ctxQt, unsigned& ctxHv, unsigned& ctxHorBt, unsigned& ctxVerBt, bool* _canSplit /*= nullptr */ ) +void DeriveCtx::CtxSplit( const CodingStructure& cs, Partitioner& partitioner, unsigned& ctxSpl, unsigned& ctxQt, unsigned& ctxHv, unsigned& ctxHorBt, unsigned& ctxVerBt, bool* _canSplit +#if JVET_AI0087_BTCUS_RESTRICTION + , bool disableBTV, bool disableBTH +#endif + +/*= nullptr */ ) { const Position pos = partitioner.currArea().blocks[partitioner.chType]; const unsigned curSliceIdx = cs.slice->getIndependentSliceIdx(); @@ -255,9 +260,17 @@ void DeriveCtx::CtxSplit( const CodingStructure& cs, Partitioner& partitioner, u { #if JVET_AH0135_TEMPORAL_PARTITIONING unsigned maxMtt; - partitioner.canSplit(cs, canSplit[0], canSplit[1], canSplit[2], canSplit[3], canSplit[4], canSplit[5], maxMtt); + partitioner.canSplit(cs, canSplit[0], canSplit[1], canSplit[2], canSplit[3], canSplit[4], canSplit[5], maxMtt +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); #else - partitioner.canSplit( cs, canSplit[0], canSplit[1], canSplit[2], canSplit[3], canSplit[4], canSplit[5] ); + partitioner.canSplit( cs, canSplit[0], canSplit[1], canSplit[2], canSplit[3], canSplit[4], canSplit[5] +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); #endif } else @@ -313,6 +326,13 @@ void DeriveCtx::CtxSplit( const CodingStructure& cs, Partitioner& partitioner, u ctxSpl += 3 * ( numSplit >> 1 ); +#if JVET_AI0087_BTCUS_RESTRICTION + if ((disableBTV || disableBTH) && partitioner.chType == CHANNEL_TYPE_LUMA) + { + ctxSpl = 9; + } +#endif + ////////////////////////// // CTX is qt split (0-5) ////////////////////////// diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h index aca51b88109442903abeefe29b14e51e643e4697..a2ebe676d87bce93ba74ff861b478a399ba237a9 100644 --- a/source/Lib/CommonLib/ContextModelling.h +++ b/source/Lib/CommonLib/ContextModelling.h @@ -1194,7 +1194,11 @@ public: namespace DeriveCtx { -void CtxSplit ( const CodingStructure& cs, Partitioner& partitioner, unsigned& ctxSpl, unsigned& ctxQt, unsigned& ctxHv, unsigned& ctxHorBt, unsigned& ctxVerBt, bool* canSplit = nullptr ); +void CtxSplit ( const CodingStructure& cs, Partitioner& partitioner, unsigned& ctxSpl, unsigned& ctxQt, unsigned& ctxHv, unsigned& ctxHorBt, unsigned& ctxVerBt, bool* canSplit = nullptr +#if JVET_AI0087_BTCUS_RESTRICTION + ,bool disableBTV = false, bool disableBTH = false +#endif +); #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS unsigned CtxModeConsFlag( const CodingStructure& cs, Partitioner& partitioner ); #endif diff --git a/source/Lib/CommonLib/Contexts_ecm13.inl b/source/Lib/CommonLib/Contexts_ecm13.inl index 40bcca860d181fdcb946754bb116bd5202773946..e2158e8eb1b92eb48493dd8467a3a9d3818eddcf 100644 --- a/source/Lib/CommonLib/Contexts_ecm13.inl +++ b/source/Lib/CommonLib/Contexts_ecm13.inl @@ -4,6 +4,29 @@ // CONTEXTS WSA START const CtxSet ContextSetCfg::SplitFlag = ContextSetCfg::addCtxSet({ // ctx 0 8 +#if JVET_AI0087_BTCUS_RESTRICTION + { 11, 20, 52, 19, 14, 30, 35, 30, 31, 14}, + { 11, 20, 52, 12, 21, 30, 13, 15, 31, 21 }, + { 27, 36, 38, 20, 29, 30, 28, 38, 31, 29}, + { 11, 20, 52, 4, 14, 38, 28, 30, 31, 14 }, + { 5, 6, 5, 5, 10, 13, 9, 7, 10, 10}, + { 6, 10, 10, 5, 10, 13, 10, 7, 13, 10 }, + { 9, 9, 9, 9, 9, 13, 6, 6, 9, 9}, + { 5, 6, 6, 5, 10, 13, 10, 7, 13, 10 }, + { 4, 4, 18, 4, 4, 11, 11, 4, 11, 4 }, + { 4, 11, 25, 4, 4, 11, 11, 4, 11, 4 }, + { 11, 4, 18, 11, 4, 18, 18, 4, 11, 4 }, + { 4, 4, 18, 4, 4, 11, 11, 4, 11, 4 }, + { 196, 152, 134, 246, 234, 234, 102, 130, 137, 234 }, + { 140, 155, 107, 170, 250, 178, 230, 115, 85, 250}, + { 195, 244, 131, 153, 250, 234, 106, 116, 148, 250}, + { 169, 250, 106, 252, 250, 121, 234, 121, 83, 250}, + { 163, 138, 150, 243, 187, 234, 107, 162, 181, 187}, + { 251, 251, 84, 251, 251, 87, 117, 123, 84, 251}, + { 196, 152, 133, 247, 250, 234, 106, 115, 164, 250}, + { 137, 187, 118, 171, 250, 119, 216, 115, 82, 250}, + }); +#else { 11, 20, 52, 19, 14, 30, 35, 30, 31 }, { 11, 20, 52, 12, 21, 30, 13, 15, 31 }, { 27, 36, 38, 20, 29, 30, 28, 38, 31 }, @@ -25,7 +48,7 @@ const CtxSet ContextSetCfg::SplitFlag = ContextSetCfg::addCtxSet({ { 196, 152, 133, 247, 250, 234, 106, 115, 164 }, { 137, 187, 118, 171, 250, 119, 216, 115, 82 }, }); - +#endif const CtxSet ContextSetCfg::SplitQtFlag = ContextSetCfg::addCtxSet({ // ctx 9 14 { 27, 22, 23, 11, 12, 6 }, diff --git a/source/Lib/CommonLib/Contexts_ecm14.0.inl b/source/Lib/CommonLib/Contexts_ecm14.0.inl index 5e3bc38da798f973b4cfb8ccca13cee02c58e371..5b9830d97cad61ebe1ad25b29361f7e41a52ba98 100644 --- a/source/Lib/CommonLib/Contexts_ecm14.0.inl +++ b/source/Lib/CommonLib/Contexts_ecm14.0.inl @@ -4,6 +4,29 @@ // CONTEXTS WSA START const CtxSet ContextSetCfg::SplitFlag = ContextSetCfg::addCtxSet({ // ctx 0 8 +#if JVET_AI0087_BTCUS_RESTRICTION + { 18, 20, 52, 19, 21, 30, 42, 37, 31, 21 }, + { 11, 20, 52, 19, 6, 30, 5, 22, 23, 6 }, + { 27, 36, 38, 20, 29, 30, 28, 38, 31, 29 }, + { 11, 20, 52, 4, 6, 30, 20, 30, 31, 6 }, + { 5, 6, 7, 5, 10, 13, 8, 7, 13, 10 }, + { 6, 10, 10, 5, 10, 13, 10, 7, 13, 10 }, + { 9, 9, 9, 9, 9, 9, 6, 9, 9, 9 }, + { 5, 6, 6, 5, 10, 13, 9, 7, 13, 10 }, + { 4, 11, 25, 11, 11, 18, 11, 11, 11, 11 }, + { 4, 11, 32, 4, 4, 11, 11, 4, 18, 4 }, + { 11, 4, 18, 11, 4, 4, 18, 11, 11, 4 }, + { 4, 4, 18, 4, 11, 18, 11, 4, 11, 11 }, + { 212, 150, 133, 230, 245, 217, 101, 145, 194, 245 }, + { 140, 133, 114, 172, 250, 117, 181, 120, 132, 250 }, + { 211, 230, 209, 188, 250, 234, 101, 115, 115, 250 }, + { 170, 234, 113, 203, 250, 229, 244, 118, 105, 250 }, + { 163, 166, 151, 243, 186, 251, 101, 130, 165, 186 }, + { 251, 251, 84, 251, 251, 91, 116, 147, 84, 251 }, + { 212, 165, 133, 247, 183, 150, 115, 114, 131, 183 }, + { 140, 155, 107, 171, 250, 216, 216, 115, 98, 250 }, +}); +#else { 18, 20, 52, 19, 21, 30, 42, 37, 31 }, { 11, 20, 52, 19, 6, 30, 5, 22, 23 }, { 27, 36, 38, 20, 29, 30, 28, 38, 31 }, @@ -25,6 +48,7 @@ const CtxSet ContextSetCfg::SplitFlag = ContextSetCfg::addCtxSet({ { 212, 165, 133, 247, 183, 150, 115, 114, 131 }, { 140, 155, 107, 171, 250, 216, 216, 115, 98 }, }); +#endif const CtxSet ContextSetCfg::SplitQtFlag = ContextSetCfg::addCtxSet({ // ctx 9 14 diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 79068fc9d56b8a563895506160b2090d1ab6ab0f..672c6de2331a460fc2757abffaeab1707725d0b9 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -94,6 +94,7 @@ #if TU_256 #define LMCS_CHROMA_CALC_CU 1 // Derive chroma LMCS parameter based on neighbor CUs. Needed by VPDU removal and 128x128 transform. #endif +#define JVET_AI0087_BTCUS_RESTRICTION 1 // JVET-AI0087: Restriction on BT CUs from applying QT like partitioning structure //-- intra #define INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS 1 // Enable 2xN and Nx2 block by removing SCIPU constraints diff --git a/source/Lib/CommonLib/UnitPartitioner.cpp b/source/Lib/CommonLib/UnitPartitioner.cpp index 0df8d83b5463068d6df006f470bdfdd60aa028be..880c2f3a010987f09d394b458ddf3f792db03316 100644 --- a/source/Lib/CommonLib/UnitPartitioner.cpp +++ b/source/Lib/CommonLib/UnitPartitioner.cpp @@ -290,10 +290,19 @@ void QTBTPartitioner::initCtu( const UnitArea& ctuArea, const ChannelType _chTyp void QTBTPartitioner::splitCurrArea( const PartSplit split, const CodingStructure& cs ) { - CHECKD( !canSplit( split, cs ), "Trying to apply a prohibited split!" ); + +#if JVET_AI0087_BTCUS_RESTRICTION + CHECKD(!canSplit(split, cs, false, false), "Trying to apply a prohibited split!"); +#else + CHECKD(!canSplit(split, cs), "Trying to apply a prohibited split!"); +#endif bool isImplicit = isSplitImplicit( split, cs ); - bool canQtSplit = canSplit( CU_QUAD_SPLIT, cs ); + bool canQtSplit = canSplit( CU_QUAD_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); bool qgEnable = currQgEnable(); bool qgChromaEnable = currQgChromaEnable(); @@ -393,6 +402,9 @@ void QTBTPartitioner::canSplit( const CodingStructure &cs, bool& canNo, bool& ca #if JVET_AH0135_TEMPORAL_PARTITIONING , unsigned& maxMtt #endif +#if JVET_AI0087_BTCUS_RESTRICTION + , bool disableBTV, bool disableBTH +#endif ) { #if JVET_AI0136_ADAPTIVE_DUAL_TREE @@ -614,6 +626,18 @@ void QTBTPartitioner::canSplit( const CodingStructure &cs, bool& canNo, bool& ca canBh = canBv = false; } +#if JVET_AI0087_BTCUS_RESTRICTION + if (disableBTV && (chType == CHANNEL_TYPE_LUMA)) + { + canBv = false; + } + + if (disableBTH && (chType == CHANNEL_TYPE_LUMA)) + { + canBh = false; + } +#endif + // specific check for BT splits if( area.height <= minBtSize ) canBh = false; #if !REMOVE_VPDU || CTU_256 @@ -666,7 +690,11 @@ void QTBTPartitioner::canSplit( const CodingStructure &cs, bool& canNo, bool& ca #endif } -bool QTBTPartitioner::canSplit( const PartSplit split, const CodingStructure &cs ) +bool QTBTPartitioner::canSplit( const PartSplit split, const CodingStructure &cs +#if JVET_AI0087_BTCUS_RESTRICTION + ,bool disableBTV, bool disableBTH +#endif +) { const CompArea area = currArea().Y(); const unsigned maxTrSize = cs.sps->getMaxTbSize(); @@ -675,9 +703,17 @@ bool QTBTPartitioner::canSplit( const PartSplit split, const CodingStructure &cs #if JVET_AH0135_TEMPORAL_PARTITIONING unsigned maxMtt; - canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv, maxMtt ); + canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv, maxMtt +#if JVET_AI0087_BTCUS_RESTRICTION + , disableBTV, disableBTH +#endif + ); #else - canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv ); + canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv +#if JVET_AI0087_BTCUS_RESTRICTION + , disableBTV, disableBTH +#endif + ); #endif switch( split ) { @@ -964,7 +1000,11 @@ bool TUIntraSubPartitioner::hasNextPart() return ( ( m_partStack.back().idx + 1 ) < m_partStack.back().parts.size() ); } -bool TUIntraSubPartitioner::canSplit( const PartSplit split, const CodingStructure &cs ) +bool TUIntraSubPartitioner::canSplit( const PartSplit split, const CodingStructure &cs +#if JVET_AI0087_BTCUS_RESTRICTION + , bool disableBTV, bool disableBTH +#endif +) { //const PartSplit implicitSplit = getImplicitSplit(cs); const UnitArea &area = currArea(); diff --git a/source/Lib/CommonLib/UnitPartitioner.h b/source/Lib/CommonLib/UnitPartitioner.h index 0e41fc0400c49eaf5a7a9cb769af7e622cdc3e5c..73ac1eb4568b84fb39d27f05a8adb3af48886c12 100644 --- a/source/Lib/CommonLib/UnitPartitioner.h +++ b/source/Lib/CommonLib/UnitPartitioner.h @@ -127,6 +127,9 @@ public: Position currQgPos; Position currQgChromaPos; +#if JVET_AI0087_BTCUS_RESTRICTION + int btFirstPartDecs[4]; +#endif unsigned currImplicitBtDepth; ChannelType chType; #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS @@ -161,9 +164,16 @@ public: #if JVET_AH0135_TEMPORAL_PARTITIONING , unsigned& maxMtt #endif +#if JVET_AI0087_BTCUS_RESTRICTION + , bool disableBTV, bool disableBTH +#endif ) = 0; - virtual bool canSplit ( const PartSplit split, const CodingStructure &cs ) = 0; + virtual bool canSplit ( const PartSplit split, const CodingStructure &cs +#if JVET_AI0087_BTCUS_RESTRICTION + , bool disableBTV, bool disableBTH +#endif + ) = 0; virtual bool isSplitImplicit ( const PartSplit split, const CodingStructure &cs ) = 0; virtual PartSplit getImplicitSplit ( const CodingStructure &cs ) = 0; #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS @@ -194,10 +204,17 @@ public: void canSplit ( const CodingStructure &cs, bool& canNo, bool& canQt, bool& canBh, bool& canBv, bool& canTh, bool& canTv #if JVET_AH0135_TEMPORAL_PARTITIONING , unsigned& maxMtt +#endif +#if JVET_AI0087_BTCUS_RESTRICTION + , bool disableBTV, bool disableBTH #endif ); - bool canSplit ( const PartSplit split, const CodingStructure &cs ); + bool canSplit ( const PartSplit split, const CodingStructure &cs +#if JVET_AI0087_BTCUS_RESTRICTION + , bool disableBTV, bool disableBTH +#endif + ); bool isSplitImplicit ( const PartSplit split, const CodingStructure &cs ); PartSplit getImplicitSplit ( const CodingStructure &cs ); }; @@ -234,9 +251,17 @@ public: #if JVET_AH0135_TEMPORAL_PARTITIONING , unsigned& maxMtt #endif +#if JVET_AI0087_BTCUS_RESTRICTION + , bool disableBTV, bool disableBTH +#endif + ) {}; - bool canSplit (const PartSplit split, const CodingStructure &cs); + bool canSplit (const PartSplit split, const CodingStructure &cs +#if JVET_AI0087_BTCUS_RESTRICTION + , bool disableBTV, bool disableBTH +#endif + ); bool isSplitImplicit (const PartSplit split, const CodingStructure &cs) { return false; }; //not needed PartSplit getImplicitSplit (const CodingStructure &cs) { return CU_DONT_SPLIT; }; //not needed }; diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index f4579c4429d6555784fbf7d5234b7c2be580451b..cf13edaa88ef1ea952bbb240c7d368505b841a20 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -138,6 +138,42 @@ bool CABACReader::terminating_bit() return false; } +#if JVET_AI0087_BTCUS_RESTRICTION +bool CABACReader::isLumaNonBoundaryCu(const Partitioner& partitioner, SizeType picWidth, SizeType picHeight ) +{ + bool validCU = false; + if (isLuma(partitioner.chType)) + { + int maxWidthHeight = std::max(partitioner.currArea().lwidth(), partitioner.currArea().lheight()) - 1; + if ((partitioner.currArea().Y().x + maxWidthHeight < picWidth) + && (partitioner.currArea().Y().y + maxWidthHeight < picHeight)) + { + validCU = true; + } + } + return validCU; +} +void CABACReader::setBtFirstPart(const Partitioner& partitioner, SizeType blockSize, CodingStructure& cs, PartSplit setValue) +{ + if (blockSize == 128) + { + cs.btFirstPartDecs[0] = setValue; + } + else if (blockSize == 64) + { + cs.btFirstPartDecs[1] = setValue; + } + else if (blockSize == 32) + { + cs.btFirstPartDecs[2] = setValue; + } + else if (blockSize == 16) + { + cs.btFirstPartDecs[3] = setValue; + } +} +#endif + void CABACReader::remaining_bytes( bool noTrailingBytesExpected ) { if( noTrailingBytesExpected ) @@ -175,7 +211,10 @@ void CABACReader::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i #endif partitioner.initCtu(area, CH_L, *cs.slice); -#if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS + #if JVET_AI0087_BTCUS_RESTRICTION + std::memset(cs.btFirstPartDecs,0, sizeof(cs.btFirstPartDecs)); +#endif + #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS cs.treeType = partitioner.treeType = TREE_D; cs.modeType = partitioner.modeType = MODE_TYPE_ALL; #endif @@ -763,7 +802,11 @@ void CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU const PartSplit splitMode = split_cu_mode( cs, partitioner ); - CHECK( !partitioner.canSplit( splitMode, cs ), "Got an invalid split!" ); +#if JVET_AI0087_BTCUS_RESTRICTION + CHECK(!partitioner.canSplit(splitMode, cs, false, false), "Got an invalid split!"); +#else + CHECK(!partitioner.canSplit(splitMode, cs), "Got an invalid split!"); +#endif if( splitMode != CU_DONT_SPLIT ) { @@ -1122,21 +1165,86 @@ ModeType CABACReader::mode_constraint( CodingStructure& cs, Partitioner &partiti PartSplit CABACReader::split_cu_mode( CodingStructure& cs, Partitioner &partitioner ) { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2( STATS__CABAC_BITS__SPLIT_FLAG, partitioner.currArea().blocks[partitioner.chType].size(), partitioner.chType ); +#if JVET_AI0087_BTCUS_RESTRICTION + bool disableBTV = false; + bool disableBTH = false; + if (CABACReader::isLumaNonBoundaryCu(partitioner, cs.picture->lwidth(), cs.picture->lheight()) && (!(cs.slice->getProcessingIntraRegion() && cs.slice->getProcessingSeparateTrees()) || cs.slice->isIntra()) ) + { + if ((partitioner.currBtDepth == 0) && (partitioner.currArea().lwidth() == partitioner.currArea().lheight())) + { + CABACReader::setBtFirstPart(partitioner, partitioner.currArea().lwidth(), cs, CTU_LEVEL); + } + + if ((partitioner.currBtDepth == 1) && (partitioner.currPartIdx() == 1)) + { + if (partitioner.currPartLevel().split == CU_HORZ_SPLIT) + { + if (partitioner.currArea().lwidth() == 128 && cs.btFirstPartDecs[0] == CU_VERT_SPLIT) + { + disableBTV = true; + } + else if (partitioner.currArea().lwidth() == 64 && cs.btFirstPartDecs[1] == CU_VERT_SPLIT) + { + disableBTV = true; + } + else if (partitioner.currArea().lwidth() == 32 && cs.btFirstPartDecs[2] == CU_VERT_SPLIT) + { + disableBTV = true; + } + else if (partitioner.currArea().lwidth() == 16 && cs.btFirstPartDecs[3] == CU_VERT_SPLIT) + { + disableBTV = true; + } + } + else if (partitioner.currPartLevel().split == CU_VERT_SPLIT) // BTV Case + { + if (partitioner.currArea().lheight() == 128 && cs.btFirstPartDecs[0] == CU_HORZ_SPLIT) + { + disableBTH = true; + } + else if (partitioner.currArea().lheight() == 64 && cs.btFirstPartDecs[1] == CU_HORZ_SPLIT) + { + disableBTH = true; + } + else if (partitioner.currArea().lheight() == 32 && cs.btFirstPartDecs[2] == CU_HORZ_SPLIT) + { + disableBTH = true; + } + else if (partitioner.currArea().lheight() == 16 && cs.btFirstPartDecs[3] == CU_HORZ_SPLIT) + { + disableBTH = true; + } + } + } + } +#endif PartSplit mode = CU_DONT_SPLIT; bool canNo, canQt, canBh, canBv, canTh, canTv; #if JVET_AH0135_TEMPORAL_PARTITIONING unsigned maxMtt; - partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv, maxMtt ); + partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv, maxMtt +#if JVET_AI0087_BTCUS_RESTRICTION + , disableBTV, disableBTH +#endif + ); #else - partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv ); + partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv +#if JVET_AI0087_BTCUS_RESTRICTION + , disableBTV, disableBTH +#endif + ); #endif bool canSpl[6] = { canNo, canQt, canBh, canBv, canTh, canTv }; unsigned ctxSplit = 0, ctxQtSplit = 0, ctxBttHV = 0, ctxBttH12 = 0, ctxBttV12; - DeriveCtx::CtxSplit( cs, partitioner, ctxSplit, ctxQtSplit, ctxBttHV, ctxBttH12, ctxBttV12, canSpl ); + DeriveCtx::CtxSplit( cs, partitioner, ctxSplit, ctxQtSplit, ctxBttHV, ctxBttH12, ctxBttV12, canSpl +#if JVET_AI0087_BTCUS_RESTRICTION + , disableBTV, disableBTH +#endif + ); bool isSplit = canBh || canBv || canTh || canTv || canQt; #if JVET_AH0135_TEMPORAL_PARTITIONING @@ -1308,6 +1416,38 @@ PartSplit CABACReader::split_cu_mode( CodingStructure& cs, Partitioner &partitio mode = CU_TRIH_SPLIT; } +#if JVET_AI0087_BTCUS_RESTRICTION + if (CABACReader::isLumaNonBoundaryCu(partitioner, cs.picture->lwidth(), cs.picture->lheight()) + && (!(cs.slice->getProcessingIntraRegion() && cs.slice->getProcessingSeparateTrees()) || cs.slice->isIntra())) + { + if ((partitioner.currBtDepth == 1) && (partitioner.currPartIdx() == 0)) + { + if (partitioner.currPartLevel().split == CU_HORZ_SPLIT) // BTH Case + { + if (mode == CU_VERT_SPLIT) + { + CABACReader::setBtFirstPart(partitioner, partitioner.currArea().lwidth(), cs, CU_VERT_SPLIT); + } + else + { + CABACReader::setBtFirstPart(partitioner, partitioner.currArea().lwidth(), cs, CTU_LEVEL); + } + } + else if (partitioner.currPartLevel().split == CU_VERT_SPLIT) // BTV Case + { + if (mode == CU_HORZ_SPLIT) + { + CABACReader::setBtFirstPart(partitioner, partitioner.currArea().lheight(), cs, CU_HORZ_SPLIT); + } + else + { + CABACReader::setBtFirstPart(partitioner, partitioner.currArea().lheight(), cs, CTU_LEVEL); + } + } + } + } +#endif + DTRACE( g_trace_ctx, D_SYNTAX, "split_cu_mode() pos=(%d,%d) size=%dx%d chType=%d ctxHv=%d ctx12=%d mode=%d\n", block.x, block.y, block.width, block.height, partitioner.chType, ctxBttHV, isVer ? ctxBttV12 : ctxBttH12, mode ); return mode; @@ -1781,8 +1921,16 @@ void CABACReader::separate_tree_cu_flag( CodingUnit& cu, Partitioner& partitione bool inferredSeparateTreeFlag = false; if ( cu.slice->getSeparateTreeEnabled() && CU::isIntra( cu ) && !cu.cs->slice->getProcessingIntraRegion() ) { - bool canSplit = partitioner.canSplit(CU_QUAD_SPLIT, *cu.cs); - canSplit = canSplit || partitioner.canSplit( CU_MT_SPLIT, *cu.cs ); + bool canSplit = partitioner.canSplit(CU_QUAD_SPLIT, *cu.cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); + canSplit = canSplit || partitioner.canSplit( CU_MT_SPLIT, *cu.cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); int separateTreeFlag = -1; cu.cs->deriveSeparateTreeFlagInference( separateTreeFlag, inferredSeparateTreeFlag, partitioner.currArea().lumaSize().width, partitioner.currArea().lumaSize().height, canSplit ); @@ -7316,22 +7464,38 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, int subTuCounter = subTuIdx; // split_transform_flag - bool split = partitioner.canSplit(TU_MAX_TR_SPLIT, cs); + bool split = partitioner.canSplit(TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); const unsigned trDepth = partitioner.currTrDepth; - if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) ) + if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { split = true; } if( !split && cu.ispMode ) { - split = partitioner.canSplit( ispType, cs ); + split = partitioner.canSplit( ispType, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); } if( split ) { - if (partitioner.canSplit(TU_MAX_TR_SPLIT, cs)) + if (partitioner.canSplit(TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + )) { #if ENABLE_TRACING const CompArea &tuArea = partitioner.currArea().blocks[partitioner.chType]; @@ -7345,7 +7509,11 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, { partitioner.splitCurrArea(ispType, cs); } - else if (cu.sbtInfo && partitioner.canSplit(PartSplit(cu.getSbtTuSplit()), cs)) + else if (cu.sbtInfo && partitioner.canSplit(PartSplit(cu.getSbtTuSplit()), cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + )) { partitioner.splitCurrArea(PartSplit(cu.getSbtTuSplit()), cs); } diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 4bc58f2a2f788e9f7508e8a309f8365f262a8592..0696b2e94cf1ea9670cf7c78dd3f4255bfd2203b 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -70,6 +70,10 @@ public: const BinStoreVector *getBinBuffer() const { return m_BinDecoder.getBinBuffer(); } void updateCtxs (BinStoreVector *bb) { m_BinDecoder.updateCtxs(bb); } #endif +#if JVET_AI0087_BTCUS_RESTRICTION + bool isLumaNonBoundaryCu (const Partitioner& partitioner, SizeType picWidth, SizeType picHeight); + void setBtFirstPart (const Partitioner& partitioner, SizeType blockSize, CodingStructure& cs, PartSplit setValue); +#endif public: // slice segment data (clause 7.3.8.1) diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 986e8b933b6d3116eaaacb6f891236257bc21721..9052734e8de62b6bf543355c248039a9ebcf3417 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -139,6 +139,42 @@ SliceType xGetCtxInitId( const Slice& slice, const BinEncIf& binEncoder, Ctx& ct } } +#if JVET_AI0087_BTCUS_RESTRICTION +bool CABACWriter::isLumaNonBoundaryCu(const Partitioner& partitioner, SizeType picWidth, SizeType picHeight) +{ + bool validCU = false; + if (isLuma(partitioner.chType)) + { + int maxWidthHeight = std::max(partitioner.currArea().lwidth(), partitioner.currArea().lheight()) - 1; + if ((partitioner.currArea().Y().x + maxWidthHeight < picWidth) + && (partitioner.currArea().Y().y + maxWidthHeight < picHeight)) + { + validCU = true; + } + } + return validCU; +} + +void CABACWriter::setBtFirstPart(Partitioner& partitioner, SizeType blockSize, PartSplit setValue) +{ + if (blockSize == 128) + { + partitioner.btFirstPartDecs[0] = setValue; + } + else if (blockSize == 64) + { + partitioner.btFirstPartDecs[1] = setValue; + } + else if (blockSize == 32) + { + partitioner.btFirstPartDecs[2] = setValue; + } + else if (blockSize == 16) + { + partitioner.btFirstPartDecs[3] = setValue; + } +} +#endif SliceType CABACWriter::getCtxInitId( const Slice& slice ) { @@ -598,14 +634,21 @@ void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitione #endif const PartSplit splitMode = CU::getSplitAtDepth( cu, partitioner.currDepth ); - + split_cu_mode(splitMode, cs, partitioner #if JVET_AI0136_ADAPTIVE_DUAL_TREE - split_cu_mode( splitMode, cs, partitioner, &cu); + , & cu +#endif +#if JVET_AI0087_BTCUS_RESTRICTION + , true +#endif + ); + +#if JVET_AI0087_BTCUS_RESTRICTION + CHECK(!partitioner.canSplit(splitMode, cs, false, false), "The chosen split mode is invalid!"); #else - split_cu_mode( splitMode, cs, partitioner); + CHECK(!partitioner.canSplit(splitMode, cs), "The chosen split mode is invalid!"); #endif - CHECK( !partitioner.canSplit( splitMode, cs ), "The chosen split mode is invalid!" ); #if JVET_AI0136_ADAPTIVE_DUAL_TREE if( splitMode != CU_DONT_SPLIT && ( cs.slice->getProcessingIntraRegion() || !CU::isIntraRegionRoot( cu, partitioner ) ) ) @@ -829,25 +872,140 @@ void CABACWriter::mode_constraint( const PartSplit split, const CodingStructure& } } #endif - +void CABACWriter::split_cu_mode( const PartSplit split, const CodingStructure& cs, Partitioner& partitioner #if JVET_AI0136_ADAPTIVE_DUAL_TREE -void CABACWriter::split_cu_mode( const PartSplit split, const CodingStructure& cs, Partitioner& partitioner, const CodingUnit* cu ) -#else -void CABACWriter::split_cu_mode( const PartSplit split, const CodingStructure& cs, Partitioner& partitioner ) + , const CodingUnit* cu #endif +#if JVET_AI0087_BTCUS_RESTRICTION + , bool updatePartInfo +#endif +) { +#if JVET_AI0087_BTCUS_RESTRICTION + bool disableBTV = false; + bool disableBTH = false; + + if (CABACWriter::isLumaNonBoundaryCu(partitioner, cs.picture->lwidth(), cs.picture->lheight()) && (!(cs.slice->getProcessingIntraRegion() && cs.slice->getProcessingSeparateTrees()) || cs.slice->isIntra()) ) + { + if ((partitioner.currBtDepth == 0) && (partitioner.currArea().lwidth() == partitioner.currArea().lheight())) + { + if (updatePartInfo) + { + CABACWriter::setBtFirstPart(partitioner, partitioner.currArea().lwidth(), CTU_LEVEL); + } + } + + if ((partitioner.currBtDepth == 1) && (partitioner.currPartIdx() == 1)) + { + if (partitioner.currPartLevel().split == CU_HORZ_SPLIT) // BTH Case + { + if (updatePartInfo) + { + if (partitioner.currArea().lwidth() == 128 && partitioner.btFirstPartDecs[0] == CU_VERT_SPLIT) + { + disableBTV = true; + } + else if (partitioner.currArea().lwidth() == 64 && partitioner.btFirstPartDecs[1] == CU_VERT_SPLIT) + { + disableBTV = true; + } + else if (partitioner.currArea().lwidth() == 32 && partitioner.btFirstPartDecs[2] == CU_VERT_SPLIT) + { + disableBTV = true; + } + else if (partitioner.currArea().lwidth() == 16 && partitioner.btFirstPartDecs[3] == CU_VERT_SPLIT) + { + disableBTV = true; + } + } + else + { + if (partitioner.currArea().lwidth() == 128 && cs.btFirstPartDecs[0] == CU_VERT_SPLIT) + { + disableBTV = true; + } + else if (partitioner.currArea().lwidth() == 64 && cs.btFirstPartDecs[1] == CU_VERT_SPLIT) + { + disableBTV = true; + } + else if (partitioner.currArea().lwidth() == 32 && cs.btFirstPartDecs[2] == CU_VERT_SPLIT) + { + disableBTV = true; + } + else if (partitioner.currArea().lwidth() == 16 && cs.btFirstPartDecs[3] == CU_VERT_SPLIT) + { + disableBTV = true; + } + } + } + else if (partitioner.currPartLevel().split == CU_VERT_SPLIT) // BTV Case + { + if (updatePartInfo) + { + if (partitioner.currArea().lheight() == 128 && partitioner.btFirstPartDecs[0] == CU_HORZ_SPLIT) + { + disableBTH = true; + } + else if (partitioner.currArea().lheight() == 64 && partitioner.btFirstPartDecs[1] == CU_HORZ_SPLIT) + { + disableBTH = true; + } + else if (partitioner.currArea().lheight() == 32 && partitioner.btFirstPartDecs[2] == CU_HORZ_SPLIT) + { + disableBTH = true; + } + else if (partitioner.currArea().lheight() == 16 && partitioner.btFirstPartDecs[3] == CU_HORZ_SPLIT) + { + disableBTH = true; + } + } + else + { + if (partitioner.currArea().lheight() == 128 && cs.btFirstPartDecs[0] == CU_HORZ_SPLIT) + { + disableBTH = true; + } + else if (partitioner.currArea().lheight() == 64 && cs.btFirstPartDecs[1] == CU_HORZ_SPLIT) + { + disableBTH = true; + } + else if (partitioner.currArea().lheight() == 32 && cs.btFirstPartDecs[2] == CU_HORZ_SPLIT) + { + disableBTH = true; + } + else if (partitioner.currArea().lheight() == 16 && cs.btFirstPartDecs[3] == CU_HORZ_SPLIT) + { + disableBTH = true; + } + } + } + } + } +#endif bool canNo, canQt, canBh, canBv, canTh, canTv; #if JVET_AH0135_TEMPORAL_PARTITIONING unsigned maxMtt; - partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv, maxMtt ); + partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv, maxMtt +#if JVET_AI0087_BTCUS_RESTRICTION + , disableBTV, disableBTH +#endif + ); #else - partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv ); + partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv +#if JVET_AI0087_BTCUS_RESTRICTION + , disableBTV, disableBTH +#endif + ); #endif bool canSpl[6] = { canNo, canQt, canBh, canBv, canTh, canTv }; unsigned ctxSplit = 0, ctxQtSplit = 0, ctxBttHV = 0, ctxBttH12 = 0, ctxBttV12; - DeriveCtx::CtxSplit( cs, partitioner, ctxSplit, ctxQtSplit, ctxBttHV, ctxBttH12, ctxBttV12, canSpl ); + DeriveCtx::CtxSplit( cs, partitioner, ctxSplit, ctxQtSplit, ctxBttHV, ctxBttH12, ctxBttV12, canSpl +#if JVET_AI0087_BTCUS_RESTRICTION + , disableBTV, disableBTH +#endif + ); const bool canSplit = canBh || canBv || canTh || canTv || canQt; #if JVET_AI0136_ADAPTIVE_DUAL_TREE @@ -985,6 +1143,37 @@ void CABACWriter::split_cu_mode( const PartSplit split, const CodingStructure& c m_BinEncoder.encodeBin( is12, Ctx::Split12Flag( isVer ? ctxBttV12 : ctxBttH12 ) ); } +#if JVET_AI0087_BTCUS_RESTRICTION + if (CABACWriter::isLumaNonBoundaryCu(partitioner, cs.picture->lwidth(), cs.picture->lheight()) + && (!(cs.slice->getProcessingIntraRegion() && cs.slice->getProcessingSeparateTrees()) || cs.slice->isIntra())) + { + if (updatePartInfo && (partitioner.currBtDepth == 1) && (partitioner.currPartIdx() == 0)) + { + if (partitioner.currPartLevel().split == CU_HORZ_SPLIT) // BTH Case + { + if (split == CU_VERT_SPLIT) + { + CABACWriter::setBtFirstPart(partitioner, partitioner.currArea().lwidth(), CU_VERT_SPLIT); + } + else + { + CABACWriter::setBtFirstPart(partitioner, partitioner.currArea().lwidth(), CTU_LEVEL); + } + } + else if (partitioner.currPartLevel().split == CU_VERT_SPLIT) // BTV Case + { + if (split == CU_HORZ_SPLIT) + { + CABACWriter::setBtFirstPart(partitioner, partitioner.currArea().lheight(), CU_HORZ_SPLIT); + } + else + { + CABACWriter::setBtFirstPart(partitioner, partitioner.currArea().lheight(), CTU_LEVEL); + } + } + } + } +#endif DTRACE( g_trace_ctx, D_SYNTAX, "split_cu_mode() pos=(%d,%d) size=%dx%d chType=%d ctxHv=%d ctx12=%d mode=%d\n", block.x, block.y, block.width, block.height, partitioner.chType, ctxBttHV, isVer ? ctxBttV12 : ctxBttH12, split); } @@ -1291,8 +1480,16 @@ void CABACWriter::separate_tree_cu_flag( const CodingUnit& cu, Partitioner& part if ( cu.slice->getSeparateTreeEnabled() && !cu.slice->getProcessingIntraRegion() && CU::isIntra( cu ) && CU::isIntraRegionRoot( cu, partitioner ) ) #endif { - bool canSplit = partitioner.canSplit( CU_QUAD_SPLIT, *cu.cs ); - canSplit = canSplit || partitioner.canSplit( CU_MT_SPLIT, *cu.cs ); + bool canSplit = partitioner.canSplit( CU_QUAD_SPLIT, *cu.cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); + canSplit = canSplit || partitioner.canSplit( CU_MT_SPLIT, *cu.cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); cu.cs->determineIfSeparateTreeFlagInferred( inferredSeparateTreeFlag, partitioner.currArea().lumaSize().width, partitioner.currArea().lumaSize().height, canSplit ); if ( !inferredSeparateTreeFlag ) @@ -7124,11 +7321,19 @@ void CABACWriter::transform_tree(const CodingStructure& cs, Partitioner& partiti const bool split = (tu.depth > trDepth); // split_transform_flag - if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) + if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { CHECK( !split, "transform split implied" ); } - else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) ) + else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { CHECK( !split, "transform split implied - sbt" ); } @@ -7139,7 +7344,11 @@ void CABACWriter::transform_tree(const CodingStructure& cs, Partitioner& partiti if( split ) { - if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) + if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { #if ENABLE_TRACING const CompArea &tuArea = partitioner.currArea().blocks[partitioner.chType]; @@ -7152,7 +7361,11 @@ void CABACWriter::transform_tree(const CodingStructure& cs, Partitioner& partiti { partitioner.splitCurrArea( ispType, cs ); } - else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) ) + else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { partitioner.splitCurrArea( PartSplit( cu.getSbtTuSplit() ), cs ); } diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index 26fb5603c05889b307d8953d1d1fbc1d0ee1168b..2460594cac40f5c775af998b4dddd3ff50039de5 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -64,9 +64,13 @@ public: public: #if JVET_AG0196_CABAC_RETRAIN - void initCtxModels ( Slice& slice ); + void initCtxModels(Slice &slice); #else - void initCtxModels ( const Slice& slice ); + void initCtxModels(const Slice &slice); +#endif +#if JVET_AI0087_BTCUS_RESTRICTION + bool isLumaNonBoundaryCu(const Partitioner& partitioner, SizeType picWidth, SizeType picHeight); + void setBtFirstPart(Partitioner& partitioner, SizeType blockSize, PartSplit setValue); #endif void setEncCu(EncCu* pcEncCu) { m_EncCu = pcEncCu; } SliceType getCtxInitId ( const Slice& slice ); @@ -109,10 +113,18 @@ public: // coding (quad)tree (clause 7.3.8.4) #if JVET_AI0136_ADAPTIVE_DUAL_TREE void coding_tree ( const CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, int (&qps)[2], Partitioner* pPartitionerChroma = nullptr, CUCtx* pCuCtxChroma = nullptr); - void split_cu_mode ( const PartSplit split, const CodingStructure& cs, Partitioner& pm, const CodingUnit* cu ); + void split_cu_mode ( const PartSplit split, const CodingStructure& cs, Partitioner& pm, const CodingUnit* cu +#if JVET_AI0087_BTCUS_RESTRICTION + , bool btUpdateInfo +#endif + ); #else void coding_tree ( const CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, Partitioner* pPartitionerChroma = nullptr, CUCtx* pCuCtxChroma = nullptr); - void split_cu_mode ( const PartSplit split, const CodingStructure& cs, Partitioner& pm ); + void split_cu_mode ( const PartSplit split, const CodingStructure& cs, Partitioner& pm +#if JVET_AI0087_BTCUS_RESTRICTION + , bool btUpdateInfo +#endif + ); #endif #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS void mode_constraint ( const PartSplit split, const CodingStructure& cs, Partitioner& pm, const ModeType modeType ); diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index bb3a6eee125d801e1754e7d6110ffd79d7452381..bd7942a254a8b7311fb032c011863dad080ce420 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -878,6 +878,119 @@ int EncCu::updateCtuDataISlice(const CPelBuf buf) return( iSumHad ); } +#if JVET_AI0087_BTCUS_RESTRICTION +bool EncCu::isLumaNonBoundaryCu(const Partitioner &partitioner, SizeType picWidth, SizeType picHeight) +{ + bool validCU = false; + if (isLuma(partitioner.chType)) + { + int maxWidthHeight = std::max(partitioner.currArea().lwidth(), partitioner.currArea().lheight()) - 1; + if ((partitioner.currArea().Y().x + maxWidthHeight < picWidth) + && (partitioner.currArea().Y().y + maxWidthHeight < picHeight)) + { + validCU = true; + } + } + return validCU; +} +bool EncCu::xStoreRDcostandPredMode(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode &encTestMode, double lastModeBestCost) +{ + if (EncCu::isLumaNonBoundaryCu(partitioner, bestCS->picture->lwidth(), bestCS->picture->lheight()) + && (!(bestCS->slice->getProcessingIntraRegion() && bestCS->slice->getProcessingSeparateTrees()) + || bestCS->slice->isIntra())) + { + bool PrevbestCostisChangedtoNewBestCost = (lastModeBestCost != bestCS->cost); + if ((partitioner.currBtDepth == 1) && (partitioner.currPartIdx() == 0) && PrevbestCostisChangedtoNewBestCost) + { + if (partitioner.currPartLevel().split == CU_HORZ_SPLIT + || partitioner.currPartLevel().split == CU_VERT_SPLIT) // BTH or BTV Case + { + if (partitioner.currPartLevel().split == CU_HORZ_SPLIT) + { + if (partitioner.currArea().lwidth() == 128) + { + bestCS->btFirstPartDecs[0] = encTestMode.type == ETM_SPLIT_BT_H + ? CU_HORZ_SPLIT + : (encTestMode.type == ETM_SPLIT_BT_V ? CU_VERT_SPLIT : 0); + tempCS->btFirstPartDecs[0] = encTestMode.type == ETM_SPLIT_BT_H + ? CU_HORZ_SPLIT + : (encTestMode.type == ETM_SPLIT_BT_V ? CU_VERT_SPLIT : 0); + } + else if (partitioner.currArea().lwidth() == 64) + { + bestCS->btFirstPartDecs[1] = encTestMode.type == ETM_SPLIT_BT_H + ? CU_HORZ_SPLIT + : (encTestMode.type == ETM_SPLIT_BT_V ? CU_VERT_SPLIT : 0); + tempCS->btFirstPartDecs[1] = encTestMode.type == ETM_SPLIT_BT_H + ? CU_HORZ_SPLIT + : (encTestMode.type == ETM_SPLIT_BT_V ? CU_VERT_SPLIT : 0); + } + else if (partitioner.currArea().lwidth() == 32) + { + bestCS->btFirstPartDecs[2] = encTestMode.type == ETM_SPLIT_BT_H + ? CU_HORZ_SPLIT + : (encTestMode.type == ETM_SPLIT_BT_V ? CU_VERT_SPLIT : 0); + tempCS->btFirstPartDecs[2] = encTestMode.type == ETM_SPLIT_BT_H + ? CU_HORZ_SPLIT + : (encTestMode.type == ETM_SPLIT_BT_V ? CU_VERT_SPLIT : 0); + } + else if (partitioner.currArea().lwidth() == 16) + { + bestCS->btFirstPartDecs[3] = encTestMode.type == ETM_SPLIT_BT_H + ? CU_HORZ_SPLIT + : (encTestMode.type == ETM_SPLIT_BT_V ? CU_VERT_SPLIT : 0); + tempCS->btFirstPartDecs[3] = encTestMode.type == ETM_SPLIT_BT_H + ? CU_HORZ_SPLIT + : (encTestMode.type == ETM_SPLIT_BT_V ? CU_VERT_SPLIT : 0); + } + } + else + { + if (partitioner.currArea().lheight() == 128) + { + bestCS->btFirstPartDecs[0] = encTestMode.type == ETM_SPLIT_BT_H + ? CU_HORZ_SPLIT + : (encTestMode.type == ETM_SPLIT_BT_V ? CU_VERT_SPLIT : 0); + tempCS->btFirstPartDecs[0] = encTestMode.type == ETM_SPLIT_BT_H + ? CU_HORZ_SPLIT + : (encTestMode.type == ETM_SPLIT_BT_V ? CU_VERT_SPLIT : 0); + } + else if (partitioner.currArea().lheight() == 64) + { + bestCS->btFirstPartDecs[1] = encTestMode.type == ETM_SPLIT_BT_H + ? CU_HORZ_SPLIT + : (encTestMode.type == ETM_SPLIT_BT_V ? CU_VERT_SPLIT : 0); + tempCS->btFirstPartDecs[1] = encTestMode.type == ETM_SPLIT_BT_H + ? CU_HORZ_SPLIT + : (encTestMode.type == ETM_SPLIT_BT_V ? CU_VERT_SPLIT : 0); + } + else if (partitioner.currArea().lheight() == 32) + { + bestCS->btFirstPartDecs[2] = encTestMode.type == ETM_SPLIT_BT_H + ? CU_HORZ_SPLIT + : (encTestMode.type == ETM_SPLIT_BT_V ? CU_VERT_SPLIT : 0); + tempCS->btFirstPartDecs[2] = encTestMode.type == ETM_SPLIT_BT_H + ? CU_HORZ_SPLIT + : (encTestMode.type == ETM_SPLIT_BT_V ? CU_VERT_SPLIT : 0); + } + else if (partitioner.currArea().lheight() == 16) + { + bestCS->btFirstPartDecs[3] = encTestMode.type == ETM_SPLIT_BT_H + ? CU_HORZ_SPLIT + : (encTestMode.type == ETM_SPLIT_BT_V ? CU_VERT_SPLIT : 0); + tempCS->btFirstPartDecs[3] = encTestMode.type == ETM_SPLIT_BT_H + ? CU_HORZ_SPLIT + : (encTestMode.type == ETM_SPLIT_BT_V ? CU_VERT_SPLIT : 0); + } + } + } + } + } + + return true; +} +#endif + bool EncCu::xCheckBestMode( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode ) { bool bestCSUpdated = false; @@ -1345,6 +1458,9 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par if( currTestMode.type == ETM_INTER_ME ) { +#if JVET_AI0087_BTCUS_RESTRICTION + double lastModeBestCost = bestCS->cost == MAX_DOUBLE ? MAX_DOUBLE : bestCS->cost; +#endif #if ENABLE_OBMC bool tryObmc = true; #if JVET_AA0129_INTERHASH_OBMCOFF_RD @@ -1365,6 +1481,9 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par tryObmc = xCheckRDCostInterIMV(tempCS, bestCS, partitioner, currTestMode, bestIntPelCost); #else xCheckRDCostInterIMV(tempCS, bestCS, partitioner, currTestMode, bestIntPelCost); +#endif +#if JVET_AI0087_BTCUS_RESTRICTION + xStoreRDcostandPredMode(tempCS, bestCS, partitioner, currTestMode, lastModeBestCost); #endif tempCS->bestCS = nullptr; #if JVET_Y0152_TT_ENC_SPEEDUP @@ -1380,6 +1499,9 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par tryObmc = xCheckRDCostInter(tempCS, bestCS, partitioner, currTestMode); #else xCheckRDCostInter( tempCS, bestCS, partitioner, currTestMode ); +#endif +#if JVET_AI0087_BTCUS_RESTRICTION + xStoreRDcostandPredMode(tempCS, bestCS, partitioner, currTestMode, lastModeBestCost); #endif tempCS->bestCS = nullptr; #if JVET_Y0152_TT_ENC_SPEEDUP @@ -1400,6 +1522,9 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par } else if (currTestMode.type == ETM_HASH_INTER) { +#if JVET_AI0087_BTCUS_RESTRICTION + double lastModeBestCost = bestCS->cost == MAX_DOUBLE ? MAX_DOUBLE : bestCS->cost; +#endif #if ENABLE_OBMC && JVET_AA0129_INTERHASH_OBMCOFF_RD bool tryObmc = xCheckRDCostHashInter( tempCS, bestCS, partitioner, currTestMode ); #else @@ -1414,6 +1539,9 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par { xCheckRDCostInterWoOBMC( tempCS, bestCS, partitioner, currTestMode ); } +#endif +#if JVET_AI0087_BTCUS_RESTRICTION + xStoreRDcostandPredMode(tempCS, bestCS, partitioner, currTestMode, lastModeBestCost); #endif } #if !MERGE_ENC_OPT @@ -1449,7 +1577,13 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par #if REUSE_CU_RESULTS else if( currTestMode.type == ETM_RECO_CACHED ) { +#if JVET_AI0087_BTCUS_RESTRICTION + double lastModeBestCost = bestCS->cost == MAX_DOUBLE ? MAX_DOUBLE : bestCS->cost; +#endif xReuseCachedResult( tempCS, bestCS, partitioner ); +#if JVET_AI0087_BTCUS_RESTRICTION + xStoreRDcostandPredMode(tempCS, bestCS, partitioner, currTestMode, lastModeBestCost); +#endif #if JVET_Y0152_TT_ENC_SPEEDUP splitRdCostBest[CTU_LEVEL] = bestCS->cost; tempCS->splitRdCostBest = splitRdCostBest; @@ -1458,7 +1592,13 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par #endif else if( currTestMode.type == ETM_MERGE_SKIP ) { +#if JVET_AI0087_BTCUS_RESTRICTION + double lastModeBestCost = bestCS->cost == MAX_DOUBLE ? MAX_DOUBLE : bestCS->cost; +#endif xCheckRDCostMerge2Nx2N( tempCS, bestCS, partitioner, currTestMode ); +#if JVET_AI0087_BTCUS_RESTRICTION + xStoreRDcostandPredMode(tempCS, bestCS, partitioner, currTestMode, lastModeBestCost); +#endif CodingUnit* cu = bestCS->getCU(partitioner.chType); @@ -1471,6 +1611,9 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par } else if( currTestMode.type == ETM_MERGE_GEO ) { +#if JVET_AI0087_BTCUS_RESTRICTION + double lastModeBestCost = bestCS->cost == MAX_DOUBLE ? MAX_DOUBLE : bestCS->cost; +#endif #if JVET_W0097_GPM_MMVD_TM CodedCUInfo &relatedCU = ((EncModeCtrlMTnoRQT *)m_modeCtrl)->getBlkInfo(partitioner.currArea()); if (!relatedCU.isGPMTested) @@ -1485,6 +1628,9 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par #else xCheckRDCostMergeGeo2Nx2N( tempCS, bestCS, partitioner, currTestMode ); #endif +#if JVET_AI0087_BTCUS_RESTRICTION + xStoreRDcostandPredMode(tempCS, bestCS, partitioner, currTestMode, lastModeBestCost); +#endif #if JVET_Y0152_TT_ENC_SPEEDUP splitRdCostBest[CTU_LEVEL] = bestCS->cost; tempCS->splitRdCostBest = splitRdCostBest; @@ -1493,7 +1639,13 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par #if MULTI_HYP_PRED else if (currTestMode.type == ETM_INTER_MULTIHYP) { +#if JVET_AI0087_BTCUS_RESTRICTION + double lastModeBestCost = bestCS->cost == MAX_DOUBLE ? MAX_DOUBLE : bestCS->cost; +#endif xCheckRDCostInterMultiHyp2Nx2N(tempCS, bestCS, partitioner, currTestMode); +#if JVET_AI0087_BTCUS_RESTRICTION + xStoreRDcostandPredMode(tempCS, bestCS, partitioner, currTestMode, lastModeBestCost); +#endif #if JVET_Y0152_TT_ENC_SPEEDUP splitRdCostBest[CTU_LEVEL] = bestCS->cost; tempCS->splitRdCostBest = splitRdCostBest; @@ -1502,6 +1654,9 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par #endif else if( currTestMode.type == ETM_INTRA ) { +#if JVET_AI0087_BTCUS_RESTRICTION + double lastModeBestCost = bestCS->cost == MAX_DOUBLE ? MAX_DOUBLE : bestCS->cost; +#endif if (slice.getSPS()->getUseColorTrans() && !CS::isDualITree(*tempCS)) { bool skipSecColorSpace = false; @@ -1548,7 +1703,9 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par } } #endif - +#if JVET_AI0087_BTCUS_RESTRICTION + xStoreRDcostandPredMode(tempCS, bestCS, partitioner, currTestMode, lastModeBestCost); +#endif #if JVET_Y0152_TT_ENC_SPEEDUP splitRdCostBest[CTU_LEVEL] = bestCS->cost; tempCS->splitRdCostBest = splitRdCostBest; @@ -1557,8 +1714,16 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par #if JVET_AI0136_ADAPTIVE_DUAL_TREE else if( currTestMode.type == ETM_SEPARATE_TREE_INTRA ) { +#if JVET_AI0087_BTCUS_RESTRICTION + double lastModeBestCost = bestCS->cost == MAX_DOUBLE ? MAX_DOUBLE : bestCS->cost; +#endif xCheckRDCostSeparateTreeIntra( tempCS, bestCS, partitioner, currTestMode ); +#if JVET_AI0087_BTCUS_RESTRICTION + xStoreRDcostandPredMode(tempCS, bestCS, partitioner, currTestMode, lastModeBestCost); +#endif + + #if JVET_AI0136_ADAPTIVE_DUAL_TREE #if JVET_Z0118_GDR if (bestCS->cus.size() > 0 && splitmode != bestCS->cus[0]->splitSeries) @@ -1582,7 +1747,13 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par #endif else if (currTestMode.type == ETM_PALETTE) { +#if JVET_AI0087_BTCUS_RESTRICTION + double lastModeBestCost = bestCS->cost == MAX_DOUBLE ? MAX_DOUBLE : bestCS->cost; +#endif xCheckPLT( tempCS, bestCS, partitioner, currTestMode ); +#if JVET_AI0087_BTCUS_RESTRICTION + xStoreRDcostandPredMode(tempCS, bestCS, partitioner, currTestMode, lastModeBestCost); +#endif #if JVET_Y0152_TT_ENC_SPEEDUP splitRdCostBest[CTU_LEVEL] = bestCS->cost; tempCS->splitRdCostBest = splitRdCostBest; @@ -1590,6 +1761,9 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par } else if (currTestMode.type == ETM_IBC) { +#if JVET_AI0087_BTCUS_RESTRICTION + double lastModeBestCost = bestCS->cost == MAX_DOUBLE ? MAX_DOUBLE : bestCS->cost; +#endif #if JVET_AA0070_RRIBC if (m_pcEncCfg->getIntraPeriod() <= 1) { @@ -1607,6 +1781,9 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par else #endif xCheckRDCostIBCMode(tempCS, bestCS, partitioner, currTestMode); +#if JVET_AI0087_BTCUS_RESTRICTION + xStoreRDcostandPredMode(tempCS, bestCS, partitioner, currTestMode, lastModeBestCost); +#endif #if JVET_Y0152_TT_ENC_SPEEDUP splitRdCostBest[CTU_LEVEL] = bestCS->cost; tempCS->splitRdCostBest = splitRdCostBest; @@ -1614,10 +1791,16 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par } else if (currTestMode.type == ETM_IBC_MERGE) { +#if JVET_AI0087_BTCUS_RESTRICTION + double lastModeBestCost = bestCS->cost == MAX_DOUBLE ? MAX_DOUBLE : bestCS->cost; +#endif #if JVET_AE0169_BIPREDICTIVE_IBC if (!m_skipIbcMerge) #endif xCheckRDCostIBCModeMerge2Nx2N(tempCS, bestCS, partitioner, currTestMode); +#if JVET_AI0087_BTCUS_RESTRICTION + xStoreRDcostandPredMode(tempCS, bestCS, partitioner, currTestMode, lastModeBestCost); +#endif #if JVET_Y0152_TT_ENC_SPEEDUP splitRdCostBest[CTU_LEVEL] = bestCS->cost; tempCS->splitRdCostBest = splitRdCostBest; @@ -1629,6 +1812,9 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par { splitmode = bestCS->cus[0]->splitSeries; } +#if JVET_AI0087_BTCUS_RESTRICTION + double lastModeBestCost = bestCS->cost == MAX_DOUBLE ? MAX_DOUBLE : bestCS->cost; +#endif #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS assert( partitioner.modeType == tempCS->modeType ); int signalModeConsVal = tempCS->signalModeCons( getPartSplit( currTestMode ), partitioner, modeTypeParent ); @@ -1682,6 +1868,9 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par xCheckModeSplit(tempCS, bestCS, partitioner, currTestMode); #endif #endif +#if JVET_AI0087_BTCUS_RESTRICTION + xStoreRDcostandPredMode(tempCS, bestCS, partitioner, currTestMode, lastModeBestCost); +#endif #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS //recover cons modes tempCS->modeType = partitioner.modeType = modeTypeParent; @@ -2305,9 +2494,17 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, m_CABACEstimator->resetBits(); #if JVET_AI0136_ADAPTIVE_DUAL_TREE - m_CABACEstimator->split_cu_mode( split, *tempCS, partitioner, nullptr ); + m_CABACEstimator->split_cu_mode( split, *tempCS, partitioner, nullptr +#if JVET_AI0087_BTCUS_RESTRICTION + , false +#endif + ); #else - m_CABACEstimator->split_cu_mode( split, *tempCS, partitioner ); + m_CABACEstimator->split_cu_mode(split, *tempCS, partitioner +#if JVET_AI0087_BTCUS_RESTRICTION + , false +#endif + ); #endif #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS m_CABACEstimator->mode_constraint( split, *tempCS, partitioner, modeTypeChild ); @@ -2401,6 +2598,66 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, } } #endif +#if JVET_AI0087_BTCUS_RESTRICTION + if (EncCu::isLumaNonBoundaryCu(partitioner, bestCS->picture->lwidth(), bestCS->picture->lheight()) + && (!(bestCS->slice->getProcessingIntraRegion() && bestCS->slice->getProcessingSeparateTrees()) + || bestCS->slice->isIntra())) + { + if (partitioner.currPartLevel().split == CU_HORZ_SPLIT + || partitioner.currPartLevel().split == CU_VERT_SPLIT) // BTH or BTV Case + { + if ((partitioner.currBtDepth == 1) && (partitioner.currPartIdx() == 0)) + { + if (partitioner.currPartLevel().split == CU_HORZ_SPLIT) + { + if (partitioner.currArea().lwidth() == 128) + { + tempCS->btFirstPartDecs[0] = 0; + bestCS->btFirstPartDecs[0] = 0; + } + else if (partitioner.currArea().lwidth() == 64) + { + tempCS->btFirstPartDecs[1] = 0; + bestCS->btFirstPartDecs[1] = 0; + } + else if (partitioner.currArea().lwidth() == 32) + { + tempCS->btFirstPartDecs[2] = 0; + bestCS->btFirstPartDecs[2] = 0; + } + else if (partitioner.currArea().lwidth() == 16) + { + tempCS->btFirstPartDecs[3] = 0; + bestCS->btFirstPartDecs[3] = 0; + } + } + else + { + if (partitioner.currArea().lheight() == 128) + { + tempCS->btFirstPartDecs[0] = 0; + bestCS->btFirstPartDecs[0] = 0; + } + else if (partitioner.currArea().lheight() == 64) + { + tempCS->btFirstPartDecs[1] = 0; + bestCS->btFirstPartDecs[1] = 0; + } + else if (partitioner.currArea().lheight() == 32) + { + tempCS->btFirstPartDecs[2] = 0; + bestCS->btFirstPartDecs[2] = 0; + } + if (partitioner.currArea().lheight() == 16) + { + tempCS->btFirstPartDecs[3] = 0; + bestCS->btFirstPartDecs[3] = 0; + } + } + } + } + } +#endif tempCS->initSubStructure( *tempSubCS, partitioner.chType, subCUArea, false ); tempCS->initSubStructure( *bestSubCS, partitioner.chType, subCUArea, false ); tempSubCS->bestParent = bestSubCS->bestParent = bestCS; @@ -2628,9 +2885,17 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, m_CABACEstimator->resetBits(); #if JVET_AI0136_ADAPTIVE_DUAL_TREE - m_CABACEstimator->split_cu_mode( split, *tempCS, partitioner, nullptr ); + m_CABACEstimator->split_cu_mode(split, *tempCS, partitioner, nullptr +#if JVET_AI0087_BTCUS_RESTRICTION + , false +#endif + ); #else - m_CABACEstimator->split_cu_mode( split, *tempCS, partitioner ); + m_CABACEstimator->split_cu_mode(split, *tempCS, partitioner +#if JVET_AI0087_BTCUS_RESTRICTION + , false +#endif + ); #endif #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS partitioner.modeType = modeTypeParent; @@ -2723,8 +2988,16 @@ void EncCu::xCheckRDCostSeparateTreeIntra( CodingStructure *&tempCS, CodingStruc int startFlagVal = 0; int endFlagVal = 1; int inferredFlagVal = -1; - bool canSplit = partitioner.canSplit( CU_QUAD_SPLIT, *tempCS ); - canSplit = canSplit || partitioner.canSplit( CU_MT_SPLIT, *tempCS ); + bool canSplit = partitioner.canSplit( CU_QUAD_SPLIT, *tempCS +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); + canSplit = canSplit || partitioner.canSplit( CU_MT_SPLIT, *tempCS +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); tempCS->deriveSeparateTreeFlagInference( inferredFlagVal, inferredSeparateTreeFlag, partitioner.currArea().lwidth(), partitioner.currArea().lheight(), canSplit ); if ( inferredSeparateTreeFlag ) @@ -23634,11 +23907,14 @@ void EncCu::xEncodeInterResidual( CodingStructure *&tempCS void EncCu::xEncodeDontSplit( CodingStructure &cs, Partitioner &partitioner ) { m_CABACEstimator->resetBits(); + m_CABACEstimator->split_cu_mode(CU_DONT_SPLIT, cs, partitioner #if JVET_AI0136_ADAPTIVE_DUAL_TREE - m_CABACEstimator->split_cu_mode( CU_DONT_SPLIT, cs, partitioner, nullptr ); -#else - m_CABACEstimator->split_cu_mode( CU_DONT_SPLIT, cs, partitioner ); + , nullptr +#endif +#if JVET_AI0087_BTCUS_RESTRICTION + , false #endif + ); #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS if( partitioner.treeType == TREE_C ) CHECK( m_CABACEstimator->getEstFracBits() != 0, "must be 0 bit" ); diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h index 218a4cd0946082a3c3bf1a5f7f1ec91d6d3dc626..8f16a4d7074e8f83b4dff429e665bc4c6c121613 100644 --- a/source/Lib/EncoderLib/EncCu.h +++ b/source/Lib/EncoderLib/EncCu.h @@ -494,7 +494,11 @@ public: void compressCtu ( CodingStructure& cs, const UnitArea& area, const unsigned ctuRsAddr, const int prevQP[], const int currQP[] ); /// CTU encoding function int updateCtuDataISlice ( const CPelBuf buf ); - + /// function to check whether the current CU is luma and non-boundary CU +#if JVET_AI0087_BTCUS_RESTRICTION + bool isLumaNonBoundaryCu(const Partitioner &partitioner, SizeType picWidth, SizeType picHeight); + bool xStoreRDcostandPredMode(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode &encTestmode, double tempcost); +#endif EncModeCtrl* getModeCtrl () { return m_modeCtrl; } #if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER @@ -521,7 +525,6 @@ protected: void xCompressCUParallel ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm ); void copyState ( EncCu* other, Partitioner& pm, const UnitArea& currArea, const bool isDist ); #endif - bool xCheckBestMode ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestmode ); #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp index 3cf0aeee7a9c6f88285aeea80ca4cf64f016e5d3..d9ffc6e843dd11b5ff679a4f3771fa433b703594 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.cpp +++ b/source/Lib/EncoderLib/EncModeCtrl.cpp @@ -177,6 +177,23 @@ void EncModeCtrl::setBest( CodingStructure& cs ) } } +#if JVET_AI0087_BTCUS_RESTRICTION +bool EncModeCtrl::isLumaNonBoundaryCu(const Partitioner& partitioner, SizeType picWidth, SizeType picHeight) +{ + bool validCU = false; + if (isLuma(partitioner.chType)) + { + int maxWidthHeight = std::max(partitioner.currArea().lwidth(), partitioner.currArea().lheight()) - 1; + if ((partitioner.currArea().Y().x + maxWidthHeight < picWidth) + && (partitioner.currArea().Y().y + maxWidthHeight < picHeight)) + { + validCU = true; + } + } + return validCU; +} +#endif + void EncModeCtrl::xGetMinMaxQP( int& minQP, int& maxQP, const CodingStructure& cs, const Partitioner &partitioner, const int baseQP, const SPS& sps, const PPS& pps, const PartSplit splitMode ) { if( m_pcEncCfg->getUseRateCtrl() ) @@ -1707,6 +1724,57 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru m_ComprCUCtxList.push_back( ComprCUCtx( cs, minDepth, maxDepth, NUM_EXTRA_FEATURES ) ); #endif +#if JVET_AI0087_BTCUS_RESTRICTION + bool disableBTV = false; + bool disableBTH = false; + if (EncModeCtrl::isLumaNonBoundaryCu(partitioner, cs.picture->lwidth(), cs.picture->lheight()) && (!(cs.slice->getProcessingIntraRegion() && cs.slice->getProcessingSeparateTrees()) || cs.slice->isIntra()) ) + { + if ((partitioner.currBtDepth == 1) && (partitioner.currPartIdx() == 1)) + { + if (partitioner.currPartLevel().split == CU_HORZ_SPLIT) // BTH Case + { + if (partitioner.currArea().lwidth() == 128 && cs.btFirstPartDecs[0] == CU_VERT_SPLIT) + { + disableBTV = true; + } + + else if (partitioner.currArea().lwidth() == 64 && cs.btFirstPartDecs[1] == CU_VERT_SPLIT) + { + disableBTV = true; + } + else if (partitioner.currArea().lwidth() == 32 && cs.btFirstPartDecs[2] == CU_VERT_SPLIT) + { + disableBTV = true; + } + else if (partitioner.currArea().lwidth() == 16 && cs.btFirstPartDecs[3] == CU_VERT_SPLIT) + { + disableBTV = true; + } + } + + else if (partitioner.currPartLevel().split == CU_VERT_SPLIT) // BTV Case + { + if (partitioner.currArea().lheight() == 128 && cs.btFirstPartDecs[0] == CU_HORZ_SPLIT) + { + disableBTH = true; + } + else if (partitioner.currArea().lheight() == 64 && cs.btFirstPartDecs[1] == CU_HORZ_SPLIT) + { + disableBTH = true; + } + else if (partitioner.currArea().lheight() == 32 && cs.btFirstPartDecs[2] == CU_HORZ_SPLIT) + { + disableBTH = true; + } + if (partitioner.currArea().lheight() == 16 && cs.btFirstPartDecs[3] == CU_HORZ_SPLIT) + { + disableBTH = true; + } + } + } + } +#endif + #if ENABLE_SPLIT_PARALLELISM if( m_runNextInParallel ) { @@ -1735,7 +1803,11 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru unsigned maxBTD; bool canNo, canQt, canBh, canBv, canTh, canTv; - partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv, maxBTD ); + partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv, maxBTD +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); if (!canBh && !canBv) { @@ -1862,7 +1934,11 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru #if JVET_AH0135_TEMPORAL_PARTITIONING if ( canTv ) #else - if( partitioner.canSplit( CU_TRIV_SPLIT, cs ) ) + if( partitioner.canSplit( CU_TRIV_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) #endif { // add split modes @@ -1879,7 +1955,11 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru #if JVET_AH0135_TEMPORAL_PARTITIONING if ( canTh ) #else - if( partitioner.canSplit( CU_TRIH_SPLIT, cs ) ) + if( partitioner.canSplit( CU_TRIH_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) #endif { // add split modes @@ -1897,9 +1977,17 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru int maxQPq = maxQP; xGetMinMaxQP( minQP, maxQP, cs, partitioner, baseQP, *cs.sps, *cs.pps, CU_BT_SPLIT ); #if JVET_AH0135_TEMPORAL_PARTITIONING - if ( canBv ) + if ( canBv +#if JVET_AI0087_BTCUS_RESTRICTION + && !(disableBTV) +#endif + ) #else - if( partitioner.canSplit( CU_VERT_SPLIT, cs ) ) + if( partitioner.canSplit( CU_VERT_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , disableBTV, disableBTH +#endif + ) ) #endif { // add split modes @@ -1927,9 +2015,17 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru } #if JVET_AH0135_TEMPORAL_PARTITIONING - if ( canBh ) + if ( canBh +#if JVET_AI0087_BTCUS_RESTRICTION + && !(disableBTH) +#endif + ) #else - if( partitioner.canSplit( CU_HORZ_SPLIT, cs ) ) + if( partitioner.canSplit( CU_HORZ_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , disableBTV, disableBTH +#endif + ) ) #endif { // add split modes @@ -2519,7 +2615,11 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt } else if( isBoundary && encTestmode.type == ETM_SPLIT_QT ) { - return partitioner.canSplit( CU_QUAD_SPLIT, cs ); + return partitioner.canSplit( CU_QUAD_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); } #if REUSE_CU_RESULTS @@ -2558,17 +2658,26 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt CodedCUInfo &relatedCU = getBlkInfo( partitioner.currArea() ); #endif - if( cuECtx.minDepth > partitioner.currQtDepth && partitioner.canSplit( CU_QUAD_SPLIT, cs ) ) + if( cuECtx.minDepth > partitioner.currQtDepth && partitioner.canSplit( CU_QUAD_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + + ) ) { // enforce QT return encTestmode.type == ETM_SPLIT_QT; } - else if( encTestmode.type == ETM_SPLIT_QT && cuECtx.maxDepth <= partitioner.currQtDepth ) + else if (encTestmode.type == ETM_SPLIT_QT && cuECtx.maxDepth <= partitioner.currQtDepth) { - // don't check this QT depth - return false; +#if JVET_AI0087_BTCUS_RESTRICTION + if (!(partitioner.chType == CHANNEL_TYPE_LUMA && partitioner.currBtDepth == 0 && (partitioner.currArea().lwidth() == 128 || partitioner.currArea().lwidth() == 64 || partitioner.currArea().lwidth() == 32))) +#endif + { + // don't check this QT depth + return false; + } } - if( bestCS && bestCS->cus.size() == 1 ) { // update the best non-split cost @@ -2984,7 +3093,11 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt } const PartSplit split = getPartSplit( encTestmode ); - if( !partitioner.canSplit( split, cs ) || skipScore >= 2 ) + if( !partitioner.canSplit( split, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) || skipScore >= 2 ) { if( split == CU_HORZ_SPLIT ) cuECtx.set( DID_HORZ_SPLIT, false ); if( split == CU_VERT_SPLIT ) cuECtx.set( DID_VERT_SPLIT, false ); @@ -3068,7 +3181,11 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt #if JVET_AH0135_TEMPORAL_PARTITIONING bool canNo, canQt, canBh, canBv, canTh, canTv; unsigned maxBTD; - partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv, maxBTD ); + partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv, maxBTD +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); #else unsigned maxBTD = cs.pcv->getMaxBtDepth( slice, partitioner.chType ); #endif @@ -3896,7 +4013,11 @@ bool EncModeCtrlMTnoRQT::useModeResult( const EncTestMode& encTestmode, CodingSt #if JVET_AH0135_TEMPORAL_PARTITIONING bool canNo, canQt, canBh, canBv, canTh, canTv; unsigned maxBTD; - partitioner.canSplit( *tempCS, canNo, canQt, canBh, canBv, canTh, canTv, maxBTD ); + partitioner.canSplit( *tempCS, canNo, canQt, canBh, canBv, canTh, canTv, maxBTD +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); maxMtD = (int)maxBTD; #endif diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h index 94e0c3661be366b6c33bb205998f8feddf8c8eff..f86fbb8b29ab9edeacbb5a8de36ee63fc43d2101 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.h +++ b/source/Lib/EncoderLib/EncModeCtrl.h @@ -407,6 +407,9 @@ public: #endif virtual void setBest ( CodingStructure& cs ); bool anyMode () const; +#if JVET_AI0087_BTCUS_RESTRICTION + bool isLumaNonBoundaryCu(const Partitioner& partitioner, SizeType picWidth, SizeType picHeight); +#endif #if JVET_AE0057_MTT_ET void setNoSplitIntraCost (double cost) { m_noSplitIntraRdCost = cost; } #endif diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index da4eedd5e920bfb3fdeca7d275b679841c929031..2a99a0f3db75e27deea79a272361019b8298469e 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -12573,11 +12573,19 @@ void InterSearch::xEncodeInterResidualQT(CodingStructure &cs, Partitioner &parti if (compID == MAX_NUM_TBLOCKS) // we are not processing a channel, instead we always recurse and code the CBFs { - if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) + if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { CHECK( !bSubdiv, "Not performing the implicit TU split" ); } - else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) ) + else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { CHECK( !bSubdiv, "Not performing the implicit TU split - sbt" ); } @@ -12652,11 +12660,19 @@ void InterSearch::xEncodeInterResidualQT(CodingStructure &cs, Partitioner &parti { if( compID == MAX_NUM_TBLOCKS || TU::getCbfAtDepth( currTU, compID, currDepth ) ) { - if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) + if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); } - else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) ) + else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { partitioner.splitCurrArea( PartSplit( cu.getSbtTuSplit() ), cs ); } @@ -12939,8 +12955,16 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par const unsigned currDepth = partitioner.currTrDepth; const bool colorTransFlag = cs.cus[0]->colorTransform; - bool bCheckFull = !partitioner.canSplit( TU_MAX_TR_SPLIT, cs ); - if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) ) + bool bCheckFull = !partitioner.canSplit( TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); + if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { bCheckFull = false; } @@ -14742,11 +14766,19 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par m_CABACEstimator->getCtx() = ctxStart; } - if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) + if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); } - else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs ) ) + else if( cu.sbtInfo && partitioner.canSplit( PartSplit( cu.getSbtTuSplit() ), cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { partitioner.splitCurrArea( PartSplit( cu.getSbtTuSplit() ), cs ); } diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index ad84c2205ca0d9e97267da98f58f40852a07bc81..a1b68d55eff481bbee2ebee7699f13e8962a67b5 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -4271,7 +4271,11 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner if (CS::isDualITree(cs)) #endif { - if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) + if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); @@ -8957,7 +8961,11 @@ void IntraSearch::xEncSubdivCbfQT( CodingStructure &cs, Partitioner &partitioner const bool subdiv = currTU.depth > currDepth; ComponentID compID = partitioner.chType == CHANNEL_TYPE_LUMA ? COMPONENT_Y : COMPONENT_Cb; - if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) + if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { CHECK( !subdiv, "TU split implied" ); } @@ -8990,7 +8998,11 @@ void IntraSearch::xEncSubdivCbfQT( CodingStructure &cs, Partitioner &partitioner if (subdiv) { - if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) + if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); } @@ -9059,7 +9071,11 @@ void IntraSearch::xEncCoeffQT( CodingStructure &cs, Partitioner &partitioner, co if (subdiv) { - if (partitioner.canSplit(TU_MAX_TR_SPLIT, cs)) + if (partitioner.canSplit(TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + )) { partitioner.splitCurrArea(TU_MAX_TR_SPLIT, cs); } @@ -10744,13 +10760,25 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par const SPS &sps = *cs.sps; bool bCheckFull = true; bool bCheckSplit = false; - bCheckFull = !partitioner.canSplit( TU_MAX_TR_SPLIT, cs ); - bCheckSplit = partitioner.canSplit( TU_MAX_TR_SPLIT, cs ); + bCheckFull = !partitioner.canSplit( TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); + bCheckSplit = partitioner.canSplit( TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); const Slice &slice = *cs.slice; if( cu.ispMode ) { - bCheckSplit = partitioner.canSplit( ispType, cs ); + bCheckSplit = partitioner.canSplit( ispType, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); bCheckFull = !bCheckSplit; } uint32_t numSig = 0; @@ -11333,7 +11361,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par bool uiSplitCbfLuma = false; bool splitIsSelected = true; - if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) + if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); } @@ -11470,7 +11502,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti const Slice &slice = *cs.slice; const SPS &sps = *cs.sps; - bool bCheckFull = !partitioner.canSplit(TU_MAX_TR_SPLIT, cs); + bool bCheckFull = !partitioner.canSplit(TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ); bool bCheckSplit = !bCheckFull; TempCtx ctxStart(m_ctxCache, m_CABACEstimator->getCtx()); @@ -12279,7 +12315,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti bool validReturnSplit = false; if (bCheckSplit) { - if (partitioner.canSplit(TU_MAX_TR_SPLIT, *csSplit)) + if (partitioner.canSplit(TU_MAX_TR_SPLIT, *csSplit +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + )) { partitioner.splitCurrArea(TU_MAX_TR_SPLIT, *csSplit); } @@ -13051,7 +13091,11 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio unsigned numValidTBlocks = ::getNumberValidTBlocks( *cs.pcv ); ChromaCbfs SplitCbfs ( false ); - if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) + if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs +#if JVET_AI0087_BTCUS_RESTRICTION + , false, false +#endif + ) ) { partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); }