当前位置:网站首页>[GLib][GStreamer] 插件编写思路 —— 继承、覆写 和 虚函数
[GLib][GStreamer] 插件编写思路 —— 继承、覆写 和 虚函数
2022-06-21 23:57:00 【ykun089】
每一个 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文件的行为。
边栏推荐
- SQL statement - permission management
- [2023 approval in advance] China Singapore SECCO
- Small protocol with great power, why can't digital transformation without nvme full flash memory?
- Enterprises can improve database security in four ways
- pytorch学习01:梯度下降实现简单线性回归
- 四数之和[数组排序+双指针]
- 12 initialization of beautifulsoup class
- Pytorch learning 07:broadcast broadcast - automatic extension
- 0x00007ffff3d3ecd0 in _IO_vfprintf_internal (s=0x7ffff40b5620 <_IO_2_1_stdout_>
- Pytorch learning 03: tensor data types and some operations
猜你喜欢

Pytorch learning 07:broadcast broadcast - automatic extension

鸿蒙OS学习(轮播图、列表、图标)

旋转框目标检测————关于旋转框定义和解决方案

0x00007ffff3d3ecd0 in _IO_vfprintf_internal (s=0x7ffff40b5620 <_IO_2_1_stdout_>

【DailyFresh】课程记录3--商品搜索相关

Pytorch learning 11:where and gather
![[examination skills] memory method and simple derivation of Green formula](/img/26/f28a9f4abaca94988845b3fdaaf571.png)
[examination skills] memory method and simple derivation of Green formula

Pytorch learning 03: tensor data types and some operations

【环境踩坑】pycharm使用qt时报错

Assembly language example
随机推荐
Is xshell worse than SecureCRT?
对“基于tensorflow+RNN的新浪新闻文本分类”一文的图示化理解
位运算位或
Visualization of camera pose
跨境贸易和跨境电商的三大区别简单分析
积分体系运营汇中,用户的哪些行为可以获得积分
DOM 节点
Is it safe to open an account for futures in Huishang futures?
Lecture 3 of Data Engineering Series: characteristic engineering of data centric AI
Introduction and use of pytest fixture, confitest and mark
pytorch学习12:自动求导
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
【环境踩坑】在自己电脑上搭建FastDFS
RISCV 的 cache
小小协议大威力,数字化转型为何缺不了NVMe全闪存?
力扣每日一题-第24天-485.最大连续1的个数
Leetcode content
leetcode 279. Perfect squares (medium)
How to judge pure IP? Where can I find it? Is it Expensive?
合理选择液压滑环密封间隙的重要性