Coverage Report

Created: 2026-04-01 07:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vvenc/source/Lib/CommonLib/IntraPrediction.cpp
Line
Count
Source
1
/* -----------------------------------------------------------------------------
2
The copyright in this software is being made available under the Clear BSD
3
License, included below. No patent rights, trademark rights and/or 
4
other Intellectual Property Rights other than the copyrights concerning 
5
the Software are granted under this license.
6
7
The Clear BSD License
8
9
Copyright (c) 2019-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVenC Authors.
10
All rights reserved.
11
12
Redistribution and use in source and binary forms, with or without modification,
13
are permitted (subject to the limitations in the disclaimer below) provided that
14
the following conditions are met:
15
16
     * Redistributions of source code must retain the above copyright notice,
17
     this list of conditions and the following disclaimer.
18
19
     * Redistributions in binary form must reproduce the above copyright
20
     notice, this list of conditions and the following disclaimer in the
21
     documentation and/or other materials provided with the distribution.
22
23
     * Neither the name of the copyright holder nor the names of its
24
     contributors may be used to endorse or promote products derived from this
25
     software without specific prior written permission.
26
27
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
28
THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
29
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
31
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
32
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
36
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38
POSSIBILITY OF SUCH DAMAGE.
39
40
41
------------------------------------------------------------------------------------------- */
42
43
44
/** \file     Prediction.cpp
45
    \brief    prediction class
46
*/
47
48
#include "IntraPrediction.h"
49
#include "Unit.h"
50
#include "UnitTools.h"
51
#include "Rom.h"
52
#include "InterpolationFilter.h"
53
#include "dtrace_next.h"
54
55
#include <memory.h>
56
57
//! \ingroup CommonLib
58
//! \{
59
60
namespace vvenc {
61
62
// ====================================================================================================================
63
// Tables
64
// ====================================================================================================================
65
66
const uint8_t IntraPrediction::m_aucIntraFilter[MAX_INTRA_FILTER_DEPTHS] =
67
{
68
  24, //   1xn
69
  24, //   2xn
70
  24, //   4xn
71
  14, //   8xn
72
  2,  //  16xn
73
  0,  //  32xn
74
  0,  //  64xn
75
  0   // 128xn
76
};
77
78
//NOTE: Bit-Limit - 24-bit source
79
void xPredIntraPlanar_Core( PelBuf& pDst, const CPelBuf& pSrc )
80
0
{
81
0
  const uint32_t width  = pDst.width;
82
0
  const uint32_t height = pDst.height;
83
0
  const uint32_t log2W  = Log2(width);
84
0
  const uint32_t log2H  = Log2(height);
85
86
0
  int leftColumn[MAX_TB_SIZEY + 1], topRow[MAX_TB_SIZEY + 1], bottomRow[MAX_TB_SIZEY], rightColumn[MAX_TB_SIZEY];
87
0
  const uint32_t offset = 1 << (log2W + log2H);
88
89
  // Get left and above reference column and row
90
0
  for( int k = 0; k < width + 1; k++ )
91
0
  {
92
0
    topRow[k] = pSrc.at( k + 1, 0 );
93
0
  }
94
95
0
  for( int k = 0; k < height + 1; k++ )
96
0
  {
97
0
    leftColumn[k] = pSrc.at( k + 1, 1 );
98
0
  }
99
100
  // Prepare intermediate variables used in interpolation
101
0
  int bottomLeft = leftColumn[height];
102
0
  int topRight = topRow[width];
103
104
  // with some optimizations gcc-8 gives spurious "-Wmaybe-uninitialized" warnings here (says leftColumn or topRow would be uninitialized here)
105
0
  GCC_WARNING_DISABLE_maybe_uninitialized
106
0
  for( int k = 0; k < width; k++ )
107
0
  {
108
0
    bottomRow[k] = bottomLeft - topRow[k];
109
0
    topRow[k]    = topRow[k] << log2H;
110
0
  }
111
112
0
  for( int k = 0; k < height; k++ )
113
0
  {
114
0
    rightColumn[k] = topRight - leftColumn[k];
115
0
    leftColumn[k]  = leftColumn[k] << log2W;
116
0
  }
117
0
  GCC_WARNING_RESET
118
119
0
  const uint32_t finalShift = 1 + log2W + log2H;
120
0
  const uint32_t stride     = pDst.stride;
121
0
  Pel*       pred       = pDst.buf;
122
0
  for( int y = 0; y < height; y++, pred += stride )
123
0
  {
124
0
    int horPred = leftColumn[y];
125
126
0
    for( int x = 0; x < width; x++ )
127
0
    {
128
0
      horPred += rightColumn[y];
129
0
      topRow[x] += bottomRow[x];
130
131
0
      int vertPred = topRow[x];
132
0
      pred[x]      = ( ( horPred << log2H ) + ( vertPred << log2W ) + offset ) >> finalShift;
133
0
    }
134
0
  }
135
0
}
136
137
void  IntraPredSampleFilter_Core(PelBuf& dstBuf, const CPelBuf& pSrc)
138
0
{
139
0
  const int iWidth  = dstBuf.width;
140
0
  const int iHeight = dstBuf.height;
141
142
0
  const int scale = ((Log2(iWidth*iHeight) - 2) >> 2);
143
0
  CHECK(scale < 0 || scale > 31, "PDPC: scale < 0 || scale > 31");
144
145
0
  for (int y = 0; y < iHeight; y++)
146
0
  {
147
0
    const int wT   = 32 >> std::min(31, ((y << 1) >> scale));
148
0
    const Pel left = pSrc.at(y + 1, 1);
149
0
    for (int x = 0; x < iWidth; x++)
150
0
    {
151
0
      const int wL    = 32 >> std::min(31, ((x << 1) >> scale));
152
0
      const Pel top   = pSrc.at(x + 1, 0);
153
0
      const Pel val   = dstBuf.at(x, y);
154
0
      dstBuf.at(x, y) = val + ((wL * (left - val) + wT * (top - val) + 32) >> 6);
155
0
    }
156
0
  }
157
0
}
158
159
void IntraHorVerPDPC_Core(Pel* pDsty,const int dstStride,Pel* refSide,const int width,const int height,int scale,const Pel* refMain, const ClpRng& clpRng)
160
0
{
161
0
  const Pel topLeft = refMain[0];
162
163
0
  for( int y = 0; y < height; y++ )
164
0
  {
165
0
    memcpy(pDsty,&refMain[1],width*sizeof(Pel));
166
0
    const Pel left    = refSide[1 + y];
167
0
    for (int x = 0; x < std::min(3 << scale, width); x++)
168
0
    {
169
0
      const int wL  = 32 >> (2 * x >> scale);
170
0
      const Pel val = pDsty[x];
171
0
      pDsty[x]      = ClipPel(val + ((wL * (left - topLeft) + 32) >> 6), clpRng);
172
0
    }
173
0
    pDsty += dstStride;
174
0
  }
175
0
}
176
void IntraAnglePDPC_Core(Pel* pDsty,const int dstStride,Pel* refSide,const int width,const int height,int scale,int invAngle)
177
0
{
178
0
  for (int y = 0; y<height; y++, pDsty += dstStride)
179
0
  {
180
0
    int       invAngleSum = 256;
181
0
    for (int x = 0; x < std::min(3 << scale, width); x++)
182
0
    {
183
0
      invAngleSum += invAngle;
184
0
      int wL   = 32 >> (2 * x >> scale);
185
0
      Pel left = refSide[y + (invAngleSum >> 9) + 1];
186
0
      pDsty[x] = pDsty[x] + ((wL * (left - pDsty[x]) + 32) >> 6);
187
0
    }
188
0
  }
189
0
}
190
191
void IntraPredAngleLuma_Core(Pel* pDstBuf,const ptrdiff_t dstStride,Pel* refMain,int width,int height,int deltaPos,int intraPredAngle,const TFilterCoeff *ff_unused,const bool useCubicFilter,const ClpRng& clpRng)
192
0
{
193
0
  for (int y = 0; y<height; y++ )
194
0
  {
195
0
    const int deltaInt   = deltaPos >> 5;
196
0
    const int deltaFract = deltaPos & ( 32 - 1 );
197
198
0
    const TFilterCoeff      intraSmoothingFilter[4] = {TFilterCoeff(16 - (deltaFract >> 1)), TFilterCoeff(32 - (deltaFract >> 1)), TFilterCoeff(16 + (deltaFract >> 1)), TFilterCoeff(deltaFract >> 1)};
199
0
    const TFilterCoeff *f = useCubicFilter ? InterpolationFilter::getChromaFilterTable(deltaFract) : intraSmoothingFilter;
200
201
0
    Pel p[4];
202
203
0
    int refMainIndex = deltaInt + 1;
204
205
 //   const TFilterCoeff *f = &ff[deltaFract << 2];
206
207
0
    for( int x = 0; x < width; x++, refMainIndex++ )
208
0
    {
209
0
      p[0] = refMain[refMainIndex - 1];
210
0
      p[1] = refMain[refMainIndex    ];
211
0
      p[2] = refMain[refMainIndex + 1];
212
0
      p[3] = refMain[refMainIndex + 2];
213
214
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);
215
216
0
      if( useCubicFilter ) // only cubic filter has negative coefficients and requires clipping
217
0
      {
218
0
        pDstBuf[y*dstStride + x] = ClipPel( pDstBuf[y*dstStride + x], clpRng );
219
0
      }
220
0
    }
221
0
    deltaPos += intraPredAngle;
222
0
  }
223
0
}
224
225
void IntraPredAngleChroma_Core(Pel* pDstBuf,const ptrdiff_t dstStride,int16_t* pBorder,int width,int height,int deltaPos,int intraPredAngle)
226
0
{
227
0
  for (int y = 0; y<height; y++)
228
0
  {
229
0
    const int deltaInt   = deltaPos >> 5;
230
0
    const int deltaFract = deltaPos & (32 - 1);
231
232
    // Do linear filtering
233
0
    const Pel* pRM = pBorder + deltaInt + 1;
234
0
    int lastRefMainPel = *pRM++;
235
236
0
    for( int x = 0; x < width; pRM++, x++ )
237
0
    {
238
0
      int thisRefMainPel = *pRM;
239
0
      pDstBuf[x + 0] = ( Pel ) ( ( ( 32 - deltaFract )*lastRefMainPel + deltaFract*thisRefMainPel + 16 ) >> 5 );
240
0
      lastRefMainPel = thisRefMainPel;
241
0
    }
242
0
    deltaPos += intraPredAngle;
243
0
    pDstBuf += dstStride;
244
0
  }
245
0
}
246
247
// ====================================================================================================================
248
// Constructor / destructor / initialize
249
// ====================================================================================================================
250
251
IntraPrediction::IntraPrediction( bool enableOpt )
252
0
:  m_pMdlmTemp( nullptr )
253
0
,  m_currChromaFormat( NUM_CHROMA_FORMAT )
254
0
{
255
0
  IntraPredAngleLuma    = IntraPredAngleLuma_Core;
256
0
  IntraPredAngleChroma  = IntraPredAngleChroma_Core;
257
0
  IntraAnglePDPC        = IntraAnglePDPC_Core;
258
0
  IntraHorVerPDPC       = IntraHorVerPDPC_Core;
259
0
  IntraPredSampleFilter = IntraPredSampleFilter_Core;
260
0
  xPredIntraPlanar      = xPredIntraPlanar_Core;
261
262
0
#if ENABLE_SIMD_OPT_INTRAPRED
263
0
  if( enableOpt )
264
0
  {
265
0
#if defined( TARGET_SIMD_X86 )
266
0
    initIntraPredictionX86();
267
0
#endif
268
#if defined( TARGET_SIMD_ARM )
269
    initIntraPredictionARM();
270
#endif
271
0
  }
272
0
#endif // ENABLE_SIMD_OPT_INTRAPRED
273
0
}
274
275
IntraPrediction::~IntraPrediction()
276
0
{
277
0
  destroy();
278
0
}
279
280
void IntraPrediction::destroy()
281
0
{
282
0
  delete[] m_pMdlmTemp;
283
0
  m_pMdlmTemp = nullptr;
284
0
}
285
286
void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepthY)
287
0
{
288
0
  m_currChromaFormat = chromaFormatIDC;
289
290
0
  if (m_pMdlmTemp == nullptr)
291
0
  {
292
0
    m_pMdlmTemp = new Pel[(2 * MAX_TB_SIZEY + 1)*(2 * MAX_TB_SIZEY + 1)];//MDLM will use top-above and left-below samples.
293
0
  }
294
0
}
295
296
// ====================================================================================================================
297
// Public member functions
298
// ====================================================================================================================
299
300
// Function for calculating DC value of the reference samples used in Intra prediction
301
//NOTE: Bit-Limit - 25-bit source
302
Pel IntraPrediction::xGetPredValDc( const CPelBuf& pSrc, const Size& dstSize )
303
0
{
304
0
  CHECK( dstSize.width == 0 || dstSize.height == 0, "Empty area provided" );
305
306
0
  int idx, sum = 0;
307
0
  Pel dcVal;
308
0
  const int width  = dstSize.width;
309
0
  const int height = dstSize.height;
310
0
  const auto denom     = (width == height) ? (width << 1) : std::max(width,height);
311
0
  const auto divShift  = Log2(denom);
312
0
  const auto divOffset = (denom >> 1);
313
0
  const int off = m_ipaParam.multiRefIndex + 1;
314
315
316
0
  if ( width >= height )
317
0
  {
318
0
    for( idx = 0; idx < width; idx++ )
319
0
    {
320
0
      sum += pSrc.at( off + idx, 0);
321
0
    }
322
0
  }
323
0
  if ( width <= height )
324
0
  {
325
0
    for( idx = 0; idx < height; idx++ )
326
0
    {
327
0
      sum += pSrc.at( off + idx, 1);
328
0
    }
329
0
  }
330
331
0
  dcVal = (sum + divOffset) >> divShift;
332
0
  return dcVal;
333
0
}
334
335
int IntraPrediction::getWideAngle( int width, int height, int predMode )
336
0
{
337
0
  if ( predMode > DC_IDX && predMode <= VDIA_IDX )
338
0
  {
339
0
    int modeShift[] = { 0, 6, 10, 12, 14, 15 };
340
0
    int deltaSize = abs(Log2(width) - Log2(height));
341
0
    if (width > height && predMode < 2 + modeShift[deltaSize])
342
0
    {
343
0
      predMode += (VDIA_IDX - 1);
344
0
    }
345
0
    else if (height > width && predMode > VDIA_IDX - modeShift[deltaSize])
346
0
    {
347
0
      predMode -= (VDIA_IDX - 1);
348
0
    }
349
0
  }
350
0
  return predMode;
351
0
}
352
353
void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf& piPred, const CodingUnit& cu)
354
0
{
355
0
  const ComponentID    compID       = compId;
356
0
  const ChannelType    channelType  = toChannelType( compID );
357
0
  const uint32_t       uiDirMode = cu.bdpcmM[channelType] ? BDPCM_IDX : CU::getFinalIntraMode(cu, channelType);
358
359
0
  CHECK( Log2(piPred.width) > 7, "Size not allowed" );
360
361
//  const int multiRefIdx = m_ipaParam.multiRefIndex;
362
0
  const int srcStride  = m_refBufferStride[compID];
363
0
  const int srcHStride = 2;
364
365
0
  const CPelBuf& srcBuf = CPelBuf(getPredictorPtr(compID), srcStride, srcHStride);
366
0
  const ClpRng& clpRng(cu.cs->slice->clpRngs[compID]);
367
368
0
  switch (uiDirMode)
369
0
  {
370
0
    case(PLANAR_IDX): xPredIntraPlanar(piPred, srcBuf); break;
371
0
    case(DC_IDX):     xPredIntraDc    ( piPred, srcBuf ); break;
372
0
    case(BDPCM_IDX):  xPredIntraBDPCM ( piPred, srcBuf, cu.bdpcmM[channelType], clpRng); break;
373
0
    default:          xPredIntraAng   ( piPred, srcBuf, channelType, clpRng); break;
374
0
  }
375
376
0
  if (m_ipaParam.applyPDPC)
377
0
  {
378
0
    if (uiDirMode == PLANAR_IDX || uiDirMode == DC_IDX)
379
0
    {
380
0
      IntraPredSampleFilter(piPred, srcBuf);
381
0
    }
382
0
  }
383
0
}
384
385
void IntraPrediction::predIntraChromaLM(const ComponentID compID, PelBuf& piPred, const CodingUnit& cu, const CompArea& chromaArea, int intraDir)
386
0
{
387
0
  CHECK( piPred.width > MAX_TB_SIZEY || piPred.height > MAX_TB_SIZEY, "not enough memory");
388
0
  const int iLumaStride = 2 * MAX_TB_SIZEY + 1;
389
0
  PelBuf Temp = PelBuf(m_pMdlmTemp + iLumaStride + 1, iLumaStride, Size(chromaArea));
390
391
0
  int a, b, iShift;
392
0
  xGetLMParameters(cu, compID, chromaArea, a, b, iShift); // th shift result is unsigned
393
394
  ////// final prediction
395
0
  piPred.copyFrom(Temp);
396
0
  piPred.linearTransform(a, iShift, b, true, cu.cs->slice->clpRngs[compID]);
397
0
}
398
399
/** Function for deriving planar intra prediction. This function derives the prediction samples for planar mode (intra coding).
400
 */
