Libav
buffer.c
Go to the documentation of this file.
1 /*
2  * This file is part of Libav.
3  *
4  * Libav 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  * Libav 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 Libav; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include <stdint.h>
20 #include <string.h>
21 
22 #include "atomic.h"
23 #include "buffer_internal.h"
24 #include "common.h"
25 #include "mem.h"
26 
28  void (*free)(void *opaque, uint8_t *data),
29  void *opaque, int flags)
30 {
31  AVBufferRef *ref = NULL;
32  AVBuffer *buf = NULL;
33 
34  buf = av_mallocz(sizeof(*buf));
35  if (!buf)
36  return NULL;
37 
38  buf->data = data;
39  buf->size = size;
40  buf->free = free ? free : av_buffer_default_free;
41  buf->opaque = opaque;
42  buf->refcount = 1;
43 
44  if (flags & AV_BUFFER_FLAG_READONLY)
46 
47  ref = av_mallocz(sizeof(*ref));
48  if (!ref) {
49  av_freep(&buf);
50  return NULL;
51  }
52 
53  ref->buffer = buf;
54  ref->data = data;
55  ref->size = size;
56 
57  return ref;
58 }
59 
60 void av_buffer_default_free(void *opaque, uint8_t *data)
61 {
62  av_free(data);
63 }
64 
66 {
67  AVBufferRef *ret = NULL;
68  uint8_t *data = NULL;
69 
70  data = av_malloc(size);
71  if (!data)
72  return NULL;
73 
74  ret = av_buffer_create(data, size, av_buffer_default_free, NULL, 0);
75  if (!ret)
76  av_freep(&data);
77 
78  return ret;
79 }
80 
82 {
83  AVBufferRef *ret = av_buffer_alloc(size);
84  if (!ret)
85  return NULL;
86 
87  memset(ret->data, 0, size);
88  return ret;
89 }
90 
92 {
93  AVBufferRef *ret = av_mallocz(sizeof(*ret));
94 
95  if (!ret)
96  return NULL;
97 
98  *ret = *buf;
99 
101 
102  return ret;
103 }
104 
106 {
107  AVBuffer *b;
108 
109  if (!buf || !*buf)
110  return;
111  b = (*buf)->buffer;
112  av_freep(buf);
113 
115  b->free(b->opaque, b->data);
116  av_freep(&b);
117  }
118 }
119 
121 {
123  return 0;
124 
125  return avpriv_atomic_int_add_and_fetch(&buf->buffer->refcount, 0) == 1;
126 }
127 
129 {
130  AVBufferRef *newbuf, *buf = *pbuf;
131 
132  if (av_buffer_is_writable(buf))
133  return 0;
134 
135  newbuf = av_buffer_alloc(buf->size);
136  if (!newbuf)
137  return AVERROR(ENOMEM);
138 
139  memcpy(newbuf->data, buf->data, buf->size);
140  av_buffer_unref(pbuf);
141  *pbuf = newbuf;
142 
143  return 0;
144 }
145 
146 int av_buffer_realloc(AVBufferRef **pbuf, int size)
147 {
148  AVBufferRef *buf = *pbuf;
149  uint8_t *tmp;
150 
151  if (!buf) {
152  /* allocate a new buffer with av_realloc(), so it will be reallocatable
153  * later */
154  uint8_t *data = av_realloc(NULL, size);
155  if (!data)
156  return AVERROR(ENOMEM);
157 
158  buf = av_buffer_create(data, size, av_buffer_default_free, NULL, 0);
159  if (!buf) {
160  av_freep(&data);
161  return AVERROR(ENOMEM);
162  }
163 
165  *pbuf = buf;
166 
167  return 0;
168  } else if (buf->size == size)
169  return 0;
170 
171  if (!(buf->buffer->flags & BUFFER_FLAG_REALLOCATABLE) ||
172  !av_buffer_is_writable(buf)) {
173  /* cannot realloc, allocate a new reallocable buffer and copy data */
174  AVBufferRef *new = NULL;
175 
176  av_buffer_realloc(&new, size);
177  if (!new)
178  return AVERROR(ENOMEM);
179 
180  memcpy(new->data, buf->data, FFMIN(size, buf->size));
181 
182  av_buffer_unref(pbuf);
183  *pbuf = new;
184  return 0;
185  }
186 
187  tmp = av_realloc(buf->buffer->data, size);
188  if (!tmp)
189  return AVERROR(ENOMEM);
190 
191  buf->buffer->data = buf->data = tmp;
192  buf->buffer->size = buf->size = size;
193  return 0;
194 }
195 
196 AVBufferPool *av_buffer_pool_init(int size, AVBufferRef* (*alloc)(int size))
197 {
198  AVBufferPool *pool = av_mallocz(sizeof(*pool));
199  if (!pool)
200  return NULL;
201 
202  pool->size = size;
203  pool->alloc = alloc ? alloc : av_buffer_alloc;
204 
205  avpriv_atomic_int_set(&pool->refcount, 1);
206 
207  return pool;
208 }
209 
210 /*
211  * This function gets called when the pool has been uninited and
212  * all the buffers returned to it.
213  */
214 static void buffer_pool_free(AVBufferPool *pool)
215 {
216  while (pool->pool) {
217  BufferPoolEntry *buf = pool->pool;
218  pool->pool = buf->next;
219 
220  buf->free(buf->opaque, buf->data);
221  av_freep(&buf);
222  }
223  av_freep(&pool);
224 }
225 
227 {
228  AVBufferPool *pool;
229 
230  if (!ppool || !*ppool)
231  return;
232  pool = *ppool;
233  *ppool = NULL;
234 
235  if (!avpriv_atomic_int_add_and_fetch(&pool->refcount, -1))
236  buffer_pool_free(pool);
237 }
238 
239 /* remove the whole buffer list from the pool and return it */
241 {
242  BufferPoolEntry *cur = NULL, *last = NULL;
243 
244  do {
245  FFSWAP(BufferPoolEntry*, cur, last);
246  cur = avpriv_atomic_ptr_cas((void * volatile *)&pool->pool, last, NULL);
247  if (!cur)
248  return NULL;
249  } while (cur != last);
250 
251  return cur;
252 }
253 
254 static void add_to_pool(BufferPoolEntry *buf)
255 {
256  AVBufferPool *pool;
257  BufferPoolEntry *cur, *end = buf;
258 
259  if (!buf)
260  return;
261  pool = buf->pool;
262 
263  while (end->next)
264  end = end->next;
265 
266  while ((cur = avpriv_atomic_ptr_cas((void * volatile *)&pool->pool, NULL, buf))) {
267  /* pool is not empty, retrieve it and append it to our list */
268  cur = get_pool(pool);
269  end->next = cur;
270  while (end->next)
271  end = end->next;
272  }
273 }
274 
275 static void pool_release_buffer(void *opaque, uint8_t *data)
276 {
277  BufferPoolEntry *buf = opaque;
278  AVBufferPool *pool = buf->pool;
279  add_to_pool(buf);
280  if (!avpriv_atomic_int_add_and_fetch(&pool->refcount, -1))
281  buffer_pool_free(pool);
282 }
283 
284 /* allocate a new buffer and override its free() callback so that
285  * it is returned to the pool on free */
287 {
288  BufferPoolEntry *buf;
289  AVBufferRef *ret;
290 
291  ret = pool->alloc(pool->size);
292  if (!ret)
293  return NULL;
294 
295  buf = av_mallocz(sizeof(*buf));
296  if (!buf) {
297  av_buffer_unref(&ret);
298  return NULL;
299  }
300 
301  buf->data = ret->buffer->data;
302  buf->opaque = ret->buffer->opaque;
303  buf->free = ret->buffer->free;
304  buf->pool = pool;
305 
306  ret->buffer->opaque = buf;
308 
310 
311  return ret;
312 }
313 
315 {
316  AVBufferRef *ret;
317  BufferPoolEntry *buf;
318 
319  /* check whether the pool is empty */
320  buf = get_pool(pool);
321  if (!buf)
322  return pool_alloc_buffer(pool);
323 
324  /* keep the first entry, return the rest of the list to the pool */
325  add_to_pool(buf->next);
326  buf->next = NULL;
327 
328  ret = av_buffer_create(buf->data, pool->size, pool_release_buffer,
329  buf, 0);
330  if (!ret) {
331  add_to_pool(buf);
332  return NULL;
333  }
335 
336  return ret;
337 }
void(* free)(void *opaque, uint8_t *data)
a callback for freeing the data
int av_buffer_make_writable(AVBufferRef **pbuf)
Create a writable reference from a given buffer reference, avoiding data copy if possible.
Definition: buffer.c:128
void * av_malloc(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:62
#define avpriv_atomic_int_add_and_fetch
Definition: atomic_gcc.h:42
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:105
int size
struct BufferPoolEntry *volatile next
memory handling functions
static void add_to_pool(BufferPoolEntry *buf)
Definition: buffer.c:254
#define BUFFER_FLAG_READONLY
The buffer is always treated as read-only.
BufferPoolEntry *volatile pool
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
volatile int refcount
number of existing AVBufferRef instances referring to this buffer
uint8_t * data
data described by this buffer
uint8_t
#define b
Definition: input.c:52
#define avpriv_atomic_int_set
Definition: atomic_gcc.h:35
const char data[16]
Definition: mxf.c:66
static int flags
Definition: log.c:44
#define AV_BUFFER_FLAG_READONLY
Always treat the buffer as read-only, even when it has only one reference.
Definition: buffer.h:113
The buffer pool.
void av_buffer_default_free(void *opaque, uint8_t *data)
Default free callback, which calls av_free() on the buffer data.
Definition: buffer.c:60
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:186
#define avpriv_atomic_ptr_cas
Definition: atomic_gcc.h:48
#define AVERROR(e)
Definition: error.h:43
AVBufferRef * av_buffer_create(uint8_t *data, int size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:27
int av_buffer_realloc(AVBufferRef **pbuf, int size)
Reallocate a given buffer.
Definition: buffer.c:146
static AVBufferRef * pool_alloc_buffer(AVBufferPool *pool)
Definition: buffer.c:286
#define FFMIN(a, b)
Definition: common.h:57
int av_buffer_is_writable(const AVBufferRef *buf)
Definition: buffer.c:120
void(* free)(void *opaque, uint8_t *data)
static void pool_release_buffer(void *opaque, uint8_t *data)
Definition: buffer.c:275
int flags
A combination of BUFFER_FLAG_*.
NULL
Definition: eval.c:55
static void buffer_pool_free(AVBufferPool *pool)
Definition: buffer.c:214
AVBufferRef * av_buffer_alloc(int size)
Allocate an AVBuffer of the given size using av_malloc().
Definition: buffer.c:65
uint8_t * data
The data buffer.
Definition: buffer.h:89
AVBufferRef * av_buffer_allocz(int size)
Same as av_buffer_alloc(), except the returned buffer will be initialized to zero.
Definition: buffer.c:81
AVBuffer * buffer
Definition: buffer.h:82
void av_buffer_pool_uninit(AVBufferPool **ppool)
Mark the pool as being available for freeing.
Definition: buffer.c:226
A reference counted buffer type.
int size
Size of data in bytes.
Definition: buffer.h:93
volatile int refcount
void * opaque
an opaque pointer, to be used by the freeing callback
A reference to a data buffer.
Definition: buffer.h:81
common internal and external API header
AVBufferPool * pool
AVBufferPool * av_buffer_pool_init(int size, AVBufferRef *(*alloc)(int size))
Allocate and initialize a buffer pool.
Definition: buffer.c:196
void * av_realloc(void *ptr, size_t size)
Allocate or reallocate a block of memory.
Definition: mem.c:117
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:91
int size
size of data in bytes
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition: buffer.c:314
#define FFSWAP(type, a, b)
Definition: common.h:60
#define BUFFER_FLAG_REALLOCATABLE
The buffer was av_realloc()ed, so it is reallocatable.
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:205
AVBufferRef *(* alloc)(int size)
static BufferPoolEntry * get_pool(AVBufferPool *pool)
Definition: buffer.c:240