[本文不是自己阅读源码, 摘自雷神的博客]
关键结构体
- AVFormatContext
- AVOutputFormat
- AVInputFormat
- AVCodecContext
- AVCodec
- AVFrame
- AVPacket
- AVPicture
- AVStream
关键函数
-
初始化函数:
- av_register_all()
- avcodec_open()
- avcodec_close()
- av_open_input_file()
- av_find_input_format()
- av_find_stream_info()
- av_close_input_file()
-
音视频编解码函数:
- avcodec_find_decoder()
- avcodec_alloc_frame()
- avpicture_get_size()
- avpicture_fill()
- img_convert()
- avcodec_alloc_context()
- avcodec_decode_video()
- av_free_packet()
- av_free()
-
文件操作:
- avnew_steam()
- av_read_frame()
- av_write_frame()
- dump_format()
-
其他函数:
- avpicture_deinterlace()
- ImgReSampleContext()
分集介绍
AVFormatContext
是一个贯穿始终的数据结构,很多函数都要用到它 作为参数;这个结构体包含了一个视频流的格式内容, 包括 AVInputFormat, AVStream, AVPacket等;
- AVInputFormat *iformat 输入数据的封装格式 执行 avformat_open_input()后, iformat 会被赋值
- AVIOContext *pb 输入数据的缓存
- AVStream **streams 所有流的数组
- unsigned int nb_streams 流的个数(音频流 1 个, 视频流 1 个等其他流)
- char filename[1024] 文件名
- int64_t duration 文件的时长(单位:微秒us,转换为秒需要除以1000000)
- int bit_rate 比特率(单位bps,转换为kbps需要除以1000)
- AVDictionary *metadata 元数据
AVInputFormat
视频的封装格式的一些数据
- const char *name 封装格式名称
- const char *long_name 封装格式的长名称
- const char *extensions 封装格式的扩展名
AVIOContext
输入输出对应的结构体,用于输入输出(读写文件,RTMP协议等)
- unsigned char *buffer 缓存开始位置(buffer用于存储ffmpeg读入的数据。例如打开一个视频文件的时候,先把数据从硬盘读入buffer,然后在送给解码器用于解码。)
- int buffer_size 缓存大小(默认32768)
- unsigned char *buf_ptr 当前指针读取到的位置
- unsigned char *buf_end 缓存结束的位置
- void *opaque URLContext结构体
AVStream
视音频流对应的结构体,用于视音频编解码
- int index 标识该视频/音频流
- AVCodecContext *codec 指向该视频/音频流的AVCodecContext(它们是一一对应的关系)
- AVRational time_base 时基。通过该值可以把PTS,DTS转化为真正的时间。FFMPEG其他结构体中也有这个字段,但是根据我的经验,只有AVStream中的time_base是可用的。PTS*time_base=真正的时间
- int64_t duration 该视频/音频流时长
- AVDictionary *metadata 元数据信息
- AVRational avg_frame_rate 帧率(注:对视频来说,这个挺重要的)
- AVPacket attached_pic 附带的图片。比如说一些MP3,AAC音频文件附带的专辑封面。
AVCodecContext
存储压缩数据(视频对应H.264等码流数据,音频对应AAC/MP3等码流数据)
- num AVMediaType codec_type 编解码器的类型(视频,音频…)
- struct AVCodec *codec 采用的解码器AVCodec(H.264,MPEG2…)
- int bit_rate 平均比特率
- uint8_t *extradata; int extradata_size 针对特定编码器包含的附加信息(例如对于H.264解码器来说,存储SPS,PPS等)
- AVRational time_base 根据该参数,可以把PTS转化为实际的时间(单位为秒s)
- int width, height 如果是视频的话,代表宽和高
- int refs 运动估计参考帧的个数(H.264的话会有多帧,MPEG2这类的一般就没有了)
- int sample_rate 采样率(音频)
- int channels 声道数(音频)
- enum AVSampleFormat sample_fmt 采样格式
- int profile 型(H.264里面就有,其他编码标准应该也有)
- int level 级(和profile差不太多)
AVCodec
编解码器信息的结构体
- const char *name 编解码器的名字,比较短
- const char *long_name 编解码器的名字,全称,比较长
- enum AVMediaType type 指明了类型,是视频,音频,还是字幕
- enum AVCodecID id ID,不重复
- const AVRational *supported_framerates 支持的帧率(仅视频)
- const enum AVPixelFormat *pix_fmts 支持的像素格式(仅视频)
- const int *supported_samplerates 支持的采样率(仅音频)
- const enum AVSampleFormat *sample_fmts 支持的采样格式(仅音频)
- const uint64_t *channel_layouts 支持的声道数(仅音频)
- int priv_data_size 私有数据的大小
AVPacket
存储压缩编码数据相关信息的结构体
- uint8_t *data:压缩编码的数据, 对于H.264来说。1个AVPacket的data通常对应一个NAL。(在这里只是对应,而不是一模一样。他们之间有微小的差别. 因此在使用FFMPEG进行视音频处理的时候,常常可以将得到的AVPacket的data数据直接写成文件,从而得到视音频的码流文件)
- int size:data的大小
- int64_t pts:显示时间戳
- int64_t dts:解码时间戳
- int stream_index:标识该AVPacket所属的视频/音频流。
AVFrame
存储每一个视频/音频流信息的结构体(视频对应RGB/YUV像素数据,音频对应PCM采样数据)
- uint8_t *data[AV_NUM_DATA_POINTERS] 解码后原始数据(对视频来说是YUV,RGB,对音频来说是PCM)对于packet格式,一幅YUV图像的Y、U、V交织存储在一个plane中,形如YUVYUV…,data[0]指向这个plane;
一个双声道的音频帧其左声道L、右声道R交织存储在一个plane中,形如LRLRLR…,data[0]指向这个plane。
对于planar格式,一幅YUV图像有Y、U、V三个plane,data[0]指向Y plane,data[1]指向U plane,data[2]指向V plane;
一个双声道的音频帧有左声道L和右声道R两个plane,data[0]指向L plane,data[1]指向R plane。 - int linesize[AV_NUM_DATA_POINTERS] data中“一行”数据的大小。注意:未必等于图像的宽,一般大于图像的宽。
- int width, height 视频帧宽和高(1920x1080,1280x720…)
- int nb_samples 音频的一个AVFrame中可能包含多个音频帧,在此标记包含了几个
- int format 解码后原始数据类型(YUV420,YUV422,RGB24…)
- int key_frame 是否是关键帧
- enum AVPictureType pict_type 帧类型(I,B,P…)
- AVRational sample_aspect_ratio 宽高比(16:9,4:3…)
- int64_t pts 显示时间戳
- int coded_picture_number 编码帧序号
- int display_picture_number 显示帧序号
- int8_t *qscale_table QP表
- uint8_t *mbskip_table 跳过宏块表
- int16_t (*motion_val[2])[2] 运动矢量表
- uint32_t *mb_type 宏块类型表
- short *dct_coeff DCT系数,这个没有提取过
- int8_t *ref_index[2] 运动估计参考帧列表(貌似H.264这种比较新的标准才会涉及到多参考帧)
- int interlaced_frame 是否是隔行扫描
- uint8_t motion_subsample_log2 一个宏块中的运动矢量采样个数,取log的
函数
av_register_all()
注册所有的组件, 该函数在所有基于ffmpeg的应用程序中几乎都是第一个被调用的。只有调用了该函数,才能使用复用器,编码器等。
avformat_alloc_context(), avio_alloc_context(), avformat_new_stream(), avcodec_alloc_context3(), av_frame_alloc(), av_init_packet();
结构体的初始化
avcodec_find_decoder(), av_find_encoder()
寻找解码编码器
avcodec_open2()
最关键的一步就是调用AVCodec的init()方法初始化具体的编码器
avformat_open_input()
打开输入文件
avformat_find_stream_info()
从文件中提取流信息
av_find_best_stream()
查找传入的流对应的stream_index 就是 传入的流在streams中对应的索引.
av_read_frame()
解码数据
avcodec_decode_video2
读取码流中的音频若干帧或者视频一帧
avcodec_send_packet()
进行解码
avcodec_receive_frame()
获取解码后的数据
avformat_close_input()
关闭一个AVFormatContext,一般情况下是和avformat_open_input()成对使用的。
av_dump_format()
打印流的多媒体信息