La modification de sortie de la caméra à l'aide de SurfaceTexture et OpenGL

Je suis en train de filtrer les flux provenant de l'appareil en cours d'exécution à travers un openGL filtre, puis les afficher dans une GLSurfaceView. Lorsque openGL va pour le rendu de l'image, le LogCat à plusieurs reprises crache une erreur:

[sans nom-3314-0] updateTexImage: compensation GL erreur: 0x502

0x502 est un générique openGL erreur, et n'a pas vraiment m'aider à éradiquer le problème. C'est une séquence de comment fonctionne le code (ou au moins devrait être de travailler comme on le voit dans ma tête), et j'ai copié mon code ci-dessous qui. J'espère que quelqu'un d'autre peut voir ce que mon problème est.

  1. Créer de nouveaux MyGLSurfaceView. Cela crée en interne la nouvelle MyGL20Renderer objet. Cette MyGLSurfaceView est défini comme l'affichage du contenu.
  2. Une fois le MyGLSurfaceView est fait gonfler/initialisation, cet événement d'achèvement déclenche le moteur de rendu pour créer un DirectVideo dessiner un objet, qui compile/liens les shaders définis et les ajoute à un programme openGL. Il crée ensuite une nouvelle openGL texture de l'objet, puis des appels vers le MainActivity avec la texture de l'objet ID.
  3. Lorsque le MainActivity méthode est appelée par le moteur de rendu, il crée un nouveau SurfaceTexture objet à l'aide d'openGL, la texture de l'objet passé. Puis, il définit lui-même comme la surface de la onFrameListener. Il crée ensuite/ouvre l'appareil photo de l'objet, définit le créé SurfaceTexture que le flux vidéo de la cible, et commence à l'alimentation de la caméra.
  4. Lorsqu'une image est disponible à partir de l'alimentation, de l'onFrameAvailable envoie un rendu demande au moteur de rendu. C'est ramassé sur l'openGL fil, qui appelle à la SurfaceTexture de updateTexImage(), qui charge le cadre de la mémoire dans la texture openGL. Il appelle ensuite la DirectVideo de l'objet de dessin, et le programme openGL séquence est exécutée. Si j'en commentaire ce .draw() de la ligne, l'erreur mentionnée ci-dessus disparaît, il semble donc probable que le problème se situe quelque part à l'intérieur ici, mais je ne suis pas la décision elle être causée par un mal lié/créé texture.

MainActivity.java

public class MainActivity extends Activity implements SurfaceTexture.OnFrameAvailableListener
{
    private Camera mCamera;
    private MyGLSurfaceView glSurfaceView;
    private SurfaceTexture surface;
    MyGL20Renderer renderer;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        glSurfaceView = new MyGLSurfaceView(this);
        renderer = glSurfaceView.getRenderer();
        setContentView(glSurfaceView);
    }

    public void startCamera(int texture)
    {
        surface = new SurfaceTexture(texture);
        surface.setOnFrameAvailableListener(this);
        renderer.setSurface(surface);

        mCamera = Camera.open();

        try
        {
            mCamera.setPreviewTexture(surface);
            mCamera.startPreview();
        }
        catch (IOException ioe)
        {
            Log.w("MainActivity","CAM LAUNCH FAILED");
        }
    }

    public void onFrameAvailable(SurfaceTexture surfaceTexture)
    {
        glSurfaceView.requestRender();
    }

    @Override
    public void onPause()
    {
        mCamera.stopPreview();
        mCamera.release();
        System.exit(0);
    }

MyGLSurfaceView.java

class MyGLSurfaceView extends GLSurfaceView
{
    MyGL20Renderer renderer;
    public MyGLSurfaceView(Context context)
    {
        super(context);

        setEGLContextClientVersion(2);

        renderer = new MyGL20Renderer((MainActivity)context);
        setRenderer(renderer);
        setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

    }
    public MyGL20Renderer getRenderer()
    {
        return renderer;
    }
}

MyGL20Renderer.java

public class MyGL20Renderer implements GLSurfaceView.Renderer
{
DirectVideo mDirectVideo;
int texture;
private SurfaceTexture surface;
MainActivity delegate;
public MyGL20Renderer(MainActivity _delegate)
{
delegate = _delegate;
}
public void onSurfaceCreated(GL10 unused, EGLConfig config)
{
mDirectVideo = new DirectVideo(texture);
texture = createTexture();
GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
delegate.startCamera(texture);
}
public void onDrawFrame(GL10 unused)
{
float[] mtx = new float[16];
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
surface.updateTexImage();
surface.getTransformMatrix(mtx); 
mDirectVideo.draw();
}
public void onSurfaceChanged(GL10 unused, int width, int height)
{
GLES20.glViewport(0, 0, width, height);
}
static public int loadShader(int type, String shaderCode)
{
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
static private int createTexture()
{
int[] texture = new int[1];
GLES20.glGenTextures(1,texture, 0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture[0]);
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);
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 texture[0];
}
public void setSurface(SurfaceTexture _surface)
{
surface = _surface;
}
}

DirectVideo.java

public class DirectVideo {
private final String vertexShaderCode =
"#extension GL_OES_EGL_image_external : require\n"+
"attribute vec4 position;" +
"attribute vec4 inputTextureCoordinate;" +
"varying vec2 textureCoordinate;" +
"void main()" +
"{"+
"gl_Position = position;"+
"textureCoordinate = inputTextureCoordinate.xy;" +
"}";
private final String fragmentShaderCode =
"#extension GL_OES_EGL_image_external : require\n"+
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
"  gl_FragColor = vColor;" +
"}";
private FloatBuffer vertexBuffer, textureVerticesBuffer;
private ShortBuffer drawListBuffer;
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mTextureCoordHandle;
//number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 2;
static float squareVertices[] = { //in counterclockwise order:
-1.0f,  1.0f,
-1.0f,  -1.0f,
1.0f,  -1.0f,
1.0f,  1.0f
};
private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; //order to draw vertices
static float textureVertices[] = { //in counterclockwise order:
1.0f,  1.0f,
1.0f,  0.0f,
0.0f,  1.0f,
0.0f,  0.0f
};
private final int vertexStride = COORDS_PER_VERTEX * 4; //4 bytes per vertex
private int texture;
public DirectVideo(int _texture)
{
texture = _texture;
ByteBuffer bb = ByteBuffer.allocateDirect(squareVertices.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(squareVertices);
vertexBuffer.position(0);
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 = MyGL20Renderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = MyGL20Renderer.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);          
}
public void draw()
{
GLES20.glUseProgram(mProgram);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture);
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "position");
GLES20.glEnableVertexAttribArray(mPositionHandle);
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);
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
//Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTextureCoordHandle);
}
}
  • 502 est GL_INVALID_OPERATION. Pouvez-vous essayer explicitement vérifiant l'erreur avant d'appeler updateTexImage? Assert.assertTrue(GLES20.glGetError() == 0); Il est possible que quelque chose que vous avez fait est à l'origine de l'erreur, et qu'il ne soit pas interrogé jusqu'à updateTexImage l'appelle. Il n'est pas clair à partir de ce message d'erreur si cette erreur est causée par updateTexImage, ou si c'est une attente d'erreur à partir de l'avant.
  • En effet, vous avez raison. Le tirage au sort de la fonction s'exécute correctement lors de l'initialisation, mais sur le premier tirage() appel lancé lors de la première onFrameAvailable fait le rendu d'une demande, l'ASSERTION échoue.
  • Vous aurez à saupoudrer affirme tout au long de votre tirage de fonction jusqu'à ce que vous trouver l'appel OpenGL qui est à l'origine de l'erreur.
  • En fait, à jouer avec cette nouvelle; en supposant que glGetError réinitialise le "erreur" à 0, Le problème peut être dans la fonction draw. J'ai mis débogages conditionnelle, il n'y a pas d'erreur lors de l'onDrawFrame est appelée avant la updateTexImage() appel, après la updateTexImage() appel, mais avant de le DirectVideo.draw() appel, et après la DirectVideo.draw() de l'appel. Les deux premiers passent sans erreur, mais le troisième ne l'est pas. Donc, il semble que le comportement que j'ai posté précédemment a été l'erreur résiduelle à partir de l'image précédente rendre le déclenchement de l'Affirmer.
  • Ok je vais essayer cela et voir ce qui apparaît. Merci!
  • Donc, j'ai trouvé que le #extension exiger que ce qui est nécessaire en raison de la GL_TEXTURE_EXTERNAL_OES devrait être dans le fragment shader, mais pas dans le vertex shader. Les erreurs sont allé une fois-je résoudre ce problème. Je suis toujours en manque de quelque chose parce que la vidéo ne s'affiche pas sur l'écran, mais je suis un pas de plus, et cela résout l'erreur affiché dans la question d'origine. Merci Encore!
  • stackoverflow.com/questions/7847912/... | stackoverflow.com/questions/18449162/... | stackoverflow.com/questions/30723055/...

InformationsquelleAutor Dan Collins | 2012-09-20