Android(安卓)OpenGLES绘制yuv420纹理
16lz
2021-01-25
Android OpenGLES绘制yuv420纹理
曾大稳丶 关注
2018.07.16 11:31 字数 76 阅读 440评论 0喜欢 3
- 把shader代码写入raw里面
vertex_shader.glsl
attribute vec4 av_Position;//顶点位置attribute vec2 af_Position;//纹理位置varying vec2 v_texPo;//纹理位置 与fragment_shader交互void main() { v_texPo = af_Position; gl_Position = av_Position;}
fragment_shader.glsl
precision mediump float;//精度 为floatvarying vec2 v_texPo;//纹理位置 接收于vertex_shaderuniform sampler2D sampler_y;//纹理yuniform sampler2D sampler_u;//纹理uuniform sampler2D sampler_v;//纹理vvoid main() { //yuv420->rgb float y,u,v; y = texture2D(sampler_y,v_texPo).r; u = texture2D(sampler_u,v_texPo).r- 0.5; v = texture2D(sampler_v,v_texPo).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);}
因为OpenGLES
需要用rgb
来加载显示,这里就需要将yuv
转rgb
,这里放在OpenGL
里面转换,OpenGL
里面使用GPU
,提高性能。
- 数据写入
YUV420Texture.java
import android.content.Context;import android.opengl.GLES20;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;public class YUV420Texture { private Context context; //顶点坐标 static float vertexData[] = { // in counterclockwise order: -1f, -1f, 0.0f, // bottom left 1f, -1f, 0.0f, // bottom right -1f, 1f, 0.0f, // top left 1f, 1f, 0.0f, // top right }; //纹理坐标 static float textureData[] = { // in counterclockwise order: 0f, 1f, 0.0f, // bottom left 1f, 1f, 0.0f, // bottom right 0f, 0f, 0.0f, // top left 1f, 0f, 0.0f, // top right }; //每一次取点的时候取几个点 static final int COORDS_PER_VERTEX = 3; private final int vertexCount = vertexData.length / COORDS_PER_VERTEX; //每一次取的总的点 大小 private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex //位置 private FloatBuffer vertexBuffer; //纹理 private FloatBuffer textureBuffer; private int program; //顶点位置 private int avPosition; //纹理位置 private int afPosition; //shader yuv变量 private int sampler_y; private int sampler_u; private int sampler_v; private int[] textureId_yuv; //YUV数据 private int width_yuv; private int height_yuv; private ByteBuffer y; private ByteBuffer u; private ByteBuffer v; public YUV420Texture(Context context) { this.context = context; vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer() .put(vertexData); vertexBuffer.position(0); textureBuffer = ByteBuffer.allocateDirect(textureData.length * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer() .put(textureData); textureBuffer.position(0); } public void initYUV() { String vertexSource = ShaderUtil.readRawTxt(context, R.raw.vertex_shader); String fragmentSource = ShaderUtil.readRawTxt(context, R.raw.fragment_shader); program = ShaderUtil.createProgram(vertexSource, fragmentSource); if (program > 0) { //获取顶点坐标字段 avPosition = GLES20.glGetAttribLocation(program, "av_Position"); //获取纹理坐标字段 afPosition = GLES20.glGetAttribLocation(program, "af_Position"); //获取yuv字段 sampler_y = GLES20.glGetUniformLocation(program, "sampler_y"); sampler_u = GLES20.glGetUniformLocation(program, "sampler_u"); sampler_v = GLES20.glGetUniformLocation(program, "sampler_v"); textureId_yuv = new int[3]; //创建3个纹理 GLES20.glGenTextures(3, textureId_yuv, 0); //绑定纹理 for (int id : textureId_yuv) { GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, id); //环绕(超出纹理坐标范围) (s==x t==y GL_REPEAT 重复) GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT); //过滤(纹理像素映射到坐标点) (缩小、放大:GL_LINEAR线性) GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); } } } public void setYUVData(int width, int height, byte[] y, byte[] u, byte[] v) { this.width_yuv = width; this.height_yuv = height; this.y = ByteBuffer.wrap(y); this.u = ByteBuffer.wrap(u); this.v = ByteBuffer.wrap(v); } public void draw() { if (width_yuv > 0 && height_yuv > 0 && y != null && u != null && v != null) { GLES20.glUseProgram(program); GLES20.glEnableVertexAttribArray(avPosition); GLES20.glVertexAttribPointer(avPosition, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer); GLES20.glEnableVertexAttribArray(afPosition); GLES20.glVertexAttribPointer(afPosition, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, textureBuffer); //激活纹理0来绑定y数据 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId_yuv[0]); //glTexImage2D (int target, // int level, // int internalformat, // int width, // int height, // int border, // int format, // int type, // Buffer pixels) GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, width_yuv, height_yuv, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, y); //激活纹理1来绑定u数据 GLES20.glActiveTexture(GLES20.GL_TEXTURE1); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId_yuv[1]); GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, width_yuv / 2, height_yuv / 2, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, u); //激活纹理2来绑定u数据 GLES20.glActiveTexture(GLES20.GL_TEXTURE2); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId_yuv[2]); GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, width_yuv / 2, height_yuv / 2, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, v); //给fragment_shader里面yuv变量设置值 0 1 2 标识纹理x GLES20.glUniform1i(sampler_y, 0); GLES20.glUniform1i(sampler_u, 1); GLES20.glUniform1i(sampler_v, 2); //绘制 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount); y.clear(); u.clear(); v.clear(); y = null; u = null; v = null; GLES20.glDisableVertexAttribArray(afPosition); GLES20.glDisableVertexAttribArray(avPosition); } }}
ShaderUtil.java
import android.content.Context;import android.opengl.GLES20;import android.util.Log;import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;public class ShaderUtil { private static final String TAG = "ShaderUtil"; public static String readRawTxt(Context context, int rawId) { InputStream inputStream = context.getResources().openRawResource(rawId); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); StringBuffer sb = new StringBuffer(); String line; try { while ((line = reader.readLine()) != null) { sb.append(line).append("\n"); } reader.close(); } catch (Exception e) { e.printStackTrace(); } return sb.toString(); } public static int loadShader(int shaderType, String source) { // create a vertex shader type (GLES20.GL_VERTEX_SHADER) // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER) int shader = GLES20.glCreateShader(shaderType); if (shader != 0) { //添加代码到shader GLES20.glShaderSource(shader, source); //编译shader GLES20.glCompileShader(shader); int[] compile = new int[1]; //检测是否编译成功 GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compile, 0); if (compile[0] != GLES20.GL_TRUE) { Log.d(TAG, "shader compile error"); GLES20.glDeleteShader(shader); shader = 0; } } return shader; } public static int createProgram(String vertexSource, String fragmentSource) { //获取vertex shader int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); if (vertexShader == 0) { return 0; } //获取fragment shader int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); if (fragmentShader == 0) { return 0; } //创建一个空的渲染程序 int program = GLES20.glCreateProgram(); if (program != 0) { //添加vertexShader到渲染程序 GLES20.glAttachShader(program, vertexShader); //添加fragmentShader到渲染程序 GLES20.glAttachShader(program, fragmentShader); //关联为可执行渲染程序 GLES20.glLinkProgram(program); int[] linsStatus = new int[1]; //检测是否关联成功 GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linsStatus, 0); if (linsStatus[0] != GLES20.GL_TRUE) { Log.d(TAG, "link program error"); GLES20.glDeleteProgram(program); program = 0; } } return program; }}
- Render书写
MyRender.java
import android.content.Context;import android.opengl.GLES20;import android.opengl.GLSurfaceView;import javax.microedition.khronos.egl.EGLConfig;import javax.microedition.khronos.opengles.GL10;public class MyRender implements GLSurfaceView.Renderer { private Context context; private YUV420Texture yuv420Texture; public MyRender(Context context) { this.context = context; } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { yuv420Texture = new YUV420Texture(context); yuv420Texture.initYUV(); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { //宽高 GLES20.glViewport(0, 0, width, height); } @Override public void onDrawFrame(GL10 gl) { //清空颜色 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); //设置背景颜色// GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); yuv420Texture.draw(); } public void setYuvData(int width, int height, byte[] y, byte[] u, byte[] v) { if (yuv420Texture != null) { yuv420Texture.setYUVData(width, height, y, u, v); } }}
- GLSurfaceView引用Renderer
MyGLSurfaceView.java
import android.content.Context;import android.opengl.GLSurfaceView;import android.util.AttributeSet;public class MyGLSurfaceView extends GLSurfaceView { private MyRender myRender; public MyGLSurfaceView(Context context) { this(context, null); } public MyGLSurfaceView(Context context, AttributeSet attrs) { super(context, attrs); setEGLContextClientVersion(2); myRender = new MyRender(context); setRenderer(myRender); //mode=GLSurfaceView.RENDERMODE_WHEN_DIRTY之后 调用requestRender()触发Render的onDrawFrame函数 //mode=GLSurfaceView.RENDERMODE_CONTINUOUSLY之后 自动调用onDrawFrame 60fps左右 setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); } public void setYUVData(int width, int height, byte[] y, byte[] u, byte[] v) { if (myRender != null) { myRender.setYuvData(width, height, y, u, v); requestRender(); } }}
更多相关文章
- android ImageView 图片宽度全屏,高度自适应的写法
- [Android]使用RecyclerView替代ListView(三)
- Android(安卓)抽屉效果
- LocationManager的使用
- android 自动换行
- android百度地图
- StickyScrollView解说
- Android(安卓)CheckBox实现SwitchButton
- android圆盘菜单效果