YUV422有打包格式(Packed),一如前文所述。同时还有平面格式(Planar),即Y、U、V是分开存储的,每个分量占一块地方,其中Y为width*height,而U、V合占width*height,该种格式每个像素占16比特。根据U、V的顺序,分出2种格式,U前V后即YUV422P,也叫I422,V前U后,叫YV16(YV表示Y后面跟着V,16表示16bit)。另外,还有一种变态的半平面格式(Semi-planar),即Y单独占一块地方,但其后U、V又紧挨着排在一起,根据U、V的顺序,又有2种,U前V后叫NV16,在国内好像很多人叫它为YUV422SP格式;V前U后叫NV61。不过这种格式似乎不太受VLC欢迎(具体可去看看VLC的wiki)。
先给出YUV422平面格式的转换函数,如下:
- /**
- 内存分布
- w
- +--------------------+
- |Y0Y1Y2Y3... |
- |... | h
- |... |
- | |
- +--------------------+
- |U0U1 |
- |... | h
- |... |
- | |
- +----------+
- |V0V1 |
- |... | h
- |... |
- | |
- +----------+
- w/2
- */
- void yuv422p_to_rgb24(YUV_TYPE type, unsigned char* yuv422p, unsigned char* rgb, int width, int height)
- {
- int y, cb, cr;
- int r, g, b;
- int i = 0;
- unsigned char* p_y;
- unsigned char* p_u;
- unsigned char* p_v;
- unsigned char* p_rgb;
- p_y = yuv422p;
- p_u = p_y + width * height;
- p_v = p_u + width * height / 2;
- if (type == FMT_YV16)
- {
- p_v = p_y + width * height;
- p_u = p_u + width * height / 2;
- }
- p_rgb = rgb;
- init_yuv422p_table();
- for (i = 0; i < width * height / 2; i++)
- {
- y = p_y[0];
- cb = p_u[0];
- cr = p_v[0];
- r = MAX (0, MIN (255, (V[cr] + Y1[y])/10000)); //R value
- b = MAX (0, MIN (255, (U[cb] + Y1[y])/10000)); //B value
- g = MAX (0, MIN (255, (Y2[y] - 5094*(r) - 1942*(b))/10000)); //G value
- // 此处可调整RGB排序,BMP图片排序为BGR
- // 默认排序为:RGB
- p_rgb[0] = r;
- p_rgb[1] = g;
- p_rgb[2] = b;
- y = p_y[1];
- cb = p_u[0];
- cr = p_v[0];
- r = MAX (0, MIN (255, (V[cr] + Y1[y])/10000)); //R value
- b = MAX (0, MIN (255, (U[cb] + Y1[y])/10000)); //B value
- g = MAX (0, MIN (255, (Y2[y] - 5094*(r) - 1942*(b))/10000)); //G value
- p_rgb[3] = r;
- p_rgb[4] = g;
- p_rgb[5] = b;
- p_y += 2;
- p_u += 1;
- p_v += 1;
- p_rgb += 6;
- }
- }
接着给出NV16、NV61转换成RGB的函数,如下:
- /**
- 内存分布
- w
- +--------------------+
- |Y0Y1Y2Y3... |
- |... | h
- |... |
- | |
- +--------------------+
- |U0V0U1V1 |
- |... | h
- |... |
- | |
- +--------------------+
- w/2
- UV交织为NV16,VU交织为NV61
- 可以与上一函数合并,但方便查看,还是不合并
- */
- void yuv422sp_to_rgb24(YUV_TYPE type, unsigned char* yuv422sp, unsigned char* rgb, int width, int height)
- {
- int y, cb, cr;
- int r, g, b;
- int i = 0;
- unsigned char* p_y;
- unsigned char* p_uv;
- unsigned char* p_rgb;
- p_y = yuv422sp;
- p_uv = p_y + width * height; // uv分量在Y后面
- p_rgb = rgb;
- init_yuv422p_table();
- for (i = 0; i < width * height / 2; i++)
- {
- y = p_y[0];
- if (type == FMT_NV16)
- {
- cb = p_uv[0];
- cr = p_uv[1]; // v紧跟u,在u的下一个位置
- }
- if (type == FMT_NV61)
- {
- cr = p_uv[0];
- cb = p_uv[1]; // u紧跟v,在v的下一个位置
- }
- r = MAX (0, MIN (255, (V[cr] + Y1[y])/10000)); //R value
- b = MAX (0, MIN (255, (U[cb] + Y1[y])/10000)); //B value
- g = MAX (0, MIN (255, (Y2[y] - 5094*(r) - 1942*(b))/10000)); //G value
- // 此处可调整RGB排序,BMP图片排序为BGR
- // 默认排序为:RGB
- p_rgb[0] = r;
- p_rgb[1] = g;
- p_rgb[2] = b;
- y = p_y[1];
- if (type == FMT_NV16)
- {
- cb = p_uv[0];
- cr = p_uv[1];
- }
- if (type == FMT_NV61)
- {
- cr = p_uv[0];
- cb = p_uv[1];
- }
- r = MAX (0, MIN (255, (V[cr] + Y1[y])/10000)); //R value
- b = MAX (0, MIN (255, (U[cb] + Y1[y])/10000)); //B value
- g = MAX (0, MIN (255, (Y2[y] - 5094*(r) - 1942*(b))/10000)); //G value
- p_rgb[3] = r;
- p_rgb[4] = g;
- p_rgb[5] = b;
- p_y += 2;
- p_uv += 2;
- p_rgb += 6;
- }
- }
参考资料: