欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

常用视频格式转换nv12,i420,i444,p010

程序员文章站 2022-06-16 18:03:25
文章目录视频存储格式NV12转I420视频存储格式P010格式与NV12格式一样,区别就是两个字节存一个像素值。Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y YY Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y YY Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y YY Y Y Y...

视频存储格式

P010格式与NV12格式一样,区别就是两个字节存一个像素值。

Y Y Y Y Y Y      Y Y Y Y Y Y      Y Y Y Y Y Y      Y Y Y Y Y Y
Y Y Y Y Y Y      Y Y Y Y Y Y      Y Y Y Y Y Y      Y Y Y Y Y Y
Y Y Y Y Y Y      Y Y Y Y Y Y      Y Y Y Y Y Y      Y Y Y Y Y Y
Y Y Y Y Y Y      Y Y Y Y Y Y      Y Y Y Y Y Y      Y Y Y Y Y Y
U U U U U U      V V V V V V      U V U V U V      V U V U V U
V V V V V V      U U U U U U      U V U V U V      V U V U V U
 - I420 -          - YV12 -         - NV12 -         - NV21 -

Y Y Y Y Y Y      Y Y Y Y Y Y    
Y Y Y Y Y Y      Y Y Y Y Y Y
Y Y Y Y Y Y      Y Y Y Y Y Y
Y Y Y Y Y Y      Y Y Y Y Y Y
U U U U U U      V V V V V V
U U U U U U      V V V V V V
U U U U U U      V V V V V V
U U U U U U      V V V V V V
V V V V V V      U U U U U U
V V V V V V      U U U U U U
V V V V V V      U U U U U U
V V V V V V      U U U U U U
 - I444 -          - YV24 -

NV12转I420

//NV12 转 I420 
void NV12_to_I420(uint8_t* nv12data, uint8_t* i420data, int frameWidth, int frameHeight) {
	uint8_t* nv12_src[2];
	nv12_src[0] = nv12data;
	nv12_src[1] = nv12_src[0] + frameWidth * frameHeight;

	uint8_t* yuv420_dst[3];
	yuv420_dst[0] = i420data;
	yuv420_dst[1] = yuv420_dst[0] + frameWidth * frameHeight;
	yuv420_dst[2] = yuv420_dst[1] + frameWidth * frameHeight / 4;

	//Y
	memcpy(yuv420_dst[0], nv12_src[0], frameWidth * frameHeight);
	// for(int i = 0; i < frameWidth * frameHeight ; i++){
	//     *(yuv420_dst[0]++) = *(nv12_src[0] + i);
	// }

	for (int i = 0; i < frameWidth * frameHeight / 2; i++) {
		unsigned char b = *(nv12_src[1] + i);
		if (i % 2 == 0) {//U
			*(yuv420_dst[1]++) = *(nv12_src[1] + i);
		}
		else {//V
			*(yuv420_dst[2]++) = *(nv12_src[1] + i);
		}
	}
}

NV12转I444

//NV12转YUV444
void NV12_to_I444(uint8_t* nv12data, uint8_t* i444data, int frameWidth, int frameHeight) {
	uint8_t* nv12_src[2];
	nv12_src[0] = nv12data;
	nv12_src[1] = nv12_src[0] + frameWidth * frameHeight;

	uint8_t* yuv444_dst[3];
	yuv444_dst[0] = i444data;
	yuv444_dst[1] = yuv444_dst[0] + frameWidth * frameHeight;
	yuv444_dst[2] = yuv444_dst[1] + frameWidth * frameHeight;

	//Y
	memcpy(yuv444_dst[0], nv12_src[0], frameWidth * frameHeight);

	//UV
	for (int i = 0; i < frameWidth * frameHeight / 2; i++) {
		if (i % 2 == 0) {//U,NV12中一位对应444中4位
			*(yuv444_dst[1]) = *(nv12_src[1] + i);
			*(yuv444_dst[1] + frameWidth) = *(nv12_src[1] + i);
			yuv444_dst[1]++;
			*(yuv444_dst[1]) = *(nv12_src[1] + i);
			*(yuv444_dst[1] + frameWidth) = *(nv12_src[1] + i);
			yuv444_dst[1]++;
		}
		else {//V,NV12中一位对应444中4位
			*(yuv444_dst[2]) = *(nv12_src[1] + i);
			*(yuv444_dst[2] + frameWidth) = *(nv12_src[1] + i);
			yuv444_dst[2]++;
			*(yuv444_dst[2]) = *(nv12_src[1] + i);
			*(yuv444_dst[2] + frameWidth) = *(nv12_src[1] + i);
			yuv444_dst[2]++;
		}
		if ((i > frameWidth && i % frameWidth == 0)) {//UV分量跳行
			yuv444_dst[1] = yuv444_dst[1] + frameWidth;
			yuv444_dst[2] = yuv444_dst[2] + frameWidth;
		}
	}
}

