From 1752d8d7cd75b497f4ba2ba14a92a6380f4fdcd8 Mon Sep 17 00:00:00 2001 From: Yin Zhao <yin.zhao@huawei.com> Date: Tue, 30 Jul 2019 21:49:42 +0800 Subject: [PATCH] JVET-O0050 encapsulated by JVET_O0050_LOCAL_DUAL_TREE --- source/Lib/CommonLib/AdaptiveLoopFilter.cpp | 5 +- source/Lib/CommonLib/CodingStructure.cpp | 191 +++++++++- source/Lib/CommonLib/CodingStructure.h | 13 + source/Lib/CommonLib/CommonDef.h | 4 + source/Lib/CommonLib/ContextModelling.cpp | 17 + source/Lib/CommonLib/ContextModelling.h | 3 + source/Lib/CommonLib/Contexts.cpp | 10 + source/Lib/CommonLib/Contexts.h | 3 + source/Lib/CommonLib/LoopFilter.cpp | 4 + source/Lib/CommonLib/TypeDef.h | 20 ++ source/Lib/CommonLib/Unit.cpp | 24 +- source/Lib/CommonLib/Unit.h | 10 + source/Lib/CommonLib/UnitPartitioner.cpp | 50 +++ source/Lib/CommonLib/UnitPartitioner.h | 19 + source/Lib/CommonLib/UnitTools.cpp | 33 ++ source/Lib/CommonLib/UnitTools.h | 3 + .../Lib/CommonLib/dtrace_blockstatistics.cpp | 12 + .../Lib/CommonLib/x86/AdaptiveLoopFilterX86.h | 10 +- source/Lib/DecoderLib/CABACReader.cpp | 166 ++++++++- source/Lib/DecoderLib/CABACReader.h | 3 + source/Lib/DecoderLib/DecCu.cpp | 7 + source/Lib/EncoderLib/CABACWriter.cpp | 168 ++++++++- source/Lib/EncoderLib/CABACWriter.h | 3 + source/Lib/EncoderLib/EncCu.cpp | 329 +++++++++++++++++- source/Lib/EncoderLib/EncCu.h | 8 + source/Lib/EncoderLib/EncModeCtrl.cpp | 53 +++ source/Lib/EncoderLib/InterSearch.cpp | 16 + source/Lib/EncoderLib/IntraSearch.cpp | 89 +++++ source/Lib/EncoderLib/IntraSearch.h | 16 + 29 files changed, 1271 insertions(+), 18 deletions(-) diff --git a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp index f99bf8b3b..34dd64d77 100644 --- a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp +++ b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp @@ -1107,10 +1107,13 @@ void AdaptiveLoopFilter::filterBlk(AlfClassifier** classifier, const PelUnitBuf for( blkX=0; blkX<4; blkX+=2 ) { Position pos(j + blkDst.x + blkX, i + blkDst.y + blkY); -#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB && !JVET_O0050_LOCAL_DUAL_TREE const CodingUnit* cu = isDualTree ? cs.getCU(pos, CH_C) : cs.getCU(recalcPosition(nChromaFormat, CH_C, CH_L, pos), CH_L); #else CodingUnit* cu = isDualTree ? cs.getCU(pos, CH_C) : cs.getCU(recalcPosition(nChromaFormat, CH_C, CH_L, pos), CH_L); +#endif +#if JVET_O0050_LOCAL_DUAL_TREE + cu = cu->isSepTree() ? cs.getCU( pos, CH_C ) : cu; #endif *flags++ = cu->ipcm ? 1 : 0; } diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp index 36d3109af..a20ca1ca3 100644 --- a/source/Lib/CommonLib/CodingStructure.cpp +++ b/source/Lib/CommonLib/CodingStructure.cpp @@ -86,7 +86,10 @@ CodingStructure::CodingStructure(CUCache& cuCache, PUCache& puCache, TUCache& tu m_motionBuf = nullptr; features.resize( NUM_ENC_FEATURES ); - +#if JVET_O0050_LOCAL_DUAL_TREE + treeType = TREE_D; + modeType = MODE_TYPE_ALL; +#endif } void CodingStructure::destroy() @@ -183,14 +186,102 @@ void CodingStructure::setDecomp(const UnitArea &_area, const bool _isCoded /*= t } } +#if JVET_O0050_LOCAL_DUAL_TREE +const int CodingStructure::signalModeCons( const PartSplit split, Partitioner &partitioner, const ModeType modeTypeParent ) const +{ + if( CS::isDualITree( *this ) || modeTypeParent != MODE_TYPE_ALL ) + return 0; + + int width = partitioner.currArea().lwidth(); + int height = partitioner.currArea().lheight(); + + //0: not constrain + //1: constrain with intra, no need signaling the flag + //2: constrain with intra or inter, need signaling the flag + if( width * height == 64 ) + { + if( split == CU_QUAD_SPLIT || split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT ) // qt or tt + return slice->isIntra() ? 1 : 1; //only intra mode allowed for child nodes (have 4x4) + else // bt + return slice->isIntra() ? 1 : 2; + } + else if( width * height == 128 ) + { + if( split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT ) + return slice->isIntra() ? 1 : 2; + else + return 0; + } + else + { + return 0; + } +} + +void CodingStructure::clearCuPuTuIdxMap( const UnitArea &_area, uint32_t numCu, uint32_t numPu, uint32_t numTu, uint32_t* pOffset ) +{ + UnitArea clippedArea = clipArea( _area, *picture ); + uint32_t numCh = ::getNumberValidChannels( _area.chromaFormat ); + for( uint32_t i = 0; i < numCh; i++ ) + { + const CompArea &_selfBlk = area.blocks[i]; + const CompArea &_blk = clippedArea.blocks[i]; + + const UnitScale& scale = unitScale[_blk.compID]; + const Area scaledSelf = scale.scale( _selfBlk ); + const Area scaledBlk = scale.scale( _blk ); + const size_t offset = rsAddr( scaledBlk.pos(), scaledSelf.pos(), scaledSelf.width ); + unsigned *idxPtrCU = m_cuIdx[i] + offset; + AreaBuf<uint32_t>( idxPtrCU, scaledSelf.width, scaledBlk.size() ).fill( 0 ); + + unsigned *idxPtrPU = m_puIdx[i] + offset; + AreaBuf<uint32_t>( idxPtrPU, scaledSelf.width, scaledBlk.size() ).fill( 0 ); + + unsigned *idxPtrTU = m_tuIdx[i] + offset; + AreaBuf<uint32_t>( idxPtrTU, scaledSelf.width, scaledBlk.size() ).fill( 0 ); + } + + //pop cu/pu/tus + for( int i = m_numTUs; i > numTu; i-- ) + { + m_tuCache.cache( tus.back() ); + tus.pop_back(); + m_numTUs--; + } + for( int i = m_numPUs; i > numPu; i-- ) + { + m_puCache.cache( pus.back() ); + pus.pop_back(); + m_numPUs--; + } + for( int i = m_numCUs; i > numCu; i-- ) + { + m_cuCache.cache( cus.back() ); + cus.pop_back(); + m_numCUs--; + } + for( int i = 0; i < 3; i++ ) + { + m_offsets[i] = pOffset[i]; + } +} +#endif CodingUnit* CodingStructure::getCU( const Position &pos, const ChannelType effChType ) { const CompArea &_blk = area.blocks[effChType]; +#if JVET_O0050_LOCAL_DUAL_TREE + if( !_blk.contains( pos ) || (treeType == TREE_C && effChType == CHANNEL_TYPE_LUMA) ) +#else if( !_blk.contains( pos ) ) +#endif { +#if JVET_O0050_LOCAL_DUAL_TREE + if( treeType == TREE_C && effChType == CHANNEL_TYPE_LUMA ) + CHECK( parent->treeType != TREE_D, "wrong parent treeType " ); +#endif if( parent ) return parent->getCU( pos, effChType ); else return nullptr; } @@ -207,8 +298,16 @@ const CodingUnit* CodingStructure::getCU( const Position &pos, const ChannelType { const CompArea &_blk = area.blocks[effChType]; +#if JVET_O0050_LOCAL_DUAL_TREE + if( !_blk.contains( pos ) || (treeType == TREE_C && effChType == CHANNEL_TYPE_LUMA) ) +#else if( !_blk.contains( pos ) ) +#endif { +#if JVET_O0050_LOCAL_DUAL_TREE + if( treeType == TREE_C && effChType == CHANNEL_TYPE_LUMA ) + CHECK( parent->treeType != TREE_D, "wrong parent treeType" ); +#endif if( parent ) return parent->getCU( pos, effChType ); else return nullptr; } @@ -289,6 +388,10 @@ TransformUnit* CodingStructure::getTU( const Position &pos, const ChannelType ef while( !tus[idx - 1 + extraIdx]->blocks[getFirstComponentOfChannel( effChType )].contains( pos ) ) { extraIdx++; +#if JVET_O0050_LOCAL_DUAL_TREE + CHECK( tus[idx - 1 + extraIdx]->cu->treeType == TREE_C, "tu searched by position points to a chroma tree CU" ); + CHECK( extraIdx > 3, "extraIdx > 3" ); +#endif } } } @@ -330,6 +433,10 @@ const TransformUnit * CodingStructure::getTU( const Position &pos, const Channel while ( !tus[idx - 1 + extraIdx]->blocks[getFirstComponentOfChannel( effChType )].contains(pos) ) { extraIdx++; +#if JVET_O0050_LOCAL_DUAL_TREE + CHECK( tus[idx - 1 + extraIdx]->cu->treeType == TREE_C, "tu searched by position points to a chroma tree CU" ); + CHECK( extraIdx > 3, "extraIdx > 3" ); +#endif } } } @@ -355,6 +462,10 @@ CodingUnit& CodingStructure::addCU( const UnitArea &unit, const ChannelType chTy cu->firstTU = nullptr; cu->lastTU = nullptr; cu->chType = chType; +#if JVET_O0050_LOCAL_DUAL_TREE + cu->treeType = treeType; + cu->modeType = modeType; +#endif CodingUnit *prevCU = m_numCUs > 0 ? cus.back() : nullptr; @@ -551,8 +662,45 @@ CUTraverser CodingStructure::traverseCUs( const UnitArea& unit, const ChannelTyp { CodingUnit* firstCU = getCU( isLuma( effChType ) ? unit.lumaPos() : unit.chromaPos(), effChType ); CodingUnit* lastCU = firstCU; - +#if JVET_O0050_LOCAL_DUAL_TREE + if( !CS::isDualITree( *this ) ) //for a more generalized separate tree + { + bool bContinue = true; + CodingUnit* currCU = firstCU; + while( bContinue ) + { + if( currCU == nullptr ) + { + bContinue = false; + lastCU = currCU; + } + else if( currCU->chType != effChType ) + { + lastCU = currCU; + currCU = currCU->next; + } + else + { + if( unit.contains( *currCU ) ) + { + lastCU = currCU; + currCU = currCU->next; + } + else + { + bContinue = false; + lastCU = currCU; + } + } + } + } + else + { +#endif do { } while( lastCU && ( lastCU = lastCU->next ) && unit.contains( *lastCU ) ); +#if JVET_O0050_LOCAL_DUAL_TREE + } +#endif return CUTraverser( firstCU, lastCU ); } @@ -784,6 +932,11 @@ void CodingStructure::initSubStructure( CodingStructure& subStruct, const Channe subStruct.motionLut = motionLut; +#if JVET_O0050_LOCAL_DUAL_TREE + subStruct.treeType = treeType; + subStruct.modeType = modeType; +#endif + subStruct.initStructData( currQP[_chType], isLossless ); if( isTuEnc ) @@ -872,8 +1025,11 @@ void CodingStructure::useSubStructure( const CodingStructure& subStruct, const C { // add an analogue CU into own CU store const UnitArea &cuPatch = *pcu; - +#if JVET_O0050_LOCAL_DUAL_TREE + CodingUnit &cu = addCU( cuPatch, pcu->chType ); +#else CodingUnit &cu = addCU( cuPatch, chType ); +#endif // copy the CU info from subPatch cu = *pcu; @@ -891,8 +1047,11 @@ void CodingStructure::useSubStructure( const CodingStructure& subStruct, const C { // add an analogue PU into own PU store const UnitArea &puPatch = *ppu; - +#if JVET_O0050_LOCAL_DUAL_TREE + PredictionUnit &pu = addPU( puPatch, ppu->chType ); +#else PredictionUnit &pu = addPU( puPatch, chType ); +#endif // copy the PU info from subPatch pu = *ppu; @@ -903,8 +1062,11 @@ void CodingStructure::useSubStructure( const CodingStructure& subStruct, const C { // add an analogue TU into own TU store const UnitArea &tuPatch = *ptu; - +#if JVET_O0050_LOCAL_DUAL_TREE + TransformUnit &tu = addTU( tuPatch, ptu->chType ); +#else TransformUnit &tu = addTU( tuPatch, chType ); +#endif // copy the TU info from subPatch tu = *ptu; @@ -936,8 +1098,11 @@ void CodingStructure::useSubStructure( const CodingStructure& subStruct, const C { // add an analogue CU into own CU store const UnitArea &cuPatch = *pcu; - +#if JVET_O0050_LOCAL_DUAL_TREE + CodingUnit &cu = addCU( cuPatch, pcu->chType ); +#else CodingUnit &cu = addCU( cuPatch, chType ); +#endif // copy the CU info from subPatch cu = *pcu; @@ -955,8 +1120,11 @@ void CodingStructure::useSubStructure( const CodingStructure& subStruct, const C { // add an analogue PU into own PU store const UnitArea &puPatch = *ppu; - +#if JVET_O0050_LOCAL_DUAL_TREE + PredictionUnit &pu = addPU( puPatch, ppu->chType ); +#else PredictionUnit &pu = addPU( puPatch, chType ); +#endif // copy the PU info from subPatch pu = *ppu; @@ -967,8 +1135,11 @@ void CodingStructure::useSubStructure( const CodingStructure& subStruct, const C { // add an analogue TU into own TU store const UnitArea &tuPatch = *ptu; - +#if JVET_O0050_LOCAL_DUAL_TREE + TransformUnit &tu = addTU( tuPatch, ptu->chType ); +#else TransformUnit &tu = addTU( tuPatch, chType ); +#endif // copy the TU info from subPatch tu = *ptu; @@ -1420,7 +1591,11 @@ IbcLumaCoverage CodingStructure::getIbcLumaCoverage(const CompArea& chromaArea) for (SizeType x = 0; x < lumaArea.width; x += MIN_PU_SIZE) { Position pos = lumaArea.offset(x, y); +#if JVET_O0050_LOCAL_DUAL_TREE + if (picture->cs->getMotionInfo(pos).isInter && picture->cs->getMotionInfo(pos).isIBCmot) +#else if (picture->cs->getMotionInfo(pos).isInter) // need to change if inter slice allows dualtree +#endif { ibcArea += unitAreaSubBlock; } diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h index aa41d9611..8adfbc068 100644 --- a/source/Lib/CommonLib/CodingStructure.h +++ b/source/Lib/CommonLib/CodingStructure.h @@ -171,6 +171,10 @@ public: uint64_t fracBits; Distortion dist; Distortion interHad; +#if JVET_O0050_LOCAL_DUAL_TREE + TreeType treeType; //because partitioner can not go deep to tu and cu coding (e.g., addCU()), need another variable for indicating treeType + ModeType modeType; +#endif void initStructData (const int &QP = MAX_INT, const bool &_isLosses = false, const bool &skipMotBuf = false); void initSubStructure( CodingStructure& cs, const ChannelType chType, const UnitArea &subArea, const bool &isTuEnc); @@ -182,6 +186,15 @@ public: void clearTUs(); void clearPUs(); void clearCUs(); +#if JVET_O0050_LOCAL_DUAL_TREE + const int signalModeCons( const PartSplit split, Partitioner &partitioner, const ModeType modeTypeParent ) const; + void clearCuPuTuIdxMap ( const UnitArea &_area, uint32_t numCu, uint32_t numPu, uint32_t numTu, uint32_t* pOffset ); + void getNumCuPuTuOffset ( uint32_t* pArray ) + { + pArray[0] = m_numCUs; pArray[1] = m_numPUs; pArray[2] = m_numTUs; + pArray[3] = m_offsets[0]; pArray[4] = m_offsets[1]; pArray[5] = m_offsets[2]; + } +#endif private: diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index ec7e37790..e72c01bba 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -447,6 +447,10 @@ static const int SBT_MAX_SIZE = 64; ///< maxi static const int SBT_NUM_SL = 10; ///< maximum number of historical PU decision saved for a CU static const int SBT_NUM_RDO = 2; ///< maximum number of SBT mode tried for a PU +#if JVET_O0050_LOCAL_DUAL_TREE +static const int NUM_INTER_CU_INFO_SAVE = 8; ///< maximum number of inter cu information saved for fast algorithm +#endif + static const int IBC_MAX_CAND_SIZE = 16; // max block size for ibc search static const int IBC_NUM_CANDIDATES = 64; ///< Maximum number of candidates to store/test static const int CHROMA_REFINEMENT_CANDIDATES = 8; /// 8 candidates BV to choose from diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp index 5db6cf368..79872a0bb 100644 --- a/source/Lib/CommonLib/ContextModelling.cpp +++ b/source/Lib/CommonLib/ContextModelling.cpp @@ -134,7 +134,24 @@ void CoeffCodingContext::initSubblock( int SubsetId, bool sigGroupFlag ) } +#if JVET_O0050_LOCAL_DUAL_TREE +unsigned DeriveCtx::CtxModeConsFlag( const CodingStructure& cs, Partitioner& partitioner ) +{ + assert( partitioner.chType == CHANNEL_TYPE_LUMA ); + const Position pos = partitioner.currArea().blocks[partitioner.chType]; + const unsigned curSliceIdx = cs.slice->getIndependentSliceIdx(); + const unsigned curTileIdx = cs.picture->brickMap->getBrickIdxRsMap( partitioner.currArea().lumaPos() ); + + // get left depth + const CodingUnit* cuLeft = cs.getCURestricted( pos.offset( -1, 0 ), pos, curSliceIdx, curTileIdx, partitioner.chType ); + + // get above depth + const CodingUnit* cuAbove = cs.getCURestricted( pos.offset( 0, -1 ), pos, curSliceIdx, curTileIdx, partitioner.chType ); + unsigned ctxId = ((cuAbove && cuAbove->predMode == MODE_INTRA) || (cuLeft && cuLeft->predMode == MODE_INTRA)) ? 1 : 0; + return ctxId; +} +#endif void DeriveCtx::CtxSplit( const CodingStructure& cs, Partitioner& partitioner, unsigned& ctxSpl, unsigned& ctxQt, unsigned& ctxHv, unsigned& ctxHorBt, unsigned& ctxVerBt, bool* _canSplit /*= nullptr */ ) diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h index 41190b2e1..2c86e0604 100644 --- a/source/Lib/CommonLib/ContextModelling.h +++ b/source/Lib/CommonLib/ContextModelling.h @@ -501,6 +501,9 @@ public: namespace DeriveCtx { void CtxSplit ( const CodingStructure& cs, Partitioner& partitioner, unsigned& ctxSpl, unsigned& ctxQt, unsigned& ctxHv, unsigned& ctxHorBt, unsigned& ctxVerBt, bool* canSplit = nullptr ); +#if JVET_O0050_LOCAL_DUAL_TREE +unsigned CtxModeConsFlag( const CodingStructure& cs, Partitioner& partitioner ); +#endif #if JVET_O0193_REMOVE_TR_DEPTH_IN_CBF_CTX unsigned CtxQtCbf ( const ComponentID compID, const bool prevCbf = false, const int ispIdx = 0 ); #else diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index 45325644e..9e030c432 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -240,6 +240,16 @@ const CtxSet ContextSetCfg::Split12Flag = ContextSetCfg::addCtxSet { 12, 12, 12, 12, }, }); +#if JVET_O0050_LOCAL_DUAL_TREE +const CtxSet ContextSetCfg::ModeConsFlag = ContextSetCfg::addCtxSet +({ + { 192, 168, }, + { 179, 139, }, + { CNU, CNU, }, + { 5, 2, }, +}); +#endif + const CtxSet ContextSetCfg::SkipFlag = ContextSetCfg::addCtxSet ({ { 197, 214, 216, }, diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index db203e802..73b92b6fd 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -201,6 +201,9 @@ public: static const CtxSet SplitQtFlag; static const CtxSet SplitHvFlag; static const CtxSet Split12Flag; +#if JVET_O0050_LOCAL_DUAL_TREE + static const CtxSet ModeConsFlag; +#endif static const CtxSet SkipFlag; static const CtxSet MergeFlag; static const CtxSet RegularMergeFlag; diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp index e0e76f57c..0313b9d99 100644 --- a/source/Lib/CommonLib/LoopFilter.cpp +++ b/source/Lib/CommonLib/LoopFilter.cpp @@ -655,7 +655,11 @@ unsigned LoopFilter::xGetBoundaryStrengthSingle ( const CodingUnit& cu, const De } const TransformUnit& tuQ = *cuQ.cs->getTU(posQ, cuQ.chType); +#if JVET_O0050_LOCAL_DUAL_TREE + const TransformUnit& tuP = *cuP.cs->getTU(posP, cuQ.chType); //based on chType of the current cu, because cuQ.chType and cuP.chType are not the same when local dual-tree is applied +#else const TransformUnit& tuP = *cuP.cs->getTU(posP, cuP.chType); +#endif const PreCalcValues& pcv = *cu.cs->pcv; const unsigned rasterIdx = getRasterIdx( Position{ localPos.x, localPos.y }, pcv ); if (m_aapucBS[edgeDir][rasterIdx] && (cuP.firstPU->mhIntraFlag || cuQ.firstPU->mhIntraFlag)) diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 811be421c..d99eeb8f2 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -89,6 +89,7 @@ #define JVET_N0288_PROPOSAL1 1 // JVET-N0288 Proposal 1 #define JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB 1 // JVET-O0090 test 2: CTB selection of ALF alternative chroma filters +#define JVET_O0050_LOCAL_DUAL_TREE 1 // JVET-O0050: avoid small intra chroma block by a "local dual-tree" technique #define JVET_O0216_ALF_COEFF_EG3 1 // JVET-O0216/O0302/O0648: using EG3 for ALF coefficients coding @@ -381,6 +382,9 @@ typedef uint32_t Intermediate_UInt; ///< used as intermediate v #endif typedef uint64_t SplitSeries; ///< used to encoded the splits that caused a particular CU size +#if JVET_O0050_LOCAL_DUAL_TREE +typedef uint64_t ModeTypeSeries; ///< used to encoded the ModeType at different split depth +#endif typedef uint64_t Distortion; ///< distortion measurement @@ -502,6 +506,22 @@ enum ChannelType MAX_NUM_CHANNEL_TYPE = 2 }; +#if JVET_O0050_LOCAL_DUAL_TREE +enum TreeType +{ + TREE_D = 0, //default tree status (for single-tree slice, TREE_D means joint tree; for dual-tree I slice, TREE_D means TREE_L for luma and TREE_C for chroma) + TREE_L = 1, //separate tree only contains luma (may split) + TREE_C = 2, //separate tree only contains chroma (not split), to avoid small chroma block +}; + +enum ModeType +{ + MODE_TYPE_ALL = 0, //all modes can try + MODE_TYPE_INTER = 1, //can try inter + MODE_TYPE_INTRA = 2, //can try intra, ibc, palette +}; +#endif + #define CH_L CHANNEL_TYPE_LUMA #define CH_C CHANNEL_TYPE_CHROMA diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index 74a3cc0ec..b83315d6d 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -287,7 +287,11 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other ) smvdMode = other.smvdMode; ispMode = other.ispMode; mipFlag = other.mipFlag; - +#if JVET_O0050_LOCAL_DUAL_TREE + treeType = other.treeType; + modeType = other.modeType; + modeTypeSeries = other.modeTypeSeries; +#endif return *this; } @@ -325,14 +329,30 @@ void CodingUnit::initData() smvdMode = 0; ispMode = 0; mipFlag = false; +#if JVET_O0050_LOCAL_DUAL_TREE + treeType = TREE_D; + modeType = MODE_TYPE_ALL; + modeTypeSeries = 0; +#endif +} + +#if JVET_O0050_LOCAL_DUAL_TREE +const bool CodingUnit::isSepTree() const +{ + return treeType != TREE_D || CS::isDualITree( *cs ); } +#endif #if JVET_O1124_ALLOW_CCLM_COND const bool CodingUnit::checkCCLMAllowed() const { bool allowCCLM = false; - if( chType != CHANNEL_TYPE_CHROMA ) //single tree +#if JVET_O0050_LOCAL_DUAL_TREE + if( !CS::isDualITree( *cs ) ) //single tree I slice or non-I slice (Note: judging chType is no longer equivalent to checking dual-tree I slice since the local dual-tree is introduced) +#else + if( chType != CHANNEL_TYPE_CHROMA ) //single tree I slice or non-I slice +#endif { allowCCLM = true; } diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index 166454005..7c8370303 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -298,6 +298,11 @@ struct CodingUnit : public UnitArea int8_t chromaQpAdj; int8_t qp; SplitSeries splitSeries; +#if JVET_O0050_LOCAL_DUAL_TREE + TreeType treeType; + ModeType modeType; + ModeTypeSeries modeTypeSeries; +#endif bool skip; bool mmvdSkip; bool affine; @@ -353,6 +358,11 @@ struct CodingUnit : public UnitArea #if JVET_O1124_ALLOW_CCLM_COND const bool checkCCLMAllowed() const; #endif +#if JVET_O0050_LOCAL_DUAL_TREE + const bool isSepTree() const; + const bool isConsInter() const { return modeType == MODE_TYPE_INTER; } + const bool isConsIntra() const { return modeType == MODE_TYPE_INTRA; } +#endif }; // --------------------------------------------------------------------------- diff --git a/source/Lib/CommonLib/UnitPartitioner.cpp b/source/Lib/CommonLib/UnitPartitioner.cpp index 3309c07d9..acc12ded5 100644 --- a/source/Lib/CommonLib/UnitPartitioner.cpp +++ b/source/Lib/CommonLib/UnitPartitioner.cpp @@ -106,6 +106,29 @@ SplitSeries Partitioner::getSplitSeries() const return splitSeries; } +#if JVET_O0050_LOCAL_DUAL_TREE +ModeTypeSeries Partitioner::getModeTypeSeries() const +{ + ModeTypeSeries modeTypeSeries = 0; + int depth = 0; + + for( const auto &level : m_partStack ) + { + if( level.split == CTU_LEVEL ) continue; + else modeTypeSeries += static_cast<int>(level.modeType) << (depth * 3); + + depth++; + } + + return modeTypeSeries; +} + +bool Partitioner::isSepTree( const CodingStructure &cs ) +{ + return treeType != TREE_D || CS::isDualITree( cs ); +} +#endif + void Partitioner::setCUData( CodingUnit& cu ) { cu.depth = currDepth; @@ -113,6 +136,9 @@ void Partitioner::setCUData( CodingUnit& cu ) cu.mtDepth = currMtDepth; cu.qtDepth = currQtDepth; cu.splitSeries = getSplitSeries(); +#if JVET_O0050_LOCAL_DUAL_TREE + cu.modeTypeSeries = getModeTypeSeries(); +#endif } void Partitioner::copyState( const Partitioner& other ) @@ -234,6 +260,10 @@ void QTBTPartitioner::initCtu( const UnitArea& ctuArea, const ChannelType _chTyp m_partStack.clear(); m_partStack.push_back( PartLevel( CTU_LEVEL, Partitioning{ ctuArea } ) ); +#if JVET_O0050_LOCAL_DUAL_TREE + treeType = TREE_D; + modeType = MODE_TYPE_ALL; +#endif } void QTBTPartitioner::splitCurrArea( const PartSplit split, const CodingStructure& cs ) @@ -249,14 +279,23 @@ void QTBTPartitioner::splitCurrArea( const PartSplit split, const CodingStructur { case CU_QUAD_SPLIT: m_partStack.push_back( PartLevel( split, PartitionerImpl::getCUSubPartitions( currArea(), cs ) ) ); +#if JVET_O0050_LOCAL_DUAL_TREE + m_partStack.back().modeType = modeType; +#endif break; case CU_HORZ_SPLIT: case CU_VERT_SPLIT: m_partStack.push_back( PartLevel( split, PartitionerImpl::getCUSubPartitions( currArea(), cs, split ) ) ); +#if JVET_O0050_LOCAL_DUAL_TREE + m_partStack.back().modeType = modeType; +#endif break; case CU_TRIH_SPLIT: case CU_TRIV_SPLIT: m_partStack.push_back( PartLevel( split, PartitionerImpl::getCUSubPartitions( currArea(), cs, split ) ) ); +#if JVET_O0050_LOCAL_DUAL_TREE + m_partStack.back().modeType = modeType; +#endif break; case TU_MAX_TR_SPLIT: m_partStack.push_back( PartLevel( split, PartitionerImpl::getMaxTuTiling( currArea(), cs ) ) ); @@ -354,6 +393,13 @@ void QTBTPartitioner::canSplit( const CodingStructure &cs, bool& canNo, bool& ca if( lastSplit != CTU_LEVEL && lastSplit != CU_QUAD_SPLIT ) canQt = false; if( area.width <= minQtSize ) canQt = false; if( chType == CHANNEL_TYPE_CHROMA && areaC.width <= MIN_DUALTREE_CHROMA_WIDTH ) canQt = false; +#if JVET_O0050_LOCAL_DUAL_TREE + if( treeType == TREE_C ) + { + canQt = canBh = canTh = canBv = canTv = false; + return; + } +#endif if( implicitSplit != CU_DONT_SPLIT ) { canNo = canTh = canTv = false; @@ -935,7 +981,11 @@ void PartitionerImpl::getTUIntraSubPartitions( Partitioning &sub, const UnitArea uint32_t nPartitions; uint32_t splitDimensionSize = CU::getISPSplitDim( tuArea.lumaSize().width, tuArea.lumaSize().height, splitType ); +#if JVET_O0050_LOCAL_DUAL_TREE + bool isDualTree = CS::isDualITree( cs ) || cs.treeType != TREE_D; +#else bool isDualTree = CS::isDualITree( cs ); +#endif if( splitType == TU_1D_HORZ_SPLIT ) { diff --git a/source/Lib/CommonLib/UnitPartitioner.h b/source/Lib/CommonLib/UnitPartitioner.h index 4fbe68f31..917c23a1b 100644 --- a/source/Lib/CommonLib/UnitPartitioner.h +++ b/source/Lib/CommonLib/UnitPartitioner.h @@ -94,6 +94,9 @@ struct PartLevel bool canQtSplit; bool qgEnable; bool qgChromaEnable; +#if JVET_O0050_LOCAL_DUAL_TREE + int modeType; +#endif PartLevel(); PartLevel( const PartSplit _split, const Partitioning& _parts ); @@ -123,6 +126,10 @@ public: unsigned currImplicitBtDepth; ChannelType chType; +#if JVET_O0050_LOCAL_DUAL_TREE + TreeType treeType; + ModeType modeType; +#endif virtual ~Partitioner () { } @@ -134,6 +141,9 @@ public: const bool currQgChromaEnable () const { return currPartLevel().qgChromaEnable; } SplitSeries getSplitSeries () const; +#if JVET_O0050_LOCAL_DUAL_TREE + ModeTypeSeries getModeTypeSeries () const; +#endif virtual void initCtu ( const UnitArea& ctuArea, const ChannelType _chType, const Slice& slice ) = 0; virtual void splitCurrArea ( const PartSplit split, const CodingStructure &cs ) = 0; @@ -150,6 +160,11 @@ public: virtual bool canSplit ( const PartSplit split, const CodingStructure &cs ) = 0; virtual bool isSplitImplicit ( const PartSplit split, const CodingStructure &cs ) = 0; virtual PartSplit getImplicitSplit ( const CodingStructure &cs ) = 0; +#if JVET_O0050_LOCAL_DUAL_TREE + bool isSepTree ( const CodingStructure &cs ); + bool isConsInter () { return modeType == MODE_TYPE_INTER; } + bool isConsIntra () { return modeType == MODE_TYPE_INTRA; } +#endif }; class AdaptiveDepthPartitioner : public Partitioner @@ -189,6 +204,10 @@ public: chType = _initialState.chType; #if _DEBUG m_currArea = _initialState.currArea(); +#endif +#if JVET_O0050_LOCAL_DUAL_TREE + treeType = _initialState.treeType; + modeType = _initialState.modeType; #endif } diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 3aec86d1c..1756e8f8c 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -63,7 +63,11 @@ bool CS::isDualITree( const CodingStructure &cs ) UnitArea CS::getArea( const CodingStructure &cs, const UnitArea &area, const ChannelType chType ) { +#if JVET_O0050_LOCAL_DUAL_TREE + return isDualITree( cs ) || cs.treeType != TREE_D ? area.singleChan( chType ) : area; +#else return isDualITree( cs ) ? area.singleChan( chType ) : area; +#endif } void CS::setRefinedMotionField(CodingStructure &cs) { @@ -170,7 +174,11 @@ uint32_t CU::getIntraSizeIdx(const CodingUnit &cu) bool CU::isLastSubCUOfCtu( const CodingUnit &cu ) { const SPS &sps = *cu.cs->sps; +#if JVET_O0050_LOCAL_DUAL_TREE + const Area cuAreaY = cu.isSepTree() ? Area( recalcPosition( cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].pos() ), recalcSize( cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].size() ) ) : (const Area&)cu.Y(); +#else const Area cuAreaY = CS::isDualITree( *cu.cs ) ? Area( recalcPosition( cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].pos() ), recalcSize( cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].size() ) ) : ( const Area& ) cu.Y(); +#endif return ( ( ( ( cuAreaY.x + cuAreaY.width ) & cu.cs->pcv->maxCUWidthMask ) == 0 || cuAreaY.x + cuAreaY.width == sps.getPicWidthInLumaSamples() ) && ( ( ( cuAreaY.y + cuAreaY.height ) & cu.cs->pcv->maxCUHeightMask ) == 0 || cuAreaY.y + cuAreaY.height == sps.getPicHeightInLumaSamples() ) ); @@ -235,6 +243,15 @@ PartSplit CU::getSplitAtDepth( const CodingUnit& cu, const unsigned depth ) else { THROW( "Unknown split mode" ); return CU_QUAD_SPLIT; } } +#if JVET_O0050_LOCAL_DUAL_TREE +ModeType CU::getModeTypeAtDepth( const CodingUnit& cu, const unsigned depth ) +{ + ModeType modeType = ModeType( (cu.modeTypeSeries >> (depth * 3)) & 0x07 ); + CHECK( depth > cu.depth, " depth is wrong" ); + return modeType; +} +#endif + bool CU::hasNonTsCodedBlock( const CodingUnit& cu ) { bool hasAnyNonTSCoded = false; @@ -772,7 +789,11 @@ void PU::getIntraChromaCandModes( const PredictionUnit &pu, unsigned modeList[NU #else Position topLeftPos = pu.blocks[pu.chType].lumaPos(); Position refPos = topLeftPos.offset( pu.blocks[pu.chType].lumaSize().width >> 1, pu.blocks[pu.chType].lumaSize().height >> 1 ); +#if JVET_O0050_LOCAL_DUAL_TREE + const PredictionUnit *lumaPU = pu.cu->isSepTree() ? pu.cs->picture->cs->getPU( refPos, CHANNEL_TYPE_LUMA ) : &pu; +#else const PredictionUnit *lumaPU = CS::isDualITree( *pu.cs ) ? pu.cs->picture->cs->getPU( refPos, CHANNEL_TYPE_LUMA ) : &pu; +#endif const uint32_t lumaMode = PU::getIntraDirLuma( *lumaPU ); #endif for( int i = 0; i < 4; i++ ) @@ -850,7 +871,11 @@ uint32_t PU::getFinalIntraMode( const PredictionUnit &pu, const ChannelType &chT #else Position topLeftPos = pu.blocks[pu.chType].lumaPos(); Position refPos = topLeftPos.offset( pu.blocks[pu.chType].lumaSize().width >> 1, pu.blocks[pu.chType].lumaSize().height >> 1 ); +#if JVET_O0050_LOCAL_DUAL_TREE + const PredictionUnit &lumaPU = pu.cu->isSepTree() ? *pu.cs->picture->cs->getPU( refPos, CHANNEL_TYPE_LUMA ) : *pu.cs->getPU( topLeftPos, CHANNEL_TYPE_LUMA ); +#else const PredictionUnit &lumaPU = CS::isDualITree( *pu.cs ) ? *pu.cs->picture->cs->getPU( refPos, CHANNEL_TYPE_LUMA ) : *pu.cs->getPU( topLeftPos, CHANNEL_TYPE_LUMA ); +#endif uiIntraMode = PU::getIntraDirLuma( lumaPU ); #endif @@ -867,7 +892,11 @@ uint32_t PU::getCoLocatedIntraLumaMode( const PredictionUnit &pu ) { Position topLeftPos = pu.blocks[pu.chType].lumaPos(); Position refPos = topLeftPos.offset( pu.blocks[pu.chType].lumaSize().width >> 1, pu.blocks[pu.chType].lumaSize().height >> 1 ); +#if JVET_O0050_LOCAL_DUAL_TREE + const PredictionUnit &lumaPU = pu.cu->isSepTree() ? *pu.cs->picture->cs->getPU( refPos, CHANNEL_TYPE_LUMA ) : *pu.cs->getPU( topLeftPos, CHANNEL_TYPE_LUMA ); +#else const PredictionUnit &lumaPU = CS::isDualITree( *pu.cs ) ? *pu.cs->picture->cs->getPU( refPos, CHANNEL_TYPE_LUMA ) : *pu.cs->getPU( topLeftPos, CHANNEL_TYPE_LUMA ); +#endif return PU::getIntraDirLuma( lumaPU ); } @@ -4552,6 +4581,10 @@ bool TU::getCbf( const TransformUnit &tu, const ComponentID &compID ) bool TU::getCbfAtDepth(const TransformUnit &tu, const ComponentID &compID, const unsigned &depth) { +#if JVET_O0050_LOCAL_DUAL_TREE + if( !tu.blocks[compID].valid() ) + CHECK( tu.cbf[compID] != 0, "cbf must be 0 if the component is not available" ); +#endif return ((tu.cbf[compID] >> depth) & 1) == 1; } diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 4423e858d..504558051 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -76,6 +76,9 @@ namespace CU void addPUs ( CodingUnit& cu); PartSplit getSplitAtDepth (const CodingUnit& cu, const unsigned depth); +#if JVET_O0050_LOCAL_DUAL_TREE + ModeType getModeTypeAtDepth (const CodingUnit& cu, const unsigned depth); +#endif bool hasNonTsCodedBlock (const CodingUnit& cu); uint32_t getNumNonZeroCoeffNonTs ( const CodingUnit& cu, const bool lumaFlag = true, const bool chromaFlag = true ); diff --git a/source/Lib/CommonLib/dtrace_blockstatistics.cpp b/source/Lib/CommonLib/dtrace_blockstatistics.cpp index d5a82c9d4..38f9221ce 100644 --- a/source/Lib/CommonLib/dtrace_blockstatistics.cpp +++ b/source/Lib/CommonLib/dtrace_blockstatistics.cpp @@ -752,7 +752,11 @@ void writeAllData(const CodingStructure& cs, const UnitArea& ctuArea) } } +#if JVET_O0050_LOCAL_DUAL_TREE + if( !(cu.chromaFormat == CHROMA_400 || (cu.isSepTree() && cu.chType == CHANNEL_TYPE_LUMA)) ) +#else if (!(cu.chromaFormat == CHROMA_400 || (CS::isDualITree(*cu.cs) && cu.chType == CHANNEL_TYPE_LUMA))) +#endif { DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::Cbf_Cb), tu.cbf[COMPONENT_Cb]); DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_ALL, tu, GetBlockStatisticName(BlockStatistic::Cbf_Cr), tu.cbf[COMPONENT_Cr]); @@ -844,7 +848,11 @@ void writeAllCodedData(const CodingStructure & cs, const UnitArea & ctuArea) { DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, pu, GetBlockStatisticName(BlockStatistic::Luma_IntraMode), PU::getFinalIntraMode(pu, ChannelType(chType))); } +#if JVET_O0050_LOCAL_DUAL_TREE + if (!(pu.chromaFormat == CHROMA_400 || (pu.cu->isSepTree() && pu.chType == CHANNEL_TYPE_LUMA))) +#else if (!(pu.chromaFormat == CHROMA_400 || (CS::isDualITree(*pu.cs) && pu.chType == CHANNEL_TYPE_LUMA))) +#endif { DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_CODED, pu, GetBlockStatisticName(BlockStatistic::Chroma_IntraMode), PU::getFinalIntraMode(pu, CHANNEL_TYPE_CHROMA)); } @@ -1030,7 +1038,11 @@ void writeAllCodedData(const CodingStructure & cs, const UnitArea & ctuArea) DTRACE_BLOCK_SCALAR(g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName(BlockStatistic::Cbf_Y), tu.cbf[COMPONENT_Y]); DTRACE_BLOCK_SCALAR( g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName( BlockStatistic::MTSIdx ), tu.mtsIdx ); } +#if JVET_O0050_LOCAL_DUAL_TREE + if (!(cu.chromaFormat == CHROMA_400 || (cu.isSepTree() && cu.chType == CHANNEL_TYPE_LUMA))) +#else if (!(cu.chromaFormat == CHROMA_400 || (CS::isDualITree(*cu.cs) && cu.chType == CHANNEL_TYPE_LUMA))) +#endif { DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName(BlockStatistic::Cbf_Cb), tu.cbf[COMPONENT_Cb]); DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_CODED, tu, GetBlockStatisticName(BlockStatistic::Cbf_Cr), tu.cbf[COMPONENT_Cr]); diff --git a/source/Lib/CommonLib/x86/AdaptiveLoopFilterX86.h b/source/Lib/CommonLib/x86/AdaptiveLoopFilterX86.h index 609a37c8f..632e18a61 100644 --- a/source/Lib/CommonLib/x86/AdaptiveLoopFilterX86.h +++ b/source/Lib/CommonLib/x86/AdaptiveLoopFilterX86.h @@ -496,10 +496,13 @@ static void simdFilter5x5Blk(AlfClassifier** classifier, const PelUnitBuf &recDs for( blkX=0; blkX<8; blkX+=2 ) { Position pos(j + blkDst.x + blkX, i + blkDst.y + blkY); -#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB && !JVET_O0050_LOCAL_DUAL_TREE const CodingUnit* cu = isDualTree ? cs.getCU(pos, CH_C) : cs.getCU(recalcPosition(nChromaFormat, CH_C, CH_L, pos), CH_L); #else CodingUnit* cu = isDualTree ? cs.getCU(pos, CH_C) : cs.getCU(recalcPosition(nChromaFormat, CH_C, CH_L, pos), CH_L); +#endif +#if JVET_O0050_LOCAL_DUAL_TREE + cu = cu->isSepTree() ? cs.getCU( pos, CH_C ) : cu; #endif if(cu != NULL) { @@ -899,10 +902,13 @@ static void simdFilter7x7Blk(AlfClassifier** classifier, const PelUnitBuf &recDs for( blkX=0; blkX<8; blkX+=2 ) { Position pos(j + blkDst.x + blkX, i + blkDst.y + blkY); -#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB +#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB && !JVET_O0050_LOCAL_DUAL_TREE const CodingUnit* cu = isDualTree ? cs.getCU(pos, CH_C) : cs.getCU(recalcPosition(nChromaFormat, CH_C, CH_L, pos), CH_L); #else CodingUnit* cu = isDualTree ? cs.getCU(pos, CH_C) : cs.getCU(recalcPosition(nChromaFormat, CH_C, CH_L, pos), CH_L); +#endif +#if JVET_O0050_LOCAL_DUAL_TREE + cu = cu->isSepTree() ? cs.getCU( pos, CH_C ) : cu; #endif if( cu != NULL) { diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index f36c9684e..cdd4ccde9 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -139,6 +139,10 @@ bool CABACReader::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i Partitioner *partitioner = PartitionerFactory::get( *cs.slice ); partitioner->initCtu( area, CH_L, *cs.slice ); +#if JVET_O0050_LOCAL_DUAL_TREE + cs.treeType = partitioner->treeType = TREE_D; + cs.modeType = partitioner->modeType = MODE_TYPE_ALL; +#endif sao( cs, ctuRsAddr ); @@ -449,7 +453,11 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU } // Reset delta QP coding flag and ChromaQPAdjustemt coding flag +#if JVET_O0050_LOCAL_DUAL_TREE + if (partitioner.isSepTree(cs) && pPartitionerChroma != nullptr) +#else if (CS::isDualITree(cs) && pPartitionerChroma != nullptr) +#endif { if (pps.getUseDQP() && pPartitionerChroma->currQgEnable()) { @@ -573,6 +581,17 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU } else { +#if JVET_O0050_LOCAL_DUAL_TREE + const ModeType modeTypeParent = partitioner.modeType; + cs.modeType = partitioner.modeType = mode_constraint( cs, partitioner, splitMode ); //change for child nodes + //decide chroma split or not + bool chromaNotSplit = modeTypeParent == MODE_TYPE_ALL && partitioner.modeType == MODE_TYPE_INTRA; + CHECK( chromaNotSplit && partitioner.chType != CHANNEL_TYPE_LUMA, "chType must be luma" ); + if( partitioner.treeType == TREE_D ) + { + cs.treeType = partitioner.treeType = chromaNotSplit ? TREE_L : TREE_D; + } +#endif partitioner.splitCurrArea( splitMode, cs ); do { @@ -583,6 +602,26 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU } while( partitioner.nextPart( cs ) ); partitioner.exitCurrSplit(); +#if JVET_O0050_LOCAL_DUAL_TREE + if( chromaNotSplit ) + { + CHECK( partitioner.chType != CHANNEL_TYPE_LUMA, "must be luma status" ); + partitioner.chType = CHANNEL_TYPE_CHROMA; + cs.treeType = partitioner.treeType = TREE_C; + + if( !lastSegment && cs.picture->blocks[partitioner.chType].contains( partitioner.currArea().blocks[partitioner.chType].pos() ) ) + { + lastSegment = coding_tree( cs, partitioner, cuCtx ); + } + + //recover treeType + partitioner.chType = CHANNEL_TYPE_LUMA; + cs.treeType = partitioner.treeType = TREE_D; + } + + //recover ModeType + cs.modeType = partitioner.modeType = modeTypeParent; +#endif } if (startShareThisLevel == 1) shareStateDec = NO_SHARE; @@ -594,6 +633,9 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU partitioner.setCUData( cu ); cu.slice = cs.slice; cu.tileIdx = cs.picture->brickMap->getBrickIdxRsMap( currArea.lumaPos() ); +#if JVET_O0050_LOCAL_DUAL_TREE + CHECK( cu.cs->treeType != partitioner.treeType, "treeType mismatch" ); +#endif // Predict QP on start of quantization group if( cuCtx.qgStart ) @@ -602,7 +644,11 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU cuCtx.qp = CU::predictQP( cu, cuCtx.qp ); } +#if JVET_O0050_LOCAL_DUAL_TREE + if (pps.getUseDQP() && partitioner.isSepTree(cs) && isChroma(cu.chType)) +#else if (pps.getUseDQP() && CS::isDualITree(cs) && isChroma(cu.chType)) +#endif { const Position chromaCentral(cu.chromaPos().offset(cu.chromaSize().width >> 1, cu.chromaSize().height >> 1)); const Position lumaRefPos(chromaCentral.x << getComponentScaleX(COMPONENT_Cb, cu.chromaFormat), chromaCentral.y << getComponentScaleY(COMPONENT_Cb, cu.chromaFormat)); @@ -626,6 +672,28 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU return isLastCtu; } +#if JVET_O0050_LOCAL_DUAL_TREE +ModeType CABACReader::mode_constraint( CodingStructure& cs, Partitioner &partitioner, PartSplit splitMode ) +{ + int val = cs.signalModeCons( splitMode, partitioner, partitioner.modeType ); + if( val == 2 ) + { + int ctxIdx = DeriveCtx::CtxModeConsFlag( cs, partitioner ); + bool flag = m_BinDecoder.decodeBin( Ctx::ModeConsFlag( ctxIdx ) ); + DTRACE( g_trace_ctx, D_SYNTAX, "mode_cons_flag() flag=%d\n", flag ); + return flag ? MODE_TYPE_INTRA : MODE_TYPE_INTER; + } + else if( val == 1 ) + { + return MODE_TYPE_INTRA; + } + else + { + return partitioner.modeType; + } +} +#endif + 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 ); @@ -717,6 +785,10 @@ PartSplit CABACReader::split_cu_mode( CodingStructure& cs, Partitioner &partitio bool CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx& cuCtx ) { CodingStructure& cs = *cu.cs; +#if JVET_O0050_LOCAL_DUAL_TREE + CHECK( cu.treeType != partitioner.treeType || cu.modeType != partitioner.modeType, "treeType or modeType mismatch" ); + DTRACE( g_trace_ctx, D_SYNTAX, "coding_unit() treeType=%d modeType=%d\n", cu.treeType, cu.modeType ); +#endif // transquant bypass flag if( cs.pps->getTransquantBypassEnabledFlag() ) { @@ -781,7 +853,11 @@ void CABACReader::cu_skip_flag( CodingUnit& cu ) { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__SKIP_FLAG ); +#if JVET_O0050_LOCAL_DUAL_TREE + if ((cu.slice->isIntra() || cu.isConsIntra()) && cu.cs->slice->getSPS()->getIBCFlag()) +#else if (cu.slice->isIntra() && cu.cs->slice->getSPS()->getIBCFlag()) +#endif { cu.skip = false; cu.rootCbf = false; @@ -810,6 +886,12 @@ void CABACReader::cu_skip_flag( CodingUnit& cu ) { return; } +#if JVET_O0050_LOCAL_DUAL_TREE + if( !cu.cs->slice->getSPS()->getIBCFlag() && cu.isConsIntra() ) + { + return; + } +#endif unsigned ctxId = DeriveCtx::CtxSkipFlag(cu); unsigned skip = m_BinDecoder.decodeBin( Ctx::SkipFlag(ctxId) ); @@ -818,9 +900,17 @@ void CABACReader::cu_skip_flag( CodingUnit& cu ) if (skip && cu.cs->slice->getSPS()->getIBCFlag()) { #if JVET_O1161_IBC_MAX_SIZE +#if JVET_O0050_LOCAL_DUAL_TREE + if (cu.lwidth() < 128 && cu.lheight() < 128 && !cu.isConsInter()) // disable IBC mode larger than 64x64 and disable IBC when only allowing inter mode +#else if (cu.lwidth() < 128 && cu.lheight() < 128) // disable IBC mode larger than 64x64 +#endif +#else +#if JVET_O0050_LOCAL_DUAL_TREE + if ((cu.lwidth() < 128 || cu.lheight() < 128) && !cu.isConsInter()) // disable IBC mode larger than 64x64 and disable IBC when only allowing inter mode #else if (cu.lwidth() < 128 || cu.lheight() < 128) // disable 128x128 IBC mode +#endif #endif { if ( cu.lwidth() == 4 && cu.lheight() == 4 ) @@ -979,7 +1069,19 @@ void CABACReader::pred_mode( CodingUnit& cu ) if (cu.cs->slice->getSPS()->getIBCFlag()) #endif { +#if JVET_O0050_LOCAL_DUAL_TREE + if( cu.isConsInter() ) + { + cu.predMode = MODE_INTER; + return; + } +#endif + +#if JVET_O0050_LOCAL_DUAL_TREE + if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) || cu.isConsIntra() ) +#else if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) ) +#endif { cu.predMode = MODE_INTRA; #if JVET_O1161_IBC_MAX_SIZE @@ -1021,6 +1123,13 @@ void CABACReader::pred_mode( CodingUnit& cu ) } else { +#if JVET_O0050_LOCAL_DUAL_TREE + if( cu.isConsIntra() || cu.isConsInter() ) + { + cu.predMode = cu.isConsIntra() ? MODE_INTRA : MODE_INTER; + return; + } +#endif if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) || m_BinDecoder.decodeBin( Ctx::PredMode( DeriveCtx::CtxPredModeFlag( cu ) ) ) ) { cu.predMode = MODE_INTRA; @@ -1318,7 +1427,11 @@ void CABACReader::intra_luma_pred_modes( CodingUnit &cu ) void CABACReader::intra_chroma_pred_modes( CodingUnit& cu ) { +#if JVET_O0050_LOCAL_DUAL_TREE + if( cu.chromaFormat == CHROMA_400 || ( cu.isSepTree() && cu.chType == CHANNEL_TYPE_LUMA ) ) +#else if( cu.chromaFormat == CHROMA_400 || ( CS::isDualITree( *cu.cs ) && cu.chType == CHANNEL_TYPE_LUMA ) ) +#endif { return; } @@ -1512,7 +1625,11 @@ bool CABACReader::end_of_ctu( CodingUnit& cu, CUCtx& cuCtx ) if ( ( ( rbPos.x & cu.cs->pcv->maxCUWidthMask ) == 0 || rbPos.x == sps.getPicWidthInLumaSamples () ) && ( ( rbPos.y & cu.cs->pcv->maxCUHeightMask ) == 0 || rbPos.y == sps.getPicHeightInLumaSamples() ) +#if JVET_O0050_LOCAL_DUAL_TREE + && ( !cu.isSepTree() || cu.chromaFormat == CHROMA_400 || isChroma( cu.chType ) ) +#else && ( !CS::isDualITree( *cu.cs ) || cu.chromaFormat == CHROMA_400 || isChroma( cu.chType ) ) +#endif ) { cuCtx.isDQPCoded = ( cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded ); @@ -2084,15 +2201,21 @@ void CABACReader::MHIntra_flag(PredictionUnit& pu) void CABACReader::pcm_samples( TransformUnit& tu ) { CHECK( !tu.cu->ipcm, "pcm mode expected" ); - +#if !JVET_O0050_LOCAL_DUAL_TREE const CodingStructure *cs = tu.cs; +#endif const ChannelType chType = tu.chType; const SPS& sps = *tu.cu->cs->sps; tu.depth = 0; +#if JVET_O0050_LOCAL_DUAL_TREE + ComponentID compStr = (tu.cu->isSepTree() && !isLuma( chType )) ? COMPONENT_Cb : COMPONENT_Y; + ComponentID compEnd = (tu.cu->isSepTree() && isLuma( chType )) ? COMPONENT_Y : COMPONENT_Cr; +#else ComponentID compStr = (CS::isDualITree(*cs) && !isLuma(chType)) ? COMPONENT_Cb: COMPONENT_Y; ComponentID compEnd = (CS::isDualITree(*cs) && isLuma(chType)) ? COMPONENT_Y : COMPONENT_Cr; +#endif for( ComponentID compID = compStr; compID <= compEnd; compID = ComponentID(compID+1) ) { PelBuf samples = tu.getPcmbuf( compID ); @@ -2161,7 +2284,11 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, const bool chromaCbfISP = area.blocks[COMPONENT_Cb].valid() && cu.ispMode && !split; // cbf_cb & cbf_cr +#if JVET_O0050_LOCAL_DUAL_TREE + if( area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && ( !cu.isSepTree() || partitioner.chType == CHANNEL_TYPE_CHROMA ) && ( !cu.ispMode || chromaCbfISP ) ) +#else if( area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && ( !CS::isDualITree( cs ) || partitioner.chType == CHANNEL_TYPE_CHROMA ) && ( !cu.ispMode || chromaCbfISP ) ) +#endif { const int cbfDepth = chromaCbfISP ? trDepth - 1 : trDepth; if (!max_tu_split) @@ -2176,7 +2303,11 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, } } } +#if JVET_O0050_LOCAL_DUAL_TREE + else if( cu.isSepTree() ) +#else else if( CS::isDualITree( cs ) ) +#endif { chromaCbfs = ChromaCbfs( false ); } @@ -2442,7 +2573,11 @@ void CABACReader::transform_unit( TransformUnit& tu, CUCtx& cuCtx, ChromaCbfs& c const bool chromaCbfISP = area.blocks[COMPONENT_Cb].valid() && cu.ispMode; // cbf_cb & cbf_cr +#if JVET_O0050_LOCAL_DUAL_TREE + if (area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && (!cu.isSepTree() || partitioner.chType == CHANNEL_TYPE_CHROMA) && (!cu.ispMode || chromaCbfISP)) +#else if (area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && (!CS::isDualITree(cs) || partitioner.chType == CHANNEL_TYPE_CHROMA) && (!cu.ispMode || chromaCbfISP)) +#endif { const int cbfDepth = chromaCbfISP ? trDepth - 1 : trDepth; { @@ -2453,7 +2588,11 @@ void CABACReader::transform_unit( TransformUnit& tu, CUCtx& cuCtx, ChromaCbfs& c chromaCbfs.Cr = cbf_comp(cs, area.blocks[COMPONENT_Cr], cbfDepth, chromaCbfs.Cb); } } +#if JVET_O0050_LOCAL_DUAL_TREE + else if (cu.isSepTree()) +#else else if (CS::isDualITree(cs)) +#endif { chromaCbfs = ChromaCbfs(false); } @@ -2526,7 +2665,11 @@ void CABACReader::transform_unit( TransformUnit& tu, CUCtx& cuCtx, ChromaCbfs& c { if( cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded ) { +#if JVET_O0050_LOCAL_DUAL_TREE + if (!tu.cu->isSepTree() || isLuma(tu.chType)) +#else if (!CS::isDualITree(*tu.cs) || isLuma(tu.chType)) +#endif { cu_qp_delta(cu, cuCtx.qp, cu.qp); cuCtx.qp = cu.qp; @@ -2861,7 +3004,11 @@ void CABACReader::residual_lfnst_mode( CodingUnit& cu ) #endif { if( cu.ispMode != NOT_INTRA_SUBPARTITIONS || cu.mipFlag == true || +#if JVET_O0050_LOCAL_DUAL_TREE + ( cu.isSepTree() && cu.chType == CHANNEL_TYPE_CHROMA && std::min( cu.blocks[ 1 ].width, cu.blocks[ 1 ].height ) < 4 ) ) +#else ( CS::isDualITree( *cu.cs ) && cu.chType == CHANNEL_TYPE_CHROMA && std::min( cu.blocks[ 1 ].width, cu.blocks[ 1 ].height ) < 4 ) ) +#endif { return; } @@ -2870,15 +3017,24 @@ void CABACReader::residual_lfnst_mode( CodingUnit& cu ) if( cu.cs->sps->getUseLFNST() && CU::isIntra( cu ) && !CU::isLosslessCoded( cu ) ) { +#if JVET_O0050_LOCAL_DUAL_TREE + const bool lumaFlag = cu.isSepTree() ? ( isLuma( cu.chType ) ? true : false ) : true; + const bool chromaFlag = cu.isSepTree() ? ( isChroma( cu.chType ) ? true : false ) : true; +#else const bool lumaFlag = CS::isDualITree( *cu.cs ) ? ( isLuma( cu.chType ) ? true : false ) : true; const bool chromaFlag = CS::isDualITree( *cu.cs ) ? ( isChroma( cu.chType ) ? true : false ) : true; +#endif bool nonZeroCoeffNonTs; #if JVET_O0094_LFNST_ZERO_PRIM_COEFFS bool nonZeroCoeffNonTsCorner8x8 = ( lumaFlag && cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_LUMA] ) || (chromaFlag && cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] ); #else bool nonZeroCoeffNonTsCorner8x8 = CU::getNumNonZeroCoeffNonTsCorner8x8( cu, lumaFlag, chromaFlag ) > 0; #endif +#if JVET_O0050_LOCAL_DUAL_TREE + const int nonZeroCoeffThr = cu.isSepTree() ? ( isLuma( cu.chType ) ? LFNST_SIG_NZ_LUMA : LFNST_SIG_NZ_CHROMA ) : LFNST_SIG_NZ_LUMA + LFNST_SIG_NZ_CHROMA; +#else const int nonZeroCoeffThr = CS::isDualITree( *cu.cs ) ? ( isLuma( cu.chType ) ? LFNST_SIG_NZ_LUMA : LFNST_SIG_NZ_CHROMA ) : LFNST_SIG_NZ_LUMA + LFNST_SIG_NZ_CHROMA; +#endif nonZeroCoeffNonTs = CU::getNumNonZeroCoeffNonTs( cu, lumaFlag, chromaFlag ) > nonZeroCoeffThr; #if JVET_O0368_LFNST_WITH_DCT2_ONLY const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx != MTS_DCT2_DCT2); @@ -2900,9 +3056,17 @@ void CABACReader::residual_lfnst_mode( CodingUnit& cu ) unsigned cctx = 0; #if JVET_O0368_LFNST_WITH_DCT2_ONLY +#if JVET_O0050_LOCAL_DUAL_TREE + if ( cu.isSepTree() ) cctx++; +#else if ( CS::isDualITree(*cu.cs) ) cctx++; +#endif +#else +#if JVET_O0050_LOCAL_DUAL_TREE + if( cu.firstTU->mtsIdx < MTS_DST7_DST7 && cu.isSepTree() ) cctx++; #else if( cu.firstTU->mtsIdx < MTS_DST7_DST7 && CS::isDualITree( *cu.cs ) ) cctx++; +#endif #endif uint32_t idxLFNST = m_BinDecoder.decodeBin( Ctx::LFNSTIdx( cctx ) ); diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 947702d7f..f64b6df1e 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -73,6 +73,9 @@ public: // coding (quad)tree (clause 7.3.8.4) bool coding_tree ( CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, Partitioner* pPartitionerChroma = nullptr, CUCtx* pCuCtxChroma = nullptr); PartSplit split_cu_mode ( CodingStructure& cs, Partitioner& pm ); +#if JVET_O0050_LOCAL_DUAL_TREE + ModeType mode_constraint ( CodingStructure& cs, Partitioner& pm, const PartSplit splitMode ); +#endif // coding unit (clause 7.3.8.5) bool coding_unit ( CodingUnit& cu, Partitioner& pm, CUCtx& cuCtx ); diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index 13367e597..29b4e11f8 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -409,11 +409,18 @@ void DecCu::xDecodePCMTexture(TransformUnit &tu, const ComponentID compID) */ void DecCu::xReconPCM(TransformUnit &tu) { +#if !JVET_O0050_LOCAL_DUAL_TREE const CodingStructure *cs = tu.cs; +#endif const ChannelType chType = tu.chType; +#if JVET_O0050_LOCAL_DUAL_TREE + ComponentID compStr = (tu.cu->isSepTree() && !isLuma( chType )) ? COMPONENT_Cb : COMPONENT_Y; + ComponentID compEnd = (tu.cu->isSepTree() && isLuma( chType )) ? COMPONENT_Y : COMPONENT_Cr; +#else ComponentID compStr = (CS::isDualITree(*cs) && !isLuma(chType)) ? COMPONENT_Cb: COMPONENT_Y; ComponentID compEnd = (CS::isDualITree(*cs) && isLuma(chType)) ? COMPONENT_Y : COMPONENT_Cr; +#endif for( ComponentID compID = compStr; compID <= compEnd; compID = ComponentID(compID+1) ) { diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 8ee4580fd..e1a7f8196 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -396,7 +396,11 @@ void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitione cuCtx.isChromaQpAdjCoded = false; } // Reset delta QP coding flag and ChromaQPAdjustemt coding flag +#if JVET_O0050_LOCAL_DUAL_TREE + if (partitioner.isSepTree(cs) && pPartitionerChroma != nullptr) +#else if (CS::isDualITree(cs) && pPartitionerChroma != nullptr) +#endif { if (pps.getUseDQP() && pPartitionerChroma->currQgEnable()) { @@ -461,6 +465,19 @@ void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitione } else { +#if JVET_O0050_LOCAL_DUAL_TREE + const ModeType modeTypeParent = partitioner.modeType; + const ModeType modeTypeChild = CU::getModeTypeAtDepth( cu, partitioner.currDepth ); + mode_constraint( splitMode, cs, partitioner, modeTypeChild ); + partitioner.modeType = modeTypeChild; + + bool chromaNotSplit = modeTypeParent == MODE_TYPE_ALL && modeTypeChild == MODE_TYPE_INTRA ? true : false; + CHECK( chromaNotSplit && partitioner.chType != CHANNEL_TYPE_LUMA, "chType must be luma" ); + if( partitioner.treeType == TREE_D ) + { + partitioner.treeType = chromaNotSplit ? TREE_L : TREE_D; + } +#endif partitioner.splitCurrArea( splitMode, cs ); do @@ -472,6 +489,24 @@ void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitione } while( partitioner.nextPart( cs ) ); partitioner.exitCurrSplit(); +#if JVET_O0050_LOCAL_DUAL_TREE + if( chromaNotSplit ) + { + CHECK( partitioner.chType != CHANNEL_TYPE_LUMA, "must be luma status" ); + partitioner.chType = CHANNEL_TYPE_CHROMA; + partitioner.treeType = TREE_C; + + if( cs.picture->blocks[partitioner.chType].contains( partitioner.currArea().blocks[partitioner.chType].pos() ) ) + { + coding_tree( cs, partitioner, cuCtx ); + } + + //recover + partitioner.chType = CHANNEL_TYPE_LUMA; + partitioner.treeType = TREE_D; + } + partitioner.modeType = modeTypeParent; +#endif } return; } @@ -482,6 +517,9 @@ void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitione cuCtx.qgStart = false; cuCtx.qp = CU::predictQP( cu, cuCtx.qp ); } +#if JVET_O0050_LOCAL_DUAL_TREE + CHECK( cu.treeType != partitioner.treeType, "treeType mismatch" ); +#endif // coding unit @@ -491,6 +529,30 @@ void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitione DTRACE_BLOCK_REC_COND( ( !isEncoding() ), cs.picture->getRecoBuf( cu ), cu, cu.predMode ); } +#if JVET_O0050_LOCAL_DUAL_TREE +void CABACWriter::mode_constraint( const PartSplit split, const CodingStructure& cs, Partitioner& partitioner, const ModeType modeType ) +{ + CHECK( split == CU_DONT_SPLIT, "splitMode shall not be no split" ); + int val = cs.signalModeCons( split, partitioner, partitioner.modeType ); + if( val == 2 ) + { + CHECK( modeType == MODE_TYPE_ALL, "shall not be no constraint case" ); + bool flag = modeType == MODE_TYPE_INTRA; + int ctxIdx = DeriveCtx::CtxModeConsFlag( cs, partitioner ); + m_BinEncoder.encodeBin( flag, Ctx::ModeConsFlag( ctxIdx ) ); + DTRACE( g_trace_ctx, D_SYNTAX, "mode_cons_flag() flag=%d\n", flag ); + } + else if( val == 1 ) + { + assert( modeType == MODE_TYPE_INTRA ); + } + else + { + assert( modeType == partitioner.modeType ); + } +} +#endif + void CABACWriter::split_cu_mode( const PartSplit split, const CodingStructure& cs, Partitioner& partitioner ) { bool canNo, canQt, canBh, canBv, canTh, canTv; @@ -573,6 +635,9 @@ void CABACWriter::split_cu_mode( const PartSplit split, const CodingStructure& c void CABACWriter::coding_unit( const CodingUnit& cu, Partitioner& partitioner, CUCtx& cuCtx ) { +#if JVET_O0050_LOCAL_DUAL_TREE + DTRACE( g_trace_ctx, D_SYNTAX, "coding_unit() treeType=%d modeType=%d\n", cu.treeType, cu.modeType ); +#endif CodingStructure& cs = *cu.cs; // transquant bypass flag if( cs.pps->getTransquantBypassEnabledFlag() ) @@ -648,7 +713,11 @@ void CABACWriter::cu_skip_flag( const CodingUnit& cu ) { unsigned ctxId = DeriveCtx::CtxSkipFlag( cu ); +#if JVET_O0050_LOCAL_DUAL_TREE + if ((cu.slice->isIntra() || cu.isConsIntra()) && cu.cs->slice->getSPS()->getIBCFlag()) +#else if (cu.slice->isIntra() && cu.cs->slice->getSPS()->getIBCFlag()) +#endif { #if JVET_O1161_IBC_MAX_SIZE if (cu.lwidth() < 128 && cu.lheight() < 128) // disable IBC mode larger than 64x64 @@ -665,15 +734,29 @@ void CABACWriter::cu_skip_flag( const CodingUnit& cu ) { return; } +#if JVET_O0050_LOCAL_DUAL_TREE + if( !cu.cs->slice->getSPS()->getIBCFlag() && cu.isConsIntra() ) + { + return; + } +#endif m_BinEncoder.encodeBin( ( cu.skip ), Ctx::SkipFlag( ctxId ) ); DTRACE( g_trace_ctx, D_SYNTAX, "cu_skip_flag() ctx=%d skip=%d\n", ctxId, cu.skip ? 1 : 0 ); if (cu.skip && cu.cs->slice->getSPS()->getIBCFlag()) { #if JVET_O1161_IBC_MAX_SIZE +#if JVET_O0050_LOCAL_DUAL_TREE + if (cu.lwidth() < 128 && cu.lheight() < 128 && !cu.isConsInter()) // // disable IBC mode larger than 64x64 and disable IBC when only allowing inter mode +#else if (cu.lwidth() < 128 && cu.lheight() < 128) // disable IBC mode larger than 64x64 +#endif +#else +#if JVET_O0050_LOCAL_DUAL_TREE + if ((cu.lwidth() < 128 || cu.lheight() < 128) && !cu.isConsInter()) // // disable 128x128 IBC mode and disable IBC when only allowing inter mode #else if (cu.lwidth() < 128 || cu.lheight() < 128) // disable 128x128 IBC mode +#endif #endif { if ( cu.lwidth() == 4 && cu.lheight() == 4 ) @@ -746,7 +829,19 @@ void CABACWriter::pred_mode( const CodingUnit& cu ) if (cu.cs->slice->getSPS()->getIBCFlag()) #endif { +#if JVET_O0050_LOCAL_DUAL_TREE + if( cu.isConsInter() ) + { + assert( CU::isInter( cu ) ); + return; + } +#endif + +#if JVET_O0050_LOCAL_DUAL_TREE + if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) || cu.isConsIntra() ) +#else if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) ) +#endif { #if JVET_O1161_IBC_MAX_SIZE if (cu.lwidth() < 128 && cu.lheight() < 128) // disable IBC mode larger than 64x64 @@ -760,6 +855,12 @@ void CABACWriter::pred_mode( const CodingUnit& cu ) } else { +#if JVET_O0050_LOCAL_DUAL_TREE + if( cu.isConsInter() ) + { + return; + } +#endif m_BinEncoder.encodeBin((CU::isIntra(cu)), Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu))); if (!CU::isIntra(cu)) { @@ -777,6 +878,13 @@ void CABACWriter::pred_mode( const CodingUnit& cu ) } else { +#if JVET_O0050_LOCAL_DUAL_TREE + if( cu.isConsIntra() || cu.isConsInter() ) + { + assert( (cu.isConsIntra() && cu.predMode == MODE_INTRA) || (cu.isConsInter() && cu.predMode == MODE_INTER) ); + return; + } +#endif if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) ) { return; @@ -1203,7 +1311,11 @@ void CABACWriter::intra_luma_pred_mode( const PredictionUnit& pu ) void CABACWriter::intra_chroma_pred_modes( const CodingUnit& cu ) { +#if JVET_O0050_LOCAL_DUAL_TREE + if( cu.chromaFormat == CHROMA_400 || ( cu.isSepTree() && cu.chType == CHANNEL_TYPE_LUMA ) ) +#else if( cu.chromaFormat == CHROMA_400 || ( CS::isDualITree( *cu.cs ) && cu.chType == CHANNEL_TYPE_LUMA ) ) +#endif { return; } @@ -1400,7 +1512,11 @@ void CABACWriter::end_of_ctu( const CodingUnit& cu, CUCtx& cuCtx ) const bool isLastSubCUOfCtu = CU::isLastSubCUOfCtu( cu ); if ( isLastSubCUOfCtu +#if JVET_O0050_LOCAL_DUAL_TREE + && ( !cu.isSepTree() || cu.chromaFormat == CHROMA_400 || isChroma( cu.chType ) ) +#else && ( !CS::isDualITree( *cu.cs ) || cu.chromaFormat == CHROMA_400 || isChroma( cu.chType ) ) +#endif ) { cuCtx.isDQPCoded = ( cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded ); @@ -1431,6 +1547,9 @@ void CABACWriter::end_of_ctu( const CodingUnit& cu, CUCtx& cuCtx ) void CABACWriter::prediction_unit( const PredictionUnit& pu ) { +#if JVET_O0050_LOCAL_DUAL_TREE + CHECK( pu.cu->treeType == TREE_C, "cannot be chroma CU" ); +#endif #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM CHECK( pu.cacheUsed, "Processing a PU that should be in cache!" ); CHECK( pu.cu->cacheUsed, "Processing a CU that should be in cache!" ); @@ -1983,12 +2102,18 @@ void CABACWriter::pcm_samples( const TransformUnit& tu ) CHECK( !tu.cu->ipcm, "pcm mode expected" ); const SPS& sps = *tu.cu->cs->sps; - +#if !JVET_O0050_LOCAL_DUAL_TREE const CodingStructure *cs = tu.cs; +#endif const ChannelType chType = tu.chType; +#if JVET_O0050_LOCAL_DUAL_TREE + ComponentID compStr = (tu.cu->isSepTree() && !isLuma( chType )) ? COMPONENT_Cb : COMPONENT_Y; + ComponentID compEnd = (tu.cu->isSepTree() && isLuma( chType )) ? COMPONENT_Y : COMPONENT_Cr; +#else ComponentID compStr = (CS::isDualITree(*cs) && !isLuma(chType)) ? COMPONENT_Cb: COMPONENT_Y; ComponentID compEnd = (CS::isDualITree(*cs) && isLuma(chType)) ? COMPONENT_Y : COMPONENT_Cr; +#endif for( ComponentID compID = compStr; compID <= compEnd; compID = ComponentID(compID+1) ) { const CPelBuf samples = tu.getPcmbuf( compID ); @@ -2057,7 +2182,11 @@ void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partit #if !JVET_O0596_CBF_SIG_ALIGN_TO_SPEC // cbf_cb & cbf_cr +#if JVET_O0050_LOCAL_DUAL_TREE + if( area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && ( !cu.isSepTree() || partitioner.chType == CHANNEL_TYPE_CHROMA ) && ( !cu.ispMode || chromaCbfISP ) ) +#else if( area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && ( !CS::isDualITree( cs ) || partitioner.chType == CHANNEL_TYPE_CHROMA ) && ( !cu.ispMode || chromaCbfISP ) ) +#endif { { unsigned cbfDepth = chromaCbfISP ? trDepth - 1 : trDepth; @@ -2076,7 +2205,11 @@ void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partit } } } +#if JVET_O0050_LOCAL_DUAL_TREE + else if( cu.isSepTree() ) +#else else if( CS::isDualITree( cs ) ) +#endif { chromaCbfs = ChromaCbfs( false ); } @@ -2297,7 +2430,11 @@ void CABACWriter::transform_unit( const TransformUnit& tu, CUCtx& cuCtx, ChromaC CHECK(tu.depth != trDepth, " transform unit should be not be futher partitioned"); // cbf_cb & cbf_cr +#if JVET_O0050_LOCAL_DUAL_TREE + if (area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && (!cu.isSepTree() || partitioner.chType == CHANNEL_TYPE_CHROMA) && (!cu.ispMode || chromaCbfISP)) +#else if (area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && (!CS::isDualITree(cs) || partitioner.chType == CHANNEL_TYPE_CHROMA) && (!cu.ispMode || chromaCbfISP)) +#endif { { unsigned cbfDepth = chromaCbfISP ? trDepth - 1 : trDepth; @@ -2316,7 +2453,11 @@ void CABACWriter::transform_unit( const TransformUnit& tu, CUCtx& cuCtx, ChromaC } } } +#if JVET_O0050_LOCAL_DUAL_TREE + else if (cu.isSepTree()) +#else else if (CS::isDualITree(cs)) +#endif { chromaCbfs = ChromaCbfs(false); } @@ -2397,7 +2538,11 @@ void CABACWriter::transform_unit( const TransformUnit& tu, CUCtx& cuCtx, ChromaC { if( cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded ) { +#if JVET_O0050_LOCAL_DUAL_TREE + if (!tu.cu->isSepTree() || isLuma(tu.chType)) +#else if (!CS::isDualITree(*tu.cs) || isLuma(tu.chType)) +#endif { cu_qp_delta(cu, cuCtx.qp, cu.qp); cuCtx.qp = cu.qp; @@ -2730,22 +2875,35 @@ void CABACWriter::explicit_rdpcm_mode( const TransformUnit& tu, ComponentID comp void CABACWriter::residual_lfnst_mode( const CodingUnit& cu, CUCtx& cuCtx ) { if( cu.ispMode != NOT_INTRA_SUBPARTITIONS || cu.mipFlag == true || +#if JVET_O0050_LOCAL_DUAL_TREE + ( cu.isSepTree() && cu.chType == CHANNEL_TYPE_CHROMA && std::min( cu.blocks[ 1 ].width, cu.blocks[ 1 ].height ) < 4 ) ) +#else ( CS::isDualITree( *cu.cs ) && cu.chType == CHANNEL_TYPE_CHROMA && std::min( cu.blocks[ 1 ].width, cu.blocks[ 1 ].height ) < 4 ) ) +#endif { return; } if( cu.cs->sps->getUseLFNST() && CU::isIntra( cu ) && !CU::isLosslessCoded( cu ) ) { +#if JVET_O0050_LOCAL_DUAL_TREE + const bool lumaFlag = cu.isSepTree() ? ( isLuma( cu.chType ) ? true : false ) : true; + const bool chromaFlag = cu.isSepTree() ? ( isChroma( cu.chType ) ? true : false ) : true; +#else const bool lumaFlag = CS::isDualITree( *cu.cs ) ? ( isLuma( cu.chType ) ? true : false ) : true; const bool chromaFlag = CS::isDualITree( *cu.cs ) ? ( isChroma( cu.chType ) ? true : false ) : true; +#endif bool nonZeroCoeffNonTs; #if JVET_O0094_LFNST_ZERO_PRIM_COEFFS bool nonZeroCoeffNonTsCorner8x8 = ( lumaFlag && cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_LUMA] ) || (chromaFlag && cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] ); #else bool nonZeroCoeffNonTsCorner8x8 = CU::getNumNonZeroCoeffNonTsCorner8x8( cu, lumaFlag, chromaFlag ) > 0; #endif +#if JVET_O0050_LOCAL_DUAL_TREE + const int nonZeroCoeffThr = cu.isSepTree() ? ( isLuma( cu.chType ) ? LFNST_SIG_NZ_LUMA : LFNST_SIG_NZ_CHROMA ) : LFNST_SIG_NZ_LUMA + LFNST_SIG_NZ_CHROMA; +#else const int nonZeroCoeffThr = CS::isDualITree( *cu.cs ) ? ( isLuma( cu.chType ) ? LFNST_SIG_NZ_LUMA : LFNST_SIG_NZ_CHROMA ) : LFNST_SIG_NZ_LUMA + LFNST_SIG_NZ_CHROMA; +#endif cuCtx.numNonZeroCoeffNonTs = CU::getNumNonZeroCoeffNonTs( cu, lumaFlag, chromaFlag ); nonZeroCoeffNonTs = cuCtx.numNonZeroCoeffNonTs > nonZeroCoeffThr; #if JVET_O0368_LFNST_WITH_DCT2_ONLY @@ -2766,9 +2924,17 @@ void CABACWriter::residual_lfnst_mode( const CodingUnit& cu, CUCtx& cuCtx ) unsigned cctx = 0; #if JVET_O0368_LFNST_WITH_DCT2_ONLY +#if JVET_O0050_LOCAL_DUAL_TREE + if ( cu.isSepTree() ) cctx++; +#else if ( CS::isDualITree(*cu.cs) ) cctx++; +#endif +#else +#if JVET_O0050_LOCAL_DUAL_TREE + if( cu.firstTU->mtsIdx < MTS_DST7_DST7 && cu.isSepTree() ) cctx++; #else if( cu.firstTU->mtsIdx < MTS_DST7_DST7 && CS::isDualITree( *cu.cs ) ) cctx++; +#endif #endif const uint32_t idxLFNST = cu.lfnstIdx; diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index 6a2453e2a..aafe19ad1 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -83,6 +83,9 @@ public: // coding (quad)tree (clause 7.3.8.4) 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 ); +#if JVET_O0050_LOCAL_DUAL_TREE + void mode_constraint ( const PartSplit split, const CodingStructure& cs, Partitioner& pm, const ModeType modeType ); +#endif // coding unit (clause 7.3.8.5) void coding_unit ( const CodingUnit& cu, Partitioner& pm, CUCtx& cuCtx ); diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 920639e84..117a437ca 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -88,11 +88,19 @@ void EncCu::create( EncCfg* encCfg ) unsigned numHeights = gp_sizeIdxInfo->numHeights(); m_pTempCS = new CodingStructure** [numWidths]; m_pBestCS = new CodingStructure** [numWidths]; +#if JVET_O0050_LOCAL_DUAL_TREE + m_pTempCS2 = new CodingStructure** [numWidths]; + m_pBestCS2 = new CodingStructure** [numWidths]; +#endif for( unsigned w = 0; w < numWidths; w++ ) { m_pTempCS[w] = new CodingStructure* [numHeights]; m_pBestCS[w] = new CodingStructure* [numHeights]; + #if JVET_O0050_LOCAL_DUAL_TREE + m_pTempCS2[w] = new CodingStructure* [numHeights]; + m_pBestCS2[w] = new CodingStructure* [numHeights]; +#endif for( unsigned h = 0; h < numHeights; h++ ) { @@ -106,11 +114,23 @@ void EncCu::create( EncCfg* encCfg ) m_pTempCS[w][h]->create( chromaFormat, Area( 0, 0, width, height ), false ); m_pBestCS[w][h]->create( chromaFormat, Area( 0, 0, width, height ), false ); + +#if JVET_O0050_LOCAL_DUAL_TREE + m_pTempCS2[w][h] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache ); + m_pBestCS2[w][h] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache ); + + m_pTempCS2[w][h]->create( chromaFormat, Area( 0, 0, width, height ), false ); + m_pBestCS2[w][h]->create( chromaFormat, Area( 0, 0, width, height ), false ); +#endif } else { m_pTempCS[w][h] = nullptr; m_pBestCS[w][h] = nullptr; +#if JVET_O0050_LOCAL_DUAL_TREE + m_pTempCS2[w][h] = nullptr; + m_pBestCS2[w][h] = nullptr; +#endif } } } @@ -190,14 +210,30 @@ void EncCu::destroy() delete m_pBestCS[w][h]; delete m_pTempCS[w][h]; + +#if JVET_O0050_LOCAL_DUAL_TREE + if( m_pBestCS2[w][h] ) m_pBestCS2[w][h]->destroy(); + if( m_pTempCS2[w][h] ) m_pTempCS2[w][h]->destroy(); + + delete m_pBestCS2[w][h]; + delete m_pTempCS2[w][h]; +#endif } delete[] m_pTempCS[w]; delete[] m_pBestCS[w]; +#if JVET_O0050_LOCAL_DUAL_TREE + delete[] m_pTempCS2[w]; + delete[] m_pBestCS2[w]; +#endif } delete[] m_pBestCS; m_pBestCS = nullptr; delete[] m_pTempCS; m_pTempCS = nullptr; +#if JVET_O0050_LOCAL_DUAL_TREE + delete[] m_pBestCS2; m_pBestCS2 = nullptr; + delete[] m_pTempCS2; m_pTempCS2 = nullptr; +#endif #if REUSE_CU_RESULTS if (m_tmpStorageLCU) @@ -290,6 +326,9 @@ void EncCu::init( EncLib* pcEncLib, const SPS& sps PARL_PARAM( const int tId ) ) void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsigned ctuRsAddr, const int prevQP[], const int currQP[] ) { m_modeCtrl->initCTUEncoding( *cs.slice ); +#if JVET_O0050_LOCAL_DUAL_TREE + cs.treeType = TREE_D; +#endif #if ENABLE_SPLIT_PARALLELISM if( m_pcEncCfg->getNumSplitThreads() > 1 ) @@ -604,6 +643,11 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par const uint32_t uiLPelX = tempCS->area.Y().lumaPos().x; const uint32_t uiTPelY = tempCS->area.Y().lumaPos().y; +#if JVET_O0050_LOCAL_DUAL_TREE + const ModeType modeTypeParent = partitioner.modeType; + const TreeType treeTypeParent = partitioner.treeType; + const ChannelType chTypeParent = partitioner.chType; +#endif const UnitArea currCsArea = clipArea( CS::getArea( *bestCS, bestCS->area, partitioner.chType ), *tempCS->picture ); m_modeCtrl->initCULevel( partitioner, *tempCS ); @@ -658,7 +702,11 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par { EncTestMode currTestMode = m_modeCtrl->currTestMode(); +#if JVET_O0050_LOCAL_DUAL_TREE + if (pps.getUseDQP() && partitioner.isSepTree(*tempCS) && isChroma( partitioner.chType )) +#else if (pps.getUseDQP() && CS::isDualITree(*tempCS) && isChroma(partitioner.chType)) +#endif { const Position chromaCentral(tempCS->area.Cb().chromaPos().offset(tempCS->area.Cb().chromaSize().width >> 1, tempCS->area.Cb().chromaSize().height >> 1)); const Position lumaRefPos(chromaCentral.x << getComponentScaleX(COMPONENT_Cb, tempCS->area.chromaFormat), chromaCentral.y << getComponentScaleY(COMPONENT_Cb, tempCS->area.chromaFormat)); @@ -752,8 +800,68 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par } else if( isModeSplit( currTestMode ) ) { +#if JVET_O0050_LOCAL_DUAL_TREE + assert( partitioner.modeType == tempCS->modeType ); + int signalModeConsVal = tempCS->signalModeCons( getPartSplit( currTestMode ), partitioner, modeTypeParent ); + int num_round_rdo = signalModeConsVal == 2 ? 2 : 1; + bool skipInterPass = false; + for( int i = 0; i < num_round_rdo; i++ ) + { + //change cons modes + if( signalModeConsVal == 2 ) + { + CHECK( num_round_rdo != 2, "num_round_rdo shall be 2 - [2]" ); + tempCS->modeType = partitioner.modeType = (i == 0) ? MODE_TYPE_INTER : MODE_TYPE_INTRA; + } + else if( signalModeConsVal == 1 ) + { + CHECK( num_round_rdo != 1, "num_round_rdo shall be 1 - [1]" ); + tempCS->modeType = partitioner.modeType = MODE_TYPE_INTRA; + } + else if( signalModeConsVal == 0 ) + { + CHECK( num_round_rdo != 1, "num_round_rdo shall be 1 - [0]" ); + tempCS->modeType = partitioner.modeType = modeTypeParent; + } + //for lite intra encoding fast algorithm, set the status to save inter coding info + if( modeTypeParent == MODE_TYPE_ALL && tempCS->modeType == MODE_TYPE_INTER ) + { + m_pcIntraSearch->setSaveCuCostInSCIPU( true ); + m_pcIntraSearch->setNumCuInSCIPU( 0 ); + } + else if( modeTypeParent == MODE_TYPE_ALL && tempCS->modeType != MODE_TYPE_INTER ) + { + m_pcIntraSearch->setSaveCuCostInSCIPU( false ); + if( tempCS->modeType == MODE_TYPE_ALL ) + { + m_pcIntraSearch->setNumCuInSCIPU( 0 ); + } + } + + xCheckModeSplit( tempCS, bestCS, partitioner, currTestMode, modeTypeParent, skipInterPass ); +#else xCheckModeSplit( tempCS, bestCS, partitioner, currTestMode ); +#endif +#if JVET_O0050_LOCAL_DUAL_TREE + //recover cons modes + tempCS->modeType = partitioner.modeType = modeTypeParent; + tempCS->treeType = partitioner.treeType = treeTypeParent; + partitioner.chType = chTypeParent; + if( modeTypeParent == MODE_TYPE_ALL ) + { + m_pcIntraSearch->setSaveCuCostInSCIPU( false ); + if( num_round_rdo == 2 && tempCS->modeType == MODE_TYPE_INTRA ) + { + m_pcIntraSearch->initCuAreaCostInSCIPU(); + } + } + if( skipInterPass ) + { + break; + } + } +#endif } else { @@ -810,6 +918,12 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par bestCS->picture->getPredBuf(currCsArea).copyFrom(bestCS->getPredBuf(currCsArea)); bestCS->picture->getRecoBuf( currCsArea ).copyFrom( bestCS->getRecoBuf( currCsArea ) ); m_modeCtrl->finishCULevel( partitioner ); +#if JVET_O0050_LOCAL_DUAL_TREE + if( m_pcIntraSearch->getSaveCuCostInSCIPU() && bestCS->cus.size() == 1 ) + { + m_pcIntraSearch->saveCuAreaCostInSCIPU( Area( partitioner.currArea().lumaPos(), partitioner.currArea().lumaSize() ), bestCS->cost ); + } +#endif #if ENABLE_SPLIT_PARALLELISM if( tempCS->picture->scheduler.getSplitJobId() == 0 && m_pcEncCfg->getNumSplitThreads() != 1 ) @@ -1095,7 +1209,11 @@ void EncCu::copyState( EncCu* other, Partitioner& partitioner, const UnitArea& c } #endif +#if JVET_O0050_LOCAL_DUAL_TREE +void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode, const ModeType modeTypeParent, bool &skipInterPass ) +#else void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode ) +#endif { const int qp = encTestMode.qp; const Slice &slice = *tempCS->slice; @@ -1108,6 +1226,9 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, #endif const PartSplit split = getPartSplit( encTestMode ); +#if JVET_O0050_LOCAL_DUAL_TREE + const ModeType modeTypeChild = partitioner.modeType; +#endif CHECK( split == CU_DONT_SPLIT, "No proper split provided!" ); @@ -1119,10 +1240,15 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, const TempCtx ctxStartQt( m_CtxCache, SubCtx( Ctx::SplitQtFlag, m_CABACEstimator->getCtx() ) ); const TempCtx ctxStartHv( m_CtxCache, SubCtx( Ctx::SplitHvFlag, m_CABACEstimator->getCtx() ) ); const TempCtx ctxStart12( m_CtxCache, SubCtx( Ctx::Split12Flag, m_CABACEstimator->getCtx() ) ); - +#if JVET_O0050_LOCAL_DUAL_TREE + const TempCtx ctxStartMC( m_CtxCache, SubCtx( Ctx::ModeConsFlag, m_CABACEstimator->getCtx() ) ); +#endif m_CABACEstimator->resetBits(); m_CABACEstimator->split_cu_mode( split, *tempCS, partitioner ); +#if JVET_O0050_LOCAL_DUAL_TREE + m_CABACEstimator->mode_constraint( split, *tempCS, partitioner, modeTypeChild ); +#endif const double factor = ( tempCS->currQP[partitioner.chType] > 30 ? 1.1 : 1.075 ); tempCS->useDbCost = m_pcEncCfg->getUseEncDbOpt(); @@ -1134,7 +1260,9 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, m_CABACEstimator->getCtx() = SubCtx( Ctx::SplitQtFlag, ctxStartQt ); m_CABACEstimator->getCtx() = SubCtx( Ctx::SplitHvFlag, ctxStartHv ); m_CABACEstimator->getCtx() = SubCtx( Ctx::Split12Flag, ctxStart12 ); - +#if JVET_O0050_LOCAL_DUAL_TREE + m_CABACEstimator->getCtx() = SubCtx( Ctx::ModeConsFlag, ctxStartMC ); +#endif if (cost > bestCS->cost + bestCS->costDbOffset #if ENABLE_QPA_SUB_CTU || (m_pcEncCfg->getUsePerceptQPA() && !m_pcEncCfg->getUseRateCtrl() && pps.getUseDQP() && (pps.getCuQpDeltaSubdiv() > 0) && (split == CU_HORZ_SPLIT || split == CU_VERT_SPLIT) && @@ -1146,6 +1274,26 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, return; } +#if JVET_O0050_LOCAL_DUAL_TREE + const bool chromaNotSplit = modeTypeParent == MODE_TYPE_ALL && modeTypeChild == MODE_TYPE_INTRA ? true : false; + if( partitioner.treeType != TREE_D ) + { + tempCS->treeType = TREE_L; + } + else + { + if( chromaNotSplit ) + { + CHECK( partitioner.chType != CHANNEL_TYPE_LUMA, "chType must be luma" ); + tempCS->treeType = partitioner.treeType = TREE_L; + } + else + { + tempCS->treeType = partitioner.treeType = TREE_D; + } + } +#endif + int startShareThisLevel = 0; const uint32_t uiLPelX = tempCS->area.Y().lumaPos().x; const uint32_t uiTPelY = tempCS->area.Y().lumaPos().y; @@ -1239,6 +1387,18 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, m_CurrCtx--; partitioner.exitCurrSplit(); xCheckBestMode( tempCS, bestCS, partitioner, encTestMode ); +#if JVET_O0050_LOCAL_DUAL_TREE //early terminate + if( partitioner.chType == CHANNEL_TYPE_LUMA ) + { + tempCS->motionLut = oldMotionLut; + } + if( startShareThisLevel == 1 ) + { + m_shareState = NO_SHARE; + m_pcInterSearch->setShareState( m_shareState ); + setShareStateDec( m_shareState ); + } +#endif return; } @@ -1249,9 +1409,50 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, { tempCS->prevQP[partitioner.chType] = bestSubCS->prevQP[partitioner.chType]; } +#if JVET_O0050_LOCAL_DUAL_TREE + if( partitioner.isConsInter() ) + { + for( int i = 0; i < bestSubCS->cus.size(); i++ ) + { + CHECK( bestSubCS->cus[i]->predMode != MODE_INTER, "all CUs must be inter mode in an Intra coding region (SCIPU)" ); + } + } + else if( partitioner.isConsIntra() ) + { + for( int i = 0; i < bestSubCS->cus.size(); i++ ) + { + CHECK( bestSubCS->cus[i]->predMode != MODE_INTRA && bestSubCS->cus[i]->predMode != MODE_IBC, "all CUs must be intra/ibc mode in an Intra coding region (SCIPU)" ); + } + } +#endif tempSubCS->releaseIntermediateData(); bestSubCS->releaseIntermediateData(); +#if JVET_O0050_LOCAL_DUAL_TREE //early terminate + if( !tempCS->slice->isIntra() && partitioner.isConsIntra() ) + { + tempCS->cost = m_pcRdCost->calcRdCost( tempCS->fracBits, tempCS->dist ); + if( tempCS->cost > bestCS->cost ) + { + tempCS->cost = MAX_DOUBLE; + tempCS->costDbOffset = 0; + tempCS->useDbCost = m_pcEncCfg->getUseEncDbOpt(); + m_CurrCtx--; + partitioner.exitCurrSplit(); + if( partitioner.chType == CHANNEL_TYPE_LUMA ) + { + tempCS->motionLut = oldMotionLut; + } + if( startShareThisLevel == 1 ) + { + m_shareState = NO_SHARE; + m_pcInterSearch->setShareState( m_shareState ); + setShareStateDec( m_shareState ); + } + return; + } + } +#endif } } while( partitioner.nextPart( *tempCS ) ); @@ -1266,6 +1467,49 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, m_CurrCtx--; +#if JVET_O0050_LOCAL_DUAL_TREE + if( chromaNotSplit ) + { + assert( tempCS->treeType == TREE_L ); + uint32_t numCuPuTu[6]; + tempCS->picture->cs->getNumCuPuTuOffset( numCuPuTu ); + tempCS->picture->cs->useSubStructure( *tempCS, partitioner.chType, CS::getArea( *tempCS, partitioner.currArea(), partitioner.chType ), false, true, false, false ); + + partitioner.chType = CHANNEL_TYPE_CHROMA; + tempCS->treeType = partitioner.treeType = TREE_C; + + m_CurrCtx++; + + const unsigned wIdx = gp_sizeIdxInfo->idxFrom( partitioner.currArea().lwidth() ); + const unsigned hIdx = gp_sizeIdxInfo->idxFrom( partitioner.currArea().lheight() ); + CodingStructure *tempCSChroma = m_pTempCS2[wIdx][hIdx]; + CodingStructure *bestCSChroma = m_pBestCS2[wIdx][hIdx]; + tempCS->initSubStructure( *tempCSChroma, partitioner.chType, partitioner.currArea(), false ); + tempCS->initSubStructure( *bestCSChroma, partitioner.chType, partitioner.currArea(), false ); + tempCS->treeType = TREE_D; + xCompressCU( tempCSChroma, bestCSChroma, partitioner ); + + //attach chromaCS to luma CS and update cost + bool keepResi = KEEP_PRED_AND_RESI_SIGNALS; + //bestCSChroma->treeType = tempCSChroma->treeType = TREE_C; + CHECK( bestCSChroma->treeType != TREE_C || tempCSChroma->treeType != TREE_C, "wrong treeType for chroma CS" ); + tempCS->useSubStructure( *bestCSChroma, partitioner.chType, CS::getArea( *bestCSChroma, partitioner.currArea(), partitioner.chType ), KEEP_PRED_AND_RESI_SIGNALS, true, keepResi, true ); + + //release tmp resource + tempCSChroma->releaseIntermediateData(); + bestCSChroma->releaseIntermediateData(); + //tempCS->picture->cs->releaseIntermediateData(); + tempCS->picture->cs->clearCuPuTuIdxMap( partitioner.currArea(), numCuPuTu[0], numCuPuTu[1], numCuPuTu[2], numCuPuTu + 3 ); + + m_CurrCtx--; + + //recover luma tree status + partitioner.chType = CHANNEL_TYPE_LUMA; + partitioner.treeType = TREE_D; + partitioner.modeType = MODE_TYPE_ALL; + } +#endif + // Finally, generate split-signaling bits for RD-cost check const PartSplit implicitSplit = partitioner.getImplicitSplit( *tempCS ); @@ -1295,7 +1539,10 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, m_CABACEstimator->resetBits(); m_CABACEstimator->split_cu_mode( split, *tempCS, partitioner ); - +#if JVET_O0050_LOCAL_DUAL_TREE + partitioner.modeType = modeTypeParent; + m_CABACEstimator->mode_constraint( split, *tempCS, partitioner, modeTypeChild ); +#endif tempCS->fracBits += m_CABACEstimator->getEstFracBits(); // split bits } } @@ -1330,6 +1577,20 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, bestCS->costDbOffset = 0; } tempCS->useDbCost = m_pcEncCfg->getUseEncDbOpt(); +#if JVET_O0050_LOCAL_DUAL_TREE + if( tempCS->cus.size() > 0 && modeTypeParent == MODE_TYPE_ALL && modeTypeChild == MODE_TYPE_INTER ) + { + int areaSizeNoResiCu = 0; + for( int k = 0; k < tempCS->cus.size(); k++ ) + { + areaSizeNoResiCu += (tempCS->cus[k]->rootCbf == false) ? tempCS->cus[k]->lumaSize().area() : 0; + } + if( areaSizeNoResiCu >= (tempCS->area.lumaSize().area() >> 1) ) + { + skipInterPass = true; + } + } +#endif // RD check for sub partitioned coding structure. xCheckBestMode( tempCS, bestCS, partitioner, encTestMode ); @@ -1378,7 +1639,11 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC int bestMtsFlag = 0; int bestLfnstIdx = 0; +#if JVET_O0050_LOCAL_DUAL_TREE + const int maxLfnstIdx = partitioner.isSepTree( *tempCS ) && partitioner.chType == CHANNEL_TYPE_CHROMA && ( partitioner.currArea().lwidth() < 8 || partitioner.currArea().lheight() < 8 ) ? 0 : 2; +#else const int maxLfnstIdx = CS::isDualITree( *tempCS ) && partitioner.chType == CHANNEL_TYPE_CHROMA && ( partitioner.currArea().lwidth() < 8 || partitioner.currArea().lheight() < 8 ) ? 0 : 2; +#endif bool skipOtherLfnst = false; int startLfnstIdx = 0; int endLfnstIdx = sps.getUseLFNST() ? maxLfnstIdx : 0; @@ -1435,7 +1700,11 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC if( isLuma( partitioner.chType ) ) { //the Intra SubPartitions mode uses the value of the best cost so far (luma if it is the fast version) to avoid test non-necessary lines +#if JVET_O0050_LOCAL_DUAL_TREE + const double bestCostSoFar = partitioner.isSepTree( *tempCS ) ? m_modeCtrl->getBestCostWithoutSplitFlags() : bestCU && bestCU->predMode == MODE_INTRA ? bestCS->lumaCost : bestCS->cost; +#else const double bestCostSoFar = CS::isDualITree( *tempCS ) ? m_modeCtrl->getBestCostWithoutSplitFlags() : bestCU && bestCU->predMode == MODE_INTRA ? bestCS->lumaCost : bestCS->cost; +#endif validCandRet = m_pcIntraSearch->estIntraPredLumaQT( cu, partitioner, bestCostSoFar, mtsFlag, startMTSIdx[ trGrpIdx ], endMTSIdx[ trGrpIdx ], ( trGrpIdx > 0 ) ); if( sps.getUseLFNST() && ( !validCandRet || ( cu.ispMode && cu.firstTU->cbf[ COMPONENT_Y ] == 0 ) ) ) { @@ -1443,7 +1712,11 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC } useIntraSubPartitions = cu.ispMode != NOT_INTRA_SUBPARTITIONS; +#if JVET_O0050_LOCAL_DUAL_TREE + if( !partitioner.isSepTree( *tempCS ) ) +#else if( !CS::isDualITree( *tempCS ) ) +#endif { tempCS->lumaCost = m_pcRdCost->calcRdCost( tempCS->fracBits, tempCS->dist ); if( useIntraSubPartitions ) @@ -1462,17 +1735,29 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC continue; } +#if JVET_O0050_LOCAL_DUAL_TREE + if( !partitioner.isSepTree( *tempCS ) ) +#else if( !CS::isDualITree( *tempCS ) ) +#endif { cu.cs->picture->getRecoBuf( cu.Y() ).copyFrom( cu.cs->getRecoBuf( COMPONENT_Y ) ); cu.cs->picture->getPredBuf(cu.Y()).copyFrom(cu.cs->getPredBuf(COMPONENT_Y)); } } +#if JVET_O0050_LOCAL_DUAL_TREE + if( tempCS->area.chromaFormat != CHROMA_400 && ( partitioner.chType == CHANNEL_TYPE_CHROMA || !cu.isSepTree() ) ) +#else if( tempCS->area.chromaFormat != CHROMA_400 && ( partitioner.chType == CHANNEL_TYPE_CHROMA || !CS::isDualITree( *tempCS ) ) ) +#endif { TUIntraSubPartitioner subTuPartitioner( partitioner ); +#if JVET_O0050_LOCAL_DUAL_TREE + m_pcIntraSearch->estIntraPredChromaQT( cu, ( !useIntraSubPartitions || ( cu.isSepTree() && !isLuma( CHANNEL_TYPE_CHROMA ) ) ) ? partitioner : subTuPartitioner, maxCostAllowedForChroma ); +#else m_pcIntraSearch->estIntraPredChromaQT( cu, ( !useIntraSubPartitions || ( CS::isDualITree( *cu.cs ) && !isLuma( CHANNEL_TYPE_CHROMA ) ) ) ? partitioner : subTuPartitioner, maxCostAllowedForChroma ); +#endif if( useIntraSubPartitions && !cu.ispMode ) { //At this point the temp cost is larger than the best cost. Therefore, we can already skip the remaining calculations @@ -1515,7 +1800,11 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC tempCS->fracBits = m_CABACEstimator->getEstFracBits(); tempCS->cost = m_pcRdCost->calcRdCost(tempCS->fracBits, tempCS->dist); +#if JVET_O0050_LOCAL_DUAL_TREE + double bestIspCost = cu.ispMode ? cu.isSepTree() ? tempCS->cost : tempCS->lumaCost : MAX_DOUBLE; +#else double bestIspCost = cu.ispMode ? CS::isDualITree( *tempCS ) ? tempCS->cost : tempCS->lumaCost : MAX_DOUBLE; +#endif const double tmpCostWithoutSplitFlags = tempCS->cost; xEncodeDontSplit( *tempCS, partitioner ); @@ -1523,7 +1812,11 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC xCheckDQP( *tempCS, partitioner ); // Check if low frequency non-separable transform (LFNST) is too expensive +#if JVET_O0050_LOCAL_DUAL_TREE + const int nonZeroCoeffThr = cu.isSepTree() ? ( isLuma( partitioner.chType ) ? LFNST_SIG_NZ_LUMA : LFNST_SIG_NZ_CHROMA ) : LFNST_SIG_NZ_LUMA + LFNST_SIG_NZ_CHROMA; +#else const int nonZeroCoeffThr = CS::isDualITree( *tempCS ) ? ( isLuma( partitioner.chType ) ? LFNST_SIG_NZ_LUMA : LFNST_SIG_NZ_CHROMA ) : LFNST_SIG_NZ_LUMA + LFNST_SIG_NZ_CHROMA; +#endif if( lfnstIdx && cuCtx.numNonZeroCoeffNonTs <= nonZeroCoeffThr ) { if (cuCtx.numNonZeroCoeffNonTs > 0) @@ -1711,7 +2004,11 @@ void EncCu::xCheckDQP( CodingStructure& cs, Partitioner& partitioner, bool bKeep return; } +#if JVET_O0050_LOCAL_DUAL_TREE + if (partitioner.isSepTree(cs) && isChroma(partitioner.chType)) +#else if (CS::isDualITree(cs) && isChroma(partitioner.chType)) +#endif { return; } @@ -3177,7 +3474,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct PU::spanMotionInfo(pu, mergeCtx); assert(mergeCtx.mrgTypeNeighbours[mergeCand] == MRG_TYPE_IBC); // should be IBC candidate at this round +#if JVET_O0050_LOCAL_DUAL_TREE + const bool chroma = !pu.cu->isSepTree(); +#else const bool chroma = !(CS::isDualITree(*tempCS)); +#endif // MC m_pcInterSearch->motionCompensation(pu,REF_PIC_LIST_0, true, chroma); @@ -3273,7 +3574,11 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best if (bValid) { PU::spanMotionInfo(pu); +#if JVET_O0050_LOCAL_DUAL_TREE + const bool chroma = !pu.cu->isSepTree(); +#else const bool chroma = !(CS::isDualITree(*tempCS)); +#endif // MC m_pcInterSearch->motionCompensation(pu, REF_PIC_LIST_0, true, chroma); @@ -3713,8 +4018,13 @@ void EncCu::xCalDebCost( CodingStructure &cs, Partitioner &partitioner, bool cal if ( calDist ) { const UnitArea currCsArea = clipArea( CS::getArea( cs, cs.area, partitioner.chType ), *cs.picture ); +#if JVET_O0050_LOCAL_DUAL_TREE + ComponentID compStr = ( cu->isSepTree() && !isLuma( partitioner.chType ) ) ? COMPONENT_Cb : COMPONENT_Y; + ComponentID compEnd = ( cu->isSepTree() && isLuma( partitioner.chType ) ) ? COMPONENT_Y : COMPONENT_Cr; +#else ComponentID compStr = ( CS::isDualITree( cs ) && !isLuma( partitioner.chType ) ) ? COMPONENT_Cb : COMPONENT_Y; ComponentID compEnd = ( CS::isDualITree( cs ) && isLuma( partitioner.chType ) ) ? COMPONENT_Y : COMPONENT_Cr; +#endif Distortion finalDistortion = 0; for ( int comp = compStr; comp <= compEnd; comp++ ) { @@ -3729,8 +4039,13 @@ void EncCu::xCalDebCost( CodingStructure &cs, Partitioner &partitioner, bool cal if ( anyEdgeAvai && m_pcEncCfg->getUseEncDbOpt() ) { +#if JVET_O0050_LOCAL_DUAL_TREE + ComponentID compStr = ( cu->isSepTree() && !isLuma( partitioner.chType ) ) ? COMPONENT_Cb : COMPONENT_Y; + ComponentID compEnd = ( cu->isSepTree() && isLuma( partitioner.chType ) ) ? COMPONENT_Y : COMPONENT_Cr; +#else ComponentID compStr = ( CS::isDualITree( cs ) && !isLuma( partitioner.chType ) ) ? COMPONENT_Cb : COMPONENT_Y; ComponentID compEnd = ( CS::isDualITree( cs ) && isLuma( partitioner.chType ) ) ? COMPONENT_Y : COMPONENT_Cr; +#endif const UnitArea currCsArea = clipArea( CS::getArea( cs, cs.area, partitioner.chType ), *cs.picture ); @@ -4291,6 +4606,10 @@ void EncCu::xEncodeDontSplit( CodingStructure &cs, Partitioner &partitioner ) m_CABACEstimator->resetBits(); m_CABACEstimator->split_cu_mode( CU_DONT_SPLIT, cs, partitioner ); +#if JVET_O0050_LOCAL_DUAL_TREE + if( partitioner.treeType == TREE_C ) + CHECK( m_CABACEstimator->getEstFracBits() != 0, "must be 0 bit" ); +#endif cs.fracBits += m_CABACEstimator->getEstFracBits(); // split bits cs.cost = m_pcRdCost->calcRdCost( cs.fracBits, cs.dist ); @@ -4338,7 +4657,11 @@ void EncCu::xReuseCachedResult( CodingStructure *&tempCS, CodingStructure *&best { const ComponentID compID = ComponentID( comp ); +#if JVET_O0050_LOCAL_DUAL_TREE + if( partitioner.isSepTree( *tempCS ) && toChannelType( compID ) != partitioner.chType ) +#else if( CS::isDualITree( *tempCS ) && toChannelType( compID ) != partitioner.chType ) +#endif { continue; } diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h index 67ef7f05f..a6ec27862 100644 --- a/source/Lib/EncoderLib/EncCu.h +++ b/source/Lib/EncoderLib/EncCu.h @@ -102,6 +102,10 @@ private: CodingStructure ***m_pTempCS; CodingStructure ***m_pBestCS; +#if JVET_O0050_LOCAL_DUAL_TREE + CodingStructure ***m_pTempCS2; + CodingStructure ***m_pBestCS2; +#endif // Access channel EncCfg* m_pcEncCfg; IntraSearch* m_pcIntraSearch; @@ -184,7 +188,11 @@ protected: bool xCheckBestMode ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestmode ); +#if JVET_O0050_LOCAL_DUAL_TREE + void xCheckModeSplit ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode, const ModeType modeTypeParent, bool &skipInterPass ); +#else void xCheckModeSplit ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode ); +#endif void xCheckRDCostIntra ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode ); void xCheckIntraPCM ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode ); diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp index e59cca54e..31a6cf582 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.cpp +++ b/source/Lib/EncoderLib/EncModeCtrl.cpp @@ -881,11 +881,23 @@ bool BestEncInfoCache::setFromCs( const CodingStructure& cs, const Partitioner& bool BestEncInfoCache::isValid( const CodingStructure& cs, const Partitioner& partitioner, int qp ) { +#if JVET_O0050_LOCAL_DUAL_TREE + if( partitioner.treeType == TREE_C ) + { + return false; //if save & load is allowed for chroma CUs, we should check whether luma info (pred, recon, etc) is the same, which is quite complex + } +#endif unsigned idx1, idx2, idx3, idx4; getAreaIdx( cs.area.Y(), *m_slice_bencinf->getPPS()->pcv, idx1, idx2, idx3, idx4 ); BestEncodingInfo& encInfo = *m_bestEncInfo[idx1][idx2][idx3][idx4]; +#if JVET_O0050_LOCAL_DUAL_TREE + if( encInfo.cu.treeType != partitioner.treeType || encInfo.cu.modeType != partitioner.modeType ) + { + return false; + } +#endif if( encInfo.cu.qp != qp ) return false; if( cs.picture->poc != encInfo.poc || CS::getArea( cs, cs.area, partitioner.chType ) != CS::getArea( cs, encInfo.cu, partitioner.chType ) || !isTheSameNbHood( encInfo.cu, cs, partitioner @@ -1140,7 +1152,11 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru // QP int baseQP = cs.baseQP; +#if JVET_O0050_LOCAL_DUAL_TREE + if (!partitioner.isSepTree(cs) || isLuma(partitioner.chType)) +#else if (!CS::isDualITree (cs) || isLuma (partitioner.chType)) +#endif { if (m_pcEncCfg->getUseAdaptiveQP()) { @@ -1296,6 +1312,20 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru ////////////////////////////////////////////////////////////////////////// // Add unit coding modes: Intra, InterME, InterMerge ... +#if JVET_O0050_LOCAL_DUAL_TREE + bool try_intra_rdo = true; + bool try_inter_rdo = true; + bool try_ibc_rdo = true; + if( partitioner.isConsIntra() ) + { + try_inter_rdo = false; + } + else if( partitioner.isConsInter() ) + { + try_intra_rdo = try_ibc_rdo = false; + } + checkIbc &= try_ibc_rdo; +#endif for( int qpLoop = maxQP; qpLoop >= minQP; qpLoop-- ) { @@ -1310,8 +1340,15 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru } #endif // add intra modes +#if JVET_O0050_LOCAL_DUAL_TREE + if( try_intra_rdo ) + { +#endif m_ComprCUCtxList.back().testModes.push_back( { ETM_IPCM, ETO_STANDARD, qp, lossless } ); m_ComprCUCtxList.back().testModes.push_back( { ETM_INTRA, ETO_STANDARD, qp, lossless } ); +#if JVET_O0050_LOCAL_DUAL_TREE + } +#endif // add ibc mode to intra path if (cs.sps->getIBCFlag() && checkIbc) { @@ -1324,7 +1361,11 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru } // add first pass modes +#if JVET_O0050_LOCAL_DUAL_TREE + if ( !m_slice->isIRAP() && !( cs.area.lwidth() == 4 && cs.area.lheight() == 4 ) && try_inter_rdo ) +#else if ( !m_slice->isIRAP() && !( cs.area.lwidth() == 4 && cs.area.lheight() == 4 ) ) +#endif { for( int qpLoop = maxQP; qpLoop >= minQP; qpLoop-- ) { @@ -1490,6 +1531,12 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt // INTRA MODES if (cs.sps->getIBCFlag() && !cuECtx.bestTU) return true; +#if JVET_O0050_LOCAL_DUAL_TREE + if( partitioner.isConsIntra() && !cuECtx.bestTU ) + { + return true; + } +#endif if ( partitioner.currArea().lumaSize().width == 4 && partitioner.currArea().lumaSize().height == 4 && !slice.isIntra() && !cuECtx.bestTU ) { return true; @@ -1824,6 +1871,12 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt #if REUSE_CU_RESULTS setFromCs( *bestCS, partitioner ); +#endif +#if JVET_O0050_LOCAL_DUAL_TREE + if( partitioner.modeType == MODE_TYPE_INTRA && partitioner.chType == CHANNEL_TYPE_LUMA ) + { + return false; //not set best coding mode for intra coding pass + } #endif // assume the non-split modes are done and set the marks for the best found mode if( bestCS && bestCU ) diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index 9aaac4ded..94fd4f40b 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -6574,7 +6574,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par if (bCheckFull) { +#if JVET_O0050_LOCAL_DUAL_TREE + TransformUnit &tu = csFull->addTU(CS::getArea( cs, currArea, partitioner.chType ), partitioner.chType); +#else TransformUnit &tu = csFull->addTU(CS::isDualITree(cs) ? cu : currArea, partitioner.chType); +#endif tu.depth = currDepth; tu.mtsIdx = MTS_DCT2_DCT2; tu.checkTuNoResidual( partitioner.currPartIdx() ); @@ -6614,7 +6618,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par saveCS.picture = cs.picture; saveCS.area.repositionTo(currArea); saveCS.clearTUs(); +#if JVET_O0050_LOCAL_DUAL_TREE + TransformUnit & bestTU = saveCS.addTU(CS::getArea(cs, currArea, partitioner.chType), partitioner.chType); +#else TransformUnit & bestTU = saveCS.addTU(CS::isDualITree(cs) ? cu : currArea, partitioner.chType); +#endif for( uint32_t c = 0; c < numTBlocks; c++ ) { @@ -7316,6 +7324,10 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa m_pcRdCost->setChromaFormat(cs.sps->getChromaFormatIdc()); CodingUnit &cu = *cs.getCU( partitioner.chType ); +#if JVET_O0050_LOCAL_DUAL_TREE + if( cu.predMode == MODE_INTER ) + CHECK( cu.isSepTree(), "CU with Inter mode must be in single tree" ); +#endif const ChromaFormat format = cs.area.chromaFormat;; const int numValidComponents = getNumberValidComponents(format); @@ -7338,7 +7350,11 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa // add an empty TU +#if JVET_O0050_LOCAL_DUAL_TREE + cs.addTU(CS::getArea(cs, cs.area, partitioner.chType), partitioner.chType); +#else cs.addTU(CS::isDualITree(cs) ? cu : cs.area, partitioner.chType); +#endif Distortion distortion = 0; for (int comp = 0; comp < numValidComponents; comp++) diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index 9f501fe5b..a3d0942a6 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -265,6 +265,25 @@ void IntraSearch::init( EncCfg* pcEncCfg, ////////////////////////////////////////////////////////////////////////// // INTRA PREDICTION ////////////////////////////////////////////////////////////////////////// +#if JVET_O0050_LOCAL_DUAL_TREE +#define COST_UNKNOWN (-65536) + +double IntraSearch::findInterCUCost( CodingUnit &cu ) +{ + if( cu.isConsIntra() && !cu.slice->isIntra() ) + { + //search corresponding inter CU cost + for( int i = 0; i < m_numCuInSCIPU; i++ ) + { + if( cu.lumaPos() == m_cuAreaInSCIPU[i].pos() && cu.lumaSize() == m_cuAreaInSCIPU[i].size() ) + { + return m_cuCostInSCIPU[i]; + } + } + } + return COST_UNKNOWN; +} +#endif bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, const double bestCostSoFar, bool mtsCheckRangeFlag, int mtsFirstCheckId, int mtsLastCheckId, bool moreProbMTSIdxFirst ) { @@ -297,6 +316,9 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, LFNSTSaveFlag &= sps.getUseIntraMTS() ? cu.mtsFlag == 0 : true; const uint32_t lfnstIdx = cu.lfnstIdx; +#if JVET_O0050_LOCAL_DUAL_TREE + double costInterCU = findInterCUCost( cu ); +#endif const int width = partitioner.currArea().lwidth(); @@ -916,6 +938,10 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, csBest->slice = cs.slice; csTemp->initStructData(); csBest->initStructData(); +#if JVET_O0050_LOCAL_DUAL_TREE + csTemp->picture = cs.picture; + csBest->picture = cs.picture; +#endif m_bestCostNonMip = MAX_DOUBLE; static_vector<int, FAST_UDI_MAX_RDMODE_NUM> rdModeIdxList; @@ -1086,6 +1112,22 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, } csTemp->releaseIntermediateData(); +#if JVET_O0050_LOCAL_DUAL_TREE + if( cu.isConsIntra() && !cu.slice->isIntra() && csBest->cost != MAX_DOUBLE && costInterCU != COST_UNKNOWN && mode >= 0 ) + { + if( m_pcEncCfg->getIntraPeriod() == -1 ) //For LDB case, the qp22 encoding time worst case is 109% without this fast algorithm + { + break; + } + else + { + if( csBest->cost > costInterCU * 1.5 ) + { + break; + } + } + } +#endif } // Mode loop cu.ispMode = uiBestPUMode.ispMod; @@ -1120,7 +1162,11 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner cs.setDecomp( cs.area.Cb(), false ); double bestCostSoFar = maxCostAllowed; +#if JVET_O0050_LOCAL_DUAL_TREE + bool lumaUsesISP = !cu.isSepTree() && cu.ispMode; +#else bool lumaUsesISP = !CS::isDualITree( *cu.cs ) && cu.ispMode; +#endif PartSplit ispType = lumaUsesISP ? CU::getISPType( cu, COMPONENT_Y ) : TU_NO_ISP; CHECK( cu.ispMode && bestCostSoFar < 0, "bestCostSoFar must be positive!" ); @@ -1147,13 +1193,21 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner saveCS.area.repositionTo( cs.area ); saveCS.clearTUs(); +#if JVET_O0050_LOCAL_DUAL_TREE + if( !cu.isSepTree() && cu.ispMode ) +#else if( !CS::isDualITree( cs ) && cu.ispMode ) +#endif { saveCS.clearCUs(); saveCS.clearPUs(); } +#if JVET_O0050_LOCAL_DUAL_TREE + if( cu.isSepTree() ) +#else if( CS::isDualITree( cs ) ) +#endif { if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) { @@ -1406,8 +1460,13 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner void IntraSearch::IPCMSearch(CodingStructure &cs, Partitioner& partitioner) { +#if JVET_O0050_LOCAL_DUAL_TREE + ComponentID compStr = (partitioner.isSepTree(cs) && !isLuma( partitioner.chType)) ? COMPONENT_Cb : COMPONENT_Y; + ComponentID compEnd = (partitioner.isSepTree(cs) && isLuma( partitioner.chType)) ? COMPONENT_Y : COMPONENT_Cr; +#else ComponentID compStr = (CS::isDualITree(cs) && !isLuma(partitioner.chType)) ? COMPONENT_Cb: COMPONENT_Y; ComponentID compEnd = (CS::isDualITree(cs) && isLuma(partitioner.chType)) ? COMPONENT_Y : COMPONENT_Cr; +#endif for( ComponentID compID = compStr; compID <= compEnd; compID = ComponentID(compID+1) ) { @@ -1460,6 +1519,28 @@ void IntraSearch::xEncPCM(CodingStructure &cs, Partitioner& partitioner, const C } } +#if JVET_O0050_LOCAL_DUAL_TREE +void IntraSearch::saveCuAreaCostInSCIPU( Area area, double cost ) +{ + if( m_numCuInSCIPU < NUM_INTER_CU_INFO_SAVE ) + { + m_cuAreaInSCIPU[m_numCuInSCIPU] = area; + m_cuCostInSCIPU[m_numCuInSCIPU] = cost; + m_numCuInSCIPU++; + } +} + +void IntraSearch::initCuAreaCostInSCIPU() +{ + for( int i = 0; i < NUM_INTER_CU_INFO_SAVE; i++ ) + { + m_cuAreaInSCIPU[i] = Area(); + m_cuCostInSCIPU[i] = 0; + } + m_numCuInSCIPU = 0; +} +#endif + // ------------------------------------------------------------------------------------------------------------------- // Intra search // ------------------------------------------------------------------------------------------------------------------- @@ -2719,8 +2800,12 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio #if JVET_O0105_ICT bool lumaUsesISP = false; +#else +#if JVET_O0050_LOCAL_DUAL_TREE + bool lumaUsesISP = !currTU.cu->isSepTree() && currTU.cu->ispMode; #else bool lumaUsesISP = !CS::isDualITree( cs ) && currTU.cu->ispMode; +#endif #endif uint32_t currDepth = partitioner.currTrDepth; const PPS &pps = *cs.pps; @@ -2740,7 +2825,11 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio saveCS.area.repositionTo( cs.area ); saveCS.initStructData( MAX_INT, false, true ); +#if JVET_O0050_LOCAL_DUAL_TREE + if( !currTU.cu->isSepTree() && currTU.cu->ispMode ) +#else if( !CS::isDualITree( cs ) && currTU.cu->ispMode ) +#endif { saveCS.clearCUs(); CodingUnit& auxCU = saveCS.addCU( *currTU.cu, partitioner.chType ); diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index fd005a552..3b5aa6b16 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -76,6 +76,13 @@ private: CodingStructure **m_pSaveCS; +#if JVET_O0050_LOCAL_DUAL_TREE + bool m_saveCuCostInSCIPU; + uint8_t m_numCuInSCIPU; + Area m_cuAreaInSCIPU[NUM_INTER_CU_INFO_SAVE]; + double m_cuCostInSCIPU[NUM_INTER_CU_INFO_SAVE]; +#endif + struct ModeInfo { bool mipFlg; // CU::mipFlag @@ -148,6 +155,15 @@ public: void setModeCtrl ( EncModeCtrl *modeCtrl ) { m_modeCtrl = modeCtrl; } +#if JVET_O0050_LOCAL_DUAL_TREE + bool getSaveCuCostInSCIPU () { return m_saveCuCostInSCIPU; } + void setSaveCuCostInSCIPU ( bool b ) { m_saveCuCostInSCIPU = b; } + void setNumCuInSCIPU ( uint8_t i ) { m_numCuInSCIPU = i; } + void saveCuAreaCostInSCIPU ( Area area, double cost ); + void initCuAreaCostInSCIPU (); + double findInterCUCost ( CodingUnit &cu ); +#endif + public: bool estIntraPredLumaQT ( CodingUnit &cu, Partitioner& pm, const double bestCostSoFar = MAX_DOUBLE, bool mtsCheckRangeFlag = false, int mtsFirstCheckId = 0, int mtsLastCheckId = 0, bool moreProbMTSIdxFirst = false ); -- GitLab