Coverage Report

Created: 2026-04-01 07:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vvenc/source/Lib/EncoderLib/EncReshape.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
/** \file     EncReshape.cpp
44
\brief    encoder reshaper class
45
*/
46
#include "EncReshape.h"
47
#include "CommonLib/Picture.h"
48
49
#include <stdio.h>
50
#include <string.h>
51
#include <math.h>
52
//! \ingroup EncLib
53
//! \{
54
55
namespace vvenc {
56
57
// ====================================================================================================================
58
// Constructor / destructor / create / destroy
59
// ====================================================================================================================
60
61
EncReshape::EncReshape()
62
0
  : m_exceedSTD     (false)
63
0
  , m_binImportance ()
64
0
  , m_tcase         (0)
65
0
  , m_rateAdpMode   (0)
66
0
  , m_useAdpCW      (false)
67
0
  , m_initCWAnalyze (0)
68
0
  , m_reshapeCW     ()
69
0
  , m_cwLumaWeight  {0}
70
0
  , m_chromaWeight  (1.0)
71
0
  , m_chromaAdj     (0)
72
0
  , m_binNum        (0)
73
0
  , m_srcSeqStats   ()
74
0
  , m_rspSeqStats   ()
75
0
{
76
0
  m_CTUFlag      = false;
77
0
  m_reshape      = true;
78
0
  m_exceedSTD    = false;
79
0
  m_signalType   = RESHAPE_SIGNAL_NULL;
80
0
}
81
82
EncReshape::~EncReshape()
83
0
{
84
0
}
85
86
void  EncReshape::init( const VVEncCfg& encCfg )
87
0
{
88
0
  if ( encCfg.m_lumaReshapeEnable )
89
0
  {
90
0
    m_lumaBD = encCfg.m_internalBitDepth[ CH_L ];
91
0
    m_reshapeLUTSize = 1 << m_lumaBD;
92
0
    m_rspBaseQP = encCfg.m_QP;
93
0
    m_initCWAnalyze = m_reshapeLUTSize / PIC_ANALYZE_CW_BINS;
94
0
    m_initCW = m_reshapeLUTSize / PIC_CODE_CW_BINS;
95
96
0
#if defined( TARGET_SIMD_X86 ) && ENABLE_SIMD_OPT_BUFFER
97
0
    if( m_fwdLUT.empty() )
98
0
      m_fwdLUT.resize( m_reshapeLUTSize + 2, 0 );
99
0
    if( m_invLUT.empty() )
100
0
      m_invLUT.resize( m_reshapeLUTSize + 2, 0 );
101
#else
102
    if( m_fwdLUT.empty() )
103
      m_fwdLUT.resize( m_reshapeLUTSize, 0 );
104
    if( m_invLUT.empty() )
105
      m_invLUT.resize( m_reshapeLUTSize, 0 );
106
#endif
107
0
    if (m_binCW.empty())
108
0
      m_binCW.resize(PIC_ANALYZE_CW_BINS);
109
0
    if (m_binImportance.empty())
110
0
      m_binImportance.resize(PIC_ANALYZE_CW_BINS);
111
0
    if (m_reshapePivot.empty())
112
0
      m_reshapePivot.resize(PIC_CODE_CW_BINS + 1, 0);
113
0
    if (m_inputPivot.empty())
114
0
      m_inputPivot.resize(PIC_CODE_CW_BINS + 1, 0);
115
0
    if (m_fwdScaleCoef.empty())
116
0
      m_fwdScaleCoef.resize(PIC_CODE_CW_BINS, 1 << FP_PREC);
117
0
    if (m_invScaleCoef.empty())
118
0
      m_invScaleCoef.resize(PIC_CODE_CW_BINS, 1 << FP_PREC);
119
0
    if (m_chromaAdjHelpLUT.empty())
120
0
      m_chromaAdjHelpLUT.resize(PIC_CODE_CW_BINS, 1<<CSCALE_FP_PREC);
121
122
0
    m_sliceReshapeInfo.sliceReshaperEnabled      = true;
123
0
    m_sliceReshapeInfo.sliceReshaperModelPresent = true;
124
0
    m_sliceReshapeInfo.enableChromaAdj           = true;
125
0
    m_sliceReshapeInfo.reshaperModelMinBinIdx    = 0;
126
0
    m_sliceReshapeInfo.reshaperModelMaxBinIdx    = PIC_CODE_CW_BINS - 1;
127
0
    memset(m_sliceReshapeInfo.reshaperModelBinCWDelta, 0, (PIC_CODE_CW_BINS) * sizeof(int));
128
0
    m_sliceReshapeInfo.maxNbitsNeededDeltaCW     = 0;
129
0
    m_sliceReshapeInfo.chrResScalingOffset       = 0;
130
131
0
    m_binNum = PIC_CODE_CW_BINS;
132
0
    m_srcSeqStats = SeqInfo();
133
0
    m_rspSeqStats = SeqInfo();
134
135
0
    m_signalType = encCfg.m_reshapeSignalType;
136
0
    m_chromaWeight = 1.0;
137
138
0
    initLumaLevelToWeightTableReshape();
139
0
  }
140
0
  else if (encCfg.m_lumaLevelToDeltaQPEnabled )
141
0
  {
142
0
    m_lumaBD = encCfg.m_internalBitDepth[ CH_L ];
143
0
    m_reshapeLUTSize = 1 << m_lumaBD;
144
0
    m_initCWAnalyze = m_reshapeLUTSize / PIC_ANALYZE_CW_BINS;
145
0
    m_initCW = m_reshapeLUTSize / PIC_CODE_CW_BINS;
146
0
    m_signalType = RESHAPE_SIGNAL_PQ;
147
0
    m_chromaWeight = 1.0;
148
149
0
    initLumaLevelToWeightTableReshape();
150
0
  }
151
0
}
152
153
void  EncReshape::destroy()
154
0
{
155
0
}
156
157
/**
158
-Perform HDR set up
159
\param   pcPic describe pointer of current coding picture
160
\param   sliceType describe the slice type
161
*/
162
void EncReshape::preAnalyzerHDR(Picture& pic, const SliceType sliceType, const vvencReshapeCW& reshapeCW)
163
0
{
164
0
  if (m_lumaBD >= 10)
165
0
  {
166
0
    m_sliceReshapeInfo.sliceReshaperEnabled = true;
167
0
    m_sliceReshapeInfo.sliceReshaperModelPresent = (sliceType == VVENC_I_SLICE );
168
0
    m_sliceReshapeInfo.enableChromaAdj = 1;
169
0
  }
170
0
  else
171
0
  {
172
0
    m_sliceReshapeInfo.sliceReshaperEnabled = false;
173
0
    m_sliceReshapeInfo.sliceReshaperModelPresent = false;
174
0
  }
175
0
}
176
177
/**
178
-Perform picture analysis for SDR
179
\param   pcPic describe pointer of current coding picture
180
\param   sliceType describe the slice type
181
\param   reshapeCW describe some input info
182
*/
183
184
void EncReshape::calcSeqStats(Picture& pic, SeqInfo &stats)
185
0
{
186
0
  CPelBuf picY     = pic.getOrigBuf(COMP_Y);
187
0
  const int width  = picY.width;
188
0
  const int height = picY.height;
189
0
  const int stride = picY.stride;
190
0
  uint32_t winLens = (m_binNum == PIC_CODE_CW_BINS) ? (std::min(height, width) / 240) : 2;
191
0
  winLens = winLens > 0 ? winLens : 1;
192
193
0
  int64_t tempSq  = 0;
194
0
  int64_t topSum  = 0,  topSumSq = 0;
195
0
  int64_t leftSum = 0, leftSumSq = 0;
196
0
  int64_t *leftColSum   = new int64_t[width];
197
0
  int64_t *leftColSumSq = new int64_t[width];
198
0
  int64_t *topRowSum    = new int64_t[height];
199
0
  int64_t *topRowSumSq  = new int64_t[height];
200
0
  int64_t *topColSum    = new int64_t[width];
201
0
  int64_t *topColSumSq  = new int64_t[width];
202
0
  uint32_t *binCnt      = new uint32_t[m_binNum];
203
0
  memset(leftColSum,   0, width * sizeof(int64_t));
204
0
  memset(leftColSumSq, 0, width * sizeof(int64_t));
205
0
  memset(topRowSum,    0, height * sizeof(int64_t));
206
0
  memset(topRowSumSq,  0, height * sizeof(int64_t));
207
0
  memset(topColSum,    0, width * sizeof(int64_t));
208
0
  memset(topColSumSq,  0, width * sizeof(int64_t));
209
0
  memset(binCnt,       0, m_binNum * sizeof(uint32_t));
210
211
0
  stats = SeqInfo();
212
0
  for (uint32_t y = 0; y < height; y++)
213
0
  {
214
0
    for (uint32_t x = 0; x < width; x++)
215
0
    {
216
0
      const Pel pxlY = picY.buf[x];
217
0
      int64_t sum = 0, sumSq = 0;
218
0
      uint32_t numPixInPart = 0;
219
0
      uint32_t y1 = std::max((int)(y - winLens), 0);
220
0
      uint32_t y2 = std::min((int)(y + winLens), (height - 1));
221
0
      uint32_t x1 = std::max((int)(x - winLens), 0);
222
0
      uint32_t x2 = std::min((int)(x + winLens), (width - 1));
223
0
      uint32_t bx = 0, by = 0;
224
0
      const Pel* pWinY = &picY.buf[0];
225
0
      numPixInPart = (x2 - x1 + 1) * (y2 - y1 + 1);
226
227
0
      if (x == 0 && y == 0)
228
0
      {
229
0
        for (by = y1; by <= y2; by++)
230
0
        {
231
0
          for (bx = x1; bx <= x2; bx++)
232
0
          {
233
0
            tempSq =  (int64_t)pWinY[bx] *  (int64_t)pWinY[bx];
234
0
            leftSum += pWinY[bx];
235
0
            leftSumSq += tempSq;
236
0
            leftColSum[bx] += pWinY[bx];
237
0
            leftColSumSq[bx] += tempSq;
238
0
            topColSum[bx] += pWinY[bx];
239
0
            topColSumSq[bx] += tempSq;
240
0
            topRowSum[by] += pWinY[bx];
241
0
            topRowSumSq[by] += tempSq;
242
0
          }
243
0
          pWinY += stride;
244
0
        }
245
0
        topSum = leftSum;
246
0
        topSumSq = leftSumSq;
247
0
        sum = leftSum;
248
0
        sumSq = leftSumSq;
249
0
      }
250
0
      else if (x == 0 && y > 0)
251
0
      {
252
0
        if (y < height - winLens)
253
0
        {
254
0
          pWinY += winLens*stride;
255
0
          topRowSum[y + winLens] = 0;
256
0
          topRowSumSq[y + winLens] = 0;
257
0
          for (bx = x1; bx <= x2; bx++)
258
0
          {
259
0
            topRowSum[y + winLens] += pWinY[bx];
260
0
            topRowSumSq[y + winLens] +=  (int64_t)pWinY[bx] *  (int64_t)pWinY[bx];
261
0
          }
262
0
          topSum += topRowSum[y + winLens];
263
0
          topSumSq += topRowSumSq[y + winLens];
264
0
        }
265
0
        if (y > winLens)
266
0
        {
267
0
          topSum -= topRowSum[y - 1 - winLens];
268
0
          topSumSq -= topRowSumSq[y - 1 - winLens];
269
0
        }
270
0
        memset(leftColSum, 0, width * sizeof(int64_t));
271
0
        memset(leftColSumSq, 0, width * sizeof(int64_t));
272
0
        pWinY = &picY.buf[0];
273
0
        pWinY -= (y <= winLens ? y : winLens)*stride;
274
0
        for (by = y1; by <= y2; by++)
275
0
        {
276
0
          for (bx = x1; bx <= x2; bx++)
277
0
          {
278
0
            leftColSum[bx] += pWinY[bx];
279
0
            leftColSumSq[bx] +=  (int64_t)pWinY[bx] *  (int64_t)pWinY[bx];
280
0
          }
281
0
          pWinY += stride;
282
0
        }
283
0
        leftSum = topSum;
284
0
        leftSumSq = topSumSq;
285
0
        sum = topSum;
286
0
        sumSq = topSumSq;
287
0
      }
288
0
      else if (x > 0)
289
0
      {
290
0
        if (x < width - winLens)
291
0
        {
292
0
          pWinY -= (y <= winLens ? y : winLens)*stride;
293
0
          if (y == 0)
294
0
          {
295
0
            leftColSum[x + winLens] = 0;
296
0
            leftColSumSq[x + winLens] = 0;
297
0
            for (by = y1; by <= y2; by++)
298
0
            {
299
0
              leftColSum[x + winLens] += pWinY[x + winLens];
300
0
              leftColSumSq[x + winLens] +=  (int64_t)pWinY[x + winLens] *  (int64_t)pWinY[x + winLens];
301
0
              pWinY += stride;
302
0
            }
303
0
          }
304
0
          else
305
0
          {
306
0
            leftColSum[x + winLens] = topColSum[x + winLens];
307
0
            leftColSumSq[x + winLens] = topColSumSq[x + winLens];
308
0
            if (y < height - winLens)
309
0
            {
310
0
              pWinY = &picY.buf[0];
311
0
              pWinY += winLens * stride;
312
0
              leftColSum[x + winLens] += pWinY[x + winLens];
313
0
              leftColSumSq[x + winLens] +=  (int64_t)pWinY[x + winLens] *  (int64_t)pWinY[x + winLens];
314
0
            }
315
0
            if (y > winLens)
316
0
            {
317
0
              pWinY = &picY.buf[0];
318
0
              pWinY -= (winLens + 1) * stride;
319
0
              leftColSum[x + winLens] -= pWinY[x + winLens];
320
0
              leftColSumSq[x + winLens] -=  (int64_t)pWinY[x + winLens] *  (int64_t)pWinY[x + winLens];
321
0
            }
322
0
          }
323
0
          topColSum[x + winLens] = leftColSum[x + winLens];
324
0
          topColSumSq[x + winLens] = leftColSumSq[x + winLens];
325
0
          leftSum += leftColSum[x + winLens];
326
0
          leftSumSq += leftColSumSq[x + winLens];
327
0
        }
328
0
        if (x > winLens)
329
0
        {
330
0
          leftSum -= leftColSum[x - 1 - winLens];
331
0
          leftSumSq -= leftColSumSq[x - 1 - winLens];
332
0
        }
333
0
        sum = leftSum;
334
0
        sumSq = leftSumSq;
335
0
      }
336
      
337
0
      double average = double(sum) / numPixInPart;
338
0
      double variance = double(sumSq) / numPixInPart - average * average;
339
0
      int binLen = m_reshapeLUTSize / m_binNum;
340
0
      uint32_t binIdx = (uint32_t)(pxlY / binLen);
341
0
      if (m_lumaBD > 10)
342
0
      {
343
0
        average = average / (double)(1 << (m_lumaBD - 10));
344
0
        variance = variance / (double)(1 << (2 * m_lumaBD - 20));
345
0
      }
346
0
      else if (m_lumaBD < 10)
347
0
      {
348
0
        average = average * (double)(1 << (10 - m_lumaBD));
349
0
        variance = variance * (double)(1 << (20 - 2 * m_lumaBD));
350
0
      }
351
0
      double varLog10 = log10(variance + 1.0);
352
0
      stats.binVar[binIdx] += varLog10;
353
0
      binCnt[binIdx]++;
354
0
    }
355
0
    picY.buf += stride;
356
0
  }
357
358
0
  for (int b = 0; b < m_binNum; b++)
359
0
  {
360
0
    stats.binHist[b] = (double)binCnt[b] / (double)(m_reshapeCW.rspPicSize);
361
0
    stats.binVar[b] = (binCnt[b] > 0) ? (stats.binVar[b] / binCnt[b]) : 0.0;
362
0
  }
363
0
  delete[] binCnt;
364
0
  delete[] topColSum;
365
0
  delete[] topColSumSq;
366
0
  delete[] topRowSum;
367
0
  delete[] topRowSumSq;
368
0
  delete[] leftColSum;
369
0
  delete[] leftColSumSq;
370
371
0
  stats.minBinVar = 5.0;
372
0
  stats.maxBinVar = 0.0;
373
0
  stats.meanBinVar = 0.0;
374
0
  stats.nonZeroCnt = 0;
375
0
  for (int b = 0; b < m_binNum; b++)
376
0
  {
377
0
    if (stats.binHist[b] > 0.001)
378
0
    {
379
0
      stats.nonZeroCnt++;
380
0
      stats.meanBinVar += stats.binVar[b];
381
0
      if (stats.binVar[b] > stats.maxBinVar) { stats.maxBinVar = stats.binVar[b]; }
382
0
      if (stats.binVar[b] < stats.minBinVar) { stats.minBinVar = stats.binVar[b]; }
383
0
    }
384
0
  }
385
0
  stats.meanBinVar /= (double)stats.nonZeroCnt;
386
0
  for (int b = 0; b < m_binNum; b++)
387
0
  {
388
0
    if (stats.meanBinVar > 0.0)
389
0
      stats.normVar[b] = stats.binVar[b] / stats.meanBinVar;
390
0
    stats.weightVar += stats.binHist[b] * stats.binVar[b];
391
0
    stats.weightNorm += stats.binHist[b] * stats.normVar[b];
392
0
  }
393
394
0
  picY = pic.getOrigBuf(COMP_Y);
395
0
  double avgY = 0.0, avgU = 0.0, avgV = 0.0;
396
0
  double varY = 0.0, varU = 0.0, varV = 0.0;
397
0
  for (int y = 0; y < height; y++)
398
0
  {
399
0
    for (int x = 0; x < width; x++)
400
0
    {
401
0
      avgY += picY.buf[x];
402
0
      varY += (double)picY.buf[x] * (double)picY.buf[x];
403
0
    }
404
0
    picY.buf += stride;
405
0
  }
406
407
0
  if( pic.chromaFormat != VVENC_CHROMA_400 )
408
0
  {
409
0
    CPelBuf picU = pic.getOrigBuf(COMP_Cb);
410
0
    CPelBuf picV = pic.getOrigBuf(COMP_Cr);
411
0
    const int widthC = picU.width;
412
0
    const int heightC = picU.height;
413
0
    const int strideC = picU.stride;
414
0
    for (int y = 0; y < heightC; y++)
415
0
    {
416
0
      for (int x = 0; x < widthC; x++)
417
0
      {
418
0
        avgU += picU.buf[x];
419
0
        avgV += picV.buf[x];
420
0
        varU += (int64_t)picU.buf[x] * (int64_t)picU.buf[x];
421
0
        varV += (int64_t)picV.buf[x] * (int64_t)picV.buf[x];
422
0
      }
423
0
      picU.buf += strideC;
424
0
      picV.buf += strideC;
425
0
    }
426
0
    avgY = avgY / (width * height);
427
0
    avgU = avgU / (widthC * heightC);
428
0
    avgV = avgV / (widthC * heightC);
429
0
    varY = varY / (width * height) - avgY * avgY;
430
0
    varU = varU / (widthC * heightC) - avgU * avgU;
431
0
    varV = varV / (widthC * heightC) - avgV * avgV;
432
0
    if (varY > 0)
433
0
    {
434
0
      stats.ratioStdU = sqrt(varU) / sqrt(varY);
435
0
      stats.ratioStdV = sqrt(varV) / sqrt(varY);
436
0
    }
437
0
  }
438
0
}
439
440
void EncReshape::preAnalyzerLMCS(Picture& pic, const uint32_t signalType, const SliceType sliceType, const vvencReshapeCW& reshapeCW)
441
0
{
442
0
  m_sliceReshapeInfo.sliceReshaperModelPresent = true;
443
0
  m_sliceReshapeInfo.sliceReshaperEnabled = true;
444
0
  int modIP = pic.getPOC() - pic.getPOC() / reshapeCW.rspFpsToIp * reshapeCW.rspFpsToIp;
445
0
  if (sliceType == VVENC_I_SLICE || (reshapeCW.updateCtrl == 2 && modIP == 0))
446
0
  {
447
0
    if (m_sliceReshapeInfo.sliceReshaperModelPresent == true)
448
0
    {
449
0
      m_reshapeCW = reshapeCW;
450
0
      m_binNum = PIC_CODE_CW_BINS;
451
0
      int stdMin = 16 << (m_lumaBD - 8);
452
0
      int stdMax = 235 << (m_lumaBD - 8);
453
0
      int binLen = m_reshapeLUTSize / m_binNum;
454
0
      int startBinIdx = stdMin / binLen;
455
0
      int endBinIdx = stdMax / binLen;
456
0
      m_sliceReshapeInfo.reshaperModelMinBinIdx = startBinIdx;
457
0
      m_sliceReshapeInfo.reshaperModelMaxBinIdx = endBinIdx;
458
0
      m_initCWAnalyze = m_lumaBD > 10 ? (binLen >> (m_lumaBD - 10)) : m_lumaBD < 10 ? (binLen << (10 - m_lumaBD)) : binLen;
459
0
      for (int b = 0; b < m_binNum; b++) { m_binCW[b] = m_initCWAnalyze; }
460
461
0
      m_reshape = true;
462
0
      m_useAdpCW = false;
463
0
      m_exceedSTD = false;
464
0
      m_chromaWeight = 1.0;
465
0
      m_sliceReshapeInfo.enableChromaAdj = 1;
466
0
      m_rateAdpMode = 0;  m_tcase = 0;
467
0
      bool intraAdp = true, interAdp = true;
468
469
0
      calcSeqStats(pic, m_srcSeqStats);
470
0
      if (m_binNum == PIC_CODE_CW_BINS)
471
0
      {
472
0
        if ((m_srcSeqStats.binHist[0] + m_srcSeqStats.binHist[m_binNum - 1]) > 0.005) { m_exceedSTD = true; }
473
0
        if (m_srcSeqStats.binHist[m_binNum - 1] > 0.0003) { intraAdp = false;  interAdp = false; }
474
0
        if (m_srcSeqStats.binHist[0] > 0.03) { intraAdp = false;  interAdp = false; }
475
0
      }
476
0
      else if (m_binNum == PIC_ANALYZE_CW_BINS)
477
0
      {
478
0
        if ((m_srcSeqStats.binHist[0] + m_srcSeqStats.binHist[1] + m_srcSeqStats.binHist[m_binNum - 2] + m_srcSeqStats.binHist[m_binNum - 1]) > 0.01) { m_exceedSTD = true; }
479
0
        if ((m_srcSeqStats.binHist[m_binNum - 2] + m_srcSeqStats.binHist[m_binNum - 1]) > 0.0003) { intraAdp = false;  interAdp = false; }
480
0
        if ((m_srcSeqStats.binHist[0] + m_srcSeqStats.binHist[1]) > 0.03) { intraAdp = false;  interAdp = false; }
481
0
      }
482
0
      if (m_exceedSTD)
483
0
      {
484
0
        for (int i = 0; i < m_binNum; i++)
485
0
        {
486
0
          if (m_srcSeqStats.binHist[i] > 0 && i < startBinIdx) { startBinIdx = i; }
487
0
          if (m_srcSeqStats.binHist[i] > 0 && i > endBinIdx) { endBinIdx = i; }
488
0
        }
489
0
        m_sliceReshapeInfo.reshaperModelMinBinIdx = startBinIdx;
490
0
        m_sliceReshapeInfo.reshaperModelMaxBinIdx = endBinIdx;
491
0
      }
492
493
0
      if ((m_srcSeqStats.ratioStdU + m_srcSeqStats.ratioStdV) > 1.5 && m_srcSeqStats.binHist[1] > 0.5) { intraAdp = false;  interAdp = false; }
494
0
      if (m_srcSeqStats.ratioStdU > 0.36 && m_srcSeqStats.ratioStdV > 0.2 && m_reshapeCW.rspPicSize > 5184000)
495
0
      {
496
0
        m_sliceReshapeInfo.enableChromaAdj = 0; m_chromaWeight = 1.05;
497
0
        if ((m_srcSeqStats.ratioStdU + m_srcSeqStats.ratioStdV) < 0.69) { m_chromaWeight = 0.95; }
498
0
      }
499
500
0
      if (interAdp)
501
0
      {
502
0
        if (m_reshapeCW.adpOption)
503
0
        {
504
0
          m_reshapeCW.binCW[0] = 0; m_reshapeCW.binCW[1] = m_reshapeCW.initialCW;
505
0
          m_rateAdpMode = m_reshapeCW.adpOption - 2 * (m_reshapeCW.adpOption / 2);
506
0
          if (m_reshapeCW.adpOption == 2) { m_tcase = 9; }
507
0
          else if (m_reshapeCW.adpOption > 2) { intraAdp = false; }
508
0
        }
509
0
        else if (signalType == RESHAPE_SIGNAL_SDR)
510
0
        {
511
0
          m_reshapeCW.binCW[0] = 0; m_reshapeCW.binCW[1] = 1022;
512
0
          deriveReshapeParametersSDR(&intraAdp, &interAdp);
513
0
        }
514
0
        else if (signalType == RESHAPE_SIGNAL_HLG)
515
0
        {
516
0
          if (m_reshapeCW.updateCtrl == 0)
517
0
          {
518
0
            m_rateAdpMode = 0;  m_tcase = 9;
519
0
            m_reshapeCW.binCW[1] = 952;
520
0
            if (m_srcSeqStats.meanBinVar < 2.5) { m_reshapeCW.binCW[1] = 840; }
521
0
          }
522
0
          else
523
0
          {
524
0
            m_useAdpCW = true;
525
0
            m_rateAdpMode = 2;
526
0
            if (m_binNum == PIC_CODE_CW_BINS) { m_reshapeCW.binCW[0] = 72;  m_reshapeCW.binCW[1] = 58; }
527
0
            else if (m_binNum == PIC_ANALYZE_CW_BINS) { m_reshapeCW.binCW[0] = 36;  m_reshapeCW.binCW[1] = 30; }
528
0
            if (m_srcSeqStats.meanBinVar < 2.5) { intraAdp = false; interAdp = false; }
529
0
          }
530
0
        }
531
0
      }
532
533
0
      if (m_rateAdpMode == 2 && m_rspBaseQP <= 22) { intraAdp = false; interAdp = false; }
534
0
      m_sliceReshapeInfo.sliceReshaperEnabled = intraAdp;
535
0
      if (!intraAdp && !interAdp)
536
0
      {
537
0
        m_sliceReshapeInfo.sliceReshaperModelPresent = false;
538
0
        m_reshape = false;
539
0
        return;
540
0
      }
541
542
0
      if (m_rateAdpMode == 1 && m_rspBaseQP <= 22)
543
0
      {
544
0
        for (int i = 0; i < m_binNum; i++)
545
0
        {
546
0
          if (i >= startBinIdx && i <= endBinIdx) { m_binCW[i] = m_initCWAnalyze + 2; }
547
0
          else { m_binCW[i] = 0; }
548
0
        }
549
0
      }
550
0
      else if (m_useAdpCW)
551
0
      {
552
0
        if (signalType == RESHAPE_SIGNAL_SDR && m_reshapeCW.updateCtrl == 2)
553
0
        {
554
0
          m_binNum = PIC_ANALYZE_CW_BINS;
555
0
          startBinIdx = startBinIdx * 2;
556
0
          endBinIdx = endBinIdx * 2 + 1;
557
0
          calcSeqStats(pic, m_srcSeqStats);
558
0
        }
559
0
        double alpha = 1.0, beta = 0.0;
560
0
        deriveReshapeParameters(m_srcSeqStats.binVar, startBinIdx, endBinIdx, m_reshapeCW, alpha, beta);
561
0
        for (int i = 0; i < m_binNum; i++)
562
0
        {
563
0
          if (i >= startBinIdx && i <= endBinIdx) { m_binCW[i] = (uint32_t)round(alpha*m_srcSeqStats.binVar[i] + beta); }
564
0
          else { m_binCW[i] = 0; }
565
0
        }
566
0
      }
567
0
      else
568
0
      {
569
0
        cwPerturbation(startBinIdx, endBinIdx, (uint16_t)m_reshapeCW.binCW[1]);
570
0
      }
571
0
      cwReduction(startBinIdx, endBinIdx);
572
0
    }
573
0
    m_chromaAdj = m_sliceReshapeInfo.enableChromaAdj;
574
0
  }
575
0
  else // Inter slices
576
0
  {
577
0
    m_sliceReshapeInfo.sliceReshaperModelPresent = false;
578
0
    m_sliceReshapeInfo.enableChromaAdj = m_chromaAdj;
579
0
    if (!m_reshape) { m_sliceReshapeInfo.sliceReshaperEnabled = false; }
580
0
    else
581
0
    {
582
0
      const int cTid = m_reshapeCW.rspTid;
583
0
      bool enableRsp = m_tcase == 5 ? false : (m_tcase < 5 ? (cTid < m_tcase + 1 ? false : true) : (cTid <= 10 - m_tcase ? true : false));
584
0
      m_sliceReshapeInfo.sliceReshaperEnabled = enableRsp;
585
586
0
      if( m_sliceReshapeInfo.sliceReshaperEnabled )
587
0
      {
588
0
        m_binNum = PIC_CODE_CW_BINS;
589
0
        CPelBuf picY = pic.getOrigBuf( COMP_Y );
590
0
        const int width = picY.width;
591
0
        const int height = picY.height;
592
0
        const int stride = picY.stride;
593
0
        uint32_t binCnt[PIC_CODE_CW_BINS];
594
0
        std::fill_n( binCnt, m_binNum, 0 );
595
596
0
        m_srcSeqStats = SeqInfo();
597
0
        for( uint32_t y = 0; y < height; y++ )
598
0
        {
599
0
          for( uint32_t x = 0; x < width; x++ )
600
0
          {
601
0
            const Pel pxlY = picY.buf[x];
602
0
            int binLen = m_reshapeLUTSize / m_binNum;
603
0
            uint32_t binIdx = ( uint32_t ) (pxlY / binLen);
604
0
            binCnt[binIdx]++;
605
0
          }
606
0
          picY.buf += stride;
607
0
        }
608
609
0
        for( int b = 0; b < m_binNum; b++ )
610
0
        {
611
0
          m_srcSeqStats.binHist[b] = ( double ) binCnt[b] / ( double ) (m_reshapeCW.rspPicSize);
612
0
        }
613
614
0
        if( m_srcSeqStats.binHist[m_binNum - 1] > 0.0003 )
615
0
        {
616
0
          m_sliceReshapeInfo.sliceReshaperEnabled = false;
617
0
        }
618
0
        if( m_srcSeqStats.binHist[0] > 0.03 )
619
0
        {
620
0
          m_sliceReshapeInfo.sliceReshaperEnabled = false;
621
0
        }
622
623
0
        if( m_sliceReshapeInfo.sliceReshaperEnabled )
624
0
        {
625
0
          double avgY = 0.0;
626
0
          double varY = 0.0;
627
0
          picY = pic.getOrigBuf( COMP_Y );
628
0
          for( int y = 0; y < height; y++ )
629
0
          {
630
0
            for( int x = 0; x < width; x++ )
631
0
            {
632
0
              avgY += picY.buf[x];
633
0
              varY += ( double ) picY.buf[x] * ( double ) picY.buf[x];
634
0
            }
635
0
            picY.buf += stride;
636
0
          }
637
0
          avgY = avgY / (width * height);
638
0
          varY = varY / (width * height) - avgY * avgY;
639
640
0
          if( isChromaEnabled( pic.chromaFormat ) )
641
0
          {
642
0
            CPelBuf picU = pic.getOrigBuf( COMP_Cb );
643
0
            CPelBuf picV = pic.getOrigBuf( COMP_Cr );
644
0
            const int widthC = picU.width;
645
0
            const int heightC = picU.height;
646
0
            const int strideC = picU.stride;
647
0
            double avgU = 0.0, avgV = 0.0;
648
0
            double varU = 0.0, varV = 0.0;
649
0
            for( int y = 0; y < heightC; y++ )
650
0
            {
651
0
              for( int x = 0; x < widthC; x++ )
652
0
              {
653
0
                avgU += picU.buf[x];
654
0
                avgV += picV.buf[x];
655
0
                varU += ( int64_t ) picU.buf[x] * ( int64_t ) picU.buf[x];
656
0
                varV += ( int64_t ) picV.buf[x] * ( int64_t ) picV.buf[x];
657
0
              }
658
0
              picU.buf += strideC;
659
0
              picV.buf += strideC;
660
0
            }
661
0
            avgU = avgU / (widthC * heightC);
662
0
            avgV = avgV / (widthC * heightC);
663
0
            varU = varU / (widthC * heightC) - avgU * avgU;
664
0
            varV = varV / (widthC * heightC) - avgV * avgV;
665
0
            if( varY > 0 )
666
0
            {
667
0
              m_srcSeqStats.ratioStdU = sqrt( varU ) / sqrt( varY );
668
0
              m_srcSeqStats.ratioStdV = sqrt( varV ) / sqrt( varY );
669
0
            }
670
0
          }
671
0
        }
672
673
0
        if( (m_srcSeqStats.ratioStdU + m_srcSeqStats.ratioStdV) > 1.5 && m_srcSeqStats.binHist[1] > 0.5 )
674
0
        {
675
0
          m_sliceReshapeInfo.sliceReshaperEnabled = false;
676
0
        }
677
0
      }
678
0
    }
679
0
  }
680
0
}
681
682
// Bubble Sort to  descending order with index
683
void EncReshape::bubbleSortDsd(double* array, int * idx, int n)
684
0
{
685
0
  int i, j;
686
0
  bool swapped;
687
0
  for (i = 0; i < n - 1; i++)
688
0
  {
689
0
    swapped = false;
690
0
    for (j = 0; j < n - i - 1; j++)
691
0
    {
692
0
      if (array[j] < array[j + 1])
693
0
      {
694
0
        std::swap(array[j], array[j + 1]);
695
0
        std::swap(idx[j], idx[j + 1]);
696
0
        swapped = true;
697
0
      }
698
0
    }
699
0
    if (swapped == false)
700
0
      break;
701
0
  }
702
0
}
703
704
void EncReshape::cwPerturbation(int startBinIdx, int endBinIdx, uint16_t maxCW)
705
0
{
706
0
  for (int i = 0; i < m_binNum; i++)
707
0
  {
708
0
    if (i >= startBinIdx && i <= endBinIdx) { m_binCW[i] = (uint32_t)round((double)maxCW / (endBinIdx - startBinIdx + 1)); }
709
0
    else { m_binCW[i] = 0; }
710
0
  }
711
712
0
  double hist = 0.0;
713
0
  uint16_t delta1 = 0, delta2 = 0;
714
0
  for (int i = 0; i < m_binNum; i++)
715
0
  {
716
0
    if (m_srcSeqStats.binHist[i] > 0.001)
717
0
    {
718
0
      hist = m_srcSeqStats.binHist[i] > 0.4 ? 0.4 : m_srcSeqStats.binHist[i];
719
0
      delta1 = (uint16_t)(10.0 * hist + 0.5);
720
0
      delta2 = (uint16_t)(20.0 * hist + 0.5);
721
0
      if (m_srcSeqStats.normVar[i] < 0.8) { m_binCW[i] = m_binCW[i] + delta2; }
722
0
      else if (m_srcSeqStats.normVar[i] < 0.9) { m_binCW[i] = m_binCW[i] + delta1; }
723
0
      if (m_srcSeqStats.normVar[i] > 1.2) { m_binCW[i] = m_binCW[i] - delta2; }
724
0
      else if (m_srcSeqStats.normVar[i] > 1.1) { m_binCW[i] = m_binCW[i] - delta1; }
725
0
    }
726
0
  }
727
0
}
728
729
void EncReshape::cwReduction(int startBinIdx, int endBinIdx)
730
0
{
731
0
  int bdShift = m_lumaBD - 10;
732
0
  int totCW = bdShift != 0 ? (bdShift > 0 ? m_reshapeLUTSize / (1 << bdShift) : m_reshapeLUTSize * (1 << (-bdShift))) : m_reshapeLUTSize;
733
0
  int maxAllowedCW = totCW - 1, usedCW = 0;
734
0
  for (int i = 0; i < m_binNum; i++) { usedCW += m_binCW[i]; }
735
0
  if (usedCW > maxAllowedCW)
736
0
  {
737
0
    int deltaCW = usedCW - maxAllowedCW;
738
0
    int divCW = deltaCW / (endBinIdx - startBinIdx + 1);
739
0
    int modCW = deltaCW - divCW * (endBinIdx - startBinIdx + 1);
740
0
    if (divCW > 0)
741
0
    {
742
0
      for (int i = startBinIdx; i <= endBinIdx; i++) { m_binCW[i] -= divCW; }
743
0
    }
744
0
    for (int i = startBinIdx; i <= endBinIdx; i++)
745
0
    {
746
0
      if (modCW == 0)  break;
747
0
      if (m_binCW[i] > 0) { m_binCW[i]--; modCW--; }
748
0
    }
749
0
  }
750
0
}
751
752
void EncReshape::deriveReshapeParametersSDR(bool *intraAdp, bool *interAdp)
753
0
{
754
0
  bool   isSkipCase = false;
755
0
  bool   isLowCase = false;
756
0
  int    firstBinVarLessThanVal1 = 0;
757
0
  int    firstBinVarLessThanVal2 = 0;
758
0
  int    firstBinVarLessThanVal3 = 0;
759
0
  double percBinVarLessThenVal1 = 0.0;
760
0
  double percBinVarLessThenVal2 = 0.0;
761
0
  double percBinVarLessThenVal3 = 0.0;
762
0
  int    *binIdxSortDsd = new int[m_binNum];
763
0
  double *binVarSortDsd = new double[m_binNum];
764
0
  double *binVarSortDsdCDF = new double[m_binNum];
765
0
  double ratioWeiVar = 0.0, ratioWeiVarNorm = 0.0;
766
0
  int startBinIdx = m_sliceReshapeInfo.reshaperModelMinBinIdx;
767
0
  int endBinIdx = m_sliceReshapeInfo.reshaperModelMaxBinIdx;
768
769
0
  for (int b = 0; b < m_binNum; b++)
770
0
  {
771
0
    binVarSortDsd[b] = m_srcSeqStats.binVar[b];
772
0
    binIdxSortDsd[b] = b;
773
0
  }
774
0
  bubbleSortDsd(binVarSortDsd, binIdxSortDsd, m_binNum);
775
0
  binVarSortDsdCDF[0] = m_srcSeqStats.binHist[binIdxSortDsd[0]];
776
0
  for (int b = 1; b < m_binNum; b++) { binVarSortDsdCDF[b] = binVarSortDsdCDF[b - 1] + m_srcSeqStats.binHist[binIdxSortDsd[b]]; }
777
0
  for (int b = 0; b < m_binNum - 1; b++)
778
0
  {
779
0
    if (binVarSortDsd[b] > 3.4) { firstBinVarLessThanVal1 = b + 1; }
780
0
    if (binVarSortDsd[b] > 2.8) { firstBinVarLessThanVal2 = b + 1; }
781
0
    if (binVarSortDsd[b] > 2.5) { firstBinVarLessThanVal3 = b + 1; }
782
0
  }
783
0
  percBinVarLessThenVal1 = binVarSortDsdCDF[firstBinVarLessThanVal1];
784
0
  percBinVarLessThenVal2 = binVarSortDsdCDF[firstBinVarLessThanVal2];
785
0
  percBinVarLessThenVal3 = binVarSortDsdCDF[firstBinVarLessThanVal3];
786
0
  delete[] binIdxSortDsd;
787
0
  delete[] binVarSortDsd;
788
0
  delete[] binVarSortDsdCDF;
789
790
0
  cwPerturbation(startBinIdx, endBinIdx, (uint16_t)m_reshapeCW.binCW[1]);
791
0
  cwReduction(startBinIdx, endBinIdx);
792
0
  m_rspSeqStats = SeqInfo();
793
0
  for (int b = 0; b < m_binNum; b++)
794
0
  {
795
0
    double scale = (m_binCW[b] > 0) ? ((double)m_binCW[b] / (double)m_initCWAnalyze) : 1.0;
796
0
    m_rspSeqStats.binHist[b] = m_srcSeqStats.binHist[b];
797
0
    m_rspSeqStats.binVar[b] = m_srcSeqStats.binVar[b] + 2.0 * log10(scale);
798
0
  }
799
0
  m_rspSeqStats.minBinVar = 5.0;
800
0
  m_rspSeqStats.maxBinVar = 0.0;
801
0
  m_rspSeqStats.meanBinVar = 0.0;
802
0
  m_rspSeqStats.nonZeroCnt = 0;
803
0
  for (int b = 0; b < m_binNum; b++)
804
0
  {
805
0
    if (m_rspSeqStats.binHist[b] > 0.001)
806
0
    {
807
0
      m_rspSeqStats.nonZeroCnt++;
808
0
      m_rspSeqStats.meanBinVar += m_rspSeqStats.binVar[b];
809
0
      if (m_rspSeqStats.binVar[b] > m_rspSeqStats.maxBinVar) { m_rspSeqStats.maxBinVar = m_rspSeqStats.binVar[b]; }
810
0
      if (m_rspSeqStats.binVar[b] < m_rspSeqStats.minBinVar) { m_rspSeqStats.minBinVar = m_rspSeqStats.binVar[b]; }
811
0
    }
812
0
  }
813
0
  m_rspSeqStats.meanBinVar /= (double)m_rspSeqStats.nonZeroCnt;
814
0
  for (int b = 0; b < m_binNum; b++)
815
0
  {
816
0
    if (m_rspSeqStats.meanBinVar > 0.0)
817
0
      m_rspSeqStats.normVar[b] = m_rspSeqStats.binVar[b] / m_rspSeqStats.meanBinVar;
818
0
    m_rspSeqStats.weightVar += m_rspSeqStats.binHist[b] * m_rspSeqStats.binVar[b];
819
0
    m_rspSeqStats.weightNorm += m_rspSeqStats.binHist[b] * m_rspSeqStats.normVar[b];
820
0
  }
821
0
  ratioWeiVar = m_rspSeqStats.weightVar / m_srcSeqStats.weightVar;
822
0
  ratioWeiVarNorm = m_rspSeqStats.weightNorm / m_srcSeqStats.weightNorm;
823
824
0
  if ((m_srcSeqStats.binHist[0] + m_srcSeqStats.binHist[m_binNum - 1]) > 0.0001 && m_srcSeqStats.binHist[m_binNum - 2] < 0.001)
825
0
  {
826
0
    if (percBinVarLessThenVal3 > 0.8 && percBinVarLessThenVal2 > 0.4 && m_srcSeqStats.binVar[m_binNum - 2] > 4.8) { isSkipCase = true; }
827
0
    else if (percBinVarLessThenVal3 < 0.1 && percBinVarLessThenVal1 < 0.05 && m_srcSeqStats.binVar[m_binNum - 2] < 4.0) { isSkipCase = true; }
828
0
  }
829
0
  if (isSkipCase) { *intraAdp = false;  *interAdp = false;  return; }
830
831
0
  if (m_reshapeCW.rspPicSize > 5184000) { isLowCase = true; }
832
0
  else if (m_srcSeqStats.binVar[1] > 4.0) { isLowCase = true; }
833
0
  else if (m_rspSeqStats.meanBinVar > 3.4 && ratioWeiVarNorm > 1.005 && ratioWeiVar > 1.02) { isLowCase = true; }
834
0
  else if (m_rspSeqStats.meanBinVar > 3.1 && ratioWeiVarNorm > 1.005 && ratioWeiVar > 1.04) { isLowCase = true; }
835
0
  else if (m_rspSeqStats.meanBinVar > 2.8 && ratioWeiVarNorm > 1.01 && ratioWeiVar > 1.04) { isLowCase = true; }
836
837
0
  if (m_reshapeCW.updateCtrl == 0)
838
0
  {
839
0
    m_reshapeCW.binCW[1] = 1022;
840
0
    if (isLowCase)
841
0
    {
842
0
      *intraAdp = false;
843
0
      m_rateAdpMode = 1;
844
0
      m_reshapeCW.binCW[1] = 980;
845
0
      if (m_srcSeqStats.binHist[m_binNum - 2] > 0.05)
846
0
      {
847
0
        m_reshapeCW.binCW[1] = 896;
848
0
        if (m_srcSeqStats.binVar[m_binNum - 2] < 1.2) { m_reshapeCW.binCW[1] = 938; }
849
0
      }
850
0
      else if (percBinVarLessThenVal2 < 0.8 && percBinVarLessThenVal3 == 1.0)
851
0
      {
852
0
        m_rateAdpMode = 1;
853
0
        m_reshapeCW.binCW[1] = 938;
854
0
      }
855
0
    }
856
0
    if (m_srcSeqStats.binHist[m_binNum - 2] < 0.001)
857
0
    {
858
0
      if (m_srcSeqStats.binHist[1] > 0.05 && m_srcSeqStats.binVar[1] > 3.0)
859
0
      {
860
0
        *intraAdp = true;
861
0
        m_rateAdpMode = 1;
862
0
        m_reshapeCW.binCW[1] = 784;
863
0
      }
864
0
      else if (m_srcSeqStats.binHist[1] < 0.006)
865
0
      {
866
0
        *intraAdp = false;
867
0
        m_rateAdpMode = 0;
868
0
        m_reshapeCW.binCW[1] = 1008;
869
0
      }
870
0
      else if (percBinVarLessThenVal3 < 0.5)
871
0
      {
872
0
        *intraAdp = true;
873
0
        m_rateAdpMode = 0;
874
0
        m_reshapeCW.binCW[1] = 1022;
875
0
      }
876
0
    }
877
0
    else if ((m_srcSeqStats.maxBinVar > 4.0 && m_rspSeqStats.meanBinVar > 3.2 && percBinVarLessThenVal2 < 0.25) || ratioWeiVar < 1.03)
878
0
    {
879
0
      *intraAdp = true;
880
0
      m_rateAdpMode = 0;
881
0
      m_reshapeCW.binCW[1] = 1022;
882
0
    }
883
0
    if (*intraAdp == true && m_rateAdpMode == 0) { m_tcase = 9; }
884
0
  }
885
0
  else if (m_reshapeCW.updateCtrl == 1)
886
0
  {
887
0
    m_reshapeCW.binCW[1] = 952;
888
0
    if (isLowCase)
889
0
    {
890
0
      if (m_reshapeCW.rspPicSize > 5184000)
891
0
      {
892
0
        m_rateAdpMode = 1;
893
0
        m_reshapeCW.binCW[1] = 812;
894
0
      }
895
0
      if (m_srcSeqStats.binHist[m_binNum - 2] > 0.05)
896
0
      {
897
0
        m_rateAdpMode = 1;
898
0
        m_reshapeCW.binCW[1] = 812;
899
0
        if (m_srcSeqStats.binHist[m_binNum - 2] > 0.1 || m_srcSeqStats.binHist[1] > 0.1)
900
0
        {
901
0
          m_rateAdpMode = 0;
902
0
          m_reshapeCW.binCW[1] = 924;
903
0
        }
904
0
      }
905
0
      else if (percBinVarLessThenVal2 < 0.8 && percBinVarLessThenVal3 == 1.0)
906
0
      {
907
0
        m_rateAdpMode = 1;
908
0
        m_reshapeCW.binCW[1] = 896;
909
0
      }
910
0
      else if (percBinVarLessThenVal2 > 0.98 && m_srcSeqStats.binHist[1] > 0.05)
911
0
      {
912
0
        m_rateAdpMode = 0;
913
0
        m_reshapeCW.binCW[1] = 784;
914
0
      }
915
0
      else if (percBinVarLessThenVal2 < 0.1)
916
0
      {
917
0
        m_rateAdpMode = 0;
918
0
        m_reshapeCW.binCW[1] = 1022;
919
0
      }
920
0
    }
921
0
    if (m_srcSeqStats.binHist[1] > 0.1 && (m_srcSeqStats.binVar[1] > 1.8 && m_srcSeqStats.binVar[1] < 3.0))
922
0
    {
923
0
      m_rateAdpMode = 1;
924
0
      if (m_srcSeqStats.binVar[m_binNum - 2] > 1.2 && m_srcSeqStats.binVar[m_binNum - 2] < 4.0) { m_reshapeCW.binCW[1] = 784; }
925
0
    }
926
0
    else if (m_srcSeqStats.binHist[m_binNum - 2] < 0.001)
927
0
    {
928
0
      if (m_srcSeqStats.binHist[1] > 0.05 && m_srcSeqStats.binVar[1] > 3.0)
929
0
      {
930
0
        m_rateAdpMode = 1;
931
0
        m_reshapeCW.binCW[1] = 784;
932
0
      }
933
0
      else if (m_srcSeqStats.binHist[1] < 0.006)
934
0
      {
935
0
        m_rateAdpMode = 0;
936
0
        m_reshapeCW.binCW[1] = 980;
937
0
      }
938
0
      else if (percBinVarLessThenVal3 < 0.5)
939
0
      {
940
0
        m_rateAdpMode = 0;
941
0
        m_reshapeCW.binCW[1] = 924;
942
0
      }
943
0
    }
944
0
    else if ((m_srcSeqStats.maxBinVar > 4.0 && m_rspSeqStats.meanBinVar > 3.2 && percBinVarLessThenVal2 < 0.25) || ratioWeiVar < 1.03)
945
0
    {
946
0
      m_rateAdpMode = 0;
947
0
      m_reshapeCW.binCW[1] = 980;
948
0
    }
949
0
  }
950
0
  else
951
0
  {
952
0
    m_useAdpCW = true;
953
0
    m_reshapeCW.binCW[0] = 36;  m_reshapeCW.binCW[1] = 30;
954
0
    if (isLowCase)
955
0
    {
956
0
      if (m_srcSeqStats.binHist[m_binNum - 2] > 0.05)
957
0
      {
958
0
        m_useAdpCW = false;
959
0
        m_rateAdpMode = 1;
960
0
        m_reshapeCW.binCW[1] = 896;
961
0
        if (m_srcSeqStats.binHist[1] > 0.005) { m_rateAdpMode = 0; }
962
0
      }
963
0
      else if (percBinVarLessThenVal2 < 0.8 && percBinVarLessThenVal3 == 1.0) { m_reshapeCW.binCW[1] = 28; }
964
0
    }
965
0
    if (m_srcSeqStats.binHist[1] > 0.1 && m_srcSeqStats.binVar[1] > 1.8 && m_srcSeqStats.binVar[1] < 3.0)
966
0
    {
967
0
      m_useAdpCW = false;
968
0
      m_rateAdpMode = 1;
969
0
      m_reshapeCW.binCW[1] = 952;
970
0
    }
971
0
    else if (m_srcSeqStats.binHist[1] > 0.05 && m_srcSeqStats.binHist[m_binNum - 2] < 0.001 && m_srcSeqStats.binVar[1] > 3.0)
972
0
    {
973
0
      m_useAdpCW = false;
974
0
      m_rateAdpMode = 1;
975
0
      m_reshapeCW.binCW[1] = 784;
976
0
    }
977
0
    else if (m_srcSeqStats.binHist[1] > 0.05 && m_srcSeqStats.binHist[m_binNum - 2] < 0.005 && m_srcSeqStats.binVar[1] > 1.0 && m_srcSeqStats.binVar[1] < 1.5)
978
0
    {
979
0
      m_rateAdpMode = 2;
980
0
      m_reshapeCW.binCW[0] = 38;
981
0
    }
982
0
    else if (m_srcSeqStats.binHist[1] < 0.005 && m_srcSeqStats.binHist[m_binNum - 2] > 0.05 && m_srcSeqStats.binVar[m_binNum - 2] > 1.0 && m_srcSeqStats.binVar[m_binNum - 2] < 1.5)
983
0
    {
984
0
      m_rateAdpMode = 2;
985
0
      m_reshapeCW.binCW[0] = 36;
986
0
    }
987
0
    else if (m_srcSeqStats.binHist[1] > 0.02 && m_srcSeqStats.binHist[m_binNum - 2] > 0.04 && m_srcSeqStats.binVar[1] < 2.0 && m_srcSeqStats.binVar[m_binNum - 2] < 1.5)
988
0
    {
989
0
      m_rateAdpMode = 2;
990
0
      m_reshapeCW.binCW[0] = 34;
991
0
    }
992
0
    else if ((m_srcSeqStats.binHist[1] > 0.05 && m_srcSeqStats.binHist[m_binNum - 2] > 0.2 && m_srcSeqStats.binVar[1] > 3.0 && m_srcSeqStats.binVar[1] < 4.0) || ratioWeiVar < 1.03)
993
0
    {
994
0
      m_rateAdpMode = 1;
995
0
      m_reshapeCW.binCW[0] = 34;
996
0
    }
997
0
    else if (m_srcSeqStats.binVar[1] < 4.0 && percBinVarLessThenVal2 == 1.0 && percBinVarLessThenVal3 == 1.0)
998
0
    {
999
0
      m_rateAdpMode = 0;
1000
0
      m_reshapeCW.binCW[0] = 34;
1001
0
    }
1002
0
    if (m_useAdpCW && !isLowCase) { m_reshapeCW.binCW[1] = 66 - m_reshapeCW.binCW[0]; }
1003
0
  }
1004
0
}
1005
1006
void EncReshape::deriveReshapeParameters(double *array, int start, int end, vvencReshapeCW respCW, double &alpha, double &beta)
1007
0
{
1008
0
  double minVar = 10.0, maxVar = 0.0;
1009
0
  for (int b = start; b <= end; b++)
1010
0
  {
1011
0
    if (array[b] < minVar)       minVar = array[b];
1012
0
    if (array[b] > maxVar)       maxVar = array[b];
1013
0
  }
1014
0
  double maxCW = (double)respCW.binCW[0];
1015
0
  double minCW = (double)respCW.binCW[1];
1016
0
  alpha = (minCW - maxCW) / (maxVar - minVar);
1017
0
  beta = (maxCW*maxVar - minCW*minVar) / (maxVar - minVar);
1018
0
}
1019
1020
/**
1021
-Init reshaping LUT  from dQP model
1022
*/
1023
void EncReshape::initLUTfromdQPModel()
1024
0
{
1025
0
  int pwlFwdLUTsize = PIC_CODE_CW_BINS;
1026
0
  int pwlFwdBinLen = m_reshapeLUTSize / PIC_CODE_CW_BINS;
1027
0
  double lumaDQP = 0.0;
1028
0
  double * slopeLUT = new double[m_reshapeLUTSize]();
1029
0
  double * fwdLUTHighPrec = new double[m_reshapeLUTSize]();
1030
0
  for (int i = 0; i < m_reshapeLUTSize; i++)
1031
0
  {
1032
0
    int inputY = m_lumaBD < 10 ? i << (10 - m_lumaBD) : m_lumaBD > 10 ? i >> (m_lumaBD - 10) : i;
1033
0
    lumaDQP = 0.015*(double)inputY - 7.5;
1034
0
    lumaDQP = lumaDQP<-3 ? -3 : (lumaDQP>6 ? 6 : lumaDQP);
1035
0
    slopeLUT[i] = pow(2.0, lumaDQP / 6.0);
1036
0
  }
1037
0
  for (int i = 0; i < (16 << (m_lumaBD - 8)); i++) { slopeLUT[i] = 0.0; }
1038
0
  for (int i = (235 << (m_lumaBD - 8)); i < m_reshapeLUTSize; i++) { slopeLUT[i] = 0.0; }
1039
0
  for (int i = 0; i < m_reshapeLUTSize - 1; i++)
1040
0
    fwdLUTHighPrec[i + 1] = fwdLUTHighPrec[i] + slopeLUT[i];
1041
0
  delete[] slopeLUT;
1042
0
  slopeLUT = nullptr;
1043
1044
0
  double maxY = fwdLUTHighPrec[m_reshapeLUTSize - 1];
1045
0
  for (int i = 0; i < m_reshapeLUTSize; i++)
1046
0
  {
1047
0
    m_fwdLUT[i] = (int16_t)((fwdLUTHighPrec[i] / maxY * (double)(m_reshapeLUTSize - 1)) + 0.5);
1048
0
  }
1049
1050
0
  delete[] fwdLUTHighPrec;
1051
0
  fwdLUTHighPrec = nullptr;
1052
0
  m_sliceReshapeInfo.reshaperModelMinBinIdx = 1;
1053
0
  m_sliceReshapeInfo.reshaperModelMaxBinIdx = PIC_CODE_CW_BINS-2;
1054
1055
0
  for (int i = 0; i < pwlFwdLUTsize; i++)
1056
0
  {
1057
0
    int16_t X1 = i * pwlFwdBinLen;
1058
0
    m_reshapePivot[i] = m_fwdLUT[X1];
1059
0
  }
1060
0
  m_reshapePivot[pwlFwdLUTsize] = ((1 << m_lumaBD) - 1);
1061
1062
0
  for (int i = 0; i < pwlFwdLUTsize; i++)
1063
0
  {
1064
0
    m_binCW[i] = m_reshapePivot[i + 1] - m_reshapePivot[i];
1065
0
  }
1066
0
  for (int i = 0; i <= PIC_CODE_CW_BINS; i++)
1067
0
  {
1068
0
    m_inputPivot[i] = m_initCW * i;
1069
0
  }
1070
1071
0
  adjustLmcsPivot();
1072
1073
0
  int maxAbsDeltaCW = 0, absDeltaCW = 0, deltaCW = 0;
1074
0
  for (int i = m_sliceReshapeInfo.reshaperModelMinBinIdx; i <= m_sliceReshapeInfo.reshaperModelMaxBinIdx; i++)
1075
0
  {
1076
0
    deltaCW = (int)m_binCW[i] - (int)m_initCW;
1077
0
    m_sliceReshapeInfo.reshaperModelBinCWDelta[i] = deltaCW;
1078
0
    absDeltaCW = (deltaCW < 0) ? (-deltaCW) : deltaCW;
1079
0
    if (absDeltaCW > maxAbsDeltaCW)     {      maxAbsDeltaCW = absDeltaCW;    }
1080
0
  }
1081
0
  m_sliceReshapeInfo.maxNbitsNeededDeltaCW = 1 + floorLog2(std::max(1, maxAbsDeltaCW));
1082
1083
0
  for (int i = 0; i < pwlFwdLUTsize; i++)
1084
0
  {
1085
0
    m_fwdScaleCoef[i] = ((int32_t)m_binCW[i] * (1 << FP_PREC) + (1 << (floorLog2(pwlFwdBinLen) - 1))) >> floorLog2(pwlFwdBinLen);
1086
0
    if (m_binCW[i] == 0)
1087
0
    {
1088
0
      m_invScaleCoef[i] = 0;
1089
0
      m_chromaAdjHelpLUT[i] = 1 << CSCALE_FP_PREC;
1090
0
    }
1091
0
    else
1092
0
    {
1093
0
      m_invScaleCoef[i] = (int32_t)(m_initCW * (1 << FP_PREC) / m_binCW[i]);
1094
0
      m_chromaAdjHelpLUT[i] = (int32_t)(m_initCW * (1 << FP_PREC) / (m_binCW[i] + m_sliceReshapeInfo.chrResScalingOffset));
1095
0
    }
1096
0
  }
1097
0
  for (int lumaSample = 0; lumaSample < m_reshapeLUTSize; lumaSample++)
1098
0
  {
1099
0
    int idxY = lumaSample / m_initCW;
1100
0
    int tempVal = m_reshapePivot[idxY] + ((m_fwdScaleCoef[idxY] * (lumaSample - m_inputPivot[idxY]) + (1 << (FP_PREC - 1))) >> FP_PREC);
1101
0
    m_fwdLUT[lumaSample] = Clip3((Pel)0, (Pel)((1 << m_lumaBD) - 1), (Pel)(tempVal));
1102
1103
0
    int idxYInv = getPWLIdxInv(lumaSample);
1104
0
    int invSample = m_inputPivot[idxYInv] + ((m_invScaleCoef[idxYInv] * (lumaSample - m_reshapePivot[idxYInv]) + (1 << (FP_PREC - 1))) >> FP_PREC);
1105
0
    m_invLUT[lumaSample] = Clip3((Pel)0, (Pel)((1 << m_lumaBD) - 1), (Pel)(invSample));
1106
0
  }
1107
0
}
1108
1109
void EncReshape::constructReshaperLMCS()
1110
0
{
1111
0
  int bdShift = m_lumaBD - 10;
1112
0
  int totCW = bdShift != 0 ? (bdShift > 0 ? m_reshapeLUTSize / (1 << bdShift) : m_reshapeLUTSize * (1 << (-bdShift))) : m_reshapeLUTSize;
1113
0
  int histLenth = totCW / m_binNum;
1114
0
  int log2HistLenth = floorLog2(histLenth);
1115
0
  int i;
1116
1117
0
  if (bdShift != 0)
1118
0
  {
1119
0
    for (int i = 0; i < PIC_ANALYZE_CW_BINS; i++)
1120
0
    {
1121
0
      m_binCW[i] = bdShift > 0 ? m_binCW[i] * (1 << bdShift) : m_binCW[i] / (1 << (-bdShift));
1122
0
    }
1123
0
  }
1124
0
  if (m_binNum == PIC_ANALYZE_CW_BINS)
1125
0
  {
1126
0
    for (int i = 0; i < PIC_CODE_CW_BINS; i++)
1127
0
    {
1128
0
      m_binCW[i] = m_binCW[2 * i] + m_binCW[2 * i + 1];
1129
0
    }
1130
0
  }
1131
0
  for (int i = 0; i <= PIC_CODE_CW_BINS; i++)
1132
0
  {
1133
0
    m_inputPivot[i] = m_initCW * i;
1134
0
  }
1135
1136
0
  m_sliceReshapeInfo.reshaperModelMinBinIdx = 0;
1137
0
  m_sliceReshapeInfo.reshaperModelMaxBinIdx = PIC_CODE_CW_BINS - 1;
1138
0
  for (int i = 0; i < PIC_CODE_CW_BINS; i++)
1139
0
  {
1140
0
    if (m_binCW[i] > 0)
1141
0
    {
1142
0
      m_sliceReshapeInfo.reshaperModelMinBinIdx = i;
1143
0
      break;
1144
0
    }
1145
0
  }
1146
0
  for (int i = PIC_CODE_CW_BINS - 1; i >= 0; i--)
1147
0
  {
1148
0
    if (m_binCW[i] > 0)
1149
0
    {
1150
0
      m_sliceReshapeInfo.reshaperModelMaxBinIdx = i;
1151
0
      break;
1152
0
    }
1153
0
  }
1154
1155
0
  adjustLmcsPivot();
1156
1157
0
  int maxAbsDeltaCW = 0, absDeltaCW = 0, deltaCW = 0;
1158
0
  for (int i = m_sliceReshapeInfo.reshaperModelMinBinIdx; i <= m_sliceReshapeInfo.reshaperModelMaxBinIdx; i++)
1159
0
  {
1160
0
    deltaCW = (int)m_binCW[i] - (int)m_initCW;
1161
0
    m_sliceReshapeInfo.reshaperModelBinCWDelta[i] = deltaCW;
1162
0
    absDeltaCW = (deltaCW < 0) ? (-deltaCW) : deltaCW;
1163
0
    if (absDeltaCW > maxAbsDeltaCW) { maxAbsDeltaCW = absDeltaCW; }
1164
0
  }
1165
0
  m_sliceReshapeInfo.maxNbitsNeededDeltaCW = 1 + floorLog2(std::max(1, maxAbsDeltaCW));
1166
1167
0
  histLenth = m_initCW;
1168
0
  log2HistLenth = floorLog2(histLenth);
1169
1170
0
  int sumBins = 0;
1171
0
  for (i = 0; i < PIC_CODE_CW_BINS; i++) { sumBins += m_binCW[i]; }
1172
0
  CHECK(sumBins >= m_reshapeLUTSize, "SDR CW assignment is wrong!!");
1173
0
  for (int i = 0; i < PIC_CODE_CW_BINS; i++)
1174
0
  {
1175
0
    m_reshapePivot[i + 1] = m_reshapePivot[i] + m_binCW[i];
1176
0
    m_fwdScaleCoef[i] = ((int32_t)m_binCW[i] * (1 << FP_PREC) + (1 << (log2HistLenth - 1))) >> log2HistLenth;
1177
0
    if (m_binCW[i] == 0)
1178
0
    {
1179
0
      m_invScaleCoef[i] = 0;
1180
0
      m_chromaAdjHelpLUT[i] = 1 << CSCALE_FP_PREC;
1181
0
    }
1182
0
    else
1183
0
    {
1184
0
      m_invScaleCoef[i] = (int32_t)(m_initCW * (1 << FP_PREC) / m_binCW[i]);
1185
0
      m_chromaAdjHelpLUT[i] = (int32_t)(m_initCW * (1 << FP_PREC) / (m_binCW[i] + m_sliceReshapeInfo.chrResScalingOffset));
1186
0
    }
1187
0
  }
1188
0
  for (int lumaSample = 0; lumaSample < m_reshapeLUTSize; lumaSample++)
1189
0
  {
1190
0
    int idxY = lumaSample / m_initCW;
1191
0
    int tempVal = m_reshapePivot[idxY] + ((m_fwdScaleCoef[idxY] * (lumaSample - m_inputPivot[idxY]) + (1 << (FP_PREC - 1))) >> FP_PREC);
1192
0
    m_fwdLUT[lumaSample] = Clip3((Pel)0, (Pel)((1 << m_lumaBD) - 1), (Pel)(tempVal));
1193
1194
0
    int idxYInv = getPWLIdxInv(lumaSample);
1195
0
    int invSample = m_inputPivot[idxYInv] + ((m_invScaleCoef[idxYInv] * (lumaSample - m_reshapePivot[idxYInv]) + (1 << (FP_PREC - 1))) >> FP_PREC);
1196
0
    m_invLUT[lumaSample] = Clip3((Pel)0, (Pel)((1 << m_lumaBD) - 1), (Pel)(invSample));
1197
0
  }
1198
0
  for (i = 0; i < PIC_CODE_CW_BINS; i++)
1199
0
  {
1200
0
    int start = i*histLenth;
1201
0
    int end = (i + 1)*histLenth - 1;
1202
0
    m_cwLumaWeight[i] = m_fwdLUT[end] - m_fwdLUT[start];
1203
0
  }
1204
0
}
1205
1206
void EncReshape::adjustLmcsPivot()
1207
0
{
1208
0
  int bdShift = m_lumaBD - 10;
1209
0
  int totCW = bdShift != 0 ? (bdShift > 0 ? m_reshapeLUTSize / (1 << bdShift) : m_reshapeLUTSize * (1 << (-bdShift))) : m_reshapeLUTSize;
1210
0
  int orgCW = totCW / PIC_CODE_CW_BINS;
1211
0
  int log2SegSize = m_lumaBD - floorLog2(LMCS_SEG_NUM);
1212
1213
0
  m_reshapePivot[0] = 0;
1214
0
  for (int i = 0; i < PIC_CODE_CW_BINS; i++)
1215
0
  {
1216
0
    m_reshapePivot[i + 1] = m_reshapePivot[i] + m_binCW[i];
1217
0
  }
1218
0
  int segIdxMax = (m_reshapePivot[m_sliceReshapeInfo.reshaperModelMaxBinIdx + 1] >> log2SegSize);
1219
0
  for (int i = m_sliceReshapeInfo.reshaperModelMinBinIdx; i <= m_sliceReshapeInfo.reshaperModelMaxBinIdx; i++)
1220
0
  {
1221
0
    m_reshapePivot[i + 1] = m_reshapePivot[i] + m_binCW[i];
1222
0
    int segIdxCurr = (m_reshapePivot[i]     >> log2SegSize);
1223
0
    int segIdxNext = (m_reshapePivot[i + 1] >> log2SegSize);
1224
1225
0
    if ((segIdxCurr == segIdxNext) && (m_reshapePivot[i] != (segIdxCurr << log2SegSize)))
1226
0
    {
1227
0
      if (segIdxCurr == segIdxMax)
1228
0
      {
1229
0
        m_reshapePivot[i] = m_reshapePivot[m_sliceReshapeInfo.reshaperModelMaxBinIdx + 1];
1230
0
        for (int j = i; j <= m_sliceReshapeInfo.reshaperModelMaxBinIdx; j++)
1231
0
        {
1232
0
          m_reshapePivot[j + 1] = m_reshapePivot[i];
1233
0
          m_binCW[j] = 0;
1234
0
        }
1235
0
        m_binCW[i - 1] = m_reshapePivot[i] - m_reshapePivot[i - 1];
1236
0
        break;
1237
0
      }
1238
0
      else
1239
0
      {
1240
0
        int16_t adjustVal = ((segIdxCurr + 1) << log2SegSize) - m_reshapePivot[i + 1];
1241
0
        m_reshapePivot[i + 1] += adjustVal;
1242
0
        m_binCW[i] += adjustVal;
1243
1244
0
        for (int j = i + 1; j <= m_sliceReshapeInfo.reshaperModelMaxBinIdx; j++)
1245
0
        {
1246
0
          if (m_binCW[j] < (adjustVal + (orgCW >> 3)))
1247
0
          {
1248
0
            adjustVal -= (m_binCW[j] - (orgCW >> 3));
1249
0
            m_binCW[j] = (orgCW >> 3);
1250
0
          }
1251
0
          else
1252
0
          {
1253
0
            m_binCW[j] -= adjustVal;
1254
0
            adjustVal = 0;
1255
0
          }
1256
0
          if (adjustVal == 0)
1257
0
            break;
1258
0
        }
1259
0
      }
1260
0
    }
1261
0
  }
1262
1263
0
  for (int i = PIC_CODE_CW_BINS - 1; i >= 0; i--)
1264
0
  {
1265
0
    if (m_binCW[i] > 0)
1266
0
    {
1267
0
      m_sliceReshapeInfo.reshaperModelMaxBinIdx = i;
1268
0
      break;
1269
0
    }
1270
0
  }
1271
0
}
1272
1273
1274
} // namespace vvenc
1275
1276
//
1277
//! \}