视频格式的转换和一些处理

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 ;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值