Coverage Report

Created: 2026-05-30 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvenc/source/Lib/EncoderLib/EncGOP.cpp
Line
Count
Source
1
/* -----------------------------------------------------------------------------
2
The copyright in this software is being made available under the Clear BSD
3
License, included below. No patent rights, trademark rights and/or 
4
other Intellectual Property Rights other than the copyrights concerning 
5
the Software are granted under this license.
6
7
The Clear BSD License
8
9
Copyright (c) 2019-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVenC Authors.
10
All rights reserved.
11
12
Redistribution and use in source and binary forms, with or without modification,
13
are permitted (subject to the limitations in the disclaimer below) provided that
14
the following conditions are met:
15
16
     * Redistributions of source code must retain the above copyright notice,
17
     this list of conditions and the following disclaimer.
18
19
     * Redistributions in binary form must reproduce the above copyright
20
     notice, this list of conditions and the following disclaimer in the
21
     documentation and/or other materials provided with the distribution.
22
23
     * Neither the name of the copyright holder nor the names of its
24
     contributors may be used to endorse or promote products derived from this
25
     software without specific prior written permission.
26
27
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
28
THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
29
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
31
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
32
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
36
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38
POSSIBILITY OF SUCH DAMAGE.
39
40
41
------------------------------------------------------------------------------------------- */
42
43
44
/** \file     EncGOP.cpp
45
    \brief    GOP encoder class
46
*/
47
48
#include "EncGOP.h"
49
#include "CommonLib/SEI.h"
50
#include "CommonLib/UnitTools.h"
51
#include "CommonLib/dtrace_codingstruct.h"
52
#include "CommonLib/dtrace_buffer.h"
53
#include "CommonLib/TimeProfiler.h"
54
#include "CommonLib/MD5.h"
55
#include "NALwrite.h"
56
#include "BitAllocation.h"
57
#include "EncHRD.h"
58
#include "GOPCfg.h"
59
60
#include <list>
61
62
//! \ingroup EncoderLib
63
//! \{
64
65
namespace vvenc {
66
67
#ifdef TRACE_ENABLE_ITT
68
static __itt_string_handle* itt_handle_start = __itt_string_handle_create( "Start" );
69
static __itt_domain* itt_domain_gopEncoder   = __itt_domain_create( "GOPEncoder" );
70
#endif
71
72
// ====================================================================================================================
73
// fast forward decoder in encoder
74
// ====================================================================================================================
75
76
void initPicAuxQPOffsets( const Slice* slice, const bool isBIM ) // get m_picShared->m_picAuxQpOffset and m_picShared->m_ctuBimQpOffset if unavailable
77
1.29k
{
78
1.29k
  const Picture* slicePic = slice->pic;
79
80
1.29k
  if (isBIM && slicePic && slicePic->m_picShared->m_ctuBimQpOffset.empty())
81
1.29k
  {
82
1.29k
    const Picture* refPicL0 = slice->getRefPic (REF_PIC_LIST_0, 0);
83
1.29k
    const Picture* refPicL1 = slice->getRefPic (REF_PIC_LIST_1, 0);
84
85
1.29k
    if (refPicL0 && !refPicL0->m_picShared->m_ctuBimQpOffset.empty() &&
86
0
        refPicL1 && !refPicL1->m_picShared->m_ctuBimQpOffset.empty() &&
87
0
        refPicL0->m_picShared->m_ctuBimQpOffset.size() == refPicL1->m_picShared->m_ctuBimQpOffset.size())
88
0
    {
89
0
      const PicShared* pic0 = refPicL0->m_picShared;
90
0
      const PicShared* pic1 = refPicL1->m_picShared;
91
0
      PicShared* const picC = slicePic->m_picShared;
92
0
      const int32_t  numCtu = (int32_t) pic0->m_ctuBimQpOffset.size();
93
0
      int i, sumCtuQpOffset = 0;
94
95
0
      picC->m_ctuBimQpOffset.resize (numCtu);
96
97
0
      for (i = 0; i < numCtu; i++) // scale and merge QPs
98
0
      {
99
0
        const int qpOffset0 = pic0->m_ctuBimQpOffset[i] + pic0->m_picAuxQpOffset; // CTU delta-QP #1
100
0
        const int qpOffset1 = pic1->m_ctuBimQpOffset[i] + pic1->m_picAuxQpOffset; // CTU delta-QP #2
101
0
        const int qpOffsetC = (3 * qpOffset0 + 3 * qpOffset1 + (qpOffset0 + qpOffset1 < 0 ? 3 : 4)) >> 3; // 3 instead of 4 for correct rounding to -2
102
103
0
        picC->m_ctuBimQpOffset[i] = qpOffsetC;
104
0
        sumCtuQpOffset += qpOffsetC;
105
0
      }
106
107
0
      picC->m_picAuxQpOffset = (sumCtuQpOffset + (sumCtuQpOffset < 0 ? -(numCtu >> 1) : numCtu >> 1)) / numCtu; // pic average; delta-QP scaling: 0.75
108
0
      for (i = 0; i < numCtu; i++) // excl. average again
109
0
      {
110
0
        picC->m_ctuBimQpOffset[i] -= picC->m_picAuxQpOffset; // delta-QP relative to the aux average
111
0
      }
112
0
    }
113
1.29k
  }
114
1.29k
}
115
116
117
// ====================================================================================================================
118
// Constructor / destructor / initialization / destroy
119
// ====================================================================================================================
120
121
EncGOP::EncGOP( MsgLog& logger )
122
1.29k
  : msg                  ( logger )
123
1.29k
  , m_recYuvBufFunc      ( nullptr )
124
1.29k
  , m_recYuvBufCtx       ( nullptr )
125
1.29k
  , m_threadPool         ( nullptr )
126
1.29k
  , m_pcEncCfg           ( nullptr )
127
1.29k
  , m_gopCfg             ( nullptr )
128
1.29k
  , m_pcRateCtrl         ( nullptr )
129
1.29k
  , m_spsMap             ( MAX_NUM_SPS )
130
1.29k
  , m_ppsMap             ( MAX_NUM_PPS )
131
1.29k
  , m_isPreAnalysis      ( false )
132
1.29k
  , m_bFirstWrite        ( true )
133
1.29k
  , m_bRefreshPending    ( false )
134
1.29k
  , m_disableLMCSIP      ( false )
135
1.29k
  , m_lastCodingNum      ( -1 )
136
1.29k
  , m_numPicsCoded       ( 0 )
137
1.29k
  , m_numPicsInMissing   ( 0 )
138
1.29k
  , m_numPicsOutOffset   ( 0 )
139
1.29k
  , m_lastCts            ( 0 )
140
1.29k
  , m_pocRecOut          ( 0 )
141
1.29k
  , m_ticksPerFrameMul4  ( 0 )
142
1.29k
  , m_lastIDR            ( 0 )
143
1.29k
  , m_lastRasPoc         ( MAX_INT )
144
1.29k
  , m_pocCRA             ( 0 )
145
1.29k
  , m_associatedIRAPPOC  ( 0 )
146
1.29k
  , m_associatedIRAPType ( VVENC_NAL_UNIT_CODED_SLICE_IDR_N_LP )
147
1.29k
{
148
1.29k
}
149
150
EncGOP::~EncGOP()
151
1.29k
{
152
1.29k
  freePicList();
153
154
1.29k
  for( auto& picEncoder : m_freePicEncoderList )
155
5.19k
  {
156
5.19k
    if( picEncoder )
157
5.19k
    {
158
5.19k
      delete picEncoder;
159
5.19k
    }
160
5.19k
  }
161
1.29k
  m_freePicEncoderList.clear();
162
1.29k
  m_threadPool = nullptr;
163
164
1.29k
  if ( m_pcEncCfg->m_fga )
165
0
  {
166
0
    m_fgAnalyzer.destroy();
167
0
  }
168
169
  // cleanup parameter sets
170
1.29k
  m_spsMap.clearMap();
171
1.29k
  m_ppsMap.clearMap();
172
173
1.29k
  for( auto& p : m_globalApsList ) delete p;
174
1.29k
  m_globalApsList.clear();
175
1.29k
}
176
177
void EncGOP::init( const VVEncCfg& encCfg, const GOPCfg* gopCfg, RateCtrl& rateCtrl, NoMallocThreadPool* threadPool, bool isPreAnalysis )
178
1.29k
{
179
1.29k
  m_pcEncCfg      = &encCfg;
180
1.29k
  m_gopCfg        = gopCfg;
181
1.29k
  m_pcRateCtrl    = &rateCtrl;
182
1.29k
  m_threadPool    = threadPool;
183
1.29k
  m_isPreAnalysis = isPreAnalysis;
184
185
  // setup parameter sets
186
1.29k
  const int dciId = m_pcEncCfg->m_decodingParameterSetEnabled ? 1 : 0;
187
1.29k
  SPS& sps0       = *( m_spsMap.allocatePS( 0 ) ); // NOTE: implementations that use more than 1 SPS need to be aware of activation issues.
188
1.29k
  PPS& pps0       = *( m_ppsMap.allocatePS( 0 ) );
189
190
1.29k
  xInitSPS( sps0 );
191
1.29k
  sps0.dciId = m_DCI.dciId;
192
1.29k
  xInitVPS( m_VPS );
193
1.29k
  xInitDCI( m_DCI, sps0, dciId );
194
1.29k
  xInitPPS( pps0, sps0 );
195
1.29k
  xInitRPL( sps0 );
196
1.29k
  xInitHrdParameters( sps0 );
197
198
1.29k
  if ( encCfg.m_fga )
199
0
  {
200
0
    m_fgAnalyzer.init( m_pcEncCfg->m_PadSourceWidth, m_pcEncCfg->m_PadSourceHeight,
201
0
                       m_pcEncCfg->m_internChromaFormat, m_pcEncCfg->m_outputBitDepth,
202
0
                       m_pcEncCfg->m_fg.m_fgcSEICompModelPresent );
203
0
  }
204
205
1.29k
  if( !m_pcEncCfg->m_poc0idr )
206
1.29k
  {
207
1.29k
    m_associatedIRAPType = VVENC_NAL_UNIT_CODED_SLICE_IDR_W_RADL;
208
1.29k
  }
209
1.29k
  m_seiEncoder.init( encCfg, gopCfg, m_EncHRD );
210
1.29k
  m_Reshaper.init  ( encCfg );
211
212
1.29k
  const int maxPicEncoder = ( encCfg.m_maxParallelFrames ) ? encCfg.m_maxParallelFrames : 1;
213
6.49k
  for ( int i = 0; i < maxPicEncoder; i++ )
214
5.19k
  {
215
5.19k
    EncPicture* picEncoder = new EncPicture;
216
5.19k
    picEncoder->init( encCfg, &m_globalCtuQpVector, sps0, pps0, rateCtrl, threadPool );
217
5.19k
    m_freePicEncoderList.push_back( picEncoder );
218
5.19k
  }
219
220
1.29k
  if (encCfg.m_usePerceptQPA)
221
1.29k
  {
222
1.29k
    m_globalCtuQpVector.resize( pps0.useDQP && (encCfg.m_internalUsePerceptQPATempFiltISlice == 2) && encCfg.m_salienceBasedOpt ? pps0.picWidthInCtu * pps0.picHeightInCtu + 1 : 1 );
223
1.29k
  }
224
225
1.29k
  if( m_pcEncCfg->m_FrameRate && m_pcEncCfg->m_TicksPerSecond > 0 )
226
1.29k
  {
227
1.29k
    m_ticksPerFrameMul4 = (int)((int64_t)4 *(int64_t)m_pcEncCfg->m_TicksPerSecond * (int64_t)m_pcEncCfg->m_FrameScale/(int64_t)m_pcEncCfg->m_FrameRate);
228
1.29k
  }
229
1.29k
  m_forceSCC = false;
230
1.29k
  m_rcap.reset();
231
1.29k
}
232
233
234
// ====================================================================================================================
235
// Class interface
236
// ====================================================================================================================
237
238
239
void EncGOP::setRecYUVBufferCallback( void* ctx, std::function<void( void*, vvencYUVBuffer* )> func )
240
1.29k
{
241
1.29k
  m_recYuvBufCtx  = ctx;
242
1.29k
  m_recYuvBufFunc = func;
243
1.29k
}
244
245
void EncGOP::initPicture( Picture* pic )
246
1.29k
{
247
1.29k
  pic->encTime.startTimer();
248
249
1.29k
  pic->TLayer = pic->gopEntry->m_temporalId;
250
1.29k
  if( pic->ctsValid )
251
1.29k
  {
252
1.29k
    if( m_lastCts )
253
0
    {
254
0
      int64_t ticksPerFrame = m_ticksPerFrameMul4/4;
255
0
      int64_t expectedCtsDiff = (m_pcEncCfg->m_TicksPerSecond > 0 ) ? ticksPerFrame : 1;
256
0
      int64_t ctsDiff = pic->cts - m_lastCts;
257
258
0
      if( ctsDiff >= (expectedCtsDiff<<1) || ctsDiff < 0 )
259
0
      {
260
        // signalize that frames are missing at that particular picture
261
0
        pic->picOutOffset = (m_pcEncCfg->m_TicksPerSecond > 0 ) ? (ctsDiff - ticksPerFrame)/ticksPerFrame : ctsDiff-1;
262
0
        m_numPicsInMissing += pic->picOutOffset;
263
0
      }
264
0
    }
265
1.29k
    m_lastCts = pic->cts;
266
1.29k
  }
267
1.29k
  if( m_numPicsInMissing )
268
0
  {
269
0
    pic->picsInMissing = m_numPicsInMissing;
270
0
  }
271
272
1.29k
  pic->setSccFlags( m_pcEncCfg );
273
274
1.29k
  CHECK( m_ppsMap.getFirstPS() == nullptr || m_spsMap.getPS( m_ppsMap.getFirstPS()->spsId ) == nullptr, "picture set not initialised" );
275
276
1.29k
  const PPS& pps = *( m_ppsMap.getFirstPS() );
277
1.29k
  const SPS& sps = *( m_spsMap.getPS( pps.spsId ) );
278
279
1.29k
  if( pic->cs && pic->cs->picHeader )
280
0
  {
281
0
    delete pic->cs->picHeader;
282
0
    pic->cs->picHeader = nullptr;
283
0
  }
284
285
1.29k
  std::mutex* mutex = ( m_pcEncCfg->m_maxParallelFrames ) ? &m_unitCacheMutex : nullptr;
286
1.29k
  pic->finalInit( m_VPS, sps, pps, nullptr, m_shrdUnitCache, mutex, nullptr, nullptr );
287
288
1.29k
  pic->vps = &m_VPS;
289
1.29k
  pic->dci = &m_DCI;
290
291
  // filter data initialization
292
1.29k
  const uint32_t numberOfCtusInFrame = pic->cs->pcv->sizeInCtus;
293
294
1.29k
  if( m_pcEncCfg->m_usePerceptQPA )
295
1.29k
  {
296
1.29k
    pic->ctuQpaLambda.resize (numberOfCtusInFrame);
297
1.29k
    pic->ctuAdaptedQP.resize (numberOfCtusInFrame);
298
1.29k
  }
299
300
1.29k
  if( pic->cs->sps->saoEnabled )
301
1.29k
  {
302
1.29k
    pic->resizeSAO( numberOfCtusInFrame, 0 );
303
1.29k
    pic->resizeSAO( numberOfCtusInFrame, 1 );
304
1.29k
  }
305
306
1.29k
  if( pic->cs->sps->alfEnabled )
307
1.29k
  {
308
1.29k
    pic->resizeAlfCtuBuffers( numberOfCtusInFrame );
309
1.29k
  }
310
311
1.29k
  pic->encTime.stopTimer();
312
1.29k
}
313
314
void EncGOP::waitForFreeEncoders()
315
1.29k
{
316
1.29k
  {
317
1.29k
    std::unique_lock<std::mutex> lock( m_gopEncMutex );
318
1.29k
    if( ! xEncodersFinished() )
319
1.29k
    {
320
1.29k
      CHECK( m_pcEncCfg->m_numThreads <= 0, "run into MT code, but no threading enabled" );
321
1.29k
      m_gopEncCond.wait( lock );
322
1.29k
    }
323
1.29k
  }
324
1.29k
}
325
326
void EncGOP::processPictures( const PicList& picList, AccessUnitList& auList, PicList& doneList, PicList& freeList )
327
2.59k
{
328
2.59k
  CHECK( picList.empty(), "empty input picture list given" );
329
330
  // create list of pictures ordered in coding order and ready to be encoded
331
2.59k
  xInitPicsInCodingOrder( picList );
332
333
  // encode pictures
334
2.59k
  xProcessPictures( auList, doneList );
335
336
  // output reconstructed YUV
337
2.59k
  xOutputRecYuv( picList );
338
339
  // release pictures not needed anymore
340
2.59k
  xReleasePictures( picList, freeList );
341
342
  // clear output access unit
343
2.59k
  if( m_isPreAnalysis )
344
0
  {
345
0
    auList.clearAu();
346
0
  }
347
2.59k
}
348
349
void EncGOP::xProcessPictures( AccessUnitList& auList, PicList& doneList )
350
2.59k
{
351
  // in lockstep mode, process all pictures in processing list
352
2.59k
  const bool lockStepMode = (m_pcEncCfg->m_RCTargetBitrate > 0 || (m_pcEncCfg->m_LookAhead > 0 && !m_isPreAnalysis)) && (m_pcEncCfg->m_maxParallelFrames > 0);
353
354
  // get list of pictures to be encoded and used for RC update
355
2.59k
  CHECK( m_pcEncCfg->m_rateCap && lockStepMode, "Rate capping should not be used in lockstep mode" );
356
  // rate cap and MT: finish the previous GOP before processing the next one
357
2.59k
  const bool rateCapPrevGopConstr = m_pcEncCfg->m_rateCap && !m_rcUpdateList.empty();
358
359
2.59k
  if( m_procList.empty() && (!m_gopEncListInput.empty() || !m_rcInputReorderList.empty()) && !rateCapPrevGopConstr )
360
1.29k
  {
361
1.29k
    xGetProcessingLists( m_procList, m_rcUpdateList, lockStepMode );
362
1.29k
  }
363
364
2.59k
  if( ! m_procList.empty() )
365
1.29k
  {
366
    // encode one picture in serial mode / multiple pictures in FPP mode
367
1.29k
    PROFILER_ACCUM_AND_START_NEW_SET( 1, g_timeProfiler, P_IGNORE );
368
2.59k
    while( true )
369
2.59k
    {
370
2.59k
      Picture* pic           = nullptr;
371
2.59k
      EncPicture* picEncoder = nullptr;
372
373
      // fetch next picture to be encoded and next free picture encoder
374
2.59k
      {
375
2.59k
        std::unique_lock<std::mutex> lock( m_gopEncMutex, std::defer_lock );
376
2.59k
        if( m_pcEncCfg->m_numThreads > 0) lock.lock();
377
378
        // leave the loop when nothing to do (when all encoders are finished or in non-blocking mode)
379
2.59k
        if( m_procList.empty() && ( isNonBlocking() || xEncodersFinished() ) )
380
1.29k
        {
381
1.29k
          break;
382
1.29k
        }
383
384
        // get next picture ready to be encoded
385
        // if ALF enabled and ALFTempPred is used, ensure that refAps is initialized
386
        // rate capping and MT frame parallel: in the first GOP after scene cut, ensure that the two first frames of 
387
        //                                     this GOP are finished. Their data will be used to adjust the QP of
388
        //                                     remaining frames of this scene-cut-GOP.
389
1.29k
        const std::list<Picture *>* rcUpdateList = &m_rcUpdateList;
390
1.29k
        const VVEncCfg* encCfg = m_pcEncCfg;
391
1.29k
        auto picItr            = find_if( m_procList.begin(), m_procList.end(), [encCfg, rcUpdateList]( auto pic ) {
392
1.29k
          return ( encCfg->m_ifp || pic->slices[ 0 ]->checkAllRefPicsReconstructed() )
393
1.29k
            && ( !encCfg->m_alf || ( !pic->refApsGlobal || pic->refApsGlobal->initalized ) )
394
1.29k
            && ( !encCfg->m_rateCap || !encCfg->m_maxParallelFrames || !pic->isSceneCutGOP || (!rcUpdateList->front()->isSceneCutCheckAdjQP && !rcUpdateList->front()->gopEntry->m_isStartOfGop ) )
395
1.29k
            ; } );
396
397
1.29k
        const bool nextPicReady = picItr != m_procList.end();
398
399
        // check at least one picture and one pic encoder ready
400
1.29k
        if( m_freePicEncoderList.empty() || ! nextPicReady )
401
0
        {
402
          // non-blocking stage: wait on top level, let other stages do their jobs
403
          // in non-lockstep mode, check if next picture can be output
404
0
          if( isNonBlocking() || ( ! lockStepMode && m_gopEncListOutput.front()->isReconstructed ) )
405
0
          {
406
0
            break;
407
0
          }
408
0
          CHECK( m_pcEncCfg->m_numThreads <= 0, "run into MT code, but no threading enabled" );
409
0
          CHECK( xEncodersFinished(), "wait for picture to be finished, but no pic encoder running" );
410
0
          m_gopEncCond.wait( lock );
411
0
          continue;
412
0
        }
413
414
1.29k
        pic = *picItr;
415
1.29k
        picEncoder = m_freePicEncoderList.front();
416
417
        // rate-control with look-ahead: init next chunk
418
1.29k
        if( m_pcEncCfg->m_RCTargetBitrate > 0 && m_pcEncCfg->m_LookAhead )
419
0
        {
420
0
          CHECK( m_isPreAnalysis, "rate control enabled for pre analysis" );
421
422
0
          if( pic->isFlush )
423
0
          {
424
0
            m_pcRateCtrl->setRCRateSavingState(0); // tell budget estimation that end of video is near
425
0
          }
426
0
          if( pic->gopEntry->m_isStartOfGop )
427
0
          {
428
            // check the RC final pass requirement for availability of preprocessed pictures (GOP + 1)
429
0
            if( m_pcRateCtrl->lastPOCInCache() <= pic->poc && ! pic->isFlush )
430
0
            {
431
0
              break;
432
0
            }
433
0
            m_pcRateCtrl->processFirstPassData( pic->isFlush, pic->poc );
434
0
          }
435
0
        }
436
437
1.29k
        m_freePicEncoderList.pop_front();
438
1.29k
      }
439
440
1.29k
      CHECK( picEncoder == nullptr, "no free picture encoder available" );
441
1.29k
      CHECK( pic        == nullptr, "no picture to be encoded, ready for encoding" );
442
1.29k
      m_procList.remove( pic );
443
444
1.29k
      xEncodePicture( pic, picEncoder );
445
1.29k
    }
446
1.29k
  }
447
448
2.59k
  if( lockStepMode && m_pcEncCfg->m_ifpLines && !m_rcUpdateList.empty() )
449
0
  {
450
0
    xUpdateRcIfp();
451
0
  }
452
453
2.59k
  if( m_pcEncCfg->m_rateCap )
454
0
  {
455
0
    xUpdateRateCap();
456
0
  }
457
458
  // picture/AU output
459
  // 
460
  // in lock-step mode:
461
  // the output of a picture is connected to evaluation of the lock-step-chunk
462
  // if the next picture to output belongs to the current chunk, do output (evaluation) when all pictures of the chunk are finished
463
464
2.59k
  if( m_gopEncListOutput.empty() || !m_gopEncListOutput.front()->isReconstructed ||
465
1.29k
    ( lockStepMode && !m_pcEncCfg->m_ifpLines && !m_rcUpdateList.empty() && m_gopEncListOutput.front() == m_rcUpdateList.front() && !xLockStepPicsFinished() ) )
466
1.29k
  {
467
1.29k
    return;
468
1.29k
  }
469
1.29k
  PROFILER_ACCUM_AND_START_NEW_SET( 1, g_timeProfiler, P_TOP_LEVEL );
470
471
  // AU output
472
1.29k
  Picture* outPic = m_gopEncListOutput.front();
473
1.29k
  m_gopEncListOutput.pop_front();
474
475
1.29k
  xWritePicture( *outPic, auList, false );
476
477
  // update pending RC
478
  // first pic has been written to bitstream
479
  // therefore we have at least for this picture a valid total bit and head bit count
480
1.29k
  if( !m_rcUpdateList.empty() && m_rcUpdateList.front() == outPic && (!lockStepMode || !m_pcEncCfg->m_ifpLines)  )
481
0
  {
482
0
    if( m_pcEncCfg->m_RCTargetBitrate > 0 )
483
0
    {
484
0
      for( auto pic : m_rcUpdateList )
485
0
      {
486
0
        if( pic != outPic )
487
0
        {
488
0
          pic->actualHeadBits  = outPic->actualHeadBits;
489
0
          pic->actualTotalBits = pic->sliceDataStreams[0].getNumberOfWrittenBits();
490
0
        }
491
0
        m_pcRateCtrl->updateAfterPicEncRC( pic );
492
0
      }
493
0
    }
494
495
0
    if( lockStepMode )
496
0
      m_rcUpdateList.clear();
497
0
    else
498
0
      m_rcUpdateList.pop_front();
499
0
  }
500
501
1.29k
  const bool skipFirstPass = ( ! m_pcRateCtrl->rcIsFinalPass || m_isPreAnalysis ) && outPic->gopEntry->m_skipFirstPass;
502
1.29k
  if( m_pcEncCfg->m_useAMaxBT && ! skipFirstPass )
503
0
  {
504
0
    m_BlkStat.updateMaxBT( *outPic->slices[0], outPic->picBlkStat );
505
0
  }
506
507
1.29k
  outPic->slices[ 0 ]->updateRefPicCounter( -1 );
508
1.29k
  outPic->isFinished = true;
509
510
1.29k
  if( ! m_isPreAnalysis )
511
1.29k
  {
512
1.29k
    outPic->getFilteredOrigBuffer().destroy();
513
1.29k
  }
514
515
1.29k
  doneList.push_back( outPic );
516
517
1.29k
  m_numPicsCoded += 1;
518
1.29k
}
519
520
void EncGOP::xSyncAlfAps( Picture& pic )
521
1.29k
{
522
1.29k
  Slice& slice = *pic.cs->slice;
523
1.29k
  const bool mtPicParallel = m_pcEncCfg->m_numThreads > 0;
524
525
1.29k
  if( mtPicParallel && slice.isIntra() )
526
1.29k
  {
527
    // reset APS propagation on Intra-Slice in MT-mode
528
1.29k
    return;
529
1.29k
  }
530
531
0
  const PicApsGlobal* refAps = pic.refApsGlobal;
532
0
  if( !refAps )
533
0
    return;
534
0
  CHECK( !refAps->initalized, "Attempt referencing from an uninitialized APS" );
535
0
  pic.refApsGlobal->refCnt--;
536
0
  CHECK( pic.refApsGlobal->refCnt < 0, "Not expected APS ref. counter\n" );
537
538
  // copy ref APSs to current picture
539
0
  const ParameterSetMap<APS>& src = refAps->apsMap;
540
0
  ParameterSetMap<APS>&       dst = pic.picApsMap;
541
0
  if( mtPicParallel && pic.TLayer == 0 )
542
0
  {
543
    // in pic.parallel case, due to limited number of APS IDs, limit propagation of TID-0 APS
544
0
    CHECK( slice.sps->maxTLayers > ALF_CTB_MAX_NUM_APS, "Not enough space for ALF APSs in MT mode: not supported"  )
545
0
    int numApsTID0 = ALF_CTB_MAX_NUM_APS - (int)slice.sps->maxTLayers;
546
0
    int lastTakenApsPOC = pic.poc;
547
0
    while( numApsTID0 > 0 )
548
0
    {
549
0
      const APS* candAPS = nullptr;
550
0
      int candMapIdx = 0;
551
0
      for( int i = 0; i < ALF_CTB_MAX_NUM_APS; i++ )
552
0
      {
553
0
        const int mapIdx = ( i << NUM_APS_TYPE_LEN ) + ALF_APS;
554
0
        const APS* srcAPS = src.getPS( mapIdx );
555
0
        if( srcAPS && srcAPS->apsId != MAX_UINT && srcAPS->poc < lastTakenApsPOC && ( !candAPS || srcAPS->poc > candAPS->poc ) )
556
0
        {
557
0
          candAPS = srcAPS;
558
0
          candMapIdx = mapIdx;
559
0
        }
560
0
      }
561
0
      if( !candAPS )
562
0
        break;
563
564
0
      APS* dstAPS = dst.allocatePS( candMapIdx );
565
0
      *dstAPS = *candAPS;
566
0
      dst.clearChangedFlag( candMapIdx );
567
0
      lastTakenApsPOC = candAPS->poc;
568
0
      numApsTID0--;
569
0
    }
570
0
  }
571
0
  else
572
0
  {
573
0
    for( int i = 0; i < ALF_CTB_MAX_NUM_APS; i++ )
574
0
    {
575
0
      const int apsMapIdx = ( i << NUM_APS_TYPE_LEN ) + ALF_APS;
576
0
      const APS* srcAPS = src.getPS( apsMapIdx );
577
0
      if( srcAPS )
578
0
      {
579
0
        APS* dstAPS = dst.allocatePS( apsMapIdx );
580
0
        *dstAPS = *srcAPS;
581
0
        dst.clearChangedFlag( apsMapIdx );
582
0
      }
583
0
    }
584
0
  }
585
0
  dst.setApsIdStart( src.getApsIdStart() );
586
0
}
587
588
void EncGOP::xEncodePicture( Picture* pic, EncPicture* picEncoder )
589
1.29k
{
590
  // first pass temporal down-sampling
591
1.29k
  if( ( ! m_pcRateCtrl->rcIsFinalPass || m_isPreAnalysis ) && pic->gopEntry->m_skipFirstPass )
592
0
  {
593
0
    pic->isReconstructed = true;
594
0
    m_freePicEncoderList.push_back( picEncoder );
595
0
    return;
596
0
  }
597
598
  // decoder in encoder
599
1.29k
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "finalpass", m_pcRateCtrl->rcIsFinalPass ? 1: 0 ) );
600
601
1.29k
  if( m_pcEncCfg->m_alf && m_pcEncCfg->m_alfTempPred )
