用复制数组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;
}
posted @ 2020-06-30 23:54  风飘而去  阅读(1349)  评论(0编辑  收藏  举报