Android 使用SurfaceTexture和OpenGL修改相机输出

Android 使用SurfaceTexture和OpenGL修改相机输出,android,opengl-es,opengl-es-2.0,Android,Opengl Es,Opengl Es 2.0,我试图通过openGL过滤器过滤来自相机硬件的流,然后在GLSurfaceView中显示它。当openGL渲染帧时,LogCat会反复抛出一个错误: [未命名-3314-0]更新最大值:清除总账错误:0x502 0x502是一个通用的openGL错误,并不能真正帮助我找到问题所在。这是一系列代码的工作方式(或者至少应该是我脑海中看到的工作方式),我已经在下面复制了我的代码。我希望其他人能看到我的问题所在 创建新的MyGLSurfaceView。这将在内部创建新的MyGL20Renderer对象。

我试图通过openGL过滤器过滤来自相机硬件的流,然后在GLSurfaceView中显示它。当openGL渲染帧时,LogCat会反复抛出一个错误:

[未命名-3314-0]更新最大值:清除总账错误:0x502

0x502是一个通用的openGL错误,并不能真正帮助我找到问题所在。这是一系列代码的工作方式(或者至少应该是我脑海中看到的工作方式),我已经在下面复制了我的代码。我希望其他人能看到我的问题所在

  • 创建新的MyGLSurfaceView。这将在内部创建新的MyGL20Renderer对象。此MyGLSurfaceView设置为内容视图
  • 一旦MyGLSurfaceView完成膨胀/初始化,此完成事件将触发渲染器创建DirectVideo绘制对象,该对象将编译/链接定义的着色器并将其添加到openGL程序中。然后创建一个新的openGL纹理对象,然后使用纹理对象ID调用MainActivity
  • 从渲染器调用MainActivity方法时,它将使用传递的openGL纹理对象创建新的SurfaceTexture对象。然后,它将自己设置为曲面的onFrameListener。然后创建/打开摄影机对象,将创建的SurfaceTexture设置为视频流的目标,并启动摄影机提要
  • 如果提要中有可用的帧,onFrameAvailable将向渲染器发送渲染请求。这是在openGL线程上获取的,该线程调用SurfacetTexture的UpdateMaximage(),该线程将帧内存加载到openGL纹理中。然后调用DirectVideo的draw对象,并运行openGL程序序列。如果我注释掉这条.draw()线,上面提到的错误就会消失,因此问题似乎就在这里的某个地方,但我不排除它是由不正确链接/创建的纹理引起的
  • 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);
        }
    }
    
    应该是

    texture = createTexture();
    mDirectVideo = new DirectVideo(texture);
    
    着色器

    private final String vertexShaderCode =
            "attribute vec4 position;" +
            "attribute vec2 inputTextureCoordinate;" +
            "varying vec2 textureCoordinate;" +
            "void main()" +
            "{"+
                "gl_Position = position;"+
                "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" +
            "}";
    
    mColorHandle=GLES20.glGetUniformLocation(mProgram,“vColor”)

    应该是

    mColorHandle=GLES20.glGetAttribLocation(mProgram,“s_纹理”)

    从DirectVideo draw.glVertexAttributePointer等中删除初始化内容。将其放入一些初始化函数中

    public void draw()
    {
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture);
        GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length,
                GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
    }
    

    502是
    GL\u无效\u操作
    。在调用UpdateMaximage之前,是否可以尝试显式检查错误<代码>Assert.assertTrue(GLES20.glGetError()==0)可能是您所做的某些操作导致了错误,并且直到UpdateMaximage调用它时才会被查询。从错误消息中不清楚该错误是由UpdateMaximage引起的,还是以前的未决错误。事实上,您是正确的。draw函数在初始化过程中运行良好,但在第一个onFrameAvailable发出渲染请求时进行的第一次draw()调用中,断言失败。您必须在整个draw函数中散布断言,直到找到导致错误的OpenGL调用。实际上,进一步处理这个问题;假设glGetError将“错误”重置为0,则问题可能出在draw函数中。我将调试输出设置为有条件的,当在updateMaximage()调用之前调用onDrawFrame时,在updateMaximage()调用之后但在DirectVideo.draw()调用之前,以及在DirectVideo.draw()调用之后调用onDrawFrame时,没有错误。前两个过程没有错误,但第三个过程没有错误。所以,我之前发布的行为似乎是触发断言的前一帧渲染的残余错误。好的,我将尝试一下,看看会出现什么。谢谢我相信这确实解决了问题。非常感谢。(并且接受了;迟做总比不做好)嗯@DanCollins我遵循了所有这些步骤,但只得到了一个灰色屏幕。。。有什么建议吗?坐标也错了,奇怪的三角形。对于本机电话使用,请使用以下命令:
    static float squarevertexts[]={-1.0f,1.0f,-1.0f,-1.0f,1.0f,-1.0f,1.0f};静态浮动纹理[]={0.0f,0.0f,1.0f,0.0f,1.0f,1.0f,0.0f,1.0f,}我已经用你的建议尝试了这个项目,并创建了一个GitHub回购协议,结果是:。我移动了GLES20.glvertexattributepointer(mTextureCoordHandle、每个顶点的COORDS\u、GLES20.GL\u FLOAT、false、vertexStride、textureVerticesBuffer);方法调用DirectVideo以使其工作。显示的图像仍为镜像反转。任何修复此问题的建议都非常受欢迎。若要删除镜像反转,请将{0.0f,0.0f,1.0f,1.0f,0.0f,1.0f,}替换为{0.0f,1.0f,1.0f,1.0f,1.0f,1.0f,0.0f,}
    
    public void draw()
    {
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture);
        GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length,
                GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
    }