SurfaceView从Android 1.0(API level 1)时就有 。它继承自类View,因此它本质上是一个View。但与普通View不同的是,它有自己的Surface。我们知道,一般的Activity包含的多个View会组成View hierachy的树形结构,只有最顶层的DecorView,也就是根结点视图,才是对WMS可见的。这个DecorView在WMS中有一个对应的WindowState。相应地,在SF中对应的Layer。而SurfaceView自带一个Surface,这个Surface在WMS中有自己对应的WindowState,在SF中也会有自己的Layer。如下图所示:
public class TriangleActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
mGLView = new GLSurfaceView(this);
mGLView.setRenderer(new RendererImpl(this));
相关类图如下。其中SurfaceView中的SurfaceHolder主要是提供了一坨操作Surface的接口。GLSurfaceView中的EglHelper和GLThread分别实现了上面提到的管理EGL环境和渲染线程的工作。GLSurfaceView的使用者需要实现Renderer接口。
109 public VideoDumpView(Context context) {
...
116 mRenderer = new VideoDumpRenderer(context);
117 setRenderer(mRenderer);
118 }
随后,GLSurfaceView中的GLThread启动,创建EGL环境后回调VideoDumpRenderer中的onSurfaceCreated()。
519 public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
...
551 // Create our texture. This has to be done each time the surface is created.
552 int[] textures = new int[1];
553 GLES20.glGenTextures(1, textures, 0);
554
555 mTextureID = textures[0];
556 GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID);
...
575 mSurface = new SurfaceTexture(mTextureID);
576 mSurface.setOnFrameAvailableListener(this);
577
578 Surface surface = new Surface(mSurface);
579 mMediaPlayer.setSurface(surface);
这里,首先通过GLES创建GL的外部纹理。外部纹理说明它的真正内容是放在ion分配出来的系统物理内存中,而不是GPU中,GPU中只是维护了其元数据。接着根据前面创建的GL纹理对象创建SurfaceTexture。流程如下:
230 static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached,
231 jint texName, jboolean singleBufferMode, jobject weakThiz)
232 {
...
235 BufferQueue::createBufferQueue(&producer, &consumer);
...
242 sp<GLConsumer> surfaceTexture;
243 if (isDetached) {
244 surfaceTexture = new GLConsumer(consumer, GL_TEXTURE_EXTERNAL_OES,
245 true, true);
246 } else {
247 surfaceTexture = new GLConsumer(consumer, texName,
248 GL_TEXTURE_EXTERNAL_OES, true, true);
249 }
...
256 SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
257 SurfaceTexture_setProducer(env, thiz, producer);
...
266 sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz,
267 clazz));
268 surfaceTexture->setFrameAvailableListener(ctx);
269 SurfaceTexture_setFrameAvailableListener(env, thiz, ctx);
由于直接的Listener在Java层,而触发者在Native层,因此需要从Native层回调到Java层。这里通过JNISurfaceTextureContext当了跳板。JNISurfaceTextureContext的onFrameAvailable()起到了Native和Java的桥接作用:
180 void JNISurfaceTextureContext::onFrameAvailable()
...
184 env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz);
其中的fields.postEvent早在SurfaceTexture_classInit()中被初始化为SurfaceTexture的postEventFromNative()函数。这个函数往所在线程的消息队列中放入消息,异步调用VideoDumpRenderer的onFrameAvailable()函数,通知VideoDumpRenderer有新的数据到来。
133 public Surface(SurfaceTexture surfaceTexture) {
...
140 setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
它实际上是把SurfaceTexture中创建的BufferQueue的Producer接口实现类拿出来后创建了相应的Surface类。
135 static jlong nativeCreateFromSurfaceTexture(JNIEnv* env, jclass clazz,
136 jobject surfaceTextureObj) {
137 sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, surfaceTextureObj));
...
144 sp<Surface> surface(new Surface(producer, true));
这样,Surface为BufferQueue的Producer端,SurfaceTexture中的GLConsumer为BufferQueue的Consumer端。当通过Surface绘制时,SurfaceTexture可以通过updateTexImage()来将绘制结果绑定到GL的纹理中。
372 public void onDrawFrame(GL10 glUnused) {
...
377 if (updateSurface) {
...
380 mSurface.updateTexImage();
381 mSurface.getTransformMatrix(mSTMatrix);
382 updateSurface = false;
...
394 // Activate the texture.
395 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
396 GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID);
...
421 // Draw a rectangle and render the video frame as a texture on it.
422 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
...
429 DumpToFile(frameNumber);
这里,通过SurfaceTexture的updateTexImage()将内容流中的新图像转成GL中的纹理,再进行坐标转换。绑定刚生成的纹理,画到屏幕上。整个流程如下:
protected void onCreate(Bundle savedInstanceState) {
...
mTextureView = new TextureView(this);
mTextureView.setSurfaceTextureListener(this);
...
}
TextureView的构造函数并不做主要的初始化工作。主要的初始化工作是在getHardwareLayer()中,而这个函数是在其基类View的draw()中调用。TextureView重载了这个函数:
348 HardwareLayer getHardwareLayer() {
...
358 mLayer = mAttachInfo.mHardwareRenderer.createTextureLayer();
359 if (!mUpdateSurface) {
360 // Create a new SurfaceTexture for the layer.
361 mSurface = new SurfaceTexture(false);
362 mLayer.setSurfaceTexture(mSurface);
363 }
364 mSurface.setDefaultBufferSize(getWidth(), getHeight());
365 nCreateNativeWindow(mSurface);
366
367 mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
368
369 if (mListener != null && !mUpdateSurface) {
370 mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
371 }
...
390 applyUpdate();
391 applyTransformMatrix();
392
393 return mLayer;
394 }
因为TextureView是硬件加速层(类型为LAYER_TYPE_HARDWARE),它首先通过HardwareRenderer创建相应的HardwareLayer类,放在mLayer成员中。然后创建SurfaceTexture类,具体流程见前文。之后将HardwareLayer与SurfaceTexture做绑定。接着调用Native函数nCreateNativeWindow,它通过SurfaceTexture中的BufferQueueProducer创建Surface类。注意Surface实现了ANativeWindow接口,这意味着它可以作为EGL
Surface传给EGL接口从而进行硬件绘制。然后setOnFrameAvailableListener()将监听者mUpdateListener注册到SurfaceTexture。这样,当内容流上有新的图像到来,mUpdateListener的onFrameAvailable()就会被调用。然后需要调用注册在TextureView中的SurfaceTextureListener的onSurfaceTextureAvailable()回调函数,通知TextureView的使用者SurfaceTexture已就绪。整个流程大体如下:
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mCamera = Camera.open();
...
mCamera.setPreviewTexture(surface);
mCamera.startPreview();
...
}
看一下setPreviewTexture()的实现,其中把SurfaceTexture中初始化时创建的GraphicBufferProducer拿出来传给Camera模块。
576 static void android_hardware_Camera_setPreviewTexture(JNIEnv *env,
577 jobject thiz, jobject jSurfaceTexture)
...
585 producer = SurfaceTexture_getProducer(env, jSurfaceTexture);
...
594 if (camera->setPreviewTarget(producer) != NO_ERROR) {
到这里,一切都初始化地差不多了。接下来当内容流有新图像可用,TextureView会被通知到(通过SurfaceTexture.OnFrameAvailableListener接口)。SurfaceTexture.OnFrameAvailableListener是SurfaceTexture有新内容来时的回调接口。TextureView中的mUpdateListener实现了该接口:
755 public void onFrameAvailable(SurfaceTexture surfaceTexture) {
756 updateLayer();
757 invalidate();
758 }
可以看到其中会调用updateLayer()函数,然后通过invalidate()函数申请更新UI。updateLayer()会设置mUpdateLayer标志位。这样,当下次VSync到来时,Choreographer通知App通过重绘View hierachy。在UI重绘函数performTranversals()中,作为View hierachy的一分子,TextureView的draw()函数被调用,其中便会相继调用applyUpdate()和HardwareLayer的updateSurfaceTexture()函数。
138 public void updateSurfaceTexture() {
139 nUpdateSurfaceTexture(mFinalizer.get());
140 mRenderer.pushLayerUpdate(this);
141 }
updateSurfaceTexture()实际通过JNI调用到android_view_HardwareLayer_updateSurfaceTexture()函数。在其中会设置相应DeferredLayerUpdater的标志位mUpdateTexImage,它表示在渲染线程中需要更新该层的纹理。
转载自:https://blog.csdn.net/jinzhuojun/article/details/44062175