使用GStreamer RTP的高比特率视频流

2020-08-25 18:45:28

RTP是低延迟音频和视频传输的主要协议。它位于广泛行业中使用的许多系统的核心,从WebRTC到SIP(IP电话),从RTSP(安全摄像头)到RIST和SMPTE ST 2022(广播电视后端)。

作为一个灵活的开源框架,GStreamer被用于各种应用程序。它的RTP堆栈已经在上述所有行业的多个用例中进行了战斗测试,使其具有能够将优化从一个用例应用到另一个用例的独特优势。毫无疑问,GStreamer拥有可用的最成熟、最完整的RTP协议栈之一。

额外的单元测试,以及对GStreamer RTP元素的关键修复和性能改进,最近已经在GStreamer 1.18中实现:

后者尤其提供了吞吐量的重要提升,为高比特率视频流打开了大门。

GStreamer的基本任务之一是将缓冲区从上游元素移动(推送)到下一个下游元素,从而使管道进展。

元件通过焊盘连接。对于每个可能的连接,每个元素都有一个焊盘,焊盘可以是元素用来输出缓冲区的源焊盘,也可以是用来输入缓冲区的信宿焊盘。要在两个元素之间创建连接,应用程序员需要将一个元素的源焊盘连接到另一个元素的宿焊盘。当一个元素希望将包含数据的缓冲区发送到下一个元素时,它会将其推送到其源垫上,然后源垫将其链接到调用下一个元素的宿垫。

元素用于推送缓冲区的基本工具是GST_PAD_PUSH函数:

缓冲区推送实际上是一系列复杂的函数调用和锁定,顺序如下:

信源焊盘在连接的信宿焊盘上进行参考(增加原子计数器)。

接收垫引用其父元素(第二个元素),这意味着它增加了原子计数器。

接收板调用第二个元素的链函数(元素的实际代码)。

源焊盘释放连接的宿焊盘上的基准(减少原子计数器)。

正如您从这个不完整的列表中看到的,缓冲区的每次传输,即使它发生在一个线程上,实际上都是一些互斥锁和其他原子操作,这些操作在现代流水线处理器上成本相对较高。分析GStreamer管道时,这实际上是传输大量小缓冲区时开销最大的部分。

GStreamer有一种称为缓冲区列表的机制,可用于减少推送单个缓冲区的开销。

缓冲器列表所做的是将多个缓冲器组合在一起,使得它们作为一个操作通过流水线转发,这可以显著降低该开销,因为上述操作序列将在每个列表中发生一次,而不是在每个缓冲器中发生一次。

如果某些元素不支持链接缓冲区列表,GStreamer提供了类似于GST_PAD_CHAIN_LIST_DEFAULT的回退机制,将缓冲区逐个推送到幕后。这意味着元素始终可以独立于其他元素中的支持级别实现列表中的处理缓冲区。

这对于兼容性很好,并且允许增量改进,但是,为了实际避免推送单个缓冲区的瓶颈,并且为了获得最大的性能改进,管道中的所有元素应该本机支持链接缓冲区列表(即在接收器垫上安装它们自己的链列表函数)。

RFC 3550中描述的RTP规范定义了一组规则,用于在使用RTP的会话期间关联参与者,这称为RTP会话。

Rtpsession元素已在其发送路径中支持缓冲区列表,但在其接收路径中不支持。

Gst-Launch-1.0-e\rtpsession name=rtpsess\Videotestsrc!ImageFreeze Num-Buffers=10000!视频/x-RAW,格式=RGB,宽度=320,高度=240!Rtpvrawpay!Rtpsess.recv_rtp_ink rtpsess.recv_rtp_src!FAKEKINK Async=FALSE SYNC=FALSE。

生成测试流(在本例中,ImageFreeze用于减少CPU使用量),将其拆分成RTP数据包,由RTPsession处理,并由fakeink元素使用。

上游元素(Rtpvrawpay)和下游元素(Fakeink)可以已经链接缓冲区列表,但rtpsession不能。

⇨注意:通过单击下面的图表,将在新窗口中打开交互式火焰图。

公平地说,这种巨大的改进只有在受控的用例中才能实现,通用的真实场景中的提升目前被其他因素缓解了。