RTMP协议详解及实例分析

RTMP协议是一种实时信息传输协议,用于处理多媒体数据的传输。协议内容涉及字节序、对齐、时间格式、分块、消息格式、消息类型等。在播放RTMP流时,包括握手、建立网络连接、创建流和播放等多个步骤。客户端通过发送连接、创建流、播放等命令与服务器交互,服务器则通过控制消息、设置带宽、发送音频视频数据进行响应。RTMP消息类型包括命令消息、数据消息、共享对象消息、音频和视频消息等。
摘要由CSDN通过智能技术生成

1、简介

       RTMP协议是Real Time Message Protocol(实时信息传输协议)的缩写,它是由Adobe公司提出的一种应用层的协议,用来解决多媒体数据传输流的多路复用(Multiplexing)和分包(packetizing)的问题。实现通常对不同类型的消息分配不同的优先级,当运载能力有限时,这会影响等待流传输的消息的次序。

       RTMP协议是应用层协议,是要靠底层可靠的传输层协议(通常是TCP)来保证信息传输的可靠性的。在基于传输层协议的链接建立完成后,RTMP协议也要客户端和服务器通过“握手”来建立基于传输层链接之上的RTMP Connection链接,在Connection链接上会传输一些控制信息,如SetChunkSize,SetACKWindowSize。其中CreateStream命令会创建一个Stream链接,用于传输具体的音视频数据和控制这些信息传输的命令信息。RTMP协议传输时会对数据做自己的格式化,这种格式的消息我们称之为RTMP Message,而实际传输的时候为了更好地实现多路复用、分包和信息的公平性,发送端会把Message划分为带有Message ID的Chunk,每个Chunk可能是一个单独的Message,也可能是Message的一部分,在接收端会根据chunk中包含的data的长度,message id和message的长度把chunk还原成完整的Message,从而实现信息的收发。

 

2、定义

  • Payload (有效载荷)一个数据包或者其它传输单元中运载的基本必要数据,例如音频采样或者压缩的视频数据。
  • Packet (数据包)一个数据包由一个固定头和有效载荷数据构成。一些底层协议可能会要求对数据包定义封装。
  • Port (端口)"传输协议用以区分开指定一台主机的不同目的地的一个抽象。TCP/IP 使用小的正整数对端口进行标识。" OSI 传输层使用的运输选择器 (TSEL) 相当于端口。
  • Transport address (传输地址)用以识别传输层端点的网络地址和端口的组合,例如一个 IP 地址和一个 TCP 端口。数据包由一个源传输地址传送到一个目的传输地址。
  • Message stream (消息流)通信中消息流通的一个逻辑通道。
  • Message stream ID (消息流 ID)每个消息有一个关联的 ID,使用 ID 可以识别出流通中的消息流。
  • Chunk ()消息的一段。消息在网络发送之前被拆分成很多小的部分。块可以确保端到端交付所有消息有序 timestamp,即使有很多不同的流。
  • Chunk stream (块流)通信中允许块流向一个特定方向的逻辑通道。块流可以从客户端流向服务器,也可以从服务器流向客户端。
  • Chunk stream ID (块流 ID)每个块有一个关联的 ID,使用 ID 可以识别出流通中的块流。
  • Multiplexing (合成)将独立的音频/视频数据合成为一个连续的音频/视频流的加工,这样可以同时发送几个视频和音频。
  • DeMultiplexing (分解)Multiplexing 的逆向处理,将交叉的音频和视频数据还原成原始音频和视频数据的格式。
  • Remote Procedure Call (RPC 远程方法调用)允许客户端或服务器调用对端的一个子程序或者程序的请求。
  • Metadata (元数据)关于数据的一个描述。一个电影的 metadata 包括电影标题、持续时间、创建时间等等。
  • Application Instance (应用实例)服务器上应用的实例,客户端可以连接这个实例并发送连接请求。
  • Action Message Format (AMF 动作消息格式协议)一个用于序列化 ActionScript 对象图的紧凑的二进制格式。AMF 有两个版本:AMF 0 [AMF0] 和 AMF 3 [AMF3]。

 

