Coverage Report

Created: 2026-10-28 06:18

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