2015-05-04 25 views
13

Sto cercando di acquisire video e visualizzarlo sullo schermo impostando una trama Open GL ES su un android surfaceTexture. Non riesco a utilizzare uno TextureView e a implementare SurfaceTextureListener come da this tutorial poiché utilizzo Google Cardboard.Utilizzo del flusso video come aperto Struttura GL ES 2.0

Ho seguito the Android documentation su come inizializzare Open GL ES 2.0 e usarlo, e anche su this tutorial su texturing.

Mettendo insieme il 2 ottengo uno schermo vuoto e occasionalmente ottengo <core_glBindTexture:572>: GL_INVALID_OPERATION nella finestra della console.

Travolto da così tanti nuovi concetti che non conosco, non sono in grado di eseguire il debug o solo capire se è possibile utilizzare i due metodi in questo modo. Ecco il mio codice di disegno, è inizializzato nel onSurfaceCreated() della classe MainActivity e disegnato da onEyeDraw() che è la funzione di disegno di Cartone.

package com.example.rich.test3; 

import android.hardware.Camera; 
import android.opengl.GLES20; 
import android.view.TextureView; 

import java.nio.ShortBuffer; 
import java.nio.FloatBuffer; 
import java.nio.ByteBuffer; 
import java.nio.ByteOrder; 

/** 
* Created by rich on 03/05/2015. 
*/ 
public class Square { 

private java.nio.FloatBuffer vertexBuffer; 
private java.nio.ShortBuffer drawListBuffer; 
private final java.nio.FloatBuffer mCubeTextureCoordinates; 

float color[] = { 1.f, 1.f, 1.f, 1.0f }; 

private final String vertexShaderCode = 
     "attribute vec4 vPosition;" + 
     "attribute vec2 a_TexCoordinate;" + 
     "varying vec2 v_TexCoordinate;" + 
       "void main() {" + 
       " gl_Position = vPosition;" + 
       " v_TexCoordinate = a_TexCoordinate;" + 
       "}"; 

private final String fragmentShaderCode = 
     "precision mediump float;" + 
       "uniform vec4 vColor;" + 
       "uniform sampler2D u_Texture;" + 
       "varying vec2 v_TexCoordinate;" + 
       "void main() {" + 
       "gl_FragColor = (texture2D(u_Texture, v_TexCoordinate));" + 
       "}"; 

// number of coordinates per vertex in this array 
static final int COORDS_PER_VERTEX = 3; 
static float squareCoords[] = { 
     -0.5f, -0.5f, 0.0f, // bottom left 
     0.5f, -0.5f, 0.0f, // bottom right 
     -0.5f, 0.5f, 0.0f, // top left 
     0.5f, 0.5f, 0.0f}; // top right 

private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices 

private int mProgram; 

private int mPositionHandle; 
private int mColorHandle; 
private int mTextureUniformHandle; 
private int mTextureCoordinateHandle; 
private final int mTextureCoordinateDataSize = 2; 

private final int vertexCount = squareCoords.length/COORDS_PER_VERTEX; 
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex 

private int mTextureDataHandle; 

float textureCoordinates[] = 
     {0.0f, 1.0f, 
     1.0f, 1.0f, 
     0.0f, 0.0f, 
     1.0f, 0.0f }; 

Camera _camera; 
TextureView _textureView; 
int[] textures; 
android.graphics.SurfaceTexture _surface; 

public Square() 
{ 
    ByteBuffer bb = ByteBuffer.allocateDirect(
      // (# of coordinate values * 4 bytes per float) 
      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(
      // (# of coordinate values * 2 bytes per short) 
      drawOrder.length * 2); 
    dlb.order(ByteOrder.nativeOrder()); 
    drawListBuffer = dlb.asShortBuffer(); 
    drawListBuffer.put(drawOrder); 
    drawListBuffer.position(0); 

    mCubeTextureCoordinates = ByteBuffer.allocateDirect(textureCoordinates.length * 4) 
      .order(ByteOrder.nativeOrder()).asFloatBuffer(); 
    mCubeTextureCoordinates.put(textureCoordinates).position(0); 

    // create empty OpenGL ES Program 
    mProgram = GLES20.glCreateProgram(); 

    textures = new int[1]; 
    GLES20.glGenTextures(1, textures, 0); 

    _surface = new android.graphics.SurfaceTexture(textures[0]); 
    _camera = Camera.open(); 
    Camera.Size previewSize = _camera.getParameters().getPreviewSize(); 

    try 
    { 
     _camera.setPreviewTexture(_surface); 
    } 
    catch (java.io.IOException ex) 
    { 
     // Console.writeLine (ex.Message); 
    } 

    final int vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER); 
    GLES20.glShaderSource(vertexShaderHandle, vertexShaderCode); 
    GLES20.glCompileShader(vertexShaderHandle); 
    final int[] compileStatus = new int[1]; 
    GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 
    if (compileStatus[0] == 0) 
    { 
     //do check here 
    } 

    final int fragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER); 
    GLES20.glShaderSource(fragmentShaderHandle, fragmentShaderCode); 
    GLES20.glCompileShader(fragmentShaderHandle); 
    GLES20.glGetShaderiv(fragmentShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 
    if (compileStatus[0] == 0) 
    { 
     //do check here 
    } 

    GLES20.glAttachShader(mProgram, vertexShaderHandle); 
    GLES20.glAttachShader(mProgram, fragmentShaderHandle); 
    GLES20.glBindAttribLocation(mProgram, 0, "a_Position"); 
    GLES20.glBindAttribLocation(mProgram, 0, "a_TexCoordinate"); 

    GLES20.glLinkProgram(mProgram); 
    final int[] linkStatus = new int[1]; 
    GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0); 
    if (linkStatus[0] == 0) 
    { 
     //do check here 
    } 

    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); 
    mTextureDataHandle = textures[0]; 

    // Set filtering 
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); 
} 

