Newer
Older

Karsten Suehring
committed
/* The copyright in this software is being made available under the BSD
* License, included below. This software may be subject to other third party
* and contributor rights, including patent rights, and no such rights are
* granted under this license.
*
* Copyright (c) 2010-2020, ITU/ISO/IEC

Karsten Suehring
committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
/** \file UnitTool.cpp
* \brief defines operations for basic units
*/
#include "UnitTools.h"
#include "dtrace_next.h"
#include "Unit.h"
#include "Slice.h"
#include "Picture.h"
#include <utility>
#include <algorithm>
// CS tools
uint64_t CS::getEstBits(const CodingStructure &cs)
{
return cs.fracBits >> SCALE_BITS;
}
bool CS::isDualITree( const CodingStructure &cs )
{
return cs.slice->isIntra() && !cs.pcv->ISingleTree;

Karsten Suehring
committed
}
UnitArea CS::getArea( const CodingStructure &cs, const UnitArea &area, const ChannelType chType )
{
return isDualITree( cs ) || cs.treeType != TREE_D ? area.singleChan( chType ) : area;

Karsten Suehring
committed
}
void CS::setRefinedMotionField(CodingStructure &cs)
{
for (CodingUnit *cu : cs.cus)
{
for (auto &pu : CU::traversePUs(*cu))
{
PredictionUnit subPu = pu;
int dx, dy, x, y, num = 0;
dy = std::min<int>(pu.lumaSize().height, DMVR_SUBCU_HEIGHT);
dx = std::min<int>(pu.lumaSize().width, DMVR_SUBCU_WIDTH);
if (PU::checkDMVRCondition(pu))
{
for (y = puPos.y; y < (puPos.y + pu.lumaSize().height); y = y + dy)
{
for (x = puPos.x; x < (puPos.x + pu.lumaSize().width); x = x + dx)
{
subPu.UnitArea::operator=(UnitArea(pu.chromaFormat, Area(x, y, dx, dy)));
subPu.mv[0] = pu.mv[0];
subPu.mv[1] = pu.mv[1];
subPu.mv[REF_PIC_LIST_0] += pu.mvdL0SubPu[num];
subPu.mv[REF_PIC_LIST_1] -= pu.mvdL0SubPu[num];
subPu.mv[REF_PIC_LIST_0].clipToStorageBitDepth();
subPu.mv[REF_PIC_LIST_1].clipToStorageBitDepth();
pu.mvdL0SubPu[num].setZero();
num++;
PU::spanMotionInfo(subPu);
}
}
}
}

Karsten Suehring
committed
// CU tools
bool CU::getRprScaling( const SPS* sps, const PPS* curPPS, Picture* refPic, int& xScale, int& yScale )
const Window& curScalingWindow = curPPS->getScalingWindow();
#if JVET_Q0487_SCALING_WINDOW_ISSUES
int curPicWidth = curPPS->getPicWidthInLumaSamples() - SPS::getWinUnitX( sps->getChromaFormatIdc() ) * (curScalingWindow.getWindowLeftOffset() + curScalingWindow.getWindowRightOffset());
int curPicHeight = curPPS->getPicHeightInLumaSamples() - SPS::getWinUnitY( sps->getChromaFormatIdc() ) * (curScalingWindow.getWindowTopOffset() + curScalingWindow.getWindowBottomOffset());
#else
int curPicWidth = curPPS->getPicWidthInLumaSamples() - curScalingWindow.getWindowLeftOffset() - curScalingWindow.getWindowRightOffset();
int curPicHeight = curPPS->getPicHeightInLumaSamples() - curScalingWindow.getWindowTopOffset() - curScalingWindow.getWindowBottomOffset();
const Window& refScalingWindow = refPic->getScalingWindow();
#if JVET_Q0487_SCALING_WINDOW_ISSUES
int refPicWidth = refPic->getPicWidthInLumaSamples() - SPS::getWinUnitX( sps->getChromaFormatIdc() ) * (refScalingWindow.getWindowLeftOffset() + refScalingWindow.getWindowRightOffset());
int refPicHeight = refPic->getPicHeightInLumaSamples() - SPS::getWinUnitY( sps->getChromaFormatIdc() ) * (refScalingWindow.getWindowTopOffset() + refScalingWindow.getWindowBottomOffset());
#else
int refPicWidth = refPic->getPicWidthInLumaSamples() - refScalingWindow.getWindowLeftOffset() - refScalingWindow.getWindowRightOffset();
int refPicHeight = refPic->getPicHeightInLumaSamples() - refScalingWindow.getWindowTopOffset() - refScalingWindow.getWindowBottomOffset();
xScale = ( ( refPicWidth << SCALE_RATIO_BITS ) + ( curPicWidth >> 1 ) ) / curPicWidth;
yScale = ( ( refPicHeight << SCALE_RATIO_BITS ) + ( curPicHeight >> 1 ) ) / curPicHeight;
Peter Chuang
committed
int curSeqMaxPicWidthY = sps->getMaxPicWidthInLumaSamples(); // pic_width_max_in_luma_samples
int curSeqMaxPicHeightY = sps->getMaxPicHeightInLumaSamples(); // pic_height_max_in_luma_samples
int curPicWidthY = curPPS->getPicWidthInLumaSamples(); // pic_width_in_luma_samples
int curPicHeightY = curPPS->getPicHeightInLumaSamples(); // pic_height_in_luma_samples
int max8MinCbSizeY = std::max((int)8, (1<<sps->getLog2MinCodingBlockSize())); // Max(8, MinCbSizeY)
CHECK((curPicWidth * curSeqMaxPicWidthY) < refPicWidth * (curPicWidthY - max8MinCbSizeY), "(curPicWidth * curSeqMaxPicWidthY) should be greater than or equal to refPicWidth * (curPicWidthY - max8MinCbSizeY))");
CHECK((curPicHeight * curSeqMaxPicHeightY) < refPicHeight * (curPicHeightY - max8MinCbSizeY), "(curPicHeight * curSeqMaxPicHeightY) should be greater than or equal to refPicHeight * (curPicHeightY - max8MinCbSizeY))");
Jonatan Samuelsson-Allendes
committed
CHECK(curPicWidth * 2 < refPicWidth, "curPicWidth * 2 shall be greater than or equal to refPicWidth");
CHECK(curPicHeight * 2 < refPicHeight, "curPicHeight * 2 shall be greater than or equal to refPicHeight");
CHECK(curPicWidth > refPicWidth * 8, "curPicWidth shall be less than or equal to refPicWidth * 8");
CHECK(curPicHeight > refPicHeight * 8, "curPicHeight shall be less than or equal to refPicHeight * 8");
#if JVET_Q0487_SCALING_WINDOW_ISSUES
return refPic->isRefScaled( curPPS );
#else
return refPicWidth != curPicWidth || refPicHeight != curPicHeight;
}

Karsten Suehring
committed
bool CU::isIntra(const CodingUnit &cu)
{
return cu.predMode == MODE_INTRA;
}
bool CU::isInter(const CodingUnit &cu)
{
return cu.predMode == MODE_INTER;
}
bool CU::isIBC(const CodingUnit &cu)
{
return cu.predMode == MODE_IBC;
}
Yung-Hsuan Chao (Jessie)
committed
bool CU::isPLT(const CodingUnit &cu)
{
return cu.predMode == MODE_PLT;
}

Karsten Suehring
committed
bool CU::isRDPCMEnabled(const CodingUnit& cu)
{
return cu.cs->sps->getSpsRangeExtension().getRdpcmEnabledFlag(cu.predMode == MODE_INTRA ? RDPCM_SIGNAL_IMPLICIT : RDPCM_SIGNAL_EXPLICIT);
}
bool CU::isSameSlice(const CodingUnit& cu, const CodingUnit& cu2)
{
return cu.slice->getIndependentSliceIdx() == cu2.slice->getIndependentSliceIdx();
}
bool CU::isSameTile(const CodingUnit& cu, const CodingUnit& cu2)
{
return cu.tileIdx == cu2.tileIdx;
}

Karsten Suehring
committed
bool CU::isSameSliceAndTile(const CodingUnit& cu, const CodingUnit& cu2)
{
return ( cu.slice->getIndependentSliceIdx() == cu2.slice->getIndependentSliceIdx() ) && ( cu.tileIdx == cu2.tileIdx );
}
#if JVET_O1143_SUBPIC_BOUNDARY
bool CU::isSameSubPic(const CodingUnit& cu, const CodingUnit& cu2)
{
return (cu.slice->getPPS()->getSubPicFromCU(cu).getSubPicIdx() == cu2.slice->getPPS()->getSubPicFromCU(cu2).getSubPicIdx()) ;
}
#endif

Karsten Suehring
committed
bool CU::isSameCtu(const CodingUnit& cu, const CodingUnit& cu2)
{
uint32_t ctuSizeBit = floorLog2(cu.cs->sps->getMaxCUWidth());

Karsten Suehring
committed
Position pos1Ctu(cu.lumaPos().x >> ctuSizeBit, cu.lumaPos().y >> ctuSizeBit);
Position pos2Ctu(cu2.lumaPos().x >> ctuSizeBit, cu2.lumaPos().y >> ctuSizeBit);
return pos1Ctu.x == pos2Ctu.x && pos1Ctu.y == pos2Ctu.y;
}
bool CU::isLastSubCUOfCtu( const CodingUnit &cu )
{
const Area cuAreaY = cu.isSepTree() ? Area( recalcPosition( cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].pos() ), recalcSize( cu.chromaFormat, cu.chType, CHANNEL_TYPE_LUMA, cu.blocks[cu.chType].size() ) ) : (const Area&)cu.Y();

Karsten Suehring
committed
return ( ( ( ( cuAreaY.x + cuAreaY.width ) & cu.cs->pcv->maxCUWidthMask ) == 0 || cuAreaY.x + cuAreaY.width == cu.cs->pps->getPicWidthInLumaSamples() ) &&
( ( ( cuAreaY.y + cuAreaY.height ) & cu.cs->pcv->maxCUHeightMask ) == 0 || cuAreaY.y + cuAreaY.height == cu.cs->pps->getPicHeightInLumaSamples() ) );

Karsten Suehring
committed
}
uint32_t CU::getCtuAddr( const CodingUnit &cu )
{
return getCtuAddr( cu.blocks[cu.chType].lumaPos(), *cu.cs->pcv );
}
int CU::predictQP( const CodingUnit& cu, const int prevQP )
{
const CodingStructure &cs = *cu.cs;
uint32_t ctuRsAddr = getCtuAddr( cu );
uint32_t ctuXPosInCtus = ctuRsAddr % cs.pcv->widthInCtus;
uint32_t tileColIdx = cu.slice->getPPS()->ctuToTileCol( ctuXPosInCtus );
uint32_t tileXPosInCtus = cu.slice->getPPS()->getTileColumnBd( tileColIdx );
if( ctuXPosInCtus == tileXPosInCtus &&
!( cu.blocks[cu.chType].x & ( cs.pcv->maxCUWidthMask >> getChannelTypeScaleX( cu.chType, cu.chromaFormat ) ) ) &&
!( cu.blocks[cu.chType].y & ( cs.pcv->maxCUHeightMask >> getChannelTypeScaleY( cu.chType, cu.chromaFormat ) ) ) &&
( cs.getCU( cu.blocks[cu.chType].pos().offset( 0, -1 ), cu.chType) != NULL ) &&
CU::isSameSliceAndTile( *cs.getCU( cu.blocks[cu.chType].pos().offset( 0, -1 ), cu.chType), cu ) )
{
return ( ( cs.getCU( cu.blocks[cu.chType].pos().offset( 0, -1 ), cu.chType ) )->qp );
}
else
{
const int a = ( cu.blocks[cu.chType].y & ( cs.pcv->maxCUHeightMask >> getChannelTypeScaleY( cu.chType, cu.chromaFormat ) ) ) ? ( cs.getCU(cu.blocks[cu.chType].pos().offset( 0, -1 ), cu.chType))->qp : prevQP;
const int b = ( cu.blocks[cu.chType].x & ( cs.pcv->maxCUWidthMask >> getChannelTypeScaleX( cu.chType, cu.chromaFormat ) ) ) ? ( cs.getCU(cu.blocks[cu.chType].pos().offset( -1, 0 ), cu.chType))->qp : prevQP;
return ( a + b + 1 ) >> 1;
}

Karsten Suehring
committed
}
uint32_t CU::getNumPUs( const CodingUnit& cu )
{
uint32_t cnt = 0;
PredictionUnit *pu = cu.firstPU;
do
{
cnt++;
} while( ( pu != cu.lastPU ) && ( pu = pu->next ) );
return cnt;
}
void CU::addPUs( CodingUnit& cu )
{
cu.cs->addPU( CS::getArea( *cu.cs, cu, cu.chType ), cu.chType );
}
void CU::saveMotionInHMVP( const CodingUnit& cu, const bool isToBeDone )
{
const PredictionUnit& pu = *cu.firstPU;
#if !JVET_Q0806
if (!cu.triangle && !cu.affine && !isToBeDone )
#else
if (!cu.geoFlag && !cu.affine && !isToBeDone)
#endif
{
MotionInfo mi = pu.getMotionInfo();
mi.BcwIdx = (mi.interDir == 3) ? cu.BcwIdx : BCW_DEFAULT;
#if JVET_Q0297_MER
const unsigned log2ParallelMergeLevel = (pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2);
const unsigned xBr = pu.cu->Y().width + pu.cu->Y().x;
const unsigned yBr = pu.cu->Y().height + pu.cu->Y().y;
bool enableHmvp = ((xBr >> log2ParallelMergeLevel) > (pu.cu->Y().x >> log2ParallelMergeLevel)) && ((yBr >> log2ParallelMergeLevel) > (pu.cu->Y().y >> log2ParallelMergeLevel));
bool enableInsertion = CU::isIBC(cu) || enableHmvp;
if (enableInsertion)
#endif
cu.cs->addMiToLut(CU::isIBC(cu) ? cu.cs->motionLut.lutIbc : cu.cs->motionLut.lut, mi);
}
}

