Coverage Report

Created: 2026-09-14 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvenc/source/Lib/EncoderLib/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.19k
  : msg             ( logger )
73
1.19k
  , m_recYuvBufFunc  ( nullptr )
74
1.19k
  , m_recYuvBufCtx   ( nullptr )
75
1.19k
  , m_encCfg         ()
76
1.19k
  , m_orgCfg         ()
77
1.19k
  , m_firstPassCfg   ()
78
1.19k
  , m_rateCtrl       ( nullptr )
79
1.19k
  , m_preProcess     ( nullptr )
80
1.19k
  , m_MCTF           ( nullptr )
81
1.19k
  , m_preEncoder     ( nullptr )
82
1.19k
  , m_gopEncoder     ( nullptr )
83
1.19k
  , m_threadPool     ( nullptr )
84
1.19k
  , m_picsRcvd       ( 0 )
85
1.19k
  , m_passInitialized( -1 )
86
1.19k
  , m_maxNumPicShared( MAX_INT )
87
1.19k
  , m_accessUnitOutputStarted( false )
88
1.19k
{
89
1.19k
}
90
91
EncLib::~EncLib()
92
1.19k
{
93
1.19k
  delete m_rateCtrl;
94
1.19k
  m_rateCtrl = nullptr;
95
1.19k
}
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.19k
{
109
  // copy config parameter
110
1.19k
  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.19k
  if( m_encCfg.m_RCNumPasses > 1 || m_encCfg.m_LookAhead )
121
0
  {
122
0
    xInitRCCfg();
123
0
  }
124
125
  // initialize pass
126
1.19k
  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.19k
}
146
147
void EncLib::uninitEncoderLib()
148
1.19k
{
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.19k
  xUninitLib();
188
1.19k
}
189
190
void EncLib::initPass( int pass, const char* statsFName )
191
1.19k
{
192
1.19k
  CHECK( m_passInitialized != pass && m_passInitialized + 1 != pass, "initialization of passes only in successive order possible" );
193
194
1.19k
  if( m_rateCtrl == nullptr )
195
1.19k
  {
196
1.19k
    m_rateCtrl = new RateCtrl(msg);
197
1.19k
  }
198
199
1.19k
  m_rateCtrl->setRCPass( m_encCfg, pass, statsFName );
200
201
1.19k
  if( m_passInitialized + 1 != pass )
202
0
  {
203
0
    return;
204
0
  }
205
206
  // reset
207
1.19k
  xUninitLib();
208
209
  // enable encoder config based on rate control pass
210
1.19k
  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.19k
  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.19k
  if( m_encCfg.m_numThreads > 0 )
236
1.19k
  {
237
1.19k
    m_threadPool = new NoMallocThreadPool( m_encCfg.m_numThreads, "EncSliceThreadPool", &m_encCfg );
238
1.19k
  }
239
1.19k
  m_maxNumPicShared = 0;
240
241
  // pre processing
242
1.19k
  m_preProcess = new PreProcess( msg );
243
1.19k
  m_preProcess->initStage( m_encCfg, 1, -m_encCfg.m_leadFrames, true, true, false );
244
1.19k
  m_preProcess->init( m_encCfg, m_rateCtrl->rcIsFinalPass );
245
1.19k
  m_encStages.push_back( m_preProcess );
246
1.19k
  m_maxNumPicShared += 1;
247
248
  // MCTF
249
1.19k
  if( m_encCfg.m_vvencMCTF.MCTF || m_encCfg.m_usePerceptQPA )
250
1.19k
  {
251
1.19k
    m_MCTF = new MCTF();
252
1.19k
    const int leadFrames   = std::min( VVENC_MCTF_RANGE, m_encCfg.m_leadFrames );
253
1.19k
    const int minQueueSize = m_encCfg.m_vvencMCTF.MCTFFutureReference ? ( leadFrames + 1 + VVENC_MCTF_RANGE ) : ( leadFrames + 1 );
254
1.19k
    m_MCTF->initStage( m_encCfg, minQueueSize, -leadFrames, true, true, false );
255
1.19k
    m_MCTF->init( m_encCfg, m_rateCtrl->rcIsFinalPass, m_threadPool );
256
1.19k
    m_encStages.push_back( m_MCTF );
257
1.19k
    m_maxNumPicShared += minQueueSize - leadFrames;
258
1.19k
  }
259
260
  // pre analysis encoder
261
1.19k
  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.19k
  m_gopEncoder = new EncGOP( msg );
273
1.19k
  const int minQueueSize = m_encCfg.m_GOPSize + 1;
274
1.19k
  m_gopEncoder->initStage( m_encCfg, minQueueSize, 0, false, false, m_encCfg.m_stageParallelProc );
275
1.19k
  m_gopEncoder->init( m_encCfg, m_preProcess->getGOPCfg(), *m_rateCtrl, m_threadPool, false );
276
1.19k
  m_encStages.push_back( m_gopEncoder );
277
1.19k
  m_maxNumPicShared += minQueueSize;
278
279
  // additional pictures due to structural delay
280
1.19k
  m_maxNumPicShared += m_preProcess->getGOPCfg()->getNumReorderPics()[ m_encCfg.m_maxTLayer ];
281
1.19k
  m_maxNumPicShared += 3;
282
  // increase number of picture buffers for GOP parallel processing
283
1.19k
  m_maxNumPicShared += m_encCfg.m_numParallelGOPs ? (m_encCfg.m_GOPSize + 1) * m_encCfg.m_numParallelGOPs: 0;
284
285
1.19k
  if( m_rateCtrl->rcIsFinalPass )
286
1.19k
  {
287
1.19k
    m_gopEncoder->setRecYUVBufferCallback( m_recYuvBufCtx, m_recYuvBufFunc );
288
1.19k
  }
289
290
  // link encoder stages
291
3.59k
  for( int i = 0; i < (int)m_encStages.size() - 1; i++ )
292
2.39k
  {
293
2.39k
    m_encStages[ i ]->linkNextStage( m_encStages[ i + 1 ] );
294
2.39k
  }
295
296
1.19k
  m_picsRcvd                = -m_encCfg.m_leadFrames;
297
1.19k
  m_accessUnitOutputStarted = false;
298
1.19k
  m_passInitialized         = pass;
299
1.19k
}
300
301
void EncLib::xUninitLib()
302
2.39k
{
303
  // make sure all processing threads are stopped before releasing data
304
2.39k
  if( m_threadPool )
305
1.19k
  {
306
1.19k
    m_threadPool->shutdown( true );
307
1.19k
  }
308
309
  // sub modules
310
2.39k
  if( m_rateCtrl != nullptr )
311
2.39k
  {
312
2.39k
    m_rateCtrl->destroy();
313
2.39k
  }
314
2.39k
  if( m_preProcess )
315
1.19k
  {
316
1.19k
    delete m_preProcess;
317
1.19k
    m_preProcess = nullptr;
318
1.19k
  }
319
2.39k
  if( m_MCTF )
320
1.19k
  {
321
1.19k
    delete m_MCTF;
322
1.19k
    m_MCTF = nullptr;
323
1.19k
  }
324
2.39k
  if( m_preEncoder )
325
0
  {
326
0
    delete m_preEncoder;
327
0
    m_preEncoder = nullptr;
328
0
  }
329
2.39k
  if( m_gopEncoder )
330
1.19k
  {
331
1.19k
    delete m_gopEncoder;
332
1.19k
    m_gopEncoder = nullptr;
333
1.19k
  }
334
2.39k
  m_encStages.clear();
335
336
2.39k
  for( auto picShared : m_picSharedList )
337
1.19k
  {
338
1.19k
    delete picShared;
339
1.19k
  }
340
2.39k
  m_picSharedList.clear();
341
342
  // thread pool
343
2.39k
  if( m_threadPool )
344
1.19k
  {
345
1.19k
    delete m_threadPool;
346
1.19k
    m_threadPool = nullptr;
347
1.19k
  }
348
2.39k
}
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.39k
{
417
2.39k
  PROFILER_ACCUM_AND_START_NEW_SET( 1, g_timeProfiler, P_TOP_LEVEL );
418
419
2.39k
  CHECK( yuvInBuf == nullptr && ! flush, "no input picture given" );
420
421
  // clear output access unit
422
2.39k
  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.39k
  PicShared* picShared = nullptr;
434
2.39k
  bool inputPending    = ( yuvInBuf != nullptr );
435
3.59k
  while( true )
436
3.59k
  {
437
    // send new YUV input buffer to first encoder stage
438
3.59k
    if( inputPending )
439
1.19k
    {
440
1.19k
      picShared = xGetFreePicShared();
441
1.19k
      if( picShared )
442
1.19k
      {
443
1.19k
        picShared->reuse( m_picsRcvd, yuvInBuf );
444
1.19k
        m_encStages[ 0 ]->addPicSorted( picShared, flush );
445
1.19k
        m_picsRcvd  += 1;
446
1.19k
        inputPending = false;
447
1.19k
      }
448
1.19k
    }
449
450
3.59k
    PROFILER_EXT_UPDATE( g_timeProfiler, P_TOP_LEVEL, 0 );
451
452
    // trigger stages
453
3.59k
    isQueueEmpty = m_picsRcvd > 0 || ( m_picsRcvd <= 0 && flush );
454
3.59k
    for( auto encStage : m_encStages )
455
10.7k
    {
456
10.7k
      encStage->runStage( flush, au );
457
10.7k
      isQueueEmpty &= encStage->isStageDone();
458
10.7k
    }
459
460
3.59k
    if( !au.empty() )
461
1.19k
    {
462
1.19k
      m_AuList.push_back( au );
463
464
1.19k
      au.detachNalUnitList();
465
1.19k
      au.clearAu();
466
      // NOTE: delay AU output in stage parallel mode only
467
1.19k
      if( !m_accessUnitOutputStarted )
468
1.19k
        m_accessUnitOutputStarted = !m_encCfg.m_stageParallelProc || m_AuList.size() > 4 || flush;
469
1.19k
    }
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.59k
    bool waitAndStay = inputPending || ( m_rateCtrl->rcIsFinalPass && m_AuList.empty() && ! isQueueEmpty && ( m_accessUnitOutputStarted || flush ) );
473
3.59k
    if( ! waitAndStay )
474
2.39k
    {
475
2.39k
      break;
476
2.39k
    }
477
478
1.19k
    if( m_encCfg.m_stageParallelProc )
479
1.19k
    {
480
1.19k
      for( auto encStage : m_encStages )
481
3.59k
      {
482
3.59k
        if( encStage->isNonBlocking() )
483
1.19k
          encStage->waitForFreeEncoders();
484
3.59k
      }
485
1.19k
    }
486
1.19k
  }
487
488
  // check if we have an AU to output
489
2.39k
  if( !m_AuList.empty() && m_accessUnitOutputStarted )
490
1.19k
  {
491
1.19k
    au = m_AuList.front();
492
1.19k
    m_AuList.front().detachNalUnitList();
493
1.19k
    m_AuList.pop_front();
494
1.19k
  }
495
496
  // reset output access unit, if not final pass
497
2.39k
  if( ! m_rateCtrl->rcIsFinalPass )
498
0
  {
499
0
    au.clearAu();
500
0
  }
501
502
  // finally, ensure that the whole queue is empty
503
2.39k
  isQueueEmpty &= m_AuList.empty();
504
2.39k
}
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.19k
{
533
1.19k
  PicShared* picShared = nullptr;
534
1.19k
  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.19k
  if( ! picShared )
544
1.19k
  {
545
1.19k
    if( m_encCfg.m_stageParallelProc && ( m_picSharedList.size() >= m_maxNumPicShared ) )
546
0
      return nullptr;
547
548
1.19k
    picShared = new PicShared();
549
1.19k
    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.19k
    m_picSharedList.push_back( picShared );
551
1.19k
  }
552
1.19k
  CHECK( picShared == nullptr, "out of memory" );
553
554
1.19k
  return picShared;
555
1.19k
}
556
557
} // namespace vvenc
558
559
//! \}