/src/ffmpeg/libavcodec/elbg.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2007 Vitor Sessak <vitor1001@gmail.com> |
3 | | * |
4 | | * This file is part of FFmpeg. |
5 | | * |
6 | | * FFmpeg is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * FFmpeg is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with FFmpeg; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | /** |
22 | | * @file |
23 | | * Codebook Generator using the ELBG algorithm |
24 | | */ |
25 | | |
26 | | #include <string.h> |
27 | | |
28 | | #include "libavutil/avassert.h" |
29 | | #include "libavutil/common.h" |
30 | | #include "libavutil/lfg.h" |
31 | | #include "libavutil/mem.h" |
32 | | #include "elbg.h" |
33 | | |
34 | 6.72M | #define DELTA_ERR_MAX 0.1 ///< Precision of the ELBG algorithm (as percentage error) |
35 | | |
36 | | /** |
37 | | * In the ELBG jargon, a cell is the set of points that are closest to a |
38 | | * codebook entry. Not to be confused with a RoQ Video cell. */ |
39 | | typedef struct cell_s { |
40 | | int index; |
41 | | struct cell_s *next; |
42 | | } cell; |
43 | | |
44 | | /** |
45 | | * ELBG internal data |
46 | | */ |
47 | | typedef struct ELBGContext { |
48 | | int error; |
49 | | int dim; |
50 | | int num_cb; |
51 | | int *codebook; |
52 | | cell **cells; |
53 | | int *utility; |
54 | | int *utility_inc; |
55 | | int *nearest_cb; |
56 | | int *points; |
57 | | int *temp_points; |
58 | | int *size_part; |
59 | | AVLFG *rand_state; |
60 | | int *scratchbuf; |
61 | | cell *cell_buffer; |
62 | | |
63 | | /* Sizes for the buffers above. Pointers without such a field |
64 | | * are not allocated by us and only valid for the duration |
65 | | * of a single call to avpriv_elbg_do(). */ |
66 | | unsigned utility_allocated; |
67 | | unsigned utility_inc_allocated; |
68 | | unsigned size_part_allocated; |
69 | | unsigned cells_allocated; |
70 | | unsigned scratchbuf_allocated; |
71 | | unsigned cell_buffer_allocated; |
72 | | unsigned temp_points_allocated; |
73 | | } ELBGContext; |
74 | | |
75 | | static inline int distance_limited(int *a, int *b, int dim, int limit) |
76 | 41.5G | { |
77 | 41.5G | int i, dist=0; |
78 | 89.8G | for (i=0; i<dim; i++) { |
79 | 84.3G | int64_t distance = a[i] - b[i]; |
80 | | |
81 | 84.3G | distance *= distance; |
82 | 84.3G | if (dist >= limit - distance) |
83 | 36.1G | return limit; |
84 | 48.2G | dist += distance; |
85 | 48.2G | } |
86 | | |
87 | 5.46G | return dist; |
88 | 41.5G | } |
89 | | |
90 | | static inline void vect_division(int *res, int *vect, int div, int dim) |
91 | 48.8M | { |
92 | 48.8M | int i; |
93 | 48.8M | if (div > 1) |
94 | 136M | for (i=0; i<dim; i++) |
95 | 115M | res[i] = ROUNDED_DIV(vect[i],div); |
96 | 27.5M | else if (res != vect) |
97 | 5.51M | memcpy(res, vect, dim*sizeof(int)); |
98 | | |
99 | 48.8M | } |
100 | | |
101 | | static int eval_error_cell(ELBGContext *elbg, int *centroid, cell *cells) |
102 | 12.0M | { |
103 | 12.0M | int error=0; |
104 | 2.18G | for (; cells; cells=cells->next) { |
105 | 2.16G | int distance = distance_limited(centroid, elbg->points + cells->index*elbg->dim, elbg->dim, INT_MAX); |
106 | 2.16G | if (error >= INT_MAX - distance) |
107 | 0 | return INT_MAX; |
108 | 2.16G | error += distance; |
109 | 2.16G | } |
110 | | |
111 | 12.0M | return error; |
112 | 12.0M | } |
113 | | |
114 | | static int get_closest_codebook(ELBGContext *elbg, int index) |
115 | 7.67M | { |
116 | 7.67M | int pick = 0; |
117 | 1.16G | for (int i = 0, diff_min = INT_MAX; i < elbg->num_cb; i++) |
118 | 1.15G | if (i != index) { |
119 | 1.14G | int diff; |
120 | 1.14G | diff = distance_limited(elbg->codebook + i*elbg->dim, elbg->codebook + index*elbg->dim, elbg->dim, diff_min); |
121 | 1.14G | if (diff < diff_min) { |
122 | 24.2M | pick = i; |
123 | 24.2M | diff_min = diff; |
124 | 24.2M | } |
125 | 1.14G | } |
126 | 7.67M | return pick; |
127 | 7.67M | } |
128 | | |
129 | | static int get_high_utility_cell(ELBGContext *elbg) |
130 | 7.67M | { |
131 | 7.67M | int i=0; |
132 | | /* Using linear search, do binary if it ever turns to be speed critical */ |
133 | 7.67M | uint64_t r; |
134 | | |
135 | 7.67M | if (elbg->utility_inc[elbg->num_cb - 1] < INT_MAX) { |
136 | 7.67M | r = av_lfg_get(elbg->rand_state) % (unsigned int)elbg->utility_inc[elbg->num_cb - 1] + 1; |
137 | 7.67M | } else { |
138 | 7 | r = av_lfg_get(elbg->rand_state); |
139 | 7 | r = (av_lfg_get(elbg->rand_state) + (r<<32)) % elbg->utility_inc[elbg->num_cb - 1] + 1; |
140 | 7 | } |
141 | | |
142 | 288M | while (elbg->utility_inc[i] < r) { |
143 | 280M | i++; |
144 | 280M | } |
145 | | |
146 | 7.67M | av_assert2(elbg->cells[i]); |
147 | | |
148 | 7.67M | return i; |
149 | 7.67M | } |
150 | | |
151 | | /** |
152 | | * Implementation of the simple LBG algorithm for just two codebooks |
153 | | */ |
154 | | static int simple_lbg(ELBGContext *elbg, |
155 | | int dim, |
156 | | int *centroid[3], |
157 | | int newutility[3], |
158 | | int *points, |
159 | | cell *cells) |
160 | 6.03M | { |
161 | 6.03M | int i, idx; |
162 | 6.03M | int numpoints[2] = {0,0}; |
163 | 6.03M | int *newcentroid[2] = { |
164 | 6.03M | elbg->scratchbuf + 3*dim, |
165 | 6.03M | elbg->scratchbuf + 4*dim |
166 | 6.03M | }; |
167 | 6.03M | cell *tempcell; |
168 | | |
169 | 6.03M | memset(newcentroid[0], 0, 2 * dim * sizeof(*newcentroid[0])); |
170 | | |
171 | 6.03M | newutility[0] = |
172 | 6.03M | newutility[1] = 0; |
173 | | |
174 | 561M | for (tempcell = cells; tempcell; tempcell=tempcell->next) { |
175 | 555M | idx = distance_limited(centroid[0], points + tempcell->index*dim, dim, INT_MAX)>= |
176 | 555M | distance_limited(centroid[1], points + tempcell->index*dim, dim, INT_MAX); |
177 | 555M | numpoints[idx]++; |
178 | 4.15G | for (i=0; i<dim; i++) |
179 | 3.59G | newcentroid[idx][i] += points[tempcell->index*dim + i]; |
180 | 555M | } |
181 | | |
182 | 6.03M | vect_division(centroid[0], newcentroid[0], numpoints[0], dim); |
183 | 6.03M | vect_division(centroid[1], newcentroid[1], numpoints[1], dim); |
184 | | |
185 | 561M | for (tempcell = cells; tempcell; tempcell=tempcell->next) { |
186 | 555M | int dist[2] = {distance_limited(centroid[0], points + tempcell->index*dim, dim, INT_MAX), |
187 | 555M | distance_limited(centroid[1], points + tempcell->index*dim, dim, INT_MAX)}; |
188 | 555M | int idx = dist[0] > dist[1]; |
189 | 555M | if (newutility[idx] >= INT_MAX - dist[idx]) |
190 | 0 | newutility[idx] = INT_MAX; |
191 | 555M | else |
192 | 555M | newutility[idx] += dist[idx]; |
193 | 555M | } |
194 | | |
195 | 6.03M | return (newutility[0] >= INT_MAX - newutility[1]) ? INT_MAX : newutility[0] + newutility[1]; |
196 | 6.03M | } |
197 | | |
198 | | static void get_new_centroids(ELBGContext *elbg, int huc, int *newcentroid_i, |
199 | | int *newcentroid_p) |
200 | 6.03M | { |
201 | 6.03M | cell *tempcell; |
202 | 6.03M | int *min = newcentroid_i; |
203 | 6.03M | int *max = newcentroid_p; |
204 | 6.03M | int i; |
205 | | |
206 | 48.0M | for (i=0; i< elbg->dim; i++) { |
207 | 42.0M | min[i]=INT_MAX; |
208 | 42.0M | max[i]=0; |
209 | 42.0M | } |
210 | | |
211 | 561M | for (tempcell = elbg->cells[huc]; tempcell; tempcell = tempcell->next) |
212 | 4.15G | for(i=0; i<elbg->dim; i++) { |
213 | 3.59G | min[i]=FFMIN(min[i], elbg->points[tempcell->index*elbg->dim + i]); |
214 | 3.59G | max[i]=FFMAX(max[i], elbg->points[tempcell->index*elbg->dim + i]); |
215 | 3.59G | } |
216 | | |
217 | 48.0M | for (i=0; i<elbg->dim; i++) { |
218 | 42.0M | int ni = min[i] + (max[i] - min[i])/3; |
219 | 42.0M | int np = min[i] + (2*(max[i] - min[i]))/3; |
220 | 42.0M | newcentroid_i[i] = ni; |
221 | 42.0M | newcentroid_p[i] = np; |
222 | 42.0M | } |
223 | 6.03M | } |
224 | | |
225 | | /** |
226 | | * Add the points in the low utility cell to its closest cell. Split the high |
227 | | * utility cell, putting the separated points in the (now empty) low utility |
228 | | * cell. |
229 | | * |
230 | | * @param elbg Internal elbg data |
231 | | * @param indexes {luc, huc, cluc} |
232 | | * @param newcentroid A vector with the position of the new centroids |
233 | | */ |
234 | | static void shift_codebook(ELBGContext *elbg, int *indexes, |
235 | | int *newcentroid[3]) |
236 | 2.12M | { |
237 | 2.12M | cell *tempdata; |
238 | 2.12M | cell **pp = &elbg->cells[indexes[2]]; |
239 | | |
240 | 671M | while(*pp) |
241 | 669M | pp= &(*pp)->next; |
242 | | |
243 | 2.12M | *pp = elbg->cells[indexes[0]]; |
244 | | |
245 | 2.12M | elbg->cells[indexes[0]] = NULL; |
246 | 2.12M | tempdata = elbg->cells[indexes[1]]; |
247 | 2.12M | elbg->cells[indexes[1]] = NULL; |
248 | | |
249 | 162M | while(tempdata) { |
250 | 160M | cell *tempcell2 = tempdata->next; |
251 | 160M | int idx = distance_limited(elbg->points + tempdata->index*elbg->dim, |
252 | 160M | newcentroid[0], elbg->dim, INT_MAX) > |
253 | 160M | distance_limited(elbg->points + tempdata->index*elbg->dim, |
254 | 160M | newcentroid[1], elbg->dim, INT_MAX); |
255 | | |
256 | 160M | tempdata->next = elbg->cells[indexes[idx]]; |
257 | 160M | elbg->cells[indexes[idx]] = tempdata; |
258 | 160M | tempdata = tempcell2; |
259 | 160M | } |
260 | 2.12M | } |
261 | | |
262 | | static void evaluate_utility_inc(ELBGContext *elbg) |
263 | 8.84M | { |
264 | 8.84M | int64_t inc=0; |
265 | | |
266 | 297M | for (int i = 0; i < elbg->num_cb; i++) { |
267 | 288M | if (elbg->num_cb * (int64_t)elbg->utility[i] > elbg->error) |
268 | 49.3M | inc += elbg->utility[i]; |
269 | 288M | elbg->utility_inc[i] = FFMIN(inc, INT_MAX); |
270 | 288M | } |
271 | 8.84M | } |
272 | | |
273 | | |
274 | | static void update_utility_and_n_cb(ELBGContext *elbg, int idx, int newutility) |
275 | 6.36M | { |
276 | 6.36M | cell *tempcell; |
277 | | |
278 | 6.36M | elbg->utility[idx] = newutility; |
279 | 907M | for (tempcell=elbg->cells[idx]; tempcell; tempcell=tempcell->next) |
280 | 901M | elbg->nearest_cb[tempcell->index] = idx; |
281 | 6.36M | } |
282 | | |
283 | | /** |
284 | | * Evaluate if a shift lower the error. If it does, call shift_codebooks |
285 | | * and update elbg->error, elbg->utility and elbg->nearest_cb. |
286 | | * |
287 | | * @param elbg Internal elbg data |
288 | | * @param idx {luc (low utility cell, huc (high utility cell), cluc (closest cell to low utility cell)} |
289 | | */ |
290 | | static void try_shift_candidate(ELBGContext *elbg, int idx[3]) |
291 | 6.03M | { |
292 | 6.03M | int j, k, cont=0, tmp; |
293 | 6.03M | int64_t olderror=0, newerror; |
294 | 6.03M | int newutility[3]; |
295 | 6.03M | int *newcentroid[3] = { |
296 | 6.03M | elbg->scratchbuf, |
297 | 6.03M | elbg->scratchbuf + elbg->dim, |
298 | 6.03M | elbg->scratchbuf + 2*elbg->dim |
299 | 6.03M | }; |
300 | 6.03M | cell *tempcell; |
301 | | |
302 | 24.1M | for (j=0; j<3; j++) |
303 | 18.1M | olderror += elbg->utility[idx[j]]; |
304 | | |
305 | 6.03M | memset(newcentroid[2], 0, elbg->dim*sizeof(int)); |
306 | | |
307 | 18.1M | for (k=0; k<2; k++) |
308 | 2.18G | for (tempcell=elbg->cells[idx[2*k]]; tempcell; tempcell=tempcell->next) { |
309 | 2.16G | cont++; |
310 | 25.8G | for (j=0; j<elbg->dim; j++) |
311 | 23.7G | newcentroid[2][j] += elbg->points[tempcell->index*elbg->dim + j]; |
312 | 2.16G | } |
313 | | |
314 | 6.03M | vect_division(newcentroid[2], newcentroid[2], cont, elbg->dim); |
315 | | |
316 | 6.03M | get_new_centroids(elbg, idx[1], newcentroid[0], newcentroid[1]); |
317 | | |
318 | 6.03M | newutility[2] = eval_error_cell(elbg, newcentroid[2], elbg->cells[idx[0]]); |
319 | 6.03M | tmp = eval_error_cell(elbg, newcentroid[2], elbg->cells[idx[2]]); |
320 | 6.03M | newutility[2] = (tmp >= INT_MAX - newutility[2]) ? INT_MAX : newutility[2] + tmp; |
321 | | |
322 | 6.03M | newerror = newutility[2]; |
323 | | |
324 | 6.03M | tmp = simple_lbg(elbg, elbg->dim, newcentroid, newutility, elbg->points, |
325 | 6.03M | elbg->cells[idx[1]]); |
326 | 6.03M | if (tmp >= INT_MAX - newerror) |
327 | 19 | newerror = INT_MAX; |
328 | 6.03M | else |
329 | 6.03M | newerror += tmp; |
330 | | |
331 | 6.03M | if (olderror > newerror) { |
332 | 2.12M | shift_codebook(elbg, idx, newcentroid); |
333 | | |
334 | 2.12M | elbg->error += newerror - olderror; |
335 | | |
336 | 8.48M | for (j=0; j<3; j++) |
337 | 6.36M | update_utility_and_n_cb(elbg, idx[j], newutility[j]); |
338 | | |
339 | 2.12M | evaluate_utility_inc(elbg); |
340 | 2.12M | } |
341 | 6.03M | } |
342 | | |
343 | | /** |
344 | | * Implementation of the ELBG block |
345 | | */ |
346 | | static void do_shiftings(ELBGContext *elbg) |
347 | 6.72M | { |
348 | 6.72M | int idx[3]; |
349 | | |
350 | 6.72M | evaluate_utility_inc(elbg); |
351 | | |
352 | 37.4M | for (idx[0]=0; idx[0] < elbg->num_cb; idx[0]++) |
353 | 30.7M | if (elbg->num_cb * (int64_t)elbg->utility[idx[0]] < elbg->error) { |
354 | 7.67M | if (elbg->utility_inc[elbg->num_cb - 1] == 0) |
355 | 0 | return; |
356 | | |
357 | 7.67M | idx[1] = get_high_utility_cell(elbg); |
358 | 7.67M | idx[2] = get_closest_codebook(elbg, idx[0]); |
359 | | |
360 | 7.67M | if (idx[1] != idx[0] && idx[1] != idx[2]) |
361 | 6.03M | try_shift_candidate(elbg, idx); |
362 | 7.67M | } |
363 | 6.72M | } |
364 | | |
365 | | static void do_elbg(ELBGContext *restrict elbg, int *points, int numpoints, |
366 | | int max_steps) |
367 | 6.54M | { |
368 | 6.54M | int *const size_part = elbg->size_part; |
369 | 6.54M | int i, j, steps = 0; |
370 | 6.54M | int best_idx = 0; |
371 | 6.54M | int last_error; |
372 | | |
373 | 6.54M | elbg->error = INT_MAX; |
374 | 6.54M | elbg->points = points; |
375 | | |
376 | 6.72M | do { |
377 | 6.72M | cell *free_cells = elbg->cell_buffer; |
378 | 6.72M | last_error = elbg->error; |
379 | 6.72M | steps++; |
380 | 6.72M | memset(elbg->utility, 0, elbg->num_cb * sizeof(*elbg->utility)); |
381 | 6.72M | memset(elbg->cells, 0, elbg->num_cb * sizeof(*elbg->cells)); |
382 | | |
383 | 6.72M | elbg->error = 0; |
384 | | |
385 | | /* This loop evaluate the actual Voronoi partition. It is the most |
386 | | costly part of the algorithm. */ |
387 | 588M | for (i=0; i < numpoints; i++) { |
388 | 581M | int best_dist = distance_limited(elbg->points + i * elbg->dim, |
389 | 581M | elbg->codebook + best_idx * elbg->dim, |
390 | 581M | elbg->dim, INT_MAX); |
391 | 35.7G | for (int k = 0; k < elbg->num_cb; k++) { |
392 | 35.1G | int dist = distance_limited(elbg->points + i * elbg->dim, |
393 | 35.1G | elbg->codebook + k * elbg->dim, |
394 | 35.1G | elbg->dim, best_dist); |
395 | 35.1G | if (dist < best_dist) { |
396 | 151M | best_dist = dist; |
397 | 151M | best_idx = k; |
398 | 151M | } |
399 | 35.1G | } |
400 | 581M | elbg->nearest_cb[i] = best_idx; |
401 | 581M | elbg->error = (elbg->error >= INT_MAX - best_dist) ? INT_MAX : elbg->error + best_dist; |
402 | 581M | elbg->utility[elbg->nearest_cb[i]] = (elbg->utility[elbg->nearest_cb[i]] >= INT_MAX - best_dist) ? |
403 | 581M | INT_MAX : elbg->utility[elbg->nearest_cb[i]] + best_dist; |
404 | 581M | free_cells->index = i; |
405 | 581M | free_cells->next = elbg->cells[elbg->nearest_cb[i]]; |
406 | 581M | elbg->cells[elbg->nearest_cb[i]] = free_cells; |
407 | 581M | free_cells++; |
408 | 581M | } |
409 | | |
410 | 6.72M | do_shiftings(elbg); |
411 | | |
412 | 6.72M | memset(size_part, 0, elbg->num_cb * sizeof(*size_part)); |
413 | | |
414 | 6.72M | memset(elbg->codebook, 0, elbg->num_cb * elbg->dim * sizeof(*elbg->codebook)); |
415 | | |
416 | 588M | for (i=0; i < numpoints; i++) { |
417 | 581M | size_part[elbg->nearest_cb[i]]++; |
418 | 3.46G | for (j=0; j < elbg->dim; j++) |
419 | 2.88G | elbg->codebook[elbg->nearest_cb[i]*elbg->dim + j] += |
420 | 2.88G | elbg->points[i*elbg->dim + j]; |
421 | 581M | } |
422 | | |
423 | 37.4M | for (int i = 0; i < elbg->num_cb; i++) |
424 | 30.7M | vect_division(elbg->codebook + i*elbg->dim, |
425 | 30.7M | elbg->codebook + i*elbg->dim, size_part[i], elbg->dim); |
426 | | |
427 | 6.72M | } while(((last_error - elbg->error) > DELTA_ERR_MAX*elbg->error) && |
428 | 6.72M | (steps < max_steps)); |
429 | 6.54M | } |
430 | | |
431 | 77.8M | #define BIG_PRIME 433494437LL |
432 | | |
433 | | /** |
434 | | * Initialize the codebook vector for the elbg algorithm. |
435 | | * If numpoints <= 24 * num_cb this function fills codebook with random numbers. |
436 | | * If not, it calls do_elbg for a (smaller) random sample of the points in |
437 | | * points. |
438 | | */ |
439 | | static void init_elbg(ELBGContext *restrict elbg, int *points, int *temp_points, |
440 | | int numpoints, int max_steps) |
441 | 6.54M | { |
442 | 6.54M | int dim = elbg->dim; |
443 | | |
444 | 6.54M | if (numpoints > 24LL * elbg->num_cb) { |
445 | | /* ELBG is very costly for a big number of points. So if we have a lot |
446 | | of them, get a good initial codebook to save on iterations */ |
447 | 52.4M | for (int i = 0; i < numpoints / 8; i++) { |
448 | 52.2M | int k = (i*BIG_PRIME) % numpoints; |
449 | 52.2M | memcpy(temp_points + i*dim, points + k*dim, dim * sizeof(*temp_points)); |
450 | 52.2M | } |
451 | | |
452 | | /* If anything is changed in the recursion parameters, |
453 | | * the allocated size of temp_points will also need to be updated. */ |
454 | 160k | init_elbg(elbg, temp_points, temp_points + numpoints / 8 * dim, |
455 | 160k | numpoints / 8, 2 * max_steps); |
456 | 160k | do_elbg(elbg, temp_points, numpoints / 8, 2 * max_steps); |
457 | 160k | } else // If not, initialize the codebook with random positions |
458 | 31.9M | for (int i = 0; i < elbg->num_cb; i++) |
459 | 25.5M | memcpy(elbg->codebook + i * dim, points + ((i*BIG_PRIME)%numpoints)*dim, |
460 | 25.5M | dim * sizeof(*elbg->codebook)); |
461 | 6.54M | } |
462 | | |
463 | | int avpriv_elbg_do(ELBGContext **elbgp, int *points, int dim, int numpoints, |
464 | | int *codebook, int num_cb, int max_steps, |
465 | | int *closest_cb, AVLFG *rand_state, uintptr_t flags) |
466 | 6.38M | { |
467 | 6.38M | ELBGContext *const restrict elbg = *elbgp ? *elbgp : av_mallocz(sizeof(*elbg)); |
468 | | |
469 | 6.38M | if (!elbg) |
470 | 0 | return AVERROR(ENOMEM); |
471 | 6.38M | *elbgp = elbg; |
472 | | |
473 | 6.38M | elbg->nearest_cb = closest_cb; |
474 | 6.38M | elbg->rand_state = rand_state; |
475 | 6.38M | elbg->codebook = codebook; |
476 | 6.38M | elbg->num_cb = num_cb; |
477 | 6.38M | elbg->dim = dim; |
478 | | |
479 | 6.38M | #define ALLOCATE_IF_NECESSARY(field, new_elements, multiplicator) \ |
480 | 38.4M | if (elbg->field ## _allocated < new_elements) { \ |
481 | 40.1k | av_freep(&elbg->field); \ |
482 | 40.1k | elbg->field = av_malloc_array(new_elements, \ |
483 | 40.1k | multiplicator * sizeof(*elbg->field)); \ |
484 | 40.1k | if (!elbg->field) { \ |
485 | 0 | elbg->field ## _allocated = 0; \ |
486 | 0 | return AVERROR(ENOMEM); \ |
487 | 0 | } \ |
488 | 40.1k | elbg->field ## _allocated = new_elements; \ |
489 | 40.1k | } |
490 | | /* Allocating the buffers for do_elbg() here once relies |
491 | | * on their size being always the same even when do_elbg() |
492 | | * is called from init_elbg(). It also relies on do_elbg() |
493 | | * never calling itself recursively. */ |
494 | 6.38M | ALLOCATE_IF_NECESSARY(cells, num_cb, 1) |
495 | 6.38M | ALLOCATE_IF_NECESSARY(utility, num_cb, 1) |
496 | 6.38M | ALLOCATE_IF_NECESSARY(utility_inc, num_cb, 1) |
497 | 6.38M | ALLOCATE_IF_NECESSARY(size_part, num_cb, 1) |
498 | 6.38M | ALLOCATE_IF_NECESSARY(cell_buffer, numpoints, 1) |
499 | 6.38M | ALLOCATE_IF_NECESSARY(scratchbuf, dim, 5) |
500 | 6.38M | if (numpoints > 24LL * elbg->num_cb) { |
501 | | /* The first step in the recursion in init_elbg() needs a buffer with |
502 | | * (numpoints / 8) * dim elements; the next step needs numpoints / 8 / 8 |
503 | | * * dim elements etc. The geometric series leads to an upper bound of |
504 | | * numpoints / 8 * 8 / 7 * dim elements. */ |
505 | 112k | uint64_t prod = dim * (uint64_t)(numpoints / 7U); |
506 | 112k | if (prod > INT_MAX) |
507 | 0 | return AVERROR(ERANGE); |
508 | 112k | ALLOCATE_IF_NECESSARY(temp_points, prod, 1) |
509 | 112k | } |
510 | | |
511 | 6.38M | init_elbg(elbg, points, elbg->temp_points, numpoints, max_steps); |
512 | 6.38M | do_elbg (elbg, points, numpoints, max_steps); |
513 | 6.38M | return 0; |
514 | 6.38M | } |
515 | | |
516 | | av_cold void avpriv_elbg_free(ELBGContext **elbgp) |
517 | 3.10k | { |
518 | 3.10k | ELBGContext *elbg = *elbgp; |
519 | 3.10k | if (!elbg) |
520 | 106 | return; |
521 | | |
522 | 2.99k | av_freep(&elbg->size_part); |
523 | 2.99k | av_freep(&elbg->utility); |
524 | 2.99k | av_freep(&elbg->cell_buffer); |
525 | 2.99k | av_freep(&elbg->cells); |
526 | 2.99k | av_freep(&elbg->utility_inc); |
527 | 2.99k | av_freep(&elbg->scratchbuf); |
528 | 2.99k | av_freep(&elbg->temp_points); |
529 | | |
530 | 2.99k | av_freep(elbgp); |
531 | 2.99k | } |