diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index 7e979bfa9d3f6291760e964bff6e4334285d968f..f261177ea76a8fb2e74d167a448ed7040a48ae49 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -196,6 +196,12 @@ static const int ADJ_DEQUANT_SHIFT = ( ADJ_QUANT_SHIFT + 1 ); static const int RVM_VCEGAM10_M = 4; +#if JVET_L0283_MULTI_REF_LINE +static const int MAX_REF_LINE_IDX = 3; //highest refLine offset in the list +static const int MRL_NUM_REF_LINES = 3; //number of candidates in the array +static const int MULTI_REF_LINE_IDX[4] = { 0, 1, 3, 0 }; +#endif + static const int NUM_LUMA_MODE = 67; ///< Planar + DC + 65 directional mode (4*16 + 1) #if JVET_L0338_MDLM static const int NUM_LMC_MODE = 1 + 2; ///< LMC + MDLM_T + MDLM_L diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index 4130a64624c5ce1c4569267d6aebd5cf197a2358..ede67ef3e71c9822a2454d511579fa5f08fa2130 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -349,6 +349,15 @@ const CtxSet ContextSetCfg::PredMode = ContextSetCfg::addCtxSet { CNU,}, }); +#if JVET_L0283_MULTI_REF_LINE +const CtxSet ContextSetCfg::MultiRefLineIdx = ContextSetCfg::addCtxSet +({ + { 154, 154, 154 }, + { 154, 154, 154 }, + { CNU, CNU, CNU }, + }); +#endif + const CtxSet ContextSetCfg::IPredMode[] = { ContextSetCfg::addCtxSet diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index 718a8b2341f47cffe95ab659dc08f0122cfa964e..522bf65184bac528f532095216c38c96cd8d888c 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -161,6 +161,9 @@ public: static const CtxSet MergeIdx; static const CtxSet PartSize; static const CtxSet PredMode; +#if JVET_L0283_MULTI_REF_LINE + static const CtxSet MultiRefLineIdx; +#endif static const CtxSet IPredMode [2]; // [ ChannelType ] static const CtxSet PdpcFlag; static const CtxSet DeltaQP; diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp index fccc63284123487e41ed213023a15f43b05b711b..9bc68a0e2b03254d93e5208dac92f14e9f0f08dc 100644 --- a/source/Lib/CommonLib/IntraPrediction.cpp +++ b/source/Lib/CommonLib/IntraPrediction.cpp @@ -210,7 +210,11 @@ void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepth if (m_piYuvExt[COMPONENT_Y][PRED_BUF_UNFILTERED] == nullptr) // check if first is null (in which case, nothing initialised yet) { +#if JVET_L0283_MULTI_REF_LINE + m_iYuvExtSize = (MAX_CU_SIZE * 2 + 1 + MAX_REF_LINE_IDX * 5) * (MAX_CU_SIZE * 2 + 1 + MAX_REF_LINE_IDX * 5); +#else m_iYuvExtSize = (MAX_CU_SIZE * 2 + 1) * (MAX_CU_SIZE * 2 + 1); +#endif for (uint32_t ch = 0; ch < MAX_NUM_COMPONENT; ch++) { @@ -339,9 +343,14 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co CHECK( g_aucLog2[iWidth] < 2 && pu.cs->pcv->noChroma2x2, "Size not allowed" ); CHECK( g_aucLog2[iWidth] > 7, "Size not allowed" ); CHECK( iWidth != iHeight && !pu.cs->pcv->rectCUs, "Rectangular block are only allowed with QTBT" ); - +#if JVET_L0283_MULTI_REF_LINE + const int multiRefIdx = (compID == COMPONENT_Y) ? pu.multiRefIdx : 0; + const int srcStride = m_topRefLength + 1 + 5 * multiRefIdx; + const int srcHStride = m_leftRefLength + 1 + 5 * multiRefIdx; +#else const int srcStride = m_topRefLength + 1; const int srcHStride = m_leftRefLength + 1; +#endif Pel *ptrSrc = getPredictorPtr(compID, useFilteredPredSamples); const ClpRng& clpRng(pu.cu->cs->slice->clpRng(compID)); @@ -356,17 +365,33 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co case(VDIA_IDX): if (getWideAngle(iWidth, iHeight, uiDirMode) == static_cast<int>(uiDirMode)) // check if uiDirMode is not wide-angle { - xPredIntraAng(CPelBuf(ptrSrc, srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps, useFilteredPredSamples); + xPredIntraAng(CPelBuf(ptrSrc, srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps +#if JVET_L0283_MULTI_REF_LINE + , multiRefIdx +#endif + , useFilteredPredSamples); break; } - default: xPredIntraAng(CPelBuf(getPredictorPtr(compID, false), srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps, useFilteredPredSamples); break; + default: xPredIntraAng(CPelBuf(getPredictorPtr(compID, false), srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps +#if JVET_L0283_MULTI_REF_LINE + , multiRefIdx +#endif + , useFilteredPredSamples); break; #else //JVET_L0628_4TAP_INTRA - default: xPredIntraAng(CPelBuf(ptrSrc, srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps, false); break; + default: xPredIntraAng(CPelBuf(ptrSrc, srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps +#if JVET_L0283_MULTI_REF_LINE + , multiRefIdx +#endif + , false); break; #endif //JVET_L0628_4TAP_INTRA } bool pdpcCondition = (uiDirMode == PLANAR_IDX || uiDirMode == DC_IDX || uiDirMode == HOR_IDX || uiDirMode == VER_IDX); +#if JVET_L0283_MULTI_REF_LINE + if (pdpcCondition && multiRefIdx == 0) +#else if (pdpcCondition) +#endif { const CPelBuf srcBuf = CPelBuf(ptrSrc, srcStride, srcStride); PelBuf dstBuf = piPred; @@ -593,11 +618,23 @@ void IntraPrediction::xDCPredFiltering(const CPelBuf &pSrc, PelBuf &pDst, const */ //NOTE: Bit-Limit - 25-bit source #if HEVC_USE_HOR_VER_PREDFILTERING -void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const bool bEnableEdgeFilters, const SPS& sps, const bool enableBoundaryFilter ) +void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const bool bEnableEdgeFilters, const SPS& sps +#if JVET_L0283_MULTI_REF_LINE + , int multiRefIdx +#endif + , const bool enableBoundaryFilter ) #elif JVET_L0628_4TAP_INTRA -void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps, const bool useFilteredPredSamples ) +void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps +#if JVET_L0283_MULTI_REF_LINE + , int multiRefIdx +#endif + , const bool useFilteredPredSamples ) #else -void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps, const bool enableBoundaryFilter ) +void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps +#if JVET_L0283_MULTI_REF_LINE + , int multiRefIdx +#endif + , const bool enableBoundaryFilter ) #endif { int width =int(pDst.width); @@ -626,9 +663,13 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch Pel* refMain; Pel* refSide; +#if JVET_L0283_MULTI_REF_LINE + Pel refAbove[2 * MAX_CU_SIZE + 3 + 5 * MAX_REF_LINE_IDX]; + Pel refLeft [2 * MAX_CU_SIZE + 3 + 5 * MAX_REF_LINE_IDX]; +#else Pel refAbove[2 * MAX_CU_SIZE + 3]; Pel refLeft [2 * MAX_CU_SIZE + 3]; - +#endif // Initialize the Main and Left reference array. if (intraPredAngle < 0) @@ -636,14 +677,26 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch #if JVET_L0628_4TAP_INTRA auto width = int(pDst.width) +1; auto height = int(pDst.height)+1; +#if JVET_L0283_MULTI_REF_LINE + auto lastIdx = (bIsModeVer ? width : height) + multiRefIdx; +#else auto lastIdx = bIsModeVer ? width : height; +#endif auto firstIdx = ( ((bIsModeVer ? height : width) -1) * intraPredAngle ) >> 5; #endif //JVET_L0628_4TAP_INTRA +#if JVET_L0283_MULTI_REF_LINE + for (int x = 0; x < width + 1 + multiRefIdx; x++) +#else for( int x = 0; x < width + 1; x++ ) +#endif { refAbove[x + height - 1] = pSrc.at( x, 0 ); } +#if JVET_L0283_MULTI_REF_LINE + for (int y = 0; y < height + 1 + multiRefIdx; y++) +#else for( int y = 0; y < height + 1; y++ ) +#endif { refLeft[y + width - 1] = pSrc.at( 0, y ); } @@ -669,7 +722,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch } else { +#if JVET_L0283_MULTI_REF_LINE + for (int x = 0; x < m_topRefLength + 1 + 5 * multiRefIdx; x++) +#else for( int x = 0; x < m_topRefLength + 1; x++ ) +#endif { #if JVET_L0628_4TAP_INTRA refAbove[x+1] = pSrc.at(x, 0); @@ -677,7 +734,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch refAbove[x] = pSrc.at(x, 0); #endif //JVET_L0628_4TAP_INTRA } +#if JVET_L0283_MULTI_REF_LINE + for (int y = 0; y < m_leftRefLength + 1 + 5 * multiRefIdx; y++) +#else for( int y = 0; y < m_leftRefLength + 1; y++ ) +#endif { #if JVET_L0628_4TAP_INTRA refLeft[y+1] = pSrc.at(0, y); @@ -692,7 +753,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch refMain++; refSide++; refMain[-1] = refMain[0]; +#if JVET_L0283_MULTI_REF_LINE + auto lastIdx = 1 + ((bIsModeVer) ? m_topRefLength : m_leftRefLength) + 5 * multiRefIdx; +#else auto lastIdx = 1 + ((bIsModeVer) ? m_topRefLength : m_leftRefLength); +#endif refMain[lastIdx] = refMain[lastIdx-1]; #endif //JVET_L0628_4TAP_INTRA } @@ -706,6 +771,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch std::swap(width, height); } +#if JVET_L0283_MULTI_REF_LINE + // compensate for line offset in reference line buffers + refMain += multiRefIdx; + refSide += multiRefIdx; +#endif if( intraPredAngle == 0 ) // pure vertical or pure horizontal { @@ -717,7 +787,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch } } #if HEVC_USE_HOR_VER_PREDFILTERING +#if JVET_L0283_MULTI_REF_LINE + if (edgeFilter && multiRefIdx == 0) +#else if (edgeFilter) +#endif { for( int y = 0; y < height; y++ ) { @@ -729,8 +803,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch else { Pel *pDsty=pDstBuf; - +#if JVET_L0283_MULTI_REF_LINE + for (int y = 0, deltaPos = intraPredAngle * (1 + multiRefIdx); y<height; y++, deltaPos += intraPredAngle, pDsty += dstStride) +#else for (int y=0, deltaPos=intraPredAngle; y<height; y++, deltaPos+=intraPredAngle, pDsty+=dstStride) +#endif { const int deltaInt = deltaPos >> 5; const int deltaFract = deltaPos & (32 - 1); @@ -747,7 +824,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch if( isLuma(channelType) ) { Pel p[4]; +#if JVET_L0283_MULTI_REF_LINE + const bool useCubicFilter = !useFilteredPredSamples || multiRefIdx > 0; +#else const bool useCubicFilter = !useFilteredPredSamples; +#endif TFilterCoeff const * const f = (useCubicFilter) ? InterpolationFilter::getChromaFilterTable(deltaFract) : g_intraGaussFilter[deltaFract]; int refMainIndex = deltaInt + 1; @@ -792,8 +873,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch const int numModes = 8; const int scale = ((g_aucLog2[width] - 2 + g_aucLog2[height] - 2 + 2) >> 2); CHECK(scale < 0 || scale > 31, "PDPC: scale < 0 || scale > 31"); - +#if JVET_L0283_MULTI_REF_LINE + if ((predMode == 2 || predMode == VDIA_IDX) && multiRefIdx == 0) +#else if (predMode == 2 || predMode == VDIA_IDX) +#endif { int wT = 16 >> std::min(31, ((y << 1) >> scale)); @@ -809,7 +893,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch pDsty[x] = ClipPel((wL * left + wT * top + (64 - wL - wT) * pDsty[x] + 32) >> 6, clpRng); } } +#if JVET_L0283_MULTI_REF_LINE + else if (((predMode >= VDIA_IDX - numModes && predMode != VDIA_IDX) || (predMode != 2 && predMode <= (2 + numModes))) && multiRefIdx == 0) +#else else if ((predMode >= VDIA_IDX - numModes && predMode != VDIA_IDX) || (predMode != 2 && predMode <= (2 + numModes))) +#endif { int invAngleSum0 = 2; for (int x = 0; x < width; x++) @@ -1006,7 +1094,11 @@ void IntraPrediction::initIntraPatternChType(const CodingUnit &cu, const CompAre // ----- Step 2: filtered reference samples ----- if( bFilterRefSamples ) { - xFilterReferenceSamples( refBufUnfiltered, refBufFiltered, area, *cs.sps ); + xFilterReferenceSamples( refBufUnfiltered, refBufFiltered, area, *cs.sps +#if JVET_L0283_MULTI_REF_LINE + , cu.firstPU->multiRefIdx +#endif + ); } } @@ -1017,11 +1109,19 @@ void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBuf const SPS &sps = *cs.sps; const PreCalcValues &pcv = *cs.pcv; +#if JVET_L0283_MULTI_REF_LINE + const int multiRefIdx = (area.compID == COMPONENT_Y) ? cu.firstPU->multiRefIdx : 0; +#endif + const int tuWidth = area.width; const int tuHeight = area.height; const int predSize = m_topRefLength; const int predHSize = m_leftRefLength; +#if JVET_L0283_MULTI_REF_LINE + const int predStride = predSize + 1 + 5 * multiRefIdx; +#else const int predStride = predSize + 1; +#endif const bool noShift = pcv.noChroma2x2 && area.width == 4; // don't shift on the lowest level (chroma not-split) const int unitWidth = pcv.minCUWidth >> (noShift ? 0 : getComponentScaleX( area.compID, sps.getChromaFormatIdc() )); @@ -1067,20 +1167,198 @@ void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBuf if( numIntraNeighbor == 0 ) { // Fill border with DC value +#if JVET_L0283_MULTI_REF_LINE + for (int j = 0; j <= predSize + multiRefIdx; j++) { ptrDst[j] = valueDC; } + for (int i = 1; i <= predHSize + multiRefIdx; i++) { ptrDst[i*predStride] = valueDC; } +#else for( int j = 0; j <= predSize; j++ ) { ptrDst[j] = valueDC; } for( int i = 1; i <= predHSize; i++ ) { ptrDst[i*predStride] = valueDC; } +#endif } else if( numIntraNeighbor == totalUnits ) { // Fill top-left border and top and top right with rec. samples +#if JVET_L0283_MULTI_REF_LINE + ptrSrc = srcBuf - (1 + multiRefIdx) * srcStride - (1 + multiRefIdx); + for (int j = 0; j <= predSize + multiRefIdx; j++) { ptrDst[j] = ptrSrc[j]; } + ptrSrc = srcBuf - multiRefIdx * srcStride - (1 + multiRefIdx); + for (int i = 1; i <= predHSize + multiRefIdx; i++) { ptrDst[i*predStride] = *(ptrSrc); ptrSrc += srcStride; } +#else ptrSrc = srcBuf - srcStride - 1; for( int j = 0; j <= predSize; j++ ) { ptrDst[j] = ptrSrc[j]; } // Fill left and below left border with rec. samples ptrSrc = srcBuf - 1; for( int i = 1; i <= predHSize; i++ ) { ptrDst[i*predStride] = *(ptrSrc); ptrSrc += srcStride; } +#endif } else // reference samples are partially available { +#if JVET_L0283_MULTI_REF_LINE + // Fill top-left sample(s) if available + ptrSrc = srcBuf - (1 + multiRefIdx) * srcStride - (1 + multiRefIdx); + ptrDst = refBufUnfiltered; + if (neighborFlags[totalLeftUnits]) + { + ptrDst[0] = ptrSrc[0]; + for (int i = 1; i <= multiRefIdx; i++) + { + ptrDst[i] = ptrSrc[i]; + ptrDst[i*predStride] = ptrSrc[i*srcStride]; + } + } + + // Fill left & below-left samples if available (downwards) + ptrSrc += (1 + multiRefIdx) * srcStride; + ptrDst += (1 + multiRefIdx) * predStride; + for (int unitIdx = totalLeftUnits - 1; unitIdx > 0; unitIdx--) + { + if (neighborFlags[unitIdx]) + { + for (int i = 0; i < unitHeight; i++) + { + ptrDst[i*predStride] = ptrSrc[i*srcStride]; + } + } + ptrSrc += unitHeight * srcStride; + ptrDst += unitHeight * predStride; + } + // Fill last below-left sample(s) + if (neighborFlags[0]) + { + int lastSample = (predHSize % unitHeight == 0) ? unitHeight : predHSize % unitHeight; + for (int i = 0; i < lastSample; i++) + { + ptrDst[i*predStride] = ptrSrc[i*srcStride]; + } + } + + // Fill above & above-right samples if available (left-to-right) + ptrSrc = srcBuf - srcStride * (1 + multiRefIdx); + ptrDst = refBufUnfiltered + 1 + multiRefIdx; + for (int unitIdx = totalLeftUnits + 1; unitIdx < totalUnits - 1; unitIdx++) + { + if (neighborFlags[unitIdx]) + { + for (int j = 0; j < unitWidth; j++) + { + ptrDst[j] = ptrSrc[j]; + } + } + ptrSrc += unitWidth; + ptrDst += unitWidth; + } + // Fill last above-right sample(s) + if (neighborFlags[totalUnits - 1]) + { + int lastSample = (predSize % unitWidth == 0) ? unitWidth : predSize % unitWidth; + for (int j = 0; j < lastSample; j++) + { + ptrDst[j] = ptrSrc[j]; + } + } + + // pad from first available down to the last below-left + ptrDst = refBufUnfiltered; + int lastAvailUnit = 0; + if (!neighborFlags[0]) + { + int firstAvailUnit = 1; + while (firstAvailUnit < totalUnits && !neighborFlags[firstAvailUnit]) + { + firstAvailUnit++; + } + + // first available sample + int firstAvailRow = 0; + int firstAvailCol = 0; + if (firstAvailUnit < totalLeftUnits) + { + firstAvailRow = (totalLeftUnits - firstAvailUnit) * unitHeight + multiRefIdx; + } + else if (firstAvailUnit == totalLeftUnits) + { + firstAvailRow = multiRefIdx; + } + else + { + firstAvailCol = (firstAvailUnit - totalLeftUnits - 1) * unitWidth + 1 + multiRefIdx; + } + const Pel firstAvailSample = ptrDst[firstAvailCol + firstAvailRow * predStride]; + + // last sample below-left (n.a.) + int lastRow = predHSize + multiRefIdx; + + // fill left column + for (int i = lastRow; i > firstAvailRow; i--) + { + ptrDst[i*predStride] = firstAvailSample; + } + // fill top row + if (firstAvailCol > 0) + { + for (int j = 0; j < firstAvailCol; j++) + { + ptrDst[j] = firstAvailSample; + } + } + lastAvailUnit = firstAvailUnit; + } + + // pad all other reference samples. + int currUnit = lastAvailUnit + 1; + while (currUnit < totalUnits) + { + if (!neighborFlags[currUnit]) // samples not available + { + // last available sample + int lastAvailRow = 0; + int lastAvailCol = 0; + if (lastAvailUnit < totalLeftUnits) + { + lastAvailRow = (totalLeftUnits - lastAvailUnit - 1) * unitHeight + multiRefIdx + 1; + } + else if (lastAvailUnit == totalLeftUnits) + { + lastAvailCol = multiRefIdx; + } + else + { + lastAvailCol = (lastAvailUnit - totalLeftUnits) * unitWidth + multiRefIdx; + } + const Pel lastAvailSample = ptrDst[lastAvailCol + lastAvailRow * predStride]; + + // fill current unit with last available sample + if (currUnit < totalLeftUnits) + { + for (int i = lastAvailRow - 1; i <= lastAvailRow + unitHeight; i++) + { + ptrDst[i*predStride] = lastAvailSample; + } + } + else if (currUnit == totalLeftUnits) + { + for (int i = 1; i < multiRefIdx + 1; i++) + { + ptrDst[i*predStride] = lastAvailSample; + } + for (int j = 0; j < multiRefIdx + 1; j++) + { + ptrDst[j] = lastAvailSample; + } + } + else + { + int numSamplesInUnit = (currUnit == totalUnits - 1) ? ((predSize % unitWidth == 0) ? unitWidth : predSize % unitWidth) : unitWidth; + for (int j = lastAvailCol + 1; j <= lastAvailCol + numSamplesInUnit; j++) + { + ptrDst[j] = lastAvailSample; + } + } + } + lastAvailUnit = currUnit; + currUnit++; + } +#else // BB: old implementation using tmpLineBuf // --------------------------------------- Pel tmpLineBuf[5 * MAX_CU_SIZE]; @@ -1182,13 +1460,35 @@ void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBuf ptrTmp = tmpLineBuf + (totalLeftUnits * unitHeight); for( int i = 1; i <= predHSize; i++ ) { ptrDst[i*predStride] = ptrTmp[-i]; } - } +#endif +} +#if JVET_L0283_MULTI_REF_LINE + // padding of extended samples above right with the last sample + int lastSample = multiRefIdx + predSize; + for (int j = 1; j <= 4 * multiRefIdx; j++) { ptrDst[lastSample + j] = ptrDst[lastSample]; } + // padding of extended samples below left with the last sample + lastSample = multiRefIdx + predHSize; + for (int i = 1; i <= 4 * multiRefIdx; i++) { ptrDst[(lastSample + i)*predStride] = ptrDst[lastSample*predStride]; } +#endif } -void IntraPrediction::xFilterReferenceSamples( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps ) +void IntraPrediction::xFilterReferenceSamples( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps +#if JVET_L0283_MULTI_REF_LINE + , int multiRefIdx +#endif +) { +#if JVET_L0283_MULTI_REF_LINE + if (area.compID != COMPONENT_Y) + { + multiRefIdx = 0; + } + const int predSize = m_topRefLength + 5 * multiRefIdx; + const int predHSize = m_leftRefLength + 5 * multiRefIdx; +#else const int predSize = m_topRefLength; const int predHSize = m_leftRefLength; +#endif const int predStride = predSize + 1; @@ -1268,6 +1568,10 @@ bool IntraPrediction::useFilteredIntraRefSamples( const ComponentID &compID, con if( !modeSpecific ) { return true; } +#if JVET_L0283_MULTI_REF_LINE + if (pu.multiRefIdx) { return false; } +#endif + // pred. mode related conditions const int dirMode = PU::getFinalIntraMode( pu, chType ); int predMode = getWideAngle(tuArea.blocks[compID].width, tuArea.blocks[compID].height, dirMode); diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h index 72618f957e6ce5079df408bae35f3a0b7d885bf3..51ff65bfd9934e18934f08c197dac41884ac6a52 100644 --- a/source/Lib/CommonLib/IntraPrediction.h +++ b/source/Lib/CommonLib/IntraPrediction.h @@ -92,18 +92,34 @@ protected: void xPredIntraPlanar ( const CPelBuf &pSrc, PelBuf &pDst, const SPS& sps ); void xPredIntraDc ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const bool enableBoundaryFilter = true ); #if HEVC_USE_HOR_VER_PREDFILTERING - void xPredIntraAng ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const bool bEnableEdgeFilters, const SPS& sps, const bool enableBoundaryFilter = true ); + void xPredIntraAng ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const bool bEnableEdgeFilters, const SPS& sps +#if JVET_L0283_MULTI_REF_LINE + , int multiRefIdx +#endif + , const bool enableBoundaryFilter = true ); #else #if JVET_L0628_4TAP_INTRA - void xPredIntraAng ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps, const bool useFilteredPredSamples ); + void xPredIntraAng ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps +#if JVET_L0283_MULTI_REF_LINE + , int multiRefIdx +#endif + , const bool useFilteredPredSamples ); #else - void xPredIntraAng ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps, const bool enableBoundaryFilter = true ); + void xPredIntraAng ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps +#if JVET_L0283_MULTI_REF_LINE + , int multiRefIdx +#endif + , const bool enableBoundaryFilter = true ); #endif //JVET_L0628_4TAP_INTRA #endif Pel xGetPredValDc ( const CPelBuf &pSrc, const Size &dstSize ); void xFillReferenceSamples ( const CPelBuf &recoBuf, Pel* refBufUnfiltered, const CompArea &area, const CodingUnit &cu ); - void xFilterReferenceSamples ( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps ); + void xFilterReferenceSamples ( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps +#if JVET_L0283_MULTI_REF_LINE + , int multiRefIdx +#endif + ); #if HEVC_USE_DC_PREDFILTERING // dc filtering diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index e6e7ff8eb8f2eedc447bd8bcd469d196a64489d8..7006892d179f75a81967da37b3973745cc903769 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -107,6 +107,8 @@ #define JVET_L0260_AFFINE_ME 1 +#define JVET_L0283_MULTI_REF_LINE 1 + #define JVET_L0256_BIO 1 #define JVET_L0646_GBI 1 // Generalized bi-prediction (GBi) diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index 098732295cef633a568eb54b362b13bc77f64139..c491ac84dc64e68663ba7a0d682a98d56ad8d32c 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -329,6 +329,9 @@ void PredictionUnit::initData() // intra data - need this default initialization for PCM intraDir[0] = DC_IDX; intraDir[1] = PLANAR_IDX; +#if JVET_L0283_MULTI_REF_LINE + multiRefIdx = 0; +#endif // inter data mergeFlag = false; @@ -368,6 +371,9 @@ PredictionUnit& PredictionUnit::operator=(const IntraPredictionData& predData) { intraDir[i] = predData.intraDir[i]; } +#if JVET_L0283_MULTI_REF_LINE + multiRefIdx = predData.multiRefIdx; +#endif return *this; } @@ -413,6 +419,9 @@ PredictionUnit& PredictionUnit::operator=( const PredictionUnit& other ) { intraDir[ i ] = other.intraDir[ i ]; } +#if JVET_L0283_MULTI_REF_LINE + multiRefIdx = other.multiRefIdx; +#endif mergeFlag = other.mergeFlag; mergeIdx = other.mergeIdx; diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index 976dfdf1f9620351bfc109b7717aa33c7e3c499c..e18c8854d45d43dc9fbd8c540091a999cc81f661 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -349,6 +349,9 @@ struct CodingUnit : public UnitArea struct IntraPredictionData { uint32_t intraDir[MAX_NUM_CHANNEL_TYPE]; +#if JVET_L0283_MULTI_REF_LINE + int multiRefIdx; +#endif }; struct InterPredictionData diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 509d3e7971aed4f02a573e1a61a27f4ac2419397..29e609e47241011d056b166923d5693d361bfc33 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -299,6 +299,9 @@ cTUTraverser CU::traverseTUs( const CodingUnit& cu ) int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType &channelType /*= CHANNEL_TYPE_LUMA*/ ) { const unsigned numMPMs = pu.cs->pcv->numMPMs; +#if JVET_L0283_MULTI_REF_LINE + const int extendRefLine = (channelType == CHANNEL_TYPE_LUMA) ? pu.multiRefIdx : 0; +#endif { int numCand = -1; #if JVET_L0165_6MPM @@ -327,56 +330,130 @@ int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType const int offset = (int)NUM_LUMA_MODE - 6; const int mod = offset + 3; - mpm[0] = leftIntraDir; - mpm[1] = (mpm[0] == PLANAR_IDX) ? DC_IDX : PLANAR_IDX; - mpm[2] = VER_IDX; - mpm[3] = HOR_IDX; - mpm[4] = VER_IDX - 4; - mpm[5] = VER_IDX + 4; - - if (leftIntraDir == aboveIntraDir) +#if JVET_L0283_MULTI_REF_LINE + if (extendRefLine) { - numCand = 1; + int modeIdx = 0; + int angularMode[2] = { 0, 0 }; + if (leftIntraDir > DC_IDX) { - mpm[0] = leftIntraDir; - mpm[1] = PLANAR_IDX; - mpm[2] = DC_IDX; - mpm[3] = ((leftIntraDir + offset) % mod) + 2; - mpm[4] = ((leftIntraDir - 1) % mod) + 2; - mpm[5] = ((leftIntraDir + offset - 1) % mod) + 2; + angularMode[modeIdx++] = leftIntraDir; + } + if (aboveIntraDir > DC_IDX) + { + angularMode[modeIdx++] = aboveIntraDir; + } + if (modeIdx == 0) + { + mpm[0] = VER_IDX; + mpm[1] = HOR_IDX; + mpm[2] = 2; + mpm[3] = DIA_IDX; + mpm[4] = VDIA_IDX; + mpm[5] = 26; + } + else if (modeIdx == 1) + { + mpm[0] = angularMode[0]; + mpm[1] = ((angularMode[0] + offset) % mod) + 2; + mpm[2] = ((angularMode[0] - 1) % mod) + 2; + mpm[3] = ((angularMode[0] + offset - 1) % mod) + 2; + mpm[4] = (angularMode[0] % mod) + 2; + mpm[5] = ((angularMode[0] + offset - 2) % mod) + 2; + } + else + { + mpm[0] = angularMode[0]; + mpm[1] = angularMode[1]; + int maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1; + int minCandModeIdx = 1 - maxCandModeIdx; + if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 1) + { + mpm[2] = ((angularMode[minCandModeIdx] + offset) % mod) + 2; + mpm[3] = ((angularMode[maxCandModeIdx] - 1) % mod) + 2; + mpm[4] = ((angularMode[minCandModeIdx] + offset - 1) % mod) + 2; + mpm[5] = ( angularMode[maxCandModeIdx] % mod) + 2; + } + else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] >= 62) + { + mpm[2] = ((angularMode[minCandModeIdx] - 1) % mod) + 2; + mpm[3] = ((angularMode[maxCandModeIdx] + offset) % mod) + 2; + mpm[4] = ((angularMode[minCandModeIdx]) % mod) + 2; + mpm[5] = ((angularMode[maxCandModeIdx] + offset - 1) % mod) + 2; + } + else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 2) + { + mpm[2] = ((angularMode[minCandModeIdx] - 1) % mod) + 2; + mpm[3] = ((angularMode[minCandModeIdx] + offset) % mod) + 2; + mpm[4] = ((angularMode[maxCandModeIdx] - 1) % mod) + 2; + mpm[5] = ((angularMode[minCandModeIdx] + offset - 1) % mod) + 2; + } + else + { + mpm[2] = ((angularMode[minCandModeIdx] + offset) % mod) + 2; + mpm[3] = ((angularMode[minCandModeIdx] - 1) % mod) + 2; + mpm[4] = ((angularMode[maxCandModeIdx] + offset) % mod) + 2; + mpm[5] = ((angularMode[maxCandModeIdx] - 1) % mod) + 2; + } } } - else //L!=A + else { - numCand = 2; +#endif mpm[0] = leftIntraDir; - mpm[1] = aboveIntraDir; - bool maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1; + mpm[1] = (mpm[0] == PLANAR_IDX) ? DC_IDX : PLANAR_IDX; + mpm[2] = VER_IDX; + mpm[3] = HOR_IDX; + mpm[4] = VER_IDX - 4; + mpm[5] = VER_IDX + 4; - if ((leftIntraDir > DC_IDX) && (aboveIntraDir > DC_IDX)) + if (leftIntraDir == aboveIntraDir) { - mpm[2] = PLANAR_IDX; - mpm[3] = DC_IDX; - if ((mpm[maxCandModeIdx] - mpm[!maxCandModeIdx] < 63) && (mpm[maxCandModeIdx] - mpm[!maxCandModeIdx] > 1)) + numCand = 1; + if (leftIntraDir > DC_IDX) { - mpm[4] = ((mpm[maxCandModeIdx] + offset) % mod) + 2; - mpm[5] = ((mpm[maxCandModeIdx] - 1) % mod) + 2; - } - else - { - mpm[4] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2; - mpm[5] = ((mpm[maxCandModeIdx] ) % mod) + 2; + mpm[0] = leftIntraDir; + mpm[1] = PLANAR_IDX; + mpm[2] = DC_IDX; + mpm[3] = ((leftIntraDir + offset) % mod) + 2; + mpm[4] = ((leftIntraDir - 1) % mod) + 2; + mpm[5] = ((leftIntraDir + offset - 1) % mod) + 2; } } - else if (leftIntraDir + aboveIntraDir >= 2) + else //L!=A { - mpm[2] = (mpm[!maxCandModeIdx] == PLANAR_IDX) ? DC_IDX : PLANAR_IDX; - mpm[3] = ((mpm[maxCandModeIdx] + offset) % mod) + 2; - mpm[4] = ((mpm[maxCandModeIdx] - 1) % mod) + 2; - mpm[5] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2; + numCand = 2; + mpm[0] = leftIntraDir; + mpm[1] = aboveIntraDir; + bool maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1; + + if ((leftIntraDir > DC_IDX) && (aboveIntraDir > DC_IDX)) + { + mpm[2] = PLANAR_IDX; + mpm[3] = DC_IDX; + if ((mpm[maxCandModeIdx] - mpm[!maxCandModeIdx] < 63) && (mpm[maxCandModeIdx] - mpm[!maxCandModeIdx] > 1)) + { + mpm[4] = ((mpm[maxCandModeIdx] + offset) % mod) + 2; + mpm[5] = ((mpm[maxCandModeIdx] - 1) % mod) + 2; + } + else + { + mpm[4] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2; + mpm[5] = ((mpm[maxCandModeIdx]) % mod) + 2; + } + } + else if (leftIntraDir + aboveIntraDir >= 2) + { + mpm[2] = (mpm[!maxCandModeIdx] == PLANAR_IDX) ? DC_IDX : PLANAR_IDX; + mpm[3] = ((mpm[maxCandModeIdx] + offset) % mod) + 2; + mpm[4] = ((mpm[maxCandModeIdx] - 1) % mod) + 2; + mpm[5] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2; + } } +#if JVET_L0283_MULTI_REF_LINE } +#endif #else int leftIntraDir = DC_IDX, aboveIntraDir = DC_IDX; @@ -422,6 +499,71 @@ int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType const int offset = 61; const int mod = 64; +#if JVET_L0283_MULTI_REF_LINE + if (extendRefLine) + { + if (leftIntraDir == aboveIntraDir) + { + numCand = 1; + + if (leftIntraDir > DC_IDX) // angular modes + { + mpm[0] = leftIntraDir; + mpm[1] = ((leftIntraDir + offset) % mod) + 2; + mpm[2] = ((leftIntraDir - 1) % mod) + 2; + } + else // non-angular + { + mpm[0] = 2; + mpm[1] = HOR_IDX; + mpm[2] = VER_IDX; + } + } + else + { + numCand = 2; + + if (leftIntraDir <= DC_IDX && aboveIntraDir <= DC_IDX) // both non-angular + { + mpm[0] = 2; + mpm[1] = HOR_IDX; + mpm[2] = VER_IDX; + } + else if (leftIntraDir <= DC_IDX) // left non-angular + { + mpm[0] = aboveIntraDir; + mpm[1] = ((aboveIntraDir + offset) % mod) + 2; + mpm[2] = ((aboveIntraDir - 1) % mod) + 2; + } + else if (aboveIntraDir <= DC_IDX) // above non-angular + { + mpm[0] = leftIntraDir; + mpm[1] = ((leftIntraDir + offset) % mod) + 2; + mpm[2] = ((leftIntraDir - 1) % mod) + 2; + } + else // both angular + { + mpm[0] = leftIntraDir; + mpm[1] = aboveIntraDir; + if (leftIntraDir == VER_IDX) + { + mpm[2] = aboveIntraDir == HOR_IDX ? 2 : HOR_IDX; + } + else if (leftIntraDir == HOR_IDX) + { + mpm[2] = aboveIntraDir == VER_IDX ? 2 : VER_IDX; + } + else + { + mpm[2] = aboveIntraDir == VER_IDX ? HOR_IDX : VER_IDX; + } + } + } + } + else + { +#endif + if (leftIntraDir == aboveIntraDir) { numCand = 1; @@ -455,6 +597,9 @@ int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType mpm[2] = (leftIntraDir + aboveIntraDir) < 2 ? VER_IDX : DC_IDX; } } +#if JVET_L0283_MULTI_REF_LINE + } +#endif #endif for (int i = 0; i < numMPMs; i++) { diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 2b517549724865c6326351b0fc351d64a1876d2b..633e15e33d06f016eca6666536bdc1c7b2cfebee 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -216,9 +216,17 @@ uint32_t getCtuAddr (const Position& pos, const PreCalcValues &pcv); template<typename T, size_t N> #if JVET_L0054_MMVD -uint32_t updateCandList(T uiMode, double uiCost, static_vector<T, N>& candModeList, static_vector<double, N>& candCostList, size_t uiFastCandNum = N, int* iserttPos = nullptr) +uint32_t updateCandList(T uiMode, double uiCost, static_vector<T, N>& candModeList, static_vector<double, N>& candCostList +#if JVET_L0283_MULTI_REF_LINE + , static_vector<int, N>& extendRefList, int extendRef +#endif + , size_t uiFastCandNum = N, int* iserttPos = nullptr) #else -uint32_t updateCandList( T uiMode, double uiCost, static_vector<T, N>& candModeList, static_vector<double, N>& candCostList, size_t uiFastCandNum = N ) +uint32_t updateCandList( T uiMode, double uiCost, static_vector<T, N>& candModeList, static_vector<double, N>& candCostList +#if JVET_L0283_MULTI_REF_LINE + , static_vector<int, N>& extendRefList, int extendRef +#endif + , size_t uiFastCandNum = N ) #endif { CHECK( std::min( uiFastCandNum, candModeList.size() ) != std::min( uiFastCandNum, candCostList.size() ), "Sizes do not match!" ); @@ -239,9 +247,21 @@ uint32_t updateCandList( T uiMode, double uiCost, static_vector<T, N>& candModeL { candModeList[currSize - i] = candModeList[currSize - 1 - i]; candCostList[currSize - i] = candCostList[currSize - 1 - i]; +#if JVET_L0283_MULTI_REF_LINE + if (extendRef != -1) + { + extendRefList[currSize - i] = extendRefList[currSize - 1 - i]; + } +#endif } candModeList[currSize - shift] = uiMode; candCostList[currSize - shift] = uiCost; +#if JVET_L0283_MULTI_REF_LINE + if (extendRef != -1) + { + extendRefList[currSize - shift] = extendRef; + } +#endif #if JVET_L0054_MMVD if (iserttPos != nullptr) { @@ -254,6 +274,12 @@ uint32_t updateCandList( T uiMode, double uiCost, static_vector<T, N>& candModeL { candModeList.insert( candModeList.end() - shift, uiMode ); candCostList.insert( candCostList.end() - shift, uiCost ); +#if JVET_L0283_MULTI_REF_LINE + if (extendRef != -1) + { + extendRefList.insert(extendRefList.end() - shift, extendRef); + } +#endif #if JVET_L0054_MMVD if (iserttPos != nullptr) { @@ -318,7 +344,7 @@ uint32_t updateDoubleCandList(T mode, double cost, static_vector<T, N>& candMode #if JVET_L0054_MMVD if (iserttPos != nullptr) { - *iserttPos = int(candModeList.size() - shift - 1); + *iserttPos = int(candModeList.size() - shift - 1); } #endif return 1; @@ -335,5 +361,4 @@ uint32_t updateDoubleCandList(T mode, double cost, static_vector<T, N>& candMode #endif -#endif - +#endif \ No newline at end of file diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index a4404254d4dcc5279e51691228bf5b248a260418..8b2c28b7ee4f5a4072fc2726bfb6df2b4614ac12 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -708,6 +708,10 @@ bool CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx& // --> create PUs CU::addPUs( cu ); +#if JVET_L0283_MULTI_REF_LINE + extend_ref_line( cu ); +#endif + // pcm samples if( CU::isIntra(cu) && cu.partSize == SIZE_2Nx2N ) { @@ -929,6 +933,46 @@ void CABACReader::xReadTruncBinCode(uint32_t& symbol, uint32_t maxSymbol) } } #endif +#if JVET_L0283_MULTI_REF_LINE +void CABACReader::extend_ref_line(CodingUnit& cu) +{ + if (!cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType)) + { + cu.firstPU->multiRefIdx = 0; + return; + } + + const int numBlocks = CU::getNumPUs(cu); + PredictionUnit* pu = cu.firstPU; + + for (int k = 0; k < numBlocks; k++) + { + bool isFirstLineOfCtu = (((cu.block(COMPONENT_Y).y)&((cu.cs->sps)->getMaxCUWidth() - 1)) == 0); + if (isFirstLineOfCtu) + { + pu->multiRefIdx = 0; + continue; + } + int multiRefIdx = 0; + + if (MRL_NUM_REF_LINES > 1) + { + multiRefIdx = m_BinDecoder.decodeBin(Ctx::MultiRefLineIdx(0)) == 1 ? MULTI_REF_LINE_IDX[1] : MULTI_REF_LINE_IDX[0]; + if (MRL_NUM_REF_LINES > 2 && multiRefIdx != MULTI_REF_LINE_IDX[0]) + { + multiRefIdx = m_BinDecoder.decodeBin(Ctx::MultiRefLineIdx(1)) == 1 ? MULTI_REF_LINE_IDX[2] : MULTI_REF_LINE_IDX[1]; + if (MRL_NUM_REF_LINES > 3 && multiRefIdx != MULTI_REF_LINE_IDX[1]) + { + multiRefIdx = m_BinDecoder.decodeBin(Ctx::MultiRefLineIdx(2)) == 1 ? MULTI_REF_LINE_IDX[3] : MULTI_REF_LINE_IDX[2]; + } + } + + } + pu->multiRefIdx = multiRefIdx; + pu = pu->next; + } +} +#endif void CABACReader::intra_luma_pred_modes( CodingUnit &cu ) { @@ -946,6 +990,14 @@ void CABACReader::intra_luma_pred_modes( CodingUnit &cu ) int mpmFlag[4]; for( int k = 0; k < numBlocks; k++ ) { +#if JVET_L0283_MULTI_REF_LINE + CHECK(numBlocks != 1, "not supported yet"); + if (cu.firstPU->multiRefIdx) + { + mpmFlag[0] = true; + } + else +#endif mpmFlag[k] = m_BinDecoder.decodeBin( Ctx::IPredMode[0]() ); } diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 16699dcdf16d6bfa201ac7caebb89e50e8e5264a..10ce7a50e3478b054706a681eea9759f084ef530 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -82,6 +82,9 @@ public: void cu_pred_data ( CodingUnit& cu ); #if JVET_L0646_GBI void cu_gbi_flag ( CodingUnit& cu ); +#endif +#if JVET_L0283_MULTI_REF_LINE + void extend_ref_line (CodingUnit& cu); #endif void intra_luma_pred_modes ( CodingUnit& cu ); void intra_chroma_pred_modes ( CodingUnit& cu ); diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 4f3ec1ddd969d0daa4b297a34b5fb1606eba148b..66e1b1d0e9add550014bf61b6eb2dc4602013a5a 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -634,6 +634,10 @@ void CABACWriter::coding_unit( const CodingUnit& cu, Partitioner& partitioner, C // prediction mode and partitioning data pred_mode ( cu ); +#if JVET_L0283_MULTI_REF_LINE + extend_ref_line(cu); +#endif + // pcm samples if( CU::isIntra(cu) && cu.partSize == SIZE_2Nx2N ) { @@ -815,6 +819,70 @@ void CABACWriter::xWriteTruncBinCode(uint32_t symbol, uint32_t maxSymbol) } #endif +#if JVET_L0283_MULTI_REF_LINE +void CABACWriter::extend_ref_line(const PredictionUnit& pu) +{ + const CodingUnit& cu = *pu.cu; + if (!cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType)) + { + return; + } + bool isFirstLineOfCtu = (((cu.block(COMPONENT_Y).y)&((cu.cs->sps)->getMaxCUWidth() - 1)) == 0); + if (isFirstLineOfCtu) + { + return; + } + int multiRefIdx = pu.multiRefIdx; + if (MRL_NUM_REF_LINES > 1) + { + m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[0], Ctx::MultiRefLineIdx(0)); + if (MRL_NUM_REF_LINES > 2 && multiRefIdx != MULTI_REF_LINE_IDX[0]) + { + m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[1], Ctx::MultiRefLineIdx(1)); + if (MRL_NUM_REF_LINES > 3 && multiRefIdx != MULTI_REF_LINE_IDX[1]) + { + m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[2], Ctx::MultiRefLineIdx(2)); + } + } + } +} + +void CABACWriter::extend_ref_line(const CodingUnit& cu) +{ + if (!cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType)) + { + return; + } + + const int numBlocks = CU::getNumPUs(cu); + const PredictionUnit* pu = cu.firstPU; + + for (int k = 0; k < numBlocks; k++) + { + bool isFirstLineOfCtu = (((cu.block(COMPONENT_Y).y)&((cu.cs->sps)->getMaxCUWidth() - 1)) == 0); + if (isFirstLineOfCtu) + { + return; + } + int multiRefIdx = pu->multiRefIdx; + if (MRL_NUM_REF_LINES > 1) + { + m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[0], Ctx::MultiRefLineIdx(0)); + if (MRL_NUM_REF_LINES > 2 && multiRefIdx != MULTI_REF_LINE_IDX[0]) + { + m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[1], Ctx::MultiRefLineIdx(1)); + if (MRL_NUM_REF_LINES > 3 && multiRefIdx != MULTI_REF_LINE_IDX[1]) + { + m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[2], Ctx::MultiRefLineIdx(2)); + } + } + + } + pu = pu->next; + } +} +#endif + void CABACWriter::intra_luma_pred_modes( const CodingUnit& cu ) { if( !cu.Y().valid() ) @@ -850,6 +918,13 @@ void CABACWriter::intra_luma_pred_modes( const CodingUnit& cu ) break; } } +#if JVET_L0283_MULTI_REF_LINE + if (pu->multiRefIdx) + { + CHECK(mpm_idx >= numMPMs, "use of non-MPM"); + } + else +#endif m_BinEncoder.encodeBin( mpm_idx < numMPMs, Ctx::IPredMode[0]() ); pu = pu->next; @@ -936,6 +1011,13 @@ void CABACWriter::intra_luma_pred_mode( const PredictionUnit& pu ) break; } } +#if JVET_L0283_MULTI_REF_LINE + if (pu.multiRefIdx) + { + CHECK(mpm_idx >= numMPMs, "use of non-MPM"); + } + else +#endif m_BinEncoder.encodeBin( mpm_idx < numMPMs, Ctx::IPredMode[0]() ); // mpm_idx / rem_intra_luma_pred_mode diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index 2e25dcac24ec79910d933bb84b769415002a7a14..3e3a23e4ec53d2f598587742c99a6b2345f8a21f 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -95,6 +95,10 @@ public: void cu_pred_data ( const CodingUnit& cu ); #if JVET_L0646_GBI void cu_gbi_flag ( const CodingUnit& cu ); +#endif +#if JVET_L0283_MULTI_REF_LINE + void extend_ref_line (const PredictionUnit& pu ); + void extend_ref_line (const CodingUnit& cu ); #endif void intra_luma_pred_modes ( const CodingUnit& cu ); void intra_luma_pred_mode ( const PredictionUnit& pu ); diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index d459e98d14eca69498d786bf70caa3090f33f9be..940040d3e0584f746a0048f318a235cd42be46ca 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -1415,6 +1415,9 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC m_CABACEstimator->cu_skip_flag ( cu ); } m_CABACEstimator->pred_mode ( cu ); +#if JVET_L0283_MULTI_REF_LINE + m_CABACEstimator->extend_ref_line( cu ); +#endif m_CABACEstimator->cu_pred_data ( cu ); m_CABACEstimator->pcm_data ( cu ); @@ -1867,7 +1870,14 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& #if JVET_L0100_MULTI_HYPOTHESIS_INTRA updateDoubleCandList(uiMergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand, &insertPos); #else - updateCandList(uiMergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos); +#if JVET_L0283_MULTI_REF_LINE + static_vector<int, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> * nullList = nullptr; +#endif + updateCandList(uiMergeCand, cost, RdModeList, candCostList +#if JVET_L0283_MULTI_REF_LINE + , *nullList, -1 +#endif + , uiNumMrgSATDCand, &insertPos); #endif if (insertPos != -1) { @@ -1889,7 +1899,14 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& #if JVET_L0100_MULTI_HYPOTHESIS_INTRA updateDoubleCandList(uiMergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand); #else - updateCandList( uiMergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand ); +#if JVET_L0283_MULTI_REF_LINE + static_vector<int, MRG_MAX_NUM_CANDS> * nullList = nullptr; +#endif + updateCandList( uiMergeCand, cost, RdModeList, candCostList +#if JVET_L0283_MULTI_REF_LINE + , *nullList, -1 +#endif + , uiNumMrgSATDCand ); #endif #endif CHECK( std::min( uiMergeCand + 1, uiNumMrgSATDCand ) != RdModeList.size(), "" ); @@ -2071,7 +2088,14 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *& #if JVET_L0100_MULTI_HYPOTHESIS_INTRA updateDoubleCandList(mergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand, &insertPos); #else - updateCandList(mergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos); +#if JVET_L0283_MULTI_REF_LINE + static_vector<int, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> * nullList = nullptr; +#endif + updateCandList(mergeCand, cost, RdModeList, candCostList +#if JVET_L0283_MULTI_REF_LINE + , *nullList, -1 +#endif + , uiNumMrgSATDCand, &insertPos); #endif if (insertPos != -1) { @@ -2500,7 +2524,14 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru double cost = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass; - updateCandList( mergeCand, cost, triangleRdModeList, tianglecandCostList, triangleNumMrgSATDCand ); +#if JVET_L0283_MULTI_REF_LINE + static_vector<int, TRIANGLE_MAX_NUM_CANDS> * nullList = nullptr; +#endif + updateCandList( mergeCand, cost, triangleRdModeList, tianglecandCostList +#if JVET_L0283_MULTI_REF_LINE + , *nullList, -1 +#endif + , triangleNumMrgSATDCand ); } // limit number of candidates using SATD-costs @@ -2757,8 +2788,14 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct uiBitsCand--; } double cost = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass; - - updateCandList( uiMergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand ); +#if JVET_L0283_MULTI_REF_LINE + static_vector<int, AFFINE_MRG_MAX_NUM_CANDS> * nullList = nullptr; +#endif + updateCandList( uiMergeCand, cost, RdModeList, candCostList +#if JVET_L0283_MULTI_REF_LINE + , *nullList, -1 +#endif + , uiNumMrgSATDCand ); CHECK( std::min( uiMergeCand + 1, uiNumMrgSATDCand ) != RdModeList.size(), "" ); } diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index bbdfb101941a67738530abe2c80717e1de239942..2e8376650e925ca594c81d6cd86793cb26d823be 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -317,12 +317,20 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) static_vector<double, FAST_UDI_MAX_RDMODE_NUM> CandCostList; static_vector<double, FAST_UDI_MAX_RDMODE_NUM> CandHadList; +#if JVET_L0283_MULTI_REF_LINE + static_vector<int, FAST_UDI_MAX_RDMODE_NUM> extendRefList; + static_vector<int, FAST_UDI_MAX_RDMODE_NUM>* nullList = NULL; +#endif + auto &pu = *cu.firstPU; int puIndex = 0; { CandHadList.clear(); CandCostList.clear(); uiHadModeList.clear(); +#if JVET_L0283_MULTI_REF_LINE + extendRefList.clear(); +#endif CHECK(pu.cu != &cu, "PU is not contained in the CU"); @@ -350,6 +358,11 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) { // this should always be true CHECK( !pu.Y().valid(), "PU is not valid" ); +#if JVET_L0283_MULTI_REF_LINE + bool isFirstLineOfCtu = (((pu.block(COMPONENT_Y).y)&((pu.cs->sps)->getMaxCUWidth() - 1)) == 0); + int numOfPassesExtendRef = (isFirstLineOfCtu ? 1 : MRL_NUM_REF_LINES); + pu.multiRefIdx = 0; +#endif //===== init pattern for luma prediction ===== initIntraPatternChType( cu, pu.Y(), IntraPrediction::useFilteredIntraRefSamples( COMPONENT_Y, pu, false, pu ) ); @@ -409,13 +422,25 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) DTRACE( g_trace_ctx, D_INTRA_COST, "IntraHAD: %u, %llu, %f (%d)\n", uiSad, fracModeBits, cost, uiMode ); - updateCandList( uiMode, cost, uiRdModeList, CandCostList, numModesForFullRD + extraModes ); - updateCandList(uiMode, (double) uiSad, uiHadModeList, CandHadList, 3 + extraModes); + updateCandList( uiMode, cost, uiRdModeList, CandCostList +#if JVET_L0283_MULTI_REF_LINE + , extendRefList, 0 +#endif + , numModesForFullRD + extraModes ); + updateCandList(uiMode, (double) uiSad, uiHadModeList, CandHadList +#if JVET_L0283_MULTI_REF_LINE + , *nullList, -1 +#endif + , 3 + extraModes); } } // NSSTFlag // forget the extra modes uiRdModeList.resize( numModesForFullRD ); +#if JVET_L0283_MULTI_REF_LINE + CandCostList.resize(numModesForFullRD); + extendRefList.resize(numModesForFullRD); +#endif static_vector<unsigned, FAST_UDI_MAX_RDMODE_NUM> parentCandList(FAST_UDI_MAX_RDMODE_NUM); std::copy_n(uiRdModeList.begin(), numModesForFullRD, parentCandList.begin()); @@ -453,19 +478,75 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) double cost = (double) sad + (double) fracModeBits * sqrtLambdaForFirstPass; - updateCandList(mode, cost, uiRdModeList, CandCostList, numModesForFullRD); - updateCandList(mode, (double)sad, uiHadModeList, CandHadList, 3); + updateCandList(mode, cost, uiRdModeList, CandCostList +#if JVET_L0283_MULTI_REF_LINE + , extendRefList, 0 +#endif + , numModesForFullRD); + updateCandList(mode, (double)sad, uiHadModeList, CandHadList +#if JVET_L0283_MULTI_REF_LINE + , *nullList, -1 +#endif + , 3); bSatdChecked[mode] = true; } } } } +#if JVET_L0283_MULTI_REF_LINE + pu.multiRefIdx = 1; + unsigned numMPMs = pu.cs->pcv->numMPMs; + unsigned *multiRefMPM = (unsigned*)alloca(pu.cs->pcv->numMPMs * sizeof(unsigned)); + PU::getIntraMPMs(pu, multiRefMPM); + for (int mRefNum = 1; mRefNum < numOfPassesExtendRef; mRefNum++) + { + int multiRefIdx = MULTI_REF_LINE_IDX[mRefNum]; + + pu.multiRefIdx = multiRefIdx; + { + initIntraPatternChType(cu, pu.Y(), IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Y, pu, false, pu)); + } + for (int x = 0; x < numMPMs; x++) + { + uint32_t mode = multiRefMPM[x]; + { + pu.intraDir[0] = mode; + + if (useDPCMForFirstPassIntraEstimation(pu, mode)) + { + encPredIntraDPCM(COMPONENT_Y, piOrg, piPred, mode); + } + else + { + predIntraAng(COMPONENT_Y, piPred, pu, IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Y, pu, true, pu)); + } + + // use Hadamard transform here + Distortion sad = distParam.distFunc(distParam); + + // NB xFracModeBitsIntra will not affect the mode for chroma that may have already been pre-estimated. + m_CABACEstimator->getCtx() = SubCtx(Ctx::IPredMode[CHANNEL_TYPE_LUMA], ctxStartIntraMode); + + uint64_t fracModeBits = xFracModeBitsIntra(pu, mode, CHANNEL_TYPE_LUMA); + + double cost = (double)sad + (double)fracModeBits * sqrtLambdaForFirstPass; + updateCandList(mode, cost, uiRdModeList, CandCostList, extendRefList, multiRefIdx, numModesForFullRD); + } + } + } + CandCostList.resize(numModesForFullRD); + extendRefList.resize(numModesForFullRD); +#endif if( m_pcEncCfg->getFastUDIUseMPMEnabled() ) { unsigned numMPMs = pu.cs->pcv->numMPMs; unsigned *uiPreds = ( unsigned* ) alloca( numMPMs * sizeof( unsigned ) ); +#if JVET_L0283_MULTI_REF_LINE + pu.multiRefIdx = 0; +#endif + const int numCand = PU::getIntraMPMs( pu, uiPreds ); for( int j = 0; j < numCand; j++ ) @@ -476,10 +557,17 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) for( int i = 0; i < numModesForFullRD; i++ ) { +#if JVET_L0283_MULTI_REF_LINE + mostProbableModeIncluded |= (mostProbableMode == uiRdModeList[i] && extendRefList[i] == 0); +#else mostProbableModeIncluded |= ( mostProbableMode == uiRdModeList[i] ); +#endif } if( !mostProbableModeIncluded ) { +#if JVET_L0283_MULTI_REF_LINE + extendRefList.push_back(0); +#endif numModesForFullRD++; uiRdModeList.push_back( mostProbableMode ); } @@ -498,6 +586,9 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) // Store the modes to be checked with RD m_savedNumRdModes[puIndex] = numModesForFullRD; std::copy_n( uiRdModeList.begin(), numModesForFullRD, m_savedRdModeList[puIndex] ); +#if JVET_L0283_MULTI_REF_LINE + std::copy_n(extendRefList.begin(), numModesForFullRD, m_savedExtendRefList[puIndex]); +#endif } } else //emtUsage = 2 (here we potentially reduce the number of modes that will be full-RD checked) @@ -529,6 +620,9 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) if( m_modeCostStore[puIndex][i] <= thresholdSkipMode * m_bestModeCostStore[puIndex] ) { uiRdModeList.push_back( m_savedRdModeList[puIndex][i] ); +#if JVET_L0283_MULTI_REF_LINE + extendRefList.push_back(m_savedExtendRefList[puIndex][i]); +#endif numModesForFullRD++; } } @@ -539,6 +633,11 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) numModesForFullRD = m_savedNumRdModes[puIndex]; uiRdModeList.resize( numModesForFullRD ); std::copy_n( m_savedRdModeList[puIndex], m_savedNumRdModes[puIndex], uiRdModeList.begin() ); +#if JVET_L0283_MULTI_REF_LINE + CandCostList.resize(numModesForFullRD); + extendRefList.resize(numModesForFullRD); + std::copy_n(m_savedExtendRefList[puIndex], m_savedNumRdModes[puIndex], extendRefList.begin()); +#endif } } @@ -576,6 +675,9 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) double dSecondBestPUCost = MAX_DOUBLE; #endif uint32_t uiBestPUMode = 0; +#if JVET_L0283_MULTI_REF_LINE + int bestExtendRef = 0; +#endif CodingStructure *csTemp = m_pTempCS[gp_sizeIdxInfo->idxFrom( cu.lwidth() )][gp_sizeIdxInfo->idxFrom( cu.lheight() )]; CodingStructure *csBest = m_pBestCS[gp_sizeIdxInfo->idxFrom( cu.lwidth() )][gp_sizeIdxInfo->idxFrom( cu.lheight() )]; @@ -593,6 +695,11 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) uint32_t uiOrgMode = uiRdModeList[uiMode]; pu.intraDir[0] = uiOrgMode; +#if JVET_L0283_MULTI_REF_LINE + int multiRefIdx = extendRefList[uiMode]; + pu.multiRefIdx = multiRefIdx; + CHECK(pu.multiRefIdx && (pu.intraDir[0] == DC_IDX || pu.intraDir[0] == PLANAR_IDX), "ERL"); +#endif // set context models @@ -622,6 +729,9 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) dSecondBestPUCost = csTemp->cost; #endif uiBestPUMode = uiOrgMode; +#if JVET_L0283_MULTI_REF_LINE + bestExtendRef = multiRefIdx; +#endif if( ( emtUsageFlag == 1 ) && m_pcEncCfg->getFastIntraEMT() ) { @@ -644,6 +754,9 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner ) csBest->releaseIntermediateData(); //=== update PU data ==== pu.intraDir[0] = uiBestPUMode; +#if JVET_L0283_MULTI_REF_LINE + pu.multiRefIdx = bestExtendRef; +#endif } //===== reset context models ===== @@ -978,6 +1091,9 @@ void IntraSearch::xEncIntraHeader(CodingStructure &cs, Partitioner &partitioner, m_CABACEstimator->cu_skip_flag( cu ); m_CABACEstimator->pred_mode ( cu ); } +#if JVET_L0283_MULTI_REF_LINE + m_CABACEstimator->extend_ref_line(cu); +#endif if( CU::isIntra(cu) && cu.partSize == SIZE_2Nx2N ) { m_CABACEstimator->pcm_data( cu ); @@ -1918,9 +2034,15 @@ uint64_t IntraSearch::xFracModeBitsIntra(PredictionUnit &pu, const uint32_t &uiM m_CABACEstimator->MHIntra_luma_pred_modes(*pu.cu); else { +#if JVET_L0283_MULTI_REF_LINE + m_CABACEstimator->extend_ref_line(pu); +#endif m_CABACEstimator->intra_luma_pred_mode(pu); } #else +#if JVET_L0283_MULTI_REF_LINE + m_CABACEstimator->extend_ref_line(pu); +#endif m_CABACEstimator->intra_luma_pred_mode( pu ); #endif } diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index 424f78da79fb42c1554a766a6494ae446f8d175d..ca9ae80e86a051f02485fbf2bd06b29fcf05fd25 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -78,6 +78,9 @@ private: double m_bestModeCostStore[4]; // RD cost of the best mode for each PU using DCT2 double m_modeCostStore [4][NUM_LUMA_MODE]; // RD cost of each mode for each PU using DCT2 uint32_t m_savedRdModeList [4][NUM_LUMA_MODE], m_savedNumRdModes[4]; +#if JVET_L0283_MULTI_REF_LINE + int m_savedExtendRefList[4][NUM_LUMA_MODE]; +#endif protected: // interface to option