I420对应YUV420P,平面格式存储,4:2:0采样,U在前,V在后。
YV12对应YUV420P,平面格式存储,4:2:0采样,V在前,U在后。
NV12对应YUV420SP,半平面格式存储,4:2:0采样,U在前,V在后。
NV21对应YUV420SP,半平面格式存储,4:2:0采样,V在前,U在后。
对应的数据存储格式是:
I420: YYYYYYYY UU VV
YV12: YYYYYYYY VV UU
NV12: YYYYYYYY UVUV
NV21: YYYYYYYY VUVU
1、NV12转I420
/**
* NV21 is a 4:2:0 YCbCr, For 1 NV21 pixel: YYYYYYYY VUVU I420YUVSemiPlanar
* is a 4:2:0 YUV, For a single I420 pixel: YYYYYYYY UVUV Apply NV21 to
* I420YUVSemiPlanar(NV12) Refer to https://wiki.videolan.org/YUV/
*/
private void NV21toI420SemiPlanar(byte[] nv21bytes, byte[] i420bytes,
int width, int height) {
int totle = width * height; //Y数据的长度
int nLen = totle / 4; //U、V数据的长度
System.arraycopy(nv21bytes, 0, i420bytes, 0, totle);
for (int i = 0; i < nLen; i++) {
i420bytes[totle + i] = nv21bytes[totle + 2 * i];
i420bytes[totle + nLen + i] = nv21bytes[totle + 2 * i + 1];
}
}
2、YV12转I420
private void YV12toI420(byte[]yv12bytes, byte[] i420bytes, int width, int height) {
int totle = width * height; //Y数据的长度
System.arraycopy(yv12bytes, 0, i420bytes, 0,totle);
System.arraycopy(yv12bytes, totle + totle/4, i420bytes, totle,totle/4);
System.arraycopy(yv12bytes, totle, i420bytes, totle + totle/4,totle/4);
}
3、YV12转NV21
private void YV12toNV21(byte[]yv12bytes, byte[] nv21bytes, int width, int height) {
int totle = width * height; //Y数据的长度
int nLen = totle / 4; //U、V数据的长度
System.arraycopy(yv12bytes, 0, nv21bytes, 0, width * height);
for (int i = 0; i < nLen; i++) {
nv21bytes[totle + 2 * i + 1] = yv12bytes[totle + nLen + i];
nv21bytes[totle + 2 * i] = yv12bytes[totle + i];
}
}