YUV编码格式(二)
程序员文章站
2022-07-14 19:21:28
...
YUV常见格式的像素分布
YUV444:
YUV422:
YUV420:
YUV常见格式的数据量的计算
YUV444:
Data(YUV)=Data(Y)*3
Data(YUV)=Data(RGB)
YUV422:
Data(YUV)=Data(Y)*2
Data(YUV)=(Data(RGB)/3)*2
YUV420:
Data(YUV)=Data(Y)*1.5
Data(YUV)=Data(RGB)/2
YUV420存储格式
Planar(平面):
YUV420P又叫plane平面模式,Y , U , V分别在不同平面,也就是有三个平面,它是YUV标准格式4:2:0,主要分为:YU12和YV12:
YU12: YYYYYYYY UUVV => YUV420P
YV12: YYYYYYYY VVUU => YUV420P
(下图为YU12存储格式示意图,将U行与V行互换则是YV12存储格式示意图)
Packed(打包):
YUV420SP格式的图像阵列又叫packed打包模式,首先是所有Y值,然后是UV或者VU交替存储,NV12和NV21属于YUV420SP格式:
NV12: YYYYYYYY UVUV =>YUV420SP
NV21: YYYYYYYY VUVU =>YUV420SP
(android手机从摄像头采集的预览数据一般都是NV21)
YUV相关代码
YUV与RGB相互转换:
Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
Cr = V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128
B = 1.164(Y - 16) + 2.018(U - 128)
G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
R = 1.164(Y - 16) + 1.596(V - 128)
分离YUV420各分量:
void split_yuv420(char *inputPath, int width, int height) {
FILE *fp_yuv = fopen(inputPath, "rb+");
FILE *fp_y = fopen("output_420_y.y", "wb+");
FILE *fp_u = fopen("output_420_u.y", "wb+");
FILE *fp_v = fopen("output_420_v.y", "wb+");
unsigned char *data = (unsigned char *) malloc(width * height * 3 / 2);
fread(data, 1, width * height * 3 / 2, fp_yuv);
//Y
fwrite(data, 1, width * height, fp_y);
//U
fwrite(data + width * height, 1, width * height / 4, fp_u);
//V
fwrite(data + width * height * 5 / 4, 1, width * height / 4, fp_v);
//释放资源
free(data);
fclose(fp_yuv);
fclose(fp_y);
fclose(fp_u);
fclose(fp_v);
}
NV12转YU12:
void NV12_to_YU12( const unsigned char* image_src,
unsigned char* image_dst,
int image_width,
int image_height)
{
unsigned char* p = image_dst;
memcpy(p, image_src, image_width * image_height * 3 / 2);
const unsigned char* pNV = image_src + image_width * image_height;
unsigned char* pU = p + image_width * image_height;
unsigned char* pV = p + image_width * image_height + ((image_width * image_height)>>2);
for (int i=0; i<(image_width * image_height)/2; i++){
if ((i%2)==0)
pU++ = (pNV + i);
else
pV++ = (pNV + i);
}
}
NV21转YU12:
void NV21_to_YU12(const unsigned char* image_src,
unsigned char* image_dst,
int image_width,
int image_height) {
unsigned char* p = image_dst;
memcpy(p, image_src, image_width * image_height * 3 / 2);
const unsigned char* pNV = image_src + image_width * image_height;
unsigned char* pU = p + image_width * image_height;
unsigned char* pV = p + image_width * image_height + ((image_width * image_height) >> 2);
for (int i = 0; i < (image_width * image_height) / 2; i++) {
if ((i % 2) == 0)
{
memcpy(pU, pNV + i, 1);
pU++;
}
else {
memcpy(pV, pNV + i, 1);
pV++;
}
}
}
YU12转NV12:
void YU12_to_NV12( unsigned char* Src,
unsigned char* Dst,
int Width,
int Height) {
unsigned char* SrcU = Src + Width * Height;
unsigned char* SrcV = SrcU + Width * Height / 4;
memcpy(Dst, Src, Width * Height);
unsigned char* DstU = Dst + Width * Height;
for (int i = 0; i < Width * Height / 4; i++) {
(*DstU++) = (*SrcU++);
(*DstU++) = (*SrcV++);
}
}
YU12转NV21:
void YU12_to_NV21(unsigned char *Src,
unsigned char *Dst,
int Width,
int Height){
unsigned char* SrcU = Src + Width * Height;
unsigned char* SrcV = SrcU + Width * Height / 4;
memcpy(Dst, Src, Width * Height);
unsigned char* DstV = Dst + Width * Height;
for (int i = 0; i < Width * Height / 4; i++)
{
(*DstV++) = (*SrcV++);
(*DstV++) = (*SrcU++);
}
}
上一篇: 设置MySQL编码格式
下一篇: 编码、转码和编码格式