二、GstMiniObject
1 GstMiniObject基本概念
“GstMiniObject” 是一个简单的结构体,可用于实现引用计数类型。
-
GstMiniObject使用的是
G_DEFINE_BOXED_TYPE
进行的定义。(也就是结构体对象,并没有普通对象的信号,属性等功能),GstMiniObject内部实现了引用计数功能。 -
具体G_DEFINE_BOXED_TYPE可以参考GObject学习笔记
-
因为不是GObject对象,所以不能使用GObject的相关函数,比如常用的 g_object_new, g_object_unref等函数。仅仅是注册一个GType类型。
子类将在其结构体中首先包含 “GstMiniObject”,然后调用 gst_mini_object_init 来初始化 “GstMiniObject” 字段。
gst_mini_object_ref 和 gst_mini_object_unref 分别用于增加和减少引用计数。mini-object 的引用计数达到 0 时,首先调用 dispose 函数,如果此函数返回 TRUE,则调用mini-object的 free 函数。(具体可参考gst_mini_object_unref
函数定义)
可以使用 gst_mini_object_copy 来复制mini-object。
当对象的引用计数恰好为 1 且没有父对象或只有一个父对象且该父对象本身是可写的时,gst_mini_object_is_writable 将返回 TRUE,这意味着当前调用者拥有该对象的唯一引用。gst_mini_object_make_writable 将返回对象的可写版本,如果引用计数不为 1,则可能是一个新的副本。
可以使用 gst_mini_object_set_qdata 和 gst_mini_object_get_qdata 将不透明数据与 GstMiniObject 关联。这些数据意在特定于特定对象,并且不会自动随着 gst_mini_object_copy 或类似方法一起复制。
可以分别使用 gst_mini_object_weak_ref 和 gst_mini_object_weak_unref 来添加和移除弱引用。
1.1 继承于GstMiniObject类的轻量级对象
-
GstBuffer: 表示流水线中单个媒体数据块。用于传输原始数据(如音频样本或视频帧)。
-
GstBufferList: 管理
GstBuffer
对象的集合,适用于需要批量处理或优化传输的情况。 -
GstMessage: 在 GStreamer 应用程序和元素之间传递异步消息,包括错误、状态变更、流结束通知等。
-
GstMemory: 表示
GstBuffer
数据的内存块,抽象了数据可以存储在的不同类型的内存。 -
GstCaps: 描述媒体数据的格式和属性,指定流水线元素可以处理或产生的媒体类型。
-
GstEvent: 在流水线元素之间传递控制事件,如流开始、配置更改、跳到新的时间点等。
-
GstContext: 在元素之间共享高层次信息,如设备句柄或平台特定数据。
-
GstSample: 包含
GstBuffer
、GstCaps
和时间戳,通常用于表示处理后的单个数据样本。 -
GstQuery: 查询流水线或其元素的状态,如持续时间、位置、格式、带宽等。
-
GstDateTime: 表示和处理日期和时间数据,用于处理时间相关的元数据或时间戳。
2 GstMiniObject类型结构
GstMiniObject
是一个GBoxed类型,类型注册函数由 gst_init
调用。
NOTE:
GStreamer中所有的GBoxed类型对象,得到类型函数和类型值是分离的。并不是:
#define GST_TYPE_MINI_OBJECT gst_mini_object_get_type()
而是:
/* filename:gstminiobject.h */
extern unsigned long _gst_mini_object_type;
#define GST_TYPE_MINI_OBJECT (_gst_mini_object_type)
/* filename:gstminiobject.c */
unsigned long _gst_mini_object_type = 0;
_gst_mini_object_type = gst_mini_object_get_type ();
2.1 GstMiniObject类型注册宏定义
/* filename:gstminiobject.h */
/* _gst_mini_object_type 是在类型系统中注册的类型值,该值由源文件定义,gst_init进行注册 */
extern unsigned long _gst_mini_object_type;
#define GST_TYPE_MINI_OBJECT (_gst_mini_object_type)
#define GST_DEFINE_MINI_OBJECT_TYPE(TypeName,type_name) \
G_DEFINE_BOXED_TYPE(TypeName,type_name, \
(GBoxedCopyFunc) gst_mini_object_ref, \
(GBoxedFreeFunc) gst_mini_object_unref)
/* 注册该类型调用的函数 */
extern gst_mini_object_get_type (void);
/* filename: gstminiobject.c */
/* GstMiniObject类型值定义 */
unsigned long _gst_mini_object_type = 0;
/* gst_mini_object_get_type函数定义
* G_DEFINE_BOXED_TYPE 拷贝和释放使用的ref和unref函数指针
*/
GST_DEFINE_MINI_OBJECT_TYPE (GstMiniObject, gst_mini_object);
/* 注册GstMiniObject类型,该函数由gst_init调用 */
void
_priv_gst_mini_object_initialize (void)
{
_gst_mini_object_type = gst_mini_object_get_type ();
weak_ref_quark = g_quark_from_static_string ("GstMiniObjectWeakRefQuark");
}
2.2 GstMiniObject类型相关枚举定义
2.2.1 GstMiniObjectFlags
/* filename: gstminiobject.h */
/**
* GstMiniObjectFlags:
* @GST_MINI_OBJECT_FLAG_LOCKABLE: 对象可以通过 gst_mini_object_lock() 和
* gst_mini_object_unlock() 进行锁定和解锁。
* @GST_MINI_OBJECT_FLAG_LOCK_READONLY: 对象被永久性地锁定在只读模式下。
* 只能对该对象执行读取锁定。
* @GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED: 预期该对象即使在调用 gst_deinit() 之后
* 也会保持存活,因此应该被内存泄漏检测工具忽略。(自版本 1.10 起可用)
* @GST_MINI_OBJECT_FLAG_LAST: 子类可以使用的第一个标志。(可以被用来计算那个flag标记了)
*
*/
typedef enum
{
GST_MINI_OBJECT_FLAG_LOCKABLE = (1 << 0),
GST_MINI_OBJECT_FLAG_LOCK_READONLY = (1 << 1),
GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED = (1 << 2),
/* padding */
GST_MINI_OBJECT_FLAG_LAST = (1 << 4)
} GstMiniObjectFlags;
该枚举类型是初始化函数中使用,标记该对象是只能还是读写模式。
void
gst_mini_object_init (GstMiniObject * mini_object, guint flags, GType type,
GstMiniObjectCopyFunction copy_func,
GstMiniObjectDisposeFunction dispose_func,
GstMiniObjectFreeFunction free_func) {
···
mini_object->flags = flags;
···
}
2.2.2 GstLockFlags
/* filename: gstminiobject.h */
/**
* GstLockFlags:
* @GST_LOCK_FLAG_READ: 用于读取访问的锁定
* @GST_LOCK_FLAG_WRITE: 用于写入访问的锁定
* @GST_LOCK_FLAG_EXCLUSIVE: 用于独占访问的锁定
* @GST_LOCK_FLAG_LAST: 一般用来占位,Mask等用途
*
*/
typedef enum {
GST_LOCK_FLAG_READ = (1 << 0),
GST_LOCK_FLAG_WRITE = (1 << 1),
GST_LOCK_FLAG_EXCLUSIVE = (1 << 2),
GST_LOCK_FLAG_LAST = (1 << 8)
} GstLockFlags;
该枚举类型在 gst_mini_object_lock
和 gst_mini_object_unlock
函数中使用。结构体_GstMiniObject
的 gint lockstate
成员有关。
2.2.3 priv_pointer锁枚举类型
/* filename: gstminiobject.c */
/**
* GST_TYPE_MINI_OBJECT:
*
* 与 #GstMiniObject 相关联的 #GType。
*
* 自版本 1.20 起可用。
*/
/* 出于向后兼容的原因,我们在 GstMiniObject 结构中
* 使用 guint 和 gpointer,以一种相当复杂的方式来存储父对象和 qdata。
* 最初,它们仅仅是 qdata 的数量和 qdata 本身。
*
* guint 被用作一个原子状态整数,具有以下状态:
* - Locked:0,基本上是一个自旋锁
* - No parent,无 qdata:1(指针为 NULL)
* - 一个父对象:2(指针包含父对象)
* - 多个父对象或 qdata:3(指针包含一个 PrivData 结构体)
*
* 除非我们处于状态 3,否则我们总是必须原子性地移动到锁定状态,
* 并在稍后再将其释放回目标状态,以便在访问指针时使用。
* 当我们处于状态 3 时,我们将不再转移到更低的状态
*
* FIXME 2.0:我们应该直接在结构体内部存储这些信息,
* 可能直接为几个父对象保留空间
*/
/* 私有数据的三种状态 */
enum {
PRIV_DATA_STATE_LOCKED = 0,
PRIV_DATA_STATE_NO_PARENT = 1,
PRIV_DATA_STATE_ONE_PARENT = 2,
PRIV_DATA_STATE_PARENTS_OR_QDATA = 3,
};
该枚举类型在 lock_priv_pointer
函数中使用。用于锁定priv_pointer
,结构体_GstMiniObject
的 guint priv_uint
成员有关。
2.3 GstMiniObject类型相关结构体定义
GstMiniObject
是主要结构体
- priv_pointer:有时候存储的就是结构体
PrivData
。 - lockstate:该变量是gint类型,一共有4个字节。
- 第一个字节:存储读或者写状态,也就是0x01或者0x02。
- 第二个字节:比如说,有三个用户进行读,第二个字节就是存储有多少个用户进行读或者写。0x301表示三个用户就行读。
- 第三个字节:独有锁,有几个用户上独有锁,这个变量存储在第三个字节。0x20000。
- flags:使用的是枚举
GstMiniObjectFlags
,子类会在该枚举的最后一个后面继续添加子类的flag。 比如`GstMemory:- 第一个字节:
GstMiniObjectFlags
。 - 第二个字节:
GstMemoryFlags
。
- 第一个字节:
/* filename: gstminiobject.h */
struct _GstMiniObject {
GType type; /* 对象注册的GType类型 */
/*< public >*/ /* with COW */
gint refcount; /* 引用计数 */
gint lockstate; /* 该对象锁状态,GstLockFlags */
guint flags; /* 该对象flag,GstMiniObjectFlags */
GstMiniObjectCopyFunction copy;
GstMiniObjectDisposeFunction dispose;
GstMiniObjectFreeFunction free;
/* < private > */
/* Used to keep track of parents, weak ref notifies and qdata */
guint priv_uint; /* priv状态 这和私有Data状态有关,具体flag如 PRIV_DATA_STATE_LOCKED*/
gpointer priv_pointer; /* 指向 */
};
/* filename: gstminiobject.c */
typedef struct {
GQuark quark;
GstMiniObjectNotify notify;
gpointer data;
GDestroyNotify destroy;
} GstQData;
typedef struct {
/* Atomic spinlock: 1 if locked, 0 otherwise */
gint parent_lock;
guint n_parents, n_parents_len;
GstMiniObject **parents;
guint n_qdata, n_qdata_len;
GstQData *qdata;
} PrivData;
3 GstMiniObject对象相关函数总结
3.1 初始化函数
该初始化函数仅仅就是把输入参数赋值给GstMiniObject结构体
/**
* gst_mini_object_init: (skip)
* @brief: 用所需要的 copy、dispose、free 函数初始化一个GstMiniObject对象
* @mini_object: a #GstMiniObject
* @flags: initial #GstMiniObjectFlags
* @type: the #GType of the mini-object to create
* @copy_func: (allow-none): the copy function, or %NULL
* @dispose_func: (allow-none): the dispose function, or %NULL
* @free_func: (allow-none): the free function or %NULL
*/
void
gst_mini_object_init (GstMiniObject * mini_object, guint flags, GType type,
GstMiniObjectCopyFunction copy_func,
GstMiniObjectDisposeFunction dispose_func,
GstMiniObjectFreeFunction free_func)
{
mini_object->type = type;
mini_object->refcount = 1;
mini_object->lockstate = 0;
mini_object->flags = flags;
mini_object->copy = copy_func;
mini_object->dispose = dispose_func;
mini_object->free = free_func;
/* 默认设定为没有父对象状态 */
g_atomic_int_set ((gint *) & mini_object->priv_uint,
PRIV_DATA_STATE_NO_PARENT);
mini_object->priv_pointer = NULL;
GST_TRACER_MINI_OBJECT_CREATED (mini_object);
}
3.2 GstMiniObject对象锁函数
根据GstLockFlags枚举类型,我们可以发现,一共有三种Flag,读、写和独有锁。
操作的GstMiniObject成员的lockstate
变量,该变量是gint类型,一共有4个字节。
-
第一个字节:存储读或者写状态,也就是0x01或者0x02。
-
第二个字节:比如说,有三个用户进行读,第二个字节就是存储有多少个用户进行读或者写。0x301表示三个用户就行读。
-
第三个字节:独有锁,有几个用户上独有锁,这个变量存储在第三个字节。0x20000。
根据下面代码发现,如果处于写锁状态,还可以再上成功写锁状态。最好写锁和独有锁一起上。可以避免同时多个写锁上成功。
3.2.1 gst_mini_object_lock
循环处理,最后 g_atomic_int_compare_and_exchange
是巧妙的多线程方式。
/**
* @brief: 用指定的GstLockFlags锁定GstMiniObject对象的访问状态
* @note: lockstate是一个gint变量,该变量具有4个字节
* 第一个字节:标记读写状态 0x01是读,0x02是
* 第二个字节是:上了几个锁 LOCK_ONE (有几个对象上了锁) 0x100
* 第三个字节是:GST_LOCK_FLAG_EXCLUSIVE有几个 0x10000
* @return: 如果被锁成功,返回TRUE
*/
gboolean
gst_mini_object_lock (GstMiniObject * object, GstLockFlags flags)
{
guint access_mode, state, newstate;
/* 检测object指针是否为NULL */
g_return_val_if_fail (object != NULL, FALSE);
/* 检查object对象可否能够进行上锁 */
g_return_val_if_fail (GST_MINI_OBJECT_IS_LOCKABLE (object), FALSE);
/* 如果该对象初始化flag就是只读,现在又要进行写锁,则返回FALSE */
if (G_UNLIKELY (object->flags & GST_MINI_OBJECT_FLAG_LOCK_READONLY &&
flags & GST_LOCK_FLAG_WRITE))
return FALSE;
do {
/* 获取进行锁的模式, FLAG_MASK就是0xFF */
access_mode = flags & FLAG_MASK;
/* 获取该对象目前锁的状态,初始化的时候 lockstate = 0; */
newstate = state = (guint) g_atomic_int_get (&object->lockstate);
GST_CAT_TRACE (GST_CAT_LOCKING, "lock %p: state %08x, access_mode %u",
object, state, access_mode);
/* 如果传入参数独有锁,则执行 */
if (access_mode & GST_LOCK_FLAG_EXCLUSIVE) {
/* shared ref,读写独有锁占用的是Flag的前八位,共享引用计数占用的是16位以后 */
newstate += SHARE_ONE; /* newstate = newstate + 0x10000*/
access_mode &= ~GST_LOCK_FLAG_EXCLUSIVE; /* access_mode 已经获取了独有锁flag,去掉独有锁,查看还剩下什么flag */
}
/**
* 如果对象已经处于写锁状态或者请求写锁,而且
* shared 计数 >= 2 ,上锁失败
*/
if (((state & GST_LOCK_FLAG_WRITE) != 0
|| (access_mode & GST_LOCK_FLAG_WRITE) != 0)
&& IS_SHARED (newstate))
goto lock_failed;
if (access_mode) {
if ((state & LOCK_FLAG_MASK) == 0) { /* 该对象没有处于任何锁状态,也就是 state = 0 */
/* nothing mapped, set access_mode */
newstate |= access_mode; /* 把请求上的锁,赋值给 newstate */
} else {
/* access_mode must match */
if ((state & access_mode) != access_mode) /* 具有写锁的时候不能上读锁,具有读锁的时候不能上写锁*/
goto lock_failed;
}
/* increase refcount */
newstate += LOCK_ONE;
}
} while (!g_atomic_int_compare_and_exchange (&object->lockstate, state,
newstate));
return TRUE;
lock_failed:
{
GST_CAT_DEBUG (GST_CAT_LOCKING,
"lock failed %p: state %08x, access_mode %u", object, state,
access_mode);
return FALSE;
}
}
3.2.2 gst_mini_object_unlock
/**
* @brief: 用指定的GstLockFlags解除GstMiniObject对象的访问状态
*/
void
gst_mini_object_unlock (GstMiniObject * object, GstLockFlags flags)
{
guint access_mode, state, newstate;
g_return_if_fail (object != NULL);
g_return_if_fail (GST_MINI_OBJECT_IS_LOCKABLE (object));
do {
access_mode = flags & FLAG_MASK;
newstate = state = (guint) g_atomic_int_get (&object->lockstate);
GST_CAT_TRACE (GST_CAT_LOCKING, "unlock %p: state %08x, access_mode %u",
object, state, access_mode);
/* 先去除独有锁的标记 */
if (access_mode & GST_LOCK_FLAG_EXCLUSIVE) {
/* shared counter */
g_return_if_fail (state >= SHARE_ONE);
newstate -= SHARE_ONE;
access_mode &= ~GST_LOCK_FLAG_EXCLUSIVE; /* 去除传入参数中的独有锁 */
}
if (access_mode) {
g_return_if_fail ((state & access_mode) == access_mode);
/* decrease the refcount */
newstate -= LOCK_ONE;
/* last refcount, unset access_mode */
if ((newstate & LOCK_FLAG_MASK) == access_mode) /* 如果是最后一个锁引用,把第一第二个字节置零 */
newstate &= ~LOCK_FLAG_MASK;
}
} while (!g_atomic_int_compare_and_exchange (&object->lockstate, state,
newstate));
}
3.3 GstMiniObject是否可写
-
不可写状态:
1.这是一个能够上锁的GstMiniObject对象 如果被上两次独有锁,也就是处于两次共享状态,直接返回不可写
2.这是一个只读的GstMiniObject对象,引用计数不等于1,直接返回不可写
-
可写状况: 对象可锁,只有一个用户上独有锁或者对象只读,引用计数等于 1 的时候
-
只有一个用户上独有锁,只有一个父对象且父对象本身是可写的,返回可写
-
只有一个用户上独有锁,没有父对象,返回可写。
-
3.3.1 gst_mini_object_is_writable
/**
* gst_mini_object_is_writable:
* @mini_object: 要检查的小型对象
*
* 如果 @mini_object 设置了 LOCKABLE 标志,检查当前对 @object 的独占锁定是否是唯一的,
* 这意味着对对象的更改不会对其他任何对象可见。
*
* 如果没有设置 LOCKABLE 标志,检查 @mini_object 的引用计数是否正好为 1,
* 这意味着没有其他对该对象的引用,因此该对象是可写的。
*
* 修改小型对象应该只在确认它是可写的之后进行。
*
* 返回:如果对象是可写的,则为 %TRUE。
*/
gboolean
gst_mini_object_is_writable (const GstMiniObject * mini_object)
{
gboolean result;
gint priv_state;
g_return_val_if_fail (mini_object != NULL, FALSE);
/* 检查 GstMiniObject 对象创建的时候,是否标记了能够锁的Flag */
if (GST_MINI_OBJECT_IS_LOCKABLE (mini_object)) { /* 创建的时候是:GST_MINI_OBJECT_FLAG_LOCKABLE */
/* 是否处于被共享状态 */
result = !IS_SHARED (g_atomic_int_get (&mini_object->lockstate));
} else { /* 创建的时候是其他Flag */
result = (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) == 1);
}
/**
* SHARED只跟独有锁有关,如果该对象被两个用户独有,就不能被写。
*/
if (!result) /* 如果处于共享状态,那就一定是可写的,直接返回 FALSE */
return result;
/* 如果不是 PRIV_DATA_STATE_PARENTS_OR_QDATA,堵塞等待可切换到 PRIV_DATA_STATE_LOCKED状态, 返回的 priv_state 是锁之前的状态*/
priv_state = lock_priv_pointer (GST_MINI_OBJECT_CAST (mini_object));
/* 现在我们要么需要检查完整的结构体以及其中的所有父对象,
* 要么如果确实只有一个父对象,我们可以检查那一个 */
if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA) {
PrivData *priv_data = mini_object->priv_pointer;
/* Lock parents( parent_lock 对应 1 是 锁, 0 不是锁 ) */
while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
/**
* @note: 如果我们有一个父对象,我们只有在那个父对象是可写的情况下才是可写的。
* 我们没有父对象,我们就是可写的
* 否则,如果我们有多个父对象,我们就不是可写的
*/
if (priv_data->n_parents == 1)
result = gst_mini_object_is_writable (priv_data->parents[0]); /* 对应基本概念中的:只有一个父对象且该父对象本身是可写的时,对象可写*/
else if (priv_data->n_parents == 0)
result = TRUE;
else
result = FALSE;
/* Unlock again(恢复到锁之前的状态) */
g_atomic_int_set (&priv_data->parent_lock, 0);
} else {
if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
result = gst_mini_object_is_writable (mini_object->priv_pointer);
} else {
g_assert (priv_state == PRIV_DATA_STATE_NO_PARENT);
result = TRUE;
}
/* Unlock again (恢复到锁之前的状态) */
g_atomic_int_set ((gint *) & mini_object->priv_uint, priv_state);
}
return result;
}
3.3.2 gst_mini_object_make_writable
/**
* gst_mini_object_make_writable: (跳过)
* @mini_object: (完全转移): 要使其可写的GstMiniObject对象
*
* 检查一个对象是否可写。如果不可写,将创建并返回一个可写的副本。
* 这会放弃对原始GstMiniObject对象的引用,并返回对新对象的引用。
*
* 多线程安全
*
* 返回:(完全转移) (可空):一个可写的GstMiniObject对象(可能与 @mini_object 相同,也可能不同)
* 或者如果需要复制但不可能时返回 %NULL。
*/
GstMiniObject *
gst_mini_object_make_writable (GstMiniObject * mini_object)
{
GstMiniObject *ret;
g_return_val_if_fail (mini_object != NULL, NULL);
if (gst_mini_object_is_writable (mini_object)) {
ret = mini_object;
} else {
ret = gst_mini_object_copy (mini_object);
GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy %s miniobject %p -> %p",
g_type_name (GST_MINI_OBJECT_TYPE (mini_object)), mini_object, ret);
gst_mini_object_unref (mini_object);
}
return ret;
}
3.4 GstMiniObject父对象
这里其实没有什么好讲的,具体函数可以看源代码。
注意:
-
gst_mini_object_add_parent
函数将 @parent 添加为 @object 的一个父对象。 -
拥有一个或多个父对象会影响 GstMiniObject 的可写性:如果一个 @parent 不可写,那么 @GstMiniObject 也不可写,无论其引用计数是多少。@GstMiniObject 只有在所有父对象都是可写的,并且其自身的引用计数正好为1时,才是可写的。
-
注意:这个函数不会获取 @parent 的所有权,也不会增加额外的引用计数。
-
调用者有责任在之后的某个时间点移除父对象。
3.4.1 gst_mini_object_add_parent
/**
* gst_mini_object_add_parent:
* @object: 一个 #GstMiniObject
* @parent: 一个父 #GstMiniObject
*
* 这个函数将 @parent 添加为 @object 的一个父对象。拥有一个或多个父对象会影响
* @object 的可写性:如果一个 @parent 不可写,那么 @object 也不可写,
* 无论其引用计数是多少。@object 只有在所有父对象都是可写的,并且其自身的引用计数
* 正好为1时,才是可写的。
*
* 注意:这个函数不会获取 @parent 的所有权,也不会增加额外的引用计数。
* 调用者有责任在之后的某个时间点移除父对象。
*
* 自版本 1.16 起可用
*/
void
gst_mini_object_add_parent (GstMiniObject * object, GstMiniObject * parent)
{
gint priv_state;
g_return_if_fail (object != NULL);
GST_CAT_TRACE (GST_CAT_REFCOUNTING, "adding parent %p to object %p", parent,
object);
priv_state = lock_priv_pointer (object);
/*如果已经有一个父对象,现在需要分配整个(完整)结构体*/
if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
/* Unlock again */
g_atomic_int_set ((gint *) & object->priv_uint, priv_state);
ensure_priv_data (object);
priv_state = PRIV_DATA_STATE_PARENTS_OR_QDATA;
}
/* 现在我们要么需要将新的父对象添加到完整的结构体中,要么将我们唯一的一个父对象添加到指针字段中 */
if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA) {
PrivData *priv_data = object->priv_pointer;
/* Lock parents */
while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
if (priv_data->n_parents >= priv_data->n_parents_len) {
priv_data->n_parents_len *= 2;
if (priv_data->n_parents_len == 0)
priv_data->n_parents_len = 16;
priv_data->parents =
g_realloc (priv_data->parents,
priv_data->n_parents_len * sizeof (GstMiniObject *));
}
priv_data->parents[priv_data->n_parents] = parent;
priv_data->n_parents++;
/* Unlock again */
g_atomic_int_set (&priv_data->parent_lock, 0);
} else if (priv_state == PRIV_DATA_STATE_NO_PARENT) {
object->priv_pointer = parent;
/* Unlock again */
g_atomic_int_set ((gint *) & object->priv_uint, PRIV_DATA_STATE_ONE_PARENT);
} else {
g_assert_not_reached ();
}
}
3.4.2 gst_mini_object_remove_parent
/**
* gst_mini_object_remove_parent:
* @object: a #GstMiniObject
* @parent: a parent #GstMiniObject
*
* This removes @parent as a parent for @object. See
* gst_mini_object_add_parent().
*
* Since: 1.16
*/
void
gst_mini_object_remove_parent (GstMiniObject * object, GstMiniObject * parent)
{
gint priv_state;
g_return_if_fail (object != NULL);
GST_CAT_TRACE (GST_CAT_REFCOUNTING, "removing parent %p from object %p",
parent, object);
priv_state = lock_priv_pointer (object);
/* 现在我们必须将新的父元素添加到完整的结构中,或者将我们唯一的父元素添加到指针字段中 */
if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA) {
PrivData *priv_data = object->priv_pointer;
guint i;
/* Lock parents */
while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
/* 在parent数组里面找到要要删除的那个parent */
for (i = 0; i < priv_data->n_parents; i++)
if (parent == priv_data->parents[i])
break;
if (i != priv_data->n_parents) {
priv_data->n_parents--;
if (priv_data->n_parents != i)
priv_data->parents[i] = priv_data->parents[priv_data->n_parents];
} else {
g_warning ("%s: couldn't find parent %p (object:%p)", G_STRFUNC,
object, parent);
}
/* Unlock again */
g_atomic_int_set (&priv_data->parent_lock, 0);
} else if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
if (object->priv_pointer != parent) {
g_warning ("%s: couldn't find parent %p (object:%p)", G_STRFUNC,
object, parent);
/* Unlock again */
g_atomic_int_set ((gint *) & object->priv_uint, priv_state);
} else {
object->priv_pointer = NULL;
/* Unlock again */
g_atomic_int_set ((gint *) & object->priv_uint,
PRIV_DATA_STATE_NO_PARENT);
}
} else {
/* Unlock again */
g_atomic_int_set ((gint *) & object->priv_uint, PRIV_DATA_STATE_NO_PARENT);
}
}
3.5 GstMiniObject对的GstQData
3.5.1 gst_mini_object_set_qdata
/**
* gst_mini_object_set_qdata:
* @object: 一个 #GstMiniObject
* @quark: 一个 #GQuark,用于命名用户数据指针
* @data: 一个不透明的用户数据指针
* @destroy: 当 @data 需要被释放时调用的函数,以 @data 作为参数
*
* 这个函数在一个GstMiniObject上设置一个不透明的、命名的指针。
* 名称通过一个 #GQuark 来指定(可以通过 g_quark_from_static_string() 等方式获取),
* 而指针可以通过 gst_mini_object_get_qdata() 从 @object 中获取,直到 @object 被销毁。
* 如果设置了之前已经设置的用户数据指针,它会覆盖(释放)旧的指针设置,使用 %NULL 作为指针
* 实际上会移除存储的数据。
*
* 当 @object 被销毁,或者数据被通过具有相同 @quark 的 gst_mini_object_set_qdata() 调用覆盖时,
* 可以指定 @destroy,它会以 @data 作为参数调用。
*/
void
gst_mini_object_set_qdata (GstMiniObject * object, GQuark quark,
gpointer data, GDestroyNotify destroy)
{
gint i;
gpointer old_data = NULL;
GDestroyNotify old_notify = NULL;
g_return_if_fail (object != NULL);
g_return_if_fail (quark > 0);
G_LOCK (qdata_mutex);
if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
PrivData *priv_data = object->priv_pointer;
old_data = QDATA_DATA (priv_data, i);
old_notify = QDATA_DESTROY (priv_data, i);
if (data == NULL)
remove_notify (object, i);
}
if (data != NULL)
set_notify (object, i, quark, NULL, data, destroy);
G_UNLOCK (qdata_mutex);
if (old_notify)
old_notify (old_data);
}
3.5.2 gst_mini_object_get_qdata
/**
* gst_mini_object_get_qdata:
* @object: 用于从中获取存储的用户数据指针的 GstMiniObject
* @quark: 一个 #GQuark,用于命名用户数据指针
*
* 这个函数用于获取通过 gst_mini_object_set_qdata() 存储的用户数据指针。
*
* 返回值:(transfer none) (nullable):设置的用户数据指针,或者 %NULL
*/
gpointer
gst_mini_object_get_qdata (GstMiniObject * object, GQuark quark)
{
guint i;
gpointer result;
g_return_val_if_fail (object != NULL, NULL);
g_return_val_if_fail (quark > 0, NULL);
G_LOCK (qdata_mutex);
if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
PrivData *priv_data = object->priv_pointer;
result = QDATA_DATA (priv_data, i);
} else {
result = NULL;
}
G_UNLOCK (qdata_mutex);
return result;
}
3.5.3 gst_mini_object_steal_qdata
注意: 从GstQData *qdata
移除匹配的qdata,并且不触发调用destroy
函数
/**
* gst_mini_object_steal_qdata:
* @object: 用于从中获取存储的用户数据指针的 GstMiniObject
* @quark: 一个 #GQuark,用于命名用户数据指针
*
* 这个函数用于获取通过 gst_mini_object_set_qdata() 存储的用户数据指针,
* 并从 @object 中移除这些数据,同时不调用其 `destroy()` 函数(如果设置了的话)。
*
* 返回值:(transfer full) (nullable):设置的用户数据指针,或者 %NULL
*/
gpointer
gst_mini_object_steal_qdata (GstMiniObject * object, GQuark quark)
{
guint i;
gpointer result;
g_return_val_if_fail (object != NULL, NULL);
g_return_val_if_fail (quark > 0, NULL);
G_LOCK (qdata_mutex);
if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
PrivData *priv_data = object->priv_pointer;
result = QDATA_DATA (priv_data, i);
remove_notify (object, i);
} else {
result = NULL;
}
G_UNLOCK (qdata_mutex);
return result;
}
3.6 GstMiniObject对象的虚引用
3.6.1 gst_mini_object_weak_ref
/**
* gst_mini_object_weak_ref: (skip)
* @object: 要弱引用的 #GstMiniObject
* @notify: 在GstMiniObject被释放之前调用的回调函数
* @data: 传递给回调函数的额外数据
*
* 在一个GstMiniObject对象上添加一个弱引用回调函数。弱引用用于在GstMiniObject对象被销毁时进行通知。
* 它们被称为 "弱引用",因为它们允许您安全地持有对GstMiniObject对象的指针,
* 而不需要调用 gst_mini_object_ref()(gst_mini_object_ref() 添加强引用,
* 即强制对象保持活动状态)。
*/
void
gst_mini_object_weak_ref (GstMiniObject * object,
GstMiniObjectNotify notify, gpointer data)
{
g_return_if_fail (object != NULL);
g_return_if_fail (notify != NULL);
g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (object) >= 1);
G_LOCK (qdata_mutex);
set_notify (object, -1, weak_ref_quark, notify, data, NULL);
G_UNLOCK (qdata_mutex);
}
3.6.2 gst_mini_object_weak_unref
/**
* gst_mini_object_weak_unref: (skip)
* @object: 用于移除弱引用的 #GstMiniObject
* @notify: 要搜索的回调函数
* @data: 要搜索的数据
*
* 从GstMiniObject对象中移除一个弱引用回调。
*/
void
gst_mini_object_weak_unref (GstMiniObject * object,
GstMiniObjectNotify notify, gpointer data)
{
gint i;
g_return_if_fail (object != NULL);
g_return_if_fail (notify != NULL);
G_LOCK (qdata_mutex);
if ((i = find_notify (object, weak_ref_quark, TRUE, notify, data)) != -1) {
remove_notify (object, i);
} else {
g_warning ("%s: couldn't find weak ref %p (object:%p data:%p)", G_STRFUNC,
notify, object, data);
}
G_UNLOCK (qdata_mutex);
}