Coverage Report

Created: 2026-06-15 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvenc/source/Lib/EncoderLib/EncLib.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     EncLib.cpp
45
    \brief    encoder class
46
*/
47
48
#include "EncLib.h"
49
#include "CommonLib/Picture.h"
50
#include "CommonLib/CommonDef.h"
51
#include "CommonLib/TimeProfiler.h"
52
#include "CommonLib/Rom.h"
53
#include "CommonLib/MCTF.h"
54
#include "Utilities/NoMallocThreadPool.h"
55
#include "Utilities/MsgLog.h"
56
#include "EncStage.h"
57
#include "PreProcess.h"
58
#include "EncGOP.h"
59
#include "CommonLib/x86/CommonDefX86.h"
60
61
//! \ingroup EncoderLib
62
//! \{
63
64
namespace vvenc {
65
66
67
// ====================================================================================================================
68
// Constructor / destructor / create / destroy
69
// ====================================================================================================================
70
71
EncLib::EncLib( MsgLog& logger )
72
1.08k
  : msg             ( logger )
73
1.08k
  , m_recYuvBufFunc  ( nullptr )
74
1.08k
  , m_recYuvBufCtx   ( nullptr )
75
1.08k
  , m_encCfg         ()
76
1.08k
  , m_orgCfg         ()
77
1.08k
  , m_firstPassCfg   ()
78
1.08k
  , m_rateCtrl       ( nullptr )
79
1.08k
  , m_preProcess     ( nullptr )
80
1.08k
  , m_MCTF           ( nullptr )
81
1.08k
  , m_preEncoder     ( nullptr )
82
1.08k
  , m_gopEncoder     ( nullptr )
83
1.08k
  , m_threadPool     ( nullptr )
84
1.08k
  , m_picsRcvd       ( 0 )
85
1.08k
  , m_passInitialized( -1 )
86
1.08k
  , m_maxNumPicShared( MAX_INT )
87
1.08k
  , m_accessUnitOutputStarted( false )
88
1.08k
{
89
1.08k
}
90
91
EncLib::~EncLib()
92
1.08k
{
93
1.08k
  delete m_rateCtrl;
94
1.08k
  m_rateCtrl = nullptr;
95
1.08k
}
96
97
void EncLib::setRecYUVBufferCallback( void* ctx, vvencRecYUVBufferCallback func )
98
0
{
99
0
  m_recYuvBufCtx  = ctx;
100
0
  m_recYuvBufFunc = func;
101
0
  if( m_rateCtrl && m_rateCtrl->rcIsFinalPass && m_gopEncoder )
102
0
  {
103
0
    m_gopEncoder->setRecYUVBufferCallback( m_recYuvBufCtx, m_recYuvBufFunc );
104
0
  }
105
0
}
106
107
void EncLib::initEncoderLib( const vvenc_config& encCfg )
108
1.08k
{
109
  // copy config parameter
110
1.08k
  const_cast<VVEncCfg&>(m_encCfg) = encCfg;
111
112
#if defined( REAL_TARGET_X86 ) && defined( _MSC_VER ) && _MSC_VER >= 1938 && _MSC_VER < 1939
113
  if( read_x86_extension_flags() >= x86_simd::AVX2 )
114
  {
115
    msg.log( VVENC_WARNING, "WARNING: MSVC version 17.8 produces invalid AVX2 code, partially disabling AVX2!\n" );
116
  }
117
118
#endif
119
  // setup modified configs for rate control
120
1.08k
  if( m_encCfg.m_RCNumPasses > 1 || m_encCfg.m_LookAhead )
121
0
  {
122
0
    xInitRCCfg();
123
0
  }
124
125
  // initialize pass
126
1.08k
  initPass( 0, nullptr );
127
128
#if ENABLE_TRACING
129
  g_trace_ctx = tracing_init( m_encCfg.m_traceFile, m_encCfg.m_traceRule, msg );
130
  if( g_trace_ctx && m_encCfg.m_listTracingChannels )
131
  {
132
    std::string sChannelsList;
133
    g_trace_ctx->getChannelsList( sChannelsList );
134
    msg.log( VVENC_INFO, "\n Using tracing channels:\n\n%s\n", sChannelsList.c_str() );
135
  }
136
#endif
137
138
#if ENABLE_TIME_PROFILING
139
  if( g_timeProfiler )
140
  {
141
    delete g_timeProfiler;
142
  }
143
  g_timeProfiler = timeProfilerCreate( encCfg );
144
#endif
145
1.08k
}
146
147
void EncLib::uninitEncoderLib()
148
1.08k
{
149
#if ENABLE_TRACING
150
  if( g_trace_ctx )
151
  {
152
    tracing_uninit( g_trace_ctx );
153
  }
154
#endif
155
156
#if ENABLE_CU_MODE_COUNTERS
157
  std::cout << std::endl;
158
  std::cout << "CU Modes statistic across picture types and temporal levels (0:Intra, >0:Inter, luma only)" << std::endl;
159
  for( size_t j = 0; j < g_cuCounters1D.getNumCntTypes(); j++ )
160
  {
161
    for( size_t i = 0; i < g_cuCounters1D.getDimHor() - 1; i++ )
162
    {
163
      g_cuCounters1D[j][0][g_cuCounters1D.getDimHor() - 1] += g_cuCounters1D[j][0][i];
164
    }
165
  }
166
  StatCounters::report2D( std::cout, g_cuCounters1D, false, true, false, true, true, CU_MODES_TESTED );
167
168
  std::cout << std::endl;
169
  std::cout << "CU Modes statistic across block-shapes (Non-I-Slices, luma only)" << std::endl;
170
  StatCounters::report2D( std::cout, g_cuCounters2D, true, true, false, true, true, CU_MODES_TESTED );
171
#endif
172
173
#if ENABLE_TIME_PROFILING
174
#if ENABLE_TIME_PROFILING_MT_MODE
175
  if( m_threadPool )
176
  {
177
    for(auto& p : m_threadPool->getProfilers())
178
    {
179
      *g_timeProfiler += *p;
180
    }
181
  }
182
#endif
183
  timeProfilerResults( g_timeProfiler );
184
  delete g_timeProfiler;
185
  g_timeProfiler = nullptr;
186
#endif
187
1.08k
  xUninitLib();
188
1.08k
}
189
190
void EncLib::initPass( int pass, const char* statsFName )
191
1.08k
{
192
1.08k
  CHECK( m_passInitialized != pass && m_passInitialized + 1 != pass, "initialization of passes only in successive order possible" );
193
194
1.08k
  if( m_rateCtrl == nullptr )
195
1.08k
  {
196
1.08k
    m_rateCtrl = new RateCtrl(msg);
197
1.08k
  }
198
199
1.08k
  m_rateCtrl->setRCPass( m_encCfg, pass, statsFName );
200
201
1.08k
  if( m_passInitialized + 1 != pass )
202
0
  {
203
0
    return;
204
0
  }
205
206
  // reset
207
1.08k
  xUninitLib();
208
209
  // enable encoder config based on rate control pass
210
1.08k
  if( m_encCfg.m_RCNumPasses > 1 || ( m_encCfg.m_LookAhead && m_orgCfg.m_RCTargetBitrate > 0 ) )
211
0
  {
212
0
    if( !m_rateCtrl->rcIsFinalPass )
213
0
    {
214
      // set encoder config for 1st rate control pass
215
0
      const_cast<VVEncCfg&>(m_encCfg) = m_firstPassCfg;
216
0
    }
217
0
    else
218
0
    {
219
      // restore encoder config for final 2nd RC pass
220
0
      const_cast<VVEncCfg&>(m_encCfg) = m_orgCfg;
221
0
      m_rateCtrl->init( m_encCfg );
222
0
      const_cast<VVEncCfg&>(m_encCfg).m_QP = m_rateCtrl->getBaseQP();
223
0
    }
224
0
    if( m_encCfg.m_RCTargetBitrate > 0 && !m_encCfg.m_LookAhead )
225
0
    {
226
0
      m_rateCtrl->processFirstPassData( false );
227
0
    }
228
0
  }
229
1.08k
  else if( m_encCfg.m_usePerceptQPA && m_encCfg.m_LookAhead )
230
0
  {
231
0
    m_rateCtrl->init( m_encCfg );
232
0
  }
233
234
  // thread pool
235
1.08k
  if( m_encCfg.m_numThreads > 0 )
236
1.08k
  {
237
1.08k
    m_threadPool = new NoMallocThreadPool( m_encCfg.m_numThreads, "EncSliceThreadPool", &m_encCfg );
238
1.08k
  }
239
1.08k
  m_maxNumPicShared = 0;
240
241
  // pre processing
242
1.08k
  m_preProcess = new PreProcess( msg );
243
1.08k
  m_preProcess->initStage( m_encCfg, 1, -m_encCfg.m_leadFrames, true, true, false );
244
1.08k
  m_preProcess->init( m_encCfg, m_rateCtrl->rcIsFinalPass );
245
1.08k
  m_encStages.push_back( m_preProcess );
246
1.08k
  m_maxNumPicShared += 1;
247
248
  // MCTF
249
1.08k
  if( m_encCfg.m_vvencMCTF.MCTF || m_encCfg.m_usePerceptQPA )
250
1.08k
  {
251
1.08k
    m_MCTF = new MCTF();
252
1.08k
    const int leadFrames   = std::min( VVENC_MCTF_RANGE, m_encCfg.m_leadFrames );
253
1.08k
    const int minQueueSize = m_encCfg.m_vvencMCTF.MCTFFutureReference ? ( leadFrames + 1 + VVENC_MCTF_RANGE ) : ( leadFrames + 1 );
254
1.08k
    m_MCTF->initStage( m_encCfg, minQueueSize, -leadFrames, true, true, false );
255
1.08k
    m_MCTF->init( m_encCfg, m_rateCtrl->rcIsFinalPass, m_threadPool );
256
1.08k
    m_encStages.push_back( m_MCTF );
257
1.08k
    m_maxNumPicShared += minQueueSize - leadFrames;
258
1.08k
  }
259
260
  // pre analysis encoder
261
1.08k
  if( m_encCfg.m_LookAhead )
262
0
  {
263
0
    m_preEncoder = new EncGOP( msg );
264
0
    const int minQueueSize = m_firstPassCfg.m_GOPSize + 1;
265
0
    m_preEncoder->initStage( m_firstPassCfg, minQueueSize, 0, false, false, false );
266
0
    m_preEncoder->init( m_firstPassCfg, m_preProcess->getGOPCfg(), *m_rateCtrl, m_threadPool, true );
267
0
    m_encStages.push_back( m_preEncoder );
268
0
    m_maxNumPicShared += minQueueSize;
269
0
  }
270
271
  // gop encoder
272
1.08k
  m_gopEncoder = new EncGOP( msg );
273
1.08k
  const int minQueueSize = m_encCfg.m_GOPSize + 1;
274
1.08k
  m_gopEncoder->initStage( m_encCfg, minQueueSize, 0, false, false, m_encCfg.m_stageParallelProc );
275
1.08k
  m_gopEncoder->init( m_encCfg, m_preProcess->getGOPCfg(), *m_rateCtrl, m_threadPool, false );
276
1.08k
  m_encStages.push_back( m_gopEncoder );
277
1.08k
  m_maxNumPicShared += minQueueSize;
278
279
  // additional pictures due to structural delay
280
1.08k
  m_maxNumPicShared += m_preProcess->getGOPCfg()->getNumReorderPics()[ m_encCfg.m_maxTLayer ];
281
1.08k
  m_maxNumPicShared += 3;
282
  // increase number of picture buffers for GOP parallel processing
283
1.08k
  m_maxNumPicShared += m_encCfg.m_numParallelGOPs ? (m_encCfg.m_GOPSize + 1) * m_encCfg.m_numParallelGOPs: 0;
284
285
1.08k
  if( m_rateCtrl->rcIsFinalPass )
286
1.08k
  {
287
1.08k
    m_gopEncoder->setRecYUVBufferCallback( m_recYuvBufCtx, m_recYuvBufFunc );
288
1.08k
  }
289
290
  // link encoder stages
291
3.25k
  for( int i = 0; i < (int)m_encStages.size() - 1; i++ )
292
2.17k
  {
293
2.17k
    m_encStages[ i ]->linkNextStage( m_encStages[ i + 1 ] );
294
2.17k
  }
295
296
1.08k
  m_picsRcvd                = -m_encCfg.m_leadFrames;
297
1.08k
  m_accessUnitOutputStarted = false;
298
1.08k
  m_passInitialized         = pass;
299
1.08k
}
300
301
void EncLib::xUninitLib()
302
2.17k
{
303
  // make sure all processing threads are stopped before releasing data
304
2.17k
  if( m_threadPool )
305
1.08k
  {
306
1.08k
    m_threadPool->shutdown( true );
307
1.08k
  }
308
309
  // sub modules
310
2.17k
  if( m_rateCtrl != nullptr )
311
2.17k
  {
312
2.17k
    m_rateCtrl->destroy();
313
2.17k
  }
314
2.17k
  if( m_preProcess )
315
1.08k
  {
316
1.08k
    delete m_preProcess;
317
1.08k
    m_preProcess = nullptr;
318
1.08k
  }
319
2.17k
  if( m_MCTF )
320
1.08k
  {
321
1.08k
    delete m_MCTF;
322
1.08k
    m_MCTF = nullptr;
323
1.08k
  }
324
2.17k
  if( m_preEncoder )
325
0
  {
326
0
    delete m_preEncoder;
327
0
    m_preEncoder = nullptr;
328
0
  }
329
2.17k
  if( m_gopEncoder )
330
1.08k
  {
331
1.08k
    delete m_gopEncoder;
332
1.08k
    m_gopEncoder = nullptr;
333
1.08k
  }
334
2.17k
  m_encStages.clear();
335
336
2.17k
  for( auto picShared : m_picSharedList )
337
1.08k
  {
338
1.08k
    delete picShared;
339
1.08k
  }
340
2.17k
  m_picSharedList.clear();
341
342
  // thread pool
343
2.17k
  if( m_threadPool )
344
1.08k
  {
345
1.08k
    delete m_threadPool;
346
1.08k
    m_threadPool = nullptr;
347
1.08k
  }
348
2.17k
}
349
350
void EncLib::xInitRCCfg()
351
0
{
352
  // backup original configuration
353
0
  const_cast<VVEncCfg&>(m_orgCfg) = m_encCfg;
354
355
  // initialize first pass configuration
356
0
  m_firstPassCfg = m_encCfg;
357
0
  vvenc_init_preset( &m_firstPassCfg, vvencPresetMode::VVENC_FIRSTPASS );
358
359
  // fixed-QP encoding in first rate control pass
360
0
  m_firstPassCfg.m_RCTargetBitrate = 0;
361
0
  if( m_firstPassCfg.m_FirstPassMode > 2 )
362
0
  {
363
0
    m_firstPassCfg.m_SourceWidth  = ( m_encCfg.m_SourceWidth  >> 1 ) & ( ~7 );
364
0
    m_firstPassCfg.m_SourceHeight = ( m_encCfg.m_SourceHeight >> 1 ) & ( ~7 );
365
0
    m_firstPassCfg.m_PadSourceWidth  = m_firstPassCfg.m_SourceWidth;
366
0
    m_firstPassCfg.m_PadSourceHeight = m_firstPassCfg.m_SourceHeight;
367
0
#if TILES_IFP_2PRC_HOTFIX
368
0
    if( m_firstPassCfg.m_ifp && (m_firstPassCfg.m_numTileCols > 1 || m_firstPassCfg.m_numTileRows > 1) )
369
0
    {
370
      // due to sub-sampling, expected different tile configuration in cfg (m_tileRowHeight[], m_tileColumnWidth[])
371
      // currently, disable auto tiles for the first pass
372
0
      m_firstPassCfg.m_numTileCols = 1;
373
0
      m_firstPassCfg.m_numTileRows = 1;
374
0
      m_firstPassCfg.m_picPartitionFlag = false;
375
0
    }
376
0
#endif
377
0
  }
378
379
  // preserve some settings
380
0
  m_firstPassCfg.m_intraQPOffset   = m_encCfg.m_intraQPOffset;
381
0
  m_firstPassCfg.m_GOPQPA          = m_encCfg.m_GOPQPA;
382
0
  if( m_firstPassCfg.m_usePerceptQPA && ( m_firstPassCfg.m_QP <= MAX_QP_PERCEPT_QPA || m_firstPassCfg.m_framesToBeEncoded == 1 ) )
383
0
  {
384
0
    m_firstPassCfg.m_CTUSize       = m_encCfg.m_CTUSize;
385
0
  }
386
0
  m_firstPassCfg.m_vvencMCTF.MCTF  = m_encCfg.m_vvencMCTF.MCTF;
387
0
  m_firstPassCfg.m_IBCMode         = m_encCfg.m_IBCMode;
388
0
  m_firstPassCfg.m_bimCtuSize      = m_encCfg.m_CTUSize;
389
0
  m_firstPassCfg.m_log2MinCodingBlockSize = m_encCfg.m_log2MinCodingBlockSize;
390
391
  // set Inter block size
392
0
  if( m_firstPassCfg.m_FirstPassMode > 0 )
393
0
  {
394
0
    m_firstPassCfg.m_MinQT[ 1 ] = m_firstPassCfg.m_MaxQT[ 1 ] = ( std::min( m_firstPassCfg.m_SourceWidth, m_firstPassCfg.m_SourceHeight ) < 720 ? 32 : 64 );
395
0
  }
396
397
  // clear MaxCuDQPSubdiv
398
0
  if( m_firstPassCfg.m_CTUSize < 128 && std::min( m_firstPassCfg.m_SourceWidth, m_firstPassCfg.m_SourceHeight ) >= 720 )
399
0
  {
400
0
    m_firstPassCfg.m_cuQpDeltaSubdiv = 0;
401
0
  }
402
0
}
403
404
// ====================================================================================================================
405
// Public member functions
406
// ====================================================================================================================
407
408
// The current I/O work flow consists of three main parts:
409
//   1. At the beginning, the encoder can consume input YUV buffers without an output.
410
//   2. After the first encoded picture/access unit is output, on each next call: one yuv-buffer IN / one encoded access unit (AU) OUT.
411
//      Hence, in stage-parallel mode, we must wait until next encoded picture (AU) is going to be output
412
//   3. When no more input is available, the top level goes into flushing mode: nullptr IN / one encoded access unit (AU) OUT. 
413
//      The encoder flushes the encoded AUs until the queues are empty.
414
415
void EncLib::encodePicture( bool flush, const vvencYUVBuffer* yuvInBuf, AccessUnitList& au, bool& isQueueEmpty )
416
2.17k
{
417
2.17k
  PROFILER_ACCUM_AND_START_NEW_SET( 1, g_timeProfiler, P_TOP_LEVEL );
418
419
2.17k
  CHECK( yuvInBuf == nullptr && ! flush, "no input picture given" );
420
421
  // clear output access unit
422
2.17k
  au.clearAu();
423
424
  // NOTE regarding the stage parallel processing
425
  // The next input yuv-buffer must be passed to the encoding process (1.Stage).
426
  // The following should be considered:
427
  //   1. The final stage is non-blocking, so it doesn't wait until picture is reconstructed.
428
  //   2. Generally, the stages have different throughput; last stage is the slowest.
429
  //   3. The number of picture-units required for the input yuv-buffers is limited.
430
  //   4. Due to chunk-mode and non-blockiness, it's possible that we can run out of picture-units.
431
  //   5. Then we have to wait for the next available picture-unit, so the input frame can be passed to the 1.stage.
432
433
2.17k
  PicShared* picShared = nullptr;
434
2.17k
  bool inputPending    = ( yuvInBuf != nullptr );
435
3.25k
  while( true )
436
3.25k
  {
437
    // send new YUV input buffer to first encoder stage
438
3.25k
    if( inputPending )
439
1.08k
    {
440
1.08k
      picShared = xGetFreePicShared();
441
1.08k
      if( picShared )
442
1.08k
      {
443
1.08k
        picShared->reuse( m_picsRcvd, yuvInBuf );
444
1.08k
        m_encStages[ 0 ]->addPicSorted( picShared, flush );
445
1.08k
        m_picsRcvd  += 1;
446
1.08k
        inputPending = false;
447
1.08k
      }
448
1.08k
    }
449
450
3.25k
    PROFILER_EXT_UPDATE( g_timeProfiler, P_TOP_LEVEL, 0 );
451
452
    // trigger stages
453
3.25k
    isQueueEmpty = m_picsRcvd > 0 || ( m_picsRcvd <= 0 && flush );
454
3.25k
    for( auto encStage : m_encStages )
455
9.77k
    {
456
9.77k
      encStage->runStage( flush, au );
457
9.77k
      isQueueEmpty &= encStage->isStageDone();
458
9.77k
    }
459
460
3.25k
    if( !au.empty() )
461
1.08k
    {
462
1.08k
      m_AuList.push_back( au );
463
464
1.08k
      au.detachNalUnitList();
465
1.08k
      au.clearAu();
466
      // NOTE: delay AU output in stage parallel mode only
467
1.08k
      if( !m_accessUnitOutputStarted )
468
1.08k
        m_accessUnitOutputStarted = !m_encCfg.m_stageParallelProc || m_AuList.size() > 4 || flush;
469
1.08k
    }
470
471
    // wait if input picture hasn't been stored yet or if encoding is running and no new output access unit has been encoded
472
3.25k
    bool waitAndStay = inputPending || ( m_rateCtrl->rcIsFinalPass && m_AuList.empty() && ! isQueueEmpty && ( m_accessUnitOutputStarted || flush ) );
473
3.25k
    if( ! waitAndStay )
474
2.17k
    {
475
2.17k
      break;
476
2.17k
    }
477
478
1.08k
    if( m_encCfg.m_stageParallelProc )
479
1.08k
    {
480
1.08k
      for( auto encStage : m_encStages )
481
3.25k
      {
482
3.25k
        if( encStage->isNonBlocking() )
483
1.08k
          encStage->waitForFreeEncoders();
484
3.25k
      }
485
1.08k
    }
486
1.08k
  }
487
488
  // check if we have an AU to output
489
2.17k
  if( !m_AuList.empty() && m_accessUnitOutputStarted )
490
1.08k
  {
491
1.08k
    au = m_AuList.front();
492
1.08k
    m_AuList.front().detachNalUnitList();
493
1.08k
    m_AuList.pop_front();
494
1.08k
  }
495
496
  // reset output access unit, if not final pass
497
2.17k
  if( ! m_rateCtrl->rcIsFinalPass )
498
0
  {
499
0
    au.clearAu();
500
0
  }
501
502
  // finally, ensure that the whole queue is empty
503
2.17k
  isQueueEmpty &= m_AuList.empty();
504
2.17k
}
505
506
void EncLib::printSummary()
507
0
{
508
0
  if( m_gopEncoder )
509
0
  {
510
0
    m_gopEncoder->printOutSummary( m_encCfg.m_printMSEBasedSequencePSNR, m_encCfg.m_printSequenceMSE, m_encCfg.m_printHexPsnr );
511
0
  }
512
0
}
513
514
void EncLib::getParameterSets( AccessUnitList& au )
515
0
{
516
0
  if( m_gopEncoder )
517
0
  {
518
0
    m_gopEncoder->getParameterSets( au );
519
0
  }
520
0
}
521
522
int EncLib::getCurPass() const
523
0
{
524
0
  return m_passInitialized;
525
0
}
526
527
// ====================================================================================================================
528
// Protected member functions
529
// ====================================================================================================================
530
531
PicShared* EncLib::xGetFreePicShared()
532
1.08k
{
533
1.08k
  PicShared* picShared = nullptr;
534
1.08k
  for( auto itr : m_picSharedList )
535
0
  {
536
0
    if( ! itr->isUsed() )
537
0
    {
538
0
      picShared = itr;
539
0
      break;
540
0
    }
541
0
  }
542
543
1.08k
  if( ! picShared )
544
1.08k
  {
545
1.08k
    if( m_encCfg.m_stageParallelProc && ( m_picSharedList.size() >= m_maxNumPicShared ) )
546
0
      return nullptr;
547
548
1.08k
    picShared = new PicShared();
549
1.08k
    picShared->create( m_encCfg.m_framesToBeEncoded, m_encCfg.m_internChromaFormat, Size( m_encCfg.m_PadSourceWidth, m_encCfg.m_PadSourceHeight ), m_encCfg.m_vvencMCTF.MCTF || m_encCfg.m_usePerceptQPA );
550
1.08k
    m_picSharedList.push_back( picShared );
551
1.08k
  }
552
1.08k
  CHECK( picShared == nullptr, "out of memory" );
553
554
1.08k
  return picShared;
555
1.08k
}
556
557
} // namespace vvenc
558
559
//! \}