Coverage Report

Created: 2026-04-01 07:49

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