精华内容
下载资源
问答
  • RTMP详解

    千次阅读 2016-08-03 23:18:33
    RTMP协议是Real Time Message Protocol(实时信息传输协议)的缩写,它是由Adobe公司提出的一种应用层的协议,用来解决多媒体数据传输流的多路复用(Multiplexing)和分包(packetizing)的问题。随着VR技术的发展,...

    转自:http://mingyangshang.github.io/2016/03/06/RTMP%E5%8D%8F%E8%AE%AE/

    RTMP协议是Real Time Message Protocol(实时信息传输协议)的缩写,它是由Adobe公司提出的一种应用层的协议,用来解决多媒体数据传输流的多路复用(Multiplexing)和分包(packetizing)的问题。随着VR技术的发展,视频直播等领域逐渐活跃起来,RTMP作为业内广泛使用的协议也重新被相关开发者重视起来。正好最近在从事这方面的工作,在此记录下自己对RTMP的理解,文章内容多翻译自英文版RTMP文档,按照本人的理解重新整理,希望可以帮助想要了解RTMP协议的朋友,也方面自己日后查阅。


    1. 总体介绍:
    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,从而实现信息的收发。
    2. 握手
    要建立一个有效的RTMP Connection链接,首先要“ 握手 ”:客户端要向服务器发送C0,C1,C2(按序)三个chunk,服务器向客户端发送S0,S1,S2(按序)三个chunk,然后才能进行有效的信息传输。RTMP协议本身并没有规定这6个Message的具体传输顺序,但RTMP协议的实现者需要保证这几点:
    - 客户端要等收到S1之后才能发送C2
    - 客户端要等收到S2之后才能发送其他信息(控制信息和真实音视频等数据)
    - 服务端要等到收到C0之后发送S1
    - 服务端必须等到收到C1之后才能发送S2
    - 服务端必须等到收到C2之后才能发送其他信息(控制信息和真实音视频等数据)
    如果每次发送一个握手chunk的话握手顺序会是这样:



    理论上来讲只要满足以上条件,如何安排6个Message的顺序都是可以的,但实际实现中为了在保证握手的身份验证功能的基础上尽量减少通信的次数,一般的发送顺序是这样的,这一点可以通过wireshark抓ffmpeg推流包进行验证:
    |client|Server |
    |---C0+C1—->|
    |<--S0+S1+S2– |
    |---C2----> |

    3. RTMP Chunk Stream

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

    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个字节,并且以小端格式存储

      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的控制信息可以设置Chunk数据量的最大值,在发送端和接受端会各自维护一个Chunk Size,可以分别设置这个值来改变自己这一方发送的Chunk的最大大小。大一点的Chunk减少了计算每个chunk的时间从而减少了CPU的占用率,但是它会占用更多的时间在发送上,尤其是在低带宽的网络情况下,很可能会阻塞后面更重要信息的传输。小一点的Chunk可以减少这种阻塞问题,但小的Chunk会引入过多额外的信息(Chunk中的Header),少量多次的传输也可能会造成发送的间断导致不能充分利用高带宽的优势,因此并不适合在高比特率的流中传输。在实际发送时应对要发送的数据用不同的Chunk Size去尝试,通过抓包分析等手段得出合适的Chunk大小,并且在传输过程中可以根据当前的带宽信息和实际信息的大小动态调整Chunk的大小,从而尽量提高CPU的利用率并减少信息的阻塞机率。
      3.3 Chunk Format(块格式)

      3.3.1 Basic Header(基本的头信息):
      包含了chunk stream ID(流通道Id)和chunk type(chunk的类型),chunk stream id一般被简写为CSID,用来唯一标识一个特定的流通道,chunk type决定了后面Message Header的格式。Basic Header的长度可能是1,2,或3个字节,其中chunk type的长度是固定的(占2位,注意单位是位,bit),Basic Header的长度取决于CSID的大小,在足够存储这两个字段的前提下最好用尽量少的字节从而减少由于引入Header增加的数据量。
      RTMP协议支持用户自定义[3,65599]之间的CSID,0,1,2由协议保留表示特殊信息。0代表Basic Header总共要占用2个字节,CSID在[64,319]之间,1代表占用3个字节,CSID在[64,65599]之间,2代表该chunk是控制信息和一些命令信息,后面会有详细的介绍。
      chunk type的长度固定为2位,因此CSID的长度是(6=8-2)、(14=16-2)、(22=24-2)中的一个。
      当Basic Header为1个字节时,CSID占6位,6位最多可以表示64个数,因此这种情况下CSID在[0,63]之间,其中用户可自定义的范围为[3,63]。

      当Basic Header为2个字节时,CSID占14位,此时协议将与chunk type所在字节的其他位都置为0,剩下的一个字节来表示CSID-64,这样共有8个字节来存储CSID,8位可以表示[0,255]共256个数,因此这种情况下CSID在[64,319],其中319=255+64。

      当Basic Header为3个字节时,CSID占22位,此时协议将[2,8]字节置为1,余下的16个字节表示CSID-64,这样共有16个位来存储CSID,16位可以表示[0,65535]共65536个数,因此这种情况下CSID在[64,65599],其中65599=65535+64,需要注意的是,Basic Header是采用小端存储的方式,越往后的字节数量级越高,因此通过这3个字节每一位的值来计算CSID时,应该是:<第三个字节的值>x256+<第二个字节的值>+64

      可以看到2个字节和3个字节的Basic Header所能表示的CSID是有交集的[64,319],但实际实现时还是应该秉着最少字节的原则使用2个字节的表示方式来表示[64,319]的CSID。

      3.3.2 Message Header(消息的头信息)
      包含了要发送的实际信息(可能是完整的,也可能是一部分)的描述信息。Message Header的格式和长度取决于Basic Header的chunk type,共有4种不同的格式,由上面所提到的Basic Header中的fmt字段控制。其中第一种格式可以表示其他三种表示的所有数据,但由于其他三种格式是基于对之前chunk的差量化的表示,因此可以更简洁地表示相同的数据,实际使用的时候还是应该采用尽量少的字节表示相同意义的数据。以下按照字节数从多到少的顺序分别介绍这4种格式的Message Header。
      Type=0:

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

      • timestamp(时间戳):占用3个字节,因此它最多能表示到18777215=0xFFFFFF=2
        24-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:

        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:

        type=2时Message Header占用3个字节,相对于type=1格式又省去了表示消息长度的3个字节和表示消息类型的1个字节,表示此chunk和上一次发送的chunk所在的流、消息的长度和消息的类型都相同。余下的这三个字节表示timestamp delta,使用同type=1
        Type = 3
        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
        3.3.3 Extended Timestamp(扩展时间戳)
        上面我们提到在chunk中会有时间戳timestamp和时间戳差timestamp delta,并且它们不会同时存在,只有这两者之一大于3个字节能表示的最大数值0xFFFFFF=16777215时,才会用这个字段来表示真正的时间戳,否则这个字段为0。扩展时间戳占4个字节,能表示的最大数值就是0xFFFFFFFF=4294967295。当扩展时间戳启用时,timestamp字段或者timestamp delta要全置为1,表示应该去扩展时间戳字段来提取真正的时间戳或者时间戳差。注意扩展时间戳存储的是完整值,而不是减去时间戳或者时间戳差的值。
        3.3.4 Chunk Data(块数据)
        用户层面上真正想要发送的与协议无关的数据,长度在(0,chunkSize]之间。
        3.3.5 chunk表示例1

        首先包含第一个Message的chunk的Chunk Type为0,因为它没有前面可参考的chunk,timestamp为1000,表示时间戳。type为0的header占用11个字节,假定chunkstreamId为3<127,因此Basic Header占用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如下:

        3.3.6 chunk表示例2

        注意到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.4 协议控制消息(Protocol Control Message)
        在RTMP的chunk流会用一些特殊的值来代表协议的控制消息,它们的Message Stream ID必须为0(代表控制流信息),CSID必须为2,Message Type ID可以为1,2,3,5,6,具体代表的消息会在下面依次说明。控制消息的接受端会忽略掉chunk中的时间戳,收到后立即生效。

        • 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。
          以下为代表Set Chunk Size消息的chunk的Data:

          其中第一位必须为0,chunk Size占31个位,最大可代表2147483647=0x7FFFFFFF=231-1,但实际上所有大于16777215=0xFFFFFF的值都用不上,因为chunk size不能大于Message的长度,表示Message的长度字段是用3个字节表示的,最大只能为0xFFFFFF。
        • Abort Message(Message Type ID=2):当一个Message被切分为多个chunk,接受端只接收到了部分chunk时,发送该控制消息表示发送端不再传输同Message的chunk,接受端接收到这个消息后要丢弃这些不完整的chunk。Data数据中只需要一个CSID,表示丢弃该CSID的所有已接收到的chunk。
        • Acknowledgement(Message Type ID=3):当收到对端的消息大小等于窗口大小(Window Size)时接受端要回馈一个ACK给发送端告知对方可以继续发送数据。窗口大小就是指收到接受端返回的ACK前最多可以发送的字节数量,返回的ACK中会带有从发送上一个ACK后接收到的字节数。
        • Window Acknowledgement Size(Message Type ID=5):发送端在接收到接受端返回的两个ACK间最多可以发送的字节数。
        • Set Peer Bandwidth(Message Type ID=6):限制对端的输出带宽。接受端接收到该消息后会通过设置消息中的Window ACK Size来限制已发送但未接受到反馈的消息的大小来限制发送端的发送带宽。如果消息中的Window ACK Size与上一次发送给发送端的size不同的话要回馈一个Window Acknowledgement 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。

    4. 不同类型的RTMP Message

    • Command Message(命令消息,Message Type ID=17或20):表示在客户端盒服务器间传递的在对端执行某些操作的命令消息,如connect表示连接对端,对端如果同意连接的话会记录发送端信息并返回连接成功消息,publish表示开始向对方推流,接受端接到命令后准备好接受对端发送的流信息,后面会对比较常见的Command Message具体介绍。当信息使用AMF0编码时,Message Type ID=20,AMF3编码时Message Type ID=17.
    • Data Message(数据消息,Message Type ID=15或18):传递一些元数据(MetaData,比如视频名,分辨率等等)或者用户自定义的一些消息。当信息使用AMF0编码时,Message Type ID=18,AMF3编码时Message Type ID=15.
    • Shared Object Message(共享消息,Message Type ID=16或19):表示一个Flash类型的对象,由键值对的集合组成,用于多客户端,多实例时使用。当信息使用AMF0编码时,Message Type ID=19,AMF3编码时Message Type ID=16.
    • Audio Message(音频信息,Message Type ID=8):音频数据。
    • Video Message(视频信息,Message Type ID=9):视频数据。
    • Aggregate Message (聚集信息,Message Type ID=22):多个RTMP子消息的集合
    • User Control Message Events(用户控制消息,Message Type ID=4):告知对方执行该信息中包含的用户控制事件,比如Stream Begin事件告知对方流信息开始传输。和前面提到的协议控制信息(Protocol Control Message)不同,这是在RTMP协议层的,而不是在RTMP chunk流协议层的,这个很容易弄混。该信息在chunk流中发送时,Message Stream ID=0,Chunk Stream Id=2,Message Type Id=4。
      ———下面对以上7种信息具体介绍———-
      4.1 Command Message(命令消息,Message Type ID=17或20)
      发送端发送时会带有命令的名字,如connect,TransactionID表示此次命令的标识,Command Object表示相关参数。接受端收到命令后,会返回以下三种消息中的一种:_result 消息表示接受该命令,对端可以继续往下执行流程,_error消息代表拒绝该命令要执行的操作,method name消息代表要在之前命令的发送端执行的函数名称。这三种回应的消息都要带有收到的命令消息中的TransactionId来表示本次的回应作用于哪个命令。
      可以认为发送命令消息的对象有两种,一种是NetConnection,表示双端的上层连接,一种是NetStream,表示流信息的传输通道,控制流信息的状态,如Play播放流,Pause暂停。
      4.1.1 NetConnection Commands(连接层的命令)
      用来管理双端之间的连接状态,同时也提供了异步远程方法调用(RPC)在对端执行某方法,以下是常见的连接层的命令:
      4.1.1.1 connect:用于客户端向服务器发送连接请求,消息的结构如下:
    字段 类型 说明
    Command Name(命令名字) String 命令的名字,如”connect”
    Transaction ID(事务ID) Number 恒为1
    Command Object(命令包含的参数对象) Object 键值对集合表示的命令参数
    Optional User Arguments(额外的用户参数) Object 用户自定义的额外信息

    第三个字段中的Command Object中会涉及到很多键值对,这里不再一一列出,使用时可以参考协议的官方文档。
    消息的回应有两种,_result表示接受连接,_error表示连接失败

    4.1.1.2 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 用户自定义参数

    4.1.1.3 Create Stream:创建传递具体信息的通道,从而可以在这个流中传递具体信息,传输信息单元为Chunk。

    字段 类型 说明
    Command Name(命令名) String “createStream”
    TransactionID Number 上面接收到的命令消息中的TransactionID
    Command Object Object 命令参数
    Optional Arguments Object 用户自定义参数

    4.1.2 NetStream Commands(流连接上的命令)

    Netstream建立在NetConnection之上,通过NetConnection的createStream命令创建,用于传输具体的音频、视频等信息。在传输层协议之上只能连接一个NetConnection,但一个NetConnection可以建立多个NetStream来建立不同的流通道传输数据。
    以下会列出一些常用的NetStream Commands,服务端收到命令后会通过onStatus的命令来响应客户端,表示当前NetStream的状态。
    onStatus命令的消息结构如下:

    字段 类型 说明
    Command Name String “onStatus”
    TransactionID Number 恒为0
    Command Object NULL 对onSatus命令来说不需要这个字段
    Info Object Object AMF类型的Object,至少包含以下三个属性:1,“level”,String类型,可以为“warning”、”status”、”error”中的一种;2,”code”,String类型,代表具体状态的关键字,比如”NetStream.Play.Start”表示开始播流;3,”description”,String类型,代表对当前状态的描述,提供对当前状态可读性更好的解释,除了这三种必要信息,用户还可以自己增加自定义的键值对

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

    字段 类型 说明
    命令名 String “play”
    事务ID Number 恒为0
    命令参数对象 Null 不需要此字段,设为空
    流名称 String 要播放的流的名称
    开始位置 Number 可选参数,表示从何时开始播流,以秒为单位。默认为-2,代表选取对应该流名称的直播流,即当前正在推送的流开始播放,如果对应该名称的直播流不存在,就选取该名称的流的录播版本,如果这也没有,当前播流端要等待直到对端开始该名称的流的直播。如果传值-1,那么只会选取直播流进行播放,即使有录播流也不会播放;如果传值或者正数,就代表从该流的该时间点开始播放,如果流不存在的话就会自动播放播放列表中的下一个流
    周期 Number 可选参数,表示回退的最小间隔单位,以秒为单位计数。默认值为-1,代表直到直播流不再可用或者录播流停止后才能回退播放;如果传值为0,代表从当前帧开始播放
    重置 Boolean 可选参数,true代表清除之前的流,重新开始一路播放,false代表保留原来的流,向本地的播放列表中再添加一条播放流

    4.1.2.2 play2(播放):和上面的play命令不同的是,play2命令可以将当前正在播放的流切换到同样数据但不同比特率的流上,服务器端会维护多种比特率的文件来供客户端使用play2命令来切换。

    字段 类型 说明
    Command Name String “play2”
    TransactionID Number 恒为0
    Command Object NULL,对onSatus命令来说不需要这个字段
    parameters Object AMF编码的Flash对象,包括了一些用于描述flash.net.NetstreamPlayOptions ActionScript obejct的参数

    4.1.2.3 deleteStream(删除流):用于客户端告知服务器端本地的某个流对象已被删除,不需要再传输此路流。

    字段 类型 说明
    Command Name String “deleteStream”
    TransactionID Number 恒为0
    Command Object NULL,对onSatus命令来说不需要这个字段
    Stream ID(流ID) Number 本地已删除,不再需要服务器传输的流的ID

    4.1.2.4 receiveAudio(接收音频):通知服务器端该客户端是否要发送音频
    receiveAudio命令结构如下:

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

    4.1.2.5 receiveVideo(接收视频):通知服务器端该客户端是否要发送视频
    receiveVideo命令结构如下:

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

    4.1.2.6 publish(推送数据):由客户端向服务器发起请求推流到服务器。
    publish命令结构如下:

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

    4.1.2.7 seek(定位流的位置):定位到视频或音频的某个位置,以毫秒为单位。
    seek命令的结构如下:

    字段 类型 说明
    Command Name String “seek”
    TransactionID Number 恒为0
    Command Object NULL,对onSatus命令来说不需要这个字段
    milliSeconds Number 定位到该文件的xx毫秒处|

    4.1.2.8 pause(暂停):客户端告知服务端停止或恢复播放。
    pause命令的结构如下:

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

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

    5. 代表流程
    5.1 推流流程


    5.2 播流流程


    6. 新手建议

    如果读者仔细读完了上面讲的RTMP协议,想必会觉得RTMP协议非常繁琐,事实也确实是这样,RTMP协议中充斥着很多冗余的字段,比如三次握手中的时间戳的校对,还有一些特殊的命令,如FCPublish、UnFCPublish等,但在实际实现中为了保证更大兼容性通常还是要处理这些看似多余的命令。加上Adobe对RTMP协议的实现细节有些并没有按照协议来或者协议中没有写清楚自己搞了一套实现,其他应用开发时还要兼容Adobe错误的实现,从而使的RTMP也一直为开发者所诟病。但不管怎样,RTMP确实提供了一种能够全面并且实现简单的协议来保证流信息的传输,这方面暂时还没有一种更完善更简洁的协议能够取代它在视频流开发中的地位。
    新人一开始接触RTMP的时候肯定会觉得头大,这也是RTMP协议不简洁的后果。建议读者在学习时先过一遍协议理解大概的概念和流程,然后对照wireshark抓的包,和协议进行比对,这样将理论和实践结合,应该会理解的更快一点。

    展开全文
  • 根据各种估计,使用RTMP进行广播,通过完整的编码路径(RTMP编码器→RTMP服务器→RTMP客户端)的延迟至少是两秒。 CMAF CMAF(Common Media Application Format,通用媒体应用格式)是由苹果和微软邀请MPEG开发的...

    点击上方“LiveVideoStack”关注我们

    作者 | Vitaly Suturikhin

    翻译 | 徐鋆

    低广播延迟已经成为任何关于建设源端站和CDN的招标和竞争中的必要特性。以前这种标准只适用于体育广播,但现在运营商要求每个领域的广播设备供应商提供低延迟,比如:广播新闻、音乐会、表演、采访、谈话节目、辩论、电子竞技等等。

    什么是低延迟?

    一般来说,延迟是指某一特定视频帧被设备(摄像机、播放机、编码器等)捕获的时间与该帧在终端用户显示器上播放的时间之间的时间差。

    什么是低延迟视频流?

    低延迟不应降低信号传输的质量,这意味着在编码和复用时使用最小的缓冲,同时在任何设备的屏幕上需要保持流畅和清晰的画面。另一个先决条件是保证传输:所有丢失的数据包都应该被恢复,以及在开放网络上的传输不应该引起任何问题。

    越来越多的服务正在迁移到云端,以节省租用的场地、电力和硬件成本。这增加了对高RTT(Round Trip Time, 往返时间)下低延迟的要求。在播放高清和超清视频时,传输高比特率的情况尤其如此。比如如果云服务器位于美国,而内容消费者在欧洲的情况。

    在这篇文章中,我们将分析目前市场上在低延迟广播方面提供的方案。

         UDP

    在现代电视广播中被广泛使用并与 "低延迟 "一词相关的第一项技术可能是通过UDP的MPEG TS流内容进行的组播。通常情况下,这种格式适合封闭的无负载网络,在这种情况下,丢包率是最小的。例如,从编码器到源端站调制器的广播(通常在同一个服务器机架内),或通过带有放大器和中继器的专用铜线或光纤线路的IPTV广播。

    这种技术被普遍使用,并表现出良好的延迟特性。市场上的公司使用以太网实现的与编码、数据传输和解码相关的延迟,在每秒25帧的情况下不超过80ms。在更高的帧率下,这一延迟特性甚至更低。

    图1. UDP广播延迟测量

    图1上半部分显示了来自SDI采集卡的信号,下半部分展示经过编码、多路复用、广播、接收和解码阶段的信号。如图所示,第二个信号晚一帧到达(在这种情况下,因为信号是25fps,1帧是40毫秒)。在Confederations Cup 2017和FIFA World Cup 2018上使用了类似的解决方案,只有一个调制器、一个分布式DVB-C网络和一个作为终端设备的电视加入到架构链中,最终总延迟为220-240毫秒。

    如果信号通过一个外部网络怎么办?有各种问题需要克服:干扰、整形、流量阻塞通道、硬件错误、电缆损坏和软件层面的问题。在这种情况下,不仅需要低延迟,还需要对丢失的数据包进行重传。

    在UDP的情况下,带有冗余的前向纠错技术FEC(有额外的测试流量或开销)做得很好。同时,对网络吞吐率的要求随之增加,因此,延迟和冗余也会增加,这取决于预期丢失数据包的百分比。由于FEC能恢复的数据包的百分比总是有限的,而且在开放网络的传输过程中可能有很大的变化。因此,为了在长距离上可靠地传输大量数据,有必要在其中增加较多的多余流量。

         TCP

    接下来让我们看看基于TCP协议的技术(可靠交付)。如果收到的数据包的校验和不符合预期值(在TCP数据包头中设置),那么这个数据包就会被重新发送。而如果客户端和服务器端不支持选择性确认(SACK)规范,那么整个TCP数据包链(从丢失的数据包到最后一个以较低速率接收的数据包)就会被重新发送。

    以前,当涉及到直播的低延迟时,通常会避免使用TCP协议,因为错误检查、数据包重发、三次握手、"慢启动 "和防止信道拥塞(TCP慢启动和拥塞避免阶段),延迟会增加。同时,即使信道很宽,传输开始前的延迟也可能达到RTT的五倍,而吞吐量的增加对延迟的影响非常小。

    另外,使用TCP广播的应用程序对协议本身没有任何控制(它的超时、重新广播的窗口大小),因为TCP传输是作为一个单一的连续流实现的,在错误发生之前,应用程序可能会无限期地 "冻结"。而且高层协议没有灵活配置TCP,以尽量减少广播问题的能力。

    同时,有些协议即使在开放的网络和长距离的情况下也能通过UDP有效工作。

    下面让我们来考虑和比较各种协议的实现。在基于TCP的协议和数据传输格式中,将会涉及RTMP、HLS和CMAF,而在基于UDP的协议和数据传输格式中,将会涉及WebRTC和SRT。

       RTMP

    RTMP是Macromedia公司的专有协议(现在归Adobe公司所有),在基于Flash的应用程序流行时非常流行。它有几个品种,支持TLS/SSL加密,甚至还有基于UDP的变种,即RTFMP(实时媒体流协议,用于点对点连接)。RTMP将数据流分割成片段,其大小可以动态变化。在通道内,与音频和视频有关的数据包可以交错和复用。

    图2. RTMP广播实现用例

    RTMP会构建几个虚拟通道,在这些通道上传输音频、视频、元数据等。大多数CDN不再支持RTMP作为向终端客户分配流量的协议。然而,Nginx有自己的RTMP模块,支持普通的RTMP协议,它运行在TCP之上,使用默认的1935端口。Nginx可以作为一个RTMP服务器,分发它从RTMP流媒体接收的内容。另外,RTMP仍然是向CDN交付流量的流行协议,但在未来,流量将使用其他协议进行传输。

    目前,Flash技术已经过时,且不受支持:浏览器或是减少对它的支持,或是完全禁止使用。RTMP不支持HTML5,在浏览器中也难以使用(播放需要通过Adobe Flash插件)。为了绕过防火墙,他们使用RTMPT(封装到HTTP请求中,并使用标准的80/443而不是1935端口),但这大大影响了延迟和冗余(根据各种估计,RTT和整体延迟增加30%)。尽管如此,RTMP仍然很流行,例如,在YouTube上的广播或在社交媒体上(Facebook的RTMPS)。

    RTMP的主要缺点是缺乏对HEVC/VP9/AV1编码器的支持,以及只允许两个音轨的限制。此外,RTMP在数据包头中不包含时间戳。RTMP只包含根据帧率计算的标签,因此解码器并不确切知道何时解码这个流。这就需要一个接收组件均匀地生成用于解码的样本,因此缓冲区必须按数据包抖动的大小来增加。

    RTMP的另一个问题是重新发送丢失的TCP数据包,这在前文已经描述过。为了保持较低的回传流量,确认收到(ACK)并不直接到发件端。只有在收到数据包链后,才会向广播方发送ACKs或NACKs的确认信息。

    根据各种估计,使用RTMP进行广播,通过完整的编码路径(RTMP编码器→RTMP服务器→RTMP客户端)的延迟至少是两秒。

       CMAF

    CMAF(Common Media Application Format,通用媒体应用格式)是由苹果和微软邀请MPEG开发的协议,用于在HTTP上进行自适应广播(具有根据整个网络带宽速率变化而变化的自适应比特率)。通常情况下,苹果公司的HTTP直播(HLS)使用MPEG TS流,而MPEG DASH使用片段式的MP4。2017年7月,CMAF标准被发布。在CMAF中,片段式的MP4片段(ISOBMFF)通过HTTP传输,同一内容有两个不同的播放列表,用于特定的播放器:iOS(HLS)或Android/Microsoft(MPEG DASH)。

    默认情况下,CMAF(像HLS和MPEG DASH)不是为低延迟广播设计的。但行业对低延迟的关注和兴趣在不断增加,所以一些厂商提供了标准的扩展,例如低延迟CMAF。这种扩展假定广播方和接收方都支持两种方法:

    1. 分块编码:将片段分成子片段(带有moof+mdat mp4框的小片段,最终构成适合播放的整个片段),并在整个片段拼合之前发送。

    2. 分块传输编码:使用HTTP 1.1发送子片段到CDN(源):每4秒只发送1次整个片段的HTTP POST请求(每秒25帧),此后在同一会话中可以发送100个小片段(每个片段有一帧)。播放器也可以尝试下载不完整的片段,而CDN则使用分块传输编码提供完成的部分,然后保持连接,直到新的片段被添加到正在下载的片段中。一旦整个片段在CDN一侧形成,向播放器传输的片段就会完成。

    图3. 标准的分块CMAF

    如果要在配置文件之间切换,则需要缓冲(至少2秒)。鉴于这一点以及有可能的分发问题,该标准的开发者声称延迟小于3秒。同时,诸如通过CDN与成千上万的同时客户端进行扩展、加密(连同通用加密支持)、HEVC和WebVTT(字幕)支持、保证交付和与不同播放器(苹果/微软)的兼容性等重要特征都得到了保留。在缺点方面,人们可能会注意到播放器方面强制性的LL CMAF支持(支持碎片化的片段和内部缓冲区的高级操作)。然而,在不兼容的情况下,播放器仍然可以使用CMAF规范内的内容,具有HLS或DASH的标准延迟。

      LL-HLS

    2019年6月,苹果发布了低延迟HLS的规范。

    它由以下部分组成:

    1. 生成部分片段(片段式的MP4或TS),最小持续时间为200毫秒,甚至在由这些部分组成的整个片段完成之前就可以使用。过时的部分片段会定期从播放列表中删除;

    2. 服务器端可以使用HTTP/2推送模式,将更新的播放列表与新的片段一起发送。然而,在2020年1月的最后一次规范修订中,这一建议被排除;

    3. 服务器的责任是保留请求(阻塞),直到包含新片段的播放列表版本可用。阻断播放列表的重新加载消除了轮询;

    4. 不发送完整的播放列表,而是发送播放列表的增量(默认的播放列表被保存,然后只在出现时发送增量,而不是发送完整的播放列表);

    5. 服务器宣布即将出现的新的部分片段(预加载提示);

    6. 关于播放列表的信息在相邻的配置文件中被同时加载,以加快切换。

    图4. LL HLS的运行原理

    在CDN和播放器完全支持该规范的情况下,预计延迟时间小于3秒。HLS由于其出色的可扩展性、加密和自适应比特率支持跨平台功能以及向后兼容,非常广泛地用于开放网络的广播,如果播放器不支持LL HLS,这一点很有用。

    WebRTC

    WebRTC(网络实时通信)是由谷歌在2011年开发的一个开源协议。它被用于Google Hangout、Slack、BigClueButton和YouTube Live。WebRTC是一套标准、协议和JavaScript编程接口,并且使用DTLS-SRTP在点对点连接中实现了端到端的加密。此外,该技术不使用第三方插件或软件,可以在不损失质量和延迟的情况下通过防火墙(例如,在浏览器的视频会议期间)。在播放视频时,通常使用基于UDP的WebRTC实现。

    该协议的工作原理如下:一台主机向要连接的对等客户发送一个连接请求。在对等客户之间的连接建立之前,它们通过第三方信号服务器相互通信。然后,每个对等客户都向STUN服务器询问 "我是谁?" (如何从外面找到我?)。

    同时,有公共的谷歌STUN服务器(例如stun.l.google.com:19302)。STUN服务器提供一个IP和端口的列表,通过这个列表可以到达当前的主机。ICE候选者是由这个列表形成的。第二个客户也进行相同的操作。ICE候选者通过信号服务器进行交换,正是在这个阶段建立了点对点的连接,即形成了一个点对点的网络。

    如果不能建立直接连接,那么一个所谓的TURN服务器就充当中继/代理服务器,它也被列入ICE候选名单。

    SCTP(应用数据)和SRTP(音频和视频数据)协议负责多路复用、发送、拥塞控制和可靠交付。对于“握手”交换和进一步的流量加密,使用了DTLS。

    图5. WebRTC协议栈

    使用Opus和VP8作为编解码器。最大支持的分辨率为720p,30fps,比特率最高到2Mbps。

    WebRTC技术在安全方面的一个缺点是,即使在NAT后面和使用Tor网络或代理服务器时,也要定义一个真实的IP。由于连接结构的原因,WebRTC不适合大量同时观看的对等客户(难以扩展),而且目前CDN也很少支持它。最后,WebRTC在编码质量和最大传输数据量方面不如其他协议。

    WebRTC在Safari中不可用,在Bowser和Edge中部分不可用。谷歌声称其延迟不到一秒。同时,该协议不仅可用于视频会议,也可用于文件传输等应用。

         SRT

    SRT(Secure Reliable Transport,安全可靠传输)是由Haivision在2012年开发的一个协议。该协议在UDT(基于UDP的数据传输协议)和ARQ数据包恢复技术的基础上运行。它支持AES-128和AES-256加密。除了监听(服务器)模式,它还支持呼叫(客户端)和会合(当双方启动连接时)模式,这使得连接可以通过防火墙和NAT建立。SRT的“握手”过程是在现有的安全策略中进行的,因此允许外部连接,而不需要在防火墙中打开永久的外部端口。

    SRT在每个数据包内都包含时间戳,这就允许以与流编码速率相等的速度播放,而不需要大量的缓冲,同时使抖动(不断变化的数据包到达率)和传入的比特率保持一致。与TCP中一个数据包的丢失可能会导致重新发送整个数据包链不同,从丢失的数据包开始,SRT通过其编号识别一个特定的数据包,并只重新发送这个数据包。这对延迟和冗余有积极作用。

    重发的数据包比标准广播的优先级更高。与标准的UDT不同,SRT完全重新设计了重发数据包的架构,一旦数据包丢失,就立即做出反应。这项技术是选择性重复/拒绝ARQ的一个变种。值得注意的是,一个特定的丢失的数据包可能只被重新发送固定的次数。当数据包上的时间超过总时延的125%时,发送方会跳过该数据包。SRT支持FEC,用户自己决定使用这两种技术中的哪一种(或同时使用两种),以平衡最低延迟和最高传输可靠性。

    图6. SRT在开放网络上的运行原理

    SRT中的数据传输可以是双向的:两点都可以同时发送数据,也可以同时作为监听和发起连接的一方。当双方都需要建立连接时,可以使用会合模式。该协议有一个内部复用机制,允许将一个会话的几个流复用到使用一个UDP端口的一个连接中。SRT也适用于快速文件传输,这个应用在UDT中首次引入。

    SRT有一个网络拥堵控制机制。每隔10毫秒,发送方就会收到关于RTT及其变化的最新数据、可用的缓冲区大小、数据包接收率和当前链接的大致大小。SRT对连续发送的两个数据包之间的最小延时有限制。如果它们不能及时送达,就会从队列中删除。

    开发者声称,在封闭网络中短距离传输中设置缓冲区为最小,使用SRT可能实现的最小延迟是120毫秒。建议稳定广播的总延迟是3-4个RTT。此外,SRT在长距离(几千公里)和高比特率(10Mbps及以上)的传输方面比其竞争对手RTMP处理得更好。

    图7. SRT广播延迟测试

    在上面的例子中,实验室测量的SRT广播的延迟在25fps的条件下是3帧。也就是40ms*3=120ms。由此我们可以得出结论,在UDP广播中可以达到的0.1秒的超低延迟,在SRT广播中也是可以实现的。SRT的可扩展性与HLS或DASH/CMAF不在同一水平上,但SRT得到CDN和转发者(restreamer)的大力支持,也支持通过媒体服务器以监听模式直接广播给终端客户。

    2017年,Haivision披露了SRT库的源代码,并创建了SRT联盟,该联盟包括350多个成员。

         总结

    作为总结,下表展示了各个协议的对比:

    1. 不支持由CDN向终端用户传输。支持内容流向最后一英里,例如,流向CDN或restreamer。

    2. 在浏览器中不支持

    3. Safari中不支持

    目前,所有开源的、文档全面的东西都在迅速流行起来。可以认为,像WebRTC和SRT这样的格式在各自的应用范围内有一个长远的未来。在最低延迟方面,这些协议已经超过了HTTP上的自适应广播,同时保持可靠的传输,具有低冗余度,并支持加密(SRT的AES和WebRTC的DTLS/SRTP)。

    另外,最近SRT的“小兄弟”(根据协议的产生时间,而不是在功能和能力方面)RIST协议,正在获得普及,但这是另一个话题了。同时,RTMP正在积极地被新的竞争者挤出市场,而且由于浏览器缺乏原生支持,它难以很快被广泛使用。

    原文标题 | Low Latency Streaming Protocols SRT, WebRTC, LL-HLS, UDP, TCP, RTMP Explained

    原文链接 | https://ottverse.com/low-latency-streaming-srt-webrtc-ll-hls-udp-tcp-rtmp/0

    本文转自公众号:


    扫描图中二维码或点击阅读原文

    了解大会更多信息

    喜欢我们的内容就点个“在看”吧!

    展开全文
  • rtmp详解

    2019-04-26 11:18:00
    文件下载地址: 中文:https://files.cnblogs.com/files/bugutian/rtmp_specification_1.0_cn.zip 英文:http://www.adobe.com/cn/devnet/rtmp.html 本文直接从中文的PDF上复制而...RTMP 协议 Adobe 官 方规范...

    文件下载地址:

     中文:https://files.cnblogs.com/files/bugutian/rtmp_specification_1.0_cn.zip

    英文:http://www.adobe.com/cn/devnet/rtmp.html 

     

    本文直接从中文的PDF上复制而来,无配图,请下载中文的zip解压成pdf之后查看。 

     

    RTMP 协议 Adobe 官 方规范
    By, Defonds
    Blog, http://blog.csdn.net/defonds
    Email, defonds@163.com

    1. 简介
    Adobe 的实时消息传输协议 (RTMP) 通过一个靠地流传输供了一个向多通 道消息服,比如 TCP [RFC0793],意图在通信端之间传递有时间信息的视频音频和
    数据消息流实通常对不类型的消息配不的优先级,当载能力有限时,会影响
    等流传输的消息的次序 本文档将对实时流传输协议 (Real Time Messaging Protocol) 的语法和操作行述

    2. 贡献者
    Rajesh Mallipeddi,Adobe Systems 原员,起草了本文档原始规范,并供大部的 原始内容 Mohit Srivastava,Adobe Systems 员,促了本规范的开发

    3. 词解释
    Payload (有效载荷)包于一个数据包中的数据,例如音频采样或者压缩的视频数据 payload 的格式和解释,超出了本文档的范围

    Packet (数据包)一个数据包由一个固定头和有效载荷数据构一些个层协议能 会要求对数据包定封装

    Port (端口)"传输协议用开指定一机的不目的地的一个抽象TCP/IP 使 用小的整数对端口行标识" OSI 传输层使用的输选择器 (TSEL) 相当于端口

    Transport address (传输地址)用识传输层端点的网地址和端口的组合,例如一个 IP 地址和一个 TCP 端口数据包由一个源传输地址传到一个目的传输地址

    Message stream (消息流)通信中消息流通的一个逻辑通道

    Message stream ID (消息流 ID)每个消息有一个关联的 ID,使用 ID 识出流通 中的消息流

    Chunk (块)消息的一段消息在网发之前被拆很多小的部块确保端 到端交付所有消息有序 timestamp,即使有很多不的流

    Chunk stream (块流)通信中允许块流向一个特定方向的逻辑通道块流从客户端 流向服器,也从服器流向客户端

    Chunk stream ID (块流 ID)每个块有一个关联的 ID,使用 ID 识出流通中的块 流

    Multiplexing (合)将独立的音频/视频数据合一个续的音频/视频流的工, 样时发几个视频和音频

    DeMultiplexing (解)Multiplexing 的逆向处理,将交的音频和视频数据原原始 音频和视频数据的格式

    Remote Procedure Call (RPC 程方法调用)允许客户端或服器调用对端的一个子程 序或者程序的求

    Metadata (元数据)关于数据的一个述一个电影的 metadata 包括电影标题持续 时间创建时间等等

    Application Instance (用实例)服器用的实例,客户端接个实例并发 接求

    Action Message Format (AMF 动作消息格式协议)一个用于序列化 ActionScript 对象 图的紧凑的制格式AMF 有两个版本AMF 0 [AMF0] 和 AMF 3 [AMF3]

    4. 节序对齐和时间格式
    所有整数型属性网节序传输,节 0 表第一个节,零是一个单词或 段最常用的有效节序通常是大端排序关于传输序的更多细节述参考 IP 协议 [RFC0791]除非另外注明,本文档中的数值常量都是十制的 ( 10 基础)

    除非另有规定,RTMP 中的所有数据都是节对准的例如,一个十的属性能 会在一个奇节偏移填充,填充节有零值

    RTMP 中的 Timestamps 一个整数形式给出,表示一个未指明的时间点型地,每 个流会一个 0 的 timestamp 起始,但不是必的,要端能够就时间点达一 注意意味着任意不流 (尤是来自不机的) 的需要 RTMP 之外的机制

    因 timestamp 的长度 32 ,每隔 49 17 小时 2 钟和 47.296 秒就要来 一次因允许流续传输,有能要多年,RTMP 用在处理 timestamp 时使用序 列码算法 [RFC1982],并且能够处理无限循例如,一个用假定所有相邻的 timestamp 都在 2^31 - 1 毫秒之内,因 10000 在 4000000000 之,而 3000000000 在 4000000000 之前

    timestamp 也使用无符整数定,相对于前面的 timestamptimestamp 的长度能 会是 24 或者 32

    5. RTMP 块流
    本节介绍实时消息传输协议的块流 (RTMP 块流) 它层多媒体流协议供合并和 打包的服

    当设 RTMP 块流使用实时消息传输协议时,它处理任何发消息流的协议每 个消息包 timestamp 和 payload 类型标识RTMP 块流和 RTMP 一起合各种音频-视 频用,从一对一和一对多直播到点播服,到互动会议用

    当使用靠传输协议时,比如 TCP [RFC0793],RTMP 块流能够对于多流供所有消 息靠的 timestamp 有序端对端传输RTMP 块流并不供任何优先权或类似形式的控制,
    但是被层协议用来供种优先级例如,一个直播视频服器能会基于发时间
    或者每个消息的确认时间丢一个传输缓慢的客户端的视频消息确保时获音频消


    RTMP 块流包括自身的内协议控制信息,并且供机制层协议植入用户控制 消息

    5.1 消息格式

    被割块支持组合的消息的格式决于层协议消息格式必包创建
    块所需的段

    Timestamp消息的 timestamp个段传输四个节

    Length消息的有效负载长度如果不能省略掉消息头,那它也被包括个长度 个段占用了块头的个节

    Type Id一些类型 ID 保留给协议控制消息使用些传播信息的消息由 RTMP 块流 协议和层协议共处理他的所有类型 ID 用于层协议,它们被 RTMP 块流处理 不透明值实,RTMP 块流中没有任何地方要把些值当做类型使用所有消息必
    是一类型,或者用使用一段来跟踪,而不是类型一段占用了块头
    的一个节

    Message Stream IDmessage stream (消息流) ID 使任意值合并到一个块流的不 的消息流是根据各自的消息流 ID 行解除之外,对 RTMP 块流而言,是一个 不透明的值个段小端格式占用了块头的四个节

    5.2 握手

    一个 RTMP 接握手开始RTMP 的握手不于他协议RTMP 握手由个固定 长度的块组,而不是像他协议一样的有头的长度的块

    客户端 (发起接求的终端) 和服器端各自发相的块便于演示,当发自 客户端时些块被指定 C0C1 和 C2当发自服器端时些块被指定 S0 S1 和 S2

    5.2.1. 握手序

    握手客户端发 C0 和 C1 块开始

    客户端必等接收到 S1 才能发 C2

    客户端必等接收到 S2 才能发任何他数据

    服器端必等接收到 C0 才能发 S0 和 S1,也等接收到 C1 发 S0 和 S1服器端必等接收到 C1 才能发 S2服器端必等接收到 C2 才能发 任何他数据

    5.2.2. C0 和 S0 的格式

    C0 和 S0 包都是一个单一的节,一个单独的整型域行处理

    是 C0/S0 包中的段

    版本 ()在 C0 中,一段指示出客户端要求的 RTMP 版本在 S0 中, 一段指示出服器端选择的 RTMP 版本本文档中规范的版本 3012 个值是由早期他产品使用的,是废值4 - 31 被保留 RTMP 协议的未来实版本使 用32 - 255 不允许使用 (开 RTMP 和他常一个打印符开始的文本协议) 无法识客户端所求版本的服器版本 3 响,(收到响的) 客户端选择 降到版本 3,或者放握手

    5.2.3. C1 和 S1 的格式

    C1 和 S1 数据包的长度都是 1536 节,包段

    Time (四个节)个段包一个 timestamp,用于本终端发的所有续块的时间 起点个值是 0,或者一些任意值要多个块流,终端发他块流当前的 timestamp 的值

    Zero (四个节)个段必都是 0

    Random data (1528 个节)个段包任意值终端需要出响来自它发
    起的握手是对端发起的握手,个数据发一些足够随机的数个不需要对随机数
    行密保,也不需要动态值

    5.2.4. C2 和 S2 的格式

    C2 和 S2 数据包长度都是 1536 节,基本就是 S1 和 C1 的副本 (),包有 段 


    Time (四 个 节) 个 段 必 包 终 端 在 S1 (给 C2) 或 者 C1 (给 S2) 发 的 timestamp

    Time2 (四个节)个段必包终端先前发出数据包 (s1 或者 c1) timestamp

    Random echo (1528 个节)个段必包终端发的 S1 (给 C2) 或者 S2 (给 C1) 的随机数两端都一起使用 time 和 time2 段当前 timestamp 快速估算宽 和/或者接延,但不能是有多大用处


    5.2.5. 握手示意图


    面述了握手示意图中到的状态

    Uninitialized (未 初 始 化) 协 议 的 版 本 在 个 阶 段 被 发 客 户 端 和 服 器 都 是 uninitialized (未初始化) 状态之客户端在数据包 C0 中将协议版本发出如果服器 支持个版本,它将在回中发 S0 和 S1如果不支持呢,服器会才去当的行 行响在 RTMP 协议中,个行就是终接

    Version Sent (版本已发)在未初始化状态之,客户端和服器都入 Version Sent (版本已发) 状态客户端会等接收数据包 S1 而服器在等 C1一旦拿到期的包, 客户端会发数据包 C2 而服器发数据包 S2(客户端和服器各自的)状态随即 Ack Sent (确认已发)

    Ack Sent (确认已发)客户端和服器等 S2 和 C2

    Handshake Done (握手结束)客户端和服器开始交换消息了


    5.3 块

    握手之,接开始对一个或多个块流行合并创建的每个块都有一个唯一 ID 对 行关联,个 ID 做 chunk stream ID (块流 ID)些块通过网行传输传递时, 每个块必被完全发才发一块在接收端,些块被根据块流 ID 被组装消 息

    块允许层协议将大的消息解更小的消息,例如,防体积大的但优先级小的消
    息 (比如视频) 阻碍体积较小但优先级高的消息 (比如音频或者控制命)

    块也让们能够使用较小开销发小消息,因块头包包在消息内部的信息压缩


    块 的 大 小 是 配 置 的 它 使 用 一 个 设 置 块 大 小 的 控 制 消 息 行 设 置 (参 考 5.4.1)更大的块大小降 CPU 开销,但在宽接时因它的大量的写入也会延
    他内容的传递更小的块不利于高比特率的流化所块的大小设置决于体情况


    5.3.1. 块格式

    每个块包一个头和数据体块头包个部

    Basic Header (基本头,1 到 3 个节)个段对块流 ID 和块类型行编码块类 型决定了消息头的编码格式(一段的) 长度完全决于块流 ID,因块流 ID 是一个 长度的段

    Message Header (消息头,0,3,7,或者 11 个节)一段对在发的消息 (不 管是整个消息,是是一小部) 的信息行编码一段的长度使用块头中定
    的块类型行决定

    Extended Timestamp (扩展 timestamp,0 或 4 节)一段是否出决于块消息 头中的 timestamp 或者 timestamp delta 段更多信息参考 5.3.1.3 节

    Chunk Data (有效大小)当前块的有效负载,相当于定的最大块大小

    5.3.1.1. 块基本头

    块基本头对块流 ID 和块类型 (由图中的 fmt 段表示) 行编码块基本头段 能会有 1,2 或者 3 个节,决于块流 ID

    一个 (RTMP) 实使用能够容纳个 ID 的最小的容量行表示

    RTMP 协议最多支持 65597 个流,流 ID 范围 3 - 65599ID 012 被保留0 值 表示节形式,并且 ID 范围 64 - 319 (第个节 + 64)1 值表示节形式,并且 ID 范围 64 - 65599 ((第个节) * 256 + 第个节 + 64)3 - 63 范围内的值表示整个流 ID有 2 值的块流 ID 被保留,用于层协议控制消息和命

    块基本头中的 0 - 5 (最有效) 表块流 ID

    块流 ID 2 - 63 编一段的一节版本中

    块流 ID 64 - 319 节的形式编码在头中ID 算 (第个节 + 64) 

    块流 ID 64 - 65599 编码在个段的节版本中ID 算 ((第个节) * 256 + (第个节) + 64)

    cs id ()一段包有块流 ID,值的范围是 2 - 63值 0 和 1 用于指示一 段是 2- 或者 3- 节版本

    fmt (两个节)一段指示 'chunk message header' 使用的四种格式之一没中块类 型的 'chunk message header' 会在一小节解释

    cs id - 64 (8 或者 16 )一段包了块流 ID 减掉 64 的值例如,ID 365 在 cs id 中会一个 1 行表示,和的一个 16 的 301 (cs id - 64)

    块流 ID 64 - 319 使用 2-byte 或者 3-byte 的形式在头中表示

    5.3.1.2. 块消息头

    块消息头四种不的格式,由块基本头中的 "fmt" 段行选择

    一个 (RTMP) 实每个块消息头使用最紧凑的表示

    5.3.1.2.1. 类型 0

    类型 0 块头的长度是 11 个节一类型必用在块流的起始置,和流 timestamp 来的时候 (比如,置)


    timestamp (个节)对于 type-0 块,当前消息的对 timestamp 在发如果 timestamp 大于或者等于 16777215 (十制 0xFFFFFF),一段必是 16777215,表 明有扩展 timestamp 段来补充完整的 32 timestamp否则的话,一段必是整个 的 timestamp

    5.3.1.2.2. 类型 1

    类型 1 块头长 7 个节不包消息流 ID一块使用前一块一样的流 ID 长度消息的流 (例如,一些视频格式) 在第一块之使用一格式表示之的每个新 消息



    5.3.1.2.3. 类型 2

    类型 2 块头长度 3 个节既不包流 ID 也不包消息长度一块有和前 一块相的流 ID 和消息长度有不长度的消息 (例如,一些音频和数据格式) 在 第一块之使用一格式表示之的每个新消息

    5.3.1.2.4. 类型 3

    类型 3 的块没有消息头流 ID消息长度 timestamp delta 等段都不在 种类型的块使用前面块一样的块流 ID当单一一个消息被割多块时,除了第一块的 他块都使用种类型参考例 2 (5.3.2.2 小节)组流的消息有样的大小,流 ID 和时间间隔在类型 2 之的所有块都使用一类型参考例 1 (5.3.2.1 小节)如果第 一个消息和第个消息之间的 delta 和第一个消息的 timestamp 一样的话,那在类型 0 的块之要紧跟一个类型 3 的块,因无需来一个类型 2 的块来注 delta 了如果一 个类型 3 的块跟着一个类型 0 的块,那个类型 3 块的 timestamp delta 和类型 0 块 的 timestamp 是一样的

    5.3.1.2.5. 通用头段

    块消息头中各段的述如

    timestamp delta (个节)对于一个类型 1 或者类型 2 的块,前一块的 timestamp 和 当前块的 timestamp 的在发如果 delta 大于或者等于 16777215 (十制 0xFFFFFF),那一段必是 16777215,表示有扩展 timestamp 段来对整个 32 delta 行编码否则的话,一段是体 delta

    message length (个节)对于一个类型 0 或者类型 1 的块,消息长度在行
    发注意通常不于块的有效载荷的长度块的有效载荷表所有的除了最一块的最
    大块大小,剩余的 (也能是小消息的整个长度) 最一块

    message type id (消息类型 id,一个节)对于类型 0 或者类型 1 的块,消息的类型 在发

    message stream id (四个节)对于一个类型 0 的块,保消息流 ID消息流 ID
    小端格式保所有一个块流的消息都来自一个消息流当将不的消息流组合
    一个块流时,种方法比头压缩的做法要好但是,当一个消息流被关闭而他的随
    另一个是打开着的,就没有理由将有块流发一个新的类型 0 的块行复用了

    5.3.1.3. 扩展 timestamp

    扩展 timestamp 段用于对大于 16777215 (0xFFFFFF) 的 timestamp 或者 timestamp delta 行编码也就是,对于不合于在 24 的类型 01 和 2 的块的 timestamp 和 timestamp delta 编码一段包了整个 32 的 timestamp 或者 timestamp delta 编码 通过设置类型 0 块的 timestamp 段类型 1 或者 2 块的 timestamp delta 段 16777215 (0xFFFFFF) 来启用一段当最的有一块流的类型 01 或 2 块指示 扩展 timestamp 段出时,一段才会在类型 3 的块中出



    5.3.2. 例子

    5.3.2.1. 例子 1

    个例子演示了一个简单地音频消息流个例子演示了信息的冗余



    一个表格演示了个流所产生的块从消息 3 起,数据传输得到了最佳化利用每 条消息的开销在一点之都有一个节



    5.3.2.2. 例子 2

    一例子阐述了一条消息大,无法装在一个 128 节的块,被割若干块



    是传输的块

    块 1 的数据头说明了整个消息长度是 307 个节

    由俩例子得知,块类型 3 被用于两种不的方式第一种是用于定一 条消息的配置第种是定一个从有状态数据中派生出来的新消息的起点


    5.4 协议控制消息

    RTMP 块流使用消息类型 ID 1235 和 6 用于协议控制消息些消息包 有 RTMP 块流协议所需要的信息

    些协议控制消息必使用消息流 ID 0 (作已知控制流) 并流 ID 2 的块发 协议控制消息一旦被接收到就立即生效协议控制消息的 timestamp 被忽略


    5.4.1. 设置块类型 (1)

    协议控制消息 1,设置块大小,通知对端一个新的最大块大小

    默认的最大块大小是 128 节,但是客户端或者服器改个大小,并使用 一消息对对端行更新例如,假定一个客户端想要发一个 131 节的音频数据,当 前块大小是默认的 128在种情况,客户端发种消息到服器通知它块大小 在是 131 节了样客户端就在单一块中发整个音频数据了

    最大块大小设置的话最少 128 节,包内容最少要一个节最大块大小由每个 方面 (服器或者客户端) 自行维



    0个必 0

    chunk size (块大小,31 )一段保新的最大块大小值,节单,将用 于 之 发 者 发 的 块 , 直 到 有 更 多 (关 于 最 大 块 大 小 的 ) 通 知 有 效 值 1 到 2147483647 (0x7FFFFFFF,1 和 2147483647 都) 但是所有大于 16777215 (0xFFFFFF) 的大小值是等的,因没有一个块比一整个消息大,并且没有一个消息大于 16777215 节

    5.4.2. 终消息

    协议控制消息 2,终消息,用于通知对端,如果对端在等去完一个消息的块的话, 然抛一个块流中已接到的部消息对端接收到块流 ID 作当前协议消息的有效
    负载一些程序能会在关闭的时候使用个消息指示不需要一对个消息的处理


    chunk stream ID (块流 ID,32 )一段保块流 ID,流的当前消息会被丢


    5.4.3. 确认 (3)

    客户端或者服器在接收到等于窗口大小的节之必要发给对端一个确认窗
    口大小是指发者在没有收到接收者确认之前发的最大数量的节个消息定了序列
    ,也就是目前接收到的节数

    sequence number (序列,32 )一段保有目前接收到的节数

    5.4.4. 窗口确认大小 (5)

    客户端或者服器端发条消息来通知对端发和答之间的窗口大小发者在发
    完窗口大小节之期对端的确认接收端在次确认发接收到的指示数值,或
    者会话建立之尚未发确认,必发一个确认 (5.4.3 小节)


    5.4.5. 设置对端宽 (6)

    客户端或者服器端发一消息来限制对端的输出宽对端接收到一消息,
    将通过限制一消息中窗口大小指出的已发但未被答复的数据的数量限制输出宽
    接收到一消息的对端回复一个窗口确认大小消息,如果个窗口大小不于发给 (设置对端宽) 发者的最一条消息

    限制类型值之一

    0 - Hard对端限制输出宽到指示的窗口大小

    1 - Soft对端限制输出宽到知识的窗口大小,或者已经有限制在作用的话就 两者之间的较小值

    2 - Dynamic如果先前的限制类型 Hard,处理个消息就好像它被标记 Hard,否 则的话忽略个消息

    6. RTMP 消息格式

    一节定了使用层传输层 (比如 RTMP 块流协议) 传输的 RTMP 消息的格式 RTMP 协议设使用 RTMP 块流,使用他任意传输协议对消息行发RTMP 块流和 RTMP 一起用于多种音频 - 视频用,从一对一和一对多直播到点播服,到 互动会议用


    6.1. RTMP 消息格式

    服器端和客户端通过网发 RTMP 消息来行彼通信消息包音频视 频数据,或者他消息

    RTMP 消息有两部头和它的有效载荷


    6.1.1. 消息头

    消息头包

    Message Type (消息类型)一个节的段来表示消息类型类型 ID 1 - 6 被保留用于 协议控制消息

    Length (长度)个节的段来表示有效负载的节数大端格式保

    Timestamp四个节的段包了当前消息的 timestamp四个节也大端格式保

    Message Stream Id (消息流 ID)个节的段指示出当前消息的流个节 大端格式保




    6.1.2. 消息有效载荷


    消息的另一个部就是有效负载,是个消息所包的实际内容例如,它是一
    些音频样本或者压缩的视频数据有效载荷格式和解释不在本文档范围之内



    6.2. 用户控制消息 (4)

    RTMP 使用消息类型 ID 4 表示用户控制消息些消息包 RTMP 流传输层所使用 的信息RTMP 块流协议使用 ID 1235 和 6 (5.4 节介绍)

    用户控制消息使用消息流 ID 0 (被认是控制流),并且 RTMP 块流发时 块流 ID 2用户控制消息一旦被接收立马生效它们的 timestamp 是被忽略的

    客户端或者服器端发个消息来通知对端用户操作一消息携有类型
    和数据

    消息数据的前两个节用于指示类型类型被数据紧随数据段的
    大小是的但是,如果消息必通过 RTMP 块流层传输时,最大块大小 (5.4.1 节) 足够大允许些消息填充在一个单一块中

    类型和数据格式将在 7.1.7 小节列出

    7. RTMP 命消息

    一节述了在服器端和客户端彼通信交换的消息和命的不的类型

    服器端和客户端交换的不消息类型包括用于发音频数据的音频消息用于发视
    频数据的视频消息用于发任意用户数据的数据消息共享对象消息命消息共享
    对象消息供了一个通用的方法来管理多用户和一服器之间的布式数据命消息在
    客户端和服器端传输 AMF 编码的命客户端或者服器端通过使用命消息和 对端通信的流求程方法调用 (RPC)


    7.1. 消息的类型

    服器端和客户端通过在网中发消息来行彼通信消息是任何类型,包
    音频消息,视频消息,命消息,共享对象消息,数据消息,用户控制消息

    7.1.1. 命消息 (20, 17)

    命消息在客户端和服器端传递 AMF 编码的命些消息被配消息类型值 20 行 AMF0 编码,消息类型值 17 行 AMF3 编码些消息发行 一些操作,比如,接,创建流,发布,播放,对端暂停命消息,像 onstatusresult 等 等,用于通知发者求的命的状态一个命消息由命 ID 和包相关参
    数的命对象组一个客户端或者一个服器端通过和对端通信的流使用些命消
    息求程调用 (RPC)

    7.1.2. 数据消息 (18, 15)

    客户端或者服器端通过发些消息发元数据或者任何用户数据到对端元数据
    包括数据 (音频,视频等等) 的细信息,比如创建时间,时长,题等等些消息被
    配消息类型 18 行 AMF0 编码和消息类型 15 行 AMF3 编码

    7.1.3. 共享对象消息 (19, 16)

    所谓共享对象实是一个 Flash 对象 (一个值对的集合),个对象在多个不客户 端用实例中保持消息类型 19 用于 AMF0 编码16 用于 AMF3 编码都被共 享对象保留每个消息包有不

    支持类型

    述 Use(=1) 客户端发一通知服器端一个已 命的共享对象已创建 Release(=2) 当共享对象在客户端被删除时客户端发 一到服器端 Request Change (=3) 客户端发给服器端一求共享 对象的已命的参数所关联到的值的改 Change (=4) 服器端发一已通知发起一求
    之外的所有客户端,一个已命参数的值的
    改 Success (=5) 如果求被接,服器端发一给 求的客户端,作 RequestChange 的响 SendMessage (=6) 客户端发一到服器端广播一条
    消息一旦接收到一,服器端将会
    给所有的客户端广播一消息,包括一消
    息的发起者 Status (=7) 服器端发一通知客户端常情 况 Clear (=8) 服器端发一消息到客户端清理一个 共享对象服器端也会对客户端发的 Use 使用一行响 Remove (=9) 服器端发一有客户端删除一个 slot
    Request Remove (=10) 客户端发一有客户端删除一个 slot Use Success (=11) 服器端发给客户端一表示接


    7.1.4. 音频消息 (8)

    客户端或者服器端发一消息发音频数据到对端消息类型 8 音频消息保 留

    7.1.5. 视频消息 (9)

    客户端或者服器发一消息发视频数据到对端消息类型 9 视频消息保留


    7.1.6. 统消息 (22)

    统消息是一个单一的包一系列的使用 6.1 节述的 RTMP 子消息的消息消息类 型 22 用于统消息

    统消息的消息流 ID 覆盖了统中子消息的消息流 ID

    统 消 息 的 timestamp 和 第 一 个 子 消 息 的 timestamp 的 不 点 在 于 子 消 息 的 timestamp 被相对流时间标调整了偏移每个子消息的 timestamp 被入偏移达到一个统 一流时间第一个子消息的 timestamp 和统消息的 timestamp 一样,所个偏移 量 0

    向指针包有前一个消息的大小 (包前一个消息的头)样子配了 FLV 文的 格式,用于向查找

    使用统消息有性能优势

    块流在一个块中多一个单一完整的消息发因,增块大小并使用统 消息减少了发块的数量 子消息在内中续储在网中系统调用发些数据时更高效

    7.1.7. 用户控制消息

    客户端或者服器端发一消息来通知对端用户控制关于个的消息格式参考 6.2 节

    支持用户控制类型

    述 Stream Begin (=0) 服器发个来通知客户端一个流已
    就绪并用来通信默认情况,一
    在接收到客户端的用接命之
    ID 0 发一数据 4 节, 表了已就绪流的流 ID Stream EOF (=1) 服器端发一来通知客户端求的
    流的回放数据已经结束在发额外的命
    之前不发任何数据客户端将丢接收
    到的个流的消息一数据 4 节,表了回放已结束的流的流 ID StreamDry (=2) 服器端发一来通知客户端当前流
    中已没有数据当服器端在一段时间内没
    有检测到任何消息,它通知相关客户端
    当前流已经没数据了一数据 4 节,表了已没数据的流的流 ID SetBuffer Length (=3) 客户端发一来通知服器端用于缓 流 中 任 何 数 据 的 缓 大 小 ( 毫 秒 单 )一在服器端开始处理流之前就 发一数据的前 4 个节表了流 ID 4 个节表了毫秒单的缓 的长度 StreamIs Recorded (=4) 服器端发一来通知客户端当前流
    是一个录制流一数据 4 节, 表了录制流的流 ID PingRequest (=6) 服器端发一用于测试是否能够 达 客 户 端 时 间 数 据 是 一 个 4 节 的 timestamp,表了服器端发一命时
    的服器本地时间客户端在接收到一消
    息会立即发 PingResponse 回复 PingResponse (=7) 客户端作对 ping 求的回复发一 到服器端一数据是一个 4 节的 timestamp,就是接收自 PingRequest 那 个


    7.2. 命类型

    客户端和服器端交换 AMF 编码的命服器端发一个命消息,个命消 息由命 ID 包有相关参数的命对象组例如,包有 'app' 参数的
    接命,个命说明了客户端接到的服器端的用接收者处理一命并回发一
    个样 ID 的响回复符串是 _result_error 或者 一个方法的任意一个, 比如,verifyClient 或者 contactExternalServer

    命符串 _result 或者 _error 是响信 ID 指示出响所指向的命 和 AMAP 和他一些协议的标签一样命符串中的方法表示发者试图执行接收者 一端的一个方法

    类的对象用于发不的命

    NetConnection 表层的服器端和客户端之间接的一个对象

    NetStream 一个表发音频流视频流和他相关数据的通道的对象当然,们也 会发控制数据流的命,如 playpause 等等

    7.2.1. NetConnection 命


    NetConnection 管理着一个客户端用和服器端之间的相接外,它供 程方法的调用

    NetConnection 发命

    connect

    call

    close

    createStream

    7.2.1.1. connect 命

    客户端发 connect 命到服器端来求接到一个服器用的实例

    由客户端发到服器端的 connect 命结构如

    段 类型 述 Command Name 符串 命 的 设 置 给 "connect" Transaction ID 数 总是设置 1 Command Object 对象 有值对的命信息对象
    Optional User Arguments 对象 任意选信息


    是 connect 命中使用的值对对象的述

    属性 类 型
    述 范例
    app


    客户端接到的服器端用的 testapp
    flashver


    Flash Player 版 本 和 ApplicationScript getversion() 方法返回 的是一个符串
    FMSc/1.0
    swfUrl


    行当前接的 SWF 文源地址 file://C:/FlvPlayer.swf
    tcUrl


    服 器 URL 有 格 式 protocol://servername:port/appName/appI nstance
    rtmp://localhost:1935/testapp/ins tance1
    fpad 布 尔
    如果使用了理就是 true true 或者 false
    audioCodecs 数
    表明客户端所支持的音频编码 SUPPORT_SND_MP3
    videoCodecs 数
    表明支持的视频编码 SUPPORT_VID_SORENSON
    videoFunctio 数 表明所支持的特殊视频方法 SUPPORT_VID_CLIENT_SEE
    n K pageUrl


    SWF 文所载的网页 URL http://somehost/sample.html
    objectEncodi ng


    AMF 编码方法 AMF3

    audioCodecs 属性的标识值

    videoCodecs 属性的标识值 


    videoFunction 属性的标识值


    encoding 属性值



    服器端到客户端的命的结构如

    命执行时消息流动如

    1. 客户端发 connect 命到服器端求对服器端用实例的接

    2. 收到 connect 命,服器端发协议消息 '窗口确认大小' 到客户端服 器端也会接到 connect 命中到的用

    3. 服器端发协议消息 '设置对端宽' 到客户端

    4. 在处理完协议消息 '设置对端宽' 之客户端发协议消息 '窗口确认大小' 到服器端

    5. 服器端发另一个用户控制消息 (StreamBegin) 类型的协议消息到客户端

    6. 服器端发结果命消息告知客户端接状态 (success/fail)一命定了 ID (常常 connect 命设置 1)一消息也定了一些属性,比如 FMS 服器 版本 (符串)外,它定了他接关联到的信息,比如 level (符串)code (符 串)description (符串)objectencoding (数) 等等


    7.2.1.2. call 方法

    NetConnection 对象的 call 方法执行接收端程方法的调用 (PRC)被调用的 PRC 作一个参数传给调用命

    发端发给接收端的命结构如

    段 类型 述 Procedure Name 符串 调用的程方法的 Transaction ID 数 如果期望回复们要给一个 ID否则们传 0 值 即 Command Object 对象 如果在一些命信息要设 置个对象,否则置空 Optional Arguments 对象 任意要供的选参数


    回复的命结构如

    段 类型 述 Command Name 符串 命的 Transaction ID 数 响所属的命的 ID Command Object 对象 如果在一些命信息要设 置个对象,否则置空 Response 对象 调用方法的回复


    7.2.1.3. createStream 命

    客户端发一命到服器端消息接创建一个逻辑通道音频视频和元数据
    使用 createStream 命创建的流通道传输

    NetConnection 是 默 认 的 通 信 通 道 , 流 ID 0 协 议 和 一 些 命 消 息 , 包 括 createStream,使用默认的通信通道

    客户端发给服器端的命结构如

    段 类型 述 Command Name 符串 命 设 置 给 "createStream" Transaction ID 数 命的 ID Command Object 对象 如果在一些命信息要设 置个对象,否则置空


    服器端发给客户端的命结构如

    段 类型 述 Command Name 符串 _result 或者 _error表明回 复是一个结果是错误 Transaction ID 数 响所属的命的 ID Command Object 对象 如果在一些命信息要设 置个对象,否则置空 Stream ID 数 返回值要是一个流 ID 要 是一个错误信息对象


    7.2.2. NetStream 命

    NetStream 定了传输通道,通过个通道,音频流视频流数据消息流通过 接客户端到服端的 NetConnection 传输

    命由客户端使用 NetStream 往服器端发

    play

    play2

    deleteStream

    closeStream

    receiveAudio

    receiveVideo

    publish

    seek

    pause


    服器端使用 "onStatus" 命向客户端发 NetStream 状态

    段 类型 述 Command Name 符串 命 "onStatus" Transaction ID 数 ID 设置 0 Command Object Null onStatus 消息没有命对象
    Info Object 对象 一个 AMF 对象少要有 个 属 性 "level" ( 符 串 ) 一 消 息 的 等 级 , "warning""status""error" 中 的某个值"code" (符串) 消 息 码 , 例 如 "NetStream.Play.Start" "description" (符串)关于 个消息人类读述


    7.2.2.1. play 命

    客户端发一命到服器端播放流也多次使用一命创建一个播放列


    如果你想要创建一个动态的播放列表一在不的直播流或者录制流之间行
    换播放的话,多次调用 play 方法,并在每次调用时传递置 false相的,如果你想 要立即播放指定流,将他等播放的流清空,并置设 true

    客户端发到服器端的命结构如

    段 类型 述 Command Name 符串 命设 "play" Transaction ID 数 ID 设 0 Command Object Null 命信息不在设 null 类型 Stream Name 符串 要播放流的要播放视频 (FLV) 文,使用没有文扩 展的对流行定 ( 例 如 , "sample") 要 播 MP3 或者 ID3,你必在流 前 mp3 例 如 , "mp3:sample" 要 播 放 H.264/AAC 文,你必在 流前 mp4并指定文 扩 展 例 如 , 要 播 放 sample.m4v 文 , 定 "mp4:sample.m4v" Start 数 一个选的参数,秒单 定开始时间默认值 -2,
    表示用户首先尝试播放流段中定的直播流如果那个的直播流没有找到,它将播放的录制流如果没有那个的录制流,客户端将等一个新的那个的直播流,并当有效时行播放如果你在 Start 段中传 递 -1,那就播放流中定的那个的直播流如果 你 在 Start 段中 传递 0 或一个整数,那将从 Start 段定的时间开始播放流中定的那个录制流如果没有找到录制流,那将播放播放列表中的一 Duration 数 一个选的参数,秒单定了回放的持续时间默认值 -1-1 值意味着一个直播流会一直播放直到它不用或者一个录制流一直播放直到结束如果你传递 0 值,它将播放单一一,因播放时间已经在录制流的开始的 Start 段指定了假 定 定 在 Start 段 中 的 值 大于或者等于 0如果你传递 一个数,将播放 Duration
    段定的一段直播流之,播放状态,或者播放 Duration 段 定 的 一 段 录 制 流 ( 如 果 流 在 Duration 段 定 的时间段内结束,那流结束时回放结束)如果你在 Duration 段 中 传 递 一 个 -1 外 的 负数 的话,它将把你给的值当做 -1 处理 Reset 布尔 一个选的布尔值或者数定了是否对前的播放列表行 flush

    命执行时的消息流动是

    1. 当客户端从服器端接收到 createStream 命的结果是 success 时,发 play 命

    2. 一旦接收到 play 命,服器端发一个协议消息来设置块大小

    3. 服 器 端 发 另 一 个 协 议 消 息 ( 用 户 控 制 ) , 个 消 息 中 定 了 'StreamIsRecorded' 和流 ID消息在前两个节中保类型,在四个节中保 流 ID

    4. 服器端发另一个协议消息 (用户控制),一消息包 'StreamBegin' , 来指示发给客户端的流的起点

    5. 如 果 客 户 端 发 的 play 命 , 服 器 端 发 一 个 onStatus 命 消 息 NetStream.Play.Start & NetStream.Play.Reset有当客户端发的 play 命设置了 reset 时 服器端才会发 NetStream.Play.Reset如果要播放的流没有找到,服器端发 onStatus 消息 NetStream.Play.StreamNotFound

    之,服器端发视频和音频数据,客户端对行播放


    7.2.2.2. play2

    不于 play 命的是,play2 在不改播放内容时间轴的情况换到不的比 特率服器端客户端在 play2 中求所有支持的码率维了不的段

    客户端发给服器端的命结构如

    段 类型 述 Command Name 符串 命,设置 "play2" Transaction ID 数 ID 设置 0 Command Object Null 命信息不在,设置 null 类型 Parameters 对象 一个 AMF 编码的对象,对 象 的 属 性 是 开 的 flash.net.NetStreamPlayOptions ActionScript 对象所述的属 性


    NetStreamPlayOptions 对象的开属性在 ActionScript 3 语言指南中 [AS3] 有所述


    命执行时的消息流动如图所示




    7.2.2.3. deleteStream 命

    当 NetStream 对象消亡时 NetStream 发 deleteStream 命

    客户端发给服器端的命结构如




    段 类型 述 Command Name 符串 命 , 设 置 "deleteStream" Transaction ID 数 ID 设置 0 Command Object Null 命信息对象不在,设 null 类型 Stream ID 数 服器端消亡的流 ID


    服器端不发任何回复

    7.2.2.4. receiveAudio 命

    NetStream 通过发 receiveAudio 消息来通知服器端是否发音频到客户端

    客户端发给服器端的命结构如

    段 类型 述 Command Name 符串 命 , 设 置 "receiveAudio" Transaction ID 数 ID 设置 0 Command Object Null 命信息对象不在,设置 null 类型 Bool Flag 布尔 true 或 者 false 表 明 是 否 接音频


    如果发来的 receiveAudio 命布尔段被设 false 时服器端不发任何回复 如 果 一 标 识 被 设 true , 服 器 端 状 态 消 息 NetStream.Seek.Notify 和 NetStream.Play.Start 行回复

    7.2.2.5. receiveVideo 命

    NetStream 通过发 receiveVideo 消息来通知服器端是否发视频到客户端

    客户端发给服器端的命结构如




    段 类型 述 Command Name 符串 命 , 设 置 "receiveVideo" Transaction ID 数 ID 设置 0 Command Object Null 命信息对象不在,设置 null 类型 Bool Flag 布尔 true 或 者 false 表 明 是 否 接视频


    如果发来的 receiveVideo 命布尔段被设 false 时服器端不发任何回复 如 果 一 标 识 被 设 true , 服 器 端 状 态 消 息 NetStream.Seek.Notify 和 NetStream.Play.Start 行回复

    7.2.2.6. publish 命

    客户端发给服器端一命发布一个已命的流使用个,任意客户端都
    播放个流,并接发布的音频视频数据消息

    客户端发给服器端的命结构如

    段 类型 述 Command Name 符串 命,设置 "publish" Transaction ID 数 ID 设置 0 Command Object Null 命信息对象不在,设置 null 类型 Publishing Name 符串 发布的流的 Publishing Type 符串 发 布 类 型 设 置 "live" "record" 或 者 "append"record流被发布,
    数据被录制到一个新的文
    新文被储在服器包
    服用目录的子路如
    果 文 已 在 , 将 写
    append流被发布,数据被添
    到一个文如果文没
    找着,将新建一个live直
    播数据被发布,并不对
    行录制


    服器端回复 onStatus 命标注发布的起始置

    7.2.2.7. seek 命

    客户端发 seek 命查找一个多媒体文或一个播放列表的偏移量 (毫秒单 )

    客户端发到服器端的命结构如

    段 类型 述 Command Name 符串 命的,设 "seek" Transaction ID 数 ID 设 0 Command Object Null 没有命信息对象,设置 null 类型 milliSeconds 数 播放列表查找的毫秒数


    seek 命执行时服器会发一个状态消息 NetStream.Seek.Notify失败的话, 服器端返回一个 _error 消息


    7.2.2.8. pause 命

    客户端发 pause 命告知服器端是暂停是开始播放

    客户端发给服器端的命结构如

    段 类型 述 Command Name 符串 命,设 "pause" Transaction ID 数 没有一命的 ID,设 0 Command Object Null 命信息对象不在,设 null 类型 Pause/Unpause Flag 布尔 true 或者 false,来指示暂停 或者新播放 milliSeconds 数 流暂停或者新开始所在的
    毫秒数个是客户端暂停的
    当前流时间当回放已恢复
    时,服器端值发有比
    个值大的 timestamp 消息

    当 流 暂 停 时 , 服 器 端 发 一 个 状 态 消 息 NetStream.Pause.Notify NetStream.Unpause.Notify 有针对没有暂停的流行发放失败的话,服器端返回一个 _error 消息

    7.3. 消息交换例子

    有几个解释使用 RTMP 交换消息的例子

    7.3.1. 发布录制视频

    个例子说明了一个客户端是如何能够发布一个直播流然传递视频流到服器的然
    他客户端对发布的流行阅并播放视频



    7.3.2. 广播一个共享对象消息

    个例子说明了在一个共享对象的创建和改期间交换消息的化它也说明了共享对
    象消息广播的处理过程 

    7.3.3. 发布来自录制流的元数据

    个例子述了用于发布元数据的消息交换


    8. 参考文献

    [RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791, September 1981.

    [RFC0793] Postel, J., "Transmission Control Protocol", STD 7,RFC 793, September 1981.

    [RFC1982] Elz, R. and R. Bush, "Serial Number Arithmetic", RFC 1982, August 1996.

    [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.

    [AS3] Adobe Systems, Inc., "ActionScript 3.0 Reference for the Adobe Flash Platform", 2011, <http://www.adobe.com/devnet/actionscript/documentation.html>.

    [AMF0] Adobe Systems, Inc., "Action Message Format -- AMF 0", December 2007, <http://opensource.adobe.com/wiki/download/attachments/1114283/amf0_spec_121207.pdf>.

    [AMF3] Adobe Systems, Inc., "Action Message Format -- AMF 3", May 2008, <http://opensource.adobe.com/wiki/download/attachments/1114283/amf3_spec_05_05_08.pdf>.

    转载于:https://www.cnblogs.com/bugutian/p/10773249.html

    展开全文
  • rtmp直播nginx配置文件

    2016-09-13 17:02:07
    nginx-rtmp支持
  • 译序:截至 Jul 8th,2013 官方公布的最新 Nginx RTMP 模块 nginx-rtmp-module 指令详解。指令Corertmp 语法:rtmp { ... } 上下文:根 描述:保存所有 RTMP 配置的块。server 语法:server { ... } 上下文:rtmp ...

    译序:截至 Jul 8th,2013 官方公布的最新 Nginx RTMP 模块 nginx-rtmp-module 指令详解。
    指令
    Core
    rtmp
    语法:rtmp { ... }
    上下文:根
    描述:保存所有 RTMP 配置的块。
    server
    语法:server { ... }
    上下文:rtmp
    描述:声明一个 RTMP 实例。
    rtmp {
      server {
      }
    }

    listen
    语法:listen (addr[:port]|port|unix:path) [bind] [ipv6only=on|off] [so_keepalive=on|off|keepidle:keepintvl:keepcnt]
    上下文:server
    描述:给 NGINX 添加一个监听端口以接收 RTMP 连接。
    server {
        listen 1935;
    }

    application
    语法:application name { ... }
    上下文:server
    描述:创建一个 RTMP 应用。application 名的模式并不类似于 http location。
    server {
        listen 1935;
        application myapp {
        }
    }

    timeout
    语法:timeout value
    上下文:rtmp, server
    描述:Socket 超时。这个值主要用于写数据时。大多数情况下,RTMP 模块并不期望除 publisher 端口之外的其他端口处于活动状态。如果你想要快速关掉 socket 可以用 keepalive 或者 RTMP ping 等。timeout 默认值为 1 分钟。
    timeout 60s;
    ping
    语法:ping value
    上下文:rtmp, server
    描述:RTMP ping 间隔。零值的话将 ping 关掉。RTMP ping 是一个用于检查活动连接的协议功能。发送一个特殊的包到远程连接,然后在 ping_timeout 指令指定的时间内期待一个回复。如果在这个时间里没有收到 ping 回复,连接断开。ping 默认值为一分钟。ping_timeout 默认值为 30 秒。
    ping 3m;
    ping_timeout 30s;

    ping_timeout
    语法:ping_timeout value
    上下文:rtmp, server
    描述:请参考上文 ping 描述。
    max_streams
    语法:max_streams value
    上下文:rtmp, server
    描述:设置 RTMP 流的最大数目。数据流被整合到一个单一的数据流里。不同的频道用于发送命令、音频、视频等。默认值为 32,适用于大多数情况。
    max_streams 32;
    ack_window
    语法:ack_window value
    上下文:rtmp, server
    描述:设置 RTMP 确认视窗大小。这是对端发送确认包到远端后应该收到的字节数量。默认值为 5000000。
    ack_window 5000000;
    chunk_size
    语法:chunk_size value
    上下文:rtmp, server
    描述:流整合的最大的块大小。默认值为 4096。这个值设置的越大 CPU 负载就越小。这个值不能低于 128。
    chunk_size 4096;
    max_queue
    语法:max_queue value
    上下文:rtmp, server
    描述:输入数据报文最大尺寸。所有输入数据会被分割成报文(然后进一步分割为块)。报文在处理结束之前会放在内存里。理论上讲,接收到的报文很大的话对于服务器的稳定性可能会有影响。默认值 1M 对于大多数情况就足够了。
    max_message 1M;
    out_queue
    out_cork

    Access
    allow
    语法:allow [play|publish] address|subnet|all
    上下文:rtmp, server, application
    允许来自指定地址或者所有地址发布/播放。allow 和 deny 指令的先后顺序可选。
    allow publish 127.0.0.1;
    deny publish all;
    allow play 192.168.0.0/24;
    deny play all;

    deny
    语法:deny [play|publish] address|subnet|all
    上下文:rtmp, server, application
    描述:参考 allow 的描述。
    Exec
    exec
    语法:exec command arg*
    上下文:rtmp, server, application
    描述:定义每个流发布时要执行的带有参数的外部命令。发布结束时进程终止。第一个参数应该是二进制可执行文件的完整路径。关于这个进程将会做些什么事没有任何假定。但这一特点在使用 ffmpeg 进行流转换时是很有用的。FFmpeg 被假定作为客户端连接到 nginx-rtmp 然后作为发布者输出转换流到 nginx-rtmp。类似于 $var/${var} 形式的替换可以在命令行使用:
    * $name - 流的名字。
    * $app - 应用名。
    * $addr - 客户端地址。
    * $flashver - 客户端 flash 版本。
    * $swfurl - 客户端 swf url。
    * $tcurl - 客户端 tc url。
    * $pageurl - 客户端页面 url。
    可以在 exec 指令中定义 Shell 格式的转向符用于写输出和接收输入。支持如下
    * 截断输出 >file。
    * 附加输出 >>file。
    * 重定向描述符类似于 1>&2。
    * 输入 <file。
    以下 ffmpeg 调用将输入流转码为 HLS-ready 流(H264/AAC)。运行这个示例,FFmpeg 须编译为支持 libx264 & libfaac。
    application src {
        live on;
        exec ffmpeg -i rtmp://localhost/src/$name -vcodec libx264 -vprofile baseline -g 10 -s 300x200 -acodec libfaac -ar 44100 -ac 1 -f flv rtmp://localhost/hls/$name 2>>/var/log/ffmpeg-$name.log;
    }


    application hls {
        live on;
        hls on;
        hls_path /tmp/hls;
        hls_fragment 15s;
    }

    exec_static
    语法:exec_static command arg*
    上下文:rtmp, server, application
    描述:类似于 exec 指令,但在 nginx 启动时将运行定义的命令。因为(启动时)尚无会话上下文,不支持替换。
    exec_static ffmpeg -i http://example.com/video.ts -c copy -f flv rtmp://localhost/myapp/mystream;
    exec_kill_signal
    语法:exec_kill_signal signal
    上下文:rtmp, server, application
    描述:设置进程终止信号。默认为 kill(SIGKILL)。你可以定义为数字或者符号名(POSIX.1-1990 信号)。
    exec_kill_signal term;
    exec_kill_signal usr1;
    exec_kill_signal 3;

    respawn
    语法:respawn on|off
    上下文:rtmp, server, application
    描述:如果打开 respawn 子进程,进程终止时发布会仍然继续。默认为打开。
    respawn off;
    respawn_timeout
    语法:respawn_timeout timeout
    上下文:rtmp, server, application
    描述:启动新的子实例之前,设置 respawn 超时时间。默认为五秒。
    respawn_timeout 10s;
    exec_publish
    语法:exec_publish command arg*
    上下文:rtmp, server, application
    描述:指定发布事件触发的带有参数的外部命令。返回码是未解析的。这里可以用 exec 替换。另外,args 变量支持持有查询字符串参数。
    exec_play
    语法:exec_play command arg*
    上下文:rtmp, server, application
    描述:指定播放事件触发的带有参数的外部命令。返回码是未解析的。替换列表同 exec_publish。
    exec_play_done
    语法:exec_play_done command arg*
    上下文:rtmp, server, application
    描述:指定播放结束事件触发的带有参数的外部命令。返回码是未解析的。替换列表同 exec_publish。
    exec_publish_done
    语法:exec_publish_done command arg*
    上下文:rtmp, server, application
    描述:指定发布结束事件触发的带有参数的外部命令。返回码是未解析的。替换列表同 exec_publish。
    exec_record_done
    语法:exec_record_done command arg*
    上下文:rtmp, server, application, recorder
    描述:指定录制结束时触发的带有参数的外部命令。这里支持 exec_publish 的替代以及额外的变量 path 和 recorder。
    # track client info
    exec_play bash -c "echo $addr $pageurl >> /tmp/clients";
    exec_publish bash -c "echo $addr $flashver >> /tmp/publishers";


    # convert recorded file to mp4 format
    exec_record_done ffmpeg -y -i $path -acodec libmp3lame -ar 44100 -ac 1 -vcodec libx264 $path.mp4;

    Live
    live
    语法:live on|off
    上下文:rtmp, server, application
    描述:切换直播模式,即一对多广播。
    live on;
    meta
    语法:meta on|off
    上下文:rtmp, server, application
    描述:切换发送元数据到客户端。默认为 on。
    meta off;
    interleave
    语法:interleave on|off
    上下文:rtmp, server, application
    描述:切换交叉模式。在这个模式下,音频和视频数据会在同一个 RTMP chunk 流中传输。默认为 off。
    interleave on;
    wait_key
    语法:wait_key on|off
    上下文:rtmp, server, application
    描述:使视频流从一个关键帧开始。默认为 off。
    wait_key on;
    wait_video
    语法:wait_video on|off
    上下文:rtmp, server, application
    描述:在第一个视频帧发送之前禁用音频。默认为 off。可以和 wait_key 进行组合以使客户端可以收到具有所有其他数据的视频关键帧。然而这通常增加连接延迟。您可以通过在编码器中调整关键帧间隔来减少延迟。
    wait_video on;
    publish_notify
    语法:publish_notify on|off
    上下文:rtmp, server, application
    描述:发送 NetStream.Publish.Start 和 NetStream.Publish.Stop 给用户。默认为 off。
    publish_notify on;
    drop_idle_publisher
    语法:drop_idle_publisher timeout
    上下文:rtmp, server, application
    描述:终止指定时间内闲置(没有音频/视频数据)的发布连接。默认为 off。注意这个仅仅对于发布模式的连接起作用(发送 publish 命令之后)。
    drop_idle_publisher 10s;
    sync
    语法:sync timeout
    上下文:rtmp, server, application
    描述:同步音频和视频流。如果用户带宽不足以接收发布率,服务器会丢弃一些帧。这将导致同步问题。当时间戳差超过 sync 指定的值,将会发送一个绝对帧来解决这个问题。默认为 300 ms。
    sync 10ms;
    play_restart
    语法:play_restart on|off
    上下文:rtmp, server, application
    描述:使 nginx-rtmp 能够在发布启动或停止时发送 NetStream.Play.Start 和 NetStream.Play.Stop 到每个用户。如果关闭的话,那么每个用户就只能在回放的开始和结束时收到这些通知了。默认为 on。
    play_restart off;
    Record
    record
    语法:record [off|all|audio|video|keyframes|manual]*
    上下文:rtmp, server, application, recorder
    描述:切换录制模式。流可以被记录到 flv 文件。本指令指定应该被记录的:
    * off - 什么也不录制
    * all - 音频和视频(所有)
    * audio - 音频
    * video - 视频
    * keyframes - 只录制关键视频帧
    * manual - 用不自动启动录制,使用控制接口来启动/停止
    在单个记录指令中可以有任何兼容的组合键。
    record all;


    record audio keyframes;

    record_path
    语法:record_path path
    上下文:rtmp, server, application, recorder
    描述:指定录制的 flv 文件存放目录。
    record_path /tmp/rec;
    record_suffix
    语法:record_suffix value
    上下文:rtmp, server, application, recorder
    描述:设置录制文件后缀名。默认为 '.flv'。
    record_suffix _recorded.flv;
    录制后缀可以匹配 strftime 格式。以下指令
    record_suffix -%d-%b-%y-%T.flv
    将会产生形如 mystream-24-Apr-13-18:23:38.flv 的文件。所有支持 strftime 格式的选项可以在 strftime man page 里进行查找。
    record_unique
    语法:record_unique on|off
    上下文:rtmp, server, application, recorder
    描述:是否添加时间戳到录制文件。否则的话同样的文件在每一次新的录制发生时将被重写。默认为 off。
    record_unique on;
    record_append
    语法:record_append on|off
    上下文:rtmp, server, application, recorder
    描述:切换文件附加模式。当这一指令为开启是,录制时将把新数据附加到老文件,如果老文件丢失的话将重新创建一个。文件中的老数据和新数据没有时间差。默认为 off。
    record_append on;
    record_lock
    语法:record_lock on|off
    上下文:rtmp, server, application, recorder
    描述:当这一指令开启时,当前录制文件将被 fcntl 调用锁定。那样可以在其他地方来核实哪个文件正在进行录制。默认为 off。
    record_lock on;
    在 FreeBSD 上你可以使用 flock 工具检查。在 Linux 上 flock 和 fcntl 无关,因此你需要去写一个简单的脚本来检查文件的锁定状态。以下 isunlocked.py 是一个这样的脚本的示例。

     
    1. #!/usr/bin/python

    2.  
    3.  
    4. import fcntl, sys

    5.  
    6.  
    7. sys.stderr.close()

    8. fcntl.lockf(open(sys.argv[1], "a"), fcntl.LOCK_EX|fcntl.LOCK_NB)


    record_max_size
    语法:record_max_size size
    上下文:rtmp, server, application, recorder
    描述:设置录制文件的最大值。
    record_max_size 128K;
    record_max_frames
    语法:record_max_frames nframes
    上下文:rtmp, server, application, recorder
    描述:设置每个录制文件的视频帧的最大数量。
    record_max_frames 2;
    record_interval
    语法:record_interval time
    上下文:rtmp, server, application, recorder
    描述:在这个指令指定数量的(毫秒)秒之后重启录制。默认为 off。设置为 0 的话意味着录制中无延迟。如果 record_unique 为 off 的话所有记录片段会被写到同一个文件。否则(文件名)将附以时间戳以区分不同文件(给定的 record_interval 要大于 1 秒)。
    record_interval 1s;


    record_interval 15m;

    recorder
    语法:recorder name {...}
    上下文:application
    描述:创建录制块。可以在单个 application 中创建多个记录。上文提到的所有录制相关的指令都可以在 recorder{} 块中进行定义。继承高层次中的所有设置。
    application {
        live on;


        # default recorder
        record all;
        record_path /var/rec;


        recorder audio {
            record audio;
            record_suffix .audio.flv;
        }


        recorder chunked {
            record all;
            record_interval 15s;
            record_path /var/rec/chunked;
        }
    }

    record_notify
    语法:record_notify on|off
    上下文:rtmp, server, application, recorder
    描述:切换当定义录制启动或停止文件时发送 NetStream.Record.Start 和 NetStream.Record.Stop 状态信息(onStatus)到发布者。状态描述字段保存录制的名字(默认录制的话为空)。默认为 off。
    recorder myrec {
        record all manual;
        record_path /var/rec;
        record_notify on;
    }

    VOD
    play
    语法:lay dir|http://loc [dir|http://loc]*
    上下文:rtmp, server, application
    描述:播放指定目录或者 HTTP 地址的 flv 或者 mp4 文件。如果此参数前缀是 http:// 那么就认为文件可以在播放前从远程 http 地址下载下来。注意播放是在整个文件下载完毕之后才开始。你可以使用本地 nginx 在本地机器缓存文件。
    同一个 play 指令可以定义多个播放地址。当多个 play 指令定义时,地址列表将被合并,并进行从更高域中继承。尝试播放每一个地址,直到发现一个成功的地址。如果没有找到成功地址,将发送错误状态到客户端。
    索引的 FLV 播放具有随机查找能力。没有索引的 FLV 则不具备查找/暂停能力(重播模式)。使用 FLV 索引器(比如 yamdi)来编索引。
    mp4 文件只有在音频和视频编码都被 RTMP 支持时才可以播放。最常见的情况是 H264/AAC。
    application vod {
        play /var/flvs;
    }


    application vod_http {
        play http://myserver.com/vod;
    }


    application vod_mirror {
        # try local location first, then access remote location
        play /var/local_mirror http://myserver.com/vod;
    }

    播放 /var/flvs/dir/file.flv:

    ffplay rtmp://localhost/vod/dir/file.flv


    play_temp_path
    语法:play_temp_path dir
    上下文:rtmp, server, application
    描述:在播放之前设置远程存储的 VOD 文件路径。默认为 /tmp。
    play_temp_path /www;
    play http://example.com/videos;

    play_local_path
    语法:play_local_path dir
    上下文:rtmp, server, application
    描述:设置远程 VOD 文件完全下载之后复制于 play_temp_path 之后的路径。空值的话禁用此功能。默认为控制。这个功能可以用于缓存远程文件在本地。
    这一路径应该和 play_temp_path 处于同一设备。
    # search file in /tmp/videos.
    # if not found play from remote location
    # and store in /tmp/videos


    play_local_path /tmp/videos;
    play /tmp/videos http://example.com/videos;

    Relay
    pull
    语法:pull url [key=value]*
    上下文:application
    描述:创建 pull 中继。流将从远程服务器上拉下来,成为本地可用的。仅当至少有一个播放器正在播放本地流时发生。
    Url 语法:[rtmp://]host[:port][/app[/playpath]]。如果 application 找不着那么将会使用本地 application 名。如果找不着 playpath 那么就是用当前流的名字。
    支持以下参数:
    * app - 明确 application 名。
    * name - 捆绑到 relay 的本地流名字。如果为空或者没有定义,那么将会使用 application 中的所有本地流。
    * tcUrl - 如果为空的话自动构建。
    * pageUrl - 模拟页面 url。
    * swfUrl - 模拟 swf url。
    * flashVer - 模拟 flash 版本,默认为 'LNX.11,1,102,55'。
    * playPath - 远程播放地址。
    * live - 切换直播特殊行为,值:0,1。
    * start - 开始时间。
    * stop - 结束时间。
    * static - 创建静态 pull,这样的 pull 在 nginx 启动时创建。
    如果某参数的值包含空格,那么你应该在整个 key=value 对周围使用引号,比如:'pageUrl=FAKE PAGE URL'。
    pull rtmp://cdn.example.com/main/ch?id=12563 name=channel_a;


    pull rtmp://cdn2.example.com/another/a?b=1&c=d pageUrl=http://www.example.com/video.html swfUrl=http://www.example.com/player.swf live=1;


    pull rtmp://cdn.example.com/main/ch?id=12563 name=channel_a static;

    push
    语法:push url [key=value]*
    上下文:application
    描述:push 的语法和 pull 一样。不同于 pull 指令的是 push 推送发布流到远程服务器。
    push_reconnect
    语法:push_reconnect time
    上下文:rtmp, server, application
    描述:在断开连接后,在 push 重新连接前等待的时间。默认为 3 秒。
    push_reconnect 1s;
    session_relay
    语法:session_relay on|off
    上下文:rtmp, server, application
    描述:切换会话 relay 模式。在这种模式下连接关闭时 relay 销毁。当设置为 off 时,流关闭,relay 销毁,这样子以后另一个 relay 可以被创建。默认为 off。
    session_relay on;
    Notify
    on_connect
    语法:on_connect url
    上下文:rtmp, server
    描述:设置 HTTP 连接回调。当客户分发连接命令一个连接命令时,一个 HTTP 请求异步发送,命令处理将被暂停,直到它返回结果代码。当 HTTP 2XX 码(成功状态码)返回时,RTMP 会话继续。返回码 3XX (重定向状态码)会使 RTMP 重定向到另一个从 HTTP 返回头里获取到的 application。否则(其他状态码)连接丢弃。
    注意这一指令在 application 域是不允许的,因为 application 在连接阶段还是未知的。
    HTTP 请求接收到一些参数。在 application/x-www-form-urlencoded MIME 类型下使用 POST 方法。以下参数将被传给调用者:
    * call=connect。
    * addr - 客户端 IP 地址。
    * app - application 名。
    * flashVer - 客户端 flash 版本。
    * swfUrl - 客户端 swf url。
    * tcUrl - tcUrl。
    * pageUrl - 客户端页面 url。
    除了上述参数以外,所有显式传递给连接命令的参数也由回调发送。你应该将连接参数和 play/publish 参数区分开。播放器常常有独特的方式设置连接字符串不同于 play/publish 流名字。这里是 JWPayer 是如何设置这些参数的一个示例:

     
    1. ...

    2. streamer: "rtmp://localhost/myapp?connarg1=a&connarg2=b",

    3. file: "mystream?strarg1=c&strarg2=d",

    4. ...


    Ffplay(带有 librtmp)示例:

    ffplay "rtmp://localhost app=myapp?connarg1=a&connarg2=b playpath=mystream?strarg1=c&strarg2=d"


    使用例子:
    on_connect http://example.com/my_auth;
    重定向例子:
    location /on_connect {
        if ($arg_flashver != "my_secret_flashver") {
            rewrite ^.*$ fallback? permanent;
        }
        return 200;
    }

    on_play
    语法:on_play url
    上下文:rtmp, server, application
    描述:设置 HTTP 播放回调。每次一个客户分发播放命令时,一个 HTTP 请求异步发送,命令处理会挂起 - 直到它返回结果码。之后再解析 HTTP 结果码。
    * HTTP 2XX 返回码的话继续 RTMP 会话。
    * HTTP 3XX 返回码的话 重定向 RTMP 到另一个流,这个流的名字在 HTTP 返回头的 Location 获取。如果新流的名字起始于 rtmp:// 然后远程 relay 会被创建。relay 要求 IP 地址是指定的而不是域名,并且只工作在 1.3.10 版本以上的 nginx。另请参考 notify_relay_redirect。
    * 其他返回码的话 RTMP 连接丢弃。
    重定向例子:
    http {
        ...
        location /local_redirect {
            rewrite ^.*$ newname? permanent;
        }
        location /remote_redirect {
            # no domain name here, only ip
            rewrite ^.*$ rtmp://192.168.1.123/someapp/somename? permanent;
        }
        ...
    }


    rtmp {
        ...
        application myapp1 {
            live on;
            # stream will be redirected to 'newname'
            on_play http://localhost:8080/local_redirect;
        }
        application myapp2 {
            live on;
            # stream will be pulled from remote location
            # requires nginx >= 1.3.10
            on_play http://localhost:8080/remote_redirect;
        }
        ...
    }

    HTTP 请求接收到一些个参数。在 application/x-www-form-urlencoded MIME 类型下使用 POST 方法。以下参数会被传送给调用者:
    * call=play。
    * addr - 客户端 IP 地址。
    * app - application 名。
    * flashVer - 客户端 flash 版本。
    * swfUrl - 客户端 swf url。
    * tcUrl - tcUrl。
    * pageUrl - 客户端页面 url。
    * name - 流名。
    出了上述参数之外其他所有播放命令参数显式地发送回调。例如如果一个流由 url rtmp://localhost/app/movie?a=100&b=face&foo=bar 访问,然后呢 a,b 和 foo 发送回调。
    on_play http://example.com/my_callback;
    on_publish
    语法:on_publish url
    上下文:rtmp, server, application
    描述:同上面提到的 on_play 一样,唯一的不同点在于这个指令在发布命令设置回调。不同于远程 pull,push 在这里是可以的。
    on_done
    语法:on_done url
    上下文:rtmp, server, application
    描述:设置播放/发布禁止回调。上述所有适用于此。但这个回调并不检查 HTTP 状态码。
    on_play_done
    语法:on_publish_done url
    上下文:rtmp, server, application
    描述:等同于 on_done 的表现,但只适用于播放结束事件。
    on_publish_done
    语法:on_publish_done url
    上下文:rtmp, server, application
    描述:等同于 on_done 的表现,但只适用于发布结束事件。
    on_record_done
    语法:on_record_done url
    上下文:rtmp, server, application, recorder
    描述:设置 record_done 回调。除了普通 HTTP 回调参数它接受录制文件路径。
    on_record_done http://example.com/recorded;
    on_update
    语法:on_update url
    上下文:rtmp, server, application
    描述:设置 update 回调。这个回调会在 notify_update_timeout 期间调用。如果一个请求返回结果不是 2XX,连接禁止。这可以用来同步过期的会话。追加 time 参数即播放/发布调用后的秒数会被发送给处理程序。
    on_update http://example.com/update;
    notify_update_timeout
    语法:notify_update_timeout timeout
    上下文:rtmp, server, application
    描述:在 on_update 回调之间的超时设置。默认为 30 秒。
    notify_update_timeout 10s;
    on_update http://example.com/update;

    notify_update_strict
    语法:notify_update_strict on|off
    上下文:rtmp, server, application
    描述:切换 on_update 回调严格模式。默认为 off。当设置为 on 时,所有连接错误,超时以及 HTTP 解析错误和空返回会被视为更新失败并导致连接终止。当设置为 off 时只有 HTTP 返回码不同于 2XX 时导致失败。
    notify_update_strict on;
    on_update http://example.com/update;

    notify_relay_redirect
    语法:notify_relay_redirect on|off
    上下文:rtmp, server, application
    描述:使本地流可以重定向为 on_play 和 on_publish 远程重定向。新的流名字是 RTMP URL 用于远程重定向。默认为 off。
    notify_relay_redirect on;
    notify_method
    语法:notify_method get|post
    上下文:rtmp, server, application, recorder
    描述:设置 HTTP 方法通知。默认是带有 application/x-www-form-urlencoded 的 POST 内容类型。在一些情况下 GET 更好,例如如果你打算在 nginx 的 http{} 部分处理调用。在这种情况下你可以使用 arg_* 变量去访问参数。
    notify_method get;
    在 http{} 部分使用 GET 方法处理通知可以使用这种方法:
    location /on_play {
        if ($arg_pageUrl ~* localhost) {
            return 200;
        }
        return 500;
    }

    HLS
    hls
    语法:hls on|off
    上下文:rtmp, server, application
    描述:在 application 切换 HLS。
    hls on;
    hls_path /tmp/hls;
    hls_fragment 15s;

    在 http{} 段为客户端播放 HLS 设置在以下位置设置:
    http {
        ...
        server {
            ...
            location /hls {
                types {
                    application/vnd.apple.mpegurl m3u8;
                }
                alias /tmp/hls;
            }
        }
    }

    hls_path
    语法:hls_path path
    上下文:rtmp, server, application
    描述:设置 HLS 播放列表和分段目录。这一目录必须在 NGINX 启动前就已存在。
    hls_fragment
    语法:hls_fragment time
    上下文:rtmp, server, application
    描述:设置 HLS 分段长度。默认为 5 秒钟。
    hls_playlist_length
    语法:hls_playlist_length time
    上下文:rtmp, server, application
    描述:设置 HLS 播放列表长度。默认为 30 秒钟。
    hls_playlist_length 10m;
    hls_sync
    语法:hls_sync time
    上下文:rtmp, server, application
    描述:设置 HLS 时间戳同步阈值。默认为 2 ms。这一功能可以防止由低分辨率 RTMP (1KHz) 转换到高分辨率 MPEG-TS (90KHz) 之后出现噪音。
    hls_sync 100ms;
    hls_continuous
    语法:hls_continuous on|off
    上下文:rtmp, server, application
    描述:切换 HLS 连续模式。这一模式下 HLS 序列号由其上次停止的最后时间开始。老的分段保留下来。默认为 off。
    hls_continuous on;
    hls_nested
    语法:hls_nested on|off
    上下文:rtmp, server, application
    描述:切换 HLS 嵌套模式。这一模式下为每个流创建了一个 hls_path 的子目录。播放列表和分段在那个子目录中创建。默认为 off。
    hls_nested on;
    hls_cleanup
    语法:hls_cleanup on|off
    上下文:rtmp, server, application
    描述:切换 HLS 清理。这一功能默认为开启的。在这一模式下 nginx 缓存管理进程将老的 HLS 片段和播放列表由 HLS 清理掉。
    hls_cleanup off;
    Access log
    access_log
    语法:access_log off|path [format_name]
    上下文:rtmp, server, application
    描述:设置访问日志参数。日志默认是开启的。关闭日志可以使用 access_log off 指令。默认情况下访问日志和 HTTP 访问日志 logs/access.log 放到同一文件。你也可以使用 access_log 指令将其定义到其他日志文件。第二个参数是可选的。可以根据名字来定义日志格式。请参考 log_format 指令来获取更多关于格式的详细信息。
    log_format new '$remote_addr';
    access_log logs/rtmp_access.log new;
    access_log logs/rtmp_access.log;
    access_log off;

    log_format
    语法:log_format format_name format
    上下文:rtmp
    描述:创建指定的日志格式。日志格式看起来很像 nginx HTTP 日志格式。日志格式里支持的几个变量有:
    * connection - 连接数。
    * remote_addr - 客户端地址。
    * app - application 名。
    * name - 上一个流名。
    * args - 上一个流播放/发布参数。
    * flashver - 客户端 flash 版本。
    * swfurl - 客户端 swf url。
    * tcurl - 客户端 tcUrl。
    * pageurl - 客户端页面 url。
    * command - 客户端发送的播放/发布命令:NONE、PLAY、PUBLISH、PLAY+PUBLISH。
    * bytes_sent - 发送到客户端的字节数。
    * bytes_received - 从客户端接收到的字节数。
    * time_local - 客户端连接结束的本地时间。
    * session_time - 持续连接的秒数。
    * session_readable_time - 在可读格式下的持续时间。
    默认的日志格式叫做 combined。这里是这一格式的定义:
    $remote_addr [$time_local] $command "$app" "$name" "$args" - 
    $bytes_received $bytes_sent "$pageurl" "$flashver" ($session_readable_time)

    Limits
    max_connections
    语法:max_connections number
    上下文:rtmp, server, application
    描述:为 rtmp 引擎设置最大连接数。默认为 off。
    max_connections 100;
    Statistics
    statistics 模块不同于本文列举的其他模块,它是 NGINX HTTP 模块。因此 statistics 指令应该位于 http{} 块内部。
    rtmp_stat
    语法:rtmp_stat all
    上下文:http, server, location
    描述:为当前 HTTP location 设置 RTMP statistics 处理程序。RTMP statistics 是一个静态的 XML 文档。可以使用 rtmp_stat_stylesheet 指令在浏览器中作为 XHTML 页面查看这个文档。
    http {
        server {
            location /stat {
                rtmp_stat all;
                rtmp_stat_stylesheet stat.xsl;
            }
            location /stat.xsl {
                root /path/to/stat/xsl/file;
            }
        }
    }

    rtmp_stat_stylesheet
    语法:rtmp_stat_stylesheet path
    上下文:http, server, location
    描述:添加 XML 样式表引用到 statistics XML 使其可以在浏览器中可视。更多信息请参考 rtmp_stat 描述和例子。
    Multi-worker live streaming
    多 worker 直播流是通过推送流到剩余的 nginx worker 实现的。
    rtmp_auto_push
    语法:rtmp_auto_push on|off
    上下文:root
    描述:切换自动推送(多 worker 直播流)模式。默认为 off。
    rtmp_auto_push_reconnect
    语法:rtmp_auto_push_reconnect timeout
    上下文:root
    描述:当 worker 被干掉时设置自动推送连接超时时间。默认为 100 毫秒。
    rtmp_socket_dir
    语法:rtmp_socket_dir dir
    上下文:root
    描述:设置用于流推送的 UNIX 域套接字目录。默认为 /tmp。
    rtmp_auto_push on;
    rtmp_auto_push_reconnect 1s;
    rtmp_socket_dir /var/sock;


    rtmp {
        server {
            listen 1935;
            application myapp {
                live on;
            }
        }
    }

    Control
    control 模块是 NGINX HTTP 模块,应该放在 http{} 块之内。
    rtmp_control
    语法:rtmp_control all
    上下文:http, server, location
    描述:为当前 HTTP location 设置 RTMP 控制程序。
    http {
        server {
            location /control {
                rtmp_control all;
            }
        }
    }

    展开全文
  • rtmp协议规范详解

    千次阅读 2018-01-17 15:49:40
    本篇文章大部分是rtmp协议1.0版本的翻译,翻译参考了网上的版本,加了一些抓包分析。 Adobe公司的实时消息传输协议 摘要  此备忘录描述了 Adobe公司的实时消息传输协议(RTMP),此协议从属于应用层,被用来...
  • RTMP协议详解

    2018-07-30 15:20:35
    流媒体协议:RTMP协议(中文)详解 流媒体协议:RTMP协议(中文)详解
  • rtmp协议详解

    千次阅读 2019-03-23 17:55:32
    最近在学习rtmp协议,在看官方文档的时候总是懵懵懂懂,硬生生看了两天,现在基本上了解rtmp协议了,想用自己觉得比较清晰的方式来讲解rtmp协议,希望能够对向我一样的初学者有所帮助。 本文将通过以下四部分讲解...
  • 流媒体协议:RTMP协议(中文)详解 流媒体协议:RTMP协议(中文)详解 流媒体协议:RTMP协议(中文)详解
  • rtmp协议详解和例子(带书签)! 很不错的资料哦!
  • The document specifies the Real Time Messaging Protocol Chunk Stream(RTMP Chunk Stream). It provides multiplexing and packetizing services for a higher-level multimedia stream protocol
  • RTMP协议详解及实例分析

    千次阅读 2020-08-17 17:19:54
    RTMP协议是Real Time Message Protocol(实时信息传输协议)的缩写,它是由Adobe公司提出的一种应用层的协议,用来解决多媒体数据传输流的多路复用(Multiplexing)和分包(packetizing)的问题。实现通常对不同类型...
  • 最近的直播很火,所以这篇文章跟大家分享了在Mac上搭建nginx+rtmp直播服务器的步骤,文章通过一步步图文介绍的很详细,有需要的朋友们可以参考借鉴。
  • nginx核心详解

    2014-10-18 22:36:47
    nginx核心详解电子书,描述nginx的原理、内部机制。
  • Rtmp Chunk详解

    2020-03-13 07:59:55
    RTMP协议中基本的数据单元称为消息(Message)。当RTMP协议在互联网中传输数据的时候,消息会被拆分成更小的单元,称为消息块(Chunk)。 每个块必须完整的发送后才能发送下一个块。接收端根据快流ID把块组装成完整...
  • Nginx配合插件nginx-rtmp-module可以做RTMP流媒体服务器,实现RTMP的拉流和推流。本方案可以用于摄像头通过4G/5G DTU模块推流RTMP到云服务器上的nginx服务器,然后通过web查看摄像头实时数据;配合DTU推流模块可以...
  • rtmpdump命令行详解

    千次阅读 2020-10-31 13:23:26
    文章目录rtmpdump使用说明命令行语法选项网络参数连接参数会话参数安全参数杂项退出状态环境变量 rtmpdump使用说明 ​ rtmpdump是一个命令行工具,它可以接收通过RTMP协议传输的流媒体内容,并转存下来。 ​ rtmp...
  • Rtmp协议中文介绍

    2017-12-12 10:02:24
    消息块流是为 Rtmp协议设计的,他可以处理任何传送消息流的协议,每一个消息包含时间戳 合有效负载类型标示, 消息块流和 一起适用于多样性音视频应用程序,从一对一和一对 多向视频点播服务器直接广播到交互式会议...
  • 本资源包含两个 pdf 文档,一本官方最新版的 rtmp_specification_1.0.pdf,一个中文翻译的 rtmp_specification_1.0_cn.pdf
  • RTMP规范简单分析

    万次阅读 多人点赞 2013-09-14 20:56:45
    RTMP协议是一个互联网TCP/IP五层体系结构中应用层的协议。RTMP协议中基本的数据单元称为消息(Message)。当RTMP协议在互联网中传输数据的时候,消息会被拆分成更小的单元,称为消息块(Chunk)。 1 消息 消息是RTMP...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,314
精华内容 925
关键字:

rtmp详解