Coverage Report

Created: 2026-06-15 06:25

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
17.3k
{
66
17.3k
  const unsigned numPos = MAX_CU_SIZE >> MIN_CU_LOG2;
67
17.3k
  const int maxSizeIdx  = MAX_CU_SIZE_IDX - MIN_CU_LOG2;
68
69
  //static constexpr size_t numCu = 7921;
70
71
17.3k
  size_t numCu = 0;
72
  
73
121k
  for( int wIdx = 0; wIdx < maxSizeIdx; wIdx++ )
74
104k
  {
75
729k
    for( int hIdx = 0; hIdx < maxSizeIdx; hIdx++ )
76
625k
    {
77
20.6M
      for( unsigned y = 0; y < numPos; y++ )
78
20.0M
      {
79
660M
        for( unsigned x = 0; x < numPos; x++ )
80
640M
        {
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
640M
          if( (x + (1 << (wIdx)) <= (ctuSize >> MIN_CU_LOG2))
87
450M
              && (y + (1 << (hIdx)) <= (ctuSize >> MIN_CU_LOG2))
88
316M
              && (((x << MIN_CU_LOG2) & ((1 << (wIdx + MIN_CU_LOG2 - 1)) - 1)) == 0)
89
208M
              && (((y << MIN_CU_LOG2) & ((1 << (hIdx + MIN_CU_LOG2 - 1)) - 1)) == 0) )
90
137M
          {
91
137M
            numCu++;
92
137M
          }
93
640M
        }
94
20.0M
      }
95
625k
    }
96
104k
  }
97
98
17.3k
  m_codedCUInfoBuf = new CodedCUInfo[numCu];
99
17.3k
  CodedCUInfo* cuInfo = m_codedCUInfoBuf;
100
101
121k
  for( int wIdx = 0; wIdx < maxSizeIdx; wIdx++ )
102
104k
  {
103
729k
    for( int hIdx = 0; hIdx < maxSizeIdx; hIdx++ )
104
625k
    {
105
20.6M
      for( unsigned y = 0; y < numPos; y++ )
106
20.0M
      {
107
660M
        for( unsigned x = 0; x < numPos; x++ )
108
640M
        {
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
640M
          if(( x + (1<<(wIdx)) <= ( ctuSize >> MIN_CU_LOG2 ) )
115
450M
            && ( y + (1<<(hIdx)) <= ( ctuSize >> MIN_CU_LOG2 ) )
116
316M
            && ( ( ( x << MIN_CU_LOG2 ) & ((1 << (wIdx + MIN_CU_LOG2 - 1)) - 1) ) == 0 )
117
208M
            && ( ( ( y << MIN_CU_LOG2 ) & ((1 << (hIdx + MIN_CU_LOG2 - 1)) - 1) ) == 0 ) )
118
137M
          {
119
137M
            m_codedCUInfo[wIdx][hIdx][x][y] = cuInfo++;
120
137M
            m_codedCUInfo[wIdx][hIdx][x][y]->poc       = -1;
121
137M
            m_codedCUInfo[wIdx][hIdx][x][y]->ctuRsAddr = -1;
122
137M
          }
123
502M
          else
124
502M
          {
125
502M
            m_codedCUInfo[wIdx][hIdx][x][y] = nullptr;
126
502M
          }
127
640M
        }
128
20.0M
      }
129
625k
    }
130
104k
  }
131
17.3k
}
132
133
void CacheBlkInfoCtrl::destroy()
134
17.3k
{
135
17.3k
  delete[] m_codedCUInfoBuf;
136
17.3k
  m_codedCUInfoBuf = nullptr;
137
17.3k
}
138
139
void CacheBlkInfoCtrl::init( const Slice &slice )
140
3.33k
{
141
3.33k
  m_pcv = slice.pps->pcv;
142
3.33k
}
143
144
void CacheBlkInfoCtrl::initBlk( const UnitArea& area, int poc )
145
116k
{
146
116k
  unsigned idx1, idx2, idx3, idx4;
147
116k
  getAreaIdxNew( area.Y(), *m_pcv, idx1, idx2, idx3, idx4 );
148
149
116k
  const int ctuRsAddr = getCtuAddr( area.lumaPos(), *m_pcv );
150
116k
  CodedCUInfo* cuInfo = m_codedCUInfo[idx1][idx2][idx3][idx4];
151
152
116k
  if( cuInfo->poc != poc || cuInfo->ctuRsAddr != ctuRsAddr )
153
83.3k
  {
154
83.3k
    GCC_WARNING_DISABLE_class_memaccess
155
83.3k
    memset( cuInfo, 0, sizeof( CodedCUInfo ) );
156
83.3k
    GCC_WARNING_RESET
157
158
83.3k
    cuInfo->poc       = poc;
159
83.3k
    cuInfo->ctuRsAddr = ctuRsAddr;
160
83.3k
  }
161
116k
}
162
163
CodedCUInfo& CacheBlkInfoCtrl::getBlkInfo( const UnitArea& area )
164
193k
{
165
193k
  unsigned idx1, idx2, idx3, idx4;
166
193k
  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
193k
  return *m_codedCUInfo[idx1][idx2][idx3][idx4];
169
193k
}
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
17.3k
{
261
17.3k
  m_reuseCuResults = reuseCuResults;
262
263
17.3k
  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
17.3k
{
403
17.3k
  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.33k
{
419
3.33k
  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
74.0k
{
432
74.0k
  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
190k
{
461
190k
  if( !m_reuseCuResults || partitioner.treeType == TREE_C || partitioner.maxBTD <= 1 )
462
190k
  {
463
190k
    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
190k
  }
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
17.3k
{
540
17.3k
  m_pcEncCfg = &encCfg;
541
17.3k
  m_pcRdCost = pRdCost;
542
17.3k
  comprCUCtx = nullptr;
543
544
17.3k
  CacheBlkInfoCtrl::create( encCfg.m_CTUSize );
545
17.3k
  BestEncInfoCache::create( encCfg.m_reuseCuResults, encCfg.m_internChromaFormat, encCfg.m_CTUSize );
546
17.3k
}
547
548
void EncModeCtrl::destroy()
549
17.3k
{
550
17.3k
  CacheBlkInfoCtrl::destroy();
551
17.3k
  BestEncInfoCache::destroy();
552
17.3k
}
553
554
void EncModeCtrl::initCTUEncoding( const Slice &slice, int tileIdx )
555
3.33k
{
556
3.33k
  CacheBlkInfoCtrl::init( slice );
557
3.33k
  BestEncInfoCache::init( slice );
558
559
3.33k
  CHECK( !m_ComprCUCtxList.empty(), "Mode list is not empty at the beginning of a CTU" );
560
561
3.33k
  if( m_pcEncCfg->m_fastQtBtEnc )
562
3.33k
  {
563
3.33k
    m_skipThresholdE0023FastEnc = ((slice.getMinPictureDistance() <= PICTURE_DISTANCE_TH) ? FAST_SKIP_DEPTH : SKIP_DEPTH);
564
3.33k
  }
565
0
  else
566
0
  {
567
0
    m_skipThresholdE0023FastEnc = SKIP_DEPTH;
568
0
  }
569
570
3.33k
  m_tileIdx = tileIdx;
571
3.33k
}
572
573
void EncModeCtrl::initCULevel( Partitioner &partitioner, const CodingStructure& cs, int  MergeSimpleFlag)
574
116k
{
575
  // Min/max depth
576
116k
  unsigned minDepth = 0;
577
116k
  unsigned maxDepth = cs.pcv->getMaxDepth( cs.slice->sliceType, partitioner.chType );
578
116k
  if( m_pcEncCfg->m_useFastLCTU )
579
116k
  {
580
116k
    partitioner.setMaxMinDepth(minDepth, maxDepth, cs, cs.picture->useQtbttSpeedUpMode, MergeSimpleFlag);
581
116k
  }
582
583
116k
  minDepth = std::max<unsigned>( minDepth, cs.pcv->getMinDepth( cs.slice->sliceType, partitioner.chType ) );
584
116k
  maxDepth = std::min<unsigned>( maxDepth, cs.pcv->getMaxDepth( cs.slice->sliceType, partitioner.chType ) );
585
586
116k
  m_ComprCUCtxList.push_back( ComprCUCtx( cs, minDepth, maxDepth ) );
587
116k
  comprCUCtx = &m_ComprCUCtxList.back();
588
589
116k
  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
116k
  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
116k
  const bool qtBeforeBt = ( (  cuLeft  &&  cuAbove  && cuLeft ->qtDepth > partitioner.currQtDepth && cuAbove->qtDepth > partitioner.currQtDepth )
593
114k
                         || (  cuLeft  && !cuAbove  && cuLeft ->qtDepth > partitioner.currQtDepth )
594
112k
                         || ( !cuLeft  &&  cuAbove  && cuAbove->qtDepth > partitioner.currQtDepth )
595
110k
                         || ( !cuAbove && !cuLeft   && cs.area.lwidth() >= ( 32 << cs.slice->TLayer ) )
596
98.1k
                         || ( m_pcEncCfg->m_qtbttSpeedUp > 1 && partitioner.maxBTD < ( ( cs.slice->isIntra() && !cs.sps->IBC ) ? 3 : 2 ) ) )
597
18.5k
                         && ( cs.area.lwidth() > ( cs.pcv->getMinQtSize( *cs.slice, partitioner.chType ) << 1 ) );
598
599
  // set features
600
116k
  ComprCUCtx &cuECtx    = *comprCUCtx;
601
116k
  cuECtx.qtBeforeBt     = qtBeforeBt;
602
116k
  cuECtx.doTriHorzSplit = true;
603
116k
  cuECtx.doTriVertSplit = true;
604
116k
  cuECtx.doMoreSplits   = 3;
605
116k
  cuECtx.isReusingCu    = isReusingCuValid( cs, partitioner, cs.baseQP );
606
116k
  cuECtx.didHorzSplit   = partitioner.canSplit( CU_HORZ_SPLIT, cs );
607
116k
  cuECtx.didVertSplit   = partitioner.canSplit( CU_VERT_SPLIT, cs );
608
116k
  cuECtx.doHorChromaSplit = true;
609
116k
  cuECtx.doVerChromaSplit = true;
610
116k
  cuECtx.doQtChromaSplit  = true;
611
612
116k
  if( m_pcEncCfg->m_contentBasedFastQtbt && cs.pcv->getMaxMTTDepth(*cs.slice, partitioner.chType))
613
116k
  {
614
116k
    const CompArea& currArea = partitioner.currArea().Y();
615
116k
    int cuHeight  = currArea.height;
616
116k
    int cuWidth   = currArea.width;
617
618
116k
    const bool condIntraInter = m_pcEncCfg->m_IntraPeriod == 1 ? ( partitioner.currBtDepth == 0 ) : ( cuHeight > 32 && cuWidth > 32 );
619
620
116k
    if( cuWidth == cuHeight && condIntraInter )
621
24.5k
    {
622
24.5k
      const CPelBuf bufCurrArea = cs.getOrgBuf( partitioner.currArea().block( COMP_Y ) );
623
624
24.5k
      Intermediate_Int horVal = 0;
625
24.5k
      Intermediate_Int verVal = 0;
626
24.5k
      Intermediate_Int dupVal = 0;
627
24.5k
      Intermediate_Int dowVal = 0;
628
629
24.5k
      unsigned j, k;
630
631
1.97M
      for( k = 0; k < cuHeight - 1; k++ )
632
1.95M
      {
633
178M
        for( j = 0; j < cuWidth - 1; j++ )
634
176M
        {
635
176M
          horVal += abs( bufCurrArea.at( j + 1, k     ) - bufCurrArea.at( j, k ) );
636
176M
          verVal += abs( bufCurrArea.at( j    , k + 1 ) - bufCurrArea.at( j, k ) );
637
176M
          dowVal += abs( bufCurrArea.at( j + 1, k )     - bufCurrArea.at( j, k + 1 ) );
638
176M
          dupVal += abs( bufCurrArea.at( j + 1, k + 1 ) - bufCurrArea.at( j, k ) );
639
176M
        }
640
1.95M
      }
641
642
24.5k
      cuECtx.grad_horVal = (double)horVal;
643
24.5k
      cuECtx.grad_verVal = (double)verVal;
644
24.5k
      cuECtx.grad_dowVal = (double)dowVal;
645
24.5k
      cuECtx.grad_dupVal = (double)dupVal;
646
24.5k
    }
647
116k
  }
648
116k
}
649
650
void EncModeCtrl::finishCULevel( Partitioner &partitioner )
651
116k
{
652
116k
  m_ComprCUCtxList.pop_back();
653
116k
  comprCUCtx = m_ComprCUCtxList.size() ? &m_ComprCUCtxList.back() : nullptr;
654
116k
}
655
656
bool EncModeCtrl::trySplit( const EncTestMode& encTestmode, const CodingStructure &cs, Partitioner& partitioner, const EncTestMode& lastTestmode )
657
285k
{
658
285k
  ComprCUCtx& cuECtx = *comprCUCtx;
659
660
285k
  const PartSplit implicitSplit = partitioner.getImplicitSplit( cs );
661
285k
  const bool isBoundary         = implicitSplit != CU_DONT_SPLIT;
662
663
285k
  if( ( m_pcEncCfg->m_IntraPeriod == 1 ) && ( partitioner.chType == CH_C ) && ( !cuECtx.doQtChromaSplit ) )
664
0
  {
665
0
    cuECtx.maxDepth         = partitioner.currDepth;
666
0
  }
667
668
285k
  if( isBoundary )
669
70.7k
  {
670
70.7k
    if( encTestmode.type != ETM_SPLIT_QT )
671
28.0k
    {
672
28.0k
      return getPartSplit( encTestmode ) == implicitSplit;
673
28.0k
    }
674
42.6k
    else
675
42.6k
    {
676
42.6k
      return partitioner.canSplit( CU_QUAD_SPLIT, cs );
677
42.6k
    }
678
70.7k
  }
679
680
214k
  const Slice&           slice       = *cs.slice;
681
214k
  const uint32_t         width       = partitioner.currArea().lumaSize().width;
682
214k
  const CodingStructure *bestCS      = cuECtx.bestCS;
683
214k
  const CodingUnit      *bestCU      = cuECtx.bestCU;
684
685
214k
  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
214k
  else if( encTestmode.type == ETM_SPLIT_QT && cuECtx.maxDepth <= partitioner.currQtDepth )
691
1.18k
  {
692
    // don't check this QT depth
693
1.18k
    return false;
694
1.18k
  }
695
696
213k
  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
213k
  int skipScore = 0;
703
704
213k
  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
213k
  const PartSplit split = getPartSplit( encTestmode );
720
213k
  if( !partitioner.canSplit( split, cs ) || skipScore >= 2 || ( skipScore == 1 && m_ComprCUCtxList.size() == 2 ) )
721
54.4k
  {
722
54.4k
    if( split == CU_HORZ_SPLIT ) cuECtx.didHorzSplit = false;
723
54.4k
    if( split == CU_VERT_SPLIT ) cuECtx.didVertSplit = false;
724
54.4k
    if( split == CU_QUAD_SPLIT ) cuECtx.didQuadSplit = false;
725
54.4k
    return false;
726
54.4k
  }
727
728
158k
  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
158k
  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
158k
  if( m_pcEncCfg->m_contentBasedFastQtbt )
749
158k
  {
750
158k
    const CompArea& currArea = partitioner.currArea().Y();
751
158k
    int cuHeight  = currArea.height;
752
158k
    int cuWidth   = currArea.width;
753
754
158k
    const bool condIntraInter = m_pcEncCfg->m_IntraPeriod == 1 ? ( partitioner.currBtDepth == 0 ) : ( cuHeight > 32 && cuWidth > 32 );
755
756
158k
    if( cuWidth == cuHeight && condIntraInter && split != CU_QUAD_SPLIT )
757
8.47k
    {
758
8.47k
      const double th1 = m_pcEncCfg->m_IntraPeriod == 1 ?  1.2              :  1.0;
759
8.47k
      const double th2 = m_pcEncCfg->m_IntraPeriod == 1 ? (1.2 / sqrt( 2 )) : (1.0 / sqrt( 2 ));
760
761
8.47k
      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
8.47k
      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
8.47k
    }
770
771
158k
    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
158k
  }
779
780
158k
  if( m_pcEncCfg->m_qtbttSpeedUp > 1 )
781
158k
  {
782
158k
    const int availDepth = cs.pcv->getMaxMTTDepth( slice, partitioner.chType ) - partitioner.currMtDepth;
783
158k
    if( bestCU && bestCU->skip && availDepth <= ( 3 - m_skipThresholdE0023FastEnc ) && !isModeSplit( lastTestmode ) && split != CU_QUAD_SPLIT )
784
0
    {
785
0
      return false;
786
0
    }
787
158k
  }
788
158k
  if( bestCU && bestCU->skip && bestCU->mtDepth >= m_skipThresholdE0023FastEnc && !isModeSplit( lastTestmode ) )
789
0
  {
790
0
    return false;
791
0
  }
792
793
158k
  bool resetFeature = false;
794
795
158k
  switch( split )
796
158k
  {
797
18.4k
    case CU_QUAD_SPLIT:
798
18.4k
      {
799
18.4k
        if( !cuECtx.qtBeforeBt && bestCU )
800
16.5k
        {
801
16.5k
          unsigned maxBTD        = cs.pcv->getMaxMTTDepth( slice, partitioner.chType );
802
16.5k
          const CodingUnit *cuBR = bestCS->cus.back();
803
16.5k
          unsigned height        = partitioner.currArea().lumaSize().height;
804
805
16.5k
          if(((bestCU->btDepth == 0 && maxBTD >= ((slice.isIntra() && !slice.sps->IBC) ? 3 : 2))
806
78
            || (bestCU->btDepth == 1 && cuBR && cuBR->btDepth == 1 && maxBTD >= ((slice.isIntra() && !slice.sps->IBC) ? 4 : 3)))
807
16.4k
            && (width <= MAX_TB_SIZEY && height <= MAX_TB_SIZEY)
808
16.4k
            && cuECtx.didHorzSplit && cuECtx.didVertSplit )
809
12.7k
          {
810
12.7k
            return false;
811
12.7k
          }
812
16.5k
        }
813
5.74k
        if( bestCS )
814
5.74k
        {
815
5.74k
          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
5.74k
          int stopSplit = (m_pcEncCfg->m_FastInferMerge >> 4) && (bestCS->slice->TLayer > 4);
821
5.74k
          int limitBLsize = stopSplit ? 2048 : 1024;
822
5.74k
          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
5.74k
        }
827
5.74k
      }
828
5.74k
      break;
829
48.7k
    case CU_HORZ_SPLIT:
830
93.3k
    case CU_VERT_SPLIT:
831
93.3k
      resetFeature = true;
832
93.3k
      break;
833
26.2k
    case CU_TRIH_SPLIT:
834
26.2k
      if( cuECtx.didHorzSplit && bestCU && bestCU->btDepth == partitioner.currBtDepth && !bestCU->rootCbf )
835
21.1k
      {
836
21.1k
        return false;
837
21.1k
      }
838
839
5.05k
      if( m_pcEncCfg->m_qtbttSpeedUp > 1 )
840
5.05k
      {
841
        //unsigned maxBTD = cs.pcv->getMaxMTTDepth( slice, partitioner.chType );
842
5.05k
        if( /*maxBTD == 1 && */cuECtx.didHorzSplit && cuECtx.didVertSplit && cuECtx.bestCostHorzSplit > cuECtx.bestCostVertSplit )
843
1.45k
        {
844
1.45k
          return false;
845
1.45k
        }
846
5.05k
      }
847
848
3.59k
      if( !cuECtx.doTriHorzSplit )
849
13
      {
850
13
        return false;
851
13
      }
852
853
3.58k
      if (m_pcEncCfg->m_fastTTSplit && cuECtx.bestCostHorzSplit < MAX_DOUBLE)
854
2.63k
      {
855
2.63k
        if (cuECtx.bestCostBeforeSplit < MAX_DOUBLE && (cuECtx.bestCostHorzSplit > m_pcEncCfg->m_fastTT_th * cuECtx.bestCostBeforeSplit))
856
2.19k
        {
857
2.19k
          return false;
858
2.19k
        }
859
440
        if (cuECtx.bestCostVertSplit < MAX_DOUBLE && (cuECtx.bestCostHorzSplit > m_pcEncCfg->m_fastTT_th * cuECtx.bestCostVertSplit))
860
0
        {
861
0
          return false;
862
0
        }
863
440
      }
864
1.38k
      break;
865
20.6k
    case CU_TRIV_SPLIT:
866
20.6k
      if( cuECtx.didVertSplit && bestCU && bestCU->btDepth == partitioner.currBtDepth && !bestCU->rootCbf )
867
17.5k
      {
868
17.5k
        return false;
869
17.5k
      }
870
871
3.11k
      if( m_pcEncCfg->m_qtbttSpeedUp > 1 )
872
3.11k
      {
873
        //unsigned maxBTD = cs.pcv->getMaxMTTDepth( slice, partitioner.chType );
874
3.11k
        if( /*maxBTD == 1 && */cuECtx.didHorzSplit && cuECtx.didVertSplit && cuECtx.bestCostHorzSplit < cuECtx.bestCostVertSplit )
875
1.70k
        {
876
1.70k
          return false;
877
1.70k
        }
878
3.11k
      }
879
880
1.41k
      if( !cuECtx.doTriVertSplit )
881
37
      {
882
37
        return false;
883
37
      }
884
885
1.37k
      if (m_pcEncCfg->m_fastTTSplit && cuECtx.bestCostVertSplit < MAX_DOUBLE)
886
472
      {
887
472
        if (cuECtx.bestCostBeforeSplit < MAX_DOUBLE && (cuECtx.bestCostVertSplit > m_pcEncCfg->m_fastTT_th * cuECtx.bestCostBeforeSplit))
888
311
        {
889
311
          return false;
890
311
        }
891
161
        if (cuECtx.bestCostHorzSplit < MAX_DOUBLE && (cuECtx.bestCostVertSplit > m_pcEncCfg->m_fastTT_th * cuECtx.bestCostHorzSplit))
892
0
        {
893
0
          return false;
894
0
        }
895
161
      }
896
1.06k
      break;
897
1.06k
    default:
898
0
      THROW( "Only CU split modes are governed by the EncModeCtrl" );
899
0
      return false;
900
0
      break;
901
158k
  }
902
903
101k
  switch( split )
904
101k
  {
905
48.7k
    case CU_HORZ_SPLIT:
906
50.1k
    case CU_TRIH_SPLIT:
907
50.1k
      if( cuECtx.qtBeforeBt && cuECtx.didQuadSplit )
908
1.62k
      {
909
1.62k
        if( cuECtx.maxQtSubDepth > partitioner.currQtDepth + 1 )
910
0
        {
911
0
          if( resetFeature ) cuECtx.didHorzSplit = false;
912
0
          return false;
913
0
        }
914
1.62k
      }
915
50.1k
      break;
916
50.1k
    case CU_VERT_SPLIT:
917
45.6k
    case CU_TRIV_SPLIT:
918
45.6k
      if( cuECtx.qtBeforeBt && cuECtx.didQuadSplit )
919
1.69k
      {
920
1.69k
        if( cuECtx.maxQtSubDepth > partitioner.currQtDepth + 1 )
921
0
        {
922
0
          if( resetFeature ) cuECtx.didVertSplit = false;
923
0
          return false;
924
0
        }
925
1.69k
      }
926
45.6k
      break;
927
45.6k
    default:
928
5.74k
      break;
929
101k
  }
930
931
101k
  if( split == CU_QUAD_SPLIT )
932
5.74k
  {
933
5.74k
    cuECtx.didQuadSplit = m_pcEncCfg->m_qtbttSpeedUp <= 1 || !!cuECtx.doMoreSplits;
934
5.74k
  }
935
936
101k
  return m_pcEncCfg->m_qtbttSpeedUp <= 1 || !!cuECtx.doMoreSplits;
937
101k
}
938
939
bool EncModeCtrl::tryMode( const EncTestMode& encTestmode, const CodingStructure &cs, Partitioner& partitioner )
940
119k
{
941
119k
  CHECK( isModeSplit( encTestmode ), "wrong method");
942
943
119k
  ComprCUCtx& cuECtx = m_ComprCUCtxList.back();
944
945
119k
  if( cuECtx.minDepth > partitioner.currQtDepth && partitioner.canSplit( CU_QUAD_SPLIT, cs ) )
946
0
  {
947
    // enforce QT
948
0
    return false;
949
0
  }
950
951
119k
  const Slice&           slice        = *cs.slice;
952
119k
  const uint32_t         numComp      = getNumberValidComponents( slice.sps->chromaFormatIdc );
953
119k
  const CodedCUInfo      &relatedCU   = getBlkInfo( partitioner.currArea() );
954
119k
  const Area             &lumaArea    = partitioner.currArea().Y();
955
119k
  const CodingStructure* bestCS       = cuECtx.bestCS;
956
119k
  const EncTestMode      bestMode     = bestCS ?cuECtx.bestMode : EncTestMode();
957
958
119k
  if( encTestmode.type == ETM_INTRA )
959
74.0k
  {
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
74.0k
    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
74.0k
    if( lumaArea.width > cs.sps->getMaxTbSize() || lumaArea.height > cs.sps->getMaxTbSize() )
972
0
    {
973
0
      return false;
974
0
    }
975
976
74.0k
    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
74.0k
    if (cs.sps->IBC && !cuECtx.bestTU)
983
53.8k
    {
984
     // return true;
985
53.8k
    }
986
20.2k
    else
987
20.2k
    if( partitioner.isConsIntra() && !cuECtx.bestTU )
988
0
    {
989
      //return true;
990
0
    }
991
20.2k
    else
992
20.2k
    if ( lumaArea.width == 4 && lumaArea.height == 4 && !slice.isIntra() && !cuECtx.bestTU )
993
0
    {
994
      //return true;
995
0
    }
996
20.2k
    else
997
20.2k
    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
20.2k
    else
1007
20.2k
    if( cuECtx.bestCS && cuECtx.bestCU && cuECtx.interHad )
1008
20.2k
    {
1009
      // Get SATD threshold from best Inter-CU
1010
20.2k
      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
20.2k
    }
1017
74.0k
    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
74.0k
    if (m_pcEncCfg->m_FastIntraTools)
1026
74.0k
    {
1027
74.0k
      if (relatedCU.relatedCuIsValid)
1028
12.4k
      {
1029
12.4k
        cuECtx.relatedCuIsValid = relatedCU.relatedCuIsValid;
1030
12.4k
      }
1031
74.0k
      if (relatedCU.isIntra)
1032
20.4k
      {
1033
20.4k
        cuECtx.isIntra = relatedCU.isIntra;
1034
20.4k
      }
1035
74.0k
    }
1036
74.0k
  }
1037
45.4k
  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
45.4k
  else if (encTestmode.type == ETM_IBC || encTestmode.type == ETM_IBC_MERGE)
1064
45.4k
  {
1065
45.4k
    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
45.4k
    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
45.4k
    return slice.sps->IBC && (partitioner.currArea().lumaSize().width < 128 && partitioner.currArea().lumaSize().height < 128);
1080
45.4k
  }
1081
0
  else
1082
0
  {
1083
0
    THROW("problem");
1084
0
    return false;
1085
0
  }
1086
1087
74.0k
  STAT_COUNT_CU_MODES( partitioner.chType == CH_L, g_cuCounters1D[CU_MODES_TRIED][0][!cs.slice->isIntra() + cs.slice->depth] );
1088
74.0k
  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
74.0k
  return true;
1090
119k
}
1091
1092
1093
void EncModeCtrl::beforeSplit( Partitioner& partitioner )
1094
74.0k
{
1095
74.0k
  ComprCUCtx&           cuECtx  = m_ComprCUCtxList.back();
1096
1097
74.0k
  if( ! cuECtx.bestCS )
1098
0
    return;
1099
1100
74.0k
  CodedCUInfo    &relatedCU   = getBlkInfo( partitioner.currArea() );
1101
74.0k
  const CodingUnit&  bestCU   = *cuECtx.bestCU;
1102
1103
74.0k
  cuECtx.bestNsPredMode       = cuECtx.bestMode;
1104
74.0k
  cuECtx.bestCostBeforeSplit  = cuECtx.bestCS->cost;
1105
1106
74.0k
  setFromCs( *cuECtx.bestCS, cuECtx.bestMode, partitioner );
1107
1108
74.0k
  if( bestCU.skip )
1109
0
  {
1110
0
    cuECtx.doMoreSplits--;
1111
0
  }
1112
1113
74.0k
  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
74.0k
  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
74.0k
  else if (CU::isIBC(bestCU))
1127
0
  {
1128
0
    relatedCU.isIBC = true;
1129
0
    relatedCU.isSkip |= bestCU.skip;
1130
0
  }
1131
74.0k
  else if( CU::isIntra( bestCU ) )
1132
74.0k
  {
1133
74.0k
    relatedCU.isIntra     = true;
1134
74.0k
    if (m_pcEncCfg->m_FastIntraTools)
1135
74.0k
    {
1136
74.0k
      if ( cuECtx.intraWasTested && (!relatedCU.relatedCuIsValid || cuECtx.bestCS->cost < relatedCU.bestCost))
1137
22.6k
      {
1138
22.6k
        relatedCU.bestCost = cuECtx.bestCS->cost;
1139
22.6k
        relatedCU.relatedCuIsValid = true;
1140
22.6k
      }
1141
74.0k
    }
1142
74.0k
  }
1143
74.0k
  cuECtx.isBestNoSplitSkip = bestCU.skip;
1144
74.0k
}
1145
1146
1147
bool EncModeCtrl::useModeResult( const EncTestMode& encTestmode, CodingStructure*& tempCS, Partitioner& partitioner, const bool useEDO )
1148
154k
{
1149
154k
  ComprCUCtx& cuECtx = m_ComprCUCtxList.back();
1150
1151
1152
154k
  if(      encTestmode.type == ETM_SPLIT_BT_H )
1153
21.8k
  {
1154
21.8k
    cuECtx.bestCostHorzSplit = tempCS->cost;
1155
21.8k
  }
1156
132k
  else if( encTestmode.type == ETM_SPLIT_BT_V )
1157
21.2k
  {
1158
21.2k
    cuECtx.bestCostVertSplit = tempCS->cost;
1159
21.2k
  }
1160
111k
  else if( !isModeSplit( encTestmode ) && isModeInter( encTestmode ) && tempCS->cus.size() == 1 )
1161
0
  {
1162
0
    cuECtx.nonSkipWasTested |= !tempCS->cus.front()->skip;
1163
0
  }
1164
154k
  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
154k
  if( encTestmode.type == ETM_SPLIT_QT )
1178
16.7k
  {
1179
16.7k
    int maxQtD = 0;
1180
16.7k
    for( const auto& cu : tempCS->cus )
1181
67.7k
    {
1182
67.7k
      maxQtD = std::max<int>( maxQtD, cu->qtDepth );
1183
67.7k
    }
1184
16.7k
    cuECtx.maxQtSubDepth = maxQtD;
1185
16.7k
  }
1186
1187
154k
  int maxMtD = tempCS->pcv->getMaxMTTDepth( *tempCS->slice, partitioner.chType ) + partitioner.currImplicitBtDepth;
1188
1189
154k
  if( encTestmode.type == ETM_SPLIT_BT_H )
1190
21.8k
  {
1191
21.8k
    if( tempCS->cus.size() > 2 )
1192
878
    {
1193
878
      int h_2   = tempCS->area.blocks[partitioner.chType].height / 2;
1194
878
      int cu1_h = tempCS->cus.front()->blocks[partitioner.chType].height;
1195
878
      int cu2_h = tempCS->cus.back() ->blocks[partitioner.chType].height;
1196
1197
878
      cuECtx.doTriHorzSplit = cu1_h < h_2 || cu2_h < h_2 || partitioner.currMtDepth + 1 == maxMtD;
1198
878
    }
1199
21.8k
  }
1200
132k
  else if( encTestmode.type == ETM_SPLIT_BT_V )
1201
21.2k
  {
1202
21.2k
    if( tempCS->cus.size() > 2 )
1203
951
    {
1204
951
      int w_2   = tempCS->area.blocks[partitioner.chType].width / 2;
1205
951
      int cu1_w = tempCS->cus.front()->blocks[partitioner.chType].width;
1206
951
      int cu2_w = tempCS->cus.back() ->blocks[partitioner.chType].width;
1207
1208
951
      cuECtx.doTriVertSplit = cu1_w < w_2 || cu2_w < w_2 || partitioner.currMtDepth + 1 == maxMtD;
1209
951
    }
1210
21.2k
  }
1211
1212
154k
  if( encTestmode.type == ETM_SPLIT_BT_V || encTestmode.type == ETM_SPLIT_BT_H || encTestmode.type == ETM_SPLIT_QT )
1213
59.8k
  {
1214
59.8k
    bool isAllSkip = true;
1215
1216
59.8k
    for( const auto& cu : tempCS->cus )
1217
135k
    {
1218
135k
      isAllSkip &= cu->skip;
1219
135k
    }
1220
1221
59.8k
    if( isAllSkip ) cuECtx.doMoreSplits--;
1222
59.8k
    if( isAllSkip && encTestmode.type == ETM_SPLIT_QT )
1223
0
                    cuECtx.doMoreSplits--;
1224
59.8k
  }
1225
1226
  // for now just a simple decision based on RD-cost or choose tempCS if bestCS is not yet coded
1227
154k
  if( tempCS->cost != MAX_DOUBLE && ( !cuECtx.bestCS || ( ( tempCS->cost + ( useEDO ? tempCS->costDbOffset : 0 ) ) < ( cuECtx.bestCS->cost + ( useEDO ? cuECtx.bestCS->costDbOffset : 0 ) ) ) ) )
1228
139k
  {
1229
139k
    cuECtx.bestCS   = tempCS;
1230
139k
    cuECtx.bestCU   = tempCS->cus[0];
1231
139k
    cuECtx.bestTU   = cuECtx.bestCU->firstTU;
1232
139k
    cuECtx.bestMode = encTestmode;
1233
1234
139k
    return true;
1235
139k
  }
1236
14.8k
  else
1237
14.8k
  {
1238
14.8k
    return false;
1239
14.8k
  }
1240
154k
}
1241
1242
} // namespace vvenc
1243
1244
//! \}
1245