注:这里同样是以gstreamer 1.8.1为蓝本
在gstreamer中GstElement的状态定义如下:
typedef enum {
GST_STATE_VOID_PENDING = 0,
GST_STATE_NULL = 1,
GST_STATE_READY = 2,
GST_STATE_PAUSED = 3,
GST_STATE_PLAYING = 4
} GstState;
gstreamer的每一个element当中都有一个状态机,不过比较有意思的一点是: gstreamer中使用枚举变量的方式定义好了状态之间的转换关系(或者叫状态转换映射),其枚举定义如下:
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
} GstStateChange;
由上面的定义可以看出,gstreamer的element从初始的NULL状态,到正确运行时的PLAYING状态的过程是:
而从PLAYING状态到NULL状态就正好是上面过程的一个反向过程:
* 接下来就来看一下一下这些状态变换过程当中,元件都需要做些什么工作:*
A. GST_STATE_CHANGE_NULL_TO_READY: 状态从NULL变为READY
B. GST_STATE_CHANGE_READY_TO_PAUSED:状态从READY变为PAUSED
C. GST_STATE_CHANGE_PAUSED_TO_PLAYING:状态从PAUSED变为PLAYING
D. GST_STATE_CHANGE_PLAYING_TO_PAUSED:状态从PLAYING变为PAUSED
E. GST_STATE_CHANGE_PAUSED_TO_READY:状态从PAUSED变为READY
F. GST_STATE_CHANGE_READY_TO_NULL:状态从READ变为NULL
GstElement的API中提供了一个名为gst_element_set_state接口来实现元件的状态设置功能,其定义为:
GstStateChangeReturn gst_element_set_state (GstElement * element, GstState state)
{
GstElementClass *oclass;
GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE);
oclass = GST_ELEMENT_GET_CLASS (element);
if (oclass->set_state)
result = (oclass->set_state) (element, state);
return result;
}
在其函数注释当中有一条特别的(完整注释请看源代码或参考文档):
/**
* .....
* State changes to %GST_STATE_READY or %GST_STATE_NULL never return
* #GST_STATE_CHANGE_ASYNC.
*/
大概意思就是,在将状态设置为READY或NULL时不会异步完成,而是会同步完成,在具体应用中可能需要注意这一点。
从函数的定义(实现)可以看出,这个接口其实只是起到封装作用,实际调用的是GstElementClass中的set_state成员方法,这也是一个“虚函数”,子类可以重实现这个接口,其默认实现为GstElement中的gst_element_set_state_func函数,定原型如下:
static GstStateChangeReturn gst_element_set_state_func (GstElement * element, GstState state)
因为此函数的代码较多,就不完全贴出来了,可以到gstreamer源代码中去查看。
在说gst_element_set_state_func函数的具体实现之前,有必要先说明一下GstElement结构体中关于状态信息的几个变量:
target_state :应用程序(Element的使用者)向元件设置的目标状态;
current_state :元件的当前状态;
next_state :
元件的下一个状态,如果元件已经处于正确的状态了,这个成员可以被设置为GST_STATE_VOID_PENDING
pending_state :
元件将要到达的最终状态,如果元件已经处于正确的状态了,这个成员可以被设置为GST_STATE_VOID_PENDING
在这里可能会比较疑惑,target_state与next_state以及pending_state有什么区别或关联,要区分它们,就先要了解gsteamer中状态设置的特点。
在一般的状态机里,定义好状态转换规则之后,如果设置下来的目标状态是无法到达的状态,那么就会返回失败,例如:
已经定义好了状态 A,B,C,D的装换规则了:
假设当前状态为A,如果上层这个时候想将状态设置为C,对于一般的状态机来说,这是不允许的是会出错的,因为状态A只能转换到状态B。
这一点在gstreamer中的状态机就不会返回错误,而是在可能的情况下一步一步转换到目标状态,还是以上面的例子为例,在转换之前:
注: -1 表示无效状态
然后转换过程为:
if (target_state > current_state)
{
next_state = current_state + 1
}
else if (target_state < current_state)
{
next_state = current_state - 1;
}
else
{
next_state = current_state;
}
3、将状态转换到next_state,其结果为current_state = next_state (这里应该就是状态B)
4、判断 current_state是否等于 pending_state? 如果不等,回到第二部,再次走一遍步骤2,3,4,如果相等,表示完成状态切换需求,将pending_state与next_state重新置为-1.
首先是gst_element_set_state_func函数(只贴出主要代码)
static GstStateChangeReturn
gst_element_set_state_func (GstElement * element, GstState state)
{
//首先判断传入的是否是一个Element的handle
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE);
//为整个状态变换过程加锁
GST_STATE_LOCK (element);
//为状态计算加锁
GST_OBJECT_LOCK (element);
//获取上一次状态变换的返回值,如果失败了,就会清空所有pending和next 状态
//也就是说,结束本次状态变换。
old_ret = GST_STATE_RETURN (element);
//获取当前,下一个以及pending的状态
current = GST_STATE (element);
next = GST_STATE_NEXT (element);
old_pending = GST_STATE_PENDING (element);
//state是需要转换过去的新状态,TARGET是上一次转换到的状态
if (state != GST_STATE_TARGET (element)) {
GST_STATE_TARGET (element) = state; //设置新的目标状态
/* increment state cookie so that we can track each state change. We only do
* this if this is actually a new state change. */
element->state_cookie++;
}
GST_STATE_PENDING (element) = state; //设置新的等待状态
/* if the element was busy doing a state change, we just update the
* target state, it'll get to it async then. */
if (old_pending != GST_STATE_VOID_PENDING) {
/* upwards state change will happen ASYNC */
if (old_pending <= state)
goto was_busy;
/* element is going to this state already */
else if (next == state)
goto was_busy;
/* element was performing an ASYNC upward state change and
* we request to go downward again. Start from the next pending
* state then. */
else if (next > state
&& GST_STATE_RETURN (element) == GST_STATE_CHANGE_ASYNC) {
current = next;
}
}
next = GST_STATE_GET_NEXT (current, state); //获取下一个状态
/* now we store the next state */
GST_STATE_NEXT (element) = next;
//如果当前状态和下一个状态不同,那么就打上一个标记,表示元件正在一步的
//变换状态
if (current != next)
GST_STATE_RETURN (element) = GST_STATE_CHANGE_ASYNC;
//得到下一个状态变化的命令或信号,就是GstStateChange定义的内容
transition = (GstStateChange) GST_STATE_TRANSITION (current, next);
/* now signal any waiters, they will error since the cookie was incremented */
GST_STATE_BROADCAST (element);
GST_OBJECT_UNLOCK (element);
//真正的转换状态,内部会去调用元件的虚函数change_state来执行元件状态
//变化具体要做的事情(如。初始化元件调用的第三方库等),并根据 change_state
//函数的返回值决定接下来的行为
ret = gst_element_change_state (element, transition);
GST_STATE_UNLOCK (element);
}
接下来就是上面函数中调用到的gst_element_change_state函数:
GstStateChangeReturn
gst_element_change_state (GstElement * element, GstStateChange transition)
{
/* call the state change function so it can set the state */
if (oclass->change_state)
ret = (oclass->change_state) (element, transition);
else
ret = GST_STATE_CHANGE_FAILURE;
switch (ret) {
case GST_STATE_CHANGE_FAILURE: //状态转换失败
/* state change failure */
gst_element_abort_state (element);
break;
case GST_STATE_CHANGE_ASYNC:
{
target = GST_STATE_TARGET (element); //获取需要变换到的最终目标状态
//因为 gstreamer中规定变换到READY或NULL状态不会异步进行,所以这里需要判断
//如果目标状态是在READY之上,那么就返回,让元件去异步变换状态。
if (target > GST_STATE_READY)
goto async;
//如果目标状态是READY或NULL,那么就会调用gst_element_continue_state继续
//进行状态变换,这个函数中会再次去计算下一个状态是什么,最终得到
// GstStateChange中定义的相应的枚举变量,然后再嵌套调用
// gst_element_change_state再次让元件去做状态变换
ret = gst_element_continue_state (element, GST_STATE_CHANGE_SUCCESS);
}
break;
case GST_STATE_CHANGE_SUCCESS://状态变换成功,继续进行下一次状态变换
ret = gst_element_continue_state (element, ret);
break;
case GST_STATE_CHANGE_NO_PREROLL:
/*he state change succeeded but the element
* cannot produce data in %GST_STATE_PAUSED.
* This typically happens with live sources. */
//上面这段是定义此返回值的注释,大概就是,状态变换成功了,但是元件还不能产生
//数据, 而这个状态就是PAUSED,一般在播放直播源的时候会出现这个返回值。
ret = gst_element_continue_state (element, ret);
break;
default:
goto invalid_return;
}
async:
return ret;
/* ERROR */
invalid_return:
/* we are in error now */
ret = GST_STATE_CHANGE_FAILURE;
GST_STATE_RETURN (element) = ret;
GST_OBJECT_UNLOCK (element);
return ret;
}