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
* 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 )
{
#if INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
return isDualITree(cs) ? area.singleChan(chType) : area;
#else
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();
int curPicWidth = curPPS->getPicWidthInLumaSamples() - SPS::getWinUnitX( sps->getChromaFormatIdc() ) * (curScalingWindow.getWindowLeftOffset() + curScalingWindow.getWindowRightOffset());
int curPicHeight = curPPS->getPicHeightInLumaSamples() - SPS::getWinUnitY( sps->getChromaFormatIdc() ) * (curScalingWindow.getWindowTopOffset() + curScalingWindow.getWindowBottomOffset());
const Window& refScalingWindow = refPic->getScalingWindow();
int refPicWidth = refPic->getPicWidthInLumaSamples() - SPS::getWinUnitX( sps->getChromaFormatIdc() ) * (refScalingWindow.getWindowLeftOffset() + refScalingWindow.getWindowRightOffset());
int refPicHeight = refPic->getPicHeightInLumaSamples() - SPS::getWinUnitY( sps->getChromaFormatIdc() ) * (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
Peter Chuang
committed
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_S0048_SCALING_OFFSET
int subWidthC = SPS::getWinUnitX(sps->getChromaFormatIdc());
int subHeightC = SPS::getWinUnitY(sps->getChromaFormatIdc());
CHECK(subWidthC * curScalingWindow.getWindowLeftOffset() < (-curPicWidthY) * 15, "The value of SubWidthC * pps_scaling_win_left_offset shall be greater than or equal to -pps_pic_width_in_luma_samples * 15");
CHECK(subWidthC * curScalingWindow.getWindowLeftOffset() >= curPicWidthY, "The value of SubWidthC * pps_scaling_win_left_offset shall be less than pic_width_in_luma_samples");
CHECK(subWidthC * curScalingWindow.getWindowRightOffset() < (-curPicWidthY) * 15, "The value of SubWidthC * pps_scaling_win_right_offset shall be greater than or equal to -pps_pic_width_in_luma_samples * 15");
CHECK(subWidthC * curScalingWindow.getWindowRightOffset() >= curPicWidthY, "The value of SubWidthC * pps_scaling_win_right_offset shall be less than pic_width_in_luma_samples");
CHECK(subHeightC * curScalingWindow.getWindowTopOffset() < (-curPicHeightY) * 15, "The value of SubHeightC * pps_scaling_win_top_offset shall be greater than or equal to -pps_pic_height_in_luma_samples * 15");
CHECK(subHeightC * curScalingWindow.getWindowTopOffset() >= curPicHeightY, "The value of SubHeightC * pps_scaling_win_top_offset shall be less than pps_pic_height_in_luma_samples");
CHECK(subHeightC * curScalingWindow.getWindowBottomOffset() < (-curPicHeightY) * 15, "The value of SubHeightC *pps_scaling_win_bottom_offset shall be greater than or equal to -pps_pic_height_in_luma_samples * 15");
CHECK(subHeightC * curScalingWindow.getWindowBottomOffset() >= curPicHeightY, "The value of SubHeightC *pps_scaling_win_bottom_offset shall be less than pps_pic_height_in_luma_samples");
CHECK(subWidthC * (curScalingWindow.getWindowLeftOffset() + curScalingWindow.getWindowRightOffset()) < (-curPicWidthY) * 15, "The value of SubWidthC * ( pps_scaling_win_left_offset + pps_scaling_win_right_offset ) shall be greater than or equal to -pps_pic_width_in_luma_samples * 15");
CHECK(subWidthC * (curScalingWindow.getWindowLeftOffset() + curScalingWindow.getWindowRightOffset()) >= curPicWidthY, "The value of SubWidthC * ( pps_scaling_win_left_offset + pps_scaling_win_right_offset ) shall be less than pic_width_in_luma_samples");
CHECK(subHeightC * (curScalingWindow.getWindowTopOffset() + curScalingWindow.getWindowBottomOffset()) < (-curPicHeightY) * 15, "The value of SubHeightC * ( pps_scaling_win_top_offset + pps_scaling_win_bottom_offset ) shall be greater than or equal to -pps_pic_height_in_luma_samples * 15");
CHECK(subHeightC * (curScalingWindow.getWindowTopOffset() + curScalingWindow.getWindowBottomOffset()) >= curPicHeightY, "The value of SubHeightC * ( pps_scaling_win_top_offset + pps_scaling_win_bottom_offset ) shall be less than pic_height_in_luma_samples");
#else
CHECK(SPS::getWinUnitX(sps->getChromaFormatIdc()) * (abs(curScalingWindow.getWindowLeftOffset()) + abs(curScalingWindow.getWindowRightOffset())) > curPPS->getPicWidthInLumaSamples(), "The value of SubWidthC * ( Abs(pps_scaling_win_left_offset) + Abs(pps_scaling_win_right_offset) ) shall be less than pic_width_in_luma_samples");
CHECK(SPS::getWinUnitY(sps->getChromaFormatIdc()) * (abs(curScalingWindow.getWindowTopOffset()) + abs(curScalingWindow.getWindowBottomOffset())) > curPPS->getPicHeightInLumaSamples(), "The value of SubHeightC * ( Abs(pps_scaling_win_top_offset) + Abs(pps_scaling_win_bottom_offset) ) shall be less than pic_height_in_luma_samples");
#endif
return refPic->isRefScaled( curPPS );
}
const int numRefList = slice->isInterB() ? 2 : 1;
#if JVET_S0258_SUBPIC_CONSTRAINTS
int currentSubPicIdx = NOT_VALID;
// derive sub-picture index for the current slice
for( int subPicIdx = 0; subPicIdx < slice->getPic()->cs->sps->getNumSubPics(); subPicIdx++ )
{
if( slice->getPic()->cs->pps->getSubPic( subPicIdx ).getSubPicID() == slice->getSliceSubPicId() )
{
currentSubPicIdx = subPicIdx;
break;
}
}
CHECK( currentSubPicIdx == NOT_VALID, "Sub-picture was not found" );
if( !slice->getPic()->cs->sps->getSubPicTreatedAsPicFlag( currentSubPicIdx ) )
{
return;
}
#endif
//constraint 1: The picture referred to by each active entry in RefPicList[ 0 ] or RefPicList[ 1 ] has the same subpicture layout as the current picture
bool isAllRefSameSubpicLayout = true;
for (int refList = 0; refList < numRefList; refList++) // loop over l0 and l1
RefPicList eRefPicList = (refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);
for (int refIdx = 0; refIdx < slice->getNumRefIdx(eRefPicList); refIdx++)
#if JVET_S0258_SUBPIC_CONSTRAINTS
const Picture* refPic = slice->getRefPic( eRefPicList, refIdx );
if( refPic->subPictures.size() != slice->getPic()->cs->pps->getNumSubPics() )
#else
const Picture* refPic = slice->getRefPic(eRefPicList, refIdx)->unscaledPic;
if (refPic->numSubpics != slice->getPic()->cs->pps->getNumSubPics())
{
isAllRefSameSubpicLayout = false;
}
else
{
#if JVET_S0258_SUBPIC_CONSTRAINTS
for( int i = 0; i < refPic->subPictures.size(); i++ )
{
const SubPic& refSubPic = refPic->subPictures[i];
const SubPic& curSubPic = slice->getPic()->cs->pps->getSubPic( i );
if( refSubPic.getSubPicWidthInCTUs() != curSubPic.getSubPicWidthInCTUs()
|| refSubPic.getSubPicHeightInCTUs() != curSubPic.getSubPicHeightInCTUs()
|| refSubPic.getSubPicCtuTopLeftX() != curSubPic.getSubPicCtuTopLeftX()
|| refSubPic.getSubPicCtuTopLeftY() != curSubPic.getSubPicCtuTopLeftY()
|| ( refPic->layerId != slice->getPic()->layerId && refSubPic.getSubPicID() != curSubPic.getSubPicID() )
|| refSubPic.getTreatedAsPicFlag() != curSubPic.getTreatedAsPicFlag())
#else
for (int i = 0; i < refPic->numSubpics; i++)
if (refPic->subpicWidthInCTUs[i] != slice->getPic()->cs->pps->getSubPic(i).getSubPicWidthInCTUs()
|| refPic->subpicHeightInCTUs[i] != slice->getPic()->cs->pps->getSubPic(i).getSubPicHeightInCTUs()
|| refPic->subpicCtuTopLeftX[i] != slice->getPic()->cs->pps->getSubPic(i).getSubPicCtuTopLeftX()
|| refPic->subpicCtuTopLeftY[i] != slice->getPic()->cs->pps->getSubPic(i).getSubPicCtuTopLeftY())
{
isAllRefSameSubpicLayout = false;
refIdx = slice->getNumRefIdx(eRefPicList);
refList = numRefList;
#if JVET_S0258_SUBPIC_CONSTRAINTS
// A picture with different sub-picture ID of the collocated sub-picture cannot be used as an active reference picture in the same layer
if( refPic->layerId == slice->getPic()->layerId )
{
isAllRefSameSubpicLayout = isAllRefSameSubpicLayout && refPic->subPictures[currentSubPicIdx].getSubPicID() == slice->getSliceSubPicId();
}
#endif
}
}
}
//constraint 2: The picture referred to by each active entry in RefPicList[ 0 ] or RefPicList[ 1 ] is an ILRP for which the value of sps_num_subpics_minus1 is equal to 0
if (!isAllRefSameSubpicLayout)
{
for (int refList = 0; refList < numRefList; refList++) // loop over l0 and l1
RefPicList eRefPicList = (refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);
for (int refIdx = 0; refIdx < slice->getNumRefIdx(eRefPicList); refIdx++)
#if JVET_S0258_SUBPIC_CONSTRAINTS
const Picture* refPic = slice->getRefPic( eRefPicList, refIdx );
CHECK( refPic->layerId == slice->getPic()->layerId || refPic->subPictures.size() > 1, "The inter-layer reference shall contain a single subpicture or have same subpicture layout with the current picture" );
#else
const Picture* refPic = slice->getRefPic(eRefPicList, refIdx)->unscaledPic;
CHECK(!(refPic->layerId != slice->getPic()->layerId && refPic->numSubpics == 1), "The inter-layer reference shall contain a single subpicture or have same subpicture layout with the current picture");
}
}
}
return;
}

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::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;
}
bool CU::isSameSliceAndTile(const CodingUnit& cu, const CodingUnit& cu2)
{
return ( cu.slice->getIndependentSliceIdx() == cu2.slice->getIndependentSliceIdx() ) && ( cu.tileIdx == cu2.tileIdx );
}
bool CU::isSameSubPic(const CodingUnit& cu, const CodingUnit& cu2)
{
return (cu.slice->getPPS()->getSubPicFromCU(cu).getSubPicIdx() == cu2.slice->getPPS()->getSubPicFromCU(cu2).getSubPicIdx()) ;
}

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 )
{
#if INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
const Area cuAreaY = CS::isDualITree(*cu.cs) ? 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();
#else
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();
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 (!cu.geoFlag && !cu.affine && !isToBeDone)
{
MotionInfo mi = pu.getMotionInfo();
#if MULTI_HYP_PRED
mi.addHypData = pu.addHypData;
#endif
mi.BcwIdx = (mi.interDir == 3) ? cu.BcwIdx : BCW_DEFAULT;
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)
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;
}

Karsten Suehring
committed
const PartSplit cuSplitType = PartSplit( ( cu.splitSeries >> ( depth * SPLIT_DMULT ) ) & SPLIT_MASK );
if (cuSplitType == CU_QUAD_SPLIT)
{
return CU_QUAD_SPLIT;
}

Karsten Suehring
committed
else if (cuSplitType == CU_HORZ_SPLIT)
{
return CU_HORZ_SPLIT;
}

Karsten Suehring
committed
else if (cuSplitType == CU_VERT_SPLIT)
{
return CU_VERT_SPLIT;
}

Karsten Suehring
committed
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;
}

Karsten Suehring
committed
}
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
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
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
#if SECONDARY_MPM
int PU::getIntraMPMs( const PredictionUnit &pu, uint8_t* mpm, uint8_t* non_mpm, const ChannelType &channelType /*= CHANNEL_TYPE_LUMA*/ )
#else
int PU::getIntraMPMs(const PredictionUnit &pu, unsigned* mpm, const ChannelType &channelType /*= CHANNEL_TYPE_LUMA*/)
#endif

Karsten Suehring
committed
{
#if SECONDARY_MPM
bool includedMode[NUM_INTRA_MODE];
memset(includedMode, false, sizeof(includedMode));
int numValidMPM = 0;
mpm[numValidMPM++] = PLANAR_IDX;
includedMode[PLANAR_IDX] = true;
#endif
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
#if SECONDARY_MPM
const PredictionUnit *puLeft = (pu.lheight() >= pu.lwidth())
? pu.cs->getPURestricted(posRT.offset(0, -1), pu, channelType)
: pu.cs->getPURestricted(posLB.offset(-1, 0), pu, channelType);
#else
const PredictionUnit *puLeft = pu.cs->getPURestricted(posLB.offset(-1, 0), pu, channelType);
#if SECONDARY_MPM
mpm[numValidMPM] = PU::getIntraDirLuma(*puLeft);
if( !includedMode[mpm[numValidMPM]] )
{
includedMode[mpm[numValidMPM++]] = true;
}
#else
leftIntraDir = PU::getIntraDirLuma( *puLeft );
#if SECONDARY_MPM
const PredictionUnit *puAbove = (pu.lheight() >= pu.lwidth())
? pu.cs->getPURestricted(posLB.offset(-1, 0), pu, channelType)
: pu.cs->getPURestricted(posRT.offset(0, -1), pu, channelType);
#else
const PredictionUnit *puAbove = pu.cs->getPURestricted(posRT.offset(0, -1), pu, channelType);
if (puAbove && CU::isIntra(*puAbove->cu) && CU::isSameCtu(*pu.cu, *puAbove->cu))
{
#if SECONDARY_MPM
mpm[numValidMPM] = PU::getIntraDirLuma(*puAbove);
if( !includedMode[mpm[numValidMPM]] )
{
includedMode[mpm[numValidMPM++]] = true;
}
#else
aboveIntraDir = PU::getIntraDirLuma( *puAbove );
#if SECONDARY_MPM
// Get intra direction of below-left PU
const PredictionUnit *puBelowLeft = pu.cs->getPURestricted(posLB.offset(-1, 1), pu, channelType);
if (puBelowLeft && CU::isIntra(*puBelowLeft->cu))
{
mpm[numValidMPM] = PU::getIntraDirLuma(*puBelowLeft);
if( !includedMode[mpm[numValidMPM]] )
{
includedMode[mpm[numValidMPM++]] = true;
}
}
// Get intra direction of above-right PU
const PredictionUnit *puAboveRight = pu.cs->getPURestricted(posRT.offset(1, -1), pu, channelType);
if (puAboveRight && CU::isIntra(*puAboveRight->cu) && CU::isSameCtu(*pu.cu, *puAboveRight->cu))
{
mpm[numValidMPM] = PU::getIntraDirLuma(*puAboveRight);
if( !includedMode[mpm[numValidMPM]] )
{
includedMode[mpm[numValidMPM++]] = true;
}
}
// Get intra direction of above-left PU
const Position posTL = area.topLeft();
const PredictionUnit *puAboveLeft = pu.cs->getPURestricted(posTL.offset(-1, -1), pu, channelType);
if (puAboveLeft && CU::isIntra(*puAboveLeft->cu) && CU::isSameCtu(*pu.cu, *puAboveLeft->cu))
mpm[numValidMPM] = PU::getIntraDirLuma(*puAboveLeft);
if( !includedMode[mpm[numValidMPM]] )
#endif
CHECK(2 >= numMPMs, "Invalid number of most probable modes");
const int offset = ( int ) NUM_LUMA_MODE - 6;
const int mod = offset + 3;
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
#if SECONDARY_MPM
numCand = numValidMPM;
#else
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;
#endif
#if ENABLE_DIMD && SECONDARY_MPM
//adding dimd modes
if (pu.cu->slice->getSPS()->getUseDimd())
{
if (pu.cu->dimdMode != -1)
{
mpm[numValidMPM] = pu.cu->dimdMode;
if( !includedMode[mpm[numValidMPM]] )
{
includedMode[mpm[numValidMPM++]] = true;
}
}
if (pu.cu->dimdBlendMode[0] != -1)
{
mpm[numValidMPM] = pu.cu->dimdBlendMode[0];
if( !includedMode[mpm[numValidMPM]] )
{
includedMode[mpm[numValidMPM++]] = true;
}
}
}
#endif
#if SECONDARY_MPM
bool checkDCEnabled = false;
// Derived modes of mpm[1]
if (numCand >= 2)
{
if (mpm[1] > DC_IDX)
{
for (int i = 0; i < 4 && numValidMPM < numMPMs; i++)
{
mpm[numValidMPM] = ((mpm[1] + offset - i) % mod) + 2;
if( !includedMode[mpm[numValidMPM]] )
{
includedMode[mpm[numValidMPM++]] = true;
}
if( numValidMPM >= numMPMs )
{
break;
}
mpm[numValidMPM] = ((mpm[1] - 1 + i) % mod) + 2;
if( !includedMode[mpm[numValidMPM]] )
{
includedMode[mpm[numValidMPM++]] = true;
}
}
}
else if( mpm[1] == DC_IDX )
{
checkDCEnabled = true;
}
}
// Derived modes of mpm[2]
if (numCand >= 3)
{
if (mpm[2] > DC_IDX)
{
for (int i = 0; i < 4 && numValidMPM < numMPMs; i++)
{
mpm[numValidMPM] = ((mpm[2] + offset - i) % mod) + 2;
if( !includedMode[mpm[numValidMPM]] )
{
includedMode[mpm[numValidMPM++]] = true;
}
if (numValidMPM >= numMPMs)
break;
mpm[numValidMPM] = ((mpm[2] - 1 + i) % mod) + 2;
if( !includedMode[mpm[numValidMPM]] )
{
includedMode[mpm[numValidMPM++]] = true;
}
}
}
else if( mpm[2] == DC_IDX )
{
checkDCEnabled = true;
}
}
// Derived modes of mpm[3]
if (checkDCEnabled && numCand >= 4 && mpm[3] > DC_IDX)
{
for (int i = 0; i < 3 && numValidMPM < numMPMs; i++)
{
mpm[numValidMPM] = ((mpm[3] + offset - i) % mod) + 2;
if( !includedMode[mpm[numValidMPM]] )
{
includedMode[mpm[numValidMPM++]] = true;
}
if( numValidMPM >= numMPMs )
{
break;
}
mpm[numValidMPM] = ((mpm[3] - 1 + i) % mod) + 2;
if( !includedMode[mpm[numValidMPM]] )
{
includedMode[mpm[numValidMPM++]] = true;
}
}
}
#else
if (leftIntraDir == aboveIntraDir)
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;
}
else //L!=A
{
numCand = 2;
int maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;
if ((leftIntraDir > DC_IDX) && (aboveIntraDir > DC_IDX))
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
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;
}
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;
}
#endif
#if SECONDARY_MPM
unsigned mpm_default[numMPMs - 1] = { DC_IDX, VER_IDX, HOR_IDX, VER_IDX - 4, VER_IDX + 4, 14, 22, 42, 58, 10, 26,
38, 62, 6, 30, 34, 66, 2, 48, 52, 16 };
for (int idx = 0; (idx < numMPMs - 1) && numValidMPM < numMPMs; idx++)
{
mpm[numValidMPM] = mpm_default[idx];
if( !includedMode[mpm[numValidMPM]] )
int numNonMPM = 0;
for (int idx = 0; idx < NUM_LUMA_MODE; idx++)
if( !includedMode[idx] )
{
non_mpm[numNonMPM++] = idx;
}

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)
{
if (chType == CHANNEL_TYPE_LUMA)
{
// Default case if chType is omitted.
return pu.cu->mipFlag;
}
else
{
return isDMChromaMIP(pu) && (pu.intraDir[CHANNEL_TYPE_CHROMA] == DM_CHROMA_IDX);
}
bool PU::isDMChromaMIP(const PredictionUnit &pu)
{
return !pu.cu->isSepTree() && (pu.chromaFormat == CHROMA_444) && getCoLocatedLumaPU(pu).cu->mipFlag;
#else
return !(CS::isDualITree(*pu.cs)) && (pu.chromaFormat == CHROMA_444) && getCoLocatedLumaPU(pu).cu->mipFlag;
#endif
uint32_t PU::getIntraDirLuma( const PredictionUnit &pu )
{
if (isMIP(pu))
{
}
else
{
return pu.intraDir[CHANNEL_TYPE_LUMA];
}
}
void PU::getIntraChromaCandModes(const PredictionUnit &pu, unsigned modeList[NUM_CHROMA_MODE])

Karsten Suehring
committed
{
modeList[0] = PLANAR_IDX;
modeList[1] = VER_IDX;
modeList[2] = HOR_IDX;
modeList[3] = DC_IDX;
modeList[4] = LM_CHROMA_IDX;
#if MMLM
modeList[5] = MDLM_L_IDX;
modeList[6] = MDLM_T_IDX;
modeList[7] = MMLM_CHROMA_IDX;
modeList[8] = MMLM_L_IDX;
modeList[9] = MMLM_T_IDX;
modeList[10] = DM_CHROMA_IDX;
#else
modeList[5] = MDLM_L_IDX;
modeList[6] = MDLM_T_IDX;
modeList[7] = DM_CHROMA_IDX;

Karsten Suehring
committed
// If Direct Mode is MIP, mode cannot be already in the list.
if (isDMChromaMIP(pu))
{
return;
}
const uint32_t lumaMode = getCoLocatedIntraLumaMode(pu);
for (int i = 0; i < 4; i++)
{
if (lumaMode == modeList[i])

Karsten Suehring
committed
{
modeList[i] = VDIA_IDX;
break;