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-2025, 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
* 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 EncCu.cpp
\brief Coding Unit (CU) encoder class
*/
#include "EncCu.h"
#include "EncLib.h"
#include "Analyze.h"
#include "AQp.h"
#include "CommonLib/dtrace_codingstruct.h"
#include "CommonLib/Picture.h"
#include "CommonLib/UnitTools.h"

Karsten Suehring
committed
#include "CommonLib/dtrace_buffer.h"
#include <stdio.h>
#include <cmath>
#include <algorithm>
//! \ingroup EncoderLib
//! \{
// ====================================================================================================================
const MergeIdxPair EncCu::m_geoModeTest[GEO_MAX_NUM_CANDS] = {
MergeIdxPair{ 0, 1 }, MergeIdxPair{ 1, 0 }, MergeIdxPair{ 0, 2 }, MergeIdxPair{ 1, 2 }, MergeIdxPair{ 2, 0 },
MergeIdxPair{ 2, 1 }, MergeIdxPair{ 0, 3 }, MergeIdxPair{ 1, 3 }, MergeIdxPair{ 2, 3 }, MergeIdxPair{ 3, 0 },
MergeIdxPair{ 3, 1 }, MergeIdxPair{ 3, 2 }, MergeIdxPair{ 0, 4 }, MergeIdxPair{ 1, 4 }, MergeIdxPair{ 2, 4 },
MergeIdxPair{ 3, 4 }, MergeIdxPair{ 4, 0 }, MergeIdxPair{ 4, 1 }, MergeIdxPair{ 4, 2 }, MergeIdxPair{ 4, 3 },
MergeIdxPair{ 0, 5 }, MergeIdxPair{ 1, 5 }, MergeIdxPair{ 2, 5 }, MergeIdxPair{ 3, 5 }, MergeIdxPair{ 4, 5 },
MergeIdxPair{ 5, 0 }, MergeIdxPair{ 5, 1 }, MergeIdxPair{ 5, 2 }, MergeIdxPair{ 5, 3 }, MergeIdxPair{ 5, 4 }

Karsten Suehring
committed
void EncCu::create( EncCfg* encCfg )
{
unsigned uiMaxWidth = encCfg->getMaxCUWidth();
unsigned uiMaxHeight = encCfg->getMaxCUHeight();
ChromaFormat chromaFormat = encCfg->getChromaFormatIdc();
unsigned numWidths = gp_sizeIdxInfo->numWidths();
unsigned numHeights = gp_sizeIdxInfo->numHeights();
m_pTempCS = new CodingStructure** [numWidths];
m_pBestCS = new CodingStructure** [numWidths];
m_pTempCS2 = new CodingStructure** [numWidths];
m_pBestCS2 = new CodingStructure** [numWidths];

Karsten Suehring
committed
m_pelUnitBufPool.initPelUnitBufPool(chromaFormat, uiMaxWidth, uiMaxHeight);
m_mergeItemList.init(encCfg->getMaxMergeRdCandNumTotal(), chromaFormat, uiMaxWidth, uiMaxHeight);

Karsten Suehring
committed
for( unsigned w = 0; w < numWidths; w++ )
{
m_pTempCS[w] = new CodingStructure* [numHeights];
m_pBestCS[w] = new CodingStructure* [numHeights];
m_pTempCS2[w] = new CodingStructure* [numHeights];
m_pBestCS2[w] = new CodingStructure* [numHeights];

Karsten Suehring
committed
for( unsigned h = 0; h < numHeights; h++ )
{
unsigned width = gp_sizeIdxInfo->sizeFrom( w );
unsigned height = gp_sizeIdxInfo->sizeFrom( h );
if( gp_sizeIdxInfo->isCuSize( width ) && gp_sizeIdxInfo->isCuSize( height )
&& width <= uiMaxWidth && height <= uiMaxHeight)

Karsten Suehring
committed
{
m_pTempCS[w][h] = new CodingStructure(m_unitPool);
m_pBestCS[w][h] = new CodingStructure(m_unitPool);

Karsten Suehring
committed
m_pTempCS[w][h]->create(chromaFormat, Area(0, 0, width, height), false, (bool)encCfg->getPLTMode());
m_pBestCS[w][h]->create(chromaFormat, Area(0, 0, width, height), false, (bool)encCfg->getPLTMode());
m_pTempCS2[w][h] = new CodingStructure(m_unitPool);
m_pBestCS2[w][h] = new CodingStructure(m_unitPool);
m_pTempCS2[w][h]->create(chromaFormat, Area(0, 0, width, height), false, (bool)encCfg->getPLTMode());
m_pBestCS2[w][h]->create(chromaFormat, Area(0, 0, width, height), false, (bool)encCfg->getPLTMode());

Karsten Suehring
committed
}
else
{
m_pTempCS[w][h] = nullptr;
m_pBestCS[w][h] = nullptr;
m_pTempCS2[w][h] = nullptr;
m_pBestCS2[w][h] = nullptr;

Karsten Suehring
committed
}
}
}
m_cuChromaQpOffsetIdxPlus1 = 0;
unsigned maxDepth = numWidths + numHeights;

Karsten Suehring
committed
m_modeCtrl->create( *encCfg );

Karsten Suehring
committed
m_CurrCtx = 0;
}
void EncCu::destroy()
{
unsigned numWidths = gp_sizeIdxInfo->numWidths();
unsigned numHeights = gp_sizeIdxInfo->numHeights();
for( unsigned w = 0; w < numWidths; w++ )
{
for( unsigned h = 0; h < numHeights; h++ )
{
if (m_pBestCS[w][h])
{
m_pBestCS[w][h]->destroy();
}
if (m_pTempCS[w][h])
{
m_pTempCS[w][h]->destroy();
}

Karsten Suehring
committed
delete m_pBestCS[w][h];
delete m_pTempCS[w][h];
if (m_pBestCS2[w][h])
{
m_pBestCS2[w][h]->destroy();
}
if (m_pTempCS2[w][h])
{
m_pTempCS2[w][h]->destroy();
}
delete m_pBestCS2[w][h];
delete m_pTempCS2[w][h];

Karsten Suehring
committed
}
delete[] m_pTempCS[w];
delete[] m_pBestCS[w];
delete[] m_pTempCS2[w];
delete[] m_pBestCS2[w];

Karsten Suehring
committed
}
delete[] m_pBestCS; m_pBestCS = nullptr;
delete[] m_pTempCS; m_pTempCS = nullptr;
delete[] m_pBestCS2; m_pBestCS2 = nullptr;
delete[] m_pTempCS2; m_pTempCS2 = nullptr;

Karsten Suehring
committed
m_tmpStorageCtu->destroy();
delete m_tmpStorageCtu;
m_tmpStorageCtu = nullptr;

Karsten Suehring
committed
#if REUSE_CU_RESULTS
m_modeCtrl->destroy();
#endif
delete m_modeCtrl;
m_modeCtrl = nullptr;
}
EncCu::~EncCu()
{
}
/** \param pcEncLib pointer of encoder class
*/
void EncCu::init( EncLib* pcEncLib, const SPS& sps )

Karsten Suehring
committed
{
m_pcEncCfg = pcEncLib;
m_pcIntraSearch = pcEncLib->getIntraSearch();
m_pcInterSearch = pcEncLib->getInterSearch();
m_pcTrQuant = pcEncLib->getTrQuant();
m_pcRdCost = pcEncLib->getRdCost ();
m_CABACEstimator = pcEncLib->getCABACEncoder()->getCABACEstimator( &sps );

Karsten Suehring
committed
m_CABACEstimator->setEncCu(this);

Karsten Suehring
committed
m_pcRateCtrl = pcEncLib->getRateCtrl();
m_pcSliceEncoder = pcEncLib->getSliceEncoder();
m_deblockingFilter = pcEncLib->getDeblockingFilter();
m_geoCostList.init(m_pcEncCfg->getMaxNumGeoCand());
m_AFFBestSATDCost = MAX_DOUBLE;

Karsten Suehring
committed
DecCu::init( m_pcTrQuant, m_pcIntraSearch, m_pcInterSearch );
m_modeCtrl->init( m_pcEncCfg, m_pcRateCtrl, m_pcRdCost );
m_modeCtrl->setBIMQPMap( m_pcEncCfg->getAdaptQPmap() );

Karsten Suehring
committed
m_pcInterSearch->setModeCtrl( m_modeCtrl );
m_modeCtrl->setInterSearch(m_pcInterSearch);
m_pcIntraSearch->setModeCtrl( m_modeCtrl );
m_pcGOPEncoder = pcEncLib->getGOPEncoder();
m_pcGOPEncoder->setModeCtrl( m_modeCtrl );

Karsten Suehring
committed
}
// ====================================================================================================================
// Public member functions
// ====================================================================================================================
void EncCu::compressCtu(CodingStructure &cs, const UnitArea &area, const unsigned ctuRsAddr,
const EnumArray<int, ChannelType> &prevQP, const EnumArray<int, ChannelType> &currQP)

Karsten Suehring
committed
{
m_modeCtrl->initCTUEncoding( *cs.slice );

Karsten Suehring
committed
cs.slice->m_mapPltCost[0].clear();
cs.slice->m_mapPltCost[1].clear();

Karsten Suehring
committed
// init the partitioning manager
partitioner.initCtu(area, ChannelType::LUMA, *cs.slice);
if (area.lx() == 0 && area.ly() == 0)
{
m_pcInterSearch->resetIbcSearch();
}
m_ctuIbcSearchRangeX = m_pcEncCfg->getIBCLocalSearchRangeX();
m_ctuIbcSearchRangeY = m_pcEncCfg->getIBCLocalSearchRangeY();
if (m_pcEncCfg->getIBCMode() && m_pcEncCfg->getIBCHashSearch() && (m_pcEncCfg->getIBCFastMethod() & IBC_FAST_METHOD_ADAPTIVE_SEARCHRANGE))
const int hashHitRatio = m_ibcHashMap.getHashHitRatio(area.Y()); // in percent
m_ctuIbcSearchRangeX >>= 1;
m_ctuIbcSearchRangeY >>= 1;
m_ctuIbcSearchRangeX >>= 1;
m_ctuIbcSearchRangeY >>= 1;

Karsten Suehring
committed
// init current context pointer

Karsten Suehring
committed
CodingStructure *tempCS = m_pTempCS[gp_sizeIdxInfo->idxFrom( area.lumaSize().width )][gp_sizeIdxInfo->idxFrom( area.lumaSize().height )];
CodingStructure *bestCS = m_pBestCS[gp_sizeIdxInfo->idxFrom( area.lumaSize().width )][gp_sizeIdxInfo->idxFrom( area.lumaSize().height )];
cs.initSubStructure(*tempCS, partitioner.chType, partitioner.currArea(), false);
cs.initSubStructure(*bestCS, partitioner.chType, partitioner.currArea(), false);
tempCS->currQP[ChannelType::LUMA] = bestCS->currQP[ChannelType::LUMA] = tempCS->baseQP = bestCS->baseQP =
currQP[ChannelType::LUMA];
tempCS->prevQP[ChannelType::LUMA] = bestCS->prevQP[ChannelType::LUMA] = prevQP[ChannelType::LUMA];

Karsten Suehring
committed
xCompressCU(tempCS, bestCS, partitioner);
cs.slice->m_mapPltCost[0].clear();
cs.slice->m_mapPltCost[1].clear();

Karsten Suehring
committed
// all signals were already copied during compression if the CTU was split - at this point only the structures are copied to the top level CS
const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1;
cs.useSubStructure(*bestCS, partitioner.chType, CS::getArea(*bestCS, area, partitioner.chType), copyUnsplitCTUSignals,
false, false, copyUnsplitCTUSignals, true);

Karsten Suehring
committed

Christian Helmrich
committed
if (CS::isDualITree (cs) && isChromaEnabled (cs.pcv->chrFormat))

Karsten Suehring
committed
{
m_CABACEstimator->getCtx() = m_CurrCtx->start;
partitioner.initCtu(area, ChannelType::CHROMA, *cs.slice);

Karsten Suehring
committed
cs.initSubStructure(*tempCS, partitioner.chType, partitioner.currArea(), false);
cs.initSubStructure(*bestCS, partitioner.chType, partitioner.currArea(), false);
tempCS->currQP[ChannelType::CHROMA] = bestCS->currQP[ChannelType::CHROMA] = tempCS->baseQP = bestCS->baseQP =
currQP[ChannelType::CHROMA];
tempCS->prevQP[ChannelType::CHROMA] = bestCS->prevQP[ChannelType::CHROMA] = prevQP[ChannelType::CHROMA];

Karsten Suehring
committed
xCompressCU(tempCS, bestCS, partitioner);

Karsten Suehring
committed
const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1;
cs.useSubStructure(*bestCS, partitioner.chType, CS::getArea(*bestCS, area, partitioner.chType),
copyUnsplitCTUSignals, false, false, copyUnsplitCTUSignals, true);

Karsten Suehring
committed
}
if (m_pcEncCfg->getUseRateCtrl())
{
(m_pcRateCtrl->getRCPic()->getLCU(ctuRsAddr)).m_actualMSE = (double)bestCS->dist / (double)m_pcRateCtrl->getRCPic()->getLCU(ctuRsAddr).m_numberOfPixel;
}

Karsten Suehring
committed
// reset context states and uninit context pointer
m_CABACEstimator->getCtx() = m_CurrCtx->start;
m_CurrCtx = 0;
// Ensure that a coding was found
// Selected mode's RD-cost must be not MAX_DOUBLE.
CHECK( bestCS->cus.empty() , "No possible encoding found" );
CHECK( bestCS->cus[0]->predMode == NUMBER_OF_PREDICTION_MODES, "No possible encoding found" );
CHECK( bestCS->cost == MAX_DOUBLE , "No possible encoding found" );
}
// ====================================================================================================================
// Protected member functions
// ====================================================================================================================
static int xCalcHADs8x8_ISlice(const Pel *piOrg, const ptrdiff_t strideOrg)

Karsten Suehring
committed
{
int k, i, j, jj;
int diff[64], m1[8][8], m2[8][8], m3[8][8], iSumHad = 0;
for (k = 0; k < 64; k += 8)
{
diff[k + 0] = piOrg[0];
diff[k + 1] = piOrg[1];
diff[k + 2] = piOrg[2];
diff[k + 3] = piOrg[3];
diff[k + 4] = piOrg[4];
diff[k + 5] = piOrg[5];
diff[k + 6] = piOrg[6];
diff[k + 7] = piOrg[7];

Karsten Suehring
committed
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
}
//horizontal
for (j = 0; j < 8; j++)
{
jj = j << 3;
m2[j][0] = diff[jj ] + diff[jj + 4];
m2[j][1] = diff[jj + 1] + diff[jj + 5];
m2[j][2] = diff[jj + 2] + diff[jj + 6];
m2[j][3] = diff[jj + 3] + diff[jj + 7];
m2[j][4] = diff[jj ] - diff[jj + 4];
m2[j][5] = diff[jj + 1] - diff[jj + 5];
m2[j][6] = diff[jj + 2] - diff[jj + 6];
m2[j][7] = diff[jj + 3] - diff[jj + 7];
m1[j][0] = m2[j][0] + m2[j][2];
m1[j][1] = m2[j][1] + m2[j][3];
m1[j][2] = m2[j][0] - m2[j][2];
m1[j][3] = m2[j][1] - m2[j][3];
m1[j][4] = m2[j][4] + m2[j][6];
m1[j][5] = m2[j][5] + m2[j][7];
m1[j][6] = m2[j][4] - m2[j][6];
m1[j][7] = m2[j][5] - m2[j][7];
m2[j][0] = m1[j][0] + m1[j][1];
m2[j][1] = m1[j][0] - m1[j][1];
m2[j][2] = m1[j][2] + m1[j][3];
m2[j][3] = m1[j][2] - m1[j][3];
m2[j][4] = m1[j][4] + m1[j][5];
m2[j][5] = m1[j][4] - m1[j][5];
m2[j][6] = m1[j][6] + m1[j][7];
m2[j][7] = m1[j][6] - m1[j][7];
}
//vertical
for (i = 0; i < 8; i++)
{
m3[0][i] = m2[0][i] + m2[4][i];
m3[1][i] = m2[1][i] + m2[5][i];
m3[2][i] = m2[2][i] + m2[6][i];
m3[3][i] = m2[3][i] + m2[7][i];
m3[4][i] = m2[0][i] - m2[4][i];
m3[5][i] = m2[1][i] - m2[5][i];
m3[6][i] = m2[2][i] - m2[6][i];
m3[7][i] = m2[3][i] - m2[7][i];
m1[0][i] = m3[0][i] + m3[2][i];
m1[1][i] = m3[1][i] + m3[3][i];
m1[2][i] = m3[0][i] - m3[2][i];
m1[3][i] = m3[1][i] - m3[3][i];
m1[4][i] = m3[4][i] + m3[6][i];
m1[5][i] = m3[5][i] + m3[7][i];
m1[6][i] = m3[4][i] - m3[6][i];
m1[7][i] = m3[5][i] - m3[7][i];
m2[0][i] = m1[0][i] + m1[1][i];
m2[1][i] = m1[0][i] - m1[1][i];
m2[2][i] = m1[2][i] + m1[3][i];
m2[3][i] = m1[2][i] - m1[3][i];
m2[4][i] = m1[4][i] + m1[5][i];
m2[5][i] = m1[4][i] - m1[5][i];
m2[6][i] = m1[6][i] + m1[7][i];
m2[7][i] = m1[6][i] - m1[7][i];
}
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
iSumHad += abs(m2[i][j]);
}
}
iSumHad -= abs(m2[0][0]);
iSumHad = (iSumHad + 2) >> 2;
return(iSumHad);
}
int EncCu::updateCtuDataISlice(const CPelBuf buf)
{
int xBl, yBl;
const int iBlkSize = 8;
const Pel* pOrgInit = buf.buf;

Karsten Suehring
committed
int iSumHad = 0;
for( yBl = 0; ( yBl + iBlkSize ) <= buf.height; yBl += iBlkSize )
{
for( xBl = 0; ( xBl + iBlkSize ) <= buf.width; xBl += iBlkSize )
{
const Pel* pOrg = pOrgInit + iStrideOrig*yBl + xBl;
iSumHad += xCalcHADs8x8_ISlice( pOrg, iStrideOrig );
}
}
return( iSumHad );
}
bool EncCu::xCheckBestMode( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )

Karsten Suehring
committed
{

Karsten Suehring
committed
if( !tempCS->cus.empty() )
{
if( tempCS->cus.size() == 1 )
{
const CodingUnit& cu = *tempCS->cus.front();
CHECK( cu.skip && !cu.firstPU->mergeFlag, "Skip flag without a merge flag is not allowed!" );
}
#if WCG_EXT
DTRACE_BEST_MODE( tempCS, bestCS, m_pcRdCost->getLambda( true ) );
#else
DTRACE_BEST_MODE( tempCS, bestCS, m_pcRdCost->getLambda() );
#endif
if( m_modeCtrl->useModeResult( encTestMode, tempCS, partitioner ) )
{
std::swap( tempCS, bestCS );
// store temp best CI for next CU coding
m_CurrCtx->best = m_CABACEstimator->getCtx();

Karsten Suehring
committed
}
}
// reset context states
m_CABACEstimator->getCtx() = m_CurrCtx->start;

Karsten Suehring
committed
}
void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& partitioner, double maxCostAllowed )

Karsten Suehring
committed
{
CHECK(maxCostAllowed < 0, "Wrong value of maxCostAllowed!");

Karsten Suehring
committed
Yung-Hsuan Chao (Jessie)
committed
uint32_t compBegin;
uint32_t numComp;
Yung-Hsuan Chao (Jessie)
committed
bool jointPLT = false;
if (partitioner.isSepTree( *tempCS ))
Yung-Hsuan Chao (Jessie)
committed
{
if( !CS::isDualITree(*tempCS) && partitioner.treeType != TREE_D )
{
compBegin = COMPONENT_Y;
numComp = getNumberValidComponents(tempCS->area.chromaFormat);
jointPLT = true;
}
else
{
if (isLuma(partitioner.chType))
{
compBegin = COMPONENT_Y;
numComp = 1;
}
else
{
compBegin = COMPONENT_Cb;
numComp = 2;
}
Yung-Hsuan Chao (Jessie)
committed
}
else
{
compBegin = COMPONENT_Y;
numComp = getNumberValidComponents(tempCS->area.chromaFormat);
jointPLT = true;
Yung-Hsuan Chao (Jessie)
committed
}
SplitSeries splitmode = -1;
uint8_t bestLastPLTSize[MAX_NUM_CHANNEL_TYPE];
Pel bestLastPLT[MAX_NUM_COMPONENT][MAXPLTPREDSIZE]; // store LastPLT for
uint8_t curLastPLTSize[MAX_NUM_CHANNEL_TYPE];
Pel curLastPLT[MAX_NUM_COMPONENT][MAXPLTPREDSIZE]; // store LastPLT if no partition
for (int i = compBegin; i < (compBegin + numComp); i++)
Yung-Hsuan Chao (Jessie)
committed
{
ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);
bestLastPLTSize[comID] = 0;
curLastPLTSize[comID] = tempCS->prevPLT.curPLTSize[comID];
memcpy(curLastPLT[i], tempCS->prevPLT.curPLT[i], tempCS->prevPLT.curPLTSize[comID] * sizeof(Pel));
Yung-Hsuan Chao (Jessie)
committed
}

Karsten Suehring
committed
Slice& slice = *tempCS->slice;
const PPS &pps = *tempCS->pps;
const SPS &sps = *tempCS->sps;
const uint32_t uiLPelX = tempCS->area.Y().lumaPos().x;
const uint32_t uiTPelY = tempCS->area.Y().lumaPos().y;
const ModeType modeTypeParent = partitioner.modeType;
const TreeType treeTypeParent = partitioner.treeType;
const ChannelType chTypeParent = partitioner.chType;

Karsten Suehring
committed
const UnitArea currCsArea = clipArea( CS::getArea( *bestCS, bestCS->area, partitioner.chType ), *tempCS->picture );
if (m_pcEncCfg->getDPF())
{
m_modeCtrl->setCurrCsArea(currCsArea);
m_modeCtrl->setQpCtu(m_pcSliceEncoder->getQpCtu());
}

Karsten Suehring
committed
m_modeCtrl->initCULevel( partitioner, *tempCS );
Seungwook Hong
committed
if (m_pcEncCfg->getGdrEnabled())
bool isInGdrInterval = slice.getPic()->gdrParam.inGdrInterval;
Seungwook Hong
committed
if (isInGdrInterval)
Seungwook Hong
committed
{
int gdrPocStart = m_pcEncCfg->getGdrPocStart();
int gdrInterval = m_pcEncCfg->getGdrInterval();
int gdrPeriod = m_pcEncCfg->getGdrPeriod();
Seungwook Hong
committed
int picWidth = slice.getPPS()->getPicWidthInLumaSamples();
int m1, m2, n1;
Seungwook Hong
committed
int curPoc = slice.getPOC();
int gdrPoc = (curPoc - gdrPocStart) % gdrPeriod;
Seungwook Hong
committed
int begGdrX = 0;
int endGdrX = 0;
Seungwook Hong
committed
double dd = (picWidth / (double)gdrInterval);
int mm = (int)((picWidth / (double)gdrInterval) + 0.49999);
m1 = ((mm + 7) >> 3) << 3;
m2 = ((mm + 0) >> 3) << 3;
Seungwook Hong
committed
if (dd > mm && m1 == m2)
Seungwook Hong
committed
m1 = m1 + 8;
Seungwook Hong
committed
n1 = (picWidth - m2 * gdrInterval) / 8;
Seungwook Hong
committed
if (gdrPoc < n1)
{
begGdrX = m1 * gdrPoc;
endGdrX = begGdrX + m1;
}
else
{
begGdrX = m1 * n1 + m2 * (gdrPoc - n1);
endGdrX = begGdrX + m2;
if (picWidth <= endGdrX)
Seungwook Hong
committed
begGdrX = picWidth;
Seungwook Hong
committed
endGdrX = picWidth;
}
}
Seungwook Hong
committed
bool isInRefreshArea = tempCS->withinRefresh(begGdrX, endGdrX);
if (isInRefreshArea)
Seungwook Hong
committed
m_modeCtrl->forceIntraMode();
Seungwook Hong
committed
else if (tempCS->containRefresh(begGdrX, endGdrX) || tempCS->overlapRefresh(begGdrX, endGdrX))
{
// 1.3.1 enable only vertical splits (QT, BT_V, TT_V)
Seungwook Hong
committed
m_modeCtrl->forceVerSplitOnly();
Seungwook Hong
committed
// 1.3.2 remove TT_V if it does not satisfy the condition
if (tempCS->refreshCrossTTV(begGdrX, endGdrX))
{
m_modeCtrl->forceRemoveTTV();
}
}
Seungwook Hong
committed
if (tempCS->area.lwidth() != tempCS->area.lheight())
{
m_modeCtrl->forceRemoveQT();
}
Seungwook Hong
committed
if (!m_modeCtrl->anyPredModeLeft())
{
m_modeCtrl->forceRemoveDontSplit();
}
if (isInRefreshArea && !m_modeCtrl->anyIntraIBCMode() && (tempCS->area.lwidth() == 4 || tempCS->area.lheight() == 4))
{
m_modeCtrl->finishCULevel(partitioner);
return;
}
if (partitioner.currQtDepth == 0 && partitioner.currMtDepth == 0 && !tempCS->slice->isIntra()
&& (sps.getUseSBT() || sps.getExplicitMtsInterEnabled()))
{
auto slsSbt = dynamic_cast<SaveLoadEncInfoSbt*>( m_modeCtrl );
Mohammed Golam Sarwer
committed
int maxSLSize = sps.getUseSBT() ? tempCS->slice->getSPS()->getMaxTbSize() : MTS_INTER_MAX_CU_SIZE;
slsSbt->resetSaveloadSbt( maxSLSize );
}
m_sbtCostSave[0] = m_sbtCostSave[1] = MAX_DOUBLE;

Karsten Suehring
committed
m_CurrCtx->start = m_CABACEstimator->getCtx();
if( slice.getUseChromaQpAdj() )
{
// TODO M0133 : double check encoder decisions with respect to chroma QG detection and actual encode
int lgMinCuSize = sps.getLog2MinCodingBlockSize() +
Philippe de Lagrange
committed
std::max<int>(0, floorLog2(sps.getCTUSize()) - sps.getLog2MinCodingBlockSize() - int((slice.getCuChromaQpOffsetSubdiv()+1) / 2));
if( partitioner.currQgChromaEnable() )
{
m_cuChromaQpOffsetIdxPlus1 = ( ( uiLPelX >> lgMinCuSize ) + ( uiTPelY >> lgMinCuSize ) ) % ( pps.getChromaQpOffsetListLen() + 1 );
}

Karsten Suehring
committed
}
Philippe de Lagrange
committed
else
{
m_cuChromaQpOffsetIdxPlus1 = 0;
}

Karsten Suehring
committed
if( !m_modeCtrl->anyMode() )
{
m_modeCtrl->finishCULevel( partitioner );
return;
}
DTRACE_UPDATE( g_trace_ctx, std::make_pair( "cux", uiLPelX ) );
DTRACE_UPDATE( g_trace_ctx, std::make_pair( "cuy", uiTPelY ) );
DTRACE_UPDATE( g_trace_ctx, std::make_pair( "cuw", tempCS->area.lwidth() ) );
DTRACE_UPDATE( g_trace_ctx, std::make_pair( "cuh", tempCS->area.lheight() ) );
DTRACE( g_trace_ctx, D_COMMON, "@(%4d,%4d) [%2dx%2d]\n", tempCS->area.lx(), tempCS->area.ly(), tempCS->area.lwidth(), tempCS->area.lheight() );
m_pcInterSearch->resetSavedAffineMotion();
if (tempCS->slice->getSPS()->getUseColorTrans())
{
tempCS->tmpColorSpaceCost = MAX_DOUBLE;
bestCS->tmpColorSpaceCost = MAX_DOUBLE;
tempCS->firstColorSpaceSelected = true;
bestCS->firstColorSpaceSelected = true;
}
if (tempCS->slice->getSPS()->getUseColorTrans() && !CS::isDualITree(*tempCS))
{
tempCS->firstColorSpaceTestOnly = false;
bestCS->firstColorSpaceTestOnly = false;
tempCS->tmpColorSpaceIntraCost[0] = MAX_DOUBLE;
tempCS->tmpColorSpaceIntraCost[1] = MAX_DOUBLE;
bestCS->tmpColorSpaceIntraCost[0] = MAX_DOUBLE;
bestCS->tmpColorSpaceIntraCost[1] = MAX_DOUBLE;
if (tempCS->bestParent && tempCS->bestParent->firstColorSpaceTestOnly)
{
tempCS->firstColorSpaceTestOnly = bestCS->firstColorSpaceTestOnly = true;
}
}
Lien-Fei Chen
committed
double splitRdCostBest[NUM_PART_SPLIT];
std::fill(std::begin(splitRdCostBest), std::end(splitRdCostBest), MAX_DOUBLE);
if (tempCS->slice->getCheckLDC())
{
m_bestBcwCost.fill(std::numeric_limits<double>::max());
m_bestBcwIdx.fill(BCW_NUM);

Karsten Suehring
committed
do
{
for (int i = compBegin; i < (compBegin + numComp); i++)
{
ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);
tempCS->prevPLT.curPLTSize[comID] = curLastPLTSize[comID];
memcpy(tempCS->prevPLT.curPLT[i], curLastPLT[i], curLastPLTSize[comID] * sizeof(Pel));
}
EncTestMode currTestMode = m_modeCtrl->currTestMode();
currTestMode.maxCostAllowed = maxCostAllowed;
if (pps.getUseDQP() && partitioner.isSepTree(*tempCS) && isChroma( partitioner.chType ))
{
const Position chromaCentral(tempCS->area.Cb().chromaPos().offset(tempCS->area.Cb().chromaSize().width >> 1, tempCS->area.Cb().chromaSize().height >> 1));
const Position lumaRefPos(chromaCentral.x << getComponentScaleX(COMPONENT_Cb, tempCS->area.chromaFormat), chromaCentral.y << getComponentScaleY(COMPONENT_Cb, tempCS->area.chromaFormat));
const CodingStructure* baseCS = bestCS->picture->cs;
const CodingUnit *colLumaCu = baseCS->getCU(lumaRefPos, ChannelType::LUMA);
Santiago de Luxán Hernández
committed
if (colLumaCu)
{
currTestMode.qp = colLumaCu->qp;
}
}

Karsten Suehring
committed

Christian Helmrich
committed
#if SHARP_LUMA_DELTA_QP || ENABLE_QPA_SUB_CTU
if (partitioner.currQgEnable() && (

Karsten Suehring
committed
#if SHARP_LUMA_DELTA_QP

Christian Helmrich
committed
(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled()) ||
#endif
(m_pcEncCfg->getSmoothQPReductionEnable()) ||

Christian Helmrich
committed
#if ENABLE_QPA_SUB_CTU
(m_pcEncCfg->getUsePerceptQPA() && !m_pcEncCfg->getUseRateCtrl() && pps.getUseDQP())
#else
false
#endif
))

Karsten Suehring
committed
{
if (currTestMode.qp >= 0)
{
updateLambda (&slice, currTestMode.qp,
#if WCG_EXT && ER_CHROMA_QP_WCG_PPS
m_pcEncCfg->getWCGChromaQPControl().isEnabled(),
#endif
CS::isDualITree (*tempCS) || (partitioner.currDepth == 0));

Karsten Suehring
committed
}
}
#endif
if( currTestMode.type == ETM_INTER_ME )
{
if( ( currTestMode.opts & ETO_IMV ) != 0 )
{
const bool skipAltHpelIF = (currTestMode.getAmvrSearchMode() == EncTestMode::AmvrSearchMode::HALF_PEL)
&& (bestIntPelCost > 1.25 * bestCS->cost);
xCheckRDCostInterAmvr(tempCS, bestCS, partitioner, currTestMode, bestIntPelCost);
Lien-Fei Chen
committed
splitRdCostBest[CTU_LEVEL] = bestCS->cost;
tempCS->splitRdCostBest = splitRdCostBest;

Karsten Suehring
committed
}
else
{
tempCS->bestCS = bestCS;

Karsten Suehring
committed
xCheckRDCostInter( tempCS, bestCS, partitioner, currTestMode );
tempCS->bestCS = nullptr;
Lien-Fei Chen
committed
splitRdCostBest[CTU_LEVEL] = bestCS->cost;
tempCS->splitRdCostBest = splitRdCostBest;

Karsten Suehring
committed
}
}
else if (currTestMode.type == ETM_HASH_INTER)
{
xCheckRDCostHashInter( tempCS, bestCS, partitioner, currTestMode );
Lien-Fei Chen
committed
splitRdCostBest[CTU_LEVEL] = bestCS->cost;
tempCS->splitRdCostBest = splitRdCostBest;

Karsten Suehring
committed
#if REUSE_CU_RESULTS
else if( currTestMode.type == ETM_RECO_CACHED )
{
xReuseCachedResult( tempCS, bestCS, partitioner );
Lien-Fei Chen
committed
splitRdCostBest[CTU_LEVEL] = bestCS->cost;
tempCS->splitRdCostBest = splitRdCostBest;

Karsten Suehring
committed
}
#endif
else if( currTestMode.type == ETM_MERGE_SKIP )
{
xCheckRDCostUnifiedMerge(tempCS, bestCS, partitioner, currTestMode);
CodingUnit* cu = bestCS->getCU(partitioner.chType);
{
cu->mmvdSkip = cu->skip == false ? false : cu->mmvdSkip;
}
Lien-Fei Chen
committed
splitRdCostBest[CTU_LEVEL] = bestCS->cost;
tempCS->splitRdCostBest = splitRdCostBest;

Karsten Suehring
committed
}
else if( currTestMode.type == ETM_INTRA )
{
if (slice.getSPS()->getUseColorTrans() && !CS::isDualITree(*tempCS))
{
bool skipSecColorSpace = false;
skipSecColorSpace = xCheckRDCostIntra(tempCS, bestCS, partitioner, currTestMode, (m_pcEncCfg->getRGBFormatFlag() ? true : false));
if ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && slice.isLossless()) && !m_pcEncCfg->getRGBFormatFlag())
{
skipSecColorSpace = true;
}
if (!skipSecColorSpace && !tempCS->firstColorSpaceTestOnly)
{
xCheckRDCostIntra(tempCS, bestCS, partitioner, currTestMode, (m_pcEncCfg->getRGBFormatFlag() ? false : true));
}
if (!tempCS->firstColorSpaceTestOnly)
{
if (tempCS->tmpColorSpaceIntraCost[0] != MAX_DOUBLE && tempCS->tmpColorSpaceIntraCost[1] != MAX_DOUBLE)
{
double skipCostRatio = m_pcEncCfg->getRGBFormatFlag() ? 1.1 : 1.0;
if (tempCS->tmpColorSpaceIntraCost[1] > (skipCostRatio*tempCS->tmpColorSpaceIntraCost[0]))
{
tempCS->firstColorSpaceTestOnly = bestCS->firstColorSpaceTestOnly = true;
}
}
}
else
{
CHECK(tempCS->tmpColorSpaceIntraCost[1] != MAX_DOUBLE, "the RD test of the second color space should be skipped");
}
}
else
{
xCheckRDCostIntra(tempCS, bestCS, partitioner, currTestMode, false);
}
if (partitioner.currQtDepth == 1 && partitioner.currBtDepth == 0 && partitioner.currArea().lwidth() == 64
&& partitioner.currArea().lheight() == 64)
{
Waqas Ahmad
committed
if ((partitioner.chType == ChannelType::LUMA)
&& ((partitioner.currArea().Y().x + 63 < bestCS->picture->lwidth())
&& (partitioner.currArea().Y().y + 63 < bestCS->picture->lheight())))
{
m_modeCtrl->setNoSplitIntraCost(bestCS->cost);
}
}
Lien-Fei Chen
committed
splitRdCostBest[CTU_LEVEL] = bestCS->cost;
tempCS->splitRdCostBest = splitRdCostBest;

Karsten Suehring
committed
}
else if (currTestMode.type == ETM_PALETTE)
{
xCheckPLT( tempCS, bestCS, partitioner, currTestMode );
Lien-Fei Chen
committed
splitRdCostBest[CTU_LEVEL] = bestCS->cost;
tempCS->splitRdCostBest = splitRdCostBest;
xCheckRDCostIBCMode(tempCS, bestCS, partitioner, currTestMode);
Lien-Fei Chen
committed
splitRdCostBest[CTU_LEVEL] = bestCS->cost;
tempCS->splitRdCostBest = splitRdCostBest;
xCheckRDCostIBCModeMerge2Nx2N(tempCS, bestCS, partitioner, currTestMode);
Lien-Fei Chen
committed
splitRdCostBest[CTU_LEVEL] = bestCS->cost;
tempCS->splitRdCostBest = splitRdCostBest;

Karsten Suehring
committed
else if( isModeSplit( currTestMode ) )
{
if (bestCS->cus.size() != 0)
{
splitmode = bestCS->cus[0]->splitSeries;
}
assert( partitioner.modeType == tempCS->modeType );
int signalModeConsVal = tempCS->signalModeCons( getPartSplit( currTestMode ), partitioner, modeTypeParent );
int numRoundRdo = signalModeConsVal == LDT_MODE_TYPE_SIGNAL ? 2 : 1;
bool skipInterPass = false;
{
//change cons modes
if( signalModeConsVal == LDT_MODE_TYPE_SIGNAL )
CHECK( numRoundRdo != 2, "numRoundRdo shall be 2 - [LDT_MODE_TYPE_SIGNAL]" );
tempCS->modeType = partitioner.modeType = (i == 0) ? MODE_TYPE_INTER : MODE_TYPE_INTRA;
}
else if( signalModeConsVal == LDT_MODE_TYPE_INFER )
CHECK( numRoundRdo != 1, "numRoundRdo shall be 1 - [LDT_MODE_TYPE_INFER]" );
tempCS->modeType = partitioner.modeType = MODE_TYPE_INTRA;
}
else if( signalModeConsVal == LDT_MODE_TYPE_INHERIT )
CHECK( numRoundRdo != 1, "numRoundRdo shall be 1 - [LDT_MODE_TYPE_INHERIT]" );
tempCS->modeType = partitioner.modeType = modeTypeParent;
}

Karsten Suehring
committed
//for lite intra encoding fast algorithm, set the status to save inter coding info
if( modeTypeParent == MODE_TYPE_ALL && tempCS->modeType == MODE_TYPE_INTER )
{
m_pcIntraSearch->setSaveCuCostInSCIPU( true );
m_pcIntraSearch->setNumCuInSCIPU( 0 );
}
else if( modeTypeParent == MODE_TYPE_ALL && tempCS->modeType != MODE_TYPE_INTER )
{
m_pcIntraSearch->setSaveCuCostInSCIPU( false );
if( tempCS->modeType == MODE_TYPE_ALL )
{
m_pcIntraSearch->setNumCuInSCIPU( 0 );
}
}
Lien-Fei Chen
committed
xCheckModeSplit( tempCS, bestCS, partitioner, currTestMode, modeTypeParent, skipInterPass, splitRdCostBest );
tempCS->splitRdCostBest = splitRdCostBest;
//recover cons modes
tempCS->modeType = partitioner.modeType = modeTypeParent;
tempCS->treeType = partitioner.treeType = treeTypeParent;
partitioner.chType = chTypeParent;
if( modeTypeParent == MODE_TYPE_ALL )
{
m_pcIntraSearch->setSaveCuCostInSCIPU( false );
if( numRoundRdo == 2 && tempCS->modeType == MODE_TYPE_INTRA )
{
m_pcIntraSearch->initCuAreaCostInSCIPU();
}
}
if( skipInterPass )
{
break;
}
}
#if GDR_ENABLED
if (bestCS->cus.size() > 0 && splitmode != bestCS->cus[0]->splitSeries)
#else
if (splitmode != bestCS->cus[0]->splitSeries)
splitmode = bestCS->cus[0]->splitSeries;
const CodingUnit& cu = *bestCS->cus.front();
cu.cs->prevPLT = bestCS->prevPLT;
for (int i = compBegin; i < (compBegin + numComp); i++)
{
ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);
bestLastPLTSize[comID] = bestCS->cus[0]->cs->prevPLT.curPLTSize[comID];
memcpy(bestLastPLT[i], bestCS->cus[0]->cs->prevPLT.curPLT[i], bestCS->cus[0]->cs->prevPLT.curPLTSize[comID] * sizeof(Pel));
}

