Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
F
ffmpeg.wasm-core
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Linshizhi
ffmpeg.wasm-core
Commits
1cec0624
Commit
1cec0624
authored
Jan 20, 2013
by
Anton Khirnov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
AVBuffer: add a new API for buffer pools
parent
8e401dbe
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
245 additions
and
0 deletions
+245
-0
buffer.c
libavutil/buffer.c
+143
-0
buffer.h
libavutil/buffer.h
+70
-0
buffer_internal.h
libavutil/buffer_internal.h
+32
-0
No files found.
libavutil/buffer.c
View file @
1cec0624
...
...
@@ -192,3 +192,146 @@ int av_buffer_realloc(AVBufferRef **pbuf, int size)
buf
->
buffer
->
size
=
buf
->
size
=
size
;
return
0
;
}
AVBufferPool
*
av_buffer_pool_init
(
int
size
,
AVBufferRef
*
(
*
alloc
)(
int
size
))
{
AVBufferPool
*
pool
=
av_mallocz
(
sizeof
(
*
pool
));
if
(
!
pool
)
return
NULL
;
pool
->
size
=
size
;
pool
->
alloc
=
alloc
?
alloc
:
av_buffer_alloc
;
avpriv_atomic_int_set
(
&
pool
->
refcount
,
1
);
return
pool
;
}
/*
* This function gets called when the pool has been uninited and
* all the buffers returned to it.
*/
static
void
buffer_pool_free
(
AVBufferPool
*
pool
)
{
while
(
pool
->
pool
)
{
BufferPoolEntry
*
buf
=
pool
->
pool
;
pool
->
pool
=
buf
->
next
;
buf
->
free
(
buf
->
opaque
,
buf
->
data
);
av_freep
(
&
buf
);
}
av_freep
(
&
pool
);
}
void
av_buffer_pool_uninit
(
AVBufferPool
**
ppool
)
{
AVBufferPool
*
pool
;
if
(
!
ppool
||
!*
ppool
)
return
;
pool
=
*
ppool
;
*
ppool
=
NULL
;
if
(
!
avpriv_atomic_int_add_and_fetch
(
&
pool
->
refcount
,
-
1
))
buffer_pool_free
(
pool
);
}
/* remove the whole buffer list from the pool and return it */
static
BufferPoolEntry
*
get_pool
(
AVBufferPool
*
pool
)
{
BufferPoolEntry
*
cur
=
NULL
,
*
last
=
NULL
;
do
{
FFSWAP
(
BufferPoolEntry
*
,
cur
,
last
);
cur
=
avpriv_atomic_ptr_cas
((
void
*
volatile
*
)
&
pool
->
pool
,
last
,
NULL
);
if
(
!
cur
)
return
NULL
;
}
while
(
cur
!=
last
);
return
cur
;
}
static
void
add_to_pool
(
BufferPoolEntry
*
buf
)
{
AVBufferPool
*
pool
;
BufferPoolEntry
*
cur
,
*
end
=
buf
;
if
(
!
buf
)
return
;
pool
=
buf
->
pool
;
while
(
end
->
next
)
end
=
end
->
next
;
while
((
cur
=
avpriv_atomic_ptr_cas
((
void
*
volatile
*
)
&
pool
->
pool
,
NULL
,
buf
)))
{
/* pool is not empty, retrieve it and append it to our list */
cur
=
get_pool
(
pool
);
end
->
next
=
cur
;
while
(
end
->
next
)
end
=
end
->
next
;
}
}
static
void
pool_release_buffer
(
void
*
opaque
,
uint8_t
*
data
)
{
BufferPoolEntry
*
buf
=
opaque
;
AVBufferPool
*
pool
=
buf
->
pool
;
add_to_pool
(
buf
);
if
(
!
avpriv_atomic_int_add_and_fetch
(
&
pool
->
refcount
,
-
1
))
buffer_pool_free
(
pool
);
}
/* allocate a new buffer and override its free() callback so that
* it is returned to the pool on free */
static
AVBufferRef
*
pool_alloc_buffer
(
AVBufferPool
*
pool
)
{
BufferPoolEntry
*
buf
;
AVBufferRef
*
ret
;
ret
=
pool
->
alloc
(
pool
->
size
);
if
(
!
ret
)
return
NULL
;
buf
=
av_mallocz
(
sizeof
(
*
buf
));
if
(
!
buf
)
{
av_buffer_unref
(
&
ret
);
return
NULL
;
}
buf
->
data
=
ret
->
buffer
->
data
;
buf
->
opaque
=
ret
->
buffer
->
opaque
;
buf
->
free
=
ret
->
buffer
->
free
;
buf
->
pool
=
pool
;
ret
->
buffer
->
opaque
=
buf
;
ret
->
buffer
->
free
=
pool_release_buffer
;
avpriv_atomic_int_add_and_fetch
(
&
pool
->
refcount
,
1
);
return
ret
;
}
AVBufferRef
*
av_buffer_pool_get
(
AVBufferPool
*
pool
)
{
AVBufferRef
*
ret
;
BufferPoolEntry
*
buf
;
/* check whether the pool is empty */
buf
=
get_pool
(
pool
);
if
(
!
buf
)
return
pool_alloc_buffer
(
pool
);
/* keep the first entry, return the rest of the list to the pool */
add_to_pool
(
buf
->
next
);
buf
->
next
=
NULL
;
ret
=
av_buffer_create
(
buf
->
data
,
pool
->
size
,
pool_release_buffer
,
buf
,
0
);
if
(
!
ret
)
{
add_to_pool
(
buf
);
return
NULL
;
}
avpriv_atomic_int_add_and_fetch
(
&
pool
->
refcount
,
1
);
return
ret
;
}
libavutil/buffer.h
View file @
1cec0624
...
...
@@ -190,6 +190,76 @@ int av_buffer_make_writable(AVBufferRef **buf);
*/
int
av_buffer_realloc
(
AVBufferRef
**
buf
,
int
size
);
/**
* @}
*/
/**
* @defgroup lavu_bufferpool AVBufferPool
* @ingroup lavu_data
*
* @{
* AVBufferPool is an API for a lock-free thread-safe pool of AVBuffers.
*
* Frequently allocating and freeing large buffers may be slow. AVBufferPool is
* meant to solve this in cases when the caller needs a set of buffers of the
* same size (the most obvious use case being buffers for raw video or audio
* frames).
*
* At the beginning, the user must call av_buffer_pool_init() to create the
* buffer pool. Then whenever a buffer is needed, call av_buffer_pool_get() to
* get a reference to a new buffer, similar to av_buffer_alloc(). This new
* reference works in all aspects the same way as the one created by
* av_buffer_alloc(). However, when the last reference to this buffer is
* unreferenced, it is returned to the pool instead of being freed and will be
* reused for subsequent av_buffer_pool_get() calls.
*
* When the caller is done with the pool and no longer needs to allocate any new
* buffers, av_buffer_pool_uninit() must be called to mark the pool as freeable.
* Once all the buffers are released, it will automatically be freed.
*
* Allocating and releasing buffers with this API is thread-safe as long as
* either the default alloc callback is used, or the user-supplied one is
* thread-safe.
*/
/**
* The buffer pool. This structure is opaque and not meant to be accessed
* directly. It is allocated with av_buffer_pool_init() and freed with
* av_buffer_pool_uninit().
*/
typedef
struct
AVBufferPool
AVBufferPool
;
/**
* Allocate and initialize a buffer pool.
*
* @param size size of each buffer in this pool
* @param alloc a function that will be used to allocate new buffers when the
* pool is empty. May be NULL, then the default allocator will be used
* (av_buffer_alloc()).
* @return newly created buffer pool on success, NULL on error.
*/
AVBufferPool
*
av_buffer_pool_init
(
int
size
,
AVBufferRef
*
(
*
alloc
)(
int
size
));
/**
* Mark the pool as being available for freeing. It will actually be freed only
* once all the allocated buffers associated with the pool are released. Thus it
* is safe to call this function while some of the allocated buffers are still
* in use.
*
* @param pool pointer to the pool to be freed. It will be set to NULL.
* @see av_buffer_pool_can_uninit()
*/
void
av_buffer_pool_uninit
(
AVBufferPool
**
pool
);
/**
* Allocate a new AVBuffer, reusing an old buffer from the pool when available.
* This function may be called simultaneously from multiple threads.
*
* @return a reference to the new buffer on success, NULL on error.
*/
AVBufferRef
*
av_buffer_pool_get
(
AVBufferPool
*
pool
);
/**
* @}
*/
...
...
libavutil/buffer_internal.h
View file @
1cec0624
...
...
@@ -57,4 +57,36 @@ struct AVBuffer {
int
flags
;
};
typedef
struct
BufferPoolEntry
{
uint8_t
*
data
;
/*
* Backups of the original opaque/free of the AVBuffer corresponding to
* data. They will be used to free the buffer when the pool is freed.
*/
void
*
opaque
;
void
(
*
free
)(
void
*
opaque
,
uint8_t
*
data
);
AVBufferPool
*
pool
;
struct
BufferPoolEntry
*
volatile
next
;
}
BufferPoolEntry
;
struct
AVBufferPool
{
BufferPoolEntry
*
volatile
pool
;
/*
* This is used to track when the pool is to be freed.
* The pointer to the pool itself held by the caller is considered to
* be one reference. Each buffer requested by the caller increases refcount
* by one, returning the buffer to the pool decreases it by one.
* refcount reaches zero when the buffer has been uninited AND all the
* buffers have been released, then it's safe to free the pool and all
* the buffers in it.
*/
volatile
int
refcount
;
int
size
;
AVBufferRef
*
(
*
alloc
)(
int
size
);
};
#endif
/* AVUTIL_BUFFER_INTERNAL_H */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment