Coverage Report

Created: 2026-10-28 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvenc/source/Lib/CommonLib/SampleAdaptiveOffset.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) 2019-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVenC 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
44
/** \file     SampleAdaptiveOffset.cpp
45
    \brief    sample adaptive offset class
46
*/
47
48
#include "SampleAdaptiveOffset.h"
49
#include "UnitTools.h"
50
#include "UnitPartitioner.h"
51
#include "CodingStructure.h"
52
#include "dtrace_codingstruct.h"
53
#include "dtrace_buffer.h"
54
55
#include <string.h>
56
#include <stdlib.h>
57
#include <math.h>
58
59
//! \ingroup CommonLib
60
//! \{
61
62
namespace vvenc {
63
64
void offsetBlock_core(const int channelBitDepth, const ClpRng& clpRng, int typeIdx, int* offset, int startIdx, 
65
                      const Pel* srcBlk, Pel* resBlk, ptrdiff_t srcStride, ptrdiff_t resStride, int width, int height, 
66
                      uint8_t availMask, std::vector<int8_t> &signLineBuf1, std::vector<int8_t> &signLineBuf2)
67
34
{
68
34
  int x, y, startX, startY, endX, endY, edgeType;
69
34
  int firstLineStartX, firstLineEndX, lastLineStartX, lastLineEndX;
70
34
  int8_t signLeft, signRight, signDown;
71
72
34
  const Pel* srcLine = srcBlk;
73
34
  Pel* resLine = resBlk;
74
75
34
  switch (typeIdx)
76
34
  {
77
0
  case SAO_TYPE_EO_0:
78
0
  {
79
0
    offset += 2;
80
0
    startX = availMask&LeftAvail ? 0 : 1;
81
0
    endX = availMask&RightAvail ? width : (width - 1);
82
0
    for (y = 0; y < height; y++)
83
0
    {
84
0
      signLeft = (int8_t)sgn(srcLine[startX] - srcLine[startX - 1]);
85
0
      for (x = startX; x < endX; x++)
86
0
      {
87
0
        signRight = (int8_t)sgn(srcLine[x] - srcLine[x + 1]);
88
0
        edgeType = signRight + signLeft;
89
0
        signLeft = -signRight;
90
91
0
        resLine[x] = ClipPel<int>(srcLine[x] + offset[edgeType], clpRng);
92
0
      }
93
0
      srcLine += srcStride;
94
0
      resLine += resStride;
95
0
    }
96
97
0
  }
98
0
  break;
99
0
  case SAO_TYPE_EO_90:
100
0
  {
101
0
    offset += 2;
102
0
    int8_t *signUpLine = &signLineBuf1[0];
103
104
0
    startY = availMask&AboveAvail ? 0 : 1;
105
0
    endY = availMask&BelowAvail ? height : height - 1;
106
0
    if (!(availMask&AboveAvail))
107
0
    {
108
0
      srcLine += srcStride;
109
0
      resLine += resStride;
110
0
    }
111
112
0
    const Pel* srcLineAbove = srcLine - srcStride;
113
0
    for (x = 0; x < width; x++)
114
0
    {
115
0
      signUpLine[x] = (int8_t)sgn(srcLine[x] - srcLineAbove[x]);
116
0
    }
117
118
0
    const Pel* srcLineBelow;
119
0
    for (y = startY; y < endY; y++)
120
0
    {
121
0
      srcLineBelow = srcLine + srcStride;
122
123
0
      for (x = 0; x < width; x++)
124
0
      {
125
0
        signDown = (int8_t)sgn(srcLine[x] - srcLineBelow[x]);
126
0
        edgeType = signDown + signUpLine[x];
127
0
        signUpLine[x] = -signDown;
128
129
0
        resLine[x] = ClipPel<int>(srcLine[x] + offset[edgeType], clpRng);
130
0
      }
131
0
      srcLine += srcStride;
132
0
      resLine += resStride;
133
0
    }
134
135
0
  }
136
0
  break;
137
0
  case SAO_TYPE_EO_135:
138
0
  {
139
0
    offset += 2;
140
0
    int8_t *signUpLine, *signDownLine, *signTmpLine;
141
142
0
    signUpLine = &signLineBuf1[0];
143
0
    signDownLine = &signLineBuf2[0];
144
145
0
    startX = availMask&LeftAvail ? 0 : 1;
146
0
    endX = availMask&RightAvail ? width : (width - 1);
147
148
    //prepare 2nd line's upper sign
149
0
    const Pel* srcLineBelow = srcLine + srcStride;
150
0
    for (x = startX; x < endX + 1; x++)
151
0
    {
152
0
      signUpLine[x] = (int8_t)sgn(srcLineBelow[x] - srcLine[x - 1]);
153
0
    }
154
155
    //1st line
156
0
    const Pel* srcLineAbove = srcLine - srcStride;
157
0
    firstLineStartX = availMask&AboveLeftAvail ? 0 : 1;
158
0
    firstLineEndX = availMask&AboveAvail ? endX : 1;
159
0
    for (x = firstLineStartX; x < firstLineEndX; x++)
160
0
    {
161
0
      edgeType = sgn(srcLine[x] - srcLineAbove[x - 1]) - signUpLine[x + 1];
162
163
0
      resLine[x] = ClipPel<int>(srcLine[x] + offset[edgeType], clpRng);
164
0
    }
165
0
    srcLine += srcStride;
166
0
    resLine += resStride;
167
168
169
    //middle lines
170
0
    for (y = 1; y < height - 1; y++)
171
0
    {
172
0
      srcLineBelow = srcLine + srcStride;
173
174
0
      for (x = startX; x < endX; x++)
175
0
      {
176
0
        signDown = (int8_t)sgn(srcLine[x] - srcLineBelow[x + 1]);
177
0
        edgeType = signDown + signUpLine[x];
178
0
        resLine[x] = ClipPel<int>(srcLine[x] + offset[edgeType], clpRng);
179
180
0
        signDownLine[x + 1] = -signDown;
181
0
      }
182
0
      signDownLine[startX] = (int8_t)sgn(srcLineBelow[startX] - srcLine[startX - 1]);
183
184
0
      signTmpLine = signUpLine;
185
0
      signUpLine = signDownLine;
186
0
      signDownLine = signTmpLine;
187
188
0
      srcLine += srcStride;
189
0
      resLine += resStride;
190
0
    }
191
192
    //last line
193
0
    srcLineBelow = srcLine + srcStride;
194
0
    lastLineStartX = availMask&BelowAvail ? startX : (width - 1);
195
0
    lastLineEndX = availMask&BelowRightAvail ? width : (width - 1);
196
0
    for (x = lastLineStartX; x < lastLineEndX; x++)
197
0
    {
198
0
      edgeType = sgn(srcLine[x] - srcLineBelow[x + 1]) + signUpLine[x];
199
0
      resLine[x] = ClipPel<int>(srcLine[x] + offset[edgeType], clpRng);
200
201
0
    }
202
0
  }
203
0
  break;
204
0
  case SAO_TYPE_EO_45:
205
0
  {
206
0
    offset += 2;
207
0
    int8_t *signUpLine = &signLineBuf1[1];
208
209
0
    startX = availMask&LeftAvail ? 0 : 1;
210
0
    endX = availMask&RightAvail ? width : (width - 1);
211
212
    //prepare 2nd line upper sign
213
0
    const Pel* srcLineBelow = srcLine + srcStride;
214
0
    for (x = startX - 1; x < endX; x++)
215
0
    {
216
0
      signUpLine[x] = (int8_t)sgn(srcLineBelow[x] - srcLine[x + 1]);
217
0
    }
218
219
220
    //first line
221
0
    const Pel* srcLineAbove = srcLine - srcStride;
222
0
    firstLineStartX = availMask&AboveAvail ? startX : (width - 1);
223
0
    firstLineEndX = availMask&AboveRightAvail ? width : (width - 1);
224
0
    for (x = firstLineStartX; x < firstLineEndX; x++)
225
0
    {
226
0
      edgeType = sgn(srcLine[x] - srcLineAbove[x + 1]) - signUpLine[x - 1];
227
0
      resLine[x] = ClipPel<int>(srcLine[x] + offset[edgeType], clpRng);
228
0
    }
229
0
    srcLine += srcStride;
230
0
    resLine += resStride;
231
232
    //middle lines
233
0
    for (y = 1; y < height - 1; y++)
234
0
    {
235
0
      srcLineBelow = srcLine + srcStride;
236
237
0
      for (x = startX; x < endX; x++)
238
0
      {
239
0
        signDown = (int8_t)sgn(srcLine[x] - srcLineBelow[x - 1]);
240
0
        edgeType = signDown + signUpLine[x];
241
0
        resLine[x] = ClipPel<int>(srcLine[x] + offset[edgeType], clpRng);
242
0
        signUpLine[x - 1] = -signDown;
243
0
      }
244
0
      signUpLine[endX - 1] = (int8_t)sgn(srcLineBelow[endX - 1] - srcLine[endX]);
245
0
      srcLine += srcStride;
246
0
      resLine += resStride;
247
0
    }
248
249
    //last line
250
0
    srcLineBelow = srcLine + srcStride;
251
0
    lastLineStartX = availMask&BelowLeftAvail ? 0 : 1;
252
0
    lastLineEndX = availMask&BelowAvail ? endX : 1;
253
0
    for (x = lastLineStartX; x < lastLineEndX; x++)
254
0
    {
255
0
      edgeType = sgn(srcLine[x] - srcLineBelow[x - 1]) + signUpLine[x];
256
0
      resLine[x] = ClipPel<int>(srcLine[x] + offset[edgeType], clpRng);
257
258
0
    }
259
0
  }
260
0
  break;
261
34
  case SAO_TYPE_BO:
262
34
  {
263
34
    const int shiftBits = channelBitDepth - NUM_SAO_BO_CLASSES_LOG2;
264
2.65k
    for (y = 0; y < height; y++)
265
2.62k
    {
266
175k
      for (x = 0; x < width; x++)
267
173k
      {
268
173k
        resLine[x] = ClipPel<int>(srcLine[x] + offset[srcLine[x] >> shiftBits], clpRng);
269
173k
      }
270
2.62k
      srcLine += srcStride;
271
2.62k
      resLine += resStride;
272
2.62k
    }
273
34
  }
274
34
  break;
275
0
  default:
276
0
  {
277
0
    THROW("Not a supported SAO types\n");
278
0
  }
279
34
  }
280
34
}
281
void calcSaoStatisticsEo0_Core(int width,int startX,int endX,int endY,Pel*  srcLine,Pel*  orgLine,int srcStride,int orgStride,int64_t  *count, int64_t *diff)
282
14.9k
{
283
14.9k
  int iNaRight=width-endX;
284
14.9k
  srcLine      = srcLine + startX;
285
14.9k
  orgLine      =orgLine + startX;
286
14.9k
  int iNaWidth = startX + iNaRight;
287
14.9k
  int i,j;
288
14.9k
  diff +=2;
289
14.9k
  count+=2;
290
885k
  for ( i = 0; i < endY; i++ )
291
870k
  {
292
870k
    int iSignLeft = sgn( *srcLine - *(srcLine - 1) );
293
56.4M
    for ( j = 0; j < width - iNaWidth; j++, srcLine++, orgLine++ )
294
55.6M
    {
295
55.6M
      int iSignRight       = sgn( *srcLine - *(srcLine + 1) );
296
55.6M
      int iType            = iSignLeft + iSignRight;
297
55.6M
      iSignLeft            = -1 * iSignRight;
298
55.6M
      diff[iType]  += (*orgLine - *srcLine);
299
55.6M
      count[iType] += 1;
300
55.6M
    }
301
870k
    srcLine += srcStride - ( width - iNaWidth );
302
870k
    orgLine += orgStride - ( width - iNaWidth );
303
870k
  }
304
14.9k
}
305
void calcSaoStatisticsEo90_Core(int width,int endX,int startY,int endY,Pel*  srcLine,Pel*  orgLine,int srcStride,int orgStride,int64_t  *count, int64_t *diff,int8_t *signUpLine)
306
14.9k
{
307
14.9k
  diff +=2;
308
14.9k
  count+=2;
309
14.9k
  int x,y,edgeType;
310
14.9k
  Pel* srcLineAbove = srcLine - srcStride;
311
14.9k
  int8_t signDown;
312
863k
  for (x=0; x<endX; x++)
313
848k
  {
314
848k
    signUpLine[x] = (int8_t)sgn(srcLine[x] - srcLineAbove[x]);
315
848k
  }
316
14.9k
  Pel* srcLineBelow;
317
870k
  for (y=startY; y<endY; y++)
318
855k
  {
319
855k
    srcLineBelow = srcLine + srcStride;
320
56.5M
    for (x=0; x<endX; x++)
321
55.6M
    {
322
55.6M
      signDown  = (int8_t)sgn(srcLine[x] - srcLineBelow[x]);
323
55.6M
      edgeType  = signDown + signUpLine[x];
324
55.6M
      signUpLine[x]= -signDown;
325
55.6M
      diff [edgeType] += (orgLine[x] - srcLine[x]);
326
55.6M
      count[edgeType] ++;
327
55.6M
    }
328
855k
    srcLine += srcStride;
329
855k
    orgLine += orgStride;
330
855k
  }
331
14.9k
}
332
333
334
void calcSaoStatisticsEo135_Core(int width,int startX,int endX,int endY,Pel*  srcLine,Pel*  orgLine,int srcStride,int orgStride,int64_t  *count, int64_t *diff,int8_t *signUpLine,int8_t *signDownLine)
335
14.9k
{
336
14.9k
  int x,y,edgeType;
337
14.9k
  int8_t signDown;
338
14.9k
  int8_t *signTmpLine;
339
14.9k
  Pel* srcLineBelow = srcLine + srcStride;
340
  //middle lines
341
863k
   for (y=1; y<endY; y++)
342
848k
   {
343
848k
     srcLineBelow = srcLine + srcStride;
344
55.2M
     for (x=startX; x<endX; x++)
345
54.3M
     {
346
54.3M
       signDown = (int8_t)sgn(srcLine[x] - srcLineBelow[x+1]);
347
54.3M
       edgeType = signDown + signUpLine[x];
348
54.3M
       diff [edgeType] += (orgLine[x] - srcLine[x]);
349
54.3M
       count[edgeType] ++;
350
54.3M
       signDownLine[x+1] = -signDown;
351
54.3M
     }
352
848k
     signDownLine[startX] = (int8_t)sgn(srcLineBelow[startX] - srcLine[startX-1]);
353
848k
     signTmpLine  = signUpLine;
354
848k
     signUpLine   = signDownLine;
355
848k
     signDownLine = signTmpLine;
356
848k
     srcLine += srcStride;
357
848k
     orgLine += orgStride;
358
848k
   }
359
14.9k
}
360
void calcSaoStatisticsEo45_Core(int width,int startX,int endX,int endY,Pel*  srcLine,Pel*  orgLine,int srcStride,int orgStride,int64_t  *count, int64_t *diff,int8_t *signUpLine)
361
14.9k
{
362
14.9k
  int x,y,edgeType;
363
14.9k
  int8_t signDown;
364
14.9k
  Pel* srcLineBelow = srcLine + srcStride;
365
  //middle lines
366
863k
  for (y=1; y<endY; y++)
367
848k
  {
368
848k
    srcLineBelow = srcLine + srcStride;
369
370
55.2M
    for(x=startX; x<endX; x++)
371
54.3M
    {
372
54.3M
      signDown = (int8_t)sgn(srcLine[x] - srcLineBelow[x-1]);
373
54.3M
      edgeType = signDown + signUpLine[x];
374
54.3M
      diff [edgeType] += (orgLine[x] - srcLine[x]);
375
54.3M
      count[edgeType] ++;
376
54.3M
      signUpLine[x-1] = -signDown;
377
54.3M
    }
378
848k
    signUpLine[endX-1] = (int8_t)sgn(srcLineBelow[endX-1] - srcLine[endX]);
379
848k
    srcLine  += srcStride;
380
848k
    orgLine  += orgStride;
381
848k
  }
382
14.9k
}
383
void calcSaoStatisticsBo_Core(int width,int endX,int endY,Pel*  srcLine,Pel*  orgLine,int srcStride,int orgStride,int channelBitDepth, int64_t *count,int64_t  *diff)
384
14.9k
{
385
14.9k
  int x,y;
386
14.9k
  int startX=0;
387
14.9k
  int shiftBits = channelBitDepth - NUM_SAO_BO_CLASSES_LOG2;
388
885k
  for (y=0; y< endY; y++)
389
871k
  {
390
57.4M
    for (x=startX; x< endX; x++)
391
56.5M
    {
392
56.5M
      int bandIdx= srcLine[x] >> shiftBits;
393
56.5M
      diff [bandIdx] += (orgLine[x] - srcLine[x]);
394
56.5M
      count[bandIdx] ++;
395
56.5M
    }
396
871k
    srcLine += srcStride;
397
871k
    orgLine += orgStride;
398
871k
  }
399
14.9k
}
400
401
void SAOOffset::reset()
402
262k
{
403
262k
  modeIdc = SAO_MODE_OFF;
404
262k
  typeIdc = -1;
405
262k
  typeAuxInfo = -1;
406
262k
  ::memset(offset, 0, sizeof(int)* MAX_NUM_SAO_CLASSES);
407
262k
}
408
409
void SAOBlkParam::reset()
410
41.2k
{
411
165k
  for(int compIdx = 0; compIdx < MAX_NUM_COMP; compIdx++)
412
123k
  {
413
123k
    SAOOffsets[compIdx].reset();
414
123k
  }
415
41.2k
}
416
417
SampleAdaptiveOffset::SampleAdaptiveOffset( bool enableOpt )
418
10.7k
{
419
10.7k
  offsetBlock = offsetBlock_core;
420
10.7k
  calcSaoStatisticsEo90 = calcSaoStatisticsEo90_Core;
421
10.7k
  calcSaoStatisticsEo135 = calcSaoStatisticsEo135_Core;
422
10.7k
  calcSaoStatisticsEo45 = calcSaoStatisticsEo45_Core;
423
10.7k
  calcSaoStatisticsEo0 = calcSaoStatisticsEo0_Core;
424
10.7k
  calcSaoStatisticsBo = calcSaoStatisticsBo_Core;
425
426
10.7k
  if( enableOpt )
427
10.7k
  {
428
#if ENABLE_SIMD_OPT_SAO && defined( TARGET_SIMD_X86 )
429
    initSampleAdaptiveOffsetX86();
430
#endif
431
#if ENABLE_SIMD_OPT_SAO && defined( TARGET_SIMD_ARM )
432
    initSampleAdaptiveOffsetARM();
433
#endif
434
10.7k
  }
435
10.7k
}
436
437
438
SampleAdaptiveOffset::~SampleAdaptiveOffset()
439
10.7k
{
440
10.7k
  m_signLineBuf1.clear();
441
10.7k
  m_signLineBuf2.clear();
442
10.7k
}
443
444
void SampleAdaptiveOffset::init( ChromaFormat format, uint32_t maxCUWidth, uint32_t maxCUHeight, uint32_t lumaBitShift, uint32_t chromaBitShift )
445
10.7k
{
446
  //bit-depth related
447
43.0k
  for(int compIdx = 0; compIdx < MAX_NUM_COMP; compIdx++)
448
32.2k
  {
449
32.2k
    m_offsetStepLog2  [compIdx] = isLuma(ComponentID(compIdx))? lumaBitShift : chromaBitShift;
450
32.2k
  }
451
10.7k
  m_numberOfComponents = getNumberValidComponents(format);
452
453
10.7k
  size_t lineBufferSize = std::max( maxCUWidth, maxCUHeight ) + 1;
454
10.7k
  if( m_signLineBuf1.size() < lineBufferSize )
455
10.7k
  {
456
10.7k
    m_signLineBuf1.resize( lineBufferSize );
457
10.7k
    m_signLineBuf2.resize( lineBufferSize );
458
10.7k
  }
459
10.7k
}
460
461
void SampleAdaptiveOffset::invertQuantOffsets(ComponentID compIdx, int typeIdc, int typeAuxInfo, int* dstOffsets, int* srcOffsets)
462
74.6k
{
463
74.6k
  int codedOffset[MAX_NUM_SAO_CLASSES];
464
465
74.6k
  ::memcpy(codedOffset, srcOffsets, sizeof(int)*MAX_NUM_SAO_CLASSES);
466
74.6k
  ::memset(dstOffsets, 0, sizeof(int)*MAX_NUM_SAO_CLASSES);
467
468
74.6k
  if(typeIdc == SAO_TYPE_START_BO)
469
14.9k
  {
470
74.7k
    for(int i=0; i< 4; i++)
471
59.7k
    {
472
59.7k
      dstOffsets[(typeAuxInfo+ i)%NUM_SAO_BO_CLASSES] = codedOffset[(typeAuxInfo+ i)%NUM_SAO_BO_CLASSES]*(1<<m_offsetStepLog2[compIdx]);
473
59.7k
    }
474
14.9k
  }
475
59.6k
  else //EO
476
59.6k
  {
477
358k
    for(int i=0; i< NUM_SAO_EO_CLASSES; i++)
478
298k
    {
479
298k
      dstOffsets[i] = codedOffset[i] *(1<<m_offsetStepLog2[compIdx]);
480
298k
    }
481
59.6k
    CHECK(dstOffsets[SAO_CLASS_EO_PLAIN] != 0, "EO offset is not '0'"); //keep EO plain offset as zero
482
59.6k
  }
483
484
74.6k
}
485
486
int SampleAdaptiveOffset::getMergeList(CodingStructure& cs, int ctuRsAddr, SAOBlkParam* blkParams, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES])
487
4.97k
{
488
4.97k
  const PreCalcValues& pcv = *cs.pcv;
489
490
4.97k
  int ctuX = ctuRsAddr % pcv.widthInCtus;
491
4.97k
  int ctuY = ctuRsAddr / pcv.widthInCtus;
492
4.97k
  const CodingUnit& cu = *cs.getCU(Position(ctuX*pcv.maxCUSize, ctuY*pcv.maxCUSize), CH_L, TREE_D);
493
4.97k
  int mergedCTUPos;
494
4.97k
  int numValidMergeCandidates = 0;
495
496
14.9k
  for(int mergeType=0; mergeType< NUM_SAO_MERGE_TYPES; mergeType++)
497
9.95k
  {
498
9.95k
    SAOBlkParam* mergeCandidate = NULL;
499
500
9.95k
    switch(mergeType)
501
9.95k
    {
502
4.97k
    case SAO_MERGE_ABOVE:
503
4.97k
      {
504
4.97k
        if(ctuY > 0)
505
2.33k
        {
506
2.33k
          mergedCTUPos = ctuRsAddr- pcv.widthInCtus;
507
2.33k
          if(cs.getCURestricted(Position(ctuX*pcv.maxCUSize, (ctuY-1)*pcv.maxCUSize), cu, cu.chType))
508
2.33k
          {
509
2.33k
            mergeCandidate = &(blkParams[mergedCTUPos]);
510
2.33k
          }
511
2.33k
        }
512
4.97k
      }
513
4.97k
      break;
514
4.97k
    case SAO_MERGE_LEFT:
515
4.97k
      {
516
4.97k
        if(ctuX > 0)
517
2.28k
        {
518
2.28k
          mergedCTUPos = ctuRsAddr- 1;
519
2.28k
          if(cs.getCURestricted(Position((ctuX-1)*pcv.maxCUSize, ctuY*pcv.maxCUSize), cu, cu.chType))
520
2.28k
          {
521
2.28k
            mergeCandidate = &(blkParams[mergedCTUPos]);
522
2.28k
          }
523
2.28k
        }
524
4.97k
      }
525
4.97k
      break;
526
0
    default:
527
0
      {
528
0
        THROW("not a supported merge type");
529
0
      }
530
9.95k
    }
531
532
9.95k
    mergeList[mergeType]=mergeCandidate;
533
9.95k
    if (mergeCandidate != NULL)
534
4.61k
    {
535
4.61k
      numValidMergeCandidates++;
536
4.61k
    }
537
9.95k
  }
538
539
4.97k
  return numValidMergeCandidates;
540
4.97k
}
541
542
543
void SampleAdaptiveOffset::reconstructBlkSAOParam(SAOBlkParam& recParam, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES])
544
4.97k
{
545
4.97k
  const int numberOfComponents = m_numberOfComponents;
546
19.9k
  for(int compIdx = 0; compIdx < numberOfComponents; compIdx++)
547
14.9k
  {
548
14.9k
    const ComponentID component = ComponentID(compIdx);
549
14.9k
    SAOOffset& offsetParam = recParam[component];
550
551
14.9k
    if(offsetParam.modeIdc == SAO_MODE_OFF)
552
4.46k
    {
553
4.46k
      continue;
554
4.46k
    }
555
556
10.4k
    switch(offsetParam.modeIdc)
557
10.4k
    {
558
21
    case SAO_MODE_NEW:
559
21
      {
560
21
        invertQuantOffsets(component, offsetParam.typeIdc, offsetParam.typeAuxInfo, offsetParam.offset, offsetParam.offset);
561
21
      }
562
21
      break;
563
10.4k
    case SAO_MODE_MERGE:
564
10.4k
      {
565
10.4k
        SAOBlkParam* mergeTarget = mergeList[offsetParam.typeIdc];
566
10.4k
        CHECK(mergeTarget == NULL, "Merge target does not exist");
567
568
10.4k
        offsetParam = (*mergeTarget)[component];
569
10.4k
      }
570
0
      break;
571
0
    default:
572
0
      {
573
0
        THROW("Not a supported mode");
574
10.4k
      }
575
10.4k
    }
576
10.4k
  }
577
4.97k
}
578
579
void SampleAdaptiveOffset::xReconstructBlkSAOParams(CodingStructure& cs, SAOBlkParam* saoBlkParams)
580
0
{
581
0
  for(uint32_t compIdx = 0; compIdx < MAX_NUM_COMP; compIdx++)
582
0
  {
583
0
    m_picSAOEnabled[compIdx] = false;
584
0
  }
585
586
0
  const uint32_t numberOfComponents = getNumberValidComponents(cs.pcv->chrFormat);
587
588
0
  for(int ctuRsAddr=0; ctuRsAddr< cs.pcv->sizeInCtus; ctuRsAddr++)
589
0
  {
590
0
    SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES] = { NULL };
591
0
    getMergeList(cs, ctuRsAddr, saoBlkParams, mergeList);
592
593
0
    reconstructBlkSAOParam(saoBlkParams[ctuRsAddr], mergeList);
594
595
0
    for(uint32_t compIdx = 0; compIdx < numberOfComponents; compIdx++)
596
0
    {
597
0
      if(saoBlkParams[ctuRsAddr][compIdx].modeIdc != SAO_MODE_OFF)
598
0
      {
599
0
        m_picSAOEnabled[compIdx] = true;
600
0
      }
601
0
    }
602
0
  }
603
0
}
604
605
void SampleAdaptiveOffset::offsetCTU( const UnitArea& area, const CPelUnitBuf& srcCtu, PelUnitBuf& res, SAOBlkParam& saoblkParam, CodingStructure& cs)
606
4.97k
{
607
4.97k
  const uint32_t numberOfComponents = getNumberValidComponents( area.chromaFormat );
608
4.97k
  bool bAllOff=true;
609
19.9k
  for( uint32_t compIdx = 0; compIdx < numberOfComponents; compIdx++)
610
14.9k
  {
611
14.9k
    if (saoblkParam[compIdx].modeIdc != SAO_MODE_OFF)
612
34
    {
613
34
      bAllOff=false;
614
34
    }
615
14.9k
  }
616
4.97k
  if (bAllOff)
617
4.94k
  {
618
4.94k
    return;
619
4.94k
  }
620
621
33
  uint8_t availMask;
622
  //block boundary availability
623
33
  deriveLoopFilterBoundaryAvailibility(cs, area.Y(), availMask);
624
625
33
  const size_t lineBufferSize = area.Y().width + 1;
626
33
  if (m_signLineBuf1.size() < lineBufferSize)
627
0
  {
628
0
    m_signLineBuf1.resize(lineBufferSize);
629
0
    m_signLineBuf2.resize(lineBufferSize);
630
0
  }
631
632
132
  for(int compIdx = 0; compIdx < numberOfComponents; compIdx++)
633
99
  {
634
99
    const ComponentID compID = ComponentID(compIdx);
635
99
    const CompArea& compArea = area.block(compID);
636
99
    SAOOffset& ctbOffset     = saoblkParam[compIdx];
637
638
99
    if(ctbOffset.modeIdc != SAO_MODE_OFF)
639
34
    {
640
34
      int  srcStride    = srcCtu.get(compID).stride;
641
34
      const Pel* srcBlk = srcCtu.get(compID).buf;
642
34
      int  resStride    = res.get(compID).stride;
643
34
      Pel* resBlk       = res.get(compID).bufAt(compArea);
644
645
34
      offsetBlock( cs.sps->bitDepths[toChannelType(compID)],
646
34
                   cs.slice->clpRngs[compID],
647
34
                   ctbOffset.typeIdc, ctbOffset.offset, ctbOffset.typeAuxInfo
648
34
                  , srcBlk, resBlk, srcStride, resStride, compArea.width, compArea.height, availMask
649
34
                  , m_signLineBuf1, m_signLineBuf2 );
650
34
    }
651
99
  } //compIdx
652
33
}
653
654
void SampleAdaptiveOffset::deriveLoopFilterBoundaryAvailibility(CodingStructure& cs, const Position& pos, uint8_t& availMask ) const
655
33
{
656
33
  const int cuSize = cs.pcv->maxCUSize;
657
33
  CodingUnit *cuLeft, *cuRight, *cuAbove, *cuBelow, *cuAboveLeft, *cuAboveRight, *cuBelowLeft, *cuBelowRight;
658
33
  const CodingUnit *cuCurr = cs.getCU( pos, CH_L, TREE_D );
659
660
33
  if (!cs.pps->getSubPicFromCU(*cuCurr).loopFilterAcrossSubPicEnabled)
661
0
  {
662
0
    THROW("no support");
663
0
  }
664
665
33
  if( !cs.pps->loopFilterAcrossSlicesEnabled || !cs.pps->loopFilterAcrossTilesEnabled )
666
0
  {
667
0
    const int ctuX = pos.x >> cs.pcv->maxCUSizeLog2;
668
0
    const int ctuY = pos.y >> cs.pcv->maxCUSizeLog2;
669
0
    const PPS* pps = cs.slice->pps;
670
0
    const int Xmax = pps->pcv->widthInCtus  - 1;
671
0
    const int Ymax = pps->pcv->heightInCtus - 1;
672
0
    cuLeft       = ctuX > 0                   && pps->canFilterCtuBdry( ctuX, ctuY, -1, 0 ) ? cs.getCU( pos.offset( -cuSize, 0       ), CH_L, TREE_D ): nullptr;
673
0
    cuRight      = ctuX < Xmax                && pps->canFilterCtuBdry( ctuX, ctuY,  1, 0 ) ? cs.getCU( pos.offset( cuSize , 0       ), CH_L, TREE_D ): nullptr;
674
0
    cuAbove      =                ctuY > 0    && pps->canFilterCtuBdry( ctuX, ctuY,  0,-1 ) ? cs.getCU( pos.offset( 0      , -cuSize ), CH_L, TREE_D ): nullptr;
675
0
    cuBelow      =                ctuY < Ymax && pps->canFilterCtuBdry( ctuX, ctuY,  0, 1 ) ? cs.getCU( pos.offset( 0      , cuSize  ), CH_L, TREE_D ): nullptr;
676
0
    cuAboveLeft  = ctuX > 0    && ctuY > 0    && pps->canFilterCtuBdry( ctuX, ctuY, -1,-1 ) ? cs.getCU( pos.offset( -cuSize, -cuSize ), CH_L, TREE_D ): nullptr;
677
0
    cuAboveRight = ctuX < Xmax && ctuY > 0    && pps->canFilterCtuBdry( ctuX, ctuY,  1,-1 ) ? cs.getCU( pos.offset( cuSize , -cuSize ), CH_L, TREE_D ): nullptr;
678
0
    cuBelowLeft  = ctuX > 0    && ctuY < Ymax && pps->canFilterCtuBdry( ctuX, ctuY, -1, 1 ) ? cs.getCU( pos.offset( -cuSize, cuSize  ), CH_L, TREE_D ): nullptr;
679
0
    cuBelowRight = ctuX < Xmax && ctuY < Ymax && pps->canFilterCtuBdry( ctuX, ctuY,  1, 1 ) ? cs.getCU( pos.offset( cuSize , cuSize  ), CH_L, TREE_D ): nullptr;
680
0
  }
681
33
  else
682
33
  {
683
33
    cuLeft       = cs.getCU( pos.offset( -cuSize,       0 ), CH_L, TREE_D );
684
33
    cuRight      = cs.getCU( pos.offset(  cuSize,       0 ), CH_L, TREE_D );
685
33
    cuAbove      = cs.getCU( pos.offset(       0, -cuSize ), CH_L, TREE_D );
686
33
    cuBelow      = cs.getCU( pos.offset(       0,  cuSize ), CH_L, TREE_D );
687
33
    cuAboveLeft  = cs.getCU( pos.offset( -cuSize, -cuSize ), CH_L, TREE_D );
688
33
    cuAboveRight = cs.getCU( pos.offset(  cuSize, -cuSize ), CH_L, TREE_D );
689
33
    cuBelowLeft  = cs.getCU( pos.offset( -cuSize,  cuSize ), CH_L, TREE_D );
690
33
    cuBelowRight = cs.getCU( pos.offset(  cuSize,  cuSize ), CH_L, TREE_D );
691
33
  }
692
33
  availMask = 0;
693
694
  // check cross slice flags
695
33
  if( cs.pps->loopFilterAcrossSlicesEnabled )
696
33
  {
697
33
    availMask |= (cuLeft       != NULL) ? LeftAvail : 0;
698
33
    availMask |= (cuAbove      != NULL) ? AboveAvail : 0;
699
33
    availMask |= (cuRight      != NULL) ? RightAvail : 0;
700
33
    availMask |= (cuBelow      != NULL) ? BelowAvail : 0;
701
33
    availMask |= (cuAboveLeft  != NULL) ? AboveLeftAvail : 0;
702
33
    availMask |= (cuBelowRight != NULL) ? BelowRightAvail : 0;
703
33
    availMask |= (cuAboveRight != NULL) ? AboveRightAvail : 0;
704
33
    availMask |= (cuBelowLeft  != NULL) ? BelowLeftAvail : 0;
705
33
  }
706
0
  else
707
0
  {
708
0
    availMask |= ((cuLeft       != NULL) && CU::isSameSlice(*cuCurr, *cuLeft) ) ? LeftAvail : 0;
709
0
    availMask |= ((cuAbove      != NULL) && CU::isSameSlice(*cuCurr, *cuAbove) ) ? AboveAvail : 0;
710
0
    availMask |= ((cuRight      != NULL) && CU::isSameSlice(*cuCurr, *cuRight)) ? RightAvail : 0;
711
0
    availMask |= ((cuBelow      != NULL) && CU::isSameSlice(*cuCurr, *cuBelow) ) ? BelowAvail : 0;
712
0
    availMask |= ((cuAboveLeft  != NULL) && CU::isSameSlice(*cuCurr, *cuAboveLeft)) ?  AboveLeftAvail : 0;
713
0
    availMask |= ((cuBelowRight != NULL) && CU::isSameSlice(*cuCurr, *cuBelowRight) ) ? BelowRightAvail : 0;
714
0
    availMask |= ((cuAboveRight != NULL) && CU::isSameSlice(*cuCurr, *cuAboveRight) ) ? AboveRightAvail : 0;
715
0
    availMask |= ( (cuBelowLeft != NULL) && CU::isSameSlice(*cuCurr, *cuBelowLeft) ) ? BelowLeftAvail : 0;
716
0
  }
717
718
  // check cross tile flags
719
33
  if (!cs.pps->loopFilterAcrossTilesEnabled)
720
0
  {
721
0
    uint8_t availMaskTile = 0;
722
0
    availMaskTile |= (availMask&LeftAvail       && CU::isSameTile(*cuCurr, *cuLeft)) ? LeftAvail : 0;
723
0
    availMaskTile |= (availMask&AboveAvail      && CU::isSameTile(*cuCurr, *cuAbove)) ? AboveAvail : 0;
724
0
    availMaskTile |= (availMask&RightAvail      && CU::isSameTile(*cuCurr, *cuRight)) ? RightAvail : 0;
725
0
    availMaskTile |= (availMask&BelowAvail      && CU::isSameTile(*cuCurr, *cuBelow)) ? BelowAvail : 0;
726
0
    availMaskTile |= (availMask&AboveLeftAvail  && CU::isSameTile(*cuCurr, *cuAboveLeft)) ? AboveLeftAvail : 0;
727
0
    availMaskTile |= (availMask&AboveRightAvail &&CU::isSameTile(*cuCurr, *cuAboveRight)) ? AboveRightAvail : 0;
728
0
    availMaskTile |= (availMask&BelowLeftAvail  && CU::isSameTile(*cuCurr, *cuBelowLeft)) ? BelowLeftAvail : 0;
729
0
    availMaskTile |= (availMask&BelowRightAvail && CU::isSameTile(*cuCurr, *cuBelowRight)) ? BelowRightAvail : 0;
730
0
    availMask = availMaskTile;
731
0
  }
732
33
}
733
734
} // namespace vvenc
735
736
//! \}
737