传输协议
RTMP
该协议是应用层协议,用来解决多媒体数据传输流的多路复用(Multiplexing)和分包(packetizing)的问题。
三种分支类型:
- RTMP: 工作在TCP协议(传输层协议)上的明文传输,它使用的端口是1935;
- RTMPT:用HTTP包装后的协议,可以穿越防火墙进行传输;
- RTMPS:用HTTP包装后的协议,不过与RTMPT不同的是,它使用HTTPS安全连接,可以保证传输的安全。
概念定义
- 载荷(Payload):包含在包中的数据
- 包(Packet):数据包由固定头和载荷数据组成,一些底层协议可能需要对被定义包进行封装
- 端口(Port):TCP/IP端口,由主机号来区分多地址
- 传输地址(Transport address):网络地址和端口的组合
- 消息流(Message stream):消息流通信的逻辑频道
- 消息流ID(Message stream ID):每个消息都有一个预期消息流匹配的id
- 块(Chunk):消息片段。消息在被网络传输前会被分成小的部分,所有的消息会通过多路由时间序端对端传输
- 块流(Chunk stream):通信的逻辑频道允许块以某一特定方向传送,块流可以从客户端传到服务端,也可以从服务端传回客户端
- 块流ID(Chunk stream ID):每个块流都有一个与之匹配的id
- 多路复用(Multiplexing):分离的音视频数据可以连续播放的过程,使得音视频可以同时传送
- 多路分用(DeMultiplexing):多路复用的逆过程,可以将交错的音视频数据聚集成原始的音视频数据
- 远程过程调用(Remote Procedure Call):允许客户端或服务端可以调用另一端服务端或客户端子程序或子进程的请求
- 元数据(Metadata):数据的描述。电影的元数据包括电影标题,时长,上映日期等等。
- 应用实例(Application Instance):客户端可以连接并发送连接请求的服务端实例
- 动作消息格式(Action Message Format):用来序列化AS(ActionScript 动作脚本)实例对象(object graphs)的压缩的二进制格式,有AMF0和AMF3两种版本
握手流程
- 流程图
+---------------+ +---------------+
| Client | TCP/IP Network | Server |
+---------------+ | +---------------+
| | |
Uninitialized | Uninitialized
| C0 | |
| -------------------> | C0 |
| | -------------------> |
| C1 | |
| -------------------> | S0 |
| | <------------------- |
| | S1 |
Version sent | <------------------- |
| S0 | |
| <------------------- | |
| S1 | |
| <------------------- | Version sent
| | C1 |
| | -------------------> |
| C2 | |
| -------------------> | S2 |
| | <------------------- |
Ack sent | Ack sent
| S2 | |
| <------------------- | |
| | C2 |
| | -------------------> |
Handshake Done | Handshake Done
| | |
- 未初始化阶段(Uninitialized):协议版本在这个阶段发送,客户端和服务端都是未初始化的。客户端在C0包中发送协议版本,如果服务端支持这个协议版本,其将会对应发送S0和S1;如果服务端不支持,服务端会采取合适的动作。在RTMP中,这个动作是中止连接。
- 版本发送阶段(Version Sent):在未初始化阶段之后客户端和服务端都处于版本发送阶段。客户端处于等待S1包,服务端处于等待C1包。在收到相应的等待的包后,客户端发送C2而服务端会发送S2,然后进入确认发送阶段。
- 确认发送阶段(Ack Sent):客户端和服务端响应的等待S2和C2
- 握手结束阶段(Handshake Done):客户端和服务端交换消息
-
握手消息的意义
- C0 & S0 : 8位整数段的RTMP版本号。
- C1 & S1 :时间戳+任意数据(长度固定),ack???
- C2 & S2 :时间戳+任意数据(长度固定),用来检测网络延迟
-
消息流(Message stream)
握手完成后,即可以传输相关的数据- 类型
- Command Message(命令消息,Message Type ID=17或20):表示在客户端盒服务器间传递的在对端执行某些操作的命令消息,如connect表示连接对端,对端如果同意连接的话会记录发送端信息并返回连接成功消息,publish表示开始向对方推流,接受端接到命令后准备好接受对端发送的流信息,后面会对比较常见的Command Message具体介绍。当信息使用AMF0编码时,Message Type ID=20,AMF3编码时Message Type ID=17.
- Data Message(数据消息,Message Type ID=15或18):传递一些元数据(MetaData,比如视频名,分辨率等等)或者用户自定义的一些消息。当信息使用AMF0编码时,Message Type ID=18,AMF3编码时Message Type ID=15.
- Shared Object Message(共享消息,Message Type ID=16或19):表示一个Flash类型的对象,由键值对的集合组成,用于多客户端,多实例时使用。当信息使用AMF0编码时,Message Type ID=19,AMF3编码时Message Type ID=16.
- Audio Message(音频信息,Message Type ID=8):音频数据。
- Video Message(视频信息,Message Type ID=9):视频数据。
- Aggregate Message (聚集信息,Message Type ID=22):多个RTMP子消息的集合
- User Control Message Events(用户控制消息,Message Type ID=4):告知对方执行该信息中包含的用户控制事件,比如Stream Begin事件告知对方流信息开始传输。和前面提到的协议控制信息(Protocol Control Message)不同,这是在RTMP协议层的,而不是在RTMP chunk流协议层的,这个很容易弄混。该信息在chunk流中发送时,Message Stream ID=0,Chunk Stream Id=2,Message Type Id=4。
- 类型
-
块流(Chunk stream)
RTMP在收发数据的时候并不是以Message为单位的,而是把Message拆分成Chunk发送,而且必须在一个Chunk发送完成之后才能开始发送下一个Chunk。每个Chunk中带有MessageID代表属于哪个Message,接受端也会按照这个id来将chunk组装成Message。
通过拆分,数据量较大的Message可以被拆分成较小的“Message”,这样就可以避免优先级低的消息持续发送阻塞优先级高的数据,比如在视频的传输过程中,会包括视频帧,音频帧和RTMP控制信息,如果持续发送音频数据或者控制数据的话可能就会造成视频帧的阻塞,然后就会造成看视频时最烦人的卡顿现象。同时对于数据量较小的Message,可以通过对Chunk Header的字段来压缩信息,从而减少信息的传输量。
DASH(Dynamic Adaptive Streaming over HTTP)
简单概括来说,就是在服务器端提前存好同一内容的不同码率、不同分辨率的多个分片以及相应的描述文件MPD,客户端在播放时即可以根据自身性能以及网络环境选择最适宜的版本。更多详细的内容可以参见MPEG组织出台的标准,标准号ISO/IEC 23009-1。
-
MPD 字段意义
-
Period:一条完整的mpeg dash码流可能由一个或多个Peroid组成,每个Period代表一个时间段。比如一个码流是60s,Peroid1是0-10s,Peroid2是11-30,Peroid3是31-60。
-
AdaptationSet:包含了媒体呈现的形式(视频/音频/字幕),AdaptationSet由一组可供切换的不同码率的码流(Representation)组成。
-
Representation:表示不同码率的码流,实际播放的时候,视频会在一个AdaptationSet中的不同Representaiton 之间切换码率,会依次请求该Representaiton下不同Segment序列。
-
Segment:每一个具体的片段。(1,2,4,6,10s …) 。MPD中描述segment URL的形式有多种,如Segment list,Segment template,Single segment。
-
HLS(HTTP Live Streaming)
HTTP Live Streaming(简称 HLS)是一个基于 HTTP 的视频流协议,由 Apple 公司实现,Mac OS 上的 QuickTime、Safari 以及 iOS 上的 Safari 都能很好的支持 HLS,高版本 Android 也增加了对 HLS 的支持。一些常见的客户端如:MPlayerX、VLC 也都支持 HLS 协议。
HLS 协议基于 HTTP,非常简单。一个提供 HLS 的服务器需要做两件事:
- 编码:以 H.263 格式对图像进行编码,以 MP3 或者 HE-AAC 对声音进行编码,最终打包到 MPEG-2 TS(Transport Stream)容器之中;
- 分割:把编码好的 TS 文件等长切分成后缀为 ts 的小文件,并生成一个 .m3u8 的纯文本索引文件;
浏览器使用的是 m3u8 文件。m3u8 跟音频列表格式 m3u 很像,可以简单的认为 m3u8 就是包含多个 ts 文件的播放列表。播放器按顺序逐个播放,全部放完再请求一下 m3u8 文件,获得包含最新 ts 文件的播放列表继续播,周而复始。整个直播过程就是依靠一个不断更新的 m3u8 和一堆小的 ts 文件组成,m3u8 必须动态更新,ts 可以走 CDN。
可以看到 HLS 协议本质还是一个个的 HTTP 请求 / 响应,所以适应性很好,不会受到防火墙影响。但它也有一个致命的弱点:延迟现象非常明显。如果每个 ts 按照 5 秒来切分,一个 m3u8 放 6 个 ts 索引,那么至少就会带来 30 秒的延迟。如果减少每个 ts 的长度,减少 m3u8 中的索引数,延时确实会减少,但会带来更频繁的缓冲,对服务端的请求压力也会成倍增加。所以只能根据实际情况找到一个折中的点。
RTSP
rtsp的能量在UDP传输这块,实际上公网环境下大量的UDP包,容易被防火墙block住,相对靠谱的模式,是rtsp over http tunnel,如果需要web端播放rtsp流的话,需要写插件,而且对浏览器也很挑剔。
rtmp兴起的原因是flash。以前网页要想直播只能flash而不是html5。比如国内网页直播始祖douyutv前身acfun生放送,那时候要想网页直播只能flash,所以rtmp是最好选择。但,rtsp其实比rtmp更复杂,rtsp需要两个连接,一个信令一个rtp数据,更多操心的地方,代码量其实更大。rtmp看似复杂,其实在流媒体直播里面更科学,比如分chunk,可以让音频包不会被大包视频发送所阻塞,但是大部分代码都是一个视频包一次发完,所以这个功能没用上。虽然rtmp有一些冗余设计,但是总规来说rtmp是目前直播协议的最广泛选择。rtsp的udp不适合外网传输,所以在外网下,不存在理论的rtsp比rtmp更快。rtmp如何更低延迟?推送端编码低延迟:h264编码是需要设置为低延迟编码的,如若默认,h264从编码到解码本来的延迟就非常非常大。比如x264,ultrafast zerolatency这些都是实时音视频会议用的。服务器低延迟:等待gop,如果一个服务器在一个新连接上来后,不发送缓存gop而是直接等待,等待下一个gop开始,这样就能到达超低延迟。客户端处理:客户端也需要优化低延迟播放。未来可能有协议替代rtmp,但还需要时间,毕竟obs只支持rtmp。可能未来出现的是udp之上的可靠协议,比如现在已经出现的srt。
RTP and RTCP
RTP协议是一种基于UDP的传输协议,RTP本身并不能为按顺序传送数据包提供可靠的传送机制,也不提供流量控制或拥塞控制,它依靠RTCP提供这些服务。
这样,对于那些丢失的数据包,不存在由于超时检测而带来的延时,同时,对于那些丢弃的包,也可以由上层根据其重要性来选择性的重传。比如,对于I帧、P帧、B帧数据,由于其重要性依次降低,故在网络状况不好的情况下,可以考虑在B帧丢失甚至P帧丢失的情况下不进行重传,这样,在客户端方面,虽然可能会有短暂的不清晰画面,但却保证了实时性的体验和要求。
RTP通常使用UDP协议来实现多媒体的传输
-实时传输协议RTP/RTCP
WebRTC
refrence
自适应流媒体传输(一)——DASH媒体内容的生成
我们为什么使用DASH
为什么现在的视频直播不使用RTSP协议而是使用RTMP?
前端应该了解的RTMP知识
带你吃透RTMP
为何一直推荐WebRTC?
网友评论