OpenGL學習筆記--渲染yuv紋理


 

OpenGL視頻學習資料:https://pan.baidu.com/s/1muWuuuo1_89AijQRNOcJmg
提取碼:xcwn

 

 

一般ffmpeg解碼后的數據類型都是I420,即YUV420P,OpenGL沒有提供直接渲染yuv的接口,我們可以通過可編程渲染管線,利用多重紋理將Y、U、V紋理分別傳入,在片元着色器GL_FRAGMENT_SHADER中將yuv進行矩陣轉化成RGB,然后進行渲染。

GLSL簡單介紹
OpenGL渲染管線的知識可以參考博客http://www.cnblogs.com/yyxt/p/4056417.html
頂點着色器和片元着色器是必須的。

GLSL的語法和C語言很類似。每一個Shader程序都有一個main函數,這一點和c語言是一樣的。這里的變量命名規則保持跟c一樣就行了,注意gl_開頭的變量名是系統內置的變量。
變量類型:
attribute:外部傳入頂點着色器的變量,每一個頂點都會有這兩個屬性。變化率高,用於定義每個點。
varying:用於頂點着色器和片元着色器之間相互傳遞的參數。
uniform:外部傳入片元着色器的變量,變化率較低,對於可能在整個渲染過程沒有改變,只是個常量。
數據類型:
vec2:包含了2個浮點數的向量
vec3:包含了3個浮點數的向量
vec4:包含了4個浮點數的向量
sampler1D:1D紋理着色器
sampler2D:2D紋理着色器
sampler3D:3D紋理着色器
mat2:2*2維矩陣
mat3:3*3維矩陣
mat4:4*4維矩陣
全局變量:
gl_Position:原始的頂點數據在Vertex Shader中經過平移、旋轉、縮放等數學變換后,生成新的頂點位置(一個四維 (vec4) 變量,包含頂點的 x、y、z 和 w 值)。新的頂點位置通過在Vertex Shader中寫入gl_Position傳遞到渲染管線的后繼階段繼續處理。
gl_FragColor:Fragment Shader的輸出,它是一個四維變量(或稱為 vec4)。gl_FragColor 表示在經過着色器代碼處理后,正在呈現的像素的 R、G、B、A 值。
Vertex Shader是作用於每一個頂點的,如果Vertex有三個點,那么Vertex Shader會被執行三次。Fragment Shader是作用於每個像素的,一個像素運行一次。從源代碼中可以看出,像素的轉換在Fragment Shader中完成。

總結一句話就是頂點着色器搞定位置,片元着色器搞定顏色。

創建YUV着色器
流程圖:
開始
創建頂點着色器和片元着色器 glCreateShader
設定GLSL源碼 glShaderSource
編譯GLSL源碼 glCompileShader
創建一個新的程序 glCreateProgram
關聯着色器 glAttachShader
綁定attribute變量 glBindAttribLocation
鏈接程序 glLinkProgram
獲取uniform變量 glGetUniformLocation
結束
代碼示例
GLuint prog_yuv;
GLuint texUniformY,texUniformU,texUniformV;
GLuint tex_yuv[3];
enum E_VER_ATTR{ver_attr_ver = 3, ver_attr_tex = 4, ver_attr_num};

struct Texture{
GLuint texID; // glGenTextures分配的ID
GLuint type; // 數據類型如GL_RGB
GLint width;
GLint height;
GLint bpp;
GLubyte* data; // 像素數據
};

// 加載YUV着色器
void loadYUVShader(){
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);

char szVS[] = " \
attribute vec4 verIn; \
attribute vec2 texIn; \
varying vec2 texOut; \
\
void main(){ \
gl_Position = verIn; \
texOut = texIn; \
} \
";
const GLchar* pszVS = szVS;
GLint len = strlen(szVS);
glShaderSource(vs, 1, (const GLchar**)&pszVS, &len);

char szFS[] = " \
varying vec2 texOut; \
uniform sampler2D tex_y; \
uniform sampler2D tex_u; \
uniform sampler2D tex_v; \
\
void main(){ \
vec3 yuv; \
vec3 rgb; \
yuv.x = texture2D(tex_y, texOut).r; \
yuv.y = texture2D(tex_u, texOut).r - 0.5; \
yuv.z = texture2D(tex_v, texOut).r - 0.5; \
rgb = mat3( 1, 1, 1, \
0, -0.39465, 2.03211, \
1.13983, -0.58060, 0) * yuv; \
gl_FragColor = vec4(rgb, 1); \
} \
";
const GLchar* pszFS = szFS;
len = strlen(szFS);
glShaderSource(fs, 1, (const GLchar**)&pszFS, &len);

glCompileShader(vs);
glCompileShader(fs);

//#ifdef _DEBUG
GLint iRet = 0;
glGetShaderiv(vs, GL_COMPILE_STATUS, &iRet);
glGetShaderiv(fs, GL_COMPILE_STATUS, &iRet);
//#endif

prog_yuv = glCreateProgram();

glAttachShader(prog_yuv, vs);
glAttachShader(prog_yuv, fs);

glBindAttribLocation(prog_yuv, ver_attr_ver, "verIn");
glBindAttribLocation(prog_yuv, ver_attr_tex, "texIn");

glLinkProgram(prog_yuv);

//#ifdef _DEBUG
glGetProgramiv(prog_yuv, GL_LINK_STATUS, &iRet);
//#endif

glValidateProgram(prog_yuv);

texUniformY = glGetUniformLocation(prog_yuv, "tex_y");
texUniformU = glGetUniformLocation(prog_yuv, "tex_u");
texUniformV = glGetUniformLocation(prog_yuv, "tex_v");


static const GLfloat vertices[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};

static const GLfloat textures[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};

// reverse
//static const GLfloat textures[] = {
// 0.0f, 0.0f,
// 1.0f, 0.0f,
// 0.0f, 1.0f,
// 1.0f, 1.0f,
//};

glVertexAttribPointer(ver_attr_ver, 2, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(ver_attr_ver);

glVertexAttribPointer(ver_attr_tex, 2, GL_FLOAT, GL_FALSE, 0, textures);
glEnableVertexAttribArray(ver_attr_tex);

glGenTextures(3, tex_yuv);
for (int i = 0; i < 3; i++){
glBindTexture(GL_TEXTURE_2D, tex_yuv[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
}

// 繪畫YUV數據
void drawYUV(Texture* tex){
glUseProgram(prog_yuv);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

int w = tex->width;
int h = tex->height;
int y_size = w*h;
GLubyte* y = tex->data;
GLubyte* u = y + y_size;
GLubyte* v = u + (y_size>>2);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex_yuv[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, y);
glUniform1i(texUniformY, 0);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tex_yuv[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w/2, h/2, 0, GL_RED, GL_UNSIGNED_BYTE, u);
glUniform1i(texUniformU, 1);

glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, tex_yuv[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w/2, h/2, 0, GL_RED, GL_UNSIGNED_BYTE, v);
glUniform1i(texUniformV, 2);

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}


這里只是貼出了關鍵的加載YUV着色器,和繪畫YUV數據關鍵的代碼
————————————————
版權聲明:本文為CSDN博主「ithewei」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/GG_SiMiDa/article/details/74474780


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM