媒体能力协商
Posted on Sun 10 December 2023 in Journal
Abstract | GStreamer 媒体能力协商 |
---|---|
Authors | Walter Fan |
Category | learning note |
Status | v1.0 |
Updated | 2023-12-10 |
License | CC-BY-NC-ND 4.0 |
概述
在 GStreamer 中, 媒体能力协商 Capabilities negotiation (缩写为 Caps negotiation) 是一个决策的过程,用来决定在 GStreamer 管道中数据流采用何种合适的媒体格式。
GStreamer 的文档 Negotiation 中对这一块有详细的解释, 在此我做些翻译和记录
有些元件有相对固定的媒体能力,有些元件则比较灵活,有些则不那么灵活。理想情况下,媒体能力协商(Capabilities negotiation) 信息将从管道中具有媒体能力的那些元件,传送到管道中相对灵活的那部分元件中,并受到管道中并不灵活的那部分元件的约束。
基本规则
以下的基本规则需要遵守
- 下游元件建议格式
- 上游元件决定格式
在 caps negotiation 中有四种 queries/events
GST_QUERY_CAPS
: 获取可能的 CapsGST_QUERY_ACCEPT_CAPS
: 检查 Caps 是否可行GST_EVENT_CAPS
: 配置 Caps(下游)GST_EVENT_RECONFIGURE
: 通知上游可用的新 Caps
查询 Queries
一个 pad 可以询问其所连接的 pad 它是不是支持某种格式 GstCaps
, 这就是 CAPS query。 支持的 caps 列表可用于为数据传输选择合适的 GstCaps
。
CAPS 查询以递归方式工作,元件在构建可能的 caps 时应考虑其对等元件。 由于结果 caps 可能非常大,因此可以使用过滤器 capsfilter 来限制 caps。 只有与过滤器匹配的 caps 才会作为结果 caps 返回。 过滤器caps 的顺序的按照调用者的优先顺序给出,并考虑下游元件所返回的 caps。
filter
(in)GST_TYPE_CAPS
(默认为 NULL):- 用于过滤结果的GstCaps
caps
(out)GST_TYPE_CAPS
(默认 NULL): - 查询到的 Caps 结果
pad 可以询问对等 pad 是否支持给定的 caps 。 它通过 ACCEPT_CAPS
查询来执行此操作, 这个返回的Caps 是固定。 “ACCEPT_CAPS”查询不需要递归地工作,如果具有这些 caps 的后续 CAPS 事件返回成功,它可以简单地返回 TRUE。
caps
(in)GST_TYPE_CAPS
:- 要检查的GstCaps
,它是固定的值result
(out)G_TYPE_BOOLEAN
(默认 FALSE): - 如果 Caps 被接受 则为 TRUE
事件 Events
当一个媒体格式协商成功,对端的元件就会以 CAPS 事件发送通知, 此 Caps 是固定的
caps
GST_TYPE_CAPS
: - 协商的GstCaps
, 它必须是固定的
操作 Operation
GStreamer 的两种调度模式(推模式和拉模式)适用于不同的机制来实现此目标。 由于推模式更常见,我们先描述推模式协商 Push-mode negotiation。
Push-mode negotiation
当一个元件想要推送缓冲区并且需要决定媒体格式时,就会发生推送模式协商。 这称为下游协商 (downstream negotiation),因为上游元件决定下游元件的格式。 这是最常见的情况。
当下游元件想要从上游元件接收另一种数据格式时,也可能发生协商。 这称为上游协商。
协商的基本过程如下:
-
GstCaps
(see caps) are refcounted before they are pushed as an event to describe the contents of the following buffer. GstCaps 用来描述媒体数据的内容 ,它会作为一个事件重新进行引用计数,然后发送给相连的元件 -
一个元件在处理数据缓冲之前收到 CAPS 事件,它可以重新更改 (reconfigure) 自己的配置为新的媒体格式。如果这个 caps 事件的数据类型不可接受,此元件可以拒绝这个 caps 事件,它同时也会拒绝接下来的数据缓冲,方法是在
chain
函数中返回GST_FLOW_NOT_NEGOTIATED
-
下游的元件可通过发送
GST_FLOW_NOT_NEGOTIATED
事件给上游的元件要求媒体流的格式更改
一个 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
一个 sink pad 开始重新协商的一般流程如下,还是讨价还价, 只不过这回发起的是买方(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
| |
参考资料
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。