RTMP协议

概要

  • 在RTMP协议中信令和媒体数据都称之为Message,在网络中传输这些Message,为了区分它们肯定是要加一个Message head的,所以RTMP协议也有一个Message head,还有一个问题因为RTMP协议是基于TCP的,由于TCP的包长度是有限制的(一般来说不超过1500个字节),而RTMP的Message长度是有可能很大的,像一个视频帧的包可能会有几十甚至几千K,这个问题就必然有一个分片的问题,在RTMP协议中对应的说法就是chunk,每一个Message + head都是由一个和多个chunk组成的。到这里对RTMP协议的概要理解就算完了。
  • RTMP在收发数据的时候并不是以Message为单位的,而是把Message拆分成Chunk发送
  • 每个Chunk中带有MessageID代表属于哪个Message,接受端也会按照这个id来将chunk组装成Message
  • Chunk的默认大小是128字节,在传输过程中,通过一个叫做Set Chunk Size的控制信息可以设置Chunk数据量的最大值,在发送端和接受端会各自维护一个Chunk Size,可以分别设置这个值来改变自己这一方发送的Chunk的最大大小。
  • csid, chunk stream ID

head

  • RTMP的head在协议中的表现形式是chunk head,前面已经说到一个Message + head可以分成一个和多个chunk,为了区分这些chunk,肯定是需要一个chunk head的,具体的实现就把Message head的信息和chunk head的信息合并在一起以chunk head的形式表现。
  • 一个完整的chunk的组成如下图所示
Basic Header Chunk Msg Header Extend TimeStamp Chunk Data
  • 说明

    • Chunk basic header:该字段包含chunk的stream ID和type。chunk的Type决定了消息头的编码方式。该字段的长度完全依赖于stream ID,该字段是一个可变长的字段.chunk basic head的长度为1~3个字节,具体长度主要是依赖chunk stream ID的长度,所谓chunk stream ID是flash server用来管理连接的客户端的信令交互的标识,在red5的文档中称之为channel ID,协议最大支持65597个streamID 从3~65599。ID 0,1,2为协议保留,0代表ID是64~319(第二个byte + 64);1代表chunk stream ID为64~65599((第三个byte)* 256 + 第二个byte + 64)(小端表示);2代表该消息为低层的协议(在RTMP协议中控制信令的chunk stream ID都是2)。3~63的chunk stream ID就是该byte的值。没有附加的字段来标识chunk stream streamID。在这里要指出的是虽然RTMP的chunk stream ID理论是可以达到65599,但是目前使用的chunk stream ID很少,2~7都是约定的,8是用来传输publish play等命令,其他的chunk stream ID目前好像没有使用,至少我不知道用来干嘛的。
      所以目前chunk basic head的长度一般为1个字节。这一个字节由两部分组成

      fmt (2bit) cs id

      fmt是chunk type,fmt占两个bit用来标识紧跟其后的chunk Msg Header的长度,cs id占六个bit。两位的fmt取值为 0~3,分别代表的意义如下:
      case 0:chunk Msg Header长度为11;
      case 1:chunk Msg Header长度为7;
      case 2:chunk Msg Header长度为3;
      case 3:chunk Msg Header长度为0;
      所以 只有一个字节的chunk basic header取值为 chunk basic header = (fmt << 6) | (cs id).

    • Chunk Msg Header:0, 3 ,7,11,该字段包含了将要发送的消息的信息(或者是一部分,一个消息拆成多个chunk的情况下是一部分)该字段的长度由chunk basic header中的type决定。Chunk Msg Header的长度是可变的,Chunk Msg Header可变的原因是为了压缩传输的字节数,把一些相同类型的chunk的head去掉一些字节,换句话说就是四种类型的包头都可以通过一定的规则还原成11个字节,这个压缩和还原在RTMP协议中称之为复用/解复用。
      那我们以11个字节的完整包头来解释Chunk Msg Header,如图所示

    timestamp message length message type id message stream id
    • Timestamp:3bytes
      对于type 0的chunk,绝对时间戳在这里表示,如果时间戳值大于等于0xffffff(16777215),该值必须是0xffffff,且时间戳扩展字段必须发送,其他情况没有要求。

      • message length:3bytes
        Message的长度,注意这里的长度并不是跟随chunk head其后的chunk data(Payload)的长度,而是前文提到的一条信令或者一帧视频数据或音频数据的长度。前文提到过信令或者媒体数据都称之为Message,一条Message可以分为一条或者多条chunk。

      • message type id:1byte. Message的类型ID

      • message stream id:4bytes. message stream id的字节序是小端序,这个字段是为了解复用而设计的,RTMP文档上说的相当的模糊,message stream ID可以使任意值,不同的消息流复用成相同的chunk stream,基于它们的ID能够解复用。于chunk stream 是相关的,这个字段是一个不透明的值没有整明白什么意思,我的理解就是用来标识和服务器连接的flash端的序号。长度是7 bytes 的chunk head,该类型不包含stream ID,该chunk的streamID和前一个chunk的stream ID是相同的,变长的消息,例如视频流格式,在第一个新的chunk以后使用这种类型,注意其中时间戳部分是相对时间,为何上一个绝对时间之间的差值 如图所示:

        timestamp delta message length message type id
    • Extend Timestamp: 0 ,4 bytes,该字段发送的时候必须是正常的时间戳设置成0xffffff时,当正常时间戳不为0xffffff时,该字段不发送。当时间戳比0xffffff小该字段不发送,当时间戳比0xffffff大时该字段必须发送,且正常时间戳设置成0xffffff。

    • Chunk Data : 实际数据(Payload),可以是信令,也可以是媒体数据。

图示

image

image

image

image

参考

RTMP payload(body)解析

  • 因为 RTMP 是 Adobe 开发的。理所当然,内部的使用格式肯定是 FLV 格式。
  • 如果是传整个 FLV 文件,根本没必要用到这个,而且,RTMP 最常用在直播当中。直播中的视频都是分段播放的。综上所述,RTMP 是根据自己的自定义协议来分段传输 FLV Tag 的。那具体的协议是啥呢?
    这个在 RTMP 官方文档中其实也没有给出。它只是告诉我们 Video Msg 的 type ID 是 9 而已。

FLV

FLV header

  • FLV是一个二进制文件,简单来说,其是由一个文件头(FLV header)和很多tag组成(FLV body)。tag又可以分成三类:audio,video,script,分别代表音频流,视频流,脚本流,而每个tag又由tag header和tag data组成。
  • 文件头由9bytes组成
  • 文件头
字段 解释 大小
文件头 总是“FLV” 3bytes
版本 一般是0x01 1bytes
流信息 倒数第一bit是1表示有视频(0x01),倒数第三bit是1表示有音频(0x4),有视频又有音频就是0x01 1bytes
header长度 最后4bytes表示FLV 头的长度,3+1+1+4 = 9。 4bytes
  • 前3个bytes是文件类型,总是“FLV”,也就是(0x46 0x4C 0x56)。第4btye是版本号,目前一般是0x01。第5byte是流的信息,倒数第一bit是1表示有视频(0x01),倒数第三bit是1表示有音频(0x4),有视频又有音频就是0x01 | 0x04(0x05),其他都应该是0。最后4bytes表示FLV 头的长度,3+1+1+4 = 9。

FLV body

  • 基本结构
tag header data
  • tag header 结构
tag type(1) length(3) timestamp(3) extend timestamp(1) stream id(3)
  • FLV header后面就是FLV body,FLV body由若干个tag组成。
  • 每一个tag第一部分是tag header,tag header长度为11bytes,但是每个tag header前面有4bytes记录着上一个tag的长度,此待会儿再说。
  • tag header的第1个byte为记录着tag的类型,音频(0x8),视频(0x9),脚本(0x12);
  • 第2到4bytes是数据区的长度,也就是tag data的长度;
  • 再后面3个bytes是时间戳,单位是毫秒,类型为0x12则时间戳为0,时间戳控制着文件播放的速度,可以根据音视频的帧率类设置;
  • 时间戳后面一个byte是扩展时间戳,时间戳不够长的时候用;
  • 最后3bytes是streamID,但是总为0,再后面就是数据区了(tagdata),也即是h264的裸流,tag header 长度为1+3+3+1+3=11。

tag data

音频数据
  • tag data如果是音频数据,第一个byte记录audio信息
  • 概览
FLV header previous tag size0 tag1 previous tag size1 tag2 previous tag size2 tagN previous tag sizeN
  • 基本结构
audio format(4) sample rate(2) 采样长度(1) 类型(1) 数据
  • 前4bits表示音频格式
含义
0 未压缩
1 ADPCM
2 MP3
4 Nellymoser 16-kHz mono
5 Nellymoser 8-kHz mono
10 AAC
  • 下面两个bits表示samplerate
含义
0 5.5KHz
1 11kHz
2 22kHz
3 44kHz
  • 下面1bit表示采样长度
含义
0 8Bit
1 16Bit
  • 下面1bit表示类型
含义
0 sndMomo
1 sndStereo
视频数据
  • 基本结构
type(4) codec id(4) if( codec_id == 7) AVCPacketType 数据
  • type
含义
1 keyframe
2 inner frame
3 disposable inner frame
4 generated keyframe
  • codec id
含义
2 seronson h.263
3 screen video
4 On2 VP6
5 On2 VP6 with alpha channel
6 Screen video version 2
7 AVC (h.264)

猜你喜欢

转载自blog.csdn.net/qq_39977813/article/details/89177138