iT邦幫忙

2026 iThome 鐵人賽

DAY 22
0

為什麼你應該試著寫插件

DeepStream的限制

DeepStream的範例程式基本上都希望你照著設計好的方式開發,最明顯能感受到的就是PGIE和SGIE的設計,設計上只接受模型的輸入只有一個影像Tensor (NCHW或NHWC格式),並且要照著PGIE負責偵測物體,SGIE負責分類物體的方式運作。雖然SDK有提供一些Hook手段或是Tensor輸出/輸入手段,但不可能滿足所有應用的需求,維護上也很困難,必須跟著DeepStream的版本走,就實際的經歷來說,版本迭代的速度其實很快,必然會造成維護的負擔

寫插件其實不困難

我相信當一個團隊決定要採用一個框架時,往往都希望直接使用別人開發完成的工具就好,但我們總不能祈禱當遇到一個需求是既有程式庫沒有的時候,會有人跳出來幫你開發對吧?

我所處的團隊初期也是面臨這種情況,但在我研究了GStreamer這個框架一段時間後發現,其實有工具可以生成插件模板,在大部分應用情境下也不需要了解太多框架的知識,於是我就勇敢地站出來說,我要開發自己的插件

需要哪些知識

學會C以及習慣GLib

首先必須得了解用C開發程式的習慣及技巧,在這個充斥著使用物件導向及擁有高階特性的程式語言的時代,我們得回到最原始的程式是如何運作的:

  • 用struct定義一組有意義的資料
  • 用function去操作這一組資料,實現特定的邏輯

其實用心感受一下就會發現,這就是最低配的物件導向,沒有繼承,沒有多型,就只有一組資料,數個函式實現邏輯

講到這裡我非常推薦對C/C++很陌生的人去看一次這支影片,POINTERS in C++。這裡面有提到一個很重要的觀念,而GObject也是這麼設計的

Everything is memory

剩下的就是習慣GLib提供的記憶體分配、字串操作、容器型別(GArray、GHashTable)

學會看GLib和GStreamer的文件

不得不提一下,我認為身為一位好的工程師,首要需求是會讀文件而不是會寫程式,很多知識其實文件就有告訴你,寫出正確的程式不是問題。反而是連文件都不看,又怎麼會期望你寫出來的程式是對的呢

首先是GLib,我就舉例g_strdup這個函式

gchar*
g_strdup (
  const gchar* str
)

這份文件注意幾個重點

  • 輸入可以是NULL

    If str is NULL it returns NULL.

  • str是呼叫端擁有

    The data is owned by the caller of the function.

    看到這句話就是你有責任保證變數的生命週期

  • str必須是NUL terminated

    The value is a NUL terminated UTF-8 string

    C所認知的字串就是一個char array以null char(\0)做結尾

  • 回傳值要釋放

    A newly-allocated copy of str.The caller of the function takes ownership of the data, and is responsible for freeing it.

重點基本上放在參數是否接受NULL,以及變數的擁有權在哪一端

再來是GStreamer的部分,以gst_element_factory_make作為例子

  • 參數或回傳是否可以是NULL

    GStreamer的文件中,如果變數可能是NULL,正常會寫上[nullable]。少數比較新的或沒在維護的文件可能什麼都沒寫

  • 變數的所有權轉移

    只要需要管理生命週期的變數,應該會看到文件寫上[transfer:none]、[transfer:full]、[transfer:floating]這幾種可能。[transfer:none]代表你不需要釋放或解引用(unref)這個變數,[transfer:full]代表你必須要釋放或解引用。

    [transfer:floating]比較特別,因為GStreamer的物件是可以有從屬關係的,當GstObject擁有Parent時,Parent有責任釋放,在此之前GstObject的引用狀態屬於floating,你有責任要釋放

插件提供的優勢

自訂Pad Capabilities

你可以限制特定的Caps,框架自己會協商到你能接受的輸入格式上,這在DeepStream提供的Hook是做不到的

根據你的需求制訂屬性

DeepStream沒有給的屬性,我們自己加上去,依照需求做出最大的彈性

深入框架

先前有示範過用GstProbe修改GstBuffer的數據,可是這麼做的維護成本也比較高,最大的缺點就是不能搭配gst-launch-1.0使用。如果自己開發插件,那就能有效管理這些邏輯,並且還能直接用gst-launch-1.0測試

維護成本

這是我在實際任務中面臨的困境,我們的需求不得不去修改nvinfer的原始碼,起初改一個版本還好,後來發現大概半年DeepStream就更新一個版本,每次更新的原始碼變動幅度又很大,加上DeepStream官方只會持續維護2 ~ 3個版本,長期來看不是一個合適的做法。雖然是自己寫元件搭配DeepStream使用,可是至少在API層面的相容性保證是很高的,不會輕易有Breaking Changes

自由運用GStreamer

你可以設計自己的GstMessage跟應用程式互動,也可以直接操作GstEvent跟Pipeline上的其他元件互動,總之寫元件的好處就是你可以善用框架提供給你的資源

結語

第一次寫插件的時候心裡也是抱持著會不會失敗的擔憂,但嘗試過後發現一點都不困難,而且當我用gst-inspect-1.0看見自己的元件資訊被顯示出來時,那個成就感是非常的棒


上一篇
[Day 21] 如何建立User Metadata
系列文
深入認識DeepStream,不只是停在執行範例 共 22 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言