rtmp协议和rtsp的区别(SRS4.0源代码分析之RTMP协议入门)
rtmp协议和rtsp的区别(SRS4.0源代码分析之RTMP协议入门)
2024-09-27 07:35:51  作者:孤旅半情调  网址:https://m.xinb2b.cn/life/hox309446.html

本文主要目的是通过学习RTMP协议,帮助读者理解SRS4.0源代码中相关协议的处理逻辑。

一、RTMP协议简介

RTMP协议是Real Time Message Protocol(实时消息传输协议)的缩写,它是由Adobe公司提出的⼀种应⽤层的协议。

RTMP协议⽤于解决音视频流传输过程中数据复⽤(Multiplexing,即一条RTMP流中同时包括音频、视频、字幕、控制命令等多种数据)和分包(packetizing)的问题。

随着互联网宽带基础设施更加完善,视频直播等领域逐渐活跃起来,RTMP作为业内⼴泛使⽤的协议也重新被相关开发者重视起来。

RTMP报文向上封装用户的音视频的帧数据和用户命令,向下依赖TCP协议保证音视频数据的可靠传输。


虽然,TCP协议可以保证上层用户报文的可靠传输,即接收的数据不丢包不乱序,但RTMP协议设计者仍然对自身做了比较冗余的过度设计,导致RTMP协议某些部分复杂且神秘,所以,不同厂商之间的协议实现存在兼容性问题。

二、RTMP协议基础

1、RTMP Message格式概述

RTMP协议面向上层用户定义了一种Message数据结构用于封装音视频的帧数据和协议控制命令,具体格式如下:

0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | Message Type | Payload length | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |Timestamp | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |Stream ID | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | Message Payload | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Message Type(1 Byte):消息类型ID,主要分为三类:协议控制消息、音视频数据帧、命令消息。

Payload Length(3-Bytes):报文净荷的字节数。以大端格式保存。

timestamp(4-Bytes):当前消息的时间戳。以大端格式保存

StreamID(4-Bytes):消息流ID,其实从抓包看,一般只有0、1两种值,0:信令,1:音视频数据

Message Payload:Message报文净荷

2、RTMP Chunk格式概述

RTMP协议的一个Message数据包可能会非常大(尤其是传输一个视频帧时,最大可能16M字节)。

为了保证TCP高效传输(超大数据包在网络传输中受MTU限制会自动切片,超大数据包在网络传输过程中丢失一个数据片,都需要重传整个报文,导致传输效率降低)。

所以,RTMP协议的设计者决定在RTMP协议内部对Message数据包分片,这里分片的单位被称为Chunk(数据块)。

Chunk报文长度默认128字节,同时用户也可以修改本端发送的Chunk报文长度,并通过RTMP协议通知接收端。所以,网络中实际传输的RTMP报文,总是如下Chunk封装格式:

1~3字节 |<-Chunk Header->| 0/3/7/11字节 0或4字节 ---------------- ---------------- ------------------- ----------- | Basic header | Msg Header | Extended Timestamp|Chunk Data | ---------------- ---------------- ------------------- ----------- 注:因为Msg Header里有一个3字节的timestamp,当timestamp 被设置为0xffffff时,才会出现Extended Timestamp字段

Basic Header也被称为Chunk header,它的实际格式一共有3种(1~3个字节),目的是为了满足不同的长度的CSID(Chunk Stream ID),所以,在足够存储CSID字段的前提下应该用尽量少的字节格式从而减少由于引入Basic Header而增加的数据量。

----------------------- ------------------ | format [2个bit] | CSID [6bit] | 结构1:1字节 ----------------------- ------------------ ----------------------- ------------------ -------------------- | format [2个bit] | 0 [6bit] | 扩展 CSID [8bit] | 结构2:2字节 ----------------------- ------------------ -------------------- ----------------------- ------------------ -------------------------------- | format [2个bit] | 1 [6bit] | 扩展 CSID [16bit] | 结构3:3字节 ----------------------- ------------------ --------------------------------

实际上为了处理方便,RTMP协议软件在具体实现时总是先读取一个字节的Basic Header,并根据前面2bit的format信息和后面6bit的CSID信息,判断报文的实际结构。

1、首先判断第一个字节的低6bit的CSID

 当低6bit的CSID为0时,Basic Header占用2个字节,扩展CSID在[64 0,255 64=319]之间。

 当低6bit的CSID为1时,Basic Header占用3个字节,扩展CSID在[64 0,65535 64=65599]之间。

 当低6bit的CSID为2~63时,Basic Header占用1个字节,这种情况适用于绝大多数的RTMP Chunk报文。

 CSID=2时,Message Type为1,2,3,5,6对应Chunk层控制协议,4对应用户控制命令

 CSID=3~8,用于connect、createStream、releaseStream 、publish、metaData、音视频数据

 (不同厂家之间,如FFMPEG、OBS在这里使用的CSID差异很大)

  显然,接下来更多的CSID已经意义不大了,毕竟有Message Type也够了。当然,用户可以使用更大的CSID做一些私有协议的扩展。

 实际上,真实环境中需要的CSID并不多,所以一般情况下,Basic Header长度总是一个字节。

2、接下来通过2bit的format字段,判断后面Msg Header格式

 format =00,Msg Header占用11个字节,这种结构最浪费,一般用于流开始发送的第一个chunk报文,且只有这种情况下,报文中的timestamp才是一个绝对时间, 后续chunk报文的Msg Header中要么是没有timestamp,有timestamp也只是相对前一个chunk报文的时间增量。

|<--Basic Header->|<------------------------Msg Header----------------------->| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | format | CSID | timestamp | message length | message type | msg stream id || 00 | | | | | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 bits 6 bits 3 bytes 3 bytes 1 bytes 4 bytes

 format =01,Msg Header占用7个字节,省去了4个字节的msg stream id,表示当前chunk和上一次发送的chunk所在的流相同

|<--Basic Header->|<---------------Msg Header---------------->| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | format | CSID | timestamp | message length | message type || 01 | | | | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 bits 6 bits 3 bytes 3 bytes 1 bytes

format =10,Msg Header占用3个字节,相对于format=01格式又省去了表示消息长度的3个字节和表示消息类型的1个字节。

|<--Basic Header->|<--Msg Header--->| - - - - - - - - - - - - - - - - - - | format | CSID | timestamp || 10 | | | - - - - - - - - - - - - - - - - - - 2 bits 6 bits 3 bytes

 format =11,Msg Header占用0个字节,它表示这个chunk的Msg Header和上一个chunk是完全相同的。

|<--Basic Header->| - - - - - - - - - | format | CSID || 11 | | - - - - - - - - - 2 bits 6 bits

3、总结

所以,实际应用过程中,RTMP协议的整体工作逻辑如下:

1、软硬件编码器以帧为单位生成音视频数据流

2、RTMP协议先将每一帧数据封装成一个Message数据包

3、再根据本端设置的trunk size(默认128字节)对Message数据包分片封装成trunk数据包,最终通过TCP协议实现网络传输。

4、反之,RTMP协议将接收的TCP数据包以chunk为单位进行组装,将多个chunk包还原成一个Message数据包,最终上层协议处理Message数据包。

领取音视频开发资料包:音视频流媒体高级开发FFmpegWebRTCRTMPRTSPHLSRTP播放器


企鵝群994289133领取资料


企鵝群994289133领取资料

三、RTMP协议报文

根据前面的学习,可知RTMP协议向上的处理逻辑是总是基于Message报文,向下的处理逻辑则基于Chunk报文,所以,接下来首先分析用户层Message报文的各种含义。

1. RTMP协议之Message报文详细说明

0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | Message Type | Payload length | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |Timestamp | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | Stream ID | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Message Type的范围是[0, 255],其中1、2、3、5、6用于Chunk层协议控制,4用于用户层控制命令;

Message Type =1 发送端向对端通知本端后续发送报文的chunk报文大小

Message Type =2 中断消息,发送端向对端通知之前收到的指定CSID的chunk报文需要全部丢弃

Message Type =3 ACK消息,接收端收到的消息大小等于ACK窗口大小时,接收端必须返回一个ACK

Message Type =5 客户端或服务端发送本消息来设置对方的ACK窗口大小

Message Type =6 限制对端的输出带宽

Message Type =4 客户端或服务端发送本消息通知对方用户层的控制命令。

Message Type =8 音频数据

Message Type =9 视频数据

Message Type =15(AMF3编码)/18(AMF0编码) 音视频元数据(Metadata)

Message Type =16(AMF3编码)/19(AMF0编码) 共享对象消息,键值对集合

Message Type =17(AMF3编码)/20(AMF0编码) 协议命令,主要分:

 NetConnection(网络连接命令)

  connect命令:客户端发给服务器端,请求建立连接

  call命令:请求对端执行某种(函数)功能

  close命令:

  createStream命令:客户端通知服务端建立一条音视频数据通道

  releaseStream命令:客户端通知服务端释放音视频数据通道资源

 NetStream(网络流命令):

  play:客户端向服务器发起请求,请求服务器端发送数据

  play2:此命令支持将当前正在播放的流切换到同样数据但不同⽐特率的流上

  deleteStream:客户端告知服务器端本地的某个流对象已被删除,不需要再传输此路流。

  receiveAudio:通知服务器端本客户端是否要发送⾳频

  receiveVideo:通知服务器端本客户端是否要发送视频

  publish:由客户端向服务器发起请求推流到服务器。

  seek:定位到视频或⾳频的某个位置,以毫秒为单位。

  pause:客户端告知服务端暂停或恢复播放。

Message Type =22 聚合消息(是一种含有一个消息列表的消息)

2. RTMP协议之Chunk报文详细说明

通过前面的学习,我们知道所有的Message报文最终都需要被分片封装为Chunk报文,再进行网络传输。所以,接下来需要了解一下上述各种类型的Message报文对应的Chunk格式。

Message Type =1;Set Chunk Size消息:发送端向对端通知本端后续发送报文的chunk报文大小

|<--Basic Header->|<------------------------Msg Header----------------------->| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | format | CSID | timestamp | message length | message type | msg stream id |Set chunk size | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 bits 6 bits 3 bytes 3 bytes 1 bytes 4 bytes 4 bytes 00 000010 0 4 0000,0001 0

Message Type =2;Abort Message消息:发送端向对端通知之前收到的指定CSID的chunk报文需要全部丢弃

|<--Basic Header->|<------------------------Msg Header----------------------->| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | format | CSID | timestamp | message length | message type | msg stream id |Chunk Stream ID| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 bits 6 bits 3 bytes 3 bytes 1 bytes 4 bytes 4 bytes 00 000010 0 4 0000,0010 0

Message Type =3;Acknowledgement确认消息:接收端收到的消息大小等于ACK窗口大小时,接收端必须返回一个ACK

|<--Basic Header->|<------------------------Msg Header----------------------->| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | format | CSID | timestamp | message length | message type | msg stream id |Sequence Number| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 bits 6 bits 3 bytes 3 bytes 1 bytes 4 bytes 4 bytes 00 000010 0 4 0000,0011 0其中Sequence Number是到当前时间为止已经接收到的字节数

Message Type =4;用户控制消息:客户端或服务端发送本消息通知对方用户层的控制命令

|<--Basic Header->|<------------------------Msg Header----------------------->| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | format | CSID | timestamp | message length | message type | msg stream id |Event Type |Event Data | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 bits 6 bits 3 bytes 3 bytes 1 bytes 4 bytes 2 bytes 2 bytes00 000010 0 4 0000,0100 0 事件类型 事件数据

Message Type =5;ACK窗口大小:客户端或服务端发送本消息来设置对方的ACK窗口大小

|<--Basic Header->|<------------------------Msg Header----------------------->| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | format | CSID | timestamp | message length | message type | msg stream id |Acknowledgement Window size| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 bits 6 bits 3 bytes 3 bytes 1 bytes 4 bytes 4 bytes00 000010 0 4 0000,0101 0

Message Type =6;设置对端输出带宽

|<--Basic Header->|<------------------------Msg Header----------------------->| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | format | CSID | timestamp | message length | message type | msg stream id |Acknowledgement Window size| Limit type| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 bits 6 bits 3 bytes 3 bytes 1 bytes 4 byte4 bytes 1 bytes 00 000010 0 5 0000,0110 0 限制类型(0硬,1软,2动态)

RTMP客户端与服务器之间连接建立后,开始推拉流时,总是先传输和音视频编码信息相关的MetaData(元数据),再传输音视频数据帧:

1)音视频数据总是采用FLV封装格式:tagHeader(1字节) tagData(编码帧)

2)对于H.264视频,第一个视频帧必须是SPS和PPS,后面才是I帧和P帧。

3)对于AAC音频,第一个音频帧必须是AAC sequence header,后面才是AAC编码音频数据。

所谓元数据MetaData,其实就是一些用字符串描述的音视频编码器ID和宽高信息,个人觉得没啥鸟用,后面会通过wireshark抓包,加深对MetaData数据包的理解。

所以,接下来以H264和ACC为例初步了解一下音视频数据在RTMP中的Chunk封装格式:

Message Type =8;Audio message

协议层 封装层 |RTMP Chunk Header | FLV AudioTagHeader | FLV AudioTagBody | FLV AudioTagHeader |SoundFormat | SoundRate | SoundSize | SoundType | OR |AACPacketType| 4bits 2bits 1bit 1bit 编码格式 采样率 采样精度8或16位 声道数(单/双)

如果音频格式是AAC(0x0A),上面的AudioTagHeader中会多出1个字节的AACPacketType描述后续的ACC包类型:

AACPacketType = 0x00 表示后续数据是AAC sequence header,

AACPacketType = 0x01 表示后续数据是AAC音频数据

最终,AAC sequence header由AudioSpecificConfig定义,简化的AudioSpecificConfig信息包括2字节如下:

|AAC Profile 5bits | 采样率 4bits | 声道数 4bits | 其他 3bits |对于RTMP推拉流,在发送第一个音频数据包前必须要发送这个AAC sequence header包。

Message Type =9;Video message

协议层 封装层|RTMP Chunk Header | FLV VideoTagHeader | FLV VideoTagBody | FLV VideoTagHeader |Frame Type | CodecID | |AVCPacketType | |CompositionTime | 4 bits 4 bits 1 byte3 byte 视频帧类型 编码器ID

Frame Type = 1表示H264的关键帧,包括IDR;Frame Type=2表示H264的非关键帧

codecID = 7表示AVC

当采用AVC编码(即H264)时,会增加1个字节的AVCPacketType字段(描述后续的AVC包类型)和3个字节的CompositionTime :

AVCPacketType=0时,表示后续数据AVC sequence header,此时3字节CompositionTime内容为0

AVCPacketType=1时,表示后续数据AVC NALU

AVCPacketType=2时,表示后续数据AVC end of sequence (一般不需要)

四、RTMP协议流程

前面学习了RTMP报文格式的基本概念,接下来学习RTMP客户端与服务器之间与推拉流相关的协议交换过程。

1. RTMP推流端协议交互流程(FFMPEG SRS)


2. RTMP拉流端协议交互流程(VLC SRS)


3. RTMP握手阶段的协议报文

1、客户端向服务端发送C0 C1(握手)请求


2、服务端向客户端发送S0 S1 S2(握手)响应


3、客户端向服务端发送C2(握手)响应


4. 连接建立阶段的协议报文

1、客户端向服务端发送connect请求


2、服务端发送设置ACK窗口大小


3、服务端发送设置对端输出


4、服务端发送set chunk size


5、服务端响应connect success


5. 流建立阶段的协议报文

1、客户端向服务端发送set chunk size请求


2、客户端向服务端发送releaseStream请求


3、客户端向服务端发送FCPublish请求


4、客户端向服务端发送createStream请求


注意:上述报文中只有第一个chunk报文是fmt=00的封装格式,剩下的都是fmt=01的封装格式,即剩下的chunk报文都省略了Stream ID字段

6. 推拉流阶段的协议报文

1、客户端向服务端发送publish请求


注意:此时chunk报文中的Stream ID字段值是1,之前报文的Stream ID字段值是0,总之,Stream ID字段其实并不是很有重要

2、服务端向客户端响应onFCPublish和onStatus报文



3、客户端向服务端发送MetaData(元数据)报文


如上,所谓MetaData元数据好像就是一堆字符串描述信息。

4、客户端向服务端发送H264的SPS PPS


5、客户端向服务端发送ACC sequence header


6、客户端向服务端发送视频数据


7、客户端向服务端发送音频数据


总结

本文的目的主要是通过了解RTMP底层报文,消除因为RTMP协议过度设计导致的复杂感和神秘感,为后续的SRS代码学习做好准备。

  • 百分之百成功的剪刘海教程(6个降低自己剪刘海失误的方法)
  • 2024-09-286个降低自己剪刘海失误的方法有刘海的女生一定要都会有个困扰,那就是刘海长的速度太快,如果每次都要跑一趟发廊,累积起来的花費可不少,所以相对之下,许多女生都会选择自己修剪,不过却也因此常常失误出糗,为了降低这样的情況发生,这回就让。
  • dnf手游体验服怎么挤进去(如何才能进入dnf手游体验服游戏)
  • 2024-09-28如何才能进入dnf手游体验服游戏dnf手游体验服是没有办法挤进去的,具备一定的条件才能进入,需要添加官方的微信号,预约DNF体验服资格,但是到时候官网会更新体验服的领取方式玩家可以填写调查问卷,然后有概率抽取到体验服资格,预约之后都。
  • 鸡蛋布丁做法
  • 2024-09-28鸡蛋布丁做法材料:一个鸡蛋、230ml牛奶、20ml淡奶油、15克糖做法:1.将淡奶油和牛奶加糖倒入奶锅加热,不停搅拌直至糖完全化开2.加入几滴香精草(去腥)3.将打散的鸡蛋放入奶中搅拌均匀,过筛两次(口感会更嫩。
  • 开车下雨起雾开什么灯(下大雨开车开什么灯)
  • 2024-09-28下大雨开车开什么灯如何正确的用灯作为影响行车安全的重要因素,其经常性的被提及,但却很少人会认真对待而一旦需要合理开灯的时候,尤其是大雨天气下,多数的车主并不知道到底该开哪个那么下面我们便为大家简要的介绍一下,当我们在大。
  • 不小心删除的微信好友怎么找回(删除的微信好友可以恢复吗)
  • 2024-09-28删除的微信好友可以恢复吗不小心把微信好友删了怎么找回?这个问题其实是很难解决的,如果是聊天记录或者文件删除了,还好解决,直接把好友都删了,就有点难了,不过就这样放弃吗?当然不可以啦,世上无难事只怕有心人,一起来尝试一下这三种。
  • 人力资源管理师有含金量嘛(人力资源管理师有什么用)
  • 2024-09-28人力资源管理师有什么用人力资源管理证书有啥用:  1、促进就业:持有人力资源管理证书的基础上,更容易找到对口的工作,尤其是原本专业不是很吃香的人,有了证书可朝着人力资源管理方向发展起来  2、升职加薪:在企事业单位当中,具。
  • 钓鱼时挂蚯蚓的最佳方法(蚯蚓挂法还能影响中鱼率)
  • 2024-09-28蚯蚓挂法还能影响中鱼率一个小小的蚯蚓挂法还能影响中鱼率?别不信,经验总结出最佳挂法,中鱼率大大提高但不管是什么事有利也有弊,选择正确的挂法的确可以提高命中率,但如果遇到特殊的鱼情,可能优势会变成劣势具体选择什么挂法,我们还。
  • 重庆猪副产品(重庆农特产品荣昌猪)
  • 2024-09-28重庆农特产品荣昌猪微信搜索“重庆地方志”关注我们的公众号哟!猪粮稳,天下安荣昌地处重庆西部,其名取自“繁荣昌盛”之意,自唐乾元元年(公元758年)始建县以来,已有1262年历史荣昌猪,因原产于重庆荣昌而得名荣昌猪品种形。
  • 去眼袋的小妙招(如何去眼袋)
  • 2024-09-28如何去眼袋蔬菜水果外敷:把新鲜的黄瓜片、土豆片、冬瓜片敷在眼睛上,然后闭眼休息十分钟,之后把蔬菜片去掉用清水洗干净,坚持每天使用可以有效缓解眼袋浮肿的问题眼部按摩:每天早晚用在眼睛周围涂抹上眼霜,然后用指腹轻轻。
  • 这些字认识5个算你厉害(这些字你认识几个)
  • 2024-09-28这些字你认识几个三个刀念刕『梨』三个力念劦『协』三个又念叒『若』三个土念垚『摇』三个士念壵『状』三个子念孨『转』三个小念尛『魔』三个心念惢『蕊』三个手念掱『爬』三个止念歮『色』三个毛念毳『脆』三个水念淼『秒』三个火念。
  • 怎样做冬瓜好吃(冬瓜的做法)
  • 2024-09-28冬瓜的做法牛肉馅用盐、料酒、白胡椒、生抽、葱姜末先腌一下肉馅掺入香菜末,用筷子朝着一个方向打到粘稠锅中加水,糖粿开锅后转入小火开始汆丸子放入冬瓜,加入盐调味,放上香菜,冬瓜丸子汤就做好了。