您的位置:首页 > 其它

YUV格式学习:YUV420P、YV12、NV12、NV21格式转换成RGB24

2017-07-23 11:34 483 查看
YUV420有打包格式(Packed),一如前文所述。同时还有平面格式(Planar),即Y、U、V是分开存储的,每个分量占一块地方,其中Y为width*height,而U、V合占Y的一半,该种格式每个像素占12比特。根据U、V的顺序,分出2种格式,U前V后即YUV420P,也叫I420,V前U后,叫YV12(YV表示Y后面跟着V,12表示12bit)。另外,还有一种半平面格式(Semi-planar),即Y单独占一块地方,但其后U、V又紧挨着排在一起,根据U、V的顺序,又有2种,U前V后叫NV12,在国内好像很多人叫它为YUV420SP格式;V前U后叫NV21。这种格式似乎比NV16稍受欢迎。

首先给出转换查询表的生成函数,代码是在网上找来的,如下:

static long int crv_tab[256];
static long int cbu_tab[256];
static long int cgu_tab[256];
static long int cgv_tab[256];
static long int tab_76309[256];
static unsigned char clp[1024];   //for clip in CCIR601

void init_yuv420p_table()
{
long int crv,cbu,cgu,cgv;
int i,ind;
static int init = 0;

if (init == 1) return;

crv = 104597; cbu = 132201;  /* fra matrise i global.h */
cgu = 25675;  cgv = 53279;

for (i = 0; i < 256; i++)
{
crv_tab[i] = (i-128) * crv;
cbu_tab[i] = (i-128) * cbu;
cgu_tab[i] = (i-128) * cgu;
cgv_tab[i] = (i-128) * cgv;
tab_76309[i] = 76309*(i-16);
}

for (i = 0; i < 384; i++)
clp[i] = 0;
ind = 384;
for (i = 0;i < 256; i++)
clp[ind++] = i;
ind = 640;
for (i = 0;i < 384; i++)
clp[ind++] = 255;

init = 1;
}

下面给出YUV420平面格式的转换函数,如下:

/**
内存分布
w
+--------------------+
|Y0Y1Y2Y3...         |
|...                 |   h
|...                 |
|                    |
+--------------------+
|U0U1      |
|...       |   h/2
|...       |
|          |
+----------+
|V0V1      |
|...       |  h/2
|...       |
|          |
+----------+
w/2
*/
void yuv420p_to_rgb24(YUV_TYPE type, unsigned char* yuvbuffer,unsigned char* rgbbuffer, int width,int height)
{
int y1, y2, u, v;
unsigned char *py1, *py2;
int i, j, c1, c2, c3, c4;
unsigned char *d1, *d2;
unsigned char *src_u, *src_v;
static int init_yuv420p = 0;

src_u = yuvbuffer + width * height;   // u
src_v = src_u + width * height / 4;  //  v

if (type == FMT_YV12)
{
src_v = yuvbuffer + width * height;   // v
src_u = src_u + width * height / 4;  //  u
}
py1 = yuvbuffer;   // y
py2 = py1 + width;
d1 = rgbbuffer;
d2 = d1 + 3 * width;

init_yuv420p_table();

for (j = 0; j < height; j += 2)
{
for (i = 0; i < width; i += 2)
{
u = *src_u++;
v = *src_v++;

c1 = crv_tab[v];
c2 = cgu_tab[u];
c3 = cgv_tab[v];
c4 = cbu_tab[u];

//up-left
y1 = tab_76309[*py1++];
*d1++ = clp[384+((y1 + c1)>>16)];
*d1++ = clp[384+((y1 - c2 - c3)>>16)];
*d1++ = clp[384+((y1 + c4)>>16)];

//down-left
y2 = tab_76309[*py2++];
*d2++ = clp[384+((y2 + c1)>>16)];
*d2++ = clp[384+((y2 - c2 - c3)>>16)];
*d2++ = clp[384+((y2 + c4)>>16)];

//up-right
y1 = tab_76309[*py1++];
*d1++ = clp[384+((y1 + c1)>>16)];
*d1++ = clp[384+((y1 - c2 - c3)>>16)];
*d1++ = clp[384+((y1 + c4)>>16)];

//down-right
y2 = tab_76309[*py2++];
*d2++ = clp[384+((y2 + c1)>>16)];
*d2++ = clp[384+((y2 - c2 - c3)>>16)];
*d2++ = clp[384+((y2 + c4)>>16)];
}
d1  += 3*width;
d2  += 3*width;
py1 += width;
py2 += width;
}
}

再给出YUV420SP转换的函数,如下:

void yuv420sp_to_rgb24(YUV_TYPE type, unsigned char* yuvbuffer,unsigned char* rgbbuffer, int width,int height) { int y1, y2, u, v; unsigned char *py1, *py2; int i, j, c1, c2, c3, c4; unsigned char *d1, *d2; unsigned char *src_u; static int init_yuv420p = 0; src_u = yuvbuffer + width * height; // u py1 = yuvbuffer; // y py2 = py1 + width; d1 = rgbbuffer; d2 = d1 + 3 * width; init_yuv420p_table(); for (j = 0; j < height; j += 2) { for (i = 0; i < width; i += 2) { if (type == FMT_NV12) { u = *src_u++; v = *src_u++; // v紧跟u,在u的下一个位置 } if (type == FMT_NV21) { v = *src_u++; u = *src_u++; // u紧跟v,在v的下一个位置 } c1 = crv_tab[v]; c2 = cgu_tab[u]; c3 = cgv_tab[v]; c4 = cbu_tab[u]; //up-left y1 = tab_76309[*py1++]; *d1++ = clp[384+((y1 + c1)>>16)]; *d1++ = clp[384+((y1 - c2 - c3)>>16)]; *d1++ = clp[384+((y1 + c4)>>16)]; //down-left y2 = tab_76309[*py2++]; *d2++ = clp[384+((y2 + c1)>>16)]; *d2++ = clp[384+((y2 - c2 - c3)>>16)]; *d2++ = clp[384+((y2 + c4)>>16)]; //up-right y1 = tab_76309[*py1++]; *d1++ = clp[384+((y1 + c1)>>16)]; *d1++ = clp[384+((y1 - c2 - c3)>>16)]; *d1++ = clp[384+((y1 + c4)>>16)]; //down-right y2 = tab_76309[*py2++]; *d2++ = clp[384+((y2 + c1)>>16)]; *d2++ = clp[384+((y2 - c2 - c3)>>16)]; *d2++ = clp[384+((y2 + c4)>>16)]; } d1 += 3*width; d2 += 3*width; py1 += width; py2 += width; } }

void yuv420sp_to_rgb24(YUV_TYPE type, unsigned char* yuvbuffer,unsigned char* rgbbuffer, int width,int height)
{
int y1, y2, u, v;
unsigned char *py1, *py2;
int i, j, c1, c2, c3, c4;
unsigned char *d1, *d2;
unsigned char *src_u;
static int init_yuv420p = 0;

src_u = yuvbuffer + width * height;   // u

py1 = yuvbuffer;   // y
py2 = py1 + width;
d1 = rgbbuffer;
d2 = d1 + 3 * width;

init_yuv420p_table();

for (j = 0; j < height; j += 2)
{
for (i = 0; i < width; i += 2)
{
if (type ==  FMT_NV12)
{
u = *src_u++;
v = *src_u++;      // v紧跟u,在u的下一个位置
}
if (type == FMT_NV21)
{
v = *src_u++;
u = *src_u++;      // u紧跟v,在v的下一个位置
}

c1 = crv_tab[v];
c2 = cgu_tab[u];
c3 = cgv_tab[v];
c4 = cbu_tab[u];

//up-left
y1 = tab_76309[*py1++];
*d1++ = clp[384+((y1 + c1)>>16)];
*d1++ = clp[384+((y1 - c2 - c3)>>16)];
*d1++ = clp[384+((y1 + c4)>>16)];

//down-left
y2 = tab_76309[*py2++];
*d2++ = clp[384+((y2 + c1)>>16)];
*d2++ = clp[384+((y2 - c2 - c3)>>16)];
*d2++ = clp[384+((y2 + c4)>>16)];

//up-right
y1 = tab_76309[*py1++];
*d1++ = clp[384+((y1 + c1)>>16)];
*d1++ = clp[384+((y1 - c2 - c3)>>16)];
*d1++ = clp[384+((y1 + c4)>>16)];

//down-right
y2 = tab_76309[*py2++];
*d2++ = clp[384+((y2 + c1)>>16)];
*d2++ = clp[384+((y2 - c2 - c3)>>16)];
*d2++ = clp[384+((y2 + c4)>>16)];
}
d1  += 3*width;
d2  += 3*width;
py1 += width;
py2 += width;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