GStreamer流媒體知識介紹
- 2019 年 10 月 3 日
- 筆記
GStreamer框架
1、GStreamer是什麼?
眾所周知,Microsoft’s Windows和Apple’s MacOS對多媒體設備、多媒體創作、播放和實時處理等方面都有很好的支援,而Linux對多媒體應用一直略顯不足,所以為了解決Linux上對多媒體方面的支援,才引進GStreamer。
GStreamer是一個通用的跨平台的流媒體應用程式框架,基於GObject,以C語言寫成。 GStreamer並不受限於音頻和影片處理,它能夠處理任意類型的數據流,因此任意一種流媒體應用都可以支援,如:MeidaPlayer、A/V Editor、VOIP、RTSP、A/V Coder等等。 GStreamer框架是基於插件(plugin)和管道(pipeline)的體系結構,框架中所有功能模組都是可插拔的組件,可隨意安裝到任意管道上,因此造就了大量的GStreamer的共享庫。
2、 pipeline是什麼?
這是個典型的MeidaPlayer的模型。
source —— 數據來源,可能是file、http、rtp等。
demux —— 負責把容器里的音影片數據剝離出來,然後分別送給audio/video decoder。
decoder —— 解碼,然後把解完後的數據(pcm/yuv)送給audio/video output輸出。
output —— 負責將decoder過來的數據呈現出來。
如果把數據想像成流水的話,每個模組功能雖然不同,但基本都是接收上個模組過來的數據,然後加工,把加工後的數據送到下一個模組,這些模組通過某種方式連接起來,就形成了一個流水線(pipeline),這個流水線就是一個MediaPlayer。 GStreamer 把每個模組都看做是一個元件(element),然後構建連接和操作這些element的方法,用戶可以通過自己的需求把不同的elements排列組合,形成不同的pipeline。
3. element是什麼?
element是一個對多媒體流進行處理的object,也是一個具體的功能模組,是pipeline的最小組成部分。
element分類:source(只提供數據源),sink(如播放設備),transform,demuxer,muxer element的輸入為sink pad,輸出為source pad,通過pad把element連接起來構成pipeline 圖中downstream為順流方向,upstream為逆流方向
4. pad是什麼?
element的襯墊(pad)對應輸入和輸出介面,對於輸入襯墊為sink pad,對於輸出襯墊為source pad element之間都是通過pad來鏈接的,順序流向不能錯,也基於pad類型進行分類
pad有處理特殊數據的能力,一個pad能夠限制數據流類型(GstCaps)的通過。 鏈接成功的條件是:只有在兩個襯墊(pads)允許通過的數據類型一致的時候才被建立,通過caps negotiation方法。 襯墊有三種類型的時效性: 永久型(always)、隨機型(sometimes)、請求型(on request)。 永久型的襯墊一直會存在,隨機型的襯墊只在某種特定的條件下才存在(會隨機消失的襯墊也屬於隨機型), 請求型的襯墊只在應用程式明確發出請求時才出現。
5. 四種狀態
element有四種可能的狀態,分別是NULL,READY,PAUSED,PLAYING。
GST_STATE_NULL 默認狀態,該狀態將會回收所有被元件佔用的資源。
GST_STATE_READY 準備狀態,該狀態會得到所需的全局資源,但數據流並未處理。
GST_STATE_PAUSED 暫停狀態,元件已經對流開始處理,一旦狀態變為 PLAYING,可以重放數據流, 與PLAYING 狀態的區別是:時鐘是禁止運行的,主要對數據進行preroll。
GST_STATE_PLAYING 與 PAUSED 狀態一模一樣,但可以運行時鐘,對數據進行處理。
通過函數gst_element_set_state()可以改變一個元件的狀態,但狀態變換不能跳變,比如不能從READY狀態 直接變換到PLAYING狀態,必須經過中間的PAUSE狀態。
6. element流程
element create
gstreamer載入時,掃描/usr/lib/gstreamer-1.0目錄下的庫,識別其中的feature,並記錄相關資訊。當使用時,檢查gstreamer core是否支援該功能,如果有,則載入相應庫,獲取資訊,創建相應的element實例。
element link
element創建後,會添加到pipeline,在link時會通過gst_pad_query_caps(pad, NULL)查詢pad template caps。因為此時尚未打開設備、初始化等,所以不知道element真正支援的caps,但只要查詢的caps有交集即可link成功。
NULL->READY
該狀態下,會初始化設備,根據相應的class調用start()或open()等函數初始化相應的硬體設備,初始化class的結構參數等。
READY->PAUSED
進一步申請資源,確定相應的參數設置,同時會激活pad。然後數據預滾(preroll),當數據到達時,檢查數據時間戳是否在segment內,進行數據同步,最後就是commit,進入PAUSED。
PAUSED->PLAYING
在這個過程,設置clock時鐘運行,接收到數據時,檢查時間有效性,進行數據同步、處理,push到下游,發送QOS事件到上游,完成一個循環。
7. bin是什麼?
箱櫃(bin)是由多個element構成的容器,同時bin本身也是一種element,所以能夠像操作普通element一樣操作一個bin,改變bin的狀態可以改變bin內部所有elements的狀態。
bin可以發送匯流排消息給它的子集elements ,包括:錯誤消息(error messages),標籤消息(tag messages),EOS消息(EOS messages)。
管道(pipeline)是一個特殊的bin,當設定管道暫停或播放狀態的時候,數據流將開始流動,並且媒體數據處理也開始處理。一旦開始,pipeline將在一個單獨的執行緒中運行,直到被停止或者數據流播放完畢。
data flow:數據流在pads之間傳送,封裝在Buffer里,Buffer包含指向數據的指針和一些metadata。
event flow:事件流與數據量不同,既有downstream方向,也有upstream,可以捕捉事件訊號,進行回調處理
pipeline構建過程
gst_pipeline_new()函數:創建一個pipeline
gst_bin_add()函數:向pipeline中添加elements
gst_bin_remove()函數:從pipeline中移除element
gst_element_link()函數:鏈接pipeline中的elements
8. 緩衝區
緩衝區是指管道里的數據流,通常一個源元件會創建一個新的緩衝區,同時元件還將會把緩衝區的數據傳遞給下一個元件。使用GStreamer創建管道,不需要自己來處理緩衝區,元件將會自動處理這些緩衝區。
一個緩衝區主要組成:
指向某塊記憶體的指針
記憶體的大小
緩衝區的時間戳
一個引用計數,指出了緩衝區所使用的元件數。沒有元件可引用的時候,這個引用將用於銷毀緩衝區
9. message/event/signal
Bus message —— 用於gstreamer和app之間交互的,比如當一個文件播放結束的時候,gstreamer會發一個EOS的message到GstBus上,如果app有去偵聽(函數gst_bus_add_watch),那麼在處理消息的callback函數中就可以收到這個消息。
event —— 用於gstreamer內部element之間(或pad之間)傳遞事件的,比如source element數據已經結束,會發出一個EOS event,順著pipeline依次向downstream方向傳遞,elements得到通知,做一些cleanup工作,當所有sink element都收到並處理之後,gstreamer內部產生一條GSTMessage,並post至GstBus,如果APP有監聽,就能知道當前播放已經結束。
signal —— 屬於GObject體系,用於app和GObject之間交互的一種機制。在gstreamer中,element本身也是gobject,所以通過signal,就可以將app和element聯繫起來。 當element發生了一些事情相讓app知道時,就可以用signal的方式來通知app,比如動態創建了一個Pad。
10. 初步總結
需要包含頭文件gst/gst.h來訪問庫函數。
使用gst_init初始化GStreamer庫和一些必要的參數。
使用gst_element_factory_make創建元件,參數為工廠對象名和新元件名,在bin中可查詢該元件。
使用gst_object_unref釋放元件,元件引用記數減1,任一元件創建時,引用記數為1,當引用記數為0時,元件會被銷毀。
使用gst_bin_new或gst_pipeline_new創建箱櫃。
使用gst_bin_add/remove添加/移除元件,元件所屬箱櫃,銷毀箱櫃,則箱櫃中的元件同樣被銷毀,元件移除則自動銷毀。
使用gst_element_link鏈接元件
每個管道默認包含一個匯流排,應用程式不需要再創建匯流排,只需在匯流排上設置一個消息處理器,匯流排會輪詢消息處理器是否有新的消息,當採集到消息後,匯流排將呼叫相應的回調函數來處理。使用gst_bus_add_watch或gst_bus_add_signal_watch偵聽回調,或使用gst_bus_peek/poll主動輪詢消息。
11. 編譯說明
比如之前的helloworld程式
編譯: gcc -Wall helloworld.c -o helloworld $(pkg-config –cflags –libs gstreamer-0.10)
編譯時藉助了pkg-config命令,用於獲得某一個庫/模組的所有編譯相關的資訊。
pkg-config –cflags –libs gstreamer-0.10 會把gstreamer-0.10編譯所依賴的庫路徑和頭文件路徑全部找出來,不用再依次寫出,這條命令參數相當於: -pthread -I/usr/include/glib-2.0 -I/usr/lib/i386-linux-gnu/glib-2.0/include -I/usr/include/gstreamer-0.10 -I/usr/include/libxml2 -pthread -L/usr/lib/i386-linux-gnu -lgstreamer-0.10 -lgobject-2.0 -lgmodule-2.0 -lxml2 -lgthread-2.0 -lrt -lglib-2.0)