FFmpeg
Loading...
Searching...
No Matches
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 "sanitizer.h"
28#include "thread.h"
29
30static AVBufferRef *buffer_create(AVBuffer *buf, uint8_t *data, size_t size,
31 void (*free)(void *opaque, uint8_t *data),
32 void *opaque, int flags)
33{
35
36 buf->data = data;
37 buf->size = size;
38 buf->free = free ? free : av_buffer_default_free;
39 buf->opaque = opaque;
40
41 atomic_init(&buf->refcount, 1);
42
43 buf->flags = flags;
44
45 ref = av_mallocz(sizeof(*ref));
46 if (!ref)
47 return NULL;
48
49 ref->buffer = buf;
50 ref->data = data;
51 ref->size = size;
52
53 return ref;
54}
55
57 void (*free)(void *opaque, uint8_t *data),
58 void *opaque, int flags)
59{
60 AVBufferRef *ret;
61 AVBuffer *buf = av_mallocz(sizeof(*buf));
62 if (!buf)
63 return NULL;
64
65 ret = buffer_create(buf, data, size, free, opaque, flags);
66 if (!ret) {
67 av_free(buf);
68 return NULL;
69 }
70 return ret;
71}
72
73void av_buffer_default_free(void *opaque, uint8_t *data)
74{
76}
77
79{
80 AVBufferRef *ret = NULL;
81 uint8_t *data = NULL;
82
84 if (!data)
85 return NULL;
86
88 if (!ret)
89 av_freep(&data);
90
91 return ret;
92}
93
95{
97 if (!ret)
98 return NULL;
99
100 memset(ret->data, 0, size);
101 return ret;
102}
103
105{
106 AVBufferRef *ret = av_mallocz(sizeof(*ret));
107
108 if (!ret)
109 return NULL;
110
111 *ret = *buf;
112
114
115 return ret;
116}
117
119{
120 AVBuffer *b;
121
122 b = (*dst)->buffer;
123
124 if (src) {
125 **dst = **src;
126 av_freep(src);
127 } else
128 av_freep(dst);
129
130 if (atomic_fetch_sub_explicit(&b->refcount, 1, memory_order_acq_rel) == 1) {
131 /* b->free below might already free the structure containing *b,
132 * so we have to read the flag now to avoid use-after-free. */
133 int free_avbuffer = !(b->flags_internal & BUFFER_FLAG_NO_FREE);
134 b->free(b->opaque, b->data);
135 if (free_avbuffer)
136 av_free(b);
137 }
138}
139
141{
142 if (!buf || !*buf)
143 return;
144
145 buffer_replace(buf, NULL);
146}
147
149{
151 return 0;
152
153 return atomic_load(&buf->buffer->refcount) == 1;
154}
155
157{
158 return buf->buffer->opaque;
159}
160
162{
163 return atomic_load(&buf->buffer->refcount);
164}
165
167{
168 AVBufferRef *newbuf, *buf = *pbuf;
169
170 if (av_buffer_is_writable(buf))
171 return 0;
172
173 newbuf = av_buffer_alloc(buf->size);
174 if (!newbuf)
175 return AVERROR(ENOMEM);
176
177 memcpy(newbuf->data, buf->data, buf->size);
178
179 buffer_replace(pbuf, &newbuf);
180
181 return 0;
182}
183
185{
186 AVBufferRef *buf = *pbuf;
187 uint8_t *tmp;
188 int ret;
189
190 if (!buf) {
191 /* allocate a new buffer with av_realloc(), so it will be reallocatable
192 * later */
193 uint8_t *data = av_realloc(NULL, size);
194 if (!data)
195 return AVERROR(ENOMEM);
196
198 if (!buf) {
199 av_freep(&data);
200 return AVERROR(ENOMEM);
201 }
202
204 *pbuf = buf;
205
206 return 0;
207 } else if (buf->size == size)
208 return 0;
209
211 !av_buffer_is_writable(buf) || buf->data != buf->buffer->data) {
212 /* cannot realloc, allocate a new reallocable buffer and copy data */
213 AVBufferRef *new = NULL;
214
215 ret = av_buffer_realloc(&new, size);
216 if (ret < 0)
217 return ret;
218
219 memcpy(new->data, buf->data, FFMIN(size, buf->size));
220
221 buffer_replace(pbuf, &new);
222 return 0;
223 }
224
225 tmp = av_realloc(buf->buffer->data, size);
226 if (!tmp)
227 return AVERROR(ENOMEM);
228
229 buf->buffer->data = buf->data = tmp;
230 buf->buffer->size = buf->size = size;
231 return 0;
232}
233
235{
236 AVBufferRef *dst = *pdst;
238
239 if (!src) {
240 av_buffer_unref(pdst);
241 return 0;
242 }
243
244 if (dst && dst->buffer == src->buffer) {
245 /* make sure the data pointers match */
246 dst->data = src->data;
247 dst->size = src->size;
248 return 0;
249 }
250
252 if (!tmp)
253 return AVERROR(ENOMEM);
254
255 av_buffer_unref(pdst);
256 *pdst = tmp;
257 return 0;
258}
259
261 AVBufferRef* (*alloc)(void *opaque, size_t size),
262 void (*pool_free)(void *opaque))
263{
264 AVBufferPool *pool = av_mallocz(sizeof(*pool));
265 if (!pool)
266 return NULL;
267
268 if (ff_mutex_init(&pool->mutex, NULL)) {
269 av_free(pool);
270 return NULL;
271 }
272
273 pool->size = size;
274 pool->opaque = opaque;
275 pool->alloc2 = alloc;
276 pool->alloc = av_buffer_alloc; // fallback
277 pool->pool_free = pool_free;
278
279 atomic_init(&pool->refcount, 1);
280
281 return pool;
282}
283
285{
286 AVBufferPool *pool = av_mallocz(sizeof(*pool));
287 if (!pool)
288 return NULL;
289
290 if (ff_mutex_init(&pool->mutex, NULL)) {
291 av_free(pool);
292 return NULL;
293 }
294
295 pool->size = size;
296 pool->alloc = alloc ? alloc : av_buffer_alloc;
297
298 atomic_init(&pool->refcount, 1);
299
300 return pool;
301}
302
304{
305 while (pool->pool) {
306 BufferPoolEntry *buf = pool->pool;
307 pool->pool = buf->next;
308
309 if (buf->free == av_buffer_default_free)
310 FF_ASAN_UNPOISON(buf->data, pool->size);
311 buf->free(buf->opaque, buf->data);
312 av_freep(&buf);
313 }
314}
315
316/*
317 * This function gets called when the pool has been uninited and
318 * all the buffers returned to it.
319 */
321{
322 buffer_pool_flush(pool);
323 ff_mutex_destroy(&pool->mutex);
324
325 if (pool->pool_free)
326 pool->pool_free(pool->opaque);
327
328 av_freep(&pool);
329}
330
332{
333 AVBufferPool *pool;
334
335 if (!ppool || !*ppool)
336 return;
337 pool = *ppool;
338 *ppool = NULL;
339
340 ff_mutex_lock(&pool->mutex);
341 buffer_pool_flush(pool);
342 ff_mutex_unlock(&pool->mutex);
343
345 buffer_pool_free(pool);
346}
347
348static void pool_release_buffer(void *opaque, uint8_t *data)
349{
350 BufferPoolEntry *buf = opaque;
351 AVBufferPool *pool = buf->pool;
352
353 if (buf->free == av_buffer_default_free)
354 FF_ASAN_POISON(buf->data, pool->size);
355
356 ff_mutex_lock(&pool->mutex);
357 buf->next = pool->pool;
358 pool->pool = buf;
359 ff_mutex_unlock(&pool->mutex);
360
362 buffer_pool_free(pool);
363}
364
365/* allocate a new buffer and override its free() callback so that
366 * it is returned to the pool on free */
368{
369 BufferPoolEntry *buf;
370 AVBufferRef *ret;
371
372 av_assert0(pool->alloc || pool->alloc2);
373
374 ret = pool->alloc2 ? pool->alloc2(pool->opaque, pool->size) :
375 pool->alloc(pool->size);
376 if (!ret)
377 return NULL;
378
379 buf = av_mallocz(sizeof(*buf));
380 if (!buf) {
381 av_buffer_unref(&ret);
382 return NULL;
383 }
384
385 buf->data = ret->buffer->data;
386 buf->opaque = ret->buffer->opaque;
387 buf->free = ret->buffer->free;
388 buf->pool = pool;
389
390 ret->buffer->opaque = buf;
392
393 return ret;
394}
395
397{
398 AVBufferRef *ret;
399 BufferPoolEntry *buf;
400
401 ff_mutex_lock(&pool->mutex);
402 buf = pool->pool;
403 if (buf) {
404 memset(&buf->buffer, 0, sizeof(buf->buffer));
405 ret = buffer_create(&buf->buffer, buf->data, pool->size,
406 pool_release_buffer, buf, 0);
407 if (ret) {
408 pool->pool = buf->next;
409 buf->next = NULL;
411 if (buf->free == av_buffer_default_free) {
412 FF_ASAN_UNPOISON(buf->data, pool->size);
413 /* A pool that zeroes its buffers may be relied upon for never
414 * written regions staying zero, so only mark a reused buffer
415 * undefined when nothing was ever promised about its contents. */
416 if (!pool->alloc2 && pool->alloc == av_buffer_alloc)
417 FF_MEM_UNDEFINED(buf->data, pool->size);
418 }
419 }
420 } else {
421 ret = pool_alloc_buffer(pool);
422 }
423 ff_mutex_unlock(&pool->mutex);
424
425 if (ret)
427
428 return ret;
429}
430
432{
433 BufferPoolEntry *buf = ref->buffer->opaque;
434 av_assert0(buf);
435 return buf->opaque;
436}
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
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:42
static void buffer_pool_flush(AVBufferPool *pool)
Definition buffer.c:303
static void buffer_pool_free(AVBufferPool *pool)
Definition buffer.c:320
static void buffer_replace(AVBufferRef **dst, AVBufferRef **src)
Definition buffer.c:118
static void pool_release_buffer(void *opaque, uint8_t *data)
Definition buffer.c:348
static AVBufferRef * pool_alloc_buffer(AVBufferPool *pool)
Definition buffer.c:367
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:30
#define BUFFER_FLAG_NO_FREE
The AVBuffer structure is part of a larger structure and should not be freed.
#define BUFFER_FLAG_REALLOCATABLE
The buffer was av_realloc()ed, so it is reallocatable.
#define flags(name, subs,...)
Definition cbs_h264.c:74
common internal and external API header
#define NULL
Definition coverity.c:32
int av_buffer_is_writable(const AVBufferRef *buf)
Definition buffer.c:148
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:140
int av_buffer_realloc(AVBufferRef **pbuf, size_t size)
Reallocate a given buffer.
Definition buffer.c:184
void av_buffer_default_free(void *opaque, uint8_t *data)
Default free callback, which calls av_free() on the buffer data.
Definition buffer.c:73
AVBufferRef * av_buffer_allocz(size_t size)
Same as av_buffer_alloc(), except the returned buffer will be initialized to zero.
Definition buffer.c:94
int av_buffer_get_ref_count(const AVBufferRef *buf)
Definition buffer.c:161
int av_buffer_replace(AVBufferRef **pdst, const AVBufferRef *src)
Ensure dst refers to the same data as src.
Definition buffer.c:234
AVBufferRef * av_buffer_ref(const AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition buffer.c:104
int av_buffer_make_writable(AVBufferRef **pbuf)
Create a writable reference from a given buffer reference, avoiding data copy if possible.
Definition buffer.c:166
void * av_buffer_get_opaque(const AVBufferRef *buf)
Definition buffer.c:156
#define AV_BUFFER_FLAG_READONLY
Always treat the buffer as read-only, even when it has only one reference.
Definition buffer.h:114
AVBufferRef * av_buffer_alloc(size_t size)
Allocate an AVBuffer of the given size using av_malloc().
Definition buffer.c:78
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:56
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:431
void av_buffer_pool_uninit(AVBufferPool **ppool)
Mark the pool as being available for freeing.
Definition buffer.c:331
AVBufferPool * av_buffer_pool_init(size_t size, AVBufferRef *(*alloc)(size_t size))
Allocate and initialize a buffer pool.
Definition buffer.c:284
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition buffer.c:396
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:260
#define AVERROR(e)
Definition error.h:45
#define b
Definition input.c:43
static int ff_mutex_unlock(AVMutex *mutex)
Definition thread.h:189
static int ff_mutex_lock(AVMutex *mutex)
Definition thread.h:188
static int ff_mutex_destroy(AVMutex *mutex)
Definition thread.h:190
static int ff_mutex_init(AVMutex *mutex, const void *attr)
Definition thread.h:187
#define FFMIN(a, b)
Definition macros.h:49
Memory handling functions.
const char data[16]
Definition mxf.c:149
#define av_realloc(p, s)
Definition ops_static.c:54
#define av_malloc(s)
Definition ops_static.c:52
static void pool_free(AVRefStructPool *pool)
Definition refstruct.c:209
#define FF_ASAN_POISON(ptr, size)
Definition sanitizer.h:55
#define FF_MEM_UNDEFINED(ptr, size)
Definition sanitizer.h:67
#define FF_ASAN_UNPOISON(ptr, size)
Definition sanitizer.h:56
@ memory_order_relaxed
Definition stdatomic.h:29
@ memory_order_acq_rel
Definition stdatomic.h:33
#define atomic_fetch_add_explicit(object, operand, order)
Definition stdatomic.h:297
#define atomic_load(object)
Definition stdatomic.h:250
#define atomic_init(obj, value)
Definition stdatomic.h:119
#define atomic_fetch_sub_explicit(object, operand, order)
Definition stdatomic.h:300
The buffer pool.
atomic_uint refcount
BufferPoolEntry * pool
void(* pool_free)(void *opaque)
AVBufferRef *(* alloc2)(void *opaque, size_t size)
AVBufferRef *(* alloc)(size_t size)
A reference to a data buffer.
Definition buffer.h:82
AVBuffer * buffer
Definition buffer.h:83
uint8_t * data
The data buffer.
Definition buffer.h:90
size_t size
Size of data in bytes.
Definition buffer.h:94
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
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_mallocz(s)
#define av_freep(p)
static uint8_t tmp[40]
Definition aes_ctr.c:52
#define src
Definition vp8dsp.c:248
static int ref[MAX_W *MAX_W]
int size