GStreamer随笔4 - 状态

前言

        基于Element的Pipeline创建后,接下来就需要控制Pipeline来工作。Element和Pipeline在不同的播放阶段有不同的状态,理解他们的状态及相关变化过程多深入理解GStreamer有重要的意义。


一、状态类型

        创建元素后,它实际上不会执行任何操作,您需要更改元素状态才能使其执行某些操作。element和pad都可以处于不同的状态,pad的状态与element的状态相关联,因此状态的设计主要围绕element的状态进行。一个element可以有 4 种状态:NULL、READY、PAUSED和PLAYING

        (1) - GST_STATE_NULL:这是默认状态,此状态下不分配任何资源。因此当pipeline转换到此状态时将释放所有资源。元素的引用计数达到 0 时必须处于此状态,然后才会被释放。
        (2) - GST_STATE_READY:在就绪状态下,元素已分配其所有全局资源,即可以保留在流中的资源。您可以考虑打开设备、分配缓冲区等。但是,流在此状态下未打开,因此流位置自动为0。如果之前打开过流,则应在此状态下关闭它,并重置位置、属性等。
        (3) - GST_STATE_PAUSED:在此状态下,元素已打开流但并未主动处理它。一旦状态更改为 PLAYING,元素就可以修改流的位置、读取和处理数据等,以准备播放,但不允许播放会使时钟运行的数据。总之,PAUSED 与 PLAYING 相同,但没有运行时钟。进入 PAUSED 状态的元素应尽快准备好进入 PLAYING 状态。例如,视频或音频输出将等待数据到达并对其进行排队,以便在状态更改后立即播放。视频接收器已经可以播放第一帧,但是大多数其他元素(例如编解码器或过滤器)不需要在此状态下明确执行任何操作。
        (4) - GST_STATE_PLAYING:在播放状态下,此时时钟开始运行。

二、状态迁移

GStreamer element的4种状态有以下几种状态迁移关系:

  1. NULL -> READY
    1. element需要检查所需的资源是否可以获得,设备型的sink和source一般会尝试检测设备来确定pads的约束参数。
    2. 如果时候设备型的element,需要打开设备。
  2. READY -> PAUSED
    1. element的pads将被激活,这样在PAUSED状态就能接收数据。streaming线程将启动。
    2. 有的element需要在信息充分的时候返回ASYNC,完成状态迁移。如果是sink element,当它接收到第一个buffer或者EOS事件(preroll)时候,是必须要返回ASYNC来完成状态迁移的。sink在PAUSED状态时还会阻塞数据流。
    3. pipeline需要把 running_time重置为0。
    4. 对于实时的source需要返回NO_PREROLL,并且不再产生数据。
  3. PAUSED -> PLAYING
    1. 绝大部分element将忽略这个状态改变
    2. pipeline需要选择一个clock并且分发给所有的子element,然后才能将它们设置成PLAYING状态。 只允许在PLAYING状态中同步时钟
    3. pipeline根据选择的clock和running_time 来计算 base_time,将base_time分发给pipeline的所有子element。
    4. sink element不再阻塞于preroll buffer或者事件,而开始渲染数据。
    5. sink element开始在PLAYING状态发出EOS消息,非PLAYING状态是不允许发送EOS消息的。
    6. 当在PAUSED 或者 PLAYING状态的时候,element是可以创建和移除sometime类型的pad。
    7. 实时的source开始生产数据,并返回SUCCESS。
  4. PLAYING -> PAUSED
    1. 绝大部分element将忽略这个状态改变。
    2. pipeline根据最后一次选择的clock和base_time 计算出running_time,存起来方便下次回到PLAYING状态的时候继续播放。
    3. sink解除所有等待clock的阻塞调用。
    4. 当sink没有待播放的缓冲区时,它会从此状态更改并返回ASYNC,在接收到新缓冲区或 EOS 事件时完成状态更改。
    5. 删除队列中所有的EOS消息,因为下次回到PLAYING状态的时候它们会重发的。EOS消息都是在Gstbin里排队的。
    6. 实时的source停止生产数据,返回NO_PREROLL.
  5. PAUSED -> READY
    1. sink解除阻塞在preroll中的任何等待,element解除阻塞在设备的任何等待。
    2. Chain 或 get_range()函数返回FLUSHING。
    3. element pad被停用,因此流传输变得不可能并且所有流传输线程都停止。
    4. sink清除所有协商的格式,element删除所有sometimes pads。
  6. READY -> NULL
    1. element关闭设备并重置任何内部状态。

三、状态控制

3.1 状态设置

         您可以使用函数 gst_element_set_state() 更改元素的状态。如果您将元素设置为另一个状态,GStreamer 将在内部遍历所有中间状态(如果您将元素从 NULL 设置为 PLAYING,GStreamer 将在内部将元素设置为 READY 和 PAUSED)。

        当状态转换到 GST_STATE_PLAYING 时,pipeline将自动处理数据,它们不需要以任何形式进行迭代。在内部,GStreamer 将启动为它们执行此任务的线程。GStreamer 还将使用 aGstBus 负责将消息从管道的线程切换到应用程序自己的线程。

        当您将 bin 或管道设置为某个目标状态时,它通常会自动将状态更改传播到 bin 或管道内的所有元素,因此通常只需要设置顶级管道的状态即可启动或关闭管道。但是,当动态地将元素添加到已经运行的管道时,例如从“pad-added”信号回调中,您需要使用 gst_element_set_state () 或 gst_element_sync_state_with_parent () 自行将其设置为所需的目标状态。 gst_element_set_state()函数的返回值能如下:

  • GST_STATE_FAILURE: 由于某种原因状态更改失败。该插件应该已经在总线上发布了一条包含错误信息的消息。
  • GST_STATE_SUCCESS:状态更改成功完成。
  • GST_STATE_ASYNC:状态更改将在稍后完成。当element需要很长时间来执行状态更改或需要接收第一个缓冲区才能完成状态更改(preroll)时,可能会发生这种情况。
  • 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,这个结果会立即返回给调用者。

3.2 状态获取

        gst_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还应在总线上发布一条错误消息,其中包含有关该问题的更多信息。

总结

       状态是核心,但是再底层的细节需要自己扒,用的时候再说……

猜你喜欢

转载自blog.csdn.net/yong_i7/article/details/141505677