什么是SRS?
SRS(Simple RTMP Server)是一个简单高效的实时视频服务器,支持RTMP/WebRTC/HLS/HTTP-FLV/SRT/GB28181协议,可以大大降低音视频流媒体服务器搭建的门槛。它是使用C++编写的开源软件,优化好,占用低,可以很方便地接入项目。
视频编码的一些基础知识
各个协议以及视频编码技术都是十分复杂的,所以不可能通过一篇文章讲解清楚。此处仅概述一下视频编码的一些基础知识。
视频编码是将视频信号转换为数字数据的过程,以便在数字通信、存储和传输中使用。它是多媒体数据压缩的重要组成部分,编码的最终目的是减小视频数据的体积,以节省带宽和存储空间,并实现高效的传输和播放。
视频是由一系列连续的图像帧组成的,每一帧都是视频数据的基本单元。我们从帧出发,将视频编码中的帧分为:I帧(Intra Frame)、P帧(Predicted Frame)和B帧(Bi-directional Predicted Frame)。
I帧(关键帧):I帧是自身编码信息完整的帧,它不依赖于其他帧。I帧通常是视频序列的起始帧或者关键变化帧,它存储了完整的图像信息。
P帧(预测帧):P帧依赖于前面的I帧或P帧,并记录了当前帧与前面帧之间的差异。P帧存储的是预测的变化信息。
B帧(双向预测帧):B帧同时依赖于前面的I帧、P帧和后面的P帧,并记录了当前帧与前后帧之间的差异。B帧存储的是双向预测的变化信息。
一个视频,通过特定的编码方式来进行压缩,并且需要保证视频质量。所以就有了视频的编码格式。常见的编码格式有:H.264/AVC(Advanced Video Coding)、H.265/HEVC(High-Efficiency Video Coding)、VP9、AV1、MPEG-2、MPEG-4、VP8等。具体格式的内容不是本文的重点。了解完视频编码的基础,可以开始看SRS的内容了。
SRS的常见部署架构
SRS与常规应用一样,支持单节点部署,也支持集群部署。与游戏服务器不同的是,SRS是单进程模型,不支持多进程;可以使用集群或者ReusePort扩展多进程(多核)能力。
单节点架构

这是官方给出的单节点架构图,原理十分简单,主播直接推流给SRS源站,源站将流量分发给观众。以下是官方给出的数据: Remark:一台服务器,SRS能支持3K个推流流,或者7.5K个播放,详细参考SRS的性能报告。
我的分析:因为SRS是单进程模型,只能利用一个核心,所以此处的结果只会受到CPU主频的影响,受CPU核心影响不大。单节点架构对于企业级应用来说并发量肯定是不够的,所以需要拓展SRS的集群能力来实现更大的并发。
边缘架构
SRS支持Edge边缘服务器,来扩展源站的支持播放的能力。如下图所示:

这是官方给出的多节点架构,从图中可以看出,源站不再直接分发流量给客户端,而是把流量分发给Edge边缘节点,再由边缘节点分发给客户端。而主播可以直接推流给源站。此处可以再新增一个调度服务器,相当于网关,客户端请求时,网关可以给客户端分配一个服务器地址,让客户端到这个地址上去拉流。也可以通过云服务商提供的DNS,由DNS根据客户端的区域,解析就近的服务器IP给客户端。图中的结构是可以水平拓展的,根据官方文档,一个SRS源站最多可以支持7千个边缘节点。这个架构适合那些主播较少,观众较多的场景,例如:在线教育、线上演唱会、赛事直播等。
该架构优点是搭建简单,并且能够很方便地支持水平拓展;缺点是:若此时有多个主播需要同时推流,例如大型多人视频会议的场景,那么此时一个源站是不够的。
接着我们引出第三种架构:集群架构。
集群架构

与边缘架构不同的是,集群架构支持多个源站的拓展,能够支持更多的主播同时在线直播。一个集群可以由多个源站组合而成,可以以地域进行集群的划分。集群架构一个最重要的特性是:两个Origin服务器之间会互相查询流,若Edge请求的流不在本源站上,会将Edge定向到有流的Origin中。通俗地说,就是边缘服务器需要多通过一次HTTP API查询流在哪个源站上,再前往对应的源站进行拉流。
这种架构复杂度较高,但是能够承受的并发量很大,并且能够无限拓展边缘站,对于多主播多观众的场景支持很好 。 除了上述的几种架构外,SRS还有其他架构,例如:Vhost集群,Reuse Port等。可以通过查阅官方Wiki根据需求进行选择。
协议之间的对比
目前主流的协议有以下几种:RTMP、HTTP流、HLS,还有新兴的WebRTC协议。我通过一个表格进行总结:
| 特性 | RTMP | HTTP流(如DASH和HLS) | WebRTC |
|---|---|---|---|
| 场景 | 如线上课堂、带货直播等对延迟没有强要求的场景。 | 流媒体传输、视频点播,对延迟没有要求的场景。 | 实时通信、视频会议、互动直播等需要低延迟的实时互动场景 |
| 传输协议 | RTMP | HTTP | SCTP(使用UDP或TCP) |
| 安全性 | RTMP无加密,RTMPS有 | HTTPS加密 | DTLS加密 |
| 流媒体传输 | 是 | 是 | 不直接支持,需要其他技术 |
| 传输延迟 | 较低(1-5秒左右) | 较高(30-60秒) | 较低(400毫秒左右,具体看优化) |
| 浏览器支持 | 需要Flash插件(Chrome已弃用) | 支持H5播放器(无需插件) | 支持H5播放器(无需插件) |
| 移动端支持 | 需要Flash插件(Chrome已弃用) | 支持H5播放器(无需插件) | 支持H5播放器(无需插件) |
| 兼容性 | 广泛支持 | 广泛支持 | 较新的浏览器和平台支持 |
| P2P通信 | 不支持 | 不支持 | 支持 |
| 实时性 | 较好 | 较差 | 非常好 |
| 复杂度 | 中等 | 低 | 较高 |
SRS框架针对RTMP协议有进行优化,可以将RTMP流的延迟做到一秒左右。接下来我们具体看看它做的优化。
SRS针对RTMP的优化
Merged-Read
由于RTMP的Read效率非常低,需要先读一个字节,判断是哪个chunk,然后读取header,接着读取payload。因此上行支持的流的路数大约只有下行的1/3,譬如SRS1.0支持下行2700上行只有1000,SRS2.0支持下行10000上行只有4500。
为了提高性能,SRS对于上行的read使用merged-read,即SRS在读写时一次读取N毫秒的数据。
也就是说,当开启merged-read之后,服务器的接收缓冲区至少会有latency毫秒的数据,延迟也就会有这么多毫秒。
若需要低延迟配置,关闭merged-read,服务器每次收到1个包就会解析。但同时会损失性能。
Min-Latency
在了解Min-Latency之前,首先要先明白SRS的Merged-Read机制。当开启最低延迟配置后,SRS会禁用mr(merged-read),并且在consumer队列中使用超时等待,大约每收到1-2个视频包就发送给客户端,达到最低延迟目标。
GOP-Cache
GOP是什么?GOP是指视频流中,两个I帧的时间距离。
GOP有什么影响?Flash(解码器)只有拿到GOP才能开始解码播放。也就是说,服务器一般先给一个I帧给Flash。但此时存在一个问题,假设GOP是10秒,也就是每隔10秒才有关键帧,如果用户在第5秒时开始播放,会发生什么?
此时有两种方案:
1、等待下一个I帧,也就是说,再等5秒才开始给客户端数据。这样延迟就很低了,总是实时的流。带来的问题是:等待的这5秒会黑屏,现象就是播放器卡在那里,什么也没有,有些用户可能以为页面卡死,就会刷新页面。
2、马上开始播放前一个I帧。换言之,服务器需要总是缓存一个GOP,这样客户端上来就从前一个I帧开始播放,就可以快速启动了。但带来的问题是延迟增加。
实践
在本地搭建SRS服务器,并使用OBS进行推流,在FLV播放器中拉流,模拟观众进行观看。
1、首先通过Docker将ossrs/srs镜像拉下来,并启动容器。暴露:10080、1935(RTMP)、1985、8000、8080(SRS的网页管理)端口。

2、启动容器

3、打开OBS,并在OBS中设置推流地址,推流码可以自定义。

4、开始推流,并使用FLV播放器或其他支持拉流的客户端查看。