Karsten Suehring
committed
else
{
THROW( "Don't know how to handle mode: type = " << currTestMode.type << ", options = " << currTestMode.opts );

Karsten Suehring
committed
}
} while( m_modeCtrl->nextMode( *tempCS, partitioner ) );

Karsten Suehring
committed
//////////////////////////////////////////////////////////////////////////
// Finishing CU
if( tempCS->cost == MAX_DOUBLE && bestCS->cost == MAX_DOUBLE )
{
//although some coding modes were planned to be tried in RDO, no coding mode actually finished encoding due to early termination
//thus tempCS->cost and bestCS->cost are both MAX_DOUBLE; in this case, skip the following process for normal case
m_modeCtrl->finishCULevel( partitioner );
return;
}

Karsten Suehring
committed
// set context states
m_CABACEstimator->getCtx() = m_CurrCtx->best;
// QP from last processed CU for further processing
//copy the qp of the last non-chroma CU
int numCUInThisNode = (int)bestCS->cus.size();
if (numCUInThisNode > 1 && bestCS->cus.back()->chType == ChannelType::CHROMA && !CS::isDualITree(*bestCS))
CHECK(bestCS->cus[numCUInThisNode - 2]->chType != ChannelType::LUMA, "wrong chType");
bestCS->prevQP[partitioner.chType] = bestCS->cus[numCUInThisNode - 2]->qp;
bestCS->prevQP[partitioner.chType] = bestCS->cus.back()->qp;
if ((!slice.isIntra() || slice.getSPS()->getIBCFlag()) && isLuma(partitioner.chType) && bestCS->cus.size() == 1
&& (CU::isInter(*bestCS->cus.back()) || CU::isIBC(*bestCS->cus.back()))
&& bestCS->area.Y() == (*bestCS->cus.back()).Y())
const CodingUnit& cu = *bestCS->cus.front();
bestCS->picture->getPredBuf(currCsArea).copyFrom(bestCS->getPredBuf(currCsArea));

Karsten Suehring
committed
bestCS->picture->getRecoBuf( currCsArea ).copyFrom( bestCS->getRecoBuf( currCsArea ) );
m_modeCtrl->finishCULevel( partitioner );
if( m_pcIntraSearch->getSaveCuCostInSCIPU() && bestCS->cus.size() == 1 )
{
m_pcIntraSearch->saveCuAreaCostInSCIPU( Area( partitioner.currArea().lumaPos(), partitioner.currArea().lumaSize() ), bestCS->cost );
}

Karsten Suehring
committed
Yung-Hsuan Chao (Jessie)
committed
if (bestCS->cus.size() == 1) // no partition
{