3、字节序、对齐和时间格式

(1)字节序

        所有整数型属性以网络字节顺序传输,字节 0 代表第一个字节,零位是一个单词或字段最常用的有效位。字节序通常是大端排序。关于传输顺序的更多细节描述参考 IP 协议[RFC0791]。

(2)对齐

       除非另有规定,RTMP 中的所有数据都是字节对准的;例如,一个十六位的属性可能会在一个奇字节偏移上。填充后,填充字节应该有零值。

(3)时间格式

       RTMP 中的 Timestamps 以一个整数形式给出,表示一个未指明的时间点。典型地,每个流会以一个为 0 的 timestamp 起始,但这不是必须的,只要双端能够就时间点达成一致。注意这意味着任意不同流 (尤其是来自不同主机的) 的同步需要 RTMP 之外的机制。

  因为 timestamp 的长度为 32 位,每隔 49 天 17 小时 2 分钟和 47.296 秒就要重来一次。因为允许流连续传输,有可能要多年,RTMP 应用在处理 timestamp 时应该使用序列码算法 [RFC1982],并且能够处理无限循环。例如,一个应用假定所有相邻的 timestamp 都在 2^31 - 1 毫秒之内,因此 10000 在 4000000000 之后,而 3000000000 在 4000000000 之前。

  timestamp 也可以使用无符整数定义,相对于前面的 timestamp。timestamp 的长度可能会是 24 位或者 32 位。

 

4、分块

       RTMP中创建的每个块都有一个唯一 ID 对其进行关联,这个 ID 叫做 chunk stream ID (块流 ID)。这些块通过网络进行传输。传递时,每个块必须被完全发送才可以发送下一块。在接收端,这些块被根据块流 ID 被组装成消息

  分块允许上层协议将大的消息分解为更小的消息,例如,防止体积大的但优先级小的消息 (比如视频) 阻碍体积较小但优先级高的消息 (比如音频或者控制命令)。

  分块也让我们能够使用较小开销发送小消息,因为块头包含包含在消息内部的信息压缩提示。

  块的大小是可以配置的。它可以使用一个设置块大小的控制消息进行设置 。更大的块大小可以降低 CPU 开销,但在低带宽连接时因为它的大量的写入也会延迟其他内容的传递。更小的块不利于高比特率的流化。所以块的大小设置取决于具体情况。

(1)块格式

       每个块包含一个头和数据体。块头包含三个部分:

 

  • Basic Header (基本头,1 3 个字节)这个字段对块流 ID 和块类型进行编码。块类型决定了消息头的编码格式。(这一字段的) 长度完全取决于块流 ID,因为块流 ID 是一个可变长度的字段。RTMP 协议最多支持 65597 个流,流 ID 范围 3 - 65599。
  • Message Header (消息头,037,或者 11 个字节)这一字段对正在发送的消息 (不管是整个消息,还是只是一小部分) 的信息进行编码。这一字段的长度可以使用块头中定义的块类型进行决定。消息头有四种不同的格式,由块基本头中的 "fmt" 字段进行选择。

类型 0 11 个字节。这一类型必须用在块流的起始位置,和流 timestamp 重来的时候 (比如,重置)。

类型 1 7 个字节。不包含消息流 ID;这一块使用前一块一样的流 ID。可变长度消息的流 (例如,一些视频格式) 应该在第一块之后使用这一格式表示之后的每个新消息。

类型 2 3 个字节。既不包含流 ID 也不包含消息长度;这一块具有和前一块相同的流 ID 和消息长度。具有不变长度的消息 (例如,一些音频和数据格式) 应该在第一块之后使用这一格式表示之后的每个新消息。

类型 3 没有消息头。流 ID、消息长度以及 timestamp delta 等字段都不存在;这种类型的块使用前面块一样的块流 ID。当单一一个消息被分割为多块时,除了第一块的其他块都应该使用这种类型。

  • Extended Timestamp (扩展 timestamp0 4 字节)这一字段是否出现取决于块消息头中的 timestamp 或者 timestamp delta 字段。扩展 timestamp 字段主要用于对大于 16777215 (0xFFFFFF) 的 timestamp 或者 timestamp delta 进行编码;也就是,对于不适合于在 24 位的类型 0、1 和 2 的块里的 timestamp 和 timestamp delta 编码。
  • Chunk Data (有效大小)当前块的有效负载,相当于定义的最大块大小。

 

5、RTMP消息格式

       RTMP 协议设计使用 RTMP 块流,可以使用其他任意传输协议对消息进行发送。服务器端和客户端通过网络发送 RTMP 消息来进行彼此通信。消息可以包含音频、视频、数据,或者其他消息。RTMP 消息有两部分:头和它的有效载荷。

(1)消息头

 

 消息头包含以下:

       Timestamp(时间戳):对于一个类型 1 或者类型 2 的块,前一块的 timestamp 和当前块的 timestamp 的区别在这里发送。如果 delta 大于或者等于 16777215 (十六进制 0xFFFFFF),那么这一字段必须是为 16777215,表示具有扩展 timestamp 字段来对整个 32 位 delta 进行编码。否则的话,这一字段应该是为具体 delta。

       Length (长度)对于一个类型 0 或者类型 1 的块,消息长度在这里进行发送。注意这通常不同于块的有效载荷的长度。块的有效载荷代表所有的除了最后一块的最大块大小,以及剩余的 (也可能是小消息的整个长度) 最后一块。

       Message Type Id (消息类型)对于类型 0 或者类型 1 的块,消息的类型在这里发送。类型 ID 1 - 6 被保留用于协议控制消息。这些传播信息的消息由 RTMP 块流协议和上层协议共同处理。其他的所有类型 ID 可用于上层协议,它们被 RTMP 块流处理为不透明值。事实上,RTMP 块流中没有任何地方要把这些值当做类型使用;所有消息必须是同一类型,或者应用使用这一字段来区分同步跟踪,而不是类型。

       Message Stream Id (消息流 ID)对于一个类型为 0 的块,保存消息流 ID。消息流 ID 以小端格式保存。所有同一个块流下的消息都来自同一个消息流。当可以将不同的消息流组合进同一个块流时,这种方法比头压缩的做法要好。但是,当一个消息流被关闭而其他的随后另一个是打开着的,就没有理由将现有块流以发送一个新的类型 0 的块进行复用了。message stream (消息流) ID 可以使任意值。合并到同一个块流的不同的消息流是根据各自的消息流 ID 进行分解。除此之外,对 RTMP 块流而言,这是一个不透明的值。

(2)有效载荷

       消息的另一个部分就是有效负载,这是这个消息所包含的实际内容。例如,它可以是一些音频样本或者压缩的视频数据。

例:

 

6、RTMP消息类型

       服务器端和客户端交换的不同消息类型包括用于发送音频数据的音频消息、用于发送视频数据的视频消息、用于发送任意用户数据的数据消息、共享对象消息以及命令消息。共享对象消息提供了一个通用的方法来管理多用户和一台服务器之间的分布式数据。命令消息在客户端和服务器端传输 AMF 编码的命令。客户端或者服务器端可以通过使用命令消息和对端通信的流请求远程方法调用 (RPC)。

       服务器端和客户端通过在网络中发送消息来进行彼此通信。消息可以是任何类型,包含音频消息,视频消息,命令消息,共享对象消息,数据消息,以及用户控制消息。

(1)命令消息(20,17)

       命令消息在客户端和服务器端传递 AMF 编码的命令。这些消息被分配以消息类型值为 20 以进行 AMF0 编码,消息类型值为 17 以进行 AMF3 编码。这些消息发送以进行一些操作,比如,连接,创建流,发布,播放,对端暂停。命令消息,像 onstatus、result 等等,用于通知发送者请求的命令的状态。一个命令消息由命令名、事务 ID 和包含相关参数的命令对象组成。一个客户端或者一个服务器端可以通过和对端通信的流使用这些命令消息请求远程调用 (RPC)。

