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 Sun Mar 23 2014 23:50:08 for FFmpeg by
1.8.2