Coverage Report

Created: 2026-10-17 06:56

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