Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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 <limits.h>
  32. #include <stdint.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #if HAVE_MALLOC_H
  36. #include <malloc.h>
  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.  
  466.