Coverage Report

Created: 2026-10-17 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvenc/source/Lib/EncoderLib/EncCu.h
Line
Count
Source
1
/* -----------------------------------------------------------------------------
2
The copyright in this software is being made available under the Clear BSD
3
License, included below. No patent rights, trademark rights and/or 
4
other Intellectual Property Rights other than the copyrights concerning 
5
the Software are granted under this license.
6
7
The Clear BSD License
8
9
Copyright (c) 2019-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVenC Authors.
10
All rights reserved.
11
12
Redistribution and use in source and binary forms, with or without modification,
13
are permitted (subject to the limitations in the disclaimer below) provided that
14
the following conditions are met:
15
16
     * Redistributions of source code must retain the above copyright notice,
17
     this list of conditions and the following disclaimer.
18
19
     * Redistributions in binary form must reproduce the above copyright
20
     notice, this list of conditions and the following disclaimer in the
21
     documentation and/or other materials provided with the distribution.
22
23
     * Neither the name of the copyright holder nor the names of its
24
     contributors may be used to endorse or promote products derived from this
25
     software without specific prior written permission.
26
27
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
28
THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
29
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
31
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
32
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
36
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38
POSSIBILITY OF SUCH DAMAGE.
39
40
41
------------------------------------------------------------------------------------------- */
42
/** \file     EncCu.h
43
    \brief    Coding Unit (CU) encoder class (header)
44
*/
45
46
#pragma once
47
48
#include "vvenc/vvencCfg.h"
49
#include "CABACWriter.h"
50
#include "IntraSearch.h"
51
#include "InterSearch.h"
52
#include "EncModeCtrl.h"
53
#include "RateCtrl.h"
54
#include "CommonLib/CommonDef.h"
55
#include "CommonLib/Unit.h"
56
#include "CommonLib/UnitPartitioner.h"
57
#include "CommonLib/LoopFilter.h"
58
#include "DecoderLib/DecCu.h"
59
60
//! \ingroup EncoderLib
61
//! \{
62
63
namespace vvenc {
64
65
class EncModeCtrl;
66
struct EncTestMode;
67
class EncPicture;
68
69
// ====================================================================================================================
70
// Class definition
71
// ====================================================================================================================
72
  struct GeoMergeCombo
73
  {
74
    int    splitDir  =  0;
75
    int8_t mergeIdx0 = -1;
76
    int8_t mergeIdx1 = -1;
77
    double cost      = 0.0;
78
  };
79
80
  struct SmallerThanComboCost
81
  {
82
    inline bool operator()(const GeoMergeCombo &first, const GeoMergeCombo &second)
83
0
    {
84
0
      return (first.cost < second.cost);
85
0
    }
86
  };
87
88
  struct GeoComboCostList
89
  {
90
    std::vector<GeoMergeCombo> list;
91
0
    void                       sortByCost() { std::stable_sort(list.begin(), list.end(), SmallerThanComboCost()); };
92
  };
93
94
  class FastGeoCostList
95
  {
96
    using CostArray = double[GEO_NUM_PARTITION_MODE][2];
97
98
    int        m_maxNumGeoCand{ 0 };
99
    CostArray *m_singleDistList{ nullptr };
100
101
  public:
102
103
4.62k
    FastGeoCostList() {}
104
    ~FastGeoCostList()
105
4.62k
    {
106
4.62k
      delete[] m_singleDistList;
107
4.62k
      m_singleDistList = nullptr;
108
4.62k
    }
109
110
    void init( int maxNumGeoCand )
111
4.62k
    {
112
4.62k
      if( m_maxNumGeoCand != maxNumGeoCand )
113
4.62k
      {
114
4.62k
        delete[] m_singleDistList;
115
4.62k
        m_singleDistList = nullptr;
116
117
4.62k
        CHECK( maxNumGeoCand > MRG_MAX_NUM_CANDS, "Too many candidates" );
118
4.62k
        m_singleDistList = new CostArray[maxNumGeoCand];
119
4.62k
        m_maxNumGeoCand  = maxNumGeoCand;
120
4.62k
      }
121
4.62k
    }
122
123
    void insert( int splitDir, int partIdx, int mergeIdx, double cost )
124
0
    {
125
0
      CHECKD( splitDir >= GEO_NUM_PARTITION_MODE, "geoIdx is too large" );
126
0
      CHECKD( mergeIdx >= m_maxNumGeoCand, "mergeIdx is too large" );
127
0
      CHECKD( partIdx >= 2, "partIdx is too large" );
128
129
0
      m_singleDistList[mergeIdx][splitDir][partIdx] = cost;
130
0
    }
131
132
    double getCost( const int splitDir, const int mergeCand0, const int mergeCand1 )
133
0
    {
134
0
      return m_singleDistList[mergeCand0][splitDir][0] + m_singleDistList[mergeCand1][splitDir][1];
135
0
    }
136
  };
137
138
139
140
  class MergeItem
141
  {
142
  private:
143
    PelStorage m_pelStorage;
144
    std::vector<MotionInfo> m_mvStorage;
145
146
  public:
147
148
    enum class MergeItemType
149
    {
150
      REGULAR,
151
      SBTMVP,
152
      AFFINE,
153
      MMVD,
154
      CIIP,
155
      GPM,
156
      IBC,
157
      NUM,
158
    };
159
160
    double        cost;
161
    std::array<MvField[3], 2>
162
                  mvField;
163
    int           mergeIdx;
164
    uint8_t       bcwIdx;
165
    uint8_t       interDir;
166
    bool          useAltHpelIf;
167
    int8_t        affineType;
168
    int8_t        numCiipIntra;
169
170
    bool          noResidual;
171
    bool          noBdofRefine;
172
173
    bool          lumaPredReady;
174
    bool          chromaPredReady;
175
176
    MergeItemType mergeItemType;
177
178
    MergeItem();
179
    ~MergeItem();
180
181
    void          create          (ChromaFormat chromaFormat, const Area& area);
182
    void          init            ();
183
    void          importMergeInfo (const MergeCtx&       mergeCtx, int _mergeIdx, MergeItemType _mergeItemType, CodingUnit& cu);
184
    void          importMergeInfo (const AffineMergeCtx& mergeCtx, int _mergeIdx, MergeItemType _mergeItemType, CodingUnit& cu);
185
    bool          exportMergeInfo (CodingUnit& cu, bool forceNoResidual) const;
186
0
    PelUnitBuf    getPredBuf      (const UnitArea& unitArea) { return m_pelStorage.getCompactBuf( unitArea ); }
187
0
    CMotionBuf    getMvBuf        (const UnitArea &unitArea) const { return CMotionBuf( m_mvStorage.data(), g_miScaling.scale( unitArea.lumaSize() ) ); }
188
0
    MotionBuf     getMvBuf        (const UnitArea &unitArea)       { return  MotionBuf( m_mvStorage.data(), g_miScaling.scale( unitArea.lumaSize() ) ); }
189
190
    static int getGpmUnfiedIndex( int splitDir, const MergeIdxPair &geoMergeIdx )
191
0
    {
192
0
      return ( splitDir << 8 ) | ( geoMergeIdx[ 0 ] << 4 ) | geoMergeIdx[ 1 ];
193
0
    }
194
195
    static void updateGpmIdx( int mergeIdx, uint8_t &splitDir, MergeIdxPair &geoMergeIdx )
196
0
    {
197
0
      splitDir       = ( mergeIdx >> 8 ) & 0xFF;
198
0
      geoMergeIdx[0] = ( mergeIdx >> 4 ) & 0xF;
199
0
      geoMergeIdx[1] =   mergeIdx        & 0xF;
200
0
    }
201
  };
202
203
  class MergeItemList
204
  {
205
  private:
206
    std::vector<MergeItem*>  m_mergeItems;
207
    std::vector<MergeItem*>  m_list;
208
    size_t                   m_maxTrackingNum = 0;
209
    size_t                   m_maxSize;
210
    size_t                   m_maxExtSize;
211
    size_t                   m_numExt;
212
213
  public:
214
    MergeItemList();
215
    ~MergeItemList();
216
217
    void          init                  (size_t maxListSize, size_t maxExtSize, ChromaFormat chromaFormat, SizeType ctuWidth, SizeType ctuHeight);
218
    MergeItem*    allocateNewMergeItem  ();
219
    bool          insertMergeItemToList (MergeItem* p);
220
    void          giveBackMergeItem     (MergeItem* p);
221
    void          resetList             (size_t maxTrackingNum);
222
    void          shrinkList            (size_t reduceTo);
223
    MergeItem*    getMergeItemInList    (size_t index);
224
0
    size_t        size                  () const { return m_list.size(); }
225
0
    size_t        capacity              () const { return m_maxTrackingNum; }
226
  };
227
228
using MergeBufVector = static_vector<PelUnitBuf, MRG_MAX_NUM_CANDS>;
229
230
/// Per-picture state of the CU encoder. The slice encoder fills it in when it starts a picture.
231
/// CU encoders belong to worker threads and serve all pictures that are encoded in parallel, so a
232
/// worker applies this state to its CU encoder before the first CTU it encodes from the picture.
233
struct PicEncState
234
{
235
  Picture* pic        = nullptr;
236
  uint64_t id         = 0;        ///< unique for every picture start, also across slice encoders
237
  double   lambda     = 0.0;      ///< picture lambda before CTU-level adaptation
238
  int      qp         = 0;        ///< picture QP matching the lambda
239
  Ctx*     syncPicCtx = nullptr;  ///< WPP context storage of the slice encoder that owns the picture
240
};
241
242
/// CU encoder class
243
class EncCu
244
  : DecCu
245
{
246
private:
247
  struct CtxPair
248
  {
249
    Ctx start;
250
    Ctx best;
251
  };
252
253
  std::vector<CtxPair>  m_CtxBuffer;
254
  CtxPair*              m_CurrCtx;
255
  CtxCache*             m_CtxCache;
256
257
  //  Data : encoder control
258
259
  static const int maxCuDepth = ( MAX_CU_SIZE_IDX - MIN_CU_LOG2 ) << 1;
260
261
  int                   m_cuChromaQpOffsetIdxPlus1;
262
  int                   m_tempQpDiff;
263
  std::vector<int>*     m_globalCtuQpVector;
264
  XUCache               m_unitCache;
265
  std::mutex*           m_wppMutex;
266
  CodingStructure*      m_pTempCS[maxCuDepth];
267
  CodingStructure*      m_pBestCS[maxCuDepth];
268
  CodingStructure*      m_pTempCS2;
269
  CodingStructure*      m_pBestCS2;
270
  PelStorage            m_pOrgBuffer[maxCuDepth];
271
272
  int                   m_lumaLevelToDeltaQPLUT[LUMA_LEVEL_TO_DQP_LUT_MAXSIZE];
273
274
  //  Access channel
275
  const VVEncCfg*       m_pcEncCfg;
276
  IntraSearch           m_cIntraSearch;
277
  InterSearch           m_cInterSearch;
278
  RdCost                m_cRdCost;
279
  LoopFilter            m_cLoopFilter;
280
281
  CABACWriter*          m_CABACEstimator;
282
  EncModeCtrl           m_modeCtrl;
283
  TrQuant               m_cTrQuant;                          ///< transform & quantization
284
  RateCtrl*             m_pcRateCtrl;
285
286
  PelStorage            m_aTmpStorageLCU  [MAX_TMP_BUFS];     ///< used with CIIP, EDO, GEO
287
  PelStorage            m_acMergeTmpBuffer[MRG_MAX_NUM_CANDS];
288
289
  SortedPelUnitBufs<SORTED_BUFS>
290
                        m_SortedPelUnitBufs;
291
  FastGeoCostList       m_GeoCostList;
292
  static const MergeIdxPair
293
                        m_GeoModeTest[GEO_MAX_NUM_CANDS];
294
  double                m_mergeBestSATDCost;
295
296
  MotionInfo            m_subPuMiBuf[(MAX_CU_SIZE * MAX_CU_SIZE) >> (MIN_CU_LOG2 << 1)];
297
  
298
  Mv                    m_refinedMvdL0[MRG_MAX_NUM_CANDS][MAX_NUM_SUBCU_DMVR];
299
300
  double                m_sbtCostSave[2];
301
  // thread stuff
302
  Ctx*                  m_syncPicCtx;                        ///< context storage for state of contexts at the wavefront/WPP/entropy-coding-sync second CTU of tile-row used for estimation
303
  uint64_t              m_boundPicId;                        ///< PicEncState::id of the picture whose state is applied
304
  PelStorage            m_dbBuffer;
305
  
306
  Partitioner           m_partitioner;
307
308
  int                   m_bestBcwIdx[2];
309
  double                m_bestBcwCost[2];
310
311
  int                   m_MergeSimpleFlag;
312
  int                   m_tileIdx;
313
  int                   m_EDO;
314
315
  GeoComboCostList      m_comboList;
316
  MergeItemList         m_mergeItemList;
317
  std::array<Mv, MAX_NUM_SUBCU_DMVR>
318
                        m_subPuMvOffset[MRG_MAX_NUM_CANDS];
319
  Distortion            m_uiSadBestForQPA;
320
321
  static const double coefSquareCUsFasterFastMedium[2][5][2][2][2];
322
  static const double coefSquareCUsSlowSlower[2][5][2][5][2][2][2];
323
324
public:
325
  EncCu();
326
  virtual ~EncCu();
327
328
  // When otherTrQuant is given, the quantizer is created from that one's quantizer and shares its read-only
329
  // tables, such as the dependent quantization scan tables (see DepQuant::DepQuant).
330
  void  init                  ( const VVEncCfg& encCfg, const SPS& sps, std::vector<int>* const globalCtuQpVector, RateCtrl* pRateCtrl, TrQuant* otherTrQuant );
331
1.15k
  TrQuant& getTrQuant         ()                            { return m_cTrQuant; }
332
  void  setCtuEncRsrc         ( CABACWriter* cabacEstimator, CtxCache* ctxCache, ReuseUniMv* pReuseUniMv, BlkUniMvInfoBuffer* pBlkUniMvInfoBuffer, AffineProfList* pAffineProfList, IbcBvCand* pCachedBvs );
333
  void  destroy               ();
334
335
  // Applies the per-picture state unless this CU encoder already works on that picture.
336
  void  bindToPicture         ( const PicEncState& picState );
337
338
  // Derives the lambda of every component and the chroma distortion weights for a QP. The RD cost
339
  // has a single lambda, so the chroma weights account for the chroma QP mapping and offsets.
340
  static void deriveComponentLambdas( const VVEncCfg& encCfg, const Slice& slice, const double lambda, const int qp,
341
                                      double lambdas[MAX_NUM_COMP], double weights[MAX_NUM_COMP] );
342
343
  void encodeCtu              ( Picture* pic, int (&prevQP)[MAX_NUM_CH], uint32_t ctuXPosInCtus, uint32_t ctuYPosInCtus );
344
345
private:
346
  void  initPic               ( Picture* pic );
347
  void  initSlice             ( const Slice* slice );
348
  void  setUpLambda           ( Slice& slice, const double dLambda, const int iQP, const bool setSliceLambda, const bool saveUnadjusted);
349
  void  updateLambda          ( const Slice& slice, const double ctuLambda, const int ctuQP, const int newQP, const bool saveUnadjusted);
350
351
  void  xCompressCtu          ( CodingStructure& cs, const UnitArea& area, const unsigned ctuRsAddr, const int prevQP[] );
352
353
  void xCalDebCost            ( CodingStructure& cs, Partitioner& partitioner );
354
  Distortion xGetDistortionDb ( CodingStructure& cs, CPelBuf& org, CPelBuf& reco, const CompArea& compArea, bool beforeDb );
355
356
  void xCompressCU            ( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& pm );
357
  bool xCheckBestMode         ( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& pm, const EncTestMode& encTestmode, const bool useEDO = false );
358
359
  void xCheckRDCostIntra      ( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& pm, const EncTestMode& encTestMode );
360
  void xCheckRDCostInter      ( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& pm, const EncTestMode& encTestMode );
361
  void xCheckRDCostInterIMV   ( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& pm, const EncTestMode& encTestMode );
362
  void xCheckRDCostUnifiedMerge
363
                              ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm,       EncTestMode& encTestMode );
364
  void xCheckModeSplit        ( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& pm, const EncTestMode& encTestMode );
365
  void xCheckModeSplitInternal( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& pm, const EncTestMode& encTestMode, const ModeType modeTypeParent, bool& skipInterPass );
366
  void xReuseCachedResult     ( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& pm );
367
368
  void xCheckDQP              ( CodingStructure& cs, Partitioner& partitioner, bool bKeepCtx = false);
369
  void xEncodeDontSplit       ( CodingStructure& cs, Partitioner& partitioner);
370
371
  void xEncodeInterResidual   ( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& pm, const EncTestMode& encTestMode, 
372
                                int residualPass = 0, bool* bestHasNonResi = NULL, double* equBcwCost = NULL );
373
  
374
  void xInitLumaDeltaQpLUT    ();
375
376
  bool xIsBcwSkip( const CodingUnit& cu )
377
0
  {
378
0
    if( cu.slice->sliceType != VVENC_B_SLICE )
379
0
    {
380
0
      return true;
381
0
    }
382
0
    return( (m_pcEncCfg->m_QP > 32) && ((cu.slice->TLayer >= 4)
383
0
            || ((cu.refIdx[0] >= 0 && cu.refIdx[1] >= 0)
384
0
              && (  abs(cu.slice->poc - cu.slice->getRefPOC(REF_PIC_LIST_0, cu.refIdx[0])) == 1
385
0
                ||  abs(cu.slice->poc - cu.slice->getRefPOC(REF_PIC_LIST_1, cu.refIdx[1])) == 1
386
0
               ) )                     ));
387
0
  }
388
389
  uint64_t xCalcPuMeBits                 ( const CodingUnit& cu);
390
  double   xCalcDistortion               ( CodingStructure *&cur_CS, ChannelType chType, int BitDepth, int imv);
391
  int      xCheckMMVDCand                ( MmvdIdx& mmvdMergeCand, int& bestDir, int tempNum, double& bestCostOffset, double& bestCostMerge, double bestCostList );
392
  void     xCheckRDCostIBCMode           ( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& pm, const EncTestMode& encTestMode );
393
  void     xCheckRDCostIBCModeMerge2Nx2N ( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& partitioner, const EncTestMode& encTestMode );
394
395
396
  CodingUnit* getCuForInterPrediction ( CodingStructure* cs, const EncTestMode& encTestMode );
397
  unsigned int updateRdCheckingNum    ( MergeItemList&, double threshold, unsigned int numMergeSatdCand );
398
399
  void    generateMergePrediction     ( const UnitArea& unitArea, MergeItem* mergeItem, CodingUnit& cu, bool luma, bool chroma,
400
                                        PelUnitBuf& dstBuf, bool finalRd, bool forceNoResidual, PelUnitBuf* predBuf1, PelUnitBuf* predBuf2 );
401
  double  calcLumaCost4MergePrediction( const TempCtx& ctxStart, const PelUnitBuf& predBuf, double lambda, CodingUnit& pu, DistParam& distParam );
402
  void    addRegularCandsToPruningList( const MergeCtx& mergeCtx, const UnitArea& localUnitArea, double sqrtLambdaForFirstPassIntra,
403
                                        const TempCtx& ctxStart, DistParam& distParam, CodingUnit& cu, bool* sameMv, MergeBufVector& regularPred );
404
  void    addCiipCandsToPruningList   ( const MergeCtx& mergeCtx, const UnitArea& localUnitArea, double sqrtLambdaForFirstPassIntra,
405
                                        const TempCtx& ctxStart, DistParam& distParam, CodingUnit& cu, bool* sameMv );
406
  void    addMmvdCandsToPruningList   ( const MergeCtx& mergeCtx, const UnitArea& localUnitArea, double sqrtLambdaForFirstPassIntra,
407
                                        const TempCtx& ctxStart, DistParam& distParam, CodingUnit& cu );
408
  void    addAffineCandsToPruningList ( AffineMergeCtx& affineMergeCtx, const UnitArea& localUnitArea, double sqrtLambdaForFirstPass,
409
                                        const TempCtx& ctxStart, DistParam& distParam, CodingUnit& cu );
410
  void    addGpmCandsToPruningList    ( const MergeCtx& mergeCtx, const UnitArea& localUnitArea, double sqrtLambdaForFirstPass,
411
                                        const TempCtx& ctxStart, const GeoComboCostList& comboList, MergeBufVector& geoBuffer, DistParam& distParam, CodingUnit& cu );
412
413
  bool    prepareGpmComboList         ( const MergeCtx& mergeCtx, const UnitArea& localUnitArea, double sqrtLambdaForFirstPass,
414
                                        GeoComboCostList& comboList, MergeBufVector& geoBuffer, CodingUnit& cu );
415
  // TODO: for now skip that
416
  //void    checkEarlySkip              ( const CodingStructure* bestCS, const Partitioner &partitioner );
417
};
418
419
} // namespace vvenc
420
421
//! \}
422