Coverage Report

Created: 2026-05-30 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvenc/source/Lib/CommonLib/UnitPartitioner.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     UnitPartitioner.h
45
 *  \brief    Provides a class for partitioning management
46
 */
47
48
#include "UnitPartitioner.h"
49
#include "CodingStructure.h"
50
#include "Unit.h"
51
#include "Slice.h"
52
#include "UnitTools.h"
53
#include "Picture.h"
54
55
//! \ingroup CommonLib
56
//! \{
57
58
namespace vvenc {
59
60
PartLevel::PartLevel()
61
2.35M
: split               ( CU_DONT_SPLIT )
62
, parts               (               )
63
2.35M
, idx                 ( 0u            )
64
2.35M
, checkdIfImplicit    ( false         )
65
2.35M
, isImplicit          ( false         )
66
2.35M
, implicitSplit       ( CU_DONT_SPLIT )
67
2.35M
, firstSubPartSplit   ( CU_DONT_SPLIT )
68
2.35M
, canQtSplit          ( true          )
69
2.35M
, qgEnable            ( true          )
70
2.35M
, qgChromaEnable      ( true          )
71
2.35M
, modeType            ( MODE_TYPE_ALL )
72
2.35M
{
73
2.35M
}
74
75
void PartLevel::init()
76
215k
{
77
215k
  split               = CU_DONT_SPLIT;
78
215k
  idx                 = 0u;
79
215k
  checkdIfImplicit    = false;
80
215k
  isImplicit          = false;
81
215k
  implicitSplit       = CU_DONT_SPLIT;
82
215k
  firstSubPartSplit   = CU_DONT_SPLIT;
83
215k
  canQtSplit          = true;
84
215k
  qgEnable            = true;
85
215k
  qgChromaEnable      = true;
86
215k
  modeType            = MODE_TYPE_ALL;
87
215k
  numParts            = 0;
88
215k
}
89
90
//////////////////////////////////////////////////////////////////////////
91
// Partitioner class
92
//////////////////////////////////////////////////////////////////////////
93
94
SplitSeries Partitioner::getSplitSeries() const
95
142k
{
96
142k
  SplitSeries splitSeries = 0;
97
142k
  SplitSeries depth = 0;
98
99
142k
  for( const auto &level : m_partStack )
100
571k
  {
101
571k
    if( level.split == CTU_LEVEL ) continue;
102
428k
    else splitSeries += static_cast< SplitSeries >( level.split ) << ( depth * SPLIT_DMULT );
103
104
428k
    depth++;
105
428k
  }
106
107
142k
  return splitSeries;
108
142k
}
109
110
ModeTypeSeries Partitioner::getModeTypeSeries() const
111
142k
{
112
142k
  ModeTypeSeries modeTypeSeries = 0;
113
142k
  int depth = 0;
114
115
142k
  for( const auto &level : m_partStack )
116
571k
  {
117
571k
    if( level.split == CTU_LEVEL ) continue;
118
428k
    else modeTypeSeries += static_cast<int>(level.modeType) << (depth * 3);
119
120
428k
    depth++;
121
428k
  }
122
123
142k
  return modeTypeSeries;
124
142k
}
125
126
bool Partitioner::isSepTree( const CodingStructure &cs )
127
783k
{
128
783k
  return treeType != TREE_D || CS::isDualITree( cs );
129
783k
}
130
131
void Partitioner::setCUData( CodingUnit& cu )
132
142k
{
133
142k
  cu.depth       = currDepth;
134
142k
  cu.btDepth     = currBtDepth;
135
142k
  cu.mtDepth     = currMtDepth;
136
142k
  cu.qtDepth     = currQtDepth;
137
142k
  cu.splitSeries = getSplitSeries();
138
142k
  cu.modeTypeSeries = getModeTypeSeries();
139
142k
  cu.treeType    = treeType; 
140
142k
  cu.modeType    = modeType; 
141
142
142k
}
143
144
void Partitioner::copyState( const Partitioner& other )
145
0
{
146
0
  m_partStack = other.m_partStack;
147
0
  currBtDepth = other.currBtDepth;
148
0
  currQtDepth = other.currQtDepth;
149
0
  currDepth   = other.currDepth;
150
0
  currMtDepth = other.currMtDepth;
151
0
  currTrDepth = other.currTrDepth;
152
0
  currSubdiv  = other.currSubdiv;
153
0
  currQgPos   = other.currQgPos;
154
0
  currQgChromaPos = other.currQgChromaPos;
155
0
  currImplicitBtDepth
156
0
              = other.currImplicitBtDepth;
157
0
  chType      = other.chType;
158
0
#ifdef _DEBUG
159
0
  m_currArea  = other.m_currArea;
160
0
#endif
161
0
}
162
163
void Partitioner::setMaxMinDepth( unsigned& minDepth, unsigned& maxDepth, const CodingStructure& cs, int QtbttSpeedUp, bool MergeFlag) const
164
139k
{
165
139k
  unsigned          stdMinDepth = 0;
166
139k
  unsigned          stdMaxDepth = cs.pcv->getMaxDepth( cs.slice->sliceType, chType );
167
139k
  const Position    pos         = currArea().blocks[chType].pos();
168
139k
  const unsigned    curSliceIdx = cs.slice->independentSliceIdx;
169
139k
  const unsigned    curTileIdx  = cs.pps->getTileIdx( currArea().lumaPos() );
170
171
139k
  const CodingUnit* cuLeft        = cs.getCURestricted( pos.offset( -1,                               0 ), pos, curSliceIdx, curTileIdx, chType, treeType );
172
139k
  const CodingUnit* cuBelowLeft   = cs.getCURestricted( pos.offset( -1, currArea().blocks[chType].height), pos, curSliceIdx, curTileIdx, chType, treeType );
173
139k
  const CodingUnit* cuAbove       = cs.getCURestricted( pos.offset(  0,                              -1 ), pos, curSliceIdx, curTileIdx, chType, treeType );
174
139k
  const CodingUnit* cuAboveRight  = cs.getCURestricted( pos.offset( currArea().blocks[chType].width, -1 ), pos, curSliceIdx, curTileIdx, chType, treeType );
175
176
139k
  minDepth = stdMaxDepth;
177
139k
  maxDepth = stdMinDepth;
178
179
139k
  if( cuLeft )
180
82.4k
  {
181
82.4k
    minDepth = std::min<unsigned>( minDepth, cuLeft->qtDepth );
182
82.4k
    maxDepth = std::max<unsigned>( maxDepth, cuLeft->qtDepth );
183
82.4k
  }
184
56.8k
  else
185
56.8k
  {
186
56.8k
    minDepth = stdMinDepth;
187
56.8k
    maxDepth = stdMaxDepth;
188
56.8k
  }
189
190
139k
  if( cuBelowLeft )
191
12.5k
  {
192
12.5k
    minDepth = std::min<unsigned>( minDepth, cuBelowLeft->qtDepth );
193
12.5k
    maxDepth = std::max<unsigned>( maxDepth, cuBelowLeft->qtDepth );
194
12.5k
  }
195
126k
  else
196
126k
  {
197
126k
    minDepth = stdMinDepth;
198
126k
    maxDepth = stdMaxDepth;
199
126k
  }
200
201
139k
  if( cuAbove )
202
85.0k
  {
203
85.0k
    minDepth = std::min<unsigned>( minDepth, cuAbove->qtDepth );
204
85.0k
    maxDepth = std::max<unsigned>( maxDepth, cuAbove->qtDepth );
205
85.0k
  }
206
54.2k
  else
207
54.2k
  {
208
54.2k
    minDepth = stdMinDepth;
209
54.2k
    maxDepth = stdMaxDepth;
210
54.2k
  }
211
212
139k
  if( cuAboveRight )
213
29.4k
  {
214
29.4k
    minDepth = std::min<unsigned>( minDepth, cuAboveRight->qtDepth );
215
29.4k
    maxDepth = std::max<unsigned>( maxDepth, cuAboveRight->qtDepth );
216
29.4k
  }
217
109k
  else
218
109k
  {
219
109k
    minDepth = stdMinDepth;
220
109k
    maxDepth = stdMaxDepth;
221
109k
  }
222
223
139k
  minDepth = ( minDepth >= 1 ? minDepth - 1 : 0 );
224
139k
  maxDepth = std::min<unsigned>( stdMaxDepth, maxDepth + 1 );
225
139k
  if((QtbttSpeedUp >> 2) && (cs.slice->TLayer > 0) && ((cs.area.Y().width >= 8) || (cs.area.Y().height >= 8)))
226
0
  {
227
0
    int minDepthCur = stdMaxDepth;
228
0
    int maxDepthCur = stdMinDepth;
229
0
    int amountN = 0;
230
0
    for (int n = 0; n < 3; n++)
231
0
    {
232
0
      const CodingUnit* cuNeigh = (n==0)?cs.getCURestricted(pos.offset(-1, -1), pos, curSliceIdx, curTileIdx, chType, treeType): (n==1)? cuAbove : cuLeft;
233
0
      if (cuNeigh)
234
0
      {
235
0
        amountN++;
236
0
        minDepthCur = std::min<unsigned>(minDepthCur, cuNeigh->qtDepth);
237
0
        maxDepthCur = std::max<unsigned>(maxDepthCur, cuNeigh->qtDepth);
238
0
      }
239
0
    }
240
0
    if (amountN)
241
0
    {
242
0
      minDepthCur = (minDepthCur >= 1 ? minDepthCur - 1 : 0);
243
0
      maxDepthCur = std::min<unsigned>(stdMaxDepth, maxDepthCur + 1);
244
0
      maxDepth = std::min<unsigned>(maxDepthCur, maxDepth);
245
0
      minDepth = std::max<unsigned>(minDepthCur, minDepth);
246
0
    }
247
0
  }
248
249
139k
  if (!cs.slice->isIntra() && (QtbttSpeedUp & 3))
250
0
  {
251
0
    bool doMin_SCC = !(((QtbttSpeedUp & 3) == 2) && (cs.area.Y().width < cs.pcv->maxCUSize));
252
0
    bool LimitDepths = (QtbttSpeedUp & 2) ? (MergeFlag == 0) : (cs.area.Y().width >= cs.pcv->maxCUSize);
253
0
    if (LimitDepths && cuAbove && cuLeft && (cuLeft->qtDepth == cuAbove->qtDepth))
254
0
    {
255
0
      int minDepthCur = cuAbove->qtDepth;
256
0
      int maxDepthCur = cuAbove->qtDepth;
257
0
      minDepthCur = (minDepthCur > 0) ? (minDepthCur - 1) : 0;
258
0
      maxDepthCur = (maxDepthCur < stdMaxDepth) ? (maxDepthCur + 1) : maxDepthCur;
259
0
      maxDepth = std::min<unsigned>(maxDepthCur, maxDepth);
260
0
      minDepth = std::max<unsigned>(minDepthCur, minDepth);
261
0
    }
262
0
    else if (doMin_SCC && LimitDepths && cuAbove && cuLeft)
263
0
    {
264
0
      int minDepthCur = cuAbove->qtDepth;
265
0
      int maxDepthCur = cuAbove->qtDepth;
266
0
      minDepthCur = (minDepthCur > 0) ? (minDepthCur - 1) : 0;
267
0
      maxDepthCur = (maxDepthCur < stdMaxDepth) ? (maxDepthCur + 1) : maxDepthCur;
268
0
      if ((cuLeft->qtDepth > maxDepthCur) && ((cuLeft->qtDepth - 1) >= maxDepthCur))
269
0
      {
270
0
        minDepthCur += 1;
271
0
        maxDepthCur += 1;
272
0
      }
273
0
      else if ((cuLeft->qtDepth < minDepthCur) && ((cuLeft->qtDepth + 1) <= minDepthCur))
274
0
      {
275
0
        maxDepthCur -= 1;
276
0
        minDepthCur -= 1;
277
0
      }
278
0
      maxDepth = std::min<unsigned>(maxDepthCur, maxDepth);
279
0
      minDepth = std::max<unsigned>(minDepthCur, minDepth);
280
0
    }
281
0
    if ((QtbttSpeedUp & 2) && MergeFlag && (maxDepth == 4) && (cs.area.Y().width <= 16))
282
0
    {
283
0
      maxDepth = 3;
284
0
      minDepth = (minDepth == 3)? 2: minDepth;
285
0
    }
286
0
  }
287
139k
}
288
289
void Partitioner::initCtu( const UnitArea& ctuArea, const ChannelType _chType, const Slice& slice )
290
24.3k
{
291
24.3k
#if _DEBUG
292
24.3k
  m_currArea = ctuArea;
293
24.3k
#endif
294
24.3k
  currDepth   = 0;
295
24.3k
  currTrDepth = 0;
296
24.3k
  currBtDepth = 0;
297
24.3k
  currMtDepth = 0;
298
24.3k
  currQtDepth = 0;
299
24.3k
  currSubdiv  = 0;
300
24.3k
  currQgPos   = ctuArea.lumaPos();
301
24.3k
  currQgChromaPos = ctuArea.chromaFormat != CHROMA_400 ? ctuArea.chromaPos() : Position();
302
24.3k
  currImplicitBtDepth = 0;
303
24.3k
  chType      = _chType;
304
305
24.3k
  const PreCalcValues& pcv = *slice.pps->pcv;
306
  
307
24.3k
  maxBTD      = pcv.getMaxMTTDepth( slice, chType );
308
24.3k
  maxBtSize   = pcv.getMaxBtSize  ( slice, chType );
309
24.3k
  minTSize    = pcv.getMinTSize   ( slice, chType );
310
24.3k
  maxTtSize   = pcv.getMaxTtSize  ( slice, chType );
311
24.3k
  minQtSize   = pcv.getMinQtSize  ( slice, chType );
312
  
313
24.3k
  m_partBufIdx = 1;
314
24.3k
  m_partStack.resize_noinit( 1 );
315
24.3k
  m_partStack.back().init();
316
24.3k
  m_partStack.back().split = CTU_LEVEL;
317
24.3k
  m_partStack.back().parts = m_partBuf;
318
24.3k
  m_partStack.back().parts[0] = ctuArea;
319
24.3k
  m_partStack.back().numParts = 1;
320
321
24.3k
  treeType = TREE_D;
322
24.3k
  modeType = MODE_TYPE_ALL;
323
24.3k
}
324
325
void Partitioner::splitCurrArea( const PartSplit split, const CodingStructure& cs )
326
191k
{
327
191k
  if ((split != TU_1D_HORZ_SPLIT) && (split != TU_1D_VERT_SPLIT))
328
169k
  {
329
169k
    CHECKD(!canSplit(split, cs), "Trying to apply a prohibited split!");
330
169k
  }
331
332
191k
  bool isImplicit = isSplitImplicit( split, cs );
333
191k
  bool canQtSplit = canSplit( CU_QUAD_SPLIT, cs );
334
191k
  bool qgEnable = currQgEnable();
335
191k
  bool qgChromaEnable = currQgChromaEnable();
336
337
191k
  const UnitArea& area = currArea();
338
191k
  m_partStack.resize_noinit( m_partStack.size() + 1 );
339
191k
  PartLevel& back = m_partStack.back();
340
191k
  back.init();
341
191k
  back.split = split;
342
191k
  back.parts = &m_partBuf[m_partBufIdx];
343
191k
  int numParts;
344
345
191k
  CHECK( m_partBufIdx > partBufSize, "Partition buffer overflow" );
346
347
191k
  switch( split )
348
191k
  {
349
55.7k
  case CU_QUAD_SPLIT:
350
55.7k
    numParts = PartitionerImpl::getCUSubPartitions( back.parts, area, cs, split );
351
55.7k
    back.modeType = modeType;
352
55.7k
    break;
353
56.2k
  case CU_HORZ_SPLIT:
354
113k
  case CU_VERT_SPLIT:
355
113k
    numParts = PartitionerImpl::getCUSubPartitions( back.parts, area, cs, split );
356
113k
    back.modeType = modeType;
357
113k
    break;
358
378
  case CU_TRIH_SPLIT:
359
440
  case CU_TRIV_SPLIT:
360
440
    numParts = PartitionerImpl::getCUSubPartitions( back.parts, area, cs, split );
361
440
    back.modeType = modeType;
362
440
    break;
363
0
  case TU_MAX_TR_SPLIT:
364
0
    numParts = PartitionerImpl::getMaxTuTiling( back.parts, area, cs );
365
0
    break;
366
0
  case SBT_VER_HALF_POS0_SPLIT:
367
0
  case SBT_VER_HALF_POS1_SPLIT:
368
0
  case SBT_HOR_HALF_POS0_SPLIT:
369
0
  case SBT_HOR_HALF_POS1_SPLIT:
370
0
  case SBT_VER_QUAD_POS0_SPLIT:
371
0
  case SBT_VER_QUAD_POS1_SPLIT:
372
0
  case SBT_HOR_QUAD_POS0_SPLIT:
373
0
  case SBT_HOR_QUAD_POS1_SPLIT:
374
0
    numParts = PartitionerImpl::getSbtTuTiling( back.parts, area, cs, split );
375
0
    break;
376
10.4k
  case TU_1D_HORZ_SPLIT:
377
21.6k
  case TU_1D_VERT_SPLIT:
378
21.6k
  {
379
21.6k
    numParts = PartitionerImpl::getTUIntraSubPartitions(back.parts, area, cs, split, TREE_D);
380
21.6k
    break;
381
10.4k
  }
382
0
  default:
383
0
    THROW( "Unknown split mode" );
384
0
    break;
385
191k
  }
386
387
191k
  back.numParts = numParts;
388
191k
  m_partBufIdx += numParts;
389
390
191k
  CHECK( m_partBufIdx > partBufSize, "Partition buffer overflow" );
391
392
191k
  currDepth++;
393
191k
  currSubdiv++;
394
191k
#if _DEBUG
395
191k
  m_currArea = m_partStack.back().parts[0];
396
191k
#endif
397
398
191k
  if ((split == TU_MAX_TR_SPLIT) || (split == TU_1D_HORZ_SPLIT) || (split == TU_1D_VERT_SPLIT))
399
21.6k
  {
400
21.6k
    currTrDepth++;
401
21.6k
  }
402
169k
  else if( split >= SBT_VER_HALF_POS0_SPLIT && split <= SBT_HOR_QUAD_POS1_SPLIT )
403
0
  {
404
0
    currTrDepth++;
405
0
  }
406
169k
  else
407
169k
  {
408
169k
    currTrDepth = 0;
409
169k
  }
410
411
191k
  if( split == CU_HORZ_SPLIT || split == CU_VERT_SPLIT || split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT )
412
114k
  {
413
114k
    currBtDepth++;
414
114k
    if( isImplicit ) currImplicitBtDepth++;
415
114k
    currMtDepth++;
416
417
114k
    if( split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT )
418
440
    {
419
      // first and last part of triple split are equivalent to double bt split
420
440
      currBtDepth++;
421
440
      currSubdiv++;
422
440
    }
423
114k
    m_partStack.back().canQtSplit = canQtSplit;
424
114k
  }
425
77.3k
  else if( split == CU_QUAD_SPLIT )
426
55.7k
  {
427
55.7k
    CHECK( currBtDepth > 0, "Cannot split a non-square area other than with a binary split" );
428
55.7k
    CHECK( currMtDepth > 0, "Cannot split a non-square area other than with a binary split" );
429
55.7k
    currMtDepth = 0;
430
55.7k
    currBtDepth = 0;
431
55.7k
    currQtDepth++;
432
55.7k
    currSubdiv++;
433
55.7k
  }
434
435
191k
  qgEnable       &= (currSubdiv <= (cs.slice->isIntra() ? cs.slice->picHeader->cuQpDeltaSubdivIntra : cs.slice->picHeader->cuQpDeltaSubdivInter ));
436
191k
  qgChromaEnable &= (currSubdiv <= (cs.slice->isIntra() ? cs.slice->picHeader->cuChromaQpOffsetSubdivIntra : cs.slice->picHeader->cuChromaQpOffsetSubdivInter ));
437
191k
  m_partStack.back().qgEnable       = qgEnable;
438
191k
  m_partStack.back().qgChromaEnable = qgChromaEnable;
439
191k
  if (qgEnable)
440
8.27k
    currQgPos = currArea().lumaPos();
441
191k
  if (qgChromaEnable)
442
0
    currQgChromaPos = currArea().chromaPos();
443
191k
}
444
445
void Partitioner::canSplit( const CodingStructure &cs, bool& canNo, bool& canQt, bool& canBh, bool& canBv, bool& canTh, bool& canTv )
446
2.44M
{
447
2.44M
  const PartSplit implicitSplit = m_partStack.back().checkdIfImplicit ? m_partStack.back().implicitSplit : getImplicitSplit( cs );
448
449
2.44M
  canNo = canQt = canBh = canTh = canBv = canTv = true;
450
2.44M
  bool canBtt = currMtDepth < (maxBTD + currImplicitBtDepth);
451
452
  // the minimal and maximal sizes are given in luma samples
453
2.44M
  const CompArea&  area  = currArea().Y();
454
2.44M
  const CompArea  *areaC = (chType == CH_C) ? &(currArea().Cb()) : nullptr;
455
2.44M
        PartLevel& level = m_partStack.back();
456
457
2.44M
  const PartSplit lastSplit = level.split;
458
2.44M
  const PartSplit parlSplit = lastSplit == CU_TRIH_SPLIT ? CU_HORZ_SPLIT : CU_VERT_SPLIT;
459
460
  // don't allow QT-splitting below a BT split
461
2.44M
  if( lastSplit != CTU_LEVEL && lastSplit != CU_QUAD_SPLIT ) canQt = false;
462
  // minQtSize is in luma samples unit
463
2.44M
  const unsigned minQTThreshold = minQtSize >> ((area.chromaFormat == CHROMA_400) ? 0 : ((int) getChannelTypeScaleX(CH_C, area.chromaFormat) - (int) getChannelTypeScaleY(CH_C, area.chromaFormat)));
464
2.44M
  if( area.width <= minQTThreshold )                         canQt = false;
465
2.44M
  if( areaC && areaC->width <= MIN_DUALTREE_CHROMA_WIDTH ) canQt = false;
466
2.44M
  if( treeType == TREE_C )
467
0
  {
468
0
    canQt = canBh = canTh = canBv = canTv = false;
469
0
    return;
470
0
  }
471
2.44M
  if( implicitSplit != CU_DONT_SPLIT )
472
908k
  {
473
908k
    canNo = canTh = canTv = false;
474
475
908k
    canBh = implicitSplit == CU_HORZ_SPLIT;
476
908k
    canBv = implicitSplit == CU_VERT_SPLIT;
477
908k
    if (areaC && areaC->width == 4) canBv = false;
478
908k
    if( !canBh && !canBv && !canQt ) canQt = true;
479
908k
    return;
480
908k
  }
481
482
1.53M
  if( ( lastSplit == CU_TRIH_SPLIT || lastSplit == CU_TRIV_SPLIT ) && currPartIdx() == 1 )
483
4.86k
  {
484
4.86k
    canBh = parlSplit != CU_HORZ_SPLIT;
485
4.86k
    canBv = parlSplit != CU_VERT_SPLIT;
486
4.86k
  }
487
488
1.53M
  if( canBtt && ( area.width <= minTSize && area.height <= minTSize ) )
489
0
  {
490
0
    canBtt = false;
491
0
  }
492
1.53M
  if( canBtt && ( area.width > maxBtSize || area.height > maxBtSize )
493
105k
      && ( ( area.width > maxTtSize || area.height > maxTtSize ) ) )
494
105k
  {
495
105k
    canBtt = false;
496
105k
  }
497
498
1.53M
  if( !canBtt )
499
346k
  {
500
346k
    canBh = canTh = canBv = canTv = false;
501
502
346k
    return;
503
346k
  }
504
505
1.18M
  if( area.width > maxBtSize || area.height > maxBtSize )
506
0
  {
507
0
    canBh = canBv = false;
508
0
  }
509
510
  // specific check for BT splits
511
1.18M
  if( area.height <= minTSize )                            canBh = false;
512
1.18M
  if( area.width > MAX_TB_SIZEY && area.height <= MAX_TB_SIZEY ) canBh = false;
513
1.18M
  if( areaC && areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE )     canBh = false;
514
1.18M
  if( area.width <= minTSize )                              canBv = false;
515
1.18M
  if( area.width <= MAX_TB_SIZEY && area.height > MAX_TB_SIZEY ) canBv = false;
516
1.18M
  if (areaC && (areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE || areaC->width == 4))     canBv = false;
517
1.18M
  if( modeType == MODE_TYPE_INTER && area.width * area.height == 32 )  canBv = canBh = false;
518
1.18M
  if( area.height <= 2 * minTSize || area.height > maxTtSize || area.width > maxTtSize )
519
497k
                                                                                       canTh = false;
520
1.18M
  if( area.width > MAX_TB_SIZEY || area.height > MAX_TB_SIZEY )  canTh = false;
521
1.18M
  if( areaC && areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE*2 )     canTh = false;
522
1.18M
  if( area.width <= 2 * minTSize || area.width > maxTtSize || area.height > maxTtSize )
523
487k
                                                                                       canTv = false;
524
1.18M
  if( area.width > MAX_TB_SIZEY || area.height > MAX_TB_SIZEY )  canTv = false;
525
1.18M
  if (areaC && (areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE * 2 || areaC->width == 8))     canTv = false;
526
1.18M
  if( modeType == MODE_TYPE_INTER && area.width * area.height == 64 )  canTv = canTh = false;
527
1.18M
}
528
529
bool Partitioner::canSplit( const PartSplit split, const CodingStructure &cs )
530
1.96M
{
531
1.96M
  const CompArea area       = currArea().Y();
532
1.96M
  const unsigned maxTrSize  = cs.sps->getMaxTbSize();
533
534
1.96M
  bool canNo, canQt, canBh, canTh, canBv, canTv;
535
536
1.96M
  canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv );
537
538
1.96M
  switch( split )
539
1.96M
  {
540
0
  case CTU_LEVEL:
541
0
    THROW( "Checking if top level split is possible" );
542
0
    return true;
543
0
    break;
544
283k
  case TU_MAX_TR_SPLIT:
545
283k
    return area.width > maxTrSize || area.height > maxTrSize;
546
0
    break;
547
0
  case SBT_VER_HALF_POS0_SPLIT:
548
0
  case SBT_VER_HALF_POS1_SPLIT:
549
0
  case SBT_HOR_HALF_POS0_SPLIT:
550
0
  case SBT_HOR_HALF_POS1_SPLIT:
551
0
  case SBT_VER_QUAD_POS0_SPLIT:
552
0
  case SBT_VER_QUAD_POS1_SPLIT:
553
0
  case SBT_HOR_QUAD_POS0_SPLIT:
554
0
  case SBT_HOR_QUAD_POS1_SPLIT:
555
0
    return currTrDepth == 0;
556
0
    break;
557
412k
  case CU_QUAD_SPLIT:
558
412k
    return canQt;
559
85.7k
  case CU_DONT_SPLIT:
560
85.7k
    return canNo;
561
423k
  case CU_HORZ_SPLIT:
562
423k
    return canBh;
563
421k
  case CU_VERT_SPLIT:
564
421k
    return canBv;
565
170k
  case CU_TRIH_SPLIT:
566
170k
    return canTh;
567
163k
  case CU_TRIV_SPLIT:
568
163k
    return canTv;
569
0
  case CU_MT_SPLIT:
570
0
    return ( canBh || canTh || canBv || canTv );
571
0
  case CU_BT_SPLIT:
572
0
    return ( canBh || canBv );
573
0
  break;
574
0
  default:
575
0
    THROW( "Unknown split mode" );
576
0
    return false;
577
0
    break;
578
1.96M
  }
579
580
0
  return true;
581
1.96M
}
582
583
bool Partitioner::canSplitISP(const PartSplit split, const CodingStructure& cs, CodingUnit& cu)
584
0
{
585
  // const PartSplit implicitSplit = getImplicitSplit(cs);
586
0
  const UnitArea& area = currArea();
587
588
0
  switch (split)
589
0
  {
590
0
  case TU_1D_HORZ_SPLIT:
591
0
  {
592
0
    return area.lheight() == cu.lheight();
593
0
  }
594
0
  case TU_1D_VERT_SPLIT:
595
0
  {
596
0
    return area.lwidth() == cu.lwidth();
597
0
  }
598
0
  case TU_MAX_TR_SPLIT:
599
0
  {
600
    // this split is performed implicitly with the other splits
601
0
    return false;
602
0
  }
603
0
  default: THROW("Unknown 1-D split mode"); break;
604
0
  }
605
0
}
606
607
bool Partitioner::isSplitImplicit( const PartSplit split, const CodingStructure &cs )
608
191k
{
609
191k
  return split == getImplicitSplit( cs );
610
191k
}
611
612
PartSplit Partitioner::getImplicitSplit( const CodingStructure &cs )
613
993k
{
614
993k
  if( m_partStack.back().checkdIfImplicit )
615
670k
  {
616
670k
    return m_partStack.back().implicitSplit;
617
670k
  }
618
619
323k
  PartSplit split = CU_DONT_SPLIT;
620
621
323k
  if( split == CU_DONT_SPLIT )
622
323k
  {
623
323k
    const bool isBlInPic = cs.picture->Y().contains( currArea().Y().bottomLeft() );
624
323k
    const bool isTrInPic = cs.picture->Y().contains( currArea().Y().topRight() );
625
626
323k
    const CompArea& area      = currArea().Y();
627
323k
    const bool isBtAllowed    = area.width <= maxBtSize && area.height <= maxBtSize && currMtDepth < (maxBTD + currImplicitBtDepth);
628
    // minQtSize is in luma samples unit
629
323k
    const unsigned minQTThreshold = minQtSize >> ((area.chromaFormat == CHROMA_400) ? 0 : ((int) getChannelTypeScaleX(CH_C, area.chromaFormat) - (int) getChannelTypeScaleY(CH_C, area.chromaFormat)));
630
323k
    const bool isQtAllowed    = area.width > minQTThreshold && currBtDepth == 0;
631
632
323k
    if( !isBlInPic && !isTrInPic && isQtAllowed )
633
21.8k
    {
634
21.8k
      split = CU_QUAD_SPLIT;
635
21.8k
    }
636
301k
    else if( !isBlInPic && isBtAllowed && area.width <= MAX_TB_SIZEY )
637
46.9k
    {
638
46.9k
      split = CU_HORZ_SPLIT;
639
46.9k
    }
640
254k
    else if( !isTrInPic && isBtAllowed && area.height <= MAX_TB_SIZEY )
641
49.2k
    {
642
49.2k
      split = CU_VERT_SPLIT;
643
49.2k
    }
644
205k
    else if( !isBlInPic || !isTrInPic )
645
25.5k
    {
646
25.5k
      split = CU_QUAD_SPLIT;
647
25.5k
    }
648
323k
    if (CS::isDualITree(cs) && (currArea().Y().width > 64 || currArea().Y().height > 64))
649
24.3k
    {
650
24.3k
      split = CU_QUAD_SPLIT;
651
24.3k
    }
652
323k
    if( (!isBlInPic || !isTrInPic) && split == CU_DONT_SPLIT )
653
0
    {
654
0
      split = CU_QUAD_SPLIT;
655
0
    }
656
323k
  }
657
658
323k
  m_partStack.back().checkdIfImplicit = true;
659
323k
  m_partStack.back().isImplicit = split != CU_DONT_SPLIT;
660
323k
  m_partStack.back().implicitSplit = split;
661
662
323k
  return split;
663
993k
}
664
665
void Partitioner::exitCurrSplit()
666
191k
{
667
191k
  const PartSplit currSplit = m_partStack.back().split;
668
191k
  const int       currIndex = m_partStack.back().idx;
669
191k
  const int       numParts  = m_partStack.back().numParts;
670
671
191k
  m_partStack.pop_back();
672
191k
  m_partBufIdx -= numParts;
673
674
191k
  CHECK( currDepth == 0, "depth is '0', although a split was performed" );
675
191k
  currDepth--;
676
191k
  currSubdiv--;
677
191k
  if( currQgEnable() )
678
39.2k
    currQgPos = currArea().lumaPos();
679
191k
  if( currArea().chromaFormat != CHROMA_400 && currQgChromaEnable() )
680
24.3k
    currQgChromaPos = currArea().chromaPos();
681
191k
#if _DEBUG
682
191k
  m_currArea = m_partStack.back().parts[m_partStack.back().idx];
683
191k
#endif
684
685
191k
  if( currSplit == CU_HORZ_SPLIT || currSplit == CU_VERT_SPLIT || currSplit == CU_TRIH_SPLIT || currSplit == CU_TRIV_SPLIT )
686
114k
  {
687
114k
    CHECK( !m_partStack.back().checkdIfImplicit, "Didn't check if the current split is implicit" );
688
114k
    CHECK( currBtDepth == 0, "BT depth is '0', athough a BT split was performed" );
689
114k
    CHECK( currMtDepth == 0, "MT depth is '0', athough a BT split was performed" );
690
114k
    currMtDepth--;
691
114k
    if( m_partStack.back().isImplicit ) currImplicitBtDepth--;
692
114k
    currBtDepth--;
693
114k
    if( ( currSplit == CU_TRIH_SPLIT || currSplit == CU_TRIV_SPLIT ) && currIndex != 1 )
694
440
    {
695
440
      CHECK( currBtDepth == 0, "BT depth is '0', athough a TT split was performed" );
696
440
      currBtDepth--;
697
440
      currSubdiv--;
698
440
    }
699
114k
  }
700
77.3k
  else if( currSplit == TU_MAX_TR_SPLIT )
701
0
  {
702
0
    CHECK( currTrDepth == 0, "TR depth is '0', although a TU split was performed" );
703
0
    currTrDepth--;
704
0
  }
705
77.3k
  else if( currSplit >= SBT_VER_HALF_POS0_SPLIT && currSplit <= SBT_HOR_QUAD_POS1_SPLIT )
706
0
  {
707
0
    CHECK( currTrDepth == 0, "TR depth is '0', although a TU split was performed" );
708
0
    currTrDepth--;
709
0
  }
710
77.3k
  else if ((currSplit == TU_1D_HORZ_SPLIT) || (currSplit == TU_1D_VERT_SPLIT))
711
21.6k
  {
712
21.6k
    CHECK(currTrDepth == 0, "TR depth is '0', although a TU split was performed");
713
21.6k
    currTrDepth--;
714
21.6k
  }
715
55.7k
  else
716
55.7k
  {
717
55.7k
    CHECK( currTrDepth > 0, "RQT found with QTBT partitioner" );
718
719
55.7k
    CHECK( currQtDepth == 0, "QT depth is '0', although a QT split was performed" );
720
55.7k
    currQtDepth--;
721
55.7k
    currSubdiv--;
722
55.7k
  }
723
191k
}
724
725
bool Partitioner::nextPart( const CodingStructure &cs, bool autoPop /*= false*/ )
726
479k
{
727
479k
  const Position& prevPos = currArea().blocks[chType].pos();
728
729
479k
  unsigned currIdx = ++m_partStack.back().idx;
730
731
479k
  m_partStack.back().checkdIfImplicit = false;
732
479k
  m_partStack.back().isImplicit = false;
733
734
479k
  if( currIdx == 1 )
735
176k
  {
736
176k
    const CodingUnit* prevCU = cs.getCU( prevPos, chType, treeType );
737
18.4E
    m_partStack.back().firstSubPartSplit = prevCU ? CU::getSplitAtDepth( *prevCU, currDepth ) : CU_DONT_SPLIT;
738
176k
  }
739
740
479k
  if( currIdx < m_partStack.back().numParts )
741
302k
  {
742
302k
    if( m_partStack.back().split == CU_TRIH_SPLIT || m_partStack.back().split == CU_TRIV_SPLIT )
743
880
    {
744
      // adapt the current bt depth
745
880
      if( currIdx == 1 ) currBtDepth--;
746
440
      else               currBtDepth++;
747
880
      if( currIdx == 1 ) currSubdiv--;
748
440
      else               currSubdiv++;
749
880
    }
750
302k
  if( currQgEnable() )
751
24.8k
    currQgPos = currArea().lumaPos();
752
302k
  if( currQgChromaEnable() )
753
0
    currQgChromaPos = currArea().chromaPos();
754
302k
#if _DEBUG
755
302k
    m_currArea = m_partStack.back().parts[currIdx];
756
302k
#endif
757
302k
    return true;
758
302k
  }
759
176k
  else
760
176k
  {
761
176k
    if( autoPop ) exitCurrSplit();
762
176k
    return false;
763
176k
  }
764
479k
}
765
766
bool Partitioner::hasNextPart()
767
131k
{
768
131k
  return ( ( m_partStack.back().idx + 1 ) < m_partStack.back().numParts );
769
131k
}
770
771
//////////////////////////////////////////////////////////////////////////
772
// Partitioner methods describing the actual partitioning logic
773
//////////////////////////////////////////////////////////////////////////
774
775
int PartitionerImpl::getCUSubPartitions( Partitioning& dst, const UnitArea &cuArea, const CodingStructure &cs, const PartSplit _splitType )
776
169k
{
777
169k
  const PartSplit splitType = _splitType;
778
779
169k
  if( splitType == CU_QUAD_SPLIT )
780
55.7k
  {
781
55.7k
    Partitioning& sub = dst;
782
783
278k
    for( uint32_t i = 0; i < 4; i++ )
784
222k
    {
785
222k
      sub[i] = cuArea;
786
787
222k
      for( auto &blk : sub[i].blocks )
788
668k
      {
789
668k
        blk.height >>= 1;
790
668k
        blk.width  >>= 1;
791
668k
        if( i >= 2 ) blk.y += blk.height;
792
668k
        if( i &  1 ) blk.x += blk.width;
793
668k
      }
794
222k
    }
795
796
55.7k
    return 4;
797
55.7k
  }
798
114k
  else if( splitType == CU_HORZ_SPLIT )
799
56.2k
  {
800
56.2k
    Partitioning& sub = dst;
801
802
168k
    for (uint32_t i = 0; i < 2; i++)
803
112k
    {
804
112k
      sub[i] = cuArea;
805
806
112k
      for (auto &blk : sub[i].blocks)
807
337k
      {
808
337k
        blk.height >>= 1;
809
337k
        if (i == 1) blk.y += blk.height;
810
337k
      }
811
112k
    }
812
813
56.2k
    return 2;
814
56.2k
  }
815
57.9k
  else if( splitType == CU_VERT_SPLIT )
816
57.5k
  {
817
57.5k
    Partitioning& sub = dst;
818
819
172k
    for( uint32_t i = 0; i < 2; i++ )
820
115k
    {
821
115k
      sub[i] = cuArea;
822
823
115k
      for( auto &blk : sub[i].blocks )
824
345k
      {
825
345k
        blk.width >>= 1;
826
345k
        if( i == 1 ) blk.x += blk.width;
827
345k
      }
828
115k
    }
829
830
57.5k
    return 2;
831
57.5k
  }
832
438
  else if( splitType == CU_TRIH_SPLIT )
833
378
  {
834
378
    Partitioning& sub = dst;
835
836
1.51k
    for( int i = 0; i < 3; i++ )
837
1.13k
    {
838
1.13k
      sub[i] = cuArea;
839
840
1.13k
      for( auto &blk : sub[i].blocks )
841
3.40k
      {
842
3.40k
        blk.height >>= 1;
843
3.40k
        if( ( i + 1 ) & 1 ) blk.height >>= 1;
844
3.40k
        if( i == 1 )        blk.y       +=     blk.height / 2;
845
3.40k
        if( i == 2 )        blk.y       += 3 * blk.height;
846
3.40k
      }
847
1.13k
    }
848
849
378
    return 3;
850
378
  }
851
60
  else if( splitType == CU_TRIV_SPLIT )
852
62
  {
853
62
    Partitioning& sub = dst;
854
855
248
    for( int i = 0; i < 3; i++ )
856
186
    {
857
186
      sub[i] = cuArea;
858
859
186
      for( auto &blk : sub[i].blocks )
860
558
      {
861
558
        blk.width >>= 1;
862
863
558
        if( ( i + 1 ) & 1 ) blk.width >>= 1;
864
558
        if( i == 1 )        blk.x      +=     blk.width / 2;
865
558
        if( i == 2 )        blk.x      += 3 * blk.width;
866
558
      }
867
186
    }
868
869
62
    return 3;
870
62
  }
871
18.4E
  else
872
18.4E
  {
873
18.4E
    THROW( "Unknown CU sub-partitioning" );
874
18.4E
  }
875
169k
}
876
877
int PartitionerImpl::getTUIntraSubPartitions( Partitioning& sub, const UnitArea &tuArea, const CodingStructure &cs, const PartSplit splitType, const TreeType treeType )
878
21.6k
{
879
21.6k
  uint32_t nPartitions;
880
21.6k
  uint32_t splitDimensionSize = CU::getISPSplitDim( tuArea.lumaSize().width, tuArea.lumaSize().height, splitType );
881
882
21.6k
  bool isDualTree = CS::isDualITree( cs ) || treeType != TREE_D;
883
884
21.6k
  if( splitType == TU_1D_HORZ_SPLIT )
885
10.4k
  {
886
10.4k
    nPartitions = tuArea.lumaSize().height >> Log2(splitDimensionSize);
887
888
52.0k
    for( uint32_t i = 0; i < nPartitions; i++ )
889
41.6k
    {
890
41.6k
      sub[i] = tuArea;
891
41.6k
      CompArea& blkY = sub[i].blocks[COMP_Y];
892
893
41.6k
      blkY.height = splitDimensionSize;
894
41.6k
      blkY.y = i > 0 ? sub[i - 1].blocks[COMP_Y].y + splitDimensionSize : blkY.y;
895
896
41.6k
      CHECK( sub[i].lumaSize().height < 1, "the cs split causes the block to be smaller than the minimal TU size" );
897
41.6k
    }
898
10.4k
  }
899
11.2k
  else if( splitType == TU_1D_VERT_SPLIT )
900
11.2k
  {
901
11.2k
    nPartitions = tuArea.lumaSize().width >> Log2(splitDimensionSize);
902
903
56.3k
    for( uint32_t i = 0; i < nPartitions; i++ )
904
45.0k
    {
905
45.0k
      sub[i] = tuArea;
906
45.0k
      CompArea& blkY = sub[i].blocks[COMP_Y];
907
908
45.0k
      blkY.width = splitDimensionSize;
909
45.0k
      blkY.x = i > 0 ? sub[i - 1].blocks[COMP_Y].x + splitDimensionSize : blkY.x;
910
45.0k
      CHECK( sub[i].lumaSize().width < 1, "the split causes the block to be smaller than the minimal TU size" );
911
45.0k
    }
912
11.2k
  }
913
0
  else
914
0
  {
915
0
    THROW( "Unknown TU sub-partitioning" );
916
0
  }
917
  //we only partition luma, so there is going to be only one chroma tu at the end (unless it is dual tree, in which case there won't be any chroma components)
918
21.6k
  uint32_t partitionsWithoutChroma = (cs.area.chromaFormat == CHROMA_400) ? 0 : (isDualTree ? nPartitions : nPartitions - 1);
919
108k
  for( uint32_t i = 0; i < partitionsWithoutChroma; i++ )
920
86.6k
  {
921
86.6k
    CompArea& blkCb = sub[i].blocks[COMP_Cb];
922
86.6k
    CompArea& blkCr = sub[i].blocks[COMP_Cr];
923
86.6k
    blkCb = CompArea();
924
86.6k
    blkCr = CompArea();
925
86.6k
  }
926
927
21.6k
  return nPartitions;
928
21.6k
}
929
930
931
static const int g_rsScanToZ_w4[16] =
932
{
933
   0,  1,  4,  5, // wouldn't work for 128x32 blocks, but those are forbidden bcs of VPDU constraints
934
   2,  3,  6,  7, // correct ordering for 128x64 (TU32)
935
   8,  9, 12, 13,
936
  10, 11, 14, 15, // correct ordering for 128x128 (TU32)
937
};
938
939
static const int g_rsScanToZ_w2[8] =
940
{
941
   0,  1, // correct ordering for 64x32 (TU32) and 128x64 (TU64)
942
   2,  3, // correct ordering for 64x64 (TU32) and 128x128 (TU64)
943
   4,  5,
944
   6,  7, // correct ordering for 32x64 (TU32) and 64x128 (TU64)
945
};
946
947
static const int g_rsScanToZ_w1[4] =
948
{
949
   0, // no tiling, never used
950
   1, // correct ordering for 64x32 (TU32) and 128x64 (TU64)
951
   2,
952
   3, // correct ordering for 128x32 (TU32)
953
};
954
955
static const int* g_rsScanToZ[3] = { g_rsScanToZ_w1, g_rsScanToZ_w2, g_rsScanToZ_w4 };
956
957
int PartitionerImpl::getMaxTuTiling( Partitioning& dst, const UnitArea& cuArea, const CodingStructure& cs )
958
0
{
959
0
  const Size area = cuArea.lumaSize();
960
0
  const int maxTrSize = cs.sps->getMaxTbSize();
961
0
  const int numTilesH = std::max<int>( 1, area.width / maxTrSize );
962
0
  const int numTilesV = std::max<int>( 1, area.height / maxTrSize );
963
0
  const int numTiles  = numTilesH * numTilesV;
964
0
  const int numLog2H  = Log2( numTilesH );
965
0
  const int* rsScanToZ = g_rsScanToZ[numLog2H];
966
967
0
  Partitioning& ret = dst;
968
969
0
  for( int i = 0; i < numTiles; i++ )
970
0
  {
971
0
    ret[i] = cuArea;
972
973
0
    const int zid = rsScanToZ[i];
974
975
0
    const int y = zid >> numLog2H;
976
0
    const int x = zid & ( ( 1 << numLog2H ) - 1 );
977
978
0
    UnitArea& tile = ret[i];
979
980
0
    for( CompArea& comp : tile.blocks )
981
0
    {
982
0
      if( !comp.valid() ) continue;
983
984
0
      comp.width  /= numTilesH;
985
0
      comp.height /= numTilesV;
986
987
0
      comp.x += comp.width  * x;
988
0
      comp.y += comp.height * y;
989
0
    }
990
0
  }
991
992
0
  return numTiles;
993
0
}
994
995
int PartitionerImpl::getSbtTuTiling( Partitioning& dst, const UnitArea& cuArea, const CodingStructure &cs, const PartSplit splitType )
996
0
{
997
0
  Partitioning& ret = dst;
998
0
  int numTiles      = 2;
999
0
  int widthFactor, heightFactor, xOffsetFactor, yOffsetFactor;
1000
1001
0
  CHECK( !(splitType >= SBT_VER_HALF_POS0_SPLIT && splitType <= SBT_HOR_QUAD_POS1_SPLIT), "wrong" );
1002
1003
0
  for( int i = 0; i < numTiles; i++ )
1004
0
  {
1005
0
    ret[i] = cuArea;
1006
1007
0
    if( splitType >= SBT_VER_QUAD_POS0_SPLIT )
1008
0
    {
1009
0
      if( splitType == SBT_HOR_QUAD_POS0_SPLIT || splitType == SBT_HOR_QUAD_POS1_SPLIT )
1010
0
      {
1011
0
        widthFactor   = 4;
1012
0
        xOffsetFactor = 0;
1013
0
        heightFactor  = ( ( i == 0 &&        splitType == SBT_HOR_QUAD_POS0_SPLIT ) || ( i == 1 && splitType == SBT_HOR_QUAD_POS1_SPLIT ) ) ? 1 : 3;
1014
0
        yOffsetFactor =   ( i == 0 ) ? 0 : ( splitType == SBT_HOR_QUAD_POS0_SPLIT ? 1 : 3 );
1015
0
      }
1016
0
      else
1017
0
      {
1018
0
        widthFactor   = ( ( i == 0 &&        splitType == SBT_VER_QUAD_POS0_SPLIT ) || ( i == 1 && splitType == SBT_VER_QUAD_POS1_SPLIT ) ) ? 1 : 3;
1019
0
        xOffsetFactor =   ( i == 0 ) ? 0 : ( splitType == SBT_VER_QUAD_POS0_SPLIT ? 1 : 3 );
1020
0
        heightFactor  = 4;
1021
0
        yOffsetFactor = 0;
1022
0
      }
1023
0
    }
1024
0
    else
1025
0
    {
1026
0
      if( splitType == SBT_HOR_HALF_POS0_SPLIT || splitType == SBT_HOR_HALF_POS1_SPLIT )
1027
0
      {
1028
0
        widthFactor   = 4;
1029
0
        xOffsetFactor = 0;
1030
0
        heightFactor  = 2;
1031
0
        yOffsetFactor = ( i == 0 ) ? 0 : 2;
1032
0
      }
1033
0
      else
1034
0
      {
1035
0
        widthFactor   = 2;
1036
0
        xOffsetFactor = ( i == 0 ) ? 0 : 2;
1037
0
        heightFactor  = 4;
1038
0
        yOffsetFactor = 0;
1039
0
      }
1040
0
    }
1041
1042
0
    UnitArea& tile = ret[i];
1043
1044
0
    for( CompArea &comp : tile.blocks )
1045
0
    {
1046
0
      if( !comp.valid() ) continue;
1047
1048
0
      comp.x     += ( comp.width  * xOffsetFactor ) >> 2;
1049
0
      comp.y     += ( comp.height * yOffsetFactor ) >> 2;
1050
0
      comp.width  = ( comp.width  * widthFactor   ) >> 2;
1051
0
      comp.height = ( comp.height * heightFactor  ) >> 2;
1052
0
    }
1053
0
  }
1054
1055
0
  return numTiles;
1056
0
}
1057
1058
1059
} // namespace vvenc
1060
1061
//! \}
1062