其他分享
首页 > 其他分享> > Gstreamer- 协商(Negotiation)

Gstreamer- 协商(Negotiation)

作者:互联网

协商

Capabilities 协商是为 GStreamer pipeline内的数据流决定适当格式的过程。理想情况下,协商(也称为“capsnego”)将信息从pipeline中具有信息的那些部分传输到pipeline的那些易扩展的部分,受pipeline中不易扩展部分的约束。

基本规则

必须遵循这些简单的规则:

  1. 下游建议格式
  2. 上游决定格式

caps协商中使用了 4 种 查询/事件(queries/events ):

  1. GST_QUERY_CAPS:获取可能的格式
  2. GST_QUERY_ACCEPT_CAPS:检查格式是否可行
  3. GST_EVENT_CAPS:配置格式(下游)
  4. GST_EVENT_RECONFIGURE:通知上游可能的新caps

查询

pad可以向peer pad询问其支持的 GstCaps。它通过 CAPS 查询完成此操作。支持的caps列表可用于为数据传输选择合适的 GstCap。 CAPS 查询以递归方式工作,element在构建可能的caps时应考虑其 peer element。由于结果caps可能非常大,因此可以使用过滤器来限制caps。只有与过滤器匹配的caps才会作为结果caps返回。过滤器caps的顺序给出了调用者的优先顺序,并且应该考虑到返回的caps。

pad可以询问peer pad 是否支持给定的caps。它通过 ACCEPT_CAPS 查询完成此操作。caps必须固定。 ACCEPT_CAPS 查询不需要递归工作,如果带有这些caps的后续 CAPS 事件返回成功,它可以简单地返回 TRUE。

事件

当协商媒体格式时,通过 CAPS 事件将 GstCaps 通知给peer element。caps必须固定。

操作

GStreamer 的两种调度模式,push 模式和 pull 模式,适用于不同的机制来实现这个目标。由于更常见,我们首先描述推模式协商。

推模式协商

当element想要推送缓冲区并需要决定格式时,会发生推模式协商。这称为下游协商,因为上游element决定下游element的格式。这是最常见的情况。

当下游element想要从上游element接收另一种数据格式时,也会发生协商。这称为上游协商。

协商的基本原则如下:

source pad开始协商的一般流程。

  src              sink
             |                 |
             |  querycaps?     |
             |---------------->|
             |     caps        |
select caps  |< - - - - - - - -|
from the     |                 |
candidates   |                 |
             |                 |-.
             |  accepts?       | |
 type A      |---------------->| | optional
             |      yes        | |
             |< - - - - - - - -| |
             |                 |-'
             |  send_event()   |
send CAPS    |---------------->| Receive type A, reconfigure to
event A      |                 | process type A.
             |                 |
             |  push           |
push buffer  |---------------->| Process buffer of type A
             |                 |

一种可能的实现方式的伪代码:

[element wants to create a buffer]
    if not format
      # see what we can do
      ourcaps = gst_pad_query_caps (srcpad)
      # see what the peer can do filtered against our caps
      candidates = gst_pad_peer_query_caps (srcpad, ourcaps)

    foreach candidate in candidates
      # make sure the caps is fixed
      fixedcaps = gst_pad_fixate_caps (srcpad, candidate)

    # see if the peer accepts it
    if gst_pad_peer_accept_caps (srcpad, fixedcaps)
      # store the caps as the negotiated caps, this will
      # call the setcaps function on the pad
      gst_pad_push_event (srcpad, gst_event_new_caps (fixedcaps))
      break
    endif
  done
endif

使用ALLOCATION 查询 协商 allocator/bufferpool

   buffer = gst_buffer_new_allocate (NULL, size, 0);
    # fill buffer and push

sink pad 开始重新协商的通用流程.

          src              sink
             |                 |
             |  accepts?       |
             |<----------------| type B
             |      yes        |
             |- - - - - - - - >|-.
             |                 | | suggest B caps next
             |                 |<'
             |                 |
             |   push_event()  |
 mark      .-|<----------------| send RECONFIGURE event
renegotiate| |                 |
           '>|                 |
             |  querycaps()    |
renegotiate  |---------------->|
             |  suggest B      |
             |< - - - - - - - -|
             |                 |
             |  send_event()   |
send CAPS    |---------------->| Receive type B, reconfigure to
event B      |                 | process type B.
             |                 |
             |  push           |
push buffer  |---------------->| Process buffer of type B
             |                 |

用例:

videotestsrc  ! xvimagesink
videotestsrc ! queue ! xvimagesink

拉模式协商

拉模式下的pipeline与推模式下激活的pipeline具有不同的协商需求。推模式针对两个用例进行了优化:

相比之下,拉模式还有其他典型用例:

[0] http://jackit.sf.net

拉模式的问题是sink必须知道格式才能知道通过 gst_pad_pull_range() 拉多少字节。这意味着在拉取之前,sink必须发起协商以决定格式。

回顾 capsnego 的原则,即信息必须从拥有它的部分流向没有它的部分,我们看到三个具名的用例具有不同的协商要求:

鉴于sink可能需要source的输入,就像在RTP的情况下一样,至少在合成的情况下作为过滤器,在拉线程被激活之前必须有一个协商阶段。此外,考虑到拉模式提供的低延迟,我们希望避免从拉线程内进行 capsnego,以防它导致我们错过我们的调度的最后期限。

拉线程一般是在PAUSED→PLAYING状态变化下开始的。我们必须能够在这种状态改变发生之前完成协商。

那么,执行 capsnego 的时间是在 SCHEDULING 查询成功之后,但在 sink 产生拉线程之前。

机制

sink通过执行 SCHEDULING 查询来确定上游element支持基于拉的调度。

sink通过将gst_pad_query_caps()从sink pad和 peer src pad获得的结果进行相交来启动协商过程。这个操作是由gst_pad_get_allowed_caps()执行。在简单的传递情况下,peer pad的caps查询应该返回在其所有sink pad上调用get_allowed_caps()的交集。通过这种方式,sink element知道整个pipeline的能力。

如有必要,sink element然后将结果caps固定,从而产生流的caps。从现在开始,sinkpad 的 caps 查询将只返回这些固定的 caps,这意味着上游element只能生成这种格式的数据。

如果sink element 无法在其sink pad上设置caps,则它应该在总线上发布一条错误消息,指示无法进行协商。

当协商成功时,sinkpad 和所有上游内部链接的pad 在pull 模式下被激活。通常,此操作将触发下游element的协商,现在将被迫协商到sink pad的最终固定所需caps。

在这些步骤之后,sink element从状态改变函数返回 ASYNC。当sink中接收到第一个缓冲区时,状态将提交到 PAUSED。这需要为期望从sink返回ASYNC值的应用程序提供一致的API ,但它也允许我们在拉动线程的上下文之外执行其余的协商。

模式

我们可以在协商中确定 3 种模式:

标签:Negotiation,协商,Gstreamer,element,pad,sink,caps,CAPS
来源: https://blog.csdn.net/zk5950886/article/details/118421374