Coverage Report

Created: 2026-09-01 06:57

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