rtmp 时间戳_流媒体传输协议之RTMP
引言
本文旨在系统地归纳与总结多种流媒体传输技术
简介
RTMP基于可靠流式传输(TCP)实现了双向的消息多路复用服务,在通讯双方之间传输与时间相关的实时同步的数据流。这些数据流包括音频、视频以及各种类型的数据消息。协议实现方通常为不同类型的报文赋予不同的传输优先权,在信道资源受限的情况下能够优化数据的传输顺序
定义
- 负载:包中所携带的数据信息。
- 包:一个数据包由固定的头部字段和所携带的数据组成。
- 端口:在一个计算机系统中用于区分不同目标的抽象标识符。在TCP/IP协议中用一个小整数来表示端口功能。
- 传输地址:标识一个传输终端网络地址和端口组合的具体数值。
- 消息流:允许消息传播的信息传输路径。
- 消息流ID:为每个消息流分配唯一的标识符。
- 块:消息的一个片段化部分,在传输前会按照大小分割开来以便管理。
- 块流:块沿着确定方向传播的信息传输路径。
- 块流ID:为每个块流分配唯一的标识符。
- 复用:将独立音频/视频数据整合为统一音视频流以实现多路同步传输。
- 复用分离:实现音视频数据分离的技术过程。
- 远程过程调用:客户端或服务端向另一方发起特定功能模块调用请求的操作过程。
- 元数据:媒体数据的相关描述信息资料集。
- 应用实例:服务器端与客户端之间建立连接的应用程序实例实例化对象。
- 动作消息格式:一种紧凑二进制格式序列化ActionScript对象图结构的方式方法。
- 字节序:多字节数据在内存中的排列顺序方式规定标准.
- 大字节序定义为高位字节存储在内存低地址位置低位字节存放在高地址位置.
- 小字节序定义为低位字节存储在内存低地址位置高位字节存放在高地址位置.
字节序,校准,时间格式
所有整数都采用网络字节序进行编码。除非另有特别说明,默认情况下所述数字均为十进制数值。在无特殊注明的情况下,默认RTMP数据块进行齐次处理。若需填充,则补充的字节字段应填以零值。RTMP系统中使用单一整数来表示时间戳,默认基于参考时间点计算毫秒值。一般而言,默认从零开始计时各流的时间戳,并非强制性要求。需要注意的是,在不同主机间实现流间同步需附加特定协议机制。因为单个时间戳字段仅占用32位数值空间,在此限制下其最大有效周期约为50天。而流可以无限持续运行直至完成漫长过程。因此,在处理RTMP应用中的时间戳时建议采用连续增量算法,并支持循环机制举例而言,在相邻事件间隔超过2^31-1毫秒时建议采用循环计数策略
RTMP块流
上层流媒体协议可借助块流实现数据的分组与重传。RTMP块流最初是为了与RTMP协议协同工作的设计工具,但其机制也适用于其他消息传输协议。每个消息都携带时间戳以及所传输的数据类型标识。结合使用RTMP块流与RTMP协议能够满足多种音视频应用的需求...当采用可靠传输机制(如TCP)时...该方案本身不具备优先级管理功能...例如,在某些客户端网络速度较慢的情况下,可能会选择丢弃部分视频数据以确保音频数据能够及时接收...除了自带的消息分发机制外,该方案还提供了用户自定义消息控制的功能,以便在需要时进行调整。
消息格式
由上层协议定义的消息格式中规定了多种数据字段以支持多路复用机制。具体包括以下几个关键字段:时间戳字段为4字节;长度字段为3字节;类型标识符字段为1字节;消息流标识符字段为4字节。这些字段分别用于标识事件发生的时间、数据总量、事件类别以及通信渠道信息等信息。
握手
RTMP连接通过握手机制启动,在这种情况下,默认情况下它会经历一种特定类型的初始阶段。通常情况下,这种类型的连接建立时会经历不同的握手流程。其中的握手过程包括三个预先定义好的数据段,并不包含可变长度的数据段以及附加的一个固定的头部标识符来完成同样的任务。
握手流程
握手过程始于客户端发送包含C0和 C1 的数据块;只有在接收完整 S1 后才能传输 C2;一旦获得 S2 即可开始传输除 S2 外的所有数据;服务端在接收 C0 后即可回复 S0 和 S1;此外,在接收 C1 后也可立即回复 S2;完成 S2 发送后即可继续传递后续请求数据
C0和S0格式
C0和S0是单独的一个字节,可以当做一个8bit的整数字段来对待。

