Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/*
2
 * default memory allocator for libavutil
3
 * Copyright (c) 2002 Fabrice Bellard
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
 
22
/**
23
 * @file
24
 * default memory allocator for libavutil
25
 */
26
 
27
#define _XOPEN_SOURCE 600
28
 
29
#include "config.h"
30
 
31
#include 
32
#include 
33
#include 
34
#include 
35
#if HAVE_MALLOC_H
36
#include 
37
#endif
38
 
39
#include "avassert.h"
40
#include "avutil.h"
41
#include "intreadwrite.h"
42
#include "mem.h"
43
 
44
#ifdef MALLOC_PREFIX
45
 
46
#define malloc         AV_JOIN(MALLOC_PREFIX, malloc)
47
#define memalign       AV_JOIN(MALLOC_PREFIX, memalign)
48
#define posix_memalign AV_JOIN(MALLOC_PREFIX, posix_memalign)
49
#define realloc        AV_JOIN(MALLOC_PREFIX, realloc)
50
#define free           AV_JOIN(MALLOC_PREFIX, free)
51
 
52
void *malloc(size_t size);
53
void *memalign(size_t align, size_t size);
54
int   posix_memalign(void **ptr, size_t align, size_t size);
55
void *realloc(void *ptr, size_t size);
56
void  free(void *ptr);
57
 
58
#endif /* MALLOC_PREFIX */
59
 
60
#define ALIGN (HAVE_AVX ? 32 : 16)
61
 
62
/* NOTE: if you want to override these functions with your own
63
 * implementations (not recommended) you have to link libav* as
64
 * dynamic libraries and remove -Wl,-Bsymbolic from the linker flags.
65
 * Note that this will cost performance. */
66
 
67
static size_t max_alloc_size= INT_MAX;
68
 
69
void av_max_alloc(size_t max){
70
    max_alloc_size = max;
71
}
72
 
73
void *av_malloc(size_t size)
74
{
75
    void *ptr = NULL;
76
#if CONFIG_MEMALIGN_HACK
77
    long diff;
78
#endif
79
 
80
    /* let's disallow possibly ambiguous cases */
81
    if (size > (max_alloc_size - 32))
82
        return NULL;
83
 
84
#if CONFIG_MEMALIGN_HACK
85
    ptr = malloc(size + ALIGN);
86
    if (!ptr)
87
        return ptr;
88
    diff              = ((~(long)ptr)&(ALIGN - 1)) + 1;
89
    ptr               = (char *)ptr + diff;
90
    ((char *)ptr)[-1] = diff;
91
#elif HAVE_POSIX_MEMALIGN
92
    if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation
93
    if (posix_memalign(&ptr, ALIGN, size))
94
        ptr = NULL;
95
#elif HAVE_ALIGNED_MALLOC
96
    ptr = _aligned_malloc(size, ALIGN);
97
#elif HAVE_MEMALIGN
98
#ifndef __DJGPP__
99
    ptr = memalign(ALIGN, size);
100
#else
101
    ptr = memalign(size, ALIGN);
102
#endif
103
    /* Why 64?
104
     * Indeed, we should align it:
105
     *   on  4 for 386
106
     *   on 16 for 486
107
     *   on 32 for 586, PPro - K6-III
108
     *   on 64 for K7 (maybe for P3 too).
109
     * Because L1 and L2 caches are aligned on those values.
110
     * But I don't want to code such logic here!
111
     */
112
    /* Why 32?
113
     * For AVX ASM. SSE / NEON needs only 16.
114
     * Why not larger? Because I did not see a difference in benchmarks ...
115
     */
116
    /* benchmarks with P3
117
     * memalign(64) + 1          3071, 3051, 3032
118
     * memalign(64) + 2          3051, 3032, 3041
119
     * memalign(64) + 4          2911, 2896, 2915
120
     * memalign(64) + 8          2545, 2554, 2550
121
     * memalign(64) + 16         2543, 2572, 2563
122
     * memalign(64) + 32         2546, 2545, 2571
123
     * memalign(64) + 64         2570, 2533, 2558
124
     *
125
     * BTW, malloc seems to do 8-byte alignment by default here.
126
     */
127
#else
128
    ptr = malloc(size);
129
#endif
130
    if(!ptr && !size) {
131
        size = 1;
132
        ptr= av_malloc(1);
133
    }
134
#if CONFIG_MEMORY_POISONING
135
    if (ptr)
136
        memset(ptr, FF_MEMORY_POISON, size);
137
#endif
138
    return ptr;
139
}
140
 
141
void *av_realloc(void *ptr, size_t size)
142
{
143
#if CONFIG_MEMALIGN_HACK
144
    int diff;
145
#endif
146
 
147
    /* let's disallow possibly ambiguous cases */
148
    if (size > (max_alloc_size - 32))
149
        return NULL;
150
 
151
#if CONFIG_MEMALIGN_HACK
152
    //FIXME this isn't aligned correctly, though it probably isn't needed
153
    if (!ptr)
154
        return av_malloc(size);
155
    diff = ((char *)ptr)[-1];
156
    av_assert0(diff>0 && diff<=ALIGN);
157
    ptr = realloc((char *)ptr - diff, size + diff);
158
    if (ptr)
159
        ptr = (char *)ptr + diff;
160
    return ptr;
161
#elif HAVE_ALIGNED_MALLOC
162
    return _aligned_realloc(ptr, size + !size, ALIGN);
163
#else
164
    return realloc(ptr, size + !size);
165
#endif
166
}
167
 
168
void *av_realloc_f(void *ptr, size_t nelem, size_t elsize)
169
{
170
    size_t size;
171
    void *r;
172
 
173
    if (av_size_mult(elsize, nelem, &size)) {
174
        av_free(ptr);
175
        return NULL;
176
    }
177
    r = av_realloc(ptr, size);
178
    if (!r && size)
179
        av_free(ptr);
180
    return r;
181
}
182
 
183
int av_reallocp(void *ptr, size_t size)
184
{
185
    void **ptrptr = ptr;
186
    void *ret;
187
 
188
    if (!size) {
189
        av_freep(ptr);
190
        return 0;
191
    }
192
    ret = av_realloc(*ptrptr, size);
193
 
194
    if (!ret) {
195
        av_freep(ptr);
196
        return AVERROR(ENOMEM);
197
    }
198
 
199
    *ptrptr = ret;
200
    return 0;
201
}
202
 
203
void *av_realloc_array(void *ptr, size_t nmemb, size_t size)
204
{
205
    if (!size || nmemb >= INT_MAX / size)
206
        return NULL;
207
    return av_realloc(ptr, nmemb * size);
208
}
209
 
210
int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
211
{
212
    void **ptrptr = ptr;
213
    *ptrptr = av_realloc_f(*ptrptr, nmemb, size);
214
    if (!*ptrptr && nmemb && size)
215
        return AVERROR(ENOMEM);
216
    return 0;
217
}
218
 
219
void av_free(void *ptr)
220
{
221
#if CONFIG_MEMALIGN_HACK
222
    if (ptr) {
223
        int v= ((char *)ptr)[-1];
224
        av_assert0(v>0 && v<=ALIGN);
225
        free((char *)ptr - v);
226
    }
227
#elif HAVE_ALIGNED_MALLOC
228
    _aligned_free(ptr);
229
#else
230
    free(ptr);
231
#endif
232
}
233
 
234
void av_freep(void *arg)
235
{
236
    void **ptr = (void **)arg;
237
    av_free(*ptr);
238
    *ptr = NULL;
239
}
240
 
241
void *av_mallocz(size_t size)
242
{
243
    void *ptr = av_malloc(size);
244
    if (ptr)
245
        memset(ptr, 0, size);
246
    return ptr;
247
}
248
 
249
void *av_calloc(size_t nmemb, size_t size)
250
{
251
    if (size <= 0 || nmemb >= INT_MAX / size)
252
        return NULL;
253
    return av_mallocz(nmemb * size);
254
}
255
 
256
char *av_strdup(const char *s)
257
{
258
    char *ptr = NULL;
259
    if (s) {
260
        int len = strlen(s) + 1;
261
        ptr = av_realloc(NULL, len);
262
        if (ptr)
263
            memcpy(ptr, s, len);
264
    }
265
    return ptr;
266
}
267
 
268
void *av_memdup(const void *p, size_t size)
269
{
270
    void *ptr = NULL;
271
    if (p) {
272
        ptr = av_malloc(size);
273
        if (ptr)
274
            memcpy(ptr, p, size);
275
    }
276
    return ptr;
277
}
278
 
279
void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
280
{
281
    /* see similar ffmpeg.c:grow_array() */
282
    int nb, nb_alloc;
283
    intptr_t *tab;
284
 
285
    nb = *nb_ptr;
286
    tab = *(intptr_t**)tab_ptr;
287
    if ((nb & (nb - 1)) == 0) {
288
        if (nb == 0) {
289
            nb_alloc = 1;
290
        } else {
291
            if (nb > INT_MAX / (2 * sizeof(intptr_t)))
292
                goto fail;
293
            nb_alloc = nb * 2;
294
        }
295
        tab = av_realloc(tab, nb_alloc * sizeof(intptr_t));
296
        if (!tab)
297
            goto fail;
298
        *(intptr_t**)tab_ptr = tab;
299
    }
300
    tab[nb++] = (intptr_t)elem;
301
    *nb_ptr = nb;
302
    return;
303
 
304
fail:
305
    av_freep(tab_ptr);
306
    *nb_ptr = 0;
307
}
308
 
309
void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
310
                       const uint8_t *elem_data)
311
{
312
    int nb = *nb_ptr, nb_alloc;
313
    uint8_t *tab = *tab_ptr, *tab_elem_data;
314
 
315
    if ((nb & (nb - 1)) == 0) {
316
        if (nb == 0) {
317
            nb_alloc = 1;
318
        } else {
319
            if (nb > INT_MAX / (2 * elem_size))
320
                goto fail;
321
            nb_alloc = nb * 2;
322
        }
323
        tab = av_realloc(tab, nb_alloc * elem_size);
324
        if (!tab)
325
            goto fail;
326
        *tab_ptr = tab;
327
    }
328
    *nb_ptr = nb + 1;
329
    tab_elem_data = tab + nb*elem_size;
330
    if (elem_data)
331
        memcpy(tab_elem_data, elem_data, elem_size);
332
    else if (CONFIG_MEMORY_POISONING)
333
        memset(tab_elem_data, FF_MEMORY_POISON, elem_size);
334
    return tab_elem_data;
335
 
336
fail:
337
    av_freep(tab_ptr);
338
    *nb_ptr = 0;
339
    return NULL;
340
}
341
 
342
static void fill16(uint8_t *dst, int len)
343
{
344
    uint32_t v = AV_RN16(dst - 2);
345
 
346
    v |= v << 16;
347
 
348
    while (len >= 4) {
349
        AV_WN32(dst, v);
350
        dst += 4;
351
        len -= 4;
352
    }
353
 
354
    while (len--) {
355
        *dst = dst[-2];
356
        dst++;
357
    }
358
}
359
 
360
static void fill24(uint8_t *dst, int len)
361
{
362
#if HAVE_BIGENDIAN
363
    uint32_t v = AV_RB24(dst - 3);
364
    uint32_t a = v << 8  | v >> 16;
365
    uint32_t b = v << 16 | v >> 8;
366
    uint32_t c = v << 24 | v;
367
#else
368
    uint32_t v = AV_RL24(dst - 3);
369
    uint32_t a = v       | v << 24;
370
    uint32_t b = v >> 8  | v << 16;
371
    uint32_t c = v >> 16 | v << 8;
372
#endif
373
 
374
    while (len >= 12) {
375
        AV_WN32(dst,     a);
376
        AV_WN32(dst + 4, b);
377
        AV_WN32(dst + 8, c);
378
        dst += 12;
379
        len -= 12;
380
    }
381
 
382
    if (len >= 4) {
383
        AV_WN32(dst, a);
384
        dst += 4;
385
        len -= 4;
386
    }
387
 
388
    if (len >= 4) {
389
        AV_WN32(dst, b);
390
        dst += 4;
391
        len -= 4;
392
    }
393
 
394
    while (len--) {
395
        *dst = dst[-3];
396
        dst++;
397
    }
398
}
399
 
400
static void fill32(uint8_t *dst, int len)
401
{
402
    uint32_t v = AV_RN32(dst - 4);
403
 
404
    while (len >= 4) {
405
        AV_WN32(dst, v);
406
        dst += 4;
407
        len -= 4;
408
    }
409
 
410
    while (len--) {
411
        *dst = dst[-4];
412
        dst++;
413
    }
414
}
415
 
416
void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
417
{
418
    const uint8_t *src = &dst[-back];
419
    if (!back)
420
        return;
421
 
422
    if (back == 1) {
423
        memset(dst, *src, cnt);
424
    } else if (back == 2) {
425
        fill16(dst, cnt);
426
    } else if (back == 3) {
427
        fill24(dst, cnt);
428
    } else if (back == 4) {
429
        fill32(dst, cnt);
430
    } else {
431
        if (cnt >= 16) {
432
            int blocklen = back;
433
            while (cnt > blocklen) {
434
                memcpy(dst, src, blocklen);
435
                dst       += blocklen;
436
                cnt       -= blocklen;
437
                blocklen <<= 1;
438
            }
439
            memcpy(dst, src, cnt);
440
            return;
441
        }
442
        if (cnt >= 8) {
443
            AV_COPY32U(dst,     src);
444
            AV_COPY32U(dst + 4, src + 4);
445
            src += 8;
446
            dst += 8;
447
            cnt -= 8;
448
        }
449
        if (cnt >= 4) {
450
            AV_COPY32U(dst, src);
451
            src += 4;
452
            dst += 4;
453
            cnt -= 4;
454
        }
455
        if (cnt >= 2) {
456
            AV_COPY16U(dst, src);
457
            src += 2;
458
            dst += 2;
459
            cnt -= 2;
460
        }
461
        if (cnt)
462
            *dst = *src;
463
    }
464
}
465