【音视频】RTMP协议详解

一、RTMP协议介绍

RTMP协议是Real Time Message Protocol(实时信息传输协议)的缩写,它是由Adobe公司提出的⼀种应⽤层的协议,⽤来解决多媒体数据传输流的多路复⽤(Multiplexing)和分包(packetizing)的问题。随着VR技术的发展,视频直播等领域逐渐活跃起来,RTMP作为业内⼴泛使⽤的协议也重新被相关开发者重视起来。

1.1 RTMP 概述

  • RTMP协议是应⽤层协议,是要靠底层可靠的传输层协议(通常是TCP)来保证信息传输的可靠性的。在基于传输层协议的链接建⽴完成后,RTMP协议也要客户端和服务器通过"握⼿"来建⽴基于传输层链接之上的RTMP Connection链接,在Connection链接上会传输⼀些控制信息,如SetChunkSize,SetACKWindowSize。

  • 其中CreateStream命令会创建⼀个Stream链接,⽤于传输具体的⾳视频数据和控制这些信息传输的命令信息。

  • RTMP协议传输时会对数据做⾃⼰的格式化,这种格式的消息我们称之为RTMP Message,⽽实际传输的时候为了更好地实现多路复⽤、分包和信息的公平性,发送端会把Message划分为带有Message ID的Chunk,每个Chunk可能是⼀个单独的Message,也可能是Message的⼀部分,在接受端会根据chunk中包含的data的⻓度,message id和message的⻓度把chunk还原成完整的Message,从⽽实现信息的收发。

1.2 RTMP 的握手流程

要建⽴⼀个有效的RTMP Connection链接,⾸先要"握⼿":客户端要向服务器发送C0,C1,C2(按序)三个chunk,服务器向客户端发送S0,S1,S2(按序)三个chunk,然后才能进⾏有效的信息传输。

RTMP协议本身并没有规定这6个Message的具体传输顺序,但RTMP协议的实现者需要保证这⼏点

  1. 客户端要等收到S1之后才能发送C2
  2. 客户端要等收到S2之后才能发送其他信息(控制信息和真实⾳视频等数据)
  3. 服务端要等到收到C0之后发送S1
  4. 服务端必须等到收到C1之后才能发送S2
  5. 服务端必须等到收到C2之后才能发送其他信息(控制信息和真实⾳视频等数据)

如果每次发送⼀个握⼿chunk的话握⼿顺序会是这样

理论上来讲只要满⾜以上条件,如何安排6个Message的顺序都是可以的,但实际实现中为了在保证握⼿的身份验证功能的基础上尽量减少通信的次数,⼀般的发送顺序是这样的,这⼀点可以通过wireshark抓ffmpeg推流包进⾏验证:

text 复制代码
|client|Server |
|---C0+C1---->|
|<--S0+S1+S2-- |
|---C2----> |

1.3 RTMP Chunk Stream

Chunk Stream是对传输RTMP Chunk的流的逻辑上的抽象,客户端和服务器之间有关RTMP的信息都在这个流上通信。这个流上的操作也是我们关注RTMP协议的重点。

1.3.1 Message

这⾥的Message是指满⾜该协议格式的、可以切分成Chunk发送的消息,消息包含的字段如下:

  • Timestamp(时间戳):消息的时间戳(但不⼀定是当前时间,后⾯会介绍),4个字节
  • Length(⻓度):是指Message Payload(消息负载)即⾳视频等信息的数据的⻓度,3个字节
  • TypeId(类型Id):消息的类型Id,1个字节
  • Message Stream ID(消息的流ID):每个消息的唯⼀标识,划分成Chunk和还原Chunk为Message的时候都是根据这个ID来辨识是否是同⼀个消息的Chunk的,4个字节,并且以⼩端格式存储(Message Stream ID如何产⽣?audio和video使⽤不同的Message Stream ID)

1.3.2 Chunking(Message 分块)

  • RTMP在收发数据的时候并不是以Message为单位的,⽽是把Message拆分成Chunk发送,⽽且必须在⼀个Chunk发送完成之后才能开始发送下⼀个Chunk。每个Chunk中带有MessageID代表属于哪个Message,接受端也会按照这个id来将chunk组装成Message

  • 为什么RTMP要将Message拆分成不同的Chunk呢?通过拆分,数据量较⼤的Message可以被拆分成较⼩的"Message",这样就可以避免优先级低的消息持续发送阻塞优先级⾼的数据,⽐如在视频的传输过程中,会包括视频帧,⾳频帧和RTMP控制信息,如果持续发送⾳频数据或者控制数据的话可能就会造成视频帧的阻塞,然后就会造成看视频时最烦⼈的卡顿现象。同时对于数据量较⼩的Message,可以通过对Chunk Header的字段来压缩信息,从⽽减少信息的传输量。

  • Chunk的默认⼤⼩是128字节,在传输过程中,通过⼀个叫做Set Chunk Size的控制信息(⻅spec 5.4.1 )可以设置Chunk数据量的最⼤值,在发送端和接受端会各⾃维护⼀个Chunk Size(srs流媒体服务器默认是60000),可以分别设置这个值来改变⾃⼰这⼀⽅发送的Chunk的最⼤⼤⼩。

  • ⼤⼀点的Chunk减少了计算每个chunk的时间从⽽减少了CPU的占⽤率,但是它会占⽤更多的时间在发送上,尤其是在低带宽的⽹络情况下,很可能会阻塞后⾯更重要信息的传输。⼩⼀点的Chunk可以减少这种阻塞问题,但⼩的Chunk会引⼊过多额外的信息(Chunk中的Header),少量多次的传输也可能会造成发送的间断导致不能充分利⽤⾼带宽的优势,因此并不适合在⾼⽐特率的流中传输。

  • 在实际发送时应对要发送的数据⽤不同的Chunk Size去尝试,通过抓包分析等⼿段得出合适的Chunk⼤⼩,并且在传输过程中可以根据当前的带宽信息和实际信息的⼤⼩动态调整Chunk的⼤⼩,从⽽尽量提⾼CPU的利⽤率并减少信息的阻塞机率。

1.3.3 Chunk Format

因为⼀个流当中可以交错传输多种消息类型的Chunk,那么多个Chunk怎么标记同属于同⼀类Message的呢?

  • 通过Chunk Stream ID区分的,同⼀个Chunk Stream ID必然属于同⼀个Message

Basic Header⾥⾯的chunk stream ID代表了通道,不同的Message 是否有不同的的chunk Stream ID?

  • RTMP流中视频和⾳频拥有单独的Chunk Stream ID,⽐如⾳频的cs id=20,视频的cs id=21。接收端接收到Chunk之后,根据cs id分别将⾳频和视频"拼成消息"
  • 每⼀种消息类型的起始chunk 的类型必须是 Type_0 类型的,表明我是⼀个新的消息的起始
1.3.3.1 Basic Header
  • 包含了chunk stream ID(流通道Id)和chunk type(chunk的类型),chunk stream id⼀般被简写为CSID,⽤来唯⼀标识⼀个特定的流通道,chunk type决定了后⾯Message Header的格式。

  • BasicHeader的⻓度可能是1,2,或3个字节,其中chunk type的⻓度是固定的(占2位,注意单位是位,bit),Basic Header是变⻓的,其⻓度取决于CSID的⼤⼩,在⾜够存储这两个字段的前提下最好⽤尽量少的字节从⽽减少由于引⼊Header增加的数据量。

  • RTMP协议最多⽀持65597个⽤户⾃定义chunk stream ID,范围为[3,65599] ,ID 0, 1, 2被协议规范直接使⽤,其中ID值为0, 1分表表示了Basic Header占⽤2个字节和3个字节:

    • ID值0:代表Basic Header占⽤2个字节,CSID在 [64,319] 之间;
    • ID值1:代表Basic Header占⽤3个字节,CSID在 [64,65599] 之间;
    • ID值2:代表该chunk是控制信息和⼀些命令信息,后⾯会有详细的介绍。

当Basic Header为1个字节时,CSID占6位,6位最多可以表示64个数,因此这种情况下CSID在 [0,63] 之间,其中⽤户可⾃定义的范围为 [3,63] ,实际是可以⽤2开始⽤?

  • 当Basic Header为2个字节时,CSID占只占8位,第⼀个字节除chunk type占⽤的bit都置为0,第⼆个字节⽤来示CSID-64,8位可以表示 [0, 255] 共256个数,ID的计算⽅法为(第⼆个字节+64),范围为 [64,319]
  • 当Basic Header为3个字节时,以在此字段⽤3字节版本编码。ID的计算⽅法为(第三字节*256+第⼆字节+64)(Basic Header是采⽤⼩端存储的⽅式),范围为 [64,65599]