本段将详细阐述CO包与S0包中的字段定义及其用途。其中,在CO(Call Origin)包中该字段用于标识客户端所报RTMP协议的具体版本号;而在S0(Session Origin)包中则用于指定服务器所选择采用的RTMP协议版本号。根据本规范的规定,默认采用的标准版本号为3;而可选值范围被划分为几个区间:其中,在此规范下规定标准版本号为3;而可选值范围被划分为几个区间:其中,在此规范下规定标准 versions are defined as follows:
C1和S1格式
C1和S1包固定为1536字节,包含以下字段:

- 时间戳字段(占4个字节):此字段存储一个时间戳。
为了同步多个块流端点可能会发送其他块流的时间戳 - 零标志位(占4个字节):此字段的所有位必须设为0
- 随机数段(长度1528个字节):此段可以包含任何数值
通过这个段来区分自己与连接的另一方
所以此数据应具备充分的随机性
但无需采用加密安全或动态生成的随机数值
C2和S2格式
C2和S2包的长度也为1536字节,基本上是S1和C1的回传,包含以下字段:

- 时间戳(4字节):该字段应包含来自发送端的时戳信息(对C2而言是S1端口,在S2上是C1端口)。- 时间2(4字节):该字段应包含已读取的前一个数据包的时戳信息。(对C2来说是S1端口,在S2上是C1端口)。- 随机数据回显(1528字节):该字段应包含接收方发送过来的随机数据字段值(对C2而言是S1端口,在S2上是C1端口)。任何一端均可通过时间戳、时间戳2两个字段值以及当前时间戳来估算网络带宽和延迟性能参数;然而这种方法虽然可行但不够实用。
握手流程示意图

上图描述的状态解释如下:
- 未初始化阶段:处于未初始化状态的客户端与服务器之间进行通信。
在该状态下: - 客户端于C0包中发送RTMP协议版本。
如果服务器接受该版本,则服务器将在响应中返回S0和S1包。
若服务器不接受该版本,则采用适当的行为进行响应,在RTMP规范下会终止连接。 - 版本发送完成:客户端与服务器均处于版本已发送状态。
客户端等待接收S1包;
服务端等待接收C1包。
双方接收到所需包后: - 客户端发送C2包;
服务端发送S2包;
随后进入发送确认状态。 - 确认发送完毕:客户端与服务端等待接收S2和C2包;
接收到这些包后,
双方进入握手完成状态。 - 握手完成:客户端与服务端开始进行消息交换。
分块
完成握手后,在传输层中允许多个块流复用同一个连接口。每个连接口负责传输自同一条消息链路的消息类型。数据传输必须遵循顺序原则,在发送下一个数据包前必须确保前一个已成功交付。接收端根据每个数据包中的标识字段重组相关数据。按分段机制将大消息划分为小段数据。确保高效率地处理不同任务流量,在优先级管理上做到层次分明。减少不必要的通信开销,在头信息编码上进行优化处理。通过附加信息位压缩原生的消息内容。增大分段长度可减少CPU负担;同时在带宽受限时,则适当减小每份分段长度以适应需求变化;对于比特率较高的场景则不适用
块格式
每个块由块头和数据组成,块头包含3部分:基本头、消息头和扩展时间戳。

