Coverage Report

Created: 2026-04-01 07:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vvdec/source/Lib/FilmGrain/FilmGrain.cpp
Line
Count
Source
1
/* -----------------------------------------------------------------------------
2
The copyright in this software is being made available under the Clear BSD
3
License, included below. No patent rights, trademark rights and/or
4
other Intellectual Property Rights other than the copyrights concerning
5
the Software are granted under this license.
6
7
The Clear BSD License
8
9
Copyright (c) 2018-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVdeC Authors.
10
All rights reserved.
11
12
Redistribution and use in source and binary forms, with or without modification,
13
are permitted (subject to the limitations in the disclaimer below) provided that
14
the following conditions are met:
15
16
     * Redistributions of source code must retain the above copyright notice,
17
     this list of conditions and the following disclaimer.
18
19
     * Redistributions in binary form must reproduce the above copyright
20
     notice, this list of conditions and the following disclaimer in the
21
     documentation and/or other materials provided with the distribution.
22
23
     * Neither the name of the copyright holder nor the names of its
24
     contributors may be used to endorse or promote products derived from this
25
     software without specific prior written permission.
26
27
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
28
THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
29
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
31
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
32
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
36
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38
POSSIBILITY OF SUCH DAMAGE.
39
40
41
------------------------------------------------------------------------------------------- */
42
43
/* This file is based on VFGS, available on
44
 * https://github.com/InterDigitalInc/VersatileFilmGrain
45
 *
46
 * VFGS implements film grain synthesis as a hardware model: it simulates the
47
 * output of a cost-effective hardware implementation in a video display
48
 * pipeline. Also, the C code is split into "fw" (firmware) and "hw" (hardware)
49
 * parts, and as self-explanatory as possible. See VFGS github repository for
50
 * more details.
51
 *
52
 * The VFGS github repository also contains other tools to experiment with film
53
 * grain synthesis (e.g. a graphical display and tuning tool for FGC SEI
54
 * message).
55
 */
