Coverage Report

Created: 2026-07-16 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvenc/source/Lib/EncoderLib/EncModeCtrl.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     EncModeCtrl.cpp
45
    \brief    Encoder controller for trying out specific modes
46
*/
47
48
#include "EncCu.h"
49
50
#include "EncModeCtrl.h"
51
#include "CommonLib/RdCost.h"
52
#include "CommonLib/CodingStructure.h"
53
#include "CommonLib/Picture.h"
54
#include "CommonLib/UnitTools.h"
55
#include "CommonLib/dtrace_next.h"
56
57
#include <cmath>
58
59
//! \ingroup EncoderLib
60
//! \{
61
62
namespace vvenc {
63
64
void CacheBlkInfoCtrl::create(int ctuSize)
65
19.4k
{
66
19.4k
  const unsigned numPos = MAX_CU_SIZE >> MIN_CU_LOG2;
67
19.4k
  const int maxSizeIdx  = MAX_CU_SIZE_IDX - MIN_CU_LOG2;
68
69
  //static constexpr size_t numCu = 7921;
70
71
19.4k
  size_t numCu = 0;
72
  
73
136k
  for( int wIdx = 0; wIdx < maxSizeIdx; wIdx++ )
74
116k
  {
75
817k
    for( int hIdx = 0; hIdx < maxSizeIdx; hIdx++ )
76
700k
    {
77
23.1M
      for( unsigned y = 0; y < numPos; y++ )
78
22.4M
      {
79
739M
        for( unsigned x = 0; x < numPos; x++ )
80
717M
        {
81
          // a block of width W might be offset of N * W + 1/2 W (bcs of TT), same for H
82
          // W = 1 << ( wIdx + 2 )
83
          // 1/2 W = 1 << ( wIdx + 1 )
84
          // remainder of (N+1/2)*W -> x & ( ( 1 << ( wIdx + 1 ) ) - 1 )
85
  
86
717M
          if( (x + (1 << (wIdx)) <= (ctuSize >> MIN_CU_LOG2))
87
504M
              && (y + (1 << (hIdx)) <= (ctuSize >> MIN_CU_LOG2))
88
354M
              && (((x << MIN_CU_LOG2) & ((1 << (wIdx + MIN_CU_LOG2 - 1)) - 1)) == 0)
89
233M
              && (((y << MIN_CU_LOG2) & ((1 << (hIdx + MIN_CU_LOG2 - 1)) - 1)) == 0) )
90
154M
          {
91
154M
            numCu++;
92
154M
          }
93
717M
        }
94
22.4M
      }
95
700k
    }
96
116k
  }
97
98
19.4k
  m_codedCUInfoBuf = new CodedCUInfo[numCu];
99
19.4k
  CodedCUInfo* cuInfo = m_codedCUInfoBuf;
100
101
136k
  for( int wIdx = 0; wIdx < maxSizeIdx; wIdx++ )
102
116k
  {
103
817k
    for( int hIdx = 0; hIdx < maxSizeIdx; hIdx++ )
104
700k
    {
105
23.1M
      for( unsigned y = 0; y < numPos; y++ )
106
22.4M
      {
107
739M
        for( unsigned x = 0; x < numPos; x++ )
108
717M
        {
109
          // a block of width W might be offset of N * W + 1/2 W (bcs of TT), same for H
110
          // W = 1 << ( wIdx + 2 )
111
          // 1/2 W = 1 << ( wIdx + 1 )
112
          // remainder of (N+1/2)*W -> x & ( ( 1 << ( wIdx + 1 ) ) - 1 )
113
114
717M
          if(( x + (1<<(wIdx)) <= ( ctuSize >> MIN_CU_LOG2 ) )
115
504M
            && ( y + (1<<(hIdx)) <= ( ctuSize >> MIN_CU_LOG2 ) )
116
354M
            && ( ( ( x << MIN_CU_LOG2 ) & ((1 << (wIdx + MIN_CU_LOG2 - 1)) - 1) ) == 0 )
117
233M
            && ( ( ( y << MIN_CU_LOG2 ) & ((1 << (hIdx + MIN_CU_LOG2 - 1)) - 1) ) == 0 ) )
118
154M
          {
119
154M
            m_codedCUInfo[wIdx][hIdx][x][y] = cuInfo++;
120
154M
            m_codedCUInfo[wIdx][hIdx][x][y]->poc       = -1;
121
154M
            m_codedCUInfo[wIdx][hIdx][x][y]->ctuRsAddr = -1;
122
154M
          }
123
563M
          else
124
563M
          {
125
563M
            m_codedCUInfo[wIdx][hIdx][x][y] = nullptr;
126
563M
          }
127
717M
        }
128
22.4M
      }
129
700k
    }
130
116k
  }
131
19.4k
}
132
133
void CacheBlkInfoCtrl::destroy()
134
19.4k
{
135
19.4k
  delete[] m_codedCUInfoBuf;
136
19.4k
  m_codedCUInfoBuf = nullptr;
137
19.4k
}
138
139
void CacheBlkInfoCtrl::init( const Slice &slice )
140
3.78k
{
141
3.78k
  m_pcv = slice.pps->pcv;
142
3.78k
}
143
144
void CacheBlkInfoCtrl::initBlk( const UnitArea& area, int poc )
145
131k
{
146
131k
  unsigned idx1, idx2, idx3, idx4;
147
131k
  getAreaIdxNew( area.Y(), *m_pcv, idx1, idx2, idx3, idx4 );
148
149
131k
  const int ctuRsAddr = getCtuAddr( area.lumaPos(), *m_pcv );
150
131k
  CodedCUInfo* cuInfo = m_codedCUInfo[idx1][idx2][idx3][idx4];
151
152
131k
  if( cuInfo->poc != poc || cuInfo->ctuRsAddr != ctuRsAddr )
153
93.8k
  {
154
93.8k
    GCC_WARNING_DISABLE_class_memaccess
155
93.8k
    memset( cuInfo, 0, sizeof( CodedCUInfo ) );
156
93.8k
    GCC_WARNING_RESET
157
158
93.8k
    cuInfo->poc       = poc;
159
93.8k
    cuInfo->ctuRsAddr = ctuRsAddr;
160
93.8k
  }
161
131k
}
162
163
CodedCUInfo& CacheBlkInfoCtrl::getBlkInfo( const UnitArea& area )
164
217k
{
165
217k
  unsigned idx1, idx2, idx3, idx4;
166
217k
  getAreaIdxNew( area.Y(), *m_pcv, idx1, idx2, idx3, idx4 );
167
//  DTRACE( g_trace_ctx, D_TMP, "%d loc %d %d %d %d\n", g_trace_ctx->getChannelCounter(D_TMP), idx1, idx2, idx3, idx4);
168
217k
  return *m_codedCUInfo[idx1][idx2][idx3][idx4];
169
217k
}
170
171
void CodedCUInfo::setMv( const RefPicList refPicList, const int iRefIdx, const Mv& rMv )
172
0
{
173
0
  if( iRefIdx >= MAX_STORED_CU_INFO_REFS ) return;
174
175
0
  saveMv [refPicList][iRefIdx] = rMv;
176
0
  validMv[refPicList][iRefIdx] = true;
177
0
}
178
179
bool CodedCUInfo::getMv( const RefPicList refPicList, const int iRefIdx, Mv& rMv ) const
180
0
{
181
0
  if( iRefIdx >= MAX_STORED_CU_INFO_REFS )
182
0
  {
183
0
    rMv = saveMv[refPicList][0];
184
0
    return false;
185
0
  }
186
187
0
  rMv = saveMv[refPicList][iRefIdx];
188
0
  return validMv[refPicList][iRefIdx];
189
0
}
190
191
uint8_t CacheBlkInfoCtrl::findBestSbt( const UnitArea& area, const uint32_t curPuSse )
192
0
{
193
0
  unsigned idx1, idx2, idx3, idx4;
194
0
  getAreaIdxNew( area.Y(), *m_pcv, idx1, idx2, idx3, idx4 );
195
0
  CodedCUInfo* pSbtSave = m_codedCUInfo[idx1][idx2][idx3][idx4];
196
197
0
  for( int i = 0; i < pSbtSave->numPuInfoStored; i++ )
198
0
  {
199
0
    if( curPuSse == pSbtSave->puSse[i] )
200
0
    {
201
0
      return pSbtSave->puSbt[i];
202
0
    }
203
0
  }
204
205
0
  return MAX_UCHAR;
206
0
}
207
208
bool CacheBlkInfoCtrl::saveBestSbt( const UnitArea& area, const uint32_t curPuSse, const uint8_t curPuSbt )
209
0
{
210
0
  unsigned idx1, idx2, idx3, idx4;
211
0
  getAreaIdxNew( area.Y(), *m_pcv, idx1, idx2, idx3, idx4 );
212
0
  CodedCUInfo* pSbtSave = m_codedCUInfo[idx1][idx2][idx3][idx4];
213
214
0
  if( pSbtSave->numPuInfoStored == SBT_NUM_SL )
215
0
  {
216
0
    return false;
217
0
  }
218
219
0
  pSbtSave->puSse[pSbtSave->numPuInfoStored] = curPuSse;
220
0
  pSbtSave->puSbt[pSbtSave->numPuInfoStored] = curPuSbt;
221
0
  pSbtSave->numPuInfoStored++;
222
223
0
  return true;
224
0
}
225
226
static bool isTheSameNbHood( const CodingUnit &cu, const CodingStructure& cs, const Partitioner &partitioner, int picW, int picH )
227
0
{
228
0
  if( cu.chType != partitioner.chType )
229
0
  {
230
0
    return false;
231
0
  }
232
233
0
  const PartitioningStack &ps = partitioner.getPartStack();
234
235
0
  int i = 1;
236
237
0
  for( ; i < ps.size(); i++ )
238
0
  {
239
0
    if( ps[i].split != CU::getSplitAtDepth( cu, i - 1 ) )
240
0
    {
241
0
      break;
242
0
    }
243
0
  }
244
245
0
  const UnitArea& cmnAnc = ps[i - 1].parts[ps[i - 1].idx];
246
0
  const UnitArea cuArea  = CS::getArea( cs, cu, partitioner.chType, partitioner.treeType );
247
248
0
  for( int i = 0; i < cmnAnc.blocks.size(); i++ )
249
0
  {
250
0
    if( i < cuArea.blocks.size() && cuArea.blocks[i].valid() && cuArea.blocks[i].pos() != cmnAnc.blocks[i].pos() )
251
0
    {
252
0
      return false;
253
0
    }
254
0
  }
255
256
0
  return true;
257
0
}
258
259
void BestEncInfoCache::create( const bool reuseCuResults, const ChromaFormat chFmt, const int ctuSize )
260
19.4k
{
261
19.4k
  m_reuseCuResults = reuseCuResults;
262
263
19.4k
  if( !m_reuseCuResults ) return;
264
265
0
  const unsigned numPos = MAX_CU_SIZE >> MIN_CU_LOG2;
266
0
  const int maxSizeIdx  = MAX_CU_SIZE_IDX - MIN_CU_LOG2;
267
268
0
  static constexpr size_t yuvNom[4] = { 1, 3, 2, 3 };
269
0
  static constexpr size_t yuvDen[4] = { 0, 1, 0, 0 };
270
271
  // only true for 128x128 CTU
272
  //static constexpr size_t numCu = 7921;
273
  //static constexpr size_t numDmvrMv = 5439;
274
  //const size_t numCoeff = ( 1345600 * yuvNom[chFmt] ) >> yuvDen[chFmt];
275
276
0
  size_t numCu = 0;
277
0
  size_t numDmvrMv = 0;
278
0
  size_t numCoeff = 0;
279
  
280
0
  for( int wIdx = 0; wIdx < maxSizeIdx; wIdx++ )
281
0
  {
282
0
    for( int hIdx = 0; hIdx < maxSizeIdx; hIdx++ )
283
0
    {
284
0
      int dmvrSize = 0;
285
0
      if( hIdx >= 1 && wIdx >= 1 && (wIdx + hIdx) >= 3 )
286
0
      {
287
0
        dmvrSize = (1 << std::max( 0, (wIdx + MIN_CU_LOG2 - DMVR_SUBCU_SIZE_LOG2) )) * (1 << std::max( 0, (hIdx + MIN_CU_LOG2 - DMVR_SUBCU_SIZE_LOG2) ));
288
0
      }
289
  
290
0
      const UnitArea area( chFmt, Area( 0, 0, 1 << (wIdx + 2), 1 << (hIdx + 2) ) );
291
  
292
0
      for( unsigned x = 0; x < numPos; x++ )
293
0
      {
294
0
        for( unsigned y = 0; y < numPos; y++ )
295
0
        {
296
          // a block of width W might be offset of N * W + 1/2 W (bcs of TT), same for H
297
          // W = 1 << ( wIdx + 2 )
298
          // 1/2 W = 1 << ( wIdx + 1 )
299
          // remainder of (N+1/2)*W -> x & ( ( 1 << ( wIdx + 1 ) ) - 1 )
300
  
301
0
          if( (x + (1 << (wIdx)) <= (ctuSize >> MIN_CU_LOG2))
302
0
            && (y + (1 << (hIdx)) <= (ctuSize >> MIN_CU_LOG2))
303
0
            && (((x << MIN_CU_LOG2) & ((1 << (wIdx + MIN_CU_LOG2 - 1)) - 1)) == 0)
304
0
            && (((y << MIN_CU_LOG2) & ((1 << (hIdx + MIN_CU_LOG2 - 1)) - 1)) == 0) )
305
0
          {
306
0
            numCu++;
307
  
308
0
            numCoeff += area.Y().area();
309
  
310
  
311
            //numCu++;
312
0
            numDmvrMv += dmvrSize;
313
0
          }
314
0
        }
315
0
      }
316
0
    }
317
0
  }
318
  
319
  //std::cout << numCu << " " << numDmvrMv << " " << numCoeff << std::endl;
320
  
321
0
  numCoeff  *= yuvNom[chFmt];
322
0
  numCoeff >>= yuvDen[chFmt];
323
324
0
  m_encInfoBuf = new BestEncodingInfo[numCu];
325
0
  BestEncodingInfo* encInfo = m_encInfoBuf;
326
327
0
  m_dmvrMvBuf = new Mv[numDmvrMv];
328
0
  Mv* dmvrMv = m_dmvrMvBuf;
329
330
0
  m_pCoeff = new TCoeffSig[numCoeff];
331
0
  TCoeffSig* coeffPtr = m_pCoeff;
332
333
0
  for( int wIdx = 0; wIdx < maxSizeIdx; wIdx++ )
334
0
  {
335
0
    for( int hIdx = 0; hIdx < maxSizeIdx; hIdx++ )
336
0
    {
337
0
      int dmvrSize = 0;
338
0
      if( hIdx >= 1 && wIdx >= 1 && (wIdx + hIdx) >= 3 )
339
0
      {
340
0
        dmvrSize = (1 << std::max( 0, (wIdx + MIN_CU_LOG2 - DMVR_SUBCU_SIZE_LOG2) )) * (1 << std::max( 0, (hIdx + MIN_CU_LOG2 - DMVR_SUBCU_SIZE_LOG2) ));
341
0
      }
342
343
0
      const UnitArea area( chFmt, Area( 0, 0, 1 << (wIdx + 2), 1 << (hIdx + 2) ) );
344
345
0
      for( unsigned x = 0; x < numPos; x++ )
346
0
      {
347
0
        for( unsigned y = 0; y < numPos; y++ )
348
0
        {
349
          // a block of width W might be offset of N * W + 1/2 W (bcs of TT), same for H
350
          // W = 1 << ( wIdx + 2 )
351
          // 1/2 W = 1 << ( wIdx + 1 )
352
          // remainder of (N+1/2)*W -> x & ( ( 1 << ( wIdx + 1 ) ) - 1 )
353
354
0
          if(( x + (1<<(wIdx)) <= ( ctuSize >> MIN_CU_LOG2 ) )
355
0
            && ( y + (1<<(hIdx)) <= ( ctuSize >> MIN_CU_LOG2 ) )
356
0
            && ( ( ( x << MIN_CU_LOG2 )  & ((1 << (wIdx + MIN_CU_LOG2 - 1)) - 1) ) == 0 )
357
0
            && ( ( ( y << MIN_CU_LOG2 )  & ((1 << (hIdx + MIN_CU_LOG2 - 1)) - 1) ) == 0 ) )
358
0
          {
359
0
            m_bestEncInfo[wIdx][hIdx][x][y] = encInfo++;
360
361
0
            m_bestEncInfo[wIdx][hIdx][x][y]->cu.UnitArea::operator=( area );
362
0
            m_bestEncInfo[wIdx][hIdx][x][y]->tu.UnitArea::operator=( area );
363
364
0
            m_bestEncInfo[wIdx][hIdx][x][y]->cu.chType = CH_L;
365
0
            m_bestEncInfo[wIdx][hIdx][x][y]->cu.treeType = TREE_D;
366
0
            m_bestEncInfo[wIdx][hIdx][x][y]->cu.modeType = MODE_TYPE_ALL;
367
0
            m_bestEncInfo[wIdx][hIdx][x][y]->cu.qp = MAX_SCHAR;
368
0
            m_bestEncInfo[wIdx][hIdx][x][y]->tu.chType = CH_L;
369
370
0
            if( dmvrSize )
371
0
            {
372
0
              m_bestEncInfo[wIdx][hIdx][x][y]->cu.mvdL0SubPu = dmvrMv; 
373
0
              dmvrMv += dmvrSize;
374
0
            }
375
376
0
            TCoeffSig* coeff[MAX_NUM_TBLOCKS] = { 0, };
377
378
0
            const UnitArea& area = m_bestEncInfo[wIdx][hIdx][x][y]->tu;
379
380
0
            for( int i = 0; i < area.blocks.size(); i++ )
381
0
            {
382
0
              coeff[i] = coeffPtr; coeffPtr += area.blocks[i].area();
383
0
            }
384
385
0
            m_bestEncInfo[wIdx][hIdx][x][y]->tu.cs = &m_dummyCS;
386
0
            m_bestEncInfo[wIdx][hIdx][x][y]->tu.init( coeff );
387
388
0
            m_bestEncInfo[wIdx][hIdx][x][y]->poc      = -1;
389
0
            m_bestEncInfo[wIdx][hIdx][x][y]->testMode = EncTestMode();
390
0
          }
391
0
          else
392
0
          {
393
0
            m_bestEncInfo[wIdx][hIdx][x][y] = nullptr;
394
0
          }
395
0
        }
396
0
      }
397
0
    }
398
0
  }
399
0
}
400
401
void BestEncInfoCache::destroy()
402
19.4k
{
403
19.4k
  if( !m_reuseCuResults ) return;
404
405
0
  delete[] m_encInfoBuf;
406
0
  m_encInfoBuf = nullptr;
407
408
0
  delete[] m_pCoeff;
409
0
  m_pCoeff = nullptr;
410
411
0
  delete[] m_dmvrMvBuf;
412
0
  m_dmvrMvBuf = nullptr;
413
414
0
  m_pcv = nullptr;
415
0
}
416
417
void BestEncInfoCache::init( const Slice &slice )
418
3.78k
{
419
3.78k
  if( !m_reuseCuResults ) return;
420
421
0
  bool isInitialized = m_pcv;
422
423
0
  m_pcv = slice.pps->pcv;
424
425
0
  if( isInitialized ) return;
426
427
0
  m_dummyCS.pcv = m_pcv;
428
0
}
429
430
bool BestEncInfoCache::setFromCs( const CodingStructure& cs, const EncTestMode& testMode, const Partitioner& partitioner )
431
83.3k
{
432
83.3k
  if( !m_reuseCuResults ) return false;
433
434
0
  if( cs.cus.size() != 1 || cs.tus.size() != 1 || partitioner.maxBTD <= 1 )
435
0
  {
436
0
    return false;
437
0
  }
438
439
0
  unsigned idx1, idx2, idx3, idx4;
440
0
  getAreaIdxNew( cs.area.Y(), *m_pcv, idx1, idx2, idx3, idx4 );
441
442
0
  BestEncodingInfo& encInfo = *m_bestEncInfo[idx1][idx2][idx3][idx4];
443
444
0
  encInfo.poc            =  cs.picture->poc;
445
0
  encInfo.cu.UnitArea::operator= ( *cs.cus.front() );
446
0
  encInfo.tu.UnitArea::operator= ( *cs.tus.front() );
447
0
  encInfo.cu             = *cs.cus.front();
448
0
  for( auto &blk : cs.tus.front()->blocks )
449
0
  {
450
0
    if( blk.valid() ) encInfo.tu.copyComponentFrom( *cs.tus.front(), blk.compID );
451
0
  }
452
0
  encInfo.testMode       = testMode;
453
0
  encInfo.dist           = cs.dist;
454
0
  encInfo.costEDO        = cs.costDbOffset;
455
456
0
  return true;
457
0
}
458
459
bool BestEncInfoCache::isReusingCuValid( const CodingStructure& cs, const Partitioner& partitioner, int qp )
460
214k
{
461
214k
  if( !m_reuseCuResults || partitioner.treeType == TREE_C || partitioner.maxBTD <= 1 )
462
214k
  {
463
214k
    return false; //if save & load is allowed for chroma CUs, we should check whether luma info (pred, recon, etc) is the same, which is quite complex
464
214k
  }
465
466
0
  unsigned idx1, idx2, idx3, idx4;
467
0
  getAreaIdxNew( cs.area.Y(), *m_pcv, idx1, idx2, idx3, idx4 );
468
469
0
  BestEncodingInfo& encInfo = *m_bestEncInfo[idx1][idx2][idx3][idx4];
470
471
0
  if( encInfo.cu.treeType != partitioner.treeType || encInfo.cu.modeType != partitioner.modeType )
472
0
  {
473
0
    return false;
474
0
  }
475
0
  if( encInfo.cu.qp != qp )
476
0
    return false;
477
0
  if( cs.picture->poc != encInfo.poc 
478
0
    || CS::getArea( cs, cs.area, partitioner.chType, partitioner.treeType ) != CS::getArea( cs, encInfo.cu, partitioner.chType, partitioner.treeType ) 
479
0
    || !isTheSameNbHood( encInfo.cu, cs, partitioner, (cs.picture->Y().width), (cs.picture->Y().height))
480
0
    || CU::isIBC(encInfo.cu)
481
0
    || partitioner.currQgEnable() || cs.currQP[partitioner.chType] != encInfo.cu.qp
482
0
    )
483
0
  {
484
0
    return false;
485
0
  }
486
0
  else
487
0
  {
488
0
    return true;
489
0
  }
490
0
}
491
492
bool BestEncInfoCache::setCsFrom( CodingStructure& cs, EncTestMode& testMode, const Partitioner& partitioner ) const
493
0
{
494
0
  if( !m_reuseCuResults ) return false;
495
496
0
  unsigned idx1, idx2, idx3, idx4;
497
0
  getAreaIdxNew( cs.area.Y(), *m_pcv, idx1, idx2, idx3, idx4 );
498
499
0
  BestEncodingInfo& encInfo = *m_bestEncInfo[idx1][idx2][idx3][idx4];
500
501
0
  if( cs.picture->poc != encInfo.poc 
502
0
    || CS::getArea( cs, cs.area, partitioner.chType, partitioner.treeType ) != CS::getArea( cs, encInfo.cu, partitioner.chType, partitioner.treeType ) 
503
0
    || !isTheSameNbHood( encInfo.cu, cs, partitioner, (cs.picture->Y().width), (cs.picture->Y().height))
504
0
    || partitioner.currQgEnable() || cs.currQP[partitioner.chType] != encInfo.cu.qp
505
0
    )
506
0
  {
507
0
    return false;
508
0
  }
509
510
0
  const UnitArea ua = CS::getArea( cs, cs.area, partitioner.chType, partitioner.treeType );
511
0
  CodingUnit     &cu = cs.addCU( ua, partitioner.chType );
512
0
  cu.treeType = partitioner.treeType;
513
0
  cu.modeType = partitioner.modeType;
514
0
  cu.initPuData();
515
0
  TransformUnit  &tu = cs.addTU( ua, partitioner.chType, &cu );
516
517
0
  cu          .repositionTo( encInfo.cu );
518
0
  cu          .repositionTo( encInfo.cu );
519
0
  tu          .repositionTo( encInfo.tu );
520
521
0
  cu          = encInfo.cu;
522
0
  cu          = encInfo.cu;
523
0
  for( auto &blk : tu.blocks )
524
0
  {
525
0
    if( blk.valid() ) tu.copyComponentFrom( encInfo.tu, blk.compID );
526
0
  }
527
528
0
  testMode    = encInfo.testMode;
529
0
  cs.dist     = encInfo.dist;
530
0
  cs.costDbOffset = encInfo.costEDO;
531
0
  return true;
532
0
}
533
534
535
//////////////////////////////////////////////////////////////////////////
536
// EncModeCtrl
537
//////////////////////////////////////////////////////////////////////////
538
void EncModeCtrl::init( const VVEncCfg& encCfg, RdCost* pRdCost )
539
19.4k
{
540
19.4k
  m_pcEncCfg = &encCfg;
541
19.4k
  m_pcRdCost = pRdCost;
542
19.4k
  comprCUCtx = nullptr;
543
544
19.4k
  CacheBlkInfoCtrl::create( encCfg.m_CTUSize );
545
19.4k
  BestEncInfoCache::create( encCfg.m_reuseCuResults, encCfg.m_internChromaFormat, encCfg.m_CTUSize );
546
19.4k
}
547
548
void EncModeCtrl::destroy()
549
19.4k
{
550
19.4k
  CacheBlkInfoCtrl::destroy();
551
19.4k
  BestEncInfoCache::destroy();
552
19.4k
}
553
554
void EncModeCtrl::initCTUEncoding( const Slice &slice, int tileIdx )
555
3.78k
{
556
3.78k
  CacheBlkInfoCtrl::init( slice );
557
3.78k
  BestEncInfoCache::init( slice );
558
559
3.78k
  CHECK( !m_ComprCUCtxList.empty(), "Mode list is not empty at the beginning of a CTU" );
560
561
3.78k
  if( m_pcEncCfg->m_fastQtBtEnc )
562
3.78k
  {
563
3.78k
    m_skipThresholdE0023FastEnc = ((slice.getMinPictureDistance() <= PICTURE_DISTANCE_TH) ? FAST_SKIP_DEPTH : SKIP_DEPTH);
564
3.78k
  }
565
0
  else
566
0
  {
567
0
    m_skipThresholdE0023FastEnc = SKIP_DEPTH;
568
0
  }
569
570
3.78k
  m_tileIdx = tileIdx;
571
3.78k
}
572
573
void EncModeCtrl::initCULevel( Partitioner &partitioner, const CodingStructure& cs, int  MergeSimpleFlag)
574
131k
{
575
  // Min/max depth
576
131k
  unsigned minDepth = 0;
577
131k
  unsigned maxDepth = cs.pcv->getMaxDepth( cs.slice->sliceType, partitioner.chType );
578
131k
  if( m_pcEncCfg->m_useFastLCTU )
579
131k
  {
580
131k
    partitioner.setMaxMinDepth(minDepth, maxDepth, cs, cs.picture->useQtbttSpeedUpMode, MergeSimpleFlag);
581
131k
  }
582
583
131k
  minDepth = std::max<unsigned>( minDepth, cs.pcv->getMinDepth( cs.slice->sliceType, partitioner.chType ) );
584
131k
  maxDepth = std::min<unsigned>( maxDepth, cs.pcv->getMaxDepth( cs.slice->sliceType, partitioner.chType ) );
585
586
131k
  m_ComprCUCtxList.push_back( ComprCUCtx( cs, minDepth, maxDepth ) );
587
131k
  comprCUCtx = &m_ComprCUCtxList.back();
588
589
131k
  const CodingUnit* cuLeft  = cs.getCURestricted( cs.area.blocks[partitioner.chType].pos().offset( -1, 0 ), cs.area.blocks[partitioner.chType].pos(), cs.slice->independentSliceIdx, m_tileIdx, partitioner.chType, partitioner.treeType );
590
131k
  const CodingUnit* cuAbove = cs.getCURestricted( cs.area.blocks[partitioner.chType].pos().offset( 0, -1 ), cs.area.blocks[partitioner.chType].pos(), cs.slice->independentSliceIdx, m_tileIdx, partitioner.chType, partitioner.treeType );
591
592
131k
  const bool qtBeforeBt = ( (  cuLeft  &&  cuAbove  && cuLeft ->qtDepth > partitioner.currQtDepth && cuAbove->qtDepth > partitioner.currQtDepth )
593
129k
                         || (  cuLeft  && !cuAbove  && cuLeft ->qtDepth > partitioner.currQtDepth )
594
127k
                         || ( !cuLeft  &&  cuAbove  && cuAbove->qtDepth > partitioner.currQtDepth )
595
124k
                         || ( !cuAbove && !cuLeft   && cs.area.lwidth() >= ( 32 << cs.slice->TLayer ) )
596
110k
                         || ( m_pcEncCfg->m_qtbttSpeedUp > 1 && partitioner.maxBTD < ( ( cs.slice->isIntra() && !cs.sps->IBC ) ? 3 : 2 ) ) )
597
20.9k
                         && ( cs.area.lwidth() > ( cs.pcv->getMinQtSize( *cs.slice, partitioner.chType ) << 1 ) );
598
599
  // set features
600
131k
  ComprCUCtx &cuECtx    = *comprCUCtx;
601
131k
  cuECtx.qtBeforeBt     = qtBeforeBt;
602
131k
  cuECtx.doTriHorzSplit = true;
603
131k
  cuECtx.doTriVertSplit = true;
604
131k
  cuECtx.doMoreSplits   = 3;
605
131k
  cuECtx.isReusingCu    = isReusingCuValid( cs, partitioner, cs.baseQP );
606
131k
  cuECtx.didHorzSplit   = partitioner.canSplit( CU_HORZ_SPLIT, cs );
607
131k
  cuECtx.didVertSplit   = partitioner.canSplit( CU_VERT_SPLIT, cs );
608
131k
  cuECtx.doHorChromaSplit = true;
609
131k
  cuECtx.doVerChromaSplit = true;
610
131k
  cuECtx.doQtChromaSplit  = true;
611
612
131k
  if( m_pcEncCfg->m_contentBasedFastQtbt && cs.pcv->getMaxMTTDepth(*cs.slice, partitioner.chType))
613
131k
  {
614
131k
    const CompArea& currArea = partitioner.currArea().Y();
615
131k
    int cuHeight  = currArea.height;
616
131k
    int cuWidth   = currArea.width;
617
618
131k
    const bool condIntraInter = m_pcEncCfg->m_IntraPeriod == 1 ? ( partitioner.currBtDepth == 0 ) : ( cuHeight > 32 && cuWidth > 32 );
619
620
131k
    if( cuWidth == cuHeight && condIntraInter )
621
27.9k
    {
622
27.9k
      const CPelBuf bufCurrArea = cs.getOrgBuf( partitioner.currArea().block( COMP_Y ) );
623
624
27.9k
      Intermediate_Int horVal = 0;
625
27.9k
      Intermediate_Int verVal = 0;
626
27.9k
      Intermediate_Int dupVal = 0;
627
27.9k
      Intermediate_Int dowVal = 0;
628
629
27.9k
      unsigned j, k;
630
631
2.24M
      for( k = 0; k < cuHeight - 1; k++ )
632
2.21M
      {
633
202M
        for( j = 0; j < cuWidth - 1; j++ )
634
200M
        {
635
200M
          horVal += abs( bufCurrArea.at( j + 1, k     ) - bufCurrArea.at( j, k ) );
636
200M
          verVal += abs( bufCurrArea.at( j    , k + 1 ) - bufCurrArea.at( j, k ) );
637
200M
          dowVal += abs( bufCurrArea.at( j + 1, k )     - bufCurrArea.at( j, k + 1 ) );
638
200M
          dupVal += abs( bufCurrArea.at( j + 1, k + 1 ) - bufCurrArea.at( j, k ) );
639
200M
        }
640
2.21M
      }
641
642
27.9k
      cuECtx.grad_horVal = (double)horVal;
643
27.9k
      cuECtx.grad_verVal = (double)verVal;
644
27.9k
      cuECtx.grad_dowVal = (double)dowVal;
645
27.9k
      cuECtx.grad_dupVal = (double)dupVal;
646
27.9k
    }
647
131k
  }
648
131k
}
649
650
void EncModeCtrl::finishCULevel( Partitioner &partitioner )
651
131k
{
652
131k
  m_ComprCUCtxList.pop_back();
653
131k
  comprCUCtx = m_ComprCUCtxList.size() ? &m_ComprCUCtxList.back() : nullptr;
654
131k
}
655
656
bool EncModeCtrl::trySplit( const EncTestMode& encTestmode, const CodingStructure &cs, Partitioner& partitioner, const EncTestMode& lastTestmode )
657
319k
{
658
319k
  ComprCUCtx& cuECtx = *comprCUCtx;
659
660
319k
  const PartSplit implicitSplit = partitioner.getImplicitSplit( cs );
661
319k
  const bool isBoundary         = implicitSplit != CU_DONT_SPLIT;
662
663
319k
  if( ( m_pcEncCfg->m_IntraPeriod == 1 ) && ( partitioner.chType == CH_C ) && ( !cuECtx.doQtChromaSplit ) )
664
0
  {
665
0
    cuECtx.maxDepth         = partitioner.currDepth;
666
0
  }
667
668
319k
  if( isBoundary )
669
79.5k
  {
670
79.5k
    if( encTestmode.type != ETM_SPLIT_QT )
671
31.5k
    {
672
31.5k
      return getPartSplit( encTestmode ) == implicitSplit;
673
31.5k
    }
674
48.0k
    else
675
48.0k
    {
676
48.0k
      return partitioner.canSplit( CU_QUAD_SPLIT, cs );
677
48.0k
    }
678
79.5k
  }
679
680
240k
  const Slice&           slice       = *cs.slice;
681
240k
  const uint32_t         width       = partitioner.currArea().lumaSize().width;
682
240k
  const CodingStructure *bestCS      = cuECtx.bestCS;
683
240k
  const CodingUnit      *bestCU      = cuECtx.bestCU;
684
685
240k
  if( cuECtx.minDepth > partitioner.currQtDepth && partitioner.canSplit( CU_QUAD_SPLIT, cs ) )
686
0
  {
687
    // enforce QT
688
0
    return encTestmode.type == ETM_SPLIT_QT;
689
0
  }
690
240k
  else if( encTestmode.type == ETM_SPLIT_QT && cuECtx.maxDepth <= partitioner.currQtDepth )
691
1.36k
  {
692
    // don't check this QT depth
693
1.36k
    return false;
694
1.36k
  }
695
696
238k
  CHECK( ! isModeSplit( encTestmode ), "wrong method" );
697
698
  //////////////////////////////////////////////////////////////////////////
699
  // skip-history rule - don't split further if at least for three past levels
700
  //                     in the split tree it was found that skip is the best mode
701
  //////////////////////////////////////////////////////////////////////////
702
238k
  int skipScore = 0;
703
704
238k
  if ((!slice.isIntra() || slice.sps->IBC) && cuECtx.isBestNoSplitSkip )
705
0
  {
706
0
    for( int i = 2; i <= m_ComprCUCtxList.size(); i++ )
707
0
    {
708
0
      if( ( m_ComprCUCtxList.end() - i )->isBestNoSplitSkip )
709
0
      {
710
0
        skipScore += 1;
711
0
      }
712
0
      else
713
0
      {
714
0
        break;
715
0
      }
716
0
    }
717
0
  }
718
719
238k
  const PartSplit split = getPartSplit( encTestmode );
720
238k
  if( !partitioner.canSplit( split, cs ) || skipScore >= 2 || ( skipScore == 1 && m_ComprCUCtxList.size() == 2 ) )
721
61.2k
  {
722
61.2k
    if( split == CU_HORZ_SPLIT ) cuECtx.didHorzSplit = false;
723
61.2k
    if( split == CU_VERT_SPLIT ) cuECtx.didVertSplit = false;
724
61.2k
    if( split == CU_QUAD_SPLIT ) cuECtx.didQuadSplit = false;
725
61.2k
    return false;
726
61.2k
  }
727
728
177k
  if( isChroma( partitioner.chType ) && !cuECtx.doHorChromaSplit && ( split == CU_HORZ_SPLIT || split == CU_TRIH_SPLIT ) )
729
0
  {
730
0
    if( split == CU_HORZ_SPLIT )
731
0
    {
732
0
      cuECtx.didHorzSplit = false;
733
0
    }
734
735
0
    return false;
736
0
  }
737
738
177k
  if( isChroma( partitioner.chType ) && !cuECtx.doVerChromaSplit && ( split == CU_VERT_SPLIT || split == CU_TRIV_SPLIT ) )
739
0
  {
740
0
    if( split == CU_VERT_SPLIT )
741
0
    {
742
0
      cuECtx.didVertSplit = false;
743
0
    }
744
745
0
    return false;
746
0
  }
747
748
177k
  if( m_pcEncCfg->m_contentBasedFastQtbt )
749
177k
  {
750
177k
    const CompArea& currArea = partitioner.currArea().Y();
751
177k
    int cuHeight  = currArea.height;
752
177k
    int cuWidth   = currArea.width;
753
754
177k
    const bool condIntraInter = m_pcEncCfg->m_IntraPeriod == 1 ? ( partitioner.currBtDepth == 0 ) : ( cuHeight > 32 && cuWidth > 32 );
755
756
177k
    if( cuWidth == cuHeight && condIntraInter && split != CU_QUAD_SPLIT )
757
9.70k
    {
758
9.70k
      const double th1 = m_pcEncCfg->m_IntraPeriod == 1 ?  1.2              :  1.0;
759
9.70k
      const double th2 = m_pcEncCfg->m_IntraPeriod == 1 ? (1.2 / sqrt( 2 )) : (1.0 / sqrt( 2 ));
760
761
9.70k
      if( cuECtx.grad_horVal > th1 * cuECtx.grad_verVal && cuECtx.grad_horVal > th2 * cuECtx.grad_dowVal && cuECtx.grad_horVal > th2 * cuECtx.grad_dupVal && ( split == CU_HORZ_SPLIT || split == CU_TRIH_SPLIT ) )
762
0
      {
763
0
        return false;
764
0
      }
765
9.70k
      if( th2 * cuECtx.grad_dupVal < cuECtx.grad_verVal && th2 * cuECtx.grad_dowVal < cuECtx.grad_verVal && th1 * cuECtx.grad_horVal < cuECtx.grad_verVal && ( split == CU_VERT_SPLIT || split == CU_TRIV_SPLIT ) )
766
0
      {
767
0
        return false;
768
0
      }
769
9.70k
    }
770
771
177k
    if( m_pcEncCfg->m_IntraPeriod == 1 && cuWidth <= 32 && cuHeight <= 32 && bestCS && bestCS->tus.size() == 1 && bestCU && bestCU->depth == partitioner.currDepth && partitioner.currBtDepth > 1 && isLuma( partitioner.chType ) )
772
0
    {
773
0
      if( !bestCU->rootCbf )
774
0
      {
775
0
        return false;
776
0
      }
777
0
    }
778
177k
  }
779
780
177k
  if( m_pcEncCfg->m_qtbttSpeedUp > 1 )
781
177k
  {
782
177k
    const int availDepth = cs.pcv->getMaxMTTDepth( slice, partitioner.chType ) - partitioner.currMtDepth;
783
177k
    if( bestCU && bestCU->skip && availDepth <= ( 3 - m_skipThresholdE0023FastEnc ) && !isModeSplit( lastTestmode ) && split != CU_QUAD_SPLIT )
784
0
    {
785
0
      return false;
786
0
    }
787
177k
  }
788
177k
  if( bestCU && bestCU->skip && bestCU->mtDepth >= m_skipThresholdE0023FastEnc && !isModeSplit( lastTestmode ) )
789
0
  {
790
0
    return false;
791
0
  }
792
793
177k
  bool resetFeature = false;
794
795
177k
  switch( split )
796
177k
  {
797
20.7k
    case CU_QUAD_SPLIT:
798
20.7k
      {
799
20.7k
        if( !cuECtx.qtBeforeBt && bestCU )
800
18.5k
        {
801
18.5k
          unsigned maxBTD        = cs.pcv->getMaxMTTDepth( slice, partitioner.chType );
802
18.5k
          const CodingUnit *cuBR = bestCS->cus.back();
803
18.5k
          unsigned height        = partitioner.currArea().lumaSize().height;
804
805
18.5k
          if(((bestCU->btDepth == 0 && maxBTD >= ((slice.isIntra() && !slice.sps->IBC) ? 3 : 2))
806
89
            || (bestCU->btDepth == 1 && cuBR && cuBR->btDepth == 1 && maxBTD >= ((slice.isIntra() && !slice.sps->IBC) ? 4 : 3)))
807
18.4k
            && (width <= MAX_TB_SIZEY && height <= MAX_TB_SIZEY)
808
18.4k
            && cuECtx.didHorzSplit && cuECtx.didVertSplit )
809
14.1k
          {
810
14.1k
            return false;
811
14.1k
          }
812
18.5k
        }
813
6.54k
        if( bestCS )
814
6.54k
        {
815
6.54k
          if( m_pcEncCfg->m_useEarlyCU == 2 && bestCS->cost != MAX_DOUBLE && bestCU && bestCU->skip && cuECtx.nonSkipWasTested && bestCS->cus.size() == 1 )
816
0
          {
817
0
            return false;
818
0
          }
819
820
6.54k
          int stopSplit = (m_pcEncCfg->m_FastInferMerge >> 4) && (bestCS->slice->TLayer > 4);
821
6.54k
          int limitBLsize = stopSplit ? 2048 : 1024;
822
6.54k
          if((m_pcEncCfg->m_useEarlyCU == 1 || stopSplit) && bestCS->cost != MAX_DOUBLE && bestCU && bestCU->skip && partitioner.currArea().lumaSize().area() < limitBLsize )
823
0
          {
824
0
            return false;
825
0
          }
826
6.54k
        }
827
6.54k
      }
828
6.54k
      break;
829
54.6k
    case CU_HORZ_SPLIT:
830
104k
    case CU_VERT_SPLIT:
831
104k
      resetFeature = true;
832
104k
      break;
833
29.1k
    case CU_TRIH_SPLIT:
834
29.1k
      if( cuECtx.didHorzSplit && bestCU && bestCU->btDepth == partitioner.currBtDepth && !bestCU->rootCbf )
835
23.5k
      {
836
23.5k
        return false;
837
23.5k
      }
838
839
5.63k
      if( m_pcEncCfg->m_qtbttSpeedUp > 1 )
840
5.63k
      {
841
        //unsigned maxBTD = cs.pcv->getMaxMTTDepth( slice, partitioner.chType );
842
5.63k
        if( /*maxBTD == 1 && */cuECtx.didHorzSplit && cuECtx.didVertSplit && cuECtx.bestCostHorzSplit > cuECtx.bestCostVertSplit )
843
1.63k
        {
844
1.63k
          return false;
845
1.63k
        }
846
5.63k
      }
847
848
3.99k
      if( !cuECtx.doTriHorzSplit )
849
17
      {
850
17
        return false;
851
17
      }
852
853
3.98k
      if (m_pcEncCfg->m_fastTTSplit && cuECtx.bestCostHorzSplit < MAX_DOUBLE)
854
2.95k
      {
855
2.95k
        if (cuECtx.bestCostBeforeSplit < MAX_DOUBLE && (cuECtx.bestCostHorzSplit > m_pcEncCfg->m_fastTT_th * cuECtx.bestCostBeforeSplit))
856
2.44k
        {
857
2.44k
          return false;
858
2.44k
        }
859
507
        if (cuECtx.bestCostVertSplit < MAX_DOUBLE && (cuECtx.bestCostHorzSplit > m_pcEncCfg->m_fastTT_th * cuECtx.bestCostVertSplit))
860
0
        {
861
0
          return false;
862
0
        }
863
507
      }
864
1.53k
      break;
865
23.0k
    case CU_TRIV_SPLIT:
866
23.0k
      if( cuECtx.didVertSplit && bestCU && bestCU->btDepth == partitioner.currBtDepth && !bestCU->rootCbf )
867
19.5k
      {
868
19.5k
        return false;
869
19.5k
      }
870
871
3.47k
      if( m_pcEncCfg->m_qtbttSpeedUp > 1 )
872
3.47k
      {
873
        //unsigned maxBTD = cs.pcv->getMaxMTTDepth( slice, partitioner.chType );
874
3.47k
        if( /*maxBTD == 1 && */cuECtx.didHorzSplit && cuECtx.didVertSplit && cuECtx.bestCostHorzSplit < cuECtx.bestCostVertSplit )
875
1.93k
        {
876
1.93k
          return false;
877
1.93k
        }
878
3.47k
      }
879
880
1.53k
      if( !cuECtx.doTriVertSplit )
881
35
      {
882
35
        return false;
883
35
      }
884
885
1.50k
      if (m_pcEncCfg->m_fastTTSplit && cuECtx.bestCostVertSplit < MAX_DOUBLE)
886
517
      {
887
517
        if (cuECtx.bestCostBeforeSplit < MAX_DOUBLE && (cuECtx.bestCostVertSplit > m_pcEncCfg->m_fastTT_th * cuECtx.bestCostBeforeSplit))
888
338
        {
889
338
          return false;
890
338
        }
891
179
        if (cuECtx.bestCostHorzSplit < MAX_DOUBLE && (cuECtx.bestCostVertSplit > m_pcEncCfg->m_fastTT_th * cuECtx.bestCostHorzSplit))
892
0
        {
893
0
          return false;
894
0
        }
895
179
      }
896
1.16k
      break;
897
1.16k
    default:
898
0
      THROW( "Only CU split modes are governed by the EncModeCtrl" );
899
0
      return false;
900
0
      break;
901
177k
  }
902
903
113k
  switch( split )
904
113k
  {
905
54.6k
    case CU_HORZ_SPLIT:
906
56.1k
    case CU_TRIH_SPLIT:
907
56.1k
      if( cuECtx.qtBeforeBt && cuECtx.didQuadSplit )
908
1.82k
      {
909
1.82k
        if( cuECtx.maxQtSubDepth > partitioner.currQtDepth + 1 )
910
0
        {
911
0
          if( resetFeature ) cuECtx.didHorzSplit = false;
912
0
          return false;
913
0
        }
914
1.82k
      }
915
56.1k
      break;
916
56.1k
    case CU_VERT_SPLIT:
917
51.0k
    case CU_TRIV_SPLIT:
918
51.0k
      if( cuECtx.qtBeforeBt && cuECtx.didQuadSplit )
919
1.89k
      {
920
1.89k
        if( cuECtx.maxQtSubDepth > partitioner.currQtDepth + 1 )
921
0
        {
922
0
          if( resetFeature ) cuECtx.didVertSplit = false;
923
0
          return false;
924
0
        }
925
1.89k
      }
926
51.0k
      break;
927
51.0k
    default:
928
6.54k
      break;
929
113k
  }
930
931
113k
  if( split == CU_QUAD_SPLIT )
932
6.54k
  {
933
6.54k
    cuECtx.didQuadSplit = m_pcEncCfg->m_qtbttSpeedUp <= 1 || !!cuECtx.doMoreSplits;
934
6.54k
  }
935
936
113k
  return m_pcEncCfg->m_qtbttSpeedUp <= 1 || !!cuECtx.doMoreSplits;
937
113k
}
938
939
bool EncModeCtrl::tryMode( const EncTestMode& encTestmode, const CodingStructure &cs, Partitioner& partitioner )
940
134k
{
941
134k
  CHECK( isModeSplit( encTestmode ), "wrong method");
942
943
134k
  ComprCUCtx& cuECtx = m_ComprCUCtxList.back();
944
945
134k
  if( cuECtx.minDepth > partitioner.currQtDepth && partitioner.canSplit( CU_QUAD_SPLIT, cs ) )
946
0
  {
947
    // enforce QT
948
0
    return false;
949
0
  }
950
951
134k
  const Slice&           slice        = *cs.slice;
952
134k
  const uint32_t         numComp      = getNumberValidComponents( slice.sps->chromaFormatIdc );
953
134k
  const CodedCUInfo      &relatedCU   = getBlkInfo( partitioner.currArea() );
954
134k
  const Area             &lumaArea    = partitioner.currArea().Y();
955
134k
  const CodingStructure* bestCS       = cuECtx.bestCS;
956
134k
  const EncTestMode      bestMode     = bestCS ?cuECtx.bestMode : EncTestMode();
957
958
134k
  if( encTestmode.type == ETM_INTRA )
959
83.3k
  {
960
    // if this is removed, the IntraSearch::xIntraCodingLumaQT needs to be adapted to support Intra TU split
961
    // also isXXAvailable in IntraPrediction.cpp need to be fixed to check availability within the same CU without isDecomp
962
83.3k
    if (m_pcEncCfg->m_FastInferMerge && !slice.isIntra() && !slice.isIRAP() && !(cs.area.lwidth() == 4 && cs.area.lheight() == 4) && !partitioner.isConsIntra())
963
0
    {
964
0
      if (bestCS && (bestCS->slice->TLayer > (m_pcEncCfg->m_maxTLayer - (m_pcEncCfg->m_FastInferMerge & 7)))
965
0
        && (bestCS->bestParent != nullptr) && bestCS->bestParent->cus.size() && (bestCS->bestParent->cus[0]->skip))
966
0
      {
967
0
        return false;
968
0
      }
969
0
    }
970
971
83.3k
    if( lumaArea.width > cs.sps->getMaxTbSize() || lumaArea.height > cs.sps->getMaxTbSize() )
972
0
    {
973
0
      return false;
974
0
    }
975
976
83.3k
    if (m_pcEncCfg->m_usePbIntraFast && (!cs.slice->isIntra() || cs.slice->sps->IBC) && cuECtx.interHad == 0 && cuECtx.bestCU && !CU::isIntra(*cuECtx.bestCU))
977
0
    {
978
0
      return false;
979
0
    }
980
981
    // INTRA MODES
982
83.3k
    if (cs.sps->IBC && !cuECtx.bestTU)
983
60.6k
    {
984
     // return true;
985
60.6k
    }
986
22.6k
    else
987
22.6k
    if( partitioner.isConsIntra() && !cuECtx.bestTU )
988
0
    {
989
      //return true;
990
0
    }
991
22.6k
    else
992
22.6k
    if ( lumaArea.width == 4 && lumaArea.height == 4 && !slice.isIntra() && !cuECtx.bestTU )
993
0
    {
994
      //return true;
995
0
    }
996
22.6k
    else
997
22.6k
    if (!(slice.isIRAP() || bestMode.type == ETM_INTRA || !cuECtx.bestTU ||
998
0
      ((!m_pcEncCfg->m_bDisableIntraCUsInInterSlices) && (!relatedCU.isInter || !relatedCU.isIBC) && (
999
0
                                    ( cuECtx.bestTU->cbf[0] != 0 ) ||
1000
0
           ( ( numComp > COMP_Cb ) && cuECtx.bestTU->cbf[1] != 0 ) ||
1001
0
           ( ( numComp > COMP_Cr ) && cuECtx.bestTU->cbf[2] != 0 )  // avoid very complex intra if it is unlikely
1002
0
         ) ) ) )
1003
0
    {
1004
0
      return false;
1005
0
    }
1006
22.6k
    else
1007
22.6k
    if( cuECtx.bestCS && cuECtx.bestCU && cuECtx.interHad )
1008
22.6k
    {
1009
      // Get SATD threshold from best Inter-CU
1010
22.6k
      if( !cs.slice->isIRAP() && m_pcEncCfg->m_usePbIntraFast )
1011
0
      {
1012
0
        const DFunc dfunc = DF_HAD;
1013
0
        DistParam distParam = m_pcRdCost->setDistParam( cs.getOrgBuf( COMP_Y ), cuECtx.bestCS->getPredBuf( COMP_Y ), cs.sps->bitDepths[ CH_L ], dfunc );
1014
0
        cuECtx.interHad = distParam.distFunc( distParam );
1015
0
      }
1016
22.6k
    }
1017
83.3k
    if ((m_pcEncCfg->m_IBCFastMethod > 1) && !cs.slice->isIntra()//IBC_FAST_METHOD_NOINTRA_IBCCBF0
1018
0
      && (bestMode.type == ETM_IBC || bestMode.type == ETM_IBC_MERGE)
1019
0
      && (!cuECtx.bestCU->Y().valid() || cuECtx.bestTU->cbf[0] == 0)
1020
0
      && (!cuECtx.bestCU->Cb().valid() || cuECtx.bestTU->cbf[1] == 0)
1021
0
      && (!cuECtx.bestCU->Cr().valid() || cuECtx.bestTU->cbf[2] == 0))
1022
0
    {
1023
0
      return false;
1024
0
    }
1025
83.3k
    if (m_pcEncCfg->m_FastIntraTools)
1026
83.3k
    {
1027
83.3k
      if (relatedCU.relatedCuIsValid)
1028
13.8k
      {
1029
13.8k
        cuECtx.relatedCuIsValid = relatedCU.relatedCuIsValid;
1030
13.8k
      }
1031
83.3k
      if (relatedCU.isIntra)
1032
22.9k
      {
1033
22.9k
        cuECtx.isIntra = relatedCU.isIntra;
1034
22.9k
      }
1035
83.3k
    }
1036
83.3k
  }
1037
50.8k
  else if( isModeInter( encTestmode ) )
1038
0
  {
1039
    // INTER MODES (ME + MERGE/SKIP)
1040
0
    CHECK( slice.isIntra(), "Inter-mode should not be in the I-Slice mode list!" );
1041
1042
    // --- Check if we can quit current mode using SAVE/LOAD coding history
1043
1044
0
    if( encTestmode.type == ETM_INTER_ME )
1045
0
    {
1046
0
      if( encTestmode.opts == ETO_STANDARD )
1047
0
      {
1048
0
        if (m_pcEncCfg->m_FastInferMerge)
1049
0
        {
1050
0
          if (bestCS && (bestCS->slice->TLayer > (m_pcEncCfg->m_maxTLayer - (m_pcEncCfg->m_FastInferMerge & 7)))
1051
0
            && (bestCS->bestParent != nullptr) && bestCS->bestParent->cus.size() && (bestCS->bestParent->cus[0]->skip))
1052
0
          {
1053
0
            return false;
1054
0
          }
1055
0
        }
1056
0
        if( relatedCU.isSkip || relatedCU.isIntra )
1057
0
        {
1058
0
          return false;
1059
0
        }
1060
0
      }
1061
0
    }
1062
0
  }
1063
50.8k
  else if (encTestmode.type == ETM_IBC || encTestmode.type == ETM_IBC_MERGE)
1064
50.8k
  {
1065
50.8k
    if ((m_pcEncCfg->m_IBCFastMethod > 1) && !(slice.isIRAP() || bestMode.type == ETM_INTRA || !cuECtx.bestTU ||
1066
0
      ((!m_pcEncCfg->m_bDisableIntraCUsInInterSlices) && (!relatedCU.isInter || !relatedCU.isIBC) && (
1067
0
        (cuECtx.bestTU->cbf[0] != 0) ||
1068
0
        ((numComp > COMP_Cb) && cuECtx.bestTU->cbf[1] != 0) ||
1069
0
        ((numComp > COMP_Cr) && cuECtx.bestTU->cbf[2] != 0)  // avoid very complex intra if it is unlikely
1070
0
        ))))
1071
0
    {
1072
0
      return false;
1073
0
    }
1074
50.8k
    if ((m_pcEncCfg->m_IBCFastMethod > 3) &&(lumaArea.width == 4 && lumaArea.height == 4 && !slice.isIntra()))
1075
0
    {
1076
0
      return false;
1077
0
    }
1078
    // IBC MODES
1079
50.8k
    return slice.sps->IBC && (partitioner.currArea().lumaSize().width < 128 && partitioner.currArea().lumaSize().height < 128);
1080
50.8k
  }
1081
0
  else
1082
0
  {
1083
0
    THROW("problem");
1084
0
    return false;
1085
0
  }
1086
1087
83.3k
  STAT_COUNT_CU_MODES( partitioner.chType == CH_L, g_cuCounters1D[CU_MODES_TRIED][0][!cs.slice->isIntra() + cs.slice->depth] );
1088
83.3k
  STAT_COUNT_CU_MODES( partitioner.chType == CH_L && !cs.slice->isIntra(), g_cuCounters2D[CU_MODES_TRIED][Log2( cs.area.lheight() )][Log2( cs.area.lwidth() )] );
1089
83.3k
  return true;
1090
134k
}
1091
1092
1093
void EncModeCtrl::beforeSplit( Partitioner& partitioner )
1094
83.3k
{
1095
83.3k
  ComprCUCtx&           cuECtx  = m_ComprCUCtxList.back();
1096
1097
83.3k
  if( ! cuECtx.bestCS )
1098
0
    return;
1099
1100
83.3k
  CodedCUInfo    &relatedCU   = getBlkInfo( partitioner.currArea() );
1101
83.3k
  const CodingUnit&  bestCU   = *cuECtx.bestCU;
1102
1103
83.3k
  cuECtx.bestNsPredMode       = cuECtx.bestMode;
1104
83.3k
  cuECtx.bestCostBeforeSplit  = cuECtx.bestCS->cost;
1105
1106
83.3k
  setFromCs( *cuECtx.bestCS, cuECtx.bestMode, partitioner );
1107
1108
83.3k
  if( bestCU.skip )
1109
0
  {
1110
0
    cuECtx.doMoreSplits--;
1111
0
  }
1112
1113
83.3k
  if( partitioner.modeType == MODE_TYPE_INTRA && partitioner.chType == CH_L )
1114
0
  {
1115
0
    return; //not set best coding mode for intra coding pass
1116
0
  }
1117
1118
  // assume the non-split modes are done and set the marks for the best found mode
1119
83.3k
  if( CU::isInter( bestCU ) )
1120
0
  {
1121
0
    relatedCU.isInter     = true;
1122
0
    relatedCU.isSkip     |= bestCU.skip;
1123
0
    relatedCU.isMMVDSkip |= bestCU.mmvdSkip;
1124
0
    relatedCU.BcwIdx      = bestCU.BcwIdx;
1125
0
  }
1126
83.3k
  else if (CU::isIBC(bestCU))
1127
0
  {
1128
0
    relatedCU.isIBC = true;
1129
0
    relatedCU.isSkip |= bestCU.skip;
1130
0
  }
1131
83.3k
  else if( CU::isIntra( bestCU ) )
1132
83.3k
  {
1133
83.3k
    relatedCU.isIntra     = true;
1134
83.3k
    if (m_pcEncCfg->m_FastIntraTools)
1135
83.3k
    {
1136
83.3k
      if ( cuECtx.intraWasTested && (!relatedCU.relatedCuIsValid || cuECtx.bestCS->cost < relatedCU.bestCost))
1137
25.4k
      {
1138
25.4k
        relatedCU.bestCost = cuECtx.bestCS->cost;
1139
25.4k
        relatedCU.relatedCuIsValid = true;
1140
25.4k
      }
1141
83.3k
    }
1142
83.3k
  }
1143
83.3k
  cuECtx.isBestNoSplitSkip = bestCU.skip;
1144
83.3k
}
1145
1146
1147
bool EncModeCtrl::useModeResult( const EncTestMode& encTestmode, CodingStructure*& tempCS, Partitioner& partitioner, const bool useEDO )
1148
173k
{
1149
173k
  ComprCUCtx& cuECtx = m_ComprCUCtxList.back();
1150
1151
1152
173k
  if(      encTestmode.type == ETM_SPLIT_BT_H )
1153
24.5k
  {
1154
24.5k
    cuECtx.bestCostHorzSplit = tempCS->cost;
1155
24.5k
  }
1156
149k
  else if( encTestmode.type == ETM_SPLIT_BT_V )
1157
23.9k
  {
1158
23.9k
    cuECtx.bestCostVertSplit = tempCS->cost;
1159
23.9k
  }
1160
125k
  else if( !isModeSplit( encTestmode ) && isModeInter( encTestmode ) && tempCS->cus.size() == 1 )
1161
0
  {
1162
0
    cuECtx.nonSkipWasTested |= !tempCS->cus.front()->skip;
1163
0
  }
1164
173k
  if (m_pcEncCfg->m_AMVRspeed && encTestmode.type == ETM_INTER_ME)
1165
0
  {
1166
0
    int imvMode = (encTestmode.opts & ETO_IMV) >> ETO_IMV_SHIFT;
1167
1168
0
    if (imvMode == 0)
1169
0
    {
1170
0
      if (tempCS->cost < cuECtx.bestCostNoImv )
1171
0
      {
1172
0
        cuECtx.bestCostNoImv = tempCS->cost;
1173
0
      }
1174
0
    }
1175
0
  }
1176
1177
173k
  if( encTestmode.type == ETM_SPLIT_QT )
1178
18.9k
  {
1179
18.9k
    int maxQtD = 0;
1180
18.9k
    for( const auto& cu : tempCS->cus )
1181
75.5k
    {
1182
75.5k
      maxQtD = std::max<int>( maxQtD, cu->qtDepth );
1183
75.5k
    }
1184
18.9k
    cuECtx.maxQtSubDepth = maxQtD;
1185
18.9k
  }
1186
1187
173k
  int maxMtD = tempCS->pcv->getMaxMTTDepth( *tempCS->slice, partitioner.chType ) + partitioner.currImplicitBtDepth;
1188
1189
173k
  if( encTestmode.type == ETM_SPLIT_BT_H )
1190
24.5k
  {
1191
24.5k
    if( tempCS->cus.size() > 2 )
1192
990
    {
1193
990
      int h_2   = tempCS->area.blocks[partitioner.chType].height / 2;
1194
990
      int cu1_h = tempCS->cus.front()->blocks[partitioner.chType].height;
1195
990
      int cu2_h = tempCS->cus.back() ->blocks[partitioner.chType].height;
1196
1197
990
      cuECtx.doTriHorzSplit = cu1_h < h_2 || cu2_h < h_2 || partitioner.currMtDepth + 1 == maxMtD;
1198
990
    }
1199
24.5k
  }
1200
149k
  else if( encTestmode.type == ETM_SPLIT_BT_V )
1201
23.9k
  {
1202
23.9k
    if( tempCS->cus.size() > 2 )
1203
1.01k
    {
1204
1.01k
      int w_2   = tempCS->area.blocks[partitioner.chType].width / 2;
1205
1.01k
      int cu1_w = tempCS->cus.front()->blocks[partitioner.chType].width;
1206
1.01k
      int cu2_w = tempCS->cus.back() ->blocks[partitioner.chType].width;
1207
1208
1.01k
      cuECtx.doTriVertSplit = cu1_w < w_2 || cu2_w < w_2 || partitioner.currMtDepth + 1 == maxMtD;
1209
1.01k
    }
1210
23.9k
  }
1211
1212
173k
  if( encTestmode.type == ETM_SPLIT_BT_V || encTestmode.type == ETM_SPLIT_BT_H || encTestmode.type == ETM_SPLIT_QT )
1213
67.4k
  {
1214
67.4k
    bool isAllSkip = true;
1215
1216
67.4k
    for( const auto& cu : tempCS->cus )
1217
152k
    {
1218
152k
      isAllSkip &= cu->skip;
1219
152k
    }
1220
1221
67.4k
    if( isAllSkip ) cuECtx.doMoreSplits--;
1222
67.4k
    if( isAllSkip && encTestmode.type == ETM_SPLIT_QT )
1223
0
                    cuECtx.doMoreSplits--;
1224
67.4k
  }
1225
1226
  // for now just a simple decision based on RD-cost or choose tempCS if bestCS is not yet coded
1227
173k
  if( tempCS->cost != MAX_DOUBLE && ( !cuECtx.bestCS || ( ( tempCS->cost + ( useEDO ? tempCS->costDbOffset : 0 ) ) < ( cuECtx.bestCS->cost + ( useEDO ? cuECtx.bestCS->costDbOffset : 0 ) ) ) ) )
1228
156k
  {
1229
156k
    cuECtx.bestCS   = tempCS;
1230
156k
    cuECtx.bestCU   = tempCS->cus[0];
1231
156k
    cuECtx.bestTU   = cuECtx.bestCU->firstTU;
1232
156k
    cuECtx.bestMode = encTestmode;
1233
1234
156k
    return true;
1235
156k
  }
1236
16.9k
  else
1237
16.9k
  {
1238
16.9k
    return false;
1239
16.9k
  }
1240
173k
}
1241
1242
} // namespace vvenc
1243
1244
//! \}
1245