Android OpenGL ES 渲染 YUV

1、EGL环境搭建

1.1 关键方法介绍

1)eglGetDisplay 获取EGL显示窗口

2)eglInitialize 对(1)中获取到的Display进行初始化

3)eglChooseConfig 根据对窗口的条件要求从系统中选择最佳的配置数据

4)eglCreateContext 结合EGLDisplay与EGLConfig创建EGL上下文

5)eglCreateWindowSurface 通过Android提供的Surface创建画布

6)eglMakeCurrent EGLContext、EGLSurface、EGLDisplay创建EGL环境,到这一步我们就可以在当前线程下执行OpenGL相关的Api了

7)eglSwapBuffer Surface内容上屏(每一次OpenGL操作后,都需要执行此操作,确保OpenGL绘制操作及时生效)

2、OpenGL 着色器

2.1 关键方法介绍

加载着色器

1)eglCreateShader 根据指定类型(GL_FRAGMENT_SHADER、GL_VERTEX_SHADER...)创建一个空的OpenGL Shader

2)glShaderSource 给创建出来的Shader输入GLSL代码

3)glCompileShader 编译shader

4)glGetShaderiv 获取编译过程中的状态信息 GL_COMPILE_STATUS 获取编译状态,0表示编译失败 GL_INFO_LOG_LENGTH 获取编译中的日志字符长度

5)glGetShaderInfoLog 根据(4)中的日志长度得到编译中的日志信息

6)glDeleteShader 清除Shader

创建着色器程序

7)glCreateProgram 创建一个空的着色器程序

8)glAttachShader 为着色器程序添加Shader

9)glLinkProgram 对(8)中的Shader进行链接

10)glGetProgramiv 获取链接过程中的状态信息 GL_LINK_STATUS 获取链接状态码,0表示链接失败 GL_INFO_LOG_LENGTH 获取链接过程中的日志字符长度

11)glGetProgramInfoLog 根据(10)中的日志长度得到链接过程中的日志信息

12)glDeleteProgram 清理着色器程序

【学习地址】:FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发

【文章福利】:免费领取更多音视频学习资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击1079654574加群领取哦~

​​​​​2.2 YUV着色器

顶点着色器

attribute vec4 vPosition;
attribute vec2 fPosition;
varying vec2 vTextCoord;
uniform mat4 vMatrix;
​
void main() {
  vTextCoord = fPosition;
  gl_Position = vPosition * vMatrix;
}

片段着色器

precision mediump float;
varying vec2 vTextCoord;
uniform sampler2D yTexture;
uniform sampler2D uTexture;
uniform sampler2D vTexture;
​
void main() {
  float y = texture2D(yTexture, vTextCoord).r;
  float u = texture2D(uTexture, vTextCoord).r - 0.5;
  float v = texture2D(vTexture, vTextCoord).r - 0.5;
​
  vec3 rgb;
  rgb.r = y + 1.403 * v;
  rgb.g = y - 0.344 * u - 0.714 * v;
  rgb.b = y + 1.770 * u;
​
  gl_FragColor = vec4(rgb, 1.0);
}

3、Demo实现

3.1 流程简介

3.2 代码实现

CMake库引入

target_link_libraries(
  ${PROJECT_NAME}
​
  # logcat
  ${android-log}
​
  # opengl lib
  # egl
  EGL
​
  # opensl lib
  OpenSLES
  # opengl es 2.0
  GLESv2
​
  # android basic lib
  # ANativeWindow
  android
)

1)创建EGL环境,使得当前线程支持OpenGL操作

// 1、获取默认窗口
EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
​
// 2、对窗口进行初始化
EGLint major,minor;
eglInitialize(eglDisplay, &major, &minor);
​
// 3、为窗口从系统中选定合适的配置
EGLint configAttrib[] = {
    EGL_RED_SIZE, 8,
    EGL_GREEN_SIZE, 8,
    EGL_BLUE_SIZE, 8,
    EGL_ALPHA_SIZE, 8,
    EGL_DEPTH_SIZE, 8,
    EGL_STENCIL_SIZE, 8,
    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,  // OpenGL ES 2.0
    EGL_NONE
 };
EGLint num;
EGLConfig eglConfig;
eglChooseConfig(eglDisplay, configAttrib, &eglConfig, 1, &num);
​
// 4、创建EGL上下文
EGLint contextAttrib[] = {
    EGL_CONTEXT_CLIENT_VERSION, 2, // OpenGL ES 2.0
    EGL_NONE
};
EGLContext eglContext = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, contextAttrib);
​
// 5、创建窗口画布
EGLint surfaceAttrib[] = {
    EGL_WIDTH, 1,
    EGL_HEIGHT, 1,
    EGL_NONE
};
// 这是一个离屏的Surface,等Android可视Surface到达后可进行更换
EGLSurface eglPbSurface = eglCreatePbufferSurface(eglDisplay, eglConfig, surfaceAttrib);
​
// 6、为当前线程绑定EGL环境
eglMakeCurrent(eglDisplay, eglPbSurface, eglPbSurface, eglContext);

2)将EGL环境中的离屏Surface更新为可视Surface(TextureView or SurfaceView or ...)

#include <android/native_window_jni.h>
​
void VideoViewYUV::OnSurfaceCreated(JNIEnv *env, jobject surface) {
  // 将surface转为ANativeWindow类型
  ANativeWindow window = ANativeWindow_fromSurface(env, surface));
  // 通过ANativeWindow创建EGLSurface
  EGLSurface surface = eglCreateWindowSurface(egl_display_, egl_config_, window, 0);
  // 将此Surface更新为当前EGL环境的输出对象
  eglMakeCurrent(eglDisplay, surface, surface, eglContext);
}

3)编译OpenGL着色器

// 1、编译vertex着色器
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderCode, NULL);
glCompileShader(vertexShader);
​
// 2、编译fragment着色器
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderCode, NULL);
glCompileShader(fragmentShader);
​
// 3、创建着色器程序
GLuint program = glCreateProgram();
// 3.1 为着色器程序链接shader
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
// 3.2 链接程序
glLinkProgram(program);

4)启用着色器并初始化相关变量

// 1、启用着色器程序
glUseProgram(program);
​
// 2、找到着色器程序中的所有变量
gpuYTexture = glGetUniformLocation(glslProgram, "yTexture");
gpuUTexture = glGetUniformLocation(glslProgram, "uTexture");
gpuVTexture = glGetUniformLocation(glslProgram, "vTexture");
gpuVMatrix = glGetUniformLocation(glslProgram, "vMatrix");
gpuVPosition = glGetAttribLocation(glslProgram, "vPosition");
gpuFPosition = glGetAttribLocation(glslProgram, "fPosition");
​
glGenTextures(3, cpuYuvTexture);
for (int i = 0; i < 3; i++) {
  glBindTexture(GL_TEXTURE_2D, cpuYuvTexture[i]);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glBindTexture(GL_TEXTURE_2D, 0);
}
​
// 3、输入坐标数据、变换矩阵数据
float v_position[8] = {
  -1.f, 1.f,
  1.f, 1.f,
  -1.f, -1.f,
  1.f, -1.f
};
​
float f_position[8] = {
  0.f, 0.f,
  1.f, 0.f,
  0.f, 1.f,
  1.f, 1.f
};
​
glEnableVertexAttribArray(gpuVPosition);
glVertexAttribPointer(gpuVPosition, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 2, v_position);
​
glEnableVertexAttribArray(gpuFPosition);
glVertexAttribPointer(gpuFPosition, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 2, f_position);
​
glUniformMatrix4fv(gpuVMatrix, 1, GL_FALSE, matrix);

5)输入YUV图片数据并绘制顶点上屏

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, cpuYuvTexture[0]);
glUniform1i(gpuYTexture, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, imageWidth, imageHeight, 0,
               GL_LUMINANCE, GL_UNSIGNED_BYTE, y);
​
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, cpuYuvTexture[1]);
glUniform1i(gpuUTexture, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, imageWidth / 2, imageHeight / 2,
               0, GL_LUMINANCE, GL_UNSIGNED_BYTE, u);
​
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, cpuYuvTexture[2]);
glUniform1i(gpuVTexture, 2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, imageWidth / 2, imageHeight / 2,
               0, GL_LUMINANCE, GL_UNSIGNED_BYTE, v);
​
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
​
// 内容上屏
eglSwapBuffer();

原文链接:Android OpenGL ES 渲染 YUV - 掘金

猜你喜欢

转载自blog.csdn.net/irainsa/article/details/130031451