Abstract
This memo describes the Real Time Messaging Protocol Chunk Stream(RTMP Chunk Stream),
an application-level protocol designed for multiplexing and packetizing multimedia transport
streams (such as audio, video, and interactive content) over a suitable transport protocol (such
as TCP).
本说明书描述了RTMP数据块流, 它是一个位于传输协议(如TCP)之上的应用层协议,
用于多路复用和封装多媒体传输流(如音频,视频,和交互内容)。
1. Introduction
The document specifies the Real Time Messaging Protocol Chunk
Stream(RTMP Chunk Stream). It provides multiplexing and packetizing
services for a higher-level multimedia stream protocol.
本文档说明了实时消息协议数据块流。它为更高级的多媒体流协议
提供了复用和封装服务。
While RTMP Chunk Stream was designed to work with the Real Time
Messaging Protocol [RTMP], it can handle any protocol that sends a
stream of messages. Each message contains timestamp and payload type
identification. RTMP Chunk Stream and RTMP together are suitable for
a wide variety of audio-video applications, from one-to-one and one-to-
many live broadcasting to video-on-demand services to interactive
conferencing applications.
当RTMP数据数据块流和RTMP一起工作时,它能处理所有能发送消息流的协议。
每个消息都包含有时间戳和负载类型标识。
RTMP数据块流和RTMP一起能广泛适用于各种音视频应用,从一对一和一对多的实时
广播,到VOD点播服务,到交互式的会议应用。
When used with a reliable transport protocol such as [TCP], RTMP
Chunk Stream provides guaranteed timestamp-ordered end-to-end
delivery of all messages, across multiple streams. RTMP Chunk Stream
does not provide any prioritization or similar forms of control, but
can be used by higher-level protocols to provide such prioritization.
For example, a live video server might choose to drop video messages
for a slow client to ensure that audio messages are received in a
timely fashion, based on either the time to send or the time to
acknowledge each message.
当使用可靠传输协议(如TCP)时,RTMP数据块流将提供有保障的
以时间戳为顺序的多种流的所有消息,端到端的传输。
RTMP数据块流没有提供任何优先级或类似的控制,但是可以通过
更高级的协议来实现优先级的控制。
例如,基于每个消息要么当前为发送,要么当前为通知收到,实时视频
服务器可以为了低速的客户端选择丢弃视频消息,来确保音频消息
都能在客户端及时收到。
RTMP Chunk Stream includes its own in-band protocol control messages,
and also offers a mechanism for the higher-level protocol to embed
user control messages.
RTMP数据块流包含有它自身内置的协议控制消息,同时还提供了为
更高级协议嵌入到用户控制消息的机制。
1.1. Terminology(术语)
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
2. Definitions(定义)
Payload:
The data contained in a packet, for example audio samples or
compressed video data. The payload format and interpretation are
beyond the scope of this document.
负载:包含有数据的包,例如,音频样本或压缩的视频数据。
负载的格式和说明超出了本文档的范畴。
Packet:
A data packet consists of fixed header and payload data. Some
underlying protocols may require an encapsulation of the packet to
be defined.
包:数据包由固定的头和负载数据组成。
有些底层的协议可能会要求要有一个包封装的定义。
Port:
The "abstraction that transport protocols use to distinguish among
multiple destinations within a given host computer. TCP/IP
protocols identify ports using small positive integers." The
transport selectors (TSEL) used by the OSI transport layer are
equivalent to ports.
端口:用于对给定主机区分多个目的地的传输协议的抽象。
TCP/IP协议使用小整数的端口。
Transport address:
The combination of a network address and port that identifies a
transport-level endpoint, for example an IP address and a TCP port.
Packets are transmitted from a source transport address to a
destination transport address.
传输地址:网络地址和端口的总称,它标识了一个传输层的端点。
例如,一个IP地址和一个TCP端口。
包都是从源传输地址到目的传输地址。
Message stream:
A logical channel of communication that allows the flow of messages.
消息流:允许消息流通信的逻辑通道。
Message stream ID:
Each message has an ID associated with it to identify the message
stream in which it is flowing.
消息流ID: 每个消息都有一个对应的ID,用来标识是哪个消息在流动。
Chunk:
A fragment of a message. The messages are broken into smaller parts
and interleaved before they are sent over the network. The chunks
ensure timestamp-ordered end-to-end delivery of all messages,
across multiple streams.
数据块:一个消息片断。消息在发送到网络前会切分成更小的部分
并交错。这些数据块确保了横跨多个流的所有消息按赶时间戳顺序
在端到端之间进行传输。
Chunk stream:
A logical channel of communication that allows flow of chunks in a
particular direction. The chunk stream can travel from the client
to the server and reverse.
数据块流:数据块流按特定的方向进行通信的逻辑通道。
数据块流能在客户端和服务器之间传输。
Chunk stream ID:
Every chunk has an ID associated with it to identify the chunk
stream in which it is flowing.
数据块流ID:每个数据块都有一个相应的ID,用来标识它
是哪个数据块流。
Multiplexing:
Process of making separate audio/video data into one coherent
audio/video stream, making it possible to transmit several video
and audio simultaneously.
多路复用:将分立的音频/视频数据合成一个音/视频流的处理,
从而使得在同一时间传输多个视频和音频成为可能。
DeMultiplexing:
Reverse process of multiplexing, in which interleaved audio and
video data are assembled to form the original audio and video data.
去复用:多路复用处理的逆过过程,将交错的音频和视频数据
重组还原成原始的音频和视频数据。
3. Byte Order, Alignment, and Time Format
字节顺序,对齐,和时间格式
All integer fields are carried in network byte order, byte zero is
the first byte shown, and bit zero is the most significant bit in a
word or field. This byte order is commonly known as big-endian.
The transmission order is described in detail in [STD5]. Unless
otherwise noted, numeric constants in this document are in decimal
(base 10).
所有的整数域都可以用来表示网络字节的顺序。字节零是第一个字节。
比特零是字节或字段中最重要的比特。
字节顺序即为通常所说的大端模式。
传输顺序的细节在STD5中描述。
除非另有声明,本文档中的数字常量都是十进制的。
Except as otherwise specified, all data in RTMP Chunk Stream is byte aligned;
for example, a 16-bit field may be at an odd byte offset.
Where padding is indicated, padding bytes SHOULD have the value zero.
Timestamps in RTMP Chunk Stream are given as an integer number of
milliseconds, relative to an unspecified epoch. Typically, each Chunk
Stream will start with a timestamp of 0, but this is not required, as
long as the two endpoints agree on the epoch. Note that this means
that any synchronization across multiple chunk streams (especially
from separate hosts) requires some additional mechanism outside of
RTMP Chunk Stream.
除非另有说明,否则,在RTMP数据块流中的所有数据都是字节对齐的。
例如,一个16比特的字段可是在一个奇数字节的偏移量,此时就会添加
填充字节,填充字节都是零值。
RTMP数据块流中的时间戳都是相对一个起始时间,以毫秒
(1秒=1000毫秒=1000 000微秒)为单位的整数表示。
通常,每个数据块流的时间戳都是从零开始。
但这并不是绝对要求的,只要通信的两个端点协商一个时间也是可以的。
这种情况下,多个数据块流的同步会要求额外的机制来保障。
Timestamps MUST be monotonically increasing, and SHOULD be linear in
time, to allow applications to handle synchronization, bandwidth
measurement, jitter detection, and flow control.
为了应用程序能处理同步,带宽,抖动检测,和流控制,时间戳必须是
单调递增的,并且是时间的线性关系。
Because timestamps are generally only 32 bits long, they will roll
over after fewer than 50 days. Because streams are allowed to run
continuously, potentially for years on end, an RTMP Chunk Stream
application MUST use modular arithmetic for subtractions and
comparisons, and SHOULD be capable of handling this wraparound
heuristically. Any reasonable method is acceptable, as long as both
endpoints agree. An application could assume, for example, that all
adjacent timestamps are within 2^31 milliseconds of each other, so
10000 comes after 4000000000, while 3000000000 comes before
4000000000.
通常,时间戳通常是32位比特长的,
因此,在50天左右将会用尽而翻转再从零开始。
但是流是允许长年累月地运行,因此RTMP数据块流的应用程序
必须对差值进行模运行并比较(?什么意思),并且要能启发式地处
理这种无限循环。
只要通信的两个端口一致,任何合理的方式都可以使用。
例如,应该程序能假设成这样,所有相邻的时间戳值都在2^31毫秒
的值域之内,如10 000之后是4 000 000 000,3 000 000 000是出现
在4 000 000 000之前。
Timestamp deltas are also specified as an unsigned integer number of
milliseconds, relative to the previous timestamp. Timestamp deltas
may be either 24 or 32 bits long.
时间戳偏移量是一个相对于前一个时间戳,定义的一个毫秒表示的
无符号整数。时间戳偏移量可以是24或32比特长。
4. Message Format(消息格式)
The format of a message that can be split into chunks to support
multiplexing, depends on higher level protocol. The message format
SHOULD however contain the following fields which are necessary for
creating the chunks.
依靠更高级的协议,消息格式能被切分成数据块以支持多路复用。
然而,消息格式在创建数据块时必须包含下列字段。
Timestamp:
Timestamp of the message. This field can transport 4 bytes.
时间戳:消息的时间戳,该字段占四个字节。
Length:
Length of the message payload. If the message header cannot be
elided, it should be included in the length. This field occupies 3
bytes in the chunk header.
长度:消息负载的长度。如果消息头不能被省略,则也应该包含
消息头的长度。该字段在数据块头中占3个字节。
Type Id:
A range of type IDs are reserved for protocol control messages.
These messages which propagate information are handled by both RTMP
Chunk Stream protocol and the higher-level protocol. All other type
IDs are available for use by the higher-level protocol, and treated
as opaque values by RTMP Chunk Stream. In fact, nothing in RTMP
Chunk Stream requires these values to be used as a type; all (nonprotocol)
messages could be of the same type, or the application
could use this field to distinguish simultaneous tracks rather than
types. This field occupies 1 byte in the chunk header.
类型ID: 有一部分类型ID保留给协议控制消息。这些传播信息的
协议可以被RTMP数据块流协议和更高级协议处理。
所有剩下的类型ID只对更高级的协议有效,对RTMP数据块流则
不可见。实际上,RTMP数据块流对用于类型的值没有任何要求。
所有的消息(非协议的)可以是同一个类型,或者应用程序可以用这个
字段来区分同时发送的轨道而不是类型。
这个字段在数据块头中占有一个字节。
Message Stream ID:
The message stream ID can be any arbitrary value. Different message
streams multiplexed onto the same chunk stream are demultiplexed
based on their message stream IDs. Beyond that, as far as RTMP
Chunk Stream is concerned, this is an opaque value. This field
occupies 4 bytes in the chunk header in little endian format.
消息流ID: 可以是任意值。不同的消息流复用到一个相同的数据块流后
可以使用这个消息流ID来解复用。
另外,对于RTMP数据块流来说,这是一个透明值,。
这个字段在数据块头中占有四个字节,以小端格式。
5. Handshake
An RTMP connection begins with a handshake. The handshake is unlike
the rest of the protocol; it consists of three static-sized chunks
rather than consisting of variable-sized chunks with headers.
The client (the endpoint that has initiated the connection) and the
server each send the same three chunks. For exposition, these chunks
will be designated C0, C1, and C2 when sent by the client; S0, S1,
and S2 when sent by the server.
握手:RTMP连接从握手开始。
这个握手和其它的协议不同,它是由头中三个固定大小的数据块组成。
而不是像其它的协议由头中的变大小的数据块组成。
客户端和服务器端每次发送相同的三个数据块。
为了说明,
由客户端发送的三个数据块标识为C0, C1, 和C2。
由服务端发送的三个数据块标识为S0, S1, 和S2。
5.1. Handshake sequence
The handshake begins with the client sending the C0 and C1 chunks.
The client MUST wait until S1 has been received before sending C2.
The client MUST wait until S2 has been received before sending any
other data.
The server MUST wait until C0 has been received before sending S0 and
S1, and MAY wait until after C1 as well. The server MUST wait until
C1 has been received before sending S2. The server MUST wait until C2
has been received before sending any other data.
握手顺序:
握手时,
客户端先发送C0和C1数据块,
客户端等待直到收到S1后,发送C2。
客户端等待直到收到S2后,才发送其它数据。
服务端等待直到收到C0后,才发送S0和S1,
服务端等待直到收到C1后,才发送S2。
服务端等待直到收到C2后,才发送其它数据。
5.2. C0 and S0 Format(C0和S0格式)
The C0 and S0 packets are a single octet, treated as a single 8-bit integer field:
C0和S0包是一个8比特的字节,可以看作是一个8比特整数域:
Figure 1 C0 and S0 bits
Following are the fields in the C0/S0 packets:
Version: 8 bits
In C0, this field identifies the RTMP version requested by the
client. In S0, this field identifies the RTMP version selected by
the server. The version defined by this specification is 3. Values
0-2 are deprecated values used by earlier proprietary products; 4-
31 are reserved for future implementations; and 32-255 are not
allowed (to allow distinguishing RTMP from text-based protocols,
which always start with a printable character). A server that does
not recognize the client's requested version SHOULD respond with 3.
The client MAY choose to degrade to version 3, or to abandon the
handshake.
在C0中,这个字段定义为客户端请求的RTMP版本。
在S0中,这个字段定义为服务端选择的RTMP版本。
本文档中,该版本定义为3。
0-2是弃用值,4-31是预留值。32-255是非法值(这样做是为了区分
基于文本的协议,因为这些协议通常都是以一个可打印的字符开始)。
如果服务端不能识别客户请求的版权,那么它应该发送3的响应,
客户端这时可以选择下降到版本3,也可以放弃这次握手。
5.3. C1 and S1 Format(C1和S1的格式)
The C1 and S1 packets are 1536 octets long, consisting of the following fields:
C1和S1长度为1536个字节,由下列字节组成:
Figure 2 C1 and S1 bits
Time: 4 bytes
This field contains a timestamp, which SHOULD be used as the epoch
for all future chunks sent from this endpoint. This may be 0, or
some arbitrary value. To synchronize multiple chunk streams, the
endpoint may wish to send the current value of the other
chunk stream's timestamp.
时钟:4 bytes
这个字段包含了一个时间戳,它是所有从这个端点发送出去的将来数据块的起始点。
它可以是零,或是任意值。
为了同步多个数据块流,端点可能会将这个字段设成其它数据块流时间戳的当前值。
Zero: 4 bytes
This field MUST be all 0s.
零:4 bytes
Random data: 1528 bytes
This field can contain any arbitrary values. Since each endpoint
has to distinguish between the response to the handshake it has
initiated and the handshake initiated by its peer, this data SHOULD
send something sufficiently random. But there is no need for
cryptographically-secure randomness, or even dynamic values.
随机数:1528 bytes
这个字段可以是任意值。
因为每个端点必须区分已经初始化的握手和对等端点初始化的握手的响应,
这个数据要足够的随机。当然,这个也不用密码级的随机,或是动态值。
5.4. C2 and S2 Format
The C2 and S2 packets are 1536 octets long, and nearly an echo of S1
and C1 (respectively), consisting of the following fields:
C2和S2包长都是1536字节,几乎是S1和C1的回显,组成的
字段如下:
Figure 3 C2 and S2 bits
Time: 4 bytes
This field MUST contain the timestamp sent by the peer in S1 (for C2) or C1 (for S2).
该字段包含有对方发送过来S1或C1的时间戳。
Time2: 4 bytes
This field MUST contain the timestamp at which the previous
packet(s1 0r c1) sent by the peer was read.
该字段包含有对方发送过来的前一个包的时间戳。
Random echo: 1528 bytes
This field MUST contain the random data field sent by the peer in
S1 (for C2) or S2 (for C1).
Either peer can use the time and time2 fields together with the
current timestamp as a quick estimate of the bandwidth and/or
latency of the connection, but this is unlikely to be useful.
随机值回显:这个字段包含有对方发送过来的随机数据字段。
每个通信端点可以使用time和time2字段,以及当前的时间戳
来快速估计带宽和/或连接时延。
但这个数值基本上没法用。
5.5. Handshake Diagram
握手流程图
客户端先发送C0和C1
服务端等待直到收到C0后,才发送S0和S1
服务端等待直到收到C1后,才发送S2
客户端等待直到收到S2后,才发送其它数据
服务端等待直到收到C2后,才发送其它数据
Figure 4 Pictorial Representation of Handshake
The following table describes the states mentioned in the hand shake
diagram:
下面的表描述了上面握手状态图中的状态:
未初始化:
在这个阶段,协议版本被发送,客户和服务端都是未初始化的。
客户端在包C0中发送协议版本。
如果服务端支持这个版本,它将会发送S0和S1作为响应。
如果不支持,则服务端会用相应的动作来响应,在RTMP中,
这个动作是结束这个连接。
版本发送完成:
客户端和服务端在未初始化状态之后都进入到版本发送完成状态。
客户端等待包S1,而服务端等待包C1。
在收到相应的包后,客户端发送包C2,而服务端发磅包S2。
状态变成询问发送完成。
询问发送完成:
客户端和服务端等待S2和C2。
握手完成:
客户端和服务端开始交换消息。
+-------------+----------------------------------------------------+
librtmp中关于RTMP握手(见librtmp/rtmp.c文件)的分析:
add_addr_info() //解析服务器地址
RTMP_Connect0()
{
// 创建socket
r->m_sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// 和服务器建立连接
connect(r->m_sb.sb_socket, service, sizeof(struct sockaddr);
// 设置连接超时
setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
// 设置时延
setsockopt(r->m_sb.sb_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on));
}
HandShake()
{
/* 1st part of handshake */
WriteN()
{
/*
* buf[] = {0x03, 0x00, 0x00, 0x00, 0x00,... 0x00};
* len = 1 + 1536 = 1537
* 发送C0和C1
*/
rc = send(sb->sb_socket, buf, len, 0);
}
ReadN()
{
/*
* sb->sb_start+sb->sb_size[]= {0x03, }
* 接收到S0和S1
*/
nBytes = recv(sb->sb_socket, sb->sb_start + sb->sb_size, nBytes, 0);
}
/* 2nd part of handshake */
WriteN()
{
/*
* buf[] = {S1的复制};
* len = 1536
* 发送C2
*/
rc = send(sb->sb_socket, buf, len, 0);
}
ReadN()
{
/*
* 接收S2
*/
nBytes = recv(sb->sb_socket, sb->sb_start + sb->sb_size, nBytes, 0);
}
}
6. Chunking(数据块)
After handshaking, the connection multiplexes one or more chunk
streams. Each chunk stream carries messages of one type from one
message stream. Each chunk that is created has a unique ID associated
with it called chunk stream ID. The chunks are transmitted over the
network. While transmitting, each chunk must be sent in full before
the next chunk. At the receiver end, the chunks are assembled into
messages based on the chunk stream ID.
在握手之后,这个连接多路复用一个或多个数据块流。
每个数据块流携带有一个消息流的一种消息。
每个数据块都有一个相应的ID号,叫做数据块流ID。
这些数据块都是通过网络传输。
传输时,每个数据块必须完整发送后才发送下一个。
在接收端,数据块基于它的数据块流ID组成消息。
Chunking allows large messages at the higher-level protocol to be
broken down into smaller messages,for example, to prevent large lowpriority
messages from blocking smaller high-priority messages.
数据块允许将更上层协议的大消息切分成更小的消息,
例如,为了防止大的低的低优先级消息而阻塞小的高优先级消息。
Chunking also allows small messages to be sent with less overhead, as
the chunk header contains a compressed representation of information
that would otherwise have to be included in the message itself.
数据块同样能用很小的负载来发送小消息,
当数据块头包含一个压缩的信息表示,这样就不需要包含消息本身。
The chunk size is configurable. It can be set using a control
message(Set Chunk Size) as described in section 7.1. The maximum
chunk size can be 65536 bytes and minimum 128 bytes. Larger values
reduce CPU usage, but also commit to larger writes that can delay
other content on lower bandwidth connections. Smaller chunks are not
good for high-bit rate streaming. Chunk size is maintained
independently for each direction.
数据块大小是可配置的。
这个大小可以使用7.1节的控制消息来设置数据块的大小。
数据块最大可以是65536bytes, 最小为128bytes。
较大的值能减少CPU负载,但是会造成其它内容在低带宽连接中导致延迟。
过小的数据块同样也不适于高码率的流。
数据块大小对于两个方向的数据传输来说是相互独立的。
6.1. Chunk Format(数据块格式)
Each chunk consists of a header and data. The header itself is broken
down into three parts:
每个数据块都是由头和数据组成的。
头本身可以分成如下三个部分:
Figure 5 Chunk Format.
Chunk basic header: 1 to 3 bytes
This field encodes the chunk stream ID and the chunk type. Chunk
type determines the format of the encoded message header. The
length depends entirely on the chunk stream ID, which is a
variable-length field.
数据块基本头:该字段编码了数据块流ID和数据块类型。
数据块类型决定了编码后消息头的格式。
该字段的长度完全依赖于数据流ID,它是一个变长字段。
Chunk message header: 0, 3, 7, or 11 bytes
This field encodes information about the message being sent
(whether in whole or in part). The length can be determined using
the chunk type specified in the chunk header.
数据块消息头:该字段编码了被发送消息的信息。
它的长度由数据块头中指定的数据块类型来决定。
Extended timestamp: 0 or 4 bytes
This field MUST be sent when the normal timsestamp is set to
0xffffff, it MUST NOT be sent if the normal timestamp is set to
anything else. So for values less than 0xffffff the normal
timestamp field SHOULD be used in which case the extended timestamp
MUST NOT be present. For values greater than or equal to 0xffffff
the normal timestamp field MUST NOT be used and MUST be set to
0xffffff and the extended timestamp MUST be sent.
扩展时间戳:
当通常的时间戳被设置成0XFFFFFF时,这个字段就必须被发送。
当通常的时间戳被设置成其它值时,这个字段不能被发送。
6.1.1. Chunk Basic Header(数据块基本头)
The Chunk Basic Header encodes the chunk stream ID and the chunk
type(represented by fmt field in the figure below). Chunk type
determines the format of the encoded message header. Chunk Basic
Header field may be 1, 2, or 3 bytes, depending on the chunk stream
ID.
数据块基本头编码了数据块流ID和数据块类型(由下图fmt域表示)。
数据块类型确定了编码后的的消息头的类型。
依赖于数据块流ID,数据块基本头字段可以是1,2,和3bytes。
An implementation SHOULD use the smallest representation that can
hold the ID.
真实的实现应当使用最小的能用ID来表示。
The protocol supports up to 65597 streams with IDs 3–65599. The IDs
0, 1, and 2 are reserved. Value 0 indicates the ID in the range of
64–319 (the second byte + 64). Value 1 indicates the ID in the range
of 64–65599 ((the third byte)*256 + the second byte + 64). Value 2
indicates its low-level protocol message. There are no additional
bytes for stream IDs. Values in the range of 3–63 represent the
complete stream ID. There are no additional bytes used to represent it.
本协议最多支持65597个流,ID号为3-65599。
ID 0,1,2为保留值。
值0指示了ID的范围在64-319(第二个字节+64);
值1指示了ID的范围在64-65599(第三个字节*256+第二个字节+64);
值2指示了它的低级协议消息。
流ID没有更多的额外字节。
3-63表示完整的流ID。
The bits 0–5 (least significant) in the chunk basic header represent
the chunk stream ID.
数据块基本头的0-5比特表示数据块流ID。
Chunk stream IDs 2-63 can be encoded in the 1-byte version of this field.
数据块流ID2-63被编码在这个字段的一字节版本中。
Figure 6 Chunk basic header 1
Chunk stream IDs 64-319 can be encoded in the 2-byte version of this
field. ID is computed as (the second byte + 64).
数据块流ID64-319被编码成本字段的两字节版本中。
ID的计算方式为:第二字节+64.
Figure 7 Chunk basic header 2
Chunk stream IDs 64-65599 can be encoded in the 3-byte version of
this field. ID is computed as ((the third byte)*256 + the second byte+ 64).
数据块ID64-65599被编码成本字段的三字节版本中。
ID的计算方式为:第三字节*256+第二字节+64。
Figure 8 Chunk basic header 3
cs id: 6 bits
This field contains the chunk stream ID, for values from 2-63.
Values 0 and 1 are used to indicate the 2- or 3-byte versions of
this field.
这个字段包含了数据块ID,值为2-63.
值0和1用来指示本字段的二字节或三字节版本中。
fmt: 2 bits
This field identifies one of four format used by the ‘chunk message
header’.The ‘chunk message header’ for each of the chunk types is
explained in the next section.
该字段用于“数据块消息头”四种格式之一。
数据块消息头和数据块类型的对应将在下节中详述。
cs id - 64: 8 or 16 bits
This field contains the chunk stream ID minus 64. For example, ID
365 would be represented by a 1 in cs id, and a 16-bit 301 here.
该字段包含数据块流ID-64。
例如,ID365表示为cs id = 1和16比特表示的301。
Chunk stream IDs with values 64-319 could be represented by both 2-
byte version and 3-byte version of this field.
数据块流ID64-319由二字节或三字节版本表示。
6.1.2. Chunk Message Header(数据块消息头)
There are four different formats for the chunk message header,
selected by the "fmt" field in the chunk basic header.
An implementation SHOULD use the most compact representation possible
for each chunk message header.
在数据块基本头的“fmt”字段中表示有四种类型的数据块消息头。
应用程序的实现使用对每个数据块消息头最匹配的表示。
6.1.2.1. Type 0
Chunks of Type 0 are 11 bytes long. This type MUST be used at the
start of a chunk stream, and whenever the stream timestamp goes
backward (e.g., because of a backward seek).
类型0的数据块为11bytes长。
这种类型必须被用在数据块流的起始位置,并且流时间戳为逆向的。
Figure 9 Chunk Message Header – Type 0
timestamp: 3 bytes
For a type-0 chunk, the absolute timestamp of the message is sent
here. If the timestamp is greater than or equal to 16777215
(hexadecimal 0x00ffffff), this value MUST be 16777215, and the
‘extended timestamp header’ MUST be present. Otherwise, this value
SHOULD be the entire timestamp.
对于类型0的数据块,消息的绝对时间戳在此处发送。
如果时间戳大于或等于16777215(0x00FFFFFF),则该值设成16777215,
并且“扩展时间戳头”必须使用。
否则,这个值必须是完整的时间戳。
6.1.2.2. Type 1
Chunks of Type 1 are 7 bytes long. The message stream ID is not
included; this chunk takes the same stream ID as the preceding chunk.
Streams with variable-sized messages (for example, many video
formats) SHOULD use this format for the first chunk of each new
message after the first.
类型1数据块为7字节长。消息流ID不包括在内。
数据块和前面的数据采用相同的流ID。
变长消息流(例如,许多视频格式)应该为每个新消息的第一个数据块
使用这个格式。
Figure 10 Chunk Message Header – Type 1
6.1.2.3. Type 2
Chunks of Type 2 are 3 bytes long. Neither the stream ID nor the
message length is included; this chunk has the same stream ID and
message length as the preceding chunk. Streams with constant-sized
messages (for example, some audio and data formats) SHOULD use this
format for the first chunk of each message after the first.
类型2数据块为3bytes长。
流ID和消息长度均不包括在内;
这种数据块的流ID和消息长度和前面的数据块相同。
定长消息的流应当用于第一个消息之后的每个消息的第一个数据块。
Figure 11 Chunk Message Header – Type 2
6.1.2.4. Type 3
Chunks of Type 3 have no header. Stream ID, message length and
timestamp delta are not present; chunks of this type take values from
the preceding chunk. When a single message is split into chunks, all
chunks of a message except the first one, SHOULD use this type. Refer
to example 2 in section 6.2.2. Stream consisting of messages of
exactly the same size, stream ID and spacing in time SHOULD use this
type for all chunks after chunk of Type 2. Refer to example 1 in
section 6.2.1. If the delta between the first message and the second
message is same as the time stamp of first message, then chunk of
type 3 would immediately follow the chunk of type 0 as there is no
need for a chunk of type 2 to register the delta. If Type 3 chunk
follows a Type 0 chunk, then timestamp delta for this Type 3 chunk is
the same as the timestamp of Type 0 chunk.
类型3数据块没有头。
流ID,消息长度和时间戳偏移量均不存在;
这种类型的数据块是从前面的数据块获得相应值。
当单个消息切分成数据块时,除了第一个数据块外,该消息的
数据块都要使用这种类型。
对于6.2.2节中的例2,由相同大小消息组成的流来说,流ID和
时间上的间隔在类型2数据块之后的所有数据块都要使用这种类型。
对于6.2.1节中的例1,如果第一个消息和第二消息的时间戳偏移量
和第一个消息的时间戳相当,那么类型0数据块之后就必须立即使用
类型3数据块,这时就不需要用类型2数据块来注册时间戳偏移量。
如果类型0数据块之后是类型3数据块,那么对于类型3数据块的时间
戳偏移量和类型0数据块的时间戳相同。
Description of each field in the chunk message header.
timestamp delta(时间戳偏移量): 3 bytes
For a type-1 or type-2 chunk, the difference between the previous
chunk's timestamp and the current chunk's timestamp is sent here.
If the delta is greater than or equal to 16777215 (hexadecimal
0x00ffffff), this value MUST be 16777215, and the ‘extended
timestamp header’ MUST be present. Otherwise, this value SHOULD be
the entire delta.
对于类型1或类型2数据块,前一个数据块和当前数据块的时间戳
之差在此发送。
如果偏移量大于或等于16777215(0x00FFFFFF),这个值必须设为16777215。
并且必须使用“扩展时间戳头”。否则,这个值应该当是完整的偏移量。
message length(消息长度): 3 bytes
For a type-0 or type-1 chunk, the length of the message is sent here.
对于类型0或类型1数据块,消息的长度在此发送。
Note that this is generally not the same as the length of the chunk payload.
The chunk payload length is the maximum chunk size for all
but the last chunk, and the remainder (which may be the entire
length, for small messages) for the last chunk.
注意: 数据块负载的长度通常是不同的。
数据块负载长度除了最后一个数据块外都是最大数据块大小,
并且剩下的(对于小消息来说,它可能是整个长度)字节在最后一个数据块。
message type id(消息类型ID): 1 byte
For a type-0 or type-1 chunk, type of the message is sent here.
对于类型0或类型1数据块,消息类型在此发送。
message stream id(消息流ID): 4 bytes
For a type-0 chunk, the message stream ID is stored. Message stream
ID is stored in little-endian format. Typically, all messages in
the same chunk stream will come from the same message stream.
While it is possible to multiplex separate message streams into the same
chunk stream, this defeats all of the header compression. However,
if one message stream is closed and another one subsequently
opened, there is no reason an existing chunk stream cannot be
reused by sending a new type-0 chunk.
对于类型0数据块,其本身包含有消息流ID.
消息流ID被存储为小端格式。
通常,所有相同数据块流的消息都是出自相同的消息流。
如果是多个分立的消息流合成一个相同数据块流,这种情况不能使用
任何头压缩。
然而,如果一个消息流关闭而另一个子序列打开,通过发送一个新的
类型0数据块来重用已存在的数据块流。
6.1.3. Extended Timestamp(扩展时间戳)
This field is transmitted only when the normal time stamp in the
chunk message header is set to 0x00ffffff. If normal time stamp is
set to any value less than 0x00ffffff, this field MUST NOT be
present. This field MUST NOT be present if the timestamp field is not
present. Type 3 chunks MUST NOT have this field.
This field if transmitted is located immediately after the chunk
message header and before the chunk data.
这个字段只在通常的数据块消息头的时间戳被置为0x00FFFFFF
时才使用。
如果一般的时间戳小于0x00FFFFFF,这个字段不能使用。
类型3数据块不能使用这个字段。
这个字段的传送位置在数据块消息头之后,数据块数据之前。
如下图所示:
Figure 12 Chunk Format.
6.2. Examples
6.2.1. Example 1
Example 1 shows a simple stream of audio messages.
This example demonstrates the redundancy of information.
例1显示了一个简单的音频消息流。
这个例子描述的是信息冗余度。
Figure 13 Sample Audio messages to be made into chunks
The next table shows chunks produced in this stream. From message 3
onward, data transmission is optimized. There is only 1 byte of
overhead per message beyond this point.
下面的表显示了流中数据块。
从消息3起,优化了数据传输。第个消息只有一个字节的消耗
Figure 14 Format of each of the chunks of audio messages above
6.2.2. Example 2
Example 2 illustrates a message that is too long to fit in a 128-
chunk and is broken into several chunks.
例2显示了消息长度超过了128字节时,要分成多个数据块。
Figure 15 Sample Message to be broken to chunks
Here are the chunks that are produced:
下面是该消息的数据块:
Figure 16 Format of each of the broken chunk.
The header data of chunk 1 specifies that the overall message is 307 bytes.
数据块1的头数据指示了整个消息长度为307bytes。
Notice from the two examples, that chunk type 3 can be used in two
different ways. The first is to specify the continuation of a
message. The second is to specify the beginning of a new message
whose header can be derived from the existing state data.
注意:从上面的两个例子可以看出,数据块类型3可以以两种不同的方式
使用。
第一种用来说明一个连续的消息。
第二种用来说明一个新消息的开始,它的头可以源于当前存在的状态数据。
7. Protocol Control Messages
RTMP Chunk Stream supports some protocol control messages. These
messages contain information required by RTMP Chunk Stream protocol
and will not be propagated to the higher protocol layers. Currently
there are two protocol messages used in RTMP Chunk Stream. One
protocol message is used for setting the chunk size and the other is
used to abort a message due to non-availability of remaining chunks
RTMP数据块流支持多种协议控制消息。
这些消息包含有RTMP数据流协议所需的信息,并被传递到更高的
协议层。
在RTMP数据块流中,当前支持两种协议消息。
一种协议消息用来设置数据块的大小;
一种协议消息用来在剩余数据块无效时丢弃消息。
Protocol control messages SHOULD have message stream ID 0(called as
control stream) and chunk stream ID 2, and are sent with highest
priority.
协议控制消息的消息流ID为0(称作控制流)且数据块流ID为2。
它们都将以最高优先级发送。
Each protocol control message type has a fixed-size payload, and is
always sent in a single chunk.
每种类型的协议控制消息都有固定大小的负载,
并在单个数据块中发送。
7.1. Set Chunk Size(设置数据块大小)
Protocol control message 1, Set Chunk Size, is used to notify the
peer about the new maximum chunk size.
协议控制消息类型1,设置数据块大小,用来提示通信对方新的
最大的数据块大小。
A default value can be set for the chunk size, but the client or the
server can change this value and update it to the peer. For example,
suppose a client wants to send 131 bytes of audio data and the chunk
size is 128. In this case, the client can send this protocol message
to the server to notify that the chunk size is set to 131 bytes. The
client can then send the audio data in a single chunk.
可以使用默认值来设置数据块大小,
但是客户端或服务端可以改变这个值并通知通信对方。
例如,如果客户端想发送131bytes的音频数据并且数据块大小是
128bytes。在这种情况下,客户端可以发送这个协议消息给服务端
来提示数据块大小已设置成了131bytes。
这样,客户端就能在一个数据块内发送完音频数据。
The maximum chunk size can be 65536 bytes. The chunk size is
maintained independently for each direction.
最大的数据块大小可以设置为65536bytes。
数据块大小在每个通信方向是独立的。
7.2. Abort Message(丢弃消息)
This protocol control message is used to notify the peer if it is
waiting for chunks to complete a message, then to discard the
partially received message over a chunk stream. The peer receives the
chunk stream ID as this protocol message’s payload. An application
may send this message when closing in order to indicate that further
processing of the messages is not required.
这个协议控制消息用来通知通信对方,如果它是在等待结束消息
的数据块,那么它要部分丢弃收到的消息。
通信对方收到这个数据块流ID作为它的协议控制消息的负载。
应用程序将会有结束时发送这个消息,以用于指示对这个消息
更多的处理是不必要的。
8. References
8.1. Normative References
[1] Bradner, S., "Key words for use in RFCs to Indicate Requirement
Levels", BCP 14, RFC 2119, March 1997.
[2] Crocker, D. and Overell, P.(Editors), "Augmented BNF for Syntax
Specifications: ABNF", RFC 2234, Internet Mail Consortium and
Demon Internet Ltd., November 1997.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
[RFC2234] Crocker, D. and Overell, P.(Editors), "Augmented BNF for
Syntax Specifications: ABNF", RFC 2234, Internet Mail
Consortium and Demon Internet Ltd., November 1997.
8.2. Informative References
[3] Faber, T., Touch, J. and W. Yue, "The TIME-WAIT state in TCP
and Its Effect on Busy Servers", Proc. Infocom 1999 pp. 1573-
1583.
[Fab1999] Faber, T., Touch, J. and W. Yue, "The TIME-WAIT state in
TCP and Its Effect on Busy Servers", Proc. Infocom 1999 pp.
1573-1583.
9. Acknowledgments
Address:
Adobe Systems Incorporated
345 Park Avenue
San Jose, CA 95110-2704