- 块流标识符与数据类型:数据类型的选定决定了后续的消息头部编码格式。
- 消息头部(0、3、7或11个字节):该部分用于传输信息的描述部分。
- 扩展时间戳(0或4字节):仅在特定条件下使用(当时间戳超出指定范围时)。
- 变长字段:实际传输的有效数据部分。
- 最大长度为配置的块大小
基本头
由块流ID及所属块类型(图中 fmt字段标识)构成的基本头信息决定了消息头部编码格式,在此规范下基本头字段长度可能取值为1、2或3个字节。根据相关协议规定建议采用最短编码方式来标识块流ID。RTMP通信协议支持最多65,597个数据流且其唯一标识码范围为0至65,598。其中当该唯一标识码处于0、1、2时则对应保留字段不作实际使用。对于具体标识码范围划分如下:若前七位二进制数值中第2至第7位所代表十进制数值为0则表明该唯一标识码对应的字段占用两个字节且其值域范围限定在64至319之间(即第二字节数值与64之和)。而若第2至第7位二进制数值计算结果等于1则表明该唯一标识码对应的字段占用三个字节且其值域范围限定在64至65,599之间(即第三字节数值乘以256后加上第二字节数值再加64所得之总和)。至于那些前七位二进制数值介于2至第63之间的唯一标识码可以直接取用前七位数值作为数据源编码。

在64-319范围内使用的块流ID采用2个字节进行编码表示;其中块流ID值即通过计算获得;具体公式如下:第二个字节的数值加上64;

在64-65599范围内的块流ID由3个字节来表示;这些块流ID是由计算得出的;具体公式如下:{第三个字节值×255 + 第二个字节值 + 64}。

上述图中各个部分的具体含义如下:
- 完整块流ID字段(共6位):标识完整块流的唯一标识符。其中数值范围限定在2至63之间。
- 其中两个特殊保留值(编码为0,1)分别用于区分基本头长度为2字节或3字节。
- fmt:该字段明确了消息头所采用的数据格式。
- 完整块流ID分为两部分:
- 前半部分为CS ID-64(占8或16位)
- 后半部分则标识完整的块流ID
64-319范围内的块流ID可以用2字节来表示,也可以用3字节表示。
消息头
消息头分为四种不同的格式形式;这些格式由basic header中的 'format'字段值决定;协议实现方应当采用最简练的方式呈现块的消息头
类型0
第0类块消息头占用11个字节长度,并且在每个视频编码流程中,在每次块流时间戳发生回退时(如视频回退操作),必须将该类型放置在每个块流的开头位置

- timestamp(3字节):在0类型的消息块中,用于发送消息的绝对时间戳字段在这里生效。若时间戳值大于等于16777215,则该字段值应设置为16777215,并需配合扩展时间戳共同编码32位的时间戳信息。
- message length(3字节): 这些类型的消息块都包含此字段以表示消息的长度。值得注意的是,在这些块中除了最后一个块外的所有块都与最大长度相同。
- message type id(3字节): 消息类型id字段用于标识这些类型的的消息。
- message stream id(4字节): 消息流ID字段用于标识消息流ID,在类型0的消息块中使用此字段表示消息流ID。
类型1
1类型的块占据7字节长度而不携带任何消息流标识码,并持续采用前一条消息的消息流标识码。对于采用大小可变数据流量(如多数视频格式)的数据流量,在发送第一条数据包后应持续采用本类型的数据包格式。

- timestamp difference (3 bytes): 时间戳差异 (3个字节)。类型1和类型2的块包含此字段,表示上一个块的时间戳字段与当前块的时间戳之间的差异。 如果时间戳差异大于或等于16777215(0xFFFFFF),该字段必须设置为16777215,并且必须设置扩展时间戳以共同表示32位的时间戳差异;否则该字段存储实际的时间戳差异。
类型2
采用2种类型的块消息头占据3个字节长度,并未包含任何关于数据流标识符或信息量的内容,并延续上一周期的消息标识符及信息量。
适用于传输固定容量信息的数据流(例如数字音频与数据包),在发送第一个数据单元之后的所有后续数据单元必须采用相同的形式。

