Coverage Report

Created: 2025-08-28 07:12

/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
}