前端应该了解的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 删除流 接收音频 接收视频 发布 寻址 暂停

参考

相关文章
|
2月前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
188 2
|
2月前
|
JavaScript 前端开发 程序员
前端学习笔记——node.js
前端学习笔记——node.js
54 0
|
2月前
|
人工智能 自然语言处理 运维
前端大模型应用笔记(一):两个指令反过来说大模型就理解不了啦?或许该让第三者插足啦 -通过引入中间LLM预处理用户输入以提高多任务处理能力
本文探讨了在多任务处理场景下,自然语言指令解析的困境及解决方案。通过增加一个LLM解析层,将复杂的指令拆解为多个明确的步骤,明确操作类型与对象识别,处理任务依赖关系,并将自然语言转化为具体的工具命令,从而提高指令解析的准确性和执行效率。
|
2月前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。
|
2月前
|
机器学习/深度学习 弹性计算 自然语言处理
前端大模型应用笔记(二):最新llama3.2小参数版本1B的古董机测试 - 支持128K上下文,表现优异,和移动端更配
llama3.1支持128K上下文,6万字+输入,适用于多种场景。模型能力超出预期,但处理中文时需加中英翻译。测试显示,其英文支持较好,中文则需改进。llama3.2 1B参数量小,适合移动端和资源受限环境,可在阿里云2vCPU和4G ECS上运行。
130 1
|
2月前
|
前端开发 算法 测试技术
前端大模型应用笔记(五):大模型基础能力大比拼-计数篇-通义千文 vs 文心一言 vs 智谱 vs 讯飞vsGPT
本文对比测试了通义千文、文心一言、智谱和讯飞等多个国产大模型在处理基础计数问题上的表现,特别是通过链式推理(COT)提示的效果。结果显示,GPTo1-mini、文心一言3.5和讯飞4.0Ultra在首轮测试中表现优秀,而其他模型在COT提示后也能显著提升正确率,唯有讯飞4.0-Lite表现不佳。测试强调了COT在提升模型逻辑推理能力中的重要性,并指出免费版本中智谱GLM较为可靠。
前端大模型应用笔记(五):大模型基础能力大比拼-计数篇-通义千文 vs 文心一言 vs 智谱 vs 讯飞vsGPT
|
3月前
|
SpringCloudAlibaba JavaScript 前端开发
谷粒商城笔记+踩坑(2)——分布式组件、前端基础,nacos+feign+gateway+ES6+vue脚手架
分布式组件、nacos注册配置中心、openfegin远程调用、网关gateway、ES6脚本语言规范、vue、elementUI
谷粒商城笔记+踩坑(2)——分布式组件、前端基础,nacos+feign+gateway+ES6+vue脚手架
|
4月前
|
存储 前端开发 JavaScript
前端语言串讲 | 青训营笔记
前端语言串讲 | 青训营笔记
51 0
|
6月前
|
JSON 前端开发 JavaScript
前端Ajax、Axios和Fetch的用法和区别笔记
前端Ajax、Axios和Fetch的用法和区别笔记
121 2
|
6月前
|
前端开发 JavaScript 数据库
如何实现前后端分离-----前端笔记
如何实现前后端分离-----前端笔记