【流媒体】RTMP协议的消息类型

RTMP协议相关:
【流媒体】RTMP协议概述
【流媒体】RTMP协议的数据格式
【流媒体】RTMP协议的消息类型
【流媒体】RTMPDump—主流程简单分析
【流媒体】RTMPDump—RTMP_Connect函数(握手、网络连接)
【流媒体】RTMPDump—RTMP_ConnectStream(创建流连接)
【流媒体】RTMPDump—Download(接收流媒体信息)
【流媒体】RTMPDump—AMF编码
【流媒体】基于libRTMP的H264推流器

不得不说RTMP协议比之前看到的RTP协议要复杂很多,其中涉及到的数据格式和控制方式要更多。前面记录了RTMP协议的主要流程和数据格式,本文记录RTMP中的消息类型,不同的消息类型决定当前的数据包完成不同的任务,因此是极其重要的内容

1. RTMP消息类型

RTMP协议中有不同的消息类型,用于完成数据传输或命令控制等操作,这些消息类型写在message type id当中

1.1 协议控制消息

RTMP 块流使用message type ID为1、2、3、5 和 6 用于协议控制消息,协议控制消息的message stream id必须为0,以表示这是用于控制流程的消息,cs_id必须为2,以标识这是一个用于传输控制消息的特殊 CSID

1.1.1 设置块大小(SetChunkSize,message type id = 1)

RTMP在网络传输的基本数据载体是chunk,发送端需要先与接收端确认数据包的大小,这样接收端才能正确的解析数据包。实际使用时,双端的chunk size是独立的,例如client端使用的chunk size为128,server在接收和解析时按照128字节来进行,同时,server端使用的chunk size可以为130,client在接收和解析时按照130字节来进行

如果message type id为1,message payload当中存储的是所配置的chunk size,共4字节,第1个比特必须为0,后面31个字节存储的是期望的chunk size,这个chunk size最小不得小于128比特
在这里插入图片描述

1.1.2 中断消息(AbortMessage ,message type id = 2 )

当一个message被切分为多个chunk,接受端只接收到了部分chunk时,发送该控制消息表示发送端不再传输同message的chunk,接受端接收到这个消息后要丢弃这些不完整的chunk

如果message type id为2,message payload当中存储的是要丢弃其当前消息的块流ID,用4字节表示
在这里插入图片描述

1.1.3 应答消息(Acknowledgement ,message type id = 3)

客户端或者服务器在接收到等同于窗口大小的字节之后必须要发送给对端一个确认。窗口大小是指发送者在没有收到接收者确认之前发送的最大数量的字节。这个消息定义了序列号,也就是目前接收到的字节数

如果message type id为3,message payload当中存储的是收到的字节数,用4字节表示
在这里插入图片描述

1.1.4 窗口确认大小(Window Acknowledgement Size,message type id = 5)

这条命令设置了一个消息窗口大小,当发送端发送了窗口大小字节之后期待对端的确认,接收端在接收到窗口大小字节之后给发送端一个反馈到发送端。这个消息窗口大小的发送方可以是客户端或者服务器端。

如果message type id为5,message payload中存储的是窗口确认大小,用4字节表示
在这里插入图片描述

1.1.5 设置流带宽(SetPeerBandwidth,message type id = 6)

客户端或者服务器端发送这一消息来限制其对端的输出带宽。对端接收到这一消息后,将通过限制这一消息中窗口大小指出的已发送但未被答复的数据的数量以限制其输出带宽。接收到这一消息的对端应该回复一个窗口确认大小消息,如果这个窗口大小不同于其发送给 (设置对端带宽) 发送者的最后一条消息

如果message type id为6,message payload共有5个字节,前4个字节存储的是限制带宽的大小,后1个字节是限制的类型。其中限制的类型为:

(1)Limit type = 0 (Hard Limit)
硬限制,对端应该限制其输出带宽到指示的窗口大小

(2)Limit type = 1 (Soft Limit)
对端应该限制其输出带宽到知识的窗口大小,或者已经有限制在其作用的话就取两者之间的较小值

(3)Limit type = 2(Dynamic Limit)
如果先前的限制类型为 Hard,处理这个消息就好像它被标记为 Hard,否则的话忽略这个消息
在这里插入图片描述

1.2 用户控制消息

RTMP 使用消息类型 ID 4 表示用户控制消息,即message stream id = 4,同时cs_id应为2。用户控制消息一旦被接收立马生效,这类消息的timestamp是被忽略的。

发送端发出这个消息来通知对端,下面我要发送用户操作事件。这一消息携带有事件类型和事件数据。前两个字节用于指示事件类型,随后是事件数据,并且这个事件数据字段的大小是可变的。如果消息必须通过 RTMP 块流层传输时,最大块大小应该足够大,使得这些消息能够放到一个块当中一起发送
在这里插入图片描述
下面展示了用户控制事件的类型:

事件 (Event)描述
StreamBegin (=0)server发送给client,一个流已就绪并可以用来通信。默认情况下,这一事件在成功接收到客户端的应用连接命令之后以 ID 0 发送。数据长度为4字节,标识已就绪流的流 ID
StreamEOF (=1)server发送给client,请求的流的回放数据已经结束。在发送额外的命令之前不再发送任何数据。client将丢弃接收到的这个流的消息。数据长度为4字节,标识回放已结束的流的流 ID
StreamDry (=2)server发送给client,当前流中已没有数据。当server在一段时间内没有检测到任何消息,它可以通知相关客户端当前流已经没数据了。数据长度为4字节,标识已没数据的流的流 ID
SetBufferLength (=3)client发送给server,用于缓存流中任何数据的缓存大小 (以毫秒为单位)。这一事件在server开始处理流之前就发送。数据的前4个字节代表了流ID,后4个字节代表了以毫秒为单位的缓存的长度
StreamIsRecorded (=4)server发送给client,当前流是一个录制流。数据长度为4字节,标识录制流的流 ID
PingRequest (=6)server发送给client,用于测试是否能够将数据送达client。数据是为一个4字节的timestamp,标识server发送这一命令时server的本地时间。client在接收到这一消息后会立即发送 PingResponse 回复
PingResponse (=7)client作为对ping请求的回复发送这一事件到server。数据是为一个4字节的 timestamp,这个timestamp来自于server发送的PingRequest中的timestamp

1.3 不同消息类型

1.3.1 命令消息(Command Message, message type id = 17 or 20)

命令消息在client和server之间传递 AMF 编码的命令。如果message type id为20,则进行AMF0编码;如果message type id为17,则进行AMF3编码。这些消息发送之后可以进行的操作包括,连接,流创建,发布,播放,暂停等。一个命令消息由命令名、事务ID 和包含相关参数的命令对象组成。

以下类的对象用于发送不同的命令:
(1)NetConnection 代表上层的服务器端和客户端之间连接的一个对象
(2)NetStream 一个代表发送音频流、视频流和其他相关数据的通道的对象。当然,我们也会发送控制数据流的命令,诸如 play、pause 等等

1.3.1.1 NetConnection命令

NetConnection 管理着一个客户端应用和服务器端之间的双相连接。此外,它还提供远程方法的异步调用。NetConnection 可以发送以下命令:
(1)connect
(2)call
(3)close
(4)createStream

1.3.1.1.1 connect

connect命令的使用,client会发送connect命令到server,请求连接到一个server app
由客户端发送connect到server命令结构如下:

字段名类型描述
Command NameString命令的名称,设置给 “connect”
Transaction IDNumber永远设置为1
Command ObjectObject具有名称-值对的命令信息对象
Optional User ArgumentsObject任意可选信息

下面是connect命令的命令对象中使用的名称-值对的描述

属性类型描述举例
appStringclient连接到的server应用程序名称testapp
flashverStringFlash Player 版本号,与ApplicationScript getversion() 方法返回的是同一个字符串FMSc/1.0
swfUrlString进行连接的源SWF文件的URLfile://c:/FlvPlayer.swf
tcUrlStringserver URL,具有以下格式:protocol://servername:port/appName/appInstancertmp://localhost:1935/testapp/instance1
fpadBoolean如果使用了代理,则设置为Truetrue或false
audioCodecsNumber表明客户端所支持的音频编码SUPPORT_SND_MP3
videoCodecsNumber表明所支持的视频编码SUPPORT_VID_SORENSON
videoFunctionNumber表示支持哪些特殊视频功能SUPPORT_VID_CLIENT_SEEK
pageUrlString加载SWF文件的网页的Urlhttp://somehost/sample.html
object EncodingNumberAMF编码方法AMF3

audioCodecs属性的标志值如下

类型描述
SUPPORT_SND_NONE原始数据,未压缩0x0001
SUPPORT_SND_ADPCMADPCM压缩0x0002
SUPPORT_SND_MP3mp3压缩0x0004
SUPPORT_SND_INTEL未使用0x0008
SUPPORT_SND_UNUSED未使用0x0010
SUPPORT_SND_NELLY8NellyMoser在8-kHz的压缩0x0020
SUPPORT_SND_NELLYNellyMoser压缩 (5, 11, 22, 和44kHz)0x0040
SUPPORT_SND_G711AG711A压缩 (Flash Media Server Only)0x0080
SUPPORT_SND_G711UG711U压缩 (Flash Media Server Only)0x0100
SUPPORT_SND_NELLY16NellyMoser在16-kHz的压缩0x0200
SUPPORT_SND_AAC高级音频编码 (AAC)0x0400
SUPPORT_SND_SPEEXspeex音频0x0800
SUPPORT_SND_ALL所有RTMP支持的音频编解码器0x0FFF

videoCodecs属性的标志值如下

类型描述
SUPPORT_VID_UNUSED不再使用 (obsolete value)0x0001
SUPPORT_VID_JPEG不再使用 (obsolete value)0x0002
SUPPORT_VID_SORENSONSorenson Flash Video0x0004
SUPPORT_VID_HOMEBREWV1 screen sharing0x0008
SUPPORT_VID_VP6 (On2)On2 video (Flash 8+)0x0010
SUPPORT_VID_VP6ALPHA (On2 with alpha channel)On2 video with alpha channel0x0020
SUPPORT_VID_HOMEBREW (screensharing v2)Screen sharing version 2 (Flash 8+)0x0040
SUPPORT_VID_H264H264 video0x0080
SUPPORT_VID_ALL所有RTMP支持的视频编解码器0x00FF

videoFunction属性的标志值如下

类型描述
SUPPORT_VID_CLIENT_SEEK表示客户端可以执行帧精确查找1

objectEncoding属性的标志值如下

类型描述
AMF0flash 6及以后版本支持的AMF0对象编码0
AMF3AMF3编码从flash 9 (AS3)3

从server到client的命令结构如下所示

字段类型描述
Command NameString_result或_error;描述返回的是结果还是错误
Transaction IDNumber连接响应的事务id为1
PropertiesObject描述连接属性(fmsver等)的名称-值对
InformationObject描述server响应的名称-值对, “code”、“level”、"description"是这些信息中为数不多的名称
1.3.1.1.2 call

NetConnection对象的调用方法在接收端运行远程过程调用(RPC)。被调用的RPC名称作为参数传递给调用命令。

从发送方到接收方的命令结构如下

字段类型描述
Procedure NameString被调用的远程过程的名称
Transaction IDNumber如果期望得到响应,设置一个事务Id,否则设置为0
Command ObjectObject如果存在一些命令信息要设置这个对象,否则置空
Optional ArgumentsObject要提供的任何可选参数

返回信息的命令结构如下

字段类型描述
Command NameString命令名称
Transaction IDNumber响应所属的命令Id
Command ObjectObject如果存在一些命令信息要设置这个对象,否则置空
ResponseObject被调用的方法的响应
1.3.1.1.3 createStream

client将此命令发送到server以创建用于消息通信的逻辑通道,音频、视频和元数据的发布通过使用createStream命令创建的流通道进行。netConnection是默认的通信通道,其流ID为0。协议和一些命令消息(包括createStream)使用默认通信通道

从client到server的命令结构如下所示

字段类型描述
Command NameString命令名称,设置为 “createStream”
Transaction IDNumber命令的事物ID
Command ObjectObject如果存在一些命令信息要设置这个对象,否则置空

从server到client的命令结构如下所示

字段类型描述
Command NameString_result 或 _error;表示返回的值是result或error
Transaction IDNumber响应所属的命令ID
Command ObjectObject如果存在一些命令信息要设置这个对象,否则置空
Stream IDNumber返回值要么是一个流 ID 要么是一个错误信息对象
1.3.1.2 NetStream命令

NetStream定义了一个通道,通过这个通道,流音频、视频和数据消息可以在连接客户端和服务器的NetConnection上流动。一个NetConnection对象可以为多个数据流支持多个NetStream

client可以在NetStream上向服务器发送以下命令:
(1)play
(2)play2
(3)deleteStream
(4)closeStream
(5)receiveAudio
(6)receiveVideo
(7)publish
(8)seek
(9)pause

server使用“onStatus”命令向client发送NetStream状态更新

字段类型描述
Command NameString命令名称 “onStatus”
Transaction IDNumber事务ID设置为0
Command ObjectNull没有onStatus消息的命令对象
Info ObjectObject一个 AMF 对象至少要有以下三个属性。“level” (String):这一消息的等级,“warning”、“status”、“error” 中的某个值;“code” (String):消息码,例如 “NetStream.Play.Start”;“description” (String):人类可读的消息描述
1.3.1.2.1 play

client将此命令发送到server以播放流。也可以使用此命令多次创建播放列表。如果想创建一个动态的播放列表,在不同的直播或录播流之间切换,调用play不止一次,并立即传递指定的流,清除排队等待播放的任何其他流,为重置传递true

client到server的命令结构如下:

字段类型描述
Command NameString命令的名称,设置为 “play”
Transaction IDNumber事物ID设置为0
Command ObjectNull命令信息不存在。设置为空类型
Stream NameString要播放流的名字。要播放视频 (FLV) 文件,使用没有文件扩展名的名字对流名进行定义 (例如,“sample”)。要重播 MP3 或者 ID3,你必须在流名前加上 mp3:例如,“mp3:sample”。要播放 H.264/AAC 文件,你必须在流名前加上 mp4:并指定文件扩展名。例如,要播放 sample.m4v 文件,定义 “mp4:sample.m4v”
StartNumber一个可选的参数,以秒为单位定义开始时间。默认值为 -2,表示用户首先尝试播放流名字段中定义的直播流。如果那个名字的直播流没有找到,它将播放同名的录制流。如果没有那个名字的录制流,客户端将等待一个新的那个名字的直播流,并当其有效时进行播放。如果你在 Start 字段中传递 -1,那么就只播放流名中定义的那个名字的直播流。如果你在 Start 字段中传递 0 或一个整数,那么将从 Start 字段定义的时间开始播放流名中定义的那个录制流。如果没有找到录制流,那么将播放播放列表中的下一项
DurationNumber一个可选的参数,以秒为单位定义了回放的持续时间。默认值为 -1。-1 值意味着一个直播流会一直播放直到它不再可用或者一个录制流一直播放直到结束。如果你传递 0 值,它将只播放单一一帧,因为播放时间已经在录制流的开始的 Start 字段指定了。假定定义在 Start 字段中的值大于或者等于 0。如果你传递一个正数,将播放 Duration 字段定义的一段直播流。之后,变为可播放状态,或者播放 Duration 字段定义的一段录制流。(如果流在 Duration 字段定义的时间段内结束,那么流结束时回放结束)。如果你在 Duration 字段中传递一个 -1 以外的负数的话,它将把你给的值当做 -1 处理
ResetBoolean一个可选的布尔值或者数字定义了是否对以前的播放列表进行 flush
1.3.1.2.2 play2

与play命令不同,play2可以切换到不同的比特率流,而无需改变播放内容的时间轴。服务器为客户端可以在play2中请求的所有支持的比特率维护多个文件

字段类型描述
Command NameString命令名,设置为 “play2”
Transaction IDNumber事物ID,设置为0
Command ObjectNull命令信息不存在,设置为 null 类型
ParametersObject一个 AMF 编码的对象,该对象的属性是为公开的 flash.net.NetStreamPlayOptions ActionScript 对象所描述的属性
1.3.1.2.3 deleteStream

当NetStream对象被销毁时,NetStream发送deleteStream命令

字段类型描述
Command NameString命令的名称,设置为 “deleteStream”
Transaction IDNumber事务ID设置为0
Command ObjectNull命令信息对象不存在。设置为空类型
Stream IDNumber在server上销毁的流的ID

server不会发送任何反馈

1.3.1.2.4 receiveAudio

NetStream发送receiveAudio消息来通知server是否将音频发送到client。从client到server的命令结构如下所示

字段类型描述
Command NameString命令的名称,设置为 “receiveAudio”
Transaction IDNumber事务ID设置为0
Command ObjectNull命令信息对象不存在。设置为空类型
Bool FlagBooleanTrue或false表示是否接收音频

如果发送receiveAudio命令时将bool标志设置为false,则服务器不发送任何响应。如果这个标志被设置为true,服务器响应状态消息NetStream.Seek.notify和NetStream.play.Start

1.3.1.2.5 receiveVideo

NetStream发送receiveVideo消息来通知服务器是否将视频发送给客户端。client到server的命令结构如下:

字段类型描述
Command NameString命令的名称,设置为 “receiveVideo”
Transaction IDNumber事务ID设置为0
Command ObjectNull命令信息对象不存在。设置为空类型
Bool FlagBooleanTrue或false表示是否接收视频

如果发送receiveVideo命令时将bool标志设置为false,则服务器不发送任何响应。如果这个标志被设置为true,服务器响应状态消息NetStream.Seek.Notify和NetStream.Play.Start

1.3.1.2.6 publish

client发送publish命令将命名流发布到server。使用此名称,任何client都可以播放此流并接收发布的音频、视频和数据消息。client到server的命令结构如下

字段类型描述
Command NameString命令的名称,设置为 “publish”
Transaction IDNumber事务ID设置为0
Command ObjectNull命令信息对象不存在,设置为 null 类型
Publishing NameString发布的流的名字
Publishing TypeString发布类型。可以设置为 “live”、“record” 或者 “append”。record:流被发布,数据被录制到一个新的文件。新文件被存储在服务器上包含服务应用目录的子路径。如果文件已存在,将重写。append:流被发布,数据被添加到一个文件。如果该文件没找着,将新建一个。live:直播数据只被发布,并不对其进行录制

服务器用onStatus命令响应以标记发布的开始

1.3.1.2.7 seek

client发送seek命令来查找媒体文件或播放列表中的偏移量(以毫秒为单位)。client到server的命令结构如下:

字段类型描述
Command NameString命令的名称,设置为 “seek”
Transaction IDNumber事务ID设置为0
Command ObjectNull该命令没有命令信息对象。设置为空类型
milliSecondsNumber搜索到播放列表的毫秒数

当seek成功时,服务器发送一个状态消息NetStream.Seek.Notify。如果失败,则返回_error消息

1.3.1.2.8 pause

client发送pause命令来告诉server暂停或开始播放

字段类型描述
Command NameString命令的名称,设置为 “pause”
Transaction IDNumber没有这一命令的事务 ID,设为 0
Command ObjectNull命令信息对象不存在,设置为空类型
Pause/Unpause FlagBoolean为true或false,表示暂停或恢复播放
milliSecondsNumber流暂停或恢复播放的毫秒数。这是流暂停时客户端的当前流时间。当回放恢复时,服务器将只发送时间戳大于此值的消息

当流暂停时,服务器发送一个状态消息NetStream.Pause.Notify。NetStream.Unpause.Notify在流处于未暂停状态时发送。如果失败,则返回_error消息

1.3.2 数据消息(Data Message, message type id = 18 or 15)

client或者server通过发送数据消息,以发送元数据或者任何用户数据到对端。元数据包括数据 (音频,视频等等) 的详细信息,如创建时间,时长,主题等等。如果message type id为18,则进行AMF0编码;如果message type id为15,则进行AMF3编码

1.3.3 共享对象消息(Shared Object Message, message type id = 19 or 16)

共享对象是一个 Flash 对象 (一个value和key的集合),这个对象在多个不同客户端、应用实例中保持同步。如果message type id为19,则使用AMF0编码;如果message type id为16,则使用AMF3编码。每个消息可以包含有不同的事件
在这里插入图片描述
事件类型的列表如下

事件 (Event)描述
Use (=1)client发送这给server,表明一个已命名的共享对象已创建
Release (=2)当共享对象在client被删除时,client发送这一事件到server
Request Change (=3)client发送这一事件,请求更改与共享对象的命名参数关联的值
Change (=4)如果请求被接受,server将发送此事件给请求的client,以响应RequestChange事件,即指定参数值的更改
Success (=5)如果请求被接受,server发送这一事件给请求的client,以作为 RequestChange 事件的响应
SendMessage (=6)client将此事件发送到server以广播消息。在接收到此事件时,server向所有client广播一条消息,包括发送方
Status (=7)server发送这一事件以通知client异常情况
Clear (=8)server向client发送此事件以清除共享对象。server还发送此事件以响应client在连接时发送的事件
Remove (=9)server发送此事件以让client删除插槽
Request Remove (=10)client发送此事件以使client删除槽
Use Success (=11)在连接成功时,server将此事件发送给client

1.3.4 音频消息(Audio Data, message type id = 8)

client或者server发送这一消息以发送音频数据到对端,message type id为8

1.3.5 视频消息(Video Data, message type id = 9)

client或者server发送这一消息以发送视频数据到对端,message type id为9

1.3.6 聚合消息(Aggregate Message, message type id = 22)

聚合消息是一条消息,它包含了一系列子RTMP信息,message type id为22。
在这里插入图片描述
聚合消息中的message stream id会覆盖其中包含的一系列子消息的message stream id。聚合消息的timestamp与第1个子消息之间的差异是用于将子消息的timestamp重新规范化为流时间刻度的偏移量。偏移量被添加到每个子消息的时间戳中。第一个子消息的时间戳应该与聚合消息的时间戳相同,因此偏移量应该为零

上面这句话的意思是,聚合消息中子信息的timestamp是有一个偏移量的,并且越后面的子消息偏移量越大(相对于第1个子消息)

使用统计消息具有以下性能优势:
(1)将多个消息融合到一个块中,这样通过适当的增加块大小,可以减少块发送的数量
(2)子消息可以在内存中连续存储。在网络中系统调用发送这些数据时更高效

2.小结

RTMP消息类型比较多,我理解其中主体可以分成3部分:
(1)RTMP协议默认使用的控制消息
(2)用户可配置的控制消息
(3)用户可配置的命令消息、数据消息等

后续需要关注一下代码当中(参考RTMPdump)是如何实现这些操作的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值