Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
F
ffmpeg
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
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
ffmpeg
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)
...
@@ -192,3 +192,146 @@ int av_buffer_realloc(AVBufferRef **pbuf, int size)
buf
->
buffer
->
size
=
buf
->
size
=
size
;
buf
->
buffer
->
size
=
buf
->
size
=
size
;
return
0
;
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);
...
@@ -190,6 +190,76 @@ int av_buffer_make_writable(AVBufferRef **buf);
*/
*/
int
av_buffer_realloc
(
AVBufferRef
**
buf
,
int
size
);
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 {
...
@@ -57,4 +57,36 @@ struct AVBuffer {
int
flags
;
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 */
#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