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
* 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_INTRA_FILTER_DEPTHS] =

Karsten Suehring
committed
{
24, // 1xn
24, // 2xn
24, // 4xn
14, // 8xn
2, // 16xn
0, // 32xn
0, // 64xn
0 // 128xn

Karsten Suehring
committed
};

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 < 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 < 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 (m_yuvExt2[COMPONENT_Y][0] != nullptr && m_currChromaFormat != chromaFormatIDC)
{
destroy();
}

Karsten Suehring
committed
m_currChromaFormat = chromaFormatIDC;
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 = floorLog2(denom);

Karsten Suehring
committed
const auto divOffset = (denom >> 1);
if ( width >= height )
{

Christian Helmrich
committed
for( idx = 0; idx < width; idx++ )
{
Adarsh Krishnan Ramasubramonian
committed
sum += pSrc.at(m_ipaParam.multiRefIndex + 1 + idx, 0);

Christian Helmrich
committed
}

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

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

Christian Helmrich
committed
}

Karsten Suehring
committed
}
dcVal = (sum + divOffset) >> divShift;
return dcVal;
}
Santiago de Luxán Hernández
committed
int IntraPrediction::getModifiedWideAngle( int width, int height, int predMode )
//The function returns a 'modified' wide angle index, given that it is not necessary
//in this software implementation to reserve the values 0 and 1 for Planar and DC to generate the prediction signal.
//It should only be used to obtain the intraPredAngle parameter.
//To simply obtain the wide angle index, the function PU::getWideAngle should be used instead.
if ( predMode > DC_IDX && predMode <= VDIA_IDX )

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

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

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;
CHECK(iWidth == 2, "Width of 2 is not supported");
CHECK(PU::isMIP(pu, toChannelType(compId)), "We should not get here for MIP.");
const uint32_t uiDirMode = isLuma( compId ) && pu.cu->bdpcmMode ? BDPCM_IDX : !isLuma(compId) && pu.cu->bdpcmModeChroma ? BDPCM_IDX : PU::getFinalIntraMode(pu, channelType);

Karsten Suehring
committed
CHECK( floorLog2(iWidth) < 2 && pu.cs->pcv->noChroma2x2, "Size not allowed" );
CHECK( floorLog2(iWidth) > 7, "Size not allowed" );
const int srcStride = m_refBufferStride[compID];
const int srcHStride = 2;
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, isLuma(compID) ? pu.cu->bdpcmMode : pu.cu->bdpcmModeChroma, 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 = ((floorLog2(iWidth) - 2 + floorLog2(iHeight) - 2 + 2) >> 2);

Karsten Suehring
committed
CHECK(scale < 0 || scale > 31, "PDPC: scale < 0 || scale > 31");
if (uiDirMode == PLANAR_IDX || uiDirMode == DC_IDX)

Karsten Suehring
committed
{
for (int y = 0; y < iHeight; y++)
{
const int wT = 32 >> std::min(31, ((y << 1) >> scale));
const Pel left = srcBuf.at(y + 1, 1);

Karsten Suehring
committed
for (int x = 0; x < iWidth; x++)
{
const int wL = 32 >> std::min(31, ((x << 1) >> scale));
const Pel top = srcBuf.at(x + 1, 0);
const Pel val = dstBuf.at(x, y);
dstBuf.at(x, y) = val + ((wL * (left - val) + wT * (top - val) + 32) >> 6);

Karsten Suehring
committed
}
}
}
}
}

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 = floorLog2( width );
const uint32_t log2H = floorLog2( 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
// Get left and above reference column and row
Adrian Browne
committed
CHECK(width > MAX_CU_SIZE, "width greater than limit");

Karsten Suehring
committed
for( int k = 0; k < width + 1; k++ )
{
topRow[k] = pSrc.at( k + 1, 0 );
}
Adrian Browne
committed
CHECK(height > MAX_CU_SIZE, "height greater than limit");

Karsten Suehring
committed
for( int k = 0; k < height + 1; k++ )
{
leftColumn[k] = pSrc.at(k + 1, 1);

Karsten Suehring
committed
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
}
// 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
// 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);
Santiago de Luxán Hernández
committed
const int predMode = getModifiedWideAngle( blockSize.width, blockSize.height, dirMode );
Alexey Filippov
committed
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 = (puSize.width >= MIN_TB_SIZEY && puSize.height >= MIN_TB_SIZEY) && m_ipaParam.multiRefIndex == 0;
Alexey Filippov
committed
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, 16384, 8192, 5461, 4096, 2731, 2048, 1638, 1365, 1170, 1024, 910, 819, 712, 630, 565,
512, 468, 420, 364, 321, 287, 256, 224, 191, 161, 128, 96, 64, 48, 32, 16
}; // (512 * 32) / Angle
Alexey Filippov
committed
const int absAngMode = abs(intraPredAngleMode);
const int signAng = intraPredAngleMode < 0 ? -1 : 1;
absAng = angTable [absAngMode];
m_ipaParam.absInvAngle = invAngTable[absAngMode];
Alexey Filippov
committed
m_ipaParam.intraPredAngle = signAng * absAng;
if (intraPredAngleMode < 0)
{
m_ipaParam.applyPDPC = false;
}
else if (intraPredAngleMode > 0)
{
const int sideSize = m_ipaParam.isModeVer ? puSize.height : puSize.width;
const int maxScale = 2;
m_ipaParam.angularScale = std::min(maxScale, floorLog2(sideSize) - (floorLog2(3 * m_ipaParam.absInvAngle - 2) - 8));
m_ipaParam.applyPDPC &= m_ipaParam.angularScale >= 0;
}
Alexey Filippov
committed
}
// high level conditions and DC intra prediction
if( sps.getSpsRangeExtension().getIntraSmoothingDisabledFlag()
|| !isLuma( chType )
Alexey Filippov
committed
|| useISP
Alexey Filippov
committed
|| m_ipaParam.multiRefIndex
|| DC_IDX == dirMode
)
Alexey Filippov
committed
}
else if ((isLuma(chType) && pu.cu->bdpcmMode) || (!isLuma(chType) && pu.cu->bdpcmModeChroma)) // 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
{
Chia-Ming Tsai
committed
const int diff = std::min<int>( abs( predMode - HOR_IDX ), abs( predMode - VER_IDX ) );
const int log2Size = ((floorLog2(puSize.width) + floorLog2(puSize.height)) >> 1);
Alexey Filippov
committed
CHECK( log2Size >= MAX_INTRA_FILTER_DEPTHS, "Size not supported" );
filterFlag = (diff > m_aucIntraFilter[log2Size]);
Alexey Filippov
committed
}
// Selelection of either ([1 2 1] / 4 ) refrence filter OR Gaussian 4-tap interpolation filter
if (filterFlag)
{
const bool isRefFilter = isIntegerSlope(absAng);
Chia-Ming Tsai
committed
CHECK( puSize.width * puSize.height <= 32, "DCT-IF interpolation filter is always used for 4x4, 4x8, and 8x4 luma CB" );
Chia-Ming Tsai
committed
m_ipaParam.refFilterFlag = isRefFilter;
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 multiRefIdx = m_ipaParam.multiRefIndex;
Alexey Filippov
committed
const int intraPredAngle = m_ipaParam.intraPredAngle;
const int absInvAngle = m_ipaParam.absInvAngle;

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)
{
{
refAbove[x + height] = pSrc.at(x, 0);
}
refLeft[y + width] = pSrc.at(y, 1);
}
refMain = bIsModeVer ? refAbove + height : refLeft + width;
refSide = bIsModeVer ? refLeft + width : refAbove + height;
// Extend the Main reference to the left.
for (int k = -sizeSide; k <= -1; k++)
{
refMain[k] = refSide[std::min((-k * absInvAngle + 256) >> 9, sizeSide)];

Karsten Suehring
committed
}
else
{
for (int x = 0; x <= m_topRefLength + multiRefIdx; x++)
{
refAbove[x] = pSrc.at(x, 0);
}
for (int y = 0; y <= m_leftRefLength + multiRefIdx; y++)
{
refLeft[y] = pSrc.at(y, 1);
}
refMain = bIsModeVer ? refAbove : refLeft;
refSide = bIsModeVer ? refLeft : refAbove;
// Extend main reference to right using replication
const int log2Ratio = floorLog2(width) - floorLog2(height);
const int s = std::max<int>(0, bIsModeVer ? log2Ratio : -log2Ratio);
const int maxIndex = (multiRefIdx << s) + 2;
const int refLength = bIsModeVer ? m_topRefLength : m_leftRefLength;
const Pel val = refMain[refLength + multiRefIdx];
for (int z = 1; z <= maxIndex; z++)
{
refMain[refLength + multiRefIdx + z] = val;

Karsten Suehring
committed
}
// swap width/height if we are doing a horizontal mode:
if (!bIsModeVer)
{
std::swap(width, height);
}
Pel tempArray[MAX_CU_SIZE * MAX_CU_SIZE];
const int dstStride = bIsModeVer ? pDst.stride : width;
Pel * pDstBuf = bIsModeVer ? pDst.buf : tempArray;

Karsten Suehring
committed
// compensate for line offset in reference line buffers
refMain += multiRefIdx;
refSide += multiRefIdx;

Karsten Suehring
committed

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++ )
{

Karsten Suehring
committed
}
const int scale = (floorLog2(width) + floorLog2(height) - 2) >> 2;
const Pel topLeft = refMain[0];
const Pel left = refSide[1 + y];
for (int x = 0; x < std::min(3 << scale, width); x++)
{
const int wL = 32 >> (2 * x >> scale);
const Pel val = pDsty[x];
pDsty[x] = ClipPel(val + ((wL * (left - topLeft) + 32) >> 6), clpRng);
}

Karsten Suehring
committed
}

Karsten Suehring
committed
}
}
else
{
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 & 31;

Karsten Suehring
committed
Alexey Filippov
committed
if ( !isIntegerSlope( abs(intraPredAngle) ) )

Karsten Suehring
committed
{
if( isLuma(channelType) )
{
const bool useCubicFilter = !m_ipaParam.interpolationFlag;
const TFilterCoeff intraSmoothingFilter[4] = {TFilterCoeff(16 - (deltaFract >> 1)), TFilterCoeff(32 - (deltaFract >> 1)), TFilterCoeff(16 + (deltaFract >> 1)), TFilterCoeff(deltaFract >> 1)};
const TFilterCoeff* const f = (useCubicFilter) ? InterpolationFilter::getChromaFilterTable(deltaFract) : intraSmoothingFilter;
p[0] = refMain[deltaInt + x];
p[1] = refMain[deltaInt + x + 1];
p[2] = refMain[deltaInt + x + 2];
p[3] = refMain[deltaInt + x + 3];
Pel val = (f[0] * p[0] + f[1] * p[1] + f[2] * p[2] + f[3] * p[3] + 32) >> 6;
pDsty[x] = ClipPel(val, clpRng); // always clip even though not always needed

Karsten Suehring
committed
{
// Do linear filtering

Karsten Suehring
committed
{
Pel p[2];
p[0] = refMain[deltaInt + x + 1];
p[1] = refMain[deltaInt + x + 2];
pDsty[x] = p[0] + ((deltaFract * (p[1] - p[0]) + 16) >> 5);

Karsten Suehring
committed
}
}
}
else
{
// Just copy the integer samples
for( int x = 0; x < width; x++ )
{
pDsty[x] = refMain[x + deltaInt + 1];
}
}
if (m_ipaParam.applyPDPC)
{
const int scale = m_ipaParam.angularScale;
int invAngleSum = 256;
for (int x = 0; x < std::min(3 << scale, width); x++)
{
invAngleSum += absInvAngle;
int wL = 32 >> (2 * x >> scale);
Pel left = refSide[y + (invAngleSum >> 9) + 1];
pDsty[x] = pDsty[x] + ((wL * (left - pDsty[x]) + 32) >> 6);
}
}

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
void IntraPrediction::geneWeightedPred(const ComponentID compId, PelBuf &pred, const PredictionUnit &pu, Pel *srcBuf)
{
const int width = pred.width;
CHECK(width == 2, "Width of 2 is not supported");
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
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->ciipFlag)
{
return;
}
const PredictionUnit* pu = cu.firstPU;
Alexey Filippov
committed
initIntraPatternChType(cu, pu->Y());
predIntraAng(COMPONENT_Y, cu.cs->getPredBuf(*pu).Y(), *pu);
int maxCompID = 1;
if (isChromaEnabled(pu->chromaFormat))
{
maxCompID = MAX_NUM_COMPONENT;
if (pu->chromaSize().width > 2)
{
initIntraPatternChType(cu, pu->Cb());
predIntraAng(COMPONENT_Cb, cu.cs->getPredBuf(*pu).Cb(), *pu);
Alexey Filippov
committed
initIntraPatternChType(cu, pu->Cr());
predIntraAng(COMPONENT_Cr, cu.cs->getPredBuf(*pu).Cr(), *pu);
}
}
for (int currCompID = 0; currCompID < maxCompID; currCompID++)
{
if (currCompID > 0 && pu->chromaSize().width <= 2)
{
continue;
}
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
{
CHECK(area.width == 2, "Width of 2 is not supported");

Karsten Suehring
committed
const CodingStructure& cs = *cu.cs;
Alexey Filippov
committed
if (!forceRefFilterFlag)
{
initPredIntraParams(*cu.firstPU, area, *cs.sps);
}
Pel *refBufUnfiltered = m_refBuffer[area.compID][PRED_BUF_UNFILTERED];
Pel *refBufFiltered = m_refBuffer[area.compID][PRED_BUF_FILTERED];

Karsten Suehring
committed

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::initIntraPatternChTypeISP(const CodingUnit& cu, const CompArea& area, PelBuf& recBuf, const bool forceRefFilterFlag)
{
const CodingStructure& cs = *cu.cs;
if (!forceRefFilterFlag)
{
initPredIntraParams(*cu.firstPU, area, *cs.sps);
}
const Position posLT = area;
bool isLeftAvail = (cs.getCURestricted(posLT.offset(-1, 0), cu, CHANNEL_TYPE_LUMA) != NULL) && cs.isDecomp(posLT.offset(-1, 0), CHANNEL_TYPE_LUMA);
bool isAboveAvail = (cs.getCURestricted(posLT.offset(0, -1), cu, CHANNEL_TYPE_LUMA) != NULL) && cs.isDecomp(posLT.offset(0, -1), CHANNEL_TYPE_LUMA);
// ----- Step 1: unfiltered reference samples -----
if (cu.blocks[area.compID].x == area.x && cu.blocks[area.compID].y == area.y)
{
Pel *refBufUnfiltered = m_refBuffer[area.compID][PRED_BUF_UNFILTERED];
// With the first subpartition all the CU reference samples are fetched at once in a single call to xFillReferenceSamples
if (cu.ispMode == HOR_INTRA_SUBPARTITIONS)
{
m_leftRefLength = cu.Y().height << 1;
m_topRefLength = cu.Y().width + area.width;
}
else //if (cu.ispMode == VER_INTRA_SUBPARTITIONS)
{
m_leftRefLength = cu.Y().height + area.height;
m_topRefLength = cu.Y().width << 1;
}
xFillReferenceSamples(cs.picture->getRecoBuf(cu.Y()), refBufUnfiltered, cu.Y(), cu);
// After having retrieved all the CU reference samples, the number of reference samples is now adjusted for the current subpartition
m_topRefLength = cu.blocks[area.compID].width + area.width;
m_leftRefLength = cu.blocks[area.compID].height + area.height;
}
else
{
m_topRefLength = cu.blocks[area.compID].width + area.width;
m_leftRefLength = cu.blocks[area.compID].height + area.height;
const int predSizeHor = m_topRefLength;
const int predSizeVer = m_leftRefLength;
if (cu.ispMode == HOR_INTRA_SUBPARTITIONS)
{
Pel* src = recBuf.bufAt(0, -1);
Pel *ref = m_refBuffer[area.compID][PRED_BUF_UNFILTERED] + m_refBufferStride[area.compID];
if (isLeftAvail)
{
for (int i = 0; i <= 2 * cu.blocks[area.compID].height - area.height; i++)
{
ref[i] = ref[i + area.height];
}
}
else
{
for (int i = 0; i <= predSizeVer; i++)
{
ref[i] = src[0];
}
}
Pel *dst = m_refBuffer[area.compID][PRED_BUF_UNFILTERED] + 1;
dst[-1] = ref[0];
for (int i = 0; i < area.width; i++)
{
dst[i] = src[i];
}
Pel sample = src[area.width - 1];
dst += area.width;
for (int i = 0; i < predSizeHor - area.width; i++)
{
dst[i] = sample;
}
}
else
{
Pel* src = recBuf.bufAt(-1, 0);
Pel *ref = m_refBuffer[area.compID][PRED_BUF_UNFILTERED];
if (isAboveAvail)
{
for (int i = 0; i <= 2 * cu.blocks[area.compID].width - area.width; i++)
{
ref[i] = ref[i + area.width];
}
}
else
{
for (int i = 0; i <= predSizeHor; i++)
{
ref[i] = src[0];
}
}
Pel *dst = m_refBuffer[area.compID][PRED_BUF_UNFILTERED] + m_refBufferStride[area.compID] + 1;
dst[-1] = ref[0];
for (int i = 0; i < area.height; i++)
{
*dst = *src;
src += recBuf.stride;
}
Pel sample = src[-recBuf.stride];
for (int i = 0; i < predSizeVer - area.height; i++)
{
*dst = sample;
}
}
}
// ----- Step 2: filtered reference samples -----
if (m_ipaParam.refFilterFlag || forceRefFilterFlag)
{
Pel *refBufUnfiltered = m_refBuffer[area.compID][PRED_BUF_UNFILTERED];
Pel *refBufFiltered = m_refBuffer[area.compID][PRED_BUF_FILTERED];
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 predStride = predSize + 1 + multiRefIdx;
m_refBufferStride[area.compID] = predStride;

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
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
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
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) -----
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 = 0; i <= predHSize + multiRefIdx; i++)
{
ptrDst[i + predStride] = valueDC;
}

Karsten Suehring
committed
}
else if( numIntraNeighbor == totalUnits )
{
// Fill top-left border and top and top right with rec. samples
ptrSrc = srcBuf - (1 + multiRefIdx) * srcStride - (1 + multiRefIdx);
for (int j = 0; j <= predSize + multiRefIdx; j++) { ptrDst[j] = ptrSrc[j]; }
for (int i = 0; i <= predHSize + multiRefIdx; i++)
{
ptrDst[i + predStride] = ptrSrc[i * srcStride];
}

Karsten Suehring
committed
}
else // reference samples are partially available
{
// Fill top-left sample(s) if available