(原)android-as_video_player中的OpenGLES视频显示

android-as_video_player中的OpenGLES视频显示

1,SurfaceView和OpenGLES

先从java的上层代码入手:

surfaceView = (SurfaceView) findViewById(R.id.gl_surface_view);
surfaceView.getLayoutParams().height =screenWidth;
SurfaceHolder mSurfaceHolder = surfaceView.getHolder();
mSurfaceHolder.addCallback(previewCallback);
private Callback previewCallback = new Callback() {
   public void surfaceCreated(SurfaceHolder holder) {
       //这里先创建一个播放器对象,然后调用播放器的初始化函数
       playerController.init(path, surfaceHolder.getSurface(), width, height,new OnInitializedCallback())
   }
 }

 

而在播放器对象中,我们是先从surface对象拿到ANativeWindow对象,然后在后文中就会用这个ANativeWindow对象跟opengles相关内容结合。

//这里会先根据上层的surface对象拿到ndk层的窗口对象ANativeWindow
window = ANativeWindow_fromSurface(env, surface);
//往下传递,将这个窗口对象
videoPlayerController->onSurfaceCreated(window, width, height);

 

接着我们跳过中间无关的内容,我们看看是如何利用这个window对象的.

bool VideoOutput::createEGLContext(ANativeWindow* window) {
   //创建一个EGL对象
   eglCore = new EGLCore();
  //这里是创建一个egl共享上下文,并初始化相关东西,我们等会分析
   bool ret = eglCore->initWithSharedContext();
   //在底层会根据相关参数,创建一个eglsurface
   this->createWindowSurface(window);
   //连接 EGLContext 和 EGLSurface
   eglCore->doneCurrent();    
}

 

接下来的内容,更多的涉及到egl相关的内容了。

2,什么是 EGL?

EGL 是 OpenGL ES 渲染 API 和本地窗口系统(native platform window system)之间的一个中间接口层,它主要由系统制造商实现。EGL提供如下机制:

  • 与设备的原生窗口系统通信

  • 查询绘图表面的可用类型和配置

  • 创建绘图表面

  • 在OpenGL ES 和其他图形渲染API之间同步渲染

  • 管理纹理贴图等渲染资源

为了让OpenGL ES能够绘制在当前设备上,我们需要EGL作为OpenGL ES与设备的桥梁

2.1,使用EGL绘图的基本步骤
  • Display(EGLDisplay) 是对实际显示设备的抽象。

  • Surface(EGLSurface)是对用来存储图像的内存区域

  • FrameBuffer 的抽象,包括 Color Buffer, Stencil Buffer ,Depth Buffer。

  • Context (EGLContext) 存储 OpenGL ES绘图的一些状态信息。

使用EGL的绘图的一般步骤:

  1. 获取 EGL Display 对象:eglGetDisplay()

  2. 初始化与 EGLDisplay 之间的连接:eglInitialize()

  3. 获取 EGLConfig 对象:eglChooseConfig()

  4. 创建 EGLContext 实例:eglCreateContext()

  5. 创建 EGLSurface 实例:eglCreateWindowSurface()

  6. 连接 EGLContext 和 EGLSurface:eglMakeCurrent()

  7. 使用 OpenGL ES API 绘制图形:gl_*()

  8. 切换 front buffer 和 back buffer 送显:eglSwapBuffer()

  9. 断开并释放与 EGLSurface 关联的 EGLContext 对象:eglRelease()

  10. 删除 EGLSurface 对象

  11. 删除 EGLContext 对象

  12. 终止与 EGLDisplay 之间的连接

 

3,接着上面的代码,继续分析我们的egl和opengles的相关代码

bool EGLCore::initWithSharedContext(){
   //这里初始化一个共享的context,所谓的共享,其实就是底层使用的单例模式,创建了一个EglShareContext
   //然后在这个单例对象中存储了一个EGLContext sharedContext;对象,这里就是返回这个对象,实际上
   EGLContext context = EglShareContext::getSharedContext();
   //也是对上面的context在初始化一次,感觉两次初始化的内容其实都是一样,所以这个地方就不再贴了
   return init(context);
}

 

而在EglShareContext的初始化中,也是初始化egl相关内容:

void EglShareContext::init() {
    sharedContext = EGL_NO_CONTEXT;
    EGLint numConfigs;
    sharedDisplay = EGL_NO_DISPLAY;
    EGLConfig config;
    const EGLint attribs[] = { EGL_BUFFER_SIZE, 32, EGL_ALPHA_SIZE, 8,
          EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8,
          EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_SURFACE_TYPE,
          EGL_WINDOW_BIT, EGL_NONE };
    //获取egl的默认显示对象
    if ((sharedDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY))
          == EGL_NO_DISPLAY) {
    }
    //初始化和display对象之间连接的相关egl实现版本信息
    if (!eglInitialize(sharedDisplay, 0, 0)) {
    }
    //选择config
    if (!eglChooseConfig(sharedDisplay, attribs, &config, 1, &numConfigs)) {
    }
    //创建一个共享contex上下文对象
    EGLint eglContextAttributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
    if (!(sharedContext = eglCreateContext(sharedDisplay, config,
          NULL == sharedContext ? EGL_NO_CONTEXT : sharedContext,
          eglContextAttributes))) {
    }
}

 

接着我们走到VideoOutput::createWindowSurface(ANativeWindow* window)函数,我们看下源码:

void VideoOutput::createWindowSurface(ANativeWindow* window) {
   this->surfaceWindow = window;
   if(NULL!=eglCore){
      //根据窗口对象window,display,以及display的config等信息来创建一个eglsurface的渲染表面对象
      renderTexSurface = eglCore->createWindowSurface(window);
      if (renderTexSurface != NULL){
         //这里是对当前的display和context所连接surface对象,即渲染表面
         //eglMakeCurrent(display, eglSurface, eglSurface, context);
         eglCore->makeCurrent(renderTexSurface);
         //然后这里就是创建一个opengl es相关内容的对象了,在这个对象内部,实现opengles相关的渲染操作
         //例如shader的加载,编译,连接,以及纹理加载,渲染等等都在这个对象里面操作
         renderer = new VideoGLSurfaceRender();
         if(NULL!=renderer){
            bool isGLViewInitialized = renderer->init(screenWidth, screenHeight);
            if (!isGLViewInitialized) {            
            } else {
               surfaceExists = true;
               forceGetFrame = true;
            }
         }
      }
   }
}

 

 转载请注明出处:https://www.cnblogs.com/lihaiping/p/opengles.html

posted @ 2020-01-08 19:15  lihaiping  阅读(740)  评论(0编辑  收藏  举报