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-2019, 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
* 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 Prediction.cpp
\brief prediction class
*/
#include "IntraPrediction.h"
#include "Unit.h"
#include "UnitTools.h"
#include "Buffer.h"
#include "dtrace_next.h"
#include "Rom.h"
#include <memory.h>
#include "CommonLib/InterpolationFilter.h"

Karsten Suehring
committed
//! \ingroup CommonLib
//! \{
// ====================================================================================================================
// Tables
// ====================================================================================================================
const uint8_t IntraPrediction::m_aucIntraFilter[MAX_NUM_CHANNEL_TYPE][MAX_INTRA_FILTER_DEPTHS] =
{
{ // Luma
20, // 1xn
20, // 2xn
20, // 4xn
14, // 8xn
2, // 16xn
0, // 32xn
0, // 64xn
0, // 128xn
},
{ // Chroma
40, // 1xn
40, // 2xn
40, // 4xn
28, // 8xn
4, // 16xn
0, // 32xn
0, // 64xn
0, // 128xn
}
};
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
const TFilterCoeff g_intraGaussFilter[32][4] = {
{ 16, 32, 16, 0 },
{ 15, 29, 17, 3 },
{ 15, 29, 17, 3 },
{ 14, 29, 18, 3 },
{ 13, 29, 18, 4 },
{ 13, 28, 19, 4 },
{ 13, 28, 19, 4 },
{ 12, 28, 20, 4 },
{ 11, 28, 20, 5 },
{ 11, 27, 21, 5 },
{ 10, 27, 22, 5 },
{ 9, 27, 22, 6 },
{ 9, 26, 23, 6 },
{ 9, 26, 23, 6 },
{ 8, 25, 24, 7 },
{ 8, 25, 24, 7 },
{ 8, 24, 24, 8 },
{ 7, 24, 25, 8 },
{ 7, 24, 25, 8 },
{ 6, 23, 26, 9 },
{ 6, 23, 26, 9 },
{ 6, 22, 27, 9 },
{ 5, 22, 27, 10 },
{ 5, 21, 27, 11 },
{ 5, 20, 28, 11 },
{ 4, 20, 28, 12 },
{ 4, 19, 28, 13 },
{ 4, 19, 28, 13 },
{ 4, 18, 29, 13 },
{ 3, 18, 29, 14 },
{ 3, 17, 29, 15 },

Christian Helmrich
committed
{ 3, 17, 29, 15 }

Karsten Suehring
committed
// ====================================================================================================================
// Constructor / destructor / initialize
// ====================================================================================================================
IntraPrediction::IntraPrediction()
:
m_currChromaFormat( NUM_CHROMA_FORMAT )
{
for (uint32_t ch = 0; ch < MAX_NUM_COMPONENT; ch++)
{
for (uint32_t buf = 0; buf < NUM_PRED_BUF; buf++)
{
m_piYuvExt[ch][buf] = nullptr;
}
}
for (uint32_t ch = 0; ch < MAX_NUM_COMPONENT; ch++)
{
for (uint32_t buf = 0; buf < 4; buf++)
{
m_yuvExt2[ch][buf] = nullptr;
}
}

Karsten Suehring
committed
m_piTemp = nullptr;

Karsten Suehring
committed
}
IntraPrediction::~IntraPrediction()
{
destroy();
}
void IntraPrediction::destroy()
{
for (uint32_t ch = 0; ch < MAX_NUM_COMPONENT; ch++)
{
for (uint32_t buf = 0; buf < NUM_PRED_BUF; buf++)
{
delete[] m_piYuvExt[ch][buf];
m_piYuvExt[ch][buf] = nullptr;
}
}
for (uint32_t ch = 0; ch < MAX_NUM_COMPONENT; ch++)
{
for (uint32_t buf = 0; buf < 4; buf++)
{
delete[] m_yuvExt2[ch][buf];
m_yuvExt2[ch][buf] = nullptr;
}
}

Karsten Suehring
committed
delete[] m_piTemp;
m_piTemp = nullptr;
delete[] m_pMdlmTemp;
m_pMdlmTemp = nullptr;

Karsten Suehring
committed
}
void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepthY)
{
// if it has been initialised before, but the chroma format has changed, release the memory and start again.
if (m_piYuvExt[COMPONENT_Y][PRED_BUF_UNFILTERED] != nullptr && m_currChromaFormat != chromaFormatIDC)
{
destroy();
}
if (m_yuvExt2[COMPONENT_Y][0] != nullptr && m_currChromaFormat != chromaFormatIDC)
{
destroy();
}

Karsten Suehring
committed
m_currChromaFormat = chromaFormatIDC;
if (m_piYuvExt[COMPONENT_Y][PRED_BUF_UNFILTERED] == nullptr) // check if first is null (in which case, nothing initialised yet)
{
m_iYuvExtSize = (MAX_CU_SIZE * 2 + 1 + MAX_REF_LINE_IDX * 33) * (MAX_CU_SIZE * 2 + 1 + MAX_REF_LINE_IDX * 33);

Karsten Suehring
committed
for (uint32_t ch = 0; ch < MAX_NUM_COMPONENT; ch++)
{
for (uint32_t buf = 0; buf < NUM_PRED_BUF; buf++)
{
m_piYuvExt[ch][buf] = new Pel[m_iYuvExtSize];
}
}
}
if (m_yuvExt2[COMPONENT_Y][0] == nullptr) // check if first is null (in which case, nothing initialised yet)
{
m_yuvExtSize2 = (MAX_CU_SIZE) * (MAX_CU_SIZE);
for (uint32_t ch = 0; ch < MAX_NUM_COMPONENT; ch++)
{
for (uint32_t buf = 0; buf < 4; buf++)
{
m_yuvExt2[ch][buf] = new Pel[m_yuvExtSize2];
}
}
}

Karsten Suehring
committed
if (m_piTemp == nullptr)
{
m_piTemp = new Pel[(MAX_CU_SIZE + 1) * (MAX_CU_SIZE + 1)];
}
if (m_pMdlmTemp == nullptr)
{
m_pMdlmTemp = new Pel[(2 * MAX_CU_SIZE + 1)*(2 * MAX_CU_SIZE + 1)];//MDLM will use top-above and left-below samples.
}

Karsten Suehring
committed
}
// ====================================================================================================================
// Public member functions
// ====================================================================================================================
// Function for calculating DC value of the reference samples used in Intra prediction
//NOTE: Bit-Limit - 25-bit source
Pel IntraPrediction::xGetPredValDc( const CPelBuf &pSrc, const Size &dstSize )
{
CHECK( dstSize.width == 0 || dstSize.height == 0, "Empty area provided" );
int idx, sum = 0;
Pel dcVal;
const int width = dstSize.width;
const int height = dstSize.height;
const auto denom = (width == height) ? (width << 1) : std::max(width,height);
const auto divShift = g_aucLog2[denom];
const auto divOffset = (denom >> 1);
if ( width >= height )
{

Christian Helmrich
committed
for( idx = 0; idx < width; idx++ )
{
sum += pSrc.at( 1 + idx, 0 );
}

Karsten Suehring
committed
}
if ( width <= height )
{

Christian Helmrich
committed
for( idx = 0; idx < height; idx++ )
{
sum += pSrc.at( 0, 1 + idx );
}

Karsten Suehring
committed
}
dcVal = (sum + divOffset) >> divShift;
return dcVal;
}
int IntraPrediction::getWideAngle( int width, int height, int predMode )
{
if ( predMode > DC_IDX && predMode <= VDIA_IDX )

Karsten Suehring
committed
{
int modeShift[] = { 0, 6, 10, 12, 14, 15 };
int deltaSize = abs(g_aucLog2[width] - g_aucLog2[height]);
if (width > height && predMode < 2 + modeShift[deltaSize])

Karsten Suehring
committed
{
predMode += (VDIA_IDX - 1);
}
else if (height > width && predMode > VDIA_IDX - modeShift[deltaSize])
{
predMode -= (VDIA_IDX - 1);

Karsten Suehring
committed
}
}

Karsten Suehring
committed
void IntraPrediction::setReferenceArrayLengths( const CompArea &area )
{
// set Top and Left reference samples length
const int width = area.width;
const int height = area.height;

Karsten Suehring
committed
m_leftRefLength = (height << 1);
m_topRefLength = (width << 1);

Karsten Suehring
committed

Karsten Suehring
committed
Alexey Filippov
committed
void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, const PredictionUnit &pu)

Karsten Suehring
committed
{
const ComponentID compID = MAP_CHROMA( compId );
const ChannelType channelType = toChannelType( compID );
const int iWidth = piPred.width;
const int iHeight = piPred.height;
const uint32_t uiDirMode = isLuma( compId ) && pu.cu->bdpcmMode ? BDPCM_IDX : PU::getFinalIntraMode( pu, channelType );

Karsten Suehring
committed
CHECK( g_aucLog2[iWidth] < 2 && pu.cs->pcv->noChroma2x2, "Size not allowed" );
CHECK( g_aucLog2[iWidth] > 7, "Size not allowed" );
Alexey Filippov
committed
const int multiRefIdx = m_ipaParam.multiRefIndex;
const int whRatio = m_ipaParam.whRatio;
const int hwRatio = m_ipaParam.hwRatio;
const int srcStride = m_topRefLength + 1 + (whRatio + 1) * multiRefIdx;
const int srcHStride = m_leftRefLength + 1 + (hwRatio + 1) * multiRefIdx;

Karsten Suehring
committed
Alexey Filippov
committed
const CPelBuf & srcBuf = CPelBuf(getPredictorPtr(compID), srcStride, srcHStride);

Karsten Suehring
committed
const ClpRng& clpRng(pu.cu->cs->slice->clpRng(compID));
switch (uiDirMode)
{
Alexey Filippov
committed
case(PLANAR_IDX): xPredIntraPlanar(srcBuf, piPred); break;
case(DC_IDX): xPredIntraDc(srcBuf, piPred, channelType, false); break;
case(BDPCM_IDX): xPredIntraBDPCM(srcBuf, piPred, pu.cu->bdpcmMode, clpRng); break;
Alexey Filippov
committed
default: xPredIntraAng(srcBuf, piPred, channelType, clpRng); break;

Karsten Suehring
committed
}
Alexey Filippov
committed
if (m_ipaParam.applyPDPC)

Karsten Suehring
committed
{
PelBuf dstBuf = piPred;
const int scale = ((g_aucLog2[iWidth] - 2 + g_aucLog2[iHeight] - 2 + 2) >> 2);
CHECK(scale < 0 || scale > 31, "PDPC: scale < 0 || scale > 31");
#if JVET_O0364_PDPC_DC
if (uiDirMode == PLANAR_IDX || uiDirMode == DC_IDX)
#else

Karsten Suehring
committed
if (uiDirMode == PLANAR_IDX)
#endif

Karsten Suehring
committed
{
for (int y = 0; y < iHeight; y++)
{
int wT = 32 >> std::min(31, ((y << 1) >> scale));
const Pel left = srcBuf.at(0, y + 1);
for (int x = 0; x < iWidth; x++)
{
const Pel top = srcBuf.at(x + 1, 0);
int wL = 32 >> std::min(31, ((x << 1) >> scale));
dstBuf.at(x, y) = ClipPel((wL * left + wT * top + (64 - wL - wT) * dstBuf.at(x, y) + 32) >> 6, clpRng);
}
}
}
#if !JVET_O0364_PDPC_DC

Karsten Suehring
committed
else if (uiDirMode == DC_IDX)
{
const Pel topLeft = srcBuf.at(0, 0);
for (int y = 0; y < iHeight; y++)
{
int wT = 32 >> std::min(31, ((y << 1) >> scale));
const Pel left = srcBuf.at(0, y + 1);
for (int x = 0; x < iWidth; x++)
{
const Pel top = srcBuf.at(x + 1, 0);
int wL = 32 >> std::min(31, ((x << 1) >> scale));
int wTL = (wL >> 4) + (wT >> 4);
dstBuf.at(x, y) = ClipPel((wL * left + wT * top - wTL * topLeft + (64 - wL - wT + wTL) * dstBuf.at(x, y) + 32) >> 6, clpRng);
}
}
}
#endif

Karsten Suehring
committed
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
else if (uiDirMode == HOR_IDX)
{
const Pel topLeft = srcBuf.at(0, 0);
for (int y = 0; y < iHeight; y++)
{
int wT = 32 >> std::min(31, ((y << 1) >> scale));
for (int x = 0; x < iWidth; x++)
{
const Pel top = srcBuf.at(x + 1, 0);
int wTL = wT;
dstBuf.at(x, y) = ClipPel((wT * top - wTL * topLeft + (64 - wT + wTL) * dstBuf.at(x, y) + 32) >> 6, clpRng);
}
}
}
else if (uiDirMode == VER_IDX)
{
const Pel topLeft = srcBuf.at(0, 0);
for (int y = 0; y < iHeight; y++)
{
const Pel left = srcBuf.at(0, y + 1);
for (int x = 0; x < iWidth; x++)
{
int wL = 32 >> std::min(31, ((x << 1) >> scale));
int wTL = wL;
dstBuf.at(x, y) = ClipPel((wL * left - wTL * topLeft + (64 - wL + wTL) * dstBuf.at(x, y) + 32) >> 6, clpRng);
}
}
}
}
}

Karsten Suehring
committed
void IntraPrediction::predIntraChromaLM(const ComponentID compID, PelBuf &piPred, const PredictionUnit &pu, const CompArea& chromaArea, int intraDir)
{
int iLumaStride = 0;
PelBuf Temp;
if ((intraDir == MDLM_L_IDX) || (intraDir == MDLM_T_IDX))
{
iLumaStride = 2 * MAX_CU_SIZE + 1;
Temp = PelBuf(m_pMdlmTemp + iLumaStride + 1, iLumaStride, Size(chromaArea));
}
else
{
iLumaStride = MAX_CU_SIZE + 1;
Temp = PelBuf(m_piTemp + iLumaStride + 1, iLumaStride, Size(chromaArea));

Karsten Suehring
committed
int a, b, iShift;
xGetLMParameters(pu, compID, chromaArea, a, b, iShift);
////// final prediction
piPred.copyFrom(Temp);
piPred.linearTransform(a, iShift, b, true, pu.cs->slice->clpRng(compID));
}
/** Function for deriving planar intra prediction. This function derives the prediction samples for planar mode (intra coding).
*/
//NOTE: Bit-Limit - 24-bit source
Alexey Filippov
committed
void IntraPrediction::xPredIntraPlanar( const CPelBuf &pSrc, PelBuf &pDst )

Karsten Suehring
committed
{
const uint32_t width = pDst.width;
const uint32_t height = pDst.height;
const uint32_t log2W = g_aucLog2[width < 2 ? 2 : width];
const uint32_t log2H = g_aucLog2[height < 2 ? 2 : height];

Karsten Suehring
committed
int leftColumn[MAX_CU_SIZE + 1], topRow[MAX_CU_SIZE + 1], bottomRow[MAX_CU_SIZE], rightColumn[MAX_CU_SIZE];
const uint32_t offset = 1 << (log2W + log2H);

Karsten Suehring
committed
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
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
// Get left and above reference column and row
for( int k = 0; k < width + 1; k++ )
{
topRow[k] = pSrc.at( k + 1, 0 );
}
for( int k = 0; k < height + 1; k++ )
{
leftColumn[k] = pSrc.at( 0, k + 1 );
}
// Prepare intermediate variables used in interpolation
int bottomLeft = leftColumn[height];
int topRight = topRow[width];
for( int k = 0; k < width; k++ )
{
bottomRow[k] = bottomLeft - topRow[k];
topRow[k] = topRow[k] << log2H;
}
for( int k = 0; k < height; k++ )
{
rightColumn[k] = topRight - leftColumn[k];
leftColumn[k] = leftColumn[k] << log2W;
}
const uint32_t finalShift = 1 + log2W + log2H;
const uint32_t stride = pDst.stride;
Pel* pred = pDst.buf;
for( int y = 0; y < height; y++, pred += stride )
{
int horPred = leftColumn[y];
for( int x = 0; x < width; x++ )
{
horPred += rightColumn[y];
topRow[x] += bottomRow[x];
int vertPred = topRow[x];
pred[x] = ( ( horPred << log2H ) + ( vertPred << log2W ) + offset ) >> finalShift;
}
}
}
void IntraPrediction::xPredIntraDc( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const bool enableBoundaryFilter )
{
const Pel dcval = xGetPredValDc( pSrc, pDst );
pDst.fill( dcval );
}
Alexey Filippov
committed
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
// Function for initialization of intra prediction parameters
void IntraPrediction::initPredIntraParams(const PredictionUnit & pu, const CompArea area, const SPS& sps)
{
const ComponentID compId = area.compID;
const ChannelType chType = toChannelType(compId);
const bool useISP = NOT_INTRA_SUBPARTITIONS != pu.cu->ispMode && isLuma( chType );
const Size cuSize = Size( pu.cu->blocks[compId].width, pu.cu->blocks[compId].height );
const Size puSize = Size( area.width, area.height );
const Size& blockSize = useISP ? cuSize : puSize;
const int dirMode = PU::getFinalIntraMode(pu, chType);
const int predMode = getWideAngle( blockSize.width, blockSize.height, dirMode );
m_ipaParam.whRatio = std::max( unsigned( 1 ), blockSize.width / blockSize.height ) ;
m_ipaParam.hwRatio = std::max( unsigned( 1 ), blockSize.height / blockSize.width ) ;
m_ipaParam.isModeVer = predMode >= DIA_IDX;
m_ipaParam.multiRefIndex = isLuma (chType) ? pu.multiRefIdx : 0 ;
m_ipaParam.refFilterFlag = false;
m_ipaParam.interpolationFlag = false;
m_ipaParam.applyPDPC = !useISP && m_ipaParam.multiRefIndex == 0;
const int intraPredAngleMode = (m_ipaParam.isModeVer) ? predMode - VER_IDX : -(predMode - HOR_IDX);
int absAng = 0;
if (dirMode > DC_IDX && dirMode < NUM_LUMA_MODE) // intraPredAngle for directional modes
{
static const int angTable[32] = { 0, 1, 2, 3, 4, 6, 8, 10, 12, 14, 16, 18, 20, 23, 26, 29, 32, 35, 39, 45, 51, 57, 64, 73, 86, 102, 128, 171, 256, 341, 512, 1024 };
static const int invAngTable[32] = { 0, 8192, 4096, 2731, 2048, 1365, 1024, 819, 683, 585, 512, 455, 410, 356, 315, 282, 256, 234, 210, 182, 161, 144, 128, 112, 95, 80, 64, 48, 32, 24, 16, 8 }; // (256 * 32) / Angle
Alexey Filippov
committed
const int absAngMode = abs(intraPredAngleMode);
const int signAng = intraPredAngleMode < 0 ? -1 : 1;
absAng = angTable [absAngMode];
m_ipaParam.invAngle = invAngTable[absAngMode];
m_ipaParam.intraPredAngle = signAng * absAng;
m_ipaParam.applyPDPC &= m_ipaParam.intraPredAngle == 0 || m_ipaParam.intraPredAngle >= 12; // intra prediction modes: HOR, VER, x, where x>=VDIA-8 or x<=2+8
}
// high level conditions and DC intra prediction
if( sps.getSpsRangeExtension().getIntraSmoothingDisabledFlag()
|| !isLuma( chType )
Alexey Filippov
committed
|| useISP
|| m_ipaParam.multiRefIndex
|| DC_IDX == dirMode
)
Alexey Filippov
committed
if (useISP)
{
m_ipaParam.interpolationFlag = (m_ipaParam.isModeVer ? puSize.width : puSize.height) > 8 ? true : false ;
}
}
else if (isLuma( chType ) && pu.cu->bdpcmMode) // BDPCM
{
m_ipaParam.refFilterFlag = false;
}
else if (dirMode == PLANAR_IDX) // Planar intra prediction
Alexey Filippov
committed
{
m_ipaParam.refFilterFlag = puSize.width * puSize.height > 32 ? true : false;
}
else if (!useISP)// HOR, VER and angular modes (MDIS)
{
Alexey Filippov
committed
if (predMode != dirMode ) // wide-anlge mode
{
filterFlag = true;
}
else
{
const int diff = std::min<int>( abs( dirMode - HOR_IDX ), abs( dirMode - VER_IDX ) );
const int log2Size = ((g_aucLog2[puSize.width] + g_aucLog2[puSize.height]) >> 1);
CHECK( log2Size >= MAX_INTRA_FILTER_DEPTHS, "Size not supported" );
filterFlag = (diff > m_aucIntraFilter[chType][log2Size]);
}
// Selelection of either ([1 2 1] / 4 ) refrence filter OR Gaussian 4-tap interpolation filter
if (filterFlag)
{
const bool isRefFilter = isIntegerSlope(absAng);
m_ipaParam.refFilterFlag = isRefFilter && puSize.width * puSize.height > 32;
Alexey Filippov
committed
m_ipaParam.interpolationFlag = !isRefFilter;
}
}
}

Karsten Suehring
committed
/** Function for deriving the simplified angular intra predictions.
*
* This function derives the prediction samples for the angular mode based on the prediction direction indicated by
* the prediction mode index. The prediction direction is given by the displacement of the bottom row of the block and
* the reference row above the block in the case of vertical prediction or displacement of the rightmost column
* of the block and reference column left from the block in the case of the horizontal prediction. The displacement
* is signalled at 1/32 pixel accuracy. When projection of the predicted pixel falls inbetween reference samples,
* the predicted value for the pixel is linearly interpolated from the reference samples. All reference samples are taken
* from the extended main reference.
*/
//NOTE: Bit-Limit - 25-bit source
Alexey Filippov
committed
void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const ClpRng& clpRng)

Karsten Suehring
committed
{
int width =int(pDst.width);
int height=int(pDst.height);
Alexey Filippov
committed
const bool bIsModeVer = m_ipaParam.isModeVer;
const int whRatio = m_ipaParam.whRatio;
const int hwRatio = m_ipaParam.hwRatio;
const int multiRefIdx = m_ipaParam.multiRefIndex;
Alexey Filippov
committed
const int intraPredAngle = m_ipaParam.intraPredAngle;
const int invAngle = m_ipaParam.invAngle;

Karsten Suehring
committed
Pel* refMain;
Pel* refSide;
Pel refAbove[2 * MAX_CU_SIZE + 3 + 33 * MAX_REF_LINE_IDX];
Pel refLeft [2 * MAX_CU_SIZE + 3 + 33 * MAX_REF_LINE_IDX];

Karsten Suehring
committed
// Initialize the Main and Left reference array.
if (intraPredAngle < 0)
{
Alexey Filippov
committed
const int width = pDst.width + 1;
const int height = pDst.height + 1;
const int lastIdx = (bIsModeVer ? width : height) + multiRefIdx;
const int firstIdx = (((bIsModeVer ? height : width) - 1) * intraPredAngle) >> 5;
for (int x = 0; x < width + 1 + multiRefIdx; x++)

Karsten Suehring
committed
{
refAbove[x + height - 1] = pSrc.at( x, 0 );
}
for (int y = 0; y < height + 1 + multiRefIdx; y++)

Karsten Suehring
committed
{
refLeft[y + width - 1] = pSrc.at( 0, y );
}
refMain = (bIsModeVer ? refAbove + height : refLeft + width ) - 1;
refSide = (bIsModeVer ? refLeft + width : refAbove + height) - 1;
// Extend the Main reference to the left.
int invAngleSum = 128; // rounding for (shift by 8)
for( int k = -1; k > firstIdx; k-- )

Karsten Suehring
committed
{
invAngleSum += invAngle;
refMain[k] = refSide[invAngleSum>>8];
}
refMain[lastIdx] = refMain[lastIdx-1];
refMain[firstIdx] = refMain[firstIdx+1];

Karsten Suehring
committed
}
else
{
for (int x = 0; x < m_topRefLength + 1 + (whRatio + 1) * multiRefIdx; x++)

Karsten Suehring
committed
{
refAbove[x+1] = pSrc.at(x, 0);

Karsten Suehring
committed
}
for (int y = 0; y < m_leftRefLength + 1 + (hwRatio + 1) * multiRefIdx; y++)

Karsten Suehring
committed
{
refLeft[y+1] = pSrc.at(0, y);

Karsten Suehring
committed
}
refMain = bIsModeVer ? refAbove : refLeft ;
refSide = bIsModeVer ? refLeft : refAbove;
refMain++;
refSide++;
refMain[-1] = refMain[0];
auto lastIdx = 1 + ((bIsModeVer) ? m_topRefLength + (whRatio + 1) * multiRefIdx : m_leftRefLength + (hwRatio + 1) * multiRefIdx);
refMain[lastIdx] = refMain[lastIdx-1];

Karsten Suehring
committed
}
// swap width/height if we are doing a horizontal mode:
Pel tempArray[MAX_CU_SIZE*MAX_CU_SIZE];
const int dstStride = bIsModeVer ? pDst.stride : MAX_CU_SIZE;
Pel *pDstBuf = bIsModeVer ? pDst.buf : tempArray;
if (!bIsModeVer)
{
std::swap(width, height);
}
// compensate for line offset in reference line buffers
refMain += multiRefIdx;
refSide += multiRefIdx;

Karsten Suehring
committed
if( intraPredAngle == 0 ) // pure vertical or pure horizontal
{
for( int y = 0; y < height; y++ )
{
for( int x = 0; x < width; x++ )
{
pDstBuf[y*dstStride + x] = refMain[x + 1];
}
}
}
else
{
Pel *pDsty=pDstBuf;
for (int y = 0, deltaPos = intraPredAngle * (1 + multiRefIdx); y<height; y++, deltaPos += intraPredAngle, pDsty += dstStride)

Karsten Suehring
committed
{
const int deltaInt = deltaPos >> 5;
const int deltaFract = deltaPos & (32 - 1);
Alexey Filippov
committed
if ( !isIntegerSlope( abs(intraPredAngle) ) )

Karsten Suehring
committed
{
if( isLuma(channelType) )
{
Pel p[4];
Alexey Filippov
committed
const bool useCubicFilter = !m_ipaParam.interpolationFlag;
TFilterCoeff const * const f = (useCubicFilter) ? InterpolationFilter::getChromaFilterTable(deltaFract) : g_intraGaussFilter[deltaFract];
int refMainIndex = deltaInt + 1;
for( int x = 0; x < width; x++, refMainIndex++ )
{
p[0] = refMain[refMainIndex - 1];
p[1] = refMain[refMainIndex];
p[2] = refMain[refMainIndex + 1];
p[3] = f[3] != 0 ? refMain[refMainIndex + 2] : 0;
pDstBuf[y*dstStride + x] = static_cast<Pel>((static_cast<int>(f[0] * p[0]) + static_cast<int>(f[1] * p[1]) + static_cast<int>(f[2] * p[2]) + static_cast<int>(f[3] * p[3]) + 32) >> 6);
if( useCubicFilter ) // only cubic filter has negative coefficients and requires clipping
{
pDstBuf[y*dstStride + x] = ClipPel( pDstBuf[y*dstStride + x], clpRng );
}
}
}
else

Karsten Suehring
committed
{
// Do linear filtering
const Pel *pRM = refMain + deltaInt + 1;
int lastRefMainPel = *pRM++;
for( int x = 0; x < width; pRM++, x++ )
{
int thisRefMainPel = *pRM;
pDsty[x + 0] = ( Pel ) ( ( ( 32 - deltaFract )*lastRefMainPel + deltaFract*thisRefMainPel + 16 ) >> 5 );
lastRefMainPel = thisRefMainPel;
}
}
}
else
{
// Just copy the integer samples
for( int x = 0; x < width; x++ )
{
pDsty[x] = refMain[x + deltaInt + 1];
}
}
const int scale = ((g_aucLog2[width] - 2 + g_aucLog2[height] - 2 + 2) >> 2);
CHECK(scale < 0 || scale > 31, "PDPC: scale < 0 || scale > 31");
Alexey Filippov
committed
if (m_ipaParam.applyPDPC)

Karsten Suehring
committed
{
if (m_ipaParam.intraPredAngle == 32) // intra prediction modes: 2 and VDIA

Karsten Suehring
committed
{
Alexey Filippov
committed
int wT = 16 >> std::min(31, ((y << 1) >> scale));

Karsten Suehring
committed
Alexey Filippov
committed
for (int x = 0; x < width; x++)
{
int wL = 16 >> std::min(31, ((x << 1) >> scale));
if (wT + wL == 0) break;
int c = x + y + 1;
if (c >= 2 * height) { wL = 0; }
if (c >= 2 * width) { wT = 0; }
const Pel left = (wL != 0) ? refSide[c + 1] : 0;
const Pel top = (wT != 0) ? refMain[c + 1] : 0;

Karsten Suehring
committed
Alexey Filippov
committed
pDsty[x] = ClipPel((wL * left + wT * top + (64 - wL - wT) * pDsty[x] + 32) >> 6, clpRng);
}

Karsten Suehring
committed
}
Alexey Filippov
committed
else

Karsten Suehring
committed
{
Alexey Filippov
committed
int invAngleSum0 = 2;
for (int x = 0; x < width; x++)
{
invAngleSum0 += invAngle;
int deltaPos0 = invAngleSum0 >> 2;
int deltaFrac0 = deltaPos0 & 63;
int deltaInt0 = deltaPos0 >> 6;

Karsten Suehring
committed
Alexey Filippov
committed
int deltay = y + deltaInt0 + 1;
if (deltay >(bIsModeVer ? m_leftRefLength : m_topRefLength) - 1) break;

Karsten Suehring
committed
Alexey Filippov
committed
int wL = 32 >> std::min(31, ((x << 1) >> scale));
if (wL == 0) break;
Pel *p = refSide + deltay;

Karsten Suehring
committed
Alexey Filippov
committed
Pel left = p[deltaFrac0 >> 5];
pDsty[x] = ClipPel((wL * left + (64 - wL) * pDsty[x] + 32) >> 6, clpRng);
}

Karsten Suehring
committed
}
}
}
}
// Flip the block if this is the horizontal mode
if( !bIsModeVer )
{
for( int y = 0; y < height; y++ )
{
for( int x = 0; x < width; x++ )
{
pDst.at( y, x ) = pDstBuf[x];
}
pDstBuf += dstStride;
}
}
}
void IntraPrediction::xPredIntraBDPCM(const CPelBuf &pSrc, PelBuf &pDst, const uint32_t dirMode, const ClpRng& clpRng )
{
const int wdt = pDst.width;
const int hgt = pDst.height;
const int strideP = pDst.stride;
const int strideS = pSrc.stride;
CHECK( !( dirMode == 1 || dirMode == 2 ), "Incorrect BDPCM mode parameter." );
if( dirMode == 1 )
{
Pel val;
for( int y = 0; y < hgt; y++ )
{
val = pSrc.buf[(y + 1) * strideS];
for( int x = 0; x < wdt; x++ )
{
}
}
else
{
for( int y = 0; y < hgt; y++ )
{
for( int x = 0; x < wdt; x++ )
{

Karsten Suehring
committed
bool IntraPrediction::useDPCMForFirstPassIntraEstimation(const PredictionUnit &pu, const uint32_t &uiDirMode)
{
return CU::isRDPCMEnabled(*pu.cu) && pu.cu->transQuantBypass && (uiDirMode == HOR_IDX || uiDirMode == VER_IDX);
}
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
void IntraPrediction::geneWeightedPred(const ComponentID compId, PelBuf &pred, const PredictionUnit &pu, Pel *srcBuf)
{
const int width = pred.width;
const int height = pred.height;
const int srcStride = width;
const int dstStride = pred.stride;
Pel* dstBuf = pred.buf;
int wIntra, wMerge;
const Position posBL = pu.Y().bottomLeft();
const Position posTR = pu.Y().topRight();
const PredictionUnit *neigh0 = pu.cs->getPURestricted(posBL.offset(-1, 0), pu, CHANNEL_TYPE_LUMA);
const PredictionUnit *neigh1 = pu.cs->getPURestricted(posTR.offset(0, -1), pu, CHANNEL_TYPE_LUMA);
bool isNeigh0Intra = neigh0 && (CU::isIntra(*neigh0->cu));
bool isNeigh1Intra = neigh1 && (CU::isIntra(*neigh1->cu));
if (isNeigh0Intra && isNeigh1Intra)
{
wIntra = 3; wMerge = 1;
}
else
{
if (!isNeigh0Intra && !isNeigh1Intra)
{
wIntra = 1; wMerge = 3;
}
else
{
wIntra = 2; wMerge = 2;
}
}
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
dstBuf[y*dstStride + x] = (wMerge * dstBuf[y*dstStride + x] + wIntra * srcBuf[y*srcStride + x] + 2) >> 2;
}
}
}
void IntraPrediction::switchBuffer(const PredictionUnit &pu, ComponentID compID, PelBuf srcBuff, Pel *dst)
{
Pel *src = srcBuff.bufAt(0, 0);
int compWidth = compID == COMPONENT_Y ? pu.Y().width : pu.Cb().width;
int compHeight = compID == COMPONENT_Y ? pu.Y().height : pu.Cb().height;
for (int i = 0; i < compHeight; i++)
{
memcpy(dst, src, compWidth * sizeof(Pel));
src += srcBuff.stride;
dst += compWidth;
}
}
void IntraPrediction::geneIntrainterPred(const CodingUnit &cu)
{
if (!cu.firstPU->mhIntraFlag)
{
return;
}
const PredictionUnit* pu = cu.firstPU;
Alexey Filippov
committed
initIntraPatternChType(cu, pu->Y());
predIntraAng(COMPONENT_Y, cu.cs->getPredBuf(*pu).Y(), *pu);
initIntraPatternChType(cu, pu->Cb());
predIntraAng(COMPONENT_Cb, cu.cs->getPredBuf(*pu).Cb(), *pu);
initIntraPatternChType(cu, pu->Cr());
predIntraAng(COMPONENT_Cr, cu.cs->getPredBuf(*pu).Cr(), *pu);
for (int currCompID = 0; currCompID < 3; currCompID++)
{
ComponentID currCompID2 = (ComponentID)currCompID;
PelBuf tmpBuf = currCompID == 0 ? cu.cs->getPredBuf(*pu).Y() : (currCompID == 1 ? cu.cs->getPredBuf(*pu).Cb() : cu.cs->getPredBuf(*pu).Cr());
switchBuffer(*pu, currCompID2, tmpBuf, getPredictorPtr2(currCompID2, 0));
}
}

Karsten Suehring
committed
inline bool isAboveLeftAvailable ( const CodingUnit &cu, const ChannelType &chType, const Position &posLT );
inline int isAboveAvailable ( const CodingUnit &cu, const ChannelType &chType, const Position &posLT, const uint32_t uiNumUnitsInPU, const uint32_t unitWidth, bool *validFlags );
inline int isLeftAvailable ( const CodingUnit &cu, const ChannelType &chType, const Position &posLT, const uint32_t uiNumUnitsInPU, const uint32_t unitWidth, bool *validFlags );
inline int isAboveRightAvailable ( const CodingUnit &cu, const ChannelType &chType, const Position &posRT, const uint32_t uiNumUnitsInPU, const uint32_t unitHeight, bool *validFlags );
inline int isBelowLeftAvailable ( const CodingUnit &cu, const ChannelType &chType, const Position &posLB, const uint32_t uiNumUnitsInPU, const uint32_t unitHeight, bool *validFlags );
Alexey Filippov
committed
void IntraPrediction::initIntraPatternChType(const CodingUnit &cu, const CompArea &area, const bool forceRefFilterFlag)

Karsten Suehring
committed
{
const CodingStructure& cs = *cu.cs;
Alexey Filippov
committed
if (!forceRefFilterFlag)
{
initPredIntraParams(*cu.firstPU, area, *cs.sps);
}

Karsten Suehring
committed
Pel *refBufUnfiltered = m_piYuvExt[area.compID][PRED_BUF_UNFILTERED];
Pel *refBufFiltered = m_piYuvExt[area.compID][PRED_BUF_FILTERED];
setReferenceArrayLengths( cu.ispMode && isLuma( area.compID ) ? cu.blocks[area.compID] : area );

Karsten Suehring
committed
// ----- Step 1: unfiltered reference samples -----
xFillReferenceSamples( cs.picture->getRecoBuf( area ), refBufUnfiltered, area, cu );
// ----- Step 2: filtered reference samples -----
Alexey Filippov
committed
if( m_ipaParam.refFilterFlag || forceRefFilterFlag )

Karsten Suehring
committed
{
Alexey Filippov
committed
xFilterReferenceSamples( refBufUnfiltered, refBufFiltered, area, *cs.sps, cu.firstPU->multiRefIdx );

Karsten Suehring
committed
}
}
void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBufUnfiltered, const CompArea &area, const CodingUnit &cu )
{
const ChannelType chType = toChannelType( area.compID );
const CodingStructure &cs = *cu.cs;
const SPS &sps = *cs.sps;
const PreCalcValues &pcv = *cs.pcv;
const int multiRefIdx = (area.compID == COMPONENT_Y) ? cu.firstPU->multiRefIdx : 0;

Karsten Suehring
committed
const int tuWidth = area.width;
const int tuHeight = area.height;
const int predSize = m_topRefLength;
const int predHSize = m_leftRefLength;
const int cuWidth = cu.blocks[area.compID].width;
const int cuHeight = cu.blocks[area.compID].height;
const int whRatio = cu.ispMode && isLuma(area.compID) ? std::max(1, cuWidth / cuHeight) : std::max(1, tuWidth / tuHeight);
const int hwRatio = cu.ispMode && isLuma(area.compID) ? std::max(1, cuHeight / cuWidth) : std::max(1, tuHeight / tuWidth);
const int predStride = predSize + 1 + (whRatio + 1) * multiRefIdx;

Karsten Suehring
committed
const bool noShift = pcv.noChroma2x2 && area.width == 4; // don't shift on the lowest level (chroma not-split)
const int unitWidth = tuWidth <= 2 && cu.ispMode && isLuma(area.compID) ? tuWidth : pcv.minCUWidth >> (noShift ? 0 : getComponentScaleX(area.compID, sps.getChromaFormatIdc()));
const int unitHeight = tuHeight <= 2 && cu.ispMode && isLuma(area.compID) ? tuHeight : pcv.minCUHeight >> (noShift ? 0 : getComponentScaleY(area.compID, sps.getChromaFormatIdc()));

Karsten Suehring
committed
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
const int totalAboveUnits = (predSize + (unitWidth - 1)) / unitWidth;
const int totalLeftUnits = (predHSize + (unitHeight - 1)) / unitHeight;
const int totalUnits = totalAboveUnits + totalLeftUnits + 1; //+1 for top-left
const int numAboveUnits = std::max<int>( tuWidth / unitWidth, 1 );
const int numLeftUnits = std::max<int>( tuHeight / unitHeight, 1 );
const int numAboveRightUnits = totalAboveUnits - numAboveUnits;
const int numLeftBelowUnits = totalLeftUnits - numLeftUnits;
CHECK( numAboveUnits <= 0 || numLeftUnits <= 0 || numAboveRightUnits <= 0 || numLeftBelowUnits <= 0, "Size not supported" );
// ----- Step 1: analyze neighborhood -----
const Position posLT = area;
const Position posRT = area.topRight();
const Position posLB = area.bottomLeft();
bool neighborFlags[4 * MAX_NUM_PART_IDXS_IN_CTU_WIDTH + 1];
int numIntraNeighbor = 0;
memset( neighborFlags, 0, totalUnits );
neighborFlags[totalLeftUnits] = isAboveLeftAvailable( cu, chType, posLT );
numIntraNeighbor += neighborFlags[totalLeftUnits] ? 1 : 0;
numIntraNeighbor += isAboveAvailable ( cu, chType, posLT, numAboveUnits, unitWidth, (neighborFlags + totalLeftUnits + 1) );
numIntraNeighbor += isAboveRightAvailable( cu, chType, posRT, numAboveRightUnits, unitWidth, (neighborFlags + totalLeftUnits + 1 + numAboveUnits) );
numIntraNeighbor += isLeftAvailable ( cu, chType, posLT, numLeftUnits, unitHeight, (neighborFlags + totalLeftUnits - 1) );
numIntraNeighbor += isBelowLeftAvailable ( cu, chType, posLB, numLeftBelowUnits, unitHeight, (neighborFlags + totalLeftUnits - 1 - numLeftUnits) );
// ----- Step 2: fill reference samples (depending on neighborhood) -----
CHECK((predHSize + 1) * predStride > m_iYuvExtSize, "Reference sample area not supported");
const Pel* srcBuf = recoBuf.buf;
const int srcStride = recoBuf.stride;
Pel* ptrDst = refBufUnfiltered;
const Pel* ptrSrc;
const Pel valueDC = 1 << (sps.getBitDepth( chType ) - 1);
if( numIntraNeighbor == 0 )
{
// Fill border with DC value
for (int j = 0; j <= predSize + multiRefIdx; j++) { ptrDst[j] = valueDC; }
for (int i = 1; i <= predHSize + multiRefIdx; i++) { ptrDst[i*predStride] = valueDC; }