MatrixIntraPrediction.cpp 28.8 KB
Newer Older
1
2
3
4
5
6
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
/* The copyright in this software is being made available under the BSD
* License, included below. This software may be subject to other third party
* and contributor rights, including patent rights, and no such rights are
* granted under this license.
*
* Copyright (c) 2010-2019, ITU/ISO/IEC
* 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     MatrixIntraPrediction.cpp
\brief    matrix-based intra prediction class
*/

#include "MatrixIntraPrediction.h"
#include "dtrace_next.h"

#include "UnitTools.h"
#include "MipData.h"


45
namespace Mip
46
47
48
49
{
  PredictorMIP::PredictorMIP():
    m_reducedBoundary          (MIP_MAX_INPUT_SIZE),
    m_reducedBoundaryTransposed(MIP_MAX_INPUT_SIZE),
50
51
52
53
54
55
#if JVET_O0925_MIP_SIMPLIFICATIONS
    m_inputOffset      ( 0 ),
    m_inputOffsetTransp( 0 ),
    m_refSamplesTop (MIP_MAX_WIDTH),
    m_refSamplesLeft(MIP_MAX_HEIGHT),
#else
56
57
    m_boundaryForUpsamplingTop (MIP_MAX_WIDTH),
    m_boundaryForUpsamplingLeft(MIP_MAX_HEIGHT),
58
#endif
59
60
61
62
    m_blockSize( 0, 0 ),
    m_numModes( 0 ),
    m_reducedBoundarySize( 0, 0 ),
    m_reducedPredictionSize( 0, 0 ),
63
#if !JVET_O0925_MIP_SIMPLIFICATIONS
64
    m_boundarySizeForUpsampling( 0, 0 ),
65
#endif
66
67
68
69
70
71
    m_upsmpFactorHor( 0 ),
    m_upsmpFactorVer( 0 )
  {
  }


72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#if JVET_O0925_MIP_SIMPLIFICATIONS
  void PredictorMIP::deriveBoundaryData(const CPelBuf &pSrc, const Area& block, const int bitDepth)
  {
    // Step 1: Save block size and calculate dependent values
    initPredBlockParams(block);

    // Step 2: Get the input data (left and top reference samples)
    m_refSamplesTop.resize(block.width);
    for (int x = 0; x < block.width; x++)
    {
      m_refSamplesTop[x] = pSrc.at(x + 1, 0);
    }

    m_refSamplesLeft.resize(block.height);
    for (int y = 0; y < block.height; y++)
    {
      m_refSamplesLeft[y] = pSrc.at(0, y + 1);
    }

    // Step 3: Compute the reduced boundary via Haar-downsampling (input for the prediction)
    m_reducedBoundary          .resize( m_reducedBoundarySize.width + m_reducedBoundarySize.height );
    m_reducedBoundaryTransposed.resize( m_reducedBoundarySize.width + m_reducedBoundarySize.height );

    int* const topReduced = m_reducedBoundary.data();
    boundaryDownsampling1D(topReduced, m_refSamplesTop.data(), block.width, m_reducedBoundarySize.width);

    int* const leftReduced = m_reducedBoundary.data() + m_reducedBoundarySize.width;
    boundaryDownsampling1D(leftReduced, m_refSamplesLeft.data(), block.height, m_reducedBoundarySize.height);

    int* const leftReducedTransposed = m_reducedBoundaryTransposed.data();
    int* const topReducedTransposed  = m_reducedBoundaryTransposed.data() + m_reducedBoundarySize.height;
    for( int x = 0; x < m_reducedBoundarySize.width; x++ )
    {
      topReducedTransposed[ x ] = topReduced[ x ];
    }
    for( int y = 0; y < m_reducedBoundarySize.height; y++ )
    {
      leftReducedTransposed[ y ] = leftReduced[ y ];
    }

    // Step 4: Rebase the reduced boundary
    const int inputSize = m_reducedBoundarySize.width + m_reducedBoundarySize.height;

    m_inputOffset       = m_reducedBoundary[0];
    m_inputOffsetTransp = m_reducedBoundaryTransposed[0];

    const bool hasFirstCol = (m_blockSize.width <= 8 && m_blockSize.height <= 8);
    m_reducedBoundary          [0] = hasFirstCol ? (m_inputOffset       - (1 << (bitDepth - 1))) : 0; // first column of matrix not needed for large blocks
    m_reducedBoundaryTransposed[0] = hasFirstCol ? (m_inputOffsetTransp - (1 << (bitDepth - 1))) : 0;
    for (int i = 1; i < inputSize; i++)
    {
      m_reducedBoundary          [i] -= m_inputOffset;
      m_reducedBoundaryTransposed[i] -= m_inputOffsetTransp;
    }
  }
#else
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  void PredictorMIP::deriveBoundaryData(const CPelBuf& src, const Area& block, const int bitDepth, const AvailableInfo &availInfo)
  {
    // Step 1: Save block size and calculate dependent values
    initPredBlockParams(block);

    // Step 2: Get the input data (left and top reference samples)
    const int defaultPad = int(1 << (bitDepth - 1));

    // TOP (save top boundary since we might need it for upsampling)
    m_boundaryForUpsamplingTop.resize( block.width );
    const int availPosTop = availInfo.maxPosTop;
    CHECKD(availPosTop > block.width, "Error: availPosTop out of range");

    if (availPosTop > 0)
    {
      // top available
      const Position posT0(block.x, block.y - 1);
      for (int x = 0; x < availPosTop; x++)
      {
        m_boundaryForUpsamplingTop[ x ] = src.at( posT0.offset( x, 0 ) );
      }
      // top unavailable
      const int padVal = m_boundaryForUpsamplingTop[ availPosTop - 1 ];
      for( int x = availPosTop; x < m_boundaryForUpsamplingTop.size(); x++ )
      {
        m_boundaryForUpsamplingTop[ x ] = padVal;
      }
    }
    else
    {
      std::fill( m_boundaryForUpsamplingTop.begin(), m_boundaryForUpsamplingTop.end(), defaultPad );
    }

    // LEFT (save left boundary since we might need it for upsampling)
    m_boundaryForUpsamplingLeft.resize( block.height );
    const int availPosLeft = availInfo.maxPosLeft;
    CHECKD(availPosLeft > block.height, "Error: availPosLeft out of range");

    if (availPosLeft > 0)
    {
      // left available
      const Position posL0(block.x - 1, block.y);
      for (int y = 0; y < availPosLeft; y++)
      {
        m_boundaryForUpsamplingLeft[ y ] = src.at( posL0.offset( 0, y ) );
      }
      // left unavailable
      const int padVal = m_boundaryForUpsamplingLeft[ availPosLeft - 1 ];
      for( int y = availPosLeft; y < m_boundaryForUpsamplingLeft.size(); y++ )
      {
        m_boundaryForUpsamplingLeft[ y ] = padVal;
      }
    }
    else
    {
      std::fill( m_boundaryForUpsamplingLeft.begin(), m_boundaryForUpsamplingLeft.end(), defaultPad );
    }

    // Step 3: Compute the reduced boundary via Haar-downsampling (input for the prediction and intermediate boundary for upsampling)
    m_reducedBoundary          .resize( m_reducedBoundarySize.width + m_reducedBoundarySize.height );
    m_reducedBoundaryTransposed.resize( m_reducedBoundarySize.width + m_reducedBoundarySize.height );

    const bool needVerticalUpsampling = ( m_upsmpFactorVer > 1 );
    int* const topReduced = m_reducedBoundary.data();
    boundaryDownsampling1D( topReduced, m_boundaryForUpsamplingTop.data(), block.width, m_reducedBoundarySize.width, needVerticalUpsampling, m_boundarySizeForUpsampling.width );
    m_boundaryForUpsamplingTop.resize( needVerticalUpsampling ? m_boundarySizeForUpsampling.width : 0 );

    const bool needHorizontalUpsampling = ( m_upsmpFactorHor > 1 );
    int* const leftReduced = m_reducedBoundary.data() + m_reducedBoundarySize.width;
    boundaryDownsampling1D( leftReduced, m_boundaryForUpsamplingLeft.data(), block.height, m_reducedBoundarySize.height, needHorizontalUpsampling, m_boundarySizeForUpsampling.height );
    m_boundaryForUpsamplingLeft.resize( needHorizontalUpsampling ? m_boundarySizeForUpsampling.height : 0 );

    int* const leftReducedTransposed = m_reducedBoundaryTransposed.data();
    int* const topReducedTransposed  = m_reducedBoundaryTransposed.data() + m_reducedBoundarySize.height;
    for( int x = 0; x < m_reducedBoundarySize.width; x++ )
    {
      topReducedTransposed[ x ] = topReduced[ x ];
    }
    for( int y = 0; y < m_reducedBoundarySize.height; y++ )
    {
      leftReducedTransposed[ y ] = leftReduced[ y ];
    }
  }
211
#endif
212
213
214
215
216
217

  void PredictorMIP::getPrediction(int* const result, const int modeIdx, const int bitDepth)
  {
    const bool transpose = isTransposed( modeIdx );
    const bool needUpsampling = ( m_upsmpFactorHor > 1 ) || ( m_upsmpFactorVer > 1 );

218
219
220
221
222
#if JVET_O0925_MIP_SIMPLIFICATIONS
    const uint8_t* matrix;
    int shiftMatrix = 0, offsetMatrix = 0;
    getMatrixData(matrix, shiftMatrix, offsetMatrix, modeIdx);
#else
223
224
225
226
    const short* matrix;
    const short* bias;
    getMatrixBias( matrix, bias, modeIdx );

227
228
229
    int shiftMatrix = 0;
    int shiftBias = 0;
    getShifts(shiftMatrix, shiftBias, modeIdx, bitDepth );
230
#endif
231

232
233
    bool leaveHorOut = ( m_blockSize.width == 4 && m_blockSize.height >= 16 );
    bool leaveVerOut = ( m_blockSize.height == 4 && m_blockSize.width >= 16 );
234
235
    if (transpose)
    {
236
      std::swap(leaveHorOut, leaveVerOut);
237
238
239
240
    }
    static_vector<int, MIP_MAX_REDUCED_OUTPUT_SAMPLES> bufReducedPred( m_reducedPredictionSize.area() );
    int* const       reducedPred     = needUpsampling ? bufReducedPred.data() : result;
    const int* const reducedBoundary = transpose ? m_reducedBoundaryTransposed.data() : m_reducedBoundary.data();
241
242
243
244
#if JVET_O0925_MIP_SIMPLIFICATIONS
    computeReducedPred( reducedPred, reducedBoundary, matrix, leaveHorOut, leaveVerOut, shiftMatrix, offsetMatrix, 
                        transpose, needUpsampling, bitDepth );
#else
245
    xComputeMatrixTimesRedBndryPlusBias( reducedPred, reducedBoundary, matrix, bias,
246
247
                                         leaveHorOut, leaveVerOut,
                                         shiftMatrix, shiftBias,
248
                                         transpose, needUpsampling );
249
#endif
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
    // Reduced prediction is transposed if ( transpose && needUpsampling ).

    if( needUpsampling )
    {
      predictionUpsampling( result, reducedPred, transpose );
    }
  }

  bool PredictorMIP::isTransposed( const int modeIdx ) const
  {
    return ( modeIdx > ( m_numModes / 2 ) );
  }

  int PredictorMIP::getWeightIdx( const int modeIdx ) const
  {
    if( modeIdx > m_numModes / 2 )
    {
      return modeIdx - m_numModes / 2;
    }
    else
    {
      return modeIdx;
    }
  }

  void PredictorMIP::initPredBlockParams(const Size& block)
  {
    m_blockSize = block;
    m_numModes  = getNumModesMip(m_blockSize);

    // init reduced boundary size
    if (m_blockSize.width > 4 || m_blockSize.height > 4)
    {
      m_reducedBoundarySize = Size(4, 4);
    }
    else
    {
      m_reducedBoundarySize = Size(2, 2);
    }

    // init reduced prediction size
    if (m_blockSize.width <= 8 && m_blockSize.height <= 8)
    {
      m_reducedPredictionSize = Size(4, 4);
    }
    else
    {
      m_reducedPredictionSize = Size(std::min<SizeType>(m_blockSize.width, 8), std::min<SizeType>(m_blockSize.height, 8));
    }

300
#if !JVET_O0925_MIP_SIMPLIFICATIONS
301
302
303
304
305
306
307
308
309
    // init boundary size for upsampling
    if (m_blockSize.height > m_blockSize.width)
    {
      m_boundarySizeForUpsampling = Size(m_blockSize.width, m_reducedPredictionSize.height);
    }
    else
    {
      m_boundarySizeForUpsampling = Size(m_reducedPredictionSize.width, m_blockSize.height);
    }
310
#endif
311
312
313
314
315
316
317
318
319
320
321
322
323

    // init upsampling factors
    m_upsmpFactorHor = m_blockSize.width / m_reducedPredictionSize.width;
    CHECKD(m_reducedPredictionSize.width * m_upsmpFactorHor != m_blockSize.width, "Need integer horizontal upsampling factor.");
    CHECKD((m_upsmpFactorHor < 1) || ((m_upsmpFactorHor & (m_upsmpFactorHor - 1)) != 0), "Need power of two horizontal upsampling factor.");

    m_upsmpFactorVer = m_blockSize.height / m_reducedPredictionSize.height;
    CHECKD(m_reducedPredictionSize.height * m_upsmpFactorVer != m_blockSize.height, "Need integer vertical upsampling factor.");
    CHECKD((m_upsmpFactorVer < 1) || ((m_upsmpFactorVer & (m_upsmpFactorVer - 1)) != 0), "Need power of two vertical upsampling factor.");
  }

  void PredictorMIP::doDownsampling( int* dst, const int* src, const SizeType srcLen, const SizeType dstLen )
  {
324
#if !JVET_O0925_MIP_SIMPLIFICATIONS
325
    // TODO: Check if src and dst can ever be negative. If not assign unsigned type and simplify rounding.
326
#endif
327
328
329
330
    const SizeType downsmpFactor = srcLen / dstLen;
    CHECKD( srcLen != dstLen * downsmpFactor, "Need integer downsampling factor." );
    CHECKD( ( downsmpFactor & ( downsmpFactor - 1 ) ) != 0, "Need power of two downsampling factor." );
    const int log2DownsmpFactor = g_aucLog2[ downsmpFactor ];
331
332
333
#if JVET_O0925_MIP_SIMPLIFICATIONS
    const int roundingOffset = ( 1 << ( log2DownsmpFactor - 1 ) );
#else
334
    const int roundingOffsetPositive = ( 1 << ( log2DownsmpFactor - 1 ) );
335
#endif
336
337
338
339
340
341
342
343

    for( SizeType srcIdx = 0, dstIdx = 0; dstIdx < dstLen; ++dstIdx )
    {
      int sum = 0;
      for( SizeType blockIdx = 0; blockIdx < downsmpFactor; ++blockIdx, ++srcIdx )
      {
        sum += src[ srcIdx ];
      }
344
#if !JVET_O0925_MIP_SIMPLIFICATIONS
345
      const int roundingOffset = roundingOffsetPositive - ( sum < 0 ? 1 : 0 );
346
#endif
347
348
349
350
351
      dst[ dstIdx ] = ( sum + roundingOffset ) >> log2DownsmpFactor;
    }
  }


352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
#if JVET_O0925_MIP_SIMPLIFICATIONS
  void PredictorMIP::boundaryDownsampling1D(int* reducedDst, const int* const fullSrc, const SizeType srcLen, const SizeType dstLen)
  {
    if (dstLen < srcLen)
    {
      // Create reduced boundary by downsampling
      doDownsampling(reducedDst, fullSrc, srcLen, dstLen);
    }
    else
    {
      // Copy boundary if no downsampling is needed
      for (SizeType i = 0; i < dstLen; ++i)
      {
        reducedDst[i] = fullSrc[i];
      }
    }
  }
#else
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
  void PredictorMIP::boundaryDownsampling1D( int* reducedDst, int* fullSrcAndIntermediateDst,
                                              const SizeType srcLen, const SizeType dstLen,
                                              const bool saveIntermediate, const SizeType intermediateLen )
  {
    SizeType currLen = srcLen;

    // Create intermediate boundary if needed.
    if( saveIntermediate && intermediateLen < srcLen )
    {
      CHECKD( intermediateLen < dstLen, "Intermediate length must not be less than target length." );
      doDownsampling( fullSrcAndIntermediateDst, fullSrcAndIntermediateDst, currLen, intermediateLen );
      currLen = intermediateLen;
    }

    if( dstLen < currLen )
    {
      // Create reduced boundary by downsampling.
      doDownsampling( reducedDst, fullSrcAndIntermediateDst, currLen, dstLen );
    }
    else
    {
      // Copy reduced boundary if no downsampling is needed.
      for( SizeType i = 0; i < dstLen; ++i )
      {
        reducedDst[ i ] = fullSrcAndIntermediateDst[ i ];
      }
    }
  }
398
#endif
399
400
401
402
403
404


  void PredictorMIP::predictionUpsampling1D( int* const dst, const int* const src, const int* const bndry,
                                              const SizeType srcSizeUpsmpDim, const SizeType srcSizeOrthDim,
                                              const SizeType srcStep, const SizeType srcStride,
                                              const SizeType dstStep, const SizeType dstStride,
405
406
407
#if JVET_O0925_MIP_SIMPLIFICATIONS
                                              const SizeType bndryStep,
#endif
408
409
                                              const unsigned int upsmpFactor )
  {
410
#if !JVET_O0925_MIP_SIMPLIFICATIONS
411
    // TODO: Check if src and dst can ever be negative. If not assign unsigned type and simplify rounding.
412
#endif
413
414
    const int log2UpsmpFactor = g_aucLog2[ upsmpFactor ];
    CHECKD( upsmpFactor <= 1, "Upsampling factor must be at least 2." );
415
416
417
#if JVET_O0925_MIP_SIMPLIFICATIONS
    const int roundingOffset = 1 << (log2UpsmpFactor - 1);
#endif
418
419
420
421

    SizeType idxOrthDim = 0;
    const int* srcLine = src;
    int* dstLine = dst;
422
423
424
#if JVET_O0925_MIP_SIMPLIFICATIONS
    const int* bndryLine = bndry + bndryStep - 1;
#endif
425
426
427
    while( idxOrthDim < srcSizeOrthDim )
    {
      SizeType idxUpsmpDim = 0;
428
429
430
#if JVET_O0925_MIP_SIMPLIFICATIONS
      const int* before = bndryLine;
#else
431
      const int* before = bndry + idxOrthDim;
432
#endif
433
434
435
436
437
438
439
440
441
442
443
      const int* behind = srcLine;
      int* currDst = dstLine;
      while( idxUpsmpDim < srcSizeUpsmpDim )
      {
        SizeType pos = 1;
        int scaledBefore = ( *before ) << log2UpsmpFactor;
        int scaledBehind = 0;
        while( pos <= upsmpFactor )
        {
          scaledBefore -= *before;
          scaledBehind += *behind;
444
445
446
#if JVET_O0925_MIP_SIMPLIFICATIONS
          *currDst = (scaledBefore + scaledBehind + roundingOffset) >> log2UpsmpFactor;
#else
447
448
449
          *currDst = scaledBefore + scaledBehind;
          *currDst = ( *currDst + ( 1 << ( log2UpsmpFactor - 1 ) ) -
            ( *currDst < 0 ? 1 : 0 ) ) >> log2UpsmpFactor;
450
#endif
451
452
453
454
455
456
457
458
459
460
461
462
463

          pos++;
          currDst += dstStep;
        }

        idxUpsmpDim++;
        before = behind;
        behind += srcStep;
      }

      idxOrthDim++;
      srcLine += srcStride;
      dstLine += dstStride;
464
465
466
#if JVET_O0925_MIP_SIMPLIFICATIONS
      bndryLine += bndryStep;
#endif
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
    }
  }


  void PredictorMIP::predictionUpsampling( int* const dst, const int* const src, const bool transpose ) const
  {
    // shorter side is upsampled first
    if( m_blockSize.height > m_blockSize.width )
    {
      const int* verSrc       = nullptr;
      SizeType   verSrcStep   = 0;
      SizeType   verSrcStride = 0;
      if( m_upsmpFactorHor > 1 )
      {
        const SizeType horSrcStep   = transpose ? m_reducedPredictionSize.height : 1;
        const SizeType horSrcStride = transpose ? 1 : m_reducedPredictionSize.width;

        int* const     horDst       = dst + ( m_upsmpFactorVer - 1 ) * m_blockSize.width;
        const SizeType horDstStride = m_upsmpFactorVer * m_blockSize.width;

487
488
489
490
491
492
#if JVET_O0925_MIP_SIMPLIFICATIONS
        predictionUpsampling1D( horDst, src, m_refSamplesLeft.data(),
                                m_reducedPredictionSize.width, m_reducedPredictionSize.height,
                                horSrcStep, horSrcStride, 1, horDstStride,
                                m_upsmpFactorVer, m_upsmpFactorHor );
#else
493
494
495
496
        predictionUpsampling1D( horDst, src, m_boundaryForUpsamplingLeft.data(),
                                m_reducedPredictionSize.width, m_reducedPredictionSize.height,
                                horSrcStep, horSrcStride, 1, horDstStride,
                                m_upsmpFactorHor );
497
#endif
498
499
500
501
502
503
504
505
506
507
508

        verSrc       = horDst;
        verSrcStep   = horDstStride;
        verSrcStride = 1;
      }
      else
      {
        verSrc       = src;
        verSrcStep   = transpose ? 1 : m_blockSize.width;
        verSrcStride = transpose ? m_reducedPredictionSize.height : 1;
      }
509
510
511
512
513
514
#if JVET_O0925_MIP_SIMPLIFICATIONS
      predictionUpsampling1D( dst, verSrc, m_refSamplesTop.data(),
                              m_reducedPredictionSize.height, m_blockSize.width,
                              verSrcStep, verSrcStride, m_blockSize.width, 1,
                              1, m_upsmpFactorVer );
#else
515
516
517
518
      predictionUpsampling1D( dst, verSrc, m_boundaryForUpsamplingTop.data(),
                              m_reducedPredictionSize.height, m_blockSize.width,
                              verSrcStep, verSrcStride, m_blockSize.width, 1,
                              m_upsmpFactorVer );
519
#endif
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
    }
    else
    {
      const int* horSrc = nullptr;
      SizeType   horSrcStep = 0;
      SizeType   horSrcStride = 0;
      if( m_upsmpFactorVer > 1 )
      {
        const SizeType verSrcStep   = transpose ? 1 : m_reducedPredictionSize.width;
        const SizeType verSrcStride = transpose ? m_reducedPredictionSize.height : 1;

        int* const     verDst       = dst + ( m_upsmpFactorHor - 1 );
        const SizeType verDstStep   = m_blockSize.width;
        const SizeType verDstStride = m_upsmpFactorHor;

535
536
537
538
539
540
#if JVET_O0925_MIP_SIMPLIFICATIONS
        predictionUpsampling1D( verDst, src, m_refSamplesTop.data(),
                                m_reducedPredictionSize.height, m_reducedPredictionSize.width,
                                verSrcStep, verSrcStride, verDstStep, verDstStride,
                                m_upsmpFactorHor, m_upsmpFactorVer );
#else
541
542
543
544
        predictionUpsampling1D( verDst, src, m_boundaryForUpsamplingTop.data(),
                                m_reducedPredictionSize.height, m_reducedPredictionSize.width,
                                verSrcStep, verSrcStride, verDstStep, verDstStride,
                                m_upsmpFactorVer );
545
#endif
546
547
548
549
550
551
552
553
554
555
556

        horSrc = verDst;
        horSrcStep = verDstStride;
        horSrcStride = verDstStep;
      }
      else
      {
        horSrc       = src;
        horSrcStep   = transpose ? m_blockSize.height : 1;
        horSrcStride = transpose ? 1 : m_reducedPredictionSize.width;
      }
557
558
559
560
561
562
#if JVET_O0925_MIP_SIMPLIFICATIONS
      predictionUpsampling1D( dst, horSrc, m_refSamplesLeft.data(),
                              m_reducedPredictionSize.width, m_blockSize.height,
                              horSrcStep, horSrcStride, 1, m_blockSize.width,
                              1, m_upsmpFactorHor );
#else
563
564
565
566
      predictionUpsampling1D( dst, horSrc, m_boundaryForUpsamplingLeft.data(),
                              m_reducedPredictionSize.width, m_blockSize.height,
                              horSrcStep, horSrcStride, 1, m_blockSize.width,
                              m_upsmpFactorHor );
567
#endif
568
569
570
    }
  }

571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
#if JVET_O0925_MIP_SIMPLIFICATIONS
  void PredictorMIP::getMatrixData(const uint8_t*& matrix, int &shiftMatrix, int &offsetMatrix, const int modeIdx) const
  {
    const int idx = getWeightIdx( modeIdx );
    if( m_blockSize.width == 4 && m_blockSize.height == 4 )
    {
      matrix       = &mipMatrix4x4      [idx][0][0];
      shiftMatrix  =  mipShiftMatrix4x4 [idx];
      offsetMatrix =  mipOffsetMatrix4x4[idx];
    }
    else if( m_blockSize.width <= 8 && m_blockSize.height <= 8 )
    {
      matrix       = &mipMatrix8x8      [idx][0][0];
      shiftMatrix  =  mipShiftMatrix8x8 [idx];
      offsetMatrix =  mipOffsetMatrix8x8[idx];
    }
    else
    {
      matrix       = &mipMatrix16x16      [idx][0][0];
      shiftMatrix  =  mipShiftMatrix16x16 [idx];
      offsetMatrix =  mipOffsetMatrix16x16[idx];
    }
  }
#else
595
596
597
598
599
600
  void PredictorMIP::getMatrixBias( const short*& matrix, const short*& bias, const int modeIdx ) const
  {
    const int idx = getWeightIdx( modeIdx );

    if( m_blockSize.width == 4 && m_blockSize.height == 4 )
    {
601
602
      matrix = &mipMatrix4x4[idx][0][0];
      bias   = &mipBias4x4  [idx][0];
603
604
605
    }
    else if( m_blockSize.width <= 8 && m_blockSize.height <= 8 )
    {
606
607
      matrix = &mipMatrix8x8[idx][0][0];
      bias   = &mipBias8x8  [idx][0];
608
609
610
    }
    else
    {
611
612
      matrix = &mipMatrix16x16[idx][0][0];
      bias   = &mipBias16x16  [idx][0];
613
614
615
616
617
618
619
620
621
    }
  }

  void PredictorMIP::getShifts( int &shiftMatrix, int &shiftBias, const int modeIdx, const int bitDepth ) const
  {
    const int idx = getWeightIdx( modeIdx );

    if( m_blockSize.width == 4 && m_blockSize.height == 4 )
    {
622
623
      shiftMatrix = mipShiftMatrix4x4[idx];
      shiftBias   = mipShiftBias4x4  [idx] + (bitDepth - 10);
624
625
626
    }
    else if( m_blockSize.width <= 8 && m_blockSize.height <= 8 )
    {
627
628
      shiftMatrix = mipShiftMatrix8x8[idx];
      shiftBias   = mipShiftBias8x8  [idx] + (bitDepth - 10);
629
630
631
    }
    else
    {
632
633
      shiftMatrix = mipShiftMatrix16x16[idx];
      shiftBias   = mipShiftBias16x16  [idx] + (bitDepth - 10);
634
635
    }
  }
636
637
638
639
640
641
642
643
#endif

#if JVET_O0925_MIP_SIMPLIFICATIONS
  void PredictorMIP::computeReducedPred( int*const result, const int* const input, const uint8_t*matrix,
                                         const bool leaveHorOut, const bool leaveVerOut, 
                                         const int shiftMatrix, const int offsetMatrix,
                                         const bool transpose, const bool needUpsampling, const int bitDepth )
#else
644
645
  void PredictorMIP::xComputeMatrixTimesRedBndryPlusBias( int*const result, const int* const input,
                                                          const short*matrix, const short*bias,
646
647
                                                          const bool leaveHorOut, const bool leaveVerOut,
                                                          const int shiftMatrix, const int shiftBias,
648
                                                          const bool transpose, const bool needUpsampling )
649
#endif
650
  {
651
    const int inputSize = m_reducedBoundarySize.width + m_reducedBoundarySize.height;
652
653
654

    // Use local buffer for transposed result if no upsampling will be done.
    static_vector<int, MIP_MAX_REDUCED_OUTPUT_SAMPLES> resBufTransposed( m_reducedPredictionSize.area() );
655
    int*const resPtr = (transpose && !needUpsampling) ? resBufTransposed.data() : result;
656

657
658
659
660
661
#if JVET_O0925_MIP_SIMPLIFICATIONS
    int sum = 0;
    for (int i = 0; i < inputSize; i++) { sum += input[i]; }
    const int offset = (1 << (shiftMatrix - 1)) - offsetMatrix * sum;
#else
662
    const int offset = 1 << (shiftMatrix - 1);
663
#endif
664
    CHECK(inputSize != 4 * (inputSize >> 2), "Error, input size not divisible by four");
665

666
667
668
669
#if JVET_O0925_MIP_SIMPLIFICATIONS
    const uint8_t *weight = matrix;
    const int   inputOffset = transpose ? m_inputOffsetTransp : m_inputOffset;
#else
670
    const short *weight = matrix;
671
#endif
672
673
674

    const int intermediateWidth  = transpose ? m_reducedPredictionSize.height : m_reducedPredictionSize.width;
    const int intermediateHeight = transpose ? m_reducedPredictionSize.width : m_reducedPredictionSize.height;
675
676
    const int xStep = leaveHorOut ? 2 : 1;
    const int yStep = leaveVerOut ? intermediateWidth : 0;
677

678
679
680
681
#if JVET_O0925_MIP_SIMPLIFICATIONS
    const int redSize = (m_blockSize.width <= 8 && m_blockSize.height <= 8) ? 0 : 1;
    if ( redSize ) weight += xStep-1; 
#endif
682
683
684
685
686
687
    int posRes  = 0;
    int posBias = 0;
    for (int y = 0; y < intermediateHeight; y++)
    {
      for (int x = 0; x < intermediateWidth; x++)
      {
688
689
690
691
692
693
694
695
#if JVET_O0925_MIP_SIMPLIFICATIONS
        if(redSize) weight -= xStep; 
        int tmp0 = redSize ? 0 : (input[0] * weight[0]);
        int tmp1 = input[1] * weight[1];
        int tmp2 = input[2] * weight[2];
        int tmp3 = input[3] * weight[3];
        for (int i = 4; i < inputSize; i += 4)
#else
696
697
698
699
        int tmp0 = 0;
        int tmp1 = 0;
        int tmp2 = 0;
        int tmp3 = 0;
700
        for (int i = 0; i < inputSize - 1; i += 4)
701
#endif
702
703
704
705
706
707
        {
          tmp0 += input[i]     * weight[i];
          tmp1 += input[i + 1] * weight[i + 1];
          tmp2 += input[i + 2] * weight[i + 2];
          tmp3 += input[i + 3] * weight[i + 3];
        }
708
709
710
#if JVET_O0925_MIP_SIMPLIFICATIONS
        resPtr[posRes++] = ClipBD<int>( ((tmp0 + tmp1 + tmp2 + tmp3 + offset) >> shiftMatrix) + inputOffset, bitDepth );
#else
711
        resPtr[posRes++] = ((tmp0 + tmp1 + tmp2 + tmp3) + (bias[posBias] << shiftBias) + offset) >> shiftMatrix;
712
#endif
713

714
        weight  += xStep * inputSize;
715
716
        posBias += xStep;
      }
717
718
719
#if JVET_O0925_MIP_SIMPLIFICATIONS
      weight  += yStep * (inputSize - redSize);
#else
720
      weight  += yStep * inputSize;
721
#endif
722
723
724
725
726
727
728
729
730
731
732
      posBias += yStep;
    }

    // Re-transpose if no upsampling will be done.
    if( transpose && !needUpsampling )
    {
      for( int y = 0; y < m_reducedPredictionSize.height; y++ )
      {
        for( int x = 0; x < m_reducedPredictionSize.width; x++ )
        {
          CHECKD( x * m_reducedPredictionSize.height + y >= m_reducedPredictionSize.area(), "error" );
733
          result[ y * m_reducedPredictionSize.width + x ] = resPtr[ x * m_reducedPredictionSize.height + y ];
734
735
736
737
738
739
740
741
742
743
744
745
        }
      }
    }
  }


} // namespace Mip

MatrixIntraPrediction::MatrixIntraPrediction()
{
}

746
747
748
749
750
751
#if JVET_O0925_MIP_SIMPLIFICATIONS
void MatrixIntraPrediction::prepareInputForPred(const CPelBuf &pSrc, const Area& puArea, const int bitDepth)
{
  m_predictorMip.deriveBoundaryData(pSrc, puArea, bitDepth);
}
#else
752
753
754
755
void MatrixIntraPrediction::prepareInputForPred(const CPelBuf &src, const Area& puArea, const int bitDepth, const AvailableInfo &availInfo)
{
  m_predictorMip.deriveBoundaryData(src, puArea, bitDepth, availInfo);
}
756
#endif
757
758
759
760
761
762
763
764
765
766
767

void MatrixIntraPrediction::predBlock( const Size &puSize, const int intraMode, PelBuf& dst, const int bitDepth )
{
  static_vector<int, MIP_MAX_WIDTH * MIP_MAX_HEIGHT> predMip(puSize.area());
  int* const resultMip = predMip.data();
  m_predictorMip.getPrediction(resultMip, intraMode, bitDepth);

  for (int y = 0; y < puSize.height; y++)
  {
    for (int x = 0; x < puSize.width; x++)
    {
768
769
770
#if JVET_O0925_MIP_SIMPLIFICATIONS
      dst.at(x, y) = Pel(resultMip[y * puSize.width + x]);
#else
771
      dst.at(x, y) = Pel(ClipBD<int>(resultMip[y * puSize.width + x], bitDepth));
772
#endif
773
774
775
776
    }
  }
}