Coverage Report

Created: 2026-10-28 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvdec/source/Lib/DecoderLib/DecLib.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
/** \file     DecLib.cpp
44
    \brief    decoder wrapper class
45
*/
46
47
#include "DecLib.h"
48
49
#include "CommonLib/dtrace_next.h"
50
#include "CommonLib/dtrace_buffer.h"
51
#include "CommonLib/TimeProfiler.h"
52
53
#include "CommonLib/arm/CommonDefARM.h"
54
#include "CommonLib/x86/CommonDefX86.h"
55
56
#include "NALread.h"
57
58
59
namespace vvdec
60
{
61
62
#ifdef TRACE_ENABLE_ITT
63
std::vector<__itt_domain*> itt_domain_decInst;
64
__itt_domain* itt_domain_dec           = __itt_domain_create( "Decode" );
65
__itt_domain* itt_domain_prs           = __itt_domain_create( "Parse" );
66
__itt_domain* itt_domain_oth           = __itt_domain_create( "Other" );
67
68
__itt_string_handle* itt_handle_alf    = __itt_string_handle_create( "ALF_CTU" );
69
__itt_string_handle* itt_handle_presao = __itt_string_handle_create( "PreSAO_Line" );
70
__itt_string_handle* itt_handle_sao    = __itt_string_handle_create( "SAO_CTU" );
71
__itt_string_handle* itt_handle_lfl    = __itt_string_handle_create( "LFL_CTU" );
72
__itt_string_handle* itt_handle_intra  = __itt_string_handle_create( "Intra_CTU" );
73
__itt_string_handle* itt_handle_inter  = __itt_string_handle_create( "Inter_CTU" );
74
__itt_string_handle* itt_handle_mider  = __itt_string_handle_create( "MI-Der_CTU" );
75
__itt_string_handle* itt_handle_lfcl   = __itt_string_handle_create( "Prep_ClearLF" );
76
__itt_string_handle* itt_handle_ext    = __itt_string_handle_create( "Prep_ExtBrdr" );
77
__itt_string_handle* itt_handle_dmvr   = __itt_string_handle_create( "MI-DMVR" );
78
__itt_string_handle* itt_handle_rsp    = __itt_string_handle_create( "Reshape_CTU" );
79
80
__itt_string_handle* itt_handle_parse  = __itt_string_handle_create( "Parse_Slice" );
81
82
__itt_string_handle* itt_handle_start  = __itt_string_handle_create( "Start_Pic" );
83
__itt_string_handle* itt_handle_done   = __itt_string_handle_create( "Pic_Done" );
84
__itt_string_handle* itt_handle_finish = __itt_string_handle_create( "Finish_Pic" );
85
86
__itt_string_handle* itt_handle_schedTasks = __itt_string_handle_create( "Scheduling_Tasks" );
87
__itt_string_handle* itt_handle_waitTasks  = __itt_string_handle_create( "Wait_for_Dec_Tasks" );
88
89
90
// create global domain for DecLib
91
__itt_domain* itt_domain_glb    = __itt_domain_create ( "Global" );
92
// create a global counter
93
__itt_counter itt_frame_counter = __itt_counter_create( "FrameNumber", "Global" );
94
95
#define ITT_TASKSTART( d, t ) __itt_task_begin( ( d ), __itt_null, __itt_null, ( t ) )
96
#define ITT_TASKEND( d, t )   __itt_task_end  ( ( d ) )
97
#else
98
#define ITT_TASKSTART( d, t )
99
#define ITT_TASKEND( d, t )
100
#endif
101
102
//! \ingroup DecoderLib
103
//! \{
104
105
DecLib::DecLib()
106
956
{
107
#ifdef TRACE_ENABLE_ITT
108
  itt_domain_dec->flags = 1;
109
  itt_domain_prs->flags = 1;
110
  itt_domain_glb->flags = 1;
111
  itt_domain_oth->flags = 1;
112
#endif
113
956
}
114
115
void DecLib::create( int numDecThreads, int parserFrameDelay, const UserAllocator& userAllocator, ErrHandlingFlags errHandlingFlags )
116
478
{
117
  // run constructor again to ensure all variables, especially in DecLibParser have been reset
118
478
  this->~DecLib();
119
478
  new( this ) DecLib;
120
121
478
  if( numDecThreads < 0 )
122
478
  {
123
478
    numDecThreads = std::thread::hardware_concurrency();
124
478
  }
125
126
478
  m_decodeThreadPool.reset( new ThreadPool( numDecThreads, "DecThread" ) );
127
128
478
  if( parserFrameDelay < 0 )
129
0
  {
130
0
    CHECK_FATAL( numDecThreads < 0, "invalid number of threads" );
131
0
    parserFrameDelay = std::min<int>( ( numDecThreads * DEFAULT_PARSE_DELAY_FACTOR ) >> 4, DEFAULT_PARSE_DELAY_MAX );
132
0
  }
133
478
  m_parseFrameDelay = parserFrameDelay;
134
135
478
  bool upscalingEnabled = false;
136
478
  m_picListManager.create( m_parseFrameDelay, (int) m_decLibRecon.size(), userAllocator );
137
478
  m_decLibParser.create  ( m_decodeThreadPool.get(), m_parseFrameDelay, (int) m_decLibRecon.size(), numDecThreads, errHandlingFlags );
138
139
478
  int id=0;
140
478
  for( auto &dec: m_decLibRecon )
141
956
  {
142
956
    dec.create( m_decodeThreadPool.get(), id++, upscalingEnabled );
143
956
  }
144
145
478
  std::stringstream cssCap;
146
478
  cssCap << "THREADS="     << numDecThreads << "; "
147
478
         << "PARSE_DELAY=" << parserFrameDelay << "; ";
148
478
#if ENABLE_SIMD_OPT
149
#  if defined( TARGET_SIMD_ARM )
150
  cssCap << "SIMD=" << read_arm_extension_name();
151
#  elif defined( TARGET_SIMD_X86 )
152
  cssCap << "SIMD=" << read_x86_extension_name();
153
#  else
154
478
  cssCap << "SIMD=SCALAR";
155
478
#  endif
156
#else
157
  cssCap << "SIMD=NONE";
158
#endif
159
160
478
  m_sDecoderCapabilities = cssCap.str();
161
162
478
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "final", 1 ) );
163
478
}
164
165
void DecLib::destroy()
166
478
{
167
478
  if( m_decodeThreadPool )
168
478
  {
169
478
    m_decodeThreadPool->shutdown( true );
170
478
    m_decodeThreadPool.reset();
171
478
  }
172
173
478
  m_decLibParser.destroy();
174
478
  for( auto &dec: m_decLibRecon )
175
956
  {
176
956
    dec.destroy();
177
956
  }
178
179
478
  m_picListManager.deleteBuffers();
180
478
}
181
182
Picture* DecLib::decode( InputNALUnit& nalu )
183
579
{
184
579
  PROFILER_SCOPE_AND_STAGE( 1, g_timeProfiler, P_NALU_SLICE_PIC_HL );
185
186
579
  bool newPic = false;
187
579
  if( m_iMaxTemporalLayer < 0 || nalu.m_temporalId <= m_iMaxTemporalLayer )
188
579
  {
189
579
    newPic = m_decLibParser.parse( nalu );
190
579
  }
191
192
579
  if( newPic )
193
0
  {
194
0
    Picture* pcParsedPic = m_decLibParser.getNextDecodablePicture();
195
196
0
    while( pcParsedPic && ( pcParsedPic->error || pcParsedPic->wasLost || pcParsedPic->parseDone.hasException() ) )
197
0
    {
198
0
      CHECK_FATAL( pcParsedPic->progress >= Picture::reconstructing, "The error picture shouldn't be in reconstructing state yet." );
199
200
0
      sanitizeBrokenPicture( pcParsedPic );
201
202
      // try again to get a picture, that we can reconstruct now
203
0
      pcParsedPic = m_decLibParser.getNextDecodablePicture();
204
0
    }
205
206
0
    if( pcParsedPic )
207
0
    {
208
0
      reconPicture( pcParsedPic );
209
0
    }
210
0
  }
211
212
579
  if( newPic || nalu.m_nalUnitType == NAL_UNIT_EOS )
213
4
  {
214
4
    Picture* outPic = getNextOutputPic( false );
215
4
    if( outPic )
216
0
    {
217
0
      CHECK_WARN( outPic->progress < Picture::finished, "Picture should have been finished by now. Blocking and finishing..." );
218
0
      if( outPic->progress < Picture::finished )
219
0
      {
220
0
        blockAndFinishPictures( outPic );
221
222
0
        CHECK( outPic->progress < Picture::finished, "Picture still not finished. Something is really broken." );
223
0
      }
224
225
0
      m_checkMissingOutput = true;
226
0
    }
227
228
    // warn if we don't produce an output picture for every incoming picture
229
4
    CHECK_WARN( m_checkMissingOutput && !outPic, "missing output picture" ); // this CHECK_FATAL is not needed in flushPic(), because in flushPic() the nullptr signals the end of the bitstream
230
4
    return outPic;
231
4
  }
232
233
575
  return nullptr;
234
579
}
235
236
Picture* DecLib::flushPic()
237
472
{
238
472
  Picture* outPic = nullptr;
239
472
  try
240
472
  {
241
472
    m_decLibParser.failIncompleteParsePic();   // no more slices are coming for the last picture
242
243
    // at end of file, fill the decompression queue and decode pictures until the next output-picture is finished
244
472
    while( Picture* pcParsedPic = m_decLibParser.getNextDecodablePicture() )
245
0
    {
246
0
      if( pcParsedPic->error || pcParsedPic->wasLost || pcParsedPic->parseDone.hasException() )
247
0
      {
248
0
        CHECK_FATAL( pcParsedPic->progress >= Picture::reconstructing, "The error picture shouldn't be in reconstructing state yet." );
249
250
0
        sanitizeBrokenPicture( pcParsedPic );
251
252
        // try again to get a picture, that we can reconstruct now
253
0
        continue;
254
0
      }
255
256
      // reconPicture() blocks and finishes one picture on each call
257
0
      reconPicture( pcParsedPic );
258
259
0
      if( !outPic )
260
0
      {
261
0
        outPic = getNextOutputPic( false );
262
0
      }
263
0
      if( outPic && outPic->progress == Picture::finished )
264
0
      {
265
0
        return outPic;
266
0
      }
267
0
    }
268
269
    // no more pictures to finish decoding, but we might still have finished pictures in the recon queue
270
472
    if( !outPic )
271
472
    {
272
472
      outPic = getNextOutputPic( false );
273
472
    }
274
472
    if( outPic && outPic->progress == Picture::finished )
275
0
    {
276
0
      return outPic;
277
0
    }
278
279
    // if all pictures have been parsed, but not finished, iteratively wait for and finish next pictures
280
472
    blockAndFinishPictures( outPic );
281
472
    if( !outPic )
282
472
    {
283
472
      outPic = getNextOutputPic( false );
284
472
    }
285
472
    if( outPic && outPic->progress == Picture::finished )
286
0
    {
287
0
      return outPic;
288
0
    }
289
290
472
    CHECK( outPic, "we shouldn't be holding an output picture here" );
291
    // flush remaining pictures without considering num reorder pics
292
472
    outPic = getNextOutputPic( true );
293
472
    if( outPic )
294
0
    {
295
0
      CHECK( outPic->progress != Picture::finished, "all pictures should have been finished by now" );
296
      // outPic->referenced = false;
297
0
      return outPic;
298
0
    }
299
472
  }
300
472
  catch( ... )
301
472
  {
302
0
    m_picListManager.releasePicture( outPic );
303
0
    throw;
304
0
  }
305
306
  // At the very end reset parser state
307
472
  InputNALUnit eosNAL;
308
472
  eosNAL.m_nalUnitType = NAL_UNIT_EOS;
309
472
  m_decLibParser.parse( eosNAL );
310
472
  m_checkMissingOutput = false;
311
312
472
  return nullptr;
313
472
}
314
315
void DecLib::sanitizeBrokenPicture( Picture* pcParsedPic )
316
0
{
317
0
  std::exception_ptr parsing_exception = pcParsedPic->parseDone.hasException() ? pcParsedPic->parseDone.getException() : nullptr;
318
0
  if( parsing_exception )
319
0
  {   // the exception has not been thrown out of the library. Do that after preparing this picture for referencing
320
0
    pcParsedPic->error = true;
321
0
    pcParsedPic->waitForAllTasks();
322
0
    pcParsedPic->parseDone.clearException();
323
0
  }
324
325
0
  pcParsedPic->waitForAllTasks();
326
327
0
  if( pcParsedPic->progress < Picture::parsing )
328
0
  {
329
    // we don't know if all structures are there yet, so we init them
330
0
    pcParsedPic->ensureUsableAsRef();
331
0
  }
332
0
  pcParsedPic->fillGrey( m_decLibParser.getParameterSetManager().getFirstSPS() );
333
334
  // need to finish picture here, because it won't go through declibRecon
335
0
  finishPicture( pcParsedPic );
336
337
  // this exception has not been thrown outside (error must have happened in slice parsing task)
338
0
  if( parsing_exception )
339
0
  {
340
0
    CHECK_FATAL( pcParsedPic->exceptionThrownOut, "The exception shouldn't have been thrown out already." );
341
0
    pcParsedPic->exceptionThrownOut = true;
342
0
    std::rethrow_exception( parsing_exception );
343
0
  }
344
0
}
345
346
#if JVET_R0270
347
int DecLib::finishPicture( Picture* pcPic, MsgLevel msgl, bool associatedWithNewClvs )
348
#else
349
int DecLib::finishPicture( Picture* pcPic, MsgLevel msgl )
350
#endif
351
0
{
352
#ifdef TRACE_ENABLE_ITT
353
  // increment Framecounter
354
  __itt_counter_inc( itt_frame_counter );
355
#endif
356
357
0
  Slice*  pcSlice = pcPic->slices[0];
358
0
  if( pcPic->wasLost || pcPic->error || pcPic->reconDone.hasException() || pcPic->parseDone.hasException() )
359
0
  {
360
0
    msg( msgl, "POC %4d LId: %2d TId: %1d %s\n", pcPic->poc, pcPic->layerId, pcSlice->getTLayer(), pcPic->wasLost ? "LOST" : "ERROR" );
361
0
    pcPic->fillGrey( pcPic->cs->sps.get() );
362
0
    pcPic->progress = Picture::finished;
363
364
    // if the picture has an exception set (originating from thread-pool tasks), don't return here, but rethrow the exception
365
0
    try
366
0
    {
367
0
      pcPic->parseDone.checkAndRethrowException();
368
0
      pcPic->reconDone.checkAndRethrowException();
369
0
    }
370
0
    catch( ... )
371
0
    {
372
0
      pcPic->waitForAllTasks();
373
374
      // need to clear exception so we can use it as reference picture
375
0
      pcPic->reconDone.clearException();
376
0
      pcPic->reconDone.unlock();
377
0
      pcPic->error = true;
378
0
      if( !pcPic->exceptionThrownOut )
379
0
      {
380
0
        pcPic->exceptionThrownOut = true;
381
0
        throw;
382
0
      }
383
0
    }
384
385
0
    return pcPic->poc;
386
0
  }
387
388
0
  ITT_TASKSTART( itt_domain_oth, itt_handle_finish );
389
390
0
  char c = ( pcSlice->isIntra() ? 'I' : pcSlice->isInterP() ? 'P' : 'B' );
391
0
  if( !pcPic->isReferencePic )
392
0
  {
393
0
    c += 32;  // tolower
394
0
  }
395
396
  //-- For time output for each slice
397
0
  msg( msgl, "POC %4d LId: %2d TId: %1d ( %c-SLICE, QP%3d ) ", pcPic->poc, pcPic->layerId,
398
0
         pcSlice->getTLayer(),
399
0
         c,
400
0
         pcSlice->getSliceQp() );
401
0
  msg( msgl, "[DT %6.3f] ", pcPic->getProcessingTime() );
402
403
0
  for (int iRefList = 0; iRefList < 2; iRefList++)
404
0
  {
405
0
    msg( msgl, "[L%d ", iRefList);
406
0
    for (int iRefIndex = 0; iRefIndex < pcSlice->getNumRefIdx(RefPicList(iRefList)); iRefIndex++)
407
0
    {
408
0
#if RPR_OUTPUT_MSG
409
0
      const std::pair<int, int>& scaleRatio = pcSlice->getScalingRatio( RefPicList( iRefList ), iRefIndex );
410
      
411
0
      if( pcSlice->getPicHeader()->getEnableTMVPFlag() && pcSlice->getColFromL0Flag() == bool(1 - iRefList) && pcSlice->getColRefIdx() == iRefIndex )
412
0
      {
413
0
        if( scaleRatio.first != 1 << SCALE_RATIO_BITS || scaleRatio.second != 1 << SCALE_RATIO_BITS )
414
0
        {
415
0
          msg( msgl, "%dc(%1.2lfx, %1.2lfx) ", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ), double( scaleRatio.first ) / ( 1 << SCALE_RATIO_BITS ), double( scaleRatio.second ) / ( 1 << SCALE_RATIO_BITS ) );
416
0
        }
417
0
        else
418
0
        {
419
0
          msg( msgl, "%dc ", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ) );
420
0
        }
421
0
      }
422
0
      else
423
0
      {
424
0
        if( scaleRatio.first != 1 << SCALE_RATIO_BITS || scaleRatio.second != 1 << SCALE_RATIO_BITS )
425
0
        {
426
0
          msg( msgl, "%d(%1.2lfx, %1.2lfx) ", pcSlice->getRefPOC( RefPicList( iRefList ), iRefIndex ), double( scaleRatio.first ) / ( 1 << SCALE_RATIO_BITS ), double( scaleRatio.second ) / ( 1 << SCALE_RATIO_BITS ) );
427
0
        }
428
0
        else
429
0
        {
430
0
      msg( msgl, "%d ", pcSlice->getRefPOC(RefPicList(iRefList), iRefIndex));
431
0
    }
432
0
      }
433
#else
434
      msg( msgl, "%d ", pcSlice->getRefPOC(RefPicList(iRefList), iRefIndex));
435
#endif
436
0
    }
437
0
    msg( msgl, "] ");
438
0
  }
439
440
0
  msg( msgl, "\n");
441
442
//  pcPic->neededForOutput = (pcSlice->getPicHeader()->getPicOutputFlag() ? true : false);
443
#if JVET_R0270
444
  if (associatedWithNewClvs && pcPic->neededForOutput)
445
  {
446
    if (!pcSlice->getPPS()->getMixedNaluTypesInPicFlag() && pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RASL)
447
    {
448
      pcPic->neededForOutput = false;
449
    }
450
    else if (pcSlice->getPPS()->getMixedNaluTypesInPicFlag())
451
    {
452
      bool isRaslPic = true;
453
      for (int i = 0; isRaslPic && i < pcPic->numSlices; i++)
454
      {
455
        if (!(pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RASL || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RADL))
456
        {
457
          isRaslPic = false;
458
        }
459
      }
460
      if (isRaslPic)
461
      {
462
        pcPic->neededForOutput = false;
463
      }
464
    }
465
  }
466
#endif
467
468
0
  m_picListManager.markUnusedPicturesReusable();
469
470
0
  if( m_parseFrameDelay > 0 )
471
0
  {
472
0
    checkPictureHashSEI( pcPic );
473
0
  }
474
475
0
  ITT_TASKEND( itt_domain_oth, itt_handle_finish );
476
477
0
  pcPic->progress = Picture::finished;
478
479
0
  return pcSlice->getPOC();
480
0
}
481
482
void DecLib::checkPictureHashSEI( Picture* pcPic )
483
0
{
484
0
  if( !m_decodedPictureHashSEIEnabled )
485
0
  {
486
0
    return;
487
0
  }
488
0
  if( !pcPic->neededForOutput || pcPic->picCheckedDPH )
489
0
  {
490
0
    return;
491
0
  }
492
493
0
  CHECK( pcPic->progress < Picture::reconstructed, "picture not reconstructed" );
494
495
0
  seiMessages pictureHashes = SEI_internal::getSeisByType( pcPic->seiMessageList, VVDEC_DECODED_PICTURE_HASH );
496
0
  if( !pictureHashes.empty() )
497
0
  {
498
0
    if( pictureHashes.size() > 1 )
499
0
    {
500
0
      msg( WARNING, "Warning: Got multiple decoded picture hash SEI messages. Using first." );
501
0
    }
502
503
0
    const vvdecSEIDecodedPictureHash* hash = (vvdecSEIDecodedPictureHash*)pictureHashes.front()->payload;
504
505
0
    msg( INFO, "         " );
506
0
    const int hashErrors              = calcAndPrintHashStatus( pcPic->getRecoBuf(), hash, pcPic->cs->sps->getBitDepths(), INFO );
507
0
    m_numberOfChecksumErrorsDetected += hashErrors;
508
0
    pcPic->dphMismatch                = !!hashErrors;
509
0
    pcPic->picCheckedDPH              = true;
510
0
    msg( INFO, "\n" );
511
0
  }
512
0
  else
513
0
  {
514
0
    if( pcPic->subPictures.empty() )
515
0
    {
516
0
      msg( WARNING, "Warning: missing decoded picture hash SEI message.\n" );
517
0
      return;
518
0
    }
519
520
0
    seiMessages scalableNestingSeis = SEI_internal::getSeisByType( pcPic->seiMessageList, VVDEC_SCALABLE_NESTING );
521
0
    for( auto* seiIt: scalableNestingSeis )
522
0
    {
523
0
      CHECK( seiIt->payloadType != VVDEC_SCALABLE_NESTING, "expected nesting SEI" );
524
525
0
      const vvdecSEIScalableNesting* nestingSei = (vvdecSEIScalableNesting*) seiIt->payload;
526
0
      if( !nestingSei->snSubpicFlag )
527
0
      {
528
0
        continue;
529
0
      }
530
531
0
      for( int i = 0; i < nestingSei->snNumSEIs; ++i )
532
0
      {
533
0
        auto& nestedSei = nestingSei->nestedSEIs[i];
534
0
        CHECK( nestedSei == nullptr, "missing nested sei" );
535
0
        if( nestedSei && nestedSei->payloadType != VVDEC_DECODED_PICTURE_HASH )
536
0
          continue;
537
538
0
        const vvdecSEIDecodedPictureHash* hash = (vvdecSEIDecodedPictureHash*) nestedSei->payload;
539
540
0
        if( pcPic->subpicsCheckedDPH.empty() )
541
0
        {
542
0
          pcPic->subpicsCheckedDPH.resize( pcPic->subPictures.size(), false );
543
0
        }
544
0
        else
545
0
        {
546
0
          CHECK( pcPic->subpicsCheckedDPH.size() != pcPic->subPictures.size(), "Picture::subpicsCheckedDPH not properly initialized" );
547
0
        }
548
549
0
        for( int j = 0; j < nestingSei->snNumSubpics; ++j )
550
0
        {
551
0
          uint32_t subpicId = nestingSei->snSubpicId[j];
552
553
0
          for( auto& subPic: pcPic->subPictures )
554
0
          {
555
0
            if( subPic.getSubPicID() != subpicId )
556
0
              continue;
557
558
0
            auto subPicIdx = subPic.getSubPicIdx();
559
0
            if( pcPic->subpicsCheckedDPH[subPicIdx] )
560
0
              continue;
561
562
0
            const UnitArea area                 = UnitArea( pcPic->chromaFormat, subPic.getLumaArea() );
563
0
            const int      hashErrors           = calcAndPrintHashStatus( pcPic->cs->getRecoBuf( area ), hash, pcPic->cs->sps->getBitDepths(), INFO );
564
0
            m_numberOfChecksumErrorsDetected   += hashErrors;
565
0
            pcPic->dphMismatch                 |= !!hashErrors;
566
0
            pcPic->subpicsCheckedDPH[subPicIdx] = true;
567
0
            msg( INFO, "\n" );
568
0
          }
569
0
        }
570
0
      }
571
0
    }
572
573
0
    size_t checkedSubpicCount = std::count( pcPic->subpicsCheckedDPH.cbegin(), pcPic->subpicsCheckedDPH.cend(), true );
574
0
    pcPic->picCheckedDPH      = ( checkedSubpicCount == pcPic->subPictures.size() );   // mark when all subpics have been checked
575
576
0
    if( m_parseFrameDelay )
577
0
    {
578
      // this warning is only enabled, when running with parse delay enabled, because otherwise we don't know here if the last DPH Suffix-SEI has already been
579
      // parsed
580
0
      if( checkedSubpicCount != pcPic->subPictures.size() )
581
0
      {
582
0
        msg( WARNING, "Warning: missing decoded picture hash SEI message for SubPics (%u/%u).\n", checkedSubpicCount, pcPic->subPictures.size() );
583
0
      }
584
0
    }
585
0
  }
586
0
}
587
588
Picture* DecLib::getNextOutputPic( bool bFlush )
589
1.42k
{
590
1.42k
  if( m_picListManager.getFrontPic() == nullptr )
591
1.42k
  {
592
1.42k
    return nullptr;
593
1.42k
  }
594
595
0
  const SPS* activeSPS      = m_picListManager.getFrontPic()->cs->sps.get();
596
0
  const int  maxNrSublayers = activeSPS->getMaxTLayers();
597
598
0
  int numReorderPicsHighestTid;
599
0
  int maxDecPicBufferingHighestTid;
600
0
  if( m_iMaxTemporalLayer == -1 || m_iMaxTemporalLayer >= maxNrSublayers )
601
0
  {
602
0
    numReorderPicsHighestTid     = activeSPS->getNumReorderPics( maxNrSublayers - 1 );
603
0
    maxDecPicBufferingHighestTid = activeSPS->getMaxDecPicBuffering( maxNrSublayers - 1 );
604
0
  }
605
0
  else
606
0
  {
607
0
    numReorderPicsHighestTid     = activeSPS->getNumReorderPics( m_iMaxTemporalLayer );
608
0
    maxDecPicBufferingHighestTid = activeSPS->getMaxDecPicBuffering( m_iMaxTemporalLayer );
609
0
  }
610
611
0
  return m_picListManager.getNextOutputPic( numReorderPicsHighestTid, maxDecPicBufferingHighestTid, bFlush );
612
1.42k
}
613
614
void DecLib::reconPicture( Picture* pcPic )
615
0
{
616
0
  CHECK_FATAL( std::any_of( m_decLibRecon.begin(), m_decLibRecon.end(), [=]( auto& rec ) { return rec.getCurrPic() == pcPic; } ),
617
0
         "(Reused) Picture structure is still in progress in decLibRecon." );
618
619
0
  DecLibRecon* reconInstance = &m_decLibRecon.front();
620
0
  move_to_end( m_decLibRecon.begin(), m_decLibRecon );
621
622
0
  Picture* donePic = reconInstance->waitForPrevDecompressedPic();
623
0
  try
624
0
  {
625
0
    reconInstance->decompressPicture( pcPic );
626
0
  }
627
0
  catch( ... )
628
0
  {
629
0
    pcPic->reconDone.setException( std::current_exception() );
630
0
    pcPic->error = true;
631
0
  }
632
633
0
  if( donePic )
634
0
  {
635
0
    finishPicture( donePic );
636
0
  }
637
0
}
638
639
void DecLib::blockAndFinishPictures( Picture* pcPic )
640
472
{
641
  // find Recon instance where current picture (if not null) is active and ensure the picture gets finished
642
  // otherwise all pictures get finished
643
472
  for( auto& recon: m_decLibRecon )
644
944
  {
645
944
    if( pcPic && recon.getCurrPic() != pcPic )
646
0
    {
647
0
      continue;
648
0
    }
649
650
944
    if( Picture* donePic = recon.waitForPrevDecompressedPic() )
651
0
    {
652
0
      finishPicture( donePic );
653
0
    }
654
944
  }
655
472
}
656
657
void DecLib::checkNalUnitConstraints( uint32_t naluType )
658
0
{
659
0
  const ConstraintInfo *cInfo = NULL;
660
0
  if (m_decLibParser.getParameterSetManager().getActiveSPS() != NULL && m_decLibParser.getParameterSetManager().getActiveSPS()->getProfileTierLevel() != NULL)
661
0
  {
662
0
    cInfo = m_decLibParser.getParameterSetManager().getActiveSPS()->getProfileTierLevel()->getConstraintInfo();
663
0
    if( cInfo != NULL )
664
0
    {
665
0
      xCheckNalUnitConstraintFlags( cInfo, naluType );
666
0
    }
667
0
  }
668
0
}
669
670
void DecLib::xCheckNalUnitConstraintFlags( const ConstraintInfo *cInfo, uint32_t naluType )
671
0
{
672
0
  if( cInfo != NULL )
673
0
  {
674
0
    CHECK( cInfo->getNoTrailConstraintFlag() && naluType == NAL_UNIT_CODED_SLICE_TRAIL,
675
0
           "Non-conforming bitstream. no_trail_constraint_flag is equal to 1 but bitstream contains NAL unit of type TRAIL_NUT." );
676
0
    CHECK( cInfo->getNoStsaConstraintFlag()  && naluType == NAL_UNIT_CODED_SLICE_STSA,
677
0
           "Non-conforming bitstream. no_stsa_constraint_flag is equal to 1 but bitstream contains NAL unit of type STSA_NUT." );
678
0
    CHECK( cInfo->getNoRaslConstraintFlag()  && naluType == NAL_UNIT_CODED_SLICE_RASL,
679
0
           "Non-conforming bitstream. no_rasl_constraint_flag is equal to 1 but bitstream contains NAL unit of type RASL_NUT." );
680
0
    CHECK( cInfo->getNoRadlConstraintFlag()  && naluType == NAL_UNIT_CODED_SLICE_RADL,
681
0
           "Non-conforming bitstream. no_radl_constraint_flag is equal to 1 but bitstream contains NAL unit of type RADL_NUT." );
682
0
    CHECK( cInfo->getNoIdrConstraintFlag()   && naluType == NAL_UNIT_CODED_SLICE_IDR_W_RADL,
683
0
           "Non-conforming bitstream. no_idr_constraint_flag is equal to 1 but bitstream contains NAL unit of type IDR_W_RADL." );
684
0
    CHECK( cInfo->getNoIdrConstraintFlag()   && naluType == NAL_UNIT_CODED_SLICE_IDR_N_LP,
685
0
           "Non-conforming bitstream. no_idr_constraint_flag is equal to 1 but bitstream contains NAL unit of type IDR_N_LP." );
686
0
    CHECK( cInfo->getNoCraConstraintFlag()   && naluType == NAL_UNIT_CODED_SLICE_CRA,
687
0
           "Non-conforming bitstream. no_cra_constraint_flag is equal to 1 but bitstream contains NAL unit of type CRA_NUT." );
688
0
    CHECK( cInfo->getNoGdrConstraintFlag()   && naluType == NAL_UNIT_CODED_SLICE_GDR,
689
0
           "Non-conforming bitstream. no_gdr_constraint_flag is equal to 1 but bitstream contains NAL unit of type GDR_NUT." );
690
0
    CHECK( cInfo->getNoApsConstraintFlag()   && naluType == NAL_UNIT_PREFIX_APS,
691
0
           "Non-conforming bitstream. no_aps_constraint_flag is equal to 1 but bitstream contains NAL unit of type APS_PREFIX_NUT." );
692
0
    CHECK( cInfo->getNoApsConstraintFlag()   && naluType == NAL_UNIT_SUFFIX_APS,
693
0
           "Non-conforming bitstream. no_aps_constraint_flag is equal to 1 but bitstream contains NAL unit of type APS_SUFFIX_NUT." );
694
0
  }
695
0
}
696
697
}