网络直播是如何实现的——流媒体协议简介

参考:极客时间《趣谈网络协议》
本文是对网络直播中视频如何传输做一个记录。

网络直播是如何实现的——流媒体协议简介

流媒体(streaming media)是指将一连串的媒体数据压缩后,经过网上分段发送数据,在网上即时传输影音以供观赏的一种技术与过程,此技术使得数据包得以像流水一样发送;如果不使用此技术,就必须在使用前下载整个媒体文件。流式传输可传送现场影音或预存于服务器上的影片,当观看者在收看这些影音文件时,影音数据在送达观看者的计算机后立即由特定播放软件播放。

我们知道直播视频是一连串的图片,我们通过帧率(FPS)、像素等等来表示视频的品质等等。

例如FPS为30,表示每秒播放30张图片,假设像素为1024*768,每个像素是由RGB组成,每个8位,共24位。

那么每秒的视频就为:30帧 × 1024 × 768 × 24 = 566,231,040Bits = 70,778,880Bytes,一分钟的话就是4G。

所以我们可以发现对于视频直播的处理必须要经过相应的编码处理,来降低传输的消耗。编码就是一个压缩的过程。

视频和图片的压缩过程的特点

  1. 空间冗余:图像的相邻像素之间有较强的相关性,一张图片相邻像素往往是渐变的,不是突变的,没必要每个像素都完整地保存,可以隔几个保存一个,中间的用算法计算出来。
  2. 时间冗余:视频序列的相邻图像之间内容相似。一个视频中连续出现的图片也不是突变的,可以根据已有的图片进行预测和推断。
  3. 视觉冗余:人的视觉系统对某些细节不敏感,因此不会每一个细节都注意到,可以允许丢失一些数据
  4. 编码冗余:不同像素值出现的概率不同,概率高的用的字节少,概率低的用的字节多,类似霍夫曼编码(Huffman Coding)的思路。

常用编码算法的编码大致流程:

img

经过编码之后,一帧一帧的图像,就变成了一串串的二进制,这个二进制可以放在一个文件里面,按照一定的格式保存起来。

常见的文件格式:

  • AVI、MPEG、RMVB、MP4、MOV、FLV、WebM、WMV、ASF、MKV。

常见的编码压缩技术:

  • H.261、 H.262、H.263、H.264、H.265。

    由 ITU(International Telecommunications Union)的 VCEG(Video Coding Experts Group),国际电联下的VCEG制定的标准。

  • MPEG-1、MPEG-2、MPEG-4、MPEG-7。

    ISO(International Standards Organization)的MPEG(Moving Picture Experts Group),ISO旗下的MPEG制定的标准。

视频直播的大致流程

大致的流程可以划分为服务器接流、转码、分发,客户端拉流、解码

  • 主播推流服务器接流:网络协议将编码好的视频流,从主播端推送到服务器,在服务器上有个运行了同样协议的服务端来接收这些网络包,从而得到里面的视频流,这个过程称为接流

  • 服务器转码:服务端接到视频流之后,可以对视频流进行一定的处理,例如转码,也即从一个编码格式,转成另一种格式。因为观众使用的客户端千差万别,要保证他们都能看到直播。

  • 客户端拉流流处理完毕之后,就可以等待观众的客户端来请求这些视频流。观众的客户端请求的过程称为拉流

  • 视频流分发:如果有非常多的观众,同时看一个视频直播,那都从一个服务器上拉流,压力太大了,因而需要一个视频的分发网络,将视频预先加载到就近的边缘节点,这样大部分观众看的视频,是从边缘节点拉取的,就能降低服务器的压力。

  • 客户端解码:当观众的客户端将视频流拉下来之后,就需要进行解码,也即通过上述过程的逆过程,将一串串看不懂的二进制,再转变成一帧帧生动的图片,在客户端播放出来。

img

编码的大致流程

编码的目的是将图片转化为一串串的二进制流

前面已经分析过,视频就是一串图片序列,如果每张图片都完整,消耗会很大,因而会将视频序列分成三种帧:

  • I帧,也称关键帧。里面是完整的图片,只需要本帧数据,就可以完成解码
  • P帧前向预测编码帧。P帧表示的是这一帧跟之前的一个关键帧(或P帧)的差别,解码时需要用之前缓存的画面,叠加上和本帧定义的差别,生成最终画面。
  • B帧双向预测内插编码帧。B帧记录的是本帧与前后帧的差别。要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的数据与本帧数据的叠加,取得最终的画面。

I帧最完整,B帧压缩率最高,而压缩后帧的序列,应该是在IBBP的间隔出现的。这就是通过时序进行编码

img

由上图所示,每一帧可划分为多个,每一片可划分为多个宏块,每个宏块又有多个子块。通过这种形式将一张大的图分解成一个个小块,可以方便进行空间上的编码

虽然视频会通过这种时序进行编码,但最终是一种二进制流。

这个流是有结构的,是一个个的网络提取层单元NALUNetwork Abstraction Layer Unit)。因为在网络上的传输,默认的是一个个的包,因而这里也就分成了一个个的单元。

img

如上图所示,每一个NALU首先是一个起始标识符,用于标识NALU之间的间隔;然后是NALU的头,里面主要配置了NALU的类型;最终Payload里面是NALU承载的数据。

  • NALU的头:主要的内容是类型NAL Type

    • 0x07表示SPS,是序列参数集, 包括一个图像序列的所有信息,如图像尺寸、视频格式等。

    • 0x08表示PPS,是图像参数集,包括一个图像的所有分片的所有相关信息,包括图像类型、序列号等。

      在传输视频流之前,必须要传输这两类参数,不然无法解码。为了保证容错性,每一个I帧前面,都会传一遍这两个参数集合。

      如果NALU Header里面的表示类型是SPS或者PPS,则Payload中就是真正的参数集的内容。

      如果类型是帧,则Payload中才是正的视频数据每一个NALU里面保存的是一片。对于每一片,到底是I帧,还是P帧,还是B帧,在片结构里面也有个Header,这里面有个类型,然后是片的内容。

这样,整个格式就出来了,一个视频,可以拆分成一系列的帧,每一帧拆分成一系列的片,每一片都放在一个NALU里面,NALU之间都是通过特殊的起始标识符分隔,在每一个I帧的第一片前面,要插入单独保存SPS和PPS的NALU,最终形成一个长长的NALU序列

数据流在主播端到服务端传输的流程

将视频进行编码后转化成的二进制流需要被打包成网络包才能够进行发送,使用的是RTMP(Real Time Messaging Protocol,实时消息传送协议)协议(这里是以RTMP协议为例,当然还有其它协议可以用于发送,原理都类似的)。这一步就是推流过程。

RTMP,全称 Real Time Messaging Protocol,即实时消息传送协议。Adobe 公司为 Flash 播放器和服务器之间音视频数据传输开发的私有协议。工作在 TCP 之上的明文协议,默认使用端口 1935。协议中的基本数据单元成为消息(Message),传输的过程中消息会被拆分为更小的消息块(Chunk)单元。最后将分割后的消息块通过 TCP 协议传输,接收端再反解接收的消息块恢复成流媒体数据。

RTMP是基于TCP的,因而肯定需要双方建立一个TCP的连接。在有TCP的连接的基础上,还需要建立一个RTMP的连接,也即在程序里面,你需要调用RTMP类库Connect函数,显示创建一个连接。

通过这个RTMP握手来协商版本号和时间戳。

  • 如果客户端、服务器的版本号不一致,则不能工作。
  • 在视频播放时,数据流互通的时候,是一定要带上时间戳的,通过这个知道需要什么时候的数据。

握手时,需要发送六条消息:客户端发送C0、C1、 C2,服务器发送S0、 S1、 S2。

C0、C1表示客户端的版本号、时间戳。

S0、S1表示服务端的版本号、时间戳。

C0、S2表示客户端对服务端时间戳的确认、服务端对客户端时间戳的确认。

  • 首先,客户端发送C0表示自己的版本号,不必等对方的回复,然后发送C1表示自己的时间戳。
  • 服务器只有在收到C0的时候,才能返回S0,表明自己的版本号,如果版本不匹配,可以断开连接。
  • 服务器发送完S0后,也不用等什么,就直接发送自己的时间戳S1。客户端收到S1的时候,发一个知道了对方时间戳的ACK C2。同理服务器收到C1的时候,发一个知道了对方时间戳的ACK S2。

img

握手之后,双方需要互相传递一些控制信息,例如Chunk块的大小、窗口大小等。

真正传输数据的时候,还是需要创建一个流Stream,然后通过这个Stream来推流publish

推流的过程,就是将NALU放在Message里面发送,这个也称为RTMP Packet包Message的格式如下:

img

在发送的时候,会去掉NALU的起始标识符。因为这是元数据信息。并且会将SPS和PPS参数集封装成一个RTMP包发送,然后发送一个个的NALU

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

前面连接的时候,设置的Chunk块大小就是指这个Chunk。将大的消息变为小的块再发送,可以在低带宽的情况下,减少网络拥塞。

通过RTMP Packet包的方式,数据就能源源不断的到达流媒体服务器,大致流程如下图:

img

这时候,为了防止用户量过大给服务器带来过大的压力以及所有用户都去同一个地方下载速度过慢的问题。流媒体服务器还需要通过分发网络将视频流进行分发。

分发网络分为中心边缘两层:

  • 边缘层服务器部署在全国各地及横跨各大运营商里,和用户距离很近;

  • 中心层是流媒体服务集群,负责内容的转发。智能负载均衡系统,根据用户的地理位置信息,就近选择边缘服务器,为用户提供推/拉流服务。

    中心层也负责转码服务,例如,把RTMP协议的码流转换为HLS码流。

在这里插入图片描述

客户端进行拉流

客户端想要观看直播,也需要通过RTMP协议想服务器进行拉流。

img

先读到的是H.264的解码参数,例如SPS和PPS,然后对收到的NALU组成的一个个帧,进行解码,交给播发器播放,一个绚丽多彩的视频画面就出来了。

注意:RTMP协议是基于TCP,由于TCP要保证可靠传输,所以可能会由较高的延迟,实际中可能会用其它基于UPD的协议来实现网络直播(例如阿里云提供的ARTC),这里只是用RTMP协议来作为案例介绍。

猜你喜欢

转载自blog.csdn.net/qq_53578500/article/details/126799445