P010转I420

p010有多种格式,区别在于数据的存放位置,即10bit的数据是如何放在16bit的空间里面的。
//P010转I420
void P010le_to_I420(uint8_t* p010data, uint8_t* i420data, int frameWidth, int frameHeight) {
	uint8_t* p010_src[2];
	p010_src[0] = p010data;
	p010_src[1] = p010_src[0] + frameWidth * frameHeight * 2;

	uint8_t* yuv420_dst[3];
	yuv420_dst[0] = i420data;
	yuv420_dst[1] = yuv420_dst[0] + frameWidth * frameHeight;
	yuv420_dst[2] = yuv420_dst[1] + frameWidth * frameHeight / 4;
	uint16_t Y, U, V;

	//Y
	for (int i = 0; i < frameWidth * frameHeight; i++) {
		Y = *((uint16_t*)p010_src[0] + i) >> 6;
		Y = Y < 64 ? 64 : Y;
		Y = Y > 940 ? 940 : Y;
		*(yuv420_dst[0]++) = (uint8_t)(Y >> 2);
	}

	//UV
	for (int i = 0; i < frameWidth * frameHeight / 2; i++) {
		if (i % 2 == 0) {
			U = (*((uint16_t*)p010_src[1] + i)) & 0x00ff;
			*(yuv420_dst[1]++) = U;
		}
		else {
			V = (*((uint16_t*)p010_src[1] + i)) & 0x00ff;
			*(yuv420_dst[2]++) = V;
		}
	}
}
void P010_to_I420(uint8_t* P010data, uint8_t* I420data, int frameWidth, int frameHeight) {
	uint8_t* p010_src[2];
	p010_src[0] = P010data;
	p010_src[1] = p010_src[0] + frameWidth * frameHeight * 2;

	uint8_t* yuv420_dst[3];
	yuv420_dst[0] = I420data;
	yuv420_dst[1] = yuv420_dst[0] + frameWidth * frameHeight;
	yuv420_dst[2] = yuv420_dst[1] + frameWidth * frameHeight / 4;
	uint8_t Y, U, V;

	//Y
	for (int i = 0; i < frameWidth * frameHeight; i++) {
		Y = *((uint16_t*)p010_src[0] + i) >> 8;
		Y = Y < 16 ? 16 : (Y > 235 ? 235 : Y);
		*(yuv420_dst[0]++) = Y;
	}

	//UV
	for (int i = 0; i < frameWidth * frameHeight / 2; i++) {
		if (i % 2 == 0) {
			U = (*((uint16_t*)p010_src[1] + i)) >> 8;
			//U = (((U - 128) * (200 + 256)) >> 8) + 128;
			U = U < 16 ? 16 : (U > 235 ? 235 : U);
			*(yuv420_dst[1]++) = U;
		}
		else {
			V = (*((uint16_t*)p010_src[1] + i)) >> 8;
			//V = (((V - 128) * (200 + 256)) >> 8) + 128;
			V = V < 16 ? 16 : (V > 235 ? 235 : V);
			*(yuv420_dst[2]++) = V;
		}
	}
}

本文地址:https://blog.csdn.net/liang_baikai/article/details/110086883