Coverage Report

Created: 2026-06-15 06:25

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
1.97M
: split               ( CU_DONT_SPLIT )
62
, parts               (               )
63
1.97M
, idx                 ( 0u            )
64
1.97M
, checkdIfImplicit    ( false         )
65
1.97M
, isImplicit          ( false         )
66
1.97M
, implicitSplit       ( CU_DONT_SPLIT )
67
1.97M
, firstSubPartSplit   ( CU_DONT_SPLIT )
68
1.97M
, canQtSplit          ( true          )
69
1.97M
, qgEnable            ( true          )
70
1.97M
, qgChromaEnable      ( true          )
71
1.97M
, modeType            ( MODE_TYPE_ALL )
72
1.97M
{
73
1.97M
}
74
75
void PartLevel::init()
76
180k
{
77
180k
  split               = CU_DONT_SPLIT;
78
180k
  idx                 = 0u;
79
180k
  checkdIfImplicit    = false;
80
180k
  isImplicit          = false;
81
180k
  implicitSplit       = CU_DONT_SPLIT;
82
180k
  firstSubPartSplit   = CU_DONT_SPLIT;
83
180k
  canQtSplit          = true;
84
180k
  qgEnable            = true;
85
180k
  qgChromaEnable      = true;
86
180k
  modeType            = MODE_TYPE_ALL;
87
180k
  numParts            = 0;
88
180k
}
89
90
//////////////////////////////////////////////////////////////////////////
91
// Partitioner class
92
//////////////////////////////////////////////////////////////////////////
93
94
SplitSeries Partitioner::getSplitSeries() const
95
119k
{
96
119k
  SplitSeries splitSeries = 0;
97
119k
  SplitSeries depth = 0;
98
99
119k
  for( const auto &level : m_partStack )
100
483k
  {
101
483k
    if( level.split == CTU_LEVEL ) continue;
102
363k
    else splitSeries += static_cast< SplitSeries >( level.split ) << ( depth * SPLIT_DMULT );
103
104
363k
    depth++;
105
363k
  }
106
107
119k
  return splitSeries;
108
119k
}
109
110
ModeTypeSeries Partitioner::getModeTypeSeries() const
111
119k
{
112
119k
  ModeTypeSeries modeTypeSeries = 0;
113
119k
  int depth = 0;
114
115
119k
  for( const auto &level : m_partStack )
116
483k
  {
117
483k
    if( level.split == CTU_LEVEL ) continue;
118
363k
    else modeTypeSeries += static_cast<int>(level.modeType) << (depth * 3);
119
120
363k
    depth++;
121
363k
  }
122
123
119k
  return modeTypeSeries;
124
119k
}
125
126
bool Partitioner::isSepTree( const CodingStructure &cs )
127
660k
{
128
660k
  return treeType != TREE_D || CS::isDualITree( cs );
129
660k
}
130
131
void Partitioner::setCUData( CodingUnit& cu )
132
119k
{
133
119k
  cu.depth       = currDepth;
134
119k
  cu.btDepth     = currBtDepth;
135
119k
  cu.mtDepth     = currMtDepth;
136
119k
  cu.qtDepth     = currQtDepth;
137
119k
  cu.splitSeries = getSplitSeries();
138
119k
  cu.modeTypeSeries = getModeTypeSeries();
139
119k
  cu.treeType    = treeType; 
140
119k
  cu.modeType    = modeType; 
141
142
119k
}
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
116k
{
165
116k
  unsigned          stdMinDepth = 0;
166
116k
  unsigned          stdMaxDepth = cs.pcv->getMaxDepth( cs.slice->sliceType, chType );
167
116k
  const Position    pos         = currArea().blocks[chType].pos();
168
116k
  const unsigned    curSliceIdx = cs.slice->independentSliceIdx;
169
116k
  const unsigned    curTileIdx  = cs.pps->getTileIdx( currArea().lumaPos() );
170
171
116k
  const CodingUnit* cuLeft        = cs.getCURestricted( pos.offset( -1,                               0 ), pos, curSliceIdx, curTileIdx, chType, treeType );
172
116k
  const CodingUnit* cuBelowLeft   = cs.getCURestricted( pos.offset( -1, currArea().blocks[chType].height), pos, curSliceIdx, curTileIdx, chType, treeType );
173
116k
  const CodingUnit* cuAbove       = cs.getCURestricted( pos.offset(  0,                              -1 ), pos, curSliceIdx, curTileIdx, chType, treeType );
174
116k
  const CodingUnit* cuAboveRight  = cs.getCURestricted( pos.offset( currArea().blocks[chType].width, -1 ), pos, curSliceIdx, curTileIdx, chType, treeType );
175
176
116k
  minDepth = stdMaxDepth;
177
116k
  maxDepth = stdMinDepth;
178
179
116k
  if( cuLeft )
180
68.5k
  {
181
68.5k
    minDepth = std::min<unsigned>( minDepth, cuLeft->qtDepth );
182
68.5k
    maxDepth = std::max<unsigned>( maxDepth, cuLeft->qtDepth );
183
68.5k
  }
184
48.2k
  else
185
48.2k
  {
186
48.2k
    minDepth = stdMinDepth;
187
48.2k
    maxDepth = stdMaxDepth;
188
48.2k
  }
189
190
116k
  if( cuBelowLeft )
191
9.87k
  {
192
9.87k
    minDepth = std::min<unsigned>( minDepth, cuBelowLeft->qtDepth );
193
9.87k
    maxDepth = std::max<unsigned>( maxDepth, cuBelowLeft->qtDepth );
194
9.87k
  }
195
106k
  else
196
106k
  {
197
106k
    minDepth = stdMinDepth;
198
106k
    maxDepth = stdMaxDepth;
199
106k
  }
200
201
116k
  if( cuAbove )
202
70.7k
  {
203
70.7k
    minDepth = std::min<unsigned>( minDepth, cuAbove->qtDepth );
204
70.7k
    maxDepth = std::max<unsigned>( maxDepth, cuAbove->qtDepth );
205
70.7k
  }
206
46.0k
  else
207
46.0k
  {
208
46.0k
    minDepth = stdMinDepth;
209
46.0k
    maxDepth = stdMaxDepth;
210
46.0k
  }
211
212
116k
  if( cuAboveRight )
213
24.5k
  {
214
24.5k
    minDepth = std::min<unsigned>( minDepth, cuAboveRight->qtDepth );
215
24.5k
    maxDepth = std::max<unsigned>( maxDepth, cuAboveRight->qtDepth );
216
24.5k
  }
217
92.2k
  else
218
92.2k
  {
219
92.2k
    minDepth = stdMinDepth;
220
92.2k
    maxDepth = stdMaxDepth;
221
92.2k
  }
222
223
116k
  minDepth = ( minDepth >= 1 ? minDepth - 1 : 0 );
224
116k
  maxDepth = std::min<unsigned>( stdMaxDepth, maxDepth + 1 );
225
116k
  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
116k
  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
116k
}
288
289
void Partitioner::initCtu( const UnitArea& ctuArea, const ChannelType _chType, const Slice& slice )
290
19.9k
{
291
19.9k
#if _DEBUG
292
19.9k
  m_currArea = ctuArea;
293
19.9k
#endif
294
19.9k
  currDepth   = 0;
295
19.9k
  currTrDepth = 0;
296
19.9k
  currBtDepth = 0;
297
19.9k
  currMtDepth = 0;
298
19.9k
  currQtDepth = 0;
299
19.9k
  currSubdiv  = 0;
300
19.9k
  currQgPos   = ctuArea.lumaPos();
301
19.9k
  currQgChromaPos = ctuArea.chromaFormat != CHROMA_400 ? ctuArea.chromaPos() : Position();
302
19.9k
  currImplicitBtDepth = 0;
303
19.9k
  chType      = _chType;
304
305
19.9k
  const PreCalcValues& pcv = *slice.pps->pcv;
306
  
307
19.9k
  maxBTD      = pcv.getMaxMTTDepth( slice, chType );
308
19.9k
  maxBtSize   = pcv.getMaxBtSize  ( slice, chType );
309
19.9k
  minTSize    = pcv.getMinTSize   ( slice, chType );
310
19.9k
  maxTtSize   = pcv.getMaxTtSize  ( slice, chType );
311
19.9k
  minQtSize   = pcv.getMinQtSize  ( slice, chType );
312
  
313
19.9k
  m_partBufIdx = 1;
314
19.9k
  m_partStack.resize_noinit( 1 );
315
19.9k
  m_partStack.back().init();
316
19.9k
  m_partStack.back().split = CTU_LEVEL;
317
19.9k
  m_partStack.back().parts = m_partBuf;
318
19.9k
  m_partStack.back().parts[0] = ctuArea;
319
19.9k
  m_partStack.back().numParts = 1;
320
321
19.9k
  treeType = TREE_D;
322
19.9k
  modeType = MODE_TYPE_ALL;
323
19.9k
}
324
325
void Partitioner::splitCurrArea( const PartSplit split, const CodingStructure& cs )
326
160k
{
327
160k
  if ((split != TU_1D_HORZ_SPLIT) && (split != TU_1D_VERT_SPLIT))
328
141k
  {
329
141k
    CHECKD(!canSplit(split, cs), "Trying to apply a prohibited split!");
330
141k
  }
331
332
160k
  bool isImplicit = isSplitImplicit( split, cs );
333
160k
  bool canQtSplit = canSplit( CU_QUAD_SPLIT, cs );
334
160k
  bool qgEnable = currQgEnable();
335
160k
  bool qgChromaEnable = currQgChromaEnable();
336
337
160k
  const UnitArea& area = currArea();
338
160k
  m_partStack.resize_noinit( m_partStack.size() + 1 );
339
160k
  PartLevel& back = m_partStack.back();
340
160k
  back.init();
341
160k
  back.split = split;
342
160k
  back.parts = &m_partBuf[m_partBufIdx];
343
160k
  int numParts;
344
345
160k
  CHECK( m_partBufIdx > partBufSize, "Partition buffer overflow" );
346
347
160k
  switch( split )
348
160k
  {
349
46.4k
  case CU_QUAD_SPLIT:
350
46.4k
    numParts = PartitionerImpl::getCUSubPartitions( back.parts, area, cs, split );
351
46.4k
    back.modeType = modeType;
352
46.4k
    break;
353
47.0k
  case CU_HORZ_SPLIT:
354
94.8k
  case CU_VERT_SPLIT:
355
94.8k
    numParts = PartitionerImpl::getCUSubPartitions( back.parts, area, cs, split );
356
94.8k
    back.modeType = modeType;
357
94.8k
    break;
358
288
  case CU_TRIH_SPLIT:
359
338
  case CU_TRIV_SPLIT:
360
338
    numParts = PartitionerImpl::getCUSubPartitions( back.parts, area, cs, split );
361
338
    back.modeType = modeType;
362
338
    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
8.86k
  case TU_1D_HORZ_SPLIT:
377
18.5k
  case TU_1D_VERT_SPLIT:
378
18.5k
  {
379
18.5k
    numParts = PartitionerImpl::getTUIntraSubPartitions(back.parts, area, cs, split, TREE_D);
380
18.5k
    break;
381
8.86k
  }
382
0
  default:
383
0
    THROW( "Unknown split mode" );
384
0
    break;
385
160k
  }
386
387
160k
  back.numParts = numParts;
388
160k
  m_partBufIdx += numParts;
389
390
160k
  CHECK( m_partBufIdx > partBufSize, "Partition buffer overflow" );
391
392
160k
  currDepth++;
393
160k
  currSubdiv++;
394
160k
#if _DEBUG
395
160k
  m_currArea = m_partStack.back().parts[0];
396
160k
#endif
397
398
160k
  if ((split == TU_MAX_TR_SPLIT) || (split == TU_1D_HORZ_SPLIT) || (split == TU_1D_VERT_SPLIT))
399
18.5k
  {
400
18.5k
    currTrDepth++;
401
18.5k
  }
402
141k
  else if( split >= SBT_VER_HALF_POS0_SPLIT && split <= SBT_HOR_QUAD_POS1_SPLIT )
403
0
  {
404
0
    currTrDepth++;
405
0
  }
406
141k
  else
407
141k
  {
408
141k
    currTrDepth = 0;
409
141k
  }
410
411
160k
  if( split == CU_HORZ_SPLIT || split == CU_VERT_SPLIT || split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT )
412
95.2k
  {
413
95.2k
    currBtDepth++;
414
95.2k
    if( isImplicit ) currImplicitBtDepth++;
415
95.2k
    currMtDepth++;
416
417
95.2k
    if( split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT )
418
338
    {
419
      // first and last part of triple split are equivalent to double bt split
420
338
      currBtDepth++;
421
338
      currSubdiv++;
422
338
    }
423
95.2k
    m_partStack.back().canQtSplit = canQtSplit;
424
95.2k
  }
425
65.0k
  else if( split == CU_QUAD_SPLIT )
426
46.4k
  {
427
46.4k
    CHECK( currBtDepth > 0, "Cannot split a non-square area other than with a binary split" );
428
46.4k
    CHECK( currMtDepth > 0, "Cannot split a non-square area other than with a binary split" );
429
46.4k
    currMtDepth = 0;
430
46.4k
    currBtDepth = 0;
431
46.4k
    currQtDepth++;
432
46.4k
    currSubdiv++;
433
46.4k
  }
434
435
160k
  qgEnable       &= (currSubdiv <= (cs.slice->isIntra() ? cs.slice->picHeader->cuQpDeltaSubdivIntra : cs.slice->picHeader->cuQpDeltaSubdivInter ));
436
160k
  qgChromaEnable &= (currSubdiv <= (cs.slice->isIntra() ? cs.slice->picHeader->cuChromaQpOffsetSubdivIntra : cs.slice->picHeader->cuChromaQpOffsetSubdivInter ));
437
160k
  m_partStack.back().qgEnable       = qgEnable;
438
160k
  m_partStack.back().qgChromaEnable = qgChromaEnable;
439
160k
  if (qgEnable)
440
7.37k
    currQgPos = currArea().lumaPos();
441
160k
  if (qgChromaEnable)
442
0
    currQgChromaPos = currArea().chromaPos();
443
160k
}
444
445
void Partitioner::canSplit( const CodingStructure &cs, bool& canNo, bool& canQt, bool& canBh, bool& canBv, bool& canTh, bool& canTv )
446
2.04M
{
447
2.04M
  const PartSplit implicitSplit = m_partStack.back().checkdIfImplicit ? m_partStack.back().implicitSplit : getImplicitSplit( cs );
448
449
2.04M
  canNo = canQt = canBh = canTh = canBv = canTv = true;
450
2.04M
  bool canBtt = currMtDepth < (maxBTD + currImplicitBtDepth);
451
452
  // the minimal and maximal sizes are given in luma samples
453
2.04M
  const CompArea&  area  = currArea().Y();
454
2.04M
  const CompArea  *areaC = (chType == CH_C) ? &(currArea().Cb()) : nullptr;
455
2.04M
        PartLevel& level = m_partStack.back();
456
457
2.04M
  const PartSplit lastSplit = level.split;
458
2.04M
  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.04M
  if( lastSplit != CTU_LEVEL && lastSplit != CU_QUAD_SPLIT ) canQt = false;
462
  // minQtSize is in luma samples unit
463
2.04M
  const unsigned minQTThreshold = minQtSize >> ((area.chromaFormat == CHROMA_400) ? 0 : ((int) getChannelTypeScaleX(CH_C, area.chromaFormat) - (int) getChannelTypeScaleY(CH_C, area.chromaFormat)));
464
2.04M
  if( area.width <= minQTThreshold )                         canQt = false;
465
2.04M
  if( areaC && areaC->width <= MIN_DUALTREE_CHROMA_WIDTH ) canQt = false;
466
2.04M
  if( treeType == TREE_C )
467
0
  {
468
0
    canQt = canBh = canTh = canBv = canTv = false;
469
0
    return;
470
0
  }
471
2.04M
  if( implicitSplit != CU_DONT_SPLIT )
472
756k
  {
473
756k
    canNo = canTh = canTv = false;
474
475
756k
    canBh = implicitSplit == CU_HORZ_SPLIT;
476
756k
    canBv = implicitSplit == CU_VERT_SPLIT;
477
756k
    if (areaC && areaC->width == 4) canBv = false;
478
756k
    if( !canBh && !canBv && !canQt ) canQt = true;
479
756k
    return;
480
756k
  }
481
482
1.28M
  if( ( lastSplit == CU_TRIH_SPLIT || lastSplit == CU_TRIV_SPLIT ) && currPartIdx() == 1 )
483
3.76k
  {
484
3.76k
    canBh = parlSplit != CU_HORZ_SPLIT;
485
3.76k
    canBv = parlSplit != CU_VERT_SPLIT;
486
3.76k
  }
487
488
1.28M
  if( canBtt && ( area.width <= minTSize && area.height <= minTSize ) )
489
0
  {
490
0
    canBtt = false;
491
0
  }
492
1.28M
  if( canBtt && ( area.width > maxBtSize || area.height > maxBtSize )
493
84.9k
      && ( ( area.width > maxTtSize || area.height > maxTtSize ) ) )
494
84.9k
  {
495
84.9k
    canBtt = false;
496
84.9k
  }
497
498
1.28M
  if( !canBtt )
499
288k
  {
500
288k
    canBh = canTh = canBv = canTv = false;
501
502
288k
    return;
503
288k
  }
504
505
997k
  if( area.width > maxBtSize || area.height > maxBtSize )
506
0
  {
507
0
    canBh = canBv = false;
508
0
  }
509
510
  // specific check for BT splits
511
997k
  if( area.height <= minTSize )                            canBh = false;
512
997k
  if( area.width > MAX_TB_SIZEY && area.height <= MAX_TB_SIZEY ) canBh = false;
513
997k
  if( areaC && areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE )     canBh = false;
514
997k
  if( area.width <= minTSize )                              canBv = false;
515
997k
  if( area.width <= MAX_TB_SIZEY && area.height > MAX_TB_SIZEY ) canBv = false;
516
997k
  if (areaC && (areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE || areaC->width == 4))     canBv = false;
517
997k
  if( modeType == MODE_TYPE_INTER && area.width * area.height == 32 )  canBv = canBh = false;
518
997k
  if( area.height <= 2 * minTSize || area.height > maxTtSize || area.width > maxTtSize )
519
413k
                                                                                       canTh = false;
520
997k
  if( area.width > MAX_TB_SIZEY || area.height > MAX_TB_SIZEY )  canTh = false;
521
997k
  if( areaC && areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE*2 )     canTh = false;
522
997k
  if( area.width <= 2 * minTSize || area.width > maxTtSize || area.height > maxTtSize )
523
403k
                                                                                       canTv = false;
524
997k
  if( area.width > MAX_TB_SIZEY || area.height > MAX_TB_SIZEY )  canTv = false;
525
997k
  if (areaC && (areaC->width * areaC->height <= MIN_DUALTREE_CHROMA_SIZE * 2 || areaC->width == 8))     canTv = false;
526
997k
  if( modeType == MODE_TYPE_INTER && area.width * area.height == 64 )  canTv = canTh = false;
527
997k
}
528
529
bool Partitioner::canSplit( const PartSplit split, const CodingStructure &cs )
530
1.64M
{
531
1.64M
  const CompArea area       = currArea().Y();
532
1.64M
  const unsigned maxTrSize  = cs.sps->getMaxTbSize();
533
534
1.64M
  bool canNo, canQt, canBh, canTh, canBv, canTv;
535
536
1.64M
  canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv );
537
538
1.64M
  switch( split )
539
1.64M
  {
540
0
  case CTU_LEVEL:
541
0
    THROW( "Checking if top level split is possible" );
542
0
    return true;
543
0
    break;
544
237k
  case TU_MAX_TR_SPLIT:
545
237k
    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
345k
  case CU_QUAD_SPLIT:
558
345k
    return canQt;
559
71.1k
  case CU_DONT_SPLIT:
560
71.1k
    return canNo;
561
354k
  case CU_HORZ_SPLIT:
562
354k
    return canBh;
563
352k
  case CU_VERT_SPLIT:
564
352k
    return canBv;
565
143k
  case CU_TRIH_SPLIT:
566
143k
    return canTh;
567
137k
  case CU_TRIV_SPLIT:
568
137k
    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.64M
  }
579
580
0
  return true;
581
1.64M
}
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
160k
{
609
160k
  return split == getImplicitSplit( cs );
610
160k
}
611
612
PartSplit Partitioner::getImplicitSplit( const CodingStructure &cs )
613
831k
{
614
831k
  if( m_partStack.back().checkdIfImplicit )
615
562k
  {
616
562k
    return m_partStack.back().implicitSplit;
617
562k
  }
618
619
269k
  PartSplit split = CU_DONT_SPLIT;
620
621
269k
  if( split == CU_DONT_SPLIT )
622
269k
  {
623
269k
    const bool isBlInPic = cs.picture->Y().contains( currArea().Y().bottomLeft() );
624
269k
    const bool isTrInPic = cs.picture->Y().contains( currArea().Y().topRight() );
625
626
269k
    const CompArea& area      = currArea().Y();
627
269k
    const bool isBtAllowed    = area.width <= maxBtSize && area.height <= maxBtSize && currMtDepth < (maxBTD + currImplicitBtDepth);
628
    // minQtSize is in luma samples unit
629
269k
    const unsigned minQTThreshold = minQtSize >> ((area.chromaFormat == CHROMA_400) ? 0 : ((int) getChannelTypeScaleX(CH_C, area.chromaFormat) - (int) getChannelTypeScaleY(CH_C, area.chromaFormat)));
630
269k
    const bool isQtAllowed    = area.width > minQTThreshold && currBtDepth == 0;
631
632
269k
    if( !isBlInPic && !isTrInPic && isQtAllowed )
633
18.7k
    {
634
18.7k
      split = CU_QUAD_SPLIT;
635
18.7k
    }
636
250k
    else if( !isBlInPic && isBtAllowed && area.width <= MAX_TB_SIZEY )
637
39.1k
    {
638
39.1k
      split = CU_HORZ_SPLIT;
639
39.1k
    }
640
211k
    else if( !isTrInPic && isBtAllowed && area.height <= MAX_TB_SIZEY )
641
40.8k
    {
642
40.8k
      split = CU_VERT_SPLIT;
643
40.8k
    }
644
170k
    else if( !isBlInPic || !isTrInPic )
645
20.7k
    {
646
20.7k
      split = CU_QUAD_SPLIT;
647
20.7k
    }
648
269k
    if (CS::isDualITree(cs) && (currArea().Y().width > 64 || currArea().Y().height > 64))
649
19.9k
    {
650
19.9k
      split = CU_QUAD_SPLIT;
651
19.9k
    }
652
269k
    if( (!isBlInPic || !isTrInPic) && split == CU_DONT_SPLIT )
653
0
    {
654
0
      split = CU_QUAD_SPLIT;
655
0
    }
656
269k
  }
657
658
269k
  m_partStack.back().checkdIfImplicit = true;
659
269k
  m_partStack.back().isImplicit = split != CU_DONT_SPLIT;
660
269k
  m_partStack.back().implicitSplit = split;
661
662
269k
  return split;
663
831k
}
664
665
void Partitioner::exitCurrSplit()
666
160k
{
667
160k
  const PartSplit currSplit = m_partStack.back().split;
668
160k
  const int       currIndex = m_partStack.back().idx;
669
160k
  const int       numParts  = m_partStack.back().numParts;
670
671
160k
  m_partStack.pop_back();
672
160k
  m_partBufIdx -= numParts;
673
674
160k
  CHECK( currDepth == 0, "depth is '0', although a split was performed" );
675
160k
  currDepth--;
676
160k
  currSubdiv--;
677
160k
  if( currQgEnable() )
678
33.3k
    currQgPos = currArea().lumaPos();
679
160k
  if( currArea().chromaFormat != CHROMA_400 && currQgChromaEnable() )
680
19.9k
    currQgChromaPos = currArea().chromaPos();
681
160k
#if _DEBUG
682
160k
  m_currArea = m_partStack.back().parts[m_partStack.back().idx];
683
160k
#endif
684
685
160k
  if( currSplit == CU_HORZ_SPLIT || currSplit == CU_VERT_SPLIT || currSplit == CU_TRIH_SPLIT || currSplit == CU_TRIV_SPLIT )
686
95.2k
  {
687
95.2k
    CHECK( !m_partStack.back().checkdIfImplicit, "Didn't check if the current split is implicit" );
688
95.2k
    CHECK( currBtDepth == 0, "BT depth is '0', athough a BT split was performed" );
689
95.2k
    CHECK( currMtDepth == 0, "MT depth is '0', athough a BT split was performed" );
690
95.2k
    currMtDepth--;
691
95.2k
    if( m_partStack.back().isImplicit ) currImplicitBtDepth--;
692
95.2k
    currBtDepth--;
693
95.2k
    if( ( currSplit == CU_TRIH_SPLIT || currSplit == CU_TRIV_SPLIT ) && currIndex != 1 )
694
338
    {
695
338
      CHECK( currBtDepth == 0, "BT depth is '0', athough a TT split was performed" );
696
338
      currBtDepth--;
697
338
      currSubdiv--;
698
338
    }
699
95.2k
  }
700
65.0k
  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
65.0k
  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
65.0k
  else if ((currSplit == TU_1D_HORZ_SPLIT) || (currSplit == TU_1D_VERT_SPLIT))
711
18.5k
  {
712
18.5k
    CHECK(currTrDepth == 0, "TR depth is '0', although a TU split was performed");
713
18.5k
    currTrDepth--;
714
18.5k
  }
715
46.4k
  else
716
46.4k
  {
717
46.4k
    CHECK( currTrDepth > 0, "RQT found with QTBT partitioner" );
718
719
46.4k
    CHECK( currQtDepth == 0, "QT depth is '0', although a QT split was performed" );
720
46.4k
    currQtDepth--;
721
46.4k
    currSubdiv--;
722
46.4k
  }
723
160k
}
724
725
bool Partitioner::nextPart( const CodingStructure &cs, bool autoPop /*= false*/ )
726
400k
{
727
400k
  const Position& prevPos = currArea().blocks[chType].pos();
728
729
400k
  unsigned currIdx = ++m_partStack.back().idx;
730
731
400k
  m_partStack.back().checkdIfImplicit = false;
732
400k
  m_partStack.back().isImplicit = false;
733
734
400k
  if( currIdx == 1 )
735
147k
  {
736
147k
    const CodingUnit* prevCU = cs.getCU( prevPos, chType, treeType );
737
18.4E
    m_partStack.back().firstSubPartSplit = prevCU ? CU::getSplitAtDepth( *prevCU, currDepth ) : CU_DONT_SPLIT;
738
147k
  }
739
740
400k
  if( currIdx < m_partStack.back().numParts )
741
252k
  {
742
252k
    if( m_partStack.back().split == CU_TRIH_SPLIT || m_partStack.back().split == CU_TRIV_SPLIT )
743
676
    {
744
      // adapt the current bt depth
745
676
      if( currIdx == 1 ) currBtDepth--;
746
338
      else               currBtDepth++;
747
676
      if( currIdx == 1 ) currSubdiv--;
748
338
      else               currSubdiv++;
749
676
    }
750
252k
  if( currQgEnable() )
751
22.1k
    currQgPos = currArea().lumaPos();
752
252k
  if( currQgChromaEnable() )
753
0
    currQgChromaPos = currArea().chromaPos();
754
252k
#if _DEBUG
755
252k
    m_currArea = m_partStack.back().parts[currIdx];
756
252k
#endif
757
252k
    return true;
758
252k
  }
759
147k
  else
760
147k
  {
761
147k
    if( autoPop ) exitCurrSplit();
762
147k
    return false;
763
147k
  }
764
400k
}
765
766
bool Partitioner::hasNextPart()
767
110k
{
768
110k
  return ( ( m_partStack.back().idx + 1 ) < m_partStack.back().numParts );
769
110k
}
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
141k
{
777
141k
  const PartSplit splitType = _splitType;
778
779
141k
  if( splitType == CU_QUAD_SPLIT )
780
46.4k
  {
781
46.4k
    Partitioning& sub = dst;
782
783
232k
    for( uint32_t i = 0; i < 4; i++ )
784
185k
    {
785
185k
      sub[i] = cuArea;
786
787
185k
      for( auto &blk : sub[i].blocks )
788
557k
      {
789
557k
        blk.height >>= 1;
790
557k
        blk.width  >>= 1;
791
557k
        if( i >= 2 ) blk.y += blk.height;
792
557k
        if( i &  1 ) blk.x += blk.width;
793
557k
      }
794
185k
    }
795
796
46.4k
    return 4;
797
46.4k
  }
798
95.2k
  else if( splitType == CU_HORZ_SPLIT )
799
47.0k
  {
800
47.0k
    Partitioning& sub = dst;
801
802
141k
    for (uint32_t i = 0; i < 2; i++)
803
94.1k
    {
804
94.1k
      sub[i] = cuArea;
805
806
94.1k
      for (auto &blk : sub[i].blocks)
807
282k
      {
808
282k
        blk.height >>= 1;
809
282k
        if (i == 1) blk.y += blk.height;
810
282k
      }
811
94.1k
    }
812
813
47.0k
    return 2;
814
47.0k
  }
815
48.1k
  else if( splitType == CU_VERT_SPLIT )
816
47.7k
  {
817
47.7k
    Partitioning& sub = dst;
818
819
143k
    for( uint32_t i = 0; i < 2; i++ )
820
95.5k
    {
821
95.5k
      sub[i] = cuArea;
822
823
95.5k
      for( auto &blk : sub[i].blocks )
824
286k
      {
825
286k
        blk.width >>= 1;
826
286k
        if( i == 1 ) blk.x += blk.width;
827
286k
      }
828
95.5k
    }
829
830
47.7k
    return 2;
831
47.7k
  }
832
336
  else if( splitType == CU_TRIH_SPLIT )
833
288
  {
834
288
    Partitioning& sub = dst;
835
836
1.15k
    for( int i = 0; i < 3; i++ )
837
864
    {
838
864
      sub[i] = cuArea;
839
840
864
      for( auto &blk : sub[i].blocks )
841
2.59k
      {
842
2.59k
        blk.height >>= 1;
843
2.59k
        if( ( i + 1 ) & 1 ) blk.height >>= 1;
844
2.59k
        if( i == 1 )        blk.y       +=     blk.height / 2;
845
2.59k
        if( i == 2 )        blk.y       += 3 * blk.height;
846
2.59k
      }
847
864
    }
848
849
288
    return 3;
850
288
  }
851
48
  else if( splitType == CU_TRIV_SPLIT )
852
50
  {
853
50
    Partitioning& sub = dst;
854
855
200
    for( int i = 0; i < 3; i++ )
856
150
    {
857
150
      sub[i] = cuArea;
858
859
150
      for( auto &blk : sub[i].blocks )
860
450
      {
861
450
        blk.width >>= 1;
862
863
450
        if( ( i + 1 ) & 1 ) blk.width >>= 1;
864
450
        if( i == 1 )        blk.x      +=     blk.width / 2;
865
450
        if( i == 2 )        blk.x      += 3 * blk.width;
866
450
      }
867
150
    }
868
869
50
    return 3;
870
50
  }
871
18.4E
  else
872
18.4E
  {
873
18.4E
    THROW( "Unknown CU sub-partitioning" );
874
18.4E
  }
875
141k
}
876
877
int PartitionerImpl::getTUIntraSubPartitions( Partitioning& sub, const UnitArea &tuArea, const CodingStructure &cs, const PartSplit splitType, const TreeType treeType )
878
18.5k
{
879
18.5k
  uint32_t nPartitions;
880
18.5k
  uint32_t splitDimensionSize = CU::getISPSplitDim( tuArea.lumaSize().width, tuArea.lumaSize().height, splitType );
881
882
18.5k
  bool isDualTree = CS::isDualITree( cs ) || treeType != TREE_D;
883
884
18.5k
  if( splitType == TU_1D_HORZ_SPLIT )
885
8.86k
  {
886
8.86k
    nPartitions = tuArea.lumaSize().height >> Log2(splitDimensionSize);
887
888
44.3k
    for( uint32_t i = 0; i < nPartitions; i++ )
889
35.4k
    {
890
35.4k
      sub[i] = tuArea;
891
35.4k
      CompArea& blkY = sub[i].blocks[COMP_Y];
892
893
35.4k
      blkY.height = splitDimensionSize;
894
35.4k
      blkY.y = i > 0 ? sub[i - 1].blocks[COMP_Y].y + splitDimensionSize : blkY.y;
895
896
35.4k
      CHECK( sub[i].lumaSize().height < 1, "the cs split causes the block to be smaller than the minimal TU size" );
897
35.4k
    }
898
8.86k
  }
899
9.70k
  else if( splitType == TU_1D_VERT_SPLIT )
900
9.70k
  {
901
9.70k
    nPartitions = tuArea.lumaSize().width >> Log2(splitDimensionSize);
902
903
48.5k
    for( uint32_t i = 0; i < nPartitions; i++ )
904
38.8k
    {
905
38.8k
      sub[i] = tuArea;
906
38.8k
      CompArea& blkY = sub[i].blocks[COMP_Y];
907
908
38.8k
      blkY.width = splitDimensionSize;
909
38.8k
      blkY.x = i > 0 ? sub[i - 1].blocks[COMP_Y].x + splitDimensionSize : blkY.x;
910
38.8k
      CHECK( sub[i].lumaSize().width < 1, "the split causes the block to be smaller than the minimal TU size" );
911
38.8k
    }
912
9.70k
  }
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
18.5k
  uint32_t partitionsWithoutChroma = (cs.area.chromaFormat == CHROMA_400) ? 0 : (isDualTree ? nPartitions : nPartitions - 1);
919
92.8k
  for( uint32_t i = 0; i < partitionsWithoutChroma; i++ )
920
74.3k
  {
921
74.3k
    CompArea& blkCb = sub[i].blocks[COMP_Cb];
922
74.3k
    CompArea& blkCr = sub[i].blocks[COMP_Cr];
923
74.3k
    blkCb = CompArea();
924
74.3k
    blkCr = CompArea();
925
74.3k
  }
926
927
18.5k
  return nPartitions;
928
18.5k
}
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