xref: /aosp_15_r20/external/libxaac/encoder/iusace_avq_enc.c (revision 15dc779a375ca8b5125643b829a8aa4b70d7f451)
1 /******************************************************************************
2  *                                                                            *
3  * Copyright (C) 2023 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *****************************************************************************
18  * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19  */
20 
21 #include <math.h>
22 #include <stdlib.h>
23 #include "ixheaac_type_def.h"
24 #include "iusace_avq_enc.h"
25 
iusace_gosset_compute_rank_and_sign(WORD32 * x,WORD32 * rank,WORD32 * sign_code)26 static VOID iusace_gosset_compute_rank_and_sign(WORD32 *x, WORD32 *rank, WORD32 *sign_code) {
27   WORD32 xs[8], a[8], q, d[8], w[8], A, B, idx, tmp, abs_i, abs_j;
28   WORD32 i, j, k;
29   for (i = 0; i < 8; i++) {
30     xs[i] = x[i];
31   }
32   for (k = 0; k < 7; k++) {
33     j = k;
34     for (i = k + 1; i < 8; i++) {
35       abs_j = abs(xs[j]);
36       abs_i = abs(xs[i]);
37       if (abs_i >= abs_j) {
38         if (abs_i > xs[j]) {
39           j = i;
40         }
41       }
42     }
43     if (j > k) {
44       tmp = xs[k];
45       xs[k] = xs[j];
46       xs[j] = tmp;
47     }
48   }
49   *sign_code = 0;
50   for (i = 0; i < 8; i++) {
51     if (xs[i] < 0) {
52       *sign_code += iusace_pow2_table[i];
53     }
54   }
55   a[0] = xs[0];
56   q = 1;
57   for (i = 1; i < 8; i++) {
58     if (xs[i] != xs[i - 1]) {
59       a[q] = xs[i];
60       q++;
61     }
62   }
63   for (i = 0; i < 8; i++) {
64     for (j = 0; j < q; j++) {
65       if (x[i] == a[j]) {
66         d[i] = j;
67         break;
68       }
69     }
70   }
71   *rank = 0;
72   for (j = 0; j < q; j++) {
73     w[j] = 0;
74   }
75   B = 1;
76   for (i = 7; i >= 0; i--) {
77     idx = d[i];
78     w[idx]++;
79     B *= w[idx];
80     A = 0;
81     for (j = 0; j < idx; j++) {
82       A += w[j];
83     }
84     if (A > 0) {
85       *rank += A * iusace_factorial_table[i] / B;
86     }
87   }
88 }
89 
iusace_gosset_compute_base_idx(WORD32 * x,WORD32 ka,WORD32 * idx)90 static VOID iusace_gosset_compute_base_idx(WORD32 *x, WORD32 ka, WORD32 *idx) {
91   WORD32 rank, offset, code, i, ks;
92   iusace_gosset_compute_rank_and_sign(x, &rank, &code);
93   ks = -1;
94   for (i = iusace_iso_code_index_table[ka]; i < LEN_SIGN_LEADER; i++) {
95     if (code == iusace_iso_code_data_table[i]) {
96       ks = i;
97       break;
98     }
99   }
100   if (ks == -1) {
101     ks = 0;
102   }
103   offset = iusace_signed_leader_is[ks];
104   *idx = offset + rank;
105   return;
106 }
107 
iusace_find_absolute_leader(WORD32 * y)108 static WORD32 iusace_find_absolute_leader(WORD32 *y) {
109   WORD32 i, nb, pos, ka;
110   WORD64 s, C[8], id;
111   for (i = 0; i < 8; i++) {
112     C[i] = (WORD64)y[i] * y[i];
113   }
114   s = 0;
115   for (i = 0; i < 8; i++) {
116     s += C[i];
117   }
118   s >>= 3;
119   ka = LEN_ABS_LEADER + 1;
120   if (s == 0) {
121     ka = LEN_ABS_LEADER;
122   } else {
123     if (s <= NB_SPHERE) {
124       id = 0;
125       for (i = 0; i < 8; i++) {
126         id += C[i] * C[i];
127       }
128       id = id >> 3;
129       nb = iusace_da_num_bits[s - 1];
130       pos = iusace_da_pos[s - 1];
131       for (i = 0; i < nb; i++) {
132         if (id == (long)iusace_da_id[pos]) {
133           ka = pos;
134           break;
135         }
136         pos++;
137       }
138     }
139   }
140   return (ka);
141 }
142 
iusace_nearest_neighbor_2d(FLOAT32 * x,WORD32 * y)143 static VOID iusace_nearest_neighbor_2d(FLOAT32 *x, WORD32 *y) {
144   WORD32 i, j;
145   WORD64 sum;
146   FLOAT32 diff[8], em;
147   sum = 0;
148   for (i = 0; i < 8; i++) {
149     if (x[i] < 0) {
150       y[i] = -2 * (((WORD32)(1.0 - x[i])) >> 1);
151     } else {
152       y[i] = 2 * (((WORD32)(1.0 + x[i])) >> 1);
153     }
154     sum += y[i];
155   }
156   if (sum % 4) {
157     FLOAT32 s;
158     em = 0;
159     j = 0;
160     for (i = 0; i < 8; i++) {
161       diff[i] = x[i] - y[i];
162       s = (FLOAT32)fabs(diff[i]);
163       if (em < s) {
164         em = s;
165         j = i;
166       }
167     }
168     if (diff[j] < 0) {
169       y[j] -= 2;
170     } else {
171       y[j] += 2;
172     }
173   }
174   return;
175 }
176 
iusace_find_nearest_neighbor(FLOAT32 * bk,WORD32 * ck)177 VOID iusace_find_nearest_neighbor(FLOAT32 *bk, WORD32 *ck) {
178   WORD32 i, y1[8], y2[8];
179   FLOAT32 e1k, e2k, x1[8], tmp;
180 
181   iusace_nearest_neighbor_2d(bk, y1);
182 
183   for (i = 0; i < 8; i++) {
184     x1[i] = bk[i] - 1.0f;
185   }
186   iusace_nearest_neighbor_2d(x1, y2);
187   for (i = 0; i < 8; i++) {
188     y2[i] += 1;
189   }
190   /* Compute e1k = (Bk - y1k)^2 and e2k = (Bk � y2k)^2 */
191   e1k = e2k = 0.0;
192   for (i = 0; i < 8; i++) {
193     tmp = bk[i] - y1[i];
194     e1k += tmp * tmp;
195     tmp = bk[i] - y2[i];
196     e2k += tmp * tmp;
197   }
198 
199   /* Select best lattice point */
200   if (e1k < e2k) {
201     for (i = 0; i < 8; i++) {
202       ck[i] = y1[i];
203     }
204   } else {
205     for (i = 0; i < 8; i++) {
206       ck[i] = y2[i];
207     }
208   }
209   return;
210 }
211 
iusace_vononoi_idx(WORD32 * kv,WORD32 m,WORD32 * y)212 static VOID iusace_vononoi_idx(WORD32 *kv, WORD32 m, WORD32 *y) {
213   WORD32 i, v[8], tmp, sum, *ptr1, *ptr2;
214   FLOAT32 z[8];
215   for (i = 0; i < 8; i++) {
216     y[i] = kv[7];
217   }
218   z[7] = (FLOAT32)y[7] / m;
219   sum = 0;
220   for (i = 6; i >= 1; i--) {
221     tmp = kv[i] << 1;
222     sum += tmp;
223     y[i] += tmp;
224     z[i] = (FLOAT32)y[i] / m;
225   }
226   y[0] += (4 * kv[0] + sum);
227   z[0] = (FLOAT32)(y[0] - 2) / m;
228   iusace_find_nearest_neighbor(z, v);
229   ptr1 = y;
230   ptr2 = v;
231   for (i = 0; i < 8; i++) {
232     *ptr1++ -= m * *ptr2++;
233   }
234 }
235 
iusace_compute_coord(WORD32 * y,WORD32 * k)236 static VOID iusace_compute_coord(WORD32 *y, WORD32 *k) {
237   WORD32 i, tmp, sum;
238   k[7] = y[7];
239   tmp = y[7];
240   sum = 5 * y[7];
241   for (i = 6; i >= 1; i--) {
242     k[i] = (y[i] - tmp) >> 1;
243     sum -= y[i];
244   }
245   k[0] = (y[0] + sum) >> 2;
246 }
247 
iusace_apply_voronoi_ext(WORD32 * x,WORD32 * n,WORD32 * idx,WORD32 * k)248 VOID iusace_apply_voronoi_ext(WORD32 *x, WORD32 *n, WORD32 *idx, WORD32 *k) {
249   WORD32 ka, c[8];
250   WORD32 i, r, m, v[8], c_tmp[8], k_mod[8], k_tmp[8], iter, ka_tmp, n_tmp, mask;
251   FLOAT32 sphere;
252   ka = iusace_find_absolute_leader(x);
253   *n = iusace_da_nq[ka];
254   if (*n <= 4) {
255     for (i = 0; i < 8; i++) {
256       c[i] = x[i];
257     }
258   } else {
259     sphere = 0.0;
260     for (i = 0; i < 8; i++) {
261       sphere += (FLOAT32)x[i] * (FLOAT32)x[i];
262     }
263     sphere *= 0.125;
264     r = 1;
265     sphere *= 0.25;
266     while (sphere > 11.0) {
267       r++;
268       sphere *= 0.25;
269     }
270     iusace_compute_coord(x, k_mod);
271     m = 1 << r;
272     mask = m - 1;
273     for (iter = 0; iter < 2; iter++) {
274       for (i = 0; i < 8; i++) {
275         k_tmp[i] = k_mod[i] & mask;
276       }
277       iusace_vononoi_idx(k_tmp, m, v);
278       for (i = 0; i < 8; i++) {
279         c_tmp[i] = (x[i] - v[i]) / m;
280       }
281       ka_tmp = iusace_find_absolute_leader(c_tmp);
282       n_tmp = iusace_da_nq[ka_tmp];
283       if (n_tmp > 4) {
284         r++;
285         m = m << 1;
286         mask = ((mask << 1) + 1);
287       } else {
288         if (n_tmp < 3) {
289           n_tmp = 3;
290         }
291         ka = ka_tmp;
292         *n = n_tmp + 2 * r;
293         for (i = 0; i < 8; i++) {
294           k[i] = k_tmp[i];
295         }
296         for (i = 0; i < 8; i++) {
297           c[i] = c_tmp[i];
298         }
299         r--;
300         m = m >> 1;
301         mask = mask >> 1;
302       }
303     }
304   }
305 
306   if (*n > 0) {
307     iusace_gosset_compute_base_idx(c, ka, idx);
308   }
309   return;
310 }
311 
iusace_alg_vec_quant(FLOAT32 * ptr_input,WORD32 * ptr_out,WORD32 * ptr_lpc_idx)312 VOID iusace_alg_vec_quant(FLOAT32 *ptr_input, WORD32 *ptr_out, WORD32 *ptr_lpc_idx) {
313   WORD32 i, l, nq, pos, c[8], kv[8];
314   FLOAT32 x1[8];
315   WORD32 lpc_index;
316 
317   pos = 2;
318   for (l = 0; l < 2; l++) {
319     for (i = 0; i < 8; i++) {
320       x1[i] = ptr_input[l * 8 + i];
321       kv[i] = 0;
322     }
323 
324     iusace_find_nearest_neighbor(x1, c);
325 
326     iusace_apply_voronoi_ext(c, &nq, &lpc_index, kv);
327 
328     for (i = 0; i < 8; i++) {
329       ptr_out[l * 8 + i] = c[i];
330     }
331 
332     ptr_lpc_idx[l] = nq;
333 
334     if (nq > 0) {
335       ptr_lpc_idx[pos++] = lpc_index;
336       for (i = 0; i < 8; i++) {
337         ptr_lpc_idx[pos++] = kv[i];
338       }
339     }
340   }
341 
342   return;
343 }
344