阶段 | 相应API | 作用 | GObject 调用顺序 | GstObject | GstElement |
1 | xxx_yyy_get_type() |
创建TypeNode, 并且赋值一些APIs: base_class_init() class_init() instance_init(), 等等 |
|||
2 | g_type_class_ref() |
调用base_class_init() 从父-->子, |
g_object_base_class_init() |
1. 父类:g_object_base_class_init() 2. 自己没有base_init() |
1. 爷爷:g_object_base_class_init() 2. 父亲没有base_init() 3. gst_element_base_class_init |
调用class_init(), 指定各种APIs 包括class->constructor(), set_property()/get_property() dispose()/finalize() |
g_object_do_class_init() |
gst_object_class_init() 1. 首选取得GObjectClass 2. 重载一些函数 3. 装载一些自己的signal |
gst_element_class_init() 1. 首选取得GObjectClass 2. 把GObjectClass的一些函数换成自己的(重载) 3. 装载自己的信号 |
||
3 | g_object_new() |
调用class->constructor() --> g_type_create_instance() --> 父类的instance(), 自己的instance() |
g_object_constructor()->g_type_create_instance() -> 1. g_object_init() |
g_object_constructor()->g_type_create_instance() -> 1. 父亲:g_object_init() 2.自己:gst_object_init() |
g_object_constructor()->g_type_create_instance() -> 1. 爷爷:g_object_init() 2.父亲:gst_object_init() 3. 自己:gst_element_init()
|
set properties |
1. 这个API完成GObject类型的注册
2. GObject 作为一个基础类型,放入全局数组以及Hash Table中
3. 分配GObject Node的数据,并且把用户指定的一系列函数指针赋值过去
4. 此时还没有真正的GObject对象实例。
void g_type_init (void) { g_type_init_with_debug_flags (0); }
/* G_TYPE_OBJECT */ g_object_type_init ();
void g_object_type_init (void) { static gboolean initialized = FALSE; static const GTypeFundamentalInfo finfo = { G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE, }; static GTypeInfo info = { sizeof (GObjectClass), (GBaseInitFunc) g_object_base_class_init, (GBaseFinalizeFunc) g_object_base_class_finalize, (GClassInitFunc) g_object_do_class_init, NULL /* class_destroy */, NULL /* class_data */, sizeof (GObject), 0 /* n_preallocs */, (GInstanceInitFunc) g_object_init, NULL, /* value_table */ }; static const GTypeValueTable value_table = { g_value_object_init, /* value_init */ g_value_object_free_value, /* value_free */ g_value_object_copy_value, /* value_copy */ g_value_object_peek_pointer, /* value_peek_pointer */ "p", /* collect_format */ g_value_object_collect_value, /* collect_value */ "p", /* lcopy_format */ g_value_object_lcopy_value, /* lcopy_value */ }; GType type; g_return_if_fail (initialized == FALSE); initialized = TRUE; /* G_TYPE_OBJECT */ info.value_table = &value_table; type = g_type_register_fundamental (G_TYPE_OBJECT, g_intern_static_string ("GObject"), &info, &finfo, 0); g_assert (type == G_TYPE_OBJECT); g_value_register_transform_func (G_TYPE_OBJECT, G_TYPE_OBJECT, g_value_object_transform_value); }
这里注册GObject类型:
1. 指定这个类型的标记flag
static const GTypeFundamentalInfo finfo = {
G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE,
};
2. 注册Class的GTypeInfo. 相关的几个函数指针
3. 注册GObject type的函数表Value Table
问题来了:
g_object_base_class_init、g_object_do_class_init、g_object_init 何时被调用?
有什么严格的顺序吗?
我们先看看GObject的内部注册过程中,干了些什么?然后再看看基于Gobject生成新的object实例时
做了些什么?
GType g_type_register_fundamental (GType type_id, const gchar *type_name, const GTypeInfo *info, const GTypeFundamentalInfo *finfo, GTypeFlags flags) { TypeNode *node; G_WRITE_LOCK (&type_rw_lock); node = type_node_fundamental_new_W (type_id, type_name, finfo->type_flags); type_add_flags_W (node, flags); if (check_type_info_I (NULL, NODE_FUNDAMENTAL_TYPE (node), type_name, info)) type_data_make_W (node, info, check_value_table_I (type_name, info->value_table) ? info->value_table : NULL); G_WRITE_UNLOCK (&type_rw_lock); return NODE_TYPE (node); }
其中关系不大的代码去掉了。
因为GObject是基础类型,没有父节点,所以代码中,去掉了部分。
static TypeNode* type_node_any_new_W (TypeNode *pnode, GType ftype, const gchar *name, GTypePlugin *plugin, GTypeFundamentalFlags type_flags) { guint n_supers; GType type; TypeNode *node; guint i, node_size = 0; n_supers = pnode ? pnode->n_supers + 1 : 0; if (!pnode) node_size += SIZEOF_FUNDAMENTAL_INFO; /* fundamental type info */ node_size += SIZEOF_BASE_TYPE_NODE (); /* TypeNode structure */ node_size += (sizeof (GType) * (1 + n_supers + 1)); /* self + ancestors + (0) for ->supers[] */ node = g_malloc0 (node_size); if (!pnode) /* offset fundamental types */ { node = G_STRUCT_MEMBER_P (node, SIZEOF_FUNDAMENTAL_INFO); static_fundamental_type_nodes[ftype >> G_TYPE_FUNDAMENTAL_SHIFT] = node; type = ftype; } node->n_supers = n_supers; if (!pnode) { node->supers[0] = type; node->supers[1] = 0; node->is_classed = (type_flags & G_TYPE_FLAG_CLASSED) != 0; node->is_instantiatable = (type_flags & G_TYPE_FLAG_INSTANTIATABLE) != 0; if (NODE_IS_IFACE (node)) { IFACE_NODE_N_PREREQUISITES (node) = 0; IFACE_NODE_PREREQUISITES (node) = NULL; } else _g_atomic_array_init (CLASSED_NODE_IFACES_ENTRIES (node)); } TRACE(GOBJECT_TYPE_NEW(name, node->supers[1], type)); node->plugin = plugin; node->n_children = 0; node->children = NULL; node->data = NULL; node->qname = g_quark_from_string (name); node->global_gdata = NULL; g_hash_table_insert (static_type_nodes_ht, GUINT_TO_POINTER (node->qname), (gpointer) type); return node; }
上面重要的地方:
static_fundamental_type_nodes[ftype >> G_TYPE_FUNDAMENTAL_SHIFT] = node; //把G_OBJECT_TYPE放入基础类型数组。
node->supers[0] = type; //没有父亲节点
node->supers[1] = 0;
node->is_classed = (type_flags & G_TYPE_FLAG_CLASSED) != 0; //可类化
node->is_instantiatable = (type_flags & G_TYPE_FLAG_INSTANTIATABLE) != 0; //可实例化
下面是把前面设置的GObject的标识:存入node的qdata中,用quark:static_quark_type_flags 来标识。
即:
static void type_add_flags_W (TypeNode *node, GTypeFlags flags) { guint dflags; g_return_if_fail ((flags & ~TYPE_FLAG_MASK) == 0); g_return_if_fail (node != NULL); if ((flags & TYPE_FLAG_MASK) && node->is_classed && node->data && node->data->class.class) g_warning ("tagging type `%s' as abstract after class initialization", NODE_NAME (node)); dflags = GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags)); dflags |= flags; type_set_qdata_W (node, static_quark_type_flags, GUINT_TO_POINTER (dflags)); }
重点是下面:
/* --- type info (type node data) --- */ static void type_data_make_W (TypeNode *node, const GTypeInfo *info, const GTypeValueTable *value_table) { TypeData *data; GTypeValueTable *vtable = NULL; guint vtable_size = 0; g_assert (node->data == NULL && info != NULL); if (!value_table) { TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); if (pnode) vtable = pnode->data->common.value_table; else { static const GTypeValueTable zero_vtable = { NULL, }; value_table = &zero_vtable; } } if (value_table) { /* need to setup vtable_size since we have to allocate it with data in one chunk */ vtable_size = sizeof (GTypeValueTable); if (value_table->collect_format) vtable_size += strlen (value_table->collect_format); if (value_table->lcopy_format) vtable_size += strlen (value_table->lcopy_format); vtable_size += 2; } if (node->is_instantiatable) /* carefull, is_instantiatable is also is_classed */ { TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); data = g_malloc0 (sizeof (InstanceData) + vtable_size); if (vtable_size) vtable = G_STRUCT_MEMBER_P (data, sizeof (InstanceData)); data->instance.class_size = info->class_size; data->instance.class_init_base = info->base_init; data->instance.class_finalize_base = info->base_finalize; data->instance.class_init = info->class_init; data->instance.class_finalize = info->class_finalize; data->instance.class_data = info->class_data; data->instance.class = NULL; data->instance.init_state = UNINITIALIZED; data->instance.instance_size = info->instance_size; /* We'll set the final value for data->instance.private size * after the parent class has been initialized */ data->instance.private_size = 0; data->instance.class_private_size = 0; if (pnode) data->instance.class_private_size = pnode->data->instance.class_private_size; #ifdef DISABLE_MEM_POOLS data->instance.n_preallocs = 0; #else /* !DISABLE_MEM_POOLS */ data->instance.n_preallocs = MIN (info->n_preallocs, 1024); #endif /* !DISABLE_MEM_POOLS */ data->instance.instance_init = info->instance_init; } else if (node->is_classed) /* only classed */ { TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); data = g_malloc0 (sizeof (ClassData) + vtable_size); if (vtable_size) vtable = G_STRUCT_MEMBER_P (data, sizeof (ClassData)); data->class.class_size = info->class_size; data->class.class_init_base = info->base_init; data->class.class_finalize_base = info->base_finalize; data->class.class_init = info->class_init; data->class.class_finalize = info->class_finalize; data->class.class_data = info->class_data; data->class.class = NULL; data->class.class_private_size = 0; if (pnode) data->class.class_private_size = pnode->data->class.class_private_size; data->class.init_state = UNINITIALIZED; } else if (NODE_IS_IFACE (node)) { data = g_malloc0 (sizeof (IFaceData) + vtable_size); if (vtable_size) vtable = G_STRUCT_MEMBER_P (data, sizeof (IFaceData)); data->iface.vtable_size = info->class_size; data->iface.vtable_init_base = info->base_init; data->iface.vtable_finalize_base = info->base_finalize; data->iface.dflt_init = info->class_init; data->iface.dflt_finalize = info->class_finalize; data->iface.dflt_data = info->class_data; data->iface.dflt_vtable = NULL; } else if (NODE_IS_BOXED (node)) { data = g_malloc0 (sizeof (BoxedData) + vtable_size); if (vtable_size) vtable = G_STRUCT_MEMBER_P (data, sizeof (BoxedData)); } else { data = g_malloc0 (sizeof (CommonData) + vtable_size); if (vtable_size) vtable = G_STRUCT_MEMBER_P (data, sizeof (CommonData)); } node->data = data; if (vtable_size) { gchar *p; /* we allocate the vtable and its strings together with the type data, so * children can take over their parent's vtable pointer, and we don't * need to worry freeing it or not when the child data is destroyed */ *vtable = *value_table; p = G_STRUCT_MEMBER_P (vtable, sizeof (*vtable)); p[0] = 0; vtable->collect_format = p; if (value_table->collect_format) { strcat (p, value_table->collect_format); p += strlen (value_table->collect_format); } p++; p[0] = 0; vtable->lcopy_format = p; if (value_table->lcopy_format) strcat (p, value_table->lcopy_format); } node->data->common.value_table = vtable; node->mutatable_check_cache = (node->data->common.value_table->value_init != NULL && !((G_TYPE_FLAG_VALUE_ABSTRACT | G_TYPE_FLAG_ABSTRACT) & GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags)))); g_assert (node->data->common.value_table != NULL); /* paranoid */ g_atomic_int_set ((int *) &node->ref_count, 1); }
这里有个union的变量:node->data: 可选4个类型:BoxedData/IFaceData/ClassData/InsanceData
node->is_instantiatable = 1
所以选择InstanceData
if (node->is_instantiatable) /* carefull, is_instantiatable is also is_classed */ { TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node)); data = g_malloc0 (sizeof (InstanceData) + vtable_size); if (vtable_size) vtable = G_STRUCT_MEMBER_P (data, sizeof (InstanceData)); data->instance.class_size = info->class_size; data->instance.class_init_base = info->base_init; data->instance.class_finalize_base = info->base_finalize; data->instance.class_init = info->class_init; data->instance.class_finalize = info->class_finalize; data->instance.class_data = info->class_data; data->instance.class = NULL; data->instance.init_state = UNINITIALIZED; data->instance.instance_size = info->instance_size; /* We'll set the final value for data->instance.private size * after the parent class has been initialized */ data->instance.private_size = 0; data->instance.class_private_size = 0; if (pnode) data->instance.class_private_size = pnode->data->instance.class_private_size; #ifdef DISABLE_MEM_POOLS data->instance.n_preallocs = 0; #else /* !DISABLE_MEM_POOLS */ data->instance.n_preallocs = MIN (info->n_preallocs, 1024); #endif /* !DISABLE_MEM_POOLS */ data->instance.instance_init = info->instance_init; }
node->data = data;
把前面class的base/class/instance的APIs, Value Table APIs, 赋值给node->data
g_type_init():
1. ....
2. g_object_type_init()
3. ...
之后应该就是g_object_new?
我们找个例子看看:
GObject
`|_____ GstObject
在gstobject.c:
G_DEFINE_ABSTRACT_TYPE (GstObject, gst_object, G_TYPE_OBJECT);
先比较一下gobject.c/gstobject.c提供的一些API:
父 | Me (当前) | 儿子 | 孙子 | 重孙子 |
GObject | GstObject | GstElement | GstBin | GstPipeline |
g_object_base_class_init() | gst_element_base_class_init | gst_bin_base_init | gst_pipeline_base_init | |
g_object_do_class_init() | gst_object_class_init() | gst_element_class_init | gst_bin_class_init | gst_pipeline_class_init |
g_object_init() | gst_object_init() | gst_element_init | gst_bin_init | gst_pipeline_init |
把宏展开,看到上面gstobject提供的两个API,绑定了:
#define _G_DEFINE_TYPE_EXTENDED_BEGIN(GstObject, gst_object, G_TYPE_OBJECT, flags) \ \ static void gst_object_init (GstObject *self); \ static void gst_object_class_init (GstObjectClass *klass); \ static gpointer gst_object_parent_class = NULL; \ static void gst_object_class_intern_init (gpointer klass) \ { \ gst_object_parent_class = g_type_class_peek_parent (klass); \ gst_object_class_init ((GstObjectlass*) klass); \ } \ \ GType \ gst_object_get_type (void) \ { \ static volatile gsize g_define_type_id__volatile = 0; \ if (g_once_init_enter (&g_define_type_id__volatile)) \ { \ GType g_define_type_id = \ g_type_register_static_simple (G_TYPE_OBJECT, \ g_intern_static_string ("GstObject"), \ sizeof (CGstObjectClass), \ (GClassInitFunc) gst_object_class_intern_init, \ sizeof (GstObject), \ (GInstanceInitFunc) gst_object_init, \ (GTypeFlags) flags); \ { /* custom code follows */ #define _G_DEFINE_TYPE_EXTENDED_END() \ /* following custom code */ \ } \ g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); \ } \ return g_define_type_id__volatile; \ } /* closes gst_object_get_type() */
首先取得父类的class数据:
gpointer g_type_class_peek_parent (gpointer g_class) { TypeNode *node; gpointer class = NULL; g_return_val_if_fail (g_class != NULL, NULL); node = lookup_type_node_I (G_TYPE_FROM_CLASS (g_class)); /* We used to acquire a read lock here. That is not necessary, since * parent->data->class.class is constant as long as the derived class * exists. */ if (node && node->is_classed && node->data && NODE_PARENT_TYPE (node)) { node = lookup_type_node_I (NODE_PARENT_TYPE (node)); class = node->data->class.class; } else if (NODE_PARENT_TYPE (node)) g_warning (G_STRLOC ": invalid class pointer `%p'", g_class); return class; }
class = node->data->class.class;
然后真正开始Init:
gst.c中:
g_type_class_ref (gst_object_get_type ());
首先会调用:
GType g_type_register_static_simple (GType parent_type, const gchar *type_name, guint class_size, GClassInitFunc class_init, guint instance_size, GInstanceInitFunc instance_init, GTypeFlags flags) { GTypeInfo info; info.class_size = class_size; info.base_init = NULL; info.base_finalize = NULL; info.class_init = class_init; info.class_finalize = NULL; info.class_data = NULL; info.instance_size = instance_size; info.n_preallocs = 0; info.instance_init = instance_init; info.value_table = NULL; return g_type_register_static (parent_type, type_name, &info, flags); }
然后指定自己的class_init/Instance_init函数,就开始创建这个TypeNode.
GType g_type_register_static (GType parent_type, const gchar *type_name, const GTypeInfo *info, GTypeFlags flags) { TypeNode *pnode, *node; GType type = 0; g_return_val_if_type_system_uninitialized (0); g_return_val_if_fail (parent_type > 0, 0); g_return_val_if_fail (type_name != NULL, 0); g_return_val_if_fail (info != NULL, 0); if (!check_type_name_I (type_name) || !check_derivation_I (parent_type, type_name)) return 0; if (info->class_finalize) { g_warning ("class finalizer specified for static type `%s'", type_name); return 0; } pnode = lookup_type_node_I (parent_type); G_WRITE_LOCK (&type_rw_lock); type_data_ref_Wm (pnode); if (check_type_info_I (pnode, NODE_FUNDAMENTAL_TYPE (pnode), type_name, info)) { node = type_node_new_W (pnode, type_name, NULL); type_add_flags_W (node, flags); type = NODE_TYPE (node); type_data_make_W (node, info, check_value_table_I (type_name, info->value_table) ? info->value_table : NULL); } G_WRITE_UNLOCK (&type_rw_lock); return type; }
1. type_data_ref_Wm (pnode); //给父节点增加一个引用计数
2. node = type_node_new_W (pnode, type_name, NULL); //从父节点拷贝出一份内存,并且建立父子关系;
并且把新创建的“子节点” 保存在父节点的数组中:pnode->children[i] = type;
3. type_data_make_W, 就是用户指定的各种APIs, Value Table APIs, 指定给这个新建的Type Node, 这里是给GstObject
g_type_class_ref(GstObject);
这个函数是个循环嵌套函数!
gpointer g_type_class_ref (GType type) { TypeNode *node; GType ptype; gboolean holds_ref; GTypeClass *pclass; /* optimize for common code path */ node = lookup_type_node_I (type); /* we need an initialized parent class for initializing derived classes */ ptype = NODE_PARENT_TYPE (node); pclass = ptype ? g_type_class_ref (ptype) : NULL;
它会顺藤摸瓜!找到最上面的祖先:
这里它会找到GObject (GstObject的父类),GObject已经是最顶层了。
好,接着往下:
if (!holds_ref) type_data_ref_Wm (node); if (!node->data->class.class) /* class uninitialized */ type_class_init_Wm (node, pclass);
最关键的地方:如果当前class并没有被初始化,则进行初始化。
先初始化GObject, 然后轮到其儿子:GstObject.
对某个typeclass进行下面的顺序进行初始化:
BASE_CLASS_INIT
BASE_IFACE_INIT
CLASS_INIT
IFACE_INIT
INITIALIZED
对GObject的初始化:
1. BASE_CLASS_INIT
/* stack all base class initialization functions, so we * call them in ascending order. */ for (bnode = node; bnode; bnode = lookup_type_node_I (NODE_PARENT_TYPE (bnode))) { if (bnode->data->class.class_init_base) init_slist = g_slist_prepend (init_slist, (gpointer) bnode->data->class.class_init_base); } for (slist = init_slist; slist; slist = slist->next) { GBaseInitFunc class_init_base = (GBaseInitFunc) slist->data; class_init_base (class); }
for (bnode = node; bnode; bnode = lookup_type_nodeI (NODE_PARENT_TYPE (bnode)))
是从最底层往上层循环(孙子 --> 儿子--> 爷爷)
init_slist, 是反过来弄的:
爷爷->儿子-->孙子,这么一个顺序,进行class_init_base()
后面会印证。
2. CLASS_INIT
g_atomic_int_set (&node->data->class.init_state, CLASS_INIT); G_WRITE_UNLOCK (&type_rw_lock); if (node->data->class.class_init) node->data->class.class_init (class, (gpointer) node->data->class.class_data);
此时执行:g_object_do_class_init()
父类初始化完成后,嵌套退回一层,开始自行GstObjec的初始化:
也是按照那个顺序,有的成员是NULL, 就跳过去:
3. GstObject的CLASS_INIT
g_atomic_int_set (&node->data->class.init_state, CLASS_INIT); G_WRITE_UNLOCK (&type_rw_lock); if (node->data->class.class_init) node->data->class.class_init (class, (gpointer) node->data->class.class_data);
此时执行:gst_object_class_init()
注意,此时:gobject/gstobject的实例instance对象还没有建立!
static void g_object_base_class_init (GObjectClass *class) { GObjectClass *pclass = g_type_class_peek_parent (class); /* Don't inherit HAS_DERIVED_CLASS flag from parent class */ class->flags &= ~CLASS_HAS_DERIVED_CLASS_FLAG; if (pclass) pclass->flags |= CLASS_HAS_DERIVED_CLASS_FLAG; /* reset instance specific fields and methods that don't get inherited */ class->construct_properties = pclass ? g_slist_copy (pclass->construct_properties) : NULL; class->get_property = NULL; class->set_property = NULL; }
static void g_object_do_class_init (GObjectClass *class) { /* read the comment about typedef struct CArray; on why not to change this quark */ quark_closure_array = g_quark_from_static_string ("GObject-closure-array"); quark_weak_refs = g_quark_from_static_string ("GObject-weak-references"); quark_toggle_refs = g_quark_from_static_string ("GObject-toggle-references"); pspec_pool = g_param_spec_pool_new (TRUE); property_notify_context.quark_notify_queue = g_quark_from_static_string ("GObject-notify-queue"); property_notify_context.dispatcher = g_object_notify_dispatcher; class->constructor = g_object_constructor; class->constructed = g_object_constructed; class->set_property = g_object_do_set_property; class->get_property = g_object_do_get_property; class->dispose = g_object_real_dispose; class->finalize = g_object_finalize; class->dispatch_properties_changed = g_object_dispatch_properties_changed; class->notify = NULL; /** * GObject::notify: * @gobject: the object which received the signal. * @pspec: the #GParamSpec of the property which changed. * * The notify signal is emitted on an object when one of its * properties has been changed. Note that getting this signal * doesn't guarantee that the value of the property has actually * changed, it may also be emitted when the setter for the property * is called to reinstate the previous value. * * This signal is typically used to obtain change notification for a * single property, by specifying the property name as a detail in the * g_signal_connect() call, like this: * |[ * g_signal_connect (text_view->buffer, "notify::paste-target-list", * G_CALLBACK (gtk_text_view_target_list_notify), * text_view) * ]| * It is important to note that you must use * <link linkend="canonical-parameter-name">canonical</link> parameter names as * detail strings for the notify signal. */ gobject_signals[NOTIFY] = g_signal_new (g_intern_static_string ("notify"), G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GObjectClass, notify), NULL, NULL, g_cclosure_marshal_VOID__PARAM, G_TYPE_NONE, 1, G_TYPE_PARAM); /* Install a check function that we'll use to verify that classes that * implement an interface implement all properties for that interface */ g_type_add_interface_check (NULL, object_interface_check_properties); }
static void gst_object_class_init (GstObjectClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); #ifndef GST_DISABLE_TRACE _gst_object_trace = gst_alloc_trace_register (g_type_name (GST_TYPE_OBJECT)); #endif gobject_class->set_property = gst_object_set_property; gobject_class->get_property = gst_object_get_property; g_object_class_install_property (gobject_class, ARG_NAME, g_param_spec_string ("name", "Name", "The name of the object", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); /** * GstObject::parent-set: * @gstobject: a #GstObject * @parent: the new parent * * Emitted when the parent of an object is set. */ gst_object_signals[PARENT_SET] = g_signal_new ("parent-set", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstObjectClass, parent_set), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_OBJECT); /** * GstObject::parent-unset: * @gstobject: a #GstObject * @parent: the old parent * * Emitted when the parent of an object is unset. */ gst_object_signals[PARENT_UNSET] = g_signal_new ("parent-unset", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstObjectClass, parent_unset), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_OBJECT); #if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED) /** * GstObject::object-saved: * @gstobject: a #GstObject * @xml_node: the xmlNodePtr of the parent node * * Trigered whenever a new object is saved to XML. You can connect to this * signal to insert custom XML tags into the core XML. */ /* FIXME This should be the GType of xmlNodePtr instead of G_TYPE_POINTER * (if libxml would use GObject) */ gst_object_signals[OBJECT_SAVED] = g_signal_new ("object-saved", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstObjectClass, object_saved), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); klass->restore_thyself = ((void (*)(GstObject * object, gpointer self)) *gst_object_real_restore_thyself); #endif /** * GstObject::deep-notify: * @gstobject: a #GstObject * @prop_object: the object that originated the signal * @prop: the property that changed * * The deep notify signal is used to be notified of property changes. It is * typically attached to the toplevel bin to receive notifications from all * the elements contained in that bin. */ gst_object_signals[DEEP_NOTIFY] = g_signal_new ("deep-notify", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET (GstObjectClass, deep_notify), NULL, NULL, gst_marshal_VOID__OBJECT_PARAM, G_TYPE_NONE, 2, GST_TYPE_OBJECT, G_TYPE_PARAM); klass->path_string_separator = "/"; /* FIXME 0.11: Store this directly in the class struct */ klass->lock = g_slice_new (GStaticRecMutex); g_static_rec_mutex_init (klass->lock); klass->signal_object = g_object_newv (gst_signal_object_get_type (), 0, NULL); /* see the comments at gst_object_dispatch_properties_changed */ gobject_class->dispatch_properties_changed = GST_DEBUG_FUNCPTR (gst_object_dispatch_properties_changed); gobject_class->dispose = gst_object_dispose; gobject_class->finalize = gst_object_finalize; }
1. g_type_class_ref(G_TYPE_OBJECT)
g_type_init(); g_type_class_ref(G_TYPE_OBJECT);
result:
Entering g_type_class_ref Type:GObject +Entering type_class_init_Wm Call GObject.class_init_base() Call GObject.class_init() -Leaving type_class_init_Wm Leaving g_type_class_ref
2.
g_type_init(); g_type_class_ref(G_TYPE_OBJECT); g_type_class_ref(GST_TYPE_OBJECT);
Entering g_type_class_ref Type:GObject +Entering type_class_init_Wm Call GObject.class_init_base() Call GObject.class_init() -Leaving type_class_init_Wm Leaving g_type_class_ref Entering g_type_class_ref Type:GstObject +Entering g_type_class_ref Type:GObject -Leaving g_type_class_ref +Entering type_class_init_Wm Call GObject.class_init_base() Call GstObject.class_init() ++Entering g_type_class_ref Type:GParamString +++Entering g_type_class_ref Type:GParam ++++Entering type_class_init_Wm Call GParam.class_init_base() Call GParam.class_init() ----Leaving type_class_init_Wm ---Leaving g_type_class_ref +++Entering type_class_init_Wm Call GParam.class_init_base() Call GParamString.class_init() ---Leaving type_class_init_Wm --Leaving g_type_class_ref ++Entering g_type_class_ref Type:GstSignalObject +++Entering g_type_class_ref Type:GObject ---Leaving g_type_class_ref +++Entering type_class_init_Wm Call GObject.class_init_base() Call GstSignalObject.class_init() ---Leaving type_class_init_Wm --Leaving g_type_class_ref ++Entering g_type_class_ref Type:GstSignalObject --Leaving g_type_class_ref -Leaving type_class_init_Wm Leaving g_type_class_ref
3.
g_type_init(); g_type_class_ref(GST_TYPE_OBJECT);
Entering g_type_class_ref Type:GstObject +Entering g_type_class_ref Type:GObject ++Entering type_class_init_Wm Call GObject.class_init_base() Call GObject.class_init() --Leaving type_class_init_Wm -Leaving g_type_class_ref +Entering type_class_init_Wm Call GObject.class_init_base() Call GstObject.class_init() ++Entering g_type_class_ref Type:GParamString +++Entering g_type_class_ref Type:GParam ++++Entering type_class_init_Wm Call GParam.class_init_base() Call GParam.class_init() ----Leaving type_class_init_Wm ---Leaving g_type_class_ref +++Entering type_class_init_Wm Call GParam.class_init_base() Call GParamString.class_init() ---Leaving type_class_init_Wm --Leaving g_type_class_ref ++Entering g_type_class_ref Type:GstSignalObject +++Entering g_type_class_ref Type:GObject ---Leaving g_type_class_ref +++Entering type_class_init_Wm Call GObject.class_init_base() Call GstSignalObject.class_init() ---Leaving type_class_init_Wm --Leaving g_type_class_ref ++Entering g_type_class_ref Type:GstSignalObject --Leaving g_type_class_ref -Leaving type_class_init_Wm Leaving g_type_class_ref
4.
g_type_init(); g_type_class_ref(G_TYPE_OBJECT); g_type_class_ref(GST_TYPE_OBJECT); g_type_class_ref(GST_TYPE_ELEMENT);
============================= Entering g_type_class_ref Type:GObject +Entering type_class_init_Wm Call GObject.class_init_base() Call GObject.class_init() -Leaving type_class_init_Wm Leaving g_type_class_ref ============================= Entering g_type_class_ref Type:GstObject +Entering g_type_class_ref Type:GObject -Leaving g_type_class_ref +Entering type_class_init_Wm Call GObject.class_init_base() Call GstObject.class_init() ++Entering g_type_class_ref Type:GParamString +++Entering g_type_class_ref Type:GParam ++++Entering type_class_init_Wm Call GParam.class_init_base() Call GParam.class_init() ----Leaving type_class_init_Wm ---Leaving g_type_class_ref +++Entering type_class_init_Wm Call GParam.class_init_base() Call GParamString.class_init() ---Leaving type_class_init_Wm --Leaving g_type_class_ref ++Entering g_type_class_ref Type:GstSignalObject +++Entering g_type_class_ref Type:GObject ---Leaving g_type_class_ref +++Entering type_class_init_Wm Call GObject.class_init_base() Call GstSignalObject.class_init() ---Leaving type_class_init_Wm --Leaving g_type_class_ref ++Entering g_type_class_ref Type:GstSignalObject --Leaving g_type_class_ref -Leaving type_class_init_Wm Leaving g_type_class_ref ============================= Entering g_type_class_ref Type:GstElement +Entering g_type_class_ref Type:GstObject -Leaving g_type_class_ref +Entering type_class_init_Wm Call GstElement.class_init_base() Call GObject.class_init_base() Call GstElement.class_init() -Leaving type_class_init_Wm Leaving g_type_class_ref
5.
g_type_init(); g_type_class_ref(GST_TYPE_ELEMENT);
Entering g_type_class_ref Type:GstElement +Entering g_type_class_ref Type:GstObject ++Entering g_type_class_ref Type:GObject +++Entering type_class_init_Wm Call GObject.class_init_base() Call GObject.class_init() ---Leaving type_class_init_Wm --Leaving g_type_class_ref ++Entering type_class_init_Wm Call GObject.class_init_base() Call GstObject.class_init() +++Entering g_type_class_ref Type:GParamString ++++Entering g_type_class_ref Type:GParam +++++Entering type_class_init_Wm Call GParam.class_init_base() Call GParam.class_init() -----Leaving type_class_init_Wm ----Leaving g_type_class_ref ++++Entering type_class_init_Wm Call GParam.class_init_base() Call GParamString.class_init() ----Leaving type_class_init_Wm ---Leaving g_type_class_ref +++Entering g_type_class_ref Type:GstSignalObject ++++Entering g_type_class_ref Type:GObject ----Leaving g_type_class_ref ++++Entering type_class_init_Wm Call GObject.class_init_base() Call GstSignalObject.class_init() ----Leaving type_class_init_Wm ---Leaving g_type_class_ref +++Entering g_type_class_ref Type:GstSignalObject ---Leaving g_type_class_ref --Leaving type_class_init_Wm -Leaving g_type_class_ref +Entering type_class_init_Wm Call GstElement.class_init_base() Call GObject.class_init_base() Call GstElement.class_init() -Leaving type_class_init_Wm Leaving g_type_class_ref
6.
g_type_init(); g_type_class_ref(GST_TYPE_PIPELINE);
Entering g_type_class_ref Type:GstPipeline +Entering g_type_class_ref Type:GstBin ++Entering g_type_class_ref Type:GstElement +++Entering g_type_class_ref Type:GstObject ++++Entering g_type_class_ref Type:GObject +++++Entering type_class_init_Wm Call GObject.class_init_base() Call GObject.class_init() -----Leaving type_class_init_Wm ----Leaving g_type_class_ref ++++Entering type_class_init_Wm Call GObject.class_init_base() Call GstObject.class_init() +++++Entering g_type_class_ref Type:GParamString ++++++Entering g_type_class_ref Type:GParam +++++++Entering type_class_init_Wm Call GParam.class_init_base() Call GParam.class_init() -------Leaving type_class_init_Wm ------Leaving g_type_class_ref ++++++Entering type_class_init_Wm Call GParam.class_init_base() Call GParamString.class_init() ------Leaving type_class_init_Wm -----Leaving g_type_class_ref +++++Entering g_type_class_ref Type:GstSignalObject ++++++Entering g_type_class_ref Type:GObject ------Leaving g_type_class_ref ++++++Entering type_class_init_Wm Call GObject.class_init_base() Call GstSignalObject.class_init() ------Leaving type_class_init_Wm -----Leaving g_type_class_ref +++++Entering g_type_class_ref Type:GstSignalObject -----Leaving g_type_class_ref ----Leaving type_class_init_Wm ---Leaving g_type_class_ref +++Entering type_class_init_Wm Call GstElement.class_init_base() Call GObject.class_init_base() Call GstElement.class_init() ---Leaving type_class_init_Wm --Leaving g_type_class_ref ++Entering type_class_init_Wm Call GstBin.class_init_base() Call GstElement.class_init_base() Call GObject.class_init_base() Call GstBin.class_init() +++Entering g_type_class_ref Type:GParamBoolean ++++Entering g_type_class_ref Type:GParam ----Leaving g_type_class_ref ++++Entering type_class_init_Wm Call GParam.class_init_base() Call GParamBoolean.class_init() ----Leaving type_class_init_Wm ---Leaving g_type_class_ref +++Entering g_type_class_ref Type:GParamBoolean ---Leaving g_type_class_ref +++Entering g_type_class_ref Type:GstBin ++++Entering g_type_class_ref Type:GstElement ----Leaving g_type_class_ref ---Leaving g_type_class_ref --Leaving type_class_init_Wm -Leaving g_type_class_ref +Entering type_class_init_Wm Call GstPipeline.class_init_base() Call GstBin.class_init_base() Call GstElement.class_init_base() Call GObject.class_init_base() Call GstPipeline.class_init() ++Entering g_type_class_ref Type:GParamUInt64 +++Entering g_type_class_ref Type:GParam ---Leaving g_type_class_ref +++Entering type_class_init_Wm Call GParam.class_init_base() Call GParamUInt64.class_init() ---Leaving type_class_init_Wm --Leaving g_type_class_ref ++Entering g_type_class_ref Type:GParamBoolean --Leaving g_type_class_ref -Leaving type_class_init_Wm Leaving g_type_class_ref
上面的base调用打印应该是反的
Call GstPipeline.class_init_base()
Call GstBin.class_init_base()
Call GstElement.class_init_base()
Call GObject.class_init_base()
实际是:
GObject.class_init_base()
GstElement.class_init_base()
GstBin.class_init_base()
GstPipeline.class_init_base()
先父亲后儿子的顺序,调用base_init():
父 | Me (当前) | 儿子 | 孙子 | 重孙子 |
GObject | GstObject | GstElement | GstBin | GstPipeline |
g_object_base_class_init() | gst_element_base_class_init | gst_bin_base_init | gst_pipeline_base_init | |
g_object_do_class_init() | gst_object_class_init() | gst_element_class_init | gst_bin_class_init | gst_pipeline_class_init |
g_object_init() | gst_object_init() | gst_element_init | gst_bin_init | gst_pipeline_init |
xxx_yyy_get_type(), 是创建type node, 并且,绑定自己定义的一些APIs;
g_type_class_ref(), 是调用用户的一些class: APIs,
先调用base_init() [老子--> 儿子-->当前],
在调用class_init()
这个时候,对象实例依然没有创建。
下面就要看g_object_newv的实力了!
examples:
1.
g_object_new(G_TYPE_OBJECT, NULL);
GEnum->is_classed = 1 GFlags->is_classed = 1 GParam->is_instantiatable = 1 GObject->is_instantiatable = 1 GParamChar->is_instantiatable = 1 GParamUChar->is_instantiatable = 1 GParamBoolean->is_instantiatable = 1 GParamInt->is_instantiatable = 1 GParamUInt->is_instantiatable = 1 GParamLong->is_instantiatable = 1 GParamULong->is_instantiatable = 1 GParamInt64->is_instantiatable = 1 GParamUInt64->is_instantiatable = 1 GParamUnichar->is_instantiatable = 1 GParamEnum->is_instantiatable = 1 GParamFlags->is_instantiatable = 1 GParamFloat->is_instantiatable = 1 GParamDouble->is_instantiatable = 1 GParamString->is_instantiatable = 1 GParamParam->is_instantiatable = 1 GParamBoxed->is_instantiatable = 1 GParamPointer->is_instantiatable = 1 GParamValueArray->is_instantiatable = 1 GParamObject->is_instantiatable = 1 GParamOverride->is_instantiatable = 1 GParamGType->is_instantiatable = 1 GParamVariant->is_instantiatable = 1 ============================= Entering g_type_class_ref Type:GObject +Entering type_class_init_Wm Call GObject.class_init_base() Call GObject.class_init() -Leaving type_class_init_Wm Leaving g_type_class_ref Entering g_type_class_ref Type:GObject Leaving g_type_class_ref Call GObject.instance_init()
2.
g_object_new(GST_TYPE_OBJECT,NULL);
GEnum->is_classed = 1 GFlags->is_classed = 1 GParam->is_instantiatable = 1 GObject->is_instantiatable = 1 GParamChar->is_instantiatable = 1 GParamUChar->is_instantiatable = 1 GParamBoolean->is_instantiatable = 1 GParamInt->is_instantiatable = 1 GParamUInt->is_instantiatable = 1 GParamLong->is_instantiatable = 1 GParamULong->is_instantiatable = 1 GParamInt64->is_instantiatable = 1 GParamUInt64->is_instantiatable = 1 GParamUnichar->is_instantiatable = 1 GParamEnum->is_instantiatable = 1 GParamFlags->is_instantiatable = 1 GParamFloat->is_instantiatable = 1 GParamDouble->is_instantiatable = 1 GParamString->is_instantiatable = 1 GParamParam->is_instantiatable = 1 GParamBoxed->is_instantiatable = 1 GParamPointer->is_instantiatable = 1 GParamValueArray->is_instantiatable = 1 GParamObject->is_instantiatable = 1 GParamOverride->is_instantiatable = 1 GParamGType->is_instantiatable = 1 GParamVariant->is_instantiatable = 1 ============================= GstObject->is_instantiatable = 1 Entering g_type_class_ref Type:GstObject +Entering g_type_class_ref Type:GObject ++Entering type_class_init_Wm Call GObject.class_init_base() Call GObject.class_init() --Leaving type_class_init_Wm -Leaving g_type_class_ref +Entering type_class_init_Wm Call GObject.class_init_base() Call GstObject.class_init() ++Entering g_type_class_ref Type:GParamString +++Entering g_type_class_ref Type:GParam ++++Entering type_class_init_Wm Call GParam.class_init_base() Call GParam.class_init() ----Leaving type_class_init_Wm ---Leaving g_type_class_ref +++Entering type_class_init_Wm Call GParam.class_init_base() Call GParamString.class_init() ---Leaving type_class_init_Wm --Leaving g_type_class_ref Call GParam.instance_init() Call GParamString.instance_init() GstSignalObject->is_instantiatable = 1 ++Entering g_type_class_ref Type:GstSignalObject +++Entering g_type_class_ref Type:GObject ---Leaving g_type_class_ref +++Entering type_class_init_Wm Call GObject.class_init_base() Call GstSignalObject.class_init() ---Leaving type_class_init_Wm --Leaving g_type_class_ref ++Entering g_type_class_ref Type:GstSignalObject --Leaving g_type_class_ref Call GObject.instance_init() Call GstSignalObject.instance_init() -Leaving type_class_init_Wm Leaving g_type_class_ref GLib-GObject-WARNING **: cannot create instance of abstract (non-instantiatable) type `GstObject' aborting...
阶段 | 相应API | 作用 | GObject 调用顺序 | GstObject | GstElement |
1 | xxx_yyy_get_type() |
创建TypeNode, 并且赋值一些APIs: base_class_init() class_init() instance_init(), 等等 |
|||
2 | g_type_class_ref() |
调用base_class_init() 从父-->子, |
g_object_base_class_init() |
1. 父类:g_object_base_class_init() 2. 自己没有base_init() |
1. 爷爷:g_object_base_class_init() 2. 父亲没有base_init() 3. gst_element_base_class_init |
调用class_init(), 指定各种APIs 包括class->constructor(), set_property()/get_property() dispose()/finalize() |
g_object_do_class_init() |
gst_object_class_init() 1. 首选取得GObjectClass 2. 重载一些函数 3. 装载一些自己的signal |
gst_element_class_init() 1. 首选取得GObjectClass 2. 把GObjectClass的一些函数换成自己的(重载) 3. 装载自己的信号 |
||
3 | g_object_new() |
调用class->constructor() --> g_type_create_instance() --> 父类的instance(), 自己的instance() |
g_object_constructor()->g_type_create_instance() -> 1. g_object_init() |
g_object_constructor()->g_type_create_instance() -> 1. 父亲:g_object_init() 2.自己:gst_object_init() |
g_object_constructor()->g_type_create_instance() -> 1. 爷爷:g_object_init() 2.父亲:gst_object_init() 3. 自己:gst_element_init()
|
set properties |
疑问:在同一进程内,如果同时注册N个话,如果管理?
“用时”注册,会浪费时间吗?
2024年2月21日 21:17
Awesome article, it was exceptionally helpful! I simply began in this and I'm becoming more acquainted with it better. The post is written in very a good manner and it contains many useful information for me. Thank you very much and will look for more postings from you.