Karsten Suehring
committed
PartSplit CU::getSplitAtDepth( const CodingUnit& cu, const unsigned depth )
{
if( depth >= cu.depth ) return CU_DONT_SPLIT;
const PartSplit cuSplitType = PartSplit( ( cu.splitSeries >> ( depth * SPLIT_DMULT ) ) & SPLIT_MASK );
if ( cuSplitType == CU_QUAD_SPLIT ) return CU_QUAD_SPLIT;
else if( cuSplitType == CU_HORZ_SPLIT ) return CU_HORZ_SPLIT;
else if( cuSplitType == CU_VERT_SPLIT ) return CU_VERT_SPLIT;
else if( cuSplitType == CU_TRIH_SPLIT ) return CU_TRIH_SPLIT;
else if( cuSplitType == CU_TRIV_SPLIT ) return CU_TRIV_SPLIT;
else { THROW( "Unknown split mode" ); return CU_QUAD_SPLIT; }
}
ModeType CU::getModeTypeAtDepth( const CodingUnit& cu, const unsigned depth )
{
ModeType modeType = ModeType( (cu.modeTypeSeries >> (depth * 3)) & 0x07 );
CHECK( depth > cu.depth, " depth is wrong" );
return modeType;
}

Karsten Suehring
committed
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
bool CU::divideTuInRows( const CodingUnit &cu )
{
CHECK( cu.ispMode != HOR_INTRA_SUBPARTITIONS && cu.ispMode != VER_INTRA_SUBPARTITIONS, "Intra Subpartitions type not recognized!" );
return cu.ispMode == HOR_INTRA_SUBPARTITIONS ? true : false;
}
PartSplit CU::getISPType( const CodingUnit &cu, const ComponentID compID )
{
if( cu.ispMode && isLuma( compID ) )
{
const bool tuIsDividedInRows = CU::divideTuInRows( cu );
return tuIsDividedInRows ? TU_1D_HORZ_SPLIT : TU_1D_VERT_SPLIT;
}
return TU_NO_ISP;
}
bool CU::isISPLast( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID )
{
PartSplit partitionType = CU::getISPType( cu, compID );
Area originalArea = cu.blocks[compID];
switch( partitionType )
{
case TU_1D_HORZ_SPLIT:
return tuArea.y + tuArea.height == originalArea.y + originalArea.height;
case TU_1D_VERT_SPLIT:
return tuArea.x + tuArea.width == originalArea.x + originalArea.width;
default:
THROW( "Unknown ISP processing order type!" );
return false;
}
}
bool CU::isISPFirst( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID )
{
return tuArea == cu.firstTU->blocks[compID];
}
Santiago de Luxán Hernández
committed
bool CU::canUseISP( const CodingUnit &cu, const ComponentID compID )
{
const int width = cu.blocks[compID].width;
const int height = cu.blocks[compID].height;
const int maxTrSize = cu.cs->sps->getMaxTbSize();
Santiago de Luxán Hernández
committed
return CU::canUseISP( width, height, maxTrSize );
Santiago de Luxán Hernández
committed
bool CU::canUseISP( const int width, const int height, const int maxTrSize )
bool notEnoughSamplesToSplit = ( floorLog2(width) + floorLog2(height) <= ( floorLog2(MIN_TB_SIZEY) << 1 ) );
Santiago de Luxán Hernández
committed
bool cuSizeLargerThanMaxTrSize = width > maxTrSize || height > maxTrSize;
if ( notEnoughSamplesToSplit || cuSizeLargerThanMaxTrSize )
Santiago de Luxán Hernández
committed
return false;
Santiago de Luxán Hernández
committed
return true;
bool CU::canUseLfnstWithISP( const CompArea& cuArea, const ISPType ispSplitType )
{
if( ispSplitType == NOT_INTRA_SUBPARTITIONS )
{
return false;
}
Size tuSize = ( ispSplitType == HOR_INTRA_SUBPARTITIONS ) ? Size( cuArea.width, CU::getISPSplitDim( cuArea.width, cuArea.height, TU_1D_HORZ_SPLIT ) ) :
Size( CU::getISPSplitDim( cuArea.width, cuArea.height, TU_1D_VERT_SPLIT ), cuArea.height );
if( !( tuSize.width >= MIN_TB_SIZEY && tuSize.height >= MIN_TB_SIZEY ) )
{
return false;
}
return true;
}
bool CU::canUseLfnstWithISP( const CodingUnit& cu, const ChannelType chType )
{
CHECK( !isLuma( chType ), "Wrong ISP mode!" );
return CU::canUseLfnstWithISP( cu.blocks[chType == CHANNEL_TYPE_LUMA ? 0 : 1], (ISPType)cu.ispMode );
}
uint32_t CU::getISPSplitDim( const int width, const int height, const PartSplit ispType )
{
bool divideTuInRows = ispType == TU_1D_HORZ_SPLIT;
uint32_t splitDimensionSize, nonSplitDimensionSize, partitionSize, divShift = 2;
if( divideTuInRows )
{
splitDimensionSize = height;
nonSplitDimensionSize = width;
}
else
{
splitDimensionSize = width;
nonSplitDimensionSize = height;
}

Karsten Suehring
committed
const int minNumberOfSamplesPerCu = 1 << ( ( floorLog2(MIN_TB_SIZEY) << 1 ) );
const int factorToMinSamples = nonSplitDimensionSize < minNumberOfSamplesPerCu ? minNumberOfSamplesPerCu >> floorLog2(nonSplitDimensionSize) : 1;
partitionSize = ( splitDimensionSize >> divShift ) < factorToMinSamples ? factorToMinSamples : ( splitDimensionSize >> divShift );
CHECK( floorLog2(partitionSize) + floorLog2(nonSplitDimensionSize) < floorLog2(minNumberOfSamplesPerCu), "A partition has less than the minimum amount of samples!" );
return partitionSize;
}

Karsten Suehring
committed
bool CU::allLumaCBFsAreZero(const CodingUnit& cu)
{
if (!cu.ispMode)
{
return TU::getCbf(*cu.firstTU, COMPONENT_Y) == false;
}
else
{
int numTotalTUs = cu.ispMode == HOR_INTRA_SUBPARTITIONS ? cu.lheight() >> floorLog2(cu.firstTU->lheight()) : cu.lwidth() >> floorLog2(cu.firstTU->lwidth());
TransformUnit* tuPtr = cu.firstTU;
for (int tuIdx = 0; tuIdx < numTotalTUs; tuIdx++)
{
if (TU::getCbf(*tuPtr, COMPONENT_Y) == true)
{
return false;
}
tuPtr = tuPtr->next;
}
return true;
}
}

Karsten Suehring
committed
PUTraverser CU::traversePUs( CodingUnit& cu )
{
return PUTraverser( cu.firstPU, cu.lastPU->next );
}
TUTraverser CU::traverseTUs( CodingUnit& cu )
{
return TUTraverser( cu.firstTU, cu.lastTU->next );
}
cPUTraverser CU::traversePUs( const CodingUnit& cu )
{
return cPUTraverser( cu.firstPU, cu.lastPU->next );
}
cTUTraverser CU::traverseTUs( const CodingUnit& cu )
{
return cTUTraverser( cu.firstTU, cu.lastTU->next );
}
// PU tools
int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType &channelType /*= CHANNEL_TYPE_LUMA*/ )
{
const int numMPMs = NUM_MOST_PROBABLE_MODES;

Karsten Suehring
committed
{
CHECK(channelType != CHANNEL_TYPE_LUMA, "Not harmonized yet");

Karsten Suehring
committed
int numCand = -1;
int leftIntraDir = PLANAR_IDX, aboveIntraDir = PLANAR_IDX;
const CompArea &area = pu.block(getFirstComponentOfChannel(channelType));
const Position posRT = area.topRight();
const Position posLB = area.bottomLeft();
// Get intra direction of left PU
const PredictionUnit *puLeft = pu.cs->getPURestricted(posLB.offset(-1, 0), pu, channelType);
if (puLeft && CU::isIntra(*puLeft->cu))
{
leftIntraDir = PU::getIntraDirLuma( *puLeft );
}
// Get intra direction of above PU
const PredictionUnit *puAbove = pu.cs->getPURestricted(posRT.offset(0, -1), pu, channelType);
if (puAbove && CU::isIntra(*puAbove->cu) && CU::isSameCtu(*pu.cu, *puAbove->cu))
{
aboveIntraDir = PU::getIntraDirLuma( *puAbove );
}
CHECK(2 >= numMPMs, "Invalid number of most probable modes");
mpm[0] = PLANAR_IDX;
mpm[1] = DC_IDX;
mpm[2] = VER_IDX;
mpm[3] = HOR_IDX;
mpm[4] = VER_IDX - 4;
mpm[5] = VER_IDX + 4;
numCand = 1;
if (leftIntraDir > DC_IDX)
mpm[0] = PLANAR_IDX;
mpm[1] = leftIntraDir;
mpm[2] = ((leftIntraDir + offset) % mod) + 2;
mpm[3] = ((leftIntraDir - 1) % mod) + 2;
mpm[4] = ((leftIntraDir + offset - 1) % mod) + 2;
mpm[5] = ( leftIntraDir % mod) + 2;
int maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;
if ((leftIntraDir > DC_IDX) && (aboveIntraDir > DC_IDX))
{
mpm[0] = PLANAR_IDX;
mpm[1] = leftIntraDir;
mpm[2] = aboveIntraDir;
maxCandModeIdx = mpm[1] > mpm[2] ? 1 : 2;
int minCandModeIdx = mpm[1] > mpm[2] ? 2 : 1;
if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 1)
{
mpm[3] = ((mpm[minCandModeIdx] + offset) % mod) + 2;
mpm[4] = ((mpm[maxCandModeIdx] - 1) % mod) + 2;
mpm[5] = ((mpm[minCandModeIdx] + offset - 1) % mod) + 2;
}
else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] >= 62)
{
mpm[3] = ((mpm[minCandModeIdx] - 1) % mod) + 2;
mpm[4] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
mpm[5] = ( mpm[minCandModeIdx] % mod) + 2;
}
else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 2)
{
mpm[3] = ((mpm[minCandModeIdx] - 1) % mod) + 2;
mpm[4] = ((mpm[minCandModeIdx] + offset) % mod) + 2;
mpm[5] = ((mpm[maxCandModeIdx] - 1) % mod) + 2;
}
else
{
mpm[3] = ((mpm[minCandModeIdx] + offset) % mod) + 2;
mpm[4] = ((mpm[minCandModeIdx] - 1) % mod) + 2;
mpm[5] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
}
}
else if (leftIntraDir + aboveIntraDir >= 2)
{
mpm[0] = PLANAR_IDX;
mpm[1] = (leftIntraDir < aboveIntraDir) ? aboveIntraDir : leftIntraDir;
maxCandModeIdx = 1;
mpm[2] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
mpm[3] = ((mpm[maxCandModeIdx] - 1) % mod) + 2;
mpm[4] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2;
mpm[5] = ( mpm[maxCandModeIdx] % mod) + 2;

Karsten Suehring
committed
for (int i = 0; i < numMPMs; i++)
{
CHECK(mpm[i] >= NUM_LUMA_MODE, "Invalid MPM");
}
CHECK(numCand == 0, "No candidates found");
return numCand;
}
}
bool PU::isMIP(const PredictionUnit &pu, const ChannelType &chType)
{
return (chType == CHANNEL_TYPE_LUMA && pu.cu->mipFlag);
}
uint32_t PU::getIntraDirLuma( const PredictionUnit &pu )
{
if (isMIP(pu))
{
}
else
{
return pu.intraDir[CHANNEL_TYPE_LUMA];
}
}

Karsten Suehring
committed
void PU::getIntraChromaCandModes( const PredictionUnit &pu, unsigned modeList[NUM_CHROMA_MODE] )
{
{
modeList[ 0 ] = PLANAR_IDX;
modeList[ 1 ] = VER_IDX;
modeList[ 2 ] = HOR_IDX;
modeList[ 3 ] = DC_IDX;
modeList[4] = LM_CHROMA_IDX;
modeList[5] = MDLM_L_IDX;
modeList[6] = MDLM_T_IDX;
modeList[7] = DM_CHROMA_IDX;

Karsten Suehring
committed
const uint32_t lumaMode = getCoLocatedIntraLumaMode(pu);

Karsten Suehring
committed
for( int i = 0; i < 4; i++ )
{
if( lumaMode == modeList[i] )
{
modeList[i] = VDIA_IDX;
break;
}
}
}
}
bool PU::isLMCMode(unsigned mode)
{
return (mode >= LM_CHROMA_IDX && mode <= MDLM_T_IDX);

Karsten Suehring
committed
}

Karsten Suehring
committed
bool PU::isLMCModeEnabled(const PredictionUnit &pu, unsigned mode)
{
Yin Zhao
committed
if ( pu.cs->sps->getUseLMChroma() && pu.cu->checkCCLMAllowed() )

Karsten Suehring
committed
{
return true;
}
return false;
}
int PU::getLMSymbolList(const PredictionUnit &pu, int *modeList)

Karsten Suehring
committed
{

Karsten Suehring
committed
modeList[idx++] = MDLM_L_IDX;
modeList[idx++] = MDLM_T_IDX;
return idx;

Karsten Suehring
committed
}
bool PU::isChromaIntraModeCrossCheckMode( const PredictionUnit &pu )
{
return !pu.cu->bdpcmModeChroma && pu.intraDir[CHANNEL_TYPE_CHROMA] == DM_CHROMA_IDX;

Karsten Suehring
committed
}
uint32_t PU::getFinalIntraMode( const PredictionUnit &pu, const ChannelType &chType )
{
uint32_t uiIntraMode = pu.intraDir[chType];
if( uiIntraMode == DM_CHROMA_IDX && !isLuma( chType ) )
{
uiIntraMode = getCoLocatedIntraLumaMode(pu);

Karsten Suehring
committed
}
if( pu.chromaFormat == CHROMA_422 && !isLuma( chType ) && uiIntraMode < NUM_LUMA_MODE ) // map directional, planar and dc

Karsten Suehring
committed
{
uiIntraMode = g_chroma422IntraAngleMappingTable[uiIntraMode];
}
return uiIntraMode;
}
uint32_t PU::getCoLocatedIntraLumaMode( const PredictionUnit &pu )
{
Position topLeftPos = pu.blocks[pu.chType].lumaPos();
Position refPos = topLeftPos.offset( pu.blocks[pu.chType].lumaSize().width >> 1, pu.blocks[pu.chType].lumaSize().height >> 1 );
const PredictionUnit &lumaPU = pu.cu->isSepTree() ? *pu.cs->picture->cs->getPU( refPos, CHANNEL_TYPE_LUMA ) : *pu.cs->getPU( topLeftPos, CHANNEL_TYPE_LUMA );
return PU::getIntraDirLuma( lumaPU );
}
int PU::getWideAngIntraMode( const TransformUnit &tu, const uint32_t dirMode, const ComponentID compID )
{
if( dirMode < 2 )
{
return ( int ) dirMode;
}
const CompArea& area = tu.cu->ispMode && isLuma(compID) ? tu.cu->blocks[compID] : tu.blocks[ compID ];
int width = area.width;
int height = area.height;
int modeShift[ ] = { 0, 6, 10, 12, 14, 15 };
int deltaSize = abs( floorLog2( width ) - floorLog2( height ) );
int predMode = dirMode;
if( width > height && dirMode < 2 + modeShift[ deltaSize ] )
{
predMode += ( VDIA_IDX - 1 );
}
else if( height > width && predMode > VDIA_IDX - modeShift[ deltaSize ] )
{
predMode -= ( VDIA_IDX + 1 );
}
return predMode;
}
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
, const bool ibcFlag
, const bool isGt4x4
)
const Slice& slice = *cs.slice;
auto &lut = ibcFlag ? cs.motionLut.lutIbc : cs.motionLut.lut;
for (int mrgIdx = 1; mrgIdx <= num_avai_candInLUT; mrgIdx++)
{
miNeighbor = lut[num_avai_candInLUT - mrgIdx];
if ( mrgIdx > 2 || ((mrgIdx > 1 || !isGt4x4) && ibcFlag)
|| ((!isAvailableA1 || (miLeft != miNeighbor)) && (!isAvailableB1 || (miAbove != miNeighbor))) )
mrgCtx.interDirNeighbours[cnt] = miNeighbor.interDir;
mrgCtx.useAltHpelIf [cnt] = !ibcFlag && miNeighbor.useAltHpelIf;
mrgCtx.BcwIdx [cnt] = (miNeighbor.interDir == 3) ? miNeighbor.BcwIdx : BCW_DEFAULT;
mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miNeighbor.mv[0], miNeighbor.refIdx[0]);
if (slice.isInterB())
{
mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miNeighbor.mv[1], miNeighbor.refIdx[1]);
}
{
return true;
}
cnt ++;
if (cnt == maxNumMergeCandMin1)
{
break;
}
}
}
if (cnt < maxNumMergeCandMin1)
{
mrgCtx.useAltHpelIf[cnt] = false;
}
void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx)
{
const CodingStructure &cs = *pu.cs;
const uint32_t maxNumMergeCand = pu.cs->sps->getMaxNumIBCMergeCand();
for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
{
mrgCtx.BcwIdx[ui] = BCW_DEFAULT;
mrgCtx.interDirNeighbours[ui] = 0;
mrgCtx.mrgTypeNeighbours[ui] = MRG_TYPE_IBC;
mrgCtx.mvFieldNeighbours[ui * 2].refIdx = NOT_VALID;
mrgCtx.mvFieldNeighbours[ui * 2 + 1].refIdx = NOT_VALID;
}
mrgCtx.numValidMergeCand = maxNumMergeCand;
// compute the location of the current PU
int cnt = 0;
const Position posRT = pu.Y().topRight();
const Position posLB = pu.Y().bottomLeft();
MotionInfo miAbove, miLeft, miAboveLeft, miAboveRight, miBelowLeft;
//left
const PredictionUnit* puLeft = cs.getPURestricted(posLB.offset(-1, 0), pu, pu.chType);
bool isGt4x4 = pu.lwidth() * pu.lheight() > 16;
#if JVET_Q0297_MER
const bool isAvailableA1 = puLeft && pu.cu != puLeft->cu && CU::isIBC(*puLeft->cu);
#else
const bool isAvailableA1 = puLeft && isDiffMER(pu, *puLeft) && pu.cu != puLeft->cu && CU::isIBC(*puLeft->cu);
{
miLeft = puLeft->getMotionInfo(posLB.offset(-1, 0));
// get Inter Dir
mrgCtx.interDirNeighbours[cnt] = miLeft.interDir;
// get Mv from Left
mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miLeft.mv[0], miLeft.refIdx[0]);
{
return;
}
cnt++;
}
// early termination
if (cnt == maxNumMergeCand)
{
return;
}
// above
const PredictionUnit *puAbove = cs.getPURestricted(posRT.offset(0, -1), pu, pu.chType);
#if JVET_Q0297_MER
bool isAvailableB1 = puAbove && pu.cu != puAbove->cu && CU::isIBC(*puAbove->cu);
#else
bool isAvailableB1 = puAbove && isDiffMER(pu, *puAbove) && pu.cu != puAbove->cu && CU::isIBC(*puAbove->cu);
{
miAbove = puAbove->getMotionInfo(posRT.offset(0, -1));
if (!isAvailableA1 || (miAbove != miLeft))
{
// get Inter Dir
mrgCtx.interDirNeighbours[cnt] = miAbove.interDir;
// get Mv from Above
mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAbove.mv[0], miAbove.refIdx[0]);
{
return;
}
cnt++;
}
}
// early termination
if (cnt == maxNumMergeCand)
{
return;
}
if (cnt != maxNumMergeCand)
bool bFound = addMergeHMVPCand(cs, mrgCtx, mrgCandIdx, maxNumMergeCand, cnt
, isAvailableA1, miLeft, isAvailableB1, miAbove
while (cnt < maxNumMergeCand)
{
mrgCtx.mvFieldNeighbours[cnt * 2].setMvField(Mv(0, 0), MAX_NUM_REF);
mrgCtx.interDirNeighbours[cnt] = 1;
void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
int mmvdList,
const int& mrgCandIdx )

Karsten Suehring
committed
{
const unsigned plevel = pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2;
#endif

Karsten Suehring
committed
const CodingStructure &cs = *pu.cs;
const Slice &slice = *pu.cs->slice;
const uint32_t maxNumMergeCand = pu.cs->sps->getMaxNumMergeCand();

Karsten Suehring
committed
for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
{
mrgCtx.BcwIdx[ui] = BCW_DEFAULT;

Karsten Suehring
committed
mrgCtx.interDirNeighbours[ui] = 0;
mrgCtx.mrgTypeNeighbours [ui] = MRG_TYPE_DEFAULT_N;
mrgCtx.mvFieldNeighbours[(ui << 1) ].refIdx = NOT_VALID;
mrgCtx.mvFieldNeighbours[(ui << 1) + 1].refIdx = NOT_VALID;

Karsten Suehring
committed
}
mrgCtx.numValidMergeCand = maxNumMergeCand;
// compute the location of the current PU
int cnt = 0;
const Position posLT = pu.Y().topLeft();
const Position posRT = pu.Y().topRight();
const Position posLB = pu.Y().bottomLeft();

Karsten Suehring
committed
MotionInfo miAbove, miLeft, miAboveLeft, miAboveRight, miBelowLeft;
// above
const PredictionUnit *puAbove = cs.getPURestricted(posRT.offset(0, -1), pu, pu.chType);
bool isAvailableB1 = puAbove && isDiffMER(pu.lumaPos(), posRT.offset(0, -1), plevel) && pu.cu != puAbove->cu && CU::isInter(*puAbove->cu);
#else
bool isAvailableB1 = puAbove && isDiffMER(pu, *puAbove) && pu.cu != puAbove->cu && CU::isInter(*puAbove->cu);
if (isAvailableB1)
{
miAbove = puAbove->getMotionInfo(posRT.offset(0, -1));
// get Inter Dir
mrgCtx.interDirNeighbours[cnt] = miAbove.interDir;
mrgCtx.useAltHpelIf[cnt] = miAbove.useAltHpelIf;
// get Mv from Above
mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAbove->cu->BcwIdx : BCW_DEFAULT;
mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAbove.mv[0], miAbove.refIdx[0]);
if (slice.isInterB())
{
mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miAbove.mv[1], miAbove.refIdx[1]);
}
{
return;
}
cnt++;
}
// early termination
if (cnt == maxNumMergeCand)
{
return;
}
//left
const PredictionUnit* puLeft = cs.getPURestricted(posLB.offset(-1, 0), pu, pu.chType);
const bool isAvailableA1 = puLeft && isDiffMER(pu.lumaPos(), posLB.offset(-1, 0), plevel) && pu.cu != puLeft->cu && CU::isInter(*puLeft->cu);
#else
const bool isAvailableA1 = puLeft && isDiffMER(pu, *puLeft) && pu.cu != puLeft->cu && CU::isInter(*puLeft->cu);
if (isAvailableA1)
{
miLeft = puLeft->getMotionInfo(posLB.offset(-1, 0));
if (!isAvailableB1 || (miAbove != miLeft))
{
// get Inter Dir
mrgCtx.interDirNeighbours[cnt] = miLeft.interDir;
mrgCtx.useAltHpelIf[cnt] = miLeft.useAltHpelIf;
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 (slice.isInterB())
{
mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miLeft.mv[1], miLeft.refIdx[1]);
}
{
return;
}
cnt++;
}
}

Karsten Suehring
committed
// early termination
if( cnt == maxNumMergeCand )
{
return;
}
// above right
const PredictionUnit *puAboveRight = cs.getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
bool isAvailableB0 = puAboveRight && isDiffMER( pu.lumaPos(), posRT.offset(1, -1), plevel) && CU::isInter( *puAboveRight->cu );
#else

Karsten Suehring
committed
bool isAvailableB0 = puAboveRight && isDiffMER( pu, *puAboveRight ) && CU::isInter( *puAboveRight->cu );

Karsten Suehring
committed
if( isAvailableB0 )
{
miAboveRight = puAboveRight->getMotionInfo( posRT.offset( 1, -1 ) );
if( !isAvailableB1 || ( miAbove != miAboveRight ) )
{
// get Inter Dir
mrgCtx.interDirNeighbours[cnt] = miAboveRight.interDir;
mrgCtx.useAltHpelIf[cnt] = miAboveRight.useAltHpelIf;
// get Mv from Above-right
mrgCtx.BcwIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveRight->cu->BcwIdx : BCW_DEFAULT;

Christian Helmrich
committed
mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveRight.mv[0], miAboveRight.refIdx[0] );

Karsten Suehring
committed
if( slice.isInterB() )
{
mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveRight.mv[1], miAboveRight.refIdx[1] );
}