App端SurfaceView控件绘制流程

来源:互联网 发布:颜色识别传感器编程 编辑:程序博客网 时间:2024/05/05 08:11
  SurfaceView,VideoView,GlSurfaceView 中的Surface如何应用 


JAVA层:
SurfaceView系列控件与其他View绘制存在很大的差别。有自己的Surface,其他View是共享一个Surface

1.最基本的SurfaceView
SurfaceView.java
public class SurfaceView extends View {
   //绘图表面
   final Surface mSurface = new Surface();

   //wms中Session代表,跟ViewRootImpl中的一样
   IWindowSession mSession;
   MyWindow mWindow;

   private void updateWindow(boolean force, boolean redrawNeeded) {
        //创建一个surface
        mSession.relayout(
                        mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
                            visible ? VISIBLE : GONE,
                            WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
                            mWinFrame, mOverscanInsets, mContentInsets,
                            mVisibleInsets, mConfiguration, mNewSurface);


        if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
         //释放以前的,以前已经创建过,可见性改变了,隐藏
             mSurfaceCreated = false;
             SurfaceHolder.Callback.surfaceDestroyed(mSurfaceHolder);
        }

       //把mNewSurface的NativeObject拷贝到mSurface中
        mSurface.transferFrom(mNewSurface);

        if (!mSurfaceCreated ...) {//当新创建见surface时候回调,通知创建了新的surface了,可以在这个surface上干活了
          SurfaceHolder.Callback.surfaceCreated(mSurfaceHolder);
        }

    if (sizeChanged ...) {//当大小,格式,等一些属性改变后,回调
               SurfaceHolder.Callback.SurfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
    }
   }


   SurfaceView的绘制的核心就是SurfaceHolder几个回调,
   1.创建新的surface
   2.surface属性改变
   3.释放surface

   private final SurfaceHolder mSurfaceHolder = new SurfaceHolder(){
        //看名字就是跟ViewRootImpl中Surface用的一样了
        public Canvas lockCanvas() {
            return internalLockCanvas(null);
        }

        private final Canvas internalLockCanvas(Rect dirty) {     
            Canvas c = null;
            c = mSurface.lockCanvas(dirty);
            return null;
        }

        public void unlockCanvasAndPost(Canvas canvas) {
            mSurface.unlockCanvasAndPost(canvas);
            mSurfaceLock.unlock();
        }

        //这个就是SurfaceView创建的Surface,绘制都在这上面
        public Surface getSurface() {
            return mSurface;
        }
   }

   SurfaceHolder的lock,unlock都是包转了一下Surface,都是在Surface基础上干活的。
   封装的没有View其他类那么严实,获取到Surface后(通过回调SurfaceHolder.Callback),
   可以在其他线程操作Surface了,不影响主线程的工作

   SurfaceView的使用

   SurfaceView.getHolder().addCallback(new Callback() {
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {

            }
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
            通过holder可以获取到surface了,
        可以启动一个线程直接直接用Surface或 Canvas

        这个Canvas也是包装了Surface,需要lock,unlock
                Canvas canvas = holder.lockCanvas();
                holder.unlockCanvasAndPost(canvas);
            }
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format,
                    int width, int height) {

            }
        });


总结:SurfaceView就是吧Surface的创建,更改等封装好了,使用者只要操作SurfaceHolder就可以了,
  通过注册回调


 2. VideoView继承SurfaceView,看一下他的Surface怎么用的

   class VideoView extends SurfaceView

    private void initVideoView() {
        getHolder().addCallback(mSHCallback); //注册一个自己处理的回调
        getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback()
    {
        public void surfaceChanged(SurfaceHolder holder, int format,
                                    int w, int h)
        {     //播放     
             start();
        }

        public void surfaceCreated(SurfaceHolder holder)
        {   //初始化video         
            openVideo();
        }
    }

    //调用了mediaplyer的start
    public void start() {
         mMediaPlayer.start();     
    }

    private void openVideo() {
        mMediaPlayer = new MediaPlayer();
    //把holder传给了mediaPlayer了
    mMediaPlayer.setDisplay(mSurfaceHolder);
    }


Mediaplayer.java
public class MediaPlayer{
     static {
         System.loadLibrary("media_jni");
     native_init();
     }
     private native void _setVideoSurface(Surface surface);
     public void setDisplay(SurfaceHolder sh) {
        mSurfaceHolder = sh;
        Surface surface= sh.getSurface();
    //把surface取出来,设置给native层了
        _setVideoSurface(surface);
    }

    这个很显然了Java层Surface包装了一个C++的Surface结构,底层直接用surface了,用ANativeWindow(GL)或者Producer

   jni层,
   android_media_MediaPlayer.cpp

   {"_setVideoSurface",    "(Landroid/view/Surface;)V",        (void *)android_media_MediaPlayer_setVideoSurface},
   static void android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface)
   {
       setVideoSurface(env, thiz, jsurface, true);
   }

   setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface, jboolean mediaPlayerMustBeAlive)
  {
    //获取c++层mediaplayer
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);   

    //通过surface获取IGraphicBufferProducer
    sp<IGraphicBufferProducer> new_st;
    sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
    new_st = surface->getIGraphicBufferProducer();

    //把producer传给mediapalyer了,通过producer直接操作图像缓冲区了
    mp->setVideoSurfaceTexture(new_st);
 }
  Mediaplayer不看了,日后再分析



3. GLSurfaceView 直接在app端使用openGl绘制的
 GLSurfaceView.java
 public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback { 

   直接都继承Holder.Callback了

    构造函数中就init
    private void init() {//很直接的注册回调
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);     
    }

    //看名字都直接转到gl绘制线程中了
    public void surfaceCreated(SurfaceHolder holder) {
        mGLThread.surfaceCreated();
    }
    public void surfaceDestroyed(SurfaceHolder holder) {
        mGLThread.surfaceDestroyed(); 
    }
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        mGLThread.onWindowResize(w, h);
    }


    static class GLThread extends Thread {

    //都一样的逻辑,设置一个变量,马上通知notifyAll一下,肯定绘制线程等待则获取surface,然后再等待绘制线程干完活
        public void surfaceCreated() {
            //设置变量,通知更改
                mHasSurface = true;
                mFinishedCreatingEglSurface = false;
                sGLThreadManager.notifyAll();

                //等待响应完成
                while (mWaitingForSurface&& !mFinishedCreatingEglSurface && !mExited) {
                        sGLThreadManager.wait();
                }
            }
        }

    //这个跟上个函数一样的
        public void surfaceDestroyed() {
                mHasSurface = false;
                sGLThreadManager.notifyAll();
                while((!mWaitingForSurface) && (!mExited)) {
                    sGLThreadManager.wait();
                }
            }
        }



        @Override
        public void run() {
             guardedRun();
        }

        private void guardedRun(){

              while(true){

            if (mEglHelper.createSurface()) {//创建完成eglsurface通知surfaceCreated等待的地方
                         synchronized(sGLThreadManager) {
                             mFinishedCreatingEglSurface = true;
                             sGLThreadManager.notifyAll();
                         }
                    }

                {//调用外部设置的render开始绘制
                        GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                        if (view != null) {
                            view.mRenderer.onDrawFrame(gl);
                        }
                    }

            //绘制完成提交后台缓冲区
                    int swapError = mEglHelper.swap();
    }
    }

    mEglHelper怎么创建EGlSurface的
     private static class EglHelper{
        public void start() {//初始化egl环境
    mEgl = (EGL10) EGLContext.getEGL();  //这个下面会用到
    mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
    mEgl.eglInitialize(mEglDisplay, version)
    mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
        mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig)
    }

    // view.getHolder()设置进去,创建EglSurface  ,都是标准的用法
     public boolean createSurface() {
        GLSurfaceView view = mGLSurfaceViewWeakRef.get();       
        mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl, mEglDisplay, mEglConfig, view.getHolder());
    mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)
     }


      GlsurfaceView中
      if (mEGLWindowSurfaceFactory == null) {
            mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
        }

      //还是用的egl
      private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {
        public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
                EGLConfig config, Object nativeWindow) {
            EGLSurface result = null;
           //又回到上面的egl了
             result = egl.eglCreateWindowSurface(display, config, nativeWindow, null);
     }

    //这是当前的egl 
    EGLContext.java
    public abstract class EGLContext
    {
       private static final EGL EGL_INSTANCE = new com.google.android.gles_jni.EGLImpl();   
       public static EGL getEGL() {
          return EGL_INSTANCE;
       }
    }

    EGLImpl.java
    public class EGLImpl implements EGL10 {
     private native int _eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
     //native_window支持好几个类型的
     public EGLSurface eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list) {
        Surface sur = null;

    //如果是surfaceholder则获取出他的surface
        } else if (native_window instanceof SurfaceHolder) {
            SurfaceHolder holder = (SurfaceHolder)native_window;
            sur = holder.getSurface();
        }

        //native创建 一个eglSurface(c++层)
        int eglSurfaceId = _eglCreateWindowSurface(display, config, sur, attrib_list);
    //包装到java中
        return new EGLSurfaceImpl( eglSurfaceId );
    }


JNI层创建EglSurface
android_opengl_EGL14.cpp
static jobject
android_eglCreateWindowSurface
  (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jobject win, jintArray attrib_list_ref, jint offset) {
   //通过java层Surface(win)获取c++层的ANativeWindow  , 其实就是c++层的Surface
   //   class Surface: public ANativeWindow

    android::sp<ANativeWindow> window=android::android_view_Surface_getNativeWindow(_env, win);
    //调用c++层eglapi创建EglSurface
    _returnValue = eglCreateWindowSurface( (EGLDisplay)dpy_native, (EGLConfig)config_native, (EGLNativeWindowType)window.get(),        (EGLint *)attrib_list
   );


   总结:
    为了提高绘制效率增加了SurfaceView系列,可以不在主线程中绘制。

    基本的SurfaceView是把Surface包装成Canvas,提供了跟普通控件一样的绘制方式。
    VideoView  把Surface(IGraphicBufferProducer)给了底层,底层直接进行绘制,上层就不需要关心绘制了
    GlSurfaceView  把Surface(ANativeWindow) 通过Egl包装成EglSurface,上层通过OpenglEs进行3d绘制
0 0
原创粉丝点击