Coverage Report

Created: 2026-10-17 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvdec/source/Lib/DecoderLib/DecLibParser.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 "DecLib.h"
44
#include "DecLibParser.h"
45
#include "NALread.h"
46
47
#include "CommonLib/dtrace_next.h"
48
49
#include "UnitTools.h"
50
#include "Utilities/ThreadPool.h"
51
52
#include <unordered_map>
53
#include <utility>
54
55
namespace vvdec
56
{
57
template<class TArr, class TElem = decltype( std::declval<TArr>()[0] )>
58
void fill_array( TArr& array, const TElem& val )
59
756
{
60
756
  std::fill( std::begin( array ), std::end( array ), val );
61
756
}
void vvdec::fill_array<vvdec::NalUnitType [64], vvdec::NalUnitType>(vvdec::NalUnitType (&) [64], vvdec::NalUnitType const&)
Line
Count
Source
59
189
{
60
189
  std::fill( std::begin( array ), std::end( array ), val );
61
189
}
void vvdec::fill_array<int [64], int>(int (&) [64], int const&)
Line
Count
Source
59
378
{
60
378
  std::fill( std::begin( array ), std::end( array ), val );
61
378
}
void vvdec::fill_array<bool [64], bool>(bool (&) [64], bool const&)
Line
Count
Source
59
189
{
60
189
  std::fill( std::begin( array ), std::end( array ), val );
61
189
}
62
63
#ifdef TRACE_ENABLE_ITT
64
extern __itt_domain* itt_domain_prs;
65
extern __itt_domain* itt_domain_oth;
66
67
extern __itt_string_handle* itt_handle_parse;
68
extern __itt_string_handle* itt_handle_start;
69
70
#define ITT_TASKSTART( d, t ) __itt_task_begin( ( d ), __itt_null, __itt_null, ( t ) )
71
#define ITT_TASKEND( d, t )   __itt_task_end  ( ( d ) )
72
#else
73
#define ITT_TASKSTART( d, t )
74
#define ITT_TASKEND( d, t )
75
#endif
76
77
static const int INIT_POC = -MAX_INT;
78
79
DecLibParser::~DecLibParser()
80
378
{
81
378
  m_prefixSEINALUs.clear();
82
83
378
  destroy();
84
378
}
85
86
void DecLibParser::create( ThreadPool* tp, int parserFrameDelay, int numReconInst, int numDecThreads, ErrHandlingFlags errHandlingFlags )
87
189
{
88
189
  m_threadPool        = tp;
89
189
  m_parseFrameDelay   = parserFrameDelay;
90
189
  m_numDecThreads     = numDecThreads;
91
189
  m_maxPicReconSkip   = numReconInst - 1;
92
189
  m_errHandlingFlags  = errHandlingFlags;
93
94
189
  m_apcSlicePilot     = new Slice;
95
189
  m_uiSliceSegmentIdx = 0;
96
97
189
  fill_array( m_associatedIRAPType,     NAL_UNIT_INVALID );
98
189
  fill_array( m_pocCRA,                 INIT_POC );
99
189
  fill_array( m_gdrRecoveryPointPocVal, INIT_POC );
100
189
  fill_array( m_gdrRecovered,           false );
101
102
189
  m_cSliceDecoder.setContextStateVec( numDecThreads );
103
189
}
104
105
void DecLibParser::destroy()
106
567
{
107
567
  SEI_internal::deleteSEIs( m_seiMessageList );
108
109
567
  m_threadPool    = nullptr;
110
111
567
  delete m_apcSlicePilot;
112
567
  m_apcSlicePilot = nullptr;
113
  
114
567
  m_picHeader.reset();
115
  
116
567
  m_cSliceDecoder.destroy();
117
  
118
567
  if( m_dci )
119
3
  {
120
3
    delete m_dci;
121
3
    m_dci = NULL;
122
3
  }
123
567
}
124
125
bool DecLibParser::parse( InputNALUnit& nalu )
126
356
{
127
356
  if( !nalu.isVcl() )
128
339
  {
129
339
    if( nalu.m_nalUnitType == NAL_UNIT_SUFFIX_APS || nalu.m_nalUnitType == NAL_UNIT_SUFFIX_SEI )
130
41
    {
131
41
      if( m_pcParsePic )
132
0
      {
133
0
        m_pcParsePic->bits += nalu.m_bits;
134
0
      }
135
41
    }
136
298
    else
137
298
    {
138
298
      m_nonVCLbits += nalu.m_bits;
139
298
    }
140
339
  }
141
142
356
  GCC_EXTRA_WARNING_switch_enum;
143
356
  switch( nalu.m_nalUnitType )
144
356
  {
145
4
  case NAL_UNIT_CODED_SLICE_TRAIL:
146
5
  case NAL_UNIT_CODED_SLICE_STSA:
147
5
  case NAL_UNIT_CODED_SLICE_RADL:
148
6
  case NAL_UNIT_CODED_SLICE_RASL:
149
6
  case NAL_UNIT_CODED_SLICE_IDR_W_RADL:
150
6
  case NAL_UNIT_CODED_SLICE_IDR_N_LP:
151
6
  case NAL_UNIT_CODED_SLICE_CRA:
152
6
  case NAL_UNIT_CODED_SLICE_GDR:
153
6
    try
154
6
    {
155
6
      if( !xDecodeSliceHead( nalu ) )
156
0
      {
157
0
        return false;
158
0
      }
159
6
      if( !xDecodeSliceMain( nalu ) || m_parseFrameList.size() <= m_parseFrameDelay )
160
0
      {
161
0
        return false;
162
0
      }
163
6
      return true;
164
6
    }
165
6
    catch( ... )
166
6
    {
167
6
      if( m_pcParsePic )
168
0
      {
169
0
        m_pcParsePic->error              = true;
170
0
        m_pcParsePic->exceptionThrownOut = true;
171
0
        if( m_pcParsePic->parseDone.hasException() )   // this happens only in the single-threaded case.
172
0
        {                                              // multithreaded mode should see exceptions from the parse tasks later
173
0
          m_pcParsePic->parseDone.clearException();
174
0
        }
175
0
      }
176
177
6
      std::rethrow_exception( std::current_exception() );
178
6
    }
179
180
1
  case NAL_UNIT_OPI:
181
    // NOT IMPLEMENTED
182
1
    return false;
183
184
5
  case NAL_UNIT_DCI:
185
5
    xDecodeDCI( nalu );
186
5
    return false;
187
188
2
  case NAL_UNIT_VPS:
189
2
    xDecodeVPS( nalu );
190
    // m_vps->m_iTargetLayer = iTargetOlsIdx;
191
2
    return false;
192
193
80
  case NAL_UNIT_SPS:
194
80
    xDecodeSPS( nalu );
195
80
    return false;
196
197
3
  case NAL_UNIT_PPS:
198
3
    xDecodePPS( nalu );
199
3
    return false;
200
201
3
  case NAL_UNIT_PREFIX_APS:
202
43
  case NAL_UNIT_SUFFIX_APS:
203
43
    xDecodeAPS( nalu );
204
43
    return false;
205
206
1
  case NAL_UNIT_PH:
207
1
    xDecodePicHeader( nalu );
208
1
    return false;
209
210
2
  case NAL_UNIT_ACCESS_UNIT_DELIMITER:
211
2
  {
212
2
    AUDReader audReader;
213
2
    uint32_t  picType;
214
2
    audReader.parseAccessUnitDelimiter( &( nalu.getBitstream() ), picType );
215
2
    msg( VERBOSE, "Found NAL_UNIT_ACCESS_UNIT_DELIMITER\n" );
216
2
    return false;
217
3
  }
218
219
189
  case NAL_UNIT_EOS:
220
189
    m_associatedIRAPType[nalu.m_nuhLayerId]     = NAL_UNIT_INVALID;
221
189
    m_pocCRA[nalu.m_nuhLayerId]                 = INIT_POC;
222
189
    m_gdrRecoveryPointPocVal[nalu.m_nuhLayerId] = INIT_POC;
223
189
    m_gdrRecovered[nalu.m_nuhLayerId]           = false;
224
189
    m_pocRandomAccess                           = MAX_INT;
225
189
    m_prevPOC                                   = MAX_INT;
226
189
    m_prevSliceSkipped                          = false;
227
189
    m_skippedPOC                                = 0;
228
189
    m_bFirstSliceInSequence[nalu.m_nuhLayerId]  = true;
229
189
    m_bFirstSliceInPicture                      = true;
230
189
    m_picListManager.restart();
231
189
    return false;
232
233
1
  case NAL_UNIT_EOB:
234
1
    return false;
235
236
2
  case NAL_UNIT_PREFIX_SEI:
237
    // Buffer up prefix SEI messages until SPS of associated VCL is known.
238
2
    m_prefixSEINALUs.emplace_back( nalu );
239
2
    m_pictureSeiNalus.emplace_back( std::move( nalu ) );
240
2
    return false;
241
242
1
  case NAL_UNIT_SUFFIX_SEI:
243
1
    if( m_pcParsePic /*&& !m_pcParsePic->wasLost*/ )
244
0
    {
245
0
      m_pictureSeiNalus.emplace_back( nalu );
246
0
      const SPS* sps = m_parameterSetManager.getActiveSPS();
247
0
      const VPS* vps = m_parameterSetManager.getVPS( sps->getVPSId() );
248
0
      m_seiReader.parseSEImessage( &( nalu.getBitstream() ), m_pcParsePic->seiMessageList, nalu.m_nalUnitType, nalu.m_nuhLayerId, nalu.m_temporalId, vps, sps, m_HRD, m_pDecodedSEIOutputStream );
249
250
0
      if( m_parseFrameDelay == 0 && !m_pcParsePic->error )   // if m_parseFrameDelay > 0, it has to be done in finishPicture()
251
0
      {
252
        // if parallel parsing is disabled, wait for the picture to finish
253
0
        if( m_threadPool->numThreads() == 0 )
254
0
        {
255
0
          m_threadPool->processTasksOnMainThread();
256
0
        }
257
0
        else
258
0
        {
259
0
          m_pcParsePic->reconDone.wait();
260
0
        }
261
0
        m_decLib.checkPictureHashSEI( m_pcParsePic );
262
0
      }
263
0
    }
264
1
    else
265
1
    {
266
1
      msg( NOTICE, "Received suffix SEI but no picture currently active.\n" );
267
1
    }
268
1
    return false;
269
270
0
  case NAL_UNIT_FD:
271
0
    return false;
272
273
4
  case NAL_UNIT_RESERVED_VCL_4:
274
6
  case NAL_UNIT_RESERVED_VCL_5:
275
11
  case NAL_UNIT_RESERVED_VCL_6:
276
11
  case NAL_UNIT_RESERVED_IRAP_VCL_11:
277
11
    msg( NOTICE, "Found reserved VCL NAL unit.\n" );
278
11
    xParsePrefixSEIsForUnknownVCLNal();
279
11
    return false;
280
1
  case NAL_UNIT_RESERVED_NVCL_26:
281
2
  case NAL_UNIT_RESERVED_NVCL_27:
282
2
    msg( NOTICE, "Found reserved NAL unit.\n" );
283
2
    return false;
284
0
  case NAL_UNIT_UNSPECIFIED_28:
285
1
  case NAL_UNIT_UNSPECIFIED_29:
286
2
  case NAL_UNIT_UNSPECIFIED_30:
287
7
  case NAL_UNIT_UNSPECIFIED_31:
288
7
    msg( NOTICE, "Found unspecified NAL unit.\n" );
289
7
    return false;
290
0
  case NAL_UNIT_INVALID:
291
0
  default:
292
0
    THROW_RECOVERABLE( "Invalid NAL unit type" );
293
0
    break;
294
356
  }
295
0
  GCC_WARNING_RESET;
296
297
0
  return false;
298
356
}
299
300
void DecLibParser::failIncompleteParsePic()
301
188
{
302
188
  if( !m_pcParsePic || m_pcParsePic->lastSliceOfPicPresent() )
303
188
  {
304
188
    return;
305
188
  }
306
307
  // reconstruction can already be waiting for CTUs, that will never be parsed, so the picture needs to be failed explicitly
308
0
  m_pcParsePic->setParseError( std::make_exception_ptr( RecoverableException( "the slices of the picture don't cover all CTUs" ) ) );
309
0
  m_pcParsePic = nullptr;
310
0
}
311
312
Picture* DecLibParser::getNextDecodablePicture()
313
188
{
314
188
  if( m_parseFrameList.empty() )
315
188
  {
316
188
    return nullptr;
317
188
  }
318
319
0
  if( m_threadPool->numThreads() == 0 || m_parseFrameDelay == 0 )
320
0
  {
321
    // adhere to strict decoding order if running singlethreaded
322
0
    Picture * pic = m_parseFrameList.front();
323
0
    m_parseFrameList.pop_front();
324
0
    return pic;
325
0
  }
326
327
0
  if( m_parseFrameList.front()->skippedDecCount >= MAX_OUT_OF_ORDER_PICS || m_parseFrameList.front()->error )
328
0
  {
329
0
    Picture* pic = m_parseFrameList.front();
330
0
    m_parseFrameList.pop_front();
331
0
    return pic;
332
0
  }
333
334
  // try to find next picture, that is parsed and has all reference pictures decoded
335
0
  for( auto picIt = m_parseFrameList.begin(); picIt != m_parseFrameList.end(); ++picIt )
336
0
  {
337
0
    Picture* pic = *picIt;
338
339
0
    if( pic->parseDone.getState() != Barrier::unlocked )   // this doesn't throw if the barrier has an exception set
340
0
      continue;
341
342
0
    if( pic->wasLost || pic->error )
343
0
      continue;
344
345
0
    bool allRefPicsDone = true;
346
0
    for( const Slice* slice: pic->slices )
347
0
    {
348
0
      if( slice->isIntra() )
349
0
      {
350
0
        continue;
351
0
      }
352
0
      for( int iDir = REF_PIC_LIST_0; iDir < NUM_REF_PIC_LIST_01 && allRefPicsDone; ++iDir )
353
0
      {
354
0
        for( int iRefIdx = 0; iRefIdx < slice->getNumRefIdx( (RefPicList) iDir ) && allRefPicsDone; iRefIdx++ )
355
0
        {
356
0
          const Picture* refPic = slice->getRefPic( (RefPicList) iDir, iRefIdx );
357
0
          if( refPic->progress < Picture::reconstructed )
358
0
          {
359
0
            allRefPicsDone = false;
360
0
            break;
361
0
          }
362
0
        }
363
0
      }
364
0
    }
365
366
0
    if( allRefPicsDone )
367
0
    {
368
      // increase skip count for all previous pictures
369
0
      for( auto& skipped: PicListRange{ m_parseFrameList.begin(), picIt } )
370
0
      {
371
0
        skipped->skippedDecCount++;
372
0
      }
373
374
0
      m_parseFrameList.erase( picIt );
375
0
      return pic;
376
0
    }
377
378
//    if( pic->getTLayer() < m_parseFrameList.front()->getTLayer() )
379
//    {
380
//      break;
381
//    }
382
0
  }
383
384
  // if no picture has all reference-pictures decoded, use next pic in (regular) decoding order.
385
0
  Picture * pic = m_parseFrameList.front();
386
0
  m_parseFrameList.pop_front();
387
0
  return pic;
388
0
}
389
390
void DecLibParser::checkAPSInPictureUnit()
391
0
{
392
0
  bool firstVCLFound  = false;
393
0
  bool suffixAPSFound = false;
394
395
0
  for( auto &nalu : m_pictureUnitNals )
396
0
  {
397
0
    if( NALUnit::isVclNalUnitType(nalu) )
398
0
    {
399
0
      firstVCLFound = true;
400
0
      CHECK( suffixAPSFound, "When any suffix APS NAL units are present in a PU, they shall follow the last VCL unit of the PU" );
401
0
    }
402
0
    else if( nalu == NAL_UNIT_PREFIX_APS )
403
0
    {
404
0
      CHECK( firstVCLFound, "When any prefix APS NAL units are present in a PU, they shall precede the first VCL unit of the PU");
405
0
    }
406
0
    else if( nalu == NAL_UNIT_SUFFIX_APS )
407
0
    {
408
0
      suffixAPSFound = true;
409
0
    }
410
0
  }
411
0
}
412
413
bool DecLibParser::xDecodeSliceHead( InputNALUnit& nalu )
414
6
{
415
  // all slices for the previous picture have been parsed
416
6
  if( m_pcParsePic && m_pcParsePic->lastSliceOfPicPresent() )
417
0
  {
418
0
    m_pcParsePic = nullptr;
419
0
  }
420
421
6
  m_apcSlicePilot->initSlice(); // the slice pilot is an object to prepare for a new slice
422
                                // it is not associated with picture, sps or pps structures.
423
424
6
  m_apcSlicePilot->setNalUnitType   ( nalu.m_nalUnitType );
425
6
  m_apcSlicePilot->setNalUnitLayerId( nalu.m_nuhLayerId  );
426
6
  m_apcSlicePilot->setTLayer        ( nalu.m_temporalId  );
427
428
6
  m_HLSReader.setBitstream( &nalu.getBitstream() );
429
430
6
  m_bFirstSliceInPicture = true;  // set for now, will be set correctly in parseSliceHeader
431
6
  m_HLSReader.parseSliceHeader( m_apcSlicePilot, m_picHeader, &m_parameterSetManager, m_prevTid0POC, m_bFirstSliceInPicture );
432
433
6
  CHECK( m_bFirstSliceInPicture != ( m_apcSlicePilot->getCtuAddrInSlice( 0 ) == 0 ), "first slice in picture should start at CTU-addr 0" );
434
435
6
  if( m_bFirstSliceInPicture )
436
0
  {
437
0
    failIncompleteParsePic();   // a new picture starts, but the previous one was never completed
438
439
0
    m_uiSliceSegmentIdx = 0;
440
0
    m_apcSlicePilot->setPicHeader   ( m_picHeader.get() );
441
0
  }
442
6
  else // if it turns out, this was not the first slice in the picture, we need to parse the header again
443
6
  {
444
6
    m_uiSliceSegmentIdx++;
445
6
    CHECK( !m_pcParsePic, "m_pcParsePic should be initialized, when this is not the first slice in the picture" );
446
6
    CHECK( m_pcParsePic->slices.size() <= m_uiSliceSegmentIdx - 1 || m_pcParsePic->slices[m_uiSliceSegmentIdx - 1] == nullptr, "can't access previous slice" );
447
6
    CHECK( !m_pcParsePic->getMixedNaluTypesInPicFlag() && nalu.m_nalUnitType != m_pcParsePic->slices[m_uiSliceSegmentIdx - 1]->getNalUnitType(),
448
6
           "The value of NAL unit type shall be the same for all coded slice NAL units of a picture if pps_mixed_nalu_types_in_pic_flag is not set" );
449
450
6
    m_apcSlicePilot->copySliceInfo( m_pcParsePic->slices[m_uiSliceSegmentIdx - 1] );
451
452
6
    m_apcSlicePilot->setNalUnitType   ( nalu.m_nalUnitType );
453
6
    m_apcSlicePilot->setNalUnitLayerId( nalu.m_nuhLayerId );
454
6
    m_apcSlicePilot->setTLayer        ( nalu.m_temporalId );
455
456
6
    nalu.getBitstream().resetToStart();
457
6
    nalu.readNalUnitHeader();
458
6
    m_HLSReader.setBitstream        ( &nalu.getBitstream() );
459
460
6
    m_HLSReader.parseSliceHeader( m_apcSlicePilot, m_picHeader, &m_parameterSetManager, m_prevTid0POC, m_bFirstSliceInPicture );
461
6
  }
462
463
6
  const PPS* pps = static_cast<const ParameterSetManager&>( m_parameterSetManager ).getPPS( m_apcSlicePilot->getPicHeader()->getPPSId() );
464
6
  CHECK( pps == 0, "No PPS present" );
465
6
  const SPS* sps = static_cast<const ParameterSetManager&>( m_parameterSetManager ).getSPS( pps->getSPSId() );
466
6
  CHECK( sps == 0, "No SPS present" );
467
6
  const VPS* vps = static_cast<const ParameterSetManager&>( m_parameterSetManager ).getVPS( sps->getVPSId() );
468
6
  CHECK( sps->getVPSId() > 0 && vps == 0, "Invalid VPS" );
469
6
  if( sps->getVPSId() == 0 && m_prevLayerID != MAX_INT )
470
0
  {
471
0
    CHECK( m_prevLayerID != nalu.m_nuhLayerId, "All VCL NAL unit in the CVS shall have the same value of nuh_layer_id "
472
0
                                                           "when sps_video_parameter_set_id is equal to 0" );
473
0
  }
474
475
6
  CHECK( vps && !vps->getIndependentLayerFlag( nalu.m_nuhLayerId ), "Decoding of dependent layers not implemented. Dependent layer POC derivation was here." );
476
477
6
  if( !m_bFirstSliceInPicture )
478
0
  {
479
    // the slices of a picture shall be in increasing order of their addresses and shall not overlap
480
0
    const Slice* prevSlice = m_pcParsePic->slices[m_uiSliceSegmentIdx - 1];
481
0
    if( pps->getRectSliceFlag() )
482
0
    {
483
      // the rect slice map is a partition of the picture (verified in PPS::checkSliceMap()), so distinct indices suffice
484
0
      CHECK( m_apcSlicePilot->getSliceID() <= prevSlice->getSliceID(), "slices shall be in increasing order of their slice indices" );
485
0
    }
486
0
    else
487
0
    {
488
      // a raster-scan slice covers the tiles [sh_slice_address, sh_slice_address + numTilesInSlice)
489
0
      const uint32_t prevSliceLastTileIdx = pps->getTileIdx( prevSlice->getCtuAddrInSlice( prevSlice->getNumCtuInSlice() - 1 ) );
490
0
      CHECK( m_apcSlicePilot->getSliceID() <= prevSliceLastTileIdx, "slices shall be in increasing order of sh_slice_address and shall not overlap" );
491
0
    }
492
0
  }
493
494
  // update independent slice index
495
6
  m_apcSlicePilot->setIndependentSliceIdx( m_uiSliceSegmentIdx );
496
497
6
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "poc", m_apcSlicePilot->getPOC() ) );
498
499
500
6
  if( m_bFirstSliceInPicture )
