文章目录

    • 视频存储格式
    • NV12转I420
    • NV12转I444
    • P010转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 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