FFmpeg 借助 struct AVBuffer
和 struct AVBufferRef
以及相关 API 实现了引用计数功能。
结构体定义
struct AVBuffer
目前共包含七个成员变量,从功能上可以划分为三部分:
- 数据部分
uint8_t *data
和size_t size
:指向一段长度为size
的内存。void *opaque
:一个指针,指向一个用户自定义类型的对象,也可为空,FFmpeg 不关心。void (*free)(void *opaque, uint8_t *data)
:函数指针,用于释放data
和opaque
。
- 计数部分:
atomic_uint refcount
:引用计数,配合AVBufferRef
使用,记录有多少个AVBufferRef
对象引用了自己。
- 辅助部分:
int flags
和int flags_internal
:一些用于描述自身状态的标志变量。
完整定义如下:
struct AVBuffer {
uint8_t *data; /**< data described by this 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;
};
struct AVBufferRef
更为简单,仅包含三个变量:
AVBuffer *buffer
:引用的AVBuffer
对象。uint8_t *data
和size_t size
:指向一段长度为size
的内存。其值与buffer->data
和buffer->size
相同。
typedef struct AVBufferRef {
AVBuffer *buffer;
/**
* The data buffer. It is considered writable if and only if
* this is the only reference to the buffer, in which case
* av_buffer_is_writable() returns 1.
*/
uint8_t *data;
/**
* Size of data in bytes.
*/
size_t size;
} AVBufferRef;
相关函数
创建新的 AVBufferRef
对象
av_buffer_alloc / av_buffer_allocz
创建一个新的 struct AVbufferRef
对象。
/**
* Allocate an AVBuffer of the given size using av_malloc().
*
* @return an AVBufferRef of given size or NULL when out of memory
*/
AVBufferRef *av_buffer_alloc(size_t size);
/**
* Same as av_buffer_alloc(), except the returned buffer will be initialized
* to zero.
*/
AVBufferRef *av_buffer_allocz(size_t size);
av_buffer_alloc
会调用三次 av_malloc
:
- 分配一段长度为
size
的内存,供用户使用。 - 分配一段长度为
sizeof(AVBuffer)
的内存,存储AVBuffer
对象。 - 分配一段长度为
sizeof(AVBufferRef)
的内存,存储AVBufferRef
对象。
av_buffer_allocz
与 av_buffer_alloc
类似,只是会将长度为 size
的内存全部值为 0
。
此时三部分内存的状态如下图:
av_buffer_create
新创建一个 AVBufferRef
对象,并使其维护一段用户分配的内存。
/**
* Create an AVBuffer from an existing array.
*
* If this function is successful, data is owned by the AVBuffer. The caller may
* only access data through the returned AVBufferRef and references derived from
* it.
* If this function fails, data is left untouched.
* @param data data array
* @param size size of data in bytes
* @param free a callback for freeing this buffer's data
* @param opaque parameter to be got for processing or passed to free
* @param flags a combination of AV_BUFFER_FLAG_*
*
* @return an AVBufferRef referring to data on success, NULL on failure.
*/
AVBufferRef *av_buffer_create(uint8_t *data, size_t size,
void (*free)(void *opaque, uint8_t *data),
void *opaque, int flags);
维护引用
av_buffer_ref
AVBufferRef *av_buffer_ref(const AVBufferRef *buf);
仅会调用一次 av_malloc
:
分配一段长度为size
的内存,供用户使用。分配一段长度为sizeof(AVBuffer)
的内存,存储AVBuffer
对象。- 分配一段长度为
sizeof(AVBufferRef)
的内存,存储AVBufferRef
对象。
新的 AVBufferRef
对象和 buf
共享一个 AVBuffer
对象。
该函数会使 buf->buffer->refcount
的值加一。
/**
* Create a new reference to an AVBuffer.
*
* @return a new AVBufferRef referring to the same AVBuffer as buf or NULL on
* failure.
*/
AVBufferRef *av_buffer_ref(const AVBufferRef *buf);
av_buffer_unref
av_buffer_unref
与 av_buffer_ref
相反。
void av_buffer_unref(AVBufferRef **buf);
做两件事:
- 释放内存:调用
av_free
释放AVBufferRef
对象自身占用的内存。 - 维护引用:将引用计数减一,如果减一后其值为
0
,则调用buffer->free
,然后将buffer
的内存释放。
/**
* Free a given reference and automatically free the buffer if there are no more
* references to it.
*
* @param buf the reference to be freed. The pointer is set to NULL on return.
*/
void av_buffer_unref(AVBufferRef **buf);
是否可写
av_buffer_is_writable
当且仅当 buf->buffer->refcount
为 1
且 buf->buffer->flag
为设置 AV_BUFFER_FLAG_READONLY
。
/**
* @return 1 if the caller may write to the data referred to by buf (which is
* true if and only if buf is the only reference to the underlying AVBuffer).
* Return 0 otherwise.
* A positive answer is valid until av_buffer_ref() is called on buf.
*/
int av_buffer_is_writable(const AVBufferRef *buf);
av_buffer_make_writable
借助 av_buffer_make_writable
函数,可将 AVBufferRef
值为可写状态。
如果传入的 AVBufferRef
不可写,则会新分配一段内存,并进行数据拷贝。换言之,此时已与不可写的 AVBuffer
对象解除引用啦。
/**
* Create a writable reference from a given buffer reference, avoiding data copy
* if possible.
*
* @param buf buffer reference to make writable. On success, buf is either left
* untouched, or it is unreferenced and a new writable AVBufferRef is
* written in its place. On failure, buf is left untouched.
* @return 0 on success, a negative AVERROR on failure.
*/
int av_buffer_make_writable(AVBufferRef **buf);
其他
av_buffer_realloc
重新分配指定长度的内存。
/**
* Reallocate a given buffer.
*
* @param buf a buffer reference to reallocate. On success, buf will be
* unreferenced and a new reference with the required size will be
* written in its place. On failure buf will be left untouched. *buf
* may be NULL, then a new buffer is allocated.
* @param size required new buffer size.
* @return 0 on success, a negative AVERROR on failure.
*
* @note the buffer is actually reallocated with av_realloc() only if it was
* initially allocated through av_buffer_realloc(NULL) and there is only one
* reference to it (i.e. the one passed to this function). In all other cases
* a new buffer is allocated and the data is copied.
*/
int av_buffer_realloc(AVBufferRef **buf, size_t size);
av_buffer_replace
改变引用。
/**
* Ensure dst refers to the same data as src.
*
* When *dst is already equivalent to src, do nothing. Otherwise unreference dst
* and replace it with a new reference to src.
*
* @param dst Pointer to either a valid buffer reference or NULL. On success,
* this will point to a buffer reference equivalent to src. On
* failure, dst will be left untouched.
* @param src A buffer reference to replace dst with. May be NULL, then this
* function is equivalent to av_buffer_unref(dst).
* @return 0 on success
* AVERROR(ENOMEM) on memory allocation failure.
*/
int av_buffer_replace(AVBufferRef **dst, const AVBufferRef *src);