package com.example.datalibrary.deptrum; import android.opengl.GLES20; import com.example.datalibrary.deptrum.openglhelper.RGBRendThread; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; /** * step to use:
* 1. new GLProgram()
* 2. buildProgram()
* 3. buildTextures()
* 4. drawFrame()
*/ public class RGB24GLProgram { private static final String VERTEX_SHADER = "uniform mat4 uMVPMatrix;\n" + "attribute vec4 vPosition;\n" + "attribute vec2 a_texCoord;\n" + "varying vec2 tc;\n" + "void main() {\n" + "gl_Position = uMVPMatrix * vPosition;\n" + "tc = a_texCoord;\n" + "}\n"; private static final String FRAGMENT_SHADER = "precision mediump float;\n" + "uniform sampler2D tex_y;\n" + "uniform sampler2D tex_u;\n" + "uniform sampler2D tex_v;\n" + "varying vec2 tc;\n" + "void main() {\n" + "vec4 c = vec4((texture2D(tex_y, tc).r - 16./255.) * 1.164);\n" + "vec4 U = vec4(texture2D(tex_u, tc).r - 128./255.);\n" + "vec4 V = vec4(texture2D(tex_v, tc).r - 128./255.);\n" + "c += V * vec4(1.596, -0.813, 0, 0);\n" + "c += U * vec4(0, -0.392, 2.017, 0);\n" + "c.a = 1.0;\n" + "gl_FragColor = c;\n" + "}\n"; private static final String VERTEX_SHADER1 = "uniform mat4 uMVPMatrix;\n" + "attribute vec4 vPosition;\n" + "attribute vec2 a_texCoord;\n" + "varying vec2 tc;\n" + "void main() {\n" + "gl_Position = uMVPMatrix * vPosition;\n" + "tc = a_texCoord;\n" + "}\n"; private static final String FRAGMENT_SHADER1 = "precision mediump float;\n" + "uniform sampler2D tex_y;\n" + "varying vec2 tc;\n" + "void main() {\n" + "gl_FragColor = texture2D(tex_y,tc);\n" + "}\n"; private float[] mViewMatrix = new float[16]; private int mVPMatrixHandle = -1; static float[] s0Matrix = { 1.0f, 0.0f, 0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; static float[] s0MirrorMatrix = { -1.0f, 0.0f, 0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; static float[] s90Matrix = { 0.0f, -1.0f, 0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; static float[] s90MirrorMatrix = { 0.0f, -1.0f, 0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; static float[] s180Matrix = { -1.0f, 0.0f, 0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; static float[] s180MirrorMatrix = { 1.0f, 0.0f, 0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; static float[] s270Matrix = { 0.0f, 1.0f, 0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; static float[] s270MirrorMatrix = { 0.0f, 1.0f, 0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; static float[] squareVertices = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, }; /*fullscreen*/ static float[] squareVertices1 = { -1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, }; /*left-top*/ static float[] squareVertices2 = { 0.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, }; /*right-bottom*/ static float[] squareVertices3 = { -1.0f, -1.0f, 0.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, }; /*left-bottom*/ static float[] squareVertices4 = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, }; /*right-top*/ private static float[] coordVertices = { 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, }; /*whole-texture*/ public final int mWinPosition; private int mGLProgram; private int mGLTextureI; private int mGLTextureII; private int mGLTextureIII; private int mGLIndexI; private int mGLIndexII; private int mGLTIndexIII; private float[] mGLVertices; private int mPositionHandle = -1; private int mCoordHandle = -1; private int mYhandle = -1; private int mUhandle = -1; private int mVhandle = -1; private int mYtid = -1; private int mUtid = -1; private int mVtid = -1; private ByteBuffer mVerticeBuffer; private ByteBuffer mCoordBuffer; private int mVideoWidth = -1; private int mVideoHeight = -1; private boolean isProgBuilt = false; /** * position can only be 0~4:
* fullscreen => 0
* left-top => 1
* right-top => 2
* left-bottom => 3
* right-bottom => 4 */ public RGB24GLProgram(int position) { if (position < 0 || position > 4) { throw new RuntimeException("Index can only be 0 to 4"); } mWinPosition = position; setup(); } /** * prepared for later use */ private void setup() { switch (mWinPosition) { case 1: mGLVertices = squareVertices1; mGLTextureI = GLES20.GL_TEXTURE0; mGLTextureII = GLES20.GL_TEXTURE1; mGLTextureIII = GLES20.GL_TEXTURE2; mGLIndexI = 0; mGLIndexII = 1; mGLTIndexIII = 2; break; case 2: mGLVertices = squareVertices2; mGLTextureI = GLES20.GL_TEXTURE3; mGLTextureII = GLES20.GL_TEXTURE4; mGLTextureIII = GLES20.GL_TEXTURE5; mGLIndexI = 3; mGLIndexII = 4; mGLTIndexIII = 5; break; case 3: mGLVertices = squareVertices3; mGLTextureI = GLES20.GL_TEXTURE6; mGLTextureII = GLES20.GL_TEXTURE7; mGLTextureIII = GLES20.GL_TEXTURE8; mGLIndexI = 6; mGLIndexII = 7; mGLTIndexIII = 8; break; case 4: mGLVertices = squareVertices4; mGLTextureI = GLES20.GL_TEXTURE9; mGLTextureII = GLES20.GL_TEXTURE10; mGLTextureIII = GLES20.GL_TEXTURE11; mGLIndexI = 9; mGLIndexII = 10; mGLTIndexIII = 11; break; case 0: default: mGLVertices = squareVertices; mGLTextureI = GLES20.GL_TEXTURE0; mGLTextureII = GLES20.GL_TEXTURE1; mGLTextureIII = GLES20.GL_TEXTURE2; mGLIndexI = 0; mGLIndexII = 1; mGLTIndexIII = 2; break; } } public boolean isProgramBuilt() { return isProgBuilt; } public void buildProgram() { if (mGLProgram <= 0) { mGLProgram = createProgram(VERTEX_SHADER1, FRAGMENT_SHADER1); } /* * get handle for "vPosition" and "a_texCoord" */ try { // mPositionHandle = GLES20.glGetAttribLocation(mGLProgram, "vPosition"); // checkGlError("glGetAttribLocation vPosition"); // if (mPositionHandle == -1) { // throw new RuntimeException("Could not get attribute location for // vPosition"); // } // mCoordHandle = GLES20.glGetAttribLocation(mGLProgram, "a_texCoord"); // checkGlError("glGetAttribLocation a_texCoord"); // if (mCoordHandle == -1) { // throw new RuntimeException("Could not get attribute location for // a_texCoord"); // } // /* // * get uniform location for y/u/v, we pass data through these uniforms // */ // mYhandle = GLES20.glGetUniformLocation(mGLProgram, "tex_y"); // checkGlError("glGetUniformLocation tex_y"); // if (mYhandle == -1) { // throw new RuntimeException("Could not get uniform location for tex_y"); // } // mUhandle = GLES20.glGetUniformLocation(mGLProgram, "tex_u"); // checkGlError("glGetUniformLocation tex_u"); // if (mUhandle == -1) { // throw new RuntimeException("Could not get uniform location for tex_u"); // } // mVhandle = GLES20.glGetUniformLocation(mGLProgram, "tex_v"); // checkGlError("glGetUniformLocation tex_v"); // if (mVhandle == -1) { // throw new RuntimeException("Could not get uniform location for tex_v"); // } mVPMatrixHandle = GLES20.glGetUniformLocation(mGLProgram, "uMVPMatrix"); mPositionHandle = GLES20.glGetAttribLocation(mGLProgram, "vPosition"); RGBRendThread.ShaderUtil.checkGlError("glGetAttribLocation vPosition"); if (mPositionHandle == -1) { throw new RuntimeException("Could not get attribute location for vPosition"); } mCoordHandle = GLES20.glGetAttribLocation(mGLProgram, "a_texCoord"); RGBRendThread.ShaderUtil.checkGlError("glGetAttribLocation a_texCoord"); if (mCoordHandle == -1) { throw new RuntimeException("Could not get attribute location for a_texCoord"); } mYhandle = GLES20.glGetUniformLocation(mGLProgram, "tex_y"); RGBRendThread.ShaderUtil.checkGlError("glGetUniformLocation tex_y"); if (mYhandle == -1) { throw new RuntimeException("Could not get uniform location for tex_y"); } isProgBuilt = true; } catch (RuntimeException e) { e.printStackTrace(); } } public void releaseProgram() { GLES20.glUseProgram(0); if (mGLProgram >= 0) { GLES20.glDeleteProgram(mGLProgram); } mGLProgram = -1; isProgBuilt = false; } /** * build a set of textures, one for R, one for G, and one for B. */ public void buildTextures(Buffer y, Buffer u, Buffer v, int width, int height) { boolean videoSizeChanged = (width != mVideoWidth || height != mVideoHeight); if (videoSizeChanged) { mVideoWidth = width; mVideoHeight = height; } // building texture for Y data if (mYtid < 0 || videoSizeChanged) { if (mYtid >= 0) { GLES20.glDeleteTextures(1, new int[]{mYtid}, 0); checkGlError("glDeleteTextures"); } // GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); int[] textures = new int[1]; GLES20.glGenTextures(1, textures, 0); checkGlError("glGenTextures"); mYtid = textures[0]; } GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mYtid); checkGlError("glBindTexture"); GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, mVideoWidth, mVideoHeight, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, y); checkGlError("glTexImage2D"); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); // building texture for U data if (mUtid < 0 || videoSizeChanged) { if (mUtid >= 0) { GLES20.glDeleteTextures(1, new int[]{mUtid}, 0); checkGlError("glDeleteTextures"); } int[] textures = new int[1]; GLES20.glGenTextures(1, textures, 0); checkGlError("glGenTextures"); mUtid = textures[0]; } GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mUtid); GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, mVideoWidth / 2, mVideoHeight / 2, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, u); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); // building texture for V data if (mVtid < 0 || videoSizeChanged) { if (mVtid >= 0) { GLES20.glDeleteTextures(1, new int[]{mVtid}, 0); checkGlError("glDeleteTextures"); } int[] textures = new int[1]; GLES20.glGenTextures(1, textures, 0); checkGlError("glGenTextures"); mVtid = textures[0]; } GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mVtid); GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, mVideoWidth / 2, mVideoHeight / 2, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, v); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); } public void buildTextures(Buffer rgbBuffer, int width, int height, boolean hasAlpha) { boolean videoSizeChanged = (width != mVideoWidth || height != mVideoHeight); if (videoSizeChanged) { mVideoWidth = width; mVideoHeight = height; } if (mYtid < 0 || videoSizeChanged) { if (mYtid >= 0) { GLES20.glDeleteTextures(1, new int[]{mYtid}, 0); RGBRendThread.ShaderUtil.checkGlError("glDeleteTextures"); } int[] textures = new int[1]; GLES20.glGenTextures(1, textures, 0); RGBRendThread.ShaderUtil.checkGlError("glGenTextures"); mYtid = textures[0]; } GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mYtid); RGBRendThread.ShaderUtil.checkGlError("glBindTexture"); GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, hasAlpha ? GLES20.GL_RGBA : GLES20.GL_RGB, mVideoWidth, mVideoHeight, 0, hasAlpha ? GLES20.GL_RGBA : GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, rgbBuffer); RGBRendThread.ShaderUtil.checkGlError("glTexImage2D"); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); } public void setDisplayOrientation(int degrees, boolean needMirror) { if (degrees == 0) { if (needMirror) { mViewMatrix = s0MirrorMatrix; } else { mViewMatrix = s0Matrix; } } else if (degrees == 90) { if (needMirror) { mViewMatrix = s90MirrorMatrix; } else { mViewMatrix = s90Matrix; } } else if (degrees == 180) { if (needMirror) { mViewMatrix = s180MirrorMatrix; } else { mViewMatrix = s180Matrix; } } else if (degrees == 270) { if (needMirror) { mViewMatrix = s270MirrorMatrix; } else { mViewMatrix = s270Matrix; } } else { } } /** * render the frame the YUV data will be converted to RGB by shader. */ public void drawFrame() { if (null == mVerticeBuffer) { return; } GLES20.glUseProgram(mGLProgram); checkGlError("glUseProgram"); GLES20.glUniformMatrix4fv(mVPMatrixHandle, 1, false, mViewMatrix, 0); GLES20.glVertexAttribPointer(mPositionHandle, 2, GLES20.GL_FLOAT, false, 8, mVerticeBuffer); checkGlError("glVertexAttribPointer mPositionHandle"); GLES20.glEnableVertexAttribArray(mPositionHandle); GLES20.glVertexAttribPointer(mCoordHandle, 2, GLES20.GL_FLOAT, false, 8, mCoordBuffer); checkGlError("glVertexAttribPointer maTextureHandle"); GLES20.glEnableVertexAttribArray(mCoordHandle); // bind textures GLES20.glActiveTexture(mGLTextureI); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mYtid); GLES20.glUniform1i(mYhandle, mGLIndexI); // GLES20.glActiveTexture(mGLTextureII); // GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mUtid); // GLES20.glUniform1i(mUhandle, mGLIndexII); // // GLES20.glActiveTexture(mGLTextureIII); // GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mVtid); // GLES20.glUniform1i(mVhandle, mGLTIndexIII); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); GLES20.glFinish(); GLES20.glDisableVertexAttribArray(mPositionHandle); GLES20.glDisableVertexAttribArray(mCoordHandle); } /** * create program and load shaders, fragment shader is very important. */ public int createProgram(String vertexSource, String fragmentSource) { // create shaders int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); // just check int program = GLES20.glCreateProgram(); if (program != 0) { GLES20.glAttachShader(program, vertexShader); checkGlError("glAttachShader"); GLES20.glAttachShader(program, pixelShader); checkGlError("glAttachShader"); GLES20.glLinkProgram(program); int[] linkStatus = new int[1]; GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); if (linkStatus[0] != GLES20.GL_TRUE) { GLES20.glDeleteProgram(program); program = 0; } } return program; } /** * create shader with given source. */ private int loadShader(int shaderType, String source) { int shader = GLES20.glCreateShader(shaderType); if (shader != 0) { GLES20.glShaderSource(shader, source); GLES20.glCompileShader(shader); int[] compiled = new int[1]; GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); if (compiled[0] == 0) { GLES20.glDeleteShader(shader); shader = 0; } } return shader; } /** * these two buffers are used for holding vertices, screen vertices and texture vertices. */ void createBuffers(float[] vert) { mVerticeBuffer = ByteBuffer.allocateDirect(vert.length * 4); mVerticeBuffer.order(ByteOrder.nativeOrder()); mVerticeBuffer.asFloatBuffer().put(vert); mVerticeBuffer.position(0); if (mCoordBuffer == null) { mCoordBuffer = ByteBuffer.allocateDirect(coordVertices.length * 4); mCoordBuffer.order(ByteOrder.nativeOrder()); mCoordBuffer.asFloatBuffer().put(coordVertices); mCoordBuffer.position(0); } } private void checkGlError(String op) { int error; while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { // throw new RuntimeException(op + ": glError " + error); } } }