501
0
  {
502
0
    const auto pictureType = m_apcSlicePilot->getNalUnitType();
503
504
0
    if( !pps->getMixedNaluTypesInPicFlag()
505
0
        && ( pictureType == NAL_UNIT_CODED_SLICE_IDR_W_RADL
506
0
             || pictureType == NAL_UNIT_CODED_SLICE_IDR_N_LP
507
0
             || pictureType == NAL_UNIT_CODED_SLICE_CRA
508
0
             || pictureType == NAL_UNIT_CODED_SLICE_GDR ) )
509
0
    {
510
0
      m_pocCRA            [nalu.m_nuhLayerId] = m_apcSlicePilot->getPOC();
511
0
      m_associatedIRAPType[nalu.m_nuhLayerId] = pictureType;
512
0
    }
513
0
  }
514
515
6
  xUpdatePreviousTid0POC( m_apcSlicePilot );
516
517
6
  m_apcSlicePilot->setAssociatedIRAPPOC ( m_pocCRA            [nalu.m_nuhLayerId] );
518
6
  m_apcSlicePilot->setAssociatedIRAPType( m_associatedIRAPType[nalu.m_nuhLayerId] );
519
520
6
  if( m_apcSlicePilot->getRapPicFlag() || m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR )
521
0
  {
522
    // Derive NoOutputBeforeRecoveryFlag
523
0
    if( !pps->getMixedNaluTypesInPicFlag() )
524
0
    {
525
0
      if( m_bFirstSliceInSequence[nalu.m_nuhLayerId] )
526
0
      {
527
0
        m_picHeader->setNoOutputBeforeRecoveryFlag( true );
528
0
      }
529
0
      else if( m_apcSlicePilot->getIdrPicFlag() )
530
0
      {
531
0
        m_picHeader->setNoOutputBeforeRecoveryFlag( true );
532
0
      }
533
0
      else if( m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA )
534
0
      {
535
0
        m_picHeader->setNoOutputBeforeRecoveryFlag( m_picHeader->getHandleCraAsCvsStartFlag() );
536
0
      }
537
0
      else if( m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR )
538
0
      {
539
0
        m_picHeader->setNoOutputBeforeRecoveryFlag( m_picHeader->getHandleGdrAsCvsStartFlag() );
540
0
      }
541
0
    }
542
0
    else
543
0
    {
544
0
      m_picHeader->setNoOutputBeforeRecoveryFlag( false );
545
0
    }
546
547
0
    if( m_apcSlicePilot->isCRAorGDR() )
548
0
    {
549
0
      m_lastNoOutputBeforeRecoveryFlag[nalu.m_nuhLayerId] = m_picHeader->getNoOutputBeforeRecoveryFlag();
550
0
    }
551
552
    // the inference for NoOutputOfPriorPicsFlag
553
0
    if( m_apcSlicePilot->getNoOutputOfPriorPicsFlag() )
554
0
    {
555
0
      m_lastPOCNoOutputPriorPics = m_apcSlicePilot->getPOC();
556
0
      m_isNoOutputPriorPics      = true;
557
0
    }
558
0
    else
559
0
    {
560
0
      m_isNoOutputPriorPics = false;
561
0
    }
562
0
  }
