模块的简单分析
【GStreamer】GstAllocator的简单分析
【GStreamer】GstMemory的简单分析
【GStreamer】GstBuffer的简单分析
【GStreamer】GstPad的简单分析
【GStreamer】GstElement的简单分析
【GStreamer】GstBus和GstMessage的简单分析
【GStreamer】GstDevice和GstPlugin的简单分析
GstElement是GStreamer中最核心的构建块,代表一个功能单元,用于处理多媒体数据流。每个元素都有特定的功能,例如source elements用于生成数据(摄像头读取视频)、filter elements用于处理数据(编解码、格式转换等)、sink elements用于接收数据(视频渲染到屏幕),GStreamer通过组合不同的GstElement来构建复杂的多媒体处理流程
1.类定义
(1)状态机
typedef enum {
GST_STATE_VOID_PENDING = 0,
GST_STATE_NULL = 1, // 初始状态,元素未被初始化
GST_STATE_READY = 2, // 元素已初始化,但未开始处理数据
GST_STATE_PAUSED = 3, // 元素已经准备好处理数据,但数据流被暂停
GST_STATE_PLAYING = 4 // 元素正在处理数据
} GstState;
(2)状态转换机
typedef enum /*< flags=0 >*/
{
GST_STATE_CHANGE_NULL_TO_READY = (GST_STATE_NULL<<3) | GST_STATE_READY,
GST_STATE_CHANGE_READY_TO_PAUSED = (GST_STATE_READY<<3) | GST_STATE_PAUSED,
GST_STATE_CHANGE_PAUSED_TO_PLAYING = (GST_STATE_PAUSED<<3) | GST_STATE_PLAYING,
GST_STATE_CHANGE_PLAYING_TO_PAUSED = (GST_STATE_PLAYING<<3) | GST_STATE_PAUSED,
GST_STATE_CHANGE_PAUSED_TO_READY = (GST_STATE_PAUSED<<3) | GST_STATE_READY,
GST_STATE_CHANGE_READY_TO_NULL = (GST_STATE_READY<<3) | GST_STATE_NULL,
GST_STATE_CHANGE_NULL_TO_NULL = (GST_STATE_NULL<<3) | GST_STATE_NULL,
GST_STATE_CHANGE_READY_TO_READY = (GST_STATE_READY<<3) | GST_STATE_READY,
GST_STATE_CHANGE_PAUSED_TO_PAUSED = (GST_STATE_PAUSED<<3) | GST_STATE_PAUSED,
GST_STATE_CHANGE_PLAYING_TO_PLAYING = (GST_STATE_PLAYING<<3) | GST_STATE_PLAYING
} GstStateChange;
(3)元素标志
描述元素的行为和特性,用于在运行时检查元素的状态或配置
typedef enum
{
// 元素状态被锁定
GST_ELEMENT_FLAG_LOCKED_STATE = (GST_OBJECT_FLAG_LAST << 0),
// 元素为sink元素
GST_ELEMENT_FLAG_SINK = (GST_OBJECT_FLAG_LAST << 1),
// 元素为source元素
GST_ELEMENT_FLAG_SOURCE = (GST_OBJECT_FLAG_LAST << 2),
// 元素可以提供时钟
GST_ELEMENT_FLAG_PROVIDE_CLOCK = (GST_OBJECT_FLAG_LAST << 3),
// 元素需要一个时钟
GST_ELEMENT_FLAG_REQUIRE_CLOCK = (GST_OBJECT_FLAG_LAST << 4),
// 元素可索引,即支持随机访问
GST_ELEMENT_FLAG_INDEXABLE = (GST_OBJECT_FLAG_LAST << 5),
/* padding */
GST_ELEMENT_FLAG_LAST = (GST_OBJECT_FLAG_LAST << 10)
} GstElementFlags;
(4)GstElement
GstElement是所有元素的基类,包括source,filter和sink
struct _GstElement
{
GstObject object;
/*< public >*/ /* with LOCK */
// 元素状态锁(递归互斥锁)
GRecMutex state_lock;
/* element state */
// 状态变化条件变量
GCond state_cond;
// 检测状态变化的版本号
guint32 state_cookie;
// 目标状态
GstState target_state;
// 当前状态
GstState current_state;
// 下一个状态
GstState next_state;
// 挂起状态
GstState pending_state;
// 上一次状态变化的返回值
GstStateChangeReturn last_return;
// 元素总线,用于传递消息和事件
GstBus *bus;
/* allocated clock */
// 元素时钟,用于同步数据流
GstClock *clock;
// 基础时间,用于计算元素的当前事件
GstClockTimeDiff base_time; /* NULL/READY: 0 - PAUSED: current time - PLAYING: difference to clock */
// 开始时间,元素开始播放的时间
GstClockTime start_time;
/* element pads, these lists can only be iterated while holding
* the LOCK or checking the cookie after each LOCK. */
// pad的总数
guint16 numpads;
// 所有pad的链表
GList *pads;
// srcpad的数量
guint16 numsrcpads;
// srcpads的链表
GList *srcpads;
// sinkpad的数量
guint16 numsinkpads;
// sinkpads的链表
GList *sinkpads;
// pad列表的版本号,用于检测pad列表的变化
guint32 pads_cookie;
/* with object LOCK */
// 元素的上下文列表,用于管理元素的运行时上下文
GList *contexts;
/*< private >*/
gpointer _gst_reserved[GST_PADDING-1];
};
(5)GstElementClass
struct _GstElementClass
{
GstObjectClass parent_class;
/*< public >*/
/* the element metadata */
// 元数据,包含元素的描述信息
gpointer metadata;
/* factory that the element was created from */
// 管理元素的创建和销毁
GstElementFactory *elementfactory;
/* templates for our pads */
// pad模板链表,描述元素支持的pad类型
GList *padtemplates;
// pad模板的数量
gint numpadtemplates;
// pad模板列表的版本号,用于检测pad模板列表的变化
guint32 pad_templ_cookie;
/*< private >*/
/* signal callbacks */
// pad添加到元素时的回调
void (*pad_added) (GstElement *element, GstPad *pad);
// pad移除时的回调
void (*pad_removed) (GstElement *element, GstPad *pad);
// 不再添加pad的回调
void (*no_more_pads) (GstElement *element);
/*< public >*/
/* virtual methods for subclasses */
/* request/release pads */
/* FIXME 2.0 harmonize naming with gst_element_request_pad */
// 请求一个新pad,根据给定的模板和名称创建pad
GstPad* (*request_new_pad) (GstElement *element, GstPadTemplate *templ,
const gchar* name, const GstCaps *caps);
// 释放一个pad,将其从元素中移除
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);
/*< private >*/
gpointer _gst_reserved[GST_PADDING_LARGE-2];
};
2.函数定义
2.1 初始化
(1)gst_element_base_class_init()
初始化元素的基类,通常在元素类被首次创建时调用(被注册到GStreamer时,通常是插件加载时),用于设置类的默认行为
static void
gst_element_base_class_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
GList *node, *padtemplates;
/* Copy the element details here so elements can inherit the
* details from their base class and classes only need to set
* the details in class_init instead of base_init */
// 设置metadata
element_class->metadata =
element_class->metadata ? gst_structure_copy (element_class->metadata) :
gst_structure_new_empty ("metadata");
/* Copy the pad templates so elements inherit them
* from their base class but elements can add pad templates in class_init
* instead of base_init.
*/
// 复制基类的pad模板链表
padtemplates = g_list_copy (element_class->padtemplates);
for (node = padtemplates; node != NULL; node = node->next) {
GstPadTemplate *tmpl = (GstPadTemplate *) node->data;
gst_object_ref (tmpl);
}
element_class->padtemplates = padtemplates;
/* set the factory, see gst_element_register() */
// 初始化工厂信息
element_class->elementfactory =
g_type_get_qdata (G_TYPE_FROM_CLASS (element_class),
__gst_elementclass_factory);
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "type %s : factory %p",
G_OBJECT_CLASS_NAME (element_class), element_class->elementfactory);
}
(2)gst_element_class_init()
初始化元素的类,通常在元素类被首次创建时调用(被注册到GStreamer时,通常是插件加载时),用于设置元素的元数据、信号、属性、pad模板等
static void
gst_element_class_init (GstElementClass * klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass *) klass;
parent_class = g_type_class_peek_parent (klass);
/**
* GstElement::pad-added:
* @gstelement: the object which received the signal
* @new_pad: the pad that has been added
*
* a new #GstPad has been added to the element. Note that this signal will
* usually be emitted from the context of the streaming thread. Also keep in
* mind that if you add new elements to the pipeline in the signal handler
* you will need to set them to the desired target state with
* gst_element_set_state() or gst_element_sync_state_with_parent().
*/
// 添加pad时的信号
gst_element_signals[PAD_ADDED] =
g_signal_new ("pad-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstElementClass, pad_added), NULL, NULL,
NULL, G_TYPE_NONE, 1, GST_TYPE_PAD);
/**
* GstElement::pad-removed:
* @gstelement: the object which received the signal
* @old_pad: the pad that has been removed
*
* a #GstPad has been removed from the element
*/
// 移除pad时的信号
gst_element_signals[PAD_REMOVED] =
g_signal_new ("pad-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstElementClass, pad_removed), NULL, NULL,
NULL, G_TYPE_NONE, 1, GST_TYPE_PAD);
/**
* GstElement::no-more-pads:
* @gstelement: the object which received the signal
*
* This signals that the element will not generate more dynamic pads.
* Note that this signal will usually be emitted from the context of
* the streaming thread.
*/
// 不期望再添加pad时的信号
gst_element_signals[NO_MORE_PADS] =
g_signal_new ("no-more-pads", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstElementClass, no_more_pads), NULL,
NULL, NULL, G_TYPE_NONE, 0);
// 构造和析构函数
gobject_class->dispose = gst_element_dispose;
gobject_class->finalize = gst_element_finalize;
gobject_class->constructed = gst_element_constructed;
// element的一些默认函数
klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state_func);
klass->set_state = GST_DEBUG_FUNCPTR (gst_element_set_state_func);
klass->get_state = GST_DEBUG_FUNCPTR (gst_element_get_state_func);
klass->set_clock = GST_DEBUG_FUNCPTR (gst_element_set_clock_func);
klass->set_bus = GST_DEBUG_FUNCPTR (gst_element_set_bus_func);
klass->query = GST_DEBUG_FUNCPTR (gst_element_default_query);
klass->send_event = GST_DEBUG_FUNCPTR (gst_element_default_send_event);
klass->numpadtemplates = 0;
klass->post_message = GST_DEBUG_FUNCPTR (gst_element_post_message_default);
klass->set_context = GST_DEBUG_FUNCPTR (gst_element_set_context_default);
klass->elementfactory = NULL;
}
(3)gst_element_init()
初始化元素的实例,它在每次创建元素的新实例时调用(例如gst_element_factory_make()),用于设置实例的初始状态和属性
static void
gst_element_init (GstElement * element)
{
GST_STATE (element) = GST_STATE_NULL;
GST_STATE_TARGET (element) = GST_STATE_NULL;
GST_STATE_NEXT (element) = GST_STATE_VOID_PENDING;
GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
GST_STATE_RETURN (element) = GST_STATE_CHANGE_SUCCESS;
g_rec_mutex_init (&element->state_lock);
g_cond_init (&element->state_cond);
}
2.2 对pad的操作
(1)向element中添加pad
gboolean
gst_element_add_pad (GstElement * element, GstPad * pad)
{
gchar *pad_name;
gboolean active;
gboolean should_activate;
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
/* locking pad to look at the name */
// 检查pad的名称和激活状态
GST_OBJECT_LOCK (pad);
pad_name = g_strdup (GST_PAD_NAME (pad));
GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element, "adding pad '%s'",
GST_STR_NULL (pad_name));
active = GST_PAD_IS_ACTIVE (pad);
GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_NEED_PARENT);
GST_OBJECT_UNLOCK (pad);
/* then check to see if there's already a pad by that name here */
// 检查是否有同名的pad
GST_OBJECT_LOCK (element);
if (G_UNLIKELY (!gst_object_check_uniqueness (element->pads, pad_name)))
goto name_exists;
/* try to set the pad's parent */
// 将element设置为pad的父元素
if (G_UNLIKELY (!gst_object_set_parent (GST_OBJECT_CAST (pad),
GST_OBJECT_CAST (element))))
goto had_parent;
/* check for active pads */
// 当前状态是非激活,但是期望要激活
should_activate = !active && (GST_STATE (element) > GST_STATE_READY ||
GST_STATE_NEXT (element) == GST_STATE_PAUSED);
g_free (pad_name);
/* add it to the list */
// 检查pad的方向,并添加到对应的列表之中
switch (gst_pad_get_direction (pad)) {
case GST_PAD_SRC:
element->srcpads = g_list_append (element->srcpads, pad);
element->numsrcpads++;
break;
case GST_PAD_SINK:
element->sinkpads = g_list_append (element->sinkpads, pad);
element->numsinkpads++;
break;
default:
goto no_direction;
}
// 无论pad的方向,添加到整体的链表当中
element->pads = g_list_append (element->pads, pad);
element->numpads++;
element->pads_cookie++;
GST_OBJECT_UNLOCK (element);
// 当前pad应该被激活,进行状态激活
if (should_activate)
gst_pad_set_active (pad, TRUE);
/* emit the PAD_ADDED signal */
// 发布信号,表示element中已经添加了一个pad
g_signal_emit (element, gst_element_signals[PAD_ADDED], 0, pad);
GST_TRACER_ELEMENT_ADD_PAD (element, pad);
return TRUE;
/* ERROR cases */
name_exists:
{
g_critical ("Padname %s is not unique in element %s, not adding",
pad_name, GST_ELEMENT_NAME (element));
GST_OBJECT_UNLOCK (element);
g_free (pad_name);
gst_object_ref_sink (pad);
gst_object_unref (pad);
return FALSE;
}
had_parent:
{
g_critical
("Pad %s already has parent when trying to add to element %s",
pad_name, GST_ELEMENT_NAME (element));
GST_OBJECT_UNLOCK (element);
g_free (pad_name);
return FALSE;
}
no_direction:
{
GST_OBJECT_LOCK (pad);
g_critical
("Trying to add pad %s to element %s, but it has no direction",
GST_OBJECT_NAME (pad), GST_ELEMENT_NAME (element));
GST_OBJECT_UNLOCK (pad);
GST_OBJECT_UNLOCK (element);
return FALSE;
}
}
(2)gst_element_remove_pad()
从element中移除一个pad,这个函数确保pad被正确地从元素中分离,并触发相关的信号和清理操作
gboolean
gst_element_remove_pad (GstElement * element, GstPad * pad)
{
GstPad *peer;
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
/* locking pad to look at the name and parent */
GST_OBJECT_LOCK (pad);
GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element, "removing pad '%s'",
GST_STR_NULL (GST_PAD_NAME (pad)));
// 检查pad是否属于该元素
if (G_UNLIKELY (GST_PAD_PARENT (pad) != element))
goto not_our_pad;
GST_OBJECT_UNLOCK (pad);
/* unlink */
// 如果pad有对等pad,需要先解锁连
if ((peer = gst_pad_get_peer (pad))) {
/* window for MT unsafeness, someone else could unlink here
* and then we call unlink with wrong pads. The unlink
* function would catch this and safely return failed. */
if (GST_PAD_IS_SRC (pad))
gst_pad_unlink (pad, peer);
else
gst_pad_unlink (peer, pad);
gst_object_unref (peer);
}
/* if this is a ghost pad we also need to unset the target or it
* will stay linked although not allowed according to the topology.
*
* FIXME 2.0: Do this generically somehow from inside GstGhostPad
* when it gets unparented.
*/
// 如果pad是一个ghost pad,清除其目标pad
if (GST_IS_GHOST_PAD (pad)) {
gst_ghost_pad_set_target (GST_GHOST_PAD (pad), NULL);
}
GST_OBJECT_LOCK (element);
/* remove it from the list */
// 从对应链表中删除
switch (gst_pad_get_direction (pad)) {
case GST_PAD_SRC:
element->srcpads = g_list_remove (element->srcpads, pad);
element->numsrcpads--;
break;
case GST_PAD_SINK:
element->sinkpads = g_list_remove (element->sinkpads, pad);
element->numsinkpads--;
break;
default:
g_critical ("Removing pad without direction???");
break;
}
element->pads = g_list_remove (element->pads, pad);
element->numpads--;
element->pads_cookie++;
GST_OBJECT_UNLOCK (element);
/* emit the PAD_REMOVED signal before unparenting and losing the last ref. */
// 触发PAD_REMOVED信号,通知其他部分pad已被移除
g_signal_emit (element, gst_element_signals[PAD_REMOVED], 0, pad);
GST_TRACER_ELEMENT_REMOVE_PAD (element, pad);
gst_object_unparent (GST_OBJECT_CAST (pad));
return TRUE;
/* ERRORS */
not_our_pad:
{
/* locking order is element > pad */
GST_OBJECT_UNLOCK (pad);
GST_OBJECT_LOCK (element);
GST_OBJECT_LOCK (pad);
g_critical ("Padname %s:%s does not belong to element %s when removing",
GST_DEBUG_PAD_NAME (pad), GST_ELEMENT_NAME (element));
GST_OBJECT_UNLOCK (pad);
GST_OBJECT_UNLOCK (element);
return FALSE;
}
}
(3)gst_element_no_more_pads()
不期望在element中添加新的pads
void
gst_element_no_more_pads (GstElement * element)
{
g_return_if_fail (GST_IS_ELEMENT (element));
// 发布信号,元素不再添加新的pads
g_signal_emit (element, gst_element_signals[NO_MORE_PADS], 0);
}
2.3 element的默认操作
(1)gst_element_constructed
构造element
static void
gst_element_constructed (GObject * object)
{
GST_TRACER_ELEMENT_NEW (GST_ELEMENT_CAST (object));
G_OBJECT_CLASS (parent_class)->constructed (object);
}
(2)gst_element_dispose
GstElement类的对象销毁方法,用于在元素被销毁时释放其引用,通常会在对象的引用计数降为0时调用
static void
gst_element_dispose (GObject * object)
{
GstElement *element = GST_ELEMENT_CAST (object);
GstClock **clock_p;
GstBus **bus_p;
GstElementClass *oclass;
GList *walk;
oclass = GST_ELEMENT_GET_CLASS (element);
GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "%p dispose", element);
// 检查element的状态
if (GST_STATE (element) != GST_STATE_NULL)
goto not_null;
/* start by releasing all request pads, this might also remove some dynamic
* pads */
// 遍历element中的pads
walk = element->pads;
while (walk) {
GstPad *pad = GST_PAD_CAST (walk->data);
walk = walk->next;
if (oclass->release_pad && GST_PAD_PAD_TEMPLATE (pad) &&
GST_PAD_TEMPLATE_PRESENCE (GST_PAD_PAD_TEMPLATE (pad))
== GST_PAD_REQUEST) {
GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
"removing request pad %s:%s", GST_DEBUG_PAD_NAME (pad));
// 释放pad
oclass->release_pad (element, pad);
/* in case the release_pad function removed the next pad too */
if (walk && g_list_position (element->pads, walk) == -1)
walk = element->pads;
}
}
/* remove the remaining pads */
// 清理剩余没有清理完的pads
while (element->pads) {
GstPad *pad = GST_PAD_CAST (element->pads->data);
GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
"removing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
if (!gst_element_remove_pad (element, pad)) {
/* only happens when someone unparented our pad.. */
g_critical ("failed to remove pad %s:%s", GST_DEBUG_PAD_NAME (pad));
break;
}
}
GST_OBJECT_LOCK (element);
clock_p = &element->clock;
bus_p = &element->bus;
// 将clock和bus设置为NULL
gst_object_replace ((GstObject **) clock_p, NULL);
gst_object_replace ((GstObject **) bus_p, NULL);
// 清理上下文
g_list_free_full (element->contexts, (GDestroyNotify) gst_context_unref);
element->contexts = NULL;
GST_OBJECT_UNLOCK (element);
GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "%p parent class dispose",
element);
G_OBJECT_CLASS (parent_class)->dispose (object);
return;
/* ERRORS */
not_null:
{
gboolean is_locked;
is_locked = GST_ELEMENT_IS_LOCKED_STATE (element);
g_critical
("\nTrying to dispose element %s, but it is in %s%s instead of the NULL"
" state.\n"
"You need to explicitly set elements to the NULL state before\n"
"dropping the final reference, to allow them to clean up.\n"
"This problem may also be caused by a refcounting bug in the\n"
"application or some element.\n",
GST_OBJECT_NAME (element),
gst_element_state_get_name (GST_STATE (element)),
is_locked ? " (locked)" : "");
return;
}
}
(3)gst_element_finalize
finalize用于释放对象所占用的所有资源,例如内存、文件句柄等,只会被调用一次
static void
gst_element_finalize (GObject * object)
{
GstElement *element = GST_ELEMENT_CAST (object);
GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "%p finalize", element);
// 清理状态信号
g_cond_clear (&element->state_cond);
// 清理状态锁
g_rec_mutex_clear (&element->state_lock);
GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "%p finalize parent",
element);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
(4)gst_element_change_state_func
状态转换函数
/* is called with STATE_LOCK */
static GstStateChangeReturn
gst_element_change_state_func (GstElement * element, GstStateChange transition)
{
GstState state, next;
GstStateChangeReturn result = GST_STATE_CHANGE_SUCCESS;
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE);
// 获取当前状态和下一个状态
state = (GstState) GST_STATE_TRANSITION_CURRENT (transition);
next = GST_STATE_TRANSITION_NEXT (transition);
/* if the element already is in the given state, we just return success */
// 如果下一个状态为pending,或者当前状态与下一个状态一致,不需要修改状态
if (next == GST_STATE_VOID_PENDING || state == next)
goto was_ok;
GST_CAT_LOG_OBJECT (GST_CAT_STATES, element,
"default handler tries setting state from %s to %s (%04x)",
gst_element_state_get_name (state),
gst_element_state_get_name (next), transition);
// 检查状态转换情况
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
// gstreamer中的状态变换,从null -> ready -> paused -> playing
// 从ready到paused,需要激活pads,表示元素已准备好处理数据,但不会主动推送数据
if (!gst_element_pads_activate (element, TRUE)) {
result = GST_STATE_CHANGE_FAILURE;
}
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
case GST_STATE_CHANGE_READY_TO_NULL:{
GList *l;
/* deactivate pads in both cases, since they are activated on
ready->paused but the element might not have made it to paused */
// 将pads设置为FALSE,表示不再接收数据
if (!gst_element_pads_activate (element, FALSE)) {
result = GST_STATE_CHANGE_FAILURE;
}
/* Remove all non-persistent contexts */
// 移除所有非持久的上下文
GST_OBJECT_LOCK (element);
for (l = element->contexts; l;) {
GstContext *context = l->data;
if (!gst_context_is_persistent (context)) {
GList *next;
gst_context_unref (context);
next = l->next;
element->contexts = g_list_delete_link (element->contexts, l);
l = next;
} else {
l = l->next;
}
}
GST_OBJECT_UNLOCK (element);
break;
}
default:
/* this will catch real but unhandled state changes;
* can only be caused by:
* - a new state was added
* - somehow the element was asked to jump across an intermediate state
*/
g_warning ("Unhandled state change from %s to %s",
gst_element_state_get_name (state),
gst_element_state_get_name (next));
break;
}
return result;
was_ok:
{
GST_OBJECT_LOCK (element);
result = GST_STATE_RETURN (element);
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
"element is already in the %s state",
gst_element_state_get_name (state));
GST_OBJECT_UNLOCK (element);
return result;
}
}
(5)gst_element_query
处理元素的查询操作,可以查询流的持续事件、查询支持的格式、请求定位操作等
gboolean
gst_element_query (GstElement * element, GstQuery * query)
{
GstElementClass *klass;
gboolean res = FALSE;
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
g_return_val_if_fail (query != NULL, FALSE);
GST_TRACER_ELEMENT_QUERY_PRE (element, query);
klass = GST_ELEMENT_GET_CLASS (element);
if (klass->query) {
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "send query on element %s",
GST_ELEMENT_NAME (element));
// 发送问询
res = klass->query (element, query);
}
GST_TRACER_ELEMENT_QUERY_POST (element, query, res);
return res;
}
(6)gst_element_send_event
向元素发送事件,事件用于在管道pipeline中传递控制信息或通知,例如事件可以用于执行定位操作、发送EOS信号、处理流的重构等
gboolean
gst_element_send_event (GstElement * element, GstEvent * event)
{
GstElementClass *oclass;
gboolean result = FALSE;
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
oclass = GST_ELEMENT_GET_CLASS (element);
GST_STATE_LOCK (element);
if (oclass->send_event) {
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "send %s event on element %s",
GST_EVENT_TYPE_NAME (event), GST_ELEMENT_NAME (element));
// 发送事件
result = oclass->send_event (element, event);
} else {
gst_event_unref (event);
}
GST_STATE_UNLOCK (element);
return result;
}
(7)gst_element_post_message
将消息发布到元素的总线。这个函数可以将元素消息传递给应用程序,应用程序可以通过监听总线来接收这些消息
gboolean
gst_element_post_message (GstElement * element, GstMessage * message)
{
GstElementClass *klass;
gboolean res = FALSE;
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
g_return_val_if_fail (message != NULL, FALSE);
GST_TRACER_ELEMENT_POST_MESSAGE_PRE (element, message);
klass = GST_ELEMENT_GET_CLASS (element);
if (klass->post_message) // 发布消息到总线
res = klass->post_message (element, message);
else
gst_message_unref (message);
GST_TRACER_ELEMENT_POST_MESSAGE_POST (element, res);
return res;
}
在上面的函数中,使用了许多的函数指针,例如klass->post_message(),这些函数的赋值在各自的element中给出