type
status
date
slug
summary
tags
category
icon
password
Edited
Jul 6, 2023 12:11 PM
Created
Jul 6, 2023 11:39 AM
流媒体协议
RTP/RTCP
一般情况下,在实时互动直播系统传输音视频数据流时,我们并不直接将音视频数据流交给 UDP 传输,而是先给音视频数据加个 RTP 头,然后再交给 UDP 进行传输。为什么要这样做呢?
我们以视频帧为例,一个 I 帧的数据量是非常大的,最少也要几十 K(I/P/B 帧的概念我在前面的文章中有过介绍)。而以太网的最大传输单元是多少呢? 1.5K,所以要传输一个 I 帧需要几十个包。并且这几十个包传到对端后,还要重新组装成 I 帧,这样才能进行解码还原出一幅幅的图像。如果是我们自己实现的话,要完成这样的过程,至少需要以下几个标识。
- 序号:用于标识传输包的序号,这样就可以知道这个包是第几个分片了。
- 起始标记:记录分帧的第一个 UDP 包。
- 结束标记:记录分帧的最后一个 UDP 包。
RTP 协议
而上面的需求,就RTP协议
RTP 协议非常简单,我这里按字段的重要性从高往低的顺序讲解一下。
- sequence number:序号,用于记录包的顺序。这与上面我们自己实现拆包、组包是同样的道理。
- timestamp:时间戳,同一个帧的不同分片的时间戳是相同的。这样就省去了前面所讲的起始标记和结束标记。一定要记住,不同帧的时间戳肯定是不一样的。
- PT:Payload Type,数据的负载类型。音频流的 PT 值与视频的 PT 值是不同的,通过它就可以知道这个包存放的是什么类型的数据。
- ……
类似这样的音视频数据:
RTCP 协议
在使用 RTP 包传输数据时,难免会发生丢包、乱序、抖动等问题,下面我们来看一下使用的网络一般都会在什么情况下出现问题:
- 网络线路质量问题引起丢包率高;
- 传输的数据超过了带宽的负载引起的丢包问题;
- 信号干扰(信号弱)引起的丢包问题;
- 跨运营商引入的丢包问题 ;
- ……
WebRTC 对这些问题在底层都有相应的处理策略,但在处理这些问题之前,它首先要让各端都知道它们自己的网络质量到底是怎样的,这就是 RTCP 的作用。
RTCP 有两个最重要的报文:RR(Reciever Report)和 SR(Sender Report)。通过这两个报文的交换,各端就知道自己的网络质量到底如何了。
SDP
SDP(Session Description Protocal)说直白点就是用文本描述的各端(PC 端、Mac 端、Android 端、iOS 端等)的能力。这里的能力指的是各端所支持的音频编解码器是什么,这些编解码器设定的参数是什么,使用的传输协议是什么,以及包括的音视频媒体是什么等等。
下面让我们来看一个真实的 SDP 片段吧!
如上面的 SDP 片段所示,该 SDP 中描述了一路音频流,即m=audio,该音频支持的 Payload ( 即数据负载 ) 类型包括 111、103、104 等等。
在该 SDP 片段中又进一步对 111、103、104 等 Payload 类型做了更详细的描述,如 a=rtpmap:111 opus/48000/2 表示 Payload 类型为 111 的数据是 OPUS 编码的音频数据,并且它的采样率是 48000,使用双声道。以此类推,你也就可以知道 a=rtpmap:104 ISAC/32000 的含义是音频数据使用 ISAC 编码,采样频率是 32000,使用单声道。
DTLS
说到网络上的数据安全你可能首先想到的是 HTTPS,你也可以简单地将 HTTPS 理解为“HTTP 协议 + 数据加密”,当然实际上它要复杂得多。HTTPS 的底层最初是使用 SSL(Secure Sockets Layer,安全套接层)协议对数据加密。当 SSL 更新到 3.0 时,IETF 对 SSL 3.0 进行了标准化,并增加了一些新的功能,不过基本与 SSL 3.0 没什么区别,标准化后的 SSL 更名为 TLS 1.0(Transport Layer Security,安全传输层协议),所以可以说 TLS 1.0 就是 SSL 的 3.1 版本。
TLS 协议由TLS 记录协议和TLS 握手协议组成:
- TLS 记录协议,用于数据的加密、数据完整性检测等;
- TLS 握手协议,主要用于密钥的交换与身份的确认。
由于 TLS 底层是基于 TCP 协议的,而 WebRTC 音视频数据的传输主要基于 UDP 协议,因此 WebRTC 对数据的保护无法直接使用 TLS 协议。但 TLS 协议在数据安全方面做得确实非常完善,所以人们就想到是否可以将 TLS 协议移植到 UDP 协议上呢? 因此 DTLS 就应运而生了。
所以你可以认为DTLS 就是运行在 UDP 协议之上的简化版本的 TLS,它使用的安全机制与 TLS 几乎一模一样。
在 DTLS 协议中,最关键是的它的握手协议,正如下图所展示的这样:
在 WebRTC 中为了更有效地保护音视频数据,所以需要使用 DTLS 协议交换公钥证书,并确认使用的密码算法,这个过程在 DTLS 协议中称为握手协议。
RTMP
RTMP,全称 Real Time Messaging Protocol ,即实时消息协议。但它实际上并不能做到真正的实时,一般情况最少都会有几秒到几十秒的延迟,底层是基于 TCP 协议的。
RTMP 的传输格式为 RTMP Chunk Format,媒体流数据的传输和 RTMP 控制消息的传输都是基于此格式的。
需要注意的是,在使用 RTMP 协议传输数据之前,RTMP 也像 TCP 协议一样,先进行三次握手才能将连接建立起来。当 RTMP 连接建立起来后,你可以通过 RTMP 协议的控制消息为通信的双方设置传输窗口的大小(缓冲区大小)、传输数据块的大小等。
优势
RTMP 协议在苹果公司宣布其产品不支持 RTMP 协议,且推出 HLS 技术来替代 RTMP 协议的“打压”下,已停止更新。但协议停止更新后,这么多年仍然屹立不倒,说明该协议肯定有它独特的优势。那有哪些呢?
- RTMP 协议底层依赖于 TCP 协议,不会出现丢包、乱序等问题,因此音视频业务质量有很好的保障。
- 使用简单,技术成熟。有现成的 RTMP 协议库实现,如 FFmpeg 项目中的 librtmp 库,用户使用起来非常方便。而且 RTMP 协议在直播领域应用多年,技术已经相当成熟。
- 市场占有率高。在日常的工作或生活中,我们或多或少都会用到 RTMP 协议。如常用的 FLV 文件,实际上就是在 RTMP 消息数据的最前面加了 FLV 文件头。
- 相较于 HLS 协议,它的实时性要高很多。
劣势
RTMP 有优势,也有劣势。在 RTMP 的众多劣势中,我认为最为关键的有两条。
- 苹果公司的 iOS 不支持 RTMP 协议,按苹果官方的说法, RTMP 协议在安全方面有重要缺陷。
- 在苹果的公司的压力下,Adobe 已经停止对 RTMP 协议的更新了。
HLS
HLS,全称 HTTP Live Streaming,是苹果公司实现的基于 HTTP 的流媒体传输协议。它可以支持流媒体的直播和点播,主要应用在 iOS 系统和 HTML5 网页播放器中。
HLS 的基本原理非常简单,它是将多媒体文件或直接流进行切片,形成一堆的 ts 文件和 m3u8 索引文件并保存到磁盘。
当播放器获取 HLS 流时,它首先根据时间戳,通过 HTTP 服务,从 m3u8 索引文件获取最新的 ts 视频文件切片地址,然后再通过 HTTP 协议将它们下载并缓存起来。当播放器播放 HLS 流时,播放线程会从缓冲区中读出数据并进行播放。
通过上面的描述我们可以知道,HLS 协议的本质就是通过 HTTP 下载文件,然后将下载的切片缓存起来。由于切片文件都非常小,所以可以实现边下载边播的效果。HLS 规范规定,播放器至少下载一个 ts 切片才能播放,所以 HLS 理论上至少会有一个切片的延迟。
优势
HLS 是为了解决 RTMP 协议中存在的一些问题而设计的,所以,它自然有自己的优势。主要体现在以下几方面:
- RTMP 协议没有使用标准的 HTTP 接口传输数据,在一些有访问限制的网络环境下,比如企业网防火墙,是没法访问外网的,因为企业内部一般只允许 80/443 端口可以访问外网。而 HLS 使用的是 HTTP 协议传输数据,所以 HLS 协议天然就解决了这个问题。
- HLS 协议本身实现了码率自适应,不同带宽的设备可以自动切换到最适合自己码率的视频进行播放。
- 浏览器天然支持 HLS 协议,而 RTMP 协议需要安装 Flash 插件才能播放 RTMP 流。
不足
HLS 最主要的问题就是实时性差。由于 HLS 往往采用 10s 的切片,所以最小也要有 10s 的延迟,一般是 20 ~ 30s 的延迟,有时甚至更差。
HLS 之所以能达到 20 ~ 30s 的延迟,主要是由于 HLS 的实现机制造成的。HLS 使用的是 HTTP 短连接,且 HTTP 是基于 TCP 的,所以这就意味着 HLS 需要不断地与服务器建立连接。TCP 每次建立连接时都要进行三次握手,而断开连接时,也要进行四次挥手,基于以上这些复杂的原因,就造成了 HLS 延迟比较久的局面。
FLV
FLV 文件是一个流式的文件格式。该文件中的数据部分是由多个 “PreviousTagSize + Tag”组成的。这样的文件结构有一个天然的好处,就是你可以将音视频数据随时添加到 FLV 文件的末尾,而不会破坏文件的整体结构。
在众多的媒体文件格式中,只有 FLV 具有这样的特点。像 MP4、MOV 等媒体文件格式都是结构化的,也就是说音频数据与视频数据是单独存放的。当服务端接收到音视频数据后,如果不通过 MP4 的文件头,你根本就找不到音频或视频数据存放的位置。
正是由于 FLV 是流式的文件格式,所以它特别适合在音视频录制中使用。
使用 FLV 进行视频回放也特别方便,将生成好的 FLV 直接推送到 CDN 云服务,在 CDN 云服务会将 FLV 文件转成 HLS 切片,这样用户就可以根据自己的终端选择使用 FLV 或 HLS 协议回放录制好的视频。
而对于回放实时性要求比较高的业务,还可以将 FLV 按 3 ~ 5 分钟进行切片,这样就可以在直播几分钟后看到录制好的内容了。
另外,FLV 相较 MP4 等多媒体文件,它的文件头是固定的,音视频数据可以随着时间的推移随时写入到文件的末尾;而 MP4 之类的文件,文件头是随着数据的增长而增长的,并且体积大,处理时间长。因此, FLV 文件相较于其他多媒体文件特别适合于在录制中使用。
CDN 网络
CDN 网络的构造十分复杂,一般情况下,它先在各运营商内构建云服务,然后再将不同运营商的云服务通过光纤连接起来,从而实现跨运营商的全网 CDN 云服务。
而每个运营商云服务内部包括了多个节点,按功能分为 3 类。
- 源节点,用于接收用户推送的媒体流。
- 主干结点,起到媒体数据快速传递的作用,比如与其他运营商传送媒体流。
- 过缘节点,用于用户来主动接流。一般边缘节点的数量众多,但机子的性能比较低,它会被布署到各地级市,主要解决网络最后一公里的问题。
接下来,我们简要描述一下 CDN 网络的处理流程。
当一个主播想将自己的音视频共享出去的时候,首先通过直播系统的信令服务器获取到可以推送媒体流的 CDN 源节点。CDN 网络从源节点接收到媒体数据后,会主动向各个主干结点传送流媒体数据,这样主干结点就将媒体数据缓存起来了。当然这个缓冲区的大小是有限的,随着时间流逝,缓冲区中的数据也在不断更替中。
当有观众想看某个主播的节目时,会从直播系统的信令服务器获取离自己最近的 CDN 边缘节点,然后到这个边缘节点去拉流。由于他是第一个在该节点拉流的用户,因此该 CDN 边缘节点还没有用户想到的媒体流,怎么办呢?那就向主干结点发送请求。主干结点收到请求后,从自己的缓冲区中取出数据流源源不断地发给边缘节点,这时边缘节点再将媒体数据发给观众。
当第二个观众再次到该 CDN 边缘节点接流时,该节点发现该流已经在自己的缓存里了,就不再向主干结点请求,直接将媒体流下发下去了。因此,观众在使用 CDN 网络时会发现,第一个观众在接流时需要花很长时间才能将流拉下来,可是后来的用户很快就将流拉下来进行播放了。
知识点
NAT
NAT 种类
现在 NAT 基本上可以总结成 4 种类型:完全锥型、IP 限制锥型、端口限制锥型和对称型。
1. 完全锥型 NAT
完全锥型 NAT 的特点是,当 host 主机通过 NAT 访问外网的 B 主机时,就会在 NAT 上打个“洞”,所有知道这个“洞”的主机都可以通过它与内网主机上的侦听程序通信。
实际上,这里所谓的“打洞”就是在 NAT 上建立一个内外网的映射表。你可以将该映射表简单地认为是一个 4 元组,即:
在 NAT 上有了这张映射表,所有发向这个“洞”的数据都会被 NAT 中转到内网的 host 主机。而在 host 主机上侦听其内网端口的应用程序就可以收到所有的数据了,是不是很神奇?
还是以上面那张图为例,如果 host 主机与 B 主机“打洞”成功,且 A 与 C 从 B 主机那里获得了 host 主机的外网 IP 及端口,那么 A 与 C 就可以向该 IP 和端口发数据,而 host 主机上侦听对应端口的应用程序就能收到它们发送的数据。
如果你在网上查找 NAT 穿越的相关资料,一定会发现大多数打洞都是使用的 UDP 协议。之所以会这样,是因为UDP 是无连接协议,它没有连接状态的判断,也就是说只要你发送数据给它,它就能收到。而 TCP 协议就做不到这一点,它必须建立连接后,才能收发数据,因此大多数人都选用 UDP 作为打洞协议。
2. IP 限制锥型 NAT
IP 限制锥型要比完全锥型 NAT 严格得多,它主要的特点是,host 主机在 NAT 上“打洞”后,NAT 会对穿越洞口的 IP 地址做限制。只有登记的 IP 地址才可以通过,也就是说,只有 host 主机访问过的外网主机才能穿越 NAT。
而其他主机即使知道“洞”的位置,也不能与 host 主机通信,因为在通过 NAT 时,NAT 会检查 IP 地址,如果发现发来数据的 IP 地址没有登记,则直接将该数据包丢弃。
所以,IP 限制锥型 NAT 的映射表是一个 5 元组,即:
还是以上图为例,host 主机访问 B 主机,那么只有 B 主机发送的数据才能穿越 NAT,其他主机 A 和 C 即使从 B 主机那里获得了 host 主机的外网 IP 和端口,也无法穿越 NAT。因为 NAT 会对通过的每个包做检测,当检查发现发送者的 IP 地址与映射表中的“被访问主机的 IP”不一致,则直接将该数据包丢弃。
需要注意的是,IP 限制型 NAT 只限制 IP 地址,如果是同一主机的不同端口穿越 NAT 是没有任何问题的。
3. 端口限制锥型
端口限制锥型比 IP 限制锥型 NAT 更加严格,它主要的特点是,不光在 NAT 上对打洞的 IP 地址做了限制,而且还对具体的端口做了限制。因此,端口限制型 NAT 的映射表是一个 6 元组,其格式如下:
在该 6 元组中,不光包括了 host 主机内外网的映射关系,还包括了要访问的主机的 IP 地址及提供服务的应用程序的端口地址。
如上图所示,host 主机访问 B 主机的 p1 端口时,只有 B 主机的 p1 端口发送的消息才能穿越 NAT 与 host 主机通信。而其他主机,甚至 B 主机的 p2 端口都无法穿越 NAT。
从上面的情况你应该看出来了,从完全锥型 NAT 到端口限制型 NAT,一级比一级严格。但其实端口型 NAT 还不是最严格的,最严格的是接下来要讲解的对称型 NAT。
4. 对称型 NAT
对称型 NAT 是所有 NAT 类型中最严格的一种类型。通过上图你可以看到,host 主机访问 B 时它在 NAT 上打了一个“洞”,而这个“洞”只有 B 主机上提供服务的端口发送的数据才能穿越,这一点与端口限制型 NAT 是一致的。
但它与端口限制型 NAT 最大的不同在于,如果 host 主机访问 A 时,它会在 NAT 上重新开一个“洞”,而不会使用之前访问 B 时打开的“洞”。也就是说对称型 NAT 对每个连接都使用不同的端口,甚至更换 IP 地址,而端口限制型 NAT 的多个连接则使用同一个端口,这对称型 NAT 与端口限制型 NAT 最大的不同。上面的描述有点抽象,你要好好理解一下。
它的这种特性为 NAT 穿越造成了很多麻烦,尤其是对称型 NAT 碰到对称型 NAT,或对称型 NAT 遇到端口限制型 NAT 时,基本上双方是无法穿越成功的。
SFU 架构
SFU 像是一个媒体流路由器,接收终端的音视频流,根据需要转发给其他终端。SFU 在音视频会议中应用非常广泛,尤其是 WebRTC 普及以后。支持 WebRTC 多方通信的媒体服务器基本都是 SFU 结构。SFU 的拓扑机构和功能模型如下图:
在上图中,B1、B2、B3、B4 分别代表 4 个浏览器,每一个浏览器都会共享一路流发给 SFU,SFU 会将每一路流转发给共享者之外的 3 个浏览器。
下面这张图是从 SFU 服务器的角度展示的功能示意图:
相比 MCU,SFU 在结构上显得简单很多,只是接收流然后转发给其他人。然而,这个简单结构也给音视频传输带来了很多便利。比如,SFU 可以根据终端下行网络状况做一些流控,可以根据当前带宽情况、网络延时情况,选择性地丢弃一些媒体数据,保证通信的连续性。
目前许多 SFU 实现都支持 SVC 模式和 Simulcast 模式,用于适配 WiFi、4G 等不同网络状况,以及 Phone、Pad、PC 等不同终端设备。
SFU 的优势有哪些呢?可总结为如下:
- 由于是数据包直接转发,不需要编码、解码,对 CPU 资源消耗很小。
- 直接转发也极大地降低了延迟,提高了实时性。
- 带来了很大的灵活性,能够更好地适应不同的网络状况和终端类型。
同样,SFU 有优势,也有不足,主要表现为:
- 由于是数据包直接转发,参与人观看多路视频的时候可能会出现不同步;相同的视频流,不同的参与人看到的画面也可能不一致。
- 参与人同时观看多路视频,在多路视频窗口显示、渲染等会带来很多麻烦,尤其对多人实时通信进行录制,多路流也会带来很多回放的困难。总之,整体在通用性、一致性方面比较差。
无论是从灵活性上,还是音视频的服务质量、负载情况等方面上,相较其他两种方案,SFU 都有明显的优势,因此这种方案也被大多数厂商广泛采用。
另外,在上面介绍 SFU 方案时,我们还提到了视频的 Simulcast 模式和 SVC 模式,下面我就这两个知识点再向你做一下讲解,来看一下这两种视频的处理模式对 SFU 架构来说都带来了哪些好处。
Simulcast 模式
所谓Simulcast 模式就是指视频的共享者可以同时向 SFU 发送多路不同分辨率的视频流(一般为三路,如 1080P、720P、360P)。而 SFU 可以将接收到的三路流根据各终端的情况而选择其中某一路发送出去。例如,由于 PC 端网络特别好,给 PC 端发送 1080P 分辨率的视频;而移动网络较差,就给 Phone 发送 360P 分辨率的视频。
Simulcast 模式对移动端的终端类型非常有用,它可以灵活而又智能地适应不同的网络环境。下图就是 Simulcast 模式的示意图:
SVC 模式
SVC 是可伸缩的视频编码模式。与 Simulcast 模式的同时传多路流不同,SVC 模式是在视频编码时做“手脚”。
它在视频编码时将视频分成多层——核心层、中间层和扩展层。上层依赖于底层,而且越上层越清晰,越底层越模糊。在带宽不好的情况下,可以只传输底层,即核心层,在带宽充足的情况下,可以将三层全部传输过去。
如下图所示,PC1 共享的是一路视频流,编码使用 SVC 分为三层发送给 SFU。SFU 根据接收端的情况,发现 PC2 网络状况不错,于是将 0、1、2 三层都发给 PC2;发现 Phone 网络不好,则只将 0 层发给 Phone。这样就可以适应不同的网络环境和终端类型了。
流媒体服务器
Medooze
注意:Medooze 只能在 Linux 或 Mac OS 中编译使用,Windows 的话,请使用 WSL
Medooze 是一款综合流媒体服务器,它不仅支持 WebRTC 协议栈,还支持很多其他协议,如 RTP、RTMP 等。其源码地址为:https://github.com/medooze/media-server 。
下面我们来看一下 Medooze 的架构图:
从大的方面来讲,Medooze 支持 RTP/RTCP、SRTP/SRCP 等相关协议,从而可以实现与 WebRTC 终端进行互联。除此之外,Medooze 还可以接入 RTP 流、RTMP 流等,因此你可以使用GStreamer/FFmpeg 向 Medooze 推流,这样进入到同一个房间的其他 WebRTC 终端就可以看到 / 听到由 GStream/FFmpeg 推送上来的音视频流了。另外,Medooze 还支持录制功能,即上图中的 Recorder 模块的作用,可以通过它将房间内的音视频流录制下来,以便后期回放。
为了提高多方通信的质量,Medooze 在音视频的内容上以及网络传输的质量上都做了大量优化。关于这些细节我们这里就不展开了,因为在后面的文章中我们还会对 Medooze 作进一步的讲解。
以上我们介绍的是 Medooze 的核心层,下面我们再来看看 Medooze 的控制逻辑层。Medooze 的控制逻辑层是通过 Node.js 实现的,Medooze 通过 Node.js 对外提供了完整的控制逻辑操作相关的 API,通过这些 API 你可以很容易的控制 Medooze 的行为了。
通过上面的介绍,我们可以知道 Medooze 与 Mediasoup 相比,两者在核心层实现的功能都差不多,但 Medooze 的功能更强大,包括了录制、推 RTMP 流、播放 FLV 文件等相关的操作,而 Mediasoup 则没有这些功能。
不过 Medooze 也有一些缺点,尽管 Medooze 也是 C++ 开发的流媒体服务务器,使用了异步 IO 事件处理机制,但它使用的异步 IO 事件处理的 API 是 poll,poll 在处理异步 IO 事件时,与 Linux 下最强劲的异步 IO 事件 API epoll 相比要逊色不少,这导致它在接收 / 发送音视频包时性能比 Mediasoup 要稍差一些。
Mediasoup
Mediasoup 是推出时间不长的 WebRTC 流媒体服务器开源库,其地址为:https://github.com/versatica/mediasoup/ 。
Mediasoup 由应用层和数据处理层组成。应用层是通过 Node.js 实现的;数据处理层由 C++ 语言实现,包括 DTLS 协议实现、ICE 协议实现、SRTP/SRTCP 协议实现、路由转发等。
下面我们来看一下 Mediasoup 的架构图,如下所示:
Mediasoup 把每个实例称为一个 Worker,在 Worker 内部有多个 Router,每个 Router 相当于一个房间。在每个房间里可以有多个用户或称为参与人,每个参与人在 Mediasoup 中由一个 Transport 代理。换句话说,对于房间(Router)来说,Transport 就相当于一个用户。
Transport 有三种类型,即 WebRtcTransport、PlainRtpTransport 和 PipeTransport。
- WebRtcTransport 用于与 WebRTC 类型的客户端进行连接,如浏览器。
- PlainRtpTransport 用于与传统的 RTP 类型的客户端连接,通过该 Transport 可以播放多媒体文件、FFmpeg 的推流等。
- PipeTransport 用于 Router 之间的连接,也就是一个房间中的音视频流通过 PipeTransport 传到另一个房间。
在每个 Transport 中可以包括多个 Producer 和 Consumer。
- Producer 表示媒体流的共享者,它又分为两种类型,即音频的共享者和视频的共享者。
- Consumer 表示媒体流的消费者,它也分为两种类型,即音频的消费者和视频的消费者。
Mediasoup 的实现逻辑非常清晰,它不关心上层应用该如何做,只关心底层数据的传输,并将它做到极致。
Mediasoup 底层使用 C++ 开发,使用 libuv 作为其异步 IO 事件处理库,所以保证了其性能的高效性。同时它支持了几乎所有 WebRTC 为了实时传输做的各种优化,所以说它是一个特别优秀的 WebRTC SFU 流媒体服务器。
所以对于想学习 WebRTC 流媒体服务器源码的同学来说,Mediasoup 是一个非常不错的项目。
另外,对于开发能力比较强的公司来说,根据自己的业务需要在 Mediasoup 上做二次开发也是非常值得推荐的技术方案。
SRS
https://github.com/ossrs/srs
SRS 是一个简单高效的实时视频服务器,支持 RTMP/WebRTC/HLS/HTTP-FLV/SRT/GB28181。
TODO: 到时候可以去体验一些,目前先用 meidasoup
参考链接
- 从0打造音视频直播系统
- 作者:JinSo
- 链接:https://jinso365.top/article/streaming-knowledge
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。