常用视频格式转换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