类型3
3类块不包含任何消息头信息;每个块都包含的消息流ID、消息长度以及时间戳增量会被记录;这些块共享与前一个块相同的头部数据。当一条消息被分割为多个块时,在分割后的第一个块之后的所有后续分段都需要按照该类型格式进行处理;从第二个分段起的所有后续分段都应遵循该类型规则;对于由相同大小、相同的消息流ID以及一致的时间间隔组成的消息流,在经过Type 2格式处理后所有后续分段都应该采用本类型编码方式;如果第一个分段与第二个分段之间的时延增量等于第一个分段的时间戳值,则在Type 0分段结束之后无需等待即可立即发送Type 3分段;同样地,在Type 0分段结束之后无需等待即可立即发送Type 3分段;
扩展时间戳
为了辅助编码超过 16,777,215(即 0xFFFFFF)的时间戳或时间增量信息,在现有技术中通常会采用扩展的方式进行处理。也就是说,在消息头无法用 24 位整数精确表示时间和增量信息的情况下(即当消息头中的时间段码或其他增益码的值等于最高有效位数为 FF 的情况),其中:
- 对于 0 类别区块而言,
- 或者对于编号为 1/2 类别的时间段码,
- 其时间段码的值应当等于 FF(即十六进制下的最大值)。
在这种情况下,则相应地需要确保对于最近属于同一区块流 ID 的同一批次的 - 同一类别下的其他相关参数
- 或者不同类别的参数
而言,
同样地需要在其对应的位置上设置相应的参数。
示例
示例1
这是一个简单的音频流消息,这是示例示范了信息冗余。

该消息流通过分块传输的形式得以呈现。采用第三类数据包开始数据传输优化工作,并且后续的数据包仅增加了一个位数。

示例2
该示例展示了一个超过128字节长度的消息,消息被分割成了数个块。

下图是被分割成的块:

该块的第一个头部字段明确了消息总长度为307字节这一重要信息。 值得参考的是以下两个示例,在两种不同场景中均可应用的3类数据块结构能够有效提升数据传输效率。
协议控制消息
采用RTMP块流的消息类型1、2、3、5及6作为协议控制信息;这些信息包含了实现RTMP块流通信所需的必要数据;每个协议控制信息都必须设置其通信路径的状态标识符为0(即控制流ID),并通过编号为2的分组发送出去;一旦接收方获得该确认信息,则立即执行相应的操作;而相关事件的时间戳则被系统自动跳过。
设置块大小
协议通过消息类型1来控制块大小设置,并以通知另一方当前的最大块容量。该消息中包含的最大容量设定为默认值128字节(MB),客户端或服务端均可自行更改该参数,并以该更新信息的形式传递给相关方。例如,在尝试传输超过标准容量的数据时(如若某客户端试图传输131字节的音频文件),其最大块大小会被相应调整至新的数值上限。需要注意的是:最大值必须至少限定为一个字节;一般建议保持在或以上(通常建议不小于)。值得注意的是,在不同方向上进行数据传输时,各方向的最大块大小设定是相互独立的。

- 0(一位): 该位必须为0. - chunk size(31位): 该字段存储新的最大块大小,并将用于后续所有块的发送直至接收新通知。该字段可取值范围为1到2147483647(十六进制表示为0x7FFFFFFF)。对于任何超过1677215的值均被视为等于等于该值。
终止消息
协议通过类型2的消息:结束通知告诉等待方接收后续数据块的位置,并指示相关方丢弃接收的数据块其中该消息所携带的标识符即为该数据块的流ID当应用程序处于关闭状态时发送此通知以表明不再需要处理后续数据块

- chunk stream id(32字节): 指定消息的块流ID。
确认消息
当接收到的数据总长度与窗口大小相等时(即二者数值一致),客户端或服务器会通过该机制进行确认性回应以传递信息。当连接建立完成之后(即系统进入稳定运行状态),消息的发送端会告知接收端当前所设定的一个特定的长度值(即窗口大小)。如果接收到该指定长度的数据后并未得到应答信息,则发送端将停止发送任何后续数据以避免造成资源浪费或其他异常情况发生

- sequence number(32字节): 到当前时刻为止接收到的字节总数。
确认窗口大小
两端向另一方发出通知以确定其是否已接受当前窗口大小的同时需等待对方返回成功信号
当接收到指定窗口大小时应立即返回成功信号

设置对方传输带宽
客户端或服务端通过发送此信息来限制接收端的数据传输带宽。一旦接收到此信息即可直接采用指定的数据块大小。若当前数据块尺寸与前一次的数据块尺寸不一致,则需通知 sender 更新数据块尺寸。这两个信息均涉及数据块尺寸的调节问题,并非简单的双向通信机制。其中一个是主动设定数据块尺寸给接收方的信息框架图(frame size);另一个则是接受方请求 sender 调整 window size 的过程框架图(window size)。

