Gstreamer 工具使用 (一)

拿 mp3 檔案做例子,用一個比較普遍而且廣泛應用的格式做練習有很多好處,一來沒有影像,就先省去同步的問題,也不會有 cpu / bandwidth 不夠的問題 (因為 video 的 bitrate 比 audio 高出很多);二來測試檔案滿地爬,而且橫跨多種不同參數的壓縮格式,更好的是可以互相參照的播放器也是滿地爬(一不小心就踩到的程度…搭捷運時年輕人幾乎 人手一台 player),抓蟲或對照功能時很好用。

gstreamer 提供了一個 command line 建立 pipeline 的工具:gst-launch。給不同的參數可以自動或手動的方式去播放一個多媒體檔,這個工具說方便很方便,說不方便也的確有點麻煩。方便是一個指令就 可以叫它開始播檔案,省去圖型化介面的慢和滑老鼠的動作;不方便是因為它除了 play 以外沒有別的 navigation command,不像 mplayer 還有給 hotkey 快轉 (快轉對於看謎片來說是很重要的呀!!)。

至於所謂的 pipeline,長得就像這樣箭頭和方塊組成的結構就稱為 pipeline,而每個方塊 (element) 都負責某一部份的資料處理,稱為 element。這和 DirectShow 的 graph 是相當神似的。有 DirectShow 基礎的人應該會比我還快了解 gstreamer 吧。

總之,自動建立 pipeline 的指令是如此:

gst-launch playbin uri=file:///path/to/file.mp3

而手動建立的話可以這麼簡單:

gst-launch filesrc location=/path/to/file.mp3 ! mad ! alsasink

其中的 mad 就是 gstreamer 會 runtime 去 load 的 element ,也就是接下來會深入去講的主題。如果你的系統缺少了解碼 mp3 必要的函式庫或 gstreamer 針對 mp3 的插件,那就會播放失敗。開源的 mp3 函式庫很多,我們就用 mad (mpeg audio decoder)。


以 ubuntu 為例,安裝必要的函式庫很容易:

sudo apt-get install libmad0 gstreamer0.10-plugins-ugly

 如此應該就可以順利聽到 mp3 的音樂了。其他必要的 element 像是 audio renderer 通常預設就會安裝了。知道了這些工具後我們就可以開始以 mad 為師的 gstreamer 插件學習過程。

首先,我們最好用 gst-inspect 看看 mad 這個插件的一些資料,這些都會是接下來寫程式或多或少會用到的。

gst-inspect mad

我們會看到一些對這個插件的描述,pad template 的 capabilities 等等,gstreamer 的文件裡有比較清楚的列出哪些 properties 對 capabilities 的描述和對應的意義,此處就不多說。

gst-launch 和 gst-inspect 是開發插件時滿重要的兩個工具,玩熟練後我們就可以開始實作自己的 mp3 gstreamer 插件。gstreamer 很體貼的在網站上擺了一個插件的 template,我們就從這個 template 開始走下去。

git clone git://anongit.freedesktop.org/gstreamer/gst-template.git

下載後在作業目錄會找到一個 gst-template 的資料夾,然後進到 gst-plugin/src 執行

../tools/make_element mp3dec

這個 tool 會用 mp3dec 為名產生一個 gstreamer plugin 的 template。這兩件事情就是在做 gstreamer plugin writer’s guide 的 section 3.1, 3.2。

接著,我們要「立刻」看到自己寫的 plugin 被 gst-inspect 找到,這要怎麼做呢?

首先,改寫 gst-plugin/src/Makefile.am,讓他編譯我們的程式,用文字編輯器把 gstplugin 這個字串換成 gstmp3dec。接著就像一般我們在編譯開源專案一樣,藉 autotool 來產生 Makefile,執行 gst-plugin/autogen.sh 。接著到 gst-plugin/src 下 make,就會在 gst-plugin/src/.libs/ 下面看到 libgstmp3dec.so,這個就是我們的 gstreamer 插件。你可以用

GST_PLUGIN_PATH=/path/to/gst-template/gst-plugin/src/.libs/ gst-inspect mp3dec

來檢視這個插件的細節,就像之前我們檢視 mad 一樣,會發現很多資訊在 mad 裡面有的,在 mp3dec 這個新生的插件裡看不到,那些就是我們要慢慢加上去的功能。

上一篇我們把一些編譯 gstreamer 插件的環境給準備好,也透過 gst-inspect 看到新加入的插件 ( 在上一個例子中是「mp3dec」) 的屬性,接著就要親眼見證它的運作了。

先打開 gstmp3dec.c 找到