563
564
6
#if !DISABLE_CHECK_NO_OUTPUT_PRIOR_PICS_FLAG
565
6
  if( m_bFirstSliceInPicture && m_apcSlicePilot->getPOC() != m_prevPOC
566
0
      && ( m_apcSlicePilot->getRapPicFlag() || m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR )
567
0
      && m_picHeader->getNoOutputBeforeRecoveryFlag()
568
0
      && getNoOutputPriorPicsFlag() )
569
0
  {
570
0
    checkNoOutputPriorPics();
571
0
    setNoOutputPriorPicsFlag( false );
572
0
  }
573
6
#endif
574
575
576
  //For inference of PicOutputFlag
577
6
  if( !pps->getMixedNaluTypesInPicFlag() && ( m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_RASL ) )
578
0
  {
579
0
    if( m_lastNoOutputBeforeRecoveryFlag[nalu.m_nuhLayerId] )
580
0
    {
581
0
      m_picHeader->setPicOutputFlag( false );
582
0
    }
583
0
  }
584
585
6
  if( sps->getVPSId() > 0 )
586
0
  {
587
0
    const VPS *vps = m_parameterSetManager.getVPS( sps->getVPSId() );
588
0
    CHECK( vps == 0, "No VPS present" );
589
0
    if( ( vps->getOlsModeIdc() == 0
590
0
          && vps->getGeneralLayerIdx( nalu.m_nuhLayerId ) < ( vps->getMaxLayers() - 1 )
591
0
          && vps->getOlsOutputLayerFlag( vps->m_iTargetLayer, vps->getMaxLayers() - 1 ) == 1 )
592
0
        || ( vps->getOlsModeIdc() == 2
593
0
             && vps->getOlsOutputLayerFlag( vps->m_iTargetLayer, vps->getGeneralLayerIdx( nalu.m_nuhLayerId ) ) == 0 ) )
594
0
    {
595
0
      m_picHeader->setPicOutputFlag( false );
596
0
    }
597
0
  }
598
599
  //Reset POC MSB when CRA or GDR has NoOutputBeforeRecoveryFlag equal to 1
600
6
  if( !pps->getMixedNaluTypesInPicFlag() && m_apcSlicePilot->isCRAorGDR() && m_lastNoOutputBeforeRecoveryFlag[nalu.m_nuhLayerId] )
601
0
  {
602
0
    int iMaxPOClsb = 1 << sps->getBitsForPOC();
603
0
    m_apcSlicePilot->setPOC( m_apcSlicePilot->getPOC() & ( iMaxPOClsb - 1 ) );
604
0
    xUpdatePreviousTid0POC ( m_apcSlicePilot );
605
0
    m_lastPOCNoOutputPriorPics = m_apcSlicePilot->getPOC();
606
0
  }
607
608
  // Skip pictures due to random access
609
6
  if( isRandomAccessSkipPicture() )
610
0
  {
611
0
    m_prevSliceSkipped = true;
612
0
    m_skippedPOC       = m_apcSlicePilot->getPOC();
613
0
    msg( VERBOSE, "POC %i: RASL not decodable\n", m_skippedPOC );
614
0
    return false;
615
0
  }
616
617
  // clear previous slice skipped flag
618
6
  m_prevSliceSkipped = false;
619
620
  //we should only get a different poc for a new picture (with CTU address==0)
621
6
  if(  m_apcSlicePilot->getPOC() != m_prevPOC
622
0
   && !m_bFirstSliceInSequence[nalu.m_nuhLayerId]
623
0
   &&  m_apcSlicePilot->getFirstCtuRsAddrInSlice() != 0 )
624
0
  {
625
0
    msg( WARNING, "Warning, the first slice of a picture might have been lost!\n");
626
0
  }
627
628
6
  m_prevLayerID = nalu.m_nuhLayerId;
629
630
  //detect lost reference picture and insert copy of earlier frame.
631
6
  if( m_apcSlicePilot->getSliceType() != I_SLICE )
632
0
  {
633
0
    for( const auto rplIdx: { REF_PIC_LIST_0, REF_PIC_LIST_1 } )
634
0
    {
635
0
      const auto* rpl = m_apcSlicePilot->getRPL( rplIdx );
636
637
0
      int missingPoc         = MAX_INT;
638
0
      int missingRefPicIndex = 0;
639
0
      while( !m_apcSlicePilot->checkThatAllRefPicsAreAvailable( m_dpbReferencePics,
640
0
                                                                rpl,
641
0
                                                                m_apcSlicePilot->getNumRefIdx( rplIdx ),
642
0
                                                                &missingPoc,
643
0
                                                                &missingRefPicIndex ) )
644
0
      {
645
0
        if( !pps->getMixedNaluTypesInPicFlag()
646
0
            && ( ( m_apcSlicePilot->isIDR() && ( sps->getIDRRefParamListPresent() || pps->getRplInfoInPhFlag() ) )
647
0
                 || ( m_apcSlicePilot->isCRAorGDR() && m_picHeader->getNoOutputBeforeRecoveryFlag() ) ) )
648
0
        {
649
0
          if( !rpl->isInterLayerRefPic( missingRefPicIndex ) )
650
0
          {
651
0
            prepareUnavailablePicture( false,
652
0
                                       pps,
653
0
                                       missingPoc,
654
0
                                       m_apcSlicePilot->getNalUnitLayerId(),
655
0
                                       rpl->isRefPicLongterm( missingRefPicIndex ),
656
0
                                       m_apcSlicePilot->getTLayer() );
657
0
          }
658
0
        }
659
0
        else
660
0
        {
661
0
          prepareUnavailablePicture( true,
662
0
                                     pps,
663
0
                                     missingPoc,
664
0
                                     m_apcSlicePilot->getNalUnitLayerId(),
665
0
                                     rpl->isRefPicLongterm( missingRefPicIndex ),
666
0
                                     m_apcSlicePilot->getTLayer() );
667
0
        }
668
0
      }
669
0
    }
670
0
  }
671
6
  xActivateParameterSets( nalu.m_nuhLayerId );
672
673
  // WARNING: don't use m_apcSlicePilot after this point, because it has been reallocated
674
675
6
  Slice* slice = m_pcParsePic->slices[m_uiSliceSegmentIdx];
676
677
6
  m_pcParsePic->neededForOutput = m_picHeader->getPicOutputFlag();
678
6
  if( m_pcParsePic->lastSliceOfPicPresent() )
679
0
  {
680
#if 0
681
    // TODO for VPS support:
682
    if( sps->getVPSId() > 0 && NOT IN OUTPUT LAYER SET )
683
    {
684
      m_pcParsePic->neededForOutput = false;
685
    }
686
    else
687
#endif
688
0
    {
689
0
      if( !m_gdrRecovered[nalu.m_nuhLayerId] && slice->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR && m_gdrRecoveryPointPocVal[nalu.m_nuhLayerId] == INIT_POC )
690
0
      {
691
0
        m_gdrRecoveryPointPocVal[nalu.m_nuhLayerId] = m_pcParsePic->poc + m_picHeader->getRecoveryPocCnt();
692
0
      }
693
694
0
      if( !m_gdrRecovered[nalu.m_nuhLayerId]
695
0
          && ( m_gdrRecoveryPointPocVal[nalu.m_nuhLayerId] == m_pcParsePic->poc || m_picHeader->getRecoveryPocCnt() == 0 ) )
696
0
      {
697
0
        m_gdrRecovered          [nalu.m_nuhLayerId] = true;
698
0
        m_gdrRecoveryPointPocVal[nalu.m_nuhLayerId] = INIT_POC;
699
0
      }
700
701
0
      const bool is_recovering_picture = slice->getAssociatedIRAPType() == NAL_UNIT_CODED_SLICE_GDR && m_pcParsePic->poc < m_gdrRecoveryPointPocVal[nalu.m_nuhLayerId];
702
0
      if( slice->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR && m_gdrRecovered[nalu.m_nuhLayerId] )
703
0
      {
704
0
        m_pcParsePic->neededForOutput = true;
705
0
      }
706
0
      else if( slice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RASL && m_lastNoOutputBeforeRecoveryFlag[nalu.m_nuhLayerId] )
707
0
      {
708
0
        m_pcParsePic->neededForOutput = false;
709
0
      }
710
0
      else if( ( slice->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR && m_picHeader->getNoOutputBeforeRecoveryFlag() )
711
0
               || ( is_recovering_picture && ( !m_gdrRecovered[nalu.m_nuhLayerId] || m_lastNoOutputBeforeRecoveryFlag[nalu.m_nuhLayerId] ) ) )
712
0
      {
713
0
        m_pcParsePic->neededForOutput = false;
714
0
      }
715
0
    }
716
0
  }
717
718
6
  return true;
