国标规定了 RTP,但落地时有四种常见承载:RTP/UDP、RTP/TCP、PS over TCP、HTTP-FLV。 它们差的不是几十个字节,是一整年的流量账—— 同一路 4 Mbps 的流,单路一年都在 16 TB 以上。
前两节讲「信令怎么翻」「控制怎么翻」,这一节讲「媒体本身怎么换承载」。 很多人以为换承载只是改个 socket,实际上 TCP 会带进来一整笔额外的固定开销。
一、从 UDP 到 TCP 换掉了什么
换掉的不只是协议名,还有三样东西: 头部从 8 字节变成 20 字节;多了 4 字节的长度前缀(因为 TCP 是流,要自己切包); 多了 ACK 和重传。 前两项是小钱,第三项是大钱:TCP 每收到两个数据包就要回一个 ACK, 这个 ACK 运的是零字节负载,但它的头一样要四十个字节。 按每秒三百多个包算,ACK 每秒一百八十多个、七千多字节,占这一路总流量的百分之一点四。 一路看着可以忽略,一千路一年就是两百多 TB。 更贵的还不是流量,是重传:丢一个包,整条连接要停下来等重传超时,后面的包全部排队。 这就是为什么高码率实时流几乎不用 TCP。
二、从 RTP 到 HTTP-FLV
为什么还要转成 HTTP-FLV:因为浏览器只认 HTTP 和 WebSocket,它没法直接收 RTP。 这一层转换不是「优化」,是「没办法」。 转成 FLV 要做的三件事: 把 PS 拆成裸流、把裸流按 FLV 标签重新打头、再套一层 HTTP 长连接把标签一个个吐出去。 开销反而更小:FLV 标签头是 11 字节加 4 字节尾,一共 15 字节,比 RTP 头还少。 因为它不需要时间戳同步信息——FLV 的时间戳是标签自带的,不像 RTP 那样按 90 千赫兹算。 但延迟会变大:HTTP 是「请求—响应」模型,浏览器要先发请求,服务端才能推, 而且中间可能经过 CDN 缓存。 监控场景能忍,对讲场景不能忍。
三、转码是最后手段
一定要分清「转封装」和「转码」: 转封装是拆开重打头,字节基本不变,CPU 几乎不耗;转码是解码再编码,CPU 吃满,画质还掉一代。 很多人说「转个协议」,其实做的是转码—— 比如浏览器要 H.264 而设备给的是 H.265,这就只能转码。 转码的成本可以粗算:一路 1080p 软解软编要占满一个核,十六路就要十六个核。 所以「让浏览器直接看 H.265」这件事,工程上通常靠「设备同时出两路码流」而不是「服务端转码」。 这也是国标平台常见的配置项:主码流给录像、子码流给预览, 两路都是设备自己出的,不占服务器 CPU。
四、动手 Demo:同一路流,四种承载各要多少流量
按一路 4096 kbps、每包 1400 字节负载算,把四种承载的实占码率、每小时流量、 单路一年流量都算出来。 再把 ACK 这一项单独拎出来算,那是表里看不出来的部分。
bitrate, payload, sec = 4096000, 1400, 3600
pps = int(round(bitrate / 8.0 / payload))
for name, extra, ack in (("RTP/UDP", 20, 0),
("RTP/TCP", 36, 40),
("PS/TCP", 45, 40),
("HTTP-FLV", 35, 40)):
rate = (payload + extra) * pps
if ack:
rate += ack * (pps // 2)
print(name, "%.2f Mbps" % (rate * 8 / 1e6),
"%.1f GB/h" % (rate * sec / 1e9),
"%.1f TB/年" % (rate * sec * 24 * 365 / 1e12))
ack_s = 40 * (pps // 2)
print("ACK 占比 %.2f%%" % (100.0 * ack_s / ((payload + 36) * pps)))
实跑输出:
--------------------------------------------------------------------
同一路流,四种承载各要多少流量
--------------------------------------------------------------------
**国标规定了 RTP 承载,但落地时常见四种承载方式**。
**本节把同一路 4 Mbps 的视频放到四种承载里,算一年的账。**
按每包 1400 字节负载算,一路每秒 366 个包
承载 每包加 实占码率 每小时 单路一年
-------------------------------------------------------------------------------------
**RTP/UDP** **+20** **4.16 Mbps** **1.9 GB/h** **16.4 TB/年**
**RTP/TCP** **+36** **4.26 Mbps** **1.9 GB/h** **16.8 TB/年**
**PS over TCP** **+45** **4.29 Mbps** **1.9 GB/h** **16.9 TB/年**
**HTTP-FLV** **+35** **4.26 Mbps** **1.9 GB/h** **16.8 TB/年**
**第一行和第二行差十六个字节**:**UDP 是 8 加 12 共 20;TCP 是 20 加 4 再加 12 共 36。**
**但表里还漏了一项:ACK**。**每两个数据包要回一个 40 字节的空包,它运的是零字节负载。**
**按每秒 366 个包算,ACK 每秒 183 个、7320 字节。**
占这一路总流量的 1.39%
一千路一年:231 TB
**一路看着可以忽略,一千路就是两百多 TB**——**这是「TCP 便宜」这个直觉最容易翻车的地方。**
**所以「为什么直播都用 UDP」这个问题,答案不在延迟上,在账上**——
**UDP 的 ACK 是零,TCP 的 ACK 是实打实的流量。**
**但 UDP 也有账要付**:**它不重传,丢一个包就是一个缺口。**
**国标的做法是「让解码器自己扛」**:**P 帧丢了就丢,等下一个 I 帧。**
**所以 I 帧间隔设得越短,抗丢包越好,码率也越高。**
**这是一个必须自己拿捏的旋钮,没有标准答案。**
每一小时都是 1.9 GB、单路一年 16 TB 以上——这个数量级值得记一下:
4 Mbps 的流跑满一年,就是十六个 TB。
所以「录像保存三十天」从来不是小成本,存储永远是监控项目里最先超预算的一项。
四行的实占码率只差 0.13 Mbps,也就是说承载方式对流量影响不到百分之三。
那为什么还要挑?因为差的不在流量,在行为和成本。
ACK 那一行是表里看不见的:每秒一百八十多个空包、七千多字节、占总量百分之一点四。
一路无所谓,一千路一年两百多 TB,这些字节全部运的是「我收到了」四个字。
最后一段说清一件事:HTTP-FLV 的开销反而比 RTP 小,
所以「转成 FLV 会变卡」这个印象是错的——变的是延迟和可控性,不是带宽。
还有一点要注意:
这张表里的 pps 是按「每包 1400 字节」算的,实际封装会把大帧切成多个包、把小帧攒进一个包,
真实包数会略有出入。
30 秒实验
- 算一下:4 Mbps 的流跑一年多少 TB?(约 16 TB)
- 想一下:为什么 TCP 的 ACK 也算流量?
- 想一下:转封装和转码的 CPU 开销差多少?
常见误区
- 以为「换承载方式会大幅改变带宽」。 四行只差百分之三,真正的差别在行为和延迟。
- 以为「转成 HTTP-FLV 会更占带宽」。 FLV 标签头才 15 字节,比 RTP 头还小。
- 以为「转协议就是转封装」。 编码不兼容时必须转码,那是另一个量级的开销。
自测三问(点开对答案)
1. TCP 比 UDP 多了哪三样东西? —— **头部从 8 变 20 字节、多了 4 字节长度前缀、多了 ACK 和重传**。 2. 为什么浏览器必须走 HTTP-FLV 而不能直接收 RTP? —— **浏览器只认 HTTP 和 WebSocket**,没有开放的 UDP 收流能力。 3. 转封装和转码的本质区别是什么? —— **转封装只拆开重打头,字节基本不变;转码要解码再编码,CPU 吃满还掉画质。**下一节扒到最里面一层:把一段 PS 流拆开,数清哪些字节是头。
- ☐ (本节完,下一节 10.05.08 媒体数据格式的转换)