FFMpeg的AVFrame数据格式解析
一、什么是AVFrame
只要使用FFmpeg做解码,必然会使用到AVFrame
结构体,AVFrame主要用于存放音频/视频未压缩的数据。
二、AVFrame
结构体内部
typedef struct AVFrame {
#define AV_NUM_DATA_POINTERS 8
uint8_t *data[AV_NUM_DATA_POINTERS]; // 存放媒体数据的指针数组
int linesize[AV_NUM_DATA_POINTERS]; // 视频或音频帧数据的行宽
uint8_t **extended_data; // 音频或视频数据的指针数组
int width, height; // 视频帧的宽和高
int nb_samples; // 当前帧的音频采样数(每个通道)
int format; // 视频帧的像素格式或音频的采样格式
int key_frame; // 当前帧是否为关键帧,1表示是,0表示不是
AVRational sample_aspect_ratio; // 视频帧的样本宽高比
int64_t pts; // 以time_base为单位的呈现时间戳
int64_t pkt_dts; // 从AVPacket复制而来的dts时间
int coded_picture_number; // 按解码先后排序的解码图像数
int display_picture_number; // 按显示前后排序的显示图像数
int quality; // 帧质量,从1到FF_LAMBDA_MAX之间取值
void *opaque; // 用户的私有数据
int interlaced_frame; // 图片的内容是否为隔行扫描
int top_field_first; // 如果内容是隔行扫描的,是否首先显示顶部字段
int sample_rate; // 音频数据的采样率
uint64_t channel_layout; // 音频数据的通道布局
AVBufferRef *buf[AV_NUM_DATA_POINTERS]; // AVBuffer引用,当前帧数据
AVBufferRef **extended_buf; // AVBufferRef的指针
int nb_extended_buf; // extended_buf的数量
enum AVColorSpace colorspace; // YUV颜色空间类型
int64_t best_effort_timestamp; // 算法预测的timestamp
int64_t pkt_pos; // 记录上一个AVPacket输入解码器的位置
int64_t pkt_duration; // packet的duration
AVDictionary *metadata; // 元数据
int channels; // 音频的通道数
int pkt_size; // 包含压缩帧的相应数据包的大小
} AVFrame;
三、AVFrame接口函数
- AVFrame *av_frame_alloc(void);
构造一个AVFrame, 对象成员被设为默认值.
此函数只分配AVFrame对象本身, 而不分配AVFrame中的数据缓存区.
- void av_frame_free(AVFrame **frame);
释放AVFrame.
- int av_frame_ref(AVFrame *dst, const AVFrame *src);
为src中的数据建立一个新的引用.
将src中帧的各属性拷到dst中, 并且为src中每个AVBufferRef创建一个新的引用.
如果src未使用引用计数, 则dst中会分配新的数据缓存区, 将src中缓存区的数据拷贝到dst中的缓存区.
- void av_frame_unref(AVFrame *frame);
解除本AVFrame对AVFrame中所有缓存区的引用, 并复位AVFrame中的各成员.
- int av_frame_get_buffer(AVFrame *frame, int align);
为音频或视频数据分配新的缓冲区.
调用本函数前, 帧中的以下成员必须先设置好:
-
- format
- width, height
- nb_samples, channel_layout
本函数会填充AVFrame.data和AVFrame.buf数组, 如果有需要, 还会分配和填充AVFrame.extended_data和AVFrame.extended_buf.
四、实例
#include <iostream>
using namespace std;
extern "C"{ //指定函数是c语言函数,函数名不包含重载标注
//引用ffmpeg头文件
#include <libavcodec/avcodec.h>
}
//预处理指令导入库
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")
int main(int argc, char* argv[])
{cout << "first ffmpeg" << endl;cout << avcodec_configuration() << endl;//创建frame对象auto frame1 = av_frame_alloc();//图像参数frame1->width = 401;frame1->height = 300;frame1->format = AV_PIX_FMT_ARGB;//分配空间 16字节对齐int re = av_frame_get_buffer(frame1, 16);if (re != 0){char buf[1024] = { 0 };av_strerror(re, buf, sizeof(buf));cout << buf << endl;}cout <<"frame1 linesize[0]="<< frame1->linesize[0] << endl;if (frame1->buf[0]){cout << "frame1 ref count = " <<av_buffer_get_ref_count(frame1->buf[0]); // 线程安全cout << endl;}auto frame2 = av_frame_alloc();av_frame_ref(frame2, frame1);cout << "frame1 ref count = " <<av_buffer_get_ref_count(frame1->buf[0]) << endl;cout << "frame2 ref count = " <<av_buffer_get_ref_count(frame2->buf[0]) << endl;//引用计数-1 并将buf清零av_frame_unref(frame2);cout << "av_frame_unref(frame2)" << endl;cout << "frame1 ref count = " <<av_buffer_get_ref_count(frame1->buf[0]) << endl;//引用计数为1 直接删除buf空间 引用计数变为0av_frame_unref(frame1);//释放frame对象空间,buf的引用计数减一//buf已经为空,只删除frame对象空间av_frame_free(&frame1);av_frame_free(&frame2);return 0;
}