zoukankan      html  css  js  c++  java
  • TextureView+SurfaceTexture+OpenGL ES来播放视频(二)

    引自:http://www.jianshu.com/p/b2d949ab1a1a

    在使用OpenGL ES 绘制前,我先概括下接下来要做的工作:我先借用一个博主kiffa举的的一个栗子,我觉得说的恰到好处,遂稍稍概括下来给大家分享分享:
    我们想像一下画家绘画的过程,在作画之前他是不是应该先准备准备呢,首先他得准备作画的画布(对应TexureView),一些笔,颜料以及辅助工具比如调色板等等(OpenGL ES API),然后他就可以在画出他的作品了(SurfaceTexture)。
    ok,假如他现在希望将它绘制好的画上传到电脑上通过显示器来展示,那他先是不是得要获取到要显示设备,好为他的画创造一个展示的环境,同时我们知道你在显示器上所看到的一副图像都是由无数个像素点(其实是一个很小很小的矩形)组成,而每幅画都又是由各种颜色搭配组合而成,在显示器上的绘制其实就是将画的颜色往这些小矩形里面去填充,然而这些颜色都是画家在调色板上一点点调出来的,与之相对应的是,这些颜色在显示器上是可以用RGB(三原色)调制出来的,好了这些准备都到位以后,画家绘制的画就可以在屏幕上显示出来了。若画家以至少24帧/s的频率将画的画不断的输送到屏幕上时就形成了一个连续的影像了。
    为了将画能够呈现给大家,同时考虑到每个人显示设备都可能不一样的情况下,维护OpenGL 的khronos组织提供了一个专门抽象层接口(EGL API OpenGL ES 和底层 Native 平台视窗系统之间的接口) 去适配不同的设备,以保证opengl es的平台无关性。
    下面我就要看看这个EGL是怎么配置的了,OK,又到了“talk is cheap,show me the code“的时刻了

    代码

    /**
     * 绘制前,renderer的配置,初始化EGL,开始一个绘制线程.
     * 这个类需要子类去实现相应的绘制工作.
     */
    public abstract class TextureSurfaceRenderer implements Runnable{
        public static String LOG_TAG = TextureSurfaceRenderer.class.getSimpleName();
    
        protected final SurfaceTexture surfaceTexture;
        protected int width;
        protected int height;
    
        private EGL10 egl;
        private EGLContext eglContext;
        private EGLDisplay eglDisplay;
        private EGLSurface eglSurface;
        /***
         * 是否正在绘制(draw)
         */
        private boolean running = false;
    
        public TextureSurfaceRenderer(SurfaceTexture surfaceTexture, int width, int height) {
            this.surfaceTexture = surfaceTexture;
            this.width = width;
            this.height = height;
            this.running = true;
            /**开个线程来进行绘制工作*/
            Thread thread = new Thread(this);
            thread.start();
        }
    
        /**
        * 初始化EGL环境
        * 1.获取display    2.初始画egl
        * 3.选择config     4.构造surface
        * 5.创建context    5.进行绘制
        */
        private void initEGL() {
            egl = (EGL10)EGLContext.getEGL();
            //获取显示设备
            eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
            //version中存放EGL 版本号,int[0]为主版本号,int[1]为子版本号
            int version[] = new int[2];
            egl.eglInitialize(eglDisplay, version);
    
            EGLConfig eglConfig = chooseEglConfig();
            //创建EGL 的window surface 并且返回它的handles(eslSurface)
            eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, surfaceTexture, null);
    
            eglContext = createContext(egl, eglDisplay, eglConfig);
    
            /**绑定context到当前渲染线程并且去绘制(通过opengl去绘制)和读取surface(通过eglSwapBuffers(EGLDisplay dpy, EGLContext ctx)来显示)*/
            try {
                if (eglSurface == null || eglSurface == EGL10.EGL_NO_SURFACE) {
                    throw new RuntimeException("GL error:" + GLUtils.getEGLErrorString(egl.eglGetError()));
                }
                if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {
                    throw new RuntimeException("GL Make current Error"+ GLUtils.getEGLErrorString(egl.eglGetError()));
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
    
        @Override
        public void run() {
            initEGL();
            initGLComponents();
            Log.d(LOG_TAG, "OpenGL init OK. start draw...");
            while (running) {
                if (draw()) {
                    egl.eglSwapBuffers(eglDisplay, eglSurface);
                }
            }
            deinitGLComponents();
            deinitEGL();
        }
    
        private void deinitEGL() {
            egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
            egl.eglDestroySurface(eglDisplay, eglSurface);
            egl.eglDestroyContext(eglDisplay, eglContext);
            egl.eglTerminate(eglDisplay);
            Log.d(LOG_TAG, "OpenGL deinit OK.");
        }
    
        /**
         * 主要的绘制函数, 需在子类中去实现绘制
         */
        protected abstract boolean draw();
    
        /***
         * 抽象函数,初始化opengl绘制所必需的一些组件比如vertextBuffer,sharders,textures等,
         * 通常在Opengl context 初始化以后被调用,需要子类去实现
         */
        protected abstract void initGLComponents();
        /***
        * 于init操作相反,做一些释放资源,停止绘制工作
        */
        protected abstract void deinitGLComponents();
        /***
        * 获取生产的 SurfaceTexture,在子类中实现
        */
        public abstract SurfaceTexture getSurfaceTexture();
    
        /**
         * 为当前渲染的API创建一个渲染上下文
         * @return a handle to the context
         */
        private EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
            int[] attrs = {
                    EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
                    EGL10.EGL_NONE
            };
            return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrs);
        }
    
        /***
         *  选择一个你所期望的配置.
         * @return 一个与你所指定最相近的一个EGL 帧缓存配置.
         */
        private EGLConfig chooseEglConfig() {
            int[] configsCount = new int[1];
            EGLConfig[] configs = new EGLConfig[1];
            int[] attributes = getAttributes();
            int confSize = 1;
    
            if (!egl.eglChooseConfig(eglDisplay, attributes, configs, confSize, configsCount)) {    //获取满足attributes的config个数
                throw new IllegalArgumentException("Failed to choose config:"+ GLUtils.getEGLErrorString(egl.eglGetError()));
            }
            else if (configsCount[0] > 0) {
                return configs[0];
            }
    
            return null;
        }
    
        /**
         * 构造你期望的绘制时所需要的特性配置,如ARGB,DEPTH...
         */
        private int[] getAttributes()
        {
            return new int[] {
                    EGL10.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,  //指定渲染api类别
                    EGL10.EGL_RED_SIZE, 8,
                    EGL10.EGL_GREEN_SIZE, 8,
                    EGL10.EGL_BLUE_SIZE, 8,
                    EGL10.EGL_ALPHA_SIZE, 8,
                    EGL10.EGL_DEPTH_SIZE, 0,
                    EGL10.EGL_STENCIL_SIZE, 0,
                    EGL10.EGL_NONE      //总是以EGL10.EGL_NONE结尾
            };
        }
    
        /**
         * 当 当前activity停止时调用,用来停止渲染线程,并释放资源.
         */
        public void onPause()
        {
            running = false;
        }
    
        @Override
        protected  void finalize() throws Throwable {
            super.finalize();
            running = false;
        }
    }
    

      

  • 相关阅读:
    根据企业信息化应用需求来分析工作流平台的选型
    如何把文件上传到另外一台服务器【转自 金色約定之家】
    如何启用sqlplus的AutoTrace功能 【转】
    使用AJAX技术构建更优秀的Web应用程序
    提高ORACLE数据库的查询统计速度
    一个弹出式menu的制作
    鼠标滑过div显示与隐藏
    使用ASP.NET Atlas AutoComplete Behavior或AutoComplete Extender实现自动完成功能(下)
    使用ASP.NET Atlas AutoComplete Behavior或AutoComplete Extender实现自动完成功能(上) 【转自http://dflying.cnblogs.com】
    用javascript来操作字符串
  • 原文地址:https://www.cnblogs.com/Anita9002/p/4936061.html
Copyright © 2011-2022 走看看