文章目录
记录自己学习 ffmpeg 的过程
一、结构体
- 解协议(http,rtsp,rtmp,mms)
AVIOContext,URLProtocol,URLContext主要存储视音频使用的协议的类型以及状态。URLProtocol存储输入视音频使用的封装格式。每种协议都对应一个URLProtocol结构。(注意:FFMPEG中文件也被当做一种协议“file”) - 解封装(flv,avi,rmvb,mp4)
AVFormatContext主要存储视音频封装格式中包含的信息;AVInputFormat存储输入视音频使用的封装格式。每种视音频封装格式都对应一个AVInputFormat 结构。 - 解码(h264,mpeg2,aac,mp3)
每个AVStream存储一个视频/音频流的相关数据;每个AVStream对应一个AVCodecContext,存储该视频/音频流使用解码方式的相关数据;每个AVCodecContext中对应一个AVCodec,包含该视频/音频对应的解码器。每种解码器都对应一个AVCodec结构。 - 存数据
视频的话,每个结构一般是存一帧;音频可能有好几帧
解码前数据:AVPacket
解码后数据:AVFrame
1.1 AVCodec 结构体
AVCodec 是存储解码器信息的结构体,表示音视频编解码器,着重于功能函数,一种媒体类型对应一个AVCodec 结构,在程序运行时有多个实例。next 变量用于把所有支持的编解码器连接成链表,便于遍历查找;id 确定了 唯 一编 解 码器 ; priv_data_size 表示具 体 的 Codec 对应的 Context 结构大 小 ,比 如 MsrleContext 或 TSContext,这些具体的结够定义散落于各个.c 文件中,为避免太多的 if else 类语句判断类型再计算大小,这里 就直接指明大小,因为这是一个编译时静态确定的字段,所以放在 AVCodec 而不是 AVCodecContext 中
typedef struct AVCodec
{
const char *name; // 标示 Codec 的名字, 比如 h264
enum CodecType type; // 标示 Codec 的类型,有 video ,audio 等类型
enum CodecID id; // 标示 Codec 的 ID,有 CODEC_ID_H264 等
int priv_data_size; // 标示具体的 Codec 对应的 Context 的 size,如:H264Context
// 以下标示 Codec 对外提供的操作,每一种解码器都会实现这些操作
int(*init)(AVCodecContext*);
int(*encode)(AVCodecContext *, uint8_t *buf, int buf_size, void *data);
int(*close)(AVCodecContext*);
int(*decode)(AVCodecContext *, void *outdata, int *outdata_size, uint8_t *buf, int buf_size);
struct AVCodec *next;
}AVCodec;
例如: H264 的主要结构的初始化如下:
AVCodec ff_h264_decoder =
{
"h264",
AVMEDIA_TYPE_VIDEO,
CODEC_ID_H264,
sizeof(H264Context),
ff_h264_decode_init,
NULL,
ff_h264_decode_end,
decode_frame
}
1.2 AVCodecContext 结构体
AVCodecContext 是描述解码器上下文的数据结构,表示程序运行的当前 Codec 使用的上下文,着重于所有 Codec 共有的属性和关联其他结构的字段。extradata 和 extradata_size 两个字段表述了相应 Codec 使用的私有数据;codec 字段关联相应的编解码器;priv_data 字段关联各个具体编解码器独有的属性 context,和 AVCodec 结构中的 priv_data_size 配对使用
typedef struct AVCodecContext
{
int bit_rate;
int frame_number;
unsigned char *extradata; //扩展数据,如 mov 格式中 audio trak 中 aac 格式中 esds 的附加解码信息
int extradata_size; //扩展数据的 size
int width, height; //视频的原始的宽度与高度
enum PixelFormat pix_fmt; //视频一帧图像的格式,如 YUV420
int sample_rate; //音频的采样率
int channels; //音频的声道的数目
int bits_per_sample;
int block_align;
struct AVCodec *codec; // 指向相应的解码器,如:ff_h264_decoder
void *priv_data; //指向具体相应的解码器的 context,如 H264Context
//公共操作函数
int(*get_buffer)(struct AVCodecContext *c, AVFrame *pic);
void(*release_buffer)(struct AVCodecContext *c, AVFrame *pic);
int(*reget_buffer)(struct AVCodecContext *c, AVFrame *pic);
}AVCodecContext;
1.3 AVInputFormat 结构体
AVInputFormat 结构体表示输入文件容器格式,着重于功能函数,在程序运行时有多个实例。next 变量用于把所有支持的输入文件容器格式连接成链表,便于遍历查找。priv_data_size 标示具体的文件容器格式对应的 Context 的大小
typedef struct AVInputFormat
{
const char *name; // 标示 format 的名字, 比如,“mov” “mp4” 等。
int priv_data_size; // 标示具体的 format 对应的 Context 的 size,如:MovContext。
//具体的操作函数
int(*read_probe)(AVProbeData*);
int(*read_header)(struct AVFormatContext *,AVFormatParameters *ap);
int(*read_packet)(struct AVFormatContext *, AVPacket *pkt);
int(*read_close)(struct AVFormatContext*);
struct AVInputFormat *next;
} AVInputFormat;
例如mov 或 mp4 的主要结构的初始化如下:
AVInputFormat ff_mov_demuxer =
{
"mov,mp4,m4a,3gp,3g2,mj2",
NULL_IF_CONFIG_SMALL("QuickTime/MPEG-4/Motion JPEG 2000 format"),
sizeof(MOVContext),
mov_probe,
mov_read_header,
mov_read_packet,
mov_read_close,
mov_read_seek,
}
1.4 AVFormatContext 结构体
AVFormatContext 结构体主要存储视音视频封装格式中包含的信息,是其它输入、输出相关信息的一个容器。它描述媒体文件或媒体流构成和基本信息,封装格式上下文结构体,也是统领全局的结构体,保存了音视频文件封装格式相关信息
1. 作为输入容器时 struct AVInputFormat *iformat; 不能为空,
其中包含了输入文件的音视频流信息,程序从输入容器从读出音视频包进行解码处理
2. 作为输出容器时 struct AVOutputFormat *oformat; 不能为空,
程序把编码好的音视频包写入到输出容器中
AVFormatContext 结构表示程序运行的当前文件容器格式使用的上下文,着重于所有文件容器共有的属性(并且是在程序运行时才能确定其值)和关联其他结构的字段。iformat 字段关联相应的文件容器格式;pb 关联广义的输入文件;streams 关联音视频流;priv_data 字段关联各个具体文件容器独有的属性上下文,和 priv_data_size 配对使用
typedef struct AVFormatContext
{
struct AVInputFormat *iformat; //指向 AVInputFormat,如对于 mp4 或 mov 为 ff_mov_demuxer
struct AVOutputFormat *oformat;
void *priv_data; // 指向具体的格式对应的 Context,如:MovContext
ByteIOContext pb; //指向数据读取统一接口 context
int nb_streams; //流的数目
AVStream *streams[MAX_STREAMS]; //至少 2 个指针元素分别指向 video stream 和 audio stream
} AVFormatContext;
1.5 MovContext
MOVContext 结构体定义了 mp4 流的一些属性
typedef struct MovContext
{
AVFormatContext *fc; //临时持有 AVFormatContext 的指针
int time_scale; //时间缩放因子
int64_t duration; //视频的时长
int found_moov; //拆包时是否发现”moov“头
int found_mdat; //拆包时是否发现"mdat"头
int isom;
MOVFragment fragment;
MOVTrackExt *trex_data;
unsigned trex_count;
int itunes_metadata; //metadata are itunes style
int chapter_track;
} MOVContext;
1.6 URLProtocol 结构体
URLProtocol 结构体存储视音频使用的协议的类型以及状态,表示广义的输入文件,着重于功能函数,一种广义的输入文件对应一个 URLProtocol 结构,比如 file,pipe,tcp 等等,定义了对 file tcp 等方式的通用模板函数。next 变量用于把所有支持的广义的输入文件连接成链表,便于遍历查找
typedef struct URLProtocol
{
const char *name;
//用的统一的模板函数
int(*url_open)(URLContext *h, const char *filename, int flags);
int(*url_read)(URLContext *h, unsigned char *buf, int size);
int(*url_write)(URLContext *h, unsigned char *buf, int size);
offset_t(*url_seek)(URLContext *h, offset_t pos, int whence);
int(*url_close)(URLContext *h);
struct URLProtocol *next;
} URLProtocol;ffurl_connect
例如:file 可初始化如下:
URLProtocol ff_file_protocol =
{
.name = "file",
.url_open = file_open,
.url_read = file_read,
.url_write = file_write,
.url_seek = file_seek,
.url_close = file_close,
.url_get_file_handle = file_get_handle,
.url_check = file_check,
}
1.7 URLContext 结构体
URLContext 结构体存储视音频使用的协议的类型以及状态,表示程序运行的当前广义输入文件使用的 context,着重于所有广义输入文件共有的属性。prot 字段关联相应的广义输入文件;priv_data 字段关联各个具体广义输入文件的句柄
typedef struct URLContext
{
struct URLProtocol *prot; //指向相应的协议(协议为从初始化链表中注册的),如 ff_file_protocol
int flags;
int max_packet_size;
void *priv_data; //相应通信方式的句柄,对于文件为 fd 句柄,对于网络为 socket 句柄等
char *filename; //文件的名字,不区分本地和网络
} URLContext
1.8 AVIOContext 结构体
AVIOContext 结构体表示 I/O 上下文,通过对该变量赋值可以改变输入源或输出目的,存储视音频使用的协议的类型以及状态。定义的主要是缓冲区相关字段,标记字段,和一个关联字段 opaque 来完成广义文件读写操作。opaque 关联字段用于关联 URLContext 结构,间接关联并扩展 URLProtocol 结构
typedef struct ByteIOContext
{
unsigned char *buffer; //数据缓冲区
int buffer_size; //数据缓冲 size
unsigned char *buf_ptr, *buf_end; //数据读取标记指针
void *opaque; //该指针指向相应的 URLContext,关联 URLContext
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size);
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size);
offset_t(*seek)(void *opaque, offset_t offset, int whence);
offset_t pos; //当前 buffer 在文件中的位置
int must_flush; //表示要进行 seek,冲刷数据
int eof_reached; //是否到达了文件末尾, true if eof reached
int write_flag;
int max_packet_size;
int error; // contains the error code or 0 if no error happened
} ByteIOContext;
1.9 AVStream 结构体
AVStream 结构体当前媒体流的上下文,每个视频(音频)流对应一个该结构体,着重于所有媒体流共有的属性。actx 字段关联当前音视频媒体使用的编解码器的 context priv_data 字段关联解析各个具体媒体流解复用拆包用的 context;还有关键帧的索引表也存于此
typedef struct AVStream
{
AVCodecContext *actx; //指向解码器 context,用于关联解码器
struct AVCodecParserContext *parser; //codec 解析器,每一种编码器在进行压缩时都会对实际负载数据进行封装,加入头信息,如 h264,需要解析 nal 单元,关联通过 avav_find_stream_info()
void *priv_data; //指向解复用的流的 context,比如 mp4 的 MovStreamcontext
AVRational time_base;
AVIndexEntry *index_entries; //用于 seek 时使用,用于快速索引关键帧,如 flv 的 keyframes 索引表和 mp4 的 I 帧的索引表都存于此,很重要
int nb_index_entries; //index_entries 的元素的个数
int index_entries_allocated_size;
double frame_last_delay;
} AVStream;
1.10 MOVStreamContext 结构体
MOVStreamContext 结构用于保存从 mov 或 mp4 中进行拆包解复用从头部得到的信息
typedef struct MOVStreamContext
{
int ffindex; //流的索引,0 或者 1
int next_chunk; //临时变量,保存下一个 chunk 块的编号
unsigned int chunk_count; //chunk 的个数(在 mp4 的文件格式中,从 stco 中取值肯定为 chunk 的总数)
int64_t *chunk_offsets; //chunk 在文件中的偏移量数组(每个 chunk 中的 sample 在文件中的物理存储是连续的,用于保存 scto 表
unsigned int stts_count; //stts 的元素的个数
MOVStts *stts_data; //stts 时间数据表
unsigned int ctts_count;//ctts(用于在有 B 帧混合时进行纠正时间戳)的元素的个数
MOVStts *ctts_data; //ctts 数据表
unsigned int stsc_count; //stsc(空间分布表)的元素的个数
MOVStsc *stsc_data; //stsc 数据表
int ctts_index; //临时变量,记录当前使用的 ctts 表的索引
int ctts_sample; //记录当前的 ctts 元素作用的 sample 的索引
unsigned int sample_size; //stsz 表中可能 smaple 的 size 相同,如果相同使用该值
unsigned int sample_count; //sample 的个数
int *sample_sizes; //stsz 数据表,记录每个 sample 的 size,如果 sample_size=0,该表才不会 //空
unsigned int keyframe_count; //stss(关键帧索引表)中元素的个数
int *keyframes; //关键帧数据表
unsigned drefs_count; //dref 的元素的个数,一般为 1
MOVDref *drefs; //dref 数据表
int width; //tkhd 宽度
int height; //tkhd 高度
} MOVStreamContext;
1.11 AVPacket 结构体
AVPacket 结构体代表音视频数据帧,固有的属性是一些标记,时钟信息,和压缩数据首地址,大小等信息,保存了解复用之后,解码之前的数据(仍然是压缩后的数据)和关于这些数据的一些附加信息,如显示时间戳(pts)、解码时间戳(dts)、数据时长,所在媒体流的索引等
typedef struct AVPacket
{
int64_t pts; //显示时间戳
int64_t dts; //解码时间戳
int64_t pos; //记录在文件或网络中的流中的字节的位置
uint8_t *data; //实际数据指针
int size; //实际的数据的大小
int stream_index; //该 packet 所属的流的索引,一般为 0 或者 1
int flags;
void(*destruct)(struct AVPacket*); //析构函数
} AVPacket;
1.12 AVPacketList 结构体
AVPacketList 结构体把音视频 AVPacket 组成一个小链表
typedef struct AVPacketList
{
AVPacket pkt;
struct AVPacketList *next;
} AVPacketList;
1.13 AVFrame 结构体
AVFrame 结构体存储一帧解码后像素(采样)数据,一般用于存储原始数据(即非压缩数据,例如对视频来说是 YUV,RGB,对音频来说是 PCM)。此外还包含了一些相关的信息,例如解码的时候存储了宏块类型表,QP 表,运动矢量表等数据;编码的时候也存储了相关的数据
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; //是否是关键帧
enum AVPictureType pict_type; //帧类型(I,B,P)
uint8_t *base[AV_NUM_DATA_POINTERS];
AVRational sample_aspect_ratio;
int64_t pts;
int64_t pkt_pts;
int64_t pkt_dts;
int coded_picture_number;
int display_picture_number;
int quality;
int reference;
int8_t *qscale_table; //QP 表
int qstride;
int qscale_type;
uint8_t *mbskip_table; //跳过宏块表
int16_t (*motion_val[2])[2]; //运动矢量表
uint32_t *mb_type; //宏块类型表
short *dct_coeff; //DCT 系数
int8_t *ref_index[2]; //参考帧列表
void *opaque;
uint64_t error[AV_NUM_DATA_POINTERS];
int type;
int repeat_pict;
int interlaced_frame;
int top_field_first;
int palette_has_changed;
int buffer_hints;
AVPanScan *pan_scan;
int64_t reordered_opaque;
void *hwaccel_picture_private;
struct AVCodecContext *owner;
void *thread_opaque;
uint8_t motion_subsample_log2;
int sample_rate; //音频采样率
uint64_t channel_layout;
int64_t best_effort_timestamp;
int64_t pkt_pos;
int64_t pkt_duration;
AVDictionary *metadata;
int decode_error_flags;
#define FF_DECODE_ERROR_INVALID_BITSTREAM 1
#define FF_DECODE_ERROR_MISSING_REFERENCE 2
int64_t channels;
} AVFrame;