Coverage Report

Created: 2026-05-16 07:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/elbg.c
Line
Count
Source
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
7.80M
#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
30.0G
{
77
30.0G
    int i, dist=0;
78
72.9G
    for (i=0; i<dim; i++) {
79
68.7G
        int64_t distance = a[i] - b[i];
80
81
68.7G
        distance *= distance;
82
68.7G
        if (dist >= limit - distance)
83
25.8G
            return limit;
84
42.8G
        dist += distance;
85
42.8G
    }
86
87
4.16G
    return dist;
88
30.0G
}
89
90
static inline void vect_division(int *res, int *vect, int div, int dim)
91
49.5M
{
92
49.5M
    int i;
93
49.5M
    if (div > 1)
94
128M
        for (i=0; i<dim; i++)
95
108M
            res[i] = ROUNDED_DIV(vect[i],div);
96
29.4M
    else if (res != vect)
97
4.59M
        memcpy(res, vect, dim*sizeof(int));
98
99
49.5M
}
100
101
static int eval_error_cell(ELBGContext *elbg, int *centroid, cell *cells)
102
10.0M
{
103
10.0M
    int error=0;
104
1.81G
    for (; cells; cells=cells->next) {
105
1.80G
        int distance = distance_limited(centroid, elbg->points + cells->index*elbg->dim, elbg->dim, INT_MAX);
106
1.80G
        if (error >= INT_MAX - distance)
107
0
            return INT_MAX;
108
1.80G
        error += distance;
109
1.80G
    }
110
111
10.0M
    return error;
112
10.0M
}
113
114
static int get_closest_codebook(ELBGContext *elbg, int index)
115
6.82M
{
116
6.82M
    int pick = 0;
117
926M
    for (int i = 0, diff_min = INT_MAX; i < elbg->num_cb; i++)
118
919M
        if (i != index) {
119
912M
            int diff;
120
912M
            diff = distance_limited(elbg->codebook + i*elbg->dim, elbg->codebook + index*elbg->dim, elbg->dim, diff_min);
121
912M
            if (diff < diff_min) {
122
20.8M
                pick = i;
123
20.8M
                diff_min = diff;
124
20.8M
            }
125
912M
        }
126
6.82M
    return pick;
127
6.82M
}
128
129
static int get_high_utility_cell(ELBGContext *elbg)
130
6.82M
{
131
6.82M
    int i=0;
132
    /* Using linear search, do binary if it ever turns to be speed critical */
133
6.82M
    uint64_t r;
134
135
6.82M
    if (elbg->utility_inc[elbg->num_cb - 1] < INT_MAX) {
136
6.82M
        r = av_lfg_get(elbg->rand_state) % (unsigned int)elbg->utility_inc[elbg->num_cb - 1] + 1;
137
6.82M
    } else {
138
0
        r = av_lfg_get(elbg->rand_state);
139
0
        r = (av_lfg_get(elbg->rand_state) + (r<<32)) % elbg->utility_inc[elbg->num_cb - 1] + 1;
140
0
    }
141
142
224M
    while (elbg->utility_inc[i] < r) {
143
218M
        i++;
144
218M
    }
145
146
6.82M
    av_assert2(elbg->cells[i]);
147
148
6.82M
    return i;
149
6.82M
}
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
5.03M
{
161
5.03M
    int i, idx;
162
5.03M
    int numpoints[2] = {0,0};
163
5.03M
    int *newcentroid[2] = {
164
5.03M
        elbg->scratchbuf + 3*dim,
165
5.03M
        elbg->scratchbuf + 4*dim
166
5.03M
    };
167
5.03M
    cell *tempcell;
168
169
5.03M
    memset(newcentroid[0], 0, 2 * dim * sizeof(*newcentroid[0]));
170
171
5.03M
    newutility[0] =
172
5.03M
    newutility[1] = 0;
173
174
390M
    for (tempcell = cells; tempcell; tempcell=tempcell->next) {
175
385M
        idx = distance_limited(centroid[0], points + tempcell->index*dim, dim, INT_MAX)>=
176
385M
              distance_limited(centroid[1], points + tempcell->index*dim, dim, INT_MAX);
177
385M
        numpoints[idx]++;
178
3.31G
        for (i=0; i<dim; i++)
179
2.92G
            newcentroid[idx][i] += points[tempcell->index*dim + i];
180
385M
    }
181
182
5.03M
    vect_division(centroid[0], newcentroid[0], numpoints[0], dim);
183
5.03M
    vect_division(centroid[1], newcentroid[1], numpoints[1], dim);
184
185
390M
    for (tempcell = cells; tempcell; tempcell=tempcell->next) {
186
385M
        int dist[2] = {distance_limited(centroid[0], points + tempcell->index*dim, dim, INT_MAX),
187
385M
                       distance_limited(centroid[1], points + tempcell->index*dim, dim, INT_MAX)};
188
385M
        int idx = dist[0] > dist[1];
189
385M
        if (newutility[idx] >= INT_MAX - dist[idx])
190
0
            newutility[idx] = INT_MAX;
191
385M
        else
192
385M
            newutility[idx] += dist[idx];
193
385M
    }
194
195
5.03M
    return (newutility[0] >= INT_MAX - newutility[1]) ? INT_MAX : newutility[0] + newutility[1];
196
5.03M
}
197
198
static void get_new_centroids(ELBGContext *elbg, int huc, int *newcentroid_i,
199
                              int *newcentroid_p)
