Coverage Report

Created: 2026-09-01 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvdec/source/Lib/vvdec/vvdecimpl.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) 2018-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVdeC 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
#include <string>
44
45
#ifdef VVDEC_WRITE_INPUT_BITSTREAM
46
#  include <fstream>
47
#endif
48
49
#if defined( __linux__ )
50
#include <malloc.h>
51
#endif
52
53
#include "vvdecimpl.h"
54
#include "vvdec/version.h"
55
#include "vvdec/sei.h"
56
#include "DecoderLib/NALread.h"
57
#include "CommonLib/CommonDef.h"
58
#include "CommonLib/x86/CommonDefX86.h"
59
#include "CommonLib/arm/CommonDefARM.h"
60
#include "FilmGrain/FilmGrain.h"
61
62
namespace vvdec
63
{
64
65
// calculate size of T and ensure the size is aligned to 8 bytes
66
template<class T>
67
constexpr size_t paddedSizeOf()
68
0
{
69
0
  return ( ( sizeof( T ) + 7 ) / 8 ) * 8;
70
0
}
Unexecuted instantiation: unsigned long vvdec::paddedSizeOf<vvdecPicAttributes>()
Unexecuted instantiation: unsigned long vvdec::paddedSizeOf<vvdecSeqInfo>()
Unexecuted instantiation: unsigned long vvdec::paddedSizeOf<vvdecVui>()
Unexecuted instantiation: unsigned long vvdec::paddedSizeOf<vvdecHrd>()
Unexecuted instantiation: unsigned long vvdec::paddedSizeOf<vvdecOlsHrd>()
71
72
// allocate object of type T in storage and advance pointer, to ensure it is still aligned to 8 bytes
73
template<class T>
74
constexpr T* allocInto( char** storage )
75
0
{
76
0
  T* ret    = new( *storage ) T;
77
0
  *storage += paddedSizeOf<T>();
78
0
  return ret;
79
0
}
Unexecuted instantiation: vvdecPicAttributes* vvdec::allocInto<vvdecPicAttributes>(char**)
Unexecuted instantiation: vvdecSeqInfo* vvdec::allocInto<vvdecSeqInfo>(char**)
Unexecuted instantiation: vvdecVui* vvdec::allocInto<vvdecVui>(char**)
Unexecuted instantiation: vvdecHrd* vvdec::allocInto<vvdecHrd>(char**)
Unexecuted instantiation: vvdecOlsHrd* vvdec::allocInto<vvdecOlsHrd>(char**)
80
81
672
VVDecImpl::VVDecImpl() = default;
82
672
VVDecImpl::~VVDecImpl() = default;
83
84
int VVDecImpl::init( const vvdecParams& params, vvdecCreateBufferCallback createBufCallback, vvdecUnrefBufferCallback unrefBufCallback )
85
672
{
86
672
  if( m_bInitialized ){ return VVDEC_ERR_INITIALIZE; }
87
88
672
  try
89
672
  {
90
#if defined(TARGET_SIMD_X86) && ENABLE_SIMD_OPT
91
#  if defined( VVDEC_ARCH_X86 )
92
    switch( params.simd )
93
    {
94
    case VVDEC_SIMD_SCALAR: read_x86_extension_flags( x86_simd::SCALAR ); break;
95
    case VVDEC_SIMD_SSE41 : read_x86_extension_flags( x86_simd::SSE41  ); break;
96
    case VVDEC_SIMD_SSE42 : read_x86_extension_flags( x86_simd::SSE42  ); break;
97
    case VVDEC_SIMD_AVX   : read_x86_extension_flags( x86_simd::AVX    ); break;
98
    case VVDEC_SIMD_AVX2  : read_x86_extension_flags( x86_simd::AVX2   ); break;
99
    case VVDEC_SIMD_DEFAULT:
100
    default:                read_x86_extension_flags( x86_simd::UNDEFINED ); break;
101
    }
102
#  else    // !VVDEC_ARCH_X86
103
    // all other architectures, that use simd-everywhere
104
    switch( params.simd )
105
    {
106
    case VVDEC_SIMD_SCALAR: read_x86_extension_flags( x86_simd::SCALAR );    break;
107
    default:                read_x86_extension_flags( x86_simd::UNDEFINED ); break;
108
    }
109
#  endif   // !VVDEC_ARCH_X86
110
#endif   // TARGET_SIMD_X86
111
112
#if defined(TARGET_SIMD_ARM) && ENABLE_SIMD_OPT
113
    switch( params.simd )
114
    {
115
    case VVDEC_SIMD_SCALAR:   read_arm_extension_flags( arm_simd::SCALAR );    break;
116
    case VVDEC_SIMD_NEON:     read_arm_extension_flags( arm_simd::NEON );      break;
117
    case VVDEC_SIMD_NEON_RDM: read_arm_extension_flags( arm_simd::NEON_RDM );  break;
118
    case VVDEC_SIMD_SVE:      read_arm_extension_flags( arm_simd::SVE );       break;
119
    case VVDEC_SIMD_SVE2:     read_arm_extension_flags( arm_simd::SVE2 );      break;
120
    case VVDEC_SIMD_DEFAULT:
121
    case VVDEC_SIMD_LEGACY:
122
    default:                  read_arm_extension_flags( arm_simd::UNDEFINED ); break;
123
    }
124
#endif   // TARGET_SIMD_ARM
125
126
672
    if( createBufCallback && unrefBufCallback )
127
0
    {
128
0
      m_cUserAllocator.enabled = true;
129
0
      m_cUserAllocator.create  = createBufCallback;
130
0
      m_cUserAllocator.unref   = unrefBufCallback;
131
0
      m_cUserAllocator.opaque  = params.opaque;
132
0
    }
133
672
    else
134
672
    {
135
672
      m_cUserAllocator = UserAllocator();
136
672
    }
137
138
672
    m_cDecLib = std::make_unique<DecLib>();
139
140
672
    initROM();
141
142
    // create decoder class
143
672
    m_cDecLib->create( params.threads, params.parseDelay, m_cUserAllocator, static_cast<ErrHandlingFlags>(params.errHandlingFlags) );
144
145
672
    g_verbosity = MsgLevel( params.logLevel );
146
672
    g_context   = this;
147
148
    // initialize decoder class
149
672
    m_cDecLib->setDecodedPictureHashSEIEnabled( (int) params.verifyPictureHash );
150
//    if (!m_outputDecodedSEIMessagesFilename.empty())
151
//    {
152
//      std::ostream &os=m_seiMessageFileStream.is_open() ? m_seiMessageFileStream : std::cout;
153
//      m_cDecLib.setDecodedSEIMessageOutputStream(&os);
154
//    }
155
156
672
    m_sDecoderCapabilities = m_cDecLib->getDecoderCapabilities();
157
158
672
    m_enableFilmGrain   = params.filmGrainSynthesis;
159
672
    m_eErrHandlingFlags = static_cast<ErrHandlingFlags>(params.errHandlingFlags);
160
672
    m_uiSeqNumber       = 0;
161
672
    m_uiSeqNumOutput    = 0;
162
672
    m_bInitialized      = true;
163
672
    m_eState            = INTERNAL_STATE_INITIALIZED;
164
672
  }
165
672
  catch( UnsupportedFeatureException& e )
166
672
  {
167
0
    std::stringstream css;
168
0
    css << "caught exception for unsupported feature " << e.what();
169
0
    m_cErrorString = "unsupported feature detected";
170
0
    m_cAdditionalErrorString = css.str();
171
0
    m_eState = INTERNAL_STATE_NOT_SUPPORTED;
172
0
    m_bInitialized           = false;
173
0
    return VVDEC_ERR_NOT_SUPPORTED;
174
0
  }
175
672
  catch( std::exception& e )
176
672
  {
177
0
    std::stringstream css;
178
0
    css << "caught exception during initialization:" << e.what();
179
0
    m_cAdditionalErrorString = css.str();
180
0
    m_eState                 = INTERNAL_STATE_RESTART_REQUIRED;
181
0
    m_bInitialized           = false;
182
0
    return VVDEC_ERR_RESTART_REQUIRED;
183
0
  }
184
185
672
  return VVDEC_OK;
186
672
}
187
188
int VVDecImpl::uninit()
189
672
{
190
672
  if( !m_bInitialized ){ return VVDEC_ERR_INITIALIZE; }
191
192
672
  reset();
193
194
  // destroy internal classes
195
672
  m_cDecLib->destroy();
196
672
  m_cDecLib.reset();
197
672
  destroyROM();
198
199
672
  m_bInitialized = false;
200
672
  m_eState       = INTERNAL_STATE_UNINITIALIZED;
201
202
672
  m_filmGrainSynth.reset();
203
204
672
  return VVDEC_OK;
205
672
}
206
207
int VVDecImpl::reset()
208
672
{
209
672
  if( !m_bInitialized ){ return VVDEC_ERR_INITIALIZE; }
210
211
672
  bool bFlushDecoder = true;
212
672
  while( bFlushDecoder)
213
672
  {
214
672
    vvdecFrame* frame= NULL;
215
216
    // flush the decoder
217
672
    int iRet = catchExceptions( &VVDecImpl::flush, &frame );
218
672
    if( iRet != 0 )  {  bFlushDecoder = false; }
219
220
672
    if( frame  )
221
0
    {
222
      // free picture memory
223
0
      objectUnref( frame );
224
0
    }
225
672
    else
226
672
    {
227
672
      bFlushDecoder = false;
228
672
      break;
229
672
    }
230
672
  };
231
232
672
  for( auto& entry: m_rcFrameList )
233
0
  {
234
0
    vvdec_frame_reset( &std::get<vvdecFrame>( entry ) );
235
0
    if( std::get<Picture*>( entry ) )
236
0
    {
237
0
      m_cDecLib->releasePicture( std::get<Picture*>( entry ) );
238
0
    }
239
0
  }
240
672
  m_rcFrameList.clear();
241
672
  m_pcFrameNext = m_rcFrameList.end();
242
243
672
  for( auto& storage : m_cFrameStorageMap )
244
0
  {
245
0
    if( storage.second.isAllocated())
246
0
    {
247
0
      storage.second.freeStorage();
248
0
    }
249
0
  }
250
672
  m_cFrameStorageMap.clear();
251
252
672
#if defined( __linux__ ) && defined( __GLIBC__ )
253
672
  malloc_trim(0);
254
672
#endif
255
256
672
  m_filmGrainCharacteristicsState = FgcNone;
257
672
  m_uiSeqNumber                   = 0;
258
672
  m_uiSeqNumOutput                = 0;
259
672
  m_eState                        = INTERNAL_STATE_INITIALIZED;
260
261
672
  return VVDEC_OK;
262
672
}
263
264
265
266
void VVDecImpl::setLoggingCallback( vvdecLoggingCallback callback )
267
0
{
268
0
  g_msgFnc      = callback;
269
0
}
270
271
int VVDecImpl::decode( vvdecAccessUnit& rcAccessUnit, vvdecFrame** ppcFrame )
272
658
{
273
658
  if( !m_bInitialized )      { return VVDEC_ERR_INITIALIZE; }
274
658
  if( m_eState == INTERNAL_STATE_RESTART_REQUIRED ) { m_cErrorString = "restart required, please reinit."; return VVDEC_ERR_RESTART_REQUIRED; }
275
658
  if( m_eState == INTERNAL_STATE_NOT_SUPPORTED ) { m_cErrorString = "not supported feature detected."; return VVDEC_ERR_NOT_SUPPORTED; }
276
277
658
  if( m_eState == INTERNAL_STATE_FINALIZED || m_eState == INTERNAL_STATE_FLUSHING )
278
0
  {
279
0
    reset();
280
0
  }
281
282
658
  if( m_eState == INTERNAL_STATE_INITIALIZED ){ m_eState = INTERNAL_STATE_TUNING_IN; }
283
284
658
  if( !rcAccessUnit.payload )
285
0
  {
286
0
    return setAndRetErrorMsg( VVDEC_ERR_DEC_INPUT, "payload is null" );
287
0
  }
288
289
658
  if( rcAccessUnit.payloadSize <= 0  )
290
0
  {
291
0
    return setAndRetErrorMsg( VVDEC_ERR_DEC_INPUT, "payloadSize must be > 0" );
292
0
  }
293
294
658
  if( rcAccessUnit.payloadUsedSize > rcAccessUnit.payloadSize )
295
0
  {
296
0
    return setAndRetErrorMsg( VVDEC_ERR_DEC_INPUT, "payloadUsedSize must be <= payloadSize" );
297
0
  }
298
299
658
  int iRet = VVDEC_OK;
300
301
658
  try
302
658
  {
303
658
    InputNALUnit nalu;
304
658
    Picture * pcPic = nullptr;
305
306
658
    int iComrpPacketCnt = 0;
307
308
658
    if( rcAccessUnit.payloadUsedSize )
309
658
    {
310
#ifdef VVDEC_WRITE_INPUT_BITSTREAM
311
      if( std::getenv( "VVDEC_WRITE_INPUT_BITSTREAM" ) )
312
      {
313
        std::string bitstreamOutFileName( std::getenv( "VVDEC_WRITE_INPUT_BITSTREAM" ) );
314
        if( !bitstreamOutFileName.empty() )
315
        {
316
          msg( WARNING, "Warning: writing input bitstream to file %s\n", bitstreamOutFileName.c_str() );
317
318
          std::ofstream bitstreamOutFile( bitstreamOutFileName, std::ios::binary | std::ios::app );
319
          bitstreamOutFile.write( (const char*) rcAccessUnit.payload, rcAccessUnit.payloadUsedSize );
320
        }
321
      }
322
#endif
323
324
658
      bool bStartCodeFound = false;
325
658
      std::vector<size_t> iStartCodePosVec;
326
658
      std::vector<size_t> iAUEndPosVec;
327
658
      std::vector<size_t> iStartCodeSizeVec;
328
329
658
      int pos = 0;
330
18.9k
      while( pos+3 < rcAccessUnit.payloadUsedSize )
331
18.2k
      {
332
        // no start code found
333
18.2k
        CHECK( pos >= rcAccessUnit.payloadUsedSize, "could not find a startcode" );
334
335
18.2k
        int iFound = xRetrieveNalStartCode( &rcAccessUnit.payload[pos], 3 );
336
18.2k
        if( iFound == 1 )
337
116
        {
338
116
          bStartCodeFound = true;
339
340
116
          iStartCodePosVec.push_back( pos+4 );
341
116
          iStartCodeSizeVec.push_back( 4 );
342
343
116
          if( pos > 0 )
344
116
          {
345
116
            iAUEndPosVec.push_back(pos);
346
116
          }
347
348
116
          pos+=3;
349
116
        }
350
18.1k
        else
351
18.1k
        {
352
18.1k
          iFound = xRetrieveNalStartCode(&rcAccessUnit.payload[pos], 2);
353
18.1k
          if( iFound == 1 )
354
804
          {
355
804
            bStartCodeFound = true;
356
357
804
            iStartCodePosVec.push_back( pos+3 );
358
804
            iStartCodeSizeVec.push_back( 3 );
359
804
            if( pos > 0 )
360
146
            {
361
146
              iAUEndPosVec.push_back(pos);
362
146
            }
363
364
804
            pos+=2;
365
804
          }
366
18.1k
        }
367
18.2k
        pos++;
368
18.2k
      }
369
370
658
      if( !bStartCodeFound )
371
0
      {
372
0
        return VVDEC_ERR_DEC_INPUT;
373
0
      }
374
375
658
      int iLastPos = rcAccessUnit.payloadUsedSize;
376
996
      while( iLastPos > 0 && rcAccessUnit.payload[iLastPos-1] == 0 )
377
338
      {
378
338
        iLastPos--;
379
338
      }
380
658
      iAUEndPosVec.push_back( iLastPos );
381
382
      // check if first AU begins on begin of payload (otherwise wrong input), but we allow empty input
383
658
      if( !iStartCodePosVec.empty() && iStartCodePosVec[0] != iStartCodeSizeVec[0] )
384
0
      {
385
0
        m_cErrorString = "vvdecAccessUnit does not start with valid start code.";
386
0
        return VVDEC_ERR_DEC_INPUT;
387
0
      }
388
389
658
      InputBitstream& rBitstream = nalu.getBitstream();
390
      // iterate over all AU´s
391
1.44k
      for( size_t iAU = 0; iAU < iStartCodePosVec.size(); iAU++ )
392
808
      {
393
808
        rBitstream.resetToStart();
394
808
        rBitstream.getFifo().clear();
395
808
        rBitstream.clearEmulationPreventionByteLocation();
396
397
808
        size_t numNaluBytes = iAUEndPosVec[iAU] - iStartCodePosVec[iAU];
398
808
        if( numNaluBytes >= 2 )
399
766
        {
400
766
          const uint8_t*    naluData = &rcAccessUnit.payload[iStartCodePosVec[iAU]];
401
766
          const NalUnitType nut      = (NalUnitType) ( ( naluData[1] >> 3 ) & 0x1f );
402
          // perform anti-emulation prevention
403
766
          if( 0 != xConvertPayloadToRBSP( naluData, numNaluBytes, &rBitstream, NALUnit::isVclNalUnitType( nut ) ) )
404
22
          {
405
22
            return VVDEC_ERR_UNSPECIFIED;
406
22
          }
407
408
744
          rBitstream.resetToStart();
409
410
744
          if( 0 != xReadNalUnitHeader(nalu) )
411
2
          {
412
2
            return VVDEC_ERR_UNSPECIFIED;
413
2
          }
414
415
742
          CHECKD( nut != nalu.m_nalUnitType, "Nal unit type parsed wrong." );
416
742
          if ( NALUnit::isVclNalUnitType( nalu.m_nalUnitType ) )
417
50
          {
418
50
            iComrpPacketCnt++;
419
50
          }
420
421
742
          if( rcAccessUnit.ctsValid ){  nalu.m_cts = rcAccessUnit.cts; }
422
742
          if( rcAccessUnit.dtsValid ){  nalu.m_dts = rcAccessUnit.dts; }
423
742
          nalu.m_rap = rcAccessUnit.rap;
424
742
          nalu.m_bits = ( numNaluBytes + iStartCodeSizeVec[iAU] ) * 8;
425
#if VVDEC_USE_UNSTABLE_API
426
          nalu.m_userData = rcAccessUnit.userData;
427
#endif
428
429
742
          pcPic = m_cDecLib->decode( nalu );
430
431
742
          iRet = xHandleOutput( pcPic );
432
742
          if( VVDEC_OK != iRet )
433
0
          {
434
0
            return iRet;
435
0
          }
436
742
        }
437
808
      }
438
658
    }
439
0
    else
440
0
    {
441
0
      nalu.m_nalUnitType = NAL_UNIT_INVALID;
442
443
      // Flush decoder
444
0
      pcPic = m_cDecLib->flushPic();
445
0
      xHandleOutput( pcPic );
446
447
0
      iRet = VVDEC_EOF;
448
449
0
      if ( !pcPic )
450
0
      {
451
0
        *ppcFrame = nullptr;
452
0
        return iRet;
453
0
      }
454
0
    }
455
456
634
    if( !m_rcFrameList.empty() )
457
0
    {
458
0
      if( m_pcFrameNext == m_rcFrameList.end()  )
459
0
      {
460
0
        if( iComrpPacketCnt )
461
0
        {
462
0
          iRet = VVDEC_TRY_AGAIN;
463
0
        }
464
0
        *ppcFrame = nullptr;
465
0
      }
466
0
      else
467
0
      {
468
0
        *ppcFrame = &std::get<vvdecFrame>( *m_pcFrameNext );
469
0
        m_uiSeqNumOutput = (*ppcFrame)->sequenceNumber;
470
0
        if( Picture* pic = std::get<Picture*>( *m_pcFrameNext ) )
471
0
        {
472
0
          pic->lockedByApplication = Picture::LOCKED;
473
0
        }
474
0
        ++m_pcFrameNext;
475
0
      }
476
0
    }
477
634
    else
478
634
    {
479
634
      *ppcFrame = nullptr;
480
634
      if( iComrpPacketCnt )
481
6
      {
482
6
        iRet = VVDEC_TRY_AGAIN;
483
6
      }
484
634
    }
485
634
  }
486
  // Only catch recoverable exceptions here, because that is handled differently between decode() and flush().
487
  // Everything else should be caught by the catchExceptions() wrapper.
488
658
  catch( RecoverableException& e )
489
658
  {
490
546
    m_cErrorString = "(possibly recoverable) exception";
491
492
546
    std::stringstream css;
493
546
    if( m_eState == INTERNAL_STATE_TUNING_IN )
494
546
    {
495
546
      css << "Exception while tuning in: " << e.what() << "\n"
496
546
          << "You can try to pass in more data to start decoding from the first RAP.";
497
546
      m_cAdditionalErrorString = css.str();
498
546
      return VVDEC_ERR_DEC_INPUT;
499
546
    }
500
0
    if( m_eErrHandlingFlags & ERR_HANDLING_TRY_CONTINUE )
501
0
    {
502
0
      css << "Exception occured: " << e.what() << "\n"
503
0
          << "Trying to continue decoding.";
504
0
      m_cAdditionalErrorString = css.str();
505
0
      return VVDEC_ERR_DEC_INPUT;
506
0
    }
507
0
    m_cAdditionalErrorString = std::string( "Exception occured: " ) + e.what();
508
0
    m_eState                 = INTERNAL_STATE_RESTART_REQUIRED;
509
0
    return VVDEC_ERR_RESTART_REQUIRED;
510
0
  }
511
512
82
  return iRet;
513
658
}
514
515
int VVDecImpl::flush( vvdecFrame** ppframe )
516
820
{
517
820
  *ppframe = nullptr;
518
519
820
  if( !m_bInitialized ){ return VVDEC_ERR_INITIALIZE; }
520
521
820
  if( m_eState == INTERNAL_STATE_INITIALIZED )      { m_cErrorString = "decoder did not receive any data to decode, cannot flush"; return VVDEC_ERR_RESTART_REQUIRED; }
522
798
  if( m_eState == INTERNAL_STATE_FINALIZED )        { m_cErrorString = "decoder already flushed, please reinit."; return VVDEC_ERR_RESTART_REQUIRED; }
523
650
  if( m_eState == INTERNAL_STATE_RESTART_REQUIRED ) { m_cErrorString = "restart required, please reinit."; return VVDEC_ERR_RESTART_REQUIRED; }
524
650
  if( m_eState == INTERNAL_STATE_NOT_SUPPORTED )    { m_cErrorString = "not supported feature detected."; return VVDEC_ERR_NOT_SUPPORTED; }
525
526
527
644
  if( m_eState == INTERNAL_STATE_TUNING_IN || m_eState == INTERNAL_STATE_DECODING )
528
644
  {
529
644
    m_eState = INTERNAL_STATE_FLUSHING;
530
644
  }
531
532
644
  int iRet= VVDEC_OK;
533
534
  // Flush decoder
535
644
  try
536
644
  {
537
644
    Picture * pcPic = nullptr;
538
539
644
    bool bContinue = true;
540
1.28k
    while( bContinue )
541
644
    {
542
644
      pcPic = m_cDecLib->flushPic();
543
644
      if( 0 != xHandleOutput( pcPic ))
544
0
      {
545
0
        iRet = VVDEC_ERR_UNSPECIFIED;
546
0
      }
547
548
644
      if( !pcPic || !m_rcFrameList.empty() )
549
644
      {
550
644
        bContinue = false;
551
644
      }
552
644
    }
553
554
644
    if( !m_rcFrameList.empty())
555
0
    {
556
0
      if( m_pcFrameNext == m_rcFrameList.end()  )
557
0
      {
558
0
        iRet = VVDEC_EOF;
559
0
        *ppframe = nullptr;
560
0
         m_eState = INTERNAL_STATE_FINALIZED;
561
0
      }
562
0
      else
563
0
      {
564
0
         *ppframe = &std::get<vvdecFrame>( *m_pcFrameNext );
565
0
         m_uiSeqNumOutput = ( *ppframe )->sequenceNumber;
566
0
         ++m_pcFrameNext;
567
0
      }
568
0
    }
569
644
    else
570
644
    {
571
644
      iRet = VVDEC_EOF;
572
644
      *ppframe = nullptr;
573
644
      m_eState = INTERNAL_STATE_FINALIZED;
574
644
    }
575
644
  }
576
  // Only catch recoverable exceptions here, because that is handled differently between decode() and flush().
577
  // Everything else should be caught by the catchExceptions() wrapper.
578
644
  catch( RecoverableException& e )
579
644
  {
580
0
    m_cErrorString = "(possibly recoverable) exception";
581
582
0
    std::stringstream css;
583
0
    if( m_eErrHandlingFlags & ERR_HANDLING_TRY_CONTINUE )
584
0
    {
585
0
      css << "Exception occured: " << e.what() << "\n"
586
0
          << "Trying to continue decoding.";
587
0
      m_cAdditionalErrorString = css.str();
588
0
      return VVDEC_ERR_DEC_INPUT;
589
0
    }
590
0
    m_cAdditionalErrorString = std::string( "Exception occured: " ) + e.what();
591
0
    m_eState                 = INTERNAL_STATE_RESTART_REQUIRED;
592
0
    return VVDEC_ERR_RESTART_REQUIRED;
593
0
  }
594
595
644
  if( 0 != iRet )
596
644
  {
597
644
    m_eState = INTERNAL_STATE_FINALIZED;
598
644
    return (int)VVDEC_EOF;
599
644
  }
600
601
0
  return iRet;
602
644
}
603
604
vvdecSEI* VVDecImpl::findFrameSei( vvdecSEIPayloadType payloadType, vvdecFrame *frame )
605
0
{
606
0
  if( !m_bInitialized ){ return nullptr; }
607
608
0
  if( nullptr == frame )
609
0
  {
610
0
    m_cErrorString = "findFrameSei: frame is null\n";
611
0
    return nullptr;
612
0
  }
613
614
0
  Picture* picture = nullptr;
615
0
  for( auto& entry: m_rcFrameList )
616
0
  {
617
0
    if( frame == &std::get<vvdecFrame>( entry ) )
618
0
    {
619
0
      picture = std::get<Picture*>( entry );
620
0
      break;
621
0
    }
622
0
  }
623
624
0
  if( picture == nullptr )
625
0
  {
626
0
    msg(VERBOSE, "findFrameSei: cannot find pictue in internal list.\n");
627
0
    return nullptr;
628
0
  }
629
630
0
  vvdecSEI *sei = nullptr;
631
0
  for( auto& s : picture->seiMessageList )
632
0
  {
633
0
    if( s->payloadType == payloadType )
634
0
    {
635
0
      sei = s;
636
0
    }
637
0
  }
638
639
0
  return sei;
640
0
}
641
642
643
int VVDecImpl::objectUnref( vvdecFrame* pcFrame )
644
0
{
645
0
  if( !m_bInitialized ){ return VVDEC_ERR_INITIALIZE; }
646
647
0
  if ( NULL == pcFrame )
648
0
  {
649
0
    m_cErrorString = "objectUnref: cannot unref pictue with null pointer";
650
0
    return VVDEC_ERR_UNSPECIFIED;
651
0
  }
652
653
0
  for( auto it = m_rcFrameList.begin(); it != m_rcFrameList.end(); ++it )
654
0
  {
655
0
    vvdecFrame* frame = &std::get<vvdecFrame>( *it );
656
0
    if( frame == pcFrame )
657
0
    {
658
0
      vvdec_frame_reset( frame );
659
0
      if( std::get<Picture*>( *it ) )
660
0
      {
661
0
        m_cDecLib->releasePicture( std::get<Picture*>( *it ) );
662
0
      }
663
0
      m_rcFrameList.erase( it );
664
0
      return VVDEC_OK;
665
0
    }
666
0
  }
667
668
0
  return VVDEC_ERR_UNSPECIFIED;
669
0
}
670
671
int VVDecImpl::getNumberOfErrorsPictureHashSEI()
672
0
{
673
0
  if( !m_bInitialized ){ return VVDEC_ERR_INITIALIZE; }
674
675
0
  uint32_t iErrors = m_cDecLib->getNumberOfChecksumErrorsDetected();
676
0
  return iErrors;
677
0
}
678
679
const char* VVDecImpl::getErrorMsg( int nRet )
680
0
{
681
0
  switch( nRet )
682
0
  {
683
0
  case VVDEC_OK :                  return vvdecErrorMsg[0]; break;
684
0
  case VVDEC_ERR_UNSPECIFIED:      return vvdecErrorMsg[1]; break;
685
0
  case VVDEC_ERR_INITIALIZE:       return vvdecErrorMsg[2]; break;
686
0
  case VVDEC_ERR_ALLOCATE:         return vvdecErrorMsg[3]; break;
687
0
  case VVDEC_ERR_DEC_INPUT:        return vvdecErrorMsg[4]; break;
688
0
  case VVDEC_NOT_ENOUGH_MEM:       return vvdecErrorMsg[5]; break;
689
0
  case VVDEC_ERR_PARAMETER:        return vvdecErrorMsg[6]; break;
690
0
  case VVDEC_ERR_NOT_SUPPORTED:    return vvdecErrorMsg[7]; break;
691
0
  case VVDEC_ERR_RESTART_REQUIRED: return vvdecErrorMsg[8]; break;
692
0
  case VVDEC_ERR_CPU:              return vvdecErrorMsg[9]; break;
693
0
  case VVDEC_TRY_AGAIN:            return vvdecErrorMsg[10]; break;
694
0
  case VVDEC_EOF:                  return vvdecErrorMsg[11]; break;
695
0
  default:                         return vvdecErrorMsg[12]; break;
696
0
  }
697
0
  return vvdecErrorMsg[12];
698
0
}
699
700
int VVDecImpl::setAndRetErrorMsg( int iRet, std::string errString  )
701
0
{
702
0
  if( !errString.empty() )
703
0
  {
704
0
    m_cErrorString = errString;
705
0
  }
706
0
  else
707
0
  {
708
0
    m_cErrorString = getErrorMsg(iRet);
709
0
  }
710
0
  return iRet;
711
0
}
712
713
const char* VVDecImpl::getVersionNumber()
714
0
{
715
0
  return VVDEC_VERSION;
716
0
}
717
718
const char* VVDecImpl::getDecoderInfo()
719
0
{
720
0
    m_sDecoderInfo  = "VVdeC, the Fraunhofer VVC/H.266 decoder";
721
0
    m_sDecoderInfo += ", version ";
722
0
    m_sDecoderInfo += getVersionNumber();
723
0
    m_sDecoderInfo += " [";
724
0
    m_sDecoderInfo += m_sDecoderCapabilities;
725
0
    m_sDecoderInfo += "]";
726
0
    return m_sDecoderInfo.c_str();
727
0
}
728
729
vvdecNalType VVDecImpl::getNalUnitType ( vvdecAccessUnit& rcAccessUnit )
730
0
{
731
0
  vvdecNalType eNalType = VVC_NAL_UNIT_INVALID;
732
733
0
  if( rcAccessUnit.payload == nullptr ||
734
0
      rcAccessUnit.payloadSize < 3 ||
735
0
      rcAccessUnit.payloadUsedSize == 0 )
736
0
  {
737
0
    return eNalType;
738
0
  }
739
740
0
  unsigned char* pcBuf = rcAccessUnit.payload;
741
0
  int iOffset=0;
742
743
0
  int found = 1;
744
0
  int i=0;
745
0
  for ( i = 0; i < 3; i++)
746
0
  {
747
0
    if( pcBuf[i] != 0 )
748
0
    {
749
0
      found = 0;
750
0
    }
751
0
  }
752
753
0
  if( pcBuf[i] != 1 )
754
0
  {
755
0
    found = 0;
756
0
  }
757
758
0
  if( found )
759
0
  {
760
0
    iOffset=5;
761
0
  }
762
0
  else
763
0
  {
764
0
    found = 1;
765
0
    i=0;
766
0
    for ( i = 0; i < 2; i++)
767
0
    {
768
0
      if( pcBuf[i] != 0 )
769
0
      {
770
0
        found = 0;
771
0
      }
772
0
    }
773
774
0
    if( pcBuf[i] != 1 )
775
0
    {
776
0
      found = 0;
777
0
    }
778
779
0
    if( found )
780
0
    {
781
0
      iOffset=4;
782
0
    }
783
0
  }
784
785
0
  if( found )
786
0
  {
787
0
    unsigned char uc = pcBuf[iOffset];
788
0
    int nalUnitType   = ((uc >> 3) & 0x1F );
789
0
    eNalType = (vvdecNalType)nalUnitType;
790
0
  }
791
792
0
  return eNalType;
793
0
}
794
795
const char* VVDecImpl::getNalUnitTypeAsString( vvdecNalType t )
796
0
{
797
0
  if( (int) t >= (int)NAL_UNIT_INVALID || (int)t < 0)
798
0
  {
799
0
    return vvdecNalTypeNames[NAL_UNIT_INVALID];
800
0
  }
801
802
0
  return vvdecNalTypeNames[t];
803
0
}
804
805
806
bool VVDecImpl::isNalUnitSlice( vvdecNalType t )
807
0
{
808
0
  return t == VVC_NAL_UNIT_CODED_SLICE_TRAIL
809
0
      || t == VVC_NAL_UNIT_CODED_SLICE_STSA
810
0
      || t == VVC_NAL_UNIT_CODED_SLICE_RADL
811
0
      || t == VVC_NAL_UNIT_CODED_SLICE_RASL
812
0
      || t == VVC_NAL_UNIT_CODED_SLICE_IDR_W_RADL
813
0
      || t == VVC_NAL_UNIT_CODED_SLICE_IDR_N_LP
814
0
      || t == VVC_NAL_UNIT_CODED_SLICE_CRA
815
0
      || t == VVC_NAL_UNIT_CODED_SLICE_GDR;
816
0
}
817
818
int VVDecImpl::copyComp( const unsigned char* pucSrc,
819
                         unsigned char*       pucDest,
820
                         unsigned int         uiWidth,
821
                         unsigned int         uiHeight,
822
                         ptrdiff_t            iStrideSrc,
823
                         ptrdiff_t            iStrideDest,
824
                         int                  iBytesPerSample )
825
0
{
826
0
  if( NULL != pucSrc && NULL != pucDest )
827
0
  {
828
0
    if( iStrideDest ==  iStrideSrc )
829
0
    {
830
0
      ::memcpy( pucDest, pucSrc, uiHeight * iStrideDest );
831
0
    }
832
0
    else
833
0
    {
834
0
      if (iBytesPerSample > 1)
835
0
      {
836
0
        uiWidth <<= 1;
837
0
        for( unsigned int uiH = 0; uiH < uiHeight; uiH++ )
838
0
        {
839
0
          ::memcpy( pucDest, pucSrc, uiWidth );
840
0
          pucSrc  += iStrideSrc;
841
0
          pucDest += iStrideDest;
842
0
        }
843
0
      }
844
0
      else
845
0
      {
846
0
        CHECKD( iStrideDest > iStrideSrc, "copyComp only supports narrowing conversions" );
847
        // shift short->char
848
0
        for( unsigned int y=0; y < uiHeight; y++ )
849
0
        {
850
0
          unsigned int x = 0;
851
852
#if ENABLE_SIMD_OPT && defined( TARGET_SIMD_X86 )
853
          for( x = 0; x < ( uiWidth & ~15 ); x += 16 )
854
          {
855
            const __m128i a = _mm_loadu_si128( (__m128i*) &pucSrc[x * 2] );
856
            const __m128i b = _mm_loadu_si128( (__m128i*) &pucSrc[x * 2 + 16] );
857
            _mm_storeu_si128( (__m128i*) &pucDest[x], _mm_packus_epi16( a, b ) );
858
          }
859
#endif   // ENABLE_SIMD_OPT && defined( TARGET_SIMD_X86 )
860
861
0
          for( ; x < uiWidth; x++ )
862
0
          {
863
0
            pucDest[x] = pucSrc[x<<1];
864
0
          }
865
0
          pucSrc   += iStrideSrc;
866
0
          pucDest  += iStrideDest;
867
0
        }
868
0
      }
869
0
    }
870
0
  }
871
0
  else
872
0
  {
873
0
    return -1;
874
0
  }
875
876
0
  return 0;
877
0
}
878
879
void VVDecImpl::xUpdateFGC( vvdecSEI* s )
880
0
{
881
0
  vvdecSEIFilmGrainCharacteristics* sei = (vvdecSEIFilmGrainCharacteristics*) s->payload;
882
883
0
  if( sei->filmGrainCharacteristicsCancelFlag )
884
0
  {
885
0
    m_filmGrainCharacteristicsState = FgcNone;
886
0
    return;
887
0
  }
888
889
0
  if( !m_filmGrainSynth )
890
0
  {
891
0
    m_filmGrainSynth = std::make_unique<FilmGrain>();
892
0
  }
893
894
0
  m_filmGrainSynth->updateFGC( sei );
895
0
  m_filmGrainCharacteristicsState = sei->filmGrainCharacteristicsPersistenceFlag ? FgcPersist : FgcDontPersist;
896
0
}
897
898
void VVDecImpl::xAddGrain( vvdecFrame* frame )
899
0
{
900
0
  if( m_filmGrainCharacteristicsState == FgcNone )
901
0
  {
902
0
    return;
903
0
  }
904
905
0
  m_filmGrainSynth->setDepth( frame->bitDepth );
906
0
  m_filmGrainSynth->setColorFormat( frame->colorFormat );
907
0
  m_filmGrainSynth->prepareBlockSeeds( frame->planes[0].width, frame->planes[0].height );
908
909
0
  struct GrainTaskData
910
0
  {
911
0
    vvdecFrame* frame;
912
0
    uint32_t    startLine;
913
0
    FilmGrain*  filmGrainSynth;
914
0
  };
915
0
  constexpr static int       LINES_PER_TASK = 16;
916
0
  const int                  numTasks       = ( frame->planes[0].height + ( LINES_PER_TASK - 1 ) ) / LINES_PER_TASK;
917
0
  std::vector<GrainTaskData> grainTaskData( numTasks );
918
919
0
  WaitCounter grainTaskCounter;
920
0
  for( int i = 0; i < numTasks; ++i )
921
0
  {
922
0
    grainTaskData[i].frame          = frame;
923
0
    grainTaskData[i].startLine      = i * LINES_PER_TASK;
924
0
    grainTaskData[i].filmGrainSynth = m_filmGrainSynth.get();
925
926
0
    static auto grainTask = []( int, void* param )
927
0
    {
928
0
      GrainTaskData* data  = static_cast<GrainTaskData*>( param );
929
0
      auto* frame = data->frame;
930
0
      for( unsigned y = data->startLine; y < std::min( data->startLine + LINES_PER_TASK, frame->planes[0].height ); ++y )
931
0
      {
932
0
        uint8_t* Y = (uint8_t*) frame->planes[0].ptr + frame->planes[0].stride * y;
933
0
        uint8_t* U = nullptr;
934
0
        uint8_t* V = nullptr;
935
0
        if( frame->colorFormat != VVDEC_CF_YUV400_PLANAR )
936
0
        {
937
0
          const int chromaSub = frame->colorFormat == VVDEC_CF_YUV420_PLANAR ? 2 : 1;
938
939
0
          U = (uint8_t*) frame->planes[1].ptr + frame->planes[1].stride * y / chromaSub;
940
0
          V = (uint8_t*) frame->planes[2].ptr + frame->planes[2].stride * y / chromaSub;
941
0
        }
942
943
0
        data->filmGrainSynth->add_grain_line( Y, U, V, y, frame->planes[0].width );
944
0
      }
945
0
      return true;
946
0
    };
947
0
    m_cDecLib->getThreadPool().addBarrierTask( grainTask, &( grainTaskData[i] ), &grainTaskCounter );
948
0
  }
949
0
  grainTaskCounter.wait();
950
951
0
  if( m_filmGrainCharacteristicsState != FgcPersist )   // Not persistent
952
0
  {
953
0
    m_filmGrainCharacteristicsState = FgcNone;
954
0
  }
955
0
}
956
957
int VVDecImpl::xAddPicture( Picture* pcPic )
958
0
{
959
  // copy internal picture to external (Priority PPS > SPS)
960
0
  const Window &conf    = pcPic->cs->pps->getConformanceWindowPresentFlag()
961
0
                          ? pcPic->cs->pps->getConformanceWindow()
962
0
                          : pcPic->cs->sps->getConformanceWindow();
963
//          const Window  defDisp = (m_respectDefDispWindow && pcPic->cs->sps->getVuiParametersPresentFlag())
964
//                                  ? pcPic->cs->sps->getVuiParameters()->getDefaultDisplayWindow()
965
//                                  : Window();
966
0
  const Window  defDisp =  Window();
967
0
  int confLeft   = conf.getWindowLeftOffset()   * SPS::getWinUnitX(pcPic->cs->sps->getChromaFormatIdc())  + defDisp.getWindowLeftOffset();
968
0
  int confRight  = conf.getWindowRightOffset()  * SPS::getWinUnitX(pcPic->cs->sps->getChromaFormatIdc())  + defDisp.getWindowRightOffset();
969
0
  int confTop    = conf.getWindowTopOffset()    * SPS::getWinUnitY(pcPic->cs->sps->getChromaFormatIdc())  + defDisp.getWindowTopOffset();
970
0
  int confBottom = conf.getWindowBottomOffset() * SPS::getWinUnitY(pcPic->cs->sps->getChromaFormatIdc())  + defDisp.getWindowBottomOffset();
971
972
0
  const CPelUnitBuf& cPicBuf = pcPic->getRecoBuf();
973
974
0
  const uint32_t uiWidth  = cPicBuf.Y().width - confLeft - confRight;
975
0
  const uint32_t uiHeight = cPicBuf.Y().height - confTop - confBottom;
976
977
0
  const BitDepths &bitDepths= pcPic->cs->sps->getBitDepths(); // use bit depths of first reconstructed picture.
978
979
0
  if ((uiWidth == 0) || (uiHeight == 0))
980
0
  {
981
0
    msg( ERROR, "vvdecimpl::xAddPicture: %dx%d luma sample output picture!\n", uiWidth, uiHeight );
982
0
    return VVDEC_ERR_UNSPECIFIED;
983
0
  }
984
985
0
  bool bCreateStorage = ( bitDepths.recon == 8 );   // for 8bit output we need to copy the lib picture from unsigned short into unsigned char buffer
986
987
0
  if( m_enableFilmGrain )
988
0
  {
989
0
    if( pcPic->isCLVSS() )
990
0
    {
991
0
      m_filmGrainCharacteristicsState = FgcNone;
992
0
    }
993
994
    // find FGC SEI
995
0
    for( auto& sei: pcPic->seiMessageList )
996
0
    {
997
0
      if( sei->payloadType == VVDEC_FILM_GRAIN_CHARACTERISTICS )
998
0
      {
999
0
        xUpdateFGC( sei );
1000
0
        msg( DETAILS, "vvdecimpl [detail]: SEI FILM_GRAIN_CHARACTERISTICS\n");
1001
0
      }
1002
0
    }
1003
0
    const bool fgsReuseBuffer = bitDepths.recon == 10 && !pcPic->stillReferenced;
1004
0
    if( !fgsReuseBuffer )
1005
0
    {
1006
0
      bCreateStorage |= m_filmGrainCharacteristicsState != FgcNone;
1007
0
    }
1008
0
  }
1009
1010
  // create a brand new picture object
1011
0
  vvdecFrame cFrame;
1012
0
  vvdec_frame_default( &cFrame );
1013
1014
0
  cFrame.sequenceNumber = m_uiSeqNumber;
1015
0
  cFrame.cts            = pcPic->getCts();
1016
0
  cFrame.ctsValid       = true;
1017
1018
0
  const bool origStride = m_filmGrainCharacteristicsState != FgcNone;
1019
0
  const int  ret        = xCreateFrame( cFrame, cPicBuf, uiWidth, uiHeight, bitDepths, bCreateStorage, origStride );
1020
0
  if( ret != VVDEC_OK )
1021
0
  {
1022
0
    return ret;
1023
0
  }
1024
1025
0
  const int maxComponent = getNumberValidComponents( cPicBuf.chromaFormat );
1026
0
  for( int comp = 0; comp < maxComponent; comp++ )
1027
0
  {
1028
0
    const ComponentID  compID         = ComponentID( comp );
1029
0
    const uint32_t     csx            = getComponentScaleX( compID, cPicBuf.chromaFormat );
1030
0
    const uint32_t     csy            = getComponentScaleY( compID, cPicBuf.chromaFormat );
1031
0
    const CPelBuf      area           = cPicBuf.get( compID );
1032
0
    const unsigned int bytesPerSample = bitDepths.recon > 8 ? 2 : 1;
1033
1034
0
    const Pel*      planeOrigin = area.buf;
1035
0
    const ptrdiff_t planeOffset = ( confLeft >> csx ) + ( confTop >> csy ) * area.stride;
1036
1037
0
    if( bCreateStorage )
1038
0
    {
1039
0
      const unsigned int copyWidth  = area.width - ( ( confLeft + confRight ) >> csx );
1040
0
      const unsigned int copyHeight = area.height - ( ( confTop + confBottom ) >> csy );
1041
1042
      // copy picture into target memory
1043
0
      copyComp( (const unsigned char*) ( planeOrigin + planeOffset ),
1044
0
                cFrame.planes[comp].ptr,
1045
0
                copyWidth,
1046
0
                copyHeight,
1047
0
                area.stride * sizeof( *area.buf ),
1048
0
                cFrame.planes[comp].stride,
1049
0
                bytesPerSample );
1050
0
    }
1051
0
    else   // !bCreateStorage
1052
0
    {
1053
0
      if( m_cUserAllocator.enabled )
1054
0
      {
1055
0
        cFrame.planes[comp].allocator = pcPic->getBufAllocator( (ComponentID) comp );
1056
0
      }
1057
1058
      // use internal lib picture memory
1059
0
      cFrame.planes[comp].ptr = (unsigned char*) ( const_cast<Pel*>( planeOrigin + planeOffset ) );
1060
0
    }
1061
0
  }
1062
1063
  // set picture attributes
1064
1065
0
  const SPS* sps = !pcPic->slices.empty() ? pcPic->slices.front()->getSPS() : nullptr;
1066
1067
0
  const VUI*              vui = sps && sps->getVuiParametersPresentFlag()  ? sps->getVuiParameters()        : nullptr;
1068
0
  const GeneralHrdParams* hrd = sps && sps->getGeneralHrdParameters()      ? sps->getGeneralHrdParameters() : nullptr;
1069
0
  const OlsHrdParams*     ols = sps && !sps->getOlsHrdParameters().empty() ? &sps->getOlsHrdParameters()[0] : nullptr;
1070
1071
  // use paddedSizeOf() instead of sizeof() to ensure all structs start aligned to an 8 byte boundary
1072
0
  size_t allocSize = paddedSizeOf<vvdecPicAttributes>() + paddedSizeOf<vvdecSeqInfo>();
1073
0
  if( vui ) allocSize += paddedSizeOf<vvdecVui>();
1074
0
  if( hrd ) allocSize += paddedSizeOf<vvdecHrd>();
1075
0
  if( ols ) allocSize += paddedSizeOf<vvdecOlsHrd>();
1076
1077
0
  char* allocPtr = (char*) xMalloc( char, allocSize );
1078
0
  if( !allocPtr )
1079
0
  {
1080
0
    return VVDEC_NOT_ENOUGH_MEM;
1081
0
  }
1082
0
  memset( allocPtr, 0, allocSize );
1083
1084
0
  cFrame.picAttributes = allocInto<vvdecPicAttributes>( &allocPtr );
1085
1086
0
  vvdec_picAttributes_default( cFrame.picAttributes );
1087
0
  cFrame.picAttributes->poc           = pcPic->poc;
1088
0
  cFrame.picAttributes->temporalLayer = pcPic->getTLayer();
1089
0
  cFrame.picAttributes->bits          = pcPic->getNaluBits();
1090
0
  cFrame.picAttributes->nalType       = (vvdecNalType)pcPic->eNalUnitType;
1091
0
  cFrame.picAttributes->isRefPic      = pcPic->isReferencePic;
1092
1093
0
  cFrame.picAttributes->seqInfo = allocInto<vvdecSeqInfo>( &allocPtr );
1094
1095
0
  cFrame.picAttributes->seqInfo->maxWidth  = pcPic->cs->sps->getMaxPicWidthInLumaSamples();
1096
0
  cFrame.picAttributes->seqInfo->maxHeight = pcPic->cs->sps->getMaxPicHeightInLumaSamples();
1097
0
  int32_t maxReorderPics = 0;
1098
0
  uint32_t maxLatencyIncreasePlus1 = 0;
1099
0
  for(uint32_t i = 0; i < sps->getMaxTLayers(); i++) {
1100
0
    maxReorderPics = std::max(maxReorderPics, sps->getNumReorderPics(i));
1101
0
    maxLatencyIncreasePlus1 = std::max(maxLatencyIncreasePlus1, sps->getMaxLatencyIncreasePlus1(i));
1102
0
  }
1103
1104
0
  cFrame.picAttributes->seqInfo->maxNumReorderPics = maxReorderPics;
1105
0
  cFrame.picAttributes->seqInfo->maxLatencyIncreasePlus1 = maxLatencyIncreasePlus1;
1106
1107
0
  cFrame.picAttributes->picHashError =
1108
0
    pcPic->dphMismatch ? VVDEC_DPH_MISMATCH                                   // first check pcPic->dphMismatch,
1109
0
                       : ( pcPic->picCheckedDPH ? VVDEC_DPH_OK                // and then pcPic->picCheckedDPH, because it will only be set when all subpics
1110
0
                                                : VVDEC_DPH_NOT_VERIFIED );   // have been checked, but the DPH-SEIs for some subpics could be missing,
1111
1112
#if VVDEC_USE_UNSTABLE_API
1113
  cFrame.picAttributes->userData = pcPic->userData;
1114
#endif
1115
0
  if( pcPic->fieldPic )
1116
0
  {
1117
0
    cFrame.frameFormat = pcPic->topField ? VVDEC_FF_TOP_FIELD : VVDEC_FF_BOT_FIELD;
1118
0
  }
1119
1120
0
  if ( !pcPic->slices.empty() )
1121
0
  {
1122
0
    switch( pcPic->slices.front()->getSliceType() )
1123
0
    {
1124
0
      case I_SLICE: cFrame.picAttributes->sliceType = VVDEC_SLICETYPE_I; break;
1125
0
      case P_SLICE: cFrame.picAttributes->sliceType = VVDEC_SLICETYPE_P; break;
1126
0
      case B_SLICE: cFrame.picAttributes->sliceType = VVDEC_SLICETYPE_B; break;
1127
0
      default:      cFrame.picAttributes->sliceType = VVDEC_SLICETYPE_UNKNOWN; break;
1128
0
    }
1129
1130
0
    if( vui )
1131
0
    {
1132
0
      cFrame.picAttributes->vui = allocInto<vvdecVui>( &allocPtr );
1133
1134
0
      cFrame.picAttributes->vui->aspectRatioInfoPresentFlag     = vui->getAspectRatioInfoPresentFlag();
1135
0
      cFrame.picAttributes->vui->aspectRatioConstantFlag        = vui->getAspectRatioConstantFlag();
1136
0
      cFrame.picAttributes->vui->nonPackedFlag                  = vui->getNonPackedFlag();
1137
0
      cFrame.picAttributes->vui->nonProjectedFlag               = vui->getNonProjectedFlag();
1138
0
      cFrame.picAttributes->vui->aspectRatioIdc                 = vui->getAspectRatioIdc();
1139
0
      cFrame.picAttributes->vui->sarWidth                       = vui->getSarWidth();
1140
0
      cFrame.picAttributes->vui->sarHeight                      = vui->getSarHeight();
1141
0
      cFrame.picAttributes->vui->colourDescriptionPresentFlag   = vui->getColourDescriptionPresentFlag();
1142
0
      cFrame.picAttributes->vui->colourPrimaries                = vui->getColourPrimaries();
1143
0
      cFrame.picAttributes->vui->transferCharacteristics        = vui->getTransferCharacteristics();
1144
0
      cFrame.picAttributes->vui->matrixCoefficients             = vui->getMatrixCoefficients();
1145
0
      cFrame.picAttributes->vui->progressiveSourceFlag          = vui->getProgressiveSourceFlag();
1146
0
      cFrame.picAttributes->vui->interlacedSourceFlag           = vui->getInterlacedSourceFlag();
1147
0
      cFrame.picAttributes->vui->chromaLocInfoPresentFlag       = vui->getChromaLocInfoPresentFlag();
1148
0
      cFrame.picAttributes->vui->chromaSampleLocTypeTopField    = vui->getChromaSampleLocTypeTopField();
1149
0
      cFrame.picAttributes->vui->chromaSampleLocTypeBottomField = vui->getChromaSampleLocTypeBottomField();
1150
0
      cFrame.picAttributes->vui->chromaSampleLocType            = vui->getChromaSampleLocType();
1151
0
      cFrame.picAttributes->vui->overscanInfoPresentFlag        = vui->getOverscanInfoPresentFlag();
1152
0
      cFrame.picAttributes->vui->overscanAppropriateFlag        = vui->getOverscanAppropriateFlag();
1153
0
      cFrame.picAttributes->vui->videoSignalTypePresentFlag     = vui->getVideoSignalTypePresentFlag();
1154
0
      cFrame.picAttributes->vui->videoFullRangeFlag             = vui->getVideoFullRangeFlag();
1155
0
    }
1156
1157
0
    if( hrd )
1158
0
    {
1159
0
      cFrame.picAttributes->hrd = allocInto<vvdecHrd>( &allocPtr );
1160
1161
0
      cFrame.picAttributes->hrd->numUnitsInTick                          = hrd->getNumUnitsInTick();
1162
0
      cFrame.picAttributes->hrd->timeScale                               = hrd->getTimeScale();
1163
0
      cFrame.picAttributes->hrd->generalNalHrdParamsPresentFlag          = hrd->getGeneralNalHrdParamsPresentFlag();
1164
0
      cFrame.picAttributes->hrd->generalVclHrdParamsPresentFlag          = hrd->getGeneralVclHrdParamsPresentFlag();
1165
0
      cFrame.picAttributes->hrd->generalSamePicTimingInAllOlsFlag        = hrd->getGeneralSamePicTimingInAllOlsFlag();
1166
0
      cFrame.picAttributes->hrd->tickDivisor                             = hrd->getTickDivisorMinus2() + 2;
1167
0
      cFrame.picAttributes->hrd->generalDecodingUnitHrdParamsPresentFlag = hrd->getGeneralDuHrdParamsPresentFlag();
1168
0
      cFrame.picAttributes->hrd->bitRateScale                            = hrd->getBitRateScale();
1169
0
      cFrame.picAttributes->hrd->cpbSizeScale                            = hrd->getCpbSizeScale();
1170
0
      cFrame.picAttributes->hrd->cpbSizeDuScale                          = hrd->getCpbSizeDuScale();
1171
0
      cFrame.picAttributes->hrd->hrdCpbCnt                               = hrd->getHrdCpbCntMinus1() + 1;
1172
0
    }
1173
1174
0
    if( ols )
1175
0
    {
1176
0
      cFrame.picAttributes->olsHrd = allocInto<vvdecOlsHrd>( &allocPtr );
1177
1178
0
      cFrame.picAttributes->olsHrd->fixedPicRateGeneralFlag   = ols->getFixedPicRateGeneralFlag();
1179
0
      cFrame.picAttributes->olsHrd->fixedPicRateWithinCvsFlag = ols->getFixedPicRateWithinCvsFlag();
1180
0
      cFrame.picAttributes->olsHrd->elementDurationInTc       = ols->getElementDurationInTcMinus1() + 1;
1181
0
      cFrame.picAttributes->olsHrd->lowDelayHrdFlag           = ols->getLowDelayHrdFlag();
1182
1183
0
      for( int j = 0; j < 2; j++ )
1184
0
      {
1185
0
        if( j == 0 && !cFrame.picAttributes->hrd->generalNalHrdParamsPresentFlag ) continue;
1186
0
        if( j == 1 && !cFrame.picAttributes->hrd->generalVclHrdParamsPresentFlag ) continue;
1187
1188
0
        for( int i = 0; i < cFrame.picAttributes->hrd->hrdCpbCnt; i++ )
1189
0
        {
1190
0
          cFrame.picAttributes->olsHrd->bitRateValueMinus1  [i][j] = ols->getBitRateValueMinus1( i, j );
1191
0
          cFrame.picAttributes->olsHrd->cpbSizeValueMinus1  [i][j] = ols->getCpbSizeValueMinus1( i, j );
1192
0
          cFrame.picAttributes->olsHrd->ducpbSizeValueMinus1[i][j] = ols->getDuCpbSizeValueMinus1( i, j );
1193
0
          cFrame.picAttributes->olsHrd->duBitRateValueMinus1[i][j] = ols->getDuBitRateValueMinus1( i, j );
1194
0
          cFrame.picAttributes->olsHrd->cbrFlag             [i][j] = ols->getCbrFlag( i, j );
1195
0
        }
1196
0
      }
1197
0
    }
1198
0
  }
1199
1200
  // Grain synthesis
1201
0
  if( m_enableFilmGrain && m_filmGrainCharacteristicsState != FgcNone )
1202
0
  {
1203
0
    xAddGrain( &cFrame );
1204
0
  }
1205
1206
0
  m_rcFrameList.emplace_back( cFrame, bCreateStorage ? nullptr : pcPic );
1207
1208
0
  if( m_pcFrameNext == m_rcFrameList.end() )
1209
0
  {
1210
0
    if( m_uiSeqNumber == 0 )
1211
0
    {
1212
0
      m_pcFrameNext = m_rcFrameList.begin();
1213
0
    }
1214
0
    else
1215
0
    {
1216
0
      for( auto it = m_rcFrameList.begin(); it != m_rcFrameList.end(); it++ )
1217
0
      {
1218
0
        if( std::get<vvdecFrame>( *it ).sequenceNumber > m_uiSeqNumOutput )
1219
0
        {
1220
0
          m_pcFrameNext = it;
1221
0
          break;
1222
0
        }
1223
0
      }
1224
0
    }
1225
0
  }
1226
1227
0
  m_uiSeqNumber++;
1228
1229
0
  if( bCreateStorage )
1230
0
  {
1231
    // release library picture storage, because picture has been copied into new storage class
1232
0
    m_cDecLib->releasePicture( pcPic );
1233
0
  }
1234
1235
0
  return 0;
1236
0
}
1237
1238
int VVDecImpl::xCreateFrame( vvdecFrame&        rcFrame,
1239
                             const CPelUnitBuf& rcPicBuf,
1240
                             uint32_t           uiWidth,
1241
                             uint32_t           uiHeight,
1242
                             const BitDepths&   rcBitDepths,
1243
                             bool               bCreateStorage,
1244
                             bool               origStride )
1245
0
{
1246
0
  rcFrame.width       = uiWidth;
1247
0
  rcFrame.height      = uiHeight;
1248
0
  rcFrame.bitDepth    = 8;
1249
0
  rcFrame.frameFormat = VVDEC_FF_PROGRESSIVE;
1250
0
  rcFrame.bitDepth    = std::max( (uint32_t)rcBitDepths.recon, rcFrame.bitDepth );
1251
1252
0
  rcFrame.planes[VVDEC_CT_Y].width          = uiWidth;
1253
0
  rcFrame.planes[VVDEC_CT_Y].height         = uiHeight;
1254
0
  rcFrame.planes[VVDEC_CT_Y].bytesPerSample = rcBitDepths.recon > 8 ? 2 : 1;
1255
0
  rcFrame.planes[VVDEC_CT_Y].stride         = bCreateStorage && !origStride ? uiWidth                                       * rcFrame.planes[VVDEC_CT_Y].bytesPerSample
1256
0
                                                                            : (uint32_t) rcPicBuf.get( COMPONENT_Y ).stride * rcFrame.planes[VVDEC_CT_Y].bytesPerSample;
1257
1258
0
  size_t nBufSize = 0;
1259
0
  size_t nLSize   = rcFrame.planes[VVDEC_CT_Y].stride * rcFrame.planes[VVDEC_CT_Y].height;
1260
0
  size_t nCSize   = 0;
1261
1262
0
  unsigned int uiCWidth  = 0;
1263
0
  unsigned int uiCHeight = 0;
1264
1265
0
  switch( rcPicBuf.chromaFormat )
1266
0
  {
1267
0
    case CHROMA_400:
1268
0
      {
1269
0
        rcFrame.colorFormat = VVDEC_CF_YUV400_PLANAR;
1270
0
        rcFrame.numPlanes = 1;
1271
0
        break;
1272
0
      }
1273
0
    case CHROMA_420:
1274
0
      {
1275
0
        rcFrame.colorFormat = VVDEC_CF_YUV420_PLANAR;
1276
0
        rcFrame.numPlanes   = 3;
1277
1278
0
        uiCWidth  = uiWidth >> 1;
1279
0
        uiCHeight = uiHeight >> 1;
1280
0
        break;
1281
0
      }
1282
0
    case CHROMA_422:
1283
0
      {
1284
0
        rcFrame.colorFormat = VVDEC_CF_YUV422_PLANAR;
1285
0
        rcFrame.numPlanes   = 3;
1286
1287
0
        uiCWidth  = uiWidth >> 1;
1288
0
        uiCHeight = uiHeight;
1289
0
        break;
1290
0
      }
1291
0
    case CHROMA_444:
1292
0
      {
1293
0
        rcFrame.colorFormat = VVDEC_CF_YUV444_PLANAR;
1294
0
        rcFrame.numPlanes   = 3;
1295
1296
0
        uiCWidth  = uiWidth;
1297
0
        uiCHeight = uiHeight;
1298
0
        break;
1299
0
      }
1300
0
    default:
1301
0
        THROW_FATAL( "unsupported chroma fromat " << rcPicBuf.chromaFormat );
1302
0
  }
1303
1304
0
  if( rcPicBuf.chromaFormat == CHROMA_400 )
1305
0
  {
1306
0
    rcFrame.planes[VVDEC_CT_U].width          = 0;
1307
0
    rcFrame.planes[VVDEC_CT_U].height         = 0;
1308
0
    rcFrame.planes[VVDEC_CT_U].stride         = 0;
1309
0
    rcFrame.planes[VVDEC_CT_U].bytesPerSample = 0;
1310
1311
0
    rcFrame.planes[VVDEC_CT_V].width          = 0;
1312
0
    rcFrame.planes[VVDEC_CT_V].height         = 0;
1313
0
    rcFrame.planes[VVDEC_CT_V].stride         = 0;
1314
0
    rcFrame.planes[VVDEC_CT_V].bytesPerSample = 0;
1315
1316
0
    nCSize = 0;
1317
0
    nBufSize = nLSize; // we have to copy the packet into 8bit, because internal bitdepth is always Pel (unsigned short)
1318
0
  }
1319
0
  else
1320
0
  {
1321
0
    rcFrame.planes[VVDEC_CT_U].width          = uiCWidth;
1322
0
    rcFrame.planes[VVDEC_CT_U].height         = uiCHeight;
1323
0
    rcFrame.planes[VVDEC_CT_U].bytesPerSample = rcBitDepths.recon > 8 ? 2 : 1;
1324
1325
0
    rcFrame.planes[VVDEC_CT_V].width          = uiCWidth;
1326
0
    rcFrame.planes[VVDEC_CT_V].height         = uiCHeight;
1327
0
    rcFrame.planes[VVDEC_CT_V].bytesPerSample = rcBitDepths.recon > 8 ? 2 : 1;
1328
1329
0
    if( bCreateStorage && !origStride )
1330
0
    {
1331
0
      rcFrame.planes[VVDEC_CT_U].stride       = uiCWidth * rcFrame.planes[CHANNEL_TYPE_CHROMA].bytesPerSample;
1332
0
      rcFrame.planes[VVDEC_CT_V].stride       = uiCWidth * rcFrame.planes[CHANNEL_TYPE_CHROMA].bytesPerSample;
1333
0
    }
1334
0
    else
1335
0
    {
1336
0
      rcFrame.planes[VVDEC_CT_U].stride       = (uint32_t)rcPicBuf.get(COMPONENT_Cb).stride * rcFrame.planes[CHANNEL_TYPE_CHROMA].bytesPerSample;
1337
0
      rcFrame.planes[VVDEC_CT_V].stride       = (uint32_t)rcPicBuf.get(COMPONENT_Cr).stride * rcFrame.planes[CHANNEL_TYPE_CHROMA].bytesPerSample;
1338
0
    }
1339
1340
0
    nCSize   = rcFrame.planes[VVDEC_CT_U].stride * rcFrame.planes[VVDEC_CT_U].height;
1341
0
    nBufSize = nLSize + nCSize * 2;
1342
0
  }
1343
1344
1345
0
  if( bCreateStorage )
1346
0
  {
1347
0
    if( nBufSize == 0 ){ return VVDEC_ERR_ALLOCATE; }
1348
1349
0
    FrameStorage frameStorage;
1350
1351
0
    if( m_cUserAllocator.enabled )
1352
0
    {
1353
0
      frameStorage.setExternAllocator();
1354
0
      if( nLSize == 0 || ( rcFrame.numPlanes > 1 && nCSize == 0 ) ){ return VVDEC_ERR_ALLOCATE; }
1355
1356
0
      for ( int plane = 0; plane < rcFrame.numPlanes; plane++ )
1357
0
      {
1358
0
        rcFrame.planes[plane].ptr = (unsigned char*) m_cUserAllocator.create( m_cUserAllocator.opaque,
1359
0
                                                                              (vvdecComponentType) plane,
1360
0
                                                                              (uint32_t) ( plane == 0 ? nLSize : nCSize ),
1361
0
                                                                              MEMORY_ALIGN_DEF_SIZE,
1362
0
                                                                              &rcFrame.planes[plane].allocator );
1363
0
        if( !rcFrame.planes[plane].ptr )
1364
0
        {
1365
0
          return VVDEC_ERR_ALLOCATE;
1366
0
        }
1367
0
      }
1368
0
    }
1369
0
    else
1370
0
    {
1371
0
      frameStorage.allocateStorage( nBufSize );
1372
0
      rcFrame.planes[VVDEC_CT_Y].ptr = frameStorage.getStorage();
1373
1374
0
      switch( rcPicBuf.chromaFormat )
1375
0
      {
1376
0
        case CHROMA_400:
1377
0
            break;
1378
0
        case CHROMA_420:
1379
0
        case CHROMA_422:
1380
0
        case CHROMA_444:
1381
0
            rcFrame.planes[VVDEC_CT_U].ptr  = rcFrame.planes[VVDEC_CT_Y].ptr + nLSize;
1382
0
            rcFrame.planes[VVDEC_CT_V].ptr  = rcFrame.planes[VVDEC_CT_Y].ptr + (nLSize + nCSize);
1383
0
            break;
1384
0
        default: break;
1385
0
      }
1386
0
    }
1387
0
    m_cFrameStorageMap.insert( FrameStorageMapType( rcFrame.sequenceNumber, std::move( frameStorage ) ) );
1388
0
  }
1389
1390
0
  return 0;
1391
0
}
1392
1393
int VVDecImpl::xRetrieveNalStartCode( unsigned char *pB, int iZerosInStartcode )
1394
36.4k
{
1395
36.4k
  int found = 1;
1396
36.4k
  int i=0;
1397
127k
  for ( i = 0; i < iZerosInStartcode; i++)
1398
91.1k
  {
1399
91.1k
    if( pB[i] != 0 )
1400
75.7k
    {
1401
75.7k
      found = 0;
1402
75.7k
    }
1403
91.1k
  }
1404
1405
36.4k
  if( pB[i] != 1 )
1406
34.9k
  {
1407
34.9k
    found = 0;
1408
34.9k
  }
1409
1410
36.4k
  return found;
1411
36.4k
}
1412
1413
int VVDecImpl::xConvertPayloadToRBSP( const uint8_t* payload, size_t payloadLen, InputBitstream* bitstream, bool isVclNalUnit )
1414
766
{
1415
766
  uint32_t zeroCount = 0;
1416
766
  bitstream->clearEmulationPreventionByteLocation();
1417
1418
766
  AlignedByteVec& nalUnitBuf = bitstream->getFifo();
1419
766
  nalUnitBuf.resize( payloadLen );
1420
1421
766
  const uint8_t*           it_read  = payload;
1422
766
  AlignedByteVec::iterator it_write = nalUnitBuf.begin();
1423
18.9k
  for( size_t pos = 0; pos < payloadLen; it_read++, it_write++, pos++ )
1424
18.2k
  {
1425
18.2k
    if(zeroCount >= 2 && *it_read < 0x03 )
1426
18
    {
1427
18
      msg( ERROR, "Zero count is '2' and read value is smaller than '0x03'\n");
1428
18
      return -1;
1429
18
    }
1430
18.2k
    if (zeroCount == 2 && *it_read == 0x03)
1431
34
    {
1432
34
      bitstream->pushEmulationPreventionByteLocation( (uint32_t) pos );
1433
34
      pos++;
1434
34
      it_read++;
1435
34
      zeroCount = 0;
1436
34
      if( pos >= payloadLen )
1437
6
      {
1438
6
        break;
1439
6
      }
1440
1441
28
      if( *it_read > 0x03 )
1442
2
      {
1443
2
        msg( ERROR, "Read a value bigger than '0x03'\n");
1444
2
        return -1;
1445
2
      }
1446
28
    }
1447
18.1k
    zeroCount = (*it_read == 0x00) ? zeroCount+1 : 0;
1448
18.1k
    *it_write = *it_read;
1449
18.1k
  }
1450
1451
746
  if( zeroCount != 0 && !isVclNalUnit )
1452
2
  {
1453
2
    msg( ERROR, "Zero count is not '0' (NUT: %u)\n", ( nalUnitBuf[1] >> 3 ) & 0x1f );
1454
2
    return -1;
1455
2
  }
1456
1457
744
  if (isVclNalUnit)
1458
70
  {
1459
    // Remove cabac_zero_word from payload if present
1460
70
    int n = 0;
1461
1462
76
    while (it_write != nalUnitBuf.begin() && it_write[-1] == 0x00)
1463
6
    {
1464
6
      it_write--;
1465
6
      n++;
1466
6
    }
1467
1468
70
    if (it_write == nalUnitBuf.begin())
1469
0
    {
1470
0
      msg( ERROR, "VCL NAL unit RBSP is entirely zero\n");
1471
0
      return -1;
1472
0
    }
1473
1474
70
    if (n > 0)
1475
4
    {
1476
4
      msg( VERBOSE, "\nDetected %d instances of cabac_zero_word\n", n/2);
1477
4
    }
1478
70
  }
1479
1480
744
  nalUnitBuf.resize(it_write - nalUnitBuf.begin());
1481
1482
744
  return 0;
1483
744
}
1484
1485
int VVDecImpl::xReadNalUnitHeader(InputNALUnit& nalu)
1486
744
{
1487
744
  InputBitstream& bs = nalu.getBitstream();
1488
1489
744
  nalu.m_forbiddenZeroBit   = bs.read(1);                 // forbidden zero bit
1490
744
  CHECK_WARN( nalu.m_forbiddenZeroBit != 0, "forbidden_zero_bit shall be equal to 0." );
1491
1492
744
  nalu.m_nuhReservedZeroBit = bs.read(1);                 // nuh_reserved_zero_bit
1493
744
  CHECK_WARN( nalu.m_forbiddenZeroBit != 0, "nuh_reserved_zero_bit shall be equal to 0." );
1494
1495
744
  nalu.m_nuhLayerId         = bs.read(6);                 // nuh_layer_id
1496
744
  if( nalu.m_nuhLayerId > 55 )
1497
2
  {
1498
2
    msg( WARNING, "ignoring NAL unit with nuh_layer_id > 55. (%d)", nalu.m_nuhLayerId );
1499
2
    return -1;
1500
2
  }
1501
1502
742
  nalu.m_nalUnitType        = (NalUnitType) bs.read(5);   // nal_unit_type
1503
742
  nalu.m_temporalId         = bs.read(3) - 1;             // nuh_temporal_id_plus1
1504
742
  CHECK( nalu.m_temporalId + 1 == 0, "The value of nuh_temporal_id_plus1 shall not be equal to 0." );
1505
726
  CHECK( nalu.m_nalUnitType >= NAL_UNIT_CODED_SLICE_IDR_W_RADL && nalu.m_nalUnitType <= NAL_UNIT_RESERVED_IRAP_VCL_11 && nalu.m_temporalId != 0,
1506
726
                     "When nal_unit_type is in the range of IDR_W_RADL to RSV_IRAP_11, inclusive, TemporalId shall be equal to 0." );
1507
1508
  // only check these rules for base layer
1509
724
  CHECK( nalu.m_nuhLayerId == 0 && nalu.m_temporalId == 0 && nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_STSA,
1510
724
                     "When NAL unit type is equal to STSA_NUT, TemporalId shall not be equal to 0\n" );
1511
1512
722
  return 0;
1513
724
}
1514
1515
int VVDecImpl::xHandleOutput( Picture* pcPic )
1516
834
{
1517
834
  int ret = 0;
1518
834
  if( pcPic )
1519
0
  {
1520
0
    if( m_eState == INTERNAL_STATE_TUNING_IN )
1521
0
    {
1522
0
      m_eState = INTERNAL_STATE_DECODING;
1523
0
    }
1524
    // copy internal picture to external
1525
0
    if( 0 != xAddPicture( pcPic ))
1526
0
    {
1527
0
      ret = -1;
1528
0
    }
1529
0
  }
1530
1531
834
  return ret;
1532
834
}
1533
1534
/*
1535
 * return true if the frame is allocated in vvdecimpl, because it had to be converted
1536
 * e.g. to convert internal 16->8bit samples
1537
 * of   to scale RPR picture
1538
*/
1539
bool VVDecImpl::isFrameConverted( vvdecFrame* frame )
1540
0
{
1541
0
  FrameStorageMap::iterator storageIter =  m_cFrameStorageMap.find( frame->sequenceNumber );
1542
0
  if( storageIter != m_cFrameStorageMap.end() )
1543
0
  {
1544
0
    if( storageIter->second.isAllocated() || storageIter->second.isExternAllocator() )
1545
0
    {
1546
0
      return true;
1547
0
    }
1548
0
  }
1549
1550
0
  return false;
1551
0
}
1552
1553
void VVDecImpl::vvdec_picAttributes_default(vvdecPicAttributes *attributes)
1554
0
{
1555
0
  memset( attributes, 0, sizeof( vvdecPicAttributes ) );
1556
1557
0
  attributes->nalType      = VVC_NAL_UNIT_INVALID;      ///< nal unit type
1558
0
  attributes->sliceType    = VVDEC_SLICETYPE_UNKNOWN;   ///< slice type (I/P/B)
1559
0
  attributes->picHashError = VVDEC_DPH_NOT_VERIFIED;
1560
0
}
1561
1562
void VVDecImpl::vvdec_frame_default(vvdecFrame *frame)
1563
0
{
1564
0
  memset( frame, 0, sizeof( vvdecFrame ) );
1565
1566
0
  for( auto & p : frame->planes )
1567
0
  {
1568
0
    vvdec_plane_default( &p );
1569
0
  }
1570
0
  frame->frameFormat = VVDEC_FF_INVALID;   ///< interlace format (VVC_FF_PROGRESSIVE)
1571
0
  frame->colorFormat = VVDEC_CF_INVALID;   ///< color format     (VVC_CF_YUV420_PLANAR)
1572
0
}
1573
1574
void VVDecImpl::vvdec_plane_default(vvdecPlane *plane)
1575
0
{
1576
0
  memset( plane, 0, sizeof( vvdecPlane ) );
1577
1578
0
  plane->bytesPerSample = 1;   ///< number of bytes per sample
1579
0
}
1580
1581
void VVDecImpl::vvdec_frame_reset(vvdecFrame *frame)
1582
0
{
1583
0
  bool bIsExternAllocator = false;
1584
0
  FrameStorageMap::iterator storageIter = m_cFrameStorageMap.find( frame->sequenceNumber );
1585
0
  if( storageIter != m_cFrameStorageMap.end() )
1586
0
  {
1587
0
    if( storageIter->second.isAllocated() )
1588
0
    {
1589
0
      storageIter->second.freeStorage();
1590
0
    }
1591
0
    else if( storageIter->second.isExternAllocator() )
1592
0
    {
1593
0
      bIsExternAllocator = true;
1594
0
    }
1595
1596
0
    m_cFrameStorageMap.erase (storageIter);
1597
0
  }
1598
1599
0
  if( frame->picAttributes )
1600
0
  {
1601
0
    xFree( frame->picAttributes );
1602
0
    frame->picAttributes = NULL;
1603
0
  }
1604
1605
0
  if( m_cUserAllocator.enabled && m_cUserAllocator.unref && bIsExternAllocator )
1606
0
  {
1607
    // unref the buffer that has been converted (e.g. to 8bit) and is not needed internal anymore
1608
0
    for( uint32_t i = 0; i < frame->numPlanes; i++ )
1609
0
    {
1610
0
      if( frame->planes[i].allocator )
1611
0
      {
1612
0
        m_cUserAllocator.unref( m_cUserAllocator.opaque, frame->planes[i].allocator );
1613
0
      }
1614
0
    }
1615
0
  }
1616
1617
0
  vvdec_frame_default( frame );
1618
0
}
1619
1620
VVDEC_DECL void rescalePlane( const vvdecPlane&      srcPlane,
1621
                              vvdecPlane&            dstPlane,
1622
                              int                    planeComponent,
1623
                              const vvdecColorFormat colorFormat,
1624
                              int                    bitDepth,
1625
                              const bool             horCollocatedChromaFlag,
1626
                              const bool             verCollocatedChromaFlag )
1627
0
{
1628
0
  const ChromaFormat chromaFormatIDC = static_cast<ChromaFormat>( colorFormat );
1629
0
  const ComponentID  compID          = static_cast<ComponentID>( planeComponent );
1630
1631
0
  const int xScale = ( ( srcPlane.width  << SCALE_RATIO_BITS ) + ( dstPlane.width  >> 1 ) ) / dstPlane.width;
1632
0
  const int yScale = ( ( srcPlane.height << SCALE_RATIO_BITS ) + ( dstPlane.height >> 1 ) ) / dstPlane.height;
1633
1634
0
#if ENABLE_SIMD_OPT_BUFFER
1635
0
  g_pelBufOP.sampleRateConv
1636
#else
1637
  sampleRateConvCore
1638
#endif
1639
0
    ( { xScale, yScale },
1640
0
      { getComponentScaleX( compID, chromaFormatIDC ), getComponentScaleY( compID, chromaFormatIDC ) },
1641
0
      (Pel*) srcPlane.ptr,
1642
0
      srcPlane.stride / srcPlane.bytesPerSample,
1643
0
      srcPlane.width,
1644
0
      srcPlane.height,
1645
0
      0,
1646
0
      0,
1647
0
      (Pel*) dstPlane.ptr,
1648
0
      dstPlane.stride / dstPlane.bytesPerSample,
1649
0
      dstPlane.width,
1650
0
      dstPlane.height,
1651
0
      0,
1652
0
      0,
1653
0
      bitDepth,
1654
0
      isLuma( compID ),
1655
0
      isLuma( compID ) ? 1 : horCollocatedChromaFlag,
1656
0
      isLuma( compID ) ? 1 : verCollocatedChromaFlag );
1657
0
}
1658
1659
}   // namespace vvdec