2020年10月13日 星期二

【暫存】GStreamer 學習筆記

GStreamer

GStreamer是什麼?

GStreamer是一個通用的跨平台的流媒體應用程序框架,基於GObject,以C語言寫成。 GStreamer並不受限於音頻和視頻處理,它能夠處理任意類型的數據流,因此任意一種流媒體應用都可以支持,如:MeidaPlayer、A/V Editor、VOIP、RTSP、A/V Coder等等。 GStreamer框架是基於插件(plugin)和管道(pipeline)的體系結構,框架中所有功能模塊都是可插拔的組件,可隨意安裝到任意管道上,因此造就了大量的GStreamer的共享庫。

pipeline是什麼?

每個模塊功能雖然不同,但基本都是接收上個模塊過來的數據,然後加工,把加工後的數據送到下一個模塊,這些模塊通過某種方式連接起來,就形成了一個流水線(pipeline) ,這個流水線就是一個MediaPlayer。


element是什麼?

element是一個對多媒體流進行處理的object,也是一個具體的功能模塊,是pipeline的最小組成部分。

element分類:
  • source(只提供數據源)
  • sink(如播放設備)
  • transform,demuxer,muxer element的輸入為sink pad,輸出為source pad
通過pad把element連接起來構成pipeline。

pad是什麼?

element的pad對應輸入和輸出接口,對於輸入為sink pad,對於輸出為source pad,element之間都是通過pad來鏈接。pad有處理特殊數據的能力,一個pad能夠限制數據流類型(GstCaps)的通過。鏈接成功的條件是:只有在兩個pads允許通過的數據類型一致的時候才被建立。通過caps negotiation方法。

上面這段白話一點的講法是這樣:
pad相當於element的接口,各個element即通過pad連接進行傳輸數據,同時pad會通過caps限制特定的數據類型通過,只有當兩個pad的caps數據類型一致時才可以建立連接。

  • 永久型(always)的pad一直會存在,以videotestsrc元素为例,该元素的Pad Templates类型为Always,该类型表示此gst元素一直存在pad,无需动态创建。同是这种类型的两个元素连接时,直接使用gst_element_link或gst_element_link_many进行连接即可。
  • 隨機型(sometimes)的pad只在某種特定的條件下才存在(會隨機消失的襯墊也屬於隨機型),这种类型的pad我们以rtspsrc元素为例,如下是该元素的pad信息。这种类型的元素在连接时则不能直接使用gst_element_link等接口,而是需要用到该元素的pad-added的signal来实现。
  •  請求型(on request)的pad只在應用程序明確發出請求時才出現,典型的gst元素就是tee。获取元素的Request Pad接口为gst_element_get_request_pad,而获取Always Pad的接口为gst_element_get_static_pad。如下展示了tee元素与后端的两个queue元素的连接方法。
每個pad,都會有以下屬性:padname、direction、presence、caps。
  • padname:padName
  • direction:pad的輸入輸出方向,有src和sink兩種
  • presence:pad的時效性,有永久型GST_PAD_ALWAYS,隨機型GST_PAD_SOMETIMES,請求型GST_PAD_REQUEST,請求型的僅在gst_element_request_pad(),隨機類型的則是會根據不同的輸入數據使用不同的pad
  • caps:pad支持的功能

cap是什麼?

cap是指該元素可以接收什麼樣的信息( 例如是接收音頻還是視頻)。可以把cap看成是電源插座上其可以接受什麼範圍電壓的規則。

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狀態。

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事件到上游,完成一個循環。

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

緩衝區

緩衝區是指管道裡的數據流,通常一個源元件會創建一個新的緩衝區,同時元件還將會把緩衝區的數據傳遞給下一個元件。使用GStreamer創建管道,不需要自己來處理緩衝區,元件將會自動處理這些緩衝區。

一個緩衝區主要組成:
  • 指向某塊內存的指針
  • 內存的大小
  • 緩衝區的時間戳
  • 一個引用計數,指出了緩衝區所使用的元件數。沒有元件可引用的時候,這個引用將用於銷毀緩衝區

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。

總結

需要包含頭文件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主動輪詢消息。







GStreamer install


Gstreamer plugin

查詢gstreamer所有的plugin:
apt-cache search '^gstreamer1.0\-' | sort

所有gstreamer相关包

gstreamer0.10-alsa                     gstreamer1.0-clutter                   gstreamer1.0-plugins-base-dbg
gstreamer0.10-doc                      gstreamer1.0-clutter-3.0               gstreamer1.0-plugins-base-doc
gstreamer0.10-ffmpeg                   gstreamer1.0-crystalhd                 gstreamer1.0-plugins-good
gstreamer0.10-ffmpeg-dbg               gstreamer1.0-doc                       gstreamer1.0-plugins-good-dbg
gstreamer0.10-gconf                    gstreamer1.0-dvswitch                  gstreamer1.0-plugins-good-doc
gstreamer0.10-gnomevfs                 gstreamer1.0-espeak                    gstreamer1.0-plugins-ugly
gstreamer0.10-nice                     gstreamer1.0-fluendo-mp3               gstreamer1.0-plugins-ugly-amr
gstreamer0.10-plugins-base             gstreamer1.0-hybris                    gstreamer1.0-plugins-ugly-dbg
gstreamer0.10-plugins-base-apps        gstreamer1.0-libav                     gstreamer1.0-plugins-ugly-doc
gstreamer0.10-plugins-base-dbg         gstreamer1.0-libav-dbg                 gstreamer1.0-pocketsphinx
gstreamer0.10-plugins-base-doc         gstreamer1.0-nice                      gstreamer1.0-pulseaudio
gstreamer0.10-plugins-good             gstreamer1.0-packagekit                gstreamer1.0-tools
gstreamer0.10-plugins-good-dbg         gstreamer1.0-plugins-bad               gstreamer1.0-vaapi
gstreamer0.10-plugins-good-doc         gstreamer1.0-plugins-bad-dbg           gstreamer1.0-vaapi-doc
gstreamer0.10-pulseaudio               gstreamer1.0-plugins-bad-doc           gstreamer1.0-x
gstreamer0.10-qapt                     gstreamer1.0-plugins-bad-faad          gstreamer-qapt
gstreamer0.10-tools                    gstreamer1.0-plugins-bad-videoparsers  gstreamer-tools
gstreamer0.10-x                        gstreamer1.0-plugins-base              
gstreamer1.0-alsa                      gstreamer1.0-plugins-base-apps         

GStreamer Debug

gst_init(&argc, &argv);所有的 GStreamer Application,都會經過這段 Initialization 的動作,因此 gst_init() 會從 main() 得到程式被執行時所代入的後綴參數,換言之,理論上不管是什麼 Application ,我們可以透過這種方式去開啟 GStreamer 的 Debug 模式:

參考 GStreamer 官方文件,會發現有數種參數可以使用:


--gst-debug-level=LEVEL

設定 Debug 級別,LEVEL 範圍從 0 (不輸出訊息) 到 5 (輸出所有訊息)

--gst-debug=LIST

要求特定的 Plugin 所 Debug 訊息輸出,亦可以分別設定不同 plugin 有的不同 Debug 級別,格式範例:--gst-debug=GST_AUTOPLUG:5,avidemux:3

--gst-plugin-spew

輸出 Plugin 載入的錯誤訊息

Gstreamer學習筆記:GStreamer Debugging

DeepStream4.0系列之pipeline分析工具

【Gstreamer】如何生成pipeline构件图

gstreamer基礎教程11-Debugging tools


gst-launch-1.0的應用

如何通过gstreamer将RTSP视频流保存到MP4文件?

gst-launch-1.0 -e rtspsrc location=rtsp://addr/ user-id=xxx user-pw=xxxx latency=0 ! rtph264depay ! h264parse ! queue ! avdec_h264 ! vaapih264enc bitrate=8000 keyframe-period=30 rate-control=vbr ! mp4mux ! filesink location=test.mp4


使用 WebRTC 的 GPU 加速流式传输

rtsp

gst-inspect-1.0 | grep src
gst-inspect-1.0 | grep sink
gst-launch-1.0 rtspsrc location=rtsp://192.168.50.246/profile1 user-id=admin user-pw=admin ! rtph264epay ! h264parse ! vaapih264dec ! videoconvert ! ximagesink
ls -la /dev/video*
gst-launch-1.0 v4l2src ! videoconvert ! ximagesink

Share Memory

shmsink & shmsrc用來串接兩個程式之間的pipeline或資料

GStreamer API Reference

GLib Reference Manual

GStreamer and webRTC example and introduce

https://gstreamer.freedesktop.org/data/events/gstreamer-conference/2017/Matthew%20Waters%20-%20GStreamer%20WebRTC.pdf


Install develop environment

apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-pulseaudio


https://stackoverflow.com/questions/54331208/how-can-i-configure-ubuntu-16-04-lts-to-develop-gstreamer-applications

Reference

1 則留言: