3. init函数和class_init函数的讲解

如何去使用GObject去构建一个所谓的“对象”呢?GObject中每个类要定义两个结构体,假设你要定义的类型为People,那么你要定义两个结构分别名为People和PeopleClass,估计刚接触的人会有些晕,一般的C++啊,JAVA什么的都是直接一个class了事儿了。但记住C本身并没有面向对象的机制,这里这样做也仅仅是为了模拟。 名为PeopleClass的结构是表示类的结构,而名为People的结构则是这个类的实例,可能这么说一般人还会有点摸不着头脑,切记,这是一种模拟。

 

下面这段话摘自《快速上手Gobject 》:

GObject世界里,类是两个结构体的组合,一个是实例结构体,另一个是类结构体。有点绕。类、对象、实例有什么区别?可以这么理解,类-对象-实例,无非就是类型,该类型所声明的变量,变量所存储的内容。后面可以知道,类结构体初始化函数一般被调用一次,而实例结构体的初始化函数的调用次数等于对象实例化的次数。所有实例共享的数据,可保存在类结构体中,而所有对象私有的数据,则保存在实例结构体中。

 

在GObject中一个对象的产生遵循如下原则,如果产生的是该类的第一个实例,那么先分配Class结构,再分配针对该实例的结构。否则直接分配针对该实例的结构。也就是说在Class结构中所有的内容,是通过该类生成的实例所公有的。而实例获每个对象时,为其单独分配专门的实例用结构。

同时需要注意的是,每个结构中的第一项描述的是其父类相关的结构,这是为了模拟继承的机制,比如,在gstimxv4l2src.h文件中:

struct _GstImxV4l2Src {
  GstPushSrc videosrc;
  gchar *device;
  guint frame_plus;
  GstBufferPool *pool;
  GstAllocator *allocator;
  gpointer v4l2handle;
  GstCaps *probed_caps;
  GstCaps *old_caps;
  GList * gstbuffer_in_v4l2;
  guint w, h, fps_n, fps_d;
  guint v4l2fmt;
  guint actual_buf_cnt;
  GstVideoAlignment video_align;
  GstClockTime duration;
  GstClockTime base_time_org;
  gboolean stream_on;
  gboolean use_my_allocator;
  gboolean use_v4l2_memory;
};

struct _GstImxV4l2SrcClass {
  GstPushSrcClass parent_class;
};

这两个结构体中的第一个元素都是与其父类相关的结构。这一点一定要注意。

 

有关这方面的理解,查看《使用C语言进行面向对象的开发--GObject入门系列》中的《使用C语言进行面向对象的开发--GObject入门[3].pdf》和《借助 C++ 来理解 GObject 的基本编程框架.pdf》这两个文档,网页链接为:

http://www.cnblogs.com/pingf/archive/2009/11/20/1606742.html

https://segmentfault.com/a/1190000003861212

或者查看《快速上手Gobject.pdf》中有关这一部分的讲解,链接如下:

http://blog.csdn.net/acs713/article/details/7778051

 

在上一篇文章中讲到了使用G_DEFINE_TYPE 宏来定义了几个函数,其中有type_name##_init

函数和type_name##_class_init函数,这两个函数分别对应实例初始化和类的初始化。

 

下面以gstimxv4l2src.c文件为例来分析,先来看看gst_imx_v4l2src_init函数:
static void
gst_imx_v4l2src_init (GstImxV4l2Src * v4l2src)
{
  v4l2src->device = g_strdup (DEFAULT_DEVICE);
  v4l2src->frame_plus = DEFAULT_FRAME_PLUS;
  v4l2src->v4l2handle = NULL;
  v4l2src->probed_caps = NULL;
  v4l2src->old_caps = NULL;
  v4l2src->pool = NULL;
  v4l2src->allocator = NULL;
  v4l2src->gstbuffer_in_v4l2 = NULL;
  v4l2src->actual_buf_cnt = 0;
  v4l2src->duration = 0;
  v4l2src->stream_on = FALSE;
  v4l2src->use_my_allocator = FALSE;
  v4l2src->use_v4l2_memory = DEFAULT_USE_V4L2SRC_MEMORY;
  v4l2src->base_time_org = GST_CLOCK_TIME_NONE;

  gst_base_src_set_format (GST_BASE_SRC (v4l2src), GST_FORMAT_TIME);
  gst_base_src_set_live (GST_BASE_SRC (v4l2src), TRUE);

  g_print("====== IMXV4L2SRC: %s build on %s %s. ======\n",  (VERSION),__DATE__,__TIME__);

}

先来看这个函数,这个函数完成的是实例的初始化,对比对应的.h头文件,可以发现这个函数只是将GstImxV4l2Src这个结构体中的各个元素赋初值。

 

 

再来看看gst_imx_v4l2src_class_init函数:

static void
gst_imx_v4l2src_class_init (GstImxV4l2SrcClass * klass)
{
  GObjectClass *gobject_class;
  GstElementClass *element_class;
  GstBaseSrcClass *basesrc_class;
  GstPushSrcClass *pushsrc_class;

  gobject_class = G_OBJECT_CLASS (klass);
  element_class = GST_ELEMENT_CLASS (klass);
  basesrc_class = GST_BASE_SRC_CLASS (klass);
  pushsrc_class = GST_PUSH_SRC_CLASS (klass);

  gobject_class->finalize = (GObjectFinalizeFunc) gst_imx_v4l2src_finalize;
  gobject_class->set_property = gst_imx_v4l2src_set_property;
  gobject_class->get_property = gst_imx_v4l2src_get_property;

  gst_imx_v4l2src_install_properties (gobject_class);

  gst_element_class_add_pad_template (element_class, \
      gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, \
        gst_imx_v4l2src_get_all_caps ()));

  basesrc_class->start = GST_DEBUG_FUNCPTR (gst_imx_v4l2src_start);
  basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_imx_v4l2src_stop);
  basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_imx_v4l2src_get_caps);
  basesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_imx_v4l2src_fixate);
  basesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_imx_v4l2src_set_caps);
  basesrc_class->query = GST_DEBUG_FUNCPTR (gst_imx_v4l2src_query);
  basesrc_class->decide_allocation = \
      GST_DEBUG_FUNCPTR (gst_imx_v4l2src_decide_allocation);
  pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_imx_v4l2src_create);

  gst_element_class_set_static_metadata (element_class, \
      "IMX Video (video4linux2) Source", "Src/Video", \
      "Capture frames from IMX SoC video4linux2 device", IMX_GST_PLUGIN_AUTHOR);

  GST_DEBUG_CATEGORY_INIT (imxv4l2src_debug, "imxv4l2src", 0, "Freescale IMX V4L2 source element");
}

这个函数类似于C++里面的构造函数,该初始化过程只进行一次。

对于这个函数的理解,首先需要理解对象的分层结构图:

3. init函数和class_init函数的讲解_第1张图片


可以看出GstPushSrcClass是按照GstObject--->GstElement--->GstBaseSrc--->GstPushSrc这样继承下来的,所以使用:

  gobject_class =G_OBJECT_CLASS (klass);

  element_class =GST_ELEMENT_CLASS (klass);

  basesrc_class =GST_BASE_SRC_CLASS (klass);

  pushsrc_class =GST_PUSH_SRC_CLASS (klass);

的方法,分别获取它们对应的父类。然后分别实现这些类中的虚函数,也就是这些结构体里面的那些函数指针。

这里之所以使用 klass 而不是 class,是因为class 是 c++ 语言的关键字,如果使用 class,那么类如是被 C++ 程序调用,那么程序编译时就杯具了。

 

对于structGObjectClass:
struct GObjectClass {
  GTypeClass   g_type_class;

  /* seldom overidden */
  GObject*   (*constructor)     (GType                  type,
                                 guint                  n_construct_properties,
                                 GObjectConstructParam *construct_properties);
  /* overridable methods */
  void       (*set_property)            (GObject        *object,
                                         guint           property_id,
                                         const GValue   *value,
                                         GParamSpec     *pspec);
  void       (*get_property)            (GObject        *object,
                                         guint           property_id,
                                         GValue         *value,
                                         GParamSpec     *pspec);
  void       (*dispose)                 (GObject        *object);
  void       (*finalize)                (GObject        *object);
  /* seldom overidden */
  void       (*dispatch_properties_changed) (GObject      *object,
                                             guint         n_pspecs,
                                             GParamSpec  **pspecs);
  /* signals */
  void       (*notify)                  (GObject *object,
                                         GParamSpec *pspec);

  /* called when done constructing */
  void       (*constructed)             (GObject *object);
};

上面标红的就是在这个函数中实现的函数指针。需要注意的是,这个是基础的对象,如果设置好这几个函数指针以后,就需要设置这个对象的属性,需要使用g_object_class_install_property函数,这个函数封装在gst_imx_v4l2src_install_properties函数里面。来看看g_object_class_install_property函数的解释:

3. init函数和class_init函数的讲解_第2张图片


至此,structGObjectClass的初始化就算完成。

 

 

对于structGstElementClass:
struct GstElementClass {
  GstObjectClass         parent_class;

  /* the element metadata */
  gpointer               metadata;

  /* factory that the element was created from */
  GstElementFactory     *elementfactory;

  /* templates for our pads */
  GList                 *padtemplates;
  gint                   numpadtemplates;
  guint32                pad_templ_cookie;

  /* virtual methods for subclasses */

  /* request/release pads */
  /* FIXME 2.0 harmonize naming with gst_element_request_pad */
  GstPad*               (*request_new_pad)      (GstElement *element, GstPadTemplate *templ,
                                                 const gchar* name, const GstCaps *caps);

  void                  (*release_pad)          (GstElement *element, GstPad *pad);

  /* state changes */
  GstStateChangeReturn (*get_state)             (GstElement * element, GstState * state,
                                                 GstState * pending, GstClockTime timeout);
  GstStateChangeReturn (*set_state)             (GstElement *element, GstState state);
  GstStateChangeReturn (*change_state)          (GstElement *element, GstStateChange transition);
  void                 (*state_changed)         (GstElement *element, GstState oldstate,
                                                 GstState newstate, GstState pending);

  /* bus */
  void                  (*set_bus)              (GstElement * element, GstBus * bus);

  /* set/get clocks */
  GstClock*             (*provide_clock)        (GstElement *element);
  gboolean              (*set_clock)            (GstElement *element, GstClock *clock);

  /* query functions */
  gboolean              (*send_event)           (GstElement *element, GstEvent *event);

  gboolean              (*query)                (GstElement *element, GstQuery *query);

  gboolean              (*post_message)         (GstElement *element, GstMessage *message);

  void                  (*set_context)          (GstElement *element, GstContext *context);
};

而对于struct GstElementClass来说,这个结构体可以看作一个pipeline中每一个元件所对应的结构体,所以,对于这个结构体主要是设置它的Pad等,需要使用gst_element_class_add_pad_template函数,函数解释如下:

3. init函数和class_init函数的讲解_第3张图片 3. init函数和class_init函数的讲解_第4张图片

关于这两个函数以后再具体分析。设置完Pad后,就需要设置metadata,使用gst_element_class_set_static_metadata函数来完成:3. init函数和class_init函数的讲解_第5张图片

这个函数也是需要在class_init函数中完成的,具体的分析查看《插件编写指南》。

 

 

对于struct GstBaseSrcClass:

struct GstBaseSrcClass {
  GstElementClass parent_class;

  /* virtual methods for subclasses */

  /* get caps from subclass */
  GstCaps*      (*get_caps)     (GstBaseSrc *src, GstCaps *filter);
  /* decide on caps */
  gboolean      (*negotiate)    (GstBaseSrc *src);
  /* called if, in negotiation, caps need fixating */
  GstCaps *     (*fixate)       (GstBaseSrc *src, GstCaps *caps);
  /* notify the subclass of new caps */
  gboolean      (*set_caps)     (GstBaseSrc *src, GstCaps *caps);

  /* setup allocation query */
  gboolean      (*decide_allocation)   (GstBaseSrc *src, GstQuery *query);

  /* start and stop processing, ideal for opening/closing the resource */
  gboolean      (*start)        (GstBaseSrc *src);
  gboolean      (*stop)         (GstBaseSrc *src);

  /* given a buffer, return start and stop time when it should be pushed
   * out. The base class will sync on the clock using these times. */
  void          (*get_times)    (GstBaseSrc *src, GstBuffer *buffer,
                                 GstClockTime *start, GstClockTime *end);

  /* get the total size of the resource in the format set by
   * gst_base_src_set_format() */
  gboolean      (*get_size)     (GstBaseSrc *src, guint64 *size);

  /* check if the resource is seekable */
  gboolean      (*is_seekable)  (GstBaseSrc *src);

  /* Prepare the segment on which to perform do_seek(), converting to the
   * current basesrc format. */
  gboolean      (*prepare_seek_segment) (GstBaseSrc *src, GstEvent *seek,
                                         GstSegment *segment);
  /* notify subclasses of a seek */
  gboolean      (*do_seek)      (GstBaseSrc *src, GstSegment *segment);

  /* unlock any pending access to the resource. subclasses should unlock
   * any function ASAP. */
  gboolean      (*unlock)       (GstBaseSrc *src);
  /* Clear any pending unlock request, as we succeeded in unlocking */
  gboolean      (*unlock_stop)  (GstBaseSrc *src);

  /* notify subclasses of a query */
  gboolean      (*query)        (GstBaseSrc *src, GstQuery *query);

  /* notify subclasses of an event */
  gboolean      (*event)        (GstBaseSrc *src, GstEvent *event);

  /* ask the subclass to create a buffer with offset and size, the default
   * implementation will call alloc and fill. */
  GstFlowReturn (*create)       (GstBaseSrc *src, guint64 offset, guint size,
                                 GstBuffer **buf);
  /* ask the subclass to allocate an output buffer. The default implementation
   * will use the negotiated allocator. */
  GstFlowReturn (*alloc)        (GstBaseSrc *src, guint64 offset, guint size,
                                 GstBuffer **buf);
  /* ask the subclass to fill the buffer with data from offset and size */
  GstFlowReturn (*fill)         (GstBaseSrc *src, guint64 offset, guint size,
                                 GstBuffer *buf);
};

上面标红的就是在这个函数中实现的函数指针。

 

对于struct GstPushSrcClass:

struct GstPushSrcClass {
  GstBaseSrcClass parent_class;

  /* ask the subclass to create a buffer, the default implementation
   * uses alloc and fill */
  GstFlowReturn (*create) (GstPushSrc *src, GstBuffer **buf);
  /* allocate memory for a buffer */
  GstFlowReturn (*alloc)  (GstPushSrc *src, GstBuffer **buf);
  /* ask the subclass to fill a buffer */
  GstFlowReturn (*fill)   (GstPushSrc *src, GstBuffer *buf);
};

上面标红的就是在这个函数中实现的函数指针。

 

至此,就简单分析完class_init函数,整个.c文件就是围绕这个class_init函数来构建的,或者说,整个.c文件就是来实现这些函数指针的具体内容。


你可能感兴趣的:(GStreamer,GStreamer专栏)