前端应该了解的RTMP知识

简介: RTMP是Real Time Messaging Protocol的简称,是基于何时的传输层协议上(如tcp协议)的应用层级别的协议,其设计是为了组包多媒体传输流(如视频,音频以及交互内容)

前端 | 前端应该了解的RTMP知识.png

概述

RTMP是Real Time Messaging Protocol的简称,是基于何时的传输层协议上(如tcp协议)的应用层级别的协议,其设计是为了组包多媒体传输流(如视频,音频以及交互内容)

介绍

RTMP协议是由Adobe公司提出的一种应用层的协议,上面引述的是RTMP官方文档的introduction部分,其目的是为了给诸如视频、音频以及数据消息通信双方提供实时的信息双向流。RTMP在实现上对不同类型的消息实施不同的权重,这样可以实现对当传输量受限时的底层流传输消息进行排队。

定义

  • 载荷(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两种版本

字节序 & 对齐 & 时间格式

所有的整字段以字节序来传输,并且是大端排列,不做特殊说明均为十进制。时间戳以毫秒记,从0开始,32位长;时间间隔用毫秒的无符号整数表示,可能是24或32位长度

RTMP块流

尽管RTMP是被设计用来实时传输消息的,但它也可以用来处理任何消息。RTMP非常适合用于大量的音视频应用,虽然并不会提供任何优化,但却被用于更高级别的协议来进行优化,例如直播视频服务器可能会选择在客户端网速较慢的情况下丢弃视频消息而保证音频消息的实时到达。

消息格式

消息格式可被分成许多块来提供多路复用,这些消息需要包括含以下字段:

字段名 含义 大小
时间戳(Timestamp) 消息的时间戳 4字节
长度(Length) 消息载荷的长度,如果消息头不能被省略,需要包含长度 3字节
类型ID(Type ID) 类型id被用于消息控制 1字节
消息流ID(Message Stream ID) 任意数值,小端存储 4字节

握手

RTMP握手不同于其他协议,它包含3个固定大小的块而不是可变大小的块

握手次序

开始时,客户端发送C0和C1

客户端必须在收到S1才能发送C2,收到S2才能发送任何其他数据

服务端必须等到收到C0才能发送S0和S1,并且最好能在收到C1后。服务端等到收到C1才能发送S2,服务端必须等到收到C2才能发送其他数据

C0 & S0 格式

C0和S0是一个8位组,被认为是一个8位整数段。对C0而言,这个字段被认为是客户端RTMP请求的版本;对S0而言,这个字段被认为是服务端选择的RTMP版本。默认是3,0-2被废弃,4-31被用于未来的版本,32-255没有被允许

 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|   version     |
+-+-+-+-+-+-+-+-+

C1 & S1 格式

C1和S1是一个1536位的长度组,包含如下字段:

字段名 含义 大小
时间(Time) 包含时间戳,可能是0也可能是任意的数值,用于时间标识 4字节
零(Zero) 必须都是0 4字节
任意数据(Random data) 任意数值,并不需要加密 1528字节
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        time (4 bytes)                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        zero (4 bytes)                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         random bytes                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         random bytes                          |
|                             (cont)                            |
|                              ....                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

C2 & S2 格式

C2和S2是一个1536位的长度组,对应S1和C1依次的回复,包含如下字段:

字段名 含义 大小
时间1(Time1) 时间戳,S1(C2发送)或C1(S2发送) 4字节
时间2(Time2) 时间戳,之前S1或C1 4字节
任意数据(Random data) 任意数值,可快速验证连接带宽或延时 1528字节
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        time (4 bytes)                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        time2 (4 bytes)                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         random bytes                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         random bytes                          |
|                             (cont)                            |
|                              ....                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

握手简图

  • 未初始化阶段(Uninitialized):协议版本在这个阶段发送,客户端和服务端都是未初始化的。客户端在C0包中发送协议版本,如果服务端支持这个协议版本,其将会对应发送S0和S1;如果服务端不支持,服务端会采取合适的动作。在RTMP中,这个动作是中止连接。
  • 版本发送阶段(Version Sent):在未初始化阶段之后客户端和服务端都处于版本发送阶段。客户端处于等待S1包,服务端处于等待C1包。在收到相应的等待的包后,客户端发送C2而服务端会发送S2,然后进入确认发送阶段。
  • 确认发送阶段(Ack Sent):客户端和服务端响应的等待S2和C2
  • 握手结束阶段(Handshake Done):客户端和服务端交换消息
+---------------+                             +---------------+
|    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
        |                      |                      |

分块

握手之后,连接便可以进行多路传输块流,每个块携带着一种信息流的一种类型,每块流都有一个独一无二的id即块流id,通过网络传输,每个块必须满载,在接收端会根据id进行重新组装。分块允许通过更高阶的协议进行小信息的分拆,比如可以通过阻止大的低优先级消息(如视频)而阻塞小的高优先级消息(如音频或控制)。分块同样也允许更少的间接消耗将小的消息进行发送,比如块头包含有代表内容的压缩信息,也可能反过来包含在信息之中。块的大小是可配置的,大的块可减少CPU使用,但是却可能由于较多的写操作而带来其他内容低带宽的延迟,小的块不适合高比特流的传输,块的大小在每个方向上独立保持。

块格式

每个块包含头和数据,头包含三部分:

字段名 含义 大小
基础头(Basic Header) 块流id和块类型 1或3字节
消息头(Message Header) 消息的主要内容 0,3,7或11字节
扩展时间戳(Extended Timestamp) 某种情境下的时间戳 0或4字节
块数据(Chunk Data) 块的载荷 可变字节
+---------------+----------------+--------------------+----------------+
|  Basic Header | Message Header | Extended Timestamp |   Chunk Data   |
+---------------+----------------+--------------------+----------------+
|                                                     |
| <------------------ Chunk Header -----------------> |
                              Chunk Format

1.块基本头

有三种类型:

字段名 含义 大小
块流id(cs id) 数值2~63 6位
格式(fmt) 格式标识 2位
块流id-64(cs id - 64) 数值减去64 8或16位

块基础头1:

 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|fmt|   cs id   |
+-+-+-+-+-+-+-+-+

块基础头2:

 0                   1
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|fmt|     0     |   cs id - 64  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

块基础头3:

 0                   1                   2
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|fmt|     1     |           cs id - 64          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

2.块消息头

有四种类型:

Type 0:11字节

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                   timestamp                   | message length|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   message length (cont)       |message type id| msg stream id |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            message stream id (cont)           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                 Chunk Message Header - Type 0

Type 1:7字节

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|              timestamp delta                  | message length|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   message length (cont)       |message type id| 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                 Chunk Message Header - Type 1

Type 2:3字节

 0                   1                   2      
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|              timestamp delta                  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         Chunk Message Header - Type 2

Type 3:没有头

公共头字段:

字段名 含义 大小
事件戳间隔(timestamp delta) 类型1或类型2 3字节
消息长度(message length) 类型0或类型1 3字节
消息类型id(message type id) 类型0或类型1 1字节
消息流id(message stream id) 类型0 4字节

3.扩展时间戳

当时间戳大于 16777215(0xFFFFFF)时使用

协议控制消息

消息类型ID为1,2,3,5,6是协议控制消息,这些内容需要块流协议做基础

设置块大小

用于提示设置最大字节,最大128字节,服务端和客户端可以修改这个值,并升级另一端的大小

中止消息

用于提示等待完成消息,之后丢弃部分接收的消息

识别

当接收字节和视窗大小相同时,客户端或服务端必须发送给对应端确认消息

视窗识别大小

当进行确认时,客户端或服务端发送给对应端视窗大小

设置端带宽

客户端和服务端向对应端发送输出限制

RTMP消息格式

RTMP可用各种传输层协议

RTMP消息

消息可以包含音频,视频,数据以及其他消息格式


1.消息头

包含消息类型,长度,时间戳,消息流id


2.消息载荷

实际消息承载内容

用户控制消息

消息类型为4

RTMP命令消息

客户端和服务端的消息相互操作

消息类型


1.命令消息

AMF0格式值为20 AMF3格式值为17


2.数据消息

AMF0格式值为18 AMF3格式值为15


3.共享对象消息

AMF0格式值为19 AMF3格式值为16


4.音频消息

值为8


5.视频消息

值为9


6.聚合消息

值为22


7.用户控制消息事件

命令类型


1.网络连接命令

连接 调用 创建流


2.网络流命令

播放 播放2 删除流 接收音频 接收视频 发布 寻址 暂停

参考

相关文章
|
3天前
|
编解码 Android开发 iOS开发
HLS直播协议详解
HLS直播协议详解
49 2
|
8月前
|
编解码 开发工具 Android开发
rtmp/rtsp直播播放器选择
相信大家在做rtmp、rtsp直播的时候,最大的困惑就是选个靠谱的播放器,直播的延迟,一定意义上说,90%的取决于播放器的好坏。
194 0
|
7月前
|
网络协议 网络安全 流计算
【流媒体】RTMP、RTSP、HLS、HTTP协议的介绍与对比
【流媒体】RTMP、RTSP、HLS、HTTP协议的介绍与对比
232 0
|
8月前
|
编解码 监控 开发工具
RTMP/RTSP直播播放器的几种选择
播放网络视频,通常解析库我们可以有多个选择,如FFMPEG,Daniulive SDK 或者 vitamio。
186 1
|
8月前
|
存储 开发工具 Android开发
如何实现Android端获取RTSP|RTMP流转推RTMP
技术背景 最近不少开发者找到我们,他们在做智能家居等传统行业时,希望实现在Android板件拉取本地的RTSP或RTMP流,然后对外推送RTMP出去,亦或内部启个轻量级RTSP服务,提供个对外对接的媒介URL,简单来说,设计架构图如下:
457 0
|
8月前
|
开发工具 Android开发 iOS开发
跨平台RTSP/RTMP转RTMP转发SDK
一个好的转发模块,首先要低延迟!其次足够稳定、灵活、有状态反馈机制、资源占用低,如果可以跨平台,还能以SDK形式提供,会给开发者提供更大的便利!
142 0
|
8月前
|
存储 编解码 开发工具
RTMP/RTSP推送端和RTMP/RTSP播放端录像设计探讨
好多开发者认为,无论是RTSP/RTMP推送端还是RTSP/RTMP播放端,涉及到录像,只要2个接口足矣:开始录像、停止录像。
|
8月前
|
Web App开发 开发工具 Android开发
利用RTMP或RTSP实现跨平台一对一互动功能
目前市面上大多一对一互动都是基于WebRTC,缺点如下: 1. 服务器部署非常复杂,不利于私有部署,在一些私密性高的场景下,无法使用,如公安、市政等体系; 2. 传输基于UDP,很难保证传输质量,由于UDP是不可靠的传输协议,在复杂的公网网络环境下,各种突发流量、偶尔的传输错误、网络抖动、超时等等都会引起丢包异常,都会在一定程度上影响音视频通信的质量; 3. 难以应对复杂的互联网环境,如跨区跨运营商、低带宽、高丢包等场景; 4. 整个框架体系不够灵活,代码复杂度高,行话说的好:从demo到实用,中间还差1万个WebRTC。
|
10月前
|
编解码 应用服务中间件 nginx
RTSP协议转换RTMP直播协议
RTSP协议转换RTMP直播协议
458 1
|
Web App开发 编解码 移动开发
秒懂流媒体协议 RTMP 与 RTSP
RTMP 与 RTSP 是比较常见的两种流媒体协议,那么什么是RTMP?什么是RTSP?它们两之间有什么区别?使用的时候应该如何选择?
670 1
秒懂流媒体协议 RTMP 与 RTSP