欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ffmpeg源码分析——libavformat.a---mp4文件读取过程

程序员文章站 2022-03-21 07:57:20
...

目录

环境:ubuntu18.04 + ffmpeg4.1源码

ffmpeg.c 这里简单列一下其调用流程中主干函数。

以下分析 mp4文件读取的时候,这个 AVInputFormat 结构体具体的注册初始化过程。

附议:1.0 全局demuxer变量的定义。


环境:ubuntu18.04 + ffmpeg4.1源码

这里假设已经下载好ffmpeg源码,编译通过,可以运行如下命令:
 # ./ffmpeg -i test.mp4 -codec copy -bsf: h264_mp4toannexb -f h264 tmp.264 -report
这条命令的效果是,把 输入文件test.mp4 中的h264源数据复制输出到 tmp.264文件。将会得到一个tmp.264裸流文件。
命令解释:
                -i test.mp4  输入
                -codec copy 编码器,直接copy
                -bsf:h264_mp4toannexb  -bsf表示  BitStreamFilter ,比特流过滤器, h264_mp4toannexb 即一个过滤器的名称,其源码在libavcodec/h264_mp4toannexb.c   就ffmpeg中是一个特定的比特流过滤器。
                -f h264 强制使用h264格式
                -report 可要可不要,加上这个命令,会在当前目录生成一份程序的运行log报告。

初步分析其源码,ffmpeg.c文件。

ffmpeg.c 这里简单列一下其调用流程中主干函数。

(ffmpeg.c):
          main.c()
        1.0 ffmpeg_parse_options(argc, argv);   /* parse options and open all input/output files */
        2.0 transcode()// The following code is the main loop of the file converter
            2.1 transcode_init()
            2.2 transcode_step()
                2.2.1 process_input()//read one packet and processed
                       2.2.1.1 get_input_packet() //read one packet
(utils.c)                      2.2.1.1.1 av_read_frame()->read_frame_internal()->ff_read_packet()-> s->iformat->read_packet(s, pkt);
                                           
                        

ffmpeg 既然能支持不同格式的视频输入文件,其中某些函数当然以动态注册的方式来匹配不同的输入。上述函数调用,在utils.c的av_read_frame即从输入文件中读取一帧数据,具体往下调用, 一直到s->iformat->read_packet(s, pkt); 即AVFormatContext (音视频格式上下文)结构体中的 struct AVInputFormat *iformat(音视频输入格式) 的函数 read_packet。 这个函数指针根据不同的输入类型,来注册。

以下分析 mp4文件读取的时候,这个 AVInputFormat 结构体具体的注册初始化过程。

(很多检查判断,可以自行添加打印信息具体确定流程,避免干扰主线分析)

ffmpeg.c ->
   ffmpeg_opt.c:: ffmpeg_parse_options()
->open_files() //open input files
->utils.c :: avformat_open_input() //  open the input file with generic avformat function 
->init_input()
->av_probe_input_buffer2()  // Probe a bytestream to determine the input format
->av_probe_input_format2()->av_probe_input_format3() //Guess file format
av_probe_input_format3()
{...  format.c L: 160
 while ((fmt1 = av_demuxer_iterate(&i))) //遍历所有 demuxer, 匹配合适的demuxer
...
}

在ffmpeg_opt.c open_input_file 调用 avformat_open_input()之后,添加如下调试信息:

	if(file_iformat && file_iformat->name)
	printf("wang track inputformate name file_iformat->name %s  [%d%s]\n",file_iformat->name,__LINE__,__FUNCTION__);
	if(ic->iformat && ic->iformat->name)
	printf("wang track inputformate name ic->file_iformat->name %s  [%d%s]\n",ic->iformat->name,__LINE__,__FUNCTION__);

对应输出ffmpeg源码分析——libavformat.a---mp4文件读取过程
这个AVInputFormat *iformat 的name 为“mov,mp4,m4a,3gp,3g2,mj2”
即匹配到 libavformat/mov.c 中定义的 AVInputFormat ff_mov_demuxer
ffmpeg源码分析——libavformat.a---mp4文件读取过程
这里就可以把之前读取帧数据的 read_packet(s, pkt)  对应到这里 的 mov_read_packet
具体mp4文件怎么读取到一帧视频数据,即 mov_read_packet函数分析,待续。

附议:1.0 全局demuxer变量的定义。

format.c :: av_probe_input_format3()匹配demuxer解复用器的时候,遍历demuxer_list 结构体数组,其中存储所有的demuxer,全部是全局变量,其中某些demuxer,  却只找到external的外部声明,却不能直接查找到其定义。比如 ff_h264_demuxer
ffmpeg源码分析——libavformat.a---mp4文件读取过程ffmpeg源码分析——libavformat.a---mp4文件读取过程

用grep命令匹配一下所有文件(包括编译出来的文件)
ffmpeg源码分析——libavformat.a---mp4文件读取过程

在 libavformat/h264dec.o 文件中匹配到这个变量符号,查看 这个文件,发现这样的一个宏定义:
FF_DEF_RAWVIDEO_DEMUXER(h264, "raw H.264 video", h264_probe, "h26l,h264,264,avc", AV_CODEC_ID_H264)
这个宏定义FF_DEF_RAWVIDEO_DEMUXER,展开来看,就是用来定义不同的AVInputFormat 变量的。上述就定义了变量
AVInputFormat ff_h264_demuxer;

相关标签: ffmpeg mp4