以下是使用 OpenGL ES 在 Android 平台上渲染 NV12 格式数据的 C 代码示例:
```c
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
// 初始化 OpenGL ES 上下文和纹理
GLuint textureId;
GLuint program;
GLint textureUniform;
void initOpenGLContextAndTexture() {
// 创建 OpenGL ES 上下文
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
EGLint major, minor;
eglInitialize(display, &major, &minor);
EGLConfig config;
EGLint numConfigs;
static const EGLint configAttribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_DEPTH_SIZE, 0,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
eglChooseConfig(display, configAttribs, &config, 1, &numConfigs);
EGLSurface surface = eglCreateWindowSurface(display, config, window, NULL);
EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
eglMakeCurrent(display, surface, surface, context);
// 生成纹理
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// 编译着色器程序
static const char* vertexShaderCode = "attribute vec4 position;\n"
"attribute vec2 texCoord;\n"
"varying vec2 v_texCoord;\n"
"void main() {\n"
" gl_Position = position;\n"
" v_texCoord = texCoord;\n"
"}\n";
static const char* fragmentShaderCode = "#extension GL_OES_EGL_image_external : require\n"
"precision mediump float;\n"
"uniform samplerExternalOES texture;\n"
"varying vec2 v_texCoord;\n"
"void main() {\n"
" gl_FragColor = texture2D(texture, v_texCoord);\n"
"}\n";
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderCode, NULL);
glCompileShader(vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderCode, NULL);
glCompileShader(fragmentShader);
program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
textureUniform = glGetUniformLocation(program, "texture");
}
// 渲染 NV12 数据
void renderNV12Data(unsigned char* data, int width, int height) {
// 绑定纹理
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
glTexImage2D(GL_TEXTURE_EXTERNAL_OES, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)data);
// 渲染纹理
glUseProgram(program);
glUniform1i(textureUniform, 0);
static const GLfloat vertexData[] = {
-1.0f, -1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
};
static const GLfloat texCoordData[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, vertexData);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texCoordData);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
```
以上代码中,`initOpenGLContextAndTexture` 函数用于初始化 OpenGL ES 上下文和纹理,`renderNV12Data` 函数用于渲染 NV12 数据。在 `renderNV12Data` 函数中,首先将 NV12 数据转换成 EGLImageOES 对象,并绑定到纹理上,然后使用着色器程序渲染纹理。其中,顶点着色器将顶点位置和纹理坐标传递给片段着色器,片段着色器从外部纹理中采样颜色并输出。