Coverage Report

Created: 2026-07-16 06:32

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