401
402
void IntraPrediction::xPredIntraDc( PelBuf& pDst, const CPelBuf& pSrc )
403
0
{
404
0
  const Pel dcval = xGetPredValDc( pSrc, pDst );
405
0
  pDst.fill( dcval );
406
0
}
407
408
// Function for initialization of intra prediction parameters
409
void IntraPrediction::initPredIntraParams(const CodingUnit& cu, const CompArea area, const SPS& sps)
410
0
{
411
0
  const ComponentID compId = area.compID;
412
0
  const ChannelType chType = toChannelType(compId);
413
414
0
  const bool        useISP = NOT_INTRA_SUBPARTITIONS != cu.ispMode && isLuma( chType );
415
416
0
  const Size   cuSize    = Size( cu.blocks[compId].width, cu.blocks[compId].height );
417
0
  const Size   puSize    = Size( area.width, area.height );
418
0
  const Size&  blockSize = useISP ? cuSize : puSize;
419
0
  const int      dirMode = CU::getFinalIntraMode(cu, chType);
420
0
  const int     predMode = getWideAngle( blockSize.width, blockSize.height, dirMode );
421
422
0
  m_ipaParam.isModeVer            = predMode >= DIA_IDX;
423
0
  m_ipaParam.multiRefIndex        = isLuma (chType) ? cu.multiRefIdx : 0 ;
424
0
  m_ipaParam.refFilterFlag        = false;
425
0
  m_ipaParam.interpolationFlag    = false;
426
0
  m_ipaParam.applyPDPC            = (puSize.width >= MIN_TB_SIZEY && puSize.height >= MIN_TB_SIZEY) && m_ipaParam.multiRefIndex == 0;
427
428
0
  const int    intraPredAngleMode = (m_ipaParam.isModeVer) ? predMode - VER_IDX : -(predMode - HOR_IDX);
429
430
431
0
  int absAng = 0;
432
0
  if (dirMode > DC_IDX && dirMode < NUM_LUMA_MODE) // intraPredAngle for directional modes
433
0
  {
434
0
    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 };
435
0
    static const int invAngTable[32] = {
436
0
      0,   16384, 8192, 5461, 4096, 2731, 2048, 1638, 1365, 1170, 1024, 910, 819, 712, 630, 565,
437
0
      512, 468,   420,  364,  321,  287,  256,  224,  191,  161,  128,  96,  64,  48,  32,  16
438
0
    };   // (512 * 32) / Angle
439
440
0
    const int     absAngMode         = abs(intraPredAngleMode);
441
0
    const int     signAng            = intraPredAngleMode < 0 ? -1 : 1;
442
0
                  absAng             = angTable  [absAngMode];
443
444
0
    m_ipaParam.absInvAngle           = invAngTable[absAngMode];
445
0
    m_ipaParam.intraPredAngle        = signAng * absAng;
446
0
    if (intraPredAngleMode < 0)
447
0
    {
448
0
      m_ipaParam.applyPDPC = false;
449
0
    }
450
0
    else if (intraPredAngleMode > 0)
451
0
    {
452
0
      const int sideSize = m_ipaParam.isModeVer ? puSize.height : puSize.width;
453
0
      const int maxScale = 2;
454
455
0
      m_ipaParam.angularScale = std::min(maxScale, floorLog2(sideSize) - (floorLog2(3 * m_ipaParam.absInvAngle - 2) - 8));
456
0
      m_ipaParam.applyPDPC &= m_ipaParam.angularScale >= 0;
457
0
    }
458
0
  }
459
460
  // high level conditions and DC intra prediction
461
0
  if( !isLuma( chType )
462
0
    || useISP
463
0
    || CU::isMIP( cu, chType ) //th remove this
464
0
    || m_ipaParam.multiRefIndex
465
0
    || DC_IDX == dirMode
466
0
    )
467
0
  {
468
0
  }
469
0
  else if (cu.bdpcmM[chType])
470
0
  {
471
0
    m_ipaParam.refFilterFlag = false;
472
0
  }
473
0
  else if (dirMode == PLANAR_IDX) // Planar intra prediction
474
0
  {
475
0
    m_ipaParam.refFilterFlag = puSize.width * puSize.height > 32 ? true : false;
476
0
  }
477
0
  else if (!useISP)// HOR, VER and angular modes (MDIS)
478
0
  {
479
0
    bool filterFlag = false;
480
0
    {
481
0
      const int diff = std::min<int>( abs( predMode - HOR_IDX ), abs( predMode - VER_IDX ) );
482
0
      const int log2Size = (Log2(puSize.width * puSize.height) >> 1);
483
0
      CHECK( log2Size >= MAX_INTRA_FILTER_DEPTHS, "Size not supported" );
484
0
      filterFlag = (diff > m_aucIntraFilter[log2Size]);
485
0
    }
486
487
    // Selelection of either ([1 2 1] / 4 ) refrence filter OR Gaussian 4-tap interpolation filter
488
0
    if (filterFlag)
489
0
    {
490
0
      const bool isRefFilter       =  isIntegerSlope(absAng);
491
0
      CHECK( puSize.width * puSize.height <= 32, "DCT-IF interpolation filter is always used for 4x4, 4x8, and 8x4 luma CB" );
492
0
      m_ipaParam.refFilterFlag     =  isRefFilter;
493
0
      m_ipaParam.interpolationFlag = !isRefFilter;
494
0
    }
495
0
  }
