用復制數組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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM