diff --git a/source/Lib/CommonLib/Buffer.cpp b/source/Lib/CommonLib/Buffer.cpp index f245bff72d8aa2a3ebe80d1569707cdaf63a5b7d..4fbd8c9dda66b96520b058067327872460cabd16 100644 --- a/source/Lib/CommonLib/Buffer.cpp +++ b/source/Lib/CommonLib/Buffer.cpp @@ -389,12 +389,14 @@ void AreaBuf<Pel>::rspSignal(std::vector<Pel>& pLUT) { Pel* dst = buf; Pel* src = buf; +#if !JVET_M0102_INTRA_SUBPARTITIONS if (width == 1) { THROW("Blocks of width = 1 not supported"); } else { +#endif for (unsigned y = 0; y < height; y++) { for (unsigned x = 0; x < width; x++) @@ -404,7 +406,9 @@ void AreaBuf<Pel>::rspSignal(std::vector<Pel>& pLUT) dst += stride; src += stride; } +#if !JVET_M0102_INTRA_SUBPARTITIONS } +#endif } template<> @@ -456,13 +460,14 @@ template<> Pel AreaBuf <Pel> ::computeAvg() const { const Pel* src = buf; - +#if !JVET_M0102_INTRA_SUBPARTITIONS if (width == 1) { THROW("Blocks of width = 1 not supported"); } else { +#endif int32_t acc = 0; #define AVG_INC \ src += stride; @@ -471,7 +476,9 @@ Pel AreaBuf <Pel> ::computeAvg() const #undef AVG_INC #undef AVG_OP return Pel((acc + (area() >> 1)) / area()); +#if !JVET_M0102_INTRA_SUBPARTITIONS } +#endif } #endif diff --git a/source/Lib/CommonLib/CodingStatistics.h b/source/Lib/CommonLib/CodingStatistics.h index 748138fdf7a5339d69a21cab167088f17ac5e40c..22a9449c3d448cac60ed25adec4ce86f3f38190b 100644 --- a/source/Lib/CommonLib/CodingStatistics.h +++ b/source/Lib/CommonLib/CodingStatistics.h @@ -68,6 +68,10 @@ enum CodingStatisticsType STATS__CABAC_BITS__MVD_EP, STATS__CABAC_BITS__AFFINE_FLAG, STATS__CABAC_BITS__AFFINE_TYPE, +#if JVET_M0102_INTRA_SUBPARTITIONS + STATS__CABAC_BITS__ISP_MODE_FLAG, + STATS__CABAC_BITS__ISP_SPLIT_FLAG, +#endif STATS__CABAC_BITS__TRANSFORM_SUBDIV_FLAG, STATS__CABAC_BITS__QT_ROOT_CBF, STATS__CABAC_BITS__DELTA_QP_EP, @@ -150,6 +154,10 @@ static inline const char* getName(CodingStatisticsType name) "CABAC_BITS__MVD_EP", "CABAC_BITS__AFFINE_FLAG", "CABAC_BITS__AFFINE_TYPE", +#if JVET_M0102_INTRA_SUBPARTITIONS + "CABAC_BITS__ISP_MODE_FLAG", + "CABAC_BITS__ISP_SPLIT_FLAG", +#endif "CABAC_BITS__TRANSFORM_SUBDIV_FLAG", "CABAC_BITS__QT_ROOT_CBF", "CABAC_BITS__DELTA_QP_EP", diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp index 829a7eeaca528e622d36c7cfb99671cbcd3032ee..76aea6cf4d7b188d1ca2640710cecad749057901 100644 --- a/source/Lib/CommonLib/CodingStructure.cpp +++ b/source/Lib/CommonLib/CodingStructure.cpp @@ -259,7 +259,11 @@ const PredictionUnit * CodingStructure::getPU( const Position &pos, const Channe } } +#if JVET_M0102_INTRA_SUBPARTITIONS +TransformUnit* CodingStructure::getTU( const Position &pos, const ChannelType effChType, const int subTuIdx ) +#else TransformUnit* CodingStructure::getTU( const Position &pos, const ChannelType effChType ) +#endif { const CompArea &_blk = area.blocks[effChType]; @@ -272,13 +276,45 @@ TransformUnit* CodingStructure::getTU( const Position &pos, const ChannelType ef { const unsigned idx = m_tuIdx[effChType][rsAddr( pos, _blk.pos(), _blk.width, unitScale[effChType] )]; +#if JVET_M0102_INTRA_SUBPARTITIONS + if( idx != 0 ) + { + unsigned extraIdx = 0; + if( isLuma( effChType ) ) + { + const TransformUnit& tu = *tus[idx - 1]; + + if( tu.cu->ispMode ) // Intra SubPartitions mode + { + //we obtain the offset to index the corresponding sub-partition + if( subTuIdx != -1 ) + { + extraIdx = subTuIdx; + } + else + { + while( pos != tus[idx - 1 + extraIdx]->blocks[getFirstComponentOfChannel( effChType )].pos() ) + { + extraIdx++; + } + } + } + } + return tus[idx - 1 + extraIdx]; + } +#else if( idx != 0 ) return tus[ idx - 1 ]; +#endif else if( m_isTuEnc ) return parent->getTU( pos, effChType ); else return nullptr; } } +#if JVET_M0102_INTRA_SUBPARTITIONS +const TransformUnit * CodingStructure::getTU( const Position &pos, const ChannelType effChType, const int subTuIdx ) const +#else const TransformUnit * CodingStructure::getTU( const Position &pos, const ChannelType effChType ) const +#endif { const CompArea &_blk = area.blocks[effChType]; @@ -290,8 +326,34 @@ const TransformUnit * CodingStructure::getTU( const Position &pos, const Channel else { const unsigned idx = m_tuIdx[effChType][rsAddr( pos, _blk.pos(), _blk.width, unitScale[effChType] )]; - +#if JVET_M0102_INTRA_SUBPARTITIONS + if( idx != 0 ) + { + unsigned extraIdx = 0; + if( isLuma( effChType ) ) + { + const TransformUnit& tu = *tus[idx - 1]; + if( tu.cu->ispMode ) // Intra SubPartitions mode + { + //we obtain the offset to index the corresponding sub-partition + if( subTuIdx != -1 ) + { + extraIdx = subTuIdx; + } + else + { + while( pos != tus[idx - 1 + extraIdx]->blocks[effChType].pos() ) + { + extraIdx++; + } + } + } + } + return tus[idx - 1 + extraIdx]; + } +#else if( idx != 0 ) return tus[idx - 1]; +#endif else if( m_isTuEnc ) return parent->getTU( pos, effChType ); else return nullptr; } @@ -418,6 +480,9 @@ TransformUnit& CodingStructure::addTU( const UnitArea &unit, const ChannelType c tu->UnitArea::operator=( unit ); tu->initData(); tu->next = nullptr; +#if JVET_M0102_INTRA_SUBPARTITIONS + tu->prev = nullptr; +#endif tu->cs = this; tu->cu = m_isTuEnc ? cus[0] : getCU( unit.blocks[chType].pos(), chType ); tu->chType = chType; @@ -433,6 +498,9 @@ TransformUnit& CodingStructure::addTU( const UnitArea &unit, const ChannelType c if( prevTU && prevTU->cu == tu->cu ) { prevTU->next = tu; +#if JVET_M0102_INTRA_SUBPARTITIONS + tu->prev = prevTU; +#endif #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM CHECK( prevTU->cacheId != tu->cacheId, "Inconsintent cacheId between previous and current TU" ); @@ -470,11 +538,25 @@ TransformUnit& CodingStructure::addTU( const UnitArea &unit, const ChannelType c const CompArea &_selfBlk = area.blocks[i]; const CompArea &_blk = tu-> blocks[i]; +#if JVET_M0102_INTRA_SUBPARTITIONS + bool isIspTu = tu->cu != nullptr && tu->cu->ispMode && isLuma( _blk.compID ); + + bool isFirstIspTu = false; + if( isIspTu ) + { + isFirstIspTu = CU::isISPFirst( *tu->cu, _blk, getFirstComponentOfChannel( ChannelType( i ) ) ); + } + if( !isIspTu || isFirstIspTu ) +#endif { const UnitScale& scale = unitScale[_blk.compID]; const Area scaledSelf = scale.scale( _selfBlk ); +#if JVET_M0102_INTRA_SUBPARTITIONS + const Area scaledBlk = isIspTu ? scale.scale( tu->cu->blocks[i] ) : scale.scale( _blk ); +#else const Area scaledBlk = scale.scale( _blk ); +#endif unsigned *idxPtr = m_tuIdx[i] + rsAddr( scaledBlk.pos(), scaledSelf.pos(), scaledSelf.width ); CHECK( *idxPtr, "Overwriting a pre-existing value, should be '0'!" ); AreaBuf<uint32_t>( idxPtr, scaledSelf.width, scaledBlk.size() ).fill( idx ); @@ -1000,6 +1082,9 @@ void CodingStructure::initStructData( const int &QP, const bool &_isLosses, cons fracBits = 0; dist = 0; cost = MAX_DOUBLE; +#if JVET_M0102_INTRA_SUBPARTITIONS + lumaCost = MAX_DOUBLE; +#endif interHad = std::numeric_limits<Distortion>::max(); } diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h index d7ab5422b8becd4f5060b0e840f150e1825a079b..f28500a798c9a02ea29c2f58e19501540d80f94a 100644 --- a/source/Lib/CommonLib/CodingStructure.h +++ b/source/Lib/CommonLib/CodingStructure.h @@ -129,11 +129,19 @@ public: const CodingUnit *getCU(const Position &pos, const ChannelType _chType) const; const PredictionUnit *getPU(const Position &pos, const ChannelType _chType) const; +#if JVET_M0102_INTRA_SUBPARTITIONS + const TransformUnit *getTU(const Position &pos, const ChannelType _chType, const int subTuIdx = -1) const; +#else const TransformUnit *getTU(const Position &pos, const ChannelType _chType) const; +#endif CodingUnit *getCU(const Position &pos, const ChannelType _chType); PredictionUnit *getPU(const Position &pos, const ChannelType _chType); +#if JVET_M0102_INTRA_SUBPARTITIONS + TransformUnit *getTU(const Position &pos, const ChannelType _chType, const int subTuIdx = -1); +#else TransformUnit *getTU(const Position &pos, const ChannelType _chType); +#endif const CodingUnit *getCU(const ChannelType &_chType) const { return getCU(area.blocks[_chType].pos(), _chType); } const PredictionUnit *getPU(const ChannelType &_chType) const { return getPU(area.blocks[_chType].pos(), _chType); } @@ -171,6 +179,9 @@ public: static_vector<double, NUM_ENC_FEATURES> features; double cost; +#if JVET_M0102_INTRA_SUBPARTITIONS + double lumaCost; +#endif uint64_t fracBits; Distortion dist; Distortion interHad; diff --git a/source/Lib/CommonLib/Common.h b/source/Lib/CommonLib/Common.h index 24746baad3be0895fd1ae962155c4fdbc17bccc4..81c92278b2bd60a59c558424bcdbedf0f1defb5b 100644 --- a/source/Lib/CommonLib/Common.h +++ b/source/Lib/CommonLib/Common.h @@ -72,6 +72,9 @@ struct Size bool operator!=(const Size &other) const { return (width != other.width) || (height != other.height); } bool operator==(const Size &other) const { return (width == other.width) && (height == other.height); } uint32_t area() const { return (uint32_t) width * (uint32_t) height; } +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + void resizeTo(const Size newSize) { width = newSize.width; height = newSize.height; } +#endif }; struct Area : public Position, public Size diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp index 1da885ebc8d7e4e341d93a709d796cca6cbb9921..2f75ce0a3759ed2f93c5643cf59cb26d191fe0e0 100644 --- a/source/Lib/CommonLib/ContextModelling.cpp +++ b/source/Lib/CommonLib/ContextModelling.cpp @@ -50,8 +50,13 @@ CoeffCodingContext::CoeffCodingContext(const TransformUnit& tu, ComponentID comp , m_chType (toChannelType(m_compID)) , m_width (tu.block(m_compID).width) , m_height (tu.block(m_compID).height) +#if JVET_M0102_INTRA_SUBPARTITIONS + , m_log2CGWidth ( g_log2SbbSize[m_chType][ g_aucLog2[m_width] ][ g_aucLog2[m_height] ][0] ) + , m_log2CGHeight ( g_log2SbbSize[m_chType][ g_aucLog2[m_width] ][ g_aucLog2[m_height] ][1] ) +#else , m_log2CGWidth ((m_width & 3) || (m_height & 3) ? 1 : 2) , m_log2CGHeight ((m_width & 3) || (m_height & 3) ? 1 : 2) +#endif , m_log2CGSize (m_log2CGWidth + m_log2CGHeight) #if JVET_M0257 , m_widthInGroups(std::min<unsigned>(JVET_C0024_ZERO_OUT_TH, m_width) >> m_log2CGWidth) @@ -74,10 +79,17 @@ CoeffCodingContext::CoeffCodingContext(const TransformUnit& tu, ComponentID comp #else , m_scanType (SCAN_DIAG) #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + , m_scan (g_scanOrder [m_chType][SCAN_GROUPED_4x4][m_scanType][gp_sizeIdxInfo->idxFrom(m_width )][gp_sizeIdxInfo->idxFrom(m_height )]) + , m_scanPosX (g_scanOrderPosXY[m_chType][SCAN_GROUPED_4x4][m_scanType][gp_sizeIdxInfo->idxFrom(m_width )][gp_sizeIdxInfo->idxFrom(m_height )][0]) + , m_scanPosY (g_scanOrderPosXY[m_chType][SCAN_GROUPED_4x4][m_scanType][gp_sizeIdxInfo->idxFrom(m_width )][gp_sizeIdxInfo->idxFrom(m_height )][1]) + , m_scanCG (g_scanOrder [m_chType][SCAN_UNGROUPED ][m_scanType][gp_sizeIdxInfo->idxFrom(m_widthInGroups)][gp_sizeIdxInfo->idxFrom(m_heightInGroups)]) +#else , m_scan (g_scanOrder [SCAN_GROUPED_4x4][m_scanType][gp_sizeIdxInfo->idxFrom(m_width )][gp_sizeIdxInfo->idxFrom(m_height )]) , m_scanPosX (g_scanOrderPosXY[SCAN_GROUPED_4x4][m_scanType][gp_sizeIdxInfo->idxFrom(m_width )][gp_sizeIdxInfo->idxFrom(m_height )][0]) , m_scanPosY (g_scanOrderPosXY[SCAN_GROUPED_4x4][m_scanType][gp_sizeIdxInfo->idxFrom(m_width )][gp_sizeIdxInfo->idxFrom(m_height )][1]) , m_scanCG (g_scanOrder[SCAN_UNGROUPED ][m_scanType][gp_sizeIdxInfo->idxFrom(m_widthInGroups)][gp_sizeIdxInfo->idxFrom(m_heightInGroups)]) +#endif , m_CtxSetLastX (Ctx::LastX[m_chType]) , m_CtxSetLastY (Ctx::LastY[m_chType]) #if JVET_M0257 @@ -314,8 +326,17 @@ unsigned DeriveCtx::CtxCUsplit( const CodingStructure& cs, Partitioner& partitio } #endif +#if JVET_M0102_INTRA_SUBPARTITIONS +unsigned DeriveCtx::CtxQtCbf( const ComponentID compID, const unsigned trDepth, const bool prevCbCbf, const int ispIdx ) +{ + if( ispIdx && isLuma( compID ) ) + { + return 2 + (int)prevCbCbf; + } +#else unsigned DeriveCtx::CtxQtCbf( const ComponentID compID, const unsigned trDepth, const bool prevCbCbf ) { +#endif if( compID == COMPONENT_Cr ) { return ( prevCbCbf ? 1 : 0 ); diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h index 4f2c0d90327606deffffdf26773083927762a763..90ca2477514aed8a76d6d4ec8d3c8bb11c79eb21 100644 --- a/source/Lib/CommonLib/ContextModelling.h +++ b/source/Lib/CommonLib/ContextModelling.h @@ -308,7 +308,11 @@ void CtxSplit ( const CodingStructure& cs, Partitioner& partitioner, uns unsigned CtxCUsplit ( const CodingStructure& cs, Partitioner& partitioner ); unsigned CtxBTsplit ( const CodingStructure& cs, Partitioner& partitioner ); #endif +#if JVET_M0102_INTRA_SUBPARTITIONS +unsigned CtxQtCbf ( const ComponentID compID, const unsigned trDepth, const bool prevCbCbf = false, const int ispIdx = 0 ); +#else unsigned CtxQtCbf ( const ComponentID compID, const unsigned trDepth, const bool prevCbCbf ); +#endif unsigned CtxInterDir ( const PredictionUnit& pu ); unsigned CtxSkipFlag ( const CodingUnit& cu ); unsigned CtxIMVFlag ( const CodingUnit& cu ); diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index 78fcd14f01e7e5cb8b622f2ebba26d84678d037f..72c26adcc6b40c338d30e036a24ca7f237ecd4be 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -745,6 +745,24 @@ const CtxSet ContextSetCfg::QtRootCbf = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::QtCbf[] = { +#if JVET_M0102_INTRA_SUBPARTITIONS +#if JVET_M0453_CABAC_ENGINE + ContextSetCfg::addCtxSet + ({ + { 155, 127, CNU, CNU}, + { 141, 127, CNU, CNU}, + { CNU, 126, CNU, CNU}, + { 4, 5, DWS, DWS}, + }), +#else + ContextSetCfg::addCtxSet + ({ + { 140, 141, CNU, CNU}, + { 155, 127, CNU, CNU}, + { CNU, 126, CNU, CNU}, + }), +#endif +#else ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE @@ -758,6 +776,7 @@ const CtxSet ContextSetCfg::QtCbf[] = { CNU, 126, }, #endif }), +#endif ContextSetCfg::addCtxSet ({ #if JVET_M0453_CABAC_ENGINE @@ -1208,6 +1227,18 @@ const CtxSet ContextSetCfg::EMTCuFlag = ContextSetCfg::addCtxSet }); #endif +#if JVET_M0102_INTRA_SUBPARTITIONS +const CtxSet ContextSetCfg::ISPMode = ContextSetCfg::addCtxSet +({ + { CNU, CNU }, + { CNU, CNU }, + { CNU, CNU }, +#if JVET_M0453_CABAC_ENGINE + { DWS, DWS }, +#endif +}); +#endif + const CtxSet ContextSetCfg::CrossCompPred = ContextSetCfg::addCtxSet ({ { 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,}, diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index fcc59f0152a14eddf03460f23822adff43834592..c3f5dc50599288223ca2cc560f1250c80046fb28 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -306,6 +306,9 @@ public: static const CtxSet TriangleIdx; #if JVET_M0444_SMVD static const CtxSet SmvdFlag; +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + static const CtxSet ISPMode; #endif static const unsigned NumberOfContexts; diff --git a/source/Lib/CommonLib/DepQuant.cpp b/source/Lib/CommonLib/DepQuant.cpp index 29794986be8be56f00e4cfa77112c363d0641fe7..b50575d4089947065b4264e2c3af08bb25783fd3 100644 --- a/source/Lib/CommonLib/DepQuant.cpp +++ b/source/Lib/CommonLib/DepQuant.cpp @@ -128,8 +128,13 @@ namespace DQIntern Rom() : m_scansInitialized(false) {} ~Rom() { xUninitScanArrays(); } void init () { xInitScanArrays(); } +#if JVET_M0102_INTRA_SUBPARTITIONS + const NbInfoSbb* getNbInfoSbb( int hd, int vd, int ch ) const { return m_scanId2NbInfoSbbArray[hd][vd][ch]; } + const NbInfoOut* getNbInfoOut( int hd, int vd, int ch ) const { return m_scanId2NbInfoOutArray[hd][vd][ch]; } +#else const NbInfoSbb* getNbInfoSbb( int hd, int vd ) const { return m_scanId2NbInfoSbbArray[hd][vd]; } const NbInfoOut* getNbInfoOut( int hd, int vd ) const { return m_scanId2NbInfoOutArray[hd][vd]; } +#endif const TUParameters* getTUPars ( const CompArea& area, const ComponentID compID ) const { return m_tuParameters[g_aucLog2[area.width]][g_aucLog2[area.height]][toChannelType(compID)]; @@ -139,8 +144,13 @@ namespace DQIntern void xUninitScanArrays (); private: bool m_scansInitialized; +#if JVET_M0102_INTRA_SUBPARTITIONS + NbInfoSbb* m_scanId2NbInfoSbbArray[ MAX_CU_DEPTH+1 ][ MAX_CU_DEPTH+1 ][ MAX_NUM_CHANNEL_TYPE ]; + NbInfoOut* m_scanId2NbInfoOutArray[ MAX_CU_DEPTH+1 ][ MAX_CU_DEPTH+1 ][ MAX_NUM_CHANNEL_TYPE ]; +#else NbInfoSbb* m_scanId2NbInfoSbbArray[ MAX_CU_DEPTH+1 ][ MAX_CU_DEPTH+1 ]; NbInfoOut* m_scanId2NbInfoOutArray[ MAX_CU_DEPTH+1 ][ MAX_CU_DEPTH+1 ]; +#endif TUParameters* m_tuParameters [ MAX_CU_DEPTH+1 ][ MAX_CU_DEPTH+1 ][ MAX_NUM_CHANNEL_TYPE ]; }; @@ -156,26 +166,52 @@ namespace DQIntern uint32_t raster2id[ MAX_CU_SIZE * MAX_CU_SIZE ]; +#if JVET_M0102_INTRA_SUBPARTITIONS + for( int ch = 0; ch < MAX_NUM_CHANNEL_TYPE; ch++ ) + { + for( int hd = 0; hd <= MAX_CU_DEPTH; hd++ ) + { + for( int vd = 0; vd <= MAX_CU_DEPTH; vd++ ) + { + if( (hd == 0 && vd <= 1) || (hd <= 1 && vd == 0) ) + { + continue; + } +#else for( int hd = 1; hd <= MAX_CU_DEPTH; hd++ ) { for( int vd = 1; vd <= MAX_CU_DEPTH; vd++ ) { +#endif const uint32_t blockWidth = (1 << hd); const uint32_t blockHeight = (1 << vd); const uint32_t totalValues = blockWidth * blockHeight; +#if JVET_M0102_INTRA_SUBPARTITIONS + const uint32_t log2CGWidth = g_log2SbbSize[ch][hd][vd][0]; + const uint32_t log2CGHeight = g_log2SbbSize[ch][hd][vd][1]; +#else const uint32_t log2CGWidth = (blockWidth & 3) + (blockHeight & 3) > 0 ? 1 : 2; const uint32_t log2CGHeight = (blockWidth & 3) + (blockHeight & 3) > 0 ? 1 : 2; +#endif const uint32_t groupWidth = 1 << log2CGWidth; const uint32_t groupHeight = 1 << log2CGHeight; const uint32_t groupSize = groupWidth * groupHeight; const CoeffScanType scanType = SCAN_DIAG; const SizeType blkWidthIdx = gp_sizeIdxInfo->idxFrom( blockWidth ); const SizeType blkHeightIdx = gp_sizeIdxInfo->idxFrom( blockHeight ); +#if JVET_M0102_INTRA_SUBPARTITIONS + const uint32_t* scanId2RP = g_scanOrder [ch][SCAN_GROUPED_4x4][scanType][blkWidthIdx][blkHeightIdx]; + const uint32_t* scanId2X = g_scanOrderPosXY[ch][SCAN_GROUPED_4x4][scanType][blkWidthIdx][blkHeightIdx][0]; + const uint32_t* scanId2Y = g_scanOrderPosXY[ch][SCAN_GROUPED_4x4][scanType][blkWidthIdx][blkHeightIdx][1]; + NbInfoSbb*& sId2NbSbb = m_scanId2NbInfoSbbArray[hd][vd][ch]; + NbInfoOut*& sId2NbOut = m_scanId2NbInfoOutArray[hd][vd][ch]; +#else const uint32_t* scanId2RP = g_scanOrder [SCAN_GROUPED_4x4][scanType][blkWidthIdx][blkHeightIdx]; const uint32_t* scanId2X = g_scanOrderPosXY[SCAN_GROUPED_4x4][scanType][blkWidthIdx][blkHeightIdx][0]; const uint32_t* scanId2Y = g_scanOrderPosXY[SCAN_GROUPED_4x4][scanType][blkWidthIdx][blkHeightIdx][1]; NbInfoSbb*& sId2NbSbb = m_scanId2NbInfoSbbArray[hd][vd]; NbInfoOut*& sId2NbOut = m_scanId2NbInfoOutArray[hd][vd]; +#endif sId2NbSbb = new NbInfoSbb[ totalValues ]; sId2NbOut = new NbInfoOut[ totalValues ]; @@ -276,12 +312,19 @@ namespace DQIntern nbOut.maxDist -= scanId; } +#if JVET_M0102_INTRA_SUBPARTITIONS + m_tuParameters[hd][vd][ch] = new TUParameters( *this, blockWidth, blockHeight, ChannelType(ch) ); +#else for( int chId = 0; chId < MAX_NUM_CHANNEL_TYPE; chId++ ) { m_tuParameters[hd][vd][chId] = new TUParameters( *this, blockWidth, blockHeight, ChannelType(chId) ); } +#endif } } +#if JVET_M0102_INTRA_SUBPARTITIONS + } +#endif m_scansInitialized = true; } @@ -291,6 +334,32 @@ namespace DQIntern { return; } +#if JVET_M0102_INTRA_SUBPARTITIONS + for( int hd = 0; hd <= MAX_CU_DEPTH; hd++ ) + { + for( int vd = 0; vd <= MAX_CU_DEPTH; vd++ ) + { + for( int ch = 0; ch < 2; ch++ ) + { + NbInfoSbb*& sId2NbSbb = m_scanId2NbInfoSbbArray[hd][vd][ch]; + NbInfoOut*& sId2NbOut = m_scanId2NbInfoOutArray[hd][vd][ch]; + TUParameters*& tuPars = m_tuParameters [hd][vd][ch]; + if( sId2NbSbb ) + { + delete [] sId2NbSbb; + } + if( sId2NbOut ) + { + delete [] sId2NbOut; + } + if( tuPars ) + { + delete tuPars; + } + } + } + } +#else for( int hd = 0; hd <= MAX_CU_DEPTH; hd++ ) { for( int vd = 0; vd <= MAX_CU_DEPTH; vd++ ) @@ -315,6 +384,7 @@ namespace DQIntern } } } +#endif m_scansInitialized = false; } @@ -328,9 +398,14 @@ namespace DQIntern m_width = width; m_height = height; m_numCoeff = m_width * m_height; +#if JVET_M0102_INTRA_SUBPARTITIONS + m_log2SbbWidth = g_log2SbbSize[m_chType][ g_aucLog2[m_width] ][ g_aucLog2[m_height] ][0]; + m_log2SbbHeight = g_log2SbbSize[m_chType][ g_aucLog2[m_width] ][ g_aucLog2[m_height] ][1]; +#else const bool no4x4 = ( ( m_width & 3 ) != 0 || ( m_height & 3 ) != 0 ); m_log2SbbWidth = ( no4x4 ? 1 : 2 ); m_log2SbbHeight = ( no4x4 ? 1 : 2 ); +#endif m_log2SbbSize = m_log2SbbWidth + m_log2SbbHeight; m_sbbSize = ( 1 << m_log2SbbSize ); m_sbbMask = m_sbbSize - 1; @@ -352,6 +427,16 @@ namespace DQIntern SizeType vsbb = gp_sizeIdxInfo->idxFrom( m_heightInSbb ); SizeType hsId = gp_sizeIdxInfo->idxFrom( m_width ); SizeType vsId = gp_sizeIdxInfo->idxFrom( m_height ); +#if JVET_M0102_INTRA_SUBPARTITIONS + m_scanSbbId2SbbPos = g_scanOrder [ chType ][ SCAN_UNGROUPED ][ m_scanType ][ hsbb ][ vsbb ]; + m_scanId2BlkPos = g_scanOrder [ chType ][ SCAN_GROUPED_4x4 ][ m_scanType ][ hsId ][ vsId ]; + m_scanId2PosX = g_scanOrderPosXY[ chType ][ SCAN_GROUPED_4x4 ][ m_scanType ][ hsId ][ vsId ][ 0 ]; + m_scanId2PosY = g_scanOrderPosXY[ chType ][ SCAN_GROUPED_4x4 ][ m_scanType ][ hsId ][ vsId ][ 1 ]; + int log2W = g_aucLog2[ m_width ]; + int log2H = g_aucLog2[ m_height ]; + m_scanId2NbInfoSbb = rom.getNbInfoSbb( log2W, log2H, chType ); + m_scanId2NbInfoOut = rom.getNbInfoOut( log2W, log2H, chType ); +#else m_scanSbbId2SbbPos = g_scanOrder [ SCAN_UNGROUPED ][ m_scanType ][ hsbb ][ vsbb ]; m_scanId2BlkPos = g_scanOrder [ SCAN_GROUPED_4x4 ][ m_scanType ][ hsId ][ vsId ]; m_scanId2PosX = g_scanOrderPosXY[ SCAN_GROUPED_4x4 ][ m_scanType ][ hsId ][ vsId ][ 0 ]; @@ -360,6 +445,7 @@ namespace DQIntern int log2H = g_aucLog2[ m_height ]; m_scanId2NbInfoSbb = rom.getNbInfoSbb( log2W, log2H ); m_scanId2NbInfoOut = rom.getNbInfoOut( log2W, log2H ); +#endif m_scanInfo = new ScanInfo[ m_numCoeff ]; for( int scanIdx = 0; scanIdx < m_numCoeff; scanIdx++ ) { @@ -473,8 +559,44 @@ namespace DQIntern } else { +#if JVET_M0102_INTRA_SUBPARTITIONS + BinFracBits bits; + bool prevLumaCbf = false; + bool lastCbfIsInferred = false; + bool useIntraSubPartitions = tu.cu->ispMode && isLuma(chType); + if( useIntraSubPartitions ) + { + bool rootCbfSoFar = false; + bool isLastSubPartition = CU::isISPLast(*tu.cu, tu.Y(), compID); + uint32_t nTus = tu.cu->ispMode == HOR_INTRA_SUBPARTITIONS ? tu.cu->lheight() >> g_aucLog2[tu.lheight()] : tu.cu->lwidth() >> g_aucLog2[tu.lwidth()]; + if( isLastSubPartition ) + { + TransformUnit* tuPointer = tu.cu->firstTU; + for( int tuIdx = 0; tuIdx < nTus - 1; tuIdx++ ) + { + rootCbfSoFar |= TU::getCbfAtDepth(*tuPointer, COMPONENT_Y, tu.depth); + tuPointer = tuPointer->next; + } + if( !rootCbfSoFar ) + { + lastCbfIsInferred = true; + } + } + if( !lastCbfIsInferred ) + { + prevLumaCbf = TU::getPrevTuCbfAtDepth(tu, compID, tu.depth); + } + bits = fracBitsAccess.getFracBitsArray(Ctx::QtCbf[compID](DeriveCtx::CtxQtCbf(compID, tu.depth, prevLumaCbf, true))); + } + else + { + bits = fracBitsAccess.getFracBitsArray(Ctx::QtCbf[compID](DeriveCtx::CtxQtCbf(compID, tu.depth, tu.cbf[COMPONENT_Cb]))); + } + cbfDeltaBits = lastCbfIsInferred ? 0 : int32_t(bits.intBits[1]) - int32_t(bits.intBits[0]); +#else BinFracBits bits = fracBitsAccess.getFracBitsArray( Ctx::QtCbf[compID]( DeriveCtx::CtxQtCbf( compID, tu.depth, tu.cbf[COMPONENT_Cb] ) ) ); cbfDeltaBits = int32_t( bits.intBits[1] ) - int32_t( bits.intBits[0] ); +#endif } static const unsigned prefixCtx[] = { 0, 0, 0, 3, 6, 10, 15, 21 }; @@ -717,7 +839,11 @@ namespace DQIntern #else const CoeffScanType scanType = SCAN_DIAG; #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + const unsigned* scan = g_scanOrder[ toChannelType(compID) ][ SCAN_GROUPED_4x4 ][ scanType ][ hsId ][ vsId ]; +#else const unsigned* scan = g_scanOrder[ SCAN_GROUPED_4x4 ][ scanType ][ hsId ][ vsId ]; +#endif const TCoeff* qCoeff = tu.getCoeffs( compID ).buf; TCoeff* tCoeff = recCoeff.buf; diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp index d48ef851161b2a354022ccf6544e5bc48159de3c..c5ee314a9d48aa61680b64b207c1ddd3e4abbc5e 100644 --- a/source/Lib/CommonLib/IntraPrediction.cpp +++ b/source/Lib/CommonLib/IntraPrediction.cpp @@ -299,6 +299,9 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co const ChannelType channelType = toChannelType( compID ); const int iWidth = piPred.width; const int iHeight = piPred.height; +#if JVET_M0102_INTRA_SUBPARTITIONS + const Size cuSize = Size( pu.cu->blocks[compId].width, pu.cu->blocks[compId].height ); +#endif const uint32_t uiDirMode = PU::getFinalIntraMode( pu, channelType ); @@ -306,8 +309,14 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co CHECK( g_aucLog2[iWidth] > 7, "Size not allowed" ); const int multiRefIdx = (compID == COMPONENT_Y) ? pu.multiRefIdx : 0; +#if JVET_M0102_INTRA_SUBPARTITIONS + const bool useISP = pu.cu->ispMode && isLuma( compID ); + const int whRatio = useISP ? std::max( unsigned( 1 ), cuSize.width / cuSize.height ) : std::max( unsigned( 1 ), cuSize.width / cuSize.height ); + const int hwRatio = useISP ? std::max( unsigned( 1 ), cuSize.height / cuSize.width ) : std::max( unsigned( 1 ), cuSize.height / cuSize.width ); +#else int whRatio = std::max(1, iWidth / iHeight); int hwRatio = std::max(1, iHeight / iWidth); +#endif const int srcStride = m_topRefLength + 1 + (whRatio + 1) * multiRefIdx; const int srcHStride = m_leftRefLength + 1 + (hwRatio + 1) * multiRefIdx; @@ -323,18 +332,30 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co case(VDIA_IDX): if (getWideAngle(iWidth, iHeight, uiDirMode) == static_cast<int>(uiDirMode)) // check if uiDirMode is not wide-angle { +#if JVET_M0102_INTRA_SUBPARTITIONS + xPredIntraAng(CPelBuf(ptrSrc, srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps, multiRefIdx, useFilteredPredSamples, useISP, cuSize ); +#else xPredIntraAng(CPelBuf(ptrSrc, srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps , multiRefIdx , useFilteredPredSamples); +#endif break; } +#if JVET_M0102_INTRA_SUBPARTITIONS + default: xPredIntraAng(CPelBuf(getPredictorPtr(compID, false), srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps, multiRefIdx, useFilteredPredSamples, useISP, cuSize); break; +#else default: xPredIntraAng(CPelBuf(getPredictorPtr(compID, false), srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps , multiRefIdx , useFilteredPredSamples); break; +#endif } bool pdpcCondition = (uiDirMode == PLANAR_IDX || uiDirMode == DC_IDX || uiDirMode == HOR_IDX || uiDirMode == VER_IDX); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( pdpcCondition && multiRefIdx == 0 && !useISP ) +#else if (pdpcCondition && multiRefIdx == 0) +#endif { const CPelBuf srcBuf = CPelBuf(ptrSrc, srcStride, srcStride); PelBuf dstBuf = piPred; @@ -445,11 +466,20 @@ void IntraPrediction::xPredIntraPlanar( const CPelBuf &pSrc, PelBuf &pDst, const { const uint32_t width = pDst.width; const uint32_t height = pDst.height; +#if JVET_M0102_INTRA_SUBPARTITIONS + const uint32_t log2W = g_aucLog2[width < 2 ? 2 : width]; + const uint32_t log2H = g_aucLog2[height < 2 ? 2 : height]; +#else const uint32_t log2W = g_aucLog2[ width ]; const uint32_t log2H = g_aucLog2[ height ]; +#endif int leftColumn[MAX_CU_SIZE + 1], topRow[MAX_CU_SIZE + 1], bottomRow[MAX_CU_SIZE], rightColumn[MAX_CU_SIZE]; +#if JVET_M0102_INTRA_SUBPARTITIONS + const uint32_t offset = 1 << (log2W + log2H); +#else const uint32_t offset = width * height; +#endif // Get left and above reference column and row for( int k = 0; k < width + 1; k++ ) @@ -561,17 +591,28 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch , int multiRefIdx , const bool enableBoundaryFilter ) #else +#if JVET_M0102_INTRA_SUBPARTITIONS +void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps, + int multiRefIdx, + const bool useFilteredPredSamples , + const bool useISP, + const Size cuSize ) +#else void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps , int multiRefIdx , const bool useFilteredPredSamples ) #endif +#endif { int width =int(pDst.width); int height=int(pDst.height); CHECK( !( dirMode > DC_IDX && dirMode < NUM_LUMA_MODE ), "Invalid intra dir" ); - +#if JVET_M0102_INTRA_SUBPARTITIONS + int predMode = useISP ? getWideAngle( cuSize.width, cuSize.height, dirMode ) : getWideAngle( cuSize.width, cuSize.height, dirMode ); +#else int predMode = getWideAngle(width, height, dirMode); +#endif const bool bIsModeVer = predMode >= DIA_IDX; const int intraPredAngleMode = (bIsModeVer) ? predMode - VER_IDX : -(predMode - HOR_IDX); const int absAngMode = abs(intraPredAngleMode); @@ -595,8 +636,13 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch Pel refAbove[2 * MAX_CU_SIZE + 3 + 33 * MAX_REF_LINE_IDX]; Pel refLeft [2 * MAX_CU_SIZE + 3 + 33 * MAX_REF_LINE_IDX]; +#if JVET_M0102_INTRA_SUBPARTITIONS + const int whRatio = useISP ? std::max( unsigned( 1 ), cuSize.width / cuSize.height ) : std::max( unsigned( 1 ), cuSize.width / cuSize.height ); + const int hwRatio = useISP ? std::max( unsigned( 1 ), cuSize.height / cuSize.width ) : std::max( unsigned( 1 ), cuSize.height / cuSize.width ); +#else int whRatio = std::max(1, width / height); int hwRatio = std::max(1, height / width); +#endif // Initialize the Main and Left reference array. if (intraPredAngle < 0) @@ -691,7 +737,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch if( isLuma(channelType) ) { Pel p[4]; +#if JVET_M0102_INTRA_SUBPARTITIONS + const bool useCubicFilter = useISP ? ( width <= 8 ) : ( !useFilteredPredSamples || multiRefIdx > 0 ); +#else const bool useCubicFilter = !useFilteredPredSamples || multiRefIdx > 0; +#endif TFilterCoeff const * const f = (useCubicFilter) ? InterpolationFilter::getChromaFilterTable(deltaFract) : g_intraGaussFilter[deltaFract]; int refMainIndex = deltaInt + 1; @@ -735,6 +785,10 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch const int numModes = 8; const int scale = ((g_aucLog2[width] - 2 + g_aucLog2[height] - 2 + 2) >> 2); CHECK(scale < 0 || scale > 31, "PDPC: scale < 0 || scale > 31"); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !useISP ) + { +#endif if ((predMode == 2 || predMode == VDIA_IDX) && multiRefIdx == 0) { int wT = 16 >> std::min(31, ((y << 1) >> scale)); @@ -778,6 +832,9 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch pDsty[x] = ClipPel((wL * left + (64 - wL) * pDsty[x] + 32) >> 6, clpRng); } } +#if JVET_M0102_INTRA_SUBPARTITIONS + } +#endif } #if HEVC_USE_HOR_VER_PREDFILTERING if( edgeFilter && absAng <= 1 ) @@ -945,7 +1002,11 @@ void IntraPrediction::initIntraPatternChType(const CodingUnit &cu, const CompAre Pel *refBufUnfiltered = m_piYuvExt[area.compID][PRED_BUF_UNFILTERED]; Pel *refBufFiltered = m_piYuvExt[area.compID][PRED_BUF_FILTERED]; +#if JVET_M0102_INTRA_SUBPARTITIONS + setReferenceArrayLengths( cu.ispMode && isLuma( area.compID ) ? cu.blocks[area.compID] : area ); +#else setReferenceArrayLengths(area); +#endif // ----- Step 1: unfiltered reference samples ----- xFillReferenceSamples( cs.picture->getRecoBuf( area ), refBufUnfiltered, area, cu ); @@ -971,13 +1032,25 @@ void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBuf const int tuHeight = area.height; const int predSize = m_topRefLength; const int predHSize = m_leftRefLength; +#if JVET_M0102_INTRA_SUBPARTITIONS + const int cuWidth = cu.blocks[area.compID].width; + const int cuHeight = cu.blocks[area.compID].height; + const int whRatio = cu.ispMode && isLuma(area.compID) ? std::max(1, cuWidth / cuHeight) : std::max(1, tuWidth / tuHeight); + const int hwRatio = cu.ispMode && isLuma(area.compID) ? std::max(1, cuHeight / cuWidth) : std::max(1, tuHeight / tuWidth); +#else int whRatio = std::max(1, tuWidth / tuHeight); int hwRatio = std::max(1, tuHeight / tuWidth); +#endif const int predStride = predSize + 1 + (whRatio + 1) * multiRefIdx; const bool noShift = pcv.noChroma2x2 && area.width == 4; // don't shift on the lowest level (chroma not-split) +#if JVET_M0102_INTRA_SUBPARTITIONS + const int unitWidth = tuWidth <= 2 && cu.ispMode && isLuma(area.compID) ? tuWidth : pcv.minCUWidth >> (noShift ? 0 : getComponentScaleX(area.compID, sps.getChromaFormatIdc())); + const int unitHeight = tuHeight <= 2 && cu.ispMode && isLuma(area.compID) ? tuHeight : pcv.minCUHeight >> (noShift ? 0 : getComponentScaleY(area.compID, sps.getChromaFormatIdc())); +#else const int unitWidth = pcv.minCUWidth >> (noShift ? 0 : getComponentScaleX( area.compID, sps.getChromaFormatIdc() )); const int unitHeight = pcv.minCUHeight >> (noShift ? 0 : getComponentScaleY( area.compID, sps.getChromaFormatIdc() )); +#endif const int totalAboveUnits = (predSize + (unitWidth - 1)) / unitWidth; const int totalLeftUnits = (predHSize + (unitHeight - 1)) / unitHeight; @@ -1293,6 +1366,9 @@ bool IntraPrediction::useFilteredIntraRefSamples( const ComponentID &compID, con if( sps.getSpsRangeExtension().getIntraSmoothingDisabledFlag() ) { return false; } if( !isLuma( chType ) && pu.chromaFormat != CHROMA_444 ) { return false; } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( pu.cu->ispMode && isLuma(compID) ) { return false; } +#endif if( !modeSpecific ) { return true; } diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h index 7a1995ed2e030f4570228fd40b8aa77c483134b9..8b162bb22d69931b594b1ce65bad0fd5f150c40a 100644 --- a/source/Lib/CommonLib/IntraPrediction.h +++ b/source/Lib/CommonLib/IntraPrediction.h @@ -91,10 +91,18 @@ protected: void xPredIntraAng ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const bool bEnableEdgeFilters, const SPS& sps , int multiRefIdx , const bool enableBoundaryFilter = true ); +#else +#if JVET_M0102_INTRA_SUBPARTITIONS + void xPredIntraAng ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps, + int multiRefIdx, + const bool useFilteredPredSamples, + const bool useISP = false, + const Size cuSize = Size( 0, 0 ) ); #else void xPredIntraAng ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps , int multiRefIdx , const bool useFilteredPredSamples ); +#endif #endif Pel xGetPredValDc ( const CPelBuf &pSrc, const Size &dstSize ); diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp index 8c775174306a79e085e5efc752af33970cfe39cb..a9c41af40a240bb5b0fbb5e320a0c4c48061d913 100644 --- a/source/Lib/CommonLib/LoopFilter.cpp +++ b/source/Lib/CommonLib/LoopFilter.cpp @@ -508,6 +508,9 @@ void LoopFilter::xSetLoopfilterParam( const CodingUnit& cu ) m_stLFCUParam.leftEdge = ( 0 < pos.x ) && isAvailable ( cu, *cu.cs->getCU( pos.offset( -1, 0 ), cu.chType ), !slice.getLFCrossSliceBoundaryFlag()); m_stLFCUParam.topEdge = ( 0 < pos.y ) && isAvailable ( cu, *cu.cs->getCU( pos.offset( 0, -1 ), cu.chType ), !slice.getLFCrossSliceBoundaryFlag()); #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + m_stLFCUParam.internalEdge &= !cu.ispMode; +#endif } unsigned LoopFilter::xGetBoundaryStrengthSingle ( const CodingUnit& cu, const DeblockEdgeDir edgeDir, const Position& localPos ) const diff --git a/source/Lib/CommonLib/QuantRDOQ.cpp b/source/Lib/CommonLib/QuantRDOQ.cpp index d711ea75bbe762181c357b1f37aaf542e522e475..2682f558a107fa6ee7aa9a3f62208548c35a9521 100644 --- a/source/Lib/CommonLib/QuantRDOQ.cpp +++ b/source/Lib/CommonLib/QuantRDOQ.cpp @@ -581,6 +581,9 @@ void QuantRDOQ::quant(TransformUnit &tu, const ComponentID &compID, const CCoeff bool useRDOQ = useTransformSkip ? m_useRDOQTS : m_useRDOQ; +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !tu.cu->ispMode || !isLuma(compID) ) +#endif { useRDOQ &= uiWidth > 2; useRDOQ &= uiHeight > 2; @@ -624,6 +627,9 @@ void QuantRDOQ::xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID, const bool extendedPrecision = sps.getSpsRangeExtension().getExtendedPrecisionProcessingFlag(); const int maxLog2TrDynamicRange = sps.getMaxLog2TrDynamicRange(chType); +#if JVET_M0102_INTRA_SUBPARTITIONS + const bool useIntraSubPartitions = tu.cu->ispMode && isLuma(compID); +#endif /* for 422 chroma blocks, the effective scaling applied during transformation is not a power of 2, hence it cannot be * implemented as a bit-shift (the quantised result will be sqrt(2) * larger than required). Alternatively, adjust the * uiLog2TrSize applied in iTransformShift, such that the result is 1/sqrt(2) the required result (i.e. smaller) @@ -1030,10 +1036,49 @@ void QuantRDOQ::xRateDistOptQuant(TransformUnit &tu, const ComponentID &compID, } else { +#if JVET_M0102_INTRA_SUBPARTITIONS + bool previousCbf = tu.cbf[COMPONENT_Cb]; + bool lastCbfIsInferred = false; + if( useIntraSubPartitions ) + { + bool rootCbfSoFar = false; + bool isLastSubPartition = CU::isISPLast(*tu.cu, tu.Y(), compID); + uint32_t nTus = tu.cu->ispMode == HOR_INTRA_SUBPARTITIONS ? tu.cu->lheight() >> g_aucLog2[tu.lheight()] : tu.cu->lwidth() >> g_aucLog2[tu.lwidth()]; + if( isLastSubPartition ) + { + TransformUnit* tuPointer = tu.cu->firstTU; + for( int tuIdx = 0; tuIdx < nTus - 1; tuIdx++ ) + { + rootCbfSoFar |= TU::getCbfAtDepth(*tuPointer, COMPONENT_Y, tu.depth); + tuPointer = tuPointer->next; + } + if( !rootCbfSoFar ) + { + lastCbfIsInferred = true; + } + } + if( !lastCbfIsInferred ) + { + previousCbf = TU::getPrevTuCbfAtDepth(tu, compID, tu.depth); + } + } + BinFracBits fracBitsQtCbf = fracBits.getFracBitsArray( Ctx::QtCbf[compID]( DeriveCtx::CtxQtCbf( rect.compID, tu.depth, previousCbf, useIntraSubPartitions ) ) ); + + if( !lastCbfIsInferred ) + { + d64BestCost = d64BlockUncodedCost + xGetICost(fracBitsQtCbf.intBits[0]); + d64BaseCost += xGetICost(fracBitsQtCbf.intBits[1]); + } + else + { + d64BestCost = d64BlockUncodedCost; + } +#else BinFracBits fracBitsQtCbf = fracBits.getFracBitsArray( Ctx::QtCbf[compID]( DeriveCtx::CtxQtCbf( rect.compID, tu.depth, tu.cbf[COMPONENT_Cb] ) ) ); d64BestCost = d64BlockUncodedCost + xGetICost( fracBitsQtCbf.intBits[0] ); d64BaseCost += xGetICost( fracBitsQtCbf.intBits[1] ); +#endif } int lastBitsX[LAST_SIGNIFICANT_GROUPS] = { 0 }; diff --git a/source/Lib/CommonLib/Rom.cpp b/source/Lib/CommonLib/Rom.cpp index 85e3526dde46b53530932c070129462bec35cf7e..2141368ce5e1ddd8c3aae7271a81c3c881db1fab 100644 --- a/source/Lib/CommonLib/Rom.cpp +++ b/source/Lib/CommonLib/Rom.cpp @@ -310,6 +310,33 @@ uint32_t deriveWeightIdxBits(uint8_t gbiIdx) // Note: align this with TEncSbac:: return numBits; } +#if JVET_M0102_INTRA_SUBPARTITIONS // define the sbb sizes +uint32_t g_log2SbbSize[2][MAX_CU_DEPTH+1][MAX_CU_DEPTH+1][2] = +{ + //===== luma ===== + { + { {0,0}, {0,1}, {0,2}, {0,3}, {0,4}, {0,4}, {0,4}, {0,4} }, + { {1,0}, {1,1}, {1,2}, {1,3}, {1,3}, {1,3}, {1,3}, {1,3} }, + { {2,0}, {2,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {3,0}, {3,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {4,0}, {3,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {4,0}, {3,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {4,0}, {3,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {4,0}, {3,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} } + }, + //===== chroma ===== + { + { {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0} }, + { {0,0}, {1,1}, {1,1}, {1,1}, {1,1}, {1,1}, {1,1}, {1,1} }, + { {0,0}, {1,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {0,0}, {1,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {0,0}, {1,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {0,0}, {1,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {0,0}, {1,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} }, + { {0,0}, {1,1}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2}, {2,2} } + }, +}; +#endif // initialize ROM variables void initROM() { @@ -373,6 +400,10 @@ void initROM() SizeIndexInfoLog2 sizeInfo; sizeInfo.init(MAX_CU_SIZE); +#if JVET_M0102_INTRA_SUBPARTITIONS + for( int ch = 0; ch < MAX_NUM_CHANNEL_TYPE; ch++ ) + { +#endif // initialize scan orders for (uint32_t blockHeightIdx = 0; blockHeightIdx < sizeInfo.numAllHeights(); blockHeightIdx++) { @@ -390,9 +421,15 @@ void initROM() { const CoeffScanType scanType = CoeffScanType(scanTypeIndex); +#if JVET_M0102_INTRA_SUBPARTITIONS + g_scanOrder [ch][SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx] = new uint32_t[totalValues]; + g_scanOrderPosXY[ch][SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx][0] = new uint32_t[totalValues]; + g_scanOrderPosXY[ch][SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx][1] = new uint32_t[totalValues]; +#else g_scanOrder [SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx] = new uint32_t[totalValues]; g_scanOrderPosXY[SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx][0] = new uint32_t[totalValues]; g_scanOrderPosXY[SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx][1] = new uint32_t[totalValues]; +#endif ScanGenerator fullBlockScan(blockWidth, blockHeight, blockWidth, scanType); @@ -401,9 +438,15 @@ void initROM() const int rasterPos = fullBlockScan.GetNextIndex( 0, 0 ); const int posY = rasterPos / blockWidth; const int posX = rasterPos - ( posY * blockWidth ); +#if JVET_M0102_INTRA_SUBPARTITIONS + g_scanOrder [ch][SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx] [scanPosition] = rasterPos; + g_scanOrderPosXY[ch][SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx][0][scanPosition] = posX; + g_scanOrderPosXY[ch][SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx][1][scanPosition] = posY; +#else g_scanOrder [SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx] [scanPosition] = rasterPos; g_scanOrderPosXY[SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx][0][scanPosition] = posX; g_scanOrderPosXY[SCAN_UNGROUPED][scanType][blockWidthIdx][blockHeightIdx][1][scanPosition] = posY; +#endif } } @@ -412,10 +455,15 @@ void initROM() // size indizes greater than numIdxs are sizes than are only used when grouping - they will never come up as a block size - thus they can be skipped at this point for( uint32_t scanTypeIndex = 0; scanTypeIndex < SCAN_NUMBER_OF_TYPES; scanTypeIndex++ ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + g_scanOrder [ch][SCAN_GROUPED_4x4][scanTypeIndex][blockWidthIdx][blockHeightIdx] = nullptr; + g_scanOrderPosXY[ch][SCAN_GROUPED_4x4][scanTypeIndex][blockWidthIdx][blockHeightIdx][0] = nullptr; + g_scanOrderPosXY[ch][SCAN_GROUPED_4x4][scanTypeIndex][blockWidthIdx][blockHeightIdx][1] = nullptr; +#else g_scanOrder [SCAN_GROUPED_4x4][scanTypeIndex][blockWidthIdx][blockHeightIdx] = nullptr; g_scanOrderPosXY[SCAN_GROUPED_4x4][scanTypeIndex][blockWidthIdx][blockHeightIdx][0] = nullptr; g_scanOrderPosXY[SCAN_GROUPED_4x4][scanTypeIndex][blockWidthIdx][blockHeightIdx][1] = nullptr; - +#endif } continue; @@ -424,8 +472,14 @@ void initROM() //-------------------------------------------------------------------------------------------------- //grouped scan orders +#if JVET_M0102_INTRA_SUBPARTITIONS + const uint32_t* log2Sbb = g_log2SbbSize[ch][ g_aucLog2[blockWidth] ][ g_aucLog2[blockHeight] ]; + const uint32_t log2CGWidth = log2Sbb[0]; + const uint32_t log2CGHeight = log2Sbb[1]; +#else const uint32_t log2CGWidth = (blockWidth & 3) + (blockHeight & 3) > 0 ? 1 : 2; const uint32_t log2CGHeight = (blockWidth & 3) + (blockHeight & 3) > 0 ? 1 : 2; +#endif const uint32_t groupWidth = 1 << log2CGWidth; const uint32_t groupHeight = 1 << log2CGHeight; @@ -444,10 +498,27 @@ void initROM() { const CoeffScanType scanType = CoeffScanType(scanTypeIndex); +#if JVET_M0102_INTRA_SUBPARTITIONS + g_scanOrder [ch][SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx] = new uint32_t[totalValues]; + g_scanOrderPosXY[ch][SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx][0] = new uint32_t[totalValues]; + g_scanOrderPosXY[ch][SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx][1] = new uint32_t[totalValues]; +#else g_scanOrder [SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx] = new uint32_t[totalValues]; g_scanOrderPosXY[SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx][0] = new uint32_t[totalValues]; g_scanOrderPosXY[SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx][1] = new uint32_t[totalValues]; +#endif #if JVET_M0257 +#if JVET_M0102_INTRA_SUBPARTITIONS + if ( blockWidth > JVET_C0024_ZERO_OUT_TH || blockHeight > JVET_C0024_ZERO_OUT_TH ) + { + for (uint32_t i = 0; i < totalValues; i++) + { + g_scanOrder [ch][SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx][i] = totalValues - 1; + g_scanOrderPosXY[ch][SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx][0][i] = blockWidth - 1; + g_scanOrderPosXY[ch][SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx][1][i] = blockHeight - 1; + } + } +#else if ( blockWidth > JVET_C0024_ZERO_OUT_TH || blockHeight > JVET_C0024_ZERO_OUT_TH ) { for (uint32_t i = 0; i < totalValues; i++) @@ -457,6 +528,7 @@ void initROM() g_scanOrderPosXY[SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx][1][i] = blockHeight - 1; } } +#endif #endif ScanGenerator fullBlockScan(widthInGroups, heightInGroups, groupWidth, scanType); @@ -477,9 +549,15 @@ void initROM() const int posY = rasterPos / blockWidth; const int posX = rasterPos - ( posY * blockWidth ); +#if JVET_M0102_INTRA_SUBPARTITIONS + g_scanOrder [ch][SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx] [groupOffsetScan + scanPosition] = rasterPos; + g_scanOrderPosXY[ch][SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx][0][groupOffsetScan + scanPosition] = posX; + g_scanOrderPosXY[ch][SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx][1][groupOffsetScan + scanPosition] = posY; +#else g_scanOrder [SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx] [groupOffsetScan + scanPosition] = rasterPos; g_scanOrderPosXY[SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx][0][groupOffsetScan + scanPosition] = posX; g_scanOrderPosXY[SCAN_GROUPED_4x4][scanType][blockWidthIdx][blockHeightIdx][1][groupOffsetScan + scanPosition] = posY; +#endif } fullBlockScan.GetNextIndex(0, 0); @@ -489,6 +567,9 @@ void initROM() //-------------------------------------------------------------------------------------------------- } } +#if JVET_M0102_INTRA_SUBPARTITIONS + } +#endif for( int idxH = MAX_CU_DEPTH - MIN_CU_LOG2; idxH >= 0; --idxH ) { @@ -518,6 +599,31 @@ void destroyROM() unsigned numWidths = gp_sizeIdxInfo->numAllWidths(); unsigned numHeights = gp_sizeIdxInfo->numAllHeights(); +#if JVET_M0102_INTRA_SUBPARTITIONS + for( uint32_t ch = 0; ch < MAX_NUM_CHANNEL_TYPE; ch++ ) + { + for( uint32_t groupTypeIndex = 0; groupTypeIndex < SCAN_NUMBER_OF_GROUP_TYPES; groupTypeIndex++ ) + { + for( uint32_t scanOrderIndex = 0; scanOrderIndex < SCAN_NUMBER_OF_TYPES; scanOrderIndex++ ) + { + for( uint32_t blockWidthIdx = 0; blockWidthIdx <= numWidths; blockWidthIdx++ ) + { + for( uint32_t blockHeightIdx = 0; blockHeightIdx <= numHeights; blockHeightIdx++ ) + { + delete[] g_scanOrder[ch][groupTypeIndex][scanOrderIndex][blockWidthIdx][blockHeightIdx]; + g_scanOrder[ch][groupTypeIndex][scanOrderIndex][blockWidthIdx][blockHeightIdx] = nullptr; + + delete[] g_scanOrderPosXY[ch][groupTypeIndex][scanOrderIndex][blockWidthIdx][blockHeightIdx][0]; + g_scanOrderPosXY[ch][groupTypeIndex][scanOrderIndex][blockWidthIdx][blockHeightIdx][0] = nullptr; + + delete[] g_scanOrderPosXY[ch][groupTypeIndex][scanOrderIndex][blockWidthIdx][blockHeightIdx][1]; + g_scanOrderPosXY[ch][groupTypeIndex][scanOrderIndex][blockWidthIdx][blockHeightIdx][1] = nullptr; + } + } + } + } + } +#else for (uint32_t groupTypeIndex = 0; groupTypeIndex < SCAN_NUMBER_OF_GROUP_TYPES; groupTypeIndex++) { for (uint32_t scanOrderIndex = 0; scanOrderIndex < SCAN_NUMBER_OF_TYPES; scanOrderIndex++) @@ -539,6 +645,7 @@ void destroyROM() } } } +#endif delete gp_sizeIdxInfo; gp_sizeIdxInfo = nullptr; @@ -672,8 +779,13 @@ UnitScale g_miScaling( MIN_CU_LOG2, MIN_CU_LOG2 ); // ==================================================================================================================== // scanning order table +#if JVET_M0102_INTRA_SUBPARTITIONS +uint32_t* g_scanOrder [2][SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1]; +uint32_t* g_scanOrderPosXY[2][SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1][2]; +#else uint32_t* g_scanOrder [SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1]; uint32_t* g_scanOrderPosXY[SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1][2]; +#endif const uint32_t ctxIndMap4x4[4 * 4] = { diff --git a/source/Lib/CommonLib/Rom.h b/source/Lib/CommonLib/Rom.h index 63520f58e341698dc48697f9fa38263bd9aa8cf7..71d4d0ee85ab821e2cb87d8641b65d198a861671 100644 --- a/source/Lib/CommonLib/Rom.h +++ b/source/Lib/CommonLib/Rom.h @@ -64,8 +64,14 @@ void generateTrafoBlockSizeScaling( SizeIndexInfo& sizeIdxInfo ); // ==================================================================================================================== // flexible conversion from relative to absolute index +#if JVET_M0102_INTRA_SUBPARTITIONS +extern uint32_t g_log2SbbSize [2][MAX_CU_DEPTH+1][MAX_CU_DEPTH+1][2]; +extern uint32_t* g_scanOrder [2][SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1]; +extern uint32_t* g_scanOrderPosXY[2][SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1][2]; +#else extern uint32_t* g_scanOrder [SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1]; extern uint32_t* g_scanOrderPosXY[SCAN_NUMBER_OF_GROUP_TYPES][SCAN_NUMBER_OF_TYPES][MAX_CU_SIZE / 2 + 1][MAX_CU_SIZE / 2 + 1][2]; +#endif extern const int g_quantScales [SCALING_LIST_REM_NUM]; // Q(QP%6) extern const int g_invQuantScales[SCALING_LIST_REM_NUM]; // IQ(QP%6) diff --git a/source/Lib/CommonLib/TrQuant.cpp b/source/Lib/CommonLib/TrQuant.cpp index 8816650a28acd4b1128dbf47d488f0b1e2ad8173..a756ed223e23da328717a8a134aad5401ff0c367 100644 --- a/source/Lib/CommonLib/TrQuant.cpp +++ b/source/Lib/CommonLib/TrQuant.cpp @@ -296,12 +296,21 @@ void TrQuant::getTrTypes ( TransformUnit tu, const ComponentID compID, int &trTy #else bool emtActivated = CU::isIntra( *tu.cu ) ? tu.cs->sps->getSpsNext().getUseIntraEMT() : tu.cs->sps->getSpsNext().getUseInterEMT(); #endif + #if JVET_M0303_IMPLICIT_MTS bool mtsImplicit = CU::isIntra( *tu.cu ) && tu.cs->sps->getSpsNext().getUseImplicitMTS() && compID == COMPONENT_Y; #endif trTypeHor = DCT2; trTypeVer = DCT2; + +#if JVET_M0102_INTRA_SUBPARTITIONS + if (tu.cu->ispMode && isLuma(compID)) + { + TU::getTransformTypeISP(tu, compID, trTypeHor, trTypeVer); + return; +} +#endif #if JVET_M0464_UNI_MTS if ( mtsActivated ) @@ -386,10 +395,28 @@ void TrQuant::xT( const TransformUnit &tu, const ComponentID &compID, const CPel } } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( width > 1 && height > 1 ) // 2-D transform + { +#endif TCoeff *tmp = ( TCoeff * ) alloca( width * height * sizeof( TCoeff ) ); fastFwdTrans[trTypeHor][transformWidthIndex ](block, tmp, shift_1st, height, 0, skipWidth); fastFwdTrans[trTypeVer][transformHeightIndex](tmp, dstCoeff.buf, shift_2nd, width, skipWidth, skipHeight); +#if JVET_M0102_INTRA_SUBPARTITIONS + } + else if( height == 1 ) //1-D horizontal transform + { + CHECKD( ( transformWidthIndex < 0 ), "There is a problem with the width." ); + fastFwdTrans[trTypeHor][transformWidthIndex]( block, dstCoeff.buf, shift_1st, 1, 0, skipWidth ); + } + else //if (iWidth == 1) //1-D vertical transform + { + CHECKD( ( transformHeightIndex < 0 ), "There is a problem with the height." ); + int newShift = ( ( g_aucLog2[height] ) + bitDepth + TRANSFORM_MATRIX_SHIFT ) - maxLog2TrDynamicRange + COM16_C806_TRANS_PREC; + fastFwdTrans[trTypeVer][transformHeightIndex]( block, dstCoeff.buf, newShift, 1, 0, skipHeight ); + } +#endif } void TrQuant::xIT( const TransformUnit &tu, const ComponentID &compID, const CCoeffBuf &pCoeff, PelBuf &pResidual ) @@ -416,11 +443,32 @@ void TrQuant::xIT( const TransformUnit &tu, const ComponentID &compID, const CCo getTrTypes ( tu, compID, trTypeHor, trTypeVer ); +#if !JVET_M0102_INTRA_SUBPARTITIONS TCoeff *tmp = ( TCoeff * ) alloca( width * height * sizeof( TCoeff ) ); +#endif TCoeff *block = ( TCoeff * ) alloca( width * height * sizeof( TCoeff ) ); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( width > 1 && height > 1 ) //2-D transform + { + TCoeff *tmp = ( TCoeff * ) alloca( width * height * sizeof( TCoeff ) ); +#endif fastInvTrans[trTypeVer][transformHeightIndex](pCoeff.buf, tmp, shift_1st, width, skipWidth, skipHeight, clipMinimum, clipMaximum); fastInvTrans[trTypeHor][transformWidthIndex] (tmp, block, shift_2nd, height, 0, skipWidth, clipMinimum, clipMaximum); +#if JVET_M0102_INTRA_SUBPARTITIONS + } + else if( width == 1 ) //1-D vertical transform + { + CHECK( ( transformHeightIndex < 0 ), "There is a problem with the height." ); + int newShift = ( TRANSFORM_MATRIX_SHIFT + maxLog2TrDynamicRange - 1 ) - bitDepth + COM16_C806_TRANS_PREC; + fastInvTrans[trTypeVer][transformHeightIndex]( pCoeff.buf, block, newShift + 1, 1, 0, skipHeight, clipMinimum, clipMaximum ); + } + else //if(iHeight == 1) //1-D horizontal transform + { + CHECK( ( transformWidthIndex < 0 ), "There is a problem with the width." ); + fastInvTrans[trTypeHor][transformWidthIndex]( pCoeff.buf, block, shift_2nd + 1, 1, 0, skipWidth, clipMinimum, clipMaximum ); + } +#endif Pel *resiBuf = pResidual.buf; int resiStride = pResidual.stride; @@ -496,7 +544,11 @@ void TrQuant::xQuant(TransformUnit &tu, const ComponentID &compID, const CCoeffB } #if JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS +void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, std::vector<TrMode>* trModes, const int maxCand, double* diagRatio, double* horVerRatio ) +#else void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, std::vector<TrMode>* trModes, const int maxCand) +#endif { CodingStructure &cs = *tu.cs; const SPS &sps = *cs.sps; @@ -545,6 +597,11 @@ void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const Q it++; } +#if JVET_M0102_INTRA_SUBPARTITIONS + // it gets the distribution of the DCT-II coefficients energy, which will be useful to discard ISP tests + CoeffBuf coeffsDCT( m_mtsCoeffs[0], rect ); + xGetCoeffEnergy( tu, compID, coeffsDCT, diagRatio, horVerRatio ); +#endif int numTests = 0; std::vector<TrCost>::iterator itC = trCosts.begin(); const double fac = facBB[g_aucLog2[std::max(width, height)]-2]; @@ -561,10 +618,18 @@ void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const Q #endif #if JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS +void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, const bool loadTr, double* diagRatio, double* horVerRatio ) +#else void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, const bool loadTr) +#endif +#else +#if JVET_M0102_INTRA_SUBPARTITIONS +void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, double* diagRatio, double* horVerRatio) #else void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx) #endif +#endif { CodingStructure &cs = *tu.cs; const SPS &sps = *cs.sps; @@ -636,6 +701,20 @@ void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const Q } #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + //we do this only with the DCT-II coefficients + if( isLuma(compID) && +#if JVET_M0464_UNI_MTS + !loadTr && tu.mtsIdx == 0 +#else + !tu.cu->emtFlag +#endif + ) + { + //it gets the distribution of the coefficients energy, which will be useful to discard ISP tests + xGetCoeffEnergy( tu, compID, tempCoeff, diagRatio, horVerRatio ); + } +#endif DTRACE_COEFF_BUF( D_TCOEFF, tempCoeff, tu, tu.cu->predMode, compID ); xQuant( tu, compID, tempCoeff, uiAbsSum, cQP, ctx ); @@ -648,6 +727,43 @@ void TrQuant::transformNxN(TransformUnit &tu, const ComponentID &compID, const Q TU::setCbfAtDepth (tu, compID, tu.depth, uiAbsSum > 0); } +#if JVET_M0102_INTRA_SUBPARTITIONS +void TrQuant::xGetCoeffEnergy( TransformUnit &tu, const ComponentID &compID, const CoeffBuf& coeffs, double* diagRatio, double* horVerRatio ) +{ + if( nullptr == diagRatio || nullptr == horVerRatio ) return; + + if( tu.cu->predMode == MODE_INTRA && !tu.cu->ispMode && isLuma( compID ) && CU::canUseISPSplit( *tu.cu, compID ) != NOT_INTRA_SUBPARTITIONS ) + { + const int width = tu.cu->blocks[compID].width; + const int height = tu.cu->blocks[compID].height; + const int log2Sl = width <= height ? g_aucLog2[height >> g_aucLog2[width]] : g_aucLog2[width >> g_aucLog2[height]]; + const int diPos1 = width <= height ? width : height; + const int diPos2 = width <= height ? height : width; + const int ofsPos1 = width <= height ? 1 : coeffs.stride; + const int ofsPos2 = width <= height ? coeffs.stride : 1; + + int wdtE = 0, hgtE = 0, diaE = 0; + int* gtE = width <= height ? &wdtE : &hgtE; + int* stE = width <= height ? &hgtE : &wdtE; + + for( int pos1 = 0; pos1 < diPos1; pos1++ ) + { + const int posN = pos1 << log2Sl; + for( int pos2 = 0; pos2 < diPos2; pos2++ ) + { + const int blkP = pos1 * ofsPos1 + pos2 * ofsPos2; + if( posN > pos2 ) *gtE += abs( coeffs.buf[ blkP ] ); + if( posN < pos2 ) *stE += abs( coeffs.buf[ blkP ] ); + if( posN == pos2 ) diaE += abs( coeffs.buf[ blkP ] ); + } + } + + *horVerRatio = 0 == wdtE && 0 == hgtE ? 1 : double( wdtE ) / double( hgtE ); + *diagRatio = 0 == wdtE && 0 == hgtE && 0 == diaE ? 1 : double( diaE ) / double( wdtE + hgtE ); + } +} +#endif + void TrQuant::applyForwardRDPCM(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const RDPCMMode &mode) { const bool bLossless = tu.cu->transQuantBypass; diff --git a/source/Lib/CommonLib/TrQuant.h b/source/Lib/CommonLib/TrQuant.h index aa58a29981b7f6a8ac09601972a487a8811cc6f5..9f477ea9f9d853e531634673a3396d6054008b6d 100644 --- a/source/Lib/CommonLib/TrQuant.h +++ b/source/Lib/CommonLib/TrQuant.h @@ -88,10 +88,19 @@ public: void invTransformNxN (TransformUnit &tu, const ComponentID &compID, PelBuf &pResi, const QpParam &cQPs); #if JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + void transformNxN ( TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, std::vector<TrMode>* trModes, const int maxCand, double* diagRatio = nullptr, double* horVerRatio = nullptr ); + void transformNxN ( TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, const bool loadTr = false, double* diagRatio = nullptr, double* horVerRatio = nullptr ); +#else void transformNxN (TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, std::vector<TrMode>* trModes, const int maxCand); void transformNxN (TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, const bool loadTr=false); +#endif +#else +#if JVET_M0102_INTRA_SUBPARTITIONS + void transformNxN (TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, double* diagRatio = nullptr, double* horVerRatio = nullptr); #else void transformNxN (TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx); +#endif #endif void rdpcmNxN (TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, RDPCMMode &rdpcmMode); void applyForwardRDPCM(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const RDPCMMode &rdpcmMode); @@ -157,6 +166,14 @@ private: const TransformUnit &tu, const ComponentID &component); +#if JVET_M0102_INTRA_SUBPARTITIONS + void xGetCoeffEnergy( + TransformUnit &tu, + const ComponentID &compID, + const CoeffBuf &coeffs, + double* diagRatio, + double* horVerRatio ); +#endif #ifdef TARGET_SIMD_X86 template<X86_VEXT vext> diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 97ec5e99a1d7640b0bc298f1b92065eba3bcda8b..2e57ed508b3d9107767009e4c6204438b546c222 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,6 +50,8 @@ #include <assert.h> #include <cassert> +#define JVET_M0102_INTRA_SUBPARTITIONS 1 + #define JVET_M0303_IMPLICIT_MTS 1 // Implicit transform selection (can be enabled with MTSImplicit encoder config parameter) #define FIX_DB_MAX_TRANSFORM_SIZE 1 @@ -144,6 +146,10 @@ typedef std::pair<int, int> TrCost; #define JVET_L0090_PAIR_AVG 1 // Add pairwise average candidates, replace HEVC combined candidates #define REUSE_CU_RESULTS 1 +#if REUSE_CU_RESULTS && JVET_M0102_INTRA_SUBPARTITIONS +#define REUSE_CU_RESULTS_WITH_MULTIPLE_TUS 1 +#define MAX_NUM_TUS 4 +#endif // clang-format on #ifndef JVET_B0051_NON_MPM_MODE @@ -399,6 +405,17 @@ enum TransType DCT2_EMT = 4 }; +#if JVET_M0102_INTRA_SUBPARTITIONS +enum ISPType +{ + NOT_INTRA_SUBPARTITIONS = 0, + HOR_INTRA_SUBPARTITIONS = 1, + VER_INTRA_SUBPARTITIONS = 2, + NUM_INTRA_SUBPARTITIONS_MODES = 3, + CAN_USE_VER_AND_HORL_SPLITS = 4 +}; +#endif + enum RDPCMMode { RDPCM_OFF = 0, diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index 138617abf7246764d22a2a6348f93c2ffee6ea68..0f11344e0e1a69784337fff1eaf7c89cbd8fd4b8 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -189,6 +189,16 @@ bool UnitArea::contains( const UnitArea& other, const ChannelType chType ) const return any && ret; } +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS +void UnitArea::resizeTo( const UnitArea& unitArea ) +{ + for( uint32_t i = 0; i < blocks.size(); i++ ) + { + blocks[i].resizeTo( unitArea.blocks[i] ); + } +} +#endif + void UnitArea::repositionTo(const UnitArea& unitArea) { for(uint32_t i = 0; i < blocks.size(); i++) @@ -281,7 +291,9 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other ) #if JVET_M0444_SMVD smvdMode = other.smvdMode; #endif - +#if JVET_M0102_INTRA_SUBPARTITIONS + ispMode = other.ispMode; +#endif return *this; } @@ -323,6 +335,9 @@ void CodingUnit::initData() #if JVET_M0444_SMVD smvdMode = 0; #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + ispMode = 0; +#endif } diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index f2f30097778855feb8d00a7282a7a14ac2544476..8cb246d99791b5838187ac6bf9a98181a40c2381 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -153,6 +153,9 @@ struct CompArea : public Area const bool operator!=(const CompArea &other) const { return !(operator==(other)); } +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + void resizeTo (const Size& newSize) { Size::resizeTo(newSize); } +#endif void repositionTo (const Position& newPos) { Position::repositionTo(newPos); } void positionRelativeTo(const CompArea& origCompArea) { Position::relativeTo(origCompArea); } @@ -214,6 +217,9 @@ struct UnitArea return true; } +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + void resizeTo (const UnitArea& unit); +#endif void repositionTo(const UnitArea& unit); const bool operator!=(const UnitArea &other) const { return !(*this == other); } @@ -320,6 +326,9 @@ struct CodingUnit : public UnitArea #if JVET_M0444_SMVD uint8_t smvdMode; #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + uint8_t ispMode; +#endif CodingUnit() : chType( CH_L ) { } CodingUnit(const UnitArea &unit); @@ -464,6 +473,9 @@ struct TransformUnit : public UnitArea unsigned idx; TransformUnit *next; +#if JVET_M0102_INTRA_SUBPARTITIONS + TransformUnit *prev; +#endif void init(TCoeff **coeffs, Pel **pcmbuf); diff --git a/source/Lib/CommonLib/UnitPartitioner.cpp b/source/Lib/CommonLib/UnitPartitioner.cpp index dae0769736f028afa368c3d303d82047aeb09b0b..39be3bb0cc5c48b67b059e1198dec2899d0ffd3a 100644 --- a/source/Lib/CommonLib/UnitPartitioner.cpp +++ b/source/Lib/CommonLib/UnitPartitioner.cpp @@ -671,6 +671,106 @@ bool QTBTPartitioner::hasNextPart() return ( ( m_partStack.back().idx + 1 ) < m_partStack.back().parts.size() ); } +#if JVET_M0102_INTRA_SUBPARTITIONS +void TUIntraSubPartitioner::splitCurrArea( const PartSplit split, const CodingStructure& cs ) +{ + switch( split ) + { + case TU_1D_HORZ_SPLIT: + case TU_1D_VERT_SPLIT: + { + const UnitArea &area = currArea(); + m_partStack.push_back( PartLevel() ); + m_partStack.back().split = split; + PartitionerImpl::getTUIntraSubPartitions( m_partStack.back().parts, area, cs, split ); + break; + } + case TU_MAX_TR_SPLIT: //we need this non ISP split because of the maxTrSize limitation + m_partStack.push_back( PartLevel( split, PartitionerImpl::getMaxTuTiling( currArea(), cs ) ) ); + break; + default: + THROW( "Unknown ISP split mode" ); + break; + } + + currDepth++; + currTrDepth++; // we need this to identify the level. since the 1d partitions are forbidden if the RQT is on, there area no compatibility issues + +#if _DEBUG + m_currArea = m_partStack.back().parts.front(); +#endif +} + +void TUIntraSubPartitioner::exitCurrSplit() +{ + PartSplit currSplit = m_partStack.back().split; + + m_partStack.pop_back(); + + CHECK( currDepth == 0, "depth is '0', although a split was performed" ); + + currDepth--; + currTrDepth--; + +#if _DEBUG + m_currArea = m_partStack.back().parts[m_partStack.back().idx]; +#endif + + CHECK( !( currSplit == TU_1D_HORZ_SPLIT || currSplit == TU_1D_VERT_SPLIT || currSplit == TU_MAX_TR_SPLIT ), "Unknown 1D partition split type!" ); +} + +bool TUIntraSubPartitioner::nextPart( const CodingStructure &cs, bool autoPop /*= false*/ ) +{ + unsigned currIdx = ++m_partStack.back().idx; + + m_partStack.back().checkdIfImplicit = false; + m_partStack.back().isImplicit = false; + + if( currIdx < m_partStack.back().parts.size() ) + { +#if _DEBUG + m_currArea = m_partStack.back().parts[m_partStack.back().idx]; +#endif + return true; + } + else + { + if( autoPop ) exitCurrSplit(); + return false; + } +} + +bool TUIntraSubPartitioner::hasNextPart() +{ + return ( ( m_partStack.back().idx + 1 ) < m_partStack.back().parts.size() ); +} + +bool TUIntraSubPartitioner::canSplit( const PartSplit split, const CodingStructure &cs ) +{ + //const PartSplit implicitSplit = getImplicitSplit(cs); + const UnitArea &area = currArea(); + + switch( split ) + { + case TU_1D_HORZ_SPLIT: + { + return area.lheight() == m_partStack[0].parts[0].lheight(); + } + case TU_1D_VERT_SPLIT: + { + return area.lwidth() == m_partStack[0].parts[0].lwidth(); + } + case TU_MAX_TR_SPLIT: + { + //this split is performed implicitly with the other splits + return false; + } + default: + THROW( "Unknown 1-D split mode" ); + break; + } +} +#endif ////////////////////////////////////////////////////////////////////////// @@ -879,6 +979,63 @@ Partitioning PartitionerImpl::getCUSubPartitions( const UnitArea &cuArea, const } } +#if JVET_M0102_INTRA_SUBPARTITIONS +void PartitionerImpl::getTUIntraSubPartitions( Partitioning &sub, const UnitArea &tuArea, const CodingStructure &cs, const PartSplit splitType ) +{ + uint32_t nPartitions; + uint32_t splitDimensionSize = CU::getISPSplitDim( tuArea.lumaSize().width, tuArea.lumaSize().height, splitType ); + + bool isDualTree = CS::isDualITree( cs ); + + if( splitType == TU_1D_HORZ_SPLIT ) + { + nPartitions = tuArea.lumaSize().height >> g_aucLog2[splitDimensionSize]; + + sub.resize( nPartitions ); + + for( uint32_t i = 0; i < nPartitions; i++ ) + { + sub[i] = tuArea; + CompArea& blkY = sub[i].blocks[COMPONENT_Y]; + + blkY.height = splitDimensionSize; + blkY.y = i > 0 ? sub[i - 1].blocks[COMPONENT_Y].y + splitDimensionSize : blkY.y; + + CHECK( sub[i].lumaSize().height < 1, "the cs split causes the block to be smaller than the minimal TU size" ); + } + } + else if( splitType == TU_1D_VERT_SPLIT ) + { + nPartitions = tuArea.lumaSize().width >> g_aucLog2[splitDimensionSize]; + + sub.resize( nPartitions ); + + for( uint32_t i = 0; i < nPartitions; i++ ) + { + sub[i] = tuArea; + CompArea& blkY = sub[i].blocks[COMPONENT_Y]; + + blkY.width = splitDimensionSize; + blkY.x = i > 0 ? sub[i - 1].blocks[COMPONENT_Y].x + splitDimensionSize : blkY.x; + CHECK( sub[i].lumaSize().width < 1, "the split causes the block to be smaller than the minimal TU size" ); + } + } + else + { + THROW( "Unknown TU sub-partitioning" ); + } + //we only partition luma, so there is going to be only one chroma tu at the end (unless it is dual tree, in which case there won't be any chroma components) + uint32_t partitionsWithoutChroma = isDualTree ? nPartitions : nPartitions - 1; + for( uint32_t i = 0; i < partitionsWithoutChroma; i++ ) + { + CompArea& blkCb = sub[i].blocks[COMPONENT_Cb]; + CompArea& blkCr = sub[i].blocks[COMPONENT_Cr]; + blkCb = CompArea(); + blkCr = CompArea(); + } +} +#endif + static const int g_maxRtGridSize = 3; static const int g_zScanToX[1 << ( g_maxRtGridSize << 1 )] = diff --git a/source/Lib/CommonLib/UnitPartitioner.h b/source/Lib/CommonLib/UnitPartitioner.h index 222fe99edeb0a83f5ef5ab5462a25f63d1bb1eb5..5cf07f530632290737dedb4072f041d1f8804bb8 100644 --- a/source/Lib/CommonLib/UnitPartitioner.h +++ b/source/Lib/CommonLib/UnitPartitioner.h @@ -43,7 +43,11 @@ #include "CommonDef.h" static_assert( MAX_CU_TILING_PARTITIONS >= 4, "Minimum required number of partitions for the Partitioning type is 4!" ); +#if JVET_M0102_INTRA_SUBPARTITIONS +typedef std::vector <UnitArea> Partitioning; +#else typedef static_vector<UnitArea, MAX_CU_TILING_PARTITIONS> Partitioning; +#endif ////////////////////////////////////////////////////////////////////////// // PartManager class - manages the partitioning tree @@ -63,6 +67,11 @@ enum PartSplit CU_TRIH_SPLIT, CU_TRIV_SPLIT, TU_MAX_TR_SPLIT, +#if JVET_M0102_INTRA_SUBPARTITIONS + TU_NO_ISP, + TU_1D_HORZ_SPLIT, + TU_1D_VERT_SPLIT, +#endif NUM_PART_SPLIT, CU_MT_SPLIT = 1000, ///< dummy element to indicate the MT (multi-type-tree) split CU_BT_SPLIT = 1001, ///< dummy element to indicate the BT split @@ -159,6 +168,37 @@ public: PartSplit getImplicitSplit ( const CodingStructure &cs ); }; +#if JVET_M0102_INTRA_SUBPARTITIONS +class TUIntraSubPartitioner : public Partitioner +{ +public: + TUIntraSubPartitioner(Partitioner& _initialState) + { + //we copy the input partitioner data + m_partStack.push_back(PartLevel(TU_NO_ISP, { _initialState.currArea() })); + + currDepth = _initialState.currDepth; + currQtDepth = _initialState.currQtDepth; + currTrDepth = _initialState.currTrDepth; + currBtDepth = _initialState.currBtDepth; + currMtDepth = _initialState.currMtDepth; + chType = _initialState.chType; +#if _DEBUG + m_currArea = _initialState.currArea(); +#endif + } + + void initCtu (const UnitArea& ctuArea, const ChannelType chType, const Slice& slice) {}; // not needed + void splitCurrArea (const PartSplit split, const CodingStructure &cs); + void exitCurrSplit (); + bool nextPart (const CodingStructure &cs, bool autoPop = false); + bool hasNextPart (); + void canSplit (const CodingStructure &cs, bool& canNo, bool& canQt, bool& canBh, bool& canBv, bool& canTh, bool& canTv) {}; + bool canSplit (const PartSplit split, const CodingStructure &cs); + bool isSplitImplicit (const PartSplit split, const CodingStructure &cs) { return false; }; //not needed + PartSplit getImplicitSplit (const CodingStructure &cs) { return CU_DONT_SPLIT; }; //not needed +}; +#endif @@ -176,6 +216,9 @@ namespace PartitionerImpl { Partitioning getCUSubPartitions( const UnitArea &cuArea, const CodingStructure &cs, const PartSplit splitType = CU_QUAD_SPLIT ); Partitioning getMaxTuTiling ( const UnitArea& curArea, const CodingStructure &cs ); +#if JVET_M0102_INTRA_SUBPARTITIONS + void getTUIntraSubPartitions( Partitioning &sub, const UnitArea &tuArea, const CodingStructure &cs, const PartSplit splitType ); +#endif }; #endif diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index e73eea309d8b5e5af61d6aa6d47a8cb5689fb522..f2ebcfbaf7bde7a7da230894f10ce0be525c151e 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -290,7 +290,175 @@ uint32_t CU::getNumNonZeroCoeffNonTs( const CodingUnit& cu ) return count; } +#if JVET_M0102_INTRA_SUBPARTITIONS +bool CU::divideTuInRows( const CodingUnit &cu ) +{ + CHECK( cu.ispMode != HOR_INTRA_SUBPARTITIONS && cu.ispMode != VER_INTRA_SUBPARTITIONS, "Intra Subpartitions type not recognized!" ); + return cu.ispMode == HOR_INTRA_SUBPARTITIONS ? true : false; +} + +bool CU::firstTestISPHorSplit( const int width, const int height, const ComponentID compID, const CodingUnit *cuLeft, const CodingUnit *cuAbove ) +{ + //this function decides which split mode (horizontal or vertical) is tested first (encoder only) + //we check the logarithmic aspect ratios of the block + int aspectRatio = g_aucLog2[width] - g_aucLog2[height]; + if( aspectRatio > 0 ) + { + return true; + } + else if( aspectRatio < 0 ) + { + return false; + } + else //if (aspectRatio == 0) + { + //we gather data from the neighboring CUs + const int cuLeftWidth = cuLeft != nullptr ? cuLeft->blocks[compID].width : -1; + const int cuLeftHeight = cuLeft != nullptr ? cuLeft->blocks[compID].height : -1; + const int cuAboveWidth = cuAbove != nullptr ? cuAbove->blocks[compID].width : -1; + const int cuAboveHeight = cuAbove != nullptr ? cuAbove->blocks[compID].height : -1; + const int cuLeft1dSplit = cuLeft != nullptr && cuLeft->predMode == MODE_INTRA ? cuLeft->ispMode : 0; + const int cuAbove1dSplit = cuAbove != nullptr && cuAbove->predMode == MODE_INTRA ? cuAbove->ispMode : 0; + if( cuLeftWidth != -1 && cuAboveWidth == -1 ) + { + int cuLeftAspectRatio = g_aucLog2[cuLeftWidth] - g_aucLog2[cuLeftHeight]; + return cuLeftAspectRatio < 0 ? false : cuLeftAspectRatio > 0 ? true : cuLeft1dSplit == VER_INTRA_SUBPARTITIONS ? false : true; + } + else if( cuLeftWidth == -1 && cuAboveWidth != -1 ) + { + int cuAboveAspectRatio = g_aucLog2[cuAboveWidth] - g_aucLog2[cuAboveHeight]; + return cuAboveAspectRatio < 0 ? false : cuAboveAspectRatio > 0 ? true : cuAbove1dSplit == VER_INTRA_SUBPARTITIONS ? false : true; + } + else if( cuLeftWidth != -1 && cuAboveWidth != -1 ) + { + int cuLeftAspectRatio = g_aucLog2[cuLeftWidth] - g_aucLog2[cuLeftHeight]; + int cuAboveAspectRatio = g_aucLog2[cuAboveWidth] - g_aucLog2[cuAboveHeight]; + if( cuLeftAspectRatio < 0 && cuAboveAspectRatio < 0 ) + { + return false; + } + else if( cuLeftAspectRatio > 0 && cuAboveAspectRatio > 0 ) + { + return true; + } + else if( cuLeftAspectRatio == 0 && cuAboveAspectRatio == 0 ) + { + if( cuLeft1dSplit != 0 && cuAbove1dSplit != 0 ) + { + return cuLeft1dSplit == VER_INTRA_SUBPARTITIONS && cuAbove1dSplit == VER_INTRA_SUBPARTITIONS ? false : true; + } + else if( cuLeft1dSplit != 0 && cuAbove1dSplit == 0 ) + { + return cuLeft1dSplit == VER_INTRA_SUBPARTITIONS ? false : true; + } + else if( cuLeft1dSplit == 0 && cuAbove1dSplit != 0 ) + { + return cuAbove1dSplit == VER_INTRA_SUBPARTITIONS ? false : true; + } + return true; + } + else + { + return cuLeftAspectRatio > cuAboveAspectRatio ? cuLeftAspectRatio > 0 : cuAboveAspectRatio > 0; + } + //return true; + } + return true; + } +} + +PartSplit CU::getISPType( const CodingUnit &cu, const ComponentID compID ) +{ + if( cu.ispMode && isLuma( compID ) ) + { + const bool tuIsDividedInRows = CU::divideTuInRows( cu ); + + return tuIsDividedInRows ? TU_1D_HORZ_SPLIT : TU_1D_VERT_SPLIT; + } + return TU_NO_ISP; +} + +bool CU::isISPLast( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID ) +{ + PartSplit partitionType = CU::getISPType( cu, compID ); + + Area originalArea = cu.blocks[compID]; + switch( partitionType ) + { + case TU_1D_HORZ_SPLIT: + return tuArea.y + tuArea.height == originalArea.y + originalArea.height; + case TU_1D_VERT_SPLIT: + return tuArea.x + tuArea.width == originalArea.x + originalArea.width; + default: + THROW( "Unknown ISP processing order type!" ); + return false; + } +} + +bool CU::isISPFirst( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID ) +{ + return tuArea == cu.firstTU->blocks[compID]; +} + +ISPType CU::canUseISPSplit( const CodingUnit &cu, const ComponentID compID ) +{ + const int width = cu.blocks[compID].width; + const int height = cu.blocks[compID].height; + const int maxTrSize = cu.cs->sps->getMaxTrSize(); + return CU::canUseISPSplit( width, height, maxTrSize ); +} + +ISPType CU::canUseISPSplit( const int width, const int height, const int maxTrSize ) +{ + bool widthCannotBeUsed = false, heightCannotBeUsed = false; + + const uint32_t minTuSizeForISP = MIN_TU_SIZE; + bool notEnoughSamplesToSplit = ( g_aucLog2[width] + g_aucLog2[height] <= ( g_aucLog2[minTuSizeForISP] << 1 ) ); + widthCannotBeUsed = width > maxTrSize || notEnoughSamplesToSplit; + heightCannotBeUsed = height > maxTrSize || notEnoughSamplesToSplit; + + if( !widthCannotBeUsed && !heightCannotBeUsed ) + { + return CAN_USE_VER_AND_HORL_SPLITS; //both splits can be used + } + else if( widthCannotBeUsed && !heightCannotBeUsed ) + { + return VER_INTRA_SUBPARTITIONS; //only the vertical split can be performed + } + else if( !widthCannotBeUsed && heightCannotBeUsed ) + { + return HOR_INTRA_SUBPARTITIONS; //only the horizontal split can be performed + } + else + { + return NOT_INTRA_SUBPARTITIONS; //neither of the splits can be used + } +} + +uint32_t CU::getISPSplitDim( const int width, const int height, const PartSplit ispType ) +{ + bool divideTuInRows = ispType == TU_1D_HORZ_SPLIT; + uint32_t splitDimensionSize, nonSplitDimensionSize, partitionSize, divShift = 2; + + if( divideTuInRows ) + { + splitDimensionSize = height; + nonSplitDimensionSize = width; + } + else + { + splitDimensionSize = width; + nonSplitDimensionSize = height; + } + const int minNumberOfSamplesPerCu = 1 << ( ( g_aucLog2[MIN_TU_SIZE] << 1 ) ); + const int factorToMinSamples = nonSplitDimensionSize < minNumberOfSamplesPerCu ? minNumberOfSamplesPerCu >> g_aucLog2[nonSplitDimensionSize] : 1; + partitionSize = ( splitDimensionSize >> divShift ) < factorToMinSamples ? factorToMinSamples : ( splitDimensionSize >> divShift ); + + CHECK( g_aucLog2[partitionSize] + g_aucLog2[nonSplitDimensionSize] < g_aucLog2[minNumberOfSamplesPerCu], "A partition has less than the minimum amount of samples!" ); + return partitionSize; +} +#endif PUTraverser CU::traversePUs( CodingUnit& cu ) @@ -319,6 +487,10 @@ int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType { const int numMPMs = NUM_MOST_PROBABLE_MODES; const int extendRefLine = (channelType == CHANNEL_TYPE_LUMA) ? pu.multiRefIdx : 0; +#if JVET_M0102_INTRA_SUBPARTITIONS + const ISPType ispType = isLuma( channelType ) ? ISPType( pu.cu->ispMode ) : NOT_INTRA_SUBPARTITIONS; + const bool isHorSplit = ispType == HOR_INTRA_SUBPARTITIONS; +#endif { int numCand = -1; int leftIntraDir = PLANAR_IDX, aboveIntraDir = PLANAR_IDX; @@ -413,6 +585,116 @@ int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType } } } +#if JVET_M0102_INTRA_SUBPARTITIONS + else if( ispType != NOT_INTRA_SUBPARTITIONS ) + { + //default case + mpm[0] = PLANAR_IDX; + if( isHorSplit ) + { + mpm[1] = HOR_IDX; + mpm[2] = 25; + mpm[3] = 10; + mpm[4] = 65; + mpm[5] = VER_IDX; + } + else + { + mpm[1] = VER_IDX; + mpm[2] = 43; + mpm[3] = 60; + mpm[4] = 3; + mpm[5] = HOR_IDX; + } + int canonicalMode = mpm[1]; + if( leftIntraDir == aboveIntraDir ) //L=A + { + numCand = 1; + if( leftIntraDir > DC_IDX ) + { + mpm[0] = leftIntraDir; + mpm[1] = ( ( leftIntraDir + offset ) % mod ) + 2; + mpm[2] = ( ( leftIntraDir - 1 ) % mod ) + 2; + if( ( isHorSplit && leftIntraDir < DIA_IDX ) || ( !isHorSplit && leftIntraDir >= DIA_IDX ) ) + { + mpm[3] = ( ( leftIntraDir + offset - 1 ) % mod ) + 2; + mpm[4] = ( leftIntraDir % mod ) + 2; + mpm[5] = ( ( leftIntraDir + offset - 2 ) % mod ) + 2;; + } + else + { + if( isHorSplit ) + { + mpm[3] = HOR_IDX; + mpm[4] = 5; + } + else + { + mpm[3] = VER_IDX; + mpm[4] = VDIA_IDX - 3; + } + mpm[5] = PLANAR_IDX; + } + } + } + else //L!=A + { + numCand = 2; + if( ( leftIntraDir > DC_IDX ) && ( aboveIntraDir > DC_IDX ) ) + { + int distLeftToCanonicalMode = abs( leftIntraDir - canonicalMode ); + int distAboveToCanonicalMode = abs( aboveIntraDir - canonicalMode ); + mpm[0] = aboveIntraDir; + mpm[1] = leftIntraDir; + if( distLeftToCanonicalMode <= distAboveToCanonicalMode ) + { + mpm[0] = leftIntraDir; + mpm[1] = aboveIntraDir; + } + int maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1; + int minCandModeIdx = 1 - maxCandModeIdx; + if( mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 1 ) + { + mpm[2] = ( ( mpm[minCandModeIdx] + offset ) % mod ) + 2; + mpm[3] = ( ( mpm[maxCandModeIdx] - 1 ) % mod ) + 2; + mpm[4] = ( ( mpm[minCandModeIdx] + offset - 1 ) % mod ) + 2; + mpm[5] = ( mpm[maxCandModeIdx] % mod ) + 2; + } + else if( mpm[maxCandModeIdx] - mpm[minCandModeIdx] >= 62 ) + { + mpm[2] = ( ( mpm[minCandModeIdx] - 1 ) % mod ) + 2; + mpm[3] = ( ( mpm[maxCandModeIdx] + offset ) % mod ) + 2; + mpm[4] = ( ( mpm[minCandModeIdx] ) % mod ) + 2; + mpm[5] = ( ( mpm[maxCandModeIdx] + offset - 1 ) % mod ) + 2; + } + else if( mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 2 ) + { + mpm[2] = ( ( mpm[minCandModeIdx] - 1 ) % mod ) + 2; + mpm[3] = ( ( mpm[minCandModeIdx] + offset ) % mod ) + 2; + mpm[4] = ( ( mpm[maxCandModeIdx] - 1 ) % mod ) + 2; + mpm[5] = ( ( mpm[minCandModeIdx] + offset - 1 ) % mod ) + 2; + } + else + { + mpm[2] = ( ( mpm[minCandModeIdx] + offset ) % mod ) + 2; + mpm[3] = ( ( mpm[minCandModeIdx] - 1 ) % mod ) + 2; + mpm[4] = ( ( mpm[maxCandModeIdx] + offset ) % mod ) + 2; + mpm[5] = ( ( mpm[maxCandModeIdx] - 1 ) % mod ) + 2; + } + } + else if( leftIntraDir + aboveIntraDir > 2 ) + { + //mpm[0] = PLANAR_IDX; + int angMode = leftIntraDir > DC_IDX ? leftIntraDir : aboveIntraDir; + mpm[1] = angMode; + mpm[2] = ( ( angMode + offset ) % mod ) + 2; + mpm[3] = ( ( angMode - 1 ) % mod ) + 2; + mpm[4] = ( ( angMode + offset - 1 ) % mod ) + 2; + mpm[5] = ( ( angMode ) % mod ) + 2; + } + } + } +#endif else { mpm[0] = leftIntraDir; @@ -4748,6 +5030,9 @@ bool TU::isTSAllowed(const TransformUnit &tu, const ComponentID compID) tsAllowed &= tu.cs->pps->getUseTransformSkip(); tsAllowed &= !tu.cu->transQuantBypass; +#if JVET_M0102_INTRA_SUBPARTITIONS + tsAllowed &= ( !tu.cu->ispMode || !isLuma(compID) ); +#endif SizeType transformSkipMaxSize = 1 << maxSize; tsAllowed &= tu.lwidth() <= transformSkipMaxSize && tu.lheight() <= transformSkipMaxSize; @@ -4762,6 +5047,9 @@ bool TU::isMTSAllowed(const TransformUnit &tu, const ComponentID compID) mtsAllowed &= CU::isIntra( *tu.cu ) ? tu.cs->sps->getSpsNext().getUseIntraMTS() : tu.cs->sps->getSpsNext().getUseInterMTS(); mtsAllowed &= ( tu.lwidth() <= maxSize && tu.lheight() <= maxSize ); +#if JVET_M0102_INTRA_SUBPARTITIONS + mtsAllowed &= !tu.cu->ispMode; +#endif return mtsAllowed; } #else @@ -4925,7 +5213,57 @@ bool TU::needsQP3Offset(const TransformUnit &tu, const ComponentID &compID) #endif +#if JVET_M0102_INTRA_SUBPARTITIONS +TransformUnit* TU::getPrevTU( const TransformUnit &tu, const ComponentID compID ) +{ + TransformUnit* prevTU = tu.prev; + if( prevTU != nullptr && ( prevTU->cu != tu.cu || !prevTU->blocks[compID].valid() ) ) + { + prevTU = nullptr; + } + + return prevTU; +} + +bool TU::getPrevTuCbfAtDepth( const TransformUnit ¤tTu, const ComponentID compID, const int trDepth ) +{ + const TransformUnit* prevTU = getPrevTU( currentTu, compID ); + return ( prevTU != nullptr ) ? TU::getCbfAtDepth( *prevTU, compID, trDepth ) : false; +} + +void TU::getTransformTypeISP( const TransformUnit &tu, const ComponentID compID, int &typeH, int &typeV ) +{ + typeH = DCT2, typeV = DCT2; + const int uiChFinalMode = PU::getFinalIntraMode( *tu.cu->firstPU, toChannelType( compID ) ); + bool intraModeIsEven = uiChFinalMode % 2 == 0; + + if( uiChFinalMode == DC_IDX || uiChFinalMode == 33 || uiChFinalMode == 35 ) + { + typeH = DCT2; + typeV = typeH; + } + else if( uiChFinalMode == PLANAR_IDX || ( uiChFinalMode >= 31 && uiChFinalMode <= 37 ) ) + { + typeH = DST7; + typeV = typeH; + } + else if( ( intraModeIsEven && uiChFinalMode >= 2 && uiChFinalMode <= 30 ) || ( !intraModeIsEven && uiChFinalMode >= 39 && uiChFinalMode <= 65 ) ) + { + typeH = DST7; + typeV = DCT2; + } + else if( ( !intraModeIsEven && uiChFinalMode >= 3 && uiChFinalMode <= 29 ) || ( intraModeIsEven && uiChFinalMode >= 38 && uiChFinalMode <= 66 ) ) + { + typeH = DCT2; + typeV = DST7; + } + //Size restriction for non-DCT-II transforms + Area tuArea = tu.blocks[compID]; + typeH = tuArea.width <= 2 || tuArea.width >= 32 ? DCT2 : typeH; + typeV = tuArea.height <= 2 || tuArea.height >= 32 ? DCT2 : typeV; +} +#endif // other tools diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 2e30af9bb25a4c4d2274ffe0096e6569672f1a7c..27d400023d3feef96d3357a5f7b686e1276602a9 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -89,6 +89,17 @@ namespace CU void setGbiIdx (CodingUnit& cu, uint8_t uh); uint8_t deriveGbiIdx (uint8_t gbiLO, uint8_t gbiL1); +#if JVET_M0102_INTRA_SUBPARTITIONS + bool divideTuInRows ( const CodingUnit &cu ); + bool firstTestISPHorSplit ( const int width, const int height, const ComponentID compID, const CodingUnit *cuLeft = nullptr, const CodingUnit *cuAbove = nullptr ); + PartSplit getISPType ( const CodingUnit &cu, const ComponentID compID ); + bool isISPLast ( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID ); + bool isISPFirst ( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID ); + ISPType canUseISPSplit ( const CodingUnit &cu, const ComponentID compID ); + ISPType canUseISPSplit ( const int width, const int height, const int maxTrSize = MAX_TU_SIZE ); + uint32_t getISPSplitDim ( const int width, const int height, const PartSplit ispType ); +#endif + PUTraverser traversePUs ( CodingUnit& cu); TUTraverser traverseTUs ( CodingUnit& cu); cPUTraverser traversePUs (const CodingUnit& cu); @@ -224,6 +235,11 @@ namespace TU #else bool needsQP3Offset (const TransformUnit &tu, const ComponentID &compID); #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + TransformUnit* getPrevTU ( const TransformUnit &tu, const ComponentID compID ); + bool getPrevTuCbfAtDepth( const TransformUnit &tu, const ComponentID compID, const int trDepth ); + void getTransformTypeISP( const TransformUnit &tu, const ComponentID compID, int &typeH, int &typeV ); +#endif } uint32_t getCtuAddr (const Position& pos, const PreCalcValues &pcv); diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index bd9ff0f130a4937cb1945d5b3de3e3da4c9648b2..0ab7f1eb51e09cdfc47e0c35c764f5c8eb99ee01 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -924,6 +924,9 @@ bool CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx& extend_ref_line( cu ); +#if JVET_M0102_INTRA_SUBPARTITIONS + isp_mode( cu ); +#endif // prediction data ( intra prediction modes / reference indexes + motion vectors ) cu_pred_data( cu ); @@ -1239,7 +1242,11 @@ void CABACReader::intra_luma_pred_modes( CodingUnit &cu ) for( int k = 0; k < numBlocks; k++ ) { CHECK(numBlocks != 1, "not supported yet"); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.firstPU->multiRefIdx || ( cu.ispMode && isLuma( cu.chType ) ) ) +#else if (cu.firstPU->multiRefIdx) +#endif { mpmFlag[0] = true; } @@ -1389,7 +1396,19 @@ void CABACReader::cu_residual( CodingUnit& cu, Partitioner &partitioner, CUCtx& } ChromaCbfs chromaCbfs; +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.ispMode && isLuma( partitioner.chType ) ) + { + TUIntraSubPartitioner subTuPartitioner( partitioner ); + transform_tree( *cu.cs, subTuPartitioner, cuCtx, chromaCbfs, CU::getISPType( cu, getFirstComponentOfChannel( partitioner.chType ) ), 0 ); + } + else + { + transform_tree( *cu.cs, partitioner, cuCtx, chromaCbfs ); + } +#else transform_tree( *cu.cs, partitioner, cuCtx, chromaCbfs ); +#endif } void CABACReader::rqt_root_cbf( CodingUnit& cu ) @@ -2096,23 +2115,53 @@ void CABACReader::pcm_samples( TransformUnit& tu ) // bool cbf_comp ( area, depth ) //================================================================================ +#if JVET_M0102_INTRA_SUBPARTITIONS +void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, CUCtx& cuCtx, ChromaCbfs& chromaCbfs, const PartSplit ispType, const int subTuIdx ) +#else void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, CUCtx& cuCtx, ChromaCbfs& chromaCbfs ) +#endif { const UnitArea& area = partitioner.currArea(); CodingUnit& cu = *cs.getCU( area.blocks[partitioner.chType], partitioner.chType ); const unsigned trDepth = partitioner.currTrDepth; +#if JVET_M0102_INTRA_SUBPARTITIONS + int subTuCounter = subTuIdx; +#endif // split_transform_flag bool split = false; split = partitioner.canSplit( TU_MAX_TR_SPLIT, cs ); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !split && cu.ispMode ) + { + split = partitioner.canSplit( ispType, cs ); + } + const bool chromaCbfISP = area.blocks[COMPONENT_Cb].valid() && cu.ispMode && !split; +#endif + // cbf_cb & cbf_cr +#if JVET_M0102_INTRA_SUBPARTITIONS + if( area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && ( !CS::isDualITree( cs ) || 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 ) ) +#endif { { { +#if JVET_M0102_INTRA_SUBPARTITIONS + const int cbfDepth = chromaCbfISP ? trDepth - 1 : trDepth; + if( chromaCbfs.Cb ) + { + chromaCbfs.Cb &= cbf_comp( cs, area.blocks[COMPONENT_Cb], cbfDepth ); + } + if( chromaCbfs.Cr ) + { + chromaCbfs.Cr &= cbf_comp( cs, area.blocks[COMPONENT_Cr], cbfDepth, chromaCbfs.Cb ); + } +#else if( chromaCbfs.Cb ) { chromaCbfs.Cb &= cbf_comp( cs, area.blocks[COMPONENT_Cb], trDepth ); @@ -2121,6 +2170,7 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, { chromaCbfs.Cr &= cbf_comp( cs, area.blocks[COMPONENT_Cr], trDepth, chromaCbfs.Cb ); } +#endif } } } @@ -2133,7 +2183,11 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, { { #if !JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + if( trDepth == 0 && !cu.ispMode ) emt_cu_flag( cu ); +#else if( trDepth == 0 ) emt_cu_flag( cu ); +#endif #endif if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) @@ -2145,6 +2199,12 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, #endif partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); } +#if JVET_M0102_INTRA_SUBPARTITIONS + else if( cu.ispMode ) + { + partitioner.splitCurrArea( ispType, cs ); + } +#endif else THROW( "Implicit TU split not available!" ); } @@ -2152,7 +2212,12 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, do { ChromaCbfs subCbfs = chromaCbfs; +#if JVET_M0102_INTRA_SUBPARTITIONS + transform_tree( cs, partitioner, cuCtx, subCbfs, ispType, subTuCounter ); + subTuCounter += subTuCounter != -1 ? 1 : 0; +#else transform_tree( cs, partitioner, cuCtx, subCbfs ); +#endif } while( partitioner.nextPart( cs ) ); partitioner.exitCurrSplit(); @@ -2162,7 +2227,17 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, const unsigned numTBlocks = getNumberValidTBlocks( *cs.pcv ); unsigned compCbf[3] = { 0, 0, 0 }; - +#if JVET_M0102_INTRA_SUBPARTITIONS + unsigned cbfDepth = 0; + for( auto &currTU : cs.traverseTUs( currArea, partitioner.chType ) ) + { + for( unsigned ch = 0; ch < numTBlocks; ch++ ) + { + cbfDepth = !isLuma( ComponentID( ch ) ) && cu.ispMode ? currDepth : currDepth + 1; + compCbf[ch] |= ( TU::getCbfAtDepth( currTU, ComponentID( ch ), cbfDepth ) ? 1 : 0 ); + } + } +#else for( auto &currTU : cs.traverseTUs( currArea, partitioner.chType ) ) { for( unsigned ch = 0; ch < numTBlocks; ch++ ) @@ -2170,6 +2245,7 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, compCbf[ch] |= ( TU::getCbfAtDepth( currTU, ComponentID( ch ), currDepth + 1 ) ? 1 : 0 ); } } +#endif { @@ -2208,11 +2284,43 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, } else { +#if JVET_M0102_INTRA_SUBPARTITIONS + bool previousCbf = false; + bool rootCbfSoFar = false; + bool lastCbfIsInferred = false; + if( cu.ispMode ) + { + uint32_t nTus = cu.ispMode == HOR_INTRA_SUBPARTITIONS ? cu.lheight() >> g_aucLog2[tu.lheight()] : cu.lwidth() >> g_aucLog2[tu.lwidth()]; + if( subTuCounter == nTus - 1 ) + { + TransformUnit* tuPointer = cu.firstTU; + for( int tuIdx = 0; tuIdx < nTus - 1; tuIdx++ ) + { + rootCbfSoFar |= TU::getCbfAtDepth( *tuPointer, COMPONENT_Y, trDepth ); + tuPointer = tuPointer->next; + } + if( !rootCbfSoFar ) + { + lastCbfIsInferred = true; + } + } + if( !lastCbfIsInferred ) + { + previousCbf = TU::getPrevTuCbfAtDepth( tu, COMPONENT_Y, trDepth ); + } + } + bool cbfY = lastCbfIsInferred ? true : cbf_comp( cs, tu.Y(), trDepth, previousCbf, cu.ispMode ); +#else bool cbfY = cbf_comp( cs, tu.Y(), trDepth ); +#endif TU::setCbfAtDepth( tu, COMPONENT_Y, trDepth, ( cbfY ? 1 : 0 ) ); } } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( area.chromaFormat != CHROMA_400 && ( !cu.ispMode || chromaCbfISP ) ) +#else if( area.chromaFormat != CHROMA_400 ) +#endif { TU::setCbfAtDepth( tu, COMPONENT_Cb, trDepth, ( chromaCbfs.Cb ? 1 : 0 ) ); TU::setCbfAtDepth( tu, COMPONENT_Cr, trDepth, ( chromaCbfs.Cr ? 1 : 0 ) ); @@ -2226,9 +2334,15 @@ void CABACReader::transform_tree( CodingStructure &cs, Partitioner &partitioner, } } +#if JVET_M0102_INTRA_SUBPARTITIONS +bool CABACReader::cbf_comp( CodingStructure& cs, const CompArea& area, unsigned depth, const bool prevCbf, const bool useISP ) +{ + const unsigned ctxId = DeriveCtx::CtxQtCbf( area.compID, depth, prevCbf, useISP && isLuma( area.compID ) ); +#else bool CABACReader::cbf_comp( CodingStructure& cs, const CompArea& area, unsigned depth, const bool prevCbCbf ) { const unsigned ctxId = DeriveCtx::CtxQtCbf( area.compID, depth, prevCbCbf ); +#endif const CtxSet& ctxSet = Ctx::QtCbf[ area.compID ]; RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2(STATS__CABAC_BITS__QT_CBF, area.size(), area.compID); @@ -2464,6 +2578,9 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID ) #if !JVET_M0464_UNI_MTS bool useEmt = ( cu.cs->sps->getSpsNext().getUseIntraEMT() && cu.predMode == MODE_INTRA ) || ( cu.cs->sps->getSpsNext().getUseInterEMT() && cu.predMode != MODE_INTRA ); useEmt = useEmt && isLuma(compID); +#if JVET_M0102_INTRA_SUBPARTITIONS + useEmt = useEmt && !cu.ispMode; +#endif #endif for( int subSetId = ( cctx.scanPosLast() >> cctx.log2CGSize() ); subSetId >= 0; subSetId--) @@ -2542,8 +2659,11 @@ void CABACReader::mts_coding( TransformUnit& tu, ComponentID compID ) #else void CABACReader::transform_skip_flag( TransformUnit& tu, ComponentID compID ) { - +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !tu.cu->cs->pps->getUseTransformSkip() || tu.cu->transQuantBypass || !TU::hasTransformSkipFlag( *tu.cs, tu.blocks[compID] ) || ( isLuma( compID ) && tu.cu->emtFlag ) || ( tu.cu->ispMode && isLuma( compID ) ) ) +#else if( !tu.cu->cs->pps->getUseTransformSkip() || tu.cu->transQuantBypass || !TU::hasTransformSkipFlag( *tu.cs, tu.blocks[compID] ) || ( isLuma( compID ) && tu.cu->emtFlag ) ) +#endif { tu.transformSkip[compID] = false; return; @@ -2587,6 +2707,12 @@ void CABACReader::emt_tu_index( TransformUnit& tu ) void CABACReader::emt_cu_flag( CodingUnit& cu ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + if ( CU::isIntra( cu ) && cu.ispMode ) + { + return; + } +#endif const CodingStructure &cs = *cu.cs; if( !( ( cs.sps->getSpsNext().getUseIntraEMT() && CU::isIntra( cu ) ) || ( cs.sps->getSpsNext().getUseInterEMT() && CU::isInter( cu ) ) ) || isChroma( cu.chType ) ) @@ -2620,6 +2746,46 @@ void CABACReader::emt_cu_flag( CodingUnit& cu ) } #endif +#if JVET_M0102_INTRA_SUBPARTITIONS +void CABACReader::isp_mode( CodingUnit& cu ) +{ + if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx ) + { + cu.ispMode = NOT_INTRA_SUBPARTITIONS; + return; + } + + const ISPType allowedSplits = CU::canUseISPSplit( cu, getFirstComponentOfChannel( cu.chType ) ); + if( allowedSplits == NOT_INTRA_SUBPARTITIONS ) + { + cu.ispMode = NOT_INTRA_SUBPARTITIONS; + return; + } + + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__ISP_MODE_FLAG ); + cu.ispMode = NOT_INTRA_SUBPARTITIONS; + int symbol = m_BinDecoder.decodeBin( Ctx::ISPMode( 0 ) ); + + if( symbol ) + { + if( allowedSplits == HOR_INTRA_SUBPARTITIONS ) + { + cu.ispMode = HOR_INTRA_SUBPARTITIONS; + } + else if( allowedSplits == VER_INTRA_SUBPARTITIONS ) + { + cu.ispMode = VER_INTRA_SUBPARTITIONS; + } + else + { + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__ISP_SPLIT_FLAG ); + cu.ispMode = 1 + m_BinDecoder.decodeBin( Ctx::ISPMode( 1 ) ); + } + } + DTRACE( g_trace_ctx, D_SYNTAX, "intra_subPartitions() etype=%d pos=(%d,%d) ispIdx=%d\n", cu.chType, cu.blocks[cu.chType].x, cu.blocks[cu.chType].y, (int)cu.ispMode ); +} +#endif + void CABACReader::explicit_rdpcm_mode( TransformUnit& tu, ComponentID compID ) { const CodingUnit& cu = *tu.cu; diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 29e463caafb6d2e4ee3a6cb904c156e50601c4e8..941be20b9b125d72668365312bc8fb603a9a2a49 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -124,8 +124,13 @@ public: void pcm_samples ( TransformUnit& tu ); // transform tree (clause 7.3.8.8) +#if JVET_M0102_INTRA_SUBPARTITIONS + void transform_tree ( CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, ChromaCbfs& chromaCbfs, const PartSplit ispType = TU_NO_ISP, const int subTuIdx = -1 ); + bool cbf_comp ( CodingStructure& cs, const CompArea& area, unsigned depth, const bool prevCbCbf = false, const bool useISP = false ); +#else void transform_tree ( CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, ChromaCbfs& chromaCbfs ); bool cbf_comp ( CodingStructure& cs, const CompArea& area, unsigned depth, const bool prevCbCbf = false ); +#endif // mvd coding (clause 7.3.8.9) void mvd_coding ( Mv &rMvd ); @@ -143,6 +148,9 @@ public: void transform_skip_flag ( TransformUnit& tu, ComponentID compID ); void emt_tu_index ( TransformUnit& tu ); void emt_cu_flag ( CodingUnit& cu ); +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + void isp_mode ( CodingUnit& cu ); #endif void explicit_rdpcm_mode ( TransformUnit& tu, ComponentID compID ); int last_sig_coeff ( CoeffCodingContext& cctx ); diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index 56c3ac80fa98e6517bfdb474930b08c4afcf4f3f..baaf5739a88746a282c8c18a17933a2f49d49630 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -253,7 +253,18 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) PelBuf pReco = cs.getRecoBuf( area ); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !tu.cu->ispMode || !isLuma( compID ) ) + { + cs.setDecomp( area ); + } + else if( tu.cu->ispMode && isLuma( compID ) && CU::isISPFirst( *tu.cu, tu.blocks[compID], compID ) ) + { + cs.setDecomp( tu.cu->blocks[compID] ); + } +#else cs.setDecomp( area ); +#endif #if JVET_M0427_INLOOP_RESHAPER #if REUSE_CU_RESULTS diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 0c5ca538c96f879290883445226651cc5e6b8f07..4323228d3b5cad6969d0f40fd5283e516b206a87 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -745,6 +745,9 @@ void CABACWriter::coding_unit( const CodingUnit& cu, Partitioner& partitioner, C extend_ref_line(cu); +#if JVET_M0102_INTRA_SUBPARTITIONS + isp_mode( cu ); +#endif // prediction data ( intra prediction modes / reference indexes + motion vectors ) cu_pred_data( cu ); @@ -1015,7 +1018,11 @@ void CABACWriter::intra_luma_pred_modes( const CodingUnit& cu ) break; } } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( pu->multiRefIdx || ( cu.ispMode && isLuma( cu.chType ) ) ) +#else if (pu->multiRefIdx) +#endif { CHECK(mpm_idx >= numMPMs, "use of non-MPM"); } @@ -1100,7 +1107,11 @@ void CABACWriter::intra_luma_pred_mode( const PredictionUnit& pu ) break; } } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( pu.multiRefIdx || ( pu.cu->ispMode && isLuma( pu.cu->chType ) ) ) +#else if (pu.multiRefIdx) +#endif { CHECK(mpm_idx >= numMPMs, "use of non-MPM"); } @@ -1240,7 +1251,19 @@ void CABACWriter::cu_residual( const CodingUnit& cu, Partitioner& partitioner, C ChromaCbfs chromaCbfs; +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.ispMode && isLuma( partitioner.chType ) ) + { + TUIntraSubPartitioner subTuPartitioner( partitioner ); + transform_tree( *cu.cs, subTuPartitioner, cuCtx, chromaCbfs, CU::getISPType( cu, getFirstComponentOfChannel( partitioner.chType ) ), 0 ); + } + else + { + transform_tree( *cu.cs, partitioner, cuCtx, chromaCbfs ); + } +#else transform_tree( *cu.cs, partitioner, cuCtx, chromaCbfs ); +#endif } void CABACWriter::rqt_root_cbf( const CodingUnit& cu ) @@ -1939,13 +1962,25 @@ void CABACWriter::pcm_samples( const TransformUnit& tu ) // bool cbf_comp ( cbf, area, depth ) //================================================================================ +#if JVET_M0102_INTRA_SUBPARTITIONS +void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partitioner, CUCtx& cuCtx, ChromaCbfs& chromaCbfs, const PartSplit ispType, const int subTuIdx ) +#else void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partitioner, CUCtx& cuCtx, ChromaCbfs& chromaCbfs ) +#endif { const UnitArea& area = partitioner.currArea(); +#if JVET_M0102_INTRA_SUBPARTITIONS + int subTuCounter = subTuIdx; + const TransformUnit& tu = *cs.getTU( area.blocks[partitioner.chType].pos(), partitioner.chType, subTuIdx ); +#else const TransformUnit& tu = *cs.getTU( area.blocks[partitioner.chType].pos(), partitioner.chType ); +#endif const CodingUnit& cu = *tu.cu; const unsigned trDepth = partitioner.currTrDepth; const bool split = ( tu.depth > trDepth ); +#if JVET_M0102_INTRA_SUBPARTITIONS + const bool chromaCbfISP = area.blocks[COMPONENT_Cb].valid() && cu.ispMode && !split; +#endif // split_transform_flag if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) @@ -1953,12 +1988,43 @@ void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partit CHECK( !split, "transform split implied" ); } else +#if JVET_M0102_INTRA_SUBPARTITIONS + CHECK( split && !cu.ispMode, "transform split not allowed with QTBT" ); +#else CHECK( split, "transform split not allowed with QTBT" ); +#endif + // cbf_cb & cbf_cr +#if JVET_M0102_INTRA_SUBPARTITIONS + if( area.chromaFormat != CHROMA_400 && area.blocks[COMPONENT_Cb].valid() && ( !CS::isDualITree( cs ) || 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 ) ) +#endif { { +#if JVET_M0102_INTRA_SUBPARTITIONS + unsigned cbfDepth = chromaCbfISP ? trDepth - 1 : trDepth; + if( trDepth == 0 || chromaCbfs.Cb || chromaCbfISP ) + { + chromaCbfs.Cb = TU::getCbfAtDepth( tu, COMPONENT_Cb, trDepth ); + cbf_comp( cs, chromaCbfs.Cb, area.blocks[COMPONENT_Cb], cbfDepth ); + } + else + { + CHECK( TU::getCbfAtDepth( tu, COMPONENT_Cb, cbfDepth ) != chromaCbfs.Cb, "incorrect Cb cbf" ); + } + + if( trDepth == 0 || chromaCbfs.Cr || chromaCbfISP ) + { + chromaCbfs.Cr = TU::getCbfAtDepth( tu, COMPONENT_Cr, trDepth ); + cbf_comp( cs, chromaCbfs.Cr, area.blocks[COMPONENT_Cr], cbfDepth, chromaCbfs.Cb ); + } + else + { + CHECK( TU::getCbfAtDepth( tu, COMPONENT_Cr, cbfDepth ) != chromaCbfs.Cr, "incorrect Cr cbf" ); + } +#else if( trDepth == 0 || chromaCbfs.Cb ) { chromaCbfs.Cb = TU::getCbfAtDepth( tu, COMPONENT_Cb, trDepth ); @@ -1978,6 +2044,7 @@ void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partit { CHECK( TU::getCbfAtDepth( tu, COMPONENT_Cr, trDepth ) != chromaCbfs.Cr, "incorrect Cr cbf" ); } +#endif } } else if( CS::isDualITree( cs ) ) @@ -1993,7 +2060,11 @@ void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partit chromaCbfs.Cr = TU::getCbfAtDepth( tu, COMPONENT_Cr, trDepth ); } #if !JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + if ( trDepth == 0 && !cu.ispMode ) emt_cu_flag( cu ); +#else if( trDepth == 0 ) emt_cu_flag( cu ); +#endif #endif if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) @@ -2005,13 +2076,24 @@ void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partit #endif partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); } +#if JVET_M0102_INTRA_SUBPARTITIONS + else if( cu.ispMode ) + { + partitioner.splitCurrArea( ispType, cs ); + } +#endif else THROW( "Implicit TU split not available" ); do { ChromaCbfs subChromaCbfs = chromaCbfs; +#if JVET_M0102_INTRA_SUBPARTITIONS + transform_tree( cs, partitioner, cuCtx, subChromaCbfs, ispType, subTuCounter ); + subTuCounter += subTuCounter != -1 ? 1 : 0; +#else transform_tree( cs, partitioner, cuCtx, subChromaCbfs ); +#endif } while( partitioner.nextPart( cs ) ); partitioner.exitCurrSplit(); @@ -2028,7 +2110,38 @@ void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partit } else { +#if JVET_M0102_INTRA_SUBPARTITIONS + bool previousCbf = false; + bool rootCbfSoFar = false; + bool lastCbfIsInferred = false; + if( cu.ispMode ) + { + uint32_t nTus = cu.ispMode == HOR_INTRA_SUBPARTITIONS ? cu.lheight() >> g_aucLog2[tu.lheight()] : cu.lwidth() >> g_aucLog2[tu.lwidth()]; + if( subTuCounter == nTus - 1 ) + { + TransformUnit* tuPointer = cu.firstTU; + for( int tuIdx = 0; tuIdx < subTuCounter; tuIdx++ ) + { + rootCbfSoFar |= TU::getCbfAtDepth( *tuPointer, COMPONENT_Y, trDepth ); + tuPointer = tuPointer->next; + } + if( !rootCbfSoFar ) + { + lastCbfIsInferred = true; + } + } + if( !lastCbfIsInferred ) + { + previousCbf = TU::getPrevTuCbfAtDepth( tu, COMPONENT_Y, partitioner.currTrDepth ); + } + } + if( !lastCbfIsInferred ) + { + cbf_comp( cs, TU::getCbfAtDepth( tu, COMPONENT_Y, trDepth ), tu.Y(), trDepth, previousCbf, cu.ispMode ); + } +#else cbf_comp( cs, TU::getCbfAtDepth( tu, COMPONENT_Y, trDepth ), tu.Y(), trDepth ); +#endif } } @@ -2040,9 +2153,15 @@ void CABACWriter::transform_tree( const CodingStructure& cs, Partitioner& partit } } +#if JVET_M0102_INTRA_SUBPARTITIONS +void CABACWriter::cbf_comp( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbCbf, const bool useISP ) +{ + const unsigned ctxId = DeriveCtx::CtxQtCbf( area.compID, depth, prevCbCbf, useISP && isLuma(area.compID) ); +#else void CABACWriter::cbf_comp( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbCbf ) { const unsigned ctxId = DeriveCtx::CtxQtCbf( area.compID, depth, prevCbCbf ); +#endif const CtxSet& ctxSet = Ctx::QtCbf[ area.compID ]; m_BinEncoder.encodeBin( cbf, ctxSet( ctxId ) ); @@ -2306,6 +2425,9 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID ) #if !JVET_M0464_UNI_MTS bool useEmt = ( cu.cs->sps->getSpsNext().getUseIntraEMT() && cu.predMode == MODE_INTRA ) || ( cu.cs->sps->getSpsNext().getUseInterEMT() && cu.predMode != MODE_INTRA ); useEmt = useEmt && isLuma(compID); +#if JVET_M0102_INTRA_SUBPARTITIONS + useEmt = useEmt && !cu.ispMode; +#endif #endif for( int subSetId = ( cctx.scanPosLast() >> cctx.log2CGSize() ); subSetId >= 0; subSetId--) @@ -2387,7 +2509,11 @@ void CABACWriter::mts_coding( const TransformUnit& tu, ComponentID compID ) #else void CABACWriter::transform_skip_flag( const TransformUnit& tu, ComponentID compID ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + if (!tu.cu->cs->pps->getUseTransformSkip() || tu.cu->transQuantBypass || !TU::hasTransformSkipFlag(*tu.cs, tu.blocks[compID]) || (isLuma(compID) && tu.cu->emtFlag) || (tu.cu->ispMode && isLuma(compID))) +#else if( !tu.cu->cs->pps->getUseTransformSkip() || tu.cu->transQuantBypass || !TU::hasTransformSkipFlag( *tu.cs, tu.blocks[compID] ) || ( isLuma( compID ) && tu.cu->emtFlag ) ) +#endif { return; } @@ -2420,6 +2546,12 @@ void CABACWriter::emt_tu_index( const TransformUnit& tu ) //void CABACWriter::emt_cu_flag(const CodingUnit& cu, uint32_t depth, bool codeCuFlag, const int tuWidth,const int tuHeight) void CABACWriter::emt_cu_flag( const CodingUnit& cu ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + if ( CU::isIntra( cu ) && cu.ispMode ) + { + return; + } +#endif const CodingStructure& cs = *cu.cs; if( !( ( cs.sps->getSpsNext().getUseIntraEMT() && CU::isIntra( cu ) ) || ( cs.sps->getSpsNext().getUseInterEMT() && CU::isInter( cu ) ) ) || isChroma( cu.chType ) ) @@ -2448,6 +2580,33 @@ void CABACWriter::emt_cu_flag( const CodingUnit& cu ) } #endif +#if JVET_M0102_INTRA_SUBPARTITIONS +void CABACWriter::isp_mode( const CodingUnit& cu ) +{ + if( !CU::isIntra( cu ) || !isLuma( cu.chType ) || cu.firstPU->multiRefIdx ) + { + CHECK( cu.ispMode != NOT_INTRA_SUBPARTITIONS, "error: cu.intraSubPartitions != 0" ); + return; + } + const ISPType allowedSplits = CU::canUseISPSplit( cu, getFirstComponentOfChannel( cu.chType ) ); + if( allowedSplits == NOT_INTRA_SUBPARTITIONS ) return; + + if( cu.ispMode == NOT_INTRA_SUBPARTITIONS ) + { + m_BinEncoder.encodeBin( 0, Ctx::ISPMode( 0 ) ); + } + else + { + m_BinEncoder.encodeBin( 1, Ctx::ISPMode( 0 ) ); + + if( allowedSplits == CAN_USE_VER_AND_HORL_SPLITS ) + { + m_BinEncoder.encodeBin( cu.ispMode - 1, Ctx::ISPMode( 1 ) ); + } + } + DTRACE( g_trace_ctx, D_SYNTAX, "intra_subPartitions() etype=%d pos=(%d,%d) ispIdx=%d\n", cu.chType, cu.blocks[cu.chType].x, cu.blocks[cu.chType].y, (int)cu.ispMode ); +} +#endif void CABACWriter::explicit_rdpcm_mode( const TransformUnit& tu, ComponentID compID ) { diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index 51fbd8ddd98eb5705e26d18101e03cac957d3264..8ddd3c5fcb0eae3260426fcd6a559e17bb859de3 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -135,8 +135,13 @@ public: void pcm_samples ( const TransformUnit& tu ); // transform tree (clause 7.3.8.8) +#if JVET_M0102_INTRA_SUBPARTITIONS + void transform_tree ( const CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, ChromaCbfs& chromaCbfs, const PartSplit ispType = TU_NO_ISP, const int subTuIdx = -1 ); + void cbf_comp ( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbCbf = false, const bool useISP = false ); +#else void transform_tree ( const CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, ChromaCbfs& chromaCbfs ); void cbf_comp ( const CodingStructure& cs, bool cbf, const CompArea& area, unsigned depth, const bool prevCbCbf = false ); +#endif // mvd coding (clause 7.3.8.9) #if JVET_M0246_AFFINE_AMVR @@ -157,6 +162,9 @@ public: void transform_skip_flag ( const TransformUnit& tu, ComponentID compID ); void emt_tu_index ( const TransformUnit& tu ); void emt_cu_flag ( const CodingUnit& cu ); +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + void isp_mode ( const CodingUnit& cu ); #endif void explicit_rdpcm_mode ( const TransformUnit& tu, ComponentID compID ); void last_sig_coeff ( CoeffCodingContext& cctx ); diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 4271515528d26af2b720baa47e09598919279742..d91e00e72fe74d49738980306ee455b0e859d531 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -323,6 +323,9 @@ void EncCu::init( EncLib* pcEncLib, const SPS& sps PARL_PARAM( const int tId ) ) m_modeCtrl->init( m_pcEncCfg, m_pcRateCtrl, m_pcRdCost ); m_pcInterSearch->setModeCtrl( m_modeCtrl ); +#if JVET_M0102_INTRA_SUBPARTITIONS + m_pcIntraSearch->setModeCtrl( m_modeCtrl ); +#endif ::memset(m_subMergeBlkSize, 0, sizeof(m_subMergeBlkSize)); ::memset(m_subMergeBlkNum, 0, sizeof(m_subMergeBlkNum)); m_prevPOC = MAX_UINT; @@ -1464,6 +1467,13 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC uint8_t considerEmtSecondPass = ( sps.getSpsNext().getUseIntraEMT() && isLuma( partitioner.chType ) && partitioner.currArea().lwidth() <= maxSizeEMT && partitioner.currArea().lheight() <= maxSizeEMT ) ? 1 : 0; #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + bool useIntraSubPartitions = false; + double maxCostAllowedForChroma = MAX_DOUBLE; +#if JVET_M0464_UNI_MTS + const CodingUnit *bestCU = bestCS->getCU( partitioner.chType ); +#endif +#endif Distortion interHad = m_modeCtrl->getInterHad(); @@ -1504,6 +1514,9 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC #if !JVET_M0464_UNI_MTS cu.emtFlag = emtCuFlag; #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + cu.ispMode = NOT_INTRA_SUBPARTITIONS; +#endif CU::addPUs( cu ); @@ -1511,7 +1524,24 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC if( isLuma( partitioner.chType ) ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + //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 + const double bestCostSoFar = CS::isDualITree( *tempCS ) ? m_modeCtrl->getBestCostWithoutSplitFlags() : bestCU && bestCU->predMode == MODE_INTRA ? bestCS->lumaCost : bestCS->cost; + m_pcIntraSearch->estIntraPredLumaQT( cu, partitioner, bestCostSoFar ); + + useIntraSubPartitions = cu.ispMode != NOT_INTRA_SUBPARTITIONS; + if( !CS::isDualITree( *tempCS ) ) + { + tempCS->lumaCost = m_pcRdCost->calcRdCost( tempCS->fracBits, tempCS->dist ); + if( useIntraSubPartitions ) + { + //the difference between the best cost so far and the current luma cost is stored to avoid testing the Cr component if the cost of luma + Cb is larger than the best cost + maxCostAllowedForChroma = bestCS->cost < MAX_DOUBLE ? bestCS->cost - tempCS->lumaCost : MAX_DOUBLE; + } + } +#else m_pcIntraSearch->estIntraPredLumaQT( cu, partitioner ); +#endif if (m_pcEncCfg->getUsePbIntraFast() && tempCS->dist == std::numeric_limits<Distortion>::max() && tempCS->interHad == 0) @@ -1537,7 +1567,21 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC if( tempCS->area.chromaFormat != CHROMA_400 && ( partitioner.chType == CHANNEL_TYPE_CHROMA || !CS::isDualITree( *tempCS ) ) ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + TUIntraSubPartitioner subTuPartitioner( partitioner ); + m_pcIntraSearch->estIntraPredChromaQT( cu, ( !useIntraSubPartitions || ( CS::isDualITree( *cu.cs ) && !isLuma( CHANNEL_TYPE_CHROMA ) ) ) ? partitioner : subTuPartitioner, maxCostAllowedForChroma ); + if( useIntraSubPartitions && !cu.ispMode ) + { + //At this point the temp cost is larger than the best cost. Therefore, we can already skip the remaining calculations +#if JVET_M0464_UNI_MTS + return; +#else + continue; +#endif + } +#else m_pcIntraSearch->estIntraPredChromaQT( cu, partitioner ); +#endif } cu.rootCbf = false; @@ -1563,6 +1607,9 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC } m_CABACEstimator->pred_mode ( cu ); m_CABACEstimator->extend_ref_line( cu ); +#if JVET_M0102_INTRA_SUBPARTITIONS + m_CABACEstimator->isp_mode ( cu ); +#endif m_CABACEstimator->cu_pred_data ( cu ); m_CABACEstimator->pcm_data ( cu, partitioner ); @@ -1575,10 +1622,22 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC tempCS->fracBits = m_CABACEstimator->getEstFracBits(); tempCS->cost = m_pcRdCost->calcRdCost(tempCS->fracBits, tempCS->dist); +#if JVET_M0102_INTRA_SUBPARTITIONS +#if !JVET_M0464_UNI_MTS + double bestIspCost = cu.ispMode ? CS::isDualITree(*tempCS) ? tempCS->cost : tempCS->lumaCost : MAX_DOUBLE; +#endif + const double tmpCostWithoutSplitFlags = tempCS->cost; +#endif xEncodeDontSplit( *tempCS, partitioner ); xCheckDQP( *tempCS, partitioner ); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( tempCS->cost < bestCS->cost ) + { + m_modeCtrl->setBestCostWithoutSplitFlags( tmpCostWithoutSplitFlags ); + } +#endif #if !JVET_M0464_UNI_MTS // we save the cost of the modes for the first EMT pass if( !emtCuFlag ) static_cast< double& >( costSize2Nx2NemtFirstPass ) = tempCS->cost; @@ -1592,6 +1651,22 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC xCheckBestMode( tempCS, bestCS, partitioner, encTestMode ); #if !JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + //we decide to skip the second emt pass or not according to the ISP results + if (considerEmtSecondPass && cu.ispMode && !emtCuFlag && tempCS->slice->isIntra()) + { + double bestCostDct2NoIsp = m_modeCtrl->getEmtFirstPassNoIspCost(); + CHECKD(bestCostDct2NoIsp <= bestIspCost, "wrong cost!"); + double nSamples = (double)(cu.lwidth() << g_aucLog2[cu.lheight()]); + double threshold = 1 + 1.4 / sqrt(nSamples); + if (bestCostDct2NoIsp > bestIspCost*threshold) + { + skipSecondEmtPass = true; + m_modeCtrl->setSkipSecondEMTPass(true); + break; + } + } +#endif //now we check whether the second pass of SIZE_2Nx2N and the whole Intra SIZE_NxN should be skipped or not if( !emtCuFlag && !tempCS->slice->isIntra() && bestCU && bestCU->predMode != MODE_INTRA && m_pcEncCfg->getFastInterEMT() ) { diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp index 560a59cf5cb805694c73e311f5cbabb52ee2baeb..6e175ebeff5ed0d4452611186602876b1304de14 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.cpp +++ b/source/Lib/EncoderLib/EncModeCtrl.cpp @@ -635,7 +635,15 @@ void BestEncInfoCache::create( const ChromaFormat chFmt ) m_bestEncInfo[x][y][wIdx][hIdx]->cu.UnitArea::operator=( area ); m_bestEncInfo[x][y][wIdx][hIdx]->pu.UnitArea::operator=( area ); +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + m_bestEncInfo[x][y][wIdx][hIdx]->numTus = 0; + for( int i = 0; i < MAX_NUM_TUS; i++ ) + { + m_bestEncInfo[x][y][wIdx][hIdx]->tus[i].UnitArea::operator=(area); + } +#else m_bestEncInfo[x][y][wIdx][hIdx]->tu.UnitArea::operator=( area ); +#endif m_bestEncInfo[x][y][wIdx][hIdx]->poc = -1; m_bestEncInfo[x][y][wIdx][hIdx]->testMode = EncTestMode(); @@ -722,8 +730,13 @@ void BestEncInfoCache::init( const Slice &slice ) } } +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + m_pCoeff = new TCoeff[numCoeff*MAX_NUM_TUS]; + m_pPcmBuf = new Pel [numCoeff*MAX_NUM_TUS]; +#else m_pCoeff = new TCoeff[numCoeff]; m_pPcmBuf = new Pel [numCoeff]; +#endif TCoeff *coeffPtr = m_pCoeff; Pel *pcmPtr = m_pPcmBuf; @@ -743,6 +756,22 @@ void BestEncInfoCache::init( const Slice &slice ) TCoeff *coeff[MAX_NUM_TBLOCKS] = { 0, }; Pel *pcmbf[MAX_NUM_TBLOCKS] = { 0, }; +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + for( int i = 0; i < MAX_NUM_TUS; i++ ) + { + TransformUnit &tu = m_bestEncInfo[x][y][wIdx][hIdx]->tus[i]; + const UnitArea &area = tu; + + for( int i = 0; i < area.blocks.size(); i++ ) + { + coeff[i] = coeffPtr; coeffPtr += area.blocks[i].area(); + pcmbf[i] = pcmPtr; pcmPtr += area.blocks[i].area(); + } + + tu.cs = &m_dummyCS; + tu.init(coeff, pcmbf); + } +#else const UnitArea &area = m_bestEncInfo[x][y][wIdx][hIdx]->tu; for( int i = 0; i < area.blocks.size(); i++ ) @@ -753,6 +782,7 @@ void BestEncInfoCache::init( const Slice &slice ) m_bestEncInfo[x][y][wIdx][hIdx]->tu.cs = &m_dummyCS; m_bestEncInfo[x][y][wIdx][hIdx]->tu.init( coeff, pcmbf ); +#endif } } } @@ -762,7 +792,11 @@ void BestEncInfoCache::init( const Slice &slice ) bool BestEncInfoCache::setFromCs( const CodingStructure& cs, const Partitioner& partitioner ) { +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + if( cs.cus.size() != 1 || cs.pus.size() != 1 ) +#else if( cs.cus.size() != 1 || cs.tus.size() != 1 || cs.pus.size() != 1 ) +#endif { return false; } @@ -775,13 +809,32 @@ bool BestEncInfoCache::setFromCs( const CodingStructure& cs, const Partitioner& encInfo.poc = cs.picture->poc; encInfo.cu.repositionTo( *cs.cus.front() ); encInfo.pu.repositionTo( *cs.pus.front() ); +#if !REUSE_CU_RESULTS_WITH_MULTIPLE_TUS encInfo.tu.repositionTo( *cs.tus.front() ); +#endif encInfo.cu = *cs.cus.front(); encInfo.pu = *cs.pus.front(); +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + int tuIdx = 0; + for( auto tu : cs.tus ) + { + encInfo.tus[tuIdx].repositionTo( *tu ); + encInfo.tus[tuIdx].resizeTo( *tu ); + for( auto &blk : tu->blocks ) + { + if( blk.valid() ) + encInfo.tus[tuIdx].copyComponentFrom( *tu, blk.compID ); + } + tuIdx++; + } + CHECKD( cs.tus.size() > MAX_NUM_TUS, "Exceeding tus array boundaries" ); + encInfo.numTus = cs.tus.size(); +#else for( auto &blk : cs.tus.front()->blocks ) { if( blk.valid() ) encInfo.tu.copyComponentFrom( *cs.tus.front(), blk.compID ); } +#endif encInfo.testMode = getCSEncMode( cs ); return true; @@ -830,18 +883,35 @@ bool BestEncInfoCache::setCsFrom( CodingStructure& cs, EncTestMode& testMode, co CodingUnit &cu = cs.addCU( CS::getArea( cs, cs.area, partitioner.chType ), partitioner.chType ); PredictionUnit &pu = cs.addPU( CS::getArea( cs, cs.area, partitioner.chType ), partitioner.chType ); +#if !REUSE_CU_RESULTS_WITH_MULTIPLE_TUS TransformUnit &tu = cs.addTU( CS::getArea( cs, cs.area, partitioner.chType ), partitioner.chType ); +#endif cu .repositionTo( encInfo.cu ); pu .repositionTo( encInfo.pu ); +#if !REUSE_CU_RESULTS_WITH_MULTIPLE_TUS tu .repositionTo( encInfo.tu ); +#endif cu = encInfo.cu; pu = encInfo.pu; +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + CHECKD( !( encInfo.numTus > 0 ), "Empty tus array" ); + for( int i = 0; i < encInfo.numTus; i++ ) + { + TransformUnit &tu = cs.addTU( encInfo.tus[i], partitioner.chType ); + + for( auto &blk : tu.blocks ) + { + if( blk.valid() ) tu.copyComponentFrom( encInfo.tus[i], blk.compID ); + } + } +#else for( auto &blk : tu.blocks ) { if( blk.valid() ) tu.copyComponentFrom( encInfo.tu, blk.compID ); } +#endif testMode = encInfo.testMode; @@ -1685,6 +1755,12 @@ bool EncModeCtrlMTnoRQT::useModeResult( const EncTestMode& encTestmode, CodingSt { cuECtx.bestEmtSize2Nx2N1stPass = tempCS->cost; } +#if JVET_M0102_INTRA_SUBPARTITIONS + if (!cu.ispMode) + { + cuECtx.bestCostEmtFirstPassNoIsp = tempCS->cost; + } +#endif } #endif diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h index b44f18c7d9a35d84d4cec94f83c7c85b4ddb6f8f..fb3e9864a90a461a426ab5dad0b7738826a030cb 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.h +++ b/source/Lib/EncoderLib/EncModeCtrl.h @@ -204,6 +204,12 @@ struct ComprCUCtx #if ENABLE_SPLIT_PARALLELISM , isLevelSplitParallel ( false ) +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + , bestCostWithoutSplitFlags( MAX_DOUBLE ) +#if !JVET_M0464_UNI_MTS + , bestCostEmtFirstPassNoIsp( MAX_DOUBLE ) +#endif #endif { getAreaIdx( cs.area.Y(), *cs.pcv, cuX, cuY, cuW, cuH ); @@ -238,6 +244,12 @@ struct ComprCUCtx Distortion interHad; #if ENABLE_SPLIT_PARALLELISM bool isLevelSplitParallel; +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + double bestCostWithoutSplitFlags; +#if !JVET_M0464_UNI_MTS + double bestCostEmtFirstPassNoIsp; +#endif #endif template<typename T> T get( int ft ) const { return typeid(T) == typeid(double) ? (T&)extraFeaturesd[ft] : T(extraFeatures[ft]); } @@ -324,6 +336,14 @@ public: bool getSkipSecondEMTPass () const { return m_ComprCUCtxList.back().skipSecondEMTPass; } void setSkipSecondEMTPass ( bool b ) { m_ComprCUCtxList.back().skipSecondEMTPass = b; } #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + double getBestCostWithoutSplitFlags () const { return m_ComprCUCtxList.back().bestCostWithoutSplitFlags; } + void setBestCostWithoutSplitFlags ( double cost ) { m_ComprCUCtxList.back().bestCostWithoutSplitFlags = cost; } +#if !JVET_M0464_UNI_MTS + double getEmtFirstPassNoIspCost () const { return m_ComprCUCtxList.back().bestCostEmtFirstPassNoIsp; } + void setEmtFirstPassNoIspCost ( double cost ) { m_ComprCUCtxList.back().bestCostEmtFirstPassNoIsp = cost; } +#endif +#endif protected: void xExtractFeatures ( const EncTestMode encTestmode, CodingStructure& cs ); @@ -406,7 +426,12 @@ struct BestEncodingInfo { CodingUnit cu; PredictionUnit pu; +#if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS + TransformUnit tus[MAX_NUM_TUS]; + size_t numTus; +#else TransformUnit tu; +#endif EncTestMode testMode; int poc; diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index 3117211d2b1fc42259f149aaac961eabc6767b0f..d7279af9ba3e7080967cff8c90a29065ceec1230 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -276,7 +276,11 @@ void IntraSearch::init( EncCfg* pcEncCfg, // INTRA PREDICTION ////////////////////////////////////////////////////////////////////////// +#if JVET_M0102_INTRA_SUBPARTITIONS +void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, const double bestCostSoFar ) +#else void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) +#endif { CodingStructure &cs = *cu.cs; const SPS &sps = *cs.sps; @@ -322,6 +326,63 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) emtUsageFlag = 0; //this forces the recalculation of the candidates list. Why is this necessary? (to be checked) } #endif +#if JVET_M0102_INTRA_SUBPARTITIONS +#if JVET_M0464_UNI_MTS + const int width = partitioner.currArea().lwidth(); + const int height = partitioner.currArea().lheight(); + int nOptionsForISP = NUM_INTRA_SUBPARTITIONS_MODES; +#else + int nOptionsForISP = cu.emtFlag == 0 ? NUM_INTRA_SUBPARTITIONS_MODES : 1; +#endif + double bestCurrentCost = bestCostSoFar; + + int ispOptions[NUM_INTRA_SUBPARTITIONS_MODES] = { 0 }; + if( nOptionsForISP > 1 ) + { + auto splitsThatCanBeUsedForISP = CU::canUseISPSplit( width, height, cu.cs->sps->getMaxTrSize() ); + if( splitsThatCanBeUsedForISP == CAN_USE_VER_AND_HORL_SPLITS ) + { + const CodingUnit* cuLeft = cu.ispMode != NOT_INTRA_SUBPARTITIONS ? cs.getCU( cs.area.blocks[partitioner.chType].pos().offset( -1, 0 ), partitioner.chType ) : nullptr; + const CodingUnit* cuAbove = cu.ispMode != NOT_INTRA_SUBPARTITIONS ? cs.getCU( cs.area.blocks[partitioner.chType].pos().offset( 0, -1 ), partitioner.chType ) : nullptr; + bool ispHorIsFirstTest = CU::firstTestISPHorSplit( width, height, COMPONENT_Y, cuLeft, cuAbove ); + if( ispHorIsFirstTest ) + { + ispOptions[1] = HOR_INTRA_SUBPARTITIONS; + ispOptions[2] = VER_INTRA_SUBPARTITIONS; + } + else + { + ispOptions[1] = VER_INTRA_SUBPARTITIONS; + ispOptions[2] = HOR_INTRA_SUBPARTITIONS; + } + } + else if( splitsThatCanBeUsedForISP == HOR_INTRA_SUBPARTITIONS ) + { + nOptionsForISP = 2; + ispOptions[1] = HOR_INTRA_SUBPARTITIONS; + } + else if( splitsThatCanBeUsedForISP == VER_INTRA_SUBPARTITIONS ) + { + nOptionsForISP = 2; + ispOptions[1] = VER_INTRA_SUBPARTITIONS; + } + else + { + nOptionsForISP = 1; + } + } + if( nOptionsForISP > 1 ) + { + //variables for the full RD list without MRL modes + m_rdModeListWithoutMrl .clear(); + m_rdModeListWithoutMrlHor .clear(); + m_rdModeListWithoutMrlVer .clear(); + //variables with data from regular intra used to skip ISP splits + m_intraModeDiagRatio .clear(); + m_intraModeHorVerRatio .clear(); + m_intraModeTestedNormalIntra.clear(); + } +#endif static_vector<uint32_t, FAST_UDI_MAX_RDMODE_NUM> uiHadModeList; static_vector<double, FAST_UDI_MAX_RDMODE_NUM> CandCostList; @@ -498,6 +559,14 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) } } } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( nOptionsForISP > 1 ) + { + //we save the list with no mrl modes to keep only the Hadamard selected modes (no mpms) + m_rdModeListWithoutMrl.resize( numModesForFullRD ); + std::copy_n( uiRdModeList.begin(), numModesForFullRD, m_rdModeListWithoutMrl.begin() ); + } +#endif pu.multiRefIdx = 1; const int numMPMs = NUM_MOST_PROBABLE_MODES; unsigned multiRefMPM [numMPMs]; @@ -568,6 +637,36 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) uiRdModeList.push_back( mostProbableMode ); } } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( nOptionsForISP > 1 ) + { + //we add the ISP MPMs to the list without mrl modes + m_rdModeListWithoutMrlHor = m_rdModeListWithoutMrl; + m_rdModeListWithoutMrlVer = m_rdModeListWithoutMrl; + static_vector<uint32_t, FAST_UDI_MAX_RDMODE_NUM>* listPointer; + for( int k = 1; k < nOptionsForISP; k++ ) + { + cu.ispMode = ispOptions[k]; + listPointer = &( cu.ispMode == HOR_INTRA_SUBPARTITIONS ? m_rdModeListWithoutMrlHor : m_rdModeListWithoutMrlVer ); + const int numCandISP = PU::getIntraMPMs( pu, uiPreds ); + for( int j = 0; j < numCandISP; j++ ) + { + bool mostProbableModeIncluded = false; + int mostProbableMode = uiPreds[j]; + + for( int i = 0; i < listPointer->size(); i++ ) + { + mostProbableModeIncluded |= ( mostProbableMode == listPointer->at( i ) ); + } + if( !mostProbableModeIncluded ) + { + listPointer->push_back( mostProbableMode ); + } + } + } + cu.ispMode = NOT_INTRA_SUBPARTITIONS; + } +#endif } } else @@ -620,6 +719,44 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) } #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + if( nOptionsForISP > 1 ) // we remove the non-MPMs from the ISP lists + { + static_vector< uint32_t, FAST_UDI_MAX_RDMODE_NUM > uiRdModeListCopyHor = m_rdModeListWithoutMrlHor; + m_rdModeListWithoutMrlHor.clear(); + static_vector< uint32_t, FAST_UDI_MAX_RDMODE_NUM > uiRdModeListCopyVer = m_rdModeListWithoutMrlVer; + m_rdModeListWithoutMrlVer.clear(); + static_vector< uint32_t, FAST_UDI_MAX_RDMODE_NUM > *listPointerCopy, *listPointer; + for( int ispOptionIdx = 1; ispOptionIdx < nOptionsForISP; ispOptionIdx++ ) + { + cu.ispMode = ispOptions[ispOptionIdx]; + //we get the mpm cand list + const int numMPMs = NUM_MOST_PROBABLE_MODES; + unsigned uiPreds[numMPMs]; + + pu.multiRefIdx = 0; + + PU::getIntraMPMs( pu, uiPreds ); + + //we copy only the ISP MPMs + listPointerCopy = &( cu.ispMode == HOR_INTRA_SUBPARTITIONS ? uiRdModeListCopyHor : uiRdModeListCopyVer ); + listPointer = &( cu.ispMode == HOR_INTRA_SUBPARTITIONS ? m_rdModeListWithoutMrlHor : m_rdModeListWithoutMrlVer ); + for( int k = 0; k < listPointerCopy->size(); k++ ) + { + for( int q = 0; q < numMPMs; q++ ) + { + if( listPointerCopy->at( k ) == uiPreds[q] ) + { + listPointer->push_back( listPointerCopy->at( k ) ); + break; + } + } + } + } + cu.ispMode = NOT_INTRA_SUBPARTITIONS; + } +#endif + CHECK( numModesForFullRD != uiRdModeList.size(), "Inconsistent state!" ); @@ -635,10 +772,24 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) if( CandHadList.size() < 3 || CandHadList[2] > cs.interHad * PBINTRA_RATIO ) { uiRdModeList.resize( std::min<size_t>( uiRdModeList.size(), 2 ) ); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( nOptionsForISP > 1 ) + { + m_rdModeListWithoutMrlHor.resize( std::min<size_t>( m_rdModeListWithoutMrlHor.size(), 2 ) ); + m_rdModeListWithoutMrlVer.resize( std::min<size_t>( m_rdModeListWithoutMrlVer.size(), 2 ) ); + } +#endif } if( CandHadList.size() < 2 || CandHadList[1] > cs.interHad * PBINTRA_RATIO ) { uiRdModeList.resize( std::min<size_t>( uiRdModeList.size(), 1 ) ); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( nOptionsForISP > 1 ) + { + m_rdModeListWithoutMrlHor.resize( std::min<size_t>( m_rdModeListWithoutMrlHor.size(), 1 ) ); + m_rdModeListWithoutMrlVer.resize( std::min<size_t>( m_rdModeListWithoutMrlVer.size(), 1 ) ); + } +#endif } if( CandHadList.size() < 1 || CandHadList[0] > cs.interHad * PBINTRA_RATIO ) { @@ -668,6 +819,60 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) // just to be sure numModesForFullRD = ( int ) uiRdModeList.size(); +#if JVET_M0102_INTRA_SUBPARTITIONS + PartSplit intraSubPartitionsProcOrder = TU_NO_ISP; + int bestNormalIntraModeIndex = -1; + uint8_t bestIspOption = NOT_INTRA_SUBPARTITIONS; + TUIntraSubPartitioner subTuPartitioner( partitioner ); +#if !JVET_M0464_UNI_MTS + if ( !cu.ispMode && !cu.emtFlag ) + { + m_modeCtrl->setEmtFirstPassNoIspCost( MAX_DOUBLE ); + } +#endif + for( uint32_t ispOptionIdx = 0; ispOptionIdx < nOptionsForISP; ispOptionIdx++ ) + { + cu.ispMode = ispOptions[ispOptionIdx]; + int numModesForFullRDispOption = cu.ispMode == NOT_INTRA_SUBPARTITIONS ? numModesForFullRD : cu.ispMode == HOR_INTRA_SUBPARTITIONS ? (int)m_rdModeListWithoutMrlHor.size() : (int)m_rdModeListWithoutMrlVer.size(); + for( uint32_t uiMode = 0; uiMode < numModesForFullRDispOption; uiMode++ ) + { + // set luma prediction mode + uint32_t uiOrgMode = cu.ispMode == NOT_INTRA_SUBPARTITIONS ? uiRdModeList[uiMode] : cu.ispMode == HOR_INTRA_SUBPARTITIONS ? m_rdModeListWithoutMrlHor[uiMode] : m_rdModeListWithoutMrlVer[uiMode]; + + pu.intraDir[0] = uiOrgMode; + + int multiRefIdx = 0; + pu.multiRefIdx = multiRefIdx; + if( cu.ispMode ) + { + intraSubPartitionsProcOrder = CU::getISPType( cu, COMPONENT_Y ); + bool tuIsDividedInRows = CU::divideTuInRows( cu ); + if( m_intraModeDiagRatio.at( bestNormalIntraModeIndex ) > 1.25 ) + { + continue; + } + if( uiOrgMode <= DC_IDX ) + { + if( ( m_intraModeHorVerRatio.at( bestNormalIntraModeIndex ) > 1.25 && tuIsDividedInRows ) || ( m_intraModeHorVerRatio.at( bestNormalIntraModeIndex ) < 0.8 && !tuIsDividedInRows ) ) + { + continue; + } + } + else + { + if( ( m_intraModeHorVerRatio.at( bestNormalIntraModeIndex ) > 1.25 && tuIsDividedInRows ) || ( m_intraModeHorVerRatio.at( bestNormalIntraModeIndex ) < 0.8 && !tuIsDividedInRows ) ) + { + continue; + } + } + } + else + { + multiRefIdx = extendRefList[uiMode]; + pu.multiRefIdx = multiRefIdx; + CHECK( pu.multiRefIdx && ( pu.intraDir[0] == DC_IDX || pu.intraDir[0] == PLANAR_IDX ), "ERL" ); + } +#else for (uint32_t uiMode = 0; uiMode < numModesForFullRD; uiMode++) { // set luma prediction mode @@ -677,6 +882,7 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) int multiRefIdx = extendRefList[uiMode]; pu.multiRefIdx = multiRefIdx; CHECK(pu.multiRefIdx && (pu.intraDir[0] == DC_IDX || pu.intraDir[0] == PLANAR_IDX), "ERL"); +#endif // set context models @@ -685,10 +891,31 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) // determine residual for partition cs.initSubStructure( *csTemp, partitioner.chType, cs.area, true ); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.ispMode ) + { + xRecurIntraCodingLumaQT( *csTemp, subTuPartitioner, bestCurrentCost, 0, intraSubPartitionsProcOrder ); + } + else + { + xRecurIntraCodingLumaQT( *csTemp, partitioner, MAX_DOUBLE, -1 ); + } + + if( cu.ispMode && !csTemp->cus[0]->firstTU->cbf[COMPONENT_Y] ) + { + csTemp->cost = MAX_DOUBLE; + } +#else xRecurIntraCodingLumaQT( *csTemp, partitioner ); +#endif + #if !JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + if (emtUsageFlag == 1 && m_pcEncCfg->getFastIntraEMT() && !cu.ispMode) +#else if( emtUsageFlag == 1 && m_pcEncCfg->getFastIntraEMT() ) +#endif { m_modeCostStore[puIndex][uiMode] = csTemp->cost; //cs.cost; } @@ -703,16 +930,43 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) uiBestPUMode = uiOrgMode; bestExtendRef = multiRefIdx; +#if JVET_M0102_INTRA_SUBPARTITIONS + bestIspOption = cu.ispMode; +#endif #if !JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + if (emtUsageFlag == 1 && m_pcEncCfg->getFastIntraEMT() && !cu.ispMode) +#else if( ( emtUsageFlag == 1 ) && m_pcEncCfg->getFastIntraEMT() ) +#endif { m_bestModeCostStore[puIndex] = csBest->cost; //cs.cost; } +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + if( csBest->cost < bestCurrentCost ) + { + bestCurrentCost = csBest->cost; + } + if( !cu.ispMode ) + { + bestNormalIntraModeIndex = uiMode; + } #endif } csTemp->releaseIntermediateData(); } // Mode loop +#if JVET_M0102_INTRA_SUBPARTITIONS +#if !JVET_M0464_UNI_MTS + if (!cu.ispMode && !cu.emtFlag) + { + m_modeCtrl->setEmtFirstPassNoIspCost(csBest->cost); + } +#endif + } + cu.ispMode = bestIspOption; +#endif #if JVET_M0427_INLOOP_RESHAPER cs.useSubStructure(*csBest, partitioner.chType, pu.singleChan(CHANNEL_TYPE_LUMA), true, true, keepResi, keepResi); @@ -729,7 +983,11 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) m_CABACEstimator->getCtx() = ctxStart; } +#if JVET_M0102_INTRA_SUBPARTITIONS +void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner, const double maxCostAllowed ) +#else void IntraSearch::estIntraPredChromaQT(CodingUnit &cu, Partitioner &partitioner) +#endif { const ChromaFormat format = cu.chromaFormat; const uint32_t numberValidComponents = getNumberValidComponents(format); @@ -738,6 +996,13 @@ void IntraSearch::estIntraPredChromaQT(CodingUnit &cu, Partitioner &partitioner) cs.setDecomp( cs.area.Cb(), false ); +#if JVET_M0102_INTRA_SUBPARTITIONS + double bestCostSoFar = maxCostAllowed; + bool lumaUsesISP = !CS::isDualITree( *cu.cs ) && cu.ispMode; + PartSplit ispType = lumaUsesISP ? CU::getISPType( cu, COMPONENT_Y ) : TU_NO_ISP; + CHECK( cu.ispMode && bestCostSoFar < 0, "bestCostSoFar must be positive!" ); +#endif + auto &pu = *cu.firstPU; { @@ -761,6 +1026,14 @@ void IntraSearch::estIntraPredChromaQT(CodingUnit &cu, Partitioner &partitioner) saveCS.area.repositionTo( cs.area ); saveCS.clearTUs(); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !CS::isDualITree( cs ) && cu.ispMode ) + { + saveCS.clearCUs(); + saveCS.clearPUs(); + } +#endif + if( CS::isDualITree( cs ) ) { if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) @@ -780,17 +1053,37 @@ void IntraSearch::estIntraPredChromaQT(CodingUnit &cu, Partitioner &partitioner) std::vector<TransformUnit*> orgTUs; +#if JVET_M0102_INTRA_SUBPARTITIONS + if( lumaUsesISP ) + { + CodingUnit& auxCU = saveCS.addCU( cu, partitioner.chType ); + auxCU.ispMode = cu.ispMode; + saveCS.sps = cu.cs->sps; + saveCS.addPU( *cu.firstPU, partitioner.chType ); + } +#endif + // create a store for the TUs for( const auto &ptu : cs.tus ) { // for split TUs in HEVC, add the TUs without Chroma parts for correct setting of Cbfs +#if JVET_M0102_INTRA_SUBPARTITIONS + if( lumaUsesISP || pu.contains( *ptu, CHANNEL_TYPE_CHROMA ) ) +#else if( pu.contains( *ptu, CHANNEL_TYPE_CHROMA ) ) +#endif { saveCS.addTU( *ptu, partitioner.chType ); orgTUs.push_back( ptu ); } } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( lumaUsesISP ) + { + saveCS.clearCUs(); + } +#endif // SATD pre-selecting. int satdModeList[NUM_CHROMA_MODE]; int64_t satdSortedCost[NUM_CHROMA_MODE]; @@ -914,20 +1207,38 @@ void IntraSearch::estIntraPredChromaQT(CodingUnit &cu, Partitioner &partitioner) //----- chroma coding ----- pu.intraDir[1] = chromaIntraMode; +#if JVET_M0102_INTRA_SUBPARTITIONS + xRecurIntraChromaCodingQT( cs, partitioner, bestCostSoFar, ispType ); + if( lumaUsesISP && cs.dist == MAX_UINT ) + { + continue; + } +#else xRecurIntraChromaCodingQT( cs, partitioner ); +#endif if (cs.pps->getUseTransformSkip()) { m_CABACEstimator->getCtx() = ctxStart; } +#if JVET_M0102_INTRA_SUBPARTITIONS + uint64_t fracBits = xGetIntraFracBitsQT( cs, partitioner, false, true, -1, ispType ); +#else uint64_t fracBits = xGetIntraFracBitsQT( cs, partitioner, false, true ); +#endif Distortion uiDist = cs.dist; double dCost = m_pcRdCost->calcRdCost( fracBits, uiDist - baseDist ); //----- compare ----- if( dCost < dBestCost ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + if( lumaUsesISP && dCost < bestCostSoFar ) + { + bestCostSoFar = dCost; + } +#endif for( uint32_t i = getFirstComponentOfChannel( CHANNEL_TYPE_CHROMA ); i < numberValidComponents; i++ ) { const CompArea &area = pu.blocks[i]; @@ -984,6 +1295,12 @@ void IntraSearch::estIntraPredChromaQT(CodingUnit &cu, Partitioner &partitioner) //----- restore context models ----- m_CABACEstimator->getCtx() = ctxStart; +#if JVET_M0102_INTRA_SUBPARTITIONS + if( lumaUsesISP && bestCostSoFar >= maxCostAllowed ) + { + cu.ispMode = 0; + } +#endif } void IntraSearch::IPCMSearch(CodingStructure &cs, Partitioner& partitioner) @@ -1042,13 +1359,21 @@ void IntraSearch::xEncPCM(CodingStructure &cs, Partitioner& partitioner, const C // Intra search // ------------------------------------------------------------------------------------------------------------------- +#if JVET_M0102_INTRA_SUBPARTITIONS +void IntraSearch::xEncIntraHeader( CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma, const int subTuIdx ) +#else void IntraSearch::xEncIntraHeader(CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma) +#endif { CodingUnit &cu = *cs.getCU( partitioner.chType ); if (bLuma) { +#if JVET_M0102_INTRA_SUBPARTITIONS + bool isFirst = cu.ispMode ? subTuIdx == 0 : partitioner.currArea().lumaPos() == cs.area.lumaPos(); +#else bool isFirst = partitioner.currArea().lumaPos() == cs.area.lumaPos(); +#endif // CU header if( isFirst ) @@ -1065,6 +1390,9 @@ void IntraSearch::xEncIntraHeader(CodingStructure &cs, Partitioner &partitioner, m_CABACEstimator->pred_mode ( cu ); } m_CABACEstimator->extend_ref_line(cu); +#if JVET_M0102_INTRA_SUBPARTITIONS + m_CABACEstimator->isp_mode ( cu ); +#endif if( CU::isIntra(cu) ) { m_CABACEstimator->pcm_data( cu, partitioner ); @@ -1099,16 +1427,29 @@ void IntraSearch::xEncIntraHeader(CodingStructure &cs, Partitioner &partitioner, } } +#if JVET_M0102_INTRA_SUBPARTITIONS +void IntraSearch::xEncSubdivCbfQT( CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma, const int subTuIdx, const PartSplit ispType ) +{ + const UnitArea &currArea = partitioner.currArea(); + int subTuCounter = subTuIdx; + TransformUnit &currTU = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType, subTuCounter ); + CodingUnit &currCU = *currTU.cu; +#else void IntraSearch::xEncSubdivCbfQT(CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma) { const UnitArea &currArea = partitioner.currArea(); TransformUnit &currTU = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType ); #if !JVET_M0464_UNI_MTS CodingUnit &currCU = *currTU.cu; +#endif #endif uint32_t currDepth = partitioner.currTrDepth; const bool subdiv = currTU.depth > currDepth; +#if JVET_M0102_INTRA_SUBPARTITIONS + ComponentID compID = partitioner.chType == CHANNEL_TYPE_LUMA ? COMPONENT_Y : COMPONENT_Cb; + const bool chromaCbfISP = currArea.blocks[COMPONENT_Cb].valid() && currCU.ispMode && !subdiv; +#endif if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) { @@ -1116,21 +1457,39 @@ void IntraSearch::xEncSubdivCbfQT(CodingStructure &cs, Partitioner &partitioner, } else { +#if JVET_M0102_INTRA_SUBPARTITIONS + CHECK( subdiv && !currCU.ispMode && isLuma( compID ), "No TU subdivision is allowed with QTBT" ); + } + + if( bChroma && ( !currCU.ispMode || chromaCbfISP ) ) +#else CHECK( subdiv, "No TU subdivision is allowed with QTBT" ); } if (bChroma) +#endif { const uint32_t numberValidComponents = getNumberValidComponents(currArea.chromaFormat); +#if JVET_M0102_INTRA_SUBPARTITIONS + const uint32_t cbfDepth = ( chromaCbfISP ? currDepth - 1 : currDepth ); +#endif for (uint32_t ch = COMPONENT_Cb; ch < numberValidComponents; ch++) { const ComponentID compID = ComponentID(ch); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( currDepth == 0 || TU::getCbfAtDepth( currTU, compID, currDepth - 1 ) || chromaCbfISP ) +#else if( currDepth == 0 || TU::getCbfAtDepth( currTU, compID, currDepth - 1 ) ) +#endif { const bool prevCbf = ( compID == COMPONENT_Cr ? TU::getCbfAtDepth( currTU, COMPONENT_Cb, currDepth ) : false ); +#if JVET_M0102_INTRA_SUBPARTITIONS + m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, compID, currDepth ), currArea.blocks[compID], cbfDepth, prevCbf ); +#else m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, compID, currDepth ), currArea.blocks[compID], currDepth, prevCbf ); +#endif } } @@ -1139,19 +1498,34 @@ void IntraSearch::xEncSubdivCbfQT(CodingStructure &cs, Partitioner &partitioner, if (subdiv) { #if !JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + if (!currCU.ispMode && isLuma( compID ) && currDepth == 0 && bLuma) m_CABACEstimator->emt_cu_flag( currCU ); +#else if( currDepth == 0 && bLuma ) m_CABACEstimator->emt_cu_flag( currCU ); +#endif #endif if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) ) { partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); } +#if JVET_M0102_INTRA_SUBPARTITIONS + else if( currCU.ispMode && isLuma( compID ) ) + { + partitioner.splitCurrArea( ispType, cs ); + } +#endif else THROW( "Cannot perform an implicit split!" ); do { +#if JVET_M0102_INTRA_SUBPARTITIONS + xEncSubdivCbfQT( cs, partitioner, bLuma, bChroma, subTuCounter, ispType ); + subTuCounter += subTuCounter != -1 ? 1 : 0; +#else xEncSubdivCbfQT( cs, partitioner, bLuma, bChroma ); +#endif } while( partitioner.nextPart( cs ) ); partitioner.exitCurrSplit(); @@ -1159,20 +1533,65 @@ void IntraSearch::xEncSubdivCbfQT(CodingStructure &cs, Partitioner &partitioner, else { #if !JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + if (!currCU.ispMode && isLuma( compID ) && currDepth == 0 && bLuma && TU::getCbfAtDepth( currTU, COMPONENT_Y, 0) ) m_CABACEstimator->emt_cu_flag( currCU ); +#else if( currDepth == 0 && bLuma && TU::getCbfAtDepth( currTU, COMPONENT_Y, 0 ) ) m_CABACEstimator->emt_cu_flag( currCU ); +#endif #endif //===== Cbfs ===== if (bLuma) { +#if JVET_M0102_INTRA_SUBPARTITIONS + bool previousCbf = false; + bool lastCbfIsInferred = false; + if( ispType != TU_NO_ISP ) + { + bool rootCbfSoFar = false; + uint32_t nTus = currCU.ispMode == HOR_INTRA_SUBPARTITIONS ? currCU.lheight() >> g_aucLog2[currTU.lheight()] : currCU.lwidth() >> g_aucLog2[currTU.lwidth()]; + if( subTuCounter == nTus - 1 ) + { + TransformUnit* tuPointer = currCU.firstTU; + for( int tuIdx = 0; tuIdx < nTus - 1; tuIdx++ ) + { + rootCbfSoFar |= TU::getCbfAtDepth( *tuPointer, COMPONENT_Y, currDepth ); + tuPointer = tuPointer->next; + } + if( !rootCbfSoFar ) + { + lastCbfIsInferred = true; + } + } + if( !lastCbfIsInferred ) + { + previousCbf = TU::getPrevTuCbfAtDepth( currTU, COMPONENT_Y, partitioner.currTrDepth ); + } + } + if( !lastCbfIsInferred ) + { + m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, COMPONENT_Y, currDepth ), currTU.Y(), currTU.depth, previousCbf, currCU.ispMode ); + } +#else m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, COMPONENT_Y, currDepth ), currTU.Y(), currTU.depth ); +#endif } } } +#if JVET_M0102_INTRA_SUBPARTITIONS +void IntraSearch::xEncCoeffQT( CodingStructure &cs, Partitioner &partitioner, const ComponentID compID, const int subTuIdx, const PartSplit ispType ) +#else void IntraSearch::xEncCoeffQT(CodingStructure &cs, Partitioner &partitioner, const ComponentID &compID) +#endif { const UnitArea &currArea = partitioner.currArea(); + +#if JVET_M0102_INTRA_SUBPARTITIONS + int subTuCounter = subTuIdx; + TransformUnit &currTU = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType, subTuIdx ); +#else TransformUnit &currTU = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType ); +#endif uint32_t currDepth = partitioner.currTrDepth; const bool subdiv = currTU.depth > currDepth; @@ -1182,12 +1601,23 @@ void IntraSearch::xEncCoeffQT(CodingStructure &cs, Partitioner &partitioner, con { partitioner.splitCurrArea(TU_MAX_TR_SPLIT, cs); } +#if JVET_M0102_INTRA_SUBPARTITIONS + else if( currTU.cu->ispMode ) + { + partitioner.splitCurrArea( ispType, cs ); + } +#endif else THROW("Implicit TU split not available!"); do { +#if JVET_M0102_INTRA_SUBPARTITIONS + xEncCoeffQT( cs, partitioner, compID, subTuCounter, ispType ); + subTuCounter += subTuCounter != -1 ? 1 : 0; +#else xEncCoeffQT( cs, partitioner, compID ); +#endif } while( partitioner.nextPart( cs ) ); partitioner.exitCurrSplit(); @@ -1207,27 +1637,80 @@ void IntraSearch::xEncCoeffQT(CodingStructure &cs, Partitioner &partitioner, con } } +#if JVET_M0102_INTRA_SUBPARTITIONS +uint64_t IntraSearch::xGetIntraFracBitsQT( CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma, const int subTuIdx, const PartSplit ispType ) +#else uint64_t IntraSearch::xGetIntraFracBitsQT( CodingStructure &cs, Partitioner &partitioner, const bool &bLuma, const bool &bChroma ) +#endif { m_CABACEstimator->resetBits(); +#if JVET_M0102_INTRA_SUBPARTITIONS + xEncIntraHeader( cs, partitioner, bLuma, bChroma, subTuIdx ); + xEncSubdivCbfQT( cs, partitioner, bLuma, bChroma, subTuIdx, ispType ); +#else xEncIntraHeader( cs, partitioner, bLuma, bChroma ); xEncSubdivCbfQT( cs, partitioner, bLuma, bChroma ); +#endif + if( bLuma ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + xEncCoeffQT( cs, partitioner, COMPONENT_Y, subTuIdx, ispType ); +#else xEncCoeffQT( cs, partitioner, COMPONENT_Y ); +#endif } if( bChroma ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + xEncCoeffQT( cs, partitioner, COMPONENT_Cb, subTuIdx, ispType ); + xEncCoeffQT( cs, partitioner, COMPONENT_Cr, subTuIdx, ispType ); +#else xEncCoeffQT( cs, partitioner, COMPONENT_Cb ); xEncCoeffQT( cs, partitioner, COMPONENT_Cr ); +#endif } uint64_t fracBits = m_CABACEstimator->getEstFracBits(); return fracBits; } +#if JVET_M0102_INTRA_SUBPARTITIONS +uint64_t IntraSearch::xGetIntraFracBitsQTSingleChromaComponent( CodingStructure &cs, Partitioner &partitioner, const ComponentID compID ) +{ + m_CABACEstimator->resetBits(); + + if( compID == COMPONENT_Cb ) + { + //intra mode coding + PredictionUnit &pu = *cs.getPU( partitioner.currArea().lumaPos(), partitioner.chType ); + m_CABACEstimator->intra_chroma_pred_mode( pu ); + //xEncIntraHeader(cs, partitioner, false, true); + } + CHECK( partitioner.currTrDepth != 1, "error in the depth!" ); + const UnitArea &currArea = partitioner.currArea(); + + TransformUnit &currTU = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType ); + + //cbf coding + m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, compID, partitioner.currTrDepth ), currArea.blocks[compID], partitioner.currTrDepth - 1 ); + //coeffs coding and cross comp coding + if( TU::hasCrossCompPredInfo( currTU, compID ) ) + { + m_CABACEstimator->cross_comp_pred( currTU, compID ); + } + if( TU::getCbf( currTU, compID ) ) + { + m_CABACEstimator->residual_coding( currTU, compID ); + } + + uint64_t fracBits = m_CABACEstimator->getEstFracBits(); + return fracBits; +} +#endif + uint64_t IntraSearch::xGetIntraFracBitsQTChroma(TransformUnit& currTU, const ComponentID &compID) { m_CABACEstimator->resetBits(); @@ -1276,6 +1759,9 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp const bool bUseCrossCPrediction = pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && isChroma( compID ) && PU::isChromaIntraModeCrossCheckMode( pu ) && checkCrossCPrediction; const bool ccUseRecoResi = m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate(); +#if JVET_M0102_INTRA_SUBPARTITIONS + const bool ispSplitIsAllowed = CU::canUseISPSplit( *tu.cu, compID ); +#endif //===== init availability pattern ===== @@ -1380,16 +1866,46 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp } #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + double diagRatio = 0, horVerRatio = 0; +#endif + #if JVET_M0464_UNI_MTS if( trModes ) { +#if JVET_M0102_INTRA_SUBPARTITIONS + m_pcTrQuant->transformNxN( tu, compID, cQP, trModes, CU::isIntra( *tu.cu ) ? m_pcEncCfg->getIntraMTSMaxCand() : m_pcEncCfg->getInterMTSMaxCand(), ispSplitIsAllowed ? &diagRatio : nullptr, ispSplitIsAllowed ? &horVerRatio : nullptr ); +#else m_pcTrQuant->transformNxN( tu, compID, cQP, trModes, CU::isIntra( *tu.cu ) ? m_pcEncCfg->getIntraMTSMaxCand() : m_pcEncCfg->getInterMTSMaxCand() ); +#endif tu.mtsIdx = trModes->at(0).first; } +#if JVET_M0102_INTRA_SUBPARTITIONS + m_pcTrQuant->transformNxN( tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr, &diagRatio, &horVerRatio ); +#else m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr); +#endif +#else +#if JVET_M0102_INTRA_SUBPARTITIONS + m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), ispSplitIsAllowed ? &diagRatio : nullptr, ispSplitIsAllowed ? &horVerRatio : nullptr); #else m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx()); #endif +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + if (!tu.cu->ispMode && isLuma(compID) && ispSplitIsAllowed && +#if JVET_M0464_UNI_MTS + tu.mtsIdx == 0 +#else + !tu.cu->emtFlag +#endif + ) + { + m_intraModeDiagRatio .push_back(diagRatio); + m_intraModeHorVerRatio .push_back(horVerRatio); + m_intraModeTestedNormalIntra.push_back((int)uiChFinalMode); + } +#endif DTRACE( g_trace_ctx, D_TU_ABS_SUM, "%d: comp=%d, abssum=%d\n", DTRACE_GET_COUNTER( g_trace_ctx, D_TU_ABS_SUM ), compID, uiAbsSum ); @@ -1459,11 +1975,20 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp } } +#if JVET_M0102_INTRA_SUBPARTITIONS +void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &partitioner, const double bestCostSoFar, const int subTuIdx, const PartSplit ispType ) +{ + int subTuCounter = subTuIdx; + const UnitArea &currArea = partitioner.currArea(); + const CodingUnit &cu = *cs.getCU( currArea.lumaPos(), partitioner.chType ); + bool earlySkipISP = false; +#else void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &partitioner ) { const UnitArea &currArea = partitioner.currArea(); #if !JVET_M0464_UNI_MTS const CodingUnit &cu = *cs.getCU(currArea.lumaPos(), partitioner.chType); +#endif #endif uint32_t currDepth = partitioner.currTrDepth; const PPS &pps = *cs.pps; @@ -1473,6 +1998,13 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par bCheckFull = !partitioner.canSplit( TU_MAX_TR_SPLIT, cs ); bCheckSplit = partitioner.canSplit( TU_MAX_TR_SPLIT, cs ); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.ispMode ) + { + bCheckSplit = partitioner.canSplit( ispType, cs ); + bCheckFull = !bCheckSplit; + } +#endif uint32_t numSig = 0; #if JVET_M0464_UNI_MTS @@ -1539,6 +2071,9 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par checkTransformSkip &= TU::hasTransformSkipFlag( *tu.cs, tu.Y() ); checkTransformSkip &= !cu.transQuantBypass; checkTransformSkip &= !cu.emtFlag; +#if JVET_M0102_INTRA_SUBPARTITIONS + checkTransformSkip &= !cu.ispMode; +#endif CHECK( !tu.Y().valid(), "Invalid TU" ); @@ -1639,6 +2174,12 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par { default0Save1Load2 = 2; } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.ispMode ) + { + default0Save1Load2 = 0; + } +#endif #if JVET_M0464_UNI_MTS if( nNumTransformCands > 1 ) { @@ -1688,7 +2229,18 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par } else { +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.ispMode && m_pcRdCost->calcRdCost( csFull->fracBits, csFull->dist + singleDistTmpLuma ) > bestCostSoFar ) + { + earlySkipISP = true; + } + else + { + singleTmpFracBits = xGetIntraFracBitsQT( *csFull, partitioner, true, false, subTuCounter, ispType ); + } +#else singleTmpFracBits = xGetIntraFracBitsQT( *csFull, partitioner, true, false ); +#endif singleCostTmp = m_pcRdCost->calcRdCost( singleTmpFracBits, singleDistTmpLuma ); } @@ -1776,13 +2328,62 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.ispMode ) + { + partitioner.splitCurrArea( ispType, *csSplit ); + } +#endif do { +#if JVET_M0102_INTRA_SUBPARTITIONS + xRecurIntraCodingLumaQT( *csSplit, partitioner, bestCostSoFar, subTuCounter, ispType ); + subTuCounter += subTuCounter != -1 ? 1 : 0; +#else xRecurIntraCodingLumaQT( *csSplit, partitioner ); +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !cu.ispMode ) + { + csSplit->setDecomp( partitioner.currArea().Y() ); + } + else if( CU::isISPFirst( cu, partitioner.currArea().Y(), COMPONENT_Y ) ) + { + csSplit->setDecomp( cu.Y() ); + } +#else csSplit->setDecomp( partitioner.currArea().Y() ); +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + uiSplitCbfLuma |= TU::getCbfAtDepth( *csSplit->getTU( partitioner.currArea().lumaPos(), partitioner.chType, subTuCounter - 1 ), COMPONENT_Y, partitioner.currTrDepth ); + if( cu.ispMode ) + { + //exit condition if the accumulated cost is already larger than the best cost so far (no impact in RD performance) + if( csSplit->cost > bestCostSoFar ) + { + earlySkipISP = true; + splitIsSelected = false; + break; + } + else + { + //more restrictive exit condition + bool tuIsDividedInRows = CU::divideTuInRows( cu ); + int nSubPartitions = tuIsDividedInRows ? cu.lheight() >> g_aucLog2[cu.firstTU->lheight()] : cu.lwidth() >> g_aucLog2[cu.firstTU->lwidth()]; + double threshold = nSubPartitions == 2 ? 0.95 : subTuCounter == 0 ? 0.67 : subTuCounter == 1 ? 0.83 : 0.91; + if( subTuCounter < nSubPartitions && csSplit->cost > bestCostSoFar*threshold ) + { + earlySkipISP = true; + splitIsSelected = false; + break; + } + } + } +#else uiSplitCbfLuma |= TU::getCbfAtDepth( *csSplit->getTU( partitioner.currArea().lumaPos(), partitioner.chType ), COMPONENT_Y, partitioner.currTrDepth ); +#endif @@ -1804,7 +2405,11 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par m_CABACEstimator->getCtx() = ctxStart; //----- determine rate and r-d cost ----- +#if JVET_M0102_INTRA_SUBPARTITIONS + csSplit->fracBits = xGetIntraFracBitsQT( *csSplit, partitioner, true, false, cu.ispMode ? 0 : -1, ispType ); +#else csSplit->fracBits = xGetIntraFracBitsQT(*csSplit, partitioner, true, false); +#endif //--- update cost --- csSplit->cost = m_pcRdCost->calcRdCost(csSplit->fracBits, csSplit->dist); @@ -1821,11 +2426,26 @@ void IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par #endif } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( cu.ispMode && earlySkipISP ) + { + cs.cost = MAX_DOUBLE; + } + else + { + cs.cost = m_pcRdCost->calcRdCost( cs.fracBits, cs.dist ); + } +#else cs.cost = m_pcRdCost->calcRdCost( cs.fracBits, cs.dist ); +#endif } } +#if JVET_M0102_INTRA_SUBPARTITIONS +ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitioner& partitioner, const double bestCostSoFar, const PartSplit ispType ) +#else ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partitioner& partitioner) +#endif { UnitArea currArea = partitioner.currArea(); const bool keepResi = cs.sps->getSpsNext().getUseLMChroma() || KEEP_PRED_AND_RESI_SIGNALS; @@ -1835,9 +2455,16 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition TransformUnit &currTU = *cs.getTU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA ); const PredictionUnit &pu = *cs.getPU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA ); #if !JVET_M0464_UNI_MTS +#if JVET_M0102_INTRA_SUBPARTITIONS + const TransformUnit &currTULuma = CS::isDualITree( cs ) ? *cs.picture->cs->getTU(currArea.lumaPos(), CHANNEL_TYPE_LUMA, 0 ) : currTU; +#else const TransformUnit &currTULuma = CS::isDualITree( cs ) ? *cs.picture->cs->getTU( currArea.lumaPos(), CHANNEL_TYPE_LUMA ) : currTU; #endif +#endif +#if JVET_M0102_INTRA_SUBPARTITIONS + bool lumaUsesISP = !CS::isDualITree( cs ) && currTU.cu->ispMode; +#endif uint32_t currDepth = partitioner.currTrDepth; const PPS &pps = *cs.pps; ChromaCbfs cbfs ( false ); @@ -1879,6 +2506,18 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition saveCS.area.repositionTo( cs.area ); saveCS.initStructData( MAX_INT, false, true ); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !CS::isDualITree( cs ) && currTU.cu->ispMode ) + { + saveCS.clearCUs(); + CodingUnit& auxCU = saveCS.addCU( *currTU.cu, partitioner.chType ); + auxCU.ispMode = currTU.cu->ispMode; + saveCS.sps = currTU.cs->sps; + saveCS.clearPUs(); + saveCS.addPU( *currTU.cu->firstPU, partitioner.chType ); + } +#endif + TransformUnit &tmpTU = saveCS.addTU(currArea, partitioner.chType); @@ -1969,6 +2608,17 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition { singleCostTmp = MAX_DOUBLE; } +#if JVET_M0102_INTRA_SUBPARTITIONS + else if( lumaUsesISP && bestCostSoFar != MAX_DOUBLE && c == COMPONENT_Cb ) + { + uint64_t fracBitsTmp = xGetIntraFracBitsQTSingleChromaComponent( cs, partitioner, ComponentID( c ) ); + singleCostTmp = m_pcRdCost->calcRdCost( fracBitsTmp, singleDistCTmp ); + if( isOneMode || ( !isOneMode && !isLastMode ) ) + { + m_CABACEstimator->getCtx() = ctxStart; + } + } +#endif else if( !isOneMode ) { uint64_t fracBitsTmp = xGetIntraFracBitsQTChroma( currTU, compID ); @@ -2004,6 +2654,17 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition } } +#if JVET_M0102_INTRA_SUBPARTITIONS + if( lumaUsesISP && dSingleCost > bestCostSoFar && c == COMPONENT_Cb ) + { + //Luma + Cb cost is already larger than the best cost, so we don't need to test Cr + cs.dist = MAX_UINT; + m_CABACEstimator->getCtx() = ctxStart; + break; + //return cbfs; + } +#endif + if (bestModeId < totalModesToTest) { #if KEEP_PRED_AND_RESI_SIGNALS @@ -2043,12 +2704,22 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition { partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs ); } +#if JVET_M0102_INTRA_SUBPARTITIONS + else if( currTU.cu->ispMode ) + { + partitioner.splitCurrArea( ispType, cs ); + } +#endif else THROW( "Implicit TU split not available" ); do { +#if JVET_M0102_INTRA_SUBPARTITIONS + ChromaCbfs subCbfs = xRecurIntraChromaCodingQT( cs, partitioner, bestCostSoFar, ispType ); +#else ChromaCbfs subCbfs = xRecurIntraChromaCodingQT( cs, partitioner ); +#endif for( uint32_t ch = COMPONENT_Cb; ch < numValidTBlocks; ch++ ) { @@ -2059,11 +2730,30 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition partitioner.exitCurrSplit(); +#if JVET_M0102_INTRA_SUBPARTITIONS + if( lumaUsesISP && cs.dist == MAX_UINT ) + { + return cbfs; + } +#endif { cbfs.Cb |= SplitCbfs.Cb; cbfs.Cr |= SplitCbfs.Cr; +#if JVET_M0102_INTRA_SUBPARTITIONS + if( !lumaUsesISP ) + { + for( auto &ptu : cs.tus ) + { + if( currArea.Cb().contains( ptu->Cb() ) || ( !ptu->Cb().valid() && currArea.Y().contains( ptu->Y() ) ) ) + { + TU::setCbfAtDepth( *ptu, COMPONENT_Cb, currDepth, SplitCbfs.Cb ); + TU::setCbfAtDepth( *ptu, COMPONENT_Cr, currDepth, SplitCbfs.Cr ); + } + } + } +#else for( auto &ptu : cs.tus ) { if( currArea.Cb().contains( ptu->Cb() ) || ( !ptu->Cb().valid() && currArea.Y().contains( ptu->Y() ) ) ) @@ -2072,6 +2762,7 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT(CodingStructure &cs, Partition TU::setCbfAtDepth( *ptu, COMPONENT_Cr, currDepth, SplitCbfs.Cr ); } } +#endif } } diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index e6d1cc7362db97f2044759f89d5eb15a489d21b9..9f4a99ac2a08fdfd6e02e63dbbbaa162658c7c1b 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -65,6 +65,9 @@ class EncModeCtrl; class IntraSearch : public IntraPrediction, CrossComponentPrediction { private: +#if JVET_M0102_INTRA_SUBPARTITIONS + EncModeCtrl *m_modeCtrl; +#endif Pel* m_pSharedPredTransformSkip[MAX_NUM_TBLOCKS]; XUCache m_unitCache; @@ -84,6 +87,15 @@ private: uint32_t m_savedRdModeList [4][NUM_LUMA_MODE], m_savedNumRdModes[4]; int m_savedExtendRefList[4][NUM_LUMA_MODE]; #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + static_vector<uint32_t, FAST_UDI_MAX_RDMODE_NUM> m_rdModeListWithoutMrl; + static_vector<uint32_t, FAST_UDI_MAX_RDMODE_NUM> m_rdModeListWithoutMrlHor; + static_vector<uint32_t, FAST_UDI_MAX_RDMODE_NUM> m_rdModeListWithoutMrlVer; + + static_vector<double, FAST_UDI_MAX_RDMODE_NUM> m_intraModeDiagRatio; + static_vector<double, FAST_UDI_MAX_RDMODE_NUM> m_intraModeHorVerRatio; + static_vector<int, FAST_UDI_MAX_RDMODE_NUM> m_intraModeTestedNormalIntra; +#endif #if JVET_M0427_INLOOP_RESHAPER PelStorage m_tmpStorageLCU; #endif @@ -128,10 +140,19 @@ public: CodingStructure****getFullCSBuf () { return m_pFullCS; } CodingStructure **getSaveCSBuf () { return m_pSaveCS; } +#if JVET_M0102_INTRA_SUBPARTITIONS + void setModeCtrl ( EncModeCtrl *modeCtrl ) { m_modeCtrl = modeCtrl; } +#endif + public: +#if JVET_M0102_INTRA_SUBPARTITIONS + void estIntraPredLumaQT ( CodingUnit &cu, Partitioner& pm, const double bestCostSoFar = MAX_DOUBLE ); + void estIntraPredChromaQT ( CodingUnit &cu, Partitioner& pm, const double maxCostAllowed = MAX_DOUBLE ); +#else void estIntraPredLumaQT ( CodingUnit &cu, Partitioner& pm ); void estIntraPredChromaQT (CodingUnit &cu, Partitioner& pm); +#endif void IPCMSearch (CodingStructure &cs, Partitioner& partitioner); uint64_t xFracModeBitsIntra (PredictionUnit &pu, const uint32_t &uiMode, const ChannelType &compID); @@ -147,12 +168,23 @@ protected: // Intra search // ------------------------------------------------------------------------------------------------------------------- +#if JVET_M0102_INTRA_SUBPARTITIONS + void xEncIntraHeader ( CodingStructure &cs, Partitioner& pm, const bool &luma, const bool &chroma, const int subTuIdx = -1 ); + void xEncSubdivCbfQT ( CodingStructure &cs, Partitioner& pm, const bool &luma, const bool &chroma, const int subTuIdx = -1, const PartSplit ispType = TU_NO_ISP ); + uint64_t xGetIntraFracBitsQT ( CodingStructure &cs, Partitioner& pm, const bool &luma, const bool &chroma, const int subTuIdx = -1, const PartSplit ispType = TU_NO_ISP ); + uint64_t xGetIntraFracBitsQTSingleChromaComponent( CodingStructure &cs, Partitioner& pm, const ComponentID compID ); +#else void xEncIntraHeader (CodingStructure &cs, Partitioner& pm, const bool &bLuma, const bool &bChroma); void xEncSubdivCbfQT (CodingStructure &cs, Partitioner& pm, const bool &bLuma, const bool &bChroma); uint64_t xGetIntraFracBitsQT (CodingStructure &cs, Partitioner& pm, const bool &bLuma, const bool &bChroma); +#endif uint64_t xGetIntraFracBitsQTChroma(TransformUnit& tu, const ComponentID &compID); +#if JVET_M0102_INTRA_SUBPARTITIONS + void xEncCoeffQT ( CodingStructure &cs, Partitioner& pm, const ComponentID compID, const int subTuIdx = -1, const PartSplit ispType = TU_NO_ISP ); +#else void xEncCoeffQT (CodingStructure &cs, Partitioner& pm, const ComponentID &compID); +#endif #if JVET_M0464_UNI_MTS @@ -161,9 +193,14 @@ protected: void xIntraCodingTUBlock (TransformUnit &tu, const ComponentID &compID, const bool &checkCrossCPrediction, Distortion& ruiDist, const int &default0Save1Load2 = 0, uint32_t* numSig = nullptr ); #endif +#if JVET_M0102_INTRA_SUBPARTITIONS + ChromaCbfs xRecurIntraChromaCodingQT( CodingStructure &cs, Partitioner& pm, const double bestCostSoFar = MAX_DOUBLE, const PartSplit ispType = TU_NO_ISP ); + void xRecurIntraCodingLumaQT ( CodingStructure &cs, Partitioner& pm, const double bestCostSoFar = MAX_DOUBLE, const int subTuIdx = -1, const PartSplit ispType = TU_NO_ISP ); +#else ChromaCbfs xRecurIntraChromaCodingQT (CodingStructure &cs, Partitioner& pm); void xRecurIntraCodingLumaQT ( CodingStructure &cs, Partitioner& pm ); +#endif void encPredIntraDPCM( const ComponentID &compID, PelBuf &pOrg, PelBuf &pDst, const uint32_t &uiDirMode );