用复制数组System.arraycopy和ByteBuffer.wrap来YUV转换
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;
}