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/UnitTools.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     UnitTool.cpp
45
 *  \brief    defines operations for basic units
46
 */
47
48
#include "UnitTools.h"
49
#include "Unit.h"
50
#include "Slice.h"
51
#include "Picture.h"
52
#include "dtrace_next.h"
53
54
#include <utility>
55
#include <algorithm>
56
57
//! \ingroup CommonLib
58
//! \{
59
60
namespace vvenc {
61
62
// CS tools
63
64
void clipColPos(int& posX, int& posY, const CodingUnit& cu);
65
66
67
bool CS::isDualITree( const CodingStructure &cs )
68
11.9M
{
69
11.9M
  return cs.slice->isIntra() && !cs.pcv->ISingleTree;
70
11.9M
}
71
72
UnitArea CS::getArea( const CodingStructure &cs, const UnitArea& area, const ChannelType chType, const TreeType treeType )
73
637k
{
74
18.4E
  return isDualITree( cs ) || treeType != TREE_D ? area.singleChan( chType ) : area;
75
637k
}
76
77
int CS::signalModeCons( const CodingStructure &cs, const UnitArea &currArea, const PartSplit split, const ModeType modeTypeParent )
78
464k
{
79
464k
  const ChromaFormat chromaFormat = currArea.chromaFormat;
80
81
464k
  if( CS::isDualITree( cs ) || modeTypeParent != MODE_TYPE_ALL || chromaFormat == CHROMA_444 || chromaFormat == CHROMA_400 )
82
464k
    return LDT_MODE_TYPE_INHERIT;
83
84
0
  int minLumaArea = currArea.lumaSize().area();
85
0
  if( split == CU_QUAD_SPLIT || split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT ) // the area is split into 3 or 4 parts
86
0
  {
87
0
    minLumaArea = minLumaArea >> 2;
88
0
  }
89
0
  else if( split == CU_VERT_SPLIT || split == CU_HORZ_SPLIT ) // the area is split into 2 parts
90
0
  {
91
0
    minLumaArea = minLumaArea >> 1;
92
0
  }
93
94
0
  int minChromaBlock = minLumaArea >> ( getChannelTypeScaleX( CH_C, chromaFormat ) + getChannelTypeScaleY( CH_C, chromaFormat ) );
95
0
  bool is2xNChroma   = ( currArea.chromaSize().width == 4 && split == CU_VERT_SPLIT ) || ( currArea.chromaSize().width == 8 && split == CU_TRIV_SPLIT );
96
0
  return minChromaBlock >= 16 && !is2xNChroma ? LDT_MODE_TYPE_INHERIT
97
0
                                              : ( ( minLumaArea < 32 ) || cs.slice->isIntra() ) ? LDT_MODE_TYPE_INFER
98
0
                                                                                                : LDT_MODE_TYPE_SIGNAL;
99
464k
}
100
101
void refineCU( const CodingUnit& cu, MotionBuf& mb, MotionInfo* orgPtr )
102
0
{
103
0
  const int dy = std::min<int>( cu.lumaSize().height, DMVR_SUBCU_SIZE );
104
0
  const int dx = std::min<int>( cu.lumaSize().width,  DMVR_SUBCU_SIZE );
105
      
106
0
  static const unsigned scale = 4 * std::max<int>( 1, 4 * AMVP_DECIMATION_FACTOR / 4 );
107
0
  static const unsigned mask  = scale - 1;
108
109
0
  const Position puPos = cu.lumaPos();
110
0
  const Mv mv0 = cu.mv[0][0];
111
0
  const Mv mv1 = cu.mv[1][0];
112
113
0
  for( int y = puPos.y, num = 0; y < ( puPos.y + cu.lumaSize().height ); y = y + dy )
114
0
  {
115
0
    for( int x = puPos.x; x < ( puPos.x + cu.lumaSize().width ); x = x + dx, num++ )
116
0
    {
117
0
      if( cu.mvdL0SubPu[num] == Mv( 0, 0 ) ) continue;
118
119
0
      const Mv subPuMv0 = mv0 + cu.mvdL0SubPu[num];
120
0
      const Mv subPuMv1 = mv1 - cu.mvdL0SubPu[num];
121
122
0
      int y2 = ( ( y - 1 ) & ~mask ) + scale;
123
124
0
      for( ; y2 < y + dy; y2 += scale )
125
0
      {
126
0
        int x2 = ( ( x - 1 ) & ~mask ) + scale;
127
128
0
        for( ; x2 < x + dx; x2 += scale )
129
0
        {
130
0
          const Position mbPos = g_miScaling.scale( Position{ x2, y2 } );
131
0
          mb.buf = orgPtr + rsAddr( mbPos, mb.stride );
132
133
0
          MotionInfo& mi = *mb.buf;
134
135
0
          mi.mv[0] = subPuMv0;
136
0
          mi.mv[1] = subPuMv1;
137
0
        }
138
0
      }
139
0
    }
140
0
  }
141
0
}
142
143
void CS::setRefinedMotionFieldCTU( CodingStructure& cs, const int ctuX, const int ctuY )
144
4.05k
{
145
4.05k
  MotionBuf   mb     = cs.getMotionBuf();
146
4.05k
  MotionInfo* orgPtr = mb.buf;
147
148
4.05k
  const int xPos = ctuX << cs.pcv->maxCUSizeLog2;
149
4.05k
  const int yPos = ctuY << cs.pcv->maxCUSizeLog2;
150
  
151
  // first CU in CTU
152
4.05k
  const CodingUnit *ptrCU = cs.getCU( Position( xPos, yPos ), CH_L, TREE_D );
153
46.6k
  while( ptrCU )
154
42.5k
  {
155
42.5k
    const CodingUnit& cu = *ptrCU;
156
    
157
42.5k
    if( isLuma( cu.chType ) && cu.mvdL0SubPu && CU::checkDMVRCondition( cu ) )
158
0
    {
159
0
      refineCU( cu, mb, orgPtr );
160
0
    }
161
162
42.5k
    ptrCU = ptrCU->next;
163
42.5k
  }
164
4.05k
}
165
void CS::setRefinedMotionField( CodingStructure& cs )
166
0
{
167
0
  for( int j = 0; j < cs.pcv->heightInCtus; j++ )
168
0
  {
169
0
    for( int i = 0; i < cs.pcv->widthInCtus; i++ )
170
0
    {
171
0
      CS::setRefinedMotionFieldCTU( cs, i, j );
172
0
    }
173
0
  }
174
0
}
175
// CU tools
176
177
bool CU::checkCCLMAllowed(const CodingUnit& cu) 
178
975k
{
179
975k
  bool allowCCLM = false;
180
181
975k
  if( !CS::isDualITree( *cu.cs ) ) //single tree I slice or non-I slice (Note: judging chType is no longer equivalent to checking dual-tree I slice since the local dual-tree is introduced)
182
0
  {
183
0
    allowCCLM = true;
184
0
  }
185
975k
  else if( cu.slice->sps->CTUSize <= 32 ) //dual tree, CTUsize < 64
186
0
  {
187
0
    allowCCLM = true;
188
0
  }
189
975k
  else //dual tree, CTU size 64 or 128
190
975k
  {
191
975k
    int depthFor64x64Node = cu.slice->sps->CTUSize == 128 ? 1 : 0;
192
975k
    const PartSplit cuSplitTypeDepth1 = CU::getSplitAtDepth( cu, depthFor64x64Node );
193
975k
    const PartSplit cuSplitTypeDepth2 = CU::getSplitAtDepth( cu, depthFor64x64Node + 1 );
194
195
    //allow CCLM if 64x64 chroma tree node uses QT split or HBT+VBT split combination
196
975k
    if( cuSplitTypeDepth1 == CU_QUAD_SPLIT || (cuSplitTypeDepth1 == CU_HORZ_SPLIT && cuSplitTypeDepth2 == CU_VERT_SPLIT) )
197
577k
    {
198
577k
      if( cu.chromaFormat == CHROMA_420 )
199
577k
      {
200
577k
        CHECK( !(cu.blocks[COMP_Cb].width <= 16 && cu.blocks[COMP_Cb].height <= 16), "chroma cu size shall be <= 16x16 for YUV420 format" );
201
577k
      }
202
577k
      allowCCLM = true;
203
577k
    }
204
    //allow CCLM if 64x64 chroma tree node uses NS (No Split) and becomes a chroma CU containing 32x32 chroma blocks
205
398k
    else if( cuSplitTypeDepth1 == CU_DONT_SPLIT )
206
89.4k
    {
207
89.4k
      if( cu.chromaFormat == CHROMA_420 )
208
89.4k
      {
209
89.4k
        CHECK( !(cu.blocks[COMP_Cb].width == 32 && cu.blocks[COMP_Cb].height == 32), "chroma cu size shall be 32x32 for YUV420 format" );
210
89.4k
      }
211
89.4k
      allowCCLM = true;
212
89.4k
    }
213
    //allow CCLM if 64x32 chroma tree node uses NS and becomes a chroma CU containing 32x16 chroma blocks
214
308k
    else if( cuSplitTypeDepth1 == CU_HORZ_SPLIT && cuSplitTypeDepth2 == CU_DONT_SPLIT )
215
39.1k
    {
216
39.1k
      if( cu.chromaFormat == CHROMA_420 )
217
39.1k
      {
218
39.1k
        CHECK( !(cu.blocks[COMP_Cb].width == 32 && cu.blocks[COMP_Cb].height == 16), "chroma cu size shall be 32x16 for YUV420 format" );
219
39.1k
      }
220
39.1k
      allowCCLM = true;
221
39.1k
    }
222
223
    //further check luma conditions
224
975k
    if( allowCCLM )
225
705k
    {
226
      //disallow CCLM if luma 64x64 block uses BT or TT or NS with ISP
227
705k
      const Position lumaRefPos( cu.chromaPos().x << getComponentScaleX( COMP_Cb, cu.chromaFormat ), cu.chromaPos().y << getComponentScaleY( COMP_Cb, cu.chromaFormat ) );
228
705k
      const CodingUnit* colLumaCu = cu.cs->lumaCS->getCU( lumaRefPos, CH_L, TREE_D );
229
230
705k
      if( colLumaCu->lwidth() < 64 || colLumaCu->lheight() < 64 ) //further split at 64x64 luma node
231
337k
      {
232
337k
        const PartSplit cuSplitTypeDepth1Luma = CU::getSplitAtDepth( *colLumaCu, depthFor64x64Node );
233
337k
        CHECK( !(cuSplitTypeDepth1Luma >= CU_QUAD_SPLIT && cuSplitTypeDepth1Luma <= CU_TRIV_SPLIT), "split mode shall be BT, TT or QT" );
234
337k
        if( cuSplitTypeDepth1Luma != CU_QUAD_SPLIT )
235
0
        {
236
0
          allowCCLM = false;
237
0
        }
238
337k
      }
239
368k
      else if( colLumaCu->lwidth() == 64 && colLumaCu->lheight() == 64 && colLumaCu->ispMode ) //not split at 64x64 luma node and use ISP mode
240
0
      {
241
0
        allowCCLM = false;
242
0
      }
243
705k
    }
244
975k
  }
245
246
975k
  return allowCCLM;
247
975k
}
248
249
uint8_t CU::checkAllowedSbt(const CodingUnit& cu) 
250
146
{
251
146
  if( !cu.slice->sps->SBT || cu.predMode != MODE_INTER || cu.ciip || cu.predMode == MODE_IBC || cu.Y().maxDim() > cu.cs->sps->getMaxTbSize() )
252
146
  {
253
146
    return 0;
254
146
  }
255
256
0
  const int cuWidth       = cu.lwidth();
257
0
  const int cuHeight      = cu.lheight();
258
0
  const int minSbtCUSize  = 1 << ( MIN_CU_LOG2 + 1 );
259
0
  const int minQuadCUSize = 1 << ( MIN_CU_LOG2 + 2 );
260
261
0
  uint8_t sbtAllowed = 0;
262
0
  if( cuWidth  >= minSbtCUSize )  sbtAllowed += 1 << SBT_VER_HALF;
263
0
  if( cuHeight >= minSbtCUSize )  sbtAllowed += 1 << SBT_HOR_HALF;
264
0
  if( cuWidth  >= minQuadCUSize ) sbtAllowed += 1 << SBT_VER_QUAD;
265
0
  if( cuHeight >= minQuadCUSize ) sbtAllowed += 1 << SBT_HOR_QUAD;
266
267
0
  return sbtAllowed;
268
146
}
269
270
271
bool CU::getRprScaling( const SPS* sps, const PPS* curPPS, Picture* refPic, int& xScale, int& yScale )
272
0
{
273
0
  const Window& curScalingWindow = curPPS->scalingWindow;
274
0
  int curPicWidth = curPPS->picWidthInLumaSamples   - SPS::getWinUnitX( sps->chromaFormatIdc ) * (curScalingWindow.winLeftOffset + curScalingWindow.winRightOffset);
275
0
  int curPicHeight = curPPS->picHeightInLumaSamples - SPS::getWinUnitY( sps->chromaFormatIdc ) * (curScalingWindow.winTopOffset  + curScalingWindow.winBottomOffset);
276
277
0
  const Window& refScalingWindow = refPic->cs->pps->scalingWindow;
278
0
  int refPicWidth = refPic->cs->pps->picWidthInLumaSamples   - SPS::getWinUnitX( sps->chromaFormatIdc ) * (refScalingWindow.winLeftOffset + refScalingWindow.winRightOffset);
279
0
  int refPicHeight = refPic->cs->pps->picHeightInLumaSamples - SPS::getWinUnitY( sps->chromaFormatIdc) * (refScalingWindow.winTopOffset  + refScalingWindow.winBottomOffset);
280
281
0
  xScale = ( ( refPicWidth << SCALE_RATIO_BITS ) + ( curPicWidth >> 1 ) ) / curPicWidth;
282
0
  yScale = ( ( refPicHeight << SCALE_RATIO_BITS ) + ( curPicHeight >> 1 ) ) / curPicHeight;
283
284
0
  int curSeqMaxPicWidthY = sps->maxPicWidthInLumaSamples;                  // pic_width_max_in_luma_samples
285
0
  int curSeqMaxPicHeightY = sps->maxPicHeightInLumaSamples;                // pic_height_max_in_luma_samples
286
0
  int curPicWidthY = curPPS->picWidthInLumaSamples;                        // pic_width_in_luma_samples
287
0
  int curPicHeightY = curPPS->picHeightInLumaSamples;                      // pic_height_in_luma_samples 
288
0
  int max8MinCbSizeY = std::max((int)8, (1<<sps->log2MinCodingBlockSize)); // Max(8, MinCbSizeY)
289
290
0
  CHECK((curPicWidth * curSeqMaxPicWidthY) < refPicWidth * (curPicWidthY - max8MinCbSizeY), "(curPicWidth * curSeqMaxPicWidthY) should be greater than or equal to refPicWidth * (curPicWidthY - max8MinCbSizeY))");
291
0
  CHECK((curPicHeight * curSeqMaxPicHeightY) < refPicHeight * (curPicHeightY - max8MinCbSizeY), "(curPicHeight * curSeqMaxPicHeightY) should be greater than or equal to refPicHeight * (curPicHeightY - max8MinCbSizeY))");
292
293
0
  return refPic->cs->pps->isRefScaled( *curPPS );
294
0
}
295
296
bool CU::isSameSubPic(const CodingUnit& cu, const CodingUnit& cu2)
297
0
{
298
0
  return (cu.slice->pps->getSubPicFromCU(cu).subPicIdx == cu2.slice->pps->getSubPicFromCU(cu2).subPicIdx) ;
299
0
}
300
301
bool CU::isSameCtu(const CodingUnit& cu, const CodingUnit& cu2)
302
0
{
303
0
  uint32_t ctuSizeBit = cu.cs->pcv->maxCUSizeLog2;
304
305
0
  Position pos1Ctu(cu.lumaPos().x  >> ctuSizeBit, cu.lumaPos().y  >> ctuSizeBit);
306
0
  Position pos2Ctu(cu2.lumaPos().x >> ctuSizeBit, cu2.lumaPos().y >> ctuSizeBit);
307
308
0
  return pos1Ctu.x == pos2Ctu.x && pos1Ctu.y == pos2Ctu.y;
309
0
}
310
311
bool CU::isLastSubCUOfCtu( const CodingUnit &cu )
312
85.7k
{
313
85.7k
  const Area cuAreaY = CU::isSepTree(cu) ? Area( recalcPosition( cu.chromaFormat, cu.chType, CH_L, cu.blocks[cu.chType].pos() ), recalcSize( cu.chromaFormat, cu.chType, CH_L, cu.blocks[cu.chType].size() ) ) : (const Area&)cu.Y();
314
315
85.7k
  return ( ( ( ( cuAreaY.x + cuAreaY.width  ) & cu.cs->pcv->maxCUSizeMask ) == 0 || cuAreaY.x + cuAreaY.width  == cu.cs->pcv->lumaWidth  ) &&
316
37.9k
           ( ( ( cuAreaY.y + cuAreaY.height ) & cu.cs->pcv->maxCUSizeMask ) == 0 || cuAreaY.y + cuAreaY.height == cu.cs->pcv->lumaHeight ) );
317
85.7k
}
318
319
uint32_t CU::getCtuAddr( const CodingUnit &cu )
320
28.6k
{
321
28.6k
  return getCtuAddr( cu.blocks[cu.chType].lumaPos(), *cu.cs->pcv );
322
28.6k
}
323
324
int CU::predictQP( const CodingUnit& cu, const int prevQP )
325
28.6k
{
326
28.6k
  const ChannelType      chType   = cu.chType;
327
28.6k
  const CodingStructure& cs       = *cu.cs;
328
28.6k
  const Slice&           slice    = *cs.slice;
329
28.6k
  const bool             inCtuA   = ( cu.blocks[cu.chType].y & ( cs.pcv->maxCUSizeMask >> getChannelTypeScaleY( cu.chType, cu.chromaFormat ) ) );
330
28.6k
  const bool             inCtuL   = ( cu.blocks[cu.chType].x & ( cs.pcv->maxCUSizeMask >> getChannelTypeScaleX( cu.chType, cu.chromaFormat ) ) );
331
28.6k
  const CodingUnit*      cuAbove  =          cs.getCURestricted( cu.blocks[chType].pos().offset( 0, -1 ), cu, chType );
332
28.6k
  const CodingUnit*      cuLeft   = inCtuL ? cs.getCURestricted( cu.blocks[chType].pos().offset( -1, 0 ), cu, chType ) : nullptr;
333
  
334
28.6k
  const uint32_t ctuRsAddr       = getCtuAddr( cu );
335
28.6k
  const uint32_t ctuXPosInCtus   = ctuRsAddr % cs.pcv->widthInCtus;
336
28.6k
  const uint32_t tileXPosInCtus  = slice.pps->tileColBd[cs.pps->ctuToTileCol[ctuXPosInCtus]];
337
  
338
28.6k
  if( ctuXPosInCtus == tileXPosInCtus && !inCtuL && !inCtuA && cuAbove )
339
4.83k
  {
340
4.83k
    return cuAbove->qp;
341
4.83k
  }
342
23.8k
  else
343
23.8k
  {
344
23.8k
    const int a = inCtuA ? cuAbove->qp : prevQP;
345
23.8k
    const int b = inCtuL ? cuLeft->qp  : prevQP;
346
  
347
23.8k
    return ( a + b + 1 ) >> 1;
348
23.8k
  }
349
28.6k
}
350
351
352
void CU::saveMotionInHMVP( const CodingUnit& cu, const bool isToBeDone )
353
0
{
354
0
  if (!cu.geo && !cu.affine && !isToBeDone)
355
0
  {
356
0
    MotionInfo puMi = cu.getMotionInfo();
357
0
    HPMVInfo     mi ( puMi, ( puMi.interDir() == 3 ) ? cu.BcwIdx : BCW_DEFAULT, cu.imv == IMV_HPEL, CU::isIBC( cu ) );
358
359
0
    const unsigned log2ParallelMergeLevel = (cu.cs->sps->log2ParallelMergeLevelMinus2 + 2);
360
0
    const unsigned xBr = cu.Y().width + cu.Y().x;
361
0
    const unsigned yBr = cu.Y().height + cu.Y().y;
362
0
    bool enableHmvp = ((xBr >> log2ParallelMergeLevel) > (cu.Y().x >> log2ParallelMergeLevel)) && ((yBr >> log2ParallelMergeLevel) > (cu.Y().y >> log2ParallelMergeLevel));
363
0
    bool enableInsertion = CU::isIBC(cu) || enableHmvp;
364
0
    if (enableInsertion)
365
0
      cu.cs->addMiToLut( CU::isIBC(cu) ? cu.cs->motionLut.lutIbc : cu.cs->motionLut.lut, mi);
366
0
  }
367
0
}
368
369
PartSplit CU::getSplitAtDepth( const CodingUnit& cu, const unsigned depth )
370
2.64M
{
371
2.64M
  if( depth >= cu.depth ) return CU_DONT_SPLIT;
372
373
2.12M
  const PartSplit cuSplitType = PartSplit( ( cu.splitSeries >> ( depth * SPLIT_DMULT ) ) & SPLIT_MASK );
374
375
2.12M
  if     ( cuSplitType == CU_QUAD_SPLIT    ) return CU_QUAD_SPLIT;
376
377
987k
  else if( cuSplitType == CU_HORZ_SPLIT    ) return CU_HORZ_SPLIT;
378
379
500k
  else if( cuSplitType == CU_VERT_SPLIT    ) return CU_VERT_SPLIT;
380
381
4.73k
  else if( cuSplitType == CU_TRIH_SPLIT    ) return CU_TRIH_SPLIT;
382
22
  else if( cuSplitType == CU_TRIV_SPLIT    ) return CU_TRIV_SPLIT;
383
18.4E
  else   { THROW( "Unknown split mode"    ); return CU_QUAD_SPLIT; }
384
2.12M
}
385
386
ModeType CU::getModeTypeAtDepth( const CodingUnit& cu, const unsigned depth )
387
82.0k
{
388
82.0k
  ModeType modeType = ModeType( (cu.modeTypeSeries >> (depth * 3)) & 0x07 );
389
82.0k
  CHECK( depth > cu.depth, " depth is wrong" );
390
82.0k
  return modeType;
391
82.0k
}
392
393
bool CU::divideTuInRows( const CodingUnit &cu )
394
38.2k
{
395
38.2k
  CHECK( cu.ispMode != HOR_INTRA_SUBPARTITIONS && cu.ispMode != VER_INTRA_SUBPARTITIONS, "Intra Subpartitions type not recognized!" );
396
38.2k
  return cu.ispMode == HOR_INTRA_SUBPARTITIONS ? true : false;
397
38.2k
}
398
399
400
PartSplit CU::getISPType( const CodingUnit &cu, const ComponentID compID )
401
82.7k
{
402
82.7k
  if( cu.ispMode && isLuma( compID ) )
403
38.2k
  {
404
38.2k
    const bool tuIsDividedInRows = CU::divideTuInRows( cu );
405
406
38.2k
    return tuIsDividedInRows ? TU_1D_HORZ_SPLIT : TU_1D_VERT_SPLIT;
407
38.2k
  }
408
44.5k
  return TU_NO_ISP;
409
82.7k
}
410
411
bool CU::isISPLast( const CodingUnit &cu, const CompArea& tuArea, const ComponentID compID )
412
32.5k
{
413
32.5k
  PartSplit partitionType = CU::getISPType( cu, compID );
414
415
32.5k
  Area originalArea = cu.blocks[compID];
416
32.5k
  switch( partitionType )
417
32.5k
  {
418
17.3k
    case TU_1D_HORZ_SPLIT:
419
17.3k
      return tuArea.y + tuArea.height == originalArea.y + originalArea.height;
420
15.2k
    case TU_1D_VERT_SPLIT:
421
15.2k
      return tuArea.x + tuArea.width == originalArea.x + originalArea.width;
422
0
    default:
423
0
      THROW( "Unknown ISP processing order type!" );
424
0
      return false;
425
32.5k
  }
426
32.5k
}
427
428
bool CU::isISPFirst( const CodingUnit &cu, const CompArea& tuArea, const ComponentID compID )
429
0
{
430
0
  return tuArea == cu.firstTU->blocks[compID];
431
0
}
432
433
bool CU::canUseISP( const CodingUnit &cu, const ComponentID compID )
434
798k
{
435
798k
  const int width     = cu.blocks[compID].width;
436
798k
  const int height    = cu.blocks[compID].height;
437
798k
  const int maxTrSize = cu.cs->sps->getMaxTbSize();
438
798k
  return CU::canUseISP( width, height, maxTrSize );
439
798k
}
440
441
bool CU::canUseISP( const int width, const int height, const int maxTrSize )
442
825k
{
443
825k
  bool  notEnoughSamplesToSplit = ( Log2(width) + Log2(height) <= ( MIN_TB_LOG2_SIZEY << 1 ) );
444
825k
  bool  cuSizeLargerThanMaxTrSize = width > maxTrSize || height > maxTrSize;
445
825k
  if ( notEnoughSamplesToSplit || cuSizeLargerThanMaxTrSize )
446
0
  {
447
0
    return false;
448
0
  }
449
825k
  return true;
450
825k
}
451
452
bool CU::canUseLfnstWithISP( const CompArea& cuArea, const ISPType ispSplitType )
453
60.9k
{
454
60.9k
  if( ispSplitType == NOT_INTRA_SUBPARTITIONS )
455
0
  {
456
0
    return false;
457
0
  }
458
60.9k
  Size tuSize = ( ispSplitType == HOR_INTRA_SUBPARTITIONS ) ? Size( cuArea.width, CU::getISPSplitDim( cuArea.width, cuArea.height, TU_1D_HORZ_SPLIT ) ) :
459
60.9k
    Size( CU::getISPSplitDim( cuArea.width, cuArea.height, TU_1D_VERT_SPLIT ), cuArea.height );
460
461
60.9k
  if( !( tuSize.width >= MIN_TB_SIZEY && tuSize.height >= MIN_TB_SIZEY ) )
462
9.09k
  {
463
9.09k
    return false;
464
9.09k
  }
465
51.8k
  return true;
466
60.9k
}
467
468
bool CU::canUseLfnstWithISP( const CodingUnit& cu, const ChannelType chType )
469
6.60k
{
470
6.60k
  CHECK( !isLuma( chType ), "Wrong ISP mode!" );
471
6.60k
  return CU::canUseLfnstWithISP( cu.blocks[chType == CH_L ? 0 : 1], (ISPType)cu.ispMode );
472
6.60k
}
473
474
uint32_t CU::getISPSplitDim( const int width, const int height, const PartSplit ispType )
475
136k
{
476
136k
  bool divideTuInRows = ispType == TU_1D_HORZ_SPLIT;
477
136k
  uint32_t splitDimensionSize, nonSplitDimensionSize, partitionSize, divShift = 2;
478
479
136k
  if( divideTuInRows )
480
68.1k
  {
481
68.1k
    splitDimensionSize    = height;
482
68.1k
    nonSplitDimensionSize = width;
483
68.1k
  }
484
68.7k
  else
485
68.7k
  {
486
68.7k
    splitDimensionSize    = width;
487
68.7k
    nonSplitDimensionSize = height;
488
68.7k
  }
489
490
136k
  const int minNumberOfSamplesPerCu = 1 << ( ( MIN_TB_LOG2_SIZEY << 1 ) );
491
136k
  const int factorToMinSamples = nonSplitDimensionSize < minNumberOfSamplesPerCu ? minNumberOfSamplesPerCu >> Log2(nonSplitDimensionSize) : 1;
492
136k
  partitionSize = ( splitDimensionSize >> divShift ) < factorToMinSamples ? factorToMinSamples : ( splitDimensionSize >> divShift );
493
494
136k
  CHECK( Log2(partitionSize) + Log2(nonSplitDimensionSize) < Log2(minNumberOfSamplesPerCu), "A partition has less than the minimum amount of samples!" );
495
136k
  return partitionSize;
496
136k
}
497
498
bool CU::allLumaCBFsAreZero(const CodingUnit& cu)
499
1.41k
{
500
1.41k
  if (!cu.ispMode)
501
0
  {
502
0
    return TU::getCbf(*cu.firstTU, COMP_Y) == false;
503
0
  }
504
1.41k
  else
505
1.41k
  {
506
1.41k
    int numTotalTUs = cu.ispMode == HOR_INTRA_SUBPARTITIONS ? cu.lheight() >> Log2(cu.firstTU->lheight()) : cu.lwidth() >> Log2(cu.firstTU->lwidth());
507
1.41k
    TransformUnit* tuPtr = cu.firstTU;
508
1.41k
    for (int tuIdx = 0; tuIdx < numTotalTUs; tuIdx++)
509
1.41k
    {
510
1.41k
      if (TU::getCbf(*tuPtr, COMP_Y) == true)
511
1.41k
      {
512
1.41k
        return false;
513
1.41k
      }
514
0
      tuPtr = tuPtr->next;
515
0
    }
516
0
    return true;
517
1.41k
  }
518
1.41k
}
519
520
TUTraverser CU::traverseTUs( CodingUnit& cu )
521
0
{
522
0
  return TUTraverser( cu.firstTU, cu.lastTU->next );
523
0
}
524
525
cTUTraverser CU::traverseTUs( const CodingUnit& cu )
526
0
{
527
0
  return cTUTraverser( cu.firstTU, cu.lastTU->next );
528
0
}
529
530
const CodingUnit* CU::getLeft(const CodingUnit& curr)
531
98.8k
{
532
98.8k
  const Position& pos = curr.blocks[curr.chType].pos();
533
98.8k
  return curr.cs->getCU(pos.offset(-1, 0), curr.chType, curr.treeType);
534
98.8k
}
535
536
const CodingUnit* CU::getAbove(const CodingUnit& curr)
537
100k
{
538
100k
  const Position& pos = curr.blocks[curr.chType].pos();
539
100k
  return curr.cs->getCU(pos.offset(0, -1), curr.chType, curr.treeType);
540
100k
}
541
542
// PU tools
543
544
int CU::getIntraMPMs( const CodingUnit& cu, unsigned* mpm )
545
283k
{
546
283k
  const int numMPMs = NUM_MOST_PROBABLE_MODES;
547
283k
  {
548
283k
    int numCand      = -1;
549
283k
    int leftIntraDir = PLANAR_IDX, aboveIntraDir = PLANAR_IDX;
550
551
283k
    const CompArea& area = cu.Y();
552
283k
    const Position posRT = area.topRight();
553
283k
    const Position posLB = area.bottomLeft();
554
555
    // Get intra direction of left PU
556
283k
    const CodingUnit* puLeft = (posLB.x & cu.cs->pcv->maxCUSizeMask) ? cu.cs->getCU(posLB.offset(-1, 0), CH_L, cu.treeType) : cu.cs->picture->cs->getCURestricted(posLB.offset(-1, 0), cu, CH_L);
557
283k
    if (puLeft && CU::isIntra(*puLeft) && !CU::isMIP(*puLeft))
558
204k
    {
559
204k
      leftIntraDir = puLeft->intraDir[CH_L];
560
204k
    }
561
562
    // Get intra direction of above PU, but only from the same CU
563
283k
    const CodingUnit* puAbove = (posRT.y & cu.cs->pcv->maxCUSizeMask) ? cu.cs->getCU(posRT.offset(0, -1), CH_L, cu.treeType) : nullptr;
564
283k
    if (puAbove && CU::isIntra(*puAbove) && !CU::isMIP(*puAbove))
565
170k
    {
566
170k
      aboveIntraDir = puAbove->intraDir[CH_L];
567
170k
    }
568
569
283k
    CHECK(2 >= numMPMs, "Invalid number of most probable modes");
570
571
283k
    const int offset = (int)NUM_LUMA_MODE - 6;
572
283k
    const int mod = offset + 3;
573
574
283k
    {
575
283k
      mpm[0] = PLANAR_IDX;
576
283k
      mpm[1] = DC_IDX;
577
283k
      mpm[2] = VER_IDX;
578
283k
      mpm[3] = HOR_IDX;
579
283k
      mpm[4] = VER_IDX - 4;
580
283k
      mpm[5] = VER_IDX + 4;
581
582
283k
      if (leftIntraDir == aboveIntraDir)
583
276k
      {
584
276k
        numCand = 1;
585
276k
        if (leftIntraDir > DC_IDX)
586
4.20k
        {
587
4.20k
          mpm[0] = PLANAR_IDX;
588
4.20k
          mpm[1] = leftIntraDir;
589
4.20k
          mpm[2] = ((leftIntraDir + offset) % mod) + 2;
590
4.20k
          mpm[3] = ((leftIntraDir - 1) % mod) + 2;
591
4.20k
          mpm[4] = ((leftIntraDir + offset - 1) % mod) + 2;
592
4.20k
          mpm[5] = ( leftIntraDir               % mod) + 2;
593
4.20k
        }
594
276k
      }
595
6.20k
      else //L!=A
596
6.20k
      {
597
6.20k
        numCand = 2;
598
6.20k
        int  maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;
599
600
6.20k
        if ((leftIntraDir > DC_IDX) && (aboveIntraDir > DC_IDX))
601
0
        {
602
0
          mpm[0] = PLANAR_IDX;
603
0
          mpm[1] = leftIntraDir;
604
0
          mpm[2] = aboveIntraDir;
605
0
          maxCandModeIdx = mpm[1] > mpm[2] ? 1 : 2;
606
0
          int minCandModeIdx = mpm[1] > mpm[2] ? 2 : 1;
607
0
          if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 1)
608
0
          {
609
0
            mpm[3] = ((mpm[minCandModeIdx] + offset)     % mod) + 2;
610
0
            mpm[4] = ((mpm[maxCandModeIdx] - 1)          % mod) + 2;
611
0
            mpm[5] = ((mpm[minCandModeIdx] + offset - 1) % mod) + 2;
612
0
          }
613
0
          else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] >= 62)
614
0
          {
615
0
            mpm[3] = ((mpm[minCandModeIdx] - 1)      % mod) + 2;
616
0
            mpm[4] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
617
0
            mpm[5] = ( mpm[minCandModeIdx]           % mod) + 2;
618
0
          }
619
0
          else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 2)
620
0
          {
621
0
            mpm[3] = ((mpm[minCandModeIdx] - 1)      % mod) + 2;
622
0
            mpm[4] = ((mpm[minCandModeIdx] + offset) % mod) + 2;
623
0
            mpm[5] = ((mpm[maxCandModeIdx] - 1)      % mod) + 2;
624
0
          }
625
0
          else
626
0
          {
627
0
            mpm[3] = ((mpm[minCandModeIdx] + offset) % mod) + 2;
628
0
            mpm[4] = ((mpm[minCandModeIdx] - 1)      % mod) + 2;
629
0
            mpm[5] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
630
0
          }
631
0
        }
632
6.20k
        else if (leftIntraDir + aboveIntraDir >= 2)
633
5.61k
        {
634
5.61k
          mpm[0] = PLANAR_IDX;
635
5.61k
          mpm[1] = (leftIntraDir < aboveIntraDir) ? aboveIntraDir : leftIntraDir;
636
5.61k
          maxCandModeIdx = 1;
637
5.61k
          mpm[2] = ((mpm[maxCandModeIdx] + offset)     % mod) + 2;
638
5.61k
          mpm[3] = ((mpm[maxCandModeIdx] - 1)          % mod) + 2;
639
5.61k
          mpm[4] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2;
640
5.61k
          mpm[5] = ( mpm[maxCandModeIdx]               % mod) + 2;
641
5.61k
        }
642
6.20k
      }
643
283k
    }
644
1.98M
    for (int i = 0; i < numMPMs; i++)
645
1.69M
    {
646
1.69M
      CHECK(mpm[i] >= NUM_LUMA_MODE, "Invalid MPM");
647
1.69M
    }
648
283k
    CHECK(numCand == 0, "No candidates found");
649
283k
    return numCand;
650
283k
  }
651
283k
}
652
653
bool CU::isMIP(const CodingUnit& cu, const ChannelType chType)
654
4.11M
{
655
4.11M
  return chType == CH_L ? cu.mipFlag : ((cu.intraDir[CH_C] == DM_CHROMA_IDX) && isDMChromaMIP(cu));
656
4.11M
}
657
658
bool CU::isDMChromaMIP(const CodingUnit& cu)
659
652k
{
660
652k
  return !CU::isSepTree(cu) && (cu.chromaFormat == CHROMA_444) && getCoLocatedLumaPU(cu).mipFlag;
661
652k
}
662
663
664
uint32_t CU::getIntraDirLuma(const CodingUnit& cu)
665
1.05M
{
666
1.05M
  if (isMIP(cu))
667
210k
  {
668
210k
    return PLANAR_IDX;
669
210k
  }
670
840k
  else
671
840k
  {
672
840k
    return cu.intraDir[CH_L];
673
840k
  }
674
1.05M
}
675
676
677
void CU::getIntraChromaCandModes( const CodingUnit& cu, unsigned modeList[NUM_CHROMA_MODE] )
678
339k
{
679
339k
  {
680
339k
    modeList[0] = PLANAR_IDX;
681
339k
    modeList[1] = VER_IDX;
682
339k
    modeList[2] = HOR_IDX;
683
339k
    modeList[3] = DC_IDX;
684
339k
    modeList[4] = LM_CHROMA_IDX;
685
339k
    modeList[5] = MDLM_L_IDX;
686
339k
    modeList[6] = MDLM_T_IDX;
687
339k
    modeList[7] = DM_CHROMA_IDX;
688
689
    // If Direct Mode is MIP, mode cannot be already in the list.
690
339k
    if (isDMChromaMIP(cu))
691
0
    {
692
0
      return;
693
0
    }
694
695
339k
    const uint32_t lumaMode = getCoLocatedIntraLumaMode(cu);
696
367k
    for( int i = 0; i < 4; i++ )
697
367k
    {
698
367k
      if( lumaMode == modeList[i] )
699
339k
      {
700
339k
        modeList[i] = VDIA_IDX;
701
339k
        break;
702
339k
      }
703
367k
    }
704
339k
  }
705
339k
}
706
707
bool CU::isLMCMode(unsigned mode)
708
3.93M
{
709
3.93M
  return (mode >= LM_CHROMA_IDX && mode <= MDLM_T_IDX);
710
3.93M
}
711
712
bool CU::isLMCModeEnabled(const CodingUnit& cu, unsigned mode)
713
578k
{
714
578k
  return ( cu.cs->sps->LMChroma && CU::checkCCLMAllowed(cu) );
715
578k
}
716
717
int CU::getLMSymbolList(const CodingUnit& cu, int *modeList)
718
36.8k
{
719
36.8k
  int idx = 0;
720
721
36.8k
  modeList[idx++] = LM_CHROMA_IDX;
722
36.8k
  modeList[idx++] = MDLM_L_IDX;
723
36.8k
  modeList[idx++] = MDLM_T_IDX;
724
36.8k
  return idx;
725
36.8k
}
726
727
uint32_t CU::getFinalIntraMode( const CodingUnit& cu, const ChannelType chType )
728
5.86M
{
729
5.86M
  uint32_t uiIntraMode = cu.intraDir[chType];
730
731
5.86M
  if( uiIntraMode == DM_CHROMA_IDX && !isLuma( chType ) )
732
511k
  {
733
511k
    uiIntraMode = getCoLocatedIntraLumaMode(cu);
734
511k
  }
735
5.86M
  if( cu.chromaFormat == CHROMA_422 && !isLuma( chType ) && uiIntraMode < NUM_LUMA_MODE ) // map directional, planar and dc
736
0
  {
737
0
    uiIntraMode = g_chroma422IntraAngleMappingTable[uiIntraMode];
738
0
  }
739
5.86M
  return uiIntraMode;
740
5.86M
}
741
742
const CodingUnit& CU::getCoLocatedLumaPU(const CodingUnit& cu)
743
1.05M
{
744
1.05M
  Position              topLeftPos = cu.blocks[cu.chType].lumaPos();
745
1.05M
  Position              refPos     = topLeftPos.offset(cu.blocks[cu.chType].lumaSize().width  >> 1,
746
1.05M
                                                       cu.blocks[cu.chType].lumaSize().height >> 1);
747
1.05M
  const CodingUnit& lumaCU     = CU::isSepTree(cu) ? *cu.cs->lumaCS->getCU(refPos, CH_L, TREE_D)
748
1.05M
                                                : *cu.cs->getCU(topLeftPos, CH_L, TREE_D);
749
750
1.05M
  return lumaCU;
751
1.05M
}
752
753
uint32_t CU::getCoLocatedIntraLumaMode(const CodingUnit& cu)
754
1.05M
{
755
1.05M
  return CU::getIntraDirLuma(CU::getCoLocatedLumaPU(cu));
756
1.05M
}
757
758
bool CU::addMergeHMVPCand(const CodingStructure &cs, MergeCtx& mrgCtx, const int& mrgCandIdx, const uint32_t maxNumMergeCandMin1, int &cnt, const bool isAvailableA1, const MotionInfo& miLeft, const bool isAvailableB1, const MotionInfo& miAbove, const bool ibcFlag, const bool isGt4x4)
759
81.4k
{
760
81.4k
  const Slice& slice = *cs.slice;
761
81.4k
  HPMVInfo miNeighbor;
762
81.4k
  auto& lut = ibcFlag ? cs.motionLut.lutIbc : cs.motionLut.lut;
763
81.4k
  int num_avai_candInLUT = (int) lut.size();
764
765
81.4k
  for (int mrgIdx = 1; mrgIdx <= num_avai_candInLUT; mrgIdx++)
766
0
  {
767
0
    miNeighbor = lut[num_avai_candInLUT - mrgIdx];
768
769
0
    if ( mrgIdx > 2 || ((mrgIdx > 1 || !isGt4x4) && ibcFlag)
770
0
      || ((!isAvailableA1 || (miNeighbor != miLeft)) && (!isAvailableB1 || (miNeighbor != miAbove))) )
771
0
    {
772
0
      mrgCtx.interDirNeighbours[cnt]    = miNeighbor.interDir();
773
0
      mrgCtx.useAltHpelIf      [cnt]    = !ibcFlag && miNeighbor.useAltHpelIf;
774
0
      mrgCtx.BcwIdx            [cnt]    = miNeighbor.interDir() == 3 ? miNeighbor.BcwIdx : BCW_DEFAULT;
775
0
      mrgCtx.mvFieldNeighbours [cnt][0] . setMvField( miNeighbor.mv[0], miNeighbor.mhRefIdx[0] );
776
777
0
      if (slice.isInterB())
778
0
      {
779
0
        mrgCtx.mvFieldNeighbours[cnt][1].setMvField( miNeighbor.mv[1], miNeighbor.mhRefIdx[1] );
780
0
      }
781
782
0
      if (mrgCandIdx == cnt)
783
0
      {
784
0
        return true;
785
0
      }
786
0
      cnt ++;
787
788
0
      if (cnt  == maxNumMergeCandMin1)
789
0
      {
790
0
        break;
791
0
      }
792
0
    }
793
0
  }
794
795
81.4k
  if (cnt < maxNumMergeCandMin1)
796
81.4k
  {
797
81.4k
    mrgCtx.useAltHpelIf[cnt] = false;
798
81.4k
  }
799
800
81.4k
  return false;
801
81.4k
}
802
803
void CU::getIBCMergeCandidates(const CodingUnit& cu, MergeCtx& mrgCtx, const int& mrgCandIdx)
804
81.4k
{
805
81.4k
  const CodingStructure& cs = *cu.cs;
806
81.4k
  const uint32_t maxNumMergeCand = cu.cs->sps->maxNumIBCMergeCand;
807
570k
  for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
808
488k
  {
809
488k
    mrgCtx.BcwIdx             [ui]           = BCW_DEFAULT;
810
488k
    mrgCtx.interDirNeighbours [ui]           = 0;
811
488k
    mrgCtx.mrgTypeNeighbours  [ui]           = MRG_TYPE_IBC;
812
488k
    mrgCtx.mvFieldNeighbours  [ui][0].refIdx = NOT_VALID;
813
488k
    mrgCtx.mvFieldNeighbours  [ui][1].refIdx = NOT_VALID;
814
488k
    mrgCtx.useAltHpelIf       [ui]           = false;
815
488k
  }
816
817
81.4k
  mrgCtx.numValidMergeCand = maxNumMergeCand;
818
  // compute the location of the current PU
819
820
81.4k
  int cnt = 0;
821
822
81.4k
  const Position posRT = cu.Y().topRight();
823
81.4k
  const Position posLB = cu.Y().bottomLeft();
824
825
81.4k
  MotionInfo miAbove, miLeft, miAboveLeft, miAboveRight, miBelowLeft;
826
827
  //left
828
81.4k
  const CodingUnit* cuLeft = cs.getCURestricted(posLB.offset(-1, 0), cu, cu.chType);
829
81.4k
  bool isGt4x4 = cu.lwidth() * cu.lheight() > 16;
830
81.4k
  const bool isAvailableA1 = cuLeft && cu != *cuLeft && CU::isIBC(*cuLeft);
831
81.4k
  if( isGt4x4 && isAvailableA1 )
832
0
  {
833
0
    miLeft             = cuLeft->getMotionInfo( posLB.offset( -1, 0 ) );
834
0
    miLeft.miRefIdx[0] = MI_NOT_VALID + 1;
835
836
    // get Inter Dir
837
0
    mrgCtx.interDirNeighbours[cnt] = miLeft.interDir();
838
    // get Mv from Left
839
0
    mrgCtx.mvFieldNeighbours[cnt][0].setMvField(miLeft.mv[0], miLeft.miRefIdx[0]);
840
0
    if (mrgCandIdx == cnt)
841
0
    {
842
0
      return;
843
0
    }
844
0
    cnt++;
845
0
  }
846
847
  // early termination
848
81.4k
  if (cnt == maxNumMergeCand)
849
0
  {
850
0
    return;
851
0
  }
852
853
  // above
854
81.4k
  const CodingUnit* cuAbove = cs.getCURestricted(posRT.offset(0, -1), cu, cu.chType);
855
81.4k
  bool isAvailableB1 = cuAbove && cu != *cuAbove && CU::isIBC(*cuAbove);
856
81.4k
  if (isGt4x4 && isAvailableB1)
857
0
  {
858
0
    miAbove             = cuAbove->getMotionInfo( posRT.offset( 0, -1 ) );
859
0
    miAbove.miRefIdx[0] = MI_NOT_VALID + 1;
860
861
0
    if( !isAvailableA1 || ( miAbove != miLeft ) )
862
0
    {
863
      // get Inter Dir
864
0
      mrgCtx.interDirNeighbours[cnt] = miAbove.interDir();
865
      // get Mv from Above
866
0
      mrgCtx.mvFieldNeighbours[cnt][0].setMvField(miAbove.mv[0], miAbove.miRefIdx[0]);
867
0
      if (mrgCandIdx == cnt)
868
0
      {
869
0
        return;
870
0
      }
871
872
0
      cnt++;
873
0
    }
874
0
  }
875
876
  // early termination
877
81.4k
  if (cnt == maxNumMergeCand)
878
0
  {
879
0
    return;
880
0
  }
881
81.4k
  else
882
81.4k
  {
883
81.4k
    bool bFound = addMergeHMVPCand( cs, mrgCtx, mrgCandIdx, maxNumMergeCand, cnt, isAvailableA1, miLeft, isAvailableB1, miAbove, true, isGt4x4 );
884
885
81.4k
    if (bFound)
886
0
    {
887
0
      return;
888
0
    }
889
81.4k
  }
890
891
298k
  while (cnt < maxNumMergeCand)
892
271k
  {
893
271k
    mrgCtx.mvFieldNeighbours[cnt][0].setMvField(Mv(0, 0), MAX_NUM_REF);
894
271k
    mrgCtx.interDirNeighbours[cnt] = 1;
895
271k
    if (mrgCandIdx == cnt)
896
54.3k
    {
897
54.3k
      return;
898
54.3k
    }
899
217k
    cnt++;
900
217k
  }
901
902
27.1k
  mrgCtx.numValidMergeCand = cnt;
903
27.1k
}
904
905
void CU::getInterMergeCandidates( const CodingUnit& cu, MergeCtx& mrgCtx, int mmvdList, const int mrgCandIdx )
906
0
{
907
0
  const unsigned plevel = cu.cs->sps->log2ParallelMergeLevelMinus2 + 2;
908
0
  const CodingStructure &cs  = *cu.cs;
909
0
  const Slice &slice         = *cu.cs->slice;
910
0
  const uint32_t maxNumMergeCand = slice.sps->maxNumMergeCand;
911
912
0
  for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
913
0
  {
914
0
    mrgCtx.BcwIdx            [ui]           = BCW_DEFAULT;
915
0
    mrgCtx.interDirNeighbours[ui]           = 0;
916
0
    mrgCtx.mrgTypeNeighbours [ui]           = MRG_TYPE_DEFAULT_N;
917
0
    mrgCtx.mvFieldNeighbours [ui][0].refIdx = NOT_VALID;
918
0
    mrgCtx.mvFieldNeighbours [ui][1].refIdx = NOT_VALID;
919
0
    mrgCtx.useAltHpelIf      [ui]           = false;
920
0
  }
921
922
0
  mrgCtx.numValidMergeCand = maxNumMergeCand;
923
  // compute the location of the current PU
924
925
0
  int cnt = 0;
926
927
0
  const Position posLT = cu.Y().topLeft();
928
0
  const Position posRT = cu.Y().topRight();
929
0
  const Position posLB = cu.Y().bottomLeft();
930
0
  MotionInfo miAbove, miLeft, miAboveLeft, miAboveRight, miBelowLeft;
931
932
  // above
933
0
  const CodingUnit* puAbove = cs.getCURestricted(posRT.offset(0, -1), cu, cu.chType);
934
935
0
  bool isAvailableB1 = puAbove && isDiffMER(cu.lumaPos(), posRT.offset(0, -1), plevel) && &cu != puAbove && CU::isInter(*puAbove);
936
937
0
  if (isAvailableB1)
938
0
  {
939
0
    miAbove = puAbove->getMotionInfo(posRT.offset(0, -1));
940
941
    // get Inter Dir
942
0
    mrgCtx.interDirNeighbours[cnt]    = miAbove.interDir();
943
0
    mrgCtx.useAltHpelIf      [cnt]    = puAbove->imv == IMV_HPEL;
944
0
    mrgCtx.BcwIdx            [cnt]    = mrgCtx.interDirNeighbours[cnt] == 3 ? puAbove->BcwIdx : BCW_DEFAULT;
945
0
    mrgCtx.mvFieldNeighbours [cnt][0] . setMvField(miAbove.mv[0], miAbove.miRefIdx[0]);
946
947
0
    if (slice.isInterB())
948
0
    {
949
0
      mrgCtx.mvFieldNeighbours[cnt][1]. setMvField(miAbove.mv[1], miAbove.miRefIdx[1]);
950
0
    }
951
0
    if (mrgCandIdx == cnt)
952
0
    {
953
0
      return;
954
0
    }
955
956
0
    cnt++;
957
0
  }
958
959
  // early termination
960
0
  if (cnt == maxNumMergeCand)
961
0
  {
962
0
    return;
963
0
  }
964
965
  //left
966
0
  const CodingUnit* puLeft = cs.getCURestricted(posLB.offset(-1, 0), cu, cu.chType);
967
968
0
  const bool isAvailableA1 = puLeft && isDiffMER(cu.lumaPos(), posLB.offset(-1, 0), plevel) && &cu != puLeft && CU::isInter(*puLeft);
969
970
0
  if (isAvailableA1)
971
0
  {
972
0
    miLeft = puLeft->getMotionInfo(posLB.offset(-1, 0));
973
974
0
    if (!isAvailableB1 || (miAbove != miLeft))
975
0
    {
976
      // get Inter Dir
977
0
      mrgCtx.interDirNeighbours[cnt]    = miLeft.interDir();
978
0
      mrgCtx.useAltHpelIf      [cnt]    = puLeft->imv == IMV_HPEL;
979
0
      mrgCtx.BcwIdx            [cnt]    = mrgCtx.interDirNeighbours[cnt] == 3 ? puLeft->BcwIdx : BCW_DEFAULT;
980
0
      mrgCtx.mvFieldNeighbours [cnt][0] . setMvField(miLeft.mv[0], miLeft.miRefIdx[0]);
981
982
0
      if (slice.isInterB())
983
0
      {
984
0
        mrgCtx.mvFieldNeighbours[cnt][1]. setMvField(miLeft.mv[1], miLeft.miRefIdx[1]);
985
0
      }
986
0
      if (mrgCandIdx == cnt)
987
0
      {
988
0
        return;
989
0
      }
990
991
0
      cnt++;
992
0
    }
993
0
  }
994
995
  // early termination
996
0
  if( cnt == maxNumMergeCand )
997
0
  {
998
0
    return;
999
0
  }
1000
1001
  // above right
1002
0
  const CodingUnit* puAboveRight = cs.getCURestricted( posRT.offset( 1, -1 ), cu, cu.chType );
1003
1004
0
  bool isAvailableB0 = puAboveRight && isDiffMER( cu.lumaPos(), posRT.offset(1, -1), plevel) && CU::isInter( *puAboveRight );
1005
1006
0
  if( isAvailableB0 )
1007
0
  {
1008
0
    miAboveRight = puAboveRight->getMotionInfo( posRT.offset( 1, -1 ) );
1009
1010
0
    if( !isAvailableB1 || ( miAbove != miAboveRight ) )
1011
0
    {
1012
      // get Inter Dir
1013
0
      mrgCtx.interDirNeighbours[cnt]    = miAboveRight.interDir();
1014
0
      mrgCtx.useAltHpelIf      [cnt]    = puAboveRight->imv == IMV_HPEL;
1015
0
      mrgCtx.BcwIdx            [cnt]    = mrgCtx.interDirNeighbours[cnt] == 3 ? puAboveRight->BcwIdx : BCW_DEFAULT;
1016
0
      mrgCtx.mvFieldNeighbours [cnt][0] . setMvField( miAboveRight.mv[0], miAboveRight.miRefIdx[0] );
1017
1018
0
      if( slice.isInterB() )
1019
0
      {
1020
0
        mrgCtx.mvFieldNeighbours[cnt][1]. setMvField( miAboveRight.mv[1], miAboveRight.miRefIdx[1] );
1021
0
      }
1022
0
      if (mrgCandIdx == cnt)
1023
0
      {
1024
0
        return;
1025
0
      }
1026
1027
0
      cnt++;
1028
0
    }
1029
0
  }
1030
  // early termination
1031
0
  if( cnt == maxNumMergeCand )
1032
0
  {
1033
0
    return;
1034
0
  }
1035
1036
  //left bottom
1037
0
  const CodingUnit* puLeftBottom = cs.getCURestricted( posLB.offset( -1, 1 ), cu, cu.chType );
1038
1039
0
  bool isAvailableA0 = puLeftBottom && isDiffMER( cu.lumaPos(), posLB.offset(-1, 1), plevel) && CU::isInter( *puLeftBottom );
1040
1041
0
  if( isAvailableA0 )
1042
0
  {
1043
0
    miBelowLeft = puLeftBottom->getMotionInfo( posLB.offset( -1, 1 ) );
1044
1045
0
    if( !isAvailableA1 || ( miBelowLeft != miLeft ) )
1046
0
    {
1047
      // get Inter Dir
1048
0
      mrgCtx.interDirNeighbours [cnt]    = miBelowLeft.interDir();
1049
0
      mrgCtx.useAltHpelIf       [cnt]    = puLeftBottom->imv == IMV_HPEL;
1050
0
      mrgCtx.BcwIdx             [cnt]    = mrgCtx.interDirNeighbours[cnt] == 3 ? puLeftBottom->BcwIdx : BCW_DEFAULT;
1051
      // get Mv from Bottom-Left
1052
0
      mrgCtx.mvFieldNeighbours  [cnt][0] . setMvField( miBelowLeft.mv[0], miBelowLeft.miRefIdx[0] );
1053
1054
0
      if( slice.isInterB() )
1055
0
      {
1056
0
        mrgCtx.mvFieldNeighbours[cnt][1] . setMvField( miBelowLeft.mv[1], miBelowLeft.miRefIdx[1] );
1057
0
      }
1058
0
      if (mrgCandIdx == cnt)
1059
0
      {
1060
0
        return;
1061
0
      }
1062
1063
0
      cnt++;
1064
0
    }
1065
0
  }
1066
  // early termination
1067
0
  if( cnt == maxNumMergeCand )
1068
0
  {
1069
0
    return;
1070
0
  }
1071
1072
1073
  // above left
1074
0
  if ( cnt < 4 )
1075
0
  {
1076
0
    const CodingUnit* puAboveLeft = cs.getCURestricted( posLT.offset( -1, -1 ), cu, cu.chType );
1077
1078
0
    bool isAvailableB2 = puAboveLeft && isDiffMER( cu.lumaPos(), posLT.offset(-1, -1), plevel ) && CU::isInter( *puAboveLeft );
1079
1080
0
    if( isAvailableB2 )
1081
0
    {
1082
0
      miAboveLeft = puAboveLeft->getMotionInfo( posLT.offset( -1, -1 ) );
1083
1084
0
      if( ( !isAvailableA1 || ( miLeft != miAboveLeft ) ) && ( !isAvailableB1 || ( miAbove != miAboveLeft ) ) )
1085
0
      {
1086
        // get Inter Dir
1087
0
        mrgCtx.interDirNeighbours [cnt]    = miAboveLeft.interDir();
1088
0
        mrgCtx.useAltHpelIf       [cnt]    = puAboveLeft->imv == IMV_HPEL;
1089
0
        mrgCtx.BcwIdx             [cnt]    = mrgCtx.interDirNeighbours[cnt] == 3 ? puAboveLeft->BcwIdx : BCW_DEFAULT;
1090
        // get Mv from Above-Left
1091
0
        mrgCtx.mvFieldNeighbours  [cnt][0] . setMvField( miAboveLeft.mv[0], miAboveLeft.miRefIdx[0] );
1092
1093
0
        if( slice.isInterB() )
1094
0
        {
1095
0
          mrgCtx.mvFieldNeighbours[cnt][1] . setMvField( miAboveLeft.mv[1], miAboveLeft.miRefIdx[1] );
1096
0
        }
1097
0
        if (mrgCandIdx == cnt)
1098
0
        {
1099
0
          return;
1100
0
        }
1101
1102
0
        cnt++;
1103
0
      }
1104
0
    }
1105
0
  }
1106
  // early termination
1107
0
  if (cnt == maxNumMergeCand)
1108
0
  {
1109
0
    return;
1110
0
  }
1111
1112
0
  if (slice.picHeader->enableTMVP && (cu.lumaSize().width + cu.lumaSize().height > 12))
1113
0
  {
1114
    //>> MTK colocated-RightBottom
1115
    // offset the pos to be sure to "point" to the same position the uiAbsPartIdx would've pointed to
1116
0
    Position posRB = cu.Y().bottomRight().offset( -3, -3 );
1117
0
    const PreCalcValues& pcv = *cs.pcv;
1118
1119
0
    Position posC0;
1120
0
    Position posC1 = cu.Y().center();
1121
0
    bool C0Avail = false;
1122
0
    bool boundaryCond = ((posRB.x + pcv.minCUSize) < pcv.lumaWidth) && ((posRB.y + pcv.minCUSize) < pcv.lumaHeight);
1123
0
    const SubPic& curSubPic = cu.cs->slice->pps->getSubPicFromPos(cu.lumaPos());
1124
0
    if (curSubPic.treatedAsPic )
1125
0
    {
1126
0
      boundaryCond = ((posRB.x + pcv.minCUSize) <= curSubPic.subPicRight &&
1127
0
                      (posRB.y + pcv.minCUSize) <= curSubPic.subPicBottom);
1128
0
    }    
1129
0
    if (boundaryCond)
1130
0
    {
1131
0
      int posYInCtu = posRB.y & pcv.maxCUSizeMask;
1132
0
      if (posYInCtu + 4 < pcv.maxCUSize)
1133
0
      {
1134
0
        posC0 = posRB.offset(4, 4);
1135
0
        C0Avail = true;
1136
0
      }
1137
0
    }
1138
1139
0
    Mv        cColMv;
1140
0
    int       iRefIdx     = 0;
1141
0
    int       dir         = 0;
1142
0
    unsigned  uiArrayAddr = cnt;
1143
0
    bool      bExistMV    = ( C0Avail && getColocatedMVP( cu, REF_PIC_LIST_0, posC0, cColMv, iRefIdx ) )
1144
0
                                      || getColocatedMVP( cu, REF_PIC_LIST_0, posC1, cColMv, iRefIdx );
1145
0
    if (bExistMV)
1146
0
    {
1147
0
      dir     |= 1;
1148
0
      mrgCtx.mvFieldNeighbours[uiArrayAddr][0].setMvField(cColMv, iRefIdx);
1149
0
    }
1150
1151
0
    if (slice.isInterB())
1152
0
    {
1153
0
      bExistMV = ( C0Avail && getColocatedMVP( cu, REF_PIC_LIST_1, posC0, cColMv, iRefIdx ) )
1154
0
                           || getColocatedMVP( cu, REF_PIC_LIST_1, posC1, cColMv, iRefIdx );
1155
0
      if (bExistMV)
1156
0
      {
1157
0
        dir     |= 2;
1158
0
        mrgCtx.mvFieldNeighbours[uiArrayAddr][1].setMvField(cColMv, iRefIdx);
1159
0
      }
1160
0
    }
1161
1162
0
    if( dir != 0 )
1163
0
    {
1164
0
      bool addTMvp = true;
1165
0
      if( addTMvp )
1166
0
      {
1167
0
        mrgCtx.interDirNeighbours[uiArrayAddr] = dir;
1168
0
        mrgCtx.BcwIdx            [uiArrayAddr] = BCW_DEFAULT;
1169
0
        mrgCtx.useAltHpelIf      [uiArrayAddr] = false;
1170
0
        if (mrgCandIdx == cnt)
1171
0
        {
1172
0
          return;
1173
0
        }
1174
1175
0
        cnt++;
1176
0
      }
1177
0
    }
1178
0
  }
1179
1180
  // early termination
1181
0
  if (cnt == maxNumMergeCand)
1182
0
  {
1183
0
    return;
1184
0
  }
1185
1186
0
  int maxNumMergeCandMin1 = maxNumMergeCand - 1;
1187
0
  if( cnt != maxNumMergeCandMin1 )
1188
0
  {
1189
0
    bool isGt4x4 = true;
1190
0
    bool bFound  = addMergeHMVPCand( cs, mrgCtx, mrgCandIdx, maxNumMergeCandMin1, cnt, isAvailableA1, miLeft, isAvailableB1, miAbove, CU::isIBC( cu ), isGt4x4 );
1191
1192
0
    if (bFound)
1193
0
    {
1194
0
      return;
1195
0
    }
1196
0
  }
1197
1198
  // pairwise-average candidates
1199
0
  {
1200
0
    if (cnt > 1 && cnt < maxNumMergeCand)
1201
0
    {
1202
0
      mrgCtx.mvFieldNeighbours[cnt][0].setMvField( Mv( 0, 0 ), NOT_VALID );
1203
0
      mrgCtx.mvFieldNeighbours[cnt][1].setMvField( Mv( 0, 0 ), NOT_VALID );
1204
      // calculate average MV for L0 and L1 seperately
1205
0
      unsigned char interDir = 0;
1206
1207
1208
0
      mrgCtx.useAltHpelIf[cnt] = (mrgCtx.useAltHpelIf[0] == mrgCtx.useAltHpelIf[1]) ? mrgCtx.useAltHpelIf[0] : false;
1209
0
      for( int refListId = 0; refListId < (slice.isInterB() ? 2 : 1); refListId++ )
1210
0
      {
1211
0
        const short refIdxI = mrgCtx.mvFieldNeighbours[0][refListId].refIdx;
1212
0
        const short refIdxJ = mrgCtx.mvFieldNeighbours[1][refListId].refIdx;
1213
1214
        // both MVs are invalid, skip
1215
0
        if( (refIdxI == NOT_VALID) && (refIdxJ == NOT_VALID) )
1216
0
        {
1217
0
          continue;
1218
0
        }
1219
1220
0
        interDir += 1 << refListId;
1221
        // both MVs are valid, average these two MVs
1222
0
        if( (refIdxI != NOT_VALID) && (refIdxJ != NOT_VALID) )
1223
0
        {
1224
0
          const Mv& MvI = mrgCtx.mvFieldNeighbours[0][refListId].mv;
1225
0
          const Mv& MvJ = mrgCtx.mvFieldNeighbours[1][refListId].mv;
1226
1227
          // average two MVs
1228
0
          Mv avgMv = MvI;
1229
0
          avgMv += MvJ;
1230
0
          roundAffineMv(avgMv.hor, avgMv.ver, 1);
1231
1232
0
          mrgCtx.mvFieldNeighbours[cnt][refListId].setMvField( avgMv, refIdxI );
1233
0
        }
1234
        // only one MV is valid, take the only one MV
1235
0
        else if( refIdxI != NOT_VALID )
1236
0
        {
1237
0
          Mv singleMv = mrgCtx.mvFieldNeighbours[0][refListId].mv;
1238
0
          mrgCtx.mvFieldNeighbours[cnt][refListId].setMvField( singleMv, refIdxI );
1239
0
        }
1240
0
        else if( refIdxJ != NOT_VALID )
1241
0
        {
1242
0
          Mv singleMv = mrgCtx.mvFieldNeighbours[1][refListId].mv;
1243
0
          mrgCtx.mvFieldNeighbours[cnt][refListId].setMvField( singleMv, refIdxJ );
1244
0
        }
1245
0
      }
1246
1247
0
      mrgCtx.interDirNeighbours[cnt] = interDir;
1248
0
      if( interDir > 0 )
1249
0
      {
1250
0
        cnt++;
1251
0
      }
1252
0
    }
1253
1254
    // early termination
1255
0
    if( cnt == maxNumMergeCand )
1256
0
    {
1257
0
      return;
1258
0
    }
1259
0
  }
1260
1261
0
  uint32_t uiArrayAddr = cnt;
1262
1263
0
  int iNumRefIdx = slice.isInterB() ? std::min(slice.numRefIdx[ REF_PIC_LIST_0 ], slice.numRefIdx[ REF_PIC_LIST_1 ]) : slice.numRefIdx[ REF_PIC_LIST_0 ];
1264
1265
0
  int r = 0;
1266
0
  int refcnt = 0;
1267
0
  while (uiArrayAddr < maxNumMergeCand && uiArrayAddr < MRG_MAX_NUM_CANDS)
1268
0
  {
1269
0
    mrgCtx.interDirNeighbours  [uiArrayAddr]    = 1;
1270
0
    mrgCtx.BcwIdx              [uiArrayAddr]    = BCW_DEFAULT;
1271
0
    mrgCtx.mvFieldNeighbours   [uiArrayAddr][0] . setMvField( Mv(0, 0), r );
1272
0
    mrgCtx.useAltHpelIf        [uiArrayAddr]    = false;
1273
1274
0
    if (slice.isInterB())
1275
0
    {
1276
0
      mrgCtx.interDirNeighbours[uiArrayAddr]    = 3;
1277
0
      mrgCtx.mvFieldNeighbours [uiArrayAddr][1] . setMvField( Mv(0, 0), r );
1278
0
    }
1279
1280
0
    if ( mrgCtx.interDirNeighbours[uiArrayAddr] == 1 && cu.cs->slice->getRefPic(REF_PIC_LIST_0, mrgCtx.mvFieldNeighbours[uiArrayAddr][0].refIdx)->getPOC() == cu.cs->slice->poc)
1281
0
    {
1282
0
      mrgCtx.mrgTypeNeighbours[uiArrayAddr] = MRG_TYPE_IBC;
1283
0
    }
1284
1285
0
    uiArrayAddr++;
1286
1287
0
    if (refcnt == iNumRefIdx - 1)
1288
0
    {
1289
0
      r = 0;
1290
0
    }
1291
0
    else
1292
0
    {
1293
0
      ++r;
1294
0
      ++refcnt;
1295
0
    }
1296
0
  }
1297
0
  mrgCtx.numValidMergeCand = uiArrayAddr;
1298
0
}
1299
1300
bool CU::checkDMVRCondition(const CodingUnit& cu)
1301
25.2k
{
1302
25.2k
  if( !cu.cs->sps->DMVR || cu.cs->slice->picHeader->disDmvrFlag )
1303
0
  {
1304
0
    return false;
1305
0
  }
1306
1307
25.2k
  return  cu.mergeFlag
1308
0
      &&  cu.mergeType == MRG_TYPE_DEFAULT_N
1309
0
      && !cu.ciip
1310
0
      && !cu.affine
1311
0
      && !cu.mmvdMergeFlag
1312
0
      && !cu.mmvdSkip
1313
0
      &&  CU::isBiPredFromDifferentDirEqDistPoc( cu )
1314
0
      &&  cu.lumaSize().minDim() >= 8
1315
0
      &&  cu.lumaSize().area() >= 128
1316
0
      &&  cu.BcwIdx == BCW_DEFAULT;
1317
25.2k
}
1318
1319
int convertMvFixedToFloat(int32_t val)
1320
0
{
1321
0
  int sign  = val >> 31;
1322
0
  int scale = floorLog2((val ^ sign) | MV_MANTISSA_UPPER_LIMIT) - (MV_MANTISSA_BITCOUNT - 1);
1323
1324
0
  int exponent;
1325
0
  int mantissa;
1326
0
  if (scale >= 0)
1327
0
  {
1328
0
    int round = (1 << scale) >> 1;
1329
0
    int n     = (val + round) >> scale;
1330
0
    exponent  = scale + ((n ^ sign) >> (MV_MANTISSA_BITCOUNT - 1));
1331
0
    mantissa  = (n & MV_MANTISSA_UPPER_LIMIT) | (sign * (1 << (MV_MANTISSA_BITCOUNT - 1)));
1332
0
  }
1333
0
  else
1334
0
  {
1335
0
    exponent = 0;
1336
0
    mantissa = val;
1337
0
  }
1338
1339
0
  return exponent | (mantissa * (1 << MV_EXPONENT_BITCOUNT));
1340
0
}
1341
1342
int convertMvFloatToFixed(int val)
1343
0
{
1344
0
  int exponent = val & MV_EXPONENT_MASK;
1345
0
  int mantissa = val >> MV_EXPONENT_BITCOUNT;
1346
0
  return exponent == 0 ? mantissa : (mantissa ^ MV_MANTISSA_LIMIT) * (1 << (exponent - 1));
1347
0
}
1348
1349
int roundMvComp(int x)
1350
0
{
1351
0
  return convertMvFloatToFixed(convertMvFixedToFloat(x));
1352
0
}
1353
1354
int CU::getDistScaleFactor(const int currPOC, const int currRefPOC, const int colPOC, const int colRefPOC)
1355
0
{
1356
0
  int iDiffPocD = colPOC - colRefPOC;
1357
0
  int iDiffPocB = currPOC - currRefPOC;
1358
1359
0
  if (iDiffPocD == iDiffPocB)
1360
0
  {
1361
0
    return 4096;
1362
0
  }
1363
0
  else
1364
0
  {
1365
0
    int iTDB = Clip3(-128, 127, iDiffPocB);
1366
0
    int iTDD = Clip3(-128, 127, iDiffPocD);
1367
0
    int iX = (0x4000 + abs(iTDD / 2)) / iTDD;
1368
0
    int iScale = Clip3(-4096, 4095, (iTDB * iX + 32) >> 6);
1369
0
    return iScale;
1370
0
  }
1371
0
}
1372
1373
void CU::getInterMMVDMergeCandidates( const CodingUnit &cu, MergeCtx &mrgCtx )
1374
0
{
1375
0
  int refIdxList0, refIdxList1;
1376
0
  int k;
1377
0
  int currBaseNum = 0;
1378
0
  const uint16_t maxNumMergeCand = mrgCtx.numValidMergeCand;
1379
1380
0
  for( k = 0; k < maxNumMergeCand; k++ )
1381
0
  {
1382
0
    if( mrgCtx.mrgTypeNeighbours[k] == MRG_TYPE_DEFAULT_N )
1383
0
    {
1384
0
      refIdxList0 = mrgCtx.mvFieldNeighbours[k][0].refIdx;
1385
0
      refIdxList1 = mrgCtx.mvFieldNeighbours[k][1].refIdx;
1386
1387
0
      if( ( refIdxList0 >= 0 ) && ( refIdxList1 >= 0 ) )
1388
0
      {
1389
0
        mrgCtx.mmvdBaseMv[currBaseNum][0] = mrgCtx.mvFieldNeighbours[k][0];
1390
0
        mrgCtx.mmvdBaseMv[currBaseNum][1] = mrgCtx.mvFieldNeighbours[k][1];
1391
0
      }
1392
0
      else if( refIdxList0 >= 0 )
1393
0
      {
1394
0
        mrgCtx.mmvdBaseMv[currBaseNum][0] = mrgCtx.mvFieldNeighbours[k][0];
1395
0
        mrgCtx.mmvdBaseMv[currBaseNum][1] = MvField( Mv( 0, 0 ), -1 );
1396
0
      }
1397
0
      else if( refIdxList1 >= 0 )
1398
0
      {
1399
0
        mrgCtx.mmvdBaseMv[currBaseNum][0] = MvField( Mv( 0, 0 ), -1 );
1400
0
        mrgCtx.mmvdBaseMv[currBaseNum][1] = mrgCtx.mvFieldNeighbours[k][1];
1401
0
      }
1402
0
      mrgCtx.mmvdUseAltHpelIf[currBaseNum] = mrgCtx.useAltHpelIf[k];
1403
1404
0
      currBaseNum++;
1405
1406
0
      if( currBaseNum == MMVD_BASE_MV_NUM )
1407
0
        break;
1408
0
    }
1409
0
  }
1410
0
}
1411
1412
bool CU::getColocatedMVP(const CodingUnit& cu, const RefPicList refPicList, const Position& _pos, Mv& rcMv, const int refIdx, bool sbFlag )
1413
0
{
1414
0
  if( CU::isIBC( cu ) )
1415
0
  {
1416
0
    return false;
1417
0
  }
1418
1419
  // don't perform MV compression when generally disabled or SbTMVP is used
1420
0
  const unsigned scale = 4 * std::max<int>(1, 4 * AMVP_DECIMATION_FACTOR / 4);
1421
0
  const unsigned mask  = ~( scale - 1 );
1422
1423
0
  const Position pos = Position{ PosType( _pos.x & mask ), PosType( _pos.y & mask ) };
1424
1425
0
  const Slice &slice = *cu.cs->slice;
1426
1427
  // use coldir.
1428
0
  const Picture* const pColPic = slice.getRefPic(RefPicList(slice.isInterB() ? 1 - slice.colFromL0Flag : 0), slice.colRefIdx);
1429
1430
0
  if( !pColPic )
1431
0
  {
1432
0
    return false;
1433
0
  }
1434
1435
  // Check the position of colocated block is within a subpicture
1436
0
  const SubPic& curSubPic = cu.cs->slice->pps->getSubPicFromPos(cu.lumaPos());
1437
0
  if (curSubPic.treatedAsPic)
1438
0
  {
1439
0
    if (!curSubPic.isContainingPos(pos))
1440
0
      return false;
1441
0
  }
1442
1443
0
  RefPicList eColRefPicList = slice.checkLDC ? refPicList : RefPicList(slice.colFromL0Flag);
1444
1445
0
  const MotionInfo& mi = pColPic->cs->getMotionInfo( pos );
1446
1447
0
  if( !mi.isInter() )
1448
0
  {
1449
0
    return false;
1450
0
  }
1451
1452
0
  int iColRefIdx = mi.miRefIdx[eColRefPicList];
1453
1454
0
  if (sbFlag && !slice.checkLDC)
1455
0
  {
1456
0
    eColRefPicList = refPicList;
1457
0
    iColRefIdx = mi.miRefIdx[eColRefPicList];
1458
0
    if (iColRefIdx < 0)
1459
0
    {
1460
0
      return false;
1461
0
    }
1462
0
  }
1463
0
  else
1464
0
  {
1465
0
    if (iColRefIdx < 0)
1466
0
    {
1467
0
      eColRefPicList = RefPicList(1 - eColRefPicList);
1468
0
      iColRefIdx = mi.miRefIdx[eColRefPicList];
1469
1470
0
      if (iColRefIdx < 0)
1471
0
      {
1472
0
        return false;
1473
0
      }
1474
0
    }
1475
0
  }
1476
1477
0
  int ctuRsAddr = getCtuAddr( pos, *pColPic->cs->pcv );
1478
0
  const Slice* sliceCol = pColPic->ctuSlice[ ctuRsAddr ];
1479
1480
0
  CHECK( sliceCol == nullptr, "Slice segment not found" );
1481
1482
0
  const bool bIsCurrRefLongTerm = slice.getRefPic(refPicList, refIdx)->isLongTerm;
1483
0
  const bool bIsColRefLongTerm  = sliceCol->isUsedAsLongTerm[eColRefPicList][iColRefIdx];
1484
1485
0
  if (bIsCurrRefLongTerm != bIsColRefLongTerm)
1486
0
  {
1487
0
    return false;
1488
0
  }
1489
1490
1491
  // Scale the vector.
1492
0
  Mv cColMv = mi.mv[eColRefPicList];
1493
0
  cColMv.hor = roundMvComp( cColMv.hor );
1494
0
  cColMv.ver = roundMvComp( cColMv.ver );
1495
1496
0
  if (bIsCurrRefLongTerm)
1497
0
  {
1498
0
    rcMv = cColMv;
1499
0
    rcMv.clipToStorageBitDepth();
1500
0
  }
1501
0
  else
1502
0
  {
1503
0
    const int currPOC    = slice.poc;
1504
0
    const int colPOC     = sliceCol->poc;
1505
0
    const int colRefPOC  = sliceCol->getRefPOC(eColRefPicList, iColRefIdx);
1506
0
    const int currRefPOC = slice.getRefPic(refPicList, refIdx)->getPOC();
1507
0
    const int distscale  = getDistScaleFactor(currPOC, currRefPOC, colPOC, colRefPOC);
1508
1509
0
    if (distscale == 4096)
1510
0
    {
1511
0
      rcMv = cColMv;
1512
0
      rcMv.clipToStorageBitDepth();
1513
0
    }
1514
0
    else
1515
0
    {
1516
0
      rcMv = cColMv.scaleMv(distscale);
1517
0
    }
1518
0
  }
1519
1520
0
  return true;
1521
0
}
1522
1523
static void isAddNeighborMvIBC( const Mv& currMv, Mv* neighborMvs, int& numNeighborMv )
1524
0
{
1525
0
  Mv bv = currMv;
1526
0
  bv.changePrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT );
1527
1528
0
  bool existed = false;
1529
0
  for( uint32_t cand = 0; cand < numNeighborMv && !existed; cand++ )
1530
0
  {
1531
0
    if( bv == neighborMvs[cand] )
1532
0
    {
1533
0
      existed = true;
1534
0
    }
1535
0
  }
1536
1537
0
  if( !existed )
1538
0
  {
1539
0
    neighborMvs[numNeighborMv++] = bv;
1540
0
  }
1541
0
}
1542
1543
static bool getDerivedMvIbc( CodingUnit& cu, const Mv& currentBv, Mv& derivedMv )
1544
0
{
1545
0
  int cuPelX  = cu.lumaPos().x;
1546
0
  int cuPelY  = cu.lumaPos().y;
1547
0
  int rX      = cuPelX + currentBv.hor;
1548
0
  int rY      = cuPelY + currentBv.ver;
1549
0
  int offsetX = currentBv.hor;
1550
0
  int offsetY = currentBv.ver;
1551
1552
0
  if( rX < 0 || rY < 0 || rX >= cu.cs->slice->pps->picWidthInLumaSamples || rY >= cu.cs->slice->pps->picHeightInLumaSamples )
1553
0
  {
1554
0
    return false;
1555
0
  }
1556
1557
0
  const CodingUnit* neibRefCU = cu.cs->getCURestricted( cu.lumaPos().offset( offsetX, offsetY ), cu, CH_L );
1558
1559
0
  if( neibRefCU && CU::isIBC( *neibRefCU ) )
1560
0
  {
1561
0
    Mv currMv  = currentBv; currMv.changePrecision( MV_PRECISION_INT, MV_PRECISION_INTERNAL );
1562
0
    derivedMv  = neibRefCU->mv[0][0];
1563
0
    derivedMv += currMv;
1564
0
    return true;
1565
0
  }
1566
1567
0
  return false;
1568
0
}
1569
1570
void CU::getIbcMVPsEncOnly(CodingUnit& cu, Mv* mvPred, int& nbPred)
1571
27.1k
{
1572
27.1k
  const PreCalcValues& pcv = *cu.cs->pcv;
1573
27.1k
  const int  cuWidth = cu.blocks[COMP_Y].width;
1574
27.1k
  const int  cuHeight = cu.blocks[COMP_Y].height;
1575
27.1k
  const int  log2UnitWidth = floorLog2(pcv.minCUSize); //(pcv.minCUWidth);
1576
27.1k
  const int  log2UnitHeight = floorLog2(pcv.minCUSize); //(pcv.minCUHeight);
1577
27.1k
  const int  totalAboveUnits = (cuWidth >> log2UnitHeight) + 1; // log2UnitWidth) + 1;
1578
27.1k
  const int  totalLeftUnits = (cuHeight >> log2UnitHeight) + 1;
1579
1580
27.1k
  nbPred = 0;
1581
27.1k
  Position posLT = cu.Y().topLeft();
1582
1583
  // above-left
1584
27.1k
  const CodingUnit* aboveLeftCU = cu.cs->getCURestricted(posLT.offset(-1, -1), cu, CH_L);
1585
27.1k
  if( aboveLeftCU && CU::isIBC( *aboveLeftCU ) )
1586
0
  {
1587
0
    isAddNeighborMvIBC(aboveLeftCU->mv[0][0], mvPred, nbPred);
1588
0
  }
1589
1590
  // above neighbors
1591
262k
  for( uint32_t dx = 0; dx < totalAboveUnits && nbPred < IBC_NUM_CANDIDATES; dx++ )
1592
234k
  {
1593
234k
    const CodingUnit* tmpCU = cu.cs->getCURestricted( posLT.offset( ( dx << log2UnitWidth ), -1 ), cu, CH_L );
1594
234k
    if( tmpCU && CU::isIBC( *tmpCU ) )
1595
0
    {
1596
0
      isAddNeighborMvIBC( tmpCU->mv[0][0], mvPred, nbPred );
1597
0
    }
1598
234k
  }
1599
1600
  // left neighbors
1601
262k
  for( uint32_t dy = 0; dy < totalLeftUnits && nbPred < IBC_NUM_CANDIDATES; dy++ )
1602
235k
  {
1603
235k
    const CodingUnit* tmpCU = cu.cs->getCURestricted( posLT.offset( -1, ( dy << log2UnitHeight ) ), cu, CH_L );
1604
235k
    if( tmpCU && CU::isIBC( *tmpCU ) )
1605
0
    {
1606
0
      isAddNeighborMvIBC( tmpCU->mv[0][0], mvPred, nbPred );
1607
0
    }
1608
235k
  }
1609
1610
27.1k
  size_t numAvaiCandInLUT = cu.cs->motionLut.lutIbc.size();
1611
27.1k
  for( uint32_t cand = 0; cand < numAvaiCandInLUT && nbPred < IBC_NUM_CANDIDATES; cand++ )
1612
0
  {
1613
0
    auto& neibMi = cu.cs->motionLut.lutIbc;
1614
0
    isAddNeighborMvIBC( neibMi[cand].mv[0], mvPred, nbPred );
1615
0
  }
1616
1617
27.1k
  bool isBvCandDerived[IBC_NUM_CANDIDATES];
1618
27.1k
  ::memset(isBvCandDerived, false, IBC_NUM_CANDIDATES);
1619
1620
27.1k
  int curNbPred = nbPred;
1621
27.1k
  if( curNbPred < IBC_NUM_CANDIDATES )
1622
27.1k
  {
1623
27.1k
    do
1624
27.1k
    {
1625
27.1k
      curNbPred = nbPred;
1626
27.1k
      for( uint32_t idx = 0; idx < curNbPred && nbPred < IBC_NUM_CANDIDATES; idx++ )
1627
0
      {
1628
0
        if( !isBvCandDerived[idx] )
1629
0
        {
1630
0
          Mv derivedMv;
1631
0
          if( getDerivedMvIbc( cu, mvPred[idx], derivedMv ) )
1632
0
          {
1633
0
            isAddNeighborMvIBC( derivedMv, mvPred, nbPred );
1634
0
          }
1635
0
          isBvCandDerived[idx] = true;
1636
0
        }
1637
0
      }
1638
27.1k
    } while( nbPred > curNbPred && nbPred < IBC_NUM_CANDIDATES );
1639
27.1k
  }
1640
27.1k
}
1641
1642
void CU::fillIBCMvpCand(CodingUnit& cu, AMVPInfo& amvpInfo)
1643
54.3k
{
1644
54.3k
  AMVPInfo* pInfo = &amvpInfo;
1645
1646
54.3k
  pInfo->numCand = 0;
1647
1648
54.3k
  MergeCtx mergeCtx;
1649
54.3k
  CU::getIBCMergeCandidates(cu, mergeCtx, AMVP_MAX_NUM_CANDS - 1);
1650
54.3k
  int candIdx = 0;
1651
162k
  while (pInfo->numCand < AMVP_MAX_NUM_CANDS)
1652
108k
  {
1653
108k
    pInfo->mvCand[pInfo->numCand] = mergeCtx.mvFieldNeighbours[candIdx][0].mv;;
1654
108k
    pInfo->numCand++;
1655
108k
    candIdx++;
1656
108k
  }
1657
1658
54.3k
  for (Mv& mv : pInfo->mvCand)
1659
162k
  {
1660
162k
    mv.roundIbcPrecInternal2Amvr(cu.imv);
1661
162k
  }
1662
54.3k
}
1663
1664
bool CU::isDiffMER(const Position &pos1, const Position &pos2, const unsigned plevel)
1665
0
{
1666
0
  const unsigned xN = pos1.x;
1667
0
  const unsigned yN = pos1.y;
1668
0
  const unsigned xP = pos2.x;
1669
0
  const unsigned yP = pos2.y;
1670
1671
0
  if ((xN >> plevel) != (xP >> plevel))
1672
0
  {
1673
0
    return true;
1674
0
  }
1675
1676
0
  if ((yN >> plevel) != (yP >> plevel))
1677
0
  {
1678
0
    return true;
1679
0
  }
1680
1681
0
  return false;
1682
0
}
1683
1684
1685
/** Constructs a list of candidates for AMVP (See specification, section "Derivation process for motion vector predictor candidates")
1686
* \param uiPartIdx
1687
* \param uiPartAddr
1688
* \param refPicList
1689
* \param iRefIdx
1690
* \param pInfo
1691
*/
1692
void CU::fillMvpCand(CodingUnit& cu, const RefPicList refPicList, const int refIdx, AMVPInfo &amvpInfo)
1693
0
{
1694
0
  CodingStructure &cs = *cu.cs;
1695
1696
0
  AMVPInfo *pInfo = &amvpInfo;
1697
1698
0
  pInfo->numCand = 0;
1699
1700
0
  if (refIdx < 0)
1701
0
  {
1702
0
    return;
1703
0
  }
1704
1705
  //-- Get Spatial MV
1706
0
  Position posLT = cu.Y().topLeft();
1707
0
  Position posRT = cu.Y().topRight();
1708
0
  Position posLB = cu.Y().bottomLeft();
1709
1710
0
  {
1711
0
    bool bAdded = addMVPCandUnscaled( cu, refPicList, refIdx, posLB, MD_BELOW_LEFT, *pInfo );
1712
1713
0
    if( !bAdded )
1714
0
    {
1715
0
      bAdded = addMVPCandUnscaled( cu, refPicList, refIdx, posLB, MD_LEFT, *pInfo );
1716
1717
0
    }
1718
0
  }
1719
1720
  // Above predictor search
1721
0
  {
1722
0
    bool bAdded = addMVPCandUnscaled( cu, refPicList, refIdx, posRT, MD_ABOVE_RIGHT, *pInfo );
1723
1724
0
    if( !bAdded )
1725
0
    {
1726
0
      bAdded = addMVPCandUnscaled( cu, refPicList, refIdx, posRT, MD_ABOVE, *pInfo );
1727
1728
0
      if( !bAdded )
1729
0
      {
1730
0
        addMVPCandUnscaled( cu, refPicList, refIdx, posLT, MD_ABOVE_LEFT, *pInfo );
1731
0
      }
1732
0
    }
1733
0
  }
1734
1735
1736
0
  for( int i = 0; i < pInfo->numCand; i++ )
1737
0
  {
1738
0
    pInfo->mvCand[i].roundTransPrecInternal2Amvr(cu.imv);
1739
0
  }
1740
1741
0
  if( pInfo->numCand == 2 )
1742
0
  {
1743
0
    if( pInfo->mvCand[0] == pInfo->mvCand[1] )
1744
0
    {
1745
0
      pInfo->numCand = 1;
1746
0
    }
1747
0
  }
1748
1749
0
  if (cs.picHeader->enableTMVP && pInfo->numCand < AMVP_MAX_NUM_CANDS && (cu.lumaSize().width + cu.lumaSize().height > 12))
1750
0
  {
1751
    // Get Temporal Motion Predictor
1752
0
    const int refIdx_Col = refIdx;
1753
1754
0
    Position posRB = cu.Y().bottomRight().offset(-3, -3);
1755
1756
0
    const PreCalcValues& pcv = *cs.pcv;
1757
1758
0
    Position posC0;
1759
0
    bool C0Avail = false;
1760
0
    Position posC1 = cu.Y().center();
1761
0
    Mv cColMv;
1762
1763
0
    bool boundaryCond = ((posRB.x + pcv.minCUSize) < pcv.lumaWidth) && ((posRB.y + pcv.minCUSize) < pcv.lumaHeight);
1764
0
    const SubPic& curSubPic = cu.cs->slice->pps->getSubPicFromPos(cu.lumaPos());
1765
0
    if (curSubPic.treatedAsPic)
1766
0
    {
1767
0
      boundaryCond = ((posRB.x + pcv.minCUSize) <= curSubPic.subPicRight &&
1768
0
                      (posRB.y + pcv.minCUSize) <= curSubPic.subPicBottom);
1769
0
    }    
1770
0
    if (boundaryCond)
1771
0
    {
1772
0
      int posYInCtu = posRB.y & pcv.maxCUSizeMask;
1773
0
      if (posYInCtu + 4 < pcv.maxCUSize)
1774
0
      {
1775
0
        posC0 = posRB.offset(4, 4);
1776
0
        C0Avail = true;
1777
0
      }
1778
0
    }
1779
0
    if ( ( C0Avail && getColocatedMVP( cu, refPicList, posC0, cColMv, refIdx_Col ) ) || getColocatedMVP( cu, refPicList, posC1, cColMv, refIdx_Col ) )
1780
0
    {
1781
0
      cColMv.roundTransPrecInternal2Amvr(cu.imv);
1782
0
      pInfo->mvCand[pInfo->numCand++] = cColMv;
1783
0
    }
1784
0
  }
1785
1786
0
  if (pInfo->numCand < AMVP_MAX_NUM_CANDS)
1787
0
  {
1788
0
    const int        currRefPOC = cs.slice->getRefPic(refPicList, refIdx)->getPOC();
1789
0
    addAMVPHMVPCand(cu, refPicList, currRefPOC, *pInfo);
1790
0
  }
1791
1792
0
  if (pInfo->numCand > AMVP_MAX_NUM_CANDS)
1793
0
  {
1794
0
    pInfo->numCand = AMVP_MAX_NUM_CANDS;
1795
0
  }
1796
1797
0
  while (pInfo->numCand < AMVP_MAX_NUM_CANDS)
1798
0
  {
1799
0
    pInfo->mvCand[pInfo->numCand] = Mv( 0, 0 );
1800
0
    pInfo->numCand++;
1801
0
  }
1802
1803
0
  for (Mv &mv : pInfo->mvCand)
1804
0
  {
1805
0
    mv.roundTransPrecInternal2Amvr(cu.imv);
1806
0
  }
1807
0
}
1808
1809
bool CU::addAffineMVPCandUnscaled(const CodingUnit& cu, const RefPicList refPicList, const int refIdx, const Position& pos, const MvpDir dir, AffineAMVPInfo &affiAMVPInfo)
1810
0
{
1811
0
  CodingStructure &cs = *cu.cs;
1812
0
  const CodingUnit* neibPU = NULL;
1813
0
  Position neibPos;
1814
1815
0
  switch (dir)
1816
0
  {
1817
0
  case MD_LEFT:
1818
0
    neibPos = pos.offset(-1, 0);
1819
0
    break;
1820
0
  case MD_ABOVE:
1821
0
    neibPos = pos.offset(0, -1);
1822
0
    break;
1823
0
  case MD_ABOVE_RIGHT:
1824
0
    neibPos = pos.offset(1, -1);
1825
0
    break;
1826
0
  case MD_BELOW_LEFT:
1827
0
    neibPos = pos.offset(-1, 1);
1828
0
    break;
1829
0
  case MD_ABOVE_LEFT:
1830
0
    neibPos = pos.offset(-1, -1);
1831
0
    break;
1832
0
  default:
1833
0
    break;
1834
0
  }
1835
1836
0
  neibPU = cs.getCURestricted(neibPos, cu, cu.chType);
1837
1838
0
  if (neibPU == NULL || !CU::isInter(*neibPU) || !neibPU->affine
1839
0
    || neibPU->mergeType != MRG_TYPE_DEFAULT_N
1840
0
    )
1841
0
  {
1842
0
    return false;
1843
0
  }
1844
1845
0
  Mv outputAffineMv[3];
1846
0
  const MotionInfo& neibMi = neibPU->getMotionInfo(neibPos);
1847
1848
0
  const int        currRefPOC = cs.slice->getRefPic(refPicList, refIdx)->getPOC();
1849
0
  const RefPicList refPicList2nd = (refPicList == REF_PIC_LIST_0) ? REF_PIC_LIST_1 : REF_PIC_LIST_0;
1850
1851
0
  for (int predictorSource = 0; predictorSource < 2; predictorSource++) // examine the indicated reference picture list, then if not available, examine the other list.
1852
0
  {
1853
0
    const RefPicList refPicListIndex = (predictorSource == 0) ? refPicList : refPicList2nd;
1854
0
    const int        neibRefIdx = neibMi.miRefIdx[refPicListIndex];
1855
1856
0
    if (((neibPU->interDir & (refPicListIndex + 1)) == 0) || cu.slice->getRefPOC(refPicListIndex, neibRefIdx) != currRefPOC)
1857
0
    {
1858
0
      continue;
1859
0
    }
1860
1861
0
    xInheritedAffineMv(cu, neibPU, refPicListIndex, outputAffineMv);
1862
0
    outputAffineMv[0].roundAffinePrecInternal2Amvr(cu.imv);
1863
0
    outputAffineMv[1].roundAffinePrecInternal2Amvr(cu.imv);
1864
0
    affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[0];
1865
0
    affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[1];
1866
0
    if (cu.affineType == AFFINEMODEL_6PARAM)
1867
0
    {
1868
0
      outputAffineMv[2].roundAffinePrecInternal2Amvr(cu.imv);
1869
0
      affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[2];
1870
0
    }
1871
0
    affiAMVPInfo.numCand++;
1872
0
    return true;
1873
0
  }
1874
1875
0
  return false;
1876
0
}
1877
1878
void CU::xInheritedAffineMv(const CodingUnit& cu, const CodingUnit* cuNeighbour, RefPicList refPicList, Mv rcMv[3])
1879
0
{
1880
0
  int posNeiX = cuNeighbour->Y().pos().x;
1881
0
  int posNeiY = cuNeighbour->Y().pos().y;
1882
0
  int posCurX = cu.Y().pos().x;
1883
0
  int posCurY = cu.Y().pos().y;
1884
1885
0
  int neiW = cuNeighbour->Y().width;
1886
0
  int curW = cu.Y().width;
1887
0
  int neiH = cuNeighbour->Y().height;
1888
0
  int curH = cu.Y().height;
1889
1890
0
  Mv mvLT, mvRT, mvLB;
1891
0
  mvLT = cuNeighbour->mv[refPicList][0];
1892
0
  mvRT = cuNeighbour->mv[refPicList][1];
1893
0
  mvLB = cuNeighbour->mv[refPicList][2];
1894
1895
0
  bool isTopCtuBoundary = false;
1896
0
  if ((posNeiY + neiH) % cu.cs->sps->CTUSize == 0 && (posNeiY + neiH) == posCurY)
1897
0
  {
1898
    // use bottom-left and bottom-right sub-block MVs for inheritance
1899
0
    const Position posRB = cuNeighbour->Y().bottomRight();
1900
0
    const Position posLB = cuNeighbour->Y().bottomLeft();
1901
0
    mvLT = cuNeighbour->getMotionInfo(posLB).mv[refPicList];
1902
0
    mvRT = cuNeighbour->getMotionInfo(posRB).mv[refPicList];
1903
0
    posNeiY += neiH;
1904
0
    isTopCtuBoundary = true;
1905
0
  }
1906
1907
0
  int shift = MAX_CU_DEPTH;
1908
0
  int iDMvHorX, iDMvHorY, iDMvVerX, iDMvVerY;
1909
1910
0
  iDMvHorX = (mvRT - mvLT).hor * (1<< (shift - Log2(neiW)));
1911
0
  iDMvHorY = (mvRT - mvLT).ver * (1<< (shift - Log2(neiW)));
1912
0
  if (cuNeighbour->affineType == AFFINEMODEL_6PARAM && !isTopCtuBoundary)
1913
0
  {
1914
0
    iDMvVerX = (mvLB - mvLT).hor * (1<< (shift - Log2(neiH)));
1915
0
    iDMvVerY = (mvLB - mvLT).ver * (1<< (shift - Log2(neiH)));
1916
0
  }
1917
0
  else
1918
0
  {
1919
0
    iDMvVerX = -iDMvHorY;
1920
0
    iDMvVerY = iDMvHorX;
1921
0
  }
1922
1923
0
  int iMvScaleHor = mvLT.hor * (1<< shift);
1924
0
  int iMvScaleVer = mvLT.ver * (1<< shift);
1925
0
  int horTmp, verTmp;
1926
1927
  // v0
1928
0
  horTmp = iMvScaleHor + iDMvHorX * (posCurX - posNeiX) + iDMvVerX * (posCurY - posNeiY);
1929
0
  verTmp = iMvScaleVer + iDMvHorY * (posCurX - posNeiX) + iDMvVerY * (posCurY - posNeiY);
1930
0
  roundAffineMv(horTmp, verTmp, shift);
1931
0
  rcMv[0].hor = horTmp;
1932
0
  rcMv[0].ver = verTmp;
1933
0
  rcMv[0].clipToStorageBitDepth();
1934
1935
  // v1
1936
0
  horTmp = iMvScaleHor + iDMvHorX * (posCurX + curW - posNeiX) + iDMvVerX * (posCurY - posNeiY);
1937
0
  verTmp = iMvScaleVer + iDMvHorY * (posCurX + curW - posNeiX) + iDMvVerY * (posCurY - posNeiY);
1938
0
  roundAffineMv(horTmp, verTmp, shift);
1939
0
  rcMv[1].hor = horTmp;
1940
0
  rcMv[1].ver = verTmp;
1941
0
  rcMv[1].clipToStorageBitDepth();
1942
1943
  // v2
1944
0
  if (cu.affineType == AFFINEMODEL_6PARAM)
1945
0
  {
1946
0
    horTmp = iMvScaleHor + iDMvHorX * (posCurX - posNeiX) + iDMvVerX * (posCurY + curH - posNeiY);
1947
0
    verTmp = iMvScaleVer + iDMvHorY * (posCurX - posNeiX) + iDMvVerY * (posCurY + curH - posNeiY);
1948
0
    roundAffineMv(horTmp, verTmp, shift);
1949
0
    rcMv[2].hor = horTmp;
1950
0
    rcMv[2].ver = verTmp;
1951
0
    rcMv[2].clipToStorageBitDepth();
1952
0
  }
1953
0
}
1954
1955
void CU::fillAffineMvpCand(CodingUnit& cu, const RefPicList refPicList, const int refIdx, AffineAMVPInfo &affiAMVPInfo)
1956
0
{
1957
0
  affiAMVPInfo.numCand = 0;
1958
1959
0
  if (refIdx < 0)
1960
0
  {
1961
0
    return;
1962
0
  }
1963
1964
  // insert inherited affine candidates
1965
0
  Mv outputAffineMv[3];
1966
0
  Position posLT = cu.Y().topLeft();
1967
0
  Position posRT = cu.Y().topRight();
1968
0
  Position posLB = cu.Y().bottomLeft();
1969
1970
  // check left neighbor
1971
0
  if (!addAffineMVPCandUnscaled(cu, refPicList, refIdx, posLB, MD_BELOW_LEFT, affiAMVPInfo))
1972
0
  {
1973
0
    addAffineMVPCandUnscaled(cu, refPicList, refIdx, posLB, MD_LEFT, affiAMVPInfo);
1974
0
  }
1975
1976
  // check above neighbor
1977
0
  if (!addAffineMVPCandUnscaled(cu, refPicList, refIdx, posRT, MD_ABOVE_RIGHT, affiAMVPInfo))
1978
0
  {
1979
0
    if (!addAffineMVPCandUnscaled(cu, refPicList, refIdx, posRT, MD_ABOVE, affiAMVPInfo))
1980
0
    {
1981
0
      addAffineMVPCandUnscaled(cu, refPicList, refIdx, posLT, MD_ABOVE_LEFT, affiAMVPInfo);
1982
0
    }
1983
0
  }
1984
1985
0
  if (affiAMVPInfo.numCand >= AMVP_MAX_NUM_CANDS)
1986
0
  {
1987
0
    for (int i = 0; i < affiAMVPInfo.numCand; i++)
1988
0
    {
1989
0
      affiAMVPInfo.mvCandLT[i].roundAffinePrecInternal2Amvr(cu.imv);
1990
0
      affiAMVPInfo.mvCandRT[i].roundAffinePrecInternal2Amvr(cu.imv);
1991
0
      affiAMVPInfo.mvCandLB[i].roundAffinePrecInternal2Amvr(cu.imv);
1992
0
    }
1993
0
    return;
1994
0
  }
1995
1996
  // insert constructed affine candidates
1997
0
  int cornerMVPattern = 0;
1998
1999
  //-------------------  V0 (START) -------------------//
2000
0
  AMVPInfo amvpInfo0;
2001
0
  amvpInfo0.numCand = 0;
2002
2003
  // A->C: Above Left, Above, Left
2004
0
  addMVPCandUnscaled(cu, refPicList, refIdx, posLT, MD_ABOVE_LEFT, amvpInfo0);
2005
0
  if (amvpInfo0.numCand < 1)
2006
0
  {
2007
0
    addMVPCandUnscaled(cu, refPicList, refIdx, posLT, MD_ABOVE, amvpInfo0);
2008
0
  }
2009
0
  if (amvpInfo0.numCand < 1)
2010
0
  {
2011
0
    addMVPCandUnscaled(cu, refPicList, refIdx, posLT, MD_LEFT, amvpInfo0);
2012
0
  }
2013
0
  cornerMVPattern = cornerMVPattern | amvpInfo0.numCand;
2014
2015
  //-------------------  V1 (START) -------------------//
2016
0
  AMVPInfo amvpInfo1;
2017
0
  amvpInfo1.numCand = 0;
2018
2019
  // D->E: Above, Above Right
2020
0
  addMVPCandUnscaled(cu, refPicList, refIdx, posRT, MD_ABOVE, amvpInfo1);
2021
0
  if (amvpInfo1.numCand < 1)
2022
0
  {
2023
0
    addMVPCandUnscaled(cu, refPicList, refIdx, posRT, MD_ABOVE_RIGHT, amvpInfo1);
2024
0
  }
2025
0
  cornerMVPattern = cornerMVPattern | (amvpInfo1.numCand << 1);
2026
2027
  //-------------------  V2 (START) -------------------//
2028
0
  AMVPInfo amvpInfo2;
2029
0
  amvpInfo2.numCand = 0;
2030
2031
  // F->G: Left, Below Left
2032
0
  addMVPCandUnscaled(cu, refPicList, refIdx, posLB, MD_LEFT, amvpInfo2);
2033
0
  if (amvpInfo2.numCand < 1)
2034
0
  {
2035
0
    addMVPCandUnscaled(cu, refPicList, refIdx, posLB, MD_BELOW_LEFT, amvpInfo2);
2036
0
  }
2037
0
  cornerMVPattern = cornerMVPattern | (amvpInfo2.numCand << 2);
2038
2039
0
  outputAffineMv[0] = amvpInfo0.mvCand[0];
2040
0
  outputAffineMv[1] = amvpInfo1.mvCand[0];
2041
0
  outputAffineMv[2] = amvpInfo2.mvCand[0];
2042
2043
0
  outputAffineMv[0].roundAffinePrecInternal2Amvr(cu.imv);
2044
0
  outputAffineMv[1].roundAffinePrecInternal2Amvr(cu.imv);
2045
0
  outputAffineMv[2].roundAffinePrecInternal2Amvr(cu.imv);
2046
2047
0
  if (cornerMVPattern == 7 || (cornerMVPattern == 3 && cu.affineType == AFFINEMODEL_4PARAM))
2048
0
  {
2049
0
    affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[0];
2050
0
    affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[1];
2051
0
    affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[2];
2052
0
    affiAMVPInfo.numCand++;
2053
0
  }
2054
2055
0
  if (affiAMVPInfo.numCand < 2)
2056
0
  {
2057
    // check corner MVs
2058
0
    for (int i = 2; i >= 0 && affiAMVPInfo.numCand < AMVP_MAX_NUM_CANDS; i--)
2059
0
    {
2060
0
      if (cornerMVPattern & (1 << i)) // MV i exist
2061
0
      {
2062
0
        affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = outputAffineMv[i];
2063
0
        affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = outputAffineMv[i];
2064
0
        affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = outputAffineMv[i];
2065
0
        affiAMVPInfo.numCand++;
2066
0
      }
2067
0
    }
2068
2069
    // Get Temporal Motion Predictor
2070
0
    if (affiAMVPInfo.numCand < 2 && cu.cs->picHeader->enableTMVP)
2071
0
    {
2072
0
      const int refIdxCol = refIdx;
2073
2074
0
      Position posRB = cu.Y().bottomRight().offset(-3, -3);
2075
2076
0
      const PreCalcValues& pcv = *cu.cs->pcv;
2077
2078
0
      Position posC0;
2079
0
      bool C0Avail = false;
2080
0
      Position posC1 = cu.Y().center();
2081
0
      Mv cColMv;
2082
0
      bool boundaryCond = ((posRB.x + pcv.minCUSize) < pcv.lumaWidth) && ((posRB.y + pcv.minCUSize) < pcv.lumaHeight);
2083
0
      const SubPic& curSubPic = cu.cs->slice->pps->getSubPicFromPos(cu.lumaPos());
2084
0
      if (curSubPic.treatedAsPic)
2085
0
      {
2086
0
        boundaryCond = ((posRB.x + pcv.minCUSize) <= curSubPic.subPicRight &&
2087
0
          (posRB.y + pcv.minCUSize) <= curSubPic.subPicBottom);
2088
0
      }
2089
0
      if (boundaryCond)
2090
0
      {
2091
0
        int posYInCtu = posRB.y & pcv.maxCUSizeMask;
2092
0
        if (posYInCtu + 4 < pcv.maxCUSize)
2093
0
        {
2094
0
          posC0 = posRB.offset(4, 4);
2095
0
          C0Avail = true;
2096
0
        }
2097
0
      }
2098
0
      if ((C0Avail && getColocatedMVP(cu, refPicList, posC0, cColMv, refIdxCol)) || getColocatedMVP(cu, refPicList, posC1, cColMv, refIdxCol))
2099
0
      {
2100
0
        cColMv.roundAffinePrecInternal2Amvr(cu.imv);
2101
0
        affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand] = cColMv;
2102
0
        affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand] = cColMv;
2103
0
        affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand] = cColMv;
2104
0
        affiAMVPInfo.numCand++;
2105
0
      }
2106
0
    }
2107
2108
0
    if (affiAMVPInfo.numCand < 2)
2109
0
    {
2110
      // add zero MV
2111
0
      for (int i = affiAMVPInfo.numCand; i < AMVP_MAX_NUM_CANDS; i++)
2112
0
      {
2113
0
        affiAMVPInfo.mvCandLT[affiAMVPInfo.numCand].setZero();
2114
0
        affiAMVPInfo.mvCandRT[affiAMVPInfo.numCand].setZero();
2115
0
        affiAMVPInfo.mvCandLB[affiAMVPInfo.numCand].setZero();
2116
0
        affiAMVPInfo.numCand++;
2117
0
      }
2118
0
    }
2119
0
  }
2120
2121
0
  for (int i = 0; i < affiAMVPInfo.numCand; i++)
2122
0
  {
2123
0
    affiAMVPInfo.mvCandLT[i].roundAffinePrecInternal2Amvr(cu.imv);
2124
0
    affiAMVPInfo.mvCandRT[i].roundAffinePrecInternal2Amvr(cu.imv);
2125
0
    affiAMVPInfo.mvCandLB[i].roundAffinePrecInternal2Amvr(cu.imv);
2126
0
  }
2127
0
}
2128
2129
bool CU::addMVPCandUnscaled( const CodingUnit& cu, const RefPicList refPicList, const int iRefIdx, const Position& pos, const MvpDir dir, AMVPInfo &info )
2130
0
{
2131
0
        CodingStructure &cs    = *cu.cs;
2132
0
  const CodingUnit* neibPU = NULL;
2133
0
        Position neibPos;
2134
2135
0
  switch (dir)
2136
0
  {
2137
0
  case MD_LEFT:
2138
0
    neibPos = pos.offset( -1,  0 );
2139
0
    break;
2140
0
  case MD_ABOVE:
2141
0
    neibPos = pos.offset(  0, -1 );
2142
0
    break;
2143
0
  case MD_ABOVE_RIGHT:
2144
0
    neibPos = pos.offset(  1, -1 );
2145
0
    break;
2146
0
  case MD_BELOW_LEFT:
2147
0
    neibPos = pos.offset( -1,  1 );
2148
0
    break;
2149
0
  case MD_ABOVE_LEFT:
2150
0
    neibPos = pos.offset( -1, -1 );
2151
0
    break;
2152
0
  default:
2153
0
    break;
2154
0
  }
2155
2156
0
  neibPU = cs.getCURestricted( neibPos, cu, cu.chType );
2157
2158
0
  if( neibPU == NULL || !CU::isInter( *neibPU ) )
2159
0
  {
2160
0
    return false;
2161
0
  }
2162
2163
0
  const MotionInfo& neibMi        = neibPU->getMotionInfo( neibPos );
2164
2165
0
  const int        currRefPOC     = cs.slice->getRefPic( refPicList, iRefIdx )->getPOC();
2166
0
  const RefPicList refPicList2nd = ( refPicList == REF_PIC_LIST_0 ) ? REF_PIC_LIST_1 : REF_PIC_LIST_0;
2167
2168
0
  for( int predictorSource = 0; predictorSource < 2; predictorSource++ ) // examine the indicated reference picture list, then if not available, examine the other list.
2169
0
  {
2170
0
    const RefPicList refPicListIndex = ( predictorSource == 0 ) ? refPicList : refPicList2nd;
2171
0
    const int        neibRefIdx       = neibMi.miRefIdx[refPicListIndex];
2172
2173
0
    if( neibRefIdx >= 0 && currRefPOC == cs.slice->getRefPOC( refPicListIndex, neibRefIdx ) )
2174
0
    {
2175
0
      info.mvCand[info.numCand++] = neibMi.mv[refPicListIndex];
2176
0
      return true;
2177
0
    }
2178
0
  }
2179
2180
0
  return false;
2181
0
}
2182
2183
2184
void CU::addAMVPHMVPCand(const CodingUnit& cu, const RefPicList refPicList, const int currRefPOC, AMVPInfo &info)
2185
0
{
2186
0
  const Slice &slice = *(*cu.cs).slice;
2187
0
  auto& lut = CU::isIBC(cu) ? cu.cs->motionLut.lutIbc : cu.cs->motionLut.lut;
2188
0
  int num_avai_candInLUT = (int) lut.size();
2189
0
  int num_allowedCand = std::min(MAX_NUM_HMVP_AVMPCANDS, num_avai_candInLUT);
2190
0
  const RefPicList refPicList2nd = (refPicList == REF_PIC_LIST_0) ? REF_PIC_LIST_1 : REF_PIC_LIST_0;
2191
2192
0
  for (int mrgIdx = 1; mrgIdx <= num_allowedCand; mrgIdx++)
2193
0
  {
2194
0
    if (info.numCand >= AMVP_MAX_NUM_CANDS)
2195
0
    {
2196
0
      return;
2197
0
    }
2198
0
    const HPMVInfo& neibMi = lut[mrgIdx - 1];
2199
2200
0
    for (int predictorSource = 0; predictorSource < 2; predictorSource++)
2201
0
    {
2202
0
      const RefPicList refPicListIndex = (predictorSource == 0) ? refPicList : refPicList2nd;
2203
0
      const int        neibRefIdx = neibMi.mhRefIdx[refPicListIndex];
2204
2205
0
      if (neibRefIdx != MH_NOT_VALID && (CU::isIBC(cu) || (currRefPOC == slice.getRefPOC(refPicListIndex, neibRefIdx))))
2206
0
      {
2207
0
        Mv pmv = neibMi.mv[refPicListIndex];
2208
0
        pmv.roundTransPrecInternal2Amvr(cu.imv);
2209
2210
0
        info.mvCand[info.numCand++] = pmv;
2211
0
        if (info.numCand >= AMVP_MAX_NUM_CANDS)
2212
0
        {
2213
0
          return;
2214
0
        }
2215
0
      }
2216
0
    }
2217
0
  }
2218
0
}
2219
2220
bool CU::isBipredRestriction(const CodingUnit& cu)
2221
162k
{
2222
162k
  if(cu.lumaSize().width == 4 && cu.lumaSize().height ==4 )
2223
0
  {
2224
0
    return true;
2225
0
  }
2226
  /* disable bi-prediction for 4x8/8x4 */
2227
162k
  if ( cu.lumaSize().width + cu.lumaSize().height == 12 )
2228
0
  {
2229
0
    return true;
2230
0
  }
2231
162k
  return false;
2232
162k
}
2233
2234
void CU::getAffineControlPointCand(const CodingUnit& cu, MotionInfo mi[4], bool isAvailable[4], int verIdx[4], int8_t BcwIdx, int modelIdx, int verNum, AffineMergeCtx& affMrgType)
2235
0
{
2236
0
  int cuW = cu.Y().width;
2237
0
  int cuH = cu.Y().height;
2238
0
  int vx, vy;
2239
0
  int shift = MAX_CU_DEPTH;
2240
0
  int shiftHtoW = shift + Log2(cuW) - Log2(cuH);
2241
2242
  // motion info
2243
0
  Mv cMv[2][4];
2244
0
  int refIdx[2] = { -1, -1 };
2245
0
  int dir = 0;
2246
0
  EAffineModel curType = (verNum == 2) ? AFFINEMODEL_4PARAM : AFFINEMODEL_6PARAM;
2247
2248
0
  if (verNum == 2)
2249
0
  {
2250
0
    int idx0 = verIdx[0], idx1 = verIdx[1];
2251
0
    if (!isAvailable[idx0] || !isAvailable[idx1])
2252
0
    {
2253
0
      return;
2254
0
    }
2255
2256
0
    for (int l = 0; l < 2; l++)
2257
0
    {
2258
0
      if (mi[idx0].miRefIdx[l] != MI_NOT_VALID && mi[idx1].miRefIdx[l] != MI_NOT_VALID)
2259
0
      {
2260
        // check same refidx and different mv
2261
0
        if (mi[idx0].miRefIdx[l] == mi[idx1].miRefIdx[l])
2262
0
        {
2263
0
          dir |= (l + 1);
2264
0
          refIdx[l] = mi[idx0].miRefIdx[l];
2265
0
        }
2266
0
      }
2267
0
    }
2268
0
  }
2269
0
  else if (verNum == 3)
2270
0
  {
2271
0
    int idx0 = verIdx[0], idx1 = verIdx[1], idx2 = verIdx[2];
2272
0
    if (!isAvailable[idx0] || !isAvailable[idx1] || !isAvailable[idx2])
2273
0
    {
2274
0
      return;
2275
0
    }
2276
2277
0
    for (int l = 0; l < 2; l++)
2278
0
    {
2279
0
      if (mi[idx0].miRefIdx[l] != MI_NOT_VALID && mi[idx1].miRefIdx[l] != MI_NOT_VALID && mi[idx2].miRefIdx[l] != MI_NOT_VALID)
2280
0
      {
2281
        // check same refidx and different mv
2282
0
        if (mi[idx0].miRefIdx[l] == mi[idx1].miRefIdx[l] && mi[idx0].miRefIdx[l] == mi[idx2].miRefIdx[l])
2283
0
        {
2284
0
          dir |= (l + 1);
2285
0
          refIdx[l] = mi[idx0].miRefIdx[l];
2286
0
        }
2287
0
      }
2288
0
      }
2289
0
    }
2290
2291
0
  if (dir == 0)
2292
0
  {
2293
0
    return;
2294
0
  }
2295
2296
2297
0
  for (int l = 0; l < 2; l++)
2298
0
  {
2299
0
    if (dir & (l + 1))
2300
0
    {
2301
0
      for (int i = 0; i < verNum; i++)
2302
0
      {
2303
0
        cMv[l][verIdx[i]] = mi[verIdx[i]].mv[l];
2304
0
      }
2305
2306
      // convert to LT, RT[, [LB]]
2307
0
      switch (modelIdx)
2308
0
      {
2309
0
      case 0: // 0 : LT, RT, LB
2310
0
        break;
2311
2312
0
      case 1: // 1 : LT, RT, RB
2313
0
        cMv[l][2].hor = cMv[l][3].hor + cMv[l][0].hor - cMv[l][1].hor;
2314
0
        cMv[l][2].ver = cMv[l][3].ver + cMv[l][0].ver - cMv[l][1].ver;
2315
0
        cMv[l][2].clipToStorageBitDepth();
2316
0
        break;
2317
2318
0
      case 2: // 2 : LT, LB, RB
2319
0
        cMv[l][1].hor = cMv[l][3].hor + cMv[l][0].hor - cMv[l][2].hor;
2320
0
        cMv[l][1].ver = cMv[l][3].ver + cMv[l][0].ver - cMv[l][2].ver;
2321
0
        cMv[l][1].clipToStorageBitDepth();
2322
0
        break;
2323
2324
0
      case 3: // 3 : RT, LB, RB
2325
0
        cMv[l][0].hor = cMv[l][1].hor + cMv[l][2].hor - cMv[l][3].hor;
2326
0
        cMv[l][0].ver = cMv[l][1].ver + cMv[l][2].ver - cMv[l][3].ver;
2327
0
        cMv[l][0].clipToStorageBitDepth();
2328
0
        break;
2329
2330
0
      case 4: // 4 : LT, RT
2331
0
        break;
2332
2333
0
      case 5: // 5 : LT, LB
2334
0
        vx = (cMv[l][0].hor *(1<< shift)) + ((cMv[l][2].ver - cMv[l][0].ver) * (1<< shiftHtoW));
2335
0
        vy = (cMv[l][0].ver *(1<< shift)) - ((cMv[l][2].hor - cMv[l][0].hor) * (1<< shiftHtoW));
2336
0
        roundAffineMv(vx, vy, shift);
2337
0
        cMv[l][1].set(vx, vy);
2338
0
        cMv[l][1].clipToStorageBitDepth();
2339
0
        break;
2340
2341
0
      default:
2342
0
        CHECK(1, "Invalid model index!\n");
2343
0
        break;
2344
0
      }
2345
0
    }
2346
0
    else
2347
0
    {
2348
0
      for (int i = 0; i < 4; i++)
2349
0
      {
2350
0
        cMv[l][i].hor = 0;
2351
0
        cMv[l][i].ver = 0;
2352
0
      }
2353
0
    }
2354
0
  }
2355
2356
0
  for (int i = 0; i < 3; i++)
2357
0
  {
2358
0
    affMrgType.mvFieldNeighbours[affMrgType.numValidMergeCand][0][i].mv     = cMv[0][i];
2359
0
    affMrgType.mvFieldNeighbours[affMrgType.numValidMergeCand][0][i].refIdx = refIdx[0];
2360
2361
0
    affMrgType.mvFieldNeighbours[affMrgType.numValidMergeCand][1][i].mv     = cMv[1][i];
2362
0
    affMrgType.mvFieldNeighbours[affMrgType.numValidMergeCand][1][i].refIdx = refIdx[1];
2363
0
  }
2364
0
  affMrgType.interDirNeighbours [affMrgType.numValidMergeCand]              = dir;
2365
0
  affMrgType.affineType         [affMrgType.numValidMergeCand]              = curType;
2366
0
  affMrgType.BcwIdx             [affMrgType.numValidMergeCand]              = dir == 3 ? BcwIdx : BCW_DEFAULT;
2367
0
  affMrgType.numValidMergeCand++;
2368
2369
2370
0
  return;
2371
0
}
2372
2373
2374
bool CU::getInterMergeSbTMVPCand(const CodingUnit& cu, AffineMergeCtx& mrgCtx, const int count)
2375
0
{
2376
0
  const Slice   &slice = *cu.cs->slice;
2377
0
  const unsigned scale = 4 * std::max<int>(1, 4 * AMVP_DECIMATION_FACTOR / 4);
2378
0
  const unsigned mask = ~(scale - 1);
2379
2380
0
  const Picture *pColPic = slice.getRefPic(RefPicList(slice.isInterB() ? 1 - slice.colFromL0Flag : 0), slice.colRefIdx);
2381
0
  Mv cTMv;
2382
2383
0
  if (count)
2384
0
  {
2385
0
    if ((mrgCtx.interDirNeighbours[0] & (1 << REF_PIC_LIST_0)) && slice.getRefPic(REF_PIC_LIST_0, mrgCtx.mvFieldNeighbours[0][REF_PIC_LIST_0][0].refIdx) == pColPic )
2386
0
    {
2387
0
      cTMv = mrgCtx.mvFieldNeighbours[0][REF_PIC_LIST_0][0].mv;
2388
0
    }
2389
0
    else if (slice.isInterB() && (mrgCtx.interDirNeighbours[0] & (1 << REF_PIC_LIST_1)) && slice.getRefPic(REF_PIC_LIST_1, mrgCtx.mvFieldNeighbours[0][REF_PIC_LIST_1][0].refIdx) == pColPic )
2390
0
    {
2391
0
      cTMv = mrgCtx.mvFieldNeighbours[0][REF_PIC_LIST_1][0].mv;
2392
0
    }
2393
0
  }
2394
2395
  ///////////////////////////////////////////////////////////////////////
2396
  ////////          GET Initial Temporal Vector                  ////////
2397
  ///////////////////////////////////////////////////////////////////////
2398
0
  Mv cTempVector = cTMv;
2399
2400
  // compute the location of the current PU
2401
0
  Position puPos = cu.lumaPos();
2402
0
  Size puSize = cu.lumaSize();
2403
0
  int numPartLine = std::max(puSize.width >> ATMVP_SUB_BLOCK_SIZE, 1u);
2404
0
  int numPartCol = std::max(puSize.height >> ATMVP_SUB_BLOCK_SIZE, 1u);
2405
0
  int puHeight = numPartCol == 1 ? puSize.height : 1 << ATMVP_SUB_BLOCK_SIZE;
2406
0
  int puWidth = numPartLine == 1 ? puSize.width : 1 << ATMVP_SUB_BLOCK_SIZE;
2407
2408
0
  Mv cColMv;
2409
0
  int refIdx = 0;
2410
  // use coldir.
2411
0
  bool     bBSlice = slice.isInterB();
2412
2413
0
  Position centerPos;
2414
2415
0
  bool found = false;
2416
0
  cTempVector = cTMv;
2417
2418
0
  cTempVector.changePrecision(MV_PRECISION_SIXTEENTH, MV_PRECISION_INT);
2419
0
  int tempX = cTempVector.hor;
2420
0
  int tempY = cTempVector.ver;
2421
2422
0
  centerPos.x = puPos.x + (puSize.width >> 1) + tempX;
2423
0
  centerPos.y = puPos.y + (puSize.height >> 1) + tempY;
2424
2425
0
  clipColPos(centerPos.x, centerPos.y, cu);
2426
2427
0
  centerPos = Position{ PosType(centerPos.x & mask), PosType(centerPos.y & mask) };
2428
2429
  // derivation of center motion parameters from the collocated CU
2430
0
  const MotionInfo &mi = pColPic->cs->getMotionInfo(centerPos);
2431
2432
0
  if (mi.isInter())
2433
0
  {
2434
0
    mrgCtx.interDirNeighbours[0] = 0;
2435
2436
0
    for (unsigned currRefListId = 0; currRefListId < (bBSlice ? 2 : 1); currRefListId++)
2437
0
    {
2438
0
      RefPicList  currRefPicList = RefPicList(currRefListId);
2439
2440
0
      if (getColocatedMVP(cu, currRefPicList, centerPos, cColMv, refIdx, true))
2441
0
      {
2442
        // set as default, for further motion vector field spanning
2443
0
        mrgCtx.mvFieldNeighbours [0][currRefListId][0] . setMvField(cColMv, 0);
2444
0
        mrgCtx.interDirNeighbours[0]                  |= (1 << currRefListId);
2445
0
        mrgCtx.BcwIdx            [0]                   = BCW_DEFAULT;
2446
0
        found = true;
2447
0
      }
2448
0
      else
2449
0
      {
2450
0
        mrgCtx.mvFieldNeighbours [0][currRefListId][0] . setMvField(Mv(), NOT_VALID);
2451
0
        mrgCtx.interDirNeighbours[0]                  &= ~(1 << currRefListId);
2452
0
      }
2453
0
    }
2454
0
  }
2455
2456
0
  if (!found)
2457
0
  {
2458
0
    return false;
2459
0
  }
2460
2461
0
  int xOff = (puWidth >> 1) + tempX;
2462
0
  int yOff = (puHeight >> 1) + tempY;
2463
2464
0
  MotionBuf& mb = mrgCtx.subPuMvpMiBuf;
2465
2466
0
  const bool isBiPred = isBipredRestriction(cu);
2467
2468
0
  for (int y = puPos.y; y < puPos.y + puSize.height; y += puHeight)
2469
0
  {
2470
0
    for (int x = puPos.x; x < puPos.x + puSize.width; x += puWidth)
2471
0
    {
2472
0
      Position colPos{ x + xOff, y + yOff };
2473
2474
0
      clipColPos(colPos.x, colPos.y, cu);
2475
2476
0
      colPos = Position{ PosType(colPos.x & mask), PosType(colPos.y & mask) };
2477
2478
0
      const MotionInfo &colMi = pColPic->cs->getMotionInfo(colPos);
2479
2480
0
      MotionInfo mi;
2481
2482
0
      found = false;
2483
0
      if (colMi.isInter())
2484
0
      {
2485
0
        for (unsigned currRefListId = 0; currRefListId < (bBSlice ? 2 : 1); currRefListId++)
2486
0
        {
2487
0
          RefPicList currRefPicList = RefPicList(currRefListId);
2488
0
          if (getColocatedMVP(cu, currRefPicList, colPos, cColMv, refIdx, true))
2489
0
          {
2490
0
            mi.miRefIdx[currRefListId] = 0;
2491
0
            mi.mv[currRefListId] = cColMv;
2492
0
            found = true;
2493
0
          }
2494
0
        }
2495
0
      }
2496
0
      if (!found)
2497
0
      {
2498
0
        mi.mv[0]       = mrgCtx.mvFieldNeighbours[0][0][0].mv;
2499
0
        mi.mv[1]       = mrgCtx.mvFieldNeighbours[0][1][0].mv;
2500
0
        mi.miRefIdx[0] = mrgCtx.mvFieldNeighbours[0][0][0].refIdx;
2501
0
        mi.miRefIdx[1] = mrgCtx.mvFieldNeighbours[0][1][0].refIdx;
2502
0
      }
2503
2504
0
      if (isBiPred && mi.interDir() == 3)
2505
0
      {
2506
0
        mi.mv[1]       = Mv();
2507
0
        mi.miRefIdx[1] = MI_NOT_VALID;
2508
0
      }
2509
2510
0
      mb.subBuf(g_miScaling.scale(Position{ x, y } -cu.lumaPos()), g_miScaling.scale(Size(puWidth, puHeight))).fill(mi);
2511
0
    }
2512
0
  }
2513
2514
0
  return true;
2515
0
}
2516
2517
2518
const int getAvailableAffineNeighboursForLeftPredictor(const CodingUnit& cu, const CodingUnit* npu[])
2519
0
{
2520
0
  const Position posLB = cu.Y().bottomLeft();
2521
0
  int num = 0;
2522
0
  const unsigned plevel = cu.cs->sps->log2ParallelMergeLevelMinus2 + 2;
2523
2524
0
  const CodingUnit* puLeftBottom = cu.cs->getCURestricted(posLB.offset(-1, 1), cu, cu.chType);
2525
0
  if (puLeftBottom && puLeftBottom->affine
2526
0
    && puLeftBottom->mergeType == MRG_TYPE_DEFAULT_N
2527
0
    && CU::isDiffMER(cu.lumaPos(), posLB.offset(-1, 1), plevel)
2528
0
    )
2529
0
  {
2530
0
    npu[num++] = puLeftBottom;
2531
0
    return num;
2532
0
  }
2533
2534
0
  const CodingUnit* puLeft = cu.cs->getCURestricted(posLB.offset(-1, 0), cu, cu.chType);
2535
0
  if (puLeft && puLeft->affine
2536
0
    && puLeft->mergeType == MRG_TYPE_DEFAULT_N
2537
0
    && CU::isDiffMER(cu.lumaPos(), posLB.offset(-1, 0), plevel)
2538
0
    )
2539
0
  {
2540
0
    npu[num++] = puLeft;
2541
0
    return num;
2542
0
  }
2543
2544
0
  return num;
2545
0
}
2546
2547
const int getAvailableAffineNeighboursForAbovePredictor(const CodingUnit& cu, const CodingUnit* npu[], int numAffNeighLeft)
2548
0
{
2549
0
  const Position posLT = cu.Y().topLeft();
2550
0
  const Position posRT = cu.Y().topRight();
2551
0
  const unsigned plevel = cu.cs->sps->log2ParallelMergeLevelMinus2 + 2;
2552
0
  int num = numAffNeighLeft;
2553
2554
0
  const CodingUnit* puAboveRight = cu.cs->getCURestricted(posRT.offset(1, -1), cu, cu.chType);
2555
0
  if (puAboveRight && puAboveRight->affine
2556
0
    && puAboveRight->mergeType == MRG_TYPE_DEFAULT_N
2557
0
    && CU::isDiffMER(cu.lumaPos(), posRT.offset(1, -1), plevel)
2558
0
    )
2559
0
  {
2560
0
    npu[num++] = puAboveRight;
2561
0
    return num;
2562
0
  }
2563
2564
0
  const CodingUnit* puAbove = cu.cs->getCURestricted(posRT.offset(0, -1), cu, cu.chType);
2565
0
  if (puAbove && puAbove->affine
2566
0
    && puAbove->mergeType == MRG_TYPE_DEFAULT_N
2567
0
    && CU::isDiffMER(cu.lumaPos(), posRT.offset(0, -1), plevel)
2568
0
    )
2569
0
  {
2570
0
    npu[num++] = puAbove;
2571
0
    return num;
2572
0
  }
2573
2574
0
  const CodingUnit* puAboveLeft = cu.cs->getCURestricted(posLT.offset(-1, -1), cu, cu.chType);
2575
0
  if (puAboveLeft && puAboveLeft->affine
2576
0
    && puAboveLeft->mergeType == MRG_TYPE_DEFAULT_N
2577
0
    && CU::isDiffMER(cu.lumaPos(), posLT.offset(-1, -1), plevel)
2578
0
    )
2579
0
  {
2580
0
    npu[num++] = puAboveLeft;
2581
0
    return num;
2582
0
  }
2583
2584
0
  return num;
2585
0
}
2586
2587
void CU::getAffineMergeCand( CodingUnit& cu, AffineMergeCtx& affMrgCtx, const int mrgCandIdx)
2588
0
{
2589
0
  const CodingStructure &cs = *cu.cs;
2590
0
  const Slice &slice = *cu.cs->slice;
2591
0
  const uint32_t maxNumAffineMergeCand = slice.picHeader->maxNumAffineMergeCand;
2592
0
  const unsigned plevel = cu.cs->sps->log2ParallelMergeLevelMinus2 + 2;
2593
2594
0
  for (int i = 0; i < maxNumAffineMergeCand; i++)
2595
0
  {
2596
0
    for (int mvNum = 0; mvNum < 3; mvNum++)
2597
0
    {
2598
0
      affMrgCtx.mvFieldNeighbours[i][0][mvNum].setMvField(Mv(), -1);
2599
0
      affMrgCtx.mvFieldNeighbours[i][1][mvNum].setMvField(Mv(), -1);
2600
0
    }
2601
0
    affMrgCtx.interDirNeighbours[i] = 0;
2602
0
    affMrgCtx.affineType[i] = AFFINEMODEL_4PARAM;
2603
0
    affMrgCtx.mergeType[i] = MRG_TYPE_DEFAULT_N;
2604
0
    affMrgCtx.BcwIdx[i] = BCW_DEFAULT;
2605
0
  }
2606
2607
0
  affMrgCtx.numValidMergeCand = 0;
2608
0
  affMrgCtx.maxNumMergeCand = maxNumAffineMergeCand;
2609
0
  bool enableSbTMVP = slice.sps->SbtMvp && !(slice.poc == slice.getRefPic(REF_PIC_LIST_0, 0)->getPOC() && slice.isIRAP());
2610
0
  bool isAvailableSubPu = false;
2611
2612
0
  if (enableSbTMVP && slice.picHeader->enableTMVP)
2613
0
  {
2614
0
    CHECK(affMrgCtx.subPuMvpMiBuf.area() == 0 || !affMrgCtx.subPuMvpMiBuf.buf, "Buffer not initialized");
2615
0
    affMrgCtx.subPuMvpMiBuf.fill(MotionInfo());
2616
2617
0
    int pos = 0;
2618
    // Get spatial MV
2619
0
    const Position posCurLB = cu.Y().bottomLeft();
2620
0
    MotionInfo miLeft;
2621
2622
    //left
2623
0
    const CodingUnit* puLeft = cs.getCURestricted(posCurLB.offset(-1, 0), cu, cu.chType);
2624
0
    const bool isAvailableA1 = puLeft && isDiffMER(cu.lumaPos(), posCurLB.offset(-1, 0), plevel) && &cu != puLeft && CU::isInter(*puLeft);
2625
0
    if (isAvailableA1)
2626
0
    {
2627
0
      miLeft = puLeft->getMotionInfo(posCurLB.offset(-1, 0));
2628
      // get Inter Dir
2629
0
      affMrgCtx.interDirNeighbours[pos] = miLeft.interDir();
2630
2631
      // get Mv from Left
2632
0
      affMrgCtx.mvFieldNeighbours[pos][0][0].setMvField(miLeft.mv[0], miLeft.miRefIdx[0]);
2633
2634
0
      if (slice.isInterB())
2635
0
      {
2636
0
        affMrgCtx.mvFieldNeighbours[pos][1][0].setMvField(miLeft.mv[1], miLeft.miRefIdx[1]);
2637
0
      }
2638
0
      pos++;
2639
0
    }
2640
2641
0
    isAvailableSubPu = getInterMergeSbTMVPCand(cu, affMrgCtx, pos);
2642
2643
0
    if (isAvailableSubPu)
2644
0
    {
2645
0
      for (int mvNum = 1; mvNum < 3; mvNum++)
2646
0
      {
2647
0
        affMrgCtx.mvFieldNeighbours[affMrgCtx.numValidMergeCand][0][mvNum] = affMrgCtx.mvFieldNeighbours[pos][0][0];
2648
0
        affMrgCtx.mvFieldNeighbours[affMrgCtx.numValidMergeCand][1][mvNum] = affMrgCtx.mvFieldNeighbours[pos][1][0];
2649
0
      }
2650
2651
0
      affMrgCtx.affineType[affMrgCtx.numValidMergeCand] = AFFINE_MODEL_NUM;
2652
0
      affMrgCtx.mergeType[affMrgCtx.numValidMergeCand] = MRG_TYPE_SUBPU_ATMVP;
2653
2654
0
      affMrgCtx.numValidMergeCand++;
2655
2656
0
      if (affMrgCtx.numValidMergeCand == mrgCandIdx + 1)
2657
0
      {
2658
0
        return;
2659
0
      }
2660
2661
      // early termination
2662
0
      if (affMrgCtx.numValidMergeCand == maxNumAffineMergeCand)
2663
0
      {
2664
0
        return;
2665
0
      }
2666
0
    }
2667
0
  }
2668
2669
0
  if (slice.sps->Affine)
2670
0
  {
2671
    ///> Start: inherited affine candidates
2672
0
    const CodingUnit* npu[5];
2673
0
    int numAffNeighLeft = getAvailableAffineNeighboursForLeftPredictor(cu, npu);
2674
0
    int numAffNeigh = getAvailableAffineNeighboursForAbovePredictor(cu, npu, numAffNeighLeft);
2675
0
    for (int idx = 0; idx < numAffNeigh; idx++)
2676
0
    {
2677
      // derive Mv from Neigh affine PU
2678
0
      Mv cMv[2][3];
2679
0
      const CodingUnit* cuNeigh = npu[idx];
2680
0
      cu.affineType = cuNeigh->affineType;
2681
0
      if (cuNeigh->interDir != 2)
2682
0
      {
2683
0
        xInheritedAffineMv(cu, cuNeigh, REF_PIC_LIST_0, cMv[0]);
2684
0
      }
2685
0
      if (slice.isInterB())
2686
0
      {
2687
0
        if (cuNeigh->interDir != 1)
2688
0
        {
2689
0
          xInheritedAffineMv(cu, cuNeigh, REF_PIC_LIST_1, cMv[1]);
2690
0
        }
2691
0
      }
2692
2693
0
      for (int mvNum = 0; mvNum < 3; mvNum++)
2694
0
      {
2695
0
        affMrgCtx.mvFieldNeighbours[affMrgCtx.numValidMergeCand][0][mvNum] . setMvField(cMv[0][mvNum], cuNeigh->refIdx[0]);
2696
0
        affMrgCtx.mvFieldNeighbours[affMrgCtx.numValidMergeCand][1][mvNum] . setMvField(cMv[1][mvNum], cuNeigh->refIdx[1]);
2697
0
      }
2698
0
      affMrgCtx.interDirNeighbours [affMrgCtx.numValidMergeCand]           = cuNeigh->interDir;
2699
0
      affMrgCtx.affineType         [affMrgCtx.numValidMergeCand]           = EAffineModel( cuNeigh->affineType );
2700
0
      affMrgCtx.BcwIdx             [affMrgCtx.numValidMergeCand]           = cuNeigh->BcwIdx;
2701
2702
0
      if( affMrgCtx.numValidMergeCand == mrgCandIdx )
2703
0
      {
2704
0
        return;
2705
0
      }
2706
2707
      // early termination
2708
0
      affMrgCtx.numValidMergeCand++;
2709
0
      if (affMrgCtx.numValidMergeCand == maxNumAffineMergeCand)
2710
0
      {
2711
0
        return;
2712
0
      }
2713
0
    }
2714
    ///> End: inherited affine candidates
2715
2716
    ///> Start: Constructed affine candidates
2717
0
    {
2718
0
      MotionInfo mi[4];
2719
0
      bool isAvailable[4] = { false };
2720
2721
0
      int8_t neighBcw[2] = { BCW_DEFAULT, BCW_DEFAULT };
2722
      // control point: LT B2->B3->A2
2723
0
      const Position posLT[3] = { cu.Y().topLeft().offset(-1, -1), cu.Y().topLeft().offset(0, -1), cu.Y().topLeft().offset(-1, 0) };
2724
0
      for (int i = 0; i < 3; i++)
2725
0
      {
2726
0
        const Position pos = posLT[i];
2727
0
        const CodingUnit* cuNeigh = cs.getCURestricted(pos, cu, cu.chType);
2728
2729
0
        if (cuNeigh && CU::isInter(*cuNeigh) && CU::isDiffMER(cu.lumaPos(), pos, plevel))
2730
0
        {
2731
0
          isAvailable[0] = true;
2732
0
          mi[0] = cuNeigh->getMotionInfo(pos);
2733
0
          neighBcw[0] = cuNeigh->BcwIdx;
2734
0
          break;
2735
0
        }
2736
0
      }
2737
2738
      // control point: RT B1->B0
2739
0
      const Position posRT[2] = { cu.Y().topRight().offset(0, -1), cu.Y().topRight().offset(1, -1) };
2740
0
      for (int i = 0; i < 2; i++)
2741
0
      {
2742
0
        const Position pos = posRT[i];
2743
0
        const CodingUnit* cuNeigh = cs.getCURestricted(pos, cu, cu.chType);
2744
2745
0
        if (cuNeigh && CU::isInter(*cuNeigh) && CU::isDiffMER(cu.lumaPos(), pos, plevel))
2746
0
        {
2747
0
          isAvailable[1] = true;
2748
0
          mi[1] = cuNeigh->getMotionInfo(pos);
2749
0
          neighBcw[1] = cuNeigh->BcwIdx;
2750
0
          break;
2751
0
        }
2752
0
      }
2753
2754
      // control point: LB A1->A0
2755
0
      const Position posLB[2] = { cu.Y().bottomLeft().offset(-1, 0), cu.Y().bottomLeft().offset(-1, 1) };
2756
0
      for (int i = 0; i < 2; i++)
2757
0
      {
2758
0
        const Position pos = posLB[i];
2759
0
        const CodingUnit* cuNeigh = cs.getCURestricted(pos, cu, cu.chType);
2760
2761
0
        if (cuNeigh && CU::isInter(*cuNeigh) && CU::isDiffMER(cu.lumaPos(), pos, plevel))
2762
0
        {
2763
0
          isAvailable[2] = true;
2764
0
          mi[2] = cuNeigh->getMotionInfo(pos);
2765
0
          break;
2766
0
        }
2767
0
      }
2768
2769
      // control point: RB
2770
0
      if (slice.picHeader->enableTMVP)
2771
0
      {
2772
        //>> MTK colocated-RightBottom
2773
        // offset the pos to be sure to "point" to the same position the uiAbsPartIdx would've pointed to
2774
0
        Position posRB = cu.Y().bottomRight().offset(-3, -3);
2775
2776
0
        const PreCalcValues& pcv = *cs.pcv;
2777
0
        Position posC0;
2778
0
        bool C0Avail = false;
2779
2780
0
        bool boundaryCond = ((posRB.x + pcv.minCUSize) < pcv.lumaWidth) && ((posRB.y + pcv.minCUSize) < pcv.lumaHeight);
2781
0
        const SubPic& curSubPic = cu.cs->slice->pps->getSubPicFromPos(cu.lumaPos());
2782
0
        if (curSubPic.treatedAsPic)
2783
0
        {
2784
0
          boundaryCond = ((posRB.x + pcv.minCUSize) <= curSubPic.subPicRight &&
2785
0
            (posRB.y + pcv.minCUSize) <= curSubPic.subPicBottom);
2786
0
        }
2787
0
        if (boundaryCond)
2788
0
        {
2789
0
          int posYInCtu = posRB.y & pcv.maxCUSizeMask;
2790
0
          if (posYInCtu + 4 < pcv.maxCUSize)
2791
0
          {
2792
0
            posC0 = posRB.offset(4, 4);
2793
0
            C0Avail = true;
2794
0
          }
2795
0
        }
2796
2797
0
        Mv        cColMv;
2798
0
        int       refIdx = 0;
2799
0
        bool      bExistMV = C0Avail && getColocatedMVP(cu, REF_PIC_LIST_0, posC0, cColMv, refIdx);
2800
0
        if (bExistMV)
2801
0
        {
2802
0
          mi[3].mv[0]       = cColMv;
2803
0
          mi[3].miRefIdx[0] = refIdx;
2804
0
          isAvailable[3] = true;
2805
0
        }
2806
2807
0
        if (slice.isInterB())
2808
0
        {
2809
0
          bExistMV = C0Avail && getColocatedMVP(cu, REF_PIC_LIST_1, posC0, cColMv, refIdx);
2810
0
          if (bExistMV)
2811
0
          {
2812
0
            mi[3].mv[1]       = cColMv;
2813
0
            mi[3].miRefIdx[1] = refIdx;
2814
0
            isAvailable[3] = true;
2815
0
          }
2816
0
        }
2817
0
      }
2818
2819
      //-------------------  insert model  -------------------//
2820
0
      int order[6] = { 0, 1, 2, 3, 4, 5 };
2821
0
      int modelNum = 6;
2822
0
      int model[6][4] = {
2823
0
        { 0, 1, 2 },          // 0:  LT, RT, LB
2824
0
        { 0, 1, 3 },          // 1:  LT, RT, RB
2825
0
        { 0, 2, 3 },          // 2:  LT, LB, RB
2826
0
        { 1, 2, 3 },          // 3:  RT, LB, RB
2827
0
        { 0, 1 },             // 4:  LT, RT
2828
0
        { 0, 2 },             // 5:  LT, LB
2829
0
      };
2830
2831
0
      int verNum[6] = { 3, 3, 3, 3, 2, 2 };
2832
0
      int startIdx = cu.cs->sps->AffineType ? 0 : 4;
2833
0
      for (int idx = startIdx; idx < modelNum; idx++)
2834
0
      {
2835
0
        int modelIdx = order[idx];
2836
0
        getAffineControlPointCand(cu, mi, isAvailable, model[modelIdx], ((modelIdx == 3) ? neighBcw[1] : neighBcw[0]), modelIdx, verNum[modelIdx], affMrgCtx);
2837
0
        if (affMrgCtx.numValidMergeCand != 0 && affMrgCtx.numValidMergeCand - 1 == mrgCandIdx)
2838
0
        {
2839
0
          return;
2840
0
        }
2841
2842
        // early termination
2843
0
        if (affMrgCtx.numValidMergeCand == maxNumAffineMergeCand)
2844
0
        {
2845
0
          return;
2846
0
        }
2847
0
      }
2848
0
    }
2849
    ///> End: Constructed affine candidates
2850
0
  }
2851
2852
  ///> zero padding
2853
0
  int cnt = affMrgCtx.numValidMergeCand;
2854
0
  while (cnt < maxNumAffineMergeCand)
2855
0
  {
2856
0
    for (int mvNum = 0; mvNum < 3; mvNum++)
2857
0
    {
2858
0
      affMrgCtx.mvFieldNeighbours[cnt][0][mvNum].setMvField(Mv(0, 0), 0);
2859
0
    }
2860
0
    affMrgCtx.interDirNeighbours[cnt] = 1;
2861
2862
0
    if (slice.isInterB())
2863
0
    {
2864
0
      for (int mvNum = 0; mvNum < 3; mvNum++)
2865
0
      {
2866
0
        affMrgCtx.mvFieldNeighbours[cnt][1][mvNum].setMvField(Mv(0, 0), 0);
2867
0
      }
2868
0
      affMrgCtx.interDirNeighbours[cnt] = 3;
2869
0
    }
2870
0
    affMrgCtx.affineType[cnt] = AFFINEMODEL_4PARAM;
2871
2872
0
    if (cnt == mrgCandIdx)
2873
0
    {
2874
0
      return;
2875
0
    }
2876
0
    cnt++;
2877
0
    affMrgCtx.numValidMergeCand++;
2878
0
  }
2879
0
}
2880
2881
void CU::setAllAffineMvField(CodingUnit& cu, const MvField *mvField, RefPicList eRefList)
2882
0
{
2883
  // Set Mv
2884
0
  Mv mv[3];
2885
0
  for (int i = 0; i < 3; i++)
2886
0
  {
2887
0
    mv[i] = mvField[i].mv;
2888
0
  }
2889
0
  setAllAffineMv( cu, mv[ 0 ], mv[ 1 ], mv[ 2 ], eRefList );
2890
  
2891
  // Set RefIdx
2892
0
  CHECK(mvField[0].refIdx != mvField[1].refIdx || mvField[0].refIdx != mvField[2].refIdx, "Affine mv corners don't have the same refIdx.");
2893
0
  cu.refIdx[eRefList] = mvField[0].refIdx;
2894
0
}
2895
2896
void CU::setAllAffineMv(CodingUnit& cu, Mv affLT, Mv affRT, Mv affLB, RefPicList eRefList, bool clipCPMVs)
2897
0
{
2898
0
  int width = cu.Y().width;
2899
0
  int shift = MAX_CU_DEPTH;
2900
0
  bool SameMV = false;
2901
0
  if (affLT == affRT)
2902
0
  {
2903
0
    if (affRT == affLB)
2904
0
    {
2905
0
      SameMV = true;
2906
0
    }
2907
0
  }
2908
0
  if (clipCPMVs)
2909
0
  {
2910
0
    affLT.mvCliptoStorageBitDepth();
2911
0
    affRT.mvCliptoStorageBitDepth();
2912
0
    if (cu.affineType == AFFINEMODEL_6PARAM)
2913
0
    {
2914
0
      affLB.mvCliptoStorageBitDepth();
2915
0
    }
2916
0
  }
2917
2918
0
  int deltaMvHorX = 0;
2919
0
  int deltaMvHorY = 0;
2920
0
  int deltaMvVerX = 0;
2921
0
  int deltaMvVerY = 0;
2922
0
  if (!SameMV)
2923
0
  {
2924
0
    deltaMvHorX = (affRT - affLT).hor * (1<< (shift - Log2(width)));
2925
0
    deltaMvHorY = (affRT - affLT).ver * (1<< (shift - Log2(width)));
2926
0
    int height = cu.Y().height;
2927
0
    if (cu.affineType == AFFINEMODEL_6PARAM)
2928
0
    {
2929
0
      deltaMvVerX = (affLB - affLT).hor * (1<< (shift - Log2(height)));
2930
0
      deltaMvVerY = (affLB - affLT).ver * (1<< (shift - Log2(height)));
2931
0
    }
2932
0
    else
2933
0
    {
2934
0
      deltaMvVerX = -deltaMvHorY;
2935
0
      deltaMvVerY = deltaMvHorX;
2936
0
    }
2937
0
  }
2938
2939
0
  int mvScaleHor = affLT.hor * (1<< shift);
2940
0
  int mvScaleVer = affLT.ver * (1<< shift);
2941
0
  int blockWidth = AFFINE_MIN_BLOCK_SIZE;
2942
0
  int blockHeight = AFFINE_MIN_BLOCK_SIZE;
2943
0
  const int halfBW = blockWidth >> 1;
2944
0
  const int halfBH = blockHeight >> 1;
2945
0
  MotionBuf mb = cu.getMotionBuf();
2946
0
  int mvScaleTmpHor, mvScaleTmpVer;
2947
0
  const bool subblkMVSpreadOverLimit = InterPredInterpolation::isSubblockVectorSpreadOverLimit(deltaMvHorX, deltaMvHorY, deltaMvVerX, deltaMvVerY, cu.interDir);
2948
2949
0
  int h = cu.Y().height / blockHeight;
2950
0
  int w = cu.Y().width / blockWidth;
2951
0
  for (int y = 0; y < h; y++)
2952
0
  {
2953
0
    for (int x = 0; x < w; x++)
2954
0
    {
2955
0
      if (SameMV)
2956
0
      {
2957
0
        mvScaleTmpHor = mvScaleHor;
2958
0
        mvScaleTmpVer = mvScaleVer;
2959
0
      }
2960
0
      else
2961
0
      {
2962
0
        if (!subblkMVSpreadOverLimit)
2963
0
        {
2964
0
          mvScaleTmpHor = mvScaleHor + deltaMvHorX * (halfBW + x*blockWidth) + deltaMvVerX * (halfBH + y*blockHeight);
2965
0
          mvScaleTmpVer = mvScaleVer + deltaMvHorY * (halfBW + x*blockWidth) + deltaMvVerY * (halfBH + y*blockHeight);
2966
2967
0
        }
2968
0
        else
2969
0
        {
2970
0
          mvScaleTmpHor = mvScaleHor + deltaMvHorX * (cu.Y().width >> 1) + deltaMvVerX * (cu.Y().height >> 1);
2971
0
          mvScaleTmpVer = mvScaleVer + deltaMvHorY * (cu.Y().width >> 1) + deltaMvVerY * (cu.Y().height >> 1);
2972
0
        }
2973
0
      }
2974
0
      roundAffineMv(mvScaleTmpHor, mvScaleTmpVer, shift);
2975
0
      Mv curMv(mvScaleTmpHor, mvScaleTmpVer);
2976
0
      curMv.clipToStorageBitDepth();
2977
2978
0
      mb.at(x, y).mv[eRefList] = curMv;
2979
0
    }
2980
0
  }
2981
2982
0
  cu.mv[eRefList][0] = affLT;
2983
0
  cu.mv[eRefList][1] = affRT;
2984
0
  cu.mv[eRefList][2] = affLB;
2985
0
}
2986
2987
void clipColPos(int& posX, int& posY, const CodingUnit& cu)
2988
0
{
2989
0
  Position puPos = cu.lumaPos();
2990
0
  int log2CtuSize = cu.cs->pcv->maxCUSizeLog2;
2991
0
  int ctuX = ((puPos.x >> log2CtuSize) << log2CtuSize);
2992
0
  int ctuY = ((puPos.y >> log2CtuSize) << log2CtuSize);
2993
0
  int horMax;
2994
0
  const SubPic& curSubPic = cu.slice->pps->getSubPicFromPos(puPos);
2995
0
  if (curSubPic.treatedAsPic)
2996
0
  {
2997
0
    horMax = std::min((int)curSubPic.subPicRight, ctuX + (int)cu.cs->sps->CTUSize + 3);
2998
0
  }
2999
0
  else
3000
0
  {
3001
0
    horMax = std::min((int)cu.cs->pps->picWidthInLumaSamples - 1, ctuX + (int)cu.cs->sps->CTUSize + 3);
3002
0
  }
3003
0
  int horMin = std::max((int)0, ctuX);
3004
0
  int verMax = std::min((int)cu.cs->pps->picHeightInLumaSamples - 1, ctuY + (int)cu.cs->sps->CTUSize - 1);
3005
0
  int verMin = std::max((int)0, ctuY);
3006
3007
0
  posX = std::min(horMax, std::max(horMin, posX));
3008
0
  posY = std::min(verMax, std::max(verMin, posY));
3009
0
}
3010
3011
3012
void CU::spanMotionInfo( CodingUnit& cu, const AffineMergeCtx *mrgCtx )
3013
24.3k
{
3014
24.3k
  MotionBuf mb = cu.getMotionBuf();
3015
3016
24.3k
  if( !cu.mergeFlag || cu.mergeType == MRG_TYPE_DEFAULT_N || cu.mergeType == MRG_TYPE_IBC )
3017
24.3k
  {
3018
24.3k
    bool isIBC   = CU::isIBC( cu );
3019
24.3k
    bool isInter = !CU::isIntra( cu ) && !isIBC;
3020
3021
24.3k
    if( isInter || isIBC )
3022
24.3k
    {
3023
24.3k
      MotionInfo mi;
3024
3025
73.0k
      for( int i = 0; i < NUM_REF_PIC_LIST_01; i++ )
3026
48.6k
      {
3027
48.6k
        mi.mv[i]       = cu.mv[i][0];
3028
48.6k
        mi.miRefIdx[i] = isIBC ? MI_NOT_VALID : cu.refIdx[i];
3029
48.6k
      }
3030
3031
24.3k
      if( cu.affine )
3032
0
      {
3033
0
        for( int y = 0; y < mb.height; y++ )
3034
0
        {
3035
0
          for( int x = 0; x < mb.width; x++ )
3036
0
          {
3037
0
            MotionInfo& dest = mb.at( x, y );
3038
3039
0
            for( int i = 0; i < NUM_REF_PIC_LIST_01; i++ )
3040
0
            {
3041
0
              if( mi.miRefIdx[i] == MI_NOT_VALID )
3042
0
              {
3043
0
                dest.mv[i] = Mv();
3044
0
              }
3045
0
              dest.miRefIdx[i] = mi.miRefIdx[i];
3046
0
            }
3047
0
          }
3048
0
        }
3049
0
        return;
3050
0
      }
3051
24.3k
      else
3052
24.3k
      {
3053
24.3k
      }
3054
3055
24.3k
      mb.fill( mi );
3056
24.3k
    }
3057
24.3k
  }
3058
0
  else if( cu.mergeType == MRG_TYPE_SUBPU_ATMVP )
3059
0
  {
3060
0
    CHECK( !mrgCtx || mrgCtx->subPuMvpMiBuf.area() == 0 || !mrgCtx->subPuMvpMiBuf.buf, "Buffer not initialized" );
3061
0
    mb.copyFrom( mrgCtx->subPuMvpMiBuf );
3062
0
  }
3063
24.3k
}
3064
3065
bool CU::isBiPredFromDifferentDirEqDistPoc(const CodingUnit& cu)
3066
0
{
3067
0
  if( cu.refIdx[0] >= 0 && cu.refIdx[1] >= 0 )
3068
0
  {
3069
0
    if( cu.slice->getRefPic( REF_PIC_LIST_0, cu.refIdx[0] )->isLongTerm
3070
0
     || cu.slice->getRefPic( REF_PIC_LIST_1, cu.refIdx[1] )->isLongTerm )
3071
0
    {
3072
0
      return false;
3073
0
    }
3074
3075
0
    const int poc0 = cu.slice->getRefPOC( REF_PIC_LIST_0, cu.refIdx[0] );
3076
0
    const int poc1 = cu.slice->getRefPOC( REF_PIC_LIST_1, cu.refIdx[1] );
3077
0
    const int poc  = cu.slice->poc;
3078
3079
0
    return ( poc - poc0 ) == ( poc1 - poc );
3080
0
  }
3081
3082
0
  return false;
3083
0
}
3084
3085
void CU::restrictBiPredMergeCandsOne( CodingUnit &cu )
3086
162k
{
3087
162k
  if( CU::isBipredRestriction( cu ) )
3088
0
  {
3089
0
    if( cu.interDir == 3 )
3090
0
    {
3091
0
      cu.interDir  =  1;
3092
0
      cu.refIdx[1] = -1;
3093
0
      cu.mv[1][0]  = Mv( 0, 0 );
3094
0
      cu.BcwIdx    = BCW_DEFAULT;
3095
0
    }
3096
0
  }
3097
162k
}
3098
3099
void CU::getGeoMergeCandidates( const CodingUnit &cu, MergeCtx &geoMrgCtx )
3100
0
{
3101
0
  MergeCtx tmpMergeCtx;
3102
3103
0
  const Slice &  slice           = *cu.cs->slice;
3104
0
  const uint32_t maxNumMergeCand = slice.sps->maxNumMergeCand;
3105
3106
0
  geoMrgCtx.numValidMergeCand = 0;
3107
3108
0
  for( int32_t i = 0; i < GEO_MAX_NUM_UNI_CANDS; i++ )
3109
0
  {
3110
0
    geoMrgCtx.BcwIdx            [i]           = BCW_DEFAULT;
3111
0
    geoMrgCtx.interDirNeighbours[i]           = 0;
3112
0
    geoMrgCtx.mrgTypeNeighbours [i]           = MRG_TYPE_DEFAULT_N;
3113
0
    geoMrgCtx.mvFieldNeighbours [i][0].refIdx = NOT_VALID;
3114
0
    geoMrgCtx.mvFieldNeighbours [i][1].refIdx = NOT_VALID;
3115
0
    geoMrgCtx.mvFieldNeighbours [i][0].mv     = Mv();
3116
0
    geoMrgCtx.mvFieldNeighbours [i][1].mv     = Mv();
3117
0
    geoMrgCtx.useAltHpelIf      [i]           = false;
3118
0
  }
3119
3120
0
  CU::getInterMergeCandidates( cu, tmpMergeCtx, 0 );
3121
3122
0
  for( int32_t i = 0; i < maxNumMergeCand; i++ )
3123
0
  {
3124
0
    int parity = i & 1;
3125
3126
0
    if( tmpMergeCtx.interDirNeighbours[i] & ( 0x01 + parity ) )
3127
0
    {
3128
0
      geoMrgCtx.interDirNeighbours[geoMrgCtx.numValidMergeCand]                 = 1 + parity;
3129
0
      geoMrgCtx.mrgTypeNeighbours [geoMrgCtx.numValidMergeCand]                 = MRG_TYPE_DEFAULT_N;
3130
0
      geoMrgCtx.mvFieldNeighbours [geoMrgCtx.numValidMergeCand][!parity].mv     = Mv(0, 0);
3131
0
      geoMrgCtx.mvFieldNeighbours [geoMrgCtx.numValidMergeCand][ parity].mv     = tmpMergeCtx.mvFieldNeighbours[i][parity].mv;
3132
0
      geoMrgCtx.mvFieldNeighbours [geoMrgCtx.numValidMergeCand][!parity].refIdx = -1;
3133
0
      geoMrgCtx.mvFieldNeighbours [geoMrgCtx.numValidMergeCand][ parity].refIdx = tmpMergeCtx.mvFieldNeighbours[i][parity].refIdx;
3134
0
      geoMrgCtx.numValidMergeCand++;
3135
3136
0
      if (geoMrgCtx.numValidMergeCand == GEO_MAX_NUM_UNI_CANDS)
3137
0
      {
3138
0
        return;
3139
0
      }
3140
0
      continue;
3141
0
    }
3142
3143
0
    if( tmpMergeCtx.interDirNeighbours[i] & ( 0x02 - parity ) )
3144
0
    {
3145
0
      geoMrgCtx.interDirNeighbours[geoMrgCtx.numValidMergeCand]                 = 2 - parity;
3146
0
      geoMrgCtx.mrgTypeNeighbours [geoMrgCtx.numValidMergeCand]                 = MRG_TYPE_DEFAULT_N;
3147
0
      geoMrgCtx.mvFieldNeighbours [geoMrgCtx.numValidMergeCand][!parity].mv     = tmpMergeCtx.mvFieldNeighbours[i][!parity].mv;
3148
0
      geoMrgCtx.mvFieldNeighbours [geoMrgCtx.numValidMergeCand][ parity].mv     = Mv(0, 0);
3149
0
      geoMrgCtx.mvFieldNeighbours [geoMrgCtx.numValidMergeCand][!parity].refIdx = tmpMergeCtx.mvFieldNeighbours[i][!parity].refIdx;
3150
0
      geoMrgCtx.mvFieldNeighbours [geoMrgCtx.numValidMergeCand][ parity].refIdx = -1;
3151
0
      geoMrgCtx.numValidMergeCand++;
3152
3153
0
      if( geoMrgCtx.numValidMergeCand == GEO_MAX_NUM_UNI_CANDS )
3154
0
      {
3155
0
        return;
3156
0
      }
3157
0
    }
3158
0
  }
3159
0
}
3160
3161
void CU::spanGeoMotionInfo( CodingUnit &cu, const MergeCtx &geoMrgCtx, const uint8_t splitDir, const uint8_t candIdx0, const uint8_t candIdx1 )
3162
0
{
3163
0
  cu.geoSplitDir    = splitDir;
3164
0
  cu.geoMergeIdx[0] = candIdx0;
3165
0
  cu.geoMergeIdx[1] = candIdx1;
3166
0
  MotionBuf mb      = cu.getMotionBuf();
3167
3168
0
  MotionInfo biMv;
3169
3170
0
  if( geoMrgCtx.interDirNeighbours[ candIdx0 ] == 1 && geoMrgCtx.interDirNeighbours[ candIdx1 ] == 2 )
3171
0
  {
3172
0
    biMv.mv[0]       = geoMrgCtx.mvFieldNeighbours[candIdx0][0].mv;
3173
0
    biMv.mv[1]       = geoMrgCtx.mvFieldNeighbours[candIdx1][1].mv;
3174
0
    biMv.miRefIdx[0] = geoMrgCtx.mvFieldNeighbours[candIdx0][0].refIdx;
3175
0
    biMv.miRefIdx[1] = geoMrgCtx.mvFieldNeighbours[candIdx1][1].refIdx;
3176
0
  }
3177
0
  else if( geoMrgCtx.interDirNeighbours[ candIdx0 ] == 2 && geoMrgCtx.interDirNeighbours[ candIdx1 ] == 1 )
3178
0
  {
3179
0
    biMv.mv[0]       = geoMrgCtx.mvFieldNeighbours[candIdx1][0].mv;
3180
0
    biMv.mv[1]       = geoMrgCtx.mvFieldNeighbours[candIdx0][1].mv;
3181
0
    biMv.miRefIdx[0] = geoMrgCtx.mvFieldNeighbours[candIdx1][0].refIdx;
3182
0
    biMv.miRefIdx[1] = geoMrgCtx.mvFieldNeighbours[candIdx0][1].refIdx;
3183
0
  }
3184
0
  else if( geoMrgCtx.interDirNeighbours[ candIdx0 ] == 1 && geoMrgCtx.interDirNeighbours[ candIdx1 ] == 1 )
3185
0
  {
3186
0
    biMv.mv[0]       = geoMrgCtx.mvFieldNeighbours[candIdx1][0].mv;
3187
0
    biMv.mv[1]       = Mv(0, 0);
3188
0
    biMv.miRefIdx[0] = geoMrgCtx.mvFieldNeighbours[candIdx1][0].refIdx;
3189
0
    biMv.miRefIdx[1] = MI_NOT_VALID;
3190
0
  }
3191
0
  else if( geoMrgCtx.interDirNeighbours[ candIdx0 ] == 2 && geoMrgCtx.interDirNeighbours[ candIdx1 ] == 2 )
3192
0
  {
3193
0
    biMv.mv[0]       = Mv(0, 0);
3194
0
    biMv.mv[1]       = geoMrgCtx.mvFieldNeighbours[candIdx1][1].mv;
3195
0
    biMv.miRefIdx[0] = MI_NOT_VALID;
3196
0
    biMv.miRefIdx[1] = geoMrgCtx.mvFieldNeighbours[candIdx1][1].refIdx;
3197
0
  }
3198
3199
0
  int16_t angle       = g_GeoParams[splitDir][0];
3200
0
  int     tpmMask     = 0;
3201
0
  int     lookUpY     = 0, motionIdx = 0;
3202
0
  bool    isFlip      = angle >= 13 && angle <= 27;
3203
0
  int     distanceIdx = g_GeoParams[splitDir][1];
3204
0
  int     distanceX   = angle;
3205
0
  int     distanceY   = (distanceX + (GEO_NUM_ANGLES >> 2)) % GEO_NUM_ANGLES;
3206
0
  int     offsetX     = (-(int) cu.lwidth()) >> 1;
3207
0
  int     offsetY     = (-(int) cu.lheight()) >> 1;
3208
3209
0
  if( distanceIdx > 0 )
3210
0
  {
3211
0
    if( angle % 16 == 8 || ( angle % 16 != 0 && cu.lheight() >= cu.lwidth() ) )
3212
0
      offsetY += angle < 16 ? ( ( distanceIdx * cu.lheight() ) >> 3 ) : -( int ) ( ( distanceIdx * cu.lheight() ) >> 3 );
3213
0
    else
3214
0
      offsetX += angle < 16 ? ( ( distanceIdx * cu.lwidth() ) >> 3 ) : -( int ) ( ( distanceIdx * cu.lwidth() ) >> 3 );
3215
0
  }
3216
0
  for (int y = 0; y < mb.height; y++)
3217
0
  {
3218
0
    lookUpY = (2 * (4 * y + offsetY) + 5) * g_Dis[distanceY];
3219
0
    for (int x = 0; x < mb.width; x++)
3220
0
    {
3221
0
      motionIdx = (2 * (4 * x + offsetX) + 5) * g_Dis[distanceX] + lookUpY;
3222
0
      tpmMask   = abs(motionIdx) < 32 ? 2 : (motionIdx <= 0 ? (1 - isFlip) : isFlip);
3223
0
      if (tpmMask == 2)
3224
0
      {
3225
0
        mb.at( x, y ) = biMv;
3226
0
      }
3227
0
      else if (tpmMask == 0)
3228
0
      {
3229
0
        mb.at(x, y).miRefIdx[0] = geoMrgCtx.mvFieldNeighbours[candIdx0][0].refIdx;
3230
0
        mb.at(x, y).miRefIdx[1] = geoMrgCtx.mvFieldNeighbours[candIdx0][1].refIdx;
3231
0
        mb.at(x, y).mv[0]       = geoMrgCtx.mvFieldNeighbours[candIdx0][0].mv;
3232
0
        mb.at(x, y).mv[1]       = geoMrgCtx.mvFieldNeighbours[candIdx0][1].mv;
3233
0
      }
3234
0
      else
3235
0
      {
3236
0
        mb.at(x, y).miRefIdx[0] = geoMrgCtx.mvFieldNeighbours[candIdx1][0].refIdx;
3237
0
        mb.at(x, y).miRefIdx[1] = geoMrgCtx.mvFieldNeighbours[candIdx1][1].refIdx;
3238
0
        mb.at(x, y).mv[0]       = geoMrgCtx.mvFieldNeighbours[candIdx1][0].mv;
3239
0
        mb.at(x, y).mv[1]       = geoMrgCtx.mvFieldNeighbours[candIdx1][1].mv;
3240
0
      }
3241
0
    }
3242
0
  }
3243
0
}
3244
3245
void CU::resetMVDandMV2Int( CodingUnit& cu )
3246
0
{
3247
0
  if( !cu.mergeFlag )
3248
0
  {
3249
0
    if( cu.interDir != 2 /* PRED_L1 */ )
3250
0
    {
3251
0
      Mv mv        = cu.mv[0][0];
3252
0
      Mv mvPred;
3253
0
      AMVPInfo amvpInfo;
3254
0
      CU::fillMvpCand(cu, REF_PIC_LIST_0, cu.refIdx[0], amvpInfo);
3255
0
      cu.mvpNum[0] = amvpInfo.numCand;
3256
3257
0
      mvPred       = amvpInfo.mvCand[cu.mvpIdx[0]];
3258
0
      mv.roundTransPrecInternal2Amvr(cu.imv);
3259
0
      cu.mv[0][0]  = mv;
3260
0
      Mv mvDiff    = mv - mvPred;
3261
0
      cu.mvd[0][0] = mvDiff;
3262
0
    }
3263
0
    if( cu.interDir != 1 /* PRED_L0 */ )
3264
0
    {
3265
0
      Mv mv        = cu.mv[1][0];
3266
0
      Mv mvPred;
3267
0
      AMVPInfo amvpInfo;
3268
0
      CU::fillMvpCand(cu, REF_PIC_LIST_1, cu.refIdx[1], amvpInfo);
3269
0
      cu.mvpNum[1] = amvpInfo.numCand;
3270
3271
0
      mvPred       = amvpInfo.mvCand[cu.mvpIdx[1]];
3272
0
      mv.roundTransPrecInternal2Amvr(cu.imv);
3273
0
      Mv mvDiff    = mv - mvPred;
3274
3275
0
      if( cu.cs->slice->picHeader->mvdL1Zero && cu.interDir == 3 /* PRED_BI */ )
3276
0
      {
3277
0
        cu.mvd[1][0] = Mv();
3278
0
        mv = mvPred;
3279
0
      }
3280
0
      else
3281
0
      {
3282
0
        cu.mvd[1][0] = mvDiff;
3283
0
      }
3284
0
      cu.mv[1][0] = mv;
3285
0
    }
3286
3287
0
  }
3288
0
  else
3289
0
  {
3290
0
    MergeCtx mrgCtx;
3291
3292
0
    CU::getInterMergeCandidates ( cu, mrgCtx, 0 );
3293
0
    mrgCtx.setMergeInfo( cu, cu.mergeIdx );
3294
0
  }
3295
3296
0
  CU::spanMotionInfo( cu );
3297
0
}
3298
3299
bool CU::hasSubCUNonZeroMVd( const CodingUnit& cu )
3300
24.3k
{
3301
24.3k
  bool bNonZeroMvd = false;
3302
3303
24.3k
  if( ( !cu.mergeFlag ) && ( !cu.skip ) )
3304
24.3k
  {
3305
24.3k
    if( cu.interDir != 2 /* PRED_L1 */ )
3306
24.3k
    {
3307
24.3k
      bNonZeroMvd |= cu.mvd[REF_PIC_LIST_0][0].hor != 0;
3308
24.3k
      bNonZeroMvd |= cu.mvd[REF_PIC_LIST_0][0].ver != 0;
3309
24.3k
    }
3310
24.3k
    if( cu.interDir != 1 /* PRED_L0 */ )
3311
0
    {
3312
0
      if( !cu.cs->slice->picHeader->mvdL1Zero || cu.interDir != 3 /* PRED_BI */ )
3313
0
      {
3314
0
        bNonZeroMvd |= cu.mvd[REF_PIC_LIST_1][0].hor != 0;
3315
0
        bNonZeroMvd |= cu.mvd[REF_PIC_LIST_1][0].ver != 0;
3316
0
      }
3317
0
    }
3318
24.3k
  }
3319
3320
24.3k
  return bNonZeroMvd;
3321
24.3k
}
3322
3323
bool CU::hasSubCUNonZeroAffineMVd( const CodingUnit& cu )
3324
0
{
3325
0
  bool nonZeroAffineMvd = false;
3326
3327
0
  if ( !cu.affine || cu.mergeFlag )
3328
0
  {
3329
0
    return false;
3330
0
  }
3331
3332
0
  if ( ( !cu.mergeFlag ) && ( !cu.skip ) )
3333
0
  {
3334
0
    if ( cu.interDir != 2 /* PRED_L1 */ )
3335
0
    {
3336
0
      for ( int i = 0; i < ( cu.affineType == AFFINEMODEL_6PARAM ? 3 : 2 ); i++ )
3337
0
      {
3338
0
        nonZeroAffineMvd |= cu.mvd[REF_PIC_LIST_0][i].hor != 0;
3339
0
        nonZeroAffineMvd |= cu.mvd[REF_PIC_LIST_0][i].ver != 0;
3340
0
      }
3341
0
    }
3342
3343
0
    if ( cu.interDir != 1 /* PRED_L0 */ )
3344
0
    {
3345
0
      if ( !cu.cs->slice->picHeader->mvdL1Zero || cu.interDir != 3 /* PRED_BI */ )
3346
0
      {
3347
0
        for ( int i = 0; i < ( cu.affineType == AFFINEMODEL_6PARAM ? 3 : 2 ); i++ )
3348
0
        {
3349
0
          nonZeroAffineMvd |= cu.mvd[REF_PIC_LIST_1][i].hor != 0;
3350
0
          nonZeroAffineMvd |= cu.mvd[REF_PIC_LIST_1][i].ver != 0;
3351
0
        }
3352
0
      }
3353
0
    }
3354
0
  }
3355
3356
0
  return nonZeroAffineMvd;
3357
0
}
3358
3359
uint8_t CU::numSbtModeRdo( uint8_t sbtAllowed )
3360
0
{
3361
0
  uint8_t num = 0;
3362
0
  uint8_t sum = 0;
3363
0
  num = targetSbtAllowed( SBT_VER_HALF, sbtAllowed ) + targetSbtAllowed( SBT_HOR_HALF, sbtAllowed );
3364
0
  sum += std::min( SBT_NUM_RDO, ( num << 1 ) );
3365
0
  num = targetSbtAllowed( SBT_VER_QUAD, sbtAllowed ) + targetSbtAllowed( SBT_HOR_QUAD, sbtAllowed );
3366
0
  sum += std::min( SBT_NUM_RDO, ( num << 1 ) );
3367
0
  return sum;
3368
0
}
3369
3370
bool CU::isSbtMode( const uint8_t sbtInfo )
3371
0
{
3372
0
  uint8_t sbtIdx = getSbtIdx( sbtInfo );
3373
0
  return sbtIdx >= SBT_VER_HALF && sbtIdx <= SBT_HOR_QUAD;
3374
0
}
3375
3376
bool CU::isSameSbtSize( const uint8_t sbtInfo1, const uint8_t sbtInfo2 )
3377
0
{
3378
0
  uint8_t sbtIdx1 = getSbtIdxFromSbtMode( sbtInfo1 );
3379
0
  uint8_t sbtIdx2 = getSbtIdxFromSbtMode( sbtInfo2 );
3380
0
  if( sbtIdx1 == SBT_HOR_HALF || sbtIdx1 == SBT_VER_HALF )
3381
0
    return sbtIdx2 == SBT_HOR_HALF || sbtIdx2 == SBT_VER_HALF;
3382
0
  else if( sbtIdx1 == SBT_HOR_QUAD || sbtIdx1 == SBT_VER_QUAD )
3383
0
    return sbtIdx2 == SBT_HOR_QUAD || sbtIdx2 == SBT_VER_QUAD;
3384
0
  else
3385
0
    return false;
3386
0
}
3387
3388
PartSplit CU::getSbtTuSplit( const uint8_t sbtInfo ) 
3389
0
{
3390
0
  uint8_t sbtTuSplitType = CU::getSbtPos( sbtInfo );
3391
0
  switch( CU::getSbtIdx( sbtInfo ) )
3392
0
  {
3393
0
  case SBT_VER_HALF: sbtTuSplitType += SBT_VER_HALF_POS0_SPLIT; break;
3394
0
  case SBT_HOR_HALF: sbtTuSplitType += SBT_HOR_HALF_POS0_SPLIT; break;
3395
0
  case SBT_VER_QUAD: sbtTuSplitType += SBT_VER_QUAD_POS0_SPLIT; break;
3396
0
  case SBT_HOR_QUAD: sbtTuSplitType += SBT_HOR_QUAD_POS0_SPLIT; break;
3397
0
  default: assert( 0 );  break;
3398
0
  }
3399
3400
0
  assert( sbtTuSplitType <= SBT_HOR_QUAD_POS1_SPLIT && sbtTuSplitType >= SBT_VER_HALF_POS0_SPLIT );
3401
0
  return PartSplit(sbtTuSplitType);
3402
0
}
3403
3404
bool CU::isPredRegDiffFromTB(const CodingUnit &cu)
3405
206k
{
3406
206k
  return (cu.ispMode == VER_INTRA_SUBPARTITIONS && ((cu.blocks[0].width == 4 )|| ((cu.blocks[0].width == 8) && (cu.blocks[0].height > 4))));
3407
206k
}
3408
3409
bool CU::isFirstTBInPredReg(const CodingUnit& cu, const CompArea& area)
3410
20.7k
{
3411
20.7k
  return ((area.topLeft().x - cu.Y().topLeft().x) % PRED_REG_MIN_WIDTH == 0);
3412
20.7k
}
3413
3414
void CU::adjustPredArea(CompArea& area)
3415
0
{
3416
0
  area.width = std::max<int>(PRED_REG_MIN_WIDTH, area.width);
3417
0
}
3418
3419
bool CU::isBcwIdxCoded( const CodingUnit &cu )
3420
24.3k
{
3421
24.3k
  if( ! cu.cs->sps->BCW )
3422
24.3k
  {
3423
24.3k
    CHECK(cu.BcwIdx != BCW_DEFAULT, "Error: cu.BcwIdx != BCW_DEFAULT");
3424
24.3k
    return false;
3425
24.3k
  }
3426
3427
0
  if( cu.predMode == MODE_IBC || cu.predMode == MODE_INTRA || cu.slice->isInterP() || cu.interDir != 3 )
3428
0
  {
3429
0
    return false;
3430
0
  }
3431
3432
0
  if( cu.lwidth() * cu.lheight() < BCW_SIZE_CONSTRAINT )
3433
0
  {
3434
0
    return false;
3435
0
  }
3436
3437
0
  if( !cu.mergeFlag )
3438
0
  {
3439
0
    if( cu.interDir == 3 )
3440
0
    {
3441
0
      WPScalingParam *wp0;
3442
0
      WPScalingParam *wp1;
3443
0
      int refIdx0 = cu.refIdx[REF_PIC_LIST_0];
3444
0
      int refIdx1 = cu.refIdx[REF_PIC_LIST_1];
3445
3446
0
      cu.cs->slice->getWpScaling(REF_PIC_LIST_0, refIdx0, wp0);
3447
0
      cu.cs->slice->getWpScaling(REF_PIC_LIST_1, refIdx1, wp1);
3448
0
      if ((wp0[COMP_Y].presentFlag || wp0[COMP_Cb].presentFlag || wp0[COMP_Cr].presentFlag
3449
0
        || wp1[COMP_Y].presentFlag || wp1[COMP_Cb].presentFlag || wp1[COMP_Cr].presentFlag))
3450
0
      {
3451
0
        return false;
3452
0
      }
3453
0
      return true;
3454
0
    }
3455
0
  }
3456
3457
0
  return false;
3458
0
}
3459
3460
uint8_t CU::getValidBcwIdx( const CodingUnit &cu )
3461
0
{
3462
0
  if( cu.interDir == 3 && !cu.mergeFlag )
3463
0
  {
3464
0
    return cu.BcwIdx;
3465
0
  }
3466
0
  else if( cu.interDir == 3 && cu.mergeFlag && cu.mergeType == MRG_TYPE_DEFAULT_N )
3467
0
  {
3468
    // This is intended to do nothing here.
3469
0
  }
3470
0
  else
3471
0
  {
3472
0
    CHECK(cu.BcwIdx != BCW_DEFAULT, " cu.BcwIdx != BCW_DEFAULT ");
3473
0
  }
3474
3475
0
  return BCW_DEFAULT;
3476
0
}
3477
3478
void CU::setBcwIdx( CodingUnit &cu, uint8_t uh )
3479
0
{
3480
0
  int8_t uhCnt = 0;
3481
3482
0
  if( cu.interDir == 3 && !cu.mergeFlag )
3483
0
  {
3484
0
    cu.BcwIdx = uh;
3485
0
    ++uhCnt;
3486
0
  }
3487
0
  else if( cu.interDir == 3 && cu.mergeFlag && cu.mergeType == MRG_TYPE_DEFAULT_N )
3488
0
  {
3489
    // This is intended to do nothing here.
3490
0
  }
3491
0
  else
3492
0
  {
3493
0
    cu.BcwIdx = BCW_DEFAULT;
3494
0
  }
3495
3496
0
  CHECK(uhCnt <= 0, " uhCnt <= 0 ");
3497
0
}
3498
3499
bool CU::bdpcmAllowed( const CodingUnit& cu, const ComponentID compID )
3500
760k
{
3501
760k
  SizeType transformSkipMaxSize = 1 << cu.cs->sps->log2MaxTransformSkipBlockSize;
3502
3503
760k
  const Size& blkSize = isLuma(compID) ? cu.lumaSize() : cu.chromaSize();
3504
760k
  bool bdpcmAllowed = cu.cs->sps->BDPCM;
3505
760k
       bdpcmAllowed &= CU::isIntra( cu );
3506
760k
       bdpcmAllowed &= (blkSize.width <= transformSkipMaxSize && blkSize.height <= transformSkipMaxSize);
3507
760k
  return bdpcmAllowed;
3508
760k
}
3509
3510
bool CU::isMTSAllowed(const CodingUnit &cu, const ComponentID compID)
3511
216k
{
3512
216k
  SizeType tsMaxSize = 1 << cu.cs->sps->log2MaxTransformSkipBlockSize;
3513
216k
  const int maxSize  = CU::isIntra( cu ) ? MTS_INTRA_MAX_CU_SIZE : MTS_INTER_MAX_CU_SIZE;
3514
216k
  const int cuWidth  = cu.blocks[0].lumaSize().width;
3515
216k
  const int cuHeight = cu.blocks[0].lumaSize().height;
3516
216k
  bool mtsAllowed    = cu.chType == CH_L && compID == COMP_Y;
3517
3518
216k
  mtsAllowed &= CU::isIntra( cu ) ? cu.cs->sps->MTSIntra : cu.cs->sps->MTSInter && CU::isInter( cu );
3519
216k
  mtsAllowed &= cuWidth <= maxSize && cuHeight <= maxSize;
3520
216k
  mtsAllowed &= !cu.ispMode;
3521
216k
  mtsAllowed &= !cu.sbtInfo;
3522
216k
  mtsAllowed &= !(cu.bdpcmM[CH_L] && cuWidth <= tsMaxSize && cuHeight <= tsMaxSize);
3523
216k
  return mtsAllowed;
3524
216k
}
3525
3526
bool CU::isMvInRangeFPP( const int yB, const int nH, const int yMv, const int ifpLines, const PreCalcValues& pcv, const int chromaShift, const int mvPrecShift )
3527
0
{
3528
  //const int dctifMarginVerBot = 4 >> yCompScale;
3529
0
  const int ctuLogScale = pcv.maxCUSizeLog2 - chromaShift;
3530
0
  const int yBMax       = ( pcv.heightInCtus - 1 - ifpLines ) << ctuLogScale;
3531
0
  const int yRefMax     = ( ( ( yB >> ctuLogScale ) + ifpLines + 1 ) << ctuLogScale ) - 1;
3532
0
  if( yB < yBMax && ( yB + nH + ( 4 >> chromaShift ) + (yMv >> (mvPrecShift + chromaShift) ) - 1 > yRefMax ) )
3533
0
    return false;
3534
0
  return true;
3535
0
}
3536
3537
bool CU::isMotionBufInRangeFPP( const CodingUnit &cu, const int ifpLines )
3538
0
{
3539
0
  const CMotionBuf mb = cu.getMotionBuf();
3540
0
  const ComponentID compID = COMP_Y;
3541
0
  const int mvPrecShift = MV_FRACTIONAL_BITS_INTERNAL;
3542
3543
0
  const int yCompScale = getComponentScaleY(compID, cu.chromaFormat);
3544
0
  const int maxCUSizeShift = cu.cs->pcv->maxCUSizeLog2 - yCompScale;
3545
0
  const int dctifMarginVerBot = 4 >> yCompScale;
3546
0
  const int curCtuRow = cu.block(compID).y >> maxCUSizeShift;
3547
0
  const int cuBottom = cu.block(compID).y + cu.block(compID).height - 1;
3548
3549
  // checking only bottom line of motion buffer
3550
0
  for( int y =  0; y < mb.height; y++ )
3551
0
  {
3552
0
    for( int x = 0; x < mb.width; x++ )
3553
0
    {
3554
0
      const MotionInfo& mi = mb.at( x, y );
3555
0
      for( int i = 0; i < NUM_REF_PIC_LIST_01; i++ )
3556
0
      {
3557
0
        if( mi.miRefIdx[i] != MI_NOT_VALID )
3558
0
        {
3559
0
          const Mv& mv = mi.mv[i];
3560
0
          const int refMaxPosY = cuBottom + dctifMarginVerBot + (mv.ver >> mvPrecShift);
3561
0
          const int refCtuRow = std::min( (int)((refMaxPosY > 0) ? refMaxPosY >> maxCUSizeShift: -1), (int)(cu.cs->pcv->heightInCtus - 1));
3562
0
          if( refCtuRow > ( curCtuRow + ifpLines ) )
3563
0
            return false;
3564
0
        }
3565
0
      }
3566
0
    }
3567
0
  }
3568
0
  return true;
3569
0
}
3570
3571
// TU tools
3572
3573
bool TU::getCbf( const TransformUnit& tu, const ComponentID compID )
3574
9.19M
{
3575
9.19M
  return getCbfAtDepth( tu, compID, tu.depth );
3576
9.19M
}
3577
3578
bool TU::getCbfAtDepth(const TransformUnit& tu, const ComponentID compID, const unsigned depth)
3579
12.2M
{
3580
12.2M
  if( !tu.blocks[compID].valid() )
3581
12.2M
    CHECK( tu.cbf[compID] != 0, "cbf must be 0 if the component is not available" );
3582
12.2M
  return ((tu.cbf[compID] >> depth) & 1) == 1;
3583
12.2M
}
3584
3585
void TU::setCbfAtDepth(TransformUnit& tu, const ComponentID compID, const unsigned depth, const bool cbf)
3586
2.69M
{
3587
  // first clear the CBF at the depth
3588
2.69M
  tu.cbf[compID] &= ~(1  << depth);
3589
  // then set the CBF
3590
2.69M
  tu.cbf[compID] |= ((cbf ? 1 : 0) << depth);
3591
2.69M
}
3592
3593
bool TU::isTSAllowed(const TransformUnit &tu, const ComponentID compID)
3594
2.92M
{
3595
2.92M
  const int maxSize = tu.cs->sps->log2MaxTransformSkipBlockSize;
3596
3597
2.92M
  bool tsAllowed = tu.cs->sps->transformSkip;
3598
2.92M
  tsAllowed &= ( !tu.cu->ispMode || !isLuma(compID) );
3599
2.92M
  SizeType transformSkipMaxSize = 1 << maxSize;
3600
2.92M
  tsAllowed &= !(tu.cu->bdpcmM[toChannelType(compID)]);
3601
2.92M
  tsAllowed &= tu.blocks[compID].width <= transformSkipMaxSize && tu.blocks[compID].height <= transformSkipMaxSize;
3602
2.92M
  tsAllowed &= !tu.cu->sbtInfo;
3603
3604
2.92M
  return tsAllowed;
3605
2.92M
}
3606
3607
int TU::getICTMode( const TransformUnit& tu, int jointCbCr )
3608
8.35M
{
3609
8.35M
  if( jointCbCr < 0 )
3610
7.21M
  {
3611
7.21M
    jointCbCr = tu.jointCbCr;
3612
7.21M
  }
3613
8.35M
  return g_ictModes[ tu.cs->picHeader->jointCbCrSign ][ jointCbCr ];
3614
8.35M
}
3615
3616
bool TU::needsSqrt2Scale( const TransformUnit& tu, const ComponentID compID )
3617
3.10M
{
3618
3.10M
  const Size& size=tu.blocks[compID];
3619
3.10M
  const bool isTransformSkip = tu.mtsIdx[compID] == MTS_SKIP;
3620
3.10M
  return (!isTransformSkip) && (((Log2(size.width * size.height)) & 1) == 1);
3621
3.10M
}
3622
3623
TransformUnit* TU::getPrevTU( const TransformUnit& tu, const ComponentID compID )
3624
27.1k
{
3625
27.1k
  TransformUnit* prevTU = tu.prev;
3626
3627
27.1k
  if( prevTU != nullptr && ( prevTU->cu != tu.cu || !prevTU->blocks[compID].valid() ) )
3628
0
  {
3629
0
    prevTU = nullptr;
3630
0
  }
3631
3632
27.1k
  return prevTU;
3633
27.1k
}
3634
3635
bool TU::getPrevTuCbfAtDepth( const TransformUnit& currentTu, const ComponentID compID, const int trDepth )
3636
27.1k
{
3637
27.1k
  const TransformUnit* prevTU = getPrevTU( currentTu, compID );
3638
27.1k
  return ( prevTU != nullptr ) ? TU::getCbfAtDepth( *prevTU, compID, trDepth ) : false;
3639
27.1k
}
3640
3641
3642
// other tools
3643
3644
uint32_t getCtuAddr( const Position& pos, const PreCalcValues& pcv )
3645
444k
{
3646
444k
  return ( pos.x >> pcv.maxCUSizeLog2 ) + ( pos.y >> pcv.maxCUSizeLog2 ) * pcv.widthInCtus;
3647
444k
}
3648
3649
uint32_t getCtuAddrFromCtuSize( const Position& pos, const unsigned maxCUSizeLog2, const unsigned widthInCtus )
3650
0
{
3651
0
  return ( pos.x >> maxCUSizeLog2 ) + ( pos.y >> maxCUSizeLog2 ) * widthInCtus;
3652
0
}
3653
3654
int getNumModesMip(const Size& block)
3655
339k
{
3656
339k
  switch( getMipSizeId(block) )
3657
339k
  {
3658
0
  case 0: return 16;
3659
7.23k
  case 1: return  8;
3660
332k
  case 2: return  6;
3661
0
  default: THROW( "Invalid mipSizeId" );
3662
339k
  }
3663
339k
}
3664
3665
int getMipSizeId(const Size& block)
3666
385k
{
3667
385k
  if( block.width == 4 && block.height == 4 )
3668
0
  {
3669
0
    return 0;
3670
0
  }
3671
385k
  else if( block.width == 4 || block.height == 4 || (block.width == 8 && block.height == 8) )
3672
7.63k
  {
3673
7.63k
    return 1;
3674
7.63k
  }
3675
378k
  else
3676
378k
  {
3677
378k
    return 2;
3678
378k
  }
3679
385k
}
3680
3681
bool allowLfnstWithMip(const Size& block)
3682
58.8k
{
3683
58.8k
  if (block.width >= 16 && block.height >= 16)
3684
54.5k
  {
3685
54.5k
    return true;
3686
54.5k
  }
3687
4.24k
  return false;
3688
58.8k
}
3689
3690
bool refPicCtuLineReady( const Slice& slice, const int refCtuRow, const PreCalcValues& pcv )
3691
0
{
3692
0
  const int checkRow = std::min( refCtuRow, (int)( pcv.heightInCtus ) - 1  );
3693
0
  for (int refList = 0; refList < NUM_REF_PIC_LIST_01; refList++)
3694
0
  {
3695
0
    int numOfActiveRef = slice.numRefIdx[refList];
3696
0
    for (int i = 0; i < numOfActiveRef; i++)
3697
0
    {
3698
      // NOTE: one additional tile column signals finished CTU row
3699
0
      if (slice.refPicList[refList][i]->m_tileColsDone->at( checkRow ) < (slice.pps->numTileCols + 1) )
3700
0
      {
3701
0
        return false;
3702
0
      }
3703
0
    }
3704
0
  }
3705
0
  return true;
3706
0
}
3707
3708
} // namespace vvenc
3709
3710
//! \}
3711