默认
发表评论 0
想开发IM:买成品怕坑?租第3方怕贵?找开源自已撸?尽量别走弯路了... 找站长给点建议
技术干货 | 直播RTMP协议简介与注意事项2
阅读(24259) | 评论(0 收藏 淘帖
03
RTMP 消息
RTMP消息格式:


•1字节消息类型
•3字节负载消息长度
•4字节时间戳
•3字节Stream ID,区分消息流
注意事项: 实际RTMP通信中并未按照上述格式去发送RTMP消息,而是将RTMP 消息分块发送,之后将介绍RTMP消息分块。

3.1. RTMP 消息分块
而对于基于TCP的RTMP协议而言,协议显得特别繁琐,但是有没有更好的替代方案。同时创建RTMP消息分块是比较复杂的地方,涉及到了AFM(也是Adobe家的东西)格式数据的数据。
RTMP消息块格式:
RTMP消息块构成:
• Basic Header
• Message Header
• Extended Timestamp
• Chunk Data
Chunk Basic header格式有3种:
格式1:


格式2:


格式3:


注意事项:
1.fmt: 用于指定Chunk Header 里面 Message Header的类型,后面会介绍到
2.cs id: 是chunk stream id的缩写,同一个RTMP消息拆成的 chunk块拥有相同的 cs id, 用于区分chunk 所属的RTMP消息, chunk basic header 的类型cs id占用的字节数来确定
Message Header格式:
Message Header的类型通过上文chunk basic header中的fmt指定,共4种:
格式0:


Message Header占用11个字节, 在chunk stream的开始的第一个chunk的时候必须采用这种格式。
• timestamp:3个字节,因此它最多能表示到16777215=0xFFFFFF=2^24-1, 当它的值超过这个最大值时,这三个字节都置为1,实际的timestamp会转存到Extended Timestamp字段中,接受端在判断timestamp字段24个位都为1时就会去Extended timestamp中解析实际的时间戳。
• message length:3个字节,表示实际发送的消息的数据如音频帧、视频帧等数据的长度,单位是字节。注意这里是Message的长度,也就是chunk属于的Message的总数据长度,而不是chunk本身Data的数据的长度。
• message type id:1个字节,表示实际发送的数据的类型,如8代表音频数据、9代表视频数据。
• msg stream id:4个字节,表示该chunk所在的流的ID,和Basic Header的CSID一样,它采用小端存储的方式
格式1:

Message Header占用7个字节,省去了表示msg stream id的4个字节,表示此chunk和上一次发的chunk所在的流相同。
• timestamp delta:3个字节,注意这里和格式0时不同,存储的是和上一个chunk的时间差。类似上面提到的timestamp,当它的值超过3个字节所能表示的最大值时,三个字节都置为1,实际的时间戳差值就会转存到Extended Timestamp字段中,接受端在判断timestamp delta字段24个位都为1时就会去Extended timestamp中解析时机的与上次时间戳的差值。
格式2:


Message Header占用3个字节,相对于格式1,又省去了表示消息长度的3个字节和表示消息类型的1个字节,表示此chunk和上一次发送的chunk所在的流、消息的长度和消息的类型都相同。余下的这三个字节表示timestamp delta,使用同格式1。
格式3:
0字节,它表示这个chunk的Message Header和上一个是完全相同的,无需再次传送
Extended Timestamp(扩展时间戳):
在chunk中会有时间戳timestamp和时间戳差timestamp delta,并且它们不会同时存在,只有这两者之一大于3个字节能表示的最大数值0xFFFFFF=16777215时,才会用这个字段来表示真正的时间戳,否则这个字段为0。
扩展时间戳占4个字节,能表示的最大数值就是0xFFFFFFFF=4294967295。当扩展时间戳启用时,timestamp字段或者timestamp delta要全置为1,表示应该去扩展时间戳字段来提取真正的时间戳或者时间戳差。注意扩展时间戳存储的是完整值,而不是减去时间戳或者时间戳差的值。
Chunk Data(块数据):
用户层面上真正想要发送的与协议无关的数据,长度在(0,chunkSize]之间, chunk size默认为128字节。
RTMP 消息分块注意事项
• Chunk Size:
RTMP是按照chunk size进行分块,chunk size 指的是 chunk的payload部分的大小,不包括chunk basic header 和 chunk message header长度。客户端和服务器端各自维护了两个chunk size, 分别是自身分块的chunk size 和 对端 的chunk size, 默认的这两个chunk size都是128字节。通过向对端发送set chunk size 消息可以告知对方更改了 chunk size的大小。
• Chunk Type:
RTMP消息分成的Chunk有4种类型,可以通过 chunk basic header的高两位(fmt)指定,一般在拆包的时候会把一个RTMP消息拆成以格式0开始的chunk,之后的包拆成格式3 类型的chunk,我查看了有不少代码也是这样实现的,这样也是最简单的实现。
如果第二个message和第一个message的message stream ID 相同,并且第二个message的长度也大于了chunk size,那么该如何拆包?当时查了很多资料,都没有介绍。后来看了一些源码,如 SRS,FFMPEG中的实现,发现第二个message可以拆成Type_1类型一个chunk, message剩余的部分拆成Type_3类型的chunk。FFMPEG中就是这么做的。

3.2 RTMP 交互消息
推流RTMP消息交互流程:


关于推流的过程,RTMP的协议文档上给了上图示例,说一下推流注意事项:

3.2.1 Connect 消息
RTMP 命令消息格式:

RTMP握手之后先发送一个connect 命令消息,命令里面包含什么东西,协议中没有具体规定,实际通信中要指定一些编解码的信息,并以AMF格式发送, 下面是用wireshake抓取connect命令需要包含的参数信息:


这些信息协议中并没有特别详细说明, 在librtmp,srs-librtmp这些源码中,以及用wireshark 抓包的时候可以看到。
服务器返回的是一个_result命令类型消息,这个消息的payload length一般不会大于128字节,但是在最新的nginx-rtmp中返回的消息长度会大于128字节。
消息的transactionID是用来标识command类型的消息的,服务器返回的_result消息可以通过 transactionID来区分是对哪个命令的回应,connect 命令发完之后还要发送其他命令消息,要保证他们的transactionID不相同。

发送完connect命令之后一般会发一个 set chunk size消息来设置chunk size 的大小,也可以不发。

Window Acknowledgement Size 是设置接收端消息窗口大小,一般是2500000字节,即告诉对端在收到设置的窗口大小长度的数据之后要返回一个ACK消息。在实际做推流的时候推流端要接收很少的服务器数据,远远到达不了窗口大小,所以这个消息可以不发。而对于服务器返回的ACK消息一般也不做处理,默认服务器都已经收到了所有消息了。



即时通讯网 - 即时通讯开发者社区! 来源: - 即时通讯开发者社区!

上一篇:技术干货 | 直播RTMP协议简介与注意事项下一篇:技术干货 | 直播RTMP协议简介与注意事项3
推荐方案
打赏楼主 ×
使用微信打赏! 使用支付宝打赏!

返回顶部