(2)数据消息 (18, 15)

       客户端或者服务器端通过发送这些消息以发送元数据或者任何用户数据到对端。元数据包括数据 (音频,视频等等) 的详细信息,比如创建时间,时长,主题等等。这些消息被分配以消息类型为 18 以进行 AMF0 编码和消息类型 15 以进行 AMF3 编码。

(3)共享对象消息 (19, 16)

       所谓共享对象其实是一个 Flash 对象 (一个名值对的集合),这个对象在多个不同客户端、应用实例中保持同步。消息类型 19 用于 AMF0 编码、16 用于 AMF3 编码都被为共享对象事件保留。每个消息可以包含有不同事件。

 

支持以下事件类型:

事件

描述

Use(=1)

客户端发送这一事件以通知服务器端一个已命名的共享对象已创建。

Release(=2)

当共享对象在客户端被删除时客户端发送这一事件到服务器端。

Request Change (=3)

客户端发送给服务器端这一事件以请求共享对象的已命名的参数所关联到的值的改变。

Change (=4)

服务器端发送这一事件已通知发起这一请求之外的所有客户端,一个已命名参数的值的改变。

Success (=5)

如果请求被接受,服务器端发送这一事件给请求的客户端,以作为 RequestChange 事件的响应。

SendMessage (=6)

客户端发送这一事件到服务器端以广播一条消息。一旦接收到这一事件,服务器端将会给所有的客户端广播这一消息,包括这一消息的发起者。

Status (=7)

服务器端发送这一事件以通知客户端异常情况。

Clear (=8)

服务器端发送这一消息到客户端以清理一个共享对象。服务器端也会对客户端发送的 Use 事件使用这一事件进行响应。

Remove (=9)

服务器端发送这一事件有客户端删除一个 slot

Request Remove (=10)

客户端发送这一事件有客户端删除一个 slot

Use Success (=11)

服务器端发送给客户端这一事件表示连接成功。

(4)音频消息 (8)

       客户端或者服务器端发送这一消息以发送音频数据到对端。消息类型 8 为音频消息保留。

(5)视频消息 (9)

       客户端或者服务器发送这一消息以发送视频数据到对端。消息类型 9 为视频消息保留。

(6)统计消息 (22)

       统计消息是一个单一的包含一系列的使用 6.1 节描述的 RTMP 子消息的消息。消息类型 22 用于统计消息。

 

  统计消息的消息流 ID 覆盖了统计中子消息的消息流 ID。

       统计消息里的 timestamp 和第一个子消息的 timestamp 的不同点在于子消息的 timestamp 被相对流时间标调整了偏移。每个子消息的 timestamp 被加入偏移以达到一个统一流时间。第一个子消息的 timestamp 应该和统计消息的 timestamp 一样,所以这个偏移量应该为 0。

  反向指针包含有前一个消息的大小 (包含前一个消息的头)。这样子匹配了 FLV 文件的格式,用于反向查找。

  使用统计消息具有以下性能优势:

  • 块流可以在一个块中以至多一个单一完整的消息发送。因此,增加块大小并使用统计消息减少了发送块的数量。
  • 子消息可以在内存中连续存储。在网络中系统调用发送这些数据时更高效。

(7)用户控制消息事件

       客户端或者服务器端发送这一消息来通知对端用户控制事件。

  支持以下用户控制事件类型:

事件

描述

Stream Begin (=0)

服务器发送这个事件来通知客户端一个流已就绪并可以用来通信。默认情况下,这一事件在成功接收到客户端的应用连接命令之后以 ID 0 发送。这一事件数据为 4 字节,代表了已就绪流的流 ID

Stream EOF (=1)

服务器端发送这一事件来通知客户端请求的流的回放数据已经结束。在发送额外的命令之前不再发送任何数据。客户端将丢弃接收到的这个流的消息。这一事件数据为 4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值