rtmp协议和rtsp的区别(SRS4.0源代码分析之RTMP协议入门)
rtmp协议和rtsp的区别(SRS4.0源代码分析之RTMP协议入门)
2024-11-06 12:49:51  作者:孤旅半情调  网址: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代码学习做好准备。

  • 命好的人身体都有这三个特征(体相这样的人是好命)
  • 2024-11-06体相这样的人是好命1.下巴阔而有肉的女人,一定能旺夫,且温柔贤惠,是不会缺钱的好命下巴尖的女人,性格强势又犀利,善于享受不爱付出,多对男人有不满意2.一般人的脚趾都是大拇趾或二拇趾长,小趾最短若是你的脚趾,五趾平齐,或。
  • 如何自己烧火锅(怎么烧火锅好吃讲解)
  • 2024-11-06怎么烧火锅好吃讲解准备青菜,如菠菜,白菜,娃娃菜,葱,等等,或者从超市或市场里进行购买,然后择菜后进行清洗干净,还有火锅底料和蘸料等,适量的肉食或者肉冻鱼丸香肠先准备个炒锅把食用油倒入锅内,加入葱姜蒜后爆出味道,适量加。
  • 宝宝高烧不退会导致什么后果(宝宝一直高烧不退)
  • 2024-11-06宝宝一直高烧不退小孩子抵抗力比较弱,一生病就容易发烧可如果高烧不退,就需要家长们引起重视了,及时做好护理,必要的时候及时就医我们一起来看一下,宝宝高烧不退可能会有哪些原因?发烧,指的是腋温≥37.5℃或者肛温≥38℃。
  • 周末带孩子参加社会实践(收集盖章帮)
  • 2024-11-06收集盖章帮你的孩子参加暑期社会实践了吗?进入暑假后,长沙不少中小学生家长开始为此“焦虑”——担心孩子完不成社会实践,又怕参与了没收获有的甚至不惜找关系、掷千金,热衷于“收集”盖章,“帮”孩子走过场,让暑期社会实。
  • 甄嬛传纯元为什么叫菀菀(甄嬛传纯元叫宛宛)
  • 2024-11-06甄嬛传纯元叫宛宛皇上对于自己钟爱的妃嫔,都总是会唤她们的爱称无论是皇上心中的“白月光”纯元皇后,还是后来的甄嬛,包括眉庄、年世兰,皇上对她们都有过宠溺的称呼宛宛是纯元的小字,是专属于皇上对于她的爱称,但是对于宜修来说。
  • 玦是哪个古代留下的耳饰 璧瑗环
  • 2024-11-06玦是哪个古代留下的耳饰 璧瑗环春秋战国时期,玉器具有丰富的文化象征意义,被广泛用在日常和礼仪生活中《荀子•大略》:“聘人以圭,问士以璧,召人以瑗,绝人以玦,反绝以环”又《尔雅·释器》:“肉倍好谓之璧,好倍肉谓之瑗,肉好若一谓之环”。
  • 悲伤逆流成河结局(结局就让你觉得悲惨了)
  • 2024-11-06结局就让你觉得悲惨了本文由明星粉丝团作者柴扉原创,未经允许不得转说到电影版《悲伤逆流成河》上映之后,很多网友心中都是难过其实这电影版《悲伤逆流成河》结局算是改编的比较幸福了,原著小说才是让大家崩溃这部作品女主角易遥她在1。
  • 10元风暴pk(十元风暴上线全新玩法)
  • 2024-11-06十元风暴上线全新玩法千呼万唤始的十元风暴终于来了,但是出场方式却大跌眼镜!1、首先快11点才出了活动和细则,让不少朋友在群里等了好久,不知道是不是招行的营销手段!2、活动玩法和前年去年规则完全变了模样,简单一句话不用组队。
  • 笑话故事大全(幽默的好处)
  • 2024-11-06幽默的好处早上我去买早饭,去卖混沌店,我说要两碗,老板在煮过程中说:打包还是带走?我吓一跳,老板又很大声的说到底打包还是带走?我战战兢兢的说能不能在这吃?我有一二货朋友知道女神胆子比较小,终于一天晚上把女神约出。
  • 快手字体加粗怎样设置
  • 2024-11-06快手字体加粗怎样设置1、首先我们先打开手机界面,点击“设置”图标2、此时打开设置的界面,点击设置界面中的“显示”选项3、在打开的界面中,点击“字体与显示大小”选项4、在弹出的“字体与显示大小”对话框,根据自己的需要调整字。
  • 封面人物舒珂是谁(封面人物舒珂)
  • 2024-11-06封面人物舒珂浙江构建党团队一体化培养机制作者|《中华儿女》记者王碧清编辑|华南作为共青团、少先队组织直接服务青少年工作平台,近年来,金华市青少年宫(简称“金华宫”)守正创新,围绕培养德智体美劳全面发展的孩子,不断。