SurfaceView、GLSurfaceView、SurfaceTexture、TextureView、SurfaceHolder、Surface
SurfaceView、GLSurfaceViewe\SurfaceTexture、TextureView、SurfaceHolder、Surface
一、简介
SurfaceTexture: SurfaceTexture是从Android3.0(API 11)加入的一个新类。这个类跟SurfaceView很像,可以从video decode里面获取图像流(image stream)。但是,和SurfaceView不同的是,SurfaceTexture在接收图像流之后,不需要显示出来。SurfaceTexture不需要显示到屏幕上,因此我们可以用SurfaceTexture接收来自decode出来的图像流,然后从SurfaceTexture中取得图像帧的拷贝进行处理,处理完毕后再送给另一个SurfaceView用于显示即可。
Surface: 处理被屏幕排序的原生的buffer,Android中的Surface就是一个用来画图形(graphics)或图像(image)的地方,对于View及其子类,都是画在Surface上,各Surface对象通过Surfaceflinger合成到frameBuffer,每个Surface都是双缓冲(实际上就是两个线程,一个渲染线程,一个UI更新线程),它有一个backBuffer和一个frontBuffer,Surface中创建了Canvas对象,用来管理Surface绘图操作,Canvas对应Bitmap,存储Surface中的内容(Surface可以理解成是用来管理Canvas画布的,而Canvas用来存储图像数据的)。
SurfaceView: 这个可能经常被说起,在Camera,MediaRecorder,MediaPlayer中用来显示图像的。SurfaceView是View的子类,且实现了Parcelable接口,其中内嵌了一个专门用于绘制的Surface,SurfaceView可以控制这个Surface的格式和尺寸,以及Surface的绘制位置。可以理解为**Surface就是管理数据的地方,SurfaceView就是展示数据的地方**。
SurfaceHolder:顾名思义,一个管理Surface的容器。SurfaceHolder是一个接口,可理解为一个Surface的监听器。
通过回调方法addCallback(SurfaceHolder.Callback callback )监听Surface的创建、改变、销毁等。通过获取Surface中的Canvas对象,并锁定所得到的Canvas对象,当修改Surface中的数据完成后,释放同步锁,并提交改变Surface的状态及图像,将新的图像数据进行展示。
而最后综合:SurfaceView中调用getHolder方法,可以获得当前SurfaceView中的Surface对应的SurfaceHolder,SurfaceHolder开始对Surface进行管理操作。这里其实按MVC模式理解的话,可以更好理解。M:Surface(图像数据),V:SurfaceView(图像展示),C:SurfaceHolder(图像数据管理)。
1、 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。如下图所示:
也就是说, 虽然在Client端(App)它仍在View hierachy中,但在Server端(WMS和SF)中,它与宿主窗口是分离的(可以理解成其他的View在一个窗口中,SurfaceView中的Surface单独占用一个窗口)。这样的好处是**对这个Surface的渲染可以放到单独线程去做,渲染时可以有自己的GL context。这对于一些游戏、视频等性能相关的应用非常有益,因为它不会影响主线程对事件的响应。但它也有缺点,因为这个Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换,也不能放在其它ViewGroup中,一些View中的特性也无法使用**。
通过源码发现,SurfaceView里面其实就是创建了一个Surface,Surface主要的实现就是管理里面的Canvas的打开、关闭等,以及监听这个Surface的创建、改变、销毁、锁定里面的Canvas以及解锁等操作的SurfaceHolder,以及一些使里面的Surface占用独立窗口的一些操作。
final Surface mSurface = new Surface(); // Current surface in use
/**
296 * Return the SurfaceHolder providing access and control over this
297 * SurfaceView's underlying surface.
298 *
299 * @return SurfaceHolder The holder of the surface.
300 */
301 public SurfaceHolder getHolder() {302 return mSurfaceHolder;
303 }
304
@UnsupportedAppUsage
1616 private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {1617 private static final String LOG_TAG = "SurfaceHolder";
1618
1624 @Override
1625 public void addCallback(Callback callback) {1626 synchronized (mCallbacks) {1627 // This is a linear search, but in practice we'll
1628 // have only a couple callbacks, so it doesn't matter.
1629 if (!mCallbacks.contains(callback)) {1630 mCallbacks.add(callback);
1631 }
1632 }
1633 }
1634
1635 @Override
1636 public void removeCallback(Callback callback) {1637 synchronized (mCallbacks) {1638 mCallbacks.remove(callback);
1639 }
1640 }
1641
1683
1684 /**
1685 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1686 *
1687 * After drawing into the provided {@link Canvas}, the caller must
1688 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1689 *
1690 * The caller must redraw the entire surface.
1691 * @return A canvas for drawing into the surface.
1692 */
1693 @Override
1694 public Canvas lockCanvas() {1695 return internalLockCanvas(null, false);
1696 }
1697
1698 /**
1699 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1700 *
1701 * After drawing into the provided {@link Canvas}, the caller must
1702 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1703 *
1704 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
1705 * to redraw. This function may choose to expand the dirty rectangle if for example
1706 * the surface has been resized or if the previous contents of the surface were
1707 * not available. The caller must redraw the entire dirty region as represented
1708 * by the contents of the inOutDirty rectangle upon return from this function.
1709 * The caller may also pass <code>null</code> instead, in the case where the
1710 * entire surface should be redrawn.
1711 * @return A canvas for drawing into the surface.
1712 */
1713 @Override
1714 public Canvas lockCanvas(Rect inOutDirty) {1715 return internalLockCanvas(inOutDirty, false);
1716 }
1717
1718 @Override
1719 public Canvas lockHardwareCanvas() {1720 return internalLockCanvas(null, true);
1721 }
private void setWindowStopped(boolean stopped) {310 mWindowStopped = stopped;
311 updateRequestedVisibility();
312 updateSurface();
313 }
314
315 @Override
316 protected void onAttachedToWindow() {317 super.onAttachedToWindow();
318
319 getViewRootImpl().addSurfaceChangedCallback(this);
320 mWindowStopped = false;
321
322 mViewVisibility = getVisibility() == VISIBLE;
323 updateRequestedVisibility();
324
325 mAttachedToWindow = true;
326 mParent.requestTransparentRegion(SurfaceView.this);
327 if (!mGlobalListenersAdded) {328 ViewTreeObserver observer = getViewTreeObserver();
329 observer.addOnScrollChangedListener(mScrollChangedListener);
330 observer.addOnPreDrawListener(mDrawListener);
331 mGlobalListenersAdded = true;
332 }
333 }
334
SurfaceView总结:里面会创建一个Surface,Surface主要管理Canvas画布对象的打开、关闭等操作,同时还有一个专门监听Surface创建、销毁、改变、里面的Canvas锁定等操作的SurfaceHolder,以及让Surface能够独占一个窗口的一系列操作。
2、GLSurfaceView
从Android 1.5(API level 3)开始加入,作为SurfaceView的补充。它可以看作是SurfaceView的一种典型使用模式。在SurfaceView的基础上,它加入了EGL的管理,并自带了渲染线程。另外它定义了用户需要实现的Render接口,提供了用Strategy pattern更改具体Render行为的灵活性。作为GLSurfaceView的Client,只需要将实现了渲染 函数的Renderer的实现类设置给GLSurfaceView即可。如:
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接口**
通过源码可知,GLSurfaceView继承至SurfaceView,同时实现了SurfaceHolder.CallBack2的接口,只是多添加了一个Renderer接口,以及GLThread渲染线程(主要执行渲染的相关工作,管理渲染器的执行操作等,比如设置渲染器的模式,请求获得Render渲染器等)和EGlHelper管理EGL环境的工作。
1921 private static final GLThreadManager sGLThreadManager = new GLThreadManager();
1922
1923 private final WeakReference<GLSurfaceView> mThisWeakRef =
1924 new WeakReference<GLSurfaceView>(this);
1925 @UnsupportedAppUsage
1926 private GLThread mGLThread;
1927 @UnsupportedAppUsage
1928 private Renderer mRenderer;
1929 private boolean mDetached;
1930 private EGLConfigChooser mEGLConfigChooser;
1931 private EGLContextFactory mEGLContextFactory;
1932 private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
1933 private GLWrapper mGLWrapper;
设置Render渲染器之后,就可以创建GLThread渲染线程管理Render中一系列的操作了
/** @param renderer the renderer to use to perform OpenGL drawing.* 设置渲染器之后,马上开启渲染线程
347 */
348 public void setRenderer(Renderer renderer) {349 checkRenderThreadState();
350 if (mEGLConfigChooser == null) {351 mEGLConfigChooser = new SimpleEGLConfigChooser(true);
352 }
353 if (mEGLContextFactory == null) {354 mEGLContextFactory = new DefaultContextFactory();
355 }
356 if (mEGLWindowSurfaceFactory == null) {357 mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
358 }
359 mRenderer = renderer;
360 mGLThread = new GLThread(mThisWeakRef);
361 mGLThread.start();
362 }/**
606 * This method is used as part of the View class and is not normally
607 * called or subclassed by clients of GLSurfaceView.
608 */
609 @Override
610 protected void onAttachedToWindow() {611 super.onAttachedToWindow();
612 if (LOG_ATTACH_DETACH) {613 Log.d(TAG, "onAttachedToWindow reattach =" + mDetached);
614 }
615 if (mDetached && (mRenderer != null)) {616 int renderMode = RENDERMODE_CONTINUOUSLY;
617 if (mGLThread != null) {618 renderMode = mGLThread.getRenderMode();
619 }
620 mGLThread = new GLThread(mThisWeakRef);
621 if (renderMode != RENDERMODE_CONTINUOUSLY) {622 mGLThread.setRenderMode(renderMode);
623 }
624 mGLThread.start();
625 }
626 mDetached = false;
627 }
管理EGL环境
public void setEGLConfigChooser(boolean needDepth) {425 setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth));
426 }
427
428 /**
429 * Install a config chooser which will choose a config
430 * with at least the specified depthSize and stencilSize,
431 * and exactly the specified redSize, greenSize, blueSize and alphaSize.
432 * <p>If this method is
433 * called, it must be called before {@link #setRenderer(Renderer)}
434 * is called.
435 * <p>
436 * If no setEGLConfigChooser method is called, then by default the
437 * view will choose an RGB_888 surface with a depth buffer depth of
438 * at least 16 bits.
439 *
440 */
441 public void setEGLConfigChooser(int redSize, int greenSize, int blueSize,
442 int alphaSize, int depthSize, int stencilSize) {443 setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize,
444 blueSize, alphaSize, depthSize, stencilSize));
445 }
可以在GLThread渲染线程里面去请求它管理的Render渲染器,也可以设置Render的各种模式等
public void setRenderMode(int renderMode) {495 mGLThread.setRenderMode(renderMode);
496 }
497
498 /**
499 * Get the current rendering mode. May be called
500 * from any thread. Must not be called before a renderer has been set.
501 * @return the current rendering mode.
502 * @see #RENDERMODE_CONTINUOUSLY
503 * @see #RENDERMODE_WHEN_DIRTY
504 */
505 public int getRenderMode() {506 return mGLThread.getRenderMode();
507 }
508
509 /**
510 * Request that the renderer render a frame.
511 * This method is typically used when the render mode has been set to
512 * {@link #RENDERMODE_WHEN_DIRTY}, so that frames are only rendered on demand.
513 * May be called
514 * from any thread. Must not be called before a renderer has been set.
515 */
516 public void requestRender() {517 mGLThread.requestRender();
518 }
519
520 /**
521 * This method is part of the SurfaceHolder.Callback interface, and is
522 * not normally called or subclassed by clients of GLSurfaceView.
523 */
524 public void surfaceCreated(SurfaceHolder holder) {525 mGLThread.surfaceCreated();
526 }
527
528 /**
529 * This method is part of the SurfaceHolder.Callback interface, and is
530 * not normally called or subclassed by clients of GLSurfaceView.
531 */
532 public void surfaceDestroyed(SurfaceHolder holder) {533 // Surface will be destroyed when we return
534 mGLThread.surfaceDestroyed();
535 }
536
537 /**
538 * This method is part of the SurfaceHolder.Callback interface, and is
539 * not normally called or subclassed by clients of GLSurfaceView.
540 */
541 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {542 mGLThread.onWindowResize(w, h);
543 }
544
当Surface被创建、改变、绘制的时候会回调Render里面的方法
public interface Renderer {710 /**
711 * Called when the surface is created or recreated.
733 */
734 void onSurfaceCreated(GL10 gl, EGLConfig config);
735
736 /**
737 * Called when the surface changed size.
753 * </pre>
754 * @param gl the GL interface. Use <code>instanceof</code> to
755 * test if the interface supports GL11 or higher interfaces.
756 * @param width
757 * @param height
758 */
759 void onSurfaceChanged(GL10 gl, int width, int height);
760
761 /**
762 * Called to draw the current frame.
763 * <p>
764 * This method is responsible for drawing the current frame.
765 * <p>
775 */
776 void onDrawFrame(GL10 gl);
777 }
778
EglHelper主要进行了一系列EGL环境的设置,以及创建、销毁Surface,GLThread中关于创建、销毁Surface等操作实际上就是调用了EglHelper中相应的方法等
private static class EglHelper {1016 public EglHelper(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {1017 mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
1018 }
1019
1020 /**
1021 * Initialize EGL for a given configuration spec.
1022 * @param configSpec
1023 */
1024 public void start() {1025 if (LOG_EGL) {1026 Log.w("EglHelper", "start() tid=" + Thread.currentThread().getId());
1027 }
1028 /*
1029 * Get an EGL instance
1030 */
1031 mEgl = (EGL10) EGLContext.getEGL();
1032
1033 /*
1034 * Get to the default display.
1035 */
1036 mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
1037
1038 if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {1039 throw new RuntimeException("eglGetDisplay failed");
1040 }
1041
1042 /*
1043 * We can now initialize EGL for that display
1044 */
1045 int[] version = new int[2];
1046 if(!mEgl.eglInitialize(mEglDisplay, version)) {1047 throw new RuntimeException("eglInitialize failed");
1048 }
1049 GLSurfaceView view = mGLSurfaceViewWeakRef.get();
1050 if (view == null) {1051 mEglConfig = null;
1052 mEglContext = null;
1053 } else {1054 mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
1055
1056 /*
1057 * Create an EGL context. We want to do this as rarely as we can, because an
1058 * EGL context is a somewhat heavy object.
1059 */
1060 mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
1061 }
1062 if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {1063 mEglContext = null;
1064 throwEglException("createContext");
1065 }
1066 if (LOG_EGL) {1067 Log.w("EglHelper", "createContext " + mEglContext + " tid=" + Thread.currentThread().getId());
1068 }
1069
1070 mEglSurface = null;
1071 }
1072
1073 /**
1074 * Create an egl surface for the current SurfaceHolder surface. If a surface
1075 * already exists, destroy it before creating the new surface.
1076 *
1077 * @return true if the surface was created successfully.
1078 */
1079 public boolean createSurface() {1095
1096 /*
1097 * The window size has changed, so we need to create a new
1098 * surface.
1099 */
1100 destroySurfaceImp();
1101
1102 /*
1103 * Create an EGL surface we can render into.
1104 */
1105 GLSurfaceView view = mGLSurfaceViewWeakRef.get();
1106 if (view != null) {1107 mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
1108 mEglDisplay, mEglConfig, view.getHolder());
1109 } else {1110 mEglSurface = null;
1111 }
1112
1113 ...
1135 }private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
1235 EGL10 mEgl;
1236 EGLDisplay mEglDisplay;
1237 EGLSurface mEglSurface;
1238 EGLConfig mEglConfig;
1239 @UnsupportedAppUsage
1240 EGLContext mEglContext;
1163 }
GLThead渲染线程主要是管理Surface等渲染相关组件的创建与销毁,但是这个里面仅仅是进行了一些boolean值进行开关控制,真正实现具体的创建、销毁Surface等操作的实在EglHelper中,当Surface被创建等Render接口中的onSurfaceCreated()此时就能够监听得到这个事件,这也是为什么要在创建Render以后才开启GLThread线程。
static class GLThread extends Thread {1254 GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {1255 super();
1256 mWidth = 0;
1257 mHeight = 0;
1258 mRequestRender = true;
1259 mRenderMode = RENDERMODE_CONTINUOUSLY;
1260 mWantRenderNotification = false;
1261 mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
1262 }
1263
1264 @Override
1265 public void run() {1266 setName("GLThread " + getId());
1267 if (LOG_THREADS) {1268 Log.i("GLThread", "starting tid=" + getId());
1269 }
1270
1271 try {1272 guardedRun();
1273 } catch (InterruptedException e) {1274 // fall thru and exit normally
1275 } finally {1276 sGLThreadManager.threadExiting(this);
1277 }
1278 }
1279
1280 /*
1281 * This private method should only be called inside a
1282 * synchronized(sGLThreadManager) block.
1283 */
1284 private void stopEglSurfaceLocked() {1285 if (mHaveEglSurface) {1286 mHaveEglSurface = false;
1287 mEglHelper.destroySurface();
1288 }
1289 }
1290
1291 /*
1292 * This private method should only be called inside a
1293 * synchronized(sGLThreadManager) block.
1294 */
1295 private void stopEglContextLocked() {1296 if (mHaveEglContext) {1297 mEglHelper.finish();
1298 mHaveEglContext = false;
1299 sGLThreadManager.releaseEglContextLocked(this);
1300 }
1301 }1839 private int mRenderMode;
1840 private boolean mRequestRender;
1841 private boolean mWantRenderNotification;
1842 private boolean mRenderComplete;
1843 private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>();
1844 private boolean mSizeChanged = true;
1845 private Runnable mFinishDrawingRunnable = null;
1846
1847 // End of member variables protected by the sGLThreadManager monitor.
1848
1849 @UnsupportedAppUsage
1850 private EglHelper mEglHelper;
1851
1852 /**
1853 * Set once at thread construction time, nulled out when the parent view is garbage
1854 * called. This weak reference allows the GLSurfaceView to be garbage collected while
1855 * the GLThread is still alive.
1856 */
1857 private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
GLSurfaceView总结:继承自SurfaceView,以及实现了SurfaceHolder.CallBack2里面的方法,也就是说就是SurfaceView的升级版,但不相同的是,里面多了一个GLThread渲染线程,用于主要执行渲染的相关工作,管理渲染器的执行操作等,比如设置渲染器的模式,请求获得Render渲染器等,和EGlHelper管理EGL环境的工作(需要注意:GLThead渲染线程主要是管理Surface等渲染相关组件的创建与销毁,但是这个里面仅仅是进行了一些boolean值进行开关控制,真正实现具体的创建、销毁Surface等操作的实在EglHelper中,当Surface被创建等Render接口中的onSurfaceCreated()此时就能够监听得到这个事件,这也是为什么要在创建Render以后才开启GLThread线程)。
3、SurfaceTexture
从Android 3.0(API level 11)加入。和SurfaceView不同的是, 它对图像流的处理并不直接显示,而是转为GL外部纹理,因此可用于图像流数据的二次处理(如Camera滤镜,桌面特效等)。比如Camera的预览数据,变成纹理后可以交给GLSurfaceView直接显示,也可以通过SurfaceTexture交给TextureView作为View heirachy中的一个硬件加速层来显示。首先,SurfaceTexture从图像流(来自Camera预览,视频解码,GL绘制场景等)中获得帧数据,当调用updateTexImage()时,根据内容流中最近的图像更新SurfaceTexture对应的GL纹理对象,接下来,就可以像操作普通GL纹理一样操作它了。从下面的类图中可以看出,它**核心管理着一个BufferQueue的Consumer和Producer两端。Producer端用于内容流的源输出数据,Consumer端用于拿GraphicBuffer并生成纹理。**SurfaceTexture.OnFrameAvailableListener用于让SurfaceTexture的使用者知道有新数据到来。JNISurfaceTextureContext是OnFrameAvailableListener从Native到Java的JNI跳板。其中SurfaceTexture中的attachToGLContext()和detachToGLContext()可以让多个GL context共享同一个内容源。
Android 5.0中将BufferQueue的核心功能分离出来,放在BufferQueueCore这个类中。BufferQueueProducer和BufferQueueConsumer分别是它的生产者和消费者实现基类(分别实现了IGraphicBufferProducer和IGraphicBufferConsumer接口)。它们都是由BufferQueue的静态 函数createBufferQueue()来创建的。Surface是生产者端的实现类,提供dequeueBuffer/queueBuffer等硬件渲染接口,和lockCanvas/unlockCanvasAndPost等软件渲染接口,其实Surface中的Canvas可以理解成就是一个存储图像数据的地方,使内容流的源可以往BufferQueue中填graphic buffer。GLConsumer继承自ConsumerBase,是消费者端的实现类。它在基类的基础上添加了GL相关的操作,如将graphic buffer中的内容转为GL纹理等操作。到此,以SurfaceTexture为中心的一个pipeline大体是这样的:
4、TextureView
在4.0(API level 14)中引入。它可以将内容流直接投影到View中,可以用于实现Live preview等功能。和SurfaceView不同, 它不会在WMS中单独创建窗口,而是作为View hierachy中的一个普通View,因此可以和其它普通View一样进行移动,旋转,缩放,动画等变化。值得注意的是 TextureView**必须在硬件加速的窗口中。它显示的内容流数据可以来自App进程或是远端进程。从类图中可以看到,TextureView继承自View,它与其它的View一样在View hierachy中管理与绘制。TextureView重载了draw()方法,其中主要把SurfaceTexture中收到的图像数据作为纹理更新到对应的HardwareLayer中**。SurfaceTexture.OnFrameAvailableListener用于通知TextureView内容流有新图像到来。SurfaceTextureListener接口用于让TextureView的使用者知道SurfaceTexture已准备好,这样就可以把SurfaceTexture交给相应的内容源。Surface为BufferQueue的Producer接口实现类,使生产者可以通过它的软件或硬件渲染接口为SurfaceTexture内部的BufferQueue提供graphic buffer。
TextureView内部就有一个SurfaceTexture,以及一个SurfaceTextureListener,用来监听SurfaceTexture的状态等,SurfaceTexture.onFrameAvailableListener主要用来通知TextureView有新图像的到来,TextureView重载了draw()方法,其中主要把SurfaceTexture中收到的图像数据作为纹理更新到对应的HardwareLayer中。
@UnsupportedAppUsage
115 private TextureLayer mLayer;
116 @UnsupportedAppUsage
117 private SurfaceTexture mSurface;
118 private SurfaceTextureListener mListener;
119 private boolean mHadSurface;
120
121 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
122 private boolean mOpaque = true;
123
124 private final Matrix mMatrix = new Matrix();
125 private boolean mMatrixChanged;
126
127 private final Object[] mLock = new Object[0];
128 private boolean mUpdateLayer;
129 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
130 private boolean mUpdateSurface;
131
132 private Canvas mCanvas;
public interface SurfaceTextureListener {818 /**
819 * Invoked when a {@link TextureView}'s SurfaceTexture is ready for use.
820 *
821 * @param surface The surface returned by
822 * {@link android.view.TextureView#getSurfaceTexture()}
823 * @param width The width of the surface
824 * @param height The height of the surface
825 */
826 void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height);
827
828 /**
829 * Invoked when the {@link SurfaceTexture}'s buffers size changed.
830 *
831 * @param surface The surface returned by
832 * {@link android.view.TextureView#getSurfaceTexture()}
833 * @param width The new width of the surface
834 * @param height The new height of the surface
835 */
836 void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height);
837
838 /**
839 * Invoked when the specified {@link SurfaceTexture} is about to be destroyed.
840 * If returns true, no rendering should happen inside the surface texture after this method
841 * is invoked. If returns false, the client needs to call {@link SurfaceTexture#release()}.
842 * Most applications should return true.
843 *
844 * @param surface The surface about to be destroyed
845 */
846 boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface);
847
848 /**
849 * Invoked when the specified {@link SurfaceTexture} is updated through
850 * {@link SurfaceTexture#updateTexImage()}.
851 *
852 * @param surface The surface just updated
853 */
854 void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface);
855 }
@Override
342 public final void draw(Canvas canvas) {343 // NOTE: Maintain this carefully (see View#draw)
344 mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
345
346 /* Simplify drawing to guarantee the layer is the only thing drawn - so e.g. no background,
347 scrolling, or fading edges. This guarantees all drawing is in the layer, so drawing
348 properties (alpha, layer paint) affect all of the content of a TextureView. */
349
350 if (canvas.isHardwareAccelerated()) {351 RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
352
353 TextureLayer layer = getTextureLayer();
354 if (layer != null) {355 applyUpdate();
356 applyTransformMatrix();
357
358 mLayer.setLayerPaint(mLayerPaint); // ensure layer paint is up to date
359 recordingCanvas.drawTextureLayer(layer);
360 }
361 }
362 }TextureLayer getTextureLayer() {387 if (mLayer == null) {388 if (mAttachInfo == null || mAttachInfo.mThreadedRenderer == null) {389 return null;
390 }
391
392 mLayer = mAttachInfo.mThreadedRenderer.createTextureLayer();
393 boolean createNewSurface = (mSurface == null);
394 if (createNewSurface) {395 // Create a new SurfaceTexture for the layer.
396 mSurface = new SurfaceTexture(false);
397 nCreateNativeWindow(mSurface);
398 }
399 mLayer.setSurfaceTexture(mSurface);
400 mSurface.setDefaultBufferSize(getWidth(), getHeight());
401 mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
402
403 if (mListener != null && createNewSurface) {404 mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
405 }
406 mLayer.setLayerPaint(mLayerPaint);
407 }
408
409 if (mUpdateSurface) {410 // Someone has requested that we use a specific SurfaceTexture, so
411 // tell mLayer about it and set the SurfaceTexture to use the
412 // current view size.
413 mUpdateSurface = false;
414
415 // Since we are updating the layer, force an update to ensure its
416 // parameters are correct (width, height, transform, etc.)
417 updateLayer();
418 mMatrixChanged = true;
419
420 mLayer.setSurfaceTexture(mSurface);
421 mSurface.setDefaultBufferSize(getWidth(), getHeight());
422 }
423
424 return mLayer;
425 }
public @Nullable Canvas lockCanvas(@Nullable Rect dirty) {688 if (!isAvailable()) return null;
689
690 if (mCanvas == null) {691 mCanvas = new Canvas();
692 }
693
694 synchronized (mNativeWindowLock) {695 if (!nLockCanvas(mNativeWindow, mCanvas, dirty)) {696 return null;
697 }
698 }
699 mSaveCount = mCanvas.save();
700
701 return mCanvas;
702 }
二、总结
SurfaceView是一个有自己独立Surface的View, 它的渲染可以放在单独线程而不是主线程中, 其缺点是不能做变形和动画。
SurfaceTexture可以用作非直接输出的内容流,这样就提供二次处理的机会。与SurfaceView直接输出相比,这样会有若干帧的延迟。同时,由于它本身管理BufferQueue,因此 内存消耗也会稍微大一些。
TextureView是一个可以把内容流作为外部纹理输出在上面的View, 它本身需要是一个硬件加速层。
事实上TextureView本身也包含了SurfaceTexture, 它与SurfaceView+SurfaceTexture组合相比可以完成类似的功能(即把内容流上的图像转成纹理,然后输出), 区别在于TextureView是在View hierachy中做绘制,因此一般它是在主线程上做的(在Android 5.0引入渲染线程后,它是在渲染线程中做的)。而SurfaceView+SurfaceTexture在单独的Surface上做绘制,可以是用户提供的线程,而不是系统的主线程或是渲染线程。另外,与SurfaceView相比,它还有个好处是可以用Hardware overlay进行显示。
SurfaceView、GLSurfaceView、SurfaceTexture、TextureView、SurfaceHolder、Surface相关推荐
- Android - TextureView, SurfaceView和GLSurfaceView 以及 SurfaceTexture
这几个概念比较绕, 又比较相近. 初看比较糊涂, 把握关键点就好. 关键字 View SurfaceView GLSurfaceView TextureView 这三个后缀都是View, 所以这三个东 ...
- SurfaceView、GLSurfaceView、SurfaceTexture、TextureView简单对比
关键字 View SurfaceView GLSurfaceView TextureView 这三个后缀都是View, 所以这三个东西都是用来显示的, 和普通的View差不多, 类似TextView等 ...
- Android 视频展示控件之 SurfaceView、GLSurfaceView、SurfaceTexture、TextureView 对比总结...
一.SurfaceView SurfaceView继承自View,并提供了一个独立的绘图层,你可以完全控制这个绘图层,比如说设定它的大小,所以SurfaceView可以嵌入到View结构树中,需要注意 ...
- 浅谈 SurfaceView、TextureView、GLSurfaceView、SurfaceTexture
一.SurfaceView SurfaceView 是一个可以在子线程中更新 UI 的 View,且不会影响到主线程.它为自己创建了一个窗口(window),就好像在视图层次(View Hierarc ...
- 安卓中的View、SurfaceView和GLSurfaceView区别
Android游戏当中主要的除了控制类外就是显示类View:SurfaceView是从View基类中派生出来的显示类.android游戏开发中常用的三种视图是:view.SurfaceView和GLS ...
- SurfaceView、SurfaceHolder与Surface
相关文章 SurfaceView.SurfaceHolder与Surface TextureView.SurfaceTexture与Surface 按照官方文档的说法,SurfaceView继承自Vi ...
- java锁(公平锁和非公平锁、可重入锁(又名递归锁)、自旋锁、独占锁(写)/共享锁(读)/互斥锁、读写锁)
前言 本文对Java的一些锁的概念和实现做个整理,涉及:公平锁和非公平锁.可重入锁(又名递归锁).自旋锁.独占锁(写)/共享锁(读)/互斥锁.读写锁 公平锁和非公平锁 概念 公平锁是指多个线程按照申请 ...
- 假如有Thread1、Thread2、ThreaD3、Thread4四条线程分别统计C、D、E、F四个盘的大小,所有线程都统计完毕交给Thread5线程去做汇总,应当如何实现?...
有两种方法: 第一种方法: 一般情况,我们实现多线程都是Thread或者Runnable(后者比较多),但是,这两种都是没返回值的,所以我们需要使用callable(有返回值的多线程)和future( ...
- AMNO.6 给出一个不多于5位的整数,要求 1、求出它是几位数 2、分别输出每一位数字 3、按逆序输出各位数字,例如原数为321,应输出123 输入 一个不大于5位的数字
题目描述 给出一个不多于5位的整数,要求 1.求出它是几位数 2.分别输出每一位数字 3.按逆序输出各位数字,例如原数为321,应输出123 输入 一个不大于5位的数字 输出 三行 第一行 位数 第二 ...
最新文章
- 【深度学习理论】(3) 激活函数
- 一阶和二阶微分方程的物理意义???
- Jvm 系列(五):Java GC 分析
- 福利 | 《人工智能之数据挖掘》报告发布:北京相关学者流动人次最高(附下载)...
- win server 2008 R2 安装IIS
- python随机抽取人名_用Python打造一个CRM系统(五)
- Dictionary,hashtable, stl:map有什么异同?
- 北斗导航 | 卫星导航基础知识(卫星轨道及卫星在轨运动)
- shell 远程协助协助(转载)
- LeetCode 358. K 距离间隔重排字符串(贪心+优先队列)
- php自增删除开始,PHP的自增自减操作
- cpu压力测试 Android,Android App 压力测试方法(Monkey)
- Error:java: Compilation failed: internal java compiler error 解决办法
- winrar加密压缩
- html调用矢量小图标的方法,微信小程序里引入SVG矢量图标的方法
- 2021-02-20
- PhysX Setup
- 佛罗里达大学计算机专业世界排名,2020年中佛罗里达大学排名TFE Times美国最佳计算机科学硕士专业排名第107...
- 【python】pythonPTA编程练习2
- ゼルダの伝説:ブレスオブザワイルド游戏手账