Gstreamer- 状态(states)

状态

element和pad都可以处于不同的状态。pad的状态与element的状态相关联,因此状态的设计主要围绕element的状态进行。
一个element可以有 4 种状态。NULL、READY、PAUSED和PLAYING。当一个element最初被实例化时,它处于 NULL 状态。

状态定义

  • NULL:这是element的初始状态。
  • READY: element应该为PAUSED状态做好准备。
  • PAUSED:element应该准备好接收和处理数据。然而,sink element只接收一个缓冲区然后阻塞。
  • PLAYING:和PAUSED状态相同,除live sources和sink外。sink接收并渲染数据。live source产生数据。

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

状态转换

以下状态更改是可能的:

  • NULL -> READY:
    • element必须检查它需要的资源是否可用。Device sink和 source 通常会尝试探测设备以限制其caps。
    • element打开设备,如果上一步需要打开设备,则这一步是需要的。
  • READY -> PAUSED:
    • element pad被激活以在PAUSED状态中接收数据。流线程已启动。
    • 某些element可能会返回ASYNC,它们需要有足够的信息才能完成状态更改。对于sink必须返回ASYNC,并在接收到第一个缓冲区或 EOS 事件(预卷)时,并完成状态更改。sink在PAUSED状态中同时也会阻塞数据流。
    • pipeline将重置running_time为 0。
    • 实时源返回NO_PREROLL并且不产生数据。
  • PAUSED -> PLAYING:
    • 大多数element忽略此状态更改。
    • pipeline选择一个时钟并将其分配给所有子element,然后再将它们设置为PLAYING. 这意味着它只允许在PLAYING状态中同步时钟。
    • pipeline使用时钟和running_time来计算 base_time。这base_time在执行状态更改时分发给所有子element。
    • sink element停止在预卷缓冲 (preroll buffer)或事件上的阻塞并开始渲染数据。
    • sink可以在PLAYING状态中发布 EOS 消息。不在PLAYING状态时是不允许发布EOS的。
    • 当流处于PAUSED或PLAYING状态中时,element可以创建和删除sometimes pads。
    • Live sources 开始生成数据并返回SUCCESS.
  • PLAYING -> PAUSED:
    • 大多数element忽略此状态更改。
    • pipeline根据最后选择的时钟和base_time计算出 running_time. 它存储此信息以便在返回PLAYING状态时继续播放。
    • sink解除阻塞时钟等待调用。
    • 当sink没有待播放的缓冲区时,它会从此状态更改返回ASYNC,并在接收到新缓冲区或 EOS 事件时完成状态更改。
    • 任何已排队的 EOS 消息都将被删除,因为它们将在返回PLAYING状态时重新发布。EOS 消息在GstBins中排队。
    • live source 停止生成数据并返回NO_PREROLL。
  • PAUSED -> READY:
    • sink解除阻塞在预卷中的任何等待。
    • element解除阻塞在设备的任何等待
    • Chain 或get_range()函数返回FLUSHING。
    • element pad被停用,因此流传输变得不可能并且所有流传输线程都停止。
    • sink清除所有协商的格式
    • element删除所有sometimes pads
  • READY -> NULL:
    • element关闭设备
    • element重置任何内部状态。

状态变量

一个element有 4 个受对象 LOCK 保护的状态变量:

  • STATE(当前状态)
  • STATE_NEXT(下一状态)
  • STATE_PENDING(挂起状态)
  • STATE_RETURN(最后一次的调用返回值)

将STATE始终反映element的当前状态。在 STATE_NEXT反映下一个状态element会去。将 STATE_PENDING始终反映该element所请求的状态。该 STATE_RETURN反映的状态改变的最后一次的返回值。
如果该element处于正确状态,则STATE_NEXT和STATE_PENDING可以是VOID_PENDING值。
一个element有一个称为STATE_LOCK的特殊锁来防止并发调用set_state()。

在element上设置状态

可以使用_element_set_state() 更改element的状态。当更改element的状态时,所有中间状态也将在element上设置,直到设置最终所需的状态。
该set_state()函数可以返回 3 个可能的值:

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

在ASYNC状态更改的情况下,在当前状态更改完成之前,有可能继续到下一次状态更改,但是,element只会在完成前一个ASYNC状态更改之后才能进行下一次状态更改。。收到ASYNC返回值后,可以使用 element_get_state()轮询element的状态。如果轮询返回SUCCESS,则element使用 set_state()完成最后请求的状态更改。
设置element的状态时,将STATE_PENDING设置为所需的状态。然后调用element的状态更改函数,该函数的结果用于更新STATE 和STATE_RETURN字段、STATE_NEXT、STATE_PENDING和STATE_RETURN字段。如果函数返回ASYNC,这个结果会立即返回给调用者。

获取element状态

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

  • 如果element向前一个_set_state()函数返回SUCCESS,则该函数将返回当前状态为element上最后设置的状态,并返回挂起状态值为VOID_PENDING。函数返回GST_STATE_SUCCESS。
  • 如果element向前一个_set_state()函数返回NO_PREROLL,则此函数将返回当前状态为element上最后设置的状态,并返回挂起状态值为VOID_PENDING。函数返回GST_STATE_NO_PREROLL。
  • 如果element向前一个_set_state()函数返回FAILURE,则此函数将返回FAILURE,当前状态设置为element的当前状态,挂起状态设置为上次调用_set_state()中使用的值。
  • 如果element向前一个_set_state()函数返回ASYNC,则此函数将等待element完成其状态更改,直至达到设定的超时时间GstClockTime.
    • 如果element在指定的时间内没有完成状态更改,则此函数将返回ASYNC,当前状态设置为element的当前状态值,挂起状态设置为element的挂起状态值。
    • 如果element在指定的超时时间内完成状态更改,则此当前状态为函数返回更新后的状态并挂起状态值为VOID_PENDING。
    • 如果elementASYNC由于指定超时内的错误而中止状态更改,则此函数返回FAILURE,当前状态设置为上次成功状态和挂起设置为最后一次尝试。该element还应在总线上发布一条错误消息,其中包含有关该问题的更多信息。

GstBin 中的状态

GstBin管理其子element的状态。它通过将对其执行的状态更改传播到其所有子element来实现此目的。在 bin上调用 _set_state()函数同时会对那些尚未在目标状态或改变状态到目标状态的子element调用_set_state()函数,。

子element从sink element迭代到source element。这确保在更改element的状态时,下游element处于正确状态以处理最终缓冲区。在向下状态更改的情况下,sink element将首先关闭,这会使上游element也关闭,因为该_push()函数返回GST_FLOW_FLUSHING错误。

如果所有的子element都返回SUCCESS,函数SUCCESS也会返回。

如果其中一个子element返回FAILURE,则该函数也返回FAILURE。在这种状态下,一些element可能成功地改变了状态。应用程序可以通过迭代element和调用_get_state()来检查哪些element的状态发生了变化,哪些element发生了错误以及哪些element没有受到影响。

如果在对所有子element调用状态更改函数后,其中一个子节点返回ASYNC,则该函数也返回ASYNC。

如果在对所有子element调用状态更改函数后,其中一个子element返回NO_PREROLL,则该函数也返回NO_PREROLL。

如果返回NO_PREROLL和ASYNC的element都存在,则返回NO_PREROLL。

可以使用_get_state() 检索 bin 的当前状态。

如果 bin 正在执行异步(ASYNC)状态更改,它会在收到来自子element的状态消息时自动更新其当前状态字段。

在element中状态实现

向上状态变化

无论是否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
  • Bin:

    • A->B: all elements SUCCESS
      • commit state
    • A->B: some elements ASYNC
      • no commit state
      • listen for commit messages on bus
      • for each commit message, poll elements, this happens in another thread.
      • if no ASYNC elements, commit state, continue state change to STATE_PENDING
向下状态变化

向下状态更改仅在最终状态为ASYNC时才返回ASYNC。这是为了确保ASYNC当人们只想关闭一个element时,不需要等待element完成预卷或其他状态更改。

  • 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
  • Bin:
    • A -> B -> SUCCESS
      • commit state
    • A -> B -> ASYNC not final state
      • commit state on behalf of element, continue state change
    • A -> B => ASYNC final state
      • no commit state
      • listen for commit messages on bus
      • for each commit message, poll elements
      • if no ASYNC elements, commit state

Locking overview(element)

  • Element committing SUCCESS

    • STATE_LOCK is taken in set_state()

    • change state is called if SUCCESS, commit state is called

    • commit state calls change_state() to next state change.

    • if final state is reached, stack unwinds and result is returned to set_state() and caller.

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

    • STATE_LOCK is taken in set_state()

    • change state is called and returns ASYNC

    • ASYNC returned to the caller.

    • element takes LOCK in streaming thread.

    • element calls commit_state in streaming thread.

    • commit state calls change_state() to next state change.

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

备注

set_state()不能同时从多个线程调用。在 STATE_LOCK防止这一点。
状态变量受 LOCK 保护。
在调用get_state()的同时调用set_state()应该解锁get_state(),并报错。cookie可以做到。

set_state(element)

STATE_LOCK

LOCK
update current, next, pending state
cookie++
UNLOCK

change_state
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值