1 // Copyright 2019 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/dsp/film_grain.h"
16
17 #include <algorithm>
18 #include <cassert>
19 #include <cstddef>
20 #include <cstdint>
21 #include <cstring>
22
23 #include "src/dsp/constants.h"
24 #include "src/dsp/dsp.h"
25 #include "src/dsp/film_grain_common.h"
26 #include "src/utils/array_2d.h"
27 #include "src/utils/common.h"
28 #include "src/utils/compiler_attributes.h"
29 #include "src/utils/constants.h"
30 #include "src/utils/memory.h"
31 #include "src/utils/types.h"
32
33 namespace libgav1 {
34 namespace dsp {
35 namespace film_grain {
36 namespace {
37
38 template <int bitdepth>
InitializeScalingLookupTable_C(int num_points,const uint8_t point_value[],const uint8_t point_scaling[],int16_t * scaling_lut,const int scaling_lut_length)39 void InitializeScalingLookupTable_C(int num_points, const uint8_t point_value[],
40 const uint8_t point_scaling[],
41 int16_t* scaling_lut,
42 const int scaling_lut_length) {
43 if (num_points == 0) {
44 memset(scaling_lut, 0, sizeof(scaling_lut[0]) * scaling_lut_length);
45 return;
46 }
47 constexpr int index_shift = (bitdepth == kBitdepth10) ? 2 : 0;
48 static_assert(sizeof(scaling_lut[0]) == 2, "");
49 Memset(scaling_lut, point_scaling[0],
50 std::max(static_cast<int>(point_value[0]), 1) << index_shift);
51 for (int i = 0; i < num_points - 1; ++i) {
52 const int delta_y = point_scaling[i + 1] - point_scaling[i];
53 const int delta_x = point_value[i + 1] - point_value[i];
54 const int delta = delta_y * ((65536 + (delta_x >> 1)) / delta_x);
55 for (int x = 0; x < delta_x; ++x) {
56 const int v = point_scaling[i] + ((x * delta + 32768) >> 16);
57 assert(v >= 0 && v <= UINT8_MAX);
58 const int lut_index = (point_value[i] + x) << index_shift;
59 scaling_lut[lut_index] = v;
60 }
61 }
62 const int16_t last_point_value = point_value[num_points - 1];
63 const int x_base = last_point_value << index_shift;
64 Memset(&scaling_lut[x_base], point_scaling[num_points - 1],
65 scaling_lut_length - x_base);
66 // Fill in the gaps.
67 if (bitdepth == kBitdepth10) {
68 for (int x = 4; x < x_base + 4; x += 4) {
69 const int start = scaling_lut[x - 4];
70 const int end = scaling_lut[x];
71 const int delta = end - start;
72 scaling_lut[x - 3] = start + RightShiftWithRounding(delta, 2);
73 scaling_lut[x - 2] = start + RightShiftWithRounding(2 * delta, 2);
74 scaling_lut[x - 1] = start + RightShiftWithRounding(3 * delta, 2);
75 }
76 }
77 }
78
79 // Section 7.18.3.5.
80 template <int bitdepth>
ScaleLut(const int16_t * scaling_lut,int index)81 int ScaleLut(const int16_t* scaling_lut, int index) {
82 if (bitdepth <= kBitdepth10) {
83 assert(index < kScalingLookupTableSize << (bitdepth - 2));
84 return scaling_lut[index];
85 }
86 // Performs a piecewise linear interpolation into the scaling table.
87 const int shift = bitdepth - kBitdepth8;
88 const int quotient = index >> shift;
89 const int remainder = index - (quotient << shift);
90 assert(quotient + 1 < kScalingLookupTableSize);
91 const int start = scaling_lut[quotient];
92 const int end = scaling_lut[quotient + 1];
93 return start + RightShiftWithRounding((end - start) * remainder, shift);
94 }
95
96 // Applies an auto-regressive filter to the white noise in luma_grain.
97 template <int bitdepth, typename GrainType>
ApplyAutoRegressiveFilterToLumaGrain_C(const FilmGrainParams & params,void * luma_grain_buffer)98 void ApplyAutoRegressiveFilterToLumaGrain_C(const FilmGrainParams& params,
99 void* luma_grain_buffer) {
100 auto* luma_grain = static_cast<GrainType*>(luma_grain_buffer);
101 const int grain_min = GetGrainMin<bitdepth>();
102 const int grain_max = GetGrainMax<bitdepth>();
103 const int auto_regression_coeff_lag = params.auto_regression_coeff_lag;
104 assert(auto_regression_coeff_lag > 0 && auto_regression_coeff_lag <= 3);
105 // A pictorial representation of the auto-regressive filter for various values
106 // of auto_regression_coeff_lag. The letter 'O' represents the current sample.
107 // (The filter always operates on the current sample with filter
108 // coefficient 1.) The letters 'X' represent the neighboring samples that the
109 // filter operates on.
110 //
111 // auto_regression_coeff_lag == 3:
112 // X X X X X X X
113 // X X X X X X X
114 // X X X X X X X
115 // X X X O
116 // auto_regression_coeff_lag == 2:
117 // X X X X X
118 // X X X X X
119 // X X O
120 // auto_regression_coeff_lag == 1:
121 // X X X
122 // X O
123 // auto_regression_coeff_lag == 0:
124 // O
125 //
126 // Note that if auto_regression_coeff_lag is 0, the filter is the identity
127 // filter and therefore can be skipped. This implementation assumes it is not
128 // called in that case.
129 const int shift = params.auto_regression_shift;
130 for (int y = kAutoRegressionBorder; y < kLumaHeight; ++y) {
131 for (int x = kAutoRegressionBorder; x < kLumaWidth - kAutoRegressionBorder;
132 ++x) {
133 int sum = 0;
134 int pos = 0;
135 int delta_row = -auto_regression_coeff_lag;
136 // The last iteration (delta_row == 0) is shorter and is handled
137 // separately.
138 do {
139 int delta_column = -auto_regression_coeff_lag;
140 do {
141 const int coeff = params.auto_regression_coeff_y[pos];
142 sum += luma_grain[(y + delta_row) * kLumaWidth + (x + delta_column)] *
143 coeff;
144 ++pos;
145 } while (++delta_column <= auto_regression_coeff_lag);
146 } while (++delta_row < 0);
147 // Last iteration: delta_row == 0.
148 {
149 int delta_column = -auto_regression_coeff_lag;
150 do {
151 const int coeff = params.auto_regression_coeff_y[pos];
152 sum += luma_grain[y * kLumaWidth + (x + delta_column)] * coeff;
153 ++pos;
154 } while (++delta_column < 0);
155 }
156 luma_grain[y * kLumaWidth + x] = Clip3(
157 luma_grain[y * kLumaWidth + x] + RightShiftWithRounding(sum, shift),
158 grain_min, grain_max);
159 }
160 }
161 }
162
163 template <int bitdepth, typename GrainType, int auto_regression_coeff_lag,
164 bool use_luma>
ApplyAutoRegressiveFilterToChromaGrains_C(const FilmGrainParams & params,const void * LIBGAV1_RESTRICT luma_grain_buffer,int subsampling_x,int subsampling_y,void * LIBGAV1_RESTRICT u_grain_buffer,void * LIBGAV1_RESTRICT v_grain_buffer)165 void ApplyAutoRegressiveFilterToChromaGrains_C(
166 const FilmGrainParams& params,
167 const void* LIBGAV1_RESTRICT luma_grain_buffer, int subsampling_x,
168 int subsampling_y, void* LIBGAV1_RESTRICT u_grain_buffer,
169 void* LIBGAV1_RESTRICT v_grain_buffer) {
170 static_assert(
171 auto_regression_coeff_lag >= 0 && auto_regression_coeff_lag <= 3,
172 "Unsupported autoregression lag for chroma.");
173 const auto* luma_grain = static_cast<const GrainType*>(luma_grain_buffer);
174 const int grain_min = GetGrainMin<bitdepth>();
175 const int grain_max = GetGrainMax<bitdepth>();
176 auto* u_grain = static_cast<GrainType*>(u_grain_buffer);
177 auto* v_grain = static_cast<GrainType*>(v_grain_buffer);
178 const int shift = params.auto_regression_shift;
179 const int chroma_height =
180 (subsampling_y == 0) ? kMaxChromaHeight : kMinChromaHeight;
181 const int chroma_width =
182 (subsampling_x == 0) ? kMaxChromaWidth : kMinChromaWidth;
183 for (int y = kAutoRegressionBorder; y < chroma_height; ++y) {
184 const int luma_y =
185 ((y - kAutoRegressionBorder) << subsampling_y) + kAutoRegressionBorder;
186 for (int x = kAutoRegressionBorder;
187 x < chroma_width - kAutoRegressionBorder; ++x) {
188 int sum_u = 0;
189 int sum_v = 0;
190 int pos = 0;
191 int delta_row = -auto_regression_coeff_lag;
192 do {
193 int delta_column = -auto_regression_coeff_lag;
194 do {
195 if (delta_row == 0 && delta_column == 0) {
196 break;
197 }
198 const int coeff_u = params.auto_regression_coeff_u[pos];
199 const int coeff_v = params.auto_regression_coeff_v[pos];
200 sum_u +=
201 u_grain[(y + delta_row) * chroma_width + (x + delta_column)] *
202 coeff_u;
203 sum_v +=
204 v_grain[(y + delta_row) * chroma_width + (x + delta_column)] *
205 coeff_v;
206 ++pos;
207 } while (++delta_column <= auto_regression_coeff_lag);
208 } while (++delta_row <= 0);
209 if (use_luma) {
210 int luma = 0;
211 const int luma_x = ((x - kAutoRegressionBorder) << subsampling_x) +
212 kAutoRegressionBorder;
213 int i = 0;
214 do {
215 int j = 0;
216 do {
217 luma += luma_grain[(luma_y + i) * kLumaWidth + (luma_x + j)];
218 } while (++j <= subsampling_x);
219 } while (++i <= subsampling_y);
220 luma = SubsampledValue(luma, subsampling_x + subsampling_y);
221 const int coeff_u = params.auto_regression_coeff_u[pos];
222 const int coeff_v = params.auto_regression_coeff_v[pos];
223 sum_u += luma * coeff_u;
224 sum_v += luma * coeff_v;
225 }
226 u_grain[y * chroma_width + x] = Clip3(
227 u_grain[y * chroma_width + x] + RightShiftWithRounding(sum_u, shift),
228 grain_min, grain_max);
229 v_grain[y * chroma_width + x] = Clip3(
230 v_grain[y * chroma_width + x] + RightShiftWithRounding(sum_v, shift),
231 grain_min, grain_max);
232 }
233 }
234 }
235
236 // This implementation is for the condition overlap_flag == false.
237 template <int bitdepth, typename GrainType>
ConstructNoiseStripes_C(const void * LIBGAV1_RESTRICT grain_buffer,int grain_seed,int width,int height,int subsampling_x,int subsampling_y,void * LIBGAV1_RESTRICT noise_stripes_buffer)238 void ConstructNoiseStripes_C(const void* LIBGAV1_RESTRICT grain_buffer,
239 int grain_seed, int width, int height,
240 int subsampling_x, int subsampling_y,
241 void* LIBGAV1_RESTRICT noise_stripes_buffer) {
242 auto* noise_stripes =
243 static_cast<Array2DView<GrainType>*>(noise_stripes_buffer);
244 const auto* grain = static_cast<const GrainType*>(grain_buffer);
245 const int half_width = DivideBy2(width + 1);
246 const int half_height = DivideBy2(height + 1);
247 assert(half_width > 0);
248 assert(half_height > 0);
249 static_assert(kLumaWidth == kMaxChromaWidth,
250 "kLumaWidth width should be equal to kMaxChromaWidth");
251 const int grain_width =
252 (subsampling_x == 0) ? kMaxChromaWidth : kMinChromaWidth;
253 const int plane_width = (width + subsampling_x) >> subsampling_x;
254 constexpr int kNoiseStripeHeight = 34;
255 int luma_num = 0;
256 int y = 0;
257 do {
258 GrainType* const noise_stripe = (*noise_stripes)[luma_num];
259 uint16_t seed = grain_seed;
260 seed ^= ((luma_num * 37 + 178) & 255) << 8;
261 seed ^= ((luma_num * 173 + 105) & 255);
262 int x = 0;
263 do {
264 const int rand = GetFilmGrainRandomNumber(8, &seed);
265 const int offset_x = rand >> 4;
266 const int offset_y = rand & 15;
267 const int plane_offset_x =
268 (subsampling_x != 0) ? 6 + offset_x : 9 + offset_x * 2;
269 const int plane_offset_y =
270 (subsampling_y != 0) ? 6 + offset_y : 9 + offset_y * 2;
271 int i = 0;
272 do {
273 // Section 7.18.3.5 says:
274 // noiseStripe[ lumaNum ][ 0 ] is 34 samples high and w samples
275 // wide (a few additional samples across are actually written to
276 // the array, but these are never read) ...
277 //
278 // Note: The warning in the parentheses also applies to
279 // noiseStripe[ lumaNum ][ 1 ] and noiseStripe[ lumaNum ][ 2 ].
280 //
281 // Writes beyond the width of each row could happen below. To
282 // prevent those writes, we clip the number of pixels to copy against
283 // the remaining width.
284 const int copy_size =
285 std::min(kNoiseStripeHeight >> subsampling_x,
286 plane_width - (x << (1 - subsampling_x)));
287 memcpy(&noise_stripe[i * plane_width + (x << (1 - subsampling_x))],
288 &grain[(plane_offset_y + i) * grain_width + plane_offset_x],
289 copy_size * sizeof(noise_stripe[0]));
290 } while (++i < (kNoiseStripeHeight >> subsampling_y));
291 x += 16;
292 } while (x < half_width);
293
294 ++luma_num;
295 y += 16;
296 } while (y < half_height);
297 }
298
299 // This implementation is for the condition overlap_flag == true.
300 template <int bitdepth, typename GrainType>
ConstructNoiseStripesWithOverlap_C(const void * LIBGAV1_RESTRICT grain_buffer,int grain_seed,int width,int height,int subsampling_x,int subsampling_y,void * LIBGAV1_RESTRICT noise_stripes_buffer)301 void ConstructNoiseStripesWithOverlap_C(
302 const void* LIBGAV1_RESTRICT grain_buffer, int grain_seed, int width,
303 int height, int subsampling_x, int subsampling_y,
304 void* LIBGAV1_RESTRICT noise_stripes_buffer) {
305 auto* noise_stripes =
306 static_cast<Array2DView<GrainType>*>(noise_stripes_buffer);
307 const auto* grain = static_cast<const GrainType*>(grain_buffer);
308 const int half_width = DivideBy2(width + 1);
309 const int half_height = DivideBy2(height + 1);
310 assert(half_width > 0);
311 assert(half_height > 0);
312 static_assert(kLumaWidth == kMaxChromaWidth,
313 "kLumaWidth width should be equal to kMaxChromaWidth");
314 const int grain_width =
315 (subsampling_x == 0) ? kMaxChromaWidth : kMinChromaWidth;
316 const int plane_width = (width + subsampling_x) >> subsampling_x;
317 constexpr int kNoiseStripeHeight = 34;
318 int luma_num = 0;
319 int y = 0;
320 do {
321 GrainType* const noise_stripe = (*noise_stripes)[luma_num];
322 uint16_t seed = grain_seed;
323 seed ^= ((luma_num * 37 + 178) & 255) << 8;
324 seed ^= ((luma_num * 173 + 105) & 255);
325 // Begin special iteration for x == 0.
326 const int rand = GetFilmGrainRandomNumber(8, &seed);
327 const int offset_x = rand >> 4;
328 const int offset_y = rand & 15;
329 const int plane_offset_x =
330 (subsampling_x != 0) ? 6 + offset_x : 9 + offset_x * 2;
331 const int plane_offset_y =
332 (subsampling_y != 0) ? 6 + offset_y : 9 + offset_y * 2;
333 // The overlap computation only occurs when x > 0, so it is omitted here.
334 int i = 0;
335 do {
336 const int copy_size =
337 std::min(kNoiseStripeHeight >> subsampling_x, plane_width);
338 memcpy(&noise_stripe[i * plane_width],
339 &grain[(plane_offset_y + i) * grain_width + plane_offset_x],
340 copy_size * sizeof(noise_stripe[0]));
341 } while (++i < (kNoiseStripeHeight >> subsampling_y));
342 // End special iteration for x == 0.
343 for (int x = 16; x < half_width; x += 16) {
344 const int rand = GetFilmGrainRandomNumber(8, &seed);
345 const int offset_x = rand >> 4;
346 const int offset_y = rand & 15;
347 const int plane_offset_x =
348 (subsampling_x != 0) ? 6 + offset_x : 9 + offset_x * 2;
349 const int plane_offset_y =
350 (subsampling_y != 0) ? 6 + offset_y : 9 + offset_y * 2;
351 int i = 0;
352 do {
353 int j = 0;
354 int grain_sample =
355 grain[(plane_offset_y + i) * grain_width + plane_offset_x];
356 // The first pixel(s) of each segment of the noise_stripe are subject to
357 // the "overlap" computation.
358 if (subsampling_x == 0) {
359 // Corresponds to the line in the spec:
360 // if (j < 2 && x > 0)
361 // j = 0
362 int old = noise_stripe[i * plane_width + x * 2];
363 grain_sample = old * 27 + grain_sample * 17;
364 grain_sample =
365 Clip3(RightShiftWithRounding(grain_sample, 5),
366 GetGrainMin<bitdepth>(), GetGrainMax<bitdepth>());
367 noise_stripe[i * plane_width + x * 2] = grain_sample;
368
369 // This check prevents overwriting for the iteration j = 1. The
370 // continue applies to the i-loop.
371 if (x * 2 + 1 >= plane_width) continue;
372 // j = 1
373 grain_sample =
374 grain[(plane_offset_y + i) * grain_width + plane_offset_x + 1];
375 old = noise_stripe[i * plane_width + x * 2 + 1];
376 grain_sample = old * 17 + grain_sample * 27;
377 grain_sample =
378 Clip3(RightShiftWithRounding(grain_sample, 5),
379 GetGrainMin<bitdepth>(), GetGrainMax<bitdepth>());
380 noise_stripe[i * plane_width + x * 2 + 1] = grain_sample;
381 j = 2;
382 } else {
383 // Corresponds to the line in the spec:
384 // if (j == 0 && x > 0)
385 const int old = noise_stripe[i * plane_width + x];
386 grain_sample = old * 23 + grain_sample * 22;
387 grain_sample =
388 Clip3(RightShiftWithRounding(grain_sample, 5),
389 GetGrainMin<bitdepth>(), GetGrainMax<bitdepth>());
390 noise_stripe[i * plane_width + x] = grain_sample;
391 j = 1;
392 }
393 // The following covers the rest of the loop over j as described in the
394 // spec.
395 //
396 // Section 7.18.3.5 says:
397 // noiseStripe[ lumaNum ][ 0 ] is 34 samples high and w samples
398 // wide (a few additional samples across are actually written to
399 // the array, but these are never read) ...
400 //
401 // Note: The warning in the parentheses also applies to
402 // noiseStripe[ lumaNum ][ 1 ] and noiseStripe[ lumaNum ][ 2 ].
403 //
404 // Writes beyond the width of each row could happen below. To
405 // prevent those writes, we clip the number of pixels to copy against
406 // the remaining width.
407 const int copy_size =
408 std::min(kNoiseStripeHeight >> subsampling_x,
409 plane_width - (x << (1 - subsampling_x))) -
410 j;
411 memcpy(&noise_stripe[i * plane_width + (x << (1 - subsampling_x)) + j],
412 &grain[(plane_offset_y + i) * grain_width + plane_offset_x + j],
413 copy_size * sizeof(noise_stripe[0]));
414 } while (++i < (kNoiseStripeHeight >> subsampling_y));
415 }
416
417 ++luma_num;
418 y += 16;
419 } while (y < half_height);
420 }
421
422 template <int bitdepth, typename GrainType>
WriteOverlapLine_C(const GrainType * LIBGAV1_RESTRICT noise_stripe_row,const GrainType * LIBGAV1_RESTRICT noise_stripe_row_prev,int plane_width,int grain_coeff,int old_coeff,GrainType * LIBGAV1_RESTRICT noise_image_row)423 inline void WriteOverlapLine_C(
424 const GrainType* LIBGAV1_RESTRICT noise_stripe_row,
425 const GrainType* LIBGAV1_RESTRICT noise_stripe_row_prev, int plane_width,
426 int grain_coeff, int old_coeff,
427 GrainType* LIBGAV1_RESTRICT noise_image_row) {
428 int x = 0;
429 do {
430 int grain = noise_stripe_row[x];
431 const int old = noise_stripe_row_prev[x];
432 grain = old * old_coeff + grain * grain_coeff;
433 grain = Clip3(RightShiftWithRounding(grain, 5), GetGrainMin<bitdepth>(),
434 GetGrainMax<bitdepth>());
435 noise_image_row[x] = grain;
436 } while (++x < plane_width);
437 }
438
439 template <int bitdepth, typename GrainType>
ConstructNoiseImageOverlap_C(const void * LIBGAV1_RESTRICT noise_stripes_buffer,int width,int height,int subsampling_x,int subsampling_y,void * LIBGAV1_RESTRICT noise_image_buffer)440 void ConstructNoiseImageOverlap_C(
441 const void* LIBGAV1_RESTRICT noise_stripes_buffer, int width, int height,
442 int subsampling_x, int subsampling_y,
443 void* LIBGAV1_RESTRICT noise_image_buffer) {
444 const auto* noise_stripes =
445 static_cast<const Array2DView<GrainType>*>(noise_stripes_buffer);
446 auto* noise_image = static_cast<Array2D<GrainType>*>(noise_image_buffer);
447 const int plane_width = (width + subsampling_x) >> subsampling_x;
448 const int plane_height = (height + subsampling_y) >> subsampling_y;
449 const int stripe_height = 32 >> subsampling_y;
450 const int stripe_mask = stripe_height - 1;
451 int y = stripe_height;
452 int luma_num = 1;
453 if (subsampling_y == 0) {
454 // Begin complete stripes section. This is when we are guaranteed to have
455 // two overlap rows in each stripe.
456 for (; y < (plane_height & ~stripe_mask); ++luma_num, y += stripe_height) {
457 const GrainType* noise_stripe = (*noise_stripes)[luma_num];
458 const GrainType* noise_stripe_prev = (*noise_stripes)[luma_num - 1];
459 // First overlap row.
460 WriteOverlapLine_C<bitdepth>(noise_stripe,
461 &noise_stripe_prev[32 * plane_width],
462 plane_width, 17, 27, (*noise_image)[y]);
463 // Second overlap row.
464 WriteOverlapLine_C<bitdepth>(&noise_stripe[plane_width],
465 &noise_stripe_prev[(32 + 1) * plane_width],
466 plane_width, 27, 17, (*noise_image)[y + 1]);
467 }
468 // End complete stripes section.
469
470 const int remaining_height = plane_height - y;
471 // Either one partial stripe remains (remaining_height > 0),
472 // OR image is less than one stripe high (remaining_height < 0),
473 // OR all stripes are completed (remaining_height == 0).
474 if (remaining_height <= 0) {
475 return;
476 }
477 const GrainType* noise_stripe = (*noise_stripes)[luma_num];
478 const GrainType* noise_stripe_prev = (*noise_stripes)[luma_num - 1];
479 WriteOverlapLine_C<bitdepth>(noise_stripe,
480 &noise_stripe_prev[32 * plane_width],
481 plane_width, 17, 27, (*noise_image)[y]);
482
483 // Check if second overlap row is in the image.
484 if (remaining_height > 1) {
485 WriteOverlapLine_C<bitdepth>(&noise_stripe[plane_width],
486 &noise_stripe_prev[(32 + 1) * plane_width],
487 plane_width, 27, 17, (*noise_image)[y + 1]);
488 }
489 } else { // |subsampling_y| == 1
490 // No special checks needed for partial stripes, because if one exists, the
491 // first and only overlap row is guaranteed to exist.
492 for (; y < plane_height; ++luma_num, y += stripe_height) {
493 const GrainType* noise_stripe = (*noise_stripes)[luma_num];
494 const GrainType* noise_stripe_prev = (*noise_stripes)[luma_num - 1];
495 WriteOverlapLine_C<bitdepth>(noise_stripe,
496 &noise_stripe_prev[16 * plane_width],
497 plane_width, 22, 23, (*noise_image)[y]);
498 }
499 }
500 }
501
502 template <int bitdepth, typename GrainType, typename Pixel>
BlendNoiseWithImageLuma_C(const void * LIBGAV1_RESTRICT noise_image_ptr,int min_value,int max_luma,int scaling_shift,int width,int height,int start_height,const int16_t * scaling_lut_y,const void * source_plane_y,ptrdiff_t source_stride_y,void * dest_plane_y,ptrdiff_t dest_stride_y)503 void BlendNoiseWithImageLuma_C(const void* LIBGAV1_RESTRICT noise_image_ptr,
504 int min_value, int max_luma, int scaling_shift,
505 int width, int height, int start_height,
506 const int16_t* scaling_lut_y,
507 const void* source_plane_y,
508 ptrdiff_t source_stride_y, void* dest_plane_y,
509 ptrdiff_t dest_stride_y) {
510 const auto* noise_image =
511 static_cast<const Array2D<GrainType>*>(noise_image_ptr);
512 const auto* in_y = static_cast<const Pixel*>(source_plane_y);
513 source_stride_y /= sizeof(Pixel);
514 auto* out_y = static_cast<Pixel*>(dest_plane_y);
515 dest_stride_y /= sizeof(Pixel);
516
517 int y = 0;
518 do {
519 int x = 0;
520 do {
521 const int orig = in_y[y * source_stride_y + x];
522 int noise = noise_image[kPlaneY][y + start_height][x];
523 noise = RightShiftWithRounding(
524 ScaleLut<bitdepth>(scaling_lut_y, orig) * noise, scaling_shift);
525 out_y[y * dest_stride_y + x] = Clip3(orig + noise, min_value, max_luma);
526 } while (++x < width);
527 } while (++y < height);
528 }
529
530 // This function is for the case params_.chroma_scaling_from_luma == false.
531 template <int bitdepth, typename GrainType, typename Pixel>
BlendNoiseWithImageChroma_C(Plane plane,const FilmGrainParams & params,const void * LIBGAV1_RESTRICT noise_image_ptr,int min_value,int max_chroma,int width,int height,int start_height,int subsampling_x,int subsampling_y,const int16_t * scaling_lut_uv,const void * source_plane_y,ptrdiff_t source_stride_y,const void * source_plane_uv,ptrdiff_t source_stride_uv,void * dest_plane_uv,ptrdiff_t dest_stride_uv)532 void BlendNoiseWithImageChroma_C(
533 Plane plane, const FilmGrainParams& params,
534 const void* LIBGAV1_RESTRICT noise_image_ptr, int min_value, int max_chroma,
535 int width, int height, int start_height, int subsampling_x,
536 int subsampling_y, const int16_t* scaling_lut_uv,
537 const void* source_plane_y, ptrdiff_t source_stride_y,
538 const void* source_plane_uv, ptrdiff_t source_stride_uv,
539 void* dest_plane_uv, ptrdiff_t dest_stride_uv) {
540 const auto* noise_image =
541 static_cast<const Array2D<GrainType>*>(noise_image_ptr);
542
543 const int chroma_width = (width + subsampling_x) >> subsampling_x;
544 const int chroma_height = (height + subsampling_y) >> subsampling_y;
545
546 const auto* in_y = static_cast<const Pixel*>(source_plane_y);
547 source_stride_y /= sizeof(Pixel);
548 const auto* in_uv = static_cast<const Pixel*>(source_plane_uv);
549 source_stride_uv /= sizeof(Pixel);
550 auto* out_uv = static_cast<Pixel*>(dest_plane_uv);
551 dest_stride_uv /= sizeof(Pixel);
552
553 const int offset = (plane == kPlaneU) ? params.u_offset : params.v_offset;
554 const int luma_multiplier =
555 (plane == kPlaneU) ? params.u_luma_multiplier : params.v_luma_multiplier;
556 const int multiplier =
557 (plane == kPlaneU) ? params.u_multiplier : params.v_multiplier;
558
559 const int scaling_shift = params.chroma_scaling;
560 start_height >>= subsampling_y;
561 int y = 0;
562 do {
563 int x = 0;
564 do {
565 const int luma_x = x << subsampling_x;
566 const int luma_y = y << subsampling_y;
567 const int luma_next_x = std::min(luma_x + 1, width - 1);
568 int average_luma;
569 if (subsampling_x != 0) {
570 average_luma = RightShiftWithRounding(
571 in_y[luma_y * source_stride_y + luma_x] +
572 in_y[luma_y * source_stride_y + luma_next_x],
573 1);
574 } else {
575 average_luma = in_y[luma_y * source_stride_y + luma_x];
576 }
577 const int orig = in_uv[y * source_stride_uv + x];
578 const int combined = average_luma * luma_multiplier + orig * multiplier;
579 const int merged =
580 Clip3((combined >> 6) + LeftShift(offset, bitdepth - kBitdepth8), 0,
581 (1 << bitdepth) - 1);
582 int noise = noise_image[plane][y + start_height][x];
583 noise = RightShiftWithRounding(
584 ScaleLut<bitdepth>(scaling_lut_uv, merged) * noise, scaling_shift);
585 out_uv[y * dest_stride_uv + x] =
586 Clip3(orig + noise, min_value, max_chroma);
587 } while (++x < chroma_width);
588 } while (++y < chroma_height);
589 }
590
591 // This function is for the case params_.chroma_scaling_from_luma == true.
592 // This further implies that scaling_lut_u == scaling_lut_v == scaling_lut_y.
593 template <int bitdepth, typename GrainType, typename Pixel>
BlendNoiseWithImageChromaWithCfl_C(Plane plane,const FilmGrainParams & params,const void * LIBGAV1_RESTRICT noise_image_ptr,int min_value,int max_chroma,int width,int height,int start_height,int subsampling_x,int subsampling_y,const int16_t * scaling_lut,const void * source_plane_y,ptrdiff_t source_stride_y,const void * source_plane_uv,ptrdiff_t source_stride_uv,void * dest_plane_uv,ptrdiff_t dest_stride_uv)594 void BlendNoiseWithImageChromaWithCfl_C(
595 Plane plane, const FilmGrainParams& params,
596 const void* LIBGAV1_RESTRICT noise_image_ptr, int min_value, int max_chroma,
597 int width, int height, int start_height, int subsampling_x,
598 int subsampling_y, const int16_t* scaling_lut, const void* source_plane_y,
599 ptrdiff_t source_stride_y, const void* source_plane_uv,
600 ptrdiff_t source_stride_uv, void* dest_plane_uv, ptrdiff_t dest_stride_uv) {
601 const auto* noise_image =
602 static_cast<const Array2D<GrainType>*>(noise_image_ptr);
603 const auto* in_y = static_cast<const Pixel*>(source_plane_y);
604 source_stride_y /= sizeof(Pixel);
605 const auto* in_uv = static_cast<const Pixel*>(source_plane_uv);
606 source_stride_uv /= sizeof(Pixel);
607 auto* out_uv = static_cast<Pixel*>(dest_plane_uv);
608 dest_stride_uv /= sizeof(Pixel);
609
610 const int chroma_width = (width + subsampling_x) >> subsampling_x;
611 const int chroma_height = (height + subsampling_y) >> subsampling_y;
612 const int scaling_shift = params.chroma_scaling;
613 start_height >>= subsampling_y;
614 int y = 0;
615 do {
616 int x = 0;
617 do {
618 const int luma_x = x << subsampling_x;
619 const int luma_y = y << subsampling_y;
620 const int luma_next_x = std::min(luma_x + 1, width - 1);
621 int average_luma;
622 if (subsampling_x != 0) {
623 average_luma = RightShiftWithRounding(
624 in_y[luma_y * source_stride_y + luma_x] +
625 in_y[luma_y * source_stride_y + luma_next_x],
626 1);
627 } else {
628 average_luma = in_y[luma_y * source_stride_y + luma_x];
629 }
630 const int orig_uv = in_uv[y * source_stride_uv + x];
631 int noise_uv = noise_image[plane][y + start_height][x];
632 noise_uv = RightShiftWithRounding(
633 ScaleLut<bitdepth>(scaling_lut, average_luma) * noise_uv,
634 scaling_shift);
635 out_uv[y * dest_stride_uv + x] =
636 Clip3(orig_uv + noise_uv, min_value, max_chroma);
637 } while (++x < chroma_width);
638 } while (++y < chroma_height);
639 }
640
Init8bpp()641 void Init8bpp() {
642 Dsp* const dsp = dsp_internal::GetWritableDspTable(8);
643 assert(dsp != nullptr);
644 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
645 // LumaAutoRegressionFunc
646 dsp->film_grain.luma_auto_regression[0] =
647 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth8, int8_t>;
648 dsp->film_grain.luma_auto_regression[1] =
649 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth8, int8_t>;
650 dsp->film_grain.luma_auto_regression[2] =
651 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth8, int8_t>;
652
653 // ChromaAutoRegressionFunc
654 // Chroma autoregression should never be called when lag is 0 and use_luma is
655 // false.
656 dsp->film_grain.chroma_auto_regression[0][0] = nullptr;
657 dsp->film_grain.chroma_auto_regression[0][1] =
658 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 1, false>;
659 dsp->film_grain.chroma_auto_regression[0][2] =
660 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 2, false>;
661 dsp->film_grain.chroma_auto_regression[0][3] =
662 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 3, false>;
663 dsp->film_grain.chroma_auto_regression[1][0] =
664 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 0, true>;
665 dsp->film_grain.chroma_auto_regression[1][1] =
666 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 1, true>;
667 dsp->film_grain.chroma_auto_regression[1][2] =
668 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 2, true>;
669 dsp->film_grain.chroma_auto_regression[1][3] =
670 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 3, true>;
671
672 // ConstructNoiseStripesFunc
673 dsp->film_grain.construct_noise_stripes[0] =
674 ConstructNoiseStripes_C<kBitdepth8, int8_t>;
675 dsp->film_grain.construct_noise_stripes[1] =
676 ConstructNoiseStripesWithOverlap_C<kBitdepth8, int8_t>;
677
678 // ConstructNoiseImageOverlapFunc
679 dsp->film_grain.construct_noise_image_overlap =
680 ConstructNoiseImageOverlap_C<kBitdepth8, int8_t>;
681
682 // InitializeScalingLutFunc
683 dsp->film_grain.initialize_scaling_lut =
684 InitializeScalingLookupTable_C<kBitdepth8>;
685
686 // BlendNoiseWithImageLumaFunc
687 dsp->film_grain.blend_noise_luma =
688 BlendNoiseWithImageLuma_C<kBitdepth8, int8_t, uint8_t>;
689
690 // BlendNoiseWithImageChromaFunc
691 dsp->film_grain.blend_noise_chroma[0] =
692 BlendNoiseWithImageChroma_C<kBitdepth8, int8_t, uint8_t>;
693 dsp->film_grain.blend_noise_chroma[1] =
694 BlendNoiseWithImageChromaWithCfl_C<kBitdepth8, int8_t, uint8_t>;
695 #else // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
696 static_cast<void>(dsp);
697 #ifndef LIBGAV1_Dsp8bpp_FilmGrainAutoregressionLuma
698 dsp->film_grain.luma_auto_regression[0] =
699 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth8, int8_t>;
700 dsp->film_grain.luma_auto_regression[1] =
701 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth8, int8_t>;
702 dsp->film_grain.luma_auto_regression[2] =
703 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth8, int8_t>;
704 #endif
705 #ifndef LIBGAV1_Dsp8bpp_FilmGrainAutoregressionChroma
706 // Chroma autoregression should never be called when lag is 0 and use_luma is
707 // false.
708 dsp->film_grain.chroma_auto_regression[0][0] = nullptr;
709 dsp->film_grain.chroma_auto_regression[0][1] =
710 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 1, false>;
711 dsp->film_grain.chroma_auto_regression[0][2] =
712 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 2, false>;
713 dsp->film_grain.chroma_auto_regression[0][3] =
714 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 3, false>;
715 dsp->film_grain.chroma_auto_regression[1][0] =
716 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 0, true>;
717 dsp->film_grain.chroma_auto_regression[1][1] =
718 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 1, true>;
719 dsp->film_grain.chroma_auto_regression[1][2] =
720 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 2, true>;
721 dsp->film_grain.chroma_auto_regression[1][3] =
722 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth8, int8_t, 3, true>;
723 #endif
724 #ifndef LIBGAV1_Dsp8bpp_FilmGrainConstructNoiseStripes
725 dsp->film_grain.construct_noise_stripes[0] =
726 ConstructNoiseStripes_C<kBitdepth8, int8_t>;
727 dsp->film_grain.construct_noise_stripes[1] =
728 ConstructNoiseStripesWithOverlap_C<kBitdepth8, int8_t>;
729 #endif
730 #ifndef LIBGAV1_Dsp8bpp_FilmGrainConstructNoiseImageOverlap
731 dsp->film_grain.construct_noise_image_overlap =
732 ConstructNoiseImageOverlap_C<kBitdepth8, int8_t>;
733 #endif
734 #ifndef LIBGAV1_Dsp8bpp_FilmGrainInitializeScalingLutFunc
735 dsp->film_grain.initialize_scaling_lut =
736 InitializeScalingLookupTable_C<kBitdepth8>;
737 #endif
738 #ifndef LIBGAV1_Dsp8bpp_FilmGrainBlendNoiseLuma
739 dsp->film_grain.blend_noise_luma =
740 BlendNoiseWithImageLuma_C<kBitdepth8, int8_t, uint8_t>;
741 #endif
742 #ifndef LIBGAV1_Dsp8bpp_FilmGrainBlendNoiseChroma
743 dsp->film_grain.blend_noise_chroma[0] =
744 BlendNoiseWithImageChroma_C<kBitdepth8, int8_t, uint8_t>;
745 #endif
746 #ifndef LIBGAV1_Dsp8bpp_FilmGrainBlendNoiseChromaWithCfl
747 dsp->film_grain.blend_noise_chroma[1] =
748 BlendNoiseWithImageChromaWithCfl_C<kBitdepth8, int8_t, uint8_t>;
749 #endif
750 #endif // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
751 }
752
753 #if LIBGAV1_MAX_BITDEPTH >= 10
Init10bpp()754 void Init10bpp() {
755 Dsp* const dsp = dsp_internal::GetWritableDspTable(10);
756 assert(dsp != nullptr);
757 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
758
759 // LumaAutoRegressionFunc
760 dsp->film_grain.luma_auto_regression[0] =
761 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth10, int16_t>;
762 dsp->film_grain.luma_auto_regression[1] =
763 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth10, int16_t>;
764 dsp->film_grain.luma_auto_regression[2] =
765 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth10, int16_t>;
766
767 // ChromaAutoRegressionFunc
768 // Chroma autoregression should never be called when lag is 0 and use_luma is
769 // false.
770 dsp->film_grain.chroma_auto_regression[0][0] = nullptr;
771 dsp->film_grain.chroma_auto_regression[0][1] =
772 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 1, false>;
773 dsp->film_grain.chroma_auto_regression[0][2] =
774 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 2, false>;
775 dsp->film_grain.chroma_auto_regression[0][3] =
776 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 3, false>;
777 dsp->film_grain.chroma_auto_regression[1][0] =
778 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 0, true>;
779 dsp->film_grain.chroma_auto_regression[1][1] =
780 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 1, true>;
781 dsp->film_grain.chroma_auto_regression[1][2] =
782 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 2, true>;
783 dsp->film_grain.chroma_auto_regression[1][3] =
784 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 3, true>;
785
786 // ConstructNoiseStripesFunc
787 dsp->film_grain.construct_noise_stripes[0] =
788 ConstructNoiseStripes_C<kBitdepth10, int16_t>;
789 dsp->film_grain.construct_noise_stripes[1] =
790 ConstructNoiseStripesWithOverlap_C<kBitdepth10, int16_t>;
791
792 // ConstructNoiseImageOverlapFunc
793 dsp->film_grain.construct_noise_image_overlap =
794 ConstructNoiseImageOverlap_C<kBitdepth10, int16_t>;
795
796 // InitializeScalingLutFunc
797 dsp->film_grain.initialize_scaling_lut =
798 InitializeScalingLookupTable_C<kBitdepth10>;
799
800 // BlendNoiseWithImageLumaFunc
801 dsp->film_grain.blend_noise_luma =
802 BlendNoiseWithImageLuma_C<kBitdepth10, int16_t, uint16_t>;
803
804 // BlendNoiseWithImageChromaFunc
805 dsp->film_grain.blend_noise_chroma[0] =
806 BlendNoiseWithImageChroma_C<kBitdepth10, int16_t, uint16_t>;
807 dsp->film_grain.blend_noise_chroma[1] =
808 BlendNoiseWithImageChromaWithCfl_C<kBitdepth10, int16_t, uint16_t>;
809 #else // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
810 static_cast<void>(dsp);
811 #ifndef LIBGAV1_Dsp10bpp_FilmGrainAutoregressionLuma
812 dsp->film_grain.luma_auto_regression[0] =
813 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth10, int16_t>;
814 dsp->film_grain.luma_auto_regression[1] =
815 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth10, int16_t>;
816 dsp->film_grain.luma_auto_regression[2] =
817 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth10, int16_t>;
818 #endif
819 #ifndef LIBGAV1_Dsp10bpp_FilmGrainAutoregressionChroma
820 // Chroma autoregression should never be called when lag is 0 and use_luma is
821 // false.
822 dsp->film_grain.chroma_auto_regression[0][0] = nullptr;
823 dsp->film_grain.chroma_auto_regression[0][1] =
824 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 1, false>;
825 dsp->film_grain.chroma_auto_regression[0][2] =
826 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 2, false>;
827 dsp->film_grain.chroma_auto_regression[0][3] =
828 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 3, false>;
829 dsp->film_grain.chroma_auto_regression[1][0] =
830 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 0, true>;
831 dsp->film_grain.chroma_auto_regression[1][1] =
832 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 1, true>;
833 dsp->film_grain.chroma_auto_regression[1][2] =
834 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 2, true>;
835 dsp->film_grain.chroma_auto_regression[1][3] =
836 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth10, int16_t, 3, true>;
837 #endif
838 #ifndef LIBGAV1_Dsp10bpp_FilmGrainConstructNoiseStripes
839 dsp->film_grain.construct_noise_stripes[0] =
840 ConstructNoiseStripes_C<kBitdepth10, int16_t>;
841 dsp->film_grain.construct_noise_stripes[1] =
842 ConstructNoiseStripesWithOverlap_C<kBitdepth10, int16_t>;
843 #endif
844 #ifndef LIBGAV1_Dsp10bpp_FilmGrainConstructNoiseImageOverlap
845 dsp->film_grain.construct_noise_image_overlap =
846 ConstructNoiseImageOverlap_C<kBitdepth10, int16_t>;
847 #endif
848 #ifndef LIBGAV1_Dsp10bpp_FilmGrainInitializeScalingLutFunc
849 dsp->film_grain.initialize_scaling_lut =
850 InitializeScalingLookupTable_C<kBitdepth10>;
851 #endif
852 #ifndef LIBGAV1_Dsp10bpp_FilmGrainBlendNoiseLuma
853 dsp->film_grain.blend_noise_luma =
854 BlendNoiseWithImageLuma_C<kBitdepth10, int16_t, uint16_t>;
855 #endif
856 #ifndef LIBGAV1_Dsp10bpp_FilmGrainBlendNoiseChroma
857 dsp->film_grain.blend_noise_chroma[0] =
858 BlendNoiseWithImageChroma_C<kBitdepth10, int16_t, uint16_t>;
859 #endif
860 #ifndef LIBGAV1_Dsp10bpp_FilmGrainBlendNoiseChromaWithCfl
861 dsp->film_grain.blend_noise_chroma[1] =
862 BlendNoiseWithImageChromaWithCfl_C<kBitdepth10, int16_t, uint16_t>;
863 #endif
864 #endif // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
865 }
866 #endif // LIBGAV1_MAX_BITDEPTH >= 10
867
868 #if LIBGAV1_MAX_BITDEPTH == 12
Init12bpp()869 void Init12bpp() {
870 Dsp* const dsp = dsp_internal::GetWritableDspTable(12);
871 assert(dsp != nullptr);
872 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
873
874 // LumaAutoRegressionFunc
875 dsp->film_grain.luma_auto_regression[0] =
876 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth12, int16_t>;
877 dsp->film_grain.luma_auto_regression[1] =
878 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth12, int16_t>;
879 dsp->film_grain.luma_auto_regression[2] =
880 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth12, int16_t>;
881
882 // ChromaAutoRegressionFunc
883 // Chroma autoregression should never be called when lag is 0 and use_luma is
884 // false.
885 dsp->film_grain.chroma_auto_regression[0][0] = nullptr;
886 dsp->film_grain.chroma_auto_regression[0][1] =
887 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 1, false>;
888 dsp->film_grain.chroma_auto_regression[0][2] =
889 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 2, false>;
890 dsp->film_grain.chroma_auto_regression[0][3] =
891 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 3, false>;
892 dsp->film_grain.chroma_auto_regression[1][0] =
893 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 0, true>;
894 dsp->film_grain.chroma_auto_regression[1][1] =
895 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 1, true>;
896 dsp->film_grain.chroma_auto_regression[1][2] =
897 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 2, true>;
898 dsp->film_grain.chroma_auto_regression[1][3] =
899 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 3, true>;
900
901 // ConstructNoiseStripesFunc
902 dsp->film_grain.construct_noise_stripes[0] =
903 ConstructNoiseStripes_C<kBitdepth12, int16_t>;
904 dsp->film_grain.construct_noise_stripes[1] =
905 ConstructNoiseStripesWithOverlap_C<kBitdepth12, int16_t>;
906
907 // ConstructNoiseImageOverlapFunc
908 dsp->film_grain.construct_noise_image_overlap =
909 ConstructNoiseImageOverlap_C<kBitdepth12, int16_t>;
910
911 // InitializeScalingLutFunc
912 dsp->film_grain.initialize_scaling_lut =
913 InitializeScalingLookupTable_C<kBitdepth12>;
914
915 // BlendNoiseWithImageLumaFunc
916 dsp->film_grain.blend_noise_luma =
917 BlendNoiseWithImageLuma_C<kBitdepth12, int16_t, uint16_t>;
918
919 // BlendNoiseWithImageChromaFunc
920 dsp->film_grain.blend_noise_chroma[0] =
921 BlendNoiseWithImageChroma_C<kBitdepth12, int16_t, uint16_t>;
922 dsp->film_grain.blend_noise_chroma[1] =
923 BlendNoiseWithImageChromaWithCfl_C<kBitdepth12, int16_t, uint16_t>;
924 #else // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
925 static_cast<void>(dsp);
926 #ifndef LIBGAV1_Dsp12bpp_FilmGrainAutoregressionLuma
927 dsp->film_grain.luma_auto_regression[0] =
928 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth12, int16_t>;
929 dsp->film_grain.luma_auto_regression[1] =
930 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth12, int16_t>;
931 dsp->film_grain.luma_auto_regression[2] =
932 ApplyAutoRegressiveFilterToLumaGrain_C<kBitdepth12, int16_t>;
933 #endif
934 #ifndef LIBGAV1_Dsp12bpp_FilmGrainAutoregressionChroma
935 // Chroma autoregression should never be called when lag is 0 and use_luma is
936 // false.
937 dsp->film_grain.chroma_auto_regression[0][0] = nullptr;
938 dsp->film_grain.chroma_auto_regression[0][1] =
939 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 1, false>;
940 dsp->film_grain.chroma_auto_regression[0][2] =
941 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 2, false>;
942 dsp->film_grain.chroma_auto_regression[0][3] =
943 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 3, false>;
944 dsp->film_grain.chroma_auto_regression[1][0] =
945 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 0, true>;
946 dsp->film_grain.chroma_auto_regression[1][1] =
947 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 1, true>;
948 dsp->film_grain.chroma_auto_regression[1][2] =
949 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 2, true>;
950 dsp->film_grain.chroma_auto_regression[1][3] =
951 ApplyAutoRegressiveFilterToChromaGrains_C<kBitdepth12, int16_t, 3, true>;
952 #endif
953 #ifndef LIBGAV1_Dsp12bpp_FilmGrainConstructNoiseStripes
954 dsp->film_grain.construct_noise_stripes[0] =
955 ConstructNoiseStripes_C<kBitdepth12, int16_t>;
956 dsp->film_grain.construct_noise_stripes[1] =
957 ConstructNoiseStripesWithOverlap_C<kBitdepth12, int16_t>;
958 #endif
959 #ifndef LIBGAV1_Dsp12bpp_FilmGrainConstructNoiseImageOverlap
960 dsp->film_grain.construct_noise_image_overlap =
961 ConstructNoiseImageOverlap_C<kBitdepth12, int16_t>;
962 #endif
963 #ifndef LIBGAV1_Dsp12bpp_FilmGrainInitializeScalingLutFunc
964 dsp->film_grain.initialize_scaling_lut =
965 InitializeScalingLookupTable_C<kBitdepth12>;
966 #endif
967 #ifndef LIBGAV1_Dsp12bpp_FilmGrainBlendNoiseLuma
968 dsp->film_grain.blend_noise_luma =
969 BlendNoiseWithImageLuma_C<kBitdepth12, int16_t, uint16_t>;
970 #endif
971 #ifndef LIBGAV1_Dsp12bpp_FilmGrainBlendNoiseChroma
972 dsp->film_grain.blend_noise_chroma[0] =
973 BlendNoiseWithImageChroma_C<kBitdepth12, int16_t, uint16_t>;
974 #endif
975 #ifndef LIBGAV1_Dsp12bpp_FilmGrainBlendNoiseChromaWithCfl
976 dsp->film_grain.blend_noise_chroma[1] =
977 BlendNoiseWithImageChromaWithCfl_C<kBitdepth12, int16_t, uint16_t>;
978 #endif
979 #endif // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
980 }
981 #endif // LIBGAV1_MAX_BITDEPTH == 12
982
983 } // namespace
984 } // namespace film_grain
985
FilmGrainInit_C()986 void FilmGrainInit_C() {
987 film_grain::Init8bpp();
988 #if LIBGAV1_MAX_BITDEPTH >= 10
989 film_grain::Init10bpp();
990 #endif
991 #if LIBGAV1_MAX_BITDEPTH == 12
992 film_grain::Init12bpp();
993 #endif
994 }
995
996 } // namespace dsp
997 } // namespace libgav1
998