Coverage Report

Created: 2026-06-10 07:00

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