yuv的一些格式
planar的YUV格式分为YUV420P和YUV420SP,YUV420P包含I420和YV12。
I420格式和YV12格式的不同处在U平面和V平面的位置不同。在I420格式中,U平面紧跟在Y平面之后,然后才是V平面(即:YUV);但YV12则是相反(即:YVU)。
YUV420SP, Y分量平面格式,UV打包格式, 即NV12。 NV12与NV21类似,U 和 V 交错排列,不同在于UV顺序。
nv12和nv21都是yuv420sp的,只是uv的位置是反的
I420: YYYYYYYY UU VV =>YUV420P
YV12: YYYYYYYY VV UU =>YUV420P
NV12: YYYYYYYY UVUV =>YUV420SP
NV21: YYYYYYYY VUVU =>YUV420SP
安卓版本
//NV12转YUV420P(I420)
public static void NV12ToYuv420P(byte[] nv12,byte[] yuv420p,int width,int height) {
int ySize = width * height;
int i, j;
//y
for (i =0; i < ySize; i++) {
yuv420p[i] = nv12[i];
}
//u
i =0;
for (j =0; j < ySize /2; j +=2) {
yuv420p[ySize + i] = nv12[ySize + j];
i++;
}
//v
i =0;
for (j =1; j < ySize /2; j+=2) {
yuv420p[ySize *5 /4 + i] = nv12[ySize + j];
i++;
}
}
//NV21转YUV420P(I420)
就是uv反过来
public static void NV12ToYuv420P(byte[] nv12,byte[] yuv420p,int width,int height) {
int ySize = width * height;
int i, j;
//y
for (i =0; i < ySize; i++) {
yuv420p[i] = nv12[i];
}
//u
i =0;
for (j =1; j < ySize /2; j +=2) {
yuv420p[ySize + i] = nv12[ySize + j];
i++;
}
//v
i =0;
for (j =0; j < ySize /2; j+=2) {
yuv420p[ySize *5 /4 + i] = nv12[ySize + j];
i++;
}
}
//NV21转NV12
private byte[] NV21ToNV12(byte[] nv21, int width, int height) {
byte[] nv12 = new byte[width * height * 3 / 2];
int frameSize = width * height;
int i, j;
System.arraycopy(nv21, 0, nv12, 0, frameSize);
//y
for (i = 0; i < frameSize; i++) {
nv12[i] = nv21[i];
}
//u
for (j = 0; j < frameSize / 2; j += 2) {
nv12[frameSize + j - 1] = nv21[j + frameSize];
}
//v
for (j = 0; j < frameSize / 2; j += 2) {
nv12[frameSize + j] = nv21[j + frameSize - 1];
}
return nv12;
}
//rgba转yuv420p(I420)
private void rgbaToYuv(byte[] rgba,int width,int height,byte[] yuv){
final int frameSize = width * height;
int yIndex = 0;
int uIndex = frameSize;
int vIndex = frameSize + frameSize/4;
int R, G, B, Y, U, V;
int index = 0;
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
index = j * width + i;
if(rgba[index*4]>127||rgba[index*4]<-128){
Log.e("color","-->"+rgba[index*4]);
}
R = rgba[index*4]&0xFF;
G = rgba[index*4+1]&0xFF;
B = rgba[index*4+2]&0xFF;
Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;
yuv[yIndex++] = (byte) ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));
if (j % 2 == 0 && index % 2 == 0) {
yuv[uIndex++] = (byte) ((U < 0) ? 0 : ((U > 255) ? 255 : U));
yuv[vIndex++] = (byte) ((V < 0) ? 0 : ((V > 255) ? 255 : V));
}
}
}
}
//yuv420p顺时针选择90度 注意执行完成后后续该视频的宽高要反转
private byte[] rotateYUV420Degree270(byte[] data, int imageWidth, int imageHeight){
byte[] yuv =new byte[imageWidth*imageHeight*3/2];
// Rotate the Y luma
int i =0;
for(int x = imageWidth-1;x >=0;x--){
for(int y =0;y < imageHeight;y++){
yuv[i]= data[y*imageWidth+x];
i++;
}
}// Rotate the U and V color components
i = imageWidth*imageHeight;
for(int x = imageWidth-1;x >0;x=x-2){
for(int y =0;y < imageHeight/2;y++){
yuv[i]= data[(imageWidth*imageHeight)+(y*imageWidth)+(x-1)];
i++;
yuv[i]= data[(imageWidth*imageHeight)+(y*imageWidth)+x];
i++;
}
}
return yuv;
}
//YUV420P图片叠加算法
public static void mergeYUV420P(byte[] yuv420P_A, byte[] yuv420P_B, int offset_x, int offset_y,int a_width, int a_height, int b_width, int b_height) {
int offset_y_4 = offset_y / 4;
int offset_x_2 = offset_x / 2;
int a_width_2 = a_width / 2;
int b_width_2 = b_width / 2;
int b_height_4 = b_height / 4;
int a_height_4 = a_height / 4;
//y
for (int i = 0; i < b_height; i++) {
for (int j = 0; j < b_width; j++) {
yuv420P_A[i * a_width + offset_y * a_width + j + offset_x] = yuv420P_B[i * b_width + j];
}
}
//uv
for (int i = 0; i < b_height / 4; i++) {
for (int j = 0; j < b_width; j++) {
if (j < b_width / 2) {
yuv420P_A[i * a_width + offset_y_4 * a_width + j + offset_x_2 + a_width * a_height] = yuv420P_B[i * b_width + j + b_width * b_height];
yuv420P_A[i * a_width + offset_y_4 * a_width + j + offset_x_2 + a_width * a_height + a_width * a_height_4] =yuv420P_B[i * b_width + j + b_width * b_height + b_width * b_height_4];
} else {
yuv420P_A[i * a_width + offset_y_4 * a_width + j + (a_width_2 - b_width_2) + offset_x_2 + a_width * a_height] = yuv420P_B[i * b_width + j + b_width * b_height];
yuv420P_A[i * a_width + offset_y_4 * a_width + j + (a_width_2 - b_width_2) + offset_x_2 + a_width * a_height + a_width * a_height_4] =yuv420P_B[i * b_width + j + b_width * b_height + b_width * b_height_4];
}
}
}
}
C++版本
#define RGBA_YUV420SP 0x00004012
#define BGRA_YUV420SP 0x00004210
#define RGBA_YUV420P 0x00014012
#define BGRA_YUV420P 0x00014210
#define RGB_YUV420SP 0x00003012
#define RGB_YUV420P 0x00013012
#define BGR_YUV420SP 0x00003210
#define BGR_YUV420P 0x00013210
/**
* type 0-3位表示b的偏移量
* 4-7位表示g的偏移量
* 8-11位表示r的偏移量
* 12-15位表示rgba一个像素所占的byte
* 16-19位表示yuv的类型,0为420sp,1为420p
*/
//rgba转yuv420p(I420)
void rgbaToYuv(int width,int height,unsigned char * rgb,unsigned char * yuv,int type){
const int frameSize = width * height;
const int yuvType=(type&0x10000)>>16;
const int byteRgba=(type&0x0F000)>>12;
const int rShift=(type&0x00F00)>>8;
const int gShift=(type&0x000F0)>>4;
const int bShift= (type&0x0000F);
const int uIndex=0;
const int vIndex=yuvType; //yuvType为1表示YUV420p,为0表示420sp
int yIndex = 0;
int uvIndex[2]={frameSize,frameSize+frameSize/4};
unsigned char R, G, B, Y, U, V;
unsigned int index = 0;
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
index = j * width + i;
R = rgb[index*byteRgba+rShift]&0xFF;
G = rgb[index*byteRgba+gShift]&0xFF;
B = rgb[index*byteRgba+bShift]&0xFF;
Y = y(R,G,B);
U = u(R,G,B);
V = v(R,G,B);
yuv[yIndex++] = color(Y);
if (j % 2 == 0 && index % 2 == 0) {
yuv[uvIndex[uIndex]++] =color(U);
yuv[uvIndex[vIndex]++] =color(V);
}
}
}
}
//NV21转YUV420P(I420)
void NV21ToYuv420P(int width,int height,unsigned char * nv12,unsigned char * yuv420p)
{
int ySize = width * height;
int i, j;
//y
for (i =0; i < ySize; i++) {
yuv420p[i] = nv12[i];
}
//u
i =0;
for (j =1; j < ySize /2; j +=2) {
yuv420p[ySize + i] = nv12[ySize + j];
i++;
}
//v
i =0;
for (j =0; j < ySize /2; j+=2) {
yuv420p[ySize *5 /4 + i] = nv12[ySize + j];
i++;
}
}
//NV12转YUV420P(I420)
void NV12ToYuv420P(int width,int height,unsigned char * nv12,unsigned char * yuv420p)
{
int ySize = width * height;
int i, j;
//y
for (i =0; i < ySize; i++) {
yuv420p[i] = nv12[i];
}
//u
i =0;
for (j =0; j < ySize /2; j +=2) {
yuv420p[ySize + i] = nv12[ySize + j];
i++;
}
//v
i =0;
for (j =1; j < ySize /2; j+=2) {
yuv420p[ySize *5 /4 + i] = nv12[ySize + j];
i++;
}
}
//YUV420P图片叠加算法
void mergeYUV420P(unsigned char * yuv420P_A, unsigned char * yuv420P_B, int offset_x, int offset_y,int a_width, int a_height, int b_width, int b_height) {
int offset_y_4 = offset_y / 4;
int offset_x_2 = offset_x / 2;
int a_width_2 = a_width / 2;
int b_width_2 = b_width / 2;
int b_height_4 = b_height / 4;
int a_height_4 = a_height / 4;
//y
for (int i = 0; i < b_height; i++) {
for (int j = 0; j < b_width; j++) {
yuv420P_A[i * a_width + offset_y * a_width + j + offset_x] = yuv420P_B[i * b_width + j];
}
}
//uv
for (int i = 0; i < b_height / 4; i++) {
for (int j = 0; j < b_width; j++) {
if (j < b_width / 2) {
yuv420P_A[i * a_width + offset_y_4 * a_width + j + offset_x_2 + a_width * a_height] = yuv420P_B[i * b_width + j + b_width * b_height];
yuv420P_A[i * a_width + offset_y_4 * a_width + j + offset_x_2 + a_width * a_height + a_width * a_height_4] =yuv420P_B[i * b_width + j + b_width * b_height + b_width * b_height_4];
} else {
yuv420P_A[i * a_width + offset_y_4 * a_width + j + (a_width_2 - b_width_2) + offset_x_2 + a_width * a_height] = yuv420P_B[i * b_width + j + b_width * b_height];
yuv420P_A[i * a_width + offset_y_4 * a_width + j + (a_width_2 - b_width_2) + offset_x_2 + a_width * a_height + a_width * a_height_4] =yuv420P_B[i * b_width + j + b_width * b_height + b_width * b_height_4];
}
}
}
}
//yuv420p顺时针选择90度 注意执行完成后后续该视频的宽高要反转
void rotateNv21Degree270(unsigned char * data, unsigned char * yuv,int imageWidth, int imageHeight){
// Rotate the Y luma
int i =0;
for(int x = imageWidth-1;x >=0;x--){
for(int y =0;y < imageHeight;y++){
yuv[i]= data[y*imageWidth+x];
i++;
}
}
// Rotate the U and V color components
i = imageWidth*imageHeight;
for(int x = imageWidth-1;x >0;x=x-2){
for(int y =0;y < imageHeight/2;y++){
yuv[i]= data[(imageWidth*imageHeight)+(y*imageWidth)+(x+1)];
i++;
yuv[i]= data[(imageWidth*imageHeight)+(y*imageWidth)+(x)];
i++;
}
}
return ;
}