g_printf(“I'm plugged, therefore I’m in.\n”);

這一行,改一下文字,然後跳出重編,執行

gst-launch filesrc location=/path/to/file.mp3 ! mad ! mp3dec ! alsasink

有沒有看到一行你剛剛改的字拚命洗畫面,那就是插件運作的明證。接著我們要開始改寫這個插件,來讓它取代 mad。所以測試方法也很明確,就是要讓

gst-launch filesrc location=/path/to/file.mp3 ! mp3dec ! alsasink

這指令可以正確地播出 file.mp3 的內容。這個指令會在接下來的測試過程中不斷的被執行。

接著編輯 gstmp3dec.c (這個檔案也會不斷的修改),尋找 GstStaticPadTemplate ,會找到已經被自動產生的兩個 pad:sink_factory 和 src_factory 。還不知道 pad 是什麼沒關係,先想像它是插件的「開口」就好;上一篇文章我們有提到所謂的 pipeline 的箭頭是有方向性的,資料從源頭 (檔案、網路…等) 讀取出來後,從讀取的插件開始(即:file-source),到播送的插件出去(即:audio-sink 和 video-sink)。

Gstreamer 工具使用 (一)_第1张图片

透過插件的「開口」,資料才能在插件之間流動,就像濾水器的進水閥和出水閥,控制流進流出的水量、速度等等。不過 gstreamer 的水閥比較複雜一點,它必須再去判斷多媒體資料流的屬性,動態地決定輸入的多媒體檔案要用哪一個濾水器來承接。在這裡水閥就是 GstPad ,而標示水閥的「屬性」就是 GstCaps。 進水閥我們稱為「sink pad」,出水閥我們稱為「source pad」,所以按上圖來看,file-source 沒有「安裝」「sink pad」是因為他在進水的那一條路是透過系統的 file I/O 來處理,不屬於 gstreamer pad 的範疇;同樣的 audio-sink 和 video-sink 沒有「安裝」「source pad」是因為在播放聲音和影像的部份是透過系統的 A/V renderer。而在中間的插件們,最基本的型態是一個進水(後稱 sinkpad )一個出水(後稱 srcpad ),像 decoder ;而 demuxer 要把 audio/video (或更多,視封裝格式而定) 資料拆開給各自的解碼器,就會有一個 sinkpad ,多個 srcpad ,因為責任重大,demuxer 寫起來也比較複雜。

解釋完插件和 pad、caps 之間的關係後,我們先透過程式去設定 mp3dec 的屬性。為求簡單,我們照抄 mad 的屬性就好,所以 sink_factory 和 src_factory 會改成如下

 

static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("audio/mpeg,   \
        mpegversion=1,      \
        layer=[1,3],        \
        rate={8000,11025,12000,16000,22050,24000,32000,44100,48000},\
        channels=[1,2]")
        );

static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("audio/x-raw-int,  \
        endianness=1234,    \
        signed=true,        \
        width=32,           \
        depth=32,           \
        rate={8000,11025,12000,16000,22050,24000,32000,44100,48000},\
        channels=[1,2]")
        );

重編後再用 gst-inspect 檢查一下就會發現在 Pad Templates 裡所描述 sinkpad 和 srcpad 的屬性都更新了,看的出來 mp3dec 接受的輸入格式是 mpeg1 audio layer3 的資料流,輸出 pcm 。設定這些屬性的目的就跟前述一樣,讓 gstreamer 在自動產生 pipeline 的時候可以按照我們設定的格式找到正確的插件來處理資料。(想像一下濾水器的進入出入閥標示著這個是濾工業用水、那個是濾農業用水、另一個是濾家庭用水, 口徑多少、每單位吃水量多少…等等等,如此就算濾水器的功能一樣,而相對應的口徑、水量不符合,gstreamer 也不會接錯。)

然而,這邊設定的 caps 只是一個樣板,告訴上下插件輸入和輸出資料的格式及相關屬性的「範圍」,做為建立 pipeline 時參考的依據,當檔案開始播放時,真正的資料流的格式、屬性要等解碼完才知道。換言之,caps 的設定不一定是在 template 裡寫死就好,有時要另外動態產生運行時對應的 caps 並指派給 pad ( 包括 sinkpad 和 srcpad )。

在處理 sinkpad 和 srcpad 的程式都還沒寫之前就先設定 caps 其實並沒有具體的功能,但我覺得這樣解釋比較不會搞不清楚或混淆 caps 的目的和重要性。

當 caps 被設定好後,我們再來執行看看前面執行過的指令

gst-launch filesrc location=/path/to/file.mp3 ! mad ! mp3dec ! alsasink

有沒有發現結果不一樣了?此時音樂不會播,程式直接中斷並吐出一行字:

WARNING: erroneous pipeline: could not link mad0 to mp3dec0

原因很簡單,就是 gstreamer 發現 mad 的輸出閥 (srcpad) 和 mp3dec 的輸入閥 (sinkpad) 的 caps 不符合。所以跑都不跑就直接跳掉了。

你可能感兴趣的:(properties,command,工具,makefile,audio,templates)