0%

rtmp

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

rtmp handshake sequence

或者原文中的图:
rtmp handshak raw

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. 1字节id

    1
    fmt(2b) | cs id(6b)
  2. 2字节id

    1
    fmt(2b) | 0(6b) | cs id-64(1)
  3. 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种格式。

  1. 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 字段
  1. fmt=1 (7bytes)

去掉了 msg stream id, 用于可变长度数据(比如视频帧)

1
timestamp delta(3) | message length(3) | msg type id(1)
  1. fmt=2 (3bytes)

用于固定长度数据(比如音频帧).

1
timestamp delta(3)
  1. 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格式,组成了相对简单的流媒体传输协议。

6 参考

  1. https://rtmp.veriskope.com/pdf/rtmp_specification_1.0.pdf