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)