看見 gstreamer plugin 的第二步

上一篇我們把一些編譯 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 的水閥比較複雜一點,它必須再去判斷多媒體資料流的屬性,動態地決定輸入的多媒體檔案要用哪一個濾水器來承接。在這裡水閥就是 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 不符合。所以跑都不跑就直接跳掉了。

你可能感兴趣的:(开源)