FFmpeg
aom_film_grain_template.c
Go to the documentation of this file.
1 /*
2  * AOM film grain synthesis
3  * Copyright (c) 2023 Niklas Haas <ffmpeg@haasn.xyz>
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /*
23  * Copyright © 2018, Niklas Haas
24  * Copyright © 2018, VideoLAN and dav1d authors
25  * Copyright © 2018, Two Orioles, LLC
26  * All rights reserved.
27  *
28  * Redistribution and use in source and binary forms, with or without
29  * modification, are permitted provided that the following conditions are met:
30  *
31  * 1. Redistributions of source code must retain the above copyright notice, this
32  * list of conditions and the following disclaimer.
33  *
34  * 2. Redistributions in binary form must reproduce the above copyright notice,
35  * this list of conditions and the following disclaimer in the documentation
36  * and/or other materials provided with the distribution.
37  *
38  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
39  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
40  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
42  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
43  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
47  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  */
49 
50 #include "bit_depth_template.c"
51 
52 #undef entry
53 #undef bitdepth
54 #undef bitdepth_max
55 #undef HBD_DECL
56 #undef HBD_CALL
57 #undef SCALING_SIZE
58 
59 #if BIT_DEPTH > 8
60 # define entry int16_t
61 # define bitdepth_max ((1 << bitdepth) - 1)
62 # define HBD_DECL , const int bitdepth
63 # define HBD_CALL , bitdepth
64 # define SCALING_SIZE 4096
65 #else
66 # define entry int8_t
67 # define bitdepth 8
68 # define bitdepth_max UINT8_MAX
69 # define HBD_DECL
70 # define HBD_CALL
71 # define SCALING_SIZE 256
72 #endif
73 
75  const AVFilmGrainParams *const params
76  HBD_DECL)
77 {
78  const AVFilmGrainAOMParams *const data = &params->codec.aom;
79  const int bitdepth_min_8 = bitdepth - 8;
80  unsigned seed = params->seed;
81  const int shift = 4 - bitdepth_min_8 + data->grain_scale_shift;
82  const int grain_ctr = 128 << bitdepth_min_8;
83  const int grain_min = -grain_ctr, grain_max = grain_ctr - 1;
84 
85  const int ar_pad = 3;
86  const int ar_lag = data->ar_coeff_lag;
87 
88  for (int y = 0; y < GRAIN_HEIGHT; y++) {
89  for (int x = 0; x < GRAIN_WIDTH; x++) {
90  const int value = get_random_number(11, &seed);
91  buf[y][x] = round2(gaussian_sequence[ value ], shift);
92  }
93  }
94 
95  for (int y = ar_pad; y < GRAIN_HEIGHT; y++) {
96  for (int x = ar_pad; x < GRAIN_WIDTH - ar_pad; x++) {
97  const int8_t *coeff = data->ar_coeffs_y;
98  int sum = 0, grain;
99  for (int dy = -ar_lag; dy <= 0; dy++) {
100  for (int dx = -ar_lag; dx <= ar_lag; dx++) {
101  if (!dx && !dy)
102  break;
103  sum += *(coeff++) * buf[y + dy][x + dx];
104  }
105  }
106 
107  grain = buf[y][x] + round2(sum, data->ar_coeff_shift);
108  buf[y][x] = av_clip(grain, grain_min, grain_max);
109  }
110  }
111 }
112 
113 static void
115  const entry buf_y[][GRAIN_WIDTH],
116  const AVFilmGrainParams *const params, const intptr_t uv,
117  const int subx, const int suby HBD_DECL)
118 {
119  const AVFilmGrainAOMParams *const data = &params->codec.aom;
120  const int bitdepth_min_8 = bitdepth - 8;
121  unsigned seed = params->seed ^ (uv ? 0x49d8 : 0xb524);
122  const int shift = 4 - bitdepth_min_8 + data->grain_scale_shift;
123  const int grain_ctr = 128 << bitdepth_min_8;
124  const int grain_min = -grain_ctr, grain_max = grain_ctr - 1;
125 
126  const int chromaW = subx ? SUB_GRAIN_WIDTH : GRAIN_WIDTH;
127  const int chromaH = suby ? SUB_GRAIN_HEIGHT : GRAIN_HEIGHT;
128 
129  const int ar_pad = 3;
130  const int ar_lag = data->ar_coeff_lag;
131 
132  for (int y = 0; y < chromaH; y++) {
133  for (int x = 0; x < chromaW; x++) {
134  const int value = get_random_number(11, &seed);
135  buf[y][x] = round2(gaussian_sequence[ value ], shift);
136  }
137  }
138 
139  for (int y = ar_pad; y < chromaH; y++) {
140  for (int x = ar_pad; x < chromaW - ar_pad; x++) {
141  const int8_t *coeff = data->ar_coeffs_uv[uv];
142  int sum = 0, grain;
143  for (int dy = -ar_lag; dy <= 0; dy++) {
144  for (int dx = -ar_lag; dx <= ar_lag; dx++) {
145  // For the final (current) pixel, we need to add in the
146  // contribution from the luma grain texture
147  if (!dx && !dy) {
148  const int lumaX = ((x - ar_pad) << subx) + ar_pad;
149  const int lumaY = ((y - ar_pad) << suby) + ar_pad;
150  int luma = 0;
151  if (!data->num_y_points)
152  break;
153  for (int i = 0; i <= suby; i++) {
154  for (int j = 0; j <= subx; j++) {
155  luma += buf_y[lumaY + i][lumaX + j];
156  }
157  }
158  luma = round2(luma, subx + suby);
159  sum += luma * (*coeff);
160  break;
161  }
162 
163  sum += *(coeff++) * buf[y + dy][x + dx];
164  }
165  }
166 
167  grain = buf[y][x] + round2(sum, data->ar_coeff_shift);
168  buf[y][x] = av_clip(grain, grain_min, grain_max);
169  }
170  }
171 }
172 
173 // samples from the correct block of a grain LUT, while taking into account the
174 // offsets provided by the offsets cache
175 static inline entry FUNC(sample_lut)(const entry grain_lut[][GRAIN_WIDTH],
176  const int offsets[2][2],
177  const int subx, const int suby,
178  const int bx, const int by,
179  const int x, const int y)
180 {
181  const int randval = offsets[bx][by];
182  const int offx = 3 + (2 >> subx) * (3 + (randval >> 4));
183  const int offy = 3 + (2 >> suby) * (3 + (randval & 0xF));
184  return grain_lut[offy + y + (FG_BLOCK_SIZE >> suby) * by]
185  [offx + x + (FG_BLOCK_SIZE >> subx) * bx];
186 }
187 
188 static void FUNC(fgy_32x32xn_c)(pixel *const dst_row, const pixel *const src_row,
189  const ptrdiff_t stride,
190  const AVFilmGrainParams *const params, const size_t pw,
191  const uint8_t scaling[SCALING_SIZE],
192  const entry grain_lut[][GRAIN_WIDTH],
193  const int bh, const int row_num HBD_DECL)
194 {
195  const AVFilmGrainAOMParams *const data = &params->codec.aom;
196  const int rows = 1 + (data->overlap_flag && row_num > 0);
197  const int bitdepth_min_8 = bitdepth - 8;
198  const int grain_ctr = 128 << bitdepth_min_8;
199  const int grain_min = -grain_ctr, grain_max = grain_ctr - 1;
200  unsigned seed[2];
201  int offsets[2 /* col offset */][2 /* row offset */];
202 
203  int min_value, max_value;
204  if (data->limit_output_range) {
205  min_value = 16 << bitdepth_min_8;
206  max_value = 235 << bitdepth_min_8;
207  } else {
208  min_value = 0;
209  max_value = bitdepth_max;
210  }
211 
212  // seed[0] contains the current row, seed[1] contains the previous
213  for (int i = 0; i < rows; i++) {
214  seed[i] = params->seed;
215  seed[i] ^= (((row_num - i) * 37 + 178) & 0xFF) << 8;
216  seed[i] ^= (((row_num - i) * 173 + 105) & 0xFF);
217  }
218 
219  av_assert1(stride % (FG_BLOCK_SIZE * sizeof(pixel)) == 0);
220 
221  // process this row in FG_BLOCK_SIZE^2 blocks
222  for (unsigned bx = 0; bx < pw; bx += FG_BLOCK_SIZE) {
223  const int bw = FFMIN(FG_BLOCK_SIZE, (int) pw - bx);
224  const pixel *src;
225  pixel *dst;
226  int noise;
227 
228  // x/y block offsets to compensate for overlapped regions
229  const int ystart = data->overlap_flag && row_num ? FFMIN(2, bh) : 0;
230  const int xstart = data->overlap_flag && bx ? FFMIN(2, bw) : 0;
231 
232  static const int w[2][2] = { { 27, 17 }, { 17, 27 } };
233 
234  if (data->overlap_flag && bx) {
235  // shift previous offsets left
236  for (int i = 0; i < rows; i++)
237  offsets[1][i] = offsets[0][i];
238  }
239 
240  // update current offsets
241  for (int i = 0; i < rows; i++)
242  offsets[0][i] = get_random_number(8, &seed[i]);
243 
244 #define add_noise_y(x, y, grain) \
245  src = (const pixel*)((const char*)src_row + (y) * stride) + (x) + bx; \
246  dst = (pixel*)((char*)dst_row + (y) * stride) + (x) + bx; \
247  noise = round2(scaling[ *src ] * (grain), data->scaling_shift); \
248  *dst = av_clip(*src + noise, min_value, max_value);
249 
250  for (int y = ystart; y < bh; y++) {
251  // Non-overlapped image region (straightforward)
252  for (int x = xstart; x < bw; x++) {
253  int grain = FUNC(sample_lut)(grain_lut, offsets, 0, 0, 0, 0, x, y);
254  add_noise_y(x, y, grain);
255  }
256 
257  // Special case for overlapped column
258  for (int x = 0; x < xstart; x++) {
259  int grain = FUNC(sample_lut)(grain_lut, offsets, 0, 0, 0, 0, x, y);
260  int old = FUNC(sample_lut)(grain_lut, offsets, 0, 0, 1, 0, x, y);
261  grain = round2(old * w[x][0] + grain * w[x][1], 5);
262  grain = av_clip(grain, grain_min, grain_max);
263  add_noise_y(x, y, grain);
264  }
265  }
266 
267  for (int y = 0; y < ystart; y++) {
268  // Special case for overlapped row (sans corner)
269  for (int x = xstart; x < bw; x++) {
270  int grain = FUNC(sample_lut)(grain_lut, offsets, 0, 0, 0, 0, x, y);
271  int old = FUNC(sample_lut)(grain_lut, offsets, 0, 0, 0, 1, x, y);
272  grain = round2(old * w[y][0] + grain * w[y][1], 5);
273  grain = av_clip(grain, grain_min, grain_max);
274  add_noise_y(x, y, grain);
275  }
276 
277  // Special case for doubly-overlapped corner
278  for (int x = 0; x < xstart; x++) {
279  int grain = FUNC(sample_lut)(grain_lut, offsets, 0, 0, 0, 0, x, y);
280  int top = FUNC(sample_lut)(grain_lut, offsets, 0, 0, 0, 1, x, y);
281  int old = FUNC(sample_lut)(grain_lut, offsets, 0, 0, 1, 1, x, y);
282 
283  // Blend the top pixel with the top left block
284  top = round2(old * w[x][0] + top * w[x][1], 5);
285  top = av_clip(top, grain_min, grain_max);
286 
287  // Blend the current pixel with the left block
288  old = FUNC(sample_lut)(grain_lut, offsets, 0, 0, 1, 0, x, y);
289  grain = round2(old * w[x][0] + grain * w[x][1], 5);
290  grain = av_clip(grain, grain_min, grain_max);
291 
292  // Mix the row rows together and apply grain
293  grain = round2(top * w[y][0] + grain * w[y][1], 5);
294  grain = av_clip(grain, grain_min, grain_max);
295  add_noise_y(x, y, grain);
296  }
297  }
298  }
299 }
300 
301 static void
302 FUNC(fguv_32x32xn_c)(pixel *const dst_row, const pixel *const src_row,
303  const ptrdiff_t stride, const AVFilmGrainParams *const params,
304  const size_t pw, const uint8_t scaling[SCALING_SIZE],
305  const entry grain_lut[][GRAIN_WIDTH], const int bh,
306  const int row_num, const pixel *const luma_row,
307  const ptrdiff_t luma_stride, const int uv, const int is_id,
308  const int sx, const int sy HBD_DECL)
309 {
310  const AVFilmGrainAOMParams *const data = &params->codec.aom;
311  const int rows = 1 + (data->overlap_flag && row_num > 0);
312  const int bitdepth_min_8 = bitdepth - 8;
313  const int grain_ctr = 128 << bitdepth_min_8;
314  const int grain_min = -grain_ctr, grain_max = grain_ctr - 1;
315  unsigned seed[2];
316  int offsets[2 /* col offset */][2 /* row offset */];
317 
318  int min_value, max_value;
319  if (data->limit_output_range) {
320  min_value = 16 << bitdepth_min_8;
321  max_value = (is_id ? 235 : 240) << bitdepth_min_8;
322  } else {
323  min_value = 0;
324  max_value = bitdepth_max;
325  }
326 
327  // seed[0] contains the current row, seed[1] contains the previous
328  for (int i = 0; i < rows; i++) {
329  seed[i] = params->seed;
330  seed[i] ^= (((row_num - i) * 37 + 178) & 0xFF) << 8;
331  seed[i] ^= (((row_num - i) * 173 + 105) & 0xFF);
332  }
333 
334  av_assert1(stride % (FG_BLOCK_SIZE * sizeof(pixel)) == 0);
335 
336  // process this row in FG_BLOCK_SIZE^2 blocks (subsampled)
337  for (unsigned bx = 0; bx < pw; bx += FG_BLOCK_SIZE >> sx) {
338  const int bw = FFMIN(FG_BLOCK_SIZE >> sx, (int)(pw - bx));
339  int val, lx, ly, noise;
340  const pixel *src, *luma;
341  pixel *dst, avg;
342 
343  // x/y block offsets to compensate for overlapped regions
344  const int ystart = data->overlap_flag && row_num ? FFMIN(2 >> sy, bh) : 0;
345  const int xstart = data->overlap_flag && bx ? FFMIN(2 >> sx, bw) : 0;
346 
347  static const int w[2 /* sub */][2 /* off */][2] = {
348  { { 27, 17 }, { 17, 27 } },
349  { { 23, 22 } },
350  };
351 
352  if (data->overlap_flag && bx) {
353  // shift previous offsets left
354  for (int i = 0; i < rows; i++)
355  offsets[1][i] = offsets[0][i];
356  }
357 
358  // update current offsets
359  for (int i = 0; i < rows; i++)
360  offsets[0][i] = get_random_number(8, &seed[i]);
361 
362 #define add_noise_uv(x, y, grain) \
363  lx = (bx + x) << sx; \
364  ly = y << sy; \
365  luma = (const pixel*)((const char*)luma_row + ly * luma_stride) + lx;\
366  avg = luma[0]; \
367  if (sx) \
368  avg = (avg + luma[1] + 1) >> 1; \
369  src = (const pixel*)((const char *)src_row + (y) * stride) + bx + (x);\
370  dst = (pixel *) ((char *) dst_row + (y) * stride) + bx + (x); \
371  val = avg; \
372  if (!data->chroma_scaling_from_luma) { \
373  const int combined = avg * data->uv_mult_luma[uv] + \
374  *src * data->uv_mult[uv]; \
375  val = av_clip( (combined >> 6) + \
376  (data->uv_offset[uv] * (1 << bitdepth_min_8)), \
377  0, bitdepth_max ); \
378  } \
379  noise = round2(scaling[ val ] * (grain), data->scaling_shift); \
380  *dst = av_clip(*src + noise, min_value, max_value);
381 
382  for (int y = ystart; y < bh; y++) {
383  // Non-overlapped image region (straightforward)
384  for (int x = xstart; x < bw; x++) {
385  int grain = FUNC(sample_lut)(grain_lut, offsets, sx, sy, 0, 0, x, y);
386  add_noise_uv(x, y, grain);
387  }
388 
389  // Special case for overlapped column
390  for (int x = 0; x < xstart; x++) {
391  int grain = FUNC(sample_lut)(grain_lut, offsets, sx, sy, 0, 0, x, y);
392  int old = FUNC(sample_lut)(grain_lut, offsets, sx, sy, 1, 0, x, y);
393  grain = round2(old * w[sx][x][0] + grain * w[sx][x][1], 5);
394  grain = av_clip(grain, grain_min, grain_max);
395  add_noise_uv(x, y, grain);
396  }
397  }
398 
399  for (int y = 0; y < ystart; y++) {
400  // Special case for overlapped row (sans corner)
401  for (int x = xstart; x < bw; x++) {
402  int grain = FUNC(sample_lut)(grain_lut, offsets, sx, sy, 0, 0, x, y);
403  int old = FUNC(sample_lut)(grain_lut, offsets, sx, sy, 0, 1, x, y);
404  grain = round2(old * w[sy][y][0] + grain * w[sy][y][1], 5);
405  grain = av_clip(grain, grain_min, grain_max);
406  add_noise_uv(x, y, grain);
407  }
408 
409  // Special case for doubly-overlapped corner
410  for (int x = 0; x < xstart; x++) {
411  int top = FUNC(sample_lut)(grain_lut, offsets, sx, sy, 0, 1, x, y);
412  int old = FUNC(sample_lut)(grain_lut, offsets, sx, sy, 1, 1, x, y);
413  int grain = FUNC(sample_lut)(grain_lut, offsets, sx, sy, 0, 0, x, y);
414 
415  // Blend the top pixel with the top left block
416  top = round2(old * w[sx][x][0] + top * w[sx][x][1], 5);
417  top = av_clip(top, grain_min, grain_max);
418 
419  // Blend the current pixel with the left block
420  old = FUNC(sample_lut)(grain_lut, offsets, sx, sy, 1, 0, x, y);
421  grain = round2(old * w[sx][x][0] + grain * w[sx][x][1], 5);
422  grain = av_clip(grain, grain_min, grain_max);
423 
424  // Mix the row rows together and apply to image
425  grain = round2(top * w[sy][y][0] + grain * w[sy][y][1], 5);
426  grain = av_clip(grain, grain_min, grain_max);
427  add_noise_uv(x, y, grain);
428  }
429  }
430  }
431 }
432 
433 static void FUNC(generate_scaling)(const uint8_t points[][2], const int num,
434  uint8_t scaling[SCALING_SIZE] HBD_DECL)
435 {
436  const int shift_x = bitdepth - 8;
437  const int scaling_size = 1 << bitdepth;
438  const int max_value = points[num - 1][0] << shift_x;
439  av_assert0(scaling_size <= SCALING_SIZE);
440 
441  if (num == 0) {
442  memset(scaling, 0, scaling_size);
443  return;
444  }
445 
446  // Fill up the preceding entries with the initial value
447  memset(scaling, points[0][1], points[0][0] << shift_x);
448 
449  // Linearly interpolate the values in the middle
450  for (int i = 0; i < num - 1; i++) {
451  const int bx = points[i][0];
452  const int by = points[i][1];
453  const int ex = points[i+1][0];
454  const int ey = points[i+1][1];
455  const int dx = ex - bx;
456  const int dy = ey - by;
457  const int delta = dy * ((0x10000 + (dx >> 1)) / dx);
458  av_assert1(dx > 0);
459  for (int x = 0, d = 0x8000; x < dx; x++) {
460  scaling[(bx + x) << shift_x] = by + (d >> 16);
461  d += delta;
462  }
463  }
464 
465  // Fill up the remaining entries with the final value
466  memset(&scaling[max_value], points[num - 1][1], scaling_size - max_value);
467 
468 #if BIT_DEPTH != 8
469  for (int i = 0; i < num - 1; i++) {
470  const int pad = 1 << shift_x, rnd = pad >> 1;
471  const int bx = points[i][0] << shift_x;
472  const int ex = points[i+1][0] << shift_x;
473  const int dx = ex - bx;
474  for (int x = 0; x < dx; x += pad) {
475  const int range = scaling[bx + x + pad] - scaling[bx + x];
476  for (int n = 1, r = rnd; n < pad; n++) {
477  r += range;
478  scaling[bx + x + n] = scaling[bx + x] + (r >> shift_x);
479  }
480  }
481  }
482 #endif
483 }
484 
485 static av_always_inline void
487  const int ss_x, const int ss_y,
488  const uint8_t scaling[3][SCALING_SIZE],
489  const entry grain_lut[3][GRAIN_HEIGHT+1][GRAIN_WIDTH],
490  const AVFilmGrainParams *params,
491  const int row HBD_DECL)
492 {
493  // Synthesize grain for the affected planes
494  const AVFilmGrainAOMParams *const data = &params->codec.aom;
495  const int cpw = (out->width + ss_x) >> ss_x;
496  const int is_id = out->colorspace == AVCOL_SPC_RGB;
497  const int bh = (FFMIN(out->height - row * FG_BLOCK_SIZE, FG_BLOCK_SIZE) + ss_y) >> ss_y;
498  const ptrdiff_t uv_off = row * FG_BLOCK_SIZE * out->linesize[1] >> ss_y;
499  pixel *const luma_src = (pixel *)
500  ((char *) in->data[0] + row * FG_BLOCK_SIZE * in->linesize[0]);
501 
502  if (data->num_y_points) {
503  const int bh = FFMIN(out->height - row * FG_BLOCK_SIZE, FG_BLOCK_SIZE);
504  const ptrdiff_t off = row * FG_BLOCK_SIZE * out->linesize[0];
505  FUNC(fgy_32x32xn_c)((pixel *) ((char *) out->data[0] + off), luma_src,
506  out->linesize[0], params, out->width, scaling[0],
507  grain_lut[0], bh, row HBD_CALL);
508  }
509 
510  if (!data->num_uv_points[0] && !data->num_uv_points[1] &&
511  !data->chroma_scaling_from_luma)
512  {
513  return;
514  }
515 
516  // extend padding pixels
517  if (out->width & ss_x) {
518  pixel *ptr = luma_src;
519  for (int y = 0; y < bh; y++) {
520  ptr[out->width] = ptr[out->width - 1];
521  ptr = (pixel *) ((char *) ptr + (in->linesize[0] << ss_y));
522  }
523  }
524 
525  if (data->chroma_scaling_from_luma) {
526  for (int pl = 0; pl < 2; pl++)
527  FUNC(fguv_32x32xn_c)((pixel *) ((char *) out->data[1 + pl] + uv_off),
528  (const pixel *) ((const char *) in->data[1 + pl] + uv_off),
529  in->linesize[1], params, cpw, scaling[0],
530  grain_lut[1 + pl], bh, row, luma_src,
531  in->linesize[0], pl, is_id, ss_x, ss_y HBD_CALL);
532  } else {
533  for (int pl = 0; pl < 2; pl++) {
534  if (data->num_uv_points[pl]) {
535  FUNC(fguv_32x32xn_c)((pixel *) ((char *) out->data[1 + pl] + uv_off),
536  (const pixel *) ((const char *) in->data[1 + pl] + uv_off),
537  in->linesize[1], params, cpw, scaling[1 + pl],
538  grain_lut[1 + pl], bh, row, luma_src,
539  in->linesize[0], pl, is_id, ss_x, ss_y HBD_CALL);
540  }
541  }
542  }
543 }
544 
545 static int FUNC(apply_film_grain)(AVFrame *out_frame, const AVFrame *in_frame,
546  const AVFilmGrainParams *params HBD_DECL)
547 {
548  entry grain_lut[3][GRAIN_HEIGHT + 1][GRAIN_WIDTH];
549  uint8_t scaling[3][SCALING_SIZE];
550 
551  const AVFilmGrainAOMParams *const data = &params->codec.aom;
552  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(out_frame->format);
553  const int rows = AV_CEIL_RSHIFT(out_frame->height, 5); /* log2(FG_BLOCK_SIZE) */
554  const int subx = desc->log2_chroma_w, suby = desc->log2_chroma_h;
555 
556  // Generate grain LUTs as needed
557  FUNC(generate_grain_y_c)(grain_lut[0], params HBD_CALL);
558  if (data->num_uv_points[0] || data->chroma_scaling_from_luma)
559  FUNC(generate_grain_uv_c)(grain_lut[1], grain_lut[0], params, 0, subx, suby HBD_CALL);
560  if (data->num_uv_points[1] || data->chroma_scaling_from_luma)
561  FUNC(generate_grain_uv_c)(grain_lut[2], grain_lut[0], params, 1, subx, suby HBD_CALL);
562 
563  // Generate scaling LUTs as needed
564  if (data->num_y_points || data->chroma_scaling_from_luma)
565  FUNC(generate_scaling)(data->y_points, data->num_y_points, scaling[0] HBD_CALL);
566  if (data->num_uv_points[0])
567  FUNC(generate_scaling)(data->uv_points[0], data->num_uv_points[0], scaling[1] HBD_CALL);
568  if (data->num_uv_points[1])
569  FUNC(generate_scaling)(data->uv_points[1], data->num_uv_points[1], scaling[2] HBD_CALL);
570 
571  for (int row = 0; row < rows; row++) {
572  FUNC(apply_grain_row)(out_frame, in_frame, subx, suby, scaling, grain_lut,
573  params, row HBD_CALL);
574  }
575 
576  return 0;
577 }
entry
#define entry
Definition: aom_film_grain_template.c:66
av_clip
#define av_clip
Definition: common.h:99
r
const char * r
Definition: vf_curves.c:127
generate_grain_y_c
static void FUNC() generate_grain_y_c(entry buf[][GRAIN_WIDTH], const AVFilmGrainParams *const params HBD_DECL)
Definition: aom_film_grain_template.c:74
out
FILE * out
Definition: movenc.c:55
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2965
HBD_DECL
#define HBD_DECL
Definition: aom_film_grain_template.c:69
sample_lut
static entry FUNC() sample_lut(const entry grain_lut[][GRAIN_WIDTH], const int offsets[2][2], const int subx, const int suby, const int bx, const int by, const int x, const int y)
Definition: aom_film_grain_template.c:175
HBD_CALL
#define HBD_CALL
Definition: aom_film_grain_template.c:70
get_random_number
static int get_random_number(const int bits, unsigned *const state)
Definition: aom_film_grain.c:35
bitdepth_max
#define bitdepth_max
Definition: aom_film_grain_template.c:68
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:374
w
uint8_t w
Definition: llviddspenc.c:38
fgy_32x32xn_c
static void FUNC() fgy_32x32xn_c(pixel *const dst_row, const pixel *const src_row, const ptrdiff_t stride, const AVFilmGrainParams *const params, const size_t pw, const uint8_t scaling[SCALING_SIZE], const entry grain_lut[][GRAIN_WIDTH], const int bh, const int row_num HBD_DECL)
Definition: aom_film_grain_template.c:188
bitdepth
#define bitdepth
Definition: aom_film_grain_template.c:67
data
const char data[16]
Definition: mxf.c:148
AVCOL_SPC_RGB
@ AVCOL_SPC_RGB
order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB), YZX and ST 428-1
Definition: pixfmt.h:610
noise
static int noise(AVBSFContext *ctx, AVPacket *pkt)
Definition: noise.c:127
val
static double val(void *priv, double ch)
Definition: aeval.c:78
AVFilmGrainAOMParams
This structure describes how to handle film grain synthesis for AOM codecs.
Definition: film_grain_params.h:44
add_noise_uv
#define add_noise_uv(x, y, grain)
rnd
#define rnd()
Definition: checkasm.h:163
offsets
static const int offsets[]
Definition: hevc_pel.c:34
AV_CEIL_RSHIFT
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:59
apply_film_grain
static int FUNC() apply_film_grain(AVFrame *out_frame, const AVFrame *in_frame, const AVFilmGrainParams *params HBD_DECL)
Definition: aom_film_grain_template.c:545
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:40
SUB_GRAIN_HEIGHT
@ SUB_GRAIN_HEIGHT
Definition: aom_film_grain.c:51
pixel
uint8_t pixel
Definition: tiny_ssim.c:41
GRAIN_HEIGHT
@ GRAIN_HEIGHT
Definition: aom_film_grain.c:49
bit_depth_template.c
FG_BLOCK_SIZE
@ FG_BLOCK_SIZE
Definition: aom_film_grain.c:52
gaussian_sequence
static const int16_t gaussian_sequence[2048]
Definition: aom_film_grain.c:55
seed
static unsigned int seed
Definition: videogen.c:78
SCALING_SIZE
#define SCALING_SIZE
Definition: aom_film_grain_template.c:71
round2
static int round2(const int x, const uint64_t shift)
Definition: aom_film_grain.c:43
generate_grain_uv_c
static void FUNC() generate_grain_uv_c(entry buf[][GRAIN_WIDTH], const entry buf_y[][GRAIN_WIDTH], const AVFilmGrainParams *const params, const intptr_t uv, const int subx, const int suby HBD_DECL)
Definition: aom_film_grain_template.c:114
shift
static int shift(int a, int b)
Definition: bonk.c:261
add_noise_y
#define add_noise_y(x, y, grain)
AVFilmGrainParams
This structure describes how to handle film grain synthesis in video for specific codecs.
Definition: film_grain_params.h:238
avg
#define avg(a, b, c, d)
Definition: colorspacedsp_template.c:28
range
enum AVColorRange range
Definition: mediacodec_wrapper.c:2464
apply_grain_row
static av_always_inline void FUNC() apply_grain_row(AVFrame *out, const AVFrame *in, const int ss_x, const int ss_y, const uint8_t scaling[3][SCALING_SIZE], const entry grain_lut[3][GRAIN_HEIGHT+1][GRAIN_WIDTH], const AVFilmGrainParams *params, const int row HBD_DECL)
Definition: aom_film_grain_template.c:486
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
av_assert1
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:56
delta
float delta
Definition: vorbis_enc_data.h:430
av_always_inline
#define av_always_inline
Definition: attributes.h:49
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
stride
#define stride
Definition: h264pred_template.c:537
SUB_GRAIN_WIDTH
@ SUB_GRAIN_WIDTH
Definition: aom_film_grain.c:50
FUNC
#define FUNC(a)
Definition: bit_depth_template.c:104
desc
const char * desc
Definition: libsvtav1.c:79
generate_scaling
static void FUNC() generate_scaling(const uint8_t points[][2], const int num, uint8_t scaling[SCALING_SIZE] HBD_DECL)
Definition: aom_film_grain_template.c:433
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
d
d
Definition: ffmpeg_filter.c:424
coeff
static const double coeff[2][5]
Definition: vf_owdenoise.c:80
fguv_32x32xn_c
static void FUNC() fguv_32x32xn_c(pixel *const dst_row, const pixel *const src_row, const ptrdiff_t stride, const AVFilmGrainParams *const params, const size_t pw, const uint8_t scaling[SCALING_SIZE], const entry grain_lut[][GRAIN_WIDTH], const int bh, const int row_num, const pixel *const luma_row, const ptrdiff_t luma_stride, const int uv, const int is_id, const int sx, const int sy HBD_DECL)
Definition: aom_film_grain_template.c:302
GRAIN_WIDTH
@ GRAIN_WIDTH
Definition: aom_film_grain.c:48