From 47ff0117bc6bb32ec1dae545202127754636aac8 Mon Sep 17 00:00:00 2001 From: vdrugeon <virginie.drugeon@eu.panasonic.com> Date: Wed, 12 Feb 2020 16:44:37 +0000 Subject: [PATCH] JVET-Q0044: slice index with subpictures --- .../TwoSubpictures_with_EightSlices.cfg | 28 ++++++++++++ source/Lib/CommonLib/Slice.cpp | 43 +++++++++++++++++++ source/Lib/CommonLib/Slice.h | 18 ++++++++ source/Lib/CommonLib/TypeDef.h | 2 + source/Lib/DecoderLib/DecLib.cpp | 29 ++++++++++++- source/Lib/DecoderLib/DecLib.h | 4 ++ source/Lib/DecoderLib/VLCReader.cpp | 24 +++++++++++ source/Lib/EncoderLib/EncGOP.cpp | 17 ++++++++ source/Lib/EncoderLib/EncLib.cpp | 12 ++++++ source/Lib/EncoderLib/VLCWriter.cpp | 15 +++++++ 10 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 cfg/nonCTC-SliceConfigExamples/TwoSubpictures_with_EightSlices.cfg diff --git a/cfg/nonCTC-SliceConfigExamples/TwoSubpictures_with_EightSlices.cfg b/cfg/nonCTC-SliceConfigExamples/TwoSubpictures_with_EightSlices.cfg new file mode 100644 index 000000000..3371a0a7b --- /dev/null +++ b/cfg/nonCTC-SliceConfigExamples/TwoSubpictures_with_EightSlices.cfg @@ -0,0 +1,28 @@ +# example cfg file, assuming an 1920x1080 input sequence with CTU size = 128x128, and split to 8 rectangular slices, 12 tiles and 2 subpictures + +SourceWidth : 1920 +SourceHeight : 1080 + +SubPicInfoPresentFlag : 1 # subpicture information present flag(0: OFF, 1: ON) +NumSubPics : 2 # number of subpictures in a picture +SubPicCtuTopLeftX : 0 11 # specifies horizontal position of top left CTU of i-th subpicture in unit of CtbSizeY +SubPicCtuTopLeftY : 0 0 # specifies vertical position of top left CTU of i-th subpicture in unit of CtbSizeY +SubPicWidth : 11 4 # specifies the width of the i-th subpicture in units of CtbSizeY +SubPicHeight : 9 9 # specifies the height of the i-th subpicture in units of CtbSizeY +SubPicTreatedAsPicFlag : 1 1 # equal to 1 specifies that the i-th subpicture of each coded picture in the CLVS is treated as a picture in the decoding process excluding in-loop filtering operations +LoopFilterAcrossSubpicEnabledFlag : 0 0 # equal to 1 specifies that in-loop filtering operations may be performed across the boundaries of the i-th subpicture in each coded picture in the CLVS +SubPicIdMappingExplicitlySignalledFlag : 0 # equal to 1 specifies that the subpicture ID mapping is explicitly signalled, either in the SPS or in the PPSs + + +#============ Tiles / Slices ================ +EnablePicPartitioning : 1 # Enable picture partitioning (0: single tile, single slice, 1: multiple tiles/slices can be used) + +# 24 tiles and 6 rectangular slices +TileColumnWidthArray : 3 4 # Tile column widths in units of CTUs. Last column width will be repeated uniformly to cover any remaining picture width +TileRowHeightArray : 3 # Tile row heights in units of CTUs. Last row height will be repeated uniformly to cover any remaining picture height +RasterScanSlices : 0 # Raster-scan or rectangular slices (0: rectangular, 1: raster-scan) +RectSliceFixedWidth : 0 # Fixed rectangular slice width in units of tiles (0: disable this feature and use RectSlicePositions instead) +RectSliceFixedHeight : 0 # Fixed rectangular slice height in units of tiles (0: disable this feature and use RectSlicePositions instead) +RectSlicePositions : 0 17 30 32 45 62 75 77 3 85 90 130 11 89 101 134 # Rectangular slices positions - list containing pairs of top-left CTU index and bottom-right CTU index +DisableLoopFilterAcrossTiles : 1 # Loop filtering (DBLK/SAO/ALF) applied across tile boundaries or not (0: filter across tile boundaries 1: do not filter across tile boundaries) +DisableLoopFilterAcrossSlices : 1 # Loop filtering (DBLK/SAO/ALF) applied across slice boundaries or not (0: filter across slice boundaries 1: do not filter across slice boundaries) diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index 19441135d..10a9ed5fb 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -2707,6 +2707,23 @@ void PPS::initSubPic(const SPS &sps) for (int i=0; i< getNumSubPics(); i++) { m_subPics[i].setSubPicIdx(i); +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + if(sps.getSubPicIdMappingExplicitlySignalledFlag()) + { + if(m_subPicIdMappingInPpsFlag) + { + m_subPics[i].setSubPicID(m_subPicId[i]); + } + else + { + m_subPics[i].setSubPicID(sps.getSubPicId(i)); + } + } + else + { + m_subPics[i].setSubPicID(i); + } +#endif m_subPics[i].setSubPicCtuTopLeftX(sps.getSubPicCtuTopLeftX(i)); m_subPics[i].setSubPicCtuTopLeftY(sps.getSubPicCtuTopLeftY(i)); m_subPics[i].setSubPicWidthInCTUs(sps.getSubPicWidth(i)); @@ -2740,9 +2757,15 @@ void PPS::initSubPic(const SPS &sps) { CHECK(getNumSubPics() != 1, "only one slice in picture, but number of subpic is not one"); m_subPics[i].addAllCtusInPicToSubPic(0, getPicWidthInCtu(), 0, getPicHeightInCtu(), getPicWidthInCtu()); +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + m_subPics[i].setNumSlicesInSubPic(1); +#endif } else { +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + int numSlicesInSubPic = 0; +#endif for (int j = 0; j < m_numSlicesInPic; j++) { uint32_t ctu = m_sliceMap[j].getCtuAddrInSlice(0); @@ -2755,8 +2778,14 @@ void PPS::initSubPic(const SPS &sps) { // add ctus in a slice to the subpicture it belongs to m_subPics[i].addCTUsToSubPic(m_sliceMap[j].getCtuAddrList()); +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + numSlicesInSubPic++; +#endif } } +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + m_subPics[i].setNumSlicesInSubPic(numSlicesInSubPic); +#endif } m_subPics[i].setTreatedAsPicFlag(sps.getSubPicTreatedAsPicFlag(i)); m_subPics[i].setloopFilterAcrossEnabledFlag(sps.getLoopFilterAcrossSubpicEnabledFlag(i)); @@ -2782,6 +2811,20 @@ SubPic PPS::getSubPicFromCU(const CodingUnit& cu) const } #endif +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS +uint32_t PPS::getSubPicIdxFromSubPicId( uint32_t subPicId ) const +{ + for (int i = 0; i < m_numSubPics; i++) + { + if(m_subPics[i].getSubPicID() == subPicId) + { + return i; + } + } + return 0; +} +#endif + void PPS::initRasterSliceMap( std::vector<uint32_t> numTilesInSlice ) { uint32_t tileIdx = 0; diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index 9246c7508..9e4602054 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -752,6 +752,9 @@ private: bool m_treatedAsPicFlag; //!< whether the subpicture is treated as a picture in the decoding process excluding in-loop filtering operations bool m_loopFilterAcrossSubPicEnabledFlag; //!< whether in-loop filtering operations may be performed across the boundaries of the subpicture +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + uint32_t m_numSlicesInSubPic; //!< Number of slices contained in this subpicture +#endif public: SubPic(); @@ -818,6 +821,15 @@ public: bool isFirstCTUinSubPic(uint32_t ctuAddr) { return ctuAddr == m_firstCtuInSubPic; } bool isLastCTUinSubPic(uint32_t ctuAddr) { return ctuAddr == m_lastCtuInSubPic; } +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + void setNumSlicesInSubPic( uint32_t val ) { m_numSlicesInSubPic = val; } + uint32_t getNumSlicesInSubPic() const { return m_numSlicesInSubPic; } + bool containsCtu(const Position& pos) const + { + return pos.x >= m_subPicCtuTopLeftX && pos.x < m_subPicCtuTopLeftX + m_subPicWidth && + pos.y >= m_subPicCtuTopLeftY && pos.y < m_subPicCtuTopLeftY + m_subPicHeight; + } +#endif }; #endif class DPS @@ -2013,6 +2025,9 @@ public: uint32_t getSubPicIdLen() const { return m_subPicIdLen; } void setSubPicId( int i, uint8_t u ) { CHECK( i >= MAX_NUM_SUB_PICS, "Sub-picture index exceeds valid range" ); m_subPicId[i] = u; } uint8_t getSubPicId( int i ) const { CHECK( i >= MAX_NUM_SUB_PICS, "Sub-picture index exceeds valid range" ); return m_subPicId[i]; } +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + uint32_t getSubPicIdxFromSubPicId( uint32_t subPicId ) const; +#endif void setNoPicPartitionFlag( bool b ) { m_noPicPartitionFlag = b; } bool getNoPicPartitionFlag( ) const { return m_noPicPartitionFlag; } void setLog2CtuSize( uint8_t u ) { m_log2CtuSize = u; m_ctuSize = 1 << m_log2CtuSize; @@ -2082,6 +2097,9 @@ public: void initRectSliceMap(); #if JVET_O1143_SUBPIC_BOUNDARY std::vector<SubPic> getSubPics() const {return m_subPics; }; +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + SubPic getSubPic(uint32_t idx) const { return m_subPics[idx]; } +#endif void initSubPic(const SPS &sps); SubPic getSubPicFromPos(const Position& pos) const; SubPic getSubPicFromCU (const CodingUnit& cu) const; diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index d86528e0b..6db873ef7 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,6 +50,8 @@ #include <assert.h> #include <cassert> +#define JVET_Q0044_SLICE_IDX_WITH_SUBPICS 1 // JVET-Q0044: slice index with subpictures + #define JVET_Q0471_CHROMA_QT_SPLIT 1 // JVET-Q0471: Chroma QT split #define JVET_P0117_PTL_SCALABILITY 1 // JVET-P0117: sps_ptl_dpb_hrd_params_present_flag related syntax change, others in JVET-Q0786 diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index e15d1dc6e..82cd41d61 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -439,6 +439,10 @@ DecLib::DecLib() , m_vps( nullptr ) , m_scalingListUpdateFlag(true) , m_PreScalingListAPSId(-1) +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + , m_maxDecSubPicIdx(0) + , m_maxDecSliceAddrInSubPic(-1) +#endif { #if ENABLE_SIMD_OPT_BUFFER g_pelBufOP.initPelBufOpsX86(); @@ -742,6 +746,10 @@ void DecLib::finishPicture(int& poc, PicList*& rpcListPic, MsgLevel msgl ) poc = pcSlice->getPOC(); rpcListPic = &m_cListPic; m_bFirstSliceInPicture = true; // TODO: immer true? hier ist irgendwas faul +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + m_maxDecSubPicIdx = 0; + m_maxDecSliceAddrInSubPic = -1; +#endif m_pcPic->destroyTempBuffers(); m_pcPic->cs->destroyCoeffs(); @@ -1066,7 +1074,7 @@ void DecLib::xActivateParameterSets( const int layerId ) THROW("Parameter set activation failed!"); } -#if JVET_O1143_SUBPIC_BOUNDARY +#if JVET_O1143_SUBPIC_BOUNDARY && !JVET_Q0044_SLICE_IDX_WITH_SUBPICS PPS* nonconstPPS = m_parameterSetManager.getPPS(m_picHeader.getPPSId()); nonconstPPS->initSubPic(*sps); #endif @@ -1508,6 +1516,25 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl CHECK(sps == 0, "No SPS present"); VPS *vps = m_parameterSetManager.getVPS(sps->getVPSId()); #endif +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + int currSubPicIdx = pps->getSubPicIdxFromSubPicId( m_apcSlicePilot->getSliceSubPicId() ); + int currSliceAddr = m_apcSlicePilot->getSliceID(); + for(int sp = 0; sp < currSubPicIdx; sp++) + { + currSliceAddr -= pps->getSubPic(sp).getNumSlicesInSubPic(); + } + CHECK( currSubPicIdx < m_maxDecSubPicIdx, "Error in the order of coded slice NAL units of subpictures" ); + CHECK( currSubPicIdx == m_maxDecSubPicIdx && currSliceAddr <= m_maxDecSliceAddrInSubPic, "Error in the order of coded slice NAL units within a subpicture" ); + if( currSubPicIdx == m_maxDecSubPicIdx ) + { + m_maxDecSliceAddrInSubPic = currSliceAddr; + } + if( currSubPicIdx > m_maxDecSubPicIdx ) + { + m_maxDecSubPicIdx = currSubPicIdx; + m_maxDecSliceAddrInSubPic = currSliceAddr; + } +#endif #if JVET_P0097_REMOVE_VPS_DEP_NONSCALABLE_LAYER if ((sps->getVPSId() == 0) && (m_prevLayerID != MAX_INT)) { diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h index 4f60dc184..0a0dd9d5a 100644 --- a/source/Lib/DecoderLib/DecLib.h +++ b/source/Lib/DecoderLib/DecLib.h @@ -146,6 +146,10 @@ private: VPS* m_vps; bool m_scalingListUpdateFlag; int m_PreScalingListAPSId; +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + int m_maxDecSubPicIdx; + int m_maxDecSliceAddrInSubPic; +#endif #if JVET_O1143_SUBPIC_BOUNDARY public: diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 231d771c0..08126b695 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -2605,6 +2605,10 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag CHECK(pps->getCtuSize() != sps->getCTUSize(), "PPS CTU size does not match CTU size in SPS"); } +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + pps->initSubPic(*sps); +#endif + #if !JVET_Q0119_CLEANUPS // sub-picture IDs if( sps->getSubPicIdPresentFlag() ) @@ -3682,17 +3686,37 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, PicHeader* picHeader, Par uint32_t sliceAddr; // slice address is the index of the slice within the current sub-picture +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + uint32_t currSubPicIdx = pps->getSubPicIdxFromSubPicId( pcSlice->getSliceSubPicId() ); + SubPic currSubPic = pps->getSubPic(currSubPicIdx); + if( currSubPic.getNumSlicesInSubPic() > 1 ) +#else if( pps->getNumSlicesInPic() > 1 ) +#endif { +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + int bitsSliceAddress = ceilLog2(currSubPic.getNumSlicesInSubPic()); +#else int bitsSliceAddress = ceilLog2(pps->getNumSlicesInPic()); // change to NumSlicesInSubPic when available +#endif READ_CODE(bitsSliceAddress, uiCode, "slice_address"); sliceAddr = uiCode; CHECK(sliceAddr >= pps->getNumSlicesInPic(), "Invalid slice address"); } else { sliceAddr = 0; } +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + uint32_t picLevelSliceIdx = sliceAddr; + for(int subpic = 0; subpic < currSubPicIdx; subpic++) + { + picLevelSliceIdx += pps->getSubPic(subpic).getNumSlicesInSubPic(); + } + pcSlice->setSliceMap( pps->getSliceMap(picLevelSliceIdx) ); + pcSlice->setSliceID(picLevelSliceIdx); +#else pcSlice->setSliceMap( pps->getSliceMap(sliceAddr) ); pcSlice->setSliceID(sliceAddr); +#endif } #if JVET_Q0819_PH_CHANGES diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index ea48b9e31..36f9cb5e7 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -2809,6 +2809,23 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, for(uint32_t sliceIdx = 0; sliceIdx < pcPic->cs->pps->getNumSlicesInPic(); sliceIdx++ ) { pcSlice->setSliceMap( pcPic->cs->pps->getSliceMap( sliceIdx ) ); +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + if( pcPic->cs->pps->getRectSliceFlag() ) + { + Position firstCtu; + firstCtu.x = pcSlice->getFirstCtuRsAddrInSlice() % pcPic->cs->pps->getPicWidthInCtu(); + firstCtu.y = pcSlice->getFirstCtuRsAddrInSlice() / pcPic->cs->pps->getPicWidthInCtu(); + int subPicIdx = 0; + for(int sp = 0; sp < pcPic->cs->pps->getNumSubPics(); sp++) + { + if(pcPic->cs->pps->getSubPic(sp).containsCtu(firstCtu)) + { + subPicIdx = sp; + } + } + pcSlice->setSliceSubPicId( pcPic->cs->pps->getSubPic(subPicIdx).getSubPicID() ); + } +#endif m_pcSliceEncoder->precompressSlice( pcPic ); m_pcSliceEncoder->compressSlice ( pcPic, false, false ); diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index b58fa77ad..b1b5618c5 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -1480,6 +1480,18 @@ void EncLib::xInitSPS( SPS& sps, VPS& vps ) sps.setLoopFilterAcrossSubpicEnabledFlag(i, m_loopFilterAcrossSubpicEnabledFlag[i]); } } +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + else //In that case, there is only one subpicture that contains the whole picture + { + sps.setNumSubPics(1); + sps.setSubPicCtuTopLeftX(0, 0); + sps.setSubPicCtuTopLeftY(0, 0); + sps.setSubPicWidth(0, m_iSourceWidth); + sps.setSubPicHeight(0, m_iSourceHeight); + sps.setSubPicTreatedAsPicFlag(0, 1); + sps.setLoopFilterAcrossSubpicEnabledFlag(0, 0); + } +#endif #if JVET_Q0119_CLEANUPS sps.setSubPicIdMappingExplicitlySignalledFlag(m_subPicIdMappingExplicitlySignalledFlag); if (m_subPicIdMappingExplicitlySignalledFlag) diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index fc5f52b73..fab86f38a 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -2618,11 +2618,26 @@ void HLSWriter::codeSliceHeader ( Slice* pcSlice ) else { // slice address is the index of the slice within the current sub-picture +#if JVET_Q0044_SLICE_IDX_WITH_SUBPICS + uint32_t currSubPicIdx = pcSlice->getPPS()->getSubPicIdxFromSubPicId( pcSlice->getSliceSubPicId() ); + SubPic currSubPic = pcSlice->getPPS()->getSubPic(currSubPicIdx); + if( currSubPic.getNumSlicesInSubPic() > 1 ) + { + int numSlicesInPreviousSubPics = 0; + for(int sp = 0; sp < currSubPicIdx; sp++) + { + numSlicesInPreviousSubPics += pcSlice->getPPS()->getSubPic(sp).getNumSlicesInSubPic(); + } + int bitsSliceAddress = ceilLog2(currSubPic.getNumSlicesInSubPic()); + WRITE_CODE( pcSlice->getSliceID() - numSlicesInPreviousSubPics, bitsSliceAddress, "slice_address"); + } +#else if( pcSlice->getPPS()->getNumSlicesInPic() > 1 ) { int bitsSliceAddress = ceilLog2(pcSlice->getPPS()->getNumSlicesInPic()); // change to NumSlicesInSubPic when available WRITE_CODE( pcSlice->getSliceID(), bitsSliceAddress, "slice_address"); } +#endif } #if JVET_Q0819_PH_CHANGES -- GitLab