YUV转为RGB24(Java版本实现)
YUV简介
一般来说,直接采集到的视频数据是RGB24的格式,RGB24一帧的大小size=width×heigth×3 Byte,RGB32的size=width×heigth×4 Byte。如果是I420(即YUV标准格式4:2:0)的数据量是size=width×heigth×1.5 Byte。在采集到RGB24数据后,需要对这个格式的数据进行第一次压缩。即将图像的颜色空间由RGB24转化为IYUV。因为X264在进行编码的时候需要标准的YUV(4:2:0)。但是这里需要注意的是,虽然YV12也是(4:2:0),但是YV12和I420的却是不同的,在存储空间上面有些区别。区别如下:
- YV12 : 亮度(行×列) + V(行×列/4) + U(行×列/4)
- I420 : 亮度(行×列) + U(行×列/4) + V(行×列/4)
可以看出,YV12和I420基本上是一样的,就是UV的顺序不同。
YUV420p 和 YUV420的区别在于存储格式上有区别:
- YUV420p:yyyyyyyy uuuu vvvvv
- YUV420: yuv yuv yuv
另外需要注意的是海康威视设备回调数据类型为YV12格式;而大华设备回调数据类型为YUV420格式。
// YV12格式一个像素占1.5个字节 private byte[] YV12_To_RGB24(byte[] yv12, int width, int height) { if(yv12 == null) { return null; } int nYLen = (int)width * height; int halfWidth = width >> 1; if(nYLen<1 || halfWidth<1) { return null; } // yv12's data structure // |WIDTH | // y......y-------- // y......y HEIGHT // y......y // y......y-------- // v..v // v..v // u..u // u..u // Convert YV12 to RGB24 byte[] rgb24 = new byte[width * height * 3]; int[] rgb = new int[3]; int i, j, m, n, x, y; m = -width; n = -halfWidth; for(y=0; y<height; y++) { m += width; if(y%2 != 0) { n += halfWidth; } for(x=0; x<width; x++) { i = m+x; j = n + (x>>1); rgb[2] = (int)((int)(yv12[i]&0xFF) + 1.370705 * ((int)(yv12[nYLen+j]&0xFF) - 128)); // r rgb[1] = (int)((int)(yv12[i]&0xFF) - 0.698001 * ((int)(yv12[nYLen+(nYLen>>2)+j]&0xFF) - 128) - 0.703125 * ((int)(yv12[nYLen+j]&0xFF) - 128)); // g rgb[0] = (int)((int)(yv12[i]&0xFF) + 1.732446 * ((int)(yv12[nYLen+(nYLen>>2)+j]&0xFF) - 128)); // b //j = nYLen - iWidth - m + x; //i = (j<<1) + j; //图像是上下颠倒的 j = m + x; i = (j<<1) + j; for(j=0; j<3; j++) { if(rgb[j]>=0 && rgb[j]<=255) { rgb24[i+j] = (byte)rgb[j]; } else { rgb24[i+j] = (byte) ((rgb[j] < 0)? 0 : 255); } } } } return rgb24; }