1、前言:
在「简单了解 iOS CVPixelBuffer (上)」中,我们了解了CVPixelBuffer
如何创建、修改、以及检查CVPixelBuffer相关的参数。在上篇文末我们有讲到在这篇文章中,我们将了解颜色空间RGB和YUV的区别以及相关的背景知识,然后回过头来再看CVPixelBuffer
中的kCVPixelFormatType
相关的类型。
相信大家对于RGB都不陌生吧,那么YUV大家是否了解呢,它为我们做了些什么?
在开篇我先提出一个问题:为什么要使用YUV呢? 这个问题在我们了解了颜色空间之后,相信大家心中就已经有了答案。接下来开始我们的正文。
2、颜色空间
颜色空间一词源于英文的Color Space
,在色彩学中,人们建立了多种颜色模型,以一维、二维、三维甚至四维空间坐标来表示某一色彩,这种用坐标系统来定义的颜色范围即颜色空间。
我们经常用到的颜色空间主要有RGB、YUV、CMYK、HSB、HSL
等,其中RGB
和YUV
是视频中使用较多的两种色彩空间。
2.1 RGB
RGB
是由红(Red)、绿(Green)、蓝(Blue)三种颜色组成,我们称为三原色。每个颜色可以取值不同,将三种颜色相混合后,会组成其他的不同的颜色。使用 RGB
表示的图像中,每个像素都有红、绿、蓝三种颜色,每个颜色占8 bit
,即1 byte
。所以一个像素占用3 byte
。
红、绿、蓝三个颜色通道每种颜色各分为256阶亮度,取值为0-255
。
在存储时,我们常常以R
G
B
或者B
G
R
的顺序进行排列,所以在前文中,我们有看到pixelFormatType有kCVPixelFormatType_32RGBA
、kCVPixelFormatType_32BGRA
两种相似的类型(这里的A指的是Alpha
,Alpha
通道一般用作不透明度参数),其实这两个类型只是它们的编码上的顺序不同;
接下来我们熟悉下另一个颜色空间。
【学习地址】:FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发
【文章福利】:免费领取更多音视频学习资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击1079654574加群领取哦~
2.2 YUV
YUV 是 Y’UV、YUV、YCbCr、YPbPr 等色彩空间的统称
YUV
是由 Y
和 UV
组成,前者表示明亮度 (Luminance、Luma)
,后者表示色度(Chrominance、Chroma)
,色度包括两个⽅面:色调、饱和度。
使用YUV的图像,每个像素点都包含 Y、U、V
分量,Y
和UV
分量是分离的,如果只有Y
没有UV
,那么图像就像以前的黑白电视机一样。为了兼容老式电视机,彩色电视机采用的也是 YUV
的颜色空间,不过UV
是存在的。
2.2.1 采样格式
YUV采样格式是个重点,YUV采样格式有三种:
-
YUV 4:4:4
-
YUV 4:2:2
-
YUV 4:2:0
YUV444
YUV444代表每个Y分量分别对应一个U分量和一个V分量。 以4个像素为例: [Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]
存放的码流为: Y0 U0 V0 Y1 U1 V1 Y2 U2 V2 Y3 U3 V3
YUV422
YUV422代表每两个Y分量分别共用一个U分量和一个V分量。 以4个像素为例: [Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]
存放的码流为: Y0 U0 Y1 V1 Y2 U2 Y3 V3
映射出像素点为: [Y0 U0 V1] [Y1 U0 V1] [Y2 U2 V3] [Y3 U2 V3]
YUV420
YUV420代表每四个Y分量分别共用一个U分量和一个V分量。 以8个像素为例: [Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]
[Y5 U5 V5] [Y6 U6 V6] [Y7 U7 V7] [Y8 U8 V8]
存放的码流为: Y0 U0 Y1 Y2 U2 Y3 Y5 V5 Y6 Y7 V7 Y8
映射出像素点为: [Y0 U0 V5] [Y1 U0 V5] [Y2 U2 V7] [Y3 U2 V7]
[Y5 U0 V5] [Y6 U0 V5] [Y7 U2 V7] [Y8 U2 V7]
综上来看,YUV444的存储的数据量和RGB相同,YUV422是RGB的2/3,YUV420是RGB的1/2。
2.2.2 存储方式
YUV有两种存储方式,一种是打包(packed
),一种是平面(planar
).
-
packed
: 先连续存储所有Y分量,然后交叉存储U、V分量; -
planar
:先连续存储所有Y分量,然后在连续存储U、V分量(保证了每个区块连续);
在懂得这些颜色空间的编码格式以及存储方式之后,我们再来看上文中的这些类型的定义,就可以依据这些理论推导出来这些类型代表什么了;
比如说: 444、422、420
表示不同的采样格式(压缩比) 8、10、16
表示bit位数 Planar、BiPlanar
表示平面、双平面 VideoRange、FullRange
其意义是YUV颜色空间中亮度部分 Y
的取值范围,fullRange
的取值范围为luma=[0,255] chroma=[1,255]
,而videoRange
的取值范围为luma=[16,235] chroma=[16,240]
。
kCVPixelFormatType_422YpCbCr8 = '2vuy', /* Component Y'CbCr 8-bit 4:2:2, ordered Cb Y'0 Cr Y'1 */
kCVPixelFormatType_4444YpCbCrA8 = 'v408', /* Component Y'CbCrA 8-bit 4:4:4:4, ordered Cb Y' Cr A */
kCVPixelFormatType_4444YpCbCrA8R = 'r408', /* Component Y'CbCrA 8-bit 4:4:4:4, rendering format. full range alpha, zero biased YUV, ordered A Y' Cb Cr */
kCVPixelFormatType_4444AYpCbCr8 = 'y408', /* Component Y'CbCrA 8-bit 4:4:4:4, ordered A Y' Cb Cr, full range alpha, video range Y'CbCr. */
kCVPixelFormatType_4444AYpCbCr16 = 'y416', /* Component Y'CbCrA 16-bit 4:4:4:4, ordered A Y' Cb Cr, full range alpha, video range Y'CbCr, 16-bit little-endian samples. */
kCVPixelFormatType_444YpCbCr8 = 'v308', /* Component Y'CbCr 8-bit 4:4:4 */
kCVPixelFormatType_422YpCbCr16 = 'v216', /* Component Y'CbCr 10,12,14,16-bit 4:2:2 */
kCVPixelFormatType_422YpCbCr10 = 'v210', /* Component Y'CbCr 10-bit 4:2:2 */
kCVPixelFormatType_444YpCbCr10 = 'v410', /* Component Y'CbCr 10-bit 4:4:4 */
kCVPixelFormatType_420YpCbCr8Planar = 'y420', /* Planar Component Y'CbCr 8-bit 4:2:0. baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrPlanar struct */
kCVPixelFormatType_420YpCbCr8PlanarFullRange = 'f420', /* Planar Component Y'CbCr 8-bit 4:2:0, full range. baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrPlanar struct */
kCVPixelFormatType_422YpCbCr_4A_8BiPlanar = 'a2vy', /* First plane: Video-range Component Y'CbCr 8-bit 4:2:2, ordered Cb Y'0 Cr Y'1; second plane: alpha 8-bit 0-255 */
kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange = '420v', /* Bi-Planar Component Y'CbCr 8-bit 4:2:0, video-range (luma=[16,235] chroma=[16,240]). baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct */
kCVPixelFormatType_420YpCbCr8BiPlanarFullRange = '420f', /* Bi-Planar Component Y'CbCr 8-bit 4:2:0, full-range (luma=[0,255] chroma=[1,255]). baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct */
kCVPixelFormatType_422YpCbCr8BiPlanarVideoRange = '422v', /* Bi-Planar Component Y'CbCr 8-bit 4:2:2, video-range (luma=[16,235] chroma=[16,240]). baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct */
kCVPixelFormatType_422YpCbCr8BiPlanarFullRange = '422f', /* Bi-Planar Component Y'CbCr 8-bit 4:2:2, full-range (luma=[0,255] chroma=[1,255]). baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct */
kCVPixelFormatType_444YpCbCr8BiPlanarVideoRange = '444v', /* Bi-Planar Component Y'CbCr 8-bit 4:4:4, video-range (luma=[16,235] chroma=[16,240]). baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct */
kCVPixelFormatType_444YpCbCr8BiPlanarFullRange = '444f', /* Bi-Planar Component Y'CbCr 8-bit 4:4:4, full-range (luma=[0,255] chroma=[1,255]). baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct */
kCVPixelFormatType_422YpCbCr8_yuvs = 'yuvs', /* Component Y'CbCr 8-bit 4:2:2, ordered Y'0 Cb Y'1 Cr */
kCVPixelFormatType_422YpCbCr8FullRange = 'yuvf', /* Component Y'CbCr 8-bit 4:2:2, full range, ordered Y'0 Cb Y'1 Cr */
3、写在最后
看到这里,为什么要使用YUV呢? 我想每个人心中都已经有了答案。 YUV的优势基本上也已经一目了然,因为压缩率比RGB要高很多,所占的数据存储量相对较小,所以适用于内存中传输视频数据或者处理图像等等一系列的操作。