diff --git a/cfg/nonCTC-SliceConfigExamples/subpicture_4Slice2VerSubPic.cfg b/cfg/nonCTC-SliceConfigExamples/subpicture_4Slice2VerSubPic.cfg index a1df9fbab047244ce6205435676acbccbf2b3e76..c37fa7de75f3b60f7ac4b66054483b6631e0cd1e 100644 --- a/cfg/nonCTC-SliceConfigExamples/subpicture_4Slice2VerSubPic.cfg +++ b/cfg/nonCTC-SliceConfigExamples/subpicture_4Slice2VerSubPic.cfg @@ -34,5 +34,5 @@ TileRowHeightArray : 2 # Tile row heights in un RasterScanSlices : 0 # Raster-scan or rectangular slices (0: rectangular, 1: raster-scan) RectSliceFixedWidth : 1 # Fixed rectangular slice width in units of tiles (0: disable this feature and use RectSlicePositions instead) RectSliceFixedHeight : 1 # Fixed rectangular slice height in units of tiles (0: disable this feature and use RectSlicePositions instead) -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) +DisableLoopFilterAcrossTiles : 0 # Loop filtering (DBLK/SAO/ALF) applied across tile boundaries or not (0: filter across tile boundaries 1: do not filter across tile boundaries) +DisableLoopFilterAcrossSlices : 0 # 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/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp index f0428bff4987ad635fe28312f064fee908379dd4..dcbe8be97fd68fc1abf7762f29b5db94a266eef3 100644 --- a/source/App/DecoderApp/DecApp.cpp +++ b/source/App/DecoderApp/DecApp.cpp @@ -717,7 +717,7 @@ void DecApp::xCreateDecLib() std::ostream &os=m_seiMessageFileStream.is_open() ? m_seiMessageFileStream : std::cout; m_cDecLib.setDecodedSEIMessageOutputStream(&os); } -#if SUBPIC_DECCHECK +#if JVET_O1143_SUBPIC_DECCHECK m_cDecLib.m_targetSubPicIdx = this->m_targetSubPicIdx; #endif m_cDecLib.initScalingList(); diff --git a/source/App/DecoderApp/DecAppCfg.cpp b/source/App/DecoderApp/DecAppCfg.cpp index 63808add02c8f034a9c3c645afe4c65742a14cc4..f5e9ffda801182deb0c292a6b23190aab8055e29 100644 --- a/source/App/DecoderApp/DecAppCfg.cpp +++ b/source/App/DecoderApp/DecAppCfg.cpp @@ -117,7 +117,7 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] ) "\t3: enable bit and tool statistic\n") #endif ("MCTSCheck", m_mctsCheck, false, "If enabled, the decoder checks for violations of mc_exact_sample_value_match_flag in Temporal MCTS ") -#if SUBPIC_DECCHECK +#if JVET_O1143_SUBPIC_DECCHECK ("targetSubPicIdx", m_targetSubPicIdx, 0, "Specify which subpicture shall be written to output, using subpic index\n" ) #endif ( "UpscaledOutput", m_upscaledOutput, 0, "Upscaled output for RPR" ) diff --git a/source/App/DecoderApp/DecAppCfg.h b/source/App/DecoderApp/DecAppCfg.h index c04f51c85fad022e42ded6df395dec7bd575aa32..e8e1af7e9eee5a1fdd13d535b5aaba47dd2b8bb9 100644 --- a/source/App/DecoderApp/DecAppCfg.h +++ b/source/App/DecoderApp/DecAppCfg.h @@ -83,7 +83,7 @@ protected: bool m_mctsCheck; int m_upscaledOutput; ////< Output upscaled (2), decoded but in full resolution buffer (1) or decoded cropped (0, default) picture for RPR. -#if SUBPIC_DECCHECK +#if JVET_O1143_SUBPIC_DECCHECK int m_targetSubPicIdx; ///< Specify which subpicture shall be write to output, using subpicture index #endif public: diff --git a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp index 4d862ff95008c1b7543b0f1d53f480f329e066ea..04a4a5019c312818bf6059ce1b8656a533761bd6 100644 --- a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp +++ b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp @@ -121,13 +121,21 @@ bool AdaptiveLoopFilter::isCrossedByVirtualBoundaries( const CodingStructure& cs int ctuSize = slice.getSPS()->getCTUSize(); const Position currCtuPos(xPos, yPos); const CodingUnit *currCtu = cs.getCU(currCtuPos, CHANNEL_TYPE_LUMA); +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY + SubPic curSubPic = slice.getPPS()->getSubPicFromPos(currCtuPos); + bool loopFilterAcrossSubPicEnabledFlag = curSubPic.getloopFilterAcrossEnabledFlag(); +#endif //top if (yPos >= ctuSize && clipTop == false) { const Position prevCtuPos(xPos, yPos - ctuSize); const CodingUnit *prevCtu = cs.getCU(prevCtuPos, CHANNEL_TYPE_LUMA); if ((!pps->getLoopFilterAcrossSlicesEnabledFlag() && !CU::isSameSlice(*currCtu, *prevCtu)) || - (!pps->getLoopFilterAcrossTilesEnabledFlag() && !CU::isSameTile(*currCtu, *prevCtu))) + (!pps->getLoopFilterAcrossTilesEnabledFlag() && !CU::isSameTile(*currCtu, *prevCtu)) +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY + || (!loopFilterAcrossSubPicEnabledFlag && !CU::isSameSubPic(*currCtu, *prevCtu)) +#endif + ) { clipTop = true; } @@ -139,7 +147,11 @@ bool AdaptiveLoopFilter::isCrossedByVirtualBoundaries( const CodingStructure& cs const Position nextCtuPos(xPos, yPos + ctuSize); const CodingUnit *nextCtu = cs.getCU(nextCtuPos, CHANNEL_TYPE_LUMA); if ((!pps->getLoopFilterAcrossSlicesEnabledFlag() && !CU::isSameSlice(*currCtu, *nextCtu)) || - (!pps->getLoopFilterAcrossTilesEnabledFlag() && !CU::isSameTile(*currCtu, *nextCtu))) + (!pps->getLoopFilterAcrossTilesEnabledFlag() && !CU::isSameTile(*currCtu, *nextCtu)) +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY + || (!loopFilterAcrossSubPicEnabledFlag && !CU::isSameSubPic(*currCtu, *nextCtu)) +#endif + ) { clipBottom = true; } @@ -151,7 +163,11 @@ bool AdaptiveLoopFilter::isCrossedByVirtualBoundaries( const CodingStructure& cs const Position prevCtuPos(xPos - ctuSize, yPos); const CodingUnit *prevCtu = cs.getCU(prevCtuPos, CHANNEL_TYPE_LUMA); if ((!pps->getLoopFilterAcrossSlicesEnabledFlag() && !CU::isSameSlice(*currCtu, *prevCtu)) || - (!pps->getLoopFilterAcrossTilesEnabledFlag() && !CU::isSameTile(*currCtu, *prevCtu))) + (!pps->getLoopFilterAcrossTilesEnabledFlag() && !CU::isSameTile(*currCtu, *prevCtu)) +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY + || (!loopFilterAcrossSubPicEnabledFlag && !CU::isSameSubPic(*currCtu, *prevCtu)) +#endif + ) { clipLeft = true; } @@ -163,7 +179,11 @@ bool AdaptiveLoopFilter::isCrossedByVirtualBoundaries( const CodingStructure& cs const Position nextCtuPos(xPos + ctuSize, yPos); const CodingUnit *nextCtu = cs.getCU(nextCtuPos, CHANNEL_TYPE_LUMA); if ((!pps->getLoopFilterAcrossSlicesEnabledFlag() && !CU::isSameSlice(*currCtu, *nextCtu)) || - (!pps->getLoopFilterAcrossTilesEnabledFlag() && !CU::isSameTile(*currCtu, *nextCtu))) + (!pps->getLoopFilterAcrossTilesEnabledFlag() && !CU::isSameTile(*currCtu, *nextCtu)) +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY + || (!loopFilterAcrossSubPicEnabledFlag && !CU::isSameSubPic(*currCtu, *nextCtu)) +#endif + ) { clipRight = true; } diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp index a9e3a60c8eda3283e83e2dd86452e9a5f6d4c174..ba4ff56166652657e02a6680a27dda802dafdf74 100644 --- a/source/Lib/CommonLib/LoopFilter.cpp +++ b/source/Lib/CommonLib/LoopFilter.cpp @@ -81,15 +81,30 @@ inline static uint32_t getRasterIdx(const Position& pos, const PreCalcValues& pc // ==================================================================================================================== // utility functions // ==================================================================================================================== - -static bool isAvailableLeft( const CodingUnit& cu, const CodingUnit& cu2, const bool bEnforceSliceRestriction, const bool bEnforceTileRestriction ) +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY +static bool isAvailableLeft( const CodingUnit& cu, const CodingUnit& cu2, const bool bEnforceSliceRestriction, const bool bEnforceTileRestriction, const bool bEnforceSubPicRestriction) +#else +static bool isAvailableLeft( const CodingUnit& cu, const CodingUnit& cu2, const bool bEnforceSliceRestriction, const bool bEnforceTileRestriction) +#endif { - return ( ( !bEnforceSliceRestriction || CU::isSameSlice( cu, cu2 ) ) && ( !bEnforceTileRestriction || CU::isSameTile( cu, cu2 ) ) ); +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY + return ((!bEnforceSliceRestriction || CU::isSameSlice(cu, cu2)) && (!bEnforceTileRestriction || CU::isSameTile(cu, cu2)) && (!bEnforceSubPicRestriction || CU::isSameSubPic(cu, cu2))); +#else + return ((!bEnforceSliceRestriction || CU::isSameSlice(cu, cu2)) && (!bEnforceTileRestriction || CU::isSameTile(cu, cu2))); +#endif } -static bool isAvailableAbove( const CodingUnit& cu, const CodingUnit& cu2, const bool bEnforceSliceRestriction, const bool bEnforceTileRestriction ) +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY +static bool isAvailableAbove( const CodingUnit& cu, const CodingUnit& cu2, const bool bEnforceSliceRestriction, const bool bEnforceTileRestriction, const bool bEnforceSubPicRestriction) +#else +static bool isAvailableAbove( const CodingUnit& cu, const CodingUnit& cu2, const bool bEnforceSliceRestriction, const bool bEnforceTileRestriction) +#endif { - return ( !bEnforceSliceRestriction || CU::isSameSlice( cu, cu2 ) ) && ( !bEnforceTileRestriction || CU::isSameTile( cu, cu2 ) ); +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY + return ( !bEnforceSliceRestriction || CU::isSameSlice( cu, cu2 ) ) && ( !bEnforceTileRestriction || CU::isSameTile( cu, cu2 ) ) && (!bEnforceSubPicRestriction || CU::isSameSubPic(cu, cu2)); +#else + return ( !bEnforceSliceRestriction || CU::isSameSlice( cu, cu2 ) ) && ( !bEnforceTileRestriction || CU::isSameTile( cu, cu2 ) ) ; +#endif } @@ -680,8 +695,19 @@ 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 ), !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag() ); - m_stLFCUParam.topEdge = ( 0 < pos.y ) && isAvailableAbove( cu, *cu.cs->getCU( pos.offset( 0, -1 ), cu.chType ), !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag() ); + +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY + m_stLFCUParam.leftEdge = ( 0 < pos.x ) && isAvailableLeft ( cu, *cu.cs->getCU( pos.offset( -1, 0 ), cu.chType ), !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag(), !pps.getSubPicFromCU(cu).getloopFilterAcrossEnabledFlag() ); +#else + m_stLFCUParam.leftEdge = ( 0 < pos.x ) && isAvailableLeft ( cu, *cu.cs->getCU( pos.offset( -1, 0 ), cu.chType ), !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag()); +#endif + +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY + m_stLFCUParam.topEdge = ( 0 < pos.y ) && isAvailableAbove( cu, *cu.cs->getCU( pos.offset( 0, -1 ), cu.chType ), !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag(), !pps.getSubPicFromCU(cu).getloopFilterAcrossEnabledFlag() ); +#else + m_stLFCUParam.topEdge = ( 0 < pos.y ) && isAvailableAbove( cu, *cu.cs->getCU( pos.offset( 0, -1 ), cu.chType ), !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag()); +#endif + } unsigned LoopFilter::xGetBoundaryStrengthSingle ( const CodingUnit& cu, const DeblockEdgeDir edgeDir, const Position& localPos ) const @@ -937,7 +963,11 @@ void LoopFilter::xEdgeFilterLuma( const CodingUnit& cu, const DeblockEdgeDir edg // Derive neighboring PU index if (edgeDir == EDGE_VER) { +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY + if (!isAvailableLeft(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag(), !pps.getSubPicFromCU(cu).getloopFilterAcrossEnabledFlag())) +#else if (!isAvailableLeft(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag())) +#endif { m_aapucBS[edgeDir][uiBsAbsIdx] = uiBs = 0; continue; @@ -945,7 +975,11 @@ void LoopFilter::xEdgeFilterLuma( const CodingUnit& cu, const DeblockEdgeDir edg } else // (iDir == EDGE_HOR) { +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY + if (!isAvailableAbove(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag(), !pps.getSubPicFromCU(cu).getloopFilterAcrossEnabledFlag())) +#else if (!isAvailableAbove(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag())) +#endif { m_aapucBS[edgeDir][uiBsAbsIdx] = uiBs = 0; continue; @@ -1205,11 +1239,19 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed if (edgeDir == EDGE_VER) { +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY + CHECK(!isAvailableLeft(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag(), !pps.getSubPicFromCU(cu).getloopFilterAcrossEnabledFlag()), "Neighbour not available"); +#else CHECK(!isAvailableLeft(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag()), "Neighbour not available"); +#endif } else // (iDir == EDGE_HOR) { +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY + CHECK(!isAvailableAbove(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag(), !pps.getSubPicFromCU(cu).getloopFilterAcrossEnabledFlag()), "Neighbour not available"); +#else CHECK(!isAvailableAbove(cu, cuP, !pps.getLoopFilterAcrossSlicesEnabledFlag(), !pps.getLoopFilterAcrossTilesEnabledFlag()), "Neighbour not available"); +#endif } bPartPNoFilter = bPartQNoFilter = false; diff --git a/source/Lib/CommonLib/Mv.cpp b/source/Lib/CommonLib/Mv.cpp index 386d0874680f79432ae174c44271c0a8cc11491b..598a26433cf80e965ac547c6388aa6cbc0ef19db 100644 --- a/source/Lib/CommonLib/Mv.cpp +++ b/source/Lib/CommonLib/Mv.cpp @@ -66,7 +66,17 @@ void clipMv( Mv& rcMv, const Position& pos, const struct Size& size, const SPS& int iVerMax = ( pps.getPicHeightInLumaSamples() + iOffset - (int)pos.y - 1 ) << iMvShift; int iVerMin = ( -( int ) sps.getMaxCUHeight() - iOffset - ( int ) pos.y + 1 ) << iMvShift; +#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY + SubPic curSubPic = pps.getSubPicFromPos(pos); + if (curSubPic.getTreatedAsPicFlag()) + { + iHorMax = (curSubPic.getSubPicWidthInLumaSample() + iOffset - (int)pos.x - 1 ) << iMvShift; + iHorMin = (-(int)sps.getMaxCUWidth() - iOffset - ((int)pos.x - curSubPic.getSubPicLeft()) + 1) << iMvShift; + iVerMax = (curSubPic.getSubPicHeightInLumaSample()+ iOffset - (int)pos.y - 1) << iMvShift; + iVerMin = (-(int)sps.getMaxCUHeight() - iOffset - ((int)pos.y - curSubPic.getSubPicTop()) + 1) << iMvShift; + } +#endif rcMv.setHor( std::min( iHorMax, std::max( iHorMin, rcMv.getHor() ) ) ); rcMv.setVer( std::min( iVerMax, std::max( iVerMin, rcMv.getVer() ) ) ); } diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp index 2821a7ef362fbbb8bf827976a1f04321ac4fe8ca..a74e5ed1e1ecf3e74d1116d80786b94552234ab6 100644 --- a/source/Lib/CommonLib/Picture.cpp +++ b/source/Lib/CommonLib/Picture.cpp @@ -173,6 +173,9 @@ int Scheduler::getNumPicInstances() const Picture::Picture() { cs = nullptr; +#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY + m_isSubPicBorderSaved = false; +#endif m_bIsBorderExtended = false; usedByCurr = false; longTerm = false; @@ -734,6 +737,219 @@ void Picture::rescalePicture( const std::pair<int, int> scalingRatio, } } +#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY +void Picture::saveSubPicBorder(int POC, int subPicX0, int subPicY0, int subPicWidth, int subPicHeight) +{ + + // 1.1 set up margin for back up memory allocation + int xMargin = margin >> getComponentScaleX(COMPONENT_Y, cs->area.chromaFormat); + int yMargin = margin >> getComponentScaleY(COMPONENT_Y, cs->area.chromaFormat); + + // 1.2 measure the size of back up memory + Area areaAboveBelow(0, 0, subPicWidth + 2 * xMargin, yMargin); + Area areaLeftRight(0, 0, xMargin, subPicHeight); + UnitArea unitAreaAboveBelow(cs->area.chromaFormat, areaAboveBelow); + UnitArea unitAreaLeftRight(cs->area.chromaFormat, areaLeftRight); + + // 1.3 create back up memory + m_bufSubPicAbove.create(unitAreaAboveBelow); + m_bufSubPicBelow.create(unitAreaAboveBelow); + m_bufSubPicLeft.create(unitAreaLeftRight); + m_bufSubPicRight.create(unitAreaLeftRight); + + for (int comp = 0; comp < getNumberValidComponents(cs->area.chromaFormat); comp++) + { + ComponentID compID = ComponentID(comp); + + // 2.1 measure the margin for each component + int xmargin = margin >> getComponentScaleX(compID, cs->area.chromaFormat); + int ymargin = margin >> getComponentScaleY(compID, cs->area.chromaFormat); + + // 2.2 calculate the origin of the subpicture + int left = subPicX0 >> getComponentScaleX(compID, cs->area.chromaFormat); + int top = subPicY0 >> getComponentScaleY(compID, cs->area.chromaFormat); + + // 2.3 calculate the width/height of the subPic + int width = subPicWidth >> getComponentScaleX(compID, cs->area.chromaFormat); + int height = subPicHeight >> getComponentScaleY(compID, cs->area.chromaFormat); + + + // 3.1.1 set reconstructed picture + PelBuf s = M_BUFS(0, PIC_RECONSTRUCTION).get(compID); + Pel *src = s.bufAt(left, top); + + // 3.2.1 set back up buffer for left + PelBuf dBufLeft = m_bufSubPicLeft.getBuf(compID); + Pel *dstLeft = dBufLeft.bufAt(0, 0); + + + // 3.2.2 set back up buffer for right + PelBuf dBufRight = m_bufSubPicRight.getBuf(compID); + Pel *dstRight = dBufRight.bufAt(0, 0); + + // 3.2.3 copy to recon picture to back up buffer + Pel *srcLeft = src - xmargin; + Pel *srcRight = src + width; + for (int y = 0; y < height; y++) + { + ::memcpy(dstLeft + y * dBufLeft.stride, srcLeft + y * s.stride, sizeof(Pel) * xmargin); + ::memcpy(dstRight + y * dBufRight.stride, srcRight + y * s.stride, sizeof(Pel) * xmargin); + } + + // 3.3.1 set back up buffer for above + PelBuf dBufTop = m_bufSubPicAbove.getBuf(compID); + Pel *dstTop = dBufTop.bufAt(0, 0); + + // 3.3.2 set back up buffer for below + PelBuf dBufBottom = m_bufSubPicBelow.getBuf(compID); + Pel *dstBottom = dBufBottom.bufAt(0, 0); + + // 3.3.3 copy to recon picture to back up buffer + Pel *srcTop = src - xmargin - ymargin * s.stride; + Pel *srcBottom = src - xmargin + height * s.stride; + for (int y = 0; y < ymargin; y++) + { + ::memcpy(dstTop + y * dBufTop.stride, srcTop + y * s.stride, sizeof(Pel) * (2 * xmargin + width)); + ::memcpy(dstBottom + y * dBufBottom.stride, srcBottom + y * s.stride, sizeof(Pel) * (2 * xmargin + width)); + } + } +} + +void Picture::extendSubPicBorder(int POC, int subPicX0, int subPicY0, int subPicWidth, int subPicHeight) +{ + + for (int comp = 0; comp < getNumberValidComponents(cs->area.chromaFormat); comp++) + { + ComponentID compID = ComponentID(comp); + + // 2.1 measure the margin for each component + int xmargin = margin >> getComponentScaleX(compID, cs->area.chromaFormat); + int ymargin = margin >> getComponentScaleY(compID, cs->area.chromaFormat); + + // 2.2 calculate the origin of the Subpicture + int left = subPicX0 >> getComponentScaleX(compID, cs->area.chromaFormat); + int top = subPicY0 >> getComponentScaleY(compID, cs->area.chromaFormat); + + // 2.3 calculate the width/height of the Subpicture + int width = subPicWidth >> getComponentScaleX(compID, cs->area.chromaFormat); + int height = subPicHeight >> getComponentScaleY(compID, cs->area.chromaFormat); + + // 3.1 set reconstructed picture + PelBuf s = M_BUFS(0, PIC_RECONSTRUCTION).get(compID); + Pel *src = s.bufAt(left, top); + + // 4.1 apply padding for left and right + { + Pel *dstLeft = src - xmargin; + Pel *dstRight = src + width; + Pel *srcLeft = src + 0; + Pel *srcRight = src + width - 1; + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < xmargin; x++) + { + dstLeft[x] = *srcLeft; + dstRight[x] = *srcRight; + } + dstLeft += s.stride; + dstRight += s.stride; + srcLeft += s.stride; + srcRight += s.stride; + } + } + + // 4.2 apply padding on bottom + Pel *srcBottom = src + s.stride * (height - 1) - xmargin; + Pel *dstBottom = srcBottom + s.stride; + for (int y = 0; y < ymargin; y++) + { + ::memcpy(dstBottom, srcBottom, sizeof(Pel)*(2 * xmargin + width)); + dstBottom += s.stride; + } + + // 4.3 apply padding for top + // si is still (-marginX, SubpictureHeight-1) + Pel *srcTop = src - xmargin; + Pel *dstTop = srcTop - s.stride; + // si is now (-marginX, 0) + for (int y = 0; y < ymargin; y++) + { + ::memcpy(dstTop, srcTop, sizeof(Pel)*(2 * xmargin + width)); + dstTop -= s.stride; + } + } // end of for +} + +void Picture::restoreSubPicBorder(int POC, int subPicX0, int subPicY0, int subPicWidth, int subPicHeight) +{ + for (int comp = 0; comp < getNumberValidComponents(cs->area.chromaFormat); comp++) + { + ComponentID compID = ComponentID(comp); + + // 2.1 measure the margin for each component + int xmargin = margin >> getComponentScaleX(compID, cs->area.chromaFormat); + int ymargin = margin >> getComponentScaleY(compID, cs->area.chromaFormat); + + // 2.2 calculate the origin of the subpicture + int left = subPicX0 >> getComponentScaleX(compID, cs->area.chromaFormat); + int top = subPicY0 >> getComponentScaleY(compID, cs->area.chromaFormat); + + // 2.3 calculate the width/height of the subpicture + int width = subPicWidth >> getComponentScaleX(compID, cs->area.chromaFormat); + int height = subPicHeight >> getComponentScaleY(compID, cs->area.chromaFormat); + + // 3.1 set reconstructed picture + PelBuf s = M_BUFS(0, PIC_RECONSTRUCTION).get(compID); + Pel *src = s.bufAt(left, top); + + // 4.2.1 copy from back up buffer to recon picture + PelBuf dBufLeft = m_bufSubPicLeft.getBuf(compID); + Pel *dstLeft = dBufLeft.bufAt(0, 0); + + // 4.2.2 set back up buffer for right + PelBuf dBufRight = m_bufSubPicRight.getBuf(compID); + Pel *dstRight = dBufRight.bufAt(0, 0); + + // 4.2.3 copy to recon picture to back up buffer + Pel *srcLeft = src - xmargin; + Pel *srcRight = src + width; + + for (int y = 0; y < height; y++) + { + // the destination and source position is reversed on purpose + ::memcpy(srcLeft + y * s.stride, dstLeft + y * dBufLeft.stride, sizeof(Pel) * xmargin); + ::memcpy(srcRight + y * s.stride, dstRight + y * dBufRight.stride, sizeof(Pel) * xmargin); + } + + + // 4.3.1 set back up buffer for above + PelBuf dBufTop = m_bufSubPicAbove.getBuf(compID); + Pel *dstTop = dBufTop.bufAt(0, 0); + + // 4.3.2 set back up buffer for below + PelBuf dBufBottom = m_bufSubPicBelow.getBuf(compID); + Pel *dstBottom = dBufBottom.bufAt(0, 0); + + // 4.3.3 copy to recon picture to back up buffer + Pel *srcTop = src - xmargin - ymargin * s.stride; + Pel *srcBottom = src - xmargin + height * s.stride; + + for (int y = 0; y < ymargin; y++) + { + ::memcpy(srcTop + y * s.stride, dstTop + y * dBufTop.stride, sizeof(Pel) * (2 * xmargin + width)); + ::memcpy(srcBottom + y * s.stride, dstBottom + y * dBufBottom.stride, sizeof(Pel) * (2 * xmargin + width)); + } + } + + // 5.0 destroy the back up memory + m_bufSubPicAbove.destroy(); + m_bufSubPicBelow.destroy(); + m_bufSubPicLeft.destroy(); + m_bufSubPicRight.destroy(); +} +#endif + void Picture::extendPicBorder() { if ( m_bIsBorderExtended ) diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h index aad5a47fc4b1f207ee4eb6919826411eba2fa8b1..911786f945524826c1f6640d28c03d5eb3353c98 100644 --- a/source/Lib/CommonLib/Picture.h +++ b/source/Lib/CommonLib/Picture.h @@ -172,6 +172,21 @@ private: Window m_scalingWindow; public: +#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY + bool m_isSubPicBorderSaved; + + PelStorage m_bufSubPicAbove; + PelStorage m_bufSubPicBelow; + PelStorage m_bufSubPicLeft; + PelStorage m_bufSubPicRight; + + void saveSubPicBorder(int POC, int subPicX0, int subPicY0, int subPicWidth, int subPicHeight); + void extendSubPicBorder(int POC, int subPicX0, int subPicY0, int subPicWidth, int subPicHeight); + void restoreSubPicBorder(int POC, int subPicX0, int subPicY0, int subPicWidth, int subPicHeight); + + bool getSubPicSaved() { return m_isSubPicBorderSaved; } + void setSubPicSaved(bool bVal) { m_isSubPicBorderSaved = bVal; } +#endif bool m_bIsBorderExtended; bool referenced; bool reconstructed; diff --git a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp index 0953b569a4650468f729db30dff7a300d8d78aad..a910f8a468b2ffd40fdcd0f8a001d912d3fc0f24 100644 --- a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp +++ b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp @@ -726,6 +726,22 @@ void SampleAdaptiveOffset::deriveLoopFilterBoundaryAvailibility(CodingStructure& isBelowLeftAvail = (!isBelowLeftAvail) ? false : CU::isSameTile(*cuCurr, *cuBelowLeft); isBelowRightAvail = (!isBelowRightAvail) ? false : CU::isSameTile(*cuCurr, *cuBelowRight); } + +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY + // check cross subpic flags + SubPic curSubPic = cs.pps->getSubPicFromCU(*cuCurr); + if (!curSubPic.getloopFilterAcrossEnabledFlag()) + { + isLeftAvail = (!isLeftAvail) ? false : CU::isSameSubPic(*cuCurr, *cuLeft); + isAboveAvail = (!isAboveAvail) ? false : CU::isSameSubPic(*cuCurr, *cuAbove); + isRightAvail = (!isRightAvail) ? false : CU::isSameSubPic(*cuCurr, *cuRight); + isBelowAvail = (!isBelowAvail) ? false : CU::isSameSubPic(*cuCurr, *cuBelow); + isAboveLeftAvail = (!isAboveLeftAvail) ? false : CU::isSameSubPic(*cuCurr, *cuAboveLeft); + isAboveRightAvail = (!isAboveRightAvail) ? false : CU::isSameSubPic(*cuCurr, *cuAboveRight); + isBelowLeftAvail = (!isBelowLeftAvail) ? false : CU::isSameSubPic(*cuCurr, *cuBelowLeft); + isBelowRightAvail = (!isBelowRightAvail) ? false : CU::isSameSubPic(*cuCurr, *cuBelowRight); + } +#endif } bool SampleAdaptiveOffset::isCrossedByVirtualBoundaries(const int xPos, const int yPos, const int width, const int height, int& numHorVirBndry, int& numVerVirBndry, int horVirBndryPos[], int verVirBndryPos[], const PicHeader* picHeader ) diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index e852a1310783ef495a9be273a09ecb7d5c056926..c1fc4bd09a1be0aabeb02029217e23890176f570 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -2472,6 +2472,7 @@ void PPS::initSubPic(const SPS &sps) m_subPics.resize(getNumSubPics()); for (int i=0; i< getNumSubPics(); i++) { + m_subPics[i].setSubPicIdx(i); m_subPics[i].setSubPicCtuTopLeftX(sps.getSubPicCtuTopLeftX(i)); m_subPics[i].setSubPicCtuTopLeftY(sps.getSubPicCtuTopLeftY(i)); m_subPics[i].setSubPicWidthInCTUs(sps.getSubPicWidth(i)); @@ -2488,10 +2489,15 @@ void PPS::initSubPic(const SPS &sps) uint32_t right = std::min(m_picWidthInLumaSamples - 1, (sps.getSubPicCtuTopLeftX(i) + sps.getSubPicWidth(i)) * m_ctuSize - 1); m_subPics[i].setSubPicRight(right); + m_subPics[i].setSubPicWidthInLumaSample(right - left + 1); + uint32_t top = sps.getSubPicCtuTopLeftY(i) * m_ctuSize; m_subPics[i].setSubPicTop(top); uint32_t bottom = std::min(m_picHeightInLumaSamples - 1, (sps.getSubPicCtuTopLeftY(i) + sps.getSubPicHeight(i)) * m_ctuSize - 1); + + m_subPics[i].setSubPicHeightInLumaSample(bottom - top + 1); + m_subPics[i].setSubPicBottom(bottom); for (int j = 0; j < m_numSlicesInPic; j++) @@ -2504,7 +2510,7 @@ void PPS::initSubPic(const SPS &sps) ctu_y >= sps.getSubPicCtuTopLeftY(i) && ctu_y < (sps.getSubPicCtuTopLeftY(i) + sps.getSubPicHeight(i))) { - // slice in the subpicture + // add ctus in a slice to the subpicture it belongs to m_subPics[i].addCTUsToSubPic(m_sliceMap[j].getCtuAddrList()); } } @@ -2512,6 +2518,24 @@ void PPS::initSubPic(const SPS &sps) m_subPics[i].setloopFilterAcrossEnabledFlag(sps.getLoopFilterAcrossSubpicEnabledFlag(i)); } } + +SubPic PPS::getSubPicFromPos(const Position& pos) const +{ + for (int i = 0; i< m_numSubPics; i++) + { + if (m_subPics[i].isContainingPos(pos)) + { + return m_subPics[i]; + } + } + return m_subPics[0]; +} + +SubPic PPS::getSubPicFromCU(const CodingUnit& cu) const +{ + const Position lumaPos = cu.Y().valid() ? cu.Y().pos() : recalcPosition(cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].pos()); + return getSubPicFromPos(lumaPos); +} #endif void PPS::initRasterSliceMap( std::vector<uint32_t> numTilesInSlice ) diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index 70fea19893c40bb0951b3e61855e63aadabbe19b..f148d808e700ebeb2dca0ea42f9b02094e899f48 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -689,11 +689,14 @@ class SubPic { private: uint32_t m_subPicID; //!< ID of subpicture + uint32_t m_subPicIdx; //!< Index of subpicture uint32_t m_numCTUsInSubPic; //!< number of CTUs contained in this sub-picture uint32_t m_subPicCtuTopLeftX; //!< horizontal position of top left CTU of the subpicture in unit of CTU uint32_t m_subPicCtuTopLeftY; //!< vertical position of top left CTU of the subpicture in unit of CTU uint32_t m_subPicWidth; //!< the width of subpicture in units of CTU uint32_t m_subPicHeight; //!< the height of subpicture in units of CTU + uint32_t m_subPicWidthInLumaSample; //!< the width of subpicture in units of luma sample + uint32_t m_subPicHeightInLumaSample; //!< the height of subpicture in units of luma sample uint32_t m_firstCtuInSubPic; //!< the raster scan index of the first CTU in a subpicture uint32_t m_lastCtuInSubPic; //!< the raster scan index of the last CTU in a subpicture uint32_t m_subPicLeft; //!< the position of left boundary @@ -711,6 +714,8 @@ public: void setSubPicID (uint32_t u) { m_subPicID = u; } uint32_t getSubPicID () const { return m_subPicID; } + void setSubPicIdx (uint32_t u) { m_subPicIdx = u; } + uint32_t getSubPicIdx () const { return m_subPicIdx; } void setNumCTUsInSubPic (uint32_t u) { m_numCTUsInSubPic = u; } uint32_t getNumCTUsInSubPic () const { return m_numCTUsInSubPic; } void setSubPicCtuTopLeftX (uint32_t u) { m_subPicCtuTopLeftX = u; } @@ -734,16 +739,28 @@ public: void setSubPicBottom (uint32_t u) { m_subPicBottom = u; } uint32_t getSubPicBottom () const { return m_subPicBottom; } + void setSubPicWidthInLumaSample (uint32_t u) { m_subPicWidthInLumaSample = u; } + uint32_t getSubPicWidthInLumaSample() const { return m_subPicWidthInLumaSample; } + void setSubPicHeightInLumaSample(uint32_t u) { m_subPicHeightInLumaSample = u; } + uint32_t getSubPicHeightInLumaSample() const { return m_subPicHeightInLumaSample; } + std::vector<uint32_t> getCtuAddrList () const { return m_ctuAddrInSubPic; } void addCTUsToSubPic(std::vector<uint32_t> ctuAddrInSlice) { for (auto ctu:ctuAddrInSlice) m_ctuAddrInSubPic.push_back(ctu); } + bool isContainingPos(const Position& pos) const + { + return pos.x >= m_subPicLeft && pos.x <= m_subPicRight && pos.y >= m_subPicTop && pos.y <= m_subPicBottom; + } void setTreatedAsPicFlag (bool u) { m_treatedAsPicFlag = u; } bool getTreatedAsPicFlag () const { return m_treatedAsPicFlag; } void setloopFilterAcrossEnabledFlag(bool u) { m_loopFilterAcrossSubPicEnabledFlag = u; } bool getloopFilterAcrossEnabledFlag() const { return m_loopFilterAcrossSubPicEnabledFlag; } + + bool isFirstCTUinSubPic(uint32_t ctuAddr) { return ctuAddr == m_firstCtuInSubPic; } + bool isLastCTUinSubPic(uint32_t ctuAddr) { return ctuAddr == m_lastCtuInSubPic; } }; #endif class DPS @@ -1925,6 +1942,8 @@ public: #if JVET_O1143_SUBPIC_BOUNDARY std::vector<SubPic> getSubPics() const {return m_subPics; }; void initSubPic(const SPS &sps); + SubPic getSubPicFromPos(const Position& pos) const; + SubPic getSubPicFromCU (const CodingUnit& cu) const; #endif void initRasterSliceMap( std::vector<uint32_t> sizes ); void checkSliceMap(); @@ -2616,7 +2635,11 @@ public: int getNumRefIdx( RefPicList e ) const { return m_aiNumRefIdx[e]; } Picture* getPic() { return m_pcPic; } const Picture* getPic() const { return m_pcPic; } +#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY + Picture* getRefPic( RefPicList e, int iRefIdx) const { return m_apcRefPicList[e][iRefIdx]; } +#else const Picture* getRefPic( RefPicList e, int iRefIdx) const { return m_apcRefPicList[e][iRefIdx]; } +#endif int getRefPOC( RefPicList e, int iRefIdx) const { return m_aiRefPOCList[e][iRefIdx]; } int getDepth() const { return m_iDepth; } bool getColFromL0Flag() const { return m_colFromL0Flag; } diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index f848d07f47e43f7bffe7af8260a8151b971b0d82..bd2ecba44893536a6ea105816f4e538729a560b9 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -137,7 +137,9 @@ #define JVET_O1143_SUBPIC_BOUNDARY 1 // treat subpicture boundary as piucture boundary #if JVET_O1143_SUBPIC_BOUNDARY -#define SUBPIC_DECCHECK 0 +#define JVET_O1143_SUBPIC_DECCHECK 0 +#define JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY 1 +#define JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY 1 #endif #define JVET_Q0495_NLALF_CLIP_CLEANUP 1 // JVET-Q0495: Cleanup of clipping table for NL-ALF diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 0b812f72b6b9da075ce28375c1f74901875949fe..00860acaf37a540cf64a0fe3a9a7ca6bf2db9c61 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -183,6 +183,13 @@ bool CU::isSameSliceAndTile(const CodingUnit& cu, const CodingUnit& cu2) return ( cu.slice->getIndependentSliceIdx() == cu2.slice->getIndependentSliceIdx() ) && ( cu.tileIdx == cu2.tileIdx ); } +#if JVET_O1143_SUBPIC_BOUNDARY +bool CU::isSameSubPic(const CodingUnit& cu, const CodingUnit& cu2) +{ + return (cu.slice->getPPS()->getSubPicFromCU(cu).getSubPicIdx() == cu2.slice->getPPS()->getSubPicFromCU(cu2).getSubPicIdx()) ; +} +#endif + bool CU::isSameCtu(const CodingUnit& cu, const CodingUnit& cu2) { uint32_t ctuSizeBit = floorLog2(cu.cs->sps->getMaxCUWidth()); @@ -1080,7 +1087,18 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, Position posC0; Position posC1 = pu.Y().center(); bool C0Avail = false; +#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY + bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight); + SubPic curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos()); + if (curSubPic.getTreatedAsPicFlag()) + { + boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() && + (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom()); + } + if (boundaryCond) +#else if (((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight)) +#endif { int posYInCtu = posRB.y & pcv.maxCUHeightMask; if (posYInCtu + 4 < pcv.maxCUHeight) @@ -1413,6 +1431,15 @@ bool PU::getColocatedMVP(const PredictionUnit &pu, const RefPicList &eRefPicList return false; } +#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY + // Check the position of colocated block is within a subpicture + SubPic curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos()); + if (curSubPic.getTreatedAsPicFlag()) + { + if (!curSubPic.isContainingPos(pos)) + return false; + } +#endif RefPicList eColRefPicList = slice.getCheckLDC() ? eRefPicList : RefPicList(slice.getColFromL0Flag()); const MotionInfo& mi = pColPic->cs->getMotionInfo( pos ); @@ -1789,7 +1816,18 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in Position posC1 = pu.Y().center(); Mv cColMv; +#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY + bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight); + SubPic curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos()); + if (curSubPic.getTreatedAsPicFlag()) + { + boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() && + (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom()); + } + if (boundaryCond) +#else if( ( ( posRB.x + pcv.minCUWidth ) < pcv.lumaWidth ) && ( ( posRB.y + pcv.minCUHeight ) < pcv.lumaHeight ) ) +#endif { int posYInCtu = posRB.y & pcv.maxCUHeightMask; if (posYInCtu + 4 < pcv.maxCUHeight) @@ -2104,7 +2142,18 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co bool C0Avail = false; Position posC1 = pu.Y().center(); Mv cColMv; +#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY + bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight); + SubPic curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos()); + if (curSubPic.getTreatedAsPicFlag()) + { + boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() && + (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom()); + } + if (boundaryCond) +#else if ( ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight) ) +#endif { int posYInCtu = posRB.y & pcv.maxCUHeightMask; if (posYInCtu + 4 < pcv.maxCUHeight) @@ -2681,7 +2730,18 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx Position posC0; bool C0Avail = false; +#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY + bool boundaryCond = ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight); + SubPic curSubPic = pu.cs->slice->getPPS()->getSubPicFromPos(pu.lumaPos()); + if (curSubPic.getTreatedAsPicFlag()) + { + boundaryCond = ((posRB.x + pcv.minCUWidth) <= curSubPic.getSubPicRight() && + (posRB.y + pcv.minCUHeight) <= curSubPic.getSubPicBottom()); + } + if (boundaryCond) +#else if ( ((posRB.x + pcv.minCUWidth) < pcv.lumaWidth) && ((posRB.y + pcv.minCUHeight) < pcv.lumaHeight) ) +#endif { int posYInCtu = posRB.y & pcv.maxCUHeightMask; if (posYInCtu + 4 < pcv.maxCUHeight) @@ -2871,7 +2931,20 @@ void clipColPos(int& posX, int& posY, const PredictionUnit& pu) int log2CtuSize = floorLog2(pu.cs->sps->getCTUSize()); int ctuX = ((puPos.x >> log2CtuSize) << log2CtuSize); int ctuY = ((puPos.y >> log2CtuSize) << log2CtuSize); +#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY + int horMax; + SubPic curSubPic = pu.cu->slice->getPPS()->getSubPicFromPos(puPos); + if (curSubPic.getTreatedAsPicFlag()) + { + horMax = std::min((int)curSubPic.getSubPicRight(), ctuX + (int)pu.cs->sps->getCTUSize() + 3); + } + else + { + horMax = std::min((int)pu.cs->pps->getPicWidthInLumaSamples() - 1, ctuX + (int)pu.cs->sps->getCTUSize() + 3); + } +#else int horMax = std::min( (int)pu.cs->pps->getPicWidthInLumaSamples() - 1, ctuX + (int)pu.cs->sps->getCTUSize() + 3 ); +#endif int horMin = std::max((int)0, ctuX); int verMax = std::min( (int)pu.cs->pps->getPicHeightInLumaSamples() - 1, ctuY + (int)pu.cs->sps->getCTUSize() - 1 ); int verMin = std::max((int)0, ctuY); diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index e13475ef6c10886d9562969009bae48d6abc9ca5..3807321f851979aa4cdd2aa63b62ca1156880703 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -66,6 +66,9 @@ namespace CU bool isSameSlice (const CodingUnit &cu, const CodingUnit &cu2); bool isSameTile (const CodingUnit &cu, const CodingUnit &cu2); bool isSameSliceAndTile (const CodingUnit &cu, const CodingUnit &cu2); +#if JVET_O1143_SUBPIC_BOUNDARY + bool isSameSubPic (const CodingUnit &cu, const CodingUnit &cu2); +#endif bool isLastSubCUOfCtu (const CodingUnit &cu); uint32_t getCtuAddr (const CodingUnit &cu); int predictQP (const CodingUnit& cu, const int prevQP ); diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index f44ebb6b39c0b3abeac9da257e54ce167de055e1..b7560efd5a32ccc677763d85285d277c2fc8f4ca 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -599,7 +599,7 @@ void DecLib::executeLoopFilters() m_cALF.ALFProcess(cs); } -#if SUBPIC_DECCHECK +#if JVET_O1143_SUBPIC_DECCHECK for (int i = 0; i < cs.pps->getNumSubPics(); i++) { // keep target subpic samples untouched, for other subpics mask their output sample value to 0 diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h index 5e8aef4978aed58794f72011d935bf6f67076a0c..31cd21d3b9c6a41abf69e6e526ffe0c1aec597d6 100644 --- a/source/Lib/DecoderLib/DecLib.h +++ b/source/Lib/DecoderLib/DecLib.h @@ -147,7 +147,7 @@ private: bool m_scalingListUpdateFlag; int m_PreScalingListAPSId; -#if SUBPIC_DECCHECK +#if JVET_O1143_SUBPIC_DECCHECK public: int m_targetSubPicIdx; #endif diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp index 9e4d1360f7ecba1201d193cf282e85e70cf90cac..762ddf16bca5d86ccdbebbc7df5b389a339a2021 100644 --- a/source/Lib/DecoderLib/DecSlice.cpp +++ b/source/Lib/DecoderLib/DecSlice.cpp @@ -143,6 +143,31 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb const unsigned maxCUSize = sps->getMaxCUWidth(); Position pos( ctuXPosInCtus*maxCUSize, ctuYPosInCtus*maxCUSize) ; UnitArea ctuArea(cs.area.chromaFormat, Area( pos.x, pos.y, maxCUSize, maxCUSize ) ); +#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY + SubPic curSubPic = slice->getPPS()->getSubPicFromPos(pos); + // padding/restore at slice level + if (curSubPic.getTreatedAsPicFlag() && ctuIdx==0) + { + int subPicX = (int)curSubPic.getSubPicLeft(); + int subPicY = (int)curSubPic.getSubPicTop(); + int subPicWidth = (int)curSubPic.getSubPicWidthInLumaSample(); + int subPicHeight = (int)curSubPic.getSubPicHeightInLumaSample(); + for (int rlist = REF_PIC_LIST_0; rlist < NUM_REF_PIC_LIST_01; rlist++) + { + int n = slice->getNumRefIdx((RefPicList)rlist); + for (int idx = 0; idx < n; idx++) + { + Picture *refPic = slice->getRefPic((RefPicList)rlist, idx); + if (!refPic->getSubPicSaved()) + { + refPic->saveSubPicBorder(refPic->getPOC(), subPicX, subPicY, subPicWidth, subPicHeight); + refPic->extendSubPicBorder(refPic->getPOC(), subPicX, subPicY, subPicWidth, subPicHeight); + refPic->setSubPicSaved(true); + } + } + } + } +#endif DTRACE_UPDATE( g_trace_ctx, std::make_pair( "ctu", ctuRsAddr ) ); @@ -232,6 +257,29 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb #endif subStrmId++; } +#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY + if (curSubPic.getTreatedAsPicFlag() && ctuIdx == (slice->getNumCtuInSlice() - 1)) + // for last Ctu in the slice + { + int subPicX = (int)curSubPic.getSubPicLeft(); + int subPicY = (int)curSubPic.getSubPicTop(); + int subPicWidth = (int)curSubPic.getSubPicWidthInLumaSample(); + int subPicHeight = (int)curSubPic.getSubPicHeightInLumaSample(); + for (int rlist = REF_PIC_LIST_0; rlist < NUM_REF_PIC_LIST_01; rlist++) + { + int n = slice->getNumRefIdx((RefPicList)rlist); + for (int idx = 0; idx < n; idx++) + { + Picture *refPic = slice->getRefPic((RefPicList)rlist, idx); + if (refPic->getSubPicSaved()) + { + refPic->restoreSubPicBorder(refPic->getPOC(), subPicX, subPicY, subPicWidth, subPicHeight); + refPic->setSubPicSaved(false); + } + } + } + } +#endif } // deallocate all created substreams, including internal buffers. diff --git a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp index 15ed5b0e24d0cf823d5a44eeb7d3cb83702b4fbe..44e214ff819d20d2b6a28fbe354fe48ca805ea44 100644 --- a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp +++ b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp @@ -1569,6 +1569,16 @@ void EncSampleAdaptiveOffset::deriveLoopFilterBoundaryAvailibility(CodingStructu isAboveAvail = (!isAboveAvail) ? false : CU::isSameTile(*cuCurr, *cuAbove); isAboveLeftAvail = (!isAboveLeftAvail) ? false : CU::isSameTile(*cuCurr, *cuAboveLeft); } + +#if JVET_O1143_LPF_ACROSS_SUBPIC_BOUNDARY + SubPic curSubPic = cs.pps->getSubPicFromCU(*cuCurr); + if (!curSubPic.getloopFilterAcrossEnabledFlag()) + { + isLeftAvail = (!isLeftAvail) ? false : CU::isSameSubPic(*cuCurr, *cuLeft); + isAboveAvail = (!isAboveAvail) ? false : CU::isSameSubPic(*cuCurr, *cuAbove); + isAboveLeftAvail = (!isAboveLeftAvail) ? false : CU::isSameSubPic(*cuCurr, *cuAboveLeft); + } +#endif } //! \} diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp index 525656424605f6c1b197df535824366f7e4fa894..449ba3af1d9f82708e8c138b0e5abecb2f179312 100644 --- a/source/Lib/EncoderLib/EncSlice.cpp +++ b/source/Lib/EncoderLib/EncSlice.cpp @@ -1462,7 +1462,32 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons cs.motionLut.lutIbc.resize(0); } +#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY + SubPic curSubPic = pcSlice->getPPS()->getSubPicFromPos(pos); + // padding/restore at slice level + if (curSubPic.getTreatedAsPicFlag() && ctuIdx == 0) + { + int subPicX = (int)curSubPic.getSubPicLeft(); + int subPicY = (int)curSubPic.getSubPicTop(); + int subPicWidth = (int)curSubPic.getSubPicWidthInLumaSample(); + int subPicHeight = (int)curSubPic.getSubPicHeightInLumaSample(); + for (int rlist = REF_PIC_LIST_0; rlist < NUM_REF_PIC_LIST_01; rlist++) + { + int n = pcSlice->getNumRefIdx((RefPicList)rlist); + for (int idx = 0; idx < n; idx++) + { + Picture *refPic = pcSlice->getRefPic((RefPicList)rlist, idx); + if (!refPic->getSubPicSaved()) + { + refPic->saveSubPicBorder(refPic->getPOC(), subPicX, subPicY, subPicWidth, subPicHeight); + refPic->extendSubPicBorder(refPic->getPOC(), subPicX, subPicY, subPicWidth, subPicHeight); + refPic->setSubPicSaved(true); + } + } + } + } +#endif if (cs.pps->ctuIsTileColBd( ctuXPosInCtus ) && cs.pps->ctuIsTileRowBd( ctuYPosInCtus )) { pCABACWriter->initCtxModels( *pcSlice ); @@ -1659,6 +1684,31 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons m_uiPicTotalBits += actualBits; m_uiPicDist = cs.dist; +#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY + // for last Ctu in the slice + if (curSubPic.getTreatedAsPicFlag() && ctuIdx == (pcSlice->getNumCtuInSlice() - 1)) + { + + int subPicX = (int)curSubPic.getSubPicLeft(); + int subPicY = (int)curSubPic.getSubPicTop(); + int subPicWidth = (int)curSubPic.getSubPicWidthInLumaSample(); + int subPicHeight = (int)curSubPic.getSubPicHeightInLumaSample(); + + for (int rlist = REF_PIC_LIST_0; rlist < NUM_REF_PIC_LIST_01; rlist++) + { + int n = pcSlice->getNumRefIdx((RefPicList)rlist); + for (int idx = 0; idx < n; idx++) + { + Picture *refPic = pcSlice->getRefPic((RefPicList)rlist, idx); + if (refPic->getSubPicSaved()) + { + refPic->restoreSubPicBorder(refPic->getPOC(), subPicX, subPicY, subPicWidth, subPicHeight); + refPic->setSubPicSaved(false); + } + } + } + } +#endif } // this is wpp exclusive section diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index 51ff99a7861f2842f10a4c8d09697415c6867e40..91fcfd1333db435b5df1dd5532b29c05c5ff5cd6 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -7984,7 +7984,17 @@ void InterSearch::xClipMv( Mv& rcMv, const Position& pos, const struct Size& siz int verMax = ( pps.getPicHeightInLumaSamples() + offset - (int)pos.y - 1 ) << mvShift; int verMin = ( -( int ) sps.getMaxCUHeight() - offset - ( int ) pos.y + 1 ) << mvShift; +#if JVET_O1143_MV_ACROSS_SUBPIC_BOUNDARY + SubPic curSubPic = pps.getSubPicFromPos(pos); + if (curSubPic.getTreatedAsPicFlag()) + { + horMax = (curSubPic.getSubPicWidthInLumaSample() + offset - (int)pos.x - 1) << mvShift; + horMin = (-(int)sps.getMaxCUWidth() - offset - ((int)pos.x - curSubPic.getSubPicLeft()) + 1) << mvShift; + verMax = (curSubPic.getSubPicHeightInLumaSample()+ offset - (int)pos.y - 1) << mvShift; + verMin = (-(int)sps.getMaxCUHeight() - offset - ((int)pos.y - curSubPic.getSubPicTop()) + 1) << mvShift; + } +#endif if( sps.getWrapAroundEnabledFlag() ) { int horMax = ( pps.getPicWidthInLumaSamples() + sps.getMaxCUWidth() - size.width + offset - (int)pos.x - 1 ) << mvShift;