• 沒有找到結果。

av_open_input_file 確認輸入檔案包裝格式

第三章 多媒體串流之自由軟體介紹及使用

3.1.3 av_open_input_file 確認輸入檔案包裝格式

圖17 av_register_input_format( )程式碼

有影音格式的初始化函式例如mp3_init( )、mpegps_init( ),而這些初 始化函式會將它們所代表的影音包裝格式以Structure AVInputFormat 傳給av_register_input_format( ),舉例來說,mpegps_init( )會將圖 15 的mpegps_demux 傳給 av_register_input_format( ),而

av_register_input_format( )則會將 mpegps_demux 與前面的影音格式串 接起來,因此我們只要很呼叫av_register_all( )這個 api,就可以建立 如圖18 所示的鏈結串列,將各種模版串接起來。而 first_iformat 則會 指向這個鏈結串列的起始位置。

圖18 各種影音格式的鏈結串列

3.1.3 av_open_input_file( )—確認輸入檔案包裝格式

在建立好各種影音格式的鏈結串列後,接下來就要判斷輸入檔案 為何種影音格式,判斷的方式如上一節所述,輸入檔案會跟每種影音

格式模板進行比對,每個影音格式模板的成員函式read_probe( )會試 著判斷輸入檔案的檔頭符不符合這種影音格式的檔頭標準,一旦符合 則會回傳一個非零整數,這個判斷的過程libavformat 這個函式庫也 提供一個api 供程式開發者使用,那就是 av_open_input_file( ),圖 19 則列出av_open_input_file( )的水平關係圖。av_open_input_file( )藉由 呼叫av_probe_input_format( )來進行搜尋鏈結串列的過程。

圖19 av_open_input_file( )水平關係圖

圖20 則是 av_probe_input_format( )的原始碼,根據圖 18,first_iformat 會指向這個鏈結串列的開頭,因此av_probe_input_format( )利用一個 for 迴圈從鏈結串列的開頭 first_iformat 一直搜尋到鏈結串列的結 尾,而for 迴圈每執行一次就代表搜尋到某一個影音格式,同時每執 行一次都會呼叫一次fmt1->read_probe(pd),這裡的 fmt1 是代表某一 個影音格式,pd 則是輸入檔案的檔頭,read_probe( )在輸入檔案的檔 頭與這個影像格式所定義的檔頭相符時,會回傳一個大於零的整數 值,並將fmt 設定為 fmt1,而 fmt 則為最後確定好的影音格式。

圖20 av_probe_input_format( )的原始碼

至於read_probe( )的函式內容則根據影音格式的不同而有不同的 定義,在這邊我們將以第二章出現過的mpeg-2 program stream 與 transport stream 為例子分別說明在 FFmpeg 中 read_probe( )如何成功 的判斷出檔案格式為program stream 與 transport stream,從圖 20 我們 可以知道當搜尋到某一個影音格式時程式會呼叫fmt1->read_probe( ) 來判斷輸入的檔案其檔頭是否符合此影音格式的定義,當此影音格式

為mpeg-2 program stream 也就是當圖 20 的 fmt1 等於圖 14 的 mpegps_demux 時,呼叫 fmt1->read_probe( )事實上就等同於呼叫圖 20 的 mpegps_probe( ),圖 21 則為 mpegps_probe( )的程式碼,首先 mpegps_probe( )會先讀進這個 program stream 的前面 2048bytes 的資 料,事實上以第二章的圖10 來看,讀進 2048bytes 就是讀進 PACK 0 與PACK 1,而判斷的規則則是這 2048bytes 至少要有一個

system_header_start_code 0x000001BB,而且 system header 的個數必 需小於或等於PACK header。只要符合這兩項,mpegps_probe( )就會 回傳一個大於零的整數,也就確定此輸入檔案為program stream。

圖21 mpegps_probe( )程式碼

Transport stream 也跟 Program stream 相似,當圖 20 的 fmt1 等於

transport stream 時,呼叫 ftm1->read_probe( )等同於呼叫

mpegts_probe( ),圖 22 則是 mpegts_probe( )的水平關係圖以及

mpegts_probe( )呼叫 analyze( )的程式碼,不同於 mpegps_probe( )直接

圖22 mpegts_probe( )與 analyze( )關係

判斷輸入檔案的檔頭有幾個system_header 與 pack_header,

mpegts_probe( )則是在副函式 analyze( )中進行判斷,其判斷的方式是 讀入輸入檔案(就是圖 22 的 p->buf)的前 1880bytes,接下來判斷這 1880bytes 中有幾個 bytes 是 Transport stream header 中的 sync_byte 0x47,每讀進一個 sync_byte 則圖 22 中的 score 會加一,從第二章的 圖11 我們可以知道 Transport stream 中每個 packet 其大小為 188bytes 且其開頭會有4 bytes 的 header,sync_byte 0x47 就包含在這 4bytes 中,因此我們可以預期讀進這1880bytes 並判斷 sync_byte 後 score 的 值將為10,程式就是藉由這個方法判斷出輸入檔案為 mpeg-2

transport stream。圖 23 則是 analyze( )的原始碼。

圖 23 analyze( )原始碼

相關文件