xref: /aosp_15_r20/external/libaom/examples/noise_model.c (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
1*77c1e3ccSAndroid Build Coastguard Worker /*
2*77c1e3ccSAndroid Build Coastguard Worker  * Copyright (c) 2018, Alliance for Open Media. All rights reserved.
3*77c1e3ccSAndroid Build Coastguard Worker  *
4*77c1e3ccSAndroid Build Coastguard Worker  * This source code is subject to the terms of the BSD 2 Clause License and
5*77c1e3ccSAndroid Build Coastguard Worker  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6*77c1e3ccSAndroid Build Coastguard Worker  * was not distributed with this source code in the LICENSE file, you can
7*77c1e3ccSAndroid Build Coastguard Worker  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8*77c1e3ccSAndroid Build Coastguard Worker  * Media Patent License 1.0 was not distributed with this source code in the
9*77c1e3ccSAndroid Build Coastguard Worker  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10*77c1e3ccSAndroid Build Coastguard Worker  */
11*77c1e3ccSAndroid Build Coastguard Worker 
12*77c1e3ccSAndroid Build Coastguard Worker /*!\file
13*77c1e3ccSAndroid Build Coastguard Worker  * \brief This is an sample binary to create noise params from input video.
14*77c1e3ccSAndroid Build Coastguard Worker  *
15*77c1e3ccSAndroid Build Coastguard Worker  * To allow for external denoising applications, this sample binary illustrates
16*77c1e3ccSAndroid Build Coastguard Worker  * how to create a film grain table (film grain params as a function of time)
17*77c1e3ccSAndroid Build Coastguard Worker  * from an input video and its corresponding denoised source.
18*77c1e3ccSAndroid Build Coastguard Worker  *
19*77c1e3ccSAndroid Build Coastguard Worker  * The --output-grain-table file can be passed as input to the encoder (in
20*77c1e3ccSAndroid Build Coastguard Worker  * aomenc this is done through the "--film-grain-table" parameter).
21*77c1e3ccSAndroid Build Coastguard Worker  *
22*77c1e3ccSAndroid Build Coastguard Worker  * As an example, where the input source is an 854x480 yuv420p 8-bit video
23*77c1e3ccSAndroid Build Coastguard Worker  * named "input.854_480.yuv" you would use steps similar to the following:
24*77c1e3ccSAndroid Build Coastguard Worker  *
25*77c1e3ccSAndroid Build Coastguard Worker  * # Run your denoiser (e.g, using hqdn3d filter):
26*77c1e3ccSAndroid Build Coastguard Worker  * ffmpeg -vcodec rawvideo -video_size 854x480 -i input.854_480.yuv \
27*77c1e3ccSAndroid Build Coastguard Worker  *    -vf hqdn3d=5:5:5:5 -vcodec rawvideo -an -f rawvideo \
28*77c1e3ccSAndroid Build Coastguard Worker  *    denoised.854_480.yuv
29*77c1e3ccSAndroid Build Coastguard Worker  *
30*77c1e3ccSAndroid Build Coastguard Worker  * # Model the noise between the denoised version and original source:
31*77c1e3ccSAndroid Build Coastguard Worker  * ./examples/noise_model --fps=25/1 --width=854 --height=480 --i420 \
32*77c1e3ccSAndroid Build Coastguard Worker  *    --input-denoised=denoised.854_480.yuv --input=original.854_480.yuv \
33*77c1e3ccSAndroid Build Coastguard Worker  *    --output-grain-table=film_grain.tbl
34*77c1e3ccSAndroid Build Coastguard Worker  *
35*77c1e3ccSAndroid Build Coastguard Worker  * # Encode with your favorite settings (including the grain table):
36*77c1e3ccSAndroid Build Coastguard Worker  * aomenc --limit=100  --cpu-used=4 --input-bit-depth=8                  \
37*77c1e3ccSAndroid Build Coastguard Worker  *    --i420 -w 854 -h 480 --end-usage=q --cq-level=25 --lag-in-frames=25 \
38*77c1e3ccSAndroid Build Coastguard Worker  *    --auto-alt-ref=2 --bit-depth=8 --film-grain-table=film_grain.tbl \
39*77c1e3ccSAndroid Build Coastguard Worker  *    -o denoised_with_grain_params.ivf denoised.854_480.yuv
40*77c1e3ccSAndroid Build Coastguard Worker  */
41*77c1e3ccSAndroid Build Coastguard Worker #include <math.h>
42*77c1e3ccSAndroid Build Coastguard Worker #include <stdio.h>
43*77c1e3ccSAndroid Build Coastguard Worker #include <stdlib.h>
44*77c1e3ccSAndroid Build Coastguard Worker #include <string.h>
45*77c1e3ccSAndroid Build Coastguard Worker 
46*77c1e3ccSAndroid Build Coastguard Worker #include "aom/aom_encoder.h"
47*77c1e3ccSAndroid Build Coastguard Worker #include "aom_dsp/aom_dsp_common.h"
48*77c1e3ccSAndroid Build Coastguard Worker 
49*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_AV1_DECODER
50*77c1e3ccSAndroid Build Coastguard Worker #include "av1/decoder/grain_synthesis.h"
51*77c1e3ccSAndroid Build Coastguard Worker #endif
52*77c1e3ccSAndroid Build Coastguard Worker 
53*77c1e3ccSAndroid Build Coastguard Worker #include "aom_dsp/grain_table.h"
54*77c1e3ccSAndroid Build Coastguard Worker #include "aom_dsp/noise_model.h"
55*77c1e3ccSAndroid Build Coastguard Worker #include "aom_dsp/noise_util.h"
56*77c1e3ccSAndroid Build Coastguard Worker #include "aom_mem/aom_mem.h"
57*77c1e3ccSAndroid Build Coastguard Worker #include "common/args.h"
58*77c1e3ccSAndroid Build Coastguard Worker #include "common/tools_common.h"
59*77c1e3ccSAndroid Build Coastguard Worker #include "common/video_writer.h"
60*77c1e3ccSAndroid Build Coastguard Worker 
61*77c1e3ccSAndroid Build Coastguard Worker static const char *exec_name;
62*77c1e3ccSAndroid Build Coastguard Worker 
usage_exit(void)63*77c1e3ccSAndroid Build Coastguard Worker void usage_exit(void) {
64*77c1e3ccSAndroid Build Coastguard Worker   fprintf(stderr,
65*77c1e3ccSAndroid Build Coastguard Worker           "Usage: %s --input=<input> --input-denoised=<denoised> "
66*77c1e3ccSAndroid Build Coastguard Worker           "--output-grain-table=<outfile> "
67*77c1e3ccSAndroid Build Coastguard Worker           "See comments in noise_model.c for more information.\n",
68*77c1e3ccSAndroid Build Coastguard Worker           exec_name);
69*77c1e3ccSAndroid Build Coastguard Worker   exit(EXIT_FAILURE);
70*77c1e3ccSAndroid Build Coastguard Worker }
71*77c1e3ccSAndroid Build Coastguard Worker 
72*77c1e3ccSAndroid Build Coastguard Worker static const arg_def_t help =
73*77c1e3ccSAndroid Build Coastguard Worker     ARG_DEF(NULL, "help", 0, "Show usage options and exit");
74*77c1e3ccSAndroid Build Coastguard Worker static const arg_def_t width_arg =
75*77c1e3ccSAndroid Build Coastguard Worker     ARG_DEF("w", "width", 1, "Input width (if rawvideo)");
76*77c1e3ccSAndroid Build Coastguard Worker static const arg_def_t height_arg =
77*77c1e3ccSAndroid Build Coastguard Worker     ARG_DEF("h", "height", 1, "Input height (if rawvideo)");
78*77c1e3ccSAndroid Build Coastguard Worker static const arg_def_t skip_frames_arg =
79*77c1e3ccSAndroid Build Coastguard Worker     ARG_DEF("s", "skip-frames", 1, "Number of frames to skip (default = 1)");
80*77c1e3ccSAndroid Build Coastguard Worker static const arg_def_t fps_arg = ARG_DEF(NULL, "fps", 1, "Frame rate");
81*77c1e3ccSAndroid Build Coastguard Worker static const arg_def_t input_arg = ARG_DEF("-i", "input", 1, "Input filename");
82*77c1e3ccSAndroid Build Coastguard Worker static const arg_def_t output_grain_table_arg =
83*77c1e3ccSAndroid Build Coastguard Worker     ARG_DEF("n", "output-grain-table", 1, "Output noise file");
84*77c1e3ccSAndroid Build Coastguard Worker static const arg_def_t input_denoised_arg =
85*77c1e3ccSAndroid Build Coastguard Worker     ARG_DEF("d", "input-denoised", 1, "Input denoised filename (YUV) only");
86*77c1e3ccSAndroid Build Coastguard Worker static const arg_def_t flat_block_finder_arg =
87*77c1e3ccSAndroid Build Coastguard Worker     ARG_DEF("b", "flat-block-finder", 1, "Run the flat block finder");
88*77c1e3ccSAndroid Build Coastguard Worker static const arg_def_t block_size_arg =
89*77c1e3ccSAndroid Build Coastguard Worker     ARG_DEF("b", "block-size", 1, "Block size");
90*77c1e3ccSAndroid Build Coastguard Worker static const arg_def_t bit_depth_arg =
91*77c1e3ccSAndroid Build Coastguard Worker     ARG_DEF(NULL, "bit-depth", 1, "Bit depth of input");
92*77c1e3ccSAndroid Build Coastguard Worker static const arg_def_t use_i420 =
93*77c1e3ccSAndroid Build Coastguard Worker     ARG_DEF(NULL, "i420", 0, "Input file (and denoised) is I420 (default)");
94*77c1e3ccSAndroid Build Coastguard Worker static const arg_def_t use_i422 =
95*77c1e3ccSAndroid Build Coastguard Worker     ARG_DEF(NULL, "i422", 0, "Input file (and denoised) is I422");
96*77c1e3ccSAndroid Build Coastguard Worker static const arg_def_t use_i444 =
97*77c1e3ccSAndroid Build Coastguard Worker     ARG_DEF(NULL, "i444", 0, "Input file (and denoised) is I444");
98*77c1e3ccSAndroid Build Coastguard Worker static const arg_def_t debug_file_arg =
99*77c1e3ccSAndroid Build Coastguard Worker     ARG_DEF(NULL, "debug-file", 1, "File to output debug info");
100*77c1e3ccSAndroid Build Coastguard Worker 
101*77c1e3ccSAndroid Build Coastguard Worker typedef struct {
102*77c1e3ccSAndroid Build Coastguard Worker   int width;
103*77c1e3ccSAndroid Build Coastguard Worker   int height;
104*77c1e3ccSAndroid Build Coastguard Worker   struct aom_rational fps;
105*77c1e3ccSAndroid Build Coastguard Worker   const char *input;
106*77c1e3ccSAndroid Build Coastguard Worker   const char *input_denoised;
107*77c1e3ccSAndroid Build Coastguard Worker   const char *output_grain_table;
108*77c1e3ccSAndroid Build Coastguard Worker   int img_fmt;
109*77c1e3ccSAndroid Build Coastguard Worker   int block_size;
110*77c1e3ccSAndroid Build Coastguard Worker   int bit_depth;
111*77c1e3ccSAndroid Build Coastguard Worker   int run_flat_block_finder;
112*77c1e3ccSAndroid Build Coastguard Worker   int force_flat_psd;
113*77c1e3ccSAndroid Build Coastguard Worker   int skip_frames;
114*77c1e3ccSAndroid Build Coastguard Worker   const char *debug_file;
115*77c1e3ccSAndroid Build Coastguard Worker } noise_model_args_t;
116*77c1e3ccSAndroid Build Coastguard Worker 
parse_args(noise_model_args_t * noise_args,char ** argv)117*77c1e3ccSAndroid Build Coastguard Worker static void parse_args(noise_model_args_t *noise_args, char **argv) {
118*77c1e3ccSAndroid Build Coastguard Worker   struct arg arg;
119*77c1e3ccSAndroid Build Coastguard Worker   static const arg_def_t *main_args[] = { &help,
120*77c1e3ccSAndroid Build Coastguard Worker                                           &input_arg,
121*77c1e3ccSAndroid Build Coastguard Worker                                           &fps_arg,
122*77c1e3ccSAndroid Build Coastguard Worker                                           &width_arg,
123*77c1e3ccSAndroid Build Coastguard Worker                                           &height_arg,
124*77c1e3ccSAndroid Build Coastguard Worker                                           &block_size_arg,
125*77c1e3ccSAndroid Build Coastguard Worker                                           &output_grain_table_arg,
126*77c1e3ccSAndroid Build Coastguard Worker                                           &input_denoised_arg,
127*77c1e3ccSAndroid Build Coastguard Worker                                           &use_i420,
128*77c1e3ccSAndroid Build Coastguard Worker                                           &use_i422,
129*77c1e3ccSAndroid Build Coastguard Worker                                           &use_i444,
130*77c1e3ccSAndroid Build Coastguard Worker                                           &debug_file_arg,
131*77c1e3ccSAndroid Build Coastguard Worker                                           NULL };
132*77c1e3ccSAndroid Build Coastguard Worker   for (; *argv; argv++) {
133*77c1e3ccSAndroid Build Coastguard Worker     if (arg_match(&arg, &help, argv)) {
134*77c1e3ccSAndroid Build Coastguard Worker       fprintf(stdout, "\nOptions:\n");
135*77c1e3ccSAndroid Build Coastguard Worker       arg_show_usage(stdout, main_args);
136*77c1e3ccSAndroid Build Coastguard Worker       exit(0);
137*77c1e3ccSAndroid Build Coastguard Worker     } else if (arg_match(&arg, &width_arg, argv)) {
138*77c1e3ccSAndroid Build Coastguard Worker       noise_args->width = atoi(arg.val);
139*77c1e3ccSAndroid Build Coastguard Worker     } else if (arg_match(&arg, &height_arg, argv)) {
140*77c1e3ccSAndroid Build Coastguard Worker       noise_args->height = atoi(arg.val);
141*77c1e3ccSAndroid Build Coastguard Worker     } else if (arg_match(&arg, &input_arg, argv)) {
142*77c1e3ccSAndroid Build Coastguard Worker       noise_args->input = arg.val;
143*77c1e3ccSAndroid Build Coastguard Worker     } else if (arg_match(&arg, &input_denoised_arg, argv)) {
144*77c1e3ccSAndroid Build Coastguard Worker       noise_args->input_denoised = arg.val;
145*77c1e3ccSAndroid Build Coastguard Worker     } else if (arg_match(&arg, &output_grain_table_arg, argv)) {
146*77c1e3ccSAndroid Build Coastguard Worker       noise_args->output_grain_table = arg.val;
147*77c1e3ccSAndroid Build Coastguard Worker     } else if (arg_match(&arg, &block_size_arg, argv)) {
148*77c1e3ccSAndroid Build Coastguard Worker       noise_args->block_size = atoi(arg.val);
149*77c1e3ccSAndroid Build Coastguard Worker     } else if (arg_match(&arg, &bit_depth_arg, argv)) {
150*77c1e3ccSAndroid Build Coastguard Worker       noise_args->bit_depth = atoi(arg.val);
151*77c1e3ccSAndroid Build Coastguard Worker     } else if (arg_match(&arg, &flat_block_finder_arg, argv)) {
152*77c1e3ccSAndroid Build Coastguard Worker       noise_args->run_flat_block_finder = atoi(arg.val);
153*77c1e3ccSAndroid Build Coastguard Worker     } else if (arg_match(&arg, &fps_arg, argv)) {
154*77c1e3ccSAndroid Build Coastguard Worker       noise_args->fps = arg_parse_rational(&arg);
155*77c1e3ccSAndroid Build Coastguard Worker     } else if (arg_match(&arg, &use_i420, argv)) {
156*77c1e3ccSAndroid Build Coastguard Worker       noise_args->img_fmt = AOM_IMG_FMT_I420;
157*77c1e3ccSAndroid Build Coastguard Worker     } else if (arg_match(&arg, &use_i422, argv)) {
158*77c1e3ccSAndroid Build Coastguard Worker       noise_args->img_fmt = AOM_IMG_FMT_I422;
159*77c1e3ccSAndroid Build Coastguard Worker     } else if (arg_match(&arg, &use_i444, argv)) {
160*77c1e3ccSAndroid Build Coastguard Worker       noise_args->img_fmt = AOM_IMG_FMT_I444;
161*77c1e3ccSAndroid Build Coastguard Worker     } else if (arg_match(&arg, &skip_frames_arg, argv)) {
162*77c1e3ccSAndroid Build Coastguard Worker       noise_args->skip_frames = atoi(arg.val);
163*77c1e3ccSAndroid Build Coastguard Worker     } else if (arg_match(&arg, &debug_file_arg, argv)) {
164*77c1e3ccSAndroid Build Coastguard Worker       noise_args->debug_file = arg.val;
165*77c1e3ccSAndroid Build Coastguard Worker     } else {
166*77c1e3ccSAndroid Build Coastguard Worker       fprintf(stdout, "Unknown arg: %s\n\nUsage:\n", *argv);
167*77c1e3ccSAndroid Build Coastguard Worker       arg_show_usage(stdout, main_args);
168*77c1e3ccSAndroid Build Coastguard Worker       exit(0);
169*77c1e3ccSAndroid Build Coastguard Worker     }
170*77c1e3ccSAndroid Build Coastguard Worker   }
171*77c1e3ccSAndroid Build Coastguard Worker   if (noise_args->bit_depth > 8) {
172*77c1e3ccSAndroid Build Coastguard Worker     noise_args->img_fmt |= AOM_IMG_FMT_HIGHBITDEPTH;
173*77c1e3ccSAndroid Build Coastguard Worker   }
174*77c1e3ccSAndroid Build Coastguard Worker }
175*77c1e3ccSAndroid Build Coastguard Worker 
176*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_AV1_DECODER
print_variance_y(FILE * debug_file,aom_image_t * raw,aom_image_t * denoised,const uint8_t * flat_blocks,int block_size,aom_film_grain_t * grain)177*77c1e3ccSAndroid Build Coastguard Worker static void print_variance_y(FILE *debug_file, aom_image_t *raw,
178*77c1e3ccSAndroid Build Coastguard Worker                              aom_image_t *denoised, const uint8_t *flat_blocks,
179*77c1e3ccSAndroid Build Coastguard Worker                              int block_size, aom_film_grain_t *grain) {
180*77c1e3ccSAndroid Build Coastguard Worker   aom_image_t renoised;
181*77c1e3ccSAndroid Build Coastguard Worker   grain->apply_grain = 1;
182*77c1e3ccSAndroid Build Coastguard Worker   grain->random_seed = 7391;
183*77c1e3ccSAndroid Build Coastguard Worker   grain->bit_depth = raw->bit_depth;
184*77c1e3ccSAndroid Build Coastguard Worker   aom_img_alloc(&renoised, raw->fmt, raw->w, raw->h, 1);
185*77c1e3ccSAndroid Build Coastguard Worker 
186*77c1e3ccSAndroid Build Coastguard Worker   if (av1_add_film_grain(grain, denoised, &renoised)) {
187*77c1e3ccSAndroid Build Coastguard Worker     fprintf(stderr, "Internal failure in av1_add_film_grain().\n");
188*77c1e3ccSAndroid Build Coastguard Worker     aom_img_free(&renoised);
189*77c1e3ccSAndroid Build Coastguard Worker     return;
190*77c1e3ccSAndroid Build Coastguard Worker   }
191*77c1e3ccSAndroid Build Coastguard Worker 
192*77c1e3ccSAndroid Build Coastguard Worker   const int num_blocks_w = (raw->w + block_size - 1) / block_size;
193*77c1e3ccSAndroid Build Coastguard Worker   const int num_blocks_h = (raw->h + block_size - 1) / block_size;
194*77c1e3ccSAndroid Build Coastguard Worker   fprintf(debug_file, "x = [");
195*77c1e3ccSAndroid Build Coastguard Worker   for (int by = 0; by < num_blocks_h; by++) {
196*77c1e3ccSAndroid Build Coastguard Worker     for (int bx = 0; bx < num_blocks_w; bx++) {
197*77c1e3ccSAndroid Build Coastguard Worker       double block_mean = 0;
198*77c1e3ccSAndroid Build Coastguard Worker       double noise_std = 0, noise_mean = 0;
199*77c1e3ccSAndroid Build Coastguard Worker       double renoise_std = 0, renoise_mean = 0;
200*77c1e3ccSAndroid Build Coastguard Worker       for (int yi = 0; yi < block_size; ++yi) {
201*77c1e3ccSAndroid Build Coastguard Worker         const int y = by * block_size + yi;
202*77c1e3ccSAndroid Build Coastguard Worker         for (int xi = 0; xi < block_size; ++xi) {
203*77c1e3ccSAndroid Build Coastguard Worker           const int x = bx * block_size + xi;
204*77c1e3ccSAndroid Build Coastguard Worker           const double noise_v = (raw->planes[0][y * raw->stride[0] + x] -
205*77c1e3ccSAndroid Build Coastguard Worker                                   denoised->planes[0][y * raw->stride[0] + x]);
206*77c1e3ccSAndroid Build Coastguard Worker           noise_mean += noise_v;
207*77c1e3ccSAndroid Build Coastguard Worker           noise_std += noise_v * noise_v;
208*77c1e3ccSAndroid Build Coastguard Worker 
209*77c1e3ccSAndroid Build Coastguard Worker           block_mean += raw->planes[0][y * raw->stride[0] + x];
210*77c1e3ccSAndroid Build Coastguard Worker 
211*77c1e3ccSAndroid Build Coastguard Worker           const double renoise_v =
212*77c1e3ccSAndroid Build Coastguard Worker               (renoised.planes[0][y * raw->stride[0] + x] -
213*77c1e3ccSAndroid Build Coastguard Worker                denoised->planes[0][y * raw->stride[0] + x]);
214*77c1e3ccSAndroid Build Coastguard Worker           renoise_mean += renoise_v;
215*77c1e3ccSAndroid Build Coastguard Worker           renoise_std += renoise_v * renoise_v;
216*77c1e3ccSAndroid Build Coastguard Worker         }
217*77c1e3ccSAndroid Build Coastguard Worker       }
218*77c1e3ccSAndroid Build Coastguard Worker       int n = (block_size * block_size);
219*77c1e3ccSAndroid Build Coastguard Worker       block_mean /= n;
220*77c1e3ccSAndroid Build Coastguard Worker       noise_mean /= n;
221*77c1e3ccSAndroid Build Coastguard Worker       renoise_mean /= n;
222*77c1e3ccSAndroid Build Coastguard Worker       noise_std = sqrt(noise_std / n - noise_mean * noise_mean);
223*77c1e3ccSAndroid Build Coastguard Worker       renoise_std = sqrt(renoise_std / n - renoise_mean * renoise_mean);
224*77c1e3ccSAndroid Build Coastguard Worker       fprintf(debug_file, "%d %3.2lf %3.2lf %3.2lf  ",
225*77c1e3ccSAndroid Build Coastguard Worker               flat_blocks[by * num_blocks_w + bx], block_mean, noise_std,
226*77c1e3ccSAndroid Build Coastguard Worker               renoise_std);
227*77c1e3ccSAndroid Build Coastguard Worker     }
228*77c1e3ccSAndroid Build Coastguard Worker     fprintf(debug_file, "\n");
229*77c1e3ccSAndroid Build Coastguard Worker   }
230*77c1e3ccSAndroid Build Coastguard Worker   fprintf(debug_file, "];\n");
231*77c1e3ccSAndroid Build Coastguard Worker 
232*77c1e3ccSAndroid Build Coastguard Worker   if (raw->fmt & AOM_IMG_FMT_HIGHBITDEPTH) {
233*77c1e3ccSAndroid Build Coastguard Worker     fprintf(stderr,
234*77c1e3ccSAndroid Build Coastguard Worker             "Detailed debug info not supported for high bit"
235*77c1e3ccSAndroid Build Coastguard Worker             "depth formats\n");
236*77c1e3ccSAndroid Build Coastguard Worker   } else {
237*77c1e3ccSAndroid Build Coastguard Worker     fprintf(debug_file, "figure(2); clf;\n");
238*77c1e3ccSAndroid Build Coastguard Worker     fprintf(debug_file,
239*77c1e3ccSAndroid Build Coastguard Worker             "scatter(x(:, 2:4:end), x(:, 3:4:end), 'r'); hold on;\n");
240*77c1e3ccSAndroid Build Coastguard Worker     fprintf(debug_file, "scatter(x(:, 2:4:end), x(:, 4:4:end), 'b');\n");
241*77c1e3ccSAndroid Build Coastguard Worker     fprintf(debug_file,
242*77c1e3ccSAndroid Build Coastguard Worker             "plot(linspace(0, 255, length(noise_strength_0)), "
243*77c1e3ccSAndroid Build Coastguard Worker             "noise_strength_0, 'b');\n");
244*77c1e3ccSAndroid Build Coastguard Worker     fprintf(debug_file,
245*77c1e3ccSAndroid Build Coastguard Worker             "title('Scatter plot of intensity vs noise strength');\n");
246*77c1e3ccSAndroid Build Coastguard Worker     fprintf(debug_file,
247*77c1e3ccSAndroid Build Coastguard Worker             "legend('Actual', 'Estimated', 'Estimated strength');\n");
248*77c1e3ccSAndroid Build Coastguard Worker     fprintf(debug_file, "figure(3); clf;\n");
249*77c1e3ccSAndroid Build Coastguard Worker     fprintf(debug_file, "scatter(x(:, 3:4:end), x(:, 4:4:end), 'k');\n");
250*77c1e3ccSAndroid Build Coastguard Worker     fprintf(debug_file, "title('Actual vs Estimated');\n");
251*77c1e3ccSAndroid Build Coastguard Worker     fprintf(debug_file, "pause(3);\n");
252*77c1e3ccSAndroid Build Coastguard Worker   }
253*77c1e3ccSAndroid Build Coastguard Worker   aom_img_free(&renoised);
254*77c1e3ccSAndroid Build Coastguard Worker }
255*77c1e3ccSAndroid Build Coastguard Worker #endif
256*77c1e3ccSAndroid Build Coastguard Worker 
print_debug_info(FILE * debug_file,aom_image_t * raw,aom_image_t * denoised,uint8_t * flat_blocks,int block_size,aom_noise_model_t * noise_model)257*77c1e3ccSAndroid Build Coastguard Worker static void print_debug_info(FILE *debug_file, aom_image_t *raw,
258*77c1e3ccSAndroid Build Coastguard Worker                              aom_image_t *denoised, uint8_t *flat_blocks,
259*77c1e3ccSAndroid Build Coastguard Worker                              int block_size, aom_noise_model_t *noise_model) {
260*77c1e3ccSAndroid Build Coastguard Worker   (void)raw;
261*77c1e3ccSAndroid Build Coastguard Worker   (void)denoised;
262*77c1e3ccSAndroid Build Coastguard Worker   (void)flat_blocks;
263*77c1e3ccSAndroid Build Coastguard Worker   (void)block_size;
264*77c1e3ccSAndroid Build Coastguard Worker   fprintf(debug_file, "figure(3); clf;\n");
265*77c1e3ccSAndroid Build Coastguard Worker   fprintf(debug_file, "figure(2); clf;\n");
266*77c1e3ccSAndroid Build Coastguard Worker   fprintf(debug_file, "figure(1); clf;\n");
267*77c1e3ccSAndroid Build Coastguard Worker   for (int c = 0; c < 3; ++c) {
268*77c1e3ccSAndroid Build Coastguard Worker     fprintf(debug_file, "noise_strength_%d = [\n", c);
269*77c1e3ccSAndroid Build Coastguard Worker     const aom_equation_system_t *eqns =
270*77c1e3ccSAndroid Build Coastguard Worker         &noise_model->combined_state[c].strength_solver.eqns;
271*77c1e3ccSAndroid Build Coastguard Worker     for (int k = 0; k < eqns->n; ++k) {
272*77c1e3ccSAndroid Build Coastguard Worker       fprintf(debug_file, "%lf ", eqns->x[k]);
273*77c1e3ccSAndroid Build Coastguard Worker     }
274*77c1e3ccSAndroid Build Coastguard Worker     fprintf(debug_file, "];\n");
275*77c1e3ccSAndroid Build Coastguard Worker     fprintf(debug_file, "plot(noise_strength_%d); hold on;\n", c);
276*77c1e3ccSAndroid Build Coastguard Worker   }
277*77c1e3ccSAndroid Build Coastguard Worker   fprintf(debug_file, "legend('Y', 'cb', 'cr');\n");
278*77c1e3ccSAndroid Build Coastguard Worker   fprintf(debug_file, "title('Noise strength function');\n");
279*77c1e3ccSAndroid Build Coastguard Worker 
280*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_AV1_DECODER
281*77c1e3ccSAndroid Build Coastguard Worker   aom_film_grain_t grain;
282*77c1e3ccSAndroid Build Coastguard Worker   aom_noise_model_get_grain_parameters(noise_model, &grain);
283*77c1e3ccSAndroid Build Coastguard Worker   print_variance_y(debug_file, raw, denoised, flat_blocks, block_size, &grain);
284*77c1e3ccSAndroid Build Coastguard Worker #endif
285*77c1e3ccSAndroid Build Coastguard Worker   fflush(debug_file);
286*77c1e3ccSAndroid Build Coastguard Worker }
287*77c1e3ccSAndroid Build Coastguard Worker 
main(int argc,char * argv[])288*77c1e3ccSAndroid Build Coastguard Worker int main(int argc, char *argv[]) {
289*77c1e3ccSAndroid Build Coastguard Worker   noise_model_args_t args = { 0,  0, { 25, 1 }, 0, 0, 0,   AOM_IMG_FMT_I420,
290*77c1e3ccSAndroid Build Coastguard Worker                               32, 8, 1,         0, 1, NULL };
291*77c1e3ccSAndroid Build Coastguard Worker   aom_image_t raw, denoised;
292*77c1e3ccSAndroid Build Coastguard Worker   FILE *infile = NULL;
293*77c1e3ccSAndroid Build Coastguard Worker   AvxVideoInfo info;
294*77c1e3ccSAndroid Build Coastguard Worker 
295*77c1e3ccSAndroid Build Coastguard Worker   memset(&info, 0, sizeof(info));
296*77c1e3ccSAndroid Build Coastguard Worker 
297*77c1e3ccSAndroid Build Coastguard Worker   (void)argc;
298*77c1e3ccSAndroid Build Coastguard Worker   exec_name = argv[0];
299*77c1e3ccSAndroid Build Coastguard Worker   parse_args(&args, argv + 1);
300*77c1e3ccSAndroid Build Coastguard Worker 
301*77c1e3ccSAndroid Build Coastguard Worker   info.frame_width = args.width;
302*77c1e3ccSAndroid Build Coastguard Worker   info.frame_height = args.height;
303*77c1e3ccSAndroid Build Coastguard Worker   info.time_base.numerator = args.fps.den;
304*77c1e3ccSAndroid Build Coastguard Worker   info.time_base.denominator = args.fps.num;
305*77c1e3ccSAndroid Build Coastguard Worker 
306*77c1e3ccSAndroid Build Coastguard Worker   if (info.frame_width <= 0 || info.frame_height <= 0 ||
307*77c1e3ccSAndroid Build Coastguard Worker       (info.frame_width % 2) != 0 || (info.frame_height % 2) != 0) {
308*77c1e3ccSAndroid Build Coastguard Worker     die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
309*77c1e3ccSAndroid Build Coastguard Worker   }
310*77c1e3ccSAndroid Build Coastguard Worker   if (!aom_img_alloc(&raw, args.img_fmt, info.frame_width, info.frame_height,
311*77c1e3ccSAndroid Build Coastguard Worker                      1)) {
312*77c1e3ccSAndroid Build Coastguard Worker     die("Failed to allocate image.");
313*77c1e3ccSAndroid Build Coastguard Worker   }
314*77c1e3ccSAndroid Build Coastguard Worker   if (!aom_img_alloc(&denoised, args.img_fmt, info.frame_width,
315*77c1e3ccSAndroid Build Coastguard Worker                      info.frame_height, 1)) {
316*77c1e3ccSAndroid Build Coastguard Worker     die("Failed to allocate image.");
317*77c1e3ccSAndroid Build Coastguard Worker   }
318*77c1e3ccSAndroid Build Coastguard Worker   infile = fopen(args.input, "rb");
319*77c1e3ccSAndroid Build Coastguard Worker   if (!infile) {
320*77c1e3ccSAndroid Build Coastguard Worker     die("Failed to open input file: %s", args.input);
321*77c1e3ccSAndroid Build Coastguard Worker   }
322*77c1e3ccSAndroid Build Coastguard Worker   fprintf(stderr, "Bit depth: %d  stride:%d\n", args.bit_depth, raw.stride[0]);
323*77c1e3ccSAndroid Build Coastguard Worker 
324*77c1e3ccSAndroid Build Coastguard Worker   const int high_bd = args.bit_depth > 8;
325*77c1e3ccSAndroid Build Coastguard Worker   const int block_size = args.block_size;
326*77c1e3ccSAndroid Build Coastguard Worker   aom_flat_block_finder_t block_finder;
327*77c1e3ccSAndroid Build Coastguard Worker   aom_flat_block_finder_init(&block_finder, block_size, args.bit_depth,
328*77c1e3ccSAndroid Build Coastguard Worker                              high_bd);
329*77c1e3ccSAndroid Build Coastguard Worker 
330*77c1e3ccSAndroid Build Coastguard Worker   const int num_blocks_w = (info.frame_width + block_size - 1) / block_size;
331*77c1e3ccSAndroid Build Coastguard Worker   const int num_blocks_h = (info.frame_height + block_size - 1) / block_size;
332*77c1e3ccSAndroid Build Coastguard Worker   uint8_t *flat_blocks = (uint8_t *)aom_malloc(num_blocks_w * num_blocks_h);
333*77c1e3ccSAndroid Build Coastguard Worker   if (!flat_blocks) die("Failed to allocate block data.");
334*77c1e3ccSAndroid Build Coastguard Worker   // Sets the random seed on the first entry in the output table
335*77c1e3ccSAndroid Build Coastguard Worker   int16_t random_seed = 7391;
336*77c1e3ccSAndroid Build Coastguard Worker   aom_noise_model_t noise_model;
337*77c1e3ccSAndroid Build Coastguard Worker   aom_noise_model_params_t params = { AOM_NOISE_SHAPE_SQUARE, 3, args.bit_depth,
338*77c1e3ccSAndroid Build Coastguard Worker                                       high_bd };
339*77c1e3ccSAndroid Build Coastguard Worker   aom_noise_model_init(&noise_model, params);
340*77c1e3ccSAndroid Build Coastguard Worker 
341*77c1e3ccSAndroid Build Coastguard Worker   FILE *denoised_file = 0;
342*77c1e3ccSAndroid Build Coastguard Worker   if (args.input_denoised) {
343*77c1e3ccSAndroid Build Coastguard Worker     denoised_file = fopen(args.input_denoised, "rb");
344*77c1e3ccSAndroid Build Coastguard Worker     if (!denoised_file)
345*77c1e3ccSAndroid Build Coastguard Worker       die("Unable to open input_denoised: %s", args.input_denoised);
346*77c1e3ccSAndroid Build Coastguard Worker   } else {
347*77c1e3ccSAndroid Build Coastguard Worker     die("--input-denoised file must be specified");
348*77c1e3ccSAndroid Build Coastguard Worker   }
349*77c1e3ccSAndroid Build Coastguard Worker   FILE *debug_file = 0;
350*77c1e3ccSAndroid Build Coastguard Worker   if (args.debug_file) {
351*77c1e3ccSAndroid Build Coastguard Worker     debug_file = fopen(args.debug_file, "w");
352*77c1e3ccSAndroid Build Coastguard Worker   }
353*77c1e3ccSAndroid Build Coastguard Worker   aom_film_grain_table_t grain_table = { 0, 0 };
354*77c1e3ccSAndroid Build Coastguard Worker 
355*77c1e3ccSAndroid Build Coastguard Worker   int64_t prev_timestamp = 0;
356*77c1e3ccSAndroid Build Coastguard Worker   int frame_count = 0;
357*77c1e3ccSAndroid Build Coastguard Worker   while (aom_img_read(&raw, infile)) {
358*77c1e3ccSAndroid Build Coastguard Worker     if (args.input_denoised) {
359*77c1e3ccSAndroid Build Coastguard Worker       if (!aom_img_read(&denoised, denoised_file)) {
360*77c1e3ccSAndroid Build Coastguard Worker         die("Unable to read input denoised file");
361*77c1e3ccSAndroid Build Coastguard Worker       }
362*77c1e3ccSAndroid Build Coastguard Worker     }
363*77c1e3ccSAndroid Build Coastguard Worker     if (frame_count % args.skip_frames == 0) {
364*77c1e3ccSAndroid Build Coastguard Worker       int num_flat_blocks = num_blocks_w * num_blocks_h;
365*77c1e3ccSAndroid Build Coastguard Worker       memset(flat_blocks, 1, num_flat_blocks);
366*77c1e3ccSAndroid Build Coastguard Worker       if (args.run_flat_block_finder) {
367*77c1e3ccSAndroid Build Coastguard Worker         memset(flat_blocks, 0, num_flat_blocks);
368*77c1e3ccSAndroid Build Coastguard Worker         num_flat_blocks = aom_flat_block_finder_run(
369*77c1e3ccSAndroid Build Coastguard Worker             &block_finder, raw.planes[0], info.frame_width, info.frame_height,
370*77c1e3ccSAndroid Build Coastguard Worker             info.frame_width, flat_blocks);
371*77c1e3ccSAndroid Build Coastguard Worker         fprintf(stdout, "Num flat blocks %d\n", num_flat_blocks);
372*77c1e3ccSAndroid Build Coastguard Worker       }
373*77c1e3ccSAndroid Build Coastguard Worker 
374*77c1e3ccSAndroid Build Coastguard Worker       const uint8_t *planes[3] = { raw.planes[0], raw.planes[1],
375*77c1e3ccSAndroid Build Coastguard Worker                                    raw.planes[2] };
376*77c1e3ccSAndroid Build Coastguard Worker       uint8_t *denoised_planes[3] = { denoised.planes[0], denoised.planes[1],
377*77c1e3ccSAndroid Build Coastguard Worker                                       denoised.planes[2] };
378*77c1e3ccSAndroid Build Coastguard Worker       int strides[3] = { raw.stride[0] >> high_bd, raw.stride[1] >> high_bd,
379*77c1e3ccSAndroid Build Coastguard Worker                          raw.stride[2] >> high_bd };
380*77c1e3ccSAndroid Build Coastguard Worker       int chroma_sub[3] = { raw.x_chroma_shift, raw.y_chroma_shift, 0 };
381*77c1e3ccSAndroid Build Coastguard Worker 
382*77c1e3ccSAndroid Build Coastguard Worker       fprintf(stdout, "Updating noise model...\n");
383*77c1e3ccSAndroid Build Coastguard Worker       aom_noise_status_t status = aom_noise_model_update(
384*77c1e3ccSAndroid Build Coastguard Worker           &noise_model, (const uint8_t *const *)planes,
385*77c1e3ccSAndroid Build Coastguard Worker           (const uint8_t *const *)denoised_planes, info.frame_width,
386*77c1e3ccSAndroid Build Coastguard Worker           info.frame_height, strides, chroma_sub, flat_blocks, block_size);
387*77c1e3ccSAndroid Build Coastguard Worker 
388*77c1e3ccSAndroid Build Coastguard Worker       int64_t cur_timestamp =
389*77c1e3ccSAndroid Build Coastguard Worker           frame_count * 10000000ULL * args.fps.den / args.fps.num;
390*77c1e3ccSAndroid Build Coastguard Worker       if (status == AOM_NOISE_STATUS_DIFFERENT_NOISE_TYPE) {
391*77c1e3ccSAndroid Build Coastguard Worker         fprintf(stdout,
392*77c1e3ccSAndroid Build Coastguard Worker                 "Noise type is different, updating parameters for time "
393*77c1e3ccSAndroid Build Coastguard Worker                 "[ %" PRId64 ", %" PRId64 ")\n",
394*77c1e3ccSAndroid Build Coastguard Worker                 prev_timestamp, cur_timestamp);
395*77c1e3ccSAndroid Build Coastguard Worker         aom_film_grain_t grain;
396*77c1e3ccSAndroid Build Coastguard Worker         aom_noise_model_get_grain_parameters(&noise_model, &grain);
397*77c1e3ccSAndroid Build Coastguard Worker         grain.random_seed = random_seed;
398*77c1e3ccSAndroid Build Coastguard Worker         random_seed = 0;
399*77c1e3ccSAndroid Build Coastguard Worker         aom_film_grain_table_append(&grain_table, prev_timestamp, cur_timestamp,
400*77c1e3ccSAndroid Build Coastguard Worker                                     &grain);
401*77c1e3ccSAndroid Build Coastguard Worker         aom_noise_model_save_latest(&noise_model);
402*77c1e3ccSAndroid Build Coastguard Worker         prev_timestamp = cur_timestamp;
403*77c1e3ccSAndroid Build Coastguard Worker       }
404*77c1e3ccSAndroid Build Coastguard Worker       if (debug_file) {
405*77c1e3ccSAndroid Build Coastguard Worker         print_debug_info(debug_file, &raw, &denoised, flat_blocks, block_size,
406*77c1e3ccSAndroid Build Coastguard Worker                          &noise_model);
407*77c1e3ccSAndroid Build Coastguard Worker       }
408*77c1e3ccSAndroid Build Coastguard Worker       fprintf(stdout, "Done noise model update, status = %d\n", status);
409*77c1e3ccSAndroid Build Coastguard Worker     }
410*77c1e3ccSAndroid Build Coastguard Worker     frame_count++;
411*77c1e3ccSAndroid Build Coastguard Worker   }
412*77c1e3ccSAndroid Build Coastguard Worker 
413*77c1e3ccSAndroid Build Coastguard Worker   aom_film_grain_t grain;
414*77c1e3ccSAndroid Build Coastguard Worker   aom_noise_model_get_grain_parameters(&noise_model, &grain);
415*77c1e3ccSAndroid Build Coastguard Worker   grain.random_seed = random_seed;
416*77c1e3ccSAndroid Build Coastguard Worker   aom_film_grain_table_append(&grain_table, prev_timestamp, INT64_MAX, &grain);
417*77c1e3ccSAndroid Build Coastguard Worker   if (args.output_grain_table) {
418*77c1e3ccSAndroid Build Coastguard Worker     struct aom_internal_error_info error_info;
419*77c1e3ccSAndroid Build Coastguard Worker     if (AOM_CODEC_OK != aom_film_grain_table_write(&grain_table,
420*77c1e3ccSAndroid Build Coastguard Worker                                                    args.output_grain_table,
421*77c1e3ccSAndroid Build Coastguard Worker                                                    &error_info)) {
422*77c1e3ccSAndroid Build Coastguard Worker       die("Unable to write output film grain table");
423*77c1e3ccSAndroid Build Coastguard Worker     }
424*77c1e3ccSAndroid Build Coastguard Worker   }
425*77c1e3ccSAndroid Build Coastguard Worker   aom_film_grain_table_free(&grain_table);
426*77c1e3ccSAndroid Build Coastguard Worker 
427*77c1e3ccSAndroid Build Coastguard Worker   if (infile) fclose(infile);
428*77c1e3ccSAndroid Build Coastguard Worker   if (denoised_file) fclose(denoised_file);
429*77c1e3ccSAndroid Build Coastguard Worker   if (debug_file) fclose(debug_file);
430*77c1e3ccSAndroid Build Coastguard Worker   aom_img_free(&raw);
431*77c1e3ccSAndroid Build Coastguard Worker   aom_img_free(&denoised);
432*77c1e3ccSAndroid Build Coastguard Worker 
433*77c1e3ccSAndroid Build Coastguard Worker   return EXIT_SUCCESS;
434*77c1e3ccSAndroid Build Coastguard Worker }
435