1 RTMP 介绍

RTMP(Real Time Messaging Control) 是Adobe 公司flash 播放器和服务器之间的音视,视频以及数据传输的流媒体协议。该协议是个协议族,包括多种协议,包括最基本的RTMP 以及RTMPE,RTMPT,RTMPS 等多种变种。关于rtmp英文spec下载见:https://www.adobe.com/devnet/rtmp.html

RTMP:工作在TCP 上, 使用端口号为1935;

RTMPE:在RTMP 上增加了加密功能。

RTMPT: 工作在HTTP 上,可穿透防火墙。

RTMPS:在RTMPT上增加了TLS/SSL 安全功能。

2 抓取RTMP 包抓取

一 使用ffmpeg download rtmp 流,如下rtmp 流是湖南卫视的,将其下载并保存为flv 文件。

ffmpeg.exe -i rtmp://58.200.131.2:1935/livetv/hunantv -c copy output1.flv

二 使用wireshark 抓包,选择要抓取的网口,然后点击开始,开始抓包,等抓包结束后,将抓取的网络包保存到一个文件中。

android ffmpeg播放rtsp ffmpeg rtsp rtmp_字段

 

3 RTMP 包分析

在过滤栏输入“rtmpt”过滤出RTMP 包, 下图为抓取的RTMP 包,下面我们将根据抓取的网络包来分析RTMP 协议。

android ffmpeg播放rtsp ffmpeg rtsp rtmp_字段_02

3.1 握手包

如上图所示, 其中C0/C1/C2, S0/S1/S2 为握手包,前者为client 端向服务器发出的,后者为服务器返回给客户端的。

1) C0/S0

C0/S0 长度为一个字节,表示当前RTMP 协议的版本号。

android ffmpeg播放rtsp ffmpeg rtsp rtmp_客户端_03

2) C1/S1 

C1/S1 长度为1536 字节,包含以下字段。

android ffmpeg播放rtsp ffmpeg rtsp rtmp_字段_04

time: 毫秒值的时间戳,这个值可以是 0,或者一些任意值。用于本终端发送的所有后续块的时间起点。 zero: 必须全 0 Random data: 本字段可以包含任意数据。由于握手的双方需要区分另一端,此字段填充的数据必须足够随机(以防止与其他握手端混淆)。不过没必要为此使用加密数据或动态数据。 服务端必须接收到 C0 消息,才能发送 S0 和 S1 消息 。

3)C2 / S2

android ffmpeg播放rtsp ffmpeg rtsp rtmp_字段_05

time1: 这个字段必须是对端发送过来的时间戳(C1 或 S1 内的)。 time2: 这个字段值为本机接收到对端发送过来的握手包的时刻。 random echo: 这个字段必须是对端发送过来的随机数据。握手的双方可以使用 time1 和 time2 字段来估算网络连接的带宽和/或延迟,但是不一定有用。 

到此握手包分析结束,可能有点迷糊了, 那么问:在C2/S2 包中的time2 - time1 值的意义是什么? 是网络延时。

3.2 RTMP Header 分析

RTMP Header 组成格式 如下图所, 通过下图我们可知RTMP Header 由:Basic header, Message Header, Exended Timestamp , Chunk Data 组成。

android ffmpeg播放rtsp ffmpeg rtsp rtmp_客户端_06

1)Basic Header

Basic Header (基本头,1 到 3 个字节):这个字段对块流 ID 和块类型进行编码。长度完全取决于块流 ID,因为块流 ID 是一个可变长度的字段。0、1、2 被保留, 3 ~ 8 基本都是固定用途,所以 9 ~ 65599 才用于自定义 csid,但一般我们用不到。

 不同的CSID 代表这不同的块。如下如Chunk Stream ID:3 ,代表客户端发出的AMF0 命令。

android ffmpeg播放rtsp ffmpeg rtsp rtmp_客户端_07

0 表示 Basic Header 总共要占用 2 个字节

1 表示 Basic Header 总共要占用 3 个字节

2 代表该 chunk 是控制信息和一些命令信息

3 代表该 chunk 是客户端发出的 AMF0 命令以及服务端对该命令的应答

4 代表该 chunk 是客户端发出的音频数据,用于 publish

5 代表该 chunk 是服务端发出的 AMF0 命令和数据

6 代表该 chunk 是服务端发出的音频数据,用于 play;或客户端发出的视频数据,用于 publish

7 代表该 chunk 是服务端发出的视频数据,用于 play

8 代表该 chunk 是客户端发出的 AMF0 命令,专用来发送: getStreamLength, play, publish  。‘

3)Message Header 

Message Header:描述RTMPPacket 包, 如下图所示,Type ID 为0x05, 代表设置确认窗口大小Packet。

android ffmpeg播放rtsp ffmpeg rtsp rtmp_客户端_08


1 设置块大小

2 中断消息,丢弃旧数据

3 确认

4 用户控制消息

5 设置确认窗口大小

6 设置流带宽

7 音频数据

9 视频数据

15(0x0f). AMF3 数据

16(0x10) AMF3 共享对象事件

17(0x11) AMF3 命令

18(0x12) AMF0 数据

19(0x13) AMF0 共享对象事件

20(0x14) AMF0 命令,Invoke 方法调用 , 播放,暂停,seek 均是这个Type ID  packet。

22(0x16) 聚合消息, H.264, 类似 FLV 文件存储格式,每个音视频包作为一个 Tag, 许多的 Tag 组成了这个 AMFType=0x16 的数据类型

参考文章:https://www.meiwen.com.cn/subject/otsjjqtx.html#r6  

4 总结

   本文简单介绍下RTMP,讲解如何通过WireShark 抓取网络包,并过滤出所需的网络包。最后分析关于RTMP 握手协议,最后分析关于RTMP Header,了解CSID 和Type ID 意义。