56
57
#include "FilmGrain.h"
58
59
#include <cstdint>
60
#include <cstring>
61
#include <algorithm>
62
63
#include "CommonDef.h"
64
65
#if defined( TARGET_SIMD_X86 ) && ENABLE_SIMD_OPT
66
#  include "FilmGrainImplX86.h"
67
#endif
68
69
namespace vvdec
70
{
71
72
// clang-format off
73
static constexpr int8_t Gaussian_LUT[2048] = {
74
   -11,  12, 103, -11,  42, -35,  12,  59,  77,  98, -87,   3,  65, -78,  45,  56,
75
   -51,  21,  13, -11, -20, -19,  33,-127,  17,  -6,-105,  18,  19,  71,  48, -10,
76
   -38,  42,  -2,  75, -67,  52, -90,  33, -47,  21,  -3, -56,  49,   1, -57, -42,
77
    -1, 120,-127,-108, -49,   9,  14, 127, 122, 109,  52, 127,   2,   7, 114,  19,
78
    30,  12,  77, 112,  82, -61,-127, 111, -52, -29,   2, -49, -24,  58, -29, -73,
79
    12, 112,  67,  79,  -3,-114, -87,  -6,  -5,  40,  58, -81,  49, -27, -31, -34,
80
  -105,  50,  16, -24, -35, -14, -15,-127, -55, -22, -55,-127,-112,   5, -26, -72,
81
   127, 127,  -2,  41,  87, -65, -16,  55,  19,  91, -81, -65, -64,  35,  -7, -54,
82
    99,  -7,  88, 125, -26,  91,   0,  63,  60, -14, -23, 113, -33, 116,  14,  26,
83
    51, -16, 107,  -8,  53,  38, -34,  17,  -7,   4, -91,   6,  63,  63, -15,  39,
84
   -36,  19,  55,  17, -51,  40,  33, -37, 126, -39,-118,  17, -30,   0,  19,  98,
85
    60, 101, -12, -73, -17, -52,  98,   3,   3,  60,  33,  -3,  -2,  10, -42,-106,
86
   -38,  14, 127,  16,-127, -31, -86, -39, -56,  46, -41,  75,  23, -19, -22, -70,
87
    74, -54,  -2,  32, -45,  17, -92,  59, -64, -67,  56,-102, -29, -87, -34, -92,
88
    68,   5, -74, -61,  93, -43,  14, -26, -38,-126, -17,  16,-127,  64,  34,  31,
89
    93,  17, -51, -59,  71,  77,  81, 127, 127,  61,  33,-106, -93,   0,   0,  75,
90
   -69,  71, 127, -19,-111,  30,  23,  15,   2,  39,  92,   5,  42,   2,  -6,  38,
91
    15, 114, -30, -37,  50,  44, 106,  27, 119,   7, -80,  25, -68, -21,  92, -11,
92
    -1,  18,  41, -50,  79,-127, -43, 127,  18,  11, -21,  32, -52,  27, -88, -90,
93
   -39, -19, -10,  24,-118,  72, -24, -44,   2,  12,  86,-107,  39, -33,-127,  47,
94
    51, -24, -22,  46,   0,  15, -35, -69,  -2, -74,  24,  -6,   0,  29,  -3,  45,
95
    32, -32, 117, -45,  79, -24, -17,-109, -10, -70,  88, -48,  24, -91, 120, -37,
96
    50,-127,  58,  32, -82, -10, -17,  -7,  46,-127, -15,  89, 127,  17,  98, -39,
97
   -33,  37,  42, -40, -32, -21, 105, -19,  19,  19, -59,  -9,  30,   0,-127,  34,
98
   127, -84,  75,  24, -40, -49,-127,-107, -14,  45, -75,   1,  30, -20,  41, -68,
99
   -40,  12, 127,  -3,   5,  20, -73, -59,-127,  -3,  -3, -53,  -6,-119,  93, 120,
100
   -80, -50,   0,  20, -46,  67,  78, -12, -22,-127,  36, -41,  56, 119,  -5,-116,
101
   -22,  68, -14, -90,  24, -82, -44,-127, 107, -25, -37,  40,  -7,  -7, -82,   5,
102
   -87,  44, -34,   9,-127,  39,  70,  49, -63,  74, -49, 109, -27, -89, -47, -39,
103
    44,  49,  -4,  60, -42,  80,   9,-127,  -9, -56, -49, 125, -66,  47,  36, 117,
104
    15, -11, -96, 109,  94, -17, -56,  70,   8, -14,  -5,  50,  37, -45, 120, -30,
105
   -76,  40, -46,   6,   3,  69,  17, -78,   1, -79,   6, 127,  43,  26, 127,-127,
106
    28, -55, -26,  55, 112,  48, 107,  -1, -77,  -1,  53,  -9, -22, -43, 123, 108,
107
   127, 102,  68,  46,   5,   1, 123, -13, -55, -34, -49,  89,  65,-105,  -5,  94,
108
   -53,  62,  45,  30,  46,  18, -35,  15,  41,  47, -98, -24,  94, -75, 127,-114,
109
   127, -68,   1, -17,  51, -95,  47,  12,  34, -45, -75,  89,-107,  -9, -58, -29,
110
  -109, -24, 127, -61, -13,  77, -45,  17,  19,  83, -24,   9, 127, -66,  54,   4,
111
    26,  13, 111,  43,-113, -22,  10, -24,  83,  67, -14,  75,-123,  59, 127, -12,
112
    99, -19,  64, -38,  54,   9,   7,  61, -56,   3, -57, 113,-104, -59,   3,  -9,
113
   -47,  74,  85, -55, -34,  12, 118,  28,  93, -72,  13, -99, -72, -20,  30,  72,
114
   -94,  19, -54,  64, -12, -63, -25,  65,  72, -10, 127,   0,-127, 103, -20, -73,
115
  -112,-103,  -6,  28, -42, -21, -59, -29, -26,  19,  -4, -51,  94, -58, -95, -37,
116
    35,  20, -69, 127, -19,-127, -22,-120, -53,  37,  74,-127,  -1, -12,-119, -53,
117
   -28,  38,  69,  17,  16,-114,  89,  62,  24,  37, -23,  49,-101, -32,  -9, -95,
118
   -53,   5,  93, -23, -49,  -8,  51,   3, -75, -90, -10, -39, 127, -86, -22,  20,
119
    20, 113,  75,  52, -31,  92, -63,   7, -12,  46,  36, 101, -43, -17, -53,  -7,
120
   -38, -76, -31, -21,  62,  31,  62,  20,-127,  31,  64,  36, 102, -85, -10,  77,
121
    80,  58, -79,  -8,  35,   8,  80, -24,  -9,   3, -17,  72, 127,  83, -87,  55,
122
    18,-119,-123,  36,  10, 127,  56, -55, 113,  13,  26,  32, -13, -48,  22, -13,
123
     5,  58,  27,  24,  26, -11, -36,  37, -92,  78,  81,   9,  51,  14,  67, -13,
124
     0,  32,  45, -76,  32, -39, -22, -49,-127, -27,  31,  -9,  36,  14,  71,  13,
125
    57,  12, -53, -86,  53, -44, -35,   2, 127,  12, -66, -44,  46,-115,   3,  10,
126
    56, -35, 119, -19, -61,  52, -59,-127, -49, -23,   4,  -5,  17, -82,  -6, 127,
127
    25,  79,  67,  64, -25,  14, -64, -37,-127, -28,  21, -63,  66, -53, -41, 109,
128
   -62,  15, -22,  13,  29, -63,  20,  27,  95, -44, -59,-116, -10,  79, -49,  22,
129
   -43, -16,  46, -47,-120, -36, -29, -52, -44,  29, 127, -13,  49,  -9,-127,  75,
130
   -28, -23,  88,  59,  11, -95,  81, -59,  58,  60, -26,  40, -92,  -3, -22, -58,
131
   -45, -59, -22, -53,  71, -29,  66, -32, -23,  14, -17, -66, -24, -28, -62,  47,
132
    38,  17,  16, -37, -24, -11,   8, -27, -19,  59,  45, -49, -47,  -4, -22, -81,
133
    30, -67,-127,  74, 102,   5, -18,  98,  34, -66,  42, -52,   7, -59,  24, -58,
134
   -19, -24,-118, -73,  91,  15, -16,  79, -32, -79,-127, -36,  41,  77, -83,   2,
135
    56,  22, -75, 127, -16, -21,  12,  31,  56,-113,-127,  90,  55,  61,  12,  55,
136
   -14,-113, -14,  32,  49, -67, -17,  91, -10,   1,  21,  69, -70,  99, -19,-112,
137
    66, -90, -10,  -9, -71, 127,  50, -81, -49,  24,  61, -61,-111,   7, -41, 127,
138
    88, -66, 108,-127,  -6,  36, -14,  41, -50,  14,  14,  73,-101, -28,  77, 127,
139
    -8,-100,  88,  38, 121,  88,-125, -60,  13, -94,-115,  20, -67, -87, -94,-119,
140
    44, -28, -30,  18,   5, -53, -61,  20, -43,  11, -77, -60,  13,  29,   3,   6,
141
   -72,  38, -60, -11, 108, -53,  41,  66, -12,-127,-127, -49,  24,  29,  46,  36,
142
    91,  34, -33, 116, -51, -34, -52,  91,   7, -83,  73, -26,-103,  24, -10,  76,
143
    84,   5,  68, -80, -13, -17, -32, -48,  20,  50,  26,  10,  63,-104, -14,  37,
144
   127, 114,  97,  35,   1, -33, -55, 127,-124, -33,  61,  -7, 119, -32,-127, -53,
145
   -42,  63,   3,  -5, -26,  70, -58, -33, -44, -43,  34, -56,-127, 127,  25, -35,
146
   -11,  16, -81,  29, -58,  40,-127,-127,  20, -47, -11, -36, -63, -52, -32, -82,
147
    78, -76, -73,   8,  27, -72,  -9, -74, -85, -86, -57,  25,  78, -10, -97,  35,
148
   -65,   8, -59,  14,   1, -42,  32, -88, -44,  17,  -3,  -9,  59,  40,  12,-108,
149
   -40,  24,  34,  18, -28,   2,  51,-110,  -4, 100,   1,  65,  22,   0, 127,  61,
150
    45,  25, -31,   6,   9,  -7, -48,  99,  16,  44,  -2, -40,  32, -39, -52,  10,
151
  -110, -19,  56,-127,  69,  26,  51,  92,  40,  61, -52,  45, -38,  13,  85, 122,
152
    27,  66,  45,-111, -83,  -3,  31,  37,  19, -36,  58,  71,  39, -78, -47,  58,
153
   -78,   8, -62, -36, -14,  61,  42,-127,  71,  -4,  24, -54,  52,-127,  67,  -4,
154
   -42,  30, -63,  59,  -3,  -1, -18, -46, -92, -81, -96, -14, -53, -10, -11, -77,
155
    13,   1,   8, -67,-127, 127, -28,  26, -14,  18, -13, -26,   2,  10, -46, -32,
156
   -15,  27, -31, -59,  59,  77,-121,  28,  40, -54, -62, -31, -21, -37, -32,  -6,
157
  -127, -25, -60,  70,-127, 112,-127, 127,  88,  -7, 116, 110,  53,  87,-127,   3,
158
    16,  23,  74,-106, -51,   3,  74, -82,-112, -74,  65,  81,  25,  53, 127, -45,
159
   -50,-103, -41, -65, -29,  79, -67,  64, -33, -30,  -8, 127,   0, -13, -51,  67,
160
   -14,   5, -92,  29, -35,  -8, -90, -57,  -3,  36,  43,  44, -31, -69,  -7,  36,
161
    39, -51,  43, -81,  58,   6, 127,  12,  57,  66,  46,  59, -43, -42,  41, -15,
162
  -120,  24,   3, -11,  19, -13,  51,  28,   3,  55, -48, -12,  -1,   2,  97, -19,
163
    29,  42,  13,  43,  78, -44,  56,-108, -43, -19, 127,  15, -11, -18, -81,  83,
164
   -37,  77,-109,  15,  65, -50,  43,  12,  13,  27,  28,  61,  57,  30,  26, 106,
165
   -18,  56,  13,  97,   4,  -8, -62,-103,  94, 108, -44,  52,  27, -47,  -9, 105,
166
   -53,  46,  89, 103, -33,  38, -34,  55,  51,  70, -94, -35, -87,-107, -19, -31,
167
     9, -19,  79, -14,  77,   5, -19,-107,  85,  21, -45, -39, -42,   9, -29,  74,
168
    47, -75,  60,-127, 120,-112, -57, -32,  41,   7,  79,  76,  66,  57,  41, -25,
169
    31,  37, -47, -36,  43, -73, -37,  63, 127, -69, -52,  90, -33, -61,  60, -55,
170
    44,  15,   4, -67,  13, -92,  64,  29, -39,  -3,  83,  -2, -38, -85, -86,  58,
171
    35, -69, -61,  29, -37, -95, -78,   4,  30,  -4, -32, -80, -22,  -9, -77,  46,
172
     7, -93, -71,  65,   9, -50, 127, -70,  26, -12, -39,-114,  63,-127,-100,   4,
173
   -32, 111,  22, -60,  65,-101,  26, -42,  21, -59, -27, -74,   2, -94,   6, 126,
174
     5,  76, -88,  -9, -43,-101, 127,   1, 125,  92, -63,  52,  56,   4,  81,-127,
175
   127,  80, 127, -29,  30, 116, -74, -17, -57, 105,  48,  45,  25, -72,  48, -38,
176
  -108,  31, -34,   4, -11,  41,-127,  52,-104, -43, -37,  52,   2,  47,  87,  -9,
177
    77,  27, -41, -25,  90,  86, -56,  75,  10,  33,  78,  58, 127, 127,  -7, -73,
178
    49, -33,-106, -35,  38,  57,  53, -17,  -4,  83,  52,-108,  54,-125,  28,  23,
179
    56, -43, -88, -17,  -6,  47,  23,  -9,   0, -13, 111,  75,  27, -52, -38, -34,
180
    39,  30,  66,  39,  38, -64,  38,   3,  21, -32, -51, -28,  54, -38, -87,  20,
181
    52, 115,  18, -81, -70,   0, -14, -46, -46,  -3, 125,  16, -14,  23, -82, -84,
182
   -69, -20, -65,-127,   9,  81, -49,  61,   7, -36, -45, -42,  57, -26,  47,  20,
183
   -85,  46, -13,  41, -37, -75, -60,  86, -78,-127,  12,  50,   2,  -3,  13,  47,
184
     5,  19, -78, -55, -27,  65, -71,  12,-108,  20, -16,  11, -31,  63, -55,  37,
185
    75, -17, 127, -73, -33, -28,-120, 105,  68, 106,-103,-106,  71,  61,   2,  23,
186
    -3,  33,  -5, -15, -67, -15, -23, -54,  15, -63,  76,  58,-110,   1,  83, -27,
187
    22,  75, -39, -17, -11,  64, -17,-127, -54, -66,  31,  96, 116,   3,-114,  -7,
188
  -108, -63,  97,   9,  50,   8,  75, -28,  72, 112, -36,-112,  95, -50,  23, -13,
189
   -19,  55,  21,  23,  92,  91,  22, -49,  16, -75,  23,   9, -49, -97, -37,  49,
190
   -36,  36,-127, -86,  43, 127, -24, -24,  84,  83, -35, -34, -12, 109, 102, -38,
191
    51, -68,  34,  19, -22,  49, -32, 127,  40,  24, -93,  -4,  -3, 105,   3, -58,
192
   -18,   8, 127, -18, 125,  68,  69, -62,  30, -36,  54, -57, -24,  17,  43, -36,
193
   -27, -57, -67, -21, -10, -49,  68,  12,  65,   4,  48,  55, 127, -75,  44,  89,
194
   -66, -13, -78, -82, -91,  22,  30,  33, -40, -87, -34,  96, -91,  39,  10, -64,
195
    -3, -12, 127, -50, -37, -56,  23, -35, -36, -54,  90, -91,   2,  50,  77,  -6,
196
  -127,  16,  46,  -5, -73,   0, -56, -18, -72,  28,  93,  60,  49,  20,  18, 111,
197
  -111,  32, -83,  47,  47, -10,  35, -88,  43,  57, -98, 127, -17,   0,   1, -39,
198
  -127,  -2,   0,  63,  93,   0,  36, -66, -61, -19,  39,-127,  58,  50, -17, 127,
199
    88, -43,-108, -51, -16,   7, -36,  68,  46, -14, 107,  40,  57,   7,  19,   8,
200
     3,  88, -90, -92, -18, -21, -24,  13,   7,  -4, -78, -91,  -4,   8, -35,  -5,
201
    19,   2,-111,   4, -66, -81, 122, -20, -34, -37, -84, 127,  68,  46,  17,  47
202
};
203
204
static constexpr uint32_t Seed_LUT[256] = {
205
   747538460, 1088979410, 1744950180, 1767011913, 1403382928,  521866116, 1060417601, 2110622736,
206
  1557184770,  105289385,  585624216, 1827676546, 1191843873, 1018104344, 1123590530,  663361569,
207
  2023850500,   76561770, 1226763489,   80325252, 1992581442,  502705249,  740409860,  516219202,
208
   557974537, 1883843076,  720112066, 1640137737, 1820967556,   40667586,  155354121, 1820967557,
209
  1115949072, 1631803309,   98284748,  287433856, 2119719977,  988742797, 1827432592,  579378475,
210
  1017745956, 1309377032, 1316535465, 2074315269, 1923385360,  209722667, 1546228260,  168102420,
211
   135274561,  355958469,  248291472, 2127839491,  146920100,  585982612, 1611702337,  696506029,
212
  1386498192, 1258072451, 1212240548, 1043171860, 1217404993, 1090770605, 1386498193,  169093201,
213
   541098240, 1468005469,  456510673, 1578687785, 1838217424, 2010752065, 2089828354, 1362717428,
214
   970073673,  854129835,  714793201, 1266069081, 1047060864, 1991471829, 1098097741,  913883585,
215
  1669598224, 1337918685, 1219264706, 1799741108, 1834116681,  683417731, 1120274457, 1073098457,
216
  1648396544,  176642749,   31171789,  718317889, 1266977808, 1400892508,  549749008, 1808010512,
217
    67112961, 1005669825,  903663673, 1771104465, 1277749632, 1229754427,  950632997, 1979371465,
218
  2074373264,  305357524, 1049387408, 1171033360, 1686114305, 2147468765, 1941195985,  117709841,
219
   809550080,  991480851, 1816248997, 1561503561,  329575568,  780651196, 1659144592, 1910793616,
220
   604016641, 1665084765, 1530186961, 1870928913,  809550081, 2079346113,   71307521,  876663040,
221
  1073807360,  832356664, 1573927377,  204073344, 2026918147, 1702476788, 2043881033,   57949587,
222
  2001393952, 1197426649, 1186508931,  332056865,  950043140,  890043474,  349099312,  148914948,
223
   236204097, 2022643605, 1441981517,  498130129, 1443421481,  924216797, 1817491777, 1913146664,
224
  1411989632,  929068432,  495735097, 1684636033, 1284520017,  432816184, 1344884865,  210843729,
225
   676364544,  234449232,   12112337, 1350619139, 1753272996, 2037118872, 1408560528,  533334916,
226
  1043640385,  357326099,  201376421,  110375493,  541106497,  416159637,  242512193,  777294080,
227
  1614872576, 1535546636,  870600145,  910810409, 1821440209, 1605432464, 1145147393,  951695441,
228
  1758494976, 1506656568, 1557150160,  608221521, 1073840384,  217672017,  684818688, 1750138880,
229
    16777217,  677990609,  953274371, 1770050213, 1359128393, 1797602707, 1984616737, 1865815816,
230
  2120835200, 2051677060, 1772234061, 1579794881, 1652821009, 1742099468, 1887260865,   46468113,
231
  1011925248, 1134107920,  881643832, 1354774993,  472508800, 1892499769, 1752793472, 1962502272,
232
   687898625,  883538000, 1354355153, 1761673473,  944820481, 2020102353,   22020353,  961597696,
233
  1342242816,  964808962, 1355809701,   17016649, 1386540177,  647682692, 1849012289,  751668241,
234
  1557184768,  127374604, 1927564752, 1045744913, 1614921984,   43588881, 1016185088, 1544617984,
235
  1090519041,  136122424,  215038417, 1563027841, 2026918145, 1688778833,  701530369, 1372639488,
236
  1342242817, 2036945104,  953274369, 1750192384,   16842753,  964808960, 1359020032, 1358954497
237
};
238
239
#define DEFINE_DCT2_P64_MATRIX(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an, ao, ap, aq, ar, as, at, au, av, aw, ax, ay, az, ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn, bo, bp, bq, br, bs, bt, bu, bv, bw, bx, by, bz, ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck) \
240
{ \
241
  { aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa,  aa }, \
242
  { bf,  bg,  bh,  bi,  bj,  bk,  bl,  bm,  bn,  bo,  bp,  bq,  br,  bs,  bt,  bu,  bv,  bw,  bx,  by,  bz,  ca,  cb,  cc,  cd,  ce,  cf,  cg,  ch,  ci,  cj,  ck, -ck, -cj, -ci, -ch, -cg, -cf, -ce, -cd, -cc, -cb, -ca, -bz, -by, -bx, -bw, -bv, -bu, -bt, -bs, -br, -bq, -bp, -bo, -bn, -bm, -bl, -bk, -bj, -bi, -bh, -bg, -bf }, \
243
  { ap,  aq,  ar,  as,  at,  au,  av,  aw,  ax,  ay,  az,  ba,  bb,  bc,  bd,  be, -be, -bd, -bc, -bb, -ba, -az, -ay, -ax, -aw, -av, -au, -at, -as, -ar, -aq, -ap, -ap, -aq, -ar, -as, -at, -au, -av, -aw, -ax, -ay, -az, -ba, -bb, -bc, -bd, -be,  be,  bd,  bc,  bb,  ba,  az,  ay,  ax,  aw,  av,  au,  at,  as,  ar,  aq,  ap }, \
244
  { bg,  bj,  bm,  bp,  bs,  bv,  by,  cb,  ce,  ch,  ck, -ci, -cf, -cc, -bz, -bw, -bt, -bq, -bn, -bk, -bh, -bf, -bi, -bl, -bo, -br, -bu, -bx, -ca, -cd, -cg, -cj,  cj,  cg,  cd,  ca,  bx,  bu,  br,  bo,  bl,  bi,  bf,  bh,  bk,  bn,  bq,  bt,  bw,  bz,  cc,  cf,  ci, -ck, -ch, -ce, -cb, -by, -bv, -bs, -bp, -bm, -bj, -bg }, \
245
  { ah,  ai,  aj,  ak,  al,  am,  an,  ao, -ao, -an, -am, -al, -ak, -aj, -ai, -ah, -ah, -ai, -aj, -ak, -al, -am, -an, -ao,  ao,  an,  am,  al,  ak,  aj,  ai,  ah,  ah,  ai,  aj,  ak,  al,  am,  an,  ao, -ao, -an, -am, -al, -ak, -aj, -ai, -ah, -ah, -ai, -aj, -ak, -al, -am, -an, -ao,  ao,  an,  am,  al,  ak,  aj,  ai,  ah }, \
246
  { bh,  bm,  br,  bw,  cb,  cg, -ck, -cf, -ca, -bv, -bq, -bl, -bg, -bi, -bn, -bs, -bx, -cc, -ch,  cj,  ce,  bz,  bu,  bp,  bk,  bf,  bj,  bo,  bt,  by,  cd,  ci, -ci, -cd, -by, -bt, -bo, -bj, -bf, -bk, -bp, -bu, -bz, -ce, -cj,  ch,  cc,  bx,  bs,  bn,  bi,  bg,  bl,  bq,  bv,  ca,  cf,  ck, -cg, -cb, -bw, -br, -bm, -bh }, \
247
  { aq,  at,  aw,  az,  bc, -be, -bb, -ay, -av, -as, -ap, -ar, -au, -ax, -ba, -bd,  bd,  ba,  ax,  au,  ar,  ap,  as,  av,  ay,  bb,  be, -bc, -az, -aw, -at, -aq, -aq, -at, -aw, -az, -bc,  be,  bb,  ay,  av,  as,  ap,  ar,  au,  ax,  ba,  bd, -bd, -ba, -ax, -au, -ar, -ap, -as, -av, -ay, -bb, -be,  bc,  az,  aw,  at,  aq }, \
248
  { bi,  bp,  bw,  cd,  ck, -ce, -bx, -bq, -bj, -bh, -bo, -bv, -cc, -cj,  cf,  by,  br,  bk,  bg,  bn,  bu,  cb,  ci, -cg, -bz, -bs, -bl, -bf, -bm, -bt, -ca, -ch,  ch,  ca,  bt,  bm,  bf,  bl,  bs,  bz,  cg, -ci, -cb, -bu, -bn, -bg, -bk, -br, -by, -cf,  cj,  cc,  bv,  bo,  bh,  bj,  bq,  bx,  ce, -ck, -cd, -bw, -bp, -bi }, \
249
  { ad,  ae,  af,  ag, -ag, -af, -ae, -ad, -ad, -ae, -af, -ag,  ag,  af,  ae,  ad,  ad,  ae,  af,  ag, -ag, -af, -ae, -ad, -ad, -ae, -af, -ag,  ag,  af,  ae,  ad,  ad,  ae,  af,  ag, -ag, -af, -ae, -ad, -ad, -ae, -af, -ag,  ag,  af,  ae,  ad,  ad,  ae,  af,  ag, -ag, -af, -ae, -ad, -ad, -ae, -af, -ag,  ag,  af,  ae,  ad }, \
250
  { bj,  bs,  cb,  ck, -cc, -bt, -bk, -bi, -br, -ca, -cj,  cd,  bu,  bl,  bh,  bq,  bz,  ci, -ce, -bv, -bm, -bg, -bp, -by, -ch,  cf,  bw,  bn,  bf,  bo,  bx,  cg, -cg, -bx, -bo, -bf, -bn, -bw, -cf,  ch,  by,  bp,  bg,  bm,  bv,  ce, -ci, -bz, -bq, -bh, -bl, -bu, -cd,  cj,  ca,  br,  bi,  bk,  bt,  cc, -ck, -cb, -bs, -bj }, \
251
  { ar,  aw,  bb, -bd, -ay, -at, -ap, -au, -az, -be,  ba,  av,  aq,  as,  ax,  bc, -bc, -ax, -as, -aq, -av, -ba,  be,  az,  au,  ap,  at,  ay,  bd, -bb, -aw, -ar, -ar, -aw, -bb,  bd,  ay,  at,  ap,  au,  az,  be, -ba, -av, -aq, -as, -ax, -bc,  bc,  ax,  as,  aq,  av,  ba, -be, -az, -au, -ap, -at, -ay, -bd,  bb,  aw,  ar }, \
252
  { bk,  bv,  cg, -ce, -bt, -bi, -bm, -bx, -ci,  cc,  br,  bg,  bo,  bz,  ck, -ca, -bp, -bf, -bq, -cb,  cj,  by,  bn,  bh,  bs,  cd, -ch, -bw, -bl, -bj, -bu, -cf,  cf,  bu,  bj,  bl,  bw,  ch, -cd, -bs, -bh, -bn, -by, -cj,  cb,  bq,  bf,  bp,  ca, -ck, -bz, -bo, -bg, -br, -cc,  ci,  bx,  bm,  bi,  bt,  ce, -cg, -bv, -bk }, \
253
  { ai,  al,  ao, -am, -aj, -ah, -ak, -an,  an,  ak,  ah,  aj,  am, -ao, -al, -ai, -ai, -al, -ao,  am,  aj,  ah,  ak,  an, -an, -ak, -ah, -aj, -am,  ao,  al,  ai,  ai,  al,  ao, -am, -aj, -ah, -ak, -an,  an,  ak,  ah,  aj,  am, -ao, -al, -ai, -ai, -al, -ao,  am,  aj,  ah,  ak,  an, -an, -ak, -ah, -aj, -am,  ao,  al,  ai }, \
254
  { bl,  by, -ck, -bx, -bk, -bm, -bz,  cj,  bw,  bj,  bn,  ca, -ci, -bv, -bi, -bo, -cb,  ch,  bu,  bh,  bp,  cc, -cg, -bt, -bg, -bq, -cd,  cf,  bs,  bf,  br,  ce, -ce, -br, -bf, -bs, -cf,  cd,  bq,  bg,  bt,  cg, -cc, -bp, -bh, -bu, -ch,  cb,  bo,  bi,  bv,  ci, -ca, -bn, -bj, -bw, -cj,  bz,  bm,  bk,  bx,  ck, -by, -bl }, \
255
  { as,  az, -bd, -aw, -ap, -av, -bc,  ba,  at,  ar,  ay, -be, -ax, -aq, -au, -bb,  bb,  au,  aq,  ax,  be, -ay, -ar, -at, -ba,  bc,  av,  ap,  aw,  bd, -az, -as, -as, -az,  bd,  aw,  ap,  av,  bc, -ba, -at, -ar, -ay,  be,  ax,  aq,  au,  bb, -bb, -au, -aq, -ax, -be,  ay,  ar,  at,  ba, -bc, -av, -ap, -aw, -bd,  az,  as }, \
256
  { bm,  cb, -cf, -bq, -bi, -bx,  cj,  bu,  bf,  bt,  ci, -by, -bj, -bp, -ce,  cc,  bn,  bl,  ca, -cg, -br, -bh, -bw,  ck,  bv,  bg,  bs,  ch, -bz, -bk, -bo, -cd,  cd,  bo,  bk,  bz, -ch, -bs, -bg, -bv, -ck,  bw,  bh,  br,  cg, -ca, -bl, -bn, -cc,  ce,  bp,  bj,  by, -ci, -bt, -bf, -bu, -cj,  bx,  bi,  bq,  cf, -cb, -bm }, \
257
  { ab,  ac, -ac, -ab, -ab, -ac,  ac,  ab,  ab,  ac, -ac, -ab, -ab, -ac,  ac,  ab,  ab,  ac, -ac, -ab, -ab, -ac,  ac,  ab,  ab,  ac, -ac, -ab, -ab, -ac,  ac,  ab,  ab,  ac, -ac, -ab, -ab, -ac,  ac,  ab,  ab,  ac, -ac, -ab, -ab, -ac,  ac,  ab,  ab,  ac, -ac, -ab, -ab, -ac,  ac,  ab,  ab,  ac, -ac, -ab, -ab, -ac,  ac,  ab }, \
258
  { bn,  ce, -ca, -bj, -br, -ci,  bw,  bf,  bv, -cj, -bs, -bi, -bz,  cf,  bo,  bm,  cd, -cb, -bk, -bq, -ch,  bx,  bg,  bu, -ck, -bt, -bh, -by,  cg,  bp,  bl,  cc, -cc, -bl, -bp, -cg,  by,  bh,  bt,  ck, -bu, -bg, -bx,  ch,  bq,  bk,  cb, -cd, -bm, -bo, -cf,  bz,  bi,  bs,  cj, -bv, -bf, -bw,  ci,  br,  bj,  ca, -ce, -bn }, \
259
  { at,  bc, -ay, -ap, -ax,  bd,  au,  as,  bb, -az, -aq, -aw,  be,  av,  ar,  ba, -ba, -ar, -av, -be,  aw,  aq,  az, -bb, -as, -au, -bd,  ax,  ap,  ay, -bc, -at, -at, -bc,  ay,  ap,  ax, -bd, -au, -as, -bb,  az,  aq,  aw, -be, -av, -ar, -ba,  ba,  ar,  av,  be, -aw, -aq, -az,  bb,  as,  au,  bd, -ax, -ap, -ay,  bc,  at }, \
260
  { bo,  ch, -bv, -bh, -ca,  cc,  bj,  bt, -cj, -bq, -bm, -cf,  bx,  bf,  by, -ce, -bl, -br, -ck,  bs,  bk,  cd, -bz, -bg, -bw,  cg,  bn,  bp,  ci, -bu, -bi, -cb,  cb,  bi,  bu, -ci, -bp, -bn, -cg,  bw,  bg,  bz, -cd, -bk, -bs,  ck,  br,  bl,  ce, -by, -bf, -bx,  cf,  bm,  bq,  cj, -bt, -bj, -cc,  ca,  bh,  bv, -ch, -bo }, \
261
  { aj,  ao, -ak, -ai, -an,  al,  ah,  am, -am, -ah, -al,  an,  ai,  ak, -ao, -aj, -aj, -ao,  ak,  ai,  an, -al, -ah, -am,  am,  ah,  al, -an, -ai, -ak,  ao,  aj,  aj,  ao, -ak, -ai, -an,  al,  ah,  am, -am, -ah, -al,  an,  ai,  ak, -ao, -aj, -aj, -ao,  ak,  ai,  an, -al, -ah, -am,  am,  ah,  al, -an, -ai, -ak,  ao,  aj }, \
262
  { bp,  ck, -bq, -bo, -cj,  br,  bn,  ci, -bs, -bm, -ch,  bt,  bl,  cg, -bu, -bk, -cf,  bv,  bj,  ce, -bw, -bi, -cd,  bx,  bh,  cc, -by, -bg, -cb,  bz,  bf,  ca, -ca, -bf, -bz,  cb,  bg,  by, -cc, -bh, -bx,  cd,  bi,  bw, -ce, -bj, -bv,  cf,  bk,  bu, -cg, -bl, -bt,  ch,  bm,  bs, -ci, -bn, -br,  cj,  bo,  bq, -ck, -bp }, \
263
  { au, -be, -at, -av,  bd,  as,  aw, -bc, -ar, -ax,  bb,  aq,  ay, -ba, -ap, -az,  az,  ap,  ba, -ay, -aq, -bb,  ax,  ar,  bc, -aw, -as, -bd,  av,  at,  be, -au, -au,  be,  at,  av, -bd, -as, -aw,  bc,  ar,  ax, -bb, -aq, -ay,  ba,  ap,  az, -az, -ap, -ba,  ay,  aq,  bb, -ax, -ar, -bc,  aw,  as,  bd, -av, -at, -be,  au }, \
264
  { bq, -ci, -bl, -bv,  cd,  bg,  ca, -by, -bi, -cf,  bt,  bn,  ck, -bo, -bs,  cg,  bj,  bx, -cb, -bf, -cc,  bw,  bk,  ch, -br, -bp,  cj,  bm,  bu, -ce, -bh, -bz,  bz,  bh,  ce, -bu, -bm, -cj,  bp,  br, -ch, -bk, -bw,  cc,  bf,  cb, -bx, -bj, -cg,  bs,  bo, -ck, -bn, -bt,  cf,  bi,  by, -ca, -bg, -cd,  bv,  bl,  ci, -bq }, \
265
  { ae, -ag, -ad, -af,  af,  ad,  ag, -ae, -ae,  ag,  ad,  af, -af, -ad, -ag,  ae,  ae, -ag, -ad, -af,  af,  ad,  ag, -ae, -ae,  ag,  ad,  af, -af, -ad, -ag,  ae,  ae, -ag, -ad, -af,  af,  ad,  ag, -ae, -ae,  ag,  ad,  af, -af, -ad, -ag,  ae,  ae, -ag, -ad, -af,  af,  ad,  ag, -ae, -ae,  ag,  ad,  af, -af, -ad, -ag,  ae }, \
266
  { br, -cf, -bg, -cc,  bu,  bo, -ci, -bj, -bz,  bx,  bl,  ck, -bm, -bw,  ca,  bi,  ch, -bp, -bt,  cd,  bf,  ce, -bs, -bq,  cg,  bh,  cb, -bv, -bn,  cj,  bk,  by, -by, -bk, -cj,  bn,  bv, -cb, -bh, -cg,  bq,  bs, -ce, -bf, -cd,  bt,  bp, -ch, -bi, -ca,  bw,  bm, -ck, -bl, -bx,  bz,  bj,  ci, -bo, -bu,  cc,  bg,  cf, -br }, \
267
  { av, -bb, -ap, -bc,  au,  aw, -ba, -aq, -bd,  at,  ax, -az, -ar, -be,  as,  ay, -ay, -as,  be,  ar,  az, -ax, -at,  bd,  aq,  ba, -aw, -au,  bc,  ap,  bb, -av, -av,  bb,  ap,  bc, -au, -aw,  ba,  aq,  bd, -at, -ax,  az,  ar,  be, -as, -ay,  ay,  as, -be, -ar, -az,  ax,  at, -bd, -aq, -ba,  aw,  au, -bc, -ap, -bb,  av }, \
268
  { bs, -cc, -bi, -cj,  bl,  bz, -bv, -bp,  cf,  bf,  cg, -bo, -bw,  by,  bm, -ci, -bh, -cd,  br,  bt, -cb, -bj, -ck,  bk,  ca, -bu, -bq,  ce,  bg,  ch, -bn, -bx,  bx,  bn, -ch, -bg, -ce,  bq,  bu, -ca, -bk,  ck,  bj,  cb, -bt, -br,  cd,  bh,  ci, -bm, -by,  bw,  bo, -cg, -bf, -cf,  bp,  bv, -bz, -bl,  cj,  bi,  cc, -bs }, \
269
  { ak, -am, -ai,  ao,  ah,  an, -aj, -al,  al,  aj, -an, -ah, -ao,  ai,  am, -ak, -ak,  am,  ai, -ao, -ah, -an,  aj,  al, -al, -aj,  an,  ah,  ao, -ai, -am,  ak,  ak, -am, -ai,  ao,  ah,  an, -aj, -al,  al,  aj, -an, -ah, -ao,  ai,  am, -ak, -ak,  am,  ai, -ao, -ah, -an,  aj,  al, -al, -aj,  an,  ah,  ao, -ai, -am,  ak }, \
270
  { bt, -bz, -bn,  cf,  bh,  ck, -bi, -ce,  bo,  by, -bu, -bs,  ca,  bm, -cg, -bg, -cj,  bj,  cd, -bp, -bx,  bv,  br, -cb, -bl,  ch,  bf,  ci, -bk, -cc,  bq,  bw, -bw, -bq,  cc,  bk, -ci, -bf, -ch,  bl,  cb, -br, -bv,  bx,  bp, -cd, -bj,  cj,  bg,  cg, -bm, -ca,  bs,  bu, -by, -bo,  ce,  bi, -ck, -bh, -cf,  bn,  bz, -bt }, \
271
  { aw, -ay, -au,  ba,  as, -bc, -aq,  be,  ap,  bd, -ar, -bb,  at,  az, -av, -ax,  ax,  av, -az, -at,  bb,  ar, -bd, -ap, -be,  aq,  bc, -as, -ba,  au,  ay, -aw, -aw,  ay,  au, -ba, -as,  bc,  aq, -be, -ap, -bd,  ar,  bb, -at, -az,  av,  ax, -ax, -av,  az,  at, -bb, -ar,  bd,  ap,  be, -aq, -bc,  as,  ba, -au, -ay,  aw }, \
272
  { bu, -bw, -bs,  by,  bq, -ca, -bo,  cc,  bm, -ce, -bk,  cg,  bi, -ci, -bg,  ck,  bf,  cj, -bh, -ch,  bj,  cf, -bl, -cd,  bn,  cb, -bp, -bz,  br,  bx, -bt, -bv,  bv,  bt, -bx, -br,  bz,  bp, -cb, -bn,  cd,  bl, -cf, -bj,  ch,  bh, -cj, -bf, -ck,  bg,  ci, -bi, -cg,  bk,  ce, -bm, -cc,  bo,  ca, -bq, -by,  bs,  bw, -bu }, \
273
  { aa, -aa, -aa,  aa,  aa, -aa, -aa,  aa,  aa, -aa, -aa,  aa,  aa, -aa, -aa,  aa,  aa, -aa, -aa,  aa,  aa, -aa, -aa,  aa,  aa, -aa, -aa,  aa,  aa, -aa, -aa,  aa,  aa, -aa, -aa,  aa,  aa, -aa, -aa,  aa,  aa, -aa, -aa,  aa,  aa, -aa, -aa,  aa,  aa, -aa, -aa,  aa,  aa, -aa, -aa,  aa,  aa, -aa, -aa,  aa,  aa, -aa, -aa,  aa }, \
274
  { bv, -bt, -bx,  br,  bz, -bp, -cb,  bn,  cd, -bl, -cf,  bj,  ch, -bh, -cj,  bf, -ck, -bg,  ci,  bi, -cg, -bk,  ce,  bm, -cc, -bo,  ca,  bq, -by, -bs,  bw,  bu, -bu, -bw,  bs,  by, -bq, -ca,  bo,  cc, -bm, -ce,  bk,  cg, -bi, -ci,  bg,  ck, -bf,  cj,  bh, -ch, -bj,  cf,  bl, -cd, -bn,  cb,  bp, -bz, -br,  bx,  bt, -bv }, \
275
  { ax, -av, -az,  at,  bb, -ar, -bd,  ap, -be, -aq,  bc,  as, -ba, -au,  ay,  aw, -aw, -ay,  au,  ba, -as, -bc,  aq,  be, -ap,  bd,  ar, -bb, -at,  az,  av, -ax, -ax,  av,  az, -at, -bb,  ar,  bd, -ap,  be,  aq, -bc, -as,  ba,  au, -ay, -aw,  aw,  ay, -au, -ba,  as,  bc, -aq, -be,  ap, -bd, -ar,  bb,  at, -az, -av,  ax }, \
276
  { bw, -bq, -cc,  bk,  ci, -bf,  ch,  bl, -cb, -br,  bv,  bx, -bp, -cd,  bj,  cj, -bg,  cg,  bm, -ca, -bs,  bu,  by, -bo, -ce,  bi,  ck, -bh,  cf,  bn, -bz, -bt,  bt,  bz, -bn, -cf,  bh, -ck, -bi,  ce,  bo, -by, -bu,  bs,  ca, -bm, -cg,  bg, -cj, -bj,  cd,  bp, -bx, -bv,  br,  cb, -bl, -ch,  bf, -ci, -bk,  cc,  bq, -bw }, \
277
  { al, -aj, -an,  ah, -ao, -ai,  am,  ak, -ak, -am,  ai,  ao, -ah,  an,  aj, -al, -al,  aj,  an, -ah,  ao,  ai, -am, -ak,  ak,  am, -ai, -ao,  ah, -an, -aj,  al,  al, -aj, -an,  ah, -ao, -ai,  am,  ak, -ak, -am,  ai,  ao, -ah,  an,  aj, -al, -al,  aj,  an, -ah,  ao,  ai, -am, -ak,  ak,  am, -ai, -ao,  ah, -an, -aj,  al }, \
278
  { bx, -bn, -ch,  bg, -ce, -bq,  bu,  ca, -bk, -ck,  bj, -cb, -bt,  br,  cd, -bh,  ci,  bm, -by, -bw,  bo,  cg, -bf,  cf,  bp, -bv, -bz,  bl,  cj, -bi,  cc,  bs, -bs, -cc,  bi, -cj, -bl,  bz,  bv, -bp, -cf,  bf, -cg, -bo,  bw,  by, -bm, -ci,  bh, -cd, -br,  bt,  cb, -bj,  ck,  bk, -ca, -bu,  bq,  ce, -bg,  ch,  bn, -bx }, \
279
  { ay, -as, -be,  ar, -az, -ax,  at,  bd, -aq,  ba,  aw, -au, -bc,  ap, -bb, -av,  av,  bb, -ap,  bc,  au, -aw, -ba,  aq, -bd, -at,  ax,  az, -ar,  be,  as, -ay, -ay,  as,  be, -ar,  az,  ax, -at, -bd,  aq, -ba, -aw,  au,  bc, -ap,  bb,  av, -av, -bb,  ap, -bc, -au,  aw,  ba, -aq,  bd,  at, -ax, -az,  ar, -be, -as,  ay }, \
280
  { by, -bk,  cj,  bn, -bv, -cb,  bh, -cg, -bq,  bs,  ce, -bf,  cd,  bt, -bp, -ch,  bi, -ca, -bw,  bm,  ck, -bl,  bx,  bz, -bj,  ci,  bo, -bu, -cc,  bg, -cf, -br,  br,  cf, -bg,  cc,  bu, -bo, -ci,  bj, -bz, -bx,  bl, -ck, -bm,  bw,  ca, -bi,  ch,  bp, -bt, -cd,  bf, -ce, -bs,  bq,  cg, -bh,  cb,  bv, -bn, -cj,  bk, -by }, \
281
  { af, -ad,  ag,  ae, -ae, -ag,  ad, -af, -af,  ad, -ag, -ae,  ae,  ag, -ad,  af,  af, -ad,  ag,  ae, -ae, -ag,  ad, -af, -af,  ad, -ag, -ae,  ae,  ag, -ad,  af,  af, -ad,  ag,  ae, -ae, -ag,  ad, -af, -af,  ad, -ag, -ae,  ae,  ag, -ad,  af,  af, -ad,  ag,  ae, -ae, -ag,  ad, -af, -af,  ad, -ag, -ae,  ae,  ag, -ad,  af }, \
282
  { bz, -bh,  ce,  bu, -bm,  cj,  bp, -br, -ch,  bk, -bw, -cc,  bf, -cb, -bx,  bj, -cg, -bs,  bo,  ck, -bn,  bt,  cf, -bi,  by,  ca, -bg,  cd,  bv, -bl,  ci,  bq, -bq, -ci,  bl, -bv, -cd,  bg, -ca, -by,  bi, -cf, -bt,  bn, -ck, -bo,  bs,  cg, -bj,  bx,  cb, -bf,  cc,  bw, -bk,  ch,  br, -bp, -cj,  bm, -bu, -ce,  bh, -bz }, \
283
  { az, -ap,  ba,  ay, -aq,  bb,  ax, -ar,  bc,  aw, -as,  bd,  av, -at,  be,  au, -au, -be,  at, -av, -bd,  as, -aw, -bc,  ar, -ax, -bb,  aq, -ay, -ba,  ap, -az, -az,  ap, -ba, -ay,  aq, -bb, -ax,  ar, -bc, -aw,  as, -bd, -av,  at, -be, -au,  au,  be, -at,  av,  bd, -as,  aw,  bc, -ar,  ax,  bb, -aq,  ay,  ba, -ap,  az }, \
284
  { ca, -bf,  bz,  cb, -bg,  by,  cc, -bh,  bx,  cd, -bi,  bw,  ce, -bj,  bv,  cf, -bk,  bu,  cg, -bl,  bt,  ch, -bm,  bs,  ci, -bn,  br,  cj, -bo,  bq,  ck, -bp,  bp, -ck, -bq,  bo, -cj, -br,  bn, -ci, -bs,  bm, -ch, -bt,  bl, -cg, -bu,  bk, -cf, -bv,  bj, -ce, -bw,  bi, -cd, -bx,  bh, -cc, -by,  bg, -cb, -bz,  bf, -ca }, \
285
  { am, -ah,  al,  an, -ai,  ak,  ao, -aj,  aj, -ao, -ak,  ai, -an, -al,  ah, -am, -am,  ah, -al, -an,  ai, -ak, -ao,  aj, -aj,  ao,  ak, -ai,  an,  al, -ah,  am,  am, -ah,  al,  an, -ai,  ak,  ao, -aj,  aj, -ao, -ak,  ai, -an, -al,  ah, -am, -am,  ah, -al, -an,  ai, -ak, -ao,  aj, -aj,  ao,  ak, -ai,  an,  al, -ah,  am }, \
286
  { cb, -bi,  bu,  ci, -bp,  bn, -cg, -bw,  bg, -bz, -cd,  bk, -bs, -ck,  br, -bl,  ce,  by, -bf,  bx,  cf, -bm,  bq, -cj, -bt,  bj, -cc, -ca,  bh, -bv, -ch,  bo, -bo,  ch,  bv, -bh,  ca,  cc, -bj,  bt,  cj, -bq,  bm, -cf, -bx,  bf, -by, -ce,  bl, -br,  ck,  bs, -bk,  cd,  bz, -bg,  bw,  cg, -bn,  bp, -ci, -bu,  bi, -cb }, \
287
  { ba, -ar,  av, -be, -aw,  aq, -az, -bb,  as, -au,  bd,  ax, -ap,  ay,  bc, -at,  at, -bc, -ay,  ap, -ax, -bd,  au, -as,  bb,  az, -aq,  aw,  be, -av,  ar, -ba, -ba,  ar, -av,  be,  aw, -aq,  az,  bb, -as,  au, -bd, -ax,  ap, -ay, -bc,  at, -at,  bc,  ay, -ap,  ax,  bd, -au,  as, -bb, -az,  aq, -aw, -be,  av, -ar,  ba }, \
288
  { cc, -bl,  bp, -cg, -by,  bh, -bt,  ck,  bu, -bg,  bx,  ch, -bq,  bk, -cb, -cd,  bm, -bo,  cf,  bz, -bi,  bs, -cj, -bv,  bf, -bw, -ci,  br, -bj,  ca,  ce, -bn,  bn, -ce, -ca,  bj, -br,  ci,  bw, -bf,  bv,  cj, -bs,  bi, -bz, -cf,  bo, -bm,  cd,  cb, -bk,  bq, -ch, -bx,  bg, -bu, -ck,  bt, -bh,  by,  cg, -bp,  bl, -cc }, \
289
  { ac, -ab,  ab, -ac, -ac,  ab, -ab,  ac,  ac, -ab,  ab, -ac, -ac,  ab, -ab,  ac,  ac, -ab,  ab, -ac, -ac,  ab, -ab,  ac,  ac, -ab,  ab, -ac, -ac,  ab, -ab,  ac,  ac, -ab,  ab, -ac, -ac,  ab, -ab,  ac,  ac, -ab,  ab, -ac, -ac,  ab, -ab,  ac,  ac, -ab,  ab, -ac, -ac,  ab, -ab,  ac,  ac, -ab,  ab, -ac, -ac,  ab, -ab,  ac }, \
290
  { cd, -bo,  bk, -bz, -ch,  bs, -bg,  bv, -ck, -bw,  bh, -br,  cg,  ca, -bl,  bn, -cc, -ce,  bp, -bj,  by,  ci, -bt,  bf, -bu,  cj,  bx, -bi,  bq, -cf, -cb,  bm, -bm,  cb,  cf, -bq,  bi, -bx, -cj,  bu, -bf,  bt, -ci, -by,  bj, -bp,  ce,  cc, -bn,  bl, -ca, -cg,  br, -bh,  bw,  ck, -bv,  bg, -bs,  ch,  bz, -bk,  bo, -cd }, \
291
  { bb, -au,  aq, -ax,  be,  ay, -ar,  at, -ba, -bc,  av, -ap,  aw, -bd, -az,  as, -as,  az,  bd, -aw,  ap, -av,  bc,  ba, -at,  ar, -ay, -be,  ax, -aq,  au, -bb, -bb,  au, -aq,  ax, -be, -ay,  ar, -at,  ba,  bc, -av,  ap, -aw,  bd,  az, -as,  as, -az, -bd,  aw, -ap,  av, -bc, -ba,  at, -ar,  ay,  be, -ax,  aq, -au,  bb }, \
292
  { ce, -br,  bf, -bs,  cf,  cd, -bq,  bg, -bt,  cg,  cc, -bp,  bh, -bu,  ch,  cb, -bo,  bi, -bv,  ci,  ca, -bn,  bj, -bw,  cj,  bz, -bm,  bk, -bx,  ck,  by, -bl,  bl, -by, -ck,  bx, -bk,  bm, -bz, -cj,  bw, -bj,  bn, -ca, -ci,  bv, -bi,  bo, -cb, -ch,  bu, -bh,  bp, -cc, -cg,  bt, -bg,  bq, -cd, -cf,  bs, -bf,  br, -ce }, \
293
  { an, -ak,  ah, -aj,  am,  ao, -al,  ai, -ai,  al, -ao, -am,  aj, -ah,  ak, -an, -an,  ak, -ah,  aj, -am, -ao,  al, -ai,  ai, -al,  ao,  am, -aj,  ah, -ak,  an,  an, -ak,  ah, -aj,  am,  ao, -al,  ai, -ai,  al, -ao, -am,  aj, -ah,  ak, -an, -an,  ak, -ah,  aj, -am, -ao,  al, -ai,  ai, -al,  ao,  am, -aj,  ah, -ak,  an }, \
294
  { cf, -bu,  bj, -bl,  bw, -ch, -cd,  bs, -bh,  bn, -by,  cj,  cb, -bq,  bf, -bp,  ca,  ck, -bz,  bo, -bg,  br, -cc, -ci,  bx, -bm,  bi, -bt,  ce,  cg, -bv,  bk, -bk,  bv, -cg, -ce,  bt, -bi,  bm, -bx,  ci,  cc, -br,  bg, -bo,  bz, -ck, -ca,  bp, -bf,  bq, -cb, -cj,  by, -bn,  bh, -bs,  cd,  ch, -bw,  bl, -bj,  bu, -cf }, \
295
  { bc, -ax,  as, -aq,  av, -ba, -be,  az, -au,  ap, -at,  ay, -bd, -bb,  aw, -ar,  ar, -aw,  bb,  bd, -ay,  at, -ap,  au, -az,  be,  ba, -av,  aq, -as,  ax, -bc, -bc,  ax, -as,  aq, -av,  ba,  be, -az,  au, -ap,  at, -ay,  bd,  bb, -aw,  ar, -ar,  aw, -bb, -bd,  ay, -at,  ap, -au,  az, -be, -ba,  av, -aq,  as, -ax,  bc }, \
296
  { cg, -bx,  bo, -bf,  bn, -bw,  cf,  ch, -by,  bp, -bg,  bm, -bv,  ce,  ci, -bz,  bq, -bh,  bl, -bu,  cd,  cj, -ca,  br, -bi,  bk, -bt,  cc,  ck, -cb,  bs, -bj,  bj, -bs,  cb, -ck, -cc,  bt, -bk,  bi, -br,  ca, -cj, -cd,  bu, -bl,  bh, -bq,  bz, -ci, -ce,  bv, -bm,  bg, -bp,  by, -ch, -cf,  bw, -bn,  bf, -bo,  bx, -cg }, \
297
  { ag, -af,  ae, -ad,  ad, -ae,  af, -ag, -ag,  af, -ae,  ad, -ad,  ae, -af,  ag,  ag, -af,  ae, -ad,  ad, -ae,  af, -ag, -ag,  af, -ae,  ad, -ad,  ae, -af,  ag,  ag, -af,  ae, -ad,  ad, -ae,  af, -ag, -ag,  af, -ae,  ad, -ad,  ae, -af,  ag,  ag, -af,  ae, -ad,  ad, -ae,  af, -ag, -ag,  af, -ae,  ad, -ad,  ae, -af,  ag }, \
298
  { ch, -ca,  bt, -bm,  bf, -bl,  bs, -bz,  cg,  ci, -cb,  bu, -bn,  bg, -bk,  br, -by,  cf,  cj, -cc,  bv, -bo,  bh, -bj,  bq, -bx,  ce,  ck, -cd,  bw, -bp,  bi, -bi,  bp, -bw,  cd, -ck, -ce,  bx, -bq,  bj, -bh,  bo, -bv,  cc, -cj, -cf,  by, -br,  bk, -bg,  bn, -bu,  cb, -ci, -cg,  bz, -bs,  bl, -bf,  bm, -bt,  ca, -ch }, \
299
  { bd, -ba,  ax, -au,  ar, -ap,  as, -av,  ay, -bb,  be,  bc, -az,  aw, -at,  aq, -aq,  at, -aw,  az, -bc, -be,  bb, -ay,  av, -as,  ap, -ar,  au, -ax,  ba, -bd, -bd,  ba, -ax,  au, -ar,  ap, -as,  av, -ay,  bb, -be, -bc,  az, -aw,  at, -aq,  aq, -at,  aw, -az,  bc,  be, -bb,  ay, -av,  as, -ap,  ar, -au,  ax, -ba,  bd }, \
300
  { ci, -cd,  by, -bt,  bo, -bj,  bf, -bk,  bp, -bu,  bz, -ce,  cj,  ch, -cc,  bx, -bs,  bn, -bi,  bg, -bl,  bq, -bv,  ca, -cf,  ck,  cg, -cb,  bw, -br,  bm, -bh,  bh, -bm,  br, -bw,  cb, -cg, -ck,  cf, -ca,  bv, -bq,  bl, -bg,  bi, -bn,  bs, -bx,  cc, -ch, -cj,  ce, -bz,  bu, -bp,  bk, -bf,  bj, -bo,  bt, -by,  cd, -ci }, \
301
  { ao, -an,  am, -al,  ak, -aj,  ai, -ah,  ah, -ai,  aj, -ak,  al, -am,  an, -ao, -ao,  an, -am,  al, -ak,  aj, -ai,  ah, -ah,  ai, -aj,  ak, -al,  am, -an,  ao,  ao, -an,  am, -al,  ak, -aj,  ai, -ah,  ah, -ai,  aj, -ak,  al, -am,  an, -ao, -ao,  an, -am,  al, -ak,  aj, -ai,  ah, -ah,  ai, -aj,  ak, -al,  am, -an,  ao }, \
302
  { cj, -cg,  cd, -ca,  bx, -bu,  br, -bo,  bl, -bi,  bf, -bh,  bk, -bn,  bq, -bt,  bw, -bz,  cc, -cf,  ci,  ck, -ch,  ce, -cb,  by, -bv,  bs, -bp,  bm, -bj,  bg, -bg,  bj, -bm,  bp, -bs,  bv, -by,  cb, -ce,  ch, -ck, -ci,  cf, -cc,  bz, -bw,  bt, -bq,  bn, -bk,  bh, -bf,  bi, -bl,  bo, -br,  bu, -bx,  ca, -cd,  cg, -cj }, \
303
  { be, -bd,  bc, -bb,  ba, -az,  ay, -ax,  aw, -av,  au, -at,  as, -ar,  aq, -ap,  ap, -aq,  ar, -as,  at, -au,  av, -aw,  ax, -ay,  az, -ba,  bb, -bc,  bd, -be, -be,  bd, -bc,  bb, -ba,  az, -ay,  ax, -aw,  av, -au,  at, -as,  ar, -aq,  ap, -ap,  aq, -ar,  as, -at,  au, -av,  aw, -ax,  ay, -az,  ba, -bb,  bc, -bd,  be }, \
304
  { ck, -cj,  ci, -ch,  cg, -cf,  ce, -cd,  cc, -cb,  ca, -bz,  by, -bx,  bw, -bv,  bu, -bt,  bs, -br,  bq, -bp,  bo, -bn,  bm, -bl,  bk, -bj,  bi, -bh,  bg, -bf,  bf, -bg,  bh, -bi,  bj, -bk,  bl, -bm,  bn, -bo,  bp, -bq,  br, -bs,  bt, -bu,  bv, -bw,  bx, -by,  bz, -ca,  cb, -cc,  cd, -ce,  cf, -cg,  ch, -ci,  cj, -ck }, \
305
}
306
307
static constexpr int8_t DCT2_64[64][64] = \
308
  DEFINE_DCT2_P64_MATRIX(64, 83, 36, 89, 75, 50, 18, 90, 87, 80, 70, 57, 43, 25, 9, 90, 90, 88, 85, 82, 78, 73, 67, 61, 54, 46, 38, 31, 22, 13, 4, 91, 90, 90, 90, 88, 87, 86, 84, 83, 81, 79, 77, 73, 71, 69, 65, 62, 59, 56, 52, 48, 44, 41, 37, 33, 28, 24, 20, 15, 11, 7, 2);
309
// clang-format on
310
311
/** Apply iDCT2 to block B[64][64] + clipping */
312
static void idct2_64( int8_t B[][64] )
313
0
{
314
0
  int16_t X[64][64];
315
0
  int     i, j, k;
316
0
  int32_t acc;
317
318
  /* 1st pass (DCT2_64'*B) = vertical */
319
0
  for( j = 0; j < 64; j++ )
320
0
  {
321
0
    for( i = 0; i < 64; i++ )
322
0
    {
323
0
      acc = 256;
324
0
      for( k = 0; k < 64; k++ )
325
0
      {
326
0
        acc += (int32_t) DCT2_64[k][j] * B[k][i];   // iDCT bases are vertical (transpose of DCT2_64)
327
0
      }
328
329
0
      X[j][i] = ( acc >> 9 );
330
0
    }
331
0
  }
332
333
  /* 2nd pass (...)*DCT2_64 = horizontal + clipping */
334
0
  for( j = 0; j < 64; j++ )
335
0
  {
336
0
    for( i = 0; i < 64; i++ )
337
0
    {
338
0
      acc = 256;
339
0
      for( k = 0; k < 64; k++ )
340
0
      {
341
0
        acc += (int32_t) X[j][k] * DCT2_64[k][i];
342
0
      }
343
344
0
      acc >>= 9;
345
0
      if( acc > 127 )
346
0
      {
347
0
        acc = 127;
348
0
      }
349
0
      if( acc < -127 )
350
0
      {
351
0
        acc = -127;
352
0
      }
353
0
      B[j][i] = acc;
354
0
    }
355
0
  }
356
0
}
357
358
/** Apply iDCT2 to block B[32][32] + clipping */
359
static void idct2_32( int8_t B[][32] )
360
0
{
361
0
  int16_t X[32][32];
362
0
  int     i, j, k;
363
0
  int32_t acc;
364
365
  /* 1st pass (R32'*B) = vertical */
366
0
  for( j = 0; j < 32; j++ )
367
0
  {
368
0
    for( i = 0; i < 32; i++ )
369
0
    {
370
0
      acc = 128;
371
0
      for( k = 0; k < 32; k++ )
372
0
      {
373
0
        acc += (int32_t) DCT2_64[k * 2][j] * B[k][i];   // iDCT bases are vertical (transpose of DCT2_64=DCT)
374
0
      }
375
376
0
      X[j][i] = ( acc >> 8 );
377
0
    }
378
0
  }
379
380
  /* 2nd pass (...)*R32 = horizontal + clipping */
381
0
  for( j = 0; j < 32; j++ )
382
0
  {
383
0
    for( i = 0; i < 32; i++ )
384
0
    {
385
0
      acc = 256;
386
0
      for( k = 0; k < 32; k++ )
387
0
      {
388
0
        acc += (int32_t) X[j][k] * DCT2_64[k * 2][i];
389
0
      }
390
391
0
      acc >>= 9;
392
0
      if( acc > 127 )
393
0
      {
394
0
        acc = 127;
395
0
      }
396
0
      if( acc < -127 )
397
0
      {
398
0
        acc = -127;
399
0
      }
400
0
      B[j][i] = acc;
401
0
    }
402
0
  }
403
0
}
404
405
static void make_sei_ff_pattern64( int8_t B[][64], int fh, int fv )
406
0
{
407
0
  int      k, l;
408
0
  uint32_t n;
409
0
  fh = 4 * ( fh + 1 );
410
0
  fv = 4 * ( fv + 1 );
411
412
0
  n = Seed_LUT[0];
413
0
  memset( B, 0, 64 * 64 * sizeof( int8_t ) );
414
0
  for( l = 0; l < 64; l++ )
415
0
  {
416
0
    for( k = 0; k < 64; k += 4 )
417
0
    {
418
0
      if( k < fh && l < fv )
419
0
      {
420
0
        B[l][k + 0] = Gaussian_LUT[( n + 0 ) & 2047];
421
0
        B[l][k + 1] = Gaussian_LUT[( n + 1 ) & 2047];
422
0
        B[l][k + 2] = Gaussian_LUT[( n + 2 ) & 2047];
423
0
        B[l][k + 3] = Gaussian_LUT[( n + 3 ) & 2047];
424
0
      }
425
0
      n = prng( n );
426
0
    }
427
0
  }
428
0
  B[0][0] = 0;
429
0
  idct2_64( B );
430
0
}
431
432
static void make_sei_ff_pattern32( int8_t B[][32], int fh, int fv )
433
0
{
434
0
  int      k, l;
435
0
  uint32_t n;
436
0
  fh = 2 * ( fh + 1 );
437
0
  fv = 2 * ( fv + 1 );
438
439
0
  n = Seed_LUT[1];
440
0
  memset( B, 0, 32 * 32 * sizeof( int8_t ) );
441
0
  for( l = 0; l < 32; l++ )
442
0
  {
443
0
    for( k = 0; k < 32; k += 2 )
444
0
    {
445
0
      if( k < fh && l < fv )
446
0
      {
447
0
        B[l][k + 0] = Gaussian_LUT[( n + 0 ) & 2047];
448
0
        B[l][k + 1] = Gaussian_LUT[( n + 1 ) & 2047];
449
0
      }
450
0
      n = prng( n );
451
0
    }
452
0
  }
453
0
  B[0][0] = 0;
454
0
  idct2_32( B );
455
0
}
456
457
static void make_ar_pattern( int8_t buf[], int8_t P[], int size, const int16_t ar_coef[], int nb_coef, int shift, int scale, uint32_t seed )
458
0
{
459
0
  int16_t  coef[4][7];
460
0
  int      L = 0;
461
0
  int      x, y, i, j, k;
462
0
  int      g;
463
0
  int      subx, suby, width, height;
464
0
  uint32_t rnd = seed;
465
466
0
  memset( coef, 0, sizeof( coef ) );
467
0
  subx = suby = ( size == 32 ) ? 2 : 1;
468
0
  width       = ( subx > 1 ) ? 44 : 82;
469
0
  height      = ( suby > 1 ) ? 38 : 73;
470
471
0
  switch( nb_coef )
472
0
  {
473
0
  case 6:
474
    // SEI.AR mode
475
0
    coef[3][2] = ar_coef[1];                                                            // left
476
0
    coef[2][3] = ( ar_coef[1] * ar_coef[4] ) >> scale;                                  // top
477
0
    coef[2][2] = ( ar_coef[3] * ar_coef[4] ) >> scale;                                  // top-left
478
0
    coef[2][4] = ( ar_coef[3] * ar_coef[4] ) >> scale;                                  // top-right
479
0
    coef[3][1] = ar_coef[5];                                                            // left-left
480
0
    coef[1][3] = ( (int32_t) ar_coef[5] * ar_coef[4] * ar_coef[4] ) >> ( 2 * scale );   // top-top
481
482
0
    L = 2;
483
0
    break;
484
485
0
  default:
486
0
    THROW_FATAL( "nb_coef != 6 not implemented" );
487
0
  }
488
0
  if( nb_coef != 6 )
489
0
  {
490
0
    for( k = 0, j = -L; j <= 0; j++ )
491
0
    {
492
0
      for( i = -L; i <= L && ( i < 0 || j < 0 ); i++, k++ )
493
0
      {
494
0
        coef[3 + j][3 + i] = ar_coef[k];
495
0
      }
496
0
    }
497
0
  }
498
499
0
  memset( buf, 0, width * height );   // debug (not needed)
500
0
  for( y = 0; y < height; y++ )
501
0
  {
502
0
    for( x = 0; x < width; x++ )
503
0
    {
504
      // Filter
505
0
      g = 0;
506
0
      if( y >= 3 && y < height && x >= 3 && x < width - 3 )
507
0
      {
508
0
        for( j = -3; j <= 0; j++ )
509
0
        {
510
0
          for( i = -3; i <= 3 && ( i < 0 || j < 0 ); i++ )
511
0
          {
512
0
            g += (int) coef[3 + j][3 + i] * buf[width * ( y + j ) + x + i];
513
0
          }
514
0
        }
515
516
0
        g = round( g, scale );
517
0
      }
518
519
      // Add random noise
520
0
      g += round( Gaussian_LUT[rnd & 2047], shift );
521
0
      rnd = prng( rnd );
522
523
0
      buf[width * y + x] = Clip3( -127, 127, g );
524
0
    }
525
0
  }
526
527
  // Copy cropped area to output
528
0
  memset( P, 0, size * size );
529
0
  for( y = 0; y < 64 / suby; y++ )
530
0
  {
531
0
    for( x = 0; x < 64 / subx; x++ )
532
0
    {
533
0
      P[size * y + x] = buf[width * ( 3 + 6 / suby + y ) + ( 3 + 6 / subx + x )];
534
0
    }
535
0
  }
536
0
}
537
538
static int same_pattern( fgs_sei* cfg, int32_t a, int32_t b )
539
0
{
540
0
  int16_t* coef_a = &cfg->comp_model_value[0][0][0] + a;
541
0
  int16_t* coef_b = &cfg->comp_model_value[0][0][0] + b;
542
543
0
  for( int i = 1; i < SEI_MAX_MODEL_VALUES; i++ )
544
0
  {
545
0
    if( coef_a[i] != coef_b[i] )
546
0
    {
547
0
      return 0;
548
0
    }
549
0
  }
550
551
0
  return 1;
552
0
}
553
554
void FilmGrain::set_seed( uint32_t seed )
555
0
{
556
0
  m_line_rnd = m_line_rnd_up = seed;
557
0
}
558
559
/** Initialize "hardware" interface from FGS SEI parameters */
560
void FilmGrain::init_sei()
561
0
{
562
0
  int8_t        P[64 * 64];
563
0
  int8_t        Lbuf[73 * 82];
564
0
  int8_t        Cbuf[38 * 44];
565
0
  uint8_t       slut[256];
566
0
  uint8_t       plut[256];
567
0
  uint8_t       intensities[VFGS_MAX_PATTERNS];
568
0
  uint32_t      patterns[VFGS_MAX_PATTERNS];
569
0
  uint8_t       np = 0;   // number of patterns
570
0
  uint8_t       a, b, i;
571
0
  unsigned char all0 = 1;
572
573
0
  int c, k;
574
575
0
  for( c = 0; c < 3; c++ )
576
0
  {
577
0
    memset( slut, 0, sizeof( slut ) );
578
0
    if( c < 2 )
579
0
    {
580
0
      np = 0;
581
0
      memset( intensities, 0, sizeof( intensities ) );
582
0
      memset( patterns, ~0, sizeof( patterns ) );
583
0
    }
584
    // 1. Look for different patterns, up to max supported number
585
0
    if( fgs.comp_model_present_flag[c] )
586
0
    {
587
0
      for( k = 0; k < fgs.num_intensity_intervals[c]; k++ )
588
0
      {
589
0
        a           = fgs.intensity_interval_lower_bound[c][k];
590
0
        uint32_t id = SEI_MAX_MODEL_VALUES * ( k + 256 * c );
591
592
0
        for( i = 0; i < VFGS_MAX_PATTERNS; i++ )
593
0
        {
594
0
          if( same_pattern( &fgs, patterns[i], id ) )
595
0
          {
596
0
            break;
597
0
          }
598
0
        }
599
600
0
        if( i == VFGS_MAX_PATTERNS && np < VFGS_MAX_PATTERNS )   // can add it
601
0
        {
602
          // keep them sorted (by intensity). The goal of this sort is
603
          // to enable meaningful pattern interpolation
604
0
          for( i = np; i > 0; i-- )
605
0
          {
606
0
            if( intensities[i - 1] > a )
607
0
            {
608
0
              intensities[i] = intensities[i - 1];
609
0
              patterns[i]    = patterns[i - 1];
610
0
            }
611
0
            else
612
0
            {
613
0
              break;
614
0
            }
615
0
          }
616
0
          intensities[i] = a;
617
0
          patterns[i]    = id;
618
0
          np++;
619
0
        }
620
0
      }
621
0
    }
622
0
    if( c == 0 || c == 2 )
623
0
    {
624
      // 2. Register the patterns (with correct order)
625
0
      for( i = 0; i < np; i++ )
626
0
      {
627
0
        int16_t* coef = &fgs.comp_model_value[0][0][0] + patterns[i];
628
629
0
        if( c == 0 )
630
0
        {
631
0
          if( fgs.model_id )
632
0
          {
633
0
            make_ar_pattern( Lbuf, P, 64, coef, 6, 1, fgs.log2_scale_factor, Seed_LUT[0] );
634
0
          }
635
0
          else
636
0
          {
637
0
            make_sei_ff_pattern64( (int8_t( * )[64]) P, coef[1], coef[2] );
638
0
          }
639
640
0
          m_impl->set_luma_pattern( i, P );
641
0
        }
642
0
        else if( c == 2 )
643
0
        {
644
0
          if( fgs.model_id )
645
0
          {
646
0
            make_ar_pattern( Cbuf, P, 32, coef, 6, 1, fgs.log2_scale_factor, Seed_LUT[1] );
647
0
          }
648
0
          else
649
0
          {
650
0
            make_sei_ff_pattern32( (int8_t( * )[32]) P, coef[1], coef[2] );
651
0
          }
652
0
          m_impl->set_chroma_pattern( i, P );
653
0
        }
654
0
      }
655
      // 3. Fill up LUTs
656
0
      for( int cc = std::min( c, 1 ); cc <= c; cc++ )
657
0
      {
658
0
        if( fgs.comp_model_present_flag[cc] )
659
0
        {
660
0
          memset( plut, 255, sizeof( plut ) );
661
          // 3a. Fill valid patterns
662
0
          for( k = 0; k < fgs.num_intensity_intervals[cc]; k++ )
663
0
          {
664
0
            a           = fgs.intensity_interval_lower_bound[cc][k];
665
0
            b           = fgs.intensity_interval_upper_bound[cc][k];
666
0
            uint32_t id = SEI_MAX_MODEL_VALUES * ( k + 256 * cc );
667
668
0
            for( i = 0; i < VFGS_MAX_PATTERNS; i++ )
669
0
            {
670
0
              if( same_pattern( &fgs, patterns[i], id ) )
671
0
              {
672
0
                break;
673
0
              }
674
0
            }
675
            // Note: if not found, could try to find interpolation value
676
677
0
            for( int l = a; l <= b; l++ )
678
0
            {
679
0
              slut[l] = (uint8_t) fgs.comp_model_value[cc][k][0];
680
0
              if( i < VFGS_MAX_PATTERNS )
681
0
              {
682
0
                plut[l] = i << 4;
683
0
              }
684
0
            }
685
0
          }
686
          // 3b. Fill holes (no interp. yet, just repeat last)
687
0
          i       = 0;
688
0
          int tmp = 0;
689
0
          for( k = 0; k < 256; k++ )
690
0
          {
691
0
            if( plut[k] == 255 )
692
0
            {
693
0
              plut[k] = i;
694
0
            }
695
0
            else
696
0
            {
697
0
              i = plut[k];
698
0
            }
699
0
            tmp += plut[k];
700
0
          }
701
0
          if( tmp != 0 )
702
0
          {
703
0
            all0 = 0;
704
0
          }
705
0
        }
706
0
        else
707
0
        {
708
0
          memset( plut, 0, sizeof( plut ) );
709
0
          all0 = 1;
710
0
        }
711
        // 3c. Register LUTs
712
0
        m_impl->set_scale_lut( cc, slut );
713
0
        m_impl->set_pattern_lut( cc, plut, all0 );
714
0
      }
715
0
    }
716
0
  }
717
718
0
  m_impl->set_scale_shift( fgs.log2_scale_factor - ( fgs.model_id ? 1 : 0 ) );   // -1 for grain shift in pattern generation (see above)
719
0
}
720
721
FilmGrain::FilmGrain()
722
0
{
723
0
#if defined( TARGET_SIMD_X86 ) && ENABLE_SIMD_OPT
724
0
  m_impl = FilmGrainImplX86<UNDEFINED>::makeFilmGrainImpl();
725
#else
726
  m_impl = std::make_unique<FilmGrainImpl>();
727
#endif
728
0
}
729
730
void FilmGrain::updateFGC( vvdecSEIFilmGrainCharacteristics* fgc )
731
0
{
732
  // Copy SEI message in vfgs structure format
733
  // TODO: check some values and warn about unsupported stuff ?
734
0
  fgs.model_id          = fgc->filmGrainModelId;
735
0
  fgs.log2_scale_factor = fgc->log2ScaleFactor;
736
0
  for( int c = 0; c < 3; c++ )
737
0
  {
738
0
    vvdecCompModel& cm = fgc->compModel[c];
739
0
    if( cm.presentFlag )
740
0
    {
741
0
      fgs.comp_model_present_flag[c] = 1;
742
0
      fgs.num_intensity_intervals[c] = cm.numIntensityIntervals;
743
0
      fgs.num_model_values[c]        = cm.numModelValues;
744
0
      for( int i = 0; i < fgs.num_intensity_intervals[c]; i++ )
745
0
      {
746
0
        vvdecCompModelIntensityValues& cmiv      = cm.intensityValues[i];
747
0
        fgs.intensity_interval_lower_bound[c][i] = cmiv.intensityIntervalLowerBound;
748
0
        fgs.intensity_interval_upper_bound[c][i] = cmiv.intensityIntervalUpperBound;
749
0
        for( int v = 0; v < fgs.num_model_values[c]; v++ )
750
0
        {
751
0
          fgs.comp_model_value[c][i][v] = cmiv.compModelValue[v];
752
0
        }
753
        // Fill with default model values (VFGS needs them; it actually ignores num_model_values)
754
0
        switch( fgs.num_model_values[c] )
755
0
        {
756
          // clang-format off
757
0
          case 0:
758
0
          case 1: fgs.comp_model_value[c][i][1] = fgs.model_id ? 0 : 8;                               // H high cutoff / 1st AR coef (left & top)
759
0
          case 2: fgs.comp_model_value[c][i][2] = fgs.model_id ? 0 : fgs.comp_model_value[c][i][1];   // V high cutoff / x-comp corr
760
0
          case 3: fgs.comp_model_value[c][i][3] = 0;                                                  // H low cutoff / 2nd AR coef (top-left, top-right)
761
0
          case 4: fgs.comp_model_value[c][i][4] = fgs.model_id << fgs.log2_scale_factor;              // V low cutoff / aspect ratio
762
0
                  fgs.comp_model_value[c][i][5] = 0;                                                  // x-comp corr / 3rd AR coef (left-left, top-top)
763
          // clang-format on
764
0
        }
765
0
      }
766
0
    }
767
0
  }
768
769
  // Conversion of component model values for 4:2:0 chroma format
770
0
  if( fgs.model_id == 0 )
771
0
  {
772
0
    for( int c = 1; c < 3; c++ )
773
0
    {
774
0
      if( fgs.comp_model_present_flag[c] )
775
0
      {
776
0
        for( int k = 0; k < fgs.num_intensity_intervals[c]; k++ )
777
0
        {
778
0
          fgs.comp_model_value[c][k][1] = std::max( 2, std::min( 14, fgs.comp_model_value[c][k][1] << 1 ) );   // Horizontal frequency
779
0
          fgs.comp_model_value[c][k][2] = std::max( 2, std::min( 14, fgs.comp_model_value[c][k][2] << 1 ) );   // Vertical frequency
780
0
          fgs.comp_model_value[c][k][0] >>= 1;
781
0
        }
782
0
      }
783
0
    }
784
0
  }
785
786
0
  init_sei();
787
788
  //  if (!m_bFgs)
789
  //    // TODO: get something random
790
  //      // TODO: make seed also impact the pattern gen
791
  //    set_seed(uint32_t seed);
792
0
}
793
794
void FilmGrain::prepareBlockSeeds( int width, int height )
795
0
{
796
0
  m_line_seeds.resize( ( height + 15 ) / 16 );
797
798
0
  m_prev_frame_line_rnd_up = m_line_rnd_up;
799
800
0
  uint32_t rnd = 0;
801
0
  for( int y = 0; y < m_line_seeds.size(); ++y )
802
0
  {
803
    // Generate / backup / restore per-line random seeds (needed to make multi-line blocks)
804
0
    if( y != 0 )
805
0
    {
806
      // new line of blocks
807
0
      m_line_rnd_up = m_line_rnd;
808
0
      m_line_rnd    = rnd;
809
0
    }
810
811
0
    m_line_seeds[y] = m_line_rnd;
812
813
    // Crank random generator
814
0
    rnd = m_line_rnd;
815
0
    for( int x = 0; x < ( width + 15 ) / 16; ++x )
816
0
    {
817
0
      rnd = prng( rnd );
818
0
    }
819
0
  }
820
0
}
821
822
void FilmGrain::setColorFormat( vvdecColorFormat fmt )
823
0
{
824
0
  switch( fmt )
825
0
  {
826
    // clang-format off
827
0
    case VVDEC_CF_YUV400_PLANAR: m_impl->set_chroma_subsampling( 0, 0 ); break;
828
0
    case VVDEC_CF_YUV420_PLANAR: m_impl->set_chroma_subsampling( 2, 2 ); break;
829
0
    case VVDEC_CF_YUV422_PLANAR: m_impl->set_chroma_subsampling( 2, 1 ); break;
830
0
    case VVDEC_CF_YUV444_PLANAR: m_impl->set_chroma_subsampling( 1, 1 ); break;
831
0
    default: THROW_FATAL( "invalid color format: " );
832
    // clang-format on
833
0
  }
834
0
}
835
836
void FilmGrain::add_grain_line( void* Y, void* U, void* V, int y, int width )
837
0
{
838
0
  uint32_t rnd_up = y < 16 ? m_prev_frame_line_rnd_up : m_line_seeds[y / 16 - 1];
839
0
  uint32_t rnd    = m_line_seeds[y / 16];
840
841
0
  int16_t grain[3][32];
842
0
  uint8_t scale[3][32];
843
844
  // Process line
845
0
  for( int x = 0; x < width; x += 16 )
846
0
  {
847
    // Process pixels for each color component
848
0
    if( fgs.comp_model_present_flag[0] )
849
0
    {
850
0
      m_impl->add_grain_block( Y, 0, x, y, width, rnd, rnd_up, grain, scale );
851
0
    }
852
0
    if( U && V )
853
0
    {
854
0
      if( fgs.comp_model_present_flag[1] )
855
0
      {
856
0
        m_impl->add_grain_block( U, 1, x, y, width, rnd, rnd_up, grain, scale );
857
0
      }
858
0
      if( fgs.comp_model_present_flag[2] )
859
0
      {
860
0
        m_impl->add_grain_block( V, 2, x, y, width, rnd, rnd_up, grain, scale );
861
0
      }
862
0
    }
863
    // Crank random generator
864
0
    rnd    = prng( rnd );
865
0
    rnd_up = prng( rnd_up );   // upper block (overlapping)
866
0
  }
867
0
}
868
869
}   // namespace vvdec