FFmpeg  4.4.5
buffer.c
Go to the documentation of this file.
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 <stdatomic.h>
20 #include <stdint.h>
21 #include <string.h>
22 
23 #include "avassert.h"
24 #include "buffer_internal.h"
25 #include "common.h"
26 #include "mem.h"
27 #include "thread.h"
28 
30  void (*free)(void *opaque, uint8_t *data),
31  void *opaque, int flags)
32 {
33  AVBufferRef *ref = NULL;
34  AVBuffer *buf = NULL;
35 
36  buf = av_mallocz(sizeof(*buf));
37  if (!buf)
38  return NULL;
39 
40  buf->data = data;
41  buf->size = size;
42  buf->free = free ? free : av_buffer_default_free;
43  buf->opaque = opaque;
44 
45  atomic_init(&buf->refcount, 1);
46 
47  buf->flags = flags;
48 
49  ref = av_mallocz(sizeof(*ref));
50  if (!ref) {
51  av_freep(&buf);
52  return NULL;
53  }
54 
55  ref->buffer = buf;
56  ref->data = data;
57  ref->size = size;
58 
59  return ref;
60 }
61 
62 void av_buffer_default_free(void *opaque, uint8_t *data)
63 {
64  av_free(data);
65 }
66 
68 {
69  AVBufferRef *ret = NULL;
70  uint8_t *data = NULL;
71 
72  data = av_malloc(size);
73  if (!data)
74  return NULL;
75 
77  if (!ret)
78  av_freep(&data);
79 
80  return ret;
81 }
82 
84 {
86  if (!ret)
87  return NULL;
88 
89  memset(ret->data, 0, size);
90  return ret;
91 }
92 
94 {
95  AVBufferRef *ret = av_mallocz(sizeof(*ret));
96 
97  if (!ret)
98  return NULL;
99 
100  *ret = *buf;
101 
102  atomic_fetch_add_explicit(&buf->buffer->refcount, 1, memory_order_relaxed);
103 
104  return ret;
105 }
106 
108 {
109  AVBuffer *b;
110 
111  b = (*dst)->buffer;
112 
113  if (src) {
114  **dst = **src;
115  av_freep(src);
116  } else
117  av_freep(dst);
118 
119  if (atomic_fetch_sub_explicit(&b->refcount, 1, memory_order_acq_rel) == 1) {
120  b->free(b->opaque, b->data);
121  av_freep(&b);
122  }
123 }
124 
126 {
127  if (!buf || !*buf)
128  return;
129 
130  buffer_replace(buf, NULL);
131 }
132 
134 {
136  return 0;
137 
138  return atomic_load(&buf->buffer->refcount) == 1;
139 }
140 
142 {
143  return buf->buffer->opaque;
144 }
145 
147 {
148  return atomic_load(&buf->buffer->refcount);
149 }
150 
152 {
153  AVBufferRef *newbuf, *buf = *pbuf;
154 
155  if (av_buffer_is_writable(buf))
156  return 0;
157 
158  newbuf = av_buffer_alloc(buf->size);
159  if (!newbuf)
160  return AVERROR(ENOMEM);
161 
162  memcpy(newbuf->data, buf->data, buf->size);
163 
164  buffer_replace(pbuf, &newbuf);
165 
166  return 0;
167 }
168 
170 {
171  AVBufferRef *buf = *pbuf;
172  uint8_t *tmp;
173  int ret;
174 
175  if (!buf) {
176  /* allocate a new buffer with av_realloc(), so it will be reallocatable
177  * later */
179  if (!data)
180  return AVERROR(ENOMEM);
181 
183  if (!buf) {
184  av_freep(&data);
185  return AVERROR(ENOMEM);
186  }
187 
189  *pbuf = buf;
190 
191  return 0;
192  } else if (buf->size == size)
193  return 0;
194 
196  !av_buffer_is_writable(buf) || buf->data != buf->buffer->data) {
197  /* cannot realloc, allocate a new reallocable buffer and copy data */
198  AVBufferRef *new = NULL;
199 
200  ret = av_buffer_realloc(&new, size);
201  if (ret < 0)
202  return ret;
203 
204  memcpy(new->data, buf->data, FFMIN(size, buf->size));
205 
206  buffer_replace(pbuf, &new);
207  return 0;
208  }
209 
210  tmp = av_realloc(buf->buffer->data, size);
211  if (!tmp)
212  return AVERROR(ENOMEM);
213 
214  buf->buffer->data = buf->data = tmp;
215  buf->buffer->size = buf->size = size;
216  return 0;
217 }
218 
220 {
221  AVBufferRef *dst = *pdst;
222  AVBufferRef *tmp;
223 
224  if (!src) {
225  av_buffer_unref(pdst);
226  return 0;
227  }
228 
229  if (dst && dst->buffer == src->buffer) {
230  /* make sure the data pointers match */
231  dst->data = src->data;
232  dst->size = src->size;
233  return 0;
234  }
235 
236  tmp = av_buffer_ref(src);
237  if (!tmp)
238  return AVERROR(ENOMEM);
239 
240  av_buffer_unref(pdst);
241  *pdst = tmp;
242  return 0;
243 }
244 
246  AVBufferRef* (*alloc)(void *opaque, buffer_size_t size),
247  void (*pool_free)(void *opaque))
248 {
249  AVBufferPool *pool = av_mallocz(sizeof(*pool));
250  if (!pool)
251  return NULL;
252 
253  if (ff_mutex_init(&pool->mutex, NULL)) {
254  av_free(pool);
255  return NULL;
256  }
257 
258  pool->size = size;
259  pool->opaque = opaque;
260  pool->alloc2 = alloc;
261  pool->alloc = av_buffer_alloc; // fallback
262  pool->pool_free = pool_free;
263 
264  atomic_init(&pool->refcount, 1);
265 
266  return pool;
267 }
268 
270 {
271  AVBufferPool *pool = av_mallocz(sizeof(*pool));
272  if (!pool)
273  return NULL;
274 
275  if (ff_mutex_init(&pool->mutex, NULL)) {
276  av_free(pool);
277  return NULL;
278  }
279 
280  pool->size = size;
281  pool->alloc = alloc ? alloc : av_buffer_alloc;
282 
283  atomic_init(&pool->refcount, 1);
284 
285  return pool;
286 }
287 
288 static void buffer_pool_flush(AVBufferPool *pool)
289 {
290  while (pool->pool) {
291  BufferPoolEntry *buf = pool->pool;
292  pool->pool = buf->next;
293 
294  buf->free(buf->opaque, buf->data);
295  av_freep(&buf);
296  }
297 }
298 
299 /*
300  * This function gets called when the pool has been uninited and
301  * all the buffers returned to it.
302  */
303 static void buffer_pool_free(AVBufferPool *pool)
304 {
305  buffer_pool_flush(pool);
306  ff_mutex_destroy(&pool->mutex);
307 
308  if (pool->pool_free)
309  pool->pool_free(pool->opaque);
310 
311  av_freep(&pool);
312 }
313 
315 {
316  AVBufferPool *pool;
317 
318  if (!ppool || !*ppool)
319  return;
320  pool = *ppool;
321  *ppool = NULL;
322 
323  ff_mutex_lock(&pool->mutex);
324  buffer_pool_flush(pool);
325  ff_mutex_unlock(&pool->mutex);
326 
327  if (atomic_fetch_sub_explicit(&pool->refcount, 1, memory_order_acq_rel) == 1)
328  buffer_pool_free(pool);
329 }
330 
331 static void pool_release_buffer(void *opaque, uint8_t *data)
332 {
333  BufferPoolEntry *buf = opaque;
334  AVBufferPool *pool = buf->pool;
335 
337  memset(buf->data, FF_MEMORY_POISON, pool->size);
338 
339  ff_mutex_lock(&pool->mutex);
340  buf->next = pool->pool;
341  pool->pool = buf;
342  ff_mutex_unlock(&pool->mutex);
343 
344  if (atomic_fetch_sub_explicit(&pool->refcount, 1, memory_order_acq_rel) == 1)
345  buffer_pool_free(pool);
346 }
347 
348 /* allocate a new buffer and override its free() callback so that
349  * it is returned to the pool on free */
351 {
352  BufferPoolEntry *buf;
353  AVBufferRef *ret;
354 
355  av_assert0(pool->alloc || pool->alloc2);
356 
357  ret = pool->alloc2 ? pool->alloc2(pool->opaque, pool->size) :
358  pool->alloc(pool->size);
359  if (!ret)
360  return NULL;
361 
362  buf = av_mallocz(sizeof(*buf));
363  if (!buf) {
364  av_buffer_unref(&ret);
365  return NULL;
366  }
367 
368  buf->data = ret->buffer->data;
369  buf->opaque = ret->buffer->opaque;
370  buf->free = ret->buffer->free;
371  buf->pool = pool;
372 
373  ret->buffer->opaque = buf;
375 
376  return ret;
377 }
378 
380 {
381  AVBufferRef *ret;
382  BufferPoolEntry *buf;
383 
384  ff_mutex_lock(&pool->mutex);
385  buf = pool->pool;
386  if (buf) {
387  ret = av_buffer_create(buf->data, pool->size, pool_release_buffer,
388  buf, 0);
389  if (ret) {
390  pool->pool = buf->next;
391  buf->next = NULL;
392  }
393  } else {
394  ret = pool_alloc_buffer(pool);
395  }
396  ff_mutex_unlock(&pool->mutex);
397 
398  if (ret)
399  atomic_fetch_add_explicit(&pool->refcount, 1, memory_order_relaxed);
400 
401  return ret;
402 }
403 
405 {
406  BufferPoolEntry *buf = ref->buffer->opaque;
407  av_assert0(buf);
408  return buf->opaque;
409 }
uint8_t
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
static void buffer_pool_flush(AVBufferPool *pool)
Definition: buffer.c:288
static void buffer_pool_free(AVBufferPool *pool)
Definition: buffer.c:303
static void buffer_replace(AVBufferRef **dst, AVBufferRef **src)
Definition: buffer.c:107
static AVBufferRef * pool_alloc_buffer(AVBufferPool *pool)
Definition: buffer.c:350
static void pool_release_buffer(void *opaque, uint8_t *data)
Definition: buffer.c:331
#define BUFFER_FLAG_REALLOCATABLE
The buffer was av_realloc()ed, so it is reallocatable.
#define flags(name, subs,...)
Definition: cbs_av1.c:572
common internal and external API header
#define FFMIN(a, b)
Definition: common.h:105
#define CONFIG_MEMORY_POISONING
Definition: config.h:596
#define NULL
Definition: coverity.c:32
#define atomic_fetch_add_explicit(object, operand, order)
Definition: stdatomic.h:149
#define atomic_load(object)
Definition: stdatomic.h:93
#define atomic_init(obj, value)
Definition: stdatomic.h:33
#define atomic_fetch_sub_explicit(object, operand, order)
Definition: stdatomic.h:152
int av_buffer_is_writable(const AVBufferRef *buf)
Definition: buffer.c:133
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it.
Definition: buffer.c:125
AVBufferRef * av_buffer_allocz(buffer_size_t size)
Same as av_buffer_alloc(), except the returned buffer will be initialized to zero.
Definition: buffer.c:83
void av_buffer_default_free(void *opaque, uint8_t *data)
Default free callback, which calls av_free() on the buffer data.
Definition: buffer.c:62
AVBufferRef * av_buffer_create(uint8_t *data, buffer_size_t size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:29
AVBufferRef * av_buffer_alloc(buffer_size_t size)
Allocate an AVBuffer of the given size using av_malloc().
Definition: buffer.c:67
int av_buffer_replace(AVBufferRef **pdst, AVBufferRef *src)
Ensure dst refers to the same data as src.
Definition: buffer.c:219
int av_buffer_get_ref_count(const AVBufferRef *buf)
Definition: buffer.c:146
int av_buffer_make_writable(AVBufferRef **pbuf)
Create a writable reference from a given buffer reference, avoiding data copy if possible.
Definition: buffer.c:151
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:93
#define AV_BUFFER_FLAG_READONLY
Always treat the buffer as read-only, even when it has only one reference.
Definition: buffer.h:128
void * av_buffer_get_opaque(const AVBufferRef *buf)
Definition: buffer.c:141
int av_buffer_realloc(AVBufferRef **pbuf, buffer_size_t size)
Reallocate a given buffer.
Definition: buffer.c:169
AVBufferPool * av_buffer_pool_init(buffer_size_t size, AVBufferRef *(*alloc)(buffer_size_t size))
Allocate and initialize a buffer pool.
Definition: buffer.c:269
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition: buffer.c:379
AVBufferPool * av_buffer_pool_init2(buffer_size_t size, void *opaque, AVBufferRef *(*alloc)(void *opaque, buffer_size_t size), void(*pool_free)(void *opaque))
Allocate and initialize a buffer pool with a more complex allocator.
Definition: buffer.c:245
void av_buffer_pool_uninit(AVBufferPool **ppool)
Mark the pool as being available for freeing.
Definition: buffer.c:314
void * av_buffer_pool_buffer_get_opaque(AVBufferRef *ref)
Query the original opaque parameter of an allocated buffer in the pool.
Definition: buffer.c:404
#define AVERROR(e)
Definition: error.h:43
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:134
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:237
#define FF_MEMORY_POISON
Definition: internal.h:88
int buffer_size_t
Definition: internal.h:306
static int ff_mutex_unlock(AVMutex *mutex)
Definition: thread.h:169
static int ff_mutex_lock(AVMutex *mutex)
Definition: thread.h:168
static int ff_mutex_destroy(AVMutex *mutex)
Definition: thread.h:170
static int ff_mutex_init(AVMutex *mutex, const void *attr)
Definition: thread.h:167
Memory handling functions.
const char data[16]
Definition: mxf.c:142
The buffer pool.
AVBufferRef *(* alloc2)(void *opaque, buffer_size_t size)
atomic_uint refcount
BufferPoolEntry * pool
void(* pool_free)(void *opaque)
AVBufferRef *(* alloc)(buffer_size_t size)
buffer_size_t size
A reference to a data buffer.
Definition: buffer.h:84
AVBuffer * buffer
Definition: buffer.h:85
int size
Size of data in bytes.
Definition: buffer.h:97
uint8_t * data
The data buffer.
Definition: buffer.h:92
A reference counted buffer type.
void(* free)(void *opaque, uint8_t *data)
a callback for freeing the data
atomic_uint refcount
number of existing AVBufferRef instances referring to this buffer
buffer_size_t size
size of data in bytes
int flags
A combination of AV_BUFFER_FLAG_*.
uint8_t * data
data described by this buffer
int flags_internal
A combination of BUFFER_FLAG_*.
void * opaque
an opaque pointer, to be used by the freeing callback
struct BufferPoolEntry * next
AVBufferPool * pool
void(* free)(void *opaque, uint8_t *data)
#define av_free(p)
#define av_freep(p)
#define av_malloc(s)
static uint8_t tmp[11]
Definition: aes_ctr.c:27
#define src
Definition: vp8dsp.c:255
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:107
int size
const char * b
Definition: vf_curves.c:118