FFmpeg实现了一个AVBufferPool ,这个pool可以用来提前做些内存分配等,在ffmpeg cuvid插件中hwcontext_cuda.c文件夹中可以看到这个Pool的用法。
下面是关键结构体的定义,可以看到几个比较重要的函数指针,比如:
void (*free)(void *opaque, uint8_t *data);
这个是用来释放AVBuffer 中的data数据的,可以由用户来指定。
/*** The buffer was av_realloc()ed, so it is reallocatable.*/
#define BUFFER_FLAG_REALLOCATABLE (1 << 0)struct AVBuffer {uint8_t *data; /**< data described by this buffer */buffer_size_t size; /**< size of data in bytes *//*** number of existing AVBufferRef instances referring to this buffer*/atomic_uint refcount;/*** a callback for freeing the data*/void (*free)(void *opaque, uint8_t *data);/*** an opaque pointer, to be used by the freeing callback*/void *opaque;/*** A combination of AV_BUFFER_FLAG_**/int flags;/*** A combination of BUFFER_FLAG_**/int flags_internal;
};
下面是Pool的元素,BufferPoolEntry,可以看到一个next指针,其实就是一个单向链表。
其中free用来释放buffer
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 *next;
} BufferPoolEntry;
下面是一个bufferPoll的定义,其中有一个refcount,作为ref来使用,另外有两个alloc函数和pool_free
struct AVBufferPool {AVMutex mutex;BufferPoolEntry *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.*/atomic_uint refcount;buffer_size_t size;void *opaque;AVBufferRef* (*alloc)(buffer_size_t size);AVBufferRef* (*alloc2)(void *opaque, buffer_size_t size);void (*pool_free)(void *opaque);
};
下面的注释,其实已经说明了该怎么去使用buffer poll。
/*** @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.*/
#if FF_API_BUFFER_SIZE_T
AVBufferPool *av_buffer_pool_init(int size, AVBufferRef* (*alloc)(int size));
#else
AVBufferPool *av_buffer_pool_init(size_t size, AVBufferRef* (*alloc)(size_t size));
#endif/*** Allocate and initialize a buffer pool with a more complex allocator.** @param size size of each buffer in this pool* @param opaque arbitrary user data used by the allocator* @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()).* @param pool_free a function that will be called immediately before the pool* is freed. I.e. after av_buffer_pool_uninit() is called* by the caller and all the frames are returned to the pool* and freed. It is intended to uninitialize the user opaque* data. May be NULL.* @return newly created buffer pool on success, NULL on error.*/
#if FF_API_BUFFER_SIZE_T
AVBufferPool *av_buffer_pool_init2(int size, void *opaque,AVBufferRef* (*alloc)(void *opaque, int size),
#else
AVBufferPool *av_buffer_pool_init2(size_t size, void *opaque,AVBufferRef* (*alloc)(void *opaque, size_t size),
#endifvoid (*pool_free)(void *opaque));/*** 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.*/
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);/*** Query the original opaque parameter of an allocated buffer in the pool.** @param ref a buffer reference to a buffer returned by av_buffer_pool_get.* @return the opaque parameter set by the buffer allocator function of the* buffer pool.** @note the opaque parameter of ref is used by the buffer pool implementation,* therefore you have to use this function to access the original opaque* parameter of an allocated buffer.*/
void *av_buffer_pool_buffer_get_opaque(AVBufferRef *ref);
使用的流程就是上面几个函数。
文章开头也说了,hwcontext_cuda.c中使用AVBufferPool,其实是AVHWFramesContext
里面有一个bufferpool.它的使用。