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 }