Coverage Report

Created: 2026-04-01 07:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vvdec/source/Lib/DecoderLib/DecLibRecon.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     DecLibRecon.cpp
44
    \brief    decoder class
45
*/
46
47
#include "DecLib.h"
48
49
#include "CommonLib/TrQuant.h"
50
#if ENABLE_SIMD_TCOEFF_OPS
51
#include "CommonLib/TrQuant_EMT.h"
52
#endif
53
#include "CommonLib/InterPrediction.h"
54
#include "CommonLib/IntraPrediction.h"
55
#include "CommonLib/Unit.h"
56
#include "CommonLib/Buffer.h"
57
#include "CommonLib/UnitTools.h"
58
59
#include "CommonLib/dtrace_next.h"
60
#include "CommonLib/dtrace_buffer.h"
61
62
namespace vvdec
63
{
64
65
#ifdef TRACE_ENABLE_ITT
66
extern __itt_domain*              itt_domain_dec;
67
extern std::vector<__itt_domain*> itt_domain_decInst;
68
69
extern __itt_string_handle* itt_handle_alf;
70
extern __itt_string_handle* itt_handle_presao;
71
extern __itt_string_handle* itt_handle_sao;
72
extern __itt_string_handle* itt_handle_lfl;
73
extern __itt_string_handle* itt_handle_intra;
74
extern __itt_string_handle* itt_handle_inter;
75
extern __itt_string_handle* itt_handle_mider;
76
extern __itt_string_handle* itt_handle_lfcl;
77
extern __itt_string_handle* itt_handle_ext;
78
extern __itt_string_handle* itt_handle_dmvr;
79
extern __itt_string_handle* itt_handle_rsp;
80
81
extern __itt_string_handle* itt_handle_schedTasks;
82
extern __itt_string_handle* itt_handle_waitTasks;
83
84
// create global domain for DecLib
85
extern __itt_domain* itt_domain_glb;
86
// create a global counter
87
extern __itt_counter itt_frame_counter;
88
89
#define ITT_TASKSTART( d, t ) __itt_task_begin( ( d ), __itt_null, __itt_null, ( t ) )
90
#define ITT_TASKEND( d, t )   __itt_task_end  ( ( d ) )
91
#else
92
#define ITT_TASKSTART( d, t )
93
#define ITT_TASKEND( d, t )
94
#endif
95
96
//! \ingroup DecoderLib
97
//! \{
98
99
void CommonTaskParam::reset( CodingStructure& cs, TaskType ctuStartState, int tasksPerLine, bool _doALF )
100
0
{
101
0
  this->cs = &cs;
102
103
0
  const int heightInCtus = cs.pcv->heightInCtus;
104
0
  CHECKD( !ctuStates.empty() && std::any_of( ctuStates.begin(), ctuStates.end(), []( CtuState& s ) { return s != DONE; } ), "some CTUs of previous pic not done" );
105
0
  ctuStates = std::vector<CtuState>( heightInCtus * tasksPerLine );
106
0
  for( auto& ctu: ctuStates )
107
0
  {
108
0
    ctu.store( ctuStartState );
109
0
  }
110
0
  perLineMiHist = std::vector<MotionHist>( heightInCtus );
111
0
  doALF         = _doALF;
112
0
}
113
114
DecLibRecon::DecLibRecon()
115
0
{
116
0
#if ENABLE_SIMD_OPT_BUFFER
117
0
#  if defined( TARGET_SIMD_X86 )
118
0
  g_pelBufOP.initPelBufOpsX86();
119
0
#  endif
120
#  if defined( TARGET_SIMD_ARM )
121
  g_pelBufOP.initPelBufOpsARM();
122
#  endif
123
0
#endif
124
0
#if ENABLE_SIMD_TCOEFF_OPS && defined( TARGET_SIMD_X86 )
125
0
  g_tCoeffOps.initTCoeffOpsX86();
126
0
#endif
127
0
}
128
129
void DecLibRecon::create( ThreadPool* threadPool, unsigned instanceId, bool upscaleOutputEnabled )
130
0
{
131
  // run constructor again to ensure all variables, especially in DecLibParser have been reset
132
0
  this->~DecLibRecon();
133
0
  new( this ) DecLibRecon;
134
135
136
#if TRACE_ENABLE_ITT
137
  if( itt_domain_decInst.size() < instanceId + 1 )
138
  {
139
    std::string name( "DecLibRecon " + std::to_string( instanceId ) );
140
    itt_domain_decInst.push_back( __itt_domain_create( name.c_str() ) );
141
    itt_domain_decInst.back()->flags = 1;
142
143
    CHECK_FATAL( itt_domain_decInst.back() != itt_domain_decInst[instanceId], "current decLibRecon ITT-Domain is not the last in vector. Instances created in the wrong order?" );
144
  }
145
  m_itt_decInst = itt_domain_decInst[instanceId];
146
#endif
147
148
0
  m_decodeThreadPool = threadPool;
149
0
  m_numDecThreads    = std::max( 1, threadPool ? threadPool->numThreads() : 1 );
150
151
0
  m_upscaleOutputEnabled = upscaleOutputEnabled;
152
0
  m_predBufSize     = 0;
153
0
  m_dmvrMvCacheSize = 0;
154
0
  m_dmvrMvCache     = nullptr;
155
156
0
  m_num4x4Elements   = 0;
157
0
  m_loopFilterParam  = nullptr;
158
0
  m_motionInfo       = nullptr;
159
160
0
  m_pcThreadResource    = new PerThreadResource*[m_numDecThreads];
161
0
  m_pcThreadResource[0] = new PerThreadResource();
162
0
  for( int i = 1; i < m_numDecThreads; i++ )
163
0
  {
164
0
    m_pcThreadResource[i] = new PerThreadResource( m_pcThreadResource[0]->m_cTrQuant );
165
0
  }
166
0
}
167
168
void DecLibRecon::destroy()
169
0
{
170
0
  m_decodeThreadPool = nullptr;
171
172
0
  if( m_predBuf )
173
0
  {
174
0
    m_predBuf.reset();
175
0
    m_predBufSize = 0;
176
0
  }
177
178
0
  if( m_dmvrMvCache )
179
0
  {
180
0
    free( m_dmvrMvCache );
181
0
    m_dmvrMvCache = nullptr;
182
0
    m_dmvrMvCacheSize = 0;
183
0
  }
184
185
0
  if( m_loopFilterParam )
186
0
  {
187
0
    free( m_loopFilterParam );
188
0
    m_loopFilterParam = nullptr;
189
0
  }
190
191
0
  if( m_motionInfo )
192
0
  {
193
0
    free( m_motionInfo );
194
0
    m_motionInfo = nullptr;
195
0
  }
196
197
0
  m_num4x4Elements = 0;
198
199
0
  for( int i = 0; i < m_numDecThreads; i++ ) delete m_pcThreadResource[i];
200
0
  delete[] m_pcThreadResource; m_pcThreadResource = nullptr;
201
0
}
202
203
204
static void getCompatibleBuffer( const CodingStructure& cs, const CPelUnitBuf& srcBuf, PelStorage& destBuf, const UserAllocator* userAllocator )
205
0
{
206
0
  if( !destBuf.bufs.empty() )
207
0
  {
208
0
    bool compat = false;
209
0
    if( destBuf.chromaFormat == srcBuf.chromaFormat )
210
0
    {
211
0
      compat = true;
212
0
      const uint32_t numCh = getNumberValidComponents( srcBuf.chromaFormat );
213
0
      for( uint32_t i = 0; i < numCh; i++ )
214
0
      {
215
        // check this otherwise it would turn out to get very weird
216
0
        compat &= destBuf.get( ComponentID( i ) )         == srcBuf.get( ComponentID( i ) );
217
0
        compat &= destBuf.get( ComponentID( i ) ).stride  == srcBuf.get( ComponentID( i ) ).stride;
218
0
        compat &= destBuf.get( ComponentID( i ) ).width   == srcBuf.get( ComponentID( i ) ).width;
219
0
        compat &= destBuf.get( ComponentID( i ) ).height  == srcBuf.get( ComponentID( i ) ).height;
220
0
      }
221
0
    }
222
0
    if( !compat )
223
0
    {
224
0
      destBuf.destroy();
225
0
    }
226
0
  }
227
0
  if( destBuf.bufs.empty() )
228
0
  {
229
0
    destBuf.create( cs.picture->chromaFormat, cs.picture->lumaSize(), cs.pcv->maxCUWidth, cs.picture->margin, MEMORY_ALIGN_DEF_SIZE, true, userAllocator );
230
0
  }
231
0
}
232
233
void DecLibRecon::borderExtPic( Picture* pic, const Picture* currPic )
234
0
{
235
  // we block and wait here, so the exceptions from the reference pic don't propagate to the current picture
236
0
  pic->waitForAllTasks();
237
0
  if( pic->progress < Picture::reconstructed )   // an exception must have happended in the picture, so we need to clean it up
238
0
  {
239
0
    CHECK_FATAL( pic->progress < Picture::parsing, "Slice parsing should have started, so all structures are there" );
240
0
    try
241
0
    {
242
0
      pic->reconDone.checkAndRethrowException();
243
0
      pic->parseDone.checkAndRethrowException();  // when the error happened in the slice parsing tasks, there might not be an exception in recon done, so check parseDone also
244
0
    }
245
0
    catch( ... )
246
0
    {
247
0
      pic->error = true;
248
0
      pic->reconDone.clearException();
249
      // TODO: for now we set it on parseDone, so we can handle it outside:
250
0
      if( !pic->parseDone.hasException() )
251
0
      {
252
0
        pic->parseDone.setException( std::current_exception() );
253
0
      }
254
255
0
      pic->fillGrey( currPic->cs->sps.get() );
256
0
    }
257
0
  }
258
259
0
  pic->borderExtStarted = true;
260
261
0
  const bool wrapAround = pic->cs->sps->getUseWrapAround();
262
0
  if( wrapAround )
263
0
  {
264
    // copy reconstruction buffer to wrapAround buffer. All other border-extension tasks depend on this task.
265
0
    static auto copyTask = []( int, Picture* picture ) {
266
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_ext );
267
0
      picture->getRecoBuf( true ).copyFrom( picture->getRecoBuf() );
268
0
      ITT_TASKEND( itt_domain_dec, itt_handle_ext );
269
0
      return true;
270
0
    };
271
0
    pic->m_copyWrapBufDone.lock();
272
0
    m_decodeThreadPool->addBarrierTask<Picture>( TP_TASK_NAME_ARG( "POC:" + std::to_string( currPic->poc ) + " copyTask Ref-POC:" + std::to_string( pic->poc ) )
273
0
                                                 copyTask,
274
0
                                                 pic,
275
0
                                                 &pic->m_borderExtTaskCounter,
276
0
                                                 &pic->m_copyWrapBufDone,
277
0
                                                 { &pic->reconDone } );
278
0
  }
279
280
  // start actual border extension tasks
281
0
  {
282
0
    static auto task = []( int, Picture* picture ) {
283
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_ext );
284
0
      picture->extendPicBorder( true, false, false, false );
285
0
      ITT_TASKEND( itt_domain_dec, itt_handle_ext );
286
0
      return true;
287
0
    };
288
0
    m_decodeThreadPool->addBarrierTask<Picture>( TP_TASK_NAME_ARG( "POC:" + std::to_string(currPic->poc) + " borderExtTask T Ref-POC:" + std::to_string(pic->poc) )
289
0
                                                 task,
290
0
                                                 pic,
291
0
                                                 &pic->m_borderExtTaskCounter,
292
0
                                                 nullptr,
293
0
                                                 { wrapAround ? &pic->m_copyWrapBufDone : &pic->reconDone } );
294
0
  }
