FFmpeg
Loading...
Searching...
No Matches
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
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
113static 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
175static 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
188static 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
301static void
302FUNC(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
433static 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
485static 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],
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
545static int FUNC(apply_film_grain)(AVFrame *out_frame, const AVFrame *in_frame,
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}
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
SwsAArch64OpImplParams params
Definition ops.c:51
static double val(void *priv, double ch)
Definition aeval.c:77
static int get_random_number(const int bits, unsigned *const state)
static int round2(const int x, const uint64_t shift)
static const int16_t gaussian_sequence[2048]
@ GRAIN_HEIGHT
@ FG_BLOCK_SIZE
@ SUB_GRAIN_HEIGHT
@ SUB_GRAIN_WIDTH
@ GRAIN_WIDTH
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)
static void FUNC generate_grain_y_c(entry buf[][GRAIN_WIDTH], const AVFilmGrainParams *const params HBD_DECL)
static int FUNC apply_film_grain(AVFrame *out_frame, const AVFrame *in_frame, const AVFilmGrainParams *params HBD_DECL)
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)
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)
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)
#define HBD_CALL
#define bitdepth_max
#define bitdepth
#define add_noise_uv(x, y, grain)
#define entry
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)
#define add_noise_y(x, y, grain)
#define SCALING_SIZE
static void FUNC generate_scaling(const uint8_t points[][2], const int num, uint8_t scaling[SCALING_SIZE] HBD_DECL)
#define HBD_DECL
static FILE * out
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition avassert.h:58
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
#define FUNC(a)
#define pixel
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define rnd
Definition checkasm.h:135
#define avg(a, b, c, d)
#define AV_CEIL_RSHIFT(a, b)
Definition common.h:60
#define av_clip
Definition common.h:100
double value
Definition eval.c:102
static const int offsets[]
Definition hevc_pel.c:34
#define r
Definition input.c:42
static int shift(int a, int b)
Definition bonk.c:261
#define av_always_inline
Definition attributes.h:72
const char * desc
Definition libsvtav1.c:83
uint8_t w
Definition llvidencdsp.c:39
#define FFMIN(a, b)
Definition macros.h:49
enum AVColorRange range
const char data[16]
Definition mxf.c:149
static int noise(AVBSFContext *ctx, AVPacket *pkt)
Definition noise.c:124
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
@ AVCOL_SPC_RGB
order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB), YZX and ST 428-1
Definition pixfmt.h:707
This structure describes how to handle film grain synthesis for AOM codecs.
This structure describes how to handle film grain synthesis in video for specific codecs.
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition pixdesc.h:69
#define stride
#define src
Definition vp8dsp.c:248
static const double coeff[2][5]
static unsigned int seed
Definition videogen.c:78
float delta