200
5.03M
{
201
5.03M
    cell *tempcell;
202
5.03M
    int *min = newcentroid_i;
203
5.03M
    int *max = newcentroid_p;
204
5.03M
    int i;
205
206
42.5M
    for (i=0; i< elbg->dim; i++) {
207
37.4M
        min[i]=INT_MAX;
208
37.4M
        max[i]=0;
209
37.4M
    }
210
211
390M
    for (tempcell = elbg->cells[huc]; tempcell; tempcell = tempcell->next)
212
3.31G
        for(i=0; i<elbg->dim; i++) {
213
2.92G
            min[i]=FFMIN(min[i], elbg->points[tempcell->index*elbg->dim + i]);
214
2.92G
            max[i]=FFMAX(max[i], elbg->points[tempcell->index*elbg->dim + i]);
215
2.92G
        }
216
217
42.5M
    for (i=0; i<elbg->dim; i++) {
218
37.4M
        int ni = min[i] + (max[i] - min[i])/3;
219
37.4M
        int np = min[i] + (2*(max[i] - min[i]))/3;
220
37.4M
        newcentroid_i[i] = ni;
221
37.4M
        newcentroid_p[i] = np;
222
37.4M
    }
223
5.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
1.88M
{
237
1.88M
    cell *tempdata;
238
1.88M
    cell **pp = &elbg->cells[indexes[2]];
239
240
597M
    while(*pp)
241
596M
        pp= &(*pp)->next;
242
243
1.88M
    *pp = elbg->cells[indexes[0]];
244
245
1.88M
    elbg->cells[indexes[0]] = NULL;
246
1.88M
    tempdata = elbg->cells[indexes[1]];
247
1.88M
    elbg->cells[indexes[1]] = NULL;
248
249
114M
    while(tempdata) {
250
112M
        cell *tempcell2 = tempdata->next;
251
112M
        int idx = distance_limited(elbg->points + tempdata->index*elbg->dim,
252
112M
                           newcentroid[0], elbg->dim, INT_MAX) >
253
112M
                  distance_limited(elbg->points + tempdata->index*elbg->dim,
254
112M
                           newcentroid[1], elbg->dim, INT_MAX);
255
256
112M
        tempdata->next = elbg->cells[indexes[idx]];
257
112M
        elbg->cells[indexes[idx]] = tempdata;
258
112M
        tempdata = tempcell2;
259
112M
    }
260
1.88M
}
261
262
static void evaluate_utility_inc(ELBGContext *elbg)
263
9.68M
{
264
9.68M
    int64_t inc=0;
265
266
245M
    for (int i = 0; i < elbg->num_cb; i++) {
267
235M
        if (elbg->num_cb * (int64_t)elbg->utility[i] > elbg->error)
268
40.0M
            inc += elbg->utility[i];
269
235M
        elbg->utility_inc[i] = FFMIN(inc, INT_MAX);
270
235M
    }
271
9.68M
}
272
273
274
static void update_utility_and_n_cb(ELBGContext *elbg, int idx, int newutility)
275
5.65M
{
276
5.65M
    cell *tempcell;
277
278
5.65M
    elbg->utility[idx] = newutility;
279
767M
    for (tempcell=elbg->cells[idx]; tempcell; tempcell=tempcell->next)
280
761M
        elbg->nearest_cb[tempcell->index] = idx;
281
5.65M
}
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
5.03M
{
292
5.03M
    int j, k, cont=0, tmp;
293
5.03M
    int64_t olderror=0, newerror;
294
5.03M
    int newutility[3];
295
5.03M
    int *newcentroid[3] = {
296
5.03M
        elbg->scratchbuf,
297
5.03M
        elbg->scratchbuf + elbg->dim,
298
5.03M
        elbg->scratchbuf + 2*elbg->dim
299
5.03M
    };
300
5.03M
    cell *tempcell;
301
302
20.1M
    for (j=0; j<3; j++)
303
15.0M
        olderror += elbg->utility[idx[j]];
304
305
5.03M
    memset(newcentroid[2], 0, elbg->dim*sizeof(int));
306
307
15.0M
    for (k=0; k<2; k++)
308
1.81G
        for (tempcell=elbg->cells[idx[2*k]]; tempcell; tempcell=tempcell->next) {
309
1.80G
            cont++;
310
24.3G
            for (j=0; j<elbg->dim; j++)
311
22.5G
                newcentroid[2][j] += elbg->points[tempcell->index*elbg->dim + j];
312
1.80G
        }
313
314
5.03M
    vect_division(newcentroid[2], newcentroid[2], cont, elbg->dim);
315
316
5.03M
    get_new_centroids(elbg, idx[1], newcentroid[0], newcentroid[1]);
317
318
5.03M
    newutility[2]  = eval_error_cell(elbg, newcentroid[2], elbg->cells[idx[0]]);
319
5.03M
    tmp            = eval_error_cell(elbg, newcentroid[2], elbg->cells[idx[2]]);
320
5.03M
    newutility[2]  = (tmp >= INT_MAX - newutility[2]) ? INT_MAX : newutility[2] + tmp;
321
322
5.03M
    newerror = newutility[2];
323
324
5.03M
    tmp = simple_lbg(elbg, elbg->dim, newcentroid, newutility, elbg->points,
325
5.03M
                           elbg->cells[idx[1]]);
326
5.03M
    if (tmp >= INT_MAX - newerror)
327
10
        newerror = INT_MAX;
328
5.03M
    else
329
5.03M
        newerror += tmp;
330
331
5.03M
    if (olderror > newerror) {
332
1.88M
        shift_codebook(elbg, idx, newcentroid);
333
334
1.88M
        elbg->error += newerror - olderror;
335
336
7.53M
        for (j=0; j<3; j++)
337
5.65M
            update_utility_and_n_cb(elbg, idx[j], newutility[j]);
338
339
1.88M
        evaluate_utility_inc(elbg);
340
1.88M
    }
341
5.03M
 }
342
343
/**
344
 * Implementation of the ELBG block
345
 */
346
static void do_shiftings(ELBGContext *elbg)
347
7.80M
{
348
7.80M
    int idx[3];
349
350
7.80M
    evaluate_utility_inc(elbg);
351
352
42.2M
    for (idx[0]=0; idx[0] < elbg->num_cb; idx[0]++)
353
34.4M
        if (elbg->num_cb * (int64_t)elbg->utility[idx[0]] < elbg->error) {
354
6.82M
            if (elbg->utility_inc[elbg->num_cb - 1] == 0)
355
0
                return;
356
357
6.82M
            idx[1] = get_high_utility_cell(elbg);
358
6.82M
            idx[2] = get_closest_codebook(elbg, idx[0]);
359
360
6.82M
            if (idx[1] != idx[0] && idx[1] != idx[2])
361
5.03M
                try_shift_candidate(elbg, idx);
362
6.82M
        }
363
7.80M
}
364
365
static void do_elbg(ELBGContext *restrict elbg, int *points, int numpoints,
366
                    int max_steps)
367
7.63M
{
368
7.63M
    int *const size_part = elbg->size_part;
369
7.63M
    int i, j, steps = 0;
370
7.63M
    int best_idx = 0;
371
7.63M
    int last_error;
372
373
7.63M
    elbg->error = INT_MAX;
374
7.63M
    elbg->points = points;
375
376
7.80M
    do {
377
7.80M
        cell *free_cells = elbg->cell_buffer;
378
7.80M
        last_error = elbg->error;
379
7.80M
        steps++;
380
7.80M
        memset(elbg->utility, 0, elbg->num_cb * sizeof(*elbg->utility));
381
7.80M
        memset(elbg->cells,   0, elbg->num_cb * sizeof(*elbg->cells));
382
383
7.80M
        elbg->error = 0;
384
385
        /* This loop evaluate the actual Voronoi partition. It is the most
386
           costly part of the algorithm. */
387
424M
        for (i=0; i < numpoints; i++) {
388
417M
            int best_dist = distance_limited(elbg->points   + i * elbg->dim,
389
417M
                                             elbg->codebook + best_idx * elbg->dim,
390
417M
                                             elbg->dim, INT_MAX);
391
25.5G
            for (int k = 0; k < elbg->num_cb; k++) {
392
25.1G
                int dist = distance_limited(elbg->points   + i * elbg->dim,
393
25.1G
                                            elbg->codebook + k * elbg->dim,
394
25.1G
                                            elbg->dim, best_dist);
395
25.1G
                if (dist < best_dist) {
396
156M
                    best_dist = dist;
397
156M
                    best_idx = k;
398
156M
                }
399
25.1G
            }
400
417M
            elbg->nearest_cb[i] = best_idx;
401
417M
            elbg->error = (elbg->error >= INT_MAX - best_dist) ? INT_MAX : elbg->error + best_dist;
402
417M
            elbg->utility[elbg->nearest_cb[i]] = (elbg->utility[elbg->nearest_cb[i]] >= INT_MAX - best_dist) ?
403
417M
                                                  INT_MAX : elbg->utility[elbg->nearest_cb[i]] + best_dist;
404
417M
            free_cells->index = i;
405
417M
            free_cells->next = elbg->cells[elbg->nearest_cb[i]];
406
417M
            elbg->cells[elbg->nearest_cb[i]] = free_cells;
407
417M
            free_cells++;
408
417M
        }
409
410
7.80M
        do_shiftings(elbg);
411
412
7.80M
        memset(size_part,      0, elbg->num_cb * sizeof(*size_part));
413
414
7.80M
        memset(elbg->codebook, 0, elbg->num_cb * elbg->dim * sizeof(*elbg->codebook));
415
416
424M
        for (i=0; i < numpoints; i++) {
417
417M
            size_part[elbg->nearest_cb[i]]++;
418
2.54G
            for (j=0; j < elbg->dim; j++)
419
2.12G
                elbg->codebook[elbg->nearest_cb[i]*elbg->dim + j] +=
420
2.12G
                    elbg->points[i*elbg->dim + j];
421
417M
        }
422
423
42.2M
        for (int i = 0; i < elbg->num_cb; i++)
424
34.4M
            vect_division(elbg->codebook + i*elbg->dim,
425
34.4M
                          elbg->codebook + i*elbg->dim, size_part[i], elbg->dim);
426
427
7.80M
    } while(((last_error - elbg->error) > DELTA_ERR_MAX*elbg->error) &&
428
7.71M
            (steps < max_steps));
429
7.63M
}
430
431
64.4M
#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
7.63M
{
442
7.63M
    int dim = elbg->dim;
443
444
7.63M
    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
33.8M
        for (int i = 0; i < numpoints / 8; i++) {
448
33.7M
            int k = (i*BIG_PRIME) % numpoints;
449
33.7M
            memcpy(temp_points + i*dim, points + k*dim, dim * sizeof(*temp_points));
450
33.7M
        }
451
452
        /* If anything is changed in the recursion parameters,
453
         * the allocated size of temp_points will also need to be updated. */
454
150k
        init_elbg(elbg, temp_points, temp_points + numpoints / 8 * dim,
455
150k
                  numpoints / 8, 2 * max_steps);
456
150k
        do_elbg(elbg, temp_points, numpoints / 8, 2 * max_steps);
457
150k
    } else  // If not, initialize the codebook with random positions
458
38.2M
        for (int i = 0; i < elbg->num_cb; i++)
459
30.7M
            memcpy(elbg->codebook + i * dim, points + ((i*BIG_PRIME)%numpoints)*dim,
460
30.7M
                   dim * sizeof(*elbg->codebook));
461
7.63M
}
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
7.48M
{
467
7.48M
    ELBGContext *const restrict elbg = *elbgp ? *elbgp : av_mallocz(sizeof(*elbg));
468
469
7.48M
    if (!elbg)
470
0
        return AVERROR(ENOMEM);
471
7.48M
    *elbgp = elbg;
472
473
7.48M
    elbg->nearest_cb = closest_cb;
474
7.48M
    elbg->rand_state = rand_state;
475
7.48M
    elbg->codebook   = codebook;
476
7.48M
    elbg->num_cb     = num_cb;
477
7.48M
    elbg->dim        = dim;
478
479
7.48M
#define ALLOCATE_IF_NECESSARY(field, new_elements, multiplicator)            \
480
45.0M
    if (elbg->field ## _allocated < new_elements) {                          \
481
38.3k
        av_freep(&elbg->field);                                              \
482
38.3k
        elbg->field = av_malloc_array(new_elements,                          \
483
38.3k
                                      multiplicator * sizeof(*elbg->field)); \
484
38.3k
        if (!elbg->field) {                                                  \
485
0
            elbg->field ## _allocated = 0;                                   \
486
0
            return AVERROR(ENOMEM);                                          \
487
0
        }                                                                    \
488
38.3k
        elbg->field ## _allocated = new_elements;                            \
489
38.3k
    }
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
7.48M
    ALLOCATE_IF_NECESSARY(cells,       num_cb,    1)
495
7.48M
    ALLOCATE_IF_NECESSARY(utility,     num_cb,    1)
496
7.48M
    ALLOCATE_IF_NECESSARY(utility_inc, num_cb,    1)
497
7.48M
    ALLOCATE_IF_NECESSARY(size_part,   num_cb,    1)
498
7.48M
    ALLOCATE_IF_NECESSARY(cell_buffer, numpoints, 1)
499
7.48M
    ALLOCATE_IF_NECESSARY(scratchbuf,  dim,       5)
500
7.48M
    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
116k
        uint64_t prod = dim * (uint64_t)(numpoints / 7U);
506
116k
        if (prod > INT_MAX)
507
0
            return AVERROR(ERANGE);
508
116k
        ALLOCATE_IF_NECESSARY(temp_points, prod, 1)
509
116k
    }
510
511
7.48M
    init_elbg(elbg, points, elbg->temp_points, numpoints, max_steps);
512
7.48M
    do_elbg (elbg, points, numpoints, max_steps);
513
7.48M
    return 0;
514
7.48M
}
515
516
av_cold void avpriv_elbg_free(ELBGContext **elbgp)
517
3.02k
{
518
3.02k
    ELBGContext *elbg = *elbgp;
519
3.02k
    if (!elbg)
520
105
        return;
521
522
2.92k
    av_freep(&elbg->size_part);
523
2.92k
    av_freep(&elbg->utility);
524
2.92k
    av_freep(&elbg->cell_buffer);
525
2.92k
    av_freep(&elbg->cells);
526
2.92k
    av_freep(&elbg->utility_inc);
527
2.92k
    av_freep(&elbg->scratchbuf);
528
2.92k
    av_freep(&elbg->temp_points);
529
530
2.92k
    av_freep(elbgp);
531
2.92k
}