使用opengl绘制yuv

首先提出一个公式,yuv转换为rgb的公式:

如果把 RGB 和YUV 的范围都放缩到 [0,255][0,255],那么常用的转换公式是这样的。 

R=Y+1.403x(V-128)
G=Y-0.343x(U-128)-0.714x(V-128)
B=Y+1.770x(U-128)
 
如果把RGB和YUV的范围都放缩到[0,1][0,1],则公式为
R=Y+1.403x(V-0.5)
G=Y-0.343x(U-0.5)-0.714x(V-0.5)
B=Y+1.770x(U-0.5)
 
有一些误差,从网上找了一个调整过的公式:
R=Y+1.13983*(V-0.5)
G=Y-0.39465*(U-0.5)-0.58060*(V-0.5)
B=Y+2.03211*(U-0.5)
 
如果源的格式为YUV420,YUV422,YUV444。因为Y,U,V都是集中存储,当将Y,U,V映射为原始图像宽高的二维图片时,每个图片的r,g,b,a的值与Y,U,V的值相同,故取出r值组成向量,则为宽x高的大小。
比如1920x1080,则通过texture2D方法后,我们得到的位图均为1920x1080,相应的y被扩充4倍,u和v被扩充16倍,由于u和v本身是y的1/4,所以u和v的数据量扩充的和y相同。
通过texture2D函数,我们可以得到每个像素的Y,U,V,他们的长度是相等的。再根据YUV转RGB的公式,就可以得到RGB的值,设置透明度返回,则交给opengl绘制出图像
opengl的shader设置为:

static const char* S_f_shader_yuv4xx1 =
"varying lowp vec2 v_texCoord;\
uniform sampler2D tex_y;\
uniform sampler2D tex_u;\
uniform sampler2D tex_v;\
void main(void)\
{\
float r, g, b, y, u, v;\
y = texture2D(tex_y, v_texCoord).r;\
u = texture2D(tex_u, v_texCoord).r - 0.5;\
v = texture2D(tex_v, v_texCoord).r - 0.5;\
r = y + 1.13983*v;\
g = y - 0.39465*u - 0.58060*v;\
b = y + 2.03211*u;\
gl_FragColor = vec4(r, g, b, 1.0);\
}";

如果为NV12,其排列方式为Y集中排列,UV交错排列

YYYYUVUV

根据这种交错的性质,UV当成一个整体来看,则恰好是Y的1/2,让其宽度增大2倍,则恰好模拟情形应该如下:

A    R   G   B

U0 V0 U0 V0

所以需要将UV作为一个整体,给OpenGL,设置宽度为width/2,高度为height,则R为V0,A为U0

static const char* S_f_shader_nv12 =
"precision highp float;\
varying vec2 v_texCoord;\
uniform sampler2D tex_y;\
uniform sampler2D tex_u;\
void main (void){\
float r, g, b, y, u, v;\
y = texture2D(tex_y, v_texCoord).r;\
u = texture2D(tex_u, v_texCoord).a - 0.5;\
v = texture2D(tex_u, v_texCoord).r - 0.5;\
r = y + 1.13983*v;\
g = y - 0.39465*u - 0.58060*v;\
b = y + 2.03211*u;\
gl_FragColor = vec4(r, g, b, 1.0);\
}";

扫描二维码关注公众号,回复: 4926684 查看本文章
 

猜你喜欢

转载自www.cnblogs.com/limedia/p/opengl_draw_yuv.html