1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.nativecodec; 18 19 import android.graphics.SurfaceTexture; 20 import android.util.Log; 21 22 import java.nio.ByteBuffer; 23 import java.nio.ByteOrder; 24 import java.nio.FloatBuffer; 25 26 import javax.microedition.khronos.egl.EGLConfig; 27 import javax.microedition.khronos.opengles.GL10; 28 29 import android.content.Context; 30 import android.opengl.GLES20; 31 import android.opengl.GLSurfaceView; 32 import android.opengl.Matrix; 33 import android.os.SystemClock; 34 import android.util.AttributeSet; 35 36 public class MyGLSurfaceView extends GLSurfaceView { 37 38 MyRenderer mRenderer; 39 MyGLSurfaceView(Context context)40 public MyGLSurfaceView(Context context) { 41 this(context, null); 42 } 43 MyGLSurfaceView(Context context, AttributeSet attributeSet)44 public MyGLSurfaceView(Context context, AttributeSet attributeSet) { 45 super(context, attributeSet); 46 init(); 47 } 48 init()49 private void init() { 50 setEGLContextClientVersion(2); 51 mRenderer = new MyRenderer(); 52 setRenderer(mRenderer); 53 Log.i("@@@", "setrenderer"); 54 } 55 56 @Override onPause()57 public void onPause() { 58 mRenderer.onPause(); 59 super.onPause(); 60 } 61 62 @Override onResume()63 public void onResume() { 64 super.onResume(); 65 mRenderer.onResume(); 66 } 67 getSurfaceTexture()68 public SurfaceTexture getSurfaceTexture() { 69 return mRenderer.getSurfaceTexture(); 70 } 71 } 72 73 class MyRenderer implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener { 74 MyRenderer()75 public MyRenderer() { 76 mVertices = ByteBuffer.allocateDirect(mVerticesData.length 77 * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer(); 78 mVertices.put(mVerticesData).position(0); 79 80 Matrix.setIdentityM(mSTMatrix, 0); 81 } onPause()82 public void onPause() { 83 } 84 onResume()85 public void onResume() { 86 mLastTime = SystemClock.elapsedRealtimeNanos(); 87 } 88 89 @Override onDrawFrame(GL10 glUnused)90 public void onDrawFrame(GL10 glUnused) { 91 synchronized(this) { 92 if (updateSurface) { 93 mSurface.updateTexImage(); 94 95 mSurface.getTransformMatrix(mSTMatrix); 96 updateSurface = false; 97 } 98 } 99 100 // Ignore the passed-in GL10 interface, and use the GLES20 101 // class's static methods instead. 102 GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT); 103 GLES20.glUseProgram(mProgram); 104 checkGlError("glUseProgram"); 105 106 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 107 GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID); 108 109 mVertices.position(VERTICES_DATA_POS_OFFSET); 110 GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 111 VERTICES_DATA_STRIDE_BYTES, mVertices); 112 checkGlError("glVertexAttribPointer maPosition"); 113 GLES20.glEnableVertexAttribArray(maPositionHandle); 114 checkGlError("glEnableVertexAttribArray maPositionHandle"); 115 116 mVertices.position(VERTICES_DATA_UV_OFFSET); 117 GLES20.glVertexAttribPointer(maTextureHandle, 3, GLES20.GL_FLOAT, false, 118 VERTICES_DATA_STRIDE_BYTES, mVertices); 119 checkGlError("glVertexAttribPointer maTextureHandle"); 120 GLES20.glEnableVertexAttribArray(maTextureHandle); 121 checkGlError("glEnableVertexAttribArray maTextureHandle"); 122 123 long now = SystemClock.elapsedRealtimeNanos(); 124 mRunTime += (now - mLastTime); 125 mLastTime = now; 126 double d = ((double)mRunTime) / 1000000000; 127 Matrix.setIdentityM(mMMatrix, 0); 128 Matrix.rotateM(mMMatrix, 0, 30, (float)Math.sin(d), (float)Math.cos(d), 0); 129 Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0); 130 Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0); 131 132 GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0); 133 GLES20.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0); 134 135 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 136 checkGlError("glDrawArrays"); 137 } 138 139 @Override onSurfaceChanged(GL10 glUnused, int width, int height)140 public void onSurfaceChanged(GL10 glUnused, int width, int height) { 141 // Ignore the passed-in GL10 interface, and use the GLES20 142 // class's static methods instead. 143 GLES20.glViewport(0, 0, width, height); 144 mRatio = (float) width / height; 145 Matrix.frustumM(mProjMatrix, 0, -mRatio, mRatio, -1, 1, 3, 7); 146 } 147 148 @Override onSurfaceCreated(GL10 glUnused, EGLConfig config)149 public void onSurfaceCreated(GL10 glUnused, EGLConfig config) { 150 // Ignore the passed-in GL10 interface, and use the GLES20 151 // class's static methods instead. 152 153 /* Set up alpha blending and an Android background color */ 154 GLES20.glEnable(GLES20.GL_BLEND); 155 GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); 156 GLES20.glClearColor(0.643f, 0.776f, 0.223f, 1.0f); 157 158 /* Set up shaders and handles to their variables */ 159 mProgram = createProgram(mVertexShader, mFragmentShader); 160 if (mProgram == 0) { 161 return; 162 } 163 maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition"); 164 checkGlError("glGetAttribLocation aPosition"); 165 if (maPositionHandle == -1) { 166 throw new RuntimeException("Could not get attrib location for aPosition"); 167 } 168 maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord"); 169 checkGlError("glGetAttribLocation aTextureCoord"); 170 if (maTextureHandle == -1) { 171 throw new RuntimeException("Could not get attrib location for aTextureCoord"); 172 } 173 174 muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); 175 checkGlError("glGetUniformLocation uMVPMatrix"); 176 if (muMVPMatrixHandle == -1) { 177 throw new RuntimeException("Could not get attrib location for uMVPMatrix"); 178 } 179 180 muSTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uSTMatrix"); 181 checkGlError("glGetUniformLocation uSTMatrix"); 182 if (muMVPMatrixHandle == -1) { 183 throw new RuntimeException("Could not get attrib location for uSTMatrix"); 184 } 185 186 checkGlError("glGetUniformLocation uCRatio"); 187 if (muMVPMatrixHandle == -1) { 188 throw new RuntimeException("Could not get attrib location for uCRatio"); 189 } 190 191 /* 192 * Create our texture. This has to be done each time the 193 * surface is created. 194 */ 195 196 int[] textures = new int[1]; 197 GLES20.glGenTextures(1, textures, 0); 198 199 mTextureID = textures[0]; 200 GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID); 201 checkGlError("glBindTexture mTextureID"); 202 203 // Can't do mipmapping with camera source 204 GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, 205 GLES20.GL_NEAREST); 206 GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, 207 GLES20.GL_LINEAR); 208 // Clamp to edge is the only option 209 GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, 210 GLES20.GL_CLAMP_TO_EDGE); 211 GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, 212 GLES20.GL_CLAMP_TO_EDGE); 213 checkGlError("glTexParameteri mTextureID"); 214 215 /* 216 * Create the SurfaceTexture that will feed this textureID, and pass it to the camera 217 */ 218 219 mSurface = new SurfaceTexture(mTextureID); 220 mSurface.setOnFrameAvailableListener(this); 221 222 Matrix.setLookAtM(mVMatrix, 0, 0, 0, 4f, 0f, 0f, 0f, 0f, 1.0f, 0.0f); 223 224 synchronized(this) { 225 updateSurface = false; 226 } 227 } 228 229 @Override onFrameAvailable(SurfaceTexture surface)230 synchronized public void onFrameAvailable(SurfaceTexture surface) { 231 /* For simplicity, SurfaceTexture calls here when it has new 232 * data available. Call may come in from some random thread, 233 * so let's be safe and use synchronize. No OpenGL calls can be done here. 234 */ 235 updateSurface = true; 236 //Log.v(TAG, "onFrameAvailable " + surface.getTimestamp()); 237 } 238 loadShader(int shaderType, String source)239 private int loadShader(int shaderType, String source) { 240 int shader = GLES20.glCreateShader(shaderType); 241 if (shader != 0) { 242 GLES20.glShaderSource(shader, source); 243 GLES20.glCompileShader(shader); 244 int[] compiled = new int[1]; 245 GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); 246 if (compiled[0] == 0) { 247 Log.e(TAG, "Could not compile shader " + shaderType + ":"); 248 Log.e(TAG, GLES20.glGetShaderInfoLog(shader)); 249 GLES20.glDeleteShader(shader); 250 shader = 0; 251 } 252 } 253 return shader; 254 } 255 createProgram(String vertexSource, String fragmentSource)256 private int createProgram(String vertexSource, String fragmentSource) { 257 int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); 258 if (vertexShader == 0) { 259 return 0; 260 } 261 int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); 262 if (pixelShader == 0) { 263 return 0; 264 } 265 266 int program = GLES20.glCreateProgram(); 267 if (program != 0) { 268 GLES20.glAttachShader(program, vertexShader); 269 checkGlError("glAttachShader"); 270 GLES20.glAttachShader(program, pixelShader); 271 checkGlError("glAttachShader"); 272 GLES20.glLinkProgram(program); 273 int[] linkStatus = new int[1]; 274 GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); 275 if (linkStatus[0] != GLES20.GL_TRUE) { 276 Log.e(TAG, "Could not link program: "); 277 Log.e(TAG, GLES20.glGetProgramInfoLog(program)); 278 GLES20.glDeleteProgram(program); 279 program = 0; 280 } 281 } 282 return program; 283 } 284 checkGlError(String op)285 private void checkGlError(String op) { 286 int error; 287 while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { 288 Log.e(TAG, op + ": glError " + error); 289 throw new RuntimeException(op + ": glError " + error); 290 } 291 } 292 293 private static final int FLOAT_SIZE_BYTES = 4; 294 private static final int VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; 295 private static final int VERTICES_DATA_POS_OFFSET = 0; 296 private static final int VERTICES_DATA_UV_OFFSET = 3; 297 private final float[] mVerticesData = { 298 // X, Y, Z, U, V 299 -1.25f, -1.0f, 0, 0.f, 0.f, 300 1.25f, -1.0f, 0, 1.f, 0.f, 301 -1.25f, 1.0f, 0, 0.f, 1.f, 302 1.25f, 1.0f, 0, 1.f, 1.f, 303 }; 304 305 private FloatBuffer mVertices; 306 307 private final String mVertexShader = 308 "uniform mat4 uMVPMatrix;\n" + 309 "uniform mat4 uSTMatrix;\n" + 310 "attribute vec4 aPosition;\n" + 311 "attribute vec4 aTextureCoord;\n" + 312 "varying vec2 vTextureCoord;\n" + 313 "void main() {\n" + 314 " gl_Position = uMVPMatrix * aPosition;\n" + 315 " vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" + 316 "}\n"; 317 318 private final String mFragmentShader = 319 "#extension GL_OES_EGL_image_external : require\n" + 320 "precision mediump float;\n" + 321 "varying vec2 vTextureCoord;\n" + 322 "uniform samplerExternalOES sTexture;\n" + 323 "void main() {\n" + 324 " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" + 325 "}\n"; 326 327 private float[] mMVPMatrix = new float[16]; 328 private float[] mProjMatrix = new float[16]; 329 private float[] mMMatrix = new float[16]; 330 private float[] mVMatrix = new float[16]; 331 private float[] mSTMatrix = new float[16]; 332 333 private int mProgram; 334 private int mTextureID; 335 private int muMVPMatrixHandle; 336 private int muSTMatrixHandle; 337 private int maPositionHandle; 338 private int maTextureHandle; 339 340 private float mRatio = 1.0f; 341 private SurfaceTexture mSurface; 342 private boolean updateSurface = false; 343 private long mLastTime = -1; 344 private long mRunTime = 0; 345 346 private static final String TAG = "MyRenderer"; 347 348 // Magic key 349 private static final int GL_TEXTURE_EXTERNAL_OES = 0x8D65; 350 getSurfaceTexture()351 public SurfaceTexture getSurfaceTexture() { 352 return mSurface; 353 } 354 } 355