602
1.29k
  {
603
    // Establish reference APS for current picture
604
1.29k
    xSyncAlfAps( *pic );
605
1.29k
  }
606
607
  // initialize next picture
608
1.29k
  pic->isPreAnalysis = m_isPreAnalysis;
609
610
1.29k
  if( pic->slices[0]->TLayer + 1 < m_pcEncCfg->m_maxTLayer ) // skip for highest two temporal levels
611
1.29k
  {
612
1.29k
    initPicAuxQPOffsets( pic->slices[0], m_pcEncCfg->m_blockImportanceMapping );
613
1.29k
  }
614
615
1.29k
  if( m_pcEncCfg->m_RCTargetBitrate > 0 )
616
0
  {
617
0
    pic->picInitialQP     = -1;
618
0
    pic->picInitialLambda = -1.0;
619
620
0
    m_pcRateCtrl->initRateControlPic( *pic, pic->slices[0], pic->picInitialQP, pic->picInitialLambda );
621
0
  }
622
623
1.29k
  if( pic->isSceneCutGOP && !pic->isSceneCutCheckAdjQP && !pic->gopEntry->m_isStartOfGop && m_rcap.gopAdaptedQPAdj )
624
0
  {
625
0
    pic->gopAdaptedQP += m_rcap.gopAdaptedQPAdj;
626
0
  }
627
628
  // compress next picture
629
1.29k
  picEncoder->compressPicture( *pic, *this );
630
631
1.29k
  if ( m_pcEncCfg->m_fga && !m_isPreAnalysis && m_pcRateCtrl->rcIsFinalPass )
632
0
  {
633
    /* It is mctf denoising for film grain analysis. Note:
634
     * when mctf is used, it is different from mctf for encoding. */
635
0
    int curFrameNum = pic->getPOC();
636
0
    int gopSize = m_pcEncCfg->m_GOPSize;
637
0
    int prevAnalysedPoc = m_fgAnalyzer.prevAnalysisPoc;
638
0
    if ( ( prevAnalysedPoc == -1 ) || ( abs( curFrameNum - prevAnalysedPoc ) >= gopSize ) )
639
0
    {
640
0
      bool isFiltered = pic->getFilteredOrigBuffer().valid();
641
0
      if ( isFiltered )
642
0
      {
643
0
        m_fgAnalyzer.estimateGrainParameters( pic );
644
0
        m_fgAnalyzer.prevAnalysisPoc = curFrameNum;
645
0
      }
646
0
    }
647
0
  }
648
649
  // finish picture encoding and cleanup
650
1.29k
  if( m_pcEncCfg->m_numThreads > 0 )
651
1.29k
  {
652
1.29k
    static auto finishTask = []( int, void* task_param )
653
1.29k
    {
654
1.29k
      FinishTaskParam* param = static_cast<FinishTaskParam*>( task_param );
655
1.29k
      param->picEncoder->finalizePicture( *param->pic );
656
1.29k
      {
657
1.29k
        std::lock_guard<std::mutex> lock( param->gopEncoder->m_gopEncMutex );
658
1.29k
        param->pic->isReconstructed = true;
659
1.29k
        if( param->pic->picApsGlobal )
660
1.29k
          param->pic->picApsGlobal->initalized = true;
661
1.29k
        param->gopEncoder->m_freePicEncoderList.push_back( param->picEncoder );
662
1.29k
        param->gopEncoder->m_gopEncCond.notify_one();
663
1.29k
      }
664
1.29k
      delete param;
665
1.29k
      return true;
666
1.29k
    };
667
1.29k
    FinishTaskParam* param = new FinishTaskParam( this, picEncoder, pic );
668
1.29k
    m_threadPool->addBarrierTask( finishTask, param, nullptr, nullptr, { &picEncoder->m_ctuTasksDoneCounter.done } );
669
1.29k
  }
670
0
  else
671
0
  {
672
0
    picEncoder->finalizePicture( *pic );
673
0
    pic->isReconstructed = true;
674
0
    if( pic->picApsGlobal ) pic->picApsGlobal->initalized = true;
675
0
    m_freePicEncoderList.push_back( picEncoder );
676
0
  }
677
1.29k
}
678
679
void EncGOP::xOutputRecYuv( const PicList& picList )
680
2.59k
{
681
2.59k
  if( m_pcRateCtrl->rcIsFinalPass && m_recYuvBufFunc )
682
0
  {
683
0
    CHECK( m_isPreAnalysis, "yuv output enabled for pre analysis" );
684
    // ordered YUV output
685
0
    bool bRun = true;
686
0
    while( bRun )
687
0
    {
688
0
      bRun = false;
689
0
      for( auto pic : picList )
690
0
      {
691
0
        if( pic->poc != m_pocRecOut )
692
0
          continue;
693
0
        if( ! pic->isReconstructed )
694
0
          return;
695
696
0
        const PPS& pps = *(pic->cs->pps);
697
0
        vvencYUVBuffer yuvBuffer;
698
0
        vvenc_YUVBuffer_default( &yuvBuffer );
699
0
        setupYuvBuffer( pic->getRecoBuf(), yuvBuffer, &pps.conformanceWindow );
700
0
        yuvBuffer.sequenceNumber = pic->poc;
701
0
        m_recYuvBufFunc( m_recYuvBufCtx, &yuvBuffer );
702
703
0
        m_pocRecOut += 1;
704
0
        pic->isNeededForOutput = false;
705
0
        bRun = true;
706
0
        break;
707
0
      }
708
0
    }
709
0
  }
710
2.59k
  else
711
2.59k
  {
712
    // no output needed, simply unmark pictures
713
2.59k
    for( auto pic : picList )
714
2.59k
    {
715
2.59k
      if( pic->isReconstructed && pic->isNeededForOutput )
716
1.29k
        pic->isNeededForOutput = false;
717
2.59k
    }
718
2.59k
  }
719
2.59k
}
720
721
void EncGOP::xReleasePictures( const PicList& picList, PicList& freeList )
722
2.59k
{
723
2.59k
  const bool allPicsDone = m_numPicsCoded >= m_picCount && ( picList.empty() || picList.back()->isFlush );
724
2.59k
  for( auto pic : picList )
725
2.59k
  {
726
2.59k
    if( ( pic->isFinished && ! pic->isNeededForOutput && ! pic->isReferenced && pic->refCounter <= 0 ) || allPicsDone )
727
1.29k
      freeList.push_back( pic );
728
2.59k
  }
729
2.59k
}
730
731
void EncGOP::printOutSummary( const bool printMSEBasedSNR, const bool printSequenceMSE, const bool printHexPsnr )
732
0
{
733
  //--CFG_KDY
734
  //const int rateMultiplier = 1;
735
0
  double fps = m_pcEncCfg->m_FrameRate/(double)m_pcEncCfg->m_FrameScale;
736
0
  m_AnalyzeAll.setFrmRate( fps );
737
0
  m_AnalyzeI.setFrmRate( fps );
738
0
  m_AnalyzeP.setFrmRate( fps );
739
0
  m_AnalyzeB.setFrmRate( fps );
740
741
0
  const ChromaFormat chFmt = m_pcEncCfg->m_internChromaFormat;
742
743
0
  const BitDepths& bitDepths = m_spsMap.getFirstPS()->bitDepths;
744
  //-- all
745
0
  std::string summary( "\n" );
746
0
  if( m_pcEncCfg->m_verbosity >= VVENC_DETAILS )
747
0
    summary.append("\nvvenc [info]: SUMMARY --------------------------------------------------------\n");
748
749
0
  summary.append( m_AnalyzeAll.printOut('a', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, bitDepths));
750
751
0
  if( m_pcEncCfg->m_verbosity < VVENC_DETAILS )
752
0
  {
753
0
    msg.log( VVENC_INFO,summary.c_str() );
754
0
  }
755
0
  else
756
0
  {
757
0
    summary.append( "\n\nvvenc [info]: I Slices--------------------------------------------------------\n" );
758
0
    summary.append( m_AnalyzeI.printOut('i', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, bitDepths));
759
760
0
    summary.append( "\n\nvvenc [info]: P Slices--------------------------------------------------------\n" );
761
0
    summary.append( m_AnalyzeP.printOut('p', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, bitDepths));
762
763
0
    summary.append( "\n\nvvenc [info]: B Slices--------------------------------------------------------\n" );
764
0
    summary.append( m_AnalyzeB.printOut('b', chFmt, printMSEBasedSNR, printSequenceMSE, printHexPsnr, bitDepths));
765
0
    msg.log( VVENC_DETAILS,summary.c_str() );
766
0
  }
767
768
0
  if (m_pcEncCfg->m_summaryOutFilename[0] != '\0' )
769
0
  {
770
0
    std::string summaryOutFilename(m_pcEncCfg->m_summaryOutFilename);
771
0
    m_AnalyzeAll.printSummary(chFmt, printSequenceMSE, printHexPsnr, bitDepths, summaryOutFilename);
772
0
  }
773
774
0
  if (m_pcEncCfg->m_summaryPicFilenameBase[0] != '\0' )
775
0
  {
776
0
    std::string summaryPicFilenameBase(m_pcEncCfg->m_summaryPicFilenameBase);
777
778
0
    m_AnalyzeI.printSummary(chFmt, printSequenceMSE, printHexPsnr, bitDepths, summaryPicFilenameBase+"I.txt");
779
0
    m_AnalyzeP.printSummary(chFmt, printSequenceMSE, printHexPsnr, bitDepths, summaryPicFilenameBase+"P.txt");
780
0
    m_AnalyzeB.printSummary(chFmt, printSequenceMSE, printHexPsnr, bitDepths, summaryPicFilenameBase+"B.txt");
781
0
  }
782
0
}
783
784
void EncGOP::getParameterSets( AccessUnitList& accessUnit )
785
0
{
786
0
  CHECK( m_ppsMap.getFirstPS() == nullptr || m_spsMap.getPS( m_ppsMap.getFirstPS()->spsId ) == nullptr, "sps/pps not initialised" );
787
788
0
  const PPS& pps = *( m_ppsMap.getFirstPS() );
789
0
  const SPS& sps = *( m_spsMap.getPS( pps.spsId ) );
790
791
0
  if (sps.vpsId != 0)
792
0
  {
793
0
    xWriteVPS( accessUnit, &m_VPS, m_HLSWriter );
794
0
  }
795
0
  xWriteDCI( accessUnit, &m_DCI, m_HLSWriter );
796
0
  xWriteSPS( accessUnit, &sps, m_HLSWriter );
797
0
  xWritePPS( accessUnit, &pps, &sps, m_HLSWriter );
798
0
}
799
800
void EncGOP::xUpdateRasInit( Slice* slice )
801
1.29k
{
802
1.29k
  slice->pendingRasInit = false;
803
1.29k
  if ( slice->poc > m_lastRasPoc )
804
0
  {
805
0
    m_lastRasPoc = MAX_INT;
806
0
    slice->pendingRasInit = true;
807
0
  }
808
1.29k
  if ( slice->isIRAP() )
809
1.29k
  {
810
1.29k
    m_lastRasPoc = slice->poc;
811
1.29k
  }
812
1.29k
}
813
814
void EncGOP::xInitVPS(VPS &vps) const
815
1.29k
{
816
  // The SPS must have already been set up.
817
  // set the VPS profile information.
818
1.29k
  vps.maxLayers                   = 1;
819
1.29k
  vps.maxSubLayers                = 1;
820
1.29k
  vps.vpsId                       = 0;
821
1.29k
  vps.allLayersSameNumSubLayers   = true;
822
1.29k
  vps.allIndependentLayers        = true;
823
1.29k
  vps.eachLayerIsAnOls            = true;
824
1.29k
  vps.olsModeIdc                  = 0;
825
1.29k
  vps.numOutputLayerSets          = 1;
826
1.29k
  vps.numPtls                     = 1;
827
1.29k
  vps.extension                   = false;
828
1.29k
  vps.totalNumOLSs                = 0;
829
1.29k
  vps.numDpbParams                = 0;
830
1.29k
  vps.sublayerDpbParamsPresent    = false;
831
1.29k
  vps.targetOlsIdx                = -1;
832
833
84.3k
  for (int i = 0; i < MAX_VPS_LAYERS; i++)
834
83.0k
  {
835
83.0k
    vps.layerId[i]                = 0;
836
83.0k
    vps.independentLayer[i]       = true;
837
5.39M
    for (int j = 0; j < MAX_VPS_LAYERS; j++)
838
5.31M
    {
839
5.31M
      vps.directRefLayer[i][j]    = 0;
840
5.31M
      vps.directRefLayerIdx[i][j] = MAX_VPS_LAYERS;
841
5.31M
      vps.interLayerRefIdx[i][i]  = NOT_VALID;
842
5.31M
    }
843
83.0k
  }
844
845
333k
  for (int i = 0; i < MAX_NUM_OLSS; i++)
846
332k
  {
847
21.5M
    for (int j = 0; j < MAX_VPS_LAYERS; j++)
848
21.2M
    {
849
21.2M
      vps.olsOutputLayer[i][j]    = 0;
850
21.2M
    }
851
332k
    vps.ptPresent[i]              = (i == 0) ? 1 : 0;
852
332k
    vps.ptlMaxTemporalId[i]       = vps.maxSubLayers - 1;
853
332k
    vps.olsPtlIdx[i]              = 0;
854
332k
  }
855
856
1.29k
  vps.profileTierLevel.resize( 1 );
857
1.29k
}
858
859
void EncGOP::xInitDCI(DCI &dci, const SPS &sps, const int dciId) const
860
1.29k
{
861
  // The SPS must have already been set up.
862
  // set the DPS profile information.
863
1.29k
  dci.dciId                 = dciId;
864
865
1.29k
  dci.profileTierLevel.resize(1);
866
  // copy profile level tier info
867
1.29k
  dci.profileTierLevel[0]   = sps.profileTierLevel;
868
1.29k
}
869
870
void EncGOP::xInitConstraintInfo(ConstraintInfo &ci) const
871
1.29k
{
872
1.29k
  ci.intraOnlyConstraintFlag                      = m_pcEncCfg->m_intraOnlyConstraintFlag;
873
1.29k
  ci.maxBitDepthConstraintIdc                     = m_pcEncCfg->m_bitDepthConstraintValue - 8;
874
1.29k
  ci.maxChromaFormatConstraintIdc                 = m_pcEncCfg->m_internChromaFormat;
875
1.29k
  ci.onePictureOnlyConstraintFlag                 = false;
876
1.29k
  ci.lowerBitRateConstraintFlag                   = false;
877
1.29k
  ci.allLayersIndependentConstraintFlag           = false;
878
1.29k
  ci.noQtbttDualTreeIntraConstraintFlag           = ! m_pcEncCfg->m_dualITree;
879
1.29k
  ci.noPartitionConstraintsOverrideConstraintFlag = false;
880
1.29k
  ci.noSaoConstraintFlag                          = ! m_pcEncCfg->m_bUseSAO;
881
1.29k
  ci.noAlfConstraintFlag                          = ! m_pcEncCfg->m_alf;
882
1.29k
  ci.noCCAlfConstraintFlag                        = ! m_pcEncCfg->m_ccalf;
883
1.29k
  ci.noRefWraparoundConstraintFlag                = false;
884
1.29k
  ci.noTemporalMvpConstraintFlag                  = m_pcEncCfg->m_TMVPModeId == 0;
885
1.29k
  ci.noSbtmvpConstraintFlag                       = !m_pcEncCfg->m_SbTMVP;
886
1.29k
  ci.noAmvrConstraintFlag                         = false;
887
1.29k
  ci.noBdofConstraintFlag                         = ! m_pcEncCfg->m_BDOF;
888
1.29k
  ci.noDmvrConstraintFlag                         = ! m_pcEncCfg->m_DMVR;
889
1.29k
  ci.noCclmConstraintFlag                         = ! m_pcEncCfg->m_LMChroma;
890
1.29k
  ci.noMtsConstraintFlag                          = !(m_pcEncCfg->m_MTSImplicit || m_pcEncCfg->m_MTS);
891
1.29k
  ci.noSbtConstraintFlag                          = m_pcEncCfg->m_SBT == 0;
892
1.29k
  ci.noAffineMotionConstraintFlag                 = ! m_pcEncCfg->m_Affine;
893
1.29k
  ci.noBcwConstraintFlag                          = true;
894
1.29k
  ci.noIbcConstraintFlag                          = m_pcEncCfg->m_IBCMode == 0;
895
1.29k
  ci.noCiipConstraintFlag                         = m_pcEncCfg->m_CIIP == 0;
896
1.29k
  ci.noGeoConstraintFlag                          = m_pcEncCfg->m_Geo == 0;
897
1.29k
  ci.noLadfConstraintFlag                         = true;
898
1.29k
  ci.noTransformSkipConstraintFlag                = m_pcEncCfg->m_TS == 0;
899
1.29k
  ci.noBDPCMConstraintFlag                        = m_pcEncCfg->m_useBDPCM==0;
900
1.29k
  ci.noJointCbCrConstraintFlag                    = ! m_pcEncCfg->m_JointCbCrMode;
901
1.29k
  ci.noMrlConstraintFlag                          = ! m_pcEncCfg->m_MRL;
902
1.29k
  ci.noIspConstraintFlag                          = true;
903
1.29k
  ci.noMipConstraintFlag                          = ! m_pcEncCfg->m_MIP;
904
1.29k
  ci.noQpDeltaConstraintFlag                      = false;
905
1.29k
  ci.noDepQuantConstraintFlag                     = ! m_pcEncCfg->m_DepQuantEnabled;
906
1.29k
  ci.noMixedNaluTypesInPicConstraintFlag          = false;
907
1.29k
  ci.noSignDataHidingConstraintFlag               = ! m_pcEncCfg->m_SignDataHidingEnabled;
908
1.29k
  ci.noLfnstConstraintFlag                        = ! m_pcEncCfg->m_LFNST;
909
1.29k
  ci.noMmvdConstraintFlag                         = ! m_pcEncCfg->m_MMVD;
910
1.29k
  ci.noSmvdConstraintFlag                         = ! m_pcEncCfg->m_SMVD;
911
1.29k
  ci.noProfConstraintFlag                         = ! m_pcEncCfg->m_PROF;
912
1.29k
  ci.noPaletteConstraintFlag                      = true;
913
1.29k
  ci.noActConstraintFlag                          = true;
914
1.29k
  ci.noLmcsConstraintFlag                         = m_pcEncCfg->m_lumaReshapeEnable == 0;
915
1.29k
  ci.noTrailConstraintFlag                        = m_pcEncCfg->m_IntraPeriod == 1;
916
1.29k
  ci.noStsaConstraintFlag                         = m_pcEncCfg->m_IntraPeriod == 1 || ! m_gopCfg->hasNonZeroTemporalId();
917
1.29k
  ci.noRaslConstraintFlag                         = m_pcEncCfg->m_IntraPeriod == 1 || ! m_gopCfg->hasLeadingPictures();
918
1.29k
  ci.noRadlConstraintFlag                         = m_pcEncCfg->m_IntraPeriod == 1 || ! m_gopCfg->hasLeadingPictures();
919
1.29k
  ci.noIdrConstraintFlag                          = false;
920
1.29k
  ci.noCraConstraintFlag                          = (m_pcEncCfg->m_DecodingRefreshType != VVENC_DRT_CRA && m_pcEncCfg->m_DecodingRefreshType != VVENC_DRT_CRA_CRE);
921
1.29k
  ci.noGdrConstraintFlag                          = false;
922
1.29k
  ci.noApsConstraintFlag                          = ( !m_pcEncCfg->m_alf && m_pcEncCfg->m_lumaReshapeEnable == 0 /*&& m_useScalingListId == SCALING_LIST_OFF*/);
923
1.29k
}
924
925
void EncGOP::xInitSPS(SPS &sps) const
926
1.29k
{
927
1.29k
  ProfileTierLevel* profileTierLevel = &sps.profileTierLevel;
928
929
1.29k
  xInitConstraintInfo( profileTierLevel->constraintInfo );
930
931
1.29k
  profileTierLevel->levelIdc      = m_pcEncCfg->m_level;
932
1.29k
  profileTierLevel->tierFlag      = m_pcEncCfg->m_levelTier;
933
1.29k
  profileTierLevel->profileIdc    = m_pcEncCfg->m_profile;
934
1.29k
  profileTierLevel->subProfileIdc.clear();
935
1.29k
  profileTierLevel->subProfileIdc.push_back( m_pcEncCfg->m_subProfile );
936
937
1.29k
  if( m_pcEncCfg->m_maxPicWidth != 0 && m_pcEncCfg->m_maxPicHeight != 0 )
938
0
  {
939
0
    const int minCuSize = std::max( 1 << ( vvenc::MIN_CU_LOG2 + 1 ), 1 << m_pcEncCfg->m_log2MinCodingBlockSize );
940
0
    int padRight = 0, padBottom = 0;
941
0
    if( m_pcEncCfg->m_maxPicWidth % minCuSize )
942
0
    {
943
0
      padRight = ( ( m_pcEncCfg->m_maxPicWidth / minCuSize) + 1 ) * minCuSize - m_pcEncCfg->m_maxPicWidth;
944
0
    }
945
0
    if( m_pcEncCfg->m_maxPicHeight % minCuSize )
946
0
    {
947
0
      padBottom = ( ( m_pcEncCfg->m_maxPicHeight / minCuSize) + 1 ) * minCuSize - m_pcEncCfg->m_maxPicHeight;
948
0
    }
949
0
    sps.maxPicWidthInLumaSamples      = m_pcEncCfg->m_maxPicWidth + padRight;
950
0
    sps.maxPicHeightInLumaSamples     = m_pcEncCfg->m_maxPicHeight + padBottom;
951
    
952
0
    sps.conformanceWindow.setWindow( 0, padRight, 0, padBottom );
953
0
  }
954
1.29k
  else
955
1.29k
  {
956
1.29k
    sps.maxPicWidthInLumaSamples      = m_pcEncCfg->m_PadSourceWidth;
957
1.29k
    sps.maxPicHeightInLumaSamples     = m_pcEncCfg->m_PadSourceHeight;
958
1.29k
    sps.conformanceWindow.setWindow( m_pcEncCfg->m_confWinLeft, m_pcEncCfg->m_confWinRight, m_pcEncCfg->m_confWinTop, m_pcEncCfg->m_confWinBottom );
959
1.29k
  }
960
1.29k
  sps.chromaFormatIdc               = m_pcEncCfg->m_internChromaFormat;
961
1.29k
  sps.CTUSize                       = m_pcEncCfg->m_CTUSize;
962
1.29k
  sps.maxMTTDepth[0]                = m_pcEncCfg->m_maxMTTDepthI;
963
1.29k
  int maxMTTDepthVal = m_pcEncCfg->m_maxMTTDepth;
964
1.29k
  int minMaxMttD = maxMTTDepthVal % 10;
965
2.59k
  while( maxMTTDepthVal )
966
1.29k
  {
967
1.29k
    minMaxMttD      = std::min( minMaxMttD, maxMTTDepthVal % 10 );
968
1.29k
    maxMTTDepthVal /= 10;
969
1.29k
  }
970
1.29k
  sps.maxMTTDepth[1]                = minMaxMttD;
971
1.29k
  sps.maxMTTDepth[2]                = m_pcEncCfg->m_maxMTTDepthIChroma;
972
5.19k
  for( int i = 0; i < 3; i++)
973
3.89k
  {
974
3.89k
    sps.minQTSize[i]                = m_pcEncCfg->m_MinQT[i];
975
3.89k
    sps.maxBTSize[i]                = m_pcEncCfg->m_maxBT[i];
976
3.89k
    sps.maxTTSize[i]                = m_pcEncCfg->m_maxTT[i];
977
3.89k
  }
978
1.29k
  sps.minQTSize[2]                <<= getChannelTypeScaleX(CH_C, m_pcEncCfg->m_internChromaFormat);
979
980
1.29k
  sps.maxNumMergeCand               = m_pcEncCfg->m_maxNumMergeCand;
981
1.29k
  sps.maxNumAffineMergeCand         = !!m_pcEncCfg->m_Affine ? m_pcEncCfg->m_maxNumAffineMergeCand : 0;
982
1.29k
  sps.maxNumGeoCand                 = !!m_pcEncCfg->m_Geo    ? m_pcEncCfg->m_maxNumGeoCand : 0;
983
1.29k
  sps.IBC                           = m_pcEncCfg->m_IBCMode != 0;
984
1.29k
  sps.maxNumIBCMergeCand            = 6;
985
986
1.29k
  sps.idrRefParamList               = m_pcEncCfg->m_idrRefParamList;
987
1.29k
  sps.dualITree                     = m_pcEncCfg->m_dualITree && m_pcEncCfg->m_internChromaFormat != VVENC_CHROMA_400;
988
1.29k
  sps.MTS                           = m_pcEncCfg->m_MTS || m_pcEncCfg->m_MTSImplicit;
989
1.29k
  sps.SMVD                          = m_pcEncCfg->m_SMVD;
990
1.29k
  sps.AMVR                          = m_pcEncCfg->m_AMVRspeed != IMV_OFF;
991
1.29k
  sps.LMChroma                      = m_pcEncCfg->m_LMChroma;
992
1.29k
  sps.horCollocatedChroma           = m_pcEncCfg->m_horCollocatedChromaFlag;
993
1.29k
  sps.verCollocatedChroma           = m_pcEncCfg->m_verCollocatedChromaFlag;
994
1.29k
  sps.BDOF                          = m_pcEncCfg->m_BDOF;
995
1.29k
  sps.DMVR                          = m_pcEncCfg->m_DMVR;
996
1.29k
  sps.lumaReshapeEnable             = m_pcEncCfg->m_lumaReshapeEnable != 0;
997
1.29k
  sps.Affine                        = m_pcEncCfg->m_Affine;
998
1.29k
  sps.PROF                          = m_pcEncCfg->m_PROF;
999
1.29k
  sps.ProfPresent                   = m_pcEncCfg->m_PROF;
1000
1.29k
  sps.AffineType                    = m_pcEncCfg->m_AffineType;
1001
1.29k
  sps.MMVD                          = m_pcEncCfg->m_MMVD != 0;
1002
1.29k
  sps.fpelMmvd                      = m_pcEncCfg->m_allowDisFracMMVD;
1003
1.29k
  sps.GEO                           = m_pcEncCfg->m_Geo != 0;
1004
1.29k
  sps.MIP                           = m_pcEncCfg->m_MIP;
1005
1.29k
  sps.MRL                           = m_pcEncCfg->m_MRL;
1006
1.29k
  sps.BdofPresent                   = m_pcEncCfg->m_BDOF;
1007
1.29k
  sps.DmvrPresent                   = m_pcEncCfg->m_DMVR;
1008
1.29k
  sps.partitionOverrideEnabled      = true; // needed for the new MaxMTTDepth logic
1009
1.29k
  sps.resChangeInClvsEnabled        = m_pcEncCfg->m_resChangeInClvsEnabled;
1010
1.29k
  sps.rprEnabled                    = m_pcEncCfg->m_rprEnabledFlag != 0;
1011
1.29k
  sps.log2MinCodingBlockSize        = m_pcEncCfg->m_log2MinCodingBlockSize;
1012
1.29k
  sps.log2MaxTbSize                 = m_pcEncCfg->m_log2MaxTbSize;
1013
1.29k
  sps.temporalMVPEnabled            = m_pcEncCfg->m_TMVPModeId == 2 || m_pcEncCfg->m_TMVPModeId == 1;
1014
1.29k
  sps.LFNST                         = m_pcEncCfg->m_LFNST != 0;
1015
1.29k
  sps.entropyCodingSyncEnabled      = m_pcEncCfg->m_entropyCodingSyncEnabled;
1016
1.29k
  sps.entryPointsPresent            = m_pcEncCfg->m_entryPointsPresent;
1017
1.29k
  sps.depQuantEnabled               = m_pcEncCfg->m_DepQuantEnabled;
1018
1.29k
  sps.signDataHidingEnabled         = m_pcEncCfg->m_SignDataHidingEnabled;
1019
1.29k
  sps.MTSIntra                      = m_pcEncCfg->m_MTS ;
1020
1.29k
  sps.ISP                           = m_pcEncCfg->m_ISP;
1021
1.29k
  sps.transformSkip                 = m_pcEncCfg->m_TS != 0;
1022
1.29k
  sps.log2MaxTransformSkipBlockSize = m_pcEncCfg->m_TSsize;
1023
1.29k
  sps.BDPCM                         = m_pcEncCfg->m_useBDPCM != 0;
1024
1.29k
  sps.BCW                           = m_pcEncCfg->m_BCW;
1025
1026
3.89k
  for (uint32_t chType = 0; chType < MAX_NUM_CH; chType++)
1027
2.59k
  {
1028
2.59k
    sps.bitDepths.recon[chType]     = m_pcEncCfg->m_internalBitDepth[chType];
1029
2.59k
    sps.qpBDOffset[chType]          = 6 * (m_pcEncCfg->m_internalBitDepth[chType] - 8);
1030
2.59k
    sps.internalMinusInputBitDepth[chType] = std::max(0, (m_pcEncCfg->m_internalBitDepth[chType] - m_pcEncCfg->m_inputBitDepth[chType]));
1031
2.59k
  }
1032
1033
1.29k
  sps.alfEnabled                    = m_pcEncCfg->m_alf;
1034
1.29k
  sps.ccalfEnabled                  = m_pcEncCfg->m_ccalf && sps.alfEnabled && m_pcEncCfg->m_internChromaFormat != VVENC_CHROMA_400;
1035
1036
1.29k
  sps.saoEnabled                    = m_pcEncCfg->m_bUseSAO;
1037
1.29k
  sps.jointCbCr                     = m_pcEncCfg->m_JointCbCrMode;
1038
1.29k
  sps.maxTLayers                    = m_pcEncCfg->m_maxTLayer + 1;
1039
1.29k
  sps.rpl1CopyFromRpl0              = ! m_pcEncCfg->m_picReordering;
1040
1.29k
  sps.SbtMvp                        = m_pcEncCfg->m_SbTMVP;
1041
1.29k
  sps.CIIP                          = m_pcEncCfg->m_CIIP != 0;
1042
1.29k
  sps.SBT                           = m_pcEncCfg->m_SBT != 0;
1043
1044
1.29k
  CHECK( sps.maxTLayers > VVENC_MAX_TLAYER, "array index out of bounds" );
1045
9.08k
  for( int i = 0; i < sps.maxTLayers; i++ )
1046
7.78k
  {
1047
7.78k
    sps.maxDecPicBuffering[ i ]     = m_gopCfg->getMaxDecPicBuffering()[ i ];
1048
7.78k
    sps.numReorderPics[ i ]         = m_gopCfg->getNumReorderPics()[ i ];
1049
7.78k
  }
1050
1051
1.29k
  sps.vuiParametersPresent          = m_pcEncCfg->m_vuiParametersPresent;
1052
1053
1.29k
  if (sps.vuiParametersPresent)
1054
0
  {
1055
0
    VUI& vui = sps.vuiParameters;
1056
0
    vui.aspectRatioInfoPresent        = m_pcEncCfg->m_aspectRatioInfoPresent;
1057
0
    vui.aspectRatioConstantFlag       = true; // false if SampleAspectRatioInfoSEIEnabled, but this SEI is not used
1058
0
    vui.aspectRatioIdc                = m_pcEncCfg->m_aspectRatioIdc;
1059
0
    vui.sarWidth                      = m_pcEncCfg->m_sarWidth;
1060
0
    vui.sarHeight                     = m_pcEncCfg->m_sarHeight;
1061
0
    vui.colourDescriptionPresent      = m_pcEncCfg->m_colourDescriptionPresent;
1062
0
    vui.colourPrimaries               = m_pcEncCfg->m_colourPrimaries;
1063
0
    vui.transferCharacteristics       = m_pcEncCfg->m_transferCharacteristics;
1064
0
    vui.matrixCoefficients            = m_pcEncCfg->m_matrixCoefficients;
1065
0
    vui.chromaLocInfoPresent          = m_pcEncCfg->m_chromaLocInfoPresent;
1066
0
    vui.chromaSampleLocType           = m_pcEncCfg->m_chromaSampleLocType;
1067
0
    vui.chromaSampleLocTypeTopField   = 0;
1068
0
    vui.chromaSampleLocTypeBottomField= 0;
1069
0
    vui.overscanInfoPresent           = m_pcEncCfg->m_overscanInfoPresent;
1070
0
    vui.overscanAppropriateFlag       = m_pcEncCfg->m_overscanAppropriateFlag;
1071
0
    vui.videoFullRangeFlag            = m_pcEncCfg->m_videoFullRangeFlag;
1072
0
  }
1073
1074
1.29k
  sps.hrdParametersPresent            = m_pcEncCfg->m_hrdParametersPresent;
1075
1076
1.29k
  sps.numLongTermRefPicSPS            = NUM_LONG_TERM_REF_PIC_SPS;
1077
1.29k
  CHECK(!(NUM_LONG_TERM_REF_PIC_SPS <= MAX_NUM_LONG_TERM_REF_PICS), "Unspecified error");
1078
1.29k
  for (int k = 0; k < NUM_LONG_TERM_REF_PIC_SPS; k++)
1079
0
  {
1080
0
    sps.ltRefPicPocLsbSps[k]          = 0;
1081
0
    sps.usedByCurrPicLtSPS[k]         = 0;
1082
0
  }
1083
1.29k
  sps.chromaQpMappingTable.m_numQpTables = (m_pcEncCfg->m_chromaQpMappingTableParams.m_sameCQPTableForAllChromaFlag ? 1 : (sps.jointCbCr ? 3 : 2));
1084
1.29k
  sps.chromaQpMappingTable.setParams(m_pcEncCfg->m_chromaQpMappingTableParams, sps.qpBDOffset[ CH_C ]);
1085
1.29k
  sps.chromaQpMappingTable.derivedChromaQPMappingTables();
1086
1.29k
}
1087
1088
void EncGOP::xInitPPS(PPS &pps, const SPS &sps) const
1089
1.29k
{
1090
1.29k
  bool bUseDQP = m_pcEncCfg->m_cuQpDeltaSubdiv > 0;
1091
1.29k
  bUseDQP |= m_pcEncCfg->m_lumaLevelToDeltaQPEnabled;
1092
1.29k
  bUseDQP |= m_pcEncCfg->m_usePerceptQPA;
1093
1.29k
  bUseDQP |= m_pcEncCfg->m_blockImportanceMapping;
1094
1095
1.29k
  if (m_pcEncCfg->m_costMode==VVENC_COST_SEQUENCE_LEVEL_LOSSLESS || m_pcEncCfg->m_costMode==VVENC_COST_LOSSLESS_CODING)
1096
0
  {
1097
0
    bUseDQP = false;
1098
0
  }
1099
1100
  // pps ID already initialised.
1101
1.29k
  pps.spsId                         = sps.spsId;
1102
1.29k
  pps.jointCbCrQpOffsetPresent      = m_pcEncCfg->m_JointCbCrMode;
1103
1.29k
  pps.picWidthInLumaSamples         = m_pcEncCfg->m_PadSourceWidth;
1104
1.29k
  pps.picHeightInLumaSamples        = m_pcEncCfg->m_PadSourceHeight;
1105
1.29k
  if( pps.picWidthInLumaSamples == sps.maxPicWidthInLumaSamples && pps.picHeightInLumaSamples == sps.maxPicHeightInLumaSamples )
1106
1.29k
  {
1107
1.29k
    pps.conformanceWindow           = sps.conformanceWindow;
1108
1.29k
  }
1109
0
  else
1110
0
  {
1111
0
    pps.conformanceWindow.setWindow( m_pcEncCfg->m_confWinLeft, m_pcEncCfg->m_confWinRight, m_pcEncCfg->m_confWinTop, m_pcEncCfg->m_confWinBottom );
1112
0
  }
1113
1114
1.29k
  pps.picWidthInCtu                 = (pps.picWidthInLumaSamples + (sps.CTUSize-1)) / sps.CTUSize;
1115
1.29k
  pps.picHeightInCtu                = (pps.picHeightInLumaSamples + (sps.CTUSize-1)) / sps.CTUSize;
1116
1.29k
  pps.subPics.clear();
1117
1.29k
  pps.subPics.resize(1);
1118
1.29k
  pps.subPics[0].init( pps.picWidthInCtu, pps.picHeightInCtu, pps.picWidthInLumaSamples, pps.picHeightInLumaSamples);
1119
1.29k
  pps.useDQP                        = bUseDQP;
1120
1121
1.29k
  if ( m_pcEncCfg->m_cuChromaQpOffsetSubdiv >= 0 )
1122
0
  {
1123
    //th check how this is configured now    pps.cuChromaQpOffsetSubdiv = m_pcEncCfg->m_cuChromaQpOffsetSubdiv;
1124
0
    pps.chromaQpOffsetListLen = 0;
1125
0
    pps.setChromaQpOffsetListEntry(1, 6, 6, 6);
1126
0
  }
1127
1128
  // fix PPS init QP to 26 or 32 (depending on BD) to make concatenating bitstreams more robust
1129
1.29k
  pps.picInitQPMinus26 = 6 - sps.qpBDOffset[CH_L] / 2;
1130
1131
1.29k
  pps.chromaQpOffset[COMP_Y]          = 0;
1132
1.29k
  pps.chromaQpOffset[COMP_Cb]         = m_pcEncCfg->m_chromaCbQpOffset;
1133
1.29k
  pps.chromaQpOffset[COMP_Cr]         = m_pcEncCfg->m_chromaCrQpOffset;
1134
1.29k
  pps.chromaQpOffset[COMP_JOINT_CbCr] = m_pcEncCfg->m_chromaCbCrQpOffset;
1135
1136
1.29k
  bool bChromaDeltaQPEnabled = false;
1137
1.29k
  {
1138
1.29k
    bChromaDeltaQPEnabled = ( m_pcEncCfg->m_sliceChromaQpOffsetIntraOrPeriodic[ 0 ] || m_pcEncCfg->m_sliceChromaQpOffsetIntraOrPeriodic[ 1 ] );
1139
1.29k
    bChromaDeltaQPEnabled |= (m_pcEncCfg->m_usePerceptQPA || (m_pcEncCfg->m_LookAhead && m_pcRateCtrl->m_pcEncCfg->m_RCTargetBitrate > 0) || m_pcEncCfg->m_sliceChromaQpOffsetPeriodicity > 0) && (m_pcEncCfg->m_internChromaFormat != VVENC_CHROMA_400);
1140
1.29k
    if( ! bChromaDeltaQPEnabled && sps.dualITree && ( m_pcEncCfg->m_internChromaFormat != VVENC_CHROMA_400 ) )
1141
0
    {
1142
0
      bChromaDeltaQPEnabled = (m_pcEncCfg->m_chromaCbQpOffsetDualTree != 0 || m_pcEncCfg->m_chromaCrQpOffsetDualTree != 0 || m_pcEncCfg->m_chromaCbCrQpOffsetDualTree != 0);
1143
0
    }
1144
1.29k
    if( ! bChromaDeltaQPEnabled )
1145
0
    {
1146
0
      bChromaDeltaQPEnabled = m_gopCfg->isChromaDeltaQPEnabled();
1147
0
    }
1148
1.29k
  }
1149
1.29k
  pps.sliceChromaQpFlag                 = bChromaDeltaQPEnabled;
1150
1.29k
  pps.outputFlagPresent                 = false;
1151
1.29k
  pps.deblockingFilterOverrideEnabled   = !m_pcEncCfg->m_loopFilterOffsetInPPS;
1152
1.29k
  pps.deblockingFilterDisabled          = m_pcEncCfg->m_bLoopFilterDisable;
1153
1154
1.29k
  if (! pps.deblockingFilterDisabled)
1155
1.29k
  {
1156
5.19k
    for( int comp = 0; comp < MAX_NUM_COMP; comp++)
1157
3.89k
    {
1158
3.89k
      pps.deblockingFilterBetaOffsetDiv2[comp]  = m_pcEncCfg->m_loopFilterBetaOffsetDiv2[comp];
1159
3.89k
      pps.deblockingFilterTcOffsetDiv2[comp]    = m_pcEncCfg->m_loopFilterTcOffsetDiv2[comp];
1160
3.89k
    }
1161
1.29k
  }
1162
1163
  // deblockingFilterControlPresent is true if any of the settings differ from the inferred values:
1164
1.29k
  bool deblockingFilterControlPresent   = pps.deblockingFilterOverrideEnabled ||
1165
1.29k
                                          pps.deblockingFilterDisabled     ||
1166
1.29k
                                          pps.deblockingFilterBetaOffsetDiv2[COMP_Y] != 0 ||
1167
1.29k
                                          pps.deblockingFilterTcOffsetDiv2  [COMP_Y] != 0 ||
1168
1.29k
                                          pps.deblockingFilterBetaOffsetDiv2[COMP_Cb] != 0 ||
1169
1.29k
                                          pps.deblockingFilterTcOffsetDiv2  [COMP_Cb] != 0 ||
1170
1.29k
                                          pps.deblockingFilterBetaOffsetDiv2[COMP_Cr] != 0 ||
1171
1.29k
                                          pps.deblockingFilterTcOffsetDiv2  [COMP_Cr] != 0;
1172
1173
1.29k
  pps.deblockingFilterControlPresent    = deblockingFilterControlPresent;
1174
1.29k
  pps.cabacInitPresent                  = m_pcEncCfg->m_cabacInitPresent != 0;
1175
1.29k
  pps.loopFilterAcrossTilesEnabled      = !m_pcEncCfg->m_bDisableLFCrossTileBoundaryFlag;
1176
1.29k
  pps.loopFilterAcrossSlicesEnabled     = !m_pcEncCfg->m_bDisableLFCrossSliceBoundaryFlag;
1177
1.29k
  pps.rpl1IdxPresent                    = sps.rpl1IdxPresent;
1178
1179
1.29k
  const uint32_t chromaArrayType = (int)sps.separateColourPlane ? CHROMA_400 : sps.chromaFormatIdc;
1180
1.29k
  if( chromaArrayType != CHROMA_400  )
1181
1.29k
  {
1182
1.29k
    bool chromaQPOffsetNotZero = ( pps.chromaQpOffset[COMP_Cb] != 0 || pps.chromaQpOffset[COMP_Cr] != 0 || pps.jointCbCrQpOffsetPresent || pps.sliceChromaQpFlag || pps.chromaQpOffsetListLen );
1183
1.29k
    bool chromaDbfOffsetNotAsLuma = ( pps.deblockingFilterBetaOffsetDiv2[COMP_Cb] != pps.deblockingFilterBetaOffsetDiv2[COMP_Y]
1184
1.29k
                                   || pps.deblockingFilterBetaOffsetDiv2[COMP_Cr] != pps.deblockingFilterBetaOffsetDiv2[COMP_Y]
1185
1.29k
                                   || pps.deblockingFilterTcOffsetDiv2[COMP_Cb] != pps.deblockingFilterTcOffsetDiv2[COMP_Y]
1186
1.29k
                                   || pps.deblockingFilterTcOffsetDiv2[COMP_Cr] != pps.deblockingFilterTcOffsetDiv2[COMP_Y]);
1187
1.29k
    pps.usePPSChromaTool = chromaQPOffsetNotZero || chromaDbfOffsetNotAsLuma;
1188
1.29k
  }
1189
1190
1.29k
  pps.numRefIdxL0DefaultActive = std::max( m_gopCfg->getDefaultNumActive( 0 ), 1 );
1191
1.29k
  pps.numRefIdxL1DefaultActive = std::max( m_gopCfg->getDefaultNumActive( 1 ), 1 );
1192
1.29k
  CHECK( pps.numRefIdxL0DefaultActive > 15, "num default ref index active exceeds maximum value");
1193
1.29k
  CHECK( pps.numRefIdxL1DefaultActive > 15, "num default ref index active exceeds maximum value");
1194
1195
1.29k
  pps.noPicPartition = !m_pcEncCfg->m_picPartitionFlag;
1196
1.29k
  pps.ctuSize        = sps.CTUSize;
1197
1.29k
  pps.log2CtuSize    = Log2( sps.CTUSize );
1198
1199
1.29k
  xInitPPSforTiles( pps, sps );
1200
1201
1.29k
  pps.pcv            = new PreCalcValues( sps, pps, m_pcEncCfg->m_MaxQT );
1202
1.29k
}
1203
1204
void EncGOP::xInitPPSforTiles(PPS &pps,const SPS &sps) const
1205
1.29k
{
1206
1.29k
  pps.numExpTileCols = m_pcEncCfg->m_numExpTileCols;
1207
1.29k
  pps.numExpTileRows = m_pcEncCfg->m_numExpTileRows;
1208
1.29k
  pps.numSlicesInPic = m_pcEncCfg->m_numSlicesInPic;
1209
1210
1.29k
  if( pps.noPicPartition )
1211
1.29k
  {
1212
1.29k
    pps.tileColWidth.resize( 1, pps.picWidthInCtu );
1213
1.29k
    pps.tileRowHeight.resize( 1, pps.picHeightInCtu );
1214
1.29k
    pps.initTiles();
1215
1.29k
    pps.sliceMap.clear();
1216
1.29k
    pps.sliceMap.resize(1);
1217
1.29k
    pps.sliceMap[0].addCtusToSlice(0, pps.picWidthInCtu, 0, pps.picHeightInCtu, pps.picWidthInCtu);
1218
1.29k
  }
1219
0
  else
1220
0
  {
1221
0
    for( int i = 0; i < pps.numExpTileCols; i++ )
1222
0
    {
1223
0
      pps.tileColWidth.push_back( m_pcEncCfg->m_tileColumnWidth[i] );
1224
0
    }
1225
0
    for( int i = 0; i < pps.numExpTileRows; i++ )
1226
0
    {
1227
0
      pps.tileRowHeight.push_back( m_pcEncCfg->m_tileRowHeight[i] );
1228
0
    }
1229
0
    pps.initTiles();
1230
0
    pps.rectSlice            = true;
1231
0
    pps.tileIdxDeltaPresent  = false;
1232
0
    pps.initRectSliceMap( &sps );
1233
0
  }
1234
1.29k
}
1235
1236
void EncGOP::xInitRPL(SPS &sps) const
1237
1.29k
{
1238
1.29k
  m_gopCfg->getDefaultRPLLists( sps.rplList[ 0 ], sps.rplList[ 1 ] );
1239
1240
1.29k
  sps.rpl1IdxPresent = ( sps.rplList[ 0 ].size() != sps.rplList[ 1 ].size() );
1241
1242
  //Check if all delta POC of STRP in each RPL has the same sign
1243
  //Check RPLL0 first
1244
1.29k
  bool isAllEntriesinRPLHasSameSignFlag = true;
1245
3.89k
  for( int list = 0; list < 2; list++)
1246
2.59k
  {
1247
2.59k
    const RPLList& rplList = sps.rplList[list];
1248
2.59k
    uint32_t numRPL        = (uint32_t)rplList.size();
1249
1250
2.59k
    bool isFirstEntry = true;
1251
2.59k
    bool lastSign = true;        //true = positive ; false = negative
1252
5.19k
    for (uint32_t ii = 0; isAllEntriesinRPLHasSameSignFlag && ii < numRPL; ii++)
1253
2.59k
    {
1254
2.59k
      const ReferencePictureList& rpl = rplList[ii];
1255
5.19k
      for (uint32_t jj = 0; jj < rpl.numberOfActivePictures; jj++)
1256
3.89k
      {
1257
3.89k
        if(rpl.isLongtermRefPic[jj])
1258
0
          continue;
1259
1260
3.89k
        if( isFirstEntry )
1261
1.29k
        {
1262
1.29k
          lastSign = (rpl.refPicIdentifier[jj] >= 0) ? true : false;
1263
1.29k
          isFirstEntry = false;
1264
1.29k
        }
1265
2.59k
        else
1266
2.59k
        {
1267
2.59k
          int ref = ( jj == 0 && !isFirstEntry ) ? 0 : rpl.refPicIdentifier[jj-1];
1268
2.59k
          if (((rpl.refPicIdentifier[jj] - ref) >= 0 ) != lastSign)
1269
1.29k
          {
1270
1.29k
            isAllEntriesinRPLHasSameSignFlag = false;
1271
1.29k
            break;  // break the inner loop
1272
1.29k
          }
1273
2.59k
        }
1274
3.89k
      }
1275
2.59k
    }
1276
2.59k
  }
1277
1278
1.29k
  sps.allRplEntriesHasSameSign = isAllEntriesinRPLHasSameSignFlag;
1279
1280
1.29k
  bool isRpl1CopiedFromRpl0 = ( sps.rplList[ 0 ].size() == sps.rplList[ 1 ].size() );
1281
3.89k
  for( int i = 0; isRpl1CopiedFromRpl0 && i < (int)sps.rplList[ 0 ].size(); i++)
1282
2.59k
  {
1283
2.59k
    isRpl1CopiedFromRpl0 = ( sps.rplList[0][i].getNumRefEntries() == sps.rplList[1][i].getNumRefEntries() );
1284
2.59k
    if( isRpl1CopiedFromRpl0 )
1285
2.59k
    {
1286
3.89k
      for( int j = 0; j < sps.rplList[0][i].getNumRefEntries(); j++ )
1287
2.59k
      {
1288
2.59k
        if( sps.rplList[0][i].refPicIdentifier[j] != sps.rplList[1][i].refPicIdentifier[j] )
1289
1.29k
        {
1290
1.29k
          isRpl1CopiedFromRpl0 = false;
1291
1.29k
          break;
1292
1.29k
        }
1293
2.59k
      }
1294
2.59k
    }
1295
2.59k
  }
1296
1.29k
  sps.rpl1CopyFromRpl0 = isRpl1CopiedFromRpl0;
1297
1.29k
}
1298
1299
void EncGOP::xInitHrdParameters(SPS &sps)
1300
1.29k
{
1301
1.29k
  m_EncHRD.initHRDParameters( *m_pcEncCfg, sps );
1302
1303
1.29k
  sps.generalHrdParams = m_EncHRD.generalHrdParams;
1304
1305
10.3k
  for(int i = 0; i < VVENC_MAX_TLAYER; i++)
1306
9.08k
  {
1307
9.08k
    sps.olsHrdParams[i] = m_EncHRD.olsHrdParams[i];
1308
9.08k
  }
1309
1.29k
}
1310
1311
/** Function for deciding the nal_unit_type.
1312
 */
1313
1314
vvencNalUnitType EncGOP::xGetNalUnitType( const GOPEntry* _gopEntry ) const
1315
2.59k
{
1316
2.59k
  const GOPEntry& gopEntry = *_gopEntry;
1317
1318
2.59k
  if( gopEntry.m_POC == 0 && m_pcEncCfg->m_poc0idr )
1319
0
  {
1320
0
    return VVENC_NAL_UNIT_CODED_SLICE_IDR_N_LP;
1321
0
  }
1322
1323
2.59k
  if( gopEntry.m_isStartOfIntra )
1324
2.59k
  {
1325
2.59k
    if( m_pcEncCfg->m_DecodingRefreshType == VVENC_DRT_CRA || m_pcEncCfg->m_DecodingRefreshType == VVENC_DRT_CRA_CRE )
1326
2.59k
    {
1327
2.59k
      if( m_lastIDR == 0 && !m_pcEncCfg->m_poc0idr )
1328
2.59k
      {
1329
2.59k
        return VVENC_NAL_UNIT_CODED_SLICE_IDR_W_RADL;
1330
2.59k
      }
1331
0
      else
1332
0
      {
1333
0
        return VVENC_NAL_UNIT_CODED_SLICE_CRA;
1334
0
      }
1335
2.59k
    }
1336
0
    else if( m_pcEncCfg->m_DecodingRefreshType == VVENC_DRT_IDR_NO_RADL )
1337
0
    {
1338
0
      return VVENC_NAL_UNIT_CODED_SLICE_IDR_N_LP;
1339
0
    }
1340
0
    else
1341
0
    {
1342
0
      return VVENC_NAL_UNIT_CODED_SLICE_IDR_W_RADL;
1343
0
    }
1344
2.59k
  }
1345
1346
0
  if( m_pocCRA > 0 && gopEntry.m_POC < m_pocCRA )
1347
0
  {
1348
    // All leading pictures are being marked as TFD pictures here since current encoder uses all
1349
    // reference pictures while encoding leading pictures. An encoder can ensure that a leading
1350
    // picture can be still decodable when random accessing to a CRA/CRANT/BLA/BLANT picture by
1351
    // controlling the reference pictures used for encoding that leading picture. Such a leading
1352
    // picture need not be marked as a TFD picture.
1353
0
    return VVENC_NAL_UNIT_CODED_SLICE_RASL;
1354
0
  }
1355
1356
0
  if( m_lastIDR > 0 && gopEntry.m_POC < m_lastIDR && m_pcEncCfg->m_DecodingRefreshType != VVENC_DRT_IDR_NO_RADL )
1357
0
  {
1358
0
    return VVENC_NAL_UNIT_CODED_SLICE_RADL;
1359
0
  }
1360
1361
0
  return VVENC_NAL_UNIT_CODED_SLICE_TRAIL;
1362
0
}
1363
1364
bool EncGOP::xIsSliceTemporalSwitchingPoint( const Slice* slice, const PicList& picList ) const
1365
1.29k
{
1366
1.29k
  if( slice->TLayer <= 0
1367
0
      || slice->nalUnitType == VVENC_NAL_UNIT_CODED_SLICE_RADL
1368
0
      || slice->nalUnitType == VVENC_NAL_UNIT_CODED_SLICE_RASL
1369
0
      || ! slice->isStepwiseTemporalLayerSwitchingPointCandidate( picList ) )
1370
1.29k
  {
1371
1.29k
    return false;
1372
1.29k
  }
1373
1374
0
  const GOPEntry& gopEntry = *(slice->pic->gopEntry);
1375
0
  const bool isSTSA        = gopEntry.m_isSTSA;
1376
0
  return isSTSA;
1377
1.29k
}
1378
1379
void EncGOP::xSetupPicAps( Picture* pic )
1380
1.29k
{
1381
  // manage global APS list
1382
1.29k
  m_globalApsList.push_back( new PicApsGlobal( pic->poc, pic->TLayer ) );
1383
1.29k
  CHECK( pic->picApsGlobal != nullptr, "Top level APS ptr must be nullptr" );
1384
1385
  // the max size of global APS list is more than enough to support parallelization 
1386
  // additional +2 offset, due two max possible processing delay of two GOPs (Threads=1 mode)
1387
1.29k
  if( m_globalApsList.size() > ( std::max( (int)MAX_NUM_APS, m_pcEncCfg->m_GOPSize ) * ( m_pcEncCfg->m_maxParallelFrames + 2 ) ) )
1388
0
  {
1389
0
    if( m_globalApsList.front()->refCnt == 0 )
1390
0
    {
1391
0
      delete m_globalApsList.front();
1392
0
      m_globalApsList.pop_front();
1393
0
    }
1394
0
  }
1395
1396
1.29k
  pic->picApsGlobal = m_globalApsList.back();
1397
1398
  // determine reference APS
1399
1.29k
  const bool mtPicParallel = m_pcEncCfg->m_numThreads > 0;
1400
1.29k
  if( mtPicParallel && pic->slices[0]->isIntra() )
1401
1.29k
  {
1402
    // reset APS propagation on Intra-Slice in MT-mode
1403
1.29k
    return;
1404
1.29k
  }
1405
1406
  // get previous APS (in coding order) to propagate from it
1407
  // in parallelization case (parallel pictures), we refer to APS from lower temporal layer
1408
  // NOTE: elements in the global APS list are following in coding order
1409
1410
0
  PicApsGlobal* refAps = nullptr;
1411
0
  auto curApsItr = std::find_if( m_globalApsList.begin(), m_globalApsList.end(), [pic]( auto p ) { return p->poc == pic->poc; } );
1412
0
  CHECK( curApsItr == m_globalApsList.end(), "Should not happen" );
1413
1414
0
  if( curApsItr != m_globalApsList.begin() )
1415
0
  {
1416
0
    if( mtPicParallel )
1417
0
    {
1418
0
      auto r_begin = std::reverse_iterator<std::deque<PicApsGlobal*>::iterator>(curApsItr);
1419
0
      auto r_end   = std::reverse_iterator<std::deque<PicApsGlobal*>::iterator>(m_globalApsList.begin());
1420
0
      auto refApsItr = ( pic->TLayer > 0 ) ? std::find_if( r_begin, r_end, [pic]( auto p ) { return p->tid  < pic->TLayer; } ):
1421
0
                                             std::find_if( r_begin, r_end, [pic]( auto p ) { return p->tid == pic->TLayer; } );
1422
0
      if( refApsItr == r_end )
1423
0
        return;
1424
0
      refAps = *refApsItr;
1425
0
    }
1426
0
    else
1427
0
    {
1428
0
      curApsItr--;
1429
0
      refAps = *curApsItr;
1430
0
    }
1431
0
    if( refAps )
1432
0
      refAps->refCnt++;
1433
0
  }
1434
1435
  //CHECK( !refAps, "Faied to get reference APS" );
1436
0
  pic->refApsGlobal = refAps;
1437
0
}
1438
1439
void EncGOP::xInitPicsInCodingOrder( const PicList& picList )
1440
2.59k
{
1441
2.59k
  CHECK( m_pcEncCfg->m_maxParallelFrames <= 0 && m_gopEncListInput.size() > 0,  "no frame parallel processing enabled, but multiple pics in flight" );
1442
2.59k
  CHECK( m_pcEncCfg->m_maxParallelFrames <= 0 && m_gopEncListOutput.size() > 0, "no frame parallel processing enabled, but multiple pics in flight" );
1443
1444
  // loop over pic list, which is sorted in coding number order 
1445
5.19k
  for( auto it = picList.begin(); it != picList.end(); ++it )
1446
2.59k
  {
1447
2.59k
    auto pic = (*it);
1448
    // skip pics, which have already been initialized
1449
2.59k
    if( pic->isInitDone )
1450
1.29k
      continue;
1451
1452
    // update visual activity for last start of GOP picture
1453
    // this may have been changed in the shared picture data due to fixStartOfLastGop()
1454
1.29k
    if( pic->gopEntry->m_isStartOfGop && picList.back()->isFlush )
1455
1.29k
    {
1456
1.29k
      xUpdateVAStartOfLastGop( *pic );
1457
1.29k
    }
1458
1459
    // GOP QP adjustments
1460
1.29k
    if( (m_pcEncCfg->m_rateCap || m_pcEncCfg->m_GOPQPA || m_pcEncCfg->m_usePerceptQPA) && pic->gopEntry->m_isStartOfGop )
1461
1.29k
    {
1462
      // note: in case of rate cap, wait until the complete GOP is in the list and update-list is empty
1463
1.29k
      if( !m_pcEncCfg->m_rateCap ||
1464
0
        ((pic->gopEntry->m_gopNum != picList.back()->gopEntry->m_gopNum || picList.back()->isFlush) && m_rcUpdateList.empty()) )
1465
1.29k
      {
1466
1.29k
        xInitGopQpCascade( *pic, it, picList );
1467
1.29k
      }
1468
0
      else
1469
0
      {
1470
        // rate cap: wait until the condition is met
1471
0
        break;
1472
0
      }
1473
1.29k
    }
1474
1475
    // continue with next pic in increasing coding number order
1476
1.29k
    if( pic->gopEntry->m_codingNum != m_lastCodingNum + 1 && ! picList.back()->isFlush )
1477
0
      break;
1478
1479
1.29k
    CHECK( m_lastCodingNum == -1 && ! pic->gopEntry->m_isStartOfIntra, "encoding should start with an I-Slice" );
1480
1481
1.29k
    xForceScc( *pic );
1482
1483
    // initialize slice header
1484
1.29k
    pic->encTime.startTimer();
1485
1.29k
    xInitFirstSlice( *pic, picList, false );
1486
1.29k
    pic->encTime.stopTimer();
1487
1488
    // pictures ready for encoding
1489
1.29k
    m_gopEncListInput.push_back( pic );
1490
1.29k
    m_gopEncListOutput.push_back( pic );
1491
1492
1.29k
    if( m_pcEncCfg->m_alf && m_pcEncCfg->m_alfTempPred )
1493
1.29k
    {
1494
1.29k
        xSetupPicAps( pic );
1495
1.29k
    }
1496
1497
    // continue with next picture
1498
1.29k
    m_lastCodingNum = pic->gopEntry->m_codingNum;
1499
1500
    // in single threading initialize only one picture per encoding loop
1501
1.29k
    if( m_pcEncCfg->m_maxParallelFrames <= 0 )
1502
0
      break;
1503
1.29k
  }
1504
1505
2.59k
  CHECK( !(m_pcEncCfg->m_rateCap || m_pcEncCfg->m_GOPQPA || m_pcEncCfg->m_usePerceptQPA) && picList.size() && m_pcEncCfg->m_maxParallelFrames <= 0 && m_gopEncListInput.size() != 1,  "no new picture for encoding found" );
1506
2.59k
  CHECK( !(m_pcEncCfg->m_rateCap || m_pcEncCfg->m_GOPQPA || m_pcEncCfg->m_usePerceptQPA) && picList.size() && m_pcEncCfg->m_maxParallelFrames <= 0 && m_gopEncListOutput.size() != 1, "no new picture for encoding found" );
1507
2.59k
}
1508
1509
void EncGOP::xUpdateRcIfp()
1510
0
{
1511
  // deterministic behavior: RC update on next finished frame in sliding window coding order,
1512
  //                         evaluate only one finished frame at front of the list that makes place for the next frame
1513
  //                         whose parameters can be set using the finished frame bits info
1514
  //
1515
  // non-deterministic behavior: RC update on any finished frame
1516
1517
#if IFP_RC_DETERMINISTIC
1518
  if( m_rcUpdateList.front()->isReconstructed && m_rcUpdateList.back()->encRCPic && ( m_rcUpdateList.front()->isFlush || m_rcUpdateList.size() == m_pcEncCfg->m_maxParallelFrames ) )
1519
  {   
1520
#endif
1521
0
    for( auto it = m_rcUpdateList.begin(); it != m_rcUpdateList.end(); )
1522
0
    {
1523
0
      auto pic = *it;
1524
0
      if( pic->isReconstructed )
1525
0
      {
1526
0
        pic->actualTotalBits = pic->sliceDataStreams[0].getNumberOfWrittenBits();
1527
0
        pic->refCounter--;
1528
0
        m_pcRateCtrl->updateAfterPicEncRC( pic );
1529
0
        it = m_rcUpdateList.erase( it );
1530
0
      }
1531
0
      else
1532
0
      {
1533
0
        ++it;
1534
0
      }
1535
#if IFP_RC_DETERMINISTIC
1536
      // in deterministic case, only one frame is allowed to update the RC
1537
      break;
1538
#endif
1539
0
    }
1540
#if IFP_RC_DETERMINISTIC
1541
  }
1542
#endif
1543
0
}
1544
1545
inline bool getReorderedProcList( std::list<Picture*>& inputList, std::list<Picture*>& procList, const int maxSize, bool isIFP, bool restrictToGOP )
1546
0
{
1547
  // deliver frames of the same TID (temporal layer) and from the same GOP
1548
0
  const int procTL = inputList.size() ? inputList.front()->TLayer             : -1;
1549
0
  const int gopNum = inputList.size() ? inputList.front()->gopEntry->m_gopNum : -1;
1550
0
  bool added = false;
1551
0
  for( auto it = inputList.begin(); it != inputList.end(); )
1552
0
  {
1553
0
    auto pic = *it;
1554
0
    if( ( pic->gopEntry->m_gopNum == gopNum || !restrictToGOP )
1555
0
        && pic->TLayer == procTL
1556
0
        && ( isIFP ? pic->slices[ 0 ]->checkAllRefPicsAccessible(): pic->slices[ 0 ]->checkAllRefPicsReconstructed() ) )
1557
0
    {
1558
0
      pic->isInProcessList = true;
1559
0
      procList.push_back  ( pic );
1560
0
      it = inputList.erase( it );
1561
0
      added = true;
1562
0
    }
1563
0
    else
1564
0
    {
1565
0
      ++it;
1566
0
    }
1567
0
    if( (int)procList.size() >= maxSize )
1568
0
      break;
1569
0
  }
1570
0
  return added;
1571
0
}
1572
1573
inline void getProcListForOneGOP( std::list<Picture*>& inputList, std::list<Picture*>& procList )
1574
0
{
1575
  // provide frames of the same GOP
1576
0
  const int gopNum = inputList.size() ? inputList.front()->gopEntry->m_gopNum : -1;
1577
0
  for( auto it = inputList.begin(); it != inputList.end(); )
1578
0
  {
1579
0
    auto pic = *it;
1580
0
    if( pic->gopEntry->m_gopNum == gopNum )
1581
0
    {
1582
0
      procList.push_back  ( pic );
1583
0
      it = inputList.erase( it );
1584
0
    }
1585
0
    else
1586
0
    {
1587
0
      ++it;
1588
0
    }
1589
0
  }
1590
0
}
1591
1592
void EncGOP::xGetProcessingLists( std::list<Picture*>& procList, std::list<Picture*>& rcUpdateList, const bool lockStepMode )
1593
1.29k
{
1594
  // in lockstep mode, frames are reordered in a specific processing order
1595
1.29k
  if( lockStepMode )
1596
0
  {
1597
0
    if( m_pcEncCfg->m_ifpLines )
1598
0
    {
1599
      // prepare reordered list
1600
      // we need an additional reordering list to ensure causality of the coding order (ref.pics) on irregular GOP structures
1601
      // in the first step, the reordered list is filled
1602
      // in the second, the frames from reordered list are moved to proc. list up to required update-list size
1603
0
      const int maxUpdateListSize = m_pcEncCfg->m_maxParallelFrames;
1604
0
      if( rcUpdateList.size() < maxUpdateListSize && ( !m_gopEncListInput.empty() || !m_rcInputReorderList.empty()))
1605
0
      {
1606
0
        while( rcUpdateList.size() < maxUpdateListSize && ( !m_gopEncListInput.empty() || !m_rcInputReorderList.empty()) )
1607
0
        {
1608
0
          if( !m_rcInputReorderList.empty() )
1609
0
          {
1610
0
            auto pic = m_rcInputReorderList.front();
1611
0
            m_rcInputReorderList.pop_front();
1612
0
            pic->refCounter++;
1613
0
            procList.push_back( pic );
1614
0
            rcUpdateList.push_back( pic );
1615
0
          }
1616
0
          else
1617
0
          {
1618
0
            while( m_rcInputReorderList.size() < maxUpdateListSize && !m_gopEncListInput.empty() )
1619
0
            {
1620
0
              getReorderedProcList( m_gopEncListInput, m_rcInputReorderList, maxUpdateListSize, true, true );
1621
0
            }
1622
0
          }
1623
0
        }
1624
0
      }
1625
0
    }
1626
0
    else if( rcUpdateList.empty() )
1627
0
    {
1628
      // retrieve next lockstep chunk from reordered list
1629
0
      const int procTL         = m_gopEncListInput.size() ? m_gopEncListInput.front()->TLayer : -1;
1630
0
      const int minSerialDepth = m_pcEncCfg->m_maxParallelFrames > 2 ? 1 : 2;  // up to this temporal layer encode pictures only in serial mode
1631
0
      const int maxSize        = procTL <= minSerialDepth ? 1 : m_pcEncCfg->m_maxParallelFrames;
1632
0
      getReorderedProcList( m_gopEncListInput, procList, maxSize, false, true );
1633
0
      std::copy( procList.begin(), procList.end(), std::back_inserter(rcUpdateList) );
1634
0
    }
1635
0
  }
1636
1.29k
  else
1637
1.29k
  {
1638
    // regular coding mode (non-RC)
1639
    // in case of IFP, using the reordered list brings an additional speedup
1640
1.29k
    if( m_pcEncCfg->m_ifpLines )
1641
0
    {
1642
0
      const size_t inputListSize = m_gopEncListInput.size();
1643
1644
      // in case of GOP parallel processing, we do not put all the frames from the current GOP in proc.list.
1645
      // the reason for this is that we want to add frames from the next GOP as soon as possible.
1646
0
      const size_t targetProcListSize = procList.size() + (m_pcEncCfg->m_numParallelGOPs ? m_pcEncCfg->m_maxParallelFrames: inputListSize);
1647
1648
0
      while( !m_gopEncListInput.empty() && procList.size() < targetProcListSize )
1649
0
      {
1650
0
        if( !getReorderedProcList( m_gopEncListInput, procList, (int)procList.size() + m_pcEncCfg->m_maxParallelFrames, true, !m_pcEncCfg->m_numParallelGOPs ) )
1651
0
          break;
1652
0
      }
1653
0
      if( m_gopEncListInput.size() == inputListSize )
1654
0
        msg.log( VVENC_WARNING, "Processing list derivation: attempting to run in a deadlock" );
1655
0
    }
1656
1.29k
    else
1657
1.29k
    {
1658
1.29k
      if( m_pcEncCfg->m_rateCap ) // TODO helmrich: what about || *->m_GOPQPA?
1659
0
      {
1660
        // ensure that procList contains only pictures from one GOP
1661
0
        getProcListForOneGOP( m_gopEncListInput, procList );
1662
0
      }
1663
1.29k
      else
1664
1.29k
      {
1665
        // just pass the input list to processing list
1666
1.29k
        procList.splice( procList.end(), m_gopEncListInput );
1667
1.29k
        m_gopEncListInput.clear();
1668
1.29k
      }
1669
1.29k
    }
1670
1.29k
    if( m_pcEncCfg->m_RCTargetBitrate > 0 || m_pcEncCfg->m_rateCap || m_pcEncCfg->m_ifpLines )
1671
0
    {
1672
      // update-list is used for RC, RateCapping or IFP
1673
0
      std::copy( procList.begin(), procList.end(), std::back_inserter( rcUpdateList ) );
1674
0
    }
1675
1.29k
  }
1676
1.29k
  CHECK( ! rcUpdateList.empty() && m_gopEncListOutput.empty(), "first picture in RC update and in output list have to be the same" );
1677
1.29k
}
1678
1679
void EncGOP::xUpdateRateCap()
1680
0
{
1681
0
  for( auto it = m_rcUpdateList.begin(); it != m_rcUpdateList.end(); )
1682
0
  {
1683
0
    auto pic = *it;
1684
0
    if( pic->isReconstructed )
1685
0
    {
1686
0
      const unsigned uibits = pic->sliceDataStreams[0].getNumberOfWrittenBits();
1687
1688
0
      if( !pic->gopEntry->m_isStartOfIntra && pic->gopEntry->m_scType == SCT_NONE )
1689
0
      {
1690
0
        xUpdateRateCapBits( pic, uibits );
1691
0
      }
1692
0
      else if( pic->gopEntry->m_isStartOfIntra && pic->gopEntry->m_gopNum == 0 && pic->poc < m_pcEncCfg->m_GOPSize && m_rcap.accumTargetBits * (uint32_t) m_pcEncCfg->m_GOPSize < uibits )
1693
0
      {
1694
0
        m_rcap.accumActualBits += uibits - m_rcap.accumTargetBits * (uint32_t) m_pcEncCfg->m_GOPSize; // capped CQF: compensate for overspending in first I-frame
1695
0
      }
1696
1697
0
      it = m_rcUpdateList.erase( it );
1698
0
    }
1699
0
    else
1700
0
    {
1701
0
      ++it;
1702
0
    }
1703
0
  }
1704
0
}
1705
1706
void EncGOP::xUpdateRateCapBits( const Picture* pic, const uint32_t uibits )
1707
0
{
1708
  // try to adjust the rate for the first GOP on the scene-cut (or start of the sequence)
1709
0
  if( pic->gopEntry->m_isStartOfGop )
1710
0
  {
1711
0
    m_rcap.gopAdaptedQPAdj = 0;
1712
0
  }
1713
0
  else if( pic->isSceneCutCheckAdjQP )
1714
0
  {
1715
0
    CHECK( uibits == 0 || m_rcap.accumTargetBits == 0, "Not expected" );
1716
0
    const double f = std::min (1.5, pow (uibits / double (3u * m_rcap.accumTargetBits), 0.25));
1717
0
    if( f > 1.0 )
1718
0
    {
1719
0
      const Slice* slice = pic->slices[0];
1720
0
      const double d = (105.0 / 128.0) * sqrt( (double)std::max( 1, slice->sliceQp ) ) * log( f ) / log( 2.0 );
1721
0
      m_rcap.gopAdaptedQPAdj = int(d + 0.5);
1722
0
      m_rcap.nonRateCapEstim = f;
1723
      //uibits = 3u * m_rcap.AccumTargetBits; // can be used to avoid overweighting of TL1 picture
1724
0
    }
1725
0
  }
1726
0
  m_rcap.accumActualBits += unsigned (0.5 + uibits * m_rcap.nonRateCapEstim);
1727
0
}
1728
1729
void EncGOP::xUpdateVAStartOfLastGop( Picture& keyPic ) const
1730
1.29k
{
1731
1.29k
  keyPic.picVA = keyPic.m_picShared->m_picVA;
1732
1.29k
}
1733
1734
void EncGOP::xInitGopQpCascade( Picture& keyPic, PicList::const_iterator picListBegin, const PicList& picList )
1735
1.29k
{
1736
1.29k
  CHECK( !keyPic.gopEntry->m_isStartOfGop, "Expecting key picture as start of GOP")
1737
1.29k
  uint32_t gopMotEstCount = 0, gopMotEstError = 0;
1738
1.29k
  const double resRatio4K = double (m_pcEncCfg->m_SourceWidth * m_pcEncCfg->m_SourceHeight) / (3840.0 * 2160.0);
1739
1.29k
  const bool isHighRes    = (std::min (m_pcEncCfg->m_SourceWidth, m_pcEncCfg->m_SourceHeight) > 1280);
1740
1.29k
  const int gopNum        = keyPic.gopEntry->m_gopNum;
1741
1.29k
  const bool keyPicIsIdrNLP      = xGetNalUnitType(keyPic.gopEntry) == VVENC_NAL_UNIT_CODED_SLICE_IDR_N_LP;
1742
1.29k
  PicList::const_iterator picItr = picListBegin;
1743
1.29k
  const bool nextKeyPicAfterIDR  = keyPicIsIdrNLP && (++picItr != picList.end()) && (*picItr)->gopEntry->m_isStartOfGop;
1744
1745
1.29k
  int dQP = 0;
1746
1.29k
  double qpStart = 24.0;
1747
1.29k
  unsigned num = 0, sum = 0;
1748
1.29k
  unsigned nSC = 0, sSC = 0;
1749
1.29k
  uint8_t gopMinNoiseLevels[QPA_MAX_NOISE_LEVELS];
1750
1751
1.29k
  std::fill_n (gopMinNoiseLevels, QPA_MAX_NOISE_LEVELS, 255u);
1752
1753
  // get spatial activity of current and previous TL0 pic
1754
1.29k
  int spVisActTL0[2] = { 0, 0 };
1755
1.29k
  for( auto ch : { CH_L, CH_C } )
1756
2.59k
  {
1757
2.59k
    const int count = ( keyPic.picVA.spatAct[ ch ] > 0 && keyPic.picVA.prevTL0spatAct[ ch ] > 0 ) ? 2 : 1;
1758
2.59k
    spVisActTL0[ch] = ( keyPic.picVA.spatAct[ ch ] + keyPic.picVA.prevTL0spatAct[ ch ] + ( count >> 1 ) ) / count;
1759
2.59k
  }
1760
1761
2.59k
  for (auto picItr = picListBegin; picItr != picList.end(); ++picItr)
1762
1.29k
  {
1763
1.29k
    auto pic = (*picItr);
1764
1.29k
    if( pic->gopEntry->m_gopNum == gopNum )
1765
1.29k
    {
1766
1.29k
      if( pic->m_picShared->m_picMotEstError > 0 )
1767
0
      {
1768
0
        CHECK( pic->isInitDone, "try to modify GOP qp of picture, which has already been initialized" );
1769
        // summarize motion errors of all MCTF filtered pictures in GOP
1770
0
        gopMotEstCount++;
1771
0
        gopMotEstError += pic->m_picShared->m_picMotEstError;
1772
        // go through ranges, search per-range minimum in GOP
1773
0
        for (int i = 0; i < QPA_MAX_NOISE_LEVELS; i++)
1774
0
        {
1775
0
          gopMinNoiseLevels[i] = std::min<uint8_t> (gopMinNoiseLevels[i], pic->m_picShared->m_minNoiseLevels[i]);
1776
0
        }
1777
0
      }
1778
1.29k
      nSC++;
1779
1.29k
      sSC += (pic->isSccStrong ? 1 : 0) + (pic->isSccWeak ? 1 : 0);
1780
1781
1.29k
      if( pic == &keyPic && nextKeyPicAfterIDR ) // consider a virtual GOP containing only one IDR pic
1782
0
        break;
1783
1.29k
    }
1784
1.29k
  }
1785
1786
1.29k
  gopMotEstError = (gopMotEstError + (gopMotEstCount >> 1)) / std::max (1u, gopMotEstCount);
1787
1788
11.6k
  for (int i = 0; i < QPA_MAX_NOISE_LEVELS; i++) // go through ranges again, find overall min-average in GOP
1789
10.3k
  {
1790
10.3k
    if (gopMinNoiseLevels[i] < 255)
1791
0
    {
1792
0
      num++;
1793
0
      sum += gopMinNoiseLevels[i];
1794
0
    }
1795
10.3k
  }
1796
1797
  // force 2nd-order filter
1798
1.29k
  const bool f2O = (m_pcEncCfg->m_usePerceptQPA) && (sSC >= (nSC >> 1)) && (sum < 18 * num); // low-noise SC
1799
  
1800
  // adapt GOP's QP offsets
1801
1.29k
  if (num > 0 && sum > 0)
1802
0
  {
1803
0
    qpStart += 0.5 * (6.0 * log ((double) sum / (double) num) / log (2.0) - 1.0 - 24.0); // see RateCtrl.cpp
1804
0
    if (m_pcEncCfg->m_GOPQPA)
1805
0
    {
1806
0
      if (((qpStart > 29) && (spVisActTL0[CH_L] > 600)) ||
1807
0
          ((qpStart > 27) && (spVisActTL0[CH_L] > 850)) || (spVisActTL0[CH_L] > 1300))
1808
0
      {
1809
0
        dQP += 1;
1810
0
      }
1811
0
      if ((qpStart < 24) && (spVisActTL0[CH_L] < 400))
1812
0
      {
1813
0
        dQP -= 1;
1814
0
      }
1815
0
    }
1816
0
  }
1817
1.29k
  qpStart += log (resRatio4K) / log (2.0); // ICIP23 paper
1818
1819
1.29k
  if (keyPic.gopEntry->m_scType == SCT_TL0_SCENE_CUT)
1820
0
  {
1821
0
    m_rcap.reset();
1822
0
  }
1823
1824
  // derive rate capping parameters
1825
1.29k
  if (m_pcEncCfg->m_rateCap)
1826
0
  {
1827
0
    const int bDepth = m_pcEncCfg->m_internalBitDepth[CH_L];
1828
0
    const int intraP = Clip3(m_pcEncCfg->m_GOPSize, 4 * VVENC_MAX_GOP, m_pcEncCfg->m_IntraPeriod);
1829
0
    const int visAct = std::max(uint16_t(spVisActTL0[CH_L] >> (12 - bDepth)), keyPic.picVA.visAct); // when vaY=0
1830
0
    const double apa = sqrt((m_pcEncCfg->m_internalUsePerceptQPATempFiltISlice ? 32.0 : 16.0) * double(1 << (2 * bDepth - 10)) / sqrt(resRatio4K)); // average picture activity
1831
0
    const int auxOff = (m_pcEncCfg->m_blockImportanceMapping && !keyPic.m_picShared->m_ctuBimQpOffset.empty() ? keyPic.m_picShared->m_picAuxQpOffset : 0) + dQP;
1832
0
    const int iFrmQP = std::min(MAX_QP, m_pcEncCfg->m_QP + m_pcEncCfg->m_intraQPOffset + auxOff + int(floor(3.0 * log(visAct / apa) / log(2.0) + 0.5)));
1833
0
    const int qp32BC = int(16384.0 + 7.21875 * pow((double)spVisActTL0[CH_L], 4.0 / 3.0) + 1.46875 * pow((double)spVisActTL0[CH_C], 4.0 / 3.0)) * (isHighRes ? 96 : 24); // TODO hlm
1834
0
    const int iFrmBC = int(0.5 + qp32BC * pow(2.0, (32.0 - iFrmQP) * 11.0 / 64.0) * pow(resRatio4K, 2.0 / 3.0)); // * HD tuning
1835
0
    const int  shift = (gopMotEstError < 32 ? 5 - (gopMotEstError >> 4) : 3);
1836
0
    if (keyPic.m_picShared->m_picMotEstError >= 256) gopMotEstError >>= 2; else // avoid 2 much capping at cuts
1837
0
    if (gopMotEstError >= 120) /*TODO tune this*/ gopMotEstError >>= 1;
1838
0
    const int bFrmBC = int((4.0 * iFrmBC * (intraP - 1)) / sqrt((double)std::max(spVisActTL0[CH_L], spVisActTL0[CH_C])) * std::max(int(gopMotEstError * gopMotEstError) >> (bDepth / 2), (keyPic.picVA.visActTL0 - visAct) >> shift) * pow(2.0, -1.0 * bDepth));
1839
0
    const int meanGopSizeInIntraP = intraP / ((intraP + m_pcEncCfg->m_GOPSize - 1) / m_pcEncCfg->m_GOPSize);
1840
1841
0
    const double eps = 1.0 - 1.0 / double(1u << std::min(31u, m_rcap.accumGopCounter));
1842
0
    const double nonKeyPicsFactor = (m_rcap.accumTargetBits == 0) ? 1.0 : pow((double)m_rcap.accumActualBits / ((meanGopSizeInIntraP - 1.0) * m_rcap.accumTargetBits), eps);
1843
0
    const unsigned bFrmBC_final = bFrmBC * nonKeyPicsFactor;
1844
0
    const unsigned targetBits = (unsigned)((bFrmBC + (intraP >> 1)) / (intraP - 1));
1845
0
    m_rcap.accumTargetBits += targetBits;
1846
0
    if (keyPic.gopEntry->m_isStartOfIntra && keyPic.gopEntry->m_gopNum == 0 && keyPic.poc < m_pcEncCfg->m_GOPSize && m_rcap.accumTargetBits * (int64_t)intraP < iFrmBC)
1847
0
    {
1848
0
      m_rcap.accumTargetBits = (iFrmBC + (intraP >> 1)) / intraP;
1849
0
    }
1850
0
    m_rcap.nonRateCapEstim = 1.0;     // changed in case of capping
1851
0
    m_rcap.gopAdaptedQPAdj = 0;       // changed in first GOP of scene
1852
1853
0
    const int  gopQP = (iFrmQP + MAX_QP + 1) >> 1;
1854
0
    const double fac = double(m_pcEncCfg->m_FrameScale * intraP) / m_pcEncCfg->m_FrameRate;
1855
0
    const double mBC = (m_pcEncCfg->m_RCMaxBitrate > 0 && m_pcEncCfg->m_RCMaxBitrate != INT32_MAX ? m_pcEncCfg->m_RCMaxBitrate * fac : 0.0);
1856
1857
0
    if (mBC > 0.0 && iFrmBC + bFrmBC_final > mBC) // max. I-period bit-count exceeded
1858
0
    {
1859
0
      m_rcap.nonRateCapEstim = double(iFrmBC + bFrmBC_final) / mBC;
1860
0
      const double d = std::max(0, gopQP) + (105.0 / 128.0) * sqrt((double)std::max(1, gopQP)) * log(m_rcap.nonRateCapEstim) / log(2.0);
1861
1862
0
      dQP += Clip3(0, MAX_QP, int(0.5 + d + 0.5 * std::max(0.0, qpStart - d))) - std::max(0, gopQP);
1863
0
    }
1864
0
  }
1865
1866
  // assign dQP to pictures 
1867
2.59k
  for (auto picItr = picListBegin; picItr != picList.end(); ++picItr)
1868
1.29k
  {
1869
1.29k
    auto pic = (*picItr);
1870
1.29k
    if( pic->gopEntry->m_gopNum == gopNum )
1871
1.29k
    {
1872
1.29k
      pic->gopAdaptedQP = dQP;
1873
1.29k
      pic->force2ndOrder = f2O;
1874
1.29k
    }
1875
1.29k
    if( pic == &keyPic && nextKeyPicAfterIDR ) // consider a virtual GOP containing only one IDR pic
1876
0
      break;
1877
1.29k
  }
1878
1879
1.29k
  keyPic.gopAdaptedQP = dQP; // TODO: add any additional key-frame offset here
1880
1.29k
  keyPic.force2ndOrder = f2O;
1881
1.29k
  if( m_pcEncCfg->m_disableForce2ndOderFilter )
1882
0
  {
1883
0
    keyPic.force2ndOrder = false;
1884
0
  }
1885
1886
1.29k
  if(m_pcEncCfg->m_rateCap)
1887
0
  {
1888
    // enable QP adjustment after coded Intra in the first GOP or on a scene cut
1889
    // NOTE: on some scene cuts, in case of low motion activity, targetBits equals zero (QPA)
1890
0
    if(m_rcap.accumGopCounter == 0 && m_rcap.accumTargetBits > 0 && !nextKeyPicAfterIDR)
1891
0
    {
1892
0
      for(auto picItr = picListBegin; picItr != picList.end(); ++picItr)
1893
0
      {
1894
0
        auto pic = (*picItr);
1895
        // just on the next picture in decoding order after start of GOP
1896
0
        if(pic->gopEntry->m_gopNum == gopNum && !pic->gopEntry->m_isStartOfGop)
1897
0
        {
1898
0
          pic->isSceneCutCheckAdjQP = true;
1899
0
          break;
1900
0
        }
1901
0
      }
1902
0
      for(auto picItr = picListBegin; picItr != picList.end(); ++picItr)
1903
0
      {
1904
0
        auto pic = (*picItr);
1905
0
        if(pic->gopEntry->m_gopNum == gopNum && !pic->gopEntry->m_isStartOfGop && !pic->isSceneCutCheckAdjQP)
1906
0
        {
1907
0
          pic->isSceneCutGOP = true;
1908
0
        }
1909
0
      }
1910
0
    }
1911
0
    m_rcap.accumGopCounter++;
1912
0
  }
1913
1.29k
}
1914
1915
void EncGOP::xInitFirstSlice( Picture& pic, const PicList& picList, bool isEncodeLtRef )
1916
1.29k
{
1917
1.29k
  memset( pic.cs->alfAps, 0, sizeof(pic.cs->alfAps));
1918
1919
1.29k
  const int curPoc          = pic.getPOC();
1920
1.29k
  Slice* slice              = pic.allocateNewSlice();
1921
1.29k
  pic.cs->picHeader         = new PicHeader;
1922
1.29k
  const SPS& sps            = *(slice->sps);
1923
1.29k
  vvencNalUnitType naluType = xGetNalUnitType( pic.gopEntry );
1924
1.29k
  const GOPEntry& gopEntry  = *pic.gopEntry;
1925
1.29k
  SliceType sliceType       = gopEntry.m_sliceType == 'B' ? VVENC_B_SLICE : ( gopEntry.m_sliceType == 'P' ? VVENC_P_SLICE : VVENC_I_SLICE );
1926
1927
  // correct slice type at start of intra period
1928
1.29k
  if( gopEntry.m_isStartOfIntra )
1929
1.29k
  {
1930
1.29k
    sliceType = VVENC_I_SLICE;
1931
1.29k
  }
1932
1933
  // update IRAP
1934
1.29k
  if( naluType == VVENC_NAL_UNIT_CODED_SLICE_IDR_W_RADL
1935
0
      || naluType == VVENC_NAL_UNIT_CODED_SLICE_IDR_N_LP
1936
0
      || naluType == VVENC_NAL_UNIT_CODED_SLICE_CRA )
1937
1.29k
  {
1938
1.29k
    m_associatedIRAPType = naluType;
1939
1.29k
    m_associatedIRAPPOC  = curPoc;
1940
1.29k
  }
1941
1942
  // update last IDR
1943
1.29k
  if( naluType == VVENC_NAL_UNIT_CODED_SLICE_IDR_W_RADL || naluType == VVENC_NAL_UNIT_CODED_SLICE_IDR_N_LP )
1944
1.29k
  {
1945
1.29k
    m_lastIDR = curPoc;
1946
1.29k
  }
1947
1948
1.29k
  slice->picHeader                 = pic.cs->picHeader;
1949
1.29k
  slice->independentSliceIdx       = 0;
1950
1.29k
  slice->sliceType                 = sliceType;
1951
1.29k
  slice->poc                       = curPoc;
1952
1.29k
  slice->TLayer                    = gopEntry.m_temporalId;
1953
1.29k
  slice->nalUnitType               = naluType;
1954
1.29k
  slice->lastIDR                   = m_lastIDR;
1955
1.29k
  slice->depQuantEnabled           = m_pcEncCfg->m_DepQuantEnabled;
1956
1.29k
  slice->signDataHidingEnabled     = m_pcEncCfg->m_SignDataHidingEnabled;
1957
1958
1.29k
  slice->picHeader->splitConsOverride = false;
1959
5.19k
  for( int i = 0; i < 3; i++ )
1960
3.89k
  {
1961
3.89k
    slice->picHeader->minQTSize[i]   = sps.minQTSize[i];
1962
3.89k
    slice->picHeader->maxMTTDepth[i] = sps.maxMTTDepth[i];
1963
3.89k
    slice->picHeader->maxBTSize[i]   = sps.maxBTSize[i];
1964
3.89k
    slice->picHeader->maxTTSize[i]   = sps.maxTTSize[i];
1965
3.89k
    if( ( i == 1 ) && ( m_pcEncCfg->m_maxMTTDepth >= 10 ) )
1966
0
    {
1967
0
      slice->picHeader->maxMTTDepth[i]    = int( m_pcEncCfg->m_maxMTTDepth / pow( 10, sps.maxTLayers - slice->TLayer - 1 ) ) % 10;
1968
0
      slice->picHeader->splitConsOverride = slice->picHeader->maxMTTDepth[i] != sps.maxMTTDepth[i];
1969
0
    }
1970
3.89k
  }
1971
1972
1.29k
  slice->associatedIRAPType        = m_associatedIRAPType;
1973
1.29k
  slice->associatedIRAP            = m_associatedIRAPPOC;
1974
1.29k
  CHECK( MAX_REF_PICS <= gopEntry.m_numRefPicsActive[ 0 ], "number of ref pics out of supported range" );
1975
1.29k
  CHECK( MAX_REF_PICS <= gopEntry.m_numRefPicsActive[ 1 ], "number of ref pics out of supported range" );
1976
1.29k
  slice->numRefIdx[REF_PIC_LIST_0] = gopEntry.m_numRefPicsActive[ 0 ];
1977
1.29k
  slice->numRefIdx[REF_PIC_LIST_1] = gopEntry.m_numRefPicsActive[ 1 ];
1978
1.29k
  slice->setDecodingRefreshMarking ( m_pocCRA, m_bRefreshPending, picList );
1979
1.29k
  slice->setDefaultClpRng          ( sps );
1980
1981
  // reference list
1982
1.29k
  xSelectReferencePictureList( slice );
1983
1.29k
  int missingPoc;
1984
1.29k
  int ipc = ( m_pcEncCfg->m_DecodingRefreshType == VVENC_DRT_IDR_NO_RADL ) ? m_pcEncCfg->m_IntraPeriod : 0;
1985
1.29k
  if ( slice->isRplPicMissing( picList, REF_PIC_LIST_0, missingPoc, ipc ) || slice->isRplPicMissing( picList, REF_PIC_LIST_1, missingPoc, ipc ) )
1986
0
  {
1987
0
    slice->createExplicitReferencePictureSetFromReference( picList, slice->rpl[0], slice->rpl[1], ipc );
1988
0
  }
1989
1.29k
  slice->applyReferencePictureListBasedMarking( picList, slice->rpl[0], slice->rpl[1], 0, *slice->pps, m_pcEncCfg->m_numThreads == 0 );
1990
1991
  // nalu type refinement
1992
1.29k
  if ( xIsSliceTemporalSwitchingPoint( slice, picList ) )
1993
0
  {
1994
0
    naluType = VVENC_NAL_UNIT_CODED_SLICE_STSA;
1995
0
    slice->nalUnitType = naluType;
1996
0
  }
1997
1998
1.29k
  const int maxTLayer  = m_pcEncCfg->m_picReordering && m_pcEncCfg->m_GOPSize > 1 ? vvenc::ceilLog2( m_pcEncCfg->m_GOPSize ) : 0;
1999
1.29k
  const int numRefCode = pic.useNumRefs ? m_pcEncCfg->m_numRefPicsSCC : m_pcEncCfg->m_numRefPics;
2000
1.29k
  const int tLayer     = slice->TLayer;
2001
1.29k
  const int numRefs    = numRefCode < 10 ? numRefCode : ( int( numRefCode / pow( 10, maxTLayer - tLayer ) ) % 10 );
2002
2003
  // reference list
2004
1.29k
  slice->numRefIdx[REF_PIC_LIST_0] = sliceType == VVENC_I_SLICE ? 0 : ( numRefs ? std::min( numRefs, slice->rpl[0]->numberOfActivePictures ) : slice->rpl[0]->numberOfActivePictures );
2005
1.29k
  slice->numRefIdx[REF_PIC_LIST_1] = sliceType != VVENC_B_SLICE ? 0 : ( numRefs ? std::min( numRefs, slice->rpl[1]->numberOfActivePictures ) : slice->rpl[1]->numberOfActivePictures );
2006
1.29k
  slice->constructRefPicList  ( picList, false, m_pcEncCfg->m_numThreads == 0 );
2007
2008
1.29k
  slice->setRefPOCList        ();
2009
1.29k
  slice->setList1IdxToList0Idx();
2010
1.29k
  slice->updateRefPicCounter  ( +1 );
2011
1.29k
  slice->setSMVDParam();
2012
2013
  // slice type refinement
2014
1.29k
  if ( sliceType == VVENC_B_SLICE && slice->numRefIdx[ REF_PIC_LIST_1 ] == 0 )
2015
0
  {
2016
0
    sliceType = VVENC_P_SLICE;
2017
0
    slice->sliceType = sliceType;
2018
0
  }
2019
2020
1.29k
  slice->picHeader->gdrPic      = false;
2021
1.29k
  slice->picHeader->disBdofFlag = false;
2022
1.29k
  slice->picHeader->disDmvrFlag = false;
2023
1.29k
  slice->picHeader->disProfFlag = false;
2024
2025
1.29k
  slice->picHeader->gdrOrIrapPic = slice->picHeader->gdrPic || slice->isIRAP();
2026
1.29k
  slice->picHeader->picInterSliceAllowed = sliceType != VVENC_I_SLICE;
2027
1.29k
  slice->picHeader->picIntraSliceAllowed = sliceType == VVENC_I_SLICE;
2028
2029
1.29k
  slice->deblockingFilterOverride = sliceType != VVENC_I_SLICE && (gopEntry.m_betaOffsetDiv2 || gopEntry.m_tcOffsetDiv2);
2030
2031
1.29k
  if( m_pcEncCfg->m_deblockLastTLayers > 0 && slice->TLayer <= m_pcEncCfg->m_maxTLayer - m_pcEncCfg->m_deblockLastTLayers )
2032
0
  {
2033
0
    slice->deblockingFilterOverride = true;
2034
0
    slice->deblockingFilterDisable  = true;
2035
0
  }
2036
2037
1.29k
  if( slice->deblockingFilterOverride )
2038
0
  {
2039
0
    for( int comp = 0; comp < MAX_NUM_COMP; comp++)
2040
0
    {
2041
      //TODO: gopEntry.m_tcOffsetDiv2 and gopEntry.m_betaOffsetDiv2 are set with the luma value also for the chroma components (currently not used or all values are equal)
2042
0
      slice->deblockingFilterTcOffsetDiv2[comp]    = slice->picHeader->deblockingFilterTcOffsetDiv2[comp]   = gopEntry.m_tcOffsetDiv2   + m_pcEncCfg->m_loopFilterTcOffsetDiv2[comp];
2043
0
      slice->deblockingFilterBetaOffsetDiv2[comp]  = slice->picHeader->deblockingFilterBetaOffsetDiv2[comp] = gopEntry.m_betaOffsetDiv2 +   m_pcEncCfg->m_loopFilterBetaOffsetDiv2[comp];
2044
0
    }
2045
0
  }
2046
1.29k
  else
2047
1.29k
  {
2048
5.19k
    for( int comp = 0; comp < MAX_NUM_COMP; comp++)
2049
3.89k
    {
2050
3.89k
      slice->deblockingFilterTcOffsetDiv2[comp]    = slice->picHeader->deblockingFilterTcOffsetDiv2[comp]   = slice->pps->deblockingFilterTcOffsetDiv2[comp];
2051
3.89k
      slice->deblockingFilterBetaOffsetDiv2[comp]  = slice->picHeader->deblockingFilterBetaOffsetDiv2[comp] = slice->pps->deblockingFilterBetaOffsetDiv2[comp];
2052
3.89k
    }
2053
1.29k
  }
2054
2055
1.29k
  if (slice->pps->useDQP)
2056
1.29k
  {
2057
1.29k
    const uint32_t cuLumaQpSubdiv = (m_pcEncCfg->m_cuQpDeltaSubdiv > 0 ? (uint32_t) m_pcEncCfg->m_cuQpDeltaSubdiv : 0);
2058
2059
1.29k
    slice->picHeader->cuQpDeltaSubdivInter = m_pcEncCfg->m_usePerceptQPA ? 0 : cuLumaQpSubdiv;
2060
1.29k
    slice->picHeader->cuQpDeltaSubdivIntra = cuLumaQpSubdiv;
2061
1.29k
  }
2062
1.29k
  if( slice->pps->chromaQpOffsetListLen > 0)
2063
0
  {
2064
0
    const uint32_t cuChromaQpSubdiv = (m_pcEncCfg->m_cuChromaQpOffsetSubdiv > 0 ? (uint32_t) m_pcEncCfg->m_cuChromaQpOffsetSubdiv : 0);
2065
2066
0
    slice->picHeader->cuChromaQpOffsetSubdivInter = m_pcEncCfg->m_usePerceptQPA ? 0 : cuChromaQpSubdiv;
2067
0
    slice->picHeader->cuChromaQpOffsetSubdivIntra = cuChromaQpSubdiv;
2068
0
  }
2069
2070
1.29k
  slice->picHeader->ppsId = slice->pps->ppsId;
2071
1.29k
  slice->picHeader->spsId = slice->sps->spsId;
2072
2073
1.29k
  pic.cs->picHeader->pic = &pic;
2074
1.29k
  xInitSliceTMVPFlag ( pic.cs->picHeader, slice );
2075
1.29k
  xInitSliceMvdL1Zero( pic.cs->picHeader, slice );
2076
1.29k
  slice->picHeader->maxNumAffineMergeCand = sps.Affine ? sps.maxNumAffineMergeCand : ( sps.SbtMvp && slice->picHeader->enableTMVP ? 1 : 0 );
2077
2078
1.29k
  if( slice->nalUnitType == VVENC_NAL_UNIT_CODED_SLICE_RASL && m_pcEncCfg->m_rprRASLtoolSwitch )
2079
0
  {
2080
0
    slice->lmChromaCheckDisable = true;
2081
0
    pic.cs->picHeader->disDmvrFlag = true;
2082
0
    xUpdateRPRtmvp( pic.cs->picHeader, slice );
2083
0
  }
2084
2085
  // update RAS
2086
1.29k
  xUpdateRasInit( slice );
2087
2088
1.29k
  if( m_pcEncCfg->m_useAMaxBT )
2089
0
  {
2090
0
    m_BlkStat.setSliceMaxBT( *slice );
2091
0
  }
2092
2093
1.29k
  {
2094
1.29k
    bool identicalToSPS=true;
2095
1.29k
    const SPS* sps =slice->sps;
2096
1.29k
    PicHeader* picHeader = slice->picHeader;
2097
1.29k
    if (picHeader->picInterSliceAllowed)
2098
0
    {
2099
0
      identicalToSPS = (picHeader->minQTSize[1] == sps->minQTSize[1] &&
2100
0
                        picHeader->maxMTTDepth[1] == sps->maxMTTDepth[1] &&
2101
0
                        picHeader->maxBTSize[1] == sps->maxBTSize[1] &&
2102
0
                        picHeader->maxTTSize[1] == sps->maxTTSize[1] );
2103
0
    }
2104
2105
1.29k
    if (identicalToSPS && picHeader->picIntraSliceAllowed)
2106
1.29k
    {
2107
1.29k
      identicalToSPS = (picHeader->minQTSize[0] == sps->minQTSize[0] &&
2108
1.29k
                        picHeader->maxMTTDepth[0] == sps->maxMTTDepth[0] &&
2109
1.29k
                        picHeader->maxBTSize[0] == sps->maxBTSize[0] &&
2110
1.29k
                        picHeader->maxTTSize[0] == sps->maxTTSize[0] );
2111
1.29k
    }
2112
2113
1.29k
    if (identicalToSPS && sps->dualITree)
2114
1.29k
    {
2115
1.29k
      identicalToSPS = (picHeader->minQTSize[2] == sps->minQTSize[2] &&
2116
1.29k
                        picHeader->maxMTTDepth[2] == sps->maxMTTDepth[2] &&
2117
1.29k
                        picHeader->maxBTSize[2] == sps->maxBTSize[2] &&
2118
1.29k
                        picHeader->maxTTSize[2] == sps->maxTTSize[2] );
2119
1.29k
    }
2120
2121
1.29k
    if (identicalToSPS)
2122
1.29k
    {
2123
1.29k
      picHeader->splitConsOverride = false;
2124
1.29k
    }
2125
2126
1.29k
  }
2127
2128
1.29k
  CHECK( slice->TLayer != 0 && slice->sliceType == VVENC_I_SLICE, "Unspecified error" );
2129
2130
1.29k
  pic.cs->slice = slice;
2131
1.29k
  pic.cs->allocateVectorsAtPicLevel();
2132
1.29k
  pic.isReferenced = true;
2133
2134
  // reshaper
2135
1.29k
  xInitLMCS( pic );
2136
2137
1.29k
  pic.picApsMap.clearActive();
2138
1.29k
  pic.picApsMap.setApsIdStart( ALF_CTB_MAX_NUM_APS );
2139
11.6k
  for ( int i = 0; i < ALF_CTB_MAX_NUM_APS; i++ )
2140
10.3k
  {
2141
10.3k
    const int apsMapIdx = ( i << NUM_APS_TYPE_LEN ) + ALF_APS;
2142
10.3k
    APS* alfAPS = pic.picApsMap.getPS( apsMapIdx );
2143
10.3k
    if ( alfAPS )
2144
0
    {
2145
0
      alfAPS->apsId      = MAX_UINT;
2146
0
      alfAPS->temporalId = MAX_INT;
2147
0
      alfAPS->poc        = MAX_INT;
2148
0
      pic.picApsMap.clearChangedFlag( apsMapIdx );
2149
0
      alfAPS->alfParam.reset();
2150
0
      alfAPS->ccAlfParam.reset();
2151
0
    }
2152
10.3k
  }
2153
1.29k
  CHECK( slice->enableDRAPSEI && m_pcEncCfg->m_maxParallelFrames, "Dependent Random Access Point is not supported by Frame Parallel Processing" );
2154
2155
1.29k
  pic.isInitDone = true;
2156
1.29k
}
2157
2158
void EncGOP::xInitSliceTMVPFlag( PicHeader* picHeader, const Slice* slice )
2159
1.29k
{
2160
1.29k
  if( m_pcEncCfg->m_TMVPModeId == 2 )
2161
0
  {
2162
0
    const GOPEntry& gopEntry = *(slice->pic->gopEntry);
2163
0
    picHeader->enableTMVP    = ! gopEntry.m_useBckwdOnly;
2164
0
  }
2165
1.29k
  else if( m_pcEncCfg->m_TMVPModeId == 1 )
2166
1.29k
  {
2167
1.29k
    picHeader->enableTMVP = true;
2168
1.29k
  }
2169
0
  else
2170
0
  {
2171
0
    picHeader->enableTMVP = false;
2172
0
  }
2173
2174
  // disable TMVP when current picture is the only ref picture
2175
1.29k
  if( slice->isIRAP() && slice->sps->IBC )
2176
1.29k
  {
2177
1.29k
    picHeader->enableTMVP = false;
2178
1.29k
  }
2179
1.29k
}
2180
2181
void EncGOP::xUpdateRPRtmvp( PicHeader* picHeader, Slice* slice )
2182
0
{
2183
0
  if( slice->sliceType != VVENC_I_SLICE && picHeader->enableTMVP && m_pcEncCfg->m_rprRASLtoolSwitch )
2184
0
  {
2185
0
    int colRefIdxL0 = -1, colRefIdxL1 = -1;
2186
2187
0
    for( int refIdx = 0; refIdx < slice->numRefIdx[REF_PIC_LIST_0]; refIdx++ )
2188
0
    {
2189
0
      if( !( slice->getRefPic( REF_PIC_LIST_0, refIdx )->slices[0]->nalUnitType != VVENC_NAL_UNIT_CODED_SLICE_RASL &&
2190
0
             slice->getRefPic( REF_PIC_LIST_0, refIdx )->poc <= m_pocCRA ) )
2191
0
      {
2192
0
        colRefIdxL0 = refIdx;
2193
0
        break;
2194
0
      }
2195
0
    }
2196
2197
0
    if( slice->sliceType == VVENC_B_SLICE )
2198
0
    {
2199
0
      for( int refIdx = 0; refIdx < slice->numRefIdx[REF_PIC_LIST_1]; refIdx++ )
2200
0
      {
2201
0
        if( !( slice->getRefPic( REF_PIC_LIST_1, refIdx )->slices[0]->nalUnitType != VVENC_NAL_UNIT_CODED_SLICE_RASL &&
2202
0
               slice->getRefPic( REF_PIC_LIST_1, refIdx )->poc <= m_pocCRA ) )
2203
0
        {
2204
0
          colRefIdxL1 = refIdx;
2205
0
          break;
2206
0
        }
2207
0
      }
2208
0
    }
2209
2210
0
    if( colRefIdxL0 >= 0 && colRefIdxL1 >= 0 )
2211
0
    {
2212
0
      const Picture *refPicL0 = slice->getRefPic( REF_PIC_LIST_0, colRefIdxL0 );
2213
0
      const Picture *refPicL1 = slice->getRefPic( REF_PIC_LIST_1, colRefIdxL1 );
2214
2215
0
      CHECK( !refPicL0->slices.size(), "Wrong L0 reference picture" );
2216
0
      CHECK( !refPicL1->slices.size(), "Wrong L1 reference picture" );
2217
2218
0
      const uint32_t uiColFromL0 = refPicL0->slices[0]->sliceQp > refPicL1->slices[0]->sliceQp;
2219
0
      picHeader->picColFromL0 = uiColFromL0;
2220
0
      slice->colFromL0Flag = uiColFromL0;
2221
0
      slice->colRefIdx = uiColFromL0 ? colRefIdxL0 : colRefIdxL1;
2222
0
      picHeader->colRefIdx = uiColFromL0 ? colRefIdxL0 : colRefIdxL1;
2223
0
    }
2224
0
    else if( colRefIdxL0 < 0 && colRefIdxL1 >= 0 )
2225
0
    {
2226
0
      picHeader->picColFromL0 = false;
2227
0
      slice->colFromL0Flag = false;
2228
0
      slice->colRefIdx = colRefIdxL1;
2229
0
      picHeader->colRefIdx = colRefIdxL1;
2230
0
    }
2231
0
    else if( colRefIdxL0 >= 0 && colRefIdxL1 < 0 )
2232
0
    {
2233
0
      picHeader->picColFromL0 = true;
2234
0
      slice->colFromL0Flag = true;
2235
0
      slice->colRefIdx = colRefIdxL0;
2236
0
      picHeader->colRefIdx = colRefIdxL0;
2237
0
    }
2238
0
    else
2239
0
    {
2240
0
      picHeader->enableTMVP = false;
2241
0
    }
2242
0
  }
2243
0
}
2244
2245
void EncGOP::xInitSliceMvdL1Zero( PicHeader* picHeader, const Slice* slice )
2246
1.29k
{
2247
1.29k
  bool bGPBcheck = false;
2248
1.29k
  if ( slice->sliceType == VVENC_B_SLICE)
2249
0
  {
2250
0
    if ( slice->numRefIdx[ 0 ] == slice->numRefIdx[ 1 ] )
2251
0
    {
2252
0
      bGPBcheck = true;
2253
0
      int i;
2254
0
      for ( i=0; i < slice->numRefIdx[ 1 ]; i++ )
2255
0
      {
2256
0
        if ( slice->getRefPOC( RefPicList( 1 ), i ) != slice->getRefPOC( RefPicList( 0 ), i ) )
2257
0
        {
2258
0
          bGPBcheck = false;
2259
0
          break;
2260
0
        }
2261
0
      }
2262
0
    }
2263
0
  }
2264
2265
1.29k
  if ( bGPBcheck )
2266
0
  {
2267
0
    picHeader->mvdL1Zero = true;
2268
0
  }
2269
1.29k
  else
2270
1.29k
  {
2271
1.29k
    picHeader->mvdL1Zero = false;
2272
1.29k
  }
2273
1.29k
}
2274
2275
void EncGOP::xInitLMCS( Picture& pic )
2276
1.29k
{
2277
1.29k
  Slice* slice = pic.cs->slice;
2278
1.29k
  const SliceType sliceType = slice->sliceType;
2279
2280
1.29k
  if( ! pic.useLMCS || (!slice->isIntra() && m_disableLMCSIP) )
2281
1.29k
  {
2282
1.29k
    pic.reshapeData.copyReshapeData( m_Reshaper );
2283
1.29k
    m_Reshaper.setCTUFlag     ( false );
2284
1.29k
    pic.reshapeData.setCTUFlag( false );
2285
1.29k
    if( slice->isIntra() )  m_disableLMCSIP = true;
2286
1.29k
    return;
2287
1.29k
  }
2288
0
  if( slice->isIntra() ) m_disableLMCSIP = false;
2289
2290
0
  m_Reshaper.getReshapeCW()->rspTid = slice->TLayer + (slice->isIntra() ? 0 : 1);
2291
0
  m_Reshaper.getSliceReshaperInfo().chrResScalingOffset = m_pcEncCfg->m_LMCSOffset;
2292
2293
0
  if ( m_pcEncCfg->m_reshapeSignalType == RESHAPE_SIGNAL_PQ )
2294
0
  {
2295
0
    m_Reshaper.preAnalyzerHDR( pic, sliceType, m_pcEncCfg->m_reshapeCW );
2296
0
  }
2297
0
  else if ( m_pcEncCfg->m_reshapeSignalType == RESHAPE_SIGNAL_SDR || m_pcEncCfg->m_reshapeSignalType == RESHAPE_SIGNAL_HLG )
2298
0
  {
2299
0
    m_Reshaper.preAnalyzerLMCS( pic, m_pcEncCfg->m_reshapeSignalType, sliceType, m_pcEncCfg->m_reshapeCW );
2300
0
  }
2301
0
  else
2302
0
  {
2303
0
    THROW("Reshaper for other signal currently not defined!");
2304
0
  }
2305
2306
0
  if ( sliceType == VVENC_I_SLICE )
2307
0
  {
2308
0
    if ( m_pcEncCfg->m_reshapeSignalType == RESHAPE_SIGNAL_PQ )
2309
0
    {
2310
0
      m_Reshaper.initLUTfromdQPModel();
2311
0
      m_Reshaper.updateReshapeLumaLevelToWeightTableChromaMD( m_Reshaper.getInvLUT() );
2312
0
    }
2313
0
    else if ( m_pcEncCfg->m_reshapeSignalType == RESHAPE_SIGNAL_SDR || m_pcEncCfg->m_reshapeSignalType == RESHAPE_SIGNAL_HLG )
2314
0
    {
2315
0
      if ( m_Reshaper.getReshapeFlag() )
2316
0
      {
2317
0
        m_Reshaper.constructReshaperLMCS();
2318
0
        m_Reshaper.updateReshapeLumaLevelToWeightTable( m_Reshaper.getSliceReshaperInfo(), m_Reshaper.getWeightTable(), m_Reshaper.getCWeight() );
2319
0
      }
2320
0
    }
2321
0
    else
2322
0
    {
2323
0
      THROW( "Reshaper for other signal currently not defined!" );
2324
0
    }
2325
2326
        //reshape original signal
2327
0
    if( m_Reshaper.getSliceReshaperInfo().sliceReshaperEnabled )
2328
0
    {
2329
0
      CPelUnitBuf origBuf = pic.getOrigBuf();
2330
0
      if( pic.getFilteredOrigBuffer().valid() )
2331
0
      {
2332
0
        pic.getRspOrigBuf().get(COMP_Y).rspSignal( m_Reshaper.getFwdLUT() );
2333
0
      }
2334
0
      else
2335
0
      {
2336
0
        pic.getFilteredOrigBuffer().create( pic.cs->pcv->chrFormat, Area( 0, 0, origBuf.get( COMP_Y ).width, origBuf.get( COMP_Y ).height) );
2337
0
        PelUnitBuf rspOrigBuf = pic.getRspOrigBuf();
2338
0
        rspOrigBuf.get(COMP_Y).rspSignal( origBuf.get(COMP_Y), m_Reshaper.getFwdLUT() );
2339
0
        if( CHROMA_400 != pic.cs->pcv->chrFormat )
2340
0
        {
2341
0
          rspOrigBuf.get(COMP_Cb).copyFrom( origBuf.get(COMP_Cb) );
2342
0
          rspOrigBuf.get(COMP_Cr).copyFrom( origBuf.get(COMP_Cr) );
2343
0
        }
2344
0
      }
2345
0
    }
2346
2347
0
    m_Reshaper.setCTUFlag( false );
2348
0
  }
2349
0
  else
2350
0
  {
2351
0
    m_Reshaper.setCTUFlag( m_Reshaper.getReshapeFlag() );
2352
0
    m_Reshaper.getSliceReshaperInfo().sliceReshaperModelPresent = false;
2353
2354
0
    if ( m_pcEncCfg->m_reshapeSignalType == RESHAPE_SIGNAL_PQ )
2355
0
    {
2356
0
      m_Reshaper.restoreReshapeLumaLevelToWeightTable();
2357
0
    }
2358
0
    else if ( m_pcEncCfg->m_reshapeSignalType == RESHAPE_SIGNAL_SDR || m_pcEncCfg->m_reshapeSignalType == RESHAPE_SIGNAL_HLG )
2359
0
    {
2360
0
      int modIP = pic.getPOC() - pic.getPOC() / m_pcEncCfg->m_reshapeCW.rspFpsToIp * m_pcEncCfg->m_reshapeCW.rspFpsToIp;
2361
0
      if (m_Reshaper.getReshapeFlag() && m_pcEncCfg->m_reshapeCW.updateCtrl == 2 && modIP == 0)
2362
0
      {
2363
0
        m_Reshaper.getSliceReshaperInfo().sliceReshaperModelPresent = true;
2364
0
        m_Reshaper.constructReshaperLMCS();
2365
0
        m_Reshaper.updateReshapeLumaLevelToWeightTable(m_Reshaper.getSliceReshaperInfo(), m_Reshaper.getWeightTable(), m_Reshaper.getCWeight());
2366
0
      }
2367
0
    }
2368
0
    else
2369
0
    {
2370
0
      THROW("Reshaper for other signal currently not defined!");
2371
0
    }
2372
0
  }
2373
2374
  //set all necessary information in LMCS APS and slice
2375
0
  slice->lmcsEnabled = slice->picHeader->lmcsEnabled = m_Reshaper.getSliceReshaperInfo().sliceReshaperEnabled;
2376
0
  slice->picHeader->lmcsChromaResidualScale          = ( m_Reshaper.getSliceReshaperInfo().enableChromaAdj == 1 );
2377
0
  if ( m_Reshaper.getSliceReshaperInfo().sliceReshaperModelPresent )
2378
0
  {
2379
0
    ParameterSetMap<APS>& picApsMap = pic.picApsMap;
2380
0
    const int apsId0                = 0;
2381
0
    const int apsMapIdx             = ( apsId0 << NUM_APS_TYPE_LEN ) + LMCS_APS;
2382
0
    APS* picAps                     = picApsMap.getPS( apsMapIdx );
2383
0
    if ( picAps == nullptr )
2384
0
    {
2385
0
      picAps = picApsMap.allocatePS( apsMapIdx );
2386
0
      picAps->apsType     = LMCS_APS;
2387
0
      picAps->apsId       = apsId0;
2388
0
    }
2389
0
    picAps->lmcsParam = m_Reshaper.getSliceReshaperInfo();
2390
0
    picApsMap.setChangedFlag( apsMapIdx );
2391
0
    slice->picHeader->lmcsAps    = picAps;
2392
0
    slice->picHeader->lmcsApsId  = apsId0;
2393
0
  }
2394
2395
0
  if ( slice->picHeader->lmcsEnabled )
2396
0
  {
2397
0
    slice->picHeader->lmcsApsId = 0;
2398
0
  }
2399
2400
0
  pic.reshapeData.copyReshapeData( m_Reshaper );
2401
0
}
2402
2403
void EncGOP::xSelectReferencePictureList( Slice* slice ) const
2404
1.29k
{
2405
1.29k
  const GOPEntry& gopEntry = *(slice->pic->gopEntry);
2406
2407
3.89k
  for( int l = 0; l < 2; l++ )
2408
2.59k
  {
2409
2.59k
    slice->rplIdx[ l ] = gopEntry.m_defaultRPLIdx;
2410
2.59k
    if( slice->rplIdx[ l ] >= 0 )
2411
2.59k
    {
2412
2.59k
      slice->rpl[ l ] = &(slice->sps->rplList[ l ][ slice->rplIdx[ l ] ]);
2413
2.59k
    }
2414
0
    else
2415
0
    {
2416
0
      slice->rplLocal[ l ].initFromGopEntry( gopEntry, l );
2417
0
      slice->rpl[ l ] = &slice->rplLocal[ l ];
2418
0
    }
2419
2.59k
  }
2420
1.29k
}
2421
2422
void EncGOP::xWritePicture( Picture& pic, AccessUnitList& au, bool isEncodeLtRef )
2423
1.29k
{
2424
  // first pass temporal down-sampling
2425
1.29k
  if( ( ! m_pcRateCtrl->rcIsFinalPass || m_isPreAnalysis ) && pic.gopEntry->m_skipFirstPass )
2426
0
  {
2427
0
    m_pcRateCtrl->addRCPassStats( pic.cs->slice->poc,
2428
0
        0,                /* qp */
2429
0
        0,                /* lambda */
2430
0
        pic.picVA.visAct,
2431
0
        0,                /* numBits */
2432
0
        0,                /* psnrY */
2433
0
        pic.cs->slice->isIntra(),
2434
0
        pic.cs->slice->TLayer,
2435
0
        pic.gopEntry->m_isStartOfIntra,
2436
0
        pic.gopEntry->m_isStartOfGop,
2437
0
        pic.gopEntry->m_gopNum,
2438
0
        pic.gopEntry->m_scType,
2439
0
        pic.picVA.spatAct[CH_L],
2440
0
        pic.m_picShared->m_picMotEstError,
2441
0
        pic.m_picShared->m_minNoiseLevels );
2442
0
    return;
2443
0
  }
2444
2445
1.29k
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "bsfinal", 1 ) );
2446
1.29k
  pic.encTime.startTimer();
2447
2448
1.29k
  au.poc           = pic.poc;
2449
1.29k
  au.temporalLayer = pic.TLayer;
2450
1.29k
  au.refPic        = pic.isReferenced;
2451
1.29k
  au.userData      = pic.userData;
2452
1.29k
  if( ! pic.slices.empty() )
2453
1.29k
  {
2454
1.29k
    au.sliceType = pic.slices[ 0 ]->sliceType;
2455
1.29k
  }
2456
2457
1.29k
  if( pic.ctsValid )
2458
1.29k
  {
2459
1.29k
    const int64_t iDiffFrames = m_numPicsCoded - pic.poc - pic.picsInMissing;
2460
1.29k
    au.cts      = pic.cts;
2461
1.29k
    au.ctsValid = pic.ctsValid;
2462
1.29k
    if ( pic.picOutOffset )
2463
0
    {
2464
0
      m_numPicsOutOffset += pic.picOutOffset;
2465
0
    }
2466
1.29k
    if( m_pcEncCfg->m_TicksPerSecond > 0 )
2467
1.29k
      au.dts      = ( ( iDiffFrames - m_pcEncCfg->m_maxTLayer + m_numPicsOutOffset ) * m_ticksPerFrameMul4 ) / 4 + au.cts;
2468
0
    else
2469
0
      au.dts      = ( ( iDiffFrames - m_pcEncCfg->m_maxTLayer + m_numPicsOutOffset )) + au.cts;
2470
1.29k
    au.dtsValid = pic.ctsValid;
2471
1.29k
  }
2472
2473
1.29k
  pic.actualTotalBits += xWriteParameterSets( pic, au, m_HLSWriter );
2474
1.29k
  xWriteLeadingSEIs( pic, au );
2475
1.29k
  pic.actualTotalBits += xWritePictureSlices( pic, au, m_HLSWriter );
2476
2477
1.29k
  pic.encTime.stopTimer();
2478
2479
1.29k
  std::string digestStr;
2480
1.29k
  xWriteTrailingSEIs( pic, au, digestStr );
2481
1.29k
  xPrintPictureInfo ( pic, au, digestStr, m_pcEncCfg->m_printFrameMSE, isEncodeLtRef );
2482
1.29k
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "bsfinal", 0 ) );
2483
1.29k
}
2484
2485
int EncGOP::xWriteParameterSets( Picture& pic, AccessUnitList& accessUnit, HLSWriter& hlsWriter )
2486
1.29k
{
2487
1.29k
  Slice* slice        = pic.slices[0];
2488
1.29k
  const SPS& sps      = *(slice->sps);
2489
1.29k
  const PPS& pps      = *(slice->pps);
2490
1.29k
  int actualTotalBits = 0;
2491
2492
1.29k
  if ( m_bFirstWrite || ( m_pcEncCfg->m_rewriteParamSets && slice->isIRAP() ) )
2493
1.29k
  {
2494
1.29k
    if (slice->sps->vpsId != 0)
2495
0
    {
2496
0
      actualTotalBits += xWriteVPS( accessUnit, pic.vps, hlsWriter );
2497
0
    }
2498
1.29k
    actualTotalBits += xWriteDCI( accessUnit, pic.dci, hlsWriter );
2499
1.29k
    actualTotalBits += xWriteSPS( accessUnit, &sps, hlsWriter );
2500
1.29k
    actualTotalBits += xWritePPS( accessUnit, &pps, &sps, hlsWriter );
2501
1.29k
    m_bFirstWrite = false;
2502
1.29k
  }
2503
2504
1.29k
  bool IrapOrGdrAu = slice->picHeader->gdrPic || (slice->isIRAP() && !slice->pps->mixedNaluTypesInPic);
2505
1.29k
  if ((( slice->vps->maxLayers > 1 && IrapOrGdrAu) || m_pcEncCfg->m_AccessUnitDelimiter) && !slice->nuhLayerId )
2506
0
  {
2507
0
    xWriteAccessUnitDelimiter( accessUnit, slice, IrapOrGdrAu, hlsWriter );
2508
0
  }
2509
2510
  // send LMCS APS when LMCSModel is updated. It can be updated even current slice does not enable reshaper.
2511
  // For example, in RA, update is on intra slice, but intra slice may not use reshaper
2512
1.29k
  if ( sps.lumaReshapeEnable && slice->picHeader->lmcsApsId >= 0 )
2513
0
  {
2514
    // only 1 LMCS data for 1 picture
2515
0
    ParameterSetMap<APS>& apsMap = pic.picApsMap;
2516
0
    const int apsId              = slice->picHeader->lmcsApsId;
2517
0
    const int apsMapIdx          = apsId >= 0 ?  ( apsId << NUM_APS_TYPE_LEN ) + LMCS_APS : 0;
2518
0
    APS* aps                     = apsId >= 0 ?  apsMap.getPS( apsMapIdx ) : nullptr;
2519
0
    const bool doAPS             = aps && apsMap.getChangedFlag( apsMapIdx );
2520
0
    if ( doAPS )
2521
0
    {
2522
0
      aps->chromaPresent = slice->sps->chromaFormatIdc != CHROMA_400;
2523
0
      aps->temporalId = slice->TLayer;
2524
0
      actualTotalBits += xWriteAPS( accessUnit, aps, hlsWriter, VVENC_NAL_UNIT_PREFIX_APS );
2525
0
      apsMap.clearChangedFlag( apsMapIdx );
2526
0
      CHECK( aps != slice->picHeader->lmcsAps, "Wrong LMCS APS pointer" );
2527
0
    }
2528
0
  }
2529
2530
  // send ALF APS
2531
1.29k
  if ( sps.alfEnabled && (slice->alfEnabled[COMP_Y] || slice->ccAlfCbEnabled || slice->ccAlfCrEnabled ))
2532
0
  {
2533
0
    for ( int apsId = 0; apsId < ALF_CTB_MAX_NUM_APS; apsId++ )
2534
0
    {
2535
0
      ParameterSetMap<APS>& apsMap = pic.picApsMap;
2536
0
      const int apsMapIdx          = ( apsId << NUM_APS_TYPE_LEN ) + ALF_APS;
2537
0
      APS* aps                     = apsMap.getPS( apsMapIdx );
2538
0
      bool writeAps                = aps && apsMap.getChangedFlag( apsMapIdx );
2539
0
      if ( writeAps )
2540
0
      {
2541
0
        aps->chromaPresent = slice->sps->chromaFormatIdc != CHROMA_400;
2542
0
        aps->temporalId = slice->TLayer;
2543
0
        actualTotalBits += xWriteAPS( accessUnit, aps, hlsWriter, VVENC_NAL_UNIT_PREFIX_APS );
2544
0
        apsMap.clearChangedFlag( apsMapIdx );
2545
0
      }
2546
0
    }
2547
0
  }
2548
2549
1.29k
  return actualTotalBits;
2550
1.29k
}
2551
2552
int EncGOP::xWritePictureSlices( Picture& pic, AccessUnitList& accessUnit, HLSWriter& hlsWriter )
2553
1.29k
{
2554
1.29k
  Slice* slice        = pic.slices[ 0 ];
2555
1.29k
  const int numSlices = (int)( pic.slices.size() );
2556
1.29k
  unsigned  numBytes  = 0;
2557
2558
2.59k
  for ( int sliceIdx = 0; sliceIdx < numSlices; sliceIdx++ )
2559
1.29k
  {
2560
1.29k
    slice = pic.slices[ sliceIdx ];
2561
2562
1.29k
    if ( sliceIdx > 0 && slice->sliceType != VVENC_I_SLICE )
2563
0
    {
2564
0
      slice->checkColRefIdx( sliceIdx, &pic );
2565
0
    }
2566
2567
    // start slice NALUnit
2568
1.29k
    OutputNALUnit nalu( slice->nalUnitType, slice->TLayer );
2569
1.29k
    hlsWriter.setBitstream( &nalu.m_Bitstream );
2570
2571
    // slice header and data
2572
1.29k
    int bitsBeforeWriting = hlsWriter.getNumberOfWrittenBits();
2573
1.29k
    hlsWriter.codeSliceHeader( slice );
2574
1.29k
    pic.actualHeadBits += ( hlsWriter.getNumberOfWrittenBits() - bitsBeforeWriting );
2575
1.29k
    hlsWriter.codeTilesWPPEntryPoint( slice );
2576
1.29k
    xAttachSliceDataToNalUnit( nalu, &pic.sliceDataStreams[ sliceIdx ] );
2577
2578
1.29k
    accessUnit.push_back( new NALUnitEBSP( nalu ) );
2579
1.29k
    numBytes += unsigned( accessUnit.back()->m_nalUnitData.str().size() );
2580
1.29k
  }
2581
2582
1.29k
  xCabacZeroWordPadding( pic, slice, pic.sliceDataNumBins, numBytes, accessUnit.back()->m_nalUnitData );
2583
2584
1.29k
  return numBytes * 8;
2585
1.29k
}
2586
2587
void EncGOP::xWriteLeadingSEIs( const Picture& pic, AccessUnitList& accessUnit )
2588
1.29k
{
2589
1.29k
  const Slice* slice = pic.slices[ 0 ];
2590
1.29k
  SEIMessages leadingSeiMessages;
2591
2592
1.29k
  bool bpPresentInAU = false;
2593
2594
1.29k
  if((m_pcEncCfg->m_bufferingPeriodSEIEnabled) && (slice->isIRAP() || slice->nalUnitType == VVENC_NAL_UNIT_CODED_SLICE_GDR) &&
2595
0
    slice->nuhLayerId==slice->vps->layerId[0] && (slice->sps->hrdParametersPresent) && m_pcRateCtrl->rcIsFinalPass && !m_isPreAnalysis )
2596
0
  {
2597
0
    SEIBufferingPeriod *bufferingPeriodSEI = new SEIBufferingPeriod();
2598
0
    bool noLeadingPictures = ( (slice->nalUnitType!= VVENC_NAL_UNIT_CODED_SLICE_IDR_W_RADL) && (slice->nalUnitType!= VVENC_NAL_UNIT_CODED_SLICE_CRA) );
2599
0
    m_seiEncoder.initBufferingPeriodSEI(*bufferingPeriodSEI, noLeadingPictures);
2600
0
    m_EncHRD.bufferingPeriodSEI = *bufferingPeriodSEI;
2601
0
    m_EncHRD.bufferingPeriodInitialized = true;
2602
2603
0
    leadingSeiMessages.push_back(bufferingPeriodSEI);
2604
0
    bpPresentInAU = true;
2605
0
  }
2606
2607
//  if (m_pcEncCfg->m_dependentRAPIndicationSEIEnabled && slice->isDRAP )
2608
//  {
2609
//    SEIDependentRAPIndication *dependentRAPIndicationSEI = new SEIDependentRAPIndication();
2610
//    m_seiEncoder.initDrapSEI( dependentRAPIndicationSEI );
2611
//    leadingSeiMessages.push_back(dependentRAPIndicationSEI);
2612
//  }
2613
2614
1.29k
  if( m_pcEncCfg->m_pictureTimingSEIEnabled && m_pcEncCfg->m_bufferingPeriodSEIEnabled && m_pcRateCtrl->rcIsFinalPass && !m_isPreAnalysis )
2615
0
  {
2616
0
    SEIMessages nestedSeiMessages;
2617
0
    SEIMessages duInfoSeiMessages;
2618
0
    uint32_t numDU = 1;
2619
0
    m_seiEncoder.initPictureTimingSEI( leadingSeiMessages, nestedSeiMessages, duInfoSeiMessages, slice, numDU, bpPresentInAU );
2620
0
  }
2621
2622
1.29k
  if( m_pcEncCfg->m_preferredTransferCharacteristics )
2623
0
  {
2624
0
    SEIAlternativeTransferCharacteristics *seiAlternativeTransferCharacteristics = new SEIAlternativeTransferCharacteristics;
2625
0
    m_seiEncoder.initSEIAlternativeTransferCharacteristics( seiAlternativeTransferCharacteristics );
2626
0
    leadingSeiMessages.push_back(seiAlternativeTransferCharacteristics);
2627
0
  }
2628
2629
  // film grain SEI
2630
1.29k
  if ( m_pcEncCfg->m_fg.m_fgcSEIEnabled && !m_pcEncCfg->m_fg.m_fgcSEIPerPictureSEI )
2631
0
  {
2632
0
    SeiFgc* sei = new SeiFgc;
2633
0
    m_seiEncoder.initSeiFgc( sei );
2634
0
    sei->log2ScaleFactor = m_fgAnalyzer.getLog2scaleFactor();
2635
0
    for ( int compIdx = 0; compIdx < getNumberValidComponents(pic.chromaFormat); compIdx++ )
2636
0
    {
2637
0
      if ( sei->compModel[compIdx].presentFlag )
2638
0
      {  // higher importance of presentFlag is from cfg file
2639
0
        sei->compModel[compIdx] = m_fgAnalyzer.getCompModel( compIdx );
2640
0
      }
2641
0
    }
2642
0
    leadingSeiMessages.push_back( sei );
2643
0
  }
2644
2645
  // mastering display colour volume
2646
1.29k
  if( (m_pcEncCfg->m_masteringDisplay[0] != 0 && m_pcEncCfg->m_masteringDisplay[1] != 0) ||
2647
1.29k
      m_pcEncCfg->m_masteringDisplay[8] )
2648
0
  {
2649
0
    SEIMasteringDisplayColourVolume *sei = new SEIMasteringDisplayColourVolume;
2650
0
    m_seiEncoder.initSEIMasteringDisplayColourVolume(sei);
2651
0
    leadingSeiMessages.push_back(sei);
2652
0
  }
2653
2654
  // content light level
2655
1.29k
  if( m_pcEncCfg->m_contentLightLevel[0] != 0 && m_pcEncCfg->m_contentLightLevel[1] != 0 )
2656
0
  {
2657
0
    SEIContentLightLevelInfo *seiCLL = new SEIContentLightLevelInfo;
2658
0
    m_seiEncoder.initSEIContentLightLevel(seiCLL);
2659
0
    leadingSeiMessages.push_back(seiCLL);
2660
0
  }
2661
2662
2663
  // Note: using accessUnit.end() works only as long as this function is called after slice coding and before EOS/EOB NAL units
2664
1.29k
  AccessUnitList::iterator pos = accessUnit.end();
2665
1.29k
  xWriteSEISeparately( VVENC_NAL_UNIT_PREFIX_SEI, leadingSeiMessages, accessUnit, pos, slice->TLayer, slice->sps );
2666
2667
1.29k
  deleteSEIs( leadingSeiMessages );
2668
1.29k
}
2669
2670
void EncGOP::xWriteTrailingSEIs( const Picture& pic, AccessUnitList& accessUnit, std::string& digestStr )
2671
1.29k
{
2672
1.29k
  const Slice* slice = pic.slices[ 0 ];
2673
1.29k
  SEIMessages trailingSeiMessages;
2674
2675
1.29k
  if ( m_pcEncCfg->m_decodedPictureHashSEIType != VVENC_HASHTYPE_NONE )
2676
0
  {
2677
0
    SEIDecodedPictureHash *decodedPictureHashSei = new SEIDecodedPictureHash();
2678
0
    const CPelUnitBuf recoBuf = pic.cs->getRecoBuf();
2679
0
    m_seiEncoder.initDecodedPictureHashSEI( *decodedPictureHashSei, recoBuf, digestStr, slice->sps->bitDepths );
2680
0
    if ( m_pcEncCfg->m_decodedPictureHashSEIType < VVENC_HASHTYPE_MD5_LOG )
2681
0
    {
2682
0
    trailingSeiMessages.push_back( decodedPictureHashSei );
2683
0
  }
2684
0
    else
2685
0
    {
2686
0
      delete decodedPictureHashSei;
2687
0
    }
2688
0
  }
2689
2690
  // Note: using accessUnit.end() works only as long as this function is called after slice coding and before EOS/EOB NAL units
2691
1.29k
  AccessUnitList::iterator pos = accessUnit.end();
2692
1.29k
  xWriteSEISeparately( VVENC_NAL_UNIT_SUFFIX_SEI, trailingSeiMessages, accessUnit, pos, slice->TLayer, slice->sps );
2693
2694
1.29k
  deleteSEIs( trailingSeiMessages );
2695
1.29k
}
2696
2697
int EncGOP::xWriteVPS ( AccessUnitList &accessUnit, const VPS *vps, HLSWriter& hlsWriter )
2698
0
{
2699
0
  OutputNALUnit nalu(VVENC_NAL_UNIT_VPS);
2700
0
  hlsWriter.setBitstream( &nalu.m_Bitstream );
2701
0
  hlsWriter.codeVPS( vps );
2702
0
  accessUnit.push_back(new NALUnitEBSP(nalu));
2703
0
  return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
2704
0
}
2705
2706
int EncGOP::xWriteDCI ( AccessUnitList &accessUnit, const DCI *dci, HLSWriter& hlsWriter )
2707
1.29k
{
2708
1.29k
  if (dci->dciId ==0)
2709
1.29k
  {
2710
1.29k
    return 0;
2711
1.29k
  }
2712
2713
0
  OutputNALUnit nalu(VVENC_NAL_UNIT_DCI);
2714
0
  hlsWriter.setBitstream( &nalu.m_Bitstream );
2715
0
  hlsWriter.codeDCI( dci );
2716
0
  accessUnit.push_back(new NALUnitEBSP(nalu));
2717
0
  return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
2718
1.29k
}
2719
2720
int EncGOP::xWriteSPS ( AccessUnitList &accessUnit, const SPS *sps, HLSWriter& hlsWriter )
2721
1.29k
{
2722
1.29k
  OutputNALUnit nalu(VVENC_NAL_UNIT_SPS);
2723
1.29k
  hlsWriter.setBitstream( &nalu.m_Bitstream );
2724
1.29k
  hlsWriter.codeSPS( sps );
2725
1.29k
  accessUnit.push_back(new NALUnitEBSP(nalu));
2726
1.29k
  return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
2727
1.29k
}
2728
2729
int EncGOP::xWritePPS ( AccessUnitList &accessUnit, const PPS *pps, const SPS *sps, HLSWriter& hlsWriter )
2730
1.29k
{
2731
1.29k
  OutputNALUnit nalu(VVENC_NAL_UNIT_PPS);
2732
1.29k
  hlsWriter.setBitstream( &nalu.m_Bitstream );
2733
1.29k
  hlsWriter.codePPS( pps, sps );
2734
1.29k
  accessUnit.push_back(new NALUnitEBSP(nalu));
2735
1.29k
  return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
2736
1.29k
}
2737
2738
int EncGOP::xWriteAPS( AccessUnitList &accessUnit, const APS *aps, HLSWriter& hlsWriter, vvencNalUnitType eNalUnitType )
2739
0
{
2740
0
  OutputNALUnit nalu(eNalUnitType, aps->temporalId);
2741
0
  hlsWriter.setBitstream(&nalu.m_Bitstream);
2742
0
  hlsWriter.codeAPS(aps);
2743
0
  accessUnit.push_back(new NALUnitEBSP(nalu));
2744
0
  return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
2745
0
}
2746
2747
void EncGOP::xWriteAccessUnitDelimiter ( AccessUnitList &accessUnit, Slice* slice, bool IrapOrGdr, HLSWriter& hlsWriter )
2748
0
{
2749
0
  OutputNALUnit nalu(VVENC_NAL_UNIT_ACCESS_UNIT_DELIMITER, slice->TLayer);
2750
0
  hlsWriter.setBitstream(&nalu.m_Bitstream);
2751
0
  hlsWriter.codeAUD( IrapOrGdr, 2-slice->sliceType );
2752
0
  accessUnit.push_front(new NALUnitEBSP(nalu));
2753
0
}
2754
2755
void EncGOP::xWriteSEI (vvencNalUnitType naluType, SEIMessages& seiMessages, AccessUnitList &accessUnit, AccessUnitList::iterator &auPos, int temporalId, const SPS *sps)
2756
0
{
2757
0
  if (seiMessages.empty())
2758
0
  {
2759
0
    return;
2760
0
  }
2761
0
  OutputNALUnit nalu(naluType, temporalId);
2762
0
  m_seiWriter.writeSEImessages(nalu.m_Bitstream, seiMessages, m_EncHRD, false, temporalId);
2763
0
  auPos = accessUnit.insert(auPos, new NALUnitEBSP(nalu));
2764
0
  auPos++;
2765
0
}
2766
2767
void EncGOP::xWriteSEISeparately (vvencNalUnitType naluType, SEIMessages& seiMessages, AccessUnitList &accessUnit, AccessUnitList::iterator &auPos, int temporalId, const SPS *sps)
2768
2.59k
{
2769
2.59k
  if (seiMessages.empty())
2770
2.59k
  {
2771
2.59k
    return;
2772
2.59k
  }
2773
0
  for (SEIMessages::const_iterator sei = seiMessages.begin(); sei!=seiMessages.end(); sei++ )
2774
0
  {
2775
0
    SEIMessages tmpMessages;
2776
0
    tmpMessages.push_back(*sei);
2777
0
    OutputNALUnit nalu(naluType, temporalId);
2778
0
    m_seiWriter.writeSEImessages(nalu.m_Bitstream, tmpMessages, m_EncHRD, false, temporalId);
2779
0
    auPos = accessUnit.insert(auPos, new NALUnitEBSP(nalu));
2780
0
    auPos++;
2781
0
  }
2782
0
}
2783
2784
/** Attaches the input bitstream to the stream in the output NAL unit
2785
    Updates rNalu to contain concatenated bitstream. rpcBitstreamRedirect is cleared at the end of this function call.
2786
 *  \param codedSliceData contains the coded slice data (bitstream) to be concatenated to rNalu
2787
 *  \param rNalu          target NAL unit
2788
 */
2789
void EncGOP::xAttachSliceDataToNalUnit( OutputNALUnit& rNalu, const OutputBitstream* codedSliceData )
2790
1.29k
{
2791
  // Byte-align
2792
1.29k
  rNalu.m_Bitstream.writeByteAlignment();   // Slice header byte-alignment
2793
2794
  // Perform bitstream concatenation
2795
1.29k
  if (codedSliceData->getNumberOfWrittenBits() > 0)
2796
1.29k
  {
2797
1.29k
    rNalu.m_Bitstream.addSubstream(codedSliceData);
2798
1.29k
  }
2799
1.29k
}
2800
2801
void EncGOP::xCabacZeroWordPadding( const Picture& pic, const Slice* slice, uint32_t binCountsInNalUnits, uint32_t numBytesInVclNalUnits, std::ostringstream &nalUnitData )
2802
1.29k
{
2803
1.29k
  const PPS &pps                     = *(slice->pps);
2804
1.29k
  const SPS &sps                     = *(slice->sps);
2805
1.29k
  const ChromaFormat format          = sps.chromaFormatIdc;
2806
1.29k
  const int log2subWidthCxsubHeightC = getComponentScaleX( COMP_Cb, format ) + getComponentScaleY( COMP_Cb, format );
2807
1.29k
  const int minCUSize                = pic.cs->pcv->minCUSize;
2808
1.29k
  const int paddedWidth              = ( (pps.picWidthInLumaSamples  + minCUSize - 1) / minCUSize) * minCUSize;
2809
1.29k
  const int paddedHeight             = ( (pps.picHeightInLumaSamples + minCUSize - 1) / minCUSize) * minCUSize;
2810
1.29k
  const int rawBits                  = paddedWidth * paddedHeight * ( sps.bitDepths[ CH_L ] + 2 * ( sps.bitDepths[ CH_C ] >> log2subWidthCxsubHeightC ) );
2811
1.29k
  const uint32_t threshold           = ( 32/3 ) * numBytesInVclNalUnits + ( rawBits/32 );
2812
1.29k
  if ( binCountsInNalUnits >= threshold )
2813
0
  {
2814
    // need to add additional cabac zero words (each one accounts for 3 bytes (=00 00 03)) to increase numBytesInVclNalUnits
2815
0
    const uint32_t targetNumBytesInVclNalUnits = ( ( binCountsInNalUnits - ( rawBits/32 ) ) * 3 + 31 ) / 32;
2816
2817
0
    if ( targetNumBytesInVclNalUnits>numBytesInVclNalUnits ) // It should be!
2818
0
    {
2819
0
      const uint32_t numberOfAdditionalBytesNeeded    = targetNumBytesInVclNalUnits - numBytesInVclNalUnits;
2820
0
      const uint32_t numberOfAdditionalCabacZeroWords = ( numberOfAdditionalBytesNeeded + 2 ) / 3;
2821
0
      const uint32_t numberOfAdditionalCabacZeroBytes = numberOfAdditionalCabacZeroWords * 3;
2822
0
      if ( m_pcEncCfg->m_cabacZeroWordPaddingEnabled )
2823
0
      {
2824
0
        std::vector<uint8_t> zeroBytesPadding(numberOfAdditionalCabacZeroBytes, uint8_t(0));
2825
0
        for( uint32_t i = 0; i < numberOfAdditionalCabacZeroWords; i++ )
2826
0
        {
2827
0
          zeroBytesPadding[ i * 3 + 2 ] = 3;  // 00 00 03
2828
0
        }
2829
0
        nalUnitData.write( reinterpret_cast<const char*>(&(zeroBytesPadding[ 0 ])), numberOfAdditionalCabacZeroBytes );
2830
0
        msg.log( VVENC_NOTICE, "Adding %d bytes of padding\n", numberOfAdditionalCabacZeroWords * 3 );
2831
0
      }
2832
0
      else
2833
0
      {
2834
0
        msg.log( VVENC_NOTICE, "Standard would normally require adding %d bytes of padding\n", numberOfAdditionalCabacZeroWords * 3 );
2835
0
      }
2836
0
    }
2837
0
  }
2838
1.29k
}
2839
2840
void EncGOP::xAddPSNRStats( const Picture* pic, CPelUnitBuf cPicD, AccessUnitList& accessUnit, bool printFrameMSE, double* PSNR_Y, bool isEncodeLtRef )
2841
1.29k
{
2842
1.29k
  const Slice* slice         = pic->slices[0];
2843
2844
1.29k
  double dPSNR[MAX_NUM_COMP];
2845
1.29k
  double MSEyuvframe[MAX_NUM_COMP];
2846
5.19k
  for (int i = 0; i < MAX_NUM_COMP; i++)
2847
3.89k
  {
2848
3.89k
    dPSNR[i]       = pic->psnr[i];
2849
3.89k
    MSEyuvframe[i] = pic->mse[i];
2850
3.89k
  }
2851
2852
  /* calculate the size of the access unit, excluding:
2853
   *  - any AnnexB contributions (start_code_prefix, zero_byte, etc.,)
2854
   *  - SEI NAL units
2855
   */
2856
1.29k
  uint32_t numRBSPBytes = 0;
2857
5.19k
  for (AccessUnitList::const_iterator it = accessUnit.begin(); it != accessUnit.end(); it++)
2858
3.89k
  {
2859
3.89k
    uint32_t numRBSPBytes_nal = uint32_t((*it)->m_nalUnitData.str().size());
2860
3.89k
    if (m_pcEncCfg->m_summaryVerboseness > 0)
2861
0
    {
2862
0
      msg.log( VVENC_NOTICE, "*** %s numBytesInNALunit: %u\n", nalUnitTypeToString((*it)->m_nalUnitType), numRBSPBytes_nal);
2863
0
    }
2864
3.89k
    if( ( *it )->m_nalUnitType != VVENC_NAL_UNIT_PREFIX_SEI && ( *it )->m_nalUnitType != VVENC_NAL_UNIT_SUFFIX_SEI )
2865
3.89k
    {
2866
3.89k
      numRBSPBytes += numRBSPBytes_nal;
2867
3.89k
      if (it == accessUnit.begin() || (*it)->m_nalUnitType == VVENC_NAL_UNIT_VPS || (*it)->m_nalUnitType == VVENC_NAL_UNIT_DCI || (*it)->m_nalUnitType == VVENC_NAL_UNIT_SPS || (*it)->m_nalUnitType == VVENC_NAL_UNIT_PPS || (*it)->m_nalUnitType == VVENC_NAL_UNIT_PREFIX_APS || (*it)->m_nalUnitType == VVENC_NAL_UNIT_SUFFIX_APS)
2868
2.59k
      {
2869
2.59k
        numRBSPBytes += 4;
2870
2.59k
      }
2871
1.29k
      else
2872
1.29k
      {
2873
1.29k
        numRBSPBytes += 3;
2874
1.29k
      }
2875
3.89k
    }
2876
3.89k
  }
2877
1.29k
  const uint32_t uibits = numRBSPBytes * 8;
2878
2879
1.29k
  if (m_isPreAnalysis || !m_pcRateCtrl->rcIsFinalPass)
2880
0
  {
2881
0
    m_pcRateCtrl->addRCPassStats( slice->poc,
2882
0
                                  slice->sliceQp,
2883
0
                                  slice->getLambdas()[0],
2884
0
                                  pic->picVA.visAct,
2885
0
                                  uibits,
2886
0
                                  dPSNR[COMP_Y],
2887
0
                                  slice->isIntra(),
2888
0
                                  slice->TLayer,
2889
0
                                  pic->gopEntry->m_isStartOfIntra,
2890
0
                                  pic->gopEntry->m_isStartOfGop,
2891
0
                                  pic->gopEntry->m_gopNum,
2892
0
                                  pic->gopEntry->m_scType,
2893
0
                                  pic->picVA.spatAct[CH_L],
2894
0
                                  pic->m_picShared->m_picMotEstError,
2895
0
                                  pic->m_picShared->m_minNoiseLevels );
2896
0
  }
2897
2898
  //===== add PSNR =====
2899
1.29k
  m_AnalyzeAll.addResult(dPSNR, (double)uibits, MSEyuvframe
2900
1.29k
    , isEncodeLtRef
2901
1.29k
  );
2902
1.29k
  if ( slice->isIntra() )
2903
1.29k
  {
2904
1.29k
    m_AnalyzeI.addResult(dPSNR, (double)uibits, MSEyuvframe
2905
1.29k
      , isEncodeLtRef
2906
1.29k
    );
2907
1.29k
    *PSNR_Y = dPSNR[COMP_Y];
2908
1.29k
  }
2909
1.29k
  if ( slice->isInterP() )
2910
0
  {
2911
0
    m_AnalyzeP.addResult(dPSNR, (double)uibits, MSEyuvframe
2912
0
      , isEncodeLtRef
2913
0
    );
2914
0
    *PSNR_Y = dPSNR[COMP_Y];
2915
0
  }
2916
1.29k
  if ( slice->isInterB() )
2917
0
  {
2918
0
    m_AnalyzeB.addResult(dPSNR, (double)uibits, MSEyuvframe
2919
0
      , isEncodeLtRef
2920
0
    );
2921
0
    *PSNR_Y = dPSNR[COMP_Y];
2922
0
  }
2923
2924
1.29k
  char c = (slice->isIntra() ? 'I' : slice->isInterP() ? 'P' : 'B');
2925
1.29k
  if ( ! pic->isReferenced && pic->refCounter == 0 && ! m_pcEncCfg->m_maxParallelFrames )
2926
0
  {
2927
0
    c += 32;
2928
0
  }
2929
2930
  // create info string
2931
1.29k
  {
2932
1.29k
    if ((m_isPreAnalysis && m_pcRateCtrl->m_pcEncCfg->m_RCTargetBitrate > 0) || !m_pcRateCtrl->rcIsFinalPass)
2933
0
    {
2934
0
      std::string cInfo;
2935
0
      if( m_pcRateCtrl->rcIsFinalPass ) // single pass RC
2936
0
      {
2937
0
        cInfo = prnt("RC analyze poc %5d", slice->poc );
2938
0
      }
2939
0
      else
2940
0
      {
2941
0
        cInfo = prnt("RC pass %d/%d, analyze poc %5d",
2942
0
            m_pcRateCtrl->rcPass + 1,
2943
0
            m_pcEncCfg->m_RCNumPasses,
2944
0
            slice->poc );
2945
0
      }
2946
0
      accessUnit.InfoString.append( cInfo );
2947
0
    }
2948
1.29k
    else
2949
1.29k
    {
2950
1.29k
      std::stringstream sMctf;
2951
1.29k
      if( pic->gopEntry->m_mctfIndex >= 0 )
2952
0
        sMctf << ", TF " << pic->gopEntry->m_mctfIndex << ")";
2953
1.29k
      else
2954
1.29k
        sMctf << ")      ";
2955
2956
1.29k
      std::string cInfo = prnt("POC %5d TId: %1d (%10s, %c-SLICE, QP %d%s %10d bits",
2957
1.29k
          slice->poc,
2958
1.29k
          slice->TLayer,
2959
1.29k
          nalUnitTypeToString( slice->nalUnitType ),
2960
1.29k
          c,
2961
1.29k
          slice->sliceQp,
2962
1.29k
          sMctf.str().c_str(),
2963
1.29k
          uibits );
2964
2965
1.29k
      std::string yPSNR = dPSNR[COMP_Y]  == MAX_DOUBLE ? prnt(" [Y %7s dB    ", "inf" ) : prnt(" [Y %6.4lf dB    ", dPSNR[COMP_Y] );
2966
1.29k
      std::string uPSNR = dPSNR[COMP_Cb] == MAX_DOUBLE ? prnt("U %7s dB    ", "inf" ) : prnt("U %6.4lf dB    ", dPSNR[COMP_Cb] );
2967
1.29k
      std::string vPSNR = dPSNR[COMP_Cr] == MAX_DOUBLE ? prnt("V %7s dB]", "inf" ) : prnt("V %6.4lf dB]", dPSNR[COMP_Cr] );
2968
2969
1.29k
      accessUnit.InfoString.append( cInfo );
2970
1.29k
      accessUnit.InfoString.append( yPSNR );
2971
1.29k
      accessUnit.InfoString.append( uPSNR );
2972
1.29k
      accessUnit.InfoString.append( vPSNR );
2973
2974
1.29k
      if ( m_pcEncCfg->m_printHexPsnr )
2975
0
      {
2976
0
        uint64_t xPsnr[MAX_NUM_COMP];
2977
0
        for (int i = 0; i < MAX_NUM_COMP; i++)
2978
0
        {
2979
0
          std::copy(reinterpret_cast<uint8_t *>(&dPSNR[i]),
2980
0
              reinterpret_cast<uint8_t *>(&dPSNR[i]) + sizeof(dPSNR[i]),
2981
0
              reinterpret_cast<uint8_t *>(&xPsnr[i]));
2982
0
        }
2983
2984
0
        std::string yPSNRHex = dPSNR[COMP_Y]  == MAX_DOUBLE ? prnt(" [xY %16s", "inf") : prnt(" [xY %16" PRIx64,  xPsnr[COMP_Y] );
2985
0
        std::string uPSNRHex = dPSNR[COMP_Cb] == MAX_DOUBLE ? prnt(" xU %16s", "inf") : prnt(" xU %16" PRIx64, xPsnr[COMP_Cb] ) ;
2986
0
        std::string vPSNRHex = dPSNR[COMP_Cr] == MAX_DOUBLE ? prnt(" xV %16s]", "inf") : prnt(" xV %16" PRIx64 "]", xPsnr[COMP_Cr]);
2987
2988
0
        accessUnit.InfoString.append( yPSNRHex );
2989
0
        accessUnit.InfoString.append( uPSNRHex );
2990
0
        accessUnit.InfoString.append( vPSNRHex );
2991
0
      }
2992
2993
1.29k
      if( printFrameMSE )
2994
0
      {
2995
0
        std::string cFrameMSE = prnt( " [Y MSE %6.4lf  U MSE %6.4lf  V MSE %6.4lf]", MSEyuvframe[COMP_Y], MSEyuvframe[COMP_Cb], MSEyuvframe[COMP_Cr]);
2996
0
        accessUnit.InfoString.append( cFrameMSE );
2997
0
      }
2998
2999
1.29k
      std::string cEncTime = prnt(" [ET %5d ]", pic->encTime.getTimerInSec() );
3000
1.29k
      accessUnit.InfoString.append( cEncTime );
3001
3002
1.29k
      std::string cRefPics;
3003
3.89k
      for( int iRefList = 0; iRefList < 2; iRefList++ )
3004
2.59k
      {
3005
2.59k
        std::string tmp = prnt(" [L%d ", iRefList);
3006
2.59k
        cRefPics.append( tmp );
3007
2.59k
        for( int iRefIndex = 0; iRefIndex < slice->numRefIdx[ iRefList ]; iRefIndex++ )
3008
0
        {
3009
0
          tmp = prnt("%d ", slice->getRefPOC( RefPicList( iRefList ), iRefIndex));
3010
0
          cRefPics.append( tmp );
3011
0
        }
3012
2.59k
        cRefPics.append( "]" );
3013
2.59k
      }
3014
1.29k
      accessUnit.InfoString.append( cRefPics );
3015
1.29k
    }
3016
1.29k
  }
3017
1.29k
}
3018
3019
uint64_t EncGOP::xFindDistortionPlane( const CPelBuf& pic0, const CPelBuf& pic1, uint32_t rshift ) const
3020
0
{
3021
0
  uint64_t uiTotalDiff;
3022
0
  const  Pel*  pSrc0 = pic0.bufAt(0, 0);
3023
0
  const  Pel*  pSrc1 = pic1.bufAt(0, 0);
3024
3025
0
  CHECK(pic0.width  != pic1.width , "Unspecified error");
3026
0
  CHECK(pic0.height != pic1.height, "Unspecified error");
3027
3028
0
  if( rshift > 0 )
3029
0
  {
3030
0
    uiTotalDiff = 0;
3031
0
    for (int y = 0; y < pic0.height; y++)
3032
0
    {
3033
0
      for (int x = 0; x < pic0.width; x++)
3034
0
      {
3035
0
        Intermediate_Int iTemp = pSrc0[x] - pSrc1[x];
3036
0
        uiTotalDiff += uint64_t((iTemp * iTemp) >> rshift);
3037
0
      }
3038
0
      pSrc0 += pic0.stride;
3039
0
      pSrc1 += pic1.stride;
3040
0
    }
3041
0
  }
3042
0
  else
3043
0
  {
3044
0
    uiTotalDiff = 0;
3045
0
    for (int y = 0; y < pic0.height; y++)
3046
0
    {
3047
0
      for (int x = 0; x < pic0.width; x++)
3048
0
      {
3049
0
        Intermediate_Int iTemp = pSrc0[x] - pSrc1[x];
3050
0
        uiTotalDiff += uint64_t(iTemp * iTemp);
3051
0
      }
3052
0
      pSrc0 += pic0.stride;
3053
0
      pSrc1 += pic1.stride;
3054
0
    }
3055
0
  }
3056
3057
0
  return uiTotalDiff;
3058
0
}
3059
3060
void EncGOP::xPrintPictureInfo( const Picture& pic, AccessUnitList& accessUnit, const std::string& digestStr, bool printFrameMSE, bool isEncodeLtRef )
3061
1.29k
{
3062
1.29k
  double PSNR_Y;
3063
1.29k
  xAddPSNRStats( &pic, pic.getRecoBuf(), accessUnit, printFrameMSE, &PSNR_Y, isEncodeLtRef );
3064
3065
1.29k
  if( ! m_isPreAnalysis && m_pcRateCtrl->rcIsFinalPass )
3066
1.29k
  {
3067
1.29k
    std::string modeName;
3068
1.29k
    switch ( m_pcEncCfg->m_decodedPictureHashSEIType )
3069
1.29k
    {
3070
0
      case VVENC_HASHTYPE_MD5:
3071
0
      case VVENC_HASHTYPE_MD5_LOG:
3072
0
        modeName = "MD5";
3073
0
        break;
3074
0
      case VVENC_HASHTYPE_CRC:
3075
0
      case VVENC_HASHTYPE_CRC_LOG:
3076
0
        modeName = "CRC";
3077
0
        break;
3078
0
      case VVENC_HASHTYPE_CHECKSUM:
3079
0
      case VVENC_HASHTYPE_CHECKSUM_LOG:
3080
0
        modeName = "Checksum";
3081
0
        break;
3082
1.29k
      default:
3083
1.29k
        break;
3084
1.29k
    }
3085
3086
1.29k
    if ( modeName.length() )
3087
0
    {
3088
0
      std::string cDigist = prnt(" [%s:%s]", modeName.c_str(), digestStr.empty() ? "?" : digestStr.c_str() );
3089
0
      accessUnit.InfoString.append( cDigist );
3090
0
    }
3091
1.29k
  }
3092
3093
1.29k
  if( !accessUnit.InfoString.empty() && m_pcEncCfg->m_verbosity >= VVENC_NOTICE )
3094
0
  {
3095
0
    std::string cPicInfo = accessUnit.InfoString;
3096
0
    cPicInfo.append("\n");
3097
0
    const vvencMsgLevel msgLevel = m_isPreAnalysis ? VVENC_DETAILS : VVENC_NOTICE;
3098
0
    msg.log( msgLevel, cPicInfo.c_str() );
3099
0
    if( m_pcEncCfg->m_verbosity >= msgLevel ) fflush( stdout );
3100
0
  }
3101
1.29k
}
3102
3103
void EncGOP::xForceScc( Picture& pic )
3104
1.29k
{
3105
1.29k
  if( pic.gopEntry->m_isStartOfGop )
3106
1.29k
  {
3107
1.29k
    m_forceSCC = pic.m_picShared->m_forceSCC;
3108
1.29k
  }
3109
1.29k
  if( m_forceSCC && (!pic.isSccStrong || !pic.isSccWeak) )
3110
0
  {
3111
0
    pic.isSccStrong = true;
3112
0
    pic.isSccWeak = true;
3113
0
    pic.setSccFlags(m_pcEncCfg);
3114
0
  }
3115
1.29k
}
3116
3117
} // namespace vvenc
3118
3119
//! \}
3120