GStreamer(二)
http://antkillerfarm.github.io/
GStreamer應用(續(xù))
TCP遠程播放
除了本地播放之外,GStreamer亦支持遠程播放。以下僅以TCP遠程播放為例。
TCP遠程播放采用Client/Server模式。
step1
1.首先打開播放端軟件。(Server端)
gst-launch-1.0 tcpserversrc host="127.0.0.1" port=3000 ! decodebin ! autoaudiosink
2.打開多媒體發(fā)送端軟件。(Clinet端)
gst-launch-1.0 filesrc location=./1.mp3 ! tcpclientsink host="127.0.0.1" port=3000
示例代碼:
https://github.com/antkillerfarm/antkillerfarm_crazy/tree/master/gstreamer/tutorials/cs
step2
來一個更復雜的例子:
gst-launch-1.0 filesrc location=./1.mp3 ! tee name=tee0 tee0. ! queue ! tcpclientsink port=3000 tee0. ! queue ! decodebin ! autoaudiosink
這個例子中,一個音頻文件被tee分成了2份,一份遠程播,一份自己播。
注意事項:
1.Server端的管道狀態(tài)和一般情況下不同。初始情況下,就要設置為PLAY,否則Client會連接不上。
2.對Client管道狀態(tài)的改變,如PAUSE等,不會改變Server的管道狀態(tài)。因此,需要另外建立控制管道控制Server的播放操作。
3.Client的EOS(End of Stream)不會觸發(fā)Server的EOS,只有Client的斷開才會觸發(fā)Server的EOS。
4.Server的EOS處理,需要先將管道狀態(tài)設置為NULL,然后再設置為PLAY。否則,會導致新的Client無法連接到Server。
示例代碼:
https://github.com/antkillerfarm/antkillerfarm_crazy/tree/master/gstreamer/tutorials/cs2
step3
前面的例子中,管道都是一次性創(chuàng)建好的。這里來個動態(tài)創(chuàng)建的例子:
https://github.com/antkillerfarm/antkillerfarm_crazy/tree/master/gstreamer/tutorials/cs3
RTP遠程播放
TCP遠程播放的優(yōu)點是數(shù)據(jù)傳輸較快,但缺點是無法控制接收端的播放操作。為此人們提出了RTP/RTCP協(xié)議,兩者一般配合使用,前者用于傳輸媒體流,后者用于傳輸控制流。
參考文檔:
https://gstreamer.freedesktop.org/documentation/rtp.html
https://cgit.freedesktop.org/gstreamer/gst-plugins-good/tree/gst/rtp/README
1.首先打開播放端軟件。(Server端)
gst-launch-1.0 udpsrc port=3000 caps="application/x-rtp, media=(string)application, payload=(int)96, clock-rate=(int)90000, encoding-name=(string)X-GST" ! rtpgstdepay ! decodebin ! autoaudiosink
2.打開多媒體發(fā)送端軟件。(Clinet端)
gst-launch-1.0 filesrc location=./03.flac ! decodebin ! rtpgstpay ! udpsink port=3000
注意事項:
1.RTP本身沒有EOS標志,因此需要通過其他手段告訴接收端——現(xiàn)在已經(jīng)EOS了。參見:
http://gstreamer-devel.966125.n4.nabble.com/Not-getting-GST-MESSAGE-EOS-from-recording-bus-td4662992.html
示例代碼:
https://github.com/antkillerfarm/antkillerfarm_crazy/tree/master/gstreamer/tutorials/rtp
2.如果Client的歌曲已經(jīng)切換,但Server管道沒有重置的話,會出現(xiàn)播放雜音。同樣,這個事件也不能僅通過RTP,告知Server。
3.雖然GStreamer已經(jīng)提供了很多格式的rtp插件,然而仍然有很多格式不支持rtp。于是就存在轉碼的問題,但遺憾的是支持rtp的格式,多是一些老的有損壓縮格式,對最近日趨流行的無損壓縮支持的不夠。
4.clock-rate似乎不能設置為90000之外的值,否則無法播放,原因不詳。
綜上,GStreamer提供的原始的RTP播放,只適合諸如監(jiān)控之類的媒體格式固定的管道。對于媒體格式不固定的管道,支持的并不好。
多設備的網(wǎng)絡時鐘同步
多個設備協(xié)同播放同一個媒體流的時候,設備之間存在著時鐘同步的問題。針對這個問題,GStreamer提供了網(wǎng)絡時鐘同步的功能。
這個功能主要涉及兩個對象:GstNetTimeProvider和GstNetClientClock。前者用于提供時鐘源,而后者負責獲取時鐘源的時鐘。
具體實現(xiàn)可參考以下文章:
https://fosdem.org/2016/schedule/event/synchronised_gstreamer/attachments/slides/889/export/events/attachments/synchronised_gstreamer/slides/889/synchronised_multidevice_media_playback_with_GStreamer.pdf
文章中的代碼需要GStreamer v1.6以上才可編譯。此外,compile文件也需要少許修改方可正常使用。這里給出一個autoconf版的demo:
https://github.com/antkillerfarm/antkillerfarm_crazy/tree/master/gstreaamer/tutorials/sync_demo
對于更精確的時鐘同步,在GStreamer v1.6之后,還提供了GstPtpClock對象。這個對象僅提供了PTP協(xié)議的Client功能。
PTP協(xié)議相關的規(guī)范是IEEE1588:2008。其服務器實現(xiàn)有:
ptpd:http://ptpd.sourceforge.net/
參考:
http://www.tinylab.org/gstreamer-sdk-a-cross-platform-multimedia-framework/
這篇文檔提到queue可通過設置緩存大小,來達到延遲播放的效果,但實際上,并沒有這個效果,原因不詳。
最簡單的多設備協(xié)同播放,可使用一主多從式的RTP分發(fā)管道。需要注意的是,主設備不要使用本地解碼管道,而要和從設備一樣使用RTP傳輸播放管道(也就是自己發(fā)自己收),否則它和從設備之間會有播放不同步的情況發(fā)生。
RTP播放狀態(tài)問題
RTP管道和其他GStreamer管道不同,其PLAYING狀態(tài)更多表示它可以接收網(wǎng)絡發(fā)過來的數(shù)據(jù),但這個時候是否有數(shù)據(jù)正在播放,實際上是不得而知的。
解決的辦法是:
1.向管道中添加queue組件。queue組件中的overrun、underrun事件可用于指示管道的微觀狀態(tài)。
2.從宏觀來看,如果管道處于播放狀態(tài),那么underrun事件會不斷產(chǎn)生。一旦underrun事件停止產(chǎn)生,那也就表明近期沒有數(shù)據(jù)發(fā)過來了,也就是管道處于空閑狀態(tài)。
一旦發(fā)現(xiàn)RTP管道從播放狀態(tài)進入空閑狀態(tài),就要及時重置管道,不然揚聲器可能會產(chǎn)生低音量的噪聲。這可能和管道中殘存的數(shù)據(jù)有關,原因不詳。
簡單的將管道設置為NULL,再設為PLAYING的方式,可以消除噪聲,但接下去的播放就不正常了。解決辦法暫未找到。
GStreamer對URI的支持
GStreamer的playbin、uridecodebin插件都可以處理URI,但dataurisrc是個例外,它接收的不是如http://或file://這樣的URI,而是RFC 2397格式的URI,如下所示:
gst-launch-1.0 -v dataurisrc uri="data:image/png;base64,iVBORw0KGgo...." \ ! pngdec ! videoconvert ! imagefreeze ! videoconvert ! autovideosink如果想做一個urisrc的話,可以使用giosrc插件,或者分不同情況,使用filesrc(file)或souphttpsrc(http)插件。
注意事項:
1.giosrc在不同平臺的支持是不一樣的。比如在Raspberry Pi上就無法獲取http資源,原因不詳。
2.giosrc不支持seek功能,而souphttpsrc支持。
3.開源項目Rygel,最近(v0.30.3)放棄使用giosrc。
GStreamer應用的內存占用情況
場景 | 內存占用
|:–:|:–:|
播放本地音頻文件 | ~10MB
播放遠程音頻文件 | ~25MB
gmediarender(非播放狀態(tài)) | 50MB~65MB
gmediarender(播放狀態(tài))| 60MB~85MB
audioconvert
audioconvert用于轉換不同格式的音頻數(shù)據(jù)。這里的格式指的是位寬、大小端、采樣率等格式,而不是音頻編解碼格式。
如果沒有使用audioconvert做轉換,可能會導致音頻文件在某些設備上無法播放。畢竟設備不可能支持所有的位寬、大小端、采樣率。
類似的,還有videoconvert、autoconvert插件。
GStreamer編程
開發(fā)環(huán)境搭建
sudo apt-get install libgstreamer1.0-dev(1.x系列)
sudo apt-get install libgstreamer0.10-dev(0.10.x系列)
helloworld程序在
https://github.com/antkillerfarm/antkillerfarm_crazy/tree/master/gstreamer/helloworld
這里的代碼盡管是針對1.x系列的,但實際上對于0.10.x系列也同樣有效,你需要做的只是將Makefile中的
CFLAGS = `pkg-config --cflags gstreamer-1.0` LDFLAGS = `pkg-config --libs gstreamer-1.0`改為
CFLAGS = `pkg-config --cflags gstreamer-0.10` LDFLAGS = `pkg-config --libs gstreamer-0.10`這個例子同時也是如何使用pkg-config來管理同一軟件的不同版本的范例。GTK+ 2.x和GTK+ 3.x的共存,也是采用了同樣的方法。
教程
官方開發(fā)指南參見:
http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/index.html
這是應用開發(fā)指南。
http://gstreamer.freedesktop.org/data/doc/gstreamer/head/pwg/html/index.html
這是插件開發(fā)指南。
這兩本書是最基礎的教程,尤其是前者。建議首先通讀一遍,然后再進行具體的編程實踐。不然,你可能連基本的概念和術語都不清楚。這兩個指南都已有中文版,盡管比較老,是針對0.10.x系列的。
官方入門代碼教程參見:
http://docs.gstreamer.com/display/GstSDK/Tutorials
這里還有一個更全的代碼示例:
https://github.com/rubenrua/GstreamerCodeSnippets
以下是教程的一些細節(jié)的學習心得。
basic-tutorial-1.c
/* Build the pipeline */ pipeline = gst_parse_launch ("playbin2 uri=http://docs.gstreamer.com/media/sintel_trailer-480p.webm", NULL);從這個教程可以看出,我們可以直接使用gst_parse_launch創(chuàng)建pipeline。
basic-tutorial-7.c
tee_src_pad_template = gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (tee), "src%d");這是代碼的其中一段,這里只談談src%d是怎么來的。使用gst-inspect工具查詢tee插件的信息,得到如下內容:
Pad Templates:SRC template: 'src%d'Availability: On requestHas request_new_pad() function: gst_tee_request_new_padCapabilities:ANYSINK template: 'sink'Availability: AlwaysCapabilities:ANY從中可知,tee插件SRC Pad的模板名就是src%d。
GStreamer的Python開發(fā)教程
Step 0
教程的起點——helloworld。這是一個最基本的GStreamer播放器的例子,使用GTK作為GUI工具。
代碼參見:
https://github.com/antkillerfarm/antkillerfarm_crazy/blob/master/python/python-gst-player-example.py
這個例子不能直接運行,需要根據(jù)具體情況,略作修改,修改的地方如下:
1)self.uri存放用于播放的媒體文件的URI,注意這里是URI,而不是普通的路徑,如果要指定本地文件的話,需要使用file://。
2)出錯的時候,先用gst-inspect檢查一下,相應的插件是否安裝好了。
Step 1
在這一步中,我們給播放器添加了暫停和進度條控制的功能。
代碼參見:
https://github.com/antkillerfarm/antkillerfarm_crazy/blob/master/gstreamer/step1/my-gst-player.py
Step 2
在這一步中,我們的修改如下:
1.添加了快進和慢進的功能。
2.使用gst_parse_launch創(chuàng)建pipeline。該pipeline可以播放視頻文件。
代碼參見:
https://github.com/antkillerfarm/antkillerfarm_crazy/blob/master/gstreamer/step2/my-gst-player.py
Step 3
在這一步中,我們使用一般的GStreamer函數(shù)構建和Step 2相同的pipeline。
代碼參見:
https://github.com/antkillerfarm/antkillerfarm_crazy/blob/master/gstreamer/step3/my-gst-player.py
這里需要注意以下幾點:
1.隨機Pad只能用pad-add消息回調的方式添加。
2.以下代碼片段在這里都可用,盡管不完全等效,請注意用法和差別:
new_pad_type = new_pad.get_current_caps().get_structure(0).get_name() new_pad_type = new_pad.query_caps(None).to_string()從這里也可以看出,gst_parse_launch會自動處理媒體流的格式匹配問題,而使用普通函數(shù)的時候,必須自己編程處理格式匹配的問題。
總結
以上是生活随笔為你收集整理的GStreamer(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GStreamer(一)
- 下一篇: 在线激活流程研究, 芯片杂烩, 软件滤波