当前位置:网站首页>FFMPEG关键结构体——AVFrame
FFMPEG关键结构体——AVFrame
2022-07-05 23:56:00 【陈小帅hh】
一、AVFrame结构体
AVFrame结构体一般用于存储原始数据(即非压缩数据,例如对视频来说是YUV,RGB,对音频来说是PCM),此外还包含了一些相关的信息。
比如说,解码的时候存储了宏块类型表,QP表,运动矢量表等数据。编码的时候也存储了相关的数据。因此在使用FFMPEG进行码流分析的时候,AVFrame是一个很重要的结构体。
AVFramet通常在解码时包含较多的码流参数,编码时主要用于承载图像数据或者音频采样数据。结构体的定义位于libavutil/frame.h,这里介绍解码情况下的主要变量
1.变量介绍
①uint8_t *data[AV_NUM_DATA_POINTERS];
(1)图像数据:
对于packed格式的数据(例如RGB24),会存到data[0]里面。
对于planar格式的数据(例如YUV420P),则会分开成data[0],data[1],data[2]…(YUV420P中data[0]存Y,data[1]存U,data[2]存V)
(2)音频数据:
采样数据PCM, 保存方式同图像数据。 对于对于planar格式的音频数据通道数超过8时,其余通道数据存放于extended_data中。
②int linesize[AV_NUM_DATA_POINTERS];
行字节的跨度,相当于stride。对于data[i]区域中的一行像素占用的字节数,对于RGB24理论是{wh3, 0, …}; 对于yuv420p,理论是{w, w/2, w/2, 0, …}。但ffmpeg内存会填充对齐,实际行字节数会大于等于理论值。
③enum AVPictureType pict_type;
帧数据类型,部分摘取如下
二、常用函数介绍
1、av_frame_alloc()
申请AVFrame结构体空间,同时会对申请的结构体初始化。注意哦,这个函数只是创建AVFrame结构的空间,AVFrame中的uint8_t *data[AV_NUM_DATA_POINTERS]空间此时NULL,不会创建的。
2、av_frame_free()
释放AVFrame的结构体空间。这个函数就有点意思了。因为他不仅仅释放结构体空间,还涉及到AVFrame中的uint8_t *data[AV_NUM_DATA_POINTERS];字段的释放问题。,如果AVFrame中的uint8_t *data[AV_NUM_DATA_POINTERS]中的引用==1,则释放data的空间。
3、int av_frame_ref(AVFrame *dst, const AVFrame *src)
对已有AVFrame的引用,这个引用做了两个动作:1、将src属性内容复制到dst,2、对AVFrame中的uint8_t *data[AV_NUM_DATA_POINTERS]字段引用计数+1。
4、void av_frame_unref(AVFrame *frame)
对frame释放引用,做了两个动作:1、将frame的各个属性初始化,2、如果AVFrame中的uint8_t *data[AV_NUM_DATA_POINTERS]中的引用==1,则释放data的空间。当然,如果data的引用计数>1则由别的frame去检测释放。
5、av_frame_get_buffer()
这个函数是建立AVFrame中的uint8_t *data[AV_NUM_DATA_POINTERS]内存空间,使用这个函数之前frame结构中的format、width、height:必须赋值,要不然函数怎么知道创建多少字节的空间呢!
三、常规解码流程使用
3个步骤:
①AVFrame *pFrame = av_frame_alloc()分配一个AVFrame对象,缓冲区data[]未分配。
②使用调用av_receive_frame解码,会对pFrame分配data[]缓冲区并保存解码数据;每一次使用后,必须需要使用av_frame_unref释放缓冲区,否则重复解码会造成内存泄露。
③需要使用av_frame_free 释放整个对象。
AVFrame *pFrame = av_frame_alloc(); // [1]
while(){
…
av_receive_frame(ctx, pFrame);
… // process
av_frame_unref(pFrame); // [2]
}
av_frame_free(pFrame); // [3]
四、图像处理
前面提到,ffmpeg内部编码器对于图像处理部分为了方便优化处理,通常创建的缓冲区比原始图像大,实际有效数据部分只是缓冲区的一部分。这一种优化方案直接反应在linesize上,使用8或16或32字节对齐,取决于平台。
对于分辨率为638*272的视频解码后yuv420p的缓冲区 linsesize为{640,320,320,…},内存布局结构如下图
图中,其中w = 640 , h = 320。可以看到,在三个通道中每一行数据间进行了数据填充,Y区域的行字节数不等于638,U/V区域的行字节数也不等于319。注意观察data[2],data[1],data[0]之间的差值。
如果我们需要yuv三个分量无填充的 yuv420p数据,可以手动分配大小为wh3/2的内存,再从解码后AVFrame的data[]中拷贝出来。
1、分配缓冲区内存
①方法一:使用malloc原生的内存管理方式,
uint8_t yuv_buf = malloc(w*h*3/2);
②方法二:fmpeg内存分配函数
// yuv420p对齐处理 变量
AVFrame *frame_yuv = av_frame_alloc();
// 分配缓冲区,接收转换后yuv420p的1字节对齐数据,分辨率不改变
av_image_alloc(frame_yuv->data, frame_yuv->linesize,
video_decoder_ctx->width, video_decoder_ctx->height, AV_PIX_FMT_YUV420P, 1);
// 对于编码,需要AVFrame有对应的参数
frame_yuv->width = video_decoder_ctx->width;
frame_yuv->height = video_decoder_ctx->height;
frame_yuv->format = AV_PIX_FMT_YUV420P;
③方法三:原生指针加ffmpeg内存分配函数
uint8_t *yuvbuf;
int linesize[4];
av_image_alloc(&yuvbuf, linesize, video_decoder_ctx->width, video_decoder_ctx->height,
AV_PIX_FMT_YUV420P, 1);
④方法四:使用av_frame_get_buffer函数(注意检查内存是否连续)
AVFrame *frame_yuv = av_frame_alloc();
frame_yuv->width = video_decoder_ctx->width;
frame_yuv->height = video_decoder_ctx->height;
frame_yuv->format = AV_PIX_FMT_YUV420P;
// 使用一下函数必须先指定frame的 音频/视频 参数
av_frame_get_buffer(frame_yuv, 1); // align = 0, 由系统选择最优对齐方式
注意,av_frame_get_buffer(frame_yuv, 1); 保证y,u,v分量数据区域是1字节对齐的、连续的,但是y,u,v三个数据区不是1字节对齐、也不是连续的。例如,手动分配100*100尺寸的yuv420的数据分量部分
AVFrame *frame_yuv = av_frame_alloc();
frame_yuv->width = 100;
frame_yuv->height = 100;
frame_yuv->format = AV_PIX_FMT_YUV420P;
av_frame_get_buffer(frame_yuv, 1);
结果如下图,三个分量数据区指针从小到大为 u < y < v,指针之间的间隔不等于wh,也不等于wh/2。
注意:后两种方式一种是使用裸指针,一种借助AVFrame,虽然访问管理缓冲区的方式不同,但是都用到了av_image_alloc,都需要传递缓冲区指针和接收linesize的数组。
边栏推荐
猜你喜欢
What are the functions of Yunna fixed assets management system?
Fiddler Everywhere 3.2.1 Crack
GFS分布式文件系统
XML configuration file (DTD detailed explanation)
Open source CRM customer relationship system management system source code, free sharing
openssl-1.0.2k版本升级openssl-1.1.1p
软件测试工程师必会的银行存款业务,你了解多少?
选择致敬持续奋斗背后的精神——对话威尔价值观【第四期】
Breadth first search open turntable lock
Initialize your vector & initializer with a list_ List introduction
随机推荐
Tips for using pads router
软件测试工程师必会的银行存款业务,你了解多少?
TS type declaration
[Luogu p3295] mengmengda (parallel search) (double)
选择致敬持续奋斗背后的精神——对话威尔价值观【第四期】
C# 反射与Type
云呐|公司固定资产管理系统有哪些?
Qcombox (rewrite) + qcompleter (auto completion, auto loading the drop-down options of qcombox, setting the background color)
Use mapper: --- tkmapper
Spreadjs 15.1 CN and spreadjs 15.1 en
20220703 week race: number of people who know the secret - dynamic rules (problem solution)
Upgrade openssl-1.1.1p for openssl-1.0.2k
How to get all the values stored in localstorage
Fiddler Everywhere 3.2.1 Crack
传输层协议------UDP协议
GFS distributed file system
[online chat] the original wechat applet can also reply to Facebook homepage messages!
QT -- thread
What are the functions of Yunna fixed assets management system?
Russian Foreign Ministry: Japan and South Korea's participation in the NATO summit affects security and stability in Asia