gt:             int[] linkStatus = new int[1];
context: package moremote.surface;
  
  import android.opengl.GLES20;
  import android.util.Log;
  
  import java.nio.Buffer;
  import java.nio.ByteBuffer;
  import java.nio.ByteOrder;
  
  /**
   * Created by Ray on 2015/3/6.
   */
  public class GLProgram {
      static final String TAG="OpenGL";
      private boolean isProgBuilt=false;
      public GLProgram(){
          _video_width = 1280;
          _video_height = 720;
      }
  
  
      public boolean isProgramBuilt() {
          return isProgBuilt;
      }
      float[] _vertices = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, };
      int _program;
      int _positionHandle;
      int _coordHandle;
      int _yhandle;
      int _uhandle;
      int _vhandle;
      public void buildProgram() {
  
          createBuffers(_vertices, coordVertices);
          Log.e(TAG, "after build program");
          if (_program <= 0) {
              _program = createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
          }
  //        Utils.LOGD("_program = " + _program);
  
          /*
           * get handle for "vPosition" and "a_texCoord"
           */
          _positionHandle = GLES20.glGetAttribLocation(_program, "vPosition");
  //        Utils.LOGD("_positionHandle = " + _positionHandle);
          checkGlError("glGetAttribLocation vPosition");
          if (_positionHandle == -1) {
              throw new RuntimeException("Could not get attribute location for vPosition");
          }
          _coordHandle = GLES20.glGetAttribLocation(_program, "a_texCoord");
  //        Utils.LOGD("_coordHandle = " + _coordHandle);
          checkGlError("glGetAttribLocation a_texCoord");
          if (_coordHandle == -1) {
              throw new RuntimeException("Could not get attribute location for a_texCoord");
          }
  
          /*
           * get uniform location for y/u/v, we pass data through these uniforms
           */
          _yhandle = GLES20.glGetUniformLocation(_program, "tex_y");
  //        Utils.LOGD("_yhandle = " + _yhandle);
          checkGlError("glGetUniformLocation tex_y");
          if (_yhandle == -1) {
              throw new RuntimeException("Could not get uniform location for tex_y");
          }
          _uhandle = GLES20.glGetUniformLocation(_program, "tex_u");
  //        Utils.LOGD("_uhandle = " + _uhandle);
          checkGlError("glGetUniformLocation tex_u");
          if (_uhandle == -1) {
              throw new RuntimeException("Could not get uniform location for tex_u");
          }
          _vhandle = GLES20.glGetUniformLocation(_program, "tex_v");
  //        Utils.LOGD("_vhandle = " + _vhandle);
          checkGlError("glGetUniformLocation tex_v");
          if (_vhandle == -1) {
              throw new RuntimeException("Could not get uniform location for tex_v");
          }
  
  
          int[] textures = new int[1];
          GLES20.glGenTextures(1, textures, 0);
          checkGlError("glGenTextures");
          _ytid = textures[0];
          Log.e("Ray", "glGenTextures Y = " + _ytid);
          GLES20.glGenTextures(1, textures, 0);
          checkGlError("glGenTextures");
          _utid = textures[0];
          Log.e("Ray", "glGenTextures U = " + _utid);
          GLES20.glGenTextures(1, textures, 0);
          checkGlError("glGenTextures");
          _vtid = textures[0];
          Log.e("Ray", "glGenTextures V = " + _vtid);
  
  
          isProgBuilt = true;
      }
  
      /**
       * build a set of textures, one for Y, one for U, and one for V.
       */
      int _video_width;
      int _video_height;
      int _ytid;
      int _utid;
      int _vtid;
      public void buildTextures(Buffer y, Buffer u, Buffer v, int width, int height) {
          boolean videoSizeChanged = (width != _video_width || height != _video_height);
          if (videoSizeChanged) {
              _video_width = width;
              _video_height = height;
  //            Utils.LOGD("buildTextures videoSizeChanged: w=" + _video_width + " h=" + _video_height);
          }
          int i=0;
          int j=0;
  
  //        Log.e(TAG, "ytid:" + _ytid + ", u=" + _utid + ", v=" + _vtid + ", sizechange: " + videoSizeChanged);
          // building texture for Y data
          if (_ytid < 0 || videoSizeChanged) {
              if (_ytid >= 0) {
  //                Utils.LOGD("glDeleteTextures Y");
                  GLES20.glDeleteTextures(1, new int[]{_ytid}, 0);
                  checkGlError("glDeleteTextures");
              }
              // GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
              int[] textures = new int[1];
              GLES20.glGenTextures(1, textures, 0);
              checkGlError("glGenTextures");
              _ytid = textures[0];
              Log.e(TAG, "glGenTextures Y = " + _ytid);
  
  //            Utils.LOGD("glGenTextures Y = " + _ytid);
          }
          GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, _ytid);
          checkGlError("glBindTexture");
          GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, _video_width, _video_height, 0,
                  GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, y);
          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);
  
          // building texture for U data
          if (_utid < 0 || videoSizeChanged) {
              if (_utid >= 0) {
  //                Utils.LOGD("glDeleteTextures U");
                  GLES20.glDeleteTextures(1, new int[]{_utid}, 0);
                  checkGlError("glDeleteTextures");
              }
              int[] textures = new int[1];
              GLES20.glGenTextures(1, textures, 0);
              checkGlError("glGenTextures");
              _utid = textures[0];
              Log.e(TAG, "glGenTextures U = " + _utid);
  //            Utils.LOGD("glGenTextures U = " + _utid);
          }
          GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, _utid);
          GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, _video_width / 2, _video_height / 2, 0,
                  GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, u);
          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);
  
          // building texture for V data
          if (_vtid < 0 || videoSizeChanged) {
              if (_vtid >= 0) {
  //                Utils.LOGD("glDeleteTextures V");
                  GLES20.glDeleteTextures(1, new int[]{_vtid}, 0);
                  checkGlError("glDeleteTextures");
              }
              int[] textures = new int[1];
              GLES20.glGenTextures(1, textures, 0);
              checkGlError("glGenTextures");
              _vtid = textures[0];
              Log.e(TAG, "glGenTextures V = " + _vtid);
  //            Utils.LOGD("glGenTextures V = " + _vtid);
          }
          GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, _vtid);
          GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, _video_width / 2, _video_height / 2, 0,
                  GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, v);
          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);
      }
  
      /**
       * render the frame
       * the YUV data will be converted to RGB by shader.
       */
      int _textureI = GLES20.GL_TEXTURE0;
      int _textureII = GLES20.GL_TEXTURE1;
      int _textureIII = GLES20.GL_TEXTURE2;
      int _tIindex = 0;
      int _tIIindex = 1;
      int _tIIIindex = 2;
  
      public void drawFrame() {
          GLES20.glUseProgram(_program);
          checkGlError("glUseProgram");
  
          GLES20.glVertexAttribPointer(_positionHandle, 2, GLES20.GL_FLOAT, false, 8, _vertice_buffer);
          checkGlError("glVertexAttribPointer mPositionHandle");
          GLES20.glEnableVertexAttribArray(_positionHandle);
  
          GLES20.glVertexAttribPointer(_coordHandle, 2, GLES20.GL_FLOAT, false, 8, _coord_buffer);
          checkGlError("glVertexAttribPointer maTextureHandle");
          GLES20.glEnableVertexAttribArray(_coordHandle);
  
          // bind textures
          GLES20.glActiveTexture(_textureI);
          GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, _ytid);
          GLES20.glUniform1i(_yhandle, _tIindex);
  
          GLES20.glActiveTexture(_textureII);
          GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, _utid);
          GLES20.glUniform1i(_uhandle, _tIIindex);
  
          GLES20.glActiveTexture(_textureIII);
          GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, _vtid);
          GLES20.glUniform1i(_vhandle, _tIIIindex);
  
          GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
          GLES20.glFinish();
  
          GLES20.glDisableVertexAttribArray(_positionHandle);
          GLES20.glDisableVertexAttribArray(_coordHandle);
      }
  
      /**
       * create program and load shaders, fragment shader is very important.
       */
      public int createProgram(String vertexSource, String fragmentSource) {
          // create shaders
          int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
          int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
          // just check
  //        Utils.LOGD("vertexShader = " + vertexShader);
  //        Utils.LOGD("pixelShader = " + pixelShader);
  
          int program = GLES20.glCreateProgram();
          if (program != 0) {
              GLES20.glAttachShader(program, vertexShader);
              checkGlError("glAttachShader");
              GLES20.glAttachShader(program, pixelShader);
              checkGlError("glAttachShader");
              GLES20.glLinkProgram(program);
  