719
6
}
720
721
bool DecLibParser::xDecodeSliceMain( InputNALUnit& nalu )
722
0
{
723
0
  ITT_TASKSTART( itt_domain_oth, itt_handle_start );
724
  // actual decoding starts here
725
0
  Slice* pcSlice = m_pcParsePic->slices[m_uiSliceSegmentIdx];
726
0
  m_pcParsePic->poc              = pcSlice->getPOC();
727
0
  m_pcParsePic->tempLayer        = pcSlice->getTLayer();
728
0
  m_pcParsePic->dpbReferenceMark = pcSlice->getPicHeader()->getNonReferencePictureFlag() ? Picture::unreferenced : Picture::ShortTerm;
729
0
  m_pcParsePic->stillReferenced  = !!m_pcParsePic->dpbReferenceMark;
730
0
  m_pcParsePic->isReferencePic   = !!m_pcParsePic->dpbReferenceMark;
731
0
  m_pcParsePic->eNalUnitType     = nalu.m_nalUnitType;
732
0
  m_pcParsePic->cts              = nalu.m_cts;
733
0
  m_pcParsePic->dts              = nalu.m_dts;
734
0
  m_pcParsePic->rap              = nalu.m_rap;
735
0
  m_pcParsePic->userData         = nalu.m_userData;
736
0
  m_pcParsePic->bits            += nalu.m_bits + m_nonVCLbits;
737
0
  m_pcParsePic->layerId          = nalu.m_nuhLayerId;
738
0
  m_pcParsePic->subLayerNonReferencePictureDueToSTSA = false;
739
740
0
  m_nonVCLbits = 0;
741
742
0
  CHECK( m_pcParsePic->tempLayer != nalu.m_temporalId,
743
0
         "Currently parsed pic should have the same temporal layer as the NAL unit" );
744
745
0
  if( pcSlice->getSPS()->getProfileTierLevel()->getConstraintInfo()->getNoApsConstraintFlag() )
746
0
  {
747
0
    bool flag = pcSlice->getSPS()->getUseCCALF() || pcSlice->getPicHeader()->getNumAlfAps() || pcSlice->getPicHeader()->getAlfEnabledFlag( COMPONENT_Cb ) || pcSlice->getPicHeader()->getAlfEnabledFlag( COMPONENT_Cr );
748
0
    CHECK( flag, "When no_aps_constraint_flag is equal to 1, the values of "
749
0
                             "ph_num_alf_aps_ids_luma, sh_num_alf_aps_ids_luma, ph_alf_cb_flag, "
750
0
                             "ph_alf_cr_flag, sh_alf_cb_flag, sh_alf_cr_flag, "
751
0
                             "and sps_ccalf_enabled_flag shall all be equal to 0" )
752
0
  }
753
754
0
  if( pcSlice->getNalUnitLayerId() != pcSlice->getSPS()->getLayerId() )
755
0
  {
756
0
    CHECK( pcSlice->getSPS()->getLayerId() > pcSlice->getNalUnitLayerId(), "Layer Id of SPS cannot be greater than layer Id of VCL NAL unit the refer to it" );
757
0
    CHECK( pcSlice->getSPS()->getVPSId() == 0, "VPSId of the referred SPS cannot be 0 when layer Id of SPS and layer Id of current slice are different" );
758
0
    for (int i = 0; i < pcSlice->getVPS()->getNumOutputLayerSets(); i++ )
759
0
    {
760
0
      bool isCurrLayerInOls = false;
761
0
      bool isRefLayerInOls = false;
762
0
      int j = pcSlice->getVPS()->getNumLayersInOls(i) - 1;
763
0
      for (; j >= 0; j--)
764
0
      {
765
0
        if( pcSlice->getVPS()->getLayerIdInOls(i, j) == pcSlice->getNalUnitLayerId() )
766
0
        {
767
0
          isCurrLayerInOls = true;
768
0
        }
769
0
        if( pcSlice->getVPS()->getLayerIdInOls(i, j) == pcSlice->getSPS()->getLayerId() )
770
0
        {
771
0
          isRefLayerInOls = true;
772
0
        }
773
0
      }
774
0
      CHECK( isCurrLayerInOls && !isRefLayerInOls, "When VCL NAl unit in layer A refers to SPS in layer B, all OLS that contains layer A shall also contains layer B" );
775
0
    }
776
0
  }
777
0
  if( pcSlice->getNalUnitLayerId() != pcSlice->getPPS()->getLayerId() )
778
0
  {
779
0
    CHECK( pcSlice->getPPS()->getLayerId() > pcSlice->getNalUnitLayerId(), "Layer Id of PPS cannot be greater than layer Id of VCL NAL unit the refer to it" );
780
0
    CHECK( pcSlice->getSPS()->getVPSId() == 0, "VPSId of the referred SPS cannot be 0 when layer Id of PPS and layer Id of current slice are different" );
781
0
    for (int i = 0; i < pcSlice->getVPS()->getNumOutputLayerSets(); i++ )
782
0
    {
783
0
      bool isCurrLayerInOls = false;
784
0
      bool isRefLayerInOls = false;
785
0
      int j = pcSlice->getVPS()->getNumLayersInOls(i) - 1;
786
0
      for (; j >= 0; j--)
787
0
      {
788
0
        if( pcSlice->getVPS()->getLayerIdInOls(i, j) == pcSlice->getNalUnitLayerId() )
789
0
        {
790
0
          isCurrLayerInOls = true;
791
0
        }
792
0
        if( pcSlice->getVPS()->getLayerIdInOls(i, j) == pcSlice->getPPS()->getLayerId() )
793
0
        {
794
0
          isRefLayerInOls = true;
795
0
        }
796
0
      }
797
0
      CHECK( isCurrLayerInOls && !isRefLayerInOls, "When VCL NAl unit in layer A refers to PPS in layer B, all OLS that contains layer A shall also contains layer B" );
798
0
    }
799
0
  }
800
801
0
  if( m_bFirstSliceInPicture )
802
0
  {
803
0
    m_pcParsePic->setDecodingOrderNumber( m_decodingOrderCounter );
804
0
    m_decodingOrderCounter++;
805
806
0
    pcSlice->getPic()->subPictures.clear();
807
0
    pcSlice->getPic()->sliceSubpicIdx.clear();
808
809
0
    for( int subPicIdx = 0; subPicIdx < pcSlice->getSPS()->getNumSubPics(); subPicIdx++ )
810
0
    {
811
0
      pcSlice->getPic()->subPictures.push_back( pcSlice->getPPS()->getSubPic( subPicIdx ) );
812
0
    }
813
0
  }
814
815
0
  pcSlice->getPic()->sliceSubpicIdx.push_back(pcSlice->getPPS()->getSubPicIdxFromSubPicId(pcSlice->getSliceSubPicId()));
816
817
  // When decoding the slice header, the stored start and end addresses were actually RS addresses, not TS addresses.
818
  // Now, having set up the maps, convert them to the correct form.
819
820
  // Sanity check: verify that there are no duplicate POCs in the DPB before constructing the ref picture lists
821
0
  m_tmpSeenPocs.clear();
822
0
  m_tmpSeenPocs.reserve( m_dpbReferencePics.size() );
823
0
  for( auto& p: m_dpbReferencePics )
824
0
  {
825
0
    CHECK( m_tmpSeenPocs.count( p->poc ) != 0, "duplicate POC in DPB" );
826
0
    if( p->dpbReferenceMark )   // we only care about reference pictures in the DPB
827
0
    {
828
0
      m_tmpSeenPocs.insert( p->poc );
829
0
    }
830
0
  }
831
832
#if !DISABLE_CONFROMANCE_CHECK
833
  pcSlice->checkCRA( m_pocCRA[nalu.m_nuhLayerId], m_associatedIRAPType[nalu.m_nuhLayerId], m_picListManager.getPicListRange( m_pcParsePic ) );
834
#endif
835
0
  pcSlice->constructRefPicLists( m_dpbReferencePics );
836
#if !DISABLE_CONFROMANCE_CHECK
837
  pcSlice->checkRPL(pcSlice->getRPL0(), pcSlice->getRPL1(), m_associatedIRAPDecodingOrderNumber, m_picListManager.getPicListRange( m_pcParsePic ) );
838
  pcSlice->checkSTSA( m_picListManager.getPicListRange( pcParsePic ) );
839
#endif
840
841
#if TBC
842
  pcSlice->setPrevGDRSubpicPOC(m_prevGDRSubpicPOC[nalu.m_nuhLayerId][currSubPicIdx]);
843
  pcSlice->setPrevIRAPSubpicPOC(m_prevIRAPSubpicPOC[nalu.m_nuhLayerId][currSubPicIdx]);
844
  pcSlice->setPrevIRAPSubpicType(m_prevIRAPSubpicType[nalu.m_nuhLayerId][currSubPicIdx]);
845
  pcSlice->checkSubpicTypeConstraints(m_cListPic, pcSlice->getRPL0(), pcSlice->getRPL1(), m_prevIRAPSubpicDecOrderNo[nalu.m_nuhLayerId][currSubPicIdx]);
846
#endif
847
848
0
  if( m_pcParsePic->cs->vps && !m_pcParsePic->cs->vps->getIndependentLayerFlag( m_pcParsePic->cs->vps->getGeneralLayerIdx( nalu.m_nuhLayerId ) ) && m_pcParsePic->cs->pps->getNumSubPics() > 1 )
849
0
  {
850
0
    CU::checkConformanceILRP(pcSlice);
851
0
  }
852
853
0
  pcSlice->scaleRefPicList();
854
855
856
0
  if (!pcSlice->isIntra())
857
0
  {
858
0
    const int iCurrPOC  = pcSlice->getPOC();
859
860
0
    bool bLowDelay = true;
861
0
    for( int iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx( REF_PIC_LIST_0 ) && bLowDelay; iRefIdx++ )
862
0
    {
863
0
      if( pcSlice->getRefPOC( REF_PIC_LIST_0, iRefIdx ) > iCurrPOC )
864
0
      {
865
0
        bLowDelay = false;
866
0
      }
867
0
    }
868
0
    if( pcSlice->isInterB() )
869
0
    {
870
0
      for( int iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx( REF_PIC_LIST_1 ) && bLowDelay; iRefIdx++ )
871
0
      {
872
0
        if( pcSlice->getRefPOC( REF_PIC_LIST_1, iRefIdx ) > iCurrPOC )
873
0
        {
874
0
          bLowDelay = false;
875
0
        }
876
0
      }
877
0
    }
878
879
0
    pcSlice->setCheckLDC( bLowDelay );
880
0
  }
881
882
0
  if( pcSlice->getSPS()->getUseSMVD() && !pcSlice->getCheckLDC() && !pcSlice->getPicHeader()->getMvdL1ZeroFlag() )
883
0
  {
884
0
    int currPOC = pcSlice->getPOC();
885
886
0
    int forwardPOC = currPOC;
887
0
    int backwardPOC = currPOC;
888
0
    int ref = 0;
889
0
    int refIdx0 = -1;
890
0
    int refIdx1 = -1;
891
892
    // search nearest forward POC in List 0
893
0
    for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_0 ); ref++ )
894
0
    {
895
0
      int poc = pcSlice->getRefPOC( REF_PIC_LIST_0, ref );
896
0
      const bool isRefLongTerm = pcSlice->getIsUsedAsLongTerm( REF_PIC_LIST_0, ref );
897
0
      if( poc < currPOC && ( poc > forwardPOC || refIdx0 == -1 ) && !isRefLongTerm )
898
0
      {
899
0
        forwardPOC = poc;
900
0
        refIdx0 = ref;
901
0
      }
902
0
    }
903
904
    // search nearest backward POC in List 1
905
0
    for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_1 ); ref++ )
906
0
    {
907
0
      int poc = pcSlice->getRefPOC( REF_PIC_LIST_1, ref );
908
0
      const bool isRefLongTerm = pcSlice->getIsUsedAsLongTerm( REF_PIC_LIST_1, ref );
909
0
      if( poc > currPOC && ( poc < backwardPOC || refIdx1 == -1 ) && !isRefLongTerm )
910
0
      {
911
0
        backwardPOC = poc;
912
0
        refIdx1 = ref;
913
0
      }
914
0
    }
915
916
0
    if ( !(forwardPOC < currPOC && backwardPOC > currPOC) )
917
0
    {
918
0
      forwardPOC = currPOC;
919
0
      backwardPOC = currPOC;
920
0
      refIdx0 = -1;
921
0
      refIdx1 = -1;
922
923
      // search nearest backward POC in List 0
924
0
      for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_0 ); ref++ )
925
0
      {
926
0
        int poc = pcSlice->getRefPOC( REF_PIC_LIST_0, ref );
927
0
        const bool isRefLongTerm = pcSlice->getIsUsedAsLongTerm( REF_PIC_LIST_0, ref );
928
0
        if( poc > currPOC && ( poc < backwardPOC || refIdx0 == -1 ) && !isRefLongTerm )
929
0
        {
930
0
          backwardPOC = poc;
931
0
          refIdx0 = ref;
932
0
        }
933
0
      }
934
935
      // search nearest forward POC in List 1
936
0
      for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_1 ); ref++ )
937
0
      {
938
0
        int poc = pcSlice->getRefPOC( REF_PIC_LIST_1, ref );
939
0
        const bool isRefLongTerm = pcSlice->getIsUsedAsLongTerm( REF_PIC_LIST_1, ref );
940
0
        if( poc < currPOC && ( poc > forwardPOC || refIdx1 == -1 ) && !isRefLongTerm )
941
0
        {
942
0
          forwardPOC = poc;
943
0
          refIdx1 = ref;
944
0
        }
945
0
      }
946
0
    }
947
948
0
    if ( forwardPOC < currPOC && backwardPOC > currPOC )
949
0
    {
950
0
      pcSlice->setBiDirPred( true, refIdx0, refIdx1 );
951
0
    }
952
0
    else
953
0
    {
954
0
      pcSlice->setBiDirPred( false, -1, -1 );
955
0
    }
956
0
  }
957
0
  else
958
0
  {
959
0
    pcSlice->setBiDirPred( false, -1, -1 );
960
0
  }
961
962
  //---------------
963
0
  xCheckMixedNalUnit( pcSlice, nalu );
964
965
0
  if( m_bFirstSliceInPicture )
966
0
  {
967
0
#if RECO_WHILE_PARSE
968
0
    for( int ctu = 0; ctu < pcSlice->getPPS()->pcv->sizeInCtus; ctu++ )
969
0
    {
970
0
      m_pcParsePic->ctuParsedBarrier[ctu].lock();
971
0
    }
972
973
0
#endif
974
0
    m_parseFrameList.push_back( m_pcParsePic );
975
0
  }
976
977
0
  ITT_TASKEND( itt_domain_oth, itt_handle_start );
978
979
0
  static const auto parseTask = []( int threadId, void* param )
980
0
  {
981
0
    Slice* slice     = static_cast<Slice*>( param );
982
0
    auto&  decLib    = slice->parseTaskParams.decLibParser;
983
0
    auto&  bitstream = slice->parseTaskParams.bitstream;
984
0
    auto*  pic       = slice->getPic();
985
986
0
    try
987
0
    {
988
0
      pic->startProcessingTimer();
989
990
      //  Decode a picture
991
0
      ITT_TASKSTART( itt_domain_prs, itt_handle_parse );
992
0
      decLib->m_cSliceDecoder.parseSlice( slice, &bitstream, threadId );
993
0
      ITT_TASKEND( itt_domain_prs, itt_handle_parse );
994
995
0
      pic->stopProcessingTimer();
996
997
0
      bitstream.clearFifo();
998
0
      bitstream.clearEmulationPreventionByteLocation();
999
0
    }
1000
0
    catch( ... )
1001
0
    {
1002
0
      pic->setParseError( std::current_exception() );
1003
0
      std::rethrow_exception( std::current_exception() );
1004
0
    }
1005
0
    return true;
1006
0
  };
1007
1008
0
  pcSlice->parseTaskParams.init( this, std::move( nalu.getBitstream() ) );
1009
0
  pcSlice->parseDone.lock();
1010
1011
0
  auto expected = Picture::init;
1012
0
  m_pcParsePic->progress.compare_exchange_strong( expected, Picture::parsing );   // if RECO_WHILE_PARSE reconstruction can already have started, so we make sure to not overwrite that state
1013
1014
0
  if( m_threadPool && m_threadPool->numThreads() > 0 )
1015
0
  {
1016
0
    if( m_uiSliceSegmentIdx > 0 )
1017
0
    {
1018
0
      m_threadPool->addBarrierTask( TP_TASK_NAME_ARG( "POC:" + std::to_string( m_pcParsePic->poc ) + " parseTask" )
1019
0
                                    parseTask, pcSlice, &m_pcParsePic->m_divTasksCounter, &pcSlice->parseDone,
1020
0
                                    CBarrierVec{ &m_pcParsePic->slices[m_uiSliceSegmentIdx - 1]->parseDone } );
1021
0
    }
1022
0
    else
1023
0
    {
1024
0
      m_threadPool->addBarrierTask( TP_TASK_NAME_ARG( "POC:" + std::to_string( m_pcParsePic->poc ) + " parseTask" )
1025
0
                                    parseTask, pcSlice,  &m_pcParsePic->m_divTasksCounter, &pcSlice->parseDone );
1026
0
    }
1027
0
  }
1028
0
  else
1029
0
  {
1030
0
    parseTask( 0, pcSlice );
1031
0
    pcSlice->parseDone.unlock();
1032
0
  }
1033
1034
0
  if( pcSlice->getFirstCtuRsAddrInSlice() == 0 && !m_bFirstSliceInPicture )
1035
0
  {
1036
0
    if( m_prevPOC >= m_pocRandomAccess )
1037
0
    {
1038
0
      DTRACE_UPDATE( g_trace_ctx, std::make_pair( "final", 0 ) );
1039
0
    }
1040
0
  }
1041
0
  else
1042
0
  {
1043
0
    DTRACE_UPDATE( g_trace_ctx, std::make_pair( "final", 1 ) );
1044
0
  }
1045
0
  m_prevPOC = pcSlice->getPOC();
1046
1047
0
  m_bFirstSliceInSequence[nalu.m_nuhLayerId] = false;
1048
0
  m_bFirstSliceInBitstream                   = false;
1049
1050
1051
0
  const unsigned lastCtuInSlice = pcSlice->getCtuAddrInSlice( pcSlice->getNumCtuInSlice() - 1 );
1052
0
  if( lastCtuInSlice == pcSlice->getPPS()->pcv->sizeInCtus - 1 )
1053
0
  {
1054
0
    return true;
1055
0
  }
1056
1057
0
  return false;
1058
0
}
1059
1060
void DecLibParser::xActivateParameterSets( const int layerId )
1061
0
{
1062
0
  ParameterSetManager::ActivePSs paramSets;
1063
1064
0
  if( m_bFirstSliceInPicture )
1065
0
  {
1066
0
              paramSets = m_parameterSetManager.xActivateParameterSets( m_bFirstSliceInPicture, m_apcSlicePilot, m_picHeader.get() );
1067
0
    const SPS*  sps     = paramSets.sps;
1068
0
    const PPS*  pps     = paramSets.pps;
1069
0
    const APS** alfApss = paramSets.alfAPSs->data();
1070
0
    const APS*  lmcsAPS = paramSets.lmcsAps;
1071
0
    const APS*  scalingListAPS = paramSets.scalingListAps;
1072
1073
0
    xParsePrefixSEImessages();
1074
1075
0
    applyReferencePictureListBasedMarking( m_apcSlicePilot, layerId, *pps );
1076
1077
    //  Get a new picture buffer
1078
0
    m_pcParsePic = m_picListManager.getNewPicBuffer( *sps, *pps, m_apcSlicePilot->getTLayer(), layerId, m_parameterSetManager.getVPS( sps->getVPSId() ) );
1079
0
    CHECK( std::find( m_dpbReferencePics.cbegin(), m_dpbReferencePics.cend(), m_pcParsePic ) != m_dpbReferencePics.cend(), "reused picture shouldn't be in decoded picture buffer" );
1080
0
    m_dpbReferencePics.push_back( m_pcParsePic );
1081
    // assign these fields already, because they are needed by PicListManager::getPicListRange() and Slice::applyReferencePictureSet()
1082
0
    m_pcParsePic->poc          = m_apcSlicePilot->getPOC();
1083
0
    m_pcParsePic->eNalUnitType = m_apcSlicePilot->getNalUnitType();
1084
0
    m_pcParsePic->finalInit( &m_cuChunkCache, &m_tuChunkCache, &m_cuMapCache, &m_chromaCuMapCache, sps, pps, m_picHeader, alfApss, lmcsAPS, scalingListAPS );
1085
1086
#if !DISABLE_CONFROMANCE_CHECK
1087
    m_apcSlicePilot->checkLeadingPictureRestrictions( m_dpbReferencePics );
1088
#endif
1089
1090
0
    m_pcParsePic->dpbReferenceMark = m_apcSlicePilot->getPicHeader()->getNonReferencePictureFlag() ? Picture::unreferenced : Picture::ShortTerm;
1091
0
    m_pcParsePic->stillReferenced  = !!m_pcParsePic->dpbReferenceMark;
1092
0
    m_pcParsePic->isReferencePic   = !!m_pcParsePic->dpbReferenceMark;
1093
1094
    // Set Field/Frame coding mode
1095
0
    bool isField    = false;
1096
0
    bool isTopField = false;
1097
0
    if(!m_seiMessageList.empty())
1098
0
    {
1099
      // Check if any new Frame Field Info SEI has arrived
1100
0
      seiMessages frameFieldSEIs = SEI_internal::getSeisByType( m_seiMessageList, VVDEC_FRAME_FIELD_INFO );
1101
0
      if(!frameFieldSEIs.empty())
1102
0
      {
1103
0
        const vvdecSEIFrameFieldInfo* ff = (vvdecSEIFrameFieldInfo*) frameFieldSEIs.front()->payload;
1104
0
        isField    = ff->fieldPicFlag;
1105
0
        isTopField = isField && (!ff->bottomFieldFlag);
1106
0
      }
1107
0
    }
1108
0
    m_pcParsePic->fieldPic = isField;
1109
0
    m_pcParsePic->topField = isTopField;
1110
1111
    // transfer any SEI messages that have been received to the picture
1112
0
    m_pcParsePic->seiMessageList = m_seiMessageList;
1113
0
    m_seiMessageList.clear();
1114
1115
0
    m_apcSlicePilot->setPicHeader( m_picHeader.get() );
1116
0
  }
1117
0
  else
1118
0
  {
1119
0
    paramSets = m_parameterSetManager.xActivateParameterSets( m_bFirstSliceInPicture, m_apcSlicePilot, m_picHeader.get() );
1120
0
    m_apcSlicePilot->setAlfApss( paramSets.alfAPSs->data() );
1121
1122
0
    for( int i = 0; i < ALF_CTB_MAX_NUM_APS; ++i )
1123
0
    {
1124
0
      m_pcParsePic->cs->alfApss[i] = paramSets.alfAPSs->data()[i] ? paramSets.alfAPSs->data()[i]->getSharedPtr() : nullptr;
1125
0
    }
1126
0
  }
1127
1128
  // make the slice-pilot a real slice, and set up the slice-pilot for the next slice
1129
0
  Slice* pSlice = m_pcParsePic->allocateNewSlice( &m_apcSlicePilot );
1130
0
  CHECK_FATAL( m_pcParsePic->slices.size() != ( m_uiSliceSegmentIdx + 1 ), "Invalid number of slices" );
1131
1132
0
  const VPS* vps = pSlice->getVPS_nothrow();
1133
0
  const SPS* sps = pSlice->getSPS();
1134
0
  const PPS* pps = pSlice->getPPS();
1135
1136
0
  if( !m_bFirstSliceInPicture )
1137
0
  {
1138
0
    const APS*  lmcsAPS = pSlice->getPicHeader()->getLmcsAPS().get();
1139
1140
    // check that the current active PPS has not changed...
1141
0
    CHECK( sps->getChangedFlag(), "Error - a new SPS has been decoded while processing a picture" );
1142
0
    CHECK( pps->getChangedFlag(), "Error - a new PPS has been decoded while processing a picture" );
1143
0
    for( int i = 0; i < ALF_CTB_MAX_NUM_APS; i++ )
1144
0
    {
1145
0
      const APS* aps = m_parameterSetManager.getAPS_nothrow( i, ALF_APS );
1146
0
      CHECK( aps && aps->getChangedFlag(), "Error - a new APS has been decoded while processing a picture" );
1147
0
    }
1148
0
    CHECK( lmcsAPS && lmcsAPS->getChangedFlag(), "Error - a new LMCS APS has been decoded while processing a picture" );
1149
1150
0
    xParsePrefixSEImessages();
1151
1152
    // Check if any new SEI has arrived
1153
0
    if( !m_seiMessageList.empty() )
1154
0
    {
1155
      // Currently only decoding Unit SEI message occurring between VCL NALUs copied
1156
0
      seiMessages& picSEI = m_pcParsePic->seiMessageList;
1157
0
      seiMessages decodingUnitInfos = SEI_internal::extractSeisByType( m_seiMessageList, VVDEC_DECODING_UNIT_INFO );
1158
0
      picSEI.insert( picSEI.end(), decodingUnitInfos.begin(), decodingUnitInfos.end() );
1159
0
      SEI_internal::deleteSEIs   ( m_seiMessageList );
1160
0
    }
1161
0
  }
1162
1163
0
  CHECK( !sps->getGDREnabledFlag() && m_picHeader->getGdrPicFlag(), "When gdr_enabled_flag is equal to 0, the value of gdr_pic_flag shall be equal to 0 " );
1164
0
  CHECK( !sps->getUseWP() && pps->getUseWP(), "When sps_weighted_pred_flag is equal to 0, the value of pps_weighted_pred_flag shall be equal to 0." );
1165
0
  CHECK( !sps->getUseWPBiPred() && pps->getWPBiPred(),
1166
0
         "When sps_weighted_bipred_flag is equal to 0, the value of pps_weighted_bipred_flag shall be equal to 0." );
1167
1168
0
  CHECK( !sps->getResChangeInClvsEnabledFlag() && pps->getPicWidthInLumaSamples() != sps->getMaxPicWidthInLumaSamples(),
1169
0
         "When res_change_in_clvs_allowed_flag equal to 0, the value of pic_width_in_luma_samples shall be equal to pic_width_max_in_luma_samples." );
1170
0
  CHECK( !sps->getResChangeInClvsEnabledFlag() && pps->getPicHeightInLumaSamples() != sps->getMaxPicHeightInLumaSamples(),
1171
0
         "When res_change_in_clvs_allowed_flag equal to 0, the value of pic_height_in_luma_samples shall be equal to pic_height_max_in_luma_samples." );
1172
0
  CHECK( sps->getResChangeInClvsEnabledFlag() && sps->getSubPicInfoPresentFlag() != 0,
1173
0
         "When res_change_in_clvs_allowed_flag is equal to 1, the value of subpic_info_present_flag shall be equal to 0." );
1174
0
  CHECK( sps->getResChangeInClvsEnabledFlag() && sps->getVirtualBoundariesEnabledFlag(),
1175
0
         "when the value of res_change_in_clvs_allowed_flag is equal to 1, the value of sps_virtual_boundaries_present_flag shall be equal to 0" );
1176
0
  if( vps && vps->m_numOutputLayersInOls[vps->m_iTargetLayer] > 1 )
1177
0
  {
1178
0
    CHECK( sps->getMaxPicWidthInLumaSamples() > vps->getOlsDpbPicSize( vps->m_iTargetLayer ).width,
1179
0
           "pic_width_max_in_luma_samples shall be less than or equal to the value of ols_dpb_pic_width[ i ]" );
1180
0
    CHECK( sps->getMaxPicHeightInLumaSamples() > vps->getOlsDpbPicSize( vps->m_iTargetLayer ).height,
1181
0
           "pic_height_max_in_luma_samples shall be less than or equal to the value of ols_dpb_pic_height[ i ]" );
1182
0
  }
1183
1184
0
  CHECK( sps->getProfileTierLevel()->getConstraintInfo()->getOneTilePerPicConstraintFlag() && pps->getNumTiles() != 1,
1185
0
         "When one_tile_per_pic_constraint_flag is equal to 1, each picture shall contain only one tile" );
1186
0
  CHECK( sps->getProfileTierLevel()->getConstraintInfo()->getOneSlicePerPicConstraintFlag() && pps->getRectSliceFlag() && pps->getNumSlicesInPic() != 1,
1187
0
         "When one_slice_per_pic_constraint_flag is equal to 1 and if pps_rect_slice_flag is equal to 1, the value of num_slices_in_pic_minus1 shall be equal to 0" );
1188
0
  CHECK( sps->getProfileTierLevel()->getConstraintInfo()->getNoRprConstraintFlag() && sps->getRprEnabledFlag(),
1189
0
         "When gci_no_ref_pic_resampling_constraint_flag is equal to 1, the value of sps_ref_pic_resampling_enabled_flag shall be equal to 0" );
1190
0
  CHECK( sps->getProfileTierLevel()->getConstraintInfo()->getNoResChangeInClvsConstraintFlag() && sps->getResChangeInClvsEnabledFlag(),
1191
0
         "When gci_no_res_change_in_clvs_constraint_flag is equal to 1, the value of sps_res_change_in_clvs_allowed_flag shall be equal to 0" );
1192
0
  CHECK( sps->getProfileTierLevel()->getConstraintInfo()->getNoIdrRplConstraintFlag() && sps->getIDRRefParamListPresent(),
1193
0
         "When gci_no_idr_rpl_constraint_flag equal to 1 , the value of sps_idr_rpl_present_flag shall be equal to 0" );
1194
0
  CHECK( sps->getProfileTierLevel()->getConstraintInfo()->getNoMixedNaluTypesInPicConstraintFlag() && pps->getMixedNaluTypesInPicFlag(),
1195
0
         "When gci_no_mixed_nalu_types_in_pic_constraint_flag equal to 1, the value of pps_mixed_nalu_types_in_pic_flag shall be equal to 0" );
1196
0
  CHECK( sps->getProfileTierLevel()->getConstraintInfo()->getNoRectSliceConstraintFlag() && pps->getRectSliceFlag(),
1197
0
         "When gci_no_rectangular_slice_constraint_flag equal to 1, the value of pps_rect_slice_flag shall be equal to 0" );
1198
0
  CHECK( sps->getProfileTierLevel()->getConstraintInfo()->getOneSlicePerSubpicConstraintFlag() && !pps->getSingleSlicePerSubPicFlag(),
1199
0
         "When gci_one_slice_per_subpic_constraint_flag equal to 1, the value of pps_single_slice_per_subpic_flag shall be equal to 1" );
1200
0
  CHECK( sps->getProfileTierLevel()->getConstraintInfo()->getNoSubpicInfoConstraintFlag() && sps->getSubPicInfoPresentFlag(),
1201
0
         "When gci_no_subpic_info_constraint_flag is equal to 1, the value of sps_subpic_info_present_flag shall be equal to 0" );
1202
1203
0
  if( sps->getProfileTierLevel()->getConstraintInfo()->getNoMttConstraintFlag() )
1204
0
  {
1205
0
    CHECK( sps->getMaxMTTHierarchyDepth() || sps->getMaxMTTHierarchyDepthI() || sps->getMaxMTTHierarchyDepthIChroma(),
1206
0
           "When gci_no_mtt_constraint_flag is equal to 1, the values of sps_max_mtt_hierarchy_depth_intra_slice_luma, sps_max_mtt_hierarchy_depth_inter_slice"
1207
0
           " and sps_max_mtt_hierarchy_depth_intra_slice_chroma shall be equal to 0" );
1208
0
  }
1209
0
  if( sps->getProfileTierLevel()->getConstraintInfo()->getNoWeightedPredictionConstraintFlag() )
1210
0
  {
1211
0
    CHECK( sps->getUseWP() || sps->getUseWPBiPred(),
1212
0
           "When gci_no_weighted_prediction_constraint_flag is equal to 1, the values of sps_weighted_pred_flag and sps_weighted_bipred_flag shall be equal to 0" );
1213
0
  }
1214
1215
0
  CHECK( sps->getProfileTierLevel()->getConstraintInfo()->getNoChromaQpOffsetConstraintFlag() && pps->getCuChromaQpOffsetEnabledFlag(),
1216
0
         "When gci_no_ChromaQpOffset_constraint_flag is equal to 1, the values of pps_cu_chroma_qp_offset_list_enabled_flag shall be equal to 0" );
1217
1218
0
  CHECK( sps->getCTUSize() > ( 1 << sps->getProfileTierLevel()->getConstraintInfo()->getMaxLog2CtuSizeConstraintIdc() ),
1219
0
         "The CTU size specified by sps_log2_ctu_size_minus5 shall not exceed the constraint specified by gci_three_minus_max_log2_ctu_size_constraint_idc" );
1220
0
  CHECK( sps->getProfileTierLevel()->getConstraintInfo()->getNoLumaTransformSize64ConstraintFlag() && sps->getLog2MaxTbSize() != 5,
1221
0
         "When gci_no_luma_transform_size_64_constraint_flag is equal to 1, the value of sps_max_luma_transform_size_64_flag shall be equal to 0" );
1222
1223
#if 0
1224
  if( vps && vps->getMaxLayers() > 1 )
1225
  {
1226
    // TODO: fix MT static maps
1227
    static std::unordered_map<int, int> m_layerChromaFormat;
1228
    static std::unordered_map<int, int> m_layerBitDepth;
1229
1230
    int curLayerIdx          = vps->getGeneralLayerIdx(layerId);
1231
    int curLayerChromaFormat = sps->getChromaFormatIdc();
1232
    int curLayerBitDepth     = sps->getBitDepth();
1233
1234
    if( pSlice->isClvssPu() && m_bFirstSliceInPicture )
1235
    {
1236
      m_layerChromaFormat[curLayerIdx] = curLayerChromaFormat;
1237
      m_layerBitDepth    [curLayerIdx] = curLayerBitDepth;
1238
    }
1239
    else
1240
    {
1241
      CHECK( m_layerChromaFormat[curLayerIdx] != curLayerChromaFormat, "Different chroma format in the same layer." );
1242
      CHECK( m_layerBitDepth    [curLayerIdx] != curLayerBitDepth, "Different bit-depth in the same layer." );
1243
    }
1244
1245
    for( int i = 0; i < curLayerIdx; i++ )
1246
    {
1247
      if( vps->getDirectRefLayerFlag( curLayerIdx, i ) )
1248
      {
1249
        int refLayerChromaFormat = m_layerChromaFormat[i];
1250
        CHECK( curLayerChromaFormat != refLayerChromaFormat, "The chroma formats of the current layer and the reference layer are different" );
1251
        int refLayerBitDepth = m_layerBitDepth[i];
1252
        CHECK( curLayerBitDepth != refLayerBitDepth, "The bit-depth of the current layer and the reference layer are different" );
1253
      }
1254
    }
1255
  }
1256
#endif
1257
1258
0
  const int minCuSize = 1 << sps->getLog2MinCodingBlockSize();
1259
0
  CHECK( ( pps->getPicWidthInLumaSamples()  % ( std::max( 8, minCuSize) ) ) != 0, "Coded frame width must be a multiple of Max(8, the minimum unit size)" );
1260
0
  CHECK( ( pps->getPicHeightInLumaSamples() % ( std::max( 8, minCuSize) ) ) != 0, "Coded frame height must be a multiple of Max(8, the minimum unit size)" );
1261
1262
0
  if( sps->getCTUSize() + 2 * ( 1 << sps->getLog2MinCodingBlockSize() ) > pps->getPicWidthInLumaSamples() )
1263
0
  {
1264
0
    CHECK( pps->getUseWrapAround(),
1265
0
           "Wraparound shall be disabled when the value of ( CtbSizeY / MinCbSizeY + 1) is greater than or equal to"
1266
0
           " ( pic_width_in_luma_samples / MinCbSizeY - 1 )" );
1267
0
  }
1268
1269
0
  if( pSlice->getPicHeader()->getGdrOrIrapPicFlag() && !pSlice->getPicHeader()->getGdrPicFlag()
1270
0
      && ( !vps || vps->getIndependentLayerFlag( vps->getGeneralLayerIdx( layerId ) ) ) )
1271
0
  {
1272
0
    CHECK( pSlice->getPicHeader()->getPicInterSliceAllowedFlag(),
1273
0
           "When gdr_or_irap_pic_flag is equal to 1 and gdr_pic_flag is equal to 0 and vps_independent_layer_flag[ GeneralLayerIdx[ nuh_layer_id ] ] "
1274
0
           "is equal to 1, ph_inter_slice_allowed_flag shall be equal to 0" );
1275
0
  }
1276
1277
0
  if( sps->getVPSId() && vps && vps->m_numLayersInOls[vps->m_iTargetLayer] == 1 )
1278
0
  {
1279
0
    CHECK( !sps->getPtlDpbHrdParamsPresentFlag(),
1280
0
           "When sps_video_parameter_set_id is greater than 0 and there is an OLS that contains only one layer"
1281
0
           " with nuh_layer_id equal to the nuh_layer_id of the SPS, the value of sps_ptl_dpb_hrd_params_present_flag shall be equal to 1" );
1282
0
  }
1283
1284
0
  ProfileLevelTierFeatures ptlFeature;
1285
0
  ptlFeature.extractPTLInformation(*sps);
1286
1287
0
  const LevelTierFeatures* ltFeature = ptlFeature.getLevelTierFeatures();
1288
0
  const ProfileFeatures*   pFeature  = ptlFeature.getProfileFeatures();
1289
1290
0
  CHECK( ltFeature && pps->getNumTileColumns() > ltFeature->maxTileCols, "Num tile columns signaled in PPS exceed level limits" );
1291
0
  CHECK( ltFeature && pps->getNumTiles() > ltFeature->maxTilesPerAu, "Num tiles signaled in PPS exceed level limits" );
1292
0
  CHECK( pFeature && sps->getBitDepth() > pFeature->maxBitDepth, "Bit depth exceed profile limit" );
1293
0
  CHECK( pFeature && sps->getChromaFormatIdc() > pFeature->maxChromaFormat, "Chroma format exceed profile limit" );
1294
0
}
1295
1296
void DecLibParser::prepareUnavailablePicture( bool isLost, const PPS* pps, int iUnavailablePoc, const int layerId, const bool longTermFlag, const int temporalId )
1297
0
{
1298
0
  if( isLost )
1299
0
  {
1300
0
    CHECK( !( m_errHandlingFlags & ERR_HANDLING_TRY_CONTINUE ), "missing reference picture poc: " << iUnavailablePoc );
1301
1302
0
    if( !m_picListManager.getBackPic() )
1303
0
    {
1304
0
      THROW_RECOVERABLE( "no pictures yet." );
1305
0
      return;
1306
0
    }
1307
0
    msg( WARNING, "inserting lost poc : %d\n", iUnavailablePoc );
1308
0
  }
1309
0
  else
1310
0
  {
1311
0
    msg( INFO, "inserting unavailable poc : %d\n", iUnavailablePoc );
1312
0
  }
1313
  // use the parameter sets of the referencing picture, so the generated reference has a compatible buffer layout
1314
0
  const SPS* sps = static_cast<const ParameterSetManager&>( m_parameterSetManager ).getSPS( pps->getSPSId() );
1315
0
  CHECK( !sps, "no SPS for unavailable reference picture" );
1316
0
  Picture* cFillPic = m_picListManager.getNewPicBuffer( *sps, *pps, 0, layerId, m_parameterSetManager.getVPS( sps->getVPSId() ) );
1317
0
  CHECK( std::find( m_dpbReferencePics.cbegin(), m_dpbReferencePics.cend(), cFillPic ) != m_dpbReferencePics.cend(), "reused picture shouldn't be in decoded picture buffer" );
1318
0
  m_dpbReferencePics.push_back( cFillPic );
1319
0
  const APS* nullAlfApss[ALF_CTB_MAX_NUM_APS] = { nullptr, };
1320
0
  cFillPic->finalInit( &m_cuChunkCache, &m_tuChunkCache, &m_cuMapCache, &m_chromaCuMapCache, sps, pps, m_picHeader, nullAlfApss, nullptr, nullptr, false );
1321
1322
0
  CHECK_FATAL( !cFillPic->slices.empty(), "fill pic should not contain slices, already." );
1323
0
  cFillPic->allocateNewSlice();
1324
0
  cFillPic->slices[0]->initSlice();
1325
0
  cFillPic->slices[0]->setPOC( iUnavailablePoc );
1326
0
  cFillPic->slices[0]->setTLayer( temporalId );
1327
0
  cFillPic->slices[0]->setNalUnitLayerId( layerId );
1328
1329
  // picture header is not derived for generated reference picture
1330
0
  cFillPic->slices[0]->setPicHeader( nullptr );
1331
0
  cFillPic->slices[0]->setPPS( pps->getSharedPtr() );
1332
1333
0
  cFillPic->dpbReferenceMark        = longTermFlag ? Picture::LongTerm : Picture::ShortTerm;
1334
0
  cFillPic->stillReferenced         = true;
1335
0
  cFillPic->isReferencePic          = true;
1336
0
  cFillPic->poc                     = iUnavailablePoc;
1337
0
  cFillPic->neededForOutput         = false;
1338
0
  cFillPic->tempLayer               = temporalId;
1339
0
  cFillPic->nonReferencePictureFlag = false;
1340
0
  cFillPic->wasLost                 = isLost;
1341
1342
0
  if( cFillPic->slices[0]->getTLayer() == 0 &&
1343
0
      cFillPic->slices[0]->getNalUnitType() != NAL_UNIT_CODED_SLICE_RASL &&
1344
0
      cFillPic->slices[0]->getNalUnitType() != NAL_UNIT_CODED_SLICE_RADL )
1345
0
  {
1346
0
    m_prevTid0POC = cFillPic->slices[0]->getPOC();
1347
0
  }
1348
1349
0
  cFillPic->subPictures.clear();
1350
0
  cFillPic->sliceSubpicIdx.clear();
1351
1352
0
  for( int subPicIdx = 0; subPicIdx < pps->getNumSubPics(); subPicIdx++ )
1353
0
  {
1354
0
    cFillPic->subPictures.push_back( pps->getSubPic( subPicIdx ) );
1355
0
  }
1356
1357
0
  cFillPic->parseDone.unlock();
1358
1359
#if 0
1360
// NOT YET IMPLEMENTED
1361
  if( isLost && ( m_errHandlingFlags & ERR_HANDLING_COPY_CLOSEST ) )
1362
  {
1363
    // this will be filled in later, when closer pictures might have been reconstructed.
1364
1365
    cFillPic->progress = Picture::parsed;
1366
    m_parseFrameList.push_back( cFillPic );
1367
    return;
1368
  }
1369
#endif
1370
1371
0
  cFillPic->fillGrey( sps );
1372
1373
0
  if( m_pocRandomAccess == MAX_INT )
1374
0
  {
1375
0
    m_pocRandomAccess = iUnavailablePoc;
1376
0
  }
1377
0
}
1378
1379
#if 0
1380
// NOT YET IMPLEMENTED
1381
void DecLibParser::fillMissingPicBuf( Picture* pcPic, bool copyClosest )
1382
{
1383
  if( copyClosest )
1384
  {
1385
    CHECK_FATAL( pcPic->progress != Picture::parsed, "filled in picture should have been marked as parsed" );
1386
    CHECK_FATAL( pcPic->parseDone.isBlocked(), "parsed barrier should be unlocked" );
1387
1388
    auto closestPic = m_picListManager.findClosestPic( pcPic->poc );
1389
    if( closestPic )
1390
    {
1391
      CHECK_FATAL( closestPic->progress < Picture::reconstructed, "closest Picture is not yet reconstructed" )
1392
      // the next not-lost picture in the parseFrameList should be the one, that referenced this picture
1393
      auto referencedBy = std::find_if( m_parseFrameList.begin(), m_parseFrameList.end(), []( Picture* p ) { return !p->wasLost && !p->error; } );
1394
      msg( INFO, "copying picture %d to %d (%d)\n", closestPic->getPOC(), pcPic->poc, ( referencedBy != m_parseFrameList.end() ) ? ( *referencedBy )->poc : -1 );
1395
1396
      pcPic->getRecoBuf().copyFrom( closestPic->getRecoBuf() );
1397
1398
      pcPic->slices[0]->copySliceInfo( closestPic->slices[0] );
1399
      pcPic->slices[0]->setPOC( pcPic->poc );
1400
    }
1401
1402
    // currently we don't output filled-in reference pictures
1403
    // pcPic->neededForOutput = true;
1404
  }
1405
  else
1406
  {
1407
    pcPic->fillGrey( pcPic->cs->sps.get() );
1408
  }
1409
1410
  pcPic->progress = Picture::reconstructed;
1411
  pcPic->reconDone.unlock();
1412
}
1413
#endif
1414
1415
1416
// Function for applying picture marking based on the Reference Picture List
1417
void DecLibParser::applyReferencePictureListBasedMarking( Slice* currSlice, const int layerId, const PPS& pps )
1418
0
{
1419
  //  checkLeadingPictureRestrictions(rcListPic, pps);
1420
1421
  // mark long-term reference pictures in List0
1422
0
  for( const auto l: { REF_PIC_LIST_0, REF_PIC_LIST_1 } )
1423
0
  {
1424
0
    const ReferencePictureList* rpl = currSlice->getRPL( l );
1425
1426
0
    for( int i = 0; i < rpl->getNumRefEntries(); i++ )
1427
0
    {
1428
0
      if( !rpl->isRefPicLongterm( i ) || rpl->isInterLayerRefPic( i ) )
1429
0
      {
1430
0
        continue;
1431
0
      }
1432
1433
0
      Picture* availableST = nullptr;
1434
0
      for( Picture* pic: m_dpbReferencePics )
1435
0
      {
1436
0
        if( !pic->dpbReferenceMark )
1437
0
        {
1438
0
          continue;
1439
0
        }
1440
1441
0
        const int bitsForPoc = pic->cs->sps->getBitsForPOC();
1442
0
        const int curPoc     = pic->getPOC();
1443
0
        const int ltRefPoc   = rpl->calcLTRefPOC( currSlice->getPOC(), bitsForPoc, i );
1444
0
        if( pic->dpbReferenceMark == Picture::LongTerm && isLTPocEqual( curPoc, ltRefPoc, bitsForPoc, rpl->getDeltaPocMSBPresentFlag( i ) ) )
1445
0
        {
1446
0
          break;
1447
0
        }
1448
1449
        // if there was no such long-term check the short terms
1450
0
        if( pic->dpbReferenceMark == Picture::ShortTerm && isLTPocEqual( curPoc, ltRefPoc, bitsForPoc, rpl->getDeltaPocMSBPresentFlag( i ) ) )
1451
0
        {
1452
0
          availableST = pic;
1453
          // but don't break here, because we might still find a LT
1454
0
        }
1455
0
      }
1456
1457
      // the found picture was not yet marked as long term, so we mark it here
1458
0
      if ( availableST )
1459
0
      {
1460
0
        availableST->dpbReferenceMark = Picture::LongTerm;
1461
0
      }
1462
0
    }
1463
0
  }
1464
1465
0
  if( currSlice->isIDR() && !pps.getMixedNaluTypesInPicFlag() )
1466
0
  {
1467
0
    for( Picture* pic: m_dpbReferencePics )
1468
0
    {
1469
0
      pic->dpbReferenceMark = Picture::unreferenced;
1470
0
    }
1471
1472
    // ignore neededForOutput flag here, because we only care about reference pictures in the DPB
1473
0
    m_dpbReferencePics.remove_if( []( Picture* pic ) { return !pic->dpbReferenceMark; } );
1474
0
    return;
1475
0
  }
1476
1477
  // loop through all pictures in the reference picture buffer
1478
0
  for( Picture* pic: m_dpbReferencePics )
1479
0
  {
1480
0
    if( !pic->dpbReferenceMark )
1481
0
    {
1482
0
      continue;
1483
0
    }
1484
1485
0
    bool isReference = false;
1486
1487
0
    for( const auto l: { REF_PIC_LIST_0, REF_PIC_LIST_1 } )
1488
0
    {
1489
0
      if( currSlice->getRPL( l )->findInRefPicList( pic, currSlice->getPOC(), layerId ) )
1490
0
      {
1491
0
        isReference = true;
1492
0
        break;
1493
0
      }
1494
0
    }
1495
1496
    // mark the picture as "unused for reference" if it is not in
1497
    // the Reference Picture List
1498
0
    if( !isReference && pic->poc != currSlice->getPOC() && pic->layerId == layerId )
1499
0
    {
1500
0
      pic->dpbReferenceMark = Picture::unreferenced;
1501
0
    }
1502
1503
    // // sanity checks
1504
    // if( pic->referenced )
1505
    // {
1506
    //   // check that pictures of higher temporal layers are not used
1507
    //   CHECK_FATAL( pic->usedByCurr && pic->temporalId > this->getTLayer(), "Invalid state" );
1508
    // }
1509
0
  }
1510
1511
  // ignore neededForOutput flag here, because we only care about reference pictures in the DPB
1512
0
  m_dpbReferencePics.remove_if( []( Picture* pic ) { return !pic->dpbReferenceMark; } );
1513
0
}
1514
1515
void DecLibParser::xParsePrefixSEImessages()
1516
0
{
1517
0
  while( !m_prefixSEINALUs.empty() )
1518
0
  {
1519
0
    InputNALUnit& nalu = m_prefixSEINALUs.front();
1520
0
    const SPS *sps = m_parameterSetManager.getActiveSPS();
1521
0
    const VPS *vps = m_parameterSetManager.getVPS(sps->getVPSId());
1522
0
    m_seiReader.parseSEImessage( &(nalu.getBitstream()), m_seiMessageList, nalu.m_nalUnitType, nalu.m_nuhLayerId, nalu.m_temporalId, vps, sps, m_HRD, m_pDecodedSEIOutputStream );
1523
0
    m_prefixSEINALUs.pop_front();
1524
0
  }
1525
0
}
1526
1527
void DecLibParser::xParsePrefixSEIsForUnknownVCLNal()
1528
11
{
1529
11
  while (!m_prefixSEINALUs.empty())
1530
0
  {
1531
    // do nothing?
1532
0
    msg( VERBOSE, "Discarding Prefix SEI associated with unknown VCL NAL unit.\n");
1533
0
    m_prefixSEINALUs.pop_front();
1534
0
  }
1535
  // TODO: discard following suffix SEIs as well?
1536
11
}
1537
1538
void DecLibParser::xDecodePicHeader( InputNALUnit& nalu )
1539
1
{
1540
1
  m_HLSReader.setBitstream( &nalu.getBitstream() );
1541
1
  m_picHeader = std::make_shared<PicHeader>();
1542
1
  m_HLSReader.parsePictureHeader( m_picHeader.get(), &m_parameterSetManager, true );
1543
1
}
1544
1545
void DecLibParser::xDecodeVPS( InputNALUnit& nalu )
1546
2
{
1547
  // We don't parse the VPS, because the needed bounds checks in parseVPS() are not yet implemented, and we don't process it anyways
1548
#if 0
1549
  std::unique_ptr<VPS> vps( new VPS() );
1550
  m_HLSReader.setBitstream( &nalu.getBitstream() );
1551
  m_HLSReader.parseVPS( vps.get() );
1552
  m_parameterSetManager.storeVPS( vps.release(), nalu.getBitstream().getFifo() );
1553
#endif
1554
2
}
1555
1556
void DecLibParser::xDecodeDCI( InputNALUnit& nalu )
1557
5
{
1558
5
  m_HLSReader.setBitstream(&nalu.getBitstream());
1559
1560
5
  CHECK(nalu.m_temporalId, "The value of TemporalId of DCI NAL units shall be equal to 0");
1561
3
  if( !m_dci )
1562
3
  {
1563
3
    m_dci = new DCI;
1564
3
    m_HLSReader.parseDCI( m_dci );
1565
3
  }
1566
0
  else
1567
0
  {
1568
0
    DCI dupDCI;
1569
0
    m_HLSReader.parseDCI( &dupDCI );
1570
0
    CHECK( !m_dci->IsIndenticalDCI( dupDCI ), "Two signaled DCIs are different");
1571
0
  }
1572
3
}
1573
1574
void DecLibParser::xDecodeSPS( InputNALUnit& nalu )
1575
80
{
1576
80
  std::unique_ptr<SPS> sps( new SPS() );
1577
80
  m_HLSReader.setBitstream( &nalu.getBitstream() );
1578
80
  m_HLSReader.parseSPS( sps.get(), &m_parameterSetManager );
1579
80
  sps->setLayerId( nalu.m_nuhLayerId );
1580
80
  DTRACE( g_trace_ctx, D_QP_PER_CTU, "CTU Size: %dx%d", sps->getMaxCUWidth(), sps->getMaxCUHeight() );  // don't move after storeSPS, because SPS could have been deleted
1581
80
  m_parameterSetManager.storeSPS( sps.release(), nalu.getBitstream().getFifo() );
1582
80
}
1583
1584
void DecLibParser::xDecodePPS( InputNALUnit& nalu )
1585
3
{
1586
3
  std::unique_ptr<PPS> pps( new PPS() );
1587
3
  m_HLSReader.setBitstream( &nalu.getBitstream() );
1588
3
  m_HLSReader.parsePPS( pps.get(), &m_parameterSetManager );
1589
3
  pps->setLayerId( nalu.m_nuhLayerId );
1590
3
  m_parameterSetManager.storePPS( pps.release(), nalu.getBitstream().getFifo() );
1591
3
}
1592
1593
void DecLibParser::xDecodeAPS( InputNALUnit& nalu )
1594
43
{
1595
43
  std::unique_ptr<APS> aps( new APS() );
1596
43
  m_HLSReader.setBitstream( &nalu.getBitstream() );
1597
43
  if( !m_HLSReader.parseAPS( aps.get() ) )
1598
2
  {   // ignore unsupported APS types
1599
2
    return;
1600
2
  }
1601
41
  aps->setTemporalId( nalu.m_temporalId );
1602
41
  aps->setLayerId( nalu.m_nuhLayerId );
1603
41
  aps->setHasPrefixNalUnitType( nalu.m_nalUnitType == NAL_UNIT_PREFIX_APS );
1604
41
  m_parameterSetManager.storeAPS( aps.release(), nalu.getBitstream().getFifo() );
1605
41
}
1606
1607
void DecLibParser::xUpdatePreviousTid0POC(Slice * pSlice)
1608
0
{
1609
0
  if( pSlice->getTLayer() == 0 && pSlice->getNalUnitType() != NAL_UNIT_CODED_SLICE_RASL && pSlice->getNalUnitType() != NAL_UNIT_CODED_SLICE_RADL
1610
0
      && !pSlice->getPicHeader()->getNonReferencePictureFlag() )
1611
0
  {
1612
0
    m_prevTid0POC = pSlice->getPOC();
1613
0
  }
1614
0
}
1615
1616
1617
void DecLibParser::checkNoOutputPriorPics()
1618
0
{
1619
0
  if( !m_isNoOutputPriorPics )
1620
0
  {
1621
0
    return;
1622
0
  }
1623
1624
0
  for( auto& pcPicTmp: m_dpbReferencePics )
1625
0
  {
1626
0
    if( pcPicTmp->progress >= Picture::reconstructed && pcPicTmp->getPOC() < m_lastPOCNoOutputPriorPics )
1627
0
    {
1628
0
      pcPicTmp->neededForOutput = false;
1629
0
    }
1630
0
  }
1631
0
}
1632
1633
/** Function for checking if picture should be skipped because of random access. This function checks the skipping of pictures in the case of -s option random access.
1634
 *  All pictures prior to the random access point indicated by the counter iSkipFrame are skipped.
1635
 *  It also checks the type of Nal unit type at the random access point.
1636
 *  If the random access point is CRA/CRANT/BLA/BLANT, TFD pictures with POC less than the POC of the random access point are skipped.
1637
 *  If the random access point is IDR all pictures after the random access point are decoded.
1638
 *  If the random access point is none of the above, a warning is issues, and decoding of pictures with POC
1639
 *  equal to or greater than the random access point POC is attempted. For non IDR/CRA/BLA random
1640
 *  access point there is no guarantee that the decoder will not crash.
1641
 */
