美文网首页opengl es
Android OpenGLES绘制yuv420纹理

Android OpenGLES绘制yuv420纹理

作者: 曾大稳丶 | 来源:发表于2018-07-16 11:31 被阅读0次
    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;//精度 为float
    varying vec2 v_texPo;//纹理位置  接收于vertex_shader
    uniform sampler2D sampler_y;//纹理y
    uniform sampler2D sampler_u;//纹理u
    uniform sampler2D sampler_v;//纹理v
    
    void 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();
            }
        }
    }
    
    

    相关文章

      网友评论

        本文标题:Android OpenGLES绘制yuv420纹理

        本文链接:https://www.haomeiwen.com/subject/alnvpftx.html