1 简介
Adobe开发的实时通信协议,基于TCP,提供双工通信服务,同时传输多路视频、音频、数据,并且附加时间信息。适用于一对一、一对多实时广播,VOD点播,交互式实时会议等应用。
控制和数据都在一条TCP链路中传输,控制消息使用 AMF
消息编码, 数据使用 FLV 格式, 也都比较简单。RTMP加上了会话协商和时间戳,方便传输实时数据。
2 Rtmp Chunk Stream
为上层应用提供链路复用和分包机制。
2.1 Message Format
2.2 handshake
Client send C0, C1, C2; Server send S0, S1, S2
2.2.1 handshake sequence
或者原文中的图:
2.2.2 C0 and S0 format
1 | version(1) |
- version: 0-2弃用,当前是3, 4-31是保留, 32-255禁用。
2.2.3 C1 and S1 format
1 | time(4) | zero(4) | random bytes(1528) |
- time: 为之后的数据包提供基准时间,可以是0,也可以是随机值
- zero: 全0;
- random data: 随机值, 不用密码学安全,甚至可以是固定的,主要用于端点区分是否是自己发出去的握手包;
2.2.4 C2 and S2 format
1 | time(4) | time2(4) | random echo(1528) |
- time: 包含对端发过来的时间戳;
- time2: 包含自己上个包发出去的时间戳;
- random echo: 包含对端发过来的 random bytes
2.3 Chunking
握手之后会发送分组包,这里会用 stream ID
做链路复用.
分组可以将大的应用数据包分解成小片段,防止大的低优先级数据包(比如视频帧)阻塞小的高优先级数据(比如音频帧或者控制信令)发送;
2.3.1 Chunk format
1 | Basic Header(1-3) | Message Header(0,3,7,11) | Extended Timestamp(0,4) | Chunk Data(variable size) |
- Basic Header: 包含 stream ID 和 chunk type(区分数据类型), 长度随数据类型不同而不同
- Message Header: 包含要发送消息的一些基本信息
- Extended Timestamp: 一些特定的场景中使用该字段;
- Chunk Data: 真正的数据
2.3.1.1 Basic Header
1字节id
1
fmt(2b) | cs id(6b)
2字节id
1
fmt(2b) | 0(6b) | cs id-64(1)
3字节id
1
fmt(2b) | 1(6b) | cs id-64(2, 小端)
chunk stream ID:
0: 表示2bytes形式,真正的id是 第2字节+64
1: 表示3bytes形式,真正的id是 第3字节*256+第2字节+64
3-63: 标识完整的id
2: 用于底层协议控制消息和命令
2.3.1.2 chunk message header
根据fmt
不同,有4种格式。
- fmt=0 (11bytes)
用于chunk流开始,或者 timestamp 回绕的时候。
1 | timestamp (3) | message length(3) | message type id(1) | msg stream id(4) |
- timestamp: 绝对时间戳, 如果大于 0xFFFFFF, 必须是 0xFFFFFF,说明完整的4字节时间戳在
Extended Timestamp
字段
- fmt=1 (7bytes)
去掉了 msg stream id, 用于可变长度数据(比如视频帧)
1 | timestamp delta(3) | message length(3) | msg type id(1) |
- fmt=2 (3bytes)
用于固定长度数据(比如音频帧).
1 | timestamp delta(3) |
- fmt=3 (0bytes)
1个消息分成多个chunk的时候,除了第1个,后续的都应该用该格式。
统一字段说明:
- timestamp delta: fmt-1,ftm-2 使用,跟前1个chunk的差值, 如果超过 0xFFFFFF, 就设置为 0xFFFFFF,完整的4字节时间戳在
Extended Timestamp
字段 - message length: fmt-0,fmt-1 使用。注意这个通常不是 payload 长度,可以看下边例子;
- message type id: 标记消息类型, 8(audio), 9(video);
- message stream id: 标记1个媒体流,通常1个 chunk stream id 中只会有1个 message stream id, 当然可以再进行链路复用;
2.3.2 例子
例子1
原始数据:
message Stream ID | Message Type ID | Time | Length | |
---|---|---|---|---|
msg1 | 12345 | 8 | 1000 | 32 |
msg2 | 12345 | 8 | 1020 | 32 |
msg3 | 12345 | 8 | 1040 | 32 |
msg4 | 12345 | 8 | 1060 | 32 |
编码成chunk后:
Chunk Stream ID | Chunk Type | Header Data | No.of Bytes After Header | Total No.of Bytes in the Chunk | |
---|---|---|---|---|---|
chunk1 | 3 | 0 | delta: 1000 length:32 type: 8 stream ID: 12345(11 bytes) |
32 | 44 |
chunk2 | 3 | 2 | 20(3 bytes) | 32 | 36 |
chunk3 | 3 | 2 | none(0 bytes) | 32 | 33 |
chunk4 | 3 | 2 | none(0 bytes) | 32 | 33 |
例子2
原始数据:
message Stream ID | Message Type ID | Time | Length | |
---|---|---|---|---|
msg1 | 12345 | 9(video) | 1000 | 307(超过128bytes chunk最大大小) |
编码成chunk后:
Chunk Stream ID | Chunk Type | Header Data | No.of Bytes After Header | Total No.of Bytes in the Chunk | |
---|---|---|---|---|---|
chunk1 | 4 | 0 | delta: 1000 length:307 type: 9 stream ID: 12346(11 bytes) |
128 | 140 |
chunk2 | 4 | 3 | none(0 bytes) | 128 | 129 |
chunk3 | 4 | 3 | none(0 bytes) | 51 | 52 |
2.4 protocol control messages
chunk stream ID 2 用于底层控制流, message stream ID 0 表示控制信令, message-type-id 1,2,3,5,6 做为协议控制消息ID
2.4.1 Set Chunk Size (id-1)
1 | 0(1b) | chunk size(31b) |
设置chunk最大大小,默认 128bytes, 可以设置 [0, 2147483647(0x7FFFFFFF)]
, 但没消息会大于 0xFFFFFF
(message长度最大是3bytes)。控制的是自己发送过去的大小。
2.4.2 Abort Message (id-2)
1 | chunk stream id(4) |
终止某个 chunk 流
2.4.3 Acknowledgement (id-3)
1 | sequence number(4) |
2.4.4 Window Acknowledgement Size(id-5)
1 | Acknowledgement Window size(4) |
2.4.5 Set Peer Bandwidth(id-6)
1 | Acknowledgement Window size(4) | Limit Type(1) |
2.5 几个标记统一说明
2.5.1 Chunk Stream Id
在chunk层,在底层标记属于哪条数据流,1-3bytes.
cs id | 说明 |
---|---|
0 | 表示2bytes形式,真正的id是 第2字节+64 , 范围是 64~319 |
1 | 表示3bytes形式,真正的id是 第3字节*256 + 第2字节 + 64 , 范围是 64~65599 |
2 | 用于底层协议控制消息和命令 |
3~63 | 表示1bytes形式,就是第1个字节的后 6bits |
2.5.2 Message Stream Id
在 message 层 (Message Header), 用于标记数据流,一般1个 chunk stream id
中只有1个 message stream id
, 但应用也可以用 message stream id
再做链路复用。
4bytes, 小端.
message stream id | 说明 |
---|---|
0 | 控制信令流 |
其他 | 数据流 |
2.5.2 Message Type Id
在 message 层(Message Header),用于标记消息类型
message type id | 说明 |
---|---|
1 | set chunk size |
2 | abort message |
3 | acknowlodgement |
4 | user control message, 这个是应用层的控制信令,其他的控制信令是 RTMP 自己的 |
5 | window acknowledgement size |
6 | set peer bandwidth |
8 | audio message |
9 | video message |
15 | AMF3编码, Metadata或者其他用户数据,描述音视频元信息 |
16 | AMF3, Flash对象,共享数据,一组键值对, reserved |
17 | AMF3编码, 控制信令 |
18 | AMF0编码, Metadata或者其他用户数据,描述音视频元信息 |
19 | AMF0, Flash对象,共享数据,一组键值对 |
20 | AMF0编码, 控制信令 |
22 | aggregate message, 聚合信息,一组RTMP次级消息 |
3 RTMP Message Formats
3.1 Format
RTMP message has two parts, a header and its payload.
3.1.1 Message Header
1 | Message Type(1) | Payload length(3) | Timestamp(4) | Stream ID(3) |
- Message Type: 标记数据类型,1-6保留用作协议控制信息;
- Length: payload的长度,大端;
- Timestamp: 消息的时间戳, 大端;
- Message Stream Id: 标记流id,大端;
3.1.2 Message Payload
消息其余部分就是负载,可以包含音频帧,视频帧等。
3.2 User Control Messages
用户控制消息的 payload 格式为:
1 | event type(2) | event data |
Event | name | Description |
---|---|---|
0 | Stream Begin | 4bytes, 可以用的 stream ID, 通常在收到 connect 命令后发送 |
1 | Stream EOF | 4bytes, 流结束的 stream ID |
2 | StreamDry | 4bytes, 一定时间内没有流数据了, server通知客户端的 |
3 | Setbuffer Length | 4+4bytes, 前4表示 stream ID, 后4表示缓存长度(单位ms),client通知server要缓存多长时间的数据 |
4 | StreamIs Recorded | 4bytes, server 通知 client 这是个录制的流 |
6 | PingRequest | 4bytes, server 本地时间戳, server检测client是否可达 |
7 | PingResponse | 4bytes, client 本地时间戳 |
4 命令
一般都是一问一答。分两种: NetConnection, NetStream, 前者管理连接,后者描述动作。
4.1 NetConnection 命令
用于在应用层描述连接。
4.1.1 connect
client 发给 server,表示请求连接 server 实例.
Field Name | Type | Description |
---|---|---|
Command Name | String | “connect” |
Transaction ID | Number | Always set to 1 |
Command Object | Object | command information object which has the name-value pairs |
Optional User Arguments | Object | Any optional information |
Command Object:
Property | Type | Description | Example Value |
---|---|---|---|
app | String | server application name | testapp |
flashver | String | flash player version | FMSc/1.0 |
swfUrl | String | URL of the source SWF file | |
tcUrl | String | URL of the Server | rtmp://localhost:1935/testapp/instance1 |
audioCodecs | Number | Indicates what audio codecs the client supports. | SUPPORT_SND_MP3 |
videoCodecs | Number | video codecs | SUPPORT_VID_SORENSON |
object Encoding | Number | AMF encoding method | AMF3 |
audioCodecs:
Codec Flag | Usage | Value |
---|---|---|
SUPPORT_SND_NONE | Raw sound, no compression | 0x0001 |
SUPPORT_SND_ADPCM | ADPCM compression | 0x0002 |
SUPPORT_SND_MP3 | mp3 compression | 0x0004 |
SUPPORT_SND_INTEL | not used | 0x0008 |
SUPPORT_SND_UNUSED | not used | 0x0010 |
SUPPORT_SND_G711A | G711A sound compression | 0x0080 |
SUPPORT_SND_G711U | G711U sound compression | 0x0100 |
SUPPORT_SND_AAC | AAC codec | 0x0400 |
SUPPORT_SND_ALL | All RTMP-supported audio codecs | 0x0FFF |
videoCodecs:
Codec Flag | Usage | Value |
---|---|---|
SUPPORT_VID_UNUSED | obsolete value | 0x0001 |
SUPPORT_VID_JPEG | obsolete value | 0x0002 |
SUPPORT_VID_H264 | H264 video | 0x0080 |
SUPPORT_VID_ALL | All RTMP-supported video codecs | 0x00FF |
4.1.2 call
就是个RPC
4.1.3 createStream
client 通知 server 为推送的音视频数据创建逻辑通道。server在应答的时候会新建一个 Stream ID
.
4.2 NetStream 命令
4.2.1 play
可以发送多次,创建多个播放列表。
client 发送给 server 的结构:
Field Name | Type | Description |
---|---|---|
Command Name | String | “play” |
Transaction | Number | 0 |
Command Object | Null | 不需要 |
Stream Name | String | mp3:sample.m4v |
Start | Number | 开始时间,秒, 默认-2, 表示client先尝试LIVE, 再尝试VOD, 最后等着上流; -1表示只尝试LIVE, >=0表示只尝试VOD |
Duration | Number | 默认-1s, 表示播放到LIVE结尾或者VOD结尾 |
Reset | Boolean | 是否重置之前的播放列表 |
server 发送应答后, 会发送 audio/video 数据流。
4.2.2 play2
改变当前播放的码率
4.2.3 deleteStream
client 请求 server 来删除流。
4.2.4 recvAudio
client 通知 server 是否要发送 audio.
4.2.6 recvVideo
client 通知 server 是否要发送 video.
4.2.7 publish
client 通知 server, 要推流.
Field Name | Type | Description |
---|---|---|
Command Name | String | “publish” |
Transaction ID | Number | 0 |
Command Object | Null | does not exist |
Publishing Name | String | stream name |
Publishing Type | String | “live”, “record”, “append” |
4.2.8 seek
跳转
4.2.9 pause
是否暂停
5 总结
RTMP 是比较简单的协议,在同一TCP链路中同时处理信令和数据。配合FLV格式,组成了相对简单的流媒体传输协议。