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);
}