iT邦幫忙

2026 iThome 鐵人賽

DAY 25
0

今天的目標就是給元件加上屬性,我們得先了解這個元件要完成什麼任務,再去新增任務需要的屬性

規劃屬性

任務目標

將每一個來源的像素RGBA數值順序換為GBRA,例如原本像素RGBA是[255,125,0,255],那麼新的像素RGBA是[125,0,255,255]

屬性

因為我們的目標是呼叫CUDA kernel修改影格的數據,必須知道要在哪一個GPU上操作,所以我們要新增一個gpu-id屬性,讓我們可以在對應的GPU上建立需要的資源

開始新增屬性

新增property_id

先到`gstironmancolormagic.c`的上半部,有一個
```c
enum
{
    PROP_0
};

我們在下面新增新的值,這個是用來代表GObject的property_id。除此之外還建議用Macro定義預設值,因為不只一處會用到

enum
{
  PROP_0,
  PROP_GPU_ID
};

#define DEFAULT_GPU_ID (0)

註冊屬性

我們要用的這些函式,g_object_install_property、g_param_spec_uint

void
g_object_class_install_property (
  GObjectClass* oclass,
  guint property_id,
  GParamSpec* pspec
)

GParamSpec*
g_param_spec_uint (
  const gchar* name,
  const gchar* nick,
  const gchar* blurb,
  guint minimum,
  guint maximum,
  guint default_value,
  GParamFlags flags
)

我們進到gst_ironman_color_magic_class_init的最後面,開始註冊屬性屬性

static void
gst_ironman_color_magic_class_init (GstIronmanColorMagicClass * klass)
{
    /* Some codes */

    g_object_class_install_property(gobject_class,  PROP_GPU_ID,
        g_param_spec_gint("gpu-id", "GPU ID",
            "The ID of GPU",
            0, G_MAXUINT, DEFAULT_GPU_ID,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_READY));
}

接著就是解說一下每個參數的用意

g_object_class_install_property

  • property_id 每個屬性都要有自己的ID,就是我們前面定義的enum數值
  • pspec 屬性的描述。因為C沒有template特性,所以每個型別的屬性都有自己的g_param_spec_<type>,我們就照著參數填

g_param_spec_uint

  • name 你用g_object_set輸入的那個屬性名稱

  • nick 給人看的那個名稱

  • blurb 屬性的詳細說明

  • minimum、maximum、default_value 這就不用特別解釋了吧

  • flags

    這個比較深入GLib,可以根據需求去改變屬性用途,常見的就是讀寫權限。詳細可以看這邊GObject.ParamFlags

    G_PARAM_STATIC_STRINGS這個是用來節省複製開銷的,當加上這個flag,你的name、nick、blurb必須是靜態變數,這樣GLib就不會額外複製一份字串到GObject的實例內

    GST_PARAM_MUTABLE_READY則是GStreamer額外的flag,用來代表這個屬性只有在GST_ELEMENT_STATE_NULL和GST_ELEMENT_STATE_READY的時候可以修改,就是沒播放的時候才能改

屬性的實作

新增struct欄位

我們先到gstironmancolormagic.h改一下struct _GstIronmanColorMagic

struct _GstIronmanColorMagic
{
    GstBaseTransform base_ironmancolormagic;
    guint gpu_id;
};

初始化欄位

到gstironmancolormagic.c的gst_ironman_color_magic_init初始化欄位的值

static void
gst_ironman_color_magic_init (GstIronmanColorMagic* self)
{
    self->gpu_id = DEFAULT_GPU_ID;
}

property setter

void
gst_ironman_color_magic_set_property (GObject* object, guint property_id,
    const GValue* value, GParamSpec* pspec)
{
    GstIronmanColorMagic* self = GST_IRONMAN_COLOR_MAGIC (object);

    GST_DEBUG_OBJECT (self, "set_property");

    switch (property_id) {
        case PROP_GPU_ID:
            self->gpu_id = g_value_get_uint(value);
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
            break;
  }
}

GValue是一個通用的數值容器,所有的GObject屬性都是透過GValue來設定。它在set/get時會將保存的值「複製」一份,所以當型別是有lifetime的,例如gchar*、GObject,就要特別留意你使用的函式有沒有複製的行為

如果你的屬性是gchar*,記得設定前要先用g_free釋放舊的值,再用g_value_dup_string複製一份,請看範例

g_free(self->my_str_prop)
self->my_str_prop = g_value_dup_string(value);

property getter

void
gst_ironman_color_magic_get_property (GObject* object, guint property_id,
    GValue* value, GParamSpec* pspec)
{
    GstIronmanColorMagic* self = GST_IRONMAN_COLOR_MAGIC (object);

    GST_DEBUG_OBJECT (self, "get_property");

    switch (property_id) {
        case PROP_GPU_ID:
            g_value_set_uint(value, self->gpu_id);
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
            break;
  }
}

這邊就是把你的欄位值複製進GValue,lifetime會由GValue負責管理

釋放欄位

如果你的struct內有需要主動釋放的欄位(如gchar*),那就必須在gst_ironman_color_magic_finalize內實作釋放資源的程式碼

成果

記得先編譯,然後我們用gst-inspect-1.0看一下成果

GST_PLUGIN_PATH=$(pwd) gst-inspect-1.0 ironmancolormagic
Element Properties:

  gpu-id              : The ID of GPU
                        flags: readable, writable, changeable only in NULL or READY state
                        Unsigned Integer. Range: 0 - 4294967295 Default: 0

  name                : The name of the object
                        flags: readable, writable
                        String. Default: "ironmancolormagic0"

  parent              : The parent of the object
                        flags: readable, writable
                        Object of type "GstObject"

  qos                 : Handle Quality-of-Service events
                        flags: readable, writable
                        Boolean. Default: false

我們有加上GST_PARAM_MUTABLE_READY,所以可以看到

changeable only in NULL or READY state

結論

這個步驟就是要改的地方比較多,以及最痛苦的要花時間想命名跟說明,畢竟這是要給人看得,否則開發者不知道怎麼用你寫的元件。看完gst-inspect-1.0的輸出是不是很有成就感呢?趕快自己嘗試一下吧


上一篇
[Day 24] 讓你的插件資訊有模有樣
下一篇
[Day 26] 元件的開始與停止
系列文
深入認識DeepStream,不只是停在執行範例 共 29 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言