[GLib][GStreamer] 插件编写思路 —— 继承、覆写 和 虚函数

每一个 GType 都有两个结构体 :instance struct 和 class struct ,二者作用和异同 见 [GLib][GStreamer] Glib 对象模型中的 instance struct 和 class struct_ykun089的博客-CSDN博客

继承:

GLib 中的继承是通过在 instance struct 和 class struct 开始部分分别定义 parent instance struct 成结构体成员 和 parent class struct 结构体成员来实现的 (这也是OO语言的底层实现)。

函数覆写:

那么函数覆写是如何实现的?下面以 GstBaseSrcClass 为例:

        类的成员函数基本上都定义在 class struct中,因此以 GstBaseSrcClass 为例

struct _GstBaseSrcClass {
  GstElementClass parent_class;

  /*< public >*/
  /* virtual methods for subclasses */

  /**
   * GstBaseSrcClass::get_caps:
   * @filter: (in) (nullable):
   *
   * Called to get the caps to report.
   */
  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);

  /**
   * GstBaseSrcClass::get_times:
   * @start: (out):
   * @end: (out):
   *
   * Given @buffer, return @start and @end 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);

  /**
   * GstBaseSrcClass::create:
   * @buf: (out):
   *
   * 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);

  /*< private >*/
  gpointer       _gst_reserved[GST_PADDING_LARGE];
};

可以看到在 class struct 中有很多函数指针,那么这些指针是怎么用的呢?再随便找一个 GstBaseSrc 的内部实现:

static gboolean
gst_base_src_prepare_seek_segment (GstBaseSrc * src, GstEvent * event,
    GstSegment * seeksegment)
{
  GstBaseSrcClass *bclass;
  gboolean result = FALSE;

  bclass = GST_BASE_SRC_GET_CLASS (src);

  //这里进行函数指针的调用
  if (bclass->prepare_seek_segment)
    result = bclass->prepare_seek_segment (src, event, seeksegment);

  return result;
}

因此,如果想覆盖 GstBaseSrc 的 prepare_seek_segment 这个函数的默认实现,只要在自定义的 MyGstBaseSrcClass 中为 GstBaseSrcClass 成员的 prepare_seek_segment 指定自定义的函数即可:

static gboolean
gst_my_prepare_seek_segment (GstBaseSrc * src, GstEvent * event, GstSegment * segment);


static void gst_my_gst_src_init_class(GstBaseSrc* src,gpointer g_class)
{
    ...
        parent_class->prepare_seek_segment = gst_my_prepare_seek_segment;
    ...
}

其实,上面的思路也是 c++ 语言的实现思路,只不过 c++ 编译器帮我们完成了语法到实现的转换。

一般情况下,某些类都会有一些默认的实现,比如 GstBaseSrc 的 class_init 函数中就用下面这些函数指定:

static void
gst_base_src_class_init (GstBaseSrcClass * klass)
{
//...

  //同样地, GstBaseSrc 也会给它自己的 parent class GstElementClass 指定一下自定义动作用来
  //覆盖 parent class 的默认动作
  gstelement_class->change_state =
      GST_DEBUG_FUNCPTR (gst_base_src_change_state);
  gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_src_send_event);

  //指定默认动作,GST_DEBUG_FUNCPTR 里面包裹的函数都是定义在 GstBaseSrc.c 文件中的 static 函数

  klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_src_default_get_caps);
  klass->negotiate = GST_DEBUG_FUNCPTR (gst_base_src_default_negotiate);
  klass->fixate = GST_DEBUG_FUNCPTR (gst_base_src_default_fixate);
  klass->prepare_seek_segment =
      GST_DEBUG_FUNCPTR (gst_base_src_default_prepare_seek_segment);
  klass->do_seek = GST_DEBUG_FUNCPTR (gst_base_src_default_do_seek);
  klass->query = GST_DEBUG_FUNCPTR (gst_base_src_default_query);
  klass->event = GST_DEBUG_FUNCPTR (gst_base_src_default_event);
  klass->create = GST_DEBUG_FUNCPTR (gst_base_src_default_create);
  klass->alloc = GST_DEBUG_FUNCPTR (gst_base_src_default_alloc);
  klass->decide_allocation = GST_DEBUG_FUNCPTR (gst_base_src_decide_allocation_default);

//...
}

虚函数:

结合上面的描述,如果 基类不提供默认动作,而继承类又不进行函数覆写,那么函数指针就是空指针,这个时候可以认为某个函数是一个纯虚函数。不过通常情况下都会进行二次包装,不会直接暴露成员函数给外部使用,比如GstBaseSrc就对外暴露了下面这些接口,可以认为这些接口是public接口:

GST_BASE_API
GType           gst_base_src_get_type (void);

GST_BASE_API
GstFlowReturn   gst_base_src_wait_playing     (GstBaseSrc *src);

GST_BASE_API
void            gst_base_src_set_live         (GstBaseSrc *src, gboolean live);

GST_BASE_API
gboolean        gst_base_src_is_live          (GstBaseSrc *src);

GST_BASE_API
void            gst_base_src_set_format       (GstBaseSrc *src, GstFormat format);

GST_BASE_API
void            gst_base_src_set_dynamic_size (GstBaseSrc * src, gboolean dynamic);

GST_BASE_API
void            gst_base_src_set_automatic_eos (GstBaseSrc * src, gboolean automatic_eos);

GST_BASE_API
void            gst_base_src_set_async        (GstBaseSrc *src, gboolean async);

GST_BASE_API
gboolean        gst_base_src_is_async         (GstBaseSrc *src);

GST_BASE_API
gboolean        gst_base_src_negotiate        (GstBaseSrc *src);

GST_BASE_API
void            gst_base_src_start_complete   (GstBaseSrc * basesrc, GstFlowReturn ret);

GST_BASE_API
GstFlowReturn   gst_base_src_start_wait       (GstBaseSrc * basesrc);

GST_BASE_API
gboolean        gst_base_src_query_latency    (GstBaseSrc *src, gboolean * live,
                                               GstClockTime * min_latency,
                                               GstClockTime * max_latency);
GST_BASE_API
void            gst_base_src_set_blocksize    (GstBaseSrc *src, guint blocksize);

GST_BASE_API
guint           gst_base_src_get_blocksize    (GstBaseSrc *src);

GST_BASE_API
void            gst_base_src_set_do_timestamp (GstBaseSrc *src, gboolean timestamp);

GST_BASE_API
gboolean        gst_base_src_get_do_timestamp (GstBaseSrc *src);

GST_BASE_API
gboolean        gst_base_src_new_seamless_segment (GstBaseSrc *src, gint64 start, gint64 stop, gint64 time);

GST_BASE_API
gboolean        gst_base_src_new_segment      (GstBaseSrc *src,
                                               const GstSegment * segment);

GST_BASE_API
gboolean        gst_base_src_set_caps         (GstBaseSrc *src, GstCaps *caps);

GST_BASE_API
GstBufferPool * gst_base_src_get_buffer_pool  (GstBaseSrc *src);

GST_BASE_API
void            gst_base_src_get_allocator    (GstBaseSrc *src,
                                               GstAllocator **allocator,
                                               GstAllocationParams *params);

GST_BASE_API
void            gst_base_src_submit_buffer_list (GstBaseSrc    * src,
                                                 GstBufferList * buffer_list);

而GstBaseSrcClass 中的那些指针则是 protected 的接口,因为只有继承类能够访问,同理可以通过在 GstBaseSrc.c 中定义Priv结构体来实现 private 接口,因为按照 c 语言的变成习惯,大家不会include c文件,这样就没法知道 Priv结构体 的内部细节。

如果想要更强制一点的制止不规范程序员试图 include c文件的话,那么可以约定一个规则,要求所有c文件都定义某个同名符号,这样在链接是就会报错重复符号,进而阻止 include c文件的行为。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值