Coverage Report

Created: 2026-09-14 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvenc/source/Lib/vvenc/vvencimpl.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
  \ingroup vvenc
45
  \file    vvencimpl.cpp
46
  \brief   This file contains the internal interface of the vvenc SDK.
47
*/
48
49
#include "vvencimpl.h"
50
51
#include <iostream>
52
#include <stdio.h>
53
#include <algorithm>
54
55
#include "vvenc/version.h"
56
#include "CommonLib/CommonDef.h"
57
#include "CommonLib/Nal.h"
58
#include "CommonLib/Picture.h"
59
#include "EncoderLib/EncGOP.h"
60
#include "EncoderLib/EncLib.h"
61
62
#if ENABLE_SIMD_TRAFO
63
#include "CommonLib/TrQuant_EMT.h"
64
#endif  // ENABLE_SIMD_TRAFO
65
66
#if defined( __linux__ )
67
#include <malloc.h>
68
#endif
69
70
#if defined( TARGET_SIMD_X86 )
71
#include "CommonLib/x86/CommonDefX86.h"
72
#endif  // defined( TARGET_SIMD_X86 )
73
#if defined( TARGET_SIMD_ARM )
74
#include "CommonLib/arm/CommonDefARM.h"
75
#endif  // defined( TARGET_SIMD_ARM )
76
77
#if _DEBUG
78
#define HANDLE_EXCEPTION 0
79
#else
80
#define HANDLE_EXCEPTION 1
81
#endif
82
83
84
namespace vvenc {
85
86
#define ROTPARAMS(x, message) if(x) { rcErrorString = message; return VVENC_ERR_PARAMETER;}
87
88
// ====================================================================================================================
89
90
static_assert( sizeof(Pel)  == sizeof(*(vvencYUVPlane::ptr)),   "internal bits per pel differ from interface definition" );
91
92
// ====================================================================================================================
93
94
VVEncImpl::VVEncImpl()
95
1.19k
{
96
1.19k
  setSIMDExtension( nullptr );   // ensure SIMD-detection is finished
97
1.19k
  m_cEncoderInfo = createEncoderInfoStr();
98
1.19k
}
99
100
VVEncImpl::~VVEncImpl()
101
1.19k
{
102
103
1.19k
}
104
105
int VVEncImpl::getConfig( vvenc_config& config ) const
106
0
{
107
0
  if( !m_bInitialized ){ return VVENC_ERR_INITIALIZE; }
108
109
0
  config = m_cVVEncCfg;
110
0
  return VVENC_OK;
111
0
}
112
113
int VVEncImpl::reconfig( const vvenc_config&  )
114
0
{
115
0
  if( !m_bInitialized ){ return VVENC_ERR_INITIALIZE; }
116
0
  return VVENC_ERR_NOT_SUPPORTED;
117
0
}
118
119
int VVEncImpl::checkConfig( const vvenc_config& config )
120
0
{
121
0
  vvenc_config configCpy = config;
122
0
  if ( vvenc_init_config_parameter(&configCpy) )
123
0
  {
124
0
    return VVENC_ERR_INITIALIZE;
125
0
  }
126
127
0
  return VVENC_OK;
128
0
}
129
130
int VVEncImpl::init( vvenc_config* config )
131
1.19k
{
132
1.19k
  if( m_bInitialized ){ return VVENC_ERR_INITIALIZE; }
133
134
1.19k
  if (nullptr == config)
135
0
  {
136
0
    msg.log( VVENC_ERROR, "vvenc_config is null\n" );
137
0
    return VVENC_ERR_PARAMETER;
138
0
  }
139
140
1.19k
  m_cVVEncCfgExt = *config;
141
1.19k
  m_cVVEncCfg    = *config;
142
143
1.19k
  if ( vvenc_init_config_parameter(&m_cVVEncCfg) ) // init auto/dependent options
144
0
  {
145
0
    return VVENC_ERR_INITIALIZE;
146
0
  }
147
148
1.19k
  if( config->m_msgFnc )
149
0
  { 
150
0
    msg.setCallback( config->m_msgCtx, config->m_msgFnc );
151
0
  }
152
153
1.19k
  #if !IFP_RC_DETERMINISTIC
154
1.19k
  if( m_cVVEncCfg.m_RCTargetBitrate != 0 && m_cVVEncCfg.m_ifp )
155
0
  {
156
0
    msg.log( VVENC_WARNING, "Using RC with IFP. Results are non-deterministic!\n" );
157
0
  }
158
1.19k
#endif
159
160
  // initialize the encoder
161
1.19k
  m_pEncLib = new EncLib ( msg );
162
163
#if HANDLE_EXCEPTION
164
  try
165
#endif
166
1.19k
  {
167
1.19k
    m_pEncLib->initEncoderLib( m_cVVEncCfg );
168
1.19k
  }
169
#if HANDLE_EXCEPTION
170
  catch( std::exception& e )
171
  {
172
    msg.log( VVENC_ERROR, "\n%s\n", e.what() );
173
    m_cErrorString = e.what();
174
    return VVENC_ERR_UNSPECIFIED;
175
  }
176
#endif
177
178
1.19k
  m_bInitialized = true;
179
1.19k
  m_eState       = INTERNAL_STATE_INITIALIZED;
180
1.19k
  return VVENC_OK;
181
1.19k
}
182
183
int VVEncImpl::initPass( int pass, const char* statsFName )
184
0
{
185
0
  if( !m_bInitialized ){ return VVENC_ERR_INITIALIZE; }
186
0
  if( pass > 1 )
187
0
  {
188
0
    std::stringstream css;
189
0
    css << "initPass(" << pass << ") no support for pass " << pass << ". use 0 (first pass) and 1 (second pass)";
190
0
    m_cErrorString = css.str();
191
0
    return VVENC_ERR_NOT_SUPPORTED;
192
0
  }
193
194
0
  if ( m_pEncLib )
195
0
  {
196
#if HANDLE_EXCEPTION
197
    try
198
#endif
199
0
    {
200
0
      m_pEncLib->initPass( pass, statsFName );
201
0
    }
202
#if HANDLE_EXCEPTION
203
    catch( std::exception& e )
204
    {
205
      msg.log( VVENC_ERROR, "\n%s\n", e.what() );
206
      m_cErrorString = e.what();
207
      return VVENC_ERR_UNSPECIFIED;
208
    }
209
#endif
210
0
  }
211
212
0
  m_eState = INTERNAL_STATE_INITIALIZED;
213
0
  return VVENC_OK;
214
0
}
215
216
int VVEncImpl::uninit()
217
1.19k
{
218
1.19k
  if( !m_bInitialized ){ return VVENC_ERR_INITIALIZE; }
219
220
1.19k
  if ( m_pEncLib )
221
1.19k
  {
222
#if HANDLE_EXCEPTION
223
    try
224
#endif
225
1.19k
    {
226
1.19k
      m_pEncLib->uninitEncoderLib();
227
1.19k
      delete m_pEncLib;
228
1.19k
      m_pEncLib = nullptr;
229
1.19k
    }
230
#if HANDLE_EXCEPTION
231
    catch( std::exception& e )
232
    {
233
      msg.log( VVENC_ERROR, "\n%s\n", e.what() );
234
      m_cErrorString = e.what();
235
      return VVENC_ERR_UNSPECIFIED;
236
    }
237
#endif
238
1.19k
  }
239
240
1.19k
#if defined( __linux__ ) && defined( __GLIBC__ )
241
1.19k
  malloc_trim(0);   // free unused heap memory
242
1.19k
#endif
243
244
1.19k
  m_bInitialized = false;
245
1.19k
  m_eState       = INTERNAL_STATE_UNINITIALIZED;
246
1.19k
  return VVENC_OK;
247
1.19k
}
248
249
bool VVEncImpl::isInitialized() const
250
0
{
251
0
  return m_bInitialized;
252
0
}
253
254
int VVEncImpl::setRecYUVBufferCallback( void * ctx, vvencRecYUVBufferCallback callback )
255
0
{
256
0
  if( !m_bInitialized || !m_pEncLib ){ return VVENC_ERR_INITIALIZE; }
257
258
0
   m_pEncLib->setRecYUVBufferCallback( ctx, callback );
259
0
  return VVENC_OK;
260
0
}
261
262
int VVEncImpl::encode( vvencYUVBuffer* pcYUVBuffer, vvencAccessUnit* pcAccessUnit, bool* pbEncodeDone )
263
2.39k
{
264
2.39k
  if( !m_bInitialized )                      { return VVENC_ERR_INITIALIZE; }
265
2.39k
  if( m_eState == INTERNAL_STATE_FINALIZED ) { m_cErrorString = "encoder already flushed, please reinit."; return VVENC_ERR_RESTART_REQUIRED; }
266
267
2.39k
  if( !pcAccessUnit )
268
0
  {
269
0
    m_cErrorString = "vvencAccessUnit is null. AU memory must be allocated before encode call.";
270
0
    return VVENC_NOT_ENOUGH_MEM;
271
0
  }
272
2.39k
  if( pcAccessUnit->payloadSize <= 0 )
273
0
  {
274
0
    m_cErrorString = "vvencAccessUnit has no payload size. AU payload must have a sufficient size to store encoded data.";
275
0
    return VVENC_NOT_ENOUGH_MEM;
276
0
  }
277
278
2.39k
  int iRet= VVENC_OK;
279
280
2.39k
  bool bFlush = false;
281
2.39k
  if( pcYUVBuffer )
282
1.19k
  {
283
1.19k
    if( m_eState == INTERNAL_STATE_FLUSHING ) { m_cErrorString = "encoder already received flush indication, please reinit."; return VVENC_ERR_RESTART_REQUIRED; }
284
285
1.19k
    if( pcYUVBuffer->planes[0].ptr == nullptr )
286
0
    {
287
0
      m_cErrorString = "InputPicture: invalid input buffers";
288
0
      return VVENC_ERR_UNSPECIFIED;
289
0
    }
290
291
1.19k
    if( m_cVVEncCfg.m_internChromaFormat != VVENC_CHROMA_400 )
292
1.19k
    {
293
1.19k
      if( pcYUVBuffer->planes[1].ptr == nullptr ||
294
1.19k
          pcYUVBuffer->planes[2].ptr == nullptr )
295
0
      {
296
0
        m_cErrorString = "InputPicture: invalid input buffers for chroma";
297
0
        return VVENC_ERR_UNSPECIFIED;
298
0
      }
299
1.19k
    }
300
301
1.19k
    if( pcYUVBuffer->planes[0].width != m_cVVEncCfg.m_SourceWidth )
302
0
    {
303
0
      m_cErrorString = "InputPicture: unsupported width";
304
0
      return VVENC_ERR_UNSPECIFIED;
305
0
    }
306
307
1.19k
    if( pcYUVBuffer->planes[0].height != m_cVVEncCfg.m_SourceHeight )
308
0
    {
309
0
      m_cErrorString = "InputPicture: unsupported height";
310
0
      return VVENC_ERR_UNSPECIFIED;
311
0
    }
312
313
1.19k
    if( pcYUVBuffer->planes[0].width > pcYUVBuffer->planes[0].stride )
314
0
    {
315
0
      m_cErrorString = "InputPicture: unsupported width stride combination";
316
0
      return VVENC_ERR_UNSPECIFIED;
317
0
    }
318
319
1.19k
    if( m_cVVEncCfg.m_internChromaFormat != VVENC_CHROMA_400 )
320
1.19k
    {
321
1.19k
      if( m_cVVEncCfg.m_internChromaFormat == VVENC_CHROMA_444 )
322
0
      {
323
0
        if( pcYUVBuffer->planes[1].stride && pcYUVBuffer->planes[0].width > pcYUVBuffer->planes[1].stride )
324
0
        {
325
0
          m_cErrorString = "InputPicture: unsupported width cstride combination for 2nd plane";
326
0
          return VVENC_ERR_UNSPECIFIED;
327
0
        }
328
329
0
        if( pcYUVBuffer->planes[2].stride && pcYUVBuffer->planes[0].width > pcYUVBuffer->planes[2].stride )
330
0
        {
331
0
          m_cErrorString = "InputPicture: unsupported width cstride combination for 3rd plane";
332
0
          return VVENC_ERR_UNSPECIFIED;
333
0
        }
334
0
      }
335
1.19k
      else
336
1.19k
      {
337
1.19k
        if( pcYUVBuffer->planes[1].stride && pcYUVBuffer->planes[0].width/2 > pcYUVBuffer->planes[1].stride )
338
0
        {
339
0
          m_cErrorString = "InputPicture: unsupported width cstride combination for 2nd plane";
340
0
          return VVENC_ERR_UNSPECIFIED;
341
0
        }
342
343
1.19k
        if( pcYUVBuffer->planes[2].stride && pcYUVBuffer->planes[0].width/2 > pcYUVBuffer->planes[2].stride )
344
0
        {
345
0
          m_cErrorString = "InputPicture: unsupported width cstride combination for 3rd plane";
346
0
          return VVENC_ERR_UNSPECIFIED;
347
0
        }
348
1.19k
      }
349
1.19k
    }
350
351
1.19k
    if ( ! xConvertVerifyYUVBuffer( pcYUVBuffer ) )
352
0
    {     
353
0
      m_cErrorString = "InputPicture: Source image contains values outside the specified bit range";
354
0
      return VVENC_ERR_UNSPECIFIED;
355
0
    }
356
357
1.19k
    if( m_eState == INTERNAL_STATE_INITIALIZED ){ m_eState = INTERNAL_STATE_ENCODING; }
358
1.19k
  }
359
1.19k
  else
360
1.19k
  {
361
1.19k
    if( m_eState == INTERNAL_STATE_ENCODING ){ m_eState = INTERNAL_STATE_FLUSHING; }
362
1.19k
    bFlush = true;
363
1.19k
  }
364
365
  // reset AU data
366
2.39k
  if( pcAccessUnit )
367
2.39k
  {
368
2.39k
    vvenc_accessUnit_reset(pcAccessUnit);
369
2.39k
  }
370
2.39k
  *pbEncodeDone  = false;
371
372
2.39k
  AccessUnitList cAu;
373
#if HANDLE_EXCEPTION
374
  try
375
#endif
376
2.39k
  {
377
2.39k
    m_pEncLib->encodePicture( bFlush, pcYUVBuffer, cAu, *pbEncodeDone );
378
2.39k
  }
379
#if HANDLE_EXCEPTION
380
  catch( std::exception& e )
381
  {
382
    msg.log( VVENC_ERROR, "\n%s\n", e.what() );
383
    m_cErrorString = e.what();
384
    return VVENC_ERR_UNSPECIFIED;
385
  }
386
#endif
387
388
2.39k
  if( *pbEncodeDone )
389
1.19k
  {
390
1.19k
    if( m_eState == INTERNAL_STATE_FLUSHING )
391
1.19k
    {
392
1.19k
      m_eState = INTERNAL_STATE_FINALIZED;
393
1.19k
    }
394
0
    else if( m_eState == INTERNAL_STATE_INITIALIZED )
395
0
    {
396
0
      m_eState = INTERNAL_STATE_INITIALIZED; // keep initialized state, when flushing without having encoded anything, we still can start to encode
397
0
    }
398
0
    else
399
0
    {
400
0
      *pbEncodeDone = false;
401
0
    }
402
1.19k
  }
403
1.19k
  else
404
1.19k
  {
405
1.19k
    if( bFlush && m_cVVEncCfg.m_RCNumPasses == 2 && m_pEncLib->getCurPass() == 0 )
406
0
    {
407
      // process all remaining pictures of first pass on first flush packet 
408
0
      while ( ! *pbEncodeDone )
409
0
      {
410
#if HANDLE_EXCEPTION
411
        try
412
#endif
413
0
        {
414
0
          m_pEncLib->encodePicture( bFlush, pcYUVBuffer, cAu, *pbEncodeDone );
415
0
        }
416
#if HANDLE_EXCEPTION
417
        catch( std::exception& e )
418
        {
419
          msg.log( VVENC_ERROR, "\n%s\n", e.what() );
420
          m_cErrorString = e.what();
421
          return VVENC_ERR_UNSPECIFIED;
422
        }
423
#endif 
424
0
      }
425
0
      m_eState = INTERNAL_STATE_FINALIZED;      
426
0
    }
427
1.19k
  }
428
429
  /* copy output AU */
430
2.39k
  if ( !cAu.empty() )
431
1.19k
  {
432
1.19k
    int sizeAu = xGetAccessUnitsSize( cAu );
433
1.19k
    if( pcAccessUnit->payloadSize < sizeAu )
434
0
    {
435
0
      std::stringstream css;
436
0
      css << "vvencAccessUnit payload size is too small to store data. (payload size: " << pcAccessUnit->payloadSize << ", needed " << sizeAu << ")";
437
0
      m_cErrorString =css.str();
438
0
      return VVENC_NOT_ENOUGH_MEM;
439
0
    }
440
441
1.19k
    iRet = xCopyAu( *pcAccessUnit, cAu  );
442
1.19k
  }
443
444
2.39k
#if defined( __linux__ ) && defined( __GLIBC__ )
445
2.39k
  malloc_trim(0);   // free unused heap memory
446
2.39k
#endif
447
448
2.39k
  return iRet;
449
2.39k
}
450
451
int VVEncImpl::getParameterSets( vvencAccessUnit *pcAccessUnit )
452
0
{
453
0
  if( !m_bInitialized )                      { return VVENC_ERR_INITIALIZE; }
454
0
  if( m_eState == INTERNAL_STATE_FINALIZED ) { m_cErrorString = "encoder already flushed, please reinit."; return VVENC_ERR_RESTART_REQUIRED; }
455
456
0
  if( !pcAccessUnit )
457
0
  {
458
0
    m_cErrorString = "vvencAccessUnit is null. AU memory must be allocated before encode call.";
459
0
    return VVENC_NOT_ENOUGH_MEM;
460
0
  }
461
0
  if( pcAccessUnit->payloadSize <= 0 )
462
0
  {
463
0
    m_cErrorString = "vvencAccessUnit has no payload size. AU payload must have a sufficient size to store encoded data.";
464
0
    return VVENC_NOT_ENOUGH_MEM;
465
0
  }
466
467
0
  int iRet= VVENC_OK;
468
469
  // reset AU data
470
0
  vvenc_accessUnit_reset(pcAccessUnit);
471
472
0
  AccessUnitList cAu;
473
#if HANDLE_EXCEPTION
474
  try
475
#endif
476
0
  {
477
0
    m_pEncLib->getParameterSets( cAu );
478
0
  }
479
#if HANDLE_EXCEPTION
480
  catch( std::exception& e )
481
  {
482
    msg.log( VVENC_ERROR, "\n%s\n", e.what() );
483
    m_cErrorString = e.what();
484
    return VVENC_ERR_UNSPECIFIED;
485
  }
486
#endif
487
488
  /* copy output AU */
489
0
  if ( !cAu.empty() )
490
0
  {
491
0
    int sizeAu = xGetAccessUnitsSize( cAu );
492
0
    if( pcAccessUnit->payloadSize < sizeAu )
493
0
    {
494
0
      std::stringstream css;
495
0
      css << "vvencAccessUnit payload size is too small to store data. (payload size: " << pcAccessUnit->payloadSize << ", needed " << sizeAu << ")";
496
0
      m_cErrorString =css.str();
497
0
      return VVENC_NOT_ENOUGH_MEM;
498
0
    }
499
500
0
    iRet = xCopyAu( *pcAccessUnit, cAu  );
501
0
  }
502
503
0
  return iRet;
504
0
}
505
506
507
508
const char* VVEncImpl::getVersionNumber()
509
0
{
510
0
  return VVENC_VERSION;
511
0
}
512
513
const char* VVEncImpl::getEncoderInfo() const
514
0
{
515
0
  return m_cEncoderInfo.c_str();
516
0
}
517
518
const char* VVEncImpl::getLastError() const
519
0
{
520
0
  return m_cErrorString.c_str();
521
0
}
522
523
const char* VVEncImpl::getErrorMsg( int nRet )
524
0
{
525
0
  switch( nRet )
526
0
  {
527
0
  case VVENC_OK :                  return vvencErrorMsg[0]; break;
528
0
  case VVENC_ERR_UNSPECIFIED:      return vvencErrorMsg[1]; break;
529
0
  case VVENC_ERR_INITIALIZE:       return vvencErrorMsg[2]; break;
530
0
  case VVENC_ERR_ALLOCATE:         return vvencErrorMsg[3]; break;
531
0
  case VVENC_NOT_ENOUGH_MEM:       return vvencErrorMsg[4]; break;
532
0
  case VVENC_ERR_PARAMETER:        return vvencErrorMsg[5]; break;
533
0
  case VVENC_ERR_NOT_SUPPORTED:    return vvencErrorMsg[6]; break;
534
0
  case VVENC_ERR_RESTART_REQUIRED: return vvencErrorMsg[7]; break;
535
0
  case VVENC_ERR_CPU:              return vvencErrorMsg[8]; break;
536
0
  default:                         return vvencErrorMsg[9]; break;
537
0
  }
538
0
  return vvencErrorMsg[9];
539
0
}
540
541
int VVEncImpl::setAndRetErrorMsg( int iRet )
542
0
{
543
0
  if( m_cErrorString.empty() )
544
0
  {
545
0
    m_cErrorString = getErrorMsg(iRet);
546
0
  }
547
548
0
  return iRet;
549
0
}
550
551
int VVEncImpl::getNumLeadFrames() const
552
0
{
553
0
  return m_cVVEncCfg.m_leadFrames;
554
0
}
555
556
int VVEncImpl::getNumTrailFrames() const
557
0
{
558
0
  return m_cVVEncCfg.m_trailFrames;
559
0
}
560
561
int VVEncImpl::printSummary() const
562
0
{
563
0
  if( !m_bInitialized ){ return -1; }
564
0
  if( nullptr == m_pEncLib )  { return -1; }
565
566
0
  m_pEncLib->printSummary();
567
0
  return 0;
568
0
}
569
570
bool VVEncImpl::xConvertVerifyYUVBuffer( vvencYUVBuffer* pcYUVBuffer )
571
1.19k
{
572
1.19k
  if( pcYUVBuffer == nullptr ){ return false; }
573
574
1.19k
  bool conv8bit = false;
575
1.19k
  if ( m_cVVEncCfg.m_inputBitDepth[0] == 10 && m_cVVEncCfg.m_internalBitDepth[0] == 8 &&
576
0
       m_cVVEncCfg.m_inputBitDepth[0] == m_cVVEncCfg.m_MSBExtendedBitDepth[0] )
577
0
  {
578
0
    conv8bit = true;
579
0
  }
580
581
1.19k
  const int numComp  = (m_cVVEncCfg.m_internChromaFormat==VVENC_CHROMA_400) ? 1 : 3;
582
1.19k
  const int16_t mask = ~( ( 1 << m_cVVEncCfg.m_internalBitDepth[0] ) - 1 );
583
1.19k
  int dstSum = 0;
584
4.79k
  for( int comp = 0; comp < numComp; comp++ )
585
3.59k
  {
586
3.59k
    vvencYUVPlane& plane = pcYUVBuffer->planes[ comp ];
587
3.59k
    int16_t* dst     = plane.ptr;
588
589
3.59k
    if ( conv8bit )
590
0
    {
591
0
      for( int y = 0; y < plane.height; y++, dst += plane.stride )
592
0
      {
593
0
        for( int x = 0; x < plane.width; x++ )
594
0
        {
595
0
          dst[ x ] = (Pel)std::min<Pel>( 255, ( dst[x] + 2 ) >> 2 );
596
0
          dstSum |= dst[ x ] & mask;
597
0
        }
598
0
      }
599
0
    }
600
3.59k
    else
601
3.59k
    {
602
376k
      for( int y = 0; y < plane.height; y++, dst += plane.stride )
603
373k
      {
604
44.9M
        for( int x = 0; x < plane.width; x++ )
605
44.5M
        {
606
44.5M
          dstSum |= dst[ x ] & mask;
607
44.5M
        }
608
373k
      }
609
3.59k
    }
610
3.59k
  }
611
1.19k
  return (dstSum != 0) ? false : true;
612
1.19k
}
613
614
int VVEncImpl::xGetAccessUnitsSize( const vvenc::AccessUnitList& rcAuList )
615
1.19k
{
616
1.19k
  uint32_t sizeSum = 0;
617
1.19k
  if ( ! rcAuList.empty() )
618
1.19k
  {
619
4.79k
    for (vvenc::AccessUnitList::const_iterator it = rcAuList.begin(); it != rcAuList.end(); it++)
620
3.59k
    {
621
3.59k
      const vvenc::NALUnitEBSP& nalu = **it;
622
3.59k
      if (it == rcAuList.begin() ||
623
2.39k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_DCI ||
624
2.39k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_SPS ||
625
2.39k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_VPS ||
626
2.39k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_PPS ||
627
1.19k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_PREFIX_APS ||
628
1.19k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_SUFFIX_APS )
629
2.39k
      {
630
2.39k
        sizeSum += 4;
631
2.39k
      }
632
1.19k
      else
633
1.19k
      {
634
1.19k
        sizeSum += 3;
635
1.19k
      }
636
3.59k
      sizeSum += uint32_t(nalu.m_nalUnitData.str().size());
637
3.59k
    }
638
1.19k
  }
639
640
1.19k
  return sizeSum;
641
1.19k
}
642
643
644
int VVEncImpl::xCopyAu( vvencAccessUnit& rcAccessUnit, const vvenc::AccessUnitList& rcAuList )
645
1.19k
{
646
1.19k
  rcAccessUnit.rap = false;
647
648
1.19k
  std::vector<uint32_t> annexBsizes;
649
650
  /* copy output AU */
651
1.19k
  if ( ! rcAuList.empty() )
652
1.19k
  {
653
1.19k
    uint32_t sizeSum = 0;
654
4.79k
    for (vvenc::AccessUnitList::const_iterator it = rcAuList.begin(); it != rcAuList.end(); it++)
655
3.59k
    {
656
3.59k
      const vvenc::NALUnitEBSP& nalu = **it;
657
3.59k
      uint32_t size = 0; /* size of annexB unit in bytes */
658
659
3.59k
      if (it == rcAuList.begin() ||
660
2.39k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_DCI ||
661
2.39k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_SPS ||
662
2.39k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_VPS ||
663
2.39k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_PPS ||
664
1.19k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_PREFIX_APS ||
665
1.19k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_SUFFIX_APS )
666
2.39k
      {
667
2.39k
        size += 4;
668
2.39k
      }
669
1.19k
      else
670
1.19k
      {
671
1.19k
        size += 3;
672
1.19k
      }
673
3.59k
      size += uint32_t(nalu.m_nalUnitData.str().size());
674
3.59k
      sizeSum += size;
675
3.59k
      annexBsizes.push_back( size );
676
677
3.59k
      switch( nalu.m_nalUnitType )
678
3.59k
      {
679
0
        case VVENC_NAL_UNIT_CODED_SLICE_TRAIL:
680
0
        case VVENC_NAL_UNIT_CODED_SLICE_STSA:
681
1.19k
        case VVENC_NAL_UNIT_CODED_SLICE_IDR_W_RADL:
682
1.19k
        case VVENC_NAL_UNIT_CODED_SLICE_IDR_N_LP:
683
1.19k
        case VVENC_NAL_UNIT_CODED_SLICE_CRA:
684
1.19k
        case VVENC_NAL_UNIT_CODED_SLICE_GDR:
685
1.19k
        case VVENC_NAL_UNIT_CODED_SLICE_RADL:
686
1.19k
        case VVENC_NAL_UNIT_CODED_SLICE_RASL:
687
1.19k
        case VVENC_NAL_UNIT_DCI:
688
1.19k
        case VVENC_NAL_UNIT_VPS:
689
2.39k
        case VVENC_NAL_UNIT_SPS:
690
3.59k
        case VVENC_NAL_UNIT_PPS:
691
3.59k
        case VVENC_NAL_UNIT_PREFIX_APS:
692
3.59k
        case VVENC_NAL_UNIT_SUFFIX_APS:
693
3.59k
          rcAccessUnit.essentialBytes += size;
694
3.59k
          break;
695
0
        default:
696
0
          break;
697
3.59k
      }
698
3.59k
    }
699
700
1.19k
    if( rcAccessUnit.payloadSize < (int)sizeSum )
701
0
    {
702
0
      return -1;
703
0
    }
704
705
1.19k
    uint32_t iUsedSize = 0;
706
4.79k
    for (vvenc::AccessUnitList::const_iterator it = rcAuList.begin(); it != rcAuList.end(); it++)
707
3.59k
    {
708
3.59k
      const vvenc::NALUnitEBSP& nalu = **it;
709
3.59k
      static const uint8_t start_code_prefix[] = {0,0,0,1};
710
3.59k
      if (it == rcAuList.begin() ||
711
2.39k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_DCI ||
712
2.39k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_SPS ||
713
2.39k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_VPS ||
714
2.39k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_PPS ||
715
1.19k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_PREFIX_APS ||
716
1.19k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_SUFFIX_APS )
717
2.39k
      {
718
        /* From AVC, When any of the following conditions are fulfilled, the
719
         * zero_byte syntax element shall be present:
720
         *  - the nal_unit_type within the nal_unit() is equal to 7 (sequence
721
         *    parameter set) or 8 (picture parameter set),
722
         *  - the byte stream NAL unit syntax structure contains the first NAL
723
         *    unit of an access unit in decoding order, as specified by subclause
724
         *    7.4.1.2.3.
725
         */
726
2.39k
        ::memcpy( rcAccessUnit.payload + iUsedSize, reinterpret_cast<const char*>(start_code_prefix), 4 );
727
2.39k
        iUsedSize += 4;
728
2.39k
      }
729
1.19k
      else
730
1.19k
      {
731
1.19k
        ::memcpy( rcAccessUnit.payload + iUsedSize, reinterpret_cast<const char*>(start_code_prefix+1), 3 );
732
1.19k
        iUsedSize += 3;
733
1.19k
      }
734
3.59k
      uint32_t nalDataSize = uint32_t(nalu.m_nalUnitData.str().size()) ;
735
3.59k
      ::memcpy( rcAccessUnit.payload + iUsedSize, nalu.m_nalUnitData.str().c_str() , nalDataSize );
736
3.59k
      iUsedSize += nalDataSize;
737
738
3.59k
      if( nalu.m_nalUnitType == VVENC_NAL_UNIT_CODED_SLICE_IDR_W_RADL ||
739
2.39k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_CODED_SLICE_IDR_N_LP ||
740
2.39k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_CODED_SLICE_CRA ||
741
2.39k
          nalu.m_nalUnitType == VVENC_NAL_UNIT_CODED_SLICE_GDR )
742
1.19k
      {
743
1.19k
        rcAccessUnit.rap = true;
744
1.19k
      }
745
      //rcAccessUnit.nalUnitTypeVec.push_back( nalu.m_nalUnitType );
746
3.59k
    }
747
748
1.19k
    rcAccessUnit.payloadUsedSize = iUsedSize;
749
1.19k
    if( iUsedSize != sizeSum  )
750
0
    {
751
0
      return VVENC_NOT_ENOUGH_MEM;
752
0
    }
753
754
    //rcAccessUnit.annexBsizeVec   = annexBsizes;
755
1.19k
    rcAccessUnit.ctsValid        = rcAuList.ctsValid;
756
1.19k
    rcAccessUnit.dtsValid        = rcAuList.dtsValid;
757
1.19k
    rcAccessUnit.cts             = rcAuList.cts;
758
1.19k
    rcAccessUnit.dts             = rcAuList.dts;
759
1.19k
    rcAccessUnit.sliceType       = (vvencSliceType)rcAuList.sliceType;
760
1.19k
    rcAccessUnit.refPic          = rcAuList.refPic;
761
1.19k
    rcAccessUnit.temporalLayer   = rcAuList.temporalLayer;
762
1.19k
    rcAccessUnit.poc             = rcAuList.poc;
763
1.19k
    rcAccessUnit.status          = rcAuList.status;
764
#if VVENC_USE_UNSTABLE_API
765
    rcAccessUnit.userData        = rcAuList.userData;
766
#endif
767
768
1.19k
    if ( !rcAuList.InfoString.empty() )
769
1.19k
    {
770
1.19k
      if( rcAuList.InfoString.size() >= VVENC_MAX_STRING_LEN )
771
0
      {
772
0
        rcAuList.InfoString.copy( rcAccessUnit.infoString , VVENC_MAX_STRING_LEN-1 );
773
0
        rcAccessUnit.infoString[VVENC_MAX_STRING_LEN-1] = '\0';
774
0
      }
775
1.19k
      else
776
1.19k
      {
777
1.19k
        rcAuList.InfoString.copy( rcAccessUnit.infoString , rcAuList.InfoString.size()+1 );
778
1.19k
        rcAccessUnit.infoString[rcAuList.InfoString.size()] = '\0';
779
1.19k
      }
780
1.19k
    }
781
0
    else
782
0
    {
783
0
      rcAccessUnit.infoString[0] = '\0';
784
0
    }
785
1.19k
  }
786
787
1.19k
  return 0;
788
1.19k
}
789
790
791
///< set message output function for encoder lib. if not set, no messages will be printed.
792
void VVEncImpl::registerMsgCbf( void * ctx, vvencLoggingCallback msgFnc )
793
0
{
794
  // DEPRECATED
795
0
  g_msgFnc    = msgFnc;
796
0
  g_msgFncCtx = ctx;
797
0
}
798
799
///< tries to set given simd extensions used. if not supported by cpu, highest possible extension level will be set and returned.
800
const char* VVEncImpl::setSIMDExtension( const char* simdId )
801
1.19k
{
802
1.19k
  const std::string simdReqStr( simdId ? simdId : "" );
803
#if ENABLE_SIMD_OPT && ( defined( TARGET_SIMD_X86 ) || defined( TARGET_SIMD_ARM ) )
804
# if HANDLE_EXCEPTION
805
  try
806
# endif  // HANDLE_EXCEPTION
807
  {
808
# if defined( TARGET_SIMD_ARM )
809
    ARM_VEXT arm_ext = string_to_arm_vext( simdReqStr );
810
#  if defined( TARGET_SIMD_X86 )
811
    // Translate any non-scalar Arm SIMD request to enable SIMDe.
812
    X86_VEXT x86_ext = arm_ext == arm_simd::UNDEFINED ? x86_simd::UNDEFINED
813
                     : arm_ext == arm_simd::SCALAR    ? x86_simd::SCALAR
814
                                                      : SIMD_EVERYWHERE_EXTENSION_LEVEL;
815
#  endif  // TARGET_SIMD_X86
816
    try
817
    {
818
#  if defined( TARGET_SIMD_X86 )
819
      read_x86_extension_flags( x86_ext );
820
#  endif   // TARGET_SIMD_X86
821
      read_arm_extension_flags( arm_ext );
822
    }
823
    catch( Exception& )
824
    {
825
      // Not using the actual message from the exception here, because we need to insert the SIMD-level name instead of
826
      // the enum.
827
      THROW( "requested SIMD level (" << simdReqStr << ") not supported by current CPU (max "
828
                                      << read_arm_extension_name() << ")." );
829
    }
830
# else  // defined( TARGET_SIMD_X86 )
831
    X86_VEXT request_ext = string_to_x86_vext( simdReqStr );
832
    try
833
    {
834
      read_x86_extension_flags( request_ext );
835
    }
836
    catch( Exception& )
837
    {
838
      // Not using the actual message from the exception here, because we need to insert the SIMD-level name instead of
839
      // the enum.
840
      THROW( "requested SIMD level (" << simdReqStr << ") not supported by current CPU (max "
841
                                      << read_x86_extension_name() << ")." );
842
    }
843
# endif  // defined( TARGET_SIMD_X86 )
844
845
# if ENABLE_SIMD_OPT_BUFFER
846
    g_pelBufOP.initPelBufOps();
847
# endif   // ENABLE_SIMD_OPT_BUFFER
848
849
# if ENABLE_SIMD_TRAFO
850
    g_tCoeffOps.initTCoeffOps();
851
# endif    // ENABLE_SIMD_TRAFO
852
853
# if defined( TARGET_SIMD_ARM )
854
    return read_arm_extension_name().c_str();
855
# else    // !TARGET_SIMD_ARM
856
    return read_x86_extension_name().c_str();
857
# endif   // !TARGET_SIMD_ARM
858
  }
859
# if HANDLE_EXCEPTION
860
  catch( Exception& e )
861
  {
862
    MsgLog msg;
863
    msg.log( VVENC_ERROR, "\n%s\n", e.what() );
864
    return nullptr;
865
  }
866
# endif  // HANDLE_EXCEPTION
867
#else   // !( ENABLE_SIMD_OPT && ( defined( TARGET_SIMD_X86 ) || defined( TARGET_SIMD_ARM ) ) )
868
1.19k
  if( !simdReqStr.empty() && simdReqStr != "SCALAR" )
869
0
  {
870
0
    MsgLog msg;
871
0
    msg.log( VVENC_ERROR, "\nVVenC built without SIMD support\n" );
872
0
    return nullptr;
873
0
  }
874
1.19k
  return "SCALAR";
875
1.19k
#endif  // !( ENABLE_SIMD_OPT && ( defined( TARGET_SIMD_X86 ) || defined( TARGET_SIMD_ARM ) ) )
876
1.19k
}
877
878
///< creates compile info string containing OS, Compiler and Bit-depth (e.g. 32 or 64 bit).
879
std::string VVEncImpl::getCompileInfoString()
880
1.19k
{
881
1.19k
  std::string info;
882
1.19k
  char convBuf[ 256 ];
883
1.19k
  snprintf( convBuf, sizeof( convBuf ), NVM_ONOS );      info += convBuf;
884
1.19k
  snprintf( convBuf, sizeof( convBuf ), NVM_COMPILEDBY); info += convBuf;
885
1.19k
  snprintf( convBuf, sizeof( convBuf ), NVM_BITS );      info += convBuf;
886
1.19k
  return info;
887
1.19k
}
888
889
std::string VVEncImpl::createEncoderInfoStr()
890
1.19k
{
891
1.19k
  std::stringstream cssCap;
892
#if defined( TARGET_SIMD_ARM ) && ENABLE_SIMD_OPT
893
  setSIMDExtension( nullptr );  // Ensure SIMD-detection is finished
894
  cssCap << getCompileInfoString() << "[SIMD=" << read_arm_extension_name() << "]";
895
#elif defined( TARGET_SIMD_X86 ) && ENABLE_SIMD_OPT
896
  setSIMDExtension( nullptr );  // Ensure SIMD-detection is finished
897
  cssCap << getCompileInfoString() << "[SIMD=" << read_x86_extension_name() <<"]";
898
#else  // !TARGET_SIMD_X86 && !TARGET_SIMD_ARM
899
1.19k
  cssCap << getCompileInfoString() << "[SIMD=SCALAR]";
900
1.19k
#endif
901
902
1.19k
  std::string cInfoStr;
903
1.19k
  cInfoStr  = "VVenC, the Fraunhofer H.266/VVC Encoder, version " VVENC_VERSION;
904
1.19k
  cInfoStr += " ";
905
1.19k
  cInfoStr += cssCap.str();
906
907
1.19k
  return cInfoStr;
908
1.19k
}
909
910
///< decode bitstream is deprecated and will be removed
911
int VVEncImpl::decodeBitstream( const char* FileName, const char* trcFile, const char* trcRule)
912
0
{
913
0
  MsgLog msg;
914
0
  msg.log( VVENC_ERROR, "vvenc_decode_bitstream is deprecated and not working anymore." );
915
0
  return VVENC_ERR_NOT_SUPPORTED;
916
0
}
917
918
919
} // namespace