- GLSurfaceview 详细工作流程
-
编写GLSurfaceView.Renderer的实例,调setRenderer()将之设成GLSurfaceView的Renderer。
-
GLSurfaceView中的GLThread启动,创建EGL环境后回调Renderer中onSurfaceCreated()
-
通过GLES创建GL的外部纹理。外部纹理说明它的真正内容是放在ion分配出来的系统物理内存中,而不是GPU中,GPU中只是维护了其元数据。
int[] textures = new int[1]; GLES20.glGenTextures(1, textures, 0); mTextureID = textures[0]; GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID);
第一个参数是什么类型的纹理,在此是GLES11Ext.GL_BLEND_EQUATION_RGB_OES,也可以是常用的2D纹理如GLES20.GL_TEXTURE_2D等;第二个参数texture,在程序第一次使用这个参数时,这个函数会创建一个新的对象,并把这个对象分配给它,之后这个texture就成了一个活动的纹理对象。如果texture=0 则OpenGL就停止使用纹理对象,并返回到初始的默认纹理。
-
根据前面创建的GL纹理对象创建SurfaceTexture。SurfaceTexture的参数为GLES接口函数glGenTexture()得到的纹理对象id,在初始化函数SurfaceTexture_init()中,先创建GLConsumer和相应的BufferQueue,再将它们的指针通过JNI放到SurfaceTexture的Java层对象成员中。
mSurface = new SurfaceTexture(mTextureID);
-
设置监听,
由于直接的Listener在Java层,而触发者在Native层,因此需要从Native层回调到Java层。这里通过JNISurfaceTextureContext当了跳板。JNISurfaceTextureContext的onFrameAvailable()起到了Native和Java的桥接作用:通知renderer新的数据到来。mSurface.setOnFrameAvailableListener(this);
-
创建供外部生产者使用的Surface类。Surface的构造函数之一带有参数SurfaceTexture。
它实际上是把SurfaceTexture中创建的BufferQueue的Producer接口实现类拿出来后创建了相应的Surface类。
这样,Surface为BufferQueue的Producer端,SurfaceTexture中的GLConsumer为BufferQueue的Consumer端。当通过Surface绘制时,SurfaceTexture可以通过updateTexImage()来将绘制结果绑定到GL的纹理中。Surface surface = new Surface(mSurface);
-
将SurfaceTexture传给MediaPlayer
因为这里MediaPlayer是生产者,SurfaceTexture是消费者。后者要接收前者输出的Video frame。这样,就通过Observer pattern建立起了一条通知链:MediaPlayer -> SurfaceTexture -> VideDumpRenderer。mMediaPlayer.setSurface(surface);
-
在onFrameAvailable()回调函数中,将updateSurface标志设为true,表示有新的图像到来,需要更新Surface了。
在这不能马上更新纹理
因为当前可能不在渲染线程。SurfaceTexture对象可以在任意线程被创建(回调也会在该线程被调用),但updateTexImage()只能在含有纹理对象的GL Context所在线程中被调用。因此一般情况下回调中不能直接调用updateTexImage()。
与此同时,GLSurfaceView中的GLThread也在运行,它会调用到VideoDumpRenderer的绘制函数onDrawFrame()。通过SurfaceTexture的updateTexImage()将内容流中的新图像转成GL中的纹理,再进行坐标转换。绑定刚生成的纹理,画到屏幕上。if (updateSurface) {mSurface.updateTexImage(); mSurface.getTransformMatrix(mSTMatrix); updateSurface = false; GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);