前一阵子研究转码的时候看了FFmpeg的源代码。由于ffmpeg.c的代码相对比较长,而且其中有相当一部分是AVFilter有关的代码(这一部分一直不太熟),因此之前学习FFmpeg的时候一直也没有好好看一下其源代码。最近正好看了看AVFilter的知识,顺便就看了下FFmpeg的源代码,在这里画图理一下它的结构。目前好多地方还没有弄明白,等到以后慢慢完善了。
调用了如下函数
av_register_all():注册所有编码器和解码器。
show_banner():打印输出FFmpeg版本信息(编译时间,编译选项,类库信息等)。
parse_options():解析输入的命令。
transcode():转码。
exit_progam():退出和清理。
下图红框中的内容即为show_banner()的输出结果。
parse_options()解析全部输入选项。即将输入命令“ffmpeg -i xxx.mpg -vcodec libx264 yyy.mkv”中的“-i”,“-vcodec”这样的命令解析出来。其函数调用结构如下图所示。
parse_option():解析一个输入选项。具体的解析步骤不再赘述。parse_options()会循环调用parse_option()直到所有选项解析完毕。FFmpeg的每一个选项信息存储在一个OptionDef结构体中。定义如下:
其中的重要字段:
name:用于存储选项的名称。例如“i”,“f”,“codec”等等。
flags:存储选项值的类型。例如:HAS_ARG(包含选项值),OPT_STRING(选项值为字符串类型),OPT_TIME(选项值为时间类型。
u:存储该选项的处理函数。
help:选项的说明信息。
FFmpeg使用一个名称为options,类型为OptionDef的数组存储所有的选项。有一部分通用选项存储在cmdutils_common_opts.h中。cmdutils_common_opts.h内容如下:
先说明一下自己画的结构图的规则:图中仅画出了比较重要的函数之间的调用关系。粉红色的函数是FFmpeg编解码类库(libavcodec,libavformat等)的API。绿色的函数是FFmpeg的libavfilter的API。其他不算很重要的函数就不再列出了。
PS:有一部分代码可能和ffmpeg.c有一些出入。因为本文使用的ffmpeg.c的代码是移植到VC之后的代码。
在看ffmpeg.c的代码之前,最好先看一下简单的代码了解FFmpeg解码,编码的关键API:100行代码实现最简单的基于FFMPEG+SDL的视频播放器
最简单的基于FFMPEG的视频编码器(YUV编码为H.264)
函数调用结构图
FFmpeg的总体函数调用结构图如下图所示
上图所示本是一张高清大图。但是页面显示不下。因此上传了一份:
http://my.csdn.net/leixiaohua1020/album/detail/1788075
上面地址的那张图保存下来的话就是一张清晰的图片了。
下文将会对主要函数分别解析。
main()
main()是FFmpeg的主函数。调用了如下函数
av_register_all():注册所有编码器和解码器。
show_banner():打印输出FFmpeg版本信息(编译时间,编译选项,类库信息等)。
parse_options():解析输入的命令。
transcode():转码。
exit_progam():退出和清理。
下图红框中的内容即为show_banner()的输出结果。
parse_options()
parse_options()解析全部输入选项。即将输入命令“ffmpeg -i xxx.mpg -vcodec libx264 yyy.mkv”中的“-i”,“-vcodec”这样的命令解析出来。其函数调用结构如下图所示。
注:定义位于cmdutils.c中。
parse_option():解析一个输入选项。具体的解析步骤不再赘述。parse_options()会循环调用parse_option()直到所有选项解析完毕。FFmpeg的每一个选项信息存储在一个OptionDef结构体中。定义如下:
- typedef struct OptionDef {
- const char *name;
- int flags;
- #define HAS_ARG 0x0001
- #define OPT_BOOL 0x0002
- #define OPT_EXPERT 0x0004
- #define OPT_STRING 0x0008
- #define OPT_VIDEO 0x0010
- #define OPT_AUDIO 0x0020
- #define OPT_INT 0x0080
- #define OPT_FLOAT 0x0100
- #define OPT_SUBTITLE 0x0200
- #define OPT_INT64 0x0400
- #define OPT_EXIT 0x0800
- #define OPT_DATA 0x1000
- #define OPT_PERFILE 0x2000 /* the option is per-file (currently ffmpeg-only).
- implied by OPT_OFFSET or OPT_SPEC */
- #define OPT_OFFSET 0x4000 /* option is specified as an offset in a passed optctx */
- #define OPT_SPEC 0x8000 /* option is to be stored in an array of SpecifierOpt.
- Implies OPT_OFFSET. Next element after the offset is
- an int containing element count in the array. */
- #define OPT_TIME 0x10000
- #define OPT_DOUBLE 0x20000
- union {
- void *dst_ptr;
- int (*func_arg)(void *, const char *, const char *);
- size_t off;
- } u;
- const char *help;
- const char *argname;
- } OptionDef;
typedef struct OptionDef {
const char *name;
int flags;
#define HAS_ARG 0x0001
#define OPT_BOOL 0x0002
#define OPT_EXPERT 0x0004
#define OPT_STRING 0x0008
#define OPT_VIDEO 0x0010
#define OPT_AUDIO 0x0020
#define OPT_INT 0x0080
#define OPT_FLOAT 0x0100
#define OPT_SUBTITLE 0x0200
#define OPT_INT64 0x0400
#define OPT_EXIT 0x0800
#define OPT_DATA 0x1000
#define OPT_PERFILE 0x2000 /* the option is per-file (currently ffmpeg-only).
implied by OPT_OFFSET or OPT_SPEC */
#define OPT_OFFSET 0x4000 /* option is specified as an offset in a passed optctx */
#define OPT_SPEC 0x8000 /* option is to be stored in an array of SpecifierOpt.
Implies OPT_OFFSET. Next element after the offset is
an int containing element count in the array. */
#define OPT_TIME 0x10000
#define OPT_DOUBLE 0x20000
union {
void *dst_ptr;
int (*func_arg)(void *, const char *, const char *);
size_t off;
} u;
const char *help;
const char *argname;
} OptionDef;
其中的重要字段:
name:用于存储选项的名称。例如“i”,“f”,“codec”等等。
flags:存储选项值的类型。例如:HAS_ARG(包含选项值),OPT_STRING(选项值为字符串类型),OPT_TIME(选项值为时间类型。
u:存储该选项的处理函数。
help:选项的说明信息。
FFmpeg使用一个名称为options,类型为OptionDef的数组存储所有的选项。有一部分通用选项存储在cmdutils_common_opts.h中。cmdutils_common_opts.h内容如下:
- { "L" , OPT_EXIT, {(void*)show_license}, "show license" },
- { "h" , OPT_EXIT, {(void*) show_help}, "s