AVBuffer
AVBuffer是FFmpeg内存管理的基础。
AVBuffer表示数据缓冲区本身,不能直接访问。我们可以通过AVFrame提供的接口来操作AVBuffer中的数据。
AVBuffer结构体
struct AVBuffer {
uint8_t *data; /**< data described by this buffer */
int size; /**< size of data in bytes */
/**
引用此缓冲区的现有AVBufferRef实例的数量
*/
atomic_uint refcount;
/**
* 释放数据的回调
*/
void (*free)(void *opaque, uint8_t *data);
/**
* 一个不透明的指针,供释放回调函数使用
*/
void *opaque;
/**
* A combination of AV_BUFFER_FLAG_*
*/
int flags;
/**
* A combination of BUFFER_FLAG_*
*/
int flags_internal;
};
引用计数refcount
AVBuffer结构体中的refcount表示引用计数,当引用计数为0时,AVBuffer占据的内存空间会被自动释放
每当新增一个AVFrame指向AVBuffer时,refcount数量加一。
可以通过int av_frame_ref(AVFrame *dst, const AVFrame *src);增加对AVBuffer的指向。
对于refcount的操作是线程安全的操作,这里使用了全局锁,参考源码如下
static inline intptr_t atomic_fetch_ ## opname(intptr_t *object, intptr_t operand)
{
intptr_t ret;
avpriv_atomic_lock();
ret = *object;
*object = *object op operand;
avpriv_atomic_unlock();
return ret;
}
avpriv_atomic_lock获取一个全局锁,锁持有期间,当前线程是唯一能访问共享资源的线程,防止多线程争抢
avpriv_atomic_unlock释放全局锁
AVFrame
下面这段代码展示了,如何通过AVFrame操作AVBuffer
//初始化AVFrame
static AVFrame* frame = nullptr;
// 打开YUV文件
yuv_file.open("400_300_25.yuv", ios::binary);
if (!yuv_file)
{
QMessageBox::information(this, "Error", "open yuv failed");
return;
}
sdl_width = 400;
sdl_height = 300;
//生成frame对象空间
frame = av_frame_alloc();
frame->width = sdl_width;
frame->height = sdl_height;
frame->format = AV_PIX_FMT_YUV420P;
//手动指定buffer大小,防止32Byte自动对齐导致的花屏
frame->linesize[0] = sdl_width; //Y
frame->linesize[1] = sdl_width/2; //U
frame->linesize[2] = sdl_width/2; //V
//生成图像空间 默认32Byte对齐
auto re = av_frame_get_buffer(frame, 0);
if (re != 0)
{
char buf[1024] = { 0 };
av_strerror(re, buf, sizeof(buf));
cerr << buf << endl;
}
//将yuv_file文件数据写入AVBuffer
//istream& read(char* buffer, streamsize count);
//buffer目标内存地址,count读取的字节数
yuv_file.read((char*)frame->data[0], sdl_width * sdl_height);//Y
yuv_file.read((char*)frame->data[1], sdl_width * sdl_height / 4);//U
yuv_file.read((char*)frame->data[2], sdl_width * sdl_height / 4);//V
AVFrame相关的函数解析
AVFrame *av_frame_alloc(void);
返回一个AVFrame指针,申请了对象的空间,存储的空间并没有申请
int av_frame_get_buffer(AVFrame *frame, int align);
传入AVFrame结构指针,int align用于设置对齐方式 int align传入0时,采用默认对齐方式32Byte
int av_buffer_get_ref_count(const AVBufferRef *buf);
返回AVBuffer结构体中的refcount,引用计数
int av_frame_ref(AVFrame *dst, const AVFrame *src);
设置一个新的AVFrame结构体dst,指向已存在AVFrame结构体src
void av_frame_unref(AVFrame *frame);
解除AVFrame指针对buffer空间的引用,此时函数内部会读取AVBuffer内部的引用计数refcount,如果refcount为0,那么释放AVBuffer
void av_frame_free(AVFrame **frame); 释放AVFrame以及其中自动分配的对象,如果AVFrame指向某个AVBuffer,那么先解除引用,将AVBuffer引用计数refcount减一,再释放AVFrame
AVFrame **frame是一个双指针,因为我们这里要修改AVFrame *frame,AVFrame *frame只能修改所指向的AVBuffer,无法修改AVFrame *frame本身,所以这里使用AVFrame **frame
结尾
感谢阅读!本文主要解析了AVFrame, AVBuffer 的概念及联系,AVBuffer中引用计数的概念和原理,分析了AVFrame常用的API。