gstreamer的状态转换

gstreamer中,element和pad都可以处于不同的状态。 pad的状态与element的状态相关联,因此状态的设计主要集中在element状态。

一个element可以处于 4 种状态: NULL、READY、PAUSED 和 PLAYING。 当一个元素最初被实例化时,它处于NULL状态。

状态定义

gstreamer/gst/gstelement.h

typedef enum {
  GST_STATE_VOID_PENDING        = 0,
  GST_STATE_NULL                = 1,
  GST_STATE_READY               = 2,
  GST_STATE_PAUSED              = 3,
  GST_STATE_PLAYING             = 4
} GstState;
  • NULL:这是元素的初始状态。
  • READY:element应该准备好进入PAUSED
  • PAUSED:element应该准备好接受和处理数据。 但是,sink element只接受一个buffer然后阻塞。
  • PLAYING:与PAUSED相同,但live sources和sinks除外,sinks接受并render数据,Live sources 产生数据。

我们将序列 NULL→PLAYING 称为向上状态变化,将 PLAYING→NULL 称为向下状态变化。

状态转换

可能会发生以下状态更改:

NULL -> READY:

  • element必须检查它需要的资源是否可用。
  • Device sinksDevice sources通常会尝试探测设备以限制其上限。如果需要打开设备,则该元素就会打开设备。

READY -> PAUSED:

  • element pads被激活,以便在暂停状态下接收数据。Streaming线程这时候已启动。
  • 某些element可能需要在返回 ASYNC后有足够信息时才完成状态改变。当sink收到第一个缓冲区或 EOS 事件或者preroll事件时,需要返回 ASYNC并完成状态更改。当处于暂停状态时,sink也会阻塞数据流。
  • 管道将 running_time 重置为 0。
  • Live sources返回 NO_PREROLL 并且不生成数据。

PAUSED -> PLAYING:

  • 大多数element忽略此状态改变。
  • pipeline选择一个时钟并将其分配给所有子节点,然后再将它们设置为 PLAYING。这意味着它只允许在PLAYING状态下同步时钟。
  • pipeline使用clock和 running_time 来计算 base_time。在执行状态更改时,此 base_time 会分发给所有子节点。
  • sink elements在这个状态改变时会停止阻塞在preroll buffer或事件,并开始render数据。
  • sink可以在 PLAYING 状态下发布EOS 消息。不在PLAYING状态时不允许发布EOS
  • PAUSEDPLAYING 中流式传输时,可以创建和删除一些pad。
  • Live sources开始生成数据并返回 SUCCESS

PLAYING -> PAUSED:

  • 大多数元素忽略此状态改变。

  • pipeline根据最后选择的clock和 base_time 计算 running_time。它存储此信息以在返回到PLAYING 状态时继续播放。

  • sink取消阻塞任何clock wait调用。

  • 当sink没有待播放的buffer时,它会从此状态的改变返回 ASYNC,并在收到新buffer或 EOS 事件时完成状态更改。

  • 任何排队的 EOS 消息都将被删除,因为它们将在返回 PLAYING 状态时重新发布。 EOS 消息在 GstBins 中排队。

  • Live sources停止生成数据并返回NO_PREROLL

PAUSED -> READY:

  • Sinks取消block在preroll中的任何等待。
  • elements取消阻止devices上的任何等待。
  • chainget_range() 函数返回 FLUSHING
  • element pads被停用,因此无法进行流式处理,并且所有流式处理线程都被停止。
  • sink会忘记所有协商的格式
  • element删除所有sometimes pads

READY -> NULL:

  • element关闭devices。
  • element重置所有内部状态。

状态变量

#define GST_STATE(elem)                 (GST_ELEMENT_CAST(elem)->current_state)
#define GST_STATE_NEXT(elem)            (GST_ELEMENT_CAST(elem)->next_state)
#define GST_STATE_PENDING(elem)         (GST_ELEMENT_CAST(elem)->pending_state)
#define GST_STATE_TARGET(elem)          (GST_ELEMENT_CAST(elem)->target_state)
#define GST_STATE_RETURN(elem)          (GST_ELEMENT_CAST(elem)->last_return)

一个element有 5 个受object LOCK 保护的状态变量:

  • STATE

    • 总是反映元素的当前状态。
  • STATE_NEXT

    • 反映元素将进入的下一个状态。
  • STATE_PENDING

    • 始终反映元素将要达到的最终状态。当最终状态涉及经历多个状态更改时,这与 STATE_NEXT 不同,例如从 PLAYING -> NULL。
  • STATE_TARGET

    • 是应用程序设置的元素应该进入的最终状态。当元素进行状态转换时,在ASYNC状态更改期间,STATE_PENDING 可能与 STATE_TARGET 不同。
  • STATE_RETURN

    • 反映状态改变的最后一个返回值。

如果element已经处于正确状态,则 STATE_NEXT 和 STATE_PENDING 可以是 VOID_PENDING。

一个element有一个特殊的锁来防止 set_state() 的并发调用,称为 STATE_LOCK

在元素上设置状态

GST_API
GstStateChangeReturn    gst_element_set_state           (GstElement *element, GstState state);

可以使用 _element_set_state() 改变元素的状态。当改变一个元素的状态时,所有的中间状态也将被设置在元素上,直到最终的期望状态被设置。

set_state() 函数可以返回 3 个可能的值:

  • GST_STATE_FAILURE:状态改变由于某种原因失败。该插件应该已经在总线上发布了一条带有信息的错误消息。
  • GST_STATE_SUCCESS:状态改变成功完成。
  • GST_STATE_ASYNC:状态改变将在稍后完成。当元素需要很长时间来执行状态改变或需要接收第一个buffer才能完成状态改变(preroll)的sink时,可能会发生这种情况。
  • GST_STATE_NO_PREROLL:状态改变成功完成,但元素将无法在 PAUSED 状态下产生数据。

在 ASYNC 状态改变的情况下,可以在当前状态更改完成之前进入下一个状态,但是,element只会在完成前一个 ASYNC 状态更改之前进入下一个状态。收到 ASYNC 返回值后,可以使用 element_get_state() 来轮询元素的状态。如果轮询返回 SUCCESS,则element使用 set_state() 将状态更改为最后请求的状态。

设置element的状态时,将 STATE_PENDING 设置为所需的状态。然后调用element的状态更改函数,该函数的结果用于更新 STATE 和 STATE_RETURN 字段、STATE_NEXT、STATE_PENDING 和 STATE_RETURN 字段。如果函数返回 ASYNC,则此结果会立即返回给调用者。

获取元素的状态

get_state() 函数接受 3 个参数,两个指针将保存当前和pending状态,一个 GstClockTime 保存timeout值。该函数返回一个 GstElementStateReturn。

GST_API
GstStateChangeReturn    gst_element_get_state           (GstElement * element,
                                                         GstState * state,
                                                         GstState * pending,
                                                         GstClockTime timeout);
  • 如果element返回 SUCCESS 给之前的 set_state() 函数,则get_state函数将返回element上设置的最后一个状态或者pending状态值中的 VOID_PENDING。正常get_state函数返回 GST_STATE_SUCCESS

  • 如果element返回 NO_PREROLL 给之前的 set_state() 函数,则get_state函数将返回element上设置的最后一个状态以及挂起状态值中的 VOID_PENDING。正常get_state函数返回 GST_STATE_NO_PREROLL

  • 如果element返回 FAILURE 到先前的 _set_state() 调用,则get_state函数将返回 FAILURE,状态设置为element的当前状态,pending状态设置为最后一次调用 _set_state() 时使用的值。

  • 如果element将 ASYNC 返回到先前的 _set_state() 调用,则get_state函数将等待element完成其状态更改,直至 GstClockTime 中指定的时间量。

    • 如果element在指定时间内未完成状态更改,则get_state函数将返回 ASYNC,状态设置为当前状态,pending状态设置为pending状态。
    • 如果element在指定的超时时间内完成状态更改,则get_state函数返回更新后的状态和 VOID_PENDING 作为挂起状态。
    • 如果element在指定的超时时间内由于错误而中止 ASYNC 状态更改,则get_state函数返回 FAILURE,状态设置为最后一次成功状态,挂起设置为最后一次尝试。该元素还应该在总线上发布一条错误消息,其中包含有关该问题的更多信息。

在元素中实现状态

这部分理解的有点模糊

向上状态变化

无论是否达到 STATE_PENDING,向上状态改变总是返回 ASYNC

Element:
A -> B => SUCCESS
	commit state
A -> B => ASYNC
	no commit state
	element commits state ASYNC
A -> B while ASYNC
	update STATE_PENDING state
	no commit state
	no change_state() called on element
向下状态变化

如果最终状态为 ASYNC,则向下状态改变仅返回 ASYNC。 这是为了确保当您只想关闭一个element时,不需要等待一个element完成preroll或其他 ASYNC 状态改变。

Element:
A -> B => SUCCESS
	commit state
A -> B => ASYNC not final state
	commit state on behalf of element
A -> B => ASYNC final state
	element will commit ASYNC

Locking overview (element)

Element committing SUCCESS
  • set_state() 中获取 STATE_LOCK
  • 改变状态如果成功则调用commit state
  • commit state调用 change_state() 到下一个状态改变。
  • 如果达到最终状态,堆栈展开并将结果返回给 set_state() 和调用者。
set_state(element)       change_state (element)   commit_state
    |                         |                       |
    |                         |                       |
STATE_LOCK                    |                       |
    |                         |                       |
    |------------------------>|                       |
    |                         |                       |
    |                         | (do state change)     |
    |                         |                       |
    |                         | if `SUCCESS`            |
    |                         |---------------------->|
    |                         |                       | post message
    |                         |<----------------------| if (!final) change_state (next)
    |                         |                       | else SIGNAL
    |                         |                       |
    |<------------------------|                       |
    |     `SUCCESS`
STATE_UNLOCK
    |
  `SUCCESS`
Element committing ASYNC
  • set_state() 中获取 STATE_LOCK
  • 调用change state并返回 ASYNC
  • ASYNC 返回给调用者。
  • element在streaming线程中持有LOCK。
  • element在streaming线程中调用commit_state()
  • commit state调用 change_state() 到下一个状态改变。
set_state(element)       change_state (element)     stream_thread      commit_state (element)
    |                         |                          |                  |
STATE_LOCK                    |                          |                  |
    |                         |                          |                  |
    |------------------------>|                          |                  |
    |                         |                          |                  |
    |                         | (start_task)             |                  |
    |                         |                          |                  |
    |                         |                     STREAM_LOCK             |
    |                         |                          |...               |
    |<------------------------|                          |                  |
    |     ASYNC                                     STREAM_UNLOCK           |
STATE_UNLOCK                                             |                  |
    |                .....sync........               STATE_LOCK             |
  ASYNC                                                  |----------------->|
                                                         |                  |
                                                         |                  |---> post_message()
                                                         |                  |---> if (!final) change_state (next)
                                                         |                  |     else SIGNAL
                                                         |<-----------------|
                                                     STATE_UNLOCK
                                                         |
                                                    STREAM_LOCK
                                                         | ...
                                                    STREAM_UNLOCK

原始链接

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值