From fe02142cd0e9e27eaeba2270ca41f021108d3f8a Mon Sep 17 00:00:00 2001 From: Karsten Suehring <karsten.suehring@hhi.fraunhofer.de> Date: Sun, 12 Apr 2020 12:07:08 +0200 Subject: [PATCH] Bugfix: initialization of slice map from subpicture layout (bug ids #1005, #1006, #1007) - initialize slice map from subpicture map - encoder support for inferring slice map from subpicture map - improve software manual --- doc/software-manual.tex | 101 ++++++++--- source/App/EncoderApp/EncAppCfg.cpp | 271 ++++++++++++++-------------- source/App/EncoderApp/EncAppCfg.h | 1 - source/Lib/CommonLib/Slice.cpp | 174 ++++++++++++------ source/Lib/CommonLib/Slice.h | 2 +- source/Lib/DecoderLib/VLCReader.cpp | 7 +- source/Lib/EncoderLib/EncLib.cpp | 5 +- 7 files changed, 334 insertions(+), 227 deletions(-) diff --git a/doc/software-manual.tex b/doc/software-manual.tex index 99f1f3b45..4a5521da6 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -1082,24 +1082,6 @@ Specifies the value of one_subpic_per_pic_constraint_flag Specifies the value of general_frame_only_constraint_flag \\ -\Option{SubPicInfoPresentFlag} & -%\ShortOption{\None} & -\Default{false} & -Specifies the value of subpicture subpic_info_present_flag -\\ - -\Option{SubPicIdMappingExplicitlySignalledFlag} & -%\ShortOption{\None} & -\Default{false} & -Specifies the value of subpicture subpic_id_mapping_explicitly_signalled_flag -\\ - -\Option{SubPicIdMappingInSpsFlag} & -%\ShortOption{\None} & -\Default{false} & -Specifies the value of subpicture subpic_id_mapping_in_sps_flag -\\ - \end{OptionTableNoShorthand} @@ -1991,6 +1973,12 @@ Tile row heights in units of CTUs. Last row height in list will be repeated unif Use raster-scan or rectangular slices (0: rectangular, 1: raster-scan). \\ +\Option{SingleSlicePerSubpic} & +%\ShortOption{\None} & +\Default{false} & +Enables slice layout derivation from subpicture layout. Requires more than one subpicture to be enabled. If enabled, all other slice layout parameters will be ignored. +\\ + \Option{RectSlicePositions} & %\ShortOption{\None} & \Default{\NotSet} & @@ -2051,16 +2039,83 @@ Note that when a slice contains more than one tile, entry point offsets for tile \end{OptionTableNoShorthand} %% -%% Slice/Sub-Picture coding parameters +%% Subpicture coding parameters %% -\begin{OptionTableNoShorthand}{Slice and Sub-Picture coding parameters}{tab:subpicture-coding} +\begin{OptionTableNoShorthand}{Subpicture coding parameters}{tab:subpicture-coding} -\Option{EnableSubPicPartitioning} & +\Option{SubPicInfoPresentFlag} & %\ShortOption{\None} & -\Default{1} & -Enable Sub Picture partitioning (0: single slice per sub-picture, 1: multiple slices per sub-picture can be used). +\Default{false} & +Enables conding of subpictures. \\ +\Option{NumSubPics} & +%\ShortOption{\None} & +\Default{0} & +Number of subpictures. Must be greater that zero, if SubPicInfoPresentFlag is enabled. +\\ + +\Option{SubPicCtuTopLeftX} & +%\ShortOption{\None} & +\Default{\None} & +Array of subpicture top left horizontal (x) coordinates. The number of entries must be equal to NumSubPics. +\\ + +\Option{SubPicCtuTopLeftY} & +%\ShortOption{\None} & +\Default{\None} & +Array of subpicture top left vertical (y) coordinates. The number of entries must be equal to NumSubPics. +\\ + +\Option{SubPicWidth} & +%\ShortOption{\None} & +\Default{\None} & +Array of subpicture widths. The number of entries must be equal to NumSubPics. +\\ + +\Option{SubPicHeight} & +%\ShortOption{\None} & +\Default{\None} & +Array of subpicture heights. The number of entries must be equal to NumSubPics. +\\ + +\Option{SubPicTreatedAsPicFlag} & +%\ShortOption{\None} & +\Default{\None} & +Setting of subpic_treated_as_pic_flag for each subpicture. If enabled subpicture boundaries will be treated as picture boundaries. The number of entries must be equal to NumSubPics. +\\ + +\Option{LoopFilterAcrossSubpicEnabledFlag} & +%\ShortOption{\None} & +\Default{\None} & +Enables loop filtering across subpicture boundaries for each subpicture. The number of entries must be equal to NumSubPics. +\\ + +\Option{SubPicIdMappingExplicitlySignalledFlag} & +%\ShortOption{\None} & +\Default{false} & +Enables explicit signalling of a subpicture ID map. If disabled, a default map will be derived. +\\ + +\Option{SubPicIdMappingInSpsFlag} & +%\ShortOption{\None} & +\Default{false} & +Specifies wheter to signal the subpicture ID map in SPS or PPS. If SubPicIdMappingInSpsFlag is enabled subpicture IDs are signalled in SPS, otherwise in PPS. +\\ + +\Option{SubPicIdLen} & +%\ShortOption{\None} & +\Default{0} & +Length of the subpicture IDs in bits. (1<<SubPicIdLen) must be bigger than the number of subpictures and the highes subpicture ID specifid in SubPicId. +\\ + +\Option{SubPicId} & +%\ShortOption{\None} & +\Default{\None} & +Array of subpicture IDs. The number of entries must be equal to NumSubPics. +\\ + + \end{OptionTableNoShorthand} %% diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index cd1e4e43b..087269d5c 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -909,6 +909,7 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) #endif ("SubPicIdLen", m_subPicIdLen, 0u, "specifies the number of bits used to represent the syntax element sps_subpic_id[ i ]. ") ("SubPicId", cfg_subPicId, cfg_subPicId, "specifies that subpicture ID of the i-th subpicture") + ("SingleSlicePerSubpic", m_singleSlicePerSubPicFlag, false, "Enables setting of a single slice per sub-picture (no explicit configuration required)") ("EnablePartitionConstraintsOverride", m_SplitConsOverrideEnabledFlag, true, "Enable partition constraints override") ("MinQTISlice", m_uiMinQT[0], 8u, "MinQTISlice") ("MinQTLumaISlice", m_uiMinQT[0], 8u, "MinQTLumaISlice") @@ -1197,7 +1198,6 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("RasterSliceSizes", cfgRasterSliceSize, cfgRasterSliceSize, "Raster-scan slice sizes in units of tiles. Last size in list will be repeated uniformly to cover any remaining tiles in the picture") ("DisableLoopFilterAcrossTiles", m_disableLFCrossTileBoundaryFlag, false, "Loop filtering applied across tile boundaries or not (0: filter across tile boundaries 1: do not filter across tile boundaries)") ("DisableLoopFilterAcrossSlices", m_disableLFCrossSliceBoundaryFlag, false, "Loop filtering applied across slice boundaries or not (0: filter across slice boundaries 1: do not filter across slice boundaries)") - ("EnableSubPicPartitioning", m_subPicPartitionFlag, true, "Enable Sub-Picture partitioning (0: single slice per sub-picture, 1: multiple slices per sub-picture can be used)") ("FastUDIUseMPMEnabled", m_bFastUDIUseMPMEnabled, true, "If enabled, adapt intra direction search, accounting for MPM") ("FastMEForGenBLowDelayEnabled", m_bFastMEForGenBLowDelayEnabled, true, "If enabled use a fast ME for generalised B Low Delay slices") ("UseBLambdaForNonKeyLowDelayPictures", m_bUseBLambdaForNonKeyLowDelayPictures, true, "Enables use of B-Lambda for non-key low-delay pictures") @@ -1783,14 +1783,6 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) { m_subProfile[i] = cfg_SubProfile.values[i]; } - if (m_subPicPartitionFlag) - { - m_singleSlicePerSubPicFlag = false; - } - else - { - m_singleSlicePerSubPicFlag = true; - } /* rules for input, output and internal bitdepths as per help text */ if (m_MSBExtendedBitDepth[CHANNEL_TYPE_LUMA ] == 0) { @@ -3387,155 +3379,162 @@ bool EncAppCfg::xCheckParameter() // rectangular slices if( !m_rasterSliceFlag ) { - uint32_t sliceIdx; - bool needTileIdxDelta = false; - - // generate slice list for the simplified fixed-rectangular-slice-size config option - if( m_rectSliceFixedWidth > 0 && m_rectSliceFixedHeight > 0 ) + if (m_singleSlicePerSubPicFlag) { - int tileIdx = 0; - m_rectSlicePos.clear(); - while( tileIdx < pps.getNumTiles() ) - { - uint32_t startTileX = tileIdx % pps.getNumTileColumns(); - uint32_t startTileY = tileIdx / pps.getNumTileColumns(); - uint32_t startCtuX = pps.getTileColumnBd( startTileX ); - uint32_t startCtuY = pps.getTileRowBd( startTileY ); - uint32_t stopCtuX = (startTileX + m_rectSliceFixedWidth) >= pps.getNumTileColumns() ? pps.getPicWidthInCtu() - 1 : pps.getTileColumnBd( startTileX + m_rectSliceFixedWidth ) - 1; - uint32_t stopCtuY = (startTileY + m_rectSliceFixedHeight) >= pps.getNumTileRows() ? pps.getPicHeightInCtu() - 1 : pps.getTileRowBd( startTileY + m_rectSliceFixedHeight ) - 1; - uint32_t stopTileX = pps.ctuToTileCol( stopCtuX ); - uint32_t stopTileY = pps.ctuToTileRow( stopCtuY ); - - // add rectangular slice to list - m_rectSlicePos.push_back( startCtuY * pps.getPicWidthInCtu() + startCtuX ); - m_rectSlicePos.push_back( stopCtuY * pps.getPicWidthInCtu() + stopCtuX ); - - // get slice size in tiles - uint32_t sliceWidth = stopTileX - startTileX + 1; - uint32_t sliceHeight = stopTileY - startTileY + 1; + xConfirmPara( m_subPicInfoPresentFlag == 0 || m_numSubPics < 2, "SingleSlicePerSubPic requires more than one subpicture."); + } + else + { + uint32_t sliceIdx; + bool needTileIdxDelta = false; - // move to next tile in raster scan order - tileIdx += sliceWidth; - if( tileIdx % pps.getNumTileColumns() == 0 ) + // generate slice list for the simplified fixed-rectangular-slice-size config option + if( m_rectSliceFixedWidth > 0 && m_rectSliceFixedHeight > 0 ) + { + int tileIdx = 0; + m_rectSlicePos.clear(); + while( tileIdx < pps.getNumTiles() ) { - tileIdx += (sliceHeight - 1) * pps.getNumTileColumns(); + uint32_t startTileX = tileIdx % pps.getNumTileColumns(); + uint32_t startTileY = tileIdx / pps.getNumTileColumns(); + uint32_t startCtuX = pps.getTileColumnBd( startTileX ); + uint32_t startCtuY = pps.getTileRowBd( startTileY ); + uint32_t stopCtuX = (startTileX + m_rectSliceFixedWidth) >= pps.getNumTileColumns() ? pps.getPicWidthInCtu() - 1 : pps.getTileColumnBd( startTileX + m_rectSliceFixedWidth ) - 1; + uint32_t stopCtuY = (startTileY + m_rectSliceFixedHeight) >= pps.getNumTileRows() ? pps.getPicHeightInCtu() - 1 : pps.getTileRowBd( startTileY + m_rectSliceFixedHeight ) - 1; + uint32_t stopTileX = pps.ctuToTileCol( stopCtuX ); + uint32_t stopTileY = pps.ctuToTileRow( stopCtuY ); + + // add rectangular slice to list + m_rectSlicePos.push_back( startCtuY * pps.getPicWidthInCtu() + startCtuX ); + m_rectSlicePos.push_back( stopCtuY * pps.getPicWidthInCtu() + stopCtuX ); + + // get slice size in tiles + uint32_t sliceWidth = stopTileX - startTileX + 1; + uint32_t sliceHeight = stopTileY - startTileY + 1; + + // move to next tile in raster scan order + tileIdx += sliceWidth; + if( tileIdx % pps.getNumTileColumns() == 0 ) + { + tileIdx += (sliceHeight - 1) * pps.getNumTileColumns(); + } } } - } - xConfirmPara( m_rectSlicePos.size() & 1, "Odd number of rectangular slice positions provided. Rectangular slice positions must be specified in pairs of (top-left / bottom-right) raster-scan CTU addresses."); - - // set default slice size if not provided - if( m_rectSlicePos.size() == 0 ) - { - m_rectSlicePos.push_back( 0 ); - m_rectSlicePos.push_back( pps.getPicWidthInCtu() * pps.getPicHeightInCtu() - 1 ); - } - pps.setNumSlicesInPic( (uint32_t)(m_rectSlicePos.size() >> 1) ); - xConfirmPara(pps.getNumSlicesInPic() > getMaxSlicesByLevel( m_level ), "Number of rectangular slices exceeds maximum number allowed according to specified level"); - pps.initRectSlices(); + xConfirmPara( m_rectSlicePos.size() & 1, "Odd number of rectangular slice positions provided. Rectangular slice positions must be specified in pairs of (top-left / bottom-right) raster-scan CTU addresses."); - // set slice parameters from CTU addresses - for( sliceIdx = 0; sliceIdx < pps.getNumSlicesInPic(); sliceIdx++ ) - { - xConfirmPara( m_rectSlicePos[2*sliceIdx] >= pps.getPicWidthInCtu() * pps.getPicHeightInCtu(), "Rectangular slice position exceeds total number of CTU in picture."); - xConfirmPara( m_rectSlicePos[2*sliceIdx + 1] >= pps.getPicWidthInCtu() * pps.getPicHeightInCtu(), "Rectangular slice position exceeds total number of CTU in picture."); - - // map raster scan CTU address to X/Y position - uint32_t startCtuX = m_rectSlicePos[2*sliceIdx] % pps.getPicWidthInCtu(); - uint32_t startCtuY = m_rectSlicePos[2*sliceIdx] / pps.getPicWidthInCtu(); - uint32_t stopCtuX = m_rectSlicePos[2*sliceIdx + 1] % pps.getPicWidthInCtu(); - uint32_t stopCtuY = m_rectSlicePos[2*sliceIdx + 1] / pps.getPicWidthInCtu(); - - // get corresponding tile index - uint32_t startTileX = pps.ctuToTileCol( startCtuX ); - uint32_t startTileY = pps.ctuToTileRow( startCtuY ); - uint32_t stopTileX = pps.ctuToTileCol( stopCtuX ); - uint32_t stopTileY = pps.ctuToTileRow( stopCtuY ); - uint32_t tileIdx = startTileY * pps.getNumTileColumns() + startTileX; - - // get slice size in tiles - uint32_t sliceWidth = stopTileX - startTileX + 1; - uint32_t sliceHeight = stopTileY - startTileY + 1; - - // check for slice / tile alignment - xConfirmPara( startCtuX != pps.getTileColumnBd( startTileX ), "Rectangular slice position does not align with a left tile edge."); - xConfirmPara( stopCtuX != (pps.getTileColumnBd( stopTileX + 1 ) - 1), "Rectangular slice position does not align with a right tile edge."); - if( sliceWidth > 1 || sliceHeight > 1 ) + // set default slice size if not provided + if( m_rectSlicePos.size() == 0 ) { - xConfirmPara( startCtuY != pps.getTileRowBd( startTileY ), "Rectangular slice position does not align with a top tile edge."); - xConfirmPara( stopCtuY != (pps.getTileRowBd( stopTileY + 1 ) - 1), "Rectangular slice position does not align with a bottom tile edge."); + m_rectSlicePos.push_back( 0 ); + m_rectSlicePos.push_back( pps.getPicWidthInCtu() * pps.getPicHeightInCtu() - 1 ); } + pps.setNumSlicesInPic( (uint32_t)(m_rectSlicePos.size() >> 1) ); + xConfirmPara(pps.getNumSlicesInPic() > getMaxSlicesByLevel( m_level ), "Number of rectangular slices exceeds maximum number allowed according to specified level"); + pps.initRectSlices(); - // set slice size and tile index - pps.setSliceWidthInTiles( sliceIdx, sliceWidth ); - pps.setSliceHeightInTiles( sliceIdx, sliceHeight ); - pps.setSliceTileIdx( sliceIdx, tileIdx ); - if( sliceIdx > 0 && !needTileIdxDelta ) + // set slice parameters from CTU addresses + for( sliceIdx = 0; sliceIdx < pps.getNumSlicesInPic(); sliceIdx++ ) { - uint32_t lastTileIdx = pps.getSliceTileIdx( sliceIdx-1 ); - lastTileIdx += pps.getSliceWidthInTiles( sliceIdx-1 ); - if( lastTileIdx % pps.getNumTileColumns() == 0) + xConfirmPara( m_rectSlicePos[2*sliceIdx] >= pps.getPicWidthInCtu() * pps.getPicHeightInCtu(), "Rectangular slice position exceeds total number of CTU in picture."); + xConfirmPara( m_rectSlicePos[2*sliceIdx + 1] >= pps.getPicWidthInCtu() * pps.getPicHeightInCtu(), "Rectangular slice position exceeds total number of CTU in picture."); + + // map raster scan CTU address to X/Y position + uint32_t startCtuX = m_rectSlicePos[2*sliceIdx] % pps.getPicWidthInCtu(); + uint32_t startCtuY = m_rectSlicePos[2*sliceIdx] / pps.getPicWidthInCtu(); + uint32_t stopCtuX = m_rectSlicePos[2*sliceIdx + 1] % pps.getPicWidthInCtu(); + uint32_t stopCtuY = m_rectSlicePos[2*sliceIdx + 1] / pps.getPicWidthInCtu(); + + // get corresponding tile index + uint32_t startTileX = pps.ctuToTileCol( startCtuX ); + uint32_t startTileY = pps.ctuToTileRow( startCtuY ); + uint32_t stopTileX = pps.ctuToTileCol( stopCtuX ); + uint32_t stopTileY = pps.ctuToTileRow( stopCtuY ); + uint32_t tileIdx = startTileY * pps.getNumTileColumns() + startTileX; + + // get slice size in tiles + uint32_t sliceWidth = stopTileX - startTileX + 1; + uint32_t sliceHeight = stopTileY - startTileY + 1; + + // check for slice / tile alignment + xConfirmPara( startCtuX != pps.getTileColumnBd( startTileX ), "Rectangular slice position does not align with a left tile edge."); + xConfirmPara( stopCtuX != (pps.getTileColumnBd( stopTileX + 1 ) - 1), "Rectangular slice position does not align with a right tile edge."); + if( sliceWidth > 1 || sliceHeight > 1 ) { - lastTileIdx += (pps.getSliceHeightInTiles( sliceIdx-1 ) - 1) * pps.getNumTileColumns(); + xConfirmPara( startCtuY != pps.getTileRowBd( startTileY ), "Rectangular slice position does not align with a top tile edge."); + xConfirmPara( stopCtuY != (pps.getTileRowBd( stopTileY + 1 ) - 1), "Rectangular slice position does not align with a bottom tile edge."); } - if( lastTileIdx != tileIdx ) + + // set slice size and tile index + pps.setSliceWidthInTiles( sliceIdx, sliceWidth ); + pps.setSliceHeightInTiles( sliceIdx, sliceHeight ); + pps.setSliceTileIdx( sliceIdx, tileIdx ); + if( sliceIdx > 0 && !needTileIdxDelta ) { - needTileIdxDelta = true; + uint32_t lastTileIdx = pps.getSliceTileIdx( sliceIdx-1 ); + lastTileIdx += pps.getSliceWidthInTiles( sliceIdx-1 ); + if( lastTileIdx % pps.getNumTileColumns() == 0) + { + lastTileIdx += (pps.getSliceHeightInTiles( sliceIdx-1 ) - 1) * pps.getNumTileColumns(); + } + if( lastTileIdx != tileIdx ) + { + needTileIdxDelta = true; + } } - } - // special case for multiple slices within a single tile - if( sliceWidth == 1 && sliceHeight == 1 ) - { - uint32_t firstSliceIdx = sliceIdx; - uint32_t numSlicesInTile = 1; - pps.setSliceHeightInCtu( sliceIdx, stopCtuY - startCtuY + 1 ); - - while( sliceIdx < pps.getNumSlicesInPic()-1 ) + // special case for multiple slices within a single tile + if( sliceWidth == 1 && sliceHeight == 1 ) { - uint32_t nextTileIdx; - startCtuX = m_rectSlicePos[2*(sliceIdx+1)] % pps.getPicWidthInCtu(); - startCtuY = m_rectSlicePos[2*(sliceIdx+1)] / pps.getPicWidthInCtu(); - stopCtuX = m_rectSlicePos[2*(sliceIdx+1) + 1] % pps.getPicWidthInCtu(); - stopCtuY = m_rectSlicePos[2*(sliceIdx+1) + 1] / pps.getPicWidthInCtu(); - startTileX = pps.ctuToTileCol( startCtuX ); - startTileY = pps.ctuToTileRow( startCtuY ); - stopTileX = pps.ctuToTileCol( stopCtuX ); - stopTileY = pps.ctuToTileRow( stopCtuY ); - nextTileIdx = startTileY * pps.getNumTileColumns() + startTileX; - sliceWidth = stopTileX - startTileX + 1; - sliceHeight = stopTileY - startTileY + 1; - if(nextTileIdx != tileIdx || sliceWidth != 1 || sliceHeight != 1) + uint32_t firstSliceIdx = sliceIdx; + uint32_t numSlicesInTile = 1; + pps.setSliceHeightInCtu( sliceIdx, stopCtuY - startCtuY + 1 ); + + while( sliceIdx < pps.getNumSlicesInPic()-1 ) { - break; + uint32_t nextTileIdx; + startCtuX = m_rectSlicePos[2*(sliceIdx+1)] % pps.getPicWidthInCtu(); + startCtuY = m_rectSlicePos[2*(sliceIdx+1)] / pps.getPicWidthInCtu(); + stopCtuX = m_rectSlicePos[2*(sliceIdx+1) + 1] % pps.getPicWidthInCtu(); + stopCtuY = m_rectSlicePos[2*(sliceIdx+1) + 1] / pps.getPicWidthInCtu(); + startTileX = pps.ctuToTileCol( startCtuX ); + startTileY = pps.ctuToTileRow( startCtuY ); + stopTileX = pps.ctuToTileCol( stopCtuX ); + stopTileY = pps.ctuToTileRow( stopCtuY ); + nextTileIdx = startTileY * pps.getNumTileColumns() + startTileX; + sliceWidth = stopTileX - startTileX + 1; + sliceHeight = stopTileY - startTileY + 1; + if(nextTileIdx != tileIdx || sliceWidth != 1 || sliceHeight != 1) + { + break; + } + numSlicesInTile++; + sliceIdx++; + pps.setSliceWidthInTiles( sliceIdx, 1 ); + pps.setSliceHeightInTiles( sliceIdx, 1 ); + pps.setSliceTileIdx( sliceIdx, tileIdx ); + pps.setSliceHeightInCtu( sliceIdx, stopCtuY - startCtuY + 1 ); } - numSlicesInTile++; - sliceIdx++; - pps.setSliceWidthInTiles( sliceIdx, 1 ); - pps.setSliceHeightInTiles( sliceIdx, 1 ); - pps.setSliceTileIdx( sliceIdx, tileIdx ); - pps.setSliceHeightInCtu( sliceIdx, stopCtuY - startCtuY + 1 ); + pps.setNumSlicesInTile( firstSliceIdx, numSlicesInTile ); } - pps.setNumSlicesInTile( firstSliceIdx, numSlicesInTile ); } - } - pps.setTileIdxDeltaPresentFlag( needTileIdxDelta ); - m_tileIdxDeltaPresentFlag = needTileIdxDelta; - - // check rectangular slice mapping and full picture CTU coverage - pps.initRectSliceMap(); + pps.setTileIdxDeltaPresentFlag( needTileIdxDelta ); + m_tileIdxDeltaPresentFlag = needTileIdxDelta; - // store rectangular slice parameters from temporary PPS structure - m_numSlicesInPic = pps.getNumSlicesInPic(); - m_rectSlices.resize( pps.getNumSlicesInPic() ); - for( sliceIdx = 0; sliceIdx < pps.getNumSlicesInPic(); sliceIdx++ ) - { - m_rectSlices[sliceIdx].setSliceWidthInTiles( pps.getSliceWidthInTiles(sliceIdx) ); - m_rectSlices[sliceIdx].setSliceHeightInTiles( pps.getSliceHeightInTiles(sliceIdx) ); - m_rectSlices[sliceIdx].setNumSlicesInTile( pps.getNumSlicesInTile(sliceIdx) ); - m_rectSlices[sliceIdx].setSliceHeightInCtu( pps.getSliceHeightInCtu(sliceIdx) ); - m_rectSlices[sliceIdx].setTileIdx( pps.getSliceTileIdx(sliceIdx) ); + // check rectangular slice mapping and full picture CTU coverage + pps.initRectSliceMap(nullptr); + + // store rectangular slice parameters from temporary PPS structure + m_numSlicesInPic = pps.getNumSlicesInPic(); + m_rectSlices.resize( pps.getNumSlicesInPic() ); + for( sliceIdx = 0; sliceIdx < pps.getNumSlicesInPic(); sliceIdx++ ) + { + m_rectSlices[sliceIdx].setSliceWidthInTiles( pps.getSliceWidthInTiles(sliceIdx) ); + m_rectSlices[sliceIdx].setSliceHeightInTiles( pps.getSliceHeightInTiles(sliceIdx) ); + m_rectSlices[sliceIdx].setNumSlicesInTile( pps.getNumSlicesInTile(sliceIdx) ); + m_rectSlices[sliceIdx].setSliceHeightInCtu( pps.getSliceHeightInCtu(sliceIdx) ); + m_rectSlices[sliceIdx].setTileIdx( pps.getSliceTileIdx(sliceIdx) ); + } } } // raster-scan slices diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 9897961ac..197ebafd8 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -499,7 +499,6 @@ protected: std::vector<RectSlice> m_rectSlices; ///< derived list of rectangular slice signalling parameters uint32_t m_numTileCols; ///< derived number of tile columns uint32_t m_numTileRows; ///< derived number of tile rows - bool m_subPicPartitionFlag; bool m_singleSlicePerSubPicFlag; bool m_entropyCodingSyncEnabledFlag; #if JVET_Q0151_Q0205_ENTRYPOINTS diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index 75ad5e25a..d213a2821 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -2938,7 +2938,7 @@ PPS::PPS() , m_numTileCols (1) , m_numTileRows (1) , m_rectSliceFlag (1) - , m_singleSlicePerSubPicFlag (0) +, m_singleSlicePerSubPicFlag (0) , m_numSlicesInPic (1) , m_tileIdxDeltaPresentFlag (0) , m_loopFilterAcrossTilesEnabledFlag (1) @@ -3138,89 +3138,143 @@ void PPS::initRectSlices() /** - initialize mapping between rectangular slices and CTUs */ -void PPS::initRectSliceMap() +void PPS::initRectSliceMap(const SPS *sps) { uint32_t ctuY; uint32_t tileX, tileY; - - // allocate new memory for slice list - CHECK(m_numSlicesInPic > MAX_SLICES, "Number of slices in picture exceeds valid range"); - m_sliceMap.resize( m_numSlicesInPic ); -#if JVET_Q0817 - if( getSingleSlicePerSubPicFlag() ) - { -#else - if ((getNumSubPics() > 0) && getSingleSlicePerSubPicFlag()) + + if (sps) { -#endif - for (uint32_t i = 0; i <= getNumSubPics() - 1; i++) + m_ctuToSubPicIdx.resize(getPicWidthInCtu() * getPicHeightInCtu()); + if (sps->getNumSubPics() > 1) { - m_sliceMap[i].initSliceMap(); + for (int i = 0; i <= sps->getNumSubPics() - 1; i++) + { + for (int y = sps->getSubPicCtuTopLeftY(i); y < sps->getSubPicCtuTopLeftY(i) + sps->getSubPicHeight(i); y++) + { + for (int x = sps->getSubPicCtuTopLeftX(i); x < sps->getSubPicCtuTopLeftX(i) + sps->getSubPicWidth(i); x++) + { + m_ctuToSubPicIdx[ x+ y * getPicWidthInCtu()] = i; + } + } + } } - uint32_t picSizeInCtu = getPicWidthInCtu() * getPicHeightInCtu(); - uint32_t sliceIdx; - for (uint32_t i = 0; i < picSizeInCtu; i++) + else { - sliceIdx = getCtuToSubPicIdx(i); - m_sliceMap[sliceIdx].pushToCtuAddrInSlice(i); + for (int i = 0; i < getPicWidthInCtu() * getPicHeightInCtu(); i++) + { + m_ctuToSubPicIdx[i] = 0; + } } } - else - { - // generate CTU maps for all rectangular slices in picture - for( uint32_t i = 0; i < m_numSlicesInPic; i++ ) + +#if JVET_Q0817 + if( getSingleSlicePerSubPicFlag() ) +#else + if ((getNumSubPics() > 0) && getSingleSlicePerSubPicFlag()) +#endif { - m_sliceMap[ i ].initSliceMap(); + CHECK (sps==nullptr, "RectSliceMap can only be initialized for slice_per_sub_pic_flag with a valid SPS"); + m_numSlicesInPic = sps->getNumSubPics(); - // get position of first tile in slice - tileX = m_rectSlices[ i ].getTileIdx() % m_numTileCols; - tileY = m_rectSlices[ i ].getTileIdx() / m_numTileCols; + // allocate new memory for slice list + CHECK(m_numSlicesInPic > MAX_SLICES, "Number of slices in picture exceeds valid range"); + m_sliceMap.resize( m_numSlicesInPic ); - // infer slice size for last slice in picture - if( i == m_numSlicesInPic-1 ) + for( int i = 0; i < m_numSlicesInPic; i++ ) { - m_rectSlices[ i ].setSliceWidthInTiles ( m_numTileCols - tileX ); - m_rectSlices[ i ].setSliceHeightInTiles( m_numTileRows - tileY ); - m_rectSlices[ i ].setNumSlicesInTile( 1 ); + m_sliceMap[ i ].initSliceMap(); } - - // set slice index - m_sliceMap[ i ].setSliceID(i); - - // complete tiles within a single slice case - if( m_rectSlices[ i ].getSliceWidthInTiles( ) > 1 || m_rectSlices[ i ].getSliceHeightInTiles( ) > 1) + for (int row = 0; row < m_numTileRows; row++) { - for( uint32_t j = 0; j < m_rectSlices[ i ].getSliceHeightInTiles( ); j++ ) + for (int col = 0; col < m_numTileCols; col++) { - for( uint32_t k = 0; k < m_rectSlices[ i ].getSliceWidthInTiles( ); k++ ) + const int tileTopLeftCtu = getTileColumnBd(col) + getTileRowBd(row) * getPicWidthInCtu(); + const int sliceIdx = getCtuToSubPicIdx(tileTopLeftCtu); + const int tileSizeInCtus = (getTileColumnBd(col + 1) - getTileColumnBd(col)) * (getTileRowBd(row + 1) - getTileRowBd(row)); + const int subPicSizeInCtus = sps->getSubPicHeight(sliceIdx) * sps->getSubPicWidth(sliceIdx); + if (subPicSizeInCtus >= tileSizeInCtus) + { + m_sliceMap[sliceIdx].addCtusToSlice(getTileColumnBd(col), getTileColumnBd(col + 1), + getTileRowBd(row), getTileRowBd(row + 1), m_picWidthInCtu); + } + else { - m_sliceMap[ i ].addCtusToSlice( getTileColumnBd(tileX + k), getTileColumnBd(tileX + k +1), - getTileRowBd(tileY + j), getTileRowBd(tileY + j +1), m_picWidthInCtu); + int sliceIdxInTile = sliceIdx; + do + { + // subpicture vertical boundary must be a tile boundary, so tile column parameter doesn't change + m_sliceMap[sliceIdxInTile].addCtusToSlice(getTileColumnBd(col), getTileColumnBd(col + 1), + sps->getSubPicCtuTopLeftY(sliceIdxInTile), sps->getSubPicCtuTopLeftY(sliceIdxInTile) + sps->getSubPicHeight(sliceIdxInTile), m_picWidthInCtu); + sliceIdxInTile++; + if (sliceIdxInTile == sps->getNumSubPics()) + { + break; + } + } while (sps->getSubPicCtuTopLeftY(sliceIdxInTile) < getTileRowBd(row + 1)); } } - } - // multiple slices within a single tile case - else + } + } + else + { + // allocate new memory for slice list + CHECK(m_numSlicesInPic > MAX_SLICES, "Number of slices in picture exceeds valid range"); + m_sliceMap.resize( m_numSlicesInPic ); + // generate CTU maps for all rectangular slices in picture + for( uint32_t i = 0; i < m_numSlicesInPic; i++ ) { - uint32_t numSlicesInTile = m_rectSlices[ i ].getNumSlicesInTile( ); + m_sliceMap[ i ].initSliceMap(); - ctuY = getTileRowBd( tileY ); - for( uint32_t j = 0; j < numSlicesInTile-1; j++ ) + // get position of first tile in slice + tileX = m_rectSlices[ i ].getTileIdx() % m_numTileCols; + tileY = m_rectSlices[ i ].getTileIdx() / m_numTileCols; + + // infer slice size for last slice in picture + if( i == m_numSlicesInPic-1 ) { - m_sliceMap[ i ].addCtusToSlice( getTileColumnBd(tileX), getTileColumnBd(tileX+1), - ctuY, ctuY + m_rectSlices[ i ].getSliceHeightInCtu(), m_picWidthInCtu); - ctuY += m_rectSlices[ i ].getSliceHeightInCtu(); - i++; - m_sliceMap[ i ].setSliceID(i); + m_rectSlices[ i ].setSliceWidthInTiles ( m_numTileCols - tileX ); + m_rectSlices[ i ].setSliceHeightInTiles( m_numTileRows - tileY ); + m_rectSlices[ i ].setNumSlicesInTile( 1 ); } - // infer slice height for last slice in tile - CHECK( ctuY >= getTileRowBd( tileY + 1 ), "Invalid rectangular slice signalling"); - m_rectSlices[ i ].setSliceHeightInCtu( getTileRowBd( tileY + 1 ) - ctuY ); - m_sliceMap[ i ].addCtusToSlice( getTileColumnBd(tileX), getTileColumnBd(tileX+1), - ctuY, getTileRowBd( tileY + 1 ), m_picWidthInCtu); - } - } + // set slice index + m_sliceMap[ i ].setSliceID(i); + + // complete tiles within a single slice case + if( m_rectSlices[ i ].getSliceWidthInTiles( ) > 1 || m_rectSlices[ i ].getSliceHeightInTiles( ) > 1) + { + for( uint32_t j = 0; j < m_rectSlices[ i ].getSliceHeightInTiles( ); j++ ) + { + for( uint32_t k = 0; k < m_rectSlices[ i ].getSliceWidthInTiles( ); k++ ) + { + m_sliceMap[ i ].addCtusToSlice( getTileColumnBd(tileX + k), getTileColumnBd(tileX + k +1), + getTileRowBd(tileY + j), getTileRowBd(tileY + j +1), m_picWidthInCtu); + } + } + } + // multiple slices within a single tile case + else + { + uint32_t numSlicesInTile = m_rectSlices[ i ].getNumSlicesInTile( ); + + ctuY = getTileRowBd( tileY ); + for( uint32_t j = 0; j < numSlicesInTile-1; j++ ) + { + m_sliceMap[ i ].addCtusToSlice( getTileColumnBd(tileX), getTileColumnBd(tileX+1), + ctuY, ctuY + m_rectSlices[ i ].getSliceHeightInCtu(), m_picWidthInCtu); + ctuY += m_rectSlices[ i ].getSliceHeightInCtu(); + i++; + m_sliceMap[ i ].setSliceID(i); + } + + // infer slice height for last slice in tile + CHECK( ctuY >= getTileRowBd( tileY + 1 ), "Invalid rectangular slice signalling"); + m_rectSlices[ i ].setSliceHeightInCtu( getTileRowBd( tileY + 1 ) - ctuY ); + m_sliceMap[ i ].addCtusToSlice( getTileColumnBd(tileX), getTileColumnBd(tileX+1), + ctuY, getTileRowBd( tileY + 1 ), m_picWidthInCtu); + } + } } // check for valid rectangular slice map checkSliceMap(); diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index d5e81aada..334d2c445 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -2295,7 +2295,7 @@ public: void resetTileSliceInfo(); void initTiles(); void initRectSlices(); - void initRectSliceMap(); + void initRectSliceMap(const SPS *sps); #if JVET_O1143_SUBPIC_BOUNDARY std::vector<SubPic> getSubPics() const {return m_subPics; }; #if JVET_Q0044_SLICE_IDX_WITH_SUBPICS diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 4db59237e..5e2b5f95e 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -713,9 +713,6 @@ void HLSyntaxReader::parsePPS( PPS* pcPPS ) } } pcPPS->setSliceTileIdx(pcPPS->getNumSlicesInPic()-1, tileIdx ); - - // initialize mapping between rectangular slices and CTUs - pcPPS->initRectSliceMap(); } // loop filtering across slice/tile controls @@ -3140,6 +3137,7 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag #endif // initialize tile/slice info for no partitioning case + if( pps->getNoPicPartitionFlag() ) { pps->resetTileSliceInfo(); @@ -3154,7 +3152,7 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag pps->initRectSlices( ); pps->setTileIdxDeltaPresentFlag( 0 ); pps->setSliceTileIdx( 0, 0 ); - pps->initRectSliceMap( ); + pps->initRectSliceMap(sps); #if JVET_O1143_SUBPIC_BOUNDARY // when no Pic partition, number of sub picture shall be less than 2 CHECK(pps->getNumSubPics()>=2, "error, no picture partitions, but have equal to or more than 2 sub pictures"); @@ -3163,6 +3161,7 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag else { CHECK(pps->getCtuSize() != sps->getCTUSize(), "PPS CTU size does not match CTU size in SPS"); + pps->initRectSliceMap(sps); } #if JVET_Q0044_SLICE_IDX_WITH_SUBPICS diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index 1c08f782f..28e5ca4a6 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -1871,10 +1871,11 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps) pps.setRectSliceFlag( m_rectSliceFlag ); if( m_rectSliceFlag ) { + pps.setSingleSlicePerSubPicFlag(m_singleSlicePerSubPicFlag); pps.setNumSlicesInPic( m_numSlicesInPic ); pps.setTileIdxDeltaPresentFlag( m_tileIdxDeltaPresentFlag ); pps.setRectSlices( m_rectSlices ); - pps.initRectSliceMap( ); + pps.initRectSliceMap(&sps); #if JVET_O1143_SUBPIC_BOUNDARY pps.initSubPic(sps); #endif @@ -1899,7 +1900,7 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps) pps.initRectSlices( ); pps.setTileIdxDeltaPresentFlag( 0 ); pps.setSliceTileIdx( 0, 0 ); - pps.initRectSliceMap( ); + pps.initRectSliceMap( &sps ); #if JVET_O1143_SUBPIC_BOUNDARY pps.initSubPic(sps); #endif -- GitLab