Problema con la vista previa de la cámara Android de OpenGL

Estoy trabajando en una aplicación de cámara Android que modifica la alimentación de la cámara y la muestra en directo en la pantalla. Tengo que trabajar y hacer lo que quiero perfectamente en mi DROID RAZR MAXX corriendo 4.3, y funciona perfectamente en otros teléfonos, pero por desgracia me he topado con un problema en varios teléfonos y soy incapaz de rastrear el problema.

He adjuntado una captura de pantalla que muestra el problema.

Es muy difícil decir lo que los "artefactos" verdes son, pero casi parece que es bloques de la alimentación de la cámara de cuando se encendió por primera vez. Los colores parpadean, pero las formas dentro de los bloques no cambian realmente.

He eliminado todo lo que no es necesario y limpiado el código lo mejor que puedo, pero sinceramente no tengo ni idea de por qué esto está sucediendo, sobre todo porque parece que funciona en algunos teléfonos bien, mientras que otros teléfonos doesn T

¡Si necesito dar más información apenas comentario y lo agregaré!

CameraActivity.java

public class CameraActivity extends Activity { private MyGLSurfaceView glSurfaceView; private MyCamera mCamera; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCamera = new MyCamera(); glSurfaceView = new MyGLSurfaceView(this, mCamera); setContentView(glSurfaceView); } @Override protected void onPause() { super.onPause(); mCamera.stop(); } } 

MyCamera.java

 public class MyCamera { private final static String LOG_TAG = "MyCamera"; private Camera mCamera; private Parameters mCameraParams; private Boolean running = false; void start(SurfaceTexture surface) { Log.v(LOG_TAG, "Starting Camera"); mCamera = Camera.open(0); mCameraParams = mCamera.getParameters(); Log.v(LOG_TAG, mCameraParams.getPreviewSize().width + " x " + mCameraParams.getPreviewSize().height); try { mCamera.setPreviewTexture(surface); mCamera.startPreview(); running = true; } catch (IOException e) { e.printStackTrace(); } } void stop() { if (running) { Log.v(LOG_TAG, "Stopping Camera"); mCamera.stopPreview(); mCamera.release(); running = false; } } } 

