From facb343be28bdf776365d39f8a024cd6abedf59a Mon Sep 17 00:00:00 2001 From: Adam Wieckowski <adam.wieckowski@hhi.fraunhofer.de> Date: Tue, 22 Jan 2019 16:10:16 +0100 Subject: [PATCH] JVET-M0421 --- source/Lib/CommonLib/ContextModelling.cpp | 113 ++++++++++++++++++++++ source/Lib/CommonLib/ContextModelling.h | 4 + source/Lib/CommonLib/Contexts.cpp | 42 ++++++++ source/Lib/CommonLib/Contexts.h | 6 ++ source/Lib/CommonLib/TypeDef.h | 2 + source/Lib/CommonLib/UnitPartitioner.cpp | 107 +++++++++++++++++++- source/Lib/CommonLib/UnitPartitioner.h | 8 +- source/Lib/DecoderLib/CABACReader.cpp | 89 ++++++++++++++++- source/Lib/DecoderLib/CABACReader.h | 4 + source/Lib/EncoderLib/CABACWriter.cpp | 83 +++++++++++++++- source/Lib/EncoderLib/CABACWriter.h | 4 + source/Lib/EncoderLib/EncCu.cpp | 24 +++++ 12 files changed, 482 insertions(+), 4 deletions(-) diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp index 57dd1636b..b9ae70afd 100644 --- a/source/Lib/CommonLib/ContextModelling.cpp +++ b/source/Lib/CommonLib/ContextModelling.cpp @@ -150,6 +150,116 @@ void CoeffCodingContext::initSubblock( int SubsetId, bool sigGroupFlag ) + +#if JVET_M0421_SPLIT_SIG +void DeriveCtx::CtxSplit( const CodingStructure& cs, Partitioner& partitioner, unsigned& ctxSpl, unsigned& ctxQt, unsigned& ctxHv, unsigned& ctxHorBt, unsigned& ctxVerBt, bool* _canSplit /*= nullptr */ ) +{ + const Position pos = partitioner.currArea().blocks[partitioner.chType]; + const unsigned curSliceIdx = cs.slice->getIndependentSliceIdx(); +#if HEVC_TILES_WPP + const unsigned curTileIdx = cs.picture->tileMap->getTileIdxMap( partitioner.currArea().lumaPos() ); +#endif + + // get left depth +#if HEVC_TILES_WPP + const CodingUnit* cuLeft = cs.getCURestricted( pos.offset( -1, 0 ), curSliceIdx, curTileIdx, partitioner.chType ); +#else + const CodingUnit* cuLeft = cs.getCURestricted( pos.offset( -1, 0 ), curSliceIdx, partitioner.chType ); +#endif + + // get above depth +#if HEVC_TILES_WPP + const CodingUnit* cuAbove = cs.getCURestricted( pos.offset( 0, -1 ), curSliceIdx, curTileIdx, partitioner.chType ); +#else + const CodingUnit* cuAbove = cs.getCURestricted( pos.offset( 0, -1 ), curSliceIdx, partitioner.chType ); +#endif + + bool canSplit[6]; + + if( _canSplit == nullptr ) + { + partitioner.canSplit( cs, canSplit[0], canSplit[1], canSplit[2], canSplit[3], canSplit[4], canSplit[5] ); + } + else + { + memcpy( canSplit, _canSplit, 6 * sizeof( bool ) ); + } + + /////////////////////// + // CTX do split (0-8) + /////////////////////// + const unsigned widthCurr = partitioner.currArea().blocks[partitioner.chType].width; + const unsigned heightCurr = partitioner.currArea().blocks[partitioner.chType].height; + + ctxSpl = 0; + + if( cuLeft ) + { + const unsigned heightLeft = cuLeft->blocks[partitioner.chType].height; + ctxSpl += ( heightLeft < heightCurr ? 1 : 0 ); + } + if( cuAbove ) + { + const unsigned widthAbove = cuAbove->blocks[partitioner.chType].width; + ctxSpl += ( widthAbove < widthCurr ? 1 : 0 ); + } + + unsigned numSplit = 0; + if( canSplit[1] ) numSplit += 2; + if( canSplit[2] ) numSplit += 1; + if( canSplit[3] ) numSplit += 1; + if( canSplit[4] ) numSplit += 1; + if( canSplit[5] ) numSplit += 1; + + if( numSplit > 0 ) numSplit--; + + ctxSpl += 3 * ( numSplit >> 1 ); + + ////////////////////////// + // CTX is qt split (0-5) + ////////////////////////// + ctxQt = ( cuLeft && cuLeft->qtDepth > partitioner.currQtDepth ) ? 1 : 0; + ctxQt += ( cuAbove && cuAbove->qtDepth > partitioner.currQtDepth ) ? 1 : 0; + ctxQt += partitioner.currQtDepth < 2 ? 0 : 3; + + //////////////////////////// + // CTX is ver split (0-4) + //////////////////////////// + ctxHv = 0; + + const unsigned numHor = ( canSplit[2] ? 1 : 0 ) + ( canSplit[4] ? 1 : 0 ); + const unsigned numVer = ( canSplit[3] ? 1 : 0 ) + ( canSplit[5] ? 1 : 0 ); + + if( numVer == numHor ) + { + const Area& area = partitioner.currArea().blocks[partitioner.chType]; + + const unsigned wAbove = cuAbove ? cuAbove->blocks[partitioner.chType].width : 1; + const unsigned hLeft = cuLeft ? cuLeft ->blocks[partitioner.chType].height : 1; + + const unsigned depAbove = area.width / wAbove; + const unsigned depLeft = area.height / hLeft; + + if( depAbove == depLeft || !cuLeft || !cuAbove ) ctxHv = 0; + else if( depAbove < depLeft ) ctxHv = 1; + else ctxHv = 2; + } + else if( numVer < numHor ) + { + ctxHv = 3; + } + else + { + ctxHv = 4; + } + + ////////////////////////// + // CTX is h/v bt (0-3) + ////////////////////////// + ctxHorBt = ( partitioner.currBtDepth >= 2 ? 1 : 0 ); + ctxVerBt = ( partitioner.currBtDepth >= 2 ? 3 : 2 ); +} +#else unsigned DeriveCtx::CtxCUsplit( const CodingStructure& cs, Partitioner& partitioner ) { auto adPartitioner = dynamic_cast<AdaptiveDepthPartitioner*>( &partitioner ); @@ -186,6 +296,7 @@ unsigned DeriveCtx::CtxCUsplit( const CodingStructure& cs, Partitioner& partitio return ctxId; } +#endif unsigned DeriveCtx::CtxQtCbf( const ComponentID compID, const unsigned trDepth, const bool prevCbCbf ) { @@ -258,6 +369,7 @@ unsigned DeriveCtx::CtxIMVFlag( const CodingUnit& cu ) return ctxId; } +#if !JVET_M0421_SPLIT_SIG unsigned DeriveCtx::CtxBTsplit(const CodingStructure& cs, Partitioner& partitioner) { const Position pos = partitioner.currArea().blocks[partitioner.chType]; @@ -306,6 +418,7 @@ unsigned DeriveCtx::CtxBTsplit(const CodingStructure& cs, Partitioner& partition return ctx; } +#endif unsigned DeriveCtx::CtxTriangleFlag( const CodingUnit& cu ) { const CodingStructure *cs = cu.cs; diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h index 76fba82a0..f0856345a 100644 --- a/source/Lib/CommonLib/ContextModelling.h +++ b/source/Lib/CommonLib/ContextModelling.h @@ -294,8 +294,12 @@ public: namespace DeriveCtx { +#if JVET_M0421_SPLIT_SIG +void CtxSplit ( const CodingStructure& cs, Partitioner& partitioner, unsigned& ctxSpl, unsigned& ctxQt, unsigned& ctxHv, unsigned& ctxHorBt, unsigned& ctxVerBt, bool* canSplit = nullptr ); +#else unsigned CtxCUsplit ( const CodingStructure& cs, Partitioner& partitioner ); unsigned CtxBTsplit ( const CodingStructure& cs, Partitioner& partitioner ); +#endif unsigned CtxQtCbf ( const ComponentID compID, const unsigned trDepth, const bool prevCbCbf ); unsigned CtxInterDir ( const PredictionUnit& pu ); unsigned CtxSkipFlag ( const CodingUnit& cu ); diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index 84a6947a1..cb190a390 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -349,6 +349,15 @@ std::vector<std::vector<uint8_t>> ContextSetCfg::sm_InitTables( NUMBER_OF_SLICE_ // clang-format off const CtxSet ContextSetCfg::SplitFlag = ContextSetCfg::addCtxSet ({ +#if JVET_M0421_SPLIT_SIG + // |-------- do split ctx -------------------| + { 93, 124, 141, 123, 125, 141, 139, 126, 157, }, + { 108, 139, 156, 138, 140, 141, 139, 141, 143, }, + { 153, 154, 172, 153, 140, 156, 154, 127, 159, }, +#if JVET_M0453_CABAC_ENGINE + { DWS, DWS, DWS, DWS, DWS, DWS, DWS, DWS, DWS, }, +#endif +#else #if JVET_M0453_CABAC_ENGINE { 107, 110, 127, 106, 123, 140,}, { 138, 140, 142, 106, 123, 125,}, @@ -359,8 +368,40 @@ const CtxSet ContextSetCfg::SplitFlag = ContextSetCfg::addCtxSet { 138, 111, 143, 107, 138, 140, }, { 138, 141, 158, 151, 124, 126, }, #endif +#endif +}); + +#if JVET_M0421_SPLIT_SIG +const CtxSet ContextSetCfg::SplitQtFlag = ContextSetCfg::addCtxSet +({ + { 153, 126, 142, 137, 109, 155, }, + { 153, 126, 157, 122, 138, 140, }, + { 153, 125, 127, 137, 153, 155, }, +#if JVET_M0453_CABAC_ENGINE + { DWS, DWS, DWS, DWS, DWS, DWS, }, +#endif +}); + +const CtxSet ContextSetCfg::SplitHvFlag = ContextSetCfg::addCtxSet +({ + { 154, 168, 155, 153, 155, }, + { 154, 168, 170, 153, 170, }, + { 154, 153, 140, 153, 154, }, +#if JVET_M0453_CABAC_ENGINE + { DWS, DWS, DWS, DWS, DWS, }, +#endif }); +const CtxSet ContextSetCfg::Split12Flag = ContextSetCfg::addCtxSet +({ + { 140, 154, 140, 154, }, + { 155, 169, 140, 154, }, + { 155, 154, 155, 154, }, +#if JVET_M0453_CABAC_ENGINE + { DWS, DWS, DWS, DWS, }, +#endif +}); +#else const CtxSet ContextSetCfg::BTSplitFlag = ContextSetCfg::addCtxSet ({ // |-------- 1st bin, 9 ctx for luma + 3 ctx for chroma------| |--2nd bin--| |3rd bin| @@ -375,6 +416,7 @@ const CtxSet ContextSetCfg::BTSplitFlag = ContextSetCfg::addCtxSet { 139, 141, 157, 139, 155, 142, 153, 125, 141, 154, 154, 154, 154, 154, 154, 140, }, #endif }); +#endif const CtxSet ContextSetCfg::SkipFlag = ContextSetCfg::addCtxSet ({ diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index dae5f60a0..336bf5453 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -245,7 +245,13 @@ class ContextSetCfg public: // context sets: specify offset and size static const CtxSet SplitFlag; +#if JVET_M0421_SPLIT_SIG + static const CtxSet SplitQtFlag; + static const CtxSet SplitHvFlag; + static const CtxSet Split12Flag; +#else static const CtxSet BTSplitFlag; +#endif static const CtxSet SkipFlag; static const CtxSet MergeFlag; static const CtxSet MergeIdx; diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 63a0c44fa..02dd93e30 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,6 +50,8 @@ #include <assert.h> #include <cassert> +#define JVET_M0421_SPLIT_SIG 1 + #define REMOVE_BIN_DECISION_TREE 1 // clang-format off diff --git a/source/Lib/CommonLib/UnitPartitioner.cpp b/source/Lib/CommonLib/UnitPartitioner.cpp index be921219b..82030ba6f 100644 --- a/source/Lib/CommonLib/UnitPartitioner.cpp +++ b/source/Lib/CommonLib/UnitPartitioner.cpp @@ -297,8 +297,89 @@ void QTBTPartitioner::splitCurrArea( const PartSplit split, const CodingStructur } } +#if JVET_M0421_SPLIT_SIG +void QTBTPartitioner::canSplit( const CodingStructure &cs, bool& canNo, bool& canQt, bool& canBh, bool& canBv, bool& canTh, bool& canTv ) +{ + const PartSplit implicitSplit = m_partStack.back().checkdIfImplicit ? m_partStack.back().implicitSplit : getImplicitSplit( cs ); + + const unsigned maxBTD = cs.pcv->getMaxBtDepth( *cs.slice, chType ) + currImplicitBtDepth; + const unsigned maxBtSize = cs.pcv->getMaxBtSize ( *cs.slice, chType ); + const unsigned minBtSize = cs.pcv->getMinBtSize ( *cs.slice, chType ); + const unsigned maxTtSize = cs.pcv->getMaxTtSize ( *cs.slice, chType ); + const unsigned minTtSize = cs.pcv->getMinTtSize ( *cs.slice, chType ); + const unsigned minQtSize = cs.pcv->getMinQtSize ( *cs.slice, chType ); + + canNo = canQt = canBh = canTh = canBv = canTv = true; + bool canBtt = currMtDepth < maxBTD; + + // the minimal and maximal sizes are given in luma samples + const CompArea& area = currArea().Y(); + PartLevel& level = m_partStack.back(); + + const PartSplit lastSplit = level.split; + const PartSplit parlSplit = lastSplit == CU_TRIH_SPLIT ? CU_HORZ_SPLIT : CU_VERT_SPLIT; + + // don't allow QT-splitting below a BT split + if( lastSplit != CTU_LEVEL && lastSplit != CU_QUAD_SPLIT ) canQt = false; + if( area.width <= minQtSize ) canQt = false; + + if( implicitSplit != CU_DONT_SPLIT ) + { + canNo = canTh = canTv = false; + + canBh = implicitSplit == CU_HORZ_SPLIT; + canBv = implicitSplit == CU_VERT_SPLIT; + + return; + } + + if( ( lastSplit == CU_TRIH_SPLIT || lastSplit == CU_TRIV_SPLIT ) && currPartIdx() == 1 ) + { + canBh = parlSplit != CU_HORZ_SPLIT; + canBv = parlSplit != CU_VERT_SPLIT; + } + + if( canBtt ) if( ( area.width <= minBtSize && area.height <= minBtSize ) + && ( ( area.width <= minTtSize && area.height <= minTtSize ) || cs.sps->getSpsNext().getMTTMode() == 0 ) ) canBtt = false; + if( canBtt ) if( ( area.width > maxBtSize || area.height > maxBtSize ) + && ( ( area.width > maxTtSize || area.height > maxTtSize ) || cs.sps->getSpsNext().getMTTMode() == 0 ) ) canBtt = false; + + if( !canBtt ) + { + canBh = canTh = canBv = canTv = false; + + return; + } + + // specific check for BT splits + if( area.height <= minBtSize || area.height > maxBtSize ) canBh = false; + if( area.width > MAX_TU_SIZE_FOR_PROFILE && area.height <= MAX_TU_SIZE_FOR_PROFILE ) canBh = false; + + if( area.width <= minBtSize || area.width > maxBtSize ) canBv = false; + if( area.width <= MAX_TU_SIZE_FOR_PROFILE && area.height > MAX_TU_SIZE_FOR_PROFILE ) canBv = false; + + if( ( cs.sps->getSpsNext().getMTTMode() & 1 ) != 1 ) canTh = false; + if( area.height <= 2 * minTtSize || area.height > maxTtSize || area.width > maxTtSize ) + canTh = false; + if( area.width > MAX_TU_SIZE_FOR_PROFILE || area.height > MAX_TU_SIZE_FOR_PROFILE ) canTh = false; + + if( ( cs.sps->getSpsNext().getMTTMode() & 1 ) != 1 ) canTv = false; + if( area.width <= 2 * minTtSize || area.width > maxTtSize || area.height > maxTtSize ) + canTv = false; + if( area.width > MAX_TU_SIZE_FOR_PROFILE || area.height > MAX_TU_SIZE_FOR_PROFILE ) canTv = false; +} + +#endif bool QTBTPartitioner::canSplit( const PartSplit split, const CodingStructure &cs ) { +#if JVET_M0421_SPLIT_SIG + const CompArea area = currArea().Y(); + const unsigned maxTrSize = cs.sps->getMaxTrSize(); + + bool canNo, canQt, canBh, canTh, canBv, canTv; + + canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv ); +#else const PartSplit implicitSplit = getImplicitSplit( cs ); // the minimal and maximal sizes are given in luma samples @@ -319,6 +400,7 @@ bool QTBTPartitioner::canSplit( const PartSplit split, const CodingStructure &cs return false; } +#endif switch( split ) { case CTU_LEVEL: @@ -328,6 +410,20 @@ bool QTBTPartitioner::canSplit( const PartSplit split, const CodingStructure &cs case TU_MAX_TR_SPLIT: return area.width > maxTrSize || area.height > maxTrSize; break; +#if JVET_M0421_SPLIT_SIG + case CU_QUAD_SPLIT: + return canQt; + case CU_DONT_SPLIT: + return canNo; + case CU_HORZ_SPLIT: + return canBh; + case CU_VERT_SPLIT: + return canBv; + case CU_TRIH_SPLIT: + return canTh; + case CU_TRIV_SPLIT: + return canTv; +#else case CU_QUAD_SPLIT: { // don't allow QT-splitting below a BT split @@ -369,8 +465,15 @@ bool QTBTPartitioner::canSplit( const PartSplit split, const CodingStructure &cs } if( implicitSplit == split ) return true; if( implicitSplit != CU_DONT_SPLIT && implicitSplit != split ) return false; +#endif case CU_MT_SPLIT: +#if JVET_M0421_SPLIT_SIG + return ( canBh || canTh || canBv || canTv ); +#endif case CU_BT_SPLIT: +#if JVET_M0421_SPLIT_SIG + return ( canBh || canBv ); +#else { if( currMtDepth >= maxBTD ) return false; if( ( area.width <= minBtSize && area.height <= minBtSize ) @@ -382,13 +485,14 @@ bool QTBTPartitioner::canSplit( const PartSplit split, const CodingStructure &cs return false; } } +#endif break; default: THROW( "Unknown split mode" ); return false; break; } - +#if !JVET_M0421_SPLIT_SIG // specific check for BT splits switch( split ) { @@ -413,6 +517,7 @@ bool QTBTPartitioner::canSplit( const PartSplit split, const CodingStructure &cs default: break; } +#endif return true; } diff --git a/source/Lib/CommonLib/UnitPartitioner.h b/source/Lib/CommonLib/UnitPartitioner.h index 6b8e354f9..222fe99ed 100644 --- a/source/Lib/CommonLib/UnitPartitioner.h +++ b/source/Lib/CommonLib/UnitPartitioner.h @@ -128,6 +128,9 @@ public: virtual void copyState ( const Partitioner& other ); public: +#if JVET_M0421_SPLIT_SIG + virtual void canSplit ( const CodingStructure &cs, bool& canNo, bool& canQt, bool& canBh, bool& canBv, bool& canTh, bool& canTv ) = 0; +#endif virtual bool canSplit ( const PartSplit split, const CodingStructure &cs ) = 0; virtual bool isSplitImplicit ( const PartSplit split, const CodingStructure &cs ) = 0; virtual PartSplit getImplicitSplit ( const CodingStructure &cs ) = 0; @@ -147,7 +150,10 @@ public: void exitCurrSplit (); bool nextPart ( const CodingStructure &cs, bool autoPop = false ); bool hasNextPart (); - + +#if JVET_M0421_SPLIT_SIG + void canSplit ( const CodingStructure &cs, bool& canNo, bool& canQt, bool& canBh, bool& canBv, bool& canTh, bool& canTv ); +#endif bool canSplit ( const PartSplit split, const CodingStructure &cs ); bool isSplitImplicit ( const PartSplit split, const CodingStructure &cs ); PartSplit getImplicitSplit ( const CodingStructure &cs ); diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index aa33ec56f..f1ee33467 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -421,6 +421,14 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU } } +#if JVET_M0421_SPLIT_SIG + const PartSplit splitMode = split_cu_mode( cs, partitioner ); + + CHECK( !partitioner.canSplit( splitMode, cs ), "Got an invalid split!" ); + + if( splitMode != CU_DONT_SPLIT ) + { +#else const PartSplit implicitSplit = partitioner.getImplicitSplit( cs ); // QT @@ -440,6 +448,7 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU // quad-tree split if( qtSplit ) { +#endif if (CS::isDualITree(cs) && pPartitionerChroma != nullptr && (partitioner.currArea().lwidth() >= 64 || partitioner.currArea().lheight() >= 64)) { partitioner.splitCurrArea(CU_QUAD_SPLIT, cs); @@ -519,7 +528,11 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU } else { +#if JVET_M0421_SPLIT_SIG + partitioner.splitCurrArea( splitMode, cs ); +#else partitioner.splitCurrArea( CU_QUAD_SPLIT, cs ); +#endif do { if( !lastSegment && cs.area.blocks[partitioner.chType].contains( partitioner.currArea().blocks[partitioner.chType].pos() ) ) @@ -531,9 +544,12 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU partitioner.exitCurrSplit(); } return lastSegment; +#if !JVET_M0421_SPLIT_SIG } +#endif } +#if !JVET_M0421_SPLIT_SIG { // MT bool mtSplit = partitioner.canSplit( CU_MT_SPLIT, cs ); @@ -560,7 +576,7 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU } } - +#endif CodingUnit& cu = cs.addCU( CS::getArea( cs, currArea, partitioner.chType ), partitioner.chType ); partitioner.setCUData( cu ); @@ -595,6 +611,76 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU return isLastCtu; } +#if JVET_M0421_SPLIT_SIG +PartSplit CABACReader::split_cu_mode( CodingStructure& cs, Partitioner &partitioner ) +{ + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2( STATS__CABAC_BITS__SPLIT_FLAG, partitioner.currArea().blocks[partitioner.chType].size(), partitioner.chType ); + + PartSplit mode = CU_DONT_SPLIT; + + bool canNo, canQt, canBh, canBv, canTh, canTv; + partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv ); + + bool canSpl[6] = { canNo, canQt, canBh, canBv, canTh, canTv }; + + unsigned ctxSplit = 0, ctxQtSplit = 0, ctxBttHV = 0, ctxBttH12 = 0, ctxBttV12; + DeriveCtx::CtxSplit( cs, partitioner, ctxSplit, ctxQtSplit, ctxBttHV, ctxBttH12, ctxBttV12, canSpl ); + + bool isSplit = canBh || canBv || canTh || canTv || canQt; + + if( canNo && isSplit ) + { + isSplit = m_BinDecoder.decodeBin( Ctx::SplitFlag( ctxSplit ) ); + } + + DTRACE( g_trace_ctx, D_SYNTAX, "split_cu_mode() ctx=%d split=%d\n", ctxSplit, isSplit ); + + if( !isSplit ) + { + return CU_DONT_SPLIT; + } + + const bool canBtt = canBh || canBv || canTh || canTv; + bool isQt = canQt; + + if( isQt && canBtt ) + { + isQt = m_BinDecoder.decodeBin( Ctx::SplitQtFlag( ctxQtSplit ) ); + } + + DTRACE( g_trace_ctx, D_SYNTAX, "split_cu_mode() ctx=%d qt=%d\n", ctxQtSplit, isQt ); + + if( isQt ) + { + return CU_QUAD_SPLIT; + } + + const bool canHor = canBh || canTh; + bool isVer = canBv || canTv; + + if( isVer && canHor ) + { + isVer = m_BinDecoder.decodeBin( Ctx::SplitHvFlag( ctxBttHV ) ); + } + + const bool can14 = isVer ? canTv : canTh; + bool is12 = isVer ? canBv : canBh; + + if( is12 && can14 ) + { + is12 = m_BinDecoder.decodeBin( Ctx::Split12Flag( isVer ? ctxBttV12 : ctxBttH12 ) ); + } + + if ( isVer && is12 ) mode = CU_VERT_SPLIT; + else if( isVer && !is12 ) mode = CU_TRIV_SPLIT; + else if( !isVer && is12 ) mode = CU_HORZ_SPLIT; + else mode = CU_TRIH_SPLIT; + + DTRACE( g_trace_ctx, D_SYNTAX, "split_cu_mode() ctxHv=%d ctx12=%d mode=%d\n", ctxBttHV, isVer ? ctxBttV12 : ctxBttH12, mode ); + + return mode; +} +#else PartSplit CABACReader::split_cu_mode_mt( CodingStructure& cs, Partitioner &partitioner ) { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__SPLIT_FLAG ); @@ -694,6 +780,7 @@ bool CABACReader::split_cu_flag( CodingStructure& cs, Partitioner &partitioner ) return split; } +#endif //================================================================================ // clause 7.3.8.5 diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 89dcf70e7..1fb95d7fb 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -70,8 +70,12 @@ public: // coding (quad)tree (clause 7.3.8.4) bool coding_tree ( CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, Partitioner* pPartitionerChroma = nullptr, CUCtx* pCuCtxChroma = nullptr); +#if JVET_M0421_SPLIT_SIG + PartSplit split_cu_mode ( CodingStructure& cs, Partitioner& pm ); +#else bool split_cu_flag ( CodingStructure& cs, Partitioner& pm ); PartSplit split_cu_mode_mt ( CodingStructure& cs, Partitioner& pm ); +#endif // coding unit (clause 7.3.8.5) bool coding_unit ( CodingUnit& cu, Partitioner& pm, CUCtx& cuCtx ); diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 014198831..453fc371f 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -396,6 +396,16 @@ void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitione } } +#if JVET_M0421_SPLIT_SIG + const PartSplit splitMode = CU::getSplitAtDepth( cu, partitioner.currDepth ); + + split_cu_mode( splitMode, cs, partitioner ); + + CHECK( !partitioner.canSplit( splitMode, cs ), "The chosen split mode is invalid!" ); + + if( splitMode != CU_DONT_SPLIT ) + { +#else const PartSplit implicitSplit = partitioner.getImplicitSplit( cs ); // QT @@ -415,6 +425,7 @@ void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitione // quad-tree split if( qtSplit ) { +#endif if (CS::isDualITree(cs) && pPartitionerChroma != nullptr && (partitioner.currArea().lwidth() >= 64 || partitioner.currArea().lheight() >= 64)) { partitioner.splitCurrArea(CU_QUAD_SPLIT, cs); @@ -459,7 +470,11 @@ void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitione } else { +#if JVET_M0421_SPLIT_SIG + partitioner.splitCurrArea( splitMode, cs ); +#else partitioner.splitCurrArea( CU_QUAD_SPLIT, cs ); +#endif do { @@ -472,9 +487,12 @@ void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitione partitioner.exitCurrSplit(); } return; +#if !JVET_M0421_SPLIT_SIG } +#endif } +#if !JVET_M0421_SPLIT_SIG { bool mtSplit = partitioner.canSplit( CU_MT_SPLIT, cs ); @@ -501,6 +519,7 @@ void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitione } } +#endif // Predict QP on start of quantization group if( pps.getUseDQP() && !cuCtx.isDQPCoded && CU::isQGStart( cu, partitioner ) ) { @@ -515,6 +534,68 @@ void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitione DTRACE_BLOCK_REC_COND( ( !isEncoding() ), cs.picture->getRecoBuf( cu ), cu, cu.predMode ); } +#if JVET_M0421_SPLIT_SIG +void CABACWriter::split_cu_mode( const PartSplit split, const CodingStructure& cs, Partitioner& partitioner ) +{ + bool canNo, canQt, canBh, canBv, canTh, canTv; + partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv ); + + bool canSpl[6] = { canNo, canQt, canBh, canBv, canTh, canTv }; + + unsigned ctxSplit = 0, ctxQtSplit = 0, ctxBttHV = 0, ctxBttH12 = 0, ctxBttV12; + DeriveCtx::CtxSplit( cs, partitioner, ctxSplit, ctxQtSplit, ctxBttHV, ctxBttH12, ctxBttV12, canSpl ); + + const bool canSplit = canBh || canBv || canTh || canTv || canQt; + const bool isNo = split == CU_DONT_SPLIT; + + if( canNo && canSplit ) + { + m_BinEncoder.encodeBin( !isNo, Ctx::SplitFlag( ctxSplit ) ); + } + + DTRACE( g_trace_ctx, D_SYNTAX, "split_cu_mode() ctx=%d split=%d\n", ctxSplit, !isNo ); + + if( isNo ) + { + return; + } + + const bool canBtt = canBh || canBv || canTh || canTv; + const bool isQt = split == CU_QUAD_SPLIT; + + if( canQt && canBtt ) + { + m_BinEncoder.encodeBin( isQt, Ctx::SplitQtFlag( ctxQtSplit ) ); + } + + DTRACE( g_trace_ctx, D_SYNTAX, "split_cu_mode() ctx=%d qt=%d\n", ctxQtSplit, isQt ); + + if( isQt ) + { + return; + } + + const bool canHor = canBh || canTh; + const bool canVer = canBv || canTv; + const bool isVer = split == CU_VERT_SPLIT || split == CU_TRIV_SPLIT; + + if( canVer && canHor ) + { + m_BinEncoder.encodeBin( isVer, Ctx::SplitHvFlag( ctxBttHV ) ); + } + + const bool can14 = isVer ? canTv : canTh; + const bool can12 = isVer ? canBv : canBh; + const bool is12 = isVer ? ( split == CU_VERT_SPLIT ) : ( split == CU_HORZ_SPLIT ); + + if( can12 && can14 ) + { + m_BinEncoder.encodeBin( is12, Ctx::Split12Flag( isVer ? ctxBttV12 : ctxBttH12 ) ); + } + + DTRACE( g_trace_ctx, D_SYNTAX, "split_cu_mode() ctxHv=%d ctx12=%d mode=%d\n", ctxBttHV, isVer ? ctxBttV12 : ctxBttH12, split ); +} +#else void CABACWriter::split_cu_flag( bool split, const CodingStructure& cs, Partitioner& partitioner ) { unsigned maxQTDepth = ( g_aucLog2[cs.sps->getCTUSize()] - g_aucLog2[cs.sps->getMinQTSize(cs.slice->getSliceType(), partitioner.chType)] ); @@ -600,7 +681,7 @@ void CABACWriter::split_cu_mode_mt(const PartSplit split, const CodingStructure& DTRACE(g_trace_ctx, D_SYNTAX, "split_cu_mode_mt() ctx=%d split=%d\n", ctxIdBT, split); } - +#endif //================================================================================ // clause 7.3.8.5 diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index 46820c7be..a43066e4c 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -82,8 +82,12 @@ public: void sao_offset_pars ( const SAOOffset& ctbPars, ComponentID compID, bool sliceEnabled, int bitDepth ); // coding (quad)tree (clause 7.3.8.4) void coding_tree ( const CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, Partitioner* pPartitionerChroma = nullptr, CUCtx* pCuCtxChroma = nullptr); +#if JVET_M0421_SPLIT_SIG + void split_cu_mode ( const PartSplit split, const CodingStructure& cs, Partitioner& pm ); +#else void split_cu_flag ( bool split, const CodingStructure& cs, Partitioner& pm ); void split_cu_mode_mt ( const PartSplit split, const CodingStructure& cs, Partitioner& pm ); +#endif // coding unit (clause 7.3.8.5) void coding_unit ( const CodingUnit& cu, Partitioner& pm, CUCtx& cuCtx ); diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index d34cdde6d..0c1987e0c 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -1029,10 +1029,19 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, m_CABACEstimator->getCtx() = m_CurrCtx->start; const TempCtx ctxStartSP( m_CtxCache, SubCtx( Ctx::SplitFlag, m_CABACEstimator->getCtx() ) ); +#if JVET_M0421_SPLIT_SIG + const TempCtx ctxStartQt( m_CtxCache, SubCtx( Ctx::SplitQtFlag, m_CABACEstimator->getCtx() ) ); + const TempCtx ctxStartHv( m_CtxCache, SubCtx( Ctx::SplitHvFlag, m_CABACEstimator->getCtx() ) ); + const TempCtx ctxStart12( m_CtxCache, SubCtx( Ctx::Split12Flag, m_CABACEstimator->getCtx() ) ); +#else const TempCtx ctxStartBT( m_CtxCache, SubCtx( Ctx::BTSplitFlag, m_CABACEstimator->getCtx() ) ); +#endif m_CABACEstimator->resetBits(); +#if JVET_M0421_SPLIT_SIG + m_CABACEstimator->split_cu_mode( split, *tempCS, partitioner ); +#else if( partitioner.getImplicitSplit( *tempCS ) != CU_QUAD_SPLIT ) { if( partitioner.canSplit( CU_QUAD_SPLIT, *tempCS ) ) @@ -1044,12 +1053,19 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, m_CABACEstimator->split_cu_mode_mt( split, *tempCS, partitioner ); } } +#endif const double factor = ( tempCS->currQP[partitioner.chType] > 30 ? 1.1 : 1.075 ); const double cost = m_pcRdCost->calcRdCost( uint64_t( m_CABACEstimator->getEstFracBits() + ( ( bestCS->fracBits ) / factor ) ), Distortion( bestCS->dist / factor ) ); m_CABACEstimator->getCtx() = SubCtx( Ctx::SplitFlag, ctxStartSP ); +#if JVET_M0421_SPLIT_SIG + m_CABACEstimator->getCtx() = SubCtx( Ctx::SplitQtFlag, ctxStartQt ); + m_CABACEstimator->getCtx() = SubCtx( Ctx::SplitHvFlag, ctxStartHv ); + m_CABACEstimator->getCtx() = SubCtx( Ctx::Split12Flag, ctxStart12 ); +#else m_CABACEstimator->getCtx() = SubCtx( Ctx::BTSplitFlag, ctxStartBT ); +#endif if( cost > bestCS->cost ) { @@ -1159,6 +1175,9 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, { m_CABACEstimator->resetBits(); +#if JVET_M0421_SPLIT_SIG + m_CABACEstimator->split_cu_mode( split, *tempCS, partitioner ); +#else if( partitioner.canSplit( CU_QUAD_SPLIT, *tempCS ) ) { m_CABACEstimator->split_cu_flag( split == CU_QUAD_SPLIT, *tempCS, partitioner ); @@ -1167,6 +1186,7 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, { m_CABACEstimator->split_cu_mode_mt( split, *tempCS, partitioner ); } +#endif tempCS->fracBits += m_CABACEstimator->getEstFracBits(); // split bits } @@ -3542,6 +3562,9 @@ void EncCu::xEncodeDontSplit( CodingStructure &cs, Partitioner &partitioner ) { m_CABACEstimator->resetBits(); +#if JVET_M0421_SPLIT_SIG + m_CABACEstimator->split_cu_mode( CU_DONT_SPLIT, cs, partitioner ); +#else { if( partitioner.canSplit( CU_QUAD_SPLIT, cs ) ) { @@ -3552,6 +3575,7 @@ void EncCu::xEncodeDontSplit( CodingStructure &cs, Partitioner &partitioner ) m_CABACEstimator->split_cu_mode_mt( CU_DONT_SPLIT, cs, partitioner ); } } +#endif cs.fracBits += m_CABACEstimator->getEstFracBits(); // split bits cs.cost = m_pcRdCost->calcRdCost( cs.fracBits, cs.dist ); -- GitLab