Coverage Report

Created: 2026-04-01 07:49

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