Limit Type(限制类型)有以下值: - 0 - Hard: 应该将输出带宽限制为指定视窗大小。 - 1 - Soft: 应该将输出带宽限制为指定视窗大小和当前视窗大小中较小的值。 - 2 - Dynamic: 如果上一个消息的限制类型为Hard,则该消息同样为Hard;否则应设为当前视窗大小和当前视窗大小中较小的值并丢弃该消息。
RTMP消息格式
尽管RTCP/TPM被设计为通过RTCP/TPM块流实现传输功能但它还可以采用其他传输协议来发送消息以满足特定场景的需求。在此情境下请参考下文了解RTCP/TPM消息的具体格式。值得注意的是当RTC/TPM与RFC30961结合应用时这一组合模式特别适用于音视频应用领域包括但不限于单播对讲实时直播视频点播以及网络会议等多种应用场景
RTMP消息格式
网络中传递RTMP消息作为服务端与客户端之间的交互手段,在线传输音频、视频以及附加数据信息等;每个RTMP消息都包含两个组成部分:头部信息与有效负载内容。
消息头
消息头包含以下信息:
- Msg Type: 消息类型, 占用了1个字节. 其中从ID 1到6的消息类型主要用于协议控制目的.
- Length: 有效负载的字节数, 占用了3个字节. 这一字段采用大端序进行编码.
- Timestamp: 时间戳, 占用了4个字节, 采用大端序编码.
- Msg Stream Id: 消息流ID, 用于标识消息所属的数据流.

消息有效负载
消息中的另一部分则是有效承载;这也同样是消息中包含的具体信息;具体信息也可以是音频片段或压缩视频文件。
用户控制消息
RTMP协议指定消息类型4作为用户自定义的消息标识符,在此过程中包含了实现RTMP流传输所需的关键信息。采用RTMP块流协议传输的消息包括类型1、2、3、5和6;而用户的自定义控制型信息则应采用ID为0的消息通道(即控制通道),并在通过 RTM P 块数据流量传输时应分配给ID为2的数据流量通道以确保可靠传输路径的有效性。一旦接收到用户的自定义事件通知后立即触发相关处理流程,并对相关的数据进行解析;其中系统会自动忽略其时间戳字段的信息以避免干扰后续的数据处理逻辑;当客户端或服务端发送此消息时,则表示已通知相关方正在进行用户自定义事件处理;而该条目中的具体细节则由相关的设备或者应用程序来完成相应的处理工作。

前两个字节用作事件类型的标识符,在其后紧跟的是事件数据字段。该字段的数据长度是可以变化的;但当采用RTMP块流传输方案时,则要求整个消息总长度不得超过单个块的最大容量,并且每个消息都能独立地通过一个单独的传输块完成发送。
RTMP指令消息
不同类型的通讯信息在客户端与服务端之间实现交互。这些通讯信息涵盖如传输音频数据所使用的音频信息、传输视频数据所使用的视频信息、处理任意用户数据的信息以及协调客户端与同一服务器间的共享资源等类型。其中共享对象信息主要用于协调客户端与同一服务器间的共享资源管理。指示信息传递的是客户端与服务端之间的AMF编码指示,并且从技术层面实现了远程过程调用(RPC)功能。
消息类型
客户端与服务端在网络安全层上进行数据传输以完成通信过程,在网络层面上支持音频数据流、视频流以及命令数据包等多种类型的消息传输方案
指令消息
通过客户端和服务端之间传递AMF编码相关的指令信息。其中,消息类型20对应AMF0编码方案,而消息类型17对应AMF3编码方案。通过发送这些特定类型的指令消息来执行连接建立、流创建以及发布、播放和暂停等操作流程。用于指示请求执行状态的状态和结果信息则以状态及结果形式传达给接收方。每条指令消息由三部分组成:操作名称(即命令名)、事务标识符(事务ID)以及包含所需参数的操作对象。
数据消息
客户端或服务端利用该消息传递元数据及其他用户所需的数据。这些元数据涵盖音频文件与视频文件创建的时间戳及其时长等内容。消息类型18对应AMF0编码方案;消息类型15对应AMF3编码方案。
共享对象消息
在多个客户端之间同步的Flash对象(键值对集合)作为共享对象。两种不同的消息类型分别代表AMF0和AMF3编码方案。每一个消息都可能携带多种事件信息。

