本文主要是介绍Android OpenGLES绘制yuv420纹理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
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;//精度 为float
varying vec2 v_texPo;//纹理位置 接收于vertex_shader
uniform sampler2D sampler_y;//纹理y
uniform sampler2D sampler_u;//纹理u
uniform sampler2D sampler_v;//纹理vvoid main() {//yuv420->rgbfloat 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 left1f, -1f, 0.0f, // bottom right-1f, 1f, 0.0f, // top left1f, 1f, 0.0f, // top right};//纹理坐标static float textureData[] = { // in counterclockwise order:0f, 1f, 0.0f, // bottom left1f, 1f, 0.0f, // bottom right0f, 0f, 0.0f, // top left1f, 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 标识纹理xGLES20.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) {//添加代码到shaderGLES20.glShaderSource(shader, source);//编译shaderGLES20.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 shaderint vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);if (vertexShader == 0) {return 0;}//获取fragment shaderint 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;}@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {yuv420Texture = new YUV420Texture(context);yuv420Texture.initYUV();}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {//宽高GLES20.glViewport(0, 0, width, height);}@Overridepublic 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 OpenGLES绘制yuv420纹理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!