• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The libgav1 Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/film_grain.h"
16 
17 #include <algorithm>
18 #include <cassert>
19 #include <cstddef>
20 #include <cstdint>
21 #include <cstring>
22 #include <new>
23 
24 #include "src/dsp/common.h"
25 #include "src/dsp/constants.h"
26 #include "src/dsp/dsp.h"
27 #include "src/dsp/film_grain_common.h"
28 #include "src/utils/array_2d.h"
29 #include "src/utils/blocking_counter.h"
30 #include "src/utils/common.h"
31 #include "src/utils/compiler_attributes.h"
32 #include "src/utils/constants.h"
33 #include "src/utils/logging.h"
34 #include "src/utils/threadpool.h"
35 
36 namespace libgav1 {
37 
38 namespace {
39 
40 // The kGaussianSequence array contains random samples from a Gaussian
41 // distribution with zero mean and standard deviation of about 512 clipped to
42 // the range of [-2048, 2047] (representable by a signed integer using 12 bits
43 // of precision) and rounded to the nearest multiple of 4.
44 //
45 // Note: It is important that every element in the kGaussianSequence array be
46 // less than 2040, so that RightShiftWithRounding(kGaussianSequence[i], 4) is
47 // less than 128 for bitdepth=8 (GrainType=int8_t).
48 constexpr int16_t kGaussianSequence[/*2048*/] = {
49     56,    568,   -180,  172,   124,   -84,   172,   -64,   -900,  24,   820,
50     224,   1248,  996,   272,   -8,    -916,  -388,  -732,  -104,  -188, 800,
51     112,   -652,  -320,  -376,  140,   -252,  492,   -168,  44,    -788, 588,
52     -584,  500,   -228,  12,    680,   272,   -476,  972,   -100,  652,  368,
53     432,   -196,  -720,  -192,  1000,  -332,  652,   -136,  -552,  -604, -4,
54     192,   -220,  -136,  1000,  -52,   372,   -96,   -624,  124,   -24,  396,
55     540,   -12,   -104,  640,   464,   244,   -208,  -84,   368,   -528, -740,
56     248,   -968,  -848,  608,   376,   -60,   -292,  -40,   -156,  252,  -292,
57     248,   224,   -280,  400,   -244,  244,   -60,   76,    -80,   212,  532,
58     340,   128,   -36,   824,   -352,  -60,   -264,  -96,   -612,  416,  -704,
59     220,   -204,  640,   -160,  1220,  -408,  900,   336,   20,    -336, -96,
60     -792,  304,   48,    -28,   -1232, -1172, -448,  104,   -292,  -520, 244,
61     60,    -948,  0,     -708,  268,   108,   356,   -548,  488,   -344, -136,
62     488,   -196,  -224,  656,   -236,  -1128, 60,    4,     140,   276,  -676,
63     -376,  168,   -108,  464,   8,     564,   64,    240,   308,   -300, -400,
64     -456,  -136,  56,    120,   -408,  -116,  436,   504,   -232,  328,  844,
65     -164,  -84,   784,   -168,  232,   -224,  348,   -376,  128,   568,  96,
66     -1244, -288,  276,   848,   832,   -360,  656,   464,   -384,  -332, -356,
67     728,   -388,  160,   -192,  468,   296,   224,   140,   -776,  -100, 280,
68     4,     196,   44,    -36,   -648,  932,   16,    1428,  28,    528,  808,
69     772,   20,    268,   88,    -332,  -284,  124,   -384,  -448,  208,  -228,
70     -1044, -328,  660,   380,   -148,  -300,  588,   240,   540,   28,   136,
71     -88,   -436,  256,   296,   -1000, 1400,  0,     -48,   1056,  -136, 264,
72     -528,  -1108, 632,   -484,  -592,  -344,  796,   124,   -668,  -768, 388,
73     1296,  -232,  -188,  -200,  -288,  -4,    308,   100,   -168,  256,  -500,
74     204,   -508,  648,   -136,  372,   -272,  -120,  -1004, -552,  -548, -384,
75     548,   -296,  428,   -108,  -8,    -912,  -324,  -224,  -88,   -112, -220,
76     -100,  996,   -796,  548,   360,   -216,  180,   428,   -200,  -212, 148,
77     96,    148,   284,   216,   -412,  -320,  120,   -300,  -384,  -604, -572,
78     -332,  -8,    -180,  -176,  696,   116,   -88,   628,   76,    44,   -516,
79     240,   -208,  -40,   100,   -592,  344,   -308,  -452,  -228,  20,   916,
80     -1752, -136,  -340,  -804,  140,   40,    512,   340,   248,   184,  -492,
81     896,   -156,  932,   -628,  328,   -688,  -448,  -616,  -752,  -100, 560,
82     -1020, 180,   -800,  -64,   76,    576,   1068,  396,   660,   552,  -108,
83     -28,   320,   -628,  312,   -92,   -92,   -472,  268,   16,    560,  516,
84     -672,  -52,   492,   -100,  260,   384,   284,   292,   304,   -148, 88,
85     -152,  1012,  1064,  -228,  164,   -376,  -684,  592,   -392,  156,  196,
86     -524,  -64,   -884,  160,   -176,  636,   648,   404,   -396,  -436, 864,
87     424,   -728,  988,   -604,  904,   -592,  296,   -224,  536,   -176, -920,
88     436,   -48,   1176,  -884,  416,   -776,  -824,  -884,  524,   -548, -564,
89     -68,   -164,  -96,   692,   364,   -692,  -1012, -68,   260,   -480, 876,
90     -1116, 452,   -332,  -352,  892,   -1088, 1220,  -676,  12,    -292, 244,
91     496,   372,   -32,   280,   200,   112,   -440,  -96,   24,    -644, -184,
92     56,    -432,  224,   -980,  272,   -260,  144,   -436,  420,   356,  364,
93     -528,  76,    172,   -744,  -368,  404,   -752,  -416,  684,   -688, 72,
94     540,   416,   92,    444,   480,   -72,   -1416, 164,   -1172, -68,  24,
95     424,   264,   1040,  128,   -912,  -524,  -356,  64,    876,   -12,  4,
96     -88,   532,   272,   -524,  320,   276,   -508,  940,   24,    -400, -120,
97     756,   60,    236,   -412,  100,   376,   -484,  400,   -100,  -740, -108,
98     -260,  328,   -268,  224,   -200,  -416,  184,   -604,  -564,  -20,  296,
99     60,    892,   -888,  60,    164,   68,    -760,  216,   -296,  904,  -336,
100     -28,   404,   -356,  -568,  -208,  -1480, -512,  296,   328,   -360, -164,
101     -1560, -776,  1156,  -428,  164,   -504,  -112,  120,   -216,  -148, -264,
102     308,   32,    64,    -72,   72,    116,   176,   -64,   -272,  460,  -536,
103     -784,  -280,  348,   108,   -752,  -132,  524,   -540,  -776,  116,  -296,
104     -1196, -288,  -560,  1040,  -472,  116,   -848,  -1116, 116,   636,  696,
105     284,   -176,  1016,  204,   -864,  -648,  -248,  356,   972,   -584, -204,
106     264,   880,   528,   -24,   -184,  116,   448,   -144,  828,   524,  212,
107     -212,  52,    12,    200,   268,   -488,  -404,  -880,  824,   -672, -40,
108     908,   -248,  500,   716,   -576,  492,   -576,  16,    720,   -108, 384,
109     124,   344,   280,   576,   -500,  252,   104,   -308,  196,   -188, -8,
110     1268,  296,   1032,  -1196, 436,   316,   372,   -432,  -200,  -660, 704,
111     -224,  596,   -132,  268,   32,    -452,  884,   104,   -1008, 424,  -1348,
112     -280,  4,     -1168, 368,   476,   696,   300,   -8,    24,    180,  -592,
113     -196,  388,   304,   500,   724,   -160,  244,   -84,   272,   -256, -420,
114     320,   208,   -144,  -156,  156,   364,   452,   28,    540,   316,  220,
115     -644,  -248,  464,   72,    360,   32,    -388,  496,   -680,  -48,  208,
116     -116,  -408,  60,    -604,  -392,  548,   -840,  784,   -460,  656,  -544,
117     -388,  -264,  908,   -800,  -628,  -612,  -568,  572,   -220,  164,  288,
118     -16,   -308,  308,   -112,  -636,  -760,  280,   -668,  432,   364,  240,
119     -196,  604,   340,   384,   196,   592,   -44,   -500,  432,   -580, -132,
120     636,   -76,   392,   4,     -412,  540,   508,   328,   -356,  -36,  16,
121     -220,  -64,   -248,  -60,   24,    -192,  368,   1040,  92,    -24,  -1044,
122     -32,   40,    104,   148,   192,   -136,  -520,  56,    -816,  -224, 732,
123     392,   356,   212,   -80,   -424,  -1008, -324,  588,   -1496, 576,  460,
124     -816,  -848,  56,    -580,  -92,   -1372, -112,  -496,  200,   364,  52,
125     -140,  48,    -48,   -60,   84,    72,    40,    132,   -356,  -268, -104,
126     -284,  -404,  732,   -520,  164,   -304,  -540,  120,   328,   -76,  -460,
127     756,   388,   588,   236,   -436,  -72,   -176,  -404,  -316,  -148, 716,
128     -604,  404,   -72,   -88,   -888,  -68,   944,   88,    -220,  -344, 960,
129     472,   460,   -232,  704,   120,   832,   -228,  692,   -508,  132,  -476,
130     844,   -748,  -364,  -44,   1116,  -1104, -1056, 76,    428,   552,  -692,
131     60,    356,   96,    -384,  -188,  -612,  -576,  736,   508,   892,  352,
132     -1132, 504,   -24,   -352,  324,   332,   -600,  -312,  292,   508,  -144,
133     -8,    484,   48,    284,   -260,  -240,  256,   -100,  -292,  -204, -44,
134     472,   -204,  908,   -188,  -1000, -256,  92,    1164,  -392,  564,  356,
135     652,   -28,   -884,  256,   484,   -192,  760,   -176,  376,   -524, -452,
136     -436,  860,   -736,  212,   124,   504,   -476,  468,   76,    -472, 552,
137     -692,  -944,  -620,  740,   -240,  400,   132,   20,    192,   -196, 264,
138     -668,  -1012, -60,   296,   -316,  -828,  76,    -156,  284,   -768, -448,
139     -832,  148,   248,   652,   616,   1236,  288,   -328,  -400,  -124, 588,
140     220,   520,   -696,  1032,  768,   -740,  -92,   -272,  296,   448,  -464,
141     412,   -200,  392,   440,   -200,  264,   -152,  -260,  320,   1032, 216,
142     320,   -8,    -64,   156,   -1016, 1084,  1172,  536,   484,   -432, 132,
143     372,   -52,   -256,  84,    116,   -352,  48,    116,   304,   -384, 412,
144     924,   -300,  528,   628,   180,   648,   44,    -980,  -220,  1320, 48,
145     332,   748,   524,   -268,  -720,  540,   -276,  564,   -344,  -208, -196,
146     436,   896,   88,    -392,  132,   80,    -964,  -288,  568,   56,   -48,
147     -456,  888,   8,     552,   -156,  -292,  948,   288,   128,   -716, -292,
148     1192,  -152,  876,   352,   -600,  -260,  -812,  -468,  -28,   -120, -32,
149     -44,   1284,  496,   192,   464,   312,   -76,   -516,  -380,  -456, -1012,
150     -48,   308,   -156,  36,    492,   -156,  -808,  188,   1652,  68,   -120,
151     -116,  316,   160,   -140,  352,   808,   -416,  592,   316,   -480, 56,
152     528,   -204,  -568,  372,   -232,  752,   -344,  744,   -4,    324,  -416,
153     -600,  768,   268,   -248,  -88,   -132,  -420,  -432,  80,    -288, 404,
154     -316,  -1216, -588,  520,   -108,  92,    -320,  368,   -480,  -216, -92,
155     1688,  -300,  180,   1020,  -176,  820,   -68,   -228,  -260,  436,  -904,
156     20,    40,    -508,  440,   -736,  312,   332,   204,   760,   -372, 728,
157     96,    -20,   -632,  -520,  -560,  336,   1076,  -64,   -532,  776,  584,
158     192,   396,   -728,  -520,  276,   -188,  80,    -52,   -612,  -252, -48,
159     648,   212,   -688,  228,   -52,   -260,  428,   -412,  -272,  -404, 180,
160     816,   -796,  48,    152,   484,   -88,   -216,  988,   696,   188,  -528,
161     648,   -116,  -180,  316,   476,   12,    -564,  96,    476,   -252, -364,
162     -376,  -392,  556,   -256,  -576,  260,   -352,  120,   -16,   -136, -260,
163     -492,  72,    556,   660,   580,   616,   772,   436,   424,   -32,  -324,
164     -1268, 416,   -324,  -80,   920,   160,   228,   724,   32,    -516, 64,
165     384,   68,    -128,  136,   240,   248,   -204,  -68,   252,   -932, -120,
166     -480,  -628,  -84,   192,   852,   -404,  -288,  -132,  204,   100,  168,
167     -68,   -196,  -868,  460,   1080,  380,   -80,   244,   0,     484,  -888,
168     64,    184,   352,   600,   460,   164,   604,   -196,  320,   -64,  588,
169     -184,  228,   12,    372,   48,    -848,  -344,  224,   208,   -200, 484,
170     128,   -20,   272,   -468,  -840,  384,   256,   -720,  -520,  -464, -580,
171     112,   -120,  644,   -356,  -208,  -608,  -528,  704,   560,   -424, 392,
172     828,   40,    84,    200,   -152,  0,     -144,  584,   280,   -120, 80,
173     -556,  -972,  -196,  -472,  724,   80,    168,   -32,   88,    160,  -688,
174     0,     160,   356,   372,   -776,  740,   -128,  676,   -248,  -480, 4,
175     -364,  96,    544,   232,   -1032, 956,   236,   356,   20,    -40,  300,
176     24,    -676,  -596,  132,   1120,  -104,  532,   -1096, 568,   648,  444,
177     508,   380,   188,   -376,  -604,  1488,  424,   24,    756,   -220, -192,
178     716,   120,   920,   688,   168,   44,    -460,  568,   284,   1144, 1160,
179     600,   424,   888,   656,   -356,  -320,  220,   316,   -176,  -724, -188,
180     -816,  -628,  -348,  -228,  -380,  1012,  -452,  -660,  736,   928,  404,
181     -696,  -72,   -268,  -892,  128,   184,   -344,  -780,  360,   336,  400,
182     344,   428,   548,   -112,  136,   -228,  -216,  -820,  -516,  340,  92,
183     -136,  116,   -300,  376,   -244,  100,   -316,  -520,  -284,  -12,  824,
184     164,   -548,  -180,  -128,  116,   -924,  -828,  268,   -368,  -580, 620,
185     192,   160,   0,     -1676, 1068,  424,   -56,   -360,  468,   -156, 720,
186     288,   -528,  556,   -364,  548,   -148,  504,   316,   152,   -648, -620,
187     -684,  -24,   -376,  -384,  -108,  -920,  -1032, 768,   180,   -264, -508,
188     -1268, -260,  -60,   300,   -240,  988,   724,   -376,  -576,  -212, -736,
189     556,   192,   1092,  -620,  -880,  376,   -56,   -4,    -216,  -32,  836,
190     268,   396,   1332,  864,   -600,  100,   56,    -412,  -92,   356,  180,
191     884,   -468,  -436,  292,   -388,  -804,  -704,  -840,  368,   -348, 140,
192     -724,  1536,  940,   372,   112,   -372,  436,   -480,  1136,  296,  -32,
193     -228,  132,   -48,   -220,  868,   -1016, -60,   -1044, -464,  328,  916,
194     244,   12,    -736,  -296,  360,   468,   -376,  -108,  -92,   788,  368,
195     -56,   544,   400,   -672,  -420,  728,   16,    320,   44,    -284, -380,
196     -796,  488,   132,   204,   -596,  -372,  88,    -152,  -908,  -636, -572,
197     -624,  -116,  -692,  -200,  -56,   276,   -88,   484,   -324,  948,  864,
198     1000,  -456,  -184,  -276,  292,   -296,  156,   676,   320,   160,  908,
199     -84,   -1236, -288,  -116,  260,   -372,  -644,  732,   -756,  -96,  84,
200     344,   -520,  348,   -688,  240,   -84,   216,   -1044, -136,  -676, -396,
201     -1500, 960,   -40,   176,   168,   1516,  420,   -504,  -344,  -364, -360,
202     1216,  -940,  -380,  -212,  252,   -660,  -708,  484,   -444,  -152, 928,
203     -120,  1112,  476,   -260,  560,   -148,  -344,  108,   -196,  228,  -288,
204     504,   560,   -328,  -88,   288,   -1008, 460,   -228,  468,   -836, -196,
205     76,    388,   232,   412,   -1168, -716,  -644,  756,   -172,  -356, -504,
206     116,   432,   528,   48,    476,   -168,  -608,  448,   160,   -532, -272,
207     28,    -676,  -12,   828,   980,   456,   520,   104,   -104,  256,  -344,
208     -4,    -28,   -368,  -52,   -524,  -572,  -556,  -200,  768,   1124, -208,
209     -512,  176,   232,   248,   -148,  -888,  604,   -600,  -304,  804,  -156,
210     -212,  488,   -192,  -804,  -256,  368,   -360,  -916,  -328,  228,  -240,
211     -448,  -472,  856,   -556,  -364,  572,   -12,   -156,  -368,  -340, 432,
212     252,   -752,  -152,  288,   268,   -580,  -848,  -592,  108,   -76,  244,
213     312,   -716,  592,   -80,   436,   360,   4,     -248,  160,   516,  584,
214     732,   44,    -468,  -280,  -292,  -156,  -588,  28,    308,   912,  24,
215     124,   156,   180,   -252,  944,   -924,  -772,  -520,  -428,  -624, 300,
216     -212,  -1144, 32,    -724,  800,   -1128, -212,  -1288, -848,  180,  -416,
217     440,   192,   -576,  -792,  -76,   -1080, 80,    -532,  -352,  -132, 380,
218     -820,  148,   1112,  128,   164,   456,   700,   -924,  144,   -668, -384,
219     648,   -832,  508,   552,   -52,   -100,  -656,  208,   -568,  748,  -88,
220     680,   232,   300,   192,   -408,  -1012, -152,  -252,  -268,  272,  -876,
221     -664,  -648,  -332,  -136,  16,    12,    1152,  -28,   332,   -536, 320,
222     -672,  -460,  -316,  532,   -260,  228,   -40,   1052,  -816,  180,  88,
223     -496,  -556,  -672,  -368,  428,   92,    356,   404,   -408,  252,  196,
224     -176,  -556,  792,   268,   32,    372,   40,    96,    -332,  328,  120,
225     372,   -900,  -40,   472,   -264,  -592,  952,   128,   656,   112,  664,
226     -232,  420,   4,     -344,  -464,  556,   244,   -416,  -32,   252,  0,
227     -412,  188,   -696,  508,   -476,  324,   -1096, 656,   -312,  560,  264,
228     -136,  304,   160,   -64,   -580,  248,   336,   -720,  560,   -348, -288,
229     -276,  -196,  -500,  852,   -544,  -236,  -1128, -992,  -776,  116,  56,
230     52,    860,   884,   212,   -12,   168,   1020,  512,   -552,  924,  -148,
231     716,   188,   164,   -340,  -520,  -184,  880,   -152,  -680,  -208, -1156,
232     -300,  -528,  -472,  364,   100,   -744,  -1056, -32,   540,   280,  144,
233     -676,  -32,   -232,  -280,  -224,  96,    568,   -76,   172,   148,  148,
234     104,   32,    -296,  -32,   788,   -80,   32,    -16,   280,   288,  944,
235     428,   -484};
236 static_assert(sizeof(kGaussianSequence) / sizeof(kGaussianSequence[0]) == 2048,
237               "");
238 
239 // The number of rows in a contiguous group computed by a single worker thread
240 // before checking for the next available group.
241 constexpr int kFrameChunkHeight = 8;
242 
243 // |width| and |height| refer to the plane, not the frame, meaning any
244 // subsampling should be applied by the caller.
245 template <typename Pixel>
CopyImagePlane(const uint8_t * source_plane,ptrdiff_t source_stride,int width,int height,uint8_t * dest_plane,ptrdiff_t dest_stride)246 inline void CopyImagePlane(const uint8_t* source_plane, ptrdiff_t source_stride,
247                            int width, int height, uint8_t* dest_plane,
248                            ptrdiff_t dest_stride) {
249   // If it's the same buffer there's nothing to do.
250   if (source_plane == dest_plane) return;
251 
252   int y = 0;
253   do {
254     memcpy(dest_plane, source_plane, width * sizeof(Pixel));
255     source_plane += source_stride;
256     dest_plane += dest_stride;
257   } while (++y < height);
258 }
259 
260 }  // namespace
261 
262 template <int bitdepth>
FilmGrain(const FilmGrainParams & params,bool is_monochrome,bool color_matrix_is_identity,int subsampling_x,int subsampling_y,int width,int height,ThreadPool * thread_pool)263 FilmGrain<bitdepth>::FilmGrain(const FilmGrainParams& params,
264                                bool is_monochrome,
265                                bool color_matrix_is_identity, int subsampling_x,
266                                int subsampling_y, int width, int height,
267                                ThreadPool* thread_pool)
268     : params_(params),
269       is_monochrome_(is_monochrome),
270       color_matrix_is_identity_(color_matrix_is_identity),
271       subsampling_x_(subsampling_x),
272       subsampling_y_(subsampling_y),
273       width_(width),
274       height_(height),
275       template_uv_width_((subsampling_x != 0) ? kMinChromaWidth
276                                               : kMaxChromaWidth),
277       template_uv_height_((subsampling_y != 0) ? kMinChromaHeight
278                                                : kMaxChromaHeight),
279       thread_pool_(thread_pool) {}
280 
281 template <int bitdepth>
Init()282 bool FilmGrain<bitdepth>::Init() {
283   // Section 7.18.3.3. Generate grain process.
284   const dsp::Dsp& dsp = *dsp::GetDspTable(bitdepth);
285   // If params_.num_y_points is 0, luma_grain_ will never be read, so we don't
286   // need to generate it.
287   const bool use_luma = params_.num_y_points > 0;
288   if (use_luma) {
289     GenerateLumaGrain(params_, luma_grain_);
290     // If params_.auto_regression_coeff_lag is 0, the filter is the identity
291     // filter and therefore can be skipped.
292     if (params_.auto_regression_coeff_lag > 0) {
293       dsp.film_grain
294           .luma_auto_regression[params_.auto_regression_coeff_lag - 1](
295               params_, luma_grain_);
296     }
297   } else {
298     // Have AddressSanitizer warn if luma_grain_ is used.
299     ASAN_POISON_MEMORY_REGION(luma_grain_, sizeof(luma_grain_));
300   }
301   if (!is_monochrome_) {
302     GenerateChromaGrains(params_, template_uv_width_, template_uv_height_,
303                          u_grain_, v_grain_);
304     if (params_.auto_regression_coeff_lag > 0 || use_luma) {
305       dsp.film_grain.chroma_auto_regression[static_cast<int>(
306           use_luma)][params_.auto_regression_coeff_lag](
307           params_, luma_grain_, subsampling_x_, subsampling_y_, u_grain_,
308           v_grain_);
309     }
310   }
311 
312   // Section 7.18.3.4. Scaling lookup initialization process.
313 
314   // Initialize scaling_lut_y_. If params_.num_y_points > 0, scaling_lut_y_
315   // is used for the Y plane. If params_.chroma_scaling_from_luma is true,
316   // scaling_lut_u_ and scaling_lut_v_ are the same as scaling_lut_y_ and are
317   // set up as aliases. So we need to initialize scaling_lut_y_ under these
318   // two conditions.
319   //
320   // Note: Although it does not seem to make sense, there are test vectors
321   // with chroma_scaling_from_luma=true and params_.num_y_points=0.
322 #if LIBGAV1_MSAN
323   // Quiet film grain / md5 msan warnings.
324   memset(scaling_lut_y_, 0, sizeof(scaling_lut_y_));
325 #endif
326   if (use_luma || params_.chroma_scaling_from_luma) {
327     dsp.film_grain.initialize_scaling_lut(
328         params_.num_y_points, params_.point_y_value, params_.point_y_scaling,
329         scaling_lut_y_, kScalingLutLength);
330   } else {
331     ASAN_POISON_MEMORY_REGION(scaling_lut_y_, sizeof(scaling_lut_y_));
332   }
333   if (!is_monochrome_) {
334     if (params_.chroma_scaling_from_luma) {
335       scaling_lut_u_ = scaling_lut_y_;
336       scaling_lut_v_ = scaling_lut_y_;
337     } else if (params_.num_u_points > 0 || params_.num_v_points > 0) {
338       const size_t buffer_size =
339           kScalingLutLength * (static_cast<int>(params_.num_u_points > 0) +
340                                static_cast<int>(params_.num_v_points > 0));
341       scaling_lut_chroma_buffer_.reset(new (std::nothrow) int16_t[buffer_size]);
342       if (scaling_lut_chroma_buffer_ == nullptr) return false;
343 
344       int16_t* buffer = scaling_lut_chroma_buffer_.get();
345 #if LIBGAV1_MSAN
346       // Quiet film grain / md5 msan warnings.
347       memset(buffer, 0, buffer_size * 2);
348 #endif
349       if (params_.num_u_points > 0) {
350         scaling_lut_u_ = buffer;
351         dsp.film_grain.initialize_scaling_lut(
352             params_.num_u_points, params_.point_u_value,
353             params_.point_u_scaling, scaling_lut_u_, kScalingLutLength);
354         buffer += kScalingLutLength;
355       }
356       if (params_.num_v_points > 0) {
357         scaling_lut_v_ = buffer;
358         dsp.film_grain.initialize_scaling_lut(
359             params_.num_v_points, params_.point_v_value,
360             params_.point_v_scaling, scaling_lut_v_, kScalingLutLength);
361       }
362     }
363   }
364   return true;
365 }
366 
367 template <int bitdepth>
GenerateLumaGrain(const FilmGrainParams & params,GrainType * luma_grain)368 void FilmGrain<bitdepth>::GenerateLumaGrain(const FilmGrainParams& params,
369                                             GrainType* luma_grain) {
370   // If params.num_y_points is equal to 0, Section 7.18.3.3 specifies we set
371   // the luma_grain array to all zeros. But the Note at the end of Section
372   // 7.18.3.3 says luma_grain "will never be read in this case". So we don't
373   // call GenerateLumaGrain if params.num_y_points is equal to 0.
374   assert(params.num_y_points > 0);
375   const int shift = kBitdepth12 - bitdepth + params.grain_scale_shift;
376   uint16_t seed = params.grain_seed;
377   GrainType* luma_grain_row = luma_grain;
378   for (int y = 0; y < kLumaHeight; ++y) {
379     for (int x = 0; x < kLumaWidth; ++x) {
380       luma_grain_row[x] = RightShiftWithRounding(
381           kGaussianSequence[GetFilmGrainRandomNumber(11, &seed)], shift);
382     }
383     luma_grain_row += kLumaWidth;
384   }
385 }
386 
387 template <int bitdepth>
GenerateChromaGrains(const FilmGrainParams & params,int chroma_width,int chroma_height,GrainType * u_grain,GrainType * v_grain)388 void FilmGrain<bitdepth>::GenerateChromaGrains(const FilmGrainParams& params,
389                                                int chroma_width,
390                                                int chroma_height,
391                                                GrainType* u_grain,
392                                                GrainType* v_grain) {
393   const int shift = kBitdepth12 - bitdepth + params.grain_scale_shift;
394   if (params.num_u_points == 0 && !params.chroma_scaling_from_luma) {
395     memset(u_grain, 0, chroma_height * chroma_width * sizeof(*u_grain));
396   } else {
397     uint16_t seed = params.grain_seed ^ 0xb524;
398     GrainType* u_grain_row = u_grain;
399     assert(chroma_width > 0);
400     assert(chroma_height > 0);
401     int y = 0;
402     do {
403       int x = 0;
404       do {
405         u_grain_row[x] = RightShiftWithRounding(
406             kGaussianSequence[GetFilmGrainRandomNumber(11, &seed)], shift);
407       } while (++x < chroma_width);
408 
409       u_grain_row += chroma_width;
410     } while (++y < chroma_height);
411   }
412   if (params.num_v_points == 0 && !params.chroma_scaling_from_luma) {
413     memset(v_grain, 0, chroma_height * chroma_width * sizeof(*v_grain));
414   } else {
415     GrainType* v_grain_row = v_grain;
416     uint16_t seed = params.grain_seed ^ 0x49d8;
417     int y = 0;
418     do {
419       int x = 0;
420       do {
421         v_grain_row[x] = RightShiftWithRounding(
422             kGaussianSequence[GetFilmGrainRandomNumber(11, &seed)], shift);
423       } while (++x < chroma_width);
424 
425       v_grain_row += chroma_width;
426     } while (++y < chroma_height);
427   }
428 }
429 
430 template <int bitdepth>
AllocateNoiseStripes()431 bool FilmGrain<bitdepth>::AllocateNoiseStripes() {
432   const int half_height = DivideBy2(height_ + 1);
433   assert(half_height > 0);
434   // ceil(half_height / 16.0)
435   const int max_luma_num = DivideBy16(half_height + 15);
436   constexpr int kNoiseStripeHeight = 34;
437   size_t noise_buffer_size = kNoiseStripePadding;
438   if (params_.num_y_points > 0) {
439     noise_buffer_size += max_luma_num * kNoiseStripeHeight * width_;
440   }
441   if (!is_monochrome_) {
442     noise_buffer_size += 2 * max_luma_num *
443                          (kNoiseStripeHeight >> subsampling_y_) *
444                          SubsampledValue(width_, subsampling_x_);
445   }
446   noise_buffer_.reset(new (std::nothrow) GrainType[noise_buffer_size]);
447   if (noise_buffer_ == nullptr) return false;
448   GrainType* noise_buffer = noise_buffer_.get();
449   if (params_.num_y_points > 0) {
450     noise_stripes_[kPlaneY].Reset(max_luma_num, kNoiseStripeHeight * width_,
451                                   noise_buffer);
452     noise_buffer += max_luma_num * kNoiseStripeHeight * width_;
453   }
454   if (!is_monochrome_) {
455     noise_stripes_[kPlaneU].Reset(max_luma_num,
456                                   (kNoiseStripeHeight >> subsampling_y_) *
457                                       SubsampledValue(width_, subsampling_x_),
458                                   noise_buffer);
459     noise_buffer += max_luma_num * (kNoiseStripeHeight >> subsampling_y_) *
460                     SubsampledValue(width_, subsampling_x_);
461     noise_stripes_[kPlaneV].Reset(max_luma_num,
462                                   (kNoiseStripeHeight >> subsampling_y_) *
463                                       SubsampledValue(width_, subsampling_x_),
464                                   noise_buffer);
465   }
466   return true;
467 }
468 
469 template <int bitdepth>
AllocateNoiseImage()470 bool FilmGrain<bitdepth>::AllocateNoiseImage() {
471   // When LIBGAV1_MSAN is enabled, zero initialize to quiet optimized film grain
472   // msan warnings.
473   constexpr bool zero_initialize = LIBGAV1_MSAN == 1;
474   if (params_.num_y_points > 0 &&
475       !noise_image_[kPlaneY].Reset(height_, width_ + kNoiseImagePadding,
476                                    zero_initialize)) {
477     return false;
478   }
479   if (!is_monochrome_) {
480     if (!noise_image_[kPlaneU].Reset(
481             (height_ + subsampling_y_) >> subsampling_y_,
482             ((width_ + subsampling_x_) >> subsampling_x_) + kNoiseImagePadding,
483             zero_initialize)) {
484       return false;
485     }
486     if (!noise_image_[kPlaneV].Reset(
487             (height_ + subsampling_y_) >> subsampling_y_,
488             ((width_ + subsampling_x_) >> subsampling_x_) + kNoiseImagePadding,
489             zero_initialize)) {
490       return false;
491     }
492   }
493   return true;
494 }
495 
496 // Uses |overlap_flag| to skip rows that are covered by the overlap computation.
497 template <int bitdepth>
ConstructNoiseImage(const Array2DView<GrainType> * noise_stripes,int width,int height,int subsampling_x,int subsampling_y,int stripe_start_offset,Array2D<GrainType> * noise_image)498 void FilmGrain<bitdepth>::ConstructNoiseImage(
499     const Array2DView<GrainType>* noise_stripes, int width, int height,
500     int subsampling_x, int subsampling_y, int stripe_start_offset,
501     Array2D<GrainType>* noise_image) {
502   const int plane_width = (width + subsampling_x) >> subsampling_x;
503   const int plane_height = (height + subsampling_y) >> subsampling_y;
504   const int stripe_height = 32 >> subsampling_y;
505   const int stripe_mask = stripe_height - 1;
506   int y = 0;
507   // |luma_num| = y >> (5 - |subsampling_y|). Hence |luma_num| == 0 for all y up
508   // to either 16 or 32.
509   const GrainType* first_noise_stripe = (*noise_stripes)[0];
510   do {
511     memcpy((*noise_image)[y], first_noise_stripe + y * plane_width,
512            plane_width * sizeof(first_noise_stripe[0]));
513   } while (++y < std::min(stripe_height, plane_height));
514   // End special iterations for luma_num == 0.
515 
516   int luma_num = 1;
517   for (; y < (plane_height & ~stripe_mask); ++luma_num, y += stripe_height) {
518     const GrainType* noise_stripe = (*noise_stripes)[luma_num];
519     int i = stripe_start_offset;
520     do {
521       memcpy((*noise_image)[y + i], noise_stripe + i * plane_width,
522              plane_width * sizeof(noise_stripe[0]));
523     } while (++i < stripe_height);
524   }
525 
526   // If there is a partial stripe, copy any rows beyond the overlap rows.
527   const int remaining_height = plane_height - y;
528   if (remaining_height > stripe_start_offset) {
529     assert(luma_num < noise_stripes->rows());
530     const GrainType* noise_stripe = (*noise_stripes)[luma_num];
531     int i = stripe_start_offset;
532     do {
533       memcpy((*noise_image)[y + i], noise_stripe + i * plane_width,
534              plane_width * sizeof(noise_stripe[0]));
535     } while (++i < remaining_height);
536   }
537 }
538 
539 template <int bitdepth>
BlendNoiseChromaWorker(const dsp::Dsp & dsp,const Plane * planes,int num_planes,std::atomic<int> * job_counter,int min_value,int max_chroma,const uint8_t * source_plane_y,ptrdiff_t source_stride_y,const uint8_t * source_plane_u,const uint8_t * source_plane_v,ptrdiff_t source_stride_uv,uint8_t * dest_plane_u,uint8_t * dest_plane_v,ptrdiff_t dest_stride_uv)540 void FilmGrain<bitdepth>::BlendNoiseChromaWorker(
541     const dsp::Dsp& dsp, const Plane* planes, int num_planes,
542     std::atomic<int>* job_counter, int min_value, int max_chroma,
543     const uint8_t* source_plane_y, ptrdiff_t source_stride_y,
544     const uint8_t* source_plane_u, const uint8_t* source_plane_v,
545     ptrdiff_t source_stride_uv, uint8_t* dest_plane_u, uint8_t* dest_plane_v,
546     ptrdiff_t dest_stride_uv) {
547   assert(num_planes > 0);
548   const int full_jobs_per_plane = height_ / kFrameChunkHeight;
549   const int remainder_job_height = height_ & (kFrameChunkHeight - 1);
550   const int total_full_jobs = full_jobs_per_plane * num_planes;
551   // If the frame height is not a multiple of kFrameChunkHeight, one job with
552   // a smaller number of rows is necessary at the end of each plane.
553   const int total_jobs =
554       total_full_jobs + ((remainder_job_height == 0) ? 0 : num_planes);
555   int job_index;
556   // Each job corresponds to a slice of kFrameChunkHeight rows in the luma
557   // plane. dsp->blend_noise_chroma handles subsampling.
558   // This loop body handles a slice of one plane or the other, depending on
559   // which are active. That way, threads working on consecutive jobs will keep
560   // the same region of luma source in working memory.
561   while ((job_index = job_counter->fetch_add(1, std::memory_order_relaxed)) <
562          total_jobs) {
563     const Plane plane = planes[job_index % num_planes];
564     const int slice_index = job_index / num_planes;
565     const int start_height = slice_index * kFrameChunkHeight;
566     const int job_height = std::min(height_ - start_height, kFrameChunkHeight);
567 
568     const auto* source_cursor_y = reinterpret_cast<const Pixel*>(
569         source_plane_y + start_height * source_stride_y);
570     const int16_t* scaling_lut_uv;
571     const uint8_t* source_plane_uv;
572     uint8_t* dest_plane_uv;
573 
574     if (plane == kPlaneU) {
575       scaling_lut_uv = scaling_lut_u_;
576       source_plane_uv = source_plane_u;
577       dest_plane_uv = dest_plane_u;
578     } else {
579       assert(plane == kPlaneV);
580       scaling_lut_uv = scaling_lut_v_;
581       source_plane_uv = source_plane_v;
582       dest_plane_uv = dest_plane_v;
583     }
584     const auto* source_cursor_uv = reinterpret_cast<const Pixel*>(
585         source_plane_uv + (start_height >> subsampling_y_) * source_stride_uv);
586     auto* dest_cursor_uv = reinterpret_cast<Pixel*>(
587         dest_plane_uv + (start_height >> subsampling_y_) * dest_stride_uv);
588     dsp.film_grain.blend_noise_chroma[params_.chroma_scaling_from_luma](
589         plane, params_, noise_image_, min_value, max_chroma, width_, job_height,
590         start_height, subsampling_x_, subsampling_y_, scaling_lut_uv,
591         source_cursor_y, source_stride_y, source_cursor_uv, source_stride_uv,
592         dest_cursor_uv, dest_stride_uv);
593   }
594 }
595 
596 template <int bitdepth>
BlendNoiseLumaWorker(const dsp::Dsp & dsp,std::atomic<int> * job_counter,int min_value,int max_luma,const uint8_t * source_plane_y,ptrdiff_t source_stride_y,uint8_t * dest_plane_y,ptrdiff_t dest_stride_y)597 void FilmGrain<bitdepth>::BlendNoiseLumaWorker(
598     const dsp::Dsp& dsp, std::atomic<int>* job_counter, int min_value,
599     int max_luma, const uint8_t* source_plane_y, ptrdiff_t source_stride_y,
600     uint8_t* dest_plane_y, ptrdiff_t dest_stride_y) {
601   const int total_full_jobs = height_ / kFrameChunkHeight;
602   const int remainder_job_height = height_ & (kFrameChunkHeight - 1);
603   const int total_jobs =
604       total_full_jobs + static_cast<int>(remainder_job_height > 0);
605   int job_index;
606   // Each job is some number of rows in a plane.
607   while ((job_index = job_counter->fetch_add(1, std::memory_order_relaxed)) <
608          total_jobs) {
609     const int start_height = job_index * kFrameChunkHeight;
610     const int job_height = std::min(height_ - start_height, kFrameChunkHeight);
611 
612     const auto* source_cursor_y = reinterpret_cast<const Pixel*>(
613         source_plane_y + start_height * source_stride_y);
614     auto* dest_cursor_y =
615         reinterpret_cast<Pixel*>(dest_plane_y + start_height * dest_stride_y);
616     dsp.film_grain.blend_noise_luma(
617         noise_image_, min_value, max_luma, params_.chroma_scaling, width_,
618         job_height, start_height, scaling_lut_y_, source_cursor_y,
619         source_stride_y, dest_cursor_y, dest_stride_y);
620   }
621 }
622 
623 template <int bitdepth>
AddNoise(const uint8_t * source_plane_y,ptrdiff_t source_stride_y,const uint8_t * source_plane_u,const uint8_t * source_plane_v,ptrdiff_t source_stride_uv,uint8_t * dest_plane_y,ptrdiff_t dest_stride_y,uint8_t * dest_plane_u,uint8_t * dest_plane_v,ptrdiff_t dest_stride_uv)624 bool FilmGrain<bitdepth>::AddNoise(
625     const uint8_t* source_plane_y, ptrdiff_t source_stride_y,
626     const uint8_t* source_plane_u, const uint8_t* source_plane_v,
627     ptrdiff_t source_stride_uv, uint8_t* dest_plane_y, ptrdiff_t dest_stride_y,
628     uint8_t* dest_plane_u, uint8_t* dest_plane_v, ptrdiff_t dest_stride_uv) {
629   if (!Init()) {
630     LIBGAV1_DLOG(ERROR, "Init() failed.");
631     return false;
632   }
633   if (!AllocateNoiseStripes()) {
634     LIBGAV1_DLOG(ERROR, "AllocateNoiseStripes() failed.");
635     return false;
636   }
637 
638   const dsp::Dsp& dsp = *dsp::GetDspTable(bitdepth);
639   const bool use_luma = params_.num_y_points > 0;
640 
641   // Construct noise stripes.
642   if (use_luma) {
643     // The luma plane is never subsampled.
644     dsp.film_grain
645         .construct_noise_stripes[static_cast<int>(params_.overlap_flag)](
646             luma_grain_, params_.grain_seed, width_, height_,
647             /*subsampling_x=*/0, /*subsampling_y=*/0, &noise_stripes_[kPlaneY]);
648   }
649   if (!is_monochrome_) {
650     dsp.film_grain
651         .construct_noise_stripes[static_cast<int>(params_.overlap_flag)](
652             u_grain_, params_.grain_seed, width_, height_, subsampling_x_,
653             subsampling_y_, &noise_stripes_[kPlaneU]);
654     dsp.film_grain
655         .construct_noise_stripes[static_cast<int>(params_.overlap_flag)](
656             v_grain_, params_.grain_seed, width_, height_, subsampling_x_,
657             subsampling_y_, &noise_stripes_[kPlaneV]);
658   }
659 
660   if (!AllocateNoiseImage()) {
661     LIBGAV1_DLOG(ERROR, "AllocateNoiseImage() failed.");
662     return false;
663   }
664 
665   // Construct noise image.
666   if (use_luma) {
667     ConstructNoiseImage(
668         &noise_stripes_[kPlaneY], width_, height_, /*subsampling_x=*/0,
669         /*subsampling_y=*/0, static_cast<int>(params_.overlap_flag) << 1,
670         &noise_image_[kPlaneY]);
671     if (params_.overlap_flag) {
672       dsp.film_grain.construct_noise_image_overlap(
673           &noise_stripes_[kPlaneY], width_, height_, /*subsampling_x=*/0,
674           /*subsampling_y=*/0, &noise_image_[kPlaneY]);
675     }
676   }
677   if (!is_monochrome_) {
678     ConstructNoiseImage(&noise_stripes_[kPlaneU], width_, height_,
679                         subsampling_x_, subsampling_y_,
680                         static_cast<int>(params_.overlap_flag)
681                             << (1 - subsampling_y_),
682                         &noise_image_[kPlaneU]);
683     ConstructNoiseImage(&noise_stripes_[kPlaneV], width_, height_,
684                         subsampling_x_, subsampling_y_,
685                         static_cast<int>(params_.overlap_flag)
686                             << (1 - subsampling_y_),
687                         &noise_image_[kPlaneV]);
688     if (params_.overlap_flag) {
689       dsp.film_grain.construct_noise_image_overlap(
690           &noise_stripes_[kPlaneU], width_, height_, subsampling_x_,
691           subsampling_y_, &noise_image_[kPlaneU]);
692       dsp.film_grain.construct_noise_image_overlap(
693           &noise_stripes_[kPlaneV], width_, height_, subsampling_x_,
694           subsampling_y_, &noise_image_[kPlaneV]);
695     }
696   }
697 
698   // Blend noise image.
699   int min_value;
700   int max_luma;
701   int max_chroma;
702   if (params_.clip_to_restricted_range) {
703     min_value = 16 << (bitdepth - kBitdepth8);
704     max_luma = 235 << (bitdepth - kBitdepth8);
705     if (color_matrix_is_identity_) {
706       max_chroma = max_luma;
707     } else {
708       max_chroma = 240 << (bitdepth - kBitdepth8);
709     }
710   } else {
711     min_value = 0;
712     max_luma = (256 << (bitdepth - kBitdepth8)) - 1;
713     max_chroma = max_luma;
714   }
715 
716   // Handle all chroma planes first because luma source may be altered in place.
717   if (!is_monochrome_) {
718     // This is done in a strange way but Vector can't be passed by copy to the
719     // lambda capture that spawns the thread.
720     Plane planes_to_blend[2];
721     int num_planes = 0;
722     if (params_.chroma_scaling_from_luma) {
723       // Both noise planes are computed from the luma scaling lookup table.
724       planes_to_blend[num_planes++] = kPlaneU;
725       planes_to_blend[num_planes++] = kPlaneV;
726     } else {
727       const int height_uv = SubsampledValue(height_, subsampling_y_);
728       const int width_uv = SubsampledValue(width_, subsampling_x_);
729 
730       // Noise is applied according to a lookup table defined by pieceiwse
731       // linear "points." If the lookup table is empty, that corresponds to
732       // outputting zero noise.
733       if (params_.num_u_points == 0) {
734         CopyImagePlane<Pixel>(source_plane_u, source_stride_uv, width_uv,
735                               height_uv, dest_plane_u, dest_stride_uv);
736       } else {
737         planes_to_blend[num_planes++] = kPlaneU;
738       }
739       if (params_.num_v_points == 0) {
740         CopyImagePlane<Pixel>(source_plane_v, source_stride_uv, width_uv,
741                               height_uv, dest_plane_v, dest_stride_uv);
742       } else {
743         planes_to_blend[num_planes++] = kPlaneV;
744       }
745     }
746     if (thread_pool_ != nullptr && num_planes > 0) {
747       const int num_workers = thread_pool_->num_threads();
748       BlockingCounter pending_workers(num_workers);
749       std::atomic<int> job_counter(0);
750       for (int i = 0; i < num_workers; ++i) {
751         thread_pool_->Schedule([this, dsp, &pending_workers, &planes_to_blend,
752                                 num_planes, &job_counter, min_value, max_chroma,
753                                 source_plane_y, source_stride_y, source_plane_u,
754                                 source_plane_v, source_stride_uv, dest_plane_u,
755                                 dest_plane_v, dest_stride_uv]() {
756           BlendNoiseChromaWorker(dsp, planes_to_blend, num_planes, &job_counter,
757                                  min_value, max_chroma, source_plane_y,
758                                  source_stride_y, source_plane_u,
759                                  source_plane_v, source_stride_uv, dest_plane_u,
760                                  dest_plane_v, dest_stride_uv);
761           pending_workers.Decrement();
762         });
763       }
764       BlendNoiseChromaWorker(
765           dsp, planes_to_blend, num_planes, &job_counter, min_value, max_chroma,
766           source_plane_y, source_stride_y, source_plane_u, source_plane_v,
767           source_stride_uv, dest_plane_u, dest_plane_v, dest_stride_uv);
768 
769       pending_workers.Wait();
770     } else {
771       // Single threaded.
772       if (params_.num_u_points > 0 || params_.chroma_scaling_from_luma) {
773         dsp.film_grain.blend_noise_chroma[params_.chroma_scaling_from_luma](
774             kPlaneU, params_, noise_image_, min_value, max_chroma, width_,
775             height_, /*start_height=*/0, subsampling_x_, subsampling_y_,
776             scaling_lut_u_, source_plane_y, source_stride_y, source_plane_u,
777             source_stride_uv, dest_plane_u, dest_stride_uv);
778       }
779       if (params_.num_v_points > 0 || params_.chroma_scaling_from_luma) {
780         dsp.film_grain.blend_noise_chroma[params_.chroma_scaling_from_luma](
781             kPlaneV, params_, noise_image_, min_value, max_chroma, width_,
782             height_, /*start_height=*/0, subsampling_x_, subsampling_y_,
783             scaling_lut_v_, source_plane_y, source_stride_y, source_plane_v,
784             source_stride_uv, dest_plane_v, dest_stride_uv);
785       }
786     }
787   }
788   if (use_luma) {
789     if (thread_pool_ != nullptr) {
790       const int num_workers = thread_pool_->num_threads();
791       BlockingCounter pending_workers(num_workers);
792       std::atomic<int> job_counter(0);
793       for (int i = 0; i < num_workers; ++i) {
794         thread_pool_->Schedule(
795             [this, dsp, &pending_workers, &job_counter, min_value, max_luma,
796              source_plane_y, source_stride_y, dest_plane_y, dest_stride_y]() {
797               BlendNoiseLumaWorker(dsp, &job_counter, min_value, max_luma,
798                                    source_plane_y, source_stride_y,
799                                    dest_plane_y, dest_stride_y);
800               pending_workers.Decrement();
801             });
802       }
803 
804       BlendNoiseLumaWorker(dsp, &job_counter, min_value, max_luma,
805                            source_plane_y, source_stride_y, dest_plane_y,
806                            dest_stride_y);
807       pending_workers.Wait();
808     } else {
809       dsp.film_grain.blend_noise_luma(
810           noise_image_, min_value, max_luma, params_.chroma_scaling, width_,
811           height_, /*start_height=*/0, scaling_lut_y_, source_plane_y,
812           source_stride_y, dest_plane_y, dest_stride_y);
813     }
814   } else {
815     CopyImagePlane<Pixel>(source_plane_y, source_stride_y, width_, height_,
816                           dest_plane_y, dest_stride_y);
817   }
818 
819   return true;
820 }
821 
822 // Explicit instantiations.
823 template class FilmGrain<kBitdepth8>;
824 #if LIBGAV1_MAX_BITDEPTH >= 10
825 template class FilmGrain<kBitdepth10>;
826 #endif
827 #if LIBGAV1_MAX_BITDEPTH == 12
828 template class FilmGrain<kBitdepth12>;
829 #endif
830 
831 }  // namespace libgav1
832