支持以下事件类型:
- 创建(1):客户端向服务端发送请求以创建指定名称的共享对象。
- 释放(2):客户端通知服务端共享对象已成功删除。
- 请求更新(3):客户端向服务端发送请求以修改共享对象属性值。
- 更新(4):客户端通知服务端除自己外其他客户端收到属性值变化的消息。
- 成功(5):“请求更新”事件被接受后服务端向客户端发送此事件确认。
- 发送消息(6):客户端向服务端发送此事件以广播消息内容并包含请求方客户端信息。
- 状态 (7):服务端通过此事件通知客户端错误信息。
- 清除(8):当共享对象被删除后服务端会告知客户端该操作已完成。
- 移除(9):当插槽不再可用时会触发此事件通知相关操作者。
- 请求移除(10):当插槽被删除时会触发此事件以同步相关操作者信息。
- 创建成功(11):当连接建立成功后会触发此事件通知相关操作者一切正常运行状态。
音频消息
应用程序为此消息传输音频数据到另一方,并将编码格式8专为此类媒体内容设计。
视频消息
客户端或服务端方为此消息而发送向对方的视频数据,并且消息类型9专门用于存储和传输视频内容。
组合消息
复合式信息流是一种信息流由多个子流组成,并且这些子流均遵循RTMP格式规范进行传输的技术手段。该技术采用的消息类型编号为22以实现对多路流的集成管理

该组合 msg 的消息流标识将覆盖其子 msg 的相关标识信息。
该组合 msg 的时间戳与第一个子msg的时间戳之差即为此处时差值。
该时差量将被加至每个sub msg 的时间戳上以计算正常流水时间。
其第一个sub msg 应当具有与该combining msg 相同的时间戳值 因此 时差量应当设置为零。
Back Pointer记录前一msg的数据长度(含头信息) 这一设计符合flv文件规范 并支持回退操作功能。
采用组合并增大块长可有效减少总block数量 从而提升传输效率。
各sub msg在内存中连续存储可显著提升网络数据传输性能。
用户控制消息事件
客户端或服务器通过该消息发送用户控制事件。

用户控制消息支持以下事件: - 流开始(0):服务端发送该事件,用来通知客户端一个流已经可以用来通讯了。默认情况下,该事件是在收到客户端连接指令并成功处理后发送的第一个事件。事件的数据使用4个字节来表示可用的流的ID。 - 流结束(1):服务端发送该事件,用来通知客户端其在流中请求的数据已经结束了。如果没有额外的指令,将不会再发送任何数据,而客户端会丢弃之后从该流接收到的消息。事件数据使用4个字节来表示回放完成的流的ID。 - 流枯竭(2):服务端发送该事件,用来通知客户端流中已经没有更多的数据了。如果服务端在一定时间后没有探测到更多数据,它就可以通知所有订阅该流的客户端,流已经枯竭。事件数据用4个字节来表示枯竭的流的ID。 - 设置缓冲区大小(3):客户端发送该事件,用来告知服务端用来缓存流中数据的缓冲区大小(单位毫秒)。该事件在服务端开始处理流数据之前发送。事件数据中,前4个字节用来表示流ID,之后的4个字节用来表示缓冲区大小(单位毫秒)。 - 流已录制(4):服务端发送该事件,用来通知客户端指定流是一个录制流。事件数据用4个字节表示录制流的ID。 - ping请求(5):服务端发送该事件,用来探测客户端是否处于可达状态。事件数据是一个4字节的时间戳,表示服务端分发该事件时的服务器本地时间。客户端收到后用ping响应回复服务端。 - ping响应(6):客户端用该事件回复服务端的ping请求,事件数据为收到的ping请求中携带的4字节的时间戳。
指令类型
客户端与服务器之间通过AMF编码进行指令传输。发送端向接收端发送一条指令消息,在该消息中包含了具体的指令名称、处理ID以及相关参数的指定信息。例如,在连接操作中包含'app'参数以指示客户端希望连接的目标程序名称。接收端接收到该条指令后会生成相应响应,并返回响应字段可能取值包括_result_、_error_或指定方法名称(如verifyClient或contactExternalServer)。响应中的_result_或_error_字段表示一条操作结果记录,并由处理ID唯一标识对应的操作条目(这与IMAP或其他类似协议的行为一致)。响应中的方法名则指示了发送端希望接收端执行的具体操作功能。在技术细节方面需要注意的是:我们所讨论的命令消息可划分为两类:第一类为NetConnection命令消息——用于描述两个节点之间的连接关系;第二类为NetStream命令消息——用于描述音频流/视频流等相关数据传输过程,并通过相应的控制命令来管理数据流动状态
NetConnection指令
NetConnection负责协调客户端程序与服务器之间的双向通信,并提供异步操作的支持。以下指令可通过NetConnection执行:Connect用于建立连接, Call用于执行远程方法, Close用于关闭连接, CreateStream用于创建流。
Connect
客户端向服务器端提交connect指令作为请求以连接至某个服务器程序实例。 指令结构如下:

