Android相机yuv输出格式是420sp,MediaCodec硬编码通常也是yuv420sp,因此yuv420sp与rgb之间的转换较为常用,这里记录一下:
转换公式按照
yuv2rgb:? ?
?rgb2yvv:??
rgb转yuv420sp(YYYYUVUV),每逢偶数行及偶数列取一次UV数据:
/**
* @param yuv420sp target to save yuv data, the length should be at least width*height*1.5
* @param rgb rgb data, every 3 bytes as a color, without alpha
* @param width image width
* @param height image height
* @param stride The number of bytes to skip between rows.
* Normally this value will be the same as the width, but it may be larger sometimes
*/
void rgb2YUV420sp(byte[] yuv420sp, byte[] rgb, int width, int height, int stride) {
int frameSize = width * height;
int yIndex = 0;
int uvIndex = frameSize;
int r, g, b, y, u, v;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int index = (i * stride + j) * 3;
r = rgb[index++];
g = rgb[index++];
b = rgb[index];
//RGB to YUV
y = (76 * r + 150 * g + 29 * b + 128) >> 8;//y=0.299r+0.587g+0.114b
yuv420sp[yIndex++] = (byte) (y < 0 ? 0 : y > 255 ? 255 : y);
if (i % 2 == 0 && j % 2 == 0) {
u = ((-43 * r - 84 * g + 128 * b + 128) >> 8) + 128;//u=-0.169r-0.331g+0.5b+128
v = ((128 * r - 107 * g - 20 * b + 128) >> 8) + 128;//v=0.5r-0.419g-0.081b+128
yuv420sp[uvIndex++] = (byte) (v < 0 ? 0 : v > 255 ? 255 : v);
yuv420sp[uvIndex++] = (byte) (u < 0 ? 0 : u > 255 ? 255 : u);
}
}
}
}
下面是yuv420sp转rgb的
/**
* Convert image format from i420sp(NV12) to ARGB
*
* @param pixels array to save pixels, it's length should be no less than width*height
* @param data YUV data(like YYYYUVUV) with <I>length=1.5*width*height</I>,
* <b>or</b> gray image that has only Y plane with <I>length=width*height</I>
* @param width width of image
* @param height height of image
*/
public void convertYuv2Rgb(int[] pixels, byte[] data, int width, int height) {
int len = width * height;
if (len == data.length) {//only has Y
for (int i = 0; i < len; i++) {
int y = data[i] & 0xff;
pixels[i] = Color.argb(255, y, y, y);
}
} else {
int[] rgb = new int[3];
int y, u, v;
int pixIndex = 0;
int yStart, uvStart;
for (int i = 0; i < height; i++) {
yStart = i * width;//use stride, if stride!=width
//uv start from width*height, every 2 columns share 1 row of uv data with stride=width
uvStart = len + (i >> 1) * width;
for (int j = 0; j < width; j++) {
y = data[yStart + j] & 0xff;
int uIndex = uvStart + (j >> 1 << 1);//every 2 pixels shared a group of uv
u = (data[uIndex++] & 0xff) - 128;
v = (data[uIndex] & 0xff) - 128;
rgb[0] = y + (v * 359 >> 8);//r=y+1.403v
rgb[1] = y - (u * 88 >> 8) - (v * 182 >> 8);//g=y-0.344u-0.714v
rgb[2] = y + (u * 453 >> 8);//b=y+1.77u
for (int k = 0; k < 3; k++) {//rgb value should be 0-255
rgb[k] = rgb[k] > 255 ? 255 : rgb[k] < 0 ? 0 : rgb[k];
}
pixels[pixIndex++] = Color.argb(255, rgb[0], rgb[1], rgb[2]);
}
}
}
}
|