FFmpeg
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 
29 static AVBufferRef *buffer_create(AVBuffer *buf, uint8_t *data, size_t size,
30  void (*free)(void *opaque, uint8_t *data),
31  void *opaque, int flags)
32 {
33  AVBufferRef *ref = NULL;
34 
35  buf->data = data;
36  buf->size = size;
37  buf->free = free ? free : av_buffer_default_free;
38  buf->opaque = opaque;
39 
40  atomic_init(&buf->refcount, 1);
41 
42  buf->flags = flags;
43 
44  ref = av_mallocz(sizeof(*ref));
45  if (!ref)
46  return NULL;
47 
48  ref->buffer = buf;
49  ref->data = data;
50  ref->size = size;
51 
52  return ref;
53 }
54 
56  void (*free)(void *opaque, uint8_t *data),
57  void *opaque, int flags)
58 {
60  AVBuffer *buf = av_mallocz(sizeof(*buf));
61  if (!buf)
62  return NULL;
63 
64  ret = buffer_create(buf, data, size, free, opaque, flags);
65  if (!ret) {
66  av_free(buf);
67  return NULL;
68  }
69  return ret;
70 }
71 
72 void av_buffer_default_free(void *opaque, uint8_t *data)
73 {
74  av_free(data);
75 }
76 
78 {
79  AVBufferRef *ret = NULL;
80  uint8_t *data = NULL;
81 
82  data = av_malloc(size);
83  if (!data)
84  return NULL;
85 
87  if (!ret)
88  av_freep(&data);
89 
90  return ret;
91 }
92 
94 {
96  if (!ret)
97  return NULL;
98 
99  memset(ret->data, 0, size);
100  return ret;
101 }
102 
104 {
105  AVBufferRef *ret = av_mallocz(sizeof(*ret));
106 
107  if (!ret)
108  return NULL;
109 
110  *ret = *buf;
111 
112  atomic_fetch_add_explicit(&buf->buffer->refcount, 1, memory_order_relaxed);
113 
114  return ret;
115 }
116 
118 {
119  AVBuffer *b;
120 
121  b = (*dst)->buffer;
122 
123  if (src) {
124  **dst = **src;
125  av_freep(src);
126  } else
127  av_freep(dst);
128 
129  if (atomic_fetch_sub_explicit(&b->refcount, 1, memory_order_acq_rel) == 1) {
130  /* b->free below might already free the structure containing *b,
131  * so we have to read the flag now to avoid use-after-free. */
132  int free_avbuffer = !(b->flags_internal & BUFFER_FLAG_NO_FREE);
133  b->free(b->opaque, b->data);
134  if (free_avbuffer)
135  av_free(b);
136  }
137 }
138 
140 {
141  if (!buf || !*buf)
142  return;
143 
144  buffer_replace(buf, NULL);
145 }
146 
148 {
150  return 0;
151 
152  return atomic_load(&buf->buffer->refcount) == 1;
153 }
154 
156 {
157  return buf->buffer->opaque;
158 }
159 
161 {
162  return atomic_load(&buf->buffer->refcount);
163 }
164 
166 {
167  AVBufferRef *newbuf, *buf = *pbuf;
168 
169  if (av_buffer_is_writable(buf))
170  return 0;
171 
172  newbuf = av_buffer_alloc(buf->size);
173  if (!newbuf)
174  return AVERROR(ENOMEM);
175 
176  memcpy(newbuf->data, buf->data, buf->size);
177 
178  buffer_replace(pbuf, &newbuf);
179 
180  return 0;
181 }
182 
183 int av_buffer_realloc(AVBufferRef **pbuf, size_t size)
184 {
185  AVBufferRef *buf = *pbuf;
186  uint8_t *tmp;
187  int ret;
188 
189  if (!buf) {
190  /* allocate a new buffer with av_realloc(), so it will be reallocatable
191  * later */
192  uint8_t *data = av_realloc(NULL, size);
193  if (!data)
194  return AVERROR(ENOMEM);
195 
197  if (!buf) {
198  av_freep(&data);
199  return AVERROR(ENOMEM);
200  }
201 
203  *pbuf = buf;
204 
205  return 0;
206  } else if (buf->size == size)
207  return 0;
208 
210  !av_buffer_is_writable(buf) || buf->data != buf->buffer->data) {
211  /* cannot realloc, allocate a new reallocable buffer and copy data */
212  AVBufferRef *new = NULL;
213 
214  ret = av_buffer_realloc(&new, size);
215  if (ret < 0)
216  return ret;
217 
218  memcpy(new->data, buf->data, FFMIN(size, buf->size));
219 
220  buffer_replace(pbuf, &new);
221  return 0;
222  }
223 
224  tmp = av_realloc(buf->buffer->data, size);
225  if (!tmp)
226  return AVERROR(ENOMEM);
227 
228  buf->buffer->data = buf->data = tmp;
229  buf->buffer->size = buf->size = size;
230  return 0;
231 }
232 
234 {
235  AVBufferRef *dst = *pdst;
236  AVBufferRef *tmp;
237 
238  if (!src) {
239  av_buffer_unref(pdst);
240  return 0;
241  }
242 
243  if (dst && dst->buffer == src->buffer) {
244  /* make sure the data pointers match */
245  dst->data = src->data;
246  dst->size = src->size;
247  return 0;
248  }
249 
250  tmp = av_buffer_ref(src);
251  if (!tmp)
252  return AVERROR(ENOMEM);
253 
254  av_buffer_unref(pdst);
255  *pdst = tmp;
256  return 0;
257 }
258 
259 AVBufferPool *av_buffer_pool_init2(size_t size, void *opaque,
260  AVBufferRef* (*alloc)(void *opaque, size_t size),
261  void (*pool_free)(void *opaque))
262 {
263  AVBufferPool *pool = av_mallocz(sizeof(*pool));
264  if (!pool)
265  return NULL;
266 
267  if (ff_mutex_init(&pool->mutex, NULL)) {
268  av_free(pool);
269  return NULL;
270  }
271 
272  pool->size = size;
273  pool->opaque = opaque;
274  pool->alloc2 = alloc;
275  pool->alloc = av_buffer_alloc; // fallback
276  pool->pool_free = pool_free;
277 
278  atomic_init(&pool->refcount, 1);
279 
280  return pool;
281 }
282 
284 {
285  AVBufferPool *pool = av_mallocz(sizeof(*pool));
286  if (!pool)
287  return NULL;
288 
289  if (ff_mutex_init(&pool->mutex, NULL)) {
290  av_free(pool);
291  return NULL;
292  }
293 
294  pool->size = size;
295  pool->alloc = alloc ? alloc : av_buffer_alloc;
296 
297  atomic_init(&pool->refcount, 1);
298 
299  return pool;
300 }
301 
302 static void buffer_pool_flush(AVBufferPool *pool)
303 {
304  while (pool->pool) {
305  BufferPoolEntry *buf = pool->pool;
306  pool->pool = buf->next;
307 
308  buf->free(buf->opaque, buf->data);
309  av_freep(&buf);
310  }
311 }
312 
313 /*
314  * This function gets called when the pool has been uninited and
315  * all the buffers returned to it.
316  */
317 static void buffer_pool_free(AVBufferPool *pool)
318 {
319  buffer_pool_flush(pool);
320  ff_mutex_destroy(&pool->mutex);
321 
322  if (pool->pool_free)
323  pool->pool_free(pool->opaque);
324 
325  av_freep(&pool);
326 }
327 
329 {
330  AVBufferPool *pool;
331 
332  if (!ppool || !*ppool)
333  return;
334  pool = *ppool;
335  *ppool = NULL;
336 
337  ff_mutex_lock(&pool->mutex);
338  buffer_pool_flush(pool);
339  ff_mutex_unlock(&pool->mutex);
340 
341  if (atomic_fetch_sub_explicit(&pool->refcount, 1, memory_order_acq_rel) == 1)
342  buffer_pool_free(pool);
343 }
344 
345 static void pool_release_buffer(void *opaque, uint8_t *data)
346 {
347  BufferPoolEntry *buf = opaque;
348  AVBufferPool *pool = buf->pool;
349 
350  ff_mutex_lock(&pool->mutex);
351  buf->next = pool->pool;
352  pool->pool = buf;
353  ff_mutex_unlock(&pool->mutex);
354 
355  if (atomic_fetch_sub_explicit(&pool->refcount, 1, memory_order_acq_rel) == 1)
356  buffer_pool_free(pool);
357 }
358 
359 /* allocate a new buffer and override its free() callback so that
360  * it is returned to the pool on free */
362 {
363  BufferPoolEntry *buf;
364  AVBufferRef *ret;
365 
366  av_assert0(pool->alloc || pool->alloc2);
367 
368  ret = pool->alloc2 ? pool->alloc2(pool->opaque, pool->size) :
369  pool->alloc(pool->size);
370  if (!ret)
371  return NULL;
372 
373  buf = av_mallocz(sizeof(*buf));
374  if (!buf) {
376  return NULL;
377  }
378 
379  buf->data = ret->buffer->data;
380  buf->opaque = ret->buffer->opaque;
381  buf->free = ret->buffer->free;
382  buf->pool = pool;
383 
384  ret->buffer->opaque = buf;
385  ret->buffer->free = pool_release_buffer;
386 
387  return ret;
388 }
389 
391 {
392  AVBufferRef *ret;
393  BufferPoolEntry *buf;
394 
395  ff_mutex_lock(&pool->mutex);
396  buf = pool->pool;
397  if (buf) {
398  memset(&buf->buffer, 0, sizeof(buf->buffer));
399  ret = buffer_create(&buf->buffer, buf->data, pool->size,
400  pool_release_buffer, buf, 0);
401  if (ret) {
402  pool->pool = buf->next;
403  buf->next = NULL;
405  }
406  } else {
407  ret = pool_alloc_buffer(pool);
408  }
409  ff_mutex_unlock(&pool->mutex);
410 
411  if (ret)
412  atomic_fetch_add_explicit(&pool->refcount, 1, memory_order_relaxed);
413 
414  return ret;
415 }
416 
418 {
419  BufferPoolEntry *buf = ref->buffer->opaque;
420  av_assert0(buf);
421  return buf->opaque;
422 }
av_buffer_pool_init
AVBufferPool * av_buffer_pool_init(size_t size, AVBufferRef *(*alloc)(size_t size))
Allocate and initialize a buffer pool.
Definition: buffer.c:283
ff_mutex_init
static int ff_mutex_init(AVMutex *mutex, const void *attr)
Definition: thread.h:187
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
AVBufferPool::mutex
AVMutex mutex
Definition: buffer_internal.h:89
AVBufferPool
The buffer pool.
Definition: buffer_internal.h:88
thread.h
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
buffer_internal.h
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:28
b
#define b
Definition: input.c:41
data
const char data[16]
Definition: mxf.c:149
pool_free
static void pool_free(FFRefStructPool *pool)
Definition: refstruct.c:208
av_buffer_ref
AVBufferRef * av_buffer_ref(const AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:103
AVBufferPool::size
size_t size
Definition: buffer_internal.h:103
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:30
BUFFER_FLAG_REALLOCATABLE
#define BUFFER_FLAG_REALLOCATABLE
The buffer was av_realloc()ed, so it is reallocatable.
Definition: buffer_internal.h:31
ff_mutex_unlock
static int ff_mutex_unlock(AVMutex *mutex)
Definition: thread.h:189
BufferPoolEntry::data
uint8_t * data
Definition: buffer_internal.h:69
AVBufferPool::refcount
atomic_uint refcount
Definition: buffer_internal.h:101
AVBuffer::flags
int flags
A combination of AV_BUFFER_FLAG_*.
Definition: buffer_internal.h:60
av_buffer_pool_init2
AVBufferPool * av_buffer_pool_init2(size_t size, void *opaque, AVBufferRef *(*alloc)(void *opaque, size_t size), void(*pool_free)(void *opaque))
Allocate and initialize a buffer pool with a more complex allocator.
Definition: buffer.c:259
avassert.h
AVBufferPool::opaque
void * opaque
Definition: buffer_internal.h:104
av_buffer_pool_get
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition: buffer.c:390
buffer_replace
static void buffer_replace(AVBufferRef **dst, AVBufferRef **src)
Definition: buffer.c:117
AV_BUFFER_FLAG_READONLY
#define AV_BUFFER_FLAG_READONLY
Always treat the buffer as read-only, even when it has only one reference.
Definition: buffer.h:114
BufferPoolEntry::pool
AVBufferPool * pool
Definition: buffer_internal.h:78
pool_release_buffer
static void pool_release_buffer(void *opaque, uint8_t *data)
Definition: buffer.c:345
av_buffer_default_free
void av_buffer_default_free(void *opaque, uint8_t *data)
Default free callback, which calls av_free() on the buffer data.
Definition: buffer.c:72
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:40
AVBuffer::free
void(* free)(void *opaque, uint8_t *data)
a callback for freeing the data
Definition: buffer_internal.h:50
BufferPoolEntry::buffer
AVBuffer buffer
Definition: buffer_internal.h:85
AVBuffer::size
size_t size
size of data in bytes
Definition: buffer_internal.h:40
atomic_load
#define atomic_load(object)
Definition: stdatomic.h:93
BUFFER_FLAG_NO_FREE
#define BUFFER_FLAG_NO_FREE
The AVBuffer structure is part of a larger structure and should not be freed.
Definition: buffer_internal.h:36
AVBuffer::flags_internal
int flags_internal
A combination of BUFFER_FLAG_*.
Definition: buffer_internal.h:65
buffer_pool_free
static void buffer_pool_free(AVBufferPool *pool)
Definition: buffer.c:317
AVBuffer::opaque
void * opaque
an opaque pointer, to be used by the freeing callback
Definition: buffer_internal.h:55
NULL
#define NULL
Definition: coverity.c:32
AVBufferPool::pool_free
void(* pool_free)(void *opaque)
Definition: buffer_internal.h:107
av_buffer_unref
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:139
AVBuffer::data
uint8_t * data
data described by this buffer
Definition: buffer_internal.h:39
av_buffer_pool_uninit
void av_buffer_pool_uninit(AVBufferPool **ppool)
Mark the pool as being available for freeing.
Definition: buffer.c:328
BufferPoolEntry::free
void(* free)(void *opaque, uint8_t *data)
Definition: buffer_internal.h:76
pool_alloc_buffer
static AVBufferRef * pool_alloc_buffer(AVBufferPool *pool)
Definition: buffer.c:361
buffer_create
static AVBufferRef * buffer_create(AVBuffer *buf, uint8_t *data, size_t size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Definition: buffer.c:29
atomic_fetch_sub_explicit
#define atomic_fetch_sub_explicit(object, operand, order)
Definition: stdatomic.h:152
av_buffer_create
AVBufferRef * av_buffer_create(uint8_t *data, size_t size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:55
ff_mutex_destroy
static int ff_mutex_destroy(AVMutex *mutex)
Definition: thread.h:190
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:83
BufferPoolEntry
Definition: buffer_internal.h:68
size
int size
Definition: twinvq_data.h:10344
atomic_fetch_add_explicit
#define atomic_fetch_add_explicit(object, operand, order)
Definition: stdatomic.h:149
AVBufferPool::alloc
AVBufferRef *(* alloc)(size_t size)
Definition: buffer_internal.h:105
av_buffer_make_writable
int av_buffer_make_writable(AVBufferRef **pbuf)
Create a writable reference from a given buffer reference, avoiding data copy if possible.
Definition: buffer.c:165
av_buffer_get_ref_count
int av_buffer_get_ref_count(const AVBufferRef *buf)
Definition: buffer.c:160
ff_mutex_lock
static int ff_mutex_lock(AVMutex *mutex)
Definition: thread.h:188
AVBufferRef::buffer
AVBuffer * buffer
Definition: buffer.h:83
av_buffer_pool_buffer_get_opaque
void * av_buffer_pool_buffer_get_opaque(const AVBufferRef *ref)
Query the original opaque parameter of an allocated buffer in the pool.
Definition: buffer.c:417
av_buffer_alloc
AVBufferRef * av_buffer_alloc(size_t size)
Allocate an AVBuffer of the given size using av_malloc().
Definition: buffer.c:77
AVBufferRef::size
size_t size
Size of data in bytes.
Definition: buffer.h:94
BufferPoolEntry::opaque
void * opaque
Definition: buffer_internal.h:75
AVBuffer
A reference counted buffer type.
Definition: buffer_internal.h:38
AVBufferPool::pool
BufferPoolEntry * pool
Definition: buffer_internal.h:90
common.h
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:256
av_buffer_replace
int av_buffer_replace(AVBufferRef **pdst, const AVBufferRef *src)
Ensure dst refers to the same data as src.
Definition: buffer.c:233
BufferPoolEntry::next
struct BufferPoolEntry * next
Definition: buffer_internal.h:79
av_buffer_is_writable
int av_buffer_is_writable(const AVBufferRef *buf)
Definition: buffer.c:147
av_buffer_allocz
AVBufferRef * av_buffer_allocz(size_t size)
Same as av_buffer_alloc(), except the returned buffer will be initialized to zero.
Definition: buffer.c:93
ret
ret
Definition: filter_design.txt:187
buffer_pool_flush
static void buffer_pool_flush(AVBufferPool *pool)
Definition: buffer.c:302
ref
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:112
av_buffer_realloc
int av_buffer_realloc(AVBufferRef **pbuf, size_t size)
Reallocate a given buffer.
Definition: buffer.c:183
av_buffer_get_opaque
void * av_buffer_get_opaque(const AVBufferRef *buf)
Definition: buffer.c:155
mem.h
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
AVBufferPool::alloc2
AVBufferRef *(* alloc2)(void *opaque, size_t size)
Definition: buffer_internal.h:106
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:482
atomic_init
#define atomic_init(obj, value)
Definition: stdatomic.h:33
AVBuffer::refcount
atomic_uint refcount
number of existing AVBufferRef instances referring to this buffer
Definition: buffer_internal.h:45
src
#define src
Definition: vp8dsp.c:248
av_realloc
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:155