说在前面的话
视频对于前端工程师来讲,真的是简单到极点,直接给一个视频地址,然后赋值到video下面,搞定!对于普通的后台工程师也很简单,因为我们编程都是对每一帧进行编程,不用关心视频的怎么编码、解码、传输等流程,但是呢,基础这东西,有一句名言:**基础就像眼镜,用到时候才知道有多重要。
现实世界的原型
第一个是30年前的放映机,不知道大家见过没有,一个非常大一卷的带子,放到放映机上面,然后以每秒x张胶片的速度一张一张的播放
第二个是一个创意,在一个空笔记本上,画上连续动物奔跑的图,然后快速的翻阅,就能看到动物在奔跑,感觉像在放动画片一样
现实世界的这两种视频的表现形式都是一致的,就是每一帧都采用完整的一张图,然后按照第秒20张的速度进行播放,从而形成视频
有什么问题吗?
这种表现形式最直观,但有一个比较严重的问题,就是体积太大了。你看第一种,要放一部电影,得需要非常大的一卷的带子,非常不利用携带;第二种,要展示几秒种的动画,你可能得画整整一本;放到数字世界里呢,假如我们存放一部无损、1小时、1080P电影,每秒20帧的速度,你需要的存储空间大约为:6203600=421G
提几个概念先
编码格式:既然文件那么大,肯定得压缩,也就是对视频进行编码和解码,用哪种方式编解码,就叫视频的编码格式。目前最流行的编码格式是:H.264,还有其他的格式,如更加先进的H.265和比较落后的H.263。
封装格式:俗称就是文件的格式,像我们看到
.avi/.mp4/.mkv
,这些都是封装格式。因为我们看到视频都是由声音和图像组成的,封装格式就是把图像和声音组合到一起,比如我们把H.264编码的视频和AAC编码的音频封装成.avi
格式的视频文件,也可以把H.265和AAC-3组合到一起,生成.mkv
格式的文件等等组合的方式。比特(bit)和字节(byte):这两个概念我们平时经常搞混,换算比较简单:1byte=8bit。有一个比较重要的结论比特用于传输,字节用来存储。举个例子:如果服务器上存放着一个80M大小的文件,你家的网络带宽是80M,你说理论上是1秒就能把文件下载来你本地吗?聪明的你,肯定猜到了,不是!因为直觉告诉我们,80M的网张带宽,下载只有8M左右,所以需要10秒才能下载完,嘿嘿,大体上是这样的,我们来计算一下啊。服务器存放着80Mbyte,注意:这里是byte,而你的带宽80Mbit,注意:这里是bit,根据上面的换算公式,80Mbit=10Mbyte,所以,你的实际传输速度是10M/s,所以需要8秒,通过上面的例子,你就能更加深刻的理解那个结论了吧。
码率:不太好总结,还是看个例子吧。一个1G的视频,100分钟,它的码率的算法是这样的:1G=1x1024MBx8bit,100min=100minx60s=6000s,码率=1024x8/6000~~1.4M/s。
视频的产生流程
摄像机采集完一帧图像之后,会生成一个无损的
.bmp
文件格式的图片文件,这个图片是位图,分8位、24位、32位,用win的话,可以用画图软件随便画一个,然后你保存,默认就是.bmp
的格式,下面就会让你选位数,我们以1080P的图像(24位)为例,算一个这个位图的大小:54+((1920*1080)x24)/8~~6M。54是图片的头信息,24是图像的位数,除以8是把bit转成byte。很显然,6M一帧的视频不可能进行网络传输,所以需要对这个.bmp
文件进行有损的压缩,压缩成200KB的JPEG文件,这块的压缩比是1/30。每一帧是200KB,很显然也不利于网络传输,咱们算一下码率(以每秒20帧):(200x20x8)/ 1024 = 32M,也就是一对一传输,你家的网络带宽至少得32M才能勉强播放(一般的视频的码率都保持在2M以内)。现在我们前面说的编码格式:H.264就粉墨登场了。
编码的基本原理
抛开其他东西不谈,我们也会发现,视频的连续帧之间的差别其他非常小,就像上面提的那个动画书,没有必要把每一帧都单独生成图片,只要记录帧和帧之间的差别其实就可以了。咱们这么想,H.264编码也是按这个思路来进行压缩的。这点和SVN比较类似,起初我们得提交一个原始文件,这个原始文件就相当是
I帧
,也就是上面我们看到摄像机产生的那张200KB
大小的JPEG
文件,有了I帧
之后,下一帧就可以以此帧进行对比,生成差异文件,这个差异文件就是P帧
,(这个P帧
是通过H.264
的运动补偿算法算出来的),依次类推,后面的帧都是前面帧的差异,直到下一个GOP
的出现。恩?GOP
是个什么鬼?GOP
就是单位时间内一组I帧和P帖
组合,一般的设置是一个GOP
为2秒,也就是在这个GOP
中,只有一个I帧
,其余都是P帧
(其实还有B帧
,这个后面说),那现在们我们得到另外一个结论:一个GOP中,只有加载出I帧,才能渲染出一段视频,这个也好理解哈,没有原始的对比文件,只有差异文件,是啥也渲染不出来的。还有一种帧叫
B帧
,P帧
我们上面已经讲清楚了,就和前一帧的差异,那B帧
是双向的差异,就是他即参考前一个帧,也参考后一个帧,这样就带来两个好处:1.更高的压缩比;2.更加快速的解码能力。第二点还好理解些,双向参考,解码时可以进行多线程解码,而不像P帧一样,要等待前一帧的结果。第一点好处,我查了很多资料也没说清楚,只知其然,不知其所以然。
一些视频现象的分析
有了上面的基础知识,我们就可以分析几个我们使用视频的时候经常遇到的问题
马赛克现象,我们先看这个图:
从图中我们能看出一些东西来,不是所有画面都出马了,只是一少部分的图像出现了错位。我们假设只有3帧,IPP,如果第一个P帧丢失,第二个P帧参考的是I帧,也就是P帧的运动补偿补偿到I帧上,是不是就出现这样的现象了。然后你会发现,过一会这个马又没有了,是因为视频是基于
GOP
的,一个GOP
里(一般2秒),只有丢一帧(P帧
或B帧
),那么整个2秒的时间都会是马赛克,再来一个GOP
,如果这人GOP
帧不丢失的情况,视频自然就好。卡顿:为了避免上面的现象,我们一般会设置,当有一帧丢失的时候,我们会放弃整个的
GOP
,这样,你的视频就会出现Loading的状态,Loading时间决定了你丢的是哪一帧,如果是I帧
,那么你得等2秒,如果你丢的是最后一帧,那么你得等1/20秒。延迟:也许你会发现,有的时候打开个视频马上就能看,有时候要等上一小会,这个也很好解释。一个
GOP
是从I帧
开始的,所以只有加载到第一个I帧
时,才会开始播放视频,我们还假定一个GOP
是2秒,如果你运气好,正好取的GOP
的I帧
,那么就是秒开;如果你运气不好,你的网络请求,正好是I帧
后面的P帧
,那么不好意思,你得2秒,等到下一个GOP来的时候,你才能开始播。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。