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
27
AVBufferRef
*
av_buffer_create
(
uint8_t
*
data
,
int
size
,
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
)
45
buf->
flags
|=
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
65
AVBufferRef
*
av_buffer_alloc
(
int
size)
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
81
AVBufferRef
*
av_buffer_allocz
(
int
size)
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
91
AVBufferRef
*
av_buffer_ref
(
AVBufferRef
*
buf
)
92
{
93
AVBufferRef
*
ret
=
av_mallocz
(
sizeof
(*ret));
94
95
if
(!ret)
96
return
NULL;
97
98
*ret = *
buf
;
99
100
avpriv_atomic_int_add_and_fetch
(&buf->
buffer
->
refcount
, 1);
101
102
return
ret
;
103
}
104
105
void
av_buffer_unref
(
AVBufferRef
**
buf
)
106
{
107
AVBuffer
*
b
;
108
109
if
(!buf || !*buf)
110
return
;
111
b = (*buf)->buffer;
112
av_freep
(buf);
113
114
if
(!
avpriv_atomic_int_add_and_fetch
(&b->
refcount
, -1)) {
115
b->
free
(b->
opaque
, b->
data
);
116
av_freep
(&b);
117
}
118
}
119
120
int
av_buffer_is_writable
(
const
AVBufferRef
*
buf
)
121
{
122
if
(buf->
buffer
->
flags
&
AV_BUFFER_FLAG_READONLY
)
123
return
0;
124
125
return
avpriv_atomic_int_get
(&buf->
buffer
->
refcount
) == 1;
126
}
127
128
void
*
av_buffer_get_opaque
(
const
AVBufferRef
*
buf
)
129
{
130
return
buf->
buffer
->
opaque
;
131
}
132
133
int
av_buffer_get_ref_count
(
const
AVBufferRef
*
buf
)
134
{
135
return
buf->
buffer
->
refcount
;
136
}
137
138
int
av_buffer_make_writable
(
AVBufferRef
**pbuf)
139
{
140
AVBufferRef
*newbuf, *
buf
= *pbuf;
141
142
if
(
av_buffer_is_writable
(buf))
143
return
0;
144
145
newbuf =
av_buffer_alloc
(buf->
size
);
146
if
(!newbuf)
147
return
AVERROR
(ENOMEM);
148
149
memcpy(newbuf->
data
, buf->
data
, buf->
size
);
150
av_buffer_unref
(pbuf);
151
*pbuf = newbuf;
152
153
return
0;
154
}
155
156
int
av_buffer_realloc
(
AVBufferRef
**pbuf,
int
size)
157
{
158
AVBufferRef
*
buf
= *pbuf;
159
uint8_t
*tmp;
160
161
if
(!buf) {
162
/* allocate a new buffer with av_realloc(), so it will be reallocatable
163
* later */
164
uint8_t
*data =
av_realloc
(NULL, size);
165
if
(!data)
166
return
AVERROR
(ENOMEM);
167
168
buf =
av_buffer_create
(data, size,
av_buffer_default_free
, NULL, 0);
169
if
(!buf) {
170
av_freep
(&data);
171
return
AVERROR
(ENOMEM);
172
}
173
174
buf->
buffer
->
flags
|=
BUFFER_FLAG_REALLOCATABLE
;
175
*pbuf =
buf
;
176
177
return
0;
178
}
else
if
(buf->
size
== size)
179
return
0;
180
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;
185
186
av_buffer_realloc
(&
new
, size);
187
if
(!
new
)
188
return
AVERROR
(ENOMEM);
189
190
memcpy(new->data, buf->
data
,
FFMIN
(size, buf->
size
));
191
192
av_buffer_unref
(pbuf);
193
*pbuf =
new
;
194
return
0;
195
}
196
197
tmp =
av_realloc
(buf->
buffer
->
data
, size);
198
if
(!tmp)
199
return
AVERROR
(ENOMEM);
200
201
buf->
buffer
->
data
= buf->
data
= tmp;
202
buf->
buffer
->
size
= buf->
size
=
size
;
203
return
0;
204
}
205
206
AVBufferPool
*
av_buffer_pool_init
(
int
size,
AVBufferRef
* (*alloc)(
int
size))
207
{
208
AVBufferPool
*pool =
av_mallocz
(
sizeof
(*pool));
209
if
(!pool)
210
return
NULL;
211
212
pool->
size
=
size
;
213
pool->
alloc
= alloc ? alloc :
av_buffer_alloc
;
214
215
avpriv_atomic_int_set
(&pool->
refcount
, 1);
216
217
return
pool;
218
}
219
220
/*
221
* This function gets called when the pool has been uninited and
222
* all the buffers returned to it.
223
*/
224
static
void
buffer_pool_free
(
AVBufferPool
*pool)
225
{
226
while
(pool->
pool
) {
227
BufferPoolEntry
*
buf
= pool->
pool
;
228
pool->
pool
= buf->
next
;
229
230
buf->
free
(buf->
opaque
, buf->
data
);
231
av_freep
(&buf);
232
}
233
av_freep
(&pool);
234
}
235
236
void
av_buffer_pool_uninit
(
AVBufferPool
**ppool)
237
{
238
AVBufferPool
*pool;
239
240
if
(!ppool || !*ppool)
241
return
;
242
pool = *ppool;
243
*ppool = NULL;
244
245
if
(!
avpriv_atomic_int_add_and_fetch
(&pool->
refcount
, -1))
246
buffer_pool_free
(pool);
247
}
248
249
/* remove the whole buffer list from the pool and return it */
250
static
BufferPoolEntry
*
get_pool
(
AVBufferPool
*pool)
251
{
252
BufferPoolEntry
*cur = *(
void
*
volatile
*)&pool->
pool
, *last = NULL;
253
254
while (cur != last) {
255
last = cur;
256
cur =
avpriv_atomic_ptr_cas
((
void
*
volatile
*)&pool->
pool
, last, NULL);
257
if
(!cur)
258
return
NULL;
259
}
260
261
return
cur;
262
}
263
264
static
void
add_to_pool
(
BufferPoolEntry
*
buf
)
265
{
266
AVBufferPool
*pool;
267
BufferPoolEntry
*cur, *
end
=
buf
;
268
269
if
(!buf)
270
return
;
271
pool = buf->
pool
;
272
273
while
(end->
next
)
274
end = end->
next
;
275
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);
279
end->
next
= cur;
280
while
(end->
next
)
281
end = end->
next
;
282
}
283
}
284
285
static
void
pool_release_buffer
(
void
*opaque,
uint8_t
*data)
286
{
287
BufferPoolEntry
*
buf
= opaque;
288
AVBufferPool
*pool = buf->
pool
;
289
290
if
(CONFIG_MEMORY_POISONING)
291
memset(buf->
data
,
FF_MEMORY_POISON
, pool->
size
);
292
293
add_to_pool
(buf);
294
if
(!
avpriv_atomic_int_add_and_fetch
(&pool->
refcount
, -1))
295
buffer_pool_free
(pool);
296
}
297
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)
301
{
302
BufferPoolEntry
*
buf
;
303
AVBufferRef
*
ret
;
304
305
ret = pool->
alloc
(pool->
size
);
306
if
(!ret)
307
return
NULL;
308
309
buf =
av_mallocz
(
sizeof
(*buf));
310
if
(!buf) {
311
av_buffer_unref
(&ret);
312
return
NULL;
313
}
314
315
buf->
data
= ret->
buffer
->
data
;
316
buf->
opaque
= ret->
buffer
->
opaque
;
317
buf->
free
= ret->
buffer
->
free
;
318
buf->
pool
= pool;
319
320
ret->
buffer
->
opaque
=
buf
;
321
ret->
buffer
->
free
=
pool_release_buffer
;
322
323
avpriv_atomic_int_add_and_fetch
(&pool->
refcount
, 1);
324
avpriv_atomic_int_add_and_fetch
(&pool->
nb_allocated
, 1);
325
326
return
ret
;
327
}
328
329
AVBufferRef
*
av_buffer_pool_get
(
AVBufferPool
*pool)
330
{
331
AVBufferRef
*
ret
;
332
BufferPoolEntry
*
buf
;
333
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);
340
}
341
342
if
(!buf)
343
return
pool_alloc_buffer
(pool);
344
345
/* keep the first entry, return the rest of the list to the pool */
346
add_to_pool
(buf->
next
);
347
buf->
next
= NULL;
348
349
ret =
av_buffer_create
(buf->
data
, pool->
size
,
pool_release_buffer
,
350
buf, 0);
351
if
(!ret) {
352
add_to_pool
(buf);
353
return
NULL;
354
}
355
avpriv_atomic_int_add_and_fetch
(&pool->
refcount
, 1);
356
357
return
ret
;
358
}
Generated on Sat Jan 25 2014 19:51:59 for FFmpeg by
1.8.2