rtmp官方标准规范详细解析

标准规范学习:

rtmp消息结构,包括几个部分:
时戳:4  byte,单位毫秒。超过最大值后会翻转。
长度:消息负载的长度。
类型ID:Type Id 一部分ID范围用于rtmp的控制信令。还有一部分能够供上层使用,rtmp只是透传。这样能够方便的在rtmp上进行扩展。
消息流ID:Message Stream ID,用于区分不一样流的消息。
 
两个ID的区别:
Message stream:传输消息的逻辑通道。
Message stream ID:每一个消息都有一个流id,用于指明属于哪一个流。
 
Chunk:是更底层的一个概念。Message有可能过大,须要分割成一个个碎片,chunk就是一个消息的部分碎片。
Chunk stream:传输chunk的逻辑通道。
Chunk stream ID:用于标示chunk属于哪一个逻辑通道。
message stream和chunk stream应该属于不一样的层次,message属于应用层次消息,chunk属于更底层rtmp协议层次。
一个chunk stream 上可以跑多个message stream。message stream id在一个chunk stream下要不相等。
 
消息会切分红一个个小的块进行传输。
 
rtmp的时戳单位是毫秒。
链接握手流程图:
握手过程:服务器和客户端各自发送三个包:c0,c1,c2,s0,s1,s2,服务器必须在收到c0后才发送s0和s1,也能够等到c1才发送;服务端必须收到c1才可以发送s2,客户端必须收到s2才可以发送c2
 
c0和s0就是一个字节:表示协议版本号。如今是03。
01 234567
+-+-+-+-+-+-+-+-+
|    version    |
+-+-+-+-+-+-+-+-+
  C0 and S0 bits
 
c1和s1长度1536,
抓包发现,zero字段不必定为0。
 
c2和s2的长度也是1536
经过vlc和nginx rtmp抓的包发现和规范不对应。安装规范,time和time2应该是为了计算带宽和延迟。
 
 
交互过程:
通常客户端一块儿发生c0和c1,而后服务器直接发送s0,1,2。客户端收到后发送c2,握手完成。三次交互就能够了。
 
块流:

一个链接能够穿输多个块流。每一个块流有不一样的id来区分。
块传输运行将大的消息包切割为小的消息包。防止大的数据好比视频阻塞链接,致使音频和信令也没法传递。
小的消息也能够成本更加低的传输,包头会压缩.
 
块流大小能够配置。有一个消息:set chunk size能够协商大小。大的块能够下降cpu 负载,可是可能会阻塞重要消息;小的块不利于传输,特别是在低带宽的状况下。
 
块容许 层协议将大的消息 解 更小的消息,例如,防 体积大的但优先级小的消 息 (好比视频) 阻碍体积较小但优先级高的消息 (好比音频或者控制命 ) ——传送过程,音频和控制的优先级较高。
 
块的大小是  配置的 它  使用一个设置块大小的控制消息 行设置 (参考 5.4.1) 更大的块大小  降  CPU 开销,但在  宽 接时因 它的大量的写入也会延   他内容的传递 更小的块不利于高比特率的流化 所 块的大小设置 决于 体状况。 ——这是使用tcp必需要考虑的问题。块过大会影响音频和控制的发送。太小会影响效率和比特率。
 
块类型:
 
块基本头:
 

 
page12image7536
 
第一个字节都是这样。其中fmt用来指示Message Header。
cs id:
cs id是chunk stream id的缩写。范围是3——65599。可变字节,后面能够跟一个字节,也能够跟两个字节。跟几个字节是有第一个字节的后面6位的值决定的。这一点中文翻译写的不完整。
若是最后6位值为0,则表示后面只有一个字节。id范围是64——319,其实就是0——255,最大和最小加64。
page13image384
若是最后6位值为1,则表示后面只有两个字节。 id范围是64 - 65599,其实就是0——65535, 最大和最小加64。j
计算方法比较特殊:(第三 个 节) * 256 + 第二 个 节 + 64
page13image7080
 
块流id应该是区分每个流,好比,一个视频通话,包括视频和音频两个流。这里的意思应该是一个链接能够传递多个流,经过块流id进行区分。
 
块消息头

块消息头格式由块基本头的fmt字段决定。共四种。
 
fmt:
四种类型:0 1 2 3
包头必须尽量的压缩。
 
type 0:用在流开始,或者时戳重置的时候。message header消息头共11byte。
三字节时戳:表示范围为0——16777215(0xffffff),若是大于等于16777215,则表示还有一个字节的扩展时戳。chunk header的第三部分就是extend timestamp。这一本部分是否存在由三个字节的值决定。 注意,这个是绝对时戳,然后面的几种类型trunk都是时戳的增量;区分消息截止是根据消息的长度来进行的。那么输入处理主动丢弃包的状况?
 
 
 
type 1:message header有7byte,比type 0少了4个字节的message stream id,使用上一个块的id。大小可变的消息(好比视频的每一帧数据)每每会在第一帧(第一帧的第一个chunk须要用type0)后面的帧的第一个chunk中使用type1。为何?由于可变数据,必须有长度信息记录。
 
type2:只有三个字节。没有message stream id和message 长度。所有使用同一个chunk stream的上一个chunk的。适用于长度不变的步伐传输。
 
type 3:0个字节的message header。时戳,长度,消息流id所有使用同一个chunk stream的上一个chunk。当一个消息切分后划分到多个chunk的时候,除了带个chunk,全部的其余chunk应该使用type3。——如何判断包结束?根据消息的长度,第一个chunk中的长度应该是一个消息完成的长度。
 
四种格式的使用:
第一个消息的第一个chunk 使用type0,携带所有的信息;后面的chunk使用type3;
第二个消息,若是是视频消息,长度可变,则第一个chunk使用type1,值丢弃message stream id便可。第二个消息的其余chunk使用type3。
 
若是是音频,且长度相同,则第一个消息用type0+type3,第二个消息用type2+type3。
若是音频消息,长度,消息间时戳增量(delta)都相同,则第一个消息能够用type0+type3,后面的全部消息所有用type3便可。这样的话也要求第一个消息的时戳必须和消息间的时戳增量相同。
 
 
注意:除type0外,其余的所有是时戳的增量。而不是时戳绝对值。
从上面来看,音频和视频的chunk id应该是不同的。不然没法区分。由于有些块是没有message stream id,只有chunk stream id的。
 
公共字段定义:
一、timestamp delta:表示的是上一个chunk 和当前chunk的时戳差。不是消息的时间差。若是大于等于16777215,则表示还有一个字节的扩展时戳。chunk header的第三部分就是extend timestamp。
二、消息长度:消息的长度。他和chunk的payload的大小是不一样的。chunk size length是全部chunk的大小再加最后一个大小。——消息长度是消息实际的大小。。
三、message type id:标示消息类型,好比音频,视频,控制等。
四、message stream id:以小端序存储。
Extended Timestamp:当时戳大于
 
play2:能够实现比特率的切换。
 
message length,chunk size,tcp分包和消息的切割

终于弄明白其中的原理了。原本这几个概念和方法在规范中描述不是很清楚,结合抓包终于弄清楚 了。
message length:及时消息自己的大小。这个消息要在chunk中进行传输。
chunk size:chunk的大小。chunk的大小默认是128。能够经过消息设置chunk size 的最大值。每一个chunk的大小最大不可以超过max chunk size。
明白上面两点后进行分析:
一、若是message length小于等于max chunk size,则一个chunk中就包含着一个message。
二、若是message length大于max chunk size,则须要将这个message切分为多个chunk。前面几个chunk size必须是max 
size,最后一个就是剩余的大小。
 
tcp分包过程:
一、收到chunk,明确chunk stream id,对一个chunk stream的数据进行处理。
二、判断fmt类型,肯定消息长度。
三、若是长度小于等于max chunk size,则这个chunk body的大小就是message length。
四、处理完这个chunk,跳过chunk header 和chunk body,就是下一个chunk。
五、若是长度大于max chunk size,则chunk body的大小就是max chunk size。处理这一部分数据,而后跳过max chunk size找到下一个chunk的头。有消息长度减去max chunk size计算剩余的数据长度,判断剩余长度是否大于max chunk size,若是大于,则代表这个chunk 大小仍是max chunk size。以此类推,直到最后一个长度小于等于max chunk size,那么这个长度就是这个chunk的实际长度,而且是这个消息的最后一个消息切片。而后把全部的有效切片拼接起来,就是完整的消息。后面收到的将是另一个消息。
 
协议控制消息:

RTMP使用1,2,3,4,5,6的message type id做为控制消息。控制协议的message stream id必须是0, chunk stream id必须是2(2的做用。0,1用来表示字节个数,2是信令,3-6xxxx是实际的。)。控制信令一收到就生效——就是没有协商过程。。。——时戳能够忽略。
 
set chunk size (1):设置chunk的最大size

message type id 为1。共四个字节:
第一位必须为0。
 
默认值是128,服务端和客户端均可以设置chunk size。注意,一个交互中chunk size是相互独立的,也就是,客户端能够设置他发送过去的chunk size,服务端也能够设置他发送过去的chunk size。两个是没有影响的。
chunk size最小建议128,必须大于等于1。
chunk size的范围是1到0x7fffffff(2147483647),可是由于message header中message length只有三个字节,因此chunk size的最大值是16777215  若是大于此,就去他。
 
Abort Message (2)

message type id为2,四个字节,携带的内容是chunk stream id。用于通知对端,若是这个chunk stream还有消息正在等待接收未到达的消息内容,则中止,并丢弃原先接受的内容。能够用在带宽有限是优先发送音频和信令,丢弃视频。
 
Acknowledgement (3) Window Acknowledgement Size (5)

Window Acknowledgement Size用于设置窗口确认大小,Acknowledgement是窗口确认消息。
会话开始时,双方都要先对端发送Window Acknowledgement Size,用于指明指望得到确认的大小。当一端收到内容大小超过Window Acknowledgement Size,就要像对方发送Acknowledgement。
一、会话开始计算收到byte个数的时间点是收到Window Acknowledgement Size消息开始。
二、byte size不包括tcp包头,应该是chunk的大小,即从tcp 的recv函数中得到的内容大小。
三、双方都要向对方发送Window Acknowledgement Size和Acknowledgement。
四、发送端发送完Window Acknowledgement Size消息后,没有收到Acknowledgement是再也不发送进一步的消息的——这样会容易引发错误,致使再也发送不出消息了。
 
 
Set Peer Bandwidth (6)

 
设置对端输出带宽。对端是经过设置Window Acknowledgement Size来实现流量控制的。超过Window Acknowledgement Size后未确认发送端将再也不发送消息。因此对端收到set peer bandwidth后,若是以前发送的Window Acknowledgement Size和这里写的的Window Acknowledgement Size不同,通常会发送一个Window Acknowledgement Size。
 
 
message format

 
上面的协议控制消息的type id是1,2,3,5,6(这些是chunk stream的控制),没有4。4是另一个类型:
User Control Messages (4):用户控制协议,是RTMP stream的控制协议。 一样,chunk stream id要设置为2,message stream id要设置为0。
 
消息体格式:两个字节的event type,后面跟可变长度的event data,
 
RTMP Command Messages

客户端和服务器之间能够发送的消息包括:音频消息,视频消息,数据消息,命令消息。命令消息采用AMF编码。
 
command message type 20,17表示是命令消息。20表示使用AMF0编码,17表示使用AMF3编码。
命令消息包括connect, createStream, publish, play, pause ,响应消息使用onstatus,result。
 
Data Message (18, 15):数据消息,用于传输Metadata或用户数据。18表示AMF0,15是AMF3。
 
Shared Object Message (19, 16):19表示AMF0,16是AMF3。
 
Audio Message (8):音频消息
Video Message (9):视频消息
 
Aggregate Message (22):一个消息中包含多个消息。
 
Types of Commands( 20,17)

netConnetion 命令:
connect :请求链接到服务器的应用实例。
 
call:请求一个远程调用。
 
creatStream:建立一个逻辑通道,用于客户端来发送音频,视频,描述数据。netConnection是默认通道,message stream id是0,creatStream使用0做为message stream id。
 
NetStream Commands:
多个Netstream能够共用一个netconnection。可是stream的id是在何时肯定的???—— 疑问
 
play2:切换到不一样的比特率的流上,而不用更改播放时间。这是一个有用的功能。这个消息是在paly以后再发送。
 
deleteStream:删除流。
 
receiveAudio:是否接受音频。若是为false,服务器不用回复。若是为true,服务器回复两个状态:
NetStream.Seek.Notify and   NetStream.Play.Start
 
receiveVideo:一样。
 
publish:发布一个流到server。须要onStatus响应。
 
seek:偏移。毫秒为单位。
 
pause:暂停。
 
example:
首先,connect是链接的服务器端的应用(nginx rtmp有配置多个应用。)
 
视频裸数据是如何打包进rtmp包的?

ffmpeg在flv和h264文件将的转换是有问题的。
 
视频性格的数据包格式和flv的格式很是的像,基本上就是flv格式的变种。参考flv文件格式官方协议详解。
视频相关包包括:onMetaData,AVCDecoderConfigurationRecord,h264数据。和flv文件中的区别是flv文件用tag头,rtmp中相关信息是放在rtmp头中。至于内部内容是同样的。
 
 
AMF0编码格式

  1. *AMF数据类型: 
  2.  *Type      Byte code 
  3.  *Number    0x00 
  4.  *Boolean   0x01 
  5.  *String    0x02 
  6.  *Object    0x03 
  7.  *MovieClip 0x04 
  8.  *Null      0x05 
  9.  *Undefined 0x06 
  10.  *Reference 0x07 
  11.  *MixedArray    0x08 
  12.  *EndOfObject   0x09 
  13.  *Array         0x0a 
  14.  *Date          0x0b 
  15.  *LongString    0x0c 
  16.  *Unsupported   0x0d 
  17.  *Recordset     0x0e 
  18.  *XML           0x0f 
  19.  *TypedObject (Class instance)  0x10 
  20.  *AMF3 data 0×11 
 
amf编码:对个数据的合集,数据的边界经过不一样的类型,以及不一样类型的长度来区分。
第一个字节是数据类型,而后根据数据类型肯定数据的长度。其中,string是可变长度,两个字节长度值。
若是是object,则object内部是个字典,key是字符串,value是数据,这里还要对数据根据类型对数据解析,同上。
 
 

我 的微信公众号nginx

相关文章
相关标签/搜索