Coverage Report

Created: 2026-07-16 06:32

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.2M
{
69
11.2M
  return cs.slice->isIntra() && !cs.pcv->ISingleTree;
70
11.2M
}
71
72
UnitArea CS::getArea( const CodingStructure &cs, const UnitArea& area, const ChannelType chType, const TreeType treeType )
73
601k
{
74
18.4E
  return isDualITree( cs ) || treeType != TREE_D ? area.singleChan( chType ) : area;
75
601k
}
76
77
int CS::signalModeCons( const CodingStructure &cs, const UnitArea &currArea, const PartSplit split, const ModeType modeTypeParent )
78
436k
{
79
436k
  const ChromaFormat chromaFormat = currArea.chromaFormat;
80
81
436k
  if( CS::isDualITree( cs ) || modeTypeParent != MODE_TYPE_ALL || chromaFormat == CHROMA_444 || chromaFormat == CHROMA_400 )
82
436k
    return LDT_MODE_TYPE_INHERIT;
83
84
18.4E
  int minLumaArea = currArea.lumaSize().area();
85
18.4E
  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
18.4E
  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
18.4E
  int minChromaBlock = minLumaArea >> ( getChannelTypeScaleX( CH_C, chromaFormat ) + getChannelTypeScaleY( CH_C, chromaFormat ) );
95
18.4E
  bool is2xNChroma   = ( currArea.chromaSize().width == 4 && split == CU_VERT_SPLIT ) || ( currArea.chromaSize().width == 8 && split == CU_TRIV_SPLIT );
96
18.4E
  return minChromaBlock >= 16 && !is2xNChroma ? LDT_MODE_TYPE_INHERIT
97
18.4E
                                              : ( ( minLumaArea < 32 ) || cs.slice->isIntra() ) ? LDT_MODE_TYPE_INFER
98
18.4E
                                                                                                : LDT_MODE_TYPE_SIGNAL;
99
436k
}
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
3.78k
{
145
3.78k
  MotionBuf   mb     = cs.getMotionBuf();
146
3.78k
  MotionInfo* orgPtr = mb.buf;
147
148
3.78k
  const int xPos = ctuX << cs.pcv->maxCUSizeLog2;
149
3.78k
  const int yPos = ctuY << cs.pcv->maxCUSizeLog2;
150
  
151
  // first CU in CTU
152
3.78k
  const CodingUnit *ptrCU = cs.getCU( Position( xPos, yPos ), CH_L, TREE_D );
153
43.3k
  while( ptrCU )
154
39.5k
  {
155
39.5k
    const CodingUnit& cu = *ptrCU;
156
    
157
39.5k
    if( isLuma( cu.chType ) && cu.mvdL0SubPu && CU::checkDMVRCondition( cu ) )
158
0
    {
159
0
      refineCU( cu, mb, orgPtr );
160
0
    }
161
162
39.5k
    ptrCU = ptrCU->next;
163
39.5k
  }
164
3.78k
}
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
926k
{
179
926k
  bool allowCCLM = false;
180
181
926k
  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
926k
  else if( cu.slice->sps->CTUSize <= 32 ) //dual tree, CTUsize < 64
186
0
  {
187
0
    allowCCLM = true;
188
0
  }
189
926k
  else //dual tree, CTU size 64 or 128
190
926k
  {
191
926k
    int depthFor64x64Node = cu.slice->sps->CTUSize == 128 ? 1 : 0;
192
926k
    const PartSplit cuSplitTypeDepth1 = CU::getSplitAtDepth( cu, depthFor64x64Node );
193
926k
    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
926k
    if( cuSplitTypeDepth1 == CU_QUAD_SPLIT || (cuSplitTypeDepth1 == CU_HORZ_SPLIT && cuSplitTypeDepth2 == CU_VERT_SPLIT) )
197
555k
    {
198
555k
      if( cu.chromaFormat == CHROMA_420 )
199
555k
      {
200
555k
        CHECK( !(cu.blocks[COMP_Cb].width <= 16 && cu.blocks[COMP_Cb].height <= 16), "chroma cu size shall be <= 16x16 for YUV420 format" );
201
555k
      }
202
555k
      allowCCLM = true;
203
555k
    }
204
    //allow CCLM if 64x64 chroma tree node uses NS (No Split) and becomes a chroma CU containing 32x32 chroma blocks
205
371k
    else if( cuSplitTypeDepth1 == CU_DONT_SPLIT )
206
82.2k
    {
207
82.2k
      if( cu.chromaFormat == CHROMA_420 )
208
82.2k
      {
209
82.2k
        CHECK( !(cu.blocks[COMP_Cb].width == 32 && cu.blocks[COMP_Cb].height == 32), "chroma cu size shall be 32x32 for YUV420 format" );
210
82.2k
      }
211
82.2k
      allowCCLM = true;
212
82.2k
    }
213
    //allow CCLM if 64x32 chroma tree node uses NS and becomes a chroma CU containing 32x16 chroma blocks
214
289k
    else if( cuSplitTypeDepth1 == CU_HORZ_SPLIT && cuSplitTypeDepth2 == CU_DONT_SPLIT )
215
33.4k
    {
216
33.4k
      if( cu.chromaFormat == CHROMA_420 )
217
33.4k
      {
218
33.4k
        CHECK( !(cu.blocks[COMP_Cb].width == 32 && cu.blocks[COMP_Cb].height == 16), "chroma cu size shall be 32x16 for YUV420 format" );
219
33.4k
      }
220
33.4k
      allowCCLM = true;
221
33.4k
    }
222
223
    //further check luma conditions
224
926k
    if( allowCCLM )
225
670k
    {
226
      //disallow CCLM if luma 64x64 block uses BT or TT or NS with ISP
227
670k
      const Position lumaRefPos( cu.chromaPos().x << getComponentScaleX( COMP_Cb, cu.chromaFormat ), cu.chromaPos().y << getComponentScaleY( COMP_Cb, cu.chromaFormat ) );
228
670k
      const CodingUnit* colLumaCu = cu.cs->lumaCS->getCU( lumaRefPos, CH_L, TREE_D );
229
230
670k
      if( colLumaCu->lwidth() < 64 || colLumaCu->lheight() < 64 ) //further split at 64x64 luma node
231
330k
      {
232
330k
        const PartSplit cuSplitTypeDepth1Luma = CU::getSplitAtDepth( *colLumaCu, depthFor64x64Node );
233
330k
        CHECK( !(cuSplitTypeDepth1Luma >= CU_QUAD_SPLIT && cuSplitTypeDepth1Luma <= CU_TRIV_SPLIT), "split mode shall be BT, TT or QT" );
234
330k
        if( cuSplitTypeDepth1Luma != CU_QUAD_SPLIT )
235
0
        {
236
0
          allowCCLM = false;
237
0
        }
238
330k
      }
239
340k
      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
670k
    }
244
926k
  }
245
246
926k
  return allowCCLM;
247
926k
}
248
249
uint8_t CU::checkAllowedSbt(const CodingUnit& cu) 
250
133
{
251
133
  if( !cu.slice->sps->SBT || cu.predMode != MODE_INTER || cu.ciip || cu.predMode == MODE_IBC || cu.Y().maxDim() > cu.cs->sps->getMaxTbSize() )
252
133
  {
253
133
    return 0;
254
133
  }
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
133
}
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
79.6k
{
313
79.6k
  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
79.6k
  return ( ( ( ( cuAreaY.x + cuAreaY.width  ) & cu.cs->pcv->maxCUSizeMask ) == 0 || cuAreaY.x + cuAreaY.width  == cu.cs->pcv->lumaWidth  ) &&
316
35.1k
           ( ( ( cuAreaY.y + cuAreaY.height ) & cu.cs->pcv->maxCUSizeMask ) == 0 || cuAreaY.y + cuAreaY.height == cu.cs->pcv->lumaHeight ) );
317
79.6k
}
318
319
uint32_t CU::getCtuAddr( const CodingUnit &cu )
320
27.6k
{
321
27.6k
  return getCtuAddr( cu.blocks[cu.chType].lumaPos(), *cu.cs->pcv );
322
27.6k
}
323
324
int CU::predictQP( const CodingUnit& cu, const int prevQP )
325
27.6k
{
326
27.6k
  const ChannelType      chType   = cu.chType;
327
27.6k
  const CodingStructure& cs       = *cu.cs;
328
27.6k
  const Slice&           slice    = *cs.slice;
329
27.6k
  const bool             inCtuA   = ( cu.blocks[cu.chType].y & ( cs.pcv->maxCUSizeMask >> getChannelTypeScaleY( cu.chType, cu.chromaFormat ) ) );
330
27.6k
  const bool             inCtuL   = ( cu.blocks[cu.chType].x & ( cs.pcv->maxCUSizeMask >> getChannelTypeScaleX( cu.chType, cu.chromaFormat ) ) );
331
27.6k
  const CodingUnit*      cuAbove  =          cs.getCURestricted( cu.blocks[chType].pos().offset( 0, -1 ), cu, chType );
332
27.6k
  const CodingUnit*      cuLeft   = inCtuL ? cs.getCURestricted( cu.blocks[chType].pos().offset( -1, 0 ), cu, chType ) : nullptr;
333
  
334
27.6k
  const uint32_t ctuRsAddr       = getCtuAddr( cu );
335
27.6k
  const uint32_t ctuXPosInCtus   = ctuRsAddr % cs.pcv->widthInCtus;
336
27.6k
  const uint32_t tileXPosInCtus  = slice.pps->tileColBd[cs.pps->ctuToTileCol[ctuXPosInCtus]];
337
  
338
27.6k
  if( ctuXPosInCtus == tileXPosInCtus && !inCtuL && !inCtuA && cuAbove )
339
4.68k
  {
340
4.68k
    return cuAbove->qp;
341
4.68k
  }
342
22.9k
  else
343
22.9k
  {
344
22.9k
    const int a = inCtuA ? cuAbove->qp : prevQP;
345
22.9k
    const int b = inCtuL ? cuLeft->qp  : prevQP;
346
  
347
22.9k
    return ( a + b + 1 ) >> 1;
348
22.9k
  }
349
27.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.51M
{
371
2.51M
  if( depth >= cu.depth ) return CU_DONT_SPLIT;
372
373
2.03M
  const PartSplit cuSplitType = PartSplit( ( cu.splitSeries >> ( depth * SPLIT_DMULT ) ) & SPLIT_MASK );
374
375
2.03M
  if     ( cuSplitType == CU_QUAD_SPLIT    ) return CU_QUAD_SPLIT;
376
377
929k
  else if( cuSplitType == CU_HORZ_SPLIT    ) return CU_HORZ_SPLIT;
378
379
466k
  else if( cuSplitType == CU_VERT_SPLIT    ) return CU_VERT_SPLIT;
380
381
4.39k
  else if( cuSplitType == CU_TRIH_SPLIT    ) return CU_TRIH_SPLIT;
382
18
  else if( cuSplitType == CU_TRIV_SPLIT    ) return CU_TRIV_SPLIT;
383
18.4E
  else   { THROW( "Unknown split mode"    ); return CU_QUAD_SPLIT; }
384
2.03M
}
385
386
ModeType CU::getModeTypeAtDepth( const CodingUnit& cu, const unsigned depth )
387
76.6k
{
388
76.6k
  ModeType modeType = ModeType( (cu.modeTypeSeries >> (depth * 3)) & 0x07 );
389
76.6k
  CHECK( depth > cu.depth, " depth is wrong" );
390
76.6k
  return modeType;
391
76.6k
}
392
393
bool CU::divideTuInRows( const CodingUnit &cu )
394
37.5k
{
395
37.5k
  CHECK( cu.ispMode != HOR_INTRA_SUBPARTITIONS && cu.ispMode != VER_INTRA_SUBPARTITIONS, "Intra Subpartitions type not recognized!" );
396
37.5k
  return cu.ispMode == HOR_INTRA_SUBPARTITIONS ? true : false;
397
37.5k
}
398
399
400
PartSplit CU::getISPType( const CodingUnit &cu, const ComponentID compID )
401
79.9k
{
402
79.9k
  if( cu.ispMode && isLuma( compID ) )
403
37.5k
  {
404
37.5k
    const bool tuIsDividedInRows = CU::divideTuInRows( cu );
405
406
37.5k
    return tuIsDividedInRows ? TU_1D_HORZ_SPLIT : TU_1D_VERT_SPLIT;
407
37.5k
  }
408
42.3k
  return TU_NO_ISP;
409
79.9k
}
410
411
bool CU::isISPLast( const CodingUnit &cu, const CompArea& tuArea, const ComponentID compID )
412
32.0k
{
413
32.0k
  PartSplit partitionType = CU::getISPType( cu, compID );
414
415
32.0k
  Area originalArea = cu.blocks[compID];
416
32.0k
  switch( partitionType )
417
32.0k
  {
418
17.0k
    case TU_1D_HORZ_SPLIT:
419
17.0k
      return tuArea.y + tuArea.height == originalArea.y + originalArea.height;
420
14.9k
    case TU_1D_VERT_SPLIT:
421
14.9k
      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.0k
  }
426
32.0k
}
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
746k
{
435
746k
  const int width     = cu.blocks[compID].width;
436
746k
  const int height    = cu.blocks[compID].height;
437
746k
  const int maxTrSize = cu.cs->sps->getMaxTbSize();
438
746k
  return CU::canUseISP( width, height, maxTrSize );
439
746k
}
440
441
bool CU::canUseISP( const int width, const int height, const int maxTrSize )
442
772k
{
443
772k
  bool  notEnoughSamplesToSplit = ( Log2(width) + Log2(height) <= ( MIN_TB_LOG2_SIZEY << 1 ) );
444
772k
  bool  cuSizeLargerThanMaxTrSize = width > maxTrSize || height > maxTrSize;
445
772k
  if ( notEnoughSamplesToSplit || cuSizeLargerThanMaxTrSize )
446
0
  {
447
0
    return false;
448
0
  }
449
772k
  return true;
450
772k
}
451
452
bool CU::canUseLfnstWithISP( const CompArea& cuArea, const ISPType ispSplitType )
453
57.2k
{
454
57.2k
  if( ispSplitType == NOT_INTRA_SUBPARTITIONS )
455
0
  {
456
0
    return false;
457
0
  }
458
57.2k
  Size tuSize = ( ispSplitType == HOR_INTRA_SUBPARTITIONS ) ? Size( cuArea.width, CU::getISPSplitDim( cuArea.width, cuArea.height, TU_1D_HORZ_SPLIT ) ) :
459
57.2k
    Size( CU::getISPSplitDim( cuArea.width, cuArea.height, TU_1D_VERT_SPLIT ), cuArea.height );
460
461
57.2k
  if( !( tuSize.width >= MIN_TB_SIZEY && tuSize.height >= MIN_TB_SIZEY ) )
462
8.72k
  {
463
8.72k
    return false;
464
8.72k
  }
465
48.5k
  return true;
466
57.2k
}
467
468
bool CU::canUseLfnstWithISP( const CodingUnit& cu, const ChannelType chType )
469
6.43k
{
470
6.43k
  CHECK( !isLuma( chType ), "Wrong ISP mode!" );
471
6.43k
  return CU::canUseLfnstWithISP( cu.blocks[chType == CH_L ? 0 : 1], (ISPType)cu.ispMode );
472
6.43k
}
473
474
uint32_t CU::getISPSplitDim( const int width, const int height, const PartSplit ispType )
475
129k
{
476
129k
  bool divideTuInRows = ispType == TU_1D_HORZ_SPLIT;
477
129k
  uint32_t splitDimensionSize, nonSplitDimensionSize, partitionSize, divShift = 2;
478
479
129k
  if( divideTuInRows )
480
64.2k
  {
481
64.2k
    splitDimensionSize    = height;
482
64.2k
    nonSplitDimensionSize = width;
483
64.2k
  }
484
64.8k
  else
485
64.8k
  {
486
64.8k
    splitDimensionSize    = width;
487
64.8k
    nonSplitDimensionSize = height;
488
64.8k
  }
489
490
129k
  const int minNumberOfSamplesPerCu = 1 << ( ( MIN_TB_LOG2_SIZEY << 1 ) );
491
129k
  const int factorToMinSamples = nonSplitDimensionSize < minNumberOfSamplesPerCu ? minNumberOfSamplesPerCu >> Log2(nonSplitDimensionSize) : 1;
492
129k
  partitionSize = ( splitDimensionSize >> divShift ) < factorToMinSamples ? factorToMinSamples : ( splitDimensionSize >> divShift );
493
494
129k
  CHECK( Log2(partitionSize) + Log2(nonSplitDimensionSize) < Log2(minNumberOfSamplesPerCu), "A partition has less than the minimum amount of samples!" );
495
129k
  return partitionSize;
496
129k
}
497
498
bool CU::allLumaCBFsAreZero(const CodingUnit& cu)
499
1.47k
{
500
1.47k
  if (!cu.ispMode)
501
0
  {
502
0
    return TU::getCbf(*cu.firstTU, COMP_Y) == false;
503
0
  }
504
1.47k
  else
505
1.47k
  {
506
1.47k
    int numTotalTUs = cu.ispMode == HOR_INTRA_SUBPARTITIONS ? cu.lheight() >> Log2(cu.firstTU->lheight()) : cu.lwidth() >> Log2(cu.firstTU->lwidth());
507
1.47k
    TransformUnit* tuPtr = cu.firstTU;
508
1.47k
    for (int tuIdx = 0; tuIdx < numTotalTUs; tuIdx++)
509
1.47k
    {
510
1.47k
      if (TU::getCbf(*tuPtr, COMP_Y) == true)
511
1.47k
      {
512
1.47k
        return false;
513
1.47k
      }
514
0
      tuPtr = tuPtr->next;
515
0
    }
516
0
    return true;
517
1.47k
  }
518
1.47k
}
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
91.8k
{
532
91.8k
  const Position& pos = curr.blocks[curr.chType].pos();
533
91.8k
  return curr.cs->getCU(pos.offset(-1, 0), curr.chType, curr.treeType);
534
91.8k
}
535
536
const CodingUnit* CU::getAbove(const CodingUnit& curr)
537
93.8k
{
538
93.8k
  const Position& pos = curr.blocks[curr.chType].pos();
539
93.8k
  return curr.cs->getCU(pos.offset(0, -1), curr.chType, curr.treeType);
540
93.8k
}
541
542
// PU tools
543
544
int CU::getIntraMPMs( const CodingUnit& cu, unsigned* mpm )
545
264k
{
546
264k
  const int numMPMs = NUM_MOST_PROBABLE_MODES;
547
264k
  {
548
264k
    int numCand      = -1;
549
264k
    int leftIntraDir = PLANAR_IDX, aboveIntraDir = PLANAR_IDX;
550
551
264k
    const CompArea& area = cu.Y();
552
264k
    const Position posRT = area.topRight();
553
264k
    const Position posLB = area.bottomLeft();
554
555
    // Get intra direction of left PU
556
264k
    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
264k
    if (puLeft && CU::isIntra(*puLeft) && !CU::isMIP(*puLeft))
558
188k
    {
559
188k
      leftIntraDir = puLeft->intraDir[CH_L];
560
188k
    }
561
562
    // Get intra direction of above PU, but only from the same CU
563
264k
    const CodingUnit* puAbove = (posRT.y & cu.cs->pcv->maxCUSizeMask) ? cu.cs->getCU(posRT.offset(0, -1), CH_L, cu.treeType) : nullptr;
564
264k
    if (puAbove && CU::isIntra(*puAbove) && !CU::isMIP(*puAbove))
565
157k
    {
566
157k
      aboveIntraDir = puAbove->intraDir[CH_L];
567
157k
    }
568
569
264k
    CHECK(2 >= numMPMs, "Invalid number of most probable modes");
570
571
264k
    const int offset = (int)NUM_LUMA_MODE - 6;
572
264k
    const int mod = offset + 3;
573
574
264k
    {
575
264k
      mpm[0] = PLANAR_IDX;
576
264k
      mpm[1] = DC_IDX;
577
264k
      mpm[2] = VER_IDX;
578
264k
      mpm[3] = HOR_IDX;
579
264k
      mpm[4] = VER_IDX - 4;
580
264k
      mpm[5] = VER_IDX + 4;
581
582
264k
      if (leftIntraDir == aboveIntraDir)
583
257k
      {
584
257k
        numCand = 1;
585
257k
        if (leftIntraDir > DC_IDX)
586
4.09k
        {
587
4.09k
          mpm[0] = PLANAR_IDX;
588
4.09k
          mpm[1] = leftIntraDir;
589
4.09k
          mpm[2] = ((leftIntraDir + offset) % mod) + 2;
590
4.09k
          mpm[3] = ((leftIntraDir - 1) % mod) + 2;
591
4.09k
          mpm[4] = ((leftIntraDir + offset - 1) % mod) + 2;
592
4.09k
          mpm[5] = ( leftIntraDir               % mod) + 2;
593
4.09k
        }
594
257k
      }
595
6.37k
      else //L!=A
596
6.37k
      {
597
6.37k
        numCand = 2;
598
6.37k
        int  maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;
599
600
6.37k
        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.37k
        else if (leftIntraDir + aboveIntraDir >= 2)
633
5.81k
        {
634
5.81k
          mpm[0] = PLANAR_IDX;
635
5.81k
          mpm[1] = (leftIntraDir < aboveIntraDir) ? aboveIntraDir : leftIntraDir;
636
5.81k
          maxCandModeIdx = 1;
637
5.81k
          mpm[2] = ((mpm[maxCandModeIdx] + offset)     % mod) + 2;
638
5.81k
          mpm[3] = ((mpm[maxCandModeIdx] - 1)          % mod) + 2;
639
5.81k
          mpm[4] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2;
640
5.81k
          mpm[5] = ( mpm[maxCandModeIdx]               % mod) + 2;
641
5.81k
        }
642
6.37k
      }
643
264k
    }
644
1.84M
    for (int i = 0; i < numMPMs; i++)
645
1.58M
    {
646
1.58M
      CHECK(mpm[i] >= NUM_LUMA_MODE, "Invalid MPM");
647
1.58M
    }
648
264k
    CHECK(numCand == 0, "No candidates found");
649
264k
    return numCand;
650
264k
  }
651
264k
}
652
653
bool CU::isMIP(const CodingUnit& cu, const ChannelType chType)
654
3.88M
{
655
3.88M
  return chType == CH_L ? cu.mipFlag : ((cu.intraDir[CH_C] == DM_CHROMA_IDX) && isDMChromaMIP(cu));
656
3.88M
}
657
658
bool CU::isDMChromaMIP(const CodingUnit& cu)
659
619k
{
660
619k
  return !CU::isSepTree(cu) && (cu.chromaFormat == CHROMA_444) && getCoLocatedLumaPU(cu).mipFlag;
661
619k
}
662
663
664
uint32_t CU::getIntraDirLuma(const CodingUnit& cu)
665
995k
{
666
995k
  if (isMIP(cu))
667
217k
  {
668
217k
    return PLANAR_IDX;
669
217k
  }
670
778k
  else
671
778k
  {
672
778k
    return cu.intraDir[CH_L];
673
778k
  }
674
995k
}
675
676
677
void CU::getIntraChromaCandModes( const CodingUnit& cu, unsigned modeList[NUM_CHROMA_MODE] )
678
323k
{
679
323k
  {
680
323k
    modeList[0] = PLANAR_IDX;
681
323k
    modeList[1] = VER_IDX;
682
323k
    modeList[2] = HOR_IDX;
683
323k
    modeList[3] = DC_IDX;
684
323k
    modeList[4] = LM_CHROMA_IDX;
685
323k
    modeList[5] = MDLM_L_IDX;
686
323k
    modeList[6] = MDLM_T_IDX;
687
323k
    modeList[7] = DM_CHROMA_IDX;
688
689
    // If Direct Mode is MIP, mode cannot be already in the list.
690
323k
    if (isDMChromaMIP(cu))
691
0
    {
692
0
      return;
693
0
    }
694
695
323k
    const uint32_t lumaMode = getCoLocatedIntraLumaMode(cu);
696
350k
    for( int i = 0; i < 4; i++ )
697
350k
    {
698
350k
      if( lumaMode == modeList[i] )
699
323k
      {
700
323k
        modeList[i] = VDIA_IDX;
701
323k
        break;
702
323k
      }
703
350k
    }
704
323k
  }
705
323k
}
706
707
bool CU::isLMCMode(unsigned mode)
708
3.74M
{
709
3.74M
  return (mode >= LM_CHROMA_IDX && mode <= MDLM_T_IDX);
710
3.74M
}
711
712
bool CU::isLMCModeEnabled(const CodingUnit& cu, unsigned mode)
713
549k
{
714
549k
  return ( cu.cs->sps->LMChroma && CU::checkCCLMAllowed(cu) );
715
549k
}
716
717
int CU::getLMSymbolList(const CodingUnit& cu, int *modeList)
718
33.5k
{
719
33.5k
  int idx = 0;
720
721
33.5k
  modeList[idx++] = LM_CHROMA_IDX;
722
33.5k
  modeList[idx++] = MDLM_L_IDX;
723
33.5k
  modeList[idx++] = MDLM_T_IDX;
724
33.5k
  return idx;
725
33.5k
}
726
727
uint32_t CU::getFinalIntraMode( const CodingUnit& cu, const ChannelType chType )
728
5.54M
{
729
5.54M
  uint32_t uiIntraMode = cu.intraDir[chType];
730
731
5.54M
  if( uiIntraMode == DM_CHROMA_IDX && !isLuma( chType ) )
732
483k
  {
733
483k
    uiIntraMode = getCoLocatedIntraLumaMode(cu);
734
483k
  }
735
5.54M
  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.54M
  return uiIntraMode;
740
5.54M
}
741
742
const CodingUnit& CU::getCoLocatedLumaPU(const CodingUnit& cu)
743
995k
{
744
995k
  Position              topLeftPos = cu.blocks[cu.chType].lumaPos();
745
995k
  Position              refPos     = topLeftPos.offset(cu.blocks[cu.chType].lumaSize().width  >> 1,
746
995k
                                                       cu.blocks[cu.chType].lumaSize().height >> 1);
747
995k
  const CodingUnit& lumaCU     = CU::isSepTree(cu) ? *cu.cs->lumaCS->getCU(refPos, CH_L, TREE_D)
748
995k
                                                : *cu.cs->getCU(topLeftPos, CH_L, TREE_D);
749
750
995k
  return lumaCU;
751
995k
}
752
753
uint32_t CU::getCoLocatedIntraLumaMode(const CodingUnit& cu)
754
995k
{
755
995k
  return CU::getIntraDirLuma(CU::getCoLocatedLumaPU(cu));
756
995k
}
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
76.2k
{
760
76.2k
  const Slice& slice = *cs.slice;
761
76.2k
  HPMVInfo miNeighbor;
762
76.2k
  auto& lut = ibcFlag ? cs.motionLut.lutIbc : cs.motionLut.lut;
763
76.2k
  int num_avai_candInLUT = (int) lut.size();
764
765
76.2k
  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
76.2k
  if (cnt < maxNumMergeCandMin1)
796
76.2k
  {
797
76.2k
    mrgCtx.useAltHpelIf[cnt] = false;
798
76.2k
  }
799
800
76.2k
  return false;
801
76.2k
}
802
803
void CU::getIBCMergeCandidates(const CodingUnit& cu, MergeCtx& mrgCtx, const int& mrgCandIdx)
804
76.2k
{
805
76.2k
  const CodingStructure& cs = *cu.cs;
806
76.2k
  const uint32_t maxNumMergeCand = cu.cs->sps->maxNumIBCMergeCand;
807
533k
  for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
808
457k
  {
809
457k
    mrgCtx.BcwIdx             [ui]           = BCW_DEFAULT;
810
457k
    mrgCtx.interDirNeighbours [ui]           = 0;
811
457k
    mrgCtx.mrgTypeNeighbours  [ui]           = MRG_TYPE_IBC;
812
457k
    mrgCtx.mvFieldNeighbours  [ui][0].refIdx = NOT_VALID;
813
457k
    mrgCtx.mvFieldNeighbours  [ui][1].refIdx = NOT_VALID;
814
457k
    mrgCtx.useAltHpelIf       [ui]           = false;
815
457k
  }
816
817
76.2k
  mrgCtx.numValidMergeCand = maxNumMergeCand;
818
  // compute the location of the current PU
819
820
76.2k
  int cnt = 0;
821
822
76.2k
  const Position posRT = cu.Y().topRight();
823
76.2k
  const Position posLB = cu.Y().bottomLeft();
824
825
76.2k
  MotionInfo miAbove, miLeft, miAboveLeft, miAboveRight, miBelowLeft;
826
827
  //left
828
76.2k
  const CodingUnit* cuLeft = cs.getCURestricted(posLB.offset(-1, 0), cu, cu.chType);
829
76.2k
  bool isGt4x4 = cu.lwidth() * cu.lheight() > 16;
830
76.2k
  const bool isAvailableA1 = cuLeft && cu != *cuLeft && CU::isIBC(*cuLeft);
831
76.2k
  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
76.2k
  if (cnt == maxNumMergeCand)
849
0
  {
850
0
    return;
851
0
  }
852
853
  // above
854
76.2k
  const CodingUnit* cuAbove = cs.getCURestricted(posRT.offset(0, -1), cu, cu.chType);
855
76.2k
  bool isAvailableB1 = cuAbove && cu != *cuAbove && CU::isIBC(*cuAbove);
856
76.2k
  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
76.2k
  if (cnt == maxNumMergeCand)
878
0
  {
879
0
    return;
880
0
  }
881
76.2k
  else
882
76.2k
  {
883
76.2k
    bool bFound = addMergeHMVPCand( cs, mrgCtx, mrgCandIdx, maxNumMergeCand, cnt, isAvailableA1, miLeft, isAvailableB1, miAbove, true, isGt4x4 );
884
885
76.2k
    if (bFound)
886
0
    {
887
0
      return;
888
0
    }
889
76.2k
  }
890
891
279k
  while (cnt < maxNumMergeCand)
892
254k
  {
893
254k
    mrgCtx.mvFieldNeighbours[cnt][0].setMvField(Mv(0, 0), MAX_NUM_REF);
894
254k
    mrgCtx.interDirNeighbours[cnt] = 1;
895
254k
    if (mrgCandIdx == cnt)
896
50.8k
    {
897
50.8k
      return;
898
50.8k
    }
899
203k
    cnt++;
900
203k
  }
901
902
25.4k
  mrgCtx.numValidMergeCand = cnt;
903
25.4k
}
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
23.4k
{
1302
23.4k
  if( !cu.cs->sps->DMVR || cu.cs->slice->picHeader->disDmvrFlag )
1303
0
  {
1304
0
    return false;
1305
0
  }
1306
1307
23.4k
  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
23.4k
}
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
25.4k
{
1572
25.4k
  const PreCalcValues& pcv = *cu.cs->pcv;
1573
25.4k
  const int  cuWidth = cu.blocks[COMP_Y].width;
1574
25.4k
  const int  cuHeight = cu.blocks[COMP_Y].height;
1575
25.4k
  const int  log2UnitWidth = floorLog2(pcv.minCUSize); //(pcv.minCUWidth);
1576
25.4k
  const int  log2UnitHeight = floorLog2(pcv.minCUSize); //(pcv.minCUHeight);
1577
25.4k
  const int  totalAboveUnits = (cuWidth >> log2UnitHeight) + 1; // log2UnitWidth) + 1;
1578
25.4k
  const int  totalLeftUnits = (cuHeight >> log2UnitHeight) + 1;
1579
1580
25.4k
  nbPred = 0;
1581
25.4k
  Position posLT = cu.Y().topLeft();
1582
1583
  // above-left
1584
25.4k
  const CodingUnit* aboveLeftCU = cu.cs->getCURestricted(posLT.offset(-1, -1), cu, CH_L);
1585
25.4k
  if( aboveLeftCU && CU::isIBC( *aboveLeftCU ) )
1586
0
  {
1587
0
    isAddNeighborMvIBC(aboveLeftCU->mv[0][0], mvPred, nbPred);
1588
0
  }
1589
1590
  // above neighbors
1591
243k
  for( uint32_t dx = 0; dx < totalAboveUnits && nbPred < IBC_NUM_CANDIDATES; dx++ )
1592
218k
  {
1593
218k
    const CodingUnit* tmpCU = cu.cs->getCURestricted( posLT.offset( ( dx << log2UnitWidth ), -1 ), cu, CH_L );
1594
218k
    if( tmpCU && CU::isIBC( *tmpCU ) )
1595
0
    {
1596
0
      isAddNeighborMvIBC( tmpCU->mv[0][0], mvPred, nbPred );
1597
0
    }
1598
218k
  }
1599
1600
  // left neighbors
1601
243k
  for( uint32_t dy = 0; dy < totalLeftUnits && nbPred < IBC_NUM_CANDIDATES; dy++ )
1602
218k
  {
1603
218k
    const CodingUnit* tmpCU = cu.cs->getCURestricted( posLT.offset( -1, ( dy << log2UnitHeight ) ), cu, CH_L );
1604
218k
    if( tmpCU && CU::isIBC( *tmpCU ) )
1605
0
    {
1606
0
      isAddNeighborMvIBC( tmpCU->mv[0][0], mvPred, nbPred );
1607
0
    }
1608
218k
  }
1609
1610
25.4k
  size_t numAvaiCandInLUT = cu.cs->motionLut.lutIbc.size();
1611
25.4k
  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
25.4k
  bool isBvCandDerived[IBC_NUM_CANDIDATES];
1618
25.4k
  ::memset(isBvCandDerived, false, IBC_NUM_CANDIDATES);
1619
1620
25.4k
  int curNbPred = nbPred;
1621
25.4k
  if( curNbPred < IBC_NUM_CANDIDATES )
1622
25.4k
  {
1623
25.4k
    do
1624
25.4k
    {
1625
25.4k
      curNbPred = nbPred;
1626
25.4k
      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
25.4k
    } while( nbPred > curNbPred && nbPred < IBC_NUM_CANDIDATES );
1639
25.4k
  }
1640
25.4k
}
1641
1642
void CU::fillIBCMvpCand(CodingUnit& cu, AMVPInfo& amvpInfo)
1643
50.8k
{
1644
50.8k
  AMVPInfo* pInfo = &amvpInfo;
1645
1646
50.8k
  pInfo->numCand = 0;
1647
1648
50.8k
  MergeCtx mergeCtx;
1649
50.8k
  CU::getIBCMergeCandidates(cu, mergeCtx, AMVP_MAX_NUM_CANDS - 1);
1650
50.8k
  int candIdx = 0;
1651
152k
  while (pInfo->numCand < AMVP_MAX_NUM_CANDS)
1652
101k
  {
1653
101k
    pInfo->mvCand[pInfo->numCand] = mergeCtx.mvFieldNeighbours[candIdx][0].mv;;
1654
101k
    pInfo->numCand++;
1655
101k
    candIdx++;
1656
101k
  }
1657
1658
50.8k
  for (Mv& mv : pInfo->mvCand)
1659
152k
  {
1660
152k
    mv.roundIbcPrecInternal2Amvr(cu.imv);
1661
152k
  }
1662
50.8k
}
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
152k
{
2222
152k
  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
152k
  if ( cu.lumaSize().width + cu.lumaSize().height == 12 )
2228
0
  {
2229
0
    return true;
2230
0
  }
2231
152k
  return false;
2232
152k
}
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
22.6k
{
3014
22.6k
  MotionBuf mb = cu.getMotionBuf();
3015
3016
22.6k
  if( !cu.mergeFlag || cu.mergeType == MRG_TYPE_DEFAULT_N || cu.mergeType == MRG_TYPE_IBC )
3017
22.6k
  {
3018
22.6k
    bool isIBC   = CU::isIBC( cu );
3019
22.6k
    bool isInter = !CU::isIntra( cu ) && !isIBC;
3020
3021
22.6k
    if( isInter || isIBC )
3022
22.6k
    {
3023
22.6k
      MotionInfo mi;
3024
3025
67.9k
      for( int i = 0; i < NUM_REF_PIC_LIST_01; i++ )
3026
45.3k
      {
3027
45.3k
        mi.mv[i]       = cu.mv[i][0];
3028
45.3k
        mi.miRefIdx[i] = isIBC ? MI_NOT_VALID : cu.refIdx[i];
3029
45.3k
      }
3030
3031
22.6k
      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
22.6k
      else
3052
22.6k
      {
3053
22.6k
      }
3054
3055
22.6k
      mb.fill( mi );
3056
22.6k
    }
3057
22.6k
  }
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
22.6k
}
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
152k
{
3087
152k
  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
152k
}
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
22.6k
{
3301
22.6k
  bool bNonZeroMvd = false;
3302
3303
22.6k
  if( ( !cu.mergeFlag ) && ( !cu.skip ) )
3304
22.6k
  {
3305
22.6k
    if( cu.interDir != 2 /* PRED_L1 */ )
3306
22.6k
    {
3307
22.6k
      bNonZeroMvd |= cu.mvd[REF_PIC_LIST_0][0].hor != 0;
3308
22.6k
      bNonZeroMvd |= cu.mvd[REF_PIC_LIST_0][0].ver != 0;
3309
22.6k
    }
3310
22.6k
    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
22.6k
  }
3319
3320
22.6k
  return bNonZeroMvd;
3321
22.6k
}
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
194k
{
3406
194k
  return (cu.ispMode == VER_INTRA_SUBPARTITIONS && ((cu.blocks[0].width == 4 )|| ((cu.blocks[0].width == 8) && (cu.blocks[0].height > 4))));
3407
194k
}
3408
3409
bool CU::isFirstTBInPredReg(const CodingUnit& cu, const CompArea& area)
3410
20.4k
{
3411
20.4k
  return ((area.topLeft().x - cu.Y().topLeft().x) % PRED_REG_MIN_WIDTH == 0);
3412
20.4k
}
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
22.6k
{
3421
22.6k
  if( ! cu.cs->sps->BCW )
3422
22.6k
  {
3423
22.6k
    CHECK(cu.BcwIdx != BCW_DEFAULT, "Error: cu.BcwIdx != BCW_DEFAULT");
3424
22.6k
    return false;
3425
22.6k
  }
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
718k
{
3501
718k
  SizeType transformSkipMaxSize = 1 << cu.cs->sps->log2MaxTransformSkipBlockSize;
3502
3503
718k
  const Size& blkSize = isLuma(compID) ? cu.lumaSize() : cu.chromaSize();
3504
718k
  bool bdpcmAllowed = cu.cs->sps->BDPCM;
3505
718k
       bdpcmAllowed &= CU::isIntra( cu );
3506
718k
       bdpcmAllowed &= (blkSize.width <= transformSkipMaxSize && blkSize.height <= transformSkipMaxSize);
3507
718k
  return bdpcmAllowed;
3508
718k
}
3509
3510
bool CU::isMTSAllowed(const CodingUnit &cu, const ComponentID compID)
3511
203k
{
3512
203k
  SizeType tsMaxSize = 1 << cu.cs->sps->log2MaxTransformSkipBlockSize;
3513
203k
  const int maxSize  = CU::isIntra( cu ) ? MTS_INTRA_MAX_CU_SIZE : MTS_INTER_MAX_CU_SIZE;
3514
203k
  const int cuWidth  = cu.blocks[0].lumaSize().width;
3515
203k
  const int cuHeight = cu.blocks[0].lumaSize().height;
3516
203k
  bool mtsAllowed    = cu.chType == CH_L && compID == COMP_Y;
3517
3518
203k
  mtsAllowed &= CU::isIntra( cu ) ? cu.cs->sps->MTSIntra : cu.cs->sps->MTSInter && CU::isInter( cu );
3519
203k
  mtsAllowed &= cuWidth <= maxSize && cuHeight <= maxSize;
3520
203k
  mtsAllowed &= !cu.ispMode;
3521
203k
  mtsAllowed &= !cu.sbtInfo;
3522
203k
  mtsAllowed &= !(cu.bdpcmM[CH_L] && cuWidth <= tsMaxSize && cuHeight <= tsMaxSize);
3523
203k
  return mtsAllowed;
3524
203k
}
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
8.72M
{
3575
8.72M
  return getCbfAtDepth( tu, compID, tu.depth );
3576
8.72M
}
3577
3578
bool TU::getCbfAtDepth(const TransformUnit& tu, const ComponentID compID, const unsigned depth)
3579
11.6M
{
3580
11.6M
  if( !tu.blocks[compID].valid() )
3581
11.6M
    CHECK( tu.cbf[compID] != 0, "cbf must be 0 if the component is not available" );
3582
11.6M
  return ((tu.cbf[compID] >> depth) & 1) == 1;
3583
11.6M
}
3584
3585
void TU::setCbfAtDepth(TransformUnit& tu, const ComponentID compID, const unsigned depth, const bool cbf)
3586
2.56M
{
3587
  // first clear the CBF at the depth
3588
2.56M
  tu.cbf[compID] &= ~(1  << depth);
3589
  // then set the CBF
3590
2.56M
  tu.cbf[compID] |= ((cbf ? 1 : 0) << depth);
3591
2.56M
}
3592
3593
bool TU::isTSAllowed(const TransformUnit &tu, const ComponentID compID)
3594
2.78M
{
3595
2.78M
  const int maxSize = tu.cs->sps->log2MaxTransformSkipBlockSize;
3596
3597
2.78M
  bool tsAllowed = tu.cs->sps->transformSkip;
3598
2.78M
  tsAllowed &= ( !tu.cu->ispMode || !isLuma(compID) );
3599
2.78M
  SizeType transformSkipMaxSize = 1 << maxSize;
3600
2.78M
  tsAllowed &= !(tu.cu->bdpcmM[toChannelType(compID)]);
3601
2.78M
  tsAllowed &= tu.blocks[compID].width <= transformSkipMaxSize && tu.blocks[compID].height <= transformSkipMaxSize;
3602
2.78M
  tsAllowed &= !tu.cu->sbtInfo;
3603
3604
2.78M
  return tsAllowed;
3605
2.78M
}
3606
3607
int TU::getICTMode( const TransformUnit& tu, int jointCbCr )
3608
7.87M
{
3609
7.87M
  if( jointCbCr < 0 )
3610
6.79M
  {
3611
6.79M
    jointCbCr = tu.jointCbCr;
3612
6.79M
  }
3613
7.87M
  return g_ictModes[ tu.cs->picHeader->jointCbCrSign ][ jointCbCr ];
3614
7.87M
}
3615
3616
bool TU::needsSqrt2Scale( const TransformUnit& tu, const ComponentID compID )
3617
2.95M
{
3618
2.95M
  const Size& size=tu.blocks[compID];
3619
2.95M
  const bool isTransformSkip = tu.mtsIdx[compID] == MTS_SKIP;
3620
2.95M
  return (!isTransformSkip) && (((Log2(size.width * size.height)) & 1) == 1);
3621
2.95M
}
3622
3623
TransformUnit* TU::getPrevTU( const TransformUnit& tu, const ComponentID compID )
3624
26.7k
{
3625
26.7k
  TransformUnit* prevTU = tu.prev;
3626
3627
26.7k
  if( prevTU != nullptr && ( prevTU->cu != tu.cu || !prevTU->blocks[compID].valid() ) )
3628
0
  {
3629
0
    prevTU = nullptr;
3630
0
  }
3631
3632
26.7k
  return prevTU;
3633
26.7k
}
3634
3635
bool TU::getPrevTuCbfAtDepth( const TransformUnit& currentTu, const ComponentID compID, const int trDepth )
3636
26.7k
{
3637
26.7k
  const TransformUnit* prevTU = getPrevTU( currentTu, compID );
3638
26.7k
  return ( prevTU != nullptr ) ? TU::getCbfAtDepth( *prevTU, compID, trDepth ) : false;
3639
26.7k
}
3640
3641
3642
// other tools
3643
3644
uint32_t getCtuAddr( const Position& pos, const PreCalcValues& pcv )
3645
418k
{
3646
418k
  return ( pos.x >> pcv.maxCUSizeLog2 ) + ( pos.y >> pcv.maxCUSizeLog2 ) * pcv.widthInCtus;
3647
418k
}
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
318k
{
3656
318k
  switch( getMipSizeId(block) )
3657
318k
  {
3658
0
  case 0: return 16;
3659
7.47k
  case 1: return  8;
3660
311k
  case 2: return  6;
3661
0
  default: THROW( "Invalid mipSizeId" );
3662
318k
  }
3663
318k
}
3664
3665
int getMipSizeId(const Size& block)
3666
361k
{
3667
361k
  if( block.width == 4 && block.height == 4 )
3668
0
  {
3669
0
    return 0;
3670
0
  }
3671
361k
  else if( block.width == 4 || block.height == 4 || (block.width == 8 && block.height == 8) )
3672
7.88k
  {
3673
7.88k
    return 1;
3674
7.88k
  }
3675
353k
  else
3676
353k
  {
3677
353k
    return 2;
3678
353k
  }
3679
361k
}
3680
3681
bool allowLfnstWithMip(const Size& block)
3682
55.4k
{
3683
55.4k
  if (block.width >= 16 && block.height >= 16)
3684
51.1k
  {
3685
51.1k
    return true;
3686
51.1k
  }
3687
4.28k
  return false;
3688
55.4k
}
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