使用SurfaceTexture和OpenGL修改相机输出
我试图通过运行openGLfilter来过滤来自相机硬件的stream,然后将其显示在GLSurfaceView中。 当openGL去渲染框架时,LogCat反复吐出一个错误:
[unnamed-3314-0] updateTexImage:清除GL错误:0x502
0x502是一个通用的OpenGL错误,并没有真正帮助我追踪这个问题。 这是代码如何工作的序列(或者至less应该像我的头上看到的那样工作),并且我已经在下面复制了我的代码。 我希望别人能看到我的问题是什么。
- 创build新的MyGLSurfaceView。 这也在内部创build新的MyGL20Renderer对象。 这个MyGLSurfaceView被设置为内容视图。
- 一旦MyGLSurfaceView完成了充气/初始化,这个完成事件触发渲染器创build一个DirectVideo绘图对象,该对象编译/链接定义的着色器并将它们添加到openGL程序中。 然后创build一个新的openGL纹理对象,然后用纹理对象ID调用MainActivity。
- 当从渲染器调用MainActivity方法时,它将使用传递的openGL纹理对象创build一个新的SurfaceTexture对象。 然后它将自己设置为表面的onFrameListener。 然后创build/打开相机对象,将创build的SurfaceTexture设置为videostream的目标,然后启动相机馈送。
- 当来自Feed的框架可用时,onFrameAvailable将向渲染器发送渲染请求。 这是在openGL线程中调用的,该线程调用SurfaceTexture的updateTexImage(),将帧存储器加载到openGL纹理中。 然后调用DirectVideo的绘图对象,并运行openGL程序序列。 如果我注释掉这个.draw()行,上面提到的错误就消失了,所以看起来问题可能出在这里,但是我不排除它是由不正确的链接/创build的纹理造成的。
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); } }
mDirectVideo = new DirectVideo(texture); texture = createTexture();
应该
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_texture");
从DirectVideo draw.glVertexAttribPointer等移除初始化的东西。把它放在一些初始化函数。
public void draw() { GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture); GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer); }