http://blog.csdn.net/defonds/article/details/17403225
译序:本文是维基百科关于 RTMP 的解释, 关于 RTMP 官方规范参见 ,关于 RTMP 官方规范的中文版,参见《》。以下是维基百科原文:
实时消息传输协议(RTMP)最初是由 Macromedia 为互联网上 Flash player 和服务器之间传输音频、视频以及数据流而开发的一个私有协议。Adobe 收购 Macromedia 购以后,公布了这个协议的一部分,以备公共使用。
RTMP 协议有多个变种: 1. 工作在 TCP 协议之上,并使用默认端口号 1935 的明文协议。 2. RTMPS 使用 TLS/SSL 连接的 RTMP 协议。 3. RTMPE 使用 Adobe 自己的安全机制的加密 RTMP。虽然它的实现细节是私有的,但使用的是行业标准加密原语。RTMPE 的设计是有缺陷的,它本身并不提供实际的安全。 4. RTMPT 封装在 HTTP 请求内部以穿越防火墙的协议。RTMPT 常用于建立 TCP 端口 80 和 443 的请求以绕开很多公司的流量过滤。封装的会话中可能会携带纯 RTMP、RTMPS 或者 RTMPE 包。
尽管 RTMP 协议的本意是一个用于播放 Flash 视频的协议,但它也往往用于其他应用,比如 Adobe LiveCycle数据服务。
基本操作 RTMP(RTMFP 除外)是一个基于 TCP 的、持久连接并提供低延迟通信的协议。为了能够顺利地传输流,并且传递尽可能多的信息,RTMP 对流进行分段,客户端和服务器可以对分段长度进行协商,尽管有时分段长度是不变的:对于音频数据默认分段长度是 64 字节,视频数据和大部分其他数据类型默认分段长度是为 128 字节。来自不同流的段会被隔离,并对单一连接的段进行合成。对于比较长的数据块,RTMP 会在每一段中携带一个单字节头,所以开销很小。然而,事实应用中,不同的段并不互相交叉。交叉和合成是在数据包层完成的,RTMP 包穿过不同的活跃通道进行交叉,用这种方法来保证每个通道都满足各自的带宽、延迟以及其他一些服务质量的需求。这种模型下交叉的 RTMP 包被视为不可分割的,并且在分段级别是不交叉的。 RTMP 定义了一些虚拟通道,通过它们可以发送和接收 RTMP 包,并且这些通道彼此是独立运作的。例如,可能会有一个用于处理 RPC 请求和响应的通道,一个用于视频流数据的通道,一个用于音频流数据的通道,一个用于带外控制信息(分段长度协商,等等)的通道,等等。在一个典型的 RTMP 会话中,在任意给定时间内,可能会有几个通道是同时活跃的。当 RTMP 数据被编码时,会产生一个包头。包头定义了其他一些事项,要发送到通道的 id,这一包产生时的 timestamp (如果需要的话),以及这一包的有效负载。包头后紧跟这一包实际负载的内容,包的内容是在发送给连接前根据当前协商好的分段长度分割好的。包头自己不会分 段,并且包头的长度也不会被计入这一包第一个分段的长度中去。换句话说,分段的主题仅仅是 RTMP 的包负载(音频数据)。 更高一层讲,RTMP 压缩 MP3 或者 AAC 音频和 FLV1 视频多媒体流,并使用 AMF (Action Message Format) 协议进行远程方法调用 (RPCs)。所需的 RPC 服务都是异步的,它们使用单一的 client/server request/response 模型,因此不需要实时通信。 加密 RTMP 会话可以使用以下两种方法的任意一种进行加密: 使用行业标准 TLS/SSL 机制。底层的 RTMP 会话呗简单地封装在一个普通的 TLS/SSL 会话中。 使用 RTMPE,将 RTMP 会话封装在一个轻量级的加密层里。 普遍认为,会话开始时的 TLS/SSL 握手是非常计算密集型的。Adobe 开发了 RTMPE 作为一个轻量级的替代,给提供加密服务的高流量的站点一个实用的选择。Adobe 通告 RTMPE 作为一个安全内容传递的方法,以避免模拟客户端的操作,这种说法是错误的。RTMPE 仅使用了 Diffie-Hellman 机制,没有提供任何一方的身份验证,这很容易在会话初始化时受到中间人攻击。 HTTP 隧道 在 RTMP 隧道 (RTMPT) 中,RTMP 数据被密封起来并通过 HTTP 进行交换,来自客户端(在这种情况下客户端是为 media player)的信息发送给服务器上的端口 80 (HTTP 默认端口号)。 由于 HTTP 头的缘故,RTMPT 中的信息要比等效的非通道的 RTMP 信息大,在非通道 RTMP 不可以的场景中,比如当客户端处于一个阻止非 HTTP 和 非 HTTPS 网络流通时,RTMPT 可以便利地使用。 这个协议通过使用 POST url 发送命令和使用 POST 体发送 AMF 消息进行工作。例子:
- POST /open/1 HTTP/1.1
用于打开一个连接。
规范文档 Adobe 公开声明的规范是 2009 年 6 月 15 日发布的 RTMP specification。那个规范,忽略了(应该说没有公开) 协议实现的关键细节。很难单单根据发布的规范将 RTMP 协议整合进我们的程序里,太多必不可少的细节被忽略了,我们只能够通过学习实现了这个协议的应用 (比如 librtmp),以及根据测试 TCP/IP 数据包捕获,来断定其很少的细节。 Adobe 关于使用这一协议的 license 要求 RTMP 服务器的实现满足这一规范。 Adobe 发布的规范中缺少的细节包括:
- 关于 RTMP 握手没有只言片语的描述。如果(关于握手)做的不正确,服务器的实现将无法传递 H.264/AAC 内容。如果握手错误,Flash player 会默默地接收 H.264 内容失败。但是所有的客户端实现能够正常工作,因为 RTMP 服务器在这方面比较宽容(包括 FMS)。
- 发送的块只以最大块大小发送;超出那个大小的块仍会被发送,这个块带有整个块大小的头,但是当超出最大块大小后,一个类型为 4 的块头会被发送,紧跟其后的是这一块被分割出来的下一部分。
- 关于流的管理信息的解释缺失(31 和 32)。FMS 会时不时发送这些包。
数据包格式
数据包由客户端和服务器之间建立的 TCP 连接进行发送。数据包包含一个头和一个体,至于连接和控制命令使用 AMF(Action Message Format)编码。头分为基本报头(在图中显示为分离出来的那块)和块消息报头。基本报头是数据包唯一不变的部分,常常由一个复合字节组成,两个有效位 代表块类型(规范中的格式),其余的组成了流 id。根据前者的值,一些消息头字段可以被忽略掉,这些字段由前面的数据包根据后面的值派生出来,基本报头可以使用两个额外字节进行扩展(图中的情况总共 有三个字节)。块消息报头包含 meta-data 信息,比如消息大小(以字节为单位),Timestamp 以及消息类型。最后一个值是一个单独的字节,它定义了这个包是一个音频包,或者视频包,或者命令以及 "低层次" RTMP 包比如一个 RTMP Ping。
以下示例,一个 flash 客户端执行以下代码时:
- var stream:NetStream = new NetStream(connectionObject);
这将生成以下块:
ASCII | |
03 00 0b 68 00 00 19 00 00 00 00 63 72 65 61 74 65 53 74 72 65 61 6D 00 40 00 00 00 00 00 00 00 05 | c r e a t e S t r e a m . @ . . . . . . . . |
这一包以一个字节的基本报头开始,两个有效位(b00000011) 定义了块头类型 0,其余部分(b00000011) 定义了块的流 ID 是 3。头类型会有 4 种可能的值,他们的意义分别是:
- b00 = 12 字节头(完整的头)。
- b01 = 8 字节 - 像类型 b00。不包含消息 ID(后四个字节)。
- b10 = 4 字节 - 包含有基本报头和 timestamp (3 个字节)。
- b11 = 1 字节 - 只包含有基本头。
最后一个类型 (b11) 常用于聚合信息的情况,在上面的例子中,第二个消息会以 id 为 0xC3 (b11000011) 起始,意味着所有消息报头字段要以流 ID 为 3 的消息传递(恰恰是其上的消息)。六个最低的有效位组成流 ID,取值范围是 3 到 65599。一些值具有特殊意义,比如 1 代表一个扩展的 ID 格式,这时会有两个字节跟随。值为 2 用于底层的消息,例如 Ping 和设置客户端带宽。 接下来的 RTMP 报头的字节(包含以上数据包例子中的值)详解如下:
- 字节 #1 (0x03) = 块头类型。
- 字节 #2-4 (0x000b68) = Timestamp。
- 字节 #5-7 (0x000019) = 包长度 - 在这个例子中是 0x000019 = 25 字节。
- 字节 #8 (0x14) = 消息类型 ID - 0x14 (20) 定义了一个 AMF0 编码的命令消息。
- 字节 #9-12 (0x00000000) = 消息流 ID。这个以小端排序(很奇怪)。
消息类型 ID 字节定义了当前包是否包含音频/视频数据,一个远程对象或者一个命令。一些可能的值如下:
- 0x01 = 设置包大小消息。
- 0x04 = Ping 消息。
- 0x05 = 服务器带宽。
- 0x06 = 客户端带宽。
- 0x08 = 音频包。
- 0x09 = 视频包。
- 0x11 = 一个 AMF3 类型命令。
- 0x12 = 调用 (onMetaData 信息会这样发送)。
- 0x14 = 一个 AMF0 类型的命令。
紧跟报头,0x02 表示一个大小为 0x000C 的串,0x63 0x72 ... 0x6D ("createStream" 命令)。其后是 0X00 代表 ID 为 2.0 的事务。最后一个字节是 0x05 (null) 表示没有参数。 Invoke 消息结构 (0x14, 0x11) 以上所述的几种消息类型,比如 Ping 和设置客户端/服务端带宽,被认为底层 RTMP 协议消息,它们不使用 AMF 编码格式。换句话说,命令消息,无论是 AMF0 (Message Type of 0x14) 还是 AMF3 (0x11),使用这种格式:(有问题?。。。)
- (String) <Command Name>
- (Number) <Transaction Id>
- (Mixed) <Argument> ex. Null, String, Object: {key1:value1, key2:value2 ... }
事务 id 用于有回复的命令。这个值可以是上面例子中的一个字符串,也可以是一个或者多个对象,每个由一个键值对组成,键值对的键经常编码为字符串值,键值对的值可以是任意 AMF 数字类型,包括复杂的类型,比如数组。 Ping 消息结构 (0x04) Ping 消息不是 AMF 编码。它们以一个流 Id 起始,带有一个完整 (类型 0) 报头,并有一个类型为 0x04 的消息。报头后面紧随六个字节:
- #0-1 - Ping 类型。
- #2-3 - 第二个参数 (对于特定的 Ping 类型有意义)。
- #4-5 - 第三个参数 (一样)。
消息体的前两个字节定义了 Ping 的类型,有六种可能取到的值。
- 类型 0 - 清除流:当连接已建立而没有带有更多数据时发送。
- 类型 1 - 清除缓存。
- 类型 3 - 客户端缓存时间。第三个参数以毫秒为单位持有这个值。
- 类型 4 - 重置流。
- 类型 6 - 从服务器 Ping 客户端。第二个参数是当前时间。
- 类型 7 - 客户端回复的 Pong。第二个参数是客户端接收到 Ping 的时间。
Pong 是 Ping 回复的名字,它使用以上介绍的值。 ServerBw/ClientBw 消息结构 (0x05, 0x06) 这个关联到和客户端向上流、服务器向下流比特率相关的消息。消息体由 4 个字节组成,表示带宽的值,它可能有一个扩展字节来设置 Limit 类型。这个可以有三种可能的值:hard、soft 或者 dynamic (就是 soft 或者 hard 任一)。 设置块大小 (0x01) 这个值可以在报体的四个字节里接收到。存在默认值 128 字节,当你想要改变默认值时才会发生这个消息。 协议 握手 建立 TCP 连接后,RTMP 连接会在两端交互三个包的握手之后建立(这在官方文档里也被引用为块)。在官方规范中,这里描述为客户端发送包 C0-2,服务器端发送包 S0-2,不要和 RTMP 包混淆,RTMP 包只会在握手完成之后才能交互。这些包拥有自己的结构,C1 包含一个设置 "epoch" timestamp 的字段,但是因为这个可以设置为 0,正如第三方实现过的,这个包可以被简化。客户端通过发送一个带有代表现有协议版本号常数值 0x03 的 C0 包初始化连接。它可以直接跟随 C1 而无须等待接收到 S0,它带有 1536 字节,前四个字节代表 timestamp,其他的随意 (第三方实现中可以将其设置为 0)。C2 和 S2 分别是 S1 和 C1 的回声,接收到它们之后,握手才被认为结束。 连接 这一点上,客户端和服务器会通过交互 AMF 编码的消息进行协商连接。这些包含关系到建立连接所需要的变量的键值对。一个来自客户端的消息例子如下:
- (Invoke) “connect”
- (Transaction ID) 1.0
- (Object1) { app: “sample”, flashVer: “MAC 10,2,153,2”, swfUrl: null,
- tcUrl: “rtmpt://127.0.0.1/sample “, fpad: false,
- capabilities: 9947.75 , audioCodecs: 3191, videoCodecs: 252,
- videoFunction: 1 , pageUrl: null, objectEncoding: 3.0 }
FMS 和其他市县使用一个 "app" 的概念来概念化为音频/视频和其他内容定义一个容器,具体实现是,在服务根目录下的一个文件夹,其下含有将要被流化的媒体文件。第一个变量含有这一 app 的名 "sample",这个是由 Wowza 服务器用于测试所提供的名字。flashVer 字符串和 Action-script 的 getversion() 方法返回的值一样。audioCodec 和 videoCodec 使用 double 编码,它们的含义可以在原始规范里找到。videoFunction 的值是 true,在这里明显是 SUPPORT_VID_CLIENT_SEEK 变量。特别有趣的是 objectEncoding,它定义了通信的其余部分是否会使用扩展的 AMF3 格式。因为当前默认版本为 3,flash 客户端必须被以 Action-script 代码显式告知去使用 AMF0。服务器会用 ServerBW 回复,一个 ClientBW 和一个 SetPacketSize 消息序列,最终跟随一个 Invoke,用一个实例消息。
- (Invoke) “_result”
- (transaction ID) 1.0
- (Object1) { fmsVer: "FMS/3,5,5,2004", capabilities: 31.0, mode: 1.0 }
- (Object2) { level: “status”, code: “NetConnection.Connect.Success",
- description: “Connection succeeded”,
- data: (array) { version: “3,5,5,2004” },
- clientId: 1728724019, objectEncoding: 3.0 }
上面的一些值会被连续加载到一个通用的 Action-script Object,这个对象随后被传递给 NetConnection 事件监听者。clientId 将会为这个连接开启的会话建立一个编号。Object 编码必须匹配前面设定的值。 播放视频 要开始一个视频流,客户端发送一个由一个 ping 消息跟随的 "createStream" 调用,其后再跟随一个以文件名为参数的 "play" 调用。服务器随后以一系列的 "onStatus" 命令和带有视频数据的 RTMP 消息进行回复。
连接建立以后,媒体由封装为 FLV tag 内容的 RTMP 消息对类型 8 和 类型 9 的音频和视频交叠发送。
HTTP 隧道 (RTMPT) 这一节讲解 RTMP 的 HTTP 隧道式版本。它交互在端口 80,并在 HTTP POST 请求和回复内部传递 AMF 数据。连接的时序如下:
- POST /fcs/ident2 HTTP/1.1
- Content-Type: application/x-fcs\r\n
- HTTP/1.0 404 Not Found
- POST /open/1 HTTP/1.1
- Content-Type: application/x-fcs\r\n
- HTTP/1.1 200 OK
- Content-Type: application/x-fcs\r\n
- 1728724019
第一个请求有一个路径 /fcs/ident2,正确的返回是 404 无法查找错误。客户端然后发送了一个 /open/1 请求,服务器以附加一个代表 session 标识的随机数的 200 ok 返回。在以上例子中,返回体中返回 1728724019。
- POST /idle/1728724019/0 HTTP/1.1
- HTTP/1.1 200 OK
- 0x01
从此开始,/idle/<session id>/<sequence #> 会轮询请求,session id 是由服务器生成并返回,sequence 是一个为以 1 开始以后每次请求递增的数字。正确的回复是一个报体中带有指示内部时间的整数,200 OK。AMF 数据通过 /send/<session id>/<sequence #> 发送。 软件实现 客户端软件 最广泛采用的 RTMP 客户端软件是 Adobe Flash Player,它能够支持来自 RTMP 服务器的音视频流的回放(当它被安装为一个 web 浏览器的插件时)。 只能部分支持 RTMP 的客户端软件宝库开源的 media player XBMC,它提供了播放 RTMP (不包括 RTMPE) 流的初步支持。 开源的命令行工具 rtmpdump 用于回放或者将整个 RTMP 流 (包括 Adobe 用于加密的 RTMPE) 保存到磁盘。RTMPdump 可以运行在 Linux、Android、Solaris、MacOSX 以及大部分其他的 Unix 派生操作系统,当然也可以运行在微软 Windows。最初支持所有 32 位版本的 Windows 系统,包括 Windows 98,从版本 2.2 起,这款软件只能泡在 Windows XP 或者更高版本的 Windows 系统之上(尽管早期版本保持功能齐全)。 RTMPdump 的一个分叉,没有包含 Adobe 声称违反了美国 DMCA 的 RTMPdump 代码,以 FLVstreamer 发布了。它的开发是 2008 年 Adobe 抵制 RTMPdump 的一个直接反应。FLVstreamer 可以将来自任意一台 RTMP 服务器的音频流或者视频流保存到磁盘,只要流没有开启 RTMPE。FLVstreamer 运行于 Windows XP 或者更高版本的 Windows 系统之上,但不支持早期版本的 Windows。 2009 年十月,在美国以外的国家,MPlayer 网站 重新启动了 RTMPdump 的研发。现有版本大大改进了功能,并且使用了 C 语言重写,大大利用了 C 的优势。尤其是,主要功能被内置到一个库 (librtmp) 中,其他程序可以很容易使用这些功能。RTMPdump 的开发者们也为其他一些开源项目 (诸如 MPlayer、FFmpeg、XBMC、cURL、VLC) 提供了 librtmp 的支持。这些项目对 librtmp 的使用,拥有了完全 RTMP 的支持。 开源的 Gnash,一个在 Linux 平台上对于 Macromedia Flash Player 的替代,拟就为 Linux 支持 RTMP streaming。 服务器端软件 一些全面执行 RTMP 的服务器有:
- Adobe 。
- Adobe 生命周期数据服务。
- 亚马逊 S3 和亚马逊 Cloudfront 可以使用 RTMP 流。
- haXeVideo 是一个完全由 haXe 语言开发的多流 FLV 流媒体服务器。
- RealNetworks 的 可以支持 RTMP、RTMPT 和 RTMPS 流的直播和点播。
- 是一个 Java 开源项目,为 Adobe Flash Player 和其他客户端技术提供了一个强大的视频流和多用户解决方案。
- Erlyvideo 具有广泛的功能:不仅仅是文件流化,而且可以使用 RTMP 对 MPEG-TS 或者 Shoutcast 为 flash 客户端重新流化。
- 支持实时和缓存 RTMP 流的直播。
- 。
- (交流版和云版,为 .NET 和 Java 企业版提供了 RTMP/RTMPT/RTMPS 消息和媒体流化支持)。
- 流媒体 mod_rtmp 可用,并允许和其他 VoIP 协议 (SIP, H.323) 互连。
- Nginx with
探索和研发
- 探索者们对 RTMFP 协议进行逆向工程。现在还是个半成品。
- - 一个意图创建开源版本的 RTMPE 和 RTMFP 的项目。
- 为 Delphi/C++Builder 支持 RTMP 的企业版多层次开发工具。
另请参阅
- Info about RTMPS and RTMPE
- (RTMFP),基于 UDP
- (VoD)
参考资料
外部链接
原文链接:。
RTMP协议就像一个用来装数据包的容器,这些数据可以是AMF格式的数据,也可以是FLV中的视/音频数据。一个单一的连接可以通过不同的通道传输多路网络流。这些通道中的包都是按照固定大小的包传输的。
图1 RTMP交互图
http://blog.csdn.net/xiaguamanshu/article/details/5457290
用途 | 大小(Byte) | 含义 |
Head_Type | 1 | 包头 |
TiMMER | 3 | 时间戳 |
AMFSize | 3 | 数据大小 |
AMFType | 1 | 数据类型 |
StreamID | 4 | 流ID |
Bits | Header Length |
00 | 12 bytes |
01 | 8 bytes |
10 | 4 bytes |
11 | 1 byte |
ChannelID | Use |
02 | Ping 和ByteRead通道 |
03 | Invoke通道 我们的connect() publish()和自字写的NetConnection.Call() 数据都是在这个通道的 |
04 | Audio和Vidio通道 |
05 06 07 | 服务器保留,经观察FMS2用这些Channel也用来发送音频或视频数据 |
0×01 | Chunk Size | changes the chunk size for packets |
0×02 | Unknown | |
0×03 | Bytes Read | send every x bytes read by both sides |
0×04 | Ping | ping is a stream control message, has subtypes |
0×05 | Server BW | the servers downstream bw |
0×06 | Client BW | the clients upstream bw |
0×07 | Unknown | |
0×08 | Audio Data | packet containing audio |
0×09 | Video Data | packet containing video data |
0x0A-0x0E | Unknown | |
0x0F | FLEX_STREAM_SEND | TYPE_FLEX_STREAM_SEND |
0x10 | FLEX_SHARED_OBJECT | TYPE_FLEX_SHARED_OBJECT |
0x11 | FLEX_MESSAGE | TYPE_FLEX_MESSAGE |
0×12 | Notify | an invoke which does not expect a reply |
0×13 | Shared Object | has subtypes |
0×14 | Invoke | like remoting call, used for stream actions too. |
0×16 | StreamData | 这是FMS3出来后新增的数据类型,这种类型数据中包含AudioData和VideoData |
类型说明(ObjType) | 数据 | dataSize |
CORE_String | 0x02 | 2字节 (2字节的数据纪录了String的实际长度) |
CORE_Object | 0x03 | 0字节(开始嵌套0x00000009表示嵌套结束) |
NULL | 0x05 | 0字节 空字节无意义 |
CORE_NUMBER | 0x00 | 8字节 |
CORE_Map | 0x08 | 4字节(开始嵌套) |
CORE_BOOLEAN | 0x01 | 1字节 |