RTMP协议分块机制学习!

分块:

握手之后,连接复用一个或多个块流。每个块流携带来自一个消息流的一种类型的消息。每个创建的块都有一个与之关联的唯一ID,称为块流ID。这些块通过网络传输。在传输过程中,每个块必须在发送下一个块之前完整发送。在接收端,根据块流ID将块组装成消息。

分块允许在更高层次的协议中将大消息分解成较小的消息,例如,为了防止大型低优先级的消息阻塞较小的高优先级消息。

分块还可以让小消息以较小的开销发送,因为块头包含了信息的压缩表示,这些信息如果通过消息本身包含,则需要更多的开销。

块大小是可配置的。如第7.1节所述,可以使用控制消息(设置块大小)来设置块大小。最大块大小可以是65536字节,最小为128字节。较大的值可以减少CPU使用率,但也会承诺更大的写入,这可能会延迟低带宽连接上的其他内容。较小的块不适合高比特率流媒体。每个方向的块大小是独立维护的

块格式:

每个块由一个头部和数据组成。头部本身分为三个部分:

  • 块基础头部 ( basic header) : 1到3个字节;这个字段编码块流ID和块类型。块类型决定了编码消息头部的格式。长度完全取决于块流ID,这是一个变长字段。

  • 块消息头部(Chunk Msg Header ):0、3、7或11字节;这个字段编码了关于正在发送(无论是完整还是部分)的消息的信息。长度可以根据块头部中指定的块类型来确定。

  • 扩展时间戳: 0或者4个字节;当普通时间戳设置为0xffffff时,必须发送此字段,如果普通时间戳设置为其他任何值,则不应发送此字段。因此,对于小于0xffffff的值,应使用普通时间戳字段,在这种情况下不应存在扩展时间戳。对于大于或等于0xffffff的值,不应使用普通时间戳字段,并且必须将其设置为0xffffff,并且必须发送扩展时间戳。

块基础头部:

块基本头编码了块流ID和块类型(由下面的图中的fmt字段表示)。块类型决定了编码消息头的格式。块基本头字段可能是1、2或3个字节,这取决于块流ID。

实现时应该使用能够容纳ID的最小表示形式。

该协议支持最多65597个流,流ID为3到65599。ID 0、1和2是保留的。值0表示64到319范围内的ID(第二字节+64)。值1表示64到65599范围内的ID(第三个字节×256 + 第二个字节 + 64)。值2表示其低级协议消息。没有额外的字节用于表示流ID。3到63范围内的值表示完整的流ID。没有使用额外的字节来表示它。

块基本头中的最低5位(即位0到位5)表示块流ID。 块流ID 2到63可以编码在该字段的1字节版本中。

可以在这个字段的2字节版本中编码64到319的块流ID。ID的计算方法是(第二个字节 + 64)。

块流ID 64 到 65599 可以在该字段的3字节版本中编码。ID的计算方式是((第三个字节)×256 + 第二个字节 + 64):

  • cs  id : 6bit ;这个字段包含块流ID,用于2到63之间的值。值0和1用来指示这个字段的2字节或3字节版本。

  • fmt : 2bit ; 这个字段识别了‘块消息头’使用的四种格式之一。每种块类型的‘块消息头’将在下一部分进行解释。

  • cs id - 64 :  8 bit 或者 16bit ;这个字段包含了块流ID减去64的结果。例如,ID为365将由cs id中的1表示,以及这里的16位301。值在64到319之间的块流ID可以由这个字段的2字节版本和3字节版本来表示。

块信息头 :

块消息头有四种不同的格式,由块基础头中的"fmt"字段选择。 实现时应该为每个块消息头使用尽可能紧凑的表示方式。

type 0 :

类型0的块长度为11字节。这种类型必须在块流开始时使用,以及每当流时间戳倒退时(例如,由于向后查找):

时间戳:3字节; 对于类型0的块,消息的绝对时间戳在这里发送。如果时间戳大于或等于16777215(十六进制0x00ffffff),这个值必须是16777215,并且必须存在“扩展时间戳头”。否则,这个值应该是整个时间戳。

type 1 :

类型1的块长度为7字节。消息流ID不包括在内;这个块应该使用与前一个块相同的流ID。具有可变大小消息的流(例如,许多视频格式)应该在第一个块之后,对每个新消息的第一个块使用这种格式:

type 2:

类型2的块长度为3字节。既不包括流ID也不包括消息长度;这个块具有与前一个块相同的流ID和消息长度。具有固定大小消息的流(例如,一些音频和数据格式)应该在第一个消息之后,对每个消息的第一个块使用这种格式。

type 3:

类型3的块没有头信息。流ID、消息长度和时间戳增量都不存在;这种类型的块从前面的块中获取值。当一个单一消息被分割成多个块时,除了第一个块之外,所有消息的块都应该使用这种类型。参考第6.2.2节中的示例2。由完全相同大小、流ID和时间间隔的消息组成的流,应该在类型2的块之后的所有块中使用这种类型。参考第6.2.1节中的示例1。如果第一条消息和第二条消息之间的增量与第一条消息的时间戳相同,那么类型3的块将紧随类型0的块,因为不需要类型2的块来注册增量。如果类型3的块跟随类型0的块,那么这个类型3的块的时间戳增量与类型0的块的时间戳相同。

  • 时间戳增量: 3字节 ;对于类型1或类型2的块,前一个块的时间戳与当前块的时间戳之间的差值在这里发送。如果这个差值大于或等于16777215(十六进制0x00ffffff),这个值必须是16777215,并且必须存在“扩展时间戳头”。否则,这个值应该是整个差值。

  • 消息长度: 3字节; 对于类型0或类型1的块,消息的长度在这里发送。 注意,这通常与块有效载荷的长度不同。块有效载荷的长度对于除最后一个块之外的所有块来说是最大的块大小,对于最后一个块来说是剩余部分(对于小消息可能是整个长度)。

  • 消息类型ID; 1字节 ;对于类型0或类型1的块,消息的类型在这里发送。

  • 消息流id : 4字节 ;对于类型0的块,存储了消息流ID。消息流ID以小端格式存储。通常,同一消息流中的所有消息都来自相同的消息流。虽然可以将不同的消息流复用到同一个消息流中,但这会破坏所有头部压缩。然而,如果一个消息流被关闭,然后另一个消息流随后被打开,没有理由不能通过发送一个新的类型0块来重用现有的消息流。

案例:

案例一:

示例1展示了一个简单的音频消息流。这个示例演示了信息的冗余性。

下表显示了在此流中生成的块。从消息3开始,数据传输被优化。从这一点开始,每条消息只有1字节的开销。

案例二:

示例2展示了一个消息太长,无法容纳在一个128字节的块中,因此被拆分成几个块

这里是生成的块:

块1的头部数据指定了整个消息是307字节。 从这两个例子中可以看出,类型3的块可以以两种不同的方式使用。第一种是指定消息的延续。第二种是指定新消息的开始,其头部可以从现有的状态数据中派生出来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值