496
0
}
497
498
}   // namespace vvenc
499
500
#ifdef TARGET_SIMD_X86
501
#include "x86/CommonDefX86.h"
502
#endif
503
504
namespace vvenc {
505
506
/** Function for deriving the simplified angular intra predictions.
507
*
508
* This function derives the prediction samples for the angular mode based on the prediction direction indicated by
509
* the prediction mode index. The prediction direction is given by the displacement of the bottom row of the block and
510
* the reference row above the block in the case of vertical prediction or displacement of the rightmost column
511
* of the block and reference column left from the block in the case of the horizontal prediction. The displacement
512
* is signalled at 1/32 pixel accuracy. When projection of the predicted pixel falls inbetween reference samples,
513
* the predicted value for the pixel is linearly interpolated from the reference samples. All reference samples are taken
514
* from the extended main reference.
515
*/
516
//NOTE: Bit-Limit - 25-bit source
517
518
void IntraPrediction::xPredIntraAng( PelBuf& pDst, const CPelBuf& pSrc, const ChannelType channelType, const ClpRng& clpRng)
519
0
{
520
0
  int width =int(pDst.width);
521
0
  int height=int(pDst.height);
522
523
0
  const bool bIsModeVer     = m_ipaParam.isModeVer;
524
0
  const int  multiRefIdx    = m_ipaParam.multiRefIndex;
525
0
  const int  intraPredAngle = m_ipaParam.intraPredAngle;
526
0
  const int  absInvAngle    = m_ipaParam.absInvAngle;
527
528
0
  Pel* refMain;
529
0
  Pel* refSide;
530
531
0
  Pel  refAbove[2 * MAX_CU_SIZE + 3 + 33 * MAX_REF_LINE_IDX];
532
0
  Pel  refLeft [2 * MAX_CU_SIZE + 3 + 33 * MAX_REF_LINE_IDX];
533
534
  // Initialize the Main and Left reference array.
535
0
  if (intraPredAngle < 0)
536
0
  {
537
0
    memcpy(&refAbove[height],pSrc.buf,(width + 2 + multiRefIdx)*sizeof(Pel));
538
0
    for (int y = 0; y <= height + 1 + multiRefIdx; y++)
539
0
    {
540
0
      refLeft[y + width] = pSrc.at(y, 1);
541
0
    }
542
0
    refMain = bIsModeVer ? refAbove + height : refLeft + width;
543
0
    refSide = bIsModeVer ? refLeft + width : refAbove + height;
544
545
    // Extend the Main reference to the left.
546
0
    int sizeSide = bIsModeVer ? height : width;
547
0
    for (int k = -sizeSide; k <= -1; k++)
548
0
    {
549
0
      refMain[k] = refSide[std::min((-k * absInvAngle + 256) >> 9, sizeSide)];
550
0
    }
551
0
  }
552
0
  else
553
0
  {
554
0
    memcpy(&refAbove[0], pSrc.buf, ((m_topRefLength)+multiRefIdx + 1) * sizeof(Pel));
555
0
    for (int y = 0; y <= m_leftRefLength + multiRefIdx; y++)
556
0
    {
557
0
      refLeft[y] = pSrc.at(y, 1);
558
0
    }
559
560
0
    refMain = bIsModeVer ? refAbove : refLeft;
561
0
    refSide = bIsModeVer ? refLeft : refAbove;
562
563
    // Extend main reference to right using replication
564
0
    const int log2Ratio = Log2(width) - Log2(height);
565
0
    const int s         = std::max<int>(0, bIsModeVer ? log2Ratio : -log2Ratio);
566
0
    const int maxIndex  = (multiRefIdx << s) + 2;
567
0
    const int refLength = bIsModeVer ? m_topRefLength : m_leftRefLength;
568
0
    const Pel val       = refMain[refLength + multiRefIdx];
569
0
    for (int z = 1; z <= maxIndex; z++)
570
0
    {
571
0
      refMain[refLength + multiRefIdx + z] = val;
572
0
    }
573
0
  }
574
575
  // swap width/height if we are doing a horizontal mode:
576
0
  if (!bIsModeVer)
577
0
  {
578
0
    std::swap(width, height);
579
0
  }
580
0
  Pel tempArray[MAX_CU_SIZE*MAX_CU_SIZE];
581
0
  const int dstStride = bIsModeVer ? pDst.stride : MAX_CU_SIZE;
582
0
  Pel* pDstBuf = bIsModeVer ? pDst.buf : tempArray;
583
584
  // compensate for line offset in reference line buffers
585
0
  refMain += multiRefIdx;
586
0
  refSide += multiRefIdx;
587
588
0
  Pel* pDsty = pDstBuf;
589
590
0
  if( intraPredAngle == 0 )  // pure vertical or pure horizontal
591
0
  {
592
0
    if (m_ipaParam.applyPDPC)
593
0
    {
594
0
      const int scale   = (Log2(width * height) - 2) >> 2;
595
0
      IntraHorVerPDPC(pDsty,dstStride,refSide,width,height,scale,refMain,clpRng);
596
0
    }
597
0
    else
598
0
    {
599
0
      for( int y = 0; y < height; y++ )
600
0
      {
601
0
        memcpy(pDsty,&refMain[1],width*sizeof(Pel));
602
0
        pDsty += dstStride;
603
0
      }
604
0
    }
605
0
  }
606
0
  else
607
0
  {
608
0
    if( !isIntegerSlope( abs( intraPredAngle ) ) )
609
0
    {
610
0
      int deltaPos = intraPredAngle * ( 1 + multiRefIdx );
611
0
      if( isLuma( channelType ) )
612
0
      {
613
0
        if( width <= 2 )
614
0
        {
615
0
          for( int y = 0, deltaPos = intraPredAngle * ( 1 + multiRefIdx );
616
0
               y < height;
617
0
               y++, deltaPos += intraPredAngle, pDsty += dstStride )
618
0
          {
619
0
            const int deltaInt   = deltaPos >> 5;
620
0
            const int deltaFract = deltaPos & 31;
621
622
0
            if( !isIntegerSlope( abs( intraPredAngle ) ) )
623
0
            {
624
0
              const bool useCubicFilter = !m_ipaParam.interpolationFlag;
625
626
0
              const TFilterCoeff intraSmoothingFilter[4] = { TFilterCoeff( 16 - ( deltaFract >> 1 ) ),
627
0
                                                             TFilterCoeff( 32 - ( deltaFract >> 1 ) ),
628
0
                                                             TFilterCoeff( 16 + ( deltaFract >> 1 ) ),
629
0
                                                             TFilterCoeff(      ( deltaFract >> 1 ) ) };
630
0
              const TFilterCoeff* const f =
631
0
                ( useCubicFilter ) ? InterpolationFilter::getChromaFilterTable( deltaFract ) : intraSmoothingFilter;
632
633
0
              for( int x = 0; x < width; x++ )
634
0
              {
635
0
                Pel p[4];
636
637
0
                p[0] = refMain[deltaInt + x + 0];
638
0
                p[1] = refMain[deltaInt + x + 1];
639
0
                p[2] = refMain[deltaInt + x + 2];
640
0
                p[3] = refMain[deltaInt + x + 3];
641
642
0
                Pel val = ( f[0] * p[0] + f[1] * p[1] + f[2] * p[2] + f[3] * p[3] + 32 ) >> 6;
643
644
0
                pDsty[x] = ClipPel( val, clpRng );   // always clip even though not always needed
645
0
              }
646
0
            }
647
0
          }
648
0
        }
649
0
        else
650
0
        {
651
0
          IntraPredAngleLuma(pDstBuf, dstStride, refMain, width, height, deltaPos, intraPredAngle, nullptr, !m_ipaParam.interpolationFlag, clpRng);
652
0
        }
653
0
      }
654
0
      else
655
0
      {
656
0
        IntraPredAngleChroma(pDstBuf,dstStride,refMain,width,height,deltaPos,intraPredAngle);
657
0
      }
658
0
    }
659
0
    else
660
0
    {
661
0
      for (int y = 0, deltaPos = intraPredAngle * (1 + multiRefIdx); y<height; y++, deltaPos += intraPredAngle, pDsty += dstStride)
662
0
      {
663
0
        const int deltaInt   = deltaPos >> 5;
664
        // Just copy the integer samples
665
0
        memcpy(pDsty,refMain  + deltaInt + 1,width*sizeof(Pel));
666
0
      }
667
0
    }
668
669
0
    if (m_ipaParam.applyPDPC)
670
0
    {
671
0
      pDsty = pDstBuf;
672
0
      IntraAnglePDPC(pDsty,dstStride,refSide,width,height,m_ipaParam.angularScale,absInvAngle);
673
0
    }
674
0
  } // else
675
676
  // Flip the block if this is the horizontal mode
677
0
  if( !bIsModeVer )
678
0
  {
679
0
    pDst.transposedFrom( CPelBuf( pDstBuf, dstStride, width, height) );
680
0
  }
681
0
}
682
683
void IntraPrediction::xPredIntraBDPCM(PelBuf& pDst, const CPelBuf& pSrc, const uint32_t dirMode, const ClpRng& clpRng)
684
0
{
685
0
  const int wdt = pDst.width;
686
0
  const int hgt = pDst.height;
687
688
0
  const int strideP = pDst.stride;
689
0
  const int strideS = pSrc.stride;
690
691
0
  CHECK(!(dirMode == 1 || dirMode == 2), "Incorrect BDPCM mode parameter.");
692
693
0
  Pel* pred = &pDst.buf[0];
694
0
  if (dirMode == 1)
695
0
  {
696
0
    Pel  val;
697
0
    for (int y = 0; y < hgt; y++)
698
0
    {
699
0
      val = pSrc.buf[(y + 1) + strideS];
700
0
      for (int x = 0; x < wdt; x++)
701
0
      {
702
0
        pred[x] = val;
703
0
      }
704
0
      pred += strideP;
705
0
    }
706
0
  }
707
0
  else
708
0
  {
709
0
    for (int y = 0; y < hgt; y++)
710
0
    {
711
0
      for (int x = 0; x < wdt; x++)
712
0
      {
713
0
        pred[x] = pSrc.buf[x + 1];
714
0
      }
715
0
      pred += strideP;
716
0
    }
717
0
  }
718
0
}
719
720
inline bool isAboveLeftAvailable  ( const CodingUnit &cu, const ChannelType& chType, const Position& posLT );
721
inline int  isAboveAvailable      ( const CodingUnit &cu, const ChannelType& chType, const Position& posLT, const uint32_t numUnits, const uint32_t unitWidth, bool *validFlags );
722
inline int  isLeftAvailable       ( const CodingUnit &cu, const ChannelType& chType, const Position& posLT, const uint32_t numUnits, const uint32_t unitWidth, bool *validFlags );
723
inline int  isAboveRightAvailable ( const CodingUnit &cu, const ChannelType& chType, const Position& posRT, const uint32_t numUnits, const uint32_t unitHeight, bool *validFlags );
724
inline int  isBelowLeftAvailable  ( const CodingUnit &cu, const ChannelType& chType, const Position& posLB, const uint32_t numUnits, const uint32_t unitHeight, bool *validFlags );
725
726
void IntraPrediction::initIntraPatternChType(const CodingUnit &cu, const CompArea& area, const bool forceRefFilterFlag)
727
0
{
728
0
  const CodingStructure& cs   = *cu.cs;
729
730
0
  if (!forceRefFilterFlag)
731
0
  {
732
0
    initPredIntraParams(cu, area, *cs.sps);
733
0
  }
734
735
0
  Pel *refBufUnfiltered = m_refBuffer[area.compID][PRED_BUF_UNFILTERED];
736
0
  Pel *refBufFiltered   = m_refBuffer[area.compID][PRED_BUF_FILTERED];
737
738
0
  setReferenceArrayLengths(area);
739
740
  // ----- Step 1: unfiltered reference samples -----
741
0
  xFillReferenceSamples( cs.picture->getRecoBuf( area ), refBufUnfiltered, area, cu );
742
  // ----- Step 2: filtered reference samples -----
743
0
  if( m_ipaParam.refFilterFlag || forceRefFilterFlag )
744
0
  {
745
0
    xFilterReferenceSamples( refBufUnfiltered, refBufFiltered, area, *cs.sps, cu.multiRefIdx );
746
0
  }
747
0
}
748
749
void IntraPrediction::reset()
750
0
{
751
0
  m_lastCh = MAX_NUM_CH;
752
0
  m_lastArea = Area(0,0,0,0);
753
0
}
754
755
void IntraPrediction::xFillReferenceSamples( const CPelBuf& recoBuf, Pel* refBufUnfiltered, const CompArea& area, const CodingUnit &cu )
756
0
{
757
0
  const ChannelType      chType = toChannelType( area.compID );
758
0
  const CodingStructure &cs     = *cu.cs;
759
0
  const SPS             &sps    = *cs.sps;
760
0
  const PreCalcValues   &pcv    = *cs.pcv;
761
762
0
  const int multiRefIdx         = (area.compID == COMP_Y) ? cu.multiRefIdx : 0;
763
764
0
  const int  tuWidth            = area.width;
765
0
  const int  tuHeight           = area.height;
766
0
  const int  predSize           = m_topRefLength;
767
0
  const int  predHSize          = m_leftRefLength;
768
0
  const int predStride = predSize + 1 + multiRefIdx;
769
0
  m_refBufferStride[area.compID] = predStride;
770
771
0
  const int  unitWidth          = tuWidth  <= 2 && cu.ispMode && isLuma(area.compID) ? tuWidth  : pcv.minCUSize >> getComponentScaleX(area.compID, sps.chromaFormatIdc);
772
0
  const int  unitHeight         = tuHeight <= 2 && cu.ispMode && isLuma(area.compID) ? tuHeight : pcv.minCUSize >> getComponentScaleY(area.compID, sps.chromaFormatIdc);
773
774
0
  const int  totalAboveUnits    = (predSize + (unitWidth - 1)) / unitWidth;
775
0
  const int  totalLeftUnits     = (predHSize + (unitHeight - 1)) / unitHeight;
776
0
  const int  totalUnits         = totalAboveUnits + totalLeftUnits + 1; //+1 for top-left
777
778
0
  if( m_lastArea != area || m_lastCh != chType )
779
0
  {
780
0
    m_lastCh = chType;
781
0
    m_lastArea = area;
782
0
    const int  numAboveUnits      = std::max<int>( tuWidth / unitWidth, 1 );
783
0
    const int  numLeftUnits       = std::max<int>( tuHeight / unitHeight, 1 );
784
0
    const int  numAboveRightUnits = totalAboveUnits - numAboveUnits;
785
0
    const int  numLeftBelowUnits  = totalLeftUnits - numLeftUnits;
786
787
0
    CHECK( numAboveUnits <= 0 || numLeftUnits <= 0 || numAboveRightUnits <= 0 || numLeftBelowUnits <= 0, "Size not supported" );
788
789
    // ----- Step 1: analyze neighborhood -----
790
0
    const Position posLT          = area;
791
0
    const Position posRT          = area.topRight();
792
0
    const Position posLB          = area.bottomLeft();
793
794
0
    m_numIntraNeighbor = 0;
795
796
0
    memset( m_neighborFlags, 0, totalUnits );
797
798
0
    m_neighborFlags[totalLeftUnits] = isAboveLeftAvailable( cu, chType, posLT );
799
0
    m_numIntraNeighbor += m_neighborFlags[totalLeftUnits] ? 1 : 0;
800
0
    m_numIntraNeighbor += isAboveAvailable     ( cu, chType, posLT, numAboveUnits,      unitWidth,  (m_neighborFlags + totalLeftUnits + 1) );
801
0
    m_numIntraNeighbor += isAboveRightAvailable( cu, chType, posRT, numAboveRightUnits, unitWidth,  (m_neighborFlags + totalLeftUnits + 1 + numAboveUnits) );
802
0
    m_numIntraNeighbor += isLeftAvailable      ( cu, chType, posLT, numLeftUnits,       unitHeight, (m_neighborFlags + totalLeftUnits - 1) );
803
0
    m_numIntraNeighbor += isBelowLeftAvailable ( cu, chType, posLB, numLeftBelowUnits,  unitHeight, (m_neighborFlags + totalLeftUnits - 1 - numLeftUnits) );
804
0
  }
805
  // ----- Step 2: fill reference samples (depending on neighborhood) -----
806
807
0
  const Pel*  srcBuf    = recoBuf.buf;
808
0
  const int   srcStride = recoBuf.stride;
809
0
        Pel*  ptrDst    = refBufUnfiltered;
810
0
  const Pel*  ptrSrc;
811
0
  const Pel   valueDC   = 1 << (sps.bitDepths[ chType ] - 1);
812
813
814
0
  if( m_numIntraNeighbor == 0 )
815
0
  {
816
    // Fill border with DC value
817
0
    for (int j = 0; j <= predSize + multiRefIdx; j++) { ptrDst[j] = valueDC; }
818
0
    for (int i = 0; i <= predHSize + multiRefIdx; i++) { ptrDst[i+predStride] = valueDC; }
819
0
  }
820
0
  else if( m_numIntraNeighbor == totalUnits )
821
0
  {
822
    // Fill top-left border and top and top right with rec. samples
823
0
    ptrSrc = srcBuf - (1 + multiRefIdx) * srcStride - (1 + multiRefIdx);
824
0
    for (int j = 0; j <= predSize + multiRefIdx; j++) { ptrDst[j] = ptrSrc[j]; }
825
0
    for (int i = 0; i <= predHSize + multiRefIdx; i++)
826
0
    {
827
0
      ptrDst[i + predStride] = ptrSrc[i * srcStride];
828
0
    }
829
0
  }
830
0
  else // reference samples are partially available
831
0
  {
832
    // Fill top-left sample(s) if available
833
0
    ptrSrc = srcBuf - (1 + multiRefIdx) * srcStride - (1 + multiRefIdx);
834
0
    ptrDst = refBufUnfiltered;
835
0
    if (m_neighborFlags[totalLeftUnits])
836
0
    {
837
0
      ptrDst[0] = ptrSrc[0];
838
0
      ptrDst[predStride] = ptrSrc[0];
839
0
      for (int i = 1; i <= multiRefIdx; i++)
840
0
      {
841
0
        ptrDst[i] = ptrSrc[i];
842
0
        ptrDst[i + predStride] = ptrSrc[i * srcStride];
843
0
      }
844
0
    }
845
846
    // Fill left & below-left samples if available (downwards)
847
0
    ptrSrc += (1 + multiRefIdx) * srcStride;
848
0
    ptrDst += (1 + multiRefIdx) + predStride;
849
0
    for (int unitIdx = totalLeftUnits - 1; unitIdx > 0; unitIdx--)
850
0
    {
851
0
      if (m_neighborFlags[unitIdx])
852
0
      {
853
0
        for (int i = 0; i < unitHeight; i++)
854
0
        {
855
0
          ptrDst[i] = ptrSrc[i*srcStride];
856
0
        }
857
0
      }
858
0
      ptrSrc += unitHeight * srcStride;
859
0
      ptrDst += unitHeight;
860
0
    }
861
    // Fill last below-left sample(s)
862
0
    if (m_neighborFlags[0])
863
0
    {
864
0
      int lastSample = (predHSize % unitHeight == 0) ? unitHeight : predHSize % unitHeight;
865
0
      for (int i = 0; i < lastSample; i++)
866
0
      {
867
0
        ptrDst[i] = ptrSrc[i*srcStride];
868
0
      }
869
0
    }
870
871
    // Fill above & above-right samples if available (left-to-right)
872
0
    ptrSrc = srcBuf - srcStride * (1 + multiRefIdx);
873
0
    ptrDst = refBufUnfiltered + 1 + multiRefIdx;
874
0
    for (int unitIdx = totalLeftUnits + 1; unitIdx < totalUnits - 1; unitIdx++)
875
0
    {
876
0
      if (m_neighborFlags[unitIdx])
877
0
      {
878
0
        memcpy(ptrDst,ptrSrc,unitWidth*sizeof(Pel));
879
0
      }
880
0
      ptrSrc += unitWidth;
881
0
      ptrDst += unitWidth;
882
0
    }
883
    // Fill last above-right sample(s)
884
0
    if (m_neighborFlags[totalUnits - 1])
885
0
    {
886
0
      int lastSample = (predSize % unitWidth == 0) ? unitWidth : predSize % unitWidth;
887
0
      memcpy(ptrDst,ptrSrc,lastSample*sizeof(Pel));
888
0
    }
889
890
    // pad from first available down to the last below-left
891
0
    ptrDst = refBufUnfiltered;
892
0
    int lastAvailUnit = 0;
893
0
    if (!m_neighborFlags[0])
894
0
    {
895
0
      int firstAvailUnit = 1;
896
0
      while (firstAvailUnit < totalUnits && !m_neighborFlags[firstAvailUnit])
897
0
      {
898
0
        firstAvailUnit++;
899
0
      }
900
901
      // first available sample
902
0
      int firstAvailRow = -1;
903
0
      int firstAvailCol = 0;
904
0
      if (firstAvailUnit < totalLeftUnits)
905
0
      {
906
0
        firstAvailRow = (totalLeftUnits - firstAvailUnit) * unitHeight + multiRefIdx;
907
0
      }
908
0
      else if (firstAvailUnit == totalLeftUnits)
909
0
      {
910
0
        firstAvailRow = multiRefIdx;
911
0
      }
912
0
      else
913
0
      {
914
0
        firstAvailCol = (firstAvailUnit - totalLeftUnits - 1) * unitWidth + 1 + multiRefIdx;
915
0
      }
916
0
      const Pel firstAvailSample = ptrDst[firstAvailRow < 0 ? firstAvailCol : firstAvailRow + predStride];
917
918
      // last sample below-left (n.a.)
919
0
      int lastRow = predHSize + multiRefIdx;
920
921
      // fill left column
922
0
      for (int i = lastRow; i > firstAvailRow; i--)
923
0
      {
924
0
        ptrDst[i + predStride] = firstAvailSample;
925
0
      }
926
      // fill top row
927
0
      if (firstAvailCol > 0)
928
0
      {
929
0
        for (int j = 0; j < firstAvailCol; j++)
930
0
        {
931
0
          ptrDst[j] = firstAvailSample;
932
0
        }
933
0
      }
934
0
      lastAvailUnit = firstAvailUnit;
935
0
    }
936
937
    // pad all other reference samples.
938
0
    int currUnit = lastAvailUnit + 1;
939
0
    while (currUnit < totalUnits)
940
0
    {
941
0
      if (!m_neighborFlags[currUnit]) // samples not available
942
0
      {
943
        // last available sample
944
0
        int lastAvailRow = -1;
945
0
        int lastAvailCol = 0;
946
0
        if (lastAvailUnit < totalLeftUnits)
947
0
        {
948
0
          lastAvailRow = (totalLeftUnits - lastAvailUnit - 1) * unitHeight + multiRefIdx + 1;
949
0
        }
950
0
        else if (lastAvailUnit == totalLeftUnits)
951
0
        {
952
0
          lastAvailCol = multiRefIdx;
953
0
        }
954
0
        else
955
0
        {
956
0
          lastAvailCol = (lastAvailUnit - totalLeftUnits) * unitWidth + multiRefIdx;
957
0
        }
958
0
        const Pel lastAvailSample = ptrDst[lastAvailRow < 0 ? lastAvailCol : lastAvailRow + predStride];
959
960
        // fill current unit with last available sample
961
0
        if (currUnit < totalLeftUnits)
962
0
        {
963
0
          for (int i = lastAvailRow - 1; i >= lastAvailRow - unitHeight; i--)
964
0
          {
965
0
            ptrDst[i + predStride] = lastAvailSample;
966
0
          }
967
0
        }
968
0
        else if (currUnit == totalLeftUnits)
969
0
        {
970
0
          for (int i = 0; i < multiRefIdx + 1; i++)
971
0
          {
972
0
            ptrDst[i + predStride] = lastAvailSample;
973
0
          }
974
0
          for (int j = 0; j < multiRefIdx + 1; j++)
975
0
          {
976
0
            ptrDst[j] = lastAvailSample;
977
0
          }
978
0
        }
979
0
        else
980
0
        {
981
0
          int numSamplesInUnit = (currUnit == totalUnits - 1) ? ((predSize % unitWidth == 0) ? unitWidth : predSize % unitWidth) : unitWidth;
982
0
          for (int j = lastAvailCol + 1; j <= lastAvailCol + numSamplesInUnit; j++)
983
0
          {
984
0
            ptrDst[j] = lastAvailSample;
985
0
          }
986
0
        }
987
0
      }
988
0
      lastAvailUnit = currUnit;
989
0
      currUnit++;
990
0
    }
991
0
  }
992
0
}
993
994
void IntraPrediction::xFilterReferenceSamples( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea& area, const SPS &sps
995
  , int multiRefIdx
996
  , int stride
997
)
998
0
{
999
0
  if (area.compID != COMP_Y)
1000
0
  {
1001
0
    multiRefIdx = 0;
1002
0
  }
1003
0
  const int predSize = m_topRefLength + multiRefIdx;
1004
0
  const int predHSize = m_leftRefLength + multiRefIdx;
1005
0
  const int predStride = stride == 0 ? predSize + 1 : stride;
1006
1007
1008
0
  const Pel topLeft =
1009
0
    (refBufUnfiltered[0] + refBufUnfiltered[1] + refBufUnfiltered[predStride] + refBufUnfiltered[predStride + 1] + 2)
1010
0
    >> 2;
1011
1012
0
  refBufFiltered[0] = topLeft;
1013
1014
0
  for (int i = 1; i < predSize; i++)
1015
0
  {
1016
0
    refBufFiltered[i] = (refBufUnfiltered[i - 1] + 2 * refBufUnfiltered[i] + refBufUnfiltered[i + 1] + 2) >> 2;
1017
0
  }
1018
0
  refBufFiltered[predSize] = refBufUnfiltered[predSize];
1019
1020
0
  refBufFiltered += predStride;
1021
0
  refBufUnfiltered += predStride;
1022
1023
0
  refBufFiltered[0] = topLeft;
1024
1025
0
  for (int i = 1; i < predHSize; i++)
1026
0
  {
1027
0
    refBufFiltered[i] = (refBufUnfiltered[i - 1] + 2 * refBufUnfiltered[i] + refBufUnfiltered[i + 1] + 2) >> 2;
1028
0
  }
1029
0
  refBufFiltered[predHSize] = refBufUnfiltered[predHSize];
1030
0
}
1031
1032
bool isAboveLeftAvailable(const CodingUnit &cu, const ChannelType& chType, const Position& posLT)
1033
0
{
1034
0
  const CodingStructure& cs = *cu.cs;
1035
0
  const Position refPos = posLT.offset(-1, -1);
1036
1037
0
  return (cs.getCURestricted(refPos, cu, chType) != NULL);
1038
0
}
1039
1040
int isAboveAvailable(const CodingUnit &cu, const ChannelType& chType, const Position& posLT, const uint32_t numUnits, const uint32_t unitWidth, bool *bValidFlags)
1041
0
{
1042
0
  const CodingStructure& cs = *cu.cs;
1043
1044
0
  bool *    validFlags  = bValidFlags;
1045
0
  int       numIntra    = 0;
1046
0
  const int maxDx       = numUnits * unitWidth;
1047
0
  unsigned  checkPosX   = 0;
1048
0
  bool      valid       = false;
1049
1050
0
  for (int dx = 0; dx < maxDx; dx += unitWidth)
1051
0
  {
1052
0
    if( dx >= checkPosX )
1053
0
    {
1054
0
      const Position refPos = posLT.offset(dx, -1);
1055
1056
0
      const CodingUnit* cuN = cs.getCURestricted(refPos, cu, chType);
1057
0
      valid = (cuN != NULL);
1058
0
      if( cuN ) checkPosX = chType == CH_C ? (cuN->Cb().x + cuN->Cb().width - posLT.x) : (cuN->Y().x + cuN->Y().width - posLT.x);
1059
0
      else break;
1060
0
    }
1061
1062
0
    numIntra += valid ? 1 : 0;
1063
0
    *validFlags = valid;
1064
1065
0
    validFlags++;
1066
0
  }
1067
1068
0
  return numIntra;
1069
0
}
1070
1071
int isLeftAvailable(const CodingUnit &cu, const ChannelType& chType, const Position& posLT, const uint32_t numUnits, const uint32_t unitHeight, bool *bValidFlags)
1072
0
{
1073
0
  const CodingStructure& cs = *cu.cs;
1074
1075
0
  bool *    validFlags = bValidFlags;
1076
0
  int       numIntra   = 0;
1077
0
  const int maxDy      = numUnits * unitHeight;
1078
0
  unsigned checkPosY   = 0;
1079
0
  bool     valid       = false;
1080
1081
0
  for (int dy = 0; dy < maxDy; dy += unitHeight)
1082
0
  {
1083
0
    if( dy >= checkPosY )
1084
0
    {
1085
0
      const Position refPos = posLT.offset(-1, dy);
1086
1087
0
      const CodingUnit* cuN = cs.getCURestricted(refPos, cu, chType);
1088
0
      valid = (cuN != NULL);
1089
0
      if( cuN ) checkPosY = chType == CH_C ? (cuN->Cb().y + cuN->Cb().height - posLT.y) : (cuN->Y().y + cuN->Y().height - posLT.y);
1090
0
      else break;
1091
0
    }
1092
1093
0
    numIntra += valid ? 1 : 0;
1094
0
    *validFlags = valid;
1095
1096
0
    validFlags--;
1097
0
  }
1098
1099
0
  return numIntra;
1100
0
}
1101
1102
int isAboveRightAvailable(const CodingUnit &cu, const ChannelType& chType, const Position& posRT, const uint32_t numUnits, const uint32_t unitWidth, bool *bValidFlags )
1103
0
{
1104
0
  const CodingStructure& cs = *cu.cs;
1105
1106
0
  bool *    validFlags = bValidFlags;
1107
0
  int       numIntra   = 0;
1108
0
  const int maxDx      = numUnits * unitWidth;
1109
0
  unsigned  checkPosX   = 0;
1110
0
  bool      valid       = false;
1111
1112
0
  for (int dx = 0; dx < maxDx; dx += unitWidth)
1113
0
  {
1114
0
    if( dx >= checkPosX )
1115
0
    {
1116
0
      const Position refPos = posRT.offset(unitWidth + dx, -1);
1117
1118
0
      const CodingUnit* cuN = cs.getCURestricted(refPos, cu, chType);
1119
0
      valid = (cuN != NULL);
1120
0
      if(cuN) checkPosX = chType == CH_C ? (cuN->Cb().x + cuN->Cb().width - (posRT.x + unitWidth)) : (cuN->Y().x + cuN->Y().width - (posRT.x + unitWidth));
1121
0
      else break;
1122
0
    }
1123
1124
0
    numIntra += valid ? 1 : 0;
1125
0
    *validFlags = valid;
1126
1127
0
    validFlags++;
1128
0
  }
1129
1130
0
  return numIntra;
1131
0
}
1132
1133
int isBelowLeftAvailable(const CodingUnit &cu, const ChannelType& chType, const Position& posLB, const uint32_t numUnits, const uint32_t unitHeight, bool *bValidFlags )
1134
0
{
1135
0
  const CodingStructure& cs = *cu.cs;
1136
1137
0
  bool *    validFlags = bValidFlags;
1138
0
  int       numIntra   = 0;
1139
0
  const int maxDy      = numUnits * unitHeight;
1140
0
  unsigned  checkPosY   = 0;
1141
0
  bool      valid       = false;
1142
1143
0
  for (int dy = 0; dy < maxDy; dy += unitHeight)
1144
0
  {
1145
0
    if( dy >= checkPosY )
1146
0
    {
1147
0
      const Position refPos = posLB.offset(-1, unitHeight + dy);
1148
1149
0
      const CodingUnit* cuN = cs.getCURestricted(refPos, cu, chType);
1150
0
      valid = (cuN != NULL);
1151
0
      if( cuN ) checkPosY = chType == CH_C ? (cuN->Cb().y + cuN->Cb().height - (posLB.y + unitHeight)) : (cuN->Y().y + cuN->Y().height - (posLB.y + unitHeight));
1152
0
      else break;
1153
0
    }
1154
1155
0
    numIntra += valid ? 1 : 0;
1156
0
    *validFlags = valid;
1157
1158
0
    validFlags--;
1159
0
  }
1160
1161
0
  return numIntra;
1162
0
}
1163
1164
// LumaRecPixels
1165
void IntraPrediction::loadLMLumaRecPels(const CodingUnit& cu, const CompArea& chromaArea )
1166
0
{
1167
0
  int iDstStride = 2 * MAX_TB_SIZEY + 1;
1168
0
  Pel* pDst0 = m_pMdlmTemp + iDstStride + 1;
1169
  //assert 420 chroma subsampling
1170
0
  CompArea lumaArea = CompArea( COMP_Y, cu.chromaFormat, chromaArea.lumaPos(), recalcSize( cu.chromaFormat, CH_C, CH_L, chromaArea.size() ) );//needed for correct pos/size (4x4 Tus)
1171
1172
0
  CHECK(lumaArea.width == chromaArea.width && CHROMA_444 != cu.chromaFormat, "");
1173
0
  CHECK(lumaArea.height == chromaArea.height && CHROMA_444 != cu.chromaFormat && CHROMA_422 != cu.chromaFormat, "");
1174
1175
0
  const SizeType uiCWidth = chromaArea.width;
1176
0
  const SizeType uiCHeight = chromaArea.height;
1177
1178
0
  const CPelBuf Src = cu.cs->picture->getRecoBuf( lumaArea );
1179
0
  Pel const* pRecSrc0   = Src.bufAt( 0, 0 );
1180
0
  int iRecStride        = Src.stride;
1181
0
  int logSubWidthC  = getChannelTypeScaleX(CH_C, cu.chromaFormat);
1182
0
  int logSubHeightC = getChannelTypeScaleY(CH_C, cu.chromaFormat);
1183
1184
0
  int iRecStride2       = iRecStride << logSubHeightC;
1185
1186
0
  const CompArea& area = isChroma( cu.chType ) ? chromaArea : lumaArea;
1187
1188
0
  const uint32_t uiTuWidth  = area.width;
1189
0
  const uint32_t uiTuHeight = area.height;
1190
1191
0
  const int  unitWidthLog2  = MIN_CU_LOG2 - getComponentScaleX( area.compID, area.chromaFormat );
1192
0
  const int  unitHeightLog2 = MIN_CU_LOG2 - getComponentScaleY( area.compID, area.chromaFormat );
1193
0
  const int  unitWidth  = 1<<unitWidthLog2;
1194
0
  const int  unitHeight = 1<<unitHeightLog2;
1195
1196
0
  const int  iTUWidthInUnits  = uiTuWidth >> unitWidthLog2;
1197
0
  const int  iTUHeightInUnits = uiTuHeight >> unitHeightLog2;
1198
0
  const int  iAboveUnits      = iTUWidthInUnits;
1199
0
  const int  iLeftUnits       = iTUHeightInUnits;
1200
1201
0
  const int  chromaUnitWidthLog2  = MIN_CU_LOG2 - logSubWidthC;
1202
0
  const int  chromaUnitHeightLog2 = MIN_CU_LOG2 - logSubHeightC;
1203
0
  const int  chromaUnitWidth = 1<<chromaUnitWidthLog2;
1204
0
  const int  chromaUnitHeight = 1<<chromaUnitHeightLog2;
1205
0
  const int  topTemplateSampNum = 2 * uiCWidth; // for MDLM, the number of template samples is 2W or 2H.
1206
0
  const int  leftTemplateSampNum = 2 * uiCHeight;
1207
0
  const int  totalAboveUnits = (topTemplateSampNum + (chromaUnitWidth - 1)) >> chromaUnitWidthLog2;
1208
0
  const int  totalLeftUnits = (leftTemplateSampNum + (chromaUnitHeight - 1)) >> chromaUnitHeightLog2;
1209
0
  const int  totalUnits = totalLeftUnits + totalAboveUnits + 1;
1210
0
  const int  aboveRightUnits = totalAboveUnits - iAboveUnits;
1211
0
  const int  leftBelowUnits = totalLeftUnits - iLeftUnits;
1212
1213
0
  int avaiAboveRightUnits = 0;
1214
0
  int avaiLeftBelowUnits = 0;
1215
0
  bool  bNeighborFlags[4 * MAX_NUM_PART_IDXS_IN_CTU_WIDTH + 1];
1216
0
  memset(bNeighborFlags, 0, totalUnits);
1217
0
  bool aboveIsAvailable, leftIsAvailable;
1218
0
  const ChannelType areaCh = toChannelType( area.compID );
1219
1220
0
  int availlableUnit = isLeftAvailable(cu, areaCh, area.pos(), iLeftUnits, unitHeight, (bNeighborFlags + iLeftUnits + leftBelowUnits - 1));
1221
1222
0
  leftIsAvailable = availlableUnit == iTUHeightInUnits;
1223
1224
0
  availlableUnit = isAboveAvailable(cu, areaCh, area.pos(), iAboveUnits, unitWidth, (bNeighborFlags + iLeftUnits + leftBelowUnits + 1));
1225
1226
0
  aboveIsAvailable = availlableUnit == iTUWidthInUnits;
1227
1228
0
  if (leftIsAvailable)   // if left is not available, then the below left is not available
1229
0
  {
1230
0
    avaiLeftBelowUnits = isBelowLeftAvailable(cu, areaCh, area.bottomLeftComp(area.compID), leftBelowUnits, unitHeight, (bNeighborFlags + leftBelowUnits - 1));
1231
0
  }
1232
1233
0
  if (aboveIsAvailable)   // if above is not available, then  the above right is not available.
1234
0
  {
1235
0
    avaiAboveRightUnits = isAboveRightAvailable(cu, areaCh, area.topRightComp(area.compID), aboveRightUnits, unitWidth, (bNeighborFlags + iLeftUnits + leftBelowUnits + iAboveUnits + 1));
1236
0
  }
1237
1238
0
  Pel*       pDst  = nullptr;
1239
0
  Pel const* piSrc = nullptr;
1240
1241
0
  bool isFirstRowOfCtu = (lumaArea.y & ((cu.cs->sps)->CTUSize - 1)) == 0;
1242
1243
0
  if (aboveIsAvailable)
1244
0
  {
1245
0
    pDst  = pDst0    - iDstStride;
1246
0
    int addedAboveRight = 0;
1247
0
    if ((cu.intraDir[1] == MDLM_L_IDX) || (cu.intraDir[1] == MDLM_T_IDX))
1248
0
    {
1249
0
      addedAboveRight = avaiAboveRightUnits*chromaUnitWidth;
1250
0
    }
1251
0
    for (int i = 0; i < uiCWidth + addedAboveRight; i++)
1252
0
    {
1253
0
      const bool leftPadding = i == 0 && !leftIsAvailable;
1254
0
      if (cu.chromaFormat == CHROMA_444)
1255
0
      {
1256
0
        piSrc = pRecSrc0 - iRecStride;
1257
0
        pDst[i] = piSrc[i];
1258
0
      }
1259
0
      else if (isFirstRowOfCtu)
1260
0
      {
1261
0
        piSrc   = pRecSrc0 - iRecStride;
1262
0
        pDst[i] = (piSrc[2 * i] * 2 + piSrc[2 * i - (leftPadding ? 0 : 1)] + piSrc[2 * i + 1] + 2) >> 2;
1263
0
      }
1264
0
      else if (cu.chromaFormat == CHROMA_422)
1265
0
      {
1266
0
        piSrc = pRecSrc0 - iRecStride2;
1267
1268
0
        int s = 2;
1269
0
        s += piSrc[2 * i] * 2;
1270
0
        s += piSrc[2 * i - (leftPadding ? 0 : 1)];
1271
0
        s += piSrc[2 * i + 1];
1272
0
        pDst[i] = s >> 2;
1273
0
      }
1274
0
      else if (cu.cs->sps->verCollocatedChroma )
1275
0
      {
1276
0
        piSrc = pRecSrc0 - iRecStride2;
1277
1278
0
        int s = 4;
1279
0
        s += piSrc[2 * i - iRecStride];
1280
0
        s += piSrc[2 * i] * 4;
1281
0
        s += piSrc[2 * i - (leftPadding ? 0 : 1)];
1282
0
        s += piSrc[2 * i + 1];
1283
0
        s += piSrc[2 * i + iRecStride];
1284
0
        pDst[i] = s >> 3;
1285
0
      }
1286
0
      else
1287
0
      {
1288
0
        piSrc = pRecSrc0 - iRecStride2;
1289
0
        int s = 4;
1290
0
        s += piSrc[2 * i] * 2;
1291
0
        s += piSrc[2 * i + 1];
1292
0
        s += piSrc[2 * i - (leftPadding ? 0 : 1)];
1293
0
        s += piSrc[2 * i + iRecStride] * 2;
1294
0
        s += piSrc[2 * i + 1 + iRecStride];
1295
0
        s += piSrc[2 * i + iRecStride - (leftPadding ? 0 : 1)];
1296
0
        pDst[i] = s >> 3;
1297
0
      }
1298
0
    }
1299
0
  }
1300
1301
0
  if (leftIsAvailable)
1302
0
  {
1303
0
    pDst  = pDst0    - 1;
1304
0
    piSrc = pRecSrc0 - 1 - logSubWidthC;
1305
1306
0
    int addedLeftBelow = 0;
1307
0
    if ((cu.intraDir[1] == MDLM_L_IDX) || (cu.intraDir[1] == MDLM_T_IDX))
1308
0
    {
1309
0
      addedLeftBelow = avaiLeftBelowUnits*chromaUnitHeight;
1310
0
    }
1311
1312
0
    for (int j = 0; j < uiCHeight + addedLeftBelow; j++)
1313
0
    {
1314
0
      if (cu.chromaFormat == CHROMA_444)
1315
0
      {
1316
0
        pDst[0] = piSrc[0];
1317
0
      }
1318
0
      else if (cu.chromaFormat == CHROMA_422)
1319
0
      {
1320
0
        int s = 2;
1321
0
        s += piSrc[0] * 2;
1322
0
        s += piSrc[-1];
1323
0
        s += piSrc[1];
1324
0
        pDst[0] = s >> 2;
1325
0
      }
1326
0
      else if (cu.cs->sps->verCollocatedChroma)
1327
0
      {
1328
0
        const bool abovePadding = j == 0 && !aboveIsAvailable;
1329
1330
0
        int s = 4;
1331
0
        s += piSrc[-(abovePadding ? 0 : iRecStride)];
1332
0
        s += piSrc[0] * 4;
1333
0
        s += piSrc[-1];
1334
0
        s += piSrc[1];
1335
0
        s += piSrc[iRecStride];
1336
0
        pDst[0] = s >> 3;
1337
0
      }
1338
0
      else
1339
0
      {
1340
0
        int s = 4;
1341
0
        s += piSrc[0] * 2;
1342
0
        s += piSrc[1];
1343
0
        s += piSrc[-1];
1344
0
        s += piSrc[iRecStride] * 2;
1345
0
        s += piSrc[iRecStride + 1];
1346
0
        s += piSrc[iRecStride - 1];
1347
0
        pDst[0] = s >> 3;
1348
0
      }
1349
1350
0
      piSrc += iRecStride2;
1351
0
      pDst  += iDstStride;
1352
0
    }
1353
0
  }
1354
1355
  // inner part from reconstructed picture buffer
1356
0
  for( int j = 0; j < uiCHeight; j++ )
1357
0
  {
1358
0
    for( int i = 0; i < uiCWidth; i++ )
1359
0
    {
1360
0
      if (cu.chromaFormat == CHROMA_444)
1361
0
      {
1362
0
        pDst0[i] = pRecSrc0[i];
1363
0
      }
1364
0
      else if (cu.chromaFormat == CHROMA_422)
1365
0
      {
1366
0
        const bool leftPadding  = i == 0 && !leftIsAvailable;
1367
1368
0
        int s = 2;
1369
0
        s += pRecSrc0[2 * i] * 2;
1370
0
        s += pRecSrc0[2 * i - (leftPadding ? 0 : 1)];
1371
0
        s += pRecSrc0[2 * i + 1];
1372
0
        pDst0[i] = s >> 2;
1373
0
      }
1374
0
      else if (cu.cs->sps->verCollocatedChroma)
1375
0
      {
1376
0
        const bool leftPadding  = i == 0 && !leftIsAvailable;
1377
0
        const bool abovePadding = j == 0 && !aboveIsAvailable;
1378
1379
0
        int s = 4;
1380
0
        s += pRecSrc0[2 * i - (abovePadding ? 0 : iRecStride)];
1381
0
        s += pRecSrc0[2 * i] * 4;
1382
0
        s += pRecSrc0[2 * i - (leftPadding ? 0 : 1)];
1383
0
        s += pRecSrc0[2 * i + 1];
1384
0
        s += pRecSrc0[2 * i + iRecStride];
1385
0
        pDst0[i] = s >> 3;
1386
0
      }
1387
0
      else
1388
0
      {
1389
0
        CHECK(cu.chromaFormat != CHROMA_420, "Chroma format must be 4:2:0 for vertical filtering");
1390
0
        const bool leftPadding = i == 0 && !leftIsAvailable;
1391
1392
0
        int s = 4;
1393
0
        s += pRecSrc0[2 * i] * 2;
1394
0
        s += pRecSrc0[2 * i + 1];
1395
0
        s += pRecSrc0[2 * i - (leftPadding ? 0 : 1)];
1396
0
        s += pRecSrc0[2 * i + iRecStride] * 2;
1397
0
        s += pRecSrc0[2 * i + 1 + iRecStride];
1398
0
        s += pRecSrc0[2 * i + iRecStride - (leftPadding ? 0 : 1)];
1399
0
        pDst0[i] = s >> 3;
1400
0
      }
1401
0
    }
1402
1403
0
    pDst0    += iDstStride;
1404
0
    pRecSrc0 += iRecStride2;
1405
0
  }
1406
0
}
1407
1408
void IntraPrediction::xGetLMParameters(const CodingUnit& cu, const ComponentID compID,
1409
                                              const CompArea& chromaArea,
1410
                                              int& a, int& b, int& iShift)
1411
0
{
1412
0
  CHECK(compID == COMP_Y, "");
1413
1414
0
  const SizeType cWidth  = chromaArea.width;
1415
0
  const SizeType cHeight = chromaArea.height;
1416
1417
0
  const Position posLT = chromaArea;
1418
1419
0
  CodingStructure & cs = *(cu.cs);
1420
1421
0
  const SPS &        sps           = *cs.sps;
1422
0
  const uint32_t     tuWidth     = chromaArea.width;
1423
0
  const uint32_t     tuHeight    = chromaArea.height;
1424
0
  const ChromaFormat nChromaFormat = sps.chromaFormatIdc;
1425
1426
0
  const int unitWidthLog2    = MIN_CU_LOG2 - getComponentScaleX(chromaArea.compID, nChromaFormat);
1427
0
  const int unitHeightLog2   = MIN_CU_LOG2 - getComponentScaleY(chromaArea.compID, nChromaFormat);
1428
0
  const int unitWidth    = 1<<unitWidthLog2;
1429
0
  const int unitHeight   = 1<<unitHeightLog2;
1430
1431
0
  const int tuWidthInUnits  = tuWidth >> unitWidthLog2;
1432
0
  const int tuHeightInUnits = tuHeight >> unitHeightLog2;
1433
0
  const int aboveUnits      = tuWidthInUnits;
1434
0
  const int leftUnits       = tuHeightInUnits;
1435
0
  int topTemplateSampNum = 2 * cWidth; // for MDLM, the template sample number is 2W or 2H;
1436
0
  int leftTemplateSampNum = 2 * cHeight;
1437
0
  int totalAboveUnits = (topTemplateSampNum + (unitWidth - 1)) >> unitWidthLog2;
1438
0
  int totalLeftUnits = (leftTemplateSampNum + (unitHeight - 1)) >> unitHeightLog2;
1439
0
  int totalUnits = totalLeftUnits + totalAboveUnits + 1;
1440
0
  int aboveRightUnits = totalAboveUnits - aboveUnits;
1441
0
  int leftBelowUnits = totalLeftUnits - leftUnits;
1442
0
  int avaiAboveRightUnits = 0;
1443
0
  int avaiLeftBelowUnits = 0;
1444
0
  int avaiAboveUnits = 0;
1445
0
  int avaiLeftUnits = 0;
1446
1447
0
  const int curChromaMode = cu.intraDir[1];
1448
0
  bool neighborFlags[4 * MAX_NUM_PART_IDXS_IN_CTU_WIDTH + 1];
1449
0
  memset(neighborFlags, 0, totalUnits);
1450
1451
0
  bool aboveAvailable, leftAvailable;
1452
1453
0
  int availableUnit = isAboveAvailable(cu, CH_C, posLT, aboveUnits, unitWidth,
1454
0
    (neighborFlags + leftUnits + leftBelowUnits + 1));
1455
0
  aboveAvailable = availableUnit == tuWidthInUnits;
1456
1457
0
  availableUnit = isLeftAvailable(cu, CH_C, posLT, leftUnits, unitHeight,
1458
0
    (neighborFlags + leftUnits + leftBelowUnits - 1));
1459
0
  leftAvailable = availableUnit == tuHeightInUnits;
1460
0
  if (leftAvailable) // if left is not available, then the below left is not available
1461
0
  {
1462
0
    avaiLeftUnits = tuHeightInUnits;
1463
0
    avaiLeftBelowUnits = isBelowLeftAvailable(cu, CH_C, chromaArea.bottomLeftComp(chromaArea.compID), leftBelowUnits, unitHeight, (neighborFlags + leftBelowUnits - 1));
1464
0
  }
1465
0
  if (aboveAvailable) // if above is not available, then  the above right is not available.
1466
0
  {
1467
0
    avaiAboveUnits = tuWidthInUnits;
1468
0
    avaiAboveRightUnits = isAboveRightAvailable(cu, CH_C, chromaArea.topRightComp(chromaArea.compID), aboveRightUnits, unitWidth, (neighborFlags + leftUnits + leftBelowUnits + aboveUnits + 1));
1469
0
  }
1470
1471
0
  const int srcStride = 2 * MAX_TB_SIZEY + 1;
1472
0
  Pel* srcColor0 = m_pMdlmTemp + srcStride + 1;
1473
1474
0
  Pel* curChroma0 = getPredictorPtr(compID);
1475
1476
0
  unsigned internalBitDepth = sps.bitDepths[CH_C];
1477
1478
0
  int minLuma[2] = {  MAX_INT, 0 };
1479
0
  int maxLuma[2] = { -MAX_INT, 0 };
1480
1481
0
  Pel* src = srcColor0 - srcStride;
1482
0
  int actualTopTemplateSampNum = 0;
1483
0
  int actualLeftTemplateSampNum = 0;
1484
0
  if (curChromaMode == MDLM_T_IDX)
1485
0
  {
1486
0
    leftAvailable = 0;
1487
0
    avaiAboveRightUnits = avaiAboveRightUnits > (cHeight>>unitWidthLog2) ?  cHeight>>unitWidthLog2 : avaiAboveRightUnits;
1488
0
    actualTopTemplateSampNum = unitWidth*(avaiAboveUnits + avaiAboveRightUnits);
1489
0
  }
1490
0
  else if (curChromaMode == MDLM_L_IDX)
1491
0
  {
1492
0
    aboveAvailable = 0;
1493
0
    avaiLeftBelowUnits = avaiLeftBelowUnits > (cWidth>>unitHeightLog2) ? cWidth>>unitHeightLog2 : avaiLeftBelowUnits;
1494
0
    actualLeftTemplateSampNum = unitHeight*(avaiLeftUnits + avaiLeftBelowUnits);
1495
0
  }
1496
0
  else if (curChromaMode == LM_CHROMA_IDX)
1497
0
  {
1498
0
    actualTopTemplateSampNum = cWidth;
1499
0
    actualLeftTemplateSampNum = cHeight;
1500
0
  }
1501
0
  int startPos[2]; //0:Above, 1: Left
1502
0
  int pickStep[2];
1503
1504
0
  int aboveIs4 = leftAvailable  ? 0 : 1;
1505
0
  int leftIs4 =  aboveAvailable ? 0 : 1;
1506
1507
0
  startPos[0] = actualTopTemplateSampNum >> (2 + aboveIs4);
1508
0
  pickStep[0] = std::max(1, actualTopTemplateSampNum >> (1 + aboveIs4));
1509
1510
0
  startPos[1] = actualLeftTemplateSampNum >> (2 + leftIs4);
1511
0
  pickStep[1] = std::max(1, actualLeftTemplateSampNum >> (1 + leftIs4));
1512
1513
0
  Pel selectLumaPix[4] = { 0, 0, 0, 0 };
1514
0
  Pel selectChromaPix[4] = { 0, 0, 0, 0 };
1515
1516
0
  int cntT, cntL;
1517
0
  cntT = cntL = 0;
1518
0
  int cnt = 0;
1519
0
  if (aboveAvailable)
1520
0
  {
1521
0
    cntT = std::min(actualTopTemplateSampNum, (1 + aboveIs4) << 1);
1522
0
    src = srcColor0 - srcStride;
1523
0
    const Pel *cur = curChroma0 + 1;
1524
0
    for (int pos = startPos[0]; cnt < cntT; pos += pickStep[0], cnt++)
1525
0
    {
1526
0
      selectLumaPix[cnt] = src[pos];
1527
0
      selectChromaPix[cnt] = cur[pos];
1528
0
    }
1529
0
  }
1530
1531
0
  if (leftAvailable)
1532
0
  {
1533
0
    cntL = std::min(actualLeftTemplateSampNum, ( 1 + leftIs4 ) << 1 );
1534
0
    src = srcColor0 - 1;
1535
0
    const Pel *cur = curChroma0 + m_refBufferStride[compID] + 1;
1536
0
    for (int pos = startPos[1], cnt = 0; cnt < cntL; pos += pickStep[1], cnt++)
1537
0
    {
1538
0
      selectLumaPix[cnt + cntT] = src[pos * srcStride];
1539
0
      selectChromaPix[cnt + cntT] = cur[pos];
1540
0
    }
1541
0
  }
1542
0
  cnt = cntL + cntT;
1543
1544
0
  if (cnt == 2)
1545
0
  {
1546
0
    selectLumaPix[3] = selectLumaPix[0]; selectChromaPix[3] = selectChromaPix[0];
1547
0
    selectLumaPix[2] = selectLumaPix[1]; selectChromaPix[2] = selectChromaPix[1];
1548
0
    selectLumaPix[0] = selectLumaPix[1]; selectChromaPix[0] = selectChromaPix[1];
1549
0
    selectLumaPix[1] = selectLumaPix[3]; selectChromaPix[1] = selectChromaPix[3];
1550
0
  }
1551
1552
0
  int minGrpIdx[2] = { 0, 2 };
1553
0
  int maxGrpIdx[2] = { 1, 3 };
1554
0
  int *tmpMinGrp = minGrpIdx;
1555
0
  int *tmpMaxGrp = maxGrpIdx;
1556
0
  if (selectLumaPix[tmpMinGrp[0]] > selectLumaPix[tmpMinGrp[1]]) std::swap(tmpMinGrp[0], tmpMinGrp[1]);
1557
0
  if (selectLumaPix[tmpMaxGrp[0]] > selectLumaPix[tmpMaxGrp[1]]) std::swap(tmpMaxGrp[0], tmpMaxGrp[1]);
1558
0
  if (selectLumaPix[tmpMinGrp[0]] > selectLumaPix[tmpMaxGrp[1]]) std::swap(tmpMinGrp, tmpMaxGrp);
1559
0
  if (selectLumaPix[tmpMinGrp[1]] > selectLumaPix[tmpMaxGrp[0]]) std::swap(tmpMinGrp[1], tmpMaxGrp[0]);
1560
1561
0
  minLuma[0] = (selectLumaPix[tmpMinGrp[0]] + selectLumaPix[tmpMinGrp[1]] + 1 )>>1;
1562
0
  minLuma[1] = (selectChromaPix[tmpMinGrp[0]] + selectChromaPix[tmpMinGrp[1]] + 1) >> 1;
1563
0
  maxLuma[0] = (selectLumaPix[tmpMaxGrp[0]] + selectLumaPix[tmpMaxGrp[1]] + 1 )>>1;
1564
0
  maxLuma[1] = (selectChromaPix[tmpMaxGrp[0]] + selectChromaPix[tmpMaxGrp[1]] + 1) >> 1;
1565
1566
0
  if (leftAvailable || aboveAvailable)
1567
0
  {
1568
0
    int diff = maxLuma[0] - minLuma[0];
1569
0
    if (diff > 0)
1570
0
    {
1571
0
      int diffC = maxLuma[1] - minLuma[1];
1572
0
      int x = floorLog2( diff );
1573
0
      static const uint8_t DivSigTable[1 << 4] = {
1574
        // 4bit significands - 8 ( MSB is omitted )
1575
0
        0,  7,  6,  5,  5,  4,  4,  3,  3,  2,  2,  1,  1,  1,  1,  0
1576
0
      };
1577
0
      int normDiff = (diff << 4 >> x) & 15;
1578
0
      int v = DivSigTable[normDiff] | 8;
1579
0
      x += normDiff != 0;
1580
1581
0
      int y = diffC == 0 ? 0 : floorLog2( abs( diffC ) ) + 1;
1582
0
      int add = 1 << y >> 1;
1583
0
      a = (diffC * v + add) >> y;
1584
0
      iShift = 3 + x - y;
1585
0
      if ( iShift < 1 )
1586
0
      {
1587
0
        iShift = 1;
1588
0
        a = ( (a == 0)? 0: (a < 0)? -15 : 15 );   // a=Sign(a)*15
1589
0
      }
1590
0
      b = minLuma[1] - ((a * minLuma[0]) >> iShift);
1591
0
    }
1592
0
    else
1593
0
    {
1594
0
      a = 0;
1595
0
      b = minLuma[1];
1596
0
      iShift = 0;
1597
0
    }
1598
0
  }
1599
0
  else
1600
0
  {
1601
0
    a = 0;
1602
0
    b = 1 << (internalBitDepth - 1);
1603
0
    iShift = 0;
1604
0
  }
1605
0
}
1606
1607
void IntraPrediction::initIntraMip( const CodingUnit& cu )
1608
0
{
1609
0
  CHECK( cu.lwidth() > cu.cs->sps->getMaxTbSize() || cu.lheight() > cu.cs->sps->getMaxTbSize(), "Error: block size not supported for MIP" );
1610
1611
  // prepare input (boundary) data for prediction
1612
0
  CHECK(m_ipaParam.refFilterFlag, "ERROR: unfiltered refs expected for MIP");
1613
0
  Pel *ptrSrc = getPredictorPtr(COMP_Y);
1614
0
  const int srcStride  = m_refBufferStride[COMP_Y];
1615
0
  const int srcHStride = 2;
1616
1617
0
  m_matrixIntraPred.prepareInputForPred(CPelBuf(ptrSrc, srcStride, srcHStride), cu.Y(), cu.slice->sps->bitDepths[CH_L]);
1618
0
}
1619
1620
void IntraPrediction::predIntraMip( PelBuf &piPred, const CodingUnit& cu )
1621
0
{
1622
0
  CHECK( cu.lwidth() > cu.cs->sps->getMaxTbSize() || cu.lheight() > cu.cs->sps->getMaxTbSize(), "Error: block size not supported for MIP" );
1623
0
  CHECK( cu.lwidth() != (1 << floorLog2(cu.lwidth())) || cu.lheight() != (1 << floorLog2(cu.lheight())), "Error: expecting blocks of size 2^M x 2^N" );
1624
1625
  // generate mode-specific prediction
1626
0
  const int bitDepth = cu.slice->sps->bitDepths[CH_L];
1627
1628
0
  CHECK( cu.lwidth() != piPred.stride, " no support yet" );
1629
 
1630
0
  m_matrixIntraPred.predBlock(piPred.buf, cu.intraDir[CH_L], cu.mipTransposedFlag, bitDepth);
1631
0
}
1632
1633
void IntraPrediction::initIntraPatternChTypeISP(const CodingUnit& cu, const CompArea& area, PelBuf& recBuf,
1634
  const bool forceRefFilterFlag)
1635
0
{
1636
0
  const CodingStructure& cs = *cu.cs;
1637
1638
0
  if (!forceRefFilterFlag)
1639
0
  {
1640
0
    initPredIntraParams(cu, area, *cs.sps);
1641
0
  }
1642
1643
0
  const Position posLT = area;
1644
0
  bool           isLeftAvail =
1645
0
    (cs.getCURestricted(posLT.offset(-1, 0), cu, CH_L) != NULL);
1646
0
  bool isAboveAvail =
1647
0
    (cs.getCURestricted(posLT.offset(0, -1), cu, CH_L) != NULL);
1648
  // ----- Step 1: unfiltered reference samples -----
1649
0
  if (cu.blocks[area.compID].x == area.x && cu.blocks[area.compID].y == area.y)
1650
0
  {
1651
0
    Pel* refBufUnfiltered = m_refBuffer[area.compID][PRED_BUF_UNFILTERED];
1652
    // With the first subpartition all the CU reference samples are fetched at once in a single call to
1653
    // xFillReferenceSamples
1654
0
    if (cu.ispMode == HOR_INTRA_SUBPARTITIONS)
1655
0
    {
1656
0
      m_leftRefLength = cu.Y().height << 1;
1657
0
      m_topRefLength = cu.Y().width + area.width;
1658
0
    }
1659
0
    else   // if (cu.ispMode == VER_INTRA_SUBPARTITIONS)
1660
0
    {
1661
0
      m_leftRefLength = cu.Y().height + area.height;
1662
0
      m_topRefLength = cu.Y().width << 1;
1663
0
    }
1664
1665
0
    xFillReferenceSamples(cs.picture->getRecoBuf(cu.Y()), refBufUnfiltered, cu.Y(), cu);
1666
1667
    // After having retrieved all the CU reference samples, the number of reference samples is now adjusted for the
1668
    // current subpartition
1669
0
    m_topRefLength = cu.blocks[area.compID].width + area.width;
1670
0
    m_leftRefLength = cu.blocks[area.compID].height + area.height;
1671
0
  }
1672
0
  else
1673
0
  {
1674
0
    m_topRefLength = cu.blocks[area.compID].width + area.width;
1675
0
    m_leftRefLength = cu.blocks[area.compID].height + area.height;
1676
1677
0
    const int predSizeHor = m_topRefLength;
1678
0
    const int predSizeVer = m_leftRefLength;
1679
0
    if (cu.ispMode == HOR_INTRA_SUBPARTITIONS)
1680
0
    {
1681
0
      Pel* src = recBuf.bufAt(0, -1);
1682
0
      Pel* ref = m_refBuffer[area.compID][PRED_BUF_UNFILTERED] + m_refBufferStride[area.compID];
1683
0
      if (isLeftAvail)
1684
0
      {
1685
0
        for (int i = 0; i <= 2 * cu.blocks[area.compID].height - area.height; i++)
1686
0
        {
1687
0
          ref[i] = ref[i + area.height];
1688
0
        }
1689
0
      }
1690
0
      else
1691
0
      {
1692
0
        for (int i = 0; i <= predSizeVer; i++)
1693
0
        {
1694
0
          ref[i] = src[0];
1695
0
        }
1696
0
      }
1697
0
      Pel* dst = m_refBuffer[area.compID][PRED_BUF_UNFILTERED] + 1;
1698
0
      dst[-1] = ref[0];
1699
0
      for (int i = 0; i < area.width; i++)
1700
0
      {
1701
0
        dst[i] = src[i];
1702
0
      }
1703
0
      Pel sample = src[area.width - 1];
1704
0
      dst += area.width;
1705
0
      for (int i = 0; i < predSizeHor - area.width; i++)
1706
0
      {
1707
0
        dst[i] = sample;
1708
0
      }
1709
0
    }
1710
0
    else
1711
0
    {
1712
0
      Pel* src = recBuf.bufAt(-1, 0);
1713
0
      Pel* ref = m_refBuffer[area.compID][PRED_BUF_UNFILTERED];
1714
0
      if (isAboveAvail)
1715
0
      {
1716
0
        for (int i = 0; i <= 2 * cu.blocks[area.compID].width - area.width; i++)
1717
0
        {
1718
0
          ref[i] = ref[i + area.width];
1719
0
        }
1720
0
      }
1721
0
      else
1722
0
      {
1723
0
        for (int i = 0; i <= predSizeHor; i++)
1724
0
        {
1725
0
          ref[i] = src[0];
1726
0
        }
1727
0
      }
1728
0
      Pel* dst = m_refBuffer[area.compID][PRED_BUF_UNFILTERED] + m_refBufferStride[area.compID] + 1;
1729
0
      dst[-1] = ref[0];
1730
0
      for (int i = 0; i < area.height; i++)
1731
0
      {
1732
0
        *dst = *src;
1733
0
        src += recBuf.stride;
1734
0
        dst++;
1735
0
      }
1736
0
      Pel sample = src[-recBuf.stride];
1737
0
      for (int i = 0; i < predSizeVer - area.height; i++)
1738
0
      {
1739
0
        *dst = sample;
1740
0
        dst++;
1741
0
      }
1742
0
    }
1743
0
  }
1744
  // ----- Step 2: filtered reference samples -----
1745
0
  if (m_ipaParam.refFilterFlag || forceRefFilterFlag)
1746
0
  {
1747
0
    Pel* refBufUnfiltered = m_refBuffer[area.compID][PRED_BUF_UNFILTERED];
1748
0
    Pel* refBufFiltered = m_refBuffer[area.compID][PRED_BUF_FILTERED];
1749
0
    xFilterReferenceSamples(refBufUnfiltered, refBufFiltered, area, *cs.sps, cu.multiRefIdx);
1750
0
  }
1751
0
}
1752
1753
void IntraPrediction::setReferenceArrayLengths(const CompArea& area)
1754
0
{
1755
  // set Top and Left reference samples length
1756
0
  const int width = area.width;
1757
0
  const int height = area.height;
1758
1759
0
  m_leftRefLength = (height << 1);
1760
0
  m_topRefLength = (width << 1);
1761
0
}
1762
1763
} // namespace vvenc
1764
1765
//! \}
1766