1642
bool DecLibParser::isRandomAccessSkipPicture()
1643
0
{
1644
0
  if( m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_W_RADL || m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_N_LP )
1645
0
  {
1646
0
    m_pocRandomAccess = -MAX_INT;   // no need to skip the reordered pictures in IDR, they are decodable.
1647
0
  }
1648
0
  else if( m_pocRandomAccess == MAX_INT )   // start of random access point, m_pocRandomAccess has not been set yet.
1649
0
  {
1650
0
#if GDR_ADJ
1651
0
    if( m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA || m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR )
1652
#else
1653
    if( m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA )
1654
#endif
1655
0
    {
1656
      // set the POC random access since we need to skip the reordered pictures in the case of CRA/CRANT/BLA/BLANT.
1657
0
      m_pocRandomAccess = m_apcSlicePilot->getPOC();
1658
0
    }
1659
0
    else
1660
0
    {
1661
0
      if( !m_warningMessageSkipPicture )
1662
0
      {
1663
0
        msg( WARNING, "Warning: this is not a valid random access point and the data is discarded until the first CRA picture\n" );
1664
0
        m_warningMessageSkipPicture = true;
1665
0
      }
1666
0
      return true;
1667
0
    }
1668
0
  }
1669
  // skip the reordered pictures, if necessary
1670
0
  else if( m_apcSlicePilot->getPOC() < m_pocRandomAccess && ( m_apcSlicePilot->getNalUnitType() == NAL_UNIT_CODED_SLICE_RASL ) )
1671
0
  {
1672
0
    return true;
1673
0
  }
1674
  // if we reach here, then the picture is not skipped.
1675
0
  return false;
1676
0
}
1677
1678
void DecLibParser::xCheckMixedNalUnit( Slice* pcSlice, const InputNALUnit& nalu )
1679
0
{
1680
0
  if( pcSlice->getPPS()->getMixedNaluTypesInPicFlag() )
1681
0
  {
1682
0
    CHECK(pcSlice->getPPS()->getNumSlicesInPic() < 2, "mixed nal unit type picture, but with less than 2 slices");
1683
1684
0
    CHECK( pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR, "picture with mixed NAL unit type cannot have GDR slice");
1685
1686
    //Check that if current slice is IRAP type, the other type of NAL can only be TRAIL_NUT
1687
0
    if( pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_W_RADL
1688
0
        || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_N_LP
1689
0
        || pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA )
1690
0
    {
1691
0
      for( int i = 0; i < m_uiSliceSegmentIdx; i++ )
1692
0
      {
1693
0
        Slice* preSlice = m_pcParsePic->slices[i];
1694
0
        CHECK( pcSlice->getNalUnitType() != preSlice->getNalUnitType()
1695
0
                 && preSlice->getNalUnitType() != NAL_UNIT_CODED_SLICE_TRAIL,
1696
0
               "In a mixed NAL unt type picture, an IRAP slice can be mixed with Trail slice(s) only" );
1697
0
      }
1698
0
    }
1699
1700
    // if this is the last slice of the picture, check whether that there are at least two different NAL unit types in the picture
1701
0
    if( pcSlice->getPPS()->getNumSlicesInPic() == (m_uiSliceSegmentIdx + 1) )
1702
0
    {
1703
0
      bool hasDiffTypes = false;
1704
0
      for( int i = 1; !hasDiffTypes && i <= m_uiSliceSegmentIdx; i++ )
1705
0
      {
1706
0
        Slice* slice1 = m_pcParsePic->slices[i-1];
1707
0
        Slice* slice2 = m_pcParsePic->slices[i];
1708
0
        if( slice1->getNalUnitType() != slice2->getNalUnitType())
1709
0
        {
1710
0
          hasDiffTypes = true;
1711
0
        }
1712
0
      }
1713
0
      CHECK( !hasDiffTypes, "VCL NAL units of the picture shall have two or more different nal_unit_type values");
1714
0
    }
1715
0
  }
1716
0
  else   // all slices shall have the same nal unit type
1717
0
  {
1718
0
    bool sameNalUnitType = true;
1719
0
    for( int i = 0; i < m_uiSliceSegmentIdx; i++ )
1720
0
    {
1721
0
      Slice* PreSlice = m_pcParsePic->slices[i];
1722
0
      if( PreSlice->getNalUnitType() != pcSlice->getNalUnitType() )
1723
0
      {
1724
0
        sameNalUnitType = false;
1725
0
      }
1726
0
    }
1727
0
    CHECK( !sameNalUnitType, "mixed_nalu_types_in_pic_flag is zero, but have different nal unit types" );
1728
0
  }
1729
0
}
1730
1731
}   // namespace vvdec