颜色编码
视频,本质上就是一连串的静态图片的播放过程。因此我们对于视频的的讨论都可以回到图片中去。
对于图片而言,可以分为两种颜色编码方法来表示图片:RGB和YUV。
RGB
现如今我们使用的屏幕设备都是RGB屏幕,主要有红,绿,蓝三种原色组成,其他的所有颜色都是这三种颜色通过比例组合而成。
由于RGB设备的普及,所以图片/视频的展示都是使用RGB的颜色编码方法来展示的。
但是我们都知道一张RGB图片占用的磁盘空间有多大,假如1920×1080的图片,单个像素格式为RGB_888,就是一个像素占位24bit,那么一张图片的大小则是:
size = 1920x1080x3 byte = 5.93M
YUV颜色编码的图片则可以实现RGB近似的效果占用空间却明显小于后者,它也是视频在存储时的主要颜色编码形式。
YUV
不同于RGB的颜色分类方法,YUV则是把颜色分为亮度和色度。
Y指的是亮度(luma,Luminance),U,V则指的是色度,这种编码方法在不同的领域名称上会有细微的差别:比如YCbCr,Y’UV,YPbPr,这些都可以统称为YUV,一般YUV/Y‘UV都用于编码电视信号(模拟信号),而YCbCr则用于编码数字图像。在本文中我们说到YUV时,主要指的是YCbCr。
Y:亮度分量,(可以理解为图像的黑白部分)
Cb:色度的蓝色分量,(照片蓝色部分去掉亮度Y)
Cr:色度的红色分量,(照片红色部分去掉亮度Y)
一张图片通过YUV编码方式进行分离后的效果如下:
关于YUV,如果对于YUV取值范围进行细分还可以分为两种类型:
- TV range(Limit range):Y∈[16,235],Cb∈[16-240] ,Cr∈[16-240] ,主要是广播电视采用的数字标准。
- Full range:Y、Cb、Cr∈[0-255] ,主要是PC端采用的标准,所以也称PC range。
YUV与RGB的转换
YUV和RGB这两种颜色编码方法是可以相互转换的,也就是知道其中一个就可以求取另一个,而而且这个转换方法是由国际相关组织提供的一些固定的公式(当然不同版本不同类型的协议公式有所不同):
以根据ITU-R BT.601 标准为例
在TV Range的的范围下
// TV Range
RGB to YUV:
Y = 0.299R+0.587G+0.114B // Y本质上就是从原图得到的一张灰度图
Cr = V = 0.713(R−Y)=0.500R−0.419G−0.081B
Cb = U = 0.564(B−Y)=−0.169R−0.331G+0.500B
YUV to RGB:
R = 1.164(Y−16)+1.596(V−128)
G = 1.164(Y−16)−0.813(V−128)−0.391(U−128)
B = 1.164(Y−16)+2.018(U−128)
//RGB的范围是[0,255],Y的范围是[16,235],UV的范围是[16,239]
同样的标准下,Full range的公式则有所不同用:
RGB to YUV:
Y = 0.299 * R + 0.587 * G + 0.114 * B
Cr = V = -0.169 * R - 0.331 * G + 0.500 * B
Cb = U = 0.500 * R - 0.439 * G - 0.081 * B
YUV to RGB:
R = Y + 1.400V - 0.7
G = Y - 0.343U - 0.711V + 0.526
B = Y + 1.765U - 0.883
// RGB的范围是[0,255],Y的范围是[0,255],UV的范围是[0,255]
YUV采样方法
经过大量研究实验表明,视觉系统对色度的敏感度远小于亮度,因此再编码YUV图片时,常常会保证Y分量数据不变,相应比例减少U V分量的数据,但是图像的质量基本不会改变。
- 4:4:4表示4个Y,对应4个Cb以及4个Cr。
- 完全采样,占用空间size=wh3 byte
- 4:2:2 表示4个Y,对应2个Cb以及2个Cr。
- size=wh2 byte,节省1/3空间
- 4:2:0 表示4个Y,对应1个Cb以及1个Cr。
- size=wh1.5 byte 节省1/2的空间
- 4:1:1 表示4个Y,对应1个Cb以及1个Cr。
- size = wh1.5 byte 节省1/2的空间
以上几种采样方法,YUV420是视频图片帧中最常用的采样比例,在这个比例下,存储空间节省一半,但是图片质量变化不大。
YUV存储方式
对于YUV数据,有两种存储方式:
- packed format
- 紧缩格式是把数据混合在一起,交错存储。比如yuv422 packed可能是这样的
- Planar format(主要的)
- 平面格式则是把不同的分量数据分开存储:先连续存储所有的Y,在连续存储所有的U,然后V……(下面的例子主要以palanar为主)
YUV存储格式
根据不同的采样方式以及不同的存储方式,可以生成不同的YUV存储格式。比如YV12/I420/YU12/NV12/NV21 都属于 YUV420。
YUV格式有YUY2、YUYV、YVYU、UYVY、AYUV、Y41P、Y411、Y211、IF09、IYUV、YV12、YVU9、YUV411、YUV420等,其中比较常见的YUV420分为两种:YUV420P和YUV420SP。
YV12/I420/YU12
YV12与YV12都称为YUV420P(Planar格式),表示他们都是4:2:0,而且是Planar的存储方式。他俩的区别在于在分开存储时,u分量和v分量谁在前面(Y分量总是在最前面)。
存储示意图
- YU12: YYYYYYYY UU VV
- YV12: YYYYYYYY VV UU
YU12格式在Android平台中也称作I420
YU12/I420存储格式
YV12存储格式
YV12的存储方式就是把上图中的U和V分量的存储位置对调即可。
NV21/NV12格式
这两种格式都属于YUV420SP(Semi-Planar)格式,这种格式和planar类似,但是UV分量时交错存储的。
因此NV21和NV12的区别主要在于UV分量交错存储时,谁在前面:
- NV12: YYYYYYYY UVUV
- NV21: YYYYYYYY VUVU
NV12存储格式
NV21存储格式
在NV12的基础上,把U和V的分量位置对调即可
虽然YUV的存储格式繁多但是对于一般的开发者而言,掌握了上述几种基本可以满足需要了。
小结
显示RGB
存储YUV
视频基本概念
复用(封装)与解复用(解封装)
-
muxer(复用)
- 把音频,视频,字幕合并到一个封装格式中 .在Android中实现复用的是MediaMuxer
-
demuxer(解复用)
- 从媒体封装格式把视频,音频,字幕等拆分开来,在Android中,实现解复用的是MediaExtractor
帧率
即视频在一秒钟之内的帧数,电影一般24,手机设备录制一般30,60。
帧类型
视频中存在三种帧,I帧,P帧,B帧:
- I帧: 也称关键帧,依靠自身的数据即可解码出一帧图像。编码压缩比例不高
- P帧:预测帧,利用时间和空间的相关性,依靠前一帧和自身来解码处一帧数据 编码压缩比例较高
- B帧: 双向预测帧,即需要利用前后两帧的数据来解码自身这一帧的数据,编码压缩比例极高。
因为B帧这种特殊的存在,所以未解码的视频流中,帧的解码顺序与播放顺序是不一致的。
假如正常帧播放顺序是I B P,那么在视频流中这三帧的顺序应该是I P B,因为B帧的生成需要前后两帧数据,所以会出现先解码P帧,再解码B帧的情况。
一般视频中I帧较少,P帧,B帧占大多数,所以才能把一部电影压缩到几个G的大小。
PTS和DTS
- PTS 显示时间戳。指示帧应该在什么时间点被呈现给用户。PTS 是在解码后确定的时间戳,用于视频帧或音频帧的渲染或播放顺序
- DTS 解码时间戳。 指示解码器应该在什么时间点开始解码该帧(解码顺序)。DTS 是在解码之前确定的时间戳,由解码器按正确的顺序解码帧。(它是在编码时由编码器设置的)
有了解码时间戳,就可以保证I/P/B帧的按照正确顺序解码,有了PTS,则可以保证I/P/B帧的按照正确顺序播放
音视频同步
由于我们说的视频往往是指音频+视频,而这两者又是独立的数据,分别由独立的设备进行播放,因此再播放时,往往需要主要音视频的同步。音视频同步的基本原理就是管理音视频的数据,按照PTS的时间顺序播放。
实际操作来看,一般需要选取一个参考时间轴,这个参考每次音频或者视频解码完成之后,通过比对现实时间戳和参考时间轴时间来控制播放进度。
而这个参考时间轴,可以选择音频时间轴,视频时间轴,或独立时间轴,一般选择独立时间轴。
编码标准
前面虽然讲到,从RGB转向YUV的过程是可以显著节省视频的存储空间,但是这远远不够,最终视频存储空间还是要靠编码来进行压缩。因此市面上有很多对视频帧进行编码的编码标准:h263,h264(重点),h265,vp8,vp9…
其中,H.264是目前使用最广泛,支持最广泛的适配编码器,而随着4K/8K的逐步普及,视频编码器应该会逐渐向H.265 过渡。
视频编码标准的算法一般是非常复杂的,对于一般开发者而言不需要深入接触
封装格式
对于视频而言,一般指的是视频+音频。而这两种数据本质上是独立的数据,因此需要把他们按照特定的规则协议封装成一个文件让播放器播放。
目前市面上主要的封装格式有:MP4(主要),MKV,AVI,FLV,TS…
这些封装格式主要可以分为两类:存储类,流媒体类
- 存储类: 面向存储使用
- MP4,MKV,AVI
- 流媒体类: 面向流媒体使用
- FLV,TS
之所以会出现这样的区别,主要是看封装格式是否能支持一遍下载,一边解码,一边播放。
资料参考
https://ibabyblue.github.io/2020/04/27/YUV%E4%B8%8ERGB%E6%A0%BC%E5%BC%8F%E8%BD%AC%E6%8D%A2/