searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

rtmp 推流链路

2023-09-20 07:36:57
13
0

1、推流链路

RTMP 协议是基于可靠传输 TCP 协议的,所以首先离不开创建 TCP 连接。RTMP 流建立过程大概要经历三个阶段:
  • 第一阶段是 TCP 连接建立过程。
  • 第二阶段是 RTMP HandShake 过程,本人理解主要是为了连接探测,因为 tcp 连接 ok ,不代表可以正常通信。比如,某个实验小程序占用了 1935 端口,connect 能成功,但是 RTMP 通信肯定不行,因为不支持此协议啊,所以需要探测这一步。
c0,c1,c2 是客户端要发送的消息,s0,s1,s2 是服务端要发送的消息。rtmp 1.0 规范中的例子是每一个包都是单发的,顺序是 c0->s0->c1->s1->c2->s2。然而,具体实现都是如下图所以,目的是为了减少交互过程,加快连接过程。
 
握手大概过程:
Client                             Server
|                                          |
|                C0, C1                 |
|---------------------->|
|                                          |
|                S0,S1,S2              |
|<----------------------|
|                                          |
| C2                                     |
|---------------------->|
 
  • 第三阶段是逻辑流通道建立过程,对于 play 和 publish 过程稍有不同。

      play 过程:

Client                                                                 Server
|                                                                              |
|                   connect(app,tcUrl, codecs)                      |
|------------------------------------------>|
|                                                                              |
|                 Window Acknowledgement Size                 |
|<------------------------------------------|
|                                                                              |
|                     Set Peer Bandwidth (0x06)                   |
|<------------------------------------------|
|                                                                              |
|                      -result(response connect)                    |
|<------------------------------------------|
|                                                                              |
|                    Window Acknowledgement Size              |
|------------------------------------------>|
|                                                                              |
|                               createStream                            |
|------------------------------------------>|
|                                                                              |
|                   _result(response createStream)               |
|<------------------------------------------|
|                                                                              |
|                          getStreamLength()                          |
|------------------------------------------>|
|                                                                              |
|                           play(stream name)                         |
|------------------------------------------>|
|                                                                              |
|             User Control Message set buffer length          |
|------------------------------------------>|
|                                                                              |
|                               Stream Begin                            |
|<------------------------------------------|
|                                                                              |
|        onStatus | RtmpSampleAccess | onMetaData        |
|<------------------------------------------|
|                                                                              |
|                                 Media Data                             |
|<------------------------------------------|
|                                                                              |
 

2、推流交互消息流程

librtmp提供了推流的API,可以在rtmp.h文件中查看所有API。我们只需要使用常用的几个API就可以将streaming推送到服务器。
- RTMP_Init()//初始化结构体
- RTMP_Free()
- RTMP_Alloc()
- RTMP_SetupURL()//设置rtmp server地址
- RTMP_EnableWrite()//打开可写选项,设定为推流状态
- RTMP_Connect()//建立NetConnection
- RTMP_Close()//关闭连接
- RTMP_ConnectStream()//建立NetStream
- RTMP_DeleteStream()//删除NetStream
- RTMP_SendPacket()//发送数据
 
3、Connect 消息
RTMP 命令消息格式:
 
+----------------+---------+---------------------------------------+
|       Field Name        |      Type     |                             Description                           |
+--------------- +---------+---------------------------------------+
|    Command Name   |     String    |         Name of the command. Set to "connect".      |
+----------------+---------+---------------------------------------+
|     Transaction ID     |    Number   |                        Always set to 1.                           |
+----------------+---------+---------------------------------------+
|   Command Object   |    Object     |         Command information object which has       |
|                              |                   |                     the name-value pairs.                    |
+----------------+---------+---------------------------------------+
|       Optional User     |     Object   |                     Any optional information                 |
|        Arguments        |                 |                                                                         |
+----------------+---------+---------------------------------------+
 
RTMP握手之后先发送一个connect命令消息,命令里面包含什么东西,协议中没有具体规定,实际通信中要携带 rtmp url 中的 appName 字段,并且指定一些编解码的信息,并以AMF格式发送。
 
这些信息协议中并没有特别详细说明, 在librtmp,srs-librtmp这些源码中,以及用wireshark 抓包的时候可以看到。
服务器返回的是一个_result命令类型消息,这个消息的payload length一般不会大于128字节,但是在最新的nginx-rtmp中返回的消息长度会大于128字节。
消息的transactionID是用来标识command类型的消息的,服务器返回的_result消息可以通过transactionID来区分是对哪个命令的回应,connect 命令发完之后还要发送其他命令消息,要保证他们的transactionID不相同。
发送完connect命令之后一般会发一个 set chunk size消息来设置chunk size的大小,也可以不发。
Window Acknowledgement Size 是设置接收端消息窗口大小,一般是2500000字节,即告诉对端在收到设置的窗口大小长度的数据之后要返回一个ACK消息。在实际做推流的时候推流端要接收很少的服务器数据,远远到达不了窗口大小,所以这个消息可以不发。而对于服务器返回的ACK消息一般也不做处理,默认服务器都已经收到了所有消息了。
之后要等待服务器对于connect消息的回应的,一般是把服务器返回的chunk都读完,组包成完整的RTMP消息,没有错误就可以进行下一步了。
 
4、Create Stream 消息
创建完RTMP连接之后就可以创建RTMP流,客户端要向服务器发送一个releaseStream命令消息,之后是FCPublish命令消息,在之后是createStream命令消息。
当发送完createStream消息之后,解析服务器返回的消息会得到一个stream ID。
这个ID也就是以后和服务器通信的 message stream ID, 一般返回的是1,不固定。
 
5、 Publish Stream
推流准备工作的最后一步是Publish Stream,即向服务器发一个publish命令消息,消息中会带有流名称字段,即rtmp url中的 streamName,这个命令的message stream ID 就是上面 create stream 之后服务器返回的stream ID,发完这个命令一般不用等待服务器返回的回应,直接发送音视频类型的RTMP数据包即可。有些rtmp库还会发setMetaData消息,这个消息可以发也可以不发,里面包含了一些音视频meta data的信息,如视频的分辨率等等。
 
6、推送音视频
当以上工作都完成的时候,就可以发送音视频了。音视频RTMP消息的Payload(消息体)中都放的是按照FLV-TAG格式封的音视频包,具体可以参照FLV封装的协议文档。格式必须封装正确,否则会造成播放端不能正常拿到音视频数据,无法播放音视频。
5. 关于RTMP的时间戳
RTMP的时间戳单位是毫秒ms,在发送音视频之前一直为零,发送音视频消息包后时候必须保证时间戳是单调递增的,时间戳必须打准确,否则播放端可能出现音视频不同步的情况。Srs-librtmp的源码中,如果推的是视频文件的话,发现他们是用H264的dts作为时间戳的。实时音视频传输的时候是先获取了下某一时刻系统时间作为基准,然后每次相机采集到的视频包,与起始的基准时间相减,得到时间戳,这样可以保证时间戳的正确性。
 
7、关于Chunk Stream ID
RTMP 的Chunk Steam ID是用来区分某一个chunk是属于哪一个message的 ,0和1是保留的。每次在发送一个不同类型的RTMP消息时都要有不用的chunk stream ID, 如上一个Message 是command类型的,之后要发送视频类型的消息,视频消息的chunk stream ID 要保证和上面 command类型的消息不同。每一种消息类型的起始chunk 的类型必须是 Type_0 类型的,表明新的消息的起始。
0条评论
作者已关闭评论
s****n
2文章数
0粉丝数
s****n
2 文章 | 0 粉丝
s****n
2文章数
0粉丝数
s****n
2 文章 | 0 粉丝
原创

rtmp 推流链路

2023-09-20 07:36:57
13
0

1、推流链路

RTMP 协议是基于可靠传输 TCP 协议的,所以首先离不开创建 TCP 连接。RTMP 流建立过程大概要经历三个阶段:
  • 第一阶段是 TCP 连接建立过程。
  • 第二阶段是 RTMP HandShake 过程,本人理解主要是为了连接探测,因为 tcp 连接 ok ,不代表可以正常通信。比如,某个实验小程序占用了 1935 端口,connect 能成功,但是 RTMP 通信肯定不行,因为不支持此协议啊,所以需要探测这一步。
c0,c1,c2 是客户端要发送的消息,s0,s1,s2 是服务端要发送的消息。rtmp 1.0 规范中的例子是每一个包都是单发的,顺序是 c0->s0->c1->s1->c2->s2。然而,具体实现都是如下图所以,目的是为了减少交互过程,加快连接过程。
 
握手大概过程:
Client                             Server
|                                          |
|                C0, C1                 |
|---------------------->|
|                                          |
|                S0,S1,S2              |
|<----------------------|
|                                          |
| C2                                     |
|---------------------->|
 
  • 第三阶段是逻辑流通道建立过程,对于 play 和 publish 过程稍有不同。

      play 过程:

Client                                                                 Server
|                                                                              |
|                   connect(app,tcUrl, codecs)                      |
|------------------------------------------>|
|                                                                              |
|                 Window Acknowledgement Size                 |
|<------------------------------------------|
|                                                                              |
|                     Set Peer Bandwidth (0x06)                   |
|<------------------------------------------|
|                                                                              |
|                      -result(response connect)                    |
|<------------------------------------------|
|                                                                              |
|                    Window Acknowledgement Size              |
|------------------------------------------>|
|                                                                              |
|                               createStream                            |
|------------------------------------------>|
|                                                                              |
|                   _result(response createStream)               |
|<------------------------------------------|
|                                                                              |
|                          getStreamLength()                          |
|------------------------------------------>|
|                                                                              |
|                           play(stream name)                         |
|------------------------------------------>|
|                                                                              |
|             User Control Message set buffer length          |
|------------------------------------------>|
|                                                                              |
|                               Stream Begin                            |
|<------------------------------------------|
|                                                                              |
|        onStatus | RtmpSampleAccess | onMetaData        |
|<------------------------------------------|
|                                                                              |
|                                 Media Data                             |
|<------------------------------------------|
|                                                                              |
 

2、推流交互消息流程

librtmp提供了推流的API,可以在rtmp.h文件中查看所有API。我们只需要使用常用的几个API就可以将streaming推送到服务器。
- RTMP_Init()//初始化结构体
- RTMP_Free()
- RTMP_Alloc()
- RTMP_SetupURL()//设置rtmp server地址
- RTMP_EnableWrite()//打开可写选项,设定为推流状态
- RTMP_Connect()//建立NetConnection
- RTMP_Close()//关闭连接
- RTMP_ConnectStream()//建立NetStream
- RTMP_DeleteStream()//删除NetStream
- RTMP_SendPacket()//发送数据
 
3、Connect 消息
RTMP 命令消息格式:
 
+----------------+---------+---------------------------------------+
|       Field Name        |      Type     |                             Description                           |
+--------------- +---------+---------------------------------------+
|    Command Name   |     String    |         Name of the command. Set to "connect".      |
+----------------+---------+---------------------------------------+
|     Transaction ID     |    Number   |                        Always set to 1.                           |
+----------------+---------+---------------------------------------+
|   Command Object   |    Object     |         Command information object which has       |
|                              |                   |                     the name-value pairs.                    |
+----------------+---------+---------------------------------------+
|       Optional User     |     Object   |                     Any optional information                 |
|        Arguments        |                 |                                                                         |
+----------------+---------+---------------------------------------+
 
RTMP握手之后先发送一个connect命令消息,命令里面包含什么东西,协议中没有具体规定,实际通信中要携带 rtmp url 中的 appName 字段,并且指定一些编解码的信息,并以AMF格式发送。
 
这些信息协议中并没有特别详细说明, 在librtmp,srs-librtmp这些源码中,以及用wireshark 抓包的时候可以看到。
服务器返回的是一个_result命令类型消息,这个消息的payload length一般不会大于128字节,但是在最新的nginx-rtmp中返回的消息长度会大于128字节。
消息的transactionID是用来标识command类型的消息的,服务器返回的_result消息可以通过transactionID来区分是对哪个命令的回应,connect 命令发完之后还要发送其他命令消息,要保证他们的transactionID不相同。
发送完connect命令之后一般会发一个 set chunk size消息来设置chunk size的大小,也可以不发。
Window Acknowledgement Size 是设置接收端消息窗口大小,一般是2500000字节,即告诉对端在收到设置的窗口大小长度的数据之后要返回一个ACK消息。在实际做推流的时候推流端要接收很少的服务器数据,远远到达不了窗口大小,所以这个消息可以不发。而对于服务器返回的ACK消息一般也不做处理,默认服务器都已经收到了所有消息了。
之后要等待服务器对于connect消息的回应的,一般是把服务器返回的chunk都读完,组包成完整的RTMP消息,没有错误就可以进行下一步了。
 
4、Create Stream 消息
创建完RTMP连接之后就可以创建RTMP流,客户端要向服务器发送一个releaseStream命令消息,之后是FCPublish命令消息,在之后是createStream命令消息。
当发送完createStream消息之后,解析服务器返回的消息会得到一个stream ID。
这个ID也就是以后和服务器通信的 message stream ID, 一般返回的是1,不固定。
 
5、 Publish Stream
推流准备工作的最后一步是Publish Stream,即向服务器发一个publish命令消息,消息中会带有流名称字段,即rtmp url中的 streamName,这个命令的message stream ID 就是上面 create stream 之后服务器返回的stream ID,发完这个命令一般不用等待服务器返回的回应,直接发送音视频类型的RTMP数据包即可。有些rtmp库还会发setMetaData消息,这个消息可以发也可以不发,里面包含了一些音视频meta data的信息,如视频的分辨率等等。
 
6、推送音视频
当以上工作都完成的时候,就可以发送音视频了。音视频RTMP消息的Payload(消息体)中都放的是按照FLV-TAG格式封的音视频包,具体可以参照FLV封装的协议文档。格式必须封装正确,否则会造成播放端不能正常拿到音视频数据,无法播放音视频。
5. 关于RTMP的时间戳
RTMP的时间戳单位是毫秒ms,在发送音视频之前一直为零,发送音视频消息包后时候必须保证时间戳是单调递增的,时间戳必须打准确,否则播放端可能出现音视频不同步的情况。Srs-librtmp的源码中,如果推的是视频文件的话,发现他们是用H264的dts作为时间戳的。实时音视频传输的时候是先获取了下某一时刻系统时间作为基准,然后每次相机采集到的视频包,与起始的基准时间相减,得到时间戳,这样可以保证时间戳的正确性。
 
7、关于Chunk Stream ID
RTMP 的Chunk Steam ID是用来区分某一个chunk是属于哪一个message的 ,0和1是保留的。每次在发送一个不同类型的RTMP消息时都要有不用的chunk stream ID, 如上一个Message 是command类型的,之后要发送视频类型的消息,视频消息的chunk stream ID 要保证和上面 command类型的消息不同。每一种消息类型的起始chunk 的类型必须是 Type_0 类型的,表明新的消息的起始。
文章来自个人专栏
rtmp
2 文章 | 1 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0