YUV數據的排列方式有4種,常用的就是YU12(安卓也叫I420),其他三個一般都需要轉換成YU12
YUV420SP——>NV12 (IOS ) YYYYYYYYYYYYUVUVUV
——>NV21 (安卓camera出來) YYYYYYYYYYYYVUVUVU
YUV420P ——> YU12(I420,安卓) YYYYYYYYYYYYUUUVVV
——> YV12, YYYYYYYYYYYYVVVUUU
前天看到有個byte數組處理方法: NV21的數據 轉成 YU12 (I420) 即 {1,1,1,1,1,1,1,1,1,1,1,1,3,2,3,2,3,2}; 轉成 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3]
還有 YV12的數據 轉成 YU12 (I420) {1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,2,2,2}; 轉成 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3]
NV21 ——> I420
NV21的數據 轉成 YU12 (I420):利用ByteBuffer 復制數組
public static byte[] nv21ToI420(byte[] data, int width, int height) {
byte[] ret = new byte[data.length];
int total = width * height;
// 初始化 YUV 三個緩存數組,跟RET數組關聯。
ByteBuffer bufferY = ByteBuffer.wrap(ret, 0, total);
ByteBuffer bufferU = ByteBuffer.wrap(ret, total, total / 4);
ByteBuffer bufferV = ByteBuffer.wrap(ret, total + total / 4, total / 4);
// 先把原來Y數據 放進去
bufferY.put(data, 0, total);
// VUVUVUVU——>UUUUVVVV ,掃描一次,i= i+2,不是i++
for (int i=total; i<data.length; i+=2) {
bufferV.put(data[i]);
bufferU.put(data[i+1]);
}
return ret;
}
NV21 ——> I420
如果是 NV12 ——.> I420 , 只需要交換下要取的數據的位置即可。
如原來是VUVUVU,取2,4,6出來是U,放進U組,取135出來是V,放進V組;現在是 UVUV,我不抓246了,改抓135取出來都是U,2,4,6取出來都是V。
// 如果是 NV12 ,即YYYYYYYYUVUV
for (int i = total;i <data.length;i+=2 ){
bufferV.put(data[i+1]);
bufferU.put(data[i]);
}
PS:自我理解,解析下這個For循環
我們for一般喜歡定型了這樣 for (int i = 0 ;i <data.length;i++ ),而上面這樣寫原因:
1,前面total數據不需要處理,或以處理過,只需要處理total后面數據。
2,循環一次,結構體處理了2個數據 ,i下標 和(i+1)下標,下次循環就不是i= i+1(即i++ ),而是i= i+2了 (即i+=2)。
3,因為i = total 所以i <data.length; 是為了 i數組下標能遍歷到所有i下標元素
YV12 ——> I420
YV12的數據 轉成 YU12 (I420) 利用 Arraycopy
private static byte[] YV12ToI420(byte[] bytes,int mWidth,int mHeight){
byte[] i420bytes = new byte[bytes.length];
int total = mWidth * mHeight;
//from YV12 to i420 YYYYYYYY VV UU——> YYYYYYYY UU VV
//UV互換 ,為什么可以用arraycopy,因為UUU和VVV都是連續的,即適用於YU12和YV12互轉
//先復制Y 都是 Y= mWidth * mHeight
System.arraycopy(bytes, 0, i420bytes, 0, total);
//把YYYYYYYY UU VV 先把原來后面那對VV 復制到新數組的YY前面,即UU和VV 兩組互換位置
System.arraycopy(bytes, total + total / 4, i420bytes, total, total / 4);
System.arraycopy(bytes, total, i420bytes, total + total / 4, total / 4);
return i420bytes;
}
這種數據轉換比較簡單,UUU和VVV是連續的,而這個方法System.arraycopy 就適合復制連續的數據。只需要把原來U組和V組數據 交換下存放位置即可。
這種應該也可以用ByteBuffer方式來復制。
private static byte[] YV12ToI420(byte[] bytes,int mWidth,int mHeight){
byte[] i420bytes = new byte[bytes.length];
int total = mWidth * mHeight;
// System.arraycopy(bytes, 0, i420bytes, 0, total);
// System.arraycopy(bytes, total + total / 4, i420bytes, total, total / 4);
// System.arraycopy(bytes, total, i420bytes, total + total / 4, total / 4);
ByteBuffer bufferY = ByteBuffer.wrap(i420bytes,0,total);
ByteBuffer bufferU =ByteBuffer.wrap(i420bytes,total,total/4);
ByteBuffer bufferV =ByteBuffer.wrap(i420bytes,total+total/4,total/4);
bufferY.put(bytes,0,total);
bufferU.put(bytes,total+total/4,total/4);
bufferV.put(bytes,total,total/4);
return i420bytes;
}