1 // Copyright 2011 Google Inc. All Rights Reserved.
2 
3 package com.example.android.videochatcameratest;
4 
5 import android.content.Context;
6 import android.graphics.SurfaceTexture;
7 import android.graphics.SurfaceTexture.OnFrameAvailableListener;
8 import android.opengl.GLES20;
9 import android.opengl.GLSurfaceView;
10 import android.util.AttributeSet;
11 import android.util.Log;
12 
13 import java.nio.ByteBuffer;
14 import java.nio.ByteOrder;
15 import java.nio.FloatBuffer;
16 import java.util.concurrent.atomic.AtomicBoolean;
17 import java.util.concurrent.atomic.AtomicInteger;
18 
19 import javax.microedition.khronos.egl.EGLConfig;
20 import javax.microedition.khronos.opengles.GL10;
21 
22 class SurfaceTextureView extends GLSurfaceView {
23     static final private String TAG = "VideoChatTest";
24 
25     private int mTextureName;
26     private SurfaceTexture mSurfaceTexture;
getTextureName()27     public int getTextureName() {
28         return mTextureName;
29     }
getSurfaceTexture()30     public SurfaceTexture getSurfaceTexture() {
31         return mSurfaceTexture;
32     }
33 
loadShader(int shaderType, String source)34     public static int loadShader(int shaderType, String source) {
35         int shader = GLES20.glCreateShader(shaderType);
36         if (shader != 0) {
37             GLES20.glShaderSource(shader, source);
38             GLES20.glCompileShader(shader);
39             int[] compiled = new int[1];
40             GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
41             if (compiled[0] == 0) {
42                 Log.e(TAG, "Could not compile shader " + shaderType + ":");
43                 Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
44                 GLES20.glDeleteShader(shader);
45                 shader = 0;
46             }
47         }
48         return shader;
49     }
50 
checkGlError(String op)51     public static void checkGlError(String op) {
52         int error;
53         while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
54             Log.e(TAG, op + ": glError " + error);
55             throw new RuntimeException(op + ": glError " + error);
56         }
57     }
58 
createProgram(String vertexSource, String fragmentSource)59     public static int createProgram(String vertexSource, String fragmentSource) {
60         int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
61         if (vertexShader == 0) {
62             return 0;
63         }
64         int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
65         if (pixelShader == 0) {
66             return 0;
67         }
68 
69         int program = GLES20.glCreateProgram();
70         if (program != 0) {
71             GLES20.glAttachShader(program, vertexShader);
72             checkGlError("glAttachShader");
73             GLES20.glAttachShader(program, pixelShader);
74             checkGlError("glAttachShader");
75             GLES20.glLinkProgram(program);
76             int[] linkStatus = new int[1];
77             GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
78             if (linkStatus[0] != GLES20.GL_TRUE) {
79                 Log.e(TAG, "Could not link program: ");
80                 Log.e(TAG, GLES20.glGetProgramInfoLog(program));
81                 GLES20.glDeleteProgram(program);
82                 program = 0;
83             }
84         }
85         return program;
86     }
87 
88     AtomicInteger mReportedFrameCount = new AtomicInteger();
89     AtomicBoolean mCameraEnabled = new AtomicBoolean();
90     AtomicInteger mCameraFrameCount = new AtomicInteger();
91 
92     /**
93      * @param context
94      */
SurfaceTextureView(Context context)95     public SurfaceTextureView(Context context) {
96         super(context);
97         init();
98     }
99 
SurfaceTextureView(Context context, AttributeSet attrs)100     public SurfaceTextureView(Context context, AttributeSet attrs) {
101         super(context, attrs);
102         init();
103     }
104 
init()105     private void init() {
106         setEGLContextClientVersion(2);
107         setRenderer(new Renderer());
108     }
109 
setCameraEnabled(boolean enabled)110     public void setCameraEnabled(boolean enabled) {
111         mCameraEnabled.set(enabled);
112     }
113 
resetFrameCounter()114     public void resetFrameCounter() {
115         mReportedFrameCount.set(0);
116     }
117 
getFrameCounter()118     public int getFrameCounter() {
119         return mReportedFrameCount.get();
120     }
121 
122     class Renderer implements GLSurfaceView.Renderer {
123         private final static String VERTEX_SHADER =
124             "attribute vec4 vPosition;\n" +
125             "attribute vec2 a_texCoord;\n" +
126             "varying vec2 v_texCoord;\n" +
127             "uniform mat4 u_xform;\n" +
128             "void main() {\n" +
129             "  gl_Position = vPosition;\n" +
130             "  v_texCoord = vec2(u_xform * vec4(a_texCoord, 1.0, 1.0));\n" +
131             "}\n";
132 
133         private final static String FRAGMENT_SHADER =
134             "#extension GL_OES_EGL_image_external : require\n" +
135             "precision mediump float;\n" +
136             "uniform samplerExternalOES s_texture;\n" +
137             "varying vec2 v_texCoord;\n" +
138             "void main() {\n" +
139             "  gl_FragColor = texture2D(s_texture, v_texCoord);\n" +
140             "}\n";
141 
142         private final float[] TEXTURE_VERTICES =
143             { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f };
144 
145         private final float[] QUAD_VERTICES =
146             { 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f };
147 
148         private final static int FLOAT_SIZE_BYTES = 4;
149 
150         private final FloatBuffer mTextureVertices;
151         private final FloatBuffer mQuadVertices;
152 
153 
154         private int mGLProgram;
155         private int mTexHandle;
156         private int mTexCoordHandle;
157         private int mTriangleVerticesHandle;
158         private int mTransformHandle;
159         private int mViewWidth;
160         private int mViewHeight;
161         private float[] mTransformMatrix;
162         private int mLastCameraFrameCount;
Renderer()163         public Renderer() {
164             mTextureVertices = ByteBuffer.allocateDirect(TEXTURE_VERTICES.length *
165                     FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
166             mTextureVertices.put(TEXTURE_VERTICES).position(0);
167             mQuadVertices = ByteBuffer.allocateDirect(QUAD_VERTICES.length *
168                     FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
169             mQuadVertices.put(QUAD_VERTICES).position(0);
170             mTransformMatrix = new float[16];
171             mLastCameraFrameCount = mCameraFrameCount.get();
172         }
173 
174         @Override
onSurfaceCreated(GL10 gl, EGLConfig config)175         public void onSurfaceCreated(GL10 gl, EGLConfig config) {
176             mGLProgram = createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
177 
178             mTexHandle = GLES20.glGetUniformLocation(mGLProgram, "s_texture");
179             mTexCoordHandle = GLES20.glGetAttribLocation(mGLProgram, "a_texCoord");
180             mTriangleVerticesHandle = GLES20.glGetAttribLocation(mGLProgram, "vPosition");
181             mTransformHandle = GLES20.glGetUniformLocation(mGLProgram, "u_xform");
182             int[] textures = new int[1];
183             GLES20.glGenTextures(1, textures, 0);
184             mTextureName = textures[0];
185             GLES20.glUseProgram(mGLProgram);
186             GLES20.glVertexAttribPointer(mTexCoordHandle, 2, GLES20.GL_FLOAT,
187                     false, 0, mTextureVertices);
188             GLES20.glVertexAttribPointer(mTriangleVerticesHandle, 2, GLES20.GL_FLOAT,
189                     false, 0, mQuadVertices);
190             checkGlError("initialization");
191             mSurfaceTexture = new SurfaceTexture(mTextureName);
192             mSurfaceTexture.setOnFrameAvailableListener(new OnFrameAvailableListener() {
193                 @Override
194                 public void onFrameAvailable(SurfaceTexture surfaceTexture) {
195                     mCameraFrameCount.incrementAndGet();
196                 }
197             });
198         }
199 
200         /* (non-Javadoc)
201          * @see android.opengl.GLSurfaceView.Renderer#onSurfaceChanged(javax.microedition.khronos.opengles.GL10, int, int)
202          */
203         @Override
onSurfaceChanged(GL10 gl, int width, int height)204         public void onSurfaceChanged(GL10 gl, int width, int height) {
205             mViewWidth = width;
206             mViewHeight = height;
207         }
208 
209         private static final int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
210         @Override
onDrawFrame(GL10 gl)211         public void onDrawFrame(GL10 gl) {
212             GLES20.glUseProgram(mGLProgram);
213             GLES20.glViewport(0, 0, mViewWidth, mViewHeight);
214             checkGlError("glViewport");
215 
216             if (mCameraEnabled.get()) {
217                 int cameraFrameCount = mCameraFrameCount.get();
218                 if (mLastCameraFrameCount != cameraFrameCount) {
219                     mReportedFrameCount.incrementAndGet();
220                     mSurfaceTexture.updateTexImage();
221                     mSurfaceTexture.getTransformMatrix(mTransformMatrix);
222                     GLES20.glUniformMatrix4fv(mTransformHandle, 1, false, mTransformMatrix, 0);
223                     checkGlError("glUniformMatrix4fv");
224                     mLastCameraFrameCount = cameraFrameCount;
225                 }
226                 GLES20.glDisable(GLES20.GL_BLEND);
227                 checkGlError("setup");
228                 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
229                 checkGlError("setup");
230                 GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureName);
231                 checkGlError("setup");
232                 GLES20.glUniform1i(mTexHandle, 0);
233                 checkGlError("setup");
234                 GLES20.glEnableVertexAttribArray(mTexCoordHandle);
235                 checkGlError("setup");
236                 GLES20.glEnableVertexAttribArray(mTriangleVerticesHandle);
237                 checkGlError("setup");
238                 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
239                 checkGlError("glDrawArrays");
240             } else {
241                 GLES20.glClearColor(0,0,0,0);
242             }
243         }
244 
245     }
246 }
247