2 * This file is part of FFmpeg.
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.
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.
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
19 #include <stdatomic.h>
24 #include "buffer_internal.h"
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
)
33 AVBufferRef
*ref
= NULL
;
37 buf
->free
= free
? free
: av_buffer_default_free
;
40 atomic_init(&buf
->refcount
, 1);
44 ref
= av_mallocz(sizeof(*ref
));
55 AVBufferRef
*av_buffer_create(uint8_t *data
, size_t size
,
56 void (*free
)(void *opaque
, uint8_t *data
),
57 void *opaque
, int flags
)
60 AVBuffer
*buf
= av_mallocz(sizeof(*buf
));
64 ret
= buffer_create(buf
, data
, size
, free
, opaque
, flags
);
72 void av_buffer_default_free(void *opaque
, uint8_t *data
)
77 AVBufferRef
*av_buffer_alloc(size_t size
)
79 AVBufferRef
*ret
= NULL
;
82 data
= av_malloc(size
);
86 ret
= av_buffer_create(data
, size
, av_buffer_default_free
, NULL
, 0);
93 AVBufferRef
*av_buffer_allocz(size_t size
)
95 AVBufferRef
*ret
= av_buffer_alloc(size
);
99 memset(ret
->data
, 0, size
);
103 AVBufferRef
*av_buffer_ref(const AVBufferRef
*buf
)
105 AVBufferRef
*ret
= av_mallocz(sizeof(*ret
));
112 atomic_fetch_add_explicit(&buf
->buffer
->refcount
, 1, memory_order_relaxed
);
117 static void buffer_replace(AVBufferRef
**dst
, AVBufferRef
**src
)
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
);
139 void av_buffer_unref(AVBufferRef
**buf
)
144 buffer_replace(buf
, NULL
);
147 int av_buffer_is_writable(const AVBufferRef
*buf
)
149 if (buf
->buffer
->flags
& AV_BUFFER_FLAG_READONLY
)
152 return atomic_load(&buf
->buffer
->refcount
) == 1;
155 void *av_buffer_get_opaque(const AVBufferRef
*buf
)
157 return buf
->buffer
->opaque
;
160 int av_buffer_get_ref_count(const AVBufferRef
*buf
)
162 return atomic_load(&buf
->buffer
->refcount
);
165 int av_buffer_make_writable(AVBufferRef
**pbuf
)
167 AVBufferRef
*newbuf
, *buf
= *pbuf
;
169 if (av_buffer_is_writable(buf
))
172 newbuf
= av_buffer_alloc(buf
->size
);
174 return AVERROR(ENOMEM
);
176 memcpy(newbuf
->data
, buf
->data
, buf
->size
);
178 buffer_replace(pbuf
, &newbuf
);
183 int av_buffer_realloc(AVBufferRef
**pbuf
, size_t size
)
185 AVBufferRef
*buf
= *pbuf
;
190 /* allocate a new buffer with av_realloc(), so it will be reallocatable
192 uint8_t *data
= av_realloc(NULL
, size
);
194 return AVERROR(ENOMEM
);
196 buf
= av_buffer_create(data
, size
, av_buffer_default_free
, NULL
, 0);
199 return AVERROR(ENOMEM
);
202 buf
->buffer
->flags_internal
|= BUFFER_FLAG_REALLOCATABLE
;
206 } else if (buf
->size
== size
)
209 if (!(buf
->buffer
->flags_internal
& BUFFER_FLAG_REALLOCATABLE
) ||
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
;
214 ret
= av_buffer_realloc(&new, size
);
218 memcpy(new->data
, buf
->data
, FFMIN(size
, buf
->size
));
220 buffer_replace(pbuf
, &new);
224 tmp
= av_realloc(buf
->buffer
->data
, size
);
226 return AVERROR(ENOMEM
);
228 buf
->buffer
->data
= buf
->data
= tmp
;
229 buf
->buffer
->size
= buf
->size
= size
;
233 int av_buffer_replace(AVBufferRef
**pdst
, const AVBufferRef
*src
)
235 AVBufferRef
*dst
= *pdst
;
239 av_buffer_unref(pdst
);
243 if (dst
&& dst
->buffer
== src
->buffer
) {
244 /* make sure the data pointers match */
245 dst
->data
= src
->data
;
246 dst
->size
= src
->size
;
250 tmp
= av_buffer_ref(src
);
252 return AVERROR(ENOMEM
);
254 av_buffer_unref(pdst
);
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
))
263 AVBufferPool
*pool
= av_mallocz(sizeof(*pool
));
267 if (ff_mutex_init(&pool
->mutex
, NULL
)) {
273 pool
->opaque
= opaque
;
274 pool
->alloc2
= alloc
;
275 pool
->alloc
= av_buffer_alloc
; // fallback
276 pool
->pool_free
= pool_free
;
278 atomic_init(&pool
->refcount
, 1);
283 AVBufferPool
*av_buffer_pool_init(size_t size
, AVBufferRef
* (*alloc
)(size_t size
))
285 AVBufferPool
*pool
= av_mallocz(sizeof(*pool
));
289 if (ff_mutex_init(&pool
->mutex
, NULL
)) {
295 pool
->alloc
= alloc
? alloc
: av_buffer_alloc
;
297 atomic_init(&pool
->refcount
, 1);
302 static void buffer_pool_flush(AVBufferPool
*pool
)
305 BufferPoolEntry
*buf
= pool
->pool
;
306 pool
->pool
= buf
->next
;
308 buf
->free(buf
->opaque
, buf
->data
);
314 * This function gets called when the pool has been uninited and
315 * all the buffers returned to it.
317 static void buffer_pool_free(AVBufferPool
*pool
)
319 buffer_pool_flush(pool
);
320 ff_mutex_destroy(&pool
->mutex
);
323 pool
->pool_free(pool
->opaque
);
328 void av_buffer_pool_uninit(AVBufferPool
**ppool
)
332 if (!ppool
|| !*ppool
)
337 ff_mutex_lock(&pool
->mutex
);
338 buffer_pool_flush(pool
);
339 ff_mutex_unlock(&pool
->mutex
);
341 if (atomic_fetch_sub_explicit(&pool
->refcount
, 1, memory_order_acq_rel
) == 1)
342 buffer_pool_free(pool
);
345 static void pool_release_buffer(void *opaque
, uint8_t *data
)
347 BufferPoolEntry
*buf
= opaque
;
348 AVBufferPool
*pool
= buf
->pool
;
350 if(CONFIG_MEMORY_POISONING
)
351 memset(buf
->data
, FF_MEMORY_POISON
, pool
->size
);
353 ff_mutex_lock(&pool
->mutex
);
354 buf
->next
= pool
->pool
;
356 ff_mutex_unlock(&pool
->mutex
);
358 if (atomic_fetch_sub_explicit(&pool
->refcount
, 1, memory_order_acq_rel
) == 1)
359 buffer_pool_free(pool
);
362 /* allocate a new buffer and override its free() callback so that
363 * it is returned to the pool on free */
364 static AVBufferRef
*pool_alloc_buffer(AVBufferPool
*pool
)
366 BufferPoolEntry
*buf
;
369 av_assert0(pool
->alloc
|| pool
->alloc2
);
371 ret
= pool
->alloc2
? pool
->alloc2(pool
->opaque
, pool
->size
) :
372 pool
->alloc(pool
->size
);
376 buf
= av_mallocz(sizeof(*buf
));
378 av_buffer_unref(&ret
);
382 buf
->data
= ret
->buffer
->data
;
383 buf
->opaque
= ret
->buffer
->opaque
;
384 buf
->free
= ret
->buffer
->free
;
387 ret
->buffer
->opaque
= buf
;
388 ret
->buffer
->free
= pool_release_buffer
;
393 AVBufferRef
*av_buffer_pool_get(AVBufferPool
*pool
)
396 BufferPoolEntry
*buf
;
398 ff_mutex_lock(&pool
->mutex
);
401 memset(&buf
->buffer
, 0, sizeof(buf
->buffer
));
402 ret
= buffer_create(&buf
->buffer
, buf
->data
, pool
->size
,
403 pool_release_buffer
, buf
, 0);
405 pool
->pool
= buf
->next
;
407 buf
->buffer
.flags_internal
|= BUFFER_FLAG_NO_FREE
;
410 ret
= pool_alloc_buffer(pool
);
412 ff_mutex_unlock(&pool
->mutex
);
415 atomic_fetch_add_explicit(&pool
->refcount
, 1, memory_order_relaxed
);
420 void *av_buffer_pool_buffer_get_opaque(const AVBufferRef
*ref
)
422 BufferPoolEntry
*buf
= ref
->buffer
->opaque
;