今天的目標就是給元件加上屬性,我們得先了解這個元件要完成什麼任務,再去新增任務需要的屬性
將每一個來源的像素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));
}
接著就是解說一下每個參數的用意
property_id 每個屬性都要有自己的ID,就是我們前面定義的enum數值pspec 屬性的描述。因為C沒有template特性,所以每個型別的屬性都有自己的g_param_spec_<type>,我們就照著參數填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的時候可以修改,就是沒播放的時候才能改
我們先到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;
}
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);
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的輸出是不是很有成就感呢?趕快自己嘗試一下吧