三、FFMPEG源码(结构体)


记录自己学习 ffmpeg 的过程

一、结构体

  1. 解协议(http,rtsp,rtmp,mms)
    AVIOContext,URLProtocol,URLContext主要存储视音频使用的协议的类型以及状态。URLProtocol存储输入视音频使用的封装格式。每种协议都对应一个URLProtocol结构。(注意:FFMPEG中文件也被当做一种协议“file”)
  2. 解封装(flv,avi,rmvb,mp4)
    AVFormatContext主要存储视音频封装格式中包含的信息;AVInputFormat存储输入视音频使用的封装格式。每种视音频封装格式都对应一个AVInputFormat 结构。
  3. 解码(h264,mpeg2,aac,mp3)
    每个AVStream存储一个视频/音频流的相关数据;每个AVStream对应一个AVCodecContext,存储该视频/音频流使用解码方式的相关数据;每个AVCodecContext中对应一个AVCodec,包含该视频/音频对应的解码器。每种解码器都对应一个AVCodec结构。
  4. 存数据
    视频的话,每个结构一般是存一帧;音频可能有好几帧
    解码前数据: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;

二、引用

FFMPEG中最关键的结构体之间的关系
FFmpeg一些结构体

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值