Connect指令中会用到的键值对:

音频编码:

视频编码:

视频功能:

对象编码:

由服务器发送至客户端的指令结构如下:

指令执行流程:

指令执行的消息流如下:
- 客户端向服务器发送connect指令以请求连接至服务器端程序实例。
- 当接收到该connect指令后,在处理完毕后,
服务器端会向客户端发送协议消息'Window Acknowledgement Size'。
同时,在处理该connect指令时,
服务方还与指定的应用进行了连接。
- 当客户端成功处理完'Set Peer Bandwidth'后,
会向服务方发送协议消息'Window Acknowledgement Size'。
- 在响应该connect请求时,
服务方会发出用户控制消息(StreamBegin)
以及相关的确认信息。
此消息包含相应的处理ID(与上一条相同),并附加了若干属性信息如Flash Media Server版本(string)等。
此外,在响应信息中还包括level(string)、code(string)、description(string)等字段详细描述。
Call
NetConnection实例的call方法负责远程执行接收端上的程序。需要远程执行的程序名称作为输入参数被指定给call指令。 发送指令结构如下:

响应指令结构如下:

CreateStream
客户端向服务器发送此指令以便建立一条用于传递消息的逻辑通道。该逻辑通道可借助已建立的流通道同步传输音频、视频以及元数据。其中NetConnection被视为默认通讯通道。协议包含若干指令消息如createStream等命令信息。客户端发出的所有指令结构如下:

服务器发出的指令结构如下:

NetStream指令
基于NetConnection的客户端至服务器间的连接关系中,NetStream提供了实现音频流、视频流以及消息流传输的一条专用通道。该对象不仅支持单个数据流的传输能力,并且能够管理多个NetStream实例来传输不同的数据流。客户端可通过以下指令与服务器交互:- 提交 - Play - Play2 - 删除 - 关闭 - 收听音频 - 收听视频 - 发布 - 寻找文件位置 - 暂停操作
服务器端通过“onStatus"将NetStream的状态更新至客户端:

Play
客户端发送此指令值将启动一个流的播放过程。
重复调用此指令可建立一个播放列表。
若要建立一个多轨切换的动态播放列表,则需重复执行play命令并传递false参数以防止重置问题。
与此相反地... 传递true以便立即启动指定流而不影响队列中的其他流程。
客户端发送的指令结构如下:

流程图如下:

在指令执行过程中:
- 客户端在接收到来自服务器createStream指令的成功响应时,则会响应play指令。
- 一旦接收到play指令后, 服务器将返回协议数据以设定块大小.
- 在处理完毕该请求后, 服务器会返回另一条用户控制的数据包, 在此信息中包含了事件标识"StreamIsRecord"及其相关的流标识.
- 这个特定的信息由两部分组成: 前两个字节表示事件类型, 后四个字节则用于存储流标识.
- 接着, 服务器将返回另一条用户控制的数据包, 在此信息中包含了事件标识"StreamBegin", 这表明流已开始播放.
- 如果客户端所发来的play指令能够顺利完成执行, 服务器将会返回一条名为onStatus的消息. 这条消息将包含NetStream.Play.Start或NetStream.Play.Reset两种状态之一. 只有当客户端设置中有reset标志被指定时, 才会返回NetStream.Play.Reset状态. 如果需要播放的内容不存在或无法播放, 则onStatus消息中将包含NetStream.Play.StreamNotFound状态. 最终, 无论结果如何, 一旦onStatus消息被成功发送出去之后, 游戏就会立即停止.
Play2
不同与play指令相比,在play2中可以实现码率切换而不影响播放内容的时间轴。服务器能够为客户端在play2中请求的所有支持的码率而维护多个字段。客户端发送的相关指令结构如下:

该指令的消息流程如下图:

DeleteStream
当NetStream对象即将被销毁时,它提交deleteStream指令。 客户端将发出相应的指令序列,具体格式如下:

服务器不需要发送任何应答。
ReceiveAudio
该消息告知服务器包括传输音频的情况。具体来说,请您提供客户端操作时所使用的完整指令详细说明。

当receiveAudio指令发送带有false的bool flag时, 服务器不会发送任何响应. 当该标志被设置为true时, 服务器会响应NetStream.Seek and Notify以及NetStream.Play.Start的状态消息.
ReceiveVideo
NetStream消息用于指示服务器是否已将视频数据传输至客户端设备。 当客户端发起操作时,请参阅完整的指令格式以获取详细信息。

若receiveVideo指令发送带有false布尔值的标志位,则服务器将不会返回任何响应;若该标志被置为true,则服务器应答NetStream.Seek_notify和NetStream.Play_start的状态信息。
Publish
客户端执行发布命令将预设名称分配给远程服务器上的特定流。通过该名称,所有客户端设备均可解码并播放此流,同时捕获来自该服务器的所有已发布的音频、视频以及数据消息包。客户端设备发出的指令架构如下:

服务器应答onStatus指令,以标记发布的开始。
Seek
客户端提交seek指令用于确定其在媒体文件中的具体位置或播放列表中的对应位置(以毫秒计)。

在定位成功的情况下, 服务器会传递NetStream.Seek_notify的状态信息; 而在定位失败的情况下, 则会返回一个错误的消息.
Pause
客户端发出pause指令以指示服务器暂停或启动播放功能。
客户端发出pause指令以指示服务器暂停或启动播放功能。

当流处于暂停状态时,服务器将NetStreamPause_notify的消息发送给客户端.一旦一个流恢复为未悬停状态,服务器将执行NetStreamUnpause_NOTIFY操作并发送相关消息.在发生故障的情况下,该系统会返回一个错误的通知消息.
消息交换例子
这里是一些样例,以解释使用RTMP的消息交换。
发布视频
通过这一实例可以看出,发布者是如何能够实现对一个流的发布,并将其传输至服务器存储位置的过程。此外,在线端点还可以订阅这一已发布的流,并通过解码器进行实时视频播放。

广播一个共享对象消息
此例阐述了在创建或修改共享对象时传输的信息,并且涉及到了共享对象消息广播机制。

发布媒体流元数据
这个例子描述了发布元数据的消息交换。

参考内容
如上所示,请访问该链接:http://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/devnet/rtmp/pdf/rtmp_specification_1.0.pdf(作者, 年)
[2]https://chenlichao.gitbooks.io/rtmp-zh_cn/content
[3]
- 本文作者: 贝克街的流浪猫
- 本文链接: https://www.beikejiedeliulangmao.top/JNI-调试技术/
- 版权声明: 本博客所有文章在未作特别说明的情况下,默认采用 BY-NC-SA 许可协议。如需转载,请注明出处。
- 创作声明: 本文基于上述所有参考内容进行创作,在此过程中可能涉及复制、修改或转换工作。其中图片均源自网络,在此提醒如有版权问题,请及时联系本人并要求删除。

