当前位置: 代码迷 >> 综合 >> OpenGL ES 渲染YUV数据
  详细解决方案

OpenGL ES 渲染YUV数据

热度:39   发布时间:2024-02-08 00:30:25.0

1.yuv的字节数

现有宽为w高为h的一个视频,现在定义了一个data[] bytes变量并存储了这个视频的一帧数据。

  • bytes数组中,先连续存储每个像素的灰度信息,y通道占w*h个字节;
  • 然后顺序存储颜色数据,u和v分别占一个字节,每个颜色数据共占2个字节,所以uv通道占(w/2)(h/2)2=w*h/2个字。

2.纹理

2.1 纹理的组成

  • y通道的数据生成一个opengl纹理;
  • uv通道的数据生成一个opengl纹理;
  • 两个纹理作为渲染时的输入,在渲染过程中由GPU组装还原出来视频画面。

2.2 纹理格式

 GL_LUMINANCE 和 GL_LUMINANCE_ALPHA 格式的纹理。

  • GL_LUMINANCE 纹理用来加载 NV21 Y Plane 的数据;
  • GL_LUMINANCE_ALPHA 纹理用来加载 UV Plane 的数据。
基本内部格式 所提取的颜色
GL_ALPHA (0,0,0,A)
GL_LUMINANCE (L,L,L,1)--->亮度
GL_LUMINANCE_ALPHA (L,L,L,A)--->透明度
GL_INTENSITY (I,I,I,I)
GL_RGB (R,G,B,1)
GL_RGBA (R,G,B,A)

3. YUV渲染步骤

  • 第一步:编译链接着色器程序,生成2个纹理;
  • 第二步:确定纹理坐标及对应的顶点坐标;
  • 第三步:分别加载NV21的两个Plane数据到2个纹理(4);
  • 第四步:加载纹理坐标和顶点坐标数据到着色器程序;
  • 第五步:绘制。

4.代码案例

第一步:生成两个

// 编译链接着色器程序,生成 2 个纹理
void NV21TextureMapSample::Init()
{char vShaderStr[] ="#version 300 es                            \n""layout(location = 0) in vec4 a_position;   \n""layout(location = 1) in vec2 a_texCoord;   \n""out vec2 v_texCoord;                       \n""void main()                                \n""{                                          \n""   gl_Position = a_position;               \n""   v_texCoord = a_texCoord;                \n""}                                          \n";char fShaderStr[] ="#version 300 es                                     \n""precision mediump float;                            \n""in vec2 v_texCoord;                                 \n""layout(location = 0) out vec4 outColor;             \n""uniform sampler2D y_texture;                        \n""uniform sampler2D uv_texture;                        \n""void main()                                         \n""{                                                   \n""	vec3 yuv;										\n""   yuv.x = texture(y_texture, v_texCoord).r;  	\n""   yuv.y = texture(uv_texture, v_texCoord).a-0.5;	\n""   yuv.z = texture(uv_texture, v_texCoord).r-0.5;	\n""	highp vec3 rgb = mat3( 1,       1,       	1,					\n""               0, 		-0.344, 	1.770,					\n""               1.403,  -0.714,       0) * yuv; 			\n""	outColor = vec4(rgb, 1);						\n""}                                                   \n";// Load the shaders and get a linked program objectm_ProgramObj= GLUtils::CreateProgram(vShaderStr, fShaderStr, m_VertexShader, m_FragmentShader);// Get the sampler locationm_ySamplerLoc = glGetUniformLocation (m_ProgramObj, "y_texture" );m_uvSamplerLoc = glGetUniformLocation(m_ProgramObj, "uv_texture");//create texturesGLuint textureIds[2] = {0};glGenTextures(2, textureIds);m_yTextureId = textureIds[0];m_uvTextureId = textureIds[1];
}

第二步:

// 加载 NV21 图像数据到纹理,加载纹理坐标和顶点坐标数据到着色器程序,绘制实现 YUV 渲染
void NV21TextureMapSample::Draw(int screenW, int screenH)
{LOGCATE("NV21TextureMapSample::Draw()");if(m_ProgramObj == GL_NONE || m_yTextureId == GL_NONE || m_uvTextureId == GL_NONE) return;//upload Y plane dataglBindTexture(GL_TEXTURE_2D, m_yTextureId);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_RenderImage.width, m_RenderImage.height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_RenderImage.ppPlane[0]);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glBindTexture(GL_TEXTURE_2D, GL_NONE);//update UV plane dataglBindTexture(GL_TEXTURE_2D, m_uvTextureId);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, m_RenderImage.width >> 1, m_RenderImage.height >> 1, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, m_RenderImage.ppPlane[1]);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glBindTexture(GL_TEXTURE_2D, GL_NONE);//glViewport(0, 0, m_RenderImage.width, m_RenderImage.height);GLfloat verticesCoords[] = {-1.0f,  0.78f, 0.0f,  // Position 0-1.0f, -0.78f, 0.0f,  // Position 11.0f,  -0.78f, 0.0f,  // Position 21.0f,   0.78f, 0.0f,  // Position 3};GLfloat textureCoords[] = {0.0f,  0.0f,        // TexCoord 00.0f,  1.0f,        // TexCoord 11.0f,  1.0f,        // TexCoord 21.0f,  0.0f         // TexCoord 3};GLushort indices[] = { 0, 1, 2, 0, 2, 3 };// Use the program objectglUseProgram (m_ProgramObj);// Load the vertex positionglVertexAttribPointer (0, 3, GL_FLOAT,GL_FALSE, 3 * sizeof (GLfloat), verticesCoords);// Load the texture coordinateglVertexAttribPointer (1, 2, GL_FLOAT,GL_FALSE, 2 * sizeof (GLfloat), textureCoords);glEnableVertexAttribArray (0);glEnableVertexAttribArray (1);// Bind the Y plane mapglActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, m_yTextureId);// Set the Y plane sampler to texture unit to 0glUniform1i(m_ySamplerLoc, 0);// Bind the UV plane mapglActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, m_uvTextureId);// Set the UV plane sampler to texture unit to 1glUniform1i(m_uvSamplerLoc, 1);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
}