package com.example.datalibrary.deptrum.openglhelper; import android.annotation.SuppressLint; import android.content.res.Resources; import android.media.MediaCodec; import android.media.MediaFormat; import android.opengl.GLES20; import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.IntBuffer; public class RGBRendThread extends BaseOpenglRenderThread implements SurfaceHolder.Callback { public RGBRendThread(String name, SurfaceView mSurfaceView) { super(name, mSurfaceView); tAG = RGBRendThread.class.getSimpleName(); setEGLContextClientVersion(2); mStanderDelta = 1000 / SFPS; } @Override protected void creatProgram() { GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); mGLGraphics = new GLGraphics(); if (!mGLGraphics.isProgramBuilt()) { mGLGraphics.buildProgram(); } GLES20.glEnable(GLES20.GL_DEPTH_TEST); GLES20.glEnable(GLES20.GL_CULL_FACE); } @Override protected void draw() { synchronized (this) { if (mLastFrameTime == 0) { mLastFrameTime = System.currentTimeMillis(); } else { long currentTime = System.currentTimeMillis(); long delta = currentTime - mLastFrameTime; if (delta < mStanderDelta) { try { sleep(mStanderDelta - delta); } catch (InterruptedException e) { e.printStackTrace(); } } mLastFrameTime = currentTime; } GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); if (mBufferImage != null || mIntBuffer != null) { if (mIntBuffer != null) { mIntBuffer.position(0); mGLGraphics.buildTextures(mIntBuffer, mFrameWidth, mFrameHeight, hasAlpha); } else if (mBufferImage != null) { mBufferImage.position(0); mGLGraphics.buildTextures(mBufferImage, mFrameWidth, mFrameHeight, hasAlpha); } } mGLGraphics.draw(); } } @Override public void surfaceCreated(SurfaceHolder holder) { super.surfaceCreated(holder); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { super.surfaceChanged(holder, format, width, height); GLES20.glViewport(0, 0, width, height); } public void update(ByteBuffer buffer, int width, int height) { if (mGLGraphics == null) { return; } mFrameWidth = width; mFrameHeight = height; mGLGraphics.setVertexData(null); mBufferImage = buffer; notifyDraw(); } public void update(int[] colors, int width, int height) { if (mGLGraphics == null) { return; } if (mIntBuffer == null) { mIntBuffer = ByteBuffer.allocateDirect(640 * 480 * 4).asIntBuffer(); } mFrameWidth = width; mFrameHeight = height; mGLGraphics.setVertexData(null); mIntBuffer.clear(); mIntBuffer.put(colors); notifyDraw(); } private GLGraphics mGLGraphics; private ByteBuffer mBufferImage; private IntBuffer mIntBuffer; private boolean bWork = true; private int mFrameWidth; private int mFrameHeight; private long mLastFrameTime = 0; private long mStanderDelta; private static final int SFPS = 25; public static class ShaderUtil { public static 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) { Log.e("ES20_ERROR", "Could not compile shader " + shaderType + ":"); Log.e("ES20_ERROR", GLES20.glGetShaderInfoLog(shader)); GLES20.glDeleteShader(shader); shader = 0; } } return shader; } public static int createProgram(String vertexSource, String fragmentSource) { int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); if (vertexShader == 0) { return 0; } int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); if (pixelShader == 0) { return 0; } 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) { Log.e("ES20_ERROR", "Could not link program: "); Log.e("ES20_ERROR", GLES20.glGetProgramInfoLog(program)); GLES20.glDeleteProgram(program); program = 0; } } return program; } public static void checkGlError(String op) { int error; while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { Log.e("ES20_ERROR", op + ": glError " + error); } } public static String loadFromAssetsFile(String fname, Resources r) { String result = null; try { InputStream in = r.getAssets().open(fname); int ch = 0; ByteArrayOutputStream baos = new ByteArrayOutputStream(); while ((ch = in.read()) != -1) { baos.write(ch); } byte[] buff = baos.toByteArray(); baos.close(); in.close(); result = new String(buff, "UTF-8"); result = result.replaceAll("\\r\\n", "\n"); } catch (Exception e) { e.printStackTrace(); } return result; } } public static class GLGraphics { private static float[] squareVertices = {-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f}; private static float[] coordVertices = {0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f}; private static final String VERTEX_SHADER = "attribute vec4 vPosition;\n" + "attribute vec2 a_texCoord;\n" + "varying vec2 tc;\n" + "void main() {\n" + "gl_Position = vPosition;\n" + "tc = a_texCoord;\n" + "}\n"; private static final String FRAGMENT_SHADER = "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 FloatBuffer mVertexBuffer; private FloatBuffer mColorBuffer; private ByteBuffer coordbuffer; private ByteBuffer verticebuffer; private int mVertexCount = -1; private int mProgram = 0; private int mTexture = 0; private int mIndex = 0; private int mPositionHandle = -1; private int mCoordHandle = -1; private int yhandle = -1; private int ytid = -1; private int mGraphWidth = -1; private int mGraphHeight = -1; private boolean isProgBuilt = false; public GLGraphics() { mTexture = GLES20.GL_TEXTURE0; createBuffers(); } private void createBuffers() { verticebuffer = ByteBuffer.allocateDirect(squareVertices.length * 4); verticebuffer.order(ByteOrder.nativeOrder()); verticebuffer.asFloatBuffer().put(squareVertices); verticebuffer.position(0); coordbuffer = ByteBuffer.allocateDirect(coordVertices.length * 4); coordbuffer.order(ByteOrder.nativeOrder()); coordbuffer.asFloatBuffer().put(coordVertices); coordbuffer.position(0); } public void setVertexData(float[] vertices) { if (vertices != null) { mVertexCount = vertices.length / 3; ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4); vbb.order(ByteOrder.nativeOrder()); mVertexBuffer = vbb.asFloatBuffer(); mVertexBuffer.put(vertices); mVertexBuffer.position(0); float[] colors = new float[mVertexCount * 4]; for (int i = 0; i < colors.length; i++) { if (i % 4 == 3) { colors[i] = 0; } else { colors[i] = 1; } } ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4); cbb.order(ByteOrder.nativeOrder()); mColorBuffer = cbb.asFloatBuffer(); mColorBuffer.put(colors); mColorBuffer.position(0); } } @SuppressLint("NewApi") public void draw() { GLES20.glUseProgram(mProgram); ShaderUtil.checkGlError("glUseProgram"); GLES20.glVertexAttribPointer(mPositionHandle, 2, GLES20.GL_FLOAT, false, 8, verticebuffer); ShaderUtil.checkGlError("glVertexAttribPointer mPositionHandle"); GLES20.glEnableVertexAttribArray(mPositionHandle); GLES20.glVertexAttribPointer(mCoordHandle, 2, GLES20.GL_FLOAT, false, 8, coordbuffer); ShaderUtil.checkGlError("glVertexAttribPointer maTextureHandle"); GLES20.glEnableVertexAttribArray(mCoordHandle); // bind textures GLES20.glActiveTexture(mTexture); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, ytid); GLES20.glUniform1i(yhandle, mIndex); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); GLES20.glDisableVertexAttribArray(mPositionHandle); GLES20.glDisableVertexAttribArray(mCoordHandle); } public boolean isProgramBuilt() { return isProgBuilt; } @SuppressLint("NewApi") public void buildProgram() { if (mProgram <= 0) { mProgram = ShaderUtil.createProgram(VERTEX_SHADER, FRAGMENT_SHADER); } mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition"); ShaderUtil.checkGlError("glGetAttribLocation vPosition"); if (mPositionHandle == -1) { throw new RuntimeException("Could not get attribute location for vPosition"); } mCoordHandle = GLES20.glGetAttribLocation(mProgram, "a_texCoord"); ShaderUtil.checkGlError("glGetAttribLocation a_texCoord"); if (mCoordHandle == -1) { throw new RuntimeException("Could not get attribute location for a_texCoord"); } yhandle = GLES20.glGetUniformLocation(mProgram, "tex_y"); ShaderUtil.checkGlError("glGetUniformLocation tex_y"); if (yhandle == -1) { throw new RuntimeException("Could not get uniform location for tex_y"); } isProgBuilt = true; } @SuppressLint("NewApi") public void buildTextures(Buffer rgbBuffer, int width, int height, boolean hasAlpha) { boolean videoSizeChanged = (width != mGraphWidth || height != mGraphHeight); if (videoSizeChanged) { mGraphWidth = width; mGraphHeight = height; } if (ytid < 0 || videoSizeChanged) { if (ytid >= 0) { GLES20.glDeleteTextures(1, new int[]{ytid}, 0); ShaderUtil.checkGlError("glDeleteTextures"); } int[] textures = new int[1]; GLES20.glGenTextures(1, textures, 0); ShaderUtil.checkGlError("glGenTextures"); ytid = textures[0]; } GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, ytid); ShaderUtil.checkGlError("glBindTexture"); GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, hasAlpha ? GLES20.GL_RGBA : GLES20.GL_RGB, mGraphWidth, mGraphHeight, 0, hasAlpha ? GLES20.GL_RGBA : GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, rgbBuffer); 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 buildTextures(Buffer rgbBuffer, int width, int height) { buildTextures(rgbBuffer, width, height, false); } } public static class DecodePanel { private MediaCodec mCodec; public DecodePanel() { } public void initDecoder(Surface surface, int width, int height) { // init decoder try { mCodec = MediaCodec.createDecoderByType("video/avc"); MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height); mCodec.configure(mediaFormat, surface, null, 0); mCodec.start(); } catch (IOException e) { e.printStackTrace(); } } public void stopDecoder() { // stop decoder if (mCodec != null) { mCodec.stop(); mCodec.release(); mCodec = null; } } public void paint(ByteBuffer bufferImage, long timeStamp) { // queue inputbuffer if (bufferImage != null) { try { int inputBufferIndex = mCodec.dequeueInputBuffer(1000); if (inputBufferIndex >= 0) { ByteBuffer[] inputBuffers = mCodec.getInputBuffers(); ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; inputBuffer.clear(); inputBuffer.put(bufferImage); mCodec.queueInputBuffer(inputBufferIndex, 0, bufferImage.capacity(), timeStamp, 0); } } catch (Exception e) { } } // release outputbuffer try { MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); int outputBufferIndex = mCodec.dequeueOutputBuffer(info, 1000); if (outputBufferIndex >= 0) { mCodec.releaseOutputBuffer(outputBufferIndex, info.size != 0); } } catch (Exception e) { } } } }