diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp index d3bb0c7352c3282ca86f8e8980a1873862b29734..1ce77c7d870a540fe1d91e915747468b9b0d6319 100644 --- a/source/App/DecoderApp/DecApp.cpp +++ b/source/App/DecoderApp/DecApp.cpp @@ -604,6 +604,9 @@ void DecApp::xCreateDecLib() #endif m_cDecLib.m_targetSubPicIdx = this->m_targetSubPicIdx; m_cDecLib.initScalingList(); +#if GDR_LEAK_TEST + m_cDecLib.m_POC_RandomAccess = this->m_POC_RandomAccess; +#endif // GDR_LEAK_TEST } void DecApp::xDestroyDecLib() diff --git a/source/App/DecoderApp/DecAppCfg.cpp b/source/App/DecoderApp/DecAppCfg.cpp index 036d7f54b9b370a2a2a27ec0db9f6f845e0c90b8..5e9b41709032dde2a26dea04d1efbc434632fb94 100644 --- a/source/App/DecoderApp/DecAppCfg.cpp +++ b/source/App/DecoderApp/DecAppCfg.cpp @@ -121,6 +121,9 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] ) ("MCTSCheck", m_mctsCheck, false, "If enabled, the decoder checks for violations of mc_exact_sample_value_match_flag in Temporal MCTS ") ("targetSubPicIdx", m_targetSubPicIdx, 0, "Specify which subpicture shall be written to output, using subpic index, 0: disabled, subpicIdx=m_targetSubPicIdx-1 \n" ) ( "UpscaledOutput", m_upscaledOutput, 0, "Upscaled output for RPR" ) +#if GDR_LEAK_TEST + ("RandomAccessPos", m_POC_RandomAccess, 0, "POC of Random access picture\n" ) +#endif // GDR_LEAK_TEST ; po::setDefaults(opts); diff --git a/source/App/DecoderApp/DecAppCfg.h b/source/App/DecoderApp/DecAppCfg.h index 36b4699d73eb6fb9b1ef57e94757b89e94c6c59a..0b245acf6ced3925de676f53d7c3752f3ae8f684 100644 --- a/source/App/DecoderApp/DecAppCfg.h +++ b/source/App/DecoderApp/DecAppCfg.h @@ -88,6 +88,9 @@ protected: int m_upscaledOutput; ////< Output upscaled (2), decoded but in full resolution buffer (1) or decoded cropped (0, default) picture for RPR. int m_targetSubPicIdx; ///< Specify which subpicture shall be write to output, using subpicture index +#if GDR_LEAK_TEST + int m_POC_RandomAccess; ///< +#endif // GDR_LEAK_TEST public: DecAppCfg(); virtual ~DecAppCfg(); diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index bd0cf1bb8ae1bc4336b107cac9e29ddc6601faab..72e15cc4909afc176c3da23445a0e4b6dc1480a4 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -521,6 +521,14 @@ void EncApp::xInitLibCfg() //====== Coding Structure ======== m_cEncLib.setIntraPeriod ( m_iIntraPeriod ); +#if GDR_ENABLED + m_cEncLib.setGdrPeriod ( m_iGdrPeriod ); + m_cEncLib.setGdrPocStart ( m_iGdrPocStart ); + m_cEncLib.setGdrFrequency ( m_iGdrFrequency); + m_cEncLib.setStartWithGdr ( m_bStartWithGdr ); + m_cEncLib.setNoHashForGdr ( m_bNoHashForGdr ); + m_cEncLib.setGdrPicOutput ( m_bGdrPicOutput ); +#endif m_cEncLib.setDecodingRefreshType ( m_iDecodingRefreshType ); m_cEncLib.setGOPSize ( m_iGOPSize ); m_cEncLib.setDrapPeriod ( m_drapPeriod ); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index c34c73bfb40352515af3e1922c4a42a043031059..00d3cfdf28dd1a8fd945a665cf3b54f05997bf72 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -1006,6 +1006,14 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) // Coding structure paramters ("IntraPeriod,-ip", m_iIntraPeriod, -1, "Intra period in frames, (-1: only first frame)") +#if GDR_ENABLED + ("GdrPocStart", m_iGdrPocStart, -1, "GDR poc start") + ("GdrPeriod", m_iGdrPeriod, -1, "GDR period") + ("GdrFrequency", m_iGdrFrequency, -1, "GDR freqency") + ("StartWithGDR", m_bStartWithGdr, false, "Start bitstream with GDR") + ("NoHashforGDR", m_bNoHashForGdr, true, "No Hash for GDR") + ("GdrPicOutput", m_bGdrPicOutput, false, "Picture Output for GDR") +#endif ("DecodingRefreshType,-dr", m_iDecodingRefreshType, 0, "Intra refresh type (0:none 1:CRA 2:IDR 3:RecPointSEI)") ("GOPSize,g", m_iGOPSize, 1, "GOP size of temporal structure") ("DRAPPeriod", m_drapPeriod, 0, "DRAP period in frames (0: disable Dependent RAP indication SEI messages)") @@ -1597,6 +1605,37 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) } } +#if GDR_ENABLED + { + m_iDecodingRefreshType = 3; + + if (m_iGdrFrequency < 0) + m_iGdrFrequency = 2; + + if (m_iGdrPocStart < 0) + { + if (m_iIntraPeriod > 0) + m_iGdrPocStart = m_iIntraPeriod; + else + m_iGdrPocStart = m_iFrameRate * m_iGdrFrequency; + } + + if (m_iGdrPeriod < 0) + { + m_iGdrPeriod = m_iFrameRate; + } + + if (m_iIntraPeriod == -1) + { + m_iFrameRate = (m_iFrameRate == 0) ? 30 : m_iFrameRate; + if (m_iGdrPocStart % m_iFrameRate != 0) + m_iIntraPeriod = -1; + else + m_iIntraPeriod = m_iFrameRate * m_iGdrFrequency; + } + } +#endif + g_verbosity = MsgLevel( m_verbosity ); @@ -2204,7 +2243,12 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) } #endif +#if GDR_ENABLED + m_virtualBoundariesEnabledFlag = 1; + m_virtualBoundariesPresentFlag = 0; +#else m_virtualBoundariesEnabledFlag = 0; +#endif if( m_numVerVirtualBoundaries > 0 || m_numHorVirtualBoundaries > 0 ) m_virtualBoundariesEnabledFlag = 1; diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 3b97a4ee1dfa0968c76f86fc299370ea5179814f..13c0349817314508f3486ab4bfbe80bb9736850a 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -218,6 +218,14 @@ protected: bool m_noSubpicInfoConstraintFlag; // coding structure int m_iIntraPeriod; ///< period of I-slice (random access period) +#if GDR_ENABLED + int m_iGdrPocStart; + int m_iGdrPeriod; + int m_iGdrFrequency; + bool m_bStartWithGdr; + bool m_bNoHashForGdr; + bool m_bGdrPicOutput; +#endif int m_iDecodingRefreshType; ///< random access type int m_iGOPSize; ///< GOP size of hierarchical structure int m_drapPeriod; ///< period of dependent RAP pictures diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp index dbfdc3ee38d7963235e5f292f9f6d5a87a2cd1ae..4fcae23e1e113c5260a7b9163abc9467eaf43c8b 100644 --- a/source/Lib/CommonLib/CodingStructure.cpp +++ b/source/Lib/CommonLib/CodingStructure.cpp @@ -93,6 +93,10 @@ CodingStructure::CodingStructure(CUCache& cuCache, PUCache& puCache, TUCache& tu } m_motionBuf = nullptr; +#if GDR_ENABLED + picHeader = nullptr; +#endif + features.resize( NUM_ENC_FEATURES ); treeType = TREE_D; modeType = MODE_TYPE_ALL; @@ -131,7 +135,14 @@ void CodingStructure::destroy() delete[] m_motionBuf; m_motionBuf = nullptr; - +#if GDR_ENABLED + if (picHeader) + { + delete picHeader; + picHeader = nullptr; + } +#endif + m_tuCache.cache( tus ); m_puCache.cache( pus ); m_cuCache.cache( cus ); @@ -144,6 +155,567 @@ void CodingStructure::releaseIntermediateData() clearCUs(); } +#if GDR_ENABLED +bool CodingStructure::containRefresh(int begX, int endX) const +{ + if (begX == endX) + return false; + + const Area csArea = area.Y(); + const Area refreshArea = Area(begX, area.ly(), endX - begX, std::min(slice->getPPS()->getPicHeightInLumaSamples(), area.lheight())); + + if (csArea.contains(refreshArea)) + return true; + + return false; +} + +bool CodingStructure::overlapRefresh(int begX, int endX) const +{ + if (begX == endX) + return false; + + const Area csArea = area.Y(); + const Area refreshArea = Area(begX, area.ly(), endX - begX, area.lheight()); + + if (csArea.overlap(refreshArea)) + return true; + + return false; +} + +bool CodingStructure::overlapRefresh() const +{ + const int csX = area.lx(); + const int csWidth = area.lwidth(); + + bool ret = overlapRefresh(csX, csX + csWidth); + + return ret; +} + +bool CodingStructure::withinRefresh(int begX, int endX) const +{ + if (begX == endX) + return false; + + const Area csArea = area.Y(); + const Area refreshArea = Area(begX, area.ly(), endX - begX, area.lheight()); + + if (refreshArea.contains(csArea)) + return true; + + return false; +} + +bool CodingStructure::refreshCrossTTV(int begX, int endX) const +{ + const int csX = area.lx(); + const int csY = area.ly(); + const int csWidth = area.lwidth(); + const int csHeight = area.lheight(); + + const Area refreshArea = Area(begX, csY, endX - begX, csHeight); + + const Area csArea0 = Area(csX, csY, csWidth >> 2, csHeight); + const Area csArea1 = Area(csX + (csWidth >> 2), csY, csWidth >> 1, csHeight); + const Area csArea2 = Area(csX + (csWidth >> 2) + (csWidth >> 1), csY, csWidth >> 2, csHeight); + + bool overlap0 = csArea0.overlap(refreshArea); + bool overlap1 = csArea1.overlap(refreshArea); + bool overlap2 = csArea2.overlap(refreshArea); + + int sum = (overlap0 ? 1 : 0) + (overlap1 ? 1 : 0) + (overlap2 ? 1 : 0); + + if (0 < sum) + return true; + + return false; +} + +bool CodingStructure::refreshCrossBTV(int begX, int endX) const +{ + const int csX = area.lx(); + const int csY = area.ly(); + const int csWidth = area.lwidth(); + const int csHeight = area.lheight(); + + const Area refreshArea = Area(begX, csY, endX - begX, csHeight); + + const Area csArea0 = Area(csX, csY, (csWidth >> 1), csHeight); + const Area csArea1 = Area(csX + (csWidth >> 1), csY, (csWidth >> 1), csHeight); + + bool overlap0 = csArea0.overlap(refreshArea); + bool overlap1 = csArea1.overlap(refreshArea); + + int sum = (overlap0 ? 1 : 0) + (overlap1 ? 1 : 0); + + if (0 < sum) + return true; + + return false; +} + +bool CodingStructure::overlapDirty() const +{ + const Position topLeft = area.Y().topLeft(); + const Position topRight = area.Y().topRight(); + + bool insideLeft = isClean(topLeft, CHANNEL_TYPE_LUMA); + bool insideRight = isClean(topRight, CHANNEL_TYPE_LUMA); + + if (insideLeft != insideRight) + return true; + + return false; +} + +bool CodingStructure::dirtyCrossTTV() const +{ + const int csX = area.lx(); + const int csY = area.ly(); + const int csWidth = area.lwidth(); + const int csHeight = area.lheight(); + + const Area csArea0 = Area(csX, csY, csWidth >> 2, csHeight); + const Area csArea1 = Area(csX + (csWidth >> 2), csY, csWidth >> 1, csHeight); + const Area csArea2 = Area(csX + (csWidth >> 2) + (csWidth >> 1), csY, csWidth >> 2, csHeight); + + bool clean0 = isClean(csArea0, CHANNEL_TYPE_LUMA); + bool clean1 = isClean(csArea1, CHANNEL_TYPE_LUMA); + bool clean2 = isClean(csArea2, CHANNEL_TYPE_LUMA); + + bool allclean = clean0 && clean1 && clean2; + + if (allclean) + return false; + + return true; +} + +bool CodingStructure::dirtyCrossBTV() const +{ + const int csX = area.lx(); + const int csY = area.ly(); + const int csWidth = area.lwidth(); + const int csHeight = area.lheight(); + + const Area csArea0 = Area(csX, csY, (csWidth >> 1), csHeight); + const Area csArea1 = Area(csX + (csWidth >> 1), csY, (csWidth >> 1), csHeight); + + bool clean0 = isClean(csArea0, CHANNEL_TYPE_LUMA); + bool clean1 = isClean(csArea1, CHANNEL_TYPE_LUMA); + + bool allclean = clean0 && clean1; + + if (allclean) + return false; + + return true; +} +#endif + + + +#if GDR_ENABLED +bool CodingStructure::isClean(const Position &IntPos, Mv FracMv) const +{ + /* + 1. non gdr picture --> false; + 2. gdr picture + pos in clean area -> true + pos in dirty area -> false + */ + const Picture* const curPic = slice->getPic(); + + if (!curPic) + return false; + + PicHeader *curPh = curPic->cs->picHeader; + bool isCurGdrPicture = curPh->getInGdrPeriod(); + + if (isCurGdrPicture) + { + const int lumaPixelAway = 4; + const int chromaPixelAway = 5; + + const int iMvShift = MV_FRACTIONAL_BITS_INTERNAL; + const int iMvLumaFrac = (1 << iMvShift); + const int iMvChromaFrac = (iMvLumaFrac << 1); + + const bool isIntLumaMv = (FracMv.getHor() % iMvLumaFrac) == 0; + const bool isIntChromaMv = (FracMv.getHor() % iMvChromaFrac) == 0; + + const int scaledEndX = curPh->getVirtualBoundariesPosX(0) << iMvShift; + + + const Position OrigFracPos = Position(IntPos.x << iMvShift, IntPos.y << iMvShift); + const int lastLumaPos = ((OrigFracPos.x / iMvLumaFrac) * iMvLumaFrac) + FracMv.getHor() + (isIntLumaMv ? 0 : (lumaPixelAway << iMvShift)); + const int lastChromaPos = ((OrigFracPos.x / iMvChromaFrac) * iMvChromaFrac) + FracMv.getHor() + (isIntChromaMv ? 0 : (chromaPixelAway << iMvShift)); + + const int lastPelPos = std::max(lastLumaPos, lastChromaPos); + + if (lastPelPos < scaledEndX) + return true; + else + return false; + } + + return true; +} + +bool CodingStructure::isClean(const Position &IntPos, Mv FracMv, const Picture* const refPic) const +{ + /* + 1. non gdr picture --> false; + 2. gdr picture + pos in clean area -> true + pos in dirty area -> false + */ + if (!refPic) return false; + if (!refPic->cs) return false; + + PicHeader *refPh = refPic->cs->picHeader; + if (!refPh) return false; + + bool isRefGdrPicture = refPh->getInGdrPeriod(); + + if (isRefGdrPicture) + { + const int lumaPixelAway = 4; + const int chromaPixelAway = 5; + + const int iMvShift = MV_FRACTIONAL_BITS_INTERNAL; + const int iMvLumaFrac = (1 << iMvShift); + const int iMvChromaFrac = (iMvLumaFrac << 1); + + const bool isIntLumaMv = (FracMv.getHor() % iMvLumaFrac) == 0; + const bool isIntChromaMv = (FracMv.getHor() % iMvChromaFrac) == 0; + + const int scaledEndX = refPh->getVirtualBoundariesPosX(0) << iMvShift; + + const Position OrigFracPos = Position((IntPos.x) << iMvShift, IntPos.y << iMvShift); + const int lastLumaPos = ((OrigFracPos.x / iMvLumaFrac) * iMvLumaFrac) + FracMv.getHor() + (isIntLumaMv ? 0 : (lumaPixelAway << iMvShift)); + const int lastChromaPos = ((OrigFracPos.x / iMvChromaFrac) * iMvChromaFrac) + FracMv.getHor() + (isIntChromaMv ? 0 : (chromaPixelAway << iMvShift)); + + const int lastPelPos = std::max(lastLumaPos, lastChromaPos); + + if (lastPelPos < scaledEndX) + return true; + else + return false; + } + else + { + // refPic is normal picture + bool isCurGdrPicture = (slice->getPicHeader()->getNumVerVirtualBoundaries() > 0); + + if (isCurGdrPicture) + return false; + else + return true; + } +} + + +bool CodingStructure::isClean(const Position &IntPos, Mv FracMv, RefPicList e, int refIdx, int isProf) const +{ + /* + 1. non gdr picture --> false; + 2. gdr picture + pos in clean area -> true + pos in dirty area -> false + */ + if (refIdx < 0) return false; + + const Picture* const refPic = slice->getRefPic(e, refIdx); + const bool isExceedNumRef = (refIdx < slice->getNumRefIdx(e)) ? false : true; + if (!refPic || isExceedNumRef) return false; + if (!refPic->cs) return false; + + PicHeader *refPh = refPic->cs->picHeader; + + if (!refPh) return false; + + bool isRefGdrPicture = refPh->getInGdrPeriod(); + + if (isRefGdrPicture) + { + const int lumaPixelAway = 4 + (isProf << 0); + const int chromaPixelAway = 4 + (isProf << 1); + + const int iMvShift = MV_FRACTIONAL_BITS_INTERNAL; + const int iMvLumaFrac = (1 << iMvShift); + const int iMvChromaFrac = (iMvLumaFrac << 1); + + const bool isIntLumaMv = (FracMv.getHor() % iMvLumaFrac ) == 0; + const bool isIntChromaMv = isProf ? false : (FracMv.getHor() % iMvChromaFrac) == 0; + + const int scaledEndX = refPh->getVirtualBoundariesPosX(0) << iMvShift; + + + const Position OrigFracPos = Position((IntPos.x) << iMvShift, IntPos.y << iMvShift); + const int lastLumaPos = ((OrigFracPos.x / iMvLumaFrac) * iMvLumaFrac) + FracMv.getHor() + (isIntLumaMv ? 0 : (lumaPixelAway << iMvShift)); + const int lastChromaPos = ((OrigFracPos.x / iMvChromaFrac) * iMvChromaFrac) + FracMv.getHor() + (isIntChromaMv ? 0 : (chromaPixelAway << iMvShift)) ; + + const int lastPelPos = std::max(lastLumaPos, lastChromaPos); + + if (lastPelPos < scaledEndX) + return true; + else + return false; + } + else + { + // refPic is normal picture + bool isCurGdrPicture = (slice->getPicHeader()->getNumVerVirtualBoundaries() > 0); + + if (isCurGdrPicture) + return false; + else + return true; + } +} + +bool CodingStructure::isClean(const Position &IntPos, Mv FracMv, RefPicList e, int refIdx, bool ibc) const +{ + /* + 1. non gdr picture --> false; + 2. gdr picture + pos in clean area -> true + pos in dirty area -> false + */ + if (refIdx < 0) return false; + + Picture* refPic; + PicHeader *refPh; + + if (refIdx == MAX_NUM_REF) + refPic = slice->getPic(); + else + refPic = slice->getRefPic(e, refIdx); + + if (!refPic) return false; + + if (refIdx == MAX_NUM_REF) + { + refPh = picHeader; + } + else + { + if (refPic->cs) return false; + + refPh = refPic->cs->picHeader; + } + + if (!refPh) return false; + + bool isRefGdrPicture = refPh->getInGdrPeriod(); + + if (isRefGdrPicture) + { + const int lumaPixelAway = 4; + const int chromaPixelAway = 5; + + const int iMvShift = MV_FRACTIONAL_BITS_INTERNAL; + const int iMvLumaFrac = (1 << iMvShift); + const int iMvChromaFrac = (iMvLumaFrac << 1); + + const bool isIntLumaMv = (FracMv.getHor() % iMvLumaFrac) == 0; + const bool isIntChromaMv = (FracMv.getHor() % iMvChromaFrac) == 0; + + const int scaledEndX = refPh->getVirtualBoundariesPosX(0) << iMvShift; + + const Position OrigFracPos = Position((IntPos.x) << iMvShift, IntPos.y << iMvShift); + const int lastLumaPos = ((OrigFracPos.x / iMvLumaFrac) * iMvLumaFrac) + FracMv.getHor() + (isIntLumaMv ? 0 : (lumaPixelAway << iMvShift)); + const int lastChromaPos = ((OrigFracPos.x / iMvChromaFrac) * iMvChromaFrac) + FracMv.getHor() + (isIntChromaMv ? 0 : (chromaPixelAway << iMvShift)); + + const int lastPelPos = std::max(lastLumaPos, lastChromaPos); + + if (lastPelPos < scaledEndX) + return true; + else + return false; + } + else + { + // refPic is normal picture + bool isCurGdrPicture = (slice->getPicHeader()->getNumVerVirtualBoundaries() > 0); + + if (isCurGdrPicture) + return false; + else + return true; + } +} + + +bool CodingStructure::isClean(const Position &IntPos, RefPicList e, int refIdx) const +{ + /* + 1. non gdr picture --> false; + 2. gdr picture + pos in clean area -> true + pos in dirty area -> false + */ + const Picture* const refPic = slice->getRefPic(e, refIdx); + + if (!refPic || refIdx < 0) + return false; + + PicHeader *refPh = refPic->cs->picHeader; + bool isRefGdrPicture = refPh->getInGdrPeriod(); + + if (isRefGdrPicture) + { + if (IntPos.x < refPh->getVirtualBoundariesPosX(0)) + { + return true; + } + else + return false; + } + else + { + // refPic is normal picture + bool isCurGdrPicture = (slice->getPicHeader()->getNumVerVirtualBoundaries() > 0); + + if (isCurGdrPicture) + return false; + else + return true; + } +} + +bool CodingStructure::isClean(const Position &IntPos, const Picture* const refPic) const +{ + if (!refPic) + return false; + + PicHeader *refPh = refPic->cs->picHeader; + bool isRefGdrPicture = refPh->getInGdrPeriod(); + + if (isRefGdrPicture) + { + if (IntPos.x < refPh->getVirtualBoundariesPosX(0)) + { + return true; + } + else + return false; + } + else + { + // refPic is normal picture + bool isCurGdrPicture = (slice->getPicHeader()->getNumVerVirtualBoundaries() > 0); + + if (isCurGdrPicture) + return false; + else + return true; + } +} + +bool CodingStructure::isClean(const int Intx, const int Inty, const ChannelType effChType) const +{ + /* + 1. non gdr picture --> false; + 2. gdr picture + pos in clean area -> true + pos in dirty area -> false + */ + PicHeader *curPh = picHeader; + bool isCurGdrPicture = curPh->getInGdrPeriod(); + if (isCurGdrPicture) + { + int virboundary_endx = curPh->getVirtualBoundariesPosX(0); + + virboundary_endx = virboundary_endx >> effChType; + if (Intx < virboundary_endx) + return true; + else + return false; + } + + return true; +} + +bool CodingStructure::isClean(const Position &IntPos, const ChannelType effChType) const +{ + bool ret = isClean(IntPos.x, IntPos.y, effChType); + + return ret; +} + +bool CodingStructure::isClean(const Area &area, const ChannelType effChType) const +{ + Position pTopLeft = area.topLeft(); + Position pTopRight = area.topRight(); + Position pBotLeft = area.bottomLeft(); + Position pBotRight = area.bottomRight(); + + bool bTopLeft = isClean(pTopLeft, effChType); + bool bTopRight = isClean(pTopRight, effChType); + bool bBotLeft = isClean(pBotLeft, effChType); + bool bBotRight = isClean(pBotRight, effChType); + + return bTopLeft && bTopRight && bBotLeft && bBotRight; +} + +bool CodingStructure::isClean(const ChannelType effChType) const +{ + bool ret = isClean(area.Y(), effChType); + + return ret; +} + +bool CodingStructure::isSubPuClean(PredictionUnit &pu, const Mv *mv) const +{ + MotionBuf mb = pu.getMotionBuf(); + + if (pu.cu->affine) + { + Position puPos = pu.Y().pos(); + Size subPuSize = Size(4, 4); + + int isProf = 1; + + for (int y = 0; y < mb.height; y++) + { + for (int x = 0; x < mb.width; x++) + { + + MotionInfo mi = mb.at(x, y); + Position subPuPos = Position{puPos.x + (x << 2), puPos.y + (y << 2)}; + Area subPuArea = Area(subPuPos, subPuSize); + Position subPuTR = subPuArea.topRight(); + + // check if SubPu with L0 is Out of boundary + if (mi.refIdx[0] >= 0) + { + if (!isClean(subPuTR, mi.mv[0], REF_PIC_LIST_0, mi.refIdx[0], isProf)) + { + return false; + } + } + + // check if SubPu wiht L1 is Out of boundary + if (mi.refIdx[1] >= 0) + { + if (!isClean(subPuTR, mi.mv[1], REF_PIC_LIST_1, mi.refIdx[1], isProf)) + { + return false; + } + } + } + } + } + + return true; +} +#endif + + bool CodingStructure::isDecomp( const Position &pos, const ChannelType effChType ) { if( area.blocks[effChType].contains( pos ) ) @@ -868,6 +1440,10 @@ void CodingStructure::create(const ChromaFormat &_chromaFormat, const Area& _are return; } +#if GDR_ENABLED + picHeader = new PicHeader(); +#endif + m_reco.create( area ); m_pred.create( area ); m_resi.create( area ); @@ -883,6 +1459,10 @@ void CodingStructure::create(const UnitArea& _unit, const bool isTopLayer, const return; } +#if GDR_ENABLED + picHeader = new PicHeader(); +#endif + m_reco.create( area ); m_pred.create( area ); m_resi.create( area ); @@ -1157,7 +1737,17 @@ void CodingStructure::initSubStructure( CodingStructure& subStruct, const Channe subStruct.sps = sps; subStruct.vps = vps; subStruct.pps = pps; +#if GDR_ENABLED + if (!subStruct.picHeader) + { + subStruct.picHeader = new PicHeader; + subStruct.picHeader->initPicHeader(); + } + *subStruct.picHeader = *picHeader; +#else subStruct.picHeader = picHeader; +#endif + memcpy(subStruct.alfApss, alfApss, sizeof(alfApss)); subStruct.lmcsAps = lmcsAps; diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h index 918fc1922ebb39376073e754b9423dcafed13c05..e5a9cfcfbd0eaf24fbd1833989b6fcdc42f1fdeb 100644 --- a/source/Lib/CommonLib/CodingStructure.h +++ b/source/Lib/CommonLib/CodingStructure.h @@ -104,6 +104,39 @@ public: void destroy(); void releaseIntermediateData(); +#if GDR_ENABLED + bool containRefresh(int begX, int endX) const; + bool overlapRefresh() const; + bool overlapRefresh(int begX, int endX) const; + bool withinRefresh(int begX, int endX) const; + + bool refreshCrossTTV(int begX, int endX) const; + bool refreshCrossBTV(int begX, int endX) const; + bool refreshCrossQT(int begX, int endX) const; + + bool refreshFitTTV(int begX, int endX) const; + bool refreshFitBTV(int begX, int endX) const; + bool refreshFitQT(int begX, int endX) const; + + bool overlapDirty() const; + bool dirtyCrossTTV() const; + bool dirtyCrossBTV() const; +#endif + +#if GDR_ENABLED + bool isClean(const ChannelType effChType) const; + bool isClean(const Position &IntPos, RefPicList e, int refIdx) const; + bool isClean(const Position &IntPos, const Picture* const ref_pic) const; + bool isClean(const Position &IntPos, Mv FracMv) const; + bool isClean(const Position &IntPos, Mv FracMv, const Picture* const refPic) const; + bool isClean(const Position &IntPos, Mv FracMv, RefPicList e, int refIdx, int isProf=0) const; + bool isClean(const Position &IntPos, Mv FracMv, RefPicList e, int refIdx, bool ibc) const; + bool isClean(const Position &IntPos, const ChannelType effChType) const; + bool isClean(const int x, const int y, const ChannelType effChType) const; + bool isClean(const Area &area, const ChannelType effChType) const; + + bool isSubPuClean(PredictionUnit &pu, const Mv *mv) const; +#endif void rebindPicBufs(); void createCoeffs(const bool isPLTused); diff --git a/source/Lib/CommonLib/Common.h b/source/Lib/CommonLib/Common.h index 174bede28a6b3b96d387e98d9b1c1da4e797db1c..52db0a72a93a5fd255c54235984b43b25853cc08 100644 --- a/source/Lib/CommonLib/Common.h +++ b/source/Lib/CommonLib/Common.h @@ -97,6 +97,31 @@ struct Area : public Position, public Size bool contains(const Position &_pos) const { return (_pos.x >= x) && (_pos.x < (x + width)) && (_pos.y >= y) && (_pos.y < (y + height)); } bool contains(const Area &_area) const { return contains(_area.pos()) && contains(_area.bottomRight()); } +#if GDR_ENABLED + bool overlap(const Area &_area) const + { + Area thisArea = Area(pos(), size()); + + if (contains(_area)) + return false; + + if (_area.contains(thisArea)) + return false; + + bool btopLeft = contains(_area.topLeft()); + bool btopRight = contains(_area.topRight()); + bool bbotLeft = contains(_area.bottomLeft()); + bool bbotRight = contains(_area.bottomRight()); + + int sum = (btopLeft ? 1 : 0) + (btopRight ? 1 : 0) + (bbotLeft ? 1 : 0) + (bbotRight ? 1 : 0); + + if (0 < sum && sum < 4) + return true; + + return false; + } +#endif + bool operator!=(const Area &other) const { return (Size::operator!=(other)) || (Position::operator!=(other)); } bool operator==(const Area &other) const { return (Size::operator==(other)) && (Position::operator==(other)); } }; diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp index 7b056b1283e83652608621bd91c356640baaada1..4077e9b6ea85e5215a3d6624ea7b0ff69ea4ff93 100644 --- a/source/Lib/CommonLib/ContextModelling.cpp +++ b/source/Lib/CommonLib/ContextModelling.cpp @@ -365,6 +365,25 @@ void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx ) pu.mvpIdx [REF_PIC_LIST_1] = NOT_VALID; pu.mvpNum [REF_PIC_LIST_0] = NOT_VALID; pu.mvpNum [REF_PIC_LIST_1] = NOT_VALID; +#if GDR_ENABLED + CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + + if (isEncodeClean) + { + Mv mv0 = pu.mv[REF_PIC_LIST_0]; + Mv mv1 = pu.mv[REF_PIC_LIST_1]; + + int refIdx0 = pu.refIdx[REF_PIC_LIST_0]; + int refIdx1 = pu.refIdx[REF_PIC_LIST_1]; + + pu.mvSolid[REF_PIC_LIST_0] = mvSolid[(candIdx << 1) + 0]; + pu.mvSolid[REF_PIC_LIST_1] = mvSolid[(candIdx << 1) + 1]; + pu.mvValid[REF_PIC_LIST_0] = cs.isClean(pu.Y().topRight(), mv0, REF_PIC_LIST_0, refIdx0); + pu.mvValid[REF_PIC_LIST_1] = cs.isClean(pu.Y().topRight(), mv1, REF_PIC_LIST_1, refIdx1); + } +#endif + if (CU::isIBC(*pu.cu)) { pu.bv = pu.mv[REF_PIC_LIST_0]; @@ -389,6 +408,11 @@ void MergeCtx::setMmvdMergeCandiInfo(PredictionUnit& pu, int candIdx) int fPosPosition = 0; Mv tempMv[2]; +#if GDR_ENABLED + const CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif + tempIdx = candIdx; fPosGroup = tempIdx / (MMVD_BASE_MV_NUM * MMVD_MAX_REFINE_NUM); tempIdx = tempIdx - fPosGroup * (MMVD_BASE_MV_NUM * MMVD_MAX_REFINE_NUM); @@ -478,6 +502,25 @@ void MergeCtx::setMmvdMergeCandiInfo(PredictionUnit& pu, int candIdx) pu.refIdx[REF_PIC_LIST_0] = refList0; pu.mv[REF_PIC_LIST_1] = mmvdBaseMv[fPosBaseIdx][1].mv + tempMv[1]; pu.refIdx[REF_PIC_LIST_1] = refList1; +#if GDR_ENABLED + if (isEncodeClean) + { + Mv mv0 = pu.mv[REF_PIC_LIST_0]; + Mv mv1 = pu.mv[REF_PIC_LIST_1]; + + int refIdx0 = pu.refIdx[REF_PIC_LIST_0]; + int refIdx1 = pu.refIdx[REF_PIC_LIST_1]; + + mmvdValid[fPosBaseIdx][0] = cs.isClean(pu.Y().topRight(), mv0, REF_PIC_LIST_0, refIdx0); + mmvdValid[fPosBaseIdx][1] = cs.isClean(pu.Y().topRight(), mv1, REF_PIC_LIST_1, refIdx1); + + pu.mvSolid[REF_PIC_LIST_0] = mmvdSolid[fPosBaseIdx][0]; + pu.mvSolid[REF_PIC_LIST_1] = mmvdSolid[fPosBaseIdx][1]; + + pu.mvValid[REF_PIC_LIST_0] = mmvdValid[fPosBaseIdx][0]; + pu.mvValid[REF_PIC_LIST_1] = mmvdValid[fPosBaseIdx][1]; + } +#endif } else if (refList0 != -1) { @@ -502,6 +545,26 @@ void MergeCtx::setMmvdMergeCandiInfo(PredictionUnit& pu, int candIdx) pu.refIdx[REF_PIC_LIST_0] = refList0; pu.mv[REF_PIC_LIST_1] = Mv(0, 0); pu.refIdx[REF_PIC_LIST_1] = -1; + +#if GDR_ENABLED + if (isEncodeClean) + { + Mv mv0 = pu.mv[REF_PIC_LIST_0]; + //Mv mv1 = pu.mv[REF_PIC_LIST_1]; + + int refIdx0 = pu.refIdx[REF_PIC_LIST_0]; + //int refIdx1 = pu.refIdx[REF_PIC_LIST_1]; + + pu.mvSolid[REF_PIC_LIST_0] = mmvdSolid[fPosBaseIdx][0]; + pu.mvSolid[REF_PIC_LIST_1] = true; + + mmvdValid[fPosBaseIdx][0] = cs.isClean(pu.Y().topRight(), mv0, REF_PIC_LIST_0, refIdx0); + mmvdValid[fPosBaseIdx][1] = true; + + pu.mvValid[REF_PIC_LIST_0] = mmvdValid[fPosBaseIdx][0]; + pu.mvValid[REF_PIC_LIST_1] = true; + } +#endif } else if (refList1 != -1) { @@ -526,6 +589,25 @@ void MergeCtx::setMmvdMergeCandiInfo(PredictionUnit& pu, int candIdx) pu.refIdx[REF_PIC_LIST_0] = -1; pu.mv[REF_PIC_LIST_1] = mmvdBaseMv[fPosBaseIdx][1].mv + tempMv[1]; pu.refIdx[REF_PIC_LIST_1] = refList1; +#if GDR_ENABLED + if (isEncodeClean) + { + // Mv mv0 = pu.mv[REF_PIC_LIST_0]; + Mv mv1 = pu.mv[REF_PIC_LIST_1]; + + // int refIdx0 = pu.refIdx[REF_PIC_LIST_0]; + int refIdx1 = pu.refIdx[REF_PIC_LIST_1]; + + mmvdValid[fPosBaseIdx][0] = true; + mmvdValid[fPosBaseIdx][1] = cs.isClean(pu.Y().topRight(), mv1, REF_PIC_LIST_1, refIdx1); + + pu.mvSolid[REF_PIC_LIST_0] = true; + pu.mvSolid[REF_PIC_LIST_1] = mmvdSolid[fPosBaseIdx][1]; + + pu.mvValid[REF_PIC_LIST_0] = true; + pu.mvValid[REF_PIC_LIST_1] = mmvdValid[fPosBaseIdx][1]; + } +#endif } pu.mmvdMergeFlag = true; diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h index 5ada3236eff299f6b265b0b3a1be9e3c11af69ee..9d863b0167285ef76daca88a15b572f8d3520f55 100644 --- a/source/Lib/CommonLib/ContextModelling.h +++ b/source/Lib/CommonLib/ContextModelling.h @@ -461,6 +461,13 @@ public: ~MergeCtx() {} public: MvField mvFieldNeighbours [ MRG_MAX_NUM_CANDS << 1 ]; // double length for mv of both lists +#if GDR_ENABLED + // note : check if source of mv and mv itself is valid + bool mvSolid [MRG_MAX_NUM_CANDS << 1]; + bool mvValid [MRG_MAX_NUM_CANDS << 1]; + Position mvPos [MRG_MAX_NUM_CANDS << 1]; + MvpType mvType [MRG_MAX_NUM_CANDS << 1]; +#endif uint8_t BcwIdx [ MRG_MAX_NUM_CANDS ]; unsigned char interDirNeighbours[ MRG_MAX_NUM_CANDS ]; MergeType mrgTypeNeighbours [ MRG_MAX_NUM_CANDS ]; @@ -470,6 +477,10 @@ public: MotionBuf subPuMvpMiBuf; MotionBuf subPuMvpExtMiBuf; MvField mmvdBaseMv[MMVD_BASE_MV_NUM][2]; +#if GDR_ENABLED + bool mmvdSolid[MMVD_BASE_MV_NUM][2]; + bool mmvdValid[MMVD_BASE_MV_NUM][2]; +#endif void setMmvdMergeCandiInfo(PredictionUnit& pu, int candIdx); bool mmvdUseAltHpelIf [ MMVD_BASE_MV_NUM ]; bool useAltHpelIf [ MRG_MAX_NUM_CANDS ]; @@ -483,6 +494,10 @@ public: ~AffineMergeCtx() {} public: MvField mvFieldNeighbours[AFFINE_MRG_MAX_NUM_CANDS << 1][3]; // double length for mv of both lists +#if GDR_ENABLED + bool mvSolid[AFFINE_MRG_MAX_NUM_CANDS << 1][3]; + bool mvValid[AFFINE_MRG_MAX_NUM_CANDS << 1][3]; +#endif unsigned char interDirNeighbours[AFFINE_MRG_MAX_NUM_CANDS]; EAffineModel affineType[AFFINE_MRG_MAX_NUM_CANDS]; uint8_t BcwIdx[AFFINE_MRG_MAX_NUM_CANDS]; diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp index a6d47243d2293b8d7c4d0d5a361be72aeaa675b3..932bf8bbb6d8c7c0646660c724385c52cb559c1a 100644 --- a/source/Lib/CommonLib/InterPrediction.cpp +++ b/source/Lib/CommonLib/InterPrediction.cpp @@ -878,7 +878,11 @@ bool InterPrediction::isSubblockVectorSpreadOverLimit( int a, int b, int c, int return false; } +#if GDR_ENABLED +bool InterPrediction::xPredAffineBlk(const ComponentID &compID, const PredictionUnit &pu, const Picture *refPic, const Mv *_mv, PelUnitBuf &dstPic, const bool &bi, const ClpRng &clpRng, bool genChromaMv, const std::pair<int, int> scalingRatio) +#else void InterPrediction::xPredAffineBlk(const ComponentID &compID, const PredictionUnit &pu, const Picture *refPic, const Mv *_mv, PelUnitBuf &dstPic, const bool &bi, const ClpRng &clpRng, bool genChromaMv, const std::pair<int, int> scalingRatio) +#endif { JVET_J0090_SET_REF_PICTURE( refPic, compID ); @@ -889,6 +893,13 @@ void InterPrediction::xPredAffineBlk(const ComponentID &compID, const Prediction Mv mvLT =_mv[0]; Mv mvRT =_mv[1]; Mv mvLB =_mv[2]; +#if GDR_ENABLED + bool allOk = true; + const CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + const int pux = pu.lx(); + const int puy = pu.ly(); +#endif // get affine sub-block width and height const int width = pu.Y().width; @@ -1113,6 +1124,16 @@ void InterPrediction::xPredAffineBlk(const ComponentID &compID, const Prediction iMvScaleTmpVer = tmpMv.getVer(); } } +#if GDR_ENABLED + if (isEncodeClean) + { + Position subPuPos = Position(pux + w + blockWidth, puy + h + blockHeight); + Mv subPuMv = Mv(iMvScaleTmpHor, iMvScaleTmpVer); + bool puClean = cs.isClean(subPuPos, subPuMv, refPic); + + allOk = allOk && puClean; + } +#endif } else { @@ -1133,6 +1154,17 @@ void InterPrediction::xPredAffineBlk(const ComponentID &compID, const Prediction } iMvScaleTmpHor = curMv.hor; iMvScaleTmpVer = curMv.ver; + +#if GDR_ENABLED + if (isEncodeClean) + { + Position subPuPos = Position(pux + (w + blockWidth) * 2, puy + (h + blockHeight) * 2); + Mv subPuMv = Mv(iMvScaleTmpHor, iMvScaleTmpVer); + bool puClean = cs.isClean(subPuPos, subPuMv, refPic); + + allOk = allOk && puClean; + } +#endif } if( xPredInterBlkRPR( scalingRatio, *pu.cs->pps, CompArea( compID, chFmt, pu.blocks[compID].offset( w, h ), Size( blockWidth, blockHeight ) ), refPic, Mv( iMvScaleTmpHor, iMvScaleTmpVer ), dstBuf.buf + w + h * dstBuf.stride, dstBuf.stride, bi, wrapRef, clpRng, 2 ) ) @@ -1237,6 +1269,9 @@ void InterPrediction::xPredAffineBlk(const ComponentID &compID, const Prediction } } } +#if GDR_ENABLED + return allOk; +#endif } void InterPrediction::applyBiOptFlow(const PredictionUnit &pu, const CPelUnitBuf &yuvSrc0, const CPelUnitBuf &yuvSrc1, const int &refIdx0, const int &refIdx1, PelUnitBuf &yuvDst, const BitDepths &clipBitDepths) diff --git a/source/Lib/CommonLib/InterPrediction.h b/source/Lib/CommonLib/InterPrediction.h index 0ff9d1169773ecd7c2508b0a002948503b8b0755..0c9a69509b2e2d53fd977022d1f869233da7d91d 100644 --- a/source/Lib/CommonLib/InterPrediction.h +++ b/source/Lib/CommonLib/InterPrediction.h @@ -137,7 +137,11 @@ protected: void xCalcBIOPar (const Pel* srcY0Temp, const Pel* srcY1Temp, const Pel* gradX0, const Pel* gradX1, const Pel* gradY0, const Pel* gradY1, int* dotProductTemp1, int* dotProductTemp2, int* dotProductTemp3, int* dotProductTemp5, int* dotProductTemp6, const int src0Stride, const int src1Stride, const int gradStride, const int widthG, const int heightG, int bitDepth); void xCalcBlkGradient (int sx, int sy, int *arraysGx2, int *arraysGxGy, int *arraysGxdI, int *arraysGy2, int *arraysGydI, int &sGx2, int &sGy2, int &sGxGy, int &sGxdI, int &sGydI, int width, int height, int unitSize); void xWeightedAverage ( const PredictionUnit& pu, const CPelUnitBuf& pcYuvSrc0, const CPelUnitBuf& pcYuvSrc1, PelUnitBuf& pcYuvDst, const BitDepths& clipBitDepths, const ClpRngs& clpRngs, const bool& bioApplied, const bool lumaOnly = false, const bool chromaOnly = false, PelUnitBuf* yuvDstTmp = NULL ); +#if GDR_ENABLED + bool xPredAffineBlk ( const ComponentID& compID, const PredictionUnit& pu, const Picture* refPic, const Mv* _mv, PelUnitBuf& dstPic, const bool& bi, const ClpRng& clpRng, const bool genChromaMv = false, const std::pair<int, int> scalingRatio = SCALE_1X ); +#else void xPredAffineBlk ( const ComponentID& compID, const PredictionUnit& pu, const Picture* refPic, const Mv* _mv, PelUnitBuf& dstPic, const bool& bi, const ClpRng& clpRng, const bool genChromaMv = false, const std::pair<int, int> scalingRatio = SCALE_1X ); +#endif static bool xCheckIdenticalMotion( const PredictionUnit& pu ); diff --git a/source/Lib/CommonLib/MotionInfo.h b/source/Lib/CommonLib/MotionInfo.h index 1e67d2ec559a0be2c00b4a3777d3150eea50bd97..1aad0ce534214909cf6eaafade2ecbff6f07d7c3 100644 --- a/source/Lib/CommonLib/MotionInfo.h +++ b/source/Lib/CommonLib/MotionInfo.h @@ -48,12 +48,43 @@ // ==================================================================================================================== // Type definition // ==================================================================================================================== +#if GDR_ENABLED +enum MvpType +{ + MVP_LEFT, + MVP_ABOVE, + MVP_ABOVE_RIGHT, + MVP_BELOW_LEFT, + MVP_ABOVE_LEFT, + + MVP_BELOW_RIGHT, + MVP_COMPOSITE, + + MVP_TMVP_C0, + MVP_TMVP_C1, + MVP_HMVP, + MVP_ZERO, + + AFFINE_INHERIT, + AFFINE_INHERIT_LB_RB, + + NUM_MVPTYPES +}; +#endif /// parameters for AMVP struct AMVPInfo { Mv mvCand[ AMVP_MAX_NUM_CANDS_MEM ]; ///< array of motion vector predictor candidates unsigned numCand; ///< number of motion vector predictor candidates +#if GDR_ENABLED + bool allCandSolidInAbove; + bool mvSolid[AMVP_MAX_NUM_CANDS_MEM]; + bool mvValid[AMVP_MAX_NUM_CANDS_MEM]; + + Position mvPos[AMVP_MAX_NUM_CANDS_MEM]; + MvpType mvType[AMVP_MAX_NUM_CANDS_MEM]; +#endif }; struct AffineAMVPInfo @@ -62,6 +93,25 @@ struct AffineAMVPInfo Mv mvCandRT[ AMVP_MAX_NUM_CANDS_MEM ]; ///< array of affine motion vector predictor candidates for right-top corner Mv mvCandLB[ AMVP_MAX_NUM_CANDS_MEM ]; ///< array of affine motion vector predictor candidates for left-bottom corner unsigned numCand; ///< number of motion vector predictor candidates +#if GDR_ENABLED + bool allCandSolidInAbove; + + bool mvSolidLT[AMVP_MAX_NUM_CANDS_MEM]; + bool mvSolidRT[AMVP_MAX_NUM_CANDS_MEM]; + bool mvSolidLB[AMVP_MAX_NUM_CANDS_MEM]; + + bool mvValidLT[AMVP_MAX_NUM_CANDS_MEM]; + bool mvValidRT[AMVP_MAX_NUM_CANDS_MEM]; + bool mvValidLB[AMVP_MAX_NUM_CANDS_MEM]; + + MvpType mvTypeLT[AMVP_MAX_NUM_CANDS_MEM]; + MvpType mvTypeRT[AMVP_MAX_NUM_CANDS_MEM]; + MvpType mvTypeLB[AMVP_MAX_NUM_CANDS_MEM]; + + Position mvPosLT[AMVP_MAX_NUM_CANDS_MEM]; + Position mvPosRT[AMVP_MAX_NUM_CANDS_MEM]; + Position mvPosLB[AMVP_MAX_NUM_CANDS_MEM]; +#endif }; // ==================================================================================================================== @@ -109,6 +159,11 @@ struct MotionInfo int16_t refIdx [ NUM_REF_PIC_LIST_01 ]; uint8_t BcwIdx; Mv bv; +#if GDR_ENABLED + bool soClean; // source Position is clean/dirty + Position soPos; // source Position of Mv +#endif + MotionInfo() : isInter(false), isIBCmot(false), interDir(0), useAltHpelIf(false), sliceIdx(0), refIdx{ NOT_VALID, NOT_VALID }, BcwIdx(0) { } // ensure that MotionInfo(0) produces '\x000....' bit pattern - needed to work with AreaBuf - don't use this constructor for anything else MotionInfo(int i) : isInter(i != 0), isIBCmot(false), interDir(0), useAltHpelIf(false), sliceIdx(0), refIdx{ 0, 0 }, BcwIdx(0) { CHECKD(i != 0, "The argument for this constructor has to be '0'"); } @@ -149,12 +204,20 @@ class BcwMotionParam bool m_readOnly[2][33]; // 2 RefLists, 33 RefFrams Mv m_mv[2][33]; Distortion m_dist[2][33]; + +#if GDR_ENABLED + bool m_mvSolid[2][33]; +#endif bool m_readOnlyAffine[2][2][33]; Mv m_mvAffine[2][2][33][3]; Distortion m_distAffine[2][2][33]; int m_mvpIdx[2][2][33]; +#if GDR_ENABLED + bool m_mvAffineSolid[2][2][33][3]; +#endif + public: void reset() @@ -176,6 +239,14 @@ public: memset(m_readOnlyAffine, false, 2 * 2 * 33 * sizeof(bool)); memset(m_distAffine, -1, 2 * 2 * 33 * sizeof(Distortion)); memset( m_mvpIdx, 0, 2 * 2 * 33 * sizeof( int ) ); + +#if GDR_ENABLED + memset(m_mvSolid, true, 2 * 2 * 33 * sizeof(bool)); +#endif + +#if GDR_ENABLED + memset(m_mvAffineSolid, true, 2 * 2 * 33 * sizeof(bool)); +#endif } void setReadMode(bool b, uint32_t uiRefList, uint32_t uiRefIdx) { m_readOnly[uiRefList][uiRefIdx] = b; } @@ -192,12 +263,30 @@ public: m_dist[uiRefList][uiRefIdx] = uiDist; } +#if GDR_ENABLED + void copyFrom(Mv& rcMv, bool& rcMvSolid, Distortion uiDist, uint32_t uiRefList, uint32_t uiRefIdx) + { + m_mv[uiRefList][uiRefIdx] = rcMv; + m_dist[uiRefList][uiRefIdx] = uiDist; + m_mvSolid[uiRefList][uiRefIdx] = rcMvSolid; + } +#endif + void copyTo(Mv& rcMv, Distortion& ruiDist, uint32_t uiRefList, uint32_t uiRefIdx) { rcMv = m_mv[uiRefList][uiRefIdx]; ruiDist = m_dist[uiRefList][uiRefIdx]; } +#if GDR_ENABLED + void copyTo(Mv& rcMv, bool& rcMvSolid, Distortion& ruiDist, uint32_t uiRefList, uint32_t uiRefIdx) + { + rcMv = m_mv[uiRefList][uiRefIdx]; + ruiDist = m_dist[uiRefList][uiRefIdx]; + rcMvSolid = m_mvSolid[uiRefList][uiRefIdx]; + } +#endif + Mv& getAffineMv(uint32_t uiRefList, uint32_t uiRefIdx, uint32_t uiAffineMvIdx, int bP4) { return m_mvAffine[bP4][uiRefList][uiRefIdx][uiAffineMvIdx]; } void copyAffineMvFrom(Mv(&racAffineMvs)[3], Distortion uiDist, uint32_t uiRefList, uint32_t uiRefIdx, int bP4 @@ -217,6 +306,26 @@ public: ruiDist = m_distAffine[bP4][uiRefList][uiRefIdx]; mvpIdx = m_mvpIdx[bP4][uiRefList][uiRefIdx]; } + +#if GDR_ENABLED + void copyAffineMvFrom(Mv(&racAffineMvs)[3], bool(&racAffineMvsSolid)[3], Distortion uiDist, uint32_t uiRefList, uint32_t uiRefIdx, int bP4, const int mvpIdx) + { + memcpy(m_mvAffine[bP4][uiRefList][uiRefIdx], racAffineMvs, 3 * sizeof(Mv)); + memcpy(m_mvAffineSolid[bP4][uiRefList][uiRefIdx], racAffineMvsSolid, 3 * sizeof(bool)); + m_distAffine[bP4][uiRefList][uiRefIdx] = uiDist; + m_mvpIdx[bP4][uiRefList][uiRefIdx] = mvpIdx; + } +#endif + +#if GDR_ENABLED + void copyAffineMvTo(Mv acAffineMvs[3], bool acAffineMvsSolid[3], Distortion& ruiDist, uint32_t uiRefList, uint32_t uiRefIdx, int bP4, int& mvpIdx) + { + memcpy(acAffineMvs, m_mvAffine[bP4][uiRefList][uiRefIdx], 3 * sizeof(Mv)); + memcpy(acAffineMvsSolid, m_mvAffineSolid[bP4][uiRefList][uiRefIdx], 3 * sizeof(bool)); + ruiDist = m_distAffine[bP4][uiRefList][uiRefIdx]; + mvpIdx = m_mvpIdx[bP4][uiRefList][uiRefIdx]; + } +#endif }; struct LutMotionCand { diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index 00980d4c580cb12c034081fe026c514e42f0d778..d0b7a02887331341a7a45fd381cf953010a666d6 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -2741,6 +2741,10 @@ void PicHeader::initPicHeader() m_RPL1.setLtrpInSliceHeaderFlag(0); m_alfApsIdsLuma.resize(0); +#if GDR_ENABLED + m_InGdrPeriod = false; + m_LastGdrPeriodPoc = -1; +#endif } const WPScalingParam *PicHeader::getWpScaling(const RefPicList refPicList, const int refIdx) const diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index bcd0333c122bb480aff149ebd4b29abfd155245c..4f48b87e39294fab4a092d244ce5213aa224481f 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -2332,6 +2332,10 @@ private: bool m_nonReferencePictureFlag; //!< non-reference picture flag bool m_gdrOrIrapPicFlag; //!< gdr or irap picture flag bool m_gdrPicFlag; //!< gradual decoding refresh picture flag +#if GDR_ENABLED + bool m_InGdrPeriod; + int m_LastGdrPeriodPoc; +#endif uint32_t m_recoveryPocCnt; //!< recovery POC count bool m_noOutputBeforeRecoveryFlag; //!< NoOutputBeforeRecoveryFlag bool m_handleCraAsCvsStartFlag; //!< HandleCraAsCvsStartFlag @@ -2418,6 +2422,10 @@ public: bool getGdrOrIrapPicFlag() const { return m_gdrOrIrapPicFlag; } void setGdrPicFlag( bool b ) { m_gdrPicFlag = b; } bool getGdrPicFlag() const { return m_gdrPicFlag; } +#if GDR_ENABLED + void setInGdrPeriod(bool b) { m_InGdrPeriod = b; } + bool getInGdrPeriod() const { return m_InGdrPeriod; } +#endif void setRecoveryPocCnt( uint32_t u ) { m_recoveryPocCnt = u; } uint32_t getRecoveryPocCnt() const { return m_recoveryPocCnt; } void setSPSId( uint32_t u ) { m_spsId = u; } @@ -2657,7 +2665,11 @@ private: const SPS* m_pcSPS; const PPS* m_pcPPS; Picture* m_pcPic; +#if GDR_ENABLED + PicHeader* m_pcPicHeader; //!< pointer to picture header structure +#else const PicHeader* m_pcPicHeader; //!< pointer to picture header structure +#endif bool m_colFromL0Flag; // collocated picture from List0 flag @@ -2711,8 +2723,13 @@ public: virtual ~Slice(); void initSlice(); void inheritFromPicHeader( PicHeader *picHeader, const PPS *pps, const SPS *sps ); +#if GDR_ENABLED + void setPicHeader(PicHeader* pcPicHeader) { m_pcPicHeader = pcPicHeader; } + PicHeader* getPicHeader() const { return m_pcPicHeader; } +#else void setPicHeader( const PicHeader* pcPicHeader ) { m_pcPicHeader = pcPicHeader; } const PicHeader* getPicHeader() const { return m_pcPicHeader; } +#endif int getRefIdx4MVPair( RefPicList eCurRefPicList, int nCurRefIdx ); @@ -2844,6 +2861,9 @@ public: bool isIntra() const { return m_eSliceType == I_SLICE; } bool isInterB() const { return m_eSliceType == B_SLICE; } bool isInterP() const { return m_eSliceType == P_SLICE; } +#if GDR_ENABLED + bool isInterGDR() const { return (m_eSliceType == B_SLICE && m_eNalUnitType == NAL_UNIT_CODED_SLICE_GDR); } +#endif bool getEnableDRAPSEI () const { return m_enableDRAPSEI; } void setEnableDRAPSEI ( bool b ) { m_enableDRAPSEI = b; } diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 67fceef085bdd69715b3b3e7c8b8cbd232847eaf..96fc0572c1472788f0a169edc98e78143acfc019 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -53,6 +53,13 @@ #define PRINT_WPSNR 1 +#define GDR_ENABLED 1 + +#if GDR_ENABLED +#define GDR_LEAK_TEST 1 +#define GDR_ENC_TRACE 0 +#define GDR_DEC_TRACE 0 +#endif // clang-format off diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index 8b48488152eddfb15b2fa7591e5b19efaecff767..8f9787c6cf69d206445dc46e8a91b63100163fa9 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -557,6 +557,10 @@ void PredictionUnit::initData() for ( uint32_t j = 0; j < 3; j++ ) { mvAffi[i][j].setZero(); +#if GDR_ENABLED + mvAffiSolid[i][j] = true; + mvAffiValid[i][j] = true; +#endif } } ciipFlag = false; diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index 430f6e8dcfc71021c917a001774bedf3b81180fc..b6b0c44e4c537477c49b7cd00f68f368626f91ee 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -390,12 +390,25 @@ struct InterPredictionData uint8_t mvpNum [NUM_REF_PIC_LIST_01]; Mv mvd [NUM_REF_PIC_LIST_01]; Mv mv [NUM_REF_PIC_LIST_01]; +#if GDR_ENABLED + bool mvSolid[NUM_REF_PIC_LIST_01]; + bool mvValid[NUM_REF_PIC_LIST_01]; + bool mvpSolid[NUM_REF_PIC_LIST_01]; + MvpType mvpType[NUM_REF_PIC_LIST_01]; + Position mvpPos[NUM_REF_PIC_LIST_01]; +#endif int16_t refIdx [NUM_REF_PIC_LIST_01]; MergeType mergeType; bool mvRefine; Mv mvdL0SubPu[MAX_NUM_SUBCU_DMVR]; Mv mvdAffi [NUM_REF_PIC_LIST_01][3]; Mv mvAffi[NUM_REF_PIC_LIST_01][3]; +#if GDR_ENABLED + bool mvAffiSolid[NUM_REF_PIC_LIST_01][3]; + bool mvAffiValid[NUM_REF_PIC_LIST_01][3]; + MvpType mvAffiType[NUM_REF_PIC_LIST_01][3]; + Position mvAffiPos[NUM_REF_PIC_LIST_01][3]; +#endif bool ciipFlag; Mv bv; // block vector for IBC diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 5674ef66ada17132faa195b83dc29a83fd7bbfa5..44c4c97717a9046c681434e6f1861cfb9922e031 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -387,6 +387,10 @@ void CU::saveMotionInHMVP( const CodingUnit& cu, const bool isToBeDone ) { MotionInfo mi = pu.getMotionInfo(); +#if GDR_ENABLED + mi.soPos = pu.lumaPos(); + mi.soClean = pu.cs->isClean(mi.soPos, CHANNEL_TYPE_LUMA); +#endif mi.BcwIdx = (mi.interDir == 3) ? cu.BcwIdx : BCW_DEFAULT; const unsigned log2ParallelMergeLevel = (pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2); @@ -855,7 +859,14 @@ int PU::getWideAngle( const TransformUnit &tu, const uint32_t dirMode, const Com bool PU::addMergeHMVPCand(const CodingStructure &cs, MergeCtx &mrgCtx, const int &mrgCandIdx, const uint32_t maxNumMergeCandMin1, int &cnt, const bool isAvailableA1, const MotionInfo miLeft, const bool isAvailableB1, const MotionInfo miAbove, +#if GDR_ENABLED + const bool ibcFlag, const bool isGt4x4 + , const PredictionUnit &pu + , bool &allCandSolidInAbove +) +#else const bool ibcFlag, const bool isGt4x4) +#endif { const Slice& slice = *cs.slice; MotionInfo miNeighbor; @@ -863,9 +874,26 @@ bool PU::addMergeHMVPCand(const CodingStructure &cs, MergeCtx &mrgCtx, const int auto &lut = ibcFlag ? cs.motionLut.lutIbc : cs.motionLut.lut; int num_avai_candInLUT = (int)lut.size(); +#if GDR_ENABLED + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + + bool vbOnCtuBoundary = true; + if (isEncodeClean) + { + vbOnCtuBoundary = (pu.cs->picHeader->getNumVerVirtualBoundaries() == 0) || (pu.cs->picHeader->getVirtualBoundariesPosX(0) % pu.cs->sps->getMaxCUWidth() == 0); + allCandSolidInAbove = allCandSolidInAbove && vbOnCtuBoundary; + } +#endif for (int mrgIdx = 1; mrgIdx <= num_avai_candInLUT; mrgIdx++) { miNeighbor = lut[num_avai_candInLUT - mrgIdx]; +#if GDR_ENABLED + Position soPos = Position(0, 0); + if (isEncodeClean) + { + soPos = miNeighbor.soPos; + } +#endif if ( mrgIdx > 2 || ((mrgIdx > 1 || !isGt4x4) && ibcFlag) || ((!isAvailableA1 || (miLeft != miNeighbor)) && (!isAvailableB1 || (miAbove != miNeighbor))) ) @@ -875,9 +903,28 @@ bool PU::addMergeHMVPCand(const CodingStructure &cs, MergeCtx &mrgCtx, const int mrgCtx.BcwIdx [cnt] = (miNeighbor.interDir == 3) ? miNeighbor.BcwIdx : BCW_DEFAULT; mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miNeighbor.mv[0], miNeighbor.refIdx[0]); +#if GDR_ENABLED + if (isEncodeClean) + { + // note : cannot gaurantee the order/value in the lut if any of the lut is in dirty area + mrgCtx.mvPos[(cnt << 1) + 0] = soPos; + mrgCtx.mvSolid[(cnt << 1) + 0] = allCandSolidInAbove && vbOnCtuBoundary; + mrgCtx.mvValid[(cnt << 1) + 0] = cs.isClean(pu.Y().bottomRight(), miNeighbor.mv[0], REF_PIC_LIST_0, miNeighbor.refIdx[0]); + allCandSolidInAbove = allCandSolidInAbove && vbOnCtuBoundary; + } +#endif if (slice.isInterB()) { mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miNeighbor.mv[1], miNeighbor.refIdx[1]); +#if GDR_ENABLED + if (isEncodeClean) + { + mrgCtx.mvPos[(cnt << 1) + 1] = soPos; + mrgCtx.mvSolid[(cnt << 1) + 1] = allCandSolidInAbove && vbOnCtuBoundary; + mrgCtx.mvValid[(cnt << 1) + 1] = cs.isClean(pu.Y().bottomRight(), miNeighbor.mv[1], REF_PIC_LIST_1, miNeighbor.refIdx[1]); + allCandSolidInAbove = allCandSolidInAbove && vbOnCtuBoundary; + } +#endif } if (mrgCandIdx == cnt) @@ -905,6 +952,11 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const { const CodingStructure &cs = *pu.cs; const uint32_t maxNumMergeCand = pu.cs->sps->getMaxNumIBCMergeCand(); +#if GDR_ENABLED + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + bool allCandSolidInAbove = true; +#endif + for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui) { mrgCtx.BcwIdx[ui] = BCW_DEFAULT; @@ -912,6 +964,15 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const mrgCtx.mrgTypeNeighbours[ui] = MRG_TYPE_IBC; mrgCtx.mvFieldNeighbours[ui * 2].refIdx = NOT_VALID; mrgCtx.mvFieldNeighbours[ui * 2 + 1].refIdx = NOT_VALID; +#if GDR_ENABLED + if (isEncodeClean) + { + mrgCtx.mvSolid[(ui << 1) + 0] = true; + mrgCtx.mvSolid[(ui << 1) + 1] = true; + mrgCtx.mvValid[(ui << 1) + 0] = true; + mrgCtx.mvValid[(ui << 1) + 1] = true; + } +#endif mrgCtx.useAltHpelIf[ui] = false; } @@ -937,6 +998,12 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const mrgCtx.interDirNeighbours[cnt] = miLeft.interDir; // get Mv from Left mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miLeft.mv[0], miLeft.refIdx[0]); +#if GDR_ENABLED + if (isEncodeClean) + { + mrgCtx.mvSolid[(cnt << 1) + 0] = cs.isClean(posLB.offset(-1, 0), pu.chType); + } +#endif if (mrgCandIdx == cnt) { return; @@ -963,6 +1030,12 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const mrgCtx.interDirNeighbours[cnt] = miAbove.interDir; // get Mv from Above mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAbove.mv[0], miAbove.refIdx[0]); +#if GDR_ENABLED + if (isEncodeClean) + { + mrgCtx.mvSolid[(cnt << 1) + 0] = cs.isClean(posRT.offset(0, -1), pu.chType); + } +#endif if (mrgCandIdx == cnt) { return; @@ -980,8 +1053,19 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const if (cnt != maxNumMergeCand) { +#if GDR_ENABLED + bool allCandSolidInAbove = true; + bool bFound = addMergeHMVPCand(cs, mrgCtx, mrgCandIdx, maxNumMergeCand, cnt + , isAvailableA1, miLeft, isAvailableB1, miAbove + , true + , isGt4x4 + , pu + , allCandSolidInAbove + ); +#else bool bFound = addMergeHMVPCand(cs, mrgCtx, mrgCandIdx, maxNumMergeCand, cnt, isAvailableA1, miLeft, isAvailableB1, miAbove, true, isGt4x4); +#endif if (bFound) { @@ -993,6 +1077,14 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const { mrgCtx.mvFieldNeighbours[cnt * 2].setMvField(Mv(0, 0), MAX_NUM_REF); mrgCtx.interDirNeighbours[cnt] = 1; +#if GDR_ENABLED + // GDR: zero mv(0,0) + if (isEncodeClean) + { + mrgCtx.mvSolid[cnt << 1] = true && allCandSolidInAbove; + allCandSolidInAbove = true && allCandSolidInAbove; + } +#endif if (mrgCandIdx == cnt) { return; @@ -1012,6 +1104,10 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, const Slice &slice = *pu.cs->slice; const uint32_t maxNumMergeCand = pu.cs->sps->getMaxNumMergeCand(); CHECK (maxNumMergeCand > MRG_MAX_NUM_CANDS, "selected maximum number of merge candidate exceeds global limit"); +#if GDR_ENABLED + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + bool allCandSolidInAbove = true; +#endif for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui) { mrgCtx.BcwIdx[ui] = BCW_DEFAULT; @@ -1019,6 +1115,17 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, mrgCtx.mrgTypeNeighbours [ui] = MRG_TYPE_DEFAULT_N; mrgCtx.mvFieldNeighbours[(ui << 1) ].refIdx = NOT_VALID; mrgCtx.mvFieldNeighbours[(ui << 1) + 1].refIdx = NOT_VALID; +#if GDR_ENABLED + if (isEncodeClean) + { + mrgCtx.mvSolid[(ui << 1) + 0] = true; + mrgCtx.mvSolid[(ui << 1) + 1] = true; + mrgCtx.mvValid[(ui << 1) + 0] = true; + mrgCtx.mvValid[(ui << 1) + 1] = true; + mrgCtx.mvPos[(ui << 1) + 0] = Position(0, 0); + mrgCtx.mvPos[(ui << 1) + 1] = Position(0, 0); + } +#endif mrgCtx.useAltHpelIf[ui] = false; } @@ -1048,9 +1155,27 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAbove->cu->BcwIdx : BCW_DEFAULT; mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAbove.mv[0], miAbove.refIdx[0]); +#if GDR_ENABLED + if (isEncodeClean) + { + Position pos = puAbove->lumaPos(); + mrgCtx.mvPos[(cnt << 1) + 0] = pos; + mrgCtx.mvSolid[(cnt << 1) + 0] = cs.isClean(pos, pu.chType); + mrgCtx.mvValid[(cnt << 1) + 0] = cs.isClean(pu.Y().bottomRight(), miAbove.mv[0], REF_PIC_LIST_0, miAbove.refIdx[0]); + } +#endif if (slice.isInterB()) { mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miAbove.mv[1], miAbove.refIdx[1]); +#if GDR_ENABLED + if (isEncodeClean) + { + Position pos = puAbove->lumaPos(); + mrgCtx.mvPos[(cnt << 1) + 1] = pos; + mrgCtx.mvSolid[(cnt << 1) + 1] = cs.isClean(pos, pu.chType); + mrgCtx.mvValid[(cnt << 1) + 1] = cs.isClean(pu.Y().bottomRight(), miAbove.mv[1], REF_PIC_LIST_1, miAbove.refIdx[1]); + } +#endif } if (mrgCandIdx == cnt) { @@ -1083,10 +1208,28 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeft->cu->BcwIdx : BCW_DEFAULT; // get Mv from Left mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miLeft.mv[0], miLeft.refIdx[0]); +#if GDR_ENABLED + if (isEncodeClean) + { + Position pos = puLeft->lumaPos(); + mrgCtx.mvPos[(cnt << 1) + 0] = pos; + mrgCtx.mvSolid[(cnt << 1) + 0] = cs.isClean(pos, pu.chType); + mrgCtx.mvValid[(cnt << 1) + 0] = cs.isClean(pu.Y().bottomRight(), miLeft.mv[0], REF_PIC_LIST_0, miLeft.refIdx[0]); + } +#endif if (slice.isInterB()) { mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miLeft.mv[1], miLeft.refIdx[1]); +#if GDR_ENABLED + if (isEncodeClean) + { + Position pos = puLeft->lumaPos(); + mrgCtx.mvPos[(cnt << 1) + 1] = pos; + mrgCtx.mvSolid[(cnt << 1) + 1] = cs.isClean(pos, pu.chType); + mrgCtx.mvValid[(cnt << 1) + 1] = cs.isClean(pu.Y().bottomRight(), miLeft.mv[1], REF_PIC_LIST_1, miLeft.refIdx[1]); + } +#endif } if (mrgCandIdx == cnt) { @@ -1121,10 +1264,28 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, // get Mv from Above-right mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveRight->cu->BcwIdx : BCW_DEFAULT; mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveRight.mv[0], miAboveRight.refIdx[0] ); +#if GDR_ENABLED + if (isEncodeClean) + { + Position pos = puAboveRight->lumaPos(); + mrgCtx.mvPos[(cnt << 1) + 0] = pos; + mrgCtx.mvSolid[(cnt << 1) + 0] = cs.isClean(pos, pu.chType); + mrgCtx.mvValid[(cnt << 1) + 0] = cs.isClean(pu.Y().bottomRight(), miAboveRight.mv[0], REF_PIC_LIST_0, miAboveRight.refIdx[0]); + } +#endif if( slice.isInterB() ) { mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveRight.mv[1], miAboveRight.refIdx[1] ); +#if GDR_ENABLED + if (isEncodeClean) + { + Position pos = puAboveRight->lumaPos(); + mrgCtx.mvPos[(cnt << 1) + 1] = pos; + mrgCtx.mvSolid[(cnt << 1) + 1] = cs.isClean(pos, pu.chType); + mrgCtx.mvValid[(cnt << 1) + 1] = cs.isClean(pu.Y().bottomRight(), miAboveRight.mv[1], REF_PIC_LIST_1, miAboveRight.refIdx[1]); + } +#endif } if (mrgCandIdx == cnt) @@ -1158,10 +1319,28 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeftBottom->cu->BcwIdx : BCW_DEFAULT; // get Mv from Bottom-Left mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miBelowLeft.mv[0], miBelowLeft.refIdx[0] ); +#if GDR_ENABLED + if (isEncodeClean) + { + Position pos = puLeftBottom->lumaPos(); + mrgCtx.mvPos[(cnt << 1) + 0] = pos; + mrgCtx.mvSolid[(cnt << 1) + 0] = cs.isClean(pos, pu.chType); + mrgCtx.mvValid[(cnt << 1) + 0] = cs.isClean(pu.Y().bottomRight(), miBelowLeft.mv[0], REF_PIC_LIST_0, miBelowLeft.refIdx[0]); + } +#endif if( slice.isInterB() ) { mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miBelowLeft.mv[1], miBelowLeft.refIdx[1] ); +#if GDR_ENABLED + if (isEncodeClean) + { + Position pos = puLeftBottom->lumaPos(); + mrgCtx.mvPos[(cnt << 1) + 1] = pos; + mrgCtx.mvSolid[(cnt << 1) + 1] = cs.isClean(pos, pu.chType); + mrgCtx.mvValid[(cnt << 1) + 1] = cs.isClean(pu.Y().bottomRight(), miBelowLeft.mv[1], REF_PIC_LIST_1, miBelowLeft.refIdx[1]); + } +#endif } if (mrgCandIdx == cnt) @@ -1198,10 +1377,28 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveLeft->cu->BcwIdx : BCW_DEFAULT; // get Mv from Above-Left mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveLeft.mv[0], miAboveLeft.refIdx[0] ); +#if GDR_ENABLED + if (isEncodeClean) + { + Position pos = puAboveLeft->lumaPos(); + mrgCtx.mvPos[(cnt << 1) + 0] = pos; + mrgCtx.mvSolid[(cnt << 1) + 0] = cs.isClean(pos, pu.chType); + mrgCtx.mvValid[(cnt << 1) + 0] = cs.isClean(pu.Y().bottomRight(), miAboveLeft.mv[0], REF_PIC_LIST_0, miAboveLeft.refIdx[0]); + } +#endif if( slice.isInterB() ) { mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveLeft.mv[1], miAboveLeft.refIdx[1] ); +#if GDR_ENABLED + if (isEncodeClean) + { + Position pos = puAboveLeft->lumaPos(); + mrgCtx.mvPos[(cnt << 1) + 1] = pos; + mrgCtx.mvSolid[(cnt << 1) + 1] = cs.isClean(pos, pu.chType); + mrgCtx.mvValid[(cnt << 1) + 1] = cs.isClean(pu.Y().bottomRight(), miAboveLeft.mv[1], REF_PIC_LIST_1, miAboveLeft.refIdx[1]); + } +#endif } if (mrgCandIdx == cnt) @@ -1225,6 +1422,12 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, // offset the pos to be sure to "point" to the same position the uiAbsPartIdx would've pointed to Position posRB = pu.Y().bottomRight().offset( -3, -3 ); const PreCalcValues& pcv = *cs.pcv; +#if GDR_ENABLED + bool posC0inCurPic_solid = true; + bool posC1inCurPic_solid = true; + bool posC0inRefPic_solid = true; + bool posC1inRefPic_solid = true; +#endif Position posC0; Position posC1 = pu.Y().center(); @@ -1256,6 +1459,24 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, { dir |= 1; mrgCtx.mvFieldNeighbours[2 * uiArrayAddr].setMvField(cColMv, iRefIdx); +#if GDR_ENABLED + if (isEncodeClean) + { + Mv ccMv; + + posC0inCurPic_solid = cs.isClean(posC0, CHANNEL_TYPE_LUMA); + posC1inCurPic_solid = cs.isClean(posC1, CHANNEL_TYPE_LUMA); + posC0inRefPic_solid = cs.isClean(posC0, REF_PIC_LIST_0, iRefIdx); + posC1inRefPic_solid = cs.isClean(posC1, REF_PIC_LIST_0, iRefIdx); + + bool isMVP0exist = C0Avail && getColocatedMVP(pu, REF_PIC_LIST_0, posC0, ccMv, iRefIdx, false); + + Position pos = isMVP0exist ? posC0 : posC1; + mrgCtx.mvPos[2 * uiArrayAddr] = pos; + mrgCtx.mvSolid[2 * uiArrayAddr] = isMVP0exist ? (posC0inCurPic_solid && posC0inRefPic_solid) : (posC1inCurPic_solid && posC1inRefPic_solid); + mrgCtx.mvValid[2 * uiArrayAddr] = cs.isClean(pu.Y().bottomRight(), ccMv, REF_PIC_LIST_0, iRefIdx); + } +#endif } if (slice.isInterB()) @@ -1266,6 +1487,25 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, { dir |= 2; mrgCtx.mvFieldNeighbours[2 * uiArrayAddr + 1].setMvField(cColMv, iRefIdx); +#if GDR_ENABLED + if (isEncodeClean) + { + Mv ccMv; + + posC0inCurPic_solid = cs.isClean(posC0, CHANNEL_TYPE_LUMA); + posC1inCurPic_solid = cs.isClean(posC1, CHANNEL_TYPE_LUMA); + posC0inRefPic_solid = cs.isClean(posC0, REF_PIC_LIST_1, iRefIdx); + posC1inRefPic_solid = cs.isClean(posC1, REF_PIC_LIST_1, iRefIdx); + + bool isMVP0exist = C0Avail && getColocatedMVP(pu, REF_PIC_LIST_1, posC0, ccMv, iRefIdx, false); + + Position pos = isMVP0exist ? posC0 : posC1; + mrgCtx.mvPos[2 * uiArrayAddr + 1] = pos; + mrgCtx.mvSolid[2 * uiArrayAddr + 1] = isMVP0exist ? (posC0inCurPic_solid && posC0inRefPic_solid) : (posC1inCurPic_solid && posC1inRefPic_solid); + mrgCtx.mvValid[2 * uiArrayAddr + 1] = cs.isClean(pu.Y().bottomRight(), ccMv, REF_PIC_LIST_1, iRefIdx); + + } +#endif } } @@ -1297,8 +1537,16 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, if (cnt != maxNumMergeCandMin1) { bool isGt4x4 = true; +#if GDR_ENABLED + allCandSolidInAbove = true; +#endif +#if GDR_ENABLED + bool bFound = addMergeHMVPCand(cs, mrgCtx, mrgCandIdx, maxNumMergeCandMin1, cnt, isAvailableA1, miLeft, + isAvailableB1, miAbove, CU::isIBC(*pu.cu), isGt4x4, pu, allCandSolidInAbove); +#else bool bFound = addMergeHMVPCand(cs, mrgCtx, mrgCandIdx, maxNumMergeCandMin1, cnt, isAvailableA1, miLeft, isAvailableB1, miAbove, CU::isIBC(*pu.cu), isGt4x4); +#endif if (bFound) { @@ -1321,6 +1569,12 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, const short refIdxI = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].refIdx; const short refIdxJ = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].refIdx; +#if GDR_ENABLED + // GDR: Pairwise average candidate + bool mvI_solid = mrgCtx.mvSolid[0 * 2 + refListId]; + bool mvJ_solid = mrgCtx.mvSolid[1 * 2 + refListId]; + bool mv_solid = true; +#endif // both MVs are invalid, skip if( (refIdxI == NOT_VALID) && (refIdxJ == NOT_VALID) ) { @@ -1340,17 +1594,53 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, roundAffineMv(avgMv.hor, avgMv.ver, 1); mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( avgMv, refIdxI ); +#if GDR_ENABLED + // GDR: Pairwise single I,J candidate + if (isEncodeClean) + { + mv_solid = mvI_solid && mvJ_solid && allCandSolidInAbove; + + mrgCtx.mvPos[cnt * 2 + refListId] = Position(0, 0); + mrgCtx.mvSolid[cnt * 2 + refListId] = mv_solid && allCandSolidInAbove; + mrgCtx.mvValid[cnt * 2 + refListId] = cs.isClean(pu.Y().bottomRight(), avgMv, (RefPicList)refListId, refIdxI); + allCandSolidInAbove = mv_solid && allCandSolidInAbove; + } +#endif } // only one MV is valid, take the only one MV else if( refIdxI != NOT_VALID ) { Mv singleMv = mrgCtx.mvFieldNeighbours[0 * 2 + refListId].mv; mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( singleMv, refIdxI ); +#if GDR_ENABLED + // GDR: Pairwise single I,J candidate + if (isEncodeClean) + { + mv_solid = mvI_solid && allCandSolidInAbove; + + mrgCtx.mvPos[cnt * 2 + refListId] = Position(0, 0); + mrgCtx.mvSolid[cnt * 2 + refListId] = mv_solid && allCandSolidInAbove; + mrgCtx.mvValid[cnt * 2 + refListId] = cs.isClean(pu.Y().bottomRight(), singleMv, (RefPicList)refListId, refIdxI); + allCandSolidInAbove = mv_solid && allCandSolidInAbove; + } +#endif } else if( refIdxJ != NOT_VALID ) { Mv singleMv = mrgCtx.mvFieldNeighbours[1 * 2 + refListId].mv; mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField( singleMv, refIdxJ ); +#if GDR_ENABLED + // GDR: Pairwise single I,J candidate + if (isEncodeClean) + { + mv_solid = mvJ_solid && allCandSolidInAbove; + + mrgCtx.mvPos[cnt * 2 + refListId] = Position(0, 0); + mrgCtx.mvSolid[cnt * 2 + refListId] = mv_solid && allCandSolidInAbove; + mrgCtx.mvValid[cnt * 2 + refListId] = cs.isClean(pu.Y().bottomRight(), singleMv, (RefPicList)refListId, refIdxJ); + allCandSolidInAbove = mv_solid && allCandSolidInAbove; + } +#endif } } @@ -1381,10 +1671,31 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx, mrgCtx.mvFieldNeighbours [uiArrayAddr << 1].setMvField(Mv(0, 0), r); mrgCtx.useAltHpelIf[uiArrayAddr] = false; +#if GDR_ENABLED + // GDR: zero mv(0,0) + if (isEncodeClean) + { + mrgCtx.mvPos[uiArrayAddr << 1] = Position(0, 0); + mrgCtx.mvSolid[uiArrayAddr << 1] = true && allCandSolidInAbove; + mrgCtx.mvValid[uiArrayAddr << 1] = cs.isClean(pu.Y().bottomRight(), Mv(0, 0), REF_PIC_LIST_0, r); + allCandSolidInAbove = true && allCandSolidInAbove; + } +#endif if (slice.isInterB()) { mrgCtx.interDirNeighbours [ uiArrayAddr ] = 3; mrgCtx.mvFieldNeighbours [(uiArrayAddr << 1) + 1].setMvField(Mv(0, 0), r); +#if GDR_ENABLED + // GDR: zero mv(0,0) + if (isEncodeClean) + { + + mrgCtx.mvPos[(uiArrayAddr << 1) + 1] = Position(0, 0); + mrgCtx.mvSolid[(uiArrayAddr << 1) + 1] = true && allCandSolidInAbove; + mrgCtx.mvValid[(uiArrayAddr << 1) + 1] = cs.isClean(pu.Y().bottomRight(), Mv(0, 0), (RefPicList)REF_PIC_LIST_1, r); + allCandSolidInAbove = true && allCandSolidInAbove; + } +#endif } if ( mrgCtx.interDirNeighbours[uiArrayAddr] == 1 && pu.cs->slice->getRefPic(REF_PIC_LIST_0, mrgCtx.mvFieldNeighbours[uiArrayAddr << 1].refIdx)->getPOC() == pu.cs->slice->getPOC()) @@ -1502,6 +1813,20 @@ void PU::getInterMMVDMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, int currBaseNum = 0; const uint16_t maxNumMergeCand = mrgCtx.numValidMergeCand; +#if GDR_ENABLED + const CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif + +#if GDR_ENABLED + for (int k = 0; k < MMVD_BASE_MV_NUM; k++) + { + mrgCtx.mmvdSolid[k][0] = true; + mrgCtx.mmvdSolid[k][1] = true; + mrgCtx.mmvdValid[k][0] = true; + mrgCtx.mmvdValid[k][1] = true; + } +#endif for (k = 0; k < maxNumMergeCand; k++) { if (mrgCtx.mrgTypeNeighbours[k] == MRG_TYPE_DEFAULT_N) @@ -1513,16 +1838,37 @@ void PU::getInterMMVDMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, { mrgCtx.mmvdBaseMv[currBaseNum][0] = mrgCtx.mvFieldNeighbours[(k << 1)]; mrgCtx.mmvdBaseMv[currBaseNum][1] = mrgCtx.mvFieldNeighbours[(k << 1) + 1]; +#if GDR_ENABLED + if (isEncodeClean) + { + mrgCtx.mmvdSolid[currBaseNum][0] = mrgCtx.mvSolid[(k << 1) + 0]; + mrgCtx.mmvdSolid[currBaseNum][1] = mrgCtx.mvSolid[(k << 1) + 1]; + } +#endif } else if (refIdxList0 >= 0) { mrgCtx.mmvdBaseMv[currBaseNum][0] = mrgCtx.mvFieldNeighbours[(k << 1)]; mrgCtx.mmvdBaseMv[currBaseNum][1] = MvField(Mv(0, 0), -1); +#if GDR_ENABLED + if (isEncodeClean) + { + mrgCtx.mmvdSolid[currBaseNum][0] = mrgCtx.mvSolid[(k << 1) + 0]; + mrgCtx.mmvdSolid[currBaseNum][1] = true; + } +#endif } else if (refIdxList1 >= 0) { mrgCtx.mmvdBaseMv[currBaseNum][0] = MvField(Mv(0, 0), -1); mrgCtx.mmvdBaseMv[currBaseNum][1] = mrgCtx.mvFieldNeighbours[(k << 1) + 1]; +#if GDR_ENABLED + if (isEncodeClean) + { + mrgCtx.mmvdSolid[currBaseNum][0] = true; + mrgCtx.mmvdSolid[currBaseNum][1] = mrgCtx.mvSolid[(k << 1) + 1]; + } +#endif } mrgCtx.mmvdUseAltHpelIf[currBaseNum] = mrgCtx.useAltHpelIf[k]; @@ -1864,6 +2210,10 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in Position posRT = pu.Y().topRight(); Position posLB = pu.Y().bottomLeft(); +#if GDR_ENABLED + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + bool &allCandSolidInAbove = amvpInfo.allCandSolidInAbove; +#endif { bool bAdded = addMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_BELOW_LEFT, *pInfo ); @@ -1934,6 +2284,24 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in } if ( ( C0Avail && getColocatedMVP( pu, eRefPicList, posC0, cColMv, refIdx_Col, false ) ) || getColocatedMVP( pu, eRefPicList, posC1, cColMv, refIdx_Col, false ) ) { +#if GDR_ENABLED + if (isEncodeClean) + { + Mv ccMv; + bool posC0inCurPic_solid = cs.isClean(posC0, CHANNEL_TYPE_LUMA); + bool posC1inCurPic_solid = cs.isClean(posC1, CHANNEL_TYPE_LUMA); + bool posC0inRefPic_solid = cs.isClean(posC0, REF_PIC_LIST_0, refIdx_Col); + bool posC1inRefPic_solid = cs.isClean(posC1, REF_PIC_LIST_0, refIdx_Col); + + bool isMVP0exist = C0Avail && getColocatedMVP(pu, eRefPicList, posC0, ccMv, refIdx_Col, false); + + Position pos = isMVP0exist ? posC0 : posC1; + pInfo->mvPos[pInfo->numCand] = pos; + pInfo->mvType[pInfo->numCand] = isMVP0exist ? MVP_TMVP_C0 : MVP_TMVP_C1; + pInfo->mvSolid[pInfo->numCand] = allCandSolidInAbove && (isMVP0exist ? (posC0inCurPic_solid && posC0inRefPic_solid) : (posC1inCurPic_solid && posC1inRefPic_solid)); + allCandSolidInAbove = allCandSolidInAbove && pInfo->mvSolid[pInfo->numCand]; + } +#endif cColMv.roundTransPrecInternal2Amvr(pu.cu->imv); pInfo->mvCand[pInfo->numCand++] = cColMv; } @@ -1952,6 +2320,13 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in while (pInfo->numCand < AMVP_MAX_NUM_CANDS) { +#if GDR_ENABLED + if (isEncodeClean) + { + pInfo->mvType[pInfo->numCand] = MVP_ZERO; + allCandSolidInAbove = pInfo->mvSolid[pInfo->numCand] = true && allCandSolidInAbove; + } +#endif pInfo->mvCand[pInfo->numCand] = Mv( 0, 0 ); pInfo->numCand++; } @@ -1968,6 +2343,9 @@ bool PU::addAffineMVPCandUnscaled( const PredictionUnit &pu, const RefPicList &r const PredictionUnit *neibPU = NULL; Position neibPos; +#if GDR_ENABLED + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif switch ( dir ) { case MD_LEFT: @@ -1997,6 +2375,11 @@ bool PU::addAffineMVPCandUnscaled( const PredictionUnit &pu, const RefPicList &r } Mv outputAffineMv[3]; +#if GDR_ENABLED + bool outputAffineMvSolid[3]; + MvpType outputAffineMvType[3]; + Position outputAffineMvPos[3]; +#endif const MotionInfo& neibMi = neibPU->getMotionInfo( neibPos ); const int currRefPOC = cs.slice->getRefPic( refPicList, refIdx )->getPOC(); @@ -2012,15 +2395,54 @@ bool PU::addAffineMVPCandUnscaled( const PredictionUnit &pu, const RefPicList &r continue; } +#if GDR_ENABLED + // note : get MV from neihgbor of neibPu (LB, RB) and save to outputAffineMv + if (isEncodeClean) + { + xInheritedAffineMv(pu, neibPU, eRefPicListIndex, outputAffineMv, outputAffineMvSolid, outputAffineMvType, outputAffineMvPos); + } + else + { + xInheritedAffineMv(pu, neibPU, eRefPicListIndex, outputAffineMv); + } +#else xInheritedAffineMv( pu, neibPU, eRefPicListIndex, outputAffineMv ); +#endif outputAffineMv[0].roundAffinePrecInternal2Amvr(pu.cu->imv); outputAffineMv[1].roundAffinePrecInternal2Amvr(pu.cu->imv); affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[0]; affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[1]; +#if GDR_ENABLED + bool neighClean = true; + + if (isEncodeClean) + { + neighClean = cs.isClean(neibPU->Y().pos(), CHANNEL_TYPE_LUMA); + + affiAMVPInfo.mvSolidLT[affiAMVPInfo.numCand] = neighClean && outputAffineMvSolid[0]; + affiAMVPInfo.mvSolidRT[affiAMVPInfo.numCand] = neighClean && outputAffineMvSolid[1]; + + affiAMVPInfo.mvTypeLT[affiAMVPInfo.numCand] = outputAffineMvType[0]; + affiAMVPInfo.mvTypeRT[affiAMVPInfo.numCand] = outputAffineMvType[1]; + + affiAMVPInfo.mvPosLT[affiAMVPInfo.numCand] = outputAffineMvPos[0];; + affiAMVPInfo.mvPosRT[affiAMVPInfo.numCand] = outputAffineMvPos[1]; + } +#endif if ( pu.cu->affineType == AFFINEMODEL_6PARAM ) { outputAffineMv[2].roundAffinePrecInternal2Amvr(pu.cu->imv); affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[2]; +#if GDR_ENABLED + if (isEncodeClean) + { + neighClean = cs.isClean(neibPU->Y().pos(), CHANNEL_TYPE_LUMA); + + affiAMVPInfo.mvSolidLB[affiAMVPInfo.numCand] = neighClean && outputAffineMvSolid[2]; + affiAMVPInfo.mvTypeLB[affiAMVPInfo.numCand] = outputAffineMvType[2]; + affiAMVPInfo.mvPosLB[affiAMVPInfo.numCand] = outputAffineMvPos[2]; + } +#endif } affiAMVPInfo.numCand++; return true; @@ -2028,6 +2450,134 @@ bool PU::addAffineMVPCandUnscaled( const PredictionUnit &pu, const RefPicList &r return false; } +#if GDR_ENABLED +void PU::xInheritedAffineMv(const PredictionUnit &pu, const PredictionUnit* puNeighbour, RefPicList eRefPicList, Mv rcMv[3], bool rcMvSolid[3], MvpType rcMvType[3], Position rcMvPos[3]) +{ +#if GDR_ENABLED + const CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif + + int posNeiX = puNeighbour->Y().pos().x; + int posNeiY = puNeighbour->Y().pos().y; + int posCurX = pu.Y().pos().x; + int posCurY = pu.Y().pos().y; + + int neiW = puNeighbour->Y().width; + int curW = pu.Y().width; + int neiH = puNeighbour->Y().height; + int curH = pu.Y().height; + + Mv mvLT, mvRT, mvLB; + + mvLT = puNeighbour->mvAffi[eRefPicList][0]; + mvRT = puNeighbour->mvAffi[eRefPicList][1]; + mvLB = puNeighbour->mvAffi[eRefPicList][2]; + + +#if GDR_ENABLED + bool neighClean = true; + + if (isEncodeClean) + { + neighClean = cs.isClean(puNeighbour->Y().pos(), CHANNEL_TYPE_LUMA); + + rcMvSolid[0] = neighClean; + rcMvSolid[1] = neighClean; + rcMvSolid[2] = neighClean; + + rcMvType[0] = AFFINE_INHERIT; + rcMvType[1] = AFFINE_INHERIT; + rcMvType[2] = AFFINE_INHERIT; + + rcMvPos[0] = puNeighbour->Y().pos(); + rcMvPos[1] = puNeighbour->Y().pos(); + rcMvPos[2] = puNeighbour->Y().pos(); + } +#endif + + + bool isTopCtuBoundary = false; + if ((posNeiY + neiH) % pu.cs->sps->getCTUSize() == 0 && (posNeiY + neiH) == posCurY) + { + // use bottom-left and bottom-right sub-block MVs for inheritance + const Position posRB = puNeighbour->Y().bottomRight(); + const Position posLB = puNeighbour->Y().bottomLeft(); + + mvLT = puNeighbour->getMotionInfo(posLB).mv[eRefPicList]; + mvRT = puNeighbour->getMotionInfo(posRB).mv[eRefPicList]; + +#if GDR_ENABLED + if (isEncodeClean) + { + neighClean = cs.isClean(puNeighbour->Y().pos(), CHANNEL_TYPE_LUMA); + + rcMvSolid[0] = cs.isClean(posLB, CHANNEL_TYPE_LUMA); + rcMvSolid[1] = cs.isClean(posRB, CHANNEL_TYPE_LUMA); + rcMvSolid[2] = neighClean; + + rcMvType[0] = AFFINE_INHERIT_LB_RB; + rcMvType[1] = AFFINE_INHERIT_LB_RB; + rcMvType[2] = AFFINE_INHERIT_LB_RB; + + rcMvPos[0] = posLB; + rcMvPos[1] = posRB; + rcMvPos[2] = puNeighbour->Y().pos(); + } +#endif + + posNeiY += neiH; + isTopCtuBoundary = true; + } + + int shift = MAX_CU_DEPTH; + int iDMvHorX, iDMvHorY, iDMvVerX, iDMvVerY; + + iDMvHorX = (mvRT - mvLT).getHor() << (shift - floorLog2(neiW)); + iDMvHorY = (mvRT - mvLT).getVer() << (shift - floorLog2(neiW)); + if (puNeighbour->cu->affineType == AFFINEMODEL_6PARAM && !isTopCtuBoundary) + { + iDMvVerX = (mvLB - mvLT).getHor() << (shift - floorLog2(neiH)); + iDMvVerY = (mvLB - mvLT).getVer() << (shift - floorLog2(neiH)); + } + else + { + iDMvVerX = -iDMvHorY; + iDMvVerY = iDMvHorX; + } + + int iMvScaleHor = mvLT.getHor() << shift; + int iMvScaleVer = mvLT.getVer() << shift; + int horTmp, verTmp; + + // v0 + horTmp = iMvScaleHor + iDMvHorX * (posCurX - posNeiX) + iDMvVerX * (posCurY - posNeiY); + verTmp = iMvScaleVer + iDMvHorY * (posCurX - posNeiX) + iDMvVerY * (posCurY - posNeiY); + roundAffineMv(horTmp, verTmp, shift); + rcMv[0].hor = horTmp; + rcMv[0].ver = verTmp; + rcMv[0].clipToStorageBitDepth(); + + // v1 + horTmp = iMvScaleHor + iDMvHorX * (posCurX + curW - posNeiX) + iDMvVerX * (posCurY - posNeiY); + verTmp = iMvScaleVer + iDMvHorY * (posCurX + curW - posNeiX) + iDMvVerY * (posCurY - posNeiY); + roundAffineMv(horTmp, verTmp, shift); + rcMv[1].hor = horTmp; + rcMv[1].ver = verTmp; + rcMv[1].clipToStorageBitDepth(); + + // v2 + if (pu.cu->affineType == AFFINEMODEL_6PARAM) + { + horTmp = iMvScaleHor + iDMvHorX * (posCurX - posNeiX) + iDMvVerX * (posCurY + curH - posNeiY); + verTmp = iMvScaleVer + iDMvHorY * (posCurX - posNeiX) + iDMvVerY * (posCurY + curH - posNeiY); + roundAffineMv(horTmp, verTmp, shift); + rcMv[2].hor = horTmp; + rcMv[2].ver = verTmp; + rcMv[2].clipToStorageBitDepth(); + } +} +#endif void PU::xInheritedAffineMv( const PredictionUnit &pu, const PredictionUnit* puNeighbour, RefPicList eRefPicList, Mv rcMv[3] ) { @@ -2116,8 +2666,31 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co return; } +#if GDR_ENABLED + const CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + bool &allCandSolidInAbove = affiAMVPInfo.allCandSolidInAbove; + + if (isEncodeClean) + { + allCandSolidInAbove = true; + + affiAMVPInfo.allCandSolidInAbove = true; + for (int i = 0; i < AMVP_MAX_NUM_CANDS_MEM; i++) + { + affiAMVPInfo.mvSolidLT[i] = true; + affiAMVPInfo.mvSolidRT[i] = true; + affiAMVPInfo.mvSolidLB[i] = true; + } + } +#endif // insert inherited affine candidates Mv outputAffineMv[3]; +#if GDR_ENABLED + bool outputAffineMvSolid[3]; + MvpType outputAffineMvType[3]; + Position outputAffineMvPos[3]; +#endif Position posLT = pu.Y().topLeft(); Position posRT = pu.Y().topRight(); Position posLB = pu.Y().bottomLeft(); @@ -2155,6 +2728,18 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co AMVPInfo amvpInfo0; amvpInfo0.numCand = 0; +#if GDR_ENABLED + if (isEncodeClean) + { + amvpInfo0.allCandSolidInAbove = true; + for (int i = 0; i < AMVP_MAX_NUM_CANDS_MEM; i++) + { + amvpInfo0.mvSolid[i] = true; + amvpInfo0.mvValid[i] = true; + } + } +#endif + // A->C: Above Left, Above, Left addMVPCandUnscaled( pu, eRefPicList, refIdx, posLT, MD_ABOVE_LEFT, amvpInfo0 ); if ( amvpInfo0.numCand < 1 ) @@ -2171,6 +2756,18 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co AMVPInfo amvpInfo1; amvpInfo1.numCand = 0; +#if GDR_ENABLED + if (isEncodeClean) + { + amvpInfo1.allCandSolidInAbove = true; + for (int i = 0; i < AMVP_MAX_NUM_CANDS_MEM; i++) + { + amvpInfo1.mvSolid[i] = true; + amvpInfo1.mvValid[i] = true; + } + } +#endif + // D->E: Above, Above Right addMVPCandUnscaled( pu, eRefPicList, refIdx, posRT, MD_ABOVE, amvpInfo1 ); if ( amvpInfo1.numCand < 1 ) @@ -2183,6 +2780,18 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co AMVPInfo amvpInfo2; amvpInfo2.numCand = 0; +#if GDR_ENABLED + if (isEncodeClean) + { + amvpInfo2.allCandSolidInAbove = true; + for (int i = 0; i < AMVP_MAX_NUM_CANDS_MEM; i++) + { + amvpInfo2.mvSolid[i] = true; + amvpInfo2.mvValid[i] = true; + } + } +#endif + // F->G: Left, Below Left addMVPCandUnscaled( pu, eRefPicList, refIdx, posLB, MD_LEFT, amvpInfo2 ); if ( amvpInfo2.numCand < 1 ) @@ -2195,6 +2804,24 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co outputAffineMv[1] = amvpInfo1.mvCand[0]; outputAffineMv[2] = amvpInfo2.mvCand[0]; +#if GDR_ENABLED + if (isEncodeClean) + { + outputAffineMvSolid[0] = amvpInfo0.mvSolid[0] && allCandSolidInAbove; + outputAffineMvSolid[1] = amvpInfo1.mvSolid[0] && allCandSolidInAbove; + outputAffineMvSolid[2] = amvpInfo2.mvSolid[0] && allCandSolidInAbove; + + outputAffineMvPos[0] = amvpInfo0.mvPos[0]; + outputAffineMvPos[1] = amvpInfo1.mvPos[0]; + outputAffineMvPos[2] = amvpInfo2.mvPos[0]; + + outputAffineMvType[0] = amvpInfo0.mvType[0]; + outputAffineMvType[1] = amvpInfo1.mvType[0]; + outputAffineMvType[2] = amvpInfo2.mvType[0]; + + allCandSolidInAbove = allCandSolidInAbove && outputAffineMvSolid[0] && outputAffineMvSolid[1] && outputAffineMvSolid[2]; + } +#endif outputAffineMv[0].roundAffinePrecInternal2Amvr(pu.cu->imv); outputAffineMv[1].roundAffinePrecInternal2Amvr(pu.cu->imv); outputAffineMv[2].roundAffinePrecInternal2Amvr(pu.cu->imv); @@ -2204,6 +2831,24 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[0]; affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[1]; affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[2]; +#if GDR_ENABLED + if (isEncodeClean) + { + affiAMVPInfo.mvSolidLT[affiAMVPInfo.numCand] = outputAffineMvSolid[0] && allCandSolidInAbove; + affiAMVPInfo.mvSolidRT[affiAMVPInfo.numCand] = outputAffineMvSolid[1] && allCandSolidInAbove; + affiAMVPInfo.mvSolidLB[affiAMVPInfo.numCand] = outputAffineMvSolid[2] && allCandSolidInAbove; + + affiAMVPInfo.mvPosLT[affiAMVPInfo.numCand] = outputAffineMvPos[0]; + affiAMVPInfo.mvPosRT[affiAMVPInfo.numCand] = outputAffineMvPos[1]; + affiAMVPInfo.mvPosLB[affiAMVPInfo.numCand] = outputAffineMvPos[2]; + + affiAMVPInfo.mvTypeLT[affiAMVPInfo.numCand] = outputAffineMvType[0]; + affiAMVPInfo.mvTypeRT[affiAMVPInfo.numCand] = outputAffineMvType[1]; + affiAMVPInfo.mvTypeLB[affiAMVPInfo.numCand] = outputAffineMvType[2]; + + allCandSolidInAbove = allCandSolidInAbove && outputAffineMvSolid[0] && outputAffineMvSolid[1] && outputAffineMvSolid[2]; + } +#endif affiAMVPInfo.numCand++; } @@ -2217,6 +2862,24 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[i]; affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[i]; affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[i]; +#if GDR_ENABLED + if (isEncodeClean) + { + affiAMVPInfo.mvSolidLT[affiAMVPInfo.numCand] = outputAffineMvSolid[i] && allCandSolidInAbove; + affiAMVPInfo.mvSolidRT[affiAMVPInfo.numCand] = outputAffineMvSolid[i] && allCandSolidInAbove; + affiAMVPInfo.mvSolidLB[affiAMVPInfo.numCand] = outputAffineMvSolid[i] && allCandSolidInAbove; + + affiAMVPInfo.mvPosLT[affiAMVPInfo.numCand] = outputAffineMvPos[i]; + affiAMVPInfo.mvPosRT[affiAMVPInfo.numCand] = outputAffineMvPos[i]; + affiAMVPInfo.mvPosLB[affiAMVPInfo.numCand] = outputAffineMvPos[i]; + + affiAMVPInfo.mvTypeLT[affiAMVPInfo.numCand] = outputAffineMvType[i]; + affiAMVPInfo.mvTypeRT[affiAMVPInfo.numCand] = outputAffineMvType[i]; + affiAMVPInfo.mvTypeLB[affiAMVPInfo.numCand] = outputAffineMvType[i]; + + allCandSolidInAbove = allCandSolidInAbove && outputAffineMvSolid[i]; + } +#endif affiAMVPInfo.numCand++; } } @@ -2256,6 +2919,52 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = cColMv; affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = cColMv; affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = cColMv; +#if GDR_ENABLED + if (isEncodeClean) + { + Mv ccMv; + + bool posC0inCurPic_solid = cs.isClean(posC0, CHANNEL_TYPE_LUMA); + bool posC1inCurPic_solid = cs.isClean(posC1, CHANNEL_TYPE_LUMA); + bool posC0inRefPic_solid = cs.isClean(posC0, eRefPicList, refIdxCol); + bool posC1inRefPic_solid = cs.isClean(posC1, eRefPicList, refIdxCol); + + bool isMVP0exist = C0Avail && getColocatedMVP(pu, eRefPicList, posC0, ccMv, refIdxCol, false); + + if (isMVP0exist) + { + affiAMVPInfo.mvSolidLT[affiAMVPInfo.numCand] = posC0inCurPic_solid && posC0inRefPic_solid && allCandSolidInAbove; + affiAMVPInfo.mvSolidRT[affiAMVPInfo.numCand] = posC0inCurPic_solid && posC0inRefPic_solid && allCandSolidInAbove; + affiAMVPInfo.mvSolidLB[affiAMVPInfo.numCand] = posC0inCurPic_solid && posC0inRefPic_solid && allCandSolidInAbove; + + affiAMVPInfo.mvPosLT[affiAMVPInfo.numCand] = posC0; + affiAMVPInfo.mvPosRT[affiAMVPInfo.numCand] = posC0; + affiAMVPInfo.mvPosLB[affiAMVPInfo.numCand] = posC0; + + affiAMVPInfo.mvTypeLT[affiAMVPInfo.numCand] = MVP_TMVP_C0; + affiAMVPInfo.mvTypeRT[affiAMVPInfo.numCand] = MVP_TMVP_C0; + affiAMVPInfo.mvTypeLB[affiAMVPInfo.numCand] = MVP_TMVP_C0; + + allCandSolidInAbove = allCandSolidInAbove && affiAMVPInfo.mvSolidLT[affiAMVPInfo.numCand] && affiAMVPInfo.mvSolidRT[affiAMVPInfo.numCand] && affiAMVPInfo.mvSolidLB[affiAMVPInfo.numCand]; + } + else + { + affiAMVPInfo.mvSolidLT[affiAMVPInfo.numCand] = posC1inCurPic_solid && posC1inRefPic_solid && allCandSolidInAbove; + affiAMVPInfo.mvSolidRT[affiAMVPInfo.numCand] = posC1inCurPic_solid && posC1inRefPic_solid && allCandSolidInAbove; + affiAMVPInfo.mvSolidLB[affiAMVPInfo.numCand] = posC1inCurPic_solid && posC1inRefPic_solid && allCandSolidInAbove; + + affiAMVPInfo.mvPosLT[affiAMVPInfo.numCand] = posC1; + affiAMVPInfo.mvPosRT[affiAMVPInfo.numCand] = posC1; + affiAMVPInfo.mvPosLB[affiAMVPInfo.numCand] = posC1; + + affiAMVPInfo.mvTypeLT[affiAMVPInfo.numCand] = MVP_TMVP_C1; + affiAMVPInfo.mvTypeRT[affiAMVPInfo.numCand] = MVP_TMVP_C1; + affiAMVPInfo.mvTypeLB[affiAMVPInfo.numCand] = MVP_TMVP_C1; + + allCandSolidInAbove = allCandSolidInAbove && affiAMVPInfo.mvSolidLT[affiAMVPInfo.numCand] && affiAMVPInfo.mvSolidRT[affiAMVPInfo.numCand] && affiAMVPInfo.mvSolidLB[affiAMVPInfo.numCand]; + } + } +#endif affiAMVPInfo.numCand++; } } @@ -2268,6 +2977,24 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand].setZero(); affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand].setZero(); affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand].setZero(); +#if GDR_ENABLED + if (isEncodeClean) + { + affiAMVPInfo.mvSolidLT[affiAMVPInfo.numCand] = true && allCandSolidInAbove; + affiAMVPInfo.mvSolidRT[affiAMVPInfo.numCand] = true && allCandSolidInAbove; + affiAMVPInfo.mvSolidLB[affiAMVPInfo.numCand] = true && allCandSolidInAbove; + + affiAMVPInfo.mvPosLT[affiAMVPInfo.numCand] = Position(0, 0); + affiAMVPInfo.mvPosRT[affiAMVPInfo.numCand] = Position(0, 0); + affiAMVPInfo.mvPosLB[affiAMVPInfo.numCand] = Position(0, 0); + + affiAMVPInfo.mvTypeLT[affiAMVPInfo.numCand] = MVP_ZERO; + affiAMVPInfo.mvTypeRT[affiAMVPInfo.numCand] = MVP_ZERO; + affiAMVPInfo.mvTypeLB[affiAMVPInfo.numCand] = MVP_ZERO; + + allCandSolidInAbove = allCandSolidInAbove && affiAMVPInfo.mvSolidLT[affiAMVPInfo.numCand] && affiAMVPInfo.mvSolidRT[affiAMVPInfo.numCand] && affiAMVPInfo.mvSolidLB[affiAMVPInfo.numCand]; + } +#endif affiAMVPInfo.numCand++; } } @@ -2287,6 +3014,11 @@ bool PU::addMVPCandUnscaled( const PredictionUnit &pu, const RefPicList &eRefPic const PredictionUnit *neibPU = NULL; Position neibPos; +#if GDR_ENABLED + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + bool &allCandSolidInAbove = info.allCandSolidInAbove; +#endif + switch (eDir) { case MD_LEFT: @@ -2327,6 +3059,18 @@ bool PU::addMVPCandUnscaled( const PredictionUnit &pu, const RefPicList &eRefPic if( neibRefIdx >= 0 && currRefPOC == cs.slice->getRefPOC( eRefPicListIndex, neibRefIdx ) ) { +#if GDR_ENABLED + if (isEncodeClean) + { + bool isSolid = cs.isClean(neibPos, CHANNEL_TYPE_LUMA); + + info.mvSolid[info.numCand] = isSolid && allCandSolidInAbove; + info.mvType[info.numCand] = (MvpType)eDir; + info.mvPos[info.numCand] = neibPos; + + allCandSolidInAbove = isSolid && allCandSolidInAbove; + } +#endif info.mvCand[info.numCand++] = neibMi.mv[eRefPicListIndex]; return true; } @@ -2346,6 +3090,22 @@ void PU::addAMVPHMVPCand(const PredictionUnit &pu, const RefPicList eRefPicList, int num_allowedCand = std::min(MAX_NUM_HMVP_AVMPCANDS, num_avai_candInLUT); const RefPicList eRefPicList2nd = (eRefPicList == REF_PIC_LIST_0) ? REF_PIC_LIST_1 : REF_PIC_LIST_0; +#if GDR_ENABLED + CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + bool &allCandSolidInAbove = info.allCandSolidInAbove; +#endif + + +#if GDR_ENABLED + bool vbOnCtuBoundary = true; + if (isEncodeClean) + { + vbOnCtuBoundary = (pu.cs->picHeader->getNumVerVirtualBoundaries() == 0) || (pu.cs->picHeader->getVirtualBoundariesPosX(0) % pu.cs->sps->getMaxCUWidth() == 0); + allCandSolidInAbove = allCandSolidInAbove && vbOnCtuBoundary; + } +#endif + for (int mrgIdx = 1; mrgIdx <= num_allowedCand; mrgIdx++) { if (info.numCand >= AMVP_MAX_NUM_CANDS) @@ -2364,6 +3124,15 @@ void PU::addAMVPHMVPCand(const PredictionUnit &pu, const RefPicList eRefPicList, Mv pmv = neibMi.mv[eRefPicListIndex]; pmv.roundTransPrecInternal2Amvr(pu.cu->imv); +#if GDR_ENABLED + if (isEncodeClean) + { + info.mvPos[info.numCand] = neibMi.soPos; + info.mvType[info.numCand] = MVP_HMVP; + info.mvSolid[info.numCand] = allCandSolidInAbove && vbOnCtuBoundary; // cs.isClean(neibMi.soPos, CHANNEL_TYPE_LUMA); + allCandSolidInAbove = allCandSolidInAbove && vbOnCtuBoundary; + } +#endif info.mvCand[info.numCand++] = pmv; if (info.numCand >= AMVP_MAX_NUM_CANDS) { @@ -2590,6 +3359,9 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx const Slice &slice = *pu.cs->slice; const uint32_t maxNumAffineMergeCand = slice.getPicHeader()->getMaxNumAffineMergeCand(); const unsigned plevel = pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2; +#if GDR_ENABLED + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif for ( int i = 0; i < maxNumAffineMergeCand; i++ ) { @@ -2597,12 +3369,33 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx { affMrgCtx.mvFieldNeighbours[(i << 1) + 0][mvNum].setMvField( Mv(), -1 ); affMrgCtx.mvFieldNeighbours[(i << 1) + 1][mvNum].setMvField( Mv(), -1 ); +#if GDR_ENABLED + if (isEncodeClean) + { + affMrgCtx.mvSolid[(i << 1) + 0][mvNum] = true; + affMrgCtx.mvSolid[(i << 1) + 1][mvNum] = true; + affMrgCtx.mvValid[(i << 1) + 0][mvNum] = true; + affMrgCtx.mvValid[(i << 1) + 1][mvNum] = true; + } +#endif } affMrgCtx.interDirNeighbours[i] = 0; affMrgCtx.affineType[i] = AFFINEMODEL_4PARAM; affMrgCtx.mergeType[i] = MRG_TYPE_DEFAULT_N; affMrgCtx.BcwIdx[i] = BCW_DEFAULT; } +#if GDR_ENABLED + if (isEncodeClean) + { + MergeCtx &mrgCtx = *affMrgCtx.mrgCtx; + int numMergeCand = MRG_MAX_NUM_CANDS << 1; + for (int i = 0; i < numMergeCand; i++) + { + mrgCtx.mvSolid[i] = true; + mrgCtx.mvValid[i] = true; + } + } +#endif affMrgCtx.numValidMergeCand = 0; affMrgCtx.maxNumMergeCand = maxNumAffineMergeCand; @@ -2639,6 +3432,14 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx { mrgCtx.mvFieldNeighbours[(pos << 1) + 1].setMvField( miLeft.mv[1], miLeft.refIdx[1] ); } +#if GDR_ENABLED + // check if the (puLeft) is in clean area + if (isEncodeClean) + { + mrgCtx.mvSolid[(pos << 1) + 0] = cs.isClean(puLeft->Y().bottomRight(), CHANNEL_TYPE_LUMA); + mrgCtx.mvSolid[(pos << 1) + 1] = cs.isClean(puLeft->Y().bottomRight(), CHANNEL_TYPE_LUMA); + } +#endif pos++; } @@ -2651,6 +3452,13 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx { affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand << 1) + 0][mvNum].setMvField( mrgCtx.mvFieldNeighbours[(pos << 1) + 0].mv, mrgCtx.mvFieldNeighbours[(pos << 1) + 0].refIdx ); affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand << 1) + 1][mvNum].setMvField( mrgCtx.mvFieldNeighbours[(pos << 1) + 1].mv, mrgCtx.mvFieldNeighbours[(pos << 1) + 1].refIdx ); +#if GDR_ENABLED + if (isEncodeClean) + { + affMrgCtx.mvSolid[(affMrgCtx.numValidMergeCand << 1) + 0][mvNum] = mrgCtx.mvSolid[(pos << 1) + 0]; + affMrgCtx.mvSolid[(affMrgCtx.numValidMergeCand << 1) + 1][mvNum] = mrgCtx.mvSolid[(pos << 1) + 1]; + } +#endif } affMrgCtx.interDirNeighbours[affMrgCtx.numValidMergeCand] = mrgCtx.interDirNeighbours[pos]; @@ -2681,17 +3489,44 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx { // derive Mv from Neigh affine PU Mv cMv[2][3]; +#if GDR_ENABLED + bool cMvSolid[2][3] = { {true, true, true}, {true, true, true} }; + MvpType cMvType[2][3]; + Position cMvPos[2][3]; +#endif const PredictionUnit* puNeigh = npu[idx]; pu.cu->affineType = puNeigh->cu->affineType; if ( puNeigh->interDir != 2 ) { - xInheritedAffineMv( pu, puNeigh, REF_PIC_LIST_0, cMv[0] ); +#if GDR_ENABLED + if (isEncodeClean) + { + xInheritedAffineMv(pu, puNeigh, REF_PIC_LIST_0, cMv[0], cMvSolid[0], cMvType[0], cMvPos[0]); + } + else + { + xInheritedAffineMv(pu, puNeigh, REF_PIC_LIST_0, cMv[0]); + } +#else + xInheritedAffineMv(pu, puNeigh, REF_PIC_LIST_0, cMv[0]); +#endif } if ( slice.isInterB() ) { if ( puNeigh->interDir != 1 ) { - xInheritedAffineMv( pu, puNeigh, REF_PIC_LIST_1, cMv[1] ); +#if GDR_ENABLED + if (isEncodeClean) + { + xInheritedAffineMv(pu, puNeigh, REF_PIC_LIST_1, cMv[1], cMvSolid[1], cMvType[1], cMvPos[1]); + } + else + { + xInheritedAffineMv(pu, puNeigh, REF_PIC_LIST_1, cMv[1]); + } +#else + xInheritedAffineMv(pu, puNeigh, REF_PIC_LIST_1, cMv[1]); +#endif } } @@ -2699,6 +3534,13 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx { affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand << 1) + 0][mvNum].setMvField( cMv[0][mvNum], puNeigh->refIdx[0] ); affMrgCtx.mvFieldNeighbours[(affMrgCtx.numValidMergeCand << 1) + 1][mvNum].setMvField( cMv[1][mvNum], puNeigh->refIdx[1] ); +#if GDR_ENABLED + if (isEncodeClean) + { + affMrgCtx.mvSolid[(affMrgCtx.numValidMergeCand << 1) + 0][mvNum] = cMvSolid[0][mvNum]; + affMrgCtx.mvSolid[(affMrgCtx.numValidMergeCand << 1) + 1][mvNum] = cMvSolid[0][mvNum]; + } +#endif } affMrgCtx.interDirNeighbours[affMrgCtx.numValidMergeCand] = puNeigh->interDir; affMrgCtx.affineType[affMrgCtx.numValidMergeCand] = (EAffineModel)(puNeigh->cu->affineType); @@ -2726,6 +3568,9 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx int8_t neighBcw[2] = { BCW_DEFAULT, BCW_DEFAULT }; // control point: LT B2->B3->A2 const Position posLT[3] = { pu.Y().topLeft().offset( -1, -1 ), pu.Y().topLeft().offset( 0, -1 ), pu.Y().topLeft().offset( -1, 0 ) }; +#if GDR_ENABLED + bool miSolid[4] = { false, false, false, false }; +#endif for ( int i = 0; i < 3; i++ ) { const Position pos = posLT[i]; @@ -2736,6 +3581,12 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx isAvailable[0] = true; mi[0] = puNeigh->getMotionInfo( pos ); neighBcw[0] = puNeigh->cu->BcwIdx; +#if GDR_ENABLED + if (isEncodeClean) + { + miSolid[0] = cs.isClean(puNeigh->Y().topRight(), CHANNEL_TYPE_LUMA); + } +#endif break; } } @@ -2752,6 +3603,12 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx isAvailable[1] = true; mi[1] = puNeigh->getMotionInfo( pos ); neighBcw[1] = puNeigh->cu->BcwIdx; +#if GDR_ENABLED + if (isEncodeClean) + { + miSolid[1] = cs.isClean(puNeigh->Y().topRight(), CHANNEL_TYPE_LUMA); + } +#endif break; } } @@ -2767,6 +3624,12 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx { isAvailable[2] = true; mi[2] = puNeigh->getMotionInfo( pos ); +#if GDR_ENABLED + if (isEncodeClean) + { + miSolid[2] = cs.isClean(puNeigh->Y().topRight(), CHANNEL_TYPE_LUMA); + } +#endif break; } } @@ -2808,6 +3671,15 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx mi[3].refIdx[0] = refIdx; mi[3].interDir = 1; isAvailable[3] = true; +#if GDR_ENABLED + if (isEncodeClean) + { + bool posL0inCurPic_solid = cs.isClean(posC0, CHANNEL_TYPE_LUMA); + bool posL0inRefPic_solid = cs.isClean(posC0, REF_PIC_LIST_0, refIdx); + + miSolid[3] = posL0inCurPic_solid && posL0inRefPic_solid; + } +#endif } if ( slice.isInterB() ) @@ -2819,6 +3691,15 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx mi[3].refIdx[1] = refIdx; mi[3].interDir |= 2; isAvailable[3] = true; +#if GDR_ENABLED + if (isEncodeClean) + { + bool posL1inCurPic_solid = cs.isClean(posC0, CHANNEL_TYPE_LUMA); + bool posL1inRefPic_solid = cs.isClean(posC0, REF_PIC_LIST_1, refIdx); + + miSolid[3] = (mi[3].interDir & 1) ? (miSolid[3] && posL1inCurPic_solid && posL1inRefPic_solid) : (posL1inCurPic_solid && posL1inRefPic_solid); + } +#endif } } } @@ -2835,12 +3716,36 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx { 0, 2 }, // 5: LT, LB }; +#if GDR_ENABLED + bool model_solid[6] = + { + miSolid[0] && miSolid[1] && miSolid[2], + miSolid[0] && miSolid[1] && miSolid[3], + miSolid[0] && miSolid[2] && miSolid[3], + miSolid[1] && miSolid[2] && miSolid[3], + miSolid[0] && miSolid[1], + miSolid[0] && miSolid[2] + }; +#endif int verNum[6] = { 3, 3, 3, 3, 2, 2 }; int startIdx = pu.cs->sps->getUseAffineType() ? 0 : 4; for ( int idx = startIdx; idx < modelNum; idx++ ) { int modelIdx = order[idx]; +#if GDR_ENABLED + int affinNumValidCand = affMrgCtx.numValidMergeCand; +#endif getAffineControlPointCand(pu, mi, isAvailable, model[modelIdx], ((modelIdx == 3) ? neighBcw[1] : neighBcw[0]), modelIdx, verNum[modelIdx], affMrgCtx); +#if GDR_ENABLED + if (isEncodeClean) + { + for (int i = 0; i < 3; i++) + { + affMrgCtx.mvSolid[(affinNumValidCand << 1) + 0][i] = model_solid[modelIdx]; + affMrgCtx.mvSolid[(affinNumValidCand << 1) + 1][i] = model_solid[modelIdx]; + } + } +#endif if ( affMrgCtx.numValidMergeCand != 0 && affMrgCtx.numValidMergeCand - 1 == mrgCandIdx ) { return; @@ -2863,6 +3768,12 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx for ( int mvNum = 0; mvNum < 3; mvNum++ ) { affMrgCtx.mvFieldNeighbours[(cnt << 1) + 0][mvNum].setMvField( Mv( 0, 0 ), 0 ); +#if GDR_ENABLED + if (isEncodeClean) + { + affMrgCtx.mvSolid[(cnt << 1) + 0][mvNum] = true; + } +#endif } affMrgCtx.interDirNeighbours[cnt] = 1; @@ -2871,6 +3782,12 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx for ( int mvNum = 0; mvNum < 3; mvNum++ ) { affMrgCtx.mvFieldNeighbours[(cnt << 1) + 1][mvNum].setMvField( Mv( 0, 0 ), 0 ); +#if GDR_ENABLED + if (isEncodeClean) + { + affMrgCtx.mvSolid[(cnt << 1) + 1][mvNum] = true; + } +#endif } affMrgCtx.interDirNeighbours[cnt] = 3; } @@ -3007,15 +3924,32 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b const Picture *pColPic = slice.getRefPic(RefPicList(slice.isInterB() ? 1 - slice.getColFromL0Flag() : 0), slice.getColRefIdx()); Mv cTMv; +#if GDR_ENABLED + const CodingStructure& cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + bool isSubPuSolid[2] = { true, true }; +#endif if ( count ) { if ( (mrgCtx.interDirNeighbours[0] & (1 << REF_PIC_LIST_0)) && slice.getRefPic( REF_PIC_LIST_0, mrgCtx.mvFieldNeighbours[REF_PIC_LIST_0].refIdx ) == pColPic ) { cTMv = mrgCtx.mvFieldNeighbours[REF_PIC_LIST_0].mv; +#if GDR_ENABLED + if (isEncodeClean) + { + isSubPuSolid[REF_PIC_LIST_0] = mrgCtx.mvSolid[REF_PIC_LIST_0]; + } +#endif } else if ( slice.isInterB() && (mrgCtx.interDirNeighbours[0] & (1 << REF_PIC_LIST_1)) && slice.getRefPic( REF_PIC_LIST_1, mrgCtx.mvFieldNeighbours[REF_PIC_LIST_1].refIdx ) == pColPic ) { cTMv = mrgCtx.mvFieldNeighbours[REF_PIC_LIST_1].mv; +#if GDR_ENABLED + if (isEncodeClean) + { + isSubPuSolid[REF_PIC_LIST_1] = mrgCtx.mvSolid[REF_PIC_LIST_1]; + } +#endif } } @@ -3071,6 +4005,12 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b // set as default, for further motion vector field spanning mrgCtx.mvFieldNeighbours[(count << 1) + currRefListId].setMvField(cColMv, 0); mrgCtx.interDirNeighbours[count] |= (1 << currRefListId); +#if GDR_ENABLED + if (isEncodeClean) + { + mrgCtx.mvSolid[(count << 1) + currRefListId] = cs.isClean(centerPos, currRefPicList, refIdx); + } +#endif LICFlag = tempLICFlag; mrgCtx.BcwIdx[count] = BCW_DEFAULT; found = true; @@ -3124,6 +4064,12 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b mi.refIdx[currRefListId] = 0; mi.mv[currRefListId] = cColMv; found = true; +#if GDR_ENABLED + if (isEncodeClean) + { + isSubPuSolid[currRefPicList] = isSubPuSolid[currRefPicList] && cs.isClean(colPos, currRefPicList, refIdx); + } +#endif } } } @@ -3149,6 +4095,16 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b } } } + +#if GDR_ENABLED + if (isEncodeClean) + { + // the final if it is solid + mrgCtx.mvSolid[(count << 1) + 0] = mrgCtx.mvSolid[(count << 1) + 0] && isSubPuSolid[0]; + mrgCtx.mvSolid[(count << 1) + 1] = mrgCtx.mvSolid[(count << 1) + 1] && isSubPuSolid[1]; + } +#endif + return true; } @@ -3326,6 +4282,10 @@ void PU::getGeoMergeCandidates( const PredictionUnit &pu, MergeCtx& geoMrgCtx ) const uint32_t maxNumMergeCand = pu.cs->sps->getMaxNumMergeCand(); geoMrgCtx.numValidMergeCand = 0; +#if GDR_ENABLED + CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif for (int32_t i = 0; i < GEO_MAX_NUM_UNI_CANDS; i++) { geoMrgCtx.BcwIdx[i] = BCW_DEFAULT; @@ -3335,6 +4295,13 @@ void PU::getGeoMergeCandidates( const PredictionUnit &pu, MergeCtx& geoMrgCtx ) geoMrgCtx.mvFieldNeighbours[(i << 1) + 1].refIdx = NOT_VALID; geoMrgCtx.mvFieldNeighbours[(i << 1)].mv = Mv(); geoMrgCtx.mvFieldNeighbours[(i << 1) + 1].mv = Mv(); +#if GDR_ENABLED + if (isEncodeClean) + { + geoMrgCtx.mvSolid[(i << 1) + 0] = true; + geoMrgCtx.mvSolid[(i << 1) + 1] = true; + } +#endif geoMrgCtx.useAltHpelIf[i] = false; } @@ -3351,6 +4318,18 @@ void PU::getGeoMergeCandidates( const PredictionUnit &pu, MergeCtx& geoMrgCtx ) geoMrgCtx.mvFieldNeighbours[(geoMrgCtx.numValidMergeCand << 1) + parity].mv = tmpMergeCtx.mvFieldNeighbours[(i << 1) + parity].mv; geoMrgCtx.mvFieldNeighbours[(geoMrgCtx.numValidMergeCand << 1) + !parity].refIdx = -1; geoMrgCtx.mvFieldNeighbours[(geoMrgCtx.numValidMergeCand << 1) + parity].refIdx = tmpMergeCtx.mvFieldNeighbours[(i << 1) + parity].refIdx; +#if GDR_ENABLED + if (isEncodeClean) + { + Mv mv = tmpMergeCtx.mvFieldNeighbours[(i << 1) + parity].mv; + int refIdx = tmpMergeCtx.mvFieldNeighbours[(i << 1) + parity].refIdx; + RefPicList refPicList = parity ? REF_PIC_LIST_1 : REF_PIC_LIST_0; + geoMrgCtx.mvSolid[(geoMrgCtx.numValidMergeCand << 1) + !parity] = true; + geoMrgCtx.mvSolid[(geoMrgCtx.numValidMergeCand << 1) + parity] = tmpMergeCtx.mvSolid[(i << 1) + parity]; + geoMrgCtx.mvValid[(geoMrgCtx.numValidMergeCand << 1) + !parity] = true; + geoMrgCtx.mvValid[(geoMrgCtx.numValidMergeCand << 1) + parity] = cs.isClean(pu.Y().bottomRight(), mv, refPicList, refIdx); + } +#endif geoMrgCtx.numValidMergeCand++; if (geoMrgCtx.numValidMergeCand == GEO_MAX_NUM_UNI_CANDS) { @@ -3367,6 +4346,18 @@ void PU::getGeoMergeCandidates( const PredictionUnit &pu, MergeCtx& geoMrgCtx ) geoMrgCtx.mvFieldNeighbours[(geoMrgCtx.numValidMergeCand << 1) + parity].mv = Mv(0, 0); geoMrgCtx.mvFieldNeighbours[(geoMrgCtx.numValidMergeCand << 1) + !parity].refIdx = tmpMergeCtx.mvFieldNeighbours[(i << 1) + !parity].refIdx; geoMrgCtx.mvFieldNeighbours[(geoMrgCtx.numValidMergeCand << 1) + parity].refIdx = -1; +#if GDR_ENABLED + if (isEncodeClean) + { + Mv mv = tmpMergeCtx.mvFieldNeighbours[(i << 1) + !parity].mv; + int refIdx = tmpMergeCtx.mvFieldNeighbours[(i << 1) + !parity].refIdx; + RefPicList refPicList = (!parity) ? REF_PIC_LIST_1 : REF_PIC_LIST_0; + geoMrgCtx.mvSolid[(geoMrgCtx.numValidMergeCand << 1) + !parity] = tmpMergeCtx.mvSolid[(i << 1) + !parity]; + geoMrgCtx.mvSolid[(geoMrgCtx.numValidMergeCand << 1) + parity] = true; + geoMrgCtx.mvValid[(geoMrgCtx.numValidMergeCand << 1) + !parity] = cs.isClean(pu.Y().bottomRight(), mv, refPicList, refIdx);; + geoMrgCtx.mvValid[(geoMrgCtx.numValidMergeCand << 1) + parity] = true; + } +#endif geoMrgCtx.numValidMergeCand++; if (geoMrgCtx.numValidMergeCand == GEO_MAX_NUM_UNI_CANDS) { diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 3ec4a6566ee42386fee58de5ff86a2b8f7eb0548..766205bd6ce317439509d2f0b1f1d705ddba70d8 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -148,11 +148,18 @@ namespace PU void fillIBCMvpCand (PredictionUnit &pu, AMVPInfo &amvpInfo); void fillAffineMvpCand ( PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AffineAMVPInfo &affiAMVPInfo); bool addMVPCandUnscaled (const PredictionUnit &pu, const RefPicList &eRefPicList, const int &iRefIdx, const Position &pos, const MvpDir &eDir, AMVPInfo &amvpInfo); +#if GDR_ENABLED + void xInheritedAffineMv(const PredictionUnit &pu, const PredictionUnit* puNeighbour, RefPicList eRefPicList, Mv rcMv[3], bool rcMvSolid[3], MvpType rcMvType[3], Position rcMvPos[3]); +#endif void xInheritedAffineMv ( const PredictionUnit &pu, const PredictionUnit* puNeighbour, RefPicList eRefPicList, Mv rcMv[3] ); bool addMergeHMVPCand (const CodingStructure &cs, MergeCtx& mrgCtx, const int& mrgCandIdx, const uint32_t maxNumMergeCandMin1, int &cnt , const bool isAvailableA1, const MotionInfo miLeft, const bool isAvailableB1, const MotionInfo miAbove , const bool ibcFlag , const bool isGt4x4 +#if GDR_ENABLED + , const PredictionUnit &pu + , bool &addMergeHMVPCand +#endif ); void addAMVPHMVPCand (const PredictionUnit &pu, const RefPicList eRefPicList, const int currRefPOC, AMVPInfo &info); bool addAffineMVPCandUnscaled ( const PredictionUnit &pu, const RefPicList &refPicList, const int &refIdx, const Position &pos, const MvpDir &dir, AffineAMVPInfo &affiAmvpInfo ); diff --git a/source/Lib/CommonLib/dtrace_blockstatistics.cpp b/source/Lib/CommonLib/dtrace_blockstatistics.cpp index d92ae1e17a27bdf137349fbaa21b0d8258de8f8e..15b349e0885ede3c34ee660aea9d6f7d304273ec 100644 --- a/source/Lib/CommonLib/dtrace_blockstatistics.cpp +++ b/source/Lib/CommonLib/dtrace_blockstatistics.cpp @@ -902,13 +902,21 @@ void writeAllData(const CodingStructure& cs, const UnitArea& ctuArea) { const uint32_t uiChFinalMode = PU::getFinalIntraMode( pu, ChannelType( chType ) ); DTRACE_BLOCK_SCALAR_CHROMA(g_trace_ctx, D_BLOCK_STATISTICS_ALL, pu, GetBlockStatisticName(BlockStatistic::Chroma_IntraMode), uiChFinalMode); +#if !GDR_ENABLED assert(0); +#endif } } } } } break; +#if GDR_ENABLED + case MODE_IBC: + case MODE_PLT: + // note: not implemented yet + break; +#endif default: THROW( "Invalid prediction mode" ); break; diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index 67132dbe0a5db5dba92e2acdf0a7451ccbce527c..930cd9e81168a4018fddce788aa6c7bdd16601a3 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -837,7 +837,11 @@ void DecLib::finishPicture(int &poc, PicList *&rpcListPic, MsgLevel msgl, bool a m_pcPic->destroyTempBuffers(); m_pcPic->cs->destroyCoeffs(); m_pcPic->cs->releaseIntermediateData(); +#if GDR_ENABLED + m_picHeader.initPicHeader(); +#else m_pcPic->cs->picHeader->initPicHeader(); +#endif m_puCounter++; } @@ -1583,7 +1587,14 @@ void DecLib::xActivateParameterSets( const InputNALUnit nalu ) // Get a new picture buffer. This will also set up m_pcPic, and therefore give us a SPS and PPS pointer that we can use. m_pcPic = xGetNewPicBuffer( *sps, *pps, m_apcSlicePilot->getTLayer(), layerId ); +#if GDR_ENABLED + PicHeader *picHeader = new PicHeader; + *picHeader = m_picHeader; + m_apcSlicePilot->setPicHeader(picHeader); + m_pcPic->finalInit(vps, *sps, *pps, picHeader, apss, lmcsAPS, scalinglistAPS); +#else m_pcPic->finalInit( vps, *sps, *pps, &m_picHeader, apss, lmcsAPS, scalinglistAPS ); +#endif m_pcPic->createTempBuffers( m_pcPic->cs->pps->pcv->maxCUWidth ); m_pcPic->cs->createCoeffs((bool)m_pcPic->cs->sps->getPLTMode()); @@ -2769,6 +2780,26 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl m_cReshaper.setRecReshaped(false); } +#if GDR_LEAK_TEST + if (m_POC_RandomAccess == pcSlice->getPOC()) + { + for (int e = 0; e < 2; e++) + { + for (int ridx = 0; ridx < 4; ridx++) + { + Picture *pic = pcSlice->getRefPic((RefPicList)e, ridx); + if (pic) + { + CodingStructure& cs = *pic->cs; + cs.getRecoBuf().Y().fill(0 * 4); // for 8-bit sequence + cs.getRecoBuf().Cb().fill(0 * 4); + cs.getRecoBuf().Cr().fill(0 * 4); + cs.getMotionBuf().memset(0); // clear MV storage + } + } + } + } +#endif // GDR_LEAK_TEST // Decode a picture m_cSliceDecoder.decompressSlice( pcSlice, &( nalu.getBitstream() ), ( m_pcPic->poc == getDebugPOC() ? getDebugCTU() : -1 ) ); diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h index 9b53f1d62bfc7f0b4f5ab48d2bda12ec3ede0d42..78deaba84d51f859789c354b6f2c16fb796ae6ec 100644 --- a/source/Lib/DecoderLib/DecLib.h +++ b/source/Lib/DecoderLib/DecLib.h @@ -204,6 +204,11 @@ public: DCI* m_dci; ParameterSetMap<APS>* m_apsMapEnc; +#if GDR_LEAK_TEST +public: + int m_POC_RandomAccess; +#endif // GDR_LEAK_TEST + public: DecLib(); virtual ~DecLib(); diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index aa9688a2fb149fc877f7b4cd92146f2da76f4dc2..8b330e07ffcc3544af04cd5836ad4e00306d903a 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -280,6 +280,9 @@ void FDReader::parseFillerData(InputBitstream* bs, uint32_t &fdSize) HLSyntaxReader::HLSyntaxReader() { +#if GDR_ENABLED + m_last_gdr_poc = -1; +#endif } HLSyntaxReader::~HLSyntaxReader() @@ -2801,6 +2804,11 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag READ_UVLC(uiCode, "ph_virtual_boundary_pos_x_minus1[i]"); picHeader->setVirtualBoundariesPosX((uiCode + 1) << 3, i); CHECK(uiCode > (((pps->getPicWidthInLumaSamples() + 7) >> 3) - 2), "The value of ph_virtual_boundary_pos_x_minus1[ i ] shall be in the range of 0 to Ceil( pps_pic_width_in_luma_samples / 8 ) - 2, inclusive."); } +#if GDR_DEC_TRACE + printf("\n"); + printf("-num_ver_boundary :%d\n", picHeader->getNumVerVirtualBoundaries()); + printf("-vir_boundary_pos :%d\n", picHeader->getVirtualBoundariesPosX(0)); +#endif READ_UVLC(uiCode, "ph_num_hor_virtual_boundaries"); picHeader->setNumHorVirtualBoundaries( uiCode ); if (pps->getPicHeightInLumaSamples() <= 8) { @@ -4327,6 +4335,37 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, PicHeader* picHeader, Par pcSlice->addSubstreamSize(entryPointOffset [ idx ] ); } } +#if GDR_ENABLED + int cur_poc = pcSlice->getPOC(); + + if (picHeader->getGdrPicFlag()) + { + setLastGdrPoc(cur_poc); + setLastGdrRecoveryPocCnt(pcSlice->getPicHeader()->getRecoveryPocCnt()); + } + + int recovery_poc_cnt = getLastGdrRecoveryPocCnt(); + + if (getLastGdrPoc() > 0 && (getLastGdrPoc() <= cur_poc) && (cur_poc < (getLastGdrPoc() + recovery_poc_cnt))) + { + picHeader->setInGdrPeriod(true); + } + else + { + picHeader->setInGdrPeriod(false); + } +#endif + +#if GDR_DEC_TRACE + printf("-gdr_pic_flag:%d\n", picHeader->getGdrPicFlag() ? 1 : 0); + printf("-recovery_poc_cnt:%d\n", picHeader->getRecoveryPocCnt()); +#if GDR_ENABLED + printf("-inGdrPeriod:%d\n", picHeader->getInGdrPeriod()); +#endif + + printf("-lmcs_enable : %d\n", picHeader->getLmcsEnabledFlag() ? 1 : 0); + printf("-lmcs_chroma : %d\n", picHeader->getLmcsChromaResidualScaleFlag() ? 1 : 0); +#endif return; } diff --git a/source/Lib/DecoderLib/VLCReader.h b/source/Lib/DecoderLib/VLCReader.h index f2299e1a5bce3166fa09a437c21c78627cc233fe..dcbd89ab568dcc57af3b9696a4b999e2198dafc6 100644 --- a/source/Lib/DecoderLib/VLCReader.h +++ b/source/Lib/DecoderLib/VLCReader.h @@ -146,6 +146,11 @@ public: class HLSyntaxReader : public VLCReader { +#if GDR_ENABLED + int m_last_gdr_poc; + int m_last_gdr_recovery_poc_cnt; +#endif + public: HLSyntaxReader(); virtual ~HLSyntaxReader(); @@ -155,6 +160,12 @@ protected: void parseRefPicList(SPS* pcSPS, ReferencePictureList* rpl, int rplIdx); public: +#if GDR_ENABLED + void setLastGdrPoc(int poc) { m_last_gdr_poc = poc; } + int getLastGdrPoc() { return m_last_gdr_poc; } + void setLastGdrRecoveryPocCnt(int recovery_poc_cnt) { m_last_gdr_recovery_poc_cnt = recovery_poc_cnt; } + int getLastGdrRecoveryPocCnt() { return m_last_gdr_recovery_poc_cnt; } +#endif void setBitstream ( InputBitstream* p ) { m_pcBitstream = p; } void parseOPI ( OPI* opi ); void parseVPS ( VPS* pcVPS ); diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 8981657ec8b5051e96aff0489e7492158fa6baf9..d45a816a8e7a4e51224bef754c05a14ea6da6d7c 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -302,6 +302,14 @@ protected: bool m_subPicIdMappingInSpsFlag; unsigned m_subPicIdLen; std::vector<uint16_t> m_subPicId; +#if GDR_ENABLED + unsigned m_GdrPeriod; + unsigned m_GdrPocStart; + int m_GdrFrequency; + bool m_bStartWithGdr; + bool m_bNoHashForGdr; + bool m_bGdrPicOutput; +#endif bool m_useSplitConsOverride; unsigned m_uiMinQT[3]; //0: I slice; 1: P/B slice, 2: I slice chroma unsigned m_uiMaxBT[3]; //0: I slice; 1: P/B slice, 2: I slice chroma @@ -996,6 +1004,21 @@ public: void setMinQTSizes ( unsigned* minQT) { m_uiMinQT[0] = minQT[0]; m_uiMinQT[1] = minQT[1]; m_uiMinQT[2] = minQT[2]; } void setMaxBTSizes ( unsigned* maxBT) { m_uiMaxBT[0] = maxBT[0]; m_uiMaxBT[1] = maxBT[1]; m_uiMaxBT[2] = maxBT[2]; } void setMaxTTSizes ( unsigned* maxTT) { m_uiMaxTT[0] = maxTT[0]; m_uiMaxTT[1] = maxTT[1]; m_uiMaxTT[2] = maxTT[2]; } +#if GDR_ENABLED + void setGdrPeriod(unsigned u) { m_GdrPeriod = u; } + void setGdrPocStart(unsigned u) { m_GdrPocStart = u; } + void setGdrFrequency(int i) { m_GdrFrequency = i; } + void setStartWithGdr(bool b) { m_bStartWithGdr = b; } + void setNoHashForGdr(bool b) { m_bNoHashForGdr = b; } + void setGdrPicOutput(bool b) { m_bGdrPicOutput = b; } + + unsigned getGdrPeriod() { return m_GdrPeriod; } + unsigned getGdrPocStart() { return m_GdrPocStart; } + int getGdrFrequency() { return m_GdrFrequency; } + bool getStartWithGdr() { return m_bStartWithGdr; } + bool getNoHashForGdr() { return m_bNoHashForGdr; } + bool getGdrPicOutput() { return m_bGdrPicOutput; } +#endif void setMaxMTTHierarchyDepth ( unsigned uiMaxMTTHierarchyDepth, unsigned uiMaxMTTHierarchyDepthI, unsigned uiMaxMTTHierarchyDepthIChroma ) { m_uiMaxMTTHierarchyDepth = uiMaxMTTHierarchyDepth; m_uiMaxMTTHierarchyDepthI = uiMaxMTTHierarchyDepthI; m_uiMaxMTTHierarchyDepthIChroma = uiMaxMTTHierarchyDepthIChroma; } unsigned getMaxMTTHierarchyDepth () const { return m_uiMaxMTTHierarchyDepth; } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index bbfa1e7fcb71649384139b8ff237f8545a36c0e3..4b482a64cd97aed4118d71ba2c766d45511bff9c 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -555,6 +555,86 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par const UnitArea currCsArea = clipArea( CS::getArea( *bestCS, bestCS->area, partitioner.chType ), *tempCS->picture ); m_modeCtrl->initCULevel( partitioner, *tempCS ); +#if GDR_ENABLED + bool isCurGdrPicture = slice.getPicHeader()->getInGdrPeriod(); + + // 1.0 applicable to inter picture only + if (isCurGdrPicture) + { + int gdrPocStart = m_pcEncCfg->getGdrPocStart(); + int gdrPeriod = m_pcEncCfg->getGdrPeriod(); + + int picWidth = slice.getPPS()->getPicWidthInLumaSamples(); + int m1, m2, n1; + + int curPoc = slice.getPOC(); + int gdrPoc = (curPoc - gdrPocStart) % gdrPeriod; + + int begGdrX = 0; + int endGdrX = 0; + + double dd = (picWidth / (double)gdrPeriod); + int mm = (int)((picWidth / (double)gdrPeriod) + 0.49999); + m1 = ((mm + 7) >> 3) << 3; + m2 = ((mm + 0) >> 3) << 3; + + if (dd > mm && m1 == m2) + m1 = m1 + 8; + + n1 = (picWidth - m2 * gdrPeriod) / 8; + + if (gdrPoc < n1) + { + begGdrX = m1 * gdrPoc; + endGdrX = begGdrX + m1; + } + else + { + begGdrX = m1 * n1 + m2 * (gdrPoc - n1); + endGdrX = begGdrX + m2; + if (picWidth <= endGdrX) + { + endGdrX = picWidth; + endGdrX = picWidth; + } + } + + bool isInRefreshArea = tempCS->withinRefresh(begGdrX, endGdrX); + + if (isInRefreshArea) + { + m_modeCtrl->forceIntraMode(); + } + else if (tempCS->containRefresh(begGdrX, endGdrX) || tempCS->overlapRefresh(begGdrX, endGdrX)) + { + // 1.3.1 enable only vertical splits (QT, BT_V, TT_V) + m_modeCtrl->forceVerSplitOnly(); + + // 1.3.2 remove TT_V if it does not satisfy the condition + if (tempCS->refreshCrossTTV(begGdrX, endGdrX)) + { + m_modeCtrl->forceRemoveTTV(); + } + } + + if (tempCS->area.lwidth() != tempCS->area.lheight()) + { + m_modeCtrl->forceRemoveQT(); + } + + if (!m_modeCtrl->anyPredModeLeft()) + { + m_modeCtrl->forceRemoveDontSplit(); + } + + if (isInRefreshArea && !m_modeCtrl->anyIntraIBCMode() && (tempCS->area.lwidth() == 4 || tempCS->area.lheight() == 4)) + { + m_modeCtrl->finishCULevel(partitioner); + return; + } + } +#endif + if( partitioner.currQtDepth == 0 && partitioner.currMtDepth == 0 && !tempCS->slice->isIntra() && ( sps.getUseSBT() || sps.getUseInterMTS() ) ) { auto slsSbt = dynamic_cast<SaveLoadEncInfoSbt*>( m_modeCtrl ); @@ -829,7 +909,11 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par break; } } +#if GDR_ENABLED + if (bestCS->cus.size() > 0 && splitmode != bestCS->cus[0]->splitSeries) +#else if (splitmode != bestCS->cus[0]->splitSeries) +#endif { splitmode = bestCS->cus[0]->splitSeries; const CodingUnit& cu = *bestCS->cus.front(); @@ -1064,7 +1148,12 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, tempCS->getPredBuf().fill(0); AffineMVInfo tmpMVInfo; bool isAffMVInfoSaved; +#if GDR_ENABLED + AffineMVInfoSolid tmpMVInfoSolid; + m_pcInterSearch->savePrevAffMVInfo(0, tmpMVInfo, tmpMVInfoSolid, isAffMVInfoSaved); +#else m_pcInterSearch->savePrevAffMVInfo(0, tmpMVInfo, isAffMVInfoSaved); +#endif BlkUniMvInfo tmpUniMvInfo; bool isUniMvInfoSaved = false; if (!tempCS->slice->isIntra()) @@ -1343,10 +1432,18 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, // RD check for sub partitioned coding structure. xCheckBestMode( tempCS, bestCS, partitioner, encTestMode ); +#if GDR_ENABLED + if (isAffMVInfoSaved) + { + m_pcInterSearch->addAffMVInfo(tmpMVInfo, tmpMVInfoSolid); + } +#else if (isAffMVInfoSaved) { m_pcInterSearch->addAffMVInfo(tmpMVInfo); } +#endif + if (!tempCS->slice->isIntra() && isUniMvInfoSaved) { m_pcInterSearch->addUniMvInfo(tmpUniMvInfo); @@ -2023,6 +2120,10 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& MergeCtx mergeCtx; const SPS &sps = *tempCS->sps; +#if GDR_ENABLED + bool isEncodeClean = false; + CodingStructure *cs; +#endif if (sps.getSbTMVPEnabledFlag()) { Size bufSize = g_miScaling.scale( tempCS->area.lumaSize() ); @@ -2046,6 +2147,10 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& PU::getInterMergeCandidates(pu, mergeCtx, 0); PU::getInterMMVDMergeCandidates(pu, mergeCtx); pu.regularMergeFlag = true; +#if GDR_ENABLED + cs = pu.cs; + isEncodeClean = cs->pcv->isEncoder && ((cs->picHeader->getInGdrPeriod() && cs->isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs->picHeader->getNumVerVirtualBoundaries() == 0)); +#endif } bool candHasNoResidual[MRG_MAX_NUM_CANDS + MMVD_ADD_NUM]; for (uint32_t ui = 0; ui < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM; ui++) @@ -2210,6 +2315,42 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& uint64_t fracBits = m_pcInterSearch->xCalcPuMeBits(pu); double cost = (double)uiSad + (double)fracBits * sqrtLambdaForFirstPassIntra; insertPos = -1; + +#if GDR_ENABLED + // Non-RD cost for regular merge + if (isEncodeClean) + { + bool isSolid = true; + bool isValid = true; + + if (mergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 0].refIdx >= 0) + { + Mv mv = mergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 0].mv; + int ridx = mergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 0].refIdx; + + mergeCtx.mvValid[(uiMergeCand << 1) + 0] = cs->isClean(pu.Y().bottomRight(), mv, REF_PIC_LIST_0, ridx); + + isSolid = isSolid && mergeCtx.mvSolid[(uiMergeCand << 1) + 0]; + isValid = isValid && mergeCtx.mvValid[(uiMergeCand << 1) + 0]; + } + + if (mergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 1].refIdx >= 0) \ + { + Mv mv = mergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 1].mv; + int ridx = mergeCtx.mvFieldNeighbours[(uiMergeCand << 1) + 1].refIdx; + + mergeCtx.mvValid[(uiMergeCand << 1) + 1] = cs->isClean(pu.Y().bottomRight(), mv, REF_PIC_LIST_1, ridx); + + isSolid = isSolid && mergeCtx.mvSolid[(uiMergeCand << 1) + 1]; + isValid = isValid && mergeCtx.mvValid[(uiMergeCand << 1) + 1]; + } + + if (!isValid || !isSolid) + { + cost = MAX_DOUBLE; + } + } +#endif updateCandList(ModeInfo(uiMergeCand, true, false, false), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos); if (insertPos != -1) { @@ -2226,7 +2367,9 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]); } } +#if !GDR_ENABLED CHECK(std::min(uiMergeCand + 1, uiNumMrgSATDCand) != RdModeList.size(), ""); +#endif } if (isIntrainterEnabled) @@ -2280,6 +2423,42 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& pu.regularMergeFlag = false; uint64_t fracBits = m_pcInterSearch->xCalcPuMeBits(pu); double cost = (double)sadValue + (double)fracBits * sqrtLambdaForFirstPassIntra; +#if GDR_ENABLED + // Non-RD cost for CIIP merge + if (isEncodeClean) + { + bool isSolid = true; + bool isValid = true; + + if (mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 0].refIdx >= 0) + { + Mv mv = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 0].mv; + int ridx = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 0].refIdx; + + mergeCtx.mvValid[(mergeCand << 1) + 0] = cs->isClean(pu.Y().bottomRight(), mv, REF_PIC_LIST_0, ridx); + + isSolid = isSolid && mergeCtx.mvSolid[(mergeCand << 1) + 0]; + isValid = isValid && mergeCtx.mvValid[(mergeCand << 1) + 0]; + } + + if (mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 1].refIdx >= 0) + { + Mv mv = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 1].mv; + int ridx = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 1].refIdx; + + mergeCtx.mvValid[(mergeCand << 1) + 1] = cs->isClean(pu.Y().bottomRight(), mv, REF_PIC_LIST_1, ridx); + + isSolid = isSolid && mergeCtx.mvSolid[(mergeCand << 1) + 1]; + isValid = isValid && mergeCtx.mvValid[(mergeCand << 1) + 1]; + } + + if (!isValid || !isSolid) + { + cost = MAX_DOUBLE; + } + } +#endif + insertPos = -1; updateCandList(ModeInfo(mergeCand, false, false, true), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos); if (insertPos != -1) @@ -2306,6 +2485,16 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& { continue; } +#if GDR_ENABLED + if (isEncodeClean) + { + pu.mvSolid[REF_PIC_LIST_0] = true; + pu.mvSolid[REF_PIC_LIST_1] = true; + + pu.mvValid[REF_PIC_LIST_0] = true; + pu.mvValid[REF_PIC_LIST_1] = true; + } +#endif mergeCtx.setMmvdMergeCandiInfo(pu, mmvdMergeCand); PU::spanMotionInfo(pu, mergeCtx); @@ -2323,6 +2512,35 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& uint64_t fracBits = m_pcInterSearch->xCalcPuMeBits(pu); double cost = (double)uiSad + (double)fracBits * sqrtLambdaForFirstPassIntra; insertPos = -1; + +#if GDR_ENABLED + if (isEncodeClean) + { + bool isSolid = true; + bool isValid = true; + + if (pu.refIdx[0] >= 0) + { + isSolid = isSolid && pu.mvSolid[0]; + isValid = isValid && pu.mvValid[0]; + } + + if (pu.refIdx[1] >= 0) + { + isSolid = isSolid && pu.mvSolid[1]; + isValid = isValid && pu.mvValid[1]; + } + + if (!isSolid || !isValid) + { + cost = MAX_DOUBLE; + } + else + { + cost = cost; + } + } +#endif updateCandList(ModeInfo(mmvdMergeCand, false, true, false), cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos); if (insertPos != -1) { @@ -2540,7 +2758,36 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& isTestSkipMerge[uiMergeCand] = true; } +#if GDR_ENABLED + if (isEncodeClean) + { + bool isSolid = true; + bool isValid = true; + + if (pu.refIdx[0] >= 0) + { + isSolid = isSolid && pu.mvSolid[0]; + isValid = isValid && pu.mvValid[0]; + } + + if (pu.refIdx[1] >= 0) + { + isSolid = isSolid && pu.mvSolid[1]; + isValid = isValid && pu.mvValid[1]; + } + + if (isSolid && isValid) + { + xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : NULL); + } + } + else + { + xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : NULL); + } +#else xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : NULL ); +#endif if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip && !pu.ciipFlag) { @@ -2620,6 +2867,11 @@ void EncCu::xCheckRDCostMergeGeo2Nx2N(CodingStructure *&tempCS, CodingStructure cu.bdpcmMode = 0; PredictionUnit &pu = tempCS->addPU(cu, pm.chType); +#if GDR_ENABLED + CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif + pu.mergeFlag = true; pu.regularMergeFlag = false; PU::getGeoMergeCandidates(pu, mergeCtx); @@ -2642,6 +2894,21 @@ void EncCu::xCheckRDCostMergeGeo2Nx2N(CodingStructure *&tempCS, CodingStructure int pocMrg[GEO_MAX_NUM_UNI_CANDS]; Mv MrgMv[GEO_MAX_NUM_UNI_CANDS]; bool isSkipThisCand[GEO_MAX_NUM_UNI_CANDS]; +#if GDR_ENABLED + bool *MrgSolid = nullptr; + bool *MrgValid = nullptr; + + if (isEncodeClean) + { + MrgSolid = new bool[maxNumMergeCandidates]; + MrgValid = new bool[maxNumMergeCandidates]; + for (int i = 0; i < maxNumMergeCandidates; i++) + { + MrgSolid[i] = true; + MrgValid[i] = true; + } + } +#endif for (int i = 0; i < maxNumMergeCandidates; i++) { isSkipThisCand[i] = false; @@ -2655,6 +2922,13 @@ void EncCu::xCheckRDCostMergeGeo2Nx2N(CodingStructure *&tempCS, CodingStructure int MrgrefIdx = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + MrgList].refIdx; pocMrg[mergeCand] = tempCS->slice->getRefPic(MrgeRefPicList, MrgrefIdx)->getPOC(); MrgMv[mergeCand] = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + MrgList].mv; +#if GDR_ENABLED + if (isEncodeClean) + { + MrgSolid[mergeCand] = mergeCtx.mvSolid[(mergeCand << 1) + MrgList]; + MrgValid[mergeCand] = mergeCtx.mvValid[(mergeCand << 1) + MrgList]; + } +#endif if (mergeCand) { for (int i = 0; i < mergeCand; i++) @@ -2679,7 +2953,20 @@ void EncCu::xCheckRDCostMergeGeo2Nx2N(CodingStructure *&tempCS, CodingStructure distParamWholeBlk.cur.buf = geoTempBuf[mergeCand].Y().buf; distParamWholeBlk.cur.stride = geoTempBuf[mergeCand].Y().stride; sadWholeBlk[mergeCand] = distParamWholeBlk.distFunc(distParamWholeBlk); +#if GDR_ENABLED + bool allOk = (sadWholeBlk[mergeCand] < bestWholeBlkSad); + if (isEncodeClean) + { + bool isSolid = mergeCtx.mvSolid[(mergeCand << 1) + MrgList]; + bool isValid = mergeCtx.mvValid[(mergeCand << 1) + MrgList]; + allOk = allOk && isSolid && isValid; + } +#endif +#if GDR_ENABLED + if (allOk) +#else if (sadWholeBlk[mergeCand] < bestWholeBlkSad) +#endif { bestWholeBlkSad = sadWholeBlk[mergeCand]; int bitsCand = mergeCand + 1; @@ -2727,12 +3014,44 @@ void EncCu::xCheckRDCostMergeGeo2Nx2N(CodingStructure *&tempCS, CodingStructure for (uint8_t mergeCand = 0; mergeCand < maxNumMergeCandidates; mergeCand++) { int bitsCand = mergeCand + 1; +#if GDR_ENABLED + if (isEncodeClean) + { + double cost0, cost1; + m_pcRdCost->setDistParam(distParam, tempCS->getOrgBuf().Y(), geoTempBuf[mergeCand].Y().buf, geoTempBuf[mergeCand].Y().stride, SADmask, maskStride, stepX, maskStride2, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y); + sadLarge = distParam.distFunc(distParam); + sadSmall = sadWholeBlk[mergeCand] - sadLarge; + + if (MrgSolid[mergeCand] && MrgValid[mergeCand]) + { + cost0 = (double)sadLarge + (double)bitsCand * sqrtLambdaForFirstPass; + cost1 = (double)sadSmall + (double)bitsCand * sqrtLambdaForFirstPass; + } + else + { + cost0 = MAX_DOUBLE; + cost1 = MAX_DOUBLE; + } + + m_GeoCostList.insert(splitDir, 0, mergeCand, cost0); + m_GeoCostList.insert(splitDir, 1, mergeCand, cost1); + } + else + { + m_pcRdCost->setDistParam(distParam, tempCS->getOrgBuf().Y(), geoTempBuf[mergeCand].Y().buf, geoTempBuf[mergeCand].Y().stride, SADmask, maskStride, stepX, maskStride2, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y); + sadLarge = distParam.distFunc(distParam); + m_GeoCostList.insert(splitDir, 0, mergeCand, (double)sadLarge + (double)bitsCand * sqrtLambdaForFirstPass); + sadSmall = sadWholeBlk[mergeCand] - sadLarge; + m_GeoCostList.insert(splitDir, 1, mergeCand, (double)sadSmall + (double)bitsCand * sqrtLambdaForFirstPass); + } +#else m_pcRdCost->setDistParam(distParam, tempCS->getOrgBuf().Y(), geoTempBuf[mergeCand].Y().buf, geoTempBuf[mergeCand].Y().stride, SADmask, maskStride, stepX, maskStride2, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y); sadLarge = distParam.distFunc(distParam); m_GeoCostList.insert(splitDir, 0, mergeCand, (double)sadLarge + (double)bitsCand * sqrtLambdaForFirstPass); sadSmall = sadWholeBlk[mergeCand] - sadLarge; m_GeoCostList.insert(splitDir, 1, mergeCand, (double)sadSmall + (double)bitsCand * sqrtLambdaForFirstPass); +#endif } } @@ -2748,6 +3067,22 @@ void EncCu::xCheckRDCostMergeGeo2Nx2N(CodingStructure *&tempCS, CodingStructure continue; } tempCost = tempCost + (double)bitsCandTB * sqrtLambdaForFirstPass; +#if GDR_ENABLED + if (isEncodeClean) + { + int idx0 = mergeCand0; + int idx1 = mergeCand1; + bool isSolid0 = mergeCtx.mvSolid[(idx0 << 1) + 0] && mergeCtx.mvSolid[(idx0 << 1) + 1]; + bool isSolid1 = mergeCtx.mvSolid[(idx1 << 1) + 0] && mergeCtx.mvSolid[(idx1 << 1) + 1]; + bool isValid0 = mergeCtx.mvValid[(idx0 << 1) + 0] && mergeCtx.mvValid[(idx0 << 1) + 1]; + bool isValid1 = mergeCtx.mvValid[(idx1 << 1) + 0] && mergeCtx.mvValid[(idx1 << 1) + 1]; + + if (!isSolid0 || !isSolid1 || !isValid0 || !isValid1) + { + tempCost = MAX_DOUBLE; + } + } +#endif comboList.list.push_back(GeoMergeCombo(splitDir, mergeCand0, mergeCand1, tempCost)); } } @@ -2786,6 +3121,22 @@ void EncCu::xCheckRDCostMergeGeo2Nx2N(CodingStructure *&tempCS, CodingStructure mvBits += mergeCand0; mvBits += mergeCand1; double updateCost = (double)sad + (double)(bitsCandTB + mvBits) * sqrtLambdaForFirstPass; +#if GDR_ENABLED + if (isEncodeClean) + { + int idx0 = mergeCand0; + int idx1 = mergeCand1; + bool isSolid0 = mergeCtx.mvSolid[(idx0 << 1) + 0] && mergeCtx.mvSolid[(idx0 << 1) + 1]; + bool isSolid1 = mergeCtx.mvSolid[(idx1 << 1) + 0] && mergeCtx.mvSolid[(idx1 << 1) + 1]; + bool isValid0 = mergeCtx.mvValid[(idx0 << 1) + 0] && mergeCtx.mvValid[(idx0 << 1) + 1]; + bool isValid1 = mergeCtx.mvValid[(idx1 << 1) + 0] && mergeCtx.mvValid[(idx1 << 1) + 1]; + + if (!isSolid0 || !isSolid1 || !isValid0 || !isValid1) + { + updateCost = MAX_DOUBLE; + } + } +#endif comboList.list[candidateIdx].cost = updateCost; updateCandList(candidateIdx, updateCost, geoRdModeList, geocandCostList, geoNumMrgSATDCand); } @@ -2850,7 +3201,28 @@ void EncCu::xCheckRDCostMergeGeo2Nx2N(CodingStructure *&tempCS, CodingStructure PU::spanGeoMotionInfo(pu, mergeCtx, pu.geoSplitDir, pu.geoMergeIdx0, pu.geoMergeIdx1); tempCS->getPredBuf().copyFrom(geoCombinations[candidateIdx]); +#if GDR_ENABLED + if (isEncodeClean) + { + int idx0 = pu.geoMergeIdx0; + int idx1 = pu.geoMergeIdx1; + bool isSolid0 = mergeCtx.mvSolid[(idx0 << 1) + 0] && mergeCtx.mvSolid[(idx0 << 1) + 1]; + bool isSolid1 = mergeCtx.mvSolid[(idx1 << 1) + 0] && mergeCtx.mvSolid[(idx1 << 1) + 1]; + bool isValid0 = mergeCtx.mvValid[(idx0 << 1) + 0] && mergeCtx.mvValid[(idx0 << 1) + 1]; + bool isValid1 = mergeCtx.mvValid[(idx1 << 1) + 0] && mergeCtx.mvValid[(idx1 << 1) + 1]; + + if (isSolid0 && isSolid1 && isValid0 && isValid1) + { + xEncodeInterResidual(tempCS, bestCS, pm, encTestMode, noResidualPass, (noResidualPass == 0 ? &geocandHasNoResidual[candidateIdx] : NULL)); + } + } + else + { + xEncodeInterResidual(tempCS, bestCS, pm, encTestMode, noResidualPass, (noResidualPass == 0 ? &geocandHasNoResidual[candidateIdx] : NULL)); + } +#else xEncodeInterResidual(tempCS, bestCS, pm, encTestMode, noResidualPass, (noResidualPass == 0 ? &geocandHasNoResidual[candidateIdx] : NULL)); +#endif if (m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip) { @@ -2863,6 +3235,14 @@ void EncCu::xCheckRDCostMergeGeo2Nx2N(CodingStructure *&tempCS, CodingStructure { xCalDebCost(*bestCS, pm); } + +#if GDR_ENABLED + if (isEncodeClean) + { + delete[] MrgSolid; + delete[] MrgValid; + } +#endif } void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode ) @@ -2876,6 +3256,10 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct { return; } +#if GDR_ENABLED + CodingStructure *cs; + bool isEncodeClean = false; +#endif m_bestModeUpdated = tempCS->useDbCost = bestCS->useDbCost = false; const Slice &slice = *tempCS->slice; @@ -2913,6 +3297,10 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct pu.cu = &cu; pu.cs = tempCS; pu.regularMergeFlag = false; +#if GDR_ENABLED + cs = pu.cs; + isEncodeClean = cs->pcv->isEncoder && ((cs->picHeader->getInGdrPeriod() && cs->isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs->picHeader->getNumVerVirtualBoundaries() == 0)); +#endif PU::getAffineMergeCand( pu, affineMergeCtx ); if ( affineMergeCtx.numValidMergeCand <= 0 ) @@ -3003,6 +3391,19 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct PU::spanMotionInfo( pu ); } +#if GDR_ENABLED + if (isEncodeClean) + { + Mv zero = Mv(0, 0); + bool isValid = cs->isSubPuClean(pu, &zero); + affineMergeCtx.mvValid[(uiMergeCand << 1) + 0][0] = isValid; + affineMergeCtx.mvValid[(uiMergeCand << 1) + 0][1] = isValid; + affineMergeCtx.mvValid[(uiMergeCand << 1) + 0][2] = isValid; + affineMergeCtx.mvValid[(uiMergeCand << 1) + 1][0] = isValid; + affineMergeCtx.mvValid[(uiMergeCand << 1) + 1][1] = isValid; + affineMergeCtx.mvValid[(uiMergeCand << 1) + 1][2] = isValid; + } +#endif distParam.cur = acMergeBuffer[uiMergeCand].Y(); m_pcInterSearch->motionCompensation( pu, acMergeBuffer[uiMergeCand], REF_PIC_LIST_X, true, false ); @@ -3014,6 +3415,23 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct uiBitsCand--; } double cost = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass; +#if GDR_ENABLED + if (isEncodeClean) + { + bool isSolid0 = affineMergeCtx.mvSolid[(uiMergeCand << 1) + 0][0] && affineMergeCtx.mvSolid[(uiMergeCand << 1) + 0][1] && affineMergeCtx.mvSolid[(uiMergeCand << 1) + 0][2]; + bool isSolid1 = affineMergeCtx.mvSolid[(uiMergeCand << 1) + 1][0] && affineMergeCtx.mvSolid[(uiMergeCand << 1) + 1][1] && affineMergeCtx.mvSolid[(uiMergeCand << 1) + 1][2]; + bool isValid0 = affineMergeCtx.mvValid[(uiMergeCand << 1) + 0][0] && affineMergeCtx.mvValid[(uiMergeCand << 1) + 0][1] && affineMergeCtx.mvValid[(uiMergeCand << 1) + 0][2]; + bool isValid1 = affineMergeCtx.mvValid[(uiMergeCand << 1) + 1][0] && affineMergeCtx.mvValid[(uiMergeCand << 1) + 1][1] && affineMergeCtx.mvValid[(uiMergeCand << 1) + 1][2]; + + bool isSolid = isSolid0 && isSolid1; + bool isValid = isValid0 && isValid1; + + if (!isSolid || !isValid) + { + cost = MAX_DOUBLE; + } + } +#endif updateCandList( uiMergeCand, cost, RdModeList, candCostList , uiNumMrgSATDCand ); @@ -3106,11 +3524,59 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct m_pcInterSearch->motionCompensation( pu ); } +#if GDR_ENABLED + bool isSolid = true; + bool isValid = true; + + if (isEncodeClean) + { + if (bestIsSkip) + { + Mv zero = Mv(0, 0); + bool isValid = cs->isSubPuClean(pu, &zero); + affineMergeCtx.mvValid[(uiMergeCand << 1) + 0][0] = isValid; + affineMergeCtx.mvValid[(uiMergeCand << 1) + 0][1] = isValid; + affineMergeCtx.mvValid[(uiMergeCand << 1) + 0][2] = isValid; + affineMergeCtx.mvValid[(uiMergeCand << 1) + 1][0] = isValid; + affineMergeCtx.mvValid[(uiMergeCand << 1) + 1][1] = isValid; + affineMergeCtx.mvValid[(uiMergeCand << 1) + 1][2] = isValid; + } + + bool isSolid0 = affineMergeCtx.mvSolid[(uiMergeCand << 1) + 0][0] && affineMergeCtx.mvSolid[(uiMergeCand << 1) + 0][1] && affineMergeCtx.mvSolid[(uiMergeCand << 1) + 0][2]; + bool isSolid1 = affineMergeCtx.mvSolid[(uiMergeCand << 1) + 1][0] && affineMergeCtx.mvSolid[(uiMergeCand << 1) + 1][1] && affineMergeCtx.mvSolid[(uiMergeCand << 1) + 1][2]; + bool isValid0 = affineMergeCtx.mvValid[(uiMergeCand << 1) + 0][0] && affineMergeCtx.mvValid[(uiMergeCand << 1) + 0][1] && affineMergeCtx.mvValid[(uiMergeCand << 1) + 0][2]; + bool isValid1 = affineMergeCtx.mvValid[(uiMergeCand << 1) + 1][0] && affineMergeCtx.mvValid[(uiMergeCand << 1) + 1][1] && affineMergeCtx.mvValid[(uiMergeCand << 1) + 1][2]; + + isSolid = isSolid0 && isSolid1; + isValid = isValid0 && isValid1; + + if (isSolid && isValid) + { + xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, (uiNoResidualPass == 0 ? &candHasNoResidual[uiMergeCand] : NULL)); + } + } + else + { + xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, (uiNoResidualPass == 0 ? &candHasNoResidual[uiMergeCand] : NULL)); + } +#else xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, ( uiNoResidualPass == 0 ? &candHasNoResidual[uiMergeCand] : NULL ) ); +#endif if ( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip ) { - bestIsSkip = bestCS->getCU( partitioner.chType )->rootCbf == 0; +#if GDR_ENABLED + if (bestCS->getCU(partitioner.chType)) + { + bestIsSkip = bestCS->getCU(partitioner.chType)->rootCbf == 0; + } + else + { + bestIsSkip = false; + } +#else + bestIsSkip = bestCS->getCU(partitioner.chType)->rootCbf == 0; +#endif } tempCS->initStructData( encTestMode.qp ); }// end loop uiMrgHADIdx @@ -3171,6 +3637,9 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct mergeCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize); } +#if GDR_ENABLED + bool bGDRclean = true; +#endif { // first get merge candidates CodingUnit cu(tempCS->area); @@ -3186,7 +3655,15 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct pu.regularMergeFlag = false; cu.geoFlag = false; PU::getIBCMergeCandidates(pu, mergeCtx); +#if GDR_ENABLED + bGDRclean = tempCS->isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA) || tempCS->picHeader->getNumVerVirtualBoundaries() == 0; +#endif } +#if GDR_ENABLED + const bool isEncodeClean = tempCS->pcv->isEncoder && tempCS->picHeader->getInGdrPeriod() && bGDRclean; + bool *MrgSolid = nullptr; + bool *MrgValid = nullptr; +#endif int candHasNoResidual[MRG_MAX_NUM_CANDS]; for (unsigned int ui = 0; ui < mergeCtx.numValidMergeCand; ui++) @@ -3194,6 +3671,19 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct candHasNoResidual[ui] = 0; } +#if GDR_ENABLED + if (isEncodeClean) + { + MrgSolid = new bool[MRG_MAX_NUM_CANDS]; + MrgValid = new bool[MRG_MAX_NUM_CANDS]; + for (int i = 0; i < MRG_MAX_NUM_CANDS; i++) + { + MrgSolid[i] = false; + MrgValid[i] = false; + } + } +#endif + bool bestIsSkip = false; unsigned numMrgSATDCand = mergeCtx.numValidMergeCand; static_vector<unsigned, MRG_MAX_NUM_CANDS> RdModeList(MRG_MAX_NUM_CANDS); @@ -3275,7 +3765,41 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct bitsCand--; } double cost = (double) sad + (double) bitsCand * sqrtLambdaForFirstPass; +#if GDR_ENABLED + if (isEncodeClean) + { + bool isSolid = true; + bool isValid = true; + if (mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 0].refIdx >= 0) + { + Mv mv = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 0].mv; + int ridx = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 0].refIdx; + + mergeCtx.mvValid[(mergeCand << 1) + 0] = tempCS->isClean(pu.Y().bottomRight(), mv, REF_PIC_LIST_0, ridx, true); + + isSolid = isSolid && mergeCtx.mvSolid[(mergeCand << 1) + 0]; + isValid = isValid && mergeCtx.mvValid[(mergeCand << 1) + 0]; + } + + if (mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 1].refIdx >= 0) + { + Mv mv = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 1].mv; + int ridx = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 1].refIdx; + + mergeCtx.mvValid[(mergeCand << 1) + 1] = tempCS->isClean(pu.Y().bottomRight(), mv, REF_PIC_LIST_1, ridx, true); + + isSolid = isSolid && mergeCtx.mvSolid[(mergeCand << 1) + 1]; + isValid = isValid && mergeCtx.mvValid[(mergeCand << 1) + 1]; + } + + if (!isValid || !isSolid) + { + cost = MAX_DOUBLE; + numValidBv--; + } + } +#endif updateCandList(mergeCand, cost, RdModeList, candCostList, numMrgSATDCand); } @@ -3342,12 +3866,62 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct assert(mergeCtx.mrgTypeNeighbours[mergeCand] == MRG_TYPE_IBC); // should be IBC candidate at this round const bool chroma = !pu.cu->isSepTree(); +#if GDR_ENABLED + // redo validation again for Skip + { + CodingStructure &cs = *pu.cs; + if (isEncodeClean) + { + if (mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 0].refIdx >= 0) + { + Mv mv = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 0].mv; + int ridx = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 0].refIdx; + + mergeCtx.mvValid[(mergeCand << 1) + 0] = cs.isClean(pu.Y().bottomRight(), mv, REF_PIC_LIST_0, ridx, true); + } + + if (mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 1].refIdx >= 0) + { + Mv mv = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 1].mv; + int ridx = mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 1].refIdx; + mergeCtx.mvValid[(mergeCand << 1) + 1] = cs.isClean(pu.Y().bottomRight(), mv, REF_PIC_LIST_1, ridx, true); + } + } + } +#endif // MC m_pcInterSearch->motionCompensation(pu,REF_PIC_LIST_0, true, chroma); m_CABACEstimator->getCtx() = m_CurrCtx->start; +#if GDR_ENABLED + if (isEncodeClean) + { + bool mvSolid = true; + bool mvValid = true; + if (mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 0].refIdx >= 0) + { + mvSolid = mvSolid && mergeCtx.mvSolid[(mergeCand << 1) + 0]; + mvValid = mvValid && mergeCtx.mvValid[(mergeCand << 1) + 0]; + } + if (mergeCtx.mvFieldNeighbours[(mergeCand << 1) + 1].refIdx >= 0) + { + mvSolid = mvSolid && mergeCtx.mvSolid[(mergeCand << 1) + 1]; + mvValid = mvValid && mergeCtx.mvValid[(mergeCand << 1) + 1]; + } + + if (mvSolid && mvValid) + { + m_pcInterSearch->encodeResAndCalcRdInterCU(*tempCS, partitioner, (numResidualPass != 0), true, chroma); + } + } + else + { + m_pcInterSearch->encodeResAndCalcRdInterCU(*tempCS, partitioner, (numResidualPass != 0), true, chroma); + } +#else m_pcInterSearch->encodeResAndCalcRdInterCU(*tempCS, partitioner, (numResidualPass != 0), true, chroma); +#endif if (tempCS->slice->getSPS()->getUseColorTrans()) { bestCS->tmpColorSpaceCost = tempCS->tmpColorSpaceCost; @@ -3392,6 +3966,13 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct { xCalDebCost( *bestCS, partitioner ); } +#if GDR_ENABLED + if (isEncodeClean) + { + delete[] MrgSolid; + delete[] MrgValid; + } +#endif } void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode) @@ -3544,6 +4125,9 @@ void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestC uint8_t bcwIdx = cu.BcwIdx; bool testBcw = (bcwIdx != BCW_DEFAULT); +#if GDR_ENABLED + const bool isEncodeClean = tempCS->pcv->isEncoder && ((tempCS->picHeader->getInGdrPeriod() && tempCS->isClean(cu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (tempCS->picHeader->getNumVerVirtualBoundaries() == 0)); +#endif m_pcInterSearch->predInterSearch(cu, partitioner); bcwIdx = CU::getValidBcwIdx(cu); @@ -3563,13 +4147,98 @@ void EncCu::xCheckRDCostInter( CodingStructure *&tempCS, CodingStructure *&bestC } } +#if GDR_ENABLED + // 2.0 xCheckRDCostInter: check residual (compare with bestCS) + if (isEncodeClean) + { + bool isClean = true; + + if (cu.affine && cu.firstPU) + { + bool L0ok = true, L1ok = true, L3ok = true; + + L0ok = L0ok && cu.firstPU->mvAffiSolid[0][0] && cu.firstPU->mvAffiSolid[0][1] && cu.firstPU->mvAffiSolid[0][2]; + L0ok = L0ok && cu.firstPU->mvAffiValid[0][0] && cu.firstPU->mvAffiValid[0][1] && cu.firstPU->mvAffiValid[0][2]; + + L1ok = L1ok && cu.firstPU->mvAffiSolid[1][0] && cu.firstPU->mvAffiSolid[1][1] && cu.firstPU->mvAffiSolid[1][2]; + L1ok = L1ok && cu.firstPU->mvAffiValid[1][0] && cu.firstPU->mvAffiValid[1][1] && cu.firstPU->mvAffiValid[1][2]; + + L3ok = L0ok && L1ok; + + if (cu.firstPU->interDir == 1 && !L0ok) + { + isClean = false; + } + if (cu.firstPU->interDir == 2 && !L1ok) + { + isClean = false; + } + if (cu.firstPU->interDir == 3 && !L3ok) + { + isClean = false; + } + } + else if (cu.firstPU) + { + bool L0ok = true; + bool L1ok = true; + bool L3ok = true; + + L0ok = L0ok && cu.firstPU->mvSolid[0]; + L0ok = L0ok && cu.firstPU->mvValid[0]; + + L1ok = L1ok && cu.firstPU->mvSolid[1]; + L1ok = L1ok && cu.firstPU->mvValid[1]; + + L3ok = L0ok && L1ok; + + if (cu.firstPU->interDir == 1 && !L0ok) + { + isClean = false; + } + if (cu.firstPU->interDir == 2 && !L1ok) + { + isClean = false; + } + if (cu.firstPU->interDir == 3 && !L3ok) + { + isClean = false; + } + } + else + { + isClean = false; + } + + if (isClean) + { + xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, 0 + , 0 + , &equBcwCost + ); + } + } + else + { + xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, 0 + , 0 + , &equBcwCost + ); + } +#else xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, 0, 0, &equBcwCost); +#endif +#if GDR_ENABLED + if (g_BcwSearchOrder[bcwLoopIdx] == BCW_DEFAULT && bestCS->cus.size() > 0) + m_pcInterSearch->setAffineModeSelected((bestCS->cus.front()->affine && !(bestCS->cus.front()->firstPU->mergeFlag))); +#else if (g_BcwSearchOrder[bcwLoopIdx] == BCW_DEFAULT) { m_pcInterSearch->setAffineModeSelected( (bestCS->cus.front()->affine && !(bestCS->cus.front()->firstPU->mergeFlag))); } +#endif tempCS->initStructData(encTestMode.qp); @@ -3674,6 +4343,9 @@ bool EncCu::xCheckRDCostInterIMV(CodingStructure *&tempCS, CodingStructure *&bes CU::addPUs( cu ); +#if GDR_ENABLED + const bool isEncodeClean = tempCS->pcv->isEncoder && ((tempCS->picHeader->getInGdrPeriod() && tempCS->isClean(cu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (tempCS->picHeader->getNumVerVirtualBoundaries() == 0)); +#endif if (testAltHpelFilter) { cu.imv = IMV_HPEL; @@ -3745,7 +4417,79 @@ bool EncCu::xCheckRDCostInterIMV(CodingStructure *&tempCS, CodingStructure *&bes } } +#if GDR_ENABLED + // 2.0 xCheckRDCostInter: check residual (compare with bestCS) + if (isEncodeClean) + { + bool isClean = true; + + if (cu.affine && cu.firstPU) + { + bool L0ok = true, L1ok = true, L3ok = true; + + L0ok = L0ok && cu.firstPU->mvAffiSolid[0][0] && cu.firstPU->mvAffiSolid[0][1] && cu.firstPU->mvAffiSolid[0][2]; + L0ok = L0ok && cu.firstPU->mvAffiValid[0][0] && cu.firstPU->mvAffiValid[0][1] && cu.firstPU->mvAffiValid[0][2]; + + L1ok = L1ok && cu.firstPU->mvAffiSolid[1][0] && cu.firstPU->mvAffiSolid[1][1] && cu.firstPU->mvAffiSolid[1][2]; + L1ok = L1ok && cu.firstPU->mvAffiValid[1][0] && cu.firstPU->mvAffiValid[1][1] && cu.firstPU->mvAffiValid[1][2]; + + L3ok = L0ok && L1ok; + + if (cu.firstPU->interDir == 1 && !L0ok) + { + isClean = false; + } + if (cu.firstPU->interDir == 2 && !L1ok) + { + isClean = false; + } + if (cu.firstPU->interDir == 3 && !L3ok) + { + isClean = false; + } + } + else if (cu.firstPU) + { + bool L0ok = cu.firstPU->mvSolid[0] && cu.firstPU->mvValid[0]; + bool L1ok = cu.firstPU->mvSolid[1] && cu.firstPU->mvValid[1]; + bool L3ok = L0ok && L1ok; + + if (cu.firstPU->interDir == 1 && !L0ok) + { + isClean = false; + } + if (cu.firstPU->interDir == 2 && !L1ok) + { + isClean = false; + } + if (cu.firstPU->interDir == 3 && !L3ok) + { + isClean = false; + } + } + else + { + isClean = false; + } + + if (isClean) + { + xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, 0 + , 0 + , &equBcwCost + ); + } + } + else + { + xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, 0 + , 0 + , &equBcwCost + ); + } +#else xEncodeInterResidual(tempCS, bestCS, partitioner, encTestModeBase, 0, 0, &equBcwCost); +#endif if( cu.imv == IMV_FPEL && tempCS->cost < bestIntPelCost ) { diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h index b953c9b2f26e3621e77d57d478cc7091c1e51ac5..7682705aa0f2d56099e45642fd150d4aecc87a9e 100644 --- a/source/Lib/EncoderLib/EncCu.h +++ b/source/Lib/EncoderLib/EncCu.h @@ -88,7 +88,28 @@ struct SmallerThanComboCost { inline bool operator() (const GeoMergeCombo& first, const GeoMergeCombo& second) { +#if GDR_ENABLED + bool ret = true; + + ret = (first.cost < second.cost); + + if (first.cost == second.cost) + { + ret = first.splitDir < second.splitDir; + if (first.splitDir == second.splitDir) + { + ret = first.mergeIdx0 < second.mergeIdx0; + if (first.mergeIdx0 == second.mergeIdx0) + { + ret = first.mergeIdx1 < second.mergeIdx1; + } + } + } + + return ret; +#else return (first.cost < second.cost); +#endif } }; class GeoComboCostList diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index 69368d1531182bf2ea39bd147565ef9fdf6dfb14..11d190b39ed4f683f9af2a5a55b8da5954c5fa19 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -312,6 +312,9 @@ void EncGOP::init ( EncLib* pcEncLib ) m_pcTransferFct = hdrtoolslib::TransferFunction::create(hdrtoolslib::TF_PQ, true, (float) maxSampleValue, 0, 0.0, 1.0, enableTFunctionLUT); } #endif +#if GDR_ENABLED + m_LastGdrPeriodPoc = -1; +#endif } int EncGOP::xWriteOPI (AccessUnit &accessUnit, const OPI *opi) @@ -374,6 +377,12 @@ int EncGOP::xWriteAPS( AccessUnit &accessUnit, APS *aps, const int layerId, cons nalu.m_temporalId = aps->getTemporalId(); aps->setLayerId( layerId ); CHECK( nalu.m_temporalId < accessUnit.temporalId, "TemporalId shall be greater than or equal to the TemporalId of the layer access unit containing the NAL unit" ); + +#if GDR_ENC_TRACE + if (aps) + printf("-aps ty:%d id:%d\n", aps->getAPSType(), aps->getAPSId()); +#endif + m_HLSWriter->codeAPS(aps); accessUnit.push_back(new NALUnitEBSP(nalu)); return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8; @@ -1919,6 +1928,9 @@ void EncGOP::xPicInitLMCS(Picture *pic, PicHeader *picHeader, Slice *slice) else if (m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_SDR || m_pcCfg->getReshapeSignalType() == RESHAPE_SIGNAL_HLG) { int modIP = pic->getPOC() - pic->getPOC() / m_pcCfg->getReshapeCW().rspFpsToIp * m_pcCfg->getReshapeCW().rspFpsToIp; +#if GDR_ENABLED + if (slice->isInterGDR()) modIP = 0; +#endif if (m_pcReshaper->getReshapeFlag() && m_pcCfg->getReshapeCW().updateCtrl == 2 && modIP == 0) { m_pcReshaper->getSliceReshaperInfo().setSliceReshapeModelPresentFlag(true); @@ -1936,6 +1948,14 @@ void EncGOP::xPicInitLMCS(Picture *pic, PicHeader *picHeader, Slice *slice) picHeader->setLmcsEnabledFlag(m_pcReshaper->getSliceReshaperInfo().getUseSliceReshaper()); slice->setLmcsEnabledFlag(m_pcReshaper->getSliceReshaperInfo().getUseSliceReshaper()); picHeader->setLmcsChromaResidualScaleFlag(m_pcReshaper->getSliceReshaperInfo().getSliceReshapeChromaAdj() == 1); + +#if GDR_ENABLED + if (picHeader->getInGdrPeriod()) + { + picHeader->setLmcsChromaResidualScaleFlag(false); + } +#endif + if (m_pcReshaper->getSliceReshaperInfo().getSliceReshapeModelPresentFlag()) { int apsId = std::min<int>( 3, m_pcEncLib->getVPS() == nullptr ? 0 : m_pcEncLib->getVPS()->getGeneralLayerIdx( m_pcEncLib->getLayerId() ) ); @@ -2140,6 +2160,18 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, pcSlice->setSliceType(I_SLICE); } pcSlice->setTLayer(m_pcCfg->getGOPEntry(iGOPid).m_temporalId); +#if GDR_ENABLED + if (pocCurr >= m_pcCfg->getGdrPocStart() && ((pocCurr - m_pcCfg->getGdrPocStart()) % (m_pcCfg->getGdrPeriod() * m_pcCfg->getGdrFrequency()) == 0)) + { + pcSlice->setSliceType(B_SLICE); + } + + // note : first picture is GDR(I_SLICE) + if (pocCurr == 0) + { + pcSlice->setSliceType(I_SLICE); + } +#endif // Set the nal unit type pcSlice->setNalUnitType(getNalUnitType(pocCurr, m_iLastIDR, isField)); @@ -2913,6 +2945,12 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, if (cs.sps->getUseLmcs() && m_pcReshaper->getSliceReshaperInfo().getUseSliceReshaper()) { picHeader->setLmcsEnabledFlag(true); +#if GDR_ENABLED + if (picHeader->getInGdrPeriod()) + { + picHeader->setLmcsChromaResidualScaleFlag(false); + } +#endif int apsId = std::min<int>(3, m_pcEncLib->getVPS() == nullptr ? 0 : m_pcEncLib->getVPS()->getGeneralLayerIdx(m_pcEncLib->getLayerId())); picHeader->setLmcsAPSId(apsId); @@ -3210,7 +3248,11 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, /////////////////////////////////////////////////////////////////////////////////////////////////// File writing // write various parameter sets +#if GDR_ENABLED // Note : insert SPS/PPS at every GDR picture + bool writePS = m_bSeqFirst || (m_pcCfg->getReWriteParamSets() && (pcSlice->isIRAP())) || pcSlice->isInterGDR(); +#else bool writePS = m_bSeqFirst || (m_pcCfg->getReWriteParamSets() && (pcSlice->isIRAP())); +#endif if (writePS) { m_pcEncLib->setParamSetChanged(pcSlice->getSPS()->getSPSId(), pcSlice->getPPS()->getPPSId()); @@ -3246,12 +3288,25 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap(); APS* aps = apsMap->getPS((apsId << NUM_APS_TYPE_LEN) + LMCS_APS); bool writeAPS = aps && apsMap->getChangedFlag((apsId << NUM_APS_TYPE_LEN) + LMCS_APS); +#if GDR_ENABLED // note : insert APS at every GDR picture + if (aps && apsId >= 0) + { + writeAPS |= pcSlice->isInterGDR(); + } +#endif if (writeAPS) { aps->chromaPresentFlag = pcSlice->getSPS()->getChromaFormatIdc() != CHROMA_400; actualTotalBits += xWriteAPS( accessUnit, aps, m_pcEncLib->getLayerId(), true ); apsMap->clearChangedFlag((apsId << NUM_APS_TYPE_LEN) + LMCS_APS); +#if GDR_ENABLED + if (!pcSlice->isInterGDR()) + { + CHECK(aps != picHeader->getLmcsAPS(), "Wrong LMCS APS pointer in compressGOP"); + } +#else CHECK(aps != picHeader->getLmcsAPS(), "Wrong LMCS APS pointer in compressGOP"); +#endif } } @@ -3262,12 +3317,25 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap(); APS* aps = apsMap->getPS( ( apsId << NUM_APS_TYPE_LEN ) + SCALING_LIST_APS ); bool writeAPS = aps && apsMap->getChangedFlag( ( apsId << NUM_APS_TYPE_LEN ) + SCALING_LIST_APS ); +#if GDR_ENABLED // note : insert APS at every GDR picture + if (aps && apsId >= 0) + { + writeAPS |= pcSlice->isInterGDR(); + } +#endif if( writeAPS ) { aps->chromaPresentFlag = pcSlice->getSPS()->getChromaFormatIdc() != CHROMA_400; actualTotalBits += xWriteAPS( accessUnit, aps, m_pcEncLib->getLayerId(), true ); apsMap->clearChangedFlag( ( apsId << NUM_APS_TYPE_LEN ) + SCALING_LIST_APS ); +#if GDR_ENABLED + if (!pcSlice->isInterGDR()) + { + CHECK(aps != picHeader->getScalingListAPS(), "Wrong SCALING LIST APS pointer in compressGOP"); + } +#else CHECK( aps != picHeader->getScalingListAPS(), "Wrong SCALING LIST APS pointer in compressGOP" ); +#endif } } @@ -3296,13 +3364,25 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, writeAPS = true; aps = apsMap->getPS((pcSlice->getCcAlfCrApsId() << NUM_APS_TYPE_LEN) + ALF_APS); } - +#if GDR_ENABLED // note : insert APS at every GDR picture + if (aps && apsId >= 0) + { + writeAPS |= (pcSlice->isInterGDR()); + } +#endif if (writeAPS ) { aps->chromaPresentFlag = pcSlice->getSPS()->getChromaFormatIdc() != CHROMA_400; actualTotalBits += xWriteAPS( accessUnit, aps, m_pcEncLib->getLayerId(), true ); apsMap->clearChangedFlag((apsId << NUM_APS_TYPE_LEN) + ALF_APS); +#if GDR_ENABLED + if (!pcSlice->isInterGDR()) + { + CHECK(aps != pcSlice->getAlfAPSs()[apsId] && apsId != pcSlice->getCcAlfCbApsId() && apsId != pcSlice->getCcAlfCrApsId(), "Wrong APS pointer in compressGOP"); + } +#else CHECK(aps != pcSlice->getAlfAPSs()[apsId] && apsId != pcSlice->getCcAlfCbApsId() && apsId != pcSlice->getCcAlfCrApsId(), "Wrong APS pointer in compressGOP"); +#endif } } } @@ -3527,7 +3607,13 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, auto encTime = std::chrono::duration_cast<std::chrono::seconds>( elapsed ).count(); std::string digestStr; +#if GDR_ENABLED + // note : generate hash sei only for non-gdr pictures + bool genHash = !(m_pcCfg->getNoHashForGdr() && pcSlice->getPicHeader()->getInGdrPeriod()); + if (m_pcCfg->getDecodedPictureHashSEIType() != HASHTYPE_NONE && genHash) +#else if (m_pcCfg->getDecodedPictureHashSEIType()!=HASHTYPE_NONE) +#endif { SEIDecodedPictureHash *decodedPictureHashSei = new SEIDecodedPictureHash(); PelUnitBuf recoBuf = pcPic->cs->getRecoBuf(); @@ -3568,7 +3654,14 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, xWriteTrailingSEIMessages(trailingSeiMessages, accessUnit, pcSlice->getTLayer()); +#if GDR_ENABLED + if (!(m_pcCfg->getNoHashForGdr() && pcSlice->getPicHeader()->getInGdrPeriod())) + { + printHash(m_pcCfg->getDecodedPictureHashSEIType(), digestStr); + } +#else printHash(m_pcCfg->getDecodedPictureHashSEIType(), digestStr); +#endif if ( m_pcCfg->getUseRateCtrl() ) { @@ -4981,7 +5074,18 @@ NalUnitType EncGOP::getNalUnitType(int pocCurr, int lastIDR, bool isField) { if (pocCurr == 0) { +#if GDR_ENABLED + if (m_pcCfg->getStartWithGdr()) + { + return NAL_UNIT_CODED_SLICE_GDR; + } + else + { + return NAL_UNIT_CODED_SLICE_IDR_N_LP; + } +#else return NAL_UNIT_CODED_SLICE_IDR_N_LP; +#endif } if (m_pcCfg->getEfficientFieldIRAPEnabled() && isField && pocCurr == (m_pcCfg->getUseCompositeRef() ? 2: 1)) @@ -4990,6 +5094,18 @@ NalUnitType EncGOP::getNalUnitType(int pocCurr, int lastIDR, bool isField) return NAL_UNIT_CODED_SLICE_TRAIL; } +#if GDR_ENABLED + if (m_pcCfg->getDecodingRefreshType() == 3 && (pocCurr >= m_pcCfg->getGdrPocStart())) + { + int m = pocCurr - m_pcCfg->getGdrPocStart(); + int n = m_pcCfg->getGdrPeriod() * m_pcCfg->getGdrFrequency(); + if (m % n == 0) + { + return NAL_UNIT_CODED_SLICE_GDR; + } + } +#endif + if (m_pcCfg->getDecodingRefreshType() != 3 && (pocCurr - isField) % (m_pcCfg->getIntraPeriod() * (m_pcCfg->getUseCompositeRef() ? 2 : 1)) == 0) { if (m_pcCfg->getDecodingRefreshType() == 1) @@ -5029,7 +5145,14 @@ NalUnitType EncGOP::getNalUnitType(int pocCurr, int lastIDR, bool isField) return NAL_UNIT_CODED_SLICE_RADL; } } +#if GDR_ENABLED + if (pocCurr >= m_pcCfg->getGdrPocStart() && ((pocCurr - m_pcCfg->getGdrPocStart()) % (m_pcCfg->getGdrPeriod() * m_pcCfg->getGdrFrequency()) == 0)) + return NAL_UNIT_CODED_SLICE_TRAIL; + else + return NAL_UNIT_CODED_SLICE_TRAIL; +#else return NAL_UNIT_CODED_SLICE_TRAIL; +#endif } void EncGOP::xUpdateRasInit(Slice* slice) diff --git a/source/Lib/EncoderLib/EncGOP.h b/source/Lib/EncoderLib/EncGOP.h index 36972e95e8fb380ca898082c4d5893bbfc328bfe..2c0599c3e6b9cb553d55b34fbd334e25ce3fddbe 100644 --- a/source/Lib/EncoderLib/EncGOP.h +++ b/source/Lib/EncoderLib/EncGOP.h @@ -183,6 +183,9 @@ private: bool m_bInitAMaxBT; AUWriterIf* m_AUWriterIf; +#if GDR_ENABLED + int m_LastGdrPeriodPoc; +#endif #if JVET_O0756_CALCULATE_HDRMETRICS @@ -234,6 +237,11 @@ public: void setLastLTRefPoc(int iLastLTRefPoc) { m_lastLTRefPoc = iLastLTRefPoc; } int getLastLTRefPoc() const { return m_lastLTRefPoc; } +#if GDR_ENABLED + void setLastGdrPeriodPoc(int p) { m_LastGdrPeriodPoc = p; } + int getLastGdrPeriodPoc() const { return m_LastGdrPeriodPoc; } +#endif + void printOutSummary( uint32_t uiNumAllPicCoded, bool isField, const bool printMSEBasedSNR, const bool printSequenceMSE, const bool printMSSSIM, const bool printHexPsnr, const bool printRprPSNR, const BitDepths &bitDepths ); #if W0038_DB_OPT diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index 7355d8e3d63c830f7a0746dd51d9fb51e8e613e1..4c9c13ca2ccf455500d084f9fdbeaca204c6b017 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -351,7 +351,13 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf ) Picture *picBg = new Picture; picBg->create( sps0.getChromaFormatIdc(), Size( pps0.getPicWidthInLumaSamples(), pps0.getPicHeightInLumaSamples() ), sps0.getMaxCUWidth(), sps0.getMaxCUWidth() + 16, false, m_layerId, m_gopBasedTemporalFilterEnabled ); picBg->getRecoBuf().fill(0); +#if GDR_ENABLED + PicHeader *picHeader = new PicHeader(); + xInitPicHeader(*picHeader, sps0, pps0); + picBg->finalInit( m_vps, sps0, pps0, picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); +#else picBg->finalInit( m_vps, sps0, pps0, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); +#endif picBg->allocateNewSlice(); picBg->createSpliceIdx(pps0.pcv->sizeInCtus); m_cGOPEncoder.setPicBg(picBg); @@ -463,7 +469,13 @@ bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* cPicYu const SPS *sps = m_spsMap.getPS( pps->getSPSId() ); picCurr->M_BUFS( 0, PIC_ORIGINAL ).copyFrom( m_cGOPEncoder.getPicBg()->getRecoBuf() ); +#if GDR_ENABLED + PicHeader *picHeader = new PicHeader(); + xInitPicHeader(*picHeader, *sps, *pps); + picCurr->finalInit( m_vps, *sps, *pps, picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); +#else picCurr->finalInit( m_vps, *sps, *pps, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); +#endif picCurr->poc = m_iPOCLast - 1; m_iPOCLast -= 2; if( getUseAdaptiveQP() ) @@ -581,8 +593,13 @@ bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* cPicYu pcPicCurr->M_BUFS( 0, PIC_FILTERED_ORIGINAL ).swap( *pcPicYuvFilteredOrg ); } } - +#if GDR_ENABLED + PicHeader *picHeader = new PicHeader(); + xInitPicHeader(*picHeader, *pSPS, *pPPS); + pcPicCurr->finalInit( m_vps, *pSPS, *pPPS, picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); +#else pcPicCurr->finalInit( m_vps, *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); +#endif pcPicCurr->poc = m_iPOCLast; @@ -727,7 +744,13 @@ bool EncLib::encodePrep( bool flush, PelStorage* pcPicYuvOrg, PelStorage* pcPicY const PPS *pPPS = ( ppsID < 0 ) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS( ppsID ); const SPS *pSPS = m_spsMap.getPS( pPPS->getSPSId() ); +#if GDR_ENABLED + PicHeader *picHeader = new PicHeader(); + xInitPicHeader(*picHeader, *pSPS, *pPPS); + pcField->finalInit( m_vps, *pSPS, *pPPS, picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); +#else pcField->finalInit( m_vps, *pSPS, *pPPS, &m_picHeader, m_apss, m_lmcsAPS, m_scalinglistAPS ); +#endif pcField->poc = m_iPOCLast; pcField->reconstructed = false; @@ -1105,6 +1128,12 @@ void EncLib::xInitSPS( SPS& sps ) /* XXX: may be a good idea to refactor the above into a function * that chooses the actual compatibility based upon options */ sps.setVPSId( m_vps->getVPSId() ); +#if GDR_ENABLED + sps.setGDREnabledFlag(true); +#else + sps.setGDREnabledFlag(false); +#endif + sps.setMaxPicWidthInLumaSamples( m_iSourceWidth ); sps.setMaxPicHeightInLumaSamples( m_iSourceHeight ); if (m_resChangeInClvsEnabled) @@ -1625,7 +1654,14 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps) pps.setUseWP( m_useWeightedPred ); pps.setWPBiPred( m_useWeightedBiPred ); - pps.setOutputFlagPresentFlag( false ); +#if GDR_ENABLED + if (getGdrPicOutput()) + pps.setOutputFlagPresentFlag( true ); + else + pps.setOutputFlagPresentFlag(false); +#else + pps.setOutputFlagPresentFlag(false); +#endif if ( getDeblockingFilterMetric() ) { diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp index bd2f9d807577b23ea4dd64a140864a6a0ae59bd7..58ae037bd17f2e480e276b72ebc10bf2ad8e5c54 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.cpp +++ b/source/Lib/EncoderLib/EncModeCtrl.cpp @@ -1266,10 +1266,12 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt ComprCUCtx& cuECtx = m_ComprCUCtxList.back(); // Fast checks, partitioning depended +#if !GDR_ENABLED if (cuECtx.isHashPerfectMatch && encTestmode.type != ETM_MERGE_SKIP && encTestmode.type != ETM_INTER_ME && encTestmode.type != ETM_AFFINE && encTestmode.type != ETM_MERGE_GEO) { return false; } +#endif // if early skip detected, skip all modes checking but the splits if( cuECtx.earlySkip && m_pcEncCfg->getUseEarlySkipDetection() && !isModeSplit( encTestmode ) && !( isModeInter( encTestmode ) ) ) diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h index b590cb9323890ec06f3a8c525afc9f49df9d42bf..bb3eb1551ac6d097d1a7bf23ad9a28a48fc6784d 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.h +++ b/source/Lib/EncoderLib/EncModeCtrl.h @@ -357,6 +357,393 @@ public: void setPltEnc ( bool b ) { m_doPlt = b; } bool getPltEnc() const { return m_doPlt; } +#if GDR_ENABLED +void forceIntraMode() +{ + // remove all inter or split to force make intra + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + + if (isModeInter(etm.type)) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +void forceIntraNoSplit() +{ + // remove all inter or split to force make intra + int n = (int)m_ComprCUCtxList.back().testModes.size(); + + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + + if (isModeInter(etm.type) || isModeSplit(etm.type)) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +// Note: ForceInterMode +void forceInterMode() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + if (etm.type == ETM_INTRA) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +void removeHashInter() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + if (etm.type == ETM_HASH_INTER) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +void removeMergeSkip() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + if (etm.type == ETM_MERGE_SKIP) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +void removeInterME() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + if (etm.type == ETM_INTER_ME) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +void removeAffine() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + if (etm.type == ETM_AFFINE) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +void removeMergeGeo() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + if (etm.type == ETM_MERGE_GEO) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +void removeIntra() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + if (etm.type == ETM_INTRA) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +void removeBadMode() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + + if (etm.type == ETM_INTER_ME && ((etm.opts & ETO_IMV) >> ETO_IMV_SHIFT) > 2) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + break; + } + } +} + +bool anyPredModeLeft() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + + if (etm.type == ETM_HASH_INTER || + etm.type == ETM_MERGE_SKIP || + etm.type == ETM_INTER_ME || + etm.type == ETM_AFFINE || + etm.type == ETM_MERGE_GEO || + etm.type == ETM_INTRA || + etm.type == ETM_PALETTE || + etm.type == ETM_IBC || + etm.type == ETM_IBC_MERGE) { + return true; + } + } + + return false; +} + +bool anyIntraIBCMode() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + + if (etm.type == ETM_INTRA || etm.type == ETM_IBC) + { + return true; + } + } + + return false; +} + +void forceRemoveDontSplit() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + + if (etm.type == ETM_POST_DONT_SPLIT) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +void forceVerSplitOnly() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + + if (etm.type != ETM_SPLIT_QT && etm.type != ETM_SPLIT_BT_V && etm.type != ETM_SPLIT_TT_V) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +void forceRemoveTTV() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + + if (etm.type == ETM_SPLIT_TT_V) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +void forceRemoveBTV() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + + if (etm.type == ETM_SPLIT_BT_V) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +void forceRemoveQT() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + + if (etm.type == ETM_SPLIT_QT) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +void forceRemoveHT() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + + if (etm.type == ETM_SPLIT_BT_H || etm.type == ETM_SPLIT_TT_H) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +void forceRemoveQTHT() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + + if (etm.type == ETM_SPLIT_QT || etm.type == ETM_SPLIT_BT_H || etm.type == ETM_SPLIT_TT_H) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +void forceRemoveAllSplit() +{ + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + + if (etm.type == ETM_SPLIT_QT || etm.type == ETM_SPLIT_BT_H || etm.type == ETM_SPLIT_BT_V || etm.type == ETM_SPLIT_TT_H || etm.type == ETM_SPLIT_TT_V) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +void forceQTonlyMode() +{ + // remove all split except QT + int n = (int)m_ComprCUCtxList.back().testModes.size(); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + + if (etm.type != ETM_SPLIT_QT) + { + m_ComprCUCtxList.back().testModes.erase(m_ComprCUCtxList.back().testModes.begin() + j); + j--; + n--; + } + } +} + +const char* printType(EncTestModeType type) +{ + char *ret; + + switch (type) { + case 0: ret = strdup("Hash"); break; + case 1: ret = strdup("Mkip"); break; + case 2: ret = strdup("Inter"); break; + case 3: ret = strdup("Affi"); break; + case 4: ret = strdup("Tria"); break; + case 5: ret = strdup("Intra"); break; + case 6: ret = strdup("Palet"); break; + + case 7: ret = strdup("QT"); break; + case 8: ret = strdup("BTH"); break; + case 9: ret = strdup("BTV"); break; + case 10: ret = strdup("TTH"); break; + case 11: ret = strdup("TTV"); break; + case 12: ret = strdup("|"); break; + case 13: ret = strdup("CACHE"); break; + case 14: ret = strdup("IMV"); break; + case 15: ret = strdup("IBC"); break; + case 16: ret = strdup("IBCM"); break; + default: + ret = strdup("INVALID"); + } + + return ret; +} + +void printMode() +{ + // remove all inter or split to force make intra + int n = (int)m_ComprCUCtxList.back().testModes.size(); + printf("-:["); + for (int j = 0; j < n; j++) + { + const EncTestMode etm = m_ComprCUCtxList.back().testModes[j]; + printf(" %s", printType(etm.type)); + } + printf("]\n"); +} +#endif + protected: void xExtractFeatures ( const EncTestMode encTestmode, CodingStructure& cs ); void xGetMinMaxQP ( int& iMinQP, int& iMaxQP, const CodingStructure& cs, const Partitioner &pm, const int baseQP, const SPS& sps, const PPS& pps, const PartSplit splitMode ); diff --git a/source/Lib/EncoderLib/EncReshape.cpp b/source/Lib/EncoderLib/EncReshape.cpp index ac70e08d426aa256fb1e2d857aec405d75aef16c..b48822358bf7d1636cb5c69eb4724a5706a9769f 100644 --- a/source/Lib/EncoderLib/EncReshape.cpp +++ b/source/Lib/EncoderLib/EncReshape.cpp @@ -444,6 +444,9 @@ void EncReshape::preAnalyzerLMCS(Picture *pcPic, const uint32_t signalType, cons m_sliceReshapeInfo.sliceReshaperModelPresentFlag = true; m_sliceReshapeInfo.sliceReshaperEnableFlag = true; int modIP = pcPic->getPOC() - pcPic->getPOC() / reshapeCW.rspFpsToIp * reshapeCW.rspFpsToIp; +#if GDR_ENABLED + if (pcPic->cs->slice->isInterGDR()) modIP = 0; +#endif if (sliceType == I_SLICE || (reshapeCW.updateCtrl == 2 && modIP == 0)) { if (m_sliceReshapeInfo.sliceReshaperModelPresentFlag == true) diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp index bbf3fe06a0901a652bfc1a1a16b7694fdb5c6f8c..31a81ff8e2083288fe027dbcd42771ecdc6392dc 100644 --- a/source/Lib/EncoderLib/EncSlice.cpp +++ b/source/Lib/EncoderLib/EncSlice.cpp @@ -438,6 +438,12 @@ void EncSlice::initEncSlice(Picture* pcPic, const int pocLast, const int pocCurr else { eSliceType = (pocLast == 0 || (pocCurr - (isField ? 1 : 0)) % (m_pcCfg->getIntraPeriod() * multipleFactor) == 0 || m_pcGOPEncoder->getGOPSize() == 0) && (!useIlRef) ? I_SLICE : eSliceType; +#if GDR_ENABLED + if (pocCurr >= m_pcCfg->getGdrPocStart() && ((pocCurr - m_pcCfg->getGdrPocStart()) % (m_pcCfg->getGdrPeriod() * m_pcCfg->getGdrFrequency()) == 0)) + { + eSliceType = B_SLICE; + } +#endif } } } @@ -603,6 +609,12 @@ void EncSlice::initEncSlice(Picture* pcPic, const int pocLast, const int pocCurr else { eSliceType = (pocLast == 0 || (pocCurr - (isField ? 1 : 0)) % (m_pcCfg->getIntraPeriod() * multipleFactor) == 0 || m_pcGOPEncoder->getGOPSize() == 0) && (!useIlRef) ? I_SLICE : eSliceType; +#if GDR_ENABLED + if (pocCurr >= m_pcCfg->getGdrPocStart() && ((pocCurr - m_pcCfg->getGdrPocStart()) % (m_pcCfg->getGdrPeriod() * m_pcCfg->getGdrFrequency()) == 0)) + { + eSliceType = B_SLICE; + } +#endif } } } @@ -705,6 +717,130 @@ void EncSlice::initEncSlice(Picture* pcPic, const int pocLast, const int pocCurr m_pcCuEncoder->getIbcHashMap().destroy(); m_pcCuEncoder->getIbcHashMap().init( pcPic->cs->pps->getPicWidthInLumaSamples(), pcPic->cs->pps->getPicHeightInLumaSamples() ); } +#if GDR_ENABLED + int gdrPocStart = m_pcCuEncoder->getEncCfg()->getGdrPocStart(); + int gdrPeriod = m_pcCuEncoder->getEncCfg()->getGdrPeriod(); + int gdr_frequency = m_pcCuEncoder->getEncCfg()->getGdrFrequency(); + + int picWidth = rpcSlice->getPPS()->getPicWidthInLumaSamples(); + + int curPoc = rpcSlice->getPOC(); + int gdrPoc = (curPoc - gdrPocStart) % gdrPeriod; + + pcPic->cs->picHeader->setGdrPicFlag(false); + pcPic->cs->picHeader->setRecoveryPocCnt(0); + pcPic->cs->picHeader->setInGdrPeriod(false); + + pcPic->cs->picHeader->setVirtualBoundariesPresentFlag(false); + + int offset = (curPoc < gdrPocStart) ? 0 : (((curPoc - gdrPocStart) / gdrPeriod) * gdrPeriod); + int actualGdrStart = gdrPocStart + offset; + int actualGdrPeriod = min(gdrPeriod, (int)(pcPic->getPicWidthInLumaSamples() / 8)); + int actualGdrEndPoc = actualGdrStart + actualGdrPeriod - 1; + + bool isActualGdrPeriod = (curPoc >= gdrPocStart) && ((((curPoc - gdrPocStart) / gdrPeriod) % gdr_frequency) == 0); + bool isGdrPeriodOver = (isActualGdrPeriod) && (curPoc > actualGdrEndPoc); + bool isGdrPic = (actualGdrStart == curPoc); + +#if GDR_ENC_TRACE + printf("\n"); + printf("-poc:%d actualGdrStart:%d actualGdrPeriod:%d actualGdrEndPoc:%d\n", rpcSlice->getPOC(), actualGdrStart, actualGdrPeriod, actualGdrEndPoc); +#endif + + // for first picture of the sequence (GDR picture with recovery_poc_cnt = 0) + if (curPoc == 0 && m_pcCfg->getStartWithGdr()) + { + pcPic->cs->picHeader->setGdrOrIrapPicFlag(true); + pcPic->cs->picHeader->setGdrPicFlag(true); + + pcPic->cs->picHeader->setInGdrPeriod(true); + pcPic->cs->picHeader->setVirtualBoundariesPresentFlag(true); + + if (m_pcCfg->getGdrPicOutput()) + pcPic->cs->picHeader->setPicOutputFlag(true); + else + pcPic->cs->picHeader->setPicOutputFlag(false); + + pcPic->cs->picHeader->setRecoveryPocCnt(0); + + pcPic->cs->picHeader->setNumHorVirtualBoundaries(0); + pcPic->cs->picHeader->setNumVerVirtualBoundaries(1); + pcPic->cs->picHeader->setVirtualBoundariesPosX(picWidth, 0); + } + // for none gdr period pictures + else if ((curPoc < gdrPocStart) || !isActualGdrPeriod || isGdrPeriodOver) + { + pcPic->cs->picHeader->setInGdrPeriod(false); + pcPic->cs->picHeader->setVirtualBoundariesPresentFlag(false); + + pcPic->cs->picHeader->setNumHorVirtualBoundaries(0); + pcPic->cs->picHeader->setNumVerVirtualBoundaries(0); + +#if GDR_ENC_TRACE + printf("-poc:%d no virtual boundary\n", rpcSlice->getPOC()); +#endif + } + // for gdr period pictures + else + { + pcPic->cs->picHeader->setInGdrPeriod(true); + pcPic->cs->picHeader->setVirtualBoundariesPresentFlag(true); + + if (m_pcCfg->getGdrPicOutput()) + pcPic->cs->picHeader->setPicOutputFlag(true); + else + pcPic->cs->picHeader->setPicOutputFlag(false); + + if (isGdrPic) + { + pcPic->cs->picHeader->setGdrOrIrapPicFlag(true); + pcPic->cs->picHeader->setGdrPicFlag(true); + + pcPic->cs->picHeader->setRecoveryPocCnt(actualGdrPeriod); + m_pcGOPEncoder->setLastGdrPeriodPoc(actualGdrStart + actualGdrPeriod - 1); + } + + pcPic->cs->picHeader->setNumHorVirtualBoundaries(0); + pcPic->cs->picHeader->setNumVerVirtualBoundaries(1); + + int begGdrX; + int endGdrX; + int m1, m2, n1; + + double dd = (picWidth / (double)gdrPeriod); + int mm = (int)((picWidth / (double)gdrPeriod) + 0.49999); + m1 = ((mm + 7) >> 3) << 3; + m2 = ((mm + 0) >> 3) << 3; + + if (dd > mm && m1 == m2) + m1 = m1 + 8; + + n1 = (picWidth - m2 * gdrPeriod) / 8; + + if (gdrPoc < n1) + { + begGdrX = m1 * gdrPoc; + endGdrX = begGdrX + m1; + } + else + { + begGdrX = m1 * n1 + m2 * (gdrPoc - n1); + endGdrX = begGdrX + m2; + if (picWidth <= begGdrX) + { + begGdrX = picWidth; + endGdrX = picWidth; + } + } + + pcPic->cs->picHeader->setVirtualBoundariesPosX(endGdrX, 0); + +#if GDR_ENC_TRACE + printf("\n"); + printf("-poc:%d beg:%d end:%d\n", rpcSlice->getPOC(), begGdrX, endGdrX); +#endif + } +#endif } double EncSlice::initializeLambda(const Slice* slice, const int GOPid, const int refQP, const double dQP) diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index 07e7e237533d7d966f483aff64709538c082d166..c08b3d300291a97d38f6545111345729ee56d674 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -110,6 +110,9 @@ InterSearch::InterSearch() setWpScalingDistParam( -1, REF_PIC_LIST_X, nullptr ); m_affMVList = nullptr; +#if GDR_ENABLED + m_affMVListSolid = nullptr; +#endif m_affMVListSize = 0; m_affMVListIdx = 0; m_uniMvList = nullptr; @@ -158,6 +161,14 @@ void InterSearch::destroy() delete[] m_affMVList; m_affMVList = nullptr; } +#if GDR_ENABLED + if (m_affMVListSolid) + { + delete[] m_affMVListSolid; + m_affMVListSolid = nullptr; + } +#endif + m_affMVListIdx = 0; m_affMVListSize = 0; if (m_uniMvList) @@ -258,6 +269,12 @@ void InterSearch::init( EncCfg* pcEncCfg, if (!m_affMVList) { m_affMVList = new AffineMVInfo[m_affMVListMaxSize]; +#if GDR_ENABLED + if (!m_affMVListSolid) + { + m_affMVListSolid = new AffineMVInfoSolid[m_affMVListMaxSize]; + } +#endif } m_affMVListIdx = 0; m_affMVListSize = 0; @@ -279,8 +296,15 @@ void InterSearch::resetSavedAffineMotion() { m_affineMotion.acMvAffine4Para[i][j] = Mv( 0, 0 ); m_affineMotion.acMvAffine6Para[i][j] = Mv( 0, 0 ); +#if GDR_ENABLED + m_affineMotion.acMvAffine4ParaSolid[i][j] = true; + m_affineMotion.acMvAffine6ParaSolid[i][j] = true; +#endif } m_affineMotion.acMvAffine6Para[i][2] = Mv( 0, 0 ); +#if GDR_ENABLED + m_affineMotion.acMvAffine6ParaSolid[i][2] = true; +#endif m_affineMotion.affine4ParaRefIdx[i] = -1; m_affineMotion.affine6ParaRefIdx[i] = -1; @@ -293,7 +317,11 @@ void InterSearch::resetSavedAffineMotion() m_affineMotion.affine6ParaAvail = false; } +#if GDR_ENABLED +void InterSearch::storeAffineMotion(Mv acAffineMv[2][3], bool acAffineMvSolid[2][3], int16_t affineRefIdx[2], EAffineModel affineType, int bcwIdx) +#else void InterSearch::storeAffineMotion( Mv acAffineMv[2][3], int16_t affineRefIdx[2], EAffineModel affineType, int bcwIdx ) +#endif { if ( ( bcwIdx == BCW_DEFAULT || !m_affineMotion.affine6ParaAvail ) && affineType == AFFINEMODEL_6PARAM ) { @@ -302,6 +330,9 @@ void InterSearch::storeAffineMotion( Mv acAffineMv[2][3], int16_t affineRefIdx[2 for ( int j = 0; j < 3; j++ ) { m_affineMotion.acMvAffine6Para[i][j] = acAffineMv[i][j]; +#if GDR_ENABLED + m_affineMotion.acMvAffine6ParaSolid[i][j] = acAffineMvSolid[i][j]; +#endif } m_affineMotion.affine6ParaRefIdx[i] = affineRefIdx[i]; } @@ -315,6 +346,9 @@ void InterSearch::storeAffineMotion( Mv acAffineMv[2][3], int16_t affineRefIdx[2 for ( int j = 0; j < 2; j++ ) { m_affineMotion.acMvAffine4Para[i][j] = acAffineMv[i][j]; +#if GDR_ENABLED + m_affineMotion.acMvAffine4ParaSolid[i][j] = acAffineMvSolid[i][j]; +#endif } m_affineMotion.affine4ParaRefIdx[i] = affineRefIdx[i]; } @@ -698,21 +732,46 @@ inline void InterSearch::xTZ8PointDiamondSearch( IntTZSearchStruct& rcStruct, } // iDist <= 8 } // iDist == 1 } +#if GDR_ENABLED +Distortion InterSearch::xPatternRefinement( + const PredictionUnit& pu, + RefPicList eRefPicList, + int iRefIdx, + const CPelBuf* pcPatternKey, + Mv baseRefMv, + int iFrac, Mv& rcMvFrac, + bool bAllowUseOfHadamard, + bool& rbCleanCandExist) +#else Distortion InterSearch::xPatternRefinement( const CPelBuf* pcPatternKey, Mv baseRefMv, int iFrac, Mv& rcMvFrac, bool bAllowUseOfHadamard ) +#endif { Distortion uiDist; Distortion uiDistBest = std::numeric_limits<Distortion>::max(); uint32_t uiDirecBest = 0; +#if GDR_ENABLED + const CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + bool uiDistOk = false; + bool uiDistBestOk = false; + bool allOk = true; +#endif Pel* piRefPos; int iRefStride = pcPatternKey->width + 1; m_pcRdCost->setDistParam( m_cDistParam, *pcPatternKey, m_filteredBlock[0][0][0], iRefStride, m_lumaClpRng.bd, COMPONENT_Y, 0, 1, m_pcEncCfg->getUseHADME() && bAllowUseOfHadamard ); const Mv* pcMvRefine = (iFrac == 2 ? s_acMvRefineH : s_acMvRefineQ); +#if GDR_ENABLED + if (isEncodeClean) + { + rbCleanCandExist = false; + } +#endif for (uint32_t i = 0; i < 9; i++) { if (m_skipFracME && i > 0) @@ -742,12 +801,51 @@ Distortion InterSearch::xPatternRefinement( const CPelBuf* pcPatternKey, uiDist = m_cDistParam.distFunc( m_cDistParam ); uiDist += m_pcRdCost->getCostOfVectorWithPredictor( cMvTest.getHor(), cMvTest.getVer(), 0 ); +#if GDR_ENABLED + allOk = (uiDist < uiDistBest); + + if (isEncodeClean) + { + Mv motion = cMvTest; + MvPrecision curPrec = (iFrac == 2 ? MV_PRECISION_HALF : MV_PRECISION_QUARTER); + motion.changePrecision(curPrec, MV_PRECISION_INTERNAL); + uiDistOk = cs.isClean(pu.Y().bottomRight(), motion, eRefPicList, iRefIdx); + + if (uiDistOk) + { + allOk = (uiDistBestOk) ? (uiDist < uiDistBest) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if ( uiDist < uiDistBest ) +#endif { uiDistBest = uiDist; uiDirecBest = i; m_cDistParam.maximumDistortionForEarlyExit = uiDist; +#if GDR_ENABLED + if (isEncodeClean) + { + uiDistBestOk = uiDistOk; + rbCleanCandExist = true; + } +#endif } +#if GDR_ENABLED + if (isEncodeClean) + { + if (!rbCleanCandExist) + uiDistBest = 65535; + } +#endif } rcMvFrac = pcMvRefine[uiDirecBest]; @@ -846,6 +944,20 @@ int InterSearch::xIBCSearchMVChromaRefine(PredictionUnit& pu, continue; } +#if GDR_ENABLED + CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + + if (isEncodeClean) + { + Position curBR(cuPelX + roiWidth + cMVCand[cand].getHor() - 1, cuPelY + roiHeight + cMVCand[cand].getVer() - 1); // is this correct??? + if (!cs.isClean(curBR, CHANNEL_TYPE_LUMA)) + { + continue; + } + } +#endif + tempSad = sadBestCand[cand]; pu.mv[0] = cMVCand[cand]; @@ -957,6 +1069,10 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct& cS Distortion sadBestCand[CHROMA_REFINEMENT_CANDIDATES]; Mv cMVCand[CHROMA_REFINEMENT_CANDIDATES]; +#if GDR_ENABLED + CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif for (int cand = 0; cand < CHROMA_REFINEMENT_CANDIDATES; cand++) { @@ -995,7 +1111,13 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct& cS && !((xPred < srLeft) || (xPred > srRight))) { bool validCand = searchBv(pu, cuPelX, cuPelY, roiWidth, roiHeight, picWidth, picHeight, xPred, yPred, lcuWidth); - +#if GDR_ENABLED + if (isEncodeClean) + { + Position BvBR(cuPelX + roiWidth + xPred - 1, cuPelY + roiHeight + yPred - 1); + validCand = validCand && cs.isClean(BvBR, CHANNEL_TYPE_LUMA); + } +#endif if (validCand) { sad = m_pcRdCost->getBvCostMultiplePreds(xPred, yPred, pu.cs->sps->getAMVREnabledFlag()); @@ -1019,6 +1141,16 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct& cS { continue; } +#if GDR_ENABLED + if (isEncodeClean) + { + Position BvBR(cuPelX + roiWidth - 1, cuPelY + roiHeight + y - 1); + if (!cs.isClean(BvBR, CHANNEL_TYPE_LUMA)) + { + continue; + } + } +#endif sad = m_pcRdCost->getBvCostMultiplePreds(0, y, pu.cs->sps->getAMVREnabledFlag()); m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * y; @@ -1044,6 +1176,16 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct& cS { continue; } +#if GDR_ENABLED + if (isEncodeClean) + { + Position BvBR(cuPelX + roiWidth + x - 1, cuPelY + roiHeight - 1); + if (!cs.isClean(BvBR, CHANNEL_TYPE_LUMA)) + { + continue; + } + } +#endif sad = m_pcRdCost->getBvCostMultiplePreds(x, 0, pu.cs->sps->getAMVREnabledFlag()); m_cDistParam.cur.buf = piRefSrch + x; @@ -1100,6 +1242,17 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct& cS continue; } +#if GDR_ENABLED + if (isEncodeClean) + { + Position BvBR(cuPelX + roiWidth + x - 1, cuPelY + roiHeight + y - 1); + if (!cs.isClean(BvBR, CHANNEL_TYPE_LUMA)) + { + continue; + } + } +#endif + sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getAMVREnabledFlag()); m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * y + x; sad += m_cDistParam.distFunc(m_cDistParam); @@ -1144,6 +1297,17 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct& cS continue; } +#if GDR_ENABLED + if (isEncodeClean) + { + Position BvBR(cuPelX + roiWidth + x - 1, cuPelY + roiHeight + y - 1); + if (!cs.isClean(BvBR, CHANNEL_TYPE_LUMA)) + { + continue; + } + } +#endif + sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getAMVREnabledFlag()); m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * y + x; sad += m_cDistParam.distFunc(m_cDistParam); @@ -1202,6 +1366,16 @@ void InterSearch::xIntraPatternSearch(PredictionUnit& pu, IntTZSearchStruct& cS { continue; } +#if GDR_ENABLED + if (isEncodeClean) + { + Position BvBR(cuPelX + roiWidth + x - 1, cuPelY + roiHeight + y - 1); + if (!cs.isClean(BvBR, CHANNEL_TYPE_LUMA)) + { + continue; + } + } +#endif sad = m_pcRdCost->getBvCostMultiplePreds(x, y, pu.cs->sps->getAMVREnabledFlag()); m_cDistParam.cur.buf = piRefSrch + cStruct.iRefStride * y + x; @@ -1277,6 +1451,11 @@ void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, CPelBuf* pcPatternKey = &tmpPattern; PelBuf tmpOrgLuma; +#if GDR_ENABLED + CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif + if ((pu.cs->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag())) { const CompArea &area = pu.blocks[COMPONENT_Y]; @@ -1319,7 +1498,17 @@ void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, int xBv = bv.hor; int yBv = bv.ver; +#if GDR_ENABLED + bool validCand = true; + if (isEncodeClean) + { + Position BvBR(cuPelX + iRoiWidth + xBv - 1, cuPelY + iRoiHeight + yBv - 1); + validCand = validCand && cs.isClean(BvBR, CHANNEL_TYPE_LUMA); + } + if (validCand && searchBv(pu, cuPelX, cuPelY, iRoiWidth, iRoiHeight, iPicWidth, iPicHeight, xBv, yBv, lcuWidth)) +#else if (searchBv(pu, cuPelX, cuPelY, iRoiWidth, iRoiHeight, iPicWidth, iPicHeight, xBv, yBv, lcuWidth)) +#endif { buffered = true; Distortion sad = m_pcRdCost->getBvCostMultiplePreds(xBv, yBv, pu.cs->sps->getAMVREnabledFlag()); @@ -1354,7 +1543,17 @@ void InterSearch::xIBCEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, int xPred = cMvPredEncOnly[cand].getHor(); int yPred = cMvPredEncOnly[cand].getVer(); +#if GDR_ENABLED + bool validCand = true; + if (isEncodeClean) + { + Position BvBR(cuPelX + iRoiWidth + xPred - 1, cuPelY + iRoiHeight + yPred - 1); + validCand = cs.isClean(BvBR, CHANNEL_TYPE_LUMA); + } + if (validCand && searchBv(pu, cuPelX, cuPelY, iRoiWidth, iRoiHeight, iPicWidth, iPicHeight, xPred, yPred, lcuWidth)) +#else if (searchBv(pu, cuPelX, cuPelY, iRoiWidth, iRoiHeight, iPicWidth, iPicHeight, xPred, yPred, lcuWidth)) +#endif { Distortion sad = m_pcRdCost->getBvCostMultiplePreds(xPred, yPred, pu.cs->sps->getAMVREnabledFlag()); m_cDistParam.cur.buf = cStruct.piRefY + cStruct.iRefStride * yPred + xPred; @@ -1443,6 +1642,20 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const m_maxCompIDToPred = MAX_NUM_COMPONENT; CHECK(pu.cu != &cu, "PU is contained in another CU"); +#if GDR_ENABLED + CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif + +#if GDR_ENABLED + if (isEncodeClean) + { + pu.mvSolid[0] = false; + pu.mvSolid[1] = false; + pu.mvValid[0] = false; + pu.mvValid[1] = false; + } +#endif ////////////////////////////////////////////////////////// /// ibc search pu.cu->imv = 2; @@ -1580,6 +1793,10 @@ void InterSearch::xxIBCHashSearch(PredictionUnit& pu, Mv* mvPred, int numMvPred, mv.setZero(); m_pcRdCost->setCostScale(0); +#if GDR_ENABLED + CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif std::vector<Position> candPos; if (ibcHashMap.ibcHashMatch(pu.Y(), candPos, *pu.cs, m_pcEncCfg->getIBCHashSearchMaxCand(), m_pcEncCfg->getIBCHashSearchRange4SmallBlk())) { @@ -1606,6 +1823,13 @@ void InterSearch::xxIBCHashSearch(PredictionUnit& pu, Mv* mvPred, int numMvPred, { continue; } +#if GDR_ENABLED + Position BvBR(cuPelX + roiWidth + candMv.getHor() - 1, cuPelY + roiHeight + candMv.getVer() - 1); + if (isEncodeClean && !cs.isClean(BvBR, CHANNEL_TYPE_LUMA)) + { + continue; + } +#endif for (int n = 0; n < numMvPred; n++) { @@ -1809,6 +2033,11 @@ bool InterSearch::xRectHashInterEstimation(PredictionUnit& pu, RefPicList& bestR unsigned int* hashValue1s = new unsigned int[baseNum]; unsigned int* hashValue2s = new unsigned int[baseNum]; +#if GDR_ENABLED + CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif + for (int k = 0; k < baseNum; k++) { if (isHorizontal) @@ -1890,6 +2119,26 @@ bool InterSearch::xRectHashInterEstimation(PredictionUnit& pu, RefPicList& bestR AMVPInfo currAMVPInfoPel; AMVPInfo currAMVPInfo4Pel; AMVPInfo currAMVPInfoQPel; + +#if GDR_ENABLED + if (isEncodeClean) + { + currAMVPInfoPel.allCandSolidInAbove = true; + currAMVPInfo4Pel.allCandSolidInAbove = true; + currAMVPInfoQPel.allCandSolidInAbove = true; + + for (int i = 0; i < AMVP_MAX_NUM_CANDS_MEM; i++) + { + currAMVPInfoPel.mvSolid[i] = true; + currAMVPInfoPel.mvValid[i] = true; + currAMVPInfo4Pel.mvSolid[i] = true; + currAMVPInfo4Pel.mvValid[i] = true; + currAMVPInfoQPel.mvSolid[i] = true; + currAMVPInfoQPel.mvValid[i] = true; + } + } +#endif + pu.cu->imv = 2; PU::fillMvpCand(pu, eRefPicList, refIdx, currAMVPInfo4Pel); pu.cu->imv = 1; @@ -1921,6 +2170,25 @@ bool InterSearch::xRectHashInterEstimation(PredictionUnit& pu, RefPicList& bestR m_hashMVStoreds[eRefPicList][refIdx][countMV++] = cMv; cMv.changePrecision(MV_PRECISION_INT, MV_PRECISION_QUARTER); +#if GDR_ENABLED + bool allOk = true; + bool anyCandOk = false; + bool Valid = true; + if (isEncodeClean) + { + Mv cMv16 = cMv; + cMv16.changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + const Position bottomRight = pu.Y().bottomRight(); + Valid = cs.isClean(bottomRight, cMv16, eRefPicList, refIdx); + } +#endif + +#if GDR_ENABLED + if (!Valid) + { + continue; + } +#endif for (int mvpIdxTemp = 0; mvpIdxTemp < 2; mvpIdxTemp++) { Mv cMvPredPel = currAMVPInfoQPel.mvCand[mvpIdxTemp]; @@ -1928,7 +2196,21 @@ bool InterSearch::xRectHashInterEstimation(PredictionUnit& pu, RefPicList& bestR unsigned int tempMVPbits = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor(), cMv.getVer(), 0); +#if GDR_ENABLED + allOk = (tempMVPbits < curMVPbits); + if (isEncodeClean) + { + bool isSolid = currAMVPInfoQPel.mvSolid[mvpIdxTemp]; + allOk = allOk && isSolid; + if (allOk) anyCandOk = true; + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if (tempMVPbits < curMVPbits) +#endif { curMVPbits = tempMVPbits; curMVPIdx = mvpIdxTemp; @@ -1941,7 +2223,21 @@ bool InterSearch::xRectHashInterEstimation(PredictionUnit& pu, RefPicList& bestR Mv mvPred1Pel = currAMVPInfoPel.mvCand[mvpIdxTemp]; m_pcRdCost->setPredictor(mvPred1Pel); bitsMVP1Pel = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor(), cMv.getVer(), 2); +#if GDR_ENABLED + allOk = (bitsMVP1Pel < curMVPbits); + if (isEncodeClean) + { + bool isSolid = currAMVPInfoPel.mvSolid[mvpIdxTemp]; + allOk = allOk && isSolid; + if (allOk) anyCandOk = true; + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if (bitsMVP1Pel < curMVPbits) +#endif { curMVPbits = bitsMVP1Pel; curMVPIdx = mvpIdxTemp; @@ -1954,7 +2250,21 @@ bool InterSearch::xRectHashInterEstimation(PredictionUnit& pu, RefPicList& bestR Mv mvPred4Pel = currAMVPInfo4Pel.mvCand[mvpIdxTemp]; m_pcRdCost->setPredictor(mvPred4Pel); bitsMVP4Pel = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor(), cMv.getVer(), 4); +#if GDR_ENABLED + allOk = (bitsMVP1Pel < curMVPbits); + if (isEncodeClean) + { + bool isSolid = currAMVPInfo4Pel.mvSolid[mvpIdxTemp]; + allOk = allOk && isSolid; + if (allOk) anyCandOk = true; + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if (bitsMVP4Pel < curMVPbits) +#endif { curMVPbits = bitsMVP4Pel; curMVPIdx = mvpIdxTemp; @@ -1963,6 +2273,14 @@ bool InterSearch::xRectHashInterEstimation(PredictionUnit& pu, RefPicList& bestR } } } + +#if GDR_ENABLED + if (isEncodeClean && !anyCandOk) + { + continue; + } +#endif + curMVPbits += bitsOnRefIdx; m_cDistParam.cur.buf = refBufStart + (*it).y*refStride + (*it).x; @@ -2033,6 +2351,10 @@ bool InterSearch::xHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPi return false; } +#if GDR_ENABLED + CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif BlockHash currBlockHash; currBlockHash.x = xPos; currBlockHash.y = yPos; @@ -2087,11 +2409,45 @@ bool InterSearch::xHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPi } AMVPInfo currAMVPInfoPel; AMVPInfo currAMVPInfo4Pel; +#if GDR_ENABLED + if (isEncodeClean) + { + currAMVPInfo4Pel.allCandSolidInAbove = true; + for (int i = 0; i < AMVP_MAX_NUM_CANDS_MEM; i++) + { + currAMVPInfo4Pel.mvSolid[i] = true; + currAMVPInfo4Pel.mvValid[i] = true; + } + } +#endif pu.cu->imv = 2; PU::fillMvpCand(pu, eRefPicList, refIdx, currAMVPInfo4Pel); + +#if GDR_ENABLED + if (isEncodeClean) + { + currAMVPInfoPel.allCandSolidInAbove = true; + for (int i = 0; i < AMVP_MAX_NUM_CANDS_MEM; i++) + { + currAMVPInfoPel.mvSolid[i] = true; + currAMVPInfoPel.mvValid[i] = true; + } + } +#endif pu.cu->imv = 1; PU::fillMvpCand(pu, eRefPicList, refIdx, currAMVPInfoPel); AMVPInfo currAMVPInfoQPel; +#if GDR_ENABLED + if (isEncodeClean) + { + currAMVPInfoQPel.allCandSolidInAbove = true; + for (int i = 0; i < AMVP_MAX_NUM_CANDS_MEM; i++) + { + currAMVPInfoQPel.mvSolid[i] = true; + currAMVPInfoQPel.mvValid[i] = true; + } + } +#endif pu.cu->imv = 0; PU::fillMvpCand(pu, eRefPicList, refIdx, currAMVPInfoQPel); CHECK(currAMVPInfoPel.numCand <= 1, "Wrong") @@ -2121,6 +2477,27 @@ bool InterSearch::xHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPi m_hashMVStoreds[eRefPicList][refIdx][countMV++] = cMv; cMv.changePrecision(MV_PRECISION_INT, MV_PRECISION_QUARTER); +#if GDR_ENABLED + bool Valid = true; + bool allOk = true; + bool anyCandOk = false; + + if (isEncodeClean) + { + Mv cMv16 = cMv; + cMv16.changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL); + const Position bottomRight = pu.Y().bottomRight(); + Valid = cs.isClean(bottomRight, cMv16, eRefPicList, refIdx); + } +#endif + +#if GDR_ENABLED + if (!Valid) + { + continue; + } +#endif + for (int mvpIdxTemp = 0; mvpIdxTemp < 2; mvpIdxTemp++) { Mv cMvPredPel = currAMVPInfoQPel.mvCand[mvpIdxTemp]; @@ -2128,7 +2505,21 @@ bool InterSearch::xHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPi unsigned int tempMVPbits = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor(), cMv.getVer(), 0); +#if GDR_ENABLED + allOk = (tempMVPbits < curMVPbits); + if (isEncodeClean) + { + bool isSolid = currAMVPInfoQPel.mvSolid[mvpIdxTemp]; + allOk = allOk && isSolid; + if (allOk) anyCandOk = true; + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if (tempMVPbits < curMVPbits) +#endif { curMVPbits = tempMVPbits; curMVPIdx = mvpIdxTemp; @@ -2141,7 +2532,21 @@ bool InterSearch::xHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPi Mv mvPred1Pel = currAMVPInfoPel.mvCand[mvpIdxTemp]; m_pcRdCost->setPredictor(mvPred1Pel); bitsMVP1Pel = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor(), cMv.getVer(), 2); +#if GDR_ENABLED + allOk = (bitsMVP1Pel < curMVPbits); + if (isEncodeClean) + { + bool isSolid = currAMVPInfoPel.mvSolid[mvpIdxTemp]; + allOk = allOk && isSolid; + if (allOk) anyCandOk = true; + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if (bitsMVP1Pel < curMVPbits) +#endif { curMVPbits = bitsMVP1Pel; curMVPIdx = mvpIdxTemp; @@ -2154,7 +2559,22 @@ bool InterSearch::xHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPi Mv mvPred4Pel = currAMVPInfo4Pel.mvCand[mvpIdxTemp]; m_pcRdCost->setPredictor(mvPred4Pel); bitsMVP4Pel = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor(), cMv.getVer(), 4); + +#if GDR_ENABLED + allOk = (bitsMVP1Pel < curMVPbits); + if (isEncodeClean) + { + bool isSolid = currAMVPInfo4Pel.mvSolid[mvpIdxTemp]; + allOk = allOk && isSolid; + if (allOk) anyCandOk = true; + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if (bitsMVP4Pel < curMVPbits) +#endif { curMVPbits = bitsMVP4Pel; curMVPIdx = mvpIdxTemp; @@ -2164,6 +2584,13 @@ bool InterSearch::xHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPi } } +#if GDR_ENABLED + if (isEncodeClean && !anyCandOk) + { + continue; + } +#endif + curMVPbits += bitsOnRefIdx; m_cDistParam.cur.buf = refBufStart + (*it).y*refStride + (*it).x; @@ -2285,6 +2712,37 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) int aaiMvpIdx[2][33]; int aaiMvpNum[2][33]; +#if GDR_ENABLED + bool cMvSolid[2]; + bool cMvValid[2]; + bool cMvBiSolid[2]; + bool cMvBiValid[2]; + + bool cMvPredSolid[2][33]; + bool cMvPredBiSolid[2][33]; + + bool cMvTempSolid[2][33]; + bool cMvTempValid[2][33]; + + bool cMvHevcTempSolid[2][33]; + bool cMvHevcTempValid[2][33]; + + bool allOk; + bool bestBiPDistOk; + bool biPDistTempOk; + bool uiCostTempOk; + bool uiCostTempL0Ok[MAX_NUM_REF]; + + bool uiHevcCostOk; + bool uiAffineCostOk; + bool uiAffine6CostOk; + bool uiCostOk[2]; + bool uiCostBiOk; + bool costValidList1Ok; + + bool bCleanCandExist; +#endif + AMVPInfo aacAMVPInfo[2][33]; int iRefIdx[2]={0,0}; //If un-initialized, may cause SEGV in bi-directional prediction iterative stage. @@ -2328,6 +2786,60 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) checkNonAffine = m_affineMotion.hevcCost[1] < m_affineMotion.hevcCost[0] * 1.06f; } +#if GDR_ENABLED + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + const bool init_value = true; +#endif + + amvp[0].numCand = 0; + amvp[1].numCand = 0; + memset(aacAMVPInfo, 0, sizeof(aacAMVPInfo)); + +#if GDR_ENABLED + if (isEncodeClean) + { + biPDistTempOk = init_value; + bestBiPDistOk = init_value; + uiCostTempOk = init_value; + + uiHevcCostOk = init_value; + uiAffineCostOk = init_value; + uiAffine6CostOk = init_value; + memset(uiCostOk, init_value, sizeof(uiCostOk)); + uiCostBiOk = init_value; + uiCostTempOk = init_value; + costValidList1Ok = init_value; + + memset(cMvSolid, init_value, sizeof(cMvSolid)); + memset(cMvValid, init_value, sizeof(cMvValid)); + memset(cMvBiSolid, !init_value, sizeof(cMvBiSolid)); + memset(cMvBiValid, !init_value, sizeof(cMvBiValid)); + + memset(cMvPredSolid, init_value, sizeof(cMvPredSolid)); + memset(cMvPredBiSolid, init_value, sizeof(cMvPredBiSolid)); + + memset(cMvTempSolid, init_value, sizeof(cMvTempSolid)); + memset(cMvTempValid, init_value, sizeof(cMvTempValid)); + memset(cMvHevcTempSolid, init_value, sizeof(cMvHevcTempSolid)); + memset(cMvHevcTempValid, init_value, sizeof(cMvHevcTempValid)); + + + memset(pu.mvSolid, init_value, sizeof(pu.mvSolid)); + memset(pu.mvValid, init_value, sizeof(pu.mvValid)); + + memset(pu.mvAffiSolid, init_value, sizeof(pu.mvAffiSolid)); + memset(pu.mvAffiValid, init_value, sizeof(pu.mvAffiValid)); + + memset(pu.mvpSolid, init_value, sizeof(pu.mvpSolid)); + memset(pu.mvpType, init_value, sizeof(pu.mvpType)); + + pu.mvpPos[0] = Position(0, 0); + pu.mvpPos[1] = Position(0, 0); + + bCleanCandExist = false; + } +#endif + { if (pu.cu->cs->bestParent != nullptr && pu.cu->cs->bestParent->getCU(CHANNEL_TYPE_LUMA) != nullptr && pu.cu->cs->bestParent->getCU(CHANNEL_TYPE_LUMA)->affine == false) { @@ -2353,6 +2865,15 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) Distortion uiCostBi = std::numeric_limits<Distortion>::max(); Distortion uiCostTemp; +#if GDR_ENABLED + memset(uiCostTempL0Ok, init_value, sizeof(uiCostTempL0Ok)); + + bool mvValidList1Solid = init_value; + bool mvValidList1Valid = init_value; + uiHevcCostOk = false; + uiAffineCostOk = false; +#endif + uint32_t uiBits[3]; uint32_t uiBitsTemp; Distortion bestBiPDist = std::numeric_limits<Distortion>::max(); @@ -2397,12 +2918,48 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) aaiMvpIdx[iRefList][iRefIdxTemp] = pu.mvpIdx[eRefPicList]; aaiMvpNum[iRefList][iRefIdxTemp] = pu.mvpNum[eRefPicList]; +#if GDR_ENABLED + if (isEncodeClean) + { + biPDistTempOk = true; + biPDistTempOk = amvp[eRefPicList].mvSolid[aaiMvpIdx[iRefList][iRefIdxTemp]]; + cMvPredSolid[iRefList][iRefIdxTemp] = biPDistTempOk; + cMvTempSolid[iRefList][iRefIdxTemp] = biPDistTempOk; + cMvTempValid[iRefList][iRefIdxTemp] = cs.isClean(pu.Y().bottomRight(), cMvTemp[iRefList][iRefIdxTemp], (RefPicList)iRefList, iRefIdxTemp); + } +#endif + +#if GDR_ENABLED + allOk = (cs.picHeader->getMvdL1ZeroFlag() && iRefList == 1 && biPDistTemp < bestBiPDist); + + if (isEncodeClean) + { + if (biPDistTempOk) + { + allOk = (bestBiPDistOk) ? (cs.picHeader->getMvdL1ZeroFlag() && iRefList == 1 && biPDistTemp < bestBiPDist) : true; + } + else + { + allOk = false; + } + } +#endif +#if GDR_ENABLED + if (allOk) +#else if(cs.picHeader->getMvdL1ZeroFlag() && iRefList==1 && biPDistTemp < bestBiPDist) +#endif { bestBiPDist = biPDistTemp; bestBiPMvpL1 = aaiMvpIdx[iRefList][iRefIdxTemp]; bestBiPRefIdxL1 = iRefIdxTemp; +#if GDR_ENABLED + if (isEncodeClean) + { + bestBiPDistOk = biPDistTempOk; + } +#endif } uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdx[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS]; @@ -2412,8 +2969,21 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) if ( cs.slice->getList1IdxToList0Idx( iRefIdxTemp ) >= 0 ) { cMvTemp[1][iRefIdxTemp] = cMvTemp[0][cs.slice->getList1IdxToList0Idx( iRefIdxTemp )]; +#if GDR_ENABLED + if (isEncodeClean) + { + cMvTempSolid[1][iRefIdxTemp] = cMvTempSolid[1][cs.slice->getList1IdxToList0Idx(iRefIdxTemp)]; + cMvTempValid[1][iRefIdxTemp] = cs.isClean(pu.Y().bottomRight(), cMvTemp[1][iRefIdxTemp], (RefPicList)1, cs.slice->getList1IdxToList0Idx(iRefIdxTemp)); + } +#endif uiCostTemp = uiCostTempL0[cs.slice->getList1IdxToList0Idx( iRefIdxTemp )]; /*first subtract the bit-rate part of the cost of the other list*/ +#if GDR_ENABLED + if (isEncodeClean) + { + uiCostTempOk = uiCostTempL0Ok[cs.slice->getList1IdxToList0Idx(iRefIdxTemp)]; + } +#endif uiCostTemp -= m_pcRdCost->getCost( uiBitsTempL0[cs.slice->getList1IdxToList0Idx( iRefIdxTemp )] ); /*correct the bit-rate part of the current ref*/ m_pcRdCost->setPredictor ( cMvPred[iRefList][iRefIdxTemp] ); @@ -2423,28 +2993,131 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) } else { +#if GDR_ENABLED + bCleanCandExist = false; + xMotionEstimation(pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], cMvTempSolid[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, amvp[eRefPicList], bCleanCandExist); +#else xMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, amvp[eRefPicList] ); +#endif + +#if GDR_ENABLED + if (isEncodeClean) + { + int mvp_idx = aaiMvpIdx[iRefList][iRefIdxTemp]; + cMvPredSolid[iRefList][iRefIdxTemp] = amvp[eRefPicList].mvSolid[mvp_idx]; + cMvTempSolid[iRefList][iRefIdxTemp] = amvp[eRefPicList].mvSolid[mvp_idx]; + cMvTempValid[iRefList][iRefIdxTemp] = cs.isClean(pu.Y().bottomRight(), cMvTemp[iRefList][iRefIdxTemp], (RefPicList)iRefList, iRefIdxTemp); + + if (cMvTempValid[iRefList][iRefIdxTemp]) + { + cMvTempValid[iRefList][iRefIdxTemp] = cMvTempSolid[iRefList][iRefIdxTemp]; + } + + uiCostTempOk = bCleanCandExist; + uiCostTempOk = uiCostTempOk && cMvPredSolid[iRefList][iRefIdxTemp]; + uiCostTempOk = uiCostTempOk && cMvTempSolid[iRefList][iRefIdxTemp]; + uiCostTempOk = uiCostTempOk && cMvTempValid[iRefList][iRefIdxTemp]; + } +#endif } } else { +#if GDR_ENABLED + bCleanCandExist = false; + xMotionEstimation(pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], cMvTempSolid[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, amvp[eRefPicList], bCleanCandExist); +#else xMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, amvp[eRefPicList] ); - } - if( cu.cs->sps->getUseBcw() && cu.BcwIdx == BCW_DEFAULT && cu.cs->slice->isInterB() ) - { +#endif + +#if GDR_ENABLED + if (isEncodeClean) + { + int mvp_idx = aaiMvpIdx[iRefList][iRefIdxTemp]; + cMvPredSolid[iRefList][iRefIdxTemp] = amvp[eRefPicList].mvSolid[mvp_idx]; + cMvTempSolid[iRefList][iRefIdxTemp] = amvp[eRefPicList].mvSolid[mvp_idx]; + cMvTempValid[iRefList][iRefIdxTemp] = cs.isClean(pu.Y().bottomRight(), cMvTemp[iRefList][iRefIdxTemp], (RefPicList)iRefList, iRefIdxTemp); + if (cMvTempValid[iRefList][iRefIdxTemp]) + { + cMvTempValid[iRefList][iRefIdxTemp] = cMvTempSolid[iRefList][iRefIdxTemp]; + } + + uiCostTempOk = bCleanCandExist; + uiCostTempOk = uiCostTempOk && cMvPredSolid[iRefList][iRefIdxTemp]; + uiCostTempOk = uiCostTempOk && cMvTempSolid[iRefList][iRefIdxTemp]; + uiCostTempOk = uiCostTempOk && cMvTempValid[iRefList][iRefIdxTemp]; + } +#endif + } + if( cu.cs->sps->getUseBcw() && cu.BcwIdx == BCW_DEFAULT && cu.cs->slice->isInterB() ) + { const bool checkIdentical = true; m_uniMotions.setReadMode(checkIdentical, (uint32_t)iRefList, (uint32_t)iRefIdxTemp); +#if GDR_ENABLED + m_uniMotions.copyFrom(cMvTemp[iRefList][iRefIdxTemp], cMvTempSolid[iRefList][iRefIdxTemp], uiCostTemp - m_pcRdCost->getCost(uiBitsTemp), (uint32_t)iRefList, (uint32_t)iRefIdxTemp); +#else m_uniMotions.copyFrom(cMvTemp[iRefList][iRefIdxTemp], uiCostTemp - m_pcRdCost->getCost(uiBitsTemp), (uint32_t)iRefList, (uint32_t)iRefIdxTemp); +#endif } xCopyAMVPInfo( &amvp[eRefPicList], &aacAMVPInfo[iRefList][iRefIdxTemp]); // must always be done ( also when AMVP_MODE = AM_NONE ) - xCheckBestMVP( eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], amvp[eRefPicList], uiBitsTemp, uiCostTemp, pu.cu->imv ); +#if GDR_ENABLED + xCheckBestMVP(pu, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], amvp[eRefPicList], uiBitsTemp, uiCostTemp, pu.cu->imv); + + if (isEncodeClean) + { + int mvp_idx = aaiMvpIdx[iRefList][iRefIdxTemp]; + + cMvPredSolid[iRefList][iRefIdxTemp] = amvp[eRefPicList].mvSolid[mvp_idx]; + cMvTempSolid[iRefList][iRefIdxTemp] = amvp[eRefPicList].mvSolid[mvp_idx]; + cMvTempValid[iRefList][iRefIdxTemp] = cs.isClean(pu.Y().bottomRight(), cMvTemp[iRefList][iRefIdxTemp], (RefPicList)iRefList, iRefIdxTemp); + if (cMvTempValid[iRefList][iRefIdxTemp]) + { + cMvTempValid[iRefList][iRefIdxTemp] = cMvTempSolid[iRefList][iRefIdxTemp]; + } + uiCostTempOk = true; + uiCostTempOk = uiCostTempOk && cMvPredSolid[iRefList][iRefIdxTemp]; + uiCostTempOk = uiCostTempOk && cMvTempSolid[iRefList][iRefIdxTemp]; + uiCostTempOk = uiCostTempOk && cMvTempValid[iRefList][iRefIdxTemp]; + } +#else + xCheckBestMVP( eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], amvp[eRefPicList], uiBitsTemp, uiCostTemp, pu.cu->imv ); +#endif if ( iRefList == 0 ) { uiCostTempL0[iRefIdxTemp] = uiCostTemp; uiBitsTempL0[iRefIdxTemp] = uiBitsTemp; } +#if GDR_ENABLED + if (isEncodeClean) + { + uiCostTempL0Ok[iRefIdxTemp] = uiCostTempOk; + } +#endif + +#if GDR_ENABLED + allOk = (uiCostTemp < uiCost[iRefList]); + if (isEncodeClean) + { + if (uiCostTempOk) + { + allOk = (uiCostOk[iRefList]) ? (uiCostTemp < uiCost[iRefList]) : true; + } + else + { + allOk = false; + } + + allOk = allOk && bCleanCandExist; + } +#endif + + +#if GDR_ENABLED + if (allOk) +#else if ( uiCostTemp < uiCost[iRefList] ) +#endif { uiCost[iRefList] = uiCostTemp; uiBits[iRefList] = uiBitsTemp; // storing for bi-prediction @@ -2452,21 +3125,65 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) // set motion cMv [iRefList] = cMvTemp[iRefList][iRefIdxTemp]; iRefIdx[iRefList] = iRefIdxTemp; + +#if GDR_ENABLED + if (isEncodeClean) + { + uiCostOk[iRefList] = uiCostTempOk; + cMvSolid[iRefList] = cMvTempSolid[iRefList][iRefIdxTemp]; + cMvValid[iRefList] = cs.isClean(pu.Y().bottomRight(), cMv[iRefList], (RefPicList)iRefList, iRefIdx[iRefList]); + } +#endif + } + + +#if GDR_ENABLED + allOk = (iRefList == 1 && uiCostTemp < costValidList1 && cs.slice->getList1IdxToList0Idx(iRefIdxTemp) < 0); + if (isEncodeClean) + { + if (uiCostTempOk) + { + allOk = (costValidList1Ok) ? (iRefList == 1 && uiCostTemp < costValidList1 && cs.slice->getList1IdxToList0Idx(iRefIdxTemp) < 0) : true; + } + else + { + allOk = false; + } } +#endif +#if GDR_ENABLED + if (allOk) +#else if ( iRefList == 1 && uiCostTemp < costValidList1 && cs.slice->getList1IdxToList0Idx( iRefIdxTemp ) < 0 ) +#endif { costValidList1 = uiCostTemp; bitsValidList1 = uiBitsTemp; // set motion mvValidList1 = cMvTemp[iRefList][iRefIdxTemp]; +#if GDR_ENABLED + if (isEncodeClean) + { + costValidList1Ok = uiCostTempOk; + mvValidList1Solid = cMvTempSolid[iRefList][iRefIdxTemp]; + mvValidList1Valid = cs.isClean(pu.Y().bottomRight(), mvValidList1, (RefPicList)iRefList, iRefIdxTemp); + } +#endif refIdxValidList1 = iRefIdxTemp; } } } ::memcpy(cMvHevcTemp, cMvTemp, sizeof(cMvTemp)); +#if GDR_ENABLED + if (isEncodeClean) + { + ::memcpy(cMvHevcTempSolid, cMvTempSolid, sizeof(cMvTempSolid)); + ::memcpy(cMvHevcTempValid, cMvTempValid, sizeof(cMvTempValid)); + } +#endif if (cu.imv == 0 && (!cu.slice->getSPS()->getUseBcw() || bcwIdx == BCW_DEFAULT)) { insertUniMvCands(pu.Y(), cMvTemp); @@ -2488,8 +3205,23 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) iRefIdxBi[0] = iRefIdx[0]; iRefIdxBi[1] = iRefIdx[1]; +#if GDR_ENABLED + if (isEncodeClean) + { + cMvBiSolid[0] = cMvSolid[0]; + cMvBiSolid[1] = cMvSolid[1]; + cMvBiValid[0] = cMvValid[0]; + cMvBiValid[1] = cMvValid[1]; + } +#endif ::memcpy( cMvPredBi, cMvPred, sizeof( cMvPred ) ); ::memcpy( aaiMvpIdxBi, aaiMvpIdx, sizeof( aaiMvpIdx ) ); +#if GDR_ENABLED + if (isEncodeClean) + { + ::memcpy(cMvPredBiSolid, cMvPredSolid, sizeof(cMvPredSolid)); + } +#endif uint32_t uiMotBits[2]; @@ -2500,10 +3232,25 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) cMvPredBi [1][bestBiPRefIdxL1] = amvp[REF_PIC_LIST_1].mvCand[bestBiPMvpL1]; cMvBi [1] = cMvPredBi[1][bestBiPRefIdxL1]; +#if GDR_ENABLED + if (isEncodeClean) + { + cMvPredBiSolid[1][bestBiPRefIdxL1] = amvp[REF_PIC_LIST_1].mvSolid[bestBiPMvpL1]; + cMvBiSolid[1] = cMvPredBiSolid[1][bestBiPRefIdxL1]; + cMvBiValid[1] = cs.isClean(pu.Y().bottomRight(), cMvBi[1], REF_PIC_LIST_1, bestBiPRefIdxL1); + } +#endif iRefIdxBi[1] = bestBiPRefIdxL1; pu.mv [REF_PIC_LIST_1] = cMvBi[1]; pu.refIdx[REF_PIC_LIST_1] = iRefIdxBi[1]; pu.mvpIdx[REF_PIC_LIST_1] = bestBiPMvpL1; +#if GDR_ENABLED + if (isEncodeClean) + { + pu.mvSolid[REF_PIC_LIST_1] = cMvBiSolid[1]; + pu.mvValid[REF_PIC_LIST_1] = cs.isClean(pu.Y().bottomRight(), pu.mv[REF_PIC_LIST_1], REF_PIC_LIST_1, pu.refIdx[REF_PIC_LIST_1]); + } +#endif if( m_pcEncCfg->getMCTSEncConstraint() ) { @@ -2538,6 +3285,13 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) uiBits[2] = uiMbBits[2] + uiMotBits[0] + uiMotBits[1]; cMvTemp[1][bestBiPRefIdxL1] = cMvBi[1]; +#if GDR_ENABLED + if (isEncodeClean) + { + cMvTempSolid[1][bestBiPRefIdxL1] = cMvBiSolid[1]; + cMvTempValid[1][bestBiPRefIdxL1] = cs.isClean(pu.Y().bottomRight(), cMvBi[1], REF_PIC_LIST_1, bestBiPRefIdxL1); + } +#endif } else { @@ -2566,7 +3320,26 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) if (m_pcEncCfg->getFastInterSearchMode() == FASTINTERSEARCH_MODE1 || m_pcEncCfg->getFastInterSearchMode() == FASTINTERSEARCH_MODE2) { +#if GDR_ENABLED + allOk = (uiCost[0] <= uiCost[1]); + if (isEncodeClean) + { + if (uiCostOk[0]) + { + allOk = (uiCostOk[1]) ? (uiCost[0] <= uiCost[1]) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if (uiCost[0] <= uiCost[1]) +#endif { iRefList = 1; } @@ -2588,7 +3361,13 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) { pu.mv[1 - iRefList] = cMv[1 - iRefList]; pu.refIdx[1 - iRefList] = iRefIdx[1 - iRefList]; - +#if GDR_ENABLED + if (isEncodeClean) + { + pu.mvSolid[1 - iRefList] = cMvSolid[1 - iRefList]; + pu.mvValid[1 - iRefList] = cs.isClean(pu.Y().bottomRight(), pu.mv[1 - iRefList], (RefPicList)(1 - iRefList), pu.refIdx[1 - iRefList]); + } +#endif PelUnitBuf predBufTmp = m_tmpPredStorage[1 - iRefList].getBuf(UnitAreaRelative(cu, pu)); motionCompensation(pu, predBufTmp, RefPicList(1 - iRefList)); } @@ -2631,19 +3410,99 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) } // call ME xCopyAMVPInfo(&aacAMVPInfo[iRefList][iRefIdxTemp], &amvp[eRefPicList]); +#if GDR_ENABLED + bCleanCandExist = false; + xMotionEstimation(pu, origBuf, eRefPicList, cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], cMvTempSolid[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, amvp[eRefPicList], bCleanCandExist, true); +#else xMotionEstimation(pu, origBuf, eRefPicList, cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, amvp[eRefPicList], true); +#endif +#if GDR_ENABLED + if (isEncodeClean) + { + int mvp_idx = aaiMvpIdxBi[iRefList][iRefIdxTemp]; + cMvPredBiSolid[iRefList][iRefIdxTemp] = amvp[eRefPicList].mvSolid[mvp_idx]; + cMvTempSolid[iRefList][iRefIdxTemp] = amvp[eRefPicList].mvSolid[mvp_idx]; + cMvTempValid[iRefList][iRefIdxTemp] = cs.isClean(pu.Y().bottomRight(), cMvTemp[iRefList][iRefIdxTemp], (RefPicList)iRefList, iRefIdxTemp); + if (cMvTempValid[iRefList][iRefIdxTemp]) + { + cMvTempValid[iRefList][iRefIdxTemp] = cMvTempSolid[iRefList][iRefIdxTemp]; + } + + uiCostTempOk = bCleanCandExist; + uiCostTempOk = uiCostTempOk && cMvPredBiSolid[iRefList][iRefIdxTemp]; + uiCostTempOk = uiCostTempOk && cMvTempSolid[iRefList][iRefIdxTemp]; + uiCostTempOk = uiCostTempOk && cMvTempValid[iRefList][iRefIdxTemp]; + } +#endif + +#if GDR_ENABLED + // note : uiCostTemp is the new Best MVP cost, + // solid info will be at amvp[eRefPicList].mvSolid[aaiMvpIdx[iRefList][iRefIdxTemp]]; + xCheckBestMVP(pu, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], amvp[eRefPicList], uiBitsTemp, uiCostTemp, pu.cu->imv); + + if (isEncodeClean) + { + int mvp_idx = aaiMvpIdxBi[iRefList][iRefIdxTemp]; + + cMvPredBiSolid[iRefList][iRefIdxTemp] = amvp[eRefPicList].mvSolid[mvp_idx]; + cMvTempSolid[iRefList][iRefIdxTemp] = amvp[eRefPicList].mvSolid[mvp_idx]; + cMvTempValid[iRefList][iRefIdxTemp] = cs.isClean(pu.Y().bottomRight(), cMvTemp[iRefList][iRefIdxTemp], (RefPicList)iRefList, iRefIdxTemp); + if (cMvTempValid[iRefList][iRefIdxTemp]) + { + cMvTempValid[iRefList][iRefIdxTemp] = cMvTempSolid[iRefList][iRefIdxTemp]; + } + + uiCostTempOk = true; + uiCostTempOk = uiCostTempOk && cMvPredBiSolid[iRefList][iRefIdxTemp]; + uiCostTempOk = uiCostTempOk && cMvTempSolid[iRefList][iRefIdxTemp]; + uiCostTempOk = uiCostTempOk && cMvTempValid[iRefList][iRefIdxTemp]; + } +#else + xCheckBestMVP(eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], amvp[eRefPicList], uiBitsTemp, uiCostTemp, pu.cu->imv); +#endif +#if GDR_ENABLED + allOk = (uiCostTemp < uiCostBi); + if (isEncodeClean) + { + if (uiCostTempOk) + { + allOk = (uiCostBiOk) ? (uiCostTemp < uiCostBi) : true; + } + else + { + allOk = false; + } + } +#endif +#if GDR_ENABLED + if (allOk) +#else if (uiCostTemp < uiCostBi) +#endif { bChanged = true; cMvBi[iRefList] = cMvTemp[iRefList][iRefIdxTemp]; +#if GDR_ENABLED + if (isEncodeClean) + { + cMvBiSolid[iRefList] = cMvTempSolid[iRefList][iRefIdxTemp]; + cMvBiValid[iRefList] = cs.isClean(pu.Y().bottomRight(), cMvTemp[iRefList][iRefIdxTemp], (RefPicList)iRefList, iRefIdxTemp); + } +#endif iRefIdxBi[iRefList] = iRefIdxTemp; uiCostBi = uiCostTemp; +#if GDR_ENABLED + if (isEncodeClean) + { + uiCostBiOk = uiCostTempOk; + } +#endif uiMotBits[iRefList] = uiBitsTemp - uiMbBits[2] - uiMotBits[1 - iRefList]; uiMotBits[iRefList] -= ((cs.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0); uiBits[2] = uiBitsTemp; @@ -2653,7 +3512,13 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) // Set motion pu.mv[eRefPicList] = cMvBi[iRefList]; pu.refIdx[eRefPicList] = iRefIdxBi[iRefList]; - +#if GDR_ENABLED + if (isEncodeClean) + { + pu.mvSolid[eRefPicList] = cMvBiSolid[iRefList]; + pu.mvValid[eRefPicList] = cs.isClean(pu.Y().bottomRight(), pu.mv[eRefPicList], (RefPicList)eRefPicList, pu.refIdx[eRefPicList]); + } +#endif PelUnitBuf predBufTmp = m_tmpPredStorage[iRefList].getBuf(UnitAreaRelative(cu, pu)); motionCompensation(pu, predBufTmp, eRefPicList); } @@ -2662,16 +3527,83 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) if (!bChanged) { +#if GDR_ENABLED + allOk = ((uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) || enforceBcwPred); + + if (isEncodeClean) + { + if (uiCostBiOk) + { + allOk = (uiCostOk[0] && uiCostOk[1]) ? ((uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) || enforceBcwPred) : true; + } + else + { + allOk = false; + } + } +#endif +#if GDR_ENABLED + if (allOk) +#else if ((uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) || enforceBcwPred) +#endif { xCopyAMVPInfo(&aacAMVPInfo[0][iRefIdxBi[0]], &amvp[REF_PIC_LIST_0]); +#if GDR_ENABLED + // note : uiCostBi is the new Best MVP cost, + // solid info will be at amvp[eRefPicList].mvSolid[aaiMvpIdx[iRefList][iRefIdxTemp]]; + xCheckBestMVP(pu, REF_PIC_LIST_0, cMvBi[0], cMvPredBi[0][iRefIdxBi[0]], aaiMvpIdxBi[0][iRefIdxBi[0]], amvp[REF_PIC_LIST_0], uiBits[2], uiCostBi, pu.cu->imv); + + if (isEncodeClean) + { + int mvp_idx = aaiMvpIdxBi[0][iRefIdxBi[0]]; + + cMvPredBiSolid[0][iRefIdxBi[0]] = amvp[0].mvSolid[mvp_idx]; + cMvBiSolid[0] = amvp[0].mvSolid[mvp_idx]; + cMvBiValid[0] = cs.isClean(pu.Y().bottomRight(), cMvBi[0], (RefPicList)0, iRefIdxBi[0]); + if (cMvBiValid[0]) + { + cMvBiValid[0] = cMvBiSolid[0]; + } + + uiCostBiOk = true; + uiCostBiOk = uiCostBiOk && cMvPredBiSolid[0][iRefIdxBi[0]]; + uiCostBiOk = uiCostBiOk && cMvBiSolid[0]; + uiCostBiOk = uiCostBiOk && cMvBiValid[0]; + } +#else xCheckBestMVP(REF_PIC_LIST_0, cMvBi[0], cMvPredBi[0][iRefIdxBi[0]], aaiMvpIdxBi[0][iRefIdxBi[0]], amvp[REF_PIC_LIST_0], uiBits[2], uiCostBi, pu.cu->imv); +#endif if (!cs.picHeader->getMvdL1ZeroFlag()) { xCopyAMVPInfo(&aacAMVPInfo[1][iRefIdxBi[1]], &amvp[REF_PIC_LIST_1]); +#if GDR_ENABLED + // note : uiCostBi is the new Best MVP cost, + // solid info will be at amvp[eRefPicList].mvSolid[aaiMvpIdx[iRefList][iRefIdxTemp]]; + xCheckBestMVP(pu, REF_PIC_LIST_1, cMvBi[1], cMvPredBi[1][iRefIdxBi[1]], aaiMvpIdxBi[1][iRefIdxBi[1]], amvp[REF_PIC_LIST_1], uiBits[2], uiCostBi, pu.cu->imv); + + if (isEncodeClean) + { + int mvp_idx = aaiMvpIdxBi[1][iRefIdxBi[1]]; + + cMvPredBiSolid[1][iRefIdxBi[1]] = aaiMvpIdxBi[1][iRefIdxBi[1]]; + cMvBiSolid[1] = amvp[REF_PIC_LIST_1].mvSolid[mvp_idx]; + cMvBiValid[1] = cs.isClean(pu.Y().bottomRight(), cMvBi[1], (RefPicList)1, iRefIdxBi[1]); + if (cMvBiValid[1]) + { + cMvBiValid[1] = cMvBiSolid[1]; + } + + uiCostBiOk = true; + uiCostBiOk = uiCostBiOk && cMvPredBiSolid[1][iRefIdxBi[1]]; + uiCostBiOk = uiCostBiOk && cMvBiSolid[1]; + uiCostBiOk = uiCostBiOk && cMvBiValid[1]; + } +#else xCheckBestMVP(REF_PIC_LIST_1, cMvBi[1], cMvPredBi[1][iRefIdxBi[1]], aaiMvpIdxBi[1][iRefIdxBi[1]], amvp[REF_PIC_LIST_1], uiBits[2], uiCostBi, pu.cu->imv); +#endif } } break; @@ -2705,6 +3637,21 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) MvField cCurMvField, cTarMvField; Distortion costStart = std::numeric_limits<Distortion>::max(); + +#if GDR_ENABLED + bool cMvPredSymSolid[2] = { init_value, init_value }; + bool cMvPredSymValid[2] = { init_value, init_value }; + + bool cCurMvFieldSolid = init_value; + bool cTarMvFieldSolid = init_value; + bool cCurMvFieldValid = init_value; + bool cTarMvFieldValid = init_value; + + bool costStartOk = false; + bool symCostOk = init_value; + bool costOk = init_value; + bool bestCostOk = init_value; +#endif for ( int i = 0; i < aacAMVPInfo[curRefList][refIdxCur].numCand; i++ ) { for ( int j = 0; j < aacAMVPInfo[tarRefList][refIdxTar].numCand; j++ ) @@ -2712,11 +3659,46 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) cCurMvField.setMvField( aacAMVPInfo[curRefList][refIdxCur].mvCand[i], refIdxCur ); cTarMvField.setMvField( aacAMVPInfo[tarRefList][refIdxTar].mvCand[j], refIdxTar ); Distortion cost = xGetSymmetricCost( pu, origBuf, eCurRefList, cCurMvField, cTarMvField, bcwIdx ); + +#if GDR_ENABLED + if (isEncodeClean) + { + cCurMvFieldSolid = aacAMVPInfo[curRefList][refIdxCur].mvSolid[i]; + cTarMvFieldSolid = aacAMVPInfo[tarRefList][refIdxTar].mvSolid[i]; + costOk = cCurMvFieldSolid && cTarMvFieldSolid; + } +#endif +#if GDR_ENABLED + allOk = (cost < costStart); + if (isEncodeClean) + { + if (costOk) + { + allOk = (costStartOk) ? (cost < costStart) : true; + } + else + { + allOk = false; + } + } +#endif +#if GDR_ENABLED + if (allOk) +#else if ( cost < costStart ) +#endif { costStart = cost; cMvPredSym[curRefList] = aacAMVPInfo[curRefList][refIdxCur].mvCand[i]; cMvPredSym[tarRefList] = aacAMVPInfo[tarRefList][refIdxTar].mvCand[j]; +#if GDR_ENABLED + if (isEncodeClean) + { + costStartOk = costOk; + cMvPredSymSolid[curRefList] = aacAMVPInfo[curRefList][refIdxCur].mvSolid[i]; + cMvPredSymSolid[tarRefList] = aacAMVPInfo[tarRefList][refIdxTar].mvSolid[j]; + } +#endif mvpIdxSym[curRefList] = i; mvpIdxSym[tarRefList] = j; } @@ -2725,6 +3707,13 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) cCurMvField.mv = cMvPredSym[curRefList]; cTarMvField.mv = cMvPredSym[tarRefList]; +#if GDR_ENABLED + if (isEncodeClean) + { + cCurMvFieldSolid = cMvPredSymSolid[curRefList]; + cTarMvFieldSolid = cMvPredSymSolid[tarRefList]; + } +#endif m_pcRdCost->setCostScale(0); Mv pred = cMvPredSym[curRefList]; pred.changeTransPrecInternal2Amvr(pu.cu->imv); @@ -2789,11 +3778,63 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) } Distortion bestCost = costStart; +#if GDR_ENABLED + symmvdCheckBestMvp(pu, origBuf, mvStart, (RefPicList)curRefList, aacAMVPInfo, bcwIdx, cMvPredSym, cMvPredSymSolid, mvpIdxSym, costStart); +#else symmvdCheckBestMvp(pu, origBuf, mvStart, (RefPicList)curRefList, aacAMVPInfo, bcwIdx, cMvPredSym, mvpIdxSym, costStart); +#endif + +#if GDR_ENABLED + if (isEncodeClean) + { + int mvp_idx0 = mvpIdxSym[0]; + int mvp_idx1 = mvpIdxSym[1]; + + cMvPredSymSolid[curRefList] = aacAMVPInfo[curRefList][refIdxCur].mvSolid[mvp_idx0]; + cMvPredSymSolid[tarRefList] = aacAMVPInfo[tarRefList][refIdxTar].mvSolid[mvp_idx1]; + cMvPredSymValid[curRefList] = cs.isClean(pu.Y().bottomRight(), mvStart, (RefPicList)curRefList, pu.cu->slice->getSymRefIdx(curRefList)); + cMvPredSymValid[tarRefList] = cs.isClean(pu.Y().bottomRight(), mvStart, (RefPicList)tarRefList, pu.cu->slice->getSymRefIdx(tarRefList)); + + costStartOk = true; + costStartOk = costStartOk && cMvPredSymSolid[curRefList]; + costStartOk = costStartOk && cMvPredSymSolid[tarRefList]; + costStartOk = costStartOk && cMvPredSymValid[curRefList]; + costStartOk = costStartOk && cMvPredSymValid[tarRefList]; + } +#endif + +#if GDR_ENABLED + bool allOk = (costStart < bestCost); + if (isEncodeClean) + { + if (costStartOk) + { + allOk = (bestCostOk) ? (costStart < bestCost) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if (costStart < bestCost) +#endif { cCurMvField.setMvField(mvStart, refIdxCur); cTarMvField.setMvField(mvStart.getSymmvdMv(cMvPredSym[curRefList], cMvPredSym[tarRefList]), refIdxTar); +#if GDR_ENABLED + if (isEncodeClean) + { + cCurMvFieldSolid = cMvPredSymSolid[curRefList]; + cTarMvFieldSolid = cMvPredSymSolid[tarRefList]; + cCurMvFieldValid = cMvPredSymValid[curRefList]; + cTarMvFieldValid = cMvPredSymValid[tarRefList]; + } +#endif } } Mv startPtMv = cCurMvField.mv; @@ -2802,13 +3843,47 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) symCost = costStart - mvpCost; // ME +#if GDR_ENABLED + xSymmetricMotionEstimation(pu, origBuf, cMvPredSym[curRefList], cMvPredSym[tarRefList], eCurRefList, cCurMvField, cTarMvField, symCost, bcwIdx, costStartOk); +#else xSymmetricMotionEstimation( pu, origBuf, cMvPredSym[curRefList], cMvPredSym[tarRefList], eCurRefList, cCurMvField, cTarMvField, symCost, bcwIdx ); - +#endif symCost += mvpCost; +#if GDR_ENABLED + if (isEncodeClean) + { + cCurMvFieldValid = cs.isClean(pu.Y().bottomRight(), cCurMvField.mv, (RefPicList)(eCurRefList), cCurMvField.refIdx); + cTarMvFieldValid = cs.isClean(pu.Y().bottomRight(), cTarMvField.mv, (RefPicList)(1 - eCurRefList), cTarMvField.refIdx); + symCostOk = (cMvPredSymSolid[curRefList] && cMvPredSymSolid[tarRefList]) && (cCurMvFieldValid && cTarMvFieldValid); + } +#endif if (startPtMv != cCurMvField.mv) { // if ME change MV, run a final check for best MVP. +#if GDR_ENABLED + symmvdCheckBestMvp(pu, origBuf, cCurMvField.mv, (RefPicList)curRefList, aacAMVPInfo, bcwIdx, cMvPredSym, cMvPredSymSolid, mvpIdxSym, symCost); +#else symmvdCheckBestMvp(pu, origBuf, cCurMvField.mv, (RefPicList)curRefList, aacAMVPInfo, bcwIdx, cMvPredSym, mvpIdxSym, symCost, true); +#endif + +#if GDR_ENABLED + if (isEncodeClean) + { + int mvp_idx0 = mvpIdxSym[0]; + int mvp_idx1 = mvpIdxSym[1]; + + cMvPredSymSolid[curRefList] = aacAMVPInfo[curRefList][refIdxCur].mvSolid[mvp_idx0]; + cMvPredSymSolid[tarRefList] = aacAMVPInfo[tarRefList][refIdxTar].mvSolid[mvp_idx1]; + cMvPredSymValid[curRefList] = cs.isClean(pu.Y().bottomRight(), cCurMvField.mv, (RefPicList)curRefList, pu.cu->slice->getSymRefIdx(curRefList)); + cMvPredSymValid[tarRefList] = cs.isClean(pu.Y().bottomRight(), cCurMvField.mv, (RefPicList)tarRefList, pu.cu->slice->getSymRefIdx(tarRefList)); + + symCostOk = true; + symCostOk = symCostOk && cMvPredSymSolid[curRefList]; + symCostOk = symCostOk && cMvPredSymSolid[tarRefList]; + symCostOk = symCostOk && cMvPredSymValid[curRefList]; + symCostOk = symCostOk && cMvPredSymValid[tarRefList]; + } +#endif } bits = uiMbBits[2]; @@ -2825,10 +3900,32 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) } } // save results +#if GDR_ENABLED + bool allOk = (symCost < uiCostBi); + if (isEncodeClean) + { + if (symCostOk) + { + allOk = (uiCostBiOk) ? (symCost < uiCostBi) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if ( symCost < uiCostBi ) +#endif { uiCostBi = symCost; symMode = 1 + curRefList; +#if GDR_ENABLED + uiCostBiOk = symCostOk; +#endif cMvBi[curRefList] = cCurMvField.mv; iRefIdxBi[curRefList] = cCurMvField.refIdx; @@ -2839,6 +3936,16 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) iRefIdxBi[tarRefList] = cTarMvField.refIdx; aaiMvpIdxBi[tarRefList][cTarMvField.refIdx] = mvpIdxSym[tarRefList]; cMvPredBi[tarRefList][iRefIdxBi[tarRefList]] = cMvPredSym[tarRefList]; + +#if GDR_ENABLED + if (isEncodeClean) + { + cMvBiValid[curRefList] = cCurMvFieldValid; + cMvBiValid[tarRefList] = cTarMvFieldValid; + cMvPredBiSolid[curRefList][iRefIdxBi[curRefList]] = cMvPredSymSolid[curRefList]; + cMvPredBiSolid[tarRefList][iRefIdxBi[tarRefList]] = cMvPredSymSolid[tarRefList]; + } +#endif } } } // if (B_SLICE) @@ -2857,12 +3964,34 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) pu.mvpNum[REF_PIC_LIST_0] = NOT_VALID; pu.mvpNum[REF_PIC_LIST_1] = NOT_VALID; +#if GDR_ENABLED + if (isEncodeClean) + { + pu.mvSolid[REF_PIC_LIST_0] = true; + pu.mvSolid[REF_PIC_LIST_1] = true; + pu.mvValid[REF_PIC_LIST_0] = true; + pu.mvValid[REF_PIC_LIST_1] = true; + } +#endif // Set Motion Field cMv[1] = mvValidList1; +#if GDR_ENABLED + if (isEncodeClean) + { + cMvSolid[1] = mvValidList1Solid; + cMvValid[1] = mvValidList1Valid; + } +#endif iRefIdx[1] = refIdxValidList1; uiBits[1] = bitsValidList1; uiCost[1] = costValidList1; +#if GDR_ENABLED + if (isEncodeClean) + { + uiCostOk[1] = costValidList1Ok; + } +#endif if (cu.cs->pps->getWPBiPred() == true && tryBipred && (bcwIdx != BCW_DEFAULT)) { CHECK(iRefIdxBi[0] < 0, "Invalid picture reference index"); @@ -2872,16 +4001,59 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) if (WPScalingParam::isWeighted(wp0) || WPScalingParam::isWeighted(wp1)) { uiCostBi = MAX_UINT; +#if GDR_ENABLED + if (isEncodeClean) + { + uiCostBiOk = false; + } +#endif enforceBcwPred = false; } } if (enforceBcwPred) { uiCost[0] = uiCost[1] = MAX_UINT; +#if GDR_ENABLED + uiCostOk[0] = uiCostOk[1] = false; +#endif } uiLastModeTemp = uiLastMode; +#if GDR_ENABLED + allOk = ((uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) || enforceBcwPred); + + if (isEncodeClean) + { + if (uiCostBiOk) + { + allOk = (uiCostOk[0] && uiCostOk[1]) ? ((uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) || enforceBcwPred) : true; + } + else + { + allOk = false; + } + } + + bool L0ok = (uiCost[0] <= uiCost[1]); + + if (isEncodeClean) + { + if (uiCostOk[0]) + { + L0ok = (uiCostOk[1]) ? (uiCost[0] <= uiCost[1]) : true; + } + else + { + L0ok = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) +#endif { uiLastMode = 2; pu.mv [REF_PIC_LIST_0] = cMvBi[0]; @@ -2897,8 +4069,23 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) pu.interDir = 3; pu.cu->smvdMode = symMode; +#if GDR_ENABLED + if (isEncodeClean) + { + int mvp_idx0 = pu.mvpIdx[REF_PIC_LIST_0]; + int mvp_idx1 = pu.mvpIdx[REF_PIC_LIST_1]; + pu.mvSolid[REF_PIC_LIST_0] = cMvBiSolid[REF_PIC_LIST_0] && cMvPredBiSolid[REF_PIC_LIST_0][mvp_idx0]; + pu.mvSolid[REF_PIC_LIST_1] = cMvBiSolid[REF_PIC_LIST_1] && cMvPredBiSolid[REF_PIC_LIST_1][mvp_idx1]; + pu.mvValid[REF_PIC_LIST_0] = cs.isClean(pu.Y().bottomRight(), pu.mv[REF_PIC_LIST_0], (RefPicList)REF_PIC_LIST_0, pu.refIdx[REF_PIC_LIST_0]); + pu.mvValid[REF_PIC_LIST_1] = cs.isClean(pu.Y().bottomRight(), pu.mv[REF_PIC_LIST_1], (RefPicList)REF_PIC_LIST_1, pu.refIdx[REF_PIC_LIST_1]); + } +#endif } +#if GDR_ENABLED + else if (L0ok) +#else else if ( uiCost[0] <= uiCost[1] ) +#endif { uiLastMode = 0; pu.mv [REF_PIC_LIST_0] = cMv[0]; @@ -2907,6 +4094,13 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) pu.mvpIdx[REF_PIC_LIST_0] = aaiMvpIdx[0][iRefIdx[0]]; pu.mvpNum[REF_PIC_LIST_0] = aaiMvpNum[0][iRefIdx[0]]; pu.interDir = 1; +#if GDR_ENABLED + if (isEncodeClean) + { + pu.mvSolid[REF_PIC_LIST_0] = cMvSolid[REF_PIC_LIST_0] && cMvPredSolid[0][iRefIdx[0]]; + pu.mvValid[REF_PIC_LIST_0] = cs.isClean(pu.Y().bottomRight(), pu.mv[REF_PIC_LIST_0], (RefPicList)REF_PIC_LIST_0, pu.refIdx[REF_PIC_LIST_0]); + } +#endif } else { @@ -2917,6 +4111,13 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) pu.mvpIdx[REF_PIC_LIST_1] = aaiMvpIdx[1][iRefIdx[1]]; pu.mvpNum[REF_PIC_LIST_1] = aaiMvpNum[1][iRefIdx[1]]; pu.interDir = 2; +#if GDR_ENABLED + if (isEncodeClean) + { + pu.mvSolid[REF_PIC_LIST_1] = cMvSolid[REF_PIC_LIST_1] && cMvPredSolid[1][iRefIdx[1]]; + pu.mvValid[REF_PIC_LIST_1] = cs.isClean(pu.Y().bottomRight(), pu.mv[REF_PIC_LIST_1], (RefPicList)REF_PIC_LIST_1, pu.refIdx[REF_PIC_LIST_1]); + } +#endif } if( bcwIdx != BCW_DEFAULT ) @@ -2927,13 +4128,26 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) uiHevcCost = (uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) ? uiCostBi : ((uiCost[0] <= uiCost[1]) ? uiCost[0] : uiCost[1]); - } +#if GDR_ENABLED + if (isEncodeClean) + { + uiHevcCostOk = (uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) ? uiCostBiOk : ((uiCost[0] <= uiCost[1]) ? uiCostOk[0] : uiCostOk[1]); + } +#endif + } + if (cu.Y().width > 8 && cu.Y().height > 8 && cu.slice->getSPS()->getUseAffine() && checkAffine && (bcwIdx == BCW_DEFAULT || m_affineModeSelected || !m_pcEncCfg->getUseBcwFast()) ) { m_hevcCost = uiHevcCost; +#if GDR_ENABLED + if (isEncodeClean) + { + m_hevcCostOk = uiHevcCostOk; + } +#endif // save normal hevc result uint32_t uiMRGIndex = pu.mergeIdx; bool bMergeFlag = pu.mergeFlag; @@ -2953,28 +4167,101 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) cHevcMvField[0].setMvField( pu.mv[REF_PIC_LIST_0], pu.refIdx[REF_PIC_LIST_0] ); cHevcMvField[1].setMvField( pu.mv[REF_PIC_LIST_1], pu.refIdx[REF_PIC_LIST_1] ); +#if GDR_ENABLED + bool cHevcMvFieldSolid[2]; + bool cHevcMvFieldValid[2]; + + if (isEncodeClean) + { + cHevcMvFieldSolid[0] = pu.mvSolid[0]; + cHevcMvFieldSolid[1] = pu.mvSolid[1]; + cHevcMvFieldValid[0] = pu.mvValid[0]; + cHevcMvFieldValid[1] = pu.mvValid[1]; + } +#endif + // do affine ME & Merge cu.affineType = AFFINEMODEL_4PARAM; Mv acMvAffine4Para[2][33][3]; +#if GDR_ENABLED + bool acMvAffine4ParaSolid[2][33][3]; + + for (int i = 0; i < 2; i++) + for (int j = 0; j < 33; j++) + for (int k = 0; k < 3; k++) + acMvAffine4ParaSolid[i][j][k] = true; +#endif int refIdx4Para[2] = { -1, -1 }; +#if GDR_ENABLED + xPredAffineInterSearch(pu, origBuf, puIdx, uiLastModeTemp, uiAffineCost, cMvHevcTemp, cMvHevcTempSolid, acMvAffine4Para, acMvAffine4ParaSolid, refIdx4Para, bcwIdx, enforceBcwPred, + ((cu.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0)); +#else xPredAffineInterSearch(pu, origBuf, puIdx, uiLastModeTemp, uiAffineCost, cMvHevcTemp, acMvAffine4Para, refIdx4Para, bcwIdx, enforceBcwPred, ((cu.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0)); +#endif if ( pu.cu->imv == 0 ) { +#if GDR_ENABLED + storeAffineMotion(pu.mvAffi, pu.mvAffiSolid, pu.refIdx, AFFINEMODEL_4PARAM, bcwIdx); +#else storeAffineMotion( pu.mvAffi, pu.refIdx, AFFINEMODEL_4PARAM, bcwIdx ); +#endif + } + +#if GDR_ENABLED + if (isEncodeClean) + { + uiAffineCostOk = true; + + if (pu.interDir & 0x01) + { + uiAffineCostOk = uiAffineCostOk && pu.mvAffiSolid[0][0] && pu.mvAffiSolid[0][1]; + uiAffineCostOk = uiAffineCostOk && pu.mvAffiValid[0][0] && pu.mvAffiValid[0][1]; + } + + if (pu.interDir & 0x02) + { + uiAffineCostOk = uiAffineCostOk && pu.mvAffiSolid[1][0] && pu.mvAffiSolid[1][1]; + uiAffineCostOk = uiAffineCostOk && pu.mvAffiValid[1][0] && pu.mvAffiValid[1][1]; + } } +#endif if ( cu.slice->getSPS()->getUseAffineType() ) { +#if GDR_ENABLED + allOk = (uiAffineCost < uiHevcCost * 1.05); + if (isEncodeClean) + { + if (uiAffineCostOk) + { + allOk = (uiHevcCostOk) ? (uiAffineCost < uiHevcCost * 1.05) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if ( uiAffineCost < uiHevcCost * 1.05 ) ///< condition for 6 parameter affine ME +#endif { // save 4 parameter results Mv bestMv[2][3], bestMvd[2][3]; int bestMvpIdx[2], bestMvpNum[2], bestRefIdx[2]; uint8_t bestInterDir; +#if GDR_ENABLED + bool bestMvSolid[2][3]; + bool bestMvValid[2][3]; +#endif + bestInterDir = pu.interDir; bestRefIdx[0] = pu.refIdx[0]; bestRefIdx[1] = pu.refIdx[1]; @@ -2991,6 +4278,19 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) bestMvd[refList][0] = pu.mvdAffi[refList][0]; bestMvd[refList][1] = pu.mvdAffi[refList][1]; bestMvd[refList][2] = pu.mvdAffi[refList][2]; + +#if GDR_ENABLED + if (isEncodeClean) + { + bestMvSolid[refList][0] = pu.mvAffiSolid[refList][0]; + bestMvSolid[refList][1] = pu.mvAffiSolid[refList][1]; + bestMvSolid[refList][2] = pu.mvAffiSolid[refList][2]; + + bestMvValid[refList][0] = pu.mvAffiValid[refList][0]; + bestMvValid[refList][1] = pu.mvAffiValid[refList][1]; + bestMvValid[refList][2] = pu.mvAffiValid[refList][2]; + } +#endif } refIdx4Para[0] = bestRefIdx[0]; @@ -2998,16 +4298,63 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) Distortion uiAffine6Cost = std::numeric_limits<Distortion>::max(); cu.affineType = AFFINEMODEL_6PARAM; +#if GDR_ENABLED + xPredAffineInterSearch(pu, origBuf, puIdx, uiLastModeTemp, uiAffine6Cost, cMvHevcTemp, cMvHevcTempSolid, acMvAffine4Para, acMvAffine4ParaSolid, refIdx4Para, bcwIdx, enforceBcwPred, + ((cu.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0)); +#else xPredAffineInterSearch(pu, origBuf, puIdx, uiLastModeTemp, uiAffine6Cost, cMvHevcTemp, acMvAffine4Para, refIdx4Para, bcwIdx, enforceBcwPred, ((cu.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0)); +#endif if ( pu.cu->imv == 0 ) { +#if GDR_ENABLED + storeAffineMotion(pu.mvAffi, pu.mvAffiSolid, pu.refIdx, AFFINEMODEL_6PARAM, bcwIdx); +#else storeAffineMotion( pu.mvAffi, pu.refIdx, AFFINEMODEL_6PARAM, bcwIdx ); +#endif + } + +#if GDR_ENABLED + if (isEncodeClean) + { + uiAffine6CostOk = true; + + if (pu.interDir & 0x01) + { + uiAffine6CostOk = uiAffine6CostOk && pu.mvAffiSolid[0][0] && pu.mvAffiSolid[0][1] && pu.mvAffiSolid[0][2]; + uiAffine6CostOk = uiAffine6CostOk && pu.mvAffiValid[0][0] && pu.mvAffiValid[0][1] && pu.mvAffiValid[0][2]; + } + + if (pu.interDir & 0x02) + { + uiAffine6CostOk = uiAffine6CostOk && pu.mvAffiSolid[1][0] && pu.mvAffiSolid[1][1] && pu.mvAffiSolid[1][2]; + uiAffine6CostOk = uiAffine6CostOk && pu.mvAffiValid[1][0] && pu.mvAffiValid[1][1] && pu.mvAffiValid[1][2]; + } + } +#endif + +#if GDR_ENABLED + allOk = (uiAffineCost <= uiAffine6Cost); + if (isEncodeClean) + { + if (uiAffineCostOk) + { + allOk = (uiAffine6CostOk) ? (uiAffineCost < uiHevcCost * 1.05) : true; + } + else + { + allOk = false; + } } +#endif // reset to 4 parameter affine inter mode +#if GDR_ENABLED + if (allOk && (uiAffineCost <= uiAffine6Cost)) +#else if ( uiAffineCost <= uiAffine6Cost ) +#endif { cu.affineType = AFFINEMODEL_4PARAM; pu.interDir = bestInterDir; @@ -3026,10 +4373,37 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) PU::setAllAffineMv( pu, bestMv[0][0], bestMv[0][1], bestMv[0][2], REF_PIC_LIST_0); PU::setAllAffineMv( pu, bestMv[1][0], bestMv[1][1], bestMv[1][2], REF_PIC_LIST_1); + +#if GDR_ENABLED + if (isEncodeClean) + { + pu.mvAffiSolid[REF_PIC_LIST_0][0] = bestMvSolid[REF_PIC_LIST_0][0]; + pu.mvAffiSolid[REF_PIC_LIST_0][1] = bestMvSolid[REF_PIC_LIST_0][1]; + pu.mvAffiSolid[REF_PIC_LIST_0][2] = bestMvSolid[REF_PIC_LIST_0][2]; + + pu.mvAffiValid[REF_PIC_LIST_0][0] = bestMvValid[REF_PIC_LIST_0][0]; + pu.mvAffiValid[REF_PIC_LIST_0][1] = bestMvValid[REF_PIC_LIST_0][1]; + pu.mvAffiValid[REF_PIC_LIST_0][2] = bestMvValid[REF_PIC_LIST_0][2]; + + pu.mvAffiSolid[REF_PIC_LIST_1][0] = bestMvSolid[REF_PIC_LIST_1][0]; + pu.mvAffiSolid[REF_PIC_LIST_1][1] = bestMvSolid[REF_PIC_LIST_1][1]; + pu.mvAffiSolid[REF_PIC_LIST_1][2] = bestMvSolid[REF_PIC_LIST_1][2]; + + pu.mvAffiValid[REF_PIC_LIST_1][0] = bestMvValid[REF_PIC_LIST_1][0]; + pu.mvAffiValid[REF_PIC_LIST_1][1] = bestMvValid[REF_PIC_LIST_1][1]; + pu.mvAffiValid[REF_PIC_LIST_1][2] = bestMvValid[REF_PIC_LIST_1][2]; + } +#endif } else { uiAffineCost = uiAffine6Cost; +#if GDR_ENABLED + if (isEncodeClean) + { + uiAffineCostOk = uiAffine6CostOk; + } +#endif } } @@ -3043,7 +4417,26 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) uiAffineCost = std::numeric_limits<Distortion>::max(); } } +#if GDR_ENABLED + allOk = (uiHevcCost <= uiAffineCost); + if (isEncodeClean) + { + if (uiHevcCostOk) + { + allOk = (uiAffineCostOk) ? (uiHevcCost <= uiAffineCost) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if ( uiHevcCost <= uiAffineCost ) +#endif { // set hevc me result cu.affine = false; @@ -3062,6 +4455,15 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner) pu.mvpNum[REF_PIC_LIST_1] = uiMvpNum[1]; pu.mvd[REF_PIC_LIST_0] = cMvd[0]; pu.mvd[REF_PIC_LIST_1] = cMvd[1]; +#if GDR_ENABLED + if (isEncodeClean) + { + pu.mvSolid[REF_PIC_LIST_0] = cHevcMvFieldSolid[0]; + pu.mvSolid[REF_PIC_LIST_1] = cHevcMvFieldSolid[1]; + pu.mvValid[REF_PIC_LIST_0] = cHevcMvFieldValid[0]; + pu.mvValid[REF_PIC_LIST_1] = cHevcMvFieldValid[1]; + } +#endif } else { @@ -3128,6 +4530,25 @@ void InterSearch::xEstimateMvPredAMVP( PredictionUnit& pu, PelUnitBuf& origBuf, int i; AMVPInfo* pcAMVPInfo = &rAMVPInfo; +#if GDR_ENABLED + const CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif + +#if GDR_ENABLED + if (isEncodeClean) + { + pcAMVPInfo->allCandSolidInAbove = true; + for (int i = 0; i < AMVP_MAX_NUM_CANDS_MEM; i++) + { + pcAMVPInfo->mvSolid[i] = true; + pcAMVPInfo->mvValid[i] = true; + } + } + + bool uiBestCostOk = false; + bool uiTmpCostOk = false; +#endif // Fill the MV Candidates if (!bFilled) @@ -3138,6 +4559,12 @@ void InterSearch::xEstimateMvPredAMVP( PredictionUnit& pu, PelUnitBuf& origBuf, // initialize Mvp index & Mvp iBestIdx = 0; cBestMv = pcAMVPInfo->mvCand[0]; +#if GDR_ENABLED + if (isEncodeClean) + { + uiBestCostOk = pcAMVPInfo->mvSolid[0]; + } +#endif PelUnitBuf predBuf = m_tmpStorageLCU.getBuf( UnitAreaRelative(*pu.cu, pu) ); @@ -3145,12 +4572,46 @@ void InterSearch::xEstimateMvPredAMVP( PredictionUnit& pu, PelUnitBuf& origBuf, for( i = 0 ; i < pcAMVPInfo->numCand; i++) { Distortion uiTmpCost = xGetTemplateCost( pu, origBuf, predBuf, pcAMVPInfo->mvCand[i], i, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx ); + +#if GDR_ENABLED + if (isEncodeClean) + { + uiTmpCostOk = pcAMVPInfo->mvSolid[i]; + } +#endif + +#if GDR_ENABLED + bool allOk = (uiBestCost > uiTmpCost); + + if (isEncodeClean) + { + if (uiBestCostOk) + { + allOk = (uiTmpCostOk) ? (uiBestCost > uiTmpCost) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if( uiBestCost > uiTmpCost ) +#endif { uiBestCost = uiTmpCost; cBestMv = pcAMVPInfo->mvCand[i]; iBestIdx = i; (*puiDistBiP) = uiTmpCost; +#if GDR_ENABLED + if (isEncodeClean) + { + uiBestCostOk = uiTmpCostOk; + } +#endif } } @@ -3159,6 +4620,13 @@ void InterSearch::xEstimateMvPredAMVP( PredictionUnit& pu, PelUnitBuf& origBuf, pu.mvpIdx[eRefPicList] = iBestIdx; pu.mvpNum[eRefPicList] = pcAMVPInfo->numCand; +#if GDR_ENABLED + if (isEncodeClean) + { + pu.mvpSolid[eRefPicList] = pcAMVPInfo->mvSolid[iBestIdx]; + } +#endif + return; } @@ -3203,11 +4671,28 @@ void InterSearch::xCopyAMVPInfo (AMVPInfo* pSrc, AMVPInfo* pDst) for (int i = 0; i < pSrc->numCand; i++) { pDst->mvCand[i] = pSrc->mvCand[i]; +#if GDR_ENABLED + pDst->mvPos[i] = pSrc->mvPos[i]; + pDst->mvSolid[i] = pSrc->mvSolid[i]; + pDst->mvValid[i] = pSrc->mvValid[i]; + pDst->mvType[i] = pSrc->mvType[i]; +#endif } } +#if GDR_ENABLED +void InterSearch::xCheckBestMVP(PredictionUnit &pu, RefPicList eRefPicList, Mv cMv, Mv& rcMvPred, int& riMVPIdx, AMVPInfo& amvpInfo, uint32_t& ruiBits, Distortion& ruiCost, const uint8_t imv) +#else void InterSearch::xCheckBestMVP ( RefPicList eRefPicList, Mv cMv, Mv& rcMvPred, int& riMVPIdx, AMVPInfo& amvpInfo, uint32_t& ruiBits, Distortion& ruiCost, const uint8_t imv ) +#endif { +#if GDR_ENABLED + const CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + bool iBestMvBitsOk = false; + bool iMvBitsOk = false; +#endif + if ( imv > 0 && imv < 3 ) { return; @@ -3234,6 +4719,12 @@ void InterSearch::xCheckBestMVP ( RefPicList eRefPicList, Mv cMv, Mv& rcMvPred, int iOrgMvBits = m_pcRdCost->getBitsOfVectorWithPredictor(mv.getHor(), mv.getVer(), 0); iOrgMvBits += m_auiMVPIdxCost[riMVPIdx][AMVP_MAX_NUM_CANDS]; int iBestMvBits = iOrgMvBits; +#if GDR_ENABLED + if (isEncodeClean) + { + iBestMvBitsOk = pcAMVPInfo->mvSolid[riMVPIdx]; + } +#endif for (int iMVPIdx = 0; iMVPIdx < pcAMVPInfo->numCand; iMVPIdx++) { @@ -3248,10 +4739,36 @@ void InterSearch::xCheckBestMVP ( RefPicList eRefPicList, Mv cMv, Mv& rcMvPred, int iMvBits = m_pcRdCost->getBitsOfVectorWithPredictor(mv.getHor(), mv.getVer(), 0); iMvBits += m_auiMVPIdxCost[iMVPIdx][AMVP_MAX_NUM_CANDS]; +#if GDR_ENABLED + bool allOk = (iMvBits < iBestMvBits); + if (isEncodeClean) + { + iMvBitsOk = pcAMVPInfo->mvSolid[iMVPIdx]; + if (iMvBitsOk) + { + allOk = (iBestMvBitsOk) ? (iMvBits < iBestMvBits) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if (iMvBits < iBestMvBits) +#endif { iBestMvBits = iMvBits; iBestMVPIdx = iMVPIdx; +#if GDR_ENABLED + if (isEncodeClean) + { + iBestMvBitsOk = iMvBitsOk; + } +#endif } } @@ -3300,7 +4817,11 @@ Distortion InterSearch::xGetTemplateCost( const PredictionUnit& pu, return uiCost; } +#if GDR_ENABLED +Distortion InterSearch::xGetAffineTemplateCost(PredictionUnit& pu, PelUnitBuf& origBuf, PelUnitBuf& predBuf, Mv acMvCand[3], int iMVPIdx, int iMVPNum, RefPicList eRefPicList, int iRefIdx, bool& rbOk) +#else Distortion InterSearch::xGetAffineTemplateCost( PredictionUnit& pu, PelUnitBuf& origBuf, PelUnitBuf& predBuf, Mv acMvCand[3], int iMVPIdx, int iMVPNum, RefPicList eRefPicList, int iRefIdx ) +#endif { Distortion uiCost = std::numeric_limits<Distortion>::max(); @@ -3311,7 +4832,12 @@ Distortion InterSearch::xGetAffineTemplateCost( PredictionUnit& pu, PelUnitBuf& Mv mv[3]; memcpy(mv, acMvCand, sizeof(mv)); m_iRefListIdx = eRefPicList; + +#if GDR_ENABLED + rbOk = xPredAffineBlk(COMPONENT_Y, pu, picRef, mv, predBuf, bi, pu.cu->slice->clpRng(COMPONENT_Y)); +#else xPredAffineBlk(COMPONENT_Y, pu, picRef, mv, predBuf, bi, pu.cu->slice->clpRng(COMPONENT_Y)); +#endif if( bi ) { xWeightedPredictionUni( pu, predBuf, eRefPicList, predBuf, iRefIdx, m_maxCompIDToPred ); @@ -3327,9 +4853,17 @@ Distortion InterSearch::xGetAffineTemplateCost( PredictionUnit& pu, PelUnitBuf& return uiCost; } +#if GDR_ENABLED +void InterSearch::xMotionEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, RefPicList eRefPicList, Mv& rcMvPred, int iRefIdxPred, Mv& rcMv, bool &rcMvSolid, int& riMVPIdx, uint32_t& ruiBits, Distortion& ruiCost, const AMVPInfo& amvpInfo, bool& rbCleanCandExist, bool bBi) +#else void InterSearch::xMotionEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, RefPicList eRefPicList, Mv& rcMvPred, int iRefIdxPred, Mv& rcMv, int& riMVPIdx, uint32_t& ruiBits, Distortion& ruiCost, const AMVPInfo& amvpInfo, bool bBi) +#endif { +#if GDR_ENABLED + if (pu.cu->cs->sps->getUseBcw() && pu.cu->BcwIdx != BCW_DEFAULT && !bBi && xReadBufferedUniMv(pu, eRefPicList, iRefIdxPred, rcMvPred, rcMv, rcMvSolid, ruiBits, ruiCost)) +#else if( pu.cu->cs->sps->getUseBcw() && pu.cu->BcwIdx != BCW_DEFAULT && !bBi && xReadBufferedUniMv(pu, eRefPicList, iRefIdxPred, rcMvPred, rcMv, ruiBits, ruiCost) ) +#endif { return; } @@ -3460,7 +4994,11 @@ void InterSearch::xMotionEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, Ref if( !bQTBTMV ) { +#if GDR_ENABLED + xSetSearchRange(pu, bestInitMv, iSrchRng, cStruct.searchRange, cStruct, eRefPicList, iRefIdxPred); +#else xSetSearchRange(pu, bestInitMv, iSrchRng, cStruct.searchRange, cStruct); +#endif } xPatternSearch( cStruct, rcMv, ruiCost); } @@ -3506,7 +5044,11 @@ void InterSearch::xMotionEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, Ref MCTSHelper::clipMvToArea( rcMv, pu.Y(), curTileAreaSubPelRestricted, *pu.cs->sps, 0 ); } } +#if GDR_ENABLED + xPatternSearchFracDIF(pu, eRefPicList, iRefIdxPred, cStruct, rcMv, cMvHalf, cMvQter, ruiCost, rbCleanCandExist); +#else xPatternSearchFracDIF( pu, eRefPicList, iRefIdxPred, cStruct, rcMv, cMvHalf, cMvQter, ruiCost ); +#endif m_pcRdCost->setCostScale( 0 ); rcMv <<= 2; rcMv += ( cMvHalf <<= 1 ); @@ -3519,7 +5061,11 @@ void InterSearch::xMotionEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, Ref else // integer refinement for integer-pel and 4-pel resolution { rcMv.changePrecision(MV_PRECISION_INT, MV_PRECISION_INTERNAL); +#if GDR_ENABLED + xPatternSearchIntRefine(pu, cStruct, rcMv, rcMvPred, riMVPIdx, ruiBits, ruiCost, amvpInfo, fWeight, eRefPicList, iRefIdxPred, rbCleanCandExist); +#else xPatternSearchIntRefine( pu, cStruct, rcMv, rcMvPred, riMVPIdx, ruiBits, ruiCost, amvpInfo, fWeight); +#endif } DTRACE(g_trace_ctx, D_ME, " MECost<L%d,%d>: %6d (%d) MV:%d,%d\n", (int)eRefPicList, (int)bBi, ruiCost, ruiBits, rcMv.getHor() << 2, rcMv.getVer() << 2); } @@ -3531,6 +5077,10 @@ void InterSearch::xSetSearchRange ( const PredictionUnit& pu, const int iSrchRng, SearchRange& sr , IntTZSearchStruct& cStruct +#if GDR_ENABLED + , RefPicList eRefPicList + , int iRefIdx +#endif ) { const int iMvShift = MV_FRACTIONAL_BITS_INTERNAL; @@ -3539,6 +5089,46 @@ void InterSearch::xSetSearchRange ( const PredictionUnit& pu, Mv mvTL(cFPMvPred.getHor() - (iSrchRng << iMvShift), cFPMvPred.getVer() - (iSrchRng << iMvShift)); Mv mvBR(cFPMvPred.getHor() + (iSrchRng << iMvShift), cFPMvPred.getVer() + (iSrchRng << iMvShift)); +#if GDR_ENABLED + bool isRefGdrPicture = pu.cs->slice->getRefPic(eRefPicList, iRefIdx)->cs->picHeader->getInGdrPeriod(); + if (isRefGdrPicture) + { + mvTL = { cFPMvPred.getHor(), cFPMvPred.getVer() }; + mvBR = { cFPMvPred.getHor(), cFPMvPred.getVer() }; + + const int lumaPixelAway = 4; + const int chromaPixelAway = 5; + + const Position LastPos = pu.Y().bottomRight(); + + const int iMvShift = MV_FRACTIONAL_BITS_INTERNAL; + const int iMvLumaFrac = (1 << iMvShift); + const int iMvChromaFrac = (iMvLumaFrac << 1); + const int iFracOne = (1 << iMvShift); + + const bool isIntLumaMv = (cFPMvPred.getHor() % iMvLumaFrac) == 0; + const bool isIntChromaMv = (cFPMvPred.getHor() % iMvChromaFrac) == 0; + + const int scaled_endx = pu.cs->slice->getRefPic(eRefPicList, iRefIdx)->cs->picHeader->getVirtualBoundariesPosX(0) << iMvShift; + + const Position OrigFracPos = Position(LastPos.x << iMvShift, LastPos.y << iMvShift); + const int last_luma_pos = ((OrigFracPos.x / iMvLumaFrac) * iMvLumaFrac) + cFPMvPred.getHor() + (isIntLumaMv ? 0 : (lumaPixelAway << iMvShift)); + const int last_chroma_pos = ((OrigFracPos.x / iMvChromaFrac) * iMvChromaFrac) + cFPMvPred.getHor() + (isIntChromaMv ? 0 : (chromaPixelAway << iMvShift)); + + const int last_pel_pos = std::max(last_luma_pos, last_chroma_pos); + + const int distance = Clip3(-(iSrchRng << iMvShift), (iSrchRng << iMvShift), scaled_endx - (last_pel_pos + iFracOne)); + + + int srLeft = cFPMvPred.getHor() - (iSrchRng << iMvShift); + int srRight = cFPMvPred.getHor() + distance; + int srTop = cFPMvPred.getVer() - (iSrchRng << iMvShift); + int srBottom = cFPMvPred.getVer() + (iSrchRng << iMvShift); + + mvTL = { srLeft, srTop }; + mvBR = { srRight, srBottom }; + } +#endif if (m_pcEncCfg->getMCTSEncConstraint()) { @@ -3703,6 +5293,10 @@ void InterSearch::xTZSearch( const PredictionUnit& pu, const uint32_t uiStarRefinementRounds = 2; // star refinement stop X rounds after best match (must be >=1) const bool bNewZeroNeighbourhoodTest = bExtendedSettings; +#if GDR_ENABLED + const CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif int iSearchRange = m_iSearchRange; if( m_pcEncCfg->getMCTSEncConstraint() ) { @@ -3789,6 +5383,37 @@ void InterSearch::xTZSearch( const PredictionUnit& pu, Distortion uiSad = m_cDistParam.distFunc(m_cDistParam); uiSad += m_pcRdCost->getCostOfVectorWithPredictor(cTmpMv.hor, cTmpMv.ver, cStruct.imvShift); +#if GDR_ENABLED + bool allOk = (uiSad < cStruct.uiBestSad); + + if (isEncodeClean) + { + Mv motion = cTmpMv; + motion.changePrecision(MV_PRECISION_INT, MV_PRECISION_INTERNAL); + bool cTmpMvOk = cs.isClean(pu.Y().bottomRight(), motion, eRefPicList, iRefIdxPred); + + Mv bestMv = { cStruct.iBestX, cStruct.iBestY }; + bestMv.changePrecision(MV_PRECISION_INT, MV_PRECISION_INTERNAL); + bool bestMvOk = cs.isClean(pu.Y().bottomRight(), bestMv, eRefPicList, iRefIdxPred); + + if (cTmpMvOk) + { + allOk = (bestMvOk) ? (uiSad < cStruct.uiBestSad) : true; + } + else + { + allOk = false; + } + } + + if (allOk) + { + cStruct.uiBestSad = uiSad; + cStruct.iBestX = cTmpMv.hor; + cStruct.iBestY = cTmpMv.ver; + m_cDistParam.maximumDistortionForEarlyExit = uiSad; + } +#else if (uiSad < cStruct.uiBestSad) { cStruct.uiBestSad = uiSad; @@ -3796,13 +5421,18 @@ void InterSearch::xTZSearch( const PredictionUnit& pu, cStruct.iBestY = cTmpMv.ver; m_cDistParam.maximumDistortionForEarlyExit = uiSad; } +#endif } { // set search range Mv currBestMv(cStruct.iBestX, cStruct.iBestY ); currBestMv <<= MV_FRACTIONAL_BITS_INTERNAL; +#if GDR_ENABLED + xSetSearchRange(pu, currBestMv, m_iSearchRange >> (bFastSettings ? 1 : 0), sr, cStruct, eRefPicList, iRefIdxPred); +#else xSetSearchRange(pu, currBestMv, m_iSearchRange >> (bFastSettings ? 1 : 0), sr, cStruct); +#endif } if (m_pcEncCfg->getUseHashME() && (m_currRefPicList == 0 || pu.cu->slice->getList1IdxToList0Idx(m_currRefPicIndex) < 0)) { @@ -4108,7 +5738,11 @@ void InterSearch::xTZSearchSelective( const PredictionUnit& pu, // set search range Mv currBestMv(cStruct.iBestX, cStruct.iBestY ); currBestMv <<= 2; +#if GDR_ENABLED + xSetSearchRange(pu, currBestMv, m_iSearchRange, sr, cStruct, eRefPicList, iRefIdxPred); +#else xSetSearchRange( pu, currBestMv, m_iSearchRange, sr, cStruct ); +#endif } if (m_pcEncCfg->getUseHashME() && (m_currRefPicList == 0 || pu.cu->slice->getList1IdxToList0Idx(m_currRefPicIndex) < 0)) { @@ -4205,8 +5839,16 @@ void InterSearch::xTZSearchSelective( const PredictionUnit& pu, ruiSAD = cStruct.uiBestSad - m_pcRdCost->getCostOfVectorWithPredictor( cStruct.iBestX, cStruct.iBestY, cStruct.imvShift ); } +#if GDR_ENABLED +void InterSearch::xPatternSearchIntRefine(PredictionUnit& pu, IntTZSearchStruct& cStruct, Mv& rcMv, Mv& rcMvPred, int& riMVPIdx, uint32_t& ruiBits, Distortion& ruiCost, const AMVPInfo& amvpInfo, double fWeight, RefPicList eRefPicList, int iRefIdxPred, bool& rbCleanCandExist) +#else void InterSearch::xPatternSearchIntRefine(PredictionUnit& pu, IntTZSearchStruct& cStruct, Mv& rcMv, Mv& rcMvPred, int& riMVPIdx, uint32_t& ruiBits, Distortion& ruiCost, const AMVPInfo& amvpInfo, double fWeight) +#endif { +#if GDR_ENABLED + const CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif CHECK( pu.cu->imv == 0 || pu.cu->imv == IMV_HPEL , "xPatternSearchIntRefine(): Sub-pel MV used."); CHECK( amvpInfo.mvCand[riMVPIdx] != rcMvPred, "xPatternSearchIntRefine(): MvPred issue."); @@ -4238,6 +5880,11 @@ void InterSearch::xPatternSearchIntRefine(PredictionUnit& pu, IntTZSearchStruct& cBaseMvd[1].roundTransPrecInternal2Amvr(pu.cu->imv); // test best integer position and all 8 neighboring positions +#if GDR_ENABLED + bool allOk = true; + bool uiDistOk = false; + bool uiBestDistOk = false; +#endif for (int pos = 0; pos < 9; pos ++) { Mv cTestMv[2]; @@ -4285,12 +5932,42 @@ void InterSearch::xPatternSearchIntRefine(PredictionUnit& pu, IntTZSearchStruct& iMvBits += m_pcRdCost->getBitsOfVectorWithPredictor( mv.getHor(), mv.getVer(), 0 ); uiDist += m_pcRdCost->getCost(iMvBits); +#if GDR_ENABLED + allOk = (uiDist < uiBestDist); + if (isEncodeClean) + { + bool isSolid = amvpInfo.mvSolid[iMVPIdx]; + bool isValid = cs.isClean(pu.Y().bottomRight(), cTestMv[iMVPIdx], eRefPicList, iRefIdxPred); + + uiDistOk = isSolid && isValid; + if (uiDistOk) + { + allOk = (uiBestDistOk) ? (uiDist < uiBestDist) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if (uiDist < uiBestDist) +#endif { uiBestDist = uiDist; cBestMv = cTestMv[iMVPIdx]; iBestMVPIdx = iMVPIdx; iBestBits = iMvBits; +#if GDR_ENABLED + if (isEncodeClean) + { + uiBestDistOk = uiDistOk; + rbCleanCandExist = true; + } +#endif } } } @@ -4326,6 +6003,9 @@ void InterSearch::xPatternSearchFracDIF( Mv& rcMvHalf, Mv& rcMvQter, Distortion& ruiCost +#if GDR_ENABLED + , bool& rbCleanCandExist +#endif ) { @@ -4339,7 +6019,11 @@ void InterSearch::xPatternSearchFracDIF( m_pcRdCost->setCostScale(0); xExtDIFUpSamplingH(&cPatternRoi, cStruct.useAltHpelIf); rcMvQter = rcMvInt; rcMvQter <<= 2; // for mv-cost +#if GDR_ENABLED + ruiCost = xPatternRefinement(pu, eRefPicList, iRefIdx, cStruct.pcPatternKey, baseRefMv, 1, rcMvQter, !pu.cs->slice->getDisableSATDForRD(), rbCleanCandExist); +#else ruiCost = xPatternRefinement(cStruct.pcPatternKey, baseRefMv, 1, rcMvQter, !pu.cs->slice->getDisableSATDForRD()); +#endif return; } @@ -4358,7 +6042,11 @@ void InterSearch::xPatternSearchFracDIF( rcMvHalf = rcMvInt; rcMvHalf <<= 1; // for mv-cost Mv baseRefMv(0, 0); +#if GDR_ENABLED + ruiCost = xPatternRefinement(pu, eRefPicList, iRefIdx, cStruct.pcPatternKey, baseRefMv, 2, rcMvHalf, (!pu.cs->slice->getDisableSATDForRD()), rbCleanCandExist); +#else ruiCost = xPatternRefinement(cStruct.pcPatternKey, baseRefMv, 2, rcMvHalf, (!pu.cs->slice->getDisableSATDForRD())); +#endif // quarter-pel refinement if (cStruct.imvShift == IMV_OFF) @@ -4370,9 +6058,11 @@ void InterSearch::xPatternSearchFracDIF( rcMvQter = rcMvInt; rcMvQter <<= 1; // for mv-cost - rcMvQter += rcMvHalf; - rcMvQter <<= 1; +#if GDR_ENABLED + ruiCost = xPatternRefinement(pu, eRefPicList, iRefIdx, cStruct.pcPatternKey, baseRefMv, 1, rcMvQter, (!pu.cs->slice->getDisableSATDForRD()), rbCleanCandExist); +#else ruiCost = xPatternRefinement(cStruct.pcPatternKey, baseRefMv, 1, rcMvQter, (!pu.cs->slice->getDisableSATDForRD())); +#endif } } @@ -4428,9 +6118,20 @@ Distortion InterSearch::xGetSymmetricCost( PredictionUnit& pu, PelUnitBuf& origB return(cost); } +#if GDR_ENABLED +Distortion InterSearch::xSymmeticRefineMvSearch( PredictionUnit &pu, PelUnitBuf& origBuf, Mv& rcMvCurPred, Mv& rcMvTarPred + , RefPicList eRefPicList, MvField& rCurMvField, MvField& rTarMvField, Distortion uiMinCost, int SearchPattern, int nSearchStepShift, uint32_t uiMaxSearchRounds, int bcwIdx, bool& rOk) +#else Distortion InterSearch::xSymmeticRefineMvSearch( PredictionUnit &pu, PelUnitBuf& origBuf, Mv& rcMvCurPred, Mv& rcMvTarPred , RefPicList eRefPicList, MvField& rCurMvField, MvField& rTarMvField, Distortion uiMinCost, int SearchPattern, int nSearchStepShift, uint32_t uiMaxSearchRounds, int bcwIdx ) +#endif { +#if GDR_ENABLED + const CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + bool uiCostOk; + bool uiMinCostOk = rOk; +#endif const Mv mvSearchOffsetCross[4] = { Mv( 0 , 1 ) , Mv( 1 , 0 ) , Mv( 0 , -1 ) , Mv( -1 , 0 ) }; const Mv mvSearchOffsetSquare[8] = { Mv( -1 , 1 ) , Mv( 0 , 1 ) , Mv( 1 , 1 ) , Mv( 1 , 0 ) , Mv( 1 , -1 ) , Mv( 0 , -1 ) , Mv( -1 , -1 ) , Mv( -1 , 0 ) }; const Mv mvSearchOffsetDiamond[8] = { Mv( 0 , 2 ) , Mv( 1 , 1 ) , Mv( 2 , 0 ) , Mv( 1 , -1 ) , Mv( 0 , -2 ) , Mv( -1 , -1 ) , Mv( -2 , 0 ) , Mv( -1 , 1 ) }; @@ -4506,6 +6207,10 @@ Distortion InterSearch::xSymmeticRefineMvSearch( PredictionUnit &pu, PelUnitBuf& uint32_t uiMvBits = m_pcRdCost->getBitsOfVectorWithPredictor( mv.getHor(), mv.getVer(), 0 ); Distortion uiCost = m_pcRdCost->getCost( uiMvBits ); +#if GDR_ENABLED + uiCostOk = cs.isClean(pu.Y().bottomRight(), mvCand.mv, eRefPicList, mvCand.refIdx); +#endif + // get MVD pair and set target MV mvPair.refIdx = rTarMvField.refIdx; mvPair.mv.set( rcMvTarPred.hor - (mvCand.mv.hor - rcMvCurPred.hor), rcMvTarPred.ver - (mvCand.mv.ver - rcMvCurPred.ver) ); @@ -4515,12 +6220,33 @@ Distortion InterSearch::xSymmeticRefineMvSearch( PredictionUnit &pu, PelUnitBuf& continue; // Skip this this pos } uiCost += xGetSymmetricCost( pu, origBuf, eRefPicList, mvCand, mvPair, bcwIdx ); + +#if GDR_ENABLED + bool allOk = (uiCost < uiMinCost); + if (isEncodeClean) + { + bool curValid = cs.isClean(pu.Y().bottomRight(), mvCand.mv, (RefPicList)(eRefPicList), mvCand.refIdx); + bool tarValid = cs.isClean(pu.Y().bottomRight(), mvPair.mv, (RefPicList)(1 - eRefPicList), mvPair.refIdx); + allOk = curValid && tarValid; + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if ( uiCost < uiMinCost ) +#endif { uiMinCost = uiCost; rCurMvField = mvCand; rTarMvField = mvPair; nBestDirect = nDirect; +#if GDR_ENABLED + if (isEncodeClean) + { + uiMinCostOk = uiCostOk; + } +#endif } } @@ -4537,11 +6263,19 @@ Distortion InterSearch::xSymmeticRefineMvSearch( PredictionUnit &pu, PelUnitBuf& nDirectEnd = nBestDirect + nStep; } +#if GDR_ENABLED + rOk = uiMinCostOk; +#endif + return(uiMinCost); } +#if GDR_ENABLED +bool InterSearch::xSymmetricMotionEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, Mv& rcMvCurPred, Mv& rcMvTarPred, RefPicList eRefPicList, MvField& rCurMvField, MvField& rTarMvField, Distortion& ruiCost, int bcwIdx, bool& ruiCostOk) +#else void InterSearch::xSymmetricMotionEstimation( PredictionUnit& pu, PelUnitBuf& origBuf, Mv& rcMvCurPred, Mv& rcMvTarPred, RefPicList eRefPicList, MvField& rCurMvField, MvField& rTarMvField, Distortion& ruiCost, int bcwIdx ) +#endif { // Refine Search int nSearchStepShift = MV_FRACTIONAL_BITS_DIFF; @@ -4551,8 +6285,17 @@ void InterSearch::xSymmetricMotionEstimation( PredictionUnit& pu, PelUnitBuf& or nSearchStepShift += pu.cu->imv == IMV_HPEL ? 1 : (pu.cu->imv << 1); nDiamondRound >>= pu.cu->imv; +#if GDR_ENABLED + ruiCost = xSymmeticRefineMvSearch(pu, origBuf, rcMvCurPred, rcMvTarPred, eRefPicList, rCurMvField, rTarMvField, ruiCost, 2, nSearchStepShift, nDiamondRound, bcwIdx, ruiCostOk); + ruiCost = xSymmeticRefineMvSearch(pu, origBuf, rcMvCurPred, rcMvTarPred, eRefPicList, rCurMvField, rTarMvField, ruiCost, 0, nSearchStepShift, nCrossRound, bcwIdx, ruiCostOk); +#else ruiCost = xSymmeticRefineMvSearch( pu, origBuf, rcMvCurPred, rcMvTarPred, eRefPicList, rCurMvField, rTarMvField, ruiCost, 2, nSearchStepShift, nDiamondRound, bcwIdx ); ruiCost = xSymmeticRefineMvSearch( pu, origBuf, rcMvCurPred, rcMvTarPred, eRefPicList, rCurMvField, rTarMvField, ruiCost, 0, nSearchStepShift, nCrossRound, bcwIdx ); +#endif + +#if GDR_ENABLED + return ruiCostOk; +#endif } void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, @@ -4561,7 +6304,13 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, uint32_t& lastMode, Distortion& affineCost, Mv hevcMv[2][33] +#if GDR_ENABLED + , bool hevcMvSolid[2][33] +#endif , Mv mvAffine4Para[2][33][3] +#if GDR_ENABLED + , bool mvAffine4ParaSolid[2][33][3] +#endif , int refIdx4Para[2] , uint8_t bcwIdx , bool enforceBcwPred @@ -4589,6 +6338,27 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, int aaiMvpIdx[2][33]; int aaiMvpNum[2][33]; +#if GDR_ENABLED + bool aacMvSolid[2][3]; + bool aacMvValid[2][3]; + + bool cMvTempSolid[2][33][3]; + bool cMvTempValid[2][33][3]; + + bool cMvBiSolid[2][3]; + bool cMvBiValid[2][3]; + + bool cMvPredSolid[2][33][3]; + bool cMvPredBiSolid[2][33][3]; + + bool mvValidList1Solid[3]; + bool mvValidList1Valid[3]; + + bool mvHevcSolid[3]; + + const CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif AffineAMVPInfo aacAffineAMVPInfo[2][33]; AffineAMVPInfo affiAMVPInfoTemp[2]; @@ -4603,9 +6373,67 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, int bestBiPMvpL1 = 0; Distortion biPDistTemp = std::numeric_limits<Distortion>::max(); +#if GDR_ENABLED + bool init_value = true; + + bool allOk = true; + bool biPDistTempOk = init_value; + bool bestBiPDistOk = init_value; + + + // if (isEncodeClean) + { + memset(mvHevcSolid, init_value, sizeof(mvHevcSolid)); + + // note : will have Solid problem if initialize to true + memset(aacMvSolid, false, sizeof(aacMvSolid)); + memset(aacMvValid, false, sizeof(aacMvValid)); + + memset(cMvBiSolid, init_value, sizeof(cMvBiSolid)); + memset(cMvBiValid, init_value, sizeof(cMvBiValid)); + + memset(cMvTempSolid, init_value, sizeof(cMvTempSolid)); + memset(cMvTempValid, init_value, sizeof(cMvTempValid)); + + memset(mvValidList1Solid, init_value, sizeof(mvValidList1Solid)); + memset(mvValidList1Valid, init_value, sizeof(mvValidList1Valid)); + + // AffineAMVPInfo aacAffineAMVPInfo[2][33]; + ::memset(aacAffineAMVPInfo, 0, sizeof(aacAffineAMVPInfo)); + ::memset(affiAMVPInfoTemp, 0, sizeof(affiAMVPInfoTemp)); + + for (int i = 0; i < 2; i++) + { + for (int j = 0; j < 33; j++) + { + for (int k = 0; k < AMVP_MAX_NUM_CANDS_MEM; k++) + { + aacAffineAMVPInfo[i][j].mvSolidLT[k] = init_value; + aacAffineAMVPInfo[i][j].mvSolidRT[k] = init_value; + aacAffineAMVPInfo[i][j].mvSolidLB[k] = init_value; + } + } + + for (int k = 0; k < AMVP_MAX_NUM_CANDS_MEM; k++) + { + affiAMVPInfoTemp[i].mvSolidLT[k] = init_value; + affiAMVPInfoTemp[i].mvSolidRT[k] = init_value; + affiAMVPInfoTemp[i].mvSolidLB[k] = init_value; + } + } + } + + bool bAnyClean = false; +#endif + Distortion uiCost[2] = { std::numeric_limits<Distortion>::max(), std::numeric_limits<Distortion>::max() }; Distortion uiCostBi = std::numeric_limits<Distortion>::max(); Distortion uiCostTemp; +#if GDR_ENABLED + bool uiCostOk[2] = { init_value, init_value }; + bool uiCostBiOk = init_value; + bool uiCostTempOk = init_value; +#endif uint32_t uiBits[3] = { 0 }; uint32_t uiBitsTemp; @@ -4616,12 +6444,24 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, { uiCostTempL0[iNumRef] = std::numeric_limits<Distortion>::max(); } + +#if GDR_ENABLED + bool uiCostTempL0Ok[MAX_NUM_REF]; + for (int iNumRef = 0; iNumRef < MAX_NUM_REF; iNumRef++) + { + uiCostTempL0Ok[iNumRef] = true; + } +#endif + uint32_t uiBitsTempL0[MAX_NUM_REF]; Mv mvValidList1[4]; int refIdxValidList1 = 0; uint32_t bitsValidList1 = MAX_UINT; Distortion costValidList1 = std::numeric_limits<Distortion>::max(); +#if GDR_ENABLED + bool costValidList1Ok = true; +#endif Mv mvHevc[3]; const bool affineAmvrEnabled = pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag(); int tryBipred = 0; @@ -4663,6 +6503,21 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, } aaiMvpIdx[iRefList][iRefIdxTemp] = pu.mvpIdx[eRefPicList]; aaiMvpNum[iRefList][iRefIdxTemp] = pu.mvpNum[eRefPicList];; + +#if GDR_ENABLED + if (isEncodeClean) + { + int mvpIdx = aaiMvpIdx[iRefList][iRefIdxTemp]; + cMvPredSolid[iRefList][iRefIdxTemp][0] = affiAMVPInfoTemp[eRefPicList].mvSolidLT[mvpIdx]; + cMvPredSolid[iRefList][iRefIdxTemp][1] = affiAMVPInfoTemp[eRefPicList].mvSolidRT[mvpIdx]; + cMvPredSolid[iRefList][iRefIdxTemp][2] = affiAMVPInfoTemp[eRefPicList].mvSolidLB[mvpIdx]; + + biPDistTempOk = true; + biPDistTempOk = biPDistTempOk && affiAMVPInfoTemp[eRefPicList].mvSolidLT[mvpIdx] && affiAMVPInfoTemp[eRefPicList].mvSolidRT[mvpIdx]; + biPDistTempOk = biPDistTempOk && ((mvNum > 2) ? affiAMVPInfoTemp[eRefPicList].mvSolidLB[mvpIdx] : true); + } +#endif + if ( pu.cu->affineType == AFFINEMODEL_6PARAM && refIdx4Para[iRefList] != iRefIdxTemp ) { xCopyAffineAMVPInfo( affiAMVPInfoTemp[eRefPicList], aacAffineAMVPInfo[iRefList][iRefIdxTemp] ); @@ -4674,11 +6529,26 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, { mvHevc[i] = hevcMv[iRefList][iRefIdxTemp]; mvHevc[i].roundAffinePrecInternal2Amvr(pu.cu->imv); + +#if GDR_ENABLED + if (isEncodeClean) + { + mvHevcSolid[i] = hevcMvSolid[iRefList][iRefIdxTemp]; + } +#endif } PelUnitBuf predBuf = m_tmpStorageLCU.getBuf( UnitAreaRelative(*pu.cu, pu) ); +#if GDR_ENABLED + bool uiCandCostOk = true; + Distortion uiCandCost = xGetAffineTemplateCost(pu, origBuf, predBuf, mvHevc, aaiMvpIdx[iRefList][iRefIdxTemp], + AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdxTemp, uiCandCostOk); + uiCandCostOk = uiCandCostOk && mvHevcSolid[0] && mvHevcSolid[1] && ((mvNum > 2) ? mvHevcSolid[2] : true); + +#else Distortion uiCandCost = xGetAffineTemplateCost(pu, origBuf, predBuf, mvHevc, aaiMvpIdx[iRefList][iRefIdxTemp], AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdxTemp); +#endif if ( affineAmvrEnabled ) { @@ -4693,19 +6563,58 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, if ( savedParaAvail ) { Mv mvFour[3]; +#if GDR_ENABLED + bool mvFourSolid[3] = { true, true, true }; +#endif for ( int i = 0; i < mvNum; i++ ) { mvFour[i] = affine4Para ? m_affineMotion.acMvAffine4Para[iRefList][i] : m_affineMotion.acMvAffine6Para[iRefList][i]; mvFour[i].roundAffinePrecInternal2Amvr(pu.cu->imv); +#if GDR_ENABLED + mvFourSolid[i] = affine4Para ? m_affineMotion.acMvAffine4ParaSolid[iRefList][i] : m_affineMotion.acMvAffine6ParaSolid[iRefList][i]; +#endif } +#if GDR_ENABLED + bool candCostInheritOk = true; + Distortion candCostInherit = xGetAffineTemplateCost(pu, origBuf, predBuf, mvFour, aaiMvpIdx[iRefList][iRefIdxTemp], AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdxTemp, candCostInheritOk); + + candCostInheritOk = candCostInheritOk && mvFourSolid[0] && mvFourSolid[1] && ((mvNum > 2) ? mvFourSolid[2] : true); +#else Distortion candCostInherit = xGetAffineTemplateCost( pu, origBuf, predBuf, mvFour, aaiMvpIdx[iRefList][iRefIdxTemp], AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdxTemp ); +#endif candCostInherit += m_pcRdCost->getCost( xCalcAffineMVBits( pu, mvFour, cMvPred[iRefList][iRefIdxTemp] ) ); +#if GDR_ENABLED + allOk = (candCostInherit < uiCandCost); + if (isEncodeClean) + { + if (candCostInheritOk) + { + allOk = (uiCandCostOk) ? (candCostInherit < uiCandCost) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if ( candCostInherit < uiCandCost ) +#endif { uiCandCost = candCostInherit; memcpy( mvHevc, mvFour, 3 * sizeof( Mv ) ); +#if GDR_ENABLED + if (isEncodeClean) + { + uiCandCostOk = candCostInheritOk; + memcpy(mvHevcSolid, mvFourSolid, 3 * sizeof(bool)); + } +#endif } } @@ -4717,6 +6626,10 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, for (int i = 0; i < m_affMVListSize; i++) { AffineMVInfo *mvInfo = m_affMVList + ((m_affMVListIdx - i - 1 + m_affMVListMaxSize) % (m_affMVListMaxSize)); +#if GDR_ENABLED + AffineMVInfoSolid *mvInfoSolid = m_affMVListSolid + ((m_affMVListIdx - i - 1 + m_affMVListMaxSize) % (m_affMVListMaxSize)); +#endif + //check; int j = 0; for (; j < i; j++) @@ -4737,6 +6650,12 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, } Mv mvTmp[3], *nbMv = mvInfo->affMVs[iRefList][iRefIdxTemp]; +#if GDR_ENABLED + bool mvTmpSolid[3]; + bool *nbMvSolid = mvInfoSolid->affMVsSolid[iRefList][iRefIdxTemp]; + mvTmpSolid[0] = nbMvSolid[0]; + mvTmpSolid[1] = nbMvSolid[1]; +#endif int vx, vy; int dMvHorX, dMvHorY, dMvVerX, dMvVerY; int mvScaleHor = nbMv[0].getHor() << shift; @@ -4761,15 +6680,48 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, clipMv( mvTmp[1], pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps, *pu.cs->pps ); mvTmp[0].roundAffinePrecInternal2Amvr(pu.cu->imv); mvTmp[1].roundAffinePrecInternal2Amvr(pu.cu->imv); + +#if GDR_ENABLED + bool tmpCostOk = true; + Distortion tmpCost = xGetAffineTemplateCost(pu, origBuf, predBuf, mvTmp, aaiMvpIdx[iRefList][iRefIdxTemp], AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdxTemp, tmpCostOk); + tmpCostOk = tmpCostOk && mvTmpSolid[0] && mvTmpSolid[1]; +#else Distortion tmpCost = xGetAffineTemplateCost(pu, origBuf, predBuf, mvTmp, aaiMvpIdx[iRefList][iRefIdxTemp], AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdxTemp); +#endif if ( affineAmvrEnabled ) { tmpCost += m_pcRdCost->getCost( xCalcAffineMVBits( pu, mvTmp, cMvPred[iRefList][iRefIdxTemp] ) ); } +#if GDR_ENABLED + allOk = (tmpCost < uiCandCost); + if (isEncodeClean) + { + if (tmpCostOk) + { + allOk = (uiCandCostOk) ? (tmpCost < uiCandCost) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if (tmpCost < uiCandCost) +#endif { uiCandCost = tmpCost; std::memcpy(mvHevc, mvTmp, 3 * sizeof(Mv)); +#if GDR_ENABLED + if (isEncodeClean) + { + uiCandCostOk = tmpCostOk; + std::memset(mvHevcSolid, true, 3 * sizeof(bool)); + } +#endif } } } @@ -4778,6 +6730,12 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, Mv mvFour[3]; mvFour[0] = mvAffine4Para[iRefList][iRefIdxTemp][0]; mvFour[1] = mvAffine4Para[iRefList][iRefIdxTemp][1]; +#if GDR_ENABLED + bool mvFourSolid[3]; + mvFourSolid[0] = mvAffine4ParaSolid[iRefList][iRefIdxTemp][0]; + mvFourSolid[1] = mvAffine4ParaSolid[iRefList][iRefIdxTemp][1]; +#endif + mvAffine4Para[iRefList][iRefIdxTemp][0].roundAffinePrecInternal2Amvr(pu.cu->imv); mvAffine4Para[iRefList][iRefIdxTemp][1].roundAffinePrecInternal2Amvr(pu.cu->imv); @@ -4793,36 +6751,134 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, mvFour[0].roundAffinePrecInternal2Amvr(pu.cu->imv); mvFour[1].roundAffinePrecInternal2Amvr(pu.cu->imv); mvFour[2].roundAffinePrecInternal2Amvr(pu.cu->imv); + +#if GDR_ENABLED + bool uiCandCostInheritOk = true; + Distortion uiCandCostInherit = xGetAffineTemplateCost(pu, origBuf, predBuf, mvFour, aaiMvpIdx[iRefList][iRefIdxTemp], AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdxTemp, uiCandCostInheritOk); + uiCandCostInheritOk = uiCandCostInheritOk && mvFourSolid[0] && mvFourSolid[1]; +#else Distortion uiCandCostInherit = xGetAffineTemplateCost( pu, origBuf, predBuf, mvFour, aaiMvpIdx[iRefList][iRefIdxTemp], AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdxTemp ); +#endif + if ( affineAmvrEnabled ) { uiCandCostInherit += m_pcRdCost->getCost( xCalcAffineMVBits( pu, mvFour, cMvPred[iRefList][iRefIdxTemp] ) ); } +#if GDR_ENABLED + allOk = (uiCandCostInherit < uiCandCost); + + if (isEncodeClean) + { + if (uiCandCostInheritOk) + { + allOk = (uiCandCostOk) ? (uiCandCostInherit < uiCandCost) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if ( uiCandCostInherit < uiCandCost ) +#endif { uiCandCost = uiCandCostInherit; for ( int i = 0; i < 3; i++ ) { mvHevc[i] = mvFour[i]; +#if GDR_ENABLED + if (isEncodeClean) + { + uiCandCostOk = uiCandCostInheritOk; + mvHevcSolid[i] = true; + } +#endif } } } + +#if GDR_ENABLED + allOk = (uiCandCost < biPDistTemp); + + if (isEncodeClean) + { + if (uiCandCostOk) + { + allOk = (biPDistTempOk) ? (uiCandCost < biPDistTemp) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if ( uiCandCost < biPDistTemp ) +#endif { ::memcpy( cMvTemp[iRefList][iRefIdxTemp], mvHevc, sizeof(Mv)*3 ); +#if GDR_ENABLED + if (isEncodeClean) + { + cMvTempSolid[iRefList][iRefIdxTemp][0] = mvHevcSolid[0]; + cMvTempSolid[iRefList][iRefIdxTemp][1] = mvHevcSolid[1]; + cMvTempSolid[iRefList][iRefIdxTemp][2] = mvHevcSolid[2]; + } +#endif } else { ::memcpy( cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], sizeof(Mv)*3 ); +#if GDR_ENABLED + if (isEncodeClean) + { + cMvTempSolid[iRefList][iRefIdxTemp][0] = cMvPredSolid[iRefList][iRefIdxTemp][0]; + cMvTempSolid[iRefList][iRefIdxTemp][1] = cMvPredSolid[iRefList][iRefIdxTemp][1]; + cMvTempSolid[iRefList][iRefIdxTemp][2] = cMvPredSolid[iRefList][iRefIdxTemp][2]; + } +#endif } // GPB list 1, save the best MvpIdx, RefIdx and Cost +#if GDR_ENABLED + allOk = (slice.getPicHeader()->getMvdL1ZeroFlag() && iRefList == 1 && (biPDistTemp < bestBiPDist)); + + if (isEncodeClean) + { + if (biPDistTempOk) + { + allOk = (bestBiPDistOk) ? (slice.getPicHeader()->getMvdL1ZeroFlag() && iRefList == 1 && (biPDistTemp < bestBiPDist)) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if ( slice.getPicHeader()->getMvdL1ZeroFlag() && iRefList==1 && biPDistTemp < bestBiPDist ) +#endif { bestBiPDist = biPDistTemp; bestBiPMvpL1 = aaiMvpIdx[iRefList][iRefIdxTemp]; bestBiPRefIdxL1 = iRefIdxTemp; +#if GDR_ENABLED + if (isEncodeClean) + { + bestBiPDistOk = biPDistTempOk; + } +#endif } // Update bits @@ -4834,6 +6890,13 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, { int iList1ToList0Idx = slice.getList1IdxToList0Idx( iRefIdxTemp ); ::memcpy( cMvTemp[1][iRefIdxTemp], cMvTemp[0][iList1ToList0Idx], sizeof(Mv)*3 ); +#if GDR_ENABLED + if (isEncodeClean) + { + ::memcpy(cMvTempSolid[1][iRefIdxTemp], cMvTempSolid[0][iList1ToList0Idx], sizeof(bool) * 3); + uiCostTempOk = uiCostTempL0Ok[iList1ToList0Idx]; + } +#endif uiCostTemp = uiCostTempL0[iList1ToList0Idx]; uiCostTemp -= m_pcRdCost->getCost( uiBitsTempL0[iList1ToList0Idx] ); @@ -4844,52 +6907,249 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, } else { +#if GDR_ENABLED + xAffineMotionEstimation(pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], cMvTempSolid[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp + , aaiMvpIdx[iRefList][iRefIdxTemp], affiAMVPInfoTemp[eRefPicList], bAnyClean +#else xAffineMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp , aaiMvpIdx[iRefList][iRefIdxTemp], affiAMVPInfoTemp[eRefPicList] +#endif ); + +#if GDR_ENABLED + if (isEncodeClean) + { + int mvp_idx = aaiMvpIdx[iRefList][iRefIdxTemp]; + PelUnitBuf tmpBuf = m_tmpAffiStorage.getBuf(UnitAreaRelative(*pu.cu, pu)); + const Picture *refPic = pu.cu->slice->getRefPic((RefPicList)iRefList, iRefIdxTemp); + + + cMvPredSolid[iRefList][iRefIdxTemp][0] = affiAMVPInfoTemp[eRefPicList].mvSolidLT[mvp_idx]; + cMvPredSolid[iRefList][iRefIdxTemp][1] = affiAMVPInfoTemp[eRefPicList].mvSolidRT[mvp_idx]; + cMvPredSolid[iRefList][iRefIdxTemp][2] = affiAMVPInfoTemp[eRefPicList].mvSolidLB[mvp_idx]; + + cMvTempSolid[iRefList][iRefIdxTemp][0] = cMvPredSolid[iRefList][iRefIdxTemp][0]; + cMvTempSolid[iRefList][iRefIdxTemp][1] = cMvPredSolid[iRefList][iRefIdxTemp][1]; + cMvTempSolid[iRefList][iRefIdxTemp][2] = cMvPredSolid[iRefList][iRefIdxTemp][2]; + + bool isSubPuYYClean = xPredAffineBlk(COMPONENT_Y, pu, refPic, cMvTemp[iRefList][iRefIdxTemp], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); + bool isSubPuCbClean = (isSubPuYYClean) ? xPredAffineBlk(COMPONENT_Cb, pu, refPic, cMvTemp[iRefList][iRefIdxTemp], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Cb)) : false; + + cMvTempValid[iRefList][iRefIdxTemp][0] = isSubPuYYClean && isSubPuCbClean; + cMvTempValid[iRefList][iRefIdxTemp][1] = isSubPuYYClean && isSubPuCbClean; + cMvTempValid[iRefList][iRefIdxTemp][2] = isSubPuYYClean && isSubPuCbClean; + + uiCostTempOk = true; + uiCostTempOk = uiCostTempOk && cMvPredSolid[iRefList][iRefIdxTemp][0] && cMvPredSolid[iRefList][iRefIdxTemp][1]; + uiCostTempOk = uiCostTempOk && ((mvNum > 2) ? cMvPredSolid[iRefList][iRefIdxTemp][2] : true); + uiCostTempOk = uiCostTempOk && cMvTempSolid[iRefList][iRefIdxTemp][0] && cMvTempSolid[iRefList][iRefIdxTemp][1] && ((mvNum > 2) ? cMvTempSolid[iRefList][iRefIdxTemp][2] : true); + uiCostTempOk = uiCostTempOk && cMvTempValid[iRefList][iRefIdxTemp][0] && cMvTempValid[iRefList][iRefIdxTemp][1] && ((mvNum > 2) ? cMvTempValid[iRefList][iRefIdxTemp][2] : true); + } +#endif } } else { +#if GDR_ENABLED + xAffineMotionEstimation(pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], cMvTempSolid[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp + , aaiMvpIdx[iRefList][iRefIdxTemp], affiAMVPInfoTemp[eRefPicList], bAnyClean + ); +#else xAffineMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp , aaiMvpIdx[iRefList][iRefIdxTemp], affiAMVPInfoTemp[eRefPicList] ); +#endif + +#if GDR_ENABLED + if (isEncodeClean) + { + int mvp_idx = aaiMvpIdx[iRefList][iRefIdxTemp]; + PelUnitBuf tmpBuf = m_tmpAffiStorage.getBuf(UnitAreaRelative(*pu.cu, pu)); + const Picture *refPic = pu.cu->slice->getRefPic((RefPicList)iRefList, iRefIdxTemp); + + cMvPredSolid[iRefList][iRefIdxTemp][0] = affiAMVPInfoTemp[eRefPicList].mvSolidLT[mvp_idx]; + cMvPredSolid[iRefList][iRefIdxTemp][1] = affiAMVPInfoTemp[eRefPicList].mvSolidRT[mvp_idx]; + cMvPredSolid[iRefList][iRefIdxTemp][2] = affiAMVPInfoTemp[eRefPicList].mvSolidLB[mvp_idx]; + + cMvTempSolid[iRefList][iRefIdxTemp][0] = cMvPredSolid[iRefList][iRefIdxTemp][0]; + cMvTempSolid[iRefList][iRefIdxTemp][1] = cMvPredSolid[iRefList][iRefIdxTemp][1]; + cMvTempSolid[iRefList][iRefIdxTemp][2] = cMvPredSolid[iRefList][iRefIdxTemp][2]; + + bool isSubPuYYClean = xPredAffineBlk(COMPONENT_Y, pu, refPic, cMvTemp[iRefList][iRefIdxTemp], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); + bool isSubPuCbClean = (isSubPuYYClean) ? xPredAffineBlk(COMPONENT_Cb, pu, refPic, cMvTemp[iRefList][iRefIdxTemp], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Cb)) : false; + + cMvTempValid[iRefList][iRefIdxTemp][0] = isSubPuYYClean && isSubPuCbClean; + cMvTempValid[iRefList][iRefIdxTemp][1] = isSubPuYYClean && isSubPuCbClean; + cMvTempValid[iRefList][iRefIdxTemp][2] = isSubPuYYClean && isSubPuCbClean; + + uiCostTempOk = true; + uiCostTempOk = uiCostTempOk && cMvPredSolid[iRefList][iRefIdxTemp][0] && cMvPredSolid[iRefList][iRefIdxTemp][1]; + uiCostTempOk = uiCostTempOk && ((mvNum > 2) ? cMvPredSolid[iRefList][iRefIdxTemp][2] : true); + uiCostTempOk = uiCostTempOk && cMvTempSolid[iRefList][iRefIdxTemp][0] && cMvTempSolid[iRefList][iRefIdxTemp][1] && ((mvNum > 2) ? cMvTempSolid[iRefList][iRefIdxTemp][2] : true); + uiCostTempOk = uiCostTempOk && cMvTempValid[iRefList][iRefIdxTemp][0] && cMvTempValid[iRefList][iRefIdxTemp][1] && ((mvNum > 2) ? cMvTempValid[iRefList][iRefIdxTemp][2] : true); + } +#endif } if(pu.cu->cs->sps->getUseBcw() && pu.cu->BcwIdx == BCW_DEFAULT && pu.cu->slice->isInterB()) { m_uniMotions.setReadModeAffine(true, (uint8_t)iRefList, (uint8_t)iRefIdxTemp, pu.cu->affineType); +#if GDR_ENABLED + if (isEncodeClean) + { + m_uniMotions.copyAffineMvFrom( + cMvTemp[iRefList][iRefIdxTemp], + cMvTempSolid[iRefList][iRefIdxTemp], + uiCostTemp - m_pcRdCost->getCost(uiBitsTemp), + (uint8_t)iRefList, + (uint8_t)iRefIdxTemp, + pu.cu->affineType, + aaiMvpIdx[iRefList][iRefIdxTemp] + ); + } + else + { + m_uniMotions.copyAffineMvFrom(cMvTemp[iRefList][iRefIdxTemp], uiCostTemp - m_pcRdCost->getCost(uiBitsTemp), (uint8_t)iRefList, (uint8_t)iRefIdxTemp, pu.cu->affineType + , aaiMvpIdx[iRefList][iRefIdxTemp] + ); + } +#else m_uniMotions.copyAffineMvFrom(cMvTemp[iRefList][iRefIdxTemp], uiCostTemp - m_pcRdCost->getCost(uiBitsTemp), (uint8_t)iRefList, (uint8_t)iRefIdxTemp, pu.cu->affineType , aaiMvpIdx[iRefList][iRefIdxTemp] ); +#endif } // Set best AMVP Index xCopyAffineAMVPInfo( affiAMVPInfoTemp[eRefPicList], aacAffineAMVPInfo[iRefList][iRefIdxTemp] ); +#if GDR_ENABLED + if ( pu.cu->imv != 2 || !m_pcEncCfg->getUseAffineAmvrEncOpt() ) + { + xCheckBestAffineMVP( pu, affiAMVPInfoTemp[eRefPicList], eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); + if (isEncodeClean) + { + int mvp_idx = aaiMvpIdx[iRefList][iRefIdxTemp]; + + cMvPredSolid[iRefList][iRefIdxTemp][0] = affiAMVPInfoTemp[eRefPicList].mvSolidLT[mvp_idx]; + cMvPredSolid[iRefList][iRefIdxTemp][1] = affiAMVPInfoTemp[eRefPicList].mvSolidRT[mvp_idx]; + cMvPredSolid[iRefList][iRefIdxTemp][2] = affiAMVPInfoTemp[eRefPicList].mvSolidLB[mvp_idx]; + + cMvTempSolid[iRefList][iRefIdxTemp][0] = cMvPredSolid[iRefList][iRefIdxTemp][0]; + cMvTempSolid[iRefList][iRefIdxTemp][1] = cMvPredSolid[iRefList][iRefIdxTemp][0]; + cMvTempSolid[iRefList][iRefIdxTemp][2] = cMvPredSolid[iRefList][iRefIdxTemp][0]; + + if (cMvTempValid[iRefList][iRefIdxTemp][0] && cMvTempValid[iRefList][iRefIdxTemp][1] && cMvTempValid[iRefList][iRefIdxTemp][2]) + { + cMvTempValid[iRefList][iRefIdxTemp][0] = cMvPredSolid[iRefList][iRefIdxTemp][0]; + cMvTempValid[iRefList][iRefIdxTemp][1] = cMvPredSolid[iRefList][iRefIdxTemp][0]; + cMvTempValid[iRefList][iRefIdxTemp][2] = cMvPredSolid[iRefList][iRefIdxTemp][0]; + } + + uiCostTempOk = true; + uiCostTempOk = uiCostTempOk && cMvPredSolid[iRefList][iRefIdxTemp][0] && cMvPredSolid[iRefList][iRefIdxTemp][1]; + uiCostTempOk = uiCostTempOk && ((mvNum > 2) ? cMvPredSolid[iRefList][iRefIdxTemp][2] : true); + uiCostTempOk = uiCostTempOk && cMvTempSolid[iRefList][iRefIdxTemp][0] && cMvTempSolid[iRefList][iRefIdxTemp][1] && ((mvNum > 2) ? cMvTempSolid[iRefList][iRefIdxTemp][2] : true); + uiCostTempOk = uiCostTempOk && cMvTempValid[iRefList][iRefIdxTemp][0] && cMvTempValid[iRefList][iRefIdxTemp][1] && ((mvNum > 2) ? cMvTempValid[iRefList][iRefIdxTemp][2] : true); + } + } +#else if ( pu.cu->imv != 2 || !m_pcEncCfg->getUseAffineAmvrEncOpt() ) - xCheckBestAffineMVP( pu, affiAMVPInfoTemp[eRefPicList], eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); + { + xCheckBestAffineMVP( pu, affiAMVPInfoTemp[eRefPicList], eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); + } +#endif if ( iRefList == 0 ) { uiCostTempL0[iRefIdxTemp] = uiCostTemp; uiBitsTempL0[iRefIdxTemp] = uiBitsTemp; +#if GDR_ENABLED + if (isEncodeClean) + { + uiCostTempL0Ok[iRefIdxTemp] = uiCostTempOk; + } +#endif } DTRACE( g_trace_ctx, D_COMMON, " (%d) uiCostTemp=%d, uiCost[iRefList]=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiCostTemp, uiCost[iRefList] ); +#if GDR_ENABLED + allOk = (uiCostTemp < uiCost[iRefList]); + + if (isEncodeClean) + { + if (uiCostTempOk) + { + allOk = (uiCostOk[iRefList]) ? (uiCostTemp < uiCost[iRefList]) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if ( uiCostTemp < uiCost[iRefList] ) +#endif { uiCost[iRefList] = uiCostTemp; uiBits[iRefList] = uiBitsTemp; // storing for bi-prediction +#if GDR_ENABLED + if (isEncodeClean) + { + uiCostOk[iRefList] = uiCostTempOk; + } +#endif // set best motion ::memcpy( aacMv[iRefList], cMvTemp[iRefList][iRefIdxTemp], sizeof(Mv) * 3 ); +#if GDR_ENABLED + if (isEncodeClean) + { + ::memcpy(aacMvSolid[iRefList], cMvTempSolid[iRefList][iRefIdxTemp], sizeof(bool) * 3); + ::memcpy(aacMvValid[iRefList], cMvTempValid[iRefList][iRefIdxTemp], sizeof(bool) * 3); + } +#endif iRefIdx[iRefList] = iRefIdxTemp; } + +#if GDR_ENABLED + allOk = (iRefList == 1 && uiCostTemp < costValidList1 && slice.getList1IdxToList0Idx(iRefIdxTemp) < 0); + + if (isEncodeClean) + { + if (uiCostTempOk) + { + allOk = (costValidList1Ok) ? (iRefList == 1 && uiCostTemp < costValidList1 && slice.getList1IdxToList0Idx(iRefIdxTemp) < 0) : true; + } + else + { + allOk = false; + } + } +#endif + + +#if GDR_ENABLED + if (allOk) +#else if ( iRefList == 1 && uiCostTemp < costValidList1 && slice.getList1IdxToList0Idx( iRefIdxTemp ) < 0 ) +#endif { costValidList1 = uiCostTemp; bitsValidList1 = uiBitsTemp; // set motion memcpy( mvValidList1, cMvTemp[iRefList][iRefIdxTemp], sizeof(Mv)*3 ); + +#if GDR_ENABLED + if (isEncodeClean) + { + costValidList1Ok = uiCostTempOk; + ::memcpy(mvValidList1Solid, cMvTempSolid[iRefList][iRefIdxTemp], sizeof(bool) * 3); + ::memcpy(mvValidList1Valid, cMvTempSolid[iRefList][iRefIdxTemp], sizeof(bool) * 3); + } +#endif refIdxValidList1 = iRefIdxTemp; } } // End refIdx loop @@ -4898,9 +7158,15 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, if ( pu.cu->affineType == AFFINEMODEL_4PARAM ) { ::memcpy( mvAffine4Para, cMvTemp, sizeof( cMvTemp ) ); +#if GDR_ENABLED + ::memcpy(mvAffine4ParaSolid, cMvTempSolid, sizeof(cMvTempSolid)); +#endif if ( pu.cu->imv == 0 && ( !pu.cu->cs->sps->getUseBcw() || bcwIdx == BCW_DEFAULT ) ) { AffineMVInfo *affMVInfo = m_affMVList + m_affMVListIdx; +#if GDR_ENABLED + AffineMVInfoSolid *affMVInfoSolid = m_affMVListSolid + m_affMVListIdx; +#endif //check; int j = 0; @@ -4912,10 +7178,19 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, break; } } +#if GDR_ENABLED if (j < m_affMVListSize) + { affMVInfo = m_affMVList + ((m_affMVListIdx - j - 1 + m_affMVListMaxSize) % (m_affMVListMaxSize)); - + affMVInfoSolid = m_affMVListSolid + ((m_affMVListIdx - j - 1 + m_affMVListMaxSize) % (m_affMVListMaxSize)); + } ::memcpy(affMVInfo->affMVs, cMvTemp, sizeof(cMvTemp)); + ::memcpy(affMVInfoSolid->affMVsSolid, cMvTempSolid, sizeof(cMvTempSolid)); +#else + if (j < m_affMVListSize) + affMVInfo = m_affMVList + ((m_affMVListIdx - j - 1 + m_affMVListMaxSize) % (m_affMVListMaxSize)); + ::memcpy(affMVInfo->affMVs, cMvTemp, sizeof(cMvTemp)); +#endif if (j == m_affMVListSize) { @@ -4943,6 +7218,15 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, ::memcpy( cMvPredBi, cMvPred, sizeof(cMvPred) ); ::memcpy( aaiMvpIdxBi, aaiMvpIdx, sizeof(aaiMvpIdx) ); +#if GDR_ENABLED + if (isEncodeClean) + { + ::memcpy(cMvBiSolid, aacMvSolid, sizeof(cMvBiSolid)); + ::memcpy(cMvBiValid, aacMvValid, sizeof(cMvBiValid)); + ::memcpy(cMvPredBiSolid, cMvPredSolid, sizeof(cMvPredSolid)); + } +#endif + uint32_t uiMotBits[2]; bool doBiPred = true; @@ -4960,6 +7244,33 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, ::memcpy( cMvBi[1], pcMvTemp, sizeof(Mv)*3 ); ::memcpy( cMvTemp[1][bestBiPRefIdxL1], pcMvTemp, sizeof(Mv)*3 ); iRefIdxBi[1] = bestBiPRefIdxL1; +#if GDR_ENABLED + if (isEncodeClean) + { + PelUnitBuf tmpBuf = m_tmpAffiStorage.getBuf(UnitAreaRelative(*pu.cu, pu)); + const Picture *refPic = pu.cu->slice->getRefPic((RefPicList)REF_PIC_LIST_1, iRefIdxBi[1]); + + cMvPredBiSolid[1][bestBiPRefIdxL1][0] = affiAMVPInfoTemp[REF_PIC_LIST_1].mvSolidLT[bestBiPMvpL1]; + cMvPredBiSolid[1][bestBiPRefIdxL1][1] = affiAMVPInfoTemp[REF_PIC_LIST_1].mvSolidRT[bestBiPMvpL1]; + cMvPredBiSolid[1][bestBiPRefIdxL1][2] = affiAMVPInfoTemp[REF_PIC_LIST_1].mvSolidLB[bestBiPMvpL1]; + + cMvBiSolid[1][0] = affiAMVPInfoTemp[REF_PIC_LIST_1].mvSolidLT[bestBiPMvpL1]; + cMvBiSolid[1][1] = affiAMVPInfoTemp[REF_PIC_LIST_1].mvSolidRT[bestBiPMvpL1]; + cMvBiSolid[1][2] = affiAMVPInfoTemp[REF_PIC_LIST_1].mvSolidLB[bestBiPMvpL1]; + + + bool isSubPuYYClean = xPredAffineBlk(COMPONENT_Y, pu, refPic, cMvTemp[1][bestBiPRefIdxL1], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); + bool isSubPuCbClean = (isSubPuYYClean) ? xPredAffineBlk(COMPONENT_Cb, pu, refPic, cMvTemp[1][bestBiPRefIdxL1], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Cb)) : false; + + cMvBiValid[1][0] = isSubPuYYClean && isSubPuCbClean; + cMvBiValid[1][1] = isSubPuYYClean && isSubPuCbClean; + cMvBiValid[1][2] = isSubPuYYClean && isSubPuCbClean; + + cMvTempSolid[1][bestBiPRefIdxL1][0] = affiAMVPInfoTemp[REF_PIC_LIST_1].mvSolidLT[bestBiPMvpL1]; + cMvTempSolid[1][bestBiPRefIdxL1][1] = affiAMVPInfoTemp[REF_PIC_LIST_1].mvSolidRT[bestBiPMvpL1]; + cMvTempSolid[1][bestBiPRefIdxL1][2] = affiAMVPInfoTemp[REF_PIC_LIST_1].mvSolidLB[bestBiPMvpL1]; + } +#endif if( m_pcEncCfg->getMCTSEncConstraint() ) { @@ -4982,6 +7293,26 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, PU::setAllAffineMv( pu, cMvBi[1][0], cMvBi[1][1], cMvBi[1][2], REF_PIC_LIST_1); pu.refIdx[REF_PIC_LIST_1] = iRefIdxBi[1]; +#if GDR_ENABLED + if (isEncodeClean) + { + PelUnitBuf tmpBuf = m_tmpAffiStorage.getBuf(UnitAreaRelative(*pu.cu, pu)); + const Picture *refPic = pu.cu->slice->getRefPic((RefPicList)REF_PIC_LIST_1, pu.refIdx[REF_PIC_LIST_1]); + + pu.mvAffiSolid[REF_PIC_LIST_1][0] = cMvBiSolid[REF_PIC_LIST_1][0]; + pu.mvAffiSolid[REF_PIC_LIST_1][1] = cMvBiSolid[REF_PIC_LIST_1][1]; + pu.mvAffiSolid[REF_PIC_LIST_1][2] = cMvBiSolid[REF_PIC_LIST_1][2]; + + + bool isSubPuYYClean = xPredAffineBlk(COMPONENT_Y, pu, refPic, cMvBi[1], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); + bool isSubPuCbClean = (isSubPuYYClean) ? xPredAffineBlk(COMPONENT_Cb, pu, refPic, cMvBi[1], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Cb)) : false; + + pu.mvAffiValid[REF_PIC_LIST_1][0] = cMvBiValid[REF_PIC_LIST_1][0] = isSubPuYYClean && isSubPuCbClean; + pu.mvAffiValid[REF_PIC_LIST_1][1] = cMvBiValid[REF_PIC_LIST_1][1] = isSubPuYYClean && isSubPuCbClean; + pu.mvAffiValid[REF_PIC_LIST_1][2] = cMvBiValid[REF_PIC_LIST_1][2] = isSubPuYYClean && isSubPuCbClean; + } +#endif + PelUnitBuf predBufTmp = m_tmpPredStorage[REF_PIC_LIST_1].getBuf( UnitAreaRelative(*pu.cu, pu) ); motionCompensation( pu, predBufTmp, REF_PIC_LIST_1 ); @@ -5023,7 +7354,27 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, int iRefList = iIter % 2; if ( m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE1 || m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE2 ) { +#if GDR_ENABLED + allOk = (uiCost[0] <= uiCost[1]); + + if (isEncodeClean) + { + if (uiCostOk[0]) + { + allOk = (uiCostOk[1]) ? (uiCost[0] <= uiCost[1]) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if( uiCost[0] <= uiCost[1] ) +#endif { iRefList = 1; } @@ -5046,6 +7397,25 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, { PU::setAllAffineMv( pu, aacMv[1-iRefList][0], aacMv[1-iRefList][1], aacMv[1-iRefList][2], RefPicList(1-iRefList)); pu.refIdx[1-iRefList] = iRefIdx[1-iRefList]; +#if GDR_ENABLED + if (isEncodeClean) + { + PelUnitBuf tmpBuf = m_tmpAffiStorage.getBuf(UnitAreaRelative(*pu.cu, pu)); + const Picture *refPic = pu.cu->slice->getRefPic((RefPicList)(1 - iRefList), pu.refIdx[1 - iRefList]); + + pu.mvAffiSolid[1 - iRefList][0] = aacMvSolid[1 - iRefList][0]; + pu.mvAffiSolid[1 - iRefList][1] = aacMvSolid[1 - iRefList][1]; + pu.mvAffiSolid[1 - iRefList][2] = aacMvSolid[1 - iRefList][2]; + + + bool isSubPuYYClean = xPredAffineBlk(COMPONENT_Y, pu, refPic, aacMv[1 - iRefList], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); + bool isSubPuCbClean = (isSubPuYYClean) ? xPredAffineBlk(COMPONENT_Cb, pu, refPic, aacMv[1 - iRefList], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Cb)) : false; + + pu.mvAffiValid[1 - iRefList][0] = aacMvValid[1 - iRefList][0] = isSubPuYYClean && isSubPuCbClean; + pu.mvAffiValid[1 - iRefList][1] = aacMvValid[1 - iRefList][1] = isSubPuYYClean && isSubPuCbClean; + pu.mvAffiValid[1 - iRefList][2] = aacMvValid[1 - iRefList][2] = isSubPuYYClean && isSubPuCbClean; + } +#endif PelUnitBuf predBufTmp = m_tmpPredStorage[1 - iRefList].getBuf( UnitAreaRelative(*pu.cu, pu) ); motionCompensation( pu, predBufTmp, RefPicList(1 - iRefList) ); @@ -5089,24 +7459,129 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdxBi[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS]; // call Affine ME +#if GDR_ENABLED + xAffineMotionEstimation(pu, origBuf, eRefPicList, cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], cMvTempSolid[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, + aaiMvpIdxBi[iRefList][iRefIdxTemp], aacAffineAMVPInfo[iRefList][iRefIdxTemp], bAnyClean, + true); +#else xAffineMotionEstimation( pu, origBuf, eRefPicList, cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, aaiMvpIdxBi[iRefList][iRefIdxTemp], aacAffineAMVPInfo[iRefList][iRefIdxTemp], true ); +#endif + +#if GDR_ENABLED + if (isEncodeClean) + { + int mvp_idx = aaiMvpIdx[iRefList][iRefIdxTemp]; + PelUnitBuf tmpBuf = m_tmpAffiStorage.getBuf(UnitAreaRelative(*pu.cu, pu)); + const Picture *refPic = pu.cu->slice->getRefPic((RefPicList)iRefList, iRefIdxTemp); + + cMvPredBiSolid[iRefList][iRefIdxTemp][0] = aacAffineAMVPInfo[iRefList][iRefIdxTemp].mvSolidLT[mvp_idx]; + cMvPredBiSolid[iRefList][iRefIdxTemp][1] = aacAffineAMVPInfo[iRefList][iRefIdxTemp].mvSolidRT[mvp_idx]; + cMvPredBiSolid[iRefList][iRefIdxTemp][2] = aacAffineAMVPInfo[iRefList][iRefIdxTemp].mvSolidLB[mvp_idx]; + + cMvTempSolid[iRefList][iRefIdxTemp][0] = cMvPredBiSolid[iRefList][iRefIdxTemp][0]; + cMvTempSolid[iRefList][iRefIdxTemp][1] = cMvPredSolid[iRefList][iRefIdxTemp][1]; + cMvTempSolid[iRefList][iRefIdxTemp][2] = cMvPredSolid[iRefList][iRefIdxTemp][2]; + + + bool isSubPuYYClean = xPredAffineBlk(COMPONENT_Y, pu, refPic, cMvTemp[iRefList][iRefIdxTemp], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); + bool isSubPuCbClean = (isSubPuYYClean) ? xPredAffineBlk(COMPONENT_Cb, pu, refPic, cMvTemp[iRefList][iRefIdxTemp], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Cb)) : false; + + cMvTempValid[iRefList][iRefIdxTemp][0] = isSubPuYYClean && isSubPuCbClean; + cMvTempValid[iRefList][iRefIdxTemp][1] = isSubPuYYClean && isSubPuCbClean; + cMvTempValid[iRefList][iRefIdxTemp][2] = isSubPuYYClean && isSubPuCbClean; + + uiCostTempOk = true; + uiCostTempOk = uiCostTempOk && cMvPredBiSolid[iRefList][iRefIdxTemp][0] && cMvPredBiSolid[iRefList][iRefIdxTemp][1]; + uiCostTempOk = uiCostTempOk && ((mvNum > 2) ? cMvPredBiSolid[iRefList][iRefIdxTemp][2] : true); + uiCostTempOk = uiCostTempOk && cMvTempSolid[iRefList][iRefIdxTemp][0] && cMvTempSolid[iRefList][iRefIdxTemp][1] && ((mvNum > 2) ? cMvTempSolid[iRefList][iRefIdxTemp][2] : true); + uiCostTempOk = uiCostTempOk && cMvTempValid[iRefList][iRefIdxTemp][0] && cMvTempValid[iRefList][iRefIdxTemp][1] && ((mvNum > 2) ? cMvTempValid[iRefList][iRefIdxTemp][2] : true); + } +#endif + xCopyAffineAMVPInfo( aacAffineAMVPInfo[iRefList][iRefIdxTemp], affiAMVPInfoTemp[eRefPicList] ); +#if GDR_ENABLED + if ( pu.cu->imv != 2 || !m_pcEncCfg->getUseAffineAmvrEncOpt() ) + { + xCheckBestAffineMVP( pu, affiAMVPInfoTemp[eRefPicList], eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp ); + if (isEncodeClean) + { + int mvp_idx = aaiMvpIdxBi[iRefList][iRefIdxTemp]; + + cMvPredBiSolid[iRefList][iRefIdxTemp][0] = affiAMVPInfoTemp[eRefPicList].mvSolidLT[mvp_idx]; + cMvPredBiSolid[iRefList][iRefIdxTemp][1] = affiAMVPInfoTemp[eRefPicList].mvSolidRT[mvp_idx]; + cMvPredBiSolid[iRefList][iRefIdxTemp][2] = affiAMVPInfoTemp[eRefPicList].mvSolidLB[mvp_idx]; + + cMvTempSolid[iRefList][iRefIdxTemp][0] = cMvPredBiSolid[iRefList][iRefIdxTemp][0]; + cMvTempSolid[iRefList][iRefIdxTemp][1] = cMvPredBiSolid[iRefList][iRefIdxTemp][1]; + cMvTempSolid[iRefList][iRefIdxTemp][2] = cMvPredBiSolid[iRefList][iRefIdxTemp][2]; + + if (cMvTempValid[iRefList][iRefIdxTemp][0] && cMvTempValid[iRefList][iRefIdxTemp][1] && cMvTempValid[iRefList][iRefIdxTemp][2]) + { + cMvTempValid[iRefList][iRefIdxTemp][0] = cMvPredBiSolid[iRefList][iRefIdxTemp][0]; + cMvTempValid[iRefList][iRefIdxTemp][1] = cMvPredBiSolid[iRefList][iRefIdxTemp][1]; + cMvTempValid[iRefList][iRefIdxTemp][2] = cMvPredBiSolid[iRefList][iRefIdxTemp][2]; + } + + uiCostTempOk = true; + uiCostTempOk = uiCostTempOk && cMvPredBiSolid[iRefList][iRefIdxTemp][0] && cMvPredBiSolid[iRefList][iRefIdxTemp][1]; + uiCostTempOk = uiCostTempOk && ((mvNum > 2) ? cMvPredBiSolid[iRefList][iRefIdxTemp][2] : true); + uiCostTempOk = uiCostTempOk && cMvTempSolid[iRefList][iRefIdxTemp][0] && cMvTempSolid[iRefList][iRefIdxTemp][1] && ((mvNum > 2) ? cMvTempSolid[iRefList][iRefIdxTemp][2] : true); + uiCostTempOk = uiCostTempOk && cMvTempValid[iRefList][iRefIdxTemp][0] && cMvTempValid[iRefList][iRefIdxTemp][1] && ((mvNum > 2) ? cMvTempValid[iRefList][iRefIdxTemp][2] : true); + } + } +#else if ( pu.cu->imv != 2 || !m_pcEncCfg->getUseAffineAmvrEncOpt() ) { xCheckBestAffineMVP(pu, affiAMVPInfoTemp[eRefPicList], eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp); } +#endif + +#if GDR_ENABLED + allOk = (uiCostTemp < uiCostBi); + if (isEncodeClean) + { + if (uiCostTempOk) + { + allOk = (uiCostBiOk) ? (uiCostTemp < uiCostBi) : true; + } + else + { + allOk = false; + } + } +#endif + + + +#if GDR_ENABLED + if (allOk) +#else if ( uiCostTemp < uiCostBi ) +#endif { bChanged = true; ::memcpy( cMvBi[iRefList], cMvTemp[iRefList][iRefIdxTemp], sizeof(Mv)*3 ); +#if GDR_ENABLED + if (isEncodeClean) + { + ::memcpy(cMvBiSolid[iRefList], cMvTempSolid[iRefList][iRefIdxTemp], sizeof(bool) * 3); + ::memcpy(cMvBiValid[iRefList], cMvTempValid[iRefList][iRefIdxTemp], sizeof(bool) * 3); + } +#endif iRefIdxBi[iRefList] = iRefIdxTemp; uiCostBi = uiCostTemp; +#if GDR_ENABLED + if (isEncodeClean) + { + uiCostBiOk = uiCostTempOk; + } +#endif uiMotBits[iRefList] = uiBitsTemp - uiMbBits[2] - uiMotBits[1-iRefList]; uiMotBits[iRefList] -= ((pu.cu->slice->getSPS()->getUseBcw() == true) ? bcwIdxBits : 0); uiBits[2] = uiBitsTemp; @@ -5116,23 +7591,119 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, // Set motion PU::setAllAffineMv( pu, cMvBi[iRefList][0], cMvBi[iRefList][1], cMvBi[iRefList][2], eRefPicList); pu.refIdx[eRefPicList] = iRefIdxBi[eRefPicList]; + +#if GDR_ENABLED + if (isEncodeClean) + { + bool isSubPuYYClean; + bool isSubPuCbClean; + PelUnitBuf tmpBuf = m_tmpAffiStorage.getBuf(UnitAreaRelative(*pu.cu, pu)); + const Picture *refPic = pu.cu->slice->getRefPic((RefPicList)iRefList, pu.refIdx[eRefPicList]); + + pu.mvAffiSolid[eRefPicList][0] = cMvBiSolid[iRefList][0]; + pu.mvAffiSolid[eRefPicList][1] = cMvBiSolid[iRefList][1]; + pu.mvAffiSolid[eRefPicList][2] = cMvBiSolid[iRefList][2]; + + isSubPuYYClean = xPredAffineBlk(COMPONENT_Y, pu, refPic, cMvBi[iRefList], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); + isSubPuCbClean = (isSubPuYYClean) ? xPredAffineBlk(COMPONENT_Cb, pu, refPic, cMvBi[iRefList], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Cb)) : false; + + pu.mvAffiValid[eRefPicList][0] = cMvBiValid[iRefList][0] = isSubPuYYClean && isSubPuCbClean; + pu.mvAffiValid[eRefPicList][1] = cMvBiValid[iRefList][1] = isSubPuYYClean && isSubPuCbClean; + pu.mvAffiValid[eRefPicList][2] = cMvBiValid[iRefList][2] = isSubPuYYClean && isSubPuCbClean; + } +#endif + PelUnitBuf predBufTmp = m_tmpPredStorage[iRefList].getBuf( UnitAreaRelative(*pu.cu, pu) ); motionCompensation( pu, predBufTmp, eRefPicList ); } } } // for loop-iRefIdxTemp - if ( !bChanged ) - { - if ((uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) || enforceBcwPred) - { - xCopyAffineAMVPInfo( aacAffineAMVPInfo[0][iRefIdxBi[0]], affiAMVPInfoTemp[REF_PIC_LIST_0] ); - xCheckBestAffineMVP( pu, affiAMVPInfoTemp[REF_PIC_LIST_0], REF_PIC_LIST_0, cMvBi[0], cMvPredBi[0][iRefIdxBi[0]], aaiMvpIdxBi[0][iRefIdxBi[0]], uiBits[2], uiCostBi ); + if ( !bChanged ) + { +#if GDR_ENABLED + allOk = ((uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) || enforceBcwPred); + + if (isEncodeClean) + { + if (uiCostBiOk) + { + allOk = (uiCostOk[0] && uiCostOk[1]) ? ((uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) || enforceBcwPred) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else + if ((uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) || enforceBcwPred) +#endif + { + xCopyAffineAMVPInfo( aacAffineAMVPInfo[0][iRefIdxBi[0]], affiAMVPInfoTemp[REF_PIC_LIST_0] ); + xCheckBestAffineMVP( pu, affiAMVPInfoTemp[REF_PIC_LIST_0], REF_PIC_LIST_0, cMvBi[0], cMvPredBi[0][iRefIdxBi[0]], aaiMvpIdxBi[0][iRefIdxBi[0]], uiBits[2], uiCostBi ); +#if GDR_ENABLED + if (isEncodeClean) + { + int mvp_idx = aaiMvpIdxBi[0][iRefIdxBi[0]]; + + cMvPredBiSolid[REF_PIC_LIST_0][iRefIdxBi[0]][0] = affiAMVPInfoTemp[REF_PIC_LIST_0].mvSolidLT[mvp_idx]; + cMvPredBiSolid[REF_PIC_LIST_0][iRefIdxBi[0]][1] = affiAMVPInfoTemp[REF_PIC_LIST_0].mvSolidRT[mvp_idx]; + cMvPredBiSolid[REF_PIC_LIST_0][iRefIdxBi[0]][2] = affiAMVPInfoTemp[REF_PIC_LIST_0].mvSolidLB[mvp_idx]; + + cMvBiSolid[REF_PIC_LIST_0][0] = cMvPredBiSolid[REF_PIC_LIST_0][iRefIdxBi[0]][0]; + cMvBiSolid[REF_PIC_LIST_0][1] = cMvPredBiSolid[REF_PIC_LIST_0][iRefIdxBi[0]][1]; + cMvBiSolid[REF_PIC_LIST_0][2] = cMvPredBiSolid[REF_PIC_LIST_0][iRefIdxBi[0]][2]; + + if (cMvBiValid[REF_PIC_LIST_0][0] && cMvBiValid[REF_PIC_LIST_0][1] && cMvBiValid[REF_PIC_LIST_0][2]) + { + cMvBiValid[REF_PIC_LIST_0][0] = cMvPredBiSolid[REF_PIC_LIST_0][iRefIdxBi[0]][0]; + cMvBiValid[REF_PIC_LIST_0][1] = cMvPredBiSolid[REF_PIC_LIST_0][iRefIdxBi[0]][1]; + cMvBiValid[REF_PIC_LIST_0][2] = cMvPredBiSolid[REF_PIC_LIST_0][iRefIdxBi[0]][2]; + } + + uiCostBiOk = true; + uiCostBiOk = uiCostBiOk && cMvPredBiSolid[REF_PIC_LIST_0][iRefIdxBi[0]][0] && cMvPredBiSolid[REF_PIC_LIST_0][iRefIdxBi[0]][1]; + uiCostBiOk = uiCostBiOk && ((mvNum > 2) ? cMvPredBiSolid[REF_PIC_LIST_0][iRefIdxBi[0]][2] : true); + uiCostBiOk = uiCostBiOk && cMvBiSolid[0][0] && cMvBiSolid[0][1] && ((mvNum > 2) ? cMvBiSolid[0][2] : true); + uiCostBiOk = uiCostBiOk && cMvBiValid[0][0] && cMvBiValid[0][1] && ((mvNum > 2) ? cMvBiValid[0][2] : true); + } +#endif if ( !slice.getPicHeader()->getMvdL1ZeroFlag() ) { xCopyAffineAMVPInfo( aacAffineAMVPInfo[1][iRefIdxBi[1]], affiAMVPInfoTemp[REF_PIC_LIST_1] ); xCheckBestAffineMVP( pu, affiAMVPInfoTemp[REF_PIC_LIST_1], REF_PIC_LIST_1, cMvBi[1], cMvPredBi[1][iRefIdxBi[1]], aaiMvpIdxBi[1][iRefIdxBi[1]], uiBits[2], uiCostBi ); +#if GDR_ENABLED + if (isEncodeClean) + { + int mvp_idx = aaiMvpIdxBi[1][iRefIdxBi[1]]; + + cMvPredBiSolid[REF_PIC_LIST_1][iRefIdxBi[1]][0] = affiAMVPInfoTemp[REF_PIC_LIST_1].mvSolidLT[mvp_idx]; + cMvPredBiSolid[REF_PIC_LIST_1][iRefIdxBi[1]][1] = affiAMVPInfoTemp[REF_PIC_LIST_1].mvSolidRT[mvp_idx]; + cMvPredBiSolid[REF_PIC_LIST_1][iRefIdxBi[1]][2] = affiAMVPInfoTemp[REF_PIC_LIST_1].mvSolidLB[mvp_idx]; + + cMvBiSolid[REF_PIC_LIST_1][0] = cMvPredBiSolid[REF_PIC_LIST_1][iRefIdxBi[1]][0]; + cMvBiSolid[REF_PIC_LIST_1][1] = cMvPredBiSolid[REF_PIC_LIST_1][iRefIdxBi[1]][1]; + cMvBiSolid[REF_PIC_LIST_1][2] = cMvPredBiSolid[REF_PIC_LIST_1][iRefIdxBi[1]][2]; + + if (cMvBiValid[REF_PIC_LIST_1][0] && cMvBiValid[REF_PIC_LIST_1][1] && cMvBiValid[REF_PIC_LIST_1][2]) + { + cMvBiValid[REF_PIC_LIST_1][0] = cMvPredBiSolid[REF_PIC_LIST_1][iRefIdxBi[1]][0]; + cMvBiValid[REF_PIC_LIST_1][1] = cMvPredBiSolid[REF_PIC_LIST_1][iRefIdxBi[1]][1]; + cMvBiValid[REF_PIC_LIST_1][2] = cMvPredBiSolid[REF_PIC_LIST_1][iRefIdxBi[1]][2]; + } + + uiCostBiOk = true; + uiCostBiOk = uiCostBiOk && cMvPredBiSolid[REF_PIC_LIST_1][iRefIdxBi[1]][0] && cMvPredBiSolid[REF_PIC_LIST_1][iRefIdxBi[1]][1]; + uiCostBiOk = uiCostBiOk && ((mvNum > 2) ? cMvPredBiSolid[REF_PIC_LIST_1][iRefIdxBi[1]][2] : true); + uiCostBiOk = uiCostBiOk && cMvBiSolid[1][0] && cMvBiSolid[1][1] && ((mvNum > 2) ? cMvBiSolid[1][2] : true); + uiCostBiOk = uiCostBiOk && cMvBiValid[1][0] && cMvBiValid[1][1] && ((mvNum > 2) ? cMvBiValid[1][2] : true); + } +#endif } } break; @@ -5164,6 +7735,15 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, iRefIdx[1] = refIdxValidList1; uiBits[1] = bitsValidList1; uiCost[1] = costValidList1; + +#if GDR_ENABLED + if (isEncodeClean) + { + memcpy(aacMvSolid[1], mvValidList1Solid, sizeof(bool) * 3); + memcpy(aacMvValid[1], mvValidList1Valid, sizeof(bool) * 3); + uiCostOk[1] = costValidList1Ok; + } +#endif if (pu.cs->pps->getWPBiPred() == true && tryBipred && (bcwIdx != BCW_DEFAULT)) { CHECK(iRefIdxBi[0]<0, "Invalid picture reference index"); @@ -5175,15 +7755,46 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, { uiCostBi = MAX_UINT; enforceBcwPred = false; +#if GDR_ENABLED + uiCostBiOk = false; +#endif } } if( enforceBcwPred ) { uiCost[0] = uiCost[1] = MAX_UINT; +#if GDR_ENABLED + uiCostOk[0] = uiCostOk[1] = false; +#endif } // Affine ME result set +#if GDR_ENABLED + bool BiOk = (uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]); + + if (isEncodeClean) + { + if (uiCostBiOk) + BiOk = (uiCostOk[0] && uiCostOk[1]) ? (uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) : true; + else + BiOk = false; + } + + bool L0ok = (uiCost[0] <= uiCost[1]); + if (isEncodeClean) + { + if (uiCostOk[0]) + L0ok = (uiCostOk[1]) ? (uiCost[0] <= uiCost[1]) : true; + else + L0ok = false; + } +#endif + +#if GDR_ENABLED + if (BiOk) +#else if ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1] ) // Bi +#endif { lastMode = 2; affineCost = uiCostBi; @@ -5193,6 +7804,39 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, pu.refIdx[REF_PIC_LIST_0] = iRefIdxBi[0]; pu.refIdx[REF_PIC_LIST_1] = iRefIdxBi[1]; +#if GDR_ENABLED + if (isEncodeClean) + { + PelUnitBuf tmpBuf = m_tmpAffiStorage.getBuf(UnitAreaRelative(*pu.cu, pu)); + const Picture *refPic0 = pu.cu->slice->getRefPic((RefPicList)REF_PIC_LIST_0, pu.refIdx[REF_PIC_LIST_0]); + const Picture *refPic1 = pu.cu->slice->getRefPic((RefPicList)REF_PIC_LIST_1, pu.refIdx[REF_PIC_LIST_1]); + + pu.mvAffiSolid[REF_PIC_LIST_0][0] = cMvBiSolid[REF_PIC_LIST_0][0]; + pu.mvAffiSolid[REF_PIC_LIST_0][1] = cMvBiSolid[REF_PIC_LIST_0][1]; + pu.mvAffiSolid[REF_PIC_LIST_0][2] = cMvBiSolid[REF_PIC_LIST_0][2]; + + bool isSubPuYYClean0 = xPredAffineBlk(COMPONENT_Y, pu, refPic0, cMvBi[0], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); + bool isSubPuCbClean0 = (isSubPuYYClean0) ? xPredAffineBlk(COMPONENT_Cb, pu, refPic0, cMvBi[0], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Cb)) : false; + + pu.mvAffiValid[REF_PIC_LIST_0][0] = cMvBiValid[REF_PIC_LIST_0][0] = isSubPuYYClean0 && isSubPuCbClean0; + pu.mvAffiValid[REF_PIC_LIST_0][1] = cMvBiValid[REF_PIC_LIST_0][1] = isSubPuYYClean0 && isSubPuCbClean0; + pu.mvAffiValid[REF_PIC_LIST_0][2] = cMvBiValid[REF_PIC_LIST_0][2] = isSubPuYYClean0 && isSubPuCbClean0; + + + pu.mvAffiSolid[REF_PIC_LIST_1][0] = cMvBiSolid[REF_PIC_LIST_1][0]; + pu.mvAffiSolid[REF_PIC_LIST_1][1] = cMvBiSolid[REF_PIC_LIST_1][1]; + pu.mvAffiSolid[REF_PIC_LIST_1][2] = cMvBiSolid[REF_PIC_LIST_1][2]; + + bool isSubPuYYClean1 = xPredAffineBlk(COMPONENT_Y, pu, refPic1, cMvBi[1], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); + bool isSubPuCbClean1 = (isSubPuYYClean1) ? xPredAffineBlk(COMPONENT_Cb, pu, refPic1, cMvBi[1], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Cb)) : false; + + pu.mvAffiValid[REF_PIC_LIST_1][0] = cMvBiValid[REF_PIC_LIST_1][0] = isSubPuYYClean1 && isSubPuCbClean1; + pu.mvAffiValid[REF_PIC_LIST_1][1] = cMvBiValid[REF_PIC_LIST_1][1] = isSubPuYYClean1 && isSubPuCbClean1; + pu.mvAffiValid[REF_PIC_LIST_1][2] = cMvBiValid[REF_PIC_LIST_1][2] = isSubPuYYClean1 && isSubPuCbClean1; + } +#endif + + for ( int verIdx = 0; verIdx < mvNum; verIdx++ ) { pu.mvdAffi[REF_PIC_LIST_0][verIdx] = cMvBi[0][verIdx] - cMvPredBi[0][iRefIdxBi[0]][verIdx]; @@ -5208,8 +7852,26 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, pu.mvpNum[REF_PIC_LIST_0] = aaiMvpNum[0][iRefIdxBi[0]]; pu.mvpIdx[REF_PIC_LIST_1] = aaiMvpIdxBi[1][iRefIdxBi[1]]; pu.mvpNum[REF_PIC_LIST_1] = aaiMvpNum[1][iRefIdxBi[1]]; + +#if GDR_ENABLED + if (isEncodeClean) + { + pu.mvpSolid[REF_PIC_LIST_0] = affiAMVPInfoTemp[0].mvSolidLT[pu.mvpIdx[0]] && affiAMVPInfoTemp[0].mvSolidRT[pu.mvpIdx[0]]; + pu.mvpSolid[REF_PIC_LIST_1] = affiAMVPInfoTemp[1].mvSolidLT[pu.mvpIdx[1]] && affiAMVPInfoTemp[1].mvSolidRT[pu.mvpIdx[1]]; + + if (pu.cu->affineType == AFFINEMODEL_6PARAM) + { + pu.mvpSolid[REF_PIC_LIST_0] = pu.mvpSolid[REF_PIC_LIST_0] && affiAMVPInfoTemp[0].mvSolidLB[pu.mvpIdx[0]]; + pu.mvpSolid[REF_PIC_LIST_1] = pu.mvpSolid[REF_PIC_LIST_1] && affiAMVPInfoTemp[1].mvSolidLB[pu.mvpIdx[1]]; + } + } +#endif } +#if GDR_ENABLED + else if (L0ok) // List 0 +#else else if ( uiCost[0] <= uiCost[1] ) // List 0 +#endif { lastMode = 0; affineCost = uiCost[0]; @@ -5217,6 +7879,27 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, PU::setAllAffineMv( pu, aacMv[0][0], aacMv[0][1], aacMv[0][2], REF_PIC_LIST_0); pu.refIdx[REF_PIC_LIST_0] = iRefIdx[0]; +#if GDR_ENABLED + if (isEncodeClean) + { + bool isSubPuYYClean; + bool isSubPuCbClean; + PelUnitBuf tmpBuf = m_tmpAffiStorage.getBuf(UnitAreaRelative(*pu.cu, pu)); + const Picture *refPic = pu.cu->slice->getRefPic((RefPicList)REF_PIC_LIST_0, pu.refIdx[REF_PIC_LIST_0]); + + pu.mvAffiSolid[0][0] = aacMvSolid[0][0]; + pu.mvAffiSolid[0][1] = aacMvSolid[0][1]; + pu.mvAffiSolid[0][2] = aacMvSolid[0][2]; + + isSubPuYYClean = xPredAffineBlk(COMPONENT_Y, pu, refPic, aacMv[0], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); + isSubPuCbClean = (isSubPuYYClean) ? xPredAffineBlk(COMPONENT_Cb, pu, refPic, aacMv[0], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Cb)) : false; + + pu.mvAffiValid[0][0] = aacMvValid[0][0] = isSubPuYYClean && isSubPuCbClean; + pu.mvAffiValid[0][1] = aacMvValid[0][1] = isSubPuYYClean && isSubPuCbClean; + pu.mvAffiValid[0][2] = aacMvValid[0][2] = isSubPuYYClean && isSubPuCbClean; + } +#endif + for ( int verIdx = 0; verIdx < mvNum; verIdx++ ) { pu.mvdAffi[REF_PIC_LIST_0][verIdx] = aacMv[0][verIdx] - cMvPred[0][iRefIdx[0]][verIdx]; @@ -5228,6 +7911,17 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, pu.mvpIdx[REF_PIC_LIST_0] = aaiMvpIdx[0][iRefIdx[0]]; pu.mvpNum[REF_PIC_LIST_0] = aaiMvpNum[0][iRefIdx[0]]; +#if GDR_ENABLED + if (isEncodeClean) + { + pu.mvpSolid[REF_PIC_LIST_0] = affiAMVPInfoTemp[0].mvSolidLT[pu.mvpIdx[0]] && affiAMVPInfoTemp[0].mvSolidRT[pu.mvpIdx[0]]; + + if (pu.cu->affineType == AFFINEMODEL_6PARAM) + { + pu.mvpSolid[REF_PIC_LIST_0] = pu.mvpSolid[REF_PIC_LIST_0] && affiAMVPInfoTemp[0].mvSolidLB[pu.mvpIdx[0]]; + } + } +#endif } else { @@ -5237,6 +7931,27 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, PU::setAllAffineMv( pu, aacMv[1][0], aacMv[1][1], aacMv[1][2], REF_PIC_LIST_1); pu.refIdx[REF_PIC_LIST_1] = iRefIdx[1]; +#if GDR_ENABLED + if (isEncodeClean) + { + bool isSubPuYYClean; + bool isSubPuCbClean; + PelUnitBuf tmpBuf = m_tmpAffiStorage.getBuf(UnitAreaRelative(*pu.cu, pu)); + const Picture *refPic = pu.cu->slice->getRefPic((RefPicList)REF_PIC_LIST_1, pu.refIdx[REF_PIC_LIST_1]); + + pu.mvAffiSolid[1][0] = aacMvSolid[1][0]; + pu.mvAffiSolid[1][1] = aacMvSolid[1][1]; + pu.mvAffiSolid[1][2] = aacMvSolid[1][2]; + + isSubPuYYClean = xPredAffineBlk(COMPONENT_Y, pu, refPic, aacMv[1], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); + isSubPuCbClean = (isSubPuYYClean) ? xPredAffineBlk(COMPONENT_Cb, pu, refPic, aacMv[1], tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Cb)) : false; + + pu.mvAffiValid[1][0] = aacMvValid[1][0] = isSubPuYYClean && isSubPuCbClean; + pu.mvAffiValid[1][1] = aacMvValid[1][1] = isSubPuYYClean && isSubPuCbClean; + pu.mvAffiValid[1][2] = aacMvValid[1][2] = isSubPuYYClean && isSubPuCbClean; + } +#endif + for ( int verIdx = 0; verIdx < mvNum; verIdx++ ) { pu.mvdAffi[REF_PIC_LIST_1][verIdx] = aacMv[1][verIdx] - cMvPred[1][iRefIdx[1]][verIdx]; @@ -5248,6 +7963,17 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit& pu, pu.mvpIdx[REF_PIC_LIST_1] = aaiMvpIdx[1][iRefIdx[1]]; pu.mvpNum[REF_PIC_LIST_1] = aaiMvpNum[1][iRefIdx[1]]; +#if GDR_ENABLED + if (isEncodeClean) + { + pu.mvpSolid[REF_PIC_LIST_1] = affiAMVPInfoTemp[1].mvSolidLT[pu.mvpIdx[1]] && affiAMVPInfoTemp[1].mvSolidRT[pu.mvpIdx[1]]; + + if (pu.cu->affineType == AFFINEMODEL_6PARAM) + { + pu.mvpSolid[REF_PIC_LIST_1] = pu.mvpSolid[REF_PIC_LIST_1] && affiAMVPInfoTemp[1].mvSolidLB[pu.mvpIdx[1]]; + } + } +#endif } if( bcwIdx != BCW_DEFAULT ) { @@ -5328,6 +8054,11 @@ void solveEqual(double dEqualCoeff[7][7], int iOrder, double *dAffinePara) void InterSearch::xCheckBestAffineMVP( PredictionUnit &pu, AffineAMVPInfo &affineAMVPInfo, RefPicList eRefPicList, Mv acMv[3], Mv acMvPred[3], int& riMVPIdx, uint32_t& ruiBits, Distortion& ruiCost ) { +#if GDR_ENABLED + const CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif + if ( affineAMVPInfo.numCand < 2 ) { return; @@ -5361,7 +8092,39 @@ void InterSearch::xCheckBestAffineMVP( PredictionUnit &pu, AffineAMVPInfo &affin int iMvBits = xCalcAffineMVBits( pu, acMv, tmpPredMv ); iMvBits += m_auiMVPIdxCost[iMVPIdx][AMVP_MAX_NUM_CANDS]; +#if GDR_ENABLED + bool allOk = (iMvBits < iBestMvBits); + if (isEncodeClean) + { + bool curOk = affineAMVPInfo.mvSolidLT[iMVPIdx] && affineAMVPInfo.mvSolidRT[iMVPIdx]; + if (pu.cu->affineType == AFFINEMODEL_6PARAM) + { + curOk = curOk && affineAMVPInfo.mvSolidLB[iMVPIdx]; + } + + bool best_ok = affineAMVPInfo.mvSolidLT[iBestMVPIdx] && affineAMVPInfo.mvSolidRT[iBestMVPIdx]; + if (pu.cu->affineType == AFFINEMODEL_6PARAM) + { + curOk = curOk && affineAMVPInfo.mvSolidLB[iBestMVPIdx]; + } + + if (curOk) + { + allOk = (best_ok) ? (iMvBits < iBestMvBits) : true; + } + else + { + allOk = false; + } + } +#endif + + +#if GDR_ENABLED + if (allOk) +#else if (iMvBits < iBestMvBits) +#endif { iBestMvBits = iMvBits; iBestMVPIdx = iMVPIdx; @@ -5380,6 +8143,21 @@ void InterSearch::xCheckBestAffineMVP( PredictionUnit &pu, AffineAMVPInfo &affin } } +#if GDR_ENABLED +void InterSearch::xAffineMotionEstimation(PredictionUnit& pu, + PelUnitBuf& origBuf, + RefPicList eRefPicList, + Mv acMvPred[3], + int iRefIdxPred, + Mv acMv[3], + bool acMvSolid[3], + uint32_t& ruiBits, + Distortion& ruiCost, + int& mvpIdx, + const AffineAMVPInfo& aamvpi, + bool& rbCleanCandExist, + bool bBi) +#else void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, PelUnitBuf& origBuf, RefPicList eRefPicList, @@ -5391,13 +8169,25 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, int& mvpIdx, const AffineAMVPInfo& aamvpi, bool bBi) +#endif { +#if GDR_ENABLED + if (pu.cu->cs->sps->getUseBcw() && pu.cu->BcwIdx != BCW_DEFAULT && !bBi && xReadBufferedAffineUniMv(pu, eRefPicList, iRefIdxPred, acMvPred, acMv, acMvSolid, ruiBits, ruiCost + , mvpIdx, aamvpi + )) +#else if( pu.cu->cs->sps->getUseBcw() && pu.cu->BcwIdx != BCW_DEFAULT && !bBi && xReadBufferedAffineUniMv(pu, eRefPicList, iRefIdxPred, acMvPred, acMv, ruiBits, ruiCost , mvpIdx, aamvpi ) ) +#endif { return; } +#if GDR_ENABLED + const CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + bool acMvValid[3]; +#endif uint32_t dirBits = ruiBits - m_auiMVPIdxCost[mvpIdx][aamvpi.numCand]; int bestMvpIdx = mvpIdx; @@ -5434,6 +8224,11 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, // Set start Mv position, use input mv as started search mv Mv acMvTemp[3]; ::memcpy( acMvTemp, acMv, sizeof(Mv)*3 ); + +#if GDR_ENABLED + bool acMvTempSolid[3]; + ::memcpy(acMvTempSolid, acMvSolid, sizeof(bool) * 3); +#endif // Set delta mv // malloc buffer int iParaNum = pu.cu->affineType ? 7 : 5; @@ -5449,6 +8244,13 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, Distortion uiCostBest = std::numeric_limits<Distortion>::max(); uint32_t uiBitsBest = 0; +#if GDR_ENABLED + bool uiCostBestOk = true; + bool uiCostTempOk = true; + bool costTempOk = true; + + bool allOk = true; +#endif // do motion compensation with origin mv if( m_pcEncCfg->getMCTSEncConstraint() ) @@ -5476,7 +8278,11 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, { acMvTemp[2].roundAffinePrecInternal2Amvr(pu.cu->imv); } +#if GDR_ENABLED + bool YYOk = xPredAffineBlk(COMPONENT_Y, pu, refPic, acMvTemp, predBuf, false, pu.cs->slice->clpRng(COMPONENT_Y)); +#else xPredAffineBlk( COMPONENT_Y, pu, refPic, acMvTemp, predBuf, false, pu.cs->slice->clpRng( COMPONENT_Y ) ); +#endif // get error uiCostBest = m_pcRdCost->getDistPart(predBuf.Y(), pBuf->Y(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, distFunc); @@ -5497,6 +8303,25 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, uiBitsBest += xCalcAffineMVBits( pu, acMvTemp, acMvPred ); DTRACE( g_trace_ctx, D_COMMON, " (%d) yy uiBitsBest=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiBitsBest ); } + +#if GDR_ENABLED + if (isEncodeClean) + { + acMvSolid[0] = aamvpi.mvSolidLT[mvpIdx]; + acMvSolid[1] = aamvpi.mvSolidRT[mvpIdx]; + acMvSolid[2] = aamvpi.mvSolidLB[mvpIdx]; + + bool isSubPuYYClean = YYOk; + bool isSubPuCbClean = true; + + acMvValid[0] = isSubPuYYClean && isSubPuCbClean; + acMvValid[1] = isSubPuYYClean && isSubPuCbClean; + acMvValid[2] = isSubPuYYClean && isSubPuCbClean; + + uiCostBestOk = (acMvSolid[0] && acMvSolid[1] && acMvSolid[2]) && (acMvValid[0] && acMvValid[1] && acMvValid[2]); + } +#endif + uiCostBest = (Distortion)( floor( fWeight * (double)uiCostBest ) + (double)m_pcRdCost->getCost( uiBitsBest ) ); DTRACE( g_trace_ctx, D_COMMON, " (%d) uiBitsBest=%d, uiCostBest=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiBitsBest, uiCostBest ); @@ -5660,7 +8485,11 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, } } +#if GDR_ENABLED + bool YYOk = xPredAffineBlk(COMPONENT_Y, pu, refPic, acMvTemp, predBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); +#else xPredAffineBlk( COMPONENT_Y, pu, refPic, acMvTemp, predBuf, false, pu.cu->slice->clpRng( COMPONENT_Y ) ); +#endif // get error Distortion uiCostTemp = m_pcRdCost->getDistPart(predBuf.Y(), pBuf->Y(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, distFunc); @@ -5680,12 +8509,53 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, { uiBitsTemp += xCalcAffineMVBits( pu, acMvTemp, acMvPred ); } +#if GDR_ENABLED + if (isEncodeClean) + { + acMvSolid[0] = aamvpi.mvSolidLT[bestMvpIdx]; + acMvSolid[1] = aamvpi.mvSolidRT[bestMvpIdx]; + acMvSolid[2] = aamvpi.mvSolidLB[bestMvpIdx]; + + bool isSubPuYYClean = YYOk; + bool isSubPuCbClean = true; + + acMvValid[0] = isSubPuYYClean && isSubPuCbClean; + acMvValid[1] = isSubPuYYClean && isSubPuCbClean; + acMvValid[2] = isSubPuYYClean && isSubPuCbClean; + + uiCostTempOk = (acMvSolid[0] && acMvSolid[1] && acMvSolid[2]) && (acMvValid[0] && acMvValid[1] && acMvValid[2]); + } +#endif + uiCostTemp = (Distortion)( floor( fWeight * (double)uiCostTemp ) + (double)m_pcRdCost->getCost( uiBitsTemp ) ); // store best cost and mv +#if GDR_ENABLED + allOk = (uiCostTemp < uiCostBest); + if (isEncodeClean) + { + if (uiCostTempOk) + { + allOk = (uiCostBestOk) ? (uiCostTemp < uiCostBest) : true; + } + else + { + allOk = false; + } + } + + if (allOk) +#else if ( uiCostTemp < uiCostBest ) +#endif { uiCostBest = uiCostTemp; +#if GDR_ENABLED + if (isEncodeClean) + { + uiCostBestOk = uiCostTempOk; + } +#endif uiBitsBest = uiBitsTemp; memcpy( acMv, acMvTemp, sizeof(Mv) * 3 ); mvpIdx = bestMvpIdx; @@ -5694,7 +8564,30 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, auto checkCPMVRdCost = [&](Mv ctrlPtMv[3]) { +#if GDR_ENABLED + bool YYOk = xPredAffineBlk(COMPONENT_Y, pu, refPic, ctrlPtMv, predBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); +#else xPredAffineBlk(COMPONENT_Y, pu, refPic, ctrlPtMv, predBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); +#endif + +#if GDR_ENABLED + if (isEncodeClean) + { + acMvSolid[0] = aamvpi.mvSolidLT[bestMvpIdx]; + acMvSolid[1] = aamvpi.mvSolidRT[bestMvpIdx]; + acMvSolid[2] = aamvpi.mvSolidLB[bestMvpIdx]; + + bool isSubPuYYClean = YYOk; + bool isSubPuCbClean = true; // (isSubPuYYClean) ? xPredAffineBlk(COMPONENT_Cb, pu, refPic, ctrlPtMv, tmpBuf, false, pu.cu->slice->clpRng(COMPONENT_Cb)) : false; + + acMvValid[0] = isSubPuYYClean && isSubPuCbClean; + acMvValid[1] = isSubPuYYClean && isSubPuCbClean; + acMvValid[2] = isSubPuYYClean && isSubPuCbClean; + + costTempOk = (acMvSolid[0] && acMvSolid[1] && acMvSolid[2]) && (acMvValid[0] && acMvValid[1] && acMvValid[2]); + } +#endif + // get error Distortion costTemp = m_pcRdCost->getDistPart(predBuf.Y(), pBuf->Y(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, distFunc); // get cost with mv @@ -5703,9 +8596,33 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, bitsTemp += xCalcAffineMVBits( pu, ctrlPtMv, acMvPred ); costTemp = (Distortion)(floor(fWeight * (double)costTemp) + (double)m_pcRdCost->getCost(bitsTemp)); // store best cost and mv +#if GDR_ENABLED + bool allOk = (costTemp < uiCostBest); + if (isEncodeClean) + { + if (costTempOk) + { + allOk = (uiCostBestOk) ? (costTemp < uiCostBest) : true; + } + else + { + allOk = false; + } + } + + if (allOk) +#else if (costTemp < uiCostBest) +#endif { uiCostBest = costTemp; +#if GDR_ENABLED + if (isEncodeClean) + { + uiCostBestOk = costTempOk; + rbCleanCandExist = true; + } +#endif uiBitsBest = bitsTemp; ::memcpy(acMv, ctrlPtMv, sizeof(Mv) * 3); } @@ -5786,15 +8703,62 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, { acMvTemp[j].set(centerMv[j].getHor() + (testPos[i][0] << mvShift), centerMv[j].getVer() + (testPos[i][1] << mvShift)); clipMv( acMvTemp[j], pu.cu->lumaPos(), pu.cu->lumaSize(), *pu.cs->sps, *pu.cs->pps ); +#if GDR_ENABLED + bool YYOk = xPredAffineBlk(COMPONENT_Y, pu, refPic, acMvTemp, predBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); +#else xPredAffineBlk(COMPONENT_Y, pu, refPic, acMvTemp, predBuf, false, pu.cu->slice->clpRng(COMPONENT_Y)); +#endif + +#if GDR_ENABLED + if (isEncodeClean) + { + acMvSolid[0] = aamvpi.mvSolidLT[bestMvpIdx]; + acMvSolid[1] = aamvpi.mvSolidRT[bestMvpIdx]; + acMvSolid[2] = aamvpi.mvSolidLB[bestMvpIdx]; + + bool isSubPuYYClean = YYOk; + bool isSubPuCbClean = true; + + acMvValid[0] = isSubPuYYClean && isSubPuCbClean; + acMvValid[1] = isSubPuYYClean && isSubPuCbClean; + acMvValid[2] = isSubPuYYClean && isSubPuCbClean; + + costTempOk = (acMvSolid[0] && acMvSolid[1] && acMvSolid[2]) && (acMvValid[0] && acMvValid[1] && acMvValid[2]); + } +#endif + Distortion costTemp = m_pcRdCost->getDistPart(predBuf.Y(), pBuf->Y(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, distFunc); uint32_t bitsTemp = ruiBits; bitsTemp += xCalcAffineMVBits(pu, acMvTemp, acMvPred); costTemp = (Distortion)(floor(fWeight * (double)costTemp) + (double)m_pcRdCost->getCost(bitsTemp)); +#if GDR_ENABLED + bool allOk = (costTemp < uiCostBest); + if (isEncodeClean) + { + if (costTempOk) + { + allOk = (uiCostBestOk) ? (costTemp < uiCostBest) : true; + } + else + { + allOk = false; + } + } + + if (allOk) +#else if (costTemp < uiCostBest) +#endif { uiCostBest = costTemp; +#if GDR_ENABLED + if (isEncodeClean) + { + uiCostBestOk = costTempOk; + rbCleanCandExist = true; + } +#endif uiBitsBest = bitsTemp; ::memcpy(acMv, acMvTemp, sizeof(Mv) * 3); modelChange = true; @@ -5814,6 +8778,12 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu, acMvPred[1] = aamvpi.mvCandRT[mvpIdx]; acMvPred[2] = aamvpi.mvCandLB[mvpIdx]; +#if GDR_ENABLED + acMvSolid[0] = aamvpi.mvSolidLT[mvpIdx]; + acMvSolid[1] = aamvpi.mvSolidRT[mvpIdx]; + acMvSolid[2] = aamvpi.mvSolidLB[mvpIdx]; +#endif + ruiBits = uiBitsBest; ruiCost = uiCostBest; DTRACE( g_trace_ctx, D_COMMON, " (%d) uiBitsBest=%d, uiCostBest=%d\n", DTRACE_GET_COUNTER(g_trace_ctx,D_COMMON), uiBitsBest, uiCostBest ); @@ -5831,6 +8801,12 @@ void InterSearch::xEstimateAffineAMVP( PredictionUnit& pu, int iBestIdx = 0; Distortion uiBestCost = std::numeric_limits<Distortion>::max(); +#if GDR_ENABLED + const CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + bool uiBestCostOk = false; +#endif + // Fill the MV Candidates PU::fillAffineMvpCand( pu, eRefPicList, iRefIdx, affineAMVPInfo ); CHECK( affineAMVPInfo.numCand == 0, "Assertion failed." ); @@ -5843,9 +8819,36 @@ void InterSearch::xEstimateAffineAMVP( PredictionUnit& pu, { Mv mv[3] = { affineAMVPInfo.mvCandLT[i], affineAMVPInfo.mvCandRT[i], affineAMVPInfo.mvCandLB[i] }; +#if GDR_ENABLED + bool uiTmpCostOk = true; + Distortion uiTmpCost = xGetAffineTemplateCost(pu, origBuf, predBuf, mv, i, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, uiTmpCostOk); + uiTmpCostOk = uiTmpCostOk && affineAMVPInfo.mvSolidLT[i] && affineAMVPInfo.mvSolidRT[i]; + uiTmpCostOk = uiTmpCostOk && ((pu.cu->affineType == AFFINEMODEL_6PARAM) ? affineAMVPInfo.mvSolidLB[i] : true); +#else Distortion uiTmpCost = xGetAffineTemplateCost( pu, origBuf, predBuf, mv, i, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx ); +#endif + +#if GDR_ENABLED + bool allOk = uiBestCost > uiTmpCost; + + if (isEncodeClean) + { + if (uiTmpCostOk) + { + allOk = uiBestCostOk ? (uiBestCost > uiTmpCost) : true; + } + else + { + allOk = false; + } + } +#endif +#if GDR_ENABLED + if (allOk) +#else if ( uiBestCost > uiTmpCost ) +#endif { uiBestCost = uiTmpCost; bestMvLT = affineAMVPInfo.mvCandLT[i]; @@ -5853,6 +8856,12 @@ void InterSearch::xEstimateAffineAMVP( PredictionUnit& pu, bestMvLB = affineAMVPInfo.mvCandLB[i]; iBestIdx = i; *puiDistBiP = uiTmpCost; +#if GDR_ENABLED + if (isEncodeClean) + { + uiBestCostOk = uiTmpCostOk; + } +#endif } } @@ -5863,6 +8872,10 @@ void InterSearch::xEstimateAffineAMVP( PredictionUnit& pu, pu.mvpIdx[eRefPicList] = iBestIdx; pu.mvpNum[eRefPicList] = affineAMVPInfo.numCand; + +#if GDR_ENABLED + pu.mvpSolid[eRefPicList] = uiBestCostOk; +#endif DTRACE( g_trace_ctx, D_COMMON, "#estAffi=%d \n", affineAMVPInfo.numCand ); } @@ -5873,6 +8886,24 @@ void InterSearch::xCopyAffineAMVPInfo (AffineAMVPInfo& src, AffineAMVPInfo& dst) ::memcpy( dst.mvCandLT, src.mvCandLT, sizeof(Mv)*src.numCand ); ::memcpy( dst.mvCandRT, src.mvCandRT, sizeof(Mv)*src.numCand ); ::memcpy( dst.mvCandLB, src.mvCandLB, sizeof(Mv)*src.numCand ); + +#if GDR_ENABLED + ::memcpy(dst.mvSolidLT, src.mvSolidLT, sizeof(bool)*src.numCand); + ::memcpy(dst.mvSolidRT, src.mvSolidRT, sizeof(bool)*src.numCand); + ::memcpy(dst.mvSolidLB, src.mvSolidLB, sizeof(bool)*src.numCand); + + ::memcpy(dst.mvValidLT, src.mvValidLT, sizeof(bool)*src.numCand); + ::memcpy(dst.mvValidRT, src.mvValidRT, sizeof(bool)*src.numCand); + ::memcpy(dst.mvValidLB, src.mvValidLB, sizeof(bool)*src.numCand); + + ::memcpy(dst.mvTypeLT, src.mvTypeLT, sizeof(MvpType)*src.numCand); + ::memcpy(dst.mvTypeRT, src.mvTypeRT, sizeof(MvpType)*src.numCand); + ::memcpy(dst.mvTypeLB, src.mvTypeLB, sizeof(MvpType)*src.numCand); + + ::memcpy(dst.mvPosLT, src.mvPosLT, sizeof(Position)*src.numCand); + ::memcpy(dst.mvPosRT, src.mvPosRT, sizeof(Position)*src.numCand); + ::memcpy(dst.mvPosLB, src.mvPosLB, sizeof(Position)*src.numCand); +#endif } @@ -7827,11 +10858,19 @@ double InterSearch::xGetMEDistortionWeight(uint8_t bcwIdx, RefPicList eRefPicLis return 0.5; } } +#if GDR_ENABLED +bool InterSearch::xReadBufferedUniMv(PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv& pcMvPred, Mv& rcMv, bool& rcMvSolid, uint32_t& ruiBits, Distortion& ruiCost) +#else bool InterSearch::xReadBufferedUniMv(PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv& pcMvPred, Mv& rcMv, uint32_t& ruiBits, Distortion& ruiCost) +#endif { if (m_uniMotions.isReadMode((uint32_t)eRefPicList, (uint32_t)iRefIdx)) { +#if GDR_ENABLED + m_uniMotions.copyTo(rcMv, rcMvSolid, ruiCost, (uint32_t)eRefPicList, (uint32_t)iRefIdx); +#else m_uniMotions.copyTo(rcMv, ruiCost, (uint32_t)eRefPicList, (uint32_t)iRefIdx); +#endif Mv pred = pcMvPred; pred.changeTransPrecInternal2Amvr(pu.cu->imv); @@ -7849,13 +10888,23 @@ bool InterSearch::xReadBufferedUniMv(PredictionUnit& pu, RefPicList eRefPicList, return false; } +#if GDR_ENABLED +bool InterSearch::xReadBufferedAffineUniMv(PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv acMvPred[3], Mv acMv[3], bool acMvSolid[3], uint32_t& ruiBits, Distortion& ruiCost + , int& mvpIdx, const AffineAMVPInfo& aamvpi +) +#else bool InterSearch::xReadBufferedAffineUniMv(PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv acMvPred[3], Mv acMv[3], uint32_t& ruiBits, Distortion& ruiCost , int& mvpIdx, const AffineAMVPInfo& aamvpi ) +#endif { if (m_uniMotions.isReadModeAffine((uint32_t)eRefPicList, (uint32_t)iRefIdx, pu.cu->affineType)) { +#if GDR_ENABLED + m_uniMotions.copyAffineMvTo(acMv, acMvSolid, ruiCost, (uint32_t)eRefPicList, (uint32_t)iRefIdx, pu.cu->affineType, mvpIdx); +#else m_uniMotions.copyAffineMvTo(acMv, ruiCost, (uint32_t)eRefPicList, (uint32_t)iRefIdx, pu.cu->affineType, mvpIdx); +#endif m_pcRdCost->setCostScale(0); acMvPred[0] = aamvpi.mvCandLT[mvpIdx]; acMvPred[1] = aamvpi.mvCandRT[mvpIdx]; @@ -7921,13 +10970,32 @@ uint32_t InterSearch::xDetermineBestMvp( PredictionUnit& pu, Mv acMvTemp[3], int { bool mvpUpdated = false; uint32_t minBits = std::numeric_limits<uint32_t>::max(); +#if GDR_ENABLED + const CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif + for ( int i = 0; i < aamvpi.numCand; i++ ) { Mv mvPred[3] = { aamvpi.mvCandLT[i], aamvpi.mvCandRT[i], aamvpi.mvCandLB[i] }; uint32_t candBits = m_auiMVPIdxCost[i][aamvpi.numCand]; candBits += xCalcAffineMVBits( pu, acMvTemp, mvPred ); +#if GDR_ENABLED + bool isSolid = true; + if (isEncodeClean) + { + isSolid = aamvpi.mvSolidLT[i] && aamvpi.mvSolidRT[i]; + if (pu.cu->affineType == AFFINEMODEL_6PARAM) + { + isSolid = isSolid && aamvpi.mvSolidLB[i]; + } + } + + if ((candBits < minBits) && isSolid) +#else if ( candBits < minBits ) +#endif { minBits = candBits; mvpIdx = i; @@ -7946,11 +11014,22 @@ void InterSearch::symmvdCheckBestMvp( AMVPInfo amvpInfo[2][33], int32_t bcwIdx, Mv cMvPredSym[2], +#if GDR_ENABLED + bool cMvPredSymSolid[2], +#endif int32_t mvpIdxSym[2], Distortion& bestCost, bool skip ) { +#if GDR_ENABLED + CodingStructure &cs = *pu.cs; + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); + bool bestCostOk = true; + bool costOk = true; + bool allOk; +#endif + RefPicList tarRefList = (RefPicList)(1 - curRefList); int32_t refIdxCur = pu.cu->slice->getSymRefIdx(curRefList); int32_t refIdxTar = pu.cu->slice->getSymRefIdx(tarRefList); @@ -8028,11 +11107,48 @@ void InterSearch::symmvdCheckBestMvp( bits += m_auiMVPIdxCost[i][AMVP_MAX_NUM_CANDS]; bits += m_auiMVPIdxCost[j][AMVP_MAX_NUM_CANDS]; cost += m_pcRdCost->getCost(bits); +#if GDR_ENABLED + if (isEncodeClean) + { + bool curSolid = amvpCur.mvSolid[i]; + bool tarSolid = amvpTar.mvSolid[j]; + costOk = curSolid && tarSolid; + } +#endif + + +#if GDR_ENABLED + allOk = (cost < bestCost); + if (isEncodeClean) + { + if (costOk) + { + allOk = (bestCostOk) ? (cost < bestCost) : true; + } + else + { + allOk = false; + } + } +#endif + +#if GDR_ENABLED + if (allOk) +#else if (cost < bestCost) +#endif { bestCost = cost; cMvPredSym[curRefList] = amvpCur.mvCand[i]; cMvPredSym[tarRefList] = amvpTar.mvCand[j]; +#if GDR_ENABLED + if (isEncodeClean) + { + bestCostOk = costOk; + cMvPredSymSolid[curRefList] = amvpCur.mvSolid[i]; + cMvPredSymSolid[tarRefList] = amvpTar.mvSolid[j]; + } +#endif mvpIdxSym[curRefList] = i; mvpIdxSym[tarRefList] = j; } diff --git a/source/Lib/EncoderLib/InterSearch.h b/source/Lib/EncoderLib/InterSearch.h index 51800ad05db6281e4e1f5c150f4d7ef23adf9653..1296420265ed62999fd1a21ef9f2df60c1f3136a 100644 --- a/source/Lib/EncoderLib/InterSearch.h +++ b/source/Lib/EncoderLib/InterSearch.h @@ -77,6 +77,12 @@ struct AffineMVInfo int x, y, w, h; }; +#if GDR_ENABLED +struct AffineMVInfoSolid +{ + bool affMVsSolid[2][33][3]; +}; +#endif struct BlkUniMvInfo { Mv uniMvs[2][33]; @@ -93,6 +99,11 @@ typedef struct Distortion affineCost[3]; bool affine4ParaAvail; bool affine6ParaAvail; + +#if GDR_ENABLED + bool acMvAffine4ParaSolid[2][3]; + bool acMvAffine6ParaSolid[2][3]; +#endif } EncAffineMotion; /// encoder search class @@ -118,6 +129,9 @@ private: bool m_affineModeSelected; std::unordered_map< Position, std::unordered_map< Size, BlkRecord> > m_ctuRecord; AffineMVInfo *m_affMVList; +#if GDR_ENABLED + AffineMVInfoSolid *m_affMVListSolid; +#endif int m_affMVListIdx; int m_affMVListSize; int m_affMVListMaxSize; @@ -126,6 +140,9 @@ private: int m_uniMvListSize; int m_uniMvListMaxSize; Distortion m_hevcCost; +#if GDR_ENABLED + bool m_hevcCostOk; +#endif EncAffineMotion m_affineMotion; PatentBvCand m_defaultCachedBvs; protected: @@ -208,33 +225,63 @@ public: void resetCtuRecord () { m_ctuRecord.clear(); } void setAffineModeSelected ( bool flag) { m_affineModeSelected = flag; } void resetAffineMVList() { m_affMVListIdx = 0; m_affMVListSize = 0; } +#if GDR_ENABLED + void savePrevAffMVInfo(int idx, AffineMVInfo &tmpMVInfo, AffineMVInfoSolid &tmpMVInfoSolid, bool& isSaved) +#else void savePrevAffMVInfo(int idx, AffineMVInfo &tmpMVInfo, bool& isSaved) +#endif { if (m_affMVListSize > idx) { tmpMVInfo = m_affMVList[(m_affMVListIdx - 1 - idx + m_affMVListMaxSize) % m_affMVListMaxSize]; +#if GDR_ENABLED + tmpMVInfoSolid = m_affMVListSolid[(m_affMVListIdx - 1 - idx + m_affMVListMaxSize) % m_affMVListMaxSize]; +#endif isSaved = true; } else isSaved = false; } +#if GDR_ENABLED + void addAffMVInfo(AffineMVInfo &tmpMVInfo, AffineMVInfoSolid &tmpMVInfoSolid) +#else void addAffMVInfo(AffineMVInfo &tmpMVInfo) +#endif { int j = 0; AffineMVInfo *prevInfo = nullptr; +#if GDR_ENABLED + AffineMVInfoSolid *prevInfoSolid = nullptr; +#endif for (; j < m_affMVListSize; j++) { prevInfo = m_affMVList + ((m_affMVListIdx - j - 1 + m_affMVListMaxSize) % (m_affMVListMaxSize)); +#if GDR_ENABLED + prevInfoSolid = m_affMVListSolid + ((m_affMVListIdx - j - 1 + m_affMVListMaxSize) % (m_affMVListMaxSize)); +#endif if ((tmpMVInfo.x == prevInfo->x) && (tmpMVInfo.y == prevInfo->y) && (tmpMVInfo.w == prevInfo->w) && (tmpMVInfo.h == prevInfo->h)) { break; } } +#if GDR_ENABLED if (j < m_affMVListSize) + { *prevInfo = tmpMVInfo; + *prevInfoSolid = tmpMVInfoSolid; + } +#else + if (j < m_affMVListSize) + { + *prevInfo = tmpMVInfo; + } +#endif else { m_affMVList[m_affMVListIdx] = tmpMVInfo; +#if GDR_ENABLED + m_affMVListSolid[m_affMVListIdx] = tmpMVInfoSolid; +#endif m_affMVListIdx = (m_affMVListIdx + 1) % m_affMVListMaxSize; m_affMVListSize = std::min(m_affMVListSize + 1, m_affMVListMaxSize); } @@ -312,13 +359,21 @@ public: } } void resetSavedAffineMotion(); +#if GDR_ENABLED + void storeAffineMotion(Mv acAffineMv[2][3], bool acAffineMvSolid[2][3], int16_t affineRefIdx[2], EAffineModel affineType, int bcwIdx); +#else void storeAffineMotion( Mv acAffineMv[2][3], int16_t affineRefIdx[2], EAffineModel affineType, int bcwIdx ); +#endif bool searchBv(PredictionUnit& pu, int xPos, int yPos, int width, int height, int picWidth, int picHeight, int xBv, int yBv, int ctuSize); void setClipMvInSubPic(bool flag) { m_clipMvInSubPic = flag; } protected: /// sub-function for motion vector refinement used in fractional-pel accuracy +#if GDR_ENABLED + Distortion xPatternRefinement(const PredictionUnit& pu, RefPicList eRefPicList, int iRefIdx, const CPelBuf* pcPatternKey, Mv baseRefMv, int iFrac, Mv& rcMvFrac, bool bAllowUseOfHadamard, bool& rbCleanCandExist); +#else Distortion xPatternRefinement ( const CPelBuf* pcPatternKey, Mv baseRefMv, int iFrac, Mv& rcMvFrac, bool bAllowUseOfHadamard ); +#endif typedef struct { @@ -400,6 +455,20 @@ protected: Distortion* puiDistBiP = NULL ); + #if GDR_ENABLED + void xCheckBestMVP( + PredictionUnit &pu, + RefPicList eRefPicList, + Mv cMv, + Mv& rcMvPred, + int& riMVPIdx, + AMVPInfo& amvpInfo, + uint32_t& ruiBits, + Distortion& ruiCost + , + const uint8_t imv + ); +#else void xCheckBestMVP ( RefPicList eRefPicList, Mv cMv, Mv& rcMvPred, @@ -410,6 +479,7 @@ protected: , const uint8_t imv ); +#endif Distortion xGetTemplateCost ( const PredictionUnit& pu, PelUnitBuf& origBuf, @@ -432,6 +502,22 @@ protected: // motion estimation // ------------------------------------------------------------------------------------------------------------------- +#if GDR_ENABLED + void xMotionEstimation ( PredictionUnit& pu, + PelUnitBuf& origBuf, + RefPicList eRefPicList, + Mv& rcMvPred, + int iRefIdxPred, + Mv& rcMv, + bool& rcMvSolid, + int& riMVPIdx, + uint32_t& ruiBits, + Distortion& ruiCost, + const AMVPInfo& amvpInfo, + bool& rbCleanCandExist, + bool bBi = false + ); +#else void xMotionEstimation ( PredictionUnit& pu, PelUnitBuf& origBuf, RefPicList eRefPicList, @@ -444,7 +530,7 @@ protected: const AMVPInfo& amvpInfo, bool bBi = false ); - +#endif void xTZSearch ( const PredictionUnit& pu, RefPicList eRefPicList, int iRefIdxPred, @@ -470,6 +556,10 @@ protected: const int iSrchRng, SearchRange& sr , IntTZSearchStruct & cStruct +#if GDR_ENABLED + , RefPicList eRefPicList + , int iRefIdx +#endif ); void xPatternSearchFast ( const PredictionUnit& pu, @@ -495,6 +585,11 @@ protected: Distortion& ruiCost, const AMVPInfo& amvpInfo, double fWeight +#if GDR_ENABLED + ,RefPicList eRefPicList + ,int iRefIdxPred + , bool& rbCleanCandExist +#endif ); void xPatternSearchFracDIF ( const PredictionUnit& pu, @@ -505,6 +600,9 @@ protected: Mv& rcMvHalf, Mv& rcMvQter, Distortion& ruiCost +#if GDR_ENABLED + ,bool& rbCleanCandExist +#endif ); void xPredAffineInterSearch ( PredictionUnit& pu, @@ -513,13 +611,35 @@ protected: uint32_t& lastMode, Distortion& affineCost, Mv hevcMv[2][33] +#if GDR_ENABLED + , bool hevcMvSolid[2][33] +#endif , Mv mvAffine4Para[2][33][3] +#if GDR_ENABLED + , bool mvAffine4ParaSolid[2][33][3] +#endif , int refIdx4Para[2] , uint8_t bcwIdx = BCW_DEFAULT , bool enforceBcwPred = false , uint32_t bcwIdxBits = 0 ); +#if GDR_ENABLED + void xAffineMotionEstimation ( PredictionUnit& pu, + PelUnitBuf& origBuf, + RefPicList eRefPicList, + Mv acMvPred[3], + int iRefIdxPred, + Mv acMv[3], + bool acMvSolid[3], + uint32_t& ruiBits, + Distortion& ruiCost, + int& mvpIdx, + const AffineAMVPInfo& aamvpi, + bool& rbCleanCandExist, + bool bBi = false + ); +#else void xAffineMotionEstimation ( PredictionUnit& pu, PelUnitBuf& origBuf, RefPicList eRefPicList, @@ -532,6 +652,7 @@ protected: const AffineAMVPInfo& aamvpi, bool bBi = false ); +#endif void xEstimateAffineAMVP ( PredictionUnit& pu, AffineAMVPInfo& affineAMVPInfo, @@ -542,23 +663,50 @@ protected: Distortion* puiDistBiP ); +#if GDR_ENABLED + Distortion xGetAffineTemplateCost(PredictionUnit& pu, PelUnitBuf& origBuf, PelUnitBuf& predBuf, Mv acMvCand[3], int iMVPIdx, int iMVPNum, RefPicList eRefPicList, int iRefIdx, bool& rbOk); +#else Distortion xGetAffineTemplateCost( PredictionUnit& pu, PelUnitBuf& origBuf, PelUnitBuf& predBuf, Mv acMvCand[3], int iMVPIdx, int iMVPNum, RefPicList eRefPicList, int iRefIdx ); +#endif void xCopyAffineAMVPInfo ( AffineAMVPInfo& src, AffineAMVPInfo& dst ); void xCheckBestAffineMVP ( PredictionUnit &pu, AffineAMVPInfo &affineAMVPInfo, RefPicList eRefPicList, Mv acMv[3], Mv acMvPred[3], int& riMVPIdx, uint32_t& ruiBits, Distortion& ruiCost ); Distortion xGetSymmetricCost( PredictionUnit& pu, PelUnitBuf& origBuf, RefPicList eCurRefPicList, const MvField& cCurMvField, MvField& cTarMvField , int bcwIdx ); +#if GDR_ENABLED + Distortion xSymmeticRefineMvSearch( + PredictionUnit& pu, PelUnitBuf& origBuf, + Mv& rcMvCurPred, Mv& rcMvTarPred, + RefPicList eRefPicList, MvField& rCurMvField, MvField& rTarMvField, + Distortion uiMinCost, int searchPattern, int nSearchStepShift, uint32_t uiMaxSearchRounds , int bcwIdx, bool& rbOk ); +#else Distortion xSymmeticRefineMvSearch( PredictionUnit& pu, PelUnitBuf& origBuf, Mv& rcMvCurPred, Mv& rcMvTarPred , RefPicList eRefPicList, MvField& rCurMvField, MvField& rTarMvField, Distortion uiMinCost, int searchPattern, int nSearchStepShift, uint32_t uiMaxSearchRounds , int bcwIdx ); +#endif +#if GDR_ENABLED + bool xSymmetricMotionEstimation( PredictionUnit& pu, PelUnitBuf& origBuf, Mv& rcMvCurPred, Mv& rcMvTarPred, + RefPicList eRefPicList, MvField& rCurMvField, MvField& rTarMvField, Distortion& ruiCost, int bcwIdx, bool& ruiCostOk ); +#else void xSymmetricMotionEstimation( PredictionUnit& pu, PelUnitBuf& origBuf, Mv& rcMvCurPred, Mv& rcMvTarPred, RefPicList eRefPicList, MvField& rCurMvField, MvField& rTarMvField, Distortion& ruiCost, int bcwIdx ); +#endif +#if GDR_ENABLED + bool xReadBufferedAffineUniMv(PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv acMvPred[3], Mv acMv[3], bool acMvSolid[3], uint32_t& ruiBits, Distortion& ruiCost + , int& mvpIdx, const AffineAMVPInfo& aamvpi + ); +#else bool xReadBufferedAffineUniMv ( PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv acMvPred[3], Mv acMv[3], uint32_t& ruiBits, Distortion& ruiCost , int& mvpIdx, const AffineAMVPInfo& aamvpi ); +#endif double xGetMEDistortionWeight ( uint8_t bcwIdx, RefPicList eRefPicList); +#if GDR_ENABLED + bool xReadBufferedUniMv (PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv& pcMvPred, Mv& rcMv, bool& rcMvSolid, uint32_t& ruiBits, Distortion& ruiCost); +#else bool xReadBufferedUniMv ( PredictionUnit& pu, RefPicList eRefPicList, int32_t iRefIdx, Mv& pcMvPred, Mv& rcMv, uint32_t& ruiBits, Distortion& ruiCost); +#endif void xClipMv ( Mv& rcMv, const struct Position& pos, const struct Size& size, const class SPS& sps, const class PPS& pps ); @@ -574,6 +722,9 @@ public: AMVPInfo amvpInfo[2][33], int32_t bcwIdx, Mv cMvPredSym[2], +#if GDR_ENABLED + bool cMvPredSymSolid[2], +#endif int32_t mvpIdxSym[2], Distortion& bestCost, bool skip = false diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index 890251ec1f39f83e03efd64026710a4e56b81384..e715da7a99ea87e028443910c8eabcca521d1282 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -367,6 +367,191 @@ double IntraSearch::findInterCUCost( CodingUnit &cu ) return COST_UNKNOWN; } +#if GDR_ENABLED +int IntraSearch::getNumTopRecons(PredictionUnit &pu, int luma_dirMode, bool isChroma) +{ + int w = isChroma ? pu.Cb().width : pu.Y().width; + int h = isChroma ? pu.Cb().height : pu.Y().height; + + int numOfTopRecons = w; + + static const int angTable[32] = { 0, 1, 2, 3, 4, 6, 8, 10, 12, 14, 16, 18, 20, 23, 26, 29, 32, 35, 39, 45, 51, 57, 64, 73, 86, 102, 128, 171, 256, 341, 512, 1024 }; + static const int invAngTable[32] = { + 0, 16384, 8192, 5461, 4096, 2731, 2048, 1638, 1365, 1170, 1024, 910, 819, 712, 630, 565, + 512, 468, 420, 364, 321, 287, 256, 224, 191, 161, 128, 96, 64, 48, 32, 16 + }; // (512 * 32) / Angle + + const int refIdx = pu.multiRefIdx; + const int predModeIntra = getModifiedWideAngle(w, h, luma_dirMode); + const int isModeVer = predModeIntra >= DIA_IDX; + const int intraPredAngleMode = (isModeVer) ? predModeIntra - VER_IDX : -(predModeIntra - HOR_IDX); + + const int absAngMode = abs(intraPredAngleMode); + const int signAng = intraPredAngleMode < 0 ? -1 : 1; + const int absAng = (luma_dirMode > DC_IDX && luma_dirMode < NUM_LUMA_MODE) ? angTable[absAngMode] : 0; + + const int invAngle = invAngTable[absAngMode]; + const int intraPredAngle = signAng * absAng; + + const int sideSize = isModeVer ? h : w; + const int maxScale = 2; + + const int angularScale = std::min(maxScale, floorLog2(sideSize) - (floorLog2(3 * invAngle - 2) - 8));; + + bool applyPDPC; + + + // 1.0 derive PDPC + applyPDPC = (refIdx == 0) ? true : false; + if (luma_dirMode > DC_IDX && luma_dirMode < NUM_LUMA_MODE) + { + if (intraPredAngleMode < 0) + { + applyPDPC &= false; + } + else if (intraPredAngleMode > 0) + { + applyPDPC &= (angularScale >= 0); + } + } + + // 2.0 calculate number of recons + switch (luma_dirMode) + { + case PLANAR_IDX: + numOfTopRecons = applyPDPC ? (w + 1) : (w + 1); + break; + + case DC_IDX: + numOfTopRecons = applyPDPC ? (w) : (w); + break; + + case HOR_IDX: + numOfTopRecons = applyPDPC ? (w) : (w); + break; + + case VER_IDX: + numOfTopRecons = applyPDPC ? (w) : (w); + break; + + default: + // 2..66 + // note: There should be a way to reduce the number of top recons, in case of non PDPC + applyPDPC |= isChroma; + + if (predModeIntra >= DIA_IDX) + { + if (intraPredAngle < 0) + { + numOfTopRecons = (applyPDPC) ? (w + w) : (w + 1); + } + else + { + numOfTopRecons = (applyPDPC) ? (w + w) : (w + w); + } + } + else + { + if (intraPredAngle < 0) + { + numOfTopRecons = (applyPDPC) ? (w + w) : (w); + } + else + { + numOfTopRecons = (applyPDPC) ? (w + w) : (w); + } + } + break; + } + + return numOfTopRecons; +} + +bool IntraSearch::isValidIntraPredLuma(PredictionUnit &pu, int luma_dirMode) +{ + bool isValid = true; + PicHeader *ph = pu.cs->picHeader; + + if (ph->getInGdrPeriod()) + { + int x = pu.Y().x; + + // count num of recons on the top + int virX = ph->getVirtualBoundariesPosX(0); + int numOfTopRecons = getNumTopRecons(pu, luma_dirMode, false); + + // check if recon is out of boundary + if (x < virX && virX < (x + numOfTopRecons)) + { + isValid = false; + } + } + + return isValid; +} + +bool IntraSearch::isValidIntraPredChroma(PredictionUnit &pu, int luma_dirMode, int chroma_dirMode) +{ + bool isValid = true; + CodingStructure *cs = pu.cs; + PicHeader *ph = cs->picHeader; + + if (ph->getInGdrPeriod()) + { + // note: chroma cordinate + int cbX = pu.Cb().x; + //int cbY = pu.Cb().y; + int cbW = pu.Cb().width; + int cbH = pu.Cb().height; + + int chromaScaleX = getComponentScaleX(COMPONENT_Cb, cs->area.chromaFormat); + int chromaScaleY = getComponentScaleY(COMPONENT_Cb, cs->area.chromaFormat); + + int lumaX = cbX << chromaScaleX; + // int lumaY = cbY << chromaScaleY; + int lumaW = cbW << chromaScaleX; + int lumaH = cbH << chromaScaleY; + + int numOfTopRecons = lumaW; + int virX = ph->getVirtualBoundariesPosX(0); + + // count num of recons on the top + switch (chroma_dirMode) + { + + case LM_CHROMA_IDX : + numOfTopRecons = lumaW; + break; + + case MDLM_L_IDX : + numOfTopRecons = lumaW; + break; + + // note: could reduce the actual #of + case MDLM_T_IDX: + numOfTopRecons = (lumaW + lumaH); + break; + + case DM_CHROMA_IDX : + numOfTopRecons = getNumTopRecons(pu, luma_dirMode, true) << chromaScaleX; + break; + + default : + numOfTopRecons = getNumTopRecons(pu, chroma_dirMode, true) << chromaScaleX; + break; + } + + // check if recon is out of boundary + if (lumaX < virX && virX < (lumaX + numOfTopRecons)) + { + isValid = false; + } + } + + return isValid; +} +#endif + bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, const double bestCostSoFar, bool mtsCheckRangeFlag, int mtsFirstCheckId, int mtsLastCheckId, bool moreProbMTSIdxFirst, CodingStructure* bestCS) { CodingStructure &cs = *cu.cs; @@ -452,6 +637,9 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c static_vector<double, FAST_UDI_MAX_RDMODE_NUM> CandHadList; auto &pu = *cu.firstPU; +#if GDR_ENABLED + const bool isEncodeClean = cs.pcv->isEncoder && ((cs.picHeader->getInGdrPeriod() && cs.isClean(pu.Y().topRight(), CHANNEL_TYPE_LUMA)) || (cs.picHeader->getNumVerVirtualBoundaries() == 0)); +#endif bool validReturn = false; { CandHadList.clear(); @@ -586,10 +774,30 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c DTRACE(g_trace_ctx, D_INTRA_COST, "IntraHAD: %u, %llu, %f (%d)\n", minSadHad, fracModeBits, cost, uiMode); +#if GDR_ENABLED + if (isEncodeClean) + { + if (isValidIntraPredLuma(pu, uiMode)) + { + updateCandList(ModeInfo(false, false, 0, NOT_INTRA_SUBPARTITIONS, uiMode), cost, uiRdModeList, + CandCostList, numModesForFullRD); + updateCandList(ModeInfo(false, false, 0, NOT_INTRA_SUBPARTITIONS, uiMode), double(minSadHad), uiHadModeList, + CandHadList, numHadCand); + } + } + else + { + updateCandList(ModeInfo(false, false, 0, NOT_INTRA_SUBPARTITIONS, uiMode), cost, uiRdModeList, + CandCostList, numModesForFullRD); + updateCandList(ModeInfo(false, false, 0, NOT_INTRA_SUBPARTITIONS, uiMode), double(minSadHad), + uiHadModeList, CandHadList, numHadCand); + } +#else updateCandList(ModeInfo(false, false, 0, NOT_INTRA_SUBPARTITIONS, uiMode), cost, uiRdModeList, CandCostList, numModesForFullRD); updateCandList(ModeInfo(false, false, 0, NOT_INTRA_SUBPARTITIONS, uiMode), double(minSadHad), uiHadModeList, CandHadList, numHadCand); +#endif } if (!sps.getUseMIP() && LFNSTSaveFlag) { @@ -619,7 +827,17 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> parentCandList = uiRdModeList; // Second round of SATD for extended Angular modes +#if GDR_ENABLED + int nn = numModesForFullRD; + if (isEncodeClean) + { + nn = std::min((int)numModesForFullRD, (int)parentCandList.size()); + } + + for (int modeIdx = 0; modeIdx < nn; modeIdx++) +#else for (int modeIdx = 0; modeIdx < numModesForFullRD; modeIdx++) +#endif { unsigned parentMode = parentCandList[modeIdx].modeId; if (parentMode > (DC_IDX + 1) && parentMode < (NUM_LUMA_MODE - 1)) @@ -652,10 +870,30 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c double cost = (double) minSadHad + (double) fracModeBits * sqrtLambdaForFirstPass; +#if GDR_ENABLED + if (isEncodeClean) + { + if (isValidIntraPredLuma(pu, mode)) + { + updateCandList(ModeInfo(false, false, 0, NOT_INTRA_SUBPARTITIONS, mode), cost, uiRdModeList, + CandCostList, numModesForFullRD); + updateCandList(ModeInfo(false, false, 0, NOT_INTRA_SUBPARTITIONS, mode), double(minSadHad), + uiHadModeList, CandHadList, numHadCand); + } + } + else + { + updateCandList(ModeInfo(false, false, 0, NOT_INTRA_SUBPARTITIONS, mode), cost, uiRdModeList, + CandCostList, numModesForFullRD); + updateCandList(ModeInfo(false, false, 0, NOT_INTRA_SUBPARTITIONS, mode), double(minSadHad), + uiHadModeList, CandHadList, numHadCand); + } +#else updateCandList(ModeInfo(false, false, 0, NOT_INTRA_SUBPARTITIONS, mode), cost, uiRdModeList, CandCostList, numModesForFullRD); updateCandList(ModeInfo(false, false, 0, NOT_INTRA_SUBPARTITIONS, mode), double(minSadHad), uiHadModeList, CandHadList, numHadCand); +#endif bSatdChecked[mode] = true; } @@ -703,14 +941,41 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c uint64_t fracModeBits = xFracModeBitsIntra(pu, mode, CHANNEL_TYPE_LUMA); double cost = (double) minSadHad + (double) fracModeBits * sqrtLambdaForFirstPass; +#if GDR_ENABLED + if (isEncodeClean) + { + if (isValidIntraPredLuma(pu, mode)) + { + updateCandList(ModeInfo(false, false, multiRefIdx, NOT_INTRA_SUBPARTITIONS, mode), cost, uiRdModeList, + CandCostList, numModesForFullRD); + updateCandList(ModeInfo(false, false, multiRefIdx, NOT_INTRA_SUBPARTITIONS, mode), double(minSadHad), + uiHadModeList, CandHadList, numHadCand); + } + } + else + { + updateCandList(ModeInfo(false, false, multiRefIdx, NOT_INTRA_SUBPARTITIONS, mode), cost, uiRdModeList, + CandCostList, numModesForFullRD); + updateCandList(ModeInfo(false, false, multiRefIdx, NOT_INTRA_SUBPARTITIONS, mode), double(minSadHad), + uiHadModeList, CandHadList, numHadCand); + } +#else updateCandList(ModeInfo(false, false, multiRefIdx, NOT_INTRA_SUBPARTITIONS, mode), cost, uiRdModeList, CandCostList, numModesForFullRD); updateCandList(ModeInfo(false, false, multiRefIdx, NOT_INTRA_SUBPARTITIONS, mode), double(minSadHad), uiHadModeList, CandHadList, numHadCand); +#endif } } } +#if GDR_ENABLED + if (!isEncodeClean) + { + CHECKD(uiRdModeList.size() != numModesForFullRD, "Error: RD mode list size"); + } +#else CHECKD(uiRdModeList.size() != numModesForFullRD, "Error: RD mode list size"); +#endif if (LFNSTSaveFlag && testMip && !allowLfnstWithMip(cu.firstPU->lumaSize())) // save a different set for the next run @@ -781,10 +1046,30 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c DTRACE(g_trace_ctx, D_INTRA_COST, "IntraMIP: %u, %llu, %f (%d)\n", minSadHad, fracModeBits, cost, uiModeFull); +#if GDR_ENABLED + if (isEncodeClean) + { + if (isValidIntraPredLuma(pu, uiMode)) + { + updateCandList(ModeInfo(true, isTransposed, 0, NOT_INTRA_SUBPARTITIONS, uiMode), cost, uiRdModeList, + CandCostList, numModesForFullRD + 1); + updateCandList(ModeInfo(true, isTransposed, 0, NOT_INTRA_SUBPARTITIONS, uiMode), + 0.8 * double(minSadHad), uiHadModeList, CandHadList, numHadCand); + } + } + else + { + updateCandList(ModeInfo(true, isTransposed, 0, NOT_INTRA_SUBPARTITIONS, uiMode), cost, uiRdModeList, + CandCostList, numModesForFullRD + 1); + updateCandList(ModeInfo(true, isTransposed, 0, NOT_INTRA_SUBPARTITIONS, uiMode), + 0.8 * double(minSadHad), uiHadModeList, CandHadList, numHadCand); + } +#else updateCandList(ModeInfo(true, isTransposed, 0, NOT_INTRA_SUBPARTITIONS, uiMode), cost, uiRdModeList, CandCostList, numModesForFullRD + 1); updateCandList(ModeInfo(true, isTransposed, 0, NOT_INTRA_SUBPARTITIONS, uiMode), 0.8 * double(minSadHad), uiHadModeList, CandHadList, numHadCand); +#endif } const double thresholdHadCost = 1.0 + 1.4 / sqrt((double) (pu.lwidth() * pu.lheight())); @@ -828,16 +1113,38 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c bool mostProbableModeIncluded = false; ModeInfo mostProbableMode( false, false, 0, NOT_INTRA_SUBPARTITIONS, uiPreds[j] ); +#if GDR_ENABLED + int nn = numModesForFullRD; + if (isEncodeClean) + { + nn = std::min((int)numModesForFullRD, (int)uiRdModeList.size()); + } + + for (int i = 0; i < nn; i++) +#else for (int i = 0; i < numModesForFullRD; i++) +#endif { mostProbableModeIncluded |= (mostProbableMode == uiRdModeList[i]); } +#if GDR_ENABLED + if (!isEncodeClean) + { + if (!mostProbableModeIncluded) + { + numModesForFullRD++; + uiRdModeList.push_back(mostProbableMode); + CandCostList.push_back(0); + } + } +#else if (!mostProbableModeIncluded) { numModesForFullRD++; uiRdModeList.push_back(mostProbableMode); CandCostList.push_back(0); } +#endif } if (saveDataForISP) { @@ -851,10 +1158,20 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c { mostProbableModeIncluded |= (mostProbableMode == m_ispCandListHor[i]); } +#if GDR_ENABLED + if (!isEncodeClean) + { + if (!mostProbableModeIncluded) + { + m_ispCandListHor.push_back(mostProbableMode); + } + } +#else if (!mostProbableModeIncluded) { m_ispCandListHor.push_back(mostProbableMode); } +#endif } } } @@ -899,7 +1216,14 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c } } +#if GDR_ENABLED + if (!isEncodeClean) + { + CHECK(numModesForFullRD != uiRdModeList.size(), "Inconsistent state!"); + } +#else CHECK(numModesForFullRD != uiRdModeList.size(), "Inconsistent state!"); +#endif // after this point, don't use numModesForFullRD @@ -965,12 +1289,24 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c if ( testISP ) { // we reserve positions for ISP in the common full RD list +#if GDR_ENABLED + if (!isEncodeClean) + { + const int maxNumRDModesISP = sps.getUseLFNST() ? 16 * NUM_LFNST_NUM_PER_SET : 16; + m_curIspLfnstIdx = 0; + for (int i = 0; i < maxNumRDModesISP; i++) + { + uiRdModeList.push_back(ModeInfo(false, false, 0, INTRA_SUBPARTITIONS_RESERVED, 0)); + } + } +#else const int maxNumRDModesISP = sps.getUseLFNST() ? 16 * NUM_LFNST_NUM_PER_SET : 16; m_curIspLfnstIdx = 0; for (int i = 0; i < maxNumRDModesISP; i++) { uiRdModeList.push_back( ModeInfo( false, false, 0, INTRA_SUBPARTITIONS_RESERVED, 0 ) ); } +#endif } //===== check modes (using r-d costs) ===== @@ -1462,7 +1798,11 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner double dCost = m_pcRdCost->calcRdCost( fracBits, uiDist - baseDist ); //----- compare ----- +#if GDR_ENABLED + if (dCost < dBestCost && isValidIntraPredChroma(pu, (int)PU::getCoLocatedIntraLumaMode(pu), chromaIntraMode)) +#else if( dCost < dBestCost ) +#endif { if( lumaUsesISP && dCost < bestCostSoFar ) { diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index 8f53122f3792bcb53eacbd25ddbc0e7c1abd4861..a1feb824c894bed1cdbed2790cd3eed5550d109c 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -440,6 +440,11 @@ public: void invalidateBestRdModeFirstColorSpace(); void setSavedRdModeIdx(int idx) { m_savedRdModeIdx = idx; } +#if GDR_ENABLED + int getNumTopRecons(PredictionUnit &pu, int luma_dirMode, bool isChroma); + bool isValidIntraPredLuma(PredictionUnit &pu, int luma_dirMode); + bool isValidIntraPredChroma(PredictionUnit &pu, int luma_dirMode, int chroma_dirMode); +#endif protected: // ------------------------------------------------------------------------------------------------------------------- diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 8e8ded9717e15f6600c4819b67b662bcc4b0b44f..33c5d432665d694509ecb0097090e5ac374e4c1f 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -1578,6 +1578,11 @@ WRITE_FLAG(picHeader->getGdrOrIrapPicFlag(), "ph_gdr_or_irap_pic_flag"); { picHeader->setRecoveryPocCnt( -1 ); } +#if GDR_ENC_TRACE + printf("-gdr_pic_flag:%d\n", picHeader->getGdrPicFlag()); + printf("-recovery_poc_cnt:%d\n", picHeader->getRecoveryPocCnt()); + printf("-InGdrPeriod:%d\n", picHeader->getInGdrPeriod()); +#endif // PH extra bits are not written in the reference encoder // as these bits are reserved for future extensions // for( i = 0; i < NumExtraPhBits; i++ ) @@ -1673,6 +1678,10 @@ WRITE_FLAG(picHeader->getGdrOrIrapPicFlag(), "ph_gdr_or_irap_pic_flag"); picHeader->setLmcsEnabledFlag(false); picHeader->setLmcsChromaResidualScaleFlag(false); } +#if GDR_ENC_TRACE + printf("-pic_lmcs_enabled_flag:%d\n", picHeader->getLmcsEnabledFlag() ? 1 : 0); + printf("-pic_chroma_residual_scale_flag:%d\n", picHeader->getLmcsChromaResidualScaleFlag() ? 1 : 0); +#endif // quantization scaling lists if( sps->getScalingListFlag() ) @@ -1696,6 +1705,37 @@ WRITE_FLAG(picHeader->getGdrOrIrapPicFlag(), "ph_gdr_or_irap_pic_flag"); WRITE_FLAG( picHeader->getVirtualBoundariesPresentFlag(), "ph_virtual_boundaries_present_flag" ); if( picHeader->getVirtualBoundariesPresentFlag() ) { + +#if GDR_ENABLED + int n = picHeader->getNumVerVirtualBoundaries(); + for (unsigned i = 0; i < n; i++) + { + if (picHeader->getVirtualBoundariesPosX(i) == pps->getPicWidthInLumaSamples()) + { + n = n - 1; + } + } + + WRITE_UVLC(n, "ph_num_ver_virtual_boundaries"); + + if (pps->getPicWidthInLumaSamples() <= 8) + { + CHECK(picHeader->getNumVerVirtualBoundaries() != 0, "PH: When picture width is less than or equal to 8, the number of vertical virtual boundaries shall be equal to 0"); + } + else + { + CHECK(picHeader->getNumVerVirtualBoundaries() > 3, "PH: The number of vertical virtual boundaries shall be in the range of 0 to 3"); + } + + for (unsigned i = 0; i < picHeader->getNumVerVirtualBoundaries(); i++) + { + if (picHeader->getVirtualBoundariesPosX(i) != pps->getPicWidthInLumaSamples()) + { + WRITE_UVLC((picHeader->getVirtualBoundariesPosX(i) >> 3) - 1, "ph_virtual_boundary_pos_x_minus1[i]"); + CHECK(((picHeader->getVirtualBoundariesPosX(i) >> 3) - 1) > (((pps->getPicWidthInLumaSamples() + 7) >> 3) - 2), "The value of ph_virtual_boundary_pos_x_minus1[ i ] shall be in the range of 0 to Ceil( pps_pic_width_in_luma_samples / 8 ) - 2, inclusive."); + } + } +#else WRITE_UVLC(picHeader->getNumVerVirtualBoundaries(), "ph_num_ver_virtual_boundaries"); if (pps->getPicWidthInLumaSamples() <= 8) { @@ -1710,6 +1750,7 @@ WRITE_FLAG(picHeader->getGdrOrIrapPicFlag(), "ph_gdr_or_irap_pic_flag"); WRITE_UVLC((picHeader->getVirtualBoundariesPosX(i) >> 3) - 1, "ph_virtual_boundary_pos_x_minus1[i]"); CHECK(((picHeader->getVirtualBoundariesPosX(i)>>3) - 1) > (((pps->getPicWidthInLumaSamples() + 7) >> 3) - 2), "The value of ph_virtual_boundary_pos_x_minus1[ i ] shall be in the range of 0 to Ceil( pps_pic_width_in_luma_samples / 8 ) - 2, inclusive."); } +#endif WRITE_UVLC(picHeader->getNumHorVirtualBoundaries(), "ph_num_hor_virtual_boundaries"); if (pps->getPicHeightInLumaSamples() <= 8) {