Coverage Report

Created: 2026-04-01 07:49

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