gobject/gstobject的初始化(包括类型,类,实例等的初始化)。

os posted @ 2013年8月28日 10:47 in GObject , 3031 阅读

gobjec相关学习文章的list.

 

Type,Class, instance 初始化,包括其中函数调用的过程总结:

阶段 相应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      

 

下面是具体的分析:

g_object_type_init()

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);


好戏都在g_type_class_ref

这个函数是个循环嵌套函数!

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对象还没有建立!

 

g_object_base_class_init

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;
}

g_object_do_class_init

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);
}

gst_object_class_init

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;
}

 

Testing:

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个话,如果管理?

“用时”注册,会浪费时间吗?

 

 

Avatar_small
seo service london 说:
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.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter