FFmpeg
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
Examples
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
libavutil
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 <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
#include "
thread.h
"
27
28
AVBufferRef
*
av_buffer_create
(
uint8_t
*
data
,
int
size
,
29
void
(*free)(
void
*opaque,
uint8_t
*data),
30
void
*opaque,
int
flags
)
31
{
32
AVBufferRef
*ref = NULL;
33
AVBuffer
*
buf
= NULL;
34
35
buf =
av_mallocz
(
sizeof
(*buf));
36
if
(!buf)
37
return
NULL;
38
39
buf->
data
=
data
;
40
buf->
size
=
size
;
41
buf->
free
= free ? free :
av_buffer_default_free
;
42
buf->
opaque
= opaque;
43
buf->
refcount
= 1;
44
45
if
(flags &
AV_BUFFER_FLAG_READONLY
)
46
buf->
flags
|=
BUFFER_FLAG_READONLY
;
47
48
ref =
av_mallocz
(
sizeof
(*ref));
49
if
(!ref) {
50
av_freep
(&buf);
51
return
NULL;
52
}
53
54
ref->
buffer
=
buf
;
55
ref->
data
=
data
;
56
ref->
size
=
size
;
57
58
return
ref;
59
}
60
61
void
av_buffer_default_free
(
void
*opaque,
uint8_t
*data)
62
{
63
av_free
(data);
64
}
65
66
AVBufferRef
*
av_buffer_alloc
(
int
size)
67
{
68
AVBufferRef
*
ret
= NULL;
69
uint8_t
*data = NULL;
70
71
data =
av_malloc
(size);
72
if
(!data)
73
return
NULL;
74
75
ret =
av_buffer_create
(data, size,
av_buffer_default_free
, NULL, 0);
76
if
(!ret)
77
av_freep
(&data);
78
79
return
ret
;
80
}
81
82
AVBufferRef
*
av_buffer_allocz
(
int
size)
83
{
84
AVBufferRef
*
ret
=
av_buffer_alloc
(size);
85
if
(!ret)
86
return
NULL;
87
88
memset(ret->
data
, 0, size);
89
return
ret
;
90
}
91
92
AVBufferRef
*
av_buffer_ref
(
AVBufferRef
*
buf
)
93
{
94
AVBufferRef
*
ret
=
av_mallocz
(
sizeof
(*ret));
95
96
if
(!ret)
97
return
NULL;
98
99
*ret = *
buf
;
100
101
avpriv_atomic_int_add_and_fetch
(&buf->
buffer
->
refcount
, 1);
102
103
return
ret
;
104
}
105
106
void
av_buffer_unref
(
AVBufferRef
**
buf
)
107
{
108
AVBuffer
*
b
;
109
110
if
(!buf || !*buf)
111
return
;
112
b = (*buf)->buffer;
113
av_freep
(buf);
114
115
if
(!
avpriv_atomic_int_add_and_fetch
(&b->
refcount
, -1)) {
116
b->
free
(b->
opaque
, b->
data
);
117
av_freep
(&b);
118
}
119
}
120
121
int
av_buffer_is_writable
(
const
AVBufferRef
*
buf
)
122
{
123
if
(buf->
buffer
->
flags
&
AV_BUFFER_FLAG_READONLY
)
124
return
0;
125
126
return
avpriv_atomic_int_get
(&buf->
buffer
->
refcount
) == 1;
127
}
128
129
void
*
av_buffer_get_opaque
(
const
AVBufferRef
*
buf
)
130
{
131
return
buf->
buffer
->
opaque
;
132
}
133
134
int
av_buffer_get_ref_count
(
const
AVBufferRef
*
buf
)
135
{
136
return
buf->
buffer
->
refcount
;
137
}
138
139
int
av_buffer_make_writable
(
AVBufferRef
**pbuf)
140
{
141
AVBufferRef
*newbuf, *
buf
= *pbuf;
142
143
if
(
av_buffer_is_writable
(buf))
144
return
0;
145
146
newbuf =
av_buffer_alloc
(buf->
size
);
147
if
(!newbuf)
148
return
AVERROR
(ENOMEM);
149
150
memcpy(newbuf->
data
, buf->
data
, buf->
size
);
151
av_buffer_unref
(pbuf);
152
*pbuf = newbuf;
153
154
return
0;
155
}
156
157
int
av_buffer_realloc
(
AVBufferRef
**pbuf,
int
size)
158
{
159
AVBufferRef
*
buf
= *pbuf;
160
uint8_t
*tmp;
161
162
if
(!buf) {
163
/* allocate a new buffer with av_realloc(), so it will be reallocatable
164
* later */
165
uint8_t
*data =
av_realloc
(NULL, size);
166
if
(!data)
167
return
AVERROR
(ENOMEM);
168
169
buf =
av_buffer_create
(data, size,
av_buffer_default_free
, NULL, 0);
170
if
(!buf) {
171
av_freep
(&data);
172
return
AVERROR
(ENOMEM);
173
}
174
175
buf->
buffer
->
flags
|=
BUFFER_FLAG_REALLOCATABLE
;
176
*pbuf =
buf
;
177
178
return
0;
179
}
else
if
(buf->
size
== size)
180
return
0;
181
182
if
(!(buf->
buffer
->
flags
&
BUFFER_FLAG_REALLOCATABLE
) ||
183
!
av_buffer_is_writable
(buf)) {
184
/* cannot realloc, allocate a new reallocable buffer and copy data */
185
AVBufferRef
*
new
= NULL;
186
187
av_buffer_realloc
(&
new
, size);
188
if
(!
new
)
189
return
AVERROR
(ENOMEM);
190
191
memcpy(new->data, buf->
data
,
FFMIN
(size, buf->
size
));
192
193
av_buffer_unref
(pbuf);
194
*pbuf =
new
;
195
return
0;
196
}
197
198
tmp =
av_realloc
(buf->
buffer
->
data
, size);
199
if
(!tmp)
200
return
AVERROR
(ENOMEM);
201
202
buf->
buffer
->
data
= buf->
data
= tmp;
203
buf->
buffer
->
size
= buf->
size
=
size
;
204
return
0;
205
}
206
207
AVBufferPool
*
av_buffer_pool_init
(
int
size,
AVBufferRef
* (*alloc)(
int
size))
208
{
209
AVBufferPool
*pool =
av_mallocz
(
sizeof
(*pool));
210
if
(!pool)
211
return
NULL;
212
213
ff_mutex_init
(&pool->
mutex
, NULL);
214
215
pool->
size
=
size
;
216
pool->
alloc
= alloc ? alloc :
av_buffer_alloc
;
217
218
avpriv_atomic_int_set
(&pool->
refcount
, 1);
219
220
return
pool;
221
}
222
223
/*
224
* This function gets called when the pool has been uninited and
225
* all the buffers returned to it.
226
*/
227
static
void
buffer_pool_free
(
AVBufferPool
*pool)
228
{
229
while
(pool->
pool
) {
230
BufferPoolEntry
*
buf
= pool->
pool
;
231
pool->
pool
= buf->
next
;
232
233
buf->
free
(buf->
opaque
, buf->
data
);
234
av_freep
(&buf);
235
}
236
ff_mutex_destroy
(&pool->
mutex
);
237
av_freep
(&pool);
238
}
239
240
void
av_buffer_pool_uninit
(
AVBufferPool
**ppool)
241
{
242
AVBufferPool
*pool;
243
244
if
(!ppool || !*ppool)
245
return
;
246
pool = *ppool;
247
*ppool = NULL;
248
249
if
(!
avpriv_atomic_int_add_and_fetch
(&pool->
refcount
, -1))
250
buffer_pool_free
(pool);
251
}
252
253
/* remove the whole buffer list from the pool and return it */
254
static
BufferPoolEntry
*
get_pool
(
AVBufferPool
*pool)
255
{
256
BufferPoolEntry
*cur = *(
void
*
volatile
*)&pool->
pool
, *last = NULL;
257
258
while (cur != last) {
259
last = cur;
260
cur =
avpriv_atomic_ptr_cas
((
void
*
volatile
*)&pool->
pool
, last, NULL);
261
if
(!cur)
262
return
NULL;
263
}
264
265
return
cur;
266
}
267
268
static
void
add_to_pool
(
BufferPoolEntry
*
buf
)
269
{
270
AVBufferPool
*pool;
271
BufferPoolEntry
*cur, *
end
=
buf
;
272
273
if
(!buf)
274
return
;
275
pool = buf->
pool
;
276
277
while
(end->
next
)
278
end = end->
next
;
279
280
while
(
avpriv_atomic_ptr_cas
((
void
*
volatile
*)&pool->
pool
, NULL, buf)) {
281
/* pool is not empty, retrieve it and append it to our list */
282
cur =
get_pool
(pool);
283
end->
next
= cur;
284
while
(end->
next
)
285
end = end->
next
;
286
}
287
}
288
289
static
void
pool_release_buffer
(
void
*opaque,
uint8_t
*data)
290
{
291
BufferPoolEntry
*
buf
= opaque;
292
AVBufferPool
*pool = buf->
pool
;
293
294
if
(CONFIG_MEMORY_POISONING)
295
memset(buf->
data
,
FF_MEMORY_POISON
, pool->
size
);
296
297
#if USE_ATOMICS
298
add_to_pool
(buf);
299
#else
300
ff_mutex_lock
(&pool->
mutex
);
301
buf->
next
= pool->
pool
;
302
pool->
pool
=
buf
;
303
ff_mutex_unlock
(&pool->
mutex
);
304
#endif
305
306
if
(!
avpriv_atomic_int_add_and_fetch
(&pool->
refcount
, -1))
307
buffer_pool_free
(pool);
308
}
309
310
/* allocate a new buffer and override its free() callback so that
311
* it is returned to the pool on free */
312
static
AVBufferRef
*
pool_alloc_buffer
(
AVBufferPool
*pool)
313
{
314
BufferPoolEntry
*
buf
;
315
AVBufferRef
*
ret
;
316
317
ret = pool->
alloc
(pool->
size
);
318
if
(!ret)
319
return
NULL;
320
321
buf =
av_mallocz
(
sizeof
(*buf));
322
if
(!buf) {
323
av_buffer_unref
(&ret);
324
return
NULL;
325
}
326
327
buf->
data
= ret->
buffer
->
data
;
328
buf->
opaque
= ret->
buffer
->
opaque
;
329
buf->
free
= ret->
buffer
->
free
;
330
buf->
pool
= pool;
331
332
ret->
buffer
->
opaque
=
buf
;
333
ret->
buffer
->
free
=
pool_release_buffer
;
334
335
#if USE_ATOMICS
336
avpriv_atomic_int_add_and_fetch
(&pool->
refcount
, 1);
337
avpriv_atomic_int_add_and_fetch
(&pool->
nb_allocated
, 1);
338
#endif
339
340
return
ret
;
341
}
342
343
AVBufferRef
*
av_buffer_pool_get
(
AVBufferPool
*pool)
344
{
345
AVBufferRef
*
ret
;
346
BufferPoolEntry
*
buf
;
347
348
#if USE_ATOMICS
349
/* check whether the pool is empty */
350
buf =
get_pool
(pool);
351
if
(!buf && pool->
refcount
<= pool->
nb_allocated
) {
352
av_log
(NULL,
AV_LOG_DEBUG
,
"Pool race dectected, spining to avoid overallocation and eventual OOM\n"
);
353
while
(!buf &&
avpriv_atomic_int_get
(&pool->
refcount
) <=
avpriv_atomic_int_get
(&pool->
nb_allocated
))
354
buf =
get_pool
(pool);
355
}
356
357
if
(!buf)
358
return
pool_alloc_buffer
(pool);
359
360
/* keep the first entry, return the rest of the list to the pool */
361
add_to_pool
(buf->
next
);
362
buf->
next
= NULL;
363
364
ret =
av_buffer_create
(buf->
data
, pool->
size
,
pool_release_buffer
,
365
buf, 0);
366
if
(!ret) {
367
add_to_pool
(buf);
368
return
NULL;
369
}
370
#else
371
ff_mutex_lock
(&pool->
mutex
);
372
buf = pool->
pool
;
373
if
(buf) {
374
ret =
av_buffer_create
(buf->
data
, pool->
size
,
pool_release_buffer
,
375
buf, 0);
376
if
(ret) {
377
pool->
pool
= buf->
next
;
378
buf->
next
= NULL;
379
}
380
}
else
{
381
ret =
pool_alloc_buffer
(pool);
382
}
383
ff_mutex_unlock
(&pool->
mutex
);
384
#endif
385
386
if
(ret)
387
avpriv_atomic_int_add_and_fetch
(&pool->
refcount
, 1);
388
389
return
ret
;
390
}
Generated on Fri Dec 5 2014 04:42:08 for FFmpeg by
1.8.2