Coverage Report

Created: 2026-07-16 06:32

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