在iOS上使用OpenGL ES点染YUV

在iOS上使用OpenGL ES渲染YUV
1)创建OpenGL context
[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];


2)layer设置成不透明
_eaglLayer = (CAEAGLLayer*) self.layer;
_eaglLayer.opaque = YES;


3)创建YUV texture
glGenTextures(1, &m_nTexturePlanarY);
glGenTextures(1, &m_nTexturePlanarU);
glGenTextures(1, &m_nTexturePlanarV);


4)添加shader
GLuint vertexShader = CompileShader(_VERTEX_SHADER_Y_U_V, GL_VERTEX_SHADER);
GLuint fragmentShader = CompileShader(_FRAGMENT_SHADER_Y_U_V, GL_FRAGMENT_SHADER);
glAttachShader(m_nProgramHandle, vertexShader);
glAttachShader(m_nProgramHandle, fragmentShader);


摘录一段GLSL介绍
OpenGL着色语言(GLSL―OpenGL Shading Language)是用来在OpenGL中着色编程的语言,也即开发人员写的短小的自定义程序,他们是在图形卡的GPU (Graphic Processor Unit图形处理单元)上执行的,代替了固定的渲染管线的一部分,使渲染管线中不同层次具有可编程型。比如:视图转换、投影转换等。GLSL(GL Shading Language)的着色器代码分成2个部分:Vertex Shader(顶点着色器)和Fragment(片断着色器),有时还会有Geometry Shader(几何着色器)。负责运行顶点着色的是顶点着色器。它可以得到当前OpenGL 中的状态,GLSL内置变量进行传递。GLSL其使用C语言作为基础高阶着色语言,避免了使用汇编语言或硬件规格语言的复杂性。


5)创建render buffer
glGenRenderbuffers(1, &nColorRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, nColorRenderBuffer);


6)创建frame buffer
glGenFramebuffers(1, &nFrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, nFrameBuffer);


7)创建viewport
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &nBackingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &nBackingHeight);
glViewport(0, 0, nBackingWidth, nBackingHeight);   
glClearColor(0.0, 0.0, 0.0, 1.0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);


8)设置四个顶点,四个顶点的设置顺序不同,可以实现图像的上下、左右翻转。

在最后render到屏幕时会用到这些顶点,如下

glVertexAttribPointer(m_nPositionSlot, 2, GL_FLOAT, 0, 0, m_fSquareVertices);
glVertexAttribPointer(m_nTexCoordSlot, 2, GL_FLOAT, 0, 0, m_fTextureVertices);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);


9)YUV数据到来时,即可以开始渲染,步骤如下


a. YUV数据更新到texture上
GLTexImage2D(m_nTexturePlanarY, m_pFrameData, m_nTextureWidth, m_nTextureHeight);
GLTexImage2D(m_nTexturePlanarU, pBuffer - (nWidthUV * nHeightUV), nWidthUV, nHeightUV);
GLTexImage2D(m_nTexturePlanarV, pBuffer, nWidthUV, nHeightUV);


b. Bind YUV texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_nTexturePlanarY);
glUniform1i(m_nTextureUniformY, 0);
   
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_nTexturePlanarU);
glUniform1i(m_nTextureUniformU, 1);
   
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, m_nTexturePlanarV);
glUniform1i(m_nTextureUniformV, 2);


c. 绘制图像
glVertexAttribPointer(m_nPositionSlot, 2, GL_FLOAT, 0, 0, m_fSquareVertices);
glVertexAttribPointer(m_nTexCoordSlot, 2, GL_FLOAT, 0, 0, m_fTextureVertices);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);


d. 在屏幕上显示出来
[m_pContext presentRenderbuffer:GL_RENDERBUFFER];


10)程序退出时释放所有之前分配出来的资源