RTMP

作者: 一亩三分甜 | 来源:发表于2022-02-03 21:39 被阅读0次

    音视频文章汇总,本文介绍RTMP。

    1.本地部署SRS

    1.1安装srs流媒体服务器

    srs官⽹ https://github.com/ossrs/srs
    码云的源速度快 https://gitee.com/winlinvip/srs.oschina.git
    github的源速度慢 https://github.com/ossrs/srs.git
    选择版本release3.0

    第一步,获取SRS。详细参考GIT获取代码

    git clone https://gitee.com/winlinvip/srs.oschina.git
    cd srs.oschina
    #使⽤当前最新的3.0版本
    git checkout -b 3.0 remotes/origin/3.0release
    cd trunk
    

    第二步,编译SRS。详细参考Build

    ./configure && make
    

    第三步,编写SRS配置⽂件。详细参考RTMP分发

    将以下内容保存为⽂件,譬如conf/rtmp.conf,服务器启动时指定该配置⽂件(srs的conf⽂件夹有该⽂件)。

    # conf/rtmp.conf
    listen 1935;
    max_connections 1000;
    vhost __defaultVhost__ {
    }
    

    第四步,启动SRS。详细参考RTMP分发

    ./objs/srs -c conf/rtmp.conf
    

    部署在虚拟机或云服务器上均可,使用ffmpeg或OBC客户端推流,ffplay或VLC拉流进行播放


    0.gif

    2.RTMP原理

    Real Time Messaging Protocol) 是一个应用层协  主要用于在Flash player和服务器之间传输视频,音频,控制命令等内容。协议的突出优点是:低延时。

    FFMPEG

    推流 +FFPLAY 播放
    推流
    ffmpeg -re -i /mnt/hgfs/linux/vod/35.mp4 -c copy -f flv rtmp://192.168.100.41/live/35
    拉流
    ffplay rtmp://192.168.100.41/live/35
    FFPLAY
    播放
    拉流
    ffplay rtmp://202.69.69.180:443/webcast/bshdlive-pc

    2.1RTMP播放流程

    image

    2.2推流流程

    image
    image
    image

    RTMP是基于TCP的应用层协议。TCP的三次握手可实现RTMP 客户端与RTMP服务器的指定端口(默认端口为1935)建立一个可靠的网络连接。这里的的网络连接接才是真正的物理连接。
    完成了三次握手,客户端和服务器端就可以开始传输数据。


    image

    2.2.1TCP三次握手修高速公路

    image
    image
    image
    图片.png

    经过三次握手客户端与服务器端1935端口建立了TCP Connection


    image

    2.2.2RTMP握手

    与其叫RTMP握手其实实质上起到的是的作用。RTMP握手的基本流程


    image

    RTMP握手主要分为简单握手和复杂握手。

    简单握手

    image
    image

    简单握手中C1 和 S1 从第9个字节开始都是随机数。
    S2 是 C1 的复制。C2 是 S1 的复制。
    协议版本号 8bit
    C0客户端版本
    S服务器版本
    目前版本为3(0 1 2已经废弃)


    图片.png
    C1和S1数据包的长度都是1536字节
    图片.png

    03( 00 (C1 开始 00 00 00 09 00 7c 02 f7 78 55 1e ce ab 8e)
    S1 片段 00 90 65 30 0d 0e 0a 0d 64 84 1c ad 1e 7f 0c
    C2和S2数据包长度都是1536字节,基本就是S1和C1的副本。   


    image
    S2片段
    图片.png
    image

    复杂握手

    相对于简单握手和复杂握手主要是增加了更严格的验证。
    主要是将简单握手中的1528Bytes随机数的部分平均分成两部分,一部分764Bytes存储,public key(公共密钥),另一部分764Bytes存储digest(密文,32字节)。
    另外复杂握手有一个明显的特征就是:Version部分不为0
    服务器端可根据这个来判断是否简单握手或复杂握手。


    image

    2.2.3Connect连接

    这里也叫连接,连接的是什么呢?必须明白RTMP中一个很重要的概念Application Instance。
    不同的Application Instance 可根据功能等进行区分,比如直播可以用live来表示,点播回放可以用vod来表示。

    rtmp://192.168.100.41/live/36
    其中live就是Application(Instance sport), music播放该流时connect 的地址就是
    rtmp://192.168.100.41/live/36
    
    image 图片.png image

    2.2.4createStream(创建流)-创建逻辑通道

    image

    createStream命令用于创建逻辑通道,逻辑通道用于传输视频、音频、metadata。
    在服务器的响应报文中会返回Stream ID,用于唯一的标示该Stream。注意Message ID和Stream ID的区别。
    The command structure from the client to the server is as follows:


    image

    The command structure from server to client is as follows:


    image
    image
    图片.png
    图片.png

    2.2.5play(播放)

    image
    图片.png

    客户端发送play命令来播放指定流。开始传输数据。
    如果发送play命令后想立即播放,需要清空play队列中的其它流,并将reset置为true。

    2.2.6delete删除流

    image

    The command structure from the client to the server is as follows:


    image

    删除指定Stream ID 的流。服务器 不用对 条命令发 响应报文。

    2.3RTMP层次

    RTMP层次(数据发送角度)


    image

    RTMP层次(数据接收角度)


    图片.png

    RTMP层次(协议角度)


    图片.png

    2.3.1Message和Chunk

    Message RTMP 中一个重要的概念就是消息。


    图片.png image

    2.3.2消息分类

    消息主要分为三类:协议控制消息、数据消息、命令消息 等。
    协议控制消息Message Type ID = 1 2 3 5 6 和 Message Type ID = 4 两大类主要用于协议内的控制消息,此部分后续将详细分析。
    数据消息
    Message Type ID = 8 9 18
    8: Audio   数据
    9: Video   数据
    18: Metadata 包括音视频编码、视频宽高等信息。
    命令消息
    Command Message (20, 17)
    此类型消息主 有 NetConnection 和 NetStream 两个类,两个类分别有多个函数,该消息的调用,可理解为远程函数调用。

    stream ID

    Message StreamID是音视频流的唯一ID, 一路流如果既有音频包又有视频包,那么音频包的StreamID和他视频包的StreamID相同。
    Chunk网络中实际发送的内容。

    message chunk
    图片.png

    cs id即是 Chunk Stream ID


    image

    Chunk Stream ID

    Each chunk that is created has a unique ID associated with it called chunk stream ID。(5.3.Chunking);
    因为一个流当中可以交错传输多种消息类型的Chunk   
    那么多个Chunk怎么标记同属于同一类Message的呢 
    答案是:Chunk Stream ID 区分的同一个Chunk Stream ID必然属于同一个Message。
    RTMP流中视频和音频拥有单独的Chunk Stream ID,比如音频的cs id=20,视频的cs id=21 。接收端接收到Chunk之后根据cs id分别将音频和视频拼成消息。

    Message & Chunk

    Message切割成一个或多个Chunk,然后在网络上进行发送。当发送时,一个chunk发送完毕后才可以发送下一个
    chunk。


    image

    拆分的时候的Chunk Size是128字节,以Message大小为300字节举例进行拆分。300 = 128 + 128 + 44


    image

    发送端

    首先将数据加工成消息(中间物),然后再将消息分割成Chunk(加上Chunk Header),然后将Chunk通过网络发送出去。

    接收端

    接收端将接收到的Chunk组装成消息。


    图片.png

    RTMP协议角度

    图片.png

    RTMP Chunk Header

    RTMP Chunk Header的长度不是固定的,分为12 Bytes、8 Bytes、4 Bytes、1 Byte四种, 由RTMP Chunk Header前2位决定。


    image

    一场直播如果不中断的话,是不是只有一个流,也就是Message Stream ID一直到直播结束都是唯一的,Message 里面的Message Stream Id和Chunk里面的Chunk Stream Id属于两个不同的东西,因为Chunk Stream Id用来区分音频和视频流

    image

    为什么Chunk Header会存在不同的长度

    一般情况下msg stream id是不会变的,所以针对视频或音频,除了第一个RTMP Chunk Header是 12Byte的,后续即可采用8Bytes的。 因为msg stream id占4个Bytes可省去。
    如果消息的长度(message length)和类型(msg type id, 如视频为9或音频为8)又相同,即可将这两部分也省去,RTMP Chunk Header采用4Bytes类型的。
    如果当前Chunk与之前的Chunk相比, msg stream id 相同,msg type id相同,message length相同,而且 都属于同一个消息,由同一个Message切割成),这类Chunk的时间戳(timestamp)也是相同的,故后续的也可以省去,RTMP Chunk Header采用1 Byte类型的。
    当Chunk Size足够大时(一般不这么干),此时所有的 Message都只能相应切割成一个Chunk,该Chunk仅msg stream id相同。此时基本上除了第一个Chunk的Header是12Bytes外,其它所有Chunk的Header是8Bytes。


    image
    image
    image
    图片.png

    12Bytes Chunk Header举例

    RTMP Header(12 Bytes)
    一般只有rtmp流刚开始的metadata、绝对时间戳的视频或音频是12Bytes。


    image
    image

    有些控制消息也是12Bytes,比如connect。


    image

    8Bytes Chunk Header举例

    image
    image

    4Bytes Chunk Header举例

    image
    image

    1Bytes Chunk Header举例

    image

    RTMP传输基本流程

    image

    发送端
    Step 1:
    把数据封装成消息(Message)。
    Step 2:
    把消息分割成消息块(Chunk, 网络中实际传输的内容)。
    Step 3:
    将分割后的消息块(Chunk),通过TCP协议发出去。
    接收端
    Step 1:
    在TCP协议收到数据后,先将消息块重新组合成消息(Message)。
    Step 2:
    通过对消息进行解封装处理就可以恢复出数据。

    RTMP为什么要将Message划分为Chunk?

    在互联网中传输数据时,消息(Message)会被拆分成更小的单元,称为消息块(Chunk)。
    大的Message被切割成利于网络上传输的小Chunk,切成小块,可防止大的数据块(如视频数据)阻塞小的数据块(如音频数据或控制信号)。

    image
    如果一帧1080P I帧数据量为244KBytes,假设带宽为10Mbit/s,传输一帧的耗时为:2441024 8/(1010241024) = 0.190625秒 =190毫秒
    假如要实时传输25帧的I帧文件,即允许每帧传输最大耗时为40毫秒,需要带宽47.65625Mbit,这还没包括传输中的ACK数据。
    在RTMP中,消息(Message)主要分为两大类:控制消息和数据消息。数据消息中由包括Video消息和Audio消息等。

    消息都是怎么进行管理的?

    通路只有一条(RTMP是单通路),到底谁先走呢,谁后走呢?
    答案是:分优先级,优先级高的先行。优先级低的不能阻塞优先级高的。


    image

    RTMP Chunk Stream层级没有优先级的划分,是在高层次Message stream提供优先级的划分。
    不同类型的消息会被分配不同的优先级,当网络传输能力受限时,优先级用来控制消息在网络底层的排队顺序。

    比如当客户端网络不佳时,流媒体服务器可能会选择丢弃视频信息,以保证音频消息可以及时送达客户端。

    image

    RTMP Chunk Stream层级允许在Message stream层次,将大消息切割成小消息,这样可以避免大的低优先级的消息(如视频消息)阻塞小的高优先级的消息(如音频消息或控制消息)。

    RTMP消息优先等级

    image
    image

    Protocol Control Messages属于RTMP Chunk Stream层级的控制消息,用于该协议的内部控制。


    image
    User Control Message 是RTMP streaming layer(即Message stream层次)的消息。

    协议先行
    协议控制消息 Protocol Control Messages 和用户控制消息User Control Messages 应该包含消息流 ID 0(控制流)和块流ID 2,并且有最高的发送优先级。
    数据次之
    数据消息(视频信息、音频消息)比控制信息的优先级低。另外,一般情况下,音频消息比视频数优先级高。

    2.4RTMP协议-时间戳

    基本介绍

    • RTMP中时间戳的单位为毫秒(ms)
    • 时间戳为相对于某个时间点的相对值
    • 时间戳的长度为32bit

    Timestamp: Four-byte field that contains a timestamp of the message.
    The 4 bytes are packed in the big endian order.
    •RTMP Message的时间戳4个字节
    •大端存储

    Chunk时间戳

    Chunk Format


    image

    用wireshark转包分析发现,rtmp流的chunk视频流 或(音频流)除第一个视频时间戳为绝对时间戳外,后续的时间戳均为timestamp delta,即当前时间戳与上一个时间戳的差值。
    比如帧率为25帧每秒的视频流,timestamp delta基本上都为40ms。
    通常情况下Chunk的时间戳(包括绝对时间戳和 Timestamp delta)是3个字节。
    但时间戳值超过0xFFFFFF时,启用Extended Timestamp(4个字节来表示时间戳)
    通常情况下-----3字节


    image
    三字节的timestamp可能为绝对timestamp或timestamp delta。
    timestamp delta (3 bytes): For a type 1 or type 2 chunk, the difference between the previous chunk’s timestamp and the current chunk’s timestamp is sent here.

    If the delta is greater than or equal to 16777215 (hexadecimal 0xFFFFFF), this field MUST be 16777215, indicating the
    presence of the Extended Timestamp field to encode the full 32 bit delta.
    Otherwise, this field SHOULD be the actual delta.
    timestamp delta的值超过16777215(即16进制的 0xFFFFFF)时,这时候这三个字节必须置为0xFFFFFF以此来标示Extended Timestamp(4字节)将会存在, 由Extended Timestamp来表示时间戳。

    相关文章

      网友评论

        本文标题:RTMP

        本文链接:https://www.haomeiwen.com/subject/ckhjkrtx.html