Coverage Report

Created: 2026-10-17 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvenc/source/Lib/EncoderLib/SEIFilmGrainAnalyzer.h
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
#ifndef __SEIFILMGRAINANALYZER__
45
#define __SEIFILMGRAINANALYZER__
46
47
#pragma once
48
49
#include "CommonLib/Picture.h"
50
#include "CommonLib/SEI.h"
51
52
#include <numeric>
53
#include <cmath>
54
#include <algorithm>
55
#include <fstream>  // Include this for std::ofstream
56
57
//using namespace vvenc;
58
namespace vvenc {
59
60
#if defined(TARGET_SIMD_X86)  && ENABLE_SIMD_OPT_FGA
61
using namespace x86_simd;
62
#endif
63
  
64
static constexpr double   PI                     = 3.14159265358979323846;
65
static constexpr double   PI_2                   = 3.14159265358979323846 / 2.0;
66
static constexpr double   pi_8                   = PI / 8.0;
67
static constexpr double   pi_3_8                 = 3.0 * PI / 8.0;
68
static constexpr double   pi_5_8                 = 5.0 * PI / 8.0;
69
static constexpr double   pi_7_8                 = 7.0 * PI / 8.0;
70
71
static constexpr int      DATA_BASE_SIZE         = 64;
72
static constexpr int      INTERVAL_SIZE          = 16;
73
static constexpr int      MAX_INTERVAL_NUMBER    = (1 << 16) / INTERVAL_SIZE;
74
static constexpr int      MAXPAIRS               = 256;
75
76
static constexpr int      KERNELSIZE             = 3;     // Dilation and erosion kernel size
77
static constexpr int      CONV_WIDTH_S           = 3;
78
static constexpr int      CONV_HEIGHT_S          = 3;
79
// ====================================================================================================================
80
// Class definition
81
// ====================================================================================================================
82
83
class Canny
84
{
85
public:
86
  Canny( bool enableOpt = true );
87
  ~Canny();
88
89
  unsigned int      m_convWidthG = 5, m_convHeightG = 5;      // Pixel's row and col positions for Gauss filtering
90
  
91
  void init ( unsigned int width,
92
              unsigned int height,
93
              ChromaFormat inputChroma );
94
95
  void destroy ();
96
97
  void detect_edges ( const PelStorage* orig,
98
                      PelStorage* dest,
99
                      unsigned int uiBitDepth,
100
                      ComponentID compID );
101
102
  // Sobel gradient of a plane: the edge magnitude replaces the samples of buff1, and the quantized edge direction
103
  // goes to buff2. tmpBuf1 and tmpBuf2 hold the two Sobel responses (Gx and Gy of gradient_core) meanwhile.
104
  void (*gradient) ( PelStorage* buff1,
105
                     PelStorage* buff2,
106
                     PelStorage *tmpBuf1,
107
                     PelStorage *tmpBuf2,
108
                     unsigned int width,
109
                     unsigned int height,
110
                     unsigned int bitDepth,
111
                     ComponentID compID);
112
113
private:
114
  double            m_lowThresholdRatio   = 0.1;               // low threshold rato
115
  int               m_highThresholdRatio  = 3;                 // high threshold rato
116
117
  PelStorage *m_orientationBuf = nullptr;
118
  PelStorage* m_gradientBufX = nullptr;
119
  PelStorage* m_gradientBufY = nullptr;
120
121
  void suppressNonMax ( PelStorage* buff1,
122
                        PelStorage* buff2,
123
                        unsigned int width,
124
                        unsigned int height,
125
                        ComponentID compID );
126
127
  void doubleThreshold ( PelStorage *buff,
128
                         unsigned int width,
129
                         unsigned int height,
130
                         unsigned int bitDepth,
131
                         ComponentID compID );
132
133
  void edgeTracking ( PelStorage* buff1,
134
                      unsigned int width,
135
                      unsigned int height,
136
                      unsigned int windowWidth,
137
                      unsigned int windowHeight,
138
                      unsigned int bitDepth,
139
                      ComponentID compID );
140
141
#if ENABLE_SIMD_OPT_FGA && defined( TARGET_SIMD_X86 )
142
  void initFGACannyX86();
143
  template <X86_VEXT vext>
144
  void _initFGACannyX86();
145
#endif
146
};
147
148
class Morph
149
{
150
public:
151
  Morph( bool enableOpt = true );
152
  ~Morph();
153
154
  void init ( uint32_t width,
155
              uint32_t height );
156
157
  void destroy ();
158
159
  int (*dilation) ( PelStorage *buff,
160
                    PelStorage *Wbuf,
161
                    uint32_t bitDepth,
162
                    ComponentID compID,
163
                    int numIter,
164
                    int iter,
165
                    Pel Value );
166
167
#if ENABLE_SIMD_OPT_FGA && defined( TARGET_SIMD_X86 )
168
  void initFGAMorphX86();
169
  template <X86_VEXT vext>
170
  void _initFGAMorphX86();
171
#endif
172
#if ENABLE_SIMD_OPT_FGA && defined( TARGET_SIMD_ARM )
173
  void initFGAMorphARM();
174
  template <ARM_VEXT vext>
175
  void _initFGAMorphARM();
176
#endif
177
178
  PelStorage* m_dilationBuf = nullptr;
179
  PelStorage* m_dilationBuf2 = nullptr;
180
  PelStorage* m_dilationBuf4 = nullptr;
181
};
182
183
184
class FGAnalyzer
185
{
186
public:
187
  FGAnalyzer( bool enableOpt = true );
188
  ~FGAnalyzer();
189
190
  int                             prevAnalysisPoc                = -1;
191
192
  void init( const int                        width,
193
             const int                        height,
194
             const ChromaFormat               inputChroma,
195
             const int                        *outputBitDepths,
196
             const bool doAnalysis[] );
197
  void destroy        ();
198
199
  void estimateGrainParameters ( Picture* pic );
200
201
0
  int getLog2scaleFactor()  { return m_log2ScaleFactor; };
202
203
0
  SeiFgc::CompModel  getCompModel( int idx ) { return m_compModel[idx];  };
204
205
  double (*calcVar) ( const Pel* org,
206
                      const ptrdiff_t origStride,
207
                      const int w,
208
                      const int h );
209
210
  int (*calcMean) ( const Pel* org,
211
                    const ptrdiff_t origStride,
212
                    const int w,
213
                    const int h );
214
215
  void (*fastDCT2_64) ( const TCoeff* src,
216
                        TCoeff* dst,
217
                        int shift,
218
                        int line,
219
                        int iSkipLine,
220
                        int iSkipLine2 );
221
222
private:
223
  int                             *m_bitDepths;
224
  ChromaFormat                    m_inputChromaFormat;
225
  bool                            m_doAnalysis[ComponentID::MAX_NUM_COMP] = { true, true, true };
226
227
  Canny                           m_edgeDetector;
228
  Morph                           m_morphOperation;
229
  double                          m_lowIntensityRatio            = 0.1;           // supress everything below 0.1*maxIntensityOffset
230
231
  CoeffBuf                        * m_dctGrainBlockList;
232
  TCoeff                          * m_coeffBuf;
233
  int                             m_numDctGrainBlocks;
234
235
  std::vector<double>             coeffs;
236
  std::vector<double>             scalingVec;
237
  std::vector<int>                quantVec;
238
239
  std::vector<int>                vecMean;
240
  std::vector<int>                vecVar;
241
242
  double                          meanSquaredDctGrain[DATA_BASE_SIZE][DATA_BASE_SIZE];
243
244
  /* Interval points for fitFunction */
245
  std::vector<int>                vec_mean_intensity;
246
  std::vector<int>                vec_variance_intensity;
247
  std::vector<int>                element_number_per_interval;
248
  std::vector<int>                tmp_data_x;
249
  std::vector<int>                tmp_data_y;
250
251
  static constexpr double         m_tapFilter[3]                = { 1, 2, 1 };
252
  static constexpr double         m_normTap                     = 4.0;
253
254
  // fg model parameters
255
  int                             m_log2ScaleFactor;
256
  std::vector<std::array<int, 3>> finalIntervalsandScalingFactors;   // lower_bound, upper_bound, scaling_factor
257
  SeiFgc::CompModel               m_compModel[ComponentID::MAX_NUM_COMP];
258
259
  const PelStorage                *m_originalBuf             = nullptr;
260
  const PelStorage                *m_workingBuf              = nullptr;
261
  PelStorage                      *m_maskBuf                 = nullptr;
262
  PelStorage                      *m_grainEstimateBuf        = nullptr;
263
  PelStorage                      *m_workingBufSubsampled2   = nullptr;
264
  PelStorage                      *m_maskSubsampled2         = nullptr;
265
  PelStorage                      *m_workingBufSubsampled4   = nullptr;
266
  PelStorage                      *m_maskSubsampled4         = nullptr;
267
  PelStorage                      *m_maskUpsampled           = nullptr;
268
  // for DCT
269
  TCoeff                          *m_DCTinout                = nullptr;
270
  TCoeff                          *m_DCTtemp                 = nullptr;
271
272
  void findMask ( ComponentID compID );
273
274
  void blockTransform ( CoeffBuf& currentCoeffBuf,
275
                        int offsetX,
276
                        int offsetY,
277
                        uint32_t bitDepth,
278
                        ComponentID compId );
279
280
  void adaptiveSampling ( int bins,
281
                          double threshold,
282
                          std::vector<int>& significantIndices,
283
                          bool isRow,
284
                          int startIdx );
285
286
  void estimateCutoffFreqAdaptive ( ComponentID compID );
287
288
  void estimateScalingFactors ( uint32_t bitDepth,
289
                                ComponentID compID );
290
291
  bool fitFunction ( int order,
292
                     int bitDepth,
293
                     bool second_pass );
294
295
  void avgScalingVec ( int bitDepth );
296
297
  bool lloydMax ( double& distortion,
298
                  int bitDepth );
299
300
  void quantize ( std::vector<double>& quantizedVec,
301
                  double& distortion,
302
                  double partition[],
303
                  double codebook[] );
304
305
  void extendPoints ( int bitDepth );
306
307
  void setEstimatedParameters ( uint32_t bitDepth,
308
                                ComponentID compID );
309
310
  void defineIntervalsAndScalings ( int bitDepth );
311
312
  void scaleDown ( int bitDepth );
313
314
  void confirmIntervals ( );
315
316
  long double ldpow ( long double n,
317
                      unsigned p );
318
319
  int countEdges ( int windowSize,
320
                   int offsetX,
321
                   int offsetY,
322
                   ComponentID compID );
323
324
  void subsample ( PelStorage& output,
325
                   const int factor = 2,
326
                   const int padding = 0, 
327
                   ComponentID compID = COMP_Y ) const;
328
329
  void upsample ( const PelStorage& input,
330
                  const int factor = 2,
331
                  const int padding = 0,
332
                  ComponentID compID = COMP_Y ) const;
333
334
  void combineMasks ( ComponentID compId );
335
336
  void suppressLowIntensity ( const PelStorage& buff1,
337
                              PelStorage& buff2,
338
                              uint32_t bitDepth,
339
                              ComponentID compId );
340
341
#if ENABLE_SIMD_OPT_FGA && defined( TARGET_SIMD_X86 )
342
  void initFGAnalyzerX86();
343
  template <X86_VEXT vext>
344
  void _initFGAnalyzerX86();
345
#endif
346
#if ENABLE_SIMD_OPT_FGA && defined( TARGET_SIMD_ARM )
347
  void initFGAnalyzerARM();
348
  template <ARM_VEXT vext>
349
  void _initFGAnalyzerARM();
350
#endif
351
};
352
353
} // namespace vvenc
354
355
// Scalar reference for Morph::dilation. Global (not vvenc::) because this
356
// header's .cpp only does "using namespace vvenc;" rather than wrapping its
357
// definitions in the namespace. SIMD dilation implementations that need a
358
// fallback for widths their vectorized path can't handle delegate to it
359
// directly instead of duplicating the 3x3 test.
360
int dilation_core( vvenc::PelStorage* buff, vvenc::PelStorage* Wbuf, uint32_t bitDepth, vvenc::ComponentID compID,
361
                   int numIter, int iter, vvenc::Pel Value );
362
363
// Scalar reference for Canny::gradient, global for the same reason. The x86 SIMD gradient falls back to it for
364
// widths its vectorized path can't handle.
365
void gradient_core( vvenc::PelStorage* buff1, vvenc::PelStorage* buff2, vvenc::PelStorage* tmpBuf1,
366
                    vvenc::PelStorage* tmpBuf2, uint32_t width, uint32_t height, uint32_t bitDepth,
367
                    vvenc::ComponentID compID );
368
369
#endif // __SEIFILMGRAINANALYZER__
370
371