王 蕊 , 劉衛(wèi)東 ,2, 王金童
(1.中國海洋大學(xué) 信息科學(xué)與工程學(xué)院,山東 青島 266100;2.海信電器股份有限公司 山東 青島 266071;3.青島海信信芯科技有限公司 山東 青島 266071)
如今多媒體系統(tǒng)的功能越來越復(fù)雜,并且由于不同的多媒體系統(tǒng)之間的硬件平臺和軟件平臺存在著巨大的差異性,這些都給多媒體系統(tǒng)的移植工作帶來了問題。為了將多媒體系統(tǒng)移植到不同的軟、硬件平臺上,必須為這些平臺重新編寫多媒體處理代碼,并且在應(yīng)用程序開發(fā)時,要花很大的時間和精力對這些底層多媒體處理重新進(jìn)行整合。但是如果這些多媒體系統(tǒng)中加入了多媒體框架GStreamer,那么就可以把復(fù)雜的底層多媒體處理的整合工作交給多媒體框架來處理。借助于GStreamer的管道機(jī)制,插件(編解碼器,復(fù)用/解復(fù)用器,控制器等)中的各種多媒體處理代碼對于上層的應(yīng)用程序而言變得透明,在開發(fā)應(yīng)用程序時就不需要把精力和注意力放在底層代碼的整合工作上。與此同時,被封裝成共享庫的插件中的元件可以被多個應(yīng)用程序共享使用,減少了重復(fù)代碼的編寫,簡化了集成和復(fù)用,提高了開發(fā)的效率。
GStreamer是一個功能強(qiáng)大的開源多媒體應(yīng)用程序框架,它的基本設(shè)計思想來自于俄勒岡(Oregon)研究生院有關(guān)視頻管道的創(chuàng)意,同時也借鑒了DirectShow的設(shè)計思想。
GStreamer作為Gnome桌面環(huán)境推薦的多媒體應(yīng)用框架,采用了基于插件的模塊化設(shè)計,框架中所有功能模塊都被實現(xiàn)成可以插拔的組件,并且在需要的時候能夠很方便地安裝到任意一個管道上,所有插件都通過管道機(jī)制進(jìn)行統(tǒng)一的數(shù)據(jù)交換。GStreamer在構(gòu)建播放器上有顯著的用途,附帶200多個音視頻處理插件,能夠支持多種格式的文件,包括MP3、 Ogg/Vorbis、MPEG-1/2、AVI、Quicktime、mod 等等。
GStreamer核心庫是一個處理插件、數(shù)據(jù)流和媒體操作的框架,為程序員編寫應(yīng)用程序提供了一些公用的API。
GStreamer有以下3個基本概念[1-6]:
1)元件(Element) 元件是GStreamer中最重要的概念,它是組成管道的基本構(gòu)件,也是框架中所有可用組件的基礎(chǔ)。按照各自功能上的差異,GStreamer的元件可以分為3類:①數(shù)據(jù)源元件 Source Element,只有輸出端,它僅能用來產(chǎn)生供管道處理的數(shù)據(jù),而本身不對數(shù)據(jù)做任何處理。比如從磁盤或者聲卡讀取數(shù)據(jù)。②過濾器元件 Filter Element,既有輸入端又有輸出端,它從輸入端獲得相應(yīng)的數(shù)據(jù),并在經(jīng)過特殊處理之后傳遞給輸出端。比如格式轉(zhuǎn)換,編解碼等。③Sink Element接收器元件,只有輸入端,它僅具有消費數(shù)據(jù)的能力,是整條媒體管道的終端。比如聲卡播放聲音以及視頻輸出等。
2)箱柜(Bin)和管道(Pipeline) 箱柜是一個可以裝載元件的容器。管道是箱柜的一個特殊的子類型,管道可以操作包含在它自身內(nèi)部的所有元件。因為箱柜本身又是元件的子集,所以能夠像操作普通元件一樣的操作一個箱柜,可以通過改變一個箱柜的狀態(tài)來改變箱柜內(nèi)部所有元件的狀態(tài)。管道是一個高級的箱柜。當(dāng)設(shè)定管道為播放狀態(tài)的時候,數(shù)據(jù)流將開始流動,并且媒體數(shù)據(jù)也開始進(jìn)行處理,一旦開始,管道將在一個單獨的線程中運行,直到被停止或者數(shù)據(jù)流播放完畢。頂層箱柜必須為一個管道,因此每個GStreamer應(yīng)用程序都至少需要一個管道。
3)襯墊(Pad) 襯墊在GStreamer中被用于多個元件的鏈接,從而讓數(shù)據(jù)流能在這樣的鏈接中流動。 一個襯墊可以被看作是一個元件插座或者端口,元件之間的鏈接就是依靠著襯墊。一個襯墊能夠限制數(shù)據(jù)流類型的通過,只有在兩個襯墊允許通過的數(shù)據(jù)類型一致的時候元件之間的鏈接才能被建立。
GStreamer通過抽象的管道概念進(jìn)行工作。管道是一個有向圖,數(shù)據(jù)流在這個有向圖中從輸入流到輸出。管道由各種元件構(gòu)成,而元件則是可以放入到管道中的對象,其中包裝了對媒體進(jìn)行的某種操作。在管道中不同的元件可以通過襯墊鏈接在一起,共同組成將輸入轉(zhuǎn)換為需要的輸出的完整處理過程。通常,使用從左(上游)到右(下游)的數(shù)據(jù)流來對管道進(jìn)行描述。所以,管道的工作過程可以簡單的描述為對數(shù)據(jù)流進(jìn)行輸入、轉(zhuǎn)換和輸出的過程?;镜腉Streamer應(yīng)用工作原理如圖1所示。
圖1 GStreamer工作原理Fig.1 Operation principle of GStreamer
在GStreamer應(yīng)用中,框架中的大部分API都會涉及到對元件的操作,元件通過襯墊與外界進(jìn)行交互,向框架中的其余部分表明自己的特性或者功能,開發(fā)者可以通過特定的函數(shù)來設(shè)置元件的屬性。襯墊根據(jù)是在元件的輸入端還是輸出端 , 分為 輸出襯墊(Src pad)和 輸入襯墊(Sink pad)。管道在箱柜之上,通過它控制媒體播放中的各種狀態(tài),包括插放、暫停、快進(jìn)、快退等??偩€[1](Bus)在箱柜之上,主要用來裝入回調(diào)函數(shù),傳遞一些管道運行后的消息。每個管道都默認(rèn)有一個總線,不需要手工創(chuàng)建,只要設(shè)置消息處理器(Handler)到總線上,管道運行起來后,等待消息被捕捉到,就會立刻調(diào)用回調(diào)函數(shù)。
為了實現(xiàn)GStreamer的一般應(yīng)用,需要安裝的模塊包括:gstreamer、gst-plugins-base、gst-plugins-good、gst-pluginsugly、gst-plugins-bad、gst-ffmpeg。 版本分別選擇其對應(yīng)的最新版本。從GStreamer官方網(wǎng)站的下載頁面分別下載到本地硬盤,解壓之后在終端中分別輸入命令./configure、make、make install按照順序逐個配置、編譯、安裝各個模塊,最終完成GStreamer的安裝。
GStreamer-0.10[3]的組成模塊及其最新版本如表1所示。
表1 GStreamer-0.10組成模塊版本Tab.1 Version of GStreamer-0.10’s composition modules
利用GStreamer的插件構(gòu)建的媒體播放管道構(gòu)建圖[5]如圖2所示。其中,Source element用來讀取媒體文件,并連接到Demuxer element,由它負(fù)責(zé)把媒體文件里的壓縮音視頻數(shù)據(jù)分離出來,之后分別連接到音頻解碼元件Audio decoder element和視頻解碼元件Video decoder element分別對分離出來的音視頻進(jìn)行解碼,然后再分別連接到音頻輸出元件Audio sink element和視頻解碼元件Video sink element完成媒體流的輸出。
在整體管道構(gòu)造中,使用到一些重要的GStreamer API[6]函數(shù),來實現(xiàn)初始化庫,創(chuàng)建元件,連接元件,設(shè)置元件屬性等。以下為具體設(shè)計管道的主要步驟:
1)gst_init(),通過 gst_init()函數(shù)來初始化 GStreamer庫,確保程序包含了 gst/gst.h頭文件,這樣GStreamer庫中的對象和函數(shù)才能夠被正確地定義。
2)g_main_loop_new (), 創(chuàng)建一個主循環(huán), 在執(zhí)行g(shù)_main_loop_run()后正式開始循環(huán)。
3)gst_pipeline_new(),創(chuàng)建一條新的管道,用來容納和管理元件。
4)gst_element_factory_make(),根據(jù)元件 Factory 中的類型創(chuàng)建元件,包括輸入源元件source,過濾器元件decoder和接收器元件sink。
5)g_object_set()[4],指定輸入文件的路徑。
6)gst_bin_add()和 gst_element_link()將新創(chuàng)建的元件添加到已創(chuàng)建的管道中,通過襯墊鏈接管道中的元件(元件要按照順序鏈接)。
圖2 媒體播放管道構(gòu)建圖Fig.2 Media-player pipeline
程序用gst_bin_add_many()函數(shù)將創(chuàng)建的所有元件都加入管道pipeline中,然后用gst_element_link_many()來連接他們,這樣各個元件就可以配合工作了。
7)gst_pipeline_get_bus()和 gst_bus_add_watch(),從管道中得到總線,創(chuàng)建一個消息處理器來偵聽管道。每當(dāng)管道發(fā)出一個消息到總線,這個消息處理器就會被觸發(fā),它調(diào)用回調(diào)函數(shù)來處理消息。
8)gst_element_set_state(),設(shè)置管道的運行狀態(tài)。狀態(tài)可以設(shè) 置 為 GST_STATE_NULL,GST_STATE_READY,GST_STATE_PAUSED和GST_STATE_PLAYING,對應(yīng)于初始化、準(zhǔn)備、暫停和播放狀態(tài)。
9)g_main_loop_run(),讓主循環(huán)運行起來,開始碼流的播放。
10)gst_object_unref(),播放完成后,釋放系統(tǒng)資源。
通常當(dāng)加載一個新的媒體流時,媒體的類型并不明了,所以在選擇一條管道來對媒體流進(jìn)行解碼之前,首先需要檢測媒體流的類型。在 GStreamer中使用了類型檢測插件typefind[1]來達(dá)到此目的。在上層提出音頻播放請求時,通過插件typefind分析音頻文件的格式,若為不支持的格式,向上層發(fā)送一個無法播放的消息;若為支持的格式,及時動態(tài)地調(diào)用插件生成對應(yīng)的插件,并連接封裝成一個管道進(jìn)行播放處理。
成功獲取文件信息后,GStreamerBus會發(fā)出消息,并按照函數(shù)g_signal_connect()的設(shè)置,調(diào)用回調(diào)函數(shù)cb_typefound();
在函數(shù)cb_typefound()成功獲取文件信息后,調(diào)用cb_typefound()時,會返回一個GstCaps數(shù)據(jù),其中包含了諸如文件類型,寬度,高度比等信息。在cb_typefound()中,可使用gst_caps_to_string(caps)函數(shù)將數(shù)據(jù)強(qiáng)制轉(zhuǎn)換成一個字符串,也可用 gst_caps_get_structure(caps,0)函數(shù)將數(shù)據(jù)轉(zhuǎn)換成為一個structure類型數(shù)據(jù),以便播放使用。
文中介紹了GStreamer的一些基礎(chǔ)知識,并簡單介紹了GStreamer庫的安裝。在閱讀、分析GStreamer源碼的基礎(chǔ)上,著重講述了GStreamer的工作原理,討論了如何利用其管道的思想來實現(xiàn)多種音視頻格式文件的播放,包括播放管道的設(shè)計以及媒體文件類型的獲取,并演示了如何利用GStreamer框架構(gòu)建簡單、高效的媒體播放管道。由于GStreamer為用戶提供了大量的公用API,使用它來構(gòu)建播放管道具有易于開發(fā),易于移植的特點,極具實際應(yīng)用價值。
[1]Taymans W,Baker S,Wingo A,et al.GStreamer Application Development Manual(0.10.35.1) [EB/OL].[2011-07-15].http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/manual.pdf.
[2]Boulton R J,Walthinsen E, Baker S,et al.GStreamer Plugin Writer’s Guide(0.10.35.1) [EB/OL].[2011-08-11].http://gstreamer.freedesktop.org/data/doc/gstreamer/head/pwg/pwg.pdf.
[3]gstreamer-0.10.35.tar.gz[CP/OL]. [2011-07-15].http://gstreamer.freedesktop.org/src/gstreamer/.
[4]GObject Reference Manual[EB/OL].http://developer.gnome.org/gobject/stable/.
[5]張海濱,李揮,吳曄等.嵌入式高清播放器的設(shè)計與實現(xiàn)[J].計算機(jī)工程與設(shè)計,2010,31 (13):3086.
ZHANG Hai-bin,LIHui,WU Ye,etal.Design and implementation ofembedded high definition player[J].Computer Engineering and Design,2010,31(13):3086.
[6]GStreamer 0.10 Core Reference Manual (0.10.35.1) [EB/OL].[2011-07-10].http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/