本文梳理了理解RTMP协议的基本概念
访问 个人博客了解更多
message 是 RTMP 中的 M,是消息的单位html
RTMP Message Header +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Message Type| Payload length| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Timestamp | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Stream ID | +-+-+-+-+-+-+-+-+-+-+-+-+
消息主要分为三类: 协议控制消息、数据消息、命令消息等shell
协议控制消息服务器
数据消息网络
Message Type ID = 8 9 18tcp
命令消息 Command Message (20, 17)ide
更多的了解见 Adobe’s Real Time Messaging Protocol 的 5.4 章节函数
rtmp 的 message 会切分为 n 个 chunk,再经过 tcp 协议传输post
为何 rtmp 基于 tcp 协议,tcp 协议已经有化整为零的方式, rtmp 还须要将 message 划分更小的单元 chunk 呢?优化
分析缘由:编码
在互联网中传输数据时, 消息(Message)会被拆分红更小的单元, 称为消息块(Chunk)。RTMP Chunk Stream 层级容许在Message stream 层次,将大消息切割成小消息,这样能够避免大的低优先级的消息(如视频消息)阻塞小的高优先级的消息(如音频消息或控制消息)。
重复强调,RTMP 是设计用来多路复用的特色,传输内容有视频、音频、控制命令。其中一个很是重要的概念是 multiplexing
(复用)
不一样类型的消息会被分配不一样的优先级,当网络传输能力受限时,优先级用来控制消息在网络底层的排队顺序。
好比当客户端网络不佳时,流媒体服务器可能会选择丢弃视频消息,以保证音频消息可及时送达客户端。
Chunk 的大小设置,经过 Message Type = 1 的控制消息声明
若是 message length 大于 max chunk size,则须要将这个message切分为多个 chunk 。前面几个 chunk size 必须是 max size,最后一个就是剩余的大小。
以上图为例,Message大小为 300 bytes,默认Chunk size 为 128 bytes,进行拆分红chunk的过程。
接下来,探寻 chunk 的结构
RTMP Chunk Header +-------------+----------------+-------------------+-----------+ | Basic header|Chunk Msg Header|Extended Time Stamp|Chunk Data | +-------------+----------------+-------------------+-----------+ 1 byte (0,3,7,11 byte) (0,4 byte)
设计基于TCP协议的上层协议时,为了防止粘包问题,通常的方法有:一、使用分隔符; 二、在报文header中声明长度。
RTMP Chunk Basic Header (1 byte) +-+-+-+-+-+-+-+-+-+-+-+-+-+- | format | chunk stream id | +-+-+-+-+-+-+-+-+-+-+-+-+-+- 2 bits 6 bits
RTMP Chunk Header 的长度不是固定的,由RTMP Chunk Basic Header 前2位二进制决定,有4种类型。chunk stream id 的范围 3~65599,0~2做为保留。
00
,Chunk Header length = 12 bytes,在一个 chunk 流的开始、时间戳返回的时候必须有这种块,好比:onMetaData, 音视频流刚开始的绝对时间戳,控制消息Basic header + Chunk Msg Header +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | format | chunk stream id | timestamp | message length | msg type id | msg stream id | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2 bits 6 bits 3 bytes 3 bytes 1 bytes 4 bytes
01
,Chunk Header length = 8 bytes,对于可变大小消息的chunk流,在第一个消息以后的每一个消息的第一个块应该使用这个格式Basic header + Chunk Msg Header +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | format | chunk stream id | timestamp | message length | msg type id | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2 bits 6 bits 3 bytes 3 bytes 1 bytes
10
,Chunk Header length = 4 bytes,对于固定大小消息的chunk流,在第一个消息以后的每一个消息的第一个块应该使用这个格式Basic header + Chunk Msg Header +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- | format | chunk stream id | timestamp | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- 2 bits 6 bits 3 bytes
11
,Chunk Header length = 1 bytes,当一个消息被分红多个块,除了第一块之外,全部的块都应使用这种类型Basic header + Chunk Msg Header +-+-+-+-+-+-+-+-+-+-+-+-+-+- | format | chunk stream id | +-+-+-+-+-+-+-+-+-+-+-+-+-+- 2 bits 6 bits
注意 timestamp
的长度为 3 bytes,当 timestamp
被设置为 0x00ffffff
,chunk header 会加上 Extended Time Stamp
字段,不然 Extended Time Stamp
不会出现。
由于一个流当中能够传输多个Chunk,那么多个Chunk怎么标记同属于一个 Message 的呢?
Message type 1~6:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Basic Header|Message Header|Ex Timestamp|Set chunk size | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Basic Header|Message Header|Ex Timestamp|Chunk Stream ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Basic Header|Message Header|Ex Timestamp| Sequence Number| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
是可变长的。
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+ |Basic Header|Message Header|Ex Timestamp| Event Type| Event Data| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |Basic Header|Message Header|Ex Timestamp| Acknowledgement Window size | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |Basic Header|Message Header|Ex Timestamp| Acknowledgement Window size | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | Limit type | ++++++++++++++++
Message type = 8,Audio message, 客户端或服务端发送本消息用于发送音频数据。消息类型 8 ,保留为音频消息
以 FLV ACC 的 RTMP Audio Chunk 为例
协议层:
协议层 封装层 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |RTMP Chunk Header | FLV AudioTagHeader | FLV AudioTagBody | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
封装层(FLV):
FLV AudioTagHeader ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |SoundFormat | SoundRate | SoundSize | SoundType | AACPacketType | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 bits 2 bits 1 bit 1 bit 8 bits
Message type = 9, Video message, 客户端或服务端使用本消息向对方发送视频数据。消息类型值 9 ,保留为视频消息。
以 FLV H.264/AVC 的 RTMP Video Chunk 为例
协议层:
协议层 封装层 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |RTMP Chunk Header | FLV VideoTagHeader | FLV VideoTagBody | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
封装层(FLV):
FLV VideoTagHeader +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |Frame Type | CodecID | AVCPacketType | CompositionTime | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 bits 4 bits 1 byte 3 bytes
编码层:
FLV VideoTagBody +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | Size | AVCDecoderConfigurationRecord or ( one or more NALUs ) | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 bytes
NALU: Network Abstract Layer Unit 网络抽象层单元