public void draw() 
{ 
    _surface.updateTexImage(); 
    GLES20.glUseProgram(mProgram); 

    mTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture"); 
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "a_Position"); 
    mColorHandle = GLES20.glGetAttribLocation(mProgram, "a_Color"); 
    mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate"); 

    GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle); 

    GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, 
      GLES20.GL_FLOAT, false, 
      vertexStride, vertexBuffer); 
    GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 
      0, mCubeTextureCoordinates); 

    GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle); 
    GLES20.glEnableVertexAttribArray(mPositionHandle); 
    GLES20.glUniform1i(mTextureUniformHandle, 0); 

    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount); 
    GLES20.glDisableVertexAttribArray(mPositionHandle); 
} 

} 
+0

Hai trovato https://github.com/google/grafika? L'attività "trama dalla fotocamera" probabilmente fa la maggior parte di ciò che desideri. – fadden

risposta

7

Durante il rendering di un oggetto SurfaceTexture consistenza, è necessario utilizzare il target GL_TEXTURE_EXTERNAL_OES texture:

L'oggetto consistenza utilizza il bersaglio tessitura GL_TEXTURE_EXTERNAL_OES, che è definito dall'estensione GL_OES_EGL_image_external OpenGL ES. Questo limita il modo in cui la trama può essere utilizzata. Ogni volta che la trama viene vincolata, deve essere associata al target GL_TEXTURE_EXTERNAL_OES anziché al target GL_TEXTURE_2D. Inoltre, qualsiasi shader OpenGL ES 2.0 che campioni dalla texture deve dichiarare il proprio uso di questa estensione utilizzando, ad esempio, una direttiva "#extension GL_OES_EGL_image_external: require". Tali shader devono anche accedere alla trama usando il tipo sampler ESTERLYOES GLSL.

quindi è necessario cambiare il vostro Shader frammento in questo modo, aggiungendo la dichiarazione #extension e dichiarando la divisa texture come samplerExternalOES:

private final String fragmentShaderCode = 
    "#extension GL_OES_EGL_image_external : require\n" + 
    "precision mediump float;" + 
    "uniform vec4 vColor;" + 
    "uniform samplerExternalOES u_Texture;" + 
    "varying vec2 v_TexCoordinate;" + 
    "void main() {" + 
      "gl_FragColor = (texture2D(u_Texture, v_TexCoordinate));" + 
    "}"; 

anche nella funzione draw(), legano la trama in questo modo:

GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureDataHandle); 
+0

ha appena avuto la possibilità di provarlo e ottenere W/Adreno-ES20: : GL_INVALID_OPERATION –

+1

È possibile ottenere quell'errore se ci si lega a target diversi: https://www.khronos.org/opengles/sdk/ docs/man/xhtml/glBindTexture.xml si sta chiamando glBindTexture sia nel costruttore che in draw(), cambiandolo per utilizzare anche GLES11Ext.GL_TEXTURE_EXTERNAL_OES e anche – samgak

+0

ben individuato. Ora ottengo questo errore W/Adreno-ES20: : GL_INVALID_VALUE. google non sta inventando nulla. riesci a vedere tutto ciò che potrebbe causare questo? –

3

Non è possibile utilizzare la trama normale per il rendering dell'anteprima della videocamera o del video, è necessario utilizzare l'estensione GL_TEXTURE_EXTERNAL_OES. Ho avuto lo stesso problema e ho trovato una soluzione completa di lavoro su GitHub. Il nome del progetto è android_instacam.

Here troverai codice sorgente da studiare. Se vuoi vederlo in azione direttamente sul tuo dispositivo, vai su Play Store here.

+0

grazie per il link, sembra molto simile a quello che sto facendo. –