rtmp协议和rtsp的区别(SRS4.0源代码分析之RTMP协议入门)
rtmp协议和rtsp的区别(SRS4.0源代码分析之RTMP协议入门)
2024-10-02 01:52:49  作者:孤旅半情调  网址:https://m.xinb2b.cn/sport/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-10-02汤镇业为她一蹶不振本文未经作者授权不得转载,发现必究!文/萌神木木当年翁美玲演出“黄蓉”一角时有多被受质疑,后来就有多成功她饰演的“黄蓉”是金庸亲选,这也是为何作为新人的她,能够在那么多人选中脱颖而出但当时许多媒体还是。
  • 新车钱江150油冷太子价格(钱江通路车金龙150上市)
  • 2024-10-02钱江通路车金龙150上市钱江通路车金龙150上市,15L大油箱,自带翻转大货架,售价9680元随着玩乐市场的崛起,貌似通路跨骑车变得越来越少了车系比较完善,车型较多的无非就是豪爵和五羊本田与新大洲本田但近日,老牌摩企钱江摩托。
  • 转生成反派师尊的动漫一口气看完(国漫看什么请和我生娃吧)
  • 2024-10-02国漫看什么请和我生娃吧龙一直以来都是中国古代传说中最为强大的奇幻生物,他们不但是皇权的象征,还是能够呼风唤雨的存在因此在很多作品中,他们的形象大多都十分高大上,令人望而生畏但要是神龙们突然有一天变成了凡人,并且还个个都一心。
  • 蓝妮与孙科的婚姻(蓝妮与孙中山儿子孙科的那些事)
  • 2024-10-02蓝妮与孙中山儿子孙科的那些事“蓝妮事件”,众所周知,让孙中山的儿子孙科与国民党副总统位置失之交臂,让他的竞争对手抓住了把柄,最后的结果是蓝妮和孙科两人选择分手,从此两不相见蓝妮在认识孙科之前,就曾经结过一次婚,因为家道中落,嫁给。
  • 特刊红旗渠精神永在,特刊红旗渠精神永在
  • 2024-10-02特刊红旗渠精神永在,特刊红旗渠精神永在红旗渠就是纪念碑,记载了林县人不认命、不服输、敢于战天斗地的英雄气概要用红旗渠精神教育人民特别是广大青少年,社会主义是拼出来、干出来、拿命换来的,不仅过去如此,新时代也是如此没有老一辈人拼命地干,没有。
  • 罗罗诺亚索隆卡通海贼王人物(海贼王大剑客现身)
  • 2024-10-02海贼王大剑客现身索隆帅气开场!个人非常喜欢画索隆,每个动态都是超帅路飞与克比乘着小船抵达海军基地的城镇,向路人打听索隆是不是在基地里,路人闻声迅速“惧散”,克比随之说基地里有一叫蒙卡的上校,众人闻声也是迅速“惧散”海。
  • 以更加昂扬姿态奋进新征程(奋进新征程建功新时代)
  • 2024-10-02奋进新征程建功新时代来源:新华网新华社贵阳4月8日电题:“陀螺王”和大山的故事新华社记者齐健瑶山,曾是贵州最贫穷落后的“三山”之一,“九山半水半分田”,不通公路,水源不足,土地贫瘠……谢友明就出生在这个地方如今,在贵州省。
  • 如果感染了梅毒会有什么症状(不洁性行为有多危险)
  • 2024-10-02不洁性行为有多危险#李易峰多次嫖娼被行政拘留#近日,一个“明星因多次嫖娼而被拘留”的新闻闹得沸沸扬扬不得不说,如今娱乐圈是应该好好整治整治,一些粉丝们也得清醒清洗,该放手时就得放手,可千万不要活在幻想中,更不要被不法。
  • 嘉兴乌镇景点有哪些(不去乌镇还有什么选择)
  • 2024-10-02不去乌镇还有什么选择嘉兴位于浙江省东北部和杭州隔江相望距离上海也不过个把小时提到嘉兴联想的关键词必有粽子、南湖、乌镇、水乡等等本次拜访嘉兴也恰逢端午节赶上烟雨濛濛的雨季前往乌镇奈何北京行程带星直接景区劝返2日水乡游立马改。
  • 金凯瑞看到老婆和别人抱一起 女友自杀不难过
  • 2024-10-02金凯瑞看到老婆和别人抱一起 女友自杀不难过标签:金凯瑞女友自杀简介:据台湾媒体报道,好莱坞喜剧演员金凯瑞前女友凯斯里欧娜怀特9月28日被发现自杀身亡,疑似因为服药过量而去世,年仅28岁就香消玉殒然而,金凯瑞最近被曝出女友死亡当天,人在跑趴还和。