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接口,其中内嵌了一个专门用于绘制的SurfaceSurfaceView可以控制这个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相关推荐

  1. Android - TextureView, SurfaceView和GLSurfaceView 以及 SurfaceTexture

    这几个概念比较绕, 又比较相近. 初看比较糊涂, 把握关键点就好. 关键字 View SurfaceView GLSurfaceView TextureView 这三个后缀都是View, 所以这三个东 ...

  2. SurfaceView、GLSurfaceView、SurfaceTexture、TextureView简单对比

    关键字 View SurfaceView GLSurfaceView TextureView 这三个后缀都是View, 所以这三个东西都是用来显示的, 和普通的View差不多, 类似TextView等 ...

  3. Android 视频展示控件之 SurfaceView、GLSurfaceView、SurfaceTexture、TextureView 对比总结...

    一.SurfaceView SurfaceView继承自View,并提供了一个独立的绘图层,你可以完全控制这个绘图层,比如说设定它的大小,所以SurfaceView可以嵌入到View结构树中,需要注意 ...

  4. 浅谈 SurfaceView、TextureView、GLSurfaceView、SurfaceTexture

    一.SurfaceView SurfaceView 是一个可以在子线程中更新 UI 的 View,且不会影响到主线程.它为自己创建了一个窗口(window),就好像在视图层次(View Hierarc ...

  5. 安卓中的View、SurfaceView和GLSurfaceView区别

    Android游戏当中主要的除了控制类外就是显示类View:SurfaceView是从View基类中派生出来的显示类.android游戏开发中常用的三种视图是:view.SurfaceView和GLS ...

  6. SurfaceView、SurfaceHolder与Surface

    相关文章 SurfaceView.SurfaceHolder与Surface TextureView.SurfaceTexture与Surface 按照官方文档的说法,SurfaceView继承自Vi ...

  7. java锁(公平锁和非公平锁、可重入锁(又名递归锁)、自旋锁、独占锁(写)/共享锁(读)/互斥锁、读写锁)

    前言 本文对Java的一些锁的概念和实现做个整理,涉及:公平锁和非公平锁.可重入锁(又名递归锁).自旋锁.独占锁(写)/共享锁(读)/互斥锁.读写锁 公平锁和非公平锁 概念 公平锁是指多个线程按照申请 ...

  8. 假如有Thread1、Thread2、ThreaD3、Thread4四条线程分别统计C、D、E、F四个盘的大小,所有线程都统计完毕交给Thread5线程去做汇总,应当如何实现?...

    有两种方法: 第一种方法: 一般情况,我们实现多线程都是Thread或者Runnable(后者比较多),但是,这两种都是没返回值的,所以我们需要使用callable(有返回值的多线程)和future( ...

  9. AMNO.6 给出一个不多于5位的整数,要求 1、求出它是几位数 2、分别输出每一位数字 3、按逆序输出各位数字,例如原数为321,应输出123 输入 一个不大于5位的数字

    题目描述 给出一个不多于5位的整数,要求 1.求出它是几位数 2.分别输出每一位数字 3.按逆序输出各位数字,例如原数为321,应输出123 输入 一个不大于5位的数字 输出 三行 第一行 位数 第二 ...

最新文章

  1. 【深度学习理论】(3) 激活函数
  2. 一阶和二阶微分方程的物理意义???
  3. Jvm 系列(五):Java GC 分析
  4. 福利 | 《人工智能之数据挖掘》报告发布:北京相关学者流动人次最高(附下载)...
  5. win server 2008 R2 安装IIS
  6. python随机抽取人名_用Python打造一个CRM系统(五)
  7. Dictionary,hashtable, stl:map有什么异同?
  8. 北斗导航 | 卫星导航基础知识(卫星轨道及卫星在轨运动)
  9. shell 远程协助协助(转载)
  10. LeetCode 358. K 距离间隔重排字符串(贪心+优先队列)
  11. php自增删除开始,PHP的自增自减操作
  12. cpu压力测试 Android,Android App 压力测试方法(Monkey)
  13. Error:java: Compilation failed: internal java compiler error 解决办法
  14. winrar加密压缩
  15. html调用矢量小图标的方法,微信小程序里引入SVG矢量图标的方法
  16. 2021-02-20
  17. PhysX Setup
  18. 佛罗里达大学计算机专业世界排名,2020年中佛罗里达大学排名TFE Times美国最佳计算机科学硕士专业排名第107...
  19. 【python】pythonPTA编程练习2
  20. ゼルダの伝説:ブレスオブザワイルド游戏手账

热门文章

  1. SWD和JTAG调试接口
  2. fs-extra 操作文件
  3. 将所有的碎片信息放进去的结构 ,大大减轻大脑的负担,更容易地解决问题
  4. sequoiadb学习笔记
  5. RBF Kernel 是一种度量的证明
  6. 想创业,有没有好点的冷门项目?
  7. 让我们走近 Microsoft Surface
  8. 安装Oracle数据库客户端时出现:INS-13001环境不满足最低要求问题
  9. python制作爬虫爬取京东商品评论教程
  10. Python核心编程06-----列表 切片 常用操作 修改列表 列表的方法 遍历列表