295
296
0
  {
297
0
    static auto task = []( int, Picture* picture ) {
298
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_ext );
299
0
      picture->extendPicBorder( false, true, false, false );
300
0
      ITT_TASKEND( itt_domain_dec, itt_handle_ext );
301
0
      return true;
302
0
    };
303
0
    m_decodeThreadPool->addBarrierTask<Picture>( TP_TASK_NAME_ARG( "POC:" + std::to_string(currPic->poc) + " borderExtTask B Ref-POC:" + std::to_string(pic->poc) )
304
0
                                                 task,
305
0
                                                 pic,
306
0
                                                 &pic->m_borderExtTaskCounter,
307
0
                                                 nullptr,
308
0
                                                 { wrapAround ? &pic->m_copyWrapBufDone : &pic->reconDone } );
309
0
  }
310
311
0
  {
312
0
    static auto task = []( int, Picture* picture ) {
313
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_ext );
314
0
      picture->extendPicBorder( false, false, true, false, CH_L );
315
0
      ITT_TASKEND( itt_domain_dec, itt_handle_ext );
316
0
      return true;
317
0
    };
318
0
    m_decodeThreadPool->addBarrierTask<Picture>( TP_TASK_NAME_ARG( "POC:" + std::to_string(currPic->poc) + " borderExtTask ltT Ref-POC:" + std::to_string(pic->poc) )
319
0
                                                 task,
320
0
                                                 pic,
321
0
                                                 &pic->m_borderExtTaskCounter,
322
0
                                                 nullptr,
323
0
                                                 { wrapAround ? &pic->m_copyWrapBufDone : &pic->reconDone } );
324
0
  }
325
0
  {
326
0
    static auto task = []( int, Picture* picture ) {
327
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_ext );
328
0
      picture->extendPicBorder( false, false, false, true, CH_L );
329
0
      ITT_TASKEND( itt_domain_dec, itt_handle_ext );
330
0
      return true;
331
0
    };
332
0
    m_decodeThreadPool->addBarrierTask<Picture>( TP_TASK_NAME_ARG( "POC:" + std::to_string(currPic->poc) + " borderExtTask lrB Y Ref-POC:" + std::to_string(pic->poc) )
333
0
                                                 task,
334
0
                                                 pic,
335
0
                                                 &pic->m_borderExtTaskCounter,
336
0
                                                 nullptr,
337
0
                                                 { wrapAround ? &pic->m_copyWrapBufDone : &pic->reconDone } );
338
0
  }
339
340
0
  {
341
0
    static auto task = []( int, Picture* picture ) {
342
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_ext );
343
0
      picture->extendPicBorder( false, false, true, false, CH_C );
344
0
      ITT_TASKEND( itt_domain_dec, itt_handle_ext );
345
0
      return true;
346
0
    };
347
0
    m_decodeThreadPool->addBarrierTask<Picture>( TP_TASK_NAME_ARG( "POC:" + std::to_string(currPic->poc) + " borderExtTask lrB UV Ref-POC:" + std::to_string(pic->poc) )
348
0
                                                 task,
349
0
                                                 pic,
350
0
                                                 &pic->m_borderExtTaskCounter,
351
0
                                                 nullptr,
352
0
                                                 { wrapAround ? &pic->m_copyWrapBufDone : &pic->reconDone } );
353
0
  }
354
0
  {
355
0
    static auto task = []( int, Picture* picture ) {
356
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_ext );
357
0
      picture->extendPicBorder( false, false, false, true, CH_C );
358
0
      ITT_TASKEND( itt_domain_dec, itt_handle_ext );
359
0
      return true;
360
0
    };
361
0
    m_decodeThreadPool->addBarrierTask<Picture>( TP_TASK_NAME_ARG( "POC:" + std::to_string(currPic->poc) + " borderExtTask lrB UV Ref-POC:" + std::to_string(pic->poc) )
362
0
                                                 task,
363
0
                                                 pic,
364
0
                                                 &pic->m_borderExtTaskCounter,
365
0
                                                 nullptr,
366
0
                                                 { wrapAround ? &pic->m_copyWrapBufDone : &pic->reconDone } );
367
0
  }
368
0
}
369
370
void DecLibRecon::createSubPicRefBufs( Picture* pic, const Picture* currPic )
371
0
{
372
0
  pic->subPicExtStarted = true;
373
374
0
  const PPS* pps       = pic->cs->pps.get();
375
0
  const SPS* sps       = pic->cs->sps.get();
376
0
  const int  numSubPic = pps->getNumSubPics();
377
378
0
  pic->m_subPicRefBufs.resize( numSubPic );
379
0
  for( int i = 0; i < numSubPic; ++i )
380
0
  {
381
0
    const SubPic& currSubPic = pps->getSubPic( i );
382
0
    const Area    subPicArea( currSubPic.getSubPicLeft(),
383
0
                              currSubPic.getSubPicTop(),
384
0
                              currSubPic.getSubPicWidthInLumaSample(),
385
0
                              currSubPic.getSubPicHeightInLumaSample() );
386
387
0
    pic->m_subPicRefBufs[i].create( pic->chromaFormat, Size( subPicArea ), sps->getMaxCUWidth(), pic->margin, MEMORY_ALIGN_DEF_SIZE );
388
389
0
    static auto task = []( int, SubPicExtTask* t ) {
390
0
      t->subPicBuf->copyFrom( t->picture->getRecoBuf().subBuf( t->subPicArea ) );
391
0
      t->picture->extendPicBorderBuf( *t->subPicBuf );
392
0
      return true;
393
0
    };
394
0
    m_subPicExtTasks.emplace_back( SubPicExtTask{ pic, &pic->m_subPicRefBufs[i], subPicArea } );
395
0
    m_decodeThreadPool->addBarrierTask<SubPicExtTask>( TP_TASK_NAME_ARG( "POC:" + std::to_string( currPic->poc ) + " subPicBorderExtTask refPOC:" + std::to_string( pic->poc ) )
396
0
                                                       task,
397
0
                                                       &m_subPicExtTasks.back(),
398
0
                                                       &pic->m_borderExtTaskCounter,
399
0
                                                       nullptr,
400
0
                                                       { &pic->reconDone } );
401
0
  }
402
0
}
403
404
void DecLibRecon::swapBufs( CodingStructure& cs )
405
0
{
406
0
  cs.picture->m_bufs[PIC_RECONSTRUCTION].swap( m_fltBuf );
407
0
  cs.rebindPicBufs();   // ensure the recon buf in the coding structure points to the correct buffer
408
0
}
409
410
void DecLibRecon::decompressPicture( Picture* pcPic )
411
0
{
412
0
  m_currDecompPic = pcPic;
413
414
0
  CodingStructure& cs = *pcPic->cs;
415
416
0
  pcPic->progress = Picture::reconstructing;
417
418
#ifdef TRACE_ENABLE_ITT
419
  // mark start of frame
420
    pcPic->m_itt_decLibInst = m_itt_decInst;
421
  __itt_frame_begin_v3( pcPic->m_itt_decLibInst, nullptr );
422
#endif
423
424
  // Initialise the various objects for the new set of settings
425
0
  const SPS * sps = cs.sps.get();
426
0
  const PPS * pps = cs.pps.get();
427
428
0
  for( int i = 0; i < m_numDecThreads; i++ )
429
0
  {
430
0
    if( sps->getUseReshaper() )
431
0
    {
432
0
      m_pcThreadResource[i]->m_cReshaper.createDec( sps->getBitDepth() );
433
0
      m_pcThreadResource[i]->m_cReshaper.initSlice( pcPic->slices[0]->getNalUnitLayerId(), *pcPic->slices[0]->getPicHeader(), pcPic->slices[0]->getVPS_nothrow() );
434
0
    }
435
436
0
    m_pcThreadResource[i]->m_cIntraPred.init( sps->getChromaFormatIdc(), sps->getBitDepth() );
437
0
    m_pcThreadResource[i]->m_cInterPred.init( &m_cRdCost, sps->getChromaFormatIdc(), sps->getMaxCUHeight() );
438
439
    // Recursive structure
440
0
    m_pcThreadResource[i]->m_cTrQuant.init( pcPic );
441
0
    m_pcThreadResource[i]->m_cCuDecoder.init( &m_pcThreadResource[i]->m_cIntraPred, &m_pcThreadResource[i]->m_cInterPred, &m_pcThreadResource[i]->m_cReshaper, &m_pcThreadResource[i]->m_cTrQuant );
442
0
  }
443
444
0
  getCompatibleBuffer( *pcPic->cs, pcPic->cs->getRecoBuf(), m_fltBuf, pcPic->getUserAllocator() );
445
446
0
  const uint32_t  log2SaoOffsetScale = (uint32_t) std::max(0, sps->getBitDepth() - MAX_SAO_TRUNCATED_BITDEPTH);
447
0
  const int maxDepth = getLog2(sps->getMaxCUWidth()) - pps->pcv->minCUWidthLog2;
448
0
  m_cSAO.create( pps->getPicWidthInLumaSamples(),
449
0
                 pps->getPicHeightInLumaSamples(),
450
0
                 sps->getChromaFormatIdc(),
451
0
                 sps->getMaxCUWidth(),
452
0
                 sps->getMaxCUHeight(),
453
0
                 maxDepth,
454
0
                 log2SaoOffsetScale,
455
0
                 m_fltBuf
456
0
               );
457
458
0
  if( sps->getUseALF() )
459
0
  {
460
0
    m_cALF.create( cs.picHeader.get(), sps, pps, m_numDecThreads, m_fltBuf );
461
0
  }
462
463
0
  const PreCalcValues* pcv = cs.pcv;
464
465
  // set reconstruction buffers in CodingStructure
466
0
  const ptrdiff_t ctuSampleSizeL = pcv->maxCUHeight * pcv->maxCUWidth;
467
0
  const ptrdiff_t ctuSampleSizeC = isChromaEnabled( pcv->chrFormat ) ? ( ctuSampleSizeL >> ( getChannelTypeScaleX( CH_C, pcv->chrFormat ) + getChannelTypeScaleY( CH_C, pcv->chrFormat ) ) ) : 0;
468
0
  const ptrdiff_t ctuSampleSize  = ctuSampleSizeL + 2 * ctuSampleSizeC;
469
0
  const size_t    predBufSize    = ctuSampleSize * pcv->sizeInCtus;
470
0
  if( predBufSize != m_predBufSize )
471
0
  {
472
0
    m_predBuf.reset( ( Pel* ) xMalloc( Pel, predBufSize ) );
473
0
    m_predBufSize = predBufSize;
474
0
  }
475
476
0
  pcPic->cs->m_predBuf = m_predBuf.get();
477
478
  // for the worst case of all PUs being 8x8 and using DMVR
479
0
  const size_t _maxNumDmvrMvs = pcv->num8x8CtuBlks * pcv->sizeInCtus;
480
0
  if( _maxNumDmvrMvs != m_dmvrMvCacheSize )
481
0
  {
482
0
    if( m_dmvrMvCache ) free( m_dmvrMvCache );
483
0
    m_dmvrMvCacheSize = _maxNumDmvrMvs;
484
0
    m_dmvrMvCache     = ( Mv* ) malloc( sizeof( Mv ) * _maxNumDmvrMvs );
485
0
  }
486
487
0
  pcPic->cs->m_dmvrMvCache = m_dmvrMvCache;
488
489
0
  if( m_num4x4Elements != cs.pcv->num4x4CtuBlks * cs.pcv->sizeInCtus )
490
0
  {
491
0
    if( m_loopFilterParam ) free( m_loopFilterParam );
492
0
    if( m_motionInfo      ) free( m_motionInfo );
493
494
0
    m_num4x4Elements = cs.pcv->num4x4CtuBlks * cs.pcv->sizeInCtus;
495
496
0
    m_loopFilterParam = ( LoopFilterParam* ) malloc( sizeof( LoopFilterParam ) * m_num4x4Elements * 2 );
497
0
    m_motionInfo      = ( MotionInfo* )      malloc( sizeof( MotionInfo      ) * m_num4x4Elements );
498
0
  }
499
  // finished
500
501
0
  const int widthInCtus  = cs.pcv->widthInCtus;
502
0
  const int heightInCtus = cs.pcv->heightInCtus;
503
504
0
  if( sps->getIBCFlag() )
505
0
  {
506
0
    cs.initVIbcBuf( heightInCtus, sps->getChromaFormatIdc(), sps->getMaxCUHeight() );
507
0
  }
508
0
  pcPic->startProcessingTimer();
509
510
0
  if( m_decodeThreadPool->numThreads() > 0 )
511
0
  {
512
0
    ITT_TASKSTART( itt_domain_dec, itt_handle_schedTasks );
513
0
  }
514
515
0
  picBarriers.clear();
516
0
#if ALLOW_MIDER_LF_DURING_PICEXT
517
0
  CBarrierVec  picExtBarriers;
518
#else
519
  CBarrierVec &picExtBarriers = picBarriers;
520
#endif
521
522
0
  const int numSubPic = cs.pps->getNumSubPics();
523
0
  if( numSubPic > 1 )
524
0
  {
525
0
    m_subPicExtTasks.clear();
526
0
    m_subPicExtTasks.reserve( pcPic->slices.size() * MAX_NUM_REF_PICS * numSubPic );
527
0
  }
528
529
0
  std::vector<Picture*> borderExtRefPics( pcPic->buildAllRefPicsVec() );
530
0
  for( Picture* refPic : borderExtRefPics )
531
0
  {
532
0
    if( !refPic->borderExtStarted )
533
0
    {
534
      // TODO: (GH) Can we bypass this border extension, when all subpics (>1) are treated as pics?
535
0
      borderExtPic( refPic, pcPic );
536
0
    }
537
538
0
    if( !refPic->subPicExtStarted && numSubPic > 1 && refPic->m_subPicRefBufs.size() != numSubPic )
539
0
    {
540
0
      CHECK( !refPic->m_subPicRefBufs.empty(), "Wrong number of subpics already present in reference picture" );
541
0
      CHECK( cs.sps->getUseWrapAround(), "Wraparound + subpics not implemented" );
542
543
0
      createSubPicRefBufs( refPic, pcPic );
544
0
    }
545
546
0
    if( refPic->m_borderExtTaskCounter.isBlocked() &&
547
0
        std::find( picExtBarriers.cbegin(), picExtBarriers.cend(), refPic->m_borderExtTaskCounter.donePtr() ) == picExtBarriers.cend() )
548
0
    {
549
0
      picExtBarriers.push_back( refPic->m_borderExtTaskCounter.donePtr() );
550
0
    }
551
0
  }
552
553
0
  if( m_decodeThreadPool->numThreads() == 0 && (
554
0
       std::any_of( picExtBarriers.cbegin(), picExtBarriers.cend(), []( const Barrier* b ) { return b->isBlocked(); } ) ||
555
0
       std::any_of( picBarriers   .cbegin(), picBarriers   .cend(), []( const Barrier* b ) { return b->isBlocked(); } ) ) )
556
0
  {
557
0
    m_decodeThreadPool->processTasksOnMainThread();
558
0
  }
559
560
0
  const bool isIntra = std::all_of( pcPic->slices.begin(), pcPic->slices.end(), []( const Slice* pcSlice ) { return pcSlice->isIntra(); } );
561
562
0
  const int numColPerTask = std::max( std::min( widthInCtus, ( widthInCtus / std::max( m_numDecThreads * ( isIntra ? 2 : 1 ), 1 ) ) + ( isIntra ? 0 : 1 ) ), 1 );
563
0
  const int numTasksPerLine = widthInCtus / numColPerTask + !!( widthInCtus % numColPerTask );
564
565
0
#if ALLOW_MIDER_LF_DURING_PICEXT
566
0
  pcPic->refPicExtDepBarriers = std::move( picExtBarriers );
567
0
#endif
568
#if !RECO_WHILE_PARSE
569
  picBarriers.push_back( &cs.picture->parseDone );
570
#endif
571
572
0
  const TaskType ctuStartState = MIDER;
573
0
  const bool     doALF         = cs.sps->getUseALF() && !AdaptiveLoopFilter::getAlfSkipPic( cs );
574
0
  commonTaskParam.reset( cs, ctuStartState, numTasksPerLine, doALF );
575
576
0
  tasksFinishMotion = std::vector<LineTaskParam>( heightInCtus, LineTaskParam{ commonTaskParam, -1 } );
577
0
  tasksCtu          = std::vector<CtuTaskParam >( heightInCtus * numTasksPerLine, CtuTaskParam{ commonTaskParam, -1, -1, {} } );
578
579
0
  pcPic->reconDone.lock();
580
581
#if 0
582
  // schedule in raster scan order
583
  for( int line = 0; line < heightInCtus; ++line )
584
  {
585
    for( int col = 0; col < widthInCtus;  ++col )
586
    {
587
#else
588
  // schedule in zig-zag scan order
589
0
  for( int i = 0; i < numTasksPerLine + heightInCtus; ++i )
590
0
  {
591
0
    int line = 0;
592
0
    for( int col = i; col >= 0; --col, ++line )
593
0
    {
594
0
#endif
595
0
      if( line < heightInCtus && col < numTasksPerLine )
596
0
      {
597
0
        CBarrierVec ctuBarriesrs = picBarriers;
598
0
        const int   ctuStart     = col * numColPerTask;
599
0
        const int   ctuEnd       = std::min( ctuStart + numColPerTask, widthInCtus );
600
601
0
#if RECO_WHILE_PARSE
602
        // wait for the last CTU in the current line to be parsed
603
0
        ctuBarriesrs.push_back( &pcPic->ctuParsedBarrier[( line + 1 ) * widthInCtus - 1] );
604
605
0
#endif
606
0
        CtuTaskParam* param    = &tasksCtu[line * numTasksPerLine + col];
607
0
        param->taskLine        = line;
608
0
        param->taskCol         = col;
609
0
        param->ctuEnd          = ctuEnd;
610
0
        param->ctuStart        = ctuStart;
611
0
        param->numColPerTask   = numColPerTask;
612
0
        param->numTasksPerLine = numTasksPerLine;
613
614
0
        m_decodeThreadPool->addBarrierTask<CtuTaskParam>( TP_TASK_NAME_ARG( "POC:" + std::to_string(pcPic->poc) + " ctuTask:" + std::to_string( col ) + "," + std::to_string( line ) )
615
0
                                                          ctuTask<false>,
616
0
                                                          param,
617
0
                                                          &pcPic->m_ctuTaskCounter,
618
0
                                                          nullptr,
619
0
                                                          std::move( ctuBarriesrs ),
620
0
                                                          ctuTask<true> );
621
0
      }
622
0
    }
623
0
  }
624
625
0
  {
626
0
    static auto finishReconTask = []( int, FinishPicTaskParam* param )
627
0
    {
628
0
      CodingStructure& cs = *param->pic->cs;
629
630
0
      if( cs.sps->getUseALF() && !AdaptiveLoopFilter::getAlfSkipPic( cs ) )
631
0
      {
632
0
        param->decLib->swapBufs( cs );
633
0
      }
634
635
0
      cs.deallocTempInternals();
636
637
#ifdef TRACE_ENABLE_ITT
638
      // mark end of frame
639
      __itt_frame_end_v3( param->pic->m_itt_decLibInst, nullptr );
640
#endif
641
0
      param->pic->stopProcessingTimer();
642
643
0
      param->pic->progress = Picture::reconstructed;
644
0
      return true;
645
0
    };
646
647
0
    taskFinishPic = FinishPicTaskParam( this, pcPic );
648
0
    m_decodeThreadPool->addBarrierTask<FinishPicTaskParam>( TP_TASK_NAME_ARG( "POC:" + std::to_string( pcPic->poc ) + " finishPicTask" )
649
0
                                                            finishReconTask,
650
0
                                                            &taskFinishPic,
651
0
                                                            &pcPic->m_divTasksCounter,
652
0
                                                            &pcPic->reconDone,
653
0
                                                            { pcPic->m_ctuTaskCounter.donePtr() } );
654
0
  }
655
656
0
  if( m_decodeThreadPool->numThreads() == 0 )
657
0
  {
658
0
  }
659
0
  else
660
0
  {
661
0
    ITT_TASKEND( itt_domain_dec, itt_handle_schedTasks );
662
0
  }
663
0
}
664
665
Picture* DecLibRecon::waitForPrevDecompressedPic()
666
0
{
667
0
  if( !m_currDecompPic )
668
0
    return nullptr;
669
670
0
  ITT_TASKSTART( itt_domain_dec, itt_handle_waitTasks );
671
0
  if( m_decodeThreadPool->numThreads() == 0 )
672
0
  {
673
0
    m_decodeThreadPool->processTasksOnMainThread();
674
0
    CHECK_FATAL( m_currDecompPic->reconDone.isBlocked(), "can't make progress. some dependecy has not been finished" );
675
0
  }
676
677
0
  try
678
0
  {
679
0
    m_currDecompPic->reconDone.wait();
680
0
  }
681
0
  catch( ... )
682
0
  {
683
0
    m_currDecompPic->error = true;
684
0
  }
685
686
  // also check error flag, which can have been set earlier (e.g., when trying to use the picture as reference)
687
0
  if( m_currDecompPic->error || m_currDecompPic->reconDone.hasException() )
688
0
  {
689
    // ensure all tasks are cleared from declibRecon
690
0
    cleanupOnException( std::current_exception() );
691
0
  }
692
693
0
  ITT_TASKEND( itt_domain_dec, itt_handle_waitTasks );
694
695
0
  return std::exchange( m_currDecompPic, nullptr );
696
0
}
697
698
void DecLibRecon::cleanupOnException( std::exception_ptr exception )
699
0
{
700
  // there was an exception anywhere in m_currDecompPic
701
  // => we need to wait for all tasks to be cleared from the thread pool
702
0
  m_currDecompPic->waitForAllTasks();
703
704
0
  commonTaskParam.ctuStates.clear();
705
0
}
706
707
template<bool onlyCheckReadyState>
708
bool DecLibRecon::ctuTask( int tid, CtuTaskParam* param )
709
0
{
710
0
  const int       taskCol      = param->taskCol;
711
0
  const int       line         = param->taskLine;
712
0
  const int       col          = taskCol;
713
714
0
  auto&           cs           = *param->common.cs;
715
0
  auto&           decLib       = param->common.decLib;
716
0
  const int       tasksPerLine = param->numTasksPerLine;
717
0
  const int       heightInCtus = cs.pcv->heightInCtus;
718
719
0
  CtuState&       thisCtuState =  param->common.ctuStates[line * tasksPerLine + taskCol];
720
0
  const CtuState* thisLine     = &param->common.ctuStates[line * tasksPerLine];
721
0
  const CtuState* lineAbove    = thisLine - tasksPerLine;
722
0
  const CtuState* lineBelow    = thisLine + tasksPerLine;
723
724
0
  const int       ctuStart     = param->ctuStart;
725
0
  const int       ctuEnd       = param->ctuEnd;
726
727
0
  try
728
0
  {
729
0
    if( cs.picture->m_ctuTaskCounter.hasException() )
730
0
    {
731
0
      std::rethrow_exception( cs.picture->m_ctuTaskCounter.getException() );
732
0
    }
733
734
0
    switch( thisCtuState.load() )
735
0
    {
736
      // all case statements fall through to continue with next task, unless they return false due to unsatisfied preconditions
737
738
0
    case MIDER:
739
0
    {
740
0
      if( col > 0 && thisLine[col - 1] <= MIDER_cont )
741
0
        return false;
742
0
      if( line > 0 )
743
0
      {
744
0
        if( col + 1 < tasksPerLine )
745
0
        {
746
0
          if( lineAbove[col + 1] <= MIDER )
747
0
            return false;
748
0
        }
749
0
        else
750
0
        {
751
0
          if( lineAbove[col] <= MIDER_cont )
752
0
            return false;
753
0
        }
754
0
      }
755
0
      if( onlyCheckReadyState )
756
0
        return true;
757
758
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_mider );
759
760
0
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
761
0
      {
762
0
        const int ctuRsAddr = ctu + line * cs.pcv->widthInCtus;
763
0
        CtuData& ctuData    = cs.getCtuData( ctuRsAddr );
764
0
        ctuData.motion      = &decLib.m_motionInfo[cs.pcv->num4x4CtuBlks * ctuRsAddr];
765
766
0
        if( !ctuData.slice->isIntra() || cs.sps->getIBCFlag() )
767
0
        {
768
0
          const UnitArea ctuArea = getCtuArea( cs, ctu, line, true );
769
0
          decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskDeriveCtuMotionInfo( cs, ctuRsAddr, ctuArea, param->common.perLineMiHist[line] );
770
0
        }
771
0
        else
772
0
        {
773
0
          memset( NO_WARNING_class_memaccess( ctuData.motion ), MI_NOT_VALID, sizeof( MotionInfo ) * cs.pcv->num4x4CtuBlks );
774
0
        }
775
776
0
        thisCtuState = MIDER_cont;
777
0
      }
778
779
0
      thisCtuState = LF_INIT;
780
781
0
      ITT_TASKEND( itt_domain_dec, itt_handle_mider );
782
0
    }
783
784
0
    case LF_INIT:
785
0
    {
786
0
      if( onlyCheckReadyState )
787
0
        return true;
788
789
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_lfcl );
790
791
0
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
792
0
      {
793
0
        const int ctuRsAddr = ctu + line * cs.pcv->widthInCtus;
794
0
        CtuData& ctuData    = cs.getCtuData( ctuRsAddr );
795
0
        ctuData.lfParam[0]  = &decLib.m_loopFilterParam[cs.pcv->num4x4CtuBlks * ( 2 * ctuRsAddr + 0 )];
796
0
        ctuData.lfParam[1]  = &decLib.m_loopFilterParam[cs.pcv->num4x4CtuBlks * ( 2 * ctuRsAddr + 1 )];
797
0
        memset( ctuData.lfParam[0], 0, sizeof( LoopFilterParam ) * 2 * cs.pcv->num4x4CtuBlks );
798
799
0
        decLib.m_cLoopFilter.calcFilterStrengthsCTU( cs, ctuRsAddr );
800
0
      }
801
802
0
      thisCtuState = INTER;
803
804
0
      ITT_TASKEND( itt_domain_dec, itt_handle_lfcl );
805
0
    }
806
807
0
    case INTER:
808
0
    {
809
0
      if( std::all_of( cs.picture->slices.begin(), cs.picture->slices.end(), []( const Slice* pcSlice ) { return pcSlice->isIntra(); } ) )
Unexecuted instantiation: vvdec::DecLibRecon::ctuTask<false>(int, vvdec::CtuTaskParam*)::{lambda(vvdec::Slice const*)#1}::operator()(vvdec::Slice const*) const
Unexecuted instantiation: vvdec::DecLibRecon::ctuTask<true>(int, vvdec::CtuTaskParam*)::{lambda(vvdec::Slice const*)#1}::operator()(vvdec::Slice const*) const
810
0
      {
811
        // not really necessary, but only for optimizing the wave-fronts
812
0
        if( col > 1 && thisLine[col - 2] <= INTER )
813
0
          return false;
814
0
        if( line > 0 && lineAbove[col] <= INTER )
815
0
          return false;
816
0
      }
817
818
0
      if( std::any_of( cs.picture->refPicExtDepBarriers.cbegin(), cs.picture->refPicExtDepBarriers.cend(), []( const Barrier* b ) { return b->isBlocked(); } ) )
Unexecuted instantiation: vvdec::DecLibRecon::ctuTask<false>(int, vvdec::CtuTaskParam*)::{lambda(vvdec::Barrier const*)#1}::operator()(vvdec::Barrier const*) const
Unexecuted instantiation: vvdec::DecLibRecon::ctuTask<true>(int, vvdec::CtuTaskParam*)::{lambda(vvdec::Barrier const*)#1}::operator()(vvdec::Barrier const*) const
819
0
      {
820
0
        return false;
821
0
      }
822
823
0
      if( onlyCheckReadyState )
824
0
        return true;
825
826
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_inter );
827
828
0
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
829
0
      {
830
0
        const int ctuRsAddr    = ctu + line * cs.pcv->widthInCtus;
831
0
        const UnitArea ctuArea = getCtuArea( cs, ctu, line, true );
832
0
        const CtuData& ctuData = cs.getCtuData( ctuRsAddr );
833
834
0
        decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskTrafoCtu( cs, ctuRsAddr, ctuArea );
835
836
0
        if( !ctuData.slice->isIntra() )
837
0
        {
838
0
          decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskInterCtu( cs, ctuRsAddr, ctuArea );
839
840
0
          if( cs.picture->stillReferenced )
841
0
          {
842
0
            decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskFinishMotionInfo( cs, ctuRsAddr, ctu, line );
843
0
          }
844
0
        }
845
0
      }
846
847
0
      thisCtuState = INTRA;
848
849
0
      ITT_TASKEND( itt_domain_dec, itt_handle_inter );
850
0
    }
851
852
0
    case INTRA:
853
0
    {
854
0
      if( col > 0 && thisLine[col - 1] <= INTRA_cont )
855
0
        return false;
856
857
0
      if( line > 0 )
858
0
      {
859
0
        if( col + 1 < tasksPerLine )
860
0
        {
861
0
          if( lineAbove[col + 1] <= INTRA )
862
0
            return false;
863
0
        }
864
0
        else
865
0
        {
866
0
          if( lineAbove[col] <= INTRA_cont )
867
0
            return false;
868
0
        }
869
0
      }
870
0
      if( onlyCheckReadyState )
871
0
        return true;
872
873
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_intra );
874
875
0
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
876
0
      {
877
0
        const int ctuRsAddr    = ctu + line * cs.pcv->widthInCtus;
878
0
        const UnitArea ctuArea = getCtuArea( cs, ctu, line, true );
879
0
        decLib.m_pcThreadResource[tid]->m_cCuDecoder.TaskCriticalIntraKernel( cs, ctuRsAddr, ctuArea );
880
881
0
        thisCtuState = INTRA_cont;
882
0
      }
883
884
0
      thisCtuState = RSP;
885
886
0
      ITT_TASKEND( itt_domain_dec, itt_handle_intra );
887
0
    }
888
889
0
    case RSP:
890
0
    {
891
      // RIRZIIIII
892
      // IIIIIXXXX
893
      //
894
      // - Z can be reshaped when it is no more an intra prediction source for X in the next line
895
896
897
0
      if     ( line + 1 < heightInCtus && col + 1 < tasksPerLine && lineBelow[col + 1] < INTRA_cont )
898
0
        return false;
899
0
      else if( line + 1 < heightInCtus &&                           lineBelow[col]     < RSP )
900
0
        return false;
901
0
      else if(                            col + 1 < tasksPerLine && thisLine [col + 1] < INTRA_cont ) // need this for the last line
902
0
        return false;
903
904
0
      if( onlyCheckReadyState )
905
0
        return true;
906
907
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_rsp );
908
909
0
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
910
0
      {
911
0
        decLib.m_pcThreadResource[tid]->m_cReshaper.rspCtuBcw( cs, ctu, line );
912
0
      }
913
914
0
      ITT_TASKEND( itt_domain_dec, itt_handle_rsp );
915
916
0
      thisCtuState = LF_V;
917
0
    }
918
919
0
    case LF_V:
920
0
    {
921
0
      if( col > 0 && thisLine[col - 1] < LF_V )
922
0
        return false;
923
0
      if( onlyCheckReadyState )
924
0
        return true;
925
926
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_lfl );
927
928
0
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
929
0
      {
930
0
        decLib.m_cLoopFilter.loopFilterCTU( cs, MAX_NUM_CHANNEL_TYPE, ctu, line, EDGE_VER );
931
932
0
        thisCtuState = LF_V_cont;
933
0
      }
934
935
0
      thisCtuState = LF_H;
936
937
0
      ITT_TASKEND( itt_domain_dec, itt_handle_lfl );
938
0
    }
939
940
0
    case LF_H:
941
0
    {
942
0
      if( line > 0 && lineAbove[col] < LF_H )
943
0
        return false;
944
945
0
      if( line > 0 && col + 1 < tasksPerLine && lineAbove[col + 1] < LF_V_cont )
946
0
        return false;
947
948
0
      if(             col + 1 < tasksPerLine && thisLine[col + 1] < LF_V_cont )
949
0
        return false;
950
951
0
      if( onlyCheckReadyState )
952
0
        return true;
953
954
0
      ITT_TASKSTART( itt_domain_dec, itt_handle_lfl );
955
956
0
      for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
957
0
      {
958
0
        decLib.m_cLoopFilter.loopFilterCTU( cs, MAX_NUM_CHANNEL_TYPE, ctu, line, EDGE_HOR );
959
0
      }
960
961
0
      thisCtuState = PRESAO;
962
963
0
      ITT_TASKEND( itt_domain_dec, itt_handle_lfl );
964
0
    }
965
966
0
    case PRESAO:
967
0
    {
968
      // only last CTU processes full line
969
0
      if( col == tasksPerLine - 1 )
970
0
      {
971
0
        if( line > 0 && lineAbove[col] <= PRESAO )
972
0
          return false;
973
974
0
        for( int c = 0; c < tasksPerLine; ++c )
975
0
        {
976
0
          if( thisLine[c] < PRESAO )
977
0
            return false;
978
979
0
          if( line + 1 < heightInCtus && lineBelow[c] < PRESAO )
980
0
            return false;
981
0
        }
982
0
        if( onlyCheckReadyState )
983
0
          return true;
984
985
0
        ITT_TASKSTART( itt_domain_dec, itt_handle_presao );
986
987
0
        if( cs.sps->getUseSAO() )
988
0
        {
989
0
          decLib.m_cSAO.SAOPrepareCTULine( cs, getLineArea( cs, line, true ) );
990
0
        }
991
992
0
        ITT_TASKEND( itt_domain_dec, itt_handle_presao );
993
0
      }
994
0
      else if( thisLine[tasksPerLine - 1] <= PRESAO )   // wait for last CTU to finish PRESAO
995
0
      {
996
0
        return false;
997
0
      }
998
0
      if( onlyCheckReadyState )
999
0
        return true;
1000
1001
0
      thisCtuState = SAO;
1002
0
    }
1003
1004
0
    case SAO:
1005
0
    {
1006
0
      if( onlyCheckReadyState )
1007
0
        return true;
1008
1009
      // only last CTU processes full line
1010
0
      if( cs.sps->getUseSAO() )
1011
0
      {
1012
0
        ITT_TASKSTART( itt_domain_dec, itt_handle_sao );
1013
1014
0
        for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
1015
0
        {
1016
0
          const UnitArea  ctuArea = getCtuArea( cs, ctu, line, true );
1017
0
          decLib.m_cSAO.SAOProcessCTU( cs, ctuArea );
1018
0
        }
1019
1020
0
        ITT_TASKEND( itt_domain_dec, itt_handle_sao );
1021
0
      }
1022
0
      if( param->common.doALF )
1023
0
      {
1024
0
        ITT_TASKSTART( itt_domain_dec, itt_handle_alf );
1025
1026
0
        for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
1027
0
        {
1028
0
          AdaptiveLoopFilter::prepareCTU( cs, ctu, line );
1029
1030
0
          thisCtuState = SAO_cont;
1031
0
        }
1032
1033
0
        ITT_TASKEND( itt_domain_dec, itt_handle_alf );
1034
0
      }
1035
1036
0
      thisCtuState = ALF;
1037
0
    }
1038
1039
0
    case ALF:
1040
0
    {
1041
0
      if( param->common.doALF )
1042
0
      {
1043
0
        const bool a = line > 0;
1044
0
        const bool b = line + 1 < heightInCtus;
1045
0
        const bool c = col > 0;
1046
0
        const bool d = col + 1 < tasksPerLine;
1047
1048
0
        if( a )
1049
0
        {
1050
0
          if( c && lineAbove[col - 1] < ALF ) return false;
1051
0
          if(      lineAbove[col    ] < ALF ) return false;
1052
0
          if( d && lineAbove[col + 1] < SAO_cont ) return false;
1053
0
        }
1054
1055
0
        if( b )
1056
0
        {
1057
0
          if( c && lineBelow[col - 1] < ALF ) return false;
1058
0
          if(      lineBelow[col    ] < ALF ) return false;
1059
0
          if( d && lineBelow[col + 1] < SAO_cont ) return false;
1060
0
        }
1061
1062
0
        if( c && thisLine[col - 1] < ALF ) return false;
1063
0
        if( d && thisLine[col + 1] < SAO_cont ) return false;
1064
1065
0
        if( onlyCheckReadyState )
1066
0
          return true;
1067
1068
0
        ITT_TASKSTART( itt_domain_dec, itt_handle_alf );
1069
0
        for( int ctu = ctuStart; ctu < ctuEnd; ctu++ )
1070
0
        {
1071
0
          decLib.m_cALF.processCTU( cs, ctu, line, tid );
1072
0
        }
1073
0
        ITT_TASKEND( itt_domain_dec, itt_handle_alf );
1074
0
      }
1075
0
      else if( onlyCheckReadyState )
1076
0
        return true;
1077
1078
0
      thisCtuState = DONE;
1079
0
    }
1080
1081
0
    default:
1082
0
      CHECKD( thisCtuState != DONE, "Wrong CTU state" );
1083
0
    }   // end switch
1084
0
  }
1085
0
  catch( ... )
1086
0
  {
1087
0
    std::rethrow_exception( std::current_exception() );
1088
0
  }
1089
1090
0
  return true;
1091
0
}
Unexecuted instantiation: bool vvdec::DecLibRecon::ctuTask<false>(int, vvdec::CtuTaskParam*)
Unexecuted instantiation: bool vvdec::DecLibRecon::ctuTask<true>(int, vvdec::CtuTaskParam*)
1092
1093
}