美文网首页一些收藏音视频进阶
音视频开发 二:自定义GLSurfaceView

音视频开发 二:自定义GLSurfaceView

作者: WhenMeet | 来源:发表于2020-08-21 14:44 被阅读0次

      创建好了EGL环境后,我们就可以自定义我们的GLSurfaceView,可以用来替代系统的GLSurfaceView。

      可以分成以下几点

    • 继承SurfaceView,并实现其CallBack回调
    • 自定义GLThread线程类,主要用于OpenGL的绘制操作
    • 添加设置Surface和EglContext的方法
    • 提供和系统GLSurfaceView相同的调用方法

      先看如何实现自己的SurfaceView

    public abstract class BaseSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
    
        private Surface surface;
        private EGLContext eglContext;
    
        private EGLThread eglThread;
        private EGLRender eglRender;
    
        /**
         * 视图更新模式
         * RENDERMODE_WHEN_DIRTY    懒更新
         * RENDERMODE_CONTINUOUSLY  主动更新
         **/
        public final static int RENDERMODE_WHEN_DIRTY = 0;
        public final static int RENDERMODE_CONTINUOUSLY = 1;
    
        private int mRenderMode = RENDERMODE_CONTINUOUSLY;
    
    
        public BaseSurfaceView(Context context) {
            this(context, null);
        }
    
        public BaseSurfaceView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public BaseSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            getHolder().addCallback(this);
        }
    
        public void setRender(EGLRender eglRender) {
            this.eglRender = eglRender;
        }
    
        public void setRenderMode(int mRenderMode) {
    
            if (eglRender == null) {
                throw new RuntimeException("must set render before");
            }
            this.mRenderMode = mRenderMode;
        }
    
        public void setSurfaceAndEglContext(Surface surface, EGLContext eglContext) {
            this.surface = surface;
            this.eglContext = eglContext;
        }
    
        public EGLContext getEglContext() {
            if (eglThread != null) {
                return eglThread.getEglContext();
            }
            return null;
        }
    
        public void requestRender() {
            if (eglThread != null) {
                eglThread.requestRender();
            }
        }
    
    
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            if (surface == null) {
                surface = holder.getSurface();
            }
            eglThread = new EGLThread(new WeakReference<BaseSurfaceView>(this));
            eglThread.isCreate = true;
            eglThread.start();
        }
    
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    
            eglThread.width = width;
            eglThread.height = height;
            eglThread.isChange = true;
    
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            eglThread.onDestroy();
            eglThread = null;
            surface = null;
            eglContext = null;
        }
    
        public interface EGLRender {
    
            /**
             * 视图创建时
             **/
            void onSurfaceCreated();
    
            /**
             * 视图发生变化时
             *
             * @param width  当前视图宽度
             * @param height 当前视图高度
             **/
            void onSurfaceChanged(int width, int height);
    
            /**
             * 数据更新时
             **/
            void onDrawFrame();
        }
    
        /**
         * 维护egl生命周期的线程
         **/
        public static class EGLThread extends Thread {
    
            private WeakReference<BaseSurfaceView> eglSurfaceViewWeakReference;
            private EglHelper eglHelper = null;
            private Object object = null;
    
            private boolean isExit = false;
            private boolean isCreate = false;
            private boolean isChange = false;
            private boolean isStart = false;
    
            private int width;
            private int height;
    
            public EGLThread(WeakReference<BaseSurfaceView> eglSurfaceViewWeakReference) {
                this.eglSurfaceViewWeakReference = eglSurfaceViewWeakReference;
            }
    
            @Override
            public void run() {
                super.run();
                isExit = false;
                isStart = false;
                object = new Object();
                eglHelper = new EglHelper();
                eglHelper.initEgl(eglSurfaceViewWeakReference.get().surface, eglSurfaceViewWeakReference.get().eglContext);
    
                while (true) {
                    if (isExit) {
                        //释放资源
                        release();
                        break;
                    }
    
                    if (isStart) {
                        if (eglSurfaceViewWeakReference.get().mRenderMode == RENDERMODE_WHEN_DIRTY) {
                            synchronized (object) {
                                try {
                                    object.wait();
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        } else if (eglSurfaceViewWeakReference.get().mRenderMode == RENDERMODE_CONTINUOUSLY) {
                            try {
                                Thread.sleep(1000 / 60);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        } else {
                            throw new RuntimeException("mRenderMode is wrong value");
                        }
                    }
    
                    onCreate();
                    onChange(width, height);
                    onDraw();
    
                    isStart = true;
    
                }
    
            }
    
            private void onCreate() {
                if (isCreate && eglSurfaceViewWeakReference.get().eglRender != null) {
                    isCreate = false;
                    eglSurfaceViewWeakReference.get().eglRender.onSurfaceCreated();
                }
            }
    
            private void onChange(int width, int height) {
                if (isChange && eglSurfaceViewWeakReference.get().eglRender != null) {
                    isChange = false;
                    eglSurfaceViewWeakReference.get().eglRender.onSurfaceChanged(width, height);
                }
            }
    
            private void onDraw() {
                if (eglSurfaceViewWeakReference.get().eglRender != null && eglHelper != null) {
                    eglSurfaceViewWeakReference.get().eglRender.onDrawFrame();
                    if (!isStart) {
                        eglSurfaceViewWeakReference.get().eglRender.onDrawFrame();
                    }
                    eglHelper.swapBuffers();
    
                }
            }
    
            /**
             * 通知更新视图
             **/
            private void requestRender() {
                if (object != null) {
                    synchronized (object) {
                        object.notifyAll();
                    }
                }
            }
    
            public void onDestroy() {
                isExit = true;
                //通知更新视图
                requestRender();
            }
    
            /**
             * 释放egl环境
             **/
            public void release() {
                if (eglHelper != null) {
                    eglHelper.destoryEgl();
                    eglHelper = null;
                    object = null;
                    eglSurfaceViewWeakReference = null;
                }
            }
    
            public EGLContext getEglContext() {
                if (eglHelper != null) {
                    return eglHelper.getmEglContext();
                }
                return null;
            }
    
        }
    
    
    }
    

      我们把上一节的创建egl环境的内容用上了,直接定义了一个线程用于管理egl的生命周期,并且定义了EGLRender类,暴露三个方法,这一点直接是模仿了SurfaceHolder.Callback的三个回调。
      然后我们看下如果继承了BaseSurfaceView的EGLRender应该怎么写,如下:

    public class MyRender implements BaseSurfaceView.EGLRender {
    
        public MyRender() {
        }
    
        @Override
        public void onSurfaceCreated() {
        }
    
        @Override
        public void onSurfaceChanged(int width, int height) {
            GLES20.glViewport(0, 0, width, height);
        }
    
        @Override
        public void onDrawFrame() {
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
            GLES20.glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
        }
    }
    

      和上一节的内容很类似,只是把这部分的写法放在了对应的生命周期方法中。
    然后我们继承BaseSurfaceView看下如何写,如下:

    public class EGlSurfaceView extends BaseSurfaceView {
    
        public EGlSurfaceView(Context context) {
            this(context, null);
        }
    
        public EGlSurfaceView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public EGlSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            setRender(new MyRender());
            setRenderMode(BaseSurfaceView.RENDERMODE_WHEN_DIRTY);
        }
    }
    

      我们设置了上面定义的MyRender为EGlSurfaceView的生命周期操作类,并且设置了渲染模式,最后看下如何调用,如下:

    public class EglSurfaceActivity extends Activity {
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_egl);
        }
    }
    

      然后是布局

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <EGlSurfaceView
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </RelativeLayout>
    

      使用起来很简单,现在也没有增加多余的操作,只是用于做最简单的显示,最终效果图:


    渲染效果图

      嗯,显示出了绿色,颜色合适。

    相关文章

      网友评论

        本文标题:音视频开发 二:自定义GLSurfaceView

        本文链接:https://www.haomeiwen.com/subject/elvujktx.html