Home | History | Annotate | Download | only in videochatcameratest
      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;
     27     public int getTextureName() {
     28         return mTextureName;
     29     }
     30     public SurfaceTexture getSurfaceTexture() {
     31         return mSurfaceTexture;
     32     }
     33 
     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 
     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 
     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      */
     95     public SurfaceTextureView(Context context) {
     96         super(context);
     97         init();
     98     }
     99 
    100     public SurfaceTextureView(Context context, AttributeSet attrs) {
    101         super(context, attrs);
    102         init();
    103     }
    104 
    105     private void init() {
    106         setEGLContextClientVersion(2);
    107         setRenderer(new Renderer());
    108     }
    109 
    110     public void setCameraEnabled(boolean enabled) {
    111         mCameraEnabled.set(enabled);
    112     }
    113 
    114     public void resetFrameCounter() {
    115         mReportedFrameCount.set(0);
    116     }
    117 
    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;
    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
    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
    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
    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