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

目录

环境: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__);

对应输出
这个AVInputFormat *iformat 的name 为“mov,mp4,m4a,3gp,3g2,mj2”
即匹配到 libavformat/mov.c 中定义的 AVInputFormat ff_mov_demuxer

这里就可以把之前读取帧数据的 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

用grep命令匹配一下所有文件(包括编译出来的文件)

在 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;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章