rtmp推流_rtmp推流地址 - CSDN
精华内容
参与话题
  • 网页html直播,推流和接受流都有,通过RTMP, 需要运行在服务器上,不能直接打开,
  • Rtmp客户端推流工具

    2020-07-30 23:31:59
    基于librtmp库的rtmp推流客户端,客户端使用步骤简单,推送数据时将H264码流输送到API接口中数据即会被打包然后推送到指定的rtmp url地址上。
  • 介绍一个基于C++开发的RTSP/RTMP推流组件PushStream,PushStream推流基础组件是一款推送流媒体音/视频流给标准RTSP流媒体服务器 (如EasyDarwin、Wowza) 或者RTMP流媒体服务器 (如Nginx) 的流媒体推送库
  • 018年8月4日第三次更新,详细介绍了RTMP协议与遇到的坑,另外纯Java重写了RTMP协议,做了个Android 推流项目,包含安卓相机采集,编码和RTMP推流,上传到github了。 项目地址:...

    018年8月4日第三次更新,详细介绍了RTMP协议与遇到的坑,另外纯Java重写了RTMP协议,做了个Android 推流项目,包含安卓相机采集,编码和RTMP推流,上传到github了。
    项目地址:https://github.com/gezhaoyou/SimpleLivePublisherLite
    参考文章:

    1. Android 直播推流简介: https://www.jianshu.com/p/0318ff29ac32
    2. 带你吃透RTMP:http://mingyangshang.github.io/2016/03/06/RTMP%E5%8D%8F%E8%AE%AE/

    :RTMP 协议整理成脑图,比较清晰,包括rtmp 消息类型,rtmp 分块chunking,rtmp分块例子。免费脑图工具 Xmind 格式,Here Get It

    1. rtmp 消息类型

       

      Paste_Image.png

    2. rtmp 消息分块

       

      Paste_Image.png

    1. 简介

    RTMP协议是Real Time Message Protocol(实时信息传输协议)的缩写,它是由Adobe公司提出的一种应用层的协议,用来解决多媒体数据传输流的多路复用(Multiplexing)和分包(packetizing)的问题。随着VR技术的发展,视频直播等领域逐渐活跃起来,RTMP作为业内广泛使用的协议也重新被相关开发者重视起来。本文主要分享对RTMP的一些简介和实际开发中遇到的一些状况。

    RTMP协议基本特点:

    • 基于TCP协议的应用层协议

    • 默认通信端口1935

    RTMP URL格式:
    rtmp://ip:[port]/appName/streamName
    例如: rtmp://192.168.178.218:1935/live/devzhaoyou

    参考:https://blog.csdn.net/ai2000ai/article/details/72771461

    2. RTMP 握手

    RTMP 握手分为简单握手和复杂握手,现在Adobe公司使用RTMP协议的产品用复杂握手的较多,不做介绍。

    握手包格式:

     0 1 2 3 4 5 6 7
    +-+-+-+-+-+-+-+-+
    |     version   |
    +-+-+-+-+-+-+-+-+
     C0 and S0 bits
    

    C0和S0:1个字节,包含了RTMP版本, 当前RTMP协议的版本为 3

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           time (4 bytes)                      |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           zero (4 bytes)                      |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           random bytes                        |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           random bytes                        |
    |                               (cont)                          |
    |                               ....                            |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                            C1 and S1 bits
    

    C1和S1:4字节时间戳,4字节的01528字节的随机数

    
      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                          time (4 bytes)                       |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                          time2 (4 bytes)                      |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                          random echo                          |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                          random echo                          |
     |                             (cont)                            |
     |                              ....                             |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                                C2 and S2 bits
    

    C2和S2:4字节时间戳,4字节从对端读到的时间戳,1528字节随机数

    RTMP握手基本过程:

    +-------------+                            +-------------+
    |   Client    |      TCP/IP Network        |     Server  |
    +-------------+             |              +-------------+
           |                    |                     |
    Uninitialized               |                Uninitialized
           |        C0          |                     |
           |------------------->|           C0        |
           |                    |-------------------->|
           |        C1          |                     |
           |------------------->|           S0        |
           |                    |<--------------------|
           |                    |           S1        |
      Version sent              |<--------------------|
           |        S0          |                     |
           |<-------------------|                     |
           |        S1          |                     |
           |<-------------------|               Version sent
           |                    |           C1        |
           |                    |-------------------->|
           |        C2          |                     |
           |------------------->|           S2        |
           |                    |<--------------------|
        Ack sent                |                   Ack Sent
           |        S2          |                     |
           |<-------------------|                     |
           |                    |           C2        |
           |                    |-------------------->|
    Handshake Done              |               Handshake Done
          |                     |                     |
              Pictorial Representation of Handshake
    

    握手开始于客户端发送C0C1块。服务器收到C0C1后发送S0S1

    当客户端收齐S0S1后,开始发送C2。当服务器收齐C0C1后,开始发送S2

    当客户端和服务器分别收到S2C2后,握手完成。

    注意事项: 在实际工程应用中,一般是客户端先将C0, C1块同时发出,服务器在收到C1 之后同时将S0, S1, S2发给客户端。S2的内容就是收到的C1块的内容。之后客户端收到S1块,并原样返回给服务器,简单握手完成。按照RTMP协议个要求,客户端需要校验C1块的内容和S2块的内容是否相同,相同的话才彻底完成握手过程,实际编写程序用一般都不去做校验。

    RTMP握手的这个过程就是完成了两件事:

    校验客户端和服务器端RTMP协议版本号

    是发了一堆随机数据,校验网络状况。

    3. RTMP 消息

    RTMP消息格式:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     | Message Type |               Payload length                   |
     |   (1 byte)   |                   (3 bytes)                    |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                          Timestamp                            |
     |                          (4 bytes)                            |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                          Stream ID            |
     |                          (3 bytes)            |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                             Message Header
    

    • 1字节消息类型

    • 3字节负载消息长度

    • 4字节时间戳

    • 3字节 Stream ID,区分消息流

    注意事项: 实际RTMP通信中并未按照上述格式去发送RTMP消息,而是将RTMP 消息分块发送,之后将介绍RTMP消息分块。

    3.1. RTMP 消息分块(chunking)

    而对于基于TCPRTMP协议而言,协议显得特别繁琐,但是有没有更好的替代方案。同时创建RTMP消息分块是比较复杂的地方,涉及到了AFM(也是Adobe家的东西)格式数据的数据。

    RTMP消息块格式:

     +--------------+----------------+--------------------+--------------+
     | Basic Header | Message Header | Extended Timestamp |  Chunk Data  |
     +--------------+----------------+--------------------+--------------+
     |                                                    |
     |<------------------- Chunk Header ----------------->|
                                Chunk Format
    

    RTMP消息块构成:

    • Basic Header

    • Message Header

    • Extended Timestamp

    • Chunk Data

    Chunk Basic header格式有3种:

    格式1:

       0 1 2 3 4 5 6 7
      +-+-+-+-+-+-+-+-+
      |fmt|   cs id   |
      +-+-+-+-+-+-+-+-+
     Chunk basic header 1
    

    格式2:

      0                      1
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |fmt|      0    |  cs id - 64   |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
          Chunk basic header 2
    

    格式3:

      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |fmt|         1 |          cs id - 64           |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                 Chunk basic header 3
    

    注意事项:

    fmt: 用于指定Chunk Header 里面 Message Header的类型,后面会介绍到

    cs id: 是chunk stream id的缩写,同一个RTMP消息拆成的 chunk 块拥有相同的 cs id, 用于区分chunk所属的RTMP消息, chunk basic header 的类型cs id占用的字节数来确定

    Message Header格式:

    Message Header的类型通过上文chunk basic header中的fmt指定,共4种:

    格式0:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                          timestamp            | message length|
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |      message length (cont)    |message type id| msg stream id |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |          message stream id (cont)             |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                    Chunk Message Header - Type 0
    

    Message Header占用11个字节, 在chunk stream的开始的第一个chunk的时候必须采用这种格式。

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

    message length3个字节,表示实际发送的消息的数据如音频帧、视频帧等数据的长度,单位是字节。注意这里是Message的长度,也就是chunk属于的Message的总数据长度,而不是chunk本身Data的数据的长度。

    message type id1个字节,表示实际发送的数据的类型,如8代表音频数据、9代表视频数据。

    msg stream id:4个字节,表示该chunk所在的流的ID,和Basic HeaderCSID一样,它采用小端存储的方式

    格式1:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                          timestamp            | message length|
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |      message length (cont)    |message type id|  
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
                    Chunk Message Header - Type 1 
    

    Message Header占用7个字节,省去了表示msg stream id的4个字节,表示此chunk和上一次发的chunk所在的流相同。

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

    格式2:

      0                   1                   2     
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
     |                          timestamp            |  
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
              Chunk Message Header - Type 2 
    

    Message Header占用3个字节,相对于格式1,又省去了表示消息长度的3个字节和表示消息类型的1个字节,表示此chunk和上一次发送的chunk所在的流、消息的长度和消息的类型都相同。余下的这三个字节表示timestamp delta,使用同格式1。

    格式3:

    0字节,它表示这个chunk的Message Header和上一个是完全相同的,无需再次传送

    Extended Timestamp(扩展时间戳):

    chunk中会有时间戳timestamp和时间戳差timestamp delta,并且它们不会同时存在,只有这两者之一大于3个字节能表示的最大数值0xFFFFFF=16777215时,才会用这个字段来表示真正的时间戳,否则这个字段为0。

    扩展时间戳占4个字节,能表示的最大数值就是0xFFFFFFFF=4294967295。当扩展时间戳启用时,timestamp字段或者timestamp delta要全置为1,表示应该去扩展时间戳字段来提取真正的时间戳或者时间戳差。注意扩展时间戳存储的是完整值,而不是减去时间戳或者时间戳差的值。

    Chunk Data(块数据): 用户层面上真正想要发送的与协议无关的数据,长度在(0,chunkSize]之间, chunk size默认为128字节。

    RTMP 消息分块注意事项

    Chunk Size:

    RTMP是按照chunk size进行分块,chunk size 指的是 chunkpayload部分的大小,不包括chunk basic headerchunk message header长度。客户端和服务器端各自维护了两个chunk size, 分别是自身分块的chunk size 和 对端 的chunk size, 默认的这两个chunk size都是128字节。通过向对端发送set chunk size 消息可以告知对方更改了 chunk size的大小。

    Chunk Type:

    RTMP消息分成的Chunk4种类型,可以通过 chunk basic header的高两位(fmt)指定,一般在拆包的时候会把一个RTMP消息拆成以格式0开始的chunk,之后的包拆成格式3 类型的chunk,我查看了有不少代码也是这样实现的,这样也是最简单的实现。

    如果第二个message和第一个messagemessage stream ID 相同,并且第二个message的长度也大于了chunk size,那么该如何拆包?当时查了很多资料,都没有介绍。后来看了一些源码,如 SRSFFMPEG中的实现,发现第二个message可以拆成Type_1类型一个chunkmessage剩余的部分拆成Type_3类型的chunkFFMPEG中就是这么做的。

    3.2 RTMP 交互消息

    推流RTMP消息交互流程:

    • pic_2.png

    关于推流的过程,RTMP的协议文档上给了上图示例,说一下推流注意事项:

    3.2.1 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格式发送, 下面是用wireshake抓取connect命令需要包含的参数信息:

    • pic_3.png

    这些信息协议中并没有特别详细说明, 在librtmpsrs-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消息,没有错误就可以进行下一步了。

    3.2.2 Create Stream 消息

    创建完RTMP连接之后就可以创建RTMP流,客户端要想服务器发送一个releaseStream命令消息,之后是FCPublish命令消息,在之后是createStream命令消息。

    当发送完createStream消息之后,解析服务器返回的消息会得到一个stream ID

    • pic_4.png

    这个ID也就是以后和服务器通信的 message stream ID, 一般返回的是1,不固定。

    3.2.3 Publish Stream

    推流准备工作的最后一步是Publish Stream,即向服务器发一个publish命令消息,消息中会带有流名称字段,即rtmp url中的 streamName,这个命令的message stream ID 就是上面 create stream 之后服务器返回的stream ID,发完这个命令一般不用等待服务器返回的回应,直接发送音视频类型的RTMP数据包即可。有些rtmp库还会发setMetaData消息,这个消息可以发也可以不发,里面包含了一些音视频meta data的信息,如视频的分辨率等等。

    整个推流过程rtmp 消息抓包

    • rtmp_pulish_message.png

    4. 推送音视频

    当以上工作都完成的时候,就可以发送音视频了。音视频RTMP消息的Payload(消息体)中都放的是按照FLV-TAG格式封的音视频包,具体可以参照FLV封装的协议文档。格式必须封装正确,否则会造成播放端不能正常拿到音视频数据,无法播放音视频。

    5. 关于RTMP的时间戳

    RTMP的时间戳单位是毫秒ms,在发送音视频之前一直为零,发送音视频消息包后时候必须保证时间戳是单调递增的,时间戳必须打准确,否则播放端可能出现音视频不同步的情况。Srs-librtmp的源码中,如果推的是视频文件的话,发现他们是用H264的dts作为时间戳的。实时音视频传输的时候是先获取了下某一时刻系统时间作为基准,然后每次相机采集到的视频包,与起始的基准时间相减,得到时间戳,这样可以保证时间戳的正确性。

    6. 关于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协议是个比较啰嗦的协议,实现起来也比较复杂,但通信过程过程相对简单。在直播的实际工程应用中,协议上很多地方都没有详细说明,注意了以上提到几点,基本能够保证RTMP音视频的通信正常。以上就是对RTMP协议的简介和一些注意事项,希望能帮到有需要的朋友,另外本文难免有错误或说的不够详细的地方,欢迎指正,一起交流探讨。


    本篇文章2017年版本

    前一段时间写过一篇文章: iOS直播视频数据采集、硬编码保存h264文件,比较详细的记录了在做iOS端进行视频数据采集和编码的过程,下一步要做的就是RTMP协议推流。因为在公司将RTMP协议用Java 和 Swift 分别实现了一遍,所以对这块比较了解,中间遇到了不少坑,记录下来也怕自己忘掉。
    RTMP协议是 Adobe 公司开发的一个基于TCP的应用层协议,Adobe 公司也公布了关于RTMP的规范,但是这个协议规范介绍的有些地方非常模糊,很多东西和实际应用是有差别的。网上也有不少关于这个协议的介绍,但都不是太详细。我遇到的比较好的参考资料就是这篇:带你吃透RTMP, 这篇文章只是在理论上对RTMP进行了比较详细的解释,很多东西还是和实际应用有出入。我这篇文章只是把遇到的一些坑记录下来,并不是详解RTMP消息的。
    另外懂RTMP消息拆包分包,而不真正的写写的话是很难把RTMP协议弄得的很清楚,关于RTMP协议的实现也是比较麻烦的事,懂和做事两回事。
    另外用wireshark 抓一下包的话可以非常直观的看到RTMP通信的过程,对理解RTMP非常有帮助,在调试代码的时候也大量借助wireshark排错,是一个非常有用的工具。

    1. RTMP 握手

    RTMP 握手分为简单握手和复杂握手,现在Adobe公司使用RTMP协议的产品应该用的都是复杂握手,这里不介绍,只说简单握手。 按照网上的说法RTMP握手的过程如下

    1. 握手开始于客户端发送C0、C1块。服务器收到C0或C1后发送S0和S1。
    1. 当客户端收齐S0和S1后,开始发送C2。当服务器收齐C0和C1后,开始发送S2。
    2. 当客户端和服务器分别收到S2和C2后,握手完成。

    在实际工程应用中,一般是客户端先将C0, C1块同时发出,服务器在收到C1 之后同时将S0, S1, S2发给客户端。S2的内容就是收到的C1块的内容。之后客户端收到S1块,并原样返回给服务器,简单握手完成。按照RTMP协议个要求,客户端需要校验C1块的内容和S2块的内容是否相同,相同的话才彻底完成握手过程,实际编写程序用一般都不去做校验。
    RTMP握手的这个过程就是完成了两件事:1. 校验客户端和服务器端RTMP协议版本号,2. 是发了一堆数据,猜想应该是测试一下网络状况,看看有没有传错或者不能传的情况。RTMP握手是整个RTMP协议中最容易实现的一步,接下来才是大头。

    2. RTMP 分块

    创建RTMP连接算是比较难的地方,开始涉及消息分块(chunking)和 AFM(也是Adobe家的东西)格式数据的一些东西,在上面提到的文章中也有介绍为什要进行RTMP分块。

    Chunk Size

    RTMP是按照chunk size进行分块,chunk size指的是 chunk的payload部分的大小,不包括chunk basic header 和 chunk message header,即chunk的body的大小。客户端和服务器端各自维护了两个chunk size, 分别是自身分块的chunk size 和 对端 的chunk size, 默认的这两个chunk size都是128字节。通过向对端发送set chunk size 消息告知对方更改了 chunk size的大小,即告诉对端:我接下来要以xxx个字节拆分RTMP消息,你在接收到消息的时候就按照新的chunk size 来组包。
    在实际写代码的时候一般会把chunk size设置的很大,有的会设置为4096,FFMPEG推流的时候设置的是 60*1000,这样设置的好处是避免了频繁的拆包组包,占用过多的CPU。设置太大的话也不好,一个很大的包如果发错了,或者丢失了,播放端就会出现长时间的花屏或者黑屏等现象。

    Chunk Type

    RTMP 分成的Chunk有4中类型,可以通过 chunk basic header的 高两位指定,一般在拆包的时候会把一个RTMP消息拆成以 Type_0 类型开始的chunk,之后的包拆成 Type_3 类型的chunk,我查看了有不少代码也是这样实现的,这样也是最简单的实现。
    RTMP 中关于Message 分chunk只举了两个例子,这两个例子不是很具有代表性。假如第二个message和第一个message的message stream ID 相同,并且第二个message的长度也大于了chunk size,那么该如何拆包?当时查了很多资料,都没有介绍。后来看了一些源码,发现第二个message可以拆成Type_1类型一个chunk, message剩余的部分拆成Type_3类型的chunk。FFMPEG中好像就是这么做的。

    3. RTMP 消息

    关于推流的过程,RTMP的协议文档上给了一个示例,而真实的RTMP通信过程和它有较大的差异,只说推流,RTMP播放端我没有做过。

    Connect消息

    握手之后先发送一个connect 命令消息,命令里面包含什么东西,协议中没有说,真实通信中要指定一些编解码的信息,这些信息是以AMF格式发送的, 下面是用swift 写的connect命令包含的参数信息:

           transactionID += 1 // 0x01
            let command:RTMPCommandMessage = RTMPCommandMessage(commandName: "connect", transactionId: transactionID, messageStreamId: 0x00)
            let objects:Amf0Object = Amf0Object()
            objects.setProperties("app", value: rtmpSocket.appName)
            objects.setProperties("flashVer",value: "FMLE/3.0 (compatible; FMSc/1.0)")
            objects.setProperties("swfUrl", value:"")
            objects.setProperties("tcUrl", value: "rtmp://" + rtmpSocket.hostname + "/" + rtmpSocket.appName)
            objects.setProperties("fpad", value: false)
            objects.setProperties("capabilities", value:239)
            objects.setProperties("audioCodecs", value:3575)
            objects.setProperties("videoCodecs", value:252)
            objects.setProperties("videoFunction",value: 1)
            objects.setProperties("pageUrl",value: "")
            objects.setProperties("objectEncoding",value: 0)
    

    这些信息具体什么意思我也不太明白,协议中也没有,都是我在看librtmp,srs-librtmp这些源码,以及用wireshark 抓包的时候看到的。其中参数少一两个貌似也没问题,但是audioCodecsvideoCodecs这两个指定音视频编码信息的不能少。
    服务器返回的是一个_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消息,没有错误就可以进行下一步了。

    Create Stream 消息

    创建完RTMP连接之后就可以创建RTMP流,客户端要想服务器发送一个releaseStream命令消息,之后是FCPublish命令消息,在之后是createStream命令消息。当发送完createStream消息之后,解析服务器返回的消息会得到一个stream ID, 这个ID也就是以后和服务器通信的 message stream ID, 一般返回的是1,不固定。

    Publish Stream

    推流准备工作的最后一步是 Publish Stream,即向服务器发一个publish命令,这个命令的message stream ID 就是上面 create stream 之后服务器返回的stream ID,发完这个命令一般不用等待服务器返回的回应,直接下一步发送音视频数据。有些rtmp库 还会发setMetaData消息,这个消息可以发也可以不发,里面包含了一些音视频编码的信息。

    4. 发布音视频

    当以上工作都完成的时候,就可以发送音视频了。音视频RTMP消息的Payload中都放的是按照FLV-TAG格式封的音视频包,具体可以参照FLV协议文档。

    5. 关于RTMP的时间戳

    RTMP的时间戳在发送音视频之前都为零,开始发送音视频消息的时候只要保证时间戳是单增的基本就可以正常播放音视频。我读Srs-librtmp的源码,发现他们是用h264的dts作为时间戳的。我在用java写的时候是先获取了下当前系统时间,然后每次发送消息的时候都与这个起始时间相减,得到时间戳。

    6. 关于Chunk Stream ID

    RTMP 的Chunk Steam ID是用来区分某一个chunk是属于哪一个message的 ,0和1是保留的。每次在发送一个不同类型的RTMP消息时都要有不用的chunk stream ID, 如上一个Message 是command类型的,之后要发送视频类型的消息,视频消息的chunk stream ID 要保证和上面 command类型的消息不同。每一种消息类型的起始chunk 的类型必须是 Type_0 类型的,表明我是一个新的消息的起始。



    作者:devzhaoyou
    链接:https://www.jianshu.com/p/00aceabce944
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

    展开全文
  • RTMP推流服务、RTMP分发、HLS分发、HTTP-FLV分发; 云端录像、云端录像检索、云端录像点播、云端录像下载; RTMP转推、推流鉴权验证、推流信息统计、播放信息统计; 直播分享、开放直播、拉转直播; 视频上传、视频...

    LiveQing云端直播点播流媒体软件: 提供设备接入; RTMP推流服务、RTMP分发、HLS分发、HTTP-FLV分发; 云端录像、云端录像检索、云端录像点播、云端录像下载; RTMP转推、推流鉴权验证、推流信息统计、播放信息统计; 直播分享、开放直播、拉转直播; 视频上传、视频转码、视频分享、视频下载; 后台管理、二次开发接口、防盗链、播放地址加密、播放器集成等。

    安装本地流媒体服务教程

    配置推流端地址

    地址规则
    rtmp://cloud.liveqing.com:10085/{application}/{name}
    application hls|live ,其中 hls可以分发HLS流
    name 自定义非重复字符串

    在这里插入图片描述

    开放直播菜单

    在这里插入图片描述

    在这里插入图片描述

    获取更多信息

    安防流媒体互联直播-QQ交流群:615081503

    国标GB28181无插件LiveGBS-QQ交流群:947137753

    邮件:support@liveqing.com

    WEB:www.liveqing.com

    Tel:15156896292 (同微信)

    Copyright © LiveQing.com 2016-2019

    展开全文
  • RTMP协议分析及推流过程

    千次阅读 2017-07-06 17:47:44
    1.RTMP(实时消息传输协议)是Adobe 公司开发的一个基于TCP的应用层协议。 2.RTMP协议中基本的数据单元称为消息(Message)。 3.当RTMP协议在互联网中传输数据的时候,消息会被拆分成更小的单元,称为消息块...

    简介:

    1.RTMP(实时消息传输协议)是Adobe 公司开发的一个基于TCP的应用层协议。

    2.RTMP协议中基本的数据单元称为消息(Message)。

    3.当RTMP协议在互联网中传输数据的时候,消息会被拆分成更小的单元,称为消息块(Chunk)。


    RTMP 握手(Handshake):


    1.握手开始于客户端发送C0、C1块。服务器收到C0或C1后发送S0和S1。
    2.当客户端收齐S0和S1后,开始发送C2。当服务器收齐C0和C1后,开始发送S2。
    3.当客户端和服务器分别收到S2和C2后,握手完成。


    在实际工程应用中,一般是客户端先将C0, C1块同时发出,服务器在收到C1 之后同时将S0, S1, S2发给客户端。之后客户端向服务器端发送C2块,简单握手完成。


    建立网络连接(NetConnection):


    1. 客户端发送命令消息中的“连接”(connect)到服务器,请求与一个服务应用实例建立连接。


    2. 服务器接收到连接命令消息后,发送确认窗口大小(Window Acknowledgement Size)协议消息到客户端,同时连接到连接命令中提到的应用程序。


    3. 服务器发送设置带宽协议消息到客户端。


    4. 客户端处理设置带宽协议消息后,发送确认窗口大小(Window Acknowledgement Size)
    协议消息到服务器端。


    5. 服务端向客户端发送“流开始”(Stream Begin)。


    6. 服务器发送命令消息中的“结果”(_result),通知客户端连接的状态。


    建立网络流(Create Stream):


    1. 客户端发送命令消息中的“创建流”(CreateStream)命令到服务器端。
    2. 服务器端接收到“创建流”命令后,发送命令消息中的“结果”(_result),通知客户端流的状态。


    播放(Play):



    1. 客户端发送命令“播放”给服务器
    2. 接收到播放命令后,服务器发送设置块大小(ChunkSize)协议消息给客户端
    3. 服务器发送“stream begin”给客户端,告诉客户端流的id
    4. 播放命令成功的话,服务器发送命令消息中的“响应状态” NetStream.Play.Start & NetStream.Play.Reset,告知客户端“播放”命令执行成功
    5. 服务器发送客户端要播放的音频和视频数据


    小结:

         关系图:


    播放一个RTMP协议的流媒体需要经过以下几个步骤:


    下面用wireshark 抓包来分析一下过程:




    RTMP 消息结构:


    RTMP消息块:

    在网络上传输数据时,消息需要被拆分成较小的数据块,才适合在相应的网络环境上传输。RTMP协议中规定,消息在网络上传输时被拆分成消息块(Chunk)。


    RTMP 消息分块:



    展开全文
  • rtmp服务器以及rtmp推流/拉流/转发

    千次阅读 2019-08-21 06:00:37
    一、服务器端 1、nignx ...5、node-rtsp-rtmp-server github搜一圈也很多 https://github.com/gwuhaolin/livego https://github.com/sevenzoe/gortmp https://github.com/c-bata/rtmp 二、rt...

    一、服务器端

    1、nignx

    2、ffmpeg

    3、srs

    4、livego

    5、node-rtsp-rtmp-server

    github搜一圈也很多

    https://github.com/gwuhaolin/livego

    https://github.com/sevenzoe/gortmp

    https://github.com/c-bata/rtmp

     

    二、rtmp推流器

    1、rtmp发布h264裸数据

    H264视频通过RTMP直播

    https://blog.csdn.net/firehood_/article/details/8783589

    整理了下 https://files.cnblogs.com/files/dong1/rtmp_pusher.zip

     

    2、发布h264 rtmp最省事的还是srs-librtmp

    开源srs自带的示例srs_h264_raw_publish.c就很容易用起来

    https://www.cnblogs.com/dong1/p/5100792.html

    我导出了srs-librtmp项目,做了两个demo,分别跑在x86和arm

    附件:https://files.cnblogs.com/files/dong1/srs-librtmp_pusher_demo.zip

     

    3、直接用ffmpeg

    https://github.com/Akagi201/ffmpeg-push

    整理了下,可以推送文件和url网络实时流

    https://files.cnblogs.com/files/dong1/ffmpeg_push.zip

    ./main source.200kbps.768x320.flv rtmp://182.61.45.149:1935/live/movie
    ./main rtsp://admin:12345@172.16.23.142:554/H.264/ch1/main/av_stream rtmp://182.61.45.149:1935/live/movie

     

    4、下面这个有音频和视频两路数据,比较方便

    This tool is used to encapsulate H264 and AAC to RTMP

    https://github.com/rainfly123/flvmuxer

    5、封装成ts也可以

    ts muxer

    https://github.com/felix-001/tslib

     

    三、拉流

    1、ffmpeg

    2、python-librtmp

     

    四、测试实例

    我这里用的开源livego和rtmp_pusher

    https://www.cnblogs.com/dong1/p/9574508.html

    https://files.cnblogs.com/files/dong1/rtmp_pusher.zip

    libRTMP + livego

    ./test 往服务器推流,然后ffplay播放

    ffplay -i rtmp://localhost:1935/live/movie

    ffplay http://127.0.0.1:7002/live/movie.m3u8

     

     

    转载于:https://www.cnblogs.com/dong1/p/10200869.html

    展开全文
  • RTMP推流及协议学习

    万次阅读 2017-03-13 13:48:02
    前期准备 了解RTMP定义 准备RTMPDump中的librtmp 使用openssl中的...推流工作 整体框架图 使用libtrmp提供的API 将streaming封装成为RTMP格式 进阶 RTMP client与RTMP server交互流程 RTMPDump源码分析 参考资料
  • 音视频开发---ffmpeg rtmp推流

    千次阅读 2019-08-14 14:52:26
    推流介绍 FFmpeg推流 推流器函数流程图 代码 遗留问题 参考 推流介绍 推流是将输入视频数据推送至流媒体服务器, 输入视频数据可以是本地视频文件(avi,mp4,flv......),也可以是内存视频数据,或者摄像头...
  • 服务器的搭建 Red5 搭建基于RTMP协议...数据推流软件 flash_media_live_encoder_3.2 客户端播放软件 vlc-2.1.5-win32.1406534096 2.安装软件 直接双击安装即可 3.数据推流 使用flash encoder软件 设置服务器的URL
  • 如果无人机自身支持RTMP推流,可以直接采用RTMP直接推流的方式;也可以采用LivePush,与定制GBR24到H.264结合的方式;可以使用稳定的RTMP推流服务器LiveQing 或是 其他运营商提供的CDN.
  • FFMPEG推流RTMP服务器命令

    万次阅读 2018-07-26 18:18:55
    FFMPEG推流RTMP服务器命令   1、将文件当作源推送到RTMP服务器 ffmpeg -re -i localFile.mp4 -c copy -f flv rtmp://server/live/streamName 参数解释 -r 以本地帧频读数据,主要用于模拟捕获设备。表示...
  • OBS推流工具下载及配置可以参见:OBS推流工具 ##第二步:安装流媒体服务 免费获得试用安装包,加入QQ群 615081503 群文件里有试用安装包,极速安装,下载解压一键启动即可,支持Windows和Linux双系统。 ##第三步:...
  • FFmpeg将网络摄像机的rtsp视频流转换成rtmp流,然后rtmp视频到nginx上面,然后使用手机播放hls的视频。 在期间遇到一些问题,总是丢包,我截了个图,请大家帮忙看看是不是我在使用ffmpeg时参数设置的不对啊...
  • rtmp推流服务器降低延时

    万次阅读 2018-09-10 11:51:52
    在搭建好的nginx-rtmp服务器上做推流延时会很高我最开始时在6s左右,这时候需要修改接收端和发送端的缓存就可以。 以下是发送端的例子(视频缓存太小后会不能播放,这个只针对音频) 录屏加摄像头和麦克风这个延时...
  • 使用ffmpeg 测试rtmp推流和拉流

    千次阅读 2018-08-01 19:25:35
    推流操作: ffmpeg -f x11grab -i :0.0+0,0 -s 640x480 -r 10 -vcodec libx264 -preset ultrafast -acodec libmp3lame -ar 44100 -ac 1 -f flv rtmp://*** 把电脑屏幕推流大指定路径。 推文件: ffm...
  • 可以将**鉴权直播**(app=hls)和**拉转直播**(app=vlive),进行 RTMP,将发布 到远程的其他的媒体服务器,这样可以配置单点送,多点分发,此处可以 添加多个配置
  • [总结]RTMP流媒体技术零基础学习方法

    万次阅读 多人点赞 2016-07-01 19:12:22
    本文主要总结一些我在学习RTMP流媒体技术过程中积累的经验。也为后来学习RTMP流媒体技术的人们一个参考。本文力图从简到难,循序渐进的介绍RTMP流媒体技术的方方面面,先从应用说起,逐步深化剖析相关工程的源代码。...
  • 要做一个android端的媒体播放器,获取服务器rtmp流。我按照网上的教程使用vitamio库https://github.com/yixia/VitamioBundle,demo里面列举了很多情况,我自己新建了一个项目,导入module,选择用videoview...
  • 流媒体压力测试rtmp&hls(含推流和拉流)

    万次阅读 热门讨论 2017-06-01 13:58:09
    http://www.linuxcache.com/archives/3328 [root@localhost ~]# yum install git unzip patch gcc gcc-c++ make [root@localhost ~]# git clone https://github.com/winlinvip/st-load.git [root@localhost
1 2 3 4 5 ... 20
收藏数 11,265
精华内容 4,506
关键字:

rtmp推流