zoukankan      html  css  js  c++  java
  • 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.

  • 相关阅读:
    Activiti 开发案例之动态指派任务
    SpringBoot开发案例之打造十万博文Web篇
    「玩转Python」打造十万博文爬虫篇
    SpringBoot开发案例Nacos配置管理中心
    「玩转Python」突破封锁继续爬取百万妹子图
    SpringBoot开发案例之分布式集群共享Session
    「玩转树莓派」树莓派 3B+ 配置无线WiFi
    「玩转树莓派」搭建智能家居远程监控系统
    「玩转树莓派」搭建属于自己的云盘服务
    「玩转树莓派」为女朋友打造一款智能语音闹钟
  • 原文地址:https://www.cnblogs.com/fellow1988/p/13203793.html
Copyright © 2011-2022 走看看