LCOV - code coverage report
Current view: top level - src/libavutil - buffer.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 155 187 82.9 %
Date: 2017-01-21 09:32:20 Functions: 17 19 89.5 %

          Line data    Source code
       1             : /*
       2             :  * This file is part of FFmpeg.
       3             :  *
       4             :  * FFmpeg is free software; you can redistribute it and/or
       5             :  * modify it under the terms of the GNU Lesser General Public
       6             :  * License as published by the Free Software Foundation; either
       7             :  * version 2.1 of the License, or (at your option) any later version.
       8             :  *
       9             :  * FFmpeg is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             :  * Lesser General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU Lesser General Public
      15             :  * License along with FFmpeg; if not, write to the Free Software
      16             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      17             :  */
      18             : 
      19             : #include <stdint.h>
      20             : #include <string.h>
      21             : 
      22             : #include "atomic.h"
      23             : #include "buffer_internal.h"
      24             : #include "common.h"
      25             : #include "mem.h"
      26             : #include "thread.h"
      27             : 
      28     2826742 : AVBufferRef *av_buffer_create(uint8_t *data, int size,
      29             :                               void (*free)(void *opaque, uint8_t *data),
      30             :                               void *opaque, int flags)
      31             : {
      32     2826742 :     AVBufferRef *ref = NULL;
      33     2826742 :     AVBuffer    *buf = NULL;
      34             : 
      35     2826742 :     buf = av_mallocz(sizeof(*buf));
      36     2826743 :     if (!buf)
      37           0 :         return NULL;
      38             : 
      39     2826743 :     buf->data     = data;
      40     2826743 :     buf->size     = size;
      41     2826743 :     buf->free     = free ? free : av_buffer_default_free;
      42     2826743 :     buf->opaque   = opaque;
      43     2826743 :     buf->refcount = 1;
      44             : 
      45     2826743 :     if (flags & AV_BUFFER_FLAG_READONLY)
      46          25 :         buf->flags |= BUFFER_FLAG_READONLY;
      47             : 
      48     2826743 :     ref = av_mallocz(sizeof(*ref));
      49     2826743 :     if (!ref) {
      50           0 :         av_freep(&buf);
      51           0 :         return NULL;
      52             :     }
      53             : 
      54     2826743 :     ref->buffer = buf;
      55     2826743 :     ref->data   = data;
      56     2826743 :     ref->size   = size;
      57             : 
      58     2826743 :     return ref;
      59             : }
      60             : 
      61     1640368 : void av_buffer_default_free(void *opaque, uint8_t *data)
      62             : {
      63     1640368 :     av_free(data);
      64     1640368 : }
      65             : 
      66      483575 : AVBufferRef *av_buffer_alloc(int size)
      67             : {
      68      483575 :     AVBufferRef *ret = NULL;
      69      483575 :     uint8_t    *data = NULL;
      70             : 
      71      483575 :     data = av_malloc(size);
      72      483575 :     if (!data)
      73           0 :         return NULL;
      74             : 
      75      483575 :     ret = av_buffer_create(data, size, av_buffer_default_free, NULL, 0);
      76      483575 :     if (!ret)
      77           0 :         av_freep(&data);
      78             : 
      79      483575 :     return ret;
      80             : }
      81             : 
      82       66394 : AVBufferRef *av_buffer_allocz(int size)
      83             : {
      84       66394 :     AVBufferRef *ret = av_buffer_alloc(size);
      85       66394 :     if (!ret)
      86           0 :         return NULL;
      87             : 
      88       66394 :     memset(ret->data, 0, size);
      89       66394 :     return ret;
      90             : }
      91             : 
      92     1973045 : AVBufferRef *av_buffer_ref(AVBufferRef *buf)
      93             : {
      94     1973045 :     AVBufferRef *ret = av_mallocz(sizeof(*ret));
      95             : 
      96     1973045 :     if (!ret)
      97           0 :         return NULL;
      98             : 
      99     1973045 :     *ret = *buf;
     100             : 
     101     1973045 :     avpriv_atomic_int_add_and_fetch(&buf->buffer->refcount, 1);
     102             : 
     103     1973045 :     return ret;
     104             : }
     105             : 
     106     4799788 : static void buffer_replace(AVBufferRef **dst, AVBufferRef **src)
     107             : {
     108             :     AVBuffer *b;
     109             : 
     110     4799788 :     b = (*dst)->buffer;
     111             : 
     112     4799788 :     if (src) {
     113       36242 :         **dst = **src;
     114       36242 :         av_freep(src);
     115             :     } else
     116     4763546 :         av_freep(dst);
     117             : 
     118     4799788 :     if (!avpriv_atomic_int_add_and_fetch(&b->refcount, -1)) {
     119     2826743 :         b->free(b->opaque, b->data);
     120     2826743 :         av_freep(&b);
     121             :     }
     122     4799788 : }
     123             : 
     124    43917873 : void av_buffer_unref(AVBufferRef **buf)
     125             : {
     126    43917873 :     if (!buf || !*buf)
     127    39154328 :         return;
     128             : 
     129     4763545 :     buffer_replace(buf, NULL);
     130             : }
     131             : 
     132      176100 : int av_buffer_is_writable(const AVBufferRef *buf)
     133             : {
     134      176100 :     if (buf->buffer->flags & AV_BUFFER_FLAG_READONLY)
     135           0 :         return 0;
     136             : 
     137      176100 :     return avpriv_atomic_int_get(&buf->buffer->refcount) == 1;
     138             : }
     139             : 
     140           0 : void *av_buffer_get_opaque(const AVBufferRef *buf)
     141             : {
     142           0 :     return buf->buffer->opaque;
     143             : }
     144             : 
     145      123775 : int av_buffer_get_ref_count(const AVBufferRef *buf)
     146             : {
     147      123775 :     return buf->buffer->refcount;
     148             : }
     149             : 
     150      136128 : int av_buffer_make_writable(AVBufferRef **pbuf)
     151             : {
     152      136128 :     AVBufferRef *newbuf, *buf = *pbuf;
     153             : 
     154      136128 :     if (av_buffer_is_writable(buf))
     155      100662 :         return 0;
     156             : 
     157       35466 :     newbuf = av_buffer_alloc(buf->size);
     158       35466 :     if (!newbuf)
     159           0 :         return AVERROR(ENOMEM);
     160             : 
     161       35466 :     memcpy(newbuf->data, buf->data, buf->size);
     162             : 
     163       35466 :     buffer_replace(pbuf, &newbuf);
     164             : 
     165       35466 :     return 0;
     166             : }
     167             : 
     168     1487389 : int av_buffer_realloc(AVBufferRef **pbuf, int size)
     169             : {
     170     1487389 :     AVBufferRef *buf = *pbuf;
     171             :     uint8_t *tmp;
     172             : 
     173     1487389 :     if (!buf) {
     174             :         /* allocate a new buffer with av_realloc(), so it will be reallocatable
     175             :          * later */
     176     1156674 :         uint8_t *data = av_realloc(NULL, size);
     177     1156674 :         if (!data)
     178           0 :             return AVERROR(ENOMEM);
     179             : 
     180     1156674 :         buf = av_buffer_create(data, size, av_buffer_default_free, NULL, 0);
     181     1156674 :         if (!buf) {
     182           0 :             av_freep(&data);
     183           0 :             return AVERROR(ENOMEM);
     184             :         }
     185             : 
     186     1156674 :         buf->buffer->flags |= BUFFER_FLAG_REALLOCATABLE;
     187     1156674 :         *pbuf = buf;
     188             : 
     189     1156674 :         return 0;
     190      330715 :     } else if (buf->size == size)
     191      321844 :         return 0;
     192             : 
     193       16966 :     if (!(buf->buffer->flags & BUFFER_FLAG_REALLOCATABLE) ||
     194        8095 :         !av_buffer_is_writable(buf)) {
     195             :         /* cannot realloc, allocate a new reallocable buffer and copy data */
     196         776 :         AVBufferRef *new = NULL;
     197             : 
     198         776 :         av_buffer_realloc(&new, size);
     199         776 :         if (!new)
     200           0 :             return AVERROR(ENOMEM);
     201             : 
     202         776 :         memcpy(new->data, buf->data, FFMIN(size, buf->size));
     203             : 
     204         776 :         buffer_replace(pbuf, &new);
     205         776 :         return 0;
     206             :     }
     207             : 
     208        8095 :     tmp = av_realloc(buf->buffer->data, size);
     209        8095 :     if (!tmp)
     210           0 :         return AVERROR(ENOMEM);
     211             : 
     212        8095 :     buf->buffer->data = buf->data = tmp;
     213        8095 :     buf->buffer->size = buf->size = size;
     214        8095 :     return 0;
     215             : }
     216             : 
     217           0 : AVBufferPool *av_buffer_pool_init2(int size, void *opaque,
     218             :                                    AVBufferRef* (*alloc)(void *opaque, int size),
     219             :                                    void (*pool_free)(void *opaque))
     220             : {
     221           0 :     AVBufferPool *pool = av_mallocz(sizeof(*pool));
     222           0 :     if (!pool)
     223           0 :         return NULL;
     224             : 
     225           0 :     ff_mutex_init(&pool->mutex, NULL);
     226             : 
     227           0 :     pool->size      = size;
     228           0 :     pool->opaque    = opaque;
     229           0 :     pool->alloc2    = alloc;
     230           0 :     pool->pool_free = pool_free;
     231             : 
     232           0 :     avpriv_atomic_int_set(&pool->refcount, 1);
     233             : 
     234           0 :     return pool;
     235             : }
     236             : 
     237       41739 : AVBufferPool *av_buffer_pool_init(int size, AVBufferRef* (*alloc)(int size))
     238             : {
     239       41739 :     AVBufferPool *pool = av_mallocz(sizeof(*pool));
     240       41739 :     if (!pool)
     241           0 :         return NULL;
     242             : 
     243       41739 :     ff_mutex_init(&pool->mutex, NULL);
     244             : 
     245       41739 :     pool->size     = size;
     246       41739 :     pool->alloc    = alloc ? alloc : av_buffer_alloc;
     247             : 
     248       41739 :     avpriv_atomic_int_set(&pool->refcount, 1);
     249             : 
     250       41739 :     return pool;
     251             : }
     252             : 
     253             : /*
     254             :  * This function gets called when the pool has been uninited and
     255             :  * all the buffers returned to it.
     256             :  */
     257       41739 : static void buffer_pool_free(AVBufferPool *pool)
     258             : {
     259      162960 :     while (pool->pool) {
     260       79482 :         BufferPoolEntry *buf = pool->pool;
     261       79482 :         pool->pool = buf->next;
     262             : 
     263       79482 :         buf->free(buf->opaque, buf->data);
     264       79482 :         av_freep(&buf);
     265             :     }
     266       41739 :     ff_mutex_destroy(&pool->mutex);
     267             : 
     268       41739 :     if (pool->pool_free)
     269           0 :         pool->pool_free(pool->opaque);
     270             : 
     271       41739 :     av_freep(&pool);
     272       41739 : }
     273             : 
     274      131033 : void av_buffer_pool_uninit(AVBufferPool **ppool)
     275             : {
     276             :     AVBufferPool *pool;
     277             : 
     278      131033 :     if (!ppool || !*ppool)
     279       89294 :         return;
     280       41739 :     pool   = *ppool;
     281       41739 :     *ppool = NULL;
     282             : 
     283       41739 :     if (!avpriv_atomic_int_add_and_fetch(&pool->refcount, -1))
     284       32925 :         buffer_pool_free(pool);
     285             : }
     286             : 
     287             : #if USE_ATOMICS
     288             : /* remove the whole buffer list from the pool and return it */
     289             : static BufferPoolEntry *get_pool(AVBufferPool *pool)
     290             : {
     291             :     BufferPoolEntry *cur = *(void * volatile *)&pool->pool, *last = NULL;
     292             : 
     293             :     while (cur != last) {
     294             :         last = cur;
     295             :         cur = avpriv_atomic_ptr_cas((void * volatile *)&pool->pool, last, NULL);
     296             :         if (!cur)
     297             :             return NULL;
     298             :     }
     299             : 
     300             :     return cur;
     301             : }
     302             : 
     303             : static void add_to_pool(BufferPoolEntry *buf)
     304             : {
     305             :     AVBufferPool *pool;
     306             :     BufferPoolEntry *cur, *end = buf;
     307             : 
     308             :     if (!buf)
     309             :         return;
     310             :     pool = buf->pool;
     311             : 
     312             :     while (end->next)
     313             :         end = end->next;
     314             : 
     315             :     while (avpriv_atomic_ptr_cas((void * volatile *)&pool->pool, NULL, buf)) {
     316             :         /* pool is not empty, retrieve it and append it to our list */
     317             :         cur = get_pool(pool);
     318             :         end->next = cur;
     319             :         while (end->next)
     320             :             end = end->next;
     321             :     }
     322             : }
     323             : #endif
     324             : 
     325     1262993 : static void pool_release_buffer(void *opaque, uint8_t *data)
     326             : {
     327     1262993 :     BufferPoolEntry *buf = opaque;
     328     1262993 :     AVBufferPool *pool = buf->pool;
     329             : 
     330             :     if(CONFIG_MEMORY_POISONING)
     331     1262993 :         memset(buf->data, FF_MEMORY_POISON, pool->size);
     332             : 
     333             : #if USE_ATOMICS
     334             :     add_to_pool(buf);
     335             : #else
     336     1262993 :     ff_mutex_lock(&pool->mutex);
     337     1262993 :     buf->next = pool->pool;
     338     1262993 :     pool->pool = buf;
     339     1262993 :     ff_mutex_unlock(&pool->mutex);
     340             : #endif
     341             : 
     342     1262993 :     if (!avpriv_atomic_int_add_and_fetch(&pool->refcount, -1))
     343        8814 :         buffer_pool_free(pool);
     344     1262993 : }
     345             : 
     346             : /* allocate a new buffer and override its free() callback so that
     347             :  * it is returned to the pool on free */
     348       79482 : static AVBufferRef *pool_alloc_buffer(AVBufferPool *pool)
     349             : {
     350             :     BufferPoolEntry *buf;
     351             :     AVBufferRef     *ret;
     352             : 
     353      158964 :     ret = pool->alloc2 ? pool->alloc2(pool->opaque, pool->size) :
     354       79482 :                          pool->alloc(pool->size);
     355       79482 :     if (!ret)
     356           0 :         return NULL;
     357             : 
     358       79482 :     buf = av_mallocz(sizeof(*buf));
     359       79482 :     if (!buf) {
     360           0 :         av_buffer_unref(&ret);
     361           0 :         return NULL;
     362             :     }
     363             : 
     364       79482 :     buf->data   = ret->buffer->data;
     365       79482 :     buf->opaque = ret->buffer->opaque;
     366       79482 :     buf->free   = ret->buffer->free;
     367       79482 :     buf->pool   = pool;
     368             : 
     369       79482 :     ret->buffer->opaque = buf;
     370       79482 :     ret->buffer->free   = pool_release_buffer;
     371             : 
     372             : #if USE_ATOMICS
     373             :     avpriv_atomic_int_add_and_fetch(&pool->refcount, 1);
     374             :     avpriv_atomic_int_add_and_fetch(&pool->nb_allocated, 1);
     375             : #endif
     376             : 
     377       79482 :     return ret;
     378             : }
     379             : 
     380     1262993 : AVBufferRef *av_buffer_pool_get(AVBufferPool *pool)
     381             : {
     382             :     AVBufferRef *ret;
     383             :     BufferPoolEntry *buf;
     384             : 
     385             : #if USE_ATOMICS
     386             :     /* check whether the pool is empty */
     387             :     buf = get_pool(pool);
     388             :     if (!buf && pool->refcount <= pool->nb_allocated) {
     389             :         av_log(NULL, AV_LOG_DEBUG, "Pool race dectected, spining to avoid overallocation and eventual OOM\n");
     390             :         while (!buf && avpriv_atomic_int_get(&pool->refcount) <= avpriv_atomic_int_get(&pool->nb_allocated))
     391             :             buf = get_pool(pool);
     392             :     }
     393             : 
     394             :     if (!buf)
     395             :         return pool_alloc_buffer(pool);
     396             : 
     397             :     /* keep the first entry, return the rest of the list to the pool */
     398             :     add_to_pool(buf->next);
     399             :     buf->next = NULL;
     400             : 
     401             :     ret = av_buffer_create(buf->data, pool->size, pool_release_buffer,
     402             :                            buf, 0);
     403             :     if (!ret) {
     404             :         add_to_pool(buf);
     405             :         return NULL;
     406             :     }
     407             : #else
     408     1262993 :     ff_mutex_lock(&pool->mutex);
     409     1262993 :     buf = pool->pool;
     410     1262993 :     if (buf) {
     411     1183511 :         ret = av_buffer_create(buf->data, pool->size, pool_release_buffer,
     412             :                                buf, 0);
     413     1183511 :         if (ret) {
     414     1183511 :             pool->pool = buf->next;
     415     1183511 :             buf->next = NULL;
     416             :         }
     417             :     } else {
     418       79482 :         ret = pool_alloc_buffer(pool);
     419             :     }
     420     1262993 :     ff_mutex_unlock(&pool->mutex);
     421             : #endif
     422             : 
     423     1262993 :     if (ret)
     424     1262993 :         avpriv_atomic_int_add_and_fetch(&pool->refcount, 1);
     425             : 
     426     1262993 :     return ret;
     427             : }

Generated by: LCOV version 1.12