MyGLSurfaceView.java

 class MyGLSurfaceView extends GLSurfaceView implements Renderer { private final static String LOG_TAG = "MyGLSurfaceView"; private MyCamera mCamera; private SurfaceTexture mSurface; private DirectVideo mDirectVideo; public MyGLSurfaceView(Context context, MyCamera camera) { super(context); mCamera = camera; setEGLContextClientVersion(2); setRenderer(this); } @Override public void onDrawFrame(GL10 gl) { float[] mtx = new float[16]; mSurface.updateTexImage(); mSurface.getTransformMatrix(mtx); mDirectVideo.draw(); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { Log.v(LOG_TAG, "Surface Changed"); GLES20.glViewport(0, 0, width, height); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { Log.v(LOG_TAG, "Surface Created"); int texture = createTexture(); mDirectVideo = new DirectVideo(texture); mSurface = new SurfaceTexture(texture); mCamera.start(mSurface); } private int createTexture() { int[] textures = new int[1]; // generate one texture pointer and bind it as an external texture. GLES20.glGenTextures(1, textures, 0); GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]); // No mip-mapping with camera source. GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); // Clamp to edge is only option. GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); return textures[0]; } public static int loadShader(int type, String shaderCode){ // create a vertex shader type (GLES20.GL_VERTEX_SHADER) // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER) int shader = GLES20.glCreateShader(type); // add the source code to the shader and compile it GLES20.glShaderSource(shader, shaderCode); GLES20.glCompileShader(shader); return shader; } } 

DirectVideo.java

 public class DirectVideo { private final String vertexShaderCode = "attribute vec4 vPosition;" + "attribute vec2 inputTextureCoordinate;" + "varying vec2 textureCoordinate;" + "void main()" + "{"+ "gl_Position = vPosition;"+ "textureCoordinate = inputTextureCoordinate;" + "}"; private final String fragmentShaderCode = "#extension GL_OES_EGL_image_external : require\n"+ "precision mediump float;" + "varying vec2 textureCoordinate;\n" + "uniform samplerExternalOES s_texture;\n" + "void main() {" + " gl_FragColor = texture2D( s_texture, textureCoordinate );\n" + "}"; private FloatBuffer vertexBuffer, textureVerticesBuffer; private ShortBuffer drawListBuffer; private final int mProgram; private int mPositionHandle; private int mTextureCoordHandle; private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices // number of coordinates per vertex in this array private static final int COORDS_PER_VERTEX = 2; private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex static float squareCoords[] = { -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, }; static float textureVertices[] = { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, }; private int texture; public DirectVideo(int texture) { this.texture = texture; // initialize vertex byte buffer for shape coordinates ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4); bb.order(ByteOrder.nativeOrder()); vertexBuffer = bb.asFloatBuffer(); vertexBuffer.put(squareCoords); vertexBuffer.position(0); // initialize byte buffer for the draw list ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2); dlb.order(ByteOrder.nativeOrder()); drawListBuffer = dlb.asShortBuffer(); drawListBuffer.put(drawOrder); drawListBuffer.position(0); ByteBuffer bb2 = ByteBuffer.allocateDirect(textureVertices.length * 4); bb2.order(ByteOrder.nativeOrder()); textureVerticesBuffer = bb2.asFloatBuffer(); textureVerticesBuffer.put(textureVertices); textureVerticesBuffer.position(0); int vertexShader = MyGLSurfaceView.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); int fragmentShader = MyGLSurfaceView.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode); mProgram = GLES20.glCreateProgram(); // create empty OpenGL ES Program GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program GLES20.glLinkProgram(mProgram); // creates OpenGL ES program executables } public void draw() { GLES20.glUseProgram(mProgram); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture); // get handle to vertex shader's vPosition member mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition"); // Enable a handle to the triangle vertices GLES20.glEnableVertexAttribArray(mPositionHandle); // Prepare the <insert shape here> coordinate data GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer); mTextureCoordHandle = GLES20.glGetAttribLocation(mProgram, "inputTextureCoordinate"); GLES20.glEnableVertexAttribArray(mTextureCoordHandle); GLES20.glVertexAttribPointer(mTextureCoordHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, textureVerticesBuffer); GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer); // Disable vertex array GLES20.glDisableVertexAttribArray(mPositionHandle); GLES20.glDisableVertexAttribArray(mTextureCoordHandle); } } 

En el método onDrawFrame obtiene una matriz de transformación, pero no la usa. Esta matriz debe utilizarse para transformar las coordenadas de textura. Para más detalles, consulte la documentación de la clase SurfaceTexture .

Aquí está la solución:

  1. Pasar la matriz al método de dibujo:

     @Override public void onDrawFrame(GL10 gl) { float[] mtx = new float[16]; mSurface.updateTexImage(); mSurface.getTransformMatrix(mtx); mDirectVideo.draw(mtx); } 
  2. Agregue el siguiente método a la clase DirectVideo:

      private float[] transformTextureCoordinates( float[] coords, float[] matrix) { float[] result = new float[ coords.length ]; float[] vt = new float[4]; for ( int i = 0 ; i < coords.length ; i += 2 ) { float[] v = { coords[i], coords[i+1], 0 , 1 }; Matrix.multiplyMV(vt, 0, matrix, 0, v, 0); result[i] = vt[0]; result[i+1] = vt[1]; } return result; } 
  3. En el método de dibujo Convierta la lista textureVertices antes de añadir al búfer (debe hacer esta conversión en cada pintura ya que la matriz puede cambiar):

     textureVerticesBuffer.clear(); textureVerticesBuffer.put( transformTextureCoordinates( textureVertices, mtx )); textureVerticesBuffer.position(0); 

Una solución alternativa es si pasas la matriz al shader.

 implements SurfaceTexture.OnFrameAvailableListener @Override public void onFrameAvailable(SurfaceTexture surfaceTexture) { // TODO Auto-generated method stub } setOnFrameAvailableListener(this); 
  • Openg GL 2.0 error de Android 0x501 (GL_INVALID_VALUE)
  • Android NDK - OpenGL ES Tutorial / Bibliotecas
  • ¿cuál es el propósito de onSurfaceChanged?
  • Compensaciones para datos por vértice intercalados en OpenGL ES en Android
  • Portar un juego iPhone a Android - Texturas y búferes
  • Convertir matriz de int en Bitmap en Android
  • Cómo detectar el clic en un objeto en OpenGL ES en la aplicación de Android?
  • Conceptos básicos de NDK y OpenGL en android
  • ¿Cuándo debemos utilizar LAYER_TYPE_HARDWARE
  • OpenGL ES tutorial para android no parece funcionar
  • Juego opengl android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.