Coverage Report

Created: 2026-09-14 06:44

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