1)YUV簡介
YUV格式有兩大類:planar和packed。
對於planar的YUV格式,先連續存儲所有像素點的Y,緊接着存儲所有像素點的U,隨后是所有像素點的V。
對於packed的YUV格式,每個像素點的Y,U,V是連續交*存儲的。
YUV,分為三個分量,“Y”表示明亮度(Luminance或Luma),也就是灰度值;而“U”和“V” 表示的則是色度(Chrominance或Chroma),作用是描述影像色彩及飽和度,用於指定像素的顏色。
與我們熟知的RGB類似,YUV也是一種顏色編碼方法,主要用於電視系統以及模擬視頻領域,它將亮度信息(Y)與色彩信息(UV)分離,沒有UV信息一樣可以顯示完整的圖像,只不過是黑白的,這樣的設計很好地解決了彩色電視機與黑白電視的兼容問題。並且,YUV不像RGB那樣要求三個獨立的視頻信號同時傳輸,所以用YUV方式傳送占用極少的頻寬。
2)YUV存儲格式
YUV碼流的存儲格式其實與其采樣的方式密切相關,主流的采樣方式有三種,YUV4:4:4,YUV4:2:2,YUV4:2:0,關於其詳細原理,可以通過網上其它文章了解,這里我想強調的是如何根據其采樣格式來從碼流中還原每個像素點的YUV值,因為只有正確地還原了每個像素點的YUV值,才能通過YUV與RGB的轉換公式提取出每個像素點的RGB值,然后顯示出來。
用三個圖來直觀地表示采集的方式吧,以黑點表示采樣該像素點的Y分量,以空心圓圈表示采用該像素點的UV分量。
先記住下面這段話,以后提取每個像素的YUV分量會用到。
1. YUV 4:4:4采樣,每一個Y對應一組UV分量8+8+8 = 24bits,3個字節。
2. YUV 4:2:2采樣,每兩個Y共用一組UV分量,一個YUV占8+4+4 = 16bits 2個字節。
3. YUV 4:2:0采樣,每四個Y共用一組UV分量一個YUV占8+2+2 = 12bits 1.5個字節。
3)YUV420類型
3.1) YUV420p和YUV420sp區別
因為YUV420比較常用, 在這里就重點介紹YUV420。YUV420分為兩種:YUV420p和YUV420sp。
YUV420sp格式如下圖:
YUV420p數據格式如下圖:
3.2) YUV420p和YUV420sp具體分類和詳情
YUV420p:又叫planer平面模式,Y ,U,V分別再不同平面,也就是有三個平面。
YUV420p又分為:他們的區別只是存儲UV的順序不一樣而已。
I420:又叫YU12,安卓的模式。存儲順序是先存Y,再存U,最后存V。YYYYUUUVVV
YV12:存儲順序是先存Y,再存V,最后存U。YYYVVVUUU
YUV420sp:又叫bi-planer或two-planer雙平面,Y一個平面,UV在同一個平面交叉存儲。
YUV420sp又分為:他們的區別只是存儲UV的順序不一樣而已。
NV12:IOS只有這一種模式。存儲順序是先存Y,再UV交替存儲。YYYYUVUVUV
NV21:安卓的模式。存儲順序是先存Y,再存U,再VU交替存儲。YYYYVUVUVU
官方文檔如下:
YV12
All of the Y samples appear first in memory as an array of unsigned char values. This array is followed immediately by all of the V (Cr) samples. The stride of the V plane is half the stride of the Y plane, and the V plane contains half as many lines as the Y plane. The V plane is followed immediately by all of the U (Cb) samples, with the same stride and number of lines as the V plane (Figure 12).
大致意思是:先存儲完所有的Y,后面緊跟着存V,V的步長(也就是寬)是Y的步長的一半,V的行高是Y的一半。V存儲完后面緊跟着存U,所有的U,步長河行高和V相同,也就是都是Y的一半。
Figure 12:

NV12
All of the Y samples are found first in memory as an array of unsigned char values with an even number of lines. The Y plane is followed immediately by an array of unsigned char values that contains packed U (Cb) and V (Cr) samples, as shown in Figure 13. When the combined U-V array is addressed as an array of little-endian WORD values, the LSBs contain the U values, and the MSBs contain the V values. NV12 is the preferred 4:2:0 pixel format for DirectX VA. It is expected to be an intermediate-term requirement for DirectX VA accelerators supporting 4:2:0 video.
Figure 13:

3.3)YUV420的內存計算
width * hight =Y(總和)
U = Y / 4 V = Y / 4
所以YUV420 數據在內存中的長度是 width * hight * 3 / 2(即一個YUV是1.5個字節),所以計算采集的數據大小:width * hight * 1.5*frame*time
以720×488大小圖象YUV420 planar為例,
其存儲格式是: 共大小為720×480×3 × 1.5字節,
分為三個部分:Y,U和V
Y分量: (720×480)個字節
U(Cb)分量:(720×480 × 1/4)個字節
V(Cr)分量:(720×480 × 1/4)個字節
三個部分內部均是行優先存儲,三個部分之間是Y,U,V 順序存儲。
即YUV數據的0--720×480字節是Y分量值,
720×480--720×480×5/4字節是U分量
720×480×5/4 --720×480×3/2字節是V分量。
一般來說,直接采集到的視頻數據是RGB24的格式,RGB24一幀的大小size=width×heigth×3 Bit,RGB32的size=width×heigth×4,YUV標准格式4:2:0 的數據量是 size=width×heigth×1.5 Bit。
在采集到RGB24數據后,需要對這個格式的數據進行第一次壓縮。即將圖像的顏色空間由RGB2YUV。因為,X264在進行編碼的時候需要標准的YUV(4:2:0)。
經過第一次數據壓縮后RGB24->YUV(I420)。這樣,數據量將減少一半,經過X264編碼后,數據量將大大減少。將編碼后的數據打包,通過RTP實時傳送。到達目的地后,將數據取出,進行解碼。完成解碼后,數據仍然是YUV格式的,所以,還需要一次轉換,就是YUV2RGB24。
3.4)關於IOS
做過iOS硬解碼的都知道,創建解碼器時,需要指定PixelFormatType。IOS只支持NV12也就是YUV420中的一種,你搜索420,發現有四個,分別如下:
kCVPixelFormatType_420YpCbCr8Planar
kCVPixelFormatType_420YpCbCr8PlanarFullRange
kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
根據表面意思,可以看出,可以分為兩類:planar(平面420p)和 BiPlanar(雙平面)。
還有一個辦法區分,CVPixelBufferGetPlaneCount(pixel)獲取平面數量,發現kCVPixelFormatType_420YpCbCr8Planar和kCVPixelFormatType_420YpCbCr8PlanarFullRange是三個兩面,屬於420p,iOS不支持。而kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange和kCVPixelFormatType_420YpCbCr8BiPlanarFullRange是兩個平面。這就糾結了,到底用哪一個呢?
我查了官網資料,解釋如下:
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 */
感覺除了亮度和顏色的范圍不一樣,沒發現其它不一樣的。還是糾結,后來查了神網,有人說WWDC視頻有,網址:https://developer.apple.com/videos/play/wwdc2011/419/?time=1527(大概在25:30‘)
解釋如下:

但是我我還是不清楚,清楚的人請告知我一下。
然后我創建的時候分辨使用了kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange和kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,視頻播放出來沒發現什么不一樣,唯一不一樣是計算的步長不一樣。
比如:480*640
如果是:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
Y和UV的步長是512(采用了64字節對齊 非對齊的補0) Y的行寬是640,UV行寬是320
如果是:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
Y和UV的步長是480(實際長度,未補齊) Y的行寬是640,UV行寬是320
我采集的時候setPreset了,所以按照上面提示(但是我還是不是很理解),最后我項目里面還是選擇了kCVPixelFormatType_420YpCbCr8BiPlanarFullRange。