xref: /aosp_15_r20/external/libaom/av1/encoder/saliency_map.c (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
1*77c1e3ccSAndroid Build Coastguard Worker /*
2*77c1e3ccSAndroid Build Coastguard Worker  * Copyright (c) 2023, 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 #include <assert.h>
12*77c1e3ccSAndroid Build Coastguard Worker #include <float.h>
13*77c1e3ccSAndroid Build Coastguard Worker #include <string.h>
14*77c1e3ccSAndroid Build Coastguard Worker 
15*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/encoder.h"
16*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/encoder_utils.h"
17*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/firstpass.h"
18*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/rdopt.h"
19*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/saliency_map.h"
20*77c1e3ccSAndroid Build Coastguard Worker 
21*77c1e3ccSAndroid Build Coastguard Worker // The Gabor filter is generated by setting the parameters as:
22*77c1e3ccSAndroid Build Coastguard Worker // ksize = 9
23*77c1e3ccSAndroid Build Coastguard Worker // sigma = 1
24*77c1e3ccSAndroid Build Coastguard Worker // theta = y*np.pi/4, where y /in {0, 1, 2, 3}, i.e., 0, 45, 90, 135 degree
25*77c1e3ccSAndroid Build Coastguard Worker // lambda1 = 1
26*77c1e3ccSAndroid Build Coastguard Worker // gamma=0.8
27*77c1e3ccSAndroid Build Coastguard Worker // phi =0
28*77c1e3ccSAndroid Build Coastguard Worker static const double kGaborFilter[4][9][9] = {  // [angle: 0, 45, 90, 135
29*77c1e3ccSAndroid Build Coastguard Worker                                                // degree][ksize][ksize]
30*77c1e3ccSAndroid Build Coastguard Worker   { { 2.0047323e-06, 6.6387620e-05, 8.0876675e-04, 3.6246411e-03, 5.9760227e-03,
31*77c1e3ccSAndroid Build Coastguard Worker       3.6246411e-03, 8.0876675e-04, 6.6387620e-05, 2.0047323e-06 },
32*77c1e3ccSAndroid Build Coastguard Worker     { 1.8831115e-05, 6.2360091e-04, 7.5970138e-03, 3.4047455e-02, 5.6134764e-02,
33*77c1e3ccSAndroid Build Coastguard Worker       3.4047455e-02, 7.5970138e-03, 6.2360091e-04, 1.8831115e-05 },
34*77c1e3ccSAndroid Build Coastguard Worker     { 9.3271126e-05, 3.0887155e-03, 3.7628256e-02, 1.6863814e-01, 2.7803731e-01,
35*77c1e3ccSAndroid Build Coastguard Worker       1.6863814e-01, 3.7628256e-02, 3.0887155e-03, 9.3271126e-05 },
36*77c1e3ccSAndroid Build Coastguard Worker     { 2.4359586e-04, 8.0667874e-03, 9.8273583e-02, 4.4043165e-01, 7.2614902e-01,
37*77c1e3ccSAndroid Build Coastguard Worker       4.4043165e-01, 9.8273583e-02, 8.0667874e-03, 2.4359586e-04 },
38*77c1e3ccSAndroid Build Coastguard Worker     { 3.3546262e-04, 1.1108996e-02, 1.3533528e-01, 6.0653067e-01, 1.0000000e+00,
39*77c1e3ccSAndroid Build Coastguard Worker       6.0653067e-01, 1.3533528e-01, 1.1108996e-02, 3.3546262e-04 },
40*77c1e3ccSAndroid Build Coastguard Worker     { 2.4359586e-04, 8.0667874e-03, 9.8273583e-02, 4.4043165e-01, 7.2614902e-01,
41*77c1e3ccSAndroid Build Coastguard Worker       4.4043165e-01, 9.8273583e-02, 8.0667874e-03, 2.4359586e-04 },
42*77c1e3ccSAndroid Build Coastguard Worker     { 9.3271126e-05, 3.0887155e-03, 3.7628256e-02, 1.6863814e-01, 2.7803731e-01,
43*77c1e3ccSAndroid Build Coastguard Worker       1.6863814e-01, 3.7628256e-02, 3.0887155e-03, 9.3271126e-05 },
44*77c1e3ccSAndroid Build Coastguard Worker     { 1.8831115e-05, 6.2360091e-04, 7.5970138e-03, 3.4047455e-02, 5.6134764e-02,
45*77c1e3ccSAndroid Build Coastguard Worker       3.4047455e-02, 7.5970138e-03, 6.2360091e-04, 1.8831115e-05 },
46*77c1e3ccSAndroid Build Coastguard Worker     { 2.0047323e-06, 6.6387620e-05, 8.0876675e-04, 3.6246411e-03, 5.9760227e-03,
47*77c1e3ccSAndroid Build Coastguard Worker       3.6246411e-03, 8.0876675e-04, 6.6387620e-05, 2.0047323e-06 } },
48*77c1e3ccSAndroid Build Coastguard Worker 
49*77c1e3ccSAndroid Build Coastguard Worker   { { -6.2165498e-08, 3.8760313e-06, 3.0079011e-06, -4.4602581e-04,
50*77c1e3ccSAndroid Build Coastguard Worker       6.6981313e-04, 1.3962291e-03, -9.9486928e-04, -8.1631159e-05,
51*77c1e3ccSAndroid Build Coastguard Worker       3.5712848e-05 },
52*77c1e3ccSAndroid Build Coastguard Worker     { 3.8760313e-06, 5.7044272e-06, -1.6041942e-03, 4.5687673e-03,
53*77c1e3ccSAndroid Build Coastguard Worker       1.8061366e-02, -2.4406660e-02, -3.7979286e-03, 3.1511115e-03,
54*77c1e3ccSAndroid Build Coastguard Worker       -8.1631159e-05 },
55*77c1e3ccSAndroid Build Coastguard Worker     { 3.0079011e-06, -1.6041942e-03, 8.6645801e-03, 6.4960226e-02,
56*77c1e3ccSAndroid Build Coastguard Worker       -1.6647682e-01, -4.9129307e-02, 7.7304743e-02, -3.7979286e-03,
57*77c1e3ccSAndroid Build Coastguard Worker       -9.9486928e-04 },
58*77c1e3ccSAndroid Build Coastguard Worker     { -4.4602581e-04, 4.5687673e-03, 6.4960226e-02, -3.1572008e-01,
59*77c1e3ccSAndroid Build Coastguard Worker       -1.7670043e-01, 5.2729243e-01, -4.9129307e-02, -2.4406660e-02,
60*77c1e3ccSAndroid Build Coastguard Worker       1.3962291e-03 },
61*77c1e3ccSAndroid Build Coastguard Worker     { 6.6981313e-04, 1.8061366e-02, -1.6647682e-01, -1.7670043e-01,
62*77c1e3ccSAndroid Build Coastguard Worker       1.0000000e+00, -1.7670043e-01, -1.6647682e-01, 1.8061366e-02,
63*77c1e3ccSAndroid Build Coastguard Worker       6.6981313e-04 },
64*77c1e3ccSAndroid Build Coastguard Worker     { 1.3962291e-03, -2.4406660e-02, -4.9129307e-02, 5.2729243e-01,
65*77c1e3ccSAndroid Build Coastguard Worker       -1.7670043e-01, -3.1572008e-01, 6.4960226e-02, 4.5687673e-03,
66*77c1e3ccSAndroid Build Coastguard Worker       -4.4602581e-04 },
67*77c1e3ccSAndroid Build Coastguard Worker     { -9.9486928e-04, -3.7979286e-03, 7.7304743e-02, -4.9129307e-02,
68*77c1e3ccSAndroid Build Coastguard Worker       -1.6647682e-01, 6.4960226e-02, 8.6645801e-03, -1.6041942e-03,
69*77c1e3ccSAndroid Build Coastguard Worker       3.0079011e-06 },
70*77c1e3ccSAndroid Build Coastguard Worker     { -8.1631159e-05, 3.1511115e-03, -3.7979286e-03, -2.4406660e-02,
71*77c1e3ccSAndroid Build Coastguard Worker       1.8061366e-02, 4.5687673e-03, -1.6041942e-03, 5.7044272e-06,
72*77c1e3ccSAndroid Build Coastguard Worker       3.8760313e-06 },
73*77c1e3ccSAndroid Build Coastguard Worker     { 3.5712848e-05, -8.1631159e-05, -9.9486928e-04, 1.3962291e-03,
74*77c1e3ccSAndroid Build Coastguard Worker       6.6981313e-04, -4.4602581e-04, 3.0079011e-06, 3.8760313e-06,
75*77c1e3ccSAndroid Build Coastguard Worker       -6.2165498e-08 } },
76*77c1e3ccSAndroid Build Coastguard Worker 
77*77c1e3ccSAndroid Build Coastguard Worker   { { 2.0047323e-06, 1.8831115e-05, 9.3271126e-05, 2.4359586e-04, 3.3546262e-04,
78*77c1e3ccSAndroid Build Coastguard Worker       2.4359586e-04, 9.3271126e-05, 1.8831115e-05, 2.0047323e-06 },
79*77c1e3ccSAndroid Build Coastguard Worker     { 6.6387620e-05, 6.2360091e-04, 3.0887155e-03, 8.0667874e-03, 1.1108996e-02,
80*77c1e3ccSAndroid Build Coastguard Worker       8.0667874e-03, 3.0887155e-03, 6.2360091e-04, 6.6387620e-05 },
81*77c1e3ccSAndroid Build Coastguard Worker     { 8.0876675e-04, 7.5970138e-03, 3.7628256e-02, 9.8273583e-02, 1.3533528e-01,
82*77c1e3ccSAndroid Build Coastguard Worker       9.8273583e-02, 3.7628256e-02, 7.5970138e-03, 8.0876675e-04 },
83*77c1e3ccSAndroid Build Coastguard Worker     { 3.6246411e-03, 3.4047455e-02, 1.6863814e-01, 4.4043165e-01, 6.0653067e-01,
84*77c1e3ccSAndroid Build Coastguard Worker       4.4043165e-01, 1.6863814e-01, 3.4047455e-02, 3.6246411e-03 },
85*77c1e3ccSAndroid Build Coastguard Worker     { 5.9760227e-03, 5.6134764e-02, 2.7803731e-01, 7.2614902e-01, 1.0000000e+00,
86*77c1e3ccSAndroid Build Coastguard Worker       7.2614902e-01, 2.7803731e-01, 5.6134764e-02, 5.9760227e-03 },
87*77c1e3ccSAndroid Build Coastguard Worker     { 3.6246411e-03, 3.4047455e-02, 1.6863814e-01, 4.4043165e-01, 6.0653067e-01,
88*77c1e3ccSAndroid Build Coastguard Worker       4.4043165e-01, 1.6863814e-01, 3.4047455e-02, 3.6246411e-03 },
89*77c1e3ccSAndroid Build Coastguard Worker     { 8.0876675e-04, 7.5970138e-03, 3.7628256e-02, 9.8273583e-02, 1.3533528e-01,
90*77c1e3ccSAndroid Build Coastguard Worker       9.8273583e-02, 3.7628256e-02, 7.5970138e-03, 8.0876675e-04 },
91*77c1e3ccSAndroid Build Coastguard Worker     { 6.6387620e-05, 6.2360091e-04, 3.0887155e-03, 8.0667874e-03, 1.1108996e-02,
92*77c1e3ccSAndroid Build Coastguard Worker       8.0667874e-03, 3.0887155e-03, 6.2360091e-04, 6.6387620e-05 },
93*77c1e3ccSAndroid Build Coastguard Worker     { 2.0047323e-06, 1.8831115e-05, 9.3271126e-05, 2.4359586e-04, 3.3546262e-04,
94*77c1e3ccSAndroid Build Coastguard Worker       2.4359586e-04, 9.3271126e-05, 1.8831115e-05, 2.0047323e-06 } },
95*77c1e3ccSAndroid Build Coastguard Worker 
96*77c1e3ccSAndroid Build Coastguard Worker   { { 3.5712848e-05, -8.1631159e-05, -9.9486928e-04, 1.3962291e-03,
97*77c1e3ccSAndroid Build Coastguard Worker       6.6981313e-04, -4.4602581e-04, 3.0079011e-06, 3.8760313e-06,
98*77c1e3ccSAndroid Build Coastguard Worker       -6.2165498e-08 },
99*77c1e3ccSAndroid Build Coastguard Worker     { -8.1631159e-05, 3.1511115e-03, -3.7979286e-03, -2.4406660e-02,
100*77c1e3ccSAndroid Build Coastguard Worker       1.8061366e-02, 4.5687673e-03, -1.6041942e-03, 5.7044272e-06,
101*77c1e3ccSAndroid Build Coastguard Worker       3.8760313e-06 },
102*77c1e3ccSAndroid Build Coastguard Worker     { -9.9486928e-04, -3.7979286e-03, 7.7304743e-02, -4.9129307e-02,
103*77c1e3ccSAndroid Build Coastguard Worker       -1.6647682e-01, 6.4960226e-02, 8.6645801e-03, -1.6041942e-03,
104*77c1e3ccSAndroid Build Coastguard Worker       3.0079011e-06 },
105*77c1e3ccSAndroid Build Coastguard Worker     { 1.3962291e-03, -2.4406660e-02, -4.9129307e-02, 5.2729243e-01,
106*77c1e3ccSAndroid Build Coastguard Worker       -1.7670043e-01, -3.1572008e-01, 6.4960226e-02, 4.5687673e-03,
107*77c1e3ccSAndroid Build Coastguard Worker       -4.4602581e-04 },
108*77c1e3ccSAndroid Build Coastguard Worker     { 6.6981313e-04, 1.8061366e-02, -1.6647682e-01, -1.7670043e-01,
109*77c1e3ccSAndroid Build Coastguard Worker       1.0000000e+00, -1.7670043e-01, -1.6647682e-01, 1.8061366e-02,
110*77c1e3ccSAndroid Build Coastguard Worker       6.6981313e-04 },
111*77c1e3ccSAndroid Build Coastguard Worker     { -4.4602581e-04, 4.5687673e-03, 6.4960226e-02, -3.1572008e-01,
112*77c1e3ccSAndroid Build Coastguard Worker       -1.7670043e-01, 5.2729243e-01, -4.9129307e-02, -2.4406660e-02,
113*77c1e3ccSAndroid Build Coastguard Worker       1.3962291e-03 },
114*77c1e3ccSAndroid Build Coastguard Worker     { 3.0079011e-06, -1.6041942e-03, 8.6645801e-03, 6.4960226e-02,
115*77c1e3ccSAndroid Build Coastguard Worker       -1.6647682e-01, -4.9129307e-02, 7.7304743e-02, -3.7979286e-03,
116*77c1e3ccSAndroid Build Coastguard Worker       -9.9486928e-04 },
117*77c1e3ccSAndroid Build Coastguard Worker     { 3.8760313e-06, 5.7044272e-06, -1.6041942e-03, 4.5687673e-03,
118*77c1e3ccSAndroid Build Coastguard Worker       1.8061366e-02, -2.4406660e-02, -3.7979286e-03, 3.1511115e-03,
119*77c1e3ccSAndroid Build Coastguard Worker       -8.1631159e-05 },
120*77c1e3ccSAndroid Build Coastguard Worker     { -6.2165498e-08, 3.8760313e-06, 3.0079011e-06, -4.4602581e-04,
121*77c1e3ccSAndroid Build Coastguard Worker       6.6981313e-04, 1.3962291e-03, -9.9486928e-04, -8.1631159e-05,
122*77c1e3ccSAndroid Build Coastguard Worker       3.5712848e-05 } }
123*77c1e3ccSAndroid Build Coastguard Worker };
124*77c1e3ccSAndroid Build Coastguard Worker 
125*77c1e3ccSAndroid Build Coastguard Worker // This function is to extract red/green/blue channels, and calculate intensity
126*77c1e3ccSAndroid Build Coastguard Worker // = (r+g+b)/3. Note that it only handles 8bits case now.
127*77c1e3ccSAndroid Build Coastguard Worker // TODO(linzhen): add high bitdepth support.
get_color_intensity(const YV12_BUFFER_CONFIG * src,int subsampling_x,int subsampling_y,double * cr,double * cg,double * cb,double * intensity)128*77c1e3ccSAndroid Build Coastguard Worker static void get_color_intensity(const YV12_BUFFER_CONFIG *src,
129*77c1e3ccSAndroid Build Coastguard Worker                                 int subsampling_x, int subsampling_y,
130*77c1e3ccSAndroid Build Coastguard Worker                                 double *cr, double *cg, double *cb,
131*77c1e3ccSAndroid Build Coastguard Worker                                 double *intensity) {
132*77c1e3ccSAndroid Build Coastguard Worker   const uint8_t *y = src->buffers[0];
133*77c1e3ccSAndroid Build Coastguard Worker   const uint8_t *u = src->buffers[1];
134*77c1e3ccSAndroid Build Coastguard Worker   const uint8_t *v = src->buffers[2];
135*77c1e3ccSAndroid Build Coastguard Worker 
136*77c1e3ccSAndroid Build Coastguard Worker   const int y_height = src->crop_heights[0];
137*77c1e3ccSAndroid Build Coastguard Worker   const int y_width = src->crop_widths[0];
138*77c1e3ccSAndroid Build Coastguard Worker   const int y_stride = src->strides[0];
139*77c1e3ccSAndroid Build Coastguard Worker   const int c_stride = src->strides[1];
140*77c1e3ccSAndroid Build Coastguard Worker 
141*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < y_height; ++i) {
142*77c1e3ccSAndroid Build Coastguard Worker     for (int j = 0; j < y_width; ++j) {
143*77c1e3ccSAndroid Build Coastguard Worker       cr[i * y_width + j] =
144*77c1e3ccSAndroid Build Coastguard Worker           fclamp((double)y[i * y_stride + j] +
145*77c1e3ccSAndroid Build Coastguard Worker                      1.370 * (double)(v[(i >> subsampling_y) * c_stride +
146*77c1e3ccSAndroid Build Coastguard Worker                                         (j >> subsampling_x)] -
147*77c1e3ccSAndroid Build Coastguard Worker                                       128),
148*77c1e3ccSAndroid Build Coastguard Worker                  0, 255);
149*77c1e3ccSAndroid Build Coastguard Worker       cg[i * y_width + j] =
150*77c1e3ccSAndroid Build Coastguard Worker           fclamp((double)y[i * y_stride + j] -
151*77c1e3ccSAndroid Build Coastguard Worker                      0.698 * (double)(u[(i >> subsampling_y) * c_stride +
152*77c1e3ccSAndroid Build Coastguard Worker                                         (j >> subsampling_x)] -
153*77c1e3ccSAndroid Build Coastguard Worker                                       128) -
154*77c1e3ccSAndroid Build Coastguard Worker                      0.337 * (double)(v[(i >> subsampling_y) * c_stride +
155*77c1e3ccSAndroid Build Coastguard Worker                                         (j >> subsampling_x)] -
156*77c1e3ccSAndroid Build Coastguard Worker                                       128),
157*77c1e3ccSAndroid Build Coastguard Worker                  0, 255);
158*77c1e3ccSAndroid Build Coastguard Worker       cb[i * y_width + j] =
159*77c1e3ccSAndroid Build Coastguard Worker           fclamp((double)y[i * y_stride + j] +
160*77c1e3ccSAndroid Build Coastguard Worker                      1.732 * (double)(u[(i >> subsampling_y) * c_stride +
161*77c1e3ccSAndroid Build Coastguard Worker                                         (j >> subsampling_x)] -
162*77c1e3ccSAndroid Build Coastguard Worker                                       128),
163*77c1e3ccSAndroid Build Coastguard Worker                  0, 255);
164*77c1e3ccSAndroid Build Coastguard Worker 
165*77c1e3ccSAndroid Build Coastguard Worker       intensity[i * y_width + j] =
166*77c1e3ccSAndroid Build Coastguard Worker           (cr[i * y_width + j] + cg[i * y_width + j] + cb[i * y_width + j]) /
167*77c1e3ccSAndroid Build Coastguard Worker           3.0;
168*77c1e3ccSAndroid Build Coastguard Worker       assert(intensity[i * y_width + j] >= 0 &&
169*77c1e3ccSAndroid Build Coastguard Worker              intensity[i * y_width + j] <= 255);
170*77c1e3ccSAndroid Build Coastguard Worker 
171*77c1e3ccSAndroid Build Coastguard Worker       intensity[i * y_width + j] /= 256;
172*77c1e3ccSAndroid Build Coastguard Worker       cr[i * y_width + j] /= 256;
173*77c1e3ccSAndroid Build Coastguard Worker       cg[i * y_width + j] /= 256;
174*77c1e3ccSAndroid Build Coastguard Worker       cb[i * y_width + j] /= 256;
175*77c1e3ccSAndroid Build Coastguard Worker     }
176*77c1e3ccSAndroid Build Coastguard Worker   }
177*77c1e3ccSAndroid Build Coastguard Worker }
178*77c1e3ccSAndroid Build Coastguard Worker 
convolve_map(const double * filter,const double * map,const int size)179*77c1e3ccSAndroid Build Coastguard Worker static inline double convolve_map(const double *filter, const double *map,
180*77c1e3ccSAndroid Build Coastguard Worker                                   const int size) {
181*77c1e3ccSAndroid Build Coastguard Worker   double result = 0;
182*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < size; ++i) {
183*77c1e3ccSAndroid Build Coastguard Worker     result += filter[i] * map[i];  // symmetric filter is used
184*77c1e3ccSAndroid Build Coastguard Worker   }
185*77c1e3ccSAndroid Build Coastguard Worker   return result;
186*77c1e3ccSAndroid Build Coastguard Worker }
187*77c1e3ccSAndroid Build Coastguard Worker 
188*77c1e3ccSAndroid Build Coastguard Worker // This function is to decimate the map by half, and apply Gaussian filter on
189*77c1e3ccSAndroid Build Coastguard Worker // top of the downsampled map.
decimate_map(const double * map,int height,int width,int stride,double * downsampled_map)190*77c1e3ccSAndroid Build Coastguard Worker static inline void decimate_map(const double *map, int height, int width,
191*77c1e3ccSAndroid Build Coastguard Worker                                 int stride, double *downsampled_map) {
192*77c1e3ccSAndroid Build Coastguard Worker   const int new_width = width / 2;
193*77c1e3ccSAndroid Build Coastguard Worker   const int window_size = 5;
194*77c1e3ccSAndroid Build Coastguard Worker   const double gaussian_filter[25] = {
195*77c1e3ccSAndroid Build Coastguard Worker     1. / 256, 1.0 / 64, 3. / 128, 1. / 64,  1. / 256, 1. / 64, 1. / 16,
196*77c1e3ccSAndroid Build Coastguard Worker     3. / 32,  1. / 16,  1. / 64,  3. / 128, 3. / 32,  9. / 64, 3. / 32,
197*77c1e3ccSAndroid Build Coastguard Worker     3. / 128, 1. / 64,  1. / 16,  3. / 32,  1. / 16,  1. / 64, 1. / 256,
198*77c1e3ccSAndroid Build Coastguard Worker     1. / 64,  3. / 128, 1. / 64,  1. / 256
199*77c1e3ccSAndroid Build Coastguard Worker   };
200*77c1e3ccSAndroid Build Coastguard Worker 
201*77c1e3ccSAndroid Build Coastguard Worker   double map_region[25];
202*77c1e3ccSAndroid Build Coastguard Worker   for (int y = 0; y < height - 1; y += 2) {
203*77c1e3ccSAndroid Build Coastguard Worker     for (int x = 0; x < width - 1; x += 2) {
204*77c1e3ccSAndroid Build Coastguard Worker       int i = 0;
205*77c1e3ccSAndroid Build Coastguard Worker       for (int yy = y - window_size / 2; yy <= y + window_size / 2; ++yy) {
206*77c1e3ccSAndroid Build Coastguard Worker         for (int xx = x - window_size / 2; xx <= x + window_size / 2; ++xx) {
207*77c1e3ccSAndroid Build Coastguard Worker           int yvalue = clamp(yy, 0, height - 1);
208*77c1e3ccSAndroid Build Coastguard Worker           int xvalue = clamp(xx, 0, width - 1);
209*77c1e3ccSAndroid Build Coastguard Worker           map_region[i++] = map[yvalue * stride + xvalue];
210*77c1e3ccSAndroid Build Coastguard Worker         }
211*77c1e3ccSAndroid Build Coastguard Worker       }
212*77c1e3ccSAndroid Build Coastguard Worker       downsampled_map[(y / 2) * new_width + (x / 2)] =
213*77c1e3ccSAndroid Build Coastguard Worker           convolve_map(gaussian_filter, map_region, window_size * window_size);
214*77c1e3ccSAndroid Build Coastguard Worker     }
215*77c1e3ccSAndroid Build Coastguard Worker   }
216*77c1e3ccSAndroid Build Coastguard Worker }
217*77c1e3ccSAndroid Build Coastguard Worker 
218*77c1e3ccSAndroid Build Coastguard Worker // This function is to upscale the map from in_level size to out_level size.
219*77c1e3ccSAndroid Build Coastguard Worker // Note that the map at "level-1" will upscale the map at "level" by x2.
upscale_map(const double * input,int in_level,int out_level,int height[9],int width[9],double * output)220*77c1e3ccSAndroid Build Coastguard Worker static inline int upscale_map(const double *input, int in_level, int out_level,
221*77c1e3ccSAndroid Build Coastguard Worker                               int height[9], int width[9], double *output) {
222*77c1e3ccSAndroid Build Coastguard Worker   for (int level = in_level; level > out_level; level--) {
223*77c1e3ccSAndroid Build Coastguard Worker     const int cur_width = width[level];
224*77c1e3ccSAndroid Build Coastguard Worker     const int cur_height = height[level];
225*77c1e3ccSAndroid Build Coastguard Worker     const int cur_stride = width[level];
226*77c1e3ccSAndroid Build Coastguard Worker 
227*77c1e3ccSAndroid Build Coastguard Worker     double *original = (level == in_level) ? (double *)input : output;
228*77c1e3ccSAndroid Build Coastguard Worker 
229*77c1e3ccSAndroid Build Coastguard Worker     assert(level > 0);
230*77c1e3ccSAndroid Build Coastguard Worker 
231*77c1e3ccSAndroid Build Coastguard Worker     const int h_upscale = height[level - 1];
232*77c1e3ccSAndroid Build Coastguard Worker     const int w_upscale = width[level - 1];
233*77c1e3ccSAndroid Build Coastguard Worker     const int s_upscale = width[level - 1];
234*77c1e3ccSAndroid Build Coastguard Worker 
235*77c1e3ccSAndroid Build Coastguard Worker     double *upscale = aom_malloc(h_upscale * w_upscale * sizeof(*upscale));
236*77c1e3ccSAndroid Build Coastguard Worker 
237*77c1e3ccSAndroid Build Coastguard Worker     if (!upscale) {
238*77c1e3ccSAndroid Build Coastguard Worker       return 0;
239*77c1e3ccSAndroid Build Coastguard Worker     }
240*77c1e3ccSAndroid Build Coastguard Worker 
241*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < h_upscale; ++i) {
242*77c1e3ccSAndroid Build Coastguard Worker       for (int j = 0; j < w_upscale; ++j) {
243*77c1e3ccSAndroid Build Coastguard Worker         const int ii = clamp((i >> 1), 0, cur_height - 1);
244*77c1e3ccSAndroid Build Coastguard Worker         const int jj = clamp((j >> 1), 0, cur_width - 1);
245*77c1e3ccSAndroid Build Coastguard Worker         upscale[j + i * s_upscale] = (double)original[jj + ii * cur_stride];
246*77c1e3ccSAndroid Build Coastguard Worker       }
247*77c1e3ccSAndroid Build Coastguard Worker     }
248*77c1e3ccSAndroid Build Coastguard Worker     memcpy(output, upscale, h_upscale * w_upscale * sizeof(double));
249*77c1e3ccSAndroid Build Coastguard Worker     aom_free(upscale);
250*77c1e3ccSAndroid Build Coastguard Worker   }
251*77c1e3ccSAndroid Build Coastguard Worker 
252*77c1e3ccSAndroid Build Coastguard Worker   return 1;
253*77c1e3ccSAndroid Build Coastguard Worker }
254*77c1e3ccSAndroid Build Coastguard Worker 
255*77c1e3ccSAndroid Build Coastguard Worker // This function calculates the differences between a fine scale c and a
256*77c1e3ccSAndroid Build Coastguard Worker // coarser scale s yielding the feature maps. c \in {2, 3, 4}, and s = c +
257*77c1e3ccSAndroid Build Coastguard Worker // delta, where delta \in {3, 4}.
center_surround_diff(const double * input[9],int height[9],int width[9],saliency_feature_map * output[6])258*77c1e3ccSAndroid Build Coastguard Worker static int center_surround_diff(const double *input[9], int height[9],
259*77c1e3ccSAndroid Build Coastguard Worker                                 int width[9], saliency_feature_map *output[6]) {
260*77c1e3ccSAndroid Build Coastguard Worker   int j = 0;
261*77c1e3ccSAndroid Build Coastguard Worker   for (int k = 2; k < 5; ++k) {
262*77c1e3ccSAndroid Build Coastguard Worker     int cur_height = height[k];
263*77c1e3ccSAndroid Build Coastguard Worker     int cur_width = width[k];
264*77c1e3ccSAndroid Build Coastguard Worker 
265*77c1e3ccSAndroid Build Coastguard Worker     if (upscale_map(input[k + 3], k + 3, k, height, width, output[j]->buf) ==
266*77c1e3ccSAndroid Build Coastguard Worker         0) {
267*77c1e3ccSAndroid Build Coastguard Worker       return 0;
268*77c1e3ccSAndroid Build Coastguard Worker     }
269*77c1e3ccSAndroid Build Coastguard Worker 
270*77c1e3ccSAndroid Build Coastguard Worker     for (int r = 0; r < cur_height; ++r) {
271*77c1e3ccSAndroid Build Coastguard Worker       for (int c = 0; c < cur_width; ++c) {
272*77c1e3ccSAndroid Build Coastguard Worker         output[j]->buf[r * cur_width + c] =
273*77c1e3ccSAndroid Build Coastguard Worker             fabs((double)(input[k][r * cur_width + c] -
274*77c1e3ccSAndroid Build Coastguard Worker                           output[j]->buf[r * cur_width + c]));
275*77c1e3ccSAndroid Build Coastguard Worker       }
276*77c1e3ccSAndroid Build Coastguard Worker     }
277*77c1e3ccSAndroid Build Coastguard Worker 
278*77c1e3ccSAndroid Build Coastguard Worker     if (upscale_map(input[k + 4], k + 4, k, height, width,
279*77c1e3ccSAndroid Build Coastguard Worker                     output[j + 1]->buf) == 0) {
280*77c1e3ccSAndroid Build Coastguard Worker       return 0;
281*77c1e3ccSAndroid Build Coastguard Worker     }
282*77c1e3ccSAndroid Build Coastguard Worker 
283*77c1e3ccSAndroid Build Coastguard Worker     for (int r = 0; r < cur_height; ++r) {
284*77c1e3ccSAndroid Build Coastguard Worker       for (int c = 0; c < cur_width; ++c) {
285*77c1e3ccSAndroid Build Coastguard Worker         output[j + 1]->buf[r * cur_width + c] =
286*77c1e3ccSAndroid Build Coastguard Worker             fabs(input[k][r * cur_width + c] -
287*77c1e3ccSAndroid Build Coastguard Worker                  output[j + 1]->buf[r * cur_width + c]);
288*77c1e3ccSAndroid Build Coastguard Worker       }
289*77c1e3ccSAndroid Build Coastguard Worker     }
290*77c1e3ccSAndroid Build Coastguard Worker 
291*77c1e3ccSAndroid Build Coastguard Worker     j += 2;
292*77c1e3ccSAndroid Build Coastguard Worker   }
293*77c1e3ccSAndroid Build Coastguard Worker   return 1;
294*77c1e3ccSAndroid Build Coastguard Worker }
295*77c1e3ccSAndroid Build Coastguard Worker 
296*77c1e3ccSAndroid Build Coastguard Worker // For color channels, the differences is calculated based on "color
297*77c1e3ccSAndroid Build Coastguard Worker // double-opponency". For example, the RG feature map is constructed between a
298*77c1e3ccSAndroid Build Coastguard Worker // fine scale c of R-G component and a coarser scale s of G-R component.
center_surround_diff_rgb(const double * input_1[9],const double * input_2[9],int height[9],int width[9],saliency_feature_map * output[6])299*77c1e3ccSAndroid Build Coastguard Worker static int center_surround_diff_rgb(const double *input_1[9],
300*77c1e3ccSAndroid Build Coastguard Worker                                     const double *input_2[9], int height[9],
301*77c1e3ccSAndroid Build Coastguard Worker                                     int width[9],
302*77c1e3ccSAndroid Build Coastguard Worker                                     saliency_feature_map *output[6]) {
303*77c1e3ccSAndroid Build Coastguard Worker   int j = 0;
304*77c1e3ccSAndroid Build Coastguard Worker   for (int k = 2; k < 5; ++k) {
305*77c1e3ccSAndroid Build Coastguard Worker     int cur_height = height[k];
306*77c1e3ccSAndroid Build Coastguard Worker     int cur_width = width[k];
307*77c1e3ccSAndroid Build Coastguard Worker 
308*77c1e3ccSAndroid Build Coastguard Worker     if (upscale_map(input_2[k + 3], k + 3, k, height, width, output[j]->buf) ==
309*77c1e3ccSAndroid Build Coastguard Worker         0) {
310*77c1e3ccSAndroid Build Coastguard Worker       return 0;
311*77c1e3ccSAndroid Build Coastguard Worker     }
312*77c1e3ccSAndroid Build Coastguard Worker 
313*77c1e3ccSAndroid Build Coastguard Worker     for (int r = 0; r < cur_height; ++r) {
314*77c1e3ccSAndroid Build Coastguard Worker       for (int c = 0; c < cur_width; ++c) {
315*77c1e3ccSAndroid Build Coastguard Worker         output[j]->buf[r * cur_width + c] =
316*77c1e3ccSAndroid Build Coastguard Worker             fabs((double)(input_1[k][r * cur_width + c] -
317*77c1e3ccSAndroid Build Coastguard Worker                           output[j]->buf[r * cur_width + c]));
318*77c1e3ccSAndroid Build Coastguard Worker       }
319*77c1e3ccSAndroid Build Coastguard Worker     }
320*77c1e3ccSAndroid Build Coastguard Worker 
321*77c1e3ccSAndroid Build Coastguard Worker     if (upscale_map(input_2[k + 4], k + 4, k, height, width,
322*77c1e3ccSAndroid Build Coastguard Worker                     output[j + 1]->buf) == 0) {
323*77c1e3ccSAndroid Build Coastguard Worker       return 0;
324*77c1e3ccSAndroid Build Coastguard Worker     }
325*77c1e3ccSAndroid Build Coastguard Worker 
326*77c1e3ccSAndroid Build Coastguard Worker     for (int r = 0; r < cur_height; ++r) {
327*77c1e3ccSAndroid Build Coastguard Worker       for (int c = 0; c < cur_width; ++c) {
328*77c1e3ccSAndroid Build Coastguard Worker         output[j + 1]->buf[r * cur_width + c] =
329*77c1e3ccSAndroid Build Coastguard Worker             fabs(input_1[k][r * cur_width + c] -
330*77c1e3ccSAndroid Build Coastguard Worker                  output[j + 1]->buf[r * cur_width + c]);
331*77c1e3ccSAndroid Build Coastguard Worker       }
332*77c1e3ccSAndroid Build Coastguard Worker     }
333*77c1e3ccSAndroid Build Coastguard Worker 
334*77c1e3ccSAndroid Build Coastguard Worker     j += 2;
335*77c1e3ccSAndroid Build Coastguard Worker   }
336*77c1e3ccSAndroid Build Coastguard Worker   return 1;
337*77c1e3ccSAndroid Build Coastguard Worker }
338*77c1e3ccSAndroid Build Coastguard Worker 
339*77c1e3ccSAndroid Build Coastguard Worker // This function is to generate Gaussian pyramid images with indexes from 0 to
340*77c1e3ccSAndroid Build Coastguard Worker // 8, and construct the feature maps from calculating the center-surround
341*77c1e3ccSAndroid Build Coastguard Worker // differences.
gaussian_pyramid(const double * src,int width[9],int height[9],saliency_feature_map * dst[6])342*77c1e3ccSAndroid Build Coastguard Worker static int gaussian_pyramid(const double *src, int width[9], int height[9],
343*77c1e3ccSAndroid Build Coastguard Worker                             saliency_feature_map *dst[6]) {
344*77c1e3ccSAndroid Build Coastguard Worker   double *gaussian_map[9];  // scale = 9
345*77c1e3ccSAndroid Build Coastguard Worker   gaussian_map[0] =
346*77c1e3ccSAndroid Build Coastguard Worker       (double *)aom_malloc(width[0] * height[0] * sizeof(*gaussian_map[0]));
347*77c1e3ccSAndroid Build Coastguard Worker   if (!gaussian_map[0]) {
348*77c1e3ccSAndroid Build Coastguard Worker     return 0;
349*77c1e3ccSAndroid Build Coastguard Worker   }
350*77c1e3ccSAndroid Build Coastguard Worker 
351*77c1e3ccSAndroid Build Coastguard Worker   memcpy(gaussian_map[0], src, width[0] * height[0] * sizeof(double));
352*77c1e3ccSAndroid Build Coastguard Worker 
353*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 1; i < 9; ++i) {
354*77c1e3ccSAndroid Build Coastguard Worker     int stride = width[i - 1];
355*77c1e3ccSAndroid Build Coastguard Worker     int new_width = width[i];
356*77c1e3ccSAndroid Build Coastguard Worker     int new_height = height[i];
357*77c1e3ccSAndroid Build Coastguard Worker 
358*77c1e3ccSAndroid Build Coastguard Worker     gaussian_map[i] =
359*77c1e3ccSAndroid Build Coastguard Worker         (double *)aom_malloc(new_width * new_height * sizeof(*gaussian_map[i]));
360*77c1e3ccSAndroid Build Coastguard Worker 
361*77c1e3ccSAndroid Build Coastguard Worker     if (!gaussian_map[i]) {
362*77c1e3ccSAndroid Build Coastguard Worker       for (int l = 0; l < i; ++l) {
363*77c1e3ccSAndroid Build Coastguard Worker         aom_free(gaussian_map[l]);
364*77c1e3ccSAndroid Build Coastguard Worker       }
365*77c1e3ccSAndroid Build Coastguard Worker       return 0;
366*77c1e3ccSAndroid Build Coastguard Worker     }
367*77c1e3ccSAndroid Build Coastguard Worker 
368*77c1e3ccSAndroid Build Coastguard Worker     memset(gaussian_map[i], 0, new_width * new_height * sizeof(double));
369*77c1e3ccSAndroid Build Coastguard Worker 
370*77c1e3ccSAndroid Build Coastguard Worker     decimate_map(gaussian_map[i - 1], height[i - 1], width[i - 1], stride,
371*77c1e3ccSAndroid Build Coastguard Worker                  gaussian_map[i]);
372*77c1e3ccSAndroid Build Coastguard Worker   }
373*77c1e3ccSAndroid Build Coastguard Worker 
374*77c1e3ccSAndroid Build Coastguard Worker   if (center_surround_diff((const double **)gaussian_map, height, width, dst) ==
375*77c1e3ccSAndroid Build Coastguard Worker       0) {
376*77c1e3ccSAndroid Build Coastguard Worker     for (int l = 0; l < 9; ++l) {
377*77c1e3ccSAndroid Build Coastguard Worker       aom_free(gaussian_map[l]);
378*77c1e3ccSAndroid Build Coastguard Worker     }
379*77c1e3ccSAndroid Build Coastguard Worker     return 0;
380*77c1e3ccSAndroid Build Coastguard Worker   }
381*77c1e3ccSAndroid Build Coastguard Worker 
382*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 9; ++i) {
383*77c1e3ccSAndroid Build Coastguard Worker     aom_free(gaussian_map[i]);
384*77c1e3ccSAndroid Build Coastguard Worker   }
385*77c1e3ccSAndroid Build Coastguard Worker   return 1;
386*77c1e3ccSAndroid Build Coastguard Worker }
387*77c1e3ccSAndroid Build Coastguard Worker 
gaussian_pyramid_rgb(double * src_1,double * src_2,int width[9],int height[9],saliency_feature_map * dst[6])388*77c1e3ccSAndroid Build Coastguard Worker static int gaussian_pyramid_rgb(double *src_1, double *src_2, int width[9],
389*77c1e3ccSAndroid Build Coastguard Worker                                 int height[9], saliency_feature_map *dst[6]) {
390*77c1e3ccSAndroid Build Coastguard Worker   double *gaussian_map[2][9];  // scale = 9
391*77c1e3ccSAndroid Build Coastguard Worker   double *src[2];
392*77c1e3ccSAndroid Build Coastguard Worker 
393*77c1e3ccSAndroid Build Coastguard Worker   src[0] = src_1;
394*77c1e3ccSAndroid Build Coastguard Worker   src[1] = src_2;
395*77c1e3ccSAndroid Build Coastguard Worker 
396*77c1e3ccSAndroid Build Coastguard Worker   for (int k = 0; k < 2; ++k) {
397*77c1e3ccSAndroid Build Coastguard Worker     gaussian_map[k][0] = (double *)aom_malloc(width[0] * height[0] *
398*77c1e3ccSAndroid Build Coastguard Worker                                               sizeof(*gaussian_map[k][0]));
399*77c1e3ccSAndroid Build Coastguard Worker     if (!gaussian_map[k][0]) {
400*77c1e3ccSAndroid Build Coastguard Worker       for (int l = 0; l < k; ++l) {
401*77c1e3ccSAndroid Build Coastguard Worker         aom_free(gaussian_map[l][0]);
402*77c1e3ccSAndroid Build Coastguard Worker       }
403*77c1e3ccSAndroid Build Coastguard Worker       return 0;
404*77c1e3ccSAndroid Build Coastguard Worker     }
405*77c1e3ccSAndroid Build Coastguard Worker     memcpy(gaussian_map[k][0], src[k], width[0] * height[0] * sizeof(double));
406*77c1e3ccSAndroid Build Coastguard Worker 
407*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 1; i < 9; ++i) {
408*77c1e3ccSAndroid Build Coastguard Worker       int stride = width[i - 1];
409*77c1e3ccSAndroid Build Coastguard Worker       int new_width = width[i];
410*77c1e3ccSAndroid Build Coastguard Worker       int new_height = height[i];
411*77c1e3ccSAndroid Build Coastguard Worker 
412*77c1e3ccSAndroid Build Coastguard Worker       gaussian_map[k][i] = (double *)aom_malloc(new_width * new_height *
413*77c1e3ccSAndroid Build Coastguard Worker                                                 sizeof(*gaussian_map[k][i]));
414*77c1e3ccSAndroid Build Coastguard Worker       if (!gaussian_map[k][i]) {
415*77c1e3ccSAndroid Build Coastguard Worker         for (int l = 0; l < k; ++l) {
416*77c1e3ccSAndroid Build Coastguard Worker           aom_free(gaussian_map[l][i]);
417*77c1e3ccSAndroid Build Coastguard Worker         }
418*77c1e3ccSAndroid Build Coastguard Worker         return 0;
419*77c1e3ccSAndroid Build Coastguard Worker       }
420*77c1e3ccSAndroid Build Coastguard Worker       memset(gaussian_map[k][i], 0, new_width * new_height * sizeof(double));
421*77c1e3ccSAndroid Build Coastguard Worker       decimate_map(gaussian_map[k][i - 1], height[i - 1], width[i - 1], stride,
422*77c1e3ccSAndroid Build Coastguard Worker                    gaussian_map[k][i]);
423*77c1e3ccSAndroid Build Coastguard Worker     }
424*77c1e3ccSAndroid Build Coastguard Worker   }
425*77c1e3ccSAndroid Build Coastguard Worker 
426*77c1e3ccSAndroid Build Coastguard Worker   if (center_surround_diff_rgb((const double **)gaussian_map[0],
427*77c1e3ccSAndroid Build Coastguard Worker                                (const double **)gaussian_map[1], height, width,
428*77c1e3ccSAndroid Build Coastguard Worker                                dst) == 0) {
429*77c1e3ccSAndroid Build Coastguard Worker     for (int l = 0; l < 2; ++l) {
430*77c1e3ccSAndroid Build Coastguard Worker       for (int i = 0; i < 9; ++i) {
431*77c1e3ccSAndroid Build Coastguard Worker         aom_free(gaussian_map[l][i]);
432*77c1e3ccSAndroid Build Coastguard Worker       }
433*77c1e3ccSAndroid Build Coastguard Worker     }
434*77c1e3ccSAndroid Build Coastguard Worker     return 0;
435*77c1e3ccSAndroid Build Coastguard Worker   }
436*77c1e3ccSAndroid Build Coastguard Worker 
437*77c1e3ccSAndroid Build Coastguard Worker   for (int l = 0; l < 2; ++l) {
438*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < 9; ++i) {
439*77c1e3ccSAndroid Build Coastguard Worker       aom_free(gaussian_map[l][i]);
440*77c1e3ccSAndroid Build Coastguard Worker     }
441*77c1e3ccSAndroid Build Coastguard Worker   }
442*77c1e3ccSAndroid Build Coastguard Worker   return 1;
443*77c1e3ccSAndroid Build Coastguard Worker }
444*77c1e3ccSAndroid Build Coastguard Worker 
get_feature_map_intensity(double * intensity,int width[9],int height[9],saliency_feature_map * i_map[6])445*77c1e3ccSAndroid Build Coastguard Worker static int get_feature_map_intensity(double *intensity, int width[9],
446*77c1e3ccSAndroid Build Coastguard Worker                                      int height[9],
447*77c1e3ccSAndroid Build Coastguard Worker                                      saliency_feature_map *i_map[6]) {
448*77c1e3ccSAndroid Build Coastguard Worker   if (gaussian_pyramid(intensity, width, height, i_map) == 0) {
449*77c1e3ccSAndroid Build Coastguard Worker     return 0;
450*77c1e3ccSAndroid Build Coastguard Worker   }
451*77c1e3ccSAndroid Build Coastguard Worker   return 1;
452*77c1e3ccSAndroid Build Coastguard Worker }
453*77c1e3ccSAndroid Build Coastguard Worker 
get_feature_map_rgb(double * cr,double * cg,double * cb,int width[9],int height[9],saliency_feature_map * rg_map[6],saliency_feature_map * by_map[6])454*77c1e3ccSAndroid Build Coastguard Worker static int get_feature_map_rgb(double *cr, double *cg, double *cb, int width[9],
455*77c1e3ccSAndroid Build Coastguard Worker                                int height[9], saliency_feature_map *rg_map[6],
456*77c1e3ccSAndroid Build Coastguard Worker                                saliency_feature_map *by_map[6]) {
457*77c1e3ccSAndroid Build Coastguard Worker   double *rg_mat = aom_malloc(height[0] * width[0] * sizeof(*rg_mat));
458*77c1e3ccSAndroid Build Coastguard Worker   double *by_mat = aom_malloc(height[0] * width[0] * sizeof(*by_mat));
459*77c1e3ccSAndroid Build Coastguard Worker   double *gr_mat = aom_malloc(height[0] * width[0] * sizeof(*gr_mat));
460*77c1e3ccSAndroid Build Coastguard Worker   double *yb_mat = aom_malloc(height[0] * width[0] * sizeof(*yb_mat));
461*77c1e3ccSAndroid Build Coastguard Worker 
462*77c1e3ccSAndroid Build Coastguard Worker   if (!rg_mat || !by_mat || !gr_mat || !yb_mat) {
463*77c1e3ccSAndroid Build Coastguard Worker     aom_free(rg_mat);
464*77c1e3ccSAndroid Build Coastguard Worker     aom_free(by_mat);
465*77c1e3ccSAndroid Build Coastguard Worker     aom_free(gr_mat);
466*77c1e3ccSAndroid Build Coastguard Worker     aom_free(yb_mat);
467*77c1e3ccSAndroid Build Coastguard Worker     return 0;
468*77c1e3ccSAndroid Build Coastguard Worker   }
469*77c1e3ccSAndroid Build Coastguard Worker 
470*77c1e3ccSAndroid Build Coastguard Worker   double r, g, b, y;
471*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < height[0]; ++i) {
472*77c1e3ccSAndroid Build Coastguard Worker     for (int j = 0; j < width[0]; ++j) {
473*77c1e3ccSAndroid Build Coastguard Worker       r = AOMMAX(0, cr[i * width[0] + j] -
474*77c1e3ccSAndroid Build Coastguard Worker                         (cg[i * width[0] + j] + cb[i * width[0] + j]) / 2);
475*77c1e3ccSAndroid Build Coastguard Worker       g = AOMMAX(0, cg[i * width[0] + j] -
476*77c1e3ccSAndroid Build Coastguard Worker                         (cr[i * width[0] + j] + cb[i * width[0] + j]) / 2);
477*77c1e3ccSAndroid Build Coastguard Worker       b = AOMMAX(0, cb[i * width[0] + j] -
478*77c1e3ccSAndroid Build Coastguard Worker                         (cr[i * width[0] + j] + cg[i * width[0] + j]) / 2);
479*77c1e3ccSAndroid Build Coastguard Worker       y = AOMMAX(0, (cr[i * width[0] + j] + cg[i * width[0] + j]) / 2 -
480*77c1e3ccSAndroid Build Coastguard Worker                         fabs(cr[i * width[0] + j] - cg[i * width[0] + j]) / 2 -
481*77c1e3ccSAndroid Build Coastguard Worker                         cb[i * width[0] + j]);
482*77c1e3ccSAndroid Build Coastguard Worker 
483*77c1e3ccSAndroid Build Coastguard Worker       rg_mat[i * width[0] + j] = r - g;
484*77c1e3ccSAndroid Build Coastguard Worker       by_mat[i * width[0] + j] = b - y;
485*77c1e3ccSAndroid Build Coastguard Worker       gr_mat[i * width[0] + j] = g - r;
486*77c1e3ccSAndroid Build Coastguard Worker       yb_mat[i * width[0] + j] = y - b;
487*77c1e3ccSAndroid Build Coastguard Worker     }
488*77c1e3ccSAndroid Build Coastguard Worker   }
489*77c1e3ccSAndroid Build Coastguard Worker 
490*77c1e3ccSAndroid Build Coastguard Worker   if (gaussian_pyramid_rgb(rg_mat, gr_mat, width, height, rg_map) == 0 ||
491*77c1e3ccSAndroid Build Coastguard Worker       gaussian_pyramid_rgb(by_mat, yb_mat, width, height, by_map) == 0) {
492*77c1e3ccSAndroid Build Coastguard Worker     aom_free(rg_mat);
493*77c1e3ccSAndroid Build Coastguard Worker     aom_free(by_mat);
494*77c1e3ccSAndroid Build Coastguard Worker     aom_free(gr_mat);
495*77c1e3ccSAndroid Build Coastguard Worker     aom_free(yb_mat);
496*77c1e3ccSAndroid Build Coastguard Worker     return 0;
497*77c1e3ccSAndroid Build Coastguard Worker   }
498*77c1e3ccSAndroid Build Coastguard Worker 
499*77c1e3ccSAndroid Build Coastguard Worker   aom_free(rg_mat);
500*77c1e3ccSAndroid Build Coastguard Worker   aom_free(by_mat);
501*77c1e3ccSAndroid Build Coastguard Worker   aom_free(gr_mat);
502*77c1e3ccSAndroid Build Coastguard Worker   aom_free(yb_mat);
503*77c1e3ccSAndroid Build Coastguard Worker   return 1;
504*77c1e3ccSAndroid Build Coastguard Worker }
505*77c1e3ccSAndroid Build Coastguard Worker 
filter2d(const double * input,const double kernel[9][9],int width,int height,double * output)506*77c1e3ccSAndroid Build Coastguard Worker static inline void filter2d(const double *input, const double kernel[9][9],
507*77c1e3ccSAndroid Build Coastguard Worker                             int width, int height, double *output) {
508*77c1e3ccSAndroid Build Coastguard Worker   const int window_size = 9;
509*77c1e3ccSAndroid Build Coastguard Worker   double map_section[81];
510*77c1e3ccSAndroid Build Coastguard Worker   for (int y = 0; y <= height - 1; ++y) {
511*77c1e3ccSAndroid Build Coastguard Worker     for (int x = 0; x <= width - 1; ++x) {
512*77c1e3ccSAndroid Build Coastguard Worker       int i = 0;
513*77c1e3ccSAndroid Build Coastguard Worker       for (int yy = y - window_size / 2; yy <= y + window_size / 2; ++yy) {
514*77c1e3ccSAndroid Build Coastguard Worker         for (int xx = x - window_size / 2; xx <= x + window_size / 2; ++xx) {
515*77c1e3ccSAndroid Build Coastguard Worker           int yvalue = clamp(yy, 0, height - 1);
516*77c1e3ccSAndroid Build Coastguard Worker           int xvalue = clamp(xx, 0, width - 1);
517*77c1e3ccSAndroid Build Coastguard Worker           map_section[i++] = input[yvalue * width + xvalue];
518*77c1e3ccSAndroid Build Coastguard Worker         }
519*77c1e3ccSAndroid Build Coastguard Worker       }
520*77c1e3ccSAndroid Build Coastguard Worker 
521*77c1e3ccSAndroid Build Coastguard Worker       output[y * width + x] = 0;
522*77c1e3ccSAndroid Build Coastguard Worker       for (int k = 0; k < window_size; ++k) {
523*77c1e3ccSAndroid Build Coastguard Worker         for (int l = 0; l < window_size; ++l) {
524*77c1e3ccSAndroid Build Coastguard Worker           output[y * width + x] +=
525*77c1e3ccSAndroid Build Coastguard Worker               kernel[k][l] * map_section[k * window_size + l];
526*77c1e3ccSAndroid Build Coastguard Worker         }
527*77c1e3ccSAndroid Build Coastguard Worker       }
528*77c1e3ccSAndroid Build Coastguard Worker     }
529*77c1e3ccSAndroid Build Coastguard Worker   }
530*77c1e3ccSAndroid Build Coastguard Worker }
531*77c1e3ccSAndroid Build Coastguard Worker 
get_feature_map_orientation(const double * intensity,int width[9],int height[9],saliency_feature_map * dst[24])532*77c1e3ccSAndroid Build Coastguard Worker static int get_feature_map_orientation(const double *intensity, int width[9],
533*77c1e3ccSAndroid Build Coastguard Worker                                        int height[9],
534*77c1e3ccSAndroid Build Coastguard Worker                                        saliency_feature_map *dst[24]) {
535*77c1e3ccSAndroid Build Coastguard Worker   double *gaussian_map[9];
536*77c1e3ccSAndroid Build Coastguard Worker 
537*77c1e3ccSAndroid Build Coastguard Worker   gaussian_map[0] =
538*77c1e3ccSAndroid Build Coastguard Worker       (double *)aom_malloc(width[0] * height[0] * sizeof(*gaussian_map[0]));
539*77c1e3ccSAndroid Build Coastguard Worker   if (!gaussian_map[0]) {
540*77c1e3ccSAndroid Build Coastguard Worker     return 0;
541*77c1e3ccSAndroid Build Coastguard Worker   }
542*77c1e3ccSAndroid Build Coastguard Worker   memcpy(gaussian_map[0], intensity, width[0] * height[0] * sizeof(double));
543*77c1e3ccSAndroid Build Coastguard Worker 
544*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 1; i < 9; ++i) {
545*77c1e3ccSAndroid Build Coastguard Worker     int stride = width[i - 1];
546*77c1e3ccSAndroid Build Coastguard Worker     int new_width = width[i];
547*77c1e3ccSAndroid Build Coastguard Worker     int new_height = height[i];
548*77c1e3ccSAndroid Build Coastguard Worker 
549*77c1e3ccSAndroid Build Coastguard Worker     gaussian_map[i] =
550*77c1e3ccSAndroid Build Coastguard Worker         (double *)aom_malloc(new_width * new_height * sizeof(*gaussian_map[i]));
551*77c1e3ccSAndroid Build Coastguard Worker     if (!gaussian_map[i]) {
552*77c1e3ccSAndroid Build Coastguard Worker       for (int l = 0; l < i; ++l) {
553*77c1e3ccSAndroid Build Coastguard Worker         aom_free(gaussian_map[l]);
554*77c1e3ccSAndroid Build Coastguard Worker       }
555*77c1e3ccSAndroid Build Coastguard Worker       return 0;
556*77c1e3ccSAndroid Build Coastguard Worker     }
557*77c1e3ccSAndroid Build Coastguard Worker     memset(gaussian_map[i], 0, new_width * new_height * sizeof(double));
558*77c1e3ccSAndroid Build Coastguard Worker     decimate_map(gaussian_map[i - 1], height[i - 1], width[i - 1], stride,
559*77c1e3ccSAndroid Build Coastguard Worker                  gaussian_map[i]);
560*77c1e3ccSAndroid Build Coastguard Worker   }
561*77c1e3ccSAndroid Build Coastguard Worker 
562*77c1e3ccSAndroid Build Coastguard Worker   double *tempGaborOutput[4][9];  //[angle: 0, 45, 90, 135 degree][filter_size]
563*77c1e3ccSAndroid Build Coastguard Worker 
564*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 2; i < 9; ++i) {
565*77c1e3ccSAndroid Build Coastguard Worker     const int cur_height = height[i];
566*77c1e3ccSAndroid Build Coastguard Worker     const int cur_width = width[i];
567*77c1e3ccSAndroid Build Coastguard Worker     for (int j = 0; j < 4; ++j) {
568*77c1e3ccSAndroid Build Coastguard Worker       tempGaborOutput[j][i] = (double *)aom_malloc(
569*77c1e3ccSAndroid Build Coastguard Worker           cur_height * cur_width * sizeof(*tempGaborOutput[j][i]));
570*77c1e3ccSAndroid Build Coastguard Worker       if (!tempGaborOutput[j][i]) {
571*77c1e3ccSAndroid Build Coastguard Worker         for (int l = 0; l < 9; ++l) {
572*77c1e3ccSAndroid Build Coastguard Worker           aom_free(gaussian_map[l]);
573*77c1e3ccSAndroid Build Coastguard Worker         }
574*77c1e3ccSAndroid Build Coastguard Worker         for (int h = 0; h < 4; ++h) {
575*77c1e3ccSAndroid Build Coastguard Worker           for (int g = 2; g < 9; ++g) {
576*77c1e3ccSAndroid Build Coastguard Worker             aom_free(tempGaborOutput[h][g]);
577*77c1e3ccSAndroid Build Coastguard Worker           }
578*77c1e3ccSAndroid Build Coastguard Worker         }
579*77c1e3ccSAndroid Build Coastguard Worker         return 0;
580*77c1e3ccSAndroid Build Coastguard Worker       }
581*77c1e3ccSAndroid Build Coastguard Worker       filter2d(gaussian_map[i], kGaborFilter[j], cur_width, cur_height,
582*77c1e3ccSAndroid Build Coastguard Worker                tempGaborOutput[j][i]);
583*77c1e3ccSAndroid Build Coastguard Worker     }
584*77c1e3ccSAndroid Build Coastguard Worker   }
585*77c1e3ccSAndroid Build Coastguard Worker 
586*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 9; ++i) {
587*77c1e3ccSAndroid Build Coastguard Worker     aom_free(gaussian_map[i]);
588*77c1e3ccSAndroid Build Coastguard Worker   }
589*77c1e3ccSAndroid Build Coastguard Worker 
590*77c1e3ccSAndroid Build Coastguard Worker   saliency_feature_map
591*77c1e3ccSAndroid Build Coastguard Worker       *tmp[4][6];  //[angle: 0, 45, 90, 135 degree][filter_size]
592*77c1e3ccSAndroid Build Coastguard Worker 
593*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 6; ++i) {
594*77c1e3ccSAndroid Build Coastguard Worker     for (int j = 0; j < 4; ++j) {
595*77c1e3ccSAndroid Build Coastguard Worker       tmp[j][i] = dst[j * 6 + i];
596*77c1e3ccSAndroid Build Coastguard Worker     }
597*77c1e3ccSAndroid Build Coastguard Worker   }
598*77c1e3ccSAndroid Build Coastguard Worker 
599*77c1e3ccSAndroid Build Coastguard Worker   for (int j = 0; j < 4; ++j) {
600*77c1e3ccSAndroid Build Coastguard Worker     if (center_surround_diff((const double **)tempGaborOutput[j], height, width,
601*77c1e3ccSAndroid Build Coastguard Worker                              tmp[j]) == 0) {
602*77c1e3ccSAndroid Build Coastguard Worker       for (int h = 0; h < 4; ++h) {
603*77c1e3ccSAndroid Build Coastguard Worker         for (int g = 2; g < 9; ++g) {
604*77c1e3ccSAndroid Build Coastguard Worker           aom_free(tempGaborOutput[h][g]);
605*77c1e3ccSAndroid Build Coastguard Worker         }
606*77c1e3ccSAndroid Build Coastguard Worker       }
607*77c1e3ccSAndroid Build Coastguard Worker       return 0;
608*77c1e3ccSAndroid Build Coastguard Worker     }
609*77c1e3ccSAndroid Build Coastguard Worker   }
610*77c1e3ccSAndroid Build Coastguard Worker 
611*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 2; i < 9; ++i) {
612*77c1e3ccSAndroid Build Coastguard Worker     for (int j = 0; j < 4; ++j) {
613*77c1e3ccSAndroid Build Coastguard Worker       aom_free(tempGaborOutput[j][i]);
614*77c1e3ccSAndroid Build Coastguard Worker     }
615*77c1e3ccSAndroid Build Coastguard Worker   }
616*77c1e3ccSAndroid Build Coastguard Worker 
617*77c1e3ccSAndroid Build Coastguard Worker   return 1;
618*77c1e3ccSAndroid Build Coastguard Worker }
619*77c1e3ccSAndroid Build Coastguard Worker 
find_min_max(const saliency_feature_map * input,double * max_value,double * min_value)620*77c1e3ccSAndroid Build Coastguard Worker static inline void find_min_max(const saliency_feature_map *input,
621*77c1e3ccSAndroid Build Coastguard Worker                                 double *max_value, double *min_value) {
622*77c1e3ccSAndroid Build Coastguard Worker   assert(input && input->buf);
623*77c1e3ccSAndroid Build Coastguard Worker   *min_value = DBL_MAX;
624*77c1e3ccSAndroid Build Coastguard Worker   *max_value = 0.0;
625*77c1e3ccSAndroid Build Coastguard Worker 
626*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < input->height; ++i) {
627*77c1e3ccSAndroid Build Coastguard Worker     for (int j = 0; j < input->width; ++j) {
628*77c1e3ccSAndroid Build Coastguard Worker       assert(input->buf[i * input->width + j] >= 0.0);
629*77c1e3ccSAndroid Build Coastguard Worker       *min_value = fmin(input->buf[i * input->width + j], *min_value);
630*77c1e3ccSAndroid Build Coastguard Worker       *max_value = fmax(input->buf[i * input->width + j], *max_value);
631*77c1e3ccSAndroid Build Coastguard Worker     }
632*77c1e3ccSAndroid Build Coastguard Worker   }
633*77c1e3ccSAndroid Build Coastguard Worker }
634*77c1e3ccSAndroid Build Coastguard Worker 
average_local_max(const saliency_feature_map * input,int stepsize)635*77c1e3ccSAndroid Build Coastguard Worker static inline double average_local_max(const saliency_feature_map *input,
636*77c1e3ccSAndroid Build Coastguard Worker                                        int stepsize) {
637*77c1e3ccSAndroid Build Coastguard Worker   int numlocal = 0;
638*77c1e3ccSAndroid Build Coastguard Worker   double lmaxmean = 0, lmax = 0, dummy = 0;
639*77c1e3ccSAndroid Build Coastguard Worker   saliency_feature_map local_map;
640*77c1e3ccSAndroid Build Coastguard Worker   local_map.height = stepsize;
641*77c1e3ccSAndroid Build Coastguard Worker   local_map.width = stepsize;
642*77c1e3ccSAndroid Build Coastguard Worker   local_map.buf =
643*77c1e3ccSAndroid Build Coastguard Worker       (double *)aom_malloc(stepsize * stepsize * sizeof(*local_map.buf));
644*77c1e3ccSAndroid Build Coastguard Worker 
645*77c1e3ccSAndroid Build Coastguard Worker   if (!local_map.buf) {
646*77c1e3ccSAndroid Build Coastguard Worker     return -1;
647*77c1e3ccSAndroid Build Coastguard Worker   }
648*77c1e3ccSAndroid Build Coastguard Worker 
649*77c1e3ccSAndroid Build Coastguard Worker   for (int y = 0; y < input->height - stepsize; y += stepsize) {
650*77c1e3ccSAndroid Build Coastguard Worker     for (int x = 0; x < input->width - stepsize; x += stepsize) {
651*77c1e3ccSAndroid Build Coastguard Worker       for (int i = 0; i < stepsize; ++i) {
652*77c1e3ccSAndroid Build Coastguard Worker         for (int j = 0; j < stepsize; ++j) {
653*77c1e3ccSAndroid Build Coastguard Worker           local_map.buf[i * stepsize + j] =
654*77c1e3ccSAndroid Build Coastguard Worker               input->buf[(y + i) * input->width + x + j];
655*77c1e3ccSAndroid Build Coastguard Worker         }
656*77c1e3ccSAndroid Build Coastguard Worker       }
657*77c1e3ccSAndroid Build Coastguard Worker 
658*77c1e3ccSAndroid Build Coastguard Worker       find_min_max(&local_map, &lmax, &dummy);
659*77c1e3ccSAndroid Build Coastguard Worker       lmaxmean += lmax;
660*77c1e3ccSAndroid Build Coastguard Worker       numlocal++;
661*77c1e3ccSAndroid Build Coastguard Worker     }
662*77c1e3ccSAndroid Build Coastguard Worker   }
663*77c1e3ccSAndroid Build Coastguard Worker 
664*77c1e3ccSAndroid Build Coastguard Worker   aom_free(local_map.buf);
665*77c1e3ccSAndroid Build Coastguard Worker 
666*77c1e3ccSAndroid Build Coastguard Worker   return lmaxmean / numlocal;
667*77c1e3ccSAndroid Build Coastguard Worker }
668*77c1e3ccSAndroid Build Coastguard Worker 
669*77c1e3ccSAndroid Build Coastguard Worker // Linear normalization the values in the map to [0,1].
minmax_normalize(saliency_feature_map * input)670*77c1e3ccSAndroid Build Coastguard Worker static void minmax_normalize(saliency_feature_map *input) {
671*77c1e3ccSAndroid Build Coastguard Worker   double max_value, min_value;
672*77c1e3ccSAndroid Build Coastguard Worker   find_min_max(input, &max_value, &min_value);
673*77c1e3ccSAndroid Build Coastguard Worker 
674*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < input->height; ++i) {
675*77c1e3ccSAndroid Build Coastguard Worker     for (int j = 0; j < input->width; ++j) {
676*77c1e3ccSAndroid Build Coastguard Worker       if (max_value != min_value) {
677*77c1e3ccSAndroid Build Coastguard Worker         input->buf[i * input->width + j] =
678*77c1e3ccSAndroid Build Coastguard Worker             input->buf[i * input->width + j] / (max_value - min_value) +
679*77c1e3ccSAndroid Build Coastguard Worker             min_value / (min_value - max_value);
680*77c1e3ccSAndroid Build Coastguard Worker       } else {
681*77c1e3ccSAndroid Build Coastguard Worker         input->buf[i * input->width + j] -= min_value;
682*77c1e3ccSAndroid Build Coastguard Worker       }
683*77c1e3ccSAndroid Build Coastguard Worker     }
684*77c1e3ccSAndroid Build Coastguard Worker   }
685*77c1e3ccSAndroid Build Coastguard Worker }
686*77c1e3ccSAndroid Build Coastguard Worker 
687*77c1e3ccSAndroid Build Coastguard Worker // This function is to promote meaningful “activation spots” in the map and
688*77c1e3ccSAndroid Build Coastguard Worker // ignores homogeneous areas.
nomalization_operator(saliency_feature_map * input,int stepsize)689*77c1e3ccSAndroid Build Coastguard Worker static int nomalization_operator(saliency_feature_map *input, int stepsize) {
690*77c1e3ccSAndroid Build Coastguard Worker   minmax_normalize(input);
691*77c1e3ccSAndroid Build Coastguard Worker   double lmaxmean = average_local_max(input, stepsize);
692*77c1e3ccSAndroid Build Coastguard Worker   if (lmaxmean < 0) {
693*77c1e3ccSAndroid Build Coastguard Worker     return 0;
694*77c1e3ccSAndroid Build Coastguard Worker   }
695*77c1e3ccSAndroid Build Coastguard Worker   double normCoeff = (1 - lmaxmean) * (1 - lmaxmean);
696*77c1e3ccSAndroid Build Coastguard Worker 
697*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < input->height; ++i) {
698*77c1e3ccSAndroid Build Coastguard Worker     for (int j = 0; j < input->width; ++j) {
699*77c1e3ccSAndroid Build Coastguard Worker       input->buf[i * input->width + j] *= normCoeff;
700*77c1e3ccSAndroid Build Coastguard Worker     }
701*77c1e3ccSAndroid Build Coastguard Worker   }
702*77c1e3ccSAndroid Build Coastguard Worker 
703*77c1e3ccSAndroid Build Coastguard Worker   return 1;
704*77c1e3ccSAndroid Build Coastguard Worker }
705*77c1e3ccSAndroid Build Coastguard Worker 
706*77c1e3ccSAndroid Build Coastguard Worker // Normalize the values in feature maps to [0,1], and then upscale all maps to
707*77c1e3ccSAndroid Build Coastguard Worker // the original frame size.
normalize_fm(saliency_feature_map * input[6],int width[9],int height[9],int num_fm,saliency_feature_map * output[6])708*77c1e3ccSAndroid Build Coastguard Worker static int normalize_fm(saliency_feature_map *input[6], int width[9],
709*77c1e3ccSAndroid Build Coastguard Worker                         int height[9], int num_fm,
710*77c1e3ccSAndroid Build Coastguard Worker                         saliency_feature_map *output[6]) {
711*77c1e3ccSAndroid Build Coastguard Worker   // Feature maps (FM) are generated by function "center_surround_diff()". The
712*77c1e3ccSAndroid Build Coastguard Worker   // difference is between a fine scale c and a coarser scale s, where c \in {2,
713*77c1e3ccSAndroid Build Coastguard Worker   // 3, 4}, and s = c + delta, where delta \in {3, 4}, and the FM size is scale
714*77c1e3ccSAndroid Build Coastguard Worker   // c. Specifically, i=0: c=2 and s=5, i=1: c=2 and s=6, i=2: c=3 and s=6, i=3:
715*77c1e3ccSAndroid Build Coastguard Worker   // c=3 and s=7, i=4: c=4 and s=7, i=5: c=4 and s=8.
716*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < num_fm; ++i) {
717*77c1e3ccSAndroid Build Coastguard Worker     if (nomalization_operator(input[i], 8) == 0) {
718*77c1e3ccSAndroid Build Coastguard Worker       return 0;
719*77c1e3ccSAndroid Build Coastguard Worker     }
720*77c1e3ccSAndroid Build Coastguard Worker 
721*77c1e3ccSAndroid Build Coastguard Worker     // Upscale FM to original frame size
722*77c1e3ccSAndroid Build Coastguard Worker     if (upscale_map(input[i]->buf, (i / 2) + 2, 0, height, width,
723*77c1e3ccSAndroid Build Coastguard Worker                     output[i]->buf) == 0) {
724*77c1e3ccSAndroid Build Coastguard Worker       return 0;
725*77c1e3ccSAndroid Build Coastguard Worker     }
726*77c1e3ccSAndroid Build Coastguard Worker   }
727*77c1e3ccSAndroid Build Coastguard Worker   return 1;
728*77c1e3ccSAndroid Build Coastguard Worker }
729*77c1e3ccSAndroid Build Coastguard Worker 
730*77c1e3ccSAndroid Build Coastguard Worker // Combine feature maps with the same category (intensity, color, or
731*77c1e3ccSAndroid Build Coastguard Worker // orientation) into one conspicuity map.
normalized_map(saliency_feature_map * input[6],int width[9],int height[9],saliency_feature_map * output)732*77c1e3ccSAndroid Build Coastguard Worker static int normalized_map(saliency_feature_map *input[6], int width[9],
733*77c1e3ccSAndroid Build Coastguard Worker                           int height[9], saliency_feature_map *output) {
734*77c1e3ccSAndroid Build Coastguard Worker   int num_fm = 6;
735*77c1e3ccSAndroid Build Coastguard Worker 
736*77c1e3ccSAndroid Build Coastguard Worker   saliency_feature_map *n_input[6];
737*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 6; ++i) {
738*77c1e3ccSAndroid Build Coastguard Worker     n_input[i] = (saliency_feature_map *)aom_malloc(sizeof(*n_input[i]));
739*77c1e3ccSAndroid Build Coastguard Worker     if (!n_input[i]) {
740*77c1e3ccSAndroid Build Coastguard Worker       return 0;
741*77c1e3ccSAndroid Build Coastguard Worker     }
742*77c1e3ccSAndroid Build Coastguard Worker     n_input[i]->buf =
743*77c1e3ccSAndroid Build Coastguard Worker         (double *)aom_malloc(width[0] * height[0] * sizeof(*n_input[i]->buf));
744*77c1e3ccSAndroid Build Coastguard Worker     if (!n_input[i]->buf) {
745*77c1e3ccSAndroid Build Coastguard Worker       aom_free(n_input[i]);
746*77c1e3ccSAndroid Build Coastguard Worker       return 0;
747*77c1e3ccSAndroid Build Coastguard Worker     }
748*77c1e3ccSAndroid Build Coastguard Worker     n_input[i]->height = height[0];
749*77c1e3ccSAndroid Build Coastguard Worker     n_input[i]->width = width[0];
750*77c1e3ccSAndroid Build Coastguard Worker   }
751*77c1e3ccSAndroid Build Coastguard Worker 
752*77c1e3ccSAndroid Build Coastguard Worker   if (normalize_fm(input, width, height, num_fm, n_input) == 0) {
753*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < num_fm; ++i) {
754*77c1e3ccSAndroid Build Coastguard Worker       aom_free(n_input[i]->buf);
755*77c1e3ccSAndroid Build Coastguard Worker       aom_free(n_input[i]);
756*77c1e3ccSAndroid Build Coastguard Worker     }
757*77c1e3ccSAndroid Build Coastguard Worker     return 0;
758*77c1e3ccSAndroid Build Coastguard Worker   }
759*77c1e3ccSAndroid Build Coastguard Worker 
760*77c1e3ccSAndroid Build Coastguard Worker   // Add up all normalized feature maps with the same category into one map.
761*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < num_fm; ++i) {
762*77c1e3ccSAndroid Build Coastguard Worker     for (int r = 0; r < height[0]; ++r) {
763*77c1e3ccSAndroid Build Coastguard Worker       for (int c = 0; c < width[0]; ++c) {
764*77c1e3ccSAndroid Build Coastguard Worker         output->buf[r * width[0] + c] += n_input[i]->buf[r * width[0] + c];
765*77c1e3ccSAndroid Build Coastguard Worker       }
766*77c1e3ccSAndroid Build Coastguard Worker     }
767*77c1e3ccSAndroid Build Coastguard Worker   }
768*77c1e3ccSAndroid Build Coastguard Worker 
769*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < num_fm; ++i) {
770*77c1e3ccSAndroid Build Coastguard Worker     aom_free(n_input[i]->buf);
771*77c1e3ccSAndroid Build Coastguard Worker     aom_free(n_input[i]);
772*77c1e3ccSAndroid Build Coastguard Worker   }
773*77c1e3ccSAndroid Build Coastguard Worker 
774*77c1e3ccSAndroid Build Coastguard Worker   nomalization_operator(output, 8);
775*77c1e3ccSAndroid Build Coastguard Worker   return 1;
776*77c1e3ccSAndroid Build Coastguard Worker }
777*77c1e3ccSAndroid Build Coastguard Worker 
normalized_map_rgb(saliency_feature_map * rg_map[6],saliency_feature_map * by_map[6],int width[9],int height[9],saliency_feature_map * output)778*77c1e3ccSAndroid Build Coastguard Worker static int normalized_map_rgb(saliency_feature_map *rg_map[6],
779*77c1e3ccSAndroid Build Coastguard Worker                               saliency_feature_map *by_map[6], int width[9],
780*77c1e3ccSAndroid Build Coastguard Worker                               int height[9], saliency_feature_map *output) {
781*77c1e3ccSAndroid Build Coastguard Worker   saliency_feature_map *color_cm[2];  // 0: color_cm_rg, 1: color_cm_by
782*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 2; ++i) {
783*77c1e3ccSAndroid Build Coastguard Worker     color_cm[i] = aom_malloc(sizeof(*color_cm[i]));
784*77c1e3ccSAndroid Build Coastguard Worker     if (!color_cm[i]) {
785*77c1e3ccSAndroid Build Coastguard Worker       return 0;
786*77c1e3ccSAndroid Build Coastguard Worker     }
787*77c1e3ccSAndroid Build Coastguard Worker     color_cm[i]->buf =
788*77c1e3ccSAndroid Build Coastguard Worker         (double *)aom_malloc(width[0] * height[0] * sizeof(*color_cm[i]->buf));
789*77c1e3ccSAndroid Build Coastguard Worker     if (!color_cm[i]->buf) {
790*77c1e3ccSAndroid Build Coastguard Worker       for (int l = 0; l < i; ++l) {
791*77c1e3ccSAndroid Build Coastguard Worker         aom_free(color_cm[l]->buf);
792*77c1e3ccSAndroid Build Coastguard Worker       }
793*77c1e3ccSAndroid Build Coastguard Worker       aom_free(color_cm[i]);
794*77c1e3ccSAndroid Build Coastguard Worker       return 0;
795*77c1e3ccSAndroid Build Coastguard Worker     }
796*77c1e3ccSAndroid Build Coastguard Worker 
797*77c1e3ccSAndroid Build Coastguard Worker     color_cm[i]->width = width[0];
798*77c1e3ccSAndroid Build Coastguard Worker     color_cm[i]->height = height[0];
799*77c1e3ccSAndroid Build Coastguard Worker     memset(color_cm[i]->buf, 0,
800*77c1e3ccSAndroid Build Coastguard Worker            width[0] * height[0] * sizeof(*color_cm[i]->buf));
801*77c1e3ccSAndroid Build Coastguard Worker   }
802*77c1e3ccSAndroid Build Coastguard Worker 
803*77c1e3ccSAndroid Build Coastguard Worker   if (normalized_map(rg_map, width, height, color_cm[0]) == 0 ||
804*77c1e3ccSAndroid Build Coastguard Worker       normalized_map(by_map, width, height, color_cm[1]) == 0) {
805*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < 2; ++i) {
806*77c1e3ccSAndroid Build Coastguard Worker       aom_free(color_cm[i]->buf);
807*77c1e3ccSAndroid Build Coastguard Worker       aom_free(color_cm[i]);
808*77c1e3ccSAndroid Build Coastguard Worker     }
809*77c1e3ccSAndroid Build Coastguard Worker     return 0;
810*77c1e3ccSAndroid Build Coastguard Worker   }
811*77c1e3ccSAndroid Build Coastguard Worker 
812*77c1e3ccSAndroid Build Coastguard Worker   for (int r = 0; r < height[0]; ++r) {
813*77c1e3ccSAndroid Build Coastguard Worker     for (int c = 0; c < width[0]; ++c) {
814*77c1e3ccSAndroid Build Coastguard Worker       output->buf[r * width[0] + c] = color_cm[0]->buf[r * width[0] + c] +
815*77c1e3ccSAndroid Build Coastguard Worker                                       color_cm[1]->buf[r * width[0] + c];
816*77c1e3ccSAndroid Build Coastguard Worker     }
817*77c1e3ccSAndroid Build Coastguard Worker   }
818*77c1e3ccSAndroid Build Coastguard Worker 
819*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 2; ++i) {
820*77c1e3ccSAndroid Build Coastguard Worker     aom_free(color_cm[i]->buf);
821*77c1e3ccSAndroid Build Coastguard Worker     aom_free(color_cm[i]);
822*77c1e3ccSAndroid Build Coastguard Worker   }
823*77c1e3ccSAndroid Build Coastguard Worker 
824*77c1e3ccSAndroid Build Coastguard Worker   nomalization_operator(output, 8);
825*77c1e3ccSAndroid Build Coastguard Worker   return 1;
826*77c1e3ccSAndroid Build Coastguard Worker }
827*77c1e3ccSAndroid Build Coastguard Worker 
normalized_map_orientation(saliency_feature_map * orientation_map[24],int width[9],int height[9],saliency_feature_map * output)828*77c1e3ccSAndroid Build Coastguard Worker static int normalized_map_orientation(saliency_feature_map *orientation_map[24],
829*77c1e3ccSAndroid Build Coastguard Worker                                       int width[9], int height[9],
830*77c1e3ccSAndroid Build Coastguard Worker                                       saliency_feature_map *output) {
831*77c1e3ccSAndroid Build Coastguard Worker   int num_fms_per_angle = 6;
832*77c1e3ccSAndroid Build Coastguard Worker 
833*77c1e3ccSAndroid Build Coastguard Worker   saliency_feature_map *ofm[4][6];
834*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < num_fms_per_angle; ++i) {
835*77c1e3ccSAndroid Build Coastguard Worker     for (int j = 0; j < 4; ++j) {
836*77c1e3ccSAndroid Build Coastguard Worker       ofm[j][i] = orientation_map[j * num_fms_per_angle + i];
837*77c1e3ccSAndroid Build Coastguard Worker     }
838*77c1e3ccSAndroid Build Coastguard Worker   }
839*77c1e3ccSAndroid Build Coastguard Worker 
840*77c1e3ccSAndroid Build Coastguard Worker   // extract conspicuity map for each angle
841*77c1e3ccSAndroid Build Coastguard Worker   saliency_feature_map *nofm = aom_malloc(sizeof(*nofm));
842*77c1e3ccSAndroid Build Coastguard Worker   if (!nofm) {
843*77c1e3ccSAndroid Build Coastguard Worker     return 0;
844*77c1e3ccSAndroid Build Coastguard Worker   }
845*77c1e3ccSAndroid Build Coastguard Worker   nofm->buf = (double *)aom_malloc(width[0] * height[0] * sizeof(*nofm->buf));
846*77c1e3ccSAndroid Build Coastguard Worker   if (!nofm->buf) {
847*77c1e3ccSAndroid Build Coastguard Worker     aom_free(nofm);
848*77c1e3ccSAndroid Build Coastguard Worker     return 0;
849*77c1e3ccSAndroid Build Coastguard Worker   }
850*77c1e3ccSAndroid Build Coastguard Worker   nofm->height = height[0];
851*77c1e3ccSAndroid Build Coastguard Worker   nofm->width = width[0];
852*77c1e3ccSAndroid Build Coastguard Worker 
853*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 4; ++i) {
854*77c1e3ccSAndroid Build Coastguard Worker     memset(nofm->buf, 0, width[0] * height[0] * sizeof(*nofm->buf));
855*77c1e3ccSAndroid Build Coastguard Worker     if (normalized_map(ofm[i], width, height, nofm) == 0) {
856*77c1e3ccSAndroid Build Coastguard Worker       aom_free(nofm->buf);
857*77c1e3ccSAndroid Build Coastguard Worker       aom_free(nofm);
858*77c1e3ccSAndroid Build Coastguard Worker       return 0;
859*77c1e3ccSAndroid Build Coastguard Worker     }
860*77c1e3ccSAndroid Build Coastguard Worker 
861*77c1e3ccSAndroid Build Coastguard Worker     for (int r = 0; r < height[0]; ++r) {
862*77c1e3ccSAndroid Build Coastguard Worker       for (int c = 0; c < width[0]; ++c) {
863*77c1e3ccSAndroid Build Coastguard Worker         output->buf[r * width[0] + c] += nofm->buf[r * width[0] + c];
864*77c1e3ccSAndroid Build Coastguard Worker       }
865*77c1e3ccSAndroid Build Coastguard Worker     }
866*77c1e3ccSAndroid Build Coastguard Worker   }
867*77c1e3ccSAndroid Build Coastguard Worker 
868*77c1e3ccSAndroid Build Coastguard Worker   aom_free(nofm->buf);
869*77c1e3ccSAndroid Build Coastguard Worker   aom_free(nofm);
870*77c1e3ccSAndroid Build Coastguard Worker 
871*77c1e3ccSAndroid Build Coastguard Worker   nomalization_operator(output, 8);
872*77c1e3ccSAndroid Build Coastguard Worker   return 1;
873*77c1e3ccSAndroid Build Coastguard Worker }
874*77c1e3ccSAndroid Build Coastguard Worker 
875*77c1e3ccSAndroid Build Coastguard Worker // Set pixel level saliency mask based on Itti-Koch algorithm
av1_set_saliency_map(AV1_COMP * cpi)876*77c1e3ccSAndroid Build Coastguard Worker int av1_set_saliency_map(AV1_COMP *cpi) {
877*77c1e3ccSAndroid Build Coastguard Worker   AV1_COMMON *const cm = &cpi->common;
878*77c1e3ccSAndroid Build Coastguard Worker 
879*77c1e3ccSAndroid Build Coastguard Worker   int frm_width = cm->width;
880*77c1e3ccSAndroid Build Coastguard Worker   int frm_height = cm->height;
881*77c1e3ccSAndroid Build Coastguard Worker 
882*77c1e3ccSAndroid Build Coastguard Worker   int pyr_height[9];
883*77c1e3ccSAndroid Build Coastguard Worker   int pyr_width[9];
884*77c1e3ccSAndroid Build Coastguard Worker 
885*77c1e3ccSAndroid Build Coastguard Worker   pyr_height[0] = frm_height;
886*77c1e3ccSAndroid Build Coastguard Worker   pyr_width[0] = frm_width;
887*77c1e3ccSAndroid Build Coastguard Worker 
888*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 1; i < 9; ++i) {
889*77c1e3ccSAndroid Build Coastguard Worker     pyr_width[i] = pyr_width[i - 1] / 2;
890*77c1e3ccSAndroid Build Coastguard Worker     pyr_height[i] = pyr_height[i - 1] / 2;
891*77c1e3ccSAndroid Build Coastguard Worker   }
892*77c1e3ccSAndroid Build Coastguard Worker 
893*77c1e3ccSAndroid Build Coastguard Worker   double *cr = aom_malloc(frm_width * frm_height * sizeof(*cr));
894*77c1e3ccSAndroid Build Coastguard Worker   double *cg = aom_malloc(frm_width * frm_height * sizeof(*cg));
895*77c1e3ccSAndroid Build Coastguard Worker   double *cb = aom_malloc(frm_width * frm_height * sizeof(*cb));
896*77c1e3ccSAndroid Build Coastguard Worker   double *intensity = aom_malloc(frm_width * frm_height * sizeof(*intensity));
897*77c1e3ccSAndroid Build Coastguard Worker 
898*77c1e3ccSAndroid Build Coastguard Worker   if (!cr || !cg || !cb || !intensity) {
899*77c1e3ccSAndroid Build Coastguard Worker     aom_free(cr);
900*77c1e3ccSAndroid Build Coastguard Worker     aom_free(cg);
901*77c1e3ccSAndroid Build Coastguard Worker     aom_free(cb);
902*77c1e3ccSAndroid Build Coastguard Worker     aom_free(intensity);
903*77c1e3ccSAndroid Build Coastguard Worker     return 0;
904*77c1e3ccSAndroid Build Coastguard Worker   }
905*77c1e3ccSAndroid Build Coastguard Worker 
906*77c1e3ccSAndroid Build Coastguard Worker   // Extract red / green / blue channels and intensity component
907*77c1e3ccSAndroid Build Coastguard Worker   get_color_intensity(cpi->source, cm->seq_params->subsampling_x,
908*77c1e3ccSAndroid Build Coastguard Worker                       cm->seq_params->subsampling_y, cr, cg, cb, intensity);
909*77c1e3ccSAndroid Build Coastguard Worker 
910*77c1e3ccSAndroid Build Coastguard Worker   // Feature Map Extraction
911*77c1e3ccSAndroid Build Coastguard Worker   // intensity map
912*77c1e3ccSAndroid Build Coastguard Worker   saliency_feature_map *i_map[6];
913*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 6; ++i) {
914*77c1e3ccSAndroid Build Coastguard Worker     int cur_height = pyr_height[(i / 2) + 2];
915*77c1e3ccSAndroid Build Coastguard Worker     int cur_width = pyr_width[(i / 2) + 2];
916*77c1e3ccSAndroid Build Coastguard Worker 
917*77c1e3ccSAndroid Build Coastguard Worker     i_map[i] = (saliency_feature_map *)aom_malloc(sizeof(*i_map[i]));
918*77c1e3ccSAndroid Build Coastguard Worker     if (!i_map[i]) {
919*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cr);
920*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cg);
921*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cb);
922*77c1e3ccSAndroid Build Coastguard Worker       aom_free(intensity);
923*77c1e3ccSAndroid Build Coastguard Worker       for (int l = 0; l < i; ++l) {
924*77c1e3ccSAndroid Build Coastguard Worker         aom_free(i_map[l]);
925*77c1e3ccSAndroid Build Coastguard Worker       }
926*77c1e3ccSAndroid Build Coastguard Worker       return 0;
927*77c1e3ccSAndroid Build Coastguard Worker     }
928*77c1e3ccSAndroid Build Coastguard Worker     i_map[i]->buf =
929*77c1e3ccSAndroid Build Coastguard Worker         (double *)aom_malloc(cur_height * cur_width * sizeof(*i_map[i]->buf));
930*77c1e3ccSAndroid Build Coastguard Worker     if (!i_map[i]->buf) {
931*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cr);
932*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cg);
933*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cb);
934*77c1e3ccSAndroid Build Coastguard Worker       aom_free(intensity);
935*77c1e3ccSAndroid Build Coastguard Worker       for (int l = 0; l < i; ++l) {
936*77c1e3ccSAndroid Build Coastguard Worker         aom_free(i_map[l]->buf);
937*77c1e3ccSAndroid Build Coastguard Worker         aom_free(i_map[l]);
938*77c1e3ccSAndroid Build Coastguard Worker       }
939*77c1e3ccSAndroid Build Coastguard Worker       return 0;
940*77c1e3ccSAndroid Build Coastguard Worker     }
941*77c1e3ccSAndroid Build Coastguard Worker     i_map[i]->height = cur_height;
942*77c1e3ccSAndroid Build Coastguard Worker     i_map[i]->width = cur_width;
943*77c1e3ccSAndroid Build Coastguard Worker   }
944*77c1e3ccSAndroid Build Coastguard Worker 
945*77c1e3ccSAndroid Build Coastguard Worker   if (get_feature_map_intensity(intensity, pyr_width, pyr_height, i_map) == 0) {
946*77c1e3ccSAndroid Build Coastguard Worker     aom_free(cr);
947*77c1e3ccSAndroid Build Coastguard Worker     aom_free(cg);
948*77c1e3ccSAndroid Build Coastguard Worker     aom_free(cb);
949*77c1e3ccSAndroid Build Coastguard Worker     aom_free(intensity);
950*77c1e3ccSAndroid Build Coastguard Worker     for (int l = 0; l < 6; ++l) {
951*77c1e3ccSAndroid Build Coastguard Worker       aom_free(i_map[l]->buf);
952*77c1e3ccSAndroid Build Coastguard Worker       aom_free(i_map[l]);
953*77c1e3ccSAndroid Build Coastguard Worker     }
954*77c1e3ccSAndroid Build Coastguard Worker     return 0;
955*77c1e3ccSAndroid Build Coastguard Worker   }
956*77c1e3ccSAndroid Build Coastguard Worker 
957*77c1e3ccSAndroid Build Coastguard Worker   // RGB map
958*77c1e3ccSAndroid Build Coastguard Worker   saliency_feature_map *rg_map[6], *by_map[6];
959*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 6; ++i) {
960*77c1e3ccSAndroid Build Coastguard Worker     int cur_height = pyr_height[(i / 2) + 2];
961*77c1e3ccSAndroid Build Coastguard Worker     int cur_width = pyr_width[(i / 2) + 2];
962*77c1e3ccSAndroid Build Coastguard Worker     rg_map[i] = (saliency_feature_map *)aom_malloc(sizeof(*rg_map[i]));
963*77c1e3ccSAndroid Build Coastguard Worker     by_map[i] = (saliency_feature_map *)aom_malloc(sizeof(*by_map[i]));
964*77c1e3ccSAndroid Build Coastguard Worker     if (!rg_map[i] || !by_map[i]) {
965*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cr);
966*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cg);
967*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cb);
968*77c1e3ccSAndroid Build Coastguard Worker       aom_free(intensity);
969*77c1e3ccSAndroid Build Coastguard Worker       for (int l = 0; l < 6; ++l) {
970*77c1e3ccSAndroid Build Coastguard Worker         aom_free(i_map[l]->buf);
971*77c1e3ccSAndroid Build Coastguard Worker         aom_free(i_map[l]);
972*77c1e3ccSAndroid Build Coastguard Worker         aom_free(rg_map[l]);
973*77c1e3ccSAndroid Build Coastguard Worker         aom_free(by_map[l]);
974*77c1e3ccSAndroid Build Coastguard Worker       }
975*77c1e3ccSAndroid Build Coastguard Worker       return 0;
976*77c1e3ccSAndroid Build Coastguard Worker     }
977*77c1e3ccSAndroid Build Coastguard Worker     rg_map[i]->buf =
978*77c1e3ccSAndroid Build Coastguard Worker         (double *)aom_malloc(cur_height * cur_width * sizeof(*rg_map[i]->buf));
979*77c1e3ccSAndroid Build Coastguard Worker     by_map[i]->buf =
980*77c1e3ccSAndroid Build Coastguard Worker         (double *)aom_malloc(cur_height * cur_width * sizeof(*by_map[i]->buf));
981*77c1e3ccSAndroid Build Coastguard Worker     if (!by_map[i]->buf || !rg_map[i]->buf) {
982*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cr);
983*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cg);
984*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cb);
985*77c1e3ccSAndroid Build Coastguard Worker       aom_free(intensity);
986*77c1e3ccSAndroid Build Coastguard Worker       for (int l = 0; l < 6; ++l) {
987*77c1e3ccSAndroid Build Coastguard Worker         aom_free(i_map[l]->buf);
988*77c1e3ccSAndroid Build Coastguard Worker         aom_free(i_map[l]);
989*77c1e3ccSAndroid Build Coastguard Worker       }
990*77c1e3ccSAndroid Build Coastguard Worker       for (int l = 0; l < i; ++l) {
991*77c1e3ccSAndroid Build Coastguard Worker         aom_free(rg_map[l]->buf);
992*77c1e3ccSAndroid Build Coastguard Worker         aom_free(by_map[l]->buf);
993*77c1e3ccSAndroid Build Coastguard Worker         aom_free(rg_map[l]);
994*77c1e3ccSAndroid Build Coastguard Worker         aom_free(by_map[l]);
995*77c1e3ccSAndroid Build Coastguard Worker       }
996*77c1e3ccSAndroid Build Coastguard Worker       return 0;
997*77c1e3ccSAndroid Build Coastguard Worker     }
998*77c1e3ccSAndroid Build Coastguard Worker     rg_map[i]->height = cur_height;
999*77c1e3ccSAndroid Build Coastguard Worker     rg_map[i]->width = cur_width;
1000*77c1e3ccSAndroid Build Coastguard Worker     by_map[i]->height = cur_height;
1001*77c1e3ccSAndroid Build Coastguard Worker     by_map[i]->width = cur_width;
1002*77c1e3ccSAndroid Build Coastguard Worker   }
1003*77c1e3ccSAndroid Build Coastguard Worker 
1004*77c1e3ccSAndroid Build Coastguard Worker   if (get_feature_map_rgb(cr, cg, cb, pyr_width, pyr_height, rg_map, by_map) ==
1005*77c1e3ccSAndroid Build Coastguard Worker       0) {
1006*77c1e3ccSAndroid Build Coastguard Worker     aom_free(cr);
1007*77c1e3ccSAndroid Build Coastguard Worker     aom_free(cg);
1008*77c1e3ccSAndroid Build Coastguard Worker     aom_free(cb);
1009*77c1e3ccSAndroid Build Coastguard Worker     aom_free(intensity);
1010*77c1e3ccSAndroid Build Coastguard Worker     for (int l = 0; l < 6; ++l) {
1011*77c1e3ccSAndroid Build Coastguard Worker       aom_free(i_map[l]->buf);
1012*77c1e3ccSAndroid Build Coastguard Worker       aom_free(rg_map[l]->buf);
1013*77c1e3ccSAndroid Build Coastguard Worker       aom_free(by_map[l]->buf);
1014*77c1e3ccSAndroid Build Coastguard Worker       aom_free(i_map[l]);
1015*77c1e3ccSAndroid Build Coastguard Worker       aom_free(rg_map[l]);
1016*77c1e3ccSAndroid Build Coastguard Worker       aom_free(by_map[l]);
1017*77c1e3ccSAndroid Build Coastguard Worker     }
1018*77c1e3ccSAndroid Build Coastguard Worker     return 0;
1019*77c1e3ccSAndroid Build Coastguard Worker   }
1020*77c1e3ccSAndroid Build Coastguard Worker 
1021*77c1e3ccSAndroid Build Coastguard Worker   // Orientation map
1022*77c1e3ccSAndroid Build Coastguard Worker   saliency_feature_map *orientation_map[24];
1023*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 24; ++i) {
1024*77c1e3ccSAndroid Build Coastguard Worker     int cur_height = pyr_height[((i % 6) / 2) + 2];
1025*77c1e3ccSAndroid Build Coastguard Worker     int cur_width = pyr_width[((i % 6) / 2) + 2];
1026*77c1e3ccSAndroid Build Coastguard Worker 
1027*77c1e3ccSAndroid Build Coastguard Worker     orientation_map[i] =
1028*77c1e3ccSAndroid Build Coastguard Worker         (saliency_feature_map *)aom_malloc(sizeof(*orientation_map[i]));
1029*77c1e3ccSAndroid Build Coastguard Worker     if (!orientation_map[i]) {
1030*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cr);
1031*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cg);
1032*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cb);
1033*77c1e3ccSAndroid Build Coastguard Worker       aom_free(intensity);
1034*77c1e3ccSAndroid Build Coastguard Worker       for (int l = 0; l < 6; ++l) {
1035*77c1e3ccSAndroid Build Coastguard Worker         aom_free(i_map[l]->buf);
1036*77c1e3ccSAndroid Build Coastguard Worker         aom_free(rg_map[l]->buf);
1037*77c1e3ccSAndroid Build Coastguard Worker         aom_free(by_map[l]->buf);
1038*77c1e3ccSAndroid Build Coastguard Worker         aom_free(i_map[l]);
1039*77c1e3ccSAndroid Build Coastguard Worker         aom_free(rg_map[l]);
1040*77c1e3ccSAndroid Build Coastguard Worker         aom_free(by_map[l]);
1041*77c1e3ccSAndroid Build Coastguard Worker       }
1042*77c1e3ccSAndroid Build Coastguard Worker       for (int h = 0; h < i; ++h) {
1043*77c1e3ccSAndroid Build Coastguard Worker         aom_free(orientation_map[h]);
1044*77c1e3ccSAndroid Build Coastguard Worker       }
1045*77c1e3ccSAndroid Build Coastguard Worker       return 0;
1046*77c1e3ccSAndroid Build Coastguard Worker     }
1047*77c1e3ccSAndroid Build Coastguard Worker 
1048*77c1e3ccSAndroid Build Coastguard Worker     orientation_map[i]->buf = (double *)aom_malloc(
1049*77c1e3ccSAndroid Build Coastguard Worker         cur_height * cur_width * sizeof(*orientation_map[i]->buf));
1050*77c1e3ccSAndroid Build Coastguard Worker     if (!orientation_map[i]->buf) {
1051*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cr);
1052*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cg);
1053*77c1e3ccSAndroid Build Coastguard Worker       aom_free(cb);
1054*77c1e3ccSAndroid Build Coastguard Worker       aom_free(intensity);
1055*77c1e3ccSAndroid Build Coastguard Worker       for (int l = 0; l < 6; ++l) {
1056*77c1e3ccSAndroid Build Coastguard Worker         aom_free(i_map[l]->buf);
1057*77c1e3ccSAndroid Build Coastguard Worker         aom_free(rg_map[l]->buf);
1058*77c1e3ccSAndroid Build Coastguard Worker         aom_free(by_map[l]->buf);
1059*77c1e3ccSAndroid Build Coastguard Worker         aom_free(i_map[l]);
1060*77c1e3ccSAndroid Build Coastguard Worker         aom_free(rg_map[l]);
1061*77c1e3ccSAndroid Build Coastguard Worker         aom_free(by_map[l]);
1062*77c1e3ccSAndroid Build Coastguard Worker       }
1063*77c1e3ccSAndroid Build Coastguard Worker 
1064*77c1e3ccSAndroid Build Coastguard Worker       for (int h = 0; h < i; ++h) {
1065*77c1e3ccSAndroid Build Coastguard Worker         aom_free(orientation_map[h]->buf);
1066*77c1e3ccSAndroid Build Coastguard Worker         aom_free(orientation_map[h]->buf);
1067*77c1e3ccSAndroid Build Coastguard Worker         aom_free(orientation_map[h]);
1068*77c1e3ccSAndroid Build Coastguard Worker         aom_free(orientation_map[h]);
1069*77c1e3ccSAndroid Build Coastguard Worker       }
1070*77c1e3ccSAndroid Build Coastguard Worker       return 0;
1071*77c1e3ccSAndroid Build Coastguard Worker     }
1072*77c1e3ccSAndroid Build Coastguard Worker 
1073*77c1e3ccSAndroid Build Coastguard Worker     orientation_map[i]->height = cur_height;
1074*77c1e3ccSAndroid Build Coastguard Worker     orientation_map[i]->width = cur_width;
1075*77c1e3ccSAndroid Build Coastguard Worker   }
1076*77c1e3ccSAndroid Build Coastguard Worker 
1077*77c1e3ccSAndroid Build Coastguard Worker   if (get_feature_map_orientation(intensity, pyr_width, pyr_height,
1078*77c1e3ccSAndroid Build Coastguard Worker                                   orientation_map) == 0) {
1079*77c1e3ccSAndroid Build Coastguard Worker     aom_free(cr);
1080*77c1e3ccSAndroid Build Coastguard Worker     aom_free(cg);
1081*77c1e3ccSAndroid Build Coastguard Worker     aom_free(cb);
1082*77c1e3ccSAndroid Build Coastguard Worker     aom_free(intensity);
1083*77c1e3ccSAndroid Build Coastguard Worker     for (int l = 0; l < 6; ++l) {
1084*77c1e3ccSAndroid Build Coastguard Worker       aom_free(i_map[l]->buf);
1085*77c1e3ccSAndroid Build Coastguard Worker       aom_free(rg_map[l]->buf);
1086*77c1e3ccSAndroid Build Coastguard Worker       aom_free(by_map[l]->buf);
1087*77c1e3ccSAndroid Build Coastguard Worker       aom_free(i_map[l]);
1088*77c1e3ccSAndroid Build Coastguard Worker       aom_free(rg_map[l]);
1089*77c1e3ccSAndroid Build Coastguard Worker       aom_free(by_map[l]);
1090*77c1e3ccSAndroid Build Coastguard Worker     }
1091*77c1e3ccSAndroid Build Coastguard Worker     for (int h = 0; h < 24; ++h) {
1092*77c1e3ccSAndroid Build Coastguard Worker       aom_free(orientation_map[h]->buf);
1093*77c1e3ccSAndroid Build Coastguard Worker       aom_free(orientation_map[h]);
1094*77c1e3ccSAndroid Build Coastguard Worker     }
1095*77c1e3ccSAndroid Build Coastguard Worker     return 0;
1096*77c1e3ccSAndroid Build Coastguard Worker   }
1097*77c1e3ccSAndroid Build Coastguard Worker 
1098*77c1e3ccSAndroid Build Coastguard Worker   aom_free(cr);
1099*77c1e3ccSAndroid Build Coastguard Worker   aom_free(cg);
1100*77c1e3ccSAndroid Build Coastguard Worker   aom_free(cb);
1101*77c1e3ccSAndroid Build Coastguard Worker   aom_free(intensity);
1102*77c1e3ccSAndroid Build Coastguard Worker 
1103*77c1e3ccSAndroid Build Coastguard Worker   saliency_feature_map
1104*77c1e3ccSAndroid Build Coastguard Worker       *normalized_maps[3];  // 0: intensity, 1: color, 2: orientation
1105*77c1e3ccSAndroid Build Coastguard Worker 
1106*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 3; ++i) {
1107*77c1e3ccSAndroid Build Coastguard Worker     normalized_maps[i] = aom_malloc(sizeof(*normalized_maps[i]));
1108*77c1e3ccSAndroid Build Coastguard Worker     if (!normalized_maps[i]) {
1109*77c1e3ccSAndroid Build Coastguard Worker       for (int l = 0; l < 6; ++l) {
1110*77c1e3ccSAndroid Build Coastguard Worker         aom_free(i_map[l]->buf);
1111*77c1e3ccSAndroid Build Coastguard Worker         aom_free(rg_map[l]->buf);
1112*77c1e3ccSAndroid Build Coastguard Worker         aom_free(by_map[l]->buf);
1113*77c1e3ccSAndroid Build Coastguard Worker         aom_free(i_map[l]);
1114*77c1e3ccSAndroid Build Coastguard Worker         aom_free(rg_map[l]);
1115*77c1e3ccSAndroid Build Coastguard Worker         aom_free(by_map[l]);
1116*77c1e3ccSAndroid Build Coastguard Worker       }
1117*77c1e3ccSAndroid Build Coastguard Worker 
1118*77c1e3ccSAndroid Build Coastguard Worker       for (int h = 0; h < 24; ++h) {
1119*77c1e3ccSAndroid Build Coastguard Worker         aom_free(orientation_map[h]->buf);
1120*77c1e3ccSAndroid Build Coastguard Worker         aom_free(orientation_map[h]);
1121*77c1e3ccSAndroid Build Coastguard Worker       }
1122*77c1e3ccSAndroid Build Coastguard Worker 
1123*77c1e3ccSAndroid Build Coastguard Worker       for (int l = 0; l < i; ++l) {
1124*77c1e3ccSAndroid Build Coastguard Worker         aom_free(normalized_maps[l]);
1125*77c1e3ccSAndroid Build Coastguard Worker       }
1126*77c1e3ccSAndroid Build Coastguard Worker       return 0;
1127*77c1e3ccSAndroid Build Coastguard Worker     }
1128*77c1e3ccSAndroid Build Coastguard Worker     normalized_maps[i]->buf = (double *)aom_malloc(
1129*77c1e3ccSAndroid Build Coastguard Worker         frm_width * frm_height * sizeof(*normalized_maps[i]->buf));
1130*77c1e3ccSAndroid Build Coastguard Worker     if (!normalized_maps[i]->buf) {
1131*77c1e3ccSAndroid Build Coastguard Worker       for (int l = 0; l < 6; ++l) {
1132*77c1e3ccSAndroid Build Coastguard Worker         aom_free(i_map[l]->buf);
1133*77c1e3ccSAndroid Build Coastguard Worker         aom_free(rg_map[l]->buf);
1134*77c1e3ccSAndroid Build Coastguard Worker         aom_free(by_map[l]->buf);
1135*77c1e3ccSAndroid Build Coastguard Worker         aom_free(i_map[l]);
1136*77c1e3ccSAndroid Build Coastguard Worker         aom_free(rg_map[l]);
1137*77c1e3ccSAndroid Build Coastguard Worker         aom_free(by_map[l]);
1138*77c1e3ccSAndroid Build Coastguard Worker       }
1139*77c1e3ccSAndroid Build Coastguard Worker       for (int h = 0; h < 24; ++h) {
1140*77c1e3ccSAndroid Build Coastguard Worker         aom_free(orientation_map[h]->buf);
1141*77c1e3ccSAndroid Build Coastguard Worker         aom_free(orientation_map[h]);
1142*77c1e3ccSAndroid Build Coastguard Worker       }
1143*77c1e3ccSAndroid Build Coastguard Worker       for (int l = 0; l < i; ++l) {
1144*77c1e3ccSAndroid Build Coastguard Worker         aom_free(normalized_maps[l]->buf);
1145*77c1e3ccSAndroid Build Coastguard Worker         aom_free(normalized_maps[l]);
1146*77c1e3ccSAndroid Build Coastguard Worker       }
1147*77c1e3ccSAndroid Build Coastguard Worker       return 0;
1148*77c1e3ccSAndroid Build Coastguard Worker     }
1149*77c1e3ccSAndroid Build Coastguard Worker     normalized_maps[i]->width = frm_width;
1150*77c1e3ccSAndroid Build Coastguard Worker     normalized_maps[i]->height = frm_height;
1151*77c1e3ccSAndroid Build Coastguard Worker     memset(normalized_maps[i]->buf, 0,
1152*77c1e3ccSAndroid Build Coastguard Worker            frm_width * frm_height * sizeof(*normalized_maps[i]->buf));
1153*77c1e3ccSAndroid Build Coastguard Worker   }
1154*77c1e3ccSAndroid Build Coastguard Worker 
1155*77c1e3ccSAndroid Build Coastguard Worker   // Conspicuity map generation
1156*77c1e3ccSAndroid Build Coastguard Worker   if (normalized_map(i_map, pyr_width, pyr_height, normalized_maps[0]) == 0 ||
1157*77c1e3ccSAndroid Build Coastguard Worker       normalized_map_rgb(rg_map, by_map, pyr_width, pyr_height,
1158*77c1e3ccSAndroid Build Coastguard Worker                          normalized_maps[1]) == 0 ||
1159*77c1e3ccSAndroid Build Coastguard Worker       normalized_map_orientation(orientation_map, pyr_width, pyr_height,
1160*77c1e3ccSAndroid Build Coastguard Worker                                  normalized_maps[2]) == 0) {
1161*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < 6; ++i) {
1162*77c1e3ccSAndroid Build Coastguard Worker       aom_free(i_map[i]->buf);
1163*77c1e3ccSAndroid Build Coastguard Worker       aom_free(rg_map[i]->buf);
1164*77c1e3ccSAndroid Build Coastguard Worker       aom_free(by_map[i]->buf);
1165*77c1e3ccSAndroid Build Coastguard Worker       aom_free(i_map[i]);
1166*77c1e3ccSAndroid Build Coastguard Worker       aom_free(rg_map[i]);
1167*77c1e3ccSAndroid Build Coastguard Worker       aom_free(by_map[i]);
1168*77c1e3ccSAndroid Build Coastguard Worker     }
1169*77c1e3ccSAndroid Build Coastguard Worker 
1170*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < 24; ++i) {
1171*77c1e3ccSAndroid Build Coastguard Worker       aom_free(orientation_map[i]->buf);
1172*77c1e3ccSAndroid Build Coastguard Worker       aom_free(orientation_map[i]);
1173*77c1e3ccSAndroid Build Coastguard Worker     }
1174*77c1e3ccSAndroid Build Coastguard Worker 
1175*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < 3; ++i) {
1176*77c1e3ccSAndroid Build Coastguard Worker       aom_free(normalized_maps[i]->buf);
1177*77c1e3ccSAndroid Build Coastguard Worker       aom_free(normalized_maps[i]);
1178*77c1e3ccSAndroid Build Coastguard Worker     }
1179*77c1e3ccSAndroid Build Coastguard Worker     return 0;
1180*77c1e3ccSAndroid Build Coastguard Worker   }
1181*77c1e3ccSAndroid Build Coastguard Worker 
1182*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 6; ++i) {
1183*77c1e3ccSAndroid Build Coastguard Worker     aom_free(i_map[i]->buf);
1184*77c1e3ccSAndroid Build Coastguard Worker     aom_free(rg_map[i]->buf);
1185*77c1e3ccSAndroid Build Coastguard Worker     aom_free(by_map[i]->buf);
1186*77c1e3ccSAndroid Build Coastguard Worker     aom_free(i_map[i]);
1187*77c1e3ccSAndroid Build Coastguard Worker     aom_free(rg_map[i]);
1188*77c1e3ccSAndroid Build Coastguard Worker     aom_free(by_map[i]);
1189*77c1e3ccSAndroid Build Coastguard Worker   }
1190*77c1e3ccSAndroid Build Coastguard Worker 
1191*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 24; ++i) {
1192*77c1e3ccSAndroid Build Coastguard Worker     aom_free(orientation_map[i]->buf);
1193*77c1e3ccSAndroid Build Coastguard Worker     aom_free(orientation_map[i]);
1194*77c1e3ccSAndroid Build Coastguard Worker   }
1195*77c1e3ccSAndroid Build Coastguard Worker 
1196*77c1e3ccSAndroid Build Coastguard Worker   // Pixel level saliency map
1197*77c1e3ccSAndroid Build Coastguard Worker   saliency_feature_map *combined_saliency_map =
1198*77c1e3ccSAndroid Build Coastguard Worker       aom_malloc(sizeof(*combined_saliency_map));
1199*77c1e3ccSAndroid Build Coastguard Worker   if (!combined_saliency_map) {
1200*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < 3; ++i) {
1201*77c1e3ccSAndroid Build Coastguard Worker       aom_free(normalized_maps[i]->buf);
1202*77c1e3ccSAndroid Build Coastguard Worker       aom_free(normalized_maps[i]);
1203*77c1e3ccSAndroid Build Coastguard Worker     }
1204*77c1e3ccSAndroid Build Coastguard Worker     return 0;
1205*77c1e3ccSAndroid Build Coastguard Worker   }
1206*77c1e3ccSAndroid Build Coastguard Worker 
1207*77c1e3ccSAndroid Build Coastguard Worker   combined_saliency_map->buf = (double *)aom_malloc(
1208*77c1e3ccSAndroid Build Coastguard Worker       frm_width * frm_height * sizeof(*combined_saliency_map->buf));
1209*77c1e3ccSAndroid Build Coastguard Worker   if (!combined_saliency_map->buf) {
1210*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < 3; ++i) {
1211*77c1e3ccSAndroid Build Coastguard Worker       aom_free(normalized_maps[i]->buf);
1212*77c1e3ccSAndroid Build Coastguard Worker       aom_free(normalized_maps[i]);
1213*77c1e3ccSAndroid Build Coastguard Worker     }
1214*77c1e3ccSAndroid Build Coastguard Worker 
1215*77c1e3ccSAndroid Build Coastguard Worker     aom_free(combined_saliency_map);
1216*77c1e3ccSAndroid Build Coastguard Worker     return 0;
1217*77c1e3ccSAndroid Build Coastguard Worker   }
1218*77c1e3ccSAndroid Build Coastguard Worker   combined_saliency_map->height = frm_height;
1219*77c1e3ccSAndroid Build Coastguard Worker   combined_saliency_map->width = frm_width;
1220*77c1e3ccSAndroid Build Coastguard Worker 
1221*77c1e3ccSAndroid Build Coastguard Worker   double w_intensity, w_color, w_orient;
1222*77c1e3ccSAndroid Build Coastguard Worker 
1223*77c1e3ccSAndroid Build Coastguard Worker   w_intensity = w_color = w_orient = (double)1 / 3;
1224*77c1e3ccSAndroid Build Coastguard Worker 
1225*77c1e3ccSAndroid Build Coastguard Worker   for (int r = 0; r < frm_height; ++r) {
1226*77c1e3ccSAndroid Build Coastguard Worker     for (int c = 0; c < frm_width; ++c) {
1227*77c1e3ccSAndroid Build Coastguard Worker       combined_saliency_map->buf[r * frm_width + c] =
1228*77c1e3ccSAndroid Build Coastguard Worker           (w_intensity * normalized_maps[0]->buf[r * frm_width + c] +
1229*77c1e3ccSAndroid Build Coastguard Worker            w_color * normalized_maps[1]->buf[r * frm_width + c] +
1230*77c1e3ccSAndroid Build Coastguard Worker            w_orient * normalized_maps[2]->buf[r * frm_width + c]);
1231*77c1e3ccSAndroid Build Coastguard Worker     }
1232*77c1e3ccSAndroid Build Coastguard Worker   }
1233*77c1e3ccSAndroid Build Coastguard Worker 
1234*77c1e3ccSAndroid Build Coastguard Worker   for (int r = 0; r < frm_height; ++r) {
1235*77c1e3ccSAndroid Build Coastguard Worker     for (int c = 0; c < frm_width; ++c) {
1236*77c1e3ccSAndroid Build Coastguard Worker       int index = r * frm_width + c;
1237*77c1e3ccSAndroid Build Coastguard Worker       cpi->saliency_map[index] =
1238*77c1e3ccSAndroid Build Coastguard Worker           (uint8_t)(combined_saliency_map->buf[index] * 255);
1239*77c1e3ccSAndroid Build Coastguard Worker     }
1240*77c1e3ccSAndroid Build Coastguard Worker   }
1241*77c1e3ccSAndroid Build Coastguard Worker 
1242*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 3; ++i) {
1243*77c1e3ccSAndroid Build Coastguard Worker     aom_free(normalized_maps[i]->buf);
1244*77c1e3ccSAndroid Build Coastguard Worker     aom_free(normalized_maps[i]);
1245*77c1e3ccSAndroid Build Coastguard Worker   }
1246*77c1e3ccSAndroid Build Coastguard Worker 
1247*77c1e3ccSAndroid Build Coastguard Worker   aom_free(combined_saliency_map->buf);
1248*77c1e3ccSAndroid Build Coastguard Worker   aom_free(combined_saliency_map);
1249*77c1e3ccSAndroid Build Coastguard Worker 
1250*77c1e3ccSAndroid Build Coastguard Worker   return 1;
1251*77c1e3ccSAndroid Build Coastguard Worker }
1252*77c1e3ccSAndroid Build Coastguard Worker 
1253*77c1e3ccSAndroid Build Coastguard Worker // Set superblock level saliency mask for rdmult scaling
av1_setup_sm_rdmult_scaling_factor(AV1_COMP * cpi,double motion_ratio)1254*77c1e3ccSAndroid Build Coastguard Worker int av1_setup_sm_rdmult_scaling_factor(AV1_COMP *cpi, double motion_ratio) {
1255*77c1e3ccSAndroid Build Coastguard Worker   AV1_COMMON *cm = &cpi->common;
1256*77c1e3ccSAndroid Build Coastguard Worker 
1257*77c1e3ccSAndroid Build Coastguard Worker   saliency_feature_map *sb_saliency_map =
1258*77c1e3ccSAndroid Build Coastguard Worker       aom_malloc(sizeof(saliency_feature_map));
1259*77c1e3ccSAndroid Build Coastguard Worker 
1260*77c1e3ccSAndroid Build Coastguard Worker   if (sb_saliency_map == NULL) {
1261*77c1e3ccSAndroid Build Coastguard Worker     return 0;
1262*77c1e3ccSAndroid Build Coastguard Worker   }
1263*77c1e3ccSAndroid Build Coastguard Worker 
1264*77c1e3ccSAndroid Build Coastguard Worker   const BLOCK_SIZE bsize = cm->seq_params->sb_size;
1265*77c1e3ccSAndroid Build Coastguard Worker   const int num_mi_w = mi_size_wide[bsize];
1266*77c1e3ccSAndroid Build Coastguard Worker   const int num_mi_h = mi_size_high[bsize];
1267*77c1e3ccSAndroid Build Coastguard Worker   const int block_width = block_size_wide[bsize];
1268*77c1e3ccSAndroid Build Coastguard Worker   const int block_height = block_size_high[bsize];
1269*77c1e3ccSAndroid Build Coastguard Worker   const int num_sb_cols = (cm->mi_params.mi_cols + num_mi_w - 1) / num_mi_w;
1270*77c1e3ccSAndroid Build Coastguard Worker   const int num_sb_rows = (cm->mi_params.mi_rows + num_mi_h - 1) / num_mi_h;
1271*77c1e3ccSAndroid Build Coastguard Worker 
1272*77c1e3ccSAndroid Build Coastguard Worker   sb_saliency_map->height = num_sb_rows;
1273*77c1e3ccSAndroid Build Coastguard Worker   sb_saliency_map->width = num_sb_cols;
1274*77c1e3ccSAndroid Build Coastguard Worker   sb_saliency_map->buf = (double *)aom_malloc(num_sb_rows * num_sb_cols *
1275*77c1e3ccSAndroid Build Coastguard Worker                                               sizeof(*sb_saliency_map->buf));
1276*77c1e3ccSAndroid Build Coastguard Worker 
1277*77c1e3ccSAndroid Build Coastguard Worker   if (sb_saliency_map->buf == NULL) {
1278*77c1e3ccSAndroid Build Coastguard Worker     aom_free(sb_saliency_map);
1279*77c1e3ccSAndroid Build Coastguard Worker     return 0;
1280*77c1e3ccSAndroid Build Coastguard Worker   }
1281*77c1e3ccSAndroid Build Coastguard Worker 
1282*77c1e3ccSAndroid Build Coastguard Worker   for (int row = 0; row < num_sb_rows; ++row) {
1283*77c1e3ccSAndroid Build Coastguard Worker     for (int col = 0; col < num_sb_cols; ++col) {
1284*77c1e3ccSAndroid Build Coastguard Worker       const int index = row * num_sb_cols + col;
1285*77c1e3ccSAndroid Build Coastguard Worker       double total_pixel = 0;
1286*77c1e3ccSAndroid Build Coastguard Worker       double total_weight = 0;
1287*77c1e3ccSAndroid Build Coastguard Worker 
1288*77c1e3ccSAndroid Build Coastguard Worker       for (int i = 0; i < block_height; i++) {
1289*77c1e3ccSAndroid Build Coastguard Worker         for (int j = 0; j < block_width; j++) {
1290*77c1e3ccSAndroid Build Coastguard Worker           if ((row * block_height + i) >= cpi->common.height ||
1291*77c1e3ccSAndroid Build Coastguard Worker               (col * block_width + j) >= cpi->common.width)
1292*77c1e3ccSAndroid Build Coastguard Worker             continue;
1293*77c1e3ccSAndroid Build Coastguard Worker           total_pixel++;
1294*77c1e3ccSAndroid Build Coastguard Worker           total_weight +=
1295*77c1e3ccSAndroid Build Coastguard Worker               cpi->saliency_map[(row * block_height + i) * cpi->common.width +
1296*77c1e3ccSAndroid Build Coastguard Worker                                 col * block_width + j];
1297*77c1e3ccSAndroid Build Coastguard Worker         }
1298*77c1e3ccSAndroid Build Coastguard Worker       }
1299*77c1e3ccSAndroid Build Coastguard Worker 
1300*77c1e3ccSAndroid Build Coastguard Worker       assert(total_pixel > 0);
1301*77c1e3ccSAndroid Build Coastguard Worker 
1302*77c1e3ccSAndroid Build Coastguard Worker       // Calculate the superblock level saliency map from pixel level saliency
1303*77c1e3ccSAndroid Build Coastguard Worker       // map
1304*77c1e3ccSAndroid Build Coastguard Worker       sb_saliency_map->buf[index] = total_weight / total_pixel;
1305*77c1e3ccSAndroid Build Coastguard Worker 
1306*77c1e3ccSAndroid Build Coastguard Worker       // Further lower the superblock saliency score for boundary superblocks.
1307*77c1e3ccSAndroid Build Coastguard Worker       if (row < 1 || row > num_sb_rows - 2 || col < 1 ||
1308*77c1e3ccSAndroid Build Coastguard Worker           col > num_sb_cols - 2) {
1309*77c1e3ccSAndroid Build Coastguard Worker         sb_saliency_map->buf[index] /= 5;
1310*77c1e3ccSAndroid Build Coastguard Worker       }
1311*77c1e3ccSAndroid Build Coastguard Worker     }
1312*77c1e3ccSAndroid Build Coastguard Worker   }
1313*77c1e3ccSAndroid Build Coastguard Worker 
1314*77c1e3ccSAndroid Build Coastguard Worker   // superblock level saliency map finalization
1315*77c1e3ccSAndroid Build Coastguard Worker   minmax_normalize(sb_saliency_map);
1316*77c1e3ccSAndroid Build Coastguard Worker 
1317*77c1e3ccSAndroid Build Coastguard Worker   double log_sum = 0.0;
1318*77c1e3ccSAndroid Build Coastguard Worker   double sum = 0.0;
1319*77c1e3ccSAndroid Build Coastguard Worker   int block_count = 0;
1320*77c1e3ccSAndroid Build Coastguard Worker 
1321*77c1e3ccSAndroid Build Coastguard Worker   // Calculate the average superblock sm_scaling_factor for a frame, to be used
1322*77c1e3ccSAndroid Build Coastguard Worker   // for clamping later.
1323*77c1e3ccSAndroid Build Coastguard Worker   for (int row = 0; row < num_sb_rows; ++row) {
1324*77c1e3ccSAndroid Build Coastguard Worker     for (int col = 0; col < num_sb_cols; ++col) {
1325*77c1e3ccSAndroid Build Coastguard Worker       const int index = row * num_sb_cols + col;
1326*77c1e3ccSAndroid Build Coastguard Worker       const double saliency = sb_saliency_map->buf[index];
1327*77c1e3ccSAndroid Build Coastguard Worker 
1328*77c1e3ccSAndroid Build Coastguard Worker       cpi->sm_scaling_factor[index] = 1 - saliency;
1329*77c1e3ccSAndroid Build Coastguard Worker       sum += cpi->sm_scaling_factor[index];
1330*77c1e3ccSAndroid Build Coastguard Worker       block_count++;
1331*77c1e3ccSAndroid Build Coastguard Worker     }
1332*77c1e3ccSAndroid Build Coastguard Worker   }
1333*77c1e3ccSAndroid Build Coastguard Worker   assert(block_count > 0);
1334*77c1e3ccSAndroid Build Coastguard Worker   sum /= block_count;
1335*77c1e3ccSAndroid Build Coastguard Worker 
1336*77c1e3ccSAndroid Build Coastguard Worker   // Calculate the geometric mean of superblock sm_scaling_factor for a frame,
1337*77c1e3ccSAndroid Build Coastguard Worker   // to be used for normalization.
1338*77c1e3ccSAndroid Build Coastguard Worker   for (int row = 0; row < num_sb_rows; ++row) {
1339*77c1e3ccSAndroid Build Coastguard Worker     for (int col = 0; col < num_sb_cols; ++col) {
1340*77c1e3ccSAndroid Build Coastguard Worker       const int index = row * num_sb_cols + col;
1341*77c1e3ccSAndroid Build Coastguard Worker       log_sum += log(fmax(cpi->sm_scaling_factor[index], 0.001));
1342*77c1e3ccSAndroid Build Coastguard Worker       cpi->sm_scaling_factor[index] =
1343*77c1e3ccSAndroid Build Coastguard Worker           fmax(cpi->sm_scaling_factor[index], 0.8 * sum);
1344*77c1e3ccSAndroid Build Coastguard Worker     }
1345*77c1e3ccSAndroid Build Coastguard Worker   }
1346*77c1e3ccSAndroid Build Coastguard Worker 
1347*77c1e3ccSAndroid Build Coastguard Worker   log_sum = exp(log_sum / block_count);
1348*77c1e3ccSAndroid Build Coastguard Worker 
1349*77c1e3ccSAndroid Build Coastguard Worker   // Normalize the sm_scaling_factor by geometric mean.
1350*77c1e3ccSAndroid Build Coastguard Worker   for (int row = 0; row < num_sb_rows; ++row) {
1351*77c1e3ccSAndroid Build Coastguard Worker     for (int col = 0; col < num_sb_cols; ++col) {
1352*77c1e3ccSAndroid Build Coastguard Worker       const int index = row * num_sb_cols + col;
1353*77c1e3ccSAndroid Build Coastguard Worker       assert(log_sum > 0);
1354*77c1e3ccSAndroid Build Coastguard Worker       cpi->sm_scaling_factor[index] /= log_sum;
1355*77c1e3ccSAndroid Build Coastguard Worker 
1356*77c1e3ccSAndroid Build Coastguard Worker       // Modulate the sm_scaling_factor by frame basis motion factor
1357*77c1e3ccSAndroid Build Coastguard Worker       cpi->sm_scaling_factor[index] =
1358*77c1e3ccSAndroid Build Coastguard Worker           cpi->sm_scaling_factor[index] * motion_ratio;
1359*77c1e3ccSAndroid Build Coastguard Worker     }
1360*77c1e3ccSAndroid Build Coastguard Worker   }
1361*77c1e3ccSAndroid Build Coastguard Worker 
1362*77c1e3ccSAndroid Build Coastguard Worker   aom_free(sb_saliency_map->buf);
1363*77c1e3ccSAndroid Build Coastguard Worker   aom_free(sb_saliency_map);
1364*77c1e3ccSAndroid Build Coastguard Worker   return 1;
1365*77c1e3ccSAndroid Build Coastguard Worker }
1366*77c1e3ccSAndroid Build Coastguard Worker 
1367*77c1e3ccSAndroid Build Coastguard Worker // av1_setup_motion_ratio() is only enabled when CONFIG_REALTIME_ONLY is 0,
1368*77c1e3ccSAndroid Build Coastguard Worker // because the computations need to access the first pass stats which are
1369*77c1e3ccSAndroid Build Coastguard Worker // only available when CONFIG_REALTIME_ONLY is equal to 0.
1370*77c1e3ccSAndroid Build Coastguard Worker #if !CONFIG_REALTIME_ONLY
1371*77c1e3ccSAndroid Build Coastguard Worker // Set motion_ratio that reflects the motion quantities between two consecutive
1372*77c1e3ccSAndroid Build Coastguard Worker // frames. Motion_ratio will be used to set up saliency_map based rdmult scaling
1373*77c1e3ccSAndroid Build Coastguard Worker // factor, i.e., the less the motion quantities are, the more bits will be spent
1374*77c1e3ccSAndroid Build Coastguard Worker // on this frame, and vice versa.
av1_setup_motion_ratio(AV1_COMP * cpi)1375*77c1e3ccSAndroid Build Coastguard Worker double av1_setup_motion_ratio(AV1_COMP *cpi) {
1376*77c1e3ccSAndroid Build Coastguard Worker   AV1_COMMON *cm = &cpi->common;
1377*77c1e3ccSAndroid Build Coastguard Worker   int frames_since_key =
1378*77c1e3ccSAndroid Build Coastguard Worker       cm->current_frame.display_order_hint - cpi->rc.frames_since_key;
1379*77c1e3ccSAndroid Build Coastguard Worker   const FIRSTPASS_STATS *cur_stats = av1_firstpass_info_peek(
1380*77c1e3ccSAndroid Build Coastguard Worker       &cpi->ppi->twopass.firstpass_info, frames_since_key);
1381*77c1e3ccSAndroid Build Coastguard Worker   assert(cur_stats != NULL);
1382*77c1e3ccSAndroid Build Coastguard Worker   assert(cpi->ppi->twopass.firstpass_info.total_stats.count > 0);
1383*77c1e3ccSAndroid Build Coastguard Worker 
1384*77c1e3ccSAndroid Build Coastguard Worker   const double avg_intra_error =
1385*77c1e3ccSAndroid Build Coastguard Worker       exp(cpi->ppi->twopass.firstpass_info.total_stats.log_intra_error /
1386*77c1e3ccSAndroid Build Coastguard Worker           cpi->ppi->twopass.firstpass_info.total_stats.count);
1387*77c1e3ccSAndroid Build Coastguard Worker   const double avg_inter_error =
1388*77c1e3ccSAndroid Build Coastguard Worker       exp(cpi->ppi->twopass.firstpass_info.total_stats.log_coded_error /
1389*77c1e3ccSAndroid Build Coastguard Worker           cpi->ppi->twopass.firstpass_info.total_stats.count);
1390*77c1e3ccSAndroid Build Coastguard Worker 
1391*77c1e3ccSAndroid Build Coastguard Worker   double inter_error = cur_stats->coded_error;
1392*77c1e3ccSAndroid Build Coastguard Worker   double error_stdev = 0;
1393*77c1e3ccSAndroid Build Coastguard Worker   const double avg_error =
1394*77c1e3ccSAndroid Build Coastguard Worker       cpi->ppi->twopass.firstpass_info.total_stats.intra_error /
1395*77c1e3ccSAndroid Build Coastguard Worker       cpi->ppi->twopass.firstpass_info.total_stats.count;
1396*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < cpi->ppi->twopass.firstpass_info.total_stats.count; i++) {
1397*77c1e3ccSAndroid Build Coastguard Worker     const FIRSTPASS_STATS *stats =
1398*77c1e3ccSAndroid Build Coastguard Worker         &cpi->ppi->twopass.firstpass_info.stats_buf[i];
1399*77c1e3ccSAndroid Build Coastguard Worker     error_stdev +=
1400*77c1e3ccSAndroid Build Coastguard Worker         (stats->intra_error - avg_error) * (stats->intra_error - avg_error);
1401*77c1e3ccSAndroid Build Coastguard Worker   }
1402*77c1e3ccSAndroid Build Coastguard Worker   error_stdev =
1403*77c1e3ccSAndroid Build Coastguard Worker       sqrt(error_stdev / cpi->ppi->twopass.firstpass_info.total_stats.count);
1404*77c1e3ccSAndroid Build Coastguard Worker 
1405*77c1e3ccSAndroid Build Coastguard Worker   double motion_ratio = 1;
1406*77c1e3ccSAndroid Build Coastguard Worker   if (error_stdev / fmax(avg_intra_error, 1) > 0.1) {
1407*77c1e3ccSAndroid Build Coastguard Worker     motion_ratio = inter_error / fmax(1, avg_inter_error);
1408*77c1e3ccSAndroid Build Coastguard Worker     motion_ratio = AOMMIN(motion_ratio, 1.5);
1409*77c1e3ccSAndroid Build Coastguard Worker     motion_ratio = AOMMAX(motion_ratio, 0.8);
1410*77c1e3ccSAndroid Build Coastguard Worker   }
1411*77c1e3ccSAndroid Build Coastguard Worker 
1412*77c1e3ccSAndroid Build Coastguard Worker   return motion_ratio;
1413*77c1e3ccSAndroid Build Coastguard Worker }
1414*77c1e3ccSAndroid Build Coastguard Worker #endif  // !CONFIG_REALTIME_ONLY
1415