ffmpeg定义的数据结构很有特色:有一些是动态与静态的关系,比如, URLProtocol 和 URLContex t ,AVInputFormat 和 AVFormatContext , AVCodec 和 AVCodecContext。从前面播放器的一般原理我们可知,播放器内部要实现的几大功能是,读文件, 识别格式,音视频解码,音视频渲染。其中音视频渲染由 SDL 实现,我们不讨论。ffplay 把其他的每个大功能抽 象成一个相当于 C++ 中 COM 接口的数据结构,着重于功能函数,同时这些功能函数指针在编译的时候就能静态 确定。每一个大功能都要支持多种类型的广义数据,ffplay 把这多种类型的广义数据的共同的部分抽象成对应的 Context 结构,这些对应的 context 结构着重于动态性,其核心成员只能在程序运行时动态确定其值。并且 COM 接口类的数据结构在程序运行时有很多很多实例,而相应的 Context 类只有一个实例,这里同时体现了数据结构 的划分原则,如果有一对多的关系就要分开定义。
有一些是指针表述的排他性包含关系(因为程序运行时同一类型的多种数据只支持一种,所以就有排他性 )。 比如,AVCodecContext 用 priv_data包含 MsrleContext 或 TSContext,AVFormatContext 用 priv_data 包含 AVIContext 或其他类 Context,AVStream 用 priv_data 包含 AVIStream 或其他类 Stream。由前面数据结构的动态与静态关系 可知,ffplay 把多种类型的广义数据的共同部分抽象成 context 结构,那么广义数据的各个特征不同部分就抽象成 各种具体类型的 context,然后用 priv_data 字段表述的指针排他性的关联起来。由于瘦身后的 ffplay 只支持有限 类型,所以 AVFormatContext 只能关联包含 AVIContext,AVStream 只能关联包含 AVIStream。
有一些是扩展包含关系,比如,ByteIOCon text 包含 URLContext ,就是在应用层把没有缓存的 URLContext
扩展有缓冲区的广义文件 ByteIOCon text ,改善程序 IO 性能。
有一些是直接包含关系,比如,AVFrame 包含 AVPicture,这两个结构共有的字段,其定义类型、大小、顺 序都一模一样,除了更准确的描述各自的意义便于阅读理解维护代码外,还可以方便的把 AVFrame 大结构强制 转换 AVPicture 小结构。
我们先来重点分析 AVCodec/AVCodecContext/MsrleContex t 这几个数据结构,这几个数据结构定义了编解码 器的核心架构,相当于 Directshow 中的各种音视频解码器 decoder。
解协议(http,rtsp,rtmp,mms)→解封装(flv,avi,rmvb,mp4)→解码h264,mpeg2,aac,mp3)→存数据
4.1 AVCodec结构体
typedef struct AVCodec
{
// 标示Codec 的名字, 比如,"h264" "h263" 等。
const char *name;
// 标示Codec 的类型,有video ,audio等类型。
enum CodecType type;
// 标示Codec 的ID,有CODEC_ID_H264等。
enum CodecID id;
// 标示具体的Codec 对应的Context 的size,如:H264Context。
int priv_data_size;
// 以下标示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
}
说明:
AVCodec 是类似 COM 接口的数据结构,表示音视频编解码器,着重于功能函数,一种媒体类型对应一个 AVCodec 结构,在程序运行时有多个实例。next 变量用于把所有支持的编解码器连接成链表,便于遍历查找;id 确定了 唯 一编 解 码器 ; priv_data_size 表示具 体 的 Codec 对应的 Context 结构大 小 ,比 如 MsrleContext 或 TSContext,这些具体的结够定义散落于各个.c 文件中,为避免太多的 if else 类语句判断类型再计算大小,这里 就直接指明大小,因为这是一个编译时静态确定的字段,所以放在 AVCodec 而不是 AVCodecContex t 中。
4.2 AVCodecContext结构体
typedef struct AVCodecContext
{
int bit_rate;
int frame_number;
//扩展数据,如mov格式中audio trak中aac格式中esds的附加解码信息。
unsigned char *extradata;
//扩展数据的size
int extradata_size;
//视频的原始的宽度与高度
int width, height; // 此逻辑段仅针对视频
//视频一帧图像的格式,如YUV420
enum PixelFormat pix_fmt;
//音频的采样率
int sample_rate;
//音频的声道的数目
int channels;
int bits_per_sample;
int block_align;
// 指向相应的解码器,如:ff_h264_decoder
struct AVCodec *codec;
//指向具体相应的解码器的context,如H264Context
void *priv_data;
//公共操作函数
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;
说明:
AVCodecContext 结构表示程序运行的当前Codec 使用的上下文,着重于所有Codec 共有的属性(并且是在程序运行时才能确定其值)和关联其他结构的字段。extradata 和extradata_size 两个字段表述了相应Codec 使用的私有数据;codec 字段关联相应的编解码器;priv_data 字段关联各个具体编解码器独有的属性context,和AVCodec 结构中的priv_data_size 配对使用。
4.3 AVInputFormat结构体
typedef struct AVInputFormat
{
// 标示format的名字, 比如,“mov” “mp4” 等。
const char *name;
// 标示具体的format对应的Context 的size,如:MovContext。
int priv_data_size;
//具体的操作函数
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,
}
说明:
AVInputFormat 是类似COM 接口的数据结构,表示输入文件容器格式,着重于功能函数,一种文件容器格式对应一个AVInputFormat 结构,在程序运行时有多个实例。next变量用于把所有支持的输入文件容器格式连接成链表,便于遍历查找。priv_data_size 标示具体的文件容器格式对应的Context的大小,在本例中是MovContext,这些具体的结够定义散落于各个.c 文件中。
4.4 AVFormatContext结构体
typedef struct AVFormatContext
{
//指向AVInputFormat,如对于mp4或mov为ff_mov_demuxer
struct AVInputFormat *iformat;
// 指向具体的格式对应的Context,如:MovContext。
void *priv_data;
//指向数据读取统一接口context
ByteIOContext pb;
//流的数目
int nb_streams;
//至少2个指针元素分别指向video stream和audio stream
AVStream *streams[MAX_STREAMS];
} AVFormatContext;
说明:
AVFormatContext 结构表示程序运行的当前文件容器格式使用的上下文,着重于所有文件容器共有的属性(并且是在程序运行时才能确定其值)和关联其他结构的字段。iformat字段关联相应的文件容器格式;pb 关联广义的输入文件;streams 关联音视频流;priv_data 字段关联各个具体文件容器独有的属性上下文,和priv_data_size 配对使用。
4.5 MovContext结构体
typedef struct MovContext
{
//临时持有AVFormatContext 的指针
AVFormatContext *fc;
//时间缩放因子
int time_scale;
//视频的时长
int64_t duration;
//拆包时是否发现”moov“头
int found_moov;
//拆包时是否发现"mdat"头
int found_mdat;
int isom;
MOVFragment fragment;
MOVTrackExt *trex_data;
unsigned trex_count;
int itunes_metadata; ///< metadata are itunes style
int chapter_track;
} MOVContext;
说明:
MOVContext定义了mp4 中流的一些属性。
4.6 URLProtocol结构体
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,
}
说明:
URLProtocol 是类似COM 接口的数据结构,表示广义的输入文件,着重于功能函数,一种广义的输入文件对应一个URLProtocol 结构,比如file,pipe,tcp 等等,定义了对file tcp等方式的通用模板函数。next 变量用于把所有支持的广义的输入文件连接成链表,便于遍历查找。
4.7 URLContext结构体
typedef struct URLContext
{
//指向相应的协议(协议为从初始化链表中注册的),如ff_file_protocol
struct URLProtocol *prot;
int flags;
int max_packet_size;
//相应通信方式的句柄,对于文件为fd句柄,对于网络为socket句柄等
void *priv_data;
//文件的名字,不区分本地和网络
char *filename;
} URLContext
说明:
URLContext 结构表示程序运行的当前广义输入文件使用的context,着重于所有广义输入文件共有的属性(并且是在程序运行时才能确定其值)和关联其他结构的字段。prot 字段关联相应的广义输入文件;priv_data 字段关联各个具体广义输入文件的句柄。
4.8 AVIOContext结构体(老版本为:ByteIOContext)
typedef struct ByteIOContext
{
//数据缓冲区
unsigned char *buffer;
//数据缓冲size
int buffer_size;
//数据读取标记指针
unsigned char *buf_ptr, *buf_end;
//该指针指向相应的URLContext,关联URLContext
void *opaque;
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);
//当前buffer在文件中的位置
offset_t pos;
//表示要进行seek,冲刷数据
int must_flush;
//是否到达了文件末尾
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;
说明:
ByteIOContext 结构扩展URLProtocol 结构成内部有缓冲机制的广泛意义上的文件,改善广义输入文件的IO性能。由其数据结构定义的字段可知,主要是缓冲区相关字段,标记字段,和一个关联字段opaque 来完成广义文件读写操作。opaque 关联字段用于关联URLContext 结构,间接关联并扩展URLProtocol 结构。
4.9 AVStream结构体
typedef struct AVStream
{
//指向解码器context,用于关联解码器
AVCodecContext *actx;
//codec解析器,每一种编码器在进行压缩时都会对实际负载数据进行封装,加//入头信息,如h264,需要解析nal单元,关联通过avav_find_stream_info()
struct AVCodecParserContext *parser;
//指向解复用的流的context,比如mp4的MovStreamcontext
void *priv_data;
AVRational time_base;
//用于seek时使用,用于快速索引关键帧,如flv的keyframes索引表和mp4的I
//帧的索引表都存于此,很重要
AVIndexEntry *index_entries;
//index_entries的元素的个数
int nb_index_entries;
int index_entries_allocated_size;
double frame_last_delay;
} AVStream;
说明:
AVStream 结构表示当前媒体流的上下文,着重于所有媒体流共有的属性(并且是在程序运行时才能确定其值)和关联其他结构的字段。actx 字段关联当前音视频媒体使用的编解码器的context;priv_data 字段关联解析各个具体媒体流解复用拆包用的context;还有关键帧的索引表也存于此。
4.10 MOVStreamContext 结构体
typedef struct MOVStreamContext {
//流的索引,0或者1
int ffindex;
//临时变量,保存下一个chunk块的编号
int next_chunk;
//chunk的个数(在mp4的文件格式中,从stco中取值肯定为chunk的总数)
unsigned int chunk_count;
//chunk在文件中的偏移量数组(每个chunk中的sample在文件中的物理存储//是连续的),用于保存scto表
int64_t *chunk_offsets;
//stts的元素的个数
unsigned int stts_count;
//stts时间数据表
MOVStts *stts_data;
//ctts(用于在有B帧混合时进行纠正时间戳)的元素的个数
unsigned int ctts_count;
//ctts数据表
MOVStts *ctts_data;
//stsc(空间分布表)的元素的个数
unsigned int stsc_count;
//stsc数据表
MOVStsc *stsc_data;
//临时变量,记录当前使用的ctts表的索引
int ctts_index;
//记录当前的ctts元素作用的sample的索引
int ctts_sample;
//stsz表中可能smaple的size相同,如果相同使用该值
unsigned int sample_size;
//stsz中元素的个数
unsigned int sample_count;//sample的个数
//stsz数据表,记录每个sample的size,如果sample_size=0,该表才不会//空
int *sample_sizes;
//stss(关键帧索引表)中元素的个数
unsigned int keyframe_count;
//关键帧数据表
int *keyframes;
//dref的元素的个数,一般为1
unsigned drefs_count;
//dref数据表
MOVDref *drefs;
//tkhd宽度
int width;
//tkhd高度
int height;
} MOVStreamContext;
说明:
MOVStreamContext结构用于保存从mov或mp4中进行拆包解复用从头部得到的信息。
by: czc1009 《FFmpeg基础库编程开发》
相关推荐
在FFmpeg中,关键的数据结构包括: - **AVFormatContext**: 这是FFmpeg中的核心上下文结构,用于存储有关媒体文件的整体信息,如文件格式、流信息、时间基等。 - **AVStream**: 表示媒体文件中的一个流,可以是...
数据结构章节深入介绍了AVCodec结构体、AVFormatContext结构体等,它们是FFmpeg中处理音视频数据的基础数据结构。 重要模块章节详细解释了libavutil公共模块、libavcodec编解码模块、libavformat容器模块等关键模块...
libavformat用于处理多媒体容器格式,libavcodec则负责编码和解码,libavutil提供了各种通用工具和数据结构,而libavfilter则用于图像和音频处理的滤镜。 在网络摄像头数据获取过程中,FFmpeg通过libavformat的`av_...
解码部分是 FFmpeg 中最重要的一部分,它负责将压缩后的多媒体数据解码为原始数据。该部分包括了多个子模块,如 avformat_open_input()、avformat_find_stream_info()、av_read_frame() 等,这些函数负责读取和解析...
FFmpeg是一款功能强大且广泛使用的多媒体处理库,它提供了丰富的数据结构和函数来处理音视频编解码、文件操作等多种任务。下面我们将对FFmpeg中的主要数据结构和函数进行归类和分析。 一、FFmpeg中的数据结构 1. ...
理解和使用这些步骤需要对音视频编码原理有一定了解,同时也需要熟悉 FFmpeg 的数据结构和接口。通过 "FFmpeg-master" 中的样例代码,你可以更直观地了解这些概念如何在实践中应用,从而更好地掌握 FFmpeg 的使用。
这个"FFmpeg源代码结构图 - 解码.rar"文件很可能包含了一个关于FFmpeg解码流程的详细图示和相关文档,如"FFmpeg源代码结构图 - 解码.docx"以及可能的阅读指南"read.txt"。 FFmpeg的解码过程通常分为以下几个关键...
7. **libavutil**:通用的工具库,包含数学函数、数据结构等。 8. **libswresample**:音频重采样库。 9. **libswscale**:视频缩放和色彩转换库。 FFmpeg 支持的格式广泛,包括但不限于MP4、AVI、MKV、FLV、WMV、...
1. **初始化FFmpeg上下文**:首先,需要创建一个`AVFormatContext`实例,这是FFmpeg处理媒体流的基本结构。通过`avformat_open_input`函数打开RTSP流,并使用`avformat_find_stream_info`获取流信息。 2. **查找...
"simplest_directshow_example.7z"可能提供了DirectShow的简单应用,这是一个微软的多媒体框架,常用于播放和捕获多媒体数据,与FFmpeg配合可以实现更复杂的视频处理流程。 "利用ffmpeg来进行视频解码(H.264).doc...
5. Libavutil:通用工具库,包含数学函数、随机数生成、数据结构等。 二、FFmpeg安装 1. 下载:访问FFmpeg官方网站(https://ffmpeg.org/download.html)下载适合操作系统的预编译版本或源代码。 2. 解压:将下载...
6. **解码视频帧**:使用`avcodec_decode_video2`函数对从文件读取的原始数据进行解码,得到`AVFrame`对象,这是FFmpeg中表示图像的基本结构。 7. **处理解码后的帧**:根据需求,可以对解码后的帧进行各种处理,如...
6. **内存管理**:FFmpeg库中的数据结构通常需要手动分配和释放。使用`av_malloc()`和`av_free()`等函数进行内存管理,遵循FFmpeg的内存管理规则。 7. **错误处理**:在使用FFmpeg API时,务必检查返回值和错误码,...
5. **libavutil**:提供通用的实用函数,如数据结构、随机数生成、数学运算等,是其他模块的基础。 6. **libavdevice**:用于与硬件设备(如摄像头、麦克风)交互,采集或输出音视频数据。 在手册中,你将深入了解...
FFmpeg是一款强大的开源多媒体处理工具,它包含了音视频编解码、转换、流媒体处理等多种功能。本手册基于FFmpeg的官方文档进行了中文翻译,旨在帮助中国用户更好地理解和使用这个工具。 1. FFmpeg基本概念: - ...
4. libavutil:包含通用工具函数,如随机数生成、数据结构管理等,为其他库提供基础支持。 5. libswscale:用于色彩空间转换和像素格式的调整。 6. libswresample:用于音频重采样和声道布局转换。 二、FFmpeg的...
FFmpeg中的关键组件包括: 1. **avcodec.dll**:这是FFmpeg的编码解码库,包含了对多种音频和视频编码格式的支持。在这个版本中,它显然已经更新以支持RMVB解码,允许用户将RMVB文件转换为其他格式,或者将其他格式...