SRS 是国产开源的流媒体服务器,一路推流能同时出四种格式。 它的卖点不是性能,是「一个进程顶好几个」。
第十章用 Nginx 拼出直播能力,这一章换成一体化的 SRS。 11.2 开始装,装之前先弄清它到底能干什么。
一、它是什么
SRS 全称 Simple Realtime Server,国产开源,MIT 许可。 它的定位很直接:一台机器、一个进程,把直播要的协议全包了。
支持哪些协议,决定了它能接住什么客户端:
① RTMP:推流的事实标准,OBS、ffmpeg 都认它。 ② HTTP-FLV:延迟低、走 HTTP,能过大多数防火墙。 ③ HLS:兼容性最好,手机浏览器原生就能播。 ④ WebRTC:延迟最低,代价是要额外编译、要开 UDP。 ⑤ SRT 与 GB28181:广电与安防场景用的,默认都不开。
这几样不是并列关系,而是「一进多出」: 一路流推上去,上面几种地址同时能看。 这是它和「只能推不能拉」的转发工具最根本的区别。
二、四种输出的成本差在哪
很多人以为「多支持一种格式,带宽就多一份」,这是错的。 码流大小由编码决定,容器只往上加头。
真正的差别在【处理成本】上:
① RTMP 与 HTTP-FLV:在内存里换个封装就发出去,成本几乎为零。 ② HLS:要把切片写到磁盘,再由 HTTP 吐出去。 磁盘 IO 与重复的关键帧是它的两份额外开销。 ③ WebRTC:要把 H265 转码或重新打包,CPU 比前几种高得多。
所以「四种输出里只有 HLS 真的要花钱」这句话是准确的: 其余几种都是在内存里换个壳,HLS 是唯一要落盘的。 这也是第 126 号 Demo 里 HLS 那份数据最大的原因。
三、它比「流媒体服务器」宽
装完 SRS,你得到的其实是四样东西:
① 流媒体服务器:收流、转发、分发。
② 小型 Web 服务器:http_server 一开,切片文件由它自己吐。
不用再装一个 Nginx。
③ 录像机:dvr 块一开,每路流都能存成文件。
④ 拉流器:ingest 让它主动去拉别人的流,方向正好反过来。
这四样合起来,才是「一个进程顶好几个」。 也正因为如此,它的配置文件比 Nginx 长得多——第十章的 Nginx 只管转发,SRS 连 Web 服务和录像都管。
四、动手 Demo:一次推流,四种输出各多大
同一段画面、同一套编码参数,只换容器, 把四种格式的字节数摆在一起看。
def encode_into(fmt):
"""真编一遍,直接写进指定容器。"""
c = av.open(path, "w", format=fmt, options=opts)
st = c.add_stream("libx264", rate=25)
st.options = {"crf": "23", "preset": "veryfast", "g": "25"}
for i in range(25):
c.mux(st.encode(frame(i)))
c.close()
return 总字节数
for fmt in ("flv", "mpegts", "mp4", "hls"):
print(fmt, encode_into(fmt))
# 再把 TS 拆开:定长 188 字节一包,看填充占多少
npk = len(raw) // 188
for i in range(npk):
pkt = raw[i * 188:(i + 1) * 188]
if pkt[3] & 0x20: # 有适配域
af += 1 + pkt[4] # 长度字节 + 内容
print("包头", npk * 4, "填充", af, "负载", len(raw) - npk * 4 - af)
实跑输出:
--------------------------------------------------------------------
SRS 简介——一次推流,几种输出
--------------------------------------------------------------------
**① 它解决的核心问题**
**没有 SRS 的时候,你想同时支持 RTMP、HTTP-FLV、HLS 三种播放,**
**要么部署三个服务,要么自己写转发。**
**SRS 把这件事变成配置项:一路流推上去,三种地址同时能看。**
能力 配一行就有 额外开销
------------------------------------------------------------------
RTMP 播放 默认就有 没有,本来就是 RTMP
HTTP-FLV `http_remux` 几乎为零,只是换个封装
HLS `hls { enabled on; }` 要写磁盘,有明显 IO
WebRTC `rtc_server` 要额外编译,CPU 也高些
**四种输出里,只有 HLS 真的要额外花钱**——**它要把切片写到磁盘,再由 HTTP 服务吐出去。**
**其余几种都是在内存里换个封装,成本几乎为零。**
**② 真测:同一段画面,封成四种格式各多大**
**内容完全一样、编码参数完全一样,差别只在容器。**
格式 字节数 封装耗时毫秒 相对最小
-------------------------------------------------
FLV 10503 144 1.00 倍
TS 16920 76 1.61 倍
MP4 10672 76 1.02 倍
HLS 14026 79 1.34 倍
**四种格式里最小的是 FLV,最大的是 TS。**
**差距主要来自容器头与索引,不是画面质量**——**编码参数一模一样,码流本身大小相同。**
**注意 HLS 那一行包含了三个切片文件加一份索引:**
**切片之间有重复的关键帧信息,索引又有额外开销,**
**所以它一定是几种格式里最吃亏的那个。**
**这是「低延迟换兼容性」这笔交易里,HLS 付的那部分钱。**
**③ 顺手拆一下 TS:它比 FLV 胖的那部分在哪儿**
**TS 是定长包:不管里面装多少,一个包永远占 188 字节。**
**这份 16920 字节的 TS 正好切成 90 个包,一个字节都不剩。**
组成部分 字节 占这份 TS
---------------------------------------------------
包固定头(每包 4 字节) 360 2.1%
适配域填充(37 个包有) 2563 15.1%
真正装数据的部分 13997 82.7%
**90 个包里有 37 个带适配域,那些字节基本都是零。**
**它们出现的唯一理由是:这一包没装满,得用填充把长度凑够 188。**
**这就是 TS 比 FLV 胖的原因:FLV 的 tag 多长就写多长,**
**TS 却要把每一段都补齐到 188 的整数倍。**
**这段画面本身很小(10503 字节的 FLV),补出来的零就显得格外多;**
**换成 1080p 的大码流,比例会降下来,但绝不会降到零。**
**代价换来的是好处:任意一个 188 字节的边界都能直接开始解码,**
**丢了包也知道下一个包从哪儿开始。广播系统要的就是这个。**
**④ 它还有两件常被忽略的事**
**① 它自带 HTTP 服务**:**切片文件由它自己吐,不用再装一个 Nginx。**
**`http_server { enabled on; }` 一行就有。**
**② 它有 `dvr` 与 `ingest`**:**前者录像,后者主动去拉别的流。**
**`ingest` 的意思正好反过来——不是别人推给我,是我去拉别人。**
**所以 SRS 的定位其实比「流媒体服务器」更宽:**
**它同时是一个小型 Web 服务器、一个录像机、一个拉流器。**
**这也是它在国内用得广的原因之一:装一个顶好几个。**
四种格式最小的是 FLV,最大的是 TS,差 1.6 倍。 编码参数完全一样,差的全在容器上。 TS 胖在定长包:90 个包里 37 个带填充,一共 2563 字节的零。 HLS 那份还含三个切片文件加一份索引,所以它比 TS 也多。
30 秒实验
- 把
crf从 23 改成 40,看四种格式的相对大小会不会变——会小幅变,但排序不变。 - 把帧数从 25 提到 100,看 TS 的填充比例怎么变——降下来,因为每包塞得更满。
- 只留 MP4 一种,猜总耗时会不会降到四分之一——不会,编码才是主要开销,封装只占一小截。
常见误区
- 「SRS 只做 RTMP」——它同时支持 HLS、HTTP-FLV、WebRTC、SRT。
- 「格式越多码流越大」——码流是编码定的,容器只往上加头。
- 「HLS 最省带宽」——刚好相反,它要落盘还要重复关键帧。
自测三问(点开对答案)
1. 一路推流最多能出几种播放格式? —— **教材列了四种**:RTMP、HTTP-FLV、HLS、WebRTC。 2. 四种输出里哪种成本最高? —— **HLS**,因为要把切片写进磁盘,还得自己再吐出去。 3. TS 为什么比 FLV 大? —— **定长 188 字节一包,塞不满就用适配域填零。**- ☐ (本节完,下一节 11.2.1 在 Ubuntu 18 上安装 SRS)