1.3.3.2 Message Header
  • 包含了要发送的实际信息(可能是完整的,也可能是⼀部分)的描述信息。
  • Message Header的格式和⻓度取决于Basic Header的chunk type,共有4种不同的格式,由上⾯所提到的Basic Header中的fmt字段控制。
  • 其中第⼀种格式可以表示其他三种表示的所有数据,但由于其他三种格式是基于对之前chunk的差量化的表示,因此可以更简洁地表示相同的数据,实际使⽤的时候还是应该采⽤尽量少的字节表示相同意义的数据。以下按照字节数从多到少的顺序分别介绍这4种格式的Message Header
Type=0: 占⽤11个字节

type=0时Message Header占⽤11个字节,其他三种能表示的数据它都能表示,但在chunk stream的开始的第⼀个chunk和头信息中的时间戳后退(即值与上⼀个chunk相⽐减⼩,通常在回退播放的时候会出现这种情况)的时候必须采⽤这种格式。

  • timestamp(时间戳):占⽤3个字节,因此它最多能表示到16777215=0xFFFFFF=2-1, 当它的值超过这个最⼤值时,这三个字节都置为1,这样实际的timestamp会转存到Extended Timestamp字段中,接受端在判断timestamp字段24个位都为1时就会去Extended timestamp中解析实际的时间戳

  • message length(消息数据的⻓度):占⽤3个字节,表示实际发送的消息的数据如⾳频帧、视频帧等数据的⻓度,单位是字节。注意这⾥是Message的⻓度,也就是chunk属于的Message的总数据⻓度,⽽不是chunk本身Data的数据的⻓度。

  • message type id(消息的类型id):占⽤1个字节,表示实际发送的数据的类型,如8代表⾳频数据、9代表视频数据

  • msg stream id(消息的流id):占⽤4个字节,表示该chunk所在的流的ID,和Basic Header的CSID⼀样,它采⽤⼩端存储的⽅式

Type = 1:占⽤7个字节

type=1时Message Header占⽤7个字节,省去了表示msg stream id的4个字节,表示此chunk和上⼀次发的chunk所在的流相同,如果在发送端只和对端有⼀个流链接的时候可以尽量去采取这种格式。

  • timestamp delta:占⽤3个字节,注意这⾥和type=0时不同,存储的是和上⼀个chunk的时间差。
  • 类似上⾯提到的timestamp,当它的值超过3个字节所能表示的最⼤值时,三个字节都置为1,实际的时间戳差值就会转存到Extended Timestamp字段中,接受端在判断timestamp delta字段24个位都为1时就会去Extended timestamp中解析时机的与上次时间戳的差值。
Type = 2:占⽤3个字节

type=2时Message Header占⽤3个字节,相对于type=1格式⼜省去了表示消息⻓度的3个字节和表示消息类型的1个字节,表示此chunk和上⼀次发送的chunk所在的流、消息的⻓度和消息的类型都相同。余下的这三个字节表示timestamp delta,使⽤同type=1。

Type = 3:占⽤0字节
  • 0字节表示这个chunk的Message Header和上⼀个是完全相同的,⾃然就不⽤再传输⼀遍了。当它跟在Type=0的chunk后⾯时,表示和前⼀个chunk的时间戳都是相同的。什么时候连时间戳都相同呢?就是⼀个Message拆分成了多个chunk,这个chunk和上⼀个chunk同属于⼀个Message。

  • ⽽当它跟在Type=1或者Type=2的chunk后⾯时,表示和前⼀个chunk的时间戳的差是相同的。⽐如第⼀个chunk的Type=0,timestamp=100,第⼆个chunk的Type=2,timestamp delta=20,表示时间戳为100+20=120,第三个chunk的Type=3,表示timestamp delta=20,时间戳为120+20=140

4种type对⽐

type 3⽆字段就不画上去了

类型 占用字节 说明
0 11 onMetaData 流刚开始的绝对时间戳 视频帧 流刚开始的绝对时间戳 ⾳频帧 控制消息,如connect
1 7 ⼤多数都是这种类型
2 3 比较少见
3 0 偶尔会出现,频率远远低于type=1
1.3.3.3 Extended Timestamp
  • 上⾯我们提到在chunk中会有时间戳timestamp和时间戳差timestamp delta,并且它们不会同时存在,只有这两者之⼀⼤于3个字节能表示的最⼤数值0xFFFFFF=16777215时,才会⽤这个字段来表示真正的时间戳,否则这个字段为0。扩展时间戳占4个字节,能表示的最⼤数值就是0xFFFFFFFF=4294967295。

  • 当扩展时间戳启⽤时,timestamp字段或者timestamp delta要全置为0xFFFFFF,表示应该去扩展时间戳字段来提取真正的时间戳或者时间戳差。

  • 注意扩展时间戳存储的是完整值,⽽不是减去时间戳或者时间戳差的值

1.3.3.4 Chunk Data

⽤户层⾯上真正想要发送的与协议⽆关的数据,⻓度在(0,chunkSize]之间

1.3.3.5 chunk 表示例1

这个例⼦显示了⼀个简单的⾳频信息流。这个例⼦演示了信息的冗余

  • ⾸先包含第⼀个Message的chunk的Chunk Type为0,因为它没有前⾯可参考的chunk,timestamp为1000,表示时间戳。type为0的header占⽤11个字节,假定chunkstreamId为3<127,因此BasicHeader占⽤1个字节,再加上Data的32个字节,因此第⼀个chunk共44=11+1+32个字节。

  • 第⼆个chunk和第⼀个chunk的CSID,TypeId,Data的⻓度都相同,因此采⽤Chunk Type=2,timestamp delta=1020-1000=20,因此第⼆个chunk占⽤36=3+1+32个字节。

  • 第三个chunk和第⼆个chunk的CSID,TypeId,Data的⻓度和时间戳差都相同,因此采⽤Chunk Type=3省去全部Message Header的信息,占⽤33=1+32个字节。

  • 第四个chunk和第三个chunk情况相同,也占⽤33=1+32个字节。

最后实际发送的chunk如下:

1.3.3.5 chunk 表示例2

此示例说明了⼀个消息因为太⻓,以⾄于⽆法适⽤⼀个128字节的chunk,从⽽被分解成多个chunk。

  • 注意到Data的Length=307>128,因此这个Message要切分成⼏个chunk发送,第⼀个chunk的Type=0,Timestamp=1000,承担128个字节的Data,因此共占⽤140=11+1+128个字节。

  • 第⼆个chunk也要发送128个字节,其他字段也同第⼀个chunk,因此采⽤Chunk Type=3,此时时间

    戳也为1000,共占⽤129=1+128个字节。

  • 第三个chunk要发送的Data的⻓度为307-128-128=51个字节,还是采⽤Type=3,共占⽤1+51=52

    个字节。

最后实际发送的chunk如下:

从两个例⼦中注意到,类型3的chunk可以⽤在两种不同的⽅式中。第⼀种是指定消息的继续。第⼆种是指定⼀个新的消息的开始,它的头可以来⾃于现有的状态数据。

1.4 协议控制消息(Protocol Control Message)

在RTMP的chunk流会⽤⼀些特殊的值来代表协议的控制消息,它们的Message Stream ID必须为0(代表控制流信息),CSID必须为2,Message Type ID可以为1,2,3,5,6,具体代表的消息会在下⾯依次说明。控制消息的接受端会忽略掉chunk中的时间戳,收到后⽴即⽣效。

Set Chunk Size(ID=1)

  • Set Chunk Size(Message Type ID=1):设置chunk中Data字段所能承载的最⼤字节数,默认为128B,通信过程中可以通过发送该消息来设置chunk Size的⼤⼩(不得⼩于128B),⽽且通信双⽅会各⾃维护⼀个chunkSize,两端的chunkSize是独⽴的。

  • ⽐如当A想向B发送⼀个200B的Message,但默认的chunkSize是128B,因此就要将该消息拆分为Data分别为128B和72B的两个chunk发送,如果此时先发送⼀个设置chunkSize为256B的消息,再发送Data为200B的chunk,本地不再划分Message,B接受到Set Chunk Size的协议控制消息时会调整的接受的chunk的Data的⼤⼩,也不⽤再将两个chunk组成为⼀个Message。

在实际写代码的时候⼀般会把chunk size设置的很⼤,有的会设置为4096,FFMPEG推流的时候设置的是 60*1000,这样设置的好处是避免了频繁的拆包组包,占⽤过多的CPU。

以下为代表Set Chunk Size消息的chunk的Data

其中第⼀位必须为0,chunk Size占31个位,最⼤可代表2147483647=0x7FFFFFFF=2^31-1,但实际

所有⼤于16777215=0xFFFFFF的值都⽤不上,因为chunk size不能⼤于Message的⻓度,表示Message的⻓度字段是⽤3个字节表示的,最⼤只能为0xFFFFFF

Abort Message (ID=2)

  • 当⼀个Message被切分为多个chunk,接受端只接收到了部分chunk时,发送该控制消息表示发送端不再传输同Message的chunk,接受端接收到这个消息后要丢弃这些不完整的chunk。

  • Data数据中只需要⼀个CSID,表示丢弃该CSID的所有已接收到的chunk。

Acknowledgement (ID=3)和Window Acknowledgement Size (ID=5)

  • Window Acknowledgement Size⽤于设置窗⼝确认⼤⼩,Acknowledgement是窗⼝确认消息

  • 会话开始时,双⽅都要先对端发送Window Acknowledgement Size,⽤于指明期望获得确认的⼤⼩。当⼀端收到内容⼤⼩超过Window Acknowledgement Size,就要像对⽅发送Acknowledgement。

  1. 会话开始计算收到byte个数的时间点是收到Window Acknowledgement Size消息开始。
  2. byte size不包括tcp包头,应该是chunk的⼤⼩,即从tcp 的recv函数中获得的内容⼤⼩。
  3. 双⽅都要向对⽅发送Window Acknowledgement Size和Acknowledgement。
  4. 发送端发送完Window Acknowledgement Size消息后,没有收到Acknowledgement是不再发送进⼀步的消息的------这样会容易引起错误,导致再也发送不出消息了。

对于拉流端,⼀般在收到av_createStream后,接着play,然后发送Acknowledgement 以让服务器继续发送数据。

Set Peer Bandwidth (ID=6)

  • 限制对端的输出带宽。接受端接收到该消息后会通过设置消息中的Window ACK Size来限制已发送但未接受到反馈的消息的⼤⼩来限制发送端的发送带宽。如果消息中的Window ACK Size与上⼀次发送给发送端的size不同的话要回馈⼀个WindowAcknowledgement Size的控制消息。
  • Hard(Limit Type=0):接受端应该将Window Ack Size设置为消息中的值

  • Soft(Limit Type=1):接受端可以讲Window Ack Size设为消息中的值,也可以保存原来的值(前提是原来的Size⼩与该控制消息中的Window Ack Size)

  • Dynamic(Limit Type=2):如果上次的Set Peer Bandwidth消息中的Limit Type为0,本次也按Hard处理,否则忽略本消息,不去设置Window Ack Size。

1.5 不同类型的RTMP Message

Command Message(命令消息,Message Type ID=17或20)

  • 实际使⽤时只是使⽤了ID=20,发送端发送时会带有命令的名字,如connect,TransactionID表示此次命令的标识,Command Object表示相关参数。

  • 接受端收到命令后,会返回以下三种消息中的⼀种:_result消息表示接受该命令,对端可以继续往下执⾏流程,_error消息代表拒绝该命令要执⾏的操作,methodname消息代表要在之前命令的发送端执⾏的函数名称。这三种回应的消息都要带有收到的命令消息中的TransactionId来表示本次的回应作⽤于哪个命令。

  • 可以认为发送命令消息的对象有两种,⼀种是NetConnection,表示双端的上层连接,⼀种是NetStream,表示流信息的传输通道,控制流信息的状态,如Play播放流,Pause暂停

NetConnection Commands(连接层的命令)

用来管理双端之间的连接状态,同时也提供了异步远程⽅法调⽤(RPC)在对端执⾏某⽅法,以下是常⻅的连接层的命令:

connect:⽤于客户端向服务器发送连接请求
  • 握手之后先发送⼀个connect 命令消息,这些信息是以AMF格式发送的,消息的结构如下:
  • 第三个字段中的Command Object中会涉及到很多键值对,使⽤时可以参考协议的官⽅⽂档
字段 类型 说明
Command Name(命令名字) String 命令的名字,如"connect"
Transaction ID(事务ID) Number 恒为1
Command Object(命令包含的参数对象) Object 键值对集合表示的命令参数
Optional User Arguments(额外的用户参数) Object 用户自定义的额外信息
  • 消息的回应有两种,_result表示接受连接,_error表示连接失败。
  • 以下是连接命令对象中使⽤的名称-值对的描述:
属性 类型 描述 范例
app 字符串 客户端连接到的服务器端应用的名字。 testapp
flashver 字符串 Flash Player 版本号。和 ApplicationScript getversion() 方法返回的是同一个字符串。 FMSc/1.0
swfUrl 字符串 进行当前连接的 SWF 文件源地址。 file:///C:/FlvPlayer.swf
tcUrl 字符串 服务器 URL。具有以下格式:protocol://servername:port/appName/appInstance rtmp://localhost:1935/testapp/instance1
fpad 布尔 如果使用了代理就是 true。 true 或者 false。
audioCodecs 数字 表明客户端所支持的音频编码。 SUPPORT_SND_MP3
videoCodecs 数字 表明支持的视频编码。 SUPPORT_VID_SORENSON
videoFunction 数字 表明所支持的特殊视频方法。 SUPPORT_VID_CLIENT_SEEK
pageUrl 字符串 SWF 文件所加载的网页 URL。 http://somehost/sample.html
objectEncoding 数字 AMF 编码方法。 AMF3
Call
  • ⽤于在对端执⾏某函数,即常说的RPC:远程进程调⽤,消息的结构如下:
字段 类型 说明
Procedure Name(进程名) String 要调用的进程名称
Transaction ID Number|如果想要对端响应的话置为非0值,否则置为0
Command Object Object 命令参数
Optional Arguents Object 用户自定义参数
如果消息中的TransactionID不为0的话,对端需要对该命令做出响应,响应的消息结构如下
字段 类型 说明
Command Name(命令名) String 命令的名称
TransactionID Number 上面接收到的命令消息中的 TransactionID
Command Object Object 命令参数
Optional Arguments Object 用户自定义参数
Create Stream:
  • 创建传递具体信息的通道,从⽽可以在这个流中传递具体信息,传输信息单元为Chunk。
  • 当发送完createStream消息之后,解析服务器返回的消息会得到⼀个stream ID, 这个ID也就是以后和服务器通信的 message stream ID, ⼀般返回的是1,不固定。
字段 类型 说明
Command Name(命令名) String "createStream"
TransactionID Number 上面接收到的命令消息中的 TransactionID
Command Object Object 命令参数
Optional Arguments Object 用户自定义参数

NetStream Commands(流连接上的命令)

  • Netstream建⽴在NetConnection之上,通过NetConnection的createStream命令创建,⽤于传输具体的⾳频、视频等信息。在传输层协议之上只能连接⼀个NetConnection,但⼀个NetConnection可以建⽴多个NetStream来建⽴不同的流通道传输数据。

  • 以下会列出⼀些常⽤的NetStream Commands,服务端收到命令后会通过onStatus的命令来响应客户端,表示当前NetStream的状态。

onStatus命令的消息结构如下:

play(播放)
  • 由客户端向服务器发起请求从服务器端接受数据(如果传输的信息是视频的话就是请求开始播流),可以多次调⽤,这样本地就会形成⼀组数据流的接收者。注意其中有⼀个reset字段,表示是覆盖之前的播流(设为true)还是重新开始⼀路播放(设为false)

play命令的结构如下:

字段 类型 说明
命令名 String "play"
事务ID Number 恒为0
命令参数对象 Null 不需要此字段,设为空
流名称 String 要播放的流的名称
开始位置 Number 可选参数,表示从何时开始播流,以秒为单位。默认为 -2,代表选取对应该流名称的直播流,即当前正在推送的流开始播放,如果对应该名称的直播流不存在,就选取该名称的流的录播版本,如果这也没有,当前播流端要等待直到对端开始该名称的流的直播。如果传值 -1,那么只会选取直播流进行播放,即使有录播流也不会播放;如果传值或者正数,就代表从该流的该时间点开始播放,如果流不存在的话就会自动播放播放列表中的下一个流
周期 Number 可选参数,表示回退的最小间隔单位,以秒为单位计数。默认为 -1,代表直到直播流不再可用或者录播流停止后才能回退播放;如果传值为0,代表从当前帧开始播放
重置 Boolean 可选参数,true代表清除之前的流,重新开始一路播放,false代表保留原来的流,向本地的播放列表中再添加一条播放流
play2(播放)
  • 和上⾯的play命令不同的是,play2命令可以将当前正在播放的流切换到同样数据但不同⽐特率的流上,服务器端会维护多种⽐特率的⽂件来供客户端使⽤play2命令来切换。
字段 类型 说明
Command Name String "play2"
TransactionID Number 恒为0
Command Object NULL,对onStatus命令来说不需要这个字段
parameters Object AMF编码的Flash对象,包括了一些用于描述flash.net.NetstreamPlayOptions ActionScript object的参数
deleteStream(删除流)
  • ⽤于客户端告知服务器端本地的某个流对象已被删除,不需要再传输此路流。
字段 类型 说明
Command Name String "deleteStream"
TransactionID Number 恒为0
Command Object NULL,对onStatus命令来说不需要这个字段
Stream ID(流ID) Number 本地已删除,不再需要服务器传输的流的ID
receiveAudio(接收⾳频)
  • 通知服务器端该客户端是否要发送⾳频

receiveAudio命令结构如下

字段 类型 说明
Command Name String "receiveAudio"
TransactionID Number 恒为0
Command Object NULL 对onStatus命令来说不需要这个字段
Bool Flag Boolean true表示发送音频,如果该值为false,服务器端不做响应,如果为true的话,服务器端就会准备接受音频数据,会向客户端回复NetStream.Seek.Notify和NetStream.Play.Start的Onstatus命令告知客户端当前流的状态
publish(推送数据)
  • 由客户端向服务器发起请求推流到服务器

publish命令结构如下:

字段 类型 说明
Command Name String "publish"
TransactionID Number 恒为 0
Command Object NULL,对 onStatus 命令来说不需要这个字段
Publishing Name(推流的名称) String 流名称
Publishing Type(推流类型) String "live"、"record"、"append" 中的一种。live 表示该推流文件不会在服务器端存储;record 表示该推流的文件会在服务器应用程序下的子目录下保存以便后续播放,如果文件已经存在的话删除原来所有的内容重新写入;append 也会将推流数据保存在服务器端,如果文件不存在的话就会建立一个新文件写入,如果对应该流的文件已经存在的话保存原来的数据,在文件末尾接着写入
seek(定位流的位置)
  • 定位到视频或⾳频的某个位置,以毫秒为单位。

seek命令的结构如下:

这是RTMP协议中seek命令的字段说明,以下是转换后的Markdown表格:

字段 类型 说明
Command Name String "seek"
TransactionID Number 恒为0
Command Object NULL,对onStatus命令来说不需要这个字段
milliSeconds Number 定位到该文件的xx毫秒处
pause(暂停)
  • 客户端告知服务端停⽌或恢复播放

  • 如果Pause为true即表示客户端请求暂停的话,服务端暂停对应的流会返回NetStream.Pause.Notify的onStatus命令来告知客户端当前流处于暂停的状态,当Pause为false时,服务端会返回NetStream.Unpause.Notify的命令来告知客户端当前流恢复。如果服务端对该命令响应失败,返回_error信息。

pause命令的结构如下:

字段 类型 说明
Command Name String "pause"
TransactionID Number 恒为 0
Command Object NULL,对 onStatus 命令来说不需要这个字段
Pause/Unpause Flag Boolean true 表示暂停,false 表示恢复
milliSeconds Number 暂停或者恢复的时间,以毫秒为单位

更多资料:https://github.com/0voice

相关推荐
漫游者Nova2 小时前
AI视频加字幕翻译配音软件VideoLingo 3.0版整合包
人工智能·音视频·视频翻译·视频配音·视频加字幕
Blossom.1187 小时前
基于深度学习的智能视频行为识别系统:技术与实践
人工智能·深度学习·神经网络·目标检测·机器学习·音视频·sklearn
aqi008 小时前
FFmpeg开发笔记(六十七)Windows给FFmpeg集成支持RIST协议的librist
ffmpeg·音视频·直播·流媒体
CaptainHailong9 小时前
ffmpeg 给视频画圆圈
ffmpeg·音视频
wkd_0079 小时前
【音视频 | RTP】RTP协议详解(H.264的RTP封包格式、AAC的RTP封包格式)
音视频·aac·h.264·rtp·rtp封包
Niuguangshuo14 小时前
如何正确处理音频数据:16位整数与32位浮点数
音视频
iphone1081 天前
单视频二维码生成与列表二维码生成(完整版)
音视频·视频转二维码·视频二维码·视频生成二维码
胖虎11 天前
(十六)深入了解 AVFoundation - 编辑:音视频裁剪与拼接的Demo项目实现
音视频·音视频编辑·音视频裁剪·音视频拼接
苗杨1 天前
【Faster-Whisper】离线识别本地视频并生成字幕
python·whisper·音视频