一、概述
1. 名词定义
帧:视频中的每一张图片
帧率(FPS):每秒图片数
像素:每一张图片,都是由像素组成的。像素由 RGB 组成,每个 8 位,共 24 位。
编码:用尽量少的位保存视频数据
2. 视频和图片的压缩的特点
视频中图片的特点:
- 空间冗余:图片通常是渐变,相邻像素之间有更高的相关性,因此不需要保存所有像素,只需要间隔几个像素,保存一个。其余的像素用算法计算出来
- 时间冗余:视频中,相邻的图像具有相关性,因此视频中也不需要保存所有图片,只需要在相邻的图片中保存一个,其余的根据已有的图片进行推测
- 视觉冗余:人的视觉对一些细节不敏感,因此可以丢失一些数据
- 编码冗余:不同像素值在图片中出现的次数不一样,出现概率高的使用更短的字节进行编码,概率 低的使用字节多的(哈夫曼编码思路)
编码过程:
二、流媒体数据传输
1. 流媒体传输流程
直播数据传输过程:
- 视频通过上述编码流程转换成二进制数据,
- 接流:将编码好的视频封装到网络协议中,通过直播端推送到服务器,服务器有一个运行了同样网络协议的进程接收网络包,从中得到视频流
- 转码:服务端接收到视频流后,对视频进行一些处理(如转码等),确保客户端不同解码器也可以观看到视频
- 拉流:视频处理完后,客户端请求视频流,这个过程叫拉流。若观看的用户很多,可以先将视频分发到边缘节点(CDN),大部分观众观看视频时,直接从边缘节点拉取,缓解服务端压力
- 解码:客户端拉取到数据后,将二进制数据转换成一帧帧的图片,在客户端播放
2. 编码
a. 视频序列
I帧:关键帧,里面包含完整的图片,不依赖于前后帧
P帧:前向预测编码帧,记录这一帧跟之前的一个关键帧(或 P 帧)的差别,依赖之前的帧,叠加上和本帧的区别,生成最终画面
B帧:双向预测内插编码帧,记录这一帧与前后帧的区别,依赖于前后的帧,通过前后画面的数据与本帧数据的叠加,获取最终画面
b. 视频编码方式
时序上的编码:I 帧最完整,B 帧压缩率最高,而压缩后帧的序列,应该是在 IBBP 的间隔出现的。
空间上的编码:在一帧中,分成多个片,每一片都放在一个 NALU 里面,NALU 之间都是通过特殊的起始标识符分隔,在每一个 I 帧的第一片前面,要插入单独保存 SPS 和 PPS 的 NALU,最终形成一个长长的 NALU 序列。
NALU结构:
起始标识符:0000001,标识 NALU 之间的间隔
NALU头:配置了 NALU 的类型,只要内容为 NAL Type,为了保证容错性,每一个 I 帧前面,都会传一遍这两个参数集合。
- 0x07 表示 SPS,是序列参数集, 包括一个图像序列的所有信息,如图像尺寸、视频格式等。
- 0x08 表示 PPS,是图像参数集,包括一个图像的所有分片的所有相关信息,包括图像类型、序列号等。
- 0x01/0x05表示I/P/B帧
Payload:真正的视频数据,由header定义了该数据保存的是I帧还是P帧
3. 推流
RTMP 协议:
- 经过上述流程后,视频数据转换成了二进制流,在推流时,需要将二进制流打包成网络包,经过RTMP协议传输
- RTMP协议基于TCP协议,双方需要建立TCP连接。在TCP 的连接的基础上,还需要建立RTMP连接
- RTMP连接主要用以协定版本号和时间戳(视频播放中,时间是很重要的,后面的数据流互通的时候,经常要带上时间戳的差值,因而一开始双方就要知道对方的时间戳。)
RTMP连接握手流程:
- 客户端发送自己的版本号(C0),不需等待应答,发送自己的时间戳(C1)
- 服务端收到C0后,返回自己的版本号(S0),若版本号不一致,断开连接。不需要等待客户端应答,服务端继续发送自己的时间戳(S1)
- 客户端在收到S1后,发送应答ACK C2。同理,服务端在接收到客户端时间戳C1后,发送ACK S2。握手完成
- 握手完成后,双方传输控制信息(Chunk 块的大小、窗口大小等)
推流数据传输过程:
- 将 NALU 放在 Message 里面发送(RTMP Packet 包)
- 发送的时候,去掉 NALU 的起始标识符。因为这部分对于 RTMP 协议来讲没有用。接下来,将 SPS 和 PPS 参数集封装成一个 RTMP 包发送,然后发送一个个片的 NALU。
- RTMP 在收发数据的时候并不是以 Message 为单位的,而是把 Message 拆分成 Chunk 发送,而且必须在一个 Chunk 发送完成之后,才能开始发送下一个 Chunk。每个 Chunk 中都带有 Message ID,表示属于哪个 Message,接收端也会按照这个 ID 将 Chunk 组装成 Message。(前面连接的时候,设置的 Chunk 块大小就是指这个 Chunk。将大的消息变为小的块再发送,可以在低带宽的情况下,减少网络拥塞。)
例子:假设一个视频消息长307,chunk大小为128,于是拆成以下三个
- Chunk 的 Type=0,包含所有头部信息与128字节视频数据
- Chunk的Type=3,不包含头部信息,包含128字节视频数据
- Chunk的Type=3,不包含头部信息,包含51字节视频数据
完整推流过程:
- 建立RTMP连接,传输窗口大小、带宽等信息
- CreateStream创建流
- 发起推送publish,流开始,发送视频数据流
客户端拉取视频流程:
- 推送完后,观众可以通过 RTMP 协议从流媒体服务器上拉取直播视频。
- 为了缓解服务器压力,可以使用分发网络。分发网络分为中心和边缘两层。边缘分发网络服务器部署在全国各地,和用户距离很近。中心网络是流媒体服务集群,可以进行视频内容转码和转发。智能负载均衡可以根据用户的地理位置,就近选择边缘服务器
4. 拉流
RTMP拉流过程: