Coverage Report

Created: 2026-10-17 06:56

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