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
23 #include "buffer_internal.h"
27 AVBufferRef
*av_buffer_create(uint8_t *data
, int size
,
28 void (*free
)(void *opaque
, uint8_t *data
),
29 void *opaque
, int flags
)
31 AVBufferRef
*ref
= NULL
;
34 buf
= av_mallocz(sizeof(*buf
));
40 buf
->free
= free
? free
: av_buffer_default_free
;
44 if (flags
& AV_BUFFER_FLAG_READONLY
)
45 buf
->flags
|= BUFFER_FLAG_READONLY
;
47 ref
= av_mallocz(sizeof(*ref
));
60 void av_buffer_default_free(void *opaque
, uint8_t *data
)
65 AVBufferRef
*av_buffer_alloc(int size
)
67 AVBufferRef
*ret
= NULL
;
70 data
= av_malloc(size
);
74 ret
= av_buffer_create(data
, size
, av_buffer_default_free
, NULL
, 0);
81 AVBufferRef
*av_buffer_allocz(int size
)
83 AVBufferRef
*ret
= av_buffer_alloc(size
);
87 memset(ret
->data
, 0, size
);
91 AVBufferRef
*av_buffer_ref(AVBufferRef
*buf
)
93 AVBufferRef
*ret
= av_mallocz(sizeof(*ret
));
100 avpriv_atomic_int_add_and_fetch(&buf
->buffer
->refcount
, 1);
105 void av_buffer_unref(AVBufferRef
**buf
)
114 if (!avpriv_atomic_int_add_and_fetch(&b
->refcount
, -1)) {
115 b
->free(b
->opaque
, b
->data
);
120 int av_buffer_is_writable(const AVBufferRef
*buf
)
122 if (buf
->buffer
->flags
& AV_BUFFER_FLAG_READONLY
)
125 return avpriv_atomic_int_get(&buf
->buffer
->refcount
) == 1;
128 void *av_buffer_get_opaque(const AVBufferRef
*buf
)
130 return buf
->buffer
->opaque
;
133 int av_buffer_get_ref_count(const AVBufferRef
*buf
)
135 return buf
->buffer
->refcount
;
138 int av_buffer_make_writable(AVBufferRef
**pbuf
)
140 AVBufferRef
*newbuf
, *buf
= *pbuf
;
142 if (av_buffer_is_writable(buf
))
145 newbuf
= av_buffer_alloc(buf
->size
);
147 return AVERROR(ENOMEM
);
149 memcpy(newbuf
->data
, buf
->data
, buf
->size
);
150 av_buffer_unref(pbuf
);
156 int av_buffer_realloc(AVBufferRef
**pbuf
, int size
)
158 AVBufferRef
*buf
= *pbuf
;
162 /* allocate a new buffer with av_realloc(), so it will be reallocatable
164 uint8_t *data
= av_realloc(NULL
, size
);
166 return AVERROR(ENOMEM
);
168 buf
= av_buffer_create(data
, size
, av_buffer_default_free
, NULL
, 0);
171 return AVERROR(ENOMEM
);
174 buf
->buffer
->flags
|= BUFFER_FLAG_REALLOCATABLE
;
178 } else if (buf
->size
== size
)
181 if (!(buf
->buffer
->flags
& BUFFER_FLAG_REALLOCATABLE
) ||
182 !av_buffer_is_writable(buf
)) {
183 /* cannot realloc, allocate a new reallocable buffer and copy data */
184 AVBufferRef
*new = NULL
;
186 av_buffer_realloc(&new, size
);
188 return AVERROR(ENOMEM
);
190 memcpy(new->data
, buf
->data
, FFMIN(size
, buf
->size
));
192 av_buffer_unref(pbuf
);
197 tmp
= av_realloc(buf
->buffer
->data
, size
);
199 return AVERROR(ENOMEM
);
201 buf
->buffer
->data
= buf
->data
= tmp
;
202 buf
->buffer
->size
= buf
->size
= size
;
206 AVBufferPool
*av_buffer_pool_init(int size
, AVBufferRef
* (*alloc
)(int size
))
208 AVBufferPool
*pool
= av_mallocz(sizeof(*pool
));
213 pool
->alloc
= alloc
? alloc
: av_buffer_alloc
;
215 avpriv_atomic_int_set(&pool
->refcount
, 1);
221 * This function gets called when the pool has been uninited and
222 * all the buffers returned to it.
224 static void buffer_pool_free(AVBufferPool
*pool
)
227 BufferPoolEntry
*buf
= pool
->pool
;
228 pool
->pool
= buf
->next
;
230 buf
->free(buf
->opaque
, buf
->data
);
236 void av_buffer_pool_uninit(AVBufferPool
**ppool
)
240 if (!ppool
|| !*ppool
)
245 if (!avpriv_atomic_int_add_and_fetch(&pool
->refcount
, -1))
246 buffer_pool_free(pool
);
249 /* remove the whole buffer list from the pool and return it */
250 static BufferPoolEntry
*get_pool(AVBufferPool
*pool
)
252 BufferPoolEntry
*cur
= *(void * volatile *)&pool
->pool
, *last
= NULL
;
254 while (cur
!= last
) {
256 cur
= avpriv_atomic_ptr_cas((void * volatile *)&pool
->pool
, last
, NULL
);
264 static void add_to_pool(BufferPoolEntry
*buf
)
267 BufferPoolEntry
*cur
, *end
= buf
;
276 while (avpriv_atomic_ptr_cas((void * volatile *)&pool
->pool
, NULL
, buf
)) {
277 /* pool is not empty, retrieve it and append it to our list */
278 cur
= get_pool(pool
);
285 static void pool_release_buffer(void *opaque
, uint8_t *data
)
287 BufferPoolEntry
*buf
= opaque
;
288 AVBufferPool
*pool
= buf
->pool
;
290 if(CONFIG_MEMORY_POISONING
)
291 memset(buf
->data
, FF_MEMORY_POISON
, pool
->size
);
294 if (!avpriv_atomic_int_add_and_fetch(&pool
->refcount
, -1))
295 buffer_pool_free(pool
);
298 /* allocate a new buffer and override its free() callback so that
299 * it is returned to the pool on free */
300 static AVBufferRef
*pool_alloc_buffer(AVBufferPool
*pool
)
302 BufferPoolEntry
*buf
;
305 ret
= pool
->alloc(pool
->size
);
309 buf
= av_mallocz(sizeof(*buf
));
311 av_buffer_unref(&ret
);
315 buf
->data
= ret
->buffer
->data
;
316 buf
->opaque
= ret
->buffer
->opaque
;
317 buf
->free
= ret
->buffer
->free
;
320 ret
->buffer
->opaque
= buf
;
321 ret
->buffer
->free
= pool_release_buffer
;
323 avpriv_atomic_int_add_and_fetch(&pool
->refcount
, 1);
324 avpriv_atomic_int_add_and_fetch(&pool
->nb_allocated
, 1);
329 AVBufferRef
*av_buffer_pool_get(AVBufferPool
*pool
)
332 BufferPoolEntry
*buf
;
334 /* check whether the pool is empty */
335 buf
= get_pool(pool
);
336 if (!buf
&& pool
->refcount
<= pool
->nb_allocated
) {
337 av_log(NULL
, AV_LOG_DEBUG
, "Pool race dectected, spining to avoid overallocation and eventual OOM\n");
338 while (!buf
&& avpriv_atomic_int_get(&pool
->refcount
) <= avpriv_atomic_int_get(&pool
->nb_allocated
))
339 buf
= get_pool(pool
);
343 return pool_alloc_buffer(pool
);
345 /* keep the first entry, return the rest of the list to the pool */
346 add_to_pool(buf
->next
);
349 ret
= av_buffer_create(buf
->data
, pool
->size
, pool_release_buffer
,
355 avpriv_atomic_int_add_and_fetch(&pool
->refcount
, 1);