Coverage Report

Created: 2026-07-25 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vvdec/source/Lib/CommonLib/MatrixIntraPrediction.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) 2018-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVdeC 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
/** \file     MatrixIntraPrediction.cpp
44
\brief    matrix-based intra prediction class
45
*/
46
47
#include "MatrixIntraPrediction.h"
48
#include "dtrace_next.h"
49
50
#include "UnitTools.h"
51
#include "MipData.h"
52
53
namespace vvdec
54
{
55
56
namespace Mip
57
{
58
  PredictorMIP::PredictorMIP():
59
59.8k
    m_blockSize( 0, 0 ),
60
59.8k
    m_sizeId( 0 ),
61
59.8k
    m_reducedBdrySize( 0 ),
62
59.8k
    m_reducedPredSize( 0 ),
63
59.8k
    m_upsmpFactorHor( 0 ),
64
59.8k
    m_upsmpFactorVer( 0 )
65
59.8k
  {
66
59.8k
  }
67
68
  void PredictorMIP::deriveBoundaryData(const CPelBuf& src, const Area& block, const int bitDepth)
69
2.68k
  {
70
    // Step 1: Save block size and calculate dependent values
71
2.68k
    initPredBlockParams(block);
72
  
73
    // Step 2: Get the input data (left and top reference samples)
74
    //    m_refSamplesTop.resize(block.width);
75
65.9k
    for (int x = 0; x < block.width; x++)
76
63.2k
    {
77
63.2k
      m_refSamplesTop[x] = src.at(x + 1, 0);
78
63.2k
    }
79
  
80
    //    m_refSamplesLeft.resize(block.height);
81
60.4k
    for (int y = 0; y < block.height; y++)
82
57.7k
    {
83
57.7k
      m_refSamplesLeft[y] = src.at(0, y + 1);
84
57.7k
    }
85
  
86
    // Step 3: Compute the reduced boundary via Haar-downsampling (input for the prediction)
87
    //    m_reducedBoundary          .resize( m_reducedBoundarySize.width + m_reducedBoundarySize.height );
88
    //    m_reducedBoundaryTransposed.resize( m_reducedBoundarySize.width + m_reducedBoundarySize.height );
89
  
90
    //    m_reducedBoundary          .resize( inputSize );
91
    //    m_reducedBoundaryTransposed.resize( inputSize );
92
  
93
2.68k
    Pel* const topReduced = m_reducedBoundary;
94
2.68k
    boundaryDownsampling1D( topReduced, m_refSamplesTop, block.width, m_reducedBdrySize );
95
  
96
2.68k
    Pel* const leftReduced = m_reducedBoundary + m_reducedBdrySize;
97
2.68k
    boundaryDownsampling1D( leftReduced, m_refSamplesLeft, block.height, m_reducedBdrySize );
98
  
99
2.68k
    Pel* const leftReducedTransposed = m_reducedBoundaryTransposed;
100
2.68k
    Pel* const topReducedTransposed  = m_reducedBoundaryTransposed + m_reducedBdrySize;
101
13.3k
    for( int x = 0; x < m_reducedBdrySize; x++ )
102
10.6k
    {
103
10.6k
      topReducedTransposed[x] = topReduced[x];
104
10.6k
    }
105
13.3k
    for( int y = 0; y < m_reducedBdrySize; y++ )
106
10.6k
    {
107
10.6k
      leftReducedTransposed[y] = leftReduced[y];
108
10.6k
    }
109
110
  // Step 4: Rebase the reduced boundary
111
2.68k
    const int inputSize = 2 * m_reducedBdrySize;
112
  
113
2.68k
    m_inputOffset       = m_reducedBoundary[0];
114
2.68k
    m_inputOffsetTransp = m_reducedBoundaryTransposed[0];
115
  
116
2.68k
    const bool hasFirstCol = (m_sizeId < 2);
117
2.68k
    m_reducedBoundary          [0] = hasFirstCol ? ((1 << (bitDepth - 1)) - m_inputOffset      ) : 0; // first column of matrix not needed for large blocks
118
2.68k
    m_reducedBoundaryTransposed[0] = hasFirstCol ? ((1 << (bitDepth - 1)) - m_inputOffsetTransp) : 0;
119
21.2k
    for (int i = 1; i < inputSize; i++)
120
18.5k
    {
121
18.5k
      m_reducedBoundary          [i] -= m_inputOffset;
122
18.5k
      m_reducedBoundaryTransposed[i] -= m_inputOffsetTransp;
123
18.5k
    }
124
2.68k
  }
125
126
  void PredictorMIP::getPrediction(Pel* const result, const int modeIdx, const bool transpose, const int bitDepth)
127
2.68k
  {
128
2.68k
    const bool needUpsampling = ( m_upsmpFactorHor > 1 ) || ( m_upsmpFactorVer > 1 );
129
130
2.68k
    const uint8_t* matrix = getMatrixData( modeIdx );
131
132
2.68k
    Pel bufReducedPred[MIP_MAX_REDUCED_OUTPUT_SAMPLES];
133
2.68k
    Pel* const       reducedPred     = needUpsampling ? bufReducedPred : result;
134
2.68k
    const Pel* const reducedBoundary = transpose ? m_reducedBoundaryTransposed : m_reducedBoundary;
135
2.68k
    computeReducedPred( reducedPred, reducedBoundary, matrix, transpose, bitDepth );
136
2.68k
    if( needUpsampling )
137
2.63k
    {
138
2.63k
      predictionUpsampling( result, reducedPred );
139
2.63k
    }
140
2.68k
  }
141
142
143
  void PredictorMIP::initPredBlockParams(const Size& block)
144
2.68k
  {
145
2.68k
    m_blockSize = block;
146
    // init size index
147
2.68k
    m_sizeId = getMipSizeId( m_blockSize );
148
149
    // init reduced boundary size
150
2.68k
    m_reducedBdrySize = (m_sizeId == 0) ? 2 : 4;
151
152
    // init reduced prediction size
153
2.68k
    m_reducedPredSize = ( m_sizeId < 2 ) ? 4 : 8;
154
155
156
    // init upsampling factors
157
2.68k
    m_upsmpFactorHor = m_blockSize.width  / m_reducedPredSize;
158
2.68k
    m_upsmpFactorVer = m_blockSize.height / m_reducedPredSize;
159
160
2.68k
    CHECKD( (m_upsmpFactorHor < 1) || ((m_upsmpFactorHor & (m_upsmpFactorHor - 1)) != 0), "Need power of two horizontal upsampling factor." );
161
2.68k
    CHECKD( (m_upsmpFactorVer < 1) || ((m_upsmpFactorVer & (m_upsmpFactorVer - 1)) != 0), "Need power of two vertical upsampling factor." );
162
2.68k
  }
163
164
165
166
void PredictorMIP::boundaryDownsampling1D(Pel* reducedDst, const Pel* const fullSrc, const SizeType srcLen, const SizeType dstLen)
167
5.36k
{
168
5.36k
  if (dstLen < srcLen)
169
5.17k
  {
170
    // Create reduced boundary by downsampling
171
5.17k
      const SizeType downsmpFactor = srcLen / dstLen;
172
5.17k
      const int log2DownsmpFactor = getLog2(downsmpFactor);
173
5.17k
      const int roundingOffset = (1 << (log2DownsmpFactor - 1));
174
175
5.17k
      SizeType srcIdx = 0;
176
25.6k
      for( SizeType dstIdx = 0; dstIdx < dstLen; dstIdx++ )
177
20.4k
      {
178
20.4k
        int sum = 0;
179
140k
        for( int k = 0; k < downsmpFactor; k++ )
180
120k
        {
181
120k
          sum += fullSrc[srcIdx++];
182
120k
        }
183
20.4k
        reducedDst[dstIdx] = (sum + roundingOffset) >> log2DownsmpFactor;
184
20.4k
      }
185
5.17k
  }
186
195
  else
187
195
  {
188
195
    memcpy( reducedDst, fullSrc, dstLen * sizeof( Pel ) );
189
195
  }
190
5.36k
}
191
192
193
  void PredictorMIP::predictionUpsampling1D( Pel* const dst, const Pel* const src, const Pel* const bndry,
194
                                              const SizeType srcSizeUpsmpDim, const SizeType srcSizeOrthDim,
195
                                              const SizeType srcStep, const SizeType srcStride,
196
                                              const SizeType dstStep, const SizeType dstStride,
197
                                              const SizeType bndryStep,
198
                                              const unsigned int upsmpFactor )
199
4.12k
  {
200
4.12k
    const Pel log2UpsmpFactor = getLog2( upsmpFactor );
201
4.12k
    CHECKD( upsmpFactor <= 1, "Upsampling factor must be at least 2." );
202
4.12k
    const int roundingOffset = 1 << ( log2UpsmpFactor - 1 );
203
204
4.12k
    const Pel* srcLine   = src;
205
4.12k
          Pel* dstLine   = dst;
206
4.12k
    const Pel* bndryLine = bndry + bndryStep - 1;
207
208
69.8k
    for( int k = 0; k < srcSizeOrthDim; k++ )
209
65.7k
    {
210
65.7k
      const Pel* before  = bndryLine;
211
65.7k
      const Pel* behind  = srcLine;
212
65.7k
            Pel* currDst = dstLine;
213
214
577k
      for( int j = 0; j < srcSizeUpsmpDim; j++ )
215
511k
      {
216
511k
        Pel valBehind = *behind;
217
511k
        Pel valBefore = *before;
218
511k
        Pel valDiff   = valBehind - valBefore;
219
511k
        Pel scaledVal = valBefore * ( 1 << log2UpsmpFactor ) + roundingOffset;
220
221
2.98M
        for( int i = 0; i < upsmpFactor; i++ )
222
2.47M
        {
223
2.47M
          scaledVal += valDiff;
224
2.47M
          *currDst   = scaledVal >> log2UpsmpFactor;
225
2.47M
          currDst   += dstStep;
226
2.47M
        }
227
228
511k
        before  = behind;
229
511k
        behind += srcStep;
230
511k
      }
231
232
65.7k
      srcLine   += srcStride;
233
65.7k
      dstLine   += dstStride;
234
65.7k
      bndryLine += bndryStep;
235
65.7k
    }
236
4.12k
  }
237
238
239
  void PredictorMIP::predictionUpsampling( Pel* const dst, const Pel* const src ) const
240
2.63k
  {
241
2.63k
    const Pel* verSrc     = src;
242
2.63k
    SizeType   verSrcStep = m_blockSize.width;
243
  
244
2.63k
    if( m_upsmpFactorHor > 1 )
245
2.30k
    {
246
2.30k
      Pel* const horDst = dst + (m_upsmpFactorVer - 1) * m_blockSize.width;
247
2.30k
      verSrc = horDst;
248
2.30k
      verSrcStep *= m_upsmpFactorVer;
249
  
250
2.30k
      predictionUpsampling1D( horDst, src, m_refSamplesLeft,
251
2.30k
                              m_reducedPredSize, m_reducedPredSize,
252
2.30k
                              1, m_reducedPredSize, 1, verSrcStep,
253
2.30k
                              m_upsmpFactorVer, m_upsmpFactorHor );
254
2.30k
    }
255
  
256
2.63k
    if( m_upsmpFactorVer > 1 )
257
1.82k
    {
258
1.82k
      predictionUpsampling1D( dst, verSrc, m_refSamplesTop,
259
1.82k
                              m_reducedPredSize, m_blockSize.width,
260
1.82k
                              verSrcStep, 1, m_blockSize.width, 1,
261
1.82k
                              1, m_upsmpFactorVer );
262
1.82k
    }
263
2.63k
  }
264
265
  const uint8_t* PredictorMIP::getMatrixData(const int modeIdx) const
266
2.68k
  {
267
2.68k
      switch( m_sizeId )
268
2.68k
      {
269
48
        case 0: return &mipMatrix4x4[modeIdx][0][0];
270
271
421
        case 1: return &mipMatrix8x8[modeIdx][0][0];
272
273
2.21k
        case 2: return &mipMatrix16x16[modeIdx][0][0];
274
275
0
        default: THROW_FATAL( "Invalid mipSizeId" );
276
2.68k
      }
277
2.68k
  }
278
279
  void PredictorMIP::computeReducedPred( Pel* const result, const Pel* const input, const uint8_t* matrix, const bool transpose, const int bitDepth )
280
2.68k
  {
281
2.68k
    const int inputSize = 2 * m_reducedBdrySize;
282
283
    // use local buffer for transposed result
284
2.68k
    Pel        resBufTransposed[MIP_MAX_REDUCED_OUTPUT_SAMPLES];
285
2.68k
    Pel* const resPtr = ( transpose ) ? resBufTransposed : result;
286
287
2.68k
    int sum = 0;
288
23.9k
    for( int i = 0; i < inputSize; i++ )
289
21.2k
    {
290
21.2k
      sum += input[i];
291
21.2k
    }
292
2.68k
    const int offset = ( 1 << ( MIP_SHIFT_MATRIX - 1 ) ) - MIP_OFFSET_MATRIX * sum;
293
2.68k
    CHECK( inputSize != 4 * ( inputSize >> 2 ), "Error, input size not divisible by four" );
294
295
2.68k
    const uint8_t* weight      = matrix;
296
2.68k
    const int      inputOffset = transpose ? m_inputOffsetTransp : m_inputOffset;
297
298
2.68k
    const bool redSize = ( m_sizeId == 2 );
299
2.68k
    int        posRes  = 0;
300
22.2k
    for( int y = 0; y < m_reducedPredSize; y++ )
301
19.5k
    {
302
168k
      for( int x = 0; x < m_reducedPredSize; x++ )
303
149k
      {
304
149k
        int tmp0 = redSize ? 0 : ( input[0] * weight[0] );
305
149k
        int tmp1 = input[1] * weight[1 - redSize];
306
149k
        int tmp2 = input[2] * weight[2 - redSize];
307
149k
        int tmp3 = input[3] * weight[3 - redSize];
308
297k
        for( int i = 4; i < inputSize; i += 4 )
309
148k
        {
310
148k
          tmp0 += input[i    ] * weight[i     - redSize];
311
148k
          tmp1 += input[i + 1] * weight[i + 1 - redSize];
312
148k
          tmp2 += input[i + 2] * weight[i + 2 - redSize];
313
148k
          tmp3 += input[i + 3] * weight[i + 3 - redSize];
314
148k
        }
315
149k
        resPtr[posRes++] = ClipBD<int>( ( ( tmp0 + tmp1 + tmp2 + tmp3 + offset ) >> MIP_SHIFT_MATRIX ) + inputOffset, bitDepth );
316
317
149k
        weight += inputSize - redSize;
318
149k
      }
319
19.5k
    }
320
321
2.68k
    if( transpose )
322
1.12k
    {
323
9.24k
      for( int y = 0; y < m_reducedPredSize; y++ )
324
8.11k
      {
325
69.5k
        for( int x = 0; x < m_reducedPredSize; x++ )
326
61.3k
        {
327
61.3k
          result[y * m_reducedPredSize + x] = resPtr[x * m_reducedPredSize + y];
328
61.3k
        }
329
8.11k
      }
330
1.12k
    }
331
2.68k
  }
332
}   // namespace Mip
333
334
MatrixIntraPrediction::MatrixIntraPrediction()
335
59.8k
{
336
59.8k
}
337
338
void MatrixIntraPrediction::prepareInputForPred(const CPelBuf &src, const Area& puArea, const int bitDepth, const ComponentID compId)
339
2.68k
{
340
2.68k
  m_component = compId;
341
342
2.68k
  m_predictorMip.deriveBoundaryData(src, puArea, bitDepth);
343
2.68k
}
344
345
void MatrixIntraPrediction::predBlock( const Size &puSize, const int intraMode, PelBuf& dst, const bool transpose, const int bitDepth, const ComponentID compId, Pel* const resultMip )
346
2.68k
{
347
2.68k
  CHECK( m_component != compId, "Boundary has not been prepared for this component." );
348
349
2.68k
  m_predictorMip.getPrediction( resultMip, intraMode, transpose, bitDepth );
350
351
60.4k
  for( int y = 0; y < puSize.height; y++ )
352
57.7k
  {
353
57.7k
    Pel* const resultLine = &resultMip[y * puSize.width];
354
57.7k
    Pel*       dstLine    = dst.bufAt( 0, y );
355
356
586k
    for( int x = 0; x < puSize.width; x += 4 )
357
528k
    {
358
528k
      dstLine[x + 0] = Pel( resultLine[x + 0] );
359
528k
      dstLine[x + 1] = Pel( resultLine[x + 1] );
360
528k
      dstLine[x + 2] = Pel( resultLine[x + 2] );
361
528k
      dstLine[x + 3] = Pel( resultLine[x + 3] );
362
528k
    }
363
57.7k
  }
364
2.68k
}
365
366
}