diff --git a/doc/software-manual.tex b/doc/software-manual.tex index 23639440535ce52013a5ac599f67ed8b52358429..27957a7f0e56384f4af6ea5f488d0fcd8ef38805 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -1614,9 +1614,9 @@ Specifies the maximum depth for CU chroma QP adjustment; if negative, CU chroma %% -%% Slice coding parameters +%% Slice/Tile/Brick coding parameters %% -\begin{OptionTableNoShorthand}{Slice coding parameters}{tab:slice-coding} +\begin{OptionTableNoShorthand}{Slice, tile and brick coding parameters}{tab:slice-coding} %\Option{SliceGranularity} & %\ShortOption{\None} & %\Default{0} & @@ -1641,40 +1641,21 @@ SliceArgument. \par \begin{tabular}{cp{0.45\textwidth}} 0 & Single slice \\ - 1 & Maximum number of CTUs per slice \\ - 2 & Maximum number of bytes per slice \\ + 1 & (deprecated) Maximum number of CTUs per slice \\ + 2 & (deprecated) Maximum number of bytes per slice \\ 3 & Maximum number of tiles per slice \\ + 4 & One slice per brick \end{tabular} \\ \Option{SliceArgument} & %\ShortOption{\None} & \Default{\NotSet} & +(deprecated) Specifies the maximum number of CTUs, bytes or tiles in a slice depending on the SliceMode setting. \\ -\Option{SliceSegmentMode} & -%\ShortOption{\None} & -\Default{0} & -Enables (dependent) slice segment coding in conjunction with -SliceSegmentArgument. -\par -\begin{tabular}{cp{0.45\textwidth}} - 0 & Single slice \\ - 1 & Maximum number of CTUs per slice segment\\ - 2 & Maximum number of bytes per slice segment\\ - 3 & Maximum number of tiles per slice segment\\ -\end{tabular} -\\ - -\Option{SliceSegmentArgument} & -%\ShortOption{\None} & -\Default{\NotSet} & -Defines the maximum number of CTUs, bytes or tiles a slice segment -depending on the SliceSegmentMode setting. -\\ - \Option{WaveFrontSynchro} & %\ShortOption{\None} & \Default{false} & @@ -1712,6 +1693,35 @@ Specifies a space or comma separated list of widths and heights, respectively, of each tile column or tile row. The first value in the list corresponds to the leftmost tile column or topmost tile row. \\ + +\Option{BrickSplit1}% +\Option{BrickSplit2} % +\Option{BrickSplitN} & +%\ShortOption{\None} & +\Default{\NotSet} & +Specifies the splitting of tiles into bricks, N can be in the range of 1 to 128 and has no further meaning except to distinguish different splitting parameters. + +The following options are supported: + +BrickSplitN tileIdx uniform (numsplits) heights + +\begin{tabular}{cp{0.45\textwidth}} + tileIdx & the index of the tile to be split in raster scan order starting with zero \\ + uniform & specifies whether uniform splitting shall be used (1 for uniform, 0 non-uniform) \\ + numsplits & specifies the number of splits, if uniform is not used \\ + heights & specifies the height of the uniform splits or a list of heights for non-uniform splits \\ +\end{tabular} + +\\ +\Option{TileRowHeightArray} & +%\ShortOption{\None} & +\Default{\NotSet} & +Specifies a space or comma separated list of widths and heights, +respectively, of each tile column or tile row. The first value in the +list corresponds to the leftmost tile column or topmost tile row. +\\ + + \end{OptionTableNoShorthand} diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 4a309088d49ee563b9fd806a1977e0c0758d4a76..e198d86c9dec3a305504e87c608309dbcc92234c 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -517,6 +517,18 @@ void EncApp::xInitLibCfg() m_cEncLib.setColumnWidth ( m_tileColumnWidth ); m_cEncLib.setRowHeight ( m_tileRowHeight ); } +#if JVET_N0857_TILES_BRICKS + m_cEncLib.setRectSliceFlag ( m_rectSliceFlag ); + m_cEncLib.setNumSlicesInPicMinus1 ( m_numSlicesInPicMinus1 ); + m_cEncLib.setTopLeftTileIdx ( m_topLeftTileIdx ); + m_cEncLib.setBottomRightTileIdx ( m_bottomRightTileIdx ); + m_cEncLib.setLoopFilterAcrossSlicesEnabledFlag ( m_loopFilterAcrossSlicesEnabledFlag ); + m_cEncLib.setSignalledSliceIdFlag ( m_signalledSliceIdFlag ), + m_cEncLib.setSignalledSliceIdLengthMinus1 ( m_signalledSliceIdLengthMinus1 ); + m_cEncLib.setSliceId ( m_sliceId ); + m_cEncLib.setBrickSplitMap (m_brickSplitMap); +#endif + m_cEncLib.xCheckGSParameters(); int uiTilesCount = (m_numTileRowsMinus1+1) * (m_numTileColumnsMinus1+1); if(uiTilesCount == 1) diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 863b17852d6349fb74fa24e82f38c0dbfa43c0a2..70465096dbda289862bbf321fac39718a866d2ec 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -217,6 +217,28 @@ std::istringstream &operator>>(std::istringstream &in, GOPEntry &entry) //in return in; } +#if JVET_N0857_TILES_BRICKS +std::istringstream &operator>>(std::istringstream &in, BrickSplit &entry) //input +{ + in>>entry.m_tileIdx; + in>>entry.m_uniformSplit; + if (entry.m_uniformSplit) + { + in>>entry.m_uniformHeight; + } + else + { + in>>entry.m_numSplits; + for ( int i = 0; i < entry.m_numSplits; i++ ) + { + in>>entry.m_brickHeight[i]; + } + } + return in; +} + +#endif + bool confirmPara(bool bflag, const char* message); static inline ChromaFormat numberToChromaFormat(const int val) @@ -689,6 +711,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) SMultiValueInput<int> cfg_codedPivotValue (std::numeric_limits<int>::min(), std::numeric_limits<int>::max(), 0, 1<<16); SMultiValueInput<int> cfg_targetPivotValue (std::numeric_limits<int>::min(), std::numeric_limits<int>::max(), 0, 1<<16); +#if JVET_N0857_TILES_BRICKS + SMultiValueInput<uint32_t> cfg_TileGroupIdx (0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max()); + SMultiValueInput<uint32_t> cfg_SignalledTileGroupId (0, std::numeric_limits<uint32_t>::max(), 0, std::numeric_limits<uint32_t>::max()); +#endif + SMultiValueInput<double> cfg_adIntraLambdaModifier (0, std::numeric_limits<double>::max(), 0, MAX_TLAYER); ///< Lambda modifier for Intra pictures, one for each temporal layer. If size>temporalLayer, then use [temporalLayer], else if size>0, use [size()-1], else use m_adLambdaModifier. #if SHARP_LUMA_DELTA_QP @@ -1076,7 +1103,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) #if K0238_SAO_GREEDY_MERGE_ENCODING ("SAOGreedyEnc", m_saoGreedyMergeEnc, false, "SAO greedy merge encoding algorithm") #endif +#if JVET_N0857_TILES_BRICKS + ("SliceMode", tmpSliceMode, int(NO_SLICES), "0: Disable all Recon slice limits, 1: (deprecated #CTU), 2: (deprecated #bytes), 3:specify tiles per slice, 4: one brick per slice") +#else ("SliceMode", tmpSliceMode, int(NO_SLICES), "0: Disable all Recon slice limits, 1: Enforce max # of CTUs, 2: Enforce max # of bytes, 3:specify tiles per dependent slice") +#endif ("SliceArgument", m_sliceArgument, 0, "Depending on SliceMode being:" "\t1: max number of CTUs per slice" "\t2: max number of bytes per slice" @@ -1107,9 +1138,10 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("Log2ParallelMergeLevel", m_log2ParallelMergeLevel, 2u, "Parallel merge estimation region") //deprecated copies of renamed tile parameters ("UniformSpacingIdc", m_tileUniformSpacingFlag, false, "deprecated alias of TileUniformSpacing") +#if !JVET_N0857_TILES_BRICKS ("ColumnWidthArray", cfg_ColumnWidth, cfg_ColumnWidth, "deprecated alias of TileColumnWidthArray") ("RowHeightArray", cfg_RowHeight, cfg_RowHeight, "deprecated alias of TileRowHeightArray") - +#endif ("TileUniformSpacing", m_tileUniformSpacingFlag, false, "Indicates that tile columns and rows are distributed uniformly") ("NumTileColumnsMinus1", m_numTileColumnsMinus1, 0, "Number of tile columns in a picture minus 1") ("NumTileRowsMinus1", m_numTileRowsMinus1, 0, "Number of rows in a picture minus 1") @@ -1117,6 +1149,17 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("TileRowHeightArray", cfg_RowHeight, cfg_RowHeight, "Array containing tile row height values in units of CTU") ("LFCrossTileBoundaryFlag", m_bLFCrossTileBoundaryFlag, true, "1: cross-tile-boundary loop filtering. 0:non-cross-tile-boundary loop filtering") ("WaveFrontSynchro", m_entropyCodingSyncEnabledFlag, false, "0: entropy coding sync disabled; 1 entropy coding sync enabled") + +#if JVET_N0857_TILES_BRICKS + ("RectTileGroupFlag", m_rectSliceFlag, true, "Rectangular tile group flag") + ("SlicesInPicMinus1", m_numSlicesInPicMinus1, 0, "Number tile groups in pic minus 1") + ("LoopFilterAcrossTileGroupsEnabledFlag", m_loopFilterAcrossSlicesEnabledFlag, false, "Loop Filter Across Tile Groups Flag") + ("SignalledIdFlag", m_signalledSliceIdFlag, false, "Signalled Slice ID Flag") + ("SignalledSliceIdLengthMinus1", m_signalledSliceIdLengthMinus1, 0, "Signalled Tile Group Length minus 1") + ("TileGroupsInPic", cfg_TileGroupIdx, cfg_TileGroupIdx, "Tile Groups In Pic") + ("SignalledTileGroupId", cfg_SignalledTileGroupId, cfg_TileGroupIdx, "Signalled Tile Group ID") +#endif + #if HEVC_USE_SCALING_LISTS ("ScalingList", m_useScalingListId, SCALING_LIST_OFF, "0/off: no scaling list, 1/default: default scaling lists, 2/file: scaling lists specified in ScalingListFile") ("ScalingListFile", m_scalingListFileName, string(""), "Scaling list file name. Use an empty string to produce help.") @@ -1349,6 +1392,16 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) cOSS<<"Frame"<<i; opts.addOptions()(cOSS.str(), m_GOPList[i-1], GOPEntry()); } + +#if JVET_N0857_TILES_BRICKS + for(int i=1; i<MAX_TILES+1; i++) + { + std::ostringstream cOSS; + cOSS<<"BrickSplit"<<i; + opts.addOptions()(cOSS.str(), m_brickSplits[i-1], BrickSplit()); + } +#endif + po::setDefaults(opts); po::ErrorReporter err; const list<const char*>& argv_unhandled = po::scanArgv(opts, argc, (const char**) argv, err); @@ -1663,6 +1716,14 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) EXIT( "Error: bad slice mode"); } m_sliceMode = SliceConstraint(tmpSliceMode); +#if JVET_N0857_TILES_BRICKS + if (m_sliceMode==FIXED_NUMBER_OF_CTU || m_sliceMode==FIXED_NUMBER_OF_BYTES) + { + // note: slice mode 2 can be re-enabled using scan order tiles + EXIT( "Error: slice mode 1 (fixed number of CTUs) and 2 (fixed number of bytes) are no longer supported"); + } +#endif + #if HEVC_DEPENDENT_SLICES if (tmpSliceSegmentMode<0 || tmpSliceSegmentMode>=int(NUMBER_OF_SLICE_CONSTRAINT_MODES)) @@ -1672,6 +1733,64 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) m_sliceSegmentMode = SliceConstraint(tmpSliceSegmentMode); #endif +#if JVET_N0857_TILES_BRICKS + m_topLeftTileIdx.clear(); + m_bottomRightTileIdx.clear(); + m_sliceId.clear(); + + bool singleTileInPicFlag = (m_numTileRowsMinus1 == 0 && m_numTileColumnsMinus1 == 0); + + if (!singleTileInPicFlag) + { + //if (!m_singleBrickPerSliceFlag && m_rectSliceFlag) + if (m_sliceMode != 0 && m_sliceMode != 4 && m_rectSliceFlag) + { + int numTileGroupsInPic = m_numSlicesInPicMinus1 + 1; + + if (cfg_TileGroupIdx.values.size() > numTileGroupsInPic * 2) + { + EXIT("Error: The number of Tile group indexs are greater than the numTileGroupsInPicMinus1."); + } + else if (cfg_TileGroupIdx.values.size() < numTileGroupsInPic * 2) + { + EXIT("Error: The number of Tile group indexs are less than the numTileGroupsInPicMinus1."); + } + else + { + m_topLeftTileIdx.resize(numTileGroupsInPic); + m_bottomRightTileIdx.resize(numTileGroupsInPic); + for (uint32_t i = 0; i < numTileGroupsInPic; ++i) + { + m_topLeftTileIdx[i] = cfg_TileGroupIdx.values[i * 2]; + m_bottomRightTileIdx[i] = cfg_TileGroupIdx.values[i * 2 + 1]; + } + } + } // (!m_singleBrickPerSliceFlag && m_rectSliceFlag) + } // !singleTileInPicFlag + + if (m_rectSliceFlag && m_signalledSliceIdFlag) + { + int numTileGroupsInPic = m_numSlicesInPicMinus1 + 1; + + if (cfg_SignalledTileGroupId.values.size() > numTileGroupsInPic) + { + EXIT("Error: The number of Tile group Ids are greater than the m_signalledTileGroupIdLengthMinus1."); + } + else if (cfg_SignalledTileGroupId.values.size() < numTileGroupsInPic) + { + EXIT("Error: The number of Tile group Ids are less than the m_signalledTileGroupIdLengthMinus1."); + } + else + { + m_sliceId.resize(numTileGroupsInPic); + for (uint32_t i = 0; i < cfg_SignalledTileGroupId.values.size(); ++i) + { + m_sliceId[i] = cfg_SignalledTileGroupId.values[i]; + } + } + } +#endif + if (tmpDecodedPictureHashSEIMappedType<0 || tmpDecodedPictureHashSEIMappedType>=int(NUMBER_OF_HASHTYPES)) { EXIT( "Error: bad checksum mode"); @@ -2858,6 +2977,17 @@ bool EncAppCfg::xCheckParameter() } } +#if JVET_N0857_TILES_BRICKS + for (int i=0; i<MAX_TILES; i++) + { + if (m_brickSplits[i].m_tileIdx>=0) + { + m_brickSplitMap[m_brickSplits[i].m_tileIdx] = m_brickSplits[i]; + // ToDo: check that brick dimensions don't exceed tile dimensions + } + } +#endif + if ((m_MCTSEncConstraint) && (m_bLFCrossTileBoundaryFlag)) { printf("Warning: Constrained Encoding for Motion Constrained Tile Sets (MCTS) is enabled. Disabling filtering across tile boundaries!\n"); diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index e4afab344507ffc206564a877e9cbdcd2e7444ba..bc8d97e2e002fded998b397cdf8db98d4fcaa274 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -165,6 +165,10 @@ protected: #endif int m_extraRPSs; ///< extra RPSs added to handle CRA GOPEntry m_GOPList[MAX_GOP]; ///< the coding structure entries from the config file +#if JVET_N0857_TILES_BRICKS + BrickSplit m_brickSplits[MAX_TILES]; + BrickSplitMap m_brickSplitMap; +#endif int m_numReorderPics[MAX_TLAYER]; ///< total number of reorder pictures int m_maxDecPicBuffering[MAX_TLAYER]; ///< total number of pictures in the decoded picture buffer bool m_crossComponentPredictionEnabledFlag; ///< flag enabling the use of cross-component prediction @@ -409,6 +413,7 @@ protected: #endif bool m_bLFCrossSliceBoundaryFlag; ///< 1: filter across slice boundaries 0: do not filter across slice boundaries + bool m_bLFCrossTileBoundaryFlag; ///< 1: filter across tile boundaries 0: do not filter across tile boundaries bool m_tileUniformSpacingFlag; int m_numTileColumnsMinus1; @@ -417,6 +422,17 @@ protected: std::vector<int> m_tileRowHeight; bool m_entropyCodingSyncEnabledFlag; +#if JVET_N0857_TILES_BRICKS + bool m_rectSliceFlag; + int m_numSlicesInPicMinus1; + std::vector<int> m_topLeftTileIdx; + std::vector<int> m_bottomRightTileIdx; + bool m_loopFilterAcrossSlicesEnabledFlag; + bool m_signalledSliceIdFlag; + int m_signalledSliceIdLengthMinus1; + std::vector<int> m_sliceId; +#endif + bool m_bUseConstrainedIntraPred; ///< flag for using constrained intra prediction bool m_bFastUDIUseMPMEnabled; bool m_bFastMEForGenBLowDelayEnabled; diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index 801b34d52949d330580552cf132456edf018bde2..ab8ec6554b21ba644256d0a40ea3df75b245f37b 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -143,6 +143,11 @@ static const int MAX_NUM_REF = 16; ///< max. static const int MAX_QP = 63; static const int NOT_VALID = -1; +#if JVET_N0857_TILES_BRICKS +static const int MAX_TILES = 128; ///< max. number of tiles for which a brick configuration can be read +static const int MAX_NUM_BRICKS_PER_TILE = 8; ///< max. number brick per tile, for which a configuration can be read +#endif + static const int AMVP_MAX_NUM_CANDS = 2; ///< AMVP: advanced motion vector prediction - max number of final candidates static const int AMVP_MAX_NUM_CANDS_MEM = 3; ///< AMVP: advanced motion vector prediction - max number of candidates static const int AMVP_DECIMATION_FACTOR = 2; diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp index b2685cac426e6f54f1d1d4276e209d9e8c198f61..4f1b8e2959083ff2508a577c959679117798767f 100644 --- a/source/Lib/CommonLib/ContextModelling.cpp +++ b/source/Lib/CommonLib/ContextModelling.cpp @@ -179,7 +179,11 @@ void DeriveCtx::CtxSplit( const CodingStructure& cs, Partitioner& partitioner, u { const Position pos = partitioner.currArea().blocks[partitioner.chType]; const unsigned curSliceIdx = cs.slice->getIndependentSliceIdx(); +#if JVET_N0857_TILES_BRICKS + const unsigned curTileIdx = cs.picture->brickMap->getBrickIdxRsMap( partitioner.currArea().lumaPos() ); +#else const unsigned curTileIdx = cs.picture->tileMap->getTileIdxMap( partitioner.currArea().lumaPos() ); +#endif // get left depth const CodingUnit* cuLeft = cs.getCURestricted( pos.offset( -1, 0 ), curSliceIdx, curTileIdx, partitioner.chType ); diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp index 76947802a2d8033dab41d012e60178dc23caf65e..2e3ed1c99bbe9dda9c8b5de7e3f207d5f0c56443 100644 --- a/source/Lib/CommonLib/LoopFilter.cpp +++ b/source/Lib/CommonLib/LoopFilter.cpp @@ -848,8 +848,8 @@ void LoopFilter::xSetLoopfilterParam( const CodingUnit& cu ) const Position& pos = cu.blocks[cu.chType].pos(); m_stLFCUParam.internalEdge = true; - m_stLFCUParam.leftEdge = ( 0 < pos.x ) && isAvailableLeft ( cu, *cu.cs->getCU( pos.offset( -1, 0 ), cu.chType ), !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag() ); - m_stLFCUParam.topEdge = ( 0 < pos.y ) && isAvailableAbove( cu, *cu.cs->getCU( pos.offset( 0, -1 ), cu.chType ), !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag() ); + m_stLFCUParam.leftEdge = ( 0 < pos.x ) && isAvailableLeft ( cu, *cu.cs->getCU( pos.offset( -1, 0 ), cu.chType ), !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag() ); + m_stLFCUParam.topEdge = ( 0 < pos.y ) && isAvailableAbove( cu, *cu.cs->getCU( pos.offset( 0, -1 ), cu.chType ), !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag() ); #if !JVET_N0473_DEBLOCK_INTERNAL_TRANSFORM_BOUNDARIES m_stLFCUParam.internalEdge &= !cu.ispMode; #endif @@ -1112,11 +1112,11 @@ void LoopFilter::xEdgeFilterLuma(const CodingUnit& cu, const DeblockEdgeDir edge // Derive neighboring PU index if (edgeDir == EDGE_VER) { - CHECK( !isAvailableLeft( cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag() ), "Neighbour not available" ); + CHECK( !isAvailableLeft( cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag() ), "Neighbour not available" ); } else // (iDir == EDGE_HOR) { - CHECK( !isAvailableAbove( cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag() ), "Neighbour not available" ); + CHECK( !isAvailableAbove( cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag() ), "Neighbour not available" ); } iQP = (cuP.qp + cuQ.qp + 1) >> 1; @@ -1401,11 +1401,11 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed if (edgeDir == EDGE_VER) { - CHECK(!isAvailableLeft(cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag()), "Neighbour not available"); + CHECK(!isAvailableLeft(cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag()), "Neighbour not available"); } else // (iDir == EDGE_HOR) { - CHECK(!isAvailableAbove(cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag()), "Neighbour not available"); + CHECK(!isAvailableAbove(cu, cuP, !slice.getLFCrossSliceBoundaryFlag(), !pps.getLoopFilterAcrossBricksEnabledFlag()), "Neighbour not available"); } bPartPNoFilter = bPartQNoFilter = false; diff --git a/source/Lib/CommonLib/MCTS.cpp b/source/Lib/CommonLib/MCTS.cpp index dd87fb11bdc1c50df48be97763be4e8ba6522ebb..1c8aaca6627dac80b07a4cc074e7819c67608d12 100644 --- a/source/Lib/CommonLib/MCTS.cpp +++ b/source/Lib/CommonLib/MCTS.cpp @@ -90,17 +90,31 @@ void MCTSHelper::clipMvToArea( Mv& rcMv, const Area& block, const Area& clipArea Area MCTSHelper::getTileArea( const CodingStructure* cs, const int ctuAddr ) { +#if JVET_N0857_TILES_BRICKS + const BrickMap* tileMap = cs->picture->brickMap; + const int tileIdx = tileMap->getBrickIdxRsMap( ctuAddr ); +#else const TileMap* tileMap = cs->picture->tileMap; const int tileIdx = tileMap->getTileIdxMap( ctuAddr ); +#endif +#if JVET_N0857_TILES_BRICKS + const Brick& currentTile = tileMap->bricks[tileIdx]; +#else const Tile& currentTile = tileMap->tiles[tileIdx]; +#endif const int frameWidthInCtus = cs->pcv->widthInCtus; const int firstCtuRsAddrOfTile = currentTile.getFirstCtuRsAddr(); const int tileXPosInCtus = firstCtuRsAddrOfTile % frameWidthInCtus; const int tileYPosInCtus = firstCtuRsAddrOfTile / frameWidthInCtus; +#if JVET_N0857_TILES_BRICKS + const int tileWidthtInCtus = currentTile.getWidthInCtus(); + const int tileHeightInCtus = currentTile.getHeightInCtus(); +#else const int tileWidthtInCtus = currentTile.getTileWidthInCtus(); const int tileHeightInCtus = currentTile.getTileHeightInCtus(); +#endif const int maxCUWidth = cs->pcv->maxCUWidth; const int maxCUHeight = cs->pcv->maxCUHeight; diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp index 9accbe45c18cab4c8e3c0874c2c8d4aa0780201c..786e2c58c6f6412706e0d5edf01a05d218877e15 100644 --- a/source/Lib/CommonLib/Picture.cpp +++ b/source/Lib/CommonLib/Picture.cpp @@ -436,7 +436,22 @@ bool Scheduler::getNextCtu( Position& pos, int ctuLine, int offset) // picture methods // --------------------------------------------------------------------------- +#if JVET_N0857_TILES_BRICKS + +Brick::Brick() +: m_widthInCtus (0) +, m_heightInCtus (0) +, m_colBd (0) +, m_rowBd (0) +, m_firstCtuRsAddr (0) +{ +} + +Brick::~Brick() +{ +} +#else Tile::Tile() : m_tileWidthInCtus (0) , m_tileHeightInCtus (0) @@ -449,7 +464,9 @@ Tile::Tile() Tile::~Tile() { } +#endif +#if !JVET_N0857_TILES_BRICKS TileMap::TileMap() : pcv(nullptr) @@ -509,7 +526,7 @@ void TileMap::initTileMap( const SPS& sps, const PPS& pps ) const uint32_t frameWidthInCtus = pcv->widthInCtus; const uint32_t frameHeightInCtus = pcv->heightInCtus; - if( pps.getTileUniformSpacingFlag() ) + if( pps.getUniformTileSpacingFlag() ) { //set width and height for each (uniform) tile for(int row=0; row < numTileRows; row++) @@ -711,9 +728,286 @@ uint32_t TileMap::getSubstreamForCtuAddr(const uint32_t ctuAddr, const bool bAdd return subStrm; } +#else +BrickMap::BrickMap() + : pcv(nullptr) + , numTiles(0) + , numTileColumns(0) + , numTileRows(0) + , brickIdxRsMap(nullptr) + , brickIdxBsMap(nullptr) + , ctuBsToRsAddrMap(nullptr) + , ctuRsToBsAddrMap(nullptr) +{ +} + +void BrickMap::create( const SPS& sps, const PPS& pps ) +{ + pcv = pps.pcv; + + numTileColumns = pps.getNumTileColumnsMinus1() + 1; + numTileRows = pps.getNumTileRowsMinus1() + 1; + numTiles = numTileColumns * numTileRows; + + const uint32_t numCtusInFrame = pcv->sizeInCtus; + brickIdxRsMap = new uint32_t[numCtusInFrame]; + brickIdxBsMap = new uint32_t[numCtusInFrame]; + ctuBsToRsAddrMap = new uint32_t[numCtusInFrame+1]; + ctuRsToBsAddrMap = new uint32_t[numCtusInFrame+1]; + + initBrickMap( sps, pps ); + + numTiles = (uint32_t) bricks.size(); +} + +void BrickMap::destroy() +{ + bricks.clear(); + + if ( brickIdxRsMap ) + { + delete[] brickIdxRsMap; + brickIdxRsMap = nullptr; + } + + if ( brickIdxBsMap ) + { + delete[] brickIdxBsMap; + brickIdxBsMap = nullptr; + } + + if ( ctuBsToRsAddrMap ) + { + delete[] ctuBsToRsAddrMap; + ctuBsToRsAddrMap = nullptr; + } + + if ( ctuRsToBsAddrMap ) + { + delete[] ctuRsToBsAddrMap; + ctuRsToBsAddrMap = nullptr; + } +} + +void BrickMap::initBrickMap( const SPS& sps, const PPS& pps ) +{ + const uint32_t frameWidthInCtus = pcv->widthInCtus; + const uint32_t frameHeightInCtus = pcv->heightInCtus; + + std::vector<uint32_t> tileRowHeight (numTileRows); + std::vector<uint32_t> tileColWidth (numTileColumns); + + if( pps.getUniformTileSpacingFlag() ) + { + //set width and height for each (uniform) tile + for(int row=0; row < numTileRows; row++) + { + tileRowHeight[row] = (row+1)*frameHeightInCtus/numTileRows - (row*frameHeightInCtus)/numTileRows; + } + for(int col=0; col < numTileColumns; col++) + { + tileColWidth[col] = (col+1)*frameWidthInCtus/numTileColumns - (col*frameWidthInCtus)/numTileColumns; + } + } + else + { + tileColWidth[ numTileColumns - 1 ] = frameWidthInCtus; + for( int i = 0; i < numTileColumns - 1; i++ ) + { + tileColWidth[ i ] = pps.getTileColumnWidth(i); + tileColWidth[ numTileColumns - 1 ] = tileColWidth[ numTileColumns - 1 ] - pps.getTileColumnWidth(i); + } + + + tileRowHeight[ numTileRows-1 ] = frameHeightInCtus; + for( int j = 0; j < numTileRows-1; j++ ) + { + tileRowHeight[ j ] = pps.getTileRowHeight( j ); + tileRowHeight[ numTileRows-1 ] = tileRowHeight[ numTileRows-1 ] - pps.getTileRowHeight( j ); + } + } + + + //initialize each tile of the current picture + std::vector<uint32_t> tileRowBd (numTileRows); + std::vector<uint32_t> tileColBd (numTileColumns); + + tileColBd[ 0 ] = 0; + for( int i = 0; i < numTileColumns - 1; i++ ) + { + tileColBd[ i + 1 ] = tileColBd[ i ] + tileColWidth[ i ]; + } + + tileRowBd[ 0 ] = 0; + for( int j = 0; j < numTileRows - 1; j++ ) + { + tileRowBd[ j + 1 ] = tileRowBd[ j ] + tileRowHeight[ j ]; + } + + int brickIdx = 0; + for(int tileIdx=0; tileIdx< numTiles; tileIdx++) + { + int tileX = tileIdx % ( pps.getNumTileColumnsMinus1() + 1 ); + int tileY = tileIdx / ( pps.getNumTileColumnsMinus1() + 1 ); + + if ( !pps.getBrickSplittingPresentFlag() || !pps.getBrickSplitFlag(tileIdx)) + { + bricks.resize(bricks.size()+1); + bricks[ brickIdx ].setColBd (tileColBd[ tileX ]); + bricks[ brickIdx ].setRowBd (tileRowBd[ tileY ]); + bricks[ brickIdx ].setWidthInCtus (tileColWidth[ tileX ]); + bricks[ brickIdx ].setHeightInCtus(tileRowHeight[ tileY ]); + bricks[ brickIdx ].setFirstCtuRsAddr(bricks[ brickIdx ].getColBd() + bricks[ brickIdx ].getRowBd() * frameWidthInCtus); + brickIdx++; + } + else + { + std::vector<uint32_t> rowHeight2; + std::vector<uint32_t> rowBd2; + int numBrickRowsMinus1 = 0; + if (pps.getUniformBrickSpacingFlag(tileIdx)) + { + int brickHeight= pps.getBrickHeightMinus1(tileIdx) + 1; + int remainingHeightInCtbsY = tileRowHeight[ tileY ]; + int brickInTile = 0; + while( remainingHeightInCtbsY > brickHeight ) + { + rowHeight2.resize(brickInTile+1); + rowHeight2[ brickInTile++ ] = brickHeight; + remainingHeightInCtbsY -= brickHeight; + } + rowHeight2.resize(brickInTile+1); + rowHeight2[ brickInTile ] = remainingHeightInCtbsY; + numBrickRowsMinus1 = brickInTile; + } + else + { + numBrickRowsMinus1 = pps.getNumBrickRowsMinus1(tileIdx); + rowHeight2.resize(numBrickRowsMinus1 + 1); + rowHeight2[ numBrickRowsMinus1 ] = tileRowHeight[ tileY ]; + for(int j = 0; j < numBrickRowsMinus1; j++ ) + { + rowHeight2[ j ] = pps.getBrickRowHeightMinus1 ( tileIdx, j )+ 1; + rowHeight2[ numBrickRowsMinus1 ] -= rowHeight2[ j ]; + } + } + rowBd2.resize(numBrickRowsMinus1 + 1); + rowBd2[ 0 ] = 0; + for( int j = 0; j < numBrickRowsMinus1; j++ ) + { + rowBd2[ j + 1 ] = rowBd2[ j ] + rowHeight2[ j ]; + } + for( int j = 0; j < numBrickRowsMinus1 + 1; j++ ) + { + bricks.resize(bricks.size()+1); + bricks[ brickIdx ].setColBd (tileColBd[ tileX ]); + bricks[ brickIdx ].setRowBd (tileRowBd[ tileY ] + rowBd2[ j ]); + bricks[ brickIdx ].setWidthInCtus (tileColWidth[ tileX ]); + bricks[ brickIdx ].setHeightInCtus(rowHeight2[ j ]); + bricks[ brickIdx ].setFirstCtuRsAddr(bricks[ brickIdx ].getColBd() + bricks[ brickIdx ].getRowBd() * frameWidthInCtus); + brickIdx++; + } + } + } + + initCtuBsRsAddrMap(); + + for( int i = 0; i < (int)bricks.size(); i++ ) + { + for( int y = bricks[i].getRowBd(); y < bricks[i].getRowBd() + bricks[i].getHeightInCtus(); y++ ) + { + for( int x = bricks[i].getColBd(); x < bricks[i].getColBd() + bricks[i].getWidthInCtus(); x++ ) + { + // brickIdxBsMap in BS scan is brickIdxMap as defined in the draft text + brickIdxBsMap[ ctuRsToBsAddrMap[ y * frameWidthInCtus+ x ] ] = i; + // brickIdxRsMap in RS scan is usually required in the software + brickIdxRsMap[ y * frameWidthInCtus+ x ] = i; + } + } + } +} + + +void BrickMap::initCtuBsRsAddrMap() +{ + const uint32_t picWidthInCtbsY = pcv->widthInCtus; + const uint32_t picHeightInCtbsY = pcv->heightInCtus; + const uint32_t picSizeInCtbsY = picWidthInCtbsY * picHeightInCtbsY; + const int numBricksInPic = (int) bricks.size(); + + for( uint32_t ctbAddrRs = 0; ctbAddrRs < picSizeInCtbsY; ctbAddrRs++ ) + { + const uint32_t tbX = ctbAddrRs % picWidthInCtbsY; + const uint32_t tbY = ctbAddrRs / picWidthInCtbsY; + bool brickFound = false; + int bkIdx = (numBricksInPic - 1); + for( int i = 0; i < (numBricksInPic - 1) && !brickFound; i++ ) + { + brickFound = tbX < ( bricks[i].getColBd() + bricks[i].getWidthInCtus() ) && + tbY < ( bricks[i].getRowBd() + bricks[i].getHeightInCtus() ); + if( brickFound ) + { + bkIdx = i; + } + } + ctuRsToBsAddrMap[ ctbAddrRs ] = 0; + + for( uint32_t i = 0; i < bkIdx; i++ ) + { + ctuRsToBsAddrMap[ ctbAddrRs ] += bricks[i].getHeightInCtus() * bricks[i].getWidthInCtus(); + } + ctuRsToBsAddrMap[ ctbAddrRs ] += ( tbY - bricks[ bkIdx ].getRowBd() ) * bricks[ bkIdx ].getWidthInCtus() + tbX - bricks[ bkIdx ].getColBd(); + } + + + for( uint32_t ctbAddrRs = 0; ctbAddrRs < picSizeInCtbsY; ctbAddrRs++ ) + { + ctuBsToRsAddrMap[ ctuRsToBsAddrMap[ ctbAddrRs ] ] = ctbAddrRs; + } +} + +uint32_t BrickMap::getSubstreamForCtuAddr(const uint32_t ctuAddr, const bool addressInRaster, Slice *slice) const +{ + const bool wppEnabled = slice->getPPS()->getEntropyCodingSyncEnabledFlag(); + uint32_t subStrm; + + if( (wppEnabled && pcv->heightInCtus > 1) || (numTiles > 1) ) // wavefronts, and possibly tiles being used. + { + // needs to be checked + CHECK (false, "bricks and WPP needs to be checked"); + + const uint32_t ctuRsAddr = addressInRaster ? ctuAddr : getCtuBsToRsAddrMap(ctuAddr); + const uint32_t brickIndex = getBrickIdxRsMap(ctuRsAddr); + + if (wppEnabled) + { + const uint32_t firstCtuRsAddrOfTile = bricks[brickIndex].getFirstCtuRsAddr(); + const uint32_t tileYInCtus = firstCtuRsAddrOfTile / pcv->widthInCtus; + const uint32_t ctuLine = ctuRsAddr / pcv->widthInCtus; + const uint32_t startingSubstreamForTile = (tileYInCtus * numTileColumns) + (bricks[brickIndex].getHeightInCtus() * (brickIndex % numTileColumns)); + subStrm = startingSubstreamForTile + (ctuLine - tileYInCtus); + } + else + { + subStrm = brickIndex; + } + } + else + { + subStrm = 0; + } + return subStrm; +} + +#endif + Picture::Picture() { +#if JVET_N0857_TILES_BRICKS + brickMap = nullptr; +#else tileMap = nullptr; +#endif cs = nullptr; m_bIsBorderExtended = false; usedByCurr = false; @@ -784,12 +1078,21 @@ void Picture::destroy() } SEIs.clear(); +#if JVET_N0857_TILES_BRICKS + if ( brickMap ) + { + brickMap->destroy(); + delete brickMap; + brickMap = nullptr; + } +#else if ( tileMap ) { tileMap->destroy(); delete tileMap; tileMap = nullptr; } +#endif if (m_spliceIdx) { delete[] m_spliceIdx; @@ -884,12 +1187,21 @@ void Picture::finalInit(const SPS& sps, const PPS& pps, APS& aps) SEIs.clear(); clearSliceBuffer(); +#if JVET_N0857_TILES_BRICKS + if( brickMap ) + { + brickMap->destroy(); + delete brickMap; + brickMap = nullptr; + } +#else if( tileMap ) { tileMap->destroy(); delete tileMap; tileMap = nullptr; } +#endif const ChromaFormat chromaFormatIDC = sps.getChromaFormatIdc(); const int iWidth = sps.getPicWidthInLumaSamples(); @@ -919,8 +1231,13 @@ void Picture::finalInit(const SPS& sps, const PPS& pps, APS& aps) #endif cs->pcv = pps.pcv; +#if JVET_N0857_TILES_BRICKS + brickMap = new BrickMap; + brickMap->create( sps, pps ); +#else tileMap = new TileMap; tileMap->create( sps, pps ); +#endif if (m_spliceIdx == NULL) { m_ctuNums = cs->pcv->sizeInCtus; diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h index 931e72868db1aedec902563fd7641961ca2c4847..c48eee6054c2499dad1bc552bb120cfdb85af07b 100644 --- a/source/Lib/CommonLib/Picture.h +++ b/source/Lib/CommonLib/Picture.h @@ -115,6 +115,35 @@ class AQpLayer; typedef std::list<SEI*> SEIMessages; +#if JVET_N0857_TILES_BRICKS + +class Brick +{ +private: + uint32_t m_widthInCtus; + uint32_t m_heightInCtus; + uint32_t m_colBd; + uint32_t m_rowBd; + uint32_t m_firstCtuRsAddr; + +public: + Brick(); + virtual ~Brick(); + + void setWidthInCtus ( uint32_t i ) { m_widthInCtus = i; } + uint32_t getWidthInCtus () const { return m_widthInCtus; } + void setHeightInCtus ( uint32_t i ) { m_heightInCtus = i; } + uint32_t getHeightInCtus () const { return m_heightInCtus; } + void setColBd ( uint32_t i ) { m_colBd = i; } + uint32_t getColBd () const { return m_colBd; } + void setRowBd ( uint32_t i ) { m_rowBd = i; } + uint32_t getRowBd () const { return m_rowBd; } + + void setFirstCtuRsAddr ( uint32_t i ) { m_firstCtuRsAddr = i; } + uint32_t getFirstCtuRsAddr () const { return m_firstCtuRsAddr; } +}; + +#else class Tile { private: @@ -139,8 +168,9 @@ public: void setFirstCtuRsAddr ( uint32_t i ) { m_firstCtuRsAddr = i; } uint32_t getFirstCtuRsAddr () const { return m_firstCtuRsAddr; } }; +#endif - +#if !JVET_N0857_TILES_BRICKS struct TileMap { TileMap(); @@ -168,6 +198,41 @@ struct TileMap uint32_t calculateNextCtuRSAddr( const uint32_t currCtuRsAddr ) const; }; +#else +struct BrickMap +{ + BrickMap(); + + void create( const SPS& sps, const PPS& pps ); + void destroy(); + + uint32_t getBrickIdxRsMap( uint32_t ctuRsAddr ) const { return *(brickIdxRsMap + ctuRsAddr); } + uint32_t getBrickIdxRsMap( const Position& pos ) const { return getBrickIdxRsMap( ( pos.x / pcv->maxCUWidth ) + ( pos.y / pcv->maxCUHeight ) * pcv->widthInCtus ); }; + + uint32_t getBrickIdxBsMap( uint32_t ctuRsAddr ) const { return *(brickIdxBsMap + ctuRsAddr); } + uint32_t getBrickIdxBsMap( const Position& pos ) const { return getBrickIdxBsMap( ( pos.x / pcv->maxCUWidth ) + ( pos.y / pcv->maxCUHeight ) * pcv->widthInCtus ); }; + + uint32_t getCtuBsToRsAddrMap( uint32_t ctuTsAddr ) const { return *(ctuBsToRsAddrMap + (ctuTsAddr>=pcv->sizeInCtus ? pcv->sizeInCtus : ctuTsAddr)); } + uint32_t getCtuRsToBsAddrMap( uint32_t ctuRsAddr ) const { return *(ctuRsToBsAddrMap + (ctuRsAddr>=pcv->sizeInCtus ? pcv->sizeInCtus : ctuRsAddr)); } + + uint32_t getSubstreamForCtuAddr(const uint32_t ctuAddr, const bool addressInRaster, Slice *slice) const; + + const PreCalcValues* pcv; + std::vector<Brick> bricks; + + uint32_t numTiles; + uint32_t numTileColumns; + uint32_t numTileRows; + uint32_t* brickIdxRsMap; + uint32_t* brickIdxBsMap; + uint32_t* ctuBsToRsAddrMap; + uint32_t* ctuRsToBsAddrMap; + + void initBrickMap( const SPS& sps, const PPS& pps ); + void initCtuBsRsAddrMap(); +}; +#endif + #if ENABLE_SPLIT_PARALLELISM #define M_BUFS(JID,PID) m_bufs[JID][PID] #else @@ -281,7 +346,11 @@ public: Slice *swapSliceObject(Slice * p, uint32_t i); void clearSliceBuffer(); +#if !JVET_N0857_TILES_BRICKS TileMap* tileMap; +#else + BrickMap* brickMap; +#endif MCTSInfo mctsInfo; std::vector<AQpLayer*> aqlayer; diff --git a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp index ad8acae438cff63616060d6b871bdeb2187e465b..f699c3e8f55f95cb463909d4c162c07e91848ed0 100644 --- a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp +++ b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp @@ -840,7 +840,7 @@ void SampleAdaptiveOffset::deriveLoopFilterBoundaryAvailibility(CodingStructure& } // check cross tile flags - const bool isLoopFilterAcrossTilePPS = cs.pps->getLoopFilterAcrossTilesEnabledFlag(); + const bool isLoopFilterAcrossTilePPS = cs.pps->getLoopFilterAcrossBricksEnabledFlag(); if (!isLoopFilterAcrossTilePPS) { isLeftAvail = (!isLeftAvail) ? false : CU::isSameTile(*cuCurr, *cuLeft); diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index ebaf0b9d0c3f61ab38b38a03506e03f7b9961171..bc7d7f55f91969ace13039726efc78daafd8992a 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -1971,12 +1971,25 @@ PPS::PPS() #if HEVC_DEPENDENT_SLICES , m_dependentSliceSegmentsEnabledFlag(false) #endif +#if !JVET_N0857_TILES_BRICKS , m_tilesEnabledFlag (false) +#endif , m_entropyCodingSyncEnabledFlag (false) -, m_loopFilterAcrossTilesEnabledFlag (true) -, m_uniformSpacingFlag (false) +, m_loopFilterAcrossBricksEnabledFlag (true) +, m_uniformTileSpacingFlag (false) , m_numTileColumnsMinus1 (0) , m_numTileRowsMinus1 (0) +#if JVET_N0857_TILES_BRICKS +, m_singleTileInPicFlag (true) +, m_tileColsWidthMinus1 (0) +, m_tileRowsHeightMinus1 (0) +, m_brickSplittingPresentFlag (false) +, m_singleBrickPerSliceFlag (true) +, m_rectSliceFlag (true) +, m_numSlicesInPicMinus1 (0) +, m_signalledSliceIdFlag (false) +,m_signalledSliceIdLengthMinus1 (0) +#endif , m_cabacInitPresentFlag (false) , m_sliceHeaderExtensionPresentFlag (false) , m_loopFilterAcrossSlicesEnabledFlag(false) diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index b7d5a2a788281d7aa47aced6a0885c4d2da44487..6f8cc6f40c3481a80ff4047c26ea90aa5350116b 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -1582,16 +1582,38 @@ private: #if HEVC_DEPENDENT_SLICES bool m_dependentSliceSegmentsEnabledFlag; //!< Indicates the presence of dependent slices #endif +#if !JVET_N0857_TILES_BRICKS bool m_tilesEnabledFlag; //!< Indicates the presence of tiles +#endif bool m_entropyCodingSyncEnabledFlag; //!< Indicates the presence of wavefronts - bool m_loopFilterAcrossTilesEnabledFlag; - bool m_uniformSpacingFlag; + bool m_loopFilterAcrossBricksEnabledFlag; + bool m_uniformTileSpacingFlag; int m_numTileColumnsMinus1; int m_numTileRowsMinus1; std::vector<int> m_tileColumnWidth; std::vector<int> m_tileRowHeight; +#if JVET_N0857_TILES_BRICKS + bool m_singleTileInPicFlag; + int m_tileColsWidthMinus1; + int m_tileRowsHeightMinus1; + bool m_brickSplittingPresentFlag; + std::vector<bool> m_brickSplitFlag; + std::vector<bool> m_uniformBrickSpacingFlag; + std::vector<int> m_brickHeightMinus1; + std::vector<int> m_numBrickRowsMinus1; + std::vector<std::vector<int>> m_brickRowHeightMinus1; + bool m_singleBrickPerSliceFlag; + bool m_rectSliceFlag; + int m_numSlicesInPicMinus1; + std::vector<int> m_topLeftTileIdx; + std::vector<int> m_bottomRightTileIdx; + bool m_signalledSliceIdFlag; + int m_signalledSliceIdLengthMinus1; + std::vector<int> m_sliceId; +#endif + bool m_cabacInitPresentFlag; bool m_sliceHeaderExtensionPresentFlag; @@ -1691,27 +1713,66 @@ public: bool getUseTransformSkip() const { return m_useTransformSkip; } void setUseTransformSkip( bool b ) { m_useTransformSkip = b; } - void setLoopFilterAcrossTilesEnabledFlag(bool b) { m_loopFilterAcrossTilesEnabledFlag = b; } - bool getLoopFilterAcrossTilesEnabledFlag() const { return m_loopFilterAcrossTilesEnabledFlag; } + void setLoopFilterAcrossBricksEnabledFlag(bool b) { m_loopFilterAcrossBricksEnabledFlag = b; } + bool getLoopFilterAcrossBricksEnabledFlag() const { return m_loopFilterAcrossBricksEnabledFlag; } #if HEVC_DEPENDENT_SLICES bool getDependentSliceSegmentsEnabledFlag() const { return m_dependentSliceSegmentsEnabledFlag; } void setDependentSliceSegmentsEnabledFlag(bool val) { m_dependentSliceSegmentsEnabledFlag = val; } +#endif +#if !JVET_N0857_TILES_BRICKS + void setTilesEnabledFlag(bool val) { m_tilesEnabledFlag = val; } + bool getTilesEnabledFlag() const { return m_tilesEnabledFlag; } #endif bool getEntropyCodingSyncEnabledFlag() const { return m_entropyCodingSyncEnabledFlag; } void setEntropyCodingSyncEnabledFlag(bool val) { m_entropyCodingSyncEnabledFlag = val; } - void setTilesEnabledFlag(bool val) { m_tilesEnabledFlag = val; } - bool getTilesEnabledFlag() const { return m_tilesEnabledFlag; } - void setTileUniformSpacingFlag(bool b) { m_uniformSpacingFlag = b; } - bool getTileUniformSpacingFlag() const { return m_uniformSpacingFlag; } + void setUniformTileSpacingFlag(bool b) { m_uniformTileSpacingFlag = b; } + bool getUniformTileSpacingFlag() const { return m_uniformTileSpacingFlag; } void setNumTileColumnsMinus1(int i) { m_numTileColumnsMinus1 = i; } int getNumTileColumnsMinus1() const { return m_numTileColumnsMinus1; } void setTileColumnWidth(const std::vector<int>& columnWidth ) { m_tileColumnWidth = columnWidth; } - uint32_t getTileColumnWidth(uint32_t columnIdx) const { return m_tileColumnWidth[columnIdx]; } + uint32_t getTileColumnWidth(uint32_t columnIdx) const { return m_tileColumnWidth[columnIdx]; } void setNumTileRowsMinus1(int i) { m_numTileRowsMinus1 = i; } int getNumTileRowsMinus1() const { return m_numTileRowsMinus1; } void setTileRowHeight(const std::vector<int>& rowHeight) { m_tileRowHeight = rowHeight; } - uint32_t getTileRowHeight(uint32_t rowIdx) const { return m_tileRowHeight[rowIdx]; } + uint32_t getTileRowHeight(uint32_t rowIdx) const { return m_tileRowHeight[rowIdx]; } + +#if JVET_N0857_TILES_BRICKS + bool getSingleTileInPicFlag() const { return m_singleTileInPicFlag; } + void setSingleTileInPicFlag(bool val) { m_singleTileInPicFlag = val; } + int getTileColsWidthMinus1() const { return m_tileColsWidthMinus1; } + void setTileColsWidthMinus1(int w) { m_tileColsWidthMinus1 = w; } + int getTileRowsHeightMinus1() const { return m_tileRowsHeightMinus1; } + void setTileRowsHeightMinus1(int h) { m_tileRowsHeightMinus1 = h; } + bool getBrickSplittingPresentFlag() const { return m_brickSplittingPresentFlag; } + void setBrickSplittingPresentFlag(bool b) { m_brickSplittingPresentFlag = b; } + bool getBrickSplitFlag(int i) const { return m_brickSplitFlag[i]; } + void setBrickSplitFlag(std::vector<bool>& val) { m_brickSplitFlag = val; } + bool getUniformBrickSpacingFlag(int i) const { return m_uniformBrickSpacingFlag[i]; } + void setUniformBrickSpacingFlag(std::vector<bool>& val) { m_uniformBrickSpacingFlag = val; } + int getBrickHeightMinus1(int i) const { return m_brickHeightMinus1[i]; } + void setBrickHeightMinus1(std::vector<int>& val) { m_brickHeightMinus1 = val; } + int getNumBrickRowsMinus1(int i) const { return m_numBrickRowsMinus1[i]; } + void setNumBrickRowsMinus1(std::vector<int>& val) { m_numBrickRowsMinus1 = val; } + int getBrickRowHeightMinus1(int i, int j) const { return m_brickRowHeightMinus1[i][j]; } + void setBrickRowHeightMinus1(std::vector<std::vector<int>>& val) { m_brickRowHeightMinus1 = val; } + bool getSingleBrickPerSliceFlag() const { return m_singleBrickPerSliceFlag; } + void setSingleBrickPerSliceFlag(bool val) { m_singleBrickPerSliceFlag = val; } + bool getRectSliceFlag() const { return m_rectSliceFlag; } + void setRectSliceFlag(bool val) { m_rectSliceFlag = val; } + int getNumSlicesInPicMinus1() const { return m_numSlicesInPicMinus1; } + void setNumSlicesInPicMinus1(int val) { m_numSlicesInPicMinus1 = val; } + int getTopLeftTileIdx(uint32_t columnIdx) const { return m_topLeftTileIdx[columnIdx]; } + void setTopLeftTileIdx(const std::vector<int>& val) { m_topLeftTileIdx = val; } + int getBottomeRightTileIdx(uint32_t columnIdx) const { return m_bottomRightTileIdx[columnIdx]; } + void setBottomRightTileIdx(const std::vector<int>& val) { m_bottomRightTileIdx = val; } + bool getSignalledSliceIdFlag() const { return m_signalledSliceIdFlag; } + void setSignalledSliceIdFlag(bool val) { m_signalledSliceIdFlag = val; } + int getSignalledSliceIdLengthMinus1() const { return m_signalledSliceIdLengthMinus1; } + void setSignalledSliceIdLengthMinus1(int val) { m_signalledSliceIdLengthMinus1 = val; } + int getSliceId(uint32_t columnIdx) const { return m_sliceId[columnIdx]; } + void setSliceId(const std::vector<int>& val) { m_sliceId = val; } +#endif void setCabacInitPresentFlag( bool flag ) { m_cabacInitPresentFlag = flag; } bool getCabacInitPresentFlag() const { return m_cabacInitPresentFlag; } diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 354d06143853bf46e55a0a2dc9e051eeece97648..a23b6af87d00953cfcfc77e2bf0b5c363daebc16 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -87,6 +87,8 @@ #define JVET_N0308_MAX_CU_SIZE_FOR_ISP 1 +#define JVET_N0857_TILES_BRICKS 1 // VTM-5 basic Slices/Tiles/Bricks design, rectangular slices not supported yet + #define JVET_N0280_RESIDUAL_CODING_TS 1 #define JVET_N0103_CGSIZE_HARMONIZATION 1 // Chroma CG sizes aligned to luma CG sizes @@ -793,7 +795,12 @@ enum SliceConstraint FIXED_NUMBER_OF_CTU = 1, ///< Limit maximum number of largest coding tree units in a slice / slice segments FIXED_NUMBER_OF_BYTES = 2, ///< Limit maximum number of bytes in a slice / slice segment FIXED_NUMBER_OF_TILES = 3, ///< slices / slice segments span an integer number of tiles +#if !JVET_N0857_TILES_BRICKS NUMBER_OF_SLICE_CONSTRAINT_MODES = 4 +#else + SINGLE_BRICK_PER_SLICE = 4, ///< each brick is coded as separate NAL unit (slice) + NUMBER_OF_SLICE_CONSTRAINT_MODES = 5 +#endif }; // For use with decoded picture hash SEI messages, generated by encoder. diff --git a/source/Lib/CommonLib/UnitPartitioner.cpp b/source/Lib/CommonLib/UnitPartitioner.cpp index c300bc224c680cd6ce717de729cdedeea096afdb..556d4c9282bde2a8f4a37eead6d60423c4d73bb2 100644 --- a/source/Lib/CommonLib/UnitPartitioner.cpp +++ b/source/Lib/CommonLib/UnitPartitioner.cpp @@ -144,7 +144,11 @@ void AdaptiveDepthPartitioner::setMaxMinDepth( unsigned& minDepth, unsigned& max unsigned stdMaxDepth = ( g_aucLog2[cs.sps->getCTUSize()] - g_aucLog2[cs.sps->getMinQTSize( cs.slice->getSliceType(), chType )]); const Position pos = currArea().blocks[chType].pos(); const unsigned curSliceIdx = cs.slice->getIndependentSliceIdx(); +#if JVET_N0857_TILES_BRICKS + const unsigned curTileIdx = cs.picture->brickMap->getBrickIdxRsMap( currArea().lumaPos() ); +#else const unsigned curTileIdx = cs.picture->tileMap->getTileIdxMap( currArea().lumaPos() ); +#endif const CodingUnit* cuLeft = cs.getCURestricted( pos.offset( -1, 0 ), curSliceIdx, curTileIdx, chType ); const CodingUnit* cuBelowLeft = cs.getCURestricted( pos.offset( -1, currArea().blocks[chType].height), curSliceIdx, curTileIdx, chType ); diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 9e43d182ffed6b1e8413de61e6d3c0b8ae6bc7e6..62915cedc6340a45ac111cbe83626b43ed1d610d 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -5430,11 +5430,19 @@ int CU::getMaxNeighboriMVCandNum( const CodingStructure& cs, const Position& pos int maxImvNumCand = 0; // Get BCBP of left PU +#if JVET_N0857_TILES_BRICKS + const CodingUnit *cuLeft = cs.getCURestricted( pos.offset( -1, 0 ), cs.slice->getIndependentSliceIdx(), cs.picture->brickMap->getBrickIdxRsMap( pos ), CH_L ); +#else const CodingUnit *cuLeft = cs.getCURestricted( pos.offset( -1, 0 ), cs.slice->getIndependentSliceIdx(), cs.picture->tileMap->getTileIdxMap( pos ), CH_L ); +#endif maxImvNumCand = ( cuLeft ) ? cuLeft->imvNumCand : numDefault; // Get BCBP of above PU +#if JVET_N0857_TILES_BRICKS + const CodingUnit *cuAbove = cs.getCURestricted( pos.offset( 0, -1 ), cs.slice->getIndependentSliceIdx(), cs.picture->brickMap->getBrickIdxRsMap( pos ), CH_L ); +#else const CodingUnit *cuAbove = cs.getCURestricted( pos.offset( 0, -1 ), cs.slice->getIndependentSliceIdx(), cs.picture->tileMap->getTileIdxMap( pos ), CH_L ); +#endif maxImvNumCand = std::max( maxImvNumCand, ( cuAbove ) ? cuAbove->imvNumCand : numDefault ); return maxImvNumCand; diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index f68fe091c75241d5cf2fcb07540ebae330fcbb09..f7adbf2627647854dfcc787ff5d72f8f1d99cf98 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -157,7 +157,11 @@ bool CABACReader::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i int rx = ctuRsAddr - ry * frame_width_in_ctus; const Position pos( rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight ); const uint32_t curSliceIdx = cs.slice->getIndependentSliceIdx(); +#if JVET_N0857_TILES_BRICKS + const uint32_t curTileIdx = cs.picture->brickMap->getBrickIdxRsMap( pos ); +#else const uint32_t curTileIdx = cs.picture->tileMap->getTileIdxMap( pos ); +#endif bool leftAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), curSliceIdx, curTileIdx, CH_L ) ? true : false; bool aboveAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), curSliceIdx, curTileIdx, CH_L ) ? true : false; @@ -301,7 +305,11 @@ void CABACReader::sao( CodingStructure& cs, unsigned ctuRsAddr ) RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__SAO ); +#if JVET_N0857_TILES_BRICKS + const unsigned curTileIdx = cs.picture->brickMap->getBrickIdxRsMap( pos ); +#else const unsigned curTileIdx = cs.picture->tileMap->getTileIdxMap( pos ); +#endif if( cs.getCURestricted( pos.offset(-(int)cs.pcv->maxCUWidth, 0), curSliceIdx, curTileIdx, CH_L ) ) { // sao_merge_left_flag @@ -583,7 +591,11 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU partitioner.setCUData( cu ); cu.slice = cs.slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = cs.picture->brickMap->getBrickIdxRsMap( currArea.lumaPos() ); +#else cu.tileIdx = cs.picture->tileMap->getTileIdxMap( currArea.lumaPos() ); +#endif // Predict QP on start of quantization group if( cuCtx.qgStart ) diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index 7c8a32853d7f64db9cde51d7efac749d7180ab51..8308a1fdbe4f9b691cd41f38ae7ee2de7bd43dd3 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -1247,15 +1247,24 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl // When decoding the slice header, the stored start and end addresses were actually RS addresses, not TS addresses. // Now, having set up the maps, convert them to the correct form. +#if JVET_N0857_TILES_BRICKS + const BrickMap& tileMap = *(m_pcPic->brickMap); +#else const TileMap& tileMap = *(m_pcPic->tileMap); +#endif #if HEVC_DEPENDENT_SLICES pcSlice->setSliceSegmentCurStartCtuTsAddr( tileMap.getCtuRsToTsAddrMap(pcSlice->getSliceSegmentCurStartCtuTsAddr()) ); pcSlice->setSliceSegmentCurEndCtuTsAddr( tileMap.getCtuRsToTsAddrMap(pcSlice->getSliceSegmentCurEndCtuTsAddr()) ); if(!pcSlice->getDependentSliceSegmentFlag()) { #endif +#if JVET_N0857_TILES_BRICKS + pcSlice->setSliceCurStartCtuTsAddr( tileMap.getCtuRsToBsAddrMap(pcSlice->getSliceCurStartCtuTsAddr()) ); + pcSlice->setSliceCurEndCtuTsAddr( tileMap.getCtuRsToBsAddrMap(pcSlice->getSliceCurEndCtuTsAddr()) ); +#else pcSlice->setSliceCurStartCtuTsAddr( tileMap.getCtuRsToTsAddrMap(pcSlice->getSliceCurStartCtuTsAddr()) ); pcSlice->setSliceCurEndCtuTsAddr( tileMap.getCtuRsToTsAddrMap(pcSlice->getSliceCurEndCtuTsAddr()) ); +#endif #if HEVC_DEPENDENT_SLICES } #endif diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp index f094bceb72c03b51736938605b64419cfce9a690..8c2e86b3c4a75da81dea64d773d1abab351ca50b 100644 --- a/source/Lib/DecoderLib/DecSlice.cpp +++ b/source/Lib/DecoderLib/DecSlice.cpp @@ -77,7 +77,11 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb const SPS* sps = slice->getSPS(); Picture* pic = slice->getPic(); +#if JVET_N0857_TILES_BRICKS + const BrickMap& tileMap = *pic->brickMap; +#else const TileMap& tileMap = *pic->tileMap; +#endif CABACReader& cabacReader = *m_CABACDecoder->getCABACReader( 0 ); // setup coding structure @@ -123,8 +127,13 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb #endif #if HEVC_DEPENDENT_SLICES const int startCtuRsAddr = startCtuTsAddr; +#else +#if JVET_N0857_TILES_BRICKS + const int startCtuRsAddr = tileMap.getCtuBsToRsAddrMap(startCtuTsAddr); #else const int startCtuRsAddr = tileMap.getCtuTsToRsAddrMap(startCtuTsAddr); +#endif + #endif const unsigned numCtusInFrame = cs.pcv->sizeInCtus; const unsigned widthInCtus = cs.pcv->widthInCtus; @@ -177,8 +186,13 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb bool isLastCtuOfSliceSegment = false; for( unsigned ctuTsAddr = startCtuTsAddr; !isLastCtuOfSliceSegment && ctuTsAddr < numCtusInFrame; ctuTsAddr++ ) { +#if JVET_N0857_TILES_BRICKS + const unsigned ctuRsAddr = tileMap.getCtuBsToRsAddrMap(ctuTsAddr); + const Brick& currentTile = tileMap.bricks[ tileMap.getBrickIdxRsMap(ctuRsAddr) ]; +#else const unsigned ctuRsAddr = tileMap.getCtuTsToRsAddrMap(ctuTsAddr); const Tile& currentTile = tileMap.tiles[ tileMap.getTileIdxMap(ctuRsAddr) ]; +#endif const unsigned firstCtuRsAddrOfTile = currentTile.getFirstCtuRsAddr(); const unsigned tileXPosInCtus = firstCtuRsAddrOfTile % widthInCtus; const unsigned tileYPosInCtus = firstCtuRsAddrOfTile / widthInCtus; @@ -209,7 +223,11 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb { cabacReader.initCtxModels( *slice ); } +#if JVET_N0857_TILES_BRICKS + if( cs.getCURestricted( pos.offset(maxCUSize, -1), slice->getIndependentSliceIdx(), tileMap.getBrickIdxRsMap( pos ), CH_L ) ) +#else if( cs.getCURestricted( pos.offset(maxCUSize, -1), slice->getIndependentSliceIdx(), tileMap.getTileIdxMap( pos ), CH_L ) ) +#endif { // Top-right is available, so use it. cabacReader.getCtx() = m_entropyCodingSyncContextState; @@ -268,8 +286,13 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb slice->setSliceSegmentCurEndCtuTsAddr( ctuTsAddr+1 ); #endif } +#if JVET_N0857_TILES_BRICKS + else if( ( ctuXPosInCtus + 1 == tileXPosInCtus + currentTile.getWidthInCtus () ) && + ( ctuYPosInCtus + 1 == tileYPosInCtus + currentTile.getHeightInCtus() || wavefrontsEnabled ) ) +#else else if( ( ctuXPosInCtus + 1 == tileXPosInCtus + currentTile.getTileWidthInCtus () ) && ( ctuYPosInCtus + 1 == tileYPosInCtus + currentTile.getTileHeightInCtus() || wavefrontsEnabled ) ) +#endif { // The sub-stream/stream should be terminated after this CTU. // (end of slice-segment, end of tile, end of wavefront-CTU-row) diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 6cff2f0ea5d4249c34ada2b0efb9f3ebf30936dd..9b9a57caf38ce533101b5d8ba8548a3fb6718c6b 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -452,26 +452,33 @@ void HLSyntaxReader::parsePPS( PPS* pcPPS ) READ_FLAG( uiCode, "transquant_bypass_enabled_flag"); pcPPS->setTransquantBypassEnabledFlag(uiCode ? true : false); - READ_FLAG( uiCode, "tiles_enabled_flag" ); pcPPS->setTilesEnabledFlag( uiCode == 1 ); - READ_FLAG( uiCode, "entropy_coding_sync_enabled_flag" ); pcPPS->setEntropyCodingSyncEnabledFlag( uiCode == 1 ); + +#if JVET_N0857_TILES_BRICKS + READ_FLAG( uiCode, "single_tile_in_pic_flag" ); pcPPS->setSingleTileInPicFlag(uiCode == 1); - if( pcPPS->getTilesEnabledFlag() ) + if(!pcPPS->getSingleTileInPicFlag()) { - READ_UVLC ( uiCode, "num_tile_columns_minus1" ); pcPPS->setNumTileColumnsMinus1( uiCode ); - READ_UVLC ( uiCode, "num_tile_rows_minus1" ); pcPPS->setNumTileRowsMinus1( uiCode ); - READ_FLAG ( uiCode, "uniform_spacing_flag" ); pcPPS->setTileUniformSpacingFlag( uiCode == 1 ); + READ_FLAG ( uiCode, "uniform_tile_spacing_flag" ); pcPPS->setUniformTileSpacingFlag( uiCode == 1 ); + if (pcPPS->getUniformTileSpacingFlag()) + { + READ_UVLC ( uiCode, "tile_cols_width_minus1" ); pcPPS->setTileColsWidthMinus1( uiCode ); + READ_UVLC ( uiCode, "tile_rows_height_minus1" ); pcPPS->setTileRowsHeightMinus1( uiCode ); + } + else + { + READ_UVLC ( uiCode, "num_tile_columns_minus1" ); pcPPS->setNumTileColumnsMinus1( uiCode ); + READ_UVLC ( uiCode, "num_tile_rows_minus1" ); pcPPS->setNumTileRowsMinus1( uiCode ); - const uint32_t tileColumnsMinus1 = pcPPS->getNumTileColumnsMinus1(); - const uint32_t tileRowsMinus1 = pcPPS->getNumTileRowsMinus1(); + const int tileColumnsMinus1 = pcPPS->getNumTileColumnsMinus1(); + const int tileRowsMinus1 = pcPPS->getNumTileRowsMinus1(); + CHECK( ((tileColumnsMinus1 + 1) * (tileColumnsMinus1 + 1)) < 2, "tile colums * rows must be > 1 when explicitly signalled."); - if ( !pcPPS->getTileUniformSpacingFlag()) - { if (tileColumnsMinus1 > 0) { std::vector<int> columnWidth(tileColumnsMinus1); - for(uint32_t i = 0; i < tileColumnsMinus1; i++) + for(int i = 0; i < tileColumnsMinus1; i++) { - READ_UVLC( uiCode, "column_width_minus1" ); + READ_UVLC( uiCode, "tile_column_width_minus1" ); columnWidth[i] = uiCode+1; } pcPPS->setTileColumnWidth(columnWidth); @@ -480,18 +487,175 @@ void HLSyntaxReader::parsePPS( PPS* pcPPS ) if (tileRowsMinus1 > 0) { std::vector<int> rowHeight (tileRowsMinus1); - for(uint32_t i = 0; i < tileRowsMinus1; i++) + for(int i = 0; i < tileRowsMinus1; i++) + { + READ_UVLC( uiCode, "tile_row_height_minus1" ); + rowHeight[i] = uiCode + 1; + } + pcPPS->setTileRowHeight(rowHeight); + } + CHECK( ( tileColumnsMinus1 + tileRowsMinus1 ) == 0, "Invalid tile configuration" ); + } + + READ_FLAG( uiCode, "brick_splitting_present_flag" ); pcPPS->setBrickSplittingPresentFlag(uiCode == 1); + + int numTilesInPic = pcPPS->getUniformTileSpacingFlag() ? 0 : (pcPPS->getNumTileColumnsMinus1() + 1) * (pcPPS->getNumTileRowsMinus1() + 1); + + if (pcPPS->getBrickSplittingPresentFlag()) + { + std::vector<bool> brickSplitFlag (numTilesInPic); + std::vector<bool> uniformBrickSpacingFlag (numTilesInPic); + std::vector<int> brickHeightMinus1 (numTilesInPic); + std::vector<int> numBrickRowsMinus1 (numTilesInPic); + std::vector<std::vector<int>> brickRowHeightMinus1 (numTilesInPic); + for( int i = 0; i < numTilesInPic; i++ ) + { + READ_FLAG( uiCode, "brick_split_flag [i]" ); + brickSplitFlag[i] = (uiCode == 1); + + if( brickSplitFlag[i] ) + { + READ_FLAG( uiCode, "uniform_brick_spacing_flag [i]" ); + uniformBrickSpacingFlag[i] = (uiCode == 1); + if( uniformBrickSpacingFlag[i] ) + { + READ_UVLC( uiCode, "brick_height_minus1" ); + brickHeightMinus1[i] = uiCode; + } + else + { + READ_UVLC( uiCode, "num_brick_rows_minus1 [i]" ); + numBrickRowsMinus1[i] = uiCode; + for(int j = 0; j < numBrickRowsMinus1[i]; j++ ) + { + brickRowHeightMinus1[i].resize(numBrickRowsMinus1[i]); + READ_UVLC( uiCode, "brick_row_height_minus1 [i][j]" ); + brickRowHeightMinus1[i][j]=uiCode; + } + } + } + } + pcPPS->setBrickSplitFlag(brickSplitFlag); + pcPPS->setUniformBrickSpacingFlag(uniformBrickSpacingFlag); + pcPPS->setBrickHeightMinus1(brickHeightMinus1); + pcPPS->setNumBrickRowsMinus1(numBrickRowsMinus1); + pcPPS->setBrickRowHeightMinus1(brickRowHeightMinus1); + } + READ_FLAG (uiCode, "single_brick_per_slice_flag" ); pcPPS->setSingleBrickPerSliceFlag(uiCode == 1); + if (!pcPPS->getSingleBrickPerSliceFlag()) + { + READ_FLAG( uiCode, "rect_slice_flag" ); pcPPS->setRectSliceFlag(uiCode == 1); + } + else + { + pcPPS->setRectSliceFlag(true); + } + + if(pcPPS->getRectSliceFlag() && !pcPPS->getSingleBrickPerSliceFlag()) + { + READ_UVLC (uiCode, "num_slices_in_pic_minus1" ); pcPPS->setNumSlicesInPicMinus1(uiCode); + const uint32_t tileColumnsMinus1 = pcPPS->getNumTileColumnsMinus1(); + const uint32_t tileRowsMinus1 = pcPPS->getNumTileRowsMinus1(); + const uint32_t numSlicesInPic = pcPPS->getNumSlicesInPicMinus1() + 1; + const uint32_t numTilesInPic = (tileColumnsMinus1 + 1) * (tileRowsMinus1 + 1); + int codeLength = (int)ceil(log2(numTilesInPic)); + if (numSlicesInPic > 0) + { + std::vector<int> topLeft(numSlicesInPic); + std::vector<int> bottomRight(numSlicesInPic); + topLeft[0] = 0; + for (uint32_t i = 0; i < numSlicesInPic; i++) + { + if (i > 0) + { + READ_CODE( codeLength, uiCode, "top_left_brick_idx" ); + topLeft[i] = uiCode; + } + READ_CODE( codeLength, uiCode, "bottom_right_brick_idx_delta" ); + bottomRight[i] = topLeft[i] + uiCode; + } + pcPPS->setTopLeftTileIdx(topLeft); + pcPPS->setBottomRightTileIdx(bottomRight); + } + } + + READ_FLAG( uiCode, "loop_filter_across_bricks_enabled_flag "); pcPPS->setLoopFilterAcrossBricksEnabledFlag(uiCode ? true : false); + if (pcPPS->getLoopFilterAcrossBricksEnabledFlag()) + { + READ_FLAG( uiCode, "loop_filter_across_slices_enabled_flag" ); pcPPS->setLoopFilterAcrossSlicesEnabledFlag(uiCode == 1); + } + } + else + { + pcPPS->setRectSliceFlag(true); + } + + if (pcPPS->getRectSliceFlag()) + { + READ_FLAG( uiCode, "signalled_slice_id_flag "); pcPPS->setSignalledSliceIdFlag(uiCode == 1); + if (pcPPS->getSignalledSliceIdFlag()) + { + READ_UVLC( uiCode, "signalled_slice_id_length_minus1" ); pcPPS->setSignalledSliceIdLengthMinus1(uiCode); + const uint32_t numTileGroups = pcPPS->getNumSlicesInPicMinus1() + 1; + int codeLength = pcPPS->getSignalledSliceIdLengthMinus1() + 1; + if (numTileGroups > 0) + { + std::vector<int> tileGroupID(numTileGroups); + for (uint32_t i = 0; i < numTileGroups; i++) + { + READ_CODE( codeLength, uiCode, "slice_id" ); + tileGroupID[i] = uiCode; + } + pcPPS->setSliceId(tileGroupID); + } + } + } +#endif + +#if !JVET_N0857_TILES_BRICKS + READ_FLAG(uiCode, "tiles_enabled_flag"); pcPPS->setTilesEnabledFlag(uiCode == 1); + + if (pcPPS->getTilesEnabledFlag()) + { + READ_UVLC(uiCode, "num_tile_columns_minus1"); pcPPS->setNumTileColumnsMinus1(uiCode); + READ_UVLC(uiCode, "num_tile_rows_minus1"); pcPPS->setNumTileRowsMinus1(uiCode); + READ_FLAG(uiCode, "uniform_spacing_flag"); pcPPS->setUniformTileSpacingFlag(uiCode == 1); + + const uint32_t tileColumnsMinus1 = pcPPS->getNumTileColumnsMinus1(); + const uint32_t tileRowsMinus1 = pcPPS->getNumTileRowsMinus1(); + + if (!pcPPS->getUniformTileSpacingFlag()) + { + if (tileColumnsMinus1 > 0) + { + std::vector<int> columnWidth(tileColumnsMinus1); + for (uint32_t i = 0; i < tileColumnsMinus1; i++) { - READ_UVLC( uiCode, "row_height_minus1" ); + READ_UVLC(uiCode, "column_width_minus1"); + columnWidth[i] = uiCode + 1; + } + pcPPS->setTileColumnWidth(columnWidth); + } + + if (tileRowsMinus1 > 0) + { + std::vector<int> rowHeight(tileRowsMinus1); + for (uint32_t i = 0; i < tileRowsMinus1; i++) + { + READ_UVLC(uiCode, "row_height_minus1"); rowHeight[i] = uiCode + 1; } pcPPS->setTileRowHeight(rowHeight); } } CHECK((tileColumnsMinus1 + tileRowsMinus1) == 0, "Invalid tile configuration"); - READ_FLAG ( uiCode, "loop_filter_across_tiles_enabled_flag" ); pcPPS->setLoopFilterAcrossTilesEnabledFlag( uiCode ? true : false ); + READ_FLAG ( uiCode, "loop_filter_across_tiles_enabled_flag" ); pcPPS->setLoopFilterAcrossBricksEnabledFlag( uiCode ? true : false ); } + READ_FLAG( uiCode, "pps_loop_filter_across_slices_enabled_flag" ); pcPPS->setLoopFilterAcrossSlicesEnabledFlag( uiCode ? true : false ); +#endif + READ_FLAG(uiCode, "entropy_coding_sync_enabled_flag"); pcPPS->setEntropyCodingSyncEnabledFlag(uiCode == 1); + READ_FLAG( uiCode, "deblocking_filter_control_present_flag" ); pcPPS->setDeblockingFilterControlPresentFlag( uiCode ? true : false ); if(pcPPS->getDeblockingFilterControlPresentFlag()) { @@ -2215,7 +2379,11 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para std::vector<uint32_t> entryPointOffset; +#if JVET_N0857_TILES_BRICKS + if( !pps->getSingleTileInPicFlag() || pps->getEntropyCodingSyncEnabledFlag() ) +#else if( pps->getTilesEnabledFlag() || pps->getEntropyCodingSyncEnabledFlag() ) +#endif { uint32_t numEntryPointOffsets; uint32_t offsetLenMinus1; @@ -2240,7 +2408,11 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para pcSlice->clearSubstreamSizes(); +#if !JVET_N0857_TILES_BRICKS if( pps->getTilesEnabledFlag() || pps->getEntropyCodingSyncEnabledFlag() ) +#else + if( !pps->getSingleTileInPicFlag() || pps->getEntropyCodingSyncEnabledFlag() ) +#endif { int endOfSliceHeaderLocation = m_pcBitstream->getByteLocation(); diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index e3878da068e8c27d3193d47ea2f40023d8804a0e..7bc3cfb5b1229d8a03d7d43d76084fe1a0ecbb6c 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -241,7 +241,11 @@ void CABACWriter::sao( const Slice& slice, unsigned ctuRsAddr ) int rx = ctuRsAddr - ry * frame_width_in_ctus; const Position pos ( rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight ); const unsigned curSliceIdx = slice.getIndependentSliceIdx(); +#if JVET_N0857_TILES_BRICKS + const unsigned curTileIdx = cs.picture->brickMap->getBrickIdxRsMap( pos ); +#else const unsigned curTileIdx = cs.picture->tileMap->getTileIdxMap( pos ); +#endif bool leftMergeAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), curSliceIdx, curTileIdx, CH_L ) ? true : false; bool aboveMergeAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), curSliceIdx, curTileIdx, CH_L ) ? true : false; sao_block_pars( sao_ctu_pars, sps.getBitDepths(), sliceEnabled, leftMergeAvail, aboveMergeAvail, false ); @@ -1453,8 +1457,12 @@ void CABACWriter::sbt_mode( const CodingUnit& cu ) void CABACWriter::end_of_ctu( const CodingUnit& cu, CUCtx& cuCtx ) { const Slice* slice = cu.cs->slice; +#if JVET_N0857_TILES_BRICKS + const int currentCTUTsAddr = cu.cs->picture->brickMap->getCtuRsToBsAddrMap( CU::getCtuAddr( cu ) ); +#else const TileMap& tileMap = *cu.cs->picture->tileMap; const int currentCTUTsAddr = tileMap.getCtuRsToTsAddrMap( CU::getCtuAddr( cu ) ); +#endif const bool isLastSubCUOfCtu = CU::isLastSubCUOfCtu( cu ); if ( isLastSubCUOfCtu @@ -3460,7 +3468,11 @@ void CABACWriter::codeAlfCtuEnableFlag( CodingStructure& cs, uint32_t ctuRsAddr, int rx = ctuRsAddr - ry * frame_width_in_ctus; const Position pos( rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight ); const uint32_t curSliceIdx = cs.slice->getIndependentSliceIdx(); +#if JVET_N0857_TILES_BRICKS + const uint32_t curTileIdx = cs.picture->brickMap->getBrickIdxRsMap( pos ); +#else const uint32_t curTileIdx = cs.picture->tileMap->getTileIdxMap( pos ); +#endif bool leftAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), curSliceIdx, curTileIdx, CH_L ) ? true : false; bool aboveAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), curSliceIdx, curTileIdx, CH_L ) ? true : false; diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 66719184b807852c01cf210beef80d6493b6803c..815077c508e8547efcf4ae1acbbb7c8312fa4026 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -105,6 +105,31 @@ struct GOPEntry }; std::istringstream &operator>>(std::istringstream &in, GOPEntry &entry); //input + +#if JVET_N0857_TILES_BRICKS +struct BrickSplit +{ + int m_tileIdx; + bool m_uniformSplit; + int m_uniformHeight; + int m_numSplits; + int m_brickHeight[MAX_NUM_BRICKS_PER_TILE]; + BrickSplit() + : m_tileIdx(-1) + , m_uniformSplit(true) + , m_uniformHeight(0) + , m_numSplits(0) + { + ::memset( m_brickHeight, 0, sizeof(m_brickHeight) ); + } +}; + +typedef std::map<int, BrickSplit> BrickSplitMap; + +std::istringstream &operator>>(std::istringstream &in, BrickSplit &entry); //input +#endif + + //! \ingroup EncoderLib //! \{ @@ -418,7 +443,7 @@ protected: bool m_bPCMInputBitDepthFlag; bool m_bPCMFilterDisableFlag; bool m_intraSmoothingDisabledFlag; - bool m_loopFilterAcrossTilesEnabledFlag; + bool m_loopFilterAcrossBricksEnabledFlag; bool m_tileUniformSpacingFlag; int m_iNumColumnsMinus1; int m_iNumRowsMinus1; @@ -426,6 +451,18 @@ protected: std::vector<int> m_tileRowHeight; bool m_entropyCodingSyncEnabledFlag; + +#if JVET_N0857_TILES_BRICKS + bool m_rectSliceFlag; + int m_numSlicesInPicMinus1; + std::vector<int> m_topLeftTileIdx; + std::vector<int> m_bottomRightTileIdx; + bool m_loopFilterAcrossSlicesEnabledFlag; + bool m_signalledSliceIdFlag; + int m_signalledSliceIdLengthMinus1; + std::vector<int> m_sliceId; + BrickSplitMap m_brickSplitMap; +#endif HashType m_decodedPictureHashSEIType; bool m_bufferingPeriodSEIEnabled; @@ -1166,8 +1203,8 @@ public: void setSaoGreedyMergeEnc (bool val) { m_saoGreedyMergeEnc = val; } bool getSaoGreedyMergeEnc () { return m_saoGreedyMergeEnc; } #endif - void setLFCrossTileBoundaryFlag ( bool val ) { m_loopFilterAcrossTilesEnabledFlag = val; } - bool getLFCrossTileBoundaryFlag () { return m_loopFilterAcrossTilesEnabledFlag; } + void setLFCrossTileBoundaryFlag ( bool val ) { m_loopFilterAcrossBricksEnabledFlag = val; } + bool getLFCrossTileBoundaryFlag () { return m_loopFilterAcrossBricksEnabledFlag; } void setTileUniformSpacingFlag ( bool b ) { m_tileUniformSpacingFlag = b; } bool getTileUniformSpacingFlag () { return m_tileUniformSpacingFlag; } void setNumColumnsMinus1 ( int i ) { m_iNumColumnsMinus1 = i; } @@ -1178,6 +1215,28 @@ public: int getNumRowsMinus1 () { return m_iNumRowsMinus1; } void setRowHeight ( const std::vector<int>& rowHeight) { m_tileRowHeight = rowHeight; } uint32_t getRowHeight ( uint32_t rowIdx ) { return m_tileRowHeight[rowIdx]; } + +#if JVET_N0857_TILES_BRICKS + bool getRectSliceFlag() const { return m_rectSliceFlag; } + void setRectSliceFlag(bool val) { m_rectSliceFlag = val; } + int getNumSlicesInPicMinus1() const { return m_numSlicesInPicMinus1; } + void setNumSlicesInPicMinus1(int val) { m_numSlicesInPicMinus1 = val; } + int getTopLeftTileIdx(uint32_t columnIdx) const { return m_topLeftTileIdx[columnIdx]; } + void setTopLeftTileIdx(const std::vector<int>& val) { m_topLeftTileIdx = val; } + int getBottomeRightTileIdx(uint32_t columnIdx) const { return m_bottomRightTileIdx[columnIdx]; } + void setBottomRightTileIdx(const std::vector<int>& val) { m_bottomRightTileIdx = val; } + bool getLoopFilterAcrossSlicesEnabledFlag() const { return m_loopFilterAcrossSlicesEnabledFlag; } + void setLoopFilterAcrossSlicesEnabledFlag(bool val) { m_loopFilterAcrossSlicesEnabledFlag = val; } + bool getSignalledSliceIdFlag() const { return m_signalledSliceIdFlag; } + void setSignalledSliceIdFlag(bool val) { m_signalledSliceIdFlag = val; } + int getSignalledSliceIdLengthMinus1() const { return m_signalledSliceIdLengthMinus1; } + void setSignalledSliceIdLengthMinus1(int val) { m_signalledSliceIdLengthMinus1 = val; } + int getSliceId(uint32_t columnIdx) const { return m_sliceId[columnIdx]; } + void setSliceId(const std::vector<int>& val) { m_sliceId = val; } + BrickSplitMap getBrickSplitMap() const { return m_brickSplitMap; } + void setBrickSplitMap(const BrickSplitMap& val) { m_brickSplitMap = val; } +#endif + void xCheckGSParameters(); void setEntropyCodingSyncEnabledFlag(bool b) { m_entropyCodingSyncEnabledFlag = b; } bool getEntropyCodingSyncEnabledFlag() const { return m_entropyCodingSyncEnabledFlag; } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 05a7d018dc1e7829ded70a5f93095de4254df5b1..c9e6a0afb64fbb6e6d096d03f35c0181bd5bccde 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -1321,6 +1321,13 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, // The exception is each slice / slice-segment must have at least one CTU. if (bestCS->cost != MAX_DOUBLE) { +#if JVET_N0857_TILES_BRICKS + const BrickMap& tileMap = *tempCS->picture->brickMap; + const uint32_t CtuAddr = CU::getCtuAddr( *bestCS->getCU( partitioner.chType ) ); + const bool isEndOfSlice = slice.getSliceMode() == FIXED_NUMBER_OF_BYTES + && ((slice.getSliceBits() + CS::getEstBits(*bestCS)) > slice.getSliceArgument() << 3) + && CtuAddr != tileMap.getCtuBsToRsAddrMap(slice.getSliceCurStartCtuTsAddr()); +#else const TileMap& tileMap = *tempCS->picture->tileMap; const uint32_t CtuAddr = CU::getCtuAddr( *bestCS->getCU( partitioner.chType ) ); const bool isEndOfSlice = slice.getSliceMode() == FIXED_NUMBER_OF_BYTES @@ -1331,6 +1338,7 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, #else ; #endif +#endif #if HEVC_DEPENDENT_SLICES const bool isEndOfSliceSegment = slice.getSliceSegmentMode() == FIXED_NUMBER_OF_BYTES @@ -1428,7 +1436,11 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.mmvdSkip = false; cu.predMode = MODE_INTRA; @@ -1697,7 +1709,11 @@ void EncCu::xCheckIntraPCM(CodingStructure *&tempCS, CodingStructure *&bestCS, P partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.mmvdSkip = false; cu.predMode = MODE_INTRA; @@ -1927,7 +1943,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& cu.cs = tempCS; cu.predMode = MODE_INTER; cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos()); +#endif PredictionUnit pu( tempCS->area ); pu.cu = &cu; @@ -2036,7 +2056,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& #endif partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.mmvdSkip = false; cu.triangle = false; @@ -2483,7 +2507,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.mmvdSkip = false; cu.triangle = false; @@ -2704,7 +2732,11 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru cu.cs = tempCS; cu.predMode = MODE_INTER; cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); +#endif cu.triangle = true; cu.mmvdSkip = false; cu.GBiIdx = GBI_DEFAULT; @@ -2760,7 +2792,11 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.predMode = MODE_INTER; cu.transQuantBypass = encTestMode.lossless; @@ -2892,7 +2928,11 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru partitioner.setCUData(cu); cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.predMode = MODE_INTER; cu.transQuantBypass = encTestMode.lossless; @@ -2981,7 +3021,11 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct cu.cs = tempCS; cu.predMode = MODE_INTER; cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); +#endif cu.mmvdSkip = false; PredictionUnit pu( tempCS->area ); @@ -3038,7 +3082,11 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.affine = true; cu.predMode = MODE_INTER; @@ -3155,7 +3203,11 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.affine = true; cu.predMode = MODE_INTER; @@ -3281,7 +3333,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct cu.cs = tempCS; cu.predMode = MODE_IBC; cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos()); +#endif PredictionUnit pu(tempCS->area); pu.cu = &cu; pu.cs = tempCS; @@ -3320,7 +3376,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct partitioner.setCUData(cu); cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos()); +#endif cu.skip = false; cu.predMode = MODE_IBC; cu.transQuantBypass = encTestMode.lossless; @@ -3443,7 +3503,11 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct partitioner.setCUData(cu); cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos()); +#endif cu.skip = false; cu.predMode = MODE_IBC; cu.transQuantBypass = encTestMode.lossless; @@ -3529,7 +3593,11 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best partitioner.setCUData(cu); cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos()); +#endif cu.skip = false; cu.predMode = MODE_IBC; cu.transQuantBypass = encTestMode.lossless; @@ -3732,7 +3800,11 @@ void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestC partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.mmvdSkip = false; //cu.affine @@ -3869,7 +3941,11 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be partitioner.setCUData( cu ); cu.slice = tempCS->slice; +#if JVET_N0857_TILES_BRICKS + cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap( tempCS->area.lumaPos() ); +#else cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() ); +#endif cu.skip = false; cu.mmvdSkip = false; //cu.affine diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index 4a4cb0f499534c09cb5e7a70613b263636b33612..104e3ed02d205da0c77a7ee9172d0f979b0251fb 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -2173,7 +2173,11 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, const uint32_t numberOfCtusInFrame = pcPic->cs->pcv->sizeInCtus; const int numSubstreamsColumns = (pcSlice->getPPS()->getNumTileColumnsMinus1() + 1); const int numSubstreamRows = pcSlice->getPPS()->getEntropyCodingSyncEnabledFlag() ? pcPic->cs->pcv->heightInCtus : (pcSlice->getPPS()->getNumTileRowsMinus1() + 1); +#if JVET_N0857_TILES_BRICKS + const int numSubstreams = std::max<int> (numSubstreamRows * numSubstreamsColumns, (int) pcPic->brickMap->bricks.size()); +#else const int numSubstreams = numSubstreamRows * numSubstreamsColumns; +#endif std::vector<OutputBitstream> substreamsOut(numSubstreams); #if ENABLE_QPA @@ -2679,11 +2683,15 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, // Append substreams... OutputBitstream *pcOut = pcBitstreamRedirect; +#if JVET_N0857_TILES_BRICKS + const int numZeroSubstreamsAtStartOfSlice = pcPic->brickMap->getSubstreamForCtuAddr(pcSlice->getSliceCurStartCtuTsAddr(), false, pcSlice); +#else #if HEVC_DEPENDENT_SLICES const int numZeroSubstreamsAtStartOfSlice = pcPic->tileMap->getSubstreamForCtuAddr(pcSlice->getSliceSegmentCurStartCtuTsAddr(), false, pcSlice); #else const int numZeroSubstreamsAtStartOfSlice = pcPic->tileMap->getSubstreamForCtuAddr(pcSlice->getSliceCurStartCtuTsAddr(), false, pcSlice); +#endif #endif const int numSubstreamsToCode = pcSlice->getNumberOfSubstreamSizes()+1; for ( uint32_t ui = 0 ; ui < numSubstreamsToCode; ui++ ) diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index b30103a4983739af61ad583e22112e1314793158..f4532e2bb57ec71620eddacf1cff94c061624700 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -1480,7 +1480,13 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps) } pps.setEntropyCodingSyncEnabledFlag( m_entropyCodingSyncEnabledFlag ); + +#if JVET_N0857_TILES_BRICKS + pps.setSingleTileInPicFlag((m_iNumColumnsMinus1 == 0 && m_iNumRowsMinus1 == 0)); +#else pps.setTilesEnabledFlag( (m_iNumColumnsMinus1 > 0 || m_iNumRowsMinus1 > 0) ); +#endif + pps.setUseWP( m_useWeightedPred ); pps.setWPBiPred( m_useWeightedBiPred ); pps.setOutputFlagPresentFlag( false ); @@ -1870,7 +1876,22 @@ int EncLib::getReferencePictureSetIdxForSOP(int POCCurr, int GOPid ) void EncLib::xInitPPSforTiles(PPS &pps) { - pps.setTileUniformSpacingFlag( m_tileUniformSpacingFlag ); +#if JVET_N0857_TILES_BRICKS + if ( (m_iNumColumnsMinus1==0) && (m_iNumRowsMinus1==0) ) + { + // one, no bricks + pps.setSingleTileInPicFlag(true); + pps.setSingleBrickPerSliceFlag(true); + pps.setRectSliceFlag(true); + } + else + { + pps.setSingleTileInPicFlag(false); + pps.setSingleBrickPerSliceFlag( m_sliceMode==SINGLE_BRICK_PER_SLICE ); + pps.setRectSliceFlag( m_sliceMode==SINGLE_BRICK_PER_SLICE ); + } +#endif + pps.setUniformTileSpacingFlag( m_tileUniformSpacingFlag ); pps.setNumTileColumnsMinus1( m_iNumColumnsMinus1 ); pps.setNumTileRowsMinus1( m_iNumRowsMinus1 ); if( !m_tileUniformSpacingFlag ) @@ -1878,9 +1899,114 @@ void EncLib::xInitPPSforTiles(PPS &pps) pps.setTileColumnWidth( m_tileColumnWidth ); pps.setTileRowHeight( m_tileRowHeight ); } - pps.setLoopFilterAcrossTilesEnabledFlag( m_loopFilterAcrossTilesEnabledFlag ); + pps.setLoopFilterAcrossBricksEnabledFlag( m_loopFilterAcrossBricksEnabledFlag ); + +#if JVET_N0857_TILES_BRICKS + //pps.setRectSliceFlag( m_rectSliceFlag ); + pps.setNumSlicesInPicMinus1( m_numSlicesInPicMinus1 ); + pps.setTopLeftTileIdx( m_topLeftTileIdx ); + pps.setBottomRightTileIdx( m_bottomRightTileIdx ); + pps.setLoopFilterAcrossBricksEnabledFlag( m_loopFilterAcrossBricksEnabledFlag ); + pps.setLoopFilterAcrossSlicesEnabledFlag( m_loopFilterAcrossSlicesEnabledFlag ); + pps.setSignalledSliceIdFlag( m_signalledSliceIdFlag ); + pps.setSignalledSliceIdLengthMinus1( m_signalledSliceIdLengthMinus1 ); + pps.setSignalledSliceIdFlag( m_signalledSliceIdFlag ); + pps.setSignalledSliceIdLengthMinus1( m_signalledSliceIdLengthMinus1 ); + pps.setSliceId( m_sliceId ); + + int numTiles= (m_iNumColumnsMinus1 + 1) * (m_iNumRowsMinus1 + 1); + + if (m_brickSplitMap.empty()) + { + pps.setBrickSplittingPresentFlag(false); + } + else + { + pps.setBrickSplittingPresentFlag(true); + + std::vector<bool> brickSplitFlag (numTiles, false); + std::vector<bool> uniformBrickSpacingFlag (numTiles, false); + std::vector<int> brickHeightMinus1 (numTiles, 0); + std::vector<int> numBrickRowsMinus1 (numTiles, 0); + std::vector<std::vector<int>> brickRowHeightMinus1 (numTiles); + + for (auto &brickSplit: m_brickSplitMap) + { + int tileIdx = brickSplit.first; + CHECK ( tileIdx >= numTiles, "Brick split specified for undefined tile"); + + brickSplitFlag[tileIdx] = true; + uniformBrickSpacingFlag [tileIdx] = brickSplit.second.m_uniformSplit; + if (uniformBrickSpacingFlag [tileIdx]) + { + brickHeightMinus1[tileIdx]=brickSplit.second.m_uniformHeight - 1; + } + else + { + numBrickRowsMinus1[tileIdx]=brickSplit.second.m_numSplits; + brickRowHeightMinus1[tileIdx].resize(brickSplit.second.m_numSplits); + for (int i=0; i<brickSplit.second.m_numSplits; i++) + { + brickRowHeightMinus1[tileIdx][i]=brickSplit.second.m_brickHeight[i] - 1; + } + } + } + pps.setBrickSplitFlag(brickSplitFlag); + pps.setUniformBrickSpacingFlag(uniformBrickSpacingFlag); + pps.setBrickHeightMinus1(brickHeightMinus1); + pps.setNumBrickRowsMinus1(numBrickRowsMinus1); + pps.setBrickRowHeightMinus1(brickRowHeightMinus1); + + // check brick dimensions + std::vector<uint32_t> tileRowHeight (m_iNumRowsMinus1+1); + int picHeightInCtus = (getSourceHeight() + m_maxCUHeight - 1) / m_maxCUHeight; + + // calculate all tile row heights + if( pps.getUniformTileSpacingFlag() ) + { + //set width and height for each (uniform) tile + for(int row=0; row < m_iNumRowsMinus1 + 1; row++) + { + tileRowHeight[row] = (row+1)*picHeightInCtus/(m_iNumRowsMinus1+1) - (row*picHeightInCtus)/(m_iNumRowsMinus1 + 1); + } + } + else + { + tileRowHeight[ m_iNumRowsMinus1 ] = picHeightInCtus; + for( int j = 0; j < m_iNumRowsMinus1; j++ ) + { + tileRowHeight[ j ] = pps.getTileRowHeight( j ); + tileRowHeight[ m_iNumRowsMinus1 ] = tileRowHeight[ m_iNumRowsMinus1 ] - pps.getTileRowHeight( j ); + } + } + + // check brick splits for each tile + for (int tileIdx=0; tileIdx < numTiles; tileIdx++) + { + if (pps.getBrickSplitFlag(tileIdx)) + { + const int tileY = tileIdx / (m_iNumColumnsMinus1+1); + + int tileHeight = tileRowHeight [tileY]; + + if (pps.getUniformBrickSpacingFlag(tileIdx)) + { + CHECK((pps.getBrickHeightMinus1(tileIdx) + 1) >= tileHeight, "Brick height larger than or equal to tile height"); + } + else + { + int cumulativeHeight=0; + for (int i = 0; i < pps.getNumBrickRowsMinus1(tileIdx); i++) + { + cumulativeHeight += pps.getBrickRowHeightMinus1(tileIdx, i) + 1; + } + CHECK(cumulativeHeight >= tileHeight, "Cumulative brick height larger than or equal to tile height"); + } + } + } + } - // # substreams is "per tile" when tiles are independent. +#endif } void EncCfg::xCheckGSParameters() diff --git a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp index 1a90c2ec66372cf41527d5c72a9206be4a03e26e..c4b69280bc6a2d5147965015a36cb1ed274a75bf 100644 --- a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp +++ b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp @@ -1592,7 +1592,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c void EncSampleAdaptiveOffset::deriveLoopFilterBoundaryAvailibility(CodingStructure& cs, const Position &pos, bool& isLeftAvail, bool& isAboveAvail, bool& isAboveLeftAvail) const { - bool isLoopFiltAcrossTilePPS = cs.pps->getLoopFilterAcrossTilesEnabledFlag(); + bool isLoopFiltAcrossTilePPS = cs.pps->getLoopFilterAcrossBricksEnabledFlag(); const int width = cs.pcv->maxCUWidth; const int height = cs.pcv->maxCUHeight; diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp index be6ec8168ce69b2b1b661db0423d4e27d18172b2..caa1e0ba99ea4bcd90ffca97ade72709cee5e9bd 100644 --- a/source/Lib/EncoderLib/EncSlice.cpp +++ b/source/Lib/EncoderLib/EncSlice.cpp @@ -222,8 +222,11 @@ static int getGlaringColorQPOffset (Picture* const pcPic, const int ctuAddr, con { for (uint32_t ctuTsAddr = startAddr; ctuTsAddr < boundingAddr; ctuTsAddr++) { +#if JVET_N0857_TILES_BRICKS + const uint32_t ctuRsAddr = pcPic->brickMap->getCtuBsToRsAddrMap (ctuTsAddr); +#else const uint32_t ctuRsAddr = pcPic->tileMap->getCtuTsToRsAddrMap (ctuTsAddr); - +#endif avgLumaValue += pcPic->m_iOffsetCtu[ctuRsAddr]; } avgLumaValue = (avgLumaValue + ((boundingAddr - startAddr) >> 1)) / (boundingAddr - startAddr); @@ -869,7 +872,11 @@ static bool applyQPAdaptation (Picture* const pcPic, Slice* const pcSlice, { const int bitDepth = pcSlice->getSPS()->getBitDepth (CHANNEL_TYPE_LUMA); const int iQPIndex = pcSlice->getSliceQp(); // initial QP index for current slice, used in following loops +#if JVET_N0857_TILES_BRICKS + const BrickMap& tileMap = *pcPic->brickMap; +#else const TileMap& tileMap = *pcPic->tileMap; +#endif bool sliceQPModified = false; uint32_t meanLuma = MAX_UINT; double hpEnerAvg = 0.0; @@ -880,7 +887,11 @@ static bool applyQPAdaptation (Picture* const pcPic, Slice* const pcSlice, { for (uint32_t ctuTsAddr = startAddr; ctuTsAddr < boundingAddr; ctuTsAddr++) { +#if JVET_N0857_TILES_BRICKS + const uint32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap (ctuTsAddr); +#else const uint32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap (ctuTsAddr); +#endif const Position pos ((ctuRsAddr % pcv.widthInCtus) * pcv.maxCUWidth, (ctuRsAddr / pcv.widthInCtus) * pcv.maxCUHeight); const CompArea ctuArea = clipArea (CompArea (COMPONENT_Y, pcPic->chromaFormat, Area (pos.x, pos.y, pcv.maxCUWidth, pcv.maxCUHeight)), pcPic->Y()); const CompArea fltArea = clipArea (CompArea (COMPONENT_Y, pcPic->chromaFormat, Area (pos.x > 0 ? pos.x - 1 : 0, pos.y > 0 ? pos.y - 1 : 0, pcv.maxCUWidth + (pos.x > 0 ? 2 : 1), pcv.maxCUHeight + (pos.y > 0 ? 2 : 1))), pcPic->Y()); @@ -927,7 +938,11 @@ static bool applyQPAdaptation (Picture* const pcPic, Slice* const pcSlice, for (uint32_t ctuTsAddr = startAddr; ctuTsAddr < boundingAddr; ctuTsAddr++) { +#if JVET_N0857_TILES_BRICKS + const uint32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap (ctuTsAddr); +#else const uint32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap (ctuTsAddr); +#endif meanLuma += pcPic->m_iOffsetCtu[ctuRsAddr]; // CTU mean } @@ -955,7 +970,11 @@ static bool applyQPAdaptation (Picture* const pcPic, Slice* const pcSlice, for (uint32_t ctuTsAddr = startAddr; ctuTsAddr < boundingAddr; ctuTsAddr++) { +#if JVET_N0857_TILES_BRICKS + const uint32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap (ctuTsAddr); +#else const uint32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap (ctuTsAddr); +#endif pcPic->m_iOffsetCtu[ctuRsAddr] = (Pel)iQPFixed; // fixed QPs } @@ -964,7 +983,11 @@ static bool applyQPAdaptation (Picture* const pcPic, Slice* const pcSlice, { for (uint32_t ctuTsAddr = startAddr; ctuTsAddr < boundingAddr; ctuTsAddr++) { +#if JVET_N0857_TILES_BRICKS + const uint32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap (ctuTsAddr); +#else const uint32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap (ctuTsAddr); +#endif int iQPAdapt = Clip3 (0, MAX_QP, iQPIndex + apprI3Log2 (pcPic->m_uEnerHpCtu[ctuRsAddr] * hpEnerPic)); @@ -1296,7 +1319,11 @@ void EncSlice::calCostSliceI(Picture* pcPic) // TODO: this only analyses the fir { double iSumHadSlice = 0; Slice * const pcSlice = pcPic->slices[getSliceSegmentIdx()]; +#if JVET_N0857_TILES_BRICKS + const BrickMap &tileMap = *pcPic->brickMap; +#else const TileMap &tileMap = *pcPic->tileMap; +#endif const PreCalcValues& pcv = *pcPic->cs->pcv; const SPS &sps = *(pcSlice->getSPS()); const int shift = sps.getBitDepth(CHANNEL_TYPE_LUMA)-8; @@ -1308,10 +1335,15 @@ void EncSlice::calCostSliceI(Picture* pcPic) // TODO: this only analyses the fir uint32_t startCtuTsAddr, boundingCtuTsAddr; xDetermineStartAndBoundingCtuTsAddr ( startCtuTsAddr, boundingCtuTsAddr, pcPic ); - +#if JVET_N0857_TILES_BRICKS + for( uint32_t ctuTsAddr = startCtuTsAddr, ctuRsAddr = tileMap.getCtuBsToRsAddrMap( startCtuTsAddr); + ctuTsAddr < boundingCtuTsAddr; + ctuRsAddr = tileMap.getCtuBsToRsAddrMap(++ctuTsAddr) ) +#else for( uint32_t ctuTsAddr = startCtuTsAddr, ctuRsAddr = tileMap.getCtuTsToRsAddrMap( startCtuTsAddr); ctuTsAddr < boundingCtuTsAddr; ctuRsAddr = tileMap.getCtuTsToRsAddrMap(++ctuTsAddr) ) +#endif { Position pos( (ctuRsAddr % pcv.widthInCtus) * pcv.maxCUWidth, (ctuRsAddr / pcv.widthInCtus) * pcv.maxCUHeight); @@ -1521,7 +1553,11 @@ void EncSlice::checkDisFracMmvd( Picture* pcPic, uint32_t startCtuTsAddr, uint32 Slice* pcSlice = cs.slice; const PreCalcValues& pcv = *cs.pcv; const uint32_t widthInCtus = pcv.widthInCtus; +#if JVET_N0857_TILES_BRICKS + const BrickMap& tileMap = *pcPic->brickMap; +#else const TileMap& tileMap = *pcPic->tileMap; +#endif const uint32_t hashThreshold = 20; uint32_t totalCtu = 0; uint32_t hashRatio = 0; @@ -1533,7 +1569,11 @@ void EncSlice::checkDisFracMmvd( Picture* pcPic, uint32_t startCtuTsAddr, uint32 for ( uint32_t ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ctuTsAddr++ ) { +#if JVET_N0857_TILES_BRICKS + const uint32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap( ctuTsAddr ); +#else const uint32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap( ctuTsAddr ); +#endif const uint32_t ctuXPosInCtus = ctuRsAddr % widthInCtus; const uint32_t ctuYPosInCtus = ctuRsAddr / widthInCtus; @@ -1560,7 +1600,11 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons Slice* pcSlice = cs.slice; const PreCalcValues& pcv = *cs.pcv; const uint32_t widthInCtus = pcv.widthInCtus; +#if JVET_N0857_TILES_BRICKS + const BrickMap& tileMap = *pcPic->brickMap; +#else const TileMap& tileMap = *pcPic->tileMap; +#endif #if ENABLE_QPA const int iQPIndex = pcSlice->getSliceQpBase(); #endif @@ -1621,10 +1665,18 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons // for every CTU in the slice segment (may terminate sooner if there is a byte limit on the slice-segment) for( uint32_t ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ctuTsAddr++ ) { +#if JVET_N0857_TILES_BRICKS + const int32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap( ctuTsAddr ); +#else const int32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap( ctuTsAddr ); +#endif // update CABAC state +#if JVET_N0857_TILES_BRICKS + const uint32_t firstCtuRsAddrOfTile = tileMap.bricks[tileMap.getBrickIdxRsMap(ctuRsAddr)].getFirstCtuRsAddr(); +#else const uint32_t firstCtuRsAddrOfTile = tileMap.tiles[tileMap.getTileIdxMap(ctuRsAddr)].getFirstCtuRsAddr(); +#endif const uint32_t tileXPosInCtus = firstCtuRsAddrOfTile % widthInCtus; const uint32_t ctuXPosInCtus = ctuRsAddr % widthInCtus; const uint32_t ctuYPosInCtus = ctuRsAddr / widthInCtus; @@ -1657,7 +1709,11 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons { // reset and then update contexts to the state at the end of the top-right CTU (if within current slice and tile). pCABACWriter->initCtxModels( *pcSlice ); +#if JVET_N0857_TILES_BRICKS + if( cs.getCURestricted( pos.offset(pcv.maxCUWidth, -1), pcSlice->getIndependentSliceIdx(), tileMap.getBrickIdxRsMap( pos ), CH_L ) ) +#else if( cs.getCURestricted( pos.offset(pcv.maxCUWidth, -1), pcSlice->getIndependentSliceIdx(), tileMap.getTileIdxMap( pos ), CH_L ) ) +#endif { // Top-right is available, we use it. pCABACWriter->getCtx() = pEncLib->m_entropyCodingSyncContextState; @@ -1903,7 +1959,11 @@ void EncSlice::encodeSlice ( Picture* pcPic, OutputBitstream* pcSubstreams, ui { Slice *const pcSlice = pcPic->slices[getSliceSegmentIdx()]; +#if JVET_N0857_TILES_BRICKS + const BrickMap& tileMap = *pcPic->brickMap; +#else const TileMap& tileMap = *pcPic->tileMap; +#endif #if HEVC_DEPENDENT_SLICES const uint32_t startCtuTsAddr = pcSlice->getSliceSegmentCurStartCtuTsAddr(); const uint32_t boundingCtuTsAddr = pcSlice->getSliceSegmentCurEndCtuTsAddr(); @@ -1956,8 +2016,13 @@ void EncSlice::encodeSlice ( Picture* pcPic, OutputBitstream* pcSubstreams, ui for( uint32_t ctuTsAddr = startCtuTsAddr; ctuTsAddr < boundingCtuTsAddr; ctuTsAddr++ ) { +#if JVET_N0857_TILES_BRICKS + const uint32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap(ctuTsAddr); + const Brick& currentTile = tileMap.bricks[tileMap.getBrickIdxRsMap(ctuRsAddr)]; +#else const uint32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap(ctuTsAddr); const Tile& currentTile = tileMap.tiles[tileMap.getTileIdxMap(ctuRsAddr)]; +#endif const uint32_t firstCtuRsAddrOfTile = currentTile.getFirstCtuRsAddr(); const uint32_t tileXPosInCtus = firstCtuRsAddrOfTile % widthInCtus; const uint32_t tileYPosInCtus = firstCtuRsAddrOfTile / widthInCtus; @@ -1986,7 +2051,11 @@ void EncSlice::encodeSlice ( Picture* pcPic, OutputBitstream* pcSubstreams, ui { m_CABACWriter->initCtxModels( *pcSlice ); } +#if JVET_N0857_TILES_BRICKS + if( cs.getCURestricted( pos.offset( pcv.maxCUWidth, -1 ), pcSlice->getIndependentSliceIdx(), tileMap.getBrickIdxRsMap( pos ), CH_L ) ) +#else if( cs.getCURestricted( pos.offset( pcv.maxCUWidth, -1 ), pcSlice->getIndependentSliceIdx(), tileMap.getTileIdxMap( pos ), CH_L ) ) +#endif { // Top-right is available, so use it. m_CABACWriter->getCtx() = m_entropyCodingSyncContextState; @@ -2008,11 +2077,18 @@ void EncSlice::encodeSlice ( Picture* pcPic, OutputBitstream* pcSubstreams, ui } // terminate the sub-stream, if required (end of slice-segment, end of tile, end of wavefront-CTU-row): +#if JVET_N0857_TILES_BRICKS + if( ctuTsAddr + 1 == boundingCtuTsAddr || + ( ctuXPosInCtus + 1 == tileXPosInCtus + currentTile.getWidthInCtus () && + ( ctuYPosInCtus + 1 == tileYPosInCtus + currentTile.getHeightInCtus() || wavefrontsEnabled ) ) + ) +#else if( ctuTsAddr + 1 == boundingCtuTsAddr || ( ctuXPosInCtus + 1 == tileXPosInCtus + currentTile.getTileWidthInCtus () && ( ctuYPosInCtus + 1 == tileYPosInCtus + currentTile.getTileHeightInCtus() || wavefrontsEnabled ) ) ) +#endif { m_CABACWriter->end_of_slice(); @@ -2054,7 +2130,11 @@ void EncSlice::calculateBoundingCtuTsAddrForSlice(uint32_t &startCtuTSAddrSlice, Picture* pcPic, const int sliceMode, const int sliceArgument) { Slice* pcSlice = pcPic->slices[getSliceSegmentIdx()]; +#if JVET_N0857_TILES_BRICKS + const BrickMap& tileMap = *( pcPic->brickMap ); +#else const TileMap& tileMap = *( pcPic->tileMap ); +#endif const PPS &pps = *( pcSlice->getPPS() ); const uint32_t numberOfCtusInFrame = pcPic->cs->pcv->sizeInCtus; boundingCtuTSAddrSlice=0; @@ -2073,16 +2153,26 @@ void EncSlice::calculateBoundingCtuTsAddrForSlice(uint32_t &startCtuTSAddrSlice, break; case FIXED_NUMBER_OF_TILES: { +#if JVET_N0857_TILES_BRICKS + const uint32_t tileIdx = tileMap.getBrickIdxRsMap( tileMap.getCtuBsToRsAddrMap(startCtuTSAddrSlice) ); + const uint32_t tileTotalCount = (uint32_t) tileMap.bricks.size(); +#else const uint32_t tileIdx = tileMap.getTileIdxMap( tileMap.getCtuTsToRsAddrMap(startCtuTSAddrSlice) ); const uint32_t tileTotalCount = (pps.getNumTileColumnsMinus1()+1) * (pps.getNumTileRowsMinus1()+1); +#endif uint32_t ctuAddrIncrement = 0; for(uint32_t tileIdxIncrement = 0; tileIdxIncrement < sliceArgument; tileIdxIncrement++) { if((tileIdx + tileIdxIncrement) < tileTotalCount) { +#if JVET_N0857_TILES_BRICKS + uint32_t tileWidthInCtus = tileMap.bricks[tileIdx + tileIdxIncrement].getWidthInCtus(); + uint32_t tileHeightInCtus = tileMap.bricks[tileIdx + tileIdxIncrement].getHeightInCtus(); +#else uint32_t tileWidthInCtus = tileMap.tiles[tileIdx + tileIdxIncrement].getTileWidthInCtus(); uint32_t tileHeightInCtus = tileMap.tiles[tileIdx + tileIdxIncrement].getTileHeightInCtus(); +#endif ctuAddrIncrement += (tileWidthInCtus * tileHeightInCtus); } } @@ -2090,6 +2180,17 @@ void EncSlice::calculateBoundingCtuTsAddrForSlice(uint32_t &startCtuTSAddrSlice, boundingCtuTSAddrSlice = ((startCtuTSAddrSlice + ctuAddrIncrement) < numberOfCtusInFrame) ? (startCtuTSAddrSlice + ctuAddrIncrement) : numberOfCtusInFrame; } break; +#if JVET_N0857_TILES_BRICKS + case SINGLE_BRICK_PER_SLICE: + { + const uint32_t brickIdx = tileMap.getBrickIdxRsMap( tileMap.getCtuBsToRsAddrMap(startCtuTSAddrSlice) ); + const uint32_t brickWidthInCtus = tileMap.bricks[brickIdx].getWidthInCtus(); + const uint32_t brickHeightInCtus = tileMap.bricks[brickIdx].getHeightInCtus(); + const uint32_t ctuAddrIncrement = brickWidthInCtus * brickHeightInCtus; + boundingCtuTSAddrSlice = ((startCtuTSAddrSlice + ctuAddrIncrement) < numberOfCtusInFrame) ? (startCtuTSAddrSlice + ctuAddrIncrement) : numberOfCtusInFrame; + } + break; +#endif default: boundingCtuTSAddrSlice = numberOfCtusInFrame; break; @@ -2101,12 +2202,21 @@ void EncSlice::calculateBoundingCtuTsAddrForSlice(uint32_t &startCtuTSAddrSlice, if ((sliceMode == FIXED_NUMBER_OF_CTU || sliceMode == FIXED_NUMBER_OF_BYTES) && (pps.getNumTileRowsMinus1() > 0 || pps.getNumTileColumnsMinus1() > 0)) { +#if JVET_N0857_TILES_BRICKS + const uint32_t ctuRsAddr = tileMap.getCtuBsToRsAddrMap(startCtuTSAddrSlice); + const uint32_t startTileIdx = tileMap.getBrickIdxRsMap(ctuRsAddr); + const Brick& startingTile = tileMap.bricks[startTileIdx]; + const uint32_t tileStartTsAddr = tileMap.getCtuRsToBsAddrMap(startingTile.getFirstCtuRsAddr()); + const uint32_t tileStartWidth = startingTile.getWidthInCtus(); + const uint32_t tileStartHeight = startingTile.getHeightInCtus(); +#else const uint32_t ctuRsAddr = tileMap.getCtuTsToRsAddrMap(startCtuTSAddrSlice); const uint32_t startTileIdx = tileMap.getTileIdxMap(ctuRsAddr); const Tile& startingTile = tileMap.tiles[startTileIdx]; const uint32_t tileStartTsAddr = tileMap.getCtuRsToTsAddrMap(startingTile.getFirstCtuRsAddr()); const uint32_t tileStartWidth = startingTile.getTileWidthInCtus(); const uint32_t tileStartHeight = startingTile.getTileHeightInCtus(); +#endif const uint32_t tileLastTsAddr_excl = tileStartTsAddr + tileStartWidth*tileStartHeight; const uint32_t tileBoundingCtuTsAddrSlice = tileLastTsAddr_excl; const uint32_t ctuColumnOfStartingTile = ((startCtuTSAddrSlice-tileStartTsAddr)%tileStartWidth); diff --git a/source/Lib/EncoderLib/SEIEncoder.cpp b/source/Lib/EncoderLib/SEIEncoder.cpp index cc4e16ce4ecb78f73755c28475c51fc55e44ea26..1af9069e97ad0f3036e147df664d812dad063ee0 100644 --- a/source/Lib/EncoderLib/SEIEncoder.cpp +++ b/source/Lib/EncoderLib/SEIEncoder.cpp @@ -356,7 +356,11 @@ void SEIEncoder::initSEITempMotionConstrainedTileSets (SEITempMotionConstrainedT CHECK(!(sei!=NULL), "Unspecified error"); CHECK(!(pps!=NULL), "Unspecified error"); +#if !JVET_N0857_TILES_BRICKS if(pps->getTilesEnabledFlag()) +#else + if(!pps->getSingleTileInPicFlag()) +#endif { if (m_pcCfg->getMCTSEncConstraint()) { diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 89ee5002072e259f9b90e10863d2ed4347595840..9bda97fafa69a929c26a248e31d830c5a2e01490 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -247,14 +247,119 @@ void HLSWriter::codePPS( const PPS* pcPPS ) WRITE_FLAG( pcPPS->getUseWP() ? 1 : 0, "weighted_pred_flag" ); // Use of Weighting Prediction (P_SLICE) WRITE_FLAG( pcPPS->getWPBiPred() ? 1 : 0, "weighted_bipred_flag" ); // Use of Weighting Bi-Prediction (B_SLICE) WRITE_FLAG( pcPPS->getTransquantBypassEnabledFlag() ? 1 : 0, "transquant_bypass_enabled_flag" ); + +#if JVET_N0857_TILES_BRICKS + WRITE_FLAG( pcPPS->getSingleTileInPicFlag() ? 1 : 0, "single_tile_in_pic_flag" ); + if (!pcPPS->getSingleTileInPicFlag()) + { + WRITE_FLAG( pcPPS->getUniformTileSpacingFlag() ? 1 : 0, "uniform_tile_spacing_flag" ); + if (pcPPS->getUniformTileSpacingFlag()) + { + WRITE_UVLC( pcPPS->getTileColsWidthMinus1(), "tile_cols_width_minus1" ); + WRITE_UVLC( pcPPS->getTileRowsHeightMinus1(), "tile_rows_height_minus1" ); + } + else + { + WRITE_UVLC( pcPPS->getNumTileColumnsMinus1(), "num_tile_columns_minus1" ); + WRITE_UVLC( pcPPS->getNumTileRowsMinus1(), "num_tile_rows_minus1" ); + + CHECK( ((pcPPS->getNumTileColumnsMinus1() + 1) * (pcPPS->getNumTileRowsMinus1() + 1)) < 2, "tile colums * rows must be > 1 when explicitly signalled."); + + for (int i = 0; i < pcPPS->getNumTileColumnsMinus1(); i++) + { + WRITE_UVLC( pcPPS->getTileColumnWidth(i) - 1, "tile_column_width_minus1" ); + } + for (int i = 0; i < pcPPS->getNumTileRowsMinus1(); i++) + { + WRITE_UVLC( pcPPS->getTileRowHeight(i) - 1, "tile_row_height_minus1" ); + } + } + WRITE_FLAG( pcPPS->getBrickSplittingPresentFlag() ? 1 : 0, "brick_splitting_present_flag" ); + + int numTilesInPic = pcPPS->getUniformTileSpacingFlag() ? 0 : (pcPPS->getNumTileColumnsMinus1() + 1) * (pcPPS->getNumTileRowsMinus1() + 1); + + for( int i = 0; pcPPS->getBrickSplittingPresentFlag() && i < numTilesInPic; i++ ) + { + WRITE_FLAG( pcPPS->getBrickSplitFlag(i) ? 1 : 0, "brick_split_flag [i]" ); + if( pcPPS->getBrickSplitFlag(i) ) + { + WRITE_FLAG( pcPPS->getUniformBrickSpacingFlag(i) ? 1 : 0, "uniform_brick_spacing_flag [i]" ); + if( pcPPS->getUniformBrickSpacingFlag(i) ) + WRITE_UVLC( pcPPS->getBrickHeightMinus1(i), "brick_height_minus1" ); + else + { + WRITE_UVLC( pcPPS->getNumBrickRowsMinus1(i), "num_brick_rows_minus1 [i]" ); + for(int j = 0; j < pcPPS->getNumBrickRowsMinus1(i); j++ ) + WRITE_UVLC( pcPPS->getBrickRowHeightMinus1(i,j), "brick_row_height_minus1 [i][j]" ); + } + } + } + + WRITE_FLAG( pcPPS->getSingleBrickPerSliceFlag() ? 1 : 0, "single_brick_per_slice_flag" ); + if (!pcPPS->getSingleBrickPerSliceFlag()) + { + WRITE_FLAG( pcPPS->getRectSliceFlag() ? 1 : 0, "rect_slice_flag" ); + } + else + { + // make sure rect_slice_flag is set + CHECK (pcPPS->getRectSliceFlag()!=true, "RectSliceFlag must be equal to 1 for single_brick_per_slice_flag equal to 1"); + } + + if (pcPPS->getRectSliceFlag() && !pcPPS->getSingleBrickPerSliceFlag()) + { + WRITE_UVLC( pcPPS->getNumSlicesInPicMinus1(), "num_slices_in_pic_minus1" ); + int numSlicesInPic = pcPPS->getNumSlicesInPicMinus1() + 1; + int numTilesInPic = (pcPPS->getNumTileColumnsMinus1() + 1) * (pcPPS->getNumTileRowsMinus1() + 1); + int codeLength = (int)ceil(log2(numTilesInPic)); + for (int i = 0; i < numSlicesInPic; ++i) + { + if (i > 0) + { + WRITE_CODE( pcPPS->getTopLeftTileIdx(i), codeLength, "top_left_brick_idx "); + } + WRITE_CODE( pcPPS->getBottomeRightTileIdx(i)-pcPPS->getTopLeftTileIdx(i), codeLength, "bottom_right_brick_idx_delta" ); + + } + } + + WRITE_FLAG( pcPPS->getLoopFilterAcrossBricksEnabledFlag() ? 1 : 0, "loop_filter_across_bricks_enabled_flag" ); + if (pcPPS->getLoopFilterAcrossBricksEnabledFlag()) + { + WRITE_FLAG( pcPPS->getLoopFilterAcrossSlicesEnabledFlag() ? 1 : 0, "loop_filter_across_slices_enabled_flag" ); + } + } + else + { + // make sure rect_slice_flag is set + CHECK (pcPPS->getRectSliceFlag()!=true, "RectSliceFlag must be equalt to 1 for single_tile_in_pic_flag equal to 1"); + } + + if (pcPPS->getRectSliceFlag()) + { + WRITE_FLAG( pcPPS->getSignalledSliceIdFlag() ? 1 : 0, "signalled_slice_id_flag" ); + if (pcPPS->getSignalledSliceIdFlag()) + { + WRITE_UVLC( pcPPS->getSignalledSliceIdLengthMinus1(), "signalled_slice_id_length_minus1" ); + int signalledTileGroupIdLength = pcPPS->getSignalledSliceIdLengthMinus1() + 1; + int numTileGroupsInPic = pcPPS->getNumSlicesInPicMinus1() + 1; + for (int i = 0; i < numTileGroupsInPic; ++i) + { + WRITE_CODE (pcPPS->getSliceId(i), signalledTileGroupIdLength, "slice_id" ); + } + } + } +#endif + + +#if !JVET_N0857_TILES_BRICKS WRITE_FLAG( pcPPS->getTilesEnabledFlag() ? 1 : 0, "tiles_enabled_flag" ); - WRITE_FLAG( pcPPS->getEntropyCodingSyncEnabledFlag() ? 1 : 0, "entropy_coding_sync_enabled_flag" ); if( pcPPS->getTilesEnabledFlag() ) { WRITE_UVLC( pcPPS->getNumTileColumnsMinus1(), "num_tile_columns_minus1" ); WRITE_UVLC( pcPPS->getNumTileRowsMinus1(), "num_tile_rows_minus1" ); - WRITE_FLAG( pcPPS->getTileUniformSpacingFlag(), "uniform_spacing_flag" ); - if( !pcPPS->getTileUniformSpacingFlag() ) + WRITE_FLAG( pcPPS->getUniformTileSpacingFlag(), "uniform_spacing_flag" ); + if( !pcPPS->getUniformTileSpacingFlag() ) { for(uint32_t i=0; i<pcPPS->getNumTileColumnsMinus1(); i++) { @@ -266,9 +371,12 @@ void HLSWriter::codePPS( const PPS* pcPPS ) } } CHECK ((pcPPS->getNumTileColumnsMinus1() + pcPPS->getNumTileRowsMinus1()) == 0, "Invalid tile parameters read"); - WRITE_FLAG( pcPPS->getLoopFilterAcrossTilesEnabledFlag()?1 : 0, "loop_filter_across_tiles_enabled_flag"); + WRITE_FLAG( pcPPS->getLoopFilterAcrossBricksEnabledFlag()?1 : 0, "loop_filter_across_tiles_enabled_flag"); } WRITE_FLAG( pcPPS->getLoopFilterAcrossSlicesEnabledFlag()?1 : 0, "pps_loop_filter_across_slices_enabled_flag"); +#endif + WRITE_FLAG( pcPPS->getEntropyCodingSyncEnabledFlag() ? 1 : 0, "entropy_coding_sync_enabled_flag" ); + WRITE_FLAG( pcPPS->getDeblockingFilterControlPresentFlag()?1 : 0, "deblocking_filter_control_present_flag"); if(pcPPS->getDeblockingFilterControlPresentFlag()) { @@ -1127,7 +1235,11 @@ void HLSWriter::codeSliceHeader ( Slice* pcSlice ) #endif //write slice address +#if JVET_N0857_TILES_BRICKS + const int sliceSegmentRsAddress = pcSlice->getPic()->brickMap->getCtuBsToRsAddrMap(ctuTsAddress); +#else const int sliceSegmentRsAddress = pcSlice->getPic()->tileMap->getCtuTsToRsAddrMap(ctuTsAddress); +#endif WRITE_FLAG( sliceSegmentRsAddress==0, "first_slice_segment_in_pic_flag" ); if ( pcSlice->getRapPicFlag() ) @@ -1752,7 +1864,11 @@ void HLSWriter::codeProfileTier( const ProfileTierLevel* ptl, const bool /*bIsSu */ void HLSWriter::codeTilesWPPEntryPoint( Slice* pSlice ) { +#if !JVET_N0857_TILES_BRICKS if (!pSlice->getPPS()->getTilesEnabledFlag() && !pSlice->getPPS()->getEntropyCodingSyncEnabledFlag()) +#else + if (pSlice->getPPS()->getSingleTileInPicFlag() && !pSlice->getPPS()->getEntropyCodingSyncEnabledFlag()) +#endif { return; }