对于直播来说,都使用了什么协议了?
无论是直播还是点播,都是基于视频数据的传输,那么如何进行传输视频数据?
我们先提出三种专有的名词,
1.AVI MPEG RMVB MP4 MOV FLV ASF等
2.H.261,H.262,H.263,H.264,H.265
3.MPEG-1,MPEG-2,MPEG-4,MPEG-7
说完这三种专有的名词,不要急,我们首先说一下视频,它的本质,视频的本质就是一组组的图片,在快速的播放从而形成的连续的视频
每一张图片可以说是一帧,只要帧数足够多,播放的足够快,假如每秒30帧就能形成一个30帧的视频,那么这每秒30帧我们称之为30fps,30帧率
那么,每一张的图片都是由像素点组成的,假设为1024*768,每个像素都是由RGB组成,每个8位,一种24位
那么假设30FPS的视频,每秒占用的大小为
30*1024*768*24=566231040Bits = 70778880Bytes
那么,一分钟的传输,就是4个G,这谁扛得住啊
于是.我们必须进行相关的压缩和编码,编码其实就是一个压缩的过程
整体的编码利用了视频的一些特性
1.空间冗余:图像的相邻像素点之间具有一定的关联性,一个图片的相邻像素往往是渐变的,并非突变的,没有必要所有的像素都保存,而是隔几个保存一个,中间的通过算法计算出来
2.时间冗余,视频之中,相邻的图像是具有相似性的,连续的图片也不是突变的,而是可以通过现有的图片进行预测和推断
3.视觉冗余:人的视觉系统对于某些的细节并不敏感,因此丢失了一些细节也没有问题,可以丢失一些数据
4.编码上的冗余,对于不同的像素值,出现的概率也不同,概率高的字节少,概率低的让其字节多,从而类似霍夫曼编码类似
大致的编码过程如下
然后视频编码既然有了思路,为了统一编码,就有了视频编码的格式
主要的流派有两个
流派一:ITU的VCEG,做视频编码出身的,对应的名词系列二
流派二:ISO的MPEG,这个是做视频传输出来的,对应的名词系列三
后来两者统一制定的, H.264/MPEG-4 AVC
经过编码后,生动活泼的一帧帧的图片,变成了一串串的二进制,在这个二进制放在一个文件中,按照一定的格式保存,就是名词系列一
如何进行直播的视频流传输呢?
二进制可以通过某种网络协议进行封装,放在互联网上传输
网络协议将编码好的视频流,从主播端推送到服务器,然后服务器上有个运行了同样网络协议的服务器端来接收网络包,然后得到网络流,这一步的操作称为接流
然后接收到流之后,进行对视频流的处理,称为转码,从一种编码格式转换到另一种编码格式,这一步是因为观众的客户端和客户端的分辨率千差万别,我们要保证统一的推送
流处理完成后,等待观众的客户端来请求这些处理好的视频流,这请求的过程称为拉流,就好比我按照1080*1920 30FPS的格式请求视频流,服务器就是将这一种格式的视频流给我
客户端获取到了视频流,也进行解码,进行处理,将二进制变成了一帧帧的图片,从而从客户端播放出来
然后下一个问题,如何进行编码呢?
首先说编码中的一个重要压缩方式,时间上的预测
我们将视频序列分为了三种帧
I帧:关键帧,里面是完整额图片,只要本帧数据数据,就可以完成解码
P帧:前向预测编码帧,P帧表示这一帧和之前一个I帧或者P帧之间的差别
B帧:双向预测内插编码帧,B帧记录的是本帧和前后帧的差别,要解码B帧,不仅要取出之前的缓存画面,还要解码之后的画面,利用叠加,获取最终的画面
那么I帧最完整,B帧压缩率最高,这就是时间上的编码
然后在一个帧中,分成了多个片,每个片分成了多个宏快,每个宏块分为了多个子快,将一个图片分为了一个个的小块,进行了空间上的编码
然后时空综合,完成了一个二进制的流,这个流是有结构的,是一个个网络提取层单元 NALU,方便传输,因为传输的是一个个的包,于是这就是一个个的单元
在这个NALU的包中,首先是一个NALU的标识,标识了NALU的间隔,然后是NALU的头,说明了NALU的类型,最终是Payload是NALU的数据
NALU的头里面,主要的内容类型是NAL TYPE
0x07标识的SPS,是序列参数集,说明了这个序列中的所有信息,说明了图像的尺寸,视频格式
0x08表示了PPS,是图像参数集,说明了一个图像的所有分片的信息,包含了图像类型和序列号
在传输视频流之前,必须要有这两个参数,不然怎么解码呢?
为了保证不出错,每个I帧都会带着两个参数集合
然后如果是 0x07 或者 0x08,其中的payload就是真正的参数集内容
然后是01-05就是说明是什么类型的帧,每个帧里面payload里面就是片的内容
那么如何推流?
那么这个格式,如何进行网络的传输呢?
肯定是有对应的协议,我们使用了RTMP协议,进行发送包,我们使用了RTMP协议,
RTMP是基于TCP的,肯定需要建立一个TCP连接的基础上,然后建立一个RTMP连接,我们需要在程序中,调用RTMP类库的Connect函数,创建一个连接
RTMP的单独连接,主要是商量了两件事情,一个是版本号,如果是客户端和服务器端的版本号不一样,就没法正常的工作,另一个是时间戳,如果时间戳有差值,就要立刻修正
整体的RTMP的建立如下
首先,客户端发送了C0表示自己的版本号,不用等待回复,直接发送了C1表示了自己的时间戳然后服务器收到了C0,才会发挥S0,表示自己的版本号,版本号不匹配则可能不连接
S0发送完也是不等待,直接发送自己的时间戳S1,客户端收到了S1,发送了一个知道对方时间戳的C2,同理服务器收到了C1,发了一个知道对方时间戳的S2
这样就是握手完成了
然后可能传递Chunk块的大小,窗口的大小的信息,
真正传输数据的时候,需要创建一个stream流,然后进行publish
推流的时候,就是讲NALU放在message中发送,这就是RTMP Packet包
发送的时候,去掉了NALU的其实标识符,然后将SPS和PPS封装为了一个RTMP包发送,然后是一个个片的NALU
RTMP收发数据的时候并不是以Message为单位的,而是把mesage拆分了,拆分成了Chunk发送,这必须在一个Chunk发送完成后,才能发送下一个Chunk
假设一个视频的消息长度是307,Chunk的大小约定为128,于是会拆分为三个Chunk
第一个Chunk的Type=0,表示头是完整的,头里面的TimeStamp为1000,,总长度为Length为307,类型为9.是个视频 stream ID为 123456,正文部分承担128个字节的Data
第二个的Chunk也发送了128个字节,由于和第一个头一样,所以表明自己的Chunk Type为3,表明头一样不就不发送了
这样,数据就源源不断的发送到流媒体的服务器,过程如下
然后观众就可以通过RTMP协议从流媒体上拉取数据,但是这么多的用户,都去一个地方拉取,肯定不合适.于是使用了内容分发网络,内容分发网络分为了中心和边缘两层,边缘层部署在全国各地和各大运营商中,中心层流媒体服务集群,负责内容的转发,只能负载均衡系统,根据用户的地理位置信息,就进选择边缘服务器,将中心层推送过来的流转发给用户
后面说,CDN会说明的
客户端如何看到视频?
首先是H.264的解码参数,例如SPS和PPS,然后对收到的NALU组成的帧,进行解码,并转发给播放器播放
本章小结:
视频的名词比较多,但是大多就是通过时间或者空间的各种算法来压缩数据
压缩好的数据,为了传输组成了一系列的NALU,然后根据帧和片来排列
排列好的NALU,传输的时候,要按照RTMP包的格式来包装,RTMP的包会拆分为Chunk来传递
推送到流媒体集群的视频经过转码和分发,可以被客户端通过RTMP协议拉取,然后组合为NALU,解码成视频格式来播放
课后思考:
1.基于RTMP的视频流传输有什么问题吗?如何优化?
2.下载电影是什么协议呢?
1.因为RTMP基于TCP传输,所以不适合做直播,需要实时的推送,引入UDP试试
2.使用了P2P协议
宏块和子块建立成为了NALU中的payload,在RTMP建立起来后,将NALU放在chuck块中的message进行发送
现在因为RTMP基于TCP做的传输,不如HTTP-FLV,基于HTTP做的封装,更容易进入防火墙内
RTMP建立连接的序列是什么呢>
客户端C0,C1,C2.服务端发送S0,S1,S2
首先,客户端发送C0表明自己的版本号,不必等对方的回复,然后发送C1表明自己的时间戳
服务器只有收到C0的时候,才能发S0,表明自己的版本号,如果版本不匹配,可以断开连接
服务器发送完S0后,会直接发送S1,客户端收到S1的时候,发一个知道了对方时间戳的ACK C2,同理服务器收到C1的时候,发一个知道了对方时间戳ACK S2