ManActivity.java:
public class MainActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener, MediaPlayer.OnPreparedListener { // public String videoPath = "/sdcard/DCIM/Camera/VID_20160718_153206.mp4";//Environment.getExternalStorageDirectory().getPath(); public String videoPath = Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/VID_20160718_153206.mp4"; private TextureView textureView; private MediaPlayer mediaPlayer; private TextureSurfaceRenderer videoRenderer; private int surfaceWidth; private int surfaceHeight; private Surface surface; public native int getValue(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textureView = (TextureView) findViewById(R.id.id_textureview); textureView.setSurfaceTextureListener(this); } private boolean bReadSDCard() { boolean state = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); return state; } private void playVideo(SurfaceTexture surfaceTexture) { if (mediaPlayer == null) { videoRenderer = new VideoTextureSurfaceRenderer(this, surfaceTexture, surfaceWidth, surfaceHeight); // surface = new Surface(videoRenderer.getSurfaceTexture()); initMediaPlayer(); } } private boolean bFileExist() { return true; } private void initMediaPlayer() { bReadSDCard(); this.mediaPlayer = new MediaPlayer(); try { while (videoRenderer.getSurfaceTexture() == null) { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } } Surface surface = new Surface(videoRenderer.getSurfaceTexture()); mediaPlayer.setDataSource(videoPath); mediaPlayer.setSurface(surface); surface.release(); mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(this); mediaPlayer.setLooping(true); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } @Override public void onPrepared(MediaPlayer mp) { try { if (mp != null) { mp.start(); } } catch (IllegalStateException e) { e.printStackTrace(); } } @Override protected void onResume() { super.onResume(); if (textureView.isAvailable()) { // playVideo(); } } @Override protected void onStart() { super.onStart();// ATTENTION: This was auto-generated to implement the App Indexing API. } @Override protected void onPause() { super.onPause(); if (videoRenderer != null) { videoRenderer.onPause(); videoRenderer = null; } if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; } } @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { surfaceWidth = width; surfaceHeight = height; playVideo(surface); } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } @Override public void onStop() { super.onStop();// ATTENTION: This was auto-generated to implement the App Indexing API. } } TextureSurfaceRenderer.java:public abstract class TextureSurfaceRenderer implements Runnable { public static String LOG_TAG = TextureSurfaceRenderer.class.getSimpleName(); protected final SurfaceTexture surfaceTexture; protected int width; protected int height; private EGL10 egl; private EGLContext eglContext; private EGLDisplay eglDisplay; private EGLSurface eglSurface; private boolean running = false; public TextureSurfaceRenderer(SurfaceTexture surfaceTexture,int width,int height){ this.surfaceTexture = surfaceTexture; this.width = width; this.height = height; this.running = true; Thread thread = new Thread(this); thread.start(); } private void initEGL(){ egl = (EGL10)EGLContext.getEGL(); eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); int version[] = new int[2]; egl.eglInitialize(eglDisplay,version); EGLConfig eglConfig = chooseEglConfig(); eglSurface = egl.eglCreateWindowSurface(eglDisplay,eglConfig,surfaceTexture,null); eglContext = createContext(egl,eglDisplay,eglConfig); try{ if(eglSurface == null || eglSurface == EGL10.EGL_NO_SURFACE){ throw new RuntimeException("GL error"); } if(!egl.eglMakeCurrent(eglDisplay,eglSurface,eglSurface,eglContext)){ throw new RuntimeException("MAKE CURRENT ERROR"); } }catch(Exception e){ e.printStackTrace(); } } @Override public void run(){ initEGL(); initGLComponents(); while (running){ if(draw()){ egl.eglSwapBuffers(eglDisplay,eglSurface); } } deinitGLComponents(); deinitEGL(); } private void deinitEGL(){ egl.eglMakeCurrent(eglDisplay,EGL10.EGL_NO_SURFACE,EGL10.EGL_NO_SURFACE,EGL10.EGL_NO_CONTEXT); egl.eglDestroySurface(eglDisplay,eglSurface); egl.eglDestroyContext(eglDisplay,eglContext); egl.eglTerminate(eglDisplay); } protected abstract boolean draw(); protected abstract void initGLComponents(); protected abstract void deinitGLComponents(); public abstract SurfaceTexture getSurfaceTexture(); private EGLContext createContext(EGL10 egl,EGLDisplay eglDisplay,EGLConfig eglconfig){ int[] attrs = { EGL14.EGL_CONTEXT_CLIENT_VERSION,2, EGL10.EGL_NONE }; return egl.eglCreateContext(eglDisplay,eglconfig,EGL10.EGL_NO_CONTEXT,attrs); } private EGLConfig chooseEglConfig(){ int[] configsCount = new int[1]; EGLConfig[] configs = new EGLConfig[1]; int[] attributes = getAttributes(); int confSize = 1; if(!egl.eglChooseConfig(eglDisplay,attributes,configs,confSize,configsCount)){ throw new IllegalArgumentException("failed to choose config"); }else if(configsCount[0]>0){ return configs[0]; } return null; } private int[] getAttributes(){ return new int[]{ EGL10.EGL_RENDERABLE_TYPE,EGL14.EGL_OPENGL_ES2_BIT, EGL10.EGL_RED_SIZE,8, EGL10.EGL_GREEN_SIZE, 8, EGL10.EGL_BLUE_SIZE, 8, EGL10.EGL_ALPHA_SIZE, 8, EGL10.EGL_DEPTH_SIZE, 0, EGL10.EGL_STENCIL_SIZE, 0, EGL10.EGL_NONE //总是以EGL10.EGL_NONE结尾 }; } public void onPause() { running = false; } @Override protected void finalize() throws Throwable{ super.finalize(); running = false; } }
VideoTextureSurfaceRenderer.java:public class VideoTextureSurfaceRenderer extends TextureSurfaceRenderer implements SurfaceTexture.OnFrameAvailableListener { public static final String TAG = VideoTextureSurfaceRenderer.class.getSimpleName(); private static float squareSize = 1.0f; private static float squareCoords[] = { -squareSize,squareSize,0.0f, -squareSize,-squareSize,0.0f, squareSize,-squareSize,0.0f, squareSize,squareSize,0.0f }; private static short drawOrder[] = { 0,1,2, 0,2,3 }; private FloatBuffer textureBuffer; private float textureCoords[] = { 0.0f,1.0f,0.0f,1.0f, 0.0f,0.0f,0.0f,1.0f, 1.0f,0.0f,0.0f,1.0f, 1.0f,1.0f,0.0f,1.0f, }; private int[] textures = new int[1]; private int shaderProgram; private FloatBuffer vertexBuffer; private ShortBuffer drawOrderBuffer; private float[] videoTextureTransform; private boolean frameAvailable = false; private Context context; private SurfaceTexture videoTexture; public VideoTextureSurfaceRenderer(Context context,SurfaceTexture texture,int width,int height){ super(texture,width,height); this.context = context; videoTextureTransform = new float[16]; } @Override protected void initGLComponents(){ setupVertexBuffer(); setupTexture(); loadShaders(); } @Override protected void deinitGLComponents() { GLES20.glDeleteTextures(1, textures, 0); GLES20.glDeleteProgram(shaderProgram); videoTexture.release(); videoTexture.setOnFrameAvailableListener(null); } @Override public SurfaceTexture getSurfaceTexture(){ return videoTexture; } @Override public void onFrameAvailable(SurfaceTexture surfaceTexture) { synchronized (this) { frameAvailable = true; } } private void setupVertexBuffer(){ ByteBuffer orderByteBuffer = ByteBuffer.allocateDirect(drawOrder.length*2); orderByteBuffer.order(ByteOrder.nativeOrder()); drawOrderBuffer = orderByteBuffer.asShortBuffer(); drawOrderBuffer.put(drawOrder); drawOrderBuffer.position(0); ByteBuffer bf = ByteBuffer.allocateDirect(squareCoords.length*4); bf.order(ByteOrder.nativeOrder()); vertexBuffer = bf.asFloatBuffer(); vertexBuffer.put(squareCoords); vertexBuffer.position(0); } private void setupTexture(){ ByteBuffer texture = ByteBuffer.allocateDirect(textureCoords.length*4); texture.order(ByteOrder.nativeOrder()); textureBuffer = texture.asFloatBuffer(); textureBuffer.put(textureCoords); textureBuffer.position(0); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glGenTextures(1,textures,0); GLES20.glBindTexture(GLES11Ext.GL_BLEND_EQUATION_RGB_OES,textures[0]); videoTexture = new SurfaceTexture(textures[0]); videoTexture.setOnFrameAvailableListener(this); } private void loadShaders() { final String vertexShader = RawResourceReader.readTextFileFromRawResource(context, R.raw.vertext_sharder); final String fragmentShader = RawResourceReader.readTextFileFromRawResource(context, R.raw.fragment_sharder); final int vertexShaderHandle = ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, vertexShader); final int fragmentShaderHandle = ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader); shaderProgram = ShaderHelper.createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, new String[]{"texture","vPosition","vTexCoordinate","textureTransform"}); } @Override protected boolean draw() { synchronized (this) { if (frameAvailable) { videoTexture.updateTexImage(); videoTexture.getTransformMatrix(videoTextureTransform); frameAvailable = false; } else { return false; } } GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); GLES20.glViewport(0, 0, width, height); this.drawTexture(); return true; } private void drawTexture(){ // Draw texture GLES20.glUseProgram(shaderProgram); //绘制时使用着色程序 int textureParamHandle = GLES20.glGetUniformLocation(shaderProgram, "texture"); //返回一个于着色器程序中变量名为"texture"相关联的索引 int textureCoordinateHandle = GLES20.glGetAttribLocation(shaderProgram, "vTexCoordinate"); int positionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition"); int textureTransformHandle = GLES20.glGetUniformLocation(shaderProgram, "textureTransform"); //在用VertexAttribArray前必须先激活它 GLES20.glEnableVertexAttribArray(positionHandle); //指定positionHandle的数据值可以在什么地方访问。 vertexBuffer在内部(NDK)是个指针,指向数组的第一组值的内存 GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer); GLES20.glBindTexture(GLES20.GL_TEXTURE0, textures[0]); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); //指定一个当前的textureParamHandle对象为一个全局的uniform 变量 GLES20.glUniform1i(textureParamHandle, 0); GLES20.glEnableVertexAttribArray(textureCoordinateHandle); GLES20.glVertexAttribPointer(textureCoordinateHandle, 4, GLES20.GL_FLOAT, false, 0, textureBuffer); GLES20.glUniformMatrix4fv(textureTransformHandle, 1, false, videoTextureTransform, 0); //GLES20.GL_TRIANGLES(以无数小三角行的模式)去绘制出这个纹理图像 GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawOrderBuffer); GLES20.glDisableVertexAttribArray(positionHandle); GLES20.glDisableVertexAttribArray(textureCoordinateHandle); } }
RawResourceReader.java:public class RawResourceReader { public static String readTextFileFromRawResource(final Context context, final int resourceId) { final InputStream inputStream = context.getResources().openRawResource( resourceId); final InputStreamReader inputStreamReader = new InputStreamReader( inputStream); final BufferedReader bufferedReader = new BufferedReader( inputStreamReader); String nextLine; final StringBuilder body = new StringBuilder(); try { while ((nextLine = bufferedReader.readLine()) != null) { body.append(nextLine); body.append('\n'); } } catch (IOException e) { return null; } return body.toString(); } }
ShaderHelper.java:public class ShaderHelper { private static final String TAG = "ShaderHelper"; /** * Helper function to compile a shader. * * @param shaderType The shader type. * @param shaderSource The shader source code. * @return An OpenGL handle to the shader. */ public static int compileShader(final int shaderType, final String shaderSource) { int shaderHandle = GLES20.glCreateShader(shaderType); if (shaderHandle != 0) { // Pass in the shader source. GLES20.glShaderSource(shaderHandle, shaderSource); // Compile the shader. GLES20.glCompileShader(shaderHandle); // Get the compilation status. final int[] compileStatus = new int[1]; GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0); // If the compilation failed, delete the shader. if (compileStatus[0] == 0) { Log.e(TAG, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shaderHandle)); GLES20.glDeleteShader(shaderHandle); shaderHandle = 0; } } if (shaderHandle == 0) { throw new RuntimeException("Error creating shader."); } return shaderHandle; } /** * Helper function to compile and link a program. * * @param vertexShaderHandle An OpenGL handle to an already-compiled vertex shader. * @param fragmentShaderHandle An OpenGL handle to an already-compiled fragment shader. * @param attributes Attributes that need to be bound to the program. * @return An OpenGL handle to the program. */ public static int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes) { int programHandle = GLES20.glCreateProgram(); if (programHandle != 0) { // Bind the vertex shader to the program. GLES20.glAttachShader(programHandle, vertexShaderHandle); // Bind the fragment shader to the program. GLES20.glAttachShader(programHandle, fragmentShaderHandle); // Bind attributes if (attributes != null) { final int size = attributes.length; for (int i = 0; i < size; i++) { GLES20.glBindAttribLocation(programHandle, i, attributes[i]); } } // Link the two shaders together into a program. GLES20.glLinkProgram(programHandle); // Get the link status. final int[] linkStatus = new int[1]; GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0); // If the link failed, delete the program. if (linkStatus[0] == 0) { Log.e(TAG, "Error compiling program: " + GLES20.glGetProgramInfoLog(programHandle)); GLES20.glDeleteProgram(programHandle); programHandle = 0; } } if (programHandle == 0) { throw new RuntimeException("Error creating program."); } return programHandle; } }
TextureHelper.java:public class TextureHelper { public static int loadTexture(final Context context, final int resourceId) { final int[] textureHandle = new int[1]; GLES20.glGenTextures(1, textureHandle, 0); if (textureHandle[0] != 0) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inScaled = false; // No pre-scaling // Read in the resource final Bitmap bitmap = BitmapFactory.decodeResource( context.getResources(), resourceId, options); // Bind to the texture in OpenGL GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]); // Set filtering GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); // Load the bitmap into the bound texture. GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); // Recycle the bitmap, since its data has been loaded into OpenGL. bitmap.recycle(); } if (textureHandle[0] == 0) { throw new RuntimeException("Error loading texture."); } return textureHandle[0]; } }
/res/raw/fragment_sharder.glsl:#extension GL_OES_EGL_image_external : require precision mediump float; uniform samplerExternalOES texture; varying vec2 v_TexCoordinate; void main () { vec4 color = texture2D(texture, v_TexCoordinate); gl_FragColor = color; }/res/raw/vertext_sharder.glsl:attribute vec4 vPosition; attribute vec4 vTexCoordinate; uniform mat4 textureTransform; varying vec2 v_TexCoordinate; void main(){ v_TexCoordinate = (textureTransform * vTexCoordinate).xy; gl_Position = vPosition; }