Gstreamer Plugin/Application 主要函数学习

参考:https://blog.csdn.net/weixin_41944449/category_7596136.html

G_DEFINE_TYPE:

G_DEFINE_TYPE是一个宏定义。宏展开如下:

#define G_DEFINE_TYPE(TN, t_n, T_P)
/******* 其中
 *TN  ---> TypeName
 *t_n ---> type_name
 *T_P ---> TYPE_PARENT
 *_f_ ---> 0
 *_c_ ---> {}
******/
/*****   以下为宏展开   *****/
static void     type_name##_init              (TypeName        *self); 
static void     type_name##_class_init        (TypeName##Class *klass); 
static gpointer type_name##_parent_class = NULL;
static gint     TypeName##_private_offset;
 
static void     type_name##_class_intern_init (gpointer klass)
{
  type_name##_parent_class = g_type_class_peek_parent (klass);
  if (TypeName##_private_offset != 0)
    g_type_class_adjust_private_offset (klass, &TypeName##_private_offset);
  type_name##_class_init ((TypeName##Class*) klass);
}
 
static inline gpointer
type_name##_get_instance_private (TypeName *self)
{
  return (G_STRUCT_MEMBER_P (self, TypeName##_private_offset));
} 
 
GType 
type_name##_get_type (void) 
{ 
  static volatile gsize g_define_type_id__volatile = 0;
  /* Prelude goes here */
  if (g_once_init_enter (&g_define_type_id__volatile))
    {
      GType g_define_type_id =
        g_type_register_static_simple (TYPE_PARENT,
                                       g_intern_static_string (#TypeName),
                                       sizeof (TypeName##Class),
                                       (GClassInitFunc)(void (*)(void)) type_name##_class_intern_init,
                                       sizeof (TypeName),
                                       (GInstanceInitFunc)(void (*)(void)) type_name##_init,
                                       (GTypeFlags) flags);
      { /* custom code follows */
              {_C_;}
        /* following custom code */
      }
      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
    }
  return g_define_type_id__volatile;
} /* closes type_name##_get_type() */

 

G_DEFINE_TYPE主要定义了type_name##_get_type ().

在此函数内调用通过g_type_register_static_simple()向GObject完成类的注册。从函数声明我们可以了解到,向Gobject系统注册一个类,需要告诉Gobject系统,我现在需要注册一个新类,它父类的类型是parent_type,大小是class_size,类的初始化函数是class_init,类的实例大小以及初始化函数,还有这个类有什么flags

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

究竟是什么时候,程序会向Gobject系统注册该新类呢?

比如我们是要注册一个名叫TestObject的类,那么就是通过TestObject_get_type()函数完成TestObject的注册登记。

在我们需要创建一个TestObject的实例时,会通过调用g_object_new()函数完成,在调用g_object_new函数,需要传进相应的参数,这个时候,我们就将TestObject_get_type()函数的返回值传递给它,即演变成以下:

TestObject *testObject = (TestObject *)g_object_new (TestObject_get_type(), NULL);

还有一种情况会调用type_name##_get_type():

plugin_init()函数中,将type_name##_get_type()作为函数参数type传递给gst_element_register()函数,从而完成类型向gobject系统的注册,只不过大多数的时候,type_name##_get_type()函数都被封装为一个宏定义GST_TYPE_xxx

plugin_init:

每个plugin都是在plugin_init()函数中通过gst_element_register()函数将plugin的相应信息注册到gstreamer中.

在gst_element_registrer内,会创建element(plugin)的factory,并将facotry类型转成feature保存到全局变量的_gst_registry_default的priv->features成员中,同时根据feature的name生成相应的hash保存(后续在创建element时,需要查找相应的feature时,是根据name的hash快速查找)。在gst_element_register中会调用g_type_class_ref会调用到class_init()。

每个plugin_init()函数定义都是个静态函数,也就证明该函数只是在本文件起作用,同时,在同一个C文件中有通过GST_PLUGIN_DEFINE这样的一个宏定义对plugin_init()进行修饰.

GST_PLUGIN_DEFINE展开如下:主要定义了两个函数gst_plugin_name_get_desc()和gst_plugin_name_register()

#define GST_PLUGIN_DEFINE(major,minor,name,description,init,version,license,package,origin)
/* 文本中的name都将使用GST_PLUGIN_DEFINE传进的name替换 */
GST_PLUGIN_EXPORT const GstPluginDesc * gst_plugin_name_get_desc (void);
GST_PLUGIN_EXPORT void gst_plugin_name_register (void);

static const GstPluginDesc gst_plugin_desc = {
  major,
  minor,
  G_STRINGIFY(name),
  (gchar *) description,
  init,
  version,
  license,
  PACKAGE,
  package,
  origin,
  __GST_PACKAGE_RELEASE_DATETIME,
  GST_PADDING_INIT
};

const GstPluginDesc *
gst_plugin_name_get_desc (void)
{
    return &gst_plugin_desc;
}

void 
gst_plugin_name_register (void)
{
  gst_plugin_register_static (major, minor, G_STRINGIFY(name),
      description, init, version, license,
      PACKAGE, package, origin);
}

plugin_init调用时机:

在gst_init()中,最后会调用到_priv_gst_plugin_load_file_for_registry()来注册plugin.

_priv_gst_plugin_load_file_for_registry所做的事情如下:

1.获取plugin so的gst_plugin_name_get_desc() symbol,获取该plugin的信息

2.gst_plugin_register_func()将会检查版本之类的信息,然后拷贝关于plugin的描述信息,在通过函数指针desc->plugin_init真正的完成plugin的注册(desc->plugin_init函数指针指向的就是上述说到的plugin_init()函数),这样,就调用到了plugin_init()。

3.gst_registry_add_plugin()函数与gst_registry_add_feature()函数类似,gst_registry_add_feature()是将feature保存到全局变量的_gst_registry_default的priv->features成员,而gst_registry_add_plugin()函数则是将plugin保存到_gst_registry_default的priv->plugins成员。 

class_init:

通过g_type_register_static_simple()函数向Gobject系统注册自定义类的时候,就传进了相应的参数,包括类的初始化函数type_name##_class_intern_init()以及类实例的初始化函数type_name##_init()(instance_init),它们两个共同的相当于类的构造函数。

class_init()函数是在第一次创建TestObject类实例对象的时候调用的,该函数只会调用一次,而instance_init()函数则是每次创建类实例对象都会调用。

class_init调用时机:

plugin_init->gst_element_register->g_type_class_ref->type_class_init_Wm->class_init

instance_init

gst_element_factory_make()用来创建Element.

1.gst_element_factory_find()使用name查找_gst_registry_default->priv->features是否注册了feature.

2.如果已经查找到已经注册过此plugin(element),调用gst_element_factory_create()来创建element。此函数会调用g_object_new来创建GObject.在g_object_new最后会调用到instance_init.

gst_element_factory_create->g_object_new->g_object_new_valist->g_object_new_internal->g_type_create_instance->instance_init.

Event:

gst_pad_event_default->gst_pad_forward->event_forward_func->gst_pad_push_event->gst_pad_push_event_unchecked(peer)->gst_pad_send_event_unchecked->event()

Query:

gst_pad_query_default->gst_pad_forward->query_forward_func->gst_pad_query->gst_pad_query->query()

change_state:

gst_element_set_state->gst_element_set_state_func->gst_element_change_state->change_state()

chain:

gst_pad_push->gst_pad_push_data->gst_pad_chain_data_unchecked(peer)->chain()

gst_bin_add_many:

添加element到bin(pipeline)的children成员,设置element的parent为bin(pipeline).

gst_element_link_many:

gst_element_link->gst_element_link_pads->gst_element_link_pads_full

在gst_element_link_pads_full:

1.遍历src element的srcpad,调用gst_element_get_compatible_pad来查找dest element是否有sinkpad可以link。

2.在在gst_element_get_compatible_pad(GstElement * element, GstPad * pad, GstCaps * caps)中,主要完成以下操作: 

2.1. 将会通过gst_element_iterate_sink_pads(element)或者gst_element_iterate_src_pads (element)函数element相应的pad;
2.2. 通过temp = gst_pad_query_caps (pad, NULL)得到pad的所有caps;
2.3. 同样的,通过temp = gst_pad_query_caps (current, NULL)得到element pad的所有caps;
2.4. 通过compatible = gst_caps_can_intersect (temp, intersection)检查,pad的caps与element pad caps数据类型是否一致;
2.5. 如果第4步返回的是一致,则从element中找到了可以与pad连接的element pad,返回element pad;
2.6. 如果循环之后都没有找到,将会尝试请求型的pad,最终都没有将会返回NULL。
3.如果在gst_element_get_compatible_pad找到了合适的sinkpad可以link,则调用pad_link_maybe_ghosting(srcpad, temp, flags)link srcpad和找到的sinkpad(temp)进行link。

3.1. 先通过prepare_link_maybe_ghosting()函数检查pad的element是否存在同一个parent,需要存在同一个parent才可以进行下一步连接,也正是这个函数限制了,element需要在同一个pipeline才可以link;
3.2. 通过gst_pad_link_full (src, sink, flags)link src pad和sink pad;通过GST_PAD_PEER设置srcpad和sinkpad

3.3 通过schedule_events (srcpad, sinkpad)函数检查srcpad、sinkpad是否有不一样的event,sink不存在的event都需要做好标记received = FALSE;
3.4 通过g_signal_emit()函数发送gst_pad_signals[PAD_LINKED]信号,完成连接,这里发送的信号,又是在实例初始化时,设置各自的pad的接收设置,部分pad并没有设置接收函数,采用默认的,也将是接收就释放;
3.5 最后通过gst_pad_send_event (srcpad, gst_event_new_reconfigure ())发送相应的event,srcpad发送的事件.将会在srcpad的event_function处理.
gst_pipeline_new:

使用gst_element_factory_make创建pipeline,会调用GstPipeline的instance_init(在instance_init内会创建pipeline的bus),由于GstPipeline继承自GstBin,也会调用GstBin的instance_init(会创建child_bus,并设置bin的bus handler为bin_bus_handler).

gst_pipeline_get_bus:

获取GstPipeline的bus.

gst_bus_add_watch:

添加callback到bus上,当pipeline内的Element由调用gst_element_post_message()时,会触发callback。

gst_bus_add_watch->gst_bus_add_watch_full->gst_bus_add_watch_full_unlocked.

在gst_bus_add_watch_full_unlocked内:

1.gst_bus_create_watch(bus)为bus创建一个watch,返回一个GSource,当message发到这个bus上时,次GSource在mainloop将会dispatch.

2.调用g_source_set_callback设置GSource的callback

3.调用g_source_attach将GSource添加到Glib的main context.

g_main_loop_run:

在while loop中调用g_main_context_iterate.

在g_main_context_iterate调用g_main_context_poll监听是否有消息,如果有消息,则调用g_main_context_dispatch,先调用source->callback_funcs->get(即g_source_callback_get)获取到callback,然后调用dispatch函数(gst_bus_source_dispatch),在dispatch会调用到callback,即gst_bus_add_watch传入的callback。

gst_bin_add_many:

gst_bin_add->gst_bin_add_func,将element加到pipeline的children链表上,设置element的bus为child_bus(GstBin instance_init时创建的child_bus)

gst_element_post_message

将message发送到elementde bus上,即child_bus.

gst_element_post_message->gst_element_post_message_default->gst_bus_post->handler(即bin_bus_handler).

在bin_bus_handler()内调用gst_bin_handler_message_func()对不同的message type做不同的处理,gst_bin_handler_message_func函数的最后调用到gst_element_post_message(GST_ELEMENT_CAST(bin), message)发送到pipeline的bus上,gst_element_post_message_default->gst_bus_post,此bus上并没有定义handler,所以直接调用gst_poll_write_control(),唤醒main loop的poll.

posted @ 2020-06-28 16:54  fellow_jing  阅读(1120)  评论(0编辑  收藏  举报