rtmp协议和rtsp的区别(SRS4.0源代码分析之RTMP协议入门)
rtmp协议和rtsp的区别(SRS4.0源代码分析之RTMP协议入门)
2024-09-29 04:48:27  作者:孤旅半情调  网址:https://m.xinb2b.cn/know/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代码学习做好准备。

  • mmc摔角狂欢夜直播在哪里看(MMC职业摔角出现在王者会盟)
  • 2024-09-29MMC职业摔角出现在王者会盟格斗世界讯:2018年1月5日,由中国古泰拳第一人黄海刚所举办的《王者会盟·MMC战神录》全明星年度格斗盛典,在广东深圳盛大举行在当晚的第四场比赛上,我们可以看到,不同于以往的自由搏击和泰拳、MMA,。
  • 王者荣耀改名卡怎么领取(王者荣耀改名卡领取方法)
  • 2024-09-29王者荣耀改名卡领取方法首先登陆自己的王者荣耀账号进入游戏以后点击【战令】然后战令等级达到42级就可以免费获得改名卡接着我们还可以点击【活动】再收集相应的游戏道具最后利用获得的游戏道具兑换改名卡。
  • 小白鞋如何去污小妙招(15分钟内让你的帆布鞋)
  • 2024-09-2915分钟内让你的帆布鞋帆布鞋成为潮流的宠儿,制造商们也把帆布鞋玩出了更多的花样复古、运动、华丽、重金属、摇滚、马毛、皮革、牛仔,不管生出怎样的变化,穿帆布鞋的百无禁忌让它成为潮流人士的必备单品帆布鞋具备了百搭、简单、时尚、。
  • 波风水门和玖辛奈奥义图(波风水门比谁都清醒)
  • 2024-09-29波风水门比谁都清醒有一个人,在火影开头昙花一现,惊艳了一票火影迷他清爽的金色短发仿佛是月下的麦浪,一袭火影战袍在风中不断拍打,他就是——波风水门仅仅24岁的年纪,没有响彻整个忍界的姓氏作为他的支撑,他用自己的努力让忍界。
  • 菱智7座是mpv吗(体验菱智中型MPV7座设计1.6L动力颜值不错)
  • 2024-09-29体验菱智中型MPV7座设计1.6L动力颜值不错给你6万元的裸车价,购买一辆大空间的车,你会如何选择呢?我相信绝大部分的朋友会考虑五菱微面车型吧,不但价格便宜,空间大,还耐造但是真的没有其它选择了吗?未必今天我们就来聊一聊东风风行菱智(图片|配置|。
  • 电水壶有水垢怎么清除(电水壶水垢清理小窍门)
  • 2024-09-29电水壶水垢清理小窍门水垢是由于开水壶用久了,内壁会长出一层厚厚的杂质水垢是沉积于与硬水接触的表面的一层或者沉淀物水垢的最普通的形式为碳酸钙,并且自然地作为白垩、石灰石和大理石的一种成份出现这些现象说明,看起来清亮透彻的水。
  • 成都新世界百货有哪些男装品牌(系列国际一线奢侈品牌)
  • 2024-09-29系列国际一线奢侈品牌原创达观天下(注:上图来源于网络)7月25日下午5点左右,我们来到了成都系列国际一线奢侈品牌、潮流服饰品牌、米其林星级餐厅以及国内外知名食府所在地---太古里游玩沿路我们经过了成都市图书馆、博物馆等地。
  • 2022年抖音游戏行业报告(2022抖音游戏报告)
  • 2024-09-292022抖音游戏报告本篇报告是对2021年10月-2022年4月抖音游戏行业内容生产及达人情况进行概述与用户洞察,梳理出了2022年抖音游戏行业值得关注的三大趋势:行业黄金流量期:暑期是游戏行业流量与用户搜索高峰期;游戏。
  • 所谓的科学养猫真的科学吗(让你养的猫教你)
  • 2024-09-29让你养的猫教你1尽管猫主子就是你的一切,但要说它能带你理解量子力学,你恐怕一时难以接受但是仔细想想你就能发现:“猫,是最具有量子属性的一种宏观世界的生物”举个例子你每天下班回家,你将有可能面对两种有天壤之别的场景—。
  • 原创春风1-65章已完结(长篇连载望星空)
  • 2024-09-29长篇连载望星空8月1日今天是八一建军节对于我们常人来讲,并没有什么特殊的也许会参加一些拥军优属活动,也许会在电视上看看军事题材的电视剧或者电影而对于杨灵来讲,意义就非同一般因为她的张长青目前正在西南前线戍边,炎炎夏。
  • 荣耀x40gt最详细参数(性能战神正式发布)
  • 2024-09-29性能战神正式发布IT之家10月13日消息,就在刚刚,荣耀带来最新机型——荣耀X40GT该机配置强悍,用上了旗舰级处理器,官方主打的“战神性能铁三角”,也让用户体验得到大幅提升!结合最新官方发布会消息及最新上手感受:性。
  • gucci双面虎头腰包大号(gucci虎头腰包)
  • 2024-09-29gucci虎头腰包gucci的包包一直都是大家比较喜欢的,而且他家的包包都很有他家的味道,很多明星都喜欢背,那么gucci虎头腰包你又了解多少呢?首先我们来了解下gucci虎头腰包实用性包包虽然是单层的,但是每次出门必。