用三個圖來直觀地表示採集的方式吧,以黑點表示採樣該像素點的 Y 份量,以空心圓圈表示採用該像素點的 UV 份量。 算法
先記住下面這段話,之後提取每一個像素的 YUV 份量會用到。
windows
YUYV 爲 YUV422 採樣的存儲格式中的一種,相鄰的兩個 Y 共用其相鄰的兩個 Cb、Cr,分析,對於像素點 Y'00、Y'01 而言,其 Cb、Cr 的值均爲 Cb00、Cr00,其餘的像素點的 YUV 取值依次類推。 編碼
UYVY 格式也是 YUV422 採樣的存儲格式中的一種,只不過與 YUYV 不一樣的是 UV 的排列順序不同而已,還原其每一個像素點的 YUV 值的方法與上面同樣。 spa
YUV422P 也屬於 YUV422 的一種,它是一種 Plane 模式,即平面模式,並非將 YUV 數據交錯存儲,而是先存放全部的 Y 份量,而後存儲全部的 U(Cb)份量,最後存儲全部的 V(Cr)份量,如上圖所示。其每個像素點的YUV 值提取方法也是遵循 YUV422 格式的最基本提取方法,即兩個 Y 共用一個 UV。好比,對於像素點Y'00、Y'01 而言,其 Cb、Cr 的值均爲 Cb00、Cr00。 設計
YU12 和 YV12 屬於 YUV420 格式,也是一種 Plane 模式,將 Y、U、V 份量分別打包,依次存儲。其每個像素點的 YUV 數據提取遵循 YUV420 格式的提取方式,即 4 個 Y 份量共用一組 UV。注意,上圖中,Y'00、Y'0一、Y'十、Y'11 共用 Cr00、Cb00,其餘依次類推。
code
NV12 和 NV21 屬於 YUV420 格式,是一種 two-planar 模式,即 Y 和 UV 分爲兩個 Plane,可是 UV(CbCr)爲交錯存儲,而不是分爲三個 plane。其提取方式與上一種相似,即 Y'00、Y'0一、Y'十、Y'11 共用 Cr00、Cb00
YUV420 planar 數據, 以 720×488 大小圖象 YUV420 planar 爲例, 視頻
三個部份內部均是行優先存儲,三個部分之間是 Y, U, V 順序存儲。 內存
4 :2:2 和4:2:0 轉換:
最簡單的方式:
YUV4:2:2 ---> YUV4:2:0 Y 不變,將 U 和 V 信號值在行(垂直方向)在進行一次隔行抽樣。 YUV4:2:0 ---> YUV4:2:2 Y 不變,將 U 和 V 信號值的每一行分別拷貝一份造成連續兩行數據。
在 YUV420 中,一個像素點對應一個 Y,一個 4X4 的小方塊對應一個 U 和 V。對於全部 YUV420 圖像,它們的 Y 值排列是徹底相同的,由於只有 Y 的圖像就是灰度圖像。YUV420sp 與 YUV420p 的數據格式它們的 UV 排列在原理上是徹底不一樣的。420p 它是先把 U 存放完後,再存放 V,也就是說 UV 它們是連續的。而 420sp 它是 UV、UV這樣交替存放的。(見下圖) 有了上面的理論,我就能夠準確的計算出一個 YUV420 在內存中存放的大小: it
width * hight = Y(總和) U = Y / 4 V = Y / 4
因此 YUV420 數據在內存中的長度是 width * hight * 3 / 2,
假設一個分辨率爲 8X4 的 YUV 圖像,它們的格式以下圖:
YUV420sp 格式以下圖
class
YUV420p 數據格式以下圖
旋轉 90 度的算法:
public static void rotateYUV240SP(byte[] src, byte[] des, int width, int height) { int wh = width * height; //旋轉Y int k = 0; for(int i = 0; i < width; i++) { for(int j = 0; j < height; j++) { des[k] = src[width*j + i]; k++; } } for(int i = 0; i < width; i+ = 2) { for(int j = 0; j < height/2; j++) { des[k] = src[wh+ width*j + i]; des[k+1]=src[wh + width*j + i+1]; k+ = 2; } } }
通常來講,直接採集到的視頻數據是 RGB24 的格式,RGB24 一幀的大小 size=width×heigth×3 Bit,RGB32 的 size=width×heigth×4,若是是 I420(即 YUV 標準格式 4:2:0)的數據量是 size=width×heigth×1.5 Bit。
在採集到 RGB24 數據後,須要對這個格式的數據進行第一次壓縮。即將圖像的顏色空間由 RGB2YUV。由於,X264在進行編碼的時候須要標準的 YUV(4:2:0)。可是這裏須要注意的是,雖然 YV12 也是(4:2:0),可是 YV12 和 I420 的倒是不一樣的,在存儲空間上面有些區別。以下:
YV12 : 亮度(行×列) + U(行×列/4) + V(行×列/4)
I420 : 亮度(行×列) + V(行×列/4) + U(行×列/4)
能夠看出,YV12 和 I420 基本上是同樣的,就是 UV 的順序不一樣。
繼續咱們的話題,通過第一次數據壓縮後 RGB24->YUV(I420)。這樣,數據量將減小一半,爲何呢?呵呵,這個就太基礎了,我就很少寫了。一樣,若是是 RGB24->YUV(YV12),也是減小一半。可是,雖然都是一半,若是是 YV12 的話效果就有很大損失。而後,通過 X264 編碼後,數據量將大大減小。將編碼後的數據打包,經過 RTP 實時傳送。到達目的地後,將數據取出,進行解碼。完成解碼後,數據仍然是 YUV 格式的,因此,還須要一次轉換,這樣 windows 的驅動才能夠處理,就是 YUV2RGB24。
YUY2 是 4:2:2 [Y0 U0 Y1 V0]
yuv420: yuv yuv yuv
YUV420P,Y,U,V 三個份量都是平面格式,分爲 I420 和 YV12。I420 格式和 YV12 格式的不一樣處在 U 平面和V 平面的位置不一樣。在 I420 格式中,U 平面緊跟在 Y 平面以後,而後纔是 V 平面(即:YUV);但 YV12 則是相反(即:YVU)。
YUV420SP, Y 份量平面格式,UV 打包格式, 即 NV12。 NV12 與 NV21 相似,U 和 V 交錯排列,不一樣在於 UV 順序。
I420: YYYYYYYY UU VV =>YUV420P
YV12: YYYYYYYY VV UU =>YUV420P
NV12: YYYYYYYY UVUV =>YUV420SP
NV21: YYYYYYYY VUVU =>YUV420SP