Android OpenGLES绘制yuv420纹理

 曾大稳丶 关注

2018.07.16 11:31 字数 76 阅读 440评论 0喜欢 3

  1. 把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来加载显示,这里就需要将yuvrgb,这里放在OpenGL里面转换,OpenGL里面使用GPU,提高性能。

  1. 数据写入

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;    }}
  1. 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);        }    }}
  1. 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();        }    }}

更多相关文章

  1. android ImageView 图片宽度全屏,高度自适应的写法
  2. [Android]使用RecyclerView替代ListView(三)
  3. Android(安卓)抽屉效果
  4. LocationManager的使用
  5. android 自动换行
  6. android百度地图
  7. StickyScrollView解说
  8. Android(安卓)CheckBox实现SwitchButton
  9. android圆盘菜单效果

随机推荐

  1. 学习01:Android 4.0_你必须知道的13点
  2. Android之输入银行卡号判断属于哪个银行
  3. Android app项目和开发总结
  4. 简单实现跑马灯
  5. Android 中文 API (16) —— AnalogClock
  6. RelativeLayout 相对布局属性
  7. android实现密码框右侧显示小眼睛
  8. 【整理】Android中EditText中的InputType
  9. GitHub 优秀的 Android 开源项目
  10. [置顶] Android屏幕适配全攻略(最权威的