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;

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