Coverage Report

Created: 2026-10-28 06:18

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
14.2M
{
69
14.2M
  return cs.slice->isIntra() && !cs.pcv->ISingleTree;
70
14.2M
}
71
72
UnitArea CS::getArea( const CodingStructure &cs, const UnitArea& area, const ChannelType chType, const TreeType treeType )
73
760k
{
74
18.4E
  return isDualITree( cs ) || treeType != TREE_D ? area.singleChan( chType ) : area;
75
760k
}
76
77
int CS::signalModeCons( const CodingStructure &cs, const UnitArea &currArea, const PartSplit split, const ModeType modeTypeParent )
78
554k
{
79
554k
  const ChromaFormat chromaFormat = currArea.chromaFormat;
80
81
554k
  if( CS::isDualITree( cs ) || modeTypeParent != MODE_TYPE_ALL || chromaFormat == CHROMA_444 || chromaFormat == CHROMA_400 )
82
554k
    return LDT_MODE_TYPE_INHERIT;
83
84
0
  int minLumaArea = currArea.lumaSize().area();
85
0
  if( split == CU_QUAD_SPLIT || split == CU_TRIH_SPLIT || split == CU_TRIV_SPLIT ) // the area is split into 3 or 4 parts
86
0
  {
87
0
    minLumaArea = minLumaArea >> 2;
88
0
  }
89
0
  else if( split == CU_VERT_SPLIT || split == CU_HORZ_SPLIT ) // the area is split into 2 parts
90
0
  {
91
0
    minLumaArea = minLumaArea >> 1;
92
0
  }
93
94
0
  int minChromaBlock = minLumaArea >> ( getChannelTypeScaleX( CH_C, chromaFormat ) + getChannelTypeScaleY( CH_C, chromaFormat ) );
95
0
  bool is2xNChroma   = ( currArea.chromaSize().width == 4 && split == CU_VERT_SPLIT ) || ( currArea.chromaSize().width == 8 && split == CU_TRIV_SPLIT );
96
0
  return minChromaBlock >= 16 && !is2xNChroma ? LDT_MODE_TYPE_INHERIT
97
0
                                              : ( ( minLumaArea < 32 ) || cs.slice->isIntra() ) ? LDT_MODE_TYPE_INFER
98
0
                                                                                                : LDT_MODE_TYPE_SIGNAL;
99
554k
}
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
4.97k
{
146
4.97k
  static const int scale = 4 * std::max<int>( 1, 4 * AMVP_DECIMATION_FACTOR / 4 );
147
148
4.97k
  const int xPos = ctuX << cs.pcv->maxCUSizeLog2;
149
4.97k
  const int yPos = ctuY << cs.pcv->maxCUSizeLog2;
150
4.97k
  const int xEnd = std::min<int>( xPos + cs.pcv->maxCUSize, cs.pcv->lumaWidth );
151
4.97k
  const int yEnd = std::min<int>( yPos + cs.pcv->maxCUSize, cs.pcv->lumaHeight );
152
60.5k
  for( int y = yPos; y < yEnd; y += scale )
153
55.6k
  {
154
674k
    for( int x = xPos; x < xEnd; x += scale )
155
619k
    {
156
619k
      cs.colocatedMotionInfo( Position( x, y ) ) = cs.getMotionInfo( Position( x, y ) );
157
619k
    }
158
55.6k
  }
159
160
4.97k
  if( !applyDmvr )
161
0
  {
162
0
    return;
163
0
  }
164
165
  // first CU in CTU
166
4.97k
  const CodingUnit *ptrCU = cs.getCU( Position( xPos, yPos ), CH_L, TREE_D );
167
56.1k
  while( ptrCU )
168
51.1k
  {
169
51.1k
    const CodingUnit& cu = *ptrCU;
170
171
51.1k
    if( isLuma( cu.chType ) && cu.mvdL0SubPu && CU::checkDMVRCondition( cu ) )
172
0
    {
173
0
      refineCU( cu, cs );
174
0
    }
175
176
51.1k
    ptrCU = ptrCU->next;
177
51.1k
  }
178
4.97k
}
179
// CU tools
180
181
bool CU::checkCCLMAllowed(const CodingUnit& cu) 
182
1.16M
{
183
1.16M
  bool allowCCLM = false;
184
185
1.16M
  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
1.16M
  else if( cu.slice->sps->CTUSize <= 32 ) //dual tree, CTUsize < 64
190
0
  {
191
0
    allowCCLM = true;
192
0
  }
193
1.16M
  else //dual tree, CTU size 64 or 128
194
1.16M
  {
195
1.16M
    int depthFor64x64Node = cu.slice->sps->CTUSize == 128 ? 1 : 0;
196
1.16M
    const PartSplit cuSplitTypeDepth1 = CU::getSplitAtDepth( cu, depthFor64x64Node );
197
1.16M
    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
1.16M
    if( cuSplitTypeDepth1 == CU_QUAD_SPLIT || (cuSplitTypeDepth1 == CU_HORZ_SPLIT && cuSplitTypeDepth2 == CU_VERT_SPLIT) )
201
681k
    {
202
681k
      if( cu.chromaFormat == CHROMA_420 )
203
681k
      {
204
681k
        CHECK( !(cu.blocks[COMP_Cb].width <= 16 && cu.blocks[COMP_Cb].height <= 16), "chroma cu size shall be <= 16x16 for YUV420 format" );
205
681k
      }
206
681k
      allowCCLM = true;
207
681k
    }
208
    //allow CCLM if 64x64 chroma tree node uses NS (No Split) and becomes a chroma CU containing 32x32 chroma blocks
209
478k
    else if( cuSplitTypeDepth1 == CU_DONT_SPLIT )
210
113k
    {
211
113k
      if( cu.chromaFormat == CHROMA_420 )
212
113k
      {
213
113k
        CHECK( !(cu.blocks[COMP_Cb].width == 32 && cu.blocks[COMP_Cb].height == 32), "chroma cu size shall be 32x32 for YUV420 format" );
214
113k
      }
215
113k
      allowCCLM = true;
216
113k
    }
217
    //allow CCLM if 64x32 chroma tree node uses NS and becomes a chroma CU containing 32x16 chroma blocks
218
364k
    else if( cuSplitTypeDepth1 == CU_HORZ_SPLIT && cuSplitTypeDepth2 == CU_DONT_SPLIT )
219
45.4k
    {
220
45.4k
      if( cu.chromaFormat == CHROMA_420 )
221
45.4k
      {
222
45.4k
        CHECK( !(cu.blocks[COMP_Cb].width == 32 && cu.blocks[COMP_Cb].height == 16), "chroma cu size shall be 32x16 for YUV420 format" );
223
45.4k
      }
224
45.4k
      allowCCLM = true;
225
45.4k
    }
226
227
    //further check luma conditions
228
1.16M
    if( allowCCLM )
229
841k
    {
230
      //disallow CCLM if luma 64x64 block uses BT or TT or NS with ISP
231
841k
      const Position lumaRefPos( cu.chromaPos().x << getComponentScaleX( COMP_Cb, cu.chromaFormat ), cu.chromaPos().y << getComponentScaleY( COMP_Cb, cu.chromaFormat ) );
232
841k
      const CodingUnit* colLumaCu = cu.cs->lumaCS->getCU( lumaRefPos, CH_L, TREE_D );
233
234
841k
      if( colLumaCu->lwidth() < 64 || colLumaCu->lheight() < 64 ) //further split at 64x64 luma node
235
371k
      {
236
371k
        const PartSplit cuSplitTypeDepth1Luma = CU::getSplitAtDepth( *colLumaCu, depthFor64x64Node );
237
371k
        CHECK( !(cuSplitTypeDepth1Luma >= CU_QUAD_SPLIT && cuSplitTypeDepth1Luma <= CU_TRIV_SPLIT), "split mode shall be BT, TT or QT" );
238
371k
        if( cuSplitTypeDepth1Luma != CU_QUAD_SPLIT )
239
0
        {
240
0
          allowCCLM = false;
241
0
        }
242
371k
      }
243
469k
      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
841k
    }
248
1.16M
  }
249
250
1.16M
  return allowCCLM;
251
1.16M
}
252
253
uint8_t CU::checkAllowedSbt(const CodingUnit& cu) 
254
161
{
255
161
  if( !cu.slice->sps->SBT || cu.predMode != MODE_INTER || cu.ciip || cu.predMode == MODE_IBC || cu.Y().maxDim() > cu.cs->sps->getMaxTbSize() )
256
161
  {
257
161
    return 0;
258
161
  }
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
161
}
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
103k
{
317
103k
  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
103k
  return ( ( ( ( cuAreaY.x + cuAreaY.width  ) & cu.cs->pcv->maxCUSizeMask ) == 0 || cuAreaY.x + cuAreaY.width  == cu.cs->pcv->lumaWidth  ) &&
320
46.1k
           ( ( ( cuAreaY.y + cuAreaY.height ) & cu.cs->pcv->maxCUSizeMask ) == 0 || cuAreaY.y + cuAreaY.height == cu.cs->pcv->lumaHeight ) );
321
103k
}
322
323
uint32_t CU::getCtuAddr( const CodingUnit &cu )
324
35.3k
{
325
35.3k
  return getCtuAddr( cu.blocks[cu.chType].lumaPos(), *cu.cs->pcv );
326
35.3k
}
327
328
int CU::predictQP( const CodingUnit& cu, const int prevQP )
329
35.3k
{
330
35.3k
  const ChannelType      chType   = cu.chType;
331
35.3k
  const CodingStructure& cs       = *cu.cs;
332
35.3k
  const Slice&           slice    = *cs.slice;
333
35.3k
  const bool             inCtuA   = ( cu.blocks[cu.chType].y & ( cs.pcv->maxCUSizeMask >> getChannelTypeScaleY( cu.chType, cu.chromaFormat ) ) );
334
35.3k
  const bool             inCtuL   = ( cu.blocks[cu.chType].x & ( cs.pcv->maxCUSizeMask >> getChannelTypeScaleX( cu.chType, cu.chromaFormat ) ) );
335
35.3k
  const CodingUnit*      cuAbove  =          cs.getCURestricted( cu.blocks[chType].pos().offset( 0, -1 ), cu, chType );
336
35.3k
  const CodingUnit*      cuLeft   = inCtuL ? cs.getCURestricted( cu.blocks[chType].pos().offset( -1, 0 ), cu, chType ) : nullptr;
337
  
338
35.3k
  const uint32_t ctuRsAddr       = getCtuAddr( cu );
339
35.3k
  const uint32_t ctuXPosInCtus   = ctuRsAddr % cs.pcv->widthInCtus;
340
35.3k
  const uint32_t tileXPosInCtus  = slice.pps->tileColBd[cs.pps->ctuToTileCol[ctuXPosInCtus]];
341
  
342
35.3k
  if( ctuXPosInCtus == tileXPosInCtus && !inCtuL && !inCtuA && cuAbove )
343
5.99k
  {
344
5.99k
    return cuAbove->qp;
345
5.99k
  }
346
29.4k
  else
347
29.4k
  {
348
29.4k
    const int a = inCtuA ? cuAbove->qp : prevQP;
349
29.4k
    const int b = inCtuL ? cuLeft->qp  : prevQP;
350
  
351
29.4k
    return ( a + b + 1 ) >> 1;
352
29.4k
  }
353
35.3k
}
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
3.11M
{
375
3.11M
  if( depth >= cu.depth ) return CU_DONT_SPLIT;
376
377
2.48M
  const PartSplit cuSplitType = PartSplit( ( cu.splitSeries >> ( depth * SPLIT_DMULT ) ) & SPLIT_MASK );
378
379
2.48M
  if     ( cuSplitType == CU_QUAD_SPLIT    ) return CU_QUAD_SPLIT;
380
381
1.16M
  else if( cuSplitType == CU_HORZ_SPLIT    ) return CU_HORZ_SPLIT;
382
383
590k
  else if( cuSplitType == CU_VERT_SPLIT    ) return CU_VERT_SPLIT;
384
385
6.06k
  else if( cuSplitType == CU_TRIH_SPLIT    ) return CU_TRIH_SPLIT;
386
19
  else if( cuSplitType == CU_TRIV_SPLIT    ) return CU_TRIV_SPLIT;
387
18.4E
  else   { THROW( "Unknown split mode"    ); return CU_QUAD_SPLIT; }
388
2.48M
}
389
390
ModeType CU::getModeTypeAtDepth( const CodingUnit& cu, const unsigned depth )
391
98.3k
{
392
98.3k
  ModeType modeType = ModeType( (cu.modeTypeSeries >> (depth * 3)) & 0x07 );
393
98.3k
  CHECK( depth > cu.depth, " depth is wrong" );
394
98.3k
  return modeType;
395
98.3k
}
396
397
bool CU::divideTuInRows( const CodingUnit &cu )
398
43.7k
{
399
43.7k
  CHECK( cu.ispMode != HOR_INTRA_SUBPARTITIONS && cu.ispMode != VER_INTRA_SUBPARTITIONS, "Intra Subpartitions type not recognized!" );
400
43.7k
  return cu.ispMode == HOR_INTRA_SUBPARTITIONS ? true : false;
401
43.7k
}
402
403
404
PartSplit CU::getISPType( const CodingUnit &cu, const ComponentID compID )
405
96.1k
{
406
96.1k
  if( cu.ispMode && isLuma( compID ) )
407
43.7k
  {
408
43.7k
    const bool tuIsDividedInRows = CU::divideTuInRows( cu );
409
410
43.7k
    return tuIsDividedInRows ? TU_1D_HORZ_SPLIT : TU_1D_VERT_SPLIT;
411
43.7k
  }
412
52.4k
  return TU_NO_ISP;
413
96.1k
}
414
415
bool CU::isISPLast( const CodingUnit &cu, const CompArea& tuArea, const ComponentID compID )
416
37.1k
{
417
37.1k
  PartSplit partitionType = CU::getISPType( cu, compID );
418
419
37.1k
  Area originalArea = cu.blocks[compID];
420
37.1k
  switch( partitionType )
421
37.1k
  {
422
19.6k
    case TU_1D_HORZ_SPLIT:
423
19.6k
      return tuArea.y + tuArea.height == originalArea.y + originalArea.height;
424
17.4k
    case TU_1D_VERT_SPLIT:
425
17.4k
      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
37.1k
  }
430
37.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
953k
{
439
953k
  const int width     = cu.blocks[compID].width;
440
953k
  const int height    = cu.blocks[compID].height;
441
953k
  const int maxTrSize = cu.cs->sps->getMaxTbSize();
442
953k
  return CU::canUseISP( width, height, maxTrSize );
443
953k
}
444
445
bool CU::canUseISP( const int width, const int height, const int maxTrSize )
446
985k
{
447
985k
  bool  notEnoughSamplesToSplit = ( Log2(width) + Log2(height) <= ( MIN_TB_LOG2_SIZEY << 1 ) );
448
985k
  bool  cuSizeLargerThanMaxTrSize = width > maxTrSize || height > maxTrSize;
449
985k
  if ( notEnoughSamplesToSplit || cuSizeLargerThanMaxTrSize )
450
0
  {
451
0
    return false;
452
0
  }
453
985k
  return true;
454
985k
}
455
456
bool CU::canUseLfnstWithISP( const CompArea& cuArea, const ISPType ispSplitType )
457
72.5k
{
458
72.5k
  if( ispSplitType == NOT_INTRA_SUBPARTITIONS )
459
0
  {
460
0
    return false;
461
0
  }
462
72.5k
  Size tuSize = ( ispSplitType == HOR_INTRA_SUBPARTITIONS ) ? Size( cuArea.width, CU::getISPSplitDim( cuArea.width, cuArea.height, TU_1D_HORZ_SPLIT ) ) :
463
72.5k
    Size( CU::getISPSplitDim( cuArea.width, cuArea.height, TU_1D_VERT_SPLIT ), cuArea.height );
464
465
72.5k
  if( !( tuSize.width >= MIN_TB_SIZEY && tuSize.height >= MIN_TB_SIZEY ) )
466
10.7k
  {
467
10.7k
    return false;
468
10.7k
  }
469
61.7k
  return true;
470
72.5k
}
471
472
bool CU::canUseLfnstWithISP( const CodingUnit& cu, const ChannelType chType )
473
7.65k
{
474
7.65k
  CHECK( !isLuma( chType ), "Wrong ISP mode!" );
475
7.65k
  return CU::canUseLfnstWithISP( cu.blocks[chType == CH_L ? 0 : 1], (ISPType)cu.ispMode );
476
7.65k
}
477
478
uint32_t CU::getISPSplitDim( const int width, const int height, const PartSplit ispType )
479
162k
{
480
162k
  bool divideTuInRows = ispType == TU_1D_HORZ_SPLIT;
481
162k
  uint32_t splitDimensionSize, nonSplitDimensionSize, partitionSize, divShift = 2;
482
483
162k
  if( divideTuInRows )
484
80.9k
  {
485
80.9k
    splitDimensionSize    = height;
486
80.9k
    nonSplitDimensionSize = width;
487
80.9k
  }
488
81.6k
  else
489
81.6k
  {
490
81.6k
    splitDimensionSize    = width;
491
81.6k
    nonSplitDimensionSize = height;
492
81.6k
  }
493
494
162k
  const int minNumberOfSamplesPerCu = 1 << ( ( MIN_TB_LOG2_SIZEY << 1 ) );
495
162k
  const int factorToMinSamples = nonSplitDimensionSize < minNumberOfSamplesPerCu ? minNumberOfSamplesPerCu >> Log2(nonSplitDimensionSize) : 1;
496
162k
  partitionSize = ( splitDimensionSize >> divShift ) < factorToMinSamples ? factorToMinSamples : ( splitDimensionSize >> divShift );
497
498
162k
  CHECK( Log2(partitionSize) + Log2(nonSplitDimensionSize) < Log2(minNumberOfSamplesPerCu), "A partition has less than the minimum amount of samples!" );
499
162k
  return partitionSize;
500
162k
}
501
502
bool CU::allLumaCBFsAreZero(const CodingUnit& cu)
503
1.51k
{
504
1.51k
  if (!cu.ispMode)
505
0
  {
506
0
    return TU::getCbf(*cu.firstTU, COMP_Y) == false;
507
0
  }
508
1.51k
  else
509
1.51k
  {
510
1.51k
    int numTotalTUs = cu.ispMode == HOR_INTRA_SUBPARTITIONS ? cu.lheight() >> Log2(cu.firstTU->lheight()) : cu.lwidth() >> Log2(cu.firstTU->lwidth());
511
1.51k
    TransformUnit* tuPtr = cu.firstTU;
512
1.51k
    for (int tuIdx = 0; tuIdx < numTotalTUs; tuIdx++)
513
1.51k
    {
514
1.51k
      if (TU::getCbf(*tuPtr, COMP_Y) == true)
515
1.51k
      {
516
1.51k
        return false;
517
1.51k
      }
518
0
      tuPtr = tuPtr->next;
519
0
    }
520
0
    return true;
521
1.51k
  }
522
1.51k
}
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
119k
{
536
119k
  const Position& pos = curr.blocks[curr.chType].pos();
537
119k
  return curr.cs->getCU(pos.offset(-1, 0), curr.chType, curr.treeType);
538
119k
}
539
540
const CodingUnit* CU::getAbove(const CodingUnit& curr)
541
121k
{
542
121k
  const Position& pos = curr.blocks[curr.chType].pos();
543
121k
  return curr.cs->getCU(pos.offset(0, -1), curr.chType, curr.treeType);
544
121k
}
545
546
// PU tools
547
548
int CU::getIntraMPMs( const CodingUnit& cu, unsigned* mpm )
549
405k
{
550
405k
  const int numMPMs = NUM_MOST_PROBABLE_MODES;
551
405k
  {
552
405k
    int numCand      = -1;
553
405k
    int leftIntraDir = PLANAR_IDX, aboveIntraDir = PLANAR_IDX;
554
555
405k
    const CompArea& area = cu.Y();
556
405k
    const Position posRT = area.topRight();
557
405k
    const Position posLB = area.bottomLeft();
558
559
    // Get intra direction of left PU
560
405k
    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
405k
    if (puLeft && CU::isIntra(*puLeft) && !CU::isMIP(*puLeft))
562
287k
    {
563
287k
      leftIntraDir = puLeft->intraDir[CH_L];
564
287k
    }
565
566
    // Get intra direction of above PU, but only from the same CU
567
405k
    const CodingUnit* puAbove = (posRT.y & cu.cs->pcv->maxCUSizeMask) ? cu.cs->getCU(posRT.offset(0, -1), CH_L, cu.treeType) : nullptr;
568
405k
    if (puAbove && CU::isIntra(*puAbove) && !CU::isMIP(*puAbove))
569
233k
    {
570
233k
      aboveIntraDir = puAbove->intraDir[CH_L];
571
233k
    }
572
573
405k
    CHECK(2 >= numMPMs, "Invalid number of most probable modes");
574
575
405k
    const int offset = (int)NUM_LUMA_MODE - 6;
576
405k
    const int mod = offset + 3;
577
578
405k
    {
579
405k
      mpm[0] = PLANAR_IDX;
580
405k
      mpm[1] = DC_IDX;
581
405k
      mpm[2] = VER_IDX;
582
405k
      mpm[3] = HOR_IDX;
583
405k
      mpm[4] = VER_IDX - 4;
584
405k
      mpm[5] = VER_IDX + 4;
585
586
405k
      if (leftIntraDir == aboveIntraDir)
587
395k
      {
588
395k
        numCand = 1;
589
395k
        if (leftIntraDir > DC_IDX)
590
6.05k
        {
591
6.05k
          mpm[0] = PLANAR_IDX;
592
6.05k
          mpm[1] = leftIntraDir;
593
6.05k
          mpm[2] = ((leftIntraDir + offset) % mod) + 2;
594
6.05k
          mpm[3] = ((leftIntraDir - 1) % mod) + 2;
595
6.05k
          mpm[4] = ((leftIntraDir + offset - 1) % mod) + 2;
596
6.05k
          mpm[5] = ( leftIntraDir               % mod) + 2;
597
6.05k
        }
598
395k
      }
599
9.25k
      else //L!=A
600
9.25k
      {
601
9.25k
        numCand = 2;
602
9.25k
        int  maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;
603
604
9.25k
        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
9.25k
        else if (leftIntraDir + aboveIntraDir >= 2)
637
8.68k
        {
638
8.68k
          mpm[0] = PLANAR_IDX;
639
8.68k
          mpm[1] = (leftIntraDir < aboveIntraDir) ? aboveIntraDir : leftIntraDir;
640
8.68k
          maxCandModeIdx = 1;
641
8.68k
          mpm[2] = ((mpm[maxCandModeIdx] + offset)     % mod) + 2;
642
8.68k
          mpm[3] = ((mpm[maxCandModeIdx] - 1)          % mod) + 2;
643
8.68k
          mpm[4] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2;
644
8.68k
          mpm[5] = ( mpm[maxCandModeIdx]               % mod) + 2;
645
8.68k
        }
646
9.25k
      }
647
405k
    }
648
2.83M
    for (int i = 0; i < numMPMs; i++)
649
2.43M
    {
650
2.43M
      CHECK(mpm[i] >= NUM_LUMA_MODE, "Invalid MPM");
651
2.43M
    }
652
405k
    CHECK(numCand == 0, "No candidates found");
653
405k
    return numCand;
654
405k
  }
655
405k
}
656
657
bool CU::isMIP(const CodingUnit& cu, const ChannelType chType)
658
4.95M
{
659
4.95M
  return chType == CH_L ? cu.mipFlag : ((cu.intraDir[CH_C] == DM_CHROMA_IDX) && isDMChromaMIP(cu));
660
4.95M
}
661
662
bool CU::isDMChromaMIP(const CodingUnit& cu)
663
774k
{
664
774k
  return !CU::isSepTree(cu) && (cu.chromaFormat == CHROMA_444) && getCoLocatedLumaPU(cu).mipFlag;
665
774k
}
666
667
668
uint32_t CU::getIntraDirLuma(const CodingUnit& cu)
669
1.24M
{
670
1.24M
  if (isMIP(cu))
671
225k
  {
672
225k
    return PLANAR_IDX;
673
225k
  }
674
1.01M
  else
675
1.01M
  {
676
1.01M
    return cu.intraDir[CH_L];
677
1.01M
  }
678
1.24M
}
679
680
681
void CU::getIntraChromaCandModes( const CodingUnit& cu, unsigned modeList[NUM_CHROMA_MODE] )
682
404k
{
683
404k
  {
684
404k
    modeList[0] = PLANAR_IDX;
685
404k
    modeList[1] = VER_IDX;
686
404k
    modeList[2] = HOR_IDX;
687
404k
    modeList[3] = DC_IDX;
688
404k
    modeList[4] = LM_CHROMA_IDX;
689
404k
    modeList[5] = MDLM_L_IDX;
690
404k
    modeList[6] = MDLM_T_IDX;
691
404k
    modeList[7] = DM_CHROMA_IDX;
692
693
    // If Direct Mode is MIP, mode cannot be already in the list.
694
404k
    if (isDMChromaMIP(cu))
695
0
    {
696
0
      return;
697
0
    }
698
699
404k
    const uint32_t lumaMode = getCoLocatedIntraLumaMode(cu);
700
433k
    for( int i = 0; i < 4; i++ )
701
433k
    {
702
433k
      if( lumaMode == modeList[i] )
703
404k
      {
704
404k
        modeList[i] = VDIA_IDX;
705
404k
        break;
706
404k
      }
707
433k
    }
708
404k
  }
709
404k
}
710
711
bool CU::isLMCMode(unsigned mode)
712
4.68M
{
713
4.68M
  return (mode >= LM_CHROMA_IDX && mode <= MDLM_T_IDX);
714
4.68M
}
715
716
bool CU::isLMCModeEnabled(const CodingUnit& cu, unsigned mode)
717
687k
{
718
687k
  return ( cu.cs->sps->LMChroma && CU::checkCCLMAllowed(cu) );
719
687k
}
720
721
int CU::getLMSymbolList(const CodingUnit& cu, int *modeList)
722
42.6k
{
723
42.6k
  int idx = 0;
724
725
42.6k
  modeList[idx++] = LM_CHROMA_IDX;
726
42.6k
  modeList[idx++] = MDLM_L_IDX;
727
42.6k
  modeList[idx++] = MDLM_T_IDX;
728
42.6k
  return idx;
729
42.6k
}
730
731
uint32_t CU::getFinalIntraMode( const CodingUnit& cu, const ChannelType chType )
732
6.96M
{
733
6.96M
  uint32_t uiIntraMode = cu.intraDir[chType];
734
735
6.96M
  if( uiIntraMode == DM_CHROMA_IDX && !isLuma( chType ) )
736
603k
  {
737
603k
    uiIntraMode = getCoLocatedIntraLumaMode(cu);
738
603k
  }
739
6.96M
  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
6.96M
  return uiIntraMode;
744
6.96M
}
745
746
const CodingUnit& CU::getCoLocatedLumaPU(const CodingUnit& cu)
747
1.24M
{
748
1.24M
  Position              topLeftPos = cu.blocks[cu.chType].lumaPos();
749
1.24M
  Position              refPos     = topLeftPos.offset(cu.blocks[cu.chType].lumaSize().width  >> 1,
750
1.24M
                                                       cu.blocks[cu.chType].lumaSize().height >> 1);
751
1.24M
  const CodingUnit& lumaCU     = CU::isSepTree(cu) ? *cu.cs->lumaCS->getCU(refPos, CH_L, TREE_D)
752
1.24M
                                                : *cu.cs->getCU(topLeftPos, CH_L, TREE_D);
753
754
1.24M
  return lumaCU;
755
1.24M
}
756
757
uint32_t CU::getCoLocatedIntraLumaMode(const CodingUnit& cu)
758
1.24M
{
759
1.24M
  return CU::getIntraDirLuma(CU::getCoLocatedLumaPU(cu));
760
1.24M
}
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
97.2k
{
764
97.2k
  const Slice& slice = *cs.slice;
765
97.2k
  HPMVInfo miNeighbor;
766
97.2k
  auto& lut = ibcFlag ? cs.motionLut.lutIbc : cs.motionLut.lut;
767
97.2k
  int num_avai_candInLUT = (int) lut.size();
768
769
97.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
97.2k
  if (cnt < maxNumMergeCandMin1)
800
97.2k
  {
801
97.2k
    mrgCtx.useAltHpelIf[cnt] = false;
802
97.2k
  }
803
804
97.2k
  return false;
805
97.2k
}
806
807
void CU::getIBCMergeCandidates(const CodingUnit& cu, MergeCtx& mrgCtx, const int& mrgCandIdx)
808
97.2k
{
809
97.2k
  const CodingStructure& cs = *cu.cs;
810
97.2k
  const uint32_t maxNumMergeCand = cu.cs->sps->maxNumIBCMergeCand;
811
680k
  for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
812
583k
  {
813
583k
    mrgCtx.BcwIdx             [ui]           = BCW_DEFAULT;
814
583k
    mrgCtx.interDirNeighbours [ui]           = 0;
815
583k
    mrgCtx.mrgTypeNeighbours  [ui]           = MRG_TYPE_IBC;
816
583k
    mrgCtx.mvFieldNeighbours  [ui][0].refIdx = NOT_VALID;
817
583k
    mrgCtx.mvFieldNeighbours  [ui][1].refIdx = NOT_VALID;
818
583k
    mrgCtx.useAltHpelIf       [ui]           = false;
819
583k
  }
820
821
97.2k
  mrgCtx.numValidMergeCand = maxNumMergeCand;
822
  // compute the location of the current PU
823
824
97.2k
  int cnt = 0;
825
826
97.2k
  const Position posRT = cu.Y().topRight();
827
97.2k
  const Position posLB = cu.Y().bottomLeft();
828
829
97.2k
  MotionInfo miAbove, miLeft, miAboveLeft, miAboveRight, miBelowLeft;
830
831
  //left
832
97.2k
  const CodingUnit* cuLeft = cs.getCURestricted(posLB.offset(-1, 0), cu, cu.chType);
833
97.2k
  bool isGt4x4 = cu.lwidth() * cu.lheight() > 16;
834
97.2k
  const bool isAvailableA1 = cuLeft && cu != *cuLeft && CU::isIBC(*cuLeft);
835
97.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
97.2k
  if (cnt == maxNumMergeCand)
853
0
  {
854
0
    return;
855
0
  }
856
857
  // above
858
97.2k
  const CodingUnit* cuAbove = cs.getCURestricted(posRT.offset(0, -1), cu, cu.chType);
859
97.2k
  bool isAvailableB1 = cuAbove && cu != *cuAbove && CU::isIBC(*cuAbove);
860
97.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
97.2k
  if (cnt == maxNumMergeCand)
882
0
  {
883
0
    return;
884
0
  }
885
97.2k
  else
886
97.2k
  {
887
97.2k
    bool bFound = addMergeHMVPCand( cs, mrgCtx, mrgCandIdx, maxNumMergeCand, cnt, isAvailableA1, miLeft, isAvailableB1, miAbove, true, isGt4x4 );
888
889
97.2k
    if (bFound)
890
0
    {
891
0
      return;
892
0
    }
893
97.2k
  }
894
895
356k
  while (cnt < maxNumMergeCand)
896
324k
  {
897
324k
    mrgCtx.mvFieldNeighbours[cnt][0].setMvField(Mv(0, 0), MAX_NUM_REF);
898
324k
    mrgCtx.interDirNeighbours[cnt] = 1;
899
324k
    if (mrgCandIdx == cnt)
900
64.8k
    {
901
64.8k
      return;
902
64.8k
    }
903
259k
    cnt++;
904
259k
  }
905
906
32.4k
  mrgCtx.numValidMergeCand = cnt;
907
32.4k
}
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
30.3k
{
1306
30.3k
  if( !cu.cs->sps->DMVR || cu.cs->slice->picHeader->disDmvrFlag )
1307
0
  {
1308
0
    return false;
1309
0
  }
1310
1311
30.3k
  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
30.3k
}
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
32.4k
{
1576
32.4k
  const PreCalcValues& pcv = *cu.cs->pcv;
1577
32.4k
  const int  cuWidth = cu.blocks[COMP_Y].width;
1578
32.4k
  const int  cuHeight = cu.blocks[COMP_Y].height;
1579
32.4k
  const int  log2UnitWidth = floorLog2(pcv.minCUSize); //(pcv.minCUWidth);
1580
32.4k
  const int  log2UnitHeight = floorLog2(pcv.minCUSize); //(pcv.minCUHeight);
1581
32.4k
  const int  totalAboveUnits = (cuWidth >> log2UnitHeight) + 1; // log2UnitWidth) + 1;
1582
32.4k
  const int  totalLeftUnits = (cuHeight >> log2UnitHeight) + 1;
1583
1584
32.4k
  nbPred = 0;
1585
32.4k
  Position posLT = cu.Y().topLeft();
1586
1587
  // above-left
1588
32.4k
  const CodingUnit* aboveLeftCU = cu.cs->getCURestricted(posLT.offset(-1, -1), cu, CH_L);
1589
32.4k
  if( aboveLeftCU && CU::isIBC( *aboveLeftCU ) )
1590
0
  {
1591
0
    isAddNeighborMvIBC(aboveLeftCU->mv[0][0], mvPred, nbPred);
1592
0
  }
1593
1594
  // above neighbors
1595
316k
  for( uint32_t dx = 0; dx < totalAboveUnits && nbPred < IBC_NUM_CANDIDATES; dx++ )
1596
284k
  {
1597
284k
    const CodingUnit* tmpCU = cu.cs->getCURestricted( posLT.offset( ( dx << log2UnitWidth ), -1 ), cu, CH_L );
1598
284k
    if( tmpCU && CU::isIBC( *tmpCU ) )
1599
0
    {
1600
0
      isAddNeighborMvIBC( tmpCU->mv[0][0], mvPred, nbPred );
1601
0
    }
1602
284k
  }
1603
1604
  // left neighbors
1605
318k
  for( uint32_t dy = 0; dy < totalLeftUnits && nbPred < IBC_NUM_CANDIDATES; dy++ )
1606
286k
  {
1607
286k
    const CodingUnit* tmpCU = cu.cs->getCURestricted( posLT.offset( -1, ( dy << log2UnitHeight ) ), cu, CH_L );
1608
286k
    if( tmpCU && CU::isIBC( *tmpCU ) )
1609
0
    {
1610
0
      isAddNeighborMvIBC( tmpCU->mv[0][0], mvPred, nbPred );
1611
0
    }
1612
286k
  }
1613
1614
32.4k
  size_t numAvaiCandInLUT = cu.cs->motionLut.lutIbc.size();
1615
32.4k
  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
32.4k
  bool isBvCandDerived[IBC_NUM_CANDIDATES];
1622
32.4k
  ::memset(isBvCandDerived, false, IBC_NUM_CANDIDATES);
1623
1624
32.4k
  int curNbPred = nbPred;
1625
32.4k
  if( curNbPred < IBC_NUM_CANDIDATES )
1626
32.4k
  {
1627
32.4k
    do
1628
32.4k
    {
1629
32.4k
      curNbPred = nbPred;
1630
32.4k
      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
32.4k
    } while( nbPred > curNbPred && nbPred < IBC_NUM_CANDIDATES );
1643
32.4k
  }
1644
32.4k
}
1645
1646
void CU::fillIBCMvpCand(CodingUnit& cu, AMVPInfo& amvpInfo)
1647
64.8k
{
1648
64.8k
  AMVPInfo* pInfo = &amvpInfo;
1649
1650
64.8k
  pInfo->numCand = 0;
1651
1652
64.8k
  MergeCtx mergeCtx;
1653
64.8k
  CU::getIBCMergeCandidates(cu, mergeCtx, AMVP_MAX_NUM_CANDS - 1);
1654
64.8k
  int candIdx = 0;
1655
194k
  while (pInfo->numCand < AMVP_MAX_NUM_CANDS)
1656
129k
  {
1657
129k
    pInfo->mvCand[pInfo->numCand] = mergeCtx.mvFieldNeighbours[candIdx][0].mv;;
1658
129k
    pInfo->numCand++;
1659
129k
    candIdx++;
1660
129k
  }
1661
1662
64.8k
  for (Mv& mv : pInfo->mvCand)
1663
194k
  {
1664
194k
    mv.roundIbcPrecInternal2Amvr(cu.imv);
1665
194k
  }
1666
64.8k
}
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
194k
{
2226
194k
  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
194k
  if ( cu.lumaSize().width + cu.lumaSize().height == 12 )
2232
0
  {
2233
0
    return true;
2234
0
  }
2235
194k
  return false;
2236
194k
}
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
29.1k
{
3018
29.1k
  MotionBuf mb = cu.getMotionBuf();
3019
3020
29.1k
  if( !cu.mergeFlag || cu.mergeType == MRG_TYPE_DEFAULT_N || cu.mergeType == MRG_TYPE_IBC )
3021
29.1k
  {
3022
29.1k
    bool isIBC   = CU::isIBC( cu );
3023
29.1k
    bool isInter = !CU::isIntra( cu ) && !isIBC;
3024
3025
29.1k
    if( isInter || isIBC )
3026
29.1k
    {
3027
29.1k
      MotionInfo mi;
3028
3029
87.3k
      for( int i = 0; i < NUM_REF_PIC_LIST_01; i++ )
3030
58.2k
      {
3031
58.2k
        mi.mv[i]       = cu.mv[i][0];
3032
58.2k
        mi.miRefIdx[i] = isIBC ? MI_NOT_VALID : cu.refIdx[i];
3033
58.2k
      }
3034
3035
29.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
29.1k
      else
3056
29.1k
      {
3057
29.1k
      }
3058
3059
29.1k
      mb.fill( mi );
3060
29.1k
    }
3061
29.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
29.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
194k
{
3091
194k
  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
194k
}
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
29.1k
{
3305
29.1k
  bool bNonZeroMvd = false;
3306
3307
29.1k
  if( ( !cu.mergeFlag ) && ( !cu.skip ) )
3308
29.1k
  {
3309
29.1k
    if( cu.interDir != 2 /* PRED_L1 */ )
3310
29.1k
    {
3311
29.1k
      bNonZeroMvd |= cu.mvd[REF_PIC_LIST_0][0].hor != 0;
3312
29.1k
      bNonZeroMvd |= cu.mvd[REF_PIC_LIST_0][0].ver != 0;
3313
29.1k
    }
3314
29.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
29.1k
  }
3323
3324
29.1k
  return bNonZeroMvd;
3325
29.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
245k
{
3410
245k
  return (cu.ispMode == VER_INTRA_SUBPARTITIONS && ((cu.blocks[0].width == 4 )|| ((cu.blocks[0].width == 8) && (cu.blocks[0].height > 4))));
3411
245k
}
3412
3413
bool CU::isFirstTBInPredReg(const CodingUnit& cu, const CompArea& area)
3414
23.7k
{
3415
23.7k
  return ((area.topLeft().x - cu.Y().topLeft().x) % PRED_REG_MIN_WIDTH == 0);
3416
23.7k
}
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
29.1k
{
3425
29.1k
  if( ! cu.cs->sps->BCW )
3426
29.1k
  {
3427
29.1k
    CHECK(cu.BcwIdx != BCW_DEFAULT, "Error: cu.BcwIdx != BCW_DEFAULT");
3428
29.1k
    return false;
3429
29.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
905k
{
3505
905k
  SizeType transformSkipMaxSize = 1 << cu.cs->sps->log2MaxTransformSkipBlockSize;
3506
3507
905k
  const Size& blkSize = isLuma(compID) ? cu.lumaSize() : cu.chromaSize();
3508
905k
  bool bdpcmAllowed = cu.cs->sps->BDPCM;
3509
905k
       bdpcmAllowed &= CU::isIntra( cu );
3510
905k
       bdpcmAllowed &= (blkSize.width <= transformSkipMaxSize && blkSize.height <= transformSkipMaxSize);
3511
905k
  return bdpcmAllowed;
3512
905k
}
3513
3514
bool CU::isMTSAllowed(const CodingUnit &cu, const ComponentID compID)
3515
256k
{
3516
256k
  SizeType tsMaxSize = 1 << cu.cs->sps->log2MaxTransformSkipBlockSize;
3517
256k
  const int maxSize  = CU::isIntra( cu ) ? MTS_INTRA_MAX_CU_SIZE : MTS_INTER_MAX_CU_SIZE;
3518
256k
  const int cuWidth  = cu.blocks[0].lumaSize().width;
3519
256k
  const int cuHeight = cu.blocks[0].lumaSize().height;
3520
256k
  bool mtsAllowed    = cu.chType == CH_L && compID == COMP_Y;
3521
3522
256k
  mtsAllowed &= CU::isIntra( cu ) ? cu.cs->sps->MTSIntra : cu.cs->sps->MTSInter && CU::isInter( cu );
3523
256k
  mtsAllowed &= cuWidth <= maxSize && cuHeight <= maxSize;
3524
256k
  mtsAllowed &= !cu.ispMode;
3525
256k
  mtsAllowed &= !cu.sbtInfo;
3526
256k
  mtsAllowed &= !(cu.bdpcmM[CH_L] && cuWidth <= tsMaxSize && cuHeight <= tsMaxSize);
3527
256k
  return mtsAllowed;
3528
256k
}
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
10.9M
{
3579
10.9M
  return getCbfAtDepth( tu, compID, tu.depth );
3580
10.9M
}
3581
3582
bool TU::getCbfAtDepth(const TransformUnit& tu, const ComponentID compID, const unsigned depth)
3583
14.5M
{
3584
14.5M
  if( !tu.blocks[compID].valid() )
3585
14.5M
    CHECK( tu.cbf[compID] != 0, "cbf must be 0 if the component is not available" );
3586
14.5M
  return ((tu.cbf[compID] >> depth) & 1) == 1;
3587
14.5M
}
3588
3589
void TU::setCbfAtDepth(TransformUnit& tu, const ComponentID compID, const unsigned depth, const bool cbf)
3590
3.19M
{
3591
  // first clear the CBF at the depth
3592
3.19M
  tu.cbf[compID] &= ~(1  << depth);
3593
  // then set the CBF
3594
3.19M
  tu.cbf[compID] |= ((cbf ? 1 : 0) << depth);
3595
3.19M
}
3596
3597
bool TU::isTSAllowed(const TransformUnit &tu, const ComponentID compID)
3598
3.46M
{
3599
3.46M
  const int maxSize = tu.cs->sps->log2MaxTransformSkipBlockSize;
3600
3601
3.46M
  bool tsAllowed = tu.cs->sps->transformSkip;
3602
3.46M
  tsAllowed &= ( !tu.cu->ispMode || !isLuma(compID) );
3603
3.46M
  SizeType transformSkipMaxSize = 1 << maxSize;
3604
3.46M
  tsAllowed &= !(tu.cu->bdpcmM[toChannelType(compID)]);
3605
3.46M
  tsAllowed &= tu.blocks[compID].width <= transformSkipMaxSize && tu.blocks[compID].height <= transformSkipMaxSize;
3606
3.46M
  tsAllowed &= !tu.cu->sbtInfo;
3607
3608
3.46M
  return tsAllowed;
3609
3.46M
}
3610
3611
int TU::getICTMode( const TransformUnit& tu, int jointCbCr )
3612
10.0M
{
3613
10.0M
  if( jointCbCr < 0 )
3614
8.67M
  {
3615
8.67M
    jointCbCr = tu.jointCbCr;
3616
8.67M
  }
3617
10.0M
  return g_ictModes[ tu.cs->picHeader->jointCbCrSign ][ jointCbCr ];
3618
10.0M
}
3619
3620
bool TU::needsSqrt2Scale( const TransformUnit& tu, const ComponentID compID )
3621
3.67M
{
3622
3.67M
  const Size& size=tu.blocks[compID];
3623
3.67M
  const bool isTransformSkip = tu.mtsIdx[compID] == MTS_SKIP;
3624
3.67M
  return (!isTransformSkip) && (((Log2(size.width * size.height)) & 1) == 1);
3625
3.67M
}
3626
3627
TransformUnit* TU::getPrevTU( const TransformUnit& tu, const ComponentID compID )
3628
30.7k
{
3629
30.7k
  TransformUnit* prevTU = tu.prev;
3630
3631
30.7k
  if( prevTU != nullptr && ( prevTU->cu != tu.cu || !prevTU->blocks[compID].valid() ) )
3632
0
  {
3633
0
    prevTU = nullptr;
3634
0
  }
3635
3636
30.7k
  return prevTU;
3637
30.7k
}
3638
3639
bool TU::getPrevTuCbfAtDepth( const TransformUnit& currentTu, const ComponentID compID, const int trDepth )
3640
30.7k
{
3641
30.7k
  const TransformUnit* prevTU = getPrevTU( currentTu, compID );
3642
30.7k
  return ( prevTU != nullptr ) ? TU::getCbfAtDepth( *prevTU, compID, trDepth ) : false;
3643
30.7k
}
3644
3645
3646
// other tools
3647
3648
uint32_t getCtuAddr( const Position& pos, const PreCalcValues& pcv )
3649
530k
{
3650
530k
  return ( pos.x >> pcv.maxCUSizeLog2 ) + ( pos.y >> pcv.maxCUSizeLog2 ) * pcv.widthInCtus;
3651
530k
}
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
406k
{
3660
406k
  switch( getMipSizeId(block) )
3661
406k
  {
3662
0
  case 0: return 16;
3663
9.39k
  case 1: return  8;
3664
397k
  case 2: return  6;
3665
0
  default: THROW( "Invalid mipSizeId" );
3666
406k
  }
3667
406k
}
3668
3669
int getMipSizeId(const Size& block)
3670
461k
{
3671
461k
  if( block.width == 4 && block.height == 4 )
3672
0
  {
3673
0
    return 0;
3674
0
  }
3675
461k
  else if( block.width == 4 || block.height == 4 || (block.width == 8 && block.height == 8) )
3676
9.91k
  {
3677
9.91k
    return 1;
3678
9.91k
  }
3679
451k
  else
3680
451k
  {
3681
451k
    return 2;
3682
451k
  }
3683
461k
}
3684
3685
bool allowLfnstWithMip(const Size& block)
3686
69.7k
{
3687
69.7k
  if (block.width >= 16 && block.height >= 16)
3688
64.8k
  {
3689
64.8k
    return true;
3690
64.8k
  }
3691
4.92k
  return false;
3692
69.7k
}
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