目录
引用计数
定义
优点
AVBuffer
AVBufferRef
av_buffer_create
av_buffer_ref
av_buffer_unref
参考:
引用计数
定义
引用计数是一种内存管理的方式,当一份内存可能被多个对象使用,可以通过引用计数的方式实现内存复用。
优点
对于没有GC机制的语言,比如C语言,提供了一种简洁高效的内存管理方式。以ffmpg为例,使用av_buffer_create()在创建buffer的时候,引用计数为1,当有module调用av_buffer_ref()对其引用时,引用计数+1,调用av_buf_unref时,引用计数减1。av_buf_unref引用计数减1后会内部检查当前buffer的引用计数,如果变为1就会自动释放buffer。引用计数机制降低了内存浪费、实现了内存的自动销毁。
AVBuffer
AVBuffer指向数据本身,usr不应该直接使用AVBuffer操作数据,而应该使用AVBufferRef(对AVBuffer的封装)来操作数据。
定义来自ffmpeg5.1。ffmpeg\libavutil\buffer.h、ffmpeg\libavutil\buffer_internal.h
/**
* The buffer was av_realloc()ed, so it is reallocatable.
*/
#define BUFFER_FLAG_REALLOCATABLE (1 << 0)
/**
* The AVBuffer structure is part of a larger structure
* and should not be freed.
*/
#define BUFFER_FLAG_NO_FREE (1 << 1)
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,内部指针,供free使用
*/
void *opaque;
/**
* A combination of AV_BUFFER_FLAG_*,通常置为AV_BUFFER_FLAG_READONLY,表示是否只读
* av_buffer_is_writable就是判断这个标志位
*/
int flags;
/**
* A combination of BUFFER_FLAG_*,可能等于BUFFER_FLAG_NO_FREE、在av_buf_unref里使用
*/
int flags_internal;
};
AVBufferRef
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.指向数据的指针,只有av_buffer_is_writable() returns
* 1才可写。
*/
uint8_t *data;//=AVBuffer->data,这两个指针相同
/**
* Size of data in bytes.
*/
size_t size;//=AVBuffer->size,这两个指针相同
} AVBufferRef;
av_buffer_create
AVBufferRef的成员data,size=AVBuffer的data、size。详见av_buffer_create和buffer_create定义。av_buffer_crate的过程申请了AVBuffer,AVBufferRef的内存,将用户传入的free函数指针进行赋值,代码比较清晰。
static AVBufferRef *buffer_create(AVBuffer *buf, uint8_t *data, size_t size,
void (*free)(void *opaque, uint8_t *data),
void *opaque, int flags)
{
AVBufferRef *ref = NULL;
buf->data = data;
buf->size = size;
buf->free = free ? free : av_buffer_default_free;
buf->opaque = opaque;
atomic_init(&buf->refcount, 1); //原子操作,引用计数初始化为1
buf->flags = flags;
ref = av_mallocz(sizeof(*ref));
if (!ref)
return NULL;
ref->buffer = buf;
ref->data = data;//AVBuffer的data和AVBufferRef指向相同
ref->size = size;
return ref;
}
AVBufferRef *av_buffer_create(uint8_t *data, size_t size,
void (*free)(void *opaque, uint8_t *data),
void *opaque, int flags)
{
AVBufferRef *ret;
AVBuffer *buf = av_mallocz(sizeof(*buf));
if (!buf)
return NULL;
ret = buffer_create(buf, data, size, free, opaque, flags);
if (!ret) {
av_free(buf);
return NULL;
}
return ret;
}
av_buffer_ref
av_buffer_ref申请了AVBufferRef的结构体大小内存,并把指向的data引用计数加1。
AVBufferRef *av_buffer_ref(const AVBufferRef *buf)
{
AVBufferRef *ret = av_mallocz(sizeof(*ret));
if (!ret)
return NULL;
*ret = *buf;
atomic_fetch_add_explicit(&buf->buffer->refcount, 1, memory_order_relaxed);
return ret;
}
av_buffer_unref
av_buffer_unref,将当前的AVBufferRef指针指向的内存释放,并对AVBufferRef指向的数据引用计数减1,如果当前数据的引用计数=1,数据内存释放。
static void buffer_replace(AVBufferRef **dst, AVBufferRef **src)
{
AVBuffer *b;
b = (*dst)->buffer;
if (src) {
**dst = **src;
av_freep(src);
} else
av_freep(dst);
if (atomic_fetch_sub_explicit(&b->refcount, 1, memory_order_acq_rel) == 1) {
/* b->free below might already free the structure containing *b,
* so we have to read the flag now to avoid use-after-free. */
int free_avbuffer = !(b->flags_internal & BUFFER_FLAG_NO_FREE);
b->free(b->opaque, b->data);
if (free_avbuffer)
av_free(b);
}
}
void av_buffer_unref(AVBufferRef **buf)
{
if (!buf || !*buf)
return;
buffer_replace(buf, NULL);
}
参考:
深入理解FFMPEG-AVBuffer/AVBufferRef/AVBufferPool_流媒体程序员的博客-CSDN博客_ffmpeg abuffer