gst-inspect-1.0我認為比起一上來就執行範例,先認識GStreamer的工具是必要的,先透過這些工具我們可以先釐清DeepStream的關鍵要素
gst-inspect-1.0是什麼這個工具的功能很單純,就是負責用來看插件的說明,我們來試用一下吧,建議大家可以一邊看一邊操作哦!
gst-inspect-1.0 --version
這個步驟其實挺重要的,因為GStreamer還是有持續在更新。我曾經在測試Intel的DLStreamer時使用了更新版本的GStreamer,觸發了一個完全沒有頭緒的錯誤,後來直接除錯GStreamer原始碼搞了幾天才找到原因是GStreamer在某個版本改動了一個框架資料複製的行為。所以為了避免類似的事情發生,請記得版本要跟SDK的依賴對齊哦!
這個指令可以直接查詢你的GStreamer能辨識到的所有插件
gst-inspect-1.0 --plugin
可以透過grep來篩選出NVIDIA提供的插件
gst-inspect-1.0 --plugin | grep "^nv"
我們挑其中一部分輸出來解釋,nvdsgst_multistream是插件名稱,而nvstreamdemux和nvstreammux則是這個插件提供的元件(Element)
nvdsgst_multistream: nvstreamdemux: Stream demultiplexer
nvdsgst_multistream: nvstreammux: Stream multiplexer
我們就以其中一個比較重要的插件nvvideoconvert來介紹
gst-inspect-1.0 nvvideoconvert
這是元件的基本資訊,挑幾個重要的欄位來說明
Rank
GStreamer有提供一個叫autoplugging的功能,某一些高階元件會做為抽象層,功能的實現是在runtime的時候從插件清單裡面去找出可以使用的元件,而Rank就是挑選時的一項指標,數字越高就會越優先被挑選。當你有使用到這類元件時再去留意就好,其他時候可以忽略。
Klass
他本來的目的是讓使用者可以辨識這個元件的作用域,例如操作Video或Audio,作用的方式如Effect、Analyzer。但是因為插件開發時,這段文字完全是用字串表達,可以輸入任意內容,導致這項資訊往往很混亂,會有定義不清楚或是完全不照定義的問題,所以當作參考就好。
Filename
這個插件是從哪個動態庫找到的。這很重要,因為插件都是用動態庫佈署的,有這項資訊可以提供一個排查問題的方向,畢竟載錯程式庫這種事情也不是不會發生。
其他資訊還是有相同的問題,就是都是用字串描述出來的,如果開發者對於框架也不是那麼熟,那麼這些資訊就會顯得很混亂,所以大多時候參考即可。

因為GStreamer是基於GLib開發的,GLib用C實現了物件導向的設計方式,GObject就是所有物件的基底,GstObject則是GStreamer物件的基底。我們可以透過繼承圖去查詢各層類別實現的功能有哪些。


前面有提到Pad是元件的輸入端和輸出端,現在我們要更深入來了解Pad給了我們什麼資訊。
Availability
這個資訊代表元件在什麼時候可以使用這個Pad。Always代表這個Pad在元件的整個生命周期都存在,對於存在的Pad我們要使用gst_element_get_static_pad去取得
GstPad *
gst_element_get_static_pad (GstElement * element,
const gchar * name)
剩下2種是On request和Sometimes,因為nvvideoconvert沒有這種Pad,所以我們就先跳過,後續遇到的時候會再跟大家說明。有興趣的人可以先查一下相關的資料哦。
Capabilities
先看黃色字video/x-raw,這代表Pad進來的資料是什麼型式,上下游之間要一致。另外綠色的字memory:NVMM代表的是這個資料有什麼feature,看到這邊我們要迎來DeepStream的其中一個重要觀念,就是memory:NVMM這個feature。在DeepStream中,這個feature代表這份資料是存放在GPU上,而元件之間只傳遞這份資料相關的GPU資訊,例如GPU ID、GPU Memoery Address。
format, width, height, framerate
剩下這些就是各種描述影像資料的屬性,只有要寫出來的都代表元件可以支援,但真正執行的時候只會鎖定一個固定值。
那我們就要來了解nvvideoconvert在DeepStream中扮演什麼角色。它的核心任務就是把原本存在Host端(RAM)的影像資料搬運到GPU端(VRAM),等AI串流的任務都完成後,再把資料搬回Host端。這個元件同樣也是DeepStream元件和其他GStreamer元件互動的關鍵,因為一般的GStreamer插件都是把資料放在Host端。
實際上這要怎麼運作呢?搬進GPU就是讓Sink Pad是video/x-raw,Src Pad是video/x-raw(memory:NVMM),反之搬出GPU就是讓Sink Pad是video/x-raw(memory:NVMM),Src Pad是video/x-raw

因為元件是基於GObject設計的,所以物件本身具備屬性的概念。不過為什麼屬性得透過工具查詢呢?因為元件在使用時是不會#include對應的.h檔案,必須要透過GLib的g_object_set和g_object_get來存取物件的屬性,我們來看一下這兩個function的宣告
void
g_object_set (
GObject* object,
const gchar* first_property_name,
...
);
void
g_object_get (
GObject* object,
const gchar* first_property_name,
...
);
如果我要設定上圖看到gpu-id和interpolation-method,我們就必須這樣寫
g_object_set(element,
"gpu-id", 1,
"interpolation-method", 1,
NULL);
留意到問題了嗎?那就是我們只能透過屬性的名稱(字串)去存取屬性的值,甚至連型別都是不明確的,如果使用錯誤也只能在runtime發現。會有這樣的設計方式,就我查到的資訊是說GLib當初在設計的時候,其目標是為了確保使用的方便性,效能或是型別安全往往都是其次。總而言之,如果你是比較吹毛求疵的C開發者,在這邊就把那些執念放下吧!用就對了。

因為nvvideoconvert沒有這項,所以上圖是先從nvurisrcbin借來的。Signal這名字是GObject定義的,但其實就是大家熟知的事件(Event),可以透過signal去處理runtime時發生的事情。例如nvurisrcbin就必須透過pad-added去處理上下游連接的事情,這邊我們就先帶大家認識有這個資訊就好。

這同樣是從nvurisrcbin借來的。同樣是從GObject定義的,就是大家熟悉的物件的方法(Method),但這在GStreamer當中就比較少用到囉。
今天文字內容也不少,學完了今天的內容,你就可以先去查查每個DeepStream元件的資訊囉。明天就要帶大家透過另外一個工具來